From c505f9eb01bb190ae3f87a924de9118d4c7bde9a Mon Sep 17 00:00:00 2001 From: philmoz Date: Wed, 14 Dec 2022 19:57:01 +1100 Subject: [PATCH] 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 --- .../src/simulation/widgets/radioknobwidget.h | 210 +++++++++--------- .../simulation/widgets/radioswitchwidget.h | 45 ++-- .../src/simulation/widgets/radiowidget.cpp | 7 +- 3 files changed, 126 insertions(+), 136 deletions(-) diff --git a/companion/src/simulation/widgets/radioknobwidget.h b/companion/src/simulation/widgets/radioknobwidget.h index 8ded84ed9..590e0742e 100644 --- a/companion/src/simulation/widgets/radioknobwidget.h +++ b/companion/src/simulation/widgets/radioknobwidget.h @@ -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("

Value (input): %1

"); + 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(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("

Value (input): %1

"); - - 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(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; }; diff --git a/companion/src/simulation/widgets/radioswitchwidget.h b/companion/src/simulation/widgets/radioswitchwidget.h index 3346a437c..c1f01262c 100644 --- a/companion/src/simulation/widgets/radioswitchwidget.h +++ b/companion/src/simulation/widgets/radioswitchwidget.h @@ -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_ diff --git a/companion/src/simulation/widgets/radiowidget.cpp b/companion/src/simulation/widgets/radiowidget.cpp index 894f642ff..9e4d9177a 100644 --- a/companion/src/simulation/widgets/radiowidget.cpp +++ b/companion/src/simulation/widgets/radiowidget.cpp @@ -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); } }