mirror of
https://github.com/opentx/opentx.git
synced 2025-07-25 01:05:10 +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:
parent
7b12c99a0b
commit
9e4a0680ab
6 changed files with 213 additions and 42 deletions
|
@ -27,9 +27,11 @@
|
|||
#include "radiodata.h"
|
||||
#include "simulator.h"
|
||||
|
||||
#include <QScrollBar>
|
||||
|
||||
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) :
|
||||
QWidget(parent),
|
||||
|
@ -42,7 +44,12 @@ RadioOutputsWidget::RadioOutputsWidget(SimulatorInterface * simulator, Firmware
|
|||
|
||||
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::channelMixValueChange, this, &RadioOutputsWidget::onChannelMixValueChange);
|
||||
connect(m_simulator, &SimulatorInterface::virtualSwValueChange, this, &RadioOutputsWidget::onVirtSwValueChange);
|
||||
connect(m_simulator, &SimulatorInterface::gVarValueChange, this, &RadioOutputsWidget::onGVarValueChange);
|
||||
connect(m_simulator, &SimulatorInterface::phaseChanged, this, &RadioOutputsWidget::onPhaseChanged);
|
||||
|
@ -69,7 +76,8 @@ void RadioOutputsWidget::changeEvent(QEvent *e)
|
|||
|
||||
void RadioOutputsWidget::start()
|
||||
{
|
||||
setupChannelsDisplay();
|
||||
setupChannelsDisplay(false);
|
||||
setupChannelsDisplay(true);
|
||||
setupGVarsDisplay();
|
||||
setupLsDisplay();
|
||||
}
|
||||
|
@ -91,6 +99,8 @@ void RadioOutputsWidget::saveState()
|
|||
stream << m_savedViewStateVersion
|
||||
<< ui->btnLogiSw->isChecked() << ui->btnGlobalVars->isChecked() << ui->btnChannels->isChecked()
|
||||
<< ui->splitter->saveState();
|
||||
// view state version 2
|
||||
stream << ui->btnMixes->isChecked();
|
||||
|
||||
SimulatorOptions opts = g.profile[m_radioProfileId].simulatorOptions();
|
||||
opts.radioOutputsState = state;
|
||||
|
@ -101,29 +111,39 @@ void RadioOutputsWidget::restoreState()
|
|||
{
|
||||
quint16 ver = 0;
|
||||
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;
|
||||
QDataStream stream(state);
|
||||
|
||||
stream >> ver;
|
||||
if (ver && ver <= m_savedViewStateVersion)
|
||||
if (ver && ver <= m_savedViewStateVersion) {
|
||||
stream >> ls >> gv >> ch >> splitterState;
|
||||
if (ver >= 2)
|
||||
stream >> mx;
|
||||
}
|
||||
|
||||
ui->btnLogiSw->setChecked(ls);
|
||||
ui->btnGlobalVars->setChecked(gv);
|
||||
ui->btnChannels->setChecked(ch);
|
||||
ui->btnMixes->setChecked(mx);
|
||||
if (!splitterState.isEmpty())
|
||||
ui->splitter->restoreState(splitterState);
|
||||
}
|
||||
|
||||
void RadioOutputsWidget::setupChannelsDisplay()
|
||||
void RadioOutputsWidget::setupChannelsDisplay(bool mixes)
|
||||
{
|
||||
int outputs = std::min(32, m_firmware->getCapability(Capability(Outputs)));
|
||||
|
||||
// delete old widgets if already exist
|
||||
m_channelsMap.clear();
|
||||
|
||||
QWidget * oldChanW = ui->channelsScroll->takeWidget();
|
||||
QWidget * oldChanW = nullptr;
|
||||
if (mixes) {
|
||||
m_mixesMap.clear();
|
||||
oldChanW = ui->mixersScroll->takeWidget();
|
||||
}
|
||||
else {
|
||||
m_channelsMap.clear();
|
||||
oldChanW = ui->channelsScroll->takeWidget();
|
||||
}
|
||||
if (oldChanW)
|
||||
oldChanW->deleteLater();
|
||||
|
||||
|
@ -136,7 +156,10 @@ void RadioOutputsWidget::setupChannelsDisplay()
|
|||
channelsLayout->setVerticalSpacing(3);
|
||||
channelsLayout->setContentsMargins(5, 5, 5, 5);
|
||||
|
||||
ui->channelsScroll->setWidget(channelsWidget);
|
||||
if (mixes)
|
||||
ui->mixersScroll->setWidget(channelsWidget);
|
||||
else
|
||||
ui->channelsScroll->setWidget(channelsWidget);
|
||||
|
||||
// populate outputs
|
||||
int column = 0;
|
||||
|
@ -168,7 +191,10 @@ void RadioOutputsWidget::setupChannelsDisplay()
|
|||
|
||||
++column;
|
||||
|
||||
m_channelsMap.insert(i, QPair<QLabel *, QSlider *>(value, slider));
|
||||
if (mixes)
|
||||
m_mixesMap.insert(i, QPair<QLabel *, QSlider *>(value, slider));
|
||||
else
|
||||
m_channelsMap.insert(i, QPair<QLabel *, QSlider *>(value, slider));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -273,14 +299,30 @@ QWidget * RadioOutputsWidget::createLogicalSwitch(QWidget * parent, int switchNo
|
|||
return swtch;
|
||||
}
|
||||
|
||||
void RadioOutputsWidget::onChannelOutValueChange(quint8 index, qint32 value)
|
||||
void RadioOutputsWidget::onChannelOutValueChange(quint8 index, qint32 value, qint32 limit)
|
||||
{
|
||||
if (m_channelsMap.contains(index)) {
|
||||
QPair<QLabel *, QSlider *> ch = m_channelsMap.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(1024, qMax(-1024, 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)
|
||||
|
|
|
@ -56,14 +56,15 @@ class RadioOutputsWidget : public QWidget
|
|||
protected slots:
|
||||
void saveState();
|
||||
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 onGVarValueChange(quint8 index, qint32 value);
|
||||
void onPhaseChanged(qint32 phase, const QString &);
|
||||
|
||||
protected:
|
||||
void changeEvent(QEvent *e);
|
||||
void setupChannelsDisplay();
|
||||
void setupChannelsDisplay(bool mixes = false);
|
||||
void setupLsDisplay();
|
||||
void setupGVarsDisplay();
|
||||
QWidget * createLogicalSwitch(QWidget * parent, int switchNo);
|
||||
|
@ -72,6 +73,7 @@ class RadioOutputsWidget : public QWidget
|
|||
Firmware * m_firmware;
|
||||
|
||||
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, QHash<int, QLabel *> > m_globalVarsMap; // m_globalVarsMap[gvarIndex][fmodeIndex] = QLabel*
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>762</width>
|
||||
<height>436</height>
|
||||
<height>452</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
|
@ -126,6 +126,25 @@
|
|||
</property>
|
||||
</widget>
|
||||
</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>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
|
@ -219,7 +238,7 @@ c</string>
|
|||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>740</width>
|
||||
<height>85</height>
|
||||
<height>68</height>
|
||||
</rect>
|
||||
</property>
|
||||
</widget>
|
||||
|
@ -297,7 +316,7 @@ l</string>
|
|||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>739</width>
|
||||
<height>101</height>
|
||||
<height>78</height>
|
||||
</rect>
|
||||
</property>
|
||||
</widget>
|
||||
|
@ -374,7 +393,81 @@ s</string>
|
|||
<x>0</x>
|
||||
<y>0</y>
|
||||
<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>
|
||||
</property>
|
||||
</widget>
|
||||
|
@ -436,5 +529,21 @@ s</string>
|
|||
</hint>
|
||||
</hints>
|
||||
</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>
|
||||
</ui>
|
||||
|
|
|
@ -158,8 +158,8 @@ class SimulatorInterface : public QObject
|
|||
void runtimeError(const QString & error);
|
||||
void lcdChange(bool backlightEnable);
|
||||
void phaseChanged(qint8 phase, const QString & name);
|
||||
void channelOutValueChange(quint8 index, qint32 value);
|
||||
void channelMixValueChange(quint8 index, qint32 value);
|
||||
void channelOutValueChange(quint8 index, qint32 value, qint32 limit);
|
||||
void channelMixValueChange(quint8 index, qint32 value, qint32 limit);
|
||||
void virtualSwValueChange(quint8 index, qint32 value);
|
||||
void trimValueChange(quint8 index, qint32 value);
|
||||
void trimRangeChange(quint8 index, qint32 min, qint16 max);
|
||||
|
|
|
@ -80,35 +80,52 @@ RadioOutputsWidget QLabel[heading=true] {
|
|||
font-size: 8pt;
|
||||
}
|
||||
|
||||
/* Channel output indicator sliders */
|
||||
/* Output indicator sliders common styles */
|
||||
|
||||
RadioOutputsWidget #channelsWidget QSlider::groove:vertical {
|
||||
RadioOutputsWidget QSlider::groove:vertical {
|
||||
width: 18px;
|
||||
background-color: transparent;
|
||||
border-image: url(:/images/simulator/icons/svg/line_horiz.svg) 0 0 0 0 stretch round;
|
||||
}
|
||||
|
||||
RadioOutputsWidget #channelsWidget QSlider::add-page:vertical,
|
||||
RadioOutputsWidget #channelsWidget QSlider::sub-page:vertical {
|
||||
RadioOutputsWidget QSlider::add-page:vertical,
|
||||
RadioOutputsWidget QSlider::sub-page:vertical {
|
||||
border: 1px solid #777;
|
||||
margin: 0 5px;
|
||||
}
|
||||
|
||||
RadioOutputsWidget #channelsWidget QSlider::sub-page:vertical {
|
||||
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 {
|
||||
RadioOutputsWidget QSlider::handle:vertical:disabled {
|
||||
background-color: darkgreen;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 1px;
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
|
@ -473,15 +473,16 @@ void OpenTxSimulator::checkOutputsChanged()
|
|||
{
|
||||
static TxOutputs lastOutputs;
|
||||
static size_t chansDim = DIM(channelOutputs);
|
||||
const static int16_t limit = 512 * 2;
|
||||
qint32 tmpVal;
|
||||
uint8_t i, idx;
|
||||
uint8_t phase = getFlightMode(); // opentx.cpp
|
||||
uint8_t mode = getStickMode();
|
||||
const uint8_t phase = getFlightMode(); // opentx.cpp
|
||||
const uint8_t mode = getStickMode();
|
||||
|
||||
for (i=0; i < chansDim; i++) {
|
||||
if (lastOutputs.chans[i] != channelOutputs[i] || m_resetOutputsData) {
|
||||
emit channelOutValueChange(i, channelOutputs[i]);
|
||||
emit channelMixValueChange(i, ex_chans[i]);
|
||||
emit channelOutValueChange(i, channelOutputs[i], (g_model.extendedLimits ? limit * LIMIT_EXT_PERCENT / 100 : limit));
|
||||
emit channelMixValueChange(i, ex_chans[i], limit * 2);
|
||||
emit outputValueChange(OUTPUT_SRC_CHAN_OUT, i, channelOutputs[i]);
|
||||
emit outputValueChange(OUTPUT_SRC_CHAN_MIX, i, ex_chans[i]);
|
||||
lastOutputs.chans[i] = channelOutputs[i];
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue