1
0
Fork 0
mirror of https://github.com/opentx/opentx.git synced 2025-07-26 17:55:19 +03:00

[Simulator] Add mixes display to Radio Outputs widget (#5811)

* [Simulator] Add mixes output display to RadioOutputsWidget (closes #2655).

* Add proper limits reporting & representation for channel and mix values in RadioOutputsWidget.
This commit is contained in:
Max Paperno 2018-04-12 14:02:27 -04:00 committed by Andre Bernet
parent 7b12c99a0b
commit 9e4a0680ab
6 changed files with 213 additions and 42 deletions

View file

@ -27,9 +27,11 @@
#include "radiodata.h" #include "radiodata.h"
#include "simulator.h" #include "simulator.h"
#include <QScrollBar>
extern AppData g; // ensure what "g" means extern AppData g; // ensure what "g" means
const quint16 RadioOutputsWidget::m_savedViewStateVersion = 1; const quint16 RadioOutputsWidget::m_savedViewStateVersion = 2;
RadioOutputsWidget::RadioOutputsWidget(SimulatorInterface * simulator, Firmware * firmware, QWidget *parent) : RadioOutputsWidget::RadioOutputsWidget(SimulatorInterface * simulator, Firmware * firmware, QWidget *parent) :
QWidget(parent), QWidget(parent),
@ -42,7 +44,12 @@ RadioOutputsWidget::RadioOutputsWidget(SimulatorInterface * simulator, Firmware
restoreState(); restoreState();
// link the channels and mixes display horizontal scroll
connect(ui->channelsScroll->horizontalScrollBar(), &QScrollBar::sliderMoved, ui->mixersScroll->horizontalScrollBar(), &QScrollBar::setValue);
connect(ui->mixersScroll->horizontalScrollBar(), &QScrollBar::sliderMoved, ui->channelsScroll->horizontalScrollBar(), &QScrollBar::setValue);
connect(m_simulator, &SimulatorInterface::channelOutValueChange, this, &RadioOutputsWidget::onChannelOutValueChange); connect(m_simulator, &SimulatorInterface::channelOutValueChange, this, &RadioOutputsWidget::onChannelOutValueChange);
connect(m_simulator, &SimulatorInterface::channelMixValueChange, this, &RadioOutputsWidget::onChannelMixValueChange);
connect(m_simulator, &SimulatorInterface::virtualSwValueChange, this, &RadioOutputsWidget::onVirtSwValueChange); connect(m_simulator, &SimulatorInterface::virtualSwValueChange, this, &RadioOutputsWidget::onVirtSwValueChange);
connect(m_simulator, &SimulatorInterface::gVarValueChange, this, &RadioOutputsWidget::onGVarValueChange); connect(m_simulator, &SimulatorInterface::gVarValueChange, this, &RadioOutputsWidget::onGVarValueChange);
connect(m_simulator, &SimulatorInterface::phaseChanged, this, &RadioOutputsWidget::onPhaseChanged); connect(m_simulator, &SimulatorInterface::phaseChanged, this, &RadioOutputsWidget::onPhaseChanged);
@ -69,7 +76,8 @@ void RadioOutputsWidget::changeEvent(QEvent *e)
void RadioOutputsWidget::start() void RadioOutputsWidget::start()
{ {
setupChannelsDisplay(); setupChannelsDisplay(false);
setupChannelsDisplay(true);
setupGVarsDisplay(); setupGVarsDisplay();
setupLsDisplay(); setupLsDisplay();
} }
@ -91,6 +99,8 @@ void RadioOutputsWidget::saveState()
stream << m_savedViewStateVersion stream << m_savedViewStateVersion
<< ui->btnLogiSw->isChecked() << ui->btnGlobalVars->isChecked() << ui->btnChannels->isChecked() << ui->btnLogiSw->isChecked() << ui->btnGlobalVars->isChecked() << ui->btnChannels->isChecked()
<< ui->splitter->saveState(); << ui->splitter->saveState();
// view state version 2
stream << ui->btnMixes->isChecked();
SimulatorOptions opts = g.profile[m_radioProfileId].simulatorOptions(); SimulatorOptions opts = g.profile[m_radioProfileId].simulatorOptions();
opts.radioOutputsState = state; opts.radioOutputsState = state;
@ -101,29 +111,39 @@ void RadioOutputsWidget::restoreState()
{ {
quint16 ver = 0; quint16 ver = 0;
QByteArray splitterState; QByteArray splitterState;
bool ls = true, gv = true, ch = true; bool ls = true, gv = true, ch = true, mx = false;
QByteArray state = g.profile[m_radioProfileId].simulatorOptions().radioOutputsState; QByteArray state = g.profile[m_radioProfileId].simulatorOptions().radioOutputsState;
QDataStream stream(state); QDataStream stream(state);
stream >> ver; stream >> ver;
if (ver && ver <= m_savedViewStateVersion) if (ver && ver <= m_savedViewStateVersion) {
stream >> ls >> gv >> ch >> splitterState; stream >> ls >> gv >> ch >> splitterState;
if (ver >= 2)
stream >> mx;
}
ui->btnLogiSw->setChecked(ls); ui->btnLogiSw->setChecked(ls);
ui->btnGlobalVars->setChecked(gv); ui->btnGlobalVars->setChecked(gv);
ui->btnChannels->setChecked(ch); ui->btnChannels->setChecked(ch);
ui->btnMixes->setChecked(mx);
if (!splitterState.isEmpty()) if (!splitterState.isEmpty())
ui->splitter->restoreState(splitterState); ui->splitter->restoreState(splitterState);
} }
void RadioOutputsWidget::setupChannelsDisplay() void RadioOutputsWidget::setupChannelsDisplay(bool mixes)
{ {
int outputs = std::min(32, m_firmware->getCapability(Capability(Outputs))); int outputs = std::min(32, m_firmware->getCapability(Capability(Outputs)));
// delete old widgets if already exist // delete old widgets if already exist
QWidget * oldChanW = nullptr;
if (mixes) {
m_mixesMap.clear();
oldChanW = ui->mixersScroll->takeWidget();
}
else {
m_channelsMap.clear(); m_channelsMap.clear();
oldChanW = ui->channelsScroll->takeWidget();
QWidget * oldChanW = ui->channelsScroll->takeWidget(); }
if (oldChanW) if (oldChanW)
oldChanW->deleteLater(); oldChanW->deleteLater();
@ -136,6 +156,9 @@ void RadioOutputsWidget::setupChannelsDisplay()
channelsLayout->setVerticalSpacing(3); channelsLayout->setVerticalSpacing(3);
channelsLayout->setContentsMargins(5, 5, 5, 5); channelsLayout->setContentsMargins(5, 5, 5, 5);
if (mixes)
ui->mixersScroll->setWidget(channelsWidget);
else
ui->channelsScroll->setWidget(channelsWidget); ui->channelsScroll->setWidget(channelsWidget);
// populate outputs // populate outputs
@ -168,6 +191,9 @@ void RadioOutputsWidget::setupChannelsDisplay()
++column; ++column;
if (mixes)
m_mixesMap.insert(i, QPair<QLabel *, QSlider *>(value, slider));
else
m_channelsMap.insert(i, QPair<QLabel *, QSlider *>(value, slider)); m_channelsMap.insert(i, QPair<QLabel *, QSlider *>(value, slider));
} }
} }
@ -273,14 +299,30 @@ QWidget * RadioOutputsWidget::createLogicalSwitch(QWidget * parent, int switchNo
return swtch; return swtch;
} }
void RadioOutputsWidget::onChannelOutValueChange(quint8 index, qint32 value) void RadioOutputsWidget::onChannelOutValueChange(quint8 index, qint32 value, qint32 limit)
{ {
if (m_channelsMap.contains(index)) { if (m_channelsMap.contains(index)) {
QPair<QLabel *, QSlider *> ch = m_channelsMap.value(index); QPair<QLabel *, QSlider *> ch = m_channelsMap.value(index);
ch.first->setText(QString("%1%").arg(calcRESXto100(value))); if (ch.second->maximum() != limit) {
ch.second->setValue(qMin(1024, qMax(-1024, value))); ch.second->setMaximum(limit);
ch.second->setMinimum(-limit);
}
ch.first->setText(QString("%1%").arg(calcRESXto100(value)));
ch.second->setValue(qMin(limit, qMax(-limit, value)));
}
}
void RadioOutputsWidget::onChannelMixValueChange(quint8 index, qint32 value, qint32 limit)
{
if (m_mixesMap.contains(index)) {
QPair<QLabel *, QSlider *> ch = m_mixesMap.value(index);
if (ch.second->maximum() != limit) {
ch.second->setMaximum(limit);
ch.second->setMinimum(-limit);
}
ch.first->setText(QString("%1%").arg(calcRESXto100(value)));
ch.second->setValue(qMin(limit, qMax(-limit, value)));
} }
//qDebug() << index << value;
} }
void RadioOutputsWidget::onVirtSwValueChange(quint8 index, qint32 value) void RadioOutputsWidget::onVirtSwValueChange(quint8 index, qint32 value)

