mirror of
https://github.com/f4exb/sdrangel.git
synced 2024-11-19 06:41:47 -05:00
c966f1cb5a
Add sizeToContents in ChannelGUI and FeatureGUI, called when widget is rolled, so we can remove resizing code from all of the individual channels and features. In RollupContents, use minimumSizeHint for calculated size, so that minimumWidth can come from .ui file. In DeviceGUI::sizeToContents(), call adjustSize(), so Device GUIs start out at minimum needed size (which should restore appearance prior to last patch). In stackSubWindows, use available space for channels if no spectrum/features present. In stackSubWindows, fix spectrum from being sized too big, resulting in scroll bars appearing. Reset user-defined channel width in stackSubWindows, when channels are removed. Don't stack maximized windows. There's one hack in Channel/FeatureGUI::maximizeWindow(). It seems that when maximimzing a window, QOpenGLWidgets aren't always paint properly immediately afterwards, so the code forces an additional update. I can't see why the first call to paintGL doesn't work.
1174 lines
44 KiB
C++
1174 lines
44 KiB
C++
///////////////////////////////////////////////////////////////////////////////////
|
|
// Copyright (C) 2022 Jon Beniston, M7RCE //
|
|
// Copyright (C) 2020 Edouard Griffiths, F4EXB //
|
|
// //
|
|
// 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"
|
|
|
|
#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();
|
|
}
|
|
|
|
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)
|
|
{
|
|
if (m_contextMenuType == ContextMenuChannelSettings)
|
|
{
|
|
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);
|
|
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);
|
|
connect(combo, &QComboBox::currentTextChanged,
|
|
[=] (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)
|
|
{
|
|
(void) checked;
|
|
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;
|
|
|
|
default:
|
|
qDebug() << "RemoteControlGUI::createControls: Unexpected type for control.";
|
|
break;
|
|
|
|
}
|
|
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))
|
|
{
|
|
if ((QMetaType::Type)value.type() == QMetaType::QString)
|
|
{
|
|
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"))
|
|
{
|
|
formattedValue = QString::asprintf(format.toUtf8(), value.toString().toUtf8().data());
|
|
}
|
|
else if (format.contains("%d") || format.contains("%u") || format.contains("%x") || format.contains("%X"))
|
|
{
|
|
formattedValue = QString::asprintf(format.toUtf8(), value.toInt());
|
|
}
|
|
else if (((QMetaType::Type)value.type() == QMetaType::Double) || ((QMetaType::Type)value.type() == QMetaType::Float))
|
|
{
|
|
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);
|
|
}
|