| 
									
										
										
										
											2022-09-16 10:20:16 +01:00
										 |  |  | ///////////////////////////////////////////////////////////////////////////////////
 | 
					
						
							| 
									
										
										
										
											2023-11-18 13:12:18 +01:00
										 |  |  | // Copyright (C) 2022-2023 Jon Beniston, M7RCE <jon@beniston.com>                //
 | 
					
						
							| 
									
										
										
										
											2022-09-16 10:20:16 +01:00
										 |  |  | //                                                                               //
 | 
					
						
							|  |  |  | // This program is free software; you can redistribute it and/or modify          //
 | 
					
						
							|  |  |  | // it under the terms of the GNU General Public License as published by          //
 | 
					
						
							|  |  |  | // the Free Software Foundation as version 3 of the License, or                  //
 | 
					
						
							|  |  |  | // (at your option) any later version.                                           //
 | 
					
						
							|  |  |  | //                                                                               //
 | 
					
						
							|  |  |  | // This program is distributed in the hope that it will be useful,               //
 | 
					
						
							|  |  |  | // but WITHOUT ANY WARRANTY; without even the implied warranty of                //
 | 
					
						
							|  |  |  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the                  //
 | 
					
						
							|  |  |  | // GNU General Public License V3 for more details.                               //
 | 
					
						
							|  |  |  | //                                                                               //
 | 
					
						
							|  |  |  | // You should have received a copy of the GNU General Public License             //
 | 
					
						
							|  |  |  | // along with this program. If not, see <http://www.gnu.org/licenses/>.          //
 | 
					
						
							|  |  |  | ///////////////////////////////////////////////////////////////////////////////////
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "feature/featureuiset.h"
 | 
					
						
							|  |  |  | #include "gui/basicfeaturesettingsdialog.h"
 | 
					
						
							|  |  |  | #include "gui/flowlayout.h"
 | 
					
						
							|  |  |  | #include "gui/scidoublespinbox.h"
 | 
					
						
							| 
									
										
										
										
											2022-12-20 10:31:15 +00:00
										 |  |  | #include "gui/dialogpositioner.h"
 | 
					
						
							| 
									
										
										
										
											2022-09-16 10:20:16 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | #include "ui_remotecontrolgui.h"
 | 
					
						
							|  |  |  | #include "remotecontrol.h"
 | 
					
						
							|  |  |  | #include "remotecontrolgui.h"
 | 
					
						
							|  |  |  | #include "remotecontrolsettingsdialog.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | RemoteControlGUI* RemoteControlGUI::create(PluginAPI* pluginAPI, FeatureUISet *featureUISet, Feature *feature) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     RemoteControlGUI* gui = new RemoteControlGUI(pluginAPI, featureUISet, feature); | 
					
						
							|  |  |  |     return gui; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void RemoteControlGUI::destroy() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     delete this; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void RemoteControlGUI::resetToDefaults() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     m_settings.resetToDefaults(); | 
					
						
							|  |  |  |     displaySettings(); | 
					
						
							|  |  |  |     applySettings(true); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | QByteArray RemoteControlGUI::serialize() const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return m_settings.serialize(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool RemoteControlGUI::deserialize(const QByteArray& data) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (m_settings.deserialize(data)) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         m_feature->setWorkspaceIndex(m_settings.m_workspaceIndex); | 
					
						
							|  |  |  |         displaySettings(); | 
					
						
							|  |  |  |         applySettings(true); | 
					
						
							|  |  |  |         on_update_clicked(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return true; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         resetToDefaults(); | 
					
						
							|  |  |  |         return false; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool RemoteControlGUI::handleMessage(const Message& message) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (RemoteControl::MsgConfigureRemoteControl::match(message)) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         qDebug("RemoteControlGUI::handleMessage: RemoteControl::MsgConfigureRemoteControl"); | 
					
						
							|  |  |  |         const RemoteControl::MsgConfigureRemoteControl& cfg = (RemoteControl::MsgConfigureRemoteControl&) message; | 
					
						
							|  |  |  |         m_settings = cfg.getSettings(); | 
					
						
							|  |  |  |         blockApplySettings(true); | 
					
						
							|  |  |  |         displaySettings(); | 
					
						
							|  |  |  |         blockApplySettings(false); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return true; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else if (RemoteControl::MsgDeviceStatus::match(message)) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         const RemoteControl::MsgDeviceStatus& msg = (RemoteControl::MsgDeviceStatus&) message; | 
					
						
							|  |  |  |         deviceUpdated(msg.getProtocol(), msg.getDeviceId(), msg.getStatus()); | 
					
						
							|  |  |  |         return true; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else if (RemoteControl::MsgDeviceError::match(message)) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         const RemoteControl::MsgDeviceError& msg = (RemoteControl::MsgDeviceError&) message; | 
					
						
							|  |  |  |         QMessageBox::critical(this,  "Remote Control Error", msg.getErrorMessage()); | 
					
						
							|  |  |  |         return true; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else if (RemoteControl::MsgDeviceUnavailable::match(message)) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         const RemoteControl::MsgDeviceUnavailable& msg = (RemoteControl::MsgDeviceUnavailable&) message; | 
					
						
							|  |  |  |         deviceUnavailable(msg.getProtocol(), msg.getDeviceId()); | 
					
						
							|  |  |  |         return true; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return false; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void RemoteControlGUI::handleInputMessages() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     Message* message; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     while ((message = getInputMessageQueue()->pop())) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         if (handleMessage(*message)) { | 
					
						
							|  |  |  |             delete message; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void RemoteControlGUI::onWidgetRolled(QWidget* widget, bool rollDown) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     (void) widget; | 
					
						
							|  |  |  |     (void) rollDown; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     getRollupContents()->saveState(m_rollupState); | 
					
						
							|  |  |  |     applySettings(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | RemoteControlGUI::RemoteControlGUI(PluginAPI* pluginAPI, FeatureUISet *featureUISet, Feature *feature, QWidget* parent) : | 
					
						
							|  |  |  |     FeatureGUI(parent), | 
					
						
							|  |  |  |     ui(new Ui::RemoteControlGUI), | 
					
						
							|  |  |  |     m_pluginAPI(pluginAPI), | 
					
						
							|  |  |  |     m_featureUISet(featureUISet), | 
					
						
							|  |  |  |     m_doApplySettings(true) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     m_feature = feature; | 
					
						
							|  |  |  |     setAttribute(Qt::WA_DeleteOnClose, true); | 
					
						
							|  |  |  |     m_helpURL = "plugins/feature/remotecontrol/readme.md"; | 
					
						
							|  |  |  |     RollupContents *rollupContents = getRollupContents(); | 
					
						
							|  |  |  | 	ui->setupUi(rollupContents); | 
					
						
							|  |  |  |     rollupContents->arrangeRollups(); | 
					
						
							|  |  |  | 	connect(rollupContents, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     ui->startStop->setStyleSheet("QToolButton { background-color : blue; }" | 
					
						
							|  |  |  |                                  "QToolButton:checked { background-color : green; }" | 
					
						
							|  |  |  |                                  "QToolButton:disabled { background-color : gray; }"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     m_startStopIcon.addFile(":/play.png", QSize(16, 16), QIcon::Normal, QIcon::Off); | 
					
						
							|  |  |  |     m_startStopIcon.addFile(":/stop.png", QSize(16, 16), QIcon::Normal, QIcon::On); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     m_remoteControl = reinterpret_cast<RemoteControl*>(feature); | 
					
						
							|  |  |  |     m_remoteControl->setMessageQueueToGUI(&m_inputMessageQueue); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     m_settings.setRollupState(&m_rollupState); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(onMenuDialogCalled(const QPoint &))); | 
					
						
							|  |  |  |     connect(getInputMessageQueue(), SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages())); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     displaySettings(); | 
					
						
							|  |  |  |     applySettings(true); | 
					
						
							|  |  |  |     makeUIConnections(); | 
					
						
							| 
									
										
										
										
											2023-11-13 20:51:03 +00:00
										 |  |  |     m_resizer.enableChildMouseTracking(); | 
					
						
							| 
									
										
										
										
											2022-09-16 10:20:16 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | RemoteControlGUI::~RemoteControlGUI() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     qDeleteAll(m_deviceGUIs); | 
					
						
							|  |  |  |     m_deviceGUIs.clear(); | 
					
						
							|  |  |  |     delete ui; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void RemoteControlGUI::setWorkspaceIndex(int index) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     m_settings.m_workspaceIndex = index; | 
					
						
							|  |  |  |     m_feature->setWorkspaceIndex(index); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void RemoteControlGUI::blockApplySettings(bool block) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     m_doApplySettings = !block; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void RemoteControlGUI::displaySettings() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     setTitleColor(m_settings.m_rgbColor); | 
					
						
							|  |  |  |     setWindowTitle(m_settings.m_title); | 
					
						
							|  |  |  |     setTitle(m_settings.m_title); | 
					
						
							|  |  |  |     createGUI(); | 
					
						
							|  |  |  |     blockApplySettings(true); | 
					
						
							|  |  |  |     getRollupContents()->restoreState(m_rollupState); | 
					
						
							|  |  |  |     blockApplySettings(false); | 
					
						
							|  |  |  |     getRollupContents()->arrangeRollups(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void RemoteControlGUI::onMenuDialogCalled(const QPoint &p) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2024-08-25 23:36:46 +02:00
										 |  |  |     if (m_contextMenuType == ContextMenuType::ContextMenuChannelSettings) | 
					
						
							| 
									
										
										
										
											2022-09-16 10:20:16 +01:00
										 |  |  |     { | 
					
						
							|  |  |  |         BasicFeatureSettingsDialog dialog(this); | 
					
						
							|  |  |  |         dialog.setTitle(m_settings.m_title); | 
					
						
							|  |  |  |         dialog.setUseReverseAPI(m_settings.m_useReverseAPI); | 
					
						
							|  |  |  |         dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress); | 
					
						
							|  |  |  |         dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); | 
					
						
							|  |  |  |         dialog.setReverseAPIFeatureSetIndex(m_settings.m_reverseAPIFeatureSetIndex); | 
					
						
							|  |  |  |         dialog.setReverseAPIFeatureIndex(m_settings.m_reverseAPIFeatureIndex); | 
					
						
							|  |  |  |         dialog.setDefaultTitle(m_displayedName); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         dialog.move(p); | 
					
						
							| 
									
										
										
										
											2022-12-20 10:31:15 +00:00
										 |  |  |         new DialogPositioner(&dialog, false); | 
					
						
							| 
									
										
										
										
											2022-09-16 10:20:16 +01:00
										 |  |  |         dialog.exec(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         m_settings.m_title = dialog.getTitle(); | 
					
						
							|  |  |  |         m_settings.m_useReverseAPI = dialog.useReverseAPI(); | 
					
						
							|  |  |  |         m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress(); | 
					
						
							|  |  |  |         m_settings.m_reverseAPIPort = dialog.getReverseAPIPort(); | 
					
						
							|  |  |  |         m_settings.m_reverseAPIFeatureSetIndex = dialog.getReverseAPIFeatureSetIndex(); | 
					
						
							|  |  |  |         m_settings.m_reverseAPIFeatureIndex = dialog.getReverseAPIFeatureIndex(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         setTitle(m_settings.m_title); | 
					
						
							|  |  |  |         setTitleColor(m_settings.m_rgbColor); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         applySettings(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     resetContextMenuType(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void RemoteControlGUI::createControls(RemoteControlDeviceGUI *gui, QBoxLayout *vBox, FlowLayout *flow, int &widgetCnt) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     // Create buttons to control the device
 | 
					
						
							|  |  |  |     QGridLayout *controlsGrid = nullptr; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (gui->m_rcDevice->m_verticalControls) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         controlsGrid = new QGridLayout(); | 
					
						
							|  |  |  |         vBox->addLayout(controlsGrid); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else if (!flow) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         flow = new FlowLayout(2, 6, 6); | 
					
						
							|  |  |  |         vBox->addItem(flow); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     int row = 0; | 
					
						
							|  |  |  |     for (auto const &control : gui->m_rcDevice->m_controls) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         if (!gui->m_rcDevice->m_verticalControls && (widgetCnt > 0)) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             QFrame *line = new QFrame(); | 
					
						
							|  |  |  |             line->setFrameShape(QFrame::VLine); | 
					
						
							|  |  |  |             line->setFrameShadow(QFrame::Sunken); | 
					
						
							|  |  |  |             flow->addWidget(line); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         DeviceDiscoverer::ControlInfo *info = gui->m_rcDevice->m_info.getControl(control.m_id); | 
					
						
							|  |  |  |         if (!info) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             qDebug() << "RemoteControlGUI::createControls: Info missing for " << control.m_id; | 
					
						
							|  |  |  |             continue; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (!control.m_labelLeft.isEmpty()) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             QLabel *controlLabelLeft = new QLabel(control.m_labelLeft); | 
					
						
							|  |  |  |             if (gui->m_rcDevice->m_verticalControls) | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 controlsGrid->addWidget(controlLabelLeft, row, 0); | 
					
						
							|  |  |  |                 controlsGrid->setColumnStretch(row, 0); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             else | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 flow->addWidget(controlLabelLeft); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         QList<QWidget *> widgets; | 
					
						
							|  |  |  |         QWidget *widget = nullptr; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         switch (info->m_type) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |         case DeviceDiscoverer::BOOL: | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 ButtonSwitch *button = new ButtonSwitch(); | 
					
						
							|  |  |  |                 button->setToolTip("Start/stop " + info->m_name); | 
					
						
							|  |  |  |                 button->setIcon(m_startStopIcon); | 
					
						
							|  |  |  |                 button->setStyleSheet("QToolButton { background-color : blue; }" | 
					
						
							|  |  |  |                                       "QToolButton:checked { background-color : green; }" | 
					
						
							|  |  |  |                                       "QToolButton:disabled { background-color : gray; }"); | 
					
						
							|  |  |  |                 connect(button, &ButtonSwitch::toggled, | 
					
						
							|  |  |  |                     [=] (bool toggled) | 
					
						
							|  |  |  |                     { | 
					
						
							|  |  |  |                         RemoteControl::MsgDeviceSetState *message = RemoteControl::MsgDeviceSetState::create(gui->m_rcDevice->m_protocol, | 
					
						
							|  |  |  |                                                                                                  gui->m_rcDevice->m_info.m_id, | 
					
						
							|  |  |  |                                                                                                  control.m_id, | 
					
						
							|  |  |  |                                                                                                  toggled); | 
					
						
							|  |  |  |                         m_remoteControl->getInputMessageQueue()->push(message); | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                 ); | 
					
						
							|  |  |  |                 widgets.append(button); | 
					
						
							|  |  |  |                 widget = button; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         case DeviceDiscoverer::INT: | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 QSpinBox *spinBox = new QSpinBox(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 spinBox->setToolTip("Set value for " + info->m_name); | 
					
						
							|  |  |  |                 spinBox->setMinimum((int)info->m_min); | 
					
						
							|  |  |  |                 spinBox->setMaximum((int)info->m_max); | 
					
						
							|  |  |  |                 connect(spinBox, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), | 
					
						
							|  |  |  |                     [=] (int value) | 
					
						
							|  |  |  |                     { | 
					
						
							|  |  |  |                         RemoteControl::MsgDeviceSetState *message = RemoteControl::MsgDeviceSetState::create(gui->m_rcDevice->m_protocol, | 
					
						
							|  |  |  |                                                                                                  gui->m_rcDevice->m_info.m_id, | 
					
						
							|  |  |  |                                                                                                  control.m_id, | 
					
						
							|  |  |  |                                                                                                  value); | 
					
						
							|  |  |  |                         m_remoteControl->getInputMessageQueue()->push(message); | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                 ); | 
					
						
							|  |  |  |                 widgets.append(spinBox); | 
					
						
							|  |  |  |                 widget = spinBox; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         case DeviceDiscoverer::FLOAT: | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 switch (info->m_widgetType) | 
					
						
							|  |  |  |                 { | 
					
						
							|  |  |  |                 case DeviceDiscoverer::SPIN_BOX: | 
					
						
							|  |  |  |                     { | 
					
						
							|  |  |  |                         QDoubleSpinBox *spinBox = new SciDoubleSpinBox(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                         spinBox->setToolTip("Set value for " + info->m_name); | 
					
						
							|  |  |  |                         spinBox->setMinimum(info->m_min); | 
					
						
							|  |  |  |                         spinBox->setMaximum(info->m_max); | 
					
						
							|  |  |  |                         spinBox->setDecimals(info->m_precision); | 
					
						
							|  |  |  |                         connect(spinBox, static_cast<void (QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged), | 
					
						
							|  |  |  |                             [=] (double value) | 
					
						
							|  |  |  |                             { | 
					
						
							|  |  |  |                                 RemoteControl::MsgDeviceSetState *message = RemoteControl::MsgDeviceSetState::create(gui->m_rcDevice->m_protocol, | 
					
						
							|  |  |  |                                                                                                          gui->m_rcDevice->m_info.m_id, | 
					
						
							|  |  |  |                                                                                                          control.m_id, | 
					
						
							|  |  |  |                                                                                                          (float)value * info->m_scale); | 
					
						
							|  |  |  |                                 m_remoteControl->getInputMessageQueue()->push(message); | 
					
						
							|  |  |  |                             } | 
					
						
							|  |  |  |                         ); | 
					
						
							|  |  |  |                         widgets.append(spinBox); | 
					
						
							|  |  |  |                         widget = spinBox; | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                     break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 case DeviceDiscoverer::DIAL: | 
					
						
							|  |  |  |                     { | 
					
						
							|  |  |  |                         widget = new QWidget(); | 
					
						
							|  |  |  |                         QHBoxLayout *layout = new QHBoxLayout(); | 
					
						
							|  |  |  |                         layout->setContentsMargins(0, 0, 0, 0); | 
					
						
							|  |  |  |                         widget->setLayout(layout); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                         QDial *dial = new QDial(); | 
					
						
							|  |  |  |                         dial->setMaximumSize(24, 24); | 
					
						
							|  |  |  |                         dial->setToolTip("Set value for " + info->m_name); | 
					
						
							|  |  |  |                         dial->setMinimum(info->m_min); | 
					
						
							|  |  |  |                         dial->setMaximum(info->m_max); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                         connect(dial, static_cast<void (QDial::*)(int)>(&QDial::valueChanged), | 
					
						
							|  |  |  |                             [=] (int value) | 
					
						
							|  |  |  |                             { | 
					
						
							|  |  |  |                                 RemoteControl::MsgDeviceSetState *message = RemoteControl::MsgDeviceSetState::create(gui->m_rcDevice->m_protocol, | 
					
						
							|  |  |  |                                                                                                          gui->m_rcDevice->m_info.m_id, | 
					
						
							|  |  |  |                                                                                                          control.m_id, | 
					
						
							|  |  |  |                                                                                                          ((float)value) * info->m_scale); | 
					
						
							|  |  |  |                                 m_remoteControl->getInputMessageQueue()->push(message); | 
					
						
							|  |  |  |                             } | 
					
						
							|  |  |  |                         ); | 
					
						
							|  |  |  |                         widgets.append(dial); | 
					
						
							|  |  |  |                         layout->addWidget(dial); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                         QLabel *label = new QLabel(QString::number(dial->value())); | 
					
						
							|  |  |  |                         label->setToolTip("Value for " + info->m_name); | 
					
						
							|  |  |  |                         widgets.append(label); | 
					
						
							|  |  |  |                         layout->addWidget(label); | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                     break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 case DeviceDiscoverer::SLIDER: | 
					
						
							|  |  |  |                     { | 
					
						
							|  |  |  |                         widget = new QWidget(); | 
					
						
							|  |  |  |                         QHBoxLayout *layout = new QHBoxLayout(); | 
					
						
							|  |  |  |                         layout->setContentsMargins(0, 0, 0, 0); | 
					
						
							|  |  |  |                         widget->setLayout(layout); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                         QSlider *slider = new QSlider(Qt::Horizontal); | 
					
						
							|  |  |  |                         slider->setToolTip("Set value for " + info->m_name); | 
					
						
							|  |  |  |                         slider->setMinimum(info->m_min); | 
					
						
							|  |  |  |                         slider->setMaximum(info->m_max); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                         connect(slider, static_cast<void (QSlider::*)(int)>(&QSlider::valueChanged), | 
					
						
							|  |  |  |                             [=] (int value) | 
					
						
							|  |  |  |                             { | 
					
						
							|  |  |  |                                 RemoteControl::MsgDeviceSetState *message = RemoteControl::MsgDeviceSetState::create(gui->m_rcDevice->m_protocol, | 
					
						
							|  |  |  |                                                                                                          gui->m_rcDevice->m_info.m_id, | 
					
						
							|  |  |  |                                                                                                          control.m_id, | 
					
						
							|  |  |  |                                                                                                          ((float)value) * info->m_scale); | 
					
						
							|  |  |  |                                 m_remoteControl->getInputMessageQueue()->push(message); | 
					
						
							|  |  |  |                             } | 
					
						
							|  |  |  |                         ); | 
					
						
							|  |  |  |                         widgets.append(slider); | 
					
						
							|  |  |  |                         layout->addWidget(slider); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                         QLabel *label = new QLabel(QString::number(slider->value())); | 
					
						
							|  |  |  |                         label->setToolTip("Value for " + info->m_name); | 
					
						
							|  |  |  |                         widgets.append(label); | 
					
						
							|  |  |  |                         layout->addWidget(label); | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                     break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         case DeviceDiscoverer::STRING: | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 QLineEdit *lineEdit = new QLineEdit(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 lineEdit->setToolTip("Set value for " + info->m_name); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 connect(lineEdit, &QLineEdit::editingFinished, | 
					
						
							|  |  |  |                     [=] () | 
					
						
							|  |  |  |                     { | 
					
						
							|  |  |  |                         QString text = lineEdit->text(); | 
					
						
							|  |  |  |                         RemoteControl::MsgDeviceSetState *message = RemoteControl::MsgDeviceSetState::create(gui->m_rcDevice->m_protocol, | 
					
						
							|  |  |  |                                                                                                  gui->m_rcDevice->m_info.m_id, | 
					
						
							|  |  |  |                                                                                                  control.m_id, | 
					
						
							|  |  |  |                                                                                                  text); | 
					
						
							|  |  |  |                         m_remoteControl->getInputMessageQueue()->push(message); | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                 ); | 
					
						
							|  |  |  |                 widgets.append(lineEdit); | 
					
						
							|  |  |  |                 widget = lineEdit; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         case DeviceDiscoverer::LIST: | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 QComboBox *combo = new QComboBox(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 combo->setToolTip("Set value for " + info->m_name); | 
					
						
							|  |  |  |                 combo->insertItems(0, info->m_values); | 
					
						
							| 
									
										
										
										
											2022-09-17 08:46:17 +01:00
										 |  |  |                 connect(combo, &QComboBox::currentTextChanged, | 
					
						
							| 
									
										
										
										
											2022-09-16 10:20:16 +01:00
										 |  |  |                     [=] (const QString &text) | 
					
						
							|  |  |  |                     { | 
					
						
							|  |  |  |                         RemoteControl::MsgDeviceSetState *message = RemoteControl::MsgDeviceSetState::create(gui->m_rcDevice->m_protocol, | 
					
						
							|  |  |  |                                                                                                  gui->m_rcDevice->m_info.m_id, | 
					
						
							|  |  |  |                                                                                                  control.m_id, | 
					
						
							|  |  |  |                                                                                                  text); | 
					
						
							|  |  |  |                         m_remoteControl->getInputMessageQueue()->push(message); | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                 ); | 
					
						
							|  |  |  |                 widgets.append(combo); | 
					
						
							|  |  |  |                 widget = combo; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         case DeviceDiscoverer::BUTTON: | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 QString label = info->m_name; | 
					
						
							|  |  |  |                 if (info->m_values.size() > 0) { | 
					
						
							|  |  |  |                     label = info->m_values[0]; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |                 QToolButton *button = new QToolButton(); | 
					
						
							|  |  |  |                 button->setText(label); | 
					
						
							|  |  |  |                 button->setToolTip("Trigger " + info->m_name); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 connect(button, &QToolButton::clicked, | 
					
						
							|  |  |  |                     [=] (bool checked) | 
					
						
							|  |  |  |                     { | 
					
						
							| 
									
										
										
										
											2022-09-16 11:41:40 +01:00
										 |  |  |                         (void) checked; | 
					
						
							| 
									
										
										
										
											2022-09-16 10:20:16 +01:00
										 |  |  |                         RemoteControl::MsgDeviceSetState *message = RemoteControl::MsgDeviceSetState::create(gui->m_rcDevice->m_protocol, | 
					
						
							|  |  |  |                                                                                                  gui->m_rcDevice->m_info.m_id, | 
					
						
							|  |  |  |                                                                                                  control.m_id, | 
					
						
							|  |  |  |                                                                                                  1); | 
					
						
							|  |  |  |                         m_remoteControl->getInputMessageQueue()->push(message); | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                 ); | 
					
						
							|  |  |  |                 widgets.append(button); | 
					
						
							|  |  |  |                 widget = button; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-16 11:41:40 +01:00
										 |  |  |         default: | 
					
						
							|  |  |  |             qDebug() << "RemoteControlGUI::createControls: Unexpected type for control."; | 
					
						
							|  |  |  |             break; | 
					
						
							| 
									
										
										
										
											2022-09-16 10:20:16 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         gui->m_controls.insert(control.m_id, widgets); | 
					
						
							|  |  |  |         if (gui->m_rcDevice->m_verticalControls) { | 
					
						
							|  |  |  |             controlsGrid->addWidget(widget, row, 1); | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |             flow->addWidget(widget); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (!control.m_labelRight.isEmpty()) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             QLabel *controlLabelRight = new QLabel(control.m_labelRight); | 
					
						
							|  |  |  |             if (gui->m_rcDevice->m_verticalControls) | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 controlsGrid->addWidget(controlLabelRight, row, 2); | 
					
						
							|  |  |  |                 controlsGrid->setColumnStretch(row, 2); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             else | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 flow->addWidget(controlLabelRight); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         widgetCnt++; | 
					
						
							|  |  |  |         row++; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void RemoteControlGUI::createChart(RemoteControlDeviceGUI *gui, QVBoxLayout *vBox, const QString &id, const QString &units) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (gui->m_chart == nullptr) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         // Create a chart to plot the sensor data
 | 
					
						
							|  |  |  |         gui->m_chart = new QChart(); | 
					
						
							|  |  |  |         gui->m_chart->setTitle(""); | 
					
						
							|  |  |  |         gui->m_chart->legend()->hide(); | 
					
						
							|  |  |  |         gui->m_chart->layout()->setContentsMargins(0, 0, 0, 0); | 
					
						
							|  |  |  |         gui->m_chart->setMargins(QMargins(1, 1, 1, 1)); | 
					
						
							|  |  |  |         gui->m_chart->setTheme(QChart::ChartThemeDark); | 
					
						
							|  |  |  |         QLineSeries *series = new QLineSeries(); | 
					
						
							|  |  |  |         gui->m_series.insert(id, series); | 
					
						
							|  |  |  |         QLineSeries *onePointSeries = new QLineSeries(); | 
					
						
							|  |  |  |         gui->m_onePointSeries.insert(id, onePointSeries); | 
					
						
							|  |  |  |         gui->m_chart->addSeries(series); | 
					
						
							|  |  |  |         QValueAxis *yAxis = new QValueAxis(); | 
					
						
							|  |  |  |         QDateTimeAxis *xAxis = new QDateTimeAxis(); | 
					
						
							|  |  |  |         xAxis->setFormat(QString("hh:mm:ss")); | 
					
						
							|  |  |  |         yAxis->setTitleText(units); | 
					
						
							|  |  |  |         gui->m_chart->addAxis(xAxis, Qt::AlignBottom); | 
					
						
							|  |  |  |         gui->m_chart->addAxis(yAxis, Qt::AlignLeft); | 
					
						
							|  |  |  |         series->attachAxis(xAxis); | 
					
						
							|  |  |  |         series->attachAxis(yAxis); | 
					
						
							|  |  |  |         gui->m_chartView = new QChartView(); | 
					
						
							|  |  |  |         gui->m_chartView->setChart(gui->m_chart); | 
					
						
							|  |  |  |         if (m_settings.m_chartHeightFixed) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             gui->m_chartView->setMinimumSize(300, m_settings.m_chartHeightPixels); | 
					
						
							|  |  |  |             gui->m_chartView->setMaximumSize(16777215, m_settings.m_chartHeightPixels); | 
					
						
							|  |  |  |             gui->m_chartView->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             gui->m_chartView->setMinimumSize(300, 130); // 130 is enough to display axis labels
 | 
					
						
							|  |  |  |             gui->m_chartView->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); | 
					
						
							|  |  |  |             gui->m_chartView->setSceneRect(0, 0, 300, 130); // This determines m_chartView->sizeHint() - default is 640x480, which is a bit big
 | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         QBoxLayout *chartLayout = new QVBoxLayout(); | 
					
						
							|  |  |  |         gui->m_chartView->setLayout(chartLayout); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         vBox->addWidget(gui->m_chartView); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         // Add new series
 | 
					
						
							|  |  |  |         QLineSeries *series = new QLineSeries(); | 
					
						
							|  |  |  |         gui->m_series.insert(id, series); | 
					
						
							|  |  |  |         QLineSeries *onePointSeries = new QLineSeries(); | 
					
						
							|  |  |  |         gui->m_onePointSeries.insert(id, onePointSeries); | 
					
						
							|  |  |  |         gui->m_chart->addSeries(series); | 
					
						
							|  |  |  |         if (!gui->m_rcDevice->m_commonYAxis) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             // Use per series Y axis
 | 
					
						
							|  |  |  |             QValueAxis *yAxis = new QValueAxis(); | 
					
						
							|  |  |  |             yAxis->setTitleText(units); | 
					
						
							|  |  |  |             gui->m_chart->addAxis(yAxis, Qt::AlignRight); | 
					
						
							|  |  |  |             series->attachAxis(yAxis); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             // Use common y axis
 | 
					
						
							|  |  |  |             QAbstractAxis *yAxis = gui->m_chart->axes(Qt::Vertical)[0]; | 
					
						
							|  |  |  |             // Only display units if all the same
 | 
					
						
							|  |  |  |             if (yAxis->titleText() != units) { | 
					
						
							|  |  |  |                 yAxis->setTitleText(""); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             series->attachAxis(yAxis); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         series->attachAxis(gui->m_chart->axes(Qt::Horizontal)[0]); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void RemoteControlGUI::createSensors(RemoteControlDeviceGUI *gui, QVBoxLayout *vBox, FlowLayout *flow, int &widgetCnt, bool &hasCharts) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     // Table doesn't seem to expand in a QHBoxLayout, so we have to use a GridLayout
 | 
					
						
							|  |  |  |     QGridLayout *grid = nullptr; | 
					
						
							|  |  |  |     QTableWidget *table = nullptr; | 
					
						
							|  |  |  |     if (gui->m_rcDevice->m_verticalSensors) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         grid = new QGridLayout(); | 
					
						
							|  |  |  |         grid->setColumnStretch(0, 1); | 
					
						
							|  |  |  |         vBox->addLayout(grid); | 
					
						
							|  |  |  |         table = new QTableWidget(gui->m_rcDevice->m_sensors.size(), 3); | 
					
						
							|  |  |  |         table->verticalHeader()->setVisible(false); | 
					
						
							|  |  |  |         table->horizontalHeader()->setVisible(false); | 
					
						
							|  |  |  |         table->horizontalHeader()->setSectionResizeMode(0, QHeaderView::ResizeToContents); | 
					
						
							|  |  |  |         table->horizontalHeader()->setSectionResizeMode(1, QHeaderView::Stretch); | 
					
						
							|  |  |  |         table->horizontalHeader()->setSectionResizeMode(2, QHeaderView::ResizeToContents); | 
					
						
							|  |  |  |         table->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum); | 
					
						
							|  |  |  |         table->setSizeAdjustPolicy(QAbstractScrollArea::AdjustToContents);  // Needed so table->sizeHint matches minimumSize set below
 | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else if (!flow) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         flow = new FlowLayout(2, 6, 6); | 
					
						
							|  |  |  |         vBox->addItem(flow); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     int row = 0; | 
					
						
							|  |  |  |     bool hasUnits = false; | 
					
						
							|  |  |  |     for (auto const &sensor : gui->m_rcDevice->m_sensors) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         // For vertical layout, we use a table
 | 
					
						
							|  |  |  |         // For horizontal, we use HBox of labels separated with bars
 | 
					
						
							|  |  |  |         if (gui->m_rcDevice->m_verticalSensors) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             if (!sensor.m_labelLeft.isEmpty()) | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 QTableWidgetItem *sensorLabel = new QTableWidgetItem(sensor.m_labelLeft); | 
					
						
							|  |  |  |                 sensorLabel->setFlags(Qt::ItemIsEnabled); | 
					
						
							|  |  |  |                 table->setItem(row, COL_LABEL, sensorLabel); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             QTableWidgetItem *valueItem = new QTableWidgetItem("-"); | 
					
						
							|  |  |  |             table->setItem(row, COL_VALUE, valueItem); | 
					
						
							|  |  |  |             valueItem->setTextAlignment(Qt::AlignRight | Qt::AlignVCenter); | 
					
						
							|  |  |  |             valueItem->setFlags(Qt::ItemIsEnabled); | 
					
						
							|  |  |  |             if (!sensor.m_labelRight.isEmpty()) | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 QTableWidgetItem *unitsItem = new QTableWidgetItem(sensor.m_labelRight); | 
					
						
							|  |  |  |                 unitsItem->setFlags(Qt::ItemIsEnabled); | 
					
						
							|  |  |  |                 table->setItem(row, COL_UNITS, unitsItem); | 
					
						
							|  |  |  |                 hasUnits = true; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             gui->m_sensorValueItems.insert(sensor.m_id, valueItem); | 
					
						
							|  |  |  |             grid->addWidget(table, 0, 0); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             if (widgetCnt > 0) | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 QFrame *line = new QFrame(); | 
					
						
							|  |  |  |                 line->setFrameShape(QFrame::VLine); | 
					
						
							|  |  |  |                 line->setFrameShadow(QFrame::Sunken); | 
					
						
							|  |  |  |                 flow->addWidget(line); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             if (!sensor.m_labelLeft.isEmpty()) | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 QLabel *sensorLabel = new QLabel(sensor.m_labelLeft); | 
					
						
							|  |  |  |                 flow->addWidget(sensorLabel); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             QLabel *sensorValue = new QLabel("-"); | 
					
						
							|  |  |  |             flow->addWidget(sensorValue); | 
					
						
							|  |  |  |             if (!sensor.m_labelRight.isEmpty()) | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 QLabel *sensorUnits = new QLabel(sensor.m_labelRight); | 
					
						
							|  |  |  |                 flow->addWidget(sensorUnits); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             gui->m_sensorValueLabels.insert(sensor.m_id, sensorValue); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (sensor.m_plot) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             createChart(gui, vBox, sensor.m_id, sensor.m_labelRight); | 
					
						
							|  |  |  |             hasCharts = true; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         widgetCnt++; | 
					
						
							|  |  |  |         row++; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (table) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         table->resizeColumnToContents(COL_LABEL); | 
					
						
							|  |  |  |         if (hasUnits) { | 
					
						
							|  |  |  |             table->resizeColumnToContents(COL_UNITS); | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |             table->hideColumn(COL_UNITS); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         int tableWidth = 0; | 
					
						
							|  |  |  |         for (int i = 0; i < table->columnCount(); i++){ | 
					
						
							|  |  |  |            tableWidth += table->columnWidth(i); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         int tableHeight = 0; | 
					
						
							|  |  |  |         for (int i = 0; i < table->rowCount(); i++){ | 
					
						
							|  |  |  |            tableHeight += table->rowHeight(i); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         table->setMinimumWidth(tableWidth); | 
					
						
							|  |  |  |         table->setMinimumHeight(tableHeight+2); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | RemoteControlGUI::RemoteControlDeviceGUI *RemoteControlGUI::createDeviceGUI(RemoteControlDevice *rcDevice) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     // Create the UI for the device
 | 
					
						
							|  |  |  |     RemoteControlDeviceGUI *gui = new RemoteControlDeviceGUI(rcDevice); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     bool hasCharts = false; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     gui->m_container = new QWidget(getRollupContents()); | 
					
						
							|  |  |  |     gui->m_container->setWindowTitle(gui->m_rcDevice->m_label); | 
					
						
							|  |  |  |     bool vertical = gui->m_rcDevice->m_verticalControls || gui->m_rcDevice->m_verticalSensors; | 
					
						
							|  |  |  |     QVBoxLayout *vBox = new QVBoxLayout(); | 
					
						
							|  |  |  |     vBox->setContentsMargins(2, 2, 2, 2); | 
					
						
							|  |  |  |     FlowLayout *flow = nullptr; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!vertical) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         flow = new FlowLayout(2, 6, 6); | 
					
						
							|  |  |  |         vBox->addItem(flow); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     int widgetCnt = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Create buttons to control the device
 | 
					
						
							|  |  |  |     createControls(gui, vBox, flow, widgetCnt); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (gui->m_rcDevice->m_verticalControls) { | 
					
						
							|  |  |  |         widgetCnt = 0; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Create widgets to display the sensor label and its value
 | 
					
						
							|  |  |  |     createSensors(gui, vBox, flow, widgetCnt, hasCharts); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     gui->m_container->setLayout(vBox); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (hasCharts && !m_settings.m_chartHeightFixed) { | 
					
						
							|  |  |  |         gui->m_container->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     gui->m_container->show(); | 
					
						
							|  |  |  |     return gui; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void RemoteControlGUI::createGUI() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     // Delete existing elements
 | 
					
						
							|  |  |  |     for (auto gui : m_deviceGUIs) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         delete gui->m_container; | 
					
						
							|  |  |  |         gui->m_container = nullptr; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     qDeleteAll(m_deviceGUIs); | 
					
						
							|  |  |  |     m_deviceGUIs.clear(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Create new GUIs for each device
 | 
					
						
							|  |  |  |     bool expanding = false; | 
					
						
							|  |  |  |     for (auto device : m_settings.m_devices) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         RemoteControlDeviceGUI *gui = createDeviceGUI(device); | 
					
						
							|  |  |  |         m_deviceGUIs.append(gui); | 
					
						
							|  |  |  |         if (gui->m_container->sizePolicy().verticalPolicy() == QSizePolicy::Expanding) { | 
					
						
							|  |  |  |             expanding = true; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (expanding) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         getRollupContents()->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); | 
					
						
							|  |  |  |         setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         getRollupContents()->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); | 
					
						
							|  |  |  |         setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // FIXME: Why are these three steps needed to get the window
 | 
					
						
							|  |  |  |     // to resize to the newly added widgets?
 | 
					
						
							|  |  |  |     getRollupContents()->arrangeRollups(); // Recalc rollup size
 | 
					
						
							|  |  |  |     layout()->activate(); // Get QMdiSubWindow to recalc its sizeHint
 | 
					
						
							|  |  |  |     resize(sizeHint()); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Need to do it twice when FlowLayout is used!
 | 
					
						
							|  |  |  |     getRollupContents()->arrangeRollups(); | 
					
						
							|  |  |  |     layout()->activate(); | 
					
						
							|  |  |  |     resize(sizeHint()); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void RemoteControlGUI::on_startStop_toggled(bool checked) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (m_doApplySettings) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         RemoteControl::MsgStartStop *message = RemoteControl::MsgStartStop::create(checked); | 
					
						
							|  |  |  |         m_remoteControl->getInputMessageQueue()->push(message); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void RemoteControlGUI::on_update_clicked() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     RemoteControl::MsgDeviceGetState *message = RemoteControl::MsgDeviceGetState::create(); | 
					
						
							|  |  |  |     m_remoteControl->getInputMessageQueue()->push(message); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void RemoteControlGUI::on_settings_clicked() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     // Display settings dialog
 | 
					
						
							|  |  |  |     RemoteControlSettingsDialog dialog(&m_settings); | 
					
						
							|  |  |  |     if (dialog.exec() == QDialog::Accepted) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         createGUI(); | 
					
						
							|  |  |  |         applySettings(); | 
					
						
							|  |  |  |         on_update_clicked(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void RemoteControlGUI::on_clearData_clicked() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     // Clear data in all charts
 | 
					
						
							|  |  |  |     for (auto deviceGUI : m_deviceGUIs) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         for (auto series : deviceGUI->m_series) { | 
					
						
							|  |  |  |             series->clear(); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         for (auto series : deviceGUI->m_onePointSeries) { | 
					
						
							|  |  |  |             series->clear(); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Update a control widget with latest state value
 | 
					
						
							|  |  |  | void RemoteControlGUI::updateControl(QWidget *widget, const DeviceDiscoverer::ControlInfo *controlInfo, const QString &key, const QVariant &value) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (ButtonSwitch *button = qobject_cast<ButtonSwitch *>(widget)) | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2022-09-16 11:41:40 +01:00
										 |  |  |         if ((QMetaType::Type)value.type() == QMetaType::QString) | 
					
						
							| 
									
										
										
										
											2022-09-16 10:20:16 +01:00
										 |  |  |         { | 
					
						
							|  |  |  |             if (value.toString() == "unavailable") | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 button->setStyleSheet("QToolButton { background-color : gray; }" | 
					
						
							|  |  |  |                                       "QToolButton:checked { background-color : gray; }" | 
					
						
							|  |  |  |                                       "QToolButton:disabled { background-color : gray; }"); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             else if (value.toString() == "error") | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 button->setStyleSheet("QToolButton { background-color : red; }" | 
					
						
							|  |  |  |                                       "QToolButton:checked { background-color : red; }" | 
					
						
							|  |  |  |                                       "QToolButton:disabled { background-color : red; }"); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             else | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 qDebug() << "RemoteControlGUI::updateControl: String value for button " << key << value; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             int state = value.toInt(); | 
					
						
							|  |  |  |             int prev = button->blockSignals(true); | 
					
						
							|  |  |  |             button->setChecked(state != 0); | 
					
						
							|  |  |  |             button->blockSignals(prev); | 
					
						
							|  |  |  |             button->setStyleSheet("QToolButton { background-color : blue; }" | 
					
						
							|  |  |  |                                   "QToolButton:checked { background-color : green; }" | 
					
						
							|  |  |  |                                   "QToolButton:disabled { background-color : gray; }"); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else if (QSpinBox *spinBox = qobject_cast<QSpinBox *>(widget)) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         int prev = spinBox->blockSignals(true); | 
					
						
							|  |  |  |         if (value.toString() == "unavailable") | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             spinBox->setStyleSheet("QSpinBox { background-color : gray; }"); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         else if (value.toString() == "error") | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             spinBox->setStyleSheet("QSpinBox { background-color : red; }"); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             int state = value.toInt(); | 
					
						
							|  |  |  |             bool outOfRange = (state < spinBox->minimum()) || (state > spinBox->maximum()); | 
					
						
							|  |  |  |             spinBox->setValue(state); | 
					
						
							|  |  |  |             if (outOfRange) { | 
					
						
							|  |  |  |                 spinBox->setStyleSheet("QSpinBox { background-color : red; }"); | 
					
						
							|  |  |  |             } else { | 
					
						
							|  |  |  |                 spinBox->setStyleSheet(""); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         spinBox->blockSignals(prev); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else if (QDoubleSpinBox *spinBox = qobject_cast<QDoubleSpinBox *>(widget)) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         int prev = spinBox->blockSignals(true); | 
					
						
							|  |  |  |         if (value.toString() == "unavailable") | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             spinBox->setStyleSheet("QDoubleSpinBox { background-color : gray; }"); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         else if (value.toString() == "error") | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             spinBox->setStyleSheet("QDoubleSpinBox { background-color : red; }"); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             double state = value.toDouble(); | 
					
						
							|  |  |  |             if (controlInfo) { | 
					
						
							|  |  |  |                 state = state / controlInfo->m_scale; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             bool outOfRange = (state < spinBox->minimum()) || (state > spinBox->maximum()); | 
					
						
							|  |  |  |             spinBox->setValue(state); | 
					
						
							|  |  |  |             if (outOfRange) { | 
					
						
							|  |  |  |                 spinBox->setStyleSheet("QDoubleSpinBox { background-color : red; }"); | 
					
						
							|  |  |  |             } else { | 
					
						
							|  |  |  |                 spinBox->setStyleSheet(""); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         spinBox->blockSignals(prev); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else if (QDial *dial = qobject_cast<QDial *>(widget)) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         int prev = dial->blockSignals(true); | 
					
						
							|  |  |  |         if (value.toString() == "unavailable") | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             dial->setStyleSheet("QDial { background-color : gray; }"); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         else if (value.toString() == "error") | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             dial->setStyleSheet("QDial { background-color : red; }"); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             double state = value.toDouble(); | 
					
						
							|  |  |  |             if (controlInfo) { | 
					
						
							|  |  |  |                 state = state / controlInfo->m_scale; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             bool outOfRange = (state < dial->minimum()) || (state > dial->maximum()); | 
					
						
							|  |  |  |             dial->setValue(state); | 
					
						
							|  |  |  |             if (outOfRange) { | 
					
						
							|  |  |  |                 dial->setStyleSheet("QDial { background-color : red; }"); | 
					
						
							|  |  |  |             } else { | 
					
						
							|  |  |  |                 dial->setStyleSheet(""); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         dial->blockSignals(prev); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else if (QSlider *slider = qobject_cast<QSlider *>(widget)) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         int prev = slider->blockSignals(true); | 
					
						
							|  |  |  |         if (value.toString() == "unavailable") | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             slider->setStyleSheet("QSlider { background-color : gray; }"); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         else if (value.toString() == "error") | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             slider->setStyleSheet("QSlider { background-color : red; }"); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             double state = value.toDouble(); | 
					
						
							|  |  |  |             if (controlInfo) { | 
					
						
							|  |  |  |                 state = state / controlInfo->m_scale; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             bool outOfRange = (state < slider->minimum()) || (state > slider->maximum()); | 
					
						
							|  |  |  |             slider->setValue(state); | 
					
						
							|  |  |  |             if (outOfRange) { | 
					
						
							|  |  |  |                 slider->setStyleSheet("QSlider { background-color : red; }"); | 
					
						
							|  |  |  |             } else { | 
					
						
							|  |  |  |                 slider->setStyleSheet(""); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         slider->blockSignals(prev); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else if (QComboBox *comboBox = qobject_cast<QComboBox *>(widget)) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         int prev = comboBox->blockSignals(true); | 
					
						
							|  |  |  |         QString string = value.toString(); | 
					
						
							|  |  |  |         int index = comboBox->findText(string); | 
					
						
							|  |  |  |         if (index != -1) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             comboBox->setCurrentIndex(index); | 
					
						
							|  |  |  |             comboBox->setStyleSheet(""); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             comboBox->setStyleSheet("QComboBox { background-color : red; }"); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         comboBox->blockSignals(prev); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else if (QLineEdit *lineEdit = qobject_cast<QLineEdit *>(widget)) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         lineEdit->setText(value.toString()); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else if (QLabel *label = qobject_cast<QLabel *>(widget)) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         label->setText(value.toString()); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         qDebug() << "RemoteControlGUI::updateControl: Unexpected widget type"; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void RemoteControlGUI::updateChart(RemoteControlDeviceGUI *deviceGUI, const QString &key, const QVariant &value) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     // Format the value for display
 | 
					
						
							|  |  |  |     bool ok = false; | 
					
						
							|  |  |  |     double d = value.toDouble(&ok); | 
					
						
							|  |  |  |     bool iOk = false; | 
					
						
							|  |  |  |     int iValue = value.toInt(&iOk); | 
					
						
							|  |  |  |     QString formattedValue; | 
					
						
							|  |  |  |     RemoteControlSensor *sensor = deviceGUI->m_rcDevice->getSensor(key); | 
					
						
							|  |  |  |     QString format = sensor->m_format.trimmed(); | 
					
						
							|  |  |  |     if (format.contains("%s")) | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2022-09-18 16:53:35 +01:00
										 |  |  |         formattedValue = QString::asprintf(format.toUtf8(), value.toString().toUtf8().data()); | 
					
						
							| 
									
										
										
										
											2022-09-16 10:20:16 +01:00
										 |  |  |     } | 
					
						
							|  |  |  |     else if (format.contains("%d") || format.contains("%u") || format.contains("%x") || format.contains("%X")) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         formattedValue = QString::asprintf(format.toUtf8(), value.toInt()); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-09-16 11:41:40 +01:00
										 |  |  |     else if (((QMetaType::Type)value.type() == QMetaType::Double) || ((QMetaType::Type)value.type() == QMetaType::Float)) | 
					
						
							| 
									
										
										
										
											2022-09-16 10:20:16 +01:00
										 |  |  |     { | 
					
						
							|  |  |  |         if (format.isEmpty()) { | 
					
						
							|  |  |  |             format = "%.1f"; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         formattedValue = QString::asprintf(format.toUtf8(), value.toDouble()); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else if (iOk) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         formattedValue = QString::asprintf("%d", iValue); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         formattedValue = value.toString(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Update sensor value widget to display the latest value
 | 
					
						
							|  |  |  |     if (deviceGUI->m_sensorValueLabels.contains(key)) { | 
					
						
							|  |  |  |         deviceGUI->m_sensorValueLabels.value(key)->setText(formattedValue); | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |         deviceGUI->m_sensorValueItems.value(key)->setText(formattedValue); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Plot value on chart
 | 
					
						
							|  |  |  |     if (deviceGUI->m_series.contains(key)) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         QLineSeries *onePointSeries = deviceGUI->m_onePointSeries.value(key); | 
					
						
							|  |  |  |         QLineSeries *series = deviceGUI->m_series.value(key); | 
					
						
							|  |  |  |         QDateTime dt = QDateTime::currentDateTime(); | 
					
						
							|  |  |  |         if (ok) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             // Charts aren't displayed properly if series has only one point,
 | 
					
						
							|  |  |  |             // so we save the first point in an additional series: onePointSeries
 | 
					
						
							|  |  |  |             if (onePointSeries->count() == 0) | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 onePointSeries->append(dt.toMSecsSinceEpoch(), d); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             else | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 if (series->count() == 0) { | 
					
						
							|  |  |  |                     series->append(onePointSeries->at(0)); | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |                 series->append(dt.toMSecsSinceEpoch(), d); | 
					
						
							|  |  |  |                 QList<QAbstractAxis *> axes = deviceGUI->m_chart->axes(Qt::Horizontal, series); | 
					
						
							|  |  |  |                 QDateTimeAxis *dtAxis = (QDateTimeAxis *)axes[0]; | 
					
						
							|  |  |  |                 QDateTime start = QDateTime::fromMSecsSinceEpoch(series->at(0).x()); | 
					
						
							|  |  |  |                 QDateTime end = QDateTime::fromMSecsSinceEpoch(series->at(series->count() - 1).x()); | 
					
						
							|  |  |  |                 if (start.date() == end.date()) | 
					
						
							|  |  |  |                 { | 
					
						
							|  |  |  |                     if (start.secsTo(end) < 60*5) { | 
					
						
							|  |  |  |                         dtAxis->setFormat(QString("hh:mm:ss")); | 
					
						
							|  |  |  |                     } else { | 
					
						
							|  |  |  |                         dtAxis->setFormat(QString("hh:mm")); | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |                 else | 
					
						
							|  |  |  |                 { | 
					
						
							|  |  |  |                     dtAxis->setFormat(QString("%1 hh:mm").arg(QLocale::system().dateFormat(QLocale::ShortFormat))); | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |                 dtAxis->setRange(start, end); | 
					
						
							|  |  |  |                 axes = deviceGUI->m_chart->axes(Qt::Vertical, series); | 
					
						
							|  |  |  |                 QValueAxis *yAxis = (QValueAxis *)axes[0]; | 
					
						
							|  |  |  |                 if (series->count() == 2) | 
					
						
							|  |  |  |                 { | 
					
						
							|  |  |  |                     double y1 = series->at(0).y(); | 
					
						
							|  |  |  |                     double y2 = series->at(1).y(); | 
					
						
							|  |  |  |                     double yMin = std::min(y1, y2); | 
					
						
							|  |  |  |                     double yMax = std::max(y1, y2); | 
					
						
							|  |  |  |                     double min = (yMin >= 0.0) ? yMin * 0.9 : yMin * 1.1; | 
					
						
							|  |  |  |                     double max = (yMax >= 0.0) ? yMax * 1.1 : yMax * 0.9; | 
					
						
							|  |  |  |                     yAxis->setRange(min, max); | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |                 else | 
					
						
							|  |  |  |                 { | 
					
						
							|  |  |  |                     double min = (d >= 0.0) ? d * 0.9 : d * 1.1; | 
					
						
							|  |  |  |                     double max = (d >= 0.0) ? d * 1.1 : d * 0.9; | 
					
						
							|  |  |  |                     if (min < yAxis->min()) { | 
					
						
							|  |  |  |                         yAxis->setMin(min); | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                     if (max > yAxis->max()) { | 
					
						
							|  |  |  |                         yAxis->setMax(max); | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             qDebug() << "RemoteControlGUI::deviceUpdated: Error converting " << key << value; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void RemoteControlGUI::deviceUpdated(const QString &protocol, const QString &deviceId, const QHash<QString, QVariant> &status) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     for (auto deviceGUI : m_deviceGUIs) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         if (   (protocol == deviceGUI->m_rcDevice->m_protocol) | 
					
						
							|  |  |  |             && (deviceId == deviceGUI->m_rcDevice->m_info.m_id)) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             deviceGUI->m_container->setEnabled(true); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             QHashIterator<QString, QVariant> itr(status); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             while (itr.hasNext()) | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 itr.next(); | 
					
						
							|  |  |  |                 QString key = itr.key(); | 
					
						
							|  |  |  |                 QVariant value = itr.value(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 if (deviceGUI->m_controls.contains(key)) | 
					
						
							|  |  |  |                 { | 
					
						
							|  |  |  |                     // Update control(s) to display latest state
 | 
					
						
							|  |  |  |                     QList<QWidget *> widgets = deviceGUI->m_controls.value(key); | 
					
						
							|  |  |  |                     DeviceDiscoverer::ControlInfo *control = deviceGUI->m_rcDevice->m_info.getControl(key); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                     for (auto widget : widgets) { | 
					
						
							|  |  |  |                         updateControl(widget, control, key, value); | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |                 else if (deviceGUI->m_sensorValueLabels.contains(key) || deviceGUI->m_sensorValueItems.contains(key)) | 
					
						
							|  |  |  |                 { | 
					
						
							|  |  |  |                     // Plot on chart
 | 
					
						
							|  |  |  |                     updateChart(deviceGUI, key, value); | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |                 else | 
					
						
							|  |  |  |                 { | 
					
						
							|  |  |  |                     qDebug() << "RemoteControlGUI::deviceUpdated: Unexpected status key " << key << value; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void RemoteControlGUI::deviceUnavailable(const QString &protocol, const QString &deviceId) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     for (auto deviceGUI : m_deviceGUIs) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         if (   (protocol == deviceGUI->m_rcDevice->m_protocol) | 
					
						
							|  |  |  |             && (deviceId == deviceGUI->m_rcDevice->m_info.m_id)) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             deviceGUI->m_container->setEnabled(false); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void RemoteControlGUI::applySettings(bool force) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (m_doApplySettings) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         RemoteControl::MsgConfigureRemoteControl* message = RemoteControl::MsgConfigureRemoteControl::create(m_settings, force); | 
					
						
							|  |  |  |         m_remoteControl->getInputMessageQueue()->push(message); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void RemoteControlGUI::makeUIConnections() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     QObject::connect(ui->startStop, &ButtonSwitch::toggled, this, &RemoteControlGUI::on_startStop_toggled); | 
					
						
							|  |  |  |     QObject::connect(ui->update, &QToolButton::clicked, this, &RemoteControlGUI::on_update_clicked); | 
					
						
							|  |  |  |     QObject::connect(ui->settings, &QToolButton::clicked, this, &RemoteControlGUI::on_settings_clicked); | 
					
						
							|  |  |  |     QObject::connect(ui->clearData, &QToolButton::clicked, this, &RemoteControlGUI::on_clearData_clicked); | 
					
						
							|  |  |  | } |