From 3af6ff37ab29a0203f94297344818a1a9492542c Mon Sep 17 00:00:00 2001 From: Massimo Callegari Date: Thu, 9 Jan 2025 20:12:19 +0100 Subject: [PATCH] vc/xypad: add pan/tilt fine external controls Requested: https://www.qlcplus.org/forum/viewtopic.php?t=13383 --- debian/changelog | 1 + ui/src/virtualconsole/vcxypad.cpp | 90 +++++++++++++-------- ui/src/virtualconsole/vcxypad.h | 24 ++++-- ui/src/virtualconsole/vcxypadproperties.cpp | 80 +++++++++++++++++- ui/src/virtualconsole/vcxypadproperties.h | 8 ++ ui/src/virtualconsole/vcxypadproperties.ui | 47 ++++++----- 6 files changed, 183 insertions(+), 67 deletions(-) diff --git a/debian/changelog b/debian/changelog index b43e91743b..45cae2b7fa 100644 --- a/debian/changelog +++ b/debian/changelog @@ -11,6 +11,7 @@ qlcplus (4.14.0) stable; urgency=low * Virtual Console/Slider: send feedback on override button press * Virtual Console/Sped Dial: fix foreground color setting on Windows * Virtual Console/Frame: fix widget page initialization on Operate mode + * Virtual Console/XY Pad: added Pan/Tilt fine external controls * Plugins/OS2L: fix receiving multiple messages at once * Web Access: reworked websocket implementation * Web Access: fix grand master stopping running functions diff --git a/ui/src/virtualconsole/vcxypad.cpp b/ui/src/virtualconsole/vcxypad.cpp index 2f96ddbfaf..b5169763f9 100644 --- a/ui/src/virtualconsole/vcxypad.cpp +++ b/ui/src/virtualconsole/vcxypad.cpp @@ -57,6 +57,8 @@ const quint8 VCXYPad::panInputSourceId = 0; const quint8 VCXYPad::tiltInputSourceId = 1; const quint8 VCXYPad::widthInputSourceId = 2; const quint8 VCXYPad::heightInputSourceId = 3; +const quint8 VCXYPad::panFineInputSourceId = 4; +const quint8 VCXYPad::tiltFineInputSourceId = 5; const qreal MAX_VALUE = 256.0; const qreal MAX_DMX_VALUE = MAX_VALUE - 1.0/256; @@ -950,6 +952,39 @@ void VCXYPad::updateFeedback() */ } +void VCXYPad::updatePosition() +{ + QPointF pt = m_area->position(false); + qreal xOffset = 0; + qreal yOffset = 0; + qreal areaWidth = MAX_VALUE; + qreal areaHeight = MAX_VALUE; + + QRectF rangeWindow = m_area->rangeWindow(); + if (rangeWindow.isValid()) + { + xOffset = rangeWindow.x(); + yOffset = rangeWindow.y(); + areaWidth = rangeWindow.width(); + areaHeight = rangeWindow.height(); + } + + pt.setX(xOffset + SCALE((qreal(m_lastPos.x()) * 256.0) + qreal(m_lastPos.width()), qreal(0), qreal(65535), + qreal(0), areaWidth)); + + if (invertedAppearance() == false) + pt.setY(yOffset + SCALE((qreal(m_lastPos.y()) * 256.0) + qreal(m_lastPos.height()), qreal(0), qreal(65535), + qreal(0), areaHeight)); + else + pt.setY(yOffset + SCALE((qreal(m_lastPos.y()) * 256.0) + qreal(m_lastPos.height()), qreal(65535), qreal(0), + qreal(0), areaHeight)); + + m_inputValueChanged = true; + + m_area->setPosition(pt); + m_area->update(); +} + void VCXYPad::slotInputValueChanged(quint32 universe, quint32 channel, uchar value) { @@ -957,59 +992,55 @@ void VCXYPad::slotInputValueChanged(quint32 universe, quint32 channel, if (acceptsInput() == false) return; - QPointF pt = m_area->position(false); quint32 pagedCh = (page() << 16) | channel; if (checkInputSource(universe, pagedCh, value, sender(), panInputSourceId)) { if (m_efx == NULL) { - qreal areaWidth = MAX_VALUE; - qreal xOffset = 0; - QRectF rangeWindow = m_area->rangeWindow(); - if (rangeWindow.isValid()) - { - areaWidth = rangeWindow.width(); - xOffset = rangeWindow.x(); - } - pt.setX(xOffset + SCALE(qreal(value), qreal(0), qreal(255), - qreal(0), areaWidth)); + m_lastPos.setX(value); + updatePosition(); } else { if (m_efx->isRunning() == false) return; + m_hRangeSlider->setMinimumValue(value); slotRangeValueChanged(); return; } } + else if (checkInputSource(universe, pagedCh, value, sender(), panFineInputSourceId)) + { + if (m_efx == NULL) + { + m_lastPos.setWidth(value); + updatePosition(); + } + } else if (checkInputSource(universe, pagedCh, value, sender(), tiltInputSourceId)) { if (m_efx == NULL) { - qreal yOffset = 0; - qreal areaHeight = MAX_VALUE; - QRectF rangeWindow = m_area->rangeWindow(); - if (rangeWindow.isValid()) - { - areaHeight = rangeWindow.height(); - yOffset = rangeWindow.y(); - } - if (invertedAppearance() == false) - pt.setY(yOffset + SCALE(qreal(value), qreal(0), qreal(255), - qreal(0), areaHeight)); - else - pt.setY(yOffset + SCALE(qreal(value), qreal(255), qreal(0), - qreal(0), areaHeight)); + m_lastPos.setY(value); + updatePosition(); } else { if (m_efx->isRunning() == false) return; + m_vRangeSlider->setMinimumValue(value); slotRangeValueChanged(); - return; + } + } + else if (checkInputSource(universe, pagedCh, value, sender(), tiltFineInputSourceId)) + { + if (m_efx == NULL) + { + m_lastPos.setHeight(value); + updatePosition(); } } else if (checkInputSource(universe, pagedCh, value, sender(), widthInputSourceId)) @@ -1019,7 +1050,6 @@ void VCXYPad::slotInputValueChanged(quint32 universe, quint32 channel, m_hRangeSlider->setMaximumValue(value); slotRangeValueChanged(); } - return; } else if (checkInputSource(universe, pagedCh, value, sender(), heightInputSourceId)) { @@ -1028,7 +1058,6 @@ void VCXYPad::slotInputValueChanged(quint32 universe, quint32 channel, m_vRangeSlider->setMaximumValue(value); slotRangeValueChanged(); } - return; } else { @@ -1048,11 +1077,6 @@ void VCXYPad::slotInputValueChanged(quint32 universe, quint32 channel, } } } - - m_inputValueChanged = true; - - m_area->setPosition(pt); - m_area->update(); } void VCXYPad::slotKeyPressed(const QKeySequence &keySequence) diff --git a/ui/src/virtualconsole/vcxypad.h b/ui/src/virtualconsole/vcxypad.h index b193b48c59..ccdaebbe78 100644 --- a/ui/src/virtualconsole/vcxypad.h +++ b/ui/src/virtualconsole/vcxypad.h @@ -88,6 +88,8 @@ class VCXYPad : public VCWidget, public DMXSource static const quint8 tiltInputSourceId; static const quint8 widthInputSourceId; static const quint8 heightInputSourceId; + static const quint8 panFineInputSourceId; + static const quint8 tiltFineInputSourceId; /************************************************************************* * Initialization @@ -100,16 +102,16 @@ class VCXYPad : public VCWidget, public DMXSource void enableWidgetUI(bool enable); private: - QVBoxLayout* m_mainVbox; // main vertical layout - QHBoxLayout* m_padBox; // box containing sliders and XYPad - QVBoxLayout* m_lvbox; // left vertical box (vertical ctkSlider) - QVBoxLayout* m_cvbox; // center vertical box (horizontal ctkSlider + XYPad + horizontal slider) - QVBoxLayout* m_rvbox; // right vertical box (vertical slider) - QSlider* m_vSlider; // tilt slider - QSlider* m_hSlider; // pan slider + QVBoxLayout *m_mainVbox; // main vertical layout + QHBoxLayout *m_padBox; // box containing sliders and XYPad + QVBoxLayout *m_lvbox; // left vertical box (vertical ctkSlider) + QVBoxLayout *m_cvbox; // center vertical box (horizontal ctkSlider + XYPad + horizontal slider) + QVBoxLayout *m_rvbox; // right vertical box (vertical slider) + QSlider *m_vSlider; // tilt slider + QSlider *m_hSlider; // pan slider ctkRangeSlider *m_vRangeSlider; // range window height control ctkRangeSlider *m_hRangeSlider; // range window width control - VCXYPadArea* m_area; + VCXYPadArea *m_area; FlowLayout *m_presetsLayout; /************************************************************************* @@ -242,11 +244,17 @@ protected slots: public: void updateFeedback(); +protected: + void updatePosition(); + protected slots: /** Called when an external input device produces input data */ void slotInputValueChanged(quint32 universe, quint32 channel, uchar value); void slotKeyPressed(const QKeySequence& keySequence); +private: + QRect m_lastPos; + /************************************************************************* * QLC+ mode *************************************************************************/ diff --git a/ui/src/virtualconsole/vcxypadproperties.cpp b/ui/src/virtualconsole/vcxypadproperties.cpp index 30f68a1d1b..8365a9c0b2 100644 --- a/ui/src/virtualconsole/vcxypadproperties.cpp +++ b/ui/src/virtualconsole/vcxypadproperties.cpp @@ -93,6 +93,19 @@ VCXYPadProperties::VCXYPadProperties(VCXYPad* xypad, Doc* doc) connect(m_panInputWidget, SIGNAL(inputValueChanged(quint32,quint32)), this, SLOT(slotPanInputValueChanged(quint32,quint32))); + m_panFineInputWidget = new InputSelectionWidget(m_doc, this); + m_panFineInputWidget->setTitle(tr("Pan Fine")); + m_panFineInputWidget->setKeyInputVisibility(false); + m_panFineInputWidget->setInputSource(m_xypad->inputSource(VCXYPad::panFineInputSourceId)); + m_panFineInputWidget->setWidgetPage(m_xypad->page()); + m_panFineInputWidget->emitOddValues(true); + m_panFineInputWidget->show(); + m_extFineInputLayout->addWidget(m_panFineInputWidget); + connect(m_panFineInputWidget, SIGNAL(autoDetectToggled(bool)), + this, SLOT(slotPanFineAutoDetectToggled(bool))); + connect(m_panFineInputWidget, SIGNAL(inputValueChanged(quint32,quint32)), + this, SLOT(slotPanFineInputValueChanged(quint32,quint32))); + m_tiltInputWidget = new InputSelectionWidget(m_doc, this); m_tiltInputWidget->setTitle(tr("Tilt / Vertical Axis")); m_tiltInputWidget->setKeyInputVisibility(false); @@ -106,6 +119,19 @@ VCXYPadProperties::VCXYPadProperties(VCXYPad* xypad, Doc* doc) connect(m_tiltInputWidget, SIGNAL(inputValueChanged(quint32,quint32)), this, SLOT(slotTiltInputValueChanged(quint32,quint32))); + m_tiltFineInputWidget = new InputSelectionWidget(m_doc, this); + m_tiltFineInputWidget->setTitle(tr("Tilt Fine")); + m_tiltFineInputWidget->setKeyInputVisibility(false); + m_tiltFineInputWidget->setInputSource(m_xypad->inputSource(VCXYPad::tiltFineInputSourceId)); + m_tiltFineInputWidget->setWidgetPage(m_xypad->page()); + m_tiltFineInputWidget->emitOddValues(true); + m_tiltFineInputWidget->show(); + m_extFineInputLayout->addWidget(m_tiltFineInputWidget); + connect(m_tiltFineInputWidget, SIGNAL(autoDetectToggled(bool)), + this, SLOT(slotTiltFineAutoDetectToggled(bool))); + connect(m_tiltFineInputWidget, SIGNAL(inputValueChanged(quint32,quint32)), + this, SLOT(slotTiltFineInputValueChanged(quint32,quint32))); + m_widthInputWidget = new InputSelectionWidget(m_doc, this); m_widthInputWidget->setTitle(tr("Width")); m_widthInputWidget->setKeyInputVisibility(false); @@ -432,10 +458,26 @@ void VCXYPadProperties::slotDMXRadioChecked() * Input page ****************************************************************************/ -void VCXYPadProperties::slotPanAutoDetectToggled(bool toggled) +void VCXYPadProperties::stopAutodetection(quint8 sourceId) { - if (toggled == true && m_tiltInputWidget->isAutoDetecting()) + if (sourceId != VCXYPad::panInputSourceId) + m_panInputWidget->stopAutoDetection(); + if (sourceId != VCXYPad::panFineInputSourceId) + m_panFineInputWidget->stopAutoDetection(); + if (sourceId != VCXYPad::tiltInputSourceId) m_tiltInputWidget->stopAutoDetection(); + if (sourceId != VCXYPad::tiltFineInputSourceId) + m_tiltFineInputWidget->stopAutoDetection(); + if (sourceId != VCXYPad::widthInputSourceId) + m_widthInputWidget->stopAutoDetection(); + if (sourceId != VCXYPad::heightInputSourceId) + m_heightInputWidget->stopAutoDetection(); +} + +void VCXYPadProperties::slotPanAutoDetectToggled(bool toggled) +{ + if (toggled == true) + stopAutodetection(VCXYPad::panInputSourceId); } void VCXYPadProperties::slotPanInputValueChanged(quint32 uni, quint32 ch) @@ -446,10 +488,24 @@ void VCXYPadProperties::slotPanInputValueChanged(quint32 uni, quint32 ch) QSharedPointer(new QLCInputSource(uni, ch))); } +void VCXYPadProperties::slotPanFineAutoDetectToggled(bool toggled) +{ + if (toggled == true) + stopAutodetection(VCXYPad::panFineInputSourceId); +} + +void VCXYPadProperties::slotPanFineInputValueChanged(quint32 uni, quint32 ch) +{ + QSharedPointer tmpSource = m_panFineInputWidget->inputSource(); + if (tmpSource->universe() != uni || tmpSource->channel() != ch) + m_tiltFineInputWidget->setInputSource( + QSharedPointer(new QLCInputSource(uni, ch))); +} + void VCXYPadProperties::slotTiltAutoDetectToggled(bool toggled) { - if (toggled == true && m_panInputWidget->isAutoDetecting()) - m_panInputWidget->stopAutoDetection(); + if (toggled == true) + stopAutodetection(VCXYPad::tiltInputSourceId); } void VCXYPadProperties::slotTiltInputValueChanged(quint32 uni, quint32 ch) @@ -460,6 +516,20 @@ void VCXYPadProperties::slotTiltInputValueChanged(quint32 uni, quint32 ch) QSharedPointer(new QLCInputSource(uni, ch))); } +void VCXYPadProperties::slotTiltFineAutoDetectToggled(bool toggled) +{ + if (toggled == true) + stopAutodetection(VCXYPad::tiltFineInputSourceId); +} + +void VCXYPadProperties::slotTiltFineInputValueChanged(quint32 uni, quint32 ch) +{ + QSharedPointer tmpSource = m_tiltFineInputWidget->inputSource(); + if (tmpSource->universe() != uni || tmpSource->channel() != ch) + m_panFineInputWidget->setInputSource( + QSharedPointer(new QLCInputSource(uni, ch))); +} + void VCXYPadProperties::writeDMX(MasterTimer *timer, QList universes) { Q_UNUSED(timer); @@ -933,7 +1003,9 @@ void VCXYPadProperties::accept() m_xypad->clearFixtures(); m_xypad->setCaption(m_nameEdit->text()); m_xypad->setInputSource(m_panInputWidget->inputSource(), VCXYPad::panInputSourceId); + m_xypad->setInputSource(m_panFineInputWidget->inputSource(), VCXYPad::panFineInputSourceId); m_xypad->setInputSource(m_tiltInputWidget->inputSource(), VCXYPad::tiltInputSourceId); + m_xypad->setInputSource(m_tiltFineInputWidget->inputSource(), VCXYPad::tiltFineInputSourceId); m_xypad->setInputSource(m_widthInputWidget->inputSource(), VCXYPad::widthInputSourceId); m_xypad->setInputSource(m_heightInputWidget->inputSource(), VCXYPad::heightInputSourceId); if (m_YNormalRadio->isChecked()) diff --git a/ui/src/virtualconsole/vcxypadproperties.h b/ui/src/virtualconsole/vcxypadproperties.h index c075cbf3b0..543b7dd530 100644 --- a/ui/src/virtualconsole/vcxypadproperties.h +++ b/ui/src/virtualconsole/vcxypadproperties.h @@ -53,7 +53,9 @@ class VCXYPadProperties : public QDialog, public Ui_VCXYPadProperties, public DM VCXYPad *m_xypad; Doc *m_doc; InputSelectionWidget *m_panInputWidget; + InputSelectionWidget *m_panFineInputWidget; InputSelectionWidget *m_tiltInputWidget; + InputSelectionWidget *m_tiltFineInputWidget; InputSelectionWidget *m_widthInputWidget; InputSelectionWidget *m_heightInputWidget; @@ -69,6 +71,8 @@ class VCXYPadProperties : public QDialog, public Ui_VCXYPadProperties, public DM void updateFixtureItem(QTreeWidgetItem* item, const VCXYPadFixture& fxi); void removeFixtureItem(GroupHead const & head); + void stopAutodetection(quint8 sourceId); + private slots: void slotAddClicked(); void slotRemoveClicked(); @@ -85,8 +89,12 @@ private slots: private slots: void slotPanAutoDetectToggled(bool toggled); void slotPanInputValueChanged(quint32 uni, quint32 ch); + void slotPanFineAutoDetectToggled(bool toggled); + void slotPanFineInputValueChanged(quint32 uni, quint32 ch); void slotTiltAutoDetectToggled(bool toggled); void slotTiltInputValueChanged(quint32 uni, quint32 ch); + void slotTiltFineAutoDetectToggled(bool toggled); + void slotTiltFineInputValueChanged(quint32 uni, quint32 ch); /******************************************************************** * Presets diff --git a/ui/src/virtualconsole/vcxypadproperties.ui b/ui/src/virtualconsole/vcxypadproperties.ui index d39dd7562f..da55d864c6 100644 --- a/ui/src/virtualconsole/vcxypadproperties.ui +++ b/ui/src/virtualconsole/vcxypadproperties.ui @@ -7,14 +7,14 @@ Copyright (c) 2015 Massimo Callegari - Licensed under the Apache License, Version 2.0 (the "License"); + Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0.txt Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, + distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. @@ -36,10 +36,10 @@ - Qt::Horizontal + Qt::Orientation::Horizontal - QDialogButtonBox::Cancel|QDialogButtonBox::Ok + QDialogButtonBox::StandardButton::Cancel|QDialogButtonBox::StandardButton::Ok @@ -56,10 +56,10 @@ - QFrame::NoFrame + QFrame::Shape::NoFrame - QFrame::Raised + QFrame::Shadow::Raised @@ -77,6 +77,9 @@ + + + @@ -86,7 +89,7 @@ - Qt::Vertical + Qt::Orientation::Vertical @@ -155,7 +158,7 @@ true - QAbstractItemView::ExtendedSelection + QAbstractItemView::SelectionMode::ExtendedSelection false @@ -195,7 +198,7 @@ ... - + :/edit_add.png:/edit_add.png @@ -215,7 +218,7 @@ ... - + :/edit_remove.png:/edit_remove.png @@ -235,7 +238,7 @@ ... - + :/edit.png:/edit.png @@ -285,7 +288,7 @@ - Qt::Vertical + Qt::Orientation::Vertical @@ -333,7 +336,7 @@ Add position - + :/xypad.png:/xypad.png @@ -344,7 +347,7 @@ Add EFX - + :/efx.png:/efx.png @@ -355,7 +358,7 @@ Add Scene - + :/scene.png:/scene.png @@ -366,7 +369,7 @@ Add Fixture Group - + :/group.png:/group.png @@ -377,7 +380,7 @@ Remove - + :/edit_remove.png:/edit_remove.png @@ -388,7 +391,7 @@ Move Up - + :/up.png:/up.png @@ -399,7 +402,7 @@ Move Down - + :/down.png:/down.png @@ -438,10 +441,10 @@ - QFrame::NoFrame + QFrame::Shape::NoFrame - QFrame::Raised + QFrame::Shadow::Raised @@ -469,7 +472,7 @@ - +