From be1f865e5802122d717de4c0497748d00bb0508e Mon Sep 17 00:00:00 2001 From: Massimo Callegari Date: Sun, 27 Oct 2024 19:39:13 +0100 Subject: [PATCH 01/68] qmlui: make sure fixture and fixture group names are unique --- qmlui/fixturemanager.cpp | 36 +++++++++++++------ qmlui/fixturemanager.h | 4 +-- .../fixturesfunctions/FixtureGroupManager.qml | 20 ++++++++--- .../fixturesfunctions/FixtureNodeDelegate.qml | 12 +++++-- 4 files changed, 53 insertions(+), 19 deletions(-) diff --git a/qmlui/fixturemanager.cpp b/qmlui/fixturemanager.cpp index 6d0c030b3a..9b03b29f24 100644 --- a/qmlui/fixturemanager.cpp +++ b/qmlui/fixturemanager.cpp @@ -285,12 +285,6 @@ bool FixtureManager::addFixture(QString manuf, QString model, QString mode, QStr fxAddress = 0; } - /* If we're adding more than one fixture, - append a number to the end of the name */ - if (quantity > 1) - fxi->setName(QString("%1 #%2").arg(name).arg(i + 1)); - else - fxi->setName(name); fxi->setAddress(fxAddress); fxi->setUniverse(uniIdx); if (fxiDef == nullptr && fxiMode == nullptr) @@ -311,6 +305,7 @@ bool FixtureManager::addFixture(QString manuf, QString model, QString mode, QStr if (m_doc->addFixture(fxi) == true) { + fxi->setName(QString("%1 [%2]").arg(name).arg(fxi->id() + 1)); Tardis::instance()->enqueueAction(Tardis::FixtureCreate, fxi->id(), QVariant(), Tardis::instance()->actionToByteArray(Tardis::FixtureCreate, fxi->id())); slotFixtureAdded(fxi->id(), QVector3D(xPos, yPos, 0)); @@ -393,7 +388,7 @@ bool FixtureManager::deleteFixtureInGroup(quint32 groupID, quint32 itemID, QStri return true; } -void FixtureManager::renameFixture(quint32 itemID, QString newName) +bool FixtureManager::renameFixture(quint32 itemID, QString newName) { quint32 fixtureID = FixtureUtils::itemFixtureID(itemID); //quint16 headIndex = FixtureUtils::itemHeadIndex(itemID); @@ -401,12 +396,21 @@ void FixtureManager::renameFixture(quint32 itemID, QString newName) Fixture *fixture = m_doc->fixture(fixtureID); if (fixture == nullptr) - return; + return false; + + QList fixtureList = m_doc->fixtures(); + for (Fixture *docFixture : fixtureList) + { + if (docFixture->name() == newName) + return false; + } Tardis::instance()->enqueueAction(Tardis::FixtureSetName, itemID, fixture->name(), newName); setItemRoleData(itemID, -1, "label", newName); fixture->setName(newName); + + return true; } int FixtureManager::fixturesCount() @@ -1156,16 +1160,28 @@ void FixtureManager::updateFixtureGroup(quint32 groupID, quint32 itemID, int hea //m_fixtureTree->printTree(); // enable for debug purposes } -void FixtureManager::renameFixtureGroup(quint32 groupID, QString newName) +bool FixtureManager::renameFixtureGroup(quint32 groupID, QString newName) { FixtureGroup *group = m_doc->fixtureGroup(groupID); if (group == nullptr) - return; + return false; + + // check for same name among existing groups + QList groupList = m_doc->fixtureGroups(); + for (FixtureGroup *docGroup : groupList) + if (docGroup->name() == newName) + return false; + + // check also among universe names since they are represented as groups + for (QString &uniName : m_doc->inputOutputMap()->universeNames()) + if (uniName == newName) + return false; group->setName(newName); updateGroupsTree(m_doc, m_fixtureTree, m_searchFilter); emit groupsTreeModelChanged(); + return true; } bool FixtureManager::deleteFixtureGroups(QVariantList IDList) diff --git a/qmlui/fixturemanager.h b/qmlui/fixturemanager.h index ce95b71904..1bf25d8707 100644 --- a/qmlui/fixturemanager.h +++ b/qmlui/fixturemanager.h @@ -171,7 +171,7 @@ public slots: Q_INVOKABLE bool deleteFixtureInGroup(quint32 groupID, quint32 itemID, QString path); /** Rename the Fixture with the provided $itemID to $newName */ - Q_INVOKABLE void renameFixture(quint32 itemID, QString newName); + Q_INVOKABLE bool renameFixture(quint32 itemID, QString newName); /** Returns the number of fixtures currently loaded in the project */ int fixturesCount(); @@ -275,7 +275,7 @@ public slots: Q_INVOKABLE void updateFixtureGroup(quint32 groupID, quint32 itemID, int headIdx); - Q_INVOKABLE void renameFixtureGroup(quint32 groupID, QString newName); + Q_INVOKABLE bool renameFixtureGroup(quint32 groupID, QString newName); /** Delete some existing Fixture Groups with IDs provided by $IDList */ Q_INVOKABLE bool deleteFixtureGroups(QVariantList IDList); diff --git a/qmlui/qml/fixturesfunctions/FixtureGroupManager.qml b/qmlui/qml/fixturesfunctions/FixtureGroupManager.qml index dc827b164d..3d801c6fdb 100644 --- a/qmlui/qml/fixturesfunctions/FixtureGroupManager.qml +++ b/qmlui/qml/fixturesfunctions/FixtureGroupManager.qml @@ -234,7 +234,9 @@ Rectangle title: qsTr("Rename items") onAccepted: { - var item; + var item + var ret + if (numberingEnabled) { var currNum = startNumber @@ -251,10 +253,12 @@ Rectangle currNum++ if (item.itemType === App.FixtureDragItem) - fixtureManager.renameFixture(item.itemID, finalName) + ret = fixtureManager.renameFixture(item.itemID, finalName) else if (item.itemType === App.FixtureGroupDragItem) - fixtureManager.renameFixtureGroup(item.itemID, finalName) + ret = fixtureManager.renameFixtureGroup(item.itemID, finalName) + if (ret === false) + break } } else @@ -262,9 +266,15 @@ Rectangle item = gfhcDragItem.itemsList[0]; if (item.itemType === App.FixtureDragItem) - fixtureManager.renameFixture(item.itemID, editText) + ret = fixtureManager.renameFixture(item.itemID, editText) else if (item.itemType === App.FixtureGroupDragItem) - fixtureManager.renameFixtureGroup(item.itemID, editText) + ret = fixtureManager.renameFixtureGroup(item.itemID, editText) + } + + if (ret === false) + { + fmGenericPopup.message = qsTr("An item with the same name already exists.\nPlease provide a different name.") + fmGenericPopup.open() } } } diff --git a/qmlui/qml/fixturesfunctions/FixtureNodeDelegate.qml b/qmlui/qml/fixturesfunctions/FixtureNodeDelegate.qml index 739e084412..846871a05b 100644 --- a/qmlui/qml/fixturesfunctions/FixtureNodeDelegate.qml +++ b/qmlui/qml/fixturesfunctions/FixtureNodeDelegate.qml @@ -136,8 +136,16 @@ Column onTextConfirmed: { - nodeContainer.pathChanged(nodePath, text) - fixtureManager.renameFixture(itemID, text) + if (fixtureManager.renameFixture(itemID, text) === false) + { + fmGenericPopup.message = qsTr("An item with the same name already exists.\nPlease provide a different name.") + fmGenericPopup.open() + nodeLabel.text = textLabel + } + else + { + nodeContainer.pathChanged(nodePath, text) + } } } From fc5acaed225a05edff6cba50ab5b1fdede96f0a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hans-J=C3=BCrgen=20Tappe?= Date: Sun, 27 Oct 2024 19:52:44 +0100 Subject: [PATCH 02/68] Fix out-of-bounds error when selecting too many balls. When setting the number to e.g. 15, the index overran. --- resources/rgbscripts/ballscolors.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/rgbscripts/ballscolors.js b/resources/rgbscripts/ballscolors.js index 994cacfde4..a000828dec 100644 --- a/resources/rgbscripts/ballscolors.js +++ b/resources/rgbscripts/ballscolors.js @@ -207,7 +207,7 @@ var testAlgo; var yDirection = (Math.random() * 2) - 1; // and random directions var xDirection = (Math.random() * 2) - 1; algo.direction[i] = [yDirection, xDirection]; - algo.colour[i] = colorPalette.collection[algo.colorIndex[i]][1]; + algo.colour[i] = colorPalette.collection[algo.colorIndex[i % algo.colorIndex.length]][1]; } algo.initialized = true; return; From 3a63e202c8917385a1ec5836a650c81f53894873 Mon Sep 17 00:00:00 2001 From: Massimo Callegari Date: Sun, 27 Oct 2024 22:00:00 +0100 Subject: [PATCH 03/68] resources: fix fixture physical dimensions --- .../Flash-Butrym/Flash-Butrym-LED-PAR-64-7x10W-RGBW.qxf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/fixtures/Flash-Butrym/Flash-Butrym-LED-PAR-64-7x10W-RGBW.qxf b/resources/fixtures/Flash-Butrym/Flash-Butrym-LED-PAR-64-7x10W-RGBW.qxf index 42fbddc565..73641b4def 100644 --- a/resources/fixtures/Flash-Butrym/Flash-Butrym-LED-PAR-64-7x10W-RGBW.qxf +++ b/resources/fixtures/Flash-Butrym/Flash-Butrym-LED-PAR-64-7x10W-RGBW.qxf @@ -52,7 +52,7 @@ - + From e112a14f9870304ee4d29fddbafa06cb00d1f8bb Mon Sep 17 00:00:00 2001 From: Massimo Callegari Date: Sun, 27 Oct 2024 22:00:27 +0100 Subject: [PATCH 04/68] qmlui: more unique naming handling --- qmlui/fixturemanager.cpp | 20 +++++++++++++--- qmlui/functionmanager.cpp | 23 +++++++++++-------- qmlui/functionmanager.h | 2 +- .../FixtureBrowserDelegate.qml | 4 ++++ qmlui/qml/fixturesfunctions/RightPanel.qml | 16 ++++++++++++- 5 files changed, 50 insertions(+), 15 deletions(-) diff --git a/qmlui/fixturemanager.cpp b/qmlui/fixturemanager.cpp index 9b03b29f24..1ff875fc74 100644 --- a/qmlui/fixturemanager.cpp +++ b/qmlui/fixturemanager.cpp @@ -1088,7 +1088,7 @@ void FixtureManager::addFixturesToNewGroup(QList fxList) int headsCount = 0; for (quint32 id : fxList) { - Fixture* fxi = m_doc->fixture(id); + Fixture *fxi = m_doc->fixture(id); if (fxi != nullptr) headsCount += fxi->heads(); } @@ -1235,11 +1235,24 @@ bool FixtureManager::addRGBPanel(QString name, qreal xPos, qreal yPos) FixtureGroup *grp = new FixtureGroup(m_doc); Q_ASSERT(grp != nullptr); - grp->setName(name); + QSize panelSize(columns, rows); grp->setSize(panelSize); m_doc->addFixtureGroup(grp); + // make sure the name is unique + QList groupList = m_doc->fixtureGroups(); + for (FixtureGroup *docGroup : groupList) + { + if (docGroup->name() == name) + { + name = QString ("%1 [%2]").arg(name).arg(grp->id()); + break; + } + } + + grp->setName(name); + int transpose = 0; if (direction == Vertical) { @@ -1402,6 +1415,7 @@ bool FixtureManager::addRGBPanel(QString name, qreal xPos, qreal yPos) m_fixtureList.clear(); m_fixtureList = m_doc->fixtures(); + updateGroupsTree(m_doc, m_fixtureTree, m_searchFilter); emit fixturesCountChanged(); emit fixturesMapChanged(); @@ -1790,7 +1804,7 @@ QMultiHash FixtureManager::getFixtureCapabilities(quint32 itemI for (quint32 ch : channelIndices) { - const QLCChannel* channel(fixture->channel(ch)); + const QLCChannel *channel(fixture->channel(ch)); if (channel == nullptr) continue; diff --git a/qmlui/functionmanager.cpp b/qmlui/functionmanager.cpp index 1af5da786a..fa7e3b066e 100644 --- a/qmlui/functionmanager.cpp +++ b/qmlui/functionmanager.cpp @@ -866,10 +866,10 @@ void FunctionManager::deleteSequenceFixtures(QVariantList list) m_sceneEditor->deleteItems(list); } -void FunctionManager::renameSelectedItems(QString newName, bool numbering, int startNumber, int digits) +bool FunctionManager::renameSelectedItems(QString newName, bool numbering, int startNumber, int digits) { if (m_selectedIDList.isEmpty() && m_selectedFolderList.isEmpty()) - return; + return false; int currNumber = startNumber; @@ -883,19 +883,22 @@ void FunctionManager::renameSelectedItems(QString newName, bool numbering, int s if (f == nullptr) continue; + QString fName = newName.simplified(); + if (numbering) { - QString fName = QString("%1 %2").arg(newName.simplified()).arg(currNumber, digits, 10, QChar('0')); - Tardis::instance()->enqueueAction(Tardis::FunctionSetName, f->id(), f->name(), fName); - f->setName(fName); + fName = QString("%1 %2").arg(fName).arg(currNumber, digits, 10, QChar('0')); currNumber++; } - else - { - Tardis::instance()->enqueueAction(Tardis::FunctionSetName, f->id(), f->name(), newName.simplified()); - f->setName(newName.simplified()); - } + + if (m_doc->functionByName(fName) != nullptr) + return false; + + Tardis::instance()->enqueueAction(Tardis::FunctionSetName, f->id(), f->name(), fName); + f->setName(fName); } + + return true; } int FunctionManager::selectedFunctionCount() const diff --git a/qmlui/functionmanager.h b/qmlui/functionmanager.h index 2b8861b1d6..ae753bfe7a 100644 --- a/qmlui/functionmanager.h +++ b/qmlui/functionmanager.h @@ -169,7 +169,7 @@ class FunctionManager : public QObject * with the provided $newName. * If $numbering is true, then $startNumber and $digits will compose * a progress number following $newName */ - Q_INVOKABLE void renameSelectedItems(QString newName, bool numbering, int startNumber, int digits); + Q_INVOKABLE bool renameSelectedItems(QString newName, bool numbering, int startNumber, int digits); /** Returns the number of the currently selected Functions */ int selectedFunctionCount() const; diff --git a/qmlui/qml/fixturesfunctions/FixtureBrowserDelegate.qml b/qmlui/qml/fixturesfunctions/FixtureBrowserDelegate.qml index b7fe91a0a7..dab65e07cf 100644 --- a/qmlui/qml/fixturesfunctions/FixtureBrowserDelegate.qml +++ b/qmlui/qml/fixturesfunctions/FixtureBrowserDelegate.qml @@ -125,10 +125,14 @@ Item } } onPositionChanged: + { if (fxDraggableItem.isManufacturer == false && drag.active == true) FxDragJS.handleDrag(mouse) + } onReleased: + { if (fxDraggableItem.isManufacturer == false && drag.active == true) FxDragJS.endDrag(mouse) + } } } diff --git a/qmlui/qml/fixturesfunctions/RightPanel.qml b/qmlui/qml/fixturesfunctions/RightPanel.qml index 7cc0880b70..bae1a15a29 100644 --- a/qmlui/qml/fixturesfunctions/RightPanel.qml +++ b/qmlui/qml/fixturesfunctions/RightPanel.qml @@ -143,6 +143,15 @@ SidePanel } } + CustomPopupDialog + { + id: fmGenericPopup + visible: false + title: qsTr("Error") + message: "" + onAccepted: {} + } + Rectangle { width: collapseWidth @@ -257,7 +266,12 @@ SidePanel title: qsTr("Rename items") onAccepted: { - functionManager.renameSelectedItems(editText, numberingEnabled, startNumber, digits) + if (functionManager.renameSelectedItems(editText, numberingEnabled, startNumber, digits) === false) + { + fmGenericPopup.message = qsTr("An item with the same name already exists.\nPlease provide a different name.") + fmGenericPopup.open() + } + } } } From aba410197f1f78daeff476adf4e65f91b86ec70f Mon Sep 17 00:00:00 2001 From: Massimo Callegari Date: Mon, 28 Oct 2024 08:43:05 +0100 Subject: [PATCH 05/68] actions: bump macos runner version --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 79c72132cc..945c626f8c 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -492,7 +492,7 @@ jobs: path: ${{matrix.task}}-${{env.OUTFILE}} build-macos: - runs-on: macos-12 + runs-on: macos-13 name: QLCplus macOS ${{matrix.task}} strategy: fail-fast: false From 1f7f95ab7a0267e7b0e492720aa62ccce230d73c Mon Sep 17 00:00:00 2001 From: Massimo Callegari Date: Tue, 29 Oct 2024 18:05:12 +0100 Subject: [PATCH 06/68] ui: cleanup cmake file --- ui/src/CMakeLists.txt | 585 +----------------------------------------- 1 file changed, 5 insertions(+), 580 deletions(-) diff --git a/ui/src/CMakeLists.txt b/ui/src/CMakeLists.txt index acb69d739b..1c98110a9d 100644 --- a/ui/src/CMakeLists.txt +++ b/ui/src/CMakeLists.txt @@ -19,22 +19,6 @@ else() qt5_add_translation(QM_FILES ${TS_FILES}) endif() -if((((QT_VERSION_MAJOR LESS 5)) AND (APPLE))) - if (${PORTAUDIO_2_FOUND}) - target_compile_definitions(${module_name} PUBLIC - HAS_PORTAUDIO - ) - - target_include_directories(${module_name} PUBLIC - ${PORTAUDIO_2_INCLUDE_DIRS} - ) - - target_link_libraries(${module_name} PUBLIC - ${PORTAUDIO_2_LIBRARIES} - ) - endif() -endif() - add_library(${module_name} SHARED ../../plugins/interfaces/rdmprotocol.cpp ../../plugins/interfaces/rdmprotocol.h @@ -182,583 +166,24 @@ target_link_libraries(${module_name} PUBLIC ) # Resources: -set_source_files_properties("../../resources/icons/png/add_dump.png" - PROPERTIES QT_RESOURCE_ALIAS "add_dump.png" -) -set_source_files_properties("../../resources/icons/png/animation.png" - PROPERTIES QT_RESOURCE_ALIAS "animation.png" -) -set_source_files_properties("../../resources/icons/png/attach.png" - PROPERTIES QT_RESOURCE_ALIAS "attach.png" -) -set_source_files_properties("../../resources/icons/png/audio.png" - PROPERTIES QT_RESOURCE_ALIAS "audio.png" -) -set_source_files_properties("../../resources/icons/png/audioinput.png" - PROPERTIES QT_RESOURCE_ALIAS "audioinput.png" -) -set_source_files_properties("../../resources/icons/png/autostart.png" - PROPERTIES QT_RESOURCE_ALIAS "autostart.png" -) -set_source_files_properties("../../resources/icons/png/back.png" - PROPERTIES QT_RESOURCE_ALIAS "back.png" -) -set_source_files_properties("../../resources/icons/png/beam.png" - PROPERTIES QT_RESOURCE_ALIAS "beam.png" -) -set_source_files_properties("../../resources/icons/png/blackout.png" - PROPERTIES QT_RESOURCE_ALIAS "blackout.png" -) -set_source_files_properties("../../resources/icons/png/blind.png" - PROPERTIES QT_RESOURCE_ALIAS "blind.png" -) -set_source_files_properties("../../resources/icons/png/button.png" - PROPERTIES QT_RESOURCE_ALIAS "button.png" -) -set_source_files_properties("../../resources/icons/png/buttonmatrix.png" - PROPERTIES QT_RESOURCE_ALIAS "buttonmatrix.png" -) -set_source_files_properties("../../resources/icons/png/chaser.png" - PROPERTIES QT_RESOURCE_ALIAS "chaser.png" -) -set_source_files_properties("../../resources/icons/png/check.png" - PROPERTIES QT_RESOURCE_ALIAS "check.png" -) -set_source_files_properties("../../resources/icons/png/checkbox_empty.png" - PROPERTIES QT_RESOURCE_ALIAS "checkbox_empty.png" -) -set_source_files_properties("../../resources/icons/png/checkbox_full.png" - PROPERTIES QT_RESOURCE_ALIAS "checkbox_full.png" -) -set_source_files_properties("../../resources/icons/png/clock.png" - PROPERTIES QT_RESOURCE_ALIAS "clock.png" -) -set_source_files_properties("../../resources/icons/png/collection.png" - PROPERTIES QT_RESOURCE_ALIAS "collection.png" -) -set_source_files_properties("../../resources/icons/png/color.png" - PROPERTIES QT_RESOURCE_ALIAS "color.png" -) -set_source_files_properties("../../resources/icons/png/colorwheel.png" - PROPERTIES QT_RESOURCE_ALIAS "colorwheel.png" -) -set_source_files_properties("../../resources/icons/png/configure.png" - PROPERTIES QT_RESOURCE_ALIAS "configure.png" -) -set_source_files_properties("../../resources/icons/png/cuelist.png" - PROPERTIES QT_RESOURCE_ALIAS "cuelist.png" -) -set_source_files_properties("../../resources/icons/png/current.png" - PROPERTIES QT_RESOURCE_ALIAS "current.png" -) -set_source_files_properties("../../resources/icons/png/delete.png" - PROPERTIES QT_RESOURCE_ALIAS "delete.png" -) -set_source_files_properties("../../resources/icons/png/design.png" - PROPERTIES QT_RESOURCE_ALIAS "design.png" -) -set_source_files_properties("../../resources/icons/png/detach.png" - PROPERTIES QT_RESOURCE_ALIAS "detach.png" -) -set_source_files_properties("../../resources/icons/png/dimmer.png" - PROPERTIES QT_RESOURCE_ALIAS "dimmer.png" -) -set_source_files_properties("../../resources/icons/png/diptool.png" - PROPERTIES QT_RESOURCE_ALIAS "diptool.png" -) -set_source_files_properties("../../resources/icons/png/down.png" - PROPERTIES QT_RESOURCE_ALIAS "down.png" -) -set_source_files_properties("../../resources/icons/png/ds_border.png" - PROPERTIES QT_RESOURCE_ALIAS "ds_border.png" -) -set_source_files_properties("../../resources/icons/png/ds_bottom.png" - PROPERTIES QT_RESOURCE_ALIAS "ds_bottom.png" -) -set_source_files_properties("../../resources/icons/png/ds_off.png" - PROPERTIES QT_RESOURCE_ALIAS "ds_off.png" -) -set_source_files_properties("../../resources/icons/png/ds_on.png" - PROPERTIES QT_RESOURCE_ALIAS "ds_on.png" -) -set_source_files_properties("../../resources/icons/png/ds_top.png" - PROPERTIES QT_RESOURCE_ALIAS "ds_top.png" -) -set_source_files_properties("../../resources/icons/png/edit.png" - PROPERTIES QT_RESOURCE_ALIAS "edit.png" -) -set_source_files_properties("../../resources/icons/png/edit_add.png" - PROPERTIES QT_RESOURCE_ALIAS "edit_add.png" -) -set_source_files_properties("../../resources/icons/png/edit_remove.png" - PROPERTIES QT_RESOURCE_ALIAS "edit_remove.png" -) -set_source_files_properties("../../resources/icons/png/editclear.png" - PROPERTIES QT_RESOURCE_ALIAS "editclear.png" -) -set_source_files_properties("../../resources/icons/png/editcopy.png" - PROPERTIES QT_RESOURCE_ALIAS "editcopy.png" -) -set_source_files_properties("../../resources/icons/png/editcopyall.png" - PROPERTIES QT_RESOURCE_ALIAS "editcopyall.png" -) -set_source_files_properties("../../resources/icons/png/editcut.png" - PROPERTIES QT_RESOURCE_ALIAS "editcut.png" -) -set_source_files_properties("../../resources/icons/png/editdelete.png" - PROPERTIES QT_RESOURCE_ALIAS "editdelete.png" -) -set_source_files_properties("../../resources/icons/png/editpaste.png" - PROPERTIES QT_RESOURCE_ALIAS "editpaste.png" -) -set_source_files_properties("../../resources/icons/png/effect.png" - PROPERTIES QT_RESOURCE_ALIAS "effect.png" -) -set_source_files_properties("../../resources/icons/png/efx.png" - PROPERTIES QT_RESOURCE_ALIAS "efx.png" -) -set_source_files_properties("../../resources/icons/png/exit.png" - PROPERTIES QT_RESOURCE_ALIAS "exit.png" -) -set_source_files_properties("../../resources/icons/png/expand.png" - PROPERTIES QT_RESOURCE_ALIAS "expand.png" -) -set_source_files_properties("../../resources/icons/png/fade.png" - PROPERTIES QT_RESOURCE_ALIAS "fade.png" -) -set_source_files_properties("../../resources/icons/png/fan.png" - PROPERTIES QT_RESOURCE_ALIAS "fan.png" -) -set_source_files_properties("../../resources/icons/png/fileclose.png" - PROPERTIES QT_RESOURCE_ALIAS "fileclose.png" -) -set_source_files_properties("../../resources/icons/png/fileexport.png" - PROPERTIES QT_RESOURCE_ALIAS "fileexport.png" -) -set_source_files_properties("../../resources/icons/png/fileimport.png" - PROPERTIES QT_RESOURCE_ALIAS "fileimport.png" -) -set_source_files_properties("../../resources/icons/png/filenew.png" - PROPERTIES QT_RESOURCE_ALIAS "filenew.png" -) -set_source_files_properties("../../resources/icons/png/fileopen.png" - PROPERTIES QT_RESOURCE_ALIAS "fileopen.png" -) -set_source_files_properties("../../resources/icons/png/filesave.png" - PROPERTIES QT_RESOURCE_ALIAS "filesave.png" -) -set_source_files_properties("../../resources/icons/png/filesaveas.png" - PROPERTIES QT_RESOURCE_ALIAS "filesaveas.png" -) -set_source_files_properties("../../resources/icons/png/fixture.png" - PROPERTIES QT_RESOURCE_ALIAS "fixture.png" -) -set_source_files_properties("../../resources/icons/png/flash.png" - PROPERTIES QT_RESOURCE_ALIAS "flash.png" -) -set_source_files_properties("../../resources/icons/png/flower.png" - PROPERTIES QT_RESOURCE_ALIAS "flower.png" -) -set_source_files_properties("../../resources/icons/png/folder.png" - PROPERTIES QT_RESOURCE_ALIAS "folder.png" -) -set_source_files_properties("../../resources/icons/png/fontcolor.png" - PROPERTIES QT_RESOURCE_ALIAS "fontcolor.png" -) -set_source_files_properties("../../resources/icons/png/fonts.png" - PROPERTIES QT_RESOURCE_ALIAS "fonts.png" -) -set_source_files_properties("../../resources/icons/png/forward.png" - PROPERTIES QT_RESOURCE_ALIAS "forward.png" -) -set_source_files_properties("../../resources/icons/png/frame.png" - PROPERTIES QT_RESOURCE_ALIAS "frame.png" -) -set_source_files_properties("../../resources/icons/png/frameraised.png" - PROPERTIES QT_RESOURCE_ALIAS "frameraised.png" -) -set_source_files_properties("../../resources/icons/png/framesunken.png" - PROPERTIES QT_RESOURCE_ALIAS "framesunken.png" -) -set_source_files_properties("../../resources/icons/png/fullscreen.png" - PROPERTIES QT_RESOURCE_ALIAS "fullscreen.png" -) -set_source_files_properties("../../resources/icons/png/function.png" - PROPERTIES QT_RESOURCE_ALIAS "function.png" -) -set_source_files_properties("../../resources/icons/png/global.png" - PROPERTIES QT_RESOURCE_ALIAS "global.png" -) -set_source_files_properties("../../resources/icons/png/gobo.png" - PROPERTIES QT_RESOURCE_ALIAS "gobo.png" -) -set_source_files_properties("../../resources/icons/png/grid.png" - PROPERTIES QT_RESOURCE_ALIAS "grid.png" -) -set_source_files_properties("../../resources/icons/png/group.png" - PROPERTIES QT_RESOURCE_ALIAS "group.png" -) -set_source_files_properties("../../resources/icons/png/hazer.png" - PROPERTIES QT_RESOURCE_ALIAS "hazer.png" -) -set_source_files_properties("../../resources/icons/png/help.png" - PROPERTIES QT_RESOURCE_ALIAS "help.png" -) -set_source_files_properties("../../resources/icons/png/image.png" - PROPERTIES QT_RESOURCE_ALIAS "image.png" -) -set_source_files_properties("../../resources/icons/png/input.png" - PROPERTIES QT_RESOURCE_ALIAS "input.png" -) -set_source_files_properties("../../resources/icons/png/input_output.png" - PROPERTIES QT_RESOURCE_ALIAS "input_output.png" -) -set_source_files_properties("../../resources/icons/png/intensity.png" - PROPERTIES QT_RESOURCE_ALIAS "intensity.png" -) -set_source_files_properties("../../resources/icons/png/key_bindings.png" - PROPERTIES QT_RESOURCE_ALIAS "key_bindings.png" -) -set_source_files_properties("../../resources/icons/png/knob.png" - PROPERTIES QT_RESOURCE_ALIAS "knob.png" -) -set_source_files_properties("../../resources/icons/png/label.png" - PROPERTIES QT_RESOURCE_ALIAS "label.png" -) -set_source_files_properties("../../resources/icons/png/laser.png" - PROPERTIES QT_RESOURCE_ALIAS "laser.png" -) -set_source_files_properties("../../resources/icons/png/ledbar_beams.png" - PROPERTIES QT_RESOURCE_ALIAS "ledbar_beams.png" -) -set_source_files_properties("../../resources/icons/png/ledbar_pixels.png" - PROPERTIES QT_RESOURCE_ALIAS "ledbar_pixels.png" -) -set_source_files_properties("../../resources/icons/png/liveedit.png" - PROPERTIES QT_RESOURCE_ALIAS "liveedit.png" -) -set_source_files_properties("../../resources/icons/png/liveedit_vc.png" - PROPERTIES QT_RESOURCE_ALIAS "liveedit_vc.png" -) -set_source_files_properties("../../resources/icons/png/lock.png" - PROPERTIES QT_RESOURCE_ALIAS "lock.png" -) -set_source_files_properties("../../resources/icons/png/monitor.png" - PROPERTIES QT_RESOURCE_ALIAS "monitor.png" -) -set_source_files_properties("../../resources/icons/png/movinghead.png" - PROPERTIES QT_RESOURCE_ALIAS "movinghead.png" -) -set_source_files_properties("../../resources/icons/png/operate.png" - PROPERTIES QT_RESOURCE_ALIAS "operate.png" -) -set_source_files_properties("../../resources/icons/png/other.png" - PROPERTIES QT_RESOURCE_ALIAS "other.png" -) -set_source_files_properties("../../resources/icons/png/pan.png" - PROPERTIES QT_RESOURCE_ALIAS "pan.png" -) -set_source_files_properties("../../resources/icons/png/panic.png" - PROPERTIES QT_RESOURCE_ALIAS "panic.png" -) -set_source_files_properties("../../resources/icons/png/player_pause.png" - PROPERTIES QT_RESOURCE_ALIAS "player_pause.png" -) -set_source_files_properties("../../resources/icons/png/player_play.png" - PROPERTIES QT_RESOURCE_ALIAS "player_play.png" -) -set_source_files_properties("../../resources/icons/png/player_stop.png" - PROPERTIES QT_RESOURCE_ALIAS "player_stop.png" -) -set_source_files_properties("../../resources/icons/png/prism.png" - PROPERTIES QT_RESOURCE_ALIAS "prism.png" -) -set_source_files_properties("../../resources/icons/png/qlcplus-fixtureeditor.png" - PROPERTIES QT_RESOURCE_ALIAS "qlcplus-fixtureeditor.png" -) -set_source_files_properties("../../resources/icons/png/qlcplus.png" - PROPERTIES QT_RESOURCE_ALIAS "qlcplus.png" -) -set_source_files_properties("../../resources/icons/png/qt.png" - PROPERTIES QT_RESOURCE_ALIAS "qt.png" -) -set_source_files_properties("../../resources/icons/png/rainbow.png" - PROPERTIES QT_RESOURCE_ALIAS "rainbow.png" -) -set_source_files_properties("../../resources/icons/png/random.png" - PROPERTIES QT_RESOURCE_ALIAS "random.png" -) -set_source_files_properties("../../resources/icons/png/record.png" - PROPERTIES QT_RESOURCE_ALIAS "record.png" -) -set_source_files_properties("../../resources/icons/png/refresh.png" - PROPERTIES QT_RESOURCE_ALIAS "refresh.png" -) -set_source_files_properties("../../resources/icons/png/remap.png" - PROPERTIES QT_RESOURCE_ALIAS "remap.png" -) -set_source_files_properties("../../resources/icons/png/resize.png" - PROPERTIES QT_RESOURCE_ALIAS "resize.png" -) -set_source_files_properties("../../resources/icons/png/rgbmatrix.png" - PROPERTIES QT_RESOURCE_ALIAS "rgbmatrix.png" -) -set_source_files_properties("../../resources/icons/png/rgbpanel.png" - PROPERTIES QT_RESOURCE_ALIAS "rgbpanel.png" -) -set_source_files_properties("../../resources/icons/png/scanner.png" - PROPERTIES QT_RESOURCE_ALIAS "scanner.png" -) -set_source_files_properties("../../resources/icons/png/scene.png" - PROPERTIES QT_RESOURCE_ALIAS "scene.png" -) -set_source_files_properties("../../resources/icons/png/script.png" - PROPERTIES QT_RESOURCE_ALIAS "script.png" -) -set_source_files_properties("../../resources/icons/png/sequence.png" - PROPERTIES QT_RESOURCE_ALIAS "sequence.png" -) -set_source_files_properties("../../resources/icons/png/show.png" - PROPERTIES QT_RESOURCE_ALIAS "show.png" -) -set_source_files_properties("../../resources/icons/png/shutter.png" - PROPERTIES QT_RESOURCE_ALIAS "shutter.png" -) -set_source_files_properties("../../resources/icons/png/slider.png" - PROPERTIES QT_RESOURCE_ALIAS "slider.png" -) -set_source_files_properties("../../resources/icons/png/slidermatrix.png" - PROPERTIES QT_RESOURCE_ALIAS "slidermatrix.png" -) -set_source_files_properties("../../resources/icons/png/smoke.png" - PROPERTIES QT_RESOURCE_ALIAS "smoke.png" -) -set_source_files_properties("../../resources/icons/png/soloframe.png" - PROPERTIES QT_RESOURCE_ALIAS "soloframe.png" -) -set_source_files_properties("../../resources/icons/png/speed.png" - PROPERTIES QT_RESOURCE_ALIAS "speed.png" -) -set_source_files_properties("../../resources/icons/png/square.png" - PROPERTIES QT_RESOURCE_ALIAS "square.png" -) -set_source_files_properties("../../resources/icons/png/star.png" - PROPERTIES QT_RESOURCE_ALIAS "star.png" -) -set_source_files_properties("../../resources/icons/png/strobe.png" - PROPERTIES QT_RESOURCE_ALIAS "strobe.png" -) -set_source_files_properties("../../resources/icons/png/tabview.png" - PROPERTIES QT_RESOURCE_ALIAS "tabview.png" -) -set_source_files_properties("../../resources/icons/png/tilt.png" - PROPERTIES QT_RESOURCE_ALIAS "tilt.png" -) -set_source_files_properties("../../resources/icons/png/uncheck.png" - PROPERTIES QT_RESOURCE_ALIAS "uncheck.png" -) -set_source_files_properties("../../resources/icons/png/undo.png" - PROPERTIES QT_RESOURCE_ALIAS "undo.png" -) -set_source_files_properties("../../resources/icons/png/ungroup.png" - PROPERTIES QT_RESOURCE_ALIAS "ungroup.png" -) -set_source_files_properties("../../resources/icons/png/unlock.png" - PROPERTIES QT_RESOURCE_ALIAS "unlock.png" -) -set_source_files_properties("../../resources/icons/png/up.png" - PROPERTIES QT_RESOURCE_ALIAS "up.png" -) -set_source_files_properties("../../resources/icons/png/video.png" - PROPERTIES QT_RESOURCE_ALIAS "video.png" -) -set_source_files_properties("../../resources/icons/png/virtualconsole.png" - PROPERTIES QT_RESOURCE_ALIAS "virtualconsole.png" -) -set_source_files_properties("../../resources/icons/png/wizard.png" - PROPERTIES QT_RESOURCE_ALIAS "wizard.png" -) -set_source_files_properties("../../resources/icons/png/wizard_256.png" - PROPERTIES QT_RESOURCE_ALIAS "wizard_256.png" -) -set_source_files_properties("../../resources/icons/png/xypad-point-blue.png" - PROPERTIES QT_RESOURCE_ALIAS "xypad-point-blue.png" -) -set_source_files_properties("../../resources/icons/png/xypad-point-yellow.png" - PROPERTIES QT_RESOURCE_ALIAS "xypad-point-yellow.png" -) -set_source_files_properties("../../resources/icons/png/xypad-point.png" - PROPERTIES QT_RESOURCE_ALIAS "xypad-point.png" -) -set_source_files_properties("../../resources/icons/png/xypad.png" - PROPERTIES QT_RESOURCE_ALIAS "xypad.png" -) -set(qlcui_resource_files - "../../resources/icons/png/add_dump.png" - "../../resources/icons/png/animation.png" - "../../resources/icons/png/attach.png" - "../../resources/icons/png/audio.png" - "../../resources/icons/png/audioinput.png" - "../../resources/icons/png/autostart.png" - "../../resources/icons/png/back.png" - "../../resources/icons/png/beam.png" - "../../resources/icons/png/blackout.png" - "../../resources/icons/png/blind.png" - "../../resources/icons/png/button.png" - "../../resources/icons/png/buttonmatrix.png" - "../../resources/icons/png/chaser.png" - "../../resources/icons/png/check.png" - "../../resources/icons/png/checkbox_empty.png" - "../../resources/icons/png/checkbox_full.png" - "../../resources/icons/png/clock.png" - "../../resources/icons/png/collection.png" - "../../resources/icons/png/color.png" - "../../resources/icons/png/colorwheel.png" - "../../resources/icons/png/configure.png" - "../../resources/icons/png/cuelist.png" - "../../resources/icons/png/current.png" - "../../resources/icons/png/delete.png" - "../../resources/icons/png/design.png" - "../../resources/icons/png/detach.png" - "../../resources/icons/png/dimmer.png" - "../../resources/icons/png/diptool.png" - "../../resources/icons/png/down.png" - "../../resources/icons/png/ds_border.png" - "../../resources/icons/png/ds_bottom.png" - "../../resources/icons/png/ds_off.png" - "../../resources/icons/png/ds_on.png" - "../../resources/icons/png/ds_top.png" - "../../resources/icons/png/edit.png" - "../../resources/icons/png/edit_add.png" - "../../resources/icons/png/edit_remove.png" - "../../resources/icons/png/editclear.png" - "../../resources/icons/png/editcopy.png" - "../../resources/icons/png/editcopyall.png" - "../../resources/icons/png/editcut.png" - "../../resources/icons/png/editdelete.png" - "../../resources/icons/png/editpaste.png" - "../../resources/icons/png/effect.png" - "../../resources/icons/png/efx.png" - "../../resources/icons/png/exit.png" - "../../resources/icons/png/expand.png" - "../../resources/icons/png/fade.png" - "../../resources/icons/png/fan.png" - "../../resources/icons/png/fileclose.png" - "../../resources/icons/png/fileexport.png" - "../../resources/icons/png/fileimport.png" - "../../resources/icons/png/filenew.png" - "../../resources/icons/png/fileopen.png" - "../../resources/icons/png/filesave.png" - "../../resources/icons/png/filesaveas.png" - "../../resources/icons/png/fixture.png" - "../../resources/icons/png/flash.png" - "../../resources/icons/png/flower.png" - "../../resources/icons/png/folder.png" - "../../resources/icons/png/fontcolor.png" - "../../resources/icons/png/fonts.png" - "../../resources/icons/png/forward.png" - "../../resources/icons/png/frame.png" - "../../resources/icons/png/frameraised.png" - "../../resources/icons/png/framesunken.png" - "../../resources/icons/png/fullscreen.png" - "../../resources/icons/png/function.png" - "../../resources/icons/png/global.png" - "../../resources/icons/png/gobo.png" - "../../resources/icons/png/grid.png" - "../../resources/icons/png/group.png" - "../../resources/icons/png/hazer.png" - "../../resources/icons/png/help.png" - "../../resources/icons/png/image.png" - "../../resources/icons/png/input.png" - "../../resources/icons/png/input_output.png" - "../../resources/icons/png/intensity.png" - "../../resources/icons/png/key_bindings.png" - "../../resources/icons/png/knob.png" - "../../resources/icons/png/label.png" - "../../resources/icons/png/laser.png" - "../../resources/icons/png/ledbar_beams.png" - "../../resources/icons/png/ledbar_pixels.png" - "../../resources/icons/png/liveedit.png" - "../../resources/icons/png/liveedit_vc.png" - "../../resources/icons/png/lock.png" - "../../resources/icons/png/monitor.png" - "../../resources/icons/png/movinghead.png" - "../../resources/icons/png/operate.png" - "../../resources/icons/png/other.png" - "../../resources/icons/png/pan.png" - "../../resources/icons/png/panic.png" - "../../resources/icons/png/player_pause.png" - "../../resources/icons/png/player_play.png" - "../../resources/icons/png/player_stop.png" - "../../resources/icons/png/prism.png" - "../../resources/icons/png/qlcplus-fixtureeditor.png" - "../../resources/icons/png/qlcplus.png" - "../../resources/icons/png/qt.png" - "../../resources/icons/png/rainbow.png" - "../../resources/icons/png/random.png" - "../../resources/icons/png/record.png" - "../../resources/icons/png/refresh.png" - "../../resources/icons/png/remap.png" - "../../resources/icons/png/resize.png" - "../../resources/icons/png/rgbmatrix.png" - "../../resources/icons/png/rgbpanel.png" - "../../resources/icons/png/scanner.png" - "../../resources/icons/png/scene.png" - "../../resources/icons/png/script.png" - "../../resources/icons/png/sequence.png" - "../../resources/icons/png/show.png" - "../../resources/icons/png/shutter.png" - "../../resources/icons/png/slider.png" - "../../resources/icons/png/slidermatrix.png" - "../../resources/icons/png/smoke.png" - "../../resources/icons/png/soloframe.png" - "../../resources/icons/png/speed.png" - "../../resources/icons/png/square.png" - "../../resources/icons/png/star.png" - "../../resources/icons/png/strobe.png" - "../../resources/icons/png/tabview.png" - "../../resources/icons/png/tilt.png" - "../../resources/icons/png/uncheck.png" - "../../resources/icons/png/undo.png" - "../../resources/icons/png/ungroup.png" - "../../resources/icons/png/unlock.png" - "../../resources/icons/png/up.png" - "../../resources/icons/png/video.png" - "../../resources/icons/png/virtualconsole.png" - "../../resources/icons/png/wizard.png" - "../../resources/icons/png/wizard_256.png" - "../../resources/icons/png/xypad-point-blue.png" - "../../resources/icons/png/xypad-point-yellow.png" - "../../resources/icons/png/xypad-point.png" - "../../resources/icons/png/xypad.png" -) - if(QT_VERSION_MAJOR GREATER 5) target_link_libraries(${module_name} PUBLIC - Qt${QT_MAJOR_VERSION}::Qml - ) + Qt${QT_MAJOR_VERSION}::Qml) qt_add_resources(${module_name} "qlcui" - PREFIX - "/" - FILES - ${qlcui_resource_files} - ) + PREFIX "/" FILES ${qlcui_resource_files}) else() target_link_libraries(${module_name} PUBLIC - Qt${QT_MAJOR_VERSION}::Script - ) + Qt${QT_MAJOR_VERSION}::Script) qt5_add_resources(qlcplusui_resource_files "qlcui.qrc") target_sources(${module_name} PRIVATE - ${qlcplusui_resource_files} - ) + ${qlcplusui_resource_files}) endif() if(WIN32) target_include_directories(${module_name} PUBLIC - ../../hotplugmonitor/src - ) + ../../hotplugmonitor/src) endif() install(TARGETS ${module_name} From ccd33225fd98b4bb52ddf5ca85c51f19a7add496 Mon Sep 17 00:00:00 2001 From: Massimo Callegari Date: Wed, 30 Oct 2024 18:16:13 +0100 Subject: [PATCH 07/68] plugins/os2l: fix receiving multiple messages at once (fix #1633) --- debian/changelog | 1 + plugins/os2l/os2lplugin.cpp | 76 ++++++++++++++++++++++--------------- plugins/os2l/os2lplugin.h | 2 + 3 files changed, 49 insertions(+), 30 deletions(-) diff --git a/debian/changelog b/debian/changelog index 0a76c4c383..5fcbd49aaa 100644 --- a/debian/changelog +++ b/debian/changelog @@ -4,6 +4,7 @@ qlcplus (4.13.2) stable; urgency=low * engine: add stopOnExit, waitFunctionStart and waitFunctionStop commands to Script - see documentation (thanks to ldebs) * UI/Fixture Manager: limit the number of RGB panel columns for RGBW to avoid crash * UI/Show Manager: show step notes on the timeline (thanks to anarchid) + * Plugins/OS2L: fix receiving multiple messages at once * Web Access: fix grand master stopping running functions * Web Access: fix simple desk not resetting the current universe * RGB scripts: added 'Sine Wave' script diff --git a/plugins/os2l/os2lplugin.cpp b/plugins/os2l/os2lplugin.cpp index 75850d3f9b..d6764f1c20 100644 --- a/plugins/os2l/os2lplugin.cpp +++ b/plugins/os2l/os2lplugin.cpp @@ -207,39 +207,55 @@ void OS2LPlugin::slotProcessTCPPackets() if (socket == NULL) return; - QHostAddress senderAddress = socket->peerAddress(); - QByteArray message = socket->readAll(); - QJsonDocument json = QJsonDocument::fromJson(message); + QHostAddress senderAddress = QHostAddress(socket->peerAddress().toIPv4Address()); - qDebug() << "[TCP] Received" << message.length() << "bytes from" << senderAddress.toString(); - QJsonObject jsonObj = json.object(); - QJsonValue jEvent = jsonObj.value("evt"); - if (jEvent.isUndefined()) - return; + while (1) + { + m_packetLeftOver.append(socket->readAll()); - QString event = jEvent.toString(); + int endIndex = m_packetLeftOver.indexOf("}"); + if (endIndex == -1) + { + if (socket->bytesAvailable()) + continue; + else + break; + } - if (event == "btn") - { - QJsonValue jName = jsonObj.value("name"); - QJsonValue jState = jsonObj.value("state"); - qDebug() << "Got button event with name" << jName.toString() << "and state" << jState.toString(); - uchar value = jState.toString() == "off" ? 0 : 255; - emit valueChanged(m_inputUniverse, 0, getHash(jName.toString()), value, jName.toString()); - } - else if (event == "cmd") - { - QJsonValue jId = jsonObj.value("id"); - QJsonValue jParam = jsonObj.value("param"); - qDebug() << "Got CMD message" << jId.toInt() << "with param" << jParam.toDouble(); - quint32 channel = quint32(jId.toInt()); - QString cmd = QString("cmd%1").arg(channel); - emit valueChanged(m_inputUniverse, 0, quint32(jId.toInt()), uchar(jParam.toDouble()), cmd); - } - else if (event == "beat") - { - qDebug() << "Got beat message" << message; - emit valueChanged(m_inputUniverse, 0, 8341, 255, "beat"); + QByteArray message = m_packetLeftOver.left(endIndex + 1); + m_packetLeftOver.remove(0, endIndex + 1); + QJsonDocument json = QJsonDocument::fromJson(message); + + qDebug() << "[TCP] Received" << message.length() << "bytes from" << senderAddress.toString(); + QJsonObject jsonObj = json.object(); + QJsonValue jEvent = jsonObj.value("evt"); + if (jEvent.isUndefined()) + return; + + QString event = jEvent.toString(); + + if (event == "btn") + { + QJsonValue jName = jsonObj.value("name"); + QJsonValue jState = jsonObj.value("state"); + qDebug() << "Got button event with name" << jName.toString() << "and state" << jState.toString(); + uchar value = jState.toString() == "off" ? 0 : 255; + emit valueChanged(m_inputUniverse, 0, getHash(jName.toString()), value, jName.toString()); + } + else if (event == "cmd") + { + QJsonValue jId = jsonObj.value("id"); + QJsonValue jParam = jsonObj.value("param"); + qDebug() << "Got CMD message" << jId.toInt() << "with param" << jParam.toDouble(); + quint32 channel = quint32(jId.toInt()); + QString cmd = QString("cmd%1").arg(channel); + emit valueChanged(m_inputUniverse, 0, quint32(jId.toInt()), uchar(jParam.toDouble()), cmd); + } + else if (event == "beat") + { + qDebug() << "Got beat message" << message; + emit valueChanged(m_inputUniverse, 0, 8341, 255, "beat"); + } } } diff --git a/plugins/os2l/os2lplugin.h b/plugins/os2l/os2lplugin.h index 5c1ec5457c..1c221d62bb 100644 --- a/plugins/os2l/os2lplugin.h +++ b/plugins/os2l/os2lplugin.h @@ -102,6 +102,8 @@ protected slots: */ QHash m_hashMap; + QByteArray m_packetLeftOver; + /********************************************************************* * Configuration *********************************************************************/ From dfd7a860452681a79a6b1e6adaccd9dc0568828b Mon Sep 17 00:00:00 2001 From: Massimo Callegari Date: Wed, 30 Oct 2024 22:12:36 +0100 Subject: [PATCH 08/68] webaccess: improve connection handling and add hotspot creation --- webaccess/res/networkconfig.js | 11 ++ webaccess/src/webaccess.cpp | 32 +++++- webaccess/src/webaccessnetwork.cpp | 155 +++++++++++++++++++++++------ webaccess/src/webaccessnetwork.h | 6 +- 4 files changed, 167 insertions(+), 37 deletions(-) diff --git a/webaccess/res/networkconfig.js b/webaccess/res/networkconfig.js index da6c515e5a..0e7e962c80 100644 --- a/webaccess/res/networkconfig.js +++ b/webaccess/res/networkconfig.js @@ -48,6 +48,17 @@ function applyParams(iface) { } } +function enableHotspot(enable) { + var ssidObj = document.getElementById("hotspotSSID"); + var ssidVal = ""; + if (ssidObj != null) { ssidVal = ssidObj.value; } + var wpapskObj = document.getElementById("hotspotWPAPSK"); + var wpapskVal = ""; + if (wpapskObj != null) { wpapskVal = wpapskObj.value; } + systemCmd("HOTSPOT", enable ? "1" : "0", ssidVal, wpapskVal); +} + + function setAutostart() { var radios = document.getElementsByName("autostart"); if (radios[0].checked) { diff --git a/webaccess/src/webaccess.cpp b/webaccess/src/webaccess.cpp index 1f98e8f36b..87bc4f229e 100644 --- a/webaccess/src/webaccess.cpp +++ b/webaccess/src/webaccess.cpp @@ -446,7 +446,7 @@ void WebAccess::slotHandleWebSocketRequest(QHttpConnection *conn, QString data) else qDebug() << "[webaccess] Command" << cmdList[1] << "not supported!"; - if (! m_auth->savePasswordsFile()) + if (!m_auth->savePasswordsFile()) { QString wsMessage = QString("ALERT|" + tr("Error while saving passwords file.")); conn->webSocketWrite(wsMessage); @@ -461,15 +461,37 @@ void WebAccess::slotHandleWebSocketRequest(QHttpConnection *conn, QString data) if (cmdList.at(1) == "NETWORK") { + QString wsMessage; if (m_netConfig->updateNetworkSettings(cmdList) == true) - { - QString wsMessage = QString("ALERT|" + tr("Network configuration changed. Reboot to apply the changes.")); - conn->webSocketWrite(wsMessage); + wsMessage = QString("ALERT|" + tr("Network configuration changed. Reboot to apply the changes.")); + else + wsMessage = QString("ALERT|" + tr("An error occurred while updating the network configuration.")); + + conn->webSocketWrite(wsMessage); + return; + } + else if (cmdList.at(1) == "HOTSPOT") + { + QString wsMessage; + if (cmdList.count() < 5) return; + + bool enable = cmdList.at(2).toInt(); + + if (enable) + { + if (m_netConfig->createWiFiHotspot(cmdList.at(3), cmdList.at(4)) == true) + wsMessage = QString("ALERT|" + tr("Wi-Fi hotspot successfully activated.")); + else + wsMessage = QString("ALERT|" + tr("An error occurred while creating a Wi-Fi hotspot.")); } else - qDebug() << "[webaccess] Error writing network configuration file!"; + { + m_netConfig->deleteWiFiHotspot(); + wsMessage = QString("ALERT|" + tr("Wi-Fi hotspot successfully deactivated.")); + } + conn->webSocketWrite(wsMessage); return; } else if (cmdList.at(1) == "AUTOSTART") diff --git a/webaccess/src/webaccessnetwork.cpp b/webaccess/src/webaccessnetwork.cpp index b94290a960..d8239ee398 100644 --- a/webaccess/src/webaccessnetwork.cpp +++ b/webaccess/src/webaccessnetwork.cpp @@ -33,6 +33,7 @@ #define IFACES_SYSTEM_FILE "/etc/network/interfaces" #define DHCPCD_CONF_FILE "/etc/dhcpcd.conf" #define WPA_SUPP_CONF_FILE "/etc/wpa_supplicant/wpa_supplicant.conf" +#define HOTSPOT_CON_NAME QString("QLCHOTSPOT") WebAccessNetwork::WebAccessNetwork(QObject *parent) : QObject(parent) @@ -46,6 +47,7 @@ void WebAccessNetwork::resetInterface(InterfaceInfo *iface) iface->connUUID = ""; iface->isStatic = false; iface->isWireless = false; + iface->isHotspot = false; iface->address = ""; iface->netmask = ""; iface->gateway = ""; @@ -68,6 +70,7 @@ void WebAccessNetwork::appendInterface(InterfaceInfo iface) { m_interfaces[i].isStatic = iface.isStatic; m_interfaces[i].isWireless = iface.isWireless; + m_interfaces[i].isHotspot = iface.isHotspot; m_interfaces[i].enabled = iface.enabled; if (!iface.address.isEmpty()) @@ -103,33 +106,59 @@ QString WebAccessNetwork::getInterfaceHTML(InterfaceInfo *iface) html += "
"; - html += tr("Network interface: ") + iface->devName + "
\n"; + html += ""; - html += "\n"; - if (iface->isWireless) + if (iface->isHotspot) { - html += tr("Access point name (SSID): ") + "devName + "SSID\" size=\"15\" value=\"" + iface->ssid + "\">
\n"; - html += tr("WPA-PSK Password: ") + "devName + "WPAPSK\" size=\"15\" value=\"" + iface->wpaPass + "\">
\n"; + html += "\n"; + + html += "\n"; + + html += "
"; + html += tr("Wi-Fi Hotspot") + "\n"; + html += ""; + html += "\n"; + html += "\n"; + html += "
" + tr("Access point name (SSID): ") + "ssid + "\">
" + tr("WPA-PSK Password: ") + "
"; + + html += "\n"; + html += "\n"; + } + else + { + html += "
"; + html += tr("Network interface") + "
" + iface->devName + "
\n"; + if (iface->isWireless) + { + html += ""; + html += "\n"; + html += "\n"; + html += "
" + tr("Access point name (SSID): ") + "devName + "SSID\" size=\"15\" value=\"" + iface->ssid + "\">
" + tr("WPA-PSK Password: ") + "devName + "WPAPSK\" size=\"15\" value=\"" + iface->wpaPass + "\">
"; + } + /** IP mode radio buttons */ + html += "devName + "', false);\" value=\"dhcp\" " + dhcpChk + ">" + tr("Dynamic (DHCP)") + "
\n"; + html += "devName + "', true);\" value=\"static\" " + staticChk + ">" + tr("Static") + "
\n"; + + /** Static IP fields */ + html += "
devName + "StaticFields\" style=\"padding: 5px 30px;\">\n"; + html += ""; + html += "\n"; + html += "\n"; + html += "\n"; + html += "
" + tr("IP Address: ") + "devName + "IPaddr\" size=\"15\" value=\"" + iface->address + "\" " + editable + ">
" + tr("Netmask: ") + "devName + "Netmask\" size=\"15\" value=\"" + iface->netmask + "\" " + editable + ">
" + tr("Gateway: ") + "devName + "Gateway\" value=\"" + iface->gateway + "\" " + editable + ">
\n"; + html += "devName + "');\" >\n"; } - /** IP mode radio buttons */ - html += "devName + "', false);\" value=\"dhcp\" " + dhcpChk + ">" + tr("Dynamic (DHCP)") + "
\n"; - html += "devName + "', true);\" value=\"static\" " + staticChk + ">" + tr("Static") + "
\n"; - - /** Static IP fields */ - html += "
devName + "StaticFields\" style=\"padding: 5px 30px;\">\n"; - html += tr("IP Address: ") + "devName + "IPaddr\" size=\"15\" value=\"" + iface->address + "\" " + editable + ">
\n"; - html += tr("Netmask: ") + "devName + "Netmask\" size=\"15\" value=\"" + iface->netmask + "\" " + editable + ">
\n"; - html += tr("Gateway: ") + "devName + "Gateway\" value=\"" + iface->gateway + "\" " + editable + ">
\n"; - html += "
\n"; - html += "devName + "');\" >\n"; - html += ""; + + html += "
"; return html; } @@ -139,8 +168,9 @@ QStringList WebAccessNetwork::getNmcliOutput(QStringList args, bool verbose) QStringList outputLines; QProcess process; - qDebug() << "Executing command line: nmcli" << args.join(' '); - process.start("nmcli", args); + args.prepend("nmcli"); + qDebug() << "Executing command line: " << args.join(' '); + process.start("sudo", args); if (process.waitForFinished()) { @@ -191,6 +221,9 @@ void WebAccessNetwork::refreshConnectionsList() if (currInterface.connName.isEmpty()) continue; + if (devTokens.at(3) == HOTSPOT_CON_NAME) + currInterface.isHotspot = true; + // run "nmcli -t con show CONN_NAME" to retrieve everything about a connection QStringList conShowOuput = getNmcliOutput(QStringList() << "-t" << "con" << "show" << currInterface.connName); foreach (QString cLine, conShowOuput) @@ -239,6 +272,7 @@ void WebAccessNetwork::refreshConnectionsList() QString WebAccessNetwork::getNetworkHTML() { QString html = ""; + bool hotspotFound = false; refreshConnectionsList(); @@ -248,6 +282,16 @@ QString WebAccessNetwork::getNetworkHTML() html += getInterfaceHTML(&info); qDebug() << "Interface:" << info.devName << "isStatic:" << info.isStatic << "address:" << info.address << "netmask:" << info.netmask << "gateway:" << info.gateway; + if (info.isHotspot) + hotspotFound = true; + } + + // add the possibility to activate a Wi-Fi hotspot + if (hotspotFound == false) + { + InterfaceInfo hs; + hs.isHotspot = true; + html += getInterfaceHTML(&hs); } return html; @@ -265,6 +309,17 @@ QString WebAccessNetwork::getHTML() " margin: 0px;\n" " background: #222;\n" "}\n" + "input[type=button] {\n" + "background-color: #364e5e;\n" + "border: none;\n" + "border-radius: .2em;\n" + "color: white;\n" + "font: 20px/1.0em 'Trebuchet MS',Arial, Helvetica;\n" + "padding: 10px 16px;\n" + "text-decoration: none;\n" + "margin: 4px 2px;\n" + "cursor: pointer;\n" + "}\n" "\n"; QString bodyHTML = "
\n" @@ -273,12 +328,12 @@ QString WebAccessNetwork::getHTML() "
\n"; bodyHTML += "
"; + "font-size: 20px; text-align: center; color: #CCCCCC; background: #333; padding: 7px;\">"; bodyHTML += tr("Network configuration") + "
\n"; bodyHTML += getNetworkHTML(); bodyHTML += "
"; + "font-size: 20px; text-align: center; color: #CCCCCC; background: #333; padding: 7px;\">"; bodyHTML += tr("Project autostart") + "
\n"; bodyHTML += "
"; @@ -289,8 +344,8 @@ QString WebAccessNetwork::getHTML() bodyHTML += "
\n"; bodyHTML += "
\n"; - bodyHTML += "" + tr("Reboot") + "\n"; - bodyHTML += "" + tr("Shutdown") + "\n"; + bodyHTML += "\n"; + bodyHTML += ""; bodyHTML += "
\n"; QString str = HTML_HEADER + m_JScode + m_CSScode + "\n\n" + bodyHTML + "\n"; @@ -374,3 +429,43 @@ bool WebAccessNetwork::updateNetworkSettings(QStringList cmdList) } return false; } + +bool WebAccessNetwork::createWiFiHotspot(QString SSID, QString password) +{ + // first off, delete the current connection profile + getNmcliOutput(QStringList() << "con" << "del" << HOTSPOT_CON_NAME); + + // create the connection + QString args = "con add type wifi ifname wlan0 mode ap con-name " + HOTSPOT_CON_NAME + " autoconnect no ssid \"" + SSID + "\""; + getNmcliOutput(args.split(" ")); + + // modify with proper parameters + args = "con modify " + HOTSPOT_CON_NAME + " 802-11-wireless.ssid " + SSID; + getNmcliOutput(args.split(" ")); + args = "con modify " + HOTSPOT_CON_NAME + " 802-11-wireless.band bg"; + getNmcliOutput(args.split(" ")); + args = "con modify " + HOTSPOT_CON_NAME + " 802-11-wireless-security.key-mgmt wpa-psk"; + getNmcliOutput(args.split(" ")); + args = "con modify " + HOTSPOT_CON_NAME + " 802-11-wireless-security.proto rsn"; + getNmcliOutput(args.split(" ")); + args = "con modify " + HOTSPOT_CON_NAME + " 802-11-wireless-security.group ccmp"; + getNmcliOutput(args.split(" ")); + args = "con modify " + HOTSPOT_CON_NAME + " 802-11-wireless-security.pairwise ccmp"; + getNmcliOutput(args.split(" ")); + args = "con modify " + HOTSPOT_CON_NAME + " 802-11-wireless-security.psk " + password; + getNmcliOutput(args.split(" ")); + args = "con modify " + HOTSPOT_CON_NAME + " ipv4.method shared"; + getNmcliOutput(args.split(" ")); + + // activate the connection + args = "con up " + HOTSPOT_CON_NAME; + getNmcliOutput(args.split(" ")); + + return true; +} + +bool WebAccessNetwork::deleteWiFiHotspot() +{ + getNmcliOutput(QStringList() << "con" << "del" << HOTSPOT_CON_NAME); + return true; +} diff --git a/webaccess/src/webaccessnetwork.h b/webaccess/src/webaccessnetwork.h index af65d98ae6..e1acf2bea1 100644 --- a/webaccess/src/webaccessnetwork.h +++ b/webaccess/src/webaccessnetwork.h @@ -30,6 +30,7 @@ typedef struct QString connUUID; bool isStatic; bool isWireless; + bool isHotspot; QString address; QString netmask; QString gateway; @@ -52,14 +53,15 @@ class WebAccessNetwork: public QObject QString getHTML(); bool updateNetworkSettings(QStringList cmdList); + bool createWiFiHotspot(QString SSID, QString password); + bool deleteWiFiHotspot(); protected: QStringList getNmcliOutput(QStringList args, bool verbose = false); void refreshConnectionsList(); protected: - QListm_interfaces; - QStringList m_dhcpcdConfCache; + QList m_interfaces; }; #endif // WEBACCESSNETWORK_H From d00bb4f2877f3a0e50674d641bbb33a18e5f644b Mon Sep 17 00:00:00 2001 From: Massimo Callegari Date: Fri, 1 Nov 2024 12:27:22 +0100 Subject: [PATCH 09/68] linux: improve DRI card detection and move after graphical target --- platforms/linux/qlcplus-start.sh | 27 ++++++++++++++++----------- platforms/linux/qlcplus.service | 3 ++- 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/platforms/linux/qlcplus-start.sh b/platforms/linux/qlcplus-start.sh index ac3cffa8b7..e18268a609 100644 --- a/platforms/linux/qlcplus-start.sh +++ b/platforms/linux/qlcplus-start.sh @@ -17,6 +17,22 @@ # See the License for the specific language governing permissions and # limitations under the License. +QLCPLUS_OPTS="-platform $QTPLATFORM --nowm --web --web-auth --operate --overscan" + +if [ ! -f $HOME/.qlcplus/eglfs.json ]; then + mkdir -p $HOME/.qlcplus + for i in {1..5} + do + GPUDEV=`find /dev/dri/by-path -name *gpu-card*` + if [ ! -z "$GPUDEV" ]; then + GPUDEV=`readlink -f $GPUDEV` + echo '{ "device": "'$GPUDEV'" }' > $HOME/.qlcplus/eglfs.json + else + sleep 2 + fi + done +fi + # detect HDMI plug state QTPLATFORM="eglfs" kmsprint -m | grep connected > /dev/null @@ -24,17 +40,6 @@ if [ $? -eq 1 ]; then QTPLATFORM="offscreen" fi -QLCPLUS_OPTS="-platform $QTPLATFORM --nowm --web --web-auth --operate --overscan" - -if [ ! -f $HOME/.qlcplus/eglfs.json ]; then - mkdir -p $HOME/.qlcplus - if [ -f /dev/dri/card1 ]; then - echo '{ "device": "/dev/dri/card1" }' > $HOME/.qlcplus/eglfs.json - else - echo '{ "device": "/dev/dri/card0" }' > $HOME/.qlcplus/eglfs.json - fi -fi - if [ -f $HOME/.qlcplus/autostart.qxw ]; then QLCPLUS_OPTS="$QLCPLUS_OPTS --open $HOME/.qlcplus/autostart.qxw" fi diff --git a/platforms/linux/qlcplus.service b/platforms/linux/qlcplus.service index 919be83f19..7456ef3cc5 100644 --- a/platforms/linux/qlcplus.service +++ b/platforms/linux/qlcplus.service @@ -1,7 +1,8 @@ [Unit] Description=Q Light Controller Plus Documentation=man:qlcplus(1) -After=basic.target +After=graphical.target +DefaultDependencies=no [Service] Type=simple From 9baecd71999a9aa537e892fb70f7d1a70747d853 Mon Sep 17 00:00:00 2001 From: Massimo Callegari Date: Fri, 1 Nov 2024 17:40:34 +0100 Subject: [PATCH 10/68] linux: fix startup script again --- platforms/linux/qlcplus-start.sh | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/platforms/linux/qlcplus-start.sh b/platforms/linux/qlcplus-start.sh index e18268a609..14c296f289 100644 --- a/platforms/linux/qlcplus-start.sh +++ b/platforms/linux/qlcplus-start.sh @@ -17,8 +17,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -QLCPLUS_OPTS="-platform $QTPLATFORM --nowm --web --web-auth --operate --overscan" - +# detect DRI card if [ ! -f $HOME/.qlcplus/eglfs.json ]; then mkdir -p $HOME/.qlcplus for i in {1..5} @@ -27,6 +26,7 @@ if [ ! -f $HOME/.qlcplus/eglfs.json ]; then if [ ! -z "$GPUDEV" ]; then GPUDEV=`readlink -f $GPUDEV` echo '{ "device": "'$GPUDEV'" }' > $HOME/.qlcplus/eglfs.json + break else sleep 2 fi @@ -40,6 +40,9 @@ if [ $? -eq 1 ]; then QTPLATFORM="offscreen" fi +# create QLC+ command line +QLCPLUS_OPTS="-platform $QTPLATFORM --nowm --web --web-auth --operate --overscan" + if [ -f $HOME/.qlcplus/autostart.qxw ]; then QLCPLUS_OPTS="$QLCPLUS_OPTS --open $HOME/.qlcplus/autostart.qxw" fi @@ -47,7 +50,7 @@ fi # if NTP hasn't done its job already, set the date to modern age... CURRDATE=`date +%Y` if [ "$CURRDATE" -lt "2024" ]; then - date +%Y%m%d -s "20240313" + date +%Y%m%d -s "20241101" fi export QT_QPA_EGLFS_PHYSICAL_WIDTH=320 From 8c1981cf1fa8aea10d21d4294b67694217dfdd97 Mon Sep 17 00:00:00 2001 From: Massimo Callegari Date: Fri, 1 Nov 2024 17:41:04 +0100 Subject: [PATCH 11/68] ui: fix resources installation with Qt6 --- ui/src/CMakeLists.txt | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/ui/src/CMakeLists.txt b/ui/src/CMakeLists.txt index 1c98110a9d..ad9a076a5d 100644 --- a/ui/src/CMakeLists.txt +++ b/ui/src/CMakeLists.txt @@ -165,21 +165,20 @@ target_link_libraries(${module_name} PUBLIC qlcplusengine ) -# Resources: +# Add resources and RGB Script deps if(QT_VERSION_MAJOR GREATER 5) target_link_libraries(${module_name} PUBLIC Qt${QT_MAJOR_VERSION}::Qml) - qt_add_resources(${module_name} "qlcui" - PREFIX "/" FILES ${qlcui_resource_files}) + qt_add_resources(qlcplusui_resource_files "qlcui.qrc") else() target_link_libraries(${module_name} PUBLIC Qt${QT_MAJOR_VERSION}::Script) qt5_add_resources(qlcplusui_resource_files "qlcui.qrc") - target_sources(${module_name} PRIVATE - ${qlcplusui_resource_files}) endif() +target_sources(${module_name} PRIVATE + ${qlcplusui_resource_files}) if(WIN32) target_include_directories(${module_name} PUBLIC From df3ccdd22d60305b8641099894b5d21cef21461f Mon Sep 17 00:00:00 2001 From: Massimo Callegari Date: Mon, 4 Nov 2024 10:01:02 +0100 Subject: [PATCH 12/68] engine: protect faders from unexpected concurrent access --- engine/src/genericfader.cpp | 9 +++- engine/src/mastertimer.cpp | 9 +--- engine/src/universe.cpp | 89 +++++++++++++++++++++++-------------- engine/src/universe.h | 15 ++++++- 4 files changed, 78 insertions(+), 44 deletions(-) diff --git a/engine/src/genericfader.cpp b/engine/src/genericfader.cpp index c21eccfe8e..6305b1ca0d 100644 --- a/engine/src/genericfader.cpp +++ b/engine/src/genericfader.cpp @@ -197,15 +197,20 @@ void GenericFader::write(Universe *universe) //qDebug() << "[GenericFader] writing channels: " << this << m_channels.count(); + // iterate through all the channels handled by this fader QMutableHashIterator it(m_channels); while (it.hasNext() == true) { FadeChannel& fc(it.next().value()); int flags = fc.flags(); - int address = int(fc.addressInUniverse()); + quint32 address = fc.addressInUniverse(); int channelCount = fc.channelCount(); - // iterate through all the channels handled by this fader + if (address == QLCChannel::invalid()) + { + qWarning() << "Invalid channel found"; + continue; + } if (flags & FadeChannel::SetTarget) { diff --git a/engine/src/mastertimer.cpp b/engine/src/mastertimer.cpp index a2c170e86a..2c00df605c 100644 --- a/engine/src/mastertimer.cpp +++ b/engine/src/mastertimer.cpp @@ -207,13 +207,8 @@ void MasterTimer::fadeAndStopAll(int timeout) QList universes = doc->inputOutputMap()->claimUniverses(); foreach (Universe *universe, universes) - { - foreach (QSharedPointer fader, universe->faders()) - { - if (!fader.isNull() && fader->parentFunctionID() != Function::invalidId()) - fader->setFadeOut(true, uint(timeout)); - } - } + universe->setFaderFadeOut(timeout); + doc->inputOutputMap()->releaseUniverses(); } diff --git a/engine/src/universe.cpp b/engine/src/universe.cpp index eceeeee709..8ab8d56161 100644 --- a/engine/src/universe.cpp +++ b/engine/src/universe.cpp @@ -32,6 +32,7 @@ #include "inputpatch.h" #include "qlcmacros.h" #include "universe.h" +#include "function.h" #include "qlcfile.h" #include "utils.h" @@ -53,6 +54,10 @@ Universe::Universe(quint32 id, GrandMaster *gm, QObject *parent) , m_fbPatch(NULL) , m_channelsMask(new QByteArray(UNIVERSE_SIZE, char(0))) , m_modifiedZeroValues(new QByteArray(UNIVERSE_SIZE, char(0))) + , m_running(false) +#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0) + , m_fadersMutex(QMutex::Recursive) +#endif , m_usedChannels(0) , m_totalChannels(0) , m_totalChannelsChanged(false) @@ -209,33 +214,36 @@ QSharedPointer Universe::requestFader(Universe::FaderPriority prio QSharedPointer fader = QSharedPointer(new GenericFader()); fader->setPriority(priority); - if (m_faders.isEmpty()) - { - m_faders.append(fader); - } - else { - for (int i = m_faders.count() - 1; i >= 0; i--) + QMutexLocker fadersLocker(&m_fadersMutex); + if (m_faders.isEmpty()) + { + m_faders.append(fader); + } + else { - QSharedPointer f = m_faders.at(i); - if (!f.isNull() && f->priority() <= fader->priority()) + for (int i = m_faders.count() - 1; i >= 0; i--) { - insertPos = i + 1; - break; + QSharedPointer f = m_faders.at(i); + if (!f.isNull() && f->priority() <= fader->priority()) + { + insertPos = i + 1; + break; + } } + + m_faders.insert(insertPos, fader); } - m_faders.insert(insertPos, fader); + qDebug() << "[Universe]" << id() << ": Generic fader with priority" << fader->priority() + << "registered at pos" << insertPos << ", count" << m_faders.count(); } - - qDebug() << "[Universe]" << id() << ": Generic fader with priority" << fader->priority() - << "registered at pos" << insertPos << ", count" << m_faders.count(); - return fader; } void Universe::dismissFader(QSharedPointer fader) { + QMutexLocker fadersLocker(&m_fadersMutex); int index = m_faders.indexOf(fader); if (index >= 0) { @@ -246,6 +254,7 @@ void Universe::dismissFader(QSharedPointer fader) void Universe::requestFaderPriority(QSharedPointer fader, Universe::FaderPriority priority) { + QMutexLocker fadersLocker(&m_fadersMutex); if (m_faders.contains(fader) == false) return; @@ -278,6 +287,7 @@ QList > Universe::faders() void Universe::setFaderPause(quint32 functionID, bool enable) { + QMutexLocker fadersLocker(&m_fadersMutex); QMutableListIterator > it(m_faders); while (it.hasNext()) { @@ -289,6 +299,16 @@ void Universe::setFaderPause(quint32 functionID, bool enable) } } +void Universe::setFaderFadeOut(int fadeTime) +{ + QMutexLocker fadersLocker(&m_fadersMutex); + foreach (QSharedPointer fader, m_faders) + { + if (!fader.isNull() && fader->parentFunctionID() != Function::invalidId()) + fader->setFadeOut(true, uint(fadeTime)); + } +} + void Universe::tick() { m_semaphore.release(1); @@ -299,28 +319,31 @@ void Universe::processFaders() flushInput(); zeroIntensityChannels(); - QMutableListIterator > it(m_faders); - while (it.hasNext()) { - QSharedPointer fader = it.next(); - if (fader.isNull()) - continue; - - // destroy a fader if it's been requested - // and it's not fading out - if (fader->deleteRequested() && !fader->isFadingOut()) + QMutexLocker fadersLocker(&m_fadersMutex); + QMutableListIterator > it(m_faders); + while (it.hasNext()) { - fader->removeAll(); - it.remove(); - fader.clear(); - continue; - } + QSharedPointer fader = it.next(); //m_faders.at(i); + if (fader.isNull()) + continue; - if (fader->isEnabled() == false) - continue; + // destroy a fader if it's been requested + // and it's not fading out + if (fader->deleteRequested() && !fader->isFadingOut()) + { + fader->removeAll(); + it.remove(); + fader.clear(); + continue; + } + + if (fader->isEnabled() == false) + continue; - //qDebug() << "Processing fader" << fader->name() << fader->channelsCount(); - fader->write(this); + //qDebug() << "Processing fader" << fader->name() << fader->channelsCount(); + fader->write(this); + } } bool dataChanged = hasChanged(); diff --git a/engine/src/universe.h b/engine/src/universe.h index a8571739ab..d282748ab8 100644 --- a/engine/src/universe.h +++ b/engine/src/universe.h @@ -265,7 +265,7 @@ protected slots: InputPatch *m_inputPatch; /** List of references to the output patches associated to this universe. */ - QListm_outputPatchList; + QList m_outputPatchList; /** Reference to the feedback patch associated to this universe. */ OutputPatch *m_fbPatch; @@ -355,6 +355,10 @@ protected slots: * to the requested pause state */ void setFaderPause(quint32 functionID, bool enable); + /** Set a fade out time to every fader of this universe. + * This is used from the fadeAndStopAll functionality */ + void setFaderFadeOut(int fadeTime); + public slots: void tick(); @@ -375,7 +379,14 @@ public slots: /** IMPORTANT: this is the list of faders that will compose * the Universe values. The order is very important ! */ - QList > m_faders; + QList> m_faders; + + /** Mutex used to protect the access to the m_faders array */ +#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0) + QMutex m_fadersMutex; +#else + QRecursiveMutex m_fadersMutex; +#endif /************************************************************************ * Values From 8a5a9468ab5e96c079c6998c8c362da9f742c1a7 Mon Sep 17 00:00:00 2001 From: Massimo Callegari Date: Mon, 4 Nov 2024 10:31:59 +0100 Subject: [PATCH 13/68] ui/show manager: handle CTRL+mouse wheel to zoom in/out (fix #1629) --- debian/changelog | 1 + ui/src/showmanager/multitrackview.cpp | 17 +++++++++++++++++ ui/src/showmanager/multitrackview.h | 3 ++- 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/debian/changelog b/debian/changelog index 5fcbd49aaa..6e6f6771af 100644 --- a/debian/changelog +++ b/debian/changelog @@ -4,6 +4,7 @@ qlcplus (4.13.2) stable; urgency=low * engine: add stopOnExit, waitFunctionStart and waitFunctionStop commands to Script - see documentation (thanks to ldebs) * UI/Fixture Manager: limit the number of RGB panel columns for RGBW to avoid crash * UI/Show Manager: show step notes on the timeline (thanks to anarchid) + * UI/Show Manager: handle CTRL+mouse wheel to zoom in/out * Plugins/OS2L: fix receiving multiple messages at once * Web Access: fix grand master stopping running functions * Web Access: fix simple desk not resetting the current universe diff --git a/ui/src/showmanager/multitrackview.cpp b/ui/src/showmanager/multitrackview.cpp index fe6a4358fc..2b08eb9bb7 100644 --- a/ui/src/showmanager/multitrackview.cpp +++ b/ui/src/showmanager/multitrackview.cpp @@ -494,6 +494,23 @@ void MultiTrackView::mouseReleaseEvent(QMouseEvent * e) //qDebug() << Q_FUNC_INFO << "View clicked at pos: " << e->pos().x() << e->pos().y(); } +void MultiTrackView::wheelEvent(QWheelEvent *event) +{ + if (event->modifiers() & Qt::ControlModifier) + { + int zoomValue = m_timeSlider->value(); + if (event->pixelDelta().y() > 0) + zoomValue++; + else + zoomValue--; + + if (zoomValue >= m_timeSlider->minimum() && zoomValue <= m_timeSlider->maximum()) + m_timeSlider->setValue(zoomValue); + return; + } + QGraphicsView::wheelEvent(event); +} + void MultiTrackView::slotHeaderClicked(QGraphicsSceneMouseEvent *event) { m_cursor->setPos(TRACK_WIDTH + event->pos().toPoint().x(), 0); diff --git a/ui/src/showmanager/multitrackview.h b/ui/src/showmanager/multitrackview.h index d3aba100a3..fe4f56716e 100644 --- a/ui/src/showmanager/multitrackview.h +++ b/ui/src/showmanager/multitrackview.h @@ -150,7 +150,8 @@ class MultiTrackView : public QGraphicsView bool m_snapToGrid; public slots: - void mouseReleaseEvent(QMouseEvent * e); + void mouseReleaseEvent(QMouseEvent *e); + void wheelEvent(QWheelEvent *event); protected slots: void slotHeaderClicked(QGraphicsSceneMouseEvent *event); From 682aee442ab198abf88e87fc586348f002b012e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christoph=20M=C3=BCllner?= Date: Wed, 6 Nov 2024 02:15:35 +0100 Subject: [PATCH 14/68] variables.cmake: Replace hard-coded QT version in PLUGINDIR path MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently, we set a PLUGINDIR path that includes a hard-coded "qt5" subdir name in it. This obviously fails for Qt6. Luckily, we already have $QT_MAJOR_VERSION variables, which can be used to replace the hard-coded 5 by the actual version to build for. Signed-off-by: Christoph Müllner --- variables.cmake | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/variables.cmake b/variables.cmake index 7c13ec1a35..fb2be80e30 100644 --- a/variables.cmake +++ b/variables.cmake @@ -287,9 +287,9 @@ elseif (APPLE) set(PLUGINDIR "PlugIns") elseif (UNIX) if (appimage) - set(PLUGINDIR "../lib/qt5/plugins/qlcplus") + set(PLUGINDIR "../lib/qt${QT_MAJOR_VERSION}/plugins/qlcplus") else () - set(PLUGINDIR "${LIBSDIR}/qt5/plugins/qlcplus") + set(PLUGINDIR "${LIBSDIR}/qt${QT_MAJOR_VERSION}/plugins/qlcplus") endif () endif () From 919144c36a4f1881fd482d87aabe938fbd59f2d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christoph=20M=C3=BCllner?= Date: Wed, 6 Nov 2024 02:40:31 +0100 Subject: [PATCH 15/68] variables.cmake: Set LIBSDIR to CMAKE_INSTALL_LIBDIR MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We already get a properly defined library directory path in the variable CMAKE_INSTALL_LIBDIR from invoking `include(GNUInstallDirs)` in the toplevel CMakeLists.txt. This is already addressing differences between different Linux distros. E.g., for Debian we get "lib/${CMAKE_LIBRARY_ARCHITECTURE}" and for Fedora we get "lib" or "lib64". So, let's use that variable. Signed-off-by: Christoph Müllner --- variables.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/variables.cmake b/variables.cmake index fb2be80e30..90c1a6141d 100644 --- a/variables.cmake +++ b/variables.cmake @@ -89,7 +89,7 @@ if (WIN32) elseif (APPLE) set(LIBSDIR "Frameworks") elseif (UNIX) - set(LIBSDIR "lib/${CMAKE_C_LIBRARY_ARCHITECTURE}") + set(LIBSDIR "${CMAKE_INSTALL_LIBDIR}") endif () if (ANDROID) From e08a62ba25e4a20167d9cb7ab9014acb68ec8714 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christoph=20M=C3=BCllner?= Date: Wed, 6 Nov 2024 03:10:04 +0100 Subject: [PATCH 16/68] resources: Remove docs subdirectory from Qt project MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Docs are no longer bundled with QLC+. The CMakeLists.txt does not need to be adjusted as it does not include the corresponding subdirectory. Signed-off-by: Christoph Müllner --- resources/resources.pro | 1 - 1 file changed, 1 deletion(-) diff --git a/resources/resources.pro b/resources/resources.pro index 7802046e85..fd6b70f10f 100644 --- a/resources/resources.pro +++ b/resources/resources.pro @@ -1,6 +1,5 @@ TEMPLATE = subdirs -!qmlui: SUBDIRS += docs SUBDIRS += fixtures SUBDIRS += gobos SUBDIRS += inputprofiles From c5a5d5be77e6ea17f616d292e4a6f299f5c90e42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christoph=20M=C3=BCllner?= Date: Wed, 6 Nov 2024 03:23:56 +0100 Subject: [PATCH 17/68] velleman: Install only on Windows, where we have real functionality MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On platforms other than Windows, libvelleman is just a mockup implementation for testing purposes. Therefore, the Qt-project file excludes this library from being installed on non-Windows platforms. Let's do the same in the CMakeLists.txt file. Signed-off-by: Christoph Müllner --- plugins/velleman/src/CMakeLists.txt | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/plugins/velleman/src/CMakeLists.txt b/plugins/velleman/src/CMakeLists.txt index c7e04dbf26..31f3eb6dba 100644 --- a/plugins/velleman/src/CMakeLists.txt +++ b/plugins/velleman/src/CMakeLists.txt @@ -61,7 +61,10 @@ else() ) endif() -install(TARGETS ${module_name} - LIBRARY DESTINATION ${INSTALLROOT}/${PLUGINDIR} - RUNTIME DESTINATION ${INSTALLROOT}/${PLUGINDIR} -) \ No newline at end of file +# Installation only on Windows; Unix targets are built only for unit testing. +if(WIN32) + install(TARGETS ${module_name} + LIBRARY DESTINATION ${INSTALLROOT}/${PLUGINDIR} + RUNTIME DESTINATION ${INSTALLROOT}/${PLUGINDIR} + ) +endif() From 78720290be66569fb556bc9a31677c83e8fa44e1 Mon Sep 17 00:00:00 2001 From: Massimo Callegari Date: Wed, 6 Nov 2024 19:07:20 +0100 Subject: [PATCH 18/68] engine: fix multi-head intensity palette Reported: https://www.qlcplus.org/forum/viewtopic.php?t=17874 --- engine/src/qlcpalette.cpp | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/engine/src/qlcpalette.cpp b/engine/src/qlcpalette.cpp index 14f4e85f3d..571f866f15 100644 --- a/engine/src/qlcpalette.cpp +++ b/engine/src/qlcpalette.cpp @@ -282,15 +282,20 @@ QList QLCPalette::valuesFromFixtures(Doc *doc, QList fixtur case Dimmer: { int dValue = value().toInt(); - quint32 intCh = fixture->type() == QLCFixtureDef::Dimmer ? + quint32 masterIntensityChannel = fixture->type() == QLCFixtureDef::Dimmer ? 0 : fixture->masterIntensityChannel(); - if (intCh != QLCChannel::invalid()) - { - if (fType != Flat) - dValue = int((qreal(intFanValue - dValue) * factor) + dValue); + if (fType != Flat) + dValue = int((qreal(intFanValue - dValue) * factor) + dValue); - list << SceneValue(id, intCh, uchar(dValue)); + if (masterIntensityChannel != QLCChannel::invalid()) + list << SceneValue(id, masterIntensityChannel, uchar(dValue)); + + for (int i = 0; i < fixture->heads(); i++) + { + quint32 headDimmerChannel = fixture->channelNumber(QLCChannel::Intensity, QLCChannel::MSB, i); + if (headDimmerChannel != QLCChannel::invalid()) + list << SceneValue(id, headDimmerChannel, uchar(dValue)); } } break; From e60bb30b729c15a8f64e545c553e4ae22fe70065 Mon Sep 17 00:00:00 2001 From: Massimo Callegari Date: Sat, 9 Nov 2024 14:14:43 +0100 Subject: [PATCH 19/68] qmlui: improve DMX dump to achieve maximum flexibility --- engine/src/doc.cpp | 5 + engine/src/doc.h | 7 + qmlui/contextmanager.cpp | 15 +- qmlui/contextmanager.h | 7 +- qmlui/fixturemanager.cpp | 25 +- qmlui/fixturemanager.h | 11 + qmlui/functionmanager.cpp | 133 +++++ qmlui/functionmanager.h | 5 + qmlui/inputoutputmanager.cpp | 5 + qmlui/inputoutputmanager.h | 1 + qmlui/qml/MainView.qml | 127 ++++- qmlui/qml/SimpleDesk.qml | 10 +- qmlui/qml/fixturesfunctions/RightPanel.qml | 132 ----- qmlui/qml/popup/PopupDMXDump.qml | 631 +++++++++++++-------- 14 files changed, 710 insertions(+), 404 deletions(-) diff --git a/engine/src/doc.cpp b/engine/src/doc.cpp index 9e285771cc..b55828dee1 100644 --- a/engine/src/doc.cpp +++ b/engine/src/doc.cpp @@ -658,6 +658,11 @@ QList const& Doc::fixtures() const return m_fixturesListCache; } +int Doc::fixturesCount() const +{ + return m_fixtures.count(); +} + Fixture* Doc::fixture(quint32 id) const { return m_fixtures.value(id, NULL); diff --git a/engine/src/doc.h b/engine/src/doc.h index 4da3ee6804..2288ee63d7 100644 --- a/engine/src/doc.h +++ b/engine/src/doc.h @@ -296,6 +296,13 @@ class Doc : public QObject */ QList const& fixtures() const; + /** + * Get the number of fixtures currently added to the project + * + * @return The number of fixtures + */ + int fixturesCount() const; + /** * Get the fixture that occupies the given DMX address. If multiple fixtures * occupy the same address, the one that has been last modified is returned. diff --git a/qmlui/contextmanager.cpp b/qmlui/contextmanager.cpp index ecb73f28a8..afc7a56412 100644 --- a/qmlui/contextmanager.cpp +++ b/qmlui/contextmanager.cpp @@ -1740,14 +1740,10 @@ int ContextManager::dumpChannelMask() const return m_dumpChannelMask; } -void ContextManager::dumpDmxChannels(QString name, quint32 mask) +void ContextManager::dumpDmxChannels(quint32 channelMask, QString sceneName, int sceneID, bool allChannels, bool nonZeroOnly) { - m_functionManager->dumpOnNewScene(m_dumpValues, selectedFixtureIDList(), mask, name); -} - -void ContextManager::dumpDmxChannels(quint32 sceneID, quint32 mask) -{ - m_functionManager->dumpOnScene(m_dumpValues, selectedFixtureIDList(), mask, sceneID); + m_functionManager->dumpDmxValues(m_dumpValues, allChannels ? QList() : selectedFixtureIDList(), channelMask, + sceneName, sceneID == -1 ? Function::invalidId() : sceneID, nonZeroOnly); } void ContextManager::resetDumpValues() @@ -1764,8 +1760,3 @@ void ContextManager::resetDumpValues() emit dumpChannelMaskChanged(); } -GenericDMXSource *ContextManager::dmxSource() const -{ - return m_source; -} - diff --git a/qmlui/contextmanager.h b/qmlui/contextmanager.h index e0aa068c97..e41495eb5b 100644 --- a/qmlui/contextmanager.h +++ b/qmlui/contextmanager.h @@ -302,15 +302,12 @@ protected slots: /** Return the current DMX dump channel type mask */ int dumpChannelMask() const; - Q_INVOKABLE void dumpDmxChannels(QString name, quint32 mask); - - Q_INVOKABLE void dumpDmxChannels(quint32 sceneID, quint32 mask); + Q_INVOKABLE void dumpDmxChannels(quint32 channelMask, QString sceneName, int sceneID, + bool allChannels, bool nonZeroOnly); /** Resets the current values used for dumping or preview */ Q_INVOKABLE void resetDumpValues(); - GenericDMXSource *dmxSource() const; - /** Return a list only of the fixture IDs from the selected preview items */ QList selectedFixtureIDList() const; diff --git a/qmlui/fixturemanager.cpp b/qmlui/fixturemanager.cpp index 1ff875fc74..529f153694 100644 --- a/qmlui/fixturemanager.cpp +++ b/qmlui/fixturemanager.cpp @@ -57,6 +57,7 @@ FixtureManager::FixtureManager(QQuickView *view, Doc *doc, QObject *parent) , m_maxBeamDegrees(0) , m_invertedZoom(false) , m_colorsMask(0) + , m_capabilityMask(0) , m_selectedChannelModifier(nullptr) { Q_ASSERT(m_doc != nullptr); @@ -415,7 +416,7 @@ bool FixtureManager::renameFixture(quint32 itemID, QString newName) int FixtureManager::fixturesCount() { - return m_doc->fixtures().count(); + return m_doc->fixturesCount(); } QVariant FixtureManager::groupsTreeModel() @@ -1776,6 +1777,7 @@ QMultiHash FixtureManager::getFixtureCapabilities(quint32 itemI bool hasShutter = false, hasColorWheel = false, hasGobos = false; bool hasBeam = false; int origColorsMask = m_colorsMask; + quint32 origCapabilityMask = m_capabilityMask; QLCPhysical phy; QList channelIndices; @@ -1810,6 +1812,18 @@ QMultiHash FixtureManager::getFixtureCapabilities(quint32 itemI int chType = channel->group(); + if (chType == QLCChannel::Intensity) + { + if (channel->colour() == QLCChannel::NoColour) + m_capabilityMask |= App::DimmerType; + else + m_capabilityMask |= App::ColorType; + } + else + { + m_capabilityMask |= (1 << chType); + } + switch (channel->group()) { case QLCChannel::Intensity: @@ -1955,6 +1969,9 @@ QMultiHash FixtureManager::getFixtureCapabilities(quint32 itemI if (origColorsMask != m_colorsMask) emit colorsMaskChanged(m_colorsMask); + if (origCapabilityMask != m_capabilityMask) + emit capabilityMaskChanged(); + updateCapabilityCounter(hasDimmer, "capIntensity", capDelta); updateCapabilityCounter(hasColor, "capColor", capDelta); updateCapabilityCounter(hasPosition, "capPosition", capDelta); @@ -1973,6 +1990,7 @@ void FixtureManager::resetCapabilities() m_minBeamDegrees = 15.0; m_maxBeamDegrees = 0; m_colorsMask = 0; + m_capabilityMask = 0; } QList FixtureManager::getFixturePosition(quint32 fxID, int type, int degrees) @@ -2136,6 +2154,11 @@ QVariantList FixtureManager::presetChannel(quint32 fixtureID, int chIndex) return prList; } +quint32 FixtureManager::capabilityMask() const +{ + return m_capabilityMask; +} + int FixtureManager::colorsMask() const { return m_colorsMask; diff --git a/qmlui/fixturemanager.h b/qmlui/fixturemanager.h index 1bf25d8707..865718e986 100644 --- a/qmlui/fixturemanager.h +++ b/qmlui/fixturemanager.h @@ -54,6 +54,7 @@ class FixtureManager : public QObject Q_PROPERTY(QVariantList colorWheelChannels READ colorWheelChannels NOTIFY colorWheelChannelsChanged) Q_PROPERTY(QVariantList shutterChannels READ shutterChannels NOTIFY shutterChannelsChanged) Q_PROPERTY(int colorsMask READ colorsMask NOTIFY colorsMaskChanged) + Q_PROPERTY(quint32 capabilityMask READ capabilityMask NOTIFY capabilityMaskChanged) Q_PROPERTY(QStringList colorFiltersFileList READ colorFiltersFileList NOTIFY colorFiltersFileListChanged) Q_PROPERTY(int colorFilterFileIndex READ colorFilterFileIndex WRITE setColorFilterFileIndex NOTIFY colorFilterFileIndexChanged) @@ -437,6 +438,9 @@ public slots: /** Returns a preset channel usable by the QML PresetTool */ Q_INVOKABLE QVariantList presetChannel(quint32 fixtureID, int chIndex); + /** Return the current capability type mask */ + quint32 capabilityMask() const; + /** Returns the currently available colors as a bitmask */ int colorsMask() const; @@ -469,6 +473,9 @@ public slots: /** Notify the listeners that the available colors changed */ void colorsMaskChanged(int colorsMask); + /** Notify the listeners that the available capabilities changed */ + void capabilityMaskChanged(); + private: /** Generic method that returns the names of the cached channels for * the required $group */ @@ -496,6 +503,10 @@ public slots: /** Bitmask holding the colors supported by the currently selected fixtures */ int m_colorsMask; + + /** Bitmask holding the capability supported by the currently selected fixtures */ + quint32 m_capabilityMask; + /** A map of the currently available colors and their counters */ QMap m_colorCounters; diff --git a/qmlui/functionmanager.cpp b/qmlui/functionmanager.cpp index fa7e3b066e..d7a6d314c7 100644 --- a/qmlui/functionmanager.cpp +++ b/qmlui/functionmanager.cpp @@ -113,6 +113,11 @@ QVariant FunctionManager::functionsList() return QVariant::fromValue(m_functionTree); } +quint32 FunctionManager::nextFunctionId() const +{ + return m_doc->nextFunctionID(); +} + QVariantList FunctionManager::usageList(quint32 fid) { QVariantList list; @@ -1103,6 +1108,134 @@ void FunctionManager::deleteSelectedFolders() * DMX values (dumping and Scene editor) *********************************************************************/ +void FunctionManager::dumpDmxValues(QList dumpValues, QList selectedFixtures, + quint32 channelMask, QString sceneName, quint32 sceneID, bool nonZeroOnly) +{ + qDebug() << "[DUMP] # of values:" << dumpValues.count(); + qDebug() << "[DUMP] Selected fixture IDs:" << selectedFixtures; + qDebug() << "[DUMP] Channel mask:" << channelMask; + qDebug() << "[DUMP] Scene name/ID:" << sceneName << sceneID; + qDebug() << "[DUMP] Only non-zero?" << nonZeroOnly; + + QList ua = m_doc->inputOutputMap()->claimUniverses(); + + // 1- load current pre-GM values from all the universes + QByteArray preGMValues(ua.size() * UNIVERSE_SIZE, 0); + + for (int i = 0; i < ua.count(); ++i) + { + const int offset = i * UNIVERSE_SIZE; + preGMValues.replace(offset, UNIVERSE_SIZE, ua.at(i)->preGMValues()); + if (ua.at(i)->passthrough()) + { + for (int j = 0; j < UNIVERSE_SIZE; ++j) + { + const int ofs = offset + j; + preGMValues[ofs] = + static_cast(ua.at(i)->applyPassthrough(j, static_cast(preGMValues[ofs]))); + } + } + } + + m_doc->inputOutputMap()->releaseUniverses(false); + + // 2- determine if we're dumping on a new or existing Scene + Scene *targetScene = nullptr; + if (sceneID != Function::invalidId()) + { + targetScene = qobject_cast(m_doc->function(sceneID)); + } + else + { + targetScene = new Scene(m_doc); + targetScene->setName(sceneName); + } + + // 3- prepare the fixture list. If 'all channels' is required, + // selectedFixtures list will be empty + + QList fixtureList; + bool allChannels = false; + for (quint32 fixtureID : selectedFixtures) + { + Fixture *fixture = m_doc->fixture(fixtureID); + if (fixture != nullptr) + fixtureList.append(fixture); + } + + if (fixtureList.isEmpty()) + { + fixtureList.append(m_doc->fixtures()); + allChannels = true; + } + + // 4- iterate over all channels of all gathered fixtures + // and store values in the target Scene + for (Fixture *fixture : fixtureList) + { + quint32 baseAddress = fixture->universeAddress(); + + for (quint32 chIndex = 0; chIndex < fixture->channels(); chIndex++) + { + if (allChannels) + { + uchar value = preGMValues.at(baseAddress + chIndex); + if (!nonZeroOnly || (nonZeroOnly && value > 0)) + { + SceneValue scv = SceneValue(fixture->id(), chIndex, value); + targetScene->setValue(scv); + } + } + else + { + const QLCChannel *channel = fixture->channel(chIndex); + quint32 chTypeBit = 0; + + if (channel->group() == QLCChannel::Intensity) + { + if (channel->colour() == QLCChannel::NoColour) + chTypeBit |= App::DimmerType; + else + chTypeBit |= App::ColorType; + } + else + { + chTypeBit |= (1 << channel->group()); + } + + if (channelMask & chTypeBit) + { + uchar value = preGMValues.at(baseAddress + chIndex); + SceneValue scv = SceneValue(fixture->id(), chIndex, value); + int matchVal = dumpValues.indexOf(scv); + if (matchVal != -1) + scv.value = dumpValues.at(matchVal).value; + + targetScene->setValue(scv); + } + } + } + } + + // 5- add Scene to the project, if needed + if (sceneID == Function::invalidId()) + { + if (sceneName.isEmpty()) + targetScene->setName(QString("%1 %2").arg(targetScene->name()).arg(m_doc->nextFunctionID() + 1)); + else + targetScene->setName(sceneName); + + if (m_doc->addFunction(targetScene) == true) + { + setPreviewEnabled(false); + Tardis::instance()->enqueueAction(Tardis::FunctionCreate, targetScene->id(), QVariant(), + Tardis::instance()->actionToByteArray(Tardis::FunctionCreate, targetScene->id())); + } + else + delete targetScene; + } +} + quint32 FunctionManager::getChannelTypeMask(quint32 fxID, quint32 channel) { Fixture *fixture = m_doc->fixture(fxID); diff --git a/qmlui/functionmanager.h b/qmlui/functionmanager.h index ae753bfe7a..e5a84e54f7 100644 --- a/qmlui/functionmanager.h +++ b/qmlui/functionmanager.h @@ -88,6 +88,8 @@ class FunctionManager : public QObject /** Read only property to expose the function tree to the QML UI */ QVariant functionsList(); + Q_INVOKABLE quint32 nextFunctionId() const; + /** Get a list of Functions that use $fid */ Q_INVOKABLE QVariantList usageList(quint32 fid); @@ -289,6 +291,9 @@ public slots: /** Reset the currently set channel values */ void resetDumpValues(); + void dumpDmxValues(QList dumpValues, QList selectedFixtures, + quint32 channelMask, QString sceneName, quint32 sceneID, bool nonZeroOnly); + /** Dump DMX values provided by $dumpValues, filtered by the provided $selectedFixtures * and the provided $channelMask. * The new Scene will be named with $name if not empty, otherwise with an autogenerated name */ diff --git a/qmlui/inputoutputmanager.cpp b/qmlui/inputoutputmanager.cpp index 5e244b7587..56f9772787 100644 --- a/qmlui/inputoutputmanager.cpp +++ b/qmlui/inputoutputmanager.cpp @@ -213,6 +213,11 @@ void InputOutputManager::removeLastUniverse() emit universeNamesChanged(); } +int InputOutputManager::universesCount() +{ + return m_ioMap->universesCount(); +} + bool InputOutputManager::blackout() const { return m_blackout; diff --git a/qmlui/inputoutputmanager.h b/qmlui/inputoutputmanager.h index 4bac8c40ee..262ae9a124 100644 --- a/qmlui/inputoutputmanager.h +++ b/qmlui/inputoutputmanager.h @@ -79,6 +79,7 @@ protected slots: Q_INVOKABLE void addUniverse(); Q_INVOKABLE void removeLastUniverse(); + Q_INVOKABLE int universesCount(); /** Get/Set the global output blackout state */ bool blackout() const; diff --git a/qmlui/qml/MainView.qml b/qmlui/qml/MainView.qml index 5204b48b1a..9fafc22dfc 100644 --- a/qmlui/qml/MainView.qml +++ b/qmlui/qml/MainView.qml @@ -274,6 +274,8 @@ Rectangle implicitHeight: parent.height color: "transparent" } + + // ################## BEATS ################## RobotoText { label: "BPM: " + (ioManager.bpmNumber > 0 ? ioManager.bpmNumber : qsTr("Off")) @@ -331,6 +333,129 @@ Rectangle } } } + + // ################## DMX DUMP ################## + IconButton + { + id: sceneDump + z: 2 + implicitWidth: UISettings.iconSizeDefault + implicitHeight: UISettings.iconSizeDefault + Layout.alignment: Qt.AlignTop + bgColor: "transparent" + imgSource: "qrc:/dmxdump.svg" + imgMargins: 10 + tooltip: qsTr("Dump on a new Scene") + counter: (qlcplus.accessMask & App.AC_FunctionEditing) + + onClicked: + { + dmxDumpDialog.open() + dmxDumpDialog.focusEditItem() + } + + // channel count bubble + Rectangle + { + x: -3 + y: parent.height - height + 3 + width: sceneDump.width * 0.4 + height: width + color: "red" + border.width: 1 + border.color: UISettings.fgMain + radius: 3 + clip: true + visible: contextManager && contextManager.dumpValuesCount ? true : false + + RobotoText + { + anchors.centerIn: parent + height: parent.height * 0.7 + label: contextManager ? contextManager.dumpValuesCount : "" + fontSize: height + } + } + + MouseArea + { + id: dumpDragArea + anchors.fill: parent + propagateComposedEvents: true + drag.target: dumpDragItem + drag.threshold: 10 + onClicked: mouse.accepted = false + + property bool dragActive: drag.active + + onDragActiveChanged: + { + console.log("Drag active changed: " + dragActive) + if (dragActive == false) + { + dumpDragItem.Drag.drop() + dumpDragItem.parent = sceneDump + dumpDragItem.x = 0 + dumpDragItem.y = 0 + } + else + { + dumpDragItem.parent = mainView + } + + dumpDragItem.Drag.active = dragActive + } + } + + Item + { + id: dumpDragItem + z: 99 + visible: dumpDragArea.drag.active + + Drag.source: dumpDragItem + Drag.keys: [ "dumpValues" ] + + function itemDropped(id, name) + { + console.log("Dump values dropped on " + id) + dmxDumpDialog.sceneID = id + dmxDumpDialog.sceneName = name + dmxDumpDialog.open() + dmxDumpDialog.focusEditItem() + } + + Rectangle + { + width: UISettings.iconSizeMedium + height: width + radius: width / 4 + color: "red" + + RobotoText + { + anchors.centerIn: parent + label: contextManager ? contextManager.dumpValuesCount : "" + } + } + } + + PopupDMXDump + { + id: dmxDumpDialog + implicitWidth: Math.min(UISettings.bigItemHeight * 4, mainView.width / 3) + capabilityMask: fixtureManager ? fixtureManager.capabilityMask : 0 + channelSetMask: contextManager ? contextManager.dumpChannelMask : 0 + + onAccepted: + { + contextManager.dumpDmxChannels(getChannelsMask(), sceneName, existingScene && func ? func.id : -1, + allChannels, nonZeroOnly); + } + } + } + + // ################## STOP ALL FUNCTIONS ################## IconButton { id: stopAllButton @@ -413,5 +538,5 @@ Rectangle color: Qt.rgba(0, 0, 0, 0.5) } - PopupDisclaimer { } + //PopupDisclaimer { } } diff --git a/qmlui/qml/SimpleDesk.qml b/qmlui/qml/SimpleDesk.qml index 0f0beb57d5..949f05790b 100644 --- a/qmlui/qml/SimpleDesk.qml +++ b/qmlui/qml/SimpleDesk.qml @@ -114,11 +114,8 @@ Rectangle onClicked: { - if (dmxDumpDialog.show) - { - dmxDumpDialog.open() - dmxDumpDialog.focusEditItem() - } + dmxDumpDialog.open() + dmxDumpDialog.focusEditItem() } Rectangle @@ -146,7 +143,8 @@ Rectangle { id: dmxDumpDialog implicitWidth: Math.min(UISettings.bigItemHeight * 4, mainView.width / 3) - channelsMask: simpleDesk ? simpleDesk.dumpChannelMask : 0 + capabilityMask: simpleDesk ? simpleDesk.dumpChannelMask : 0 + channelSetMask: simpleDesk ? simpleDesk.dumpChannelMask : 0 onAccepted: simpleDesk.dumpDmxChannels(sceneName, getChannelsMask()) } diff --git a/qmlui/qml/fixturesfunctions/RightPanel.qml b/qmlui/qml/fixturesfunctions/RightPanel.qml index bae1a15a29..80d76d4080 100644 --- a/qmlui/qml/fixturesfunctions/RightPanel.qml +++ b/qmlui/qml/fixturesfunctions/RightPanel.qml @@ -321,138 +321,6 @@ SidePanel } } - IconButton - { - id: sceneDump - z: 2 - width: iconSize - height: iconSize - imgSource: "qrc:/dmxdump.svg" - tooltip: qsTr("Dump on a new Scene") - counter: contextManager ? contextManager.dumpValuesCount && (qlcplus.accessMask & App.AC_FunctionEditing) : 0 - - onClicked: - { - if (dmxDumpDialog.show) - { - dmxDumpDialog.sceneID = -1 - dmxDumpDialog.open() - dmxDumpDialog.focusEditItem() - } - else - { - contextManager.dumpDmxChannels("") - loaderSource = "qrc:/FunctionManager.qml" - animatePanel(true) - funcEditor.checked = true - } - } - - Rectangle - { - x: -3 - y: -3 - width: sceneDump.width * 0.4 - height: width - color: "red" - border.width: 1 - border.color: UISettings.fgMain - radius: 3 - clip: true - - RobotoText - { - anchors.centerIn: parent - height: parent.height * 0.7 - label: contextManager ? contextManager.dumpValuesCount : "" - fontSize: height - } - } - - MouseArea - { - id: dumpDragArea - anchors.fill: parent - propagateComposedEvents: true - drag.target: dumpDragItem - drag.threshold: 10 - onClicked: mouse.accepted = false - - property bool dragActive: drag.active - - onDragActiveChanged: - { - console.log("Drag active changed: " + dragActive) - if (dragActive == false) - { - dumpDragItem.Drag.drop() - dumpDragItem.parent = sceneDump - dumpDragItem.x = 0 - dumpDragItem.y = 0 - } - else - { - dumpDragItem.parent = mainView - } - - dumpDragItem.Drag.active = dragActive - } - } - - Item - { - id: dumpDragItem - z: 99 - visible: dumpDragArea.drag.active - - Drag.source: dumpDragItem - Drag.keys: [ "dumpValues" ] - - function itemDropped(id, name) - { - console.log("Dump values dropped on " + id) - dmxDumpDialog.sceneID = id - dmxDumpDialog.sceneName = name - dmxDumpDialog.open() - dmxDumpDialog.focusEditItem() - } - - Rectangle - { - width: UISettings.iconSizeMedium - height: width - radius: width / 4 - color: "red" - - RobotoText - { - anchors.centerIn: parent - label: contextManager ? contextManager.dumpValuesCount : "" - } - } - } - - PopupDMXDump - { - id: dmxDumpDialog - implicitWidth: Math.min(UISettings.bigItemHeight * 4, mainView.width / 3) - channelsMask: contextManager ? contextManager.dumpChannelMask : 0 - - property int sceneID: -1 - - onAccepted: - { - if (sceneID == -1) - contextManager.dumpDmxChannels(sceneName, getChannelsMask()) - else - contextManager.dumpDmxChannels(sceneID, getChannelsMask()) - loaderSource = "qrc:/FunctionManager.qml" - animatePanel(true) - funcEditor.checked = true - } - } - } - IconButton { z: 2 diff --git a/qmlui/qml/popup/PopupDMXDump.qml b/qmlui/qml/popup/PopupDMXDump.qml index 4fc8d376eb..96181a200b 100644 --- a/qmlui/qml/popup/PopupDMXDump.qml +++ b/qmlui/qml/popup/PopupDMXDump.qml @@ -28,11 +28,31 @@ CustomPopupDialog { id: popupRoot width: mainView.width / 2 - title: qsTr("Enter a name for the scene") + title: qsTr("DMX Channel Dump") - property bool show: !dontAskCheck.checked - property int channelsMask: 0 + property int capabilityMask: 0 + property int channelSetMask: 0 property alias sceneName: nameInputBox.text + property alias existingScene: existingSceneCheck.checked + property alias allChannels: allChannelsCheck.checked + property alias nonZeroOnly: nonZeroCheck.checked + property int universesCount: 0 + property int nextFunctionId: 0 + + property QLCFunction func + property int selectedFunctionsCount: 0 + + onOpened: + { + universesCount = ioManager.universesCount() + nextFunctionId = functionManager.nextFunctionId() + + // handle Function selection + var funcList = functionManager.selectedFunctionsID() + selectedFunctionsCount = funcList.length + if (funcList.length > 0) + func = functionManager.getFunction(funcList[0]) + } function getChannelsMask() { @@ -71,275 +91,392 @@ CustomPopupDialog nameInputBox.selectAndFocus() } + ButtonGroup { id: sceneTypeGroup } + ButtonGroup { id: dumpTypeGroup } + contentItem: GridLayout { - columns: 4 - columnSpacing: 5 + width: parent.width + columns: 1 - // row 1 - RowLayout + GroupBox { - Layout.columnSpan: 4 + title: qsTr("Target Scene") + Layout.fillWidth: true + font.family: UISettings.robotoFontName + font.pixelSize: UISettings.textSizeDefault + palette.windowText: UISettings.fgMain - RobotoText + GridLayout { - height: UISettings.listItemHeight - label: qsTr("Scene name") - } + width: parent.width + columns: 3 - CustomTextEdit - { - id: nameInputBox - Layout.fillWidth: true - text: qsTr("New Scene") - onAccepted: popupRoot.accept() - } - } + // row 1 + CustomCheckBox + { + id: newSceneCheck + implicitHeight: UISettings.listItemHeight + implicitWidth: implicitHeight + ButtonGroup.group: sceneTypeGroup + checked: true + } - // row 2 - CustomCheckBox - { - id: dontAskCheck - implicitHeight: UISettings.listItemHeight - implicitWidth: implicitHeight - Layout.alignment: Qt.AlignRight - autoExclusive: false - } - RobotoText - { - Layout.columnSpan: 3 - label: qsTr("Don't ask again") - } + RobotoText + { + height: UISettings.listItemHeight + label: qsTr("Dump to a new Scene") + } - // row 3 - RobotoText - { - Layout.columnSpan: 4 - label: qsTr("Available channel types") - } + CustomTextEdit + { + id: nameInputBox + Layout.fillWidth: true + text: qsTr("New Scene") + " " + nextFunctionId + onAccepted: popupRoot.accept() + } - // row 4 - CustomCheckBox - { - id: intTypeCheck - visible: channelsMask & App.DimmerType - implicitHeight: UISettings.listItemHeight - implicitWidth: implicitHeight - Layout.alignment: Qt.AlignRight - autoExclusive: false - checked: channelsMask & App.DimmerType + // row 2 + CustomCheckBox + { + id: existingSceneCheck + implicitHeight: UISettings.listItemHeight + implicitWidth: implicitHeight + ButtonGroup.group: sceneTypeGroup + } - } - IconTextEntry - { - visible: channelsMask & App.DimmerType - Layout.fillWidth: true - iSrc: "qrc:/intensity.svg" - tLabel: qsTr("Intensity") - } + RobotoText + { + height: UISettings.listItemHeight + label: qsTr("Dump to existing Scene") + } - CustomCheckBox - { - id: colTypeCheck - visible: channelsMask & App.ColorType - implicitHeight: UISettings.listItemHeight - implicitWidth: implicitHeight - Layout.alignment: Qt.AlignRight - autoExclusive: false - checked: channelsMask & App.ColorType - } - IconTextEntry - { - visible: channelsMask & App.ColorType - Layout.fillWidth: true - iSrc: "qrc:/color.svg" - tLabel: qsTr("RGB/CMY/WAUV") - } + RobotoText + { + visible: selectedFunctionsCount === 0 + label: qsTr("(None selected)") + } - // row 5 - CustomCheckBox - { - id: colMacroTypeCheck - visible: channelsMask & App.ColorMacroType - implicitHeight: UISettings.listItemHeight - implicitWidth: implicitHeight - Layout.alignment: Qt.AlignRight - autoExclusive: false - checked: channelsMask & App.ColorMacroType - } - IconTextEntry - { - visible: channelsMask & App.ColorMacroType - Layout.fillWidth: true - iSrc: "qrc:/colorwheel.svg" - tLabel: qsTr("Color macros") - } + IconTextEntry + { + id: funcBox + visible: selectedFunctionsCount + Layout.fillWidth: true - CustomCheckBox - { - id: goboTypeCheck - visible: channelsMask & App.GoboType - implicitHeight: UISettings.listItemHeight - implicitWidth: implicitHeight - Layout.alignment: Qt.AlignRight - autoExclusive: false - checked: channelsMask & App.GoboType - } - IconTextEntry - { - visible: channelsMask & App.GoboType - Layout.fillWidth: true - iSrc: "qrc:/gobo.svg" - tLabel: qsTr("Gobo") - } + tFontSize: UISettings.textSizeDefault - // row 6 - CustomCheckBox - { - id: panTypeCheck - visible: channelsMask & App.PanType - implicitHeight: UISettings.listItemHeight - implicitWidth: implicitHeight - Layout.alignment: Qt.AlignRight - autoExclusive: false - checked: channelsMask & App.PanType - } - IconTextEntry - { - visible: channelsMask & App.PanType - Layout.fillWidth: true - iSrc: "qrc:/pan.svg" - tLabel: qsTr("Pan") + tLabel: func ? func.name : "" + functionType: func ? func.type : -1 + } + } } - CustomCheckBox - { - id: tiltTypeCheck - visible: channelsMask & App.TiltType - implicitHeight: UISettings.listItemHeight - implicitWidth: implicitHeight - Layout.alignment: Qt.AlignRight - autoExclusive: false - checked: channelsMask & App.TiltType - } - IconTextEntry + GroupBox { - visible: channelsMask & App.TiltType + title: qsTr("Channels to dump") Layout.fillWidth: true - iSrc: "qrc:/tilt.svg" - tLabel: qsTr("Tilt") - } + font.family: UISettings.robotoFontName + font.pixelSize: UISettings.textSizeDefault + palette.windowText: UISettings.fgMain - // row 7 - CustomCheckBox - { - id: speedTypeCheck - visible: channelsMask & App.SpeedType - implicitHeight: UISettings.listItemHeight - implicitWidth: implicitHeight - Layout.alignment: Qt.AlignRight - autoExclusive: false - checked: channelsMask & App.SpeedType - } - IconTextEntry - { - visible: channelsMask & App.SpeedType - Layout.fillWidth: true - iSrc: "qrc:/speed.svg" - tLabel: qsTr("Speed") - } + GridLayout + { + width: parent.width + columns: 4 + columnSpacing: 5 - CustomCheckBox - { - id: shutterTypeCheck - visible: channelsMask & App.ShutterType - implicitHeight: UISettings.listItemHeight - implicitWidth: implicitHeight - Layout.alignment: Qt.AlignRight - autoExclusive: false - checked: channelsMask & App.ShutterType - } - IconTextEntry - { - visible: channelsMask & App.ShutterType - Layout.fillWidth: true - iSrc: "qrc:/shutter.svg" - tLabel: qsTr("Shutter/Strobe") - } + // row 1 + RowLayout + { + Layout.columnSpan: 4 + Layout.fillWidth: true - // row 8 - CustomCheckBox - { - id: prismTypeCheck - visible: channelsMask & App.PrismType - implicitHeight: UISettings.listItemHeight - implicitWidth: implicitHeight - Layout.alignment: Qt.AlignRight - autoExclusive: false - checked: channelsMask & App.PrismType - } - IconTextEntry - { - visible: channelsMask & App.PrismType - Layout.fillWidth: true - iSrc: "qrc:/prism.svg" - tLabel: qsTr("Prism") - } + CustomCheckBox + { + id: allChannelsCheck + implicitHeight: UISettings.listItemHeight + implicitWidth: implicitHeight + ButtonGroup.group: dumpTypeGroup + } + RobotoText + { + implicitHeight: UISettings.listItemHeight + Layout.fillWidth: true + label: qsTr("Dump all the available channels") + " (" + universesCount + " " + qsTr("Universes") + ", " + + fixtureManager.fixturesCount + " " + qsTr("Fixtures") + ")" + } + } - CustomCheckBox - { - id: beamTypeCheck - visible: channelsMask & App.BeamType - implicitHeight: UISettings.listItemHeight - implicitWidth: implicitHeight - Layout.alignment: Qt.AlignRight - autoExclusive: false - checked: channelsMask & App.BeamType - } - IconTextEntry - { - visible: channelsMask & App.BeamType - Layout.fillWidth: true - iSrc: "qrc:/beam.svg" - tLabel: qsTr("Beam") - } + Rectangle + { + width: UISettings.bigItemHeight / 2 + height: UISettings.listItemHeight + color: "transparent" + } - // row 9 - CustomCheckBox - { - id: effectTypeCheck - visible: channelsMask & App.EffectType - implicitHeight: UISettings.listItemHeight - implicitWidth: implicitHeight - Layout.alignment: Qt.AlignRight - autoExclusive: false - checked: channelsMask & App.EffectType - } - IconTextEntry - { - visible: channelsMask & App.EffectType - Layout.fillWidth: true - iSrc: "qrc:/star.svg" - tLabel: qsTr("Effect") - } + // row 2 + RowLayout + { + Layout.columnSpan: 3 + Layout.fillWidth: true - CustomCheckBox - { - id: maintTypeCheck - visible: channelsMask & App.MaintenanceType - implicitHeight: UISettings.listItemHeight - implicitWidth: implicitHeight - Layout.alignment: Qt.AlignRight - autoExclusive: false - checked: channelsMask & App.MaintenanceType - } - IconTextEntry - { - visible: channelsMask & App.MaintenanceType - Layout.fillWidth: true - iSrc: "qrc:/configure.svg" - tLabel: qsTr("Maintenance") - } + CustomCheckBox + { + id: nonZeroCheck + implicitHeight: UISettings.listItemHeight + implicitWidth: implicitHeight + checked: false + enabled: allChannelsCheck.checked + } + RobotoText + { + implicitHeight: UISettings.listItemHeight + Layout.fillWidth: true + label: qsTr("Dump only non-zero values") + enabled: allChannelsCheck.checked + } + } + + // row 3 + RowLayout + { + Layout.columnSpan: 4 + Layout.fillWidth: true + + CustomCheckBox + { + id: activeChannelsCheck + implicitHeight: UISettings.listItemHeight + implicitWidth: implicitHeight + checked: true + ButtonGroup.group: dumpTypeGroup + } + RobotoText + { + implicitHeight: UISettings.listItemHeight + label: qsTr("Dump the selected fixture channels") + } + } + + // row 5 + RobotoText + { + Layout.columnSpan: 4 + label: qsTr("Detected channel types") + } + + // row 6 + CustomCheckBox + { + id: intTypeCheck + visible: capabilityMask & App.DimmerType + implicitHeight: UISettings.listItemHeight + implicitWidth: implicitHeight + Layout.alignment: Qt.AlignRight + checked: channelSetMask & App.DimmerType + + } + IconTextEntry + { + visible: capabilityMask & App.DimmerType + Layout.fillWidth: true + iSrc: "qrc:/intensity.svg" + tLabel: qsTr("Intensity") + } + + CustomCheckBox + { + id: colTypeCheck + visible: capabilityMask & App.ColorType + implicitHeight: UISettings.listItemHeight + implicitWidth: implicitHeight + Layout.alignment: Qt.AlignRight + checked: channelSetMask & App.ColorType + } + IconTextEntry + { + visible: capabilityMask & App.ColorType + Layout.fillWidth: true + iSrc: "qrc:/color.svg" + tLabel: qsTr("RGB/CMY/WAUV") + } + + // row 7 + CustomCheckBox + { + id: colMacroTypeCheck + visible: capabilityMask & App.ColorMacroType + implicitHeight: UISettings.listItemHeight + implicitWidth: implicitHeight + Layout.alignment: Qt.AlignRight + checked: channelSetMask & App.ColorMacroType + } + IconTextEntry + { + visible: capabilityMask & App.ColorMacroType + Layout.fillWidth: true + iSrc: "qrc:/colorwheel.svg" + tLabel: qsTr("Color macros") + } + + CustomCheckBox + { + id: goboTypeCheck + visible: capabilityMask & App.GoboType + implicitHeight: UISettings.listItemHeight + implicitWidth: implicitHeight + Layout.alignment: Qt.AlignRight + checked: channelSetMask & App.GoboType + } + IconTextEntry + { + visible: capabilityMask & App.GoboType + Layout.fillWidth: true + iSrc: "qrc:/gobo.svg" + tLabel: qsTr("Gobo") + } + + // row 8 + CustomCheckBox + { + id: panTypeCheck + visible: capabilityMask & App.PanType + implicitHeight: UISettings.listItemHeight + implicitWidth: implicitHeight + Layout.alignment: Qt.AlignRight + checked: channelSetMask & App.PanType + } + IconTextEntry + { + visible: capabilityMask & App.PanType + Layout.fillWidth: true + iSrc: "qrc:/pan.svg" + tLabel: qsTr("Pan") + } + + CustomCheckBox + { + id: tiltTypeCheck + visible: capabilityMask & App.TiltType + implicitHeight: UISettings.listItemHeight + implicitWidth: implicitHeight + Layout.alignment: Qt.AlignRight + checked: channelSetMask & App.TiltType + } + IconTextEntry + { + visible: capabilityMask & App.TiltType + Layout.fillWidth: true + iSrc: "qrc:/tilt.svg" + tLabel: qsTr("Tilt") + } + + // row 9 + CustomCheckBox + { + id: speedTypeCheck + visible: capabilityMask & App.SpeedType + implicitHeight: UISettings.listItemHeight + implicitWidth: implicitHeight + Layout.alignment: Qt.AlignRight + checked: channelSetMask & App.SpeedType + } + IconTextEntry + { + visible: capabilityMask & App.SpeedType + Layout.fillWidth: true + iSrc: "qrc:/speed.svg" + tLabel: qsTr("Speed") + } + + CustomCheckBox + { + id: shutterTypeCheck + visible: capabilityMask & App.ShutterType + implicitHeight: UISettings.listItemHeight + implicitWidth: implicitHeight + Layout.alignment: Qt.AlignRight + checked: channelSetMask & App.ShutterType + } + IconTextEntry + { + visible: capabilityMask & App.ShutterType + Layout.fillWidth: true + iSrc: "qrc:/shutter.svg" + tLabel: qsTr("Shutter/Strobe") + } + + // row 10 + CustomCheckBox + { + id: prismTypeCheck + visible: capabilityMask & App.PrismType + implicitHeight: UISettings.listItemHeight + implicitWidth: implicitHeight + Layout.alignment: Qt.AlignRight + checked: channelSetMask & App.PrismType + } + IconTextEntry + { + visible: capabilityMask & App.PrismType + Layout.fillWidth: true + iSrc: "qrc:/prism.svg" + tLabel: qsTr("Prism") + } + + CustomCheckBox + { + id: beamTypeCheck + visible: capabilityMask & App.BeamType + implicitHeight: UISettings.listItemHeight + implicitWidth: implicitHeight + Layout.alignment: Qt.AlignRight + checked: channelSetMask & App.BeamType + } + IconTextEntry + { + visible: capabilityMask & App.BeamType + Layout.fillWidth: true + iSrc: "qrc:/beam.svg" + tLabel: qsTr("Beam") + } + + // row 11 + CustomCheckBox + { + id: effectTypeCheck + visible: capabilityMask & App.EffectType + implicitHeight: UISettings.listItemHeight + implicitWidth: implicitHeight + Layout.alignment: Qt.AlignRight + checked: channelSetMask & App.EffectType + } + IconTextEntry + { + visible: capabilityMask & App.EffectType + Layout.fillWidth: true + iSrc: "qrc:/star.svg" + tLabel: qsTr("Effect") + } + + CustomCheckBox + { + id: maintTypeCheck + visible: capabilityMask & App.MaintenanceType + implicitHeight: UISettings.listItemHeight + implicitWidth: implicitHeight + Layout.alignment: Qt.AlignRight + checked: channelSetMask & App.MaintenanceType + } + IconTextEntry + { + visible: capabilityMask & App.MaintenanceType + Layout.fillWidth: true + iSrc: "qrc:/configure.svg" + tLabel: qsTr("Maintenance") + } + } // GridLayout + } // GroupBox } // GridLayout } From c9eba4b91888df7f28290587605c1c63c5f023fa Mon Sep 17 00:00:00 2001 From: Massimo Callegari Date: Sat, 9 Nov 2024 20:27:23 +0100 Subject: [PATCH 20/68] virtual console: sort custom feedback tab order (fix #1637) --- ui/src/customfeedbackdialog.ui | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/ui/src/customfeedbackdialog.ui b/ui/src/customfeedbackdialog.ui index b8b0637bf7..2151436156 100644 --- a/ui/src/customfeedbackdialog.ui +++ b/ui/src/customfeedbackdialog.ui @@ -218,6 +218,18 @@ + + m_lowerSpin + m_lowerColor + m_upperSpin + m_upperColor + m_monitorSpin + m_monitorColor + m_lowerChannelCombo + m_upperChannelCombo + m_monitorChannelCombo + m_profileColorsTree + From 12db94b388640cb8a643e67039388b9ddbaad2e7 Mon Sep 17 00:00:00 2001 From: Massimo Callegari Date: Sun, 10 Nov 2024 11:14:47 +0100 Subject: [PATCH 21/68] qmlui: improve DMX dump UX and merge with Simple Desk --- qmlui/qml/MainView.qml | 173 +++++++++++++++++++------------ qmlui/qml/SimpleDesk.qml | 47 --------- qmlui/qml/popup/PopupDMXDump.qml | 6 ++ 3 files changed, 113 insertions(+), 113 deletions(-) diff --git a/qmlui/qml/MainView.qml b/qmlui/qml/MainView.qml index 9fafc22dfc..fb284be451 100644 --- a/qmlui/qml/MainView.qml +++ b/qmlui/qml/MainView.qml @@ -275,65 +275,6 @@ Rectangle color: "transparent" } - // ################## BEATS ################## - RobotoText - { - label: "BPM: " + (ioManager.bpmNumber > 0 ? ioManager.bpmNumber : qsTr("Off")) - color: gsMouseArea.containsMouse ? UISettings.bgLight : "transparent" - fontSize: UISettings.textSizeDefault - Layout.alignment: Qt.AlignTop - implicitWidth: width - implicitHeight: parent.height - - MouseArea - { - id: gsMouseArea - anchors.fill: parent - hoverEnabled: true - onClicked: beatSelectionPanel.visible = !beatSelectionPanel.visible - } - BeatGeneratorsPanel - { - id: beatSelectionPanel - parent: mainView - y: mainToolbar.height - x: beatIndicator.x - width - z: 51 - visible: false - } - } - Rectangle - { - id: beatIndicator - implicitWidth: height - implicitHeight: parent.height * 0.5 - Layout.alignment: Qt.AlignVCenter - radius: height / 2 - border.width: 2 - border.color: "#333" - color: UISettings.fgMedium - - ColorAnimation on color - { - id: cAnim - from: "#00FF00" - to: UISettings.fgMedium - // half the duration of the current BPM - duration: ioManager.bpmNumber ? 30000 / ioManager.bpmNumber : 200 - running: false - } - - Connections - { - id: beatSignal - target: ioManager - function onBeat() - { - cAnim.restart() - } - } - } - // ################## DMX DUMP ################## IconButton { @@ -345,11 +286,33 @@ Rectangle bgColor: "transparent" imgSource: "qrc:/dmxdump.svg" imgMargins: 10 - tooltip: qsTr("Dump on a new Scene") + tooltip: qsTr("Dump DMX values on a Scene") counter: (qlcplus.accessMask & App.AC_FunctionEditing) + property string bubbleLabel: { + if (currentContext === sdEntry.ctxName) + return simpleDesk ? simpleDesk.dumpValuesCount : "" + else + return contextManager ? contextManager.dumpValuesCount : "" + } + + function updateDumpVariables() + { + if (currentContext === sdEntry.ctxName) + { + dmxDumpDialog.capabilityMask = simpleDesk ? simpleDesk.dumpChannelMask : 0 + dmxDumpDialog.channelSetMask = simpleDesk ? simpleDesk.dumpChannelMask : 0 + } + else + { + dmxDumpDialog.capabilityMask = fixtureManager ? fixtureManager.capabilityMask : 0 + dmxDumpDialog.channelSetMask = contextManager ? contextManager.dumpChannelMask : 0 + } + } + onClicked: { + updateDumpVariables() dmxDumpDialog.open() dmxDumpDialog.focusEditItem() } @@ -366,13 +329,13 @@ Rectangle border.color: UISettings.fgMain radius: 3 clip: true - visible: contextManager && contextManager.dumpValuesCount ? true : false + visible: sceneDump.bubbleLabel !== "0" ? true : false RobotoText { anchors.centerIn: parent height: parent.height * 0.7 - label: contextManager ? contextManager.dumpValuesCount : "" + label: sceneDump.bubbleLabel fontSize: height } } @@ -435,7 +398,7 @@ Rectangle RobotoText { anchors.centerIn: parent - label: contextManager ? contextManager.dumpValuesCount : "" + label: sceneDump.bubbleLabel } } } @@ -444,17 +407,95 @@ Rectangle { id: dmxDumpDialog implicitWidth: Math.min(UISettings.bigItemHeight * 4, mainView.width / 3) - capabilityMask: fixtureManager ? fixtureManager.capabilityMask : 0 - channelSetMask: contextManager ? contextManager.dumpChannelMask : 0 onAccepted: { - contextManager.dumpDmxChannels(getChannelsMask(), sceneName, existingScene && func ? func.id : -1, + if (currentContext === sdEntry.ctxName) + { + simpleDesk.dumpDmxChannels(sceneName, getChannelsMask()) + } + else + { + contextManager.dumpDmxChannels(getChannelsMask(), sceneName, existingScene && func ? func.id : -1, allChannels, nonZeroOnly); + } } } } + // spacer + Rectangle + { + width: UISettings.iconSizeDefault / 2 + color: "transparent" + } + + // ################## BEATS ################## + RobotoText + { + label: "BPM: " + (ioManager.bpmNumber > 0 ? ioManager.bpmNumber : qsTr("Off")) + color: gsMouseArea.containsMouse ? UISettings.bgLight : "transparent" + fontSize: UISettings.textSizeDefault + Layout.alignment: Qt.AlignTop + implicitWidth: width + implicitHeight: parent.height + + MouseArea + { + id: gsMouseArea + anchors.fill: parent + hoverEnabled: true + onClicked: beatSelectionPanel.visible = !beatSelectionPanel.visible + } + BeatGeneratorsPanel + { + id: beatSelectionPanel + parent: mainView + y: mainToolbar.height + x: beatIndicator.x - width + z: 51 + visible: false + } + } + Rectangle + { + id: beatIndicator + implicitWidth: height + implicitHeight: parent.height * 0.5 + Layout.alignment: Qt.AlignVCenter + radius: height / 2 + border.width: 2 + border.color: "#333" + color: UISettings.fgMedium + + ColorAnimation on color + { + id: cAnim + from: "#00FF00" + to: UISettings.fgMedium + // half the duration of the current BPM + duration: ioManager.bpmNumber ? 30000 / ioManager.bpmNumber : 200 + running: false + } + + Connections + { + id: beatSignal + target: ioManager + function onBeat() + { + cAnim.restart() + } + } + } + + // spacer + Rectangle + { + width: UISettings.iconSizeDefault / 2 + color: "transparent" + } + // ################## STOP ALL FUNCTIONS ################## IconButton { diff --git a/qmlui/qml/SimpleDesk.qml b/qmlui/qml/SimpleDesk.qml index 949f05790b..348161741e 100644 --- a/qmlui/qml/SimpleDesk.qml +++ b/qmlui/qml/SimpleDesk.qml @@ -103,53 +103,6 @@ Rectangle Rectangle { Layout.fillWidth: true; color: "transparent" } - // Scene dump button - IconButton - { - id: sceneDump - z: 2 - imgSource: "qrc:/dmxdump.svg" - tooltip: qsTr("Dump on a new Scene") - counter: simpleDesk ? simpleDesk.dumpValuesCount && (qlcplus.accessMask & App.AC_FunctionEditing) : 0 - - onClicked: - { - dmxDumpDialog.open() - dmxDumpDialog.focusEditItem() - } - - Rectangle - { - x: -3 - //y: -3 - width: sceneDump.width * 0.4 - height: width - color: "red" - border.width: 1 - border.color: UISettings.fgMain - radius: 3 - clip: true - - RobotoText - { - anchors.centerIn: parent - height: parent.height * 0.7 - label: simpleDesk ? simpleDesk.dumpValuesCount : "" - fontSize: height - } - } - - PopupDMXDump - { - id: dmxDumpDialog - implicitWidth: Math.min(UISettings.bigItemHeight * 4, mainView.width / 3) - capabilityMask: simpleDesk ? simpleDesk.dumpChannelMask : 0 - channelSetMask: simpleDesk ? simpleDesk.dumpChannelMask : 0 - - onAccepted: simpleDesk.dumpDmxChannels(sceneName, getChannelsMask()) - } - } - // DMX/Percentage button DMXPercentageButton { diff --git a/qmlui/qml/popup/PopupDMXDump.qml b/qmlui/qml/popup/PopupDMXDump.qml index 96181a200b..762b3b1362 100644 --- a/qmlui/qml/popup/PopupDMXDump.qml +++ b/qmlui/qml/popup/PopupDMXDump.qml @@ -52,6 +52,9 @@ CustomPopupDialog selectedFunctionsCount = funcList.length if (funcList.length > 0) func = functionManager.getFunction(funcList[0]) + + if (capabilityMask == 0 && activeChannelsCheck.checked) + allChannels = true } function getChannelsMask() @@ -249,11 +252,13 @@ CustomPopupDialog id: activeChannelsCheck implicitHeight: UISettings.listItemHeight implicitWidth: implicitHeight + enabled: capabilityMask !== 0 ? true : false checked: true ButtonGroup.group: dumpTypeGroup } RobotoText { + enabled: capabilityMask !== 0 ? true : false implicitHeight: UISettings.listItemHeight label: qsTr("Dump the selected fixture channels") } @@ -263,6 +268,7 @@ CustomPopupDialog RobotoText { Layout.columnSpan: 4 + visible: capabilityMask !== 0 ? true : false label: qsTr("Detected channel types") } From 8b8049b11a6b3cce5385b3ca047d3ea20a1999e8 Mon Sep 17 00:00:00 2001 From: Massimo Callegari Date: Sun, 10 Nov 2024 12:26:42 +0100 Subject: [PATCH 22/68] build: move variable dump helper to main cmake file --- CMakeLists.txt | 9 +++++++++ platforms/macos/CMakeLists.txt | 9 --------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 874b02f6dc..55e9af1a0b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -219,3 +219,12 @@ INCLUDE(CPack) # Leave this on the last row of this file add_subdirectory(platforms) + +# HELPER: PRINT ALL VARIABLES KNOWN BY CMAKE + +#message("QTDIR: ${QT_DIR}") +#get_cmake_property(_variableNames VARIABLES) +#list (SORT _variableNames) +#foreach (_variableName ${_variableNames}) +# message(STATUS "${_variableName}=${${_variableName}}") +#endforeach() diff --git a/platforms/macos/CMakeLists.txt b/platforms/macos/CMakeLists.txt index 31dd16d5e0..d3595279a6 100644 --- a/platforms/macos/CMakeLists.txt +++ b/platforms/macos/CMakeLists.txt @@ -82,12 +82,3 @@ install(FILES ${SNDFILE_LIBDIR}/libsndfile.1.0.37.dylib DESTINATION ${INSTALLROO #install(FILES ${FFTW3_LIBDIR}/libpcre2-16.0.dylib DESTINATION ${INSTALLROOT}/${LIBSDIR}) # more deps: libzstd.1.dylib #libgthread-2.0.0.dylib #libglib-2.0.0.dylib #libintl.8.dylib # libpng16.16.dylib #libqjpeg.dylib #libjpeg.8.dylib #libmp3lame.0.dylib - -# HELPER: PRINT ALL VARIABLES KNOWN BY CMAKE - -#message("QTDIR: ${QT_DIR}") -#get_cmake_property(_variableNames VARIABLES) -#list (SORT _variableNames) -#foreach (_variableName ${_variableNames}) -# message(STATUS "${_variableName}=${${_variableName}}") -#endforeach() From e8ecb67e854989833fa5154c545e387a07b08576 Mon Sep 17 00:00:00 2001 From: Massimo Callegari Date: Mon, 11 Nov 2024 13:02:04 +0100 Subject: [PATCH 23/68] qmlui: fix fixture head selection Reported: https://www.qlcplus.org/forum/viewtopic.php?t=17864 --- qmlui/contextmanager.cpp | 3 +++ qmlui/fixturemanager.cpp | 4 +--- qmlui/qml/fixturesfunctions/FixtureGroupManager.qml | 1 - 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/qmlui/contextmanager.cpp b/qmlui/contextmanager.cpp index afc7a56412..6cb8c07e7e 100644 --- a/qmlui/contextmanager.cpp +++ b/qmlui/contextmanager.cpp @@ -553,6 +553,9 @@ void ContextManager::setFixtureSelection(quint32 itemID, int headIndex, bool ena int linkedIndex = FixtureUtils::itemLinkedIndex(itemID); int headIdx = FixtureUtils::itemHeadIndex(itemID); + if (enable) + qDebug() << "Selected itemID" << itemID << ", fixture ID" << fixtureID << ", head" << headIdx; + if (m_selectedFixtures.contains(itemID)) { if (enable == false) diff --git a/qmlui/fixturemanager.cpp b/qmlui/fixturemanager.cpp index 529f153694..ae59357fc0 100644 --- a/qmlui/fixturemanager.cpp +++ b/qmlui/fixturemanager.cpp @@ -621,9 +621,7 @@ void FixtureManager::addFixtureNode(Doc *doc, TreeModel *treeModel, Fixture *fix { for (int headIdx = 0; headIdx < fixture->heads(); headIdx++) { - quint32 iID = itemID; - if (fixture->type() == QLCFixtureDef::Dimmer) - iID = FixtureUtils::fixtureItemID(fixture->id(), headIdx, linkedIndex); + quint32 iID = FixtureUtils::fixtureItemID(fixture->id(), headIdx, linkedIndex); QVariantList headParams; headParams.append(QVariant::fromValue(fixture)); // classRef diff --git a/qmlui/qml/fixturesfunctions/FixtureGroupManager.qml b/qmlui/qml/fixturesfunctions/FixtureGroupManager.qml index 3d801c6fdb..d709920c48 100644 --- a/qmlui/qml/fixturesfunctions/FixtureGroupManager.qml +++ b/qmlui/qml/fixturesfunctions/FixtureGroupManager.qml @@ -500,7 +500,6 @@ Rectangle contextManager.setFixtureSelection(iID, -1, true) break; case App.HeadDragItem: - console.log("Head clicked. ItemID: " + qItem.itemID + ", head: " + iID) itemID = qItem.itemID contextManager.setFixtureSelection(qItem.itemID, iID, true); break; From edb4d31b81f1690efa70f4084acc479a28a163c3 Mon Sep 17 00:00:00 2001 From: Massimo Callegari Date: Mon, 11 Nov 2024 19:25:16 +0100 Subject: [PATCH 24/68] qmlui: increase position tool precision to 0.01 degrees --- engine/src/fixture.cpp | 2 +- engine/src/fixture.h | 2 +- qmlui/contextmanager.cpp | 2 +- qmlui/contextmanager.h | 2 +- qmlui/qml/CustomDoubleSpinBox.qml | 6 +++ qmlui/qml/fixturesfunctions/PositionTool.qml | 40 +++++++++++--------- 6 files changed, 32 insertions(+), 22 deletions(-) diff --git a/engine/src/fixture.cpp b/engine/src/fixture.cpp index 79153f8c5b..5535b13c3a 100644 --- a/engine/src/fixture.cpp +++ b/engine/src/fixture.cpp @@ -310,7 +310,7 @@ QVector Fixture::cmyChannels(int head) const return m_fixtureMode->heads().at(head).cmyChannels(); } -QList Fixture::positionToValues(int type, int degrees, bool isRelative) +QList Fixture::positionToValues(int type, float degrees, bool isRelative) { QList posList; // cache a list of channels processed, to avoid duplicates diff --git a/engine/src/fixture.h b/engine/src/fixture.h index 8dc2a49a42..f360210020 100644 --- a/engine/src/fixture.h +++ b/engine/src/fixture.h @@ -277,7 +277,7 @@ class Fixture : public QObject /** Return a list of DMX values based on the given position degrees * and the provided type (Pan or Tilt) */ - QList positionToValues(int type, int degrees, bool isRelative = false); + QList positionToValues(int type, float degrees, bool isRelative = false); /** Return a list of DMX values based on the given zoom degrees */ QList zoomToValues(float degrees, bool isRelative); diff --git a/qmlui/contextmanager.cpp b/qmlui/contextmanager.cpp index 6cb8c07e7e..c17520441b 100644 --- a/qmlui/contextmanager.cpp +++ b/qmlui/contextmanager.cpp @@ -1478,7 +1478,7 @@ void ContextManager::setChannelValueByType(int type, int value, bool isRelative, } } -void ContextManager::setPositionValue(int type, int degrees, bool isRelative) +void ContextManager::setPositionValue(int type, float degrees, bool isRelative) { // list to keep track of the already processed Fixture IDs QListfxIDs; diff --git a/qmlui/contextmanager.h b/qmlui/contextmanager.h index e41495eb5b..d39f8fada6 100644 --- a/qmlui/contextmanager.h +++ b/qmlui/contextmanager.h @@ -238,7 +238,7 @@ public slots: Q_INVOKABLE void setColorValue(QColor col, QColor wauv); /** Set a Pan/Tilt position in degrees */ - Q_INVOKABLE void setPositionValue(int type, int degrees, bool isRelative); + Q_INVOKABLE void setPositionValue(int type, float degrees, bool isRelative); /** Set Pan/Tilt values at half position */ Q_INVOKABLE void setPositionCenter(); diff --git a/qmlui/qml/CustomDoubleSpinBox.qml b/qmlui/qml/CustomDoubleSpinBox.qml index f60fe2a02b..628403e1e0 100644 --- a/qmlui/qml/CustomDoubleSpinBox.qml +++ b/qmlui/qml/CustomDoubleSpinBox.qml @@ -50,4 +50,10 @@ CustomSpinBox } onValueModified: realValue = value / Math.pow(10, decimals) + + function setValue(newValue) + { + value = newValue + realValue = newValue / Math.pow(10, decimals) + } } diff --git a/qmlui/qml/fixturesfunctions/PositionTool.qml b/qmlui/qml/fixturesfunctions/PositionTool.qml index 8aa9f3f910..c17fd4e160 100644 --- a/qmlui/qml/fixturesfunctions/PositionTool.qml +++ b/qmlui/qml/fixturesfunctions/PositionTool.qml @@ -36,11 +36,11 @@ Rectangle property int panMaxDegrees: 360 property int tiltMaxDegrees: 270 - property alias panDegrees: panSpinBox.value + property alias panDegrees: panSpinBox.realValue property int previousPanDegrees: 0 property bool relativePanValue: false - property alias tiltDegrees: tiltSpinBox.value + property alias tiltDegrees: tiltSpinBox.realValue property int previousTiltDegrees: 0 property bool relativeTiltValue: false @@ -63,7 +63,7 @@ Rectangle else { relativePanValue = false - panDegrees = Math.round(pan) + panDegrees = pan * Math.pow(10, panSpinBox.decimals) } var tilt = contextManager.getCurrentValue(QLCChannel.Tilt, true) @@ -75,7 +75,7 @@ Rectangle else { relativeTiltValue = false - tiltDegrees = Math.round(tilt) + tiltDegrees = tilt * Math.pow(10, tiltSpinBox.decimals) } } @@ -361,12 +361,13 @@ Rectangle label: "Pan" } - CustomSpinBox + CustomDoubleSpinBox { id: panSpinBox Layout.fillWidth: true - from: relativePanValue ? -panMaxDegrees : 0 - to: panMaxDegrees + realFrom: relativePanValue ? -panMaxDegrees : 0 + realTo: panMaxDegrees + realStep: 0.1 value: 0 suffix: "°" @@ -381,9 +382,10 @@ Rectangle tooltip: qsTr("Snap to the previous value") onClicked: { - var prev = (parseInt(panSpinBox.value / 45) * 45) - 45 + var prev = (parseInt(panSpinBox.realValue / 45) * 45) - 45 + console.log("---- PREV PAN " + prev) if (prev >= 0) - panSpinBox.value = prev + panSpinBox.setValue(prev * 100) } } IconButton @@ -394,9 +396,10 @@ Rectangle tooltip: qsTr("Snap to the next value") onClicked: { - var next = (parseInt(panSpinBox.value / 45) * 45) + 45 + var next = (parseInt(panSpinBox.realValue / 45) * 45) + 45 + console.log("---- NEXT PAN " + next) if (next <= panMaxDegrees) - panSpinBox.value = next + panSpinBox.setValue(next * 100) } } @@ -407,12 +410,13 @@ Rectangle label: "Tilt" } - CustomSpinBox + CustomDoubleSpinBox { id: tiltSpinBox Layout.fillWidth: true - from: relativeTiltValue ? -tiltMaxDegrees : 0 - to: tiltMaxDegrees + realFrom: relativeTiltValue ? -tiltMaxDegrees : 0 + realTo: tiltMaxDegrees + realStep: 0.1 value: 0 suffix: "°" @@ -430,9 +434,9 @@ Rectangle var fixedPos = tiltPositionsArray() for (var i = fixedPos.length - 1; i >= 0; i--) { - if (parseInt(fixedPos[i]) < tiltSpinBox.value) + if (parseInt(fixedPos[i]) < tiltDegrees) { - tiltSpinBox.value = parseInt(fixedPos[i]) + tiltSpinBox.setValue(parseInt(fixedPos[i]) * 100) break; } } @@ -449,9 +453,9 @@ Rectangle var fixedPos = tiltPositionsArray() for (var i = 0; i < fixedPos.length; i++) { - if (tiltSpinBox.value < parseInt(fixedPos[i])) + if (tiltDegrees < parseInt(fixedPos[i])) { - tiltSpinBox.value = parseInt(fixedPos[i]) + tiltSpinBox.setValue(parseInt(fixedPos[i]) * 100) break; } } From 604971604fdd40458a32e8730b808017e6f49cb4 Mon Sep 17 00:00:00 2001 From: Massimo Callegari Date: Tue, 12 Nov 2024 19:01:02 +0100 Subject: [PATCH 25/68] vcslider: send feedback for override button (fix #1635) --- ui/src/customfeedbackdialog.cpp | 1 + ui/src/virtualconsole/vcslider.cpp | 10 ++++++++++ ui/src/virtualconsole/vcslider.h | 2 ++ 3 files changed, 13 insertions(+) diff --git a/ui/src/customfeedbackdialog.cpp b/ui/src/customfeedbackdialog.cpp index 7e3b57fd61..9968cd7e37 100644 --- a/ui/src/customfeedbackdialog.cpp +++ b/ui/src/customfeedbackdialog.cpp @@ -134,6 +134,7 @@ void CustomFeedbackDialog::setMonitoringVisibility(bool visible) { m_monitorLabel->setVisible(visible); m_monitorSpin->setVisible(visible); + m_monitorColor->setVisible(visible); m_monitorChannelCombo->setVisible(visible); } diff --git a/ui/src/virtualconsole/vcslider.cpp b/ui/src/virtualconsole/vcslider.cpp index 676951d94a..c7e065a6ab 100644 --- a/ui/src/virtualconsole/vcslider.cpp +++ b/ui/src/virtualconsole/vcslider.cpp @@ -881,6 +881,7 @@ void VCSlider::slotResetButtonClicked() if (!fader.isNull()) fader->removeAll(); } + updateOverrideFeedback(false); emit monitorDMXValueChanged(m_monitorValue); } @@ -1370,6 +1371,7 @@ void VCSlider::setSliderValue(uchar value, bool scale, bool external) { m_resetButton->setStyleSheet(QString("QToolButton{ background: red; }")); m_isOverriding = true; + updateOverrideFeedback(true); } setLevelValue(val, external); setClickAndGoWidgetFromLevel(val); @@ -1510,6 +1512,13 @@ void VCSlider::updateFeedback() sendFeedback(fbv); } +void VCSlider::updateOverrideFeedback(bool on) +{ + QSharedPointer src = inputSource(overrideResetInputSourceId); + if (!src.isNull() && src->isValid() == true) + sendFeedback(src->feedbackValue(on ? QLCInputFeedback::UpperValue : QLCInputFeedback::LowerValue), overrideResetInputSourceId); +} + void VCSlider::slotSliderMoved(int value) { /* Set text for the top label */ @@ -1574,6 +1583,7 @@ void VCSlider::slotInputValueChanged(quint32 universe, quint32 channel, uchar va { m_resetButton->setStyleSheet(QString("QToolButton{ background: red; }")); m_isOverriding = true; + updateOverrideFeedback(true); } if (invertedAppearance()) diff --git a/ui/src/virtualconsole/vcslider.h b/ui/src/virtualconsole/vcslider.h index 280b498eae..d1eacdf1c7 100644 --- a/ui/src/virtualconsole/vcslider.h +++ b/ui/src/virtualconsole/vcslider.h @@ -494,6 +494,8 @@ protected slots: void updateFeedback(); + void updateOverrideFeedback(bool on); + signals: void requestSliderUpdate(int value); void valueChanged(QString val); From b23b6af6946b76ca3cce28539a290fe0f1c3715a Mon Sep 17 00:00:00 2001 From: Massimo Callegari Date: Sat, 16 Nov 2024 16:28:30 +0100 Subject: [PATCH 26/68] qmlui: implement custom feedback configuration dialog --- qmlui/qml/ExternalControlDelegate.qml | 99 +++--- qmlui/qml/ExternalControls.qml | 22 +- qmlui/qml/KeyboardSequenceDelegate.qml | 10 +- qmlui/qml/popup/PopupCustomFeedback.qml | 403 ++++++++++++++++++++++++ qmlui/qml/virtualconsole/qmldir | 1 + qmlui/qmlui.qrc | 1 + qmlui/virtualconsole/vcbutton.cpp | 3 - qmlui/virtualconsole/vcwidget.cpp | 217 +++++++++---- qmlui/virtualconsole/vcwidget.h | 21 +- 9 files changed, 645 insertions(+), 132 deletions(-) create mode 100644 qmlui/qml/popup/PopupCustomFeedback.qml diff --git a/qmlui/qml/ExternalControlDelegate.qml b/qmlui/qml/ExternalControlDelegate.qml index e7398a7963..af130a149f 100644 --- a/qmlui/qml/ExternalControlDelegate.qml +++ b/qmlui/qml/ExternalControlDelegate.qml @@ -25,9 +25,10 @@ import "." Column { + id: itemRoot width: parent.width - property var dObjRef: null + property var widgetObjRef: null property bool invalid: false property int controlID property alias inputModel: controlsCombo.model @@ -36,8 +37,8 @@ Column property string uniName property string chName property bool customFeedback: false - property int lowerFb: 0 - property int upperFb: 255 + + signal requestCustomFeedbackPopup() GridLayout { @@ -52,49 +53,27 @@ Column height: UISettings.listItemHeight label: qsTr("Control") } + CustomComboBox { id: controlsCombo Layout.fillWidth: true - Layout.columnSpan: 2 height: UISettings.listItemHeight currValue: controlID onValueChanged: { controlID = value - dObjRef.updateInputSourceControlID(universe, channel, controlID) + widgetObjRef.updateInputSourceControlID(universe, channel, controlID) } } - // row 2 - RobotoText - { - height: UISettings.listItemHeight - label: qsTr("Universe") - } - RobotoText - { - id: uniNameBox - Layout.fillWidth: true - height: UISettings.listItemHeight - color: UISettings.bgLight - label: uniName - - SequentialAnimation on color - { - PropertyAnimation { to: "red"; duration: 1000 } - PropertyAnimation { to: UISettings.bgLight; duration: 1000 } - running: invalid - loops: Animation.Infinite - } - } IconButton { width: UISettings.iconSizeMedium height: width checkable: true checked: invalid - imgSource: "qrc:/inputoutput.svg" + imgSource: "qrc:/wizard.svg" tooltip: qsTr("Activate auto detection") onToggled: @@ -102,7 +81,7 @@ Column if (checked == true) { if (invalid === false && - virtualConsole.enableInputSourceAutoDetection(dObjRef, controlID, universe, channel) === true) + virtualConsole.enableInputSourceAutoDetection(widgetObjRef, controlID, universe, channel) === true) invalid = true else checked = false @@ -117,19 +96,20 @@ Column } } - // row 3 + // row 2 RobotoText { height: UISettings.listItemHeight - label: qsTr("Channel") + label: qsTr("Universe") } + RobotoText { - id: chNameBox + id: uniNameBox Layout.fillWidth: true height: UISettings.listItemHeight color: UISettings.bgLight - label: chName + label: uniName SequentialAnimation on color { @@ -139,6 +119,7 @@ Column loops: Animation.Infinite } } + IconButton { width: UISettings.iconSizeMedium @@ -146,46 +127,44 @@ Column imgSource: "qrc:/remove.svg" tooltip: qsTr("Remove this input source") - onClicked: virtualConsole.deleteInputSource(dObjRef, controlID, universe, channel) + onClicked: virtualConsole.deleteInputSource(widgetObjRef, controlID, universe, channel) } + // row 3 RobotoText { - Layout.columnSpan: 3 - Layout.fillWidth: true height: UISettings.listItemHeight - visible: customFeedback - label: qsTr("Custom feedback") - color: UISettings.bgMedium + label: qsTr("Channel") } - Row + RobotoText { - id: cfRow - Layout.columnSpan: 3 + id: chNameBox Layout.fillWidth: true - spacing: 5 - visible: customFeedback + height: UISettings.listItemHeight + color: UISettings.bgLight + label: chName - RobotoText { id: cfLower; height: UISettings.listItemHeight; label: qsTr("Lower") } - CustomSpinBox + SequentialAnimation on color { - id: lowerSpin - width: (cfRow.width - cfLower.width - cfUpper.width - 20) / 2 - from: 0 - to: 255 - value: lowerFb - onValueChanged: if (dObjRef) dObjRef.updateInputSourceRange(universe, channel, value, upperSpin.value) + PropertyAnimation { to: "red"; duration: 1000 } + PropertyAnimation { to: UISettings.bgLight; duration: 1000 } + running: invalid + loops: Animation.Infinite } - RobotoText { id: cfUpper; height: UISettings.listItemHeight; label: qsTr("Upper") } - CustomSpinBox + } + + IconButton + { + visible: customFeedback + width: UISettings.iconSizeMedium + height: width + imgSource: "qrc:/inputoutput.svg" + tooltip: qsTr("Custom feedback selection") + + onClicked: { - id: upperSpin - width: (cfRow.width - cfLower.width - cfUpper.width - 20) / 2 - from: 0 - to: 255 - value: upperFb - onValueChanged: if (dObjRef) dObjRef.updateInputSourceRange(universe, channel, lowerSpin.value, value) + itemRoot.requestCustomFeedbackPopup() } } } // end of GridLayout diff --git a/qmlui/qml/ExternalControls.qml b/qmlui/qml/ExternalControls.qml index fb38d1a6bb..f440fef1a7 100644 --- a/qmlui/qml/ExternalControls.qml +++ b/qmlui/qml/ExternalControls.qml @@ -31,6 +31,11 @@ Column * an input sources list */ property var objRef: null + PopupCustomFeedback + { + id: cfbPopup + } + Rectangle { color: UISettings.bgMedium @@ -134,11 +139,12 @@ Column delegate: Loader { + id: extSrcListLoader width: sourcesListView.width source: modelData.type === VCWidget.Controller ? "qrc:/ExternalControlDelegate.qml" : "qrc:/KeyboardSequenceDelegate.qml" onLoaded: { - item.dObjRef = objRef + item.widgetObjRef = objRef item.inputModel = objRef.externalControlsList item.controlID = modelData.id @@ -152,14 +158,24 @@ Column item.uniName = modelData.uniString item.chName = modelData.chString item.customFeedback = modelData.customFeedback - item.lowerFb = modelData.lower - item.upperFb = modelData.upper } else if (modelData.type === VCWidget.Keyboard) { item.sequence = modelData.keySequence } } + + Connections + { + target: extSrcListLoader.item + function onRequestCustomFeedbackPopup() + { + cfbPopup.widgetObjRef = item.widgetObjRef + cfbPopup.universe = item.universe + cfbPopup.channel = item.channel + cfbPopup.open() + } + } } } } diff --git a/qmlui/qml/KeyboardSequenceDelegate.qml b/qmlui/qml/KeyboardSequenceDelegate.qml index 6f61848ef5..7bab2b46dd 100644 --- a/qmlui/qml/KeyboardSequenceDelegate.qml +++ b/qmlui/qml/KeyboardSequenceDelegate.qml @@ -27,7 +27,7 @@ Column { width: parent.width - property var dObjRef: null + property var widgetObjRef: null property int controlID property alias inputModel: controlsCombo.model property string sequence @@ -54,11 +54,11 @@ Column currValue: controlID onValueChanged: { - if (dObjRef && value != controlID) + if (widgetObjRef && value != controlID) { console.log("Key control changed " + value) controlID = value - virtualConsole.updateKeySequenceControlID(dObjRef, controlID, sequence) + virtualConsole.updateKeySequenceControlID(widgetObjRef, controlID, sequence) } } } @@ -98,7 +98,7 @@ Column if (checked == true) { if (invalid === false && - virtualConsole.enableKeyAutoDetection(dObjRef, controlID, sequence) === true) + virtualConsole.enableKeyAutoDetection(widgetObjRef, controlID, sequence) === true) invalid = true else checked = false @@ -118,7 +118,7 @@ Column imgSource: "qrc:/remove.svg" tooltip: qsTr("Remove this keyboard combination") - onClicked: virtualConsole.deleteKeySequence(dObjRef, controlID, sequence) + onClicked: virtualConsole.deleteKeySequence(widgetObjRef, controlID, sequence) } } } diff --git a/qmlui/qml/popup/PopupCustomFeedback.qml b/qmlui/qml/popup/PopupCustomFeedback.qml new file mode 100644 index 0000000000..296612537f --- /dev/null +++ b/qmlui/qml/popup/PopupCustomFeedback.qml @@ -0,0 +1,403 @@ +/* + Q Light Controller Plus + PopupCustomFeedback.qml + + Copyright (c) Massimo Callegari + + 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, + 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. +*/ + +import QtQuick 2.14 +import QtQuick.Layouts 1.14 +import QtQuick.Controls 2.14 + +import org.qlcplus.classes 1.0 +import "." + +CustomPopupDialog +{ + id: popupRoot + width: mainView.width / (colorTableList.visible ? 2 : 3) + title: qsTr("Custom Feedback") + standardButtons: Dialog.Cancel | Dialog.Ok + + property var widgetObjRef: null + property var universe + property var channel + + property alias lowerValue: lowerValueSpin.value + property alias upperValue: upperValueSpin.value + property alias monitorValue: monitorValueSpin.value + + property alias lowerColor: lowerColorBox.color + property alias upperColor: upperColorBox.color + property alias monitorColor: monitorColorBox.color + + property int selectedValue: -1 + + property bool hasColorTable: false + property bool hasMidiChannelTable: false + + onOpened: + { + if (!widgetObjRef) + return + + var sourceInfo = widgetObjRef.inputSourceFullInfo(universe, channel) + + lowerValue = sourceInfo.lowerValue + upperValue = sourceInfo.upperValue + monitorValue = sourceInfo.monitorValue + + if (sourceInfo.hasColorTable) + { + if (sourceInfo.hasOwnProperty("lowerColor")) + lowerColor = sourceInfo.lowerColor + if (sourceInfo.hasOwnProperty("upperColor")) + upperColor = sourceInfo.upperColor + if (sourceInfo.hasOwnProperty("monitorColor")) + monitorColor = sourceInfo.monitorColor + + hasColorTable = true + colorTableList.model = sourceInfo.colorTable + } + else + hasColorTable = false + + if (sourceInfo.hasMIDIChannelTable) + { + hasMidiChannelTable = true + lowerChannelCombo.model = sourceInfo.midiChannelTable + upperChannelCombo.model = sourceInfo.midiChannelTable + monitorChannelCombo.model = sourceInfo.midiChannelTable + + if (sourceInfo.hasOwnProperty("lowerChannel")) + lowerChannelCombo.currentIndex = sourceInfo.lowerChannel + if (sourceInfo.hasOwnProperty("upperChannel")) + upperChannelCombo.currentIndex = sourceInfo.upperChannel + if (sourceInfo.hasOwnProperty("monitorChannel")) + monitorChannelCombo.currentIndex = sourceInfo.monitorChannel + } + else + hasMidiChannelTable = false + } + + onAccepted: + { + if (!widgetObjRef) + return + + widgetObjRef.updateInputSourceFeedbackValues(universe, channel, lowerValue, upperValue, monitorValue) + + if (hasMidiChannelTable) + widgetObjRef.updateInputSourceExtraParams(universe, channel, + lowerChannelCombo.currentIndex, upperChannelCombo.currentIndex, monitorChannelCombo.currentIndex) + } + + function setFeedbackValue(value, color) + { + if (selectedValue == 0) + { + lowerValue = value + lowerColor = color + } + else if (selectedValue == 1) + { + upperValue = value + upperColor = color + } + else if (selectedValue == 2) + { + monitorValue = value + monitorColor = color + } + } + + contentItem: + GridLayout + { + width: popupRoot.width + columns: 2 + + ColumnLayout + { + id: valuesColumn + Layout.fillWidth: true + + GroupBox + { + title: qsTr("Values") + width: parent.width + font.family: UISettings.robotoFontName + font.pixelSize: UISettings.textSizeDefault + palette.windowText: UISettings.fgMain + + GridLayout + { + width: parent.width + columns: 3 + + // row 1 + RobotoText + { + height: UISettings.listItemHeight + label: qsTr("Lower Value") + } + + CustomSpinBox + { + id: lowerValueSpin + from: 0 + to: 255 + } + + Rectangle + { + id: lowerColorBox + visible: popupRoot.hasColorTable + height: UISettings.listItemHeight + width: UISettings.bigItemHeight + color: "black" + + border.width: 2 + border.color: popupRoot.selectedValue === 0 ? UISettings.selection : UISettings.fgMain + + MouseArea + { + anchors.fill: parent + onClicked: + { + selectedValue = 0 + colorTableList.visible = true + } + } + } + + // row 2 + RobotoText + { + height: UISettings.listItemHeight + label: qsTr("Upper Value") + } + + CustomSpinBox + { + id: upperValueSpin + from: 0 + to: 255 + } + + Rectangle + { + id: upperColorBox + visible: popupRoot.hasColorTable + height: UISettings.listItemHeight + width: UISettings.bigItemHeight + color: "black" + + border.width: 2 + border.color: popupRoot.selectedValue === 1 ? UISettings.selection : UISettings.fgMain + + MouseArea + { + anchors.fill: parent + onClicked: + { + selectedValue = 1 + colorTableList.visible = true + } + } + } + + // row 3 + RobotoText + { + height: UISettings.listItemHeight + label: qsTr("Monitor Value") + } + + CustomSpinBox + { + id: monitorValueSpin + from: 0 + to: 255 + } + + Rectangle + { + id: monitorColorBox + visible: popupRoot.hasColorTable + height: UISettings.listItemHeight + width: UISettings.bigItemHeight + color: "black" + + border.width: 2 + border.color: popupRoot.selectedValue === 2 ? UISettings.selection : UISettings.fgMain + + MouseArea + { + anchors.fill: parent + onClicked: + { + selectedValue = 2 + colorTableList.visible = true + } + } + } + } + } // GroupBox + + GroupBox + { + visible: popupRoot.hasMidiChannelTable + title: qsTr("MIDI Channel") + width: parent.width + font.family: UISettings.robotoFontName + font.pixelSize: UISettings.textSizeDefault + palette.windowText: UISettings.fgMain + + GridLayout + { + width: parent.width + columns: 2 + + // row 1 + RobotoText + { + height: UISettings.listItemHeight + label: qsTr("Lower Channel") + } + + CustomComboBox + { + id: lowerChannelCombo + Layout.fillWidth: true + height: UISettings.listItemHeight + textRole: "" + } + + // row 2 + RobotoText + { + height: UISettings.listItemHeight + label: qsTr("Upper Channel") + } + + CustomComboBox + { + id: upperChannelCombo + Layout.fillWidth: true + height: UISettings.listItemHeight + textRole: "" + } + + // row 3 + RobotoText + { + height: UISettings.listItemHeight + label: qsTr("Monitor Channel") + } + + CustomComboBox + { + id: monitorChannelCombo + Layout.fillWidth: true + height: UISettings.listItemHeight + textRole: "" + } + } + } // GroupBox + } // ColumnLayout + + ListView + { + id: colorTableList + visible: false + Layout.fillWidth: true + height: valuesColumn.height + + clip: true + boundsBehavior: Flickable.StopAtBounds + headerPositioning: ListView.OverlayHeader + + header: + RowLayout + { + z: 2 + width: colorTableList.width + height: UISettings.listItemHeight + + RobotoText + { + width: UISettings.bigItemHeight * 0.7 + height: UISettings.listItemHeight + label: qsTr("Value") + color: UISettings.sectionHeader + } + Rectangle { width: 1; height: UISettings.listItemHeight; color: UISettings.fgMedium } + + RobotoText + { + Layout.fillWidth: true + height: UISettings.listItemHeight + label: qsTr("Label") + color: UISettings.sectionHeader + } + Rectangle { width: 1; height: UISettings.listItemHeight; color: UISettings.fgMedium } + + RobotoText + { + width: UISettings.bigItemHeight + height: UISettings.listItemHeight + label: qsTr("Color") + color: UISettings.sectionHeader + } + } + + delegate: + RowLayout + { + width: colorTableList.width + height: UISettings.listItemHeight + + RobotoText + { + width: UISettings.bigItemHeight + height: UISettings.listItemHeight + label: modelData.index + } + RobotoText + { + Layout.fillWidth: true + height: UISettings.listItemHeight + label: modelData.name + } + Rectangle + { + width: UISettings.bigItemHeight + height: UISettings.listItemHeight + color: modelData.color + + MouseArea + { + anchors.fill: parent + onClicked: + { + popupRoot.setFeedbackValue(modelData.index, modelData.color) + } + } + } + } + } + } +} diff --git a/qmlui/qml/virtualconsole/qmldir b/qmlui/qml/virtualconsole/qmldir index 2d813e6045..716489b86e 100644 --- a/qmlui/qml/virtualconsole/qmldir +++ b/qmlui/qml/virtualconsole/qmldir @@ -21,6 +21,7 @@ IconButton 0.1 ../IconButton.qml IconPopupButton 0.1 ../IconPopupButton.qml IconTextEntry 0.1 ../IconTextEntry.qml MenuBarEntry 0.1 ../MenuBarEntry.qml +PopupCustomFeedback 0.1 ../popup/PopupCustomFeedback.qml QLCPlusFader 0.1 ../QLCPlusFader.qml QLCPlusKnob 0.1 ../QLCPlusKnob.qml RobotoText 0.1 ../RobotoText.qml diff --git a/qmlui/qmlui.qrc b/qmlui/qmlui.qrc index e0c168ee2b..307119419a 100644 --- a/qmlui/qmlui.qrc +++ b/qmlui/qmlui.qrc @@ -66,6 +66,7 @@ qml/popup/PopupChannelModifiers.qml qml/popup/PopupChannelWizard.qml qml/popup/PopupCreatePalette.qml + qml/popup/PopupCustomFeedback.qml qml/popup/PopupDisclaimer.qml qml/popup/PopupImportProject.qml qml/popup/PopupPINRequest.qml diff --git a/qmlui/virtualconsole/vcbutton.cpp b/qmlui/virtualconsole/vcbutton.cpp index 415f98d506..f64f428dc4 100644 --- a/qmlui/virtualconsole/vcbutton.cpp +++ b/qmlui/virtualconsole/vcbutton.cpp @@ -511,9 +511,6 @@ void VCButton::setStartupIntensity(qreal fraction) void VCButton::updateFeedback() { - if (m_state == Monitoring) - return; - if (m_state == Inactive) sendFeedback(0, INPUT_PRESSURE_ID, VCWidget::LowerValue); else if (m_state == Monitoring) diff --git a/qmlui/virtualconsole/vcwidget.cpp b/qmlui/virtualconsole/vcwidget.cpp index 5ef301fdb6..ac2572bc31 100644 --- a/qmlui/virtualconsole/vcwidget.cpp +++ b/qmlui/virtualconsole/vcwidget.cpp @@ -642,6 +642,113 @@ QVariant VCWidget::externalControlsList() const * Input sources *********************************************************************/ +QSharedPointer VCWidget::inputSource(quint32 universe, quint32 channel) +{ + for (QSharedPointer &source : m_inputSources) + if (source->universe() == universe && source->channel() == channel) + return source; + + return QSharedPointer(); +} + +QSharedPointer VCWidget::inputSource(quint32 id, quint32 universe, quint32 channel) const +{ + for (QSharedPointer source : m_inputSources) + { + if (source->id() == id && source->universe() == universe && source->channel() == channel) + return source; + } + + return QSharedPointer(); +} + +QVariant VCWidget::inputSourceFullInfo(quint32 universe, quint32 channel) +{ + QSharedPointer source = inputSource(universe, channel); + if (source.isNull()) + return QVariant(); + + uchar lowerValue = source->feedbackValue(QLCInputFeedback::LowerValue); + uchar upperValue = source->feedbackValue(QLCInputFeedback::UpperValue); + uchar monitorValue = source->feedbackValue(QLCInputFeedback::MonitorValue); + + QVariantMap infoMap; + infoMap["lowerValue"] = lowerValue; + infoMap["upperValue"] = upperValue; + infoMap["monitorValue"] = monitorValue; + + InputPatch *ip = m_doc->inputOutputMap()->inputPatch(source->universe()); + if (ip != NULL && ip->profile() != NULL) + { + QLCInputProfile *profile = ip->profile(); + if (profile->hasColorTable()) + { + infoMap["hasColorTable"] = true; + QVariantList colorTable; + QMapIterator > it(profile->colorTable()); + while (it.hasNext() == true) + { + it.next(); + QPair lc = it.value(); + QVariantMap colorInfoMap; + colorInfoMap["index"] = it.key(); + colorInfoMap["name"] = lc.first; + colorInfoMap["color"] = lc.second.name(); + + if (it.key() == lowerValue) + infoMap["lowerColor"] = lc.second.name(); + if (it.key() == upperValue) + infoMap["upperColor"] = lc.second.name(); + if (it.key() == monitorValue) + infoMap["monitorColor"] = lc.second.name(); + + colorTable.append(colorInfoMap); + } + infoMap["colorTable"] = QVariant::fromValue(colorTable); + } + else + { + infoMap["hasColorTable"] = false; + } + + if (profile->type() == QLCInputProfile::MIDI && profile->hasMidiChannelTable()) + { + infoMap["hasMIDIChannelTable"] = true; + + QVariantList midiChanelTable; + + midiChanelTable.append(tr("From plugin settings")); + + QMapIterator it(profile->midiChannelTable()); + while (it.hasNext() == true) + { + it.next(); + midiChanelTable.append(it.value()); + } + + QVariant extraParam = source->feedbackExtraParams(QLCInputFeedback::LowerValue); + if (extraParam.isValid()) + infoMap["lowerChannel"] = extraParam.toInt() + 1; + + extraParam = source->feedbackExtraParams(QLCInputFeedback::UpperValue); + if (extraParam.isValid()) + infoMap["upperChannel"] = extraParam.toInt() + 1; + + extraParam = source->feedbackExtraParams(QLCInputFeedback::MonitorValue); + if (extraParam.isValid()) + infoMap["monitorChannel"] = extraParam.toInt() + 1; + + infoMap["midiChannelTable"] = QVariant::fromValue(midiChanelTable); + } + else + { + infoMap["hasMIDIChannelTable"] = false; + } + } + + return QVariant::fromValue(infoMap); +} + void VCWidget::addInputSource(QSharedPointer const& source) { if (source.isNull() || m_externalControlList.isEmpty()) @@ -730,29 +837,50 @@ bool VCWidget::updateInputSource(QSharedPointer const& source, q bool VCWidget::updateInputSourceControlID(quint32 universe, quint32 channel, quint32 id) { - for (QSharedPointer source : m_inputSources) // C++11 - { - if (source->universe() == universe && source->channel() == channel) - { - source->setID(id); - return true; - } - } - return false; + QSharedPointer source = inputSource(universe, channel); + if (source.isNull()) + return false; + + source-> setID(id); + + return true; } -bool VCWidget::updateInputSourceRange(quint32 universe, quint32 channel, quint8 lower, quint8 upper) +bool VCWidget::updateInputSourceFeedbackValues(quint32 universe, quint32 channel, + quint8 lower, quint8 upper, quint8 monitor) { - for (QSharedPointer source : m_inputSources) // C++11 - { - if (source->universe() == universe && source->channel() == channel) - { - source->setFeedbackValue(QLCInputFeedback::LowerValue, lower); - source->setFeedbackValue(QLCInputFeedback::UpperValue, upper); - return true; - } - } - return false; + QSharedPointer source = inputSource(universe, channel); + if (source.isNull()) + return false; + + source->setFeedbackValue(QLCInputFeedback::LowerValue, lower); + source->setFeedbackValue(QLCInputFeedback::UpperValue, upper); + source->setFeedbackValue(QLCInputFeedback::MonitorValue, monitor); + + // TODO: tardis + m_doc->setModified(); + + updateFeedback(); + + return true; +} + +bool VCWidget::updateInputSourceExtraParams(quint32 universe, quint32 channel, int lower, int upper, int monitor) +{ + QSharedPointer source = inputSource(universe, channel); + if (source.isNull()) + return false; + + source->setFeedbackExtraParams(QLCInputFeedback::LowerValue, lower - 1); + source->setFeedbackExtraParams(QLCInputFeedback::UpperValue, upper - 1); + source->setFeedbackExtraParams(QLCInputFeedback::MonitorValue, monitor - 1); + + // TODO: tardis + m_doc->setModified(); + + updateFeedback(); + + return true; } void VCWidget::deleteInputSurce(quint32 id, quint32 universe, quint32 channel) @@ -781,14 +909,13 @@ QVariantList VCWidget::inputSourcesList() { m_sourcesList.clear(); - for (QSharedPointer source : m_inputSources) // C++11 + for (QSharedPointer &source : m_inputSources) // C++11 { if (source.isNull()) continue; QString uniName; QString chName; - uchar min = 0, max = UCHAR_MAX; bool supportCustomFeedback = false; if (!source->isValid() || m_doc->inputOutputMap()->inputSourceNames(source, uniName, chName) == false) @@ -802,16 +929,10 @@ QVariantList VCWidget::inputSourcesList() { QLCInputChannel *ich = ip->profile()->channel(source->channel()); if (ich != nullptr && ich->type() == QLCInputChannel::Button) - { - min = ich->lowerValue(); - max = ich->upperValue(); supportCustomFeedback = true; - } } QVariantMap sourceMap; - uchar lower = source->feedbackValue(QLCInputFeedback::LowerValue); - uchar upper = source->feedbackValue(QLCInputFeedback::UpperValue); if (source->isValid() == false) sourceMap.insert("invalid", true); @@ -822,8 +943,6 @@ QVariantList VCWidget::inputSourcesList() sourceMap.insert("chString", chName); sourceMap.insert("universe", source->universe()); sourceMap.insert("channel", source->channel()); - sourceMap.insert("lower", lower != 0 ? lower : min); - sourceMap.insert("upper", upper != UCHAR_MAX ? upper : max); sourceMap.insert("customFeedback", supportCustomFeedback); m_sourcesList.append(sourceMap); } @@ -868,33 +987,32 @@ void VCWidget::slotInputSourceValueChanged(quint32 universe, quint32 channel, uc slotInputValueChanged(source->id(), value); } -QSharedPointer VCWidget::inputSource(quint32 id, quint32 universe, quint32 channel) const -{ - for (QSharedPointer source : m_inputSources) // C++11 - { - if (source->id() == id && source->universe() == universe && source->channel() == channel) - return source; - } - - return QSharedPointer(); -} - void VCWidget::sendFeedback(int value, quint8 id, SourceValueType type) { if (isDisabled()) return; - for (QSharedPointer source : m_inputSources) // C++11 + for (QSharedPointer &source : m_inputSources) // C++11 { if (source->id() != id) continue; + QVariant extraParam = source->feedbackExtraParams(QLCInputFeedback::UpperValue); + if (type == LowerValue) + { value = source->feedbackValue(QLCInputFeedback::LowerValue); + extraParam = source->feedbackExtraParams(QLCInputFeedback::LowerValue); + } else if (type == UpperValue) + { value = source->feedbackValue(QLCInputFeedback::UpperValue); + } else if (type == MonitorValue) + { value = source->feedbackValue(QLCInputFeedback::MonitorValue); + extraParam = source->feedbackExtraParams(QLCInputFeedback::MonitorValue); + } // if in relative mode, send a "feedback" to this // input source so it can continue to emit values @@ -905,20 +1023,7 @@ void VCWidget::sendFeedback(int value, quint8 id, SourceValueType type) if (isDisabled()) // was acceptsInput() return; - QString chName = QString(); - - InputPatch *ip = m_doc->inputOutputMap()->inputPatch(source->universe()); - if (ip != nullptr) - { - QLCInputProfile *profile = ip->profile(); - if (profile != nullptr) - { - QLCInputChannel *ich = profile->channel(source->channel() & 0x0000FFFF); - if (ich != nullptr) - chName = ich->name(); - } - } - m_doc->inputOutputMap()->sendFeedBack(source->universe(), source->channel(), value, chName); + m_doc->inputOutputMap()->sendFeedBack(source->universe(), source->channel(), value, extraParam); return; } } diff --git a/qmlui/virtualconsole/vcwidget.h b/qmlui/virtualconsole/vcwidget.h index fbb06aec0d..3c2a5c0476 100644 --- a/qmlui/virtualconsole/vcwidget.h +++ b/qmlui/virtualconsole/vcwidget.h @@ -486,10 +486,20 @@ class VCWidget : public QObject /********************************************************************* * Input sources *********************************************************************/ +private: + /** Returns an input source from the provided universe and channel. + * Returns nullptr if not found */ + QSharedPointer inputSource(quint32 universe, quint32 channel); + public: enum SourceValueType { ExactValue, LowerValue, UpperValue, MonitorValue }; Q_ENUM(SourceValueType) + /** Return a input source reference that matches the specified $id, $universe and $channel */ + QSharedPointer inputSource(quint32 id, quint32 universe, quint32 channel) const; + + Q_INVOKABLE QVariant inputSourceFullInfo(quint32 universe, quint32 channel); + /** * Add an external input $source to the sources known by thie widget. * @@ -503,9 +513,13 @@ class VCWidget : public QObject /** Update the control ID of an existing input source bound to $universe and $channel */ Q_INVOKABLE bool updateInputSourceControlID(quint32 universe, quint32 channel, quint32 id); - /** Update the lower/upper values of an existing input source bound to $universe and $channel */ - Q_INVOKABLE bool updateInputSourceRange(quint32 universe, quint32 channel, quint8 lower, quint8 upper); + /** Update the feedback values of an existing input source bound to $universe and $channel */ + Q_INVOKABLE bool updateInputSourceFeedbackValues(quint32 universe, quint32 channel, + quint8 lower, quint8 upper, quint8 monitor); + /** Update the feedback extra parameters of an existing input source bound to $universe and $channel */ + Q_INVOKABLE bool updateInputSourceExtraParams(quint32 universe, quint32 channel, + int lower, int upper, int monitor); /** Delete an existing input source from this widget */ void deleteInputSurce(quint32 id, quint32 universe, quint32 channel); @@ -516,9 +530,6 @@ class VCWidget : public QObject /** Return a list of input sources to be used by the UI */ QVariantList inputSourcesList(); - /** Return a input source reference that matches the specified $id, $universe and $channel */ - QSharedPointer inputSource(quint32 id, quint32 universe, quint32 channel) const; - /** * Send a feedback to an external controller. * From 082ccaedc6b9e86521801a96096215453b82b285 Mon Sep 17 00:00:00 2001 From: Massimo Callegari Date: Sat, 16 Nov 2024 16:39:09 +0100 Subject: [PATCH 27/68] qmlui: don't allow the deletion of all VC pages Reported: https://www.qlcplus.org/forum/viewtopic.php?t=17906 --- qmlui/virtualconsole/virtualconsole.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/qmlui/virtualconsole/virtualconsole.cpp b/qmlui/virtualconsole/virtualconsole.cpp index 5eca190f7a..a2ebf0b94b 100644 --- a/qmlui/virtualconsole/virtualconsole.cpp +++ b/qmlui/virtualconsole/virtualconsole.cpp @@ -328,6 +328,9 @@ void VirtualConsole::deletePage(int index) if (index < 0 || index >= m_pages.count()) return; + if (m_pages.count() == 1) + return; + m_pages.at(index)->deleteChildren(); VCPage *page = m_pages.takeAt(index); m_contextManager->unregisterContext(page->previewContext()->name()); From 3022ee5d2dd5639373fe3b29652572425f71395e Mon Sep 17 00:00:00 2001 From: Massimo Callegari Date: Sat, 16 Nov 2024 17:30:12 +0100 Subject: [PATCH 28/68] ui: fix key sequence load with Qt 6.8.0 Reported: https://www.qlcplus.org/forum/viewtopic.php?t=17904 --- ui/src/virtualconsole/vcwidget.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ui/src/virtualconsole/vcwidget.cpp b/ui/src/virtualconsole/vcwidget.cpp index 0c4b0e148f..867c3560d4 100644 --- a/ui/src/virtualconsole/vcwidget.cpp +++ b/ui/src/virtualconsole/vcwidget.cpp @@ -780,7 +780,8 @@ QKeySequence VCWidget::stripKeySequence(const QKeySequence& seq) keys[i] = seq[i]; } #else - QKeyCombination keys[4] = { Qt::Key_unknown, Qt::Key_unknown, Qt::Key_unknown, Qt::Key_unknown}; + QKeyCombination keys[4] = { Qt::Key_unknown, QKeyCombination::fromCombined(0), + QKeyCombination::fromCombined(0), QKeyCombination::fromCombined(0)}; for (int i = 0; i < (int)seq.count() && i < 4; i++) { if ((seq[i].toCombined() & Qt::ControlModifier) != 0) From 0b4adcf9accd90d7d71bc3865c2419a71e0acc1d Mon Sep 17 00:00:00 2001 From: Massimo Callegari Date: Sat, 16 Nov 2024 20:08:40 +0100 Subject: [PATCH 29/68] engine: fix RGB panel physical properties save/load --- engine/src/fixture.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/engine/src/fixture.cpp b/engine/src/fixture.cpp index 5535b13c3a..f395dfed2c 100644 --- a/engine/src/fixture.cpp +++ b/engine/src/fixture.cpp @@ -1041,7 +1041,7 @@ bool Fixture::loadXML(QXmlStreamReader &xmlDoc, Doc *doc, { modeName = xmlDoc.readElementText(); } - else if (xmlDoc.name() == KXMLQLCPhysicalDimensionsWeight) + else if (xmlDoc.name() == KXMLQLCPhysicalDimensionsWidth) { width = xmlDoc.readElementText().toUInt(); } @@ -1260,7 +1260,7 @@ bool Fixture::saveXML(QXmlStreamWriter *doc) const /* RGB Panel physical dimensions */ if (m_fixtureDef != NULL && m_fixtureDef->model() == KXMLFixtureRGBPanel && m_fixtureMode != NULL) { - doc->writeTextElement(KXMLQLCPhysicalDimensionsWeight, + doc->writeTextElement(KXMLQLCPhysicalDimensionsWidth, QString::number(m_fixtureMode->physical().width())); doc->writeTextElement(KXMLQLCPhysicalDimensionsHeight, From 620f481a9d51bce30bb12e87a8f9a6f105e48277 Mon Sep 17 00:00:00 2001 From: Massimo Callegari Date: Sat, 16 Nov 2024 20:36:04 +0100 Subject: [PATCH 30/68] actions: build 32bit version with Qt6 A few packages have been removed from Qt5 --- .github/workflows/build.yml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 945c626f8c..3cdcc9feb8 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -368,15 +368,15 @@ jobs: mingw-w64-i686-flac mingw-w64-i686-fftw mingw-w64-i686-python-lxml - mingw-w64-i686-qt5-base - mingw-w64-i686-qt5-multimedia - mingw-w64-i686-qt5-serialport - mingw-w64-i686-qt5-websockets - mingw-w64-i686-qt5-script - mingw-w64-i686-qt5-tools - mingw-w64-i686-qt5-imageformats - mingw-w64-i686-qt5-svg - mingw-w64-i686-qt5-declarative + mingw-w64-i686-qt6-base + mingw-w64-i686-qt6-multimedia + mingw-w64-i686-qt6-serialport + mingw-w64-i686-qt6-websockets + mingw-w64-i686-qt6-script + mingw-w64-i686-qt6-tools + mingw-w64-i686-qt6-imageformats + mingw-w64-i686-qt6-svg + mingw-w64-i686-qt6-declarative mingw-w64-i686-nsis - name: Install legacy libusb (32 bit) From 87572c96af98debaae34700120deab409915cd5e Mon Sep 17 00:00:00 2001 From: Massimo Callegari Date: Sat, 16 Nov 2024 20:41:50 +0100 Subject: [PATCH 31/68] actions: disable 32bit builds as no longer possible (not without more effort) --- .github/workflows/build.yml | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 3cdcc9feb8..f26ae274dd 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -258,7 +258,7 @@ jobs: strategy: fail-fast: false matrix: - task: [compile-qt5, compile-qt5-32bit, compile-qt5qml] + task: [compile-qt5, compile-qt5qml] env: CI_REPO_SLUG: ${{ github.repository }} CI_BRANCH: ${{ github.head_ref }} @@ -368,15 +368,15 @@ jobs: mingw-w64-i686-flac mingw-w64-i686-fftw mingw-w64-i686-python-lxml - mingw-w64-i686-qt6-base - mingw-w64-i686-qt6-multimedia - mingw-w64-i686-qt6-serialport - mingw-w64-i686-qt6-websockets - mingw-w64-i686-qt6-script - mingw-w64-i686-qt6-tools - mingw-w64-i686-qt6-imageformats - mingw-w64-i686-qt6-svg - mingw-w64-i686-qt6-declarative + mingw-w64-i686-qt5-base + mingw-w64-i686-qt5-multimedia + mingw-w64-i686-qt5-serialport + mingw-w64-i686-qt5-websockets + mingw-w64-i686-qt5-script + mingw-w64-i686-qt5-tools + mingw-w64-i686-qt5-imageformats + mingw-w64-i686-qt5-svg + mingw-w64-i686-qt5-declarative mingw-w64-i686-nsis - name: Install legacy libusb (32 bit) From 3cc60e753ea164f13c728b7e14f8f5f67cc111d4 Mon Sep 17 00:00:00 2001 From: Massimo Callegari Date: Wed, 20 Nov 2024 19:14:58 +0100 Subject: [PATCH 32/68] plugins/osc: remove trailing padding from path Reported: https://www.qlcplus.org/forum/viewtopic.php?t=17911 --- plugins/osc/oscpacketizer.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/plugins/osc/oscpacketizer.cpp b/plugins/osc/oscpacketizer.cpp index 5deb9926bf..4213418075 100644 --- a/plugins/osc/oscpacketizer.cpp +++ b/plugins/osc/oscpacketizer.cpp @@ -111,7 +111,9 @@ bool OSCPacketizer::parseMessage(QByteArray const& data, QString& path, QByteArr return false; path = QString(data.mid(0, commaPos)); - qDebug() << " [OSC] path extracted:" << path; + // remove possible trailing zeroes used for padding + path.remove(QChar(0x00)); + //qDebug() << "[OSC] path extracted:" << path; int currPos = commaPos + 1; while (tagsEnded == false) @@ -133,7 +135,7 @@ bool OSCPacketizer::parseMessage(QByteArray const& data, QString& path, QByteArr int left = (typeArray.count() + 1) % 4; currPos += 3 - left; - qDebug () << "[OSC] Tags found:" << typeArray.count() << "currpos at" << currPos; + //qDebug () << "[OSC] Tags found:" << typeArray.count() << "currpos at" << currPos; foreach (TagType tag, typeArray) { From 03a31f0f8f53c4b25b41a409868adc1bdc577289 Mon Sep 17 00:00:00 2001 From: Massimo Callegari Date: Thu, 21 Nov 2024 18:35:30 +0100 Subject: [PATCH 33/68] macos: add local network access to bundle manifest (fix #1641) --- platforms/macos/Info.plist | 6 ++++++ platforms/macos/Info.plist.qmlui | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/platforms/macos/Info.plist b/platforms/macos/Info.plist index f5d8f90612..3aa35f8e4e 100644 --- a/platforms/macos/Info.plist +++ b/platforms/macos/Info.plist @@ -32,6 +32,12 @@ NSMicrophoneUsageDescription Process incoming audio + NSLocalNetworkUsageDescription + Access the local network for DMX-related protocols + + com.apple.developer.networking.multicast + + CFBundleDocumentTypes diff --git a/platforms/macos/Info.plist.qmlui b/platforms/macos/Info.plist.qmlui index 77f3e5367e..211659f627 100644 --- a/platforms/macos/Info.plist.qmlui +++ b/platforms/macos/Info.plist.qmlui @@ -32,6 +32,12 @@ NSMicrophoneUsageDescription Process incoming audio + NSLocalNetworkUsageDescription + Access the local network for DMX-related protocols + + com.apple.developer.networking.multicast + + CFBundleDocumentTypes From b747ea82f536a6f97c8d82c86e508b623bd147ca Mon Sep 17 00:00:00 2001 From: Massimo Callegari Date: Sat, 23 Nov 2024 10:05:01 +0100 Subject: [PATCH 34/68] build: improve appimage script to build v4 too --- create-appimage-cmake.sh | 50 ++++++++++++++++++++++++---------------- 1 file changed, 30 insertions(+), 20 deletions(-) diff --git a/create-appimage-cmake.sh b/create-appimage-cmake.sh index 66312c2211..8f2170e421 100755 --- a/create-appimage-cmake.sh +++ b/create-appimage-cmake.sh @@ -10,9 +10,14 @@ set -e TARGET_DIR=$HOME/qlcplus.AppDir +CMAKE_OPTS="" -# Compile translations -./translate.sh "qmlui" +if [ "$1" == "qmlui" ]; then + ./translate.sh "qmlui" + CMAKE_OPTS="-Dqmlui=ON" +else + ./translate.sh "ui" +fi # Build if [ -d build ]; then @@ -22,9 +27,9 @@ mkdir build cd build if [ -n "$QTDIR" ]; then - cmake -DCMAKE_PREFIX_PATH="$QTDIR/lib/cmake/" -Dqmlui=ON -Dappimage=ON -DINSTALL_ROOT=$TARGET_DIR .. + cmake -DCMAKE_PREFIX_PATH="$QTDIR/lib/cmake/" $CMAKE_OPTS -Dappimage=ON -DINSTALL_ROOT=$TARGET_DIR .. else - cmake -DCMAKE_PREFIX_PATH="/usr/lib/x86_64-linux-gnu/cmake/Qt5" -Dqmlui=ON -Dappimage=ON -DINSTALL_ROOT=$TARGET_DIR .. + cmake -DCMAKE_PREFIX_PATH="/usr/lib/x86_64-linux-gnu/cmake/Qt5" $CMAKE_OPTS -Dappimage=ON -DINSTALL_ROOT=$TARGET_DIR .. fi NUM_CPUS=$(nproc) || true @@ -40,30 +45,35 @@ if [ ! -d "$TARGET_DIR" ]; then fi make install -strip $TARGET_DIR/usr/bin/qlcplus-qml -# see variables.pri, where to find the LIBSDIR find $TARGET_DIR/usr/lib/ -name 'libqlcplusengine.so*' -exec strip -v {} \; -# FIXME: no rpath or runpath tag found. -chrpath -r "../lib" $TARGET_DIR/usr/bin/qlcplus-qml || true +if [ "$1" == "qmlui" ]; then + strip $TARGET_DIR/usr/bin/qlcplus-qml + # FIXME: no rpath or runpath tag found. + chrpath -r "../lib" $TARGET_DIR/usr/bin/qlcplus-qml || true + + pushd $TARGET_DIR/usr/bin + find . -name plugins.qmltypes -type f -delete + find . -name *.qmlc -type f -delete + rm -rf QtQuick/Extras QtQuick/Particles.2 QtQuick/XmlListModel + rm -rf QtQuick/Controls.2/designer QtQuick/Controls.2/Material + rm -rf QtQuick/Controls.2/Universal QtQuick/Controls.2/Fusion + rm -rf QtQuick/Controls.2/Imagine QtQuick/Controls.2/Scene2D + popd + sed -i -e 's/Exec=qlcplus --open %f/Exec=qlcplus-qml/g' $TARGET_DIR/qlcplus.desktop +else + strip $TARGET_DIR/usr/bin/qlcplus + chrpath -r "../lib" $TARGET_DIR/usr/bin/qlcplus || true + sed -i -e 's/Exec=qlcplus --open %f/Exec=qlcplus/g' $TARGET_DIR/qlcplus.desktop +fi -pushd $TARGET_DIR/usr/bin -find . -name plugins.qmltypes -type f -delete -find . -name *.qmlc -type f -delete -rm -rf QtQuick/Extras QtQuick/Particles.2 QtQuick/XmlListModel -rm -rf QtQuick/Controls.2/designer QtQuick/Controls.2/Material -rm -rf QtQuick/Controls.2/Universal QtQuick/Controls.2/Fusion -rm -rf QtQuick/Controls.2/Imagine QtQuick/Controls.2/Scene2D -popd +cp -v ../resources/icons/svg/qlcplus.svg $TARGET_DIR +cp -v ../platforms/linux/qlcplus.desktop $TARGET_DIR # There might be a new version of the tool available. wget -c https://github.com/AppImage/AppImageKit/releases/download/continuous/AppRun-x86_64 -O $TARGET_DIR/AppRun chmod a+x $TARGET_DIR/AppRun -cp -v ../resources/icons/svg/qlcplus.svg $TARGET_DIR -cp -v ../platforms/linux/qlcplus.desktop $TARGET_DIR -sed -i -e 's/Exec=qlcplus --open %f/Exec=qlcplus-qml/g' $TARGET_DIR/qlcplus.desktop - # There might be a new version of the tool available. wget -c https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage -O /tmp/appimagetool-x86_64.AppImage chmod a+x /tmp/appimagetool-x86_64.AppImage From 46d7895ed06acbb37a3e684118266d3612432c82 Mon Sep 17 00:00:00 2001 From: Massimo Callegari Date: Sat, 23 Nov 2024 10:05:16 +0100 Subject: [PATCH 35/68] actions: use cmake for Linux builds --- .github/workflows/build.yml | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index f26ae274dd..01938e9b68 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -150,18 +150,25 @@ jobs: - name: Configure for QT5 build if: ${{ matrix.task == 'compile-qt5' }} run: | - ${QMAKE} QMAKE_CXX="${CXX}" QMAKE_CC="${CC}" QMAKE_LINK="${CXX}" QMAKE_LINK_SHLIB="${CXX}" CONFIG+=appimage FORCECONFIG=release + # force a release build + sed -i -e 's/Debug/Release/g' CMakeLists.txt + mkdir build + cd build + cmake -DCMAKE_PREFIX_PATH="$QTDIR/lib/cmake/" -Dappimage=ON -DINSTALL_ROOT=$TARGET_DIR .. - name: Configure for QT5QML build if: ${{ matrix.task == 'compile-qt5qml' }} run: | - $QMAKE QMAKE_CXX="$CXX" QMAKE_CC="$CC" QMAKE_LINK="$CXX" QMAKE_LINK_SHLIB="$CXX" CONFIG+=appimage CONFIG+=qmlui FORCECONFIG=release + # force a release build + sed -i -e 's/Debug/Release/g' CMakeLists.txt + mkdir build + cd build + cmake -DCMAKE_PREFIX_PATH="$QTDIR/lib/cmake/" -Dqmlui=ON -Dappimage=ON -DINSTALL_ROOT=$TARGET_DIR .. - name: Configure for QT5 coverage build if: ${{ matrix.task == 'coverage-qt5' }} run: | $QMAKE QMAKE_CXX="$CXX" QMAKE_CC="$CC" QMAKE_LINK="$CXX" QMAKE_LINK_SHLIB="$CXX" CONFIG+=coverage - #QMAKE_CXXFLAGS+="-fno-sized-deallocation" - name: Build run: make -j $NPROC From b2c90ee16a5b6b712a4939da7978b4d32f078fd1 Mon Sep 17 00:00:00 2001 From: Massimo Callegari Date: Sat, 23 Nov 2024 10:14:02 +0100 Subject: [PATCH 36/68] actions: fix cmake install root path --- .github/workflows/build.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 01938e9b68..7f431632f5 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -154,7 +154,7 @@ jobs: sed -i -e 's/Debug/Release/g' CMakeLists.txt mkdir build cd build - cmake -DCMAKE_PREFIX_PATH="$QTDIR/lib/cmake/" -Dappimage=ON -DINSTALL_ROOT=$TARGET_DIR .. + cmake -DCMAKE_PREFIX_PATH="$QTDIR/lib/cmake/" -Dappimage=ON -DINSTALL_ROOT=${INSTALL_ROOT} .. - name: Configure for QT5QML build if: ${{ matrix.task == 'compile-qt5qml' }} @@ -163,7 +163,7 @@ jobs: sed -i -e 's/Debug/Release/g' CMakeLists.txt mkdir build cd build - cmake -DCMAKE_PREFIX_PATH="$QTDIR/lib/cmake/" -Dqmlui=ON -Dappimage=ON -DINSTALL_ROOT=$TARGET_DIR .. + cmake -DCMAKE_PREFIX_PATH="$QTDIR/lib/cmake/" -Dqmlui=ON -Dappimage=ON -DINSTALL_ROOT=${INSTALL_ROOT} .. - name: Configure for QT5 coverage build if: ${{ matrix.task == 'coverage-qt5' }} From 7fbefde9e7f09e9f899aa8a668015873fd234d08 Mon Sep 17 00:00:00 2001 From: Massimo Callegari Date: Sat, 23 Nov 2024 10:17:53 +0100 Subject: [PATCH 37/68] actions: fix some more paths --- .github/workflows/build.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 7f431632f5..11627a57a4 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -171,7 +171,7 @@ jobs: $QMAKE QMAKE_CXX="$CXX" QMAKE_CC="$CC" QMAKE_LINK="$CXX" QMAKE_LINK_SHLIB="$CXX" CONFIG+=coverage - name: Build - run: make -j $NPROC + run: cd build && make -j $NPROC - name: Test if: ${{ ! startsWith( matrix.task, 'coverage') }} @@ -192,6 +192,7 @@ jobs: - name: Install if: ${{ ! startsWith( matrix.task, 'coverage') }} run: | + cd build make INSTALL_ROOT=${INSTALL_ROOT} install cp -v resources/icons/svg/qlcplus.svg ${INSTALL_ROOT} cp -v platforms/linux/qlcplus.desktop ${INSTALL_ROOT} From 21de26f8eb83c8d89c9876c9303230d5a68a98de Mon Sep 17 00:00:00 2001 From: Massimo Callegari Date: Sat, 23 Nov 2024 10:24:09 +0100 Subject: [PATCH 38/68] actions: fix coverage build --- .github/workflows/build.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 11627a57a4..081b7bb2e5 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -171,8 +171,13 @@ jobs: $QMAKE QMAKE_CXX="$CXX" QMAKE_CC="$CC" QMAKE_LINK="$CXX" QMAKE_LINK_SHLIB="$CXX" CONFIG+=coverage - name: Build + if: ${{ ! startsWith( matrix.task, 'coverage') }} run: cd build && make -j $NPROC + - name: Build Coverage + if: ${{ startsWith( matrix.task, 'coverage') }} + run: make -j $NPROC + - name: Test if: ${{ ! startsWith( matrix.task, 'coverage') }} run: make check From 5872b022aab570b0224654c22212fc43cb907aec Mon Sep 17 00:00:00 2001 From: Massimo Callegari Date: Sat, 23 Nov 2024 10:31:23 +0100 Subject: [PATCH 39/68] actions: fix unit test check --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 081b7bb2e5..2070b9287c 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -180,7 +180,7 @@ jobs: - name: Test if: ${{ ! startsWith( matrix.task, 'coverage') }} - run: make check + run: cd build && make check - name: Test with Coverage if: ${{ startsWith( matrix.task, 'coverage') }} From 48a8bf859f518ee852343193f6d41bfbf93eae1b Mon Sep 17 00:00:00 2001 From: Massimo Callegari Date: Sat, 23 Nov 2024 10:39:54 +0100 Subject: [PATCH 40/68] actions: fix more paths --- .github/workflows/build.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 2070b9287c..9b49a408e7 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -199,8 +199,8 @@ jobs: run: | cd build make INSTALL_ROOT=${INSTALL_ROOT} install - cp -v resources/icons/svg/qlcplus.svg ${INSTALL_ROOT} - cp -v platforms/linux/qlcplus.desktop ${INSTALL_ROOT} + cp -v ../resources/icons/svg/qlcplus.svg ${INSTALL_ROOT} + cp -v ../platforms/linux/qlcplus.desktop ${INSTALL_ROOT} - name: Adapt qlcplus for AppImage (qt5) if: ${{ matrix.task == 'compile-qt5' }} From 456f2284c362beb240c827284d79a89eb24c3a7e Mon Sep 17 00:00:00 2001 From: Massimo Callegari Date: Sun, 24 Nov 2024 16:28:29 +0100 Subject: [PATCH 41/68] plugins/dmxusb: chore --- plugins/dmxusb/src/enttecdmxusbpro.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/plugins/dmxusb/src/enttecdmxusbpro.cpp b/plugins/dmxusb/src/enttecdmxusbpro.cpp index 12b6c16d49..08d624cf57 100644 --- a/plugins/dmxusb/src/enttecdmxusbpro.cpp +++ b/plugins/dmxusb/src/enttecdmxusbpro.cpp @@ -243,11 +243,10 @@ bool EnttecDMXUSBPro::close(quint32 line, bool input) int readData(DMXInterface *iface, QByteArray &payload, bool &isMIDI, bool needRDM) { - bool ok = false; uchar byte = 0; // Skip bytes until we find the start of the next message - if ((byte = iface->readByte(&ok)) != ENTTEC_PRO_START_OF_MSG) + if ((iface->readByte()) != ENTTEC_PRO_START_OF_MSG) return 0; // Check the message type From 97756c0da938b70873038cbde592cb10d13ec011 Mon Sep 17 00:00:00 2001 From: Massimo Callegari Date: Sun, 24 Nov 2024 17:59:23 +0100 Subject: [PATCH 42/68] qmlui: improve Scene editor fixture selection --- qmlui/modelselector.cpp | 3 ++ qmlui/modelselector.h | 1 + qmlui/qml/fixturesfunctions/SceneEditor.qml | 46 +++++++-------------- 3 files changed, 19 insertions(+), 31 deletions(-) diff --git a/qmlui/modelselector.cpp b/qmlui/modelselector.cpp index e641d1ab8f..2a6e1ae195 100644 --- a/qmlui/modelselector.cpp +++ b/qmlui/modelselector.cpp @@ -40,6 +40,8 @@ void ModelSelector::selectSingleItem(int index, ListModel *model) model->setDataWithRole(idx, "isSelected", true); m_selectedIndices.append(index); m_itemsCount++; + + emit itemSelectionChanged(index, true); } void ModelSelector::selectItem(int index, ListModel *model, int keyModifiers) @@ -78,6 +80,7 @@ void ModelSelector::resetSelection(ListModel *model) { QModelIndex idx = model->index(int(sidx), 0, QModelIndex()); model->setDataWithRole(idx, "isSelected", false); + emit itemSelectionChanged(sidx, false); } m_selectedIndices.clear(); diff --git a/qmlui/modelselector.h b/qmlui/modelselector.h index 2c9f99e1a9..582e093d61 100644 --- a/qmlui/modelselector.h +++ b/qmlui/modelselector.h @@ -55,6 +55,7 @@ class ModelSelector : public QObject signals: void itemsCountChanged(int itemsCount); + void itemSelectionChanged(int itemIndex, bool selected); private: /** List of the currently selected item indices */ diff --git a/qmlui/qml/fixturesfunctions/SceneEditor.qml b/qmlui/qml/fixturesfunctions/SceneEditor.qml index cc7bd4daae..b103033cd7 100644 --- a/qmlui/qml/fixturesfunctions/SceneEditor.qml +++ b/qmlui/qml/fixturesfunctions/SceneEditor.qml @@ -58,7 +58,17 @@ Rectangle ModelSelector { id: seSelector - onItemsCountChanged: console.log("Scene Editor selected items changed!") + //onItemsCountChanged: console.log("Scene Editor selected items changed!") + onItemSelectionChanged: + { + var item = sfxList.itemAtIndex(itemIndex) + if (item.itemType === App.FixtureDragItem) + { + contextManager.setFixtureIDSelection(item.itemId, selected) + if (selected) + sceneEditor.setFixtureSelection(item.itemId) + } + } } TimeEditTool @@ -238,6 +248,7 @@ Rectangle color: "transparent" property int itemType: model.type + property int itemId: model.cRef.id Rectangle { @@ -273,44 +284,17 @@ Rectangle onClicked: { - seSelector.selectItem(index, sfxList.model, mouse.modifiers) - if (compDelegate.itemType === App.FixtureDragItem) { - if (!(mouse.modifiers & Qt.ControlModifier)) + if (!mouse.modifiers) contextManager.resetFixtureSelection() - - contextManager.setFixtureIDSelection(model.cRef.id, true) - sceneEditor.setFixtureSelection(model.cRef.id) } - } - //onDoubleClicked: fxDelegate.mouseEvent(App.DoubleClicked, cRef.id, cRef.type, fxDelegate, -1) - } - } - } - /* - FixtureDelegate - { - cRef: model.cRef - width: seContainer.width - isSelected: model.isSelected - Component.onCompleted: contextManager.setFixtureIDSelection(cRef.id, true) - Component.onDestruction: if (contextManager) contextManager.setFixtureIDSelection(cRef.id, false) - onMouseEvent: - { - if (type === App.Clicked) - { - seSelector.selectItem(index, sfxList.model, mouseMods) - - if (!(mouseMods & Qt.ControlModifier)) - contextManager.resetFixtureSelection() - contextManager.setFixtureIDSelection(cRef.id, true) - sceneEditor.setFixtureSelection(cRef.id) + seSelector.selectItem(index, sfxList.model, mouse.modifiers) + } } } } - */ DropArea { From 6ee40aa635f27315950318b9c44a9fd54e2afd4f Mon Sep 17 00:00:00 2001 From: Massimo Callegari Date: Mon, 25 Nov 2024 19:20:09 +0100 Subject: [PATCH 43/68] resources: 6 new fixtures (see changelog) --- debian/changelog | 9 +- .../fixtures/Ayra/Ayra-ERO-Micro-Beam-FX.qxf | 87 ++ resources/fixtures/Ayrton/Ayrton-Kyalami.qxf | 327 +++++++ .../Chauvet/Chauvet-EVE-P-160-RGBW.qxf | 122 +++ resources/fixtures/FixturesMap.xml | 6 + .../Shehds/Shehds-LED-Beam-12x12W-RGBW.qxf | 76 ++ .../Shehds-LED-Wall-Wash-18x18W-RGBWA+UV.qxf | 796 ++++++++++++++++++ .../Stairville-Wild-Wash-132-LED-CW.qxf | 71 ++ 8 files changed, 1492 insertions(+), 2 deletions(-) create mode 100644 resources/fixtures/Ayra/Ayra-ERO-Micro-Beam-FX.qxf create mode 100644 resources/fixtures/Ayrton/Ayrton-Kyalami.qxf create mode 100644 resources/fixtures/Chauvet/Chauvet-EVE-P-160-RGBW.qxf create mode 100644 resources/fixtures/Shehds/Shehds-LED-Beam-12x12W-RGBW.qxf create mode 100644 resources/fixtures/Shehds/Shehds-LED-Wall-Wash-18x18W-RGBWA+UV.qxf create mode 100644 resources/fixtures/Stairville/Stairville-Wild-Wash-132-LED-CW.qxf diff --git a/debian/changelog b/debian/changelog index 6e6f6771af..8868492664 100644 --- a/debian/changelog +++ b/debian/changelog @@ -10,14 +10,19 @@ qlcplus (4.13.2) stable; urgency=low * Web Access: fix simple desk not resetting the current universe * RGB scripts: added 'Sine Wave' script * RGB scripts: fix Vertical Fall not allowing changing color when cloned - * New fixtures: GLP Impression X5, Ayrton Rivale Profile (thanks to Masatoshi Fujino) + * New fixtures: GLP Impression X5, Ayrton Rivale Profile, Ayrton Kyalami (thanks to Masatoshi Fujino) * New fixture: Eurolite LED Mini Strobe Cluster SMD 48 (thanks to Oliver) * New fixture: Ayra Compar Kit 3 (thanks to Robert) * New fixtures: Acme Pixel Line IP, Ayrton Domino LT (thanks to Yestalgia) * New fixture: GLP JDC1 (thanks to Flo Edelmann) * New fixture: Shehds 2 Eyes 200W LED COB Cool Warm White (thanks to Devsider) + * New fixture: Ayra ERO Micro Beam FX (thanks to Gianni) + * New fixture: Shehds LED Wall Wash 18x18W RGBWA+UV (thanks to Fede79) + * New fixture: Shehds LED Beam 12x12W RGBW (thanks to Lukas Hanisch) + * New fixture: Chauvet EVE P-160 RGBW (thanks to Max Wheatley) + * New fixture: Stairville Wild Wash 132 LED CW (thanks to e-shock) - -- Massimo Callegari Sun, 24 Nov 2024 18:19:20 +0200 + -- Massimo Callegari Sun, 29 Dec 2024 18:19:20 +0200 qlcplus (4.13.1) stable; urgency=low diff --git a/resources/fixtures/Ayra/Ayra-ERO-Micro-Beam-FX.qxf b/resources/fixtures/Ayra/Ayra-ERO-Micro-Beam-FX.qxf new file mode 100644 index 0000000000..f72d90c809 --- /dev/null +++ b/resources/fixtures/Ayra/Ayra-ERO-Micro-Beam-FX.qxf @@ -0,0 +1,87 @@ + + + + + Q Light Controller Plus + 4.13.2 GIT + gianni + + Ayra + ERO Micro Beam FX + Moving Head + + + + + + + + + + + + + + + + + + + Maintenance + Normal DMX control + Auto run mode 1 (colour fade mode) + Auto run mode 2 (colour jump mode) + Sound controller mode + + + Speed + Speed slow to fast, only when channel 15 is running auto show mode values (095 - 180) + + + Master dimmer + Strobe + Pan + Tilt + Pan/Tilt speed + Red + Green + Blue + White + + + Master dimmer + Strobe + Pan + Pan fine + Tilt + Tilt fine + Pan/Tilt speed + Red Beam + Green Beam + Blue Beam + White + Red Ring + Green Ring + Blue Ring + DMX Mode + Auto Show Speed + + 7 + 8 + 9 + 10 + + + 11 + 12 + 13 + + + + + + + + + + diff --git a/resources/fixtures/Ayrton/Ayrton-Kyalami.qxf b/resources/fixtures/Ayrton/Ayrton-Kyalami.qxf new file mode 100644 index 0000000000..c209b2e889 --- /dev/null +++ b/resources/fixtures/Ayrton/Ayrton-Kyalami.qxf @@ -0,0 +1,327 @@ + + + + + Q Light Controller Plus + 4.13.2 GIT + Masatoshi Fujino + + Ayrton + Kyalami + Moving Head + + + + + + Speed + max to min speed + blackout by movement + blackout by all wheel changing + no function + + + Pan + stop rotation by spinout + stop rotation by shortcut + Forwards Pan rotation from fast to slow + No rotation + Backwards Pan rotation from slow to fast + + + Tilt + stop rotation by spinout + stop rotation by shortcut + Forwards Tilt rotation from fast to slow + No rotation + Backwards Tilt rotation from slow to fast + + + Shutter + Shutter closed + No function (shutter open) + Strobe effect slow to fast + No function (shutter open) + Pulse-effect in sequences + No function (shutter open) + Random strobe effect slow to fast + No function (shutter open) + + + + + + + Colour + Oopen/White + Color1 + Color2 + Color3 + Color4 + Color5 + Color6 + Color7 + Color8 + Color9 + Color10 + Color11 + Color12 + Color13 + Color14 + Color15 + Color16 + Color17 + Color18 + Color19 + Color20 + Color21 + Color22 + Color indexing + Forwards rainbow effect from fast to slow + No rotation + Backwards rainbow effect from slow to fast + + + + + + + + + + Maintenance + No Blanking + Blanking Zone #1 + Blanking Zone #2 + Blanking Zone #3 + Blanking Zone #4 + unused + + + Maintenance + No Blanking + Set pan min + Set pan max + Set tilt min + Set tilt max + + + + Gobo + open + Gobo1 + Gobo2 + Gobo3 + Gobo4 + Gobo5 + Gobo6 + Gobo7 + Gobo8 + Gobo9 + Gobo10 + Gobo11 + Gobo12 + Gobo13 + Gobo14 + Gobo15 + Gobo16 + Gobo17 + Gobo18 + Gobo19 + Gobo20 + Gobo21 + Gobo22 + Gobo23 + Gobo24 + Gobo25 + Gobo26 + Gobo27 + Gobo28 + Gobo29 + Gobo 1 shake slow to fast + Gobo 2 shake slow to fast + Gobo 3 shake slow to fast + Gobo 4 shake slow to fast + Gobo 5 shake slow to fast + Gobo 6 shake slow to fast + Gobo 7 shake slow to fast + Gobo 8 shake slow to fast + Gobo 9 shake slow to fast + Gobo 10 shake slow to fast + Gobo 11 shake slow to fast + Gobo 12 shake slow to fast + Gobo 13 shake slow to fast + Gobo 14 shake slow to fast + Gobo 15 shake slow to fast + Gobo 16 shake slow to fast + Gobo 17 shake slow to fast + Gobo 18 shake slow to fast + Gobo 19 shake slow to fast + Gobo 20 shake slow to fast + Gobo 21 shake slow to fast + Gobo 22 shake slow to fast + Gobo 23 shake slow to fast + Gobo 24 shake slow to fast + Gobo 25 shake slow to fast + Gobo 26 shake slow to fast + Gobo 27 shake slow to fast + Gobo 28 shake slow to fast + Gobo 29 shake slow to fast + Clock-wise scroll from fast to slow + Reserved + Counter clock-wise scroll from slow to fast + + + Prism + Open + Prism1 + + + Prism + Prism indexing + Forwards prism rotation from fast to slow + No rotation + Backwards prism rotation from slow to fast + + + Prism + Fine indexing + + + Prism + Open + Prism 2 + + + Prism + Prism indexing + Forwards prism rotation from fast to slow + No rotation + Backwards prism rotation from slow to fast + + + Prism + Fine indexing + + + Effect + lite + + + Effect + heavy + + + Maintenance + unused + Display Off + Display On + Display Invert Off + Display Invert On + Auto fan control mode + Stage fan control mode + Silence fan control mode + Super Silence fan control mode + Constant Fans Off + Constant Fans On + unused + Square Law + Linear + 1.2K + 2.4K + 16K + 25K + unused + nused + All motor reset + Scan motor reset + Colors motor reset + Gobo motor reset + unused + Reset P/T Fade Off + Reset P/T Fade On + Other motor reset + unused + unused + CMY speed Fast + CMY speed Medium + CMY speed Slow + unused + unused + Sun Protection Off + Sun Protection On + Pan Reverse Off + Pan Reverse On + Tilt Reverse Off + Tilt Reverse On + Pan Degree 540° + Pan Degree 630° + Tilt Degree 540° + Tilt Degree 270° + Feedback Off + Feedback On + Init PAN Off + Init PAN On + Init TILT Off + Init TILT On + Prerig INIT Off + Prerig INIT On + Reset Mode (Fast) + Reset Mode (All Rot Gobos) + Pan/Tilt Spd Fast + Pan/Tilt Spd Medium + Pan/Tilt Spd Slow + unused + Zoom/Focus Spd Fast + Zoom/Focus Spd Medium + Zoom/Focus Spd Slow + Reset Laser Fade Off + Reset Laser Fade On + Defog Off + Defog Auto + Defog On + unused + + + Pan + Pan Fine + Tilt + Tilt Fine + Speed Pan/Tilt movement + Pan Motor continuous rotation + Tilt Motor continuous rotation + Shutter, strobe + Dimmer intensity + Fine Dimmer intensity + Focus + Focus Fine + Color Wheel + Color Wheel Fine + Cyan Color + Cyan Color Fine + Magenta Color + Magenta Color Fine + Yellow Color + Yellow Color Fine + Blanking Zone Number (different zone) + Blanking Zone Settings (4 points) + Reserved + Fixed Gobo + Prism1 + Rotating prism index, rotating prism rotation 1 + Rotating prism indexing Fine 1 + Prism 2 + Rotating prism index, rotating prism rotation 2 + Rotating prism indexing Fine 2 + Frost1 + Frost2 + Control, reset, internal programs + + + + + + + + + diff --git a/resources/fixtures/Chauvet/Chauvet-EVE-P-160-RGBW.qxf b/resources/fixtures/Chauvet/Chauvet-EVE-P-160-RGBW.qxf new file mode 100644 index 0000000000..bbd88002be --- /dev/null +++ b/resources/fixtures/Chauvet/Chauvet-EVE-P-160-RGBW.qxf @@ -0,0 +1,122 @@ + + + + + Q Light Controller Plus + 4.13.2 GIT + Max Wheatley + + Chauvet + EVE P-160 RGBW + Color Changer + + + + + + + Effect + No function + Color macros + + + Intensity + No function + 2800k + 3000k + 3200k + 3500k + 4000k + 4500k + 5000k + 5600k + 6000k + 6500k + No function + + + Shutter + No function + Strobe, Slow to fast + + + Effect + No function + 0-100% + + + 100-0% + + + 100-0-100% + + + Colour fade + + + 7 colour snap program + + + 18 colour snap program + + + Sound activated 1 + + + Soiund Activated 2 + + + + + Speed + Program speed - Slow to fast + + + Speed + Dimmer speed set for display + Dimmer speed mode off + Dimmer speed mode 1 (fast) + Dimmer speed mode 2 (medium) + Dimmer speed mode 3 (slow) + + + + Effect + Sound Sensitivity OFF + Sound Sensitivity, low to high + + + Dimmer + Red + Green + Blue + White + Colour Macros + Colour temperature + Strobe + Automatic programs + No function + Dimmer speed + + + Dimmer + Red + Green + Blue + White + Strobe + + + Red + Green + Blue + White + + + + + + + + + diff --git a/resources/fixtures/FixturesMap.xml b/resources/fixtures/FixturesMap.xml index 45f03eafc3..d34ee77d26 100644 --- a/resources/fixtures/FixturesMap.xml +++ b/resources/fixtures/FixturesMap.xml @@ -217,6 +217,7 @@ + @@ -226,6 +227,7 @@ + @@ -450,6 +452,7 @@ + @@ -1524,8 +1527,10 @@ + + @@ -1706,6 +1711,7 @@ + diff --git a/resources/fixtures/Shehds/Shehds-LED-Beam-12x12W-RGBW.qxf b/resources/fixtures/Shehds/Shehds-LED-Beam-12x12W-RGBW.qxf new file mode 100644 index 0000000000..d3f57597f2 --- /dev/null +++ b/resources/fixtures/Shehds/Shehds-LED-Beam-12x12W-RGBW.qxf @@ -0,0 +1,76 @@ + + + + + Q Light Controller Plus + 4.13.2 GIT + Lukas Hanisch + + Shehds + LED Beam 12x12W RGBW + Moving Head + + + + + + + + + + + + + + Maintenance + Reset + + + Maintenance + No function + + + Speed + No function + + + Colour + RGB mixer + + + Pan + Tilt + Master dimmer + Red + Green + Blue + White + Strobe + Pan/Tilt speed + + + Pan + Tilt + Master dimmer + Red + Green + Blue + White + Strobe + Pan/Tilt speed + RGB mixer + RGB Mixer Speed Control + Default + Default Speed + Pan fine + Tilt fine + Reset + + + + + + + + + diff --git a/resources/fixtures/Shehds/Shehds-LED-Wall-Wash-18x18W-RGBWA+UV.qxf b/resources/fixtures/Shehds/Shehds-LED-Wall-Wash-18x18W-RGBWA+UV.qxf new file mode 100644 index 0000000000..857c9871cb --- /dev/null +++ b/resources/fixtures/Shehds/Shehds-LED-Wall-Wash-18x18W-RGBWA+UV.qxf @@ -0,0 +1,796 @@ + + + + + Q Light Controller Plus + 4.13.2 GIT + Fede79 + + Shehds + LED Wall Wash 18x18W RGBWA+UV + LED Bar (Pixels) + + + + Colour + No function + White color + Run horse mode1(Color control by CH5-10) + Color select (Color control by CH5) + Color Jump mode + Color Gradual change mode + Run horse mode + Sound control + + + Effect + Run horse mode direction + + + Speed + Program Speed adjustment + + + + + + + + + Colour + LED color select + + + Colour + LED color select + + + Colour + LED color select + + + Colour + LED color select + + + Colour + LED color select + + + Colour + LED color select + + + Colour + LED color select + + + Colour + LED color select + + + Colour + LED color select + + + Colour + LED color select + + + Colour + LED color select + + + Colour + LED color select + + + Colour + LED color select + + + Colour + LED color select + + + Colour + LED color select + + + Colour + LED color select + + + Colour + LED color select + + + Colour + LED color select + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Total Dimmer + Total Strobe/Flash + Color Macro + Run horse mode direction + Program Speed adjustment + Total Red Dimmer + Total Green Dimmer + Total Blue Dimmer + Total White Dimmer + Total Amber Dimmer + Total Violet Dimmer + + + Total Dimmer + Total Strobe/Flash + Color Macro + Run horse mode direction + Program Speed adjustment + Total Red Dim + Total Green Dim + Total Blue Dim + Total White Dim + Total Amber Dim + Total UV Dim + LED color select 1 + LED color select 2 + LED color select 3 + LED color select 4 + LED color select 5 + LED color select 6 + LED color select 7 + LED color select 8 + LED color select 9 + LED color select 10 + LED color select 11 + LED color select 12 + LED color select 13 + LED color select 14 + LED color select 15 + LED color select 16 + LED color select 17 + LED color select 18 + + + Red 1 + Green 1 + Blue 1 + White 1 + Amber 1 + UV 1 + Red 2 + Green 2 + Blue 2 + White 2 + Amber 2 + UV 2 + Red 3 + Green 3 + Blue 3 + White 3 + Amber 3 + UV 3 + Red 4 + Green 4 + Blue 4 + White 4 + Amber 4 + UV 4 + Red 5 + Green 5 + Blue 5 + White 5 + Amber 5 + UV 5 + Red 6 + Green 6 + Blue 6 + White 6 + Amber 6 + UV 6 + Red 7 + Green 7 + Blue 7 + White 7 + Amber 7 + UV 7 + Red 8 + Green 8 + Blue 8 + White 8 + Amber 8 + UV 8 + Red 9 + Green 9 + Blue 9 + White 9 + Amber 9 + UV 9 + Red 10 + Green 10 + Blue 10 + White 10 + Amber 10 + UV 10 + Red 11 + Green 11 + Blue 11 + White 11 + Amber 11 + UV 11 + Red 12 + Green 12 + Blue 12 + White 12 + Amber 12 + UV 12 + Red 13 + Green 13 + Blue 13 + White 13 + Amber 13 + UV 13 + Red 14 + Green 14 + Blue 14 + White 14 + Amber 14 + UV 14 + Red 15 + Green 15 + Blue 15 + White 15 + Amber 15 + UV 15 + Red 16 + Green 16 + Blue 16 + White 16 + Amber 16 + UV 16 + Red 17 + Green 17 + Blue 17 + White 17 + Amber 17 + UV 17 + Red 18 + Green 18 + Blue 18 + White 18 + Amber 18 + UV 18 + + 0 + 1 + 2 + 3 + 4 + 5 + + + 6 + 7 + 8 + 9 + 10 + 11 + + + 12 + 13 + 14 + 15 + 16 + 17 + + + 18 + 19 + 20 + 21 + 22 + 23 + + + 24 + 25 + 26 + 27 + 28 + 29 + + + 30 + 31 + 32 + 33 + 34 + 35 + + + 36 + 37 + 38 + 39 + 40 + 41 + + + 42 + 43 + 44 + 45 + 46 + 47 + + + 48 + 49 + 50 + 51 + 52 + 53 + + + 54 + 55 + 56 + 57 + 58 + 59 + + + 60 + 61 + 62 + 63 + 64 + 65 + + + 66 + 67 + 68 + 69 + 70 + 71 + + + 72 + 73 + 74 + 75 + 76 + 77 + + + 78 + 79 + 80 + 81 + 82 + 83 + + + 84 + 85 + 86 + 87 + 88 + 89 + + + 90 + 91 + 92 + 93 + 94 + 95 + + + 96 + 97 + 98 + 99 + 100 + 101 + + + 102 + 103 + 104 + 105 + 106 + 107 + + + + Total Dimmer + Total Strobe/Flash + Color Macro + Run horse mode direction + Program Speed adjustment + Total Red Dim + Total Green Dim + Total Blue Dim + Total White Dim + Total Amber Dim + Total UV Dim + Red 1 + Green 1 + Blue 1 + White 1 + Amber 1 + UV 1 + Red 2 + Green 2 + Blue 2 + White 2 + Amber 2 + UV 2 + Red 3 + Green 3 + Blue 3 + White 3 + Amber 3 + UV 3 + Red 4 + Green 4 + Blue 4 + White 4 + Amber 4 + UV 4 + Red 5 + Green 5 + Blue 5 + White 5 + Amber 5 + UV 5 + Red 6 + Green 6 + Blue 6 + White 6 + Amber 6 + UV 6 + Red 7 + Green 7 + Blue 7 + White 7 + Amber 7 + UV 7 + Red 8 + Green 8 + Blue 8 + White 8 + Amber 8 + UV 8 + Red 9 + Green 9 + Blue 9 + White 9 + Amber 9 + UV 9 + Red 10 + Green 10 + Blue 10 + White 10 + Amber 10 + UV 10 + Red 11 + Green 11 + Blue 11 + White 11 + Amber 11 + UV 11 + Red 12 + Green 12 + Blue 12 + White 12 + Amber 12 + UV 12 + Red 13 + Green 13 + Blue 13 + White 13 + Amber 13 + UV 13 + Red 14 + Green 14 + Blue 14 + White 14 + Amber 14 + UV 14 + Red 15 + Green 15 + Blue 15 + White 15 + Amber 15 + UV 15 + Red 16 + Green 16 + Blue 16 + White 16 + Amber 16 + UV 16 + Red 17 + Green 17 + Blue 17 + White 17 + Amber 17 + UV 17 + Red 18 + Green 18 + Blue 18 + White 18 + Amber 18 + UV 18 + + 11 + 12 + 13 + 14 + 15 + 16 + + + 17 + 18 + 19 + 20 + 21 + 22 + + + 23 + 24 + 25 + 26 + 27 + 28 + + + 29 + 30 + 31 + 32 + 33 + 34 + + + 35 + 36 + 37 + 38 + 39 + 40 + + + 41 + 42 + 43 + 44 + 45 + 46 + + + 47 + 48 + 49 + 50 + 51 + 52 + + + 53 + 54 + 55 + 56 + 57 + 58 + + + 59 + 60 + 61 + 62 + 63 + 64 + + + 65 + 66 + 67 + 68 + 69 + 70 + + + 71 + 72 + 73 + 74 + 75 + 76 + + + 77 + 78 + 79 + 80 + 81 + 82 + + + 83 + 84 + 85 + 86 + 87 + 88 + + + 89 + 90 + 91 + 92 + 93 + 94 + + + 95 + 96 + 97 + 98 + 99 + 100 + + + 101 + 102 + 103 + 104 + 105 + 106 + + + 107 + 108 + 109 + 110 + 111 + 112 + + + 113 + 114 + 115 + 116 + 117 + 118 + + + + + + + + + + + diff --git a/resources/fixtures/Stairville/Stairville-Wild-Wash-132-LED-CW.qxf b/resources/fixtures/Stairville/Stairville-Wild-Wash-132-LED-CW.qxf new file mode 100644 index 0000000000..5f1c61d809 --- /dev/null +++ b/resources/fixtures/Stairville/Stairville-Wild-Wash-132-LED-CW.qxf @@ -0,0 +1,71 @@ + + + + + Q Light Controller Plus + 4.13.2 GIT + e-shock + + Stairville + Wild Wash 132 LED CW + Strobe + + Shutter + LEDs off (blackout) + Strobe effect, speed increasing from approx. 0 Hz to 30 Hz + + + + Shutter + LEDs on + LEDs off (blackout) + Strobe effect, speed increasing from approx. 0 Hz to 30 Hz + LEDs on + + + Speed + Flash impulse duration, increasing from 0 ms to 510 ms + + + Shutter + LEDs on, brightness controlled by channel 1 + LEDs off (blackout) + Random impulses, increasing speed + Randomly increasing brightness, increasing speed + Randomly decreasing brightness, increasing speed + Random Strobe effect, increasing speed + Interrupt effect, 5 s to 1 s + Strobe effect, speed increasing from approx. 0 Hz to 30 Hz + LEDs on, brightness controlled by channel 1 + + + Maintenance + Sound control off + Sound control on, increasing sensitivity + + + Strobe 1 + + + Dimmer + Strobe + + + Dimmer + Strobe + Flash impulse + + + Dimmer + Strobe 2 + Sound control + + + + + + + + + + From 8d0ae8f15a10168793105e4c660cd62f31199086 Mon Sep 17 00:00:00 2001 From: Massimo Callegari Date: Tue, 3 Dec 2024 19:20:57 +0100 Subject: [PATCH 44/68] vc/speeddial: fix UI colors on Windows (fix #1640) --- ui/src/speeddial.cpp | 1 - ui/src/virtualconsole/vcspeeddial.cpp | 53 +++++++++++++++++++++++++-- ui/src/virtualconsole/vcspeeddial.h | 18 +++++++++ 3 files changed, 68 insertions(+), 4 deletions(-) diff --git a/ui/src/speeddial.cpp b/ui/src/speeddial.cpp index 97e1c0624e..f65ab671f7 100644 --- a/ui/src/speeddial.cpp +++ b/ui/src/speeddial.cpp @@ -55,7 +55,6 @@ const QString tapTickSS = "QPushButton { background-color: #DDDDDD; border: 3px "QPushButton:pressed { background-color: #AAAAAA; }" "QPushButton:disabled { border: 2px solid #BBBBBB; }"; - /**************************************************************************** * FocusSpinBox ****************************************************************************/ diff --git a/ui/src/virtualconsole/vcspeeddial.cpp b/ui/src/virtualconsole/vcspeeddial.cpp index 524eead2f8..c775239aac 100644 --- a/ui/src/virtualconsole/vcspeeddial.cpp +++ b/ui/src/virtualconsole/vcspeeddial.cpp @@ -46,9 +46,15 @@ const quint8 VCSpeedDial::multDivResetInputSourceId = 4; const quint8 VCSpeedDial::applyInputSourceId = 5; const QSize VCSpeedDial::defaultSize(QSize(200, 175)); -static const QString presetBtnSS = "QPushButton { background-color: %1; height: 32px; border: 2px solid #6A6A6A; border-radius: 5px; }" - "QPushButton:pressed { border: 2px solid #0000FF; }" - "QPushButton:disabled { border: 2px solid #BBBBBB; color: #8f8f8f }"; +static const QString presetBtnSS = + "QPushButton { background-color: %1; height: 32px; border: 2px solid #6A6A6A; border-radius: 5px; }" + "QPushButton:pressed { border: 2px solid #0000FF; }" + "QPushButton:disabled { border: 2px solid #BBBBBB; color: #8f8f8f }"; + +static const QString dialSS = + "QGroupBox { background-color: %1; border: 2px solid gray; border-radius: 5px; margin-top: 1ex; font-size: %2pt; }" + "QGroupBox::title { subcontrol-origin: margin; subcontrol-position: top left; padding: 5px 5px;" + " background-color: transparent; color: %3; }"; /**************************************************************************** * Initialization @@ -160,6 +166,11 @@ VCSpeedDial::VCSpeedDial(QWidget* parent, Doc* doc) this, SLOT(slotUpdate())); m_updateTimer->setSingleShot(true); + m_foregroundColor = palette().color(QPalette::WindowText); + m_dial->setStyleSheet(dialSS.arg(palette().color(QPalette::Window).name()) + .arg(font().pointSize()) + .arg(m_foregroundColor.name())); + slotModeChanged(m_doc->mode()); setLiveEdit(m_liveEdit); } @@ -238,6 +249,42 @@ bool VCSpeedDial::copyFrom(const VCWidget* widget) return VCWidget::copyFrom(widget); } +void VCSpeedDial::setFont(const QFont &font) +{ + VCWidget::setFont(font); + m_dial->setStyleSheet(dialSS.arg(palette().color(QPalette::Window).name()) + .arg(font.pointSize()) + .arg(m_foregroundColor.name())); +} + +/********************************************************************* + * Background/Foreground color + *********************************************************************/ + +void VCSpeedDial::setBackgroundColor(const QColor &color) +{ + VCWidget::setBackgroundColor(color); + m_dial->setStyleSheet(dialSS.arg(palette().color(QPalette::Window).name()) + .arg(font().pointSize()) + .arg(m_foregroundColor.name())); +} + +void VCSpeedDial::setForegroundColor(const QColor &color) +{ + m_foregroundColor = color; + m_hasCustomForegroundColor = true; + + m_dial->setStyleSheet(dialSS.arg(palette().color(QPalette::Window).name()) + .arg(font().pointSize()) + .arg(color.name())); + m_doc->setModified(); +} + +QColor VCSpeedDial::foregroundColor() const +{ + return m_foregroundColor; +} + /***************************************************************************** * Properties *****************************************************************************/ diff --git a/ui/src/virtualconsole/vcspeeddial.h b/ui/src/virtualconsole/vcspeeddial.h index 604758caa8..a49c31588f 100644 --- a/ui/src/virtualconsole/vcspeeddial.h +++ b/ui/src/virtualconsole/vcspeeddial.h @@ -105,6 +105,24 @@ class VCSpeedDial : public VCWidget /** @reimp */ bool copyFrom(const VCWidget* widget); + /********************************************************************* + * Background/Foreground color + *********************************************************************/ +public: + /** @reimp */ + void setFont(const QFont& font); + + /** @reimp */ + void setBackgroundColor(const QColor& color); + + /** @reimp */ + void setForegroundColor(const QColor& color); + + /** @reimp */ + QColor foregroundColor() const; + +private: + QColor m_foregroundColor; /************************************************************************* * Caption *************************************************************************/ From e4513ef935d52b25f3a9b2fb99060fbf496ce87f Mon Sep 17 00:00:00 2001 From: Massimo Callegari Date: Sat, 7 Dec 2024 16:52:43 +0100 Subject: [PATCH 45/68] qmlui: implement "paste to all" in Scene Editor --- qmlui/functionmanager.cpp | 2 + qmlui/qml/FixtureConsole.qml | 13 ++- qmlui/qml/SimpleDesk.qml | 4 +- qmlui/qml/UISettings.qml | 48 ++++++----- qmlui/qml/fixturesfunctions/BottomPanel.qml | 83 +++++++++++++------ qmlui/qml/fixturesfunctions/SceneEditor.qml | 2 +- .../fixturesfunctions/SceneFixtureConsole.qml | 6 +- qmlui/sceneeditor.cpp | 50 +++++++++++ qmlui/sceneeditor.h | 28 ++++++- 9 files changed, 182 insertions(+), 54 deletions(-) diff --git a/qmlui/functionmanager.cpp b/qmlui/functionmanager.cpp index d7a6d314c7..5e42bcec0b 100644 --- a/qmlui/functionmanager.cpp +++ b/qmlui/functionmanager.cpp @@ -105,6 +105,8 @@ void FunctionManager::setStartupFunctionID(quint32 fid) else m_doc->setStartupFunction(fid); + m_doc->setModified(); + emit startupFunctionIDChanged(); } diff --git a/qmlui/qml/FixtureConsole.qml b/qmlui/qml/FixtureConsole.qml index 0ab730f138..93c1314784 100644 --- a/qmlui/qml/FixtureConsole.qml +++ b/qmlui/qml/FixtureConsole.qml @@ -48,6 +48,7 @@ Rectangle property bool showEnablers: false property bool sceneConsole: false property bool externalChange: false + property bool multipleSelection: false signal doubleClicked signal clicked @@ -144,7 +145,7 @@ Rectangle Rectangle { id: chDelegate - color: "transparent" + color: isSelected ? UISettings.selection : "transparent" border.width: 1 border.color: UISettings.borderColorDark width: UISettings.iconSizeDefault @@ -152,6 +153,7 @@ Rectangle property real dmxValue property bool isEnabled: showEnablers ? false : true + property bool isSelected: false function updateChannel() { @@ -210,7 +212,7 @@ Rectangle height: UISettings.iconSizeMedium / 2 radius: 2 visible: showEnablers - color: isEnabled ? UISettings.highlight : UISettings.bgLight + color: isEnabled ? (chDelegate.isSelected ? UISettings.selection : UISettings.highlight) : UISettings.bgLight border.width: 1 border.color: isEnabled ? "white" : UISettings.bgLighter //Layout.alignment: Qt.AlignCenter @@ -220,6 +222,13 @@ Rectangle anchors.fill: parent onClicked: { + if (isEnabled && ((mouse.modifiers & Qt.ControlModifier) || multipleSelection)) + { + chDelegate.isSelected = !chDelegate.isSelected + sceneEditor.setChannelSelection(fixtureObj.id, index, chDelegate.isSelected); + return + } + isEnabled = !isEnabled if (sceneConsole == true) { diff --git a/qmlui/qml/SimpleDesk.qml b/qmlui/qml/SimpleDesk.qml index 348161741e..4ef25a6be7 100644 --- a/qmlui/qml/SimpleDesk.qml +++ b/qmlui/qml/SimpleDesk.qml @@ -161,8 +161,8 @@ Rectangle switch(chDisplay) { case SimpleDesk.None: return "transparent" - case SimpleDesk.Odd: return "#414b41" - case SimpleDesk.Even: return "#42444b" + case SimpleDesk.Odd: return UISettings.bgFixtureOdd + case SimpleDesk.Even: return UISettings.bgFixtureEven } } } diff --git a/qmlui/qml/UISettings.qml b/qmlui/qml/UISettings.qml index 8318576475..b091b15914 100644 --- a/qmlui/qml/UISettings.qml +++ b/qmlui/qml/UISettings.qml @@ -28,31 +28,33 @@ QtObject property real scalingFactor: 1.0 /* Colors */ - property color bgStronger: "#161616" - property color bgStrong: "#232323" - property color bgMedium: "#333" - property color bgControl: "#555" - property color bgLight: "#6F6F6F" - property color bgLighter: "#8F8F8F" + property color bgStronger: "#161616" + property color bgStrong: "#232323" + property color bgMedium: "#333" + property color bgControl: "#555" + property color bgLight: "#6F6F6F" + property color bgLighter: "#8F8F8F" + property color bgFixtureOdd: "#414b41" + property color bgFixtureEven: "#42444b" - property color fgMain: "white" - property color fgMedium: "#888" - property color fgLight: "#aaa" + property color fgMain: "white" + property color fgMedium: "#888" + property color fgLight: "#aaa" - property color sectionHeader: "#31456B" - property color sectionHeaderDiv: "#22304a" - property color highlight: "#0978FF" - property color highlightPressed: "#044089" - property color hover: "#B6B6B6" - property color selection: "yellow" - property color activeDropArea: "#9DFF52" - property color borderColorDark: "#111" + property color sectionHeader: "#31456B" + property color sectionHeaderDiv: "#22304a" + property color highlight: "#0978FF" + property color highlightPressed: "#044089" + property color hover: "#B6B6B6" + property color selection: "yellow" + property color activeDropArea: "#9DFF52" + property color borderColorDark: "#111" - property color toolbarStartMain: "#222" - property color toolbarStartSub: "#333" - property color toolbarEnd: "#111" - property color toolbarHoverStart:"#444" - property color toolbarHoverEnd: "#171717" + property color toolbarStartMain: "#222" + property color toolbarStartSub: "#333" + property color toolbarEnd: "#111" + property color toolbarHoverStart: "#444" + property color toolbarHoverEnd: "#171717" property color toolbarSelectionMain: "#12B4FF" property color toolbarSelectionSub: "yellow" @@ -67,7 +69,7 @@ QtObject property real scrollBarWidth: screenPixelDensity * scalingFactor * 6 property real sidePanelWidth: screenPixelDensity * scalingFactor * 50 - // channel properties column widths + /* Channel properties column widths */ property real chPropsModesWidth: bigItemHeight * 1.2 property real chPropsFlagsWidth: bigItemHeight property real chPropsCanFadeWidth: bigItemHeight * 0.7 diff --git a/qmlui/qml/fixturesfunctions/BottomPanel.qml b/qmlui/qml/fixturesfunctions/BottomPanel.qml index 738eada858..30108f3f04 100644 --- a/qmlui/qml/fixturesfunctions/BottomPanel.qml +++ b/qmlui/qml/fixturesfunctions/BottomPanel.qml @@ -17,7 +17,9 @@ limitations under the License. */ -import QtQuick 2.0 +import QtQuick 2.14 +import QtQuick.Layouts 1.14 + import "." Rectangle @@ -93,29 +95,6 @@ Rectangle GradientStop { position: 1; color: "#141414" } } - IconButton - { - id: expandButton - x: parent.width - width - 4 - z: 2 - anchors.verticalCenter: parent.verticalCenter - width: height * 1.2 - height: parent.height * 0.7 - checkable: true - tooltip: qsTr("Expand/Collapse this panel") - onToggled: animatePanel(checked) - - Image - { - anchors.centerIn: parent - source: "qrc:/arrow-down.svg" - width: parent.width * 0.8 - height: parent.height * 0.5 - rotation: expandButton.checked ? 0 : 180 - sourceSize: Qt.size(width, height) - } - } - MouseArea { id: rpClickArea @@ -140,6 +119,62 @@ Rectangle } //onClicked: animatePanel() } + + RowLayout + { + anchors.fill: parent + z: 2 + + // filler + Rectangle + { + height: parent.height + Layout.fillWidth: true + color: "transparent" + } + + IconButton + { + visible: isOpen && editorLoader.item && editorLoader.item.hasOwnProperty("isSceneEditor") + width: UISettings.iconSizeDefault + height: UISettings.iconSizeDefault + imgSource: "qrc:/edit-copy.svg" + tooltip: qsTr("Copy the selected channel values to all the fixtures of the same type") + enabled: sceneEditor.selectedChannelCount > 0 ? true : false + onClicked: sceneEditor.pasteToAllFixtureSameType() + } + + IconButton + { + visible: isOpen && editorLoader.item && editorLoader.item.hasOwnProperty("isSceneEditor") + width: UISettings.iconSizeDefault + height: UISettings.iconSizeDefault + imgSource: "qrc:/multiple.svg" + tooltip: qsTr("Toggle multiple channel selection") + checkable: true + onToggled: editorLoader.item.multipleSelection = checked + } + + IconButton + { + id: expandButton + width: height * 1.2 + height: parent.height * 0.7 + checkable: true + tooltip: qsTr("Expand/Collapse this panel") + onToggled: animatePanel(checked) + + Image + { + anchors.centerIn: parent + source: "qrc:/arrow-down.svg" + width: parent.width * 0.8 + height: parent.height * 0.5 + rotation: expandButton.checked ? 0 : 180 + sourceSize: Qt.size(width, height) + } + } + } } Rectangle diff --git a/qmlui/qml/fixturesfunctions/SceneEditor.qml b/qmlui/qml/fixturesfunctions/SceneEditor.qml index b103033cd7..255463696b 100644 --- a/qmlui/qml/fixturesfunctions/SceneEditor.qml +++ b/qmlui/qml/fixturesfunctions/SceneEditor.qml @@ -129,7 +129,7 @@ Rectangle id: toolbar visible: !boundToSequence text: sceneEditor ? sceneEditor.functionName : "" - onTextChanged: sceneEditor.functionName = text + onTextChanged: if (sceneEditor) sceneEditor.functionName = text onBackClicked: { diff --git a/qmlui/qml/fixturesfunctions/SceneFixtureConsole.qml b/qmlui/qml/fixturesfunctions/SceneFixtureConsole.qml index fea80e72e5..54f53d3d1b 100644 --- a/qmlui/qml/fixturesfunctions/SceneFixtureConsole.qml +++ b/qmlui/qml/fixturesfunctions/SceneFixtureConsole.qml @@ -33,6 +33,9 @@ Rectangle Component.onCompleted: sceneEditor.sceneConsoleLoaded(true) Component.onDestruction: sceneEditor.sceneConsoleLoaded(false) + property bool isSceneEditor: true + property bool multipleSelection: false + function scrollToItem(fxIdx) { console.log("[scrollToItem] fxIdx: " + fxIdx) @@ -76,9 +79,10 @@ Rectangle fixtureObj: model.cRef isSelected: model.isSelected height: parent.height - color: index % 2 ? "#202020" : "#404040" + color: index % 2 ? UISettings.bgFixtureEven : UISettings.bgFixtureOdd showEnablers: true sceneConsole: true + multipleSelection: sfcContainer.multipleSelection onRequestTool: channelToolLoader.loadChannelTool(item, fixtureID, chIndex, value) } diff --git a/qmlui/sceneeditor.cpp b/qmlui/sceneeditor.cpp index 320e71382f..2fb4138929 100644 --- a/qmlui/sceneeditor.cpp +++ b/qmlui/sceneeditor.cpp @@ -70,6 +70,7 @@ void SceneEditor::setFunctionID(quint32 id) m_source->setOutputEnabled(false); m_fixtureList->clear(); m_fixtureIDs.clear(); + m_selectedChannels.clear(); if (bottomPanel != nullptr) bottomPanel->setProperty("visible", false); return; @@ -263,6 +264,28 @@ void SceneEditor::setFixtureSelection(quint32 fxID) Q_ARG(QVariant, fxIndex)); } +void SceneEditor::setChannelSelection(quint32 fxID, quint32 channel, bool selected) +{ + SceneValue scv(fxID, channel); + + if (selected) + { + if (m_selectedChannels.contains(scv) == false) + m_selectedChannels.append(scv); + } + else + { + m_selectedChannels.removeAll(scv); + } + + emit selectedChannelCountChanged(); +} + +int SceneEditor::selectedChannelCount() +{ + return m_selectedChannels.count(); +} + void SceneEditor::addComponent(int type, quint32 id) { if (m_scene == nullptr) @@ -294,6 +317,33 @@ void SceneEditor::addComponent(int type, quint32 id) updateLists(); } +void SceneEditor::pasteToAllFixtureSameType() +{ + for (SceneValue scv : m_selectedChannels) + { + Fixture *sourceFixture = m_doc->fixture(scv.fxi); + if (sourceFixture == nullptr) + continue; + + uchar currentValue = m_scene->value(scv.fxi, scv.channel); + + for (quint32 dstFxId : m_scene->fixtures()) + { + Fixture *destFixture = m_doc->fixture(scv.fxi); + if (dstFxId == scv.fxi || destFixture == nullptr) + continue; + + if (sourceFixture->fixtureDef() == destFixture->fixtureDef() && + sourceFixture->fixtureMode() == destFixture->fixtureMode()) + { + SceneValue dstScv(dstFxId, scv.channel, currentValue); + m_scene->setValue(dstScv); + slotSceneValueChanged(dstScv); + } + } + } +} + void SceneEditor::deleteItems(QVariantList list) { if (m_scene == nullptr || list.isEmpty()) diff --git a/qmlui/sceneeditor.h b/qmlui/sceneeditor.h index 8c18a43978..2ac90fc664 100644 --- a/qmlui/sceneeditor.h +++ b/qmlui/sceneeditor.h @@ -34,6 +34,7 @@ class SceneEditor : public FunctionEditor Q_PROPERTY(QVariant fixtureList READ fixtureList NOTIFY fixtureListChanged) Q_PROPERTY(QVariant componentList READ componentList NOTIFY componentListChanged) + Q_PROPERTY(int selectedChannelCount READ selectedChannelCount NOTIFY selectedChannelCountChanged) public: SceneEditor(QQuickView *view, Doc *doc, QObject *parent = nullptr); @@ -65,18 +66,33 @@ class SceneEditor : public FunctionEditor * requested $fixture's $channel */ Q_INVOKABLE bool hasChannel(quint32 fxID, quint32 channel); - /** QML invokable method that returns the values of the + /** QML invokable method that returns the value of the * requested $fixture's $channel */ Q_INVOKABLE double channelValue(quint32 fxID, quint32 channel); + /** Remove a channel with the provided $fxID and $channel + * from the Scene currently being edited */ Q_INVOKABLE void unsetChannel(quint32 fxID, quint32 channel); + /** Set a Fixture selection by ID to scroll the UI to the + * related FixtureConsole item */ Q_INVOKABLE void setFixtureSelection(quint32 fxID); + /** Add/remove a channel from the clipboard selection, to allow + * the paste-to-all functionality */ + Q_INVOKABLE void setChannelSelection(quint32 fxID, quint32 channel, bool selected); + + /** Return the number of channels currently selected for paste-to-all */ + int selectedChannelCount(); + /** Add a component with of given type * e.g. FixtureGroup, Fixture, Palette */ Q_INVOKABLE void addComponent(int type, quint32 id); + /** Paste all the values selected with setChannelSelection + * to all the fixture of the same type and mode */ + Q_INVOKABLE void pasteToAllFixtureSameType(); + /** @reimp */ void deleteItems(QVariantList list); @@ -93,25 +109,35 @@ protected slots: signals: void fixtureListChanged(); void componentListChanged(); + void selectedChannelCountChanged(); private: /** Reference of the Scene currently being edited */ Scene *m_scene; + /** A list of the $m_scene Fixture IDs for fast lookup */ QList m_fixtureIDs; + /** A QML-readable list of references to Fixtures used in $m_scene */ ListModel *m_fixtureList; + /** A QML-readable list of all the components used by the Scene * (Fixture groups, Fixtures, Palettes) */ ListModel *m_componentList; + /** A reference to the SceneFixtureConsole when loaded */ QQuickItem *m_sceneConsole; + /** Keep a track of the registered Fixture consoles in a Scene Console, * to rapidly set a channel value */ QMap m_fxConsoleMap; + /** Pre-cache initial channel values including palettes. * arranged as */ QMap m_channelsCache; + + QList m_selectedChannels; + /** Reference to a DMX source used to edit a Scene */ GenericDMXSource *m_source; }; From 136eef7619f49c127f4761185b4f07498ce3e170 Mon Sep 17 00:00:00 2001 From: Massimo Callegari Date: Sat, 7 Dec 2024 18:44:57 +0100 Subject: [PATCH 46/68] windows: no need to debug Qt libraries --- platforms/windows/CMakeLists.txt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/platforms/windows/CMakeLists.txt b/platforms/windows/CMakeLists.txt index 4e0e7b31c6..af425bbf17 100644 --- a/platforms/windows/CMakeLists.txt +++ b/platforms/windows/CMakeLists.txt @@ -9,11 +9,11 @@ else() endif() # Set debug mode -if(CMAKE_BUILD_TYPE STREQUAL "Debug") - set(QT_D "d") -else() - set(QT_D "") -endif() +#if(CMAKE_BUILD_TYPE STREQUAL "Debug") +# set(QT_D "d") +#else() +# set(QT_D "") +#endif() # Set paths # message("${QT_LIBRARY_DIR}") From 5ac4e9c4b8285f3005d966e9f9f2c5b909f63885 Mon Sep 17 00:00:00 2001 From: Massimo Callegari Date: Sat, 7 Dec 2024 18:47:29 +0100 Subject: [PATCH 47/68] vc/speeddial: fix foreground color and margins --- ui/src/virtualconsole/vcspeeddial.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ui/src/virtualconsole/vcspeeddial.cpp b/ui/src/virtualconsole/vcspeeddial.cpp index c775239aac..b9282395fe 100644 --- a/ui/src/virtualconsole/vcspeeddial.cpp +++ b/ui/src/virtualconsole/vcspeeddial.cpp @@ -52,8 +52,8 @@ static const QString presetBtnSS = "QPushButton:disabled { border: 2px solid #BBBBBB; color: #8f8f8f }"; static const QString dialSS = - "QGroupBox { background-color: %1; border: 2px solid gray; border-radius: 5px; margin-top: 1ex; font-size: %2pt; }" - "QGroupBox::title { subcontrol-origin: margin; subcontrol-position: top left; padding: 5px 5px;" + "QGroupBox { background-color: %1; border: 1px solid gray; border-radius: 5px; margin-top: 0; font-size: %2pt; }" + "QGroupBox::title { subcontrol-origin: margin; subcontrol-position: top left; padding: 0px 5px;" " background-color: transparent; color: %3; }"; /**************************************************************************** @@ -277,7 +277,7 @@ void VCSpeedDial::setForegroundColor(const QColor &color) m_dial->setStyleSheet(dialSS.arg(palette().color(QPalette::Window).name()) .arg(font().pointSize()) .arg(color.name())); - m_doc->setModified(); + VCWidget::setForegroundColor(color); } QColor VCSpeedDial::foregroundColor() const From 6d26c71fb26f602bfc42a5de298d8a557ec6db50 Mon Sep 17 00:00:00 2001 From: Massimo Callegari Date: Sun, 8 Dec 2024 08:17:44 +0100 Subject: [PATCH 48/68] windows: fixes to build and deploy with Qt6 --- engine/src/mastertimer-win32.cpp | 8 +- hotplugmonitor/src/hpmprivate-win32.cpp | 9 +- platforms/windows/CMakeLists.txt | 142 ++++++++++++++++++------ 3 files changed, 118 insertions(+), 41 deletions(-) diff --git a/engine/src/mastertimer-win32.cpp b/engine/src/mastertimer-win32.cpp index a04691c19e..4840d82bf6 100644 --- a/engine/src/mastertimer-win32.cpp +++ b/engine/src/mastertimer-win32.cpp @@ -19,9 +19,11 @@ */ // Let's assume we have at least W2K (http://msdn.microsoft.com/en-us/library/Aa383745) -#define _WIN32_WINNT 0x05000000 -#define _WIN32_WINDOWS 0x05000000 -#define WINVER 0x05000000 +#ifndef _WIN32_WINNT + #define _WIN32_WINNT 0x05000000 + #define _WIN32_WINDOWS 0x05000000 + #define WINVER 0x05000000 +#endif #include diff --git a/hotplugmonitor/src/hpmprivate-win32.cpp b/hotplugmonitor/src/hpmprivate-win32.cpp index 3e43022685..fa4314f921 100644 --- a/hotplugmonitor/src/hpmprivate-win32.cpp +++ b/hotplugmonitor/src/hpmprivate-win32.cpp @@ -18,9 +18,12 @@ */ // Let's assume we have at least W2K (http://msdn.microsoft.com/en-us/library/Aa383745) -#define _WIN32_WINNT 0x05000000 -#define _WIN32_WINDOWS 0x05000000 -#define WINVER 0x05000000 +#ifndef _WIN32_WINNT + #define _WIN32_WINNT 0x05000000 + #define _WIN32_WINDOWS 0x05000000 + #define WINVER 0x05000000 +#endif + #include #include diff --git a/platforms/windows/CMakeLists.txt b/platforms/windows/CMakeLists.txt index af425bbf17..aa0fc13d57 100644 --- a/platforms/windows/CMakeLists.txt +++ b/platforms/windows/CMakeLists.txt @@ -52,7 +52,7 @@ if(qmlui) "${SYS_LIBS_PATH}/libminizip-1.dll") endif() -if(Qt5_MAJOR_VERSION GREATER 5) +if(QT_MAJOR_VERSION GREATER 5) list(APPEND qtdeps_files "${SYS_LIBS_PATH}/libb2-1.dll") endif() install(FILES ${qtdeps_files} OPTIONAL DESTINATION ${qtdeps_path}) @@ -60,7 +60,6 @@ install(FILES ${qtdeps_files} OPTIONAL DESTINATION ${qtdeps_path}) set(qtlibs_path "${INSTALLROOT}/${LIBSDIR}") set(qtlibs_files "${QT_LIBS_PATH}/${QT_V}Core${QT_D}.dll" - "${QT_LIBS_PATH}/${QT_V}Script${QT_D}.dll" "${QT_LIBS_PATH}/${QT_V}Network${QT_D}.dll" "${QT_LIBS_PATH}/${QT_V}Gui${QT_D}.dll" "${QT_LIBS_PATH}/${QT_V}Svg${QT_D}.dll" @@ -71,6 +70,11 @@ set(qtlibs_files "${QT_LIBS_PATH}/${QT_V}SerialPort${QT_D}.dll" "${QT_LIBS_PATH}/${QT_V}WebSockets${QT_D}.dll" ) +if(QT_MAJOR_VERSION GREATER 5) + list(APPEND qtlibs_files "${QT_LIBS_PATH}/${QT_V}Qml${QT_D}.dll") +else() + list(APPEND qtlibs_files "${QT_LIBS_PATH}/${QT_V}Script${QT_D}.dll") +endif() if(qmlui) list(APPEND qtlibs_files "${QT_LIBS_PATH}/${QT_V}Qml${QT_D}.dll" @@ -106,13 +110,16 @@ install(FILES ${qtplatform_files} DESTINATION ${qtplatform_path}) # Qt styles plugin set(qtstyles_path "${INSTALLROOT}/${LIBSDIR}/styles") -set(qtstyles_files "${QT_PLUGINS_PATH}/styles/qwindowsvistastyle${QT_D}.dll") +if(QT_MAJOR_VERSION GREATER 5) + set(qtstyles_files "${QT_PLUGINS_PATH}/styles/qmodernwindowsstyle${QT_D}.dll") +else() + set(qtstyles_files "${QT_PLUGINS_PATH}/styles/qwindowsvistastyle${QT_D}.dll") +endif() install(FILES ${qtstyles_files} DESTINATION ${qtstyles_path}) -if(Qt5_MAJOR_VERSION GREATER 5) +if(QT_MAJOR_VERSION GREATER 5) set(qtmedia_path "${INSTALLROOT}/${LIBSDIR}/multimedia") - set(qtmedia_files "${QT_PLUGINS_PATH}/multimedia/ffmpegmediaplugin${QT_D}.dll" - "${QT_PLUGINS_PATH}/multimedia/windowsmediaplugin${QT_D}.dll") + set(qtmedia_files "${QT_PLUGINS_PATH}/multimedia/ffmpegmediaplugin${QT_D}.dll") install(FILES ${qtmedia_files} DESTINATION ${qtmedia_path}) else() set(qtaudio_path "${INSTALLROOT}/${LIBSDIR}/audio") @@ -182,38 +189,103 @@ set(msys_files "${SYS_LIBS_PATH}/libstdc++-6.dll" "${SYS_LIBS_PATH}/libusb-1.0.dll") install(FILES ${msys_files} DESTINATION ${msys_path}) +function(copy_system_library target libname) + if(EXISTS ${SYS_LIBS_PATH}/${libname}) + list(APPEND audio_files ${SYS_LIBS_PATH}/${libname}) + set(${target} "${${target}}" PARENT_SCOPE) + endif() +endfunction() + # audio libraries set(audio_path "${INSTALLROOT}/${LIBSDIR}") -if(EXISTS "${SYS_LIBS_PATH}/libmad-0.dll") - list(APPEND audio_files "${SYS_LIBS_PATH}/libmad-0.dll") -endif() -if(EXISTS "${SYS_LIBS_PATH}/libogg-0.dll") - list(APPEND audio_files "${SYS_LIBS_PATH}/libogg-0.dll") -endif() -if(EXISTS "${SYS_LIBS_PATH}/libopus-0.dll") - list(APPEND audio_files "${SYS_LIBS_PATH}/libopus-0.dll") -endif() -if(EXISTS "${SYS_LIBS_PATH}/libmp3lame-0.dll") - list(APPEND audio_files "${SYS_LIBS_PATH}/libmp3lame-0.dll") -endif() -if(EXISTS "${SYS_LIBS_PATH}/libmpg123-0.dll") - list(APPEND audio_files "${SYS_LIBS_PATH}/libmpg123-0.dll") -endif() -if(EXISTS "${SYS_LIBS_PATH}/libvorbis-0.dll") - list(APPEND audio_files "${SYS_LIBS_PATH}/libvorbis-0.dll") -endif() -if(EXISTS "${SYS_LIBS_PATH}/libvorbisenc-2.dll") - list(APPEND audio_files "${SYS_LIBS_PATH}/libvorbisenc-2.dll") -endif() -if(EXISTS "${SYS_LIBS_PATH}/libFLAC.dll") - list(APPEND audio_files "${SYS_LIBS_PATH}/libFLAC.dll") -endif() -if(EXISTS "${SYS_LIBS_PATH}/libsndfile-1.dll") - list(APPEND audio_files "${SYS_LIBS_PATH}/libsndfile-1.dll") -endif() -if(EXISTS "${SYS_LIBS_PATH}/libfftw3-3.dll") - list(APPEND audio_files "${SYS_LIBS_PATH}/libfftw3-3.dll") +copy_system_library(audio_files "libmad-0.dll") +copy_system_library(audio_files "libogg-0.dll") +copy_system_library(audio_files "libopus-0.dll") +copy_system_library(audio_files "libmp3lame-0.dll") +copy_system_library(audio_files "libmpg123-0.dll") +copy_system_library(audio_files "libvorbis-0.dll") +copy_system_library(audio_files "libvorbisenc-2.dll") +copy_system_library(audio_files "libFLAC.dll") +copy_system_library(audio_files "libsndfile-1.dll") +copy_system_library(audio_files "libfftw3-3.dll") + +if(QT_MAJOR_VERSION GREATER 5) + copy_system_library(audio_files "avformat-61.dll") + copy_system_library(audio_files "avutil-59.dll") + copy_system_library(audio_files "avcodec-61.dll") + copy_system_library(audio_files "libbluray-2.dll") + copy_system_library(audio_files "libgme.dll") + copy_system_library(audio_files "libgnutls-30.dll") + copy_system_library(audio_files "libmodplug-1.dll") + copy_system_library(audio_files "librtmp-1.dll") + copy_system_library(audio_files "libsrt.dll") + copy_system_library(audio_files "libssh.dll") + copy_system_library(audio_files "libdav1d-7.dll") + copy_system_library(audio_files "libaom.dll") + copy_system_library(audio_files "libcairo-2.dll") + copy_system_library(audio_files "libgobject-2.0-0.dll") + copy_system_library(audio_files "libgsm.dll") + copy_system_library(audio_files "libjxl_threads.dll") + copy_system_library(audio_files "libjxl.dll") + copy_system_library(audio_files "liblzma-5.dll") + copy_system_library(audio_files "liblc3-1.dll") + copy_system_library(audio_files "libxml2-2.dll") + copy_system_library(audio_files "libva.dll") + copy_system_library(audio_files "libvpl-2.dll") + copy_system_library(audio_files "libva_win32.dll") + copy_system_library(audio_files "swscale-8.dll") + copy_system_library(audio_files "swresample-5.dll") + copy_system_library(audio_files "libopencore-amrnb-0.dll") + copy_system_library(audio_files "libopencore-amrwb-0.dll") + copy_system_library(audio_files "libopenjp2-7.dll") + copy_system_library(audio_files "rav1e.dll") + copy_system_library(audio_files "librsvg-2-2.dll") + copy_system_library(audio_files "libtheoradec-1.dll") + copy_system_library(audio_files "libSvtAv1Enc-2.dll") + copy_system_library(audio_files "libtheoraenc-1.dll") + copy_system_library(audio_files "libvpx-1.dll") + copy_system_library(audio_files "libwebp-7.dll") + copy_system_library(audio_files "libwebpmux-3.dll") + copy_system_library(audio_files "libx265-209.dll") + copy_system_library(audio_files "libx264-164.dll") + copy_system_library(audio_files "xvidcore.dll") + copy_system_library(audio_files "libzvbi-0.dll") + copy_system_library(audio_files "libbrotlienc.dll") + copy_system_library(audio_files "libgmp-10.dll") + copy_system_library(audio_files "libhogweed-6.dll") + copy_system_library(audio_files "libidn2-0.dll") + copy_system_library(audio_files "libp11-kit-0.dll") + copy_system_library(audio_files "libtasn1-6.dll") + copy_system_library(audio_files "libunistring-5.dll") + copy_system_library(audio_files "libnettle-8.dll") + copy_system_library(audio_files "libcrypto-3-x64.dll") + copy_system_library(audio_files "libfontconfig-1.dll") + copy_system_library(audio_files "libpixman-1-0.dll") + copy_system_library(audio_files "libffi-8.dll") + copy_system_library(audio_files "libhwy.dll") + copy_system_library(audio_files "libjxl_cms.dll") + copy_system_library(audio_files "libsoxr.dll") + copy_system_library(audio_files "libgdk_pixbuf-2.0-0.dll") + copy_system_library(audio_files "libcairo-gobject-2.dll") + copy_system_library(audio_files "libgio-2.0-0.dll") + copy_system_library(audio_files "libpango-1.0-0.dll") + copy_system_library(audio_files "libpangocairo-1.0-0.dll") + copy_system_library(audio_files "libsharpyuv-0.dll") + copy_system_library(audio_files "libexpat-1.dll") + copy_system_library(audio_files "liblcms2-2.dll") + copy_system_library(audio_files "libgomp-1.dll") + copy_system_library(audio_files "libgmodule-2.0-0.dll") + copy_system_library(audio_files "libtiff-6.dll") + copy_system_library(audio_files "libfribidi-0.dll") + copy_system_library(audio_files "libthai-0.dll") + copy_system_library(audio_files "libpangoft2-1.0-0.dll") + copy_system_library(audio_files "libpangowin32-1.0-0.dll") + copy_system_library(audio_files "libdeflate.dll") + copy_system_library(audio_files "libjbig-0.dll") + copy_system_library(audio_files "libLerc.dll") + copy_system_library(audio_files "libdatrie-1.dll") endif() + install(FILES ${audio_files} DESTINATION ${audio_path}) # NullSoft installer files From 4dff367e14769df6daa344281d79e208002ba66e Mon Sep 17 00:00:00 2001 From: Massimo Callegari Date: Sun, 8 Dec 2024 09:46:36 +0100 Subject: [PATCH 49/68] vc/speeddial: fix color palette with Qt6 --- ui/src/virtualconsole/vcspeeddial.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ui/src/virtualconsole/vcspeeddial.cpp b/ui/src/virtualconsole/vcspeeddial.cpp index b9282395fe..98a3129126 100644 --- a/ui/src/virtualconsole/vcspeeddial.cpp +++ b/ui/src/virtualconsole/vcspeeddial.cpp @@ -166,6 +166,10 @@ VCSpeedDial::VCSpeedDial(QWidget* parent, Doc* doc) this, SLOT(slotUpdate())); m_updateTimer->setSingleShot(true); +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) + // Background color has been moved to Base + setBackgroundColor(palette().color(QPalette::Base)); +#endif m_foregroundColor = palette().color(QPalette::WindowText); m_dial->setStyleSheet(dialSS.arg(palette().color(QPalette::Window).name()) .arg(font().pointSize()) From 6450d4452a88143f6e6d2079c5b7cabf0d2cb6d2 Mon Sep 17 00:00:00 2001 From: Massimo Callegari Date: Sun, 8 Dec 2024 12:24:43 +0100 Subject: [PATCH 50/68] linux: automatically activate hotspot at boot --- webaccess/src/webaccessnetwork.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webaccess/src/webaccessnetwork.cpp b/webaccess/src/webaccessnetwork.cpp index d8239ee398..38198ba5a8 100644 --- a/webaccess/src/webaccessnetwork.cpp +++ b/webaccess/src/webaccessnetwork.cpp @@ -436,7 +436,7 @@ bool WebAccessNetwork::createWiFiHotspot(QString SSID, QString password) getNmcliOutput(QStringList() << "con" << "del" << HOTSPOT_CON_NAME); // create the connection - QString args = "con add type wifi ifname wlan0 mode ap con-name " + HOTSPOT_CON_NAME + " autoconnect no ssid \"" + SSID + "\""; + QString args = "con add type wifi ifname wlan0 mode ap con-name " + HOTSPOT_CON_NAME + " autoconnect yes ssid \"" + SSID + "\""; getNmcliOutput(args.split(" ")); // modify with proper parameters From 2d857c8af552048e4620aab71aaccb730ce58d1b Mon Sep 17 00:00:00 2001 From: Massimo Callegari Date: Mon, 9 Dec 2024 19:56:28 +0100 Subject: [PATCH 51/68] Adjust volume on video intensity change Reported: https://www.qlcplus.org/forum/viewtopic.php?t=17851 --- qmlui/qml/fixturesfunctions/VideoContext.qml | 9 ++++++++- ui/src/videoprovider.cpp | 2 ++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/qmlui/qml/fixturesfunctions/VideoContext.qml b/qmlui/qml/fixturesfunctions/VideoContext.qml index 9e045d344e..647315807e 100644 --- a/qmlui/qml/fixturesfunctions/VideoContext.qml +++ b/qmlui/qml/fixturesfunctions/VideoContext.qml @@ -18,7 +18,7 @@ */ import QtQuick 2.0 -import QtMultimedia 5.8 +import QtMultimedia 5.14 import org.qlcplus.classes 1.0 import "." @@ -149,6 +149,13 @@ Rectangle id: player //source: "sourceURL" autoPlay: true + volume: video.intensity + /* Qt 6.8 + audioOutput: + AudioOutput { + volume: video.intensity + } + */ onStopped: { diff --git a/ui/src/videoprovider.cpp b/ui/src/videoprovider.cpp index 47fa5320e1..77200bd189 100644 --- a/ui/src/videoprovider.cpp +++ b/ui/src/videoprovider.cpp @@ -315,6 +315,8 @@ void VideoWidget::slotBrightnessAdjust(int value) #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) if (m_videoWidget != NULL) m_videoWidget->setBrightness(value); + if (m_videoPlayer) + m_videoPlayer->setVolume(value + 100); #else Q_UNUSED(value) #endif From d9c138c7509935d2757e310fdfffcd79c819b51c Mon Sep 17 00:00:00 2001 From: Massimo Callegari Date: Tue, 10 Dec 2024 17:31:28 +0100 Subject: [PATCH 52/68] qmlui: improve DMX keypad --- engine/src/keypadparser.cpp | 16 +++++++--------- qmlui/qml/KeyPad.qml | 12 ++++++++---- qmlui/simpledesk.cpp | 7 ++++++- qmlui/simpledesk.h | 2 +- 4 files changed, 22 insertions(+), 15 deletions(-) diff --git a/engine/src/keypadparser.cpp b/engine/src/keypadparser.cpp index d22ef00eef..66573245f6 100644 --- a/engine/src/keypadparser.cpp +++ b/engine/src/keypadparser.cpp @@ -18,6 +18,7 @@ */ #include +#include #include "keypadparser.h" #include "qlcmacros.h" @@ -32,7 +33,7 @@ QList KeyPadParser::parseCommand(Doc *doc, QString command, QByteArray &uniData) { QList values; - if (doc == NULL) + if (doc == NULL || command.isEmpty()) return values; QStringList tokens = command.split(" "); @@ -61,16 +62,12 @@ QList KeyPadParser::parseCommand(Doc *doc, QString command, } else if (token == "FULL") { - if (lastCommand == CommandAT) - toValue = 255; - + toValue = 255; lastCommand = CommandFULL; } else if (token == "ZERO") { - if (lastCommand == CommandAT) - toValue = 0; - + toValue = 0; lastCommand = CommandZERO; } else if (token == "BY") @@ -89,7 +86,6 @@ QList KeyPadParser::parseCommand(Doc *doc, QString command, { lastCommand = CommandPlusPercent; } - else if (token == "-%") { lastCommand = CommandMinusPercent; @@ -114,11 +110,13 @@ QList KeyPadParser::parseCommand(Doc *doc, QString command, { case CommandNone: // no command: this is a channel number - if (number <= 0) + if (number <= 1) break; fromChannel = number; toChannel = fromChannel; + fromValue = uchar(uniData.at(number - 1)); + toValue = fromValue; channelSet = true; break; case CommandAT: diff --git a/qmlui/qml/KeyPad.qml b/qmlui/qml/KeyPad.qml index ffa0f51c0e..6ab7d3d513 100644 --- a/qmlui/qml/KeyPad.qml +++ b/qmlui/qml/KeyPad.qml @@ -230,11 +230,13 @@ Rectangle { Layout.fillWidth: true implicitHeight: itemHeight - label: "-" + label: showDMXcontrol ? "-%" : "-" repetition: true onClicked: { - if (showDMXcontrol == false) + if (showDMXcontrol) + commandBox.appendText(" -% ") + else commandBox.text = parseInt(commandBox.text) - 1 } } @@ -249,11 +251,13 @@ Rectangle { Layout.fillWidth: true implicitHeight: itemHeight - label: "+" + label: showDMXcontrol ? "+%" : "+" repetition: true onClicked: { - if (showDMXcontrol == false) + if (showDMXcontrol) + commandBox.appendText(" +% ") + else commandBox.text = parseInt(commandBox.text) + 1 } } diff --git a/qmlui/simpledesk.cpp b/qmlui/simpledesk.cpp index d3e3180eb8..5bf9883991 100644 --- a/qmlui/simpledesk.cpp +++ b/qmlui/simpledesk.cpp @@ -424,8 +424,11 @@ void SimpleDesk::dumpDmxChannels(QString name, quint32 mask) * Keypad ************************************************************************/ -void SimpleDesk::sendKeypadCommand(QString command) +bool SimpleDesk::sendKeypadCommand(QString command) { + if (command.isEmpty()) + return false; + QByteArray uniData = m_prevUniverseValues.value(m_universeFilter); QList scvList = m_keyPadParser->parseCommand(m_doc, command, uniData); @@ -446,6 +449,8 @@ void SimpleDesk::sendKeypadCommand(QString command) m_keypadCommandHistory.removeLast(); emit commandHistoryChanged(); + + return true; } QStringList SimpleDesk::commandHistory() const diff --git a/qmlui/simpledesk.h b/qmlui/simpledesk.h index 695bc975d5..56abc6c8ed 100644 --- a/qmlui/simpledesk.h +++ b/qmlui/simpledesk.h @@ -163,7 +163,7 @@ protected slots: * Keypad ************************************************************************/ public: - Q_INVOKABLE void sendKeypadCommand(QString command); + Q_INVOKABLE bool sendKeypadCommand(QString command); /** Return a list of the last N commands * entered on the keypad */ From e982e70ac59c4c75755f6c6060087eb34c86f89a Mon Sep 17 00:00:00 2001 From: Massimo Callegari Date: Tue, 10 Dec 2024 18:31:28 +0100 Subject: [PATCH 53/68] resources: 4 new fixtures (see changelog) --- debian/changelog | 6 + resources/fixtures/FixturesMap.xml | 4 + resources/fixtures/Ghost/Ghost-Lumy.qxf | 47 ++ .../Showtec/Showtec-Luna-Par-120-Q4.qxf | 127 +++++ .../Showtec/Showtec-Phantom-180-Wash.qxf | 224 ++++++++ .../Stairville-Infinite-Pixel-250.qxf | 491 ++++++++++++++++++ 6 files changed, 899 insertions(+) create mode 100644 resources/fixtures/Ghost/Ghost-Lumy.qxf create mode 100644 resources/fixtures/Showtec/Showtec-Luna-Par-120-Q4.qxf create mode 100644 resources/fixtures/Showtec/Showtec-Phantom-180-Wash.qxf create mode 100644 resources/fixtures/Stairville/Stairville-Infinite-Pixel-250.qxf diff --git a/debian/changelog b/debian/changelog index 8868492664..b18f09e609 100644 --- a/debian/changelog +++ b/debian/changelog @@ -2,10 +2,14 @@ qlcplus (4.13.2) stable; urgency=low * engine: fix flashing fade out * engine: add stopOnExit, waitFunctionStart and waitFunctionStop commands to Script - see documentation (thanks to ldebs) + * UI: adjust audio volume on video intensity change * UI/Fixture Manager: limit the number of RGB panel columns for RGBW to avoid crash * UI/Show Manager: show step notes on the timeline (thanks to anarchid) * UI/Show Manager: handle CTRL+mouse wheel to zoom in/out + * Virtual Console/Slider: send feedback on override button press + * Virtual Console/Sped Dial: fix foreground color setting on Windows * Plugins/OS2L: fix receiving multiple messages at once + * Web Access: reworked websocket implementation * Web Access: fix grand master stopping running functions * Web Access: fix simple desk not resetting the current universe * RGB scripts: added 'Sine Wave' script @@ -21,6 +25,8 @@ qlcplus (4.13.2) stable; urgency=low * New fixture: Shehds LED Beam 12x12W RGBW (thanks to Lukas Hanisch) * New fixture: Chauvet EVE P-160 RGBW (thanks to Max Wheatley) * New fixture: Stairville Wild Wash 132 LED CW (thanks to e-shock) + * New fixture: Showtec Luna Par 120 Q4, Showtec Phantom 180 Wash, Stairville Infinite Pixel 250 + * New fixture: Ghost Lumy (thanks to Manu) -- Massimo Callegari Sun, 29 Dec 2024 18:19:20 +0200 diff --git a/resources/fixtures/FixturesMap.xml b/resources/fixtures/FixturesMap.xml index d34ee77d26..ee2e94c5d4 100644 --- a/resources/fixtures/FixturesMap.xml +++ b/resources/fixtures/FixturesMap.xml @@ -979,6 +979,7 @@ + @@ -1576,6 +1577,7 @@ + @@ -1583,6 +1585,7 @@ + @@ -1660,6 +1663,7 @@ + diff --git a/resources/fixtures/Ghost/Ghost-Lumy.qxf b/resources/fixtures/Ghost/Ghost-Lumy.qxf new file mode 100644 index 0000000000..61af0ca1eb --- /dev/null +++ b/resources/fixtures/Ghost/Ghost-Lumy.qxf @@ -0,0 +1,47 @@ + + + + + Q Light Controller Plus + 5.0.0 Beta 3 + Manu + + Ghost + Lumy + Color Changer + + + + + + + Shutter + No function + Strobe (fast to slow) + + + Effect + No function + Jump mode + Fade mode + Pulse mode + Auto mode + Audio mode + + + Dimmer + Red + Green + Blue + White + Strobe + Automatic mode + + + + + + + + + diff --git a/resources/fixtures/Showtec/Showtec-Luna-Par-120-Q4.qxf b/resources/fixtures/Showtec/Showtec-Luna-Par-120-Q4.qxf new file mode 100644 index 0000000000..e32f03dd30 --- /dev/null +++ b/resources/fixtures/Showtec/Showtec-Luna-Par-120-Q4.qxf @@ -0,0 +1,127 @@ + + + + + Q Light Controller Plus + 5.0.0 Beta 3 + Till Wetzlich + + Showtec + Luna Par 120 Q4 + Color Changer + + + Shutter + No Function + From low to high frequency + + + Shutter + No function + From low to high frequency + + + Colour + Color 1 + Color 2 + Color 3 + Color 4 + Color 5 + Color 6 + Color 7 + Color 8 + Color 9 + Color 10 + Color 11 + Color 12 + Color 13 + Color 14 + Color 15 + Color 16 + Color 17 + Color 18 + Color 19 + Color 20 + Color 21 + Color 22 + Color 23 + Color 24 + Color 25 + Color 26 + Color 27 + Color 28 + Color 29 + Color 30 + Color 31 + Color 32 + Color 33 + Color 34 + + + Colour + No function + Jump 1 + Jump 2 + Jump 3 + Jump 4 + Jump 5 + Jump 6 + Jump 7 + Jump 8 + Fade 1 + Fade 2 + Fade 3 + Fade 4 + Fade 5 + Fade 6 + Fade 7 + + + Speed + Speed adjustment of the built-in chases, from slow +to fast + + + Effect + No function + Sensitivity adjustment, from low to high (0–100 %) + + + + + + + Red + Green + Blue + White + + + Master dimmer + Linear Strobe + Red + Green + Blue + White + + + Master dimmer + Linear Strobe + Random Strobe + Color Presets + Built-in Chases + Speed + Sound-Mode + Red + Green + Blue + White + + + + + + + + + diff --git a/resources/fixtures/Showtec/Showtec-Phantom-180-Wash.qxf b/resources/fixtures/Showtec/Showtec-Phantom-180-Wash.qxf new file mode 100644 index 0000000000..a6f9d2f054 --- /dev/null +++ b/resources/fixtures/Showtec/Showtec-Phantom-180-Wash.qxf @@ -0,0 +1,224 @@ + + + + + Q Light Controller Plus + 5.0.0 Beta 3 + Till Wetzlich + + Showtec + Phantom 180 Wash + Moving Head + + + + + + + + + + + + + + + + + + + + + + Colour + Not functional + Color 1 + Color 2 + Color 3 + Color 4 + Color 5 + Color 6 + Color 7 + Color 8 + Color 9 + Color 10 + Color 11 + Color 12 + Color 13 + Color 14 + Color 15 + Color 16 + Color 17 + Color 18 + Color 19 + Color 20 + Color 21 + Color 22 + Color 23 + Color 24 + Color 25 + Color 26 + Color 27 + Color 28 + Color 29 + Color 30 + Color 31 + Color 32 + Color 33 + Color 34 + Not functional + Continuous clockwise (CW) color flow, from fast to slow + Stop + Continuous counterclockwise (CCW) color flow, from fast to slow + Not functional + Color switch, from fast to slow + Sound-controlled color switch + + + Colour + Not functional + LED program 1 (custom color) + LED program 2 (custom color) + LED program 3 (custom color) + LED program 4 (custom color) + LED program 5 (custom color) + LED program 6 (custom color) + LED program 7 (custom color) + LED program 8 (auto color) + LED program 9 (auto color) + LED program 10 (auto color) + LED program 11 (auto color) + LED program 12 (auto color) + LED program 13 (auto color) + LED program 14 (auto color) + LED program 15 (auto color) + + + Speed + LED program speed, from slow to fast + + + + Shutter + Not functional + Shutter open + Strobe 1, from high to low frequency + Shutter open + Strobe 2 (slow close/fast open), from high to low frequency + Shutter open + Strobe 3 (fast close/slow open), from high to low frequency + Shutter open + Strobe 4 (random strobe), from high to low frequency + Shutter open + Strobe 5 (random slow close/fast open), from high to low frequency + Shutter open + Strobe 6 (random fast close/slow open), from high to low frequency + Shutter open + Strobe 7 (pulse strobe), from high to low frequency + Shutter open + Strobe 8 (random pulse strobe), from high to low frequency + Shutter open + Strobe 9 (fade in/fade out), from high to low frequency + Shutter open + Strobe 10 (random pulse), from high to low frequency + Shutter open + + + + Maintenance + Not functional + Blackout during Pan/Tilt movement + Not functional + Reset Pan + Reset tilt + Reset zoom + Not functional + Reset all + Not functional + Reverse Pan/Tilt movement + Reverse Pan + Reverse Tilt + Cancel Reverse Pan + Cancel Reverse Tilt + Cancel Reverse Pan/Tilt + Not functional + Fan, full speed + Fan, auto speed + Not functional + + + Effect + No Function + Built-in program 1 + Built-in program 2 + Built-in program 3 + Built-in program 4 + Built-in program 5 + Built-in program 6 + Built-in program 7 + Built-in program 8 + Sound-controlled program 1 + Sound-controlled program 2 + Sound-controlled program 3 + Sound-controlled program 4 + Sound-controlled program 5 + Sound-controlled program 6 + Sound-controlled program 7 + Sound-controlled program 8 + + + + Pan + Tilt + Pan fine + Tilt fine + Pan/Tilt speed + Red 1 + Green 1 + Blue 1 + White 1 + Red 2 + Green 2 + Blue 2 + White 2 + Red 3 + Green 3 + Blue 3 + White 3 + Red 4 + Green 4 + Blue 4 + White 4 + Color macros + LED built-in programs + LED built-in program speed + Dimmer + Strobe + Zoom + Functions + Pan/Tilt + Sound control built-in programs + + + Pan + Tilt + Pan/Tilt speed + Red 1 + Green 1 + Blue 1 + White 1 + LED built-in programs + LED built-in program speed + Dimmer + Strobe + Zoom + Functions + Pan/Tilt + Sound control built-in programs + + + + + + + + + diff --git a/resources/fixtures/Stairville/Stairville-Infinite-Pixel-250.qxf b/resources/fixtures/Stairville/Stairville-Infinite-Pixel-250.qxf new file mode 100644 index 0000000000..c74cc18f78 --- /dev/null +++ b/resources/fixtures/Stairville/Stairville-Infinite-Pixel-250.qxf @@ -0,0 +1,491 @@ + + + + + Q Light Controller Plus + 5.0.0 Beta 3 + Fema + + Stairville + Infinite Pixel 250 + Moving Head + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Speed + Program speed - slow ... fast + + + Maintenance + No function + Reset, if the value is transmitted for at least 5 seconds + No function + + + Maintenance + Auto-correction of rotation (pan) and inclination (tilt), decreasing speed + + + Pan + Fixed position (0° to 540°) + Constant clockwise rotation, speed decreasing + Constant anti-clockwise rotation, speed increasing + + + + Tilt + Fixed position (0° to 270°) + Constant clockwise inclination, speed decreasing + Constant anti-clockwise inclination, speed increasing + + + + Pan + No movement + Continuous clockwise rotation, speed decreasing + Continuous anti-clockwise rotation, speed increasing + + + Tilt + No movement + Continuous clockwise rotation, speed decreasing + Continuous anti-clockwise rotation, speed increasing + + + + Effect + No program + Program 1 + Program 2 + Program 3 + Program 4 + Program 5 + Program 6 + + + Effect + No function + Preprogrammed automatic show no. 1 + Preprogrammed automatic show no. 2 + Preprogrammed automatic show no. 3 + Preprogrammed automatic show no. 4 + Preprogrammed automatic show no. 5 + Preprogrammed automatic show no. 6 + + + Shutter + LEDs off + Impulse effect, increasing speed + Constant strobe effect, increasing speed + + + Colour + No function + Colour macros 1 to 32 + + + Effect + No function + Numbers from 0 to 9 + Letters from A to Z + + + Speed + Running speed decreasing + + + Pan + Pan fine + Tilt + Tilt fine + Auto-correction of pan and tilt + Continous Pan + Continous Tilt + Master Dimmer + Red 1 + Green 1 + Blue 1 + White 1 + Strobe + Colour macro + Text Number + Programs + Preprogrammed show speed + Reset + + + Pan + Pan fine + Tilt + Tilt fine + Auto-correction of pan and tilt + Continous Pan + Continous Tilt + Reset + Red 1 + Green 1 + Blue 1 + White 1 + Red 2 + Green 2 + Blue 2 + White 2 + Red 3 + Green 3 + Blue 3 + White 3 + Red 4 + Green 4 + Blue 4 + White 4 + Red 5 + Green 5 + Blue 5 + White 5 + Red 6 + Green 6 + Blue 6 + White 6 + Red 7 + Green 7 + Blue 7 + White 7 + Red 8 + Green 8 + Blue 8 + White 8 + Red 9 + Green 9 + Blue 9 + White 9 + Red 10 + Green 10 + Blue 10 + White 10 + Red 11 + Green 11 + Blue 11 + White 11 + Red 12 + Green 12 + Blue 12 + White 12 + Red 13 + Green 13 + Blue 13 + White 13 + Red 14 + Green 14 + Blue 14 + White 14 + Red 15 + Green 15 + Blue 15 + White 15 + Red 16 + Green 16 + Blue 16 + White 16 + Red 17 + Green 17 + Blue 17 + White 17 + Red 18 + Green 18 + Blue 18 + White 18 + Red 19 + Green 19 + Blue 19 + White 19 + Red 20 + Green 20 + Blue 20 + White 20 + Red 21 + Green 21 + Blue 21 + White 21 + Red 22 + Green 22 + Blue 22 + White 22 + Red 23 + Green 23 + Blue 23 + White 23 + Red 24 + Green 24 + Blue 24 + White 24 + Red 25 + Green 25 + Blue 25 + White 25 + + 8 + 9 + 10 + 11 + + + 12 + 13 + 14 + 15 + + + 16 + 17 + 18 + 19 + + + 20 + 21 + 22 + 23 + + + 24 + 25 + 26 + 27 + + + 28 + 29 + 30 + 31 + + + 32 + 33 + 34 + 35 + + + 36 + 37 + 38 + 39 + + + 40 + 41 + 42 + 43 + + + 44 + 45 + 46 + 47 + + + 48 + 49 + 50 + 51 + + + 52 + 53 + 54 + 55 + + + 56 + 57 + 58 + 59 + + + 60 + 61 + 62 + 63 + + + 64 + 65 + 66 + 67 + + + 68 + 69 + 70 + 71 + + + 72 + 73 + 74 + 75 + + + 76 + 77 + 78 + 79 + + + 80 + 81 + 82 + 83 + + + 84 + 85 + 86 + 87 + + + 88 + 89 + 90 + 91 + + + 92 + 93 + 94 + 95 + + + 96 + 97 + 98 + 99 + + + 100 + 101 + 102 + 103 + + + 104 + 105 + 106 + 107 + + + + Pan + Pan fine + Tilt + Tilt fine + Auto-correction of pan and tilt + Continous Pan + Continous Tilt + Reset + + + + + + + + + From 7a212d88e7f07e857e0edf24ab17409ec985b5b6 Mon Sep 17 00:00:00 2001 From: Massimo Callegari Date: Tue, 10 Dec 2024 18:39:20 +0100 Subject: [PATCH 54/68] engine: fix keypad parser --- engine/src/keypadparser.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/engine/src/keypadparser.cpp b/engine/src/keypadparser.cpp index 66573245f6..fba4617f2d 100644 --- a/engine/src/keypadparser.cpp +++ b/engine/src/keypadparser.cpp @@ -18,7 +18,6 @@ */ #include -#include #include "keypadparser.h" #include "qlcmacros.h" @@ -110,7 +109,7 @@ QList KeyPadParser::parseCommand(Doc *doc, QString command, { case CommandNone: // no command: this is a channel number - if (number <= 1) + if (number <= 0) break; fromChannel = number; From 9b973d31ff17a86f9bee000321b18502b5a282ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20Gscho=C3=9Fmann?= <109181247+mgschossmann@users.noreply.github.com> Date: Tue, 10 Dec 2024 21:49:29 +0100 Subject: [PATCH 55/68] universe: clamp 16-bit values in writeRelative --- engine/src/universe.cpp | 2 +- engine/test/universe/universe_test.cpp | 49 ++++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 1 deletion(-) diff --git a/engine/src/universe.cpp b/engine/src/universe.cpp index 8ab8d56161..b1ddd407dd 100644 --- a/engine/src/universe.cpp +++ b/engine/src/universe.cpp @@ -997,7 +997,7 @@ bool Universe::writeRelative(int address, quint32 value, int channelCount) for (int i = 0; i < channelCount; i++) currentValue = (currentValue << 8) + uchar(m_preGMValues->at(address + i)); - currentValue += (value - RELATIVE_ZERO_16BIT); + currentValue = qint32(CLAMP((qint32)currentValue + (qint32)value - RELATIVE_ZERO_16BIT, 0, 0xFFFF)); for (int i = 0; i < channelCount; i++) { diff --git a/engine/test/universe/universe_test.cpp b/engine/test/universe/universe_test.cpp index de42bfbdb9..68ebb34517 100644 --- a/engine/test/universe/universe_test.cpp +++ b/engine/test/universe/universe_test.cpp @@ -379,6 +379,55 @@ void Universe_Test::writeRelative() QCOMPARE(quint8(m_uni->postGMValues()->at(9)), quint8(0)); QVERIFY(m_uni->writeRelative(9, 0, 1) == true); QCOMPARE(quint8(m_uni->postGMValues()->at(9)), quint8(0)); + + + m_uni->reset(); + + // write 4887 = 19*256+23 + QVERIFY(m_uni->write(9, 19) == true); + QVERIFY(m_uni->write(10, 23) == true); + QCOMPARE(quint8(m_uni->postGMValues()->at(9)), quint8(19)); + QCOMPARE(quint8(m_uni->postGMValues()->at(10)), quint8(23)); + + // write relative 30067 = 117*256+115 + QVERIFY(m_uni->writeRelative(9, 30067, 2) == true); + + // expect 2442 = 9*256+138 + QCOMPARE(quint8(m_uni->postGMValues()->at(9)), quint8(9)); + QCOMPARE(quint8(m_uni->postGMValues()->at(10)), quint8(138)); + + + + // write 4887 = 19*256+23 + QVERIFY(m_uni->write(9, 19) == true); + QVERIFY(m_uni->write(10, 23) == true); + QCOMPARE(quint8(m_uni->postGMValues()->at(9)), quint8(19)); + QCOMPARE(quint8(m_uni->postGMValues()->at(10)), quint8(23)); + + // write relative 27507 = 107*256+115 + QVERIFY(m_uni->writeRelative(9, 27507, 2) == true); + + // expect 0 (due to clamping) + QCOMPARE(quint8(m_uni->postGMValues()->at(9)), quint8(0)); + QCOMPARE(quint8(m_uni->postGMValues()->at(10)), quint8(0)); + + + + // write 48663 = 190*256+23 + QVERIFY(m_uni->write(9, 190) == true); + QVERIFY(m_uni->write(10, 23) == true); + QCOMPARE(quint8(m_uni->postGMValues()->at(9)), quint8(190)); + QCOMPARE(quint8(m_uni->postGMValues()->at(10)), quint8(23)); + + // write relative 58995 = 230*256+115 + QVERIFY(m_uni->writeRelative(9, 58995, 2) == true); + + // expect 65535 = 255*256+255 (due to clamping) + QCOMPARE(quint8(m_uni->postGMValues()->at(9)), quint8(255)); + QCOMPARE(quint8(m_uni->postGMValues()->at(10)), quint8(255)); + + + } void Universe_Test::reset() From e5c77d278d840f2fec04b6418382458a736988ae Mon Sep 17 00:00:00 2001 From: Massimo Callegari Date: Wed, 11 Dec 2024 20:37:34 +0100 Subject: [PATCH 56/68] resources: 3 new fixtures (see changelog) --- debian/changelog | 1 + resources/fixtures/FixturesMap.xml | 3 + ...Constellaser-12W-Waterproof-Scan-Laser.qxf | 133 +++++++++++++++ ...yJet-LED-Beam-300W-Beam&Spot&Wash-3in1.qxf | 152 ++++++++++++++++++ .../Shehds/Shehds-LED-200W-RGB-FLASH.qxf | 144 +++++++++++++++++ 5 files changed, 433 insertions(+) create mode 100644 resources/fixtures/Shehds/Shehds-Constellaser-12W-Waterproof-Scan-Laser.qxf create mode 100644 resources/fixtures/Shehds/Shehds-GalaxyJet-LED-Beam-300W-Beam&Spot&Wash-3in1.qxf create mode 100644 resources/fixtures/Shehds/Shehds-LED-200W-RGB-FLASH.qxf diff --git a/debian/changelog b/debian/changelog index b18f09e609..8bf0fcebb7 100644 --- a/debian/changelog +++ b/debian/changelog @@ -27,6 +27,7 @@ qlcplus (4.13.2) stable; urgency=low * New fixture: Stairville Wild Wash 132 LED CW (thanks to e-shock) * New fixture: Showtec Luna Par 120 Q4, Showtec Phantom 180 Wash, Stairville Infinite Pixel 250 * New fixture: Ghost Lumy (thanks to Manu) + * New fixture: Shehds LED 200W RGB FLASH, GalaxyJet LED Beam 300W Beam&Spot&Wash, Constellaser 12W Waterproof Scan Laser (thanks to Tóth János) -- Massimo Callegari Sun, 29 Dec 2024 18:19:20 +0200 diff --git a/resources/fixtures/FixturesMap.xml b/resources/fixtures/FixturesMap.xml index ee2e94c5d4..cc41d5525b 100644 --- a/resources/fixtures/FixturesMap.xml +++ b/resources/fixtures/FixturesMap.xml @@ -1525,8 +1525,11 @@ + + + diff --git a/resources/fixtures/Shehds/Shehds-Constellaser-12W-Waterproof-Scan-Laser.qxf b/resources/fixtures/Shehds/Shehds-Constellaser-12W-Waterproof-Scan-Laser.qxf new file mode 100644 index 0000000000..9db39ce0ee --- /dev/null +++ b/resources/fixtures/Shehds/Shehds-Constellaser-12W-Waterproof-Scan-Laser.qxf @@ -0,0 +1,133 @@ + + + + + Q Light Controller Plus + 5.0.0 Beta 3 + Tóth János + + Shehds + Constellaser 12W Waterproof Scan Laser + Laser + + + + + Pan + X + + + Tilt + Y + + + Colour + Color select + Change color speed slow to fast + Changing color effect mode 1 (slow to fast) + Changing color effect mode 2 (slow to fast) + Changing color effect mode 3 (slow to fast) + Changing color effect mode 4 (slow to fast) + Changing color effect mode 5 (slow to fast) + + + Effect + Line + Point + + + Effect + Library Select + + + Effect + Animation Library 1 + Animation library 2 + Animation library 3 + Pattern library + + + Speed + Animation playback speed (default) + Animation playback speed (slow to fast) + Sound mode (sound sensitivity slow to high) + + + Effect + Pattern Z axis rotating 360 + rotating slow to fast + + + Effect + Pattern X axis rotating 360 + Rotating slow to fast + + + Effect + Pattern Y axis rotating 360 + rotating speed slow to fast + + + Pan + Pattern or animation X-axis movement + X-axis left to right move (slow to fast) + + + Tilt + Pattern or animation Y-axis movement + Y-axis left to right move (slow to fast) + + + Beam + Pattern or animation zoom + Zoom in&out slow to fast + + + Effect + pattern draw effect slow to fast + + + Effect + X axis twisted Waves + Y axis twisted waves + + + Laser source on + Strobe + Linear Pattern Size + X coordinate + Y coordinate + Color + Scan Mode + Library select + Pattern Animation library + Play Speed + Z rotation + X rotation + Y rotation + X axis move + Y axis move + Zoom + Draw Effect + Twisted Waves + + + Laser source on + Strobe + Linear Pattern Size + X coordinate + Y coordinate + Color + Scan Mode + Library select + Pattern Animation library + Play Speed + + + + + + + + + diff --git a/resources/fixtures/Shehds/Shehds-GalaxyJet-LED-Beam-300W-Beam&Spot&Wash-3in1.qxf b/resources/fixtures/Shehds/Shehds-GalaxyJet-LED-Beam-300W-Beam&Spot&Wash-3in1.qxf new file mode 100644 index 0000000000..b87fa504db --- /dev/null +++ b/resources/fixtures/Shehds/Shehds-GalaxyJet-LED-Beam-300W-Beam&Spot&Wash-3in1.qxf @@ -0,0 +1,152 @@ + + + + + Q Light Controller Plus + 5.0.0 Beta 3 + Tóth János + + Shehds + GalaxyJet LED Beam 300W Beam&Spot&Wash 3in1 + Moving Head + + + + + + + Shutter + None + Strobe from slow to fast + Open + Random strobe from slow to fast + Open + + + + Colour + Open + Open+red + Red + Red+Yellow + Yellow + Yellow+blue + Blue + Blue+Green + Green + Green+rose red + Rose Red + Rose Red+Light Blue + Light Blue + Light Blue+Orange + Orange + Orange+Light green + Light green + Light green+pink + Pink + Pink+Open + Open + Color Rotate Left + Color Rotate Right + + + Gobo + Open + Gobo1 + Gobo2 + Gobo3 + Gobo4 + Gobo5 + Gobo6 + Gobo rotate left + Gobo rotate right + + + Gobo + Open + Gobo1 + Gobo2 + Gobo3 + Gobo4 + Gobo5 + Gobo6 + Gobo7 + Open + Gobo1 + Gobo2 + Gobo3 + Gobo4 + Gobo5 + Gobo6 + Gobo7 + Gobo rotate left + Gobo rotate right + + + Gobo + Rotating 360 + Clockwise Rotation + Anti Clockwise rotation + + + + + Prism + None + 8 facet prism + + + Prism + Rotating 360 + Clockwise Rotation + Anti clockwise rotation + Clockwise rotation and anti clockwise rotation + + + Beam + None + Frost + + + Maintenance + Auto zoom + + + Pan + Pan and tilt move + + + Maintenance + None + Reset Effect + Reset + + + Pan + Pan fine + Tilt + Tilt fine + Pan tilt speed + Strobe + Master dimmer + Color + Gobo1 + Gobo2 + Gobo 2 rotate + Focus + Zoom + Prism + Prism Rotate + Frost + Auto zoom + Auto Move + Reset + + + + + + + + + diff --git a/resources/fixtures/Shehds/Shehds-LED-200W-RGB-FLASH.qxf b/resources/fixtures/Shehds/Shehds-LED-200W-RGB-FLASH.qxf new file mode 100644 index 0000000000..ef0cdbe5de --- /dev/null +++ b/resources/fixtures/Shehds/Shehds-LED-200W-RGB-FLASH.qxf @@ -0,0 +1,144 @@ + + + + + Q Light Controller Plus + 5.0.0 Beta 3 + Tóth János + + Shehds + LED 200W RGB FLASH + LED Bar (Pixels) + + + + + Speed + Color macro speed presets + + + + + + Effect + Background Color intensity (0 - 100%) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Master dimmer + Strobe + Color macro + Color macro speed + Red + Green + Blue + Background Color + Background dimming + + + Red dimmer + Green dimmer + Blue dimmer + + + Red 24 1# + Green 24 1# + Blue 24 1# + Red 24 2# + Green 24 2# + Blue 24 2# + Red 24 3# + Green 24 3# + Blue 24 3# + Red 24 4# + Green 24 4# + Blue 24 4# + Red 24 5# + Green 24 5# + Blue 24 5# + Red 24 6# + Green 24 6# + Blue 24 6# + Red 24 7# + Green 24 7# + Blue 24 7# + Red 24 8# + Green 24 8# + Blue 24 8# + + 0 + 1 + 2 + + + 3 + 4 + 5 + + + 6 + 7 + 8 + + + 9 + 10 + 11 + + + 12 + 13 + 14 + + + 15 + 16 + 17 + + + 18 + 19 + 20 + + + 21 + 22 + 23 + + + + + + + + + + + From 2d87473784fb625581b753b8674700a3202601c2 Mon Sep 17 00:00:00 2001 From: Massimo Callegari Date: Thu, 12 Dec 2024 13:04:57 +0100 Subject: [PATCH 57/68] resrouces: fix unlisted DMX connector and add validation check --- resources/fixtures/FixturesMap.xml | 2 +- .../Shehds/Shehds-Constellaser-12W-Waterproof-Scan-Laser.qxf | 2 +- .../Shehds-GalaxyJet-LED-Beam-300W-Beam&Spot&Wash-3in1.qxf | 2 +- resources/fixtures/Shehds/Shehds-LED-200W-RGB-FLASH.qxf | 2 +- resources/fixtures/scripts/fixtures-tool.py | 5 +++++ 5 files changed, 9 insertions(+), 4 deletions(-) diff --git a/resources/fixtures/FixturesMap.xml b/resources/fixtures/FixturesMap.xml index cc41d5525b..e55f8b7b49 100644 --- a/resources/fixtures/FixturesMap.xml +++ b/resources/fixtures/FixturesMap.xml @@ -1525,7 +1525,7 @@ - + diff --git a/resources/fixtures/Shehds/Shehds-Constellaser-12W-Waterproof-Scan-Laser.qxf b/resources/fixtures/Shehds/Shehds-Constellaser-12W-Waterproof-Scan-Laser.qxf index 9db39ce0ee..ebf4242fc9 100644 --- a/resources/fixtures/Shehds/Shehds-Constellaser-12W-Waterproof-Scan-Laser.qxf +++ b/resources/fixtures/Shehds/Shehds-Constellaser-12W-Waterproof-Scan-Laser.qxf @@ -128,6 +128,6 @@ - +
diff --git a/resources/fixtures/Shehds/Shehds-GalaxyJet-LED-Beam-300W-Beam&Spot&Wash-3in1.qxf b/resources/fixtures/Shehds/Shehds-GalaxyJet-LED-Beam-300W-Beam&Spot&Wash-3in1.qxf index b87fa504db..eba7789bac 100644 --- a/resources/fixtures/Shehds/Shehds-GalaxyJet-LED-Beam-300W-Beam&Spot&Wash-3in1.qxf +++ b/resources/fixtures/Shehds/Shehds-GalaxyJet-LED-Beam-300W-Beam&Spot&Wash-3in1.qxf @@ -147,6 +147,6 @@ - + diff --git a/resources/fixtures/Shehds/Shehds-LED-200W-RGB-FLASH.qxf b/resources/fixtures/Shehds/Shehds-LED-200W-RGB-FLASH.qxf index ef0cdbe5de..6787bac156 100644 --- a/resources/fixtures/Shehds/Shehds-LED-200W-RGB-FLASH.qxf +++ b/resources/fixtures/Shehds/Shehds-LED-200W-RGB-FLASH.qxf @@ -139,6 +139,6 @@ - + diff --git a/resources/fixtures/scripts/fixtures-tool.py b/resources/fixtures/scripts/fixtures-tool.py index 436e19be07..32b97e8097 100755 --- a/resources/fixtures/scripts/fixtures-tool.py +++ b/resources/fixtures/scripts/fixtures-tool.py @@ -286,10 +286,15 @@ def check_physical(absname, node, hasPan, hasTilt, hasZoom, errNum): errNum += 1 if tech_tag is not None: + connectorsArray = [ "3-pin", "5-pin", "3-pin and 5-pin", "3-pin IP65", "5-pin IP65", "3.5 mm stereo jack", "Wireless", "Other" ] power = int(tech_tag.attrib.get('PowerConsumption', 0)) if power == 0: print(absname + ": Invalid power consumption") errNum += 1 + dmxConnector = tech_tag.attrib.get('DmxConnector', "") + if dmxConnector not in connectorsArray: + print(absname + ": Invalid DMX connector") + errNum += 1 return errNum From d54db2eaf0b9a71f87b2bae59c9e9c02ffb9f614 Mon Sep 17 00:00:00 2001 From: Massimo Callegari Date: Mon, 16 Dec 2024 19:03:14 +0100 Subject: [PATCH 58/68] qmlui: improve fixture and head selection --- qmlui/contextmanager.cpp | 48 +++++++++++++++++++++++++--------------- qmlui/fixturemanager.cpp | 10 +++++++++ 2 files changed, 40 insertions(+), 18 deletions(-) diff --git a/qmlui/contextmanager.cpp b/qmlui/contextmanager.cpp index c17520441b..73c739beb2 100644 --- a/qmlui/contextmanager.cpp +++ b/qmlui/contextmanager.cpp @@ -554,7 +554,7 @@ void ContextManager::setFixtureSelection(quint32 itemID, int headIndex, bool ena int headIdx = FixtureUtils::itemHeadIndex(itemID); if (enable) - qDebug() << "Selected itemID" << itemID << ", fixture ID" << fixtureID << ", head" << headIdx; + qDebug() << "Selected itemID" << itemID << ", fixture ID" << fixtureID << ", head from item" << headIdx << "head passed" << headIndex; if (m_selectedFixtures.contains(itemID)) { @@ -585,36 +585,41 @@ void ContextManager::setFixtureSelection(quint32 itemID, int headIndex, bool ena if (fixture == nullptr) return; - m_fixtureManager->setItemRoleData(itemID, enable ? 2 : 0, TreeModel::IsSelectedRole); + if (headIndex == -1) + m_fixtureManager->setItemRoleData(itemID, enable ? 2 : 0, TreeModel::IsSelectedRole); if (m_DMXView->isEnabled()) m_DMXView->updateFixtureSelection(fixtureID, enable); - if (headIndex == -1 && fixture->type() == QLCFixtureDef::Dimmer) + // update fixture selection only if whole fixture is selected (not a specific head) + if (headIndex == -1) { - for (quint32 &subID : m_monProps->fixtureIDList(fixtureID)) + if (fixture->type() == QLCFixtureDef::Dimmer) { - quint16 hIndex = m_monProps->fixtureHeadIndex(subID); - quint16 lIndex = m_monProps->fixtureLinkedIndex(subID); + for (quint32 &subID : m_monProps->fixtureIDList(fixtureID)) + { + quint16 hIndex = m_monProps->fixtureHeadIndex(subID); + quint16 lIndex = m_monProps->fixtureLinkedIndex(subID); - if (lIndex != linkedIndex) - continue; + if (lIndex != linkedIndex) + continue; - quint32 id = FixtureUtils::fixtureItemID(fixtureID, hIndex, linkedIndex); + quint32 id = FixtureUtils::fixtureItemID(fixtureID, hIndex, linkedIndex); + if (m_2DView->isEnabled()) + m_2DView->updateFixtureSelection(id, enable); + if (m_3DView->isEnabled()) + m_3DView->updateFixtureSelection(id, enable); + } + } + else + { if (m_2DView->isEnabled()) - m_2DView->updateFixtureSelection(id, enable); + m_2DView->updateFixtureSelection(itemID, enable); if (m_3DView->isEnabled()) - m_3DView->updateFixtureSelection(id, enable); + m_3DView->updateFixtureSelection(itemID, enable); } } - else - { - if (m_2DView->isEnabled()) - m_2DView->updateFixtureSelection(itemID, enable); - if (m_3DView->isEnabled()) - m_3DView->updateFixtureSelection(itemID, enable); - } QMultiHash channels = m_fixtureManager->getFixtureCapabilities(itemID, headIndex, enable); if (channels.keys().isEmpty()) @@ -662,6 +667,7 @@ void ContextManager::setFixtureIDSelection(quint32 fixtureID, bool enable) void ContextManager::resetFixtureSelection() { +/* for (Fixture *fixture : m_doc->fixtures()) // C++11 { if (fixture == nullptr) @@ -675,6 +681,12 @@ void ContextManager::resetFixtureSelection() setFixtureSelection(itemID, -1, false); } } +*/ + for (quint32 itemID : m_selectedFixtures) + setFixtureSelection(itemID, -1, false); + + m_selectedFixtures.clear(); + m_channelsMap.clear(); } void ContextManager::toggleFixturesSelection() diff --git a/qmlui/fixturemanager.cpp b/qmlui/fixturemanager.cpp index ae59357fc0..e49b58b757 100644 --- a/qmlui/fixturemanager.cpp +++ b/qmlui/fixturemanager.cpp @@ -1989,6 +1989,16 @@ void FixtureManager::resetCapabilities() m_maxBeamDegrees = 0; m_colorsMask = 0; m_capabilityMask = 0; + + emit capabilityMaskChanged(); + + setCapabilityCounter("capIntensity", 0); + setCapabilityCounter("capColor", 0); + setCapabilityCounter("capPosition", 0); + setCapabilityCounter("capColorWheel", 0); + setCapabilityCounter("capGobos", 0); + setCapabilityCounter("capShutter", 0); + setCapabilityCounter("capBeam", 0); } QList FixtureManager::getFixturePosition(quint32 fxID, int type, int degrees) From e99173ccc637ae572bbf37cade2de396c6697378 Mon Sep 17 00:00:00 2001 From: Massimo Callegari Date: Mon, 16 Dec 2024 22:17:54 +0100 Subject: [PATCH 59/68] resources: 5 new fixtures (see changelog) --- debian/changelog | 7 +- resources/fixtures/FixturesMap.xml | 5 + ...Generation-PicoWash-40Z-Pixel-Quad-LED.qxf | 170 ++++++++++ resources/fixtures/Ibiza/Ibiza-Star-Beam.qxf | 87 +++++ .../fixtures/Martin/Martin-MAC-2000-Wash.qxf | 305 ++++++++++++++++++ .../Showtec/Showtec-Club-Par-12-4-RGBW.qxf | 72 +++++ resources/fixtures/UKing/UKing-36W-UV-PAR.qxf | 43 +++ 7 files changed, 687 insertions(+), 2 deletions(-) create mode 100644 resources/fixtures/Fun-Generation/Fun-Generation-PicoWash-40Z-Pixel-Quad-LED.qxf create mode 100644 resources/fixtures/Ibiza/Ibiza-Star-Beam.qxf create mode 100644 resources/fixtures/Martin/Martin-MAC-2000-Wash.qxf create mode 100644 resources/fixtures/Showtec/Showtec-Club-Par-12-4-RGBW.qxf create mode 100644 resources/fixtures/UKing/UKing-36W-UV-PAR.qxf diff --git a/debian/changelog b/debian/changelog index 8bf0fcebb7..fa862ca2de 100644 --- a/debian/changelog +++ b/debian/changelog @@ -48,7 +48,7 @@ qlcplus (4.13.1) stable; urgency=low * New fixtures: beamZ BAC500 and BAC506 (thanks to Olivier Michel) * New fixtures: American DJ Par Z4, beamZ SB400, OXO ColorBeam 7 FCW IR, Pro-Lights Pixie Spot (thanks to Dmitry Kolesnikov) * New fixtures: BoomToneDJ LED PAR 7X10W 5in1, BoomToneDJ Maxi Spot 60, Mac Mah FLAT PAR 7x12W 6in1, Eurolite LED PIX-16 QCL Bar (thanks to Cédric Monféfoul) - * New fixture: Showtec ACT PC 60 RGBW (thanks to Michel Sliepenbeek) + * New fixtures: Showtec ACT PC 60 RGBW, Ibiza Star Beam (thanks to Michel Sliepenbeek) * New fixtures: Robe LEDBeam 350, Robe LEDBeam 350 RGBA, Briteq COB Blinder 2x100W, Ayrton MiniPanel FX (thanks to Giacomo Gorini) * New fixture: Elation ELED B48 (thanks to Xoneoo) * New fixture: beamZ PS10W (thanks to Jesper Korsen) @@ -56,9 +56,12 @@ qlcplus (4.13.1) stable; urgency=low * New fixtures: Mac Mah Moving-FX Bar, Varytec LED Pad Bar Compact ST RGB, Laserworld EL-400RGB MK2 (thanks to Clément Delabroye) * New fixtures: Electroconcept Club Scan 30, Club Scan 120, LED Blinder, Profile 120 Spot LED, Micro Spot 60 LED (thanks to Clément Delabroye) * New fixture: Ayrton Mistral (thanks to Masatoshi Fujino) - * New fixture: Chauvet COLORtube 3.0 EQ Controller (thanks to Fede79) + * New fixtures: Chauvet COLORtube 3.0 EQ Controller, Martin MAC 2000 Wash (thanks to Fede79) * New fixture: Shehds Big Bee Eyes LED Wash 19x40W RGBW (thanks to István Király) * New fixture: Fun-Generation Mr. Beam 120 W (thanks to Mariano) + * New fixture: UKing 36W PAR UV ZQ01087 (thanks to Lance Moore) + * New fixture: Showtec Club Par 12-4 RGBW (thanks to Simon Dovicovic) + * New fixture: Fun-Generation PicoWash 40Z Pixel Quad LED (thanks to Kristers) -- Massimo Callegari Thu, 30 May 2024 18:19:20 +0200 diff --git a/resources/fixtures/FixturesMap.xml b/resources/fixtures/FixturesMap.xml index e55f8b7b49..e4e946c871 100644 --- a/resources/fixtures/FixturesMap.xml +++ b/resources/fixtures/FixturesMap.xml @@ -921,6 +921,7 @@ + @@ -1038,6 +1039,7 @@ + @@ -1254,6 +1256,7 @@ + @@ -1547,6 +1550,7 @@ + @@ -1776,6 +1780,7 @@ + diff --git a/resources/fixtures/Fun-Generation/Fun-Generation-PicoWash-40Z-Pixel-Quad-LED.qxf b/resources/fixtures/Fun-Generation/Fun-Generation-PicoWash-40Z-Pixel-Quad-LED.qxf new file mode 100644 index 0000000000..80f325bda3 --- /dev/null +++ b/resources/fixtures/Fun-Generation/Fun-Generation-PicoWash-40Z-Pixel-Quad-LED.qxf @@ -0,0 +1,170 @@ + + + + + Q Light Controller Plus + 5.0.0 Beta 3 + Kristers D + + Fun-Generation + PicoWash 40Z Pixel Quad LED + Moving Head + + + + + + + + Shutter + No function (open) + Strobe, slow to fast (1 Hz - 25 Hz) + + + + + + + + + + + + + + + + + + + Effect + No function + Red + Green + Blue + White + Yellow + Cyan + Magenta + All White + Empty + Programme 1 + Programme 2 + Programme 3 + Programme 4 + Programme 5 + Programme 6 + Programme 7 + Programme 8 + Programme 9 + Empty + Reset + Empty + Sound-controlled mode + + + Speed + Speed / Sensitivity + + + + + + + Beam + Zoom + + + Pan + Tilt + Zoom + Master dimmer + + + Pan + Pan (fine) + Tilt + Tilt (fine) + Motor speed + Zoom + Master dimmer + Function + Speed / Sensitivity + + + Pan + Pan (fine) + Tilt + Tilt (fine) + Motor speed + Zoom + Master dimmer + Strobe + Red + Green + Blue + White + Function + Speed / Sensitivity + + + Pan + Pan (fine) + Tilt + Tilt (fine) + Motor speed + Zoom + Master dimmer + Strobe + LED 1 Red + LED 1 Green + LED 1 Blue + LED 1 White + LED 2 Red + LED 2 Green + LED 2 Blue + LED 2 White + LED 3 Red + LED 3 Green + LED 3 Blue + LED 3 White + LED 4 Red + LED 4 Green + LED 4 Blue + LED 4 White + Function + Speed / Sensitivity + + 7 + 8 + 9 + 10 + + + 11 + 12 + 13 + 14 + + + 15 + 16 + 17 + 18 + + + 19 + 20 + 21 + 22 + + + + + + + + + + + diff --git a/resources/fixtures/Ibiza/Ibiza-Star-Beam.qxf b/resources/fixtures/Ibiza/Ibiza-Star-Beam.qxf new file mode 100644 index 0000000000..404cbe139f --- /dev/null +++ b/resources/fixtures/Ibiza/Ibiza-Star-Beam.qxf @@ -0,0 +1,87 @@ + + + + + Q Light Controller Plus + 5.0.0 Beta 3 + Michel Sliepenbeek + + Ibiza + Star Beam + Moving Head + + + + + + + + Shutter + No function + Strobe (Slow to Fast) + + + + + + + + Effect + Auto + Sound + + + Speed + Fast to Slow + + + Effect + No function + Reset + + + + + Pan + Pan fine + Tilt + Tilt fine + Pan/Tilt speed + Master dimmer + Strobe + Red LED + Green LED + Blue LED + White LED + Built in Wash Effect + Auto, Sound Control + Auto Speed + Reset + Outer Light Circle + Inner Light Circle + + + Pan + Tilt + Pan/Tilt speed + Master dimmer + Strobe + Red LED + Green LED + Blue LED + White LED + Built in Wash Effect + Auto, Sound Control + Auto Speed + Reset + Outer Light Circle + Inner Light Circle + + + + + + + + + diff --git a/resources/fixtures/Martin/Martin-MAC-2000-Wash.qxf b/resources/fixtures/Martin/Martin-MAC-2000-Wash.qxf new file mode 100644 index 0000000000..2a913b6f7f --- /dev/null +++ b/resources/fixtures/Martin/Martin-MAC-2000-Wash.qxf @@ -0,0 +1,305 @@ + + + + + Q Light Controller Plus + 5.0.0 Beta 3 + Fede79 + + Martin + MAC 2000 Wash + Moving Head + + Shutter + Shutter closed + No function (shutter open) + Strobe fast to slow + Shutter open, lamp reduced to 700 W + Pulse opening, fast to slow + Pulse closing, fast to slow + No function + Random strobe, fast + Random strobe, medium + Random strobe, slow + No function + Random pulse opening, fast + Random pulse opening, slow + Random pulse closing, fast + Random pulse closing, slow + No function + Reset fixture + No function + Lamp on + No function + Lamp off + + + + + Effect + Normal (full range) + Minimum cyan setting (127 = full cyan) + Maximum cyan setting (128 = no cyan) + Normal (full range) + + + + Effect + Normal (full range) + Minimum cyan setting (127 = full magenta) + Maximum cyan setting (128 = no magenta) + Normal (full range) + + + + Effect + Normal (full range) + Minimum cyan setting (127 = full yellow) + Maximum cyan setting (128 = no yellow) + Normal (full range) + + + Colour + White to CTC + + + Colour + White + White to Green + Green + Green to Blue + Blue + Blue to UV Transmitter + UV Transmitter + UV Transmitter to Half Minus Green + Half Minus Green + Half Minus Green to White + White + Half Minus Green + UV Transmitter + Blue + Green + White + Color wheel scroll, Fast to slow CW + Color wheel scroll, Slow to fast CCW + Random color CMY, fast + + + + + + + + + + + + + + Random color CMY, medium + + + + + + + + + + + + + + Random color CMY, slow + + + + + + + + + + + + + + + + Colour + White + White to Red + Red + Red to Orange + Orange + Orange to Green + Green + Green to Blue + Blue + Blue to White + White + Blue + Green + Orange + Red + White + Color wheel scroll, Fast to slow CW + Color wheel scroll, Slow to fast CCW + No function + + + + Beam + Zoom, wide to narrow + No changes + Open + + + Beam + Out to In + + + Beam + Out to In + + + Beam + Out to In + + + Beam + Out to In + + + Beam + Right to center to left + + + Beam + No macro action + All doors at 50% + No macro action + Large doors at 80% and small doors at 0% + No macro action + Small doors at 80% and large doors at 0% + No macro action + + + + + + + Speed + Tracking + Speed, fast to slow + Tracking, slow speed + Tracking, normal speed + Tracking, fast speed + No function + + + Speed + Tracking + Speed, fast to slow + Tracking, studio mode disabled + Tracking, studio mode enabled + Tracking, shortcuts disabled + Tracking, shortcuts enabled + Fast speed + + + Shutter and function + Dimmer blades + Cyan + Magenta + Yellow + CTC + Color wheel 1 + Color wheel 2 + Zoom + Barndoor 1 (Upper) + Barndoor 2 (Lower) + Barndoor 3 (Left) + Barndoor 4 (Right) + Rotate barndoors + MACRO functions (Barndoors) + Pan + Tilt + Speed pan/tilt movement + Speed effect + + + Shutter and function + Dimmer blades + Cyan + Magenta + Yellow + CTC + Color wheel 1 + Dimmer wheel + Zoom + Barndoor 1 (Upper) + Barndoor 2 (Lower) + Barndoor 3 (Left) + Barndoor 4 (Right) + Rotate barndoors + MACRO functions (Barndoors) + Pan + Tilt + Speed pan/tilt movement + Speed effect + + + Shutter and function + Dimmer blades + Cyan + Magenta + Yellow + CTC + Color wheel 1 + Color wheel 2 + Zoom + Barndoor 1 (Upper) + Barndoor 2 (Lower) + Barndoor 3 (Left) + Barndoor 4 (Right) + Rotate barndoors + MACRO functions (Barndoors) + Pan + Pan fine + Tilt + Tilt fine + Speed pan/tilt movement + Speed effect + + + Shutter and function + Dimmer blades + Cyan + Magenta + Yellow + CTC + Color wheel 1 + Dimmer wheel + Zoom + Barndoor 1 (Upper) + Barndoor 2 (Lower) + Barndoor 3 (Left) + Barndoor 4 (Right) + Rotate barndoors + MACRO functions (Barndoors) + Pan + Pan fine + Tilt + Tilt fine + Speed pan/tilt movement + Speed effect + + + + + + + + + diff --git a/resources/fixtures/Showtec/Showtec-Club-Par-12-4-RGBW.qxf b/resources/fixtures/Showtec/Showtec-Club-Par-12-4-RGBW.qxf new file mode 100644 index 0000000000..315b9202eb --- /dev/null +++ b/resources/fixtures/Showtec/Showtec-Club-Par-12-4-RGBW.qxf @@ -0,0 +1,72 @@ + + + + + Q Light Controller Plus + 5.0.0 Beta 3 + Simon Dovicovic + + Showtec + Club Par 12-4 RGBW + Color Changer + + + + + + + Shutter + Closed + Strobe flash frequency, from slow to fast + + + Effect + Not functional + Program 1 + Program 2 + Program 3 + Program 4 + Program 5 + Program 6 + Program 7 + Program 8 + Program 9 + Program 10 + Program 11 + Program 12 + Program 13 + Sound-controlled + + + Speed + Gradual speed adjustment, from slow to fast + + + Speed + Gradual speed adjustment, from color jump to color fade + + + Red + Green + Blue + White + + + Intensity + Red + Green + Blue + White + Strobe + Build in program + Speed + Fade time + + + + + + + + + diff --git a/resources/fixtures/UKing/UKing-36W-UV-PAR.qxf b/resources/fixtures/UKing/UKing-36W-UV-PAR.qxf new file mode 100644 index 0000000000..70763f3431 --- /dev/null +++ b/resources/fixtures/UKing/UKing-36W-UV-PAR.qxf @@ -0,0 +1,43 @@ + + + + + Q Light Controller Plus + 5.0.0 Beta 3 + Lance Moore + + UKing + 36W PAR UV ZQ01087 + Color Changer + + + + + + + Effect + Manual Control (Ch1 - 5) + Colors Selection (By Ch7) + Colors Shade (By Ch7) + Colors Pulse Transform (By Ch7) + Colors Transition (By Ch7) + Sound Active Mode + + + + Master dimmer + Brightness UV LED Bank1 + Brightness UV LED Bank 2 + Brightness UV LED Bank 3 + Strobe + Presets & Sound (211-255 Sound) + Effect Speed (Ch6) + + + + + + + + + From 9ad6c19be6b1ad1e0c32c046b7bf97b93b4e3ea4 Mon Sep 17 00:00:00 2001 From: Massimo Callegari Date: Tue, 17 Dec 2024 09:04:59 +0100 Subject: [PATCH 60/68] ui: increase fixture add dialog limits --- ui/src/addfixture.ui | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ui/src/addfixture.ui b/ui/src/addfixture.ui index 3c4cc4a21e..8b4183ab33 100644 --- a/ui/src/addfixture.ui +++ b/ui/src/addfixture.ui @@ -148,7 +148,7 @@ 1 - 128 + 1000 1 @@ -240,7 +240,7 @@ 1 - 128 + 512 @@ -257,7 +257,7 @@ Number of empty channels to leave between added fixtures - 128 + 511 From c96a60c745252208d8fbb5660ccdb674138cddd3 Mon Sep 17 00:00:00 2001 From: Massimo Callegari Date: Tue, 17 Dec 2024 19:19:55 +0100 Subject: [PATCH 61/68] resources: 2 new and 2 updated fixtures (see changelog) --- debian/changelog | 2 + .../fixtures/Acme/Acme-Super-Dotline.qxf | 78 ++--- .../Chauvet/Chauvet-Ovation-H-605FC.qxf | 203 +++++++++++++ resources/fixtures/FixturesMap.xml | 2 + resources/fixtures/Martin/Martin-smartMAC.qxf | 273 ++++++++++++++++++ .../Showtec-Spectral-M1000-Tour-Q4-MKII.qxf | 18 -- 6 files changed, 519 insertions(+), 57 deletions(-) create mode 100644 resources/fixtures/Chauvet/Chauvet-Ovation-H-605FC.qxf create mode 100644 resources/fixtures/Martin/Martin-smartMAC.qxf diff --git a/debian/changelog b/debian/changelog index fa862ca2de..fa4e71d461 100644 --- a/debian/changelog +++ b/debian/changelog @@ -62,6 +62,8 @@ qlcplus (4.13.1) stable; urgency=low * New fixture: UKing 36W PAR UV ZQ01087 (thanks to Lance Moore) * New fixture: Showtec Club Par 12-4 RGBW (thanks to Simon Dovicovic) * New fixture: Fun-Generation PicoWash 40Z Pixel Quad LED (thanks to Kristers) + * New fixture: Chauvet Ovation H-605FC (thanks to Ken Coughlin) + * New fixture: Martin smartMAC (thanks to Mads Vejrup) -- Massimo Callegari Thu, 30 May 2024 18:19:20 +0200 diff --git a/resources/fixtures/Acme/Acme-Super-Dotline.qxf b/resources/fixtures/Acme/Acme-Super-Dotline.qxf index fff8798f29..e43457e5de 100644 --- a/resources/fixtures/Acme/Acme-Super-Dotline.qxf +++ b/resources/fixtures/Acme/Acme-Super-Dotline.qxf @@ -3,7 +3,7 @@ Q Light Controller Plus - 4.13.0 GIT + 5.0.0 Beta 3 Michael Tosatto Acme @@ -2152,6 +2152,18 @@ LINE_RGB Red 24 LINE_RGB Green 24 LINE_RGB Blue 24 + + 0 + 1 + 2 + 3 + + + 4 + 5 + 6 + 7 + 8 9 @@ -2203,12 +2215,16 @@ 40 41 + + 42 43 44 45 + + 46 47 @@ -2295,138 +2311,122 @@ 88 89 - - 90 - 91 + 91 92 93 94 95 + 96 - 96 97 98 + 99 - 99 100 101 + 102 - 102 103 104 + 105 - 105 106 107 + 108 - 108 109 110 + 111 - 111 112 113 + 114 - 114 115 116 + 117 - 117 118 119 + 120 - 120 121 122 + 123 - 123 124 125 + 126 - 126 127 128 + 129 - 129 130 131 + 132 - 132 133 134 + 135 - 135 136 137 + 138 - 138 139 140 + 141 - 141 142 143 + 144 - 144 145 146 + 147 - 147 148 149 + 150 - 150 151 152 + 153 - 153 154 155 + 156 - 156 157 158 - - 159 - 160 - 161 - - - 162 - 163 - 164 - - - 165 - 166 - 167 diff --git a/resources/fixtures/Chauvet/Chauvet-Ovation-H-605FC.qxf b/resources/fixtures/Chauvet/Chauvet-Ovation-H-605FC.qxf new file mode 100644 index 0000000000..6d88dc1fd4 --- /dev/null +++ b/resources/fixtures/Chauvet/Chauvet-Ovation-H-605FC.qxf @@ -0,0 +1,203 @@ + + + + + Q Light Controller Plus + 5.0.0 Beta 3 + Ken Coughlin + + Chauvet + Ovation H-605FC + Color Changer + + + + + + + + + + + + + + + Colour + Black Out + C3050 - Medium Yellow + C3040 - Light Yellow + C3240 - Amber Yellow + C2340 - Very Light Amber + C2040 - Light Amber + C2050 - Medium Amber + C2060 - Dark Amber + C1050 - Light Red + C1080 - Medium Red + C1020 - No Color Pink + C1030 - Medium Pink + C1630 - Dark Pink + C1250 - Medium Red Amber + C1060 - Dark Red Amber + C1650 - Magenta + C6170 - Dark Magenta + C6020 - Light Lavender + C5030 - Light Blue + C5020 - Very Light Blue + C5430 - Light Blue 2 + C5070 - Blue + C5050 - Md Blue + C5060 - Dark Blue + C5690 - Indigo + C5080 - Very Dark Blue + C5081 - Very Dark Blue2 + C4370 - Yellow Green + C4070 - Green + C4550 - Turquoise + C4560 - Aqua + C4570 - Blue Green + Black Out + + + Colour + Black Out + 2800K + 3000K + 3200K + 3500K + 4000K + 4500K + 5000K + 5600K + 6000K + 6500K + Black Out + + + Maintenance + No function + Dimmer reset + Red Shift On + Red Shift Off + Dimmer: S-Curve + Dimmer: Linear + Dimmer: Square + Dimmer: Inverse Square + Dimmer Mode Off + Dimmer Mode 1 + Dimmer Mode 2 + Dimmer Mode 3 + Fan Auto + Fan On + Fan Off + Fan Silent + No function + + + Colour + No function + Auto Program 1 + Auto Program 2 + Auto Program 3 + Auto Program 4 + Auto Program 5 + + + + + + + Hue + Saturation + Value + + + Master dimmer + + + Master dimmer + Virtual Color Wheel + Color Temperature + + + Red + Green + Blue + Amber + Lime + + + Master dimmer + Red + Green + Blue + Amber + Lime + Strobe + + + Master dimmer + Master dimmer fine + Red + Green + Blue + Amber + Lime + Strobe + Virtual Color Wheel + Color Temperature + + + Master dimmer + Red + Green + Blue + Amber + Lime + Strobe + Virtual Color Wheel + Color Temperature + Auto Programs + Auto Program speed + Control + + + Master dimmer + Master dimmer fine + Red + Red fine + Green + Green fine + Blue + Blue fine + Amber + Amber fine + Lime + Lime fine + Strobe + + + Master dimmer + Master dimmer fine + Red + Red fine + Green + Green fine + Blue + Blue fine + Amber + Amber fine + Lime + Lime fine + Strobe + Virtual Color Wheel + Color Temperature + + + + + + + + + diff --git a/resources/fixtures/FixturesMap.xml b/resources/fixtures/FixturesMap.xml index e4e946c871..87d44fd9ff 100644 --- a/resources/fixtures/FixturesMap.xml +++ b/resources/fixtures/FixturesMap.xml @@ -522,6 +522,7 @@ + @@ -1302,6 +1303,7 @@ + diff --git a/resources/fixtures/Martin/Martin-smartMAC.qxf b/resources/fixtures/Martin/Martin-smartMAC.qxf new file mode 100644 index 0000000000..2e800abaa4 --- /dev/null +++ b/resources/fixtures/Martin/Martin-smartMAC.qxf @@ -0,0 +1,273 @@ + + + + + Q Light Controller Plus + 5.0.0 Beta 3 + Mads Vejrup + + Martin + smartMAC + Moving Head + + Shutter + Shutter closed + Shutter open + Shutter fade in + Shutter fade out + Strobe fast to slow + Shutter open + Opening pulse fast to slow + Closing pulse fast to slow + Shutter open + Music triggered shutter + Random strobe fast + Random strobe medium + Random strobe slow + Shutter open + Random opening pulse fast + Random opening pulse slow + Random closing pulse fast + Random closing pulse slow + Shutter open + Reset fixture + Shutter open + Lamp on + Shutter open + Lamp power off (hold for 5 sec.) + + + + Colour + Open + Open/Blue + Blue + Blue/Green + Green + Green/Orange + Orange + Orange/Yellow + Yellow + Yellow/Pink + Pink + Pink/Magenta + Magenta + Magenta/Congo + Congo + Congo/Red + Red + Red/Open + Open + Red + Congo + Magenta + Pink + Yellow + Orange + Green + Blue + Open + CW fast to slow + Color Wheel stop + CCW slow to fast + Music trigger fast + Music trigger medium + Music trigger slow + Random color fast + Random color medium + Random color slow + + + Gobo + Open gobo + Gobo 1 (Indexing) + Gobo 2 (Indexing) + Gobo 3 (Indexing) + Gobo 4 (Indexing) + Gobo 5 (Indexing) + Gobo 6 (Indexing) + Open gobo + Gobo 1 (Rotation) + Gobo 2 (Rotation) + Gobo 3 (Rotation) + Gobo 4 (Rotation) + Gobo 5 (Rotation) + Gobo 6 (Rotation) + Gobo 1 shake slow to fast (indexed) + Gobo 2 shake slow to fast (indexed) + Gobo 3 shake slow to fast (indexed) + Gobo 4 shake slow to fast (indexed) + Gobo 5 shake slow to fast (indexed) + Gobo 6 shake slow to fast (indexed) + Gobo 1 shake slow to fast (rotating) + Gobo 2 shake slow to fast (rotating) + Gobo 3 shake slow to fast (rotating) + Gobo 4 shake slow to fast (rotating) + Gobo 5 shake slow to fast (rotating) + Gobo 6 shake slow to fast (rotating) + CW slow to fast + CCW fast to slow + Music triggered fast + Music triggered medium + Music triggered slow + + + Effect + No rotation + CW - slow to fast + CCW - fast to slow + No rotation + + + Effect + Gobo rotation fine + + + + Effect + No Macro + Macro 1.1 + Macro 1.2 + Macro 1.3 + Macro 1.4 + Macro 2.1 + Macro 2.2 + Macro 2.3 + Macro 2.4 + Macro 3.1 + Macro 3.2 + Macro 3.3 + Macro 3.4 + Macro 4.1 + Macro 4.2 + Macro 4.3 + Macro 4.4 + Macro 5.1 + Macro 5.2 + Macro 5.3 + Macro 5.4 + Macro 6.1 + Macro 6.2 + Macro 6.3 + Macro 6.4 + Macro 7.1 + Macro 7.2 + Macro 7.3 + Macro 7.4 + Macro 8.1 + Macro 8.2 + Macro 8.3 + Macro 8.4 + Macro 9.1 + Macro 9.2 + Macro 9.3 + Macro 9.4 + Macro 10.1 + Macro 10.2 + Macro 10.3 + Macro 10.4 + Reserved (no effect) + + + + + + + Speed + Tracking mode + Vector mode - fast to slow + Tracking mode - PTSP=NORM + Tracking mode - PTSP=FAST + Blackout while moving + + + Speed + Tracking mode + Vector mode - fast to slow + Tracking mode + Vector mode - maximum speed + + + Effect + No Macro + Macro 1.1 + Macro 1.2 + Macro 1.3 + Macro 1.4 + Macro 2.1 + Macro 2.2 + Macro 2.3 + Macro 2.4 + Macro 3.1 + Macro 3.2 + Macro 3.3 + Macro 3.4 + Macro 4.1 + Macro 4.2 + Macro 4.3 + Macro 4.4 + Macro 5.1 + Macro 5.2 + Macro 5.3 + Macro 5.4 + Macro 6.1 + Macro 6.2 + Macro 6.3 + Macro 6.4 + Macro 7.1 + Macro 7.2 + Macro 7.3 + Macro 7.4 + Macro 8.1 + Macro 8.2 + Macro 8.3 + Macro 8.4 + Macro 9.1 + Macro 9.2 + Macro 9.3 + Macro 9.4 + Macro 10.1 + Macro 10.2 + Macro 10.3 + Macro 10.4 + Reserved (no effect) + + + Shutter / Strobe + Shutter Fading + Color Wheel + Gobo + Gobo Rotation + Gobo Rotation Fine + Focus + Pan/Tilt Macros + Effect Macros + Pan + Pan Fine + Tilt + Tilt Fine + Pan/Tilt Speed + Effects Speed (Shutter, focus) + + + Shutter / Strobe + Shutter Fading + Color Wheel + Gobo + Gobo Rotation + Focus + Pan/Tilt Macros + Effect Macros + Pan + Tilt + Pan/Tilt Speed + Effects Speed (Shutter, focus) + + + + + + + + + diff --git a/resources/fixtures/Showtec/Showtec-Spectral-M1000-Tour-Q4-MKII.qxf b/resources/fixtures/Showtec/Showtec-Spectral-M1000-Tour-Q4-MKII.qxf index 3c85c11195..bfe5a58025 100644 --- a/resources/fixtures/Showtec/Showtec-Spectral-M1000-Tour-Q4-MKII.qxf +++ b/resources/fixtures/Showtec/Showtec-Spectral-M1000-Tour-Q4-MKII.qxf @@ -168,24 +168,6 @@ Hue (colour variations) Colour Saturation Dimmer Intensity - - 1 - 2 - 3 - 4 - - - 5 - 6 - 7 - 8 - - - 9 - 10 - 11 - 12 - Dimmer Intensity From c348c2b4ae3967f39db212e6f96b833f98bfecda Mon Sep 17 00:00:00 2001 From: Massimo Callegari Date: Sat, 21 Dec 2024 11:17:06 +0100 Subject: [PATCH 62/68] ui: adjust audio volume of a video TODO: apparently in Qt6 the Qt company forgot to implement the color adjustment methods... --- ui/src/videoprovider.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ui/src/videoprovider.cpp b/ui/src/videoprovider.cpp index 77200bd189..3c74cd2d86 100644 --- a/ui/src/videoprovider.cpp +++ b/ui/src/videoprovider.cpp @@ -318,7 +318,8 @@ void VideoWidget::slotBrightnessAdjust(int value) if (m_videoPlayer) m_videoPlayer->setVolume(value + 100); #else - Q_UNUSED(value) + if (m_audioOutput) + m_audioOutput->setVolume(value + 100); #endif } From 1bd5524f85408704a80a18ee6871308f7c02a254 Mon Sep 17 00:00:00 2001 From: Massimo Callegari Date: Sat, 21 Dec 2024 11:54:49 +0100 Subject: [PATCH 63/68] webaccess: add widget ID to getWidgetType and getWidgetStatus response --- debian/changelog | 5 +++-- webaccess/res/Test_Web_API.html | 4 ++-- webaccess/src/webaccess.cpp | 7 +++++-- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/debian/changelog b/debian/changelog index fa4e71d461..c91679d586 100644 --- a/debian/changelog +++ b/debian/changelog @@ -12,6 +12,7 @@ qlcplus (4.13.2) stable; urgency=low * Web Access: reworked websocket implementation * Web Access: fix grand master stopping running functions * Web Access: fix simple desk not resetting the current universe + * Web Access: add widget ID to getWidgetType and getWidgetStatus response * RGB scripts: added 'Sine Wave' script * RGB scripts: fix Vertical Fall not allowing changing color when cloned * New fixtures: GLP Impression X5, Ayrton Rivale Profile, Ayrton Kyalami (thanks to Masatoshi Fujino) @@ -28,6 +29,8 @@ qlcplus (4.13.2) stable; urgency=low * New fixture: Showtec Luna Par 120 Q4, Showtec Phantom 180 Wash, Stairville Infinite Pixel 250 * New fixture: Ghost Lumy (thanks to Manu) * New fixture: Shehds LED 200W RGB FLASH, GalaxyJet LED Beam 300W Beam&Spot&Wash, Constellaser 12W Waterproof Scan Laser (thanks to Tóth János) + * New fixture: Chauvet Ovation H-605FC (thanks to Ken Coughlin) + * New fixture: Martin smartMAC (thanks to Mads Vejrup) -- Massimo Callegari Sun, 29 Dec 2024 18:19:20 +0200 @@ -62,8 +65,6 @@ qlcplus (4.13.1) stable; urgency=low * New fixture: UKing 36W PAR UV ZQ01087 (thanks to Lance Moore) * New fixture: Showtec Club Par 12-4 RGBW (thanks to Simon Dovicovic) * New fixture: Fun-Generation PicoWash 40Z Pixel Quad LED (thanks to Kristers) - * New fixture: Chauvet Ovation H-605FC (thanks to Ken Coughlin) - * New fixture: Martin smartMAC (thanks to Mads Vejrup) -- Massimo Callegari Thu, 30 May 2024 18:19:20 +0200 diff --git a/webaccess/res/Test_Web_API.html b/webaccess/res/Test_Web_API.html index 52c6b6fa09..813776abc5 100644 --- a/webaccess/res/Test_Web_API.html +++ b/webaccess/res/Test_Web_API.html @@ -213,11 +213,11 @@ } else if (msgParams[1] === "getWidgetType") { - document.getElementById('getWidgetTypeBox').innerHTML = msgParams[2]; + document.getElementById('getWidgetTypeBox').innerHTML = msgParams[3]; } else if (msgParams[1] === "getWidgetStatus") { - var status = msgParams[2]; + var status = msgParams[3]; if (msgParams[2] === "PLAY") status = msgParams[2] + "(Step: " + msgParams[3] + ")"; document.getElementById('getWidgetStatusBox').innerHTML = status; diff --git a/webaccess/src/webaccess.cpp b/webaccess/src/webaccess.cpp index 87bc4f229e..60a7db3c99 100644 --- a/webaccess/src/webaccess.cpp +++ b/webaccess/src/webaccess.cpp @@ -622,9 +622,9 @@ void WebAccess::slotHandleWebSocketRequest(QHttpConnection *conn, QString data) quint32 wID = cmdList[2].toUInt(); VCWidget *widget = m_vc->widget(wID); if (widget != NULL) - wsAPIMessage.append(widget->typeToString(widget->type())); + wsAPIMessage.append(QString("%1|%2").arg(widget->id()).arg(widget->typeToString(widget->type()))); else - wsAPIMessage.append(widget->typeToString(VCWidget::UnknownWidget)); + wsAPIMessage.append(QString("%1|%2").arg(widget->id()).arg(widget->typeToString(VCWidget::UnknownWidget))); } else if (apiCmd == "getWidgetStatus") { @@ -635,6 +635,9 @@ void WebAccess::slotHandleWebSocketRequest(QHttpConnection *conn, QString data) VCWidget *widget = m_vc->widget(wID); if (widget != NULL) { + // add widget ID to the response + wsAPIMessage.append(QString("%1|").arg(widget->id())); + switch(widget->type()) { case VCWidget::ButtonWidget: From 46f4109d29f9deeb6c132ad5d8550d4995c0a3aa Mon Sep 17 00:00:00 2001 From: Massimo Callegari Date: Sat, 21 Dec 2024 12:01:28 +0100 Subject: [PATCH 64/68] webaccess: fix usage of widget ID --- webaccess/src/webaccess.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/webaccess/src/webaccess.cpp b/webaccess/src/webaccess.cpp index 60a7db3c99..45466014ca 100644 --- a/webaccess/src/webaccess.cpp +++ b/webaccess/src/webaccess.cpp @@ -622,9 +622,9 @@ void WebAccess::slotHandleWebSocketRequest(QHttpConnection *conn, QString data) quint32 wID = cmdList[2].toUInt(); VCWidget *widget = m_vc->widget(wID); if (widget != NULL) - wsAPIMessage.append(QString("%1|%2").arg(widget->id()).arg(widget->typeToString(widget->type()))); + wsAPIMessage.append(QString("%1|%2").arg(wID).arg(widget->typeToString(widget->type()))); else - wsAPIMessage.append(QString("%1|%2").arg(widget->id()).arg(widget->typeToString(VCWidget::UnknownWidget))); + wsAPIMessage.append(QString("%1|%2").arg(wID).arg(widget->typeToString(VCWidget::UnknownWidget))); } else if (apiCmd == "getWidgetStatus") { @@ -636,7 +636,7 @@ void WebAccess::slotHandleWebSocketRequest(QHttpConnection *conn, QString data) if (widget != NULL) { // add widget ID to the response - wsAPIMessage.append(QString("%1|").arg(widget->id())); + wsAPIMessage.append(QString("%1|").arg(wID)); switch(widget->type()) { From ad4d7c3890ff047bd29f0869b4079f903e829a6f Mon Sep 17 00:00:00 2001 From: Massimo Callegari Date: Sun, 22 Dec 2024 12:24:40 +0100 Subject: [PATCH 65/68] qmlui: improve project loading with Function editor open --- qmlui/app.cpp | 4 +++- qmlui/contextmanager.cpp | 5 ++++- qmlui/functionmanager.cpp | 7 +++++++ qmlui/qml/SidePanel.qml | 1 + qmlui/qml/fixturesfunctions/RightPanel.qml | 19 ++++++++++++++----- 5 files changed, 29 insertions(+), 7 deletions(-) diff --git a/qmlui/app.cpp b/qmlui/app.cpp index daf8b5240c..0c5b046277 100644 --- a/qmlui/app.cpp +++ b/qmlui/app.cpp @@ -602,6 +602,8 @@ bool App::newWorkspace() bool App::loadWorkspace(const QString &fileName) { + m_contextManager->resetContexts(); + /* Clear existing document data */ clearDocument(); m_docLoaded = false; @@ -618,9 +620,9 @@ bool App::loadWorkspace(const QString &fileName) m_docLoaded = true; updateRecentFilesList(localFilename); emit docLoadedChanged(); - m_contextManager->resetContexts(); m_doc->resetModified(); m_videoProvider = new VideoProvider(this, m_doc); + m_contextManager->resetContexts(); // autostart Function if set if (m_doc->startupFunction() != Function::invalidId()) diff --git a/qmlui/contextmanager.cpp b/qmlui/contextmanager.cpp index 73c739beb2..da7b52577f 100644 --- a/qmlui/contextmanager.cpp +++ b/qmlui/contextmanager.cpp @@ -420,10 +420,13 @@ void ContextManager::resetContexts() { m_channelsMap.clear(); resetDumpValues(); + for (quint32 &itemID : m_selectedFixtures) setFixtureSelection(itemID, -1, false); - m_selectedFixtures.clear(); + + m_functionManager->setEditorFunction(-1, true, false); + m_functionManager->selectFunctionID(-1, false); m_editingEnabled = false; emit environmentSizeChanged(); diff --git a/qmlui/functionmanager.cpp b/qmlui/functionmanager.cpp index 5e42bcec0b..c5fedad4c6 100644 --- a/qmlui/functionmanager.cpp +++ b/qmlui/functionmanager.cpp @@ -607,6 +607,13 @@ void FunctionManager::setEditorFunction(quint32 fID, bool requestUI, bool back) if ((int)fID == -1) { emit isEditingChanged(false); + + if (requestUI == true) + { + QQuickItem *rightPanel = qobject_cast(m_view->rootObject()->findChild("funcRightPanel")); + if (rightPanel != nullptr) + QMetaObject::invokeMethod(rightPanel, "requestEditor", Q_ARG(QVariant, -1), Q_ARG(QVariant, 0)); + } return; } diff --git a/qmlui/qml/SidePanel.qml b/qmlui/qml/SidePanel.qml index 84df2897c0..ba415e6d6d 100644 --- a/qmlui/qml/SidePanel.qml +++ b/qmlui/qml/SidePanel.qml @@ -41,6 +41,7 @@ Rectangle function animatePanel(checked) { + console.log("checked=" + checked + ", isOpen=" + isOpen) if (checked === isOpen) return diff --git a/qmlui/qml/fixturesfunctions/RightPanel.qml b/qmlui/qml/fixturesfunctions/RightPanel.qml index 80d76d4080..e295f59da9 100644 --- a/qmlui/qml/fixturesfunctions/RightPanel.qml +++ b/qmlui/qml/fixturesfunctions/RightPanel.qml @@ -86,7 +86,7 @@ SidePanel loaderSource = fEditor animatePanel(true) addFunction.checked = false - funcEditor.checked = true + funcManagerButton.checked = true } } @@ -98,8 +98,17 @@ SidePanel // reset the currently loaded item first loaderSource = "" itemID = funcID - loaderSource = functionManager.getEditorResource(funcID) - animatePanel(true) + + if (funcID === -1) + { + animatePanel(false) + funcManagerButton.checked = false + } + else + { + loaderSource = functionManager.getEditorResource(funcID) + animatePanel(true) + } } onContentLoaded: @@ -139,7 +148,7 @@ SidePanel animatePanel(true) addFunction.checked = false - funcEditor.checked = true + funcManagerButton.checked = true } } @@ -168,7 +177,7 @@ SidePanel IconButton { - id: funcEditor + id: funcManagerButton z: 2 width: iconSize height: iconSize From c014d384613bcefa1ca119ea602149f27308c42d Mon Sep 17 00:00:00 2001 From: Massimo Callegari Date: Sun, 29 Dec 2024 10:46:31 +0100 Subject: [PATCH 66/68] ui: fix 2D fixture monitor settings tab order (fix #1648) --- ui/src/monitor/monitorfixturepropertieseditor.ui | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/ui/src/monitor/monitorfixturepropertieseditor.ui b/ui/src/monitor/monitorfixturepropertieseditor.ui index 53372c0d4d..9514d43255 100644 --- a/ui/src/monitor/monitorfixturepropertieseditor.ui +++ b/ui/src/monitor/monitorfixturepropertieseditor.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. @@ -182,7 +182,6 @@ - 75 true @@ -198,6 +197,13 @@ + + m_xPosSpin + m_yPosSpin + m_rotationSpin + m_gelColorButton + m_gelResetButton + From eff23a3730f0e190c44a8d083c05a3ca9550cfdc Mon Sep 17 00:00:00 2001 From: Massimo Callegari Date: Sun, 29 Dec 2024 11:38:27 +0100 Subject: [PATCH 67/68] ui: update simple desk slider stylesheet on reset via web API (fix #1647) --- ui/src/simpledesk.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/ui/src/simpledesk.cpp b/ui/src/simpledesk.cpp index 1ae447ca25..1994d48ca0 100644 --- a/ui/src/simpledesk.cpp +++ b/ui/src/simpledesk.cpp @@ -410,6 +410,7 @@ void SimpleDesk::setAbsoluteChannelValue(uint address, uchar value) void SimpleDesk::resetChannel(quint32 address) { m_engine->resetChannel(address); + slotUniversePageChanged(m_universePageSpin->value()); } void SimpleDesk::resetUniverse() From 370437d3b806d73b6b37ec52de34bad6f36f3959 Mon Sep 17 00:00:00 2001 From: Massimo Callegari Date: Sun, 29 Dec 2024 13:51:56 +0100 Subject: [PATCH 68/68] ui/simpledesk: improve the previous commit --- ui/src/simpledesk.cpp | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/ui/src/simpledesk.cpp b/ui/src/simpledesk.cpp index 1994d48ca0..adf3c298c8 100644 --- a/ui/src/simpledesk.cpp +++ b/ui/src/simpledesk.cpp @@ -410,7 +410,26 @@ void SimpleDesk::setAbsoluteChannelValue(uint address, uchar value) void SimpleDesk::resetChannel(quint32 address) { m_engine->resetChannel(address); - slotUniversePageChanged(m_universePageSpin->value()); + + quint32 start = (m_universePageSpin->value() - 1) * m_channelsPerPage; + + if (m_viewModeButton->isChecked() == false && + address >= start && address < start + m_channelsPerPage) + { + Fixture *fxi = m_doc->fixture(m_doc->fixtureForAddress(address)); + ConsoleChannel *cc = m_universeSliders[address - start]; + if (fxi == NULL) + { + cc->setChannelStyleSheet(ssNone); + } + else + { + if (fxi->id() % 2) + cc->setChannelStyleSheet(ssEven); + else + cc->setChannelStyleSheet(ssOdd); + } + } } void SimpleDesk::resetUniverse()