View file

@ -56,14 +56,15 @@ class RadioOutputsWidget : public QWidget
protected slots: protected slots:
void saveState(); void saveState();
void restoreState(); void restoreState();
void onChannelOutValueChange(quint8 index, qint32 value); void onChannelOutValueChange(quint8 index, qint32 value, qint32 limit);
void onChannelMixValueChange(quint8 index, qint32 value, qint32 limit);
void onVirtSwValueChange(quint8 index, qint32 value); void onVirtSwValueChange(quint8 index, qint32 value);
void onGVarValueChange(quint8 index, qint32 value); void onGVarValueChange(quint8 index, qint32 value);
void onPhaseChanged(qint32 phase, const QString &); void onPhaseChanged(qint32 phase, const QString &);
protected: protected:
void changeEvent(QEvent *e); void changeEvent(QEvent *e);
void setupChannelsDisplay(); void setupChannelsDisplay(bool mixes = false);
void setupLsDisplay(); void setupLsDisplay();
void setupGVarsDisplay(); void setupGVarsDisplay();
QWidget * createLogicalSwitch(QWidget * parent, int switchNo); QWidget * createLogicalSwitch(QWidget * parent, int switchNo);
@ -72,6 +73,7 @@ class RadioOutputsWidget : public QWidget
Firmware * m_firmware; Firmware * m_firmware;
QHash<int, QPair<QLabel *, QSlider *> > m_channelsMap; // m_channelsMap[chanIndex] = {QLabel*, QSlider*} QHash<int, QPair<QLabel *, QSlider *> > m_channelsMap; // m_channelsMap[chanIndex] = {QLabel*, QSlider*}
QHash<int, QPair<QLabel *, QSlider *> > m_mixesMap; // m_mixesMap[chanIndex] = {QLabel*, QSlider*}
QHash<int, QLabel *> m_logicSwitchMap; // m_logicSwitchMap[lsIndex] = QLabel* QHash<int, QLabel *> m_logicSwitchMap; // m_logicSwitchMap[lsIndex] = QLabel*
QHash<int, QHash<int, QLabel *> > m_globalVarsMap; // m_globalVarsMap[gvarIndex][fmodeIndex] = QLabel* QHash<int, QHash<int, QLabel *> > m_globalVarsMap; // m_globalVarsMap[gvarIndex][fmodeIndex] = QLabel*

View file

@ -7,7 +7,7 @@
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>762</width> <width>762</width>
<height>436</height> <height>452</height>
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
@ -126,6 +126,25 @@
</property> </property>
</widget> </widget>
</item> </item>
<item>
<widget class="QToolButton" name="btnMixes">
<property name="text">
<string>Mix Outputs</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<property name="checked">
<bool>true</bool>
</property>
<property name="toolButtonStyle">
<enum>Qt::ToolButtonTextBesideIcon</enum>
</property>
<property name="autoRaise">
<bool>true</bool>
</property>
</widget>
</item>
<item> <item>
<spacer name="horizontalSpacer"> <spacer name="horizontalSpacer">
<property name="orientation"> <property name="orientation">
@ -219,7 +238,7 @@ c</string>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>740</width> <width>740</width>
<height>85</height> <height>68</height>
</rect> </rect>
</property> </property>
</widget> </widget>
@ -297,7 +316,7 @@ l</string>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>739</width> <width>739</width>
<height>101</height> <height>78</height>
</rect> </rect>
</property> </property>
</widget> </widget>
@ -374,7 +393,81 @@ s</string>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>739</width> <width>739</width>
<height>194</height> <height>128</height>
</rect>
</property>
</widget>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="mixersWidget" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>3</verstretch>
</sizepolicy>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_11">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>1</number>
</property>
<property name="topMargin">
<number>1</number>
</property>
<property name="rightMargin">
<number>1</number>
</property>
<property name="bottomMargin">
<number>1</number>
</property>
<item>
<widget class="QLabel" name="label_11">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="midLineWidth">
<number>3</number>
</property>
<property name="text">
<string>M
i
x
e
s</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="heading" stdset="0">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QScrollArea" name="mixersScroll">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="widgetResizable">
<bool>true</bool>
</property>
<widget class="QWidget" name="scrollAreaWidgetContents_12">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>738</width>
<height>118</height>
</rect> </rect>
</property> </property>
</widget> </widget>
@ -436,5 +529,21 @@ s</string>
</hint> </hint>
</hints> </hints>
</connection> </connection>
<connection>
<sender>btnMixes</sender>
<signal>toggled(bool)</signal>
<receiver>mixersWidget</receiver>
<slot>setVisible(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>370</x>
<y>17</y>
</hint>
<hint type="destinationlabel">
<x>380</x>
<y>384</y>
</hint>
</hints>
</connection>
</connections> </connections>
</ui> </ui>

View file

@ -158,8 +158,8 @@ class SimulatorInterface : public QObject
void runtimeError(const QString & error); void runtimeError(const QString & error);
void lcdChange(bool backlightEnable); void lcdChange(bool backlightEnable);
void phaseChanged(qint8 phase, const QString & name); void phaseChanged(qint8 phase, const QString & name);
void channelOutValueChange(quint8 index, qint32 value); void channelOutValueChange(quint8 index, qint32 value, qint32 limit);
void channelMixValueChange(quint8 index, qint32 value); void channelMixValueChange(quint8 index, qint32 value, qint32 limit);
void virtualSwValueChange(quint8 index, qint32 value); void virtualSwValueChange(quint8 index, qint32 value);
void trimValueChange(quint8 index, qint32 value); void trimValueChange(quint8 index, qint32 value);
void trimRangeChange(quint8 index, qint32 min, qint16 max); void trimRangeChange(quint8 index, qint32 min, qint16 max);

View file

@ -80,35 +80,52 @@ RadioOutputsWidget QLabel[heading=true] {
font-size: 8pt; font-size: 8pt;
} }
/* Channel output indicator sliders */ /* Output indicator sliders common styles */
RadioOutputsWidget #channelsWidget QSlider::groove:vertical { RadioOutputsWidget QSlider::groove:vertical {
width: 18px; width: 18px;
background-color: transparent; background-color: transparent;
border-image: url(:/images/simulator/icons/svg/line_horiz.svg) 0 0 0 0 stretch round; border-image: url(:/images/simulator/icons/svg/line_horiz.svg) 0 0 0 0 stretch round;
} }
RadioOutputsWidget #channelsWidget QSlider::add-page:vertical, RadioOutputsWidget QSlider::add-page:vertical,
RadioOutputsWidget #channelsWidget QSlider::sub-page:vertical { RadioOutputsWidget QSlider::sub-page:vertical {
border: 1px solid #777; border: 1px solid #777;
margin: 0 5px; margin: 0 5px;
} }
RadioOutputsWidget #channelsWidget QSlider::sub-page:vertical { RadioOutputsWidget QSlider::handle:vertical:disabled {
background: qlineargradient(x1: .4, y1: 0, x2: 1, y2: 1, stop: 0 #bbb, stop:1 #fff);
border-top-left-radius: 4px;
border-top-right-radius: 4px;
}
RadioOutputsWidget #channelsWidget QSlider::add-page:vertical {
background: qlineargradient(x1: .6, y1: 1, x2: 0, y2: 0, stop:0 #55f, stop: 1 #eef);
border-bottom-left-radius: 4px;
border-bottom-right-radius: 4px;
}
RadioOutputsWidget #channelsWidget QSlider::handle:vertical:disabled {
background-color: darkgreen; background-color: darkgreen;
border: 1px solid #ccc; border: 1px solid #ccc;
border-radius: 1px; border-radius: 1px;
height: 3px; height: 3px;
} }
RadioOutputsWidget QSlider::sub-page:vertical {
border-top-left-radius: 4px;
border-top-right-radius: 4px;
}
RadioOutputsWidget QSlider::add-page:vertical {
border-bottom-left-radius: 4px;
border-bottom-right-radius: 4px;
}
/* Channel output indicator sliders */
RadioOutputsWidget #channelsWidget QSlider::sub-page:vertical {
background: qlineargradient(x1: .4, y1: 0, x2: 1, y2: 1, stop: 0 #bbb, stop:1 #fff);
}
RadioOutputsWidget #channelsWidget QSlider::add-page:vertical {
background: qlineargradient(x1: .6, y1: 1, x2: 0, y2: 0, stop:0 #55f, stop: 1 #eef);
}
/* Mixes output indicator sliders */
RadioOutputsWidget #mixersWidget QSlider::sub-page:vertical {
background: qlineargradient(x1: .4, y1: 0, x2: 1, y2: 1, stop: 0 #bbb, stop:1 #686868);
}
RadioOutputsWidget #mixersWidget QSlider::add-page:vertical {
background: qlineargradient(x1: .6, y1: 1, x2: 0, y2: 0, stop:0 #9E38FF, stop: 1 #F1DDFF);
}

