[companion] Adjust GVAR not possible in global functions (fix #5425)
[opentx.git] / companion / src / simulation / radiooutputswidget.cpp
blob646f16b327bf449ca5e94c3c30742d66f22e3c8f
1 /*
2 * Copyright (C) OpenTX
4 * Based on code named
5 * th9x - http://code.google.com/p/th9x
6 * er9x - http://code.google.com/p/er9x
7 * gruvin9x - http://code.google.com/p/gruvin9x
9 * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License version 2 as
13 * published by the Free Software Foundation.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
21 #include "radiooutputswidget.h"
22 #include "ui_radiooutputswidget.h"
24 #include "appdata.h"
25 #include "constants.h"
26 #include "eeprominterface.h"
27 #include "radiodata.h"
28 #include "simulator.h"
30 extern AppData g; // ensure what "g" means
32 const quint16 RadioOutputsWidget::m_savedViewStateVersion = 1;
34 RadioOutputsWidget::RadioOutputsWidget(SimulatorInterface * simulator, Firmware * firmware, QWidget *parent) :
35 QWidget(parent),
36 m_simulator(simulator),
37 m_firmware(firmware),
38 m_radioProfileId(g.sessionId()),
39 ui(new Ui::RadioOutputsWidget)
41 ui->setupUi(this);
43 restoreState();
45 connect(m_simulator, &SimulatorInterface::channelOutValueChange, this, &RadioOutputsWidget::onChannelOutValueChange);
46 connect(m_simulator, &SimulatorInterface::virtualSwValueChange, this, &RadioOutputsWidget::onVirtSwValueChange);
47 connect(m_simulator, &SimulatorInterface::gVarValueChange, this, &RadioOutputsWidget::onGVarValueChange);
48 connect(m_simulator, &SimulatorInterface::phaseChanged, this, &RadioOutputsWidget::onPhaseChanged);
51 RadioOutputsWidget::~RadioOutputsWidget()
53 //stop();
54 saveState();
55 delete ui;
58 void RadioOutputsWidget::changeEvent(QEvent *e)
60 QWidget::changeEvent(e);
61 switch (e->type()) {
62 case QEvent::LanguageChange:
63 ui->retranslateUi(this);
64 break;
65 default:
66 break;
70 void RadioOutputsWidget::start()
72 setupChannelsDisplay();
73 setupGVarsDisplay();
74 setupLsDisplay();
77 //void RadioOutputsWidget::stop()
78 //{
79 //}
81 void RadioOutputsWidget::restart()
83 //stop();
84 start();
87 void RadioOutputsWidget::saveState()
89 QByteArray state;
90 QDataStream stream(&state, QIODevice::WriteOnly);
91 stream << m_savedViewStateVersion
92 << ui->btnLogiSw->isChecked() << ui->btnGlobalVars->isChecked() << ui->btnChannels->isChecked()
93 << ui->splitter->saveState();
95 SimulatorOptions opts = g.profile[m_radioProfileId].simulatorOptions();
96 opts.radioOutputsState = state;
97 g.profile[m_radioProfileId].simulatorOptions(opts);
100 void RadioOutputsWidget::restoreState()
102 quint16 ver = 0;
103 QByteArray splitterState;
104 bool ls = true, gv = true, ch = true;
105 QByteArray state = g.profile[m_radioProfileId].simulatorOptions().radioOutputsState;
106 QDataStream stream(state);
108 stream >> ver;
109 if (ver && ver <= m_savedViewStateVersion)
110 stream >> ls >> gv >> ch >> splitterState;
112 ui->btnLogiSw->setChecked(ls);
113 ui->btnGlobalVars->setChecked(gv);
114 ui->btnChannels->setChecked(ch);
115 if (!splitterState.isEmpty())
116 ui->splitter->restoreState(splitterState);
119 void RadioOutputsWidget::setupChannelsDisplay()
121 int outputs = std::min(32, m_firmware->getCapability(Capability(Outputs)));
123 // delete old widgets if already exist
124 m_channelsMap.clear();
126 QWidget * oldChanW = ui->channelsScroll->takeWidget();
127 if (oldChanW)
128 oldChanW->deleteLater();
130 if (!outputs)
131 return;
133 QWidget * channelsWidget = new QWidget();
134 QGridLayout * channelsLayout = new QGridLayout(channelsWidget);
135 channelsLayout->setHorizontalSpacing(4);
136 channelsLayout->setVerticalSpacing(3);
137 channelsLayout->setContentsMargins(5, 5, 5, 5);
139 ui->channelsScroll->setWidget(channelsWidget);
141 // populate outputs
142 int column = 0;
143 for (int i=0; i < outputs; i++) {
144 QLabel * label = new QLabel(channelsWidget);
145 label->setText(" " + RawSource(SOURCE_TYPE_CH, i).toString() + " ");
146 label->setAlignment(Qt::AlignCenter);
147 label->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
148 channelsLayout->addWidget(label, 0, column, 1, 1);
150 QSlider * slider = new QSlider(channelsWidget);
151 slider->setEnabled(false);
152 slider->setMinimum(-1024);
153 slider->setMaximum(1024);
154 slider->setPageStep(128);
155 slider->setTracking(false);
156 slider->setOrientation(Qt::Vertical);
157 slider->setInvertedAppearance(false);
158 slider->setTickPosition(QSlider::TicksRight);
159 slider->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred);
160 channelsLayout->addWidget(slider, 2, column, 1, 1);
161 channelsLayout->setAlignment(slider, Qt::AlignHCenter);
163 QLabel * value = new QLabel(channelsWidget);
164 value->setMinimumSize(QSize(value->fontMetrics().size(Qt::TextSingleLine, "-100.0").width(), 0));
165 value->setAlignment(Qt::AlignCenter);
166 value->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
167 channelsLayout->addWidget(value, 1, column, 1, 1);
169 ++column;
171 m_channelsMap.insert(i, QPair<QLabel *, QSlider *>(value, slider));
175 void RadioOutputsWidget::setupGVarsDisplay()
177 int gvars = m_firmware->getCapability(Capability(Gvars));
178 int fmodes = m_firmware->getCapability(Capability(FlightModes));
180 // delete old widgets if already exist
181 m_globalVarsMap.clear();
183 QWidget * oldGv = ui->globalVarsScroll->takeWidget();
184 if (oldGv)
185 oldGv->deleteLater();
187 if (!gvars)
188 return;
190 QWidget * gvarsWidget = new QWidget();
191 QGridLayout * gvarsLayout = new QGridLayout(gvarsWidget);
192 gvarsLayout->setContentsMargins(5, 5, 5, 5);
193 gvarsLayout->setHorizontalSpacing(6);
194 gvarsLayout->setVerticalSpacing(3);
195 ui->globalVarsScroll->setWidget(gvarsWidget);
197 QPalette::ColorRole bgrole = QPalette::AlternateBase;
198 for (int fm=0; fm < fmodes; fm++) {
199 QLabel * label = new QLabel(gvarsWidget);
200 label->setText(QString("FM%1").arg(fm));
201 label->setAlignment(Qt::AlignCenter);
202 label->setBackgroundRole(bgrole);
203 gvarsLayout->addWidget(label, 0, fm+1);
205 QHash<int, QLabel *> fmMap;
206 for (int gv=0; gv < gvars; gv++) {
207 bgrole = ((gv % 2) ? QPalette::Background : QPalette::AlternateBase);
208 QLabel * label = new QLabel(gvarsWidget);
209 label->setText(QString("GV%1").arg(gv+1));
210 label->setAutoFillBackground(true);
211 label->setBackgroundRole(bgrole);
212 gvarsLayout->addWidget(label, gv+1, 0);
213 for (int fm=0; fm < fmodes; fm++) {
214 QLabel * value = new QLabel(gvarsWidget);
215 value->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
216 value->setAutoFillBackground(true);
217 value->setBackgroundRole(bgrole);
218 value->setText("0");
219 value->setStyleSheet("padding-right: .06em;");
220 gvarsLayout->addWidget(value, gv+1, fm+1);
222 fmMap.insert(fm, value);
224 m_globalVarsMap.insert(gv, fmMap);
228 void RadioOutputsWidget::setupLsDisplay()
230 int switches = m_firmware->getCapability(LogicalSwitches);
232 // delete old widgets if already exist
233 m_logicSwitchMap.clear();
235 QWidget * oldLsW = ui->logicalSwitchesScroll->takeWidget();
236 if (oldLsW)
237 oldLsW->deleteLater();
239 if (!switches)
240 return;
242 QWidget * logicalSwitches = new QWidget();
243 logicalSwitches->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Maximum);
244 QGridLayout * logicalSwitchesLayout = new QGridLayout(logicalSwitches);
245 logicalSwitchesLayout->setHorizontalSpacing(3);
246 logicalSwitchesLayout->setVerticalSpacing(2);
247 logicalSwitchesLayout->setContentsMargins(5, 5, 5, 5);
248 ui->logicalSwitchesScroll->setWidget(logicalSwitches);
250 // populate logical switches
251 int rows = switches / (switches > 16 ? 4 : 2);
252 for (int i=0; i < switches; i++) {
253 logicalSwitchesLayout->addWidget(createLogicalSwitch(logicalSwitches, i), i / rows, i % rows, 1, 1);
257 QWidget * RadioOutputsWidget::createLogicalSwitch(QWidget * parent, int switchNo)
259 QLabel * swtch = new QLabel(parent);
260 swtch->setAutoFillBackground(true);
261 swtch->setFrameStyle(QFrame::Panel | QFrame::Raised);
262 swtch->setLineWidth(2);
263 swtch->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
264 QFont font = swtch->font();
265 font.setBold(true);
266 swtch->setFont(font);
267 swtch->setMinimumWidth(swtch->fontMetrics().width("99") + 10);
268 font.setBold(false);
269 swtch->setFont(font);
270 swtch->setText(QString("%1").arg(switchNo+1, 2, 10, QChar('0')));
271 swtch->setAlignment(Qt::AlignCenter);
272 m_logicSwitchMap.insert(switchNo, swtch);
273 return swtch;
276 void RadioOutputsWidget::onChannelOutValueChange(quint8 index, qint32 value)
278 if (m_channelsMap.contains(index)) {
279 QPair<QLabel *, QSlider *> ch = m_channelsMap.value(index);
280 ch.first->setText(QString("%1%").arg(calcRESXto100(value)));
281 ch.second->setValue(qMin(1024, qMax(-1024, value)));
283 //qDebug() << index << value;
286 void RadioOutputsWidget::onVirtSwValueChange(quint8 index, qint32 value)
288 if (!m_logicSwitchMap.contains(index))
289 return;
291 QLabel * ls = m_logicSwitchMap.value(index);
292 ls->setBackgroundRole(value ? QPalette::Dark : QPalette::Background);
293 ls->setForegroundRole(value ? QPalette::BrightText : QPalette::WindowText);
294 ls->setFrameShadow(value ? QFrame::Sunken : QFrame::Raised);
295 QFont font = ls->font();
296 font.setBold((bool)value);
297 ls->setFont(font);
298 //qDebug() << index << value;
301 void RadioOutputsWidget::onGVarValueChange(quint8 index, qint32 value)
303 if (!m_globalVarsMap.contains(index))
304 return;
306 QHash<int, QLabel *> fmMap = m_globalVarsMap.value(index);
307 SimulatorInterface::gVarMode_t gv(value);
308 QLabel * lbl;
310 if (fmMap.contains(gv.mode) && (lbl = fmMap.value(gv.mode))) {
311 GVarData gvar;
312 gvar.prec = gv.prec;
313 gvar.unit = gv.unit;
314 lbl->setText(QString::number(gv.value * gvar.multiplierGet(), 'f', gv.prec) + gvar.unitToString());
316 //qDebug() << index << value << gv.mode << gv.value << gv.prec << gv.unit;
319 void RadioOutputsWidget::onPhaseChanged(qint32 phase, const QString &)
321 QPalette::ColorRole fgrole, bgrole;
322 QLabel * lbl;
323 QFont font;
324 QHash<int, QHash<int, QLabel *> >::const_iterator gv;
325 QHash<int, QLabel *>::const_iterator fm;
327 for (gv = m_globalVarsMap.constBegin(); gv != m_globalVarsMap.constEnd(); ++gv) {
328 for (fm = gv.value().constBegin(); fm != gv.value().constEnd(); ++fm) {
329 lbl = fm.value();
330 font = lbl->font();
331 if (fm.key() == phase) {
332 fgrole = QPalette::BrightText;
333 bgrole = QPalette::Dark;
334 font.setBold(true);
336 else {
337 fgrole = QPalette::WindowText;
338 bgrole = ((gv.key() % 2) ? QPalette::Background : QPalette::AlternateBase);
339 font.setBold(false);
341 lbl->setForegroundRole(fgrole);
342 lbl->setBackgroundRole(bgrole);
343 lbl->setFont(font);
346 //qDebug() << phase;