From db575a0cda6d3220362c1de24ed8d380b1e331a9 Mon Sep 17 00:00:00 2001 From: Thomas Achtner Date: Fri, 13 Mar 2015 00:58:48 +0100 Subject: [PATCH 01/25] added empty Softpatch Editor Window --- ui/src/fixturemanager.cpp | 20 +++++++ ui/src/fixturemanager.h | 4 ++ ui/src/softpatcheditor.cpp | 63 +++++++++++++++++++++ ui/src/softpatcheditor.h | 53 ++++++++++++++++++ ui/src/softpatcheditor.ui | 112 +++++++++++++++++++++++++++++++++++++ ui/src/src.pro | 9 ++- 6 files changed, 258 insertions(+), 3 deletions(-) create mode 100644 ui/src/softpatcheditor.cpp create mode 100644 ui/src/softpatcheditor.h create mode 100644 ui/src/softpatcheditor.ui diff --git a/ui/src/fixturemanager.cpp b/ui/src/fixturemanager.cpp index 4504b44e60..68610b6223 100644 --- a/ui/src/fixturemanager.cpp +++ b/ui/src/fixturemanager.cpp @@ -47,6 +47,7 @@ #include "fixturetreewidget.h" #include "channelsselection.h" #include "addchannelsgroup.h" +#include "softpatcheditor.h" #include "fixturemanager.h" #include "fixtureremap.h" #include "mastertimer.h" @@ -100,6 +101,7 @@ FixtureManager::FixtureManager(QWidget* parent, Doc* doc) , m_moveDownAction(NULL) , m_importAction(NULL) , m_exportAction(NULL) + , m_softpatchAction(NULL) , m_groupMenu(NULL) { Q_ASSERT(s_instance == NULL); @@ -403,12 +405,14 @@ void FixtureManager::updateView() m_exportAction->setEnabled(true); m_remapAction->setEnabled(true); m_fadeConfigAction->setEnabled(true); + m_softpatchAction->setEnabled(true); } else { m_exportAction->setEnabled(false); m_fadeConfigAction->setEnabled(false); m_remapAction->setEnabled(false); + m_softpatchAction->setEnabled(false); } m_importAction->setEnabled(true); m_moveUpAction->setEnabled(false); @@ -477,6 +481,7 @@ void FixtureManager::updateChannelsGroupView() m_exportAction->setEnabled(false); m_importAction->setEnabled(false); m_remapAction->setEnabled(false); + m_softpatchAction->setEnabled(false); m_channel_groups_tree->resizeColumnToContents(KColumnName); m_channel_groups_tree->resizeColumnToContents(KColumnChannels); @@ -864,6 +869,11 @@ void FixtureManager::initActions() tr("Remap fixtures..."), this); connect(m_remapAction, SIGNAL(triggered(bool)), this, SLOT(slotRemap())); + + m_softpatchAction = new QAction(QIcon(":/input_output.png"), + tr("Patch Fixture Channels ..."), this); + connect(m_softpatchAction, SIGNAL(triggered(bool)), + this, SLOT(slotSoftpatch())); } void FixtureManager::updateGroupMenu() @@ -913,6 +923,7 @@ void FixtureManager::initToolBar() toolbar->addAction(m_importAction); toolbar->addAction(m_exportAction); toolbar->addAction(m_remapAction); + toolbar->addAction(m_softpatchAction); QToolButton* btn = qobject_cast (toolbar->widgetForAction(m_groupAction)); Q_ASSERT(btn != NULL); @@ -1482,6 +1493,15 @@ void FixtureManager::slotMoveGroupDown() } } +void FixtureManager::slotSoftpatch() +{ + SoftpatchEditor spe(m_doc); + if (spe.exec() == QDialog::Rejected) + return; // User pressed cancel + + updateView(); +} + QString FixtureManager::createDialog(bool import) { QString fileName; diff --git a/ui/src/fixturemanager.h b/ui/src/fixturemanager.h index f65f0349e1..206a0fa62c 100644 --- a/ui/src/fixturemanager.h +++ b/ui/src/fixturemanager.h @@ -199,6 +199,7 @@ private slots: void slotMoveGroupDown(); void slotImport(); void slotExport(); + void slotSoftpatch(); /** Callback for right mouse button clicks over a fixture item */ void slotContextMenuRequested(const QPoint& pos); @@ -219,6 +220,9 @@ private slots: QAction* m_importAction; QAction* m_exportAction; + + QAction* m_softpatchAction; + QMenu* m_groupMenu; }; diff --git a/ui/src/softpatcheditor.cpp b/ui/src/softpatcheditor.cpp new file mode 100644 index 0000000000..6ed851e09f --- /dev/null +++ b/ui/src/softpatcheditor.cpp @@ -0,0 +1,63 @@ +/* + Q Light Controller Plus + channelsselection.cpp + + 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. +*/ + +#include +#include + +#include "softpatcheditor.h" +#include "universe.h" +#include "doc.h" + +#define KColumnName 0 +#define KColumnUniverse 1 +#define KColumnAddressRange 2 +#define KColumnStartAddress 3 + +SoftpatchEditor::SoftpatchEditor(Doc *doc, QWidget *parent) + : QDialog(parent) + , m_doc(doc) +{ + Q_ASSERT(doc != NULL); + + setupUi(this); + + QStringList hdrLabels; + hdrLabels << tr("Name") << tr("Universe") << tr("Address") << tr("New Address"); + m_tree->setHeaderLabels(hdrLabels); +} + +SoftpatchEditor::~SoftpatchEditor() +{ + +} + +void SoftpatchEditor::updateFixturesTree() +{ + +} + +void SoftpatchEditor::slotTestButtonPressed() +{ + +} + +void SoftpatchEditor::accept() +{ + +} diff --git a/ui/src/softpatcheditor.h b/ui/src/softpatcheditor.h new file mode 100644 index 0000000000..b325bc3a58 --- /dev/null +++ b/ui/src/softpatcheditor.h @@ -0,0 +1,53 @@ +/* + Q Light Controller Plus + channelsselection.h + + 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. +*/ + +#ifndef SOFTPATCHEDITOR_H +#define SOFTPATCHEDITOR_H + +#include + +#include "ui_softpatcheditor.h" +#include "scenevalue.h" + +class Doc; + +class SoftpatchEditor: public QDialog, public Ui_SoftpatchEditor +{ + Q_OBJECT + Q_DISABLE_COPY(SoftpatchEditor) + +public: + SoftpatchEditor(Doc* doc, QWidget *parent = 0); + ~SoftpatchEditor(); + +private: + Doc* m_doc; + +protected: + void updateFixturesTree(); + +protected slots: + /** Slot called when Test Button is pressed / released */ + void slotTestButtonPressed(); + + /** Callback for OK button clicks */ + void accept(); +}; + +#endif // SOFTPATCHEDITOR_H diff --git a/ui/src/softpatcheditor.ui b/ui/src/softpatcheditor.ui new file mode 100644 index 0000000000..59d956cd2d --- /dev/null +++ b/ui/src/softpatcheditor.ui @@ -0,0 +1,112 @@ + + + SoftpatchEditor + + + + 0 + 0 + 544 + 505 + + + + Channels selection + + + + :/star.png:/star.png + + + + + + true + + + + Name + + + + + Type + + + + + + + + + + PushButton + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + + + + m_testButton + accepted() + SoftpatchEditor + accept() + + + 248 + 254 + + + 157 + 274 + + + + + m_testButton + rejected() + SoftpatchEditor + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/ui/src/src.pro b/ui/src/src.pro index 372479f209..484b9df8e5 100644 --- a/ui/src/src.pro +++ b/ui/src/src.pro @@ -95,7 +95,8 @@ HEADERS += aboutbox.h \ simpledeskengine.h \ speeddial.h \ speeddialwidget.h \ - universeitemwidget.h + universeitemwidget.h \ + softpatcheditor.h # Monitor headers HEADERS += monitor/monitor.h \ @@ -186,7 +187,8 @@ FORMS += aboutbox.ui \ sceneeditor.ui \ scripteditor.ui \ selectinputchannel.ui \ - showmanager/showeditor.ui + showmanager/showeditor.ui \ + softpatcheditor.ui # Virtual Console Forms FORMS += virtualconsole/addvcbuttonmatrix.ui \ @@ -264,7 +266,8 @@ SOURCES += aboutbox.cpp \ simpledeskengine.cpp \ speeddial.cpp \ speeddialwidget.cpp \ - universeitemwidget.cpp + universeitemwidget.cpp \ + softpatcheditor.cpp # Monitor sources SOURCES += monitor/monitor.cpp \ From a81b4b6eb532cf4151c27b1b7c20b248c91fe10e Mon Sep 17 00:00:00 2001 From: Thomas Achtner Date: Fri, 13 Mar 2015 14:16:06 +0100 Subject: [PATCH 02/25] *Softpatch Dialog (Fixture Tree, change Channels) *implemented fixture tree including SpinButton column for new Addresses *Channels are chanels on accept *bug: still bug in SimpleDesk, not updated correctly (crashing) --- ui/src/fixturemanager.cpp | 3 +- ui/src/softpatcheditor.cpp | 103 ++++++++++++++++++++++++++++++++++--- ui/src/softpatcheditor.h | 13 ++++- ui/src/softpatcheditor.ui | 2 +- 4 files changed, 110 insertions(+), 11 deletions(-) diff --git a/ui/src/fixturemanager.cpp b/ui/src/fixturemanager.cpp index 68610b6223..2f05766842 100644 --- a/ui/src/fixturemanager.cpp +++ b/ui/src/fixturemanager.cpp @@ -1313,6 +1313,7 @@ void FixtureManager::editFixtureProperties() msg.exec(); } } + updateView(); } void FixtureManager::editChannelGroupProperties() @@ -1495,7 +1496,7 @@ void FixtureManager::slotMoveGroupDown() void FixtureManager::slotSoftpatch() { - SoftpatchEditor spe(m_doc); + SoftpatchEditor spe(m_doc, this); if (spe.exec() == QDialog::Rejected) return; // User pressed cancel diff --git a/ui/src/softpatcheditor.cpp b/ui/src/softpatcheditor.cpp index 6ed851e09f..f8d9e66595 100644 --- a/ui/src/softpatcheditor.cpp +++ b/ui/src/softpatcheditor.cpp @@ -19,45 +19,132 @@ #include #include +#include #include "softpatcheditor.h" +#include "fixturemanager.h" #include "universe.h" #include "doc.h" #define KColumnName 0 #define KColumnUniverse 1 -#define KColumnAddressRange 2 -#define KColumnStartAddress 3 +#define KColumnAddress 2 +#define KColumnPatch 3 -SoftpatchEditor::SoftpatchEditor(Doc *doc, QWidget *parent) +SoftpatchEditor::SoftpatchEditor(Doc *doc, FixtureManager *mgr, QWidget *parent) : QDialog(parent) , m_doc(doc) + , m_fixture_manager(mgr) { Q_ASSERT(doc != NULL); setupUi(this); + setWindowTitle(tr("Patch start addresses of Fixtures")); + setWindowIcon(QIcon(":/input_output.png")); + QStringList hdrLabels; hdrLabels << tr("Name") << tr("Universe") << tr("Address") << tr("New Address"); m_tree->setHeaderLabels(hdrLabels); -} -SoftpatchEditor::~SoftpatchEditor() -{ + updateFixturesTree(); + connect(m_testButton, SIGNAL(pressed()), this, SLOT(slotTestButtonPressed())); + connect(m_testButton, SIGNAL(released()), this, SLOT(slotTestButtonPressed())); } +SoftpatchEditor::~SoftpatchEditor() {} + void SoftpatchEditor::updateFixturesTree() { - + m_tree->clear(); + m_tree->setIconSize(QSize(24, 24)); + m_tree->setAllColumnsShowFocus(true); + + foreach(Fixture *fxi, m_doc->fixtures()) + { + QTreeWidgetItem *topItem = NULL; + quint32 uni = fxi->universe(); + for (int i = 0; i < m_tree->topLevelItemCount(); i++) + { + QTreeWidgetItem* tItem = m_tree->topLevelItem(i); + quint32 tUni = tItem->text(KColumnUniverse).toUInt(); + if ((tUni-1) == uni) + { + topItem = tItem; + break; + } + } + // Haven't found this universe node ? Create it. + if (topItem == NULL) + { + topItem = new QTreeWidgetItem(m_tree); + topItem->setText(KColumnName, tr("Universe %1").arg(uni + 1)); + topItem->setText(KColumnUniverse, QString::number(uni + 1)); + topItem->setExpanded(true); + } + QTreeWidgetItem *fItem = new QTreeWidgetItem(topItem); + // Column Name + fItem->setText(KColumnName, fxi->name()); + fItem->setIcon(KColumnName, fxi->getIconFromType(fxi->type())); + fItem->setData(KColumnName, PROP_ID, fxi->id()); + // Column Universe + fItem->setText(KColumnUniverse, QString::number(fxi->universe() + 1)); + // Column Address + QString s; + s.sprintf("%.3d - %.3d", fxi->address() + 1, fxi->address() + fxi->channels()); + fItem->setText(KColumnAddress, s); + fItem->setData(KColumnAddress, PROP_ADDRESS, fxi->address()); + // Column Softpatch + QSpinBox *spin = new QSpinBox(); + spin->setRange(1, 255); + spin->setProperty("treeItem", qVariantFromValue((void *)fItem)); + spin->setValue(fxi->address()+1); + m_tree->setItemWidget(fItem, KColumnPatch ,spin); + connect(spin, SIGNAL(valueChanged(int)), this, SLOT(slotChannelPatched(int))); + } + m_tree->resizeColumnToContents(KColumnName); + m_tree->resizeColumnToContents(KColumnUniverse); + m_tree->resizeColumnToContents(KColumnAddress); + m_tree->resizeColumnToContents(KColumnPatch); } void SoftpatchEditor::slotTestButtonPressed() { + // switches on (pressed) and off (released) channels +} +void SoftpatchEditor::slotChannelPatched(int address) +{ + Q_UNUSED(address); + //spin->setStyleSheet("QWidget {color:red}"); } void SoftpatchEditor::accept() { - + QList unis = m_doc->inputOutputMap()->claimUniverses(); + + for (int t = 0; t < m_tree->topLevelItemCount(); t++) + { + QTreeWidgetItem *uniItem = m_tree->topLevelItem(t); + for (int f = 0; f < uniItem->childCount(); f++) + { + QTreeWidgetItem *fItem = uniItem->child(f); + quint32 fxID = fItem->data(KColumnName, PROP_ID).toUInt(); + QSpinBox *spin = (QSpinBox *)m_tree->itemWidget(fItem, KColumnPatch); + Fixture *fixture = m_doc->fixture(fxID); + if (fixture != NULL) + { + //quint32 universe = fixture->universe(); + //unis[universe]->reset(fixture->address(), fixture->channels()); + m_doc->moveFixture(fixture->id(), spin->value()-1); + //fixture->setUniverse(universe); + fixture->setAddress(spin->value()-1); + emit m_doc->fixtureChanged(fixture->id()); + m_fixture_manager->updateView(); + } + } + } + m_doc->inputOutputMap()->releaseUniverses(true); + QDialog::accept(); } diff --git a/ui/src/softpatcheditor.h b/ui/src/softpatcheditor.h index b325bc3a58..933dc9b3f2 100644 --- a/ui/src/softpatcheditor.h +++ b/ui/src/softpatcheditor.h @@ -26,6 +26,12 @@ #include "scenevalue.h" class Doc; +class FixtureManager; + +#define PROP_ID Qt::UserRole +#define PROP_UNIVERSE Qt::UserRole + 1 +#define PROP_ADDRESS Qt::UserRole + 2 +#define PROP_PATCH Qt::UserRole + 3 class SoftpatchEditor: public QDialog, public Ui_SoftpatchEditor { @@ -33,11 +39,12 @@ class SoftpatchEditor: public QDialog, public Ui_SoftpatchEditor Q_DISABLE_COPY(SoftpatchEditor) public: - SoftpatchEditor(Doc* doc, QWidget *parent = 0); + SoftpatchEditor(Doc* doc, FixtureManager *mgr, QWidget *parent=0); ~SoftpatchEditor(); private: Doc* m_doc; + FixtureManager* m_fixture_manager; protected: void updateFixturesTree(); @@ -46,6 +53,10 @@ protected slots: /** Slot called when Test Button is pressed / released */ void slotTestButtonPressed(); + /** Slot called when channel address is changed */ + /** Used for checks */ + void slotChannelPatched(int); + /** Callback for OK button clicks */ void accept(); }; diff --git a/ui/src/softpatcheditor.ui b/ui/src/softpatcheditor.ui index 59d956cd2d..7fc73fd226 100644 --- a/ui/src/softpatcheditor.ui +++ b/ui/src/softpatcheditor.ui @@ -40,7 +40,7 @@ - PushButton + Test Channel From 5526bcba20ef8e6a37f1f630c57da72c0b48f878 Mon Sep 17 00:00:00 2001 From: Thomas Achtner Date: Sat, 14 Mar 2015 15:30:36 +0100 Subject: [PATCH 03/25] *Softpatcheditor (works only on first universe for now, due bug in simpledesk and consolechannel) *check for overlapping channels added, overlapping channels marked red, Warning Dialog added --- ui/src/softpatcheditor.cpp | 116 +++++++++++++++++++++++++++++++++++-- ui/src/softpatcheditor.h | 4 ++ 2 files changed, 116 insertions(+), 4 deletions(-) diff --git a/ui/src/softpatcheditor.cpp b/ui/src/softpatcheditor.cpp index f8d9e66595..abd46c5f6d 100644 --- a/ui/src/softpatcheditor.cpp +++ b/ui/src/softpatcheditor.cpp @@ -19,6 +19,7 @@ #include #include +#include #include #include "softpatcheditor.h" @@ -83,18 +84,23 @@ void SoftpatchEditor::updateFixturesTree() topItem->setText(KColumnUniverse, QString::number(uni + 1)); topItem->setExpanded(true); } + QTreeWidgetItem *fItem = new QTreeWidgetItem(topItem); + // Column Name fItem->setText(KColumnName, fxi->name()); fItem->setIcon(KColumnName, fxi->getIconFromType(fxi->type())); fItem->setData(KColumnName, PROP_ID, fxi->id()); + // Column Universe fItem->setText(KColumnUniverse, QString::number(fxi->universe() + 1)); + // Column Address QString s; s.sprintf("%.3d - %.3d", fxi->address() + 1, fxi->address() + fxi->channels()); fItem->setText(KColumnAddress, s); fItem->setData(KColumnAddress, PROP_ADDRESS, fxi->address()); + // Column Softpatch QSpinBox *spin = new QSpinBox(); spin->setRange(1, 255); @@ -109,6 +115,19 @@ void SoftpatchEditor::updateFixturesTree() m_tree->resizeColumnToContents(KColumnPatch); } +bool SoftpatchEditor::hasOverlappingChannels() +{ + int count; + + const QList keys = m_overlappingChannels.keys(); + for (int i = 0; i < keys.size(); i++) + { + QList values = m_overlappingChannels.values(keys[i]); + count += values.size(); + } + return count; +} + void SoftpatchEditor::slotTestButtonPressed() { // switches on (pressed) and off (released) channels @@ -116,12 +135,99 @@ void SoftpatchEditor::slotTestButtonPressed() void SoftpatchEditor::slotChannelPatched(int address) { - Q_UNUSED(address); - //spin->setStyleSheet("QWidget {color:red}"); + QSpinBox* senderSpin = qobject_cast(QObject::sender()); + QVariant var = senderSpin->property("treeItem"); + QTreeWidgetItem *item = (QTreeWidgetItem *) var.value(); + quint32 senderFxID = item->data(KColumnName, PROP_ID).toUInt(); + Fixture* senderFxi = m_doc->fixture(senderFxID); + quint32 numChannels = senderFxi->channels(); + + //FIXME: limit to first universe now + if (senderFxi->universe() > 0) + return; + + // search overlapping map for current item and reset it to white + const QList keys = m_overlappingChannels.keys(); + for (int i = 0; i < keys.size(); i++) + { + QList values = m_overlappingChannels.values(keys[i]); + foreach (QTreeWidgetItem* fItem, values) + { + if (fItem == item) + { + // unmark current item and remove it from map + QSpinBox *spin = (QSpinBox *)m_tree->itemWidget(fItem, KColumnPatch); + spin->setStyleSheet("QWidget {background-color:white}"); + m_overlappingChannels.remove(keys[i], fItem); + } + } + } + + // loop through map keys (channels) for single entries and remove them + for (int i = 0; i < keys.size(); i++) + { + QList values = m_overlappingChannels.values(keys[i]); + // leftover single map entries (umark them) + if (values.size() == 1) + { + QTreeWidgetItem *fItem = values.at(0); + QSpinBox *spin = (QSpinBox *)m_tree->itemWidget(fItem, KColumnPatch); + spin->setStyleSheet("QWidget {background-color:white}"); + m_overlappingChannels.remove(keys[i], fItem); + } + } + + // test fixture tree on overlapping channels + for (int t = 0; t < m_tree->topLevelItemCount(); t++) + { + QTreeWidgetItem *uniItem = m_tree->topLevelItem(t); + for (int f = 0; f < uniItem->childCount(); f++) + { + QTreeWidgetItem *fItem = uniItem->child(f); + quint32 fxID = fItem->data(KColumnName, PROP_ID).toUInt(); + Fixture *testFixture = m_doc->fixture(fxID); + if (senderFxID != fxID) + { + quint32 testNumChannels = testFixture->channels(); + QSpinBox *spin = (QSpinBox *)m_tree->itemWidget(fItem, KColumnPatch); + + // check on overlapping channel + quint32 testAddress = spin->value(); + + // check first and last channel of current fixture + if ((quint32(address) >= testAddress && quint32(address) < testAddress + testNumChannels) + || (quint32(address + numChannels -1) >= testAddress && quint32(address + numChannels -1) < testAddress + testNumChannels)) + { + // insert overlapping channels into map + if (!m_overlappingChannels.contains(address, fItem)) + m_overlappingChannels.insertMulti(address, fItem); + if (!m_overlappingChannels.contains(address, item)) + m_overlappingChannels.insertMulti(address, item); + } + } + } + + // all overlapping channels marked red now + QList values = m_overlappingChannels.values(address); + for (int i = 0; i < values.size(); ++i) + { + QTreeWidgetItem *fItem = values.at(i); + QSpinBox *spin = (QSpinBox *)m_tree->itemWidget(fItem, KColumnPatch); + spin->setStyleSheet("QWidget {background-color:red}"); + } + } } void SoftpatchEditor::accept() { + if(hasOverlappingChannels()) + { + QMessageBox msg(QMessageBox::Critical, tr("Error"), + tr("Please solve overlapping channels first"), QMessageBox::Ok); + msg.exec(); + return; + } + QList unis = m_doc->inputOutputMap()->claimUniverses(); for (int t = 0; t < m_tree->topLevelItemCount(); t++) @@ -133,7 +239,9 @@ void SoftpatchEditor::accept() quint32 fxID = fItem->data(KColumnName, PROP_ID).toUInt(); QSpinBox *spin = (QSpinBox *)m_tree->itemWidget(fItem, KColumnPatch); Fixture *fixture = m_doc->fixture(fxID); - if (fixture != NULL) + + //FIXME: limit to first universe for now + if (fixture != NULL && fixture->universe() == 0) { //quint32 universe = fixture->universe(); //unis[universe]->reset(fixture->address(), fixture->channels()); @@ -141,10 +249,10 @@ void SoftpatchEditor::accept() //fixture->setUniverse(universe); fixture->setAddress(spin->value()-1); emit m_doc->fixtureChanged(fixture->id()); - m_fixture_manager->updateView(); } } } + m_fixture_manager->updateView(); m_doc->inputOutputMap()->releaseUniverses(true); QDialog::accept(); } diff --git a/ui/src/softpatcheditor.h b/ui/src/softpatcheditor.h index 933dc9b3f2..ba90cb1ebc 100644 --- a/ui/src/softpatcheditor.h +++ b/ui/src/softpatcheditor.h @@ -45,10 +45,14 @@ class SoftpatchEditor: public QDialog, public Ui_SoftpatchEditor private: Doc* m_doc; FixtureManager* m_fixture_manager; + QMultiMap m_overlappingChannels; protected: void updateFixturesTree(); + /** returns if overlapping channels in current softpatch */ + bool hasOverlappingChannels(); + protected slots: /** Slot called when Test Button is pressed / released */ void slotTestButtonPressed(); From 3150d30789dcda52f7992f4eff69811af42f76ba Mon Sep 17 00:00:00 2001 From: Thomas Achtner Date: Mon, 16 Mar 2015 15:37:59 +0100 Subject: [PATCH 04/25] *fix for crashing SimpleDesk crashing, when moving Fixture to different universe with the Fixturemanager (Properties Dialog) --- engine/src/doc.cpp | 26 +++++++++++++++++++++----- ui/src/fixturemanager.cpp | 7 ++++++- 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/engine/src/doc.cpp b/engine/src/doc.cpp index a3bd63980b..2231f56bd8 100644 --- a/engine/src/doc.cpp +++ b/engine/src/doc.cpp @@ -662,14 +662,30 @@ int Doc::totalPowerConsumption(int& fuzzy) const } void Doc::slotFixtureChanged(quint32 id) -{ +{ + QTextStream out(stdout); + /* Keep track of fixture addresses */ - Fixture* fxi = fixture(id); - for (uint i = fxi->universeAddress(); i < fxi->universeAddress() + fxi->channels(); i++) + + if (m_fixtures.contains(id) == true) { - m_addresses[i] = id; - } + Fixture* fxi = fixture(id); + + /* cleanup first - search for old entry of this fixture*/ + QMutableHashIterator it(m_addresses); + while (it.hasNext() == true) + { + it.next(); + if (it.value() == id) + it.remove(); + } + /* write new entries */ + for (uint i = fxi->universeAddress(); i < fxi->universeAddress() + fxi->channels(); i++) + { + m_addresses[i] = id; + } + } setModified(); emit fixtureChanged(id); } diff --git a/ui/src/fixturemanager.cpp b/ui/src/fixturemanager.cpp index 2f05766842..0fd2479be8 100644 --- a/ui/src/fixturemanager.cpp +++ b/ui/src/fixturemanager.cpp @@ -1281,7 +1281,12 @@ void FixtureManager::editFixtureProperties() fxi->setUniverse(af.universe()); if (fxi->address() != af.address()) { - m_doc->moveFixture(id, af.address()); + /** BUG: this caused entries on the wrong universe (when universe is changed), + * simpledesk was crashing because of this + * as m_addresses is also handled by slotFixtureChanged() emitted by Fixtures itself + * we dont need moveFixture + */ + //m_doc->moveFixture(id, af.address()); fxi->setAddress(af.address()); } From 40eb3d76ec665d3157c6ad97eab1a76ca3edc6ea Mon Sep 17 00:00:00 2001 From: Thomas Achtner Date: Mon, 16 Mar 2015 15:41:14 +0100 Subject: [PATCH 05/25] cleanup, removed unused QTextStream --- engine/src/doc.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/engine/src/doc.cpp b/engine/src/doc.cpp index 2231f56bd8..145a94d46e 100644 --- a/engine/src/doc.cpp +++ b/engine/src/doc.cpp @@ -663,8 +663,6 @@ int Doc::totalPowerConsumption(int& fuzzy) const void Doc::slotFixtureChanged(quint32 id) { - QTextStream out(stdout); - /* Keep track of fixture addresses */ if (m_fixtures.contains(id) == true) From 6582f32324dc56902a34411aa534502008decea9 Mon Sep 17 00:00:00 2001 From: Thomas Achtner Date: Mon, 16 Mar 2015 17:26:46 +0100 Subject: [PATCH 06/25] softpatch now works in all universes (cross universe patching is not supported - why it should?) --- ui/src/softpatcheditor.cpp | 67 +++++++++++++++++++------------------- 1 file changed, 33 insertions(+), 34 deletions(-) diff --git a/ui/src/softpatcheditor.cpp b/ui/src/softpatcheditor.cpp index abd46c5f6d..f4bb496d2f 100644 --- a/ui/src/softpatcheditor.cpp +++ b/ui/src/softpatcheditor.cpp @@ -22,6 +22,8 @@ #include #include +#include + #include "softpatcheditor.h" #include "fixturemanager.h" #include "universe.h" @@ -54,7 +56,10 @@ SoftpatchEditor::SoftpatchEditor(Doc *doc, FixtureManager *mgr, QWidget *parent) connect(m_testButton, SIGNAL(released()), this, SLOT(slotTestButtonPressed())); } -SoftpatchEditor::~SoftpatchEditor() {} +SoftpatchEditor::~SoftpatchEditor() +{ + m_overlappingChannels.clear(); +} void SoftpatchEditor::updateFixturesTree() { @@ -130,21 +135,19 @@ bool SoftpatchEditor::hasOverlappingChannels() void SoftpatchEditor::slotTestButtonPressed() { - // switches on (pressed) and off (released) channels + // on/off button - on (pressed) and off (released) channels } void SoftpatchEditor::slotChannelPatched(int address) { + QTextStream out(stdout); QSpinBox* senderSpin = qobject_cast(QObject::sender()); QVariant var = senderSpin->property("treeItem"); QTreeWidgetItem *item = (QTreeWidgetItem *) var.value(); quint32 senderFxID = item->data(KColumnName, PROP_ID).toUInt(); Fixture* senderFxi = m_doc->fixture(senderFxID); quint32 numChannels = senderFxi->channels(); - - //FIXME: limit to first universe now - if (senderFxi->universe() > 0) - return; + quint32 uniAddress = address + (senderFxi->universe() << 9); // search overlapping map for current item and reset it to white const QList keys = m_overlappingChannels.keys(); @@ -186,35 +189,35 @@ void SoftpatchEditor::slotChannelPatched(int address) QTreeWidgetItem *fItem = uniItem->child(f); quint32 fxID = fItem->data(KColumnName, PROP_ID).toUInt(); Fixture *testFixture = m_doc->fixture(fxID); + quint32 testUniverse = testFixture->universe(); if (senderFxID != fxID) { quint32 testNumChannels = testFixture->channels(); QSpinBox *spin = (QSpinBox *)m_tree->itemWidget(fItem, KColumnPatch); - // check on overlapping channel - quint32 testAddress = spin->value(); + // check on overlapping channel / based on universe adresses + quint32 testAddress = spin->value() + (testUniverse << 9); // check first and last channel of current fixture - if ((quint32(address) >= testAddress && quint32(address) < testAddress + testNumChannels) - || (quint32(address + numChannels -1) >= testAddress && quint32(address + numChannels -1) < testAddress + testNumChannels)) + if ((quint32(uniAddress) >= testAddress && quint32(uniAddress) < testAddress + testNumChannels) + || (quint32(uniAddress + numChannels -1) >= testAddress && quint32(uniAddress + numChannels -1) < testAddress + testNumChannels)) { // insert overlapping channels into map - if (!m_overlappingChannels.contains(address, fItem)) - m_overlappingChannels.insertMulti(address, fItem); - if (!m_overlappingChannels.contains(address, item)) - m_overlappingChannels.insertMulti(address, item); + if (!m_overlappingChannels.contains(uniAddress, fItem)) + m_overlappingChannels.insertMulti(uniAddress, fItem); + if (!m_overlappingChannels.contains(uniAddress, item)) + m_overlappingChannels.insertMulti(uniAddress, item); } } } - - // all overlapping channels marked red now - QList values = m_overlappingChannels.values(address); - for (int i = 0; i < values.size(); ++i) - { - QTreeWidgetItem *fItem = values.at(i); - QSpinBox *spin = (QSpinBox *)m_tree->itemWidget(fItem, KColumnPatch); - spin->setStyleSheet("QWidget {background-color:red}"); - } + } + // all overlapping channels marked red now + QList values = m_overlappingChannels.values(uniAddress); + for (int i = 0; i < values.size(); ++i) + { + QTreeWidgetItem *fItem = values.at(i); + QSpinBox *spin = (QSpinBox *)m_tree->itemWidget(fItem, KColumnPatch); + spin->setStyleSheet("QWidget {background-color:red}"); } } @@ -240,19 +243,15 @@ void SoftpatchEditor::accept() QSpinBox *spin = (QSpinBox *)m_tree->itemWidget(fItem, KColumnPatch); Fixture *fixture = m_doc->fixture(fxID); - //FIXME: limit to first universe for now - if (fixture != NULL && fixture->universe() == 0) - { - //quint32 universe = fixture->universe(); - //unis[universe]->reset(fixture->address(), fixture->channels()); - m_doc->moveFixture(fixture->id(), spin->value()-1); - //fixture->setUniverse(universe); - fixture->setAddress(spin->value()-1); - emit m_doc->fixtureChanged(fixture->id()); - } + // FIXME: slotFixtureChanged seems to produce errors, by cutting one channels + //quint32 universe = fixture->universe(); + //unis[universe]->reset(fixture->address(), fixture->channels()); + //fixture->setUniverse(universe); + fixture->setAddress(spin->value()-1); } } m_fixture_manager->updateView(); - m_doc->inputOutputMap()->releaseUniverses(true); + m_doc->inputOutputMap()->releaseUniverses(); + m_overlappingChannels.clear(); QDialog::accept(); } From a6389ee0a38908761e45c70cc898f50742ad4a8d Mon Sep 17 00:00:00 2001 From: Thomas Achtner Date: Mon, 16 Mar 2015 17:37:19 +0100 Subject: [PATCH 07/25] softpatcheditor FIXME added --- ui/src/softpatcheditor.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ui/src/softpatcheditor.cpp b/ui/src/softpatcheditor.cpp index f4bb496d2f..74ff7b1235 100644 --- a/ui/src/softpatcheditor.cpp +++ b/ui/src/softpatcheditor.cpp @@ -180,6 +180,8 @@ void SoftpatchEditor::slotChannelPatched(int address) } } + //FIXME: working fast on spin boxes, temporarly marked (overlapping) channels are not unmarked + // test fixture tree on overlapping channels for (int t = 0; t < m_tree->topLevelItemCount(); t++) { From e7d7d5d12fd61c4111d136329a9efd2d6a62e2ff Mon Sep 17 00:00:00 2001 From: Thomas Achtner Date: Mon, 16 Mar 2015 17:52:11 +0100 Subject: [PATCH 08/25] fixed overlapping channel test --- ui/src/softpatcheditor.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/ui/src/softpatcheditor.cpp b/ui/src/softpatcheditor.cpp index 74ff7b1235..7b9f9c6ad6 100644 --- a/ui/src/softpatcheditor.cpp +++ b/ui/src/softpatcheditor.cpp @@ -149,6 +149,8 @@ void SoftpatchEditor::slotChannelPatched(int address) quint32 numChannels = senderFxi->channels(); quint32 uniAddress = address + (senderFxi->universe() << 9); + senderSpin->blockSignals(true); + // search overlapping map for current item and reset it to white const QList keys = m_overlappingChannels.keys(); for (int i = 0; i < keys.size(); i++) @@ -180,8 +182,6 @@ void SoftpatchEditor::slotChannelPatched(int address) } } - //FIXME: working fast on spin boxes, temporarly marked (overlapping) channels are not unmarked - // test fixture tree on overlapping channels for (int t = 0; t < m_tree->topLevelItemCount(); t++) { @@ -201,7 +201,7 @@ void SoftpatchEditor::slotChannelPatched(int address) quint32 testAddress = spin->value() + (testUniverse << 9); // check first and last channel of current fixture - if ((quint32(uniAddress) >= testAddress && quint32(uniAddress) < testAddress + testNumChannels) + if ((quint32(uniAddress) >= testAddress && quint32(uniAddress) < testAddress + testNumChannels - 1) || (quint32(uniAddress + numChannels -1) >= testAddress && quint32(uniAddress + numChannels -1) < testAddress + testNumChannels)) { // insert overlapping channels into map @@ -221,6 +221,7 @@ void SoftpatchEditor::slotChannelPatched(int address) QSpinBox *spin = (QSpinBox *)m_tree->itemWidget(fItem, KColumnPatch); spin->setStyleSheet("QWidget {background-color:red}"); } + senderSpin->blockSignals(false); } void SoftpatchEditor::accept() From b825276c6d3c61b9eab1fc7c32e7370623f4cffa Mon Sep 17 00:00:00 2001 From: Thomas Achtner Date: Mon, 16 Mar 2015 20:59:29 +0100 Subject: [PATCH 09/25] added Channel Test Button, "preview" of the patched Channel --- ui/src/softpatcheditor.cpp | 61 +++++++++++++++++++++++++++++++------- ui/src/softpatcheditor.h | 15 ++++++++-- ui/src/softpatcheditor.ui | 8 ++--- 3 files changed, 68 insertions(+), 16 deletions(-) diff --git a/ui/src/softpatcheditor.cpp b/ui/src/softpatcheditor.cpp index 7b9f9c6ad6..2560453a5c 100644 --- a/ui/src/softpatcheditor.cpp +++ b/ui/src/softpatcheditor.cpp @@ -22,8 +22,6 @@ #include #include -#include - #include "softpatcheditor.h" #include "fixturemanager.h" #include "universe.h" @@ -38,9 +36,16 @@ SoftpatchEditor::SoftpatchEditor(Doc *doc, FixtureManager *mgr, QWidget *parent) : QDialog(parent) , m_doc(doc) , m_fixture_manager(mgr) + , runTest(false) + , resetTest(false) + , testUniverse(0) + , testChannel(0) + , testValue(0) { Q_ASSERT(doc != NULL); + m_doc->masterTimer()->registerDMXSource(this, "SoftpatchTest"); + setupUi(this); setWindowTitle(tr("Patch start addresses of Fixtures")); @@ -59,6 +64,9 @@ SoftpatchEditor::SoftpatchEditor(Doc *doc, FixtureManager *mgr, QWidget *parent) SoftpatchEditor::~SoftpatchEditor() { m_overlappingChannels.clear(); + m_mutex.lock(); + m_doc->masterTimer()->unregisterDMXSource(this); + m_mutex.unlock(); } void SoftpatchEditor::updateFixturesTree() @@ -135,13 +143,36 @@ bool SoftpatchEditor::hasOverlappingChannels() void SoftpatchEditor::slotTestButtonPressed() { - // on/off button - on (pressed) and off (released) channels + + if (m_testButton->isDown()) + { + m_mutex.lock(); + QTreeWidgetItem* item = m_tree->currentItem(); + quint32 FxID = item->data(KColumnName, PROP_ID).toUInt(); + Fixture* fxi = m_doc->fixture(FxID); + QSpinBox *spin = (QSpinBox *)m_tree->itemWidget(item, KColumnPatch); + + testChannel = spin->value() - 1; + testUniverse = fxi->universe(); + testValue = uchar(255); + runTest = true; + resetTest = false; + m_mutex.unlock(); + } + else + { + m_mutex.lock(); + testValue = uchar(0); + resetTest = true; + m_mutex.unlock(); + } } void SoftpatchEditor::slotChannelPatched(int address) { - QTextStream out(stdout); QSpinBox* senderSpin = qobject_cast(QObject::sender()); + senderSpin->blockSignals(true); + QVariant var = senderSpin->property("treeItem"); QTreeWidgetItem *item = (QTreeWidgetItem *) var.value(); quint32 senderFxID = item->data(KColumnName, PROP_ID).toUInt(); @@ -149,7 +180,6 @@ void SoftpatchEditor::slotChannelPatched(int address) quint32 numChannels = senderFxi->channels(); quint32 uniAddress = address + (senderFxi->universe() << 9); - senderSpin->blockSignals(true); // search overlapping map for current item and reset it to white const QList keys = m_overlappingChannels.keys(); @@ -245,11 +275,8 @@ void SoftpatchEditor::accept() quint32 fxID = fItem->data(KColumnName, PROP_ID).toUInt(); QSpinBox *spin = (QSpinBox *)m_tree->itemWidget(fItem, KColumnPatch); Fixture *fixture = m_doc->fixture(fxID); - - // FIXME: slotFixtureChanged seems to produce errors, by cutting one channels - //quint32 universe = fixture->universe(); - //unis[universe]->reset(fixture->address(), fixture->channels()); - //fixture->setUniverse(universe); + quint32 universe = fixture->universe(); + fixture->setUniverse(universe); fixture->setAddress(spin->value()-1); } } @@ -258,3 +285,17 @@ void SoftpatchEditor::accept() m_overlappingChannels.clear(); QDialog::accept(); } + +void SoftpatchEditor::writeDMX(MasterTimer* timer, QList ua) +{ + Q_UNUSED(timer); + + m_mutex.lock(); + if (runTest) + { + ua[testUniverse]->write(testChannel, testValue); + if (resetTest) + runTest = false; + } + m_mutex.unlock(); +} diff --git a/ui/src/softpatcheditor.h b/ui/src/softpatcheditor.h index ba90cb1ebc..1e0ef287a8 100644 --- a/ui/src/softpatcheditor.h +++ b/ui/src/softpatcheditor.h @@ -21,9 +21,10 @@ #define SOFTPATCHEDITOR_H #include +#include #include "ui_softpatcheditor.h" -#include "scenevalue.h" +#include "dmxsource.h" class Doc; class FixtureManager; @@ -33,7 +34,7 @@ class FixtureManager; #define PROP_ADDRESS Qt::UserRole + 2 #define PROP_PATCH Qt::UserRole + 3 -class SoftpatchEditor: public QDialog, public Ui_SoftpatchEditor +class SoftpatchEditor: public QDialog, public Ui_SoftpatchEditor, public DMXSource { Q_OBJECT Q_DISABLE_COPY(SoftpatchEditor) @@ -42,10 +43,20 @@ class SoftpatchEditor: public QDialog, public Ui_SoftpatchEditor SoftpatchEditor(Doc* doc, FixtureManager *mgr, QWidget *parent=0); ~SoftpatchEditor(); + /** @reimp */ + void writeDMX(MasterTimer* timer, QList ua); + private: Doc* m_doc; FixtureManager* m_fixture_manager; QMultiMap m_overlappingChannels; + QMutex m_mutex; + + bool runTest; + bool resetTest; + quint32 testUniverse; + int testChannel; + uchar testValue; protected: void updateFixturesTree(); diff --git a/ui/src/softpatcheditor.ui b/ui/src/softpatcheditor.ui index 7fc73fd226..3794768aec 100644 --- a/ui/src/softpatcheditor.ui +++ b/ui/src/softpatcheditor.ui @@ -38,7 +38,7 @@ - + Test Channel @@ -60,7 +60,7 @@ - + Qt::Horizontal @@ -77,7 +77,7 @@ - m_testButton + dialog_button accepted() SoftpatchEditor accept() @@ -93,7 +93,7 @@ - m_testButton + dialog_button rejected() SoftpatchEditor reject() From fc2ffe731d36eb0dda1c745ccd8bb8d166d80829 Mon Sep 17 00:00:00 2001 From: Thomas Achtner Date: Sat, 21 Mar 2015 03:03:24 +0100 Subject: [PATCH 10/25] SoftpatchEditor, fixed duplicate Search and View --- ui/src/softpatcheditor.cpp | 133 ++++++++++++++++++++----------------- ui/src/softpatcheditor.h | 31 +++++++-- 2 files changed, 98 insertions(+), 66 deletions(-) diff --git a/ui/src/softpatcheditor.cpp b/ui/src/softpatcheditor.cpp index 2560453a5c..78623613fb 100644 --- a/ui/src/softpatcheditor.cpp +++ b/ui/src/softpatcheditor.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #include "softpatcheditor.h" #include "fixturemanager.h" @@ -63,7 +64,7 @@ SoftpatchEditor::SoftpatchEditor(Doc *doc, FixtureManager *mgr, QWidget *parent) SoftpatchEditor::~SoftpatchEditor() { - m_overlappingChannels.clear(); + m_duplicateChannels.clear(); m_mutex.lock(); m_doc->masterTimer()->unregisterDMXSource(this); m_mutex.unlock(); @@ -120,7 +121,7 @@ void SoftpatchEditor::updateFixturesTree() spin->setProperty("treeItem", qVariantFromValue((void *)fItem)); spin->setValue(fxi->address()+1); m_tree->setItemWidget(fItem, KColumnPatch ,spin); - connect(spin, SIGNAL(valueChanged(int)), this, SLOT(slotChannelPatched(int))); + connect(spin, SIGNAL(valueChanged(int)), this, SLOT(slotChannelPatched())); } m_tree->resizeColumnToContents(KColumnName); m_tree->resizeColumnToContents(KColumnUniverse); @@ -128,14 +129,12 @@ void SoftpatchEditor::updateFixturesTree() m_tree->resizeColumnToContents(KColumnPatch); } -bool SoftpatchEditor::hasOverlappingChannels() +bool SoftpatchEditor::hasDupliateChannels() { int count; - - const QList keys = m_overlappingChannels.keys(); - for (int i = 0; i < keys.size(); i++) + foreach(uint key, m_duplicateChannels.uniqueKeys()) { - QList values = m_overlappingChannels.values(keys[i]); + QList values = m_duplicateChannels.values(key); count += values.size(); } return count; @@ -168,49 +167,78 @@ void SoftpatchEditor::slotTestButtonPressed() } } -void SoftpatchEditor::slotChannelPatched(int address) +void SoftpatchEditor::initChannelSearch(QTreeWidgetItem* item) { - QSpinBox* senderSpin = qobject_cast(QObject::sender()); - senderSpin->blockSignals(true); - - QVariant var = senderSpin->property("treeItem"); - QTreeWidgetItem *item = (QTreeWidgetItem *) var.value(); - quint32 senderFxID = item->data(KColumnName, PROP_ID).toUInt(); - Fixture* senderFxi = m_doc->fixture(senderFxID); - quint32 numChannels = senderFxi->channels(); - quint32 uniAddress = address + (senderFxi->universe() << 9); - - - // search overlapping map for current item and reset it to white - const QList keys = m_overlappingChannels.keys(); - for (int i = 0; i < keys.size(); i++) + // reset prev entry + foreach (const uint &key, m_duplicateChannels.uniqueKeys()) { - QList values = m_overlappingChannels.values(keys[i]); - foreach (QTreeWidgetItem* fItem, values) + foreach (QTreeWidgetItem* pItem, m_duplicateChannels.values(key)) { - if (fItem == item) + if (pItem == item) { - // unmark current item and remove it from map - QSpinBox *spin = (QSpinBox *)m_tree->itemWidget(fItem, KColumnPatch); + QSpinBox *spin = (QSpinBox *)m_tree->itemWidget(pItem, KColumnPatch); spin->setStyleSheet("QWidget {background-color:white}"); - m_overlappingChannels.remove(keys[i], fItem); + m_duplicateChannels.remove(key, pItem); } } } - // loop through map keys (channels) for single entries and remove them - for (int i = 0; i < keys.size(); i++) + // remove single leftover entries + foreach (const uint &key, m_duplicateChannels.uniqueKeys()) { - QList values = m_overlappingChannels.values(keys[i]); - // leftover single map entries (umark them) - if (values.size() == 1) + if (m_duplicateChannels.values(key).size() == 1) { - QTreeWidgetItem *fItem = values.at(0); - QSpinBox *spin = (QSpinBox *)m_tree->itemWidget(fItem, KColumnPatch); + QTreeWidgetItem* mItem = m_duplicateChannels.values(key).at(0); + QSpinBox *spin = (QSpinBox *)m_tree->itemWidget(mItem, KColumnPatch); spin->setStyleSheet("QWidget {background-color:white}"); - m_overlappingChannels.remove(keys[i], fItem); + + m_duplicateChannels.remove(key); + } + } +} + +void SoftpatchEditor::markFixtures() +{ + foreach (const uint &key, m_duplicateChannels.uniqueKeys()) + { + foreach (QTreeWidgetItem* mItem, m_duplicateChannels.values(key)) + { + QSpinBox *spin = (QSpinBox *)m_tree->itemWidget(mItem, KColumnPatch); + spin->setStyleSheet("QWidget {background-color:red}"); } } +} + +QSet SoftpatchEditor::getChannelSet(QTreeWidgetItem* item) +{ + quint32 fxID = item->data(KColumnName, PROP_ID).toUInt(); + Fixture *fxi = m_doc->fixture(fxID); + QSpinBox *spin = (QSpinBox *)m_tree->itemWidget(item, KColumnPatch); + QSet set = QSet(); + for (uint i = 0; i < fxi->channels(); i++) + { + // universe starts with 0 ( channel = spin.value -1 ) + set.insert((spin->value() - 1) + i + (fxi->universe() << 9)); + } + return set; +} + +QSet SoftpatchEditor::duplicateChannelsSet(QTreeWidgetItem* changed, QTreeWidgetItem* other) +{ + QSet set = getChannelSet(changed); + return set.intersect(getChannelSet(other)); +} + +void SoftpatchEditor::slotChannelPatched() +{ + QSpinBox* senderSpin = qobject_cast(QObject::sender()); + senderSpin->blockSignals(true); + + QVariant var = senderSpin->property("treeItem"); + QTreeWidgetItem *item = (QTreeWidgetItem *) var.value(); + quint32 senderFxID = item->data(KColumnName, PROP_ID).toUInt(); + + initChannelSearch(item); // test fixture tree on overlapping channels for (int t = 0; t < m_tree->topLevelItemCount(); t++) @@ -220,43 +248,26 @@ void SoftpatchEditor::slotChannelPatched(int address) { QTreeWidgetItem *fItem = uniItem->child(f); quint32 fxID = fItem->data(KColumnName, PROP_ID).toUInt(); - Fixture *testFixture = m_doc->fixture(fxID); - quint32 testUniverse = testFixture->universe(); if (senderFxID != fxID) { - quint32 testNumChannels = testFixture->channels(); - QSpinBox *spin = (QSpinBox *)m_tree->itemWidget(fItem, KColumnPatch); - - // check on overlapping channel / based on universe adresses - quint32 testAddress = spin->value() + (testUniverse << 9); - - // check first and last channel of current fixture - if ((quint32(uniAddress) >= testAddress && quint32(uniAddress) < testAddress + testNumChannels - 1) - || (quint32(uniAddress + numChannels -1) >= testAddress && quint32(uniAddress + numChannels -1) < testAddress + testNumChannels)) + foreach (quint32 dSet, duplicateChannelsSet(item, fItem)) { // insert overlapping channels into map - if (!m_overlappingChannels.contains(uniAddress, fItem)) - m_overlappingChannels.insertMulti(uniAddress, fItem); - if (!m_overlappingChannels.contains(uniAddress, item)) - m_overlappingChannels.insertMulti(uniAddress, item); + if (!m_duplicateChannels.contains(dSet, fItem)) + m_duplicateChannels.insertMulti(dSet, fItem); + if (!m_duplicateChannels.contains(dSet, item)) + m_duplicateChannels.insertMulti(dSet, item); } } } } - // all overlapping channels marked red now - QList values = m_overlappingChannels.values(uniAddress); - for (int i = 0; i < values.size(); ++i) - { - QTreeWidgetItem *fItem = values.at(i); - QSpinBox *spin = (QSpinBox *)m_tree->itemWidget(fItem, KColumnPatch); - spin->setStyleSheet("QWidget {background-color:red}"); - } + markFixtures(); senderSpin->blockSignals(false); } void SoftpatchEditor::accept() { - if(hasOverlappingChannels()) + if(hasDupliateChannels()) { QMessageBox msg(QMessageBox::Critical, tr("Error"), tr("Please solve overlapping channels first"), QMessageBox::Ok); @@ -282,7 +293,7 @@ void SoftpatchEditor::accept() } m_fixture_manager->updateView(); m_doc->inputOutputMap()->releaseUniverses(); - m_overlappingChannels.clear(); + m_duplicateChannels.clear(); QDialog::accept(); } diff --git a/ui/src/softpatcheditor.h b/ui/src/softpatcheditor.h index 1e0ef287a8..bf24cd6c2f 100644 --- a/ui/src/softpatcheditor.h +++ b/ui/src/softpatcheditor.h @@ -26,6 +26,14 @@ #include "ui_softpatcheditor.h" #include "dmxsource.h" + + +/** + * TODO: + * FIX: use real universeAddreses + * + */ + class Doc; class FixtureManager; @@ -49,7 +57,7 @@ class SoftpatchEditor: public QDialog, public Ui_SoftpatchEditor, public DMXSour private: Doc* m_doc; FixtureManager* m_fixture_manager; - QMultiMap m_overlappingChannels; + QMultiMap m_duplicateChannels; QMutex m_mutex; bool runTest; @@ -62,15 +70,28 @@ class SoftpatchEditor: public QDialog, public Ui_SoftpatchEditor, public DMXSour void updateFixturesTree(); /** returns if overlapping channels in current softpatch */ - bool hasOverlappingChannels(); + bool hasDupliateChannels(); + + /** returns a set containing universe channels a Fixture stored in the TreewidgetItem **/ + QSet getChannelSet(QTreeWidgetItem* item); + void initChannelSearch(QTreeWidgetItem* item); + + /** return a set of duplicate or overlapping channels of two Fixtures stored in the Treewidget **/ + QSet duplicateChannelsSet(QTreeWidgetItem* changed, QTreeWidgetItem* other); + + /** mark all Fixtures containing overlapping channels with others red **/ + void markFixtures(); + protected slots: /** Slot called when Test Button is pressed / released */ void slotTestButtonPressed(); - /** Slot called when channel address is changed */ - /** Used for checks */ - void slotChannelPatched(int); + /** + * Slot called when channel address is changed + * check for channel duplicates + */ + void slotChannelPatched(); /** Callback for OK button clicks */ void accept(); From 2140291b4c198acc4ed66f621ec87b30e7a69b04 Mon Sep 17 00:00:00 2001 From: Thomas Achtner Date: Sat, 21 Mar 2015 03:20:36 +0100 Subject: [PATCH 11/25] SoftpatchEditor: fixed init of count in hasDupliateChannels --- ui/src/softpatcheditor.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/ui/src/softpatcheditor.cpp b/ui/src/softpatcheditor.cpp index 78623613fb..02cdc2e1c2 100644 --- a/ui/src/softpatcheditor.cpp +++ b/ui/src/softpatcheditor.cpp @@ -131,12 +131,13 @@ void SoftpatchEditor::updateFixturesTree() bool SoftpatchEditor::hasDupliateChannels() { - int count; + int count = 0; foreach(uint key, m_duplicateChannels.uniqueKeys()) { QList values = m_duplicateChannels.values(key); count += values.size(); } + QTextStream out(stdout); return count; } @@ -293,7 +294,15 @@ void SoftpatchEditor::accept() } m_fixture_manager->updateView(); m_doc->inputOutputMap()->releaseUniverses(); + m_duplicateChannels.clear(); +// QMap::iterator iter = m_duplicateChannels.begin(); +// while (iter != m_duplicateChannels.end()) +// { +// iter = m_duplicateChannels.erase(iter); +// ++iter; +// } + QDialog::accept(); } From d580ca57190d216fda6db9440993e556a63daed8 Mon Sep 17 00:00:00 2001 From: Thomas Achtner Date: Sat, 21 Mar 2015 19:38:44 +0100 Subject: [PATCH 12/25] Update MonitorFixtures channels and values after Fixture was changed with FixtureManager or SoftpatchEditor --- ui/src/monitor/monitor.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ui/src/monitor/monitor.cpp b/ui/src/monitor/monitor.cpp index 208b83a23e..d1f3e1e71b 100644 --- a/ui/src/monitor/monitor.cpp +++ b/ui/src/monitor/monitor.cpp @@ -587,7 +587,10 @@ void Monitor::slotFixtureChanged(quint32 fxi_id) { MonitorFixture* mof = it.next(); if (mof->fixture() == fxi_id) + { mof->setFixture(fxi_id); + mof->updateLabelStyles(); + } } m_monitorLayout->sort(); From b156c620c5339be032f0687a079b87cd121daa02 Mon Sep 17 00:00:00 2001 From: Thomas Achtner Date: Sun, 22 Mar 2015 20:37:45 +0100 Subject: [PATCH 13/25] Fix for occupied channels in Doc::m_addresses during softpatch --- engine/src/doc.cpp | 93 ++++++++++++++++++++++++-------------- engine/src/doc.h | 11 ++++- ui/src/fixturemanager.cpp | 6 --- ui/src/softpatcheditor.cpp | 16 ++----- 4 files changed, 73 insertions(+), 53 deletions(-) diff --git a/engine/src/doc.cpp b/engine/src/doc.cpp index 145a94d46e..9c89296335 100644 --- a/engine/src/doc.cpp +++ b/engine/src/doc.cpp @@ -365,7 +365,7 @@ bool Doc::addFixture(Fixture* fixture, quint32 id) this, SLOT(slotFixtureChanged(quint32))); /* Keep track of fixture addresses */ - for (uint i = fixture->universeAddress(); + for (quint32 i = fixture->universeAddress(); i < fixture->universeAddress() + fixture->channels(); i++) { m_addresses[i] = id; @@ -437,34 +437,34 @@ bool Doc::deleteFixture(quint32 id) } } -bool Doc::moveFixture(quint32 id, quint32 newAddress) -{ - if (m_fixtures.contains(id) == true) - { - Fixture* fixture = m_fixtures[id]; - // remove it - QMutableHashIterator it(m_addresses); - while (it.hasNext() == true) - { - it.next(); - if (it.value() == id) - it.remove(); - } - // add it to new address - for (uint i = newAddress; i < newAddress + fixture->channels(); i++) - { - m_addresses[i] = id; - } - setModified(); - - return true; - } - else - { - qWarning() << Q_FUNC_INFO << "No fixture with id" << id; - return false; - } -} +//bool Doc::moveFixture(quint32 id, quint32 newAddress) +//{ +// if (m_fixtures.contains(id) == true) +// { +// Fixture* fixture = m_fixtures[id]; +// // remove it +// QMutableHashIterator it(m_addresses); +// while (it.hasNext() == true) +// { +// it.next(); +// if (it.value() == id) +// it.remove(); +// } +// // add it to new address +// for (uint i = newAddress; i < newAddress + fixture->channels(); i++) +// { +// m_addresses[i] = id; +// } +// setModified(); + +// return true; +// } +// else +// { +// qWarning() << Q_FUNC_INFO << "No fixture with id" << id; +// return false; +// } +//} bool Doc::replaceFixtures(QList newFixturesList) { @@ -661,10 +661,28 @@ int Doc::totalPowerConsumption(int& fuzzy) const return totalPowerConsumption; } +void Doc::rebuildAddressMap() +{ + if (mode() == Design) + { + qDebug() << "Doc::rebuildAddressMap"; + m_addresses.clear(); + + QListIterator fxit(m_fixtures.keys()); + while (fxit.hasNext() == true) + { + Fixture* fxi = fixture(fxit.next()); + for (quint32 i = fxi->universeAddress(); i < fxi->universeAddress() + fxi->channels(); i++) + { + m_addresses[i] = fxi->id(); + } + } + } +} + void Doc::slotFixtureChanged(quint32 id) { /* Keep track of fixture addresses */ - if (m_fixtures.contains(id) == true) { Fixture* fxi = fixture(id); @@ -675,17 +693,24 @@ void Doc::slotFixtureChanged(quint32 id) { it.next(); if (it.value() == id) + it.remove(); } /* write new entries */ - for (uint i = fxi->universeAddress(); i < fxi->universeAddress() + fxi->channels(); i++) + for (quint32 i = fxi->universeAddress(); i < fxi->universeAddress() + fxi->channels(); i++) { - m_addresses[i] = id; + if (!m_addresses.contains(id)) + m_addresses[i] = id; + else + rebuildAddressMap(); } + + setModified(); + emit fixtureChanged(id); } - setModified(); - emit fixtureChanged(id); + else + qWarning() << Q_FUNC_INFO << "No fixture with id" << id; } /***************************************************************************** diff --git a/engine/src/doc.h b/engine/src/doc.h index 644005f176..5d6501ceef 100644 --- a/engine/src/doc.h +++ b/engine/src/doc.h @@ -252,7 +252,7 @@ class Doc : public QObject * @param id The ID of the fixture instance to move * @param newAddress the new DMX address where the fixture must take place */ - bool moveFixture(quint32 id, quint32 newAddress); +// bool moveFixture(quint32 id, quint32 newAddress); /** * Replace the whole fixtures list with a new one. @@ -311,6 +311,15 @@ class Doc : public QObject */ int totalPowerConsumption(int& fuzzy) const; +private: + /** + * clears and rebuild m_addresses Map + * after changing channels with softpatch, channels can be lost + * this fixes it in a bruteforce way + * + */ + void rebuildAddressMap(); + protected: /** * Create a new fixture ID diff --git a/ui/src/fixturemanager.cpp b/ui/src/fixturemanager.cpp index 0fd2479be8..3807d7cb68 100644 --- a/ui/src/fixturemanager.cpp +++ b/ui/src/fixturemanager.cpp @@ -1281,12 +1281,6 @@ void FixtureManager::editFixtureProperties() fxi->setUniverse(af.universe()); if (fxi->address() != af.address()) { - /** BUG: this caused entries on the wrong universe (when universe is changed), - * simpledesk was crashing because of this - * as m_addresses is also handled by slotFixtureChanged() emitted by Fixtures itself - * we dont need moveFixture - */ - //m_doc->moveFixture(id, af.address()); fxi->setAddress(af.address()); } diff --git a/ui/src/softpatcheditor.cpp b/ui/src/softpatcheditor.cpp index 02cdc2e1c2..27358bf7ad 100644 --- a/ui/src/softpatcheditor.cpp +++ b/ui/src/softpatcheditor.cpp @@ -21,7 +21,7 @@ #include #include #include -#include +#include #include "softpatcheditor.h" #include "fixturemanager.h" @@ -137,7 +137,6 @@ bool SoftpatchEditor::hasDupliateChannels() QList values = m_duplicateChannels.values(key); count += values.size(); } - QTextStream out(stdout); return count; } @@ -276,7 +275,7 @@ void SoftpatchEditor::accept() return; } - QList unis = m_doc->inputOutputMap()->claimUniverses(); + m_doc->inputOutputMap()->claimUniverses(); for (int t = 0; t < m_tree->topLevelItemCount(); t++) { @@ -287,21 +286,14 @@ void SoftpatchEditor::accept() quint32 fxID = fItem->data(KColumnName, PROP_ID).toUInt(); QSpinBox *spin = (QSpinBox *)m_tree->itemWidget(fItem, KColumnPatch); Fixture *fixture = m_doc->fixture(fxID); - quint32 universe = fixture->universe(); - fixture->setUniverse(universe); - fixture->setAddress(spin->value()-1); + if (fixture->address() != quint32(spin->value()-1)) + fixture->setAddress(spin->value()-1); } } m_fixture_manager->updateView(); m_doc->inputOutputMap()->releaseUniverses(); m_duplicateChannels.clear(); -// QMap::iterator iter = m_duplicateChannels.begin(); -// while (iter != m_duplicateChannels.end()) -// { -// iter = m_duplicateChannels.erase(iter); -// ++iter; -// } QDialog::accept(); } From cebfd70b37b706729742e8e73c2d2df94e4017dc Mon Sep 17 00:00:00 2001 From: Thomas Achtner Date: Sun, 22 Mar 2015 22:28:38 +0100 Subject: [PATCH 14/25] *Test limited to Dimmer only Fixtures *Warning added --- ui/src/softpatcheditor.cpp | 17 ++++++++++------- ui/src/softpatcheditor.ui | 17 +++++++---------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/ui/src/softpatcheditor.cpp b/ui/src/softpatcheditor.cpp index 27358bf7ad..60f15c7b2a 100644 --- a/ui/src/softpatcheditor.cpp +++ b/ui/src/softpatcheditor.cpp @@ -145,18 +145,21 @@ void SoftpatchEditor::slotTestButtonPressed() if (m_testButton->isDown()) { - m_mutex.lock(); QTreeWidgetItem* item = m_tree->currentItem(); quint32 FxID = item->data(KColumnName, PROP_ID).toUInt(); Fixture* fxi = m_doc->fixture(FxID); QSpinBox *spin = (QSpinBox *)m_tree->itemWidget(item, KColumnPatch); - testChannel = spin->value() - 1; - testUniverse = fxi->universe(); - testValue = uchar(255); - runTest = true; - resetTest = false; - m_mutex.unlock(); + if(fxi->isDimmer()) + { + m_mutex.lock(); + testChannel = spin->value() - 1; + testUniverse = fxi->universe(); + testValue = uchar(255); + runTest = true; + resetTest = false; + m_mutex.unlock(); + } } else { diff --git a/ui/src/softpatcheditor.ui b/ui/src/softpatcheditor.ui index 3794768aec..475d46d4dc 100644 --- a/ui/src/softpatcheditor.ui +++ b/ui/src/softpatcheditor.ui @@ -40,22 +40,19 @@ - Test Channel + Test Dimmer - - - Qt::Horizontal + + + - - - 40 - 20 - + + <html><head/><body><p align="justify"><span style=" color:#ff0000;">Test works only for Dimmer Fixtures.<br/>Use with caution, if you changed the Address.<br/>Make sure not to activate your smoke maschine<br/>or your flame jet by accident.</span></p></body></html> - + From e26cba87a2c3c1bdb7a362901384711c232d585e Mon Sep 17 00:00:00 2001 From: Thomas Achtner Date: Thu, 26 Mar 2015 01:45:40 +0100 Subject: [PATCH 15/25] Softpatch now works on universe level, dumpOutput sends patched values instead of GMValues, GMValues stay internal provides: *patch saved in qxw files *reset patch / one to one patch *unpatch channels by assigning channel 0 in SoftpatchEditor Todo: *Gui improvements for patching multiple channels per dimmer *Notification in FixtureManager that Address is patched *Tests --- engine/src/doc.cpp | 36 ++++----- engine/src/doc.h | 16 ++-- engine/src/inputoutputmap.cpp | 4 +- engine/src/universe.cpp | 146 +++++++++++++++++++++++++++++++++- engine/src/universe.h | 97 ++++++++++++++++++++++ ui/src/softpatcheditor.cpp | 69 ++++++++++++++-- ui/src/softpatcheditor.h | 3 + ui/src/softpatcheditor.ui | 7 ++ 8 files changed, 342 insertions(+), 36 deletions(-) diff --git a/engine/src/doc.cpp b/engine/src/doc.cpp index 9c89296335..d249a325e0 100644 --- a/engine/src/doc.cpp +++ b/engine/src/doc.cpp @@ -661,24 +661,24 @@ int Doc::totalPowerConsumption(int& fuzzy) const return totalPowerConsumption; } -void Doc::rebuildAddressMap() -{ - if (mode() == Design) - { - qDebug() << "Doc::rebuildAddressMap"; - m_addresses.clear(); +//void Doc::rebuildAddressMap() +//{ +// if (mode() == Design) +// { +// qDebug() << "Doc::rebuildAddressMap"; +// m_addresses.clear(); - QListIterator fxit(m_fixtures.keys()); - while (fxit.hasNext() == true) - { - Fixture* fxi = fixture(fxit.next()); - for (quint32 i = fxi->universeAddress(); i < fxi->universeAddress() + fxi->channels(); i++) - { - m_addresses[i] = fxi->id(); - } - } - } -} +// QListIterator fxit(m_fixtures.keys()); +// while (fxit.hasNext() == true) +// { +// Fixture* fxi = fixture(fxit.next()); +// for (quint32 i = fxi->universeAddress(); i < fxi->universeAddress() + fxi->channels(); i++) +// { +// m_addresses[i] = fxi->id(); +// } +// } +// } +//} void Doc::slotFixtureChanged(quint32 id) { @@ -703,7 +703,7 @@ void Doc::slotFixtureChanged(quint32 id) if (!m_addresses.contains(id)) m_addresses[i] = id; else - rebuildAddressMap(); + qWarning() << Q_FUNC_INFO << "m_addresses already contains id: " << id; } setModified(); diff --git a/engine/src/doc.h b/engine/src/doc.h index 5d6501ceef..61517c2286 100644 --- a/engine/src/doc.h +++ b/engine/src/doc.h @@ -311,14 +311,14 @@ class Doc : public QObject */ int totalPowerConsumption(int& fuzzy) const; -private: - /** - * clears and rebuild m_addresses Map - * after changing channels with softpatch, channels can be lost - * this fixes it in a bruteforce way - * - */ - void rebuildAddressMap(); +//private: +// /** +// * clears and rebuild m_addresses Map +// * after changing channels with softpatch, channels can be lost +// * this fixes it in a bruteforce way +// * +// */ +// void rebuildAddressMap(); protected: /** diff --git a/engine/src/inputoutputmap.cpp b/engine/src/inputoutputmap.cpp index edb2390035..102408832d 100644 --- a/engine/src/inputoutputmap.cpp +++ b/engine/src/inputoutputmap.cpp @@ -264,8 +264,10 @@ void InputOutputMap::dumpUniverses() locker.relock(); } + const QByteArray patched = universe->patchedValues()->mid(0, universe->usedChannels()); + // this is where QLC+ sends data to the output plugins - universe->dumpOutput(postGM); + universe->dumpOutput(patched); } } } diff --git a/engine/src/universe.cpp b/engine/src/universe.cpp index 95d2f30387..4b4b65e3c3 100644 --- a/engine/src/universe.cpp +++ b/engine/src/universe.cpp @@ -50,10 +50,14 @@ Universe::Universe(quint32 id, GrandMaster *gm, QObject *parent) , m_hasChanged(false) , m_preGMValues(new QByteArray(UNIVERSE_SIZE, char(0))) , m_postGMValues(new QByteArray(UNIVERSE_SIZE, char(0))) + , m_patchedValues(new QByteArray(UNIVERSE_SIZE, char(0))) + , m_patchTable(UNIVERSE_SIZE) { m_relativeValues.fill(0, UNIVERSE_SIZE); m_modifiers.fill(NULL, UNIVERSE_SIZE); + patchOneToOne(); + m_name = QString("Universe %1").arg(id + 1); connect(m_grandMaster, SIGNAL(valueChanged(uchar)), @@ -71,6 +75,8 @@ Universe::~Universe() if (m_fbPatch != NULL) delete m_fbPatch; + patchClear(); + m_inputPatch = NULL; m_outputPatch = NULL; m_fbPatch = NULL; @@ -486,6 +492,93 @@ ChannelModifier *Universe::channelModifier(ushort channel) return m_modifiers.at(channel); } + +/**************************************************************************** + * Softpatch + ****************************************************************************/ + +void Universe::patchClear() +{ + for (uint i = 0; i < UNIVERSE_SIZE; i++) + { + m_patchTable[i].clear(); + } + m_patchHash.clear(); +} + +void Universe::patchDimmer(uint dimmer, uint channel) +{ + if (dimmer < UNIVERSE_SIZE && channel < UNIVERSE_SIZE) + { + qDebug() << Q_FUNC_INFO << " dimmer: " << dimmer << " channel: " << channel << " m_patchHash.contains(channel) = " << m_patchHash.contains(channel); + if (m_patchHash.contains(channel)) + { + unPatchChannel(channel); + } + + if (m_patchTable[dimmer].isEmpty() || !m_patchTable[dimmer].contains(channel)) + { + m_patchHash.insert(channel, dimmer); + m_patchTable[dimmer].append(channel); + qDebug() << Q_FUNC_INFO << " dimmer: " << dimmer << " channel: " << channel; + } + } +} + +void Universe::unPatchChannel(uint channel) +{ + if (channel < UNIVERSE_SIZE) + { + if (m_patchHash.contains(channel)) + { + uint dimmer = m_patchHash[channel]; + if (m_patchTable[dimmer].contains(channel)) + { + int idx = m_patchTable[dimmer].indexOf(channel); + m_patchTable[dimmer].removeAt(idx); + m_patchHash.remove(channel); + qDebug() << Q_FUNC_INFO << " unpatch: " << channel << " from dimmer: " << dimmer; + } + else + qDebug() << Q_FUNC_INFO << " requested channel not found in dimmer"; + } + } +} + +void Universe::patchOneToOne() +{ + resetChanged(); + patchClear(); + for (uint i = 0; i < UNIVERSE_SIZE; i++) + patchDimmer(i, i); +} + +const QList Universe::getPatchedChannels(uint dimmer) const +{ + return m_patchTable[dimmer]; +} + +uint Universe::getPatchedDimmer(uint channel) const +{ + Q_ASSERT(m_patchHash.contains(channel) == true); + return m_patchHash[channel]; +} + +void Universe::applyPatch(uint dimmer, uchar value) +{ + foreach (uint channel, m_patchTable[dimmer]) { + if (channel >= m_usedChannels) + m_usedChannels = channel + 1; + (*m_patchedValues)[channel] = value; + } +} + +const QByteArray* Universe::patchedValues() const +{ + return m_patchedValues; +} + + /**************************************************************************** * Writing ****************************************************************************/ @@ -528,6 +621,8 @@ bool Universe::write(int channel, uchar value, bool forceLTP) value = applyGM(channel, value); (*m_postGMValues)[channel] = char(value); + applyPatch(channel, value); + return true; } @@ -552,6 +647,8 @@ bool Universe::writeRelative(int channel, uchar value) value = applyGM(channel, value); (*m_postGMValues)[channel] = char(value); + applyPatch(channel, value); + m_hasChanged = true; return true; @@ -616,7 +713,35 @@ bool Universe::loadXML(const QDomElement &root, int index, InputOutputMap *ioMap output = tag.attribute(KXMLQLCUniverseFeedbackLine).toUInt(); ioMap->setOutputPatch(index, plugin, output, true); } - + else if (tag.tagName() == KXMLQLCUniversePatch) + { + /* clear Patch */ + patchClear(); + + /* Load Dimmers */ + QDomNode dimmerNode = node.firstChildElement(); + while (dimmerNode.isNull() == false) + { + QDomElement dimmerEl = dimmerNode.toElement(); + + if (dimmerEl.tagName() == KXMLQLCUniversePatchDimmer && dimmerEl.hasAttribute(KXMLQLCUniversePatchChannel)) + { + uint dimmer = dimmerEl.attribute(KXMLQLCUniversePatchChannel).toUInt(); + QString strvals = dimmerEl.text(); + if (strvals.isEmpty() == false) + { + QStringList varray = strvals.split(","); + for (int i = 0; i < varray.count(); i++) + { + uint channel = QString(varray.at(i)).toUInt(); + //unPatchDimmer(id); + patchDimmer(dimmer, channel); + } + } + } + dimmerNode = dimmerNode.nextSibling(); + } + } node = node.nextSibling(); } @@ -663,6 +788,25 @@ bool Universe::saveXML(QDomDocument *doc, QDomElement *wksp_root) const root.appendChild(fbp); } + QDomElement patch = doc->createElement(KXMLQLCUniversePatch); + for (int i = 0; i < UNIVERSE_SIZE; i++ ) { + QDomElement dimmer = doc->createElement(KXMLQLCUniversePatchDimmer); + dimmer.setAttribute(KXMLQLCUniversePatchChannel, i); + QList dim = getPatchedChannels(i); + QListIterator it(dim); + QString dimValues; + while (it.hasNext()) + { + dimValues.append(QString("%1").arg(it.next())); + if(it.hasNext()) + dimValues.append(","); + } + QDomText text = doc->createTextNode(dimValues); + dimmer.appendChild(text); + patch.appendChild(dimmer); + } + root.appendChild(patch); + // append universe element wksp_root->appendChild(root); diff --git a/engine/src/universe.h b/engine/src/universe.h index 340b3e1d42..99f522f97b 100644 --- a/engine/src/universe.h +++ b/engine/src/universe.h @@ -56,6 +56,10 @@ class InputPatch; #define KXMLQLCUniverseFeedbackPlugin "Plugin" #define KXMLQLCUniverseFeedbackLine "Line" +#define KXMLQLCUniversePatch "Patch" +#define KXMLQLCUniversePatchDimmer "Dimmer" +#define KXMLQLCUniversePatchChannel "Channel" + /** Universe class contains input/output data for one DMX universe */ class Universe: public QObject @@ -342,6 +346,99 @@ protected slots: QVector m_relativeValues; + /**************************************************************************** + * Softpatch + ****************************************************************************/ +public: + /** create one to one patch */ + void patchOneToOne(); + + /** empty patch list - full reset*/ + void patchClear(); + + /** + * patch Dimmer to Channel + * + * Dimmer is a single channel used by a QLC+ Fixture + * Channel is the dmx Address, to which the Dimmer channel is patched + * + * Multiple channels can be assigned to one dimmer, but + * channels itself, can be assigned once inside the hole patch. + * + * If we have a Fixture called SimpleDimmer with an startAddress of 10, + * containing 1 channels, we can patch one SimpleDimmer (10) + * to one or more channels (e.g. 21 and 22). + * A Dimmer previously patched to one of that channels, will loose this channel + * in his patch. + * + * SimpleDimmer can be also unpatched, which means it has no channels patched + * and produces no output. + * + * The term Dimmer is used, because we only patch single Channels (aka Dimmers). + * The patch is the done one universe level, which is lowlevel and does not know + * about existence of things like Fixtures. + * On higher level (softpatch editor) a dimmer is analog to an fixture channel. + * If we patch a generic RGB Fixture, we patch three dimmers there. + * + * @param dimmer single address used by a fixture + * @param channel channel to which the output goes + * + */ + void patchDimmer(uint dimmer, uint channel); + + /** + * removes a channels from the patch of the dimmer + * output is blocked on that channel + * + * @param patched channel + * + */ + void unPatchChannel(uint channel); + + /** + * write channel value to m_patchedValues + */ + void applyPatch(uint channel, uchar value); + + /** + * get patched channels + * @param dimmer channel (of a fixture) + * + * @return list of channels patched to the channel + */ + const QList getPatchedChannels(uint dimmer) const; + + /** + * get dimmer from a patched channel + * @param channel patched channel + * + * @return true if successful, otherwise false + */ + uint getPatchedDimmer(uint channel) const; + + /** + * returns array with the patched values + */ + const QByteArray* patchedValues() const; + +private: + + /** Array of values applied by Patch Table*/ + QByteArray* m_patchedValues; + + /** + * Vector containing sets with index numbers of the patch table + * [Dimmer Number [ List (output to:) [ Channel, Channel, ... ] ] + */ + QVector< QList > m_patchTable; + + /** + * key: dimmer + * Set holds back reference of patched channels, + * provides check against multiple entries + */ + QHash m_patchHash; + /************************************************************************ * Writing ************************************************************************/ diff --git a/ui/src/softpatcheditor.cpp b/ui/src/softpatcheditor.cpp index 60f15c7b2a..93ddb59236 100644 --- a/ui/src/softpatcheditor.cpp +++ b/ui/src/softpatcheditor.cpp @@ -60,6 +60,7 @@ SoftpatchEditor::SoftpatchEditor(Doc *doc, FixtureManager *mgr, QWidget *parent) connect(m_testButton, SIGNAL(pressed()), this, SLOT(slotTestButtonPressed())); connect(m_testButton, SIGNAL(released()), this, SLOT(slotTestButtonPressed())); + connect(m_oneToOneButton, SIGNAL(pressed()), this, SLOT(slotOneToOnePressed())); } SoftpatchEditor::~SoftpatchEditor() @@ -116,12 +117,23 @@ void SoftpatchEditor::updateFixturesTree() fItem->setData(KColumnAddress, PROP_ADDRESS, fxi->address()); // Column Softpatch + QList unis = m_doc->inputOutputMap()->claimUniverses(); QSpinBox *spin = new QSpinBox(); - spin->setRange(1, 255); + spin->setRange(0, 512); spin->setProperty("treeItem", qVariantFromValue((void *)fItem)); - spin->setValue(fxi->address()+1); + spin->setStyleSheet("QWidget {background-color:white}"); + const QList channels = unis[fxi->universe()]->getPatchedChannels(fxi->address()); + if(channels.size()) + { + spin->setValue(channels[0] + 1); + } + else + { + spin->setValue(0); + } m_tree->setItemWidget(fItem, KColumnPatch ,spin); connect(spin, SIGNAL(valueChanged(int)), this, SLOT(slotChannelPatched())); + m_doc->inputOutputMap()->releaseUniverses(); } m_tree->resizeColumnToContents(KColumnName); m_tree->resizeColumnToContents(KColumnUniverse); @@ -170,6 +182,17 @@ void SoftpatchEditor::slotTestButtonPressed() } } +void SoftpatchEditor::slotOneToOnePressed() +{ + QList unis = m_doc->inputOutputMap()->claimUniverses(); + foreach (Universe* universe, unis) { + universe->patchOneToOne(); + } + m_doc->inputOutputMap()->releaseUniverses(); + m_duplicateChannels.clear(); + updateFixturesTree(); +} + void SoftpatchEditor::initChannelSearch(QTreeWidgetItem* item) { // reset prev entry @@ -220,8 +243,10 @@ QSet SoftpatchEditor::getChannelSet(QTreeWidgetItem* item) QSet set = QSet(); for (uint i = 0; i < fxi->channels(); i++) { - // universe starts with 0 ( channel = spin.value -1 ) - set.insert((spin->value() - 1) + i + (fxi->universe() << 9)); + // value == 0 means unpatched + if (spin->value() > 0) + // universe starts with 0 ( channel = spin.value -1 ) + set.insert((spin->value() - 1) + i + (fxi->universe() << 9)); } return set; } @@ -278,7 +303,7 @@ void SoftpatchEditor::accept() return; } - m_doc->inputOutputMap()->claimUniverses(); + QList unis = m_doc->inputOutputMap()->claimUniverses(); for (int t = 0; t < m_tree->topLevelItemCount(); t++) { @@ -289,11 +314,39 @@ void SoftpatchEditor::accept() quint32 fxID = fItem->data(KColumnName, PROP_ID).toUInt(); QSpinBox *spin = (QSpinBox *)m_tree->itemWidget(fItem, KColumnPatch); Fixture *fixture = m_doc->fixture(fxID); - if (fixture->address() != quint32(spin->value()-1)) - fixture->setAddress(spin->value()-1); + Universe *universe = unis[fixture->universe()]; + + if (spin->value() > 0) + { + for (uint i = 0; i < fixture->channels(); i++) + { + // gui provides only one channel per dimmer for now, remove old patch + uint dimmer = fixture->address() + i; + QList channels = universe->getPatchedChannels(dimmer); + foreach (uint channel, channels) + universe->unPatchChannel(channel); + + // new patch + uint channel = spin->value()-1 + i; + unis[fixture->universe()]->patchDimmer(dimmer, channel); + } + } + // spin value == 0 is unpatch + else + { + // unpatch each patched channel for each channel in fixture (if Fixture (1,2) is patched to (10,12) and (11,13), unpatch 10,11,12,13) + for (uint i = 0; i < fixture->channels(); i++) + { + // 1. get current patch of the dimmer + uint dimmer = fixture->address() + i; + QList channels = universe->getPatchedChannels(dimmer); + // 2. unpatch each channel found in patch for this dimmer + foreach (uint channel, channels) + universe->unPatchChannel(channel); + } + } } } - m_fixture_manager->updateView(); m_doc->inputOutputMap()->releaseUniverses(); m_duplicateChannels.clear(); diff --git a/ui/src/softpatcheditor.h b/ui/src/softpatcheditor.h index bf24cd6c2f..065e0d6560 100644 --- a/ui/src/softpatcheditor.h +++ b/ui/src/softpatcheditor.h @@ -87,6 +87,9 @@ protected slots: /** Slot called when Test Button is pressed / released */ void slotTestButtonPressed(); + /** Slot called when 1:1 Patch is pressed */ + void slotOneToOnePressed(); + /** * Slot called when channel address is changed * check for channel duplicates diff --git a/ui/src/softpatcheditor.ui b/ui/src/softpatcheditor.ui index 475d46d4dc..3fca2bf47f 100644 --- a/ui/src/softpatcheditor.ui +++ b/ui/src/softpatcheditor.ui @@ -37,6 +37,13 @@ + + + + 1:1 Patch + + + From deae9fe1d42881a4d330bfe015a537c078c8d597 Mon Sep 17 00:00:00 2001 From: Thomas Achtner Date: Sun, 29 Mar 2015 20:44:37 +0200 Subject: [PATCH 16/25] TODO --- engine/src/universe.cpp | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/engine/src/universe.cpp b/engine/src/universe.cpp index 4b4b65e3c3..407a97b693 100644 --- a/engine/src/universe.cpp +++ b/engine/src/universe.cpp @@ -654,6 +654,10 @@ bool Universe::writeRelative(int channel, uchar value) return true; } +/********************************************************************* + * Load & Save + *********************************************************************/ + bool Universe::loadXML(const QDomElement &root, int index, InputOutputMap *ioMap) { if (root.tagName() != KXMLQLCUniverse) @@ -715,6 +719,12 @@ bool Universe::loadXML(const QDomElement &root, int index, InputOutputMap *ioMap } else if (tag.tagName() == KXMLQLCUniversePatch) { + /* + * TODO: load only non one to one dimmers (see save) + * patchOneToOne(); instead patchClear(); + * just patch whats in the file (nothing if it was one to one) + */ + /* clear Patch */ patchClear(); @@ -748,10 +758,6 @@ bool Universe::loadXML(const QDomElement &root, int index, InputOutputMap *ioMap return true; } -/********************************************************************* - * Load & Save - *********************************************************************/ - bool Universe::saveXML(QDomDocument *doc, QDomElement *wksp_root) const { Q_ASSERT(doc != NULL); @@ -793,6 +799,10 @@ bool Universe::saveXML(QDomDocument *doc, QDomElement *wksp_root) const QDomElement dimmer = doc->createElement(KXMLQLCUniversePatchDimmer); dimmer.setAttribute(KXMLQLCUniversePatchChannel, i); QList dim = getPatchedChannels(i); + /* + * TODO: save only non one to one dimmers + * condition: dim.size() == 1 && dim[0] == i + */ QListIterator it(dim); QString dimValues; while (it.hasNext()) From 8593c1d1d492af857d00298d70c6765b05b6f0e8 Mon Sep 17 00:00:00 2001 From: Thomas Achtner Date: Mon, 30 Mar 2015 22:52:54 +0200 Subject: [PATCH 17/25] Softpatch: *implemented patch to multiple channels --- engine/src/universe.cpp | 18 ++++ engine/src/universe.h | 19 ++++ ui/src/softpatcheditor.cpp | 195 ++++++++++++++++++++++++------------- ui/src/softpatcheditor.h | 14 ++- 4 files changed, 175 insertions(+), 71 deletions(-) diff --git a/engine/src/universe.cpp b/engine/src/universe.cpp index 407a97b693..1110dd2e7a 100644 --- a/engine/src/universe.cpp +++ b/engine/src/universe.cpp @@ -508,6 +508,7 @@ void Universe::patchClear() void Universe::patchDimmer(uint dimmer, uint channel) { + qDebug() << Q_FUNC_INFO << " dimmer: " << dimmer << " channel: " << channel ; if (dimmer < UNIVERSE_SIZE && channel < UNIVERSE_SIZE) { qDebug() << Q_FUNC_INFO << " dimmer: " << dimmer << " channel: " << channel << " m_patchHash.contains(channel) = " << m_patchHash.contains(channel); @@ -545,6 +546,23 @@ void Universe::unPatchChannel(uint channel) } } +void Universe::testDimmer(QList channels, bool on) +{ + //qDebug() << Q_FUNC_INFO << " channels: " << channels << " switch: " << on; + foreach (uint channel, channels) { + // check already patched dimmers + if (m_patchHash.contains(channel)) + { + uint tc = getPatchedDimmer(channel); + write(tc, on ? uchar(255) : uchar(0)); + } + // testing on unpatched dimmers ? + else + { + } + } +} + void Universe::patchOneToOne() { resetChanged(); diff --git a/engine/src/universe.h b/engine/src/universe.h index 99f522f97b..d77b8b7aaf 100644 --- a/engine/src/universe.h +++ b/engine/src/universe.h @@ -21,6 +21,15 @@ #ifndef UNIVERSE_H #define UNIVERSE_H + +/** + * TODO: + * Just save patched / unpatched channels (dont save 1to1 channels) + * Test for unpatched Dimmers can not work (maybe tmp patch in softpatch editor, when testing) + * + */ + + #include #include @@ -395,6 +404,16 @@ protected slots: */ void unPatchChannel(uint channel); + + /** + * used for testing Dimmers before doing the patch + * + * @param patched channels + * @param on switches dimmer (on/off) + * + */ + void testDimmer(QList channels, bool on); + /** * write channel value to m_patchedValues */ diff --git a/ui/src/softpatcheditor.cpp b/ui/src/softpatcheditor.cpp index 93ddb59236..c9bfa93982 100644 --- a/ui/src/softpatcheditor.cpp +++ b/ui/src/softpatcheditor.cpp @@ -20,7 +20,7 @@ #include #include #include -#include +#include #include #include "softpatcheditor.h" @@ -40,8 +40,7 @@ SoftpatchEditor::SoftpatchEditor(Doc *doc, FixtureManager *mgr, QWidget *parent) , runTest(false) , resetTest(false) , testUniverse(0) - , testChannel(0) - , testValue(0) + , testSwitch(false) { Q_ASSERT(doc != NULL); @@ -118,21 +117,16 @@ void SoftpatchEditor::updateFixturesTree() // Column Softpatch QList unis = m_doc->inputOutputMap()->claimUniverses(); - QSpinBox *spin = new QSpinBox(); - spin->setRange(0, 512); - spin->setProperty("treeItem", qVariantFromValue((void *)fItem)); - spin->setStyleSheet("QWidget {background-color:white}"); + QLineEdit *ledit = new QLineEdit(); + // TODO + //ledit->setRange(0, 512); + ledit->setProperty("treeItem", qVariantFromValue((void *)fItem)); + ledit->setStyleSheet("QWidget {background-color:white}"); const QList channels = unis[fxi->universe()]->getPatchedChannels(fxi->address()); - if(channels.size()) - { - spin->setValue(channels[0] + 1); - } - else - { - spin->setValue(0); - } - m_tree->setItemWidget(fItem, KColumnPatch ,spin); - connect(spin, SIGNAL(valueChanged(int)), this, SLOT(slotChannelPatched())); + QString tc = channelsToText(channels); + ledit->setText(tc); + m_tree->setItemWidget(fItem, KColumnPatch ,ledit); + connect(ledit, SIGNAL(editingFinished()), this, SLOT(slotChannelPatched())); m_doc->inputOutputMap()->releaseUniverses(); } m_tree->resizeColumnToContents(KColumnName); @@ -160,14 +154,15 @@ void SoftpatchEditor::slotTestButtonPressed() QTreeWidgetItem* item = m_tree->currentItem(); quint32 FxID = item->data(KColumnName, PROP_ID).toUInt(); Fixture* fxi = m_doc->fixture(FxID); - QSpinBox *spin = (QSpinBox *)m_tree->itemWidget(item, KColumnPatch); + QLineEdit *ledit = (QLineEdit *)m_tree->itemWidget(item, KColumnPatch); if(fxi->isDimmer()) { m_mutex.lock(); - testChannel = spin->value() - 1; + foreach (uint ch, textToChannels(ledit->text())) + testChannels.append(ch - 1); testUniverse = fxi->universe(); - testValue = uchar(255); + testSwitch = true; runTest = true; resetTest = false; m_mutex.unlock(); @@ -176,7 +171,7 @@ void SoftpatchEditor::slotTestButtonPressed() else { m_mutex.lock(); - testValue = uchar(0); + testSwitch = false; resetTest = true; m_mutex.unlock(); } @@ -184,13 +179,28 @@ void SoftpatchEditor::slotTestButtonPressed() void SoftpatchEditor::slotOneToOnePressed() { - QList unis = m_doc->inputOutputMap()->claimUniverses(); - foreach (Universe* universe, unis) { - universe->patchOneToOne(); + QMessageBox msg(QMessageBox::Warning, tr("Reset Patch"), + tr("Pressing OK will reset your patch to a one to one patch"), QMessageBox::Ok|QMessageBox::Cancel); + + int ret = msg.exec(); + + switch (ret) { + case QMessageBox::Ok: + { + QList unis = m_doc->inputOutputMap()->claimUniverses(); + foreach (Universe* universe, unis) + universe->patchOneToOne(); + m_doc->inputOutputMap()->releaseUniverses(); + m_duplicateChannels.clear(); + updateFixturesTree(); + break; + } + case QMessageBox::Cancel: + break; + default: + break; } - m_doc->inputOutputMap()->releaseUniverses(); - m_duplicateChannels.clear(); - updateFixturesTree(); + } void SoftpatchEditor::initChannelSearch(QTreeWidgetItem* item) @@ -202,8 +212,8 @@ void SoftpatchEditor::initChannelSearch(QTreeWidgetItem* item) { if (pItem == item) { - QSpinBox *spin = (QSpinBox *)m_tree->itemWidget(pItem, KColumnPatch); - spin->setStyleSheet("QWidget {background-color:white}"); + QLineEdit *ledit = (QLineEdit *)m_tree->itemWidget(pItem, KColumnPatch); + ledit->setStyleSheet("QWidget {background-color:white}"); m_duplicateChannels.remove(key, pItem); } } @@ -215,8 +225,8 @@ void SoftpatchEditor::initChannelSearch(QTreeWidgetItem* item) if (m_duplicateChannels.values(key).size() == 1) { QTreeWidgetItem* mItem = m_duplicateChannels.values(key).at(0); - QSpinBox *spin = (QSpinBox *)m_tree->itemWidget(mItem, KColumnPatch); - spin->setStyleSheet("QWidget {background-color:white}"); + QLineEdit *ledit = (QLineEdit *)m_tree->itemWidget(mItem, KColumnPatch); + ledit->setStyleSheet("QWidget {background-color:white}"); m_duplicateChannels.remove(key); } @@ -229,8 +239,8 @@ void SoftpatchEditor::markFixtures() { foreach (QTreeWidgetItem* mItem, m_duplicateChannels.values(key)) { - QSpinBox *spin = (QSpinBox *)m_tree->itemWidget(mItem, KColumnPatch); - spin->setStyleSheet("QWidget {background-color:red}"); + QLineEdit *ledit = (QLineEdit *)m_tree->itemWidget(mItem, KColumnPatch); + ledit->setStyleSheet("QWidget {background-color:red}"); } } } @@ -239,15 +249,20 @@ QSet SoftpatchEditor::getChannelSet(QTreeWidgetItem* item) { quint32 fxID = item->data(KColumnName, PROP_ID).toUInt(); Fixture *fxi = m_doc->fixture(fxID); - QSpinBox *spin = (QSpinBox *)m_tree->itemWidget(item, KColumnPatch); + QLineEdit *ledit = (QLineEdit *)m_tree->itemWidget(item, KColumnPatch); QSet set = QSet(); - for (uint i = 0; i < fxi->channels(); i++) + + foreach (uint ch, textToChannels(ledit->text())) { - // value == 0 means unpatched - if (spin->value() > 0) - // universe starts with 0 ( channel = spin.value -1 ) - set.insert((spin->value() - 1) + i + (fxi->universe() << 9)); + for (uint i = 0; i < fxi->channels(); i++) + { + // value == 0 means unpatched + if (ch > 0) + // universe starts with 0 ( channel = gui_entry -1 ) + set.insert((ch - 1) + i + (fxi->universe() << 9)); + } } + qDebug() << Q_FUNC_INFO << " Set: " << set; return set; } @@ -259,10 +274,10 @@ QSet SoftpatchEditor::duplicateChannelsSet(QTreeWidgetItem* changed, QT void SoftpatchEditor::slotChannelPatched() { - QSpinBox* senderSpin = qobject_cast(QObject::sender()); - senderSpin->blockSignals(true); + QLineEdit* senderLedit = qobject_cast(QObject::sender()); + senderLedit->blockSignals(true); - QVariant var = senderSpin->property("treeItem"); + QVariant var = senderLedit->property("treeItem"); QTreeWidgetItem *item = (QTreeWidgetItem *) var.value(); quint32 senderFxID = item->data(KColumnName, PROP_ID).toUInt(); @@ -290,7 +305,7 @@ void SoftpatchEditor::slotChannelPatched() } } markFixtures(); - senderSpin->blockSignals(false); + senderLedit->blockSignals(false); } void SoftpatchEditor::accept() @@ -312,37 +327,45 @@ void SoftpatchEditor::accept() { QTreeWidgetItem *fItem = uniItem->child(f); quint32 fxID = fItem->data(KColumnName, PROP_ID).toUInt(); - QSpinBox *spin = (QSpinBox *)m_tree->itemWidget(fItem, KColumnPatch); + QLineEdit *ledit = (QLineEdit *)m_tree->itemWidget(fItem, KColumnPatch); Fixture *fixture = m_doc->fixture(fxID); Universe *universe = unis[fixture->universe()]; - if (spin->value() > 0) + + // remove old patch + for (uint i = 0; i < fixture->channels(); i++) { - for (uint i = 0; i < fixture->channels(); i++) - { - // gui provides only one channel per dimmer for now, remove old patch - uint dimmer = fixture->address() + i; - QList channels = universe->getPatchedChannels(dimmer); - foreach (uint channel, channels) - universe->unPatchChannel(channel); - - // new patch - uint channel = spin->value()-1 + i; - unis[fixture->universe()]->patchDimmer(dimmer, channel); - } + uint dimmer = fixture->address() + i; + QList channels = universe->getPatchedChannels(dimmer); + foreach (uint channel, channels) + universe->unPatchChannel(channel); } - // spin value == 0 is unpatch - else + + foreach (uint ch, textToChannels(ledit->text())) { - // unpatch each patched channel for each channel in fixture (if Fixture (1,2) is patched to (10,12) and (11,13), unpatch 10,11,12,13) - for (uint i = 0; i < fixture->channels(); i++) + if (ch > 0) { - // 1. get current patch of the dimmer - uint dimmer = fixture->address() + i; - QList channels = universe->getPatchedChannels(dimmer); - // 2. unpatch each channel found in patch for this dimmer - foreach (uint channel, channels) - universe->unPatchChannel(channel); + for (uint i = 0; i < fixture->channels(); i++) + { + // new patch + uint dimmer = fixture->address() + i; + uint channel = ch - 1 + i; + unis[fixture->universe()]->patchDimmer(dimmer, channel); + } + } + // ledit value == 0 is unpatch + else + { + // unpatch each patched channel for each channel in fixture (if Fixture (1,2) is patched to (10,12) and (11,13), unpatch 10,11,12,13) + for (uint i = 0; i < fixture->channels(); i++) + { + // 1. get current patch of the dimmer + uint dimmer = fixture->address(); + QList channels = universe->getPatchedChannels(dimmer); + // 2. unpatch each channel found in patch for this dimmer + foreach (uint channel, channels) + universe->unPatchChannel(channel); + } } } } @@ -361,9 +384,45 @@ void SoftpatchEditor::writeDMX(MasterTimer* timer, QList ua) m_mutex.lock(); if (runTest) { - ua[testUniverse]->write(testChannel, testValue); + ua[testUniverse]->testDimmer(testChannels, testSwitch); if (resetTest) + { + testChannels.clear(); runTest = false; + } } m_mutex.unlock(); } + +QList SoftpatchEditor::textToChannels(QString text) +{ + QString s = text.trimmed(); + QStringList slist = s.split(",", QString::SkipEmptyParts); + QList channels; + foreach (QString ch, slist) { + bool ok; + uint v = ch.toUInt(&ok); + if (ok == true && v <= 512) + channels.append(v); + else + { + QMessageBox msg(QMessageBox::Warning, tr("Patch Error"), + tr("separate channels by \",\""), QMessageBox::Ok); + } + } + return channels; +} + +QString SoftpatchEditor::channelsToText(QList channels) +{ + QListIterator it(channels); + QString chanstr; + while (it.hasNext()) + { + chanstr.append(QString("%1").arg(it.next()+1)); + if(it.hasNext()) + chanstr.append(","); + } + + return chanstr; +} diff --git a/ui/src/softpatcheditor.h b/ui/src/softpatcheditor.h index 065e0d6560..0f711834fa 100644 --- a/ui/src/softpatcheditor.h +++ b/ui/src/softpatcheditor.h @@ -30,7 +30,10 @@ /** * TODO: - * FIX: use real universeAddreses + * QLineEdit: limit to Digits and Komma + * small Text howto patch (multiple channels ...) + * dont use channel 0, empty should mean unpatch + * think about reseting universe at a certain point (testDimmer?) * */ @@ -63,8 +66,8 @@ class SoftpatchEditor: public QDialog, public Ui_SoftpatchEditor, public DMXSour bool runTest; bool resetTest; quint32 testUniverse; - int testChannel; - uchar testValue; + QList testChannels; + bool testSwitch; protected: void updateFixturesTree(); @@ -98,6 +101,11 @@ protected slots: /** Callback for OK button clicks */ void accept(); + +private: + /** conversion from QLineEdit String to channels and back */ + QList textToChannels(QString text); + QString channelsToText(QList channels); }; #endif // SOFTPATCHEDITOR_H From af078008d3fecc5df16630cc174e666a13b0b9d5 Mon Sep 17 00:00:00 2001 From: Thomas Achtner Date: Tue, 31 Mar 2015 19:12:18 +0200 Subject: [PATCH 18/25] reset Universe (otherwise channel values will stay after switching to blind mode) --- engine/src/universe.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/engine/src/universe.cpp b/engine/src/universe.cpp index 1110dd2e7a..cffcbc3890 100644 --- a/engine/src/universe.cpp +++ b/engine/src/universe.cpp @@ -227,6 +227,7 @@ void Universe::zeroIntensityChannels() (*m_preGMValues)[channel] = 0; (*m_postGMValues)[channel] = 0; m_relativeValues[channel] = 0; + (*m_patchedValues)[channel] = 0; } } From 51af831bf60dd2557c44c4948d64038397f5a3fb Mon Sep 17 00:00:00 2001 From: Thomas Achtner Date: Tue, 31 Mar 2015 19:46:33 +0200 Subject: [PATCH 19/25] fixed dimmer test --- engine/src/universe.cpp | 31 ++++++++++++++++--------------- engine/src/universe.h | 7 +++++-- 2 files changed, 21 insertions(+), 17 deletions(-) diff --git a/engine/src/universe.cpp b/engine/src/universe.cpp index cffcbc3890..0490ff15e1 100644 --- a/engine/src/universe.cpp +++ b/engine/src/universe.cpp @@ -52,6 +52,7 @@ Universe::Universe(quint32 id, GrandMaster *gm, QObject *parent) , m_postGMValues(new QByteArray(UNIVERSE_SIZE, char(0))) , m_patchedValues(new QByteArray(UNIVERSE_SIZE, char(0))) , m_patchTable(UNIVERSE_SIZE) + , m_testDimmer(false) { m_relativeValues.fill(0, UNIVERSE_SIZE); m_modifiers.fill(NULL, UNIVERSE_SIZE); @@ -549,19 +550,11 @@ void Universe::unPatchChannel(uint channel) void Universe::testDimmer(QList channels, bool on) { - //qDebug() << Q_FUNC_INFO << " channels: " << channels << " switch: " << on; + m_testDimmer = true; foreach (uint channel, channels) { - // check already patched dimmers - if (m_patchHash.contains(channel)) - { - uint tc = getPatchedDimmer(channel); - write(tc, on ? uchar(255) : uchar(0)); - } - // testing on unpatched dimmers ? - else - { - } + write(channel, on ? uchar(255) : uchar(0)); } + m_testDimmer = false; } void Universe::patchOneToOne() @@ -585,10 +578,18 @@ uint Universe::getPatchedDimmer(uint channel) const void Universe::applyPatch(uint dimmer, uchar value) { - foreach (uint channel, m_patchTable[dimmer]) { - if (channel >= m_usedChannels) - m_usedChannels = channel + 1; - (*m_patchedValues)[channel] = value; + if (!m_testDimmer) + { + foreach (uint channel, m_patchTable[dimmer]) { + if (channel >= m_usedChannels) + m_usedChannels = channel + 1; + (*m_patchedValues)[channel] = value; + } + } + else + { + // testDimmer bypasses the patch table + (*m_patchedValues)[dimmer] = value; } } diff --git a/engine/src/universe.h b/engine/src/universe.h index d77b8b7aaf..90df46c8ef 100644 --- a/engine/src/universe.h +++ b/engine/src/universe.h @@ -25,8 +25,6 @@ /** * TODO: * Just save patched / unpatched channels (dont save 1to1 channels) - * Test for unpatched Dimmers can not work (maybe tmp patch in softpatch editor, when testing) - * */ @@ -458,6 +456,11 @@ protected slots: */ QHash m_patchHash; + /** + * indicates dimmer test running + */ + bool m_testDimmer; + /************************************************************************ * Writing ************************************************************************/ From ce158d9dbcc4f310e5ff8c1dc570298024c175e3 Mon Sep 17 00:00:00 2001 From: Thomas Achtner Date: Tue, 31 Mar 2015 21:27:57 +0200 Subject: [PATCH 20/25] proper reset of patchedValues --- engine/src/universe.cpp | 8 ++++++++ engine/src/universe.h | 1 + 2 files changed, 9 insertions(+) diff --git a/engine/src/universe.cpp b/engine/src/universe.cpp index 0490ff15e1..ac493ef9fc 100644 --- a/engine/src/universe.cpp +++ b/engine/src/universe.cpp @@ -69,6 +69,8 @@ Universe::~Universe() { delete m_preGMValues; delete m_postGMValues; + delete m_patchedValues; + patchClear(); if (m_inputPatch != NULL) delete m_inputPatch; if (m_outputPatch != NULL) @@ -204,6 +206,7 @@ void Universe::reset() { m_preGMValues->fill(0); m_postGMValues->fill(0); + m_patchedValues->fill(0); zeroRelativeValues(); m_modifiers.fill(NULL, UNIVERSE_SIZE); m_passthrough = false; @@ -216,6 +219,11 @@ void Universe::reset(int address, int range) (*m_preGMValues)[i] = 0; (*m_postGMValues)[i] = 0; m_relativeValues[i] = 0; + qDebug() << Q_FUNC_INFO << " address: " << i << " patched channels: " << getPatchedChannels(i); + foreach (uint channel, getPatchedChannels(i)) + { + (*m_patchedValues)[channel] = 0; + } } } diff --git a/engine/src/universe.h b/engine/src/universe.h index 90df46c8ef..e8da3f8e82 100644 --- a/engine/src/universe.h +++ b/engine/src/universe.h @@ -25,6 +25,7 @@ /** * TODO: * Just save patched / unpatched channels (dont save 1to1 channels) + * Proper reset of not explicit patched channels in simple desk (channels without fixtures) */ From 597de640e553ad4454a6fb7a1e89ac022fca1ed5 Mon Sep 17 00:00:00 2001 From: Thomas Achtner Date: Tue, 31 Mar 2015 21:28:43 +0200 Subject: [PATCH 21/25] removed one todo --- engine/src/universe.h | 1 - 1 file changed, 1 deletion(-) diff --git a/engine/src/universe.h b/engine/src/universe.h index e8da3f8e82..90df46c8ef 100644 --- a/engine/src/universe.h +++ b/engine/src/universe.h @@ -25,7 +25,6 @@ /** * TODO: * Just save patched / unpatched channels (dont save 1to1 channels) - * Proper reset of not explicit patched channels in simple desk (channels without fixtures) */ From 52e279644ce944e8e8e1dab9dd10fa7dbacd7fa9 Mon Sep 17 00:00:00 2001 From: Thomas Achtner Date: Tue, 31 Mar 2015 22:06:41 +0200 Subject: [PATCH 22/25] SoftpatchEditor: added button to clear patch (for Fixtures, not the hole universe) --- ui/src/softpatcheditor.cpp | 15 +++++++++++++++ ui/src/softpatcheditor.h | 5 +++-- ui/src/softpatcheditor.ui | 38 ++++++++++++++++++++++++++++++++++---- 3 files changed, 52 insertions(+), 6 deletions(-) diff --git a/ui/src/softpatcheditor.cpp b/ui/src/softpatcheditor.cpp index c9bfa93982..4c56a5e29b 100644 --- a/ui/src/softpatcheditor.cpp +++ b/ui/src/softpatcheditor.cpp @@ -60,6 +60,7 @@ SoftpatchEditor::SoftpatchEditor(Doc *doc, FixtureManager *mgr, QWidget *parent) connect(m_testButton, SIGNAL(pressed()), this, SLOT(slotTestButtonPressed())); connect(m_testButton, SIGNAL(released()), this, SLOT(slotTestButtonPressed())); connect(m_oneToOneButton, SIGNAL(pressed()), this, SLOT(slotOneToOnePressed())); + connect(m_clearPatchButton, SIGNAL(pressed()), this, SLOT(slotClearPatch())); } SoftpatchEditor::~SoftpatchEditor() @@ -203,6 +204,20 @@ void SoftpatchEditor::slotOneToOnePressed() } +void SoftpatchEditor::slotClearPatch() +{ + for (int t = 0; t < m_tree->topLevelItemCount(); t++) + { + QTreeWidgetItem *uniItem = m_tree->topLevelItem(t); + for (int f = 0; f < uniItem->childCount(); f++) + { + QTreeWidgetItem *fItem = uniItem->child(f); + QLineEdit *ledit = (QLineEdit *)m_tree->itemWidget(fItem, KColumnPatch); + ledit->clear(); + } + } +} + void SoftpatchEditor::initChannelSearch(QTreeWidgetItem* item) { // reset prev entry diff --git a/ui/src/softpatcheditor.h b/ui/src/softpatcheditor.h index 0f711834fa..edcce38f06 100644 --- a/ui/src/softpatcheditor.h +++ b/ui/src/softpatcheditor.h @@ -31,10 +31,8 @@ /** * TODO: * QLineEdit: limit to Digits and Komma - * small Text howto patch (multiple channels ...) * dont use channel 0, empty should mean unpatch * think about reseting universe at a certain point (testDimmer?) - * */ class Doc; @@ -93,6 +91,9 @@ protected slots: /** Slot called when 1:1 Patch is pressed */ void slotOneToOnePressed(); + /** Slot called when clear patch is pressed */ + void slotClearPatch(); + /** * Slot called when channel address is changed * check for channel duplicates diff --git a/ui/src/softpatcheditor.ui b/ui/src/softpatcheditor.ui index 3fca2bf47f..f20a1ea047 100644 --- a/ui/src/softpatcheditor.ui +++ b/ui/src/softpatcheditor.ui @@ -6,8 +6,8 @@ 0 0 - 544 - 505 + 603 + 513 @@ -18,6 +18,16 @@ :/star.png:/star.png + + + + <html><head/><body><p><span style=" font-weight:600;">Softpatch Editor</span></p><p align="justify">you can patch a Fixture to one or more output channels. Multiple output Channels should be separated by comma. An output channel can be patched only once. If you patch Fixture with channel 1 to 1,2, the Fixture holding channel 2 should be unpatched (booth marked red in this case). You can unpatch a channel by leaving the output channel blank.</p></body></html> + + + true + + + @@ -36,7 +46,10 @@ - + + + QLayout::SetDefaultConstraint + @@ -44,6 +57,17 @@ + + + + ClearPatch + + + + + + + @@ -56,8 +80,14 @@ + + 1 + - <html><head/><body><p align="justify"><span style=" color:#ff0000;">Test works only for Dimmer Fixtures.<br/>Use with caution, if you changed the Address.<br/>Make sure not to activate your smoke maschine<br/>or your flame jet by accident.</span></p></body></html> + <html><head/><body><p align="justify"><span style=" font-size:9pt; color:#ff0000;">Test works only for Dimmer Fixtures. Use with caution, if you changed the Address. Make sure not to activate your smoke maschine or your flame jet by accident.</span></p></body></html> + + + true From 9200a6c38bbddf117dc4f1aa415182e97fd9b8f9 Mon Sep 17 00:00:00 2001 From: Thomas Achtner Date: Wed, 1 Apr 2015 00:44:42 +0200 Subject: [PATCH 23/25] SoftpatchEditor/Universe - commented out some debug statements (too much warnings in tests) --- engine/src/universe.cpp | 6 +++--- ui/src/softpatcheditor.cpp | 1 - 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/engine/src/universe.cpp b/engine/src/universe.cpp index ac493ef9fc..7f55182066 100644 --- a/engine/src/universe.cpp +++ b/engine/src/universe.cpp @@ -518,10 +518,10 @@ void Universe::patchClear() void Universe::patchDimmer(uint dimmer, uint channel) { - qDebug() << Q_FUNC_INFO << " dimmer: " << dimmer << " channel: " << channel ; + //qDebug() << Q_FUNC_INFO << " dimmer: " << dimmer << " channel: " << channel ; if (dimmer < UNIVERSE_SIZE && channel < UNIVERSE_SIZE) { - qDebug() << Q_FUNC_INFO << " dimmer: " << dimmer << " channel: " << channel << " m_patchHash.contains(channel) = " << m_patchHash.contains(channel); + //qDebug() << Q_FUNC_INFO << " dimmer: " << dimmer << " channel: " << channel << " m_patchHash.contains(channel) = " << m_patchHash.contains(channel); if (m_patchHash.contains(channel)) { unPatchChannel(channel); @@ -531,7 +531,7 @@ void Universe::patchDimmer(uint dimmer, uint channel) { m_patchHash.insert(channel, dimmer); m_patchTable[dimmer].append(channel); - qDebug() << Q_FUNC_INFO << " dimmer: " << dimmer << " channel: " << channel; + //qDebug() << Q_FUNC_INFO << " dimmer: " << dimmer << " channel: " << channel; } } } diff --git a/ui/src/softpatcheditor.cpp b/ui/src/softpatcheditor.cpp index 4c56a5e29b..0aabff8f45 100644 --- a/ui/src/softpatcheditor.cpp +++ b/ui/src/softpatcheditor.cpp @@ -277,7 +277,6 @@ QSet SoftpatchEditor::getChannelSet(QTreeWidgetItem* item) set.insert((ch - 1) + i + (fxi->universe() << 9)); } } - qDebug() << Q_FUNC_INFO << " Set: " << set; return set; } From 35d2e1121ea1313e85517142bcfd60feae279a03 Mon Sep 17 00:00:00 2001 From: Thomas Achtner Date: Mon, 6 Apr 2015 15:36:17 +0200 Subject: [PATCH 24/25] reverting changes in fixturemanager (universe change of fixtures fix), done in a separate branch --- engine/src/doc.cpp | 109 ++++++++++++-------------------------- engine/src/doc.h | 2 +- ui/src/fixturemanager.cpp | 2 +- 3 files changed, 37 insertions(+), 76 deletions(-) diff --git a/engine/src/doc.cpp b/engine/src/doc.cpp index d249a325e0..7f87b15142 100644 --- a/engine/src/doc.cpp +++ b/engine/src/doc.cpp @@ -437,34 +437,34 @@ bool Doc::deleteFixture(quint32 id) } } -//bool Doc::moveFixture(quint32 id, quint32 newAddress) -//{ -// if (m_fixtures.contains(id) == true) -// { -// Fixture* fixture = m_fixtures[id]; -// // remove it -// QMutableHashIterator it(m_addresses); -// while (it.hasNext() == true) -// { -// it.next(); -// if (it.value() == id) -// it.remove(); -// } -// // add it to new address -// for (uint i = newAddress; i < newAddress + fixture->channels(); i++) -// { -// m_addresses[i] = id; -// } -// setModified(); - -// return true; -// } -// else -// { -// qWarning() << Q_FUNC_INFO << "No fixture with id" << id; -// return false; -// } -//} +bool Doc::moveFixture(quint32 id, quint32 newAddress) +{ + if (m_fixtures.contains(id) == true) + { + Fixture* fixture = m_fixtures[id]; + // remove it + QMutableHashIterator it(m_addresses); + while (it.hasNext() == true) + { + it.next(); + if (it.value() == id) + it.remove(); + } + // add it to new address + for (uint i = newAddress; i < newAddress + fixture->channels(); i++) + { + m_addresses[i] = id; + } + setModified(); + + return true; + } + else + { + qWarning() << Q_FUNC_INFO << "No fixture with id" << id; + return false; + } +} bool Doc::replaceFixtures(QList newFixturesList) { @@ -661,56 +661,17 @@ int Doc::totalPowerConsumption(int& fuzzy) const return totalPowerConsumption; } -//void Doc::rebuildAddressMap() -//{ -// if (mode() == Design) -// { -// qDebug() << "Doc::rebuildAddressMap"; -// m_addresses.clear(); - -// QListIterator fxit(m_fixtures.keys()); -// while (fxit.hasNext() == true) -// { -// Fixture* fxi = fixture(fxit.next()); -// for (quint32 i = fxi->universeAddress(); i < fxi->universeAddress() + fxi->channels(); i++) -// { -// m_addresses[i] = fxi->id(); -// } -// } -// } -//} - void Doc::slotFixtureChanged(quint32 id) -{ +{ /* Keep track of fixture addresses */ - if (m_fixtures.contains(id) == true) + Fixture* fxi = fixture(id); + for (uint i = fxi->universeAddress(); i < fxi->universeAddress() + fxi->channels(); i++) { - Fixture* fxi = fixture(id); - - /* cleanup first - search for old entry of this fixture*/ - QMutableHashIterator it(m_addresses); - while (it.hasNext() == true) - { - it.next(); - if (it.value() == id) - - it.remove(); - } - - /* write new entries */ - for (quint32 i = fxi->universeAddress(); i < fxi->universeAddress() + fxi->channels(); i++) - { - if (!m_addresses.contains(id)) - m_addresses[i] = id; - else - qWarning() << Q_FUNC_INFO << "m_addresses already contains id: " << id; - } - - setModified(); - emit fixtureChanged(id); + m_addresses[i] = id; } - else - qWarning() << Q_FUNC_INFO << "No fixture with id" << id; + + setModified(); + emit fixtureChanged(id); } /***************************************************************************** diff --git a/engine/src/doc.h b/engine/src/doc.h index 61517c2286..4209a5a5b7 100644 --- a/engine/src/doc.h +++ b/engine/src/doc.h @@ -252,7 +252,7 @@ class Doc : public QObject * @param id The ID of the fixture instance to move * @param newAddress the new DMX address where the fixture must take place */ -// bool moveFixture(quint32 id, quint32 newAddress); + bool moveFixture(quint32 id, quint32 newAddress); /** * Replace the whole fixtures list with a new one. diff --git a/ui/src/fixturemanager.cpp b/ui/src/fixturemanager.cpp index cbef122068..10c639fcd8 100644 --- a/ui/src/fixturemanager.cpp +++ b/ui/src/fixturemanager.cpp @@ -1281,6 +1281,7 @@ void FixtureManager::editFixtureProperties() fxi->setUniverse(af.universe()); if (fxi->address() != af.address()) { + m_doc->moveFixture(id, af.address()); fxi->setAddress(af.address()); } @@ -1312,7 +1313,6 @@ void FixtureManager::editFixtureProperties() msg.exec(); } } - updateView(); } void FixtureManager::editChannelGroupProperties() From 0c99d57721a261ae5dcb3e7c2a4773bc838b0491 Mon Sep 17 00:00:00 2001 From: Thomas Achtner Date: Mon, 6 Apr 2015 15:40:40 +0200 Subject: [PATCH 25/25] cleanup --- engine/src/doc.h | 9 --------- 1 file changed, 9 deletions(-) diff --git a/engine/src/doc.h b/engine/src/doc.h index 4209a5a5b7..644005f176 100644 --- a/engine/src/doc.h +++ b/engine/src/doc.h @@ -311,15 +311,6 @@ class Doc : public QObject */ int totalPowerConsumption(int& fuzzy) const; -//private: -// /** -// * clears and rebuild m_addresses Map -// * after changing channels with softpatch, channels can be lost -// * this fixes it in a bruteforce way -// * -// */ -// void rebuildAddressMap(); - protected: /** * Create a new fixture ID