fix(sim): Fix for 2POS switch logic affected by 6POS switch change (#2860)

* Fix 2POS switch logic in simulator. Recent change for 6POS switch broke the 2POS switches.

* Rework switch and pot controls in the simulator ensure consistent values, avoid extraneous events in Qt and, hopefully, simplify the code.

Co-authored-by: Phil Mitchell <phil.a.mitchell@gmail.com>
This commit is contained in:
philmoz
2022-12-14 18:57:01 +10:00
committed by GitHub
co-authored by Phil Mitchell
parent 22e51fb6d0
commit c505f9eb01
3 changed files with 126 additions and 136 deletions
+104 -106
View File
@@ -39,124 +39,122 @@ class RadioKnobWidget : public RadioWidget
public:
explicit RadioKnobWidget(Board::PotType type = Board::POT_WITH_DETENT, QWidget * parent = Q_NULLPTR, Qt::WindowFlags f = Qt::WindowFlags()) :
RadioWidget(parent, f),
m_potType(type)
RadioWidget(parent, f)
{
init();
}
explicit RadioKnobWidget(Board::PotType type, const QString & labelText, int value = 0, QWidget * parent = Q_NULLPTR, Qt::WindowFlags f = Qt::WindowFlags()) :
RadioWidget(labelText, value, parent, f),
m_potType(type)
{
init();
init(type);
}
void init()
explicit RadioKnobWidget(Board::PotType type, const QString & labelText, int value = 0, QWidget * parent = Q_NULLPTR, Qt::WindowFlags f = Qt::WindowFlags()) :
RadioWidget(labelText, value, parent, f)
{
init(type);
}
void init(Board::PotType potType)
{
m_type = RADIO_WIDGET_KNOB;
KnobWidget * pot = new KnobWidget(m_potType, this);
pot->setValue(m_value);
m_stepSize = (potType == Board::POT_MULTIPOS_SWITCH) ? 2048 / 5 : 1;
connect(pot, &KnobWidget::valueChanged, this, &RadioWidget::setValue);
connect(this, &RadioWidget::valueChanged, pot, &KnobWidget::setValue);
m_toolTip = tr("<p>Value (input): <b>%1</b></p>");
if (m_stepSize == 1)
m_toolTip.append(tr("Right-double-click to reset to center."));
setWidget(pot);
m_dial = new QDial(this);
#ifdef __APPLE__
// Set style for dial to show dot instead of arrow pointer for selected position
m_dial->setStyle(QStyleFactory::create("fusion"));
#endif
m_dial->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
m_dial->setFixedSize(QSize(42, 42));
m_dial->setNotchesVisible(true);
if (m_stepSize > 1) {
m_dial->setMinimum(0);
m_dial->setMaximum(2048);
// this is a bit of a hack to get the notch markers to display correctly
// the actual notches/value are constrained in setValue()
m_dial->setSingleStep(m_stepSize / 10);
m_dial->setPageStep(m_stepSize);
m_dial->setNotchTarget(5.7);
}
else {
m_dial->setMinimum(-1024);
m_dial->setMaximum(1024);
m_dial->setPageStep(128);
m_dial->setNotchTarget(64);
}
m_dial->setValue(m_value);
connect(m_dial, &QDial::valueChanged, this, &RadioKnobWidget::setValueFromDial);
connect(this, &RadioWidget::valueChanged, m_dial, &QDial::setValue);
setWidget(m_dial);
}
void setValueFromDial(const int & value)
{
int v = value;
if (m_stepSize > 1) {
v = ((v + m_stepSize / 2) / m_stepSize) * m_stepSize;
// Fix values to account for lack of precision from using integer step size
// This makes the values more symmetrical around the center point
// Note: this is specific to the 6 position switch which is currently the only use case here
if (v > 1024) v += 3;
if (v != value) {
// If the desired value is different then update the slider position
// Note: this will trigger another value changed event call back into this function, at which time setValue will be called below
m_dial->setValue(v);
return;
}
}
setValue(value);
}
void mousePressEvent(QMouseEvent * event)
{
if (m_stepSize == 1 && event->button() == Qt::RightButton && event->type() == QEvent::MouseButtonDblClick) {
m_dial->setValue(0);
event->accept();
return;
}
RadioWidget::mousePressEvent(event);
}
void wheelEvent(QWheelEvent * event)
{
if (event->angleDelta().isNull())
return;
if (m_stepSize > 1) {
int numSteps = event->angleDelta().y() / 8 / 15 * m_stepSize; // one step per 15deg
m_dial->setValue(m_dial->value() + numSteps);
event->accept();
return;
}
RadioWidget::wheelEvent(event);
}
bool event(QEvent *event)
{
if (event->type() == QEvent::ToolTip) {
QHelpEvent * helpEvent = static_cast<QHelpEvent *>(event);
if (helpEvent) {
QToolTip::showText(helpEvent->globalPos(), m_toolTip.arg(m_dial->value()));
return true;
}
}
return RadioWidget::event(event);
}
private:
Board::PotType m_potType;
class KnobWidget : public QDial
{
public:
explicit KnobWidget(Board::PotType type, QWidget * parent = 0):
QDial(parent)
{
#ifdef __APPLE__
// Set style for dial to show dot instead of arrow pointer for selected position
setStyle(QStyleFactory::create("fusion"));
#endif
m_toolTip = tr("<p>Value (input): <b>%1</b></p>");
setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
setFixedSize(QSize(42, 42));
setNotchesVisible(true);
if (type == Board::POT_MULTIPOS_SWITCH) {
m_stepSize = 2048 / 5;
setMinimum(0);
setMaximum(2048);
// this is a bit of a hack to get the notch markers to display correctly
// the actual notches/value are constrained in setValue()
setSingleStep(m_stepSize / 10);
setPageStep(m_stepSize);
setNotchTarget(5.7);
}
else {
m_stepSize = 1;
m_toolTip.append(tr("Right-double-click to reset to center."));
setMinimum(-1024);
setMaximum(1024);
setPageStep(128);
setNotchTarget(64);
}
}
void setValue(int value)
{
if (m_stepSize > 1) {
value = ((value + m_stepSize / 2) / m_stepSize) * m_stepSize;
// Fix values to account for lack of precision from using integer step size
// This makes the values more symmetrical around the center point
// Note: this is specific to the TX16 6 position switch which is currently the only use case here
if (value > 1024) value += 3;
}
QDial::setValue(value);
}
bool event(QEvent *event)
{
if (event->type() == QEvent::ToolTip) {
QHelpEvent * helpEvent = static_cast<QHelpEvent *>(event);
if (helpEvent) {
QToolTip::showText(helpEvent->globalPos(), m_toolTip.arg(this->value()));
return true;
}
}
return QWidget::event(event);
}
void mousePressEvent(QMouseEvent * event)
{
if (m_stepSize == 1 && event->button() == Qt::RightButton && event->type() == QEvent::MouseButtonDblClick) {
setValue(0);
event->accept();
return;
}
QDial::mousePressEvent(event);
}
void wheelEvent(QWheelEvent * event)
{
if (event->angleDelta().isNull())
return;
if (m_stepSize > 1) {
int numSteps = event->angleDelta().y() / 8 / 15 * m_stepSize; // one step per 15deg
setValue(value() + numSteps);
event->accept();
return;
}
QDial::wheelEvent(event);
}
quint16 m_stepSize;
QString m_toolTip;
};
QDial * m_dial;
quint16 m_stepSize;
QString m_toolTip;
};
@@ -36,34 +36,34 @@ class RadioSwitchWidget : public RadioWidget
public:
explicit RadioSwitchWidget(Board::SwitchType type = Board::SWITCH_3POS, QWidget * parent = Q_NULLPTR, Qt::WindowFlags f = Qt::WindowFlags()) :
RadioWidget(parent, f),
swType(type)
RadioWidget(parent, f)
{
init();
init(type);
}
explicit RadioSwitchWidget(Board::SwitchType type, const QString & labelText, int value = -1, QWidget * parent = Q_NULLPTR, Qt::WindowFlags f = Qt::WindowFlags()) :
RadioWidget(labelText, value, parent, f),
swType(type)
RadioWidget(labelText, value, parent, f)
{
init();
init(type);
}
void init()
void init(Board::SwitchType swType)
{
m_type = RADIO_WIDGET_SWITCH;
m_stepSize = (swType == Board::SWITCH_3POS ? 1 : 2);
m_slider = new QSlider();
m_slider->setOrientation(Qt::Vertical);
m_slider->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred);
m_slider->setInvertedAppearance(true);
m_slider->setInvertedControls(true);
m_slider->setTickPosition(QSlider::TicksBothSides);
m_slider->setPageStep(1);
m_slider->setMinimum((swType == Board::SWITCH_3POS ? -1 : 0));
m_slider->setMinimum(-1);
m_slider->setMaximum(1);
m_slider->setTickInterval(1);
m_slider->setSingleStep(1);
m_slider->setTickInterval(m_stepSize);
m_slider->setSingleStep(m_stepSize);
m_slider->setPageStep(m_stepSize);
m_slider->setValue(m_value);
if (swType == Board::SWITCH_TOGGLE) {
@@ -101,20 +101,15 @@ class RadioSwitchWidget : public RadioWidget
connect(this, &RadioWidget::valueChanged, m_slider, &QSlider::setValue);
}
int getValue() const override
{
if (swType == Board::SWITCH_3POS)
return m_slider->value();
else
return m_slider->value() > 0 ? 1 : 0;
}
void setValueFromSlider(const int & value)
{
if (swType == Board::SWITCH_3POS)
RadioWidget::setValue(value);
else
RadioWidget::setValue(value ? 1 : -1);
// 2POS and TOGGLE switches do not have a center point - force slider value to 1 if dragged to center
if ((m_stepSize > 1) && (value == 0)) {
// Note: this will trigger another value changed event call back into this function, at which time setValue will be called below
m_slider->setValue(1);
return;
}
setValue(value);
}
void setToggleLocked(bool lock)
@@ -145,8 +140,10 @@ class RadioSwitchWidget : public RadioWidget
}
private:
Board::SwitchType swType;
QSlider * m_slider;
quint16 m_stepSize;
};
#endif // _RADIOSWITCHWIDGET_H_
@@ -66,13 +66,8 @@ void RadioWidget::setValue(const int & value)
if (value != m_value || m_valueReset) {
m_value = value;
m_valueReset = false;
// This 'emit valueChanged()' call can trigger another call into this function if the value is altered.
// This can happen with the TX16 6 Position switch control.
emit valueChanged(value);
// If actual value was changed by the 'emit valueChanged()' call above, then
// skip the 'valueChange' signal that would send the original value. We have already sent the signal with the updated value.
if (value == getValue())
emit valueChange(m_type, m_index, value);
emit valueChange(m_type, m_index, value);
}
}