From e9da470ccae2a98df2c5d6cf87fdc388ad57c5c5 Mon Sep 17 00:00:00 2001 From: Marcus Birkin Date: Sat, 5 Jun 2021 13:47:27 +0100 Subject: [PATCH] Monitor address has concept of ownership Big display uses new spinbox widget Resolves #241 --- sACNView.pro | 2 + src/sacn/sacnlistener.cpp | 5 +- src/sacn/sacnlistener.h | 14 ++- src/ui/bigdisplay.cpp | 169 ++++++++------------------------- src/ui/bigdisplay.h | 18 +--- src/ui/scopewindow.cpp | 6 +- src/widgets/monitorspinbox.cpp | 92 ++++++++++++++++++ src/widgets/monitorspinbox.h | 43 +++++++++ tools/depot_tools | 2 +- ui/bigdisplay.ui | 21 ++-- 10 files changed, 211 insertions(+), 161 deletions(-) create mode 100644 src/widgets/monitorspinbox.cpp create mode 100644 src/widgets/monitorspinbox.h diff --git a/sACNView.pro b/sACNView.pro index 68f5a72f..52cb097c 100644 --- a/sACNView.pro +++ b/sACNView.pro @@ -89,6 +89,7 @@ INCLUDEPATH += src \ ## Sources SOURCES += src/main.cpp\ + src/widgets/monitorspinbox.cpp \ src/widgets/qspinbox_resizetocontent.cpp \ src/qt56.cpp \ src/ui/newversiondialog.cpp \ @@ -134,6 +135,7 @@ SOURCES += src/main.cpp\ src/widgets/grideditwidget.cpp HEADERS += src/ui/mdimainwindow.h \ + src/widgets/monitorspinbox.h \ src/widgets/qspinbox_resizetocontent.h \ src/ui/newversiondialog.h \ src/ui/scopewindow.h \ diff --git a/src/sacn/sacnlistener.cpp b/src/sacn/sacnlistener.cpp index 631b8a22..3ededfdb 100644 --- a/src/sacn/sacnlistener.cpp +++ b/src/sacn/sacnlistener.cpp @@ -64,7 +64,7 @@ void sACNListener::startReception() if (Preferences::getInstance()->GetNetworkListenAll() & !Preferences::getInstance()->networkInterface().flags().testFlag(QNetworkInterface::IsLoopBack)) { // Listen on ALL interfaces and not working offline - for (auto interface : QNetworkInterface::allInterfaces()) + for (const auto &interface : QNetworkInterface::allInterfaces()) { // If the interface is ok for use... if(Preferences::getInstance()->interfaceSuitable(interface)) @@ -603,7 +603,8 @@ void sACNListener::performMerge() { QMutexLocker locker(&m_monitoredChannelsMutex); - for(auto chan: m_monitoredChannels) + const auto uniqeChannels = m_monitoredChannels.values().toSet(); + for(auto chan: uniqeChannels) { QPointF data; data.setX(m_elapsedTime.nsecsElapsed()/1000000.0); diff --git a/src/sacn/sacnlistener.h b/src/sacn/sacnlistener.h index 0d6714d2..ee17928a 100644 --- a/src/sacn/sacnlistener.h +++ b/src/sacn/sacnlistener.h @@ -96,13 +96,17 @@ class sACNListener : public QObject public slots: void startReception(); - void monitorAddress(int address) { + void monitorAddress(int address, const QObject *owner) { QMutexLocker locker(&m_monitoredChannelsMutex); - m_monitoredChannels.insert(address); + m_monitoredChannels.insert(owner, address); + connect(owner, &QObject::destroyed, this, [this](const QObject *owner) { + QMutexLocker locker(&m_monitoredChannelsMutex); + m_monitoredChannels.remove(owner); + }); } - void unMonitorAddress(int address) { + void unMonitorAddress(int address, const QObject *owner) { QMutexLocker locker(&m_monitoredChannelsMutex); - m_monitoredChannels.remove(address); + m_monitoredChannels.remove(owner, address); } signals: void listenerStarted(int universe); @@ -137,7 +141,7 @@ private slots: QElapsedTimer m_elapsedTime; int m_predictableTimerValue; QMutex m_monitoredChannelsMutex; - QSet m_monitoredChannels; + QMultiMap m_monitoredChannels; bool m_mergeAll; // A flag to initiate a complete remerge of everything unsigned int m_mergesPerSecond = 0; int m_mergeCounter; diff --git a/src/ui/bigdisplay.cpp b/src/ui/bigdisplay.cpp index 67ddb0a8..c85b5f3f 100644 --- a/src/ui/bigdisplay.cpp +++ b/src/ui/bigdisplay.cpp @@ -4,58 +4,37 @@ BigDisplay::BigDisplay(int universe, quint16 address, QWidget *parent) : QWidget(parent), - ui(new Ui::BigDisplay), - m_universe(universe) + ui(new Ui::BigDisplay) { ui->setupUi(this); - // Make address human readable - address++; - // 8bit controls - ui->spinBox_8->setMinimum(MIN_DMX_ADDRESS); - ui->spinBox_8->setMaximum(MAX_DMX_ADDRESS); - ui->spinBox_8->setValue(address); - ui->spinBox_8->setWrapping(true); + ui->spinBox_8->setAddress(universe, address); + connect(ui->spinBox_8, &monitorspinbox::dataReady, this, &BigDisplay::dataReady); // 16bit controls - ui->spinBox_16_Coarse->setMinimum(MIN_DMX_ADDRESS); - ui->spinBox_16_Coarse->setMaximum(MAX_DMX_ADDRESS); - ui->spinBox_16_Coarse->setValue(address); - ui->spinBox_16_Coarse->setWrapping(true); + ui->spinBox_16_Coarse->setAddress(universe, address); + connect(ui->spinBox_16_Coarse, &monitorspinbox::dataReady, this, &BigDisplay::dataReady); //-- - ui->spinBox_16_Fine->setMinimum(MIN_DMX_ADDRESS); - ui->spinBox_16_Fine->setMaximum(MAX_DMX_ADDRESS); - ui->spinBox_16_Fine->setValue(address + 1); - ui->spinBox_16_Fine->setWrapping(true); + ui->spinBox_16_Fine->setAddress(universe, address + 1); + connect(ui->spinBox_16_Fine, &monitorspinbox::dataReady, this, &BigDisplay::dataReady); // Colour controls - ui->spinBox_RGB_1->setMinimum(MIN_DMX_ADDRESS); - ui->spinBox_RGB_1->setMaximum(MAX_DMX_ADDRESS); - ui->spinBox_RGB_1->setValue(address); - ui->spinBox_RGB_1->setWrapping(true); + ui->spinBox_RGB_1->setAddress(universe, address); + connect(ui->spinBox_RGB_1, &monitorspinbox::dataReady, this, &BigDisplay::dataReady); //-- - ui->spinBox_RGB_2->setMinimum(MIN_DMX_ADDRESS); - ui->spinBox_RGB_2->setMaximum(MAX_DMX_ADDRESS); - ui->spinBox_RGB_2->setValue(address + 1); - ui->spinBox_RGB_2->setWrapping(true); + ui->spinBox_RGB_2->setAddress(universe, address + 1); + connect(ui->spinBox_RGB_2, &monitorspinbox::dataReady, this, &BigDisplay::dataReady); //-- - ui->spinBox_RGB_3->setMinimum(MIN_DMX_ADDRESS); - ui->spinBox_RGB_3->setMaximum(MAX_DMX_ADDRESS); - ui->spinBox_RGB_3->setValue(address + 2); - ui->spinBox_RGB_3->setWrapping(true); + ui->spinBox_RGB_3->setAddress(universe, address + 2); + connect(ui->spinBox_RGB_3, &monitorspinbox::dataReady, this, &BigDisplay::dataReady); // Window - this->setWindowTitle(tr("Big Display Universe %1").arg(m_universe)); + this->setWindowTitle(tr("Big Display Universe %1").arg(universe)); this->setWindowIcon(parent->windowIcon()); - // Listen to universe - m_listener = sACNManager::getInstance()->getListener(m_universe); - connect(m_listener.data(), SIGNAL(dataReady(int, QPointF)), this, SLOT(dataReady(int, QPointF))); - - m_data = 0; - - setupAddressMonitors(); + m_level = 0; + displayLevel(); } BigDisplay::~BigDisplay() @@ -63,22 +42,10 @@ BigDisplay::~BigDisplay() delete ui; } -void BigDisplay::setupAddressMonitors() -{ - m_listener->monitorAddress(ui->spinBox_8->value() - 1); - - m_listener->monitorAddress(ui->spinBox_16_Coarse->value() - 1); - m_listener->monitorAddress(ui->spinBox_16_Fine->value() - 1); - - m_listener->monitorAddress(ui->spinBox_RGB_1->value() - 1); - m_listener->monitorAddress(ui->spinBox_RGB_2->value() - 1); - m_listener->monitorAddress(ui->spinBox_RGB_3->value() - 1); -} - -void BigDisplay::displayData() +void BigDisplay::displayLevel() { QPalette palette = ui->lcdNumber->palette(); - QColor colour(m_data | 0xFF000000); + QColor colour(m_level | 0xFF000000); // Display format if((ui->tabWidget->currentIndex() == tabModes_bit8) | @@ -94,13 +61,13 @@ void BigDisplay::displayData() case Preferences::DECIMAL: { ui->lcdNumber->setMode(QLCDNumber::Dec); - ui->lcdNumber->display((int)m_data); + ui->lcdNumber->display((int)m_level); break; } case Preferences::HEXADECIMAL: { ui->lcdNumber->setMode(QLCDNumber::Hex); - ui->lcdNumber->display((int)m_data); + ui->lcdNumber->display((int)m_level); break; } case Preferences::PERCENT: @@ -109,12 +76,12 @@ void BigDisplay::displayData() // Display percent with an optional fraction if(ui->tabWidget->currentIndex() == tabModes_bit8) { - ui->lcdNumber->display(HTOPT[m_data & 0xFF]); + ui->lcdNumber->display(HTOPT[m_level & 0xFF]); } else { - int percent = HTOPT[(m_data & 0xFF00) >> 8]; - int fraction = m_data & 0xFF; + int percent = HTOPT[(m_level & 0xFF00) >> 8]; + int fraction = m_level & 0xFF; double value = percent + fraction/255.0; ui->lcdNumber->display(value); } @@ -131,100 +98,46 @@ void BigDisplay::displayData() ui->lcdNumber->setPalette(palette); ui->lcdNumber->setDigitCount(6); ui->lcdNumber->setMode(QLCDNumber::Hex); - ui->lcdNumber->display((int)m_data); + ui->lcdNumber->display((int)m_level); } - - - } -void BigDisplay::dataReady(int address, QPointF data) +void BigDisplay::dataReady(int universe, quint16 address, QPointF data) { - bool required = false; - address++; - quint32 value = data.y(); - + Q_UNUSED(universe); + quint8 level = data.y() > 0 ? data.y() : 0; switch (ui->tabWidget->currentIndex()) { case tabModes_bit8: - if (address == ui->spinBox_8->value()) { - required = true; - m_data = data.y(); - } + if (address == ui->spinBox_8->address()) + m_level = level; break; case tabModes_bit16: - if (address == ui->spinBox_16_Coarse->value()) { - required = true; - m_data = (m_data & 0x00FF) | (0xFF00 & (value << 8)); - } + if (address == ui->spinBox_16_Coarse->address()) + m_level = (m_level & 0x00FF) | (0xFF00 & (level << 8)); - if (address == ui->spinBox_16_Fine->value()) { - required = true; - m_data = (m_data & 0xFF00) | (0x00FF & value); - } + if (address == ui->spinBox_16_Fine->address()) + m_level = (m_level & 0xFF00) | (0x00FF & level); break; case tabModes_rgb: - if (address == ui->spinBox_RGB_1->value()) { - required = true; - m_data = (m_data & 0x00FFFFu) | (0xFF0000u & ((quint32)value << 16)); - } + if (address == ui->spinBox_RGB_1->address()) + m_level = (m_level & 0x00FFFFu) | (0xFF0000u & ((quint32)level << 16)); - if (address == ui->spinBox_RGB_2->value()) { - required = true; - m_data = (m_data & 0xFF00FFu) | (0x00FF00u & ((quint32)value << 8)); - } + if (address == ui->spinBox_RGB_2->address()) + m_level = (m_level & 0xFF00FFu) | (0x00FF00u & ((quint32)level << 8)); - if (address == ui->spinBox_RGB_3->value()) { - required = true; - m_data = (m_data & 0xFFFF00u) | (0x0000FFu & value); - } + if (address == ui->spinBox_RGB_3->address()) + m_level = (m_level & 0xFFFF00u) | (0x0000FFu & level); break; default: - m_data = -1; + m_level = -1; break; } - // Unrequired address? - if (!required) - { - m_listener->unMonitorAddress(address); - setupAddressMonitors(); - } - - displayData(); -} - -void BigDisplay::on_spinBox_8_editingFinished() -{ - setupAddressMonitors(); -} - -void BigDisplay::on_spinBox_16_Coarse_editingFinished() -{ - setupAddressMonitors(); -} - -void BigDisplay::on_spinBox_16_Fine_editingFinished() -{ - setupAddressMonitors(); -} - -void BigDisplay::on_spinBox_RGB_1_editingFinished() -{ - setupAddressMonitors(); -} - -void BigDisplay::on_spinBox_RGB_2_editingFinished() -{ - setupAddressMonitors(); -} - -void BigDisplay::on_spinBox_RGB_3_editingFinished() -{ - setupAddressMonitors(); + displayLevel(); } diff --git a/src/ui/bigdisplay.h b/src/ui/bigdisplay.h index ee996859..3137502d 100644 --- a/src/ui/bigdisplay.h +++ b/src/ui/bigdisplay.h @@ -3,7 +3,6 @@ #include #include "consts.h" -#include "sacnlistener.h" namespace Ui { class BigDisplay; @@ -19,8 +18,6 @@ class BigDisplay : public QWidget private: Ui::BigDisplay *ui; - int m_universe; - sACNManager::tListener m_listener; enum tabModes { @@ -29,22 +26,13 @@ class BigDisplay : public QWidget tabModes_rgb }; - void setupAddressMonitors(); - private slots: - void dataReady(int address, QPointF data); - - void on_spinBox_8_editingFinished(); - void on_spinBox_16_Coarse_editingFinished(); - void on_spinBox_16_Fine_editingFinished(); - void on_spinBox_RGB_1_editingFinished(); - void on_spinBox_RGB_2_editingFinished(); - void on_spinBox_RGB_3_editingFinished(); + void dataReady(int universe, quint16 address, QPointF data); private: - void displayData(); + void displayLevel(); - quint32 m_data; + quint32 m_level; }; #endif // BIGDISPLAY_H diff --git a/src/ui/scopewindow.cpp b/src/ui/scopewindow.cpp index d7f7a900..318f8ff3 100644 --- a/src/ui/scopewindow.cpp +++ b/src/ui/scopewindow.cpp @@ -216,9 +216,9 @@ void ScopeWindow::on_tableWidget_itemChanged(QTableWidgetItem * item) listener = m_universes[ch->universe()]; - listener->unMonitorAddress(ch->address()); + listener->unMonitorAddress(ch->address(), this); ch->setAddress(address-1); - listener->monitorAddress(ch->address()); + listener->monitorAddress(ch->address(), this); ch->clear(); } else @@ -245,7 +245,7 @@ void ScopeWindow::on_tableWidget_itemChanged(QTableWidgetItem * item) ch->setUniverse(universe); disconnect(listener.data(), 0, this->ui->widget, 0); connect(listener.data(), SIGNAL(dataReady(int, QPointF)), this->ui->widget, SLOT(dataReady(int, QPointF))); - listener->monitorAddress(ch->address()); + listener->monitorAddress(ch->address(), this); ch->clear(); } else diff --git a/src/widgets/monitorspinbox.cpp b/src/widgets/monitorspinbox.cpp new file mode 100644 index 00000000..2464cf95 --- /dev/null +++ b/src/widgets/monitorspinbox.cpp @@ -0,0 +1,92 @@ +#include "monitorspinbox.h" +#include "consts.h" +#include "sacnlistener.h" +#include + +monitorspinbox::monitorspinbox(QWidget* parent) : QAbstractSpinBox(parent), + m_address(0) +{ + QAbstractSpinBox::setWrapping(true); + + connect( + this->lineEdit(), &QLineEdit::textEdited, + this, [this]() { + QString input = lineEdit()->text(); + int pos = 0; + if (QValidator::Acceptable == validate(input, pos)) + setAddress(addressFromText(input)); + else + lineEdit()->setText(textFromAddress(this->address())); + } + ); + + // Default listener + setupListener(MIN_SACN_UNIVERSE); +} + +void monitorspinbox::setupListener(int universe) { + // New universe? + if (m_listener == Q_NULLPTR || m_listener->universe() != universe) { + m_listener = sACNManager::getInstance()->getListener(universe); + + connect( + m_listener.data(), &sACNListener::dataReady, + this, [this](int address, QPointF data) { + emit dataReady(m_listener->universe(), address, data); + } + ); + } +} + +void monitorspinbox::setAddress(int universe, quint16 address) +{ + if (!validate(address)) + return; + + m_listener->unMonitorAddress(this->address(), this); + + m_address = address; + setupListener(universe); + m_listener->monitorAddress(this->address(), this); + + lineEdit()->setText(textFromAddress(this->address())); +} + +void monitorspinbox::stepBy(int steps) +{ + quint16 newAddress = address() + steps; + + if (steps > 0) + while (QValidator::Invalid == validate(newAddress)) ++newAddress; + else if (steps < 0) + while (QValidator::Invalid == validate(newAddress)) --newAddress; + + setAddress(newAddress); +} + +QValidator::State monitorspinbox::validate(QString &input, int &pos) const { + bool ok; + quint16 value = input.midRef(pos).toUShort(&ok); + if (!ok) + return QValidator::Invalid; + + return validate(value); +} + +QValidator::State monitorspinbox::validate(const quint16 value) const { + if (value > (MAX_DMX_ADDRESS - 1) || value < (MIN_DMX_ADDRESS - 1)) + return QValidator::Invalid; + + return QValidator::Acceptable; +} + +quint16 monitorspinbox::addressFromText(const QString &text) const +{ + return text.toUShort() - 1; +} + +QString monitorspinbox::textFromAddress(quint16 address) const +{ + return QString::number(address + 1); +} + diff --git a/src/widgets/monitorspinbox.h b/src/widgets/monitorspinbox.h new file mode 100644 index 00000000..706feae6 --- /dev/null +++ b/src/widgets/monitorspinbox.h @@ -0,0 +1,43 @@ +#ifndef MONITORSPINBOX_H +#define MONITORSPINBOX_H + +#include +#include "sacnlistener.h" + +class monitorspinbox : public QAbstractSpinBox +{ + Q_OBJECT +public: + monitorspinbox(QWidget* parent = nullptr); + + quint16 address() const { return m_address; } + void setAddress(int universe, quint16 address); + void setAddress(quint16 address) { setAddress(m_listener->universe(), address); } + + int universe() const { return m_listener->universe(); } + + quint8 level() const { + auto level = m_listener->mergedLevels().at(m_address).level; + return level > 0 ? level : 0; + } + +signals: + void dataReady(int universe, quint16 address, QPointF data); + +protected: + void stepBy(int steps); + QAbstractSpinBox::StepEnabled stepEnabled() const {return StepUpEnabled | StepDownEnabled; } + + QValidator::State validate(QString &input, int &pos) const; + QValidator::State validate(const quint16 value) const; + + quint16 addressFromText(const QString &text) const; + QString textFromAddress(quint16 address) const; + +private: + sACNManager::tListener m_listener = Q_NULLPTR; + void setupListener(int universe); + quint16 m_address; +}; + +#endif // MONITORSPINBOX_H diff --git a/tools/depot_tools b/tools/depot_tools index 3253a1de..a5b6b2f8 160000 --- a/tools/depot_tools +++ b/tools/depot_tools @@ -1 +1 @@ -Subproject commit 3253a1deca587cc8dd5d83d790cea8f9654e2c33 +Subproject commit a5b6b2f8b75c5c0a14a074be91c7c32ddd278388 diff --git a/ui/bigdisplay.ui b/ui/bigdisplay.ui index ddc8b6af..c189af3e 100644 --- a/ui/bigdisplay.ui +++ b/ui/bigdisplay.ui @@ -53,7 +53,7 @@ - 2 + 1 @@ -81,7 +81,7 @@ QLayout::SetNoConstraint - + 0 @@ -131,7 +131,7 @@ QLayout::SetNoConstraint - + 0 @@ -173,7 +173,7 @@ QLayout::SetMinimumSize - + 0 @@ -226,7 +226,7 @@ QLayout::SetNoConstraint - + 0 @@ -268,7 +268,7 @@ QLayout::SetNoConstraint - + 0 @@ -310,7 +310,7 @@ QLayout::SetNoConstraint - + 0 @@ -346,6 +346,13 @@ + + + monitorspinbox + QSpinBox +
monitorspinbox.h
+
+