View file

@ -473,15 +473,16 @@ void OpenTxSimulator::checkOutputsChanged()
{ {
static TxOutputs lastOutputs; static TxOutputs lastOutputs;
static size_t chansDim = DIM(channelOutputs); static size_t chansDim = DIM(channelOutputs);
const static int16_t limit = 512 * 2;
qint32 tmpVal; qint32 tmpVal;
uint8_t i, idx; uint8_t i, idx;
uint8_t phase = getFlightMode(); // opentx.cpp const uint8_t phase = getFlightMode(); // opentx.cpp
uint8_t mode = getStickMode(); const uint8_t mode = getStickMode();
for (i=0; i < chansDim; i++) { for (i=0; i < chansDim; i++) {
if (lastOutputs.chans[i] != channelOutputs[i] || m_resetOutputsData) { if (lastOutputs.chans[i] != channelOutputs[i] || m_resetOutputsData) {
emit channelOutValueChange(i, channelOutputs[i]); emit channelOutValueChange(i, channelOutputs[i], (g_model.extendedLimits ? limit * LIMIT_EXT_PERCENT / 100 : limit));
emit channelMixValueChange(i, ex_chans[i]); emit channelMixValueChange(i, ex_chans[i], limit * 2);
emit outputValueChange(OUTPUT_SRC_CHAN_OUT, i, channelOutputs[i]); emit outputValueChange(OUTPUT_SRC_CHAN_OUT, i, channelOutputs[i]);
emit outputValueChange(OUTPUT_SRC_CHAN_MIX, i, ex_chans[i]); emit outputValueChange(OUTPUT_SRC_CHAN_MIX, i, ex_chans[i]);
lastOutputs.chans[i] = channelOutputs[i]; lastOutputs.chans[i] = channelOutputs[i];