[Simulator] Further improvements (reload radio, momentary switches, etc.) (#4303)
* [Simulator] Add ability to reload all radio data w/out exiting simulator (will also adjust UI for any hardware changes); Refactor how keymap help text is generated.
* [Simulator] Only update channel/logical switch/GVar output displays if the corresponding tab is actually visible (further CPU usage reductions).
* [Simulator] Implement momentary toggle switches with "latch" function.
* [Simulator] Mouse wheel event over multi-position knobs now properly rotates them to detent positions.
* [Simulator] Fix mouse wheel event propagation after multi-position knob rotation; Cosmetics.
* [Simulator] Internals: Greatly improve object cleanup on exit; Refactor SimulatedUIWidget timer event triggering.
* [Simulator] Fix throttle stick position/lock not being set properly upon repeated launches from Companion.
* [Simulator] Fix build w/out SDL. KnobWidget cleanup.
* [Companion] Do NOT delete SimulatorInterface on simulator dialog exit (fix possible crash on dialog close).
* [Simulator] Ensure joystick is NULL at start.
* [Simulator] Fix/improve color blending on 4-bit screens with different BG colors; Cosmetics.
* [Simulator] Fix LCD screenshot folder path; Fix timer slot for Qt backwards compatibility.
* [TravisCI] Set Qt version to 5.3 to match release build servers.
* Fixed segfault when saving setup with no models defined [Horus]
* Fixed radio data import [Horus] (broken in 0f90ff0b65)
* [Simulator] Always keep toggle switch active while held with mouse button.
This commit is contained in:
committed by
Bertrand Songis
parent
f40e64c2aa
commit
de68db0905
+2
-2
@@ -11,11 +11,11 @@ python:
|
||||
|
||||
env:
|
||||
global:
|
||||
# - QT_BASE=53
|
||||
- QT_BASE=53
|
||||
# - QT_BASE=54
|
||||
# - QT_BASE=55
|
||||
# - QT_BASE=56
|
||||
- QT_BASE=57
|
||||
# - QT_BASE=57
|
||||
#- GCC_ARM=/opt/gcc-arm-none-eabi/bin
|
||||
- AVR_FLAVORS="AVR9X 9X GRUVIN9X MEGA2560"
|
||||
matrix:
|
||||
|
||||
@@ -11,7 +11,9 @@
|
||||
<file>images/maps.png</file>
|
||||
<file>images/track.png</file>
|
||||
<file>images/track0.png</file>
|
||||
<file>images/taranison.png</file>
|
||||
<file>images/taranison.png</file>
|
||||
<file>images/simulator/icons/8/lock-locked.png</file>
|
||||
<file>images/simulator/icons/8/lock-unlocked.png</file>
|
||||
<file>images/simulator/Horus/middle.png</file>
|
||||
<file>images/simulator/Horus/left.png</file>
|
||||
<file>images/simulator/Horus/right.png</file>
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 152 B |
Binary file not shown.
|
After Width: | Height: | Size: 154 B |
@@ -0,0 +1 @@
|
||||
Open Iconic collection, used under MIT License. https://github.com/iconic/open-iconic
|
||||
@@ -83,8 +83,9 @@ QPolygon SimulatedUIWidget::polyArc(int ctrX, int ctrY, int radius, int startAng
|
||||
return polygon;
|
||||
}
|
||||
|
||||
void SimulatedUIWidget::timedUpdate(unsigned loop)
|
||||
void SimulatedUIWidget::updateUi()
|
||||
{
|
||||
//static quint32 loop = 0;
|
||||
if (m_lcd->isVisible()) {
|
||||
bool lightEnable;
|
||||
if (m_simulator->lcdChanged(lightEnable)) {
|
||||
@@ -126,7 +127,7 @@ void SimulatedUIWidget::saveScreenshot(int idx)
|
||||
m_simuDialog->traceCallback("SIMULATOR ERROR - Cannot open screenshot folder, check your settings.\n");
|
||||
return;
|
||||
}
|
||||
fileName += QString("%1screenshot_%2.png").arg(dir.absolutePath(), QDateTime::currentDateTime().toString("yy-MM-dd_HH-mm-ss"));
|
||||
fileName += QString("%1/screenshot_%2.png").arg(dir.absolutePath(), QDateTime::currentDateTime().toString("yy-MM-dd_HH-mm-ss"));
|
||||
}
|
||||
m_lcd->makeScreenshot(fileName);
|
||||
}
|
||||
|
||||
@@ -62,7 +62,7 @@ class SimulatedUIWidget : public QWidget
|
||||
|
||||
public slots:
|
||||
|
||||
void timedUpdate(unsigned loop);
|
||||
void updateUi();
|
||||
void saveScreenshot(int idx = -1);
|
||||
void captureScreenshot() { saveScreenshot(); }
|
||||
void simulatorWheelEvent(qint8 steps);
|
||||
|
||||
@@ -75,7 +75,8 @@ SimulatorDialog::SimulatorDialog(QWidget * parent, SimulatorInterface *simulator
|
||||
startupFromFile(false),
|
||||
deleteTempRadioData(false),
|
||||
saveTempRadioData(false),
|
||||
middleButtonPressed(false)
|
||||
middleButtonPressed(false),
|
||||
firstShow(true)
|
||||
{
|
||||
setWindowFlags(Qt::Window);
|
||||
|
||||
@@ -83,6 +84,10 @@ SimulatorDialog::SimulatorDialog(QWidget * parent, SimulatorInterface *simulator
|
||||
traceCallbackInstance = this;
|
||||
simulator->installTraceHook(traceCb);
|
||||
|
||||
#ifdef JOYSTICKS
|
||||
joystick = NULL;
|
||||
#endif
|
||||
|
||||
// defaults
|
||||
setRadioProfileId(radioProfileId);
|
||||
setSdPath(g.profile[radioProfileId].sdPath());
|
||||
@@ -93,8 +98,26 @@ SimulatorDialog::SimulatorDialog(QWidget * parent, SimulatorInterface *simulator
|
||||
SimulatorDialog::~SimulatorDialog()
|
||||
{
|
||||
traceCallbackInstance = 0;
|
||||
delete timer;
|
||||
delete simulator;
|
||||
|
||||
if (timer) {
|
||||
timer->stop();
|
||||
timer->deleteLater();
|
||||
}
|
||||
if (radioUiWidget)
|
||||
radioUiWidget->deleteLater();
|
||||
if (vJoyLeft)
|
||||
vJoyLeft->deleteLater();
|
||||
if (vJoyRight)
|
||||
vJoyRight->deleteLater();
|
||||
#ifdef JOYSTICKS
|
||||
if (joystick)
|
||||
joystick->deleteLater();
|
||||
#endif
|
||||
|
||||
firmware = NULL; // Not sure we should delete this but at least release our pointer.
|
||||
// NOTE : <simulator> should be deleted (or not) in the parent process which gave it to us in the first place.
|
||||
|
||||
delete ui;
|
||||
}
|
||||
|
||||
|
||||
@@ -280,7 +303,7 @@ bool SimulatorDialog::saveTempData()
|
||||
QString error;
|
||||
QString file = g.profile[radioProfileId].simulatorOptions().dataFile;
|
||||
|
||||
if (!saveTempRadioData || radioDataPath.isEmpty() || file.isEmpty())
|
||||
if (radioDataPath.isEmpty() || file.isEmpty())
|
||||
return ret;
|
||||
|
||||
RadioData radioData;
|
||||
@@ -312,6 +335,14 @@ void SimulatorDialog::deleteTempData()
|
||||
}
|
||||
}
|
||||
|
||||
void SimulatorDialog::saveState()
|
||||
{
|
||||
SimulatorOptions opts = g.profile[radioProfileId].simulatorOptions();
|
||||
opts.windowGeometry = saveGeometry();
|
||||
opts.controlsState = saveRadioWidgetsState();
|
||||
g.profile[radioProfileId].simulatorOptions(opts);
|
||||
}
|
||||
|
||||
void SimulatorDialog::setUiAreaStyle(const QString & style)
|
||||
{
|
||||
ui->radioUiTab->setStyleSheet(style);
|
||||
@@ -339,7 +370,6 @@ void SimulatorDialog::start()
|
||||
setupOutputsDisplay();
|
||||
setupGVarsDisplay();
|
||||
restoreRadioWidgetsState();
|
||||
setTrims();
|
||||
|
||||
if (startupData.isEmpty())
|
||||
simulator->start((const char *)0);
|
||||
@@ -348,9 +378,23 @@ void SimulatorDialog::start()
|
||||
else
|
||||
simulator->start(startupData, (flags & SIMULATOR_FLAGS_NOTX) ? false : true);
|
||||
|
||||
setTrims();
|
||||
getValues();
|
||||
setupTimer();
|
||||
startupData.clear(); // this is safe because simulator->start() makes copy of data/discards the file name
|
||||
}
|
||||
|
||||
void SimulatorDialog::stop()
|
||||
{
|
||||
timer->stop();
|
||||
simulator->stop();
|
||||
}
|
||||
|
||||
void SimulatorDialog::restart()
|
||||
{
|
||||
stop();
|
||||
saveState();
|
||||
setStartupData(startupData, startupFromFile);
|
||||
start();
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -412,31 +456,28 @@ void SimulatorDialog::setupUi()
|
||||
connect(ui->btn_debugConsole, SIGNAL(released()), this, SLOT(openDebugOutput()));
|
||||
connect(ui->btn_luaReload, SIGNAL(released()), this, SLOT(luaReload()));
|
||||
connect(ui->btn_screenshot, SIGNAL(released()), radioUiWidget, SLOT(captureScreenshot()));
|
||||
|
||||
// Hide some main UI buttons based on board capabilities, and add keymap help texts.
|
||||
|
||||
keymapHelp.append(keymapHelp_t(ui->btn_help->shortcut().toString(QKeySequence::NativeText), ui->btn_help->statusTip()));
|
||||
connect(ui->btn_reloadSimu, SIGNAL(released()), this, SLOT(restart()));
|
||||
|
||||
#ifdef JOYSTICKS
|
||||
keymapHelp.append(keymapHelp_t(ui->btn_joystickDialog->shortcut().toString(QKeySequence::NativeText), ui->btn_joystickDialog->statusTip()));
|
||||
bool showJoystick = true;
|
||||
#else
|
||||
ui->btn_joystickDialog->hide();
|
||||
bool showJoystick = false;
|
||||
#endif
|
||||
|
||||
if (firmware->getCapability(Capability(SportTelemetry)))
|
||||
keymapHelp.append(keymapHelp_t(ui->btn_telemSim->shortcut().toString(QKeySequence::NativeText), ui->btn_telemSim->statusTip()));
|
||||
else
|
||||
ui->btn_telemSim->hide();
|
||||
|
||||
keymapHelp.append(keymapHelp_t(ui->btn_trainerSim->shortcut().toString(QKeySequence::NativeText), ui->btn_trainerSim->statusTip()));
|
||||
keymapHelp.append(keymapHelp_t(ui->btn_debugConsole->shortcut().toString(QKeySequence::NativeText), ui->btn_debugConsole->statusTip()));
|
||||
|
||||
if (firmware->getCapability(Capability(LuaInputsPerScript))) // hackish! but using "LuaScripts" checks for id "lua" in fw.
|
||||
keymapHelp.append(keymapHelp_t(ui->btn_luaReload->shortcut().toString(QKeySequence::NativeText), ui->btn_luaReload->statusTip()));
|
||||
else
|
||||
ui->btn_luaReload->hide();
|
||||
|
||||
keymapHelp.append(keymapHelp_t(ui->btn_screenshot->shortcut().toString(QKeySequence::NativeText), ui->btn_screenshot->statusTip()));
|
||||
// Hide some main UI buttons based on board capabilities, and add keymap help texts.
|
||||
QString role;
|
||||
foreach (QPushButton * btn, ui->buttonBox->findChildren<QPushButton *>()) {
|
||||
role = btn->property("role").toString();
|
||||
if ((role == "joystick" && !showJoystick) ||
|
||||
(role == "telemetry" && !firmware->getCapability(Capability(SportTelemetry))) ||
|
||||
(role == "reloadLua" && !firmware->getCapability(Capability(LuaInputsPerScript))) )
|
||||
{
|
||||
btn->hide();
|
||||
continue;
|
||||
}
|
||||
if (!btn->shortcut().isEmpty())
|
||||
keymapHelp.append(keymapHelp_t(btn->shortcut().toString(QKeySequence::NativeText), btn->statusTip()));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -452,6 +493,7 @@ void SimulatorDialog::setupRadioWidgets()
|
||||
ui->radioWidgetsHTLayout->removeWidget(w);
|
||||
w->deleteLater();
|
||||
}
|
||||
switches.clear();
|
||||
}
|
||||
if (analogs.size()) {
|
||||
foreach (RadioWidget * w, analogs) {
|
||||
@@ -461,6 +503,7 @@ void SimulatorDialog::setupRadioWidgets()
|
||||
ui->VCGridLayout->removeWidget(w);
|
||||
w->deleteLater();
|
||||
}
|
||||
analogs.clear();
|
||||
}
|
||||
|
||||
// Now set up new widgets.
|
||||
@@ -535,7 +578,22 @@ void SimulatorDialog::setupRadioWidgets()
|
||||
void SimulatorDialog::setupOutputsDisplay()
|
||||
{
|
||||
// setup Outputs tab
|
||||
QWidget * outputsWidget = new QWidget();
|
||||
QWidget * outputsWidget;
|
||||
|
||||
// delete old widget if already exists
|
||||
if (ui->tabWidget->count() > 1 && ui->tabWidget->widget(1)->objectName() == "RadioOutputsWidget") {
|
||||
outputsWidget = ui->tabWidget->widget(1);
|
||||
ui->tabWidget->removeTab(1);
|
||||
outputsWidget->deleteLater();
|
||||
outputsWidget = NULL;
|
||||
}
|
||||
|
||||
channelValues.clear();
|
||||
channelSliders.clear();
|
||||
logicalSwitchLabels.clear();
|
||||
|
||||
outputsWidget = new QWidget();
|
||||
outputsWidget->setObjectName("RadioOutputsWidget");
|
||||
QGridLayout * gridLayout = new QGridLayout(outputsWidget);
|
||||
gridLayout->setHorizontalSpacing(0);
|
||||
gridLayout->setVerticalSpacing(3);
|
||||
@@ -609,39 +667,54 @@ void SimulatorDialog::setupOutputsDisplay()
|
||||
|
||||
void SimulatorDialog::setupGVarsDisplay()
|
||||
{
|
||||
int fmodes = firmware->getCapability(FlightModes);
|
||||
int gvars = firmware->getCapability(Gvars);
|
||||
if (gvars>0) {
|
||||
// setup GVars tab
|
||||
QWidget * gvarsWidget = new QWidget();
|
||||
QGridLayout * gvarsLayout = new QGridLayout(gvarsWidget);
|
||||
ui->tabWidget->addTab(gvarsWidget, QString(tr("GVars")));
|
||||
// setup GVars tab
|
||||
|
||||
for (int fm=0; fm<fmodes; fm++) {
|
||||
QLabel * label = new QLabel(gvarsWidget);
|
||||
label->setText(QString("FM%1").arg(fm));
|
||||
label->setAlignment(Qt::AlignCenter);
|
||||
gvarsLayout->addWidget(label, 0, fm+1);
|
||||
int gvars = firmware->getCapability(Gvars);
|
||||
int fmodes = firmware->getCapability(FlightModes);
|
||||
|
||||
QWidget * gvarsWidget;
|
||||
// delete old widget if already exists
|
||||
if (ui->tabWidget->count() > 2 && ui->tabWidget->widget(2)->objectName() == "RadioGVOutputsWidget") {
|
||||
gvarsWidget = ui->tabWidget->widget(2);
|
||||
ui->tabWidget->removeTab(2);
|
||||
gvarsWidget->deleteLater();
|
||||
gvarsWidget = NULL;
|
||||
}
|
||||
|
||||
gvarValues.clear();
|
||||
|
||||
if (!gvars)
|
||||
return;
|
||||
|
||||
gvarsWidget = new QWidget();
|
||||
gvarsWidget->setObjectName("RadioGVOutputsWidget");
|
||||
QGridLayout * gvarsLayout = new QGridLayout(gvarsWidget);
|
||||
ui->tabWidget->insertTab(2, gvarsWidget, QString(tr("GVars")));
|
||||
|
||||
for (int fm=0; fm<fmodes; fm++) {
|
||||
QLabel * label = new QLabel(gvarsWidget);
|
||||
label->setText(QString("FM%1").arg(fm));
|
||||
label->setAlignment(Qt::AlignCenter);
|
||||
gvarsLayout->addWidget(label, 0, fm+1);
|
||||
}
|
||||
for (int i=0; i<gvars; i++) {
|
||||
QLabel * label = new QLabel(gvarsWidget);
|
||||
label->setText(QString("GV%1").arg(i+1));
|
||||
label->setAutoFillBackground(true);
|
||||
if ((i % 2) ==0 ) {
|
||||
label->setStyleSheet("QLabel { background-color: rgb(220, 220, 220) }");
|
||||
}
|
||||
for (int i=0; i<gvars; i++) {
|
||||
QLabel * label = new QLabel(gvarsWidget);
|
||||
label->setText(QString("GV%1").arg(i+1));
|
||||
label->setAutoFillBackground(true);
|
||||
gvarsLayout->addWidget(label, i+1, 0);
|
||||
for (int fm=0; fm<fmodes; fm++) {
|
||||
QLabel * value = new QLabel(gvarsWidget);
|
||||
value->setAutoFillBackground(true);
|
||||
value->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
|
||||
if ((i % 2) ==0 ) {
|
||||
label->setStyleSheet("QLabel { background-color: rgb(220, 220, 220) }");
|
||||
}
|
||||
gvarsLayout->addWidget(label, i+1, 0);
|
||||
for (int fm=0; fm<fmodes; fm++) {
|
||||
QLabel * value = new QLabel(gvarsWidget);
|
||||
value->setAutoFillBackground(true);
|
||||
value->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
|
||||
if ((i % 2) ==0 ) {
|
||||
value->setStyleSheet("QLabel { background-color: rgb(220, 220, 220) }");
|
||||
}
|
||||
value->setText("0");
|
||||
gvarValues << value;
|
||||
gvarsLayout->addWidget(value, i+1, fm+1);
|
||||
value->setStyleSheet("QLabel { background-color: rgb(220, 220, 220) }");
|
||||
}
|
||||
value->setText("0");
|
||||
gvarValues << value;
|
||||
gvarsLayout->addWidget(value, i+1, fm+1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -689,7 +762,12 @@ void SimulatorDialog::setupJoysticks()
|
||||
QMessageBox::critical(this, tr("Warning"), tr("Joystick enabled but not configured correctly"));
|
||||
return;
|
||||
}
|
||||
joystick = new Joystick(this);
|
||||
|
||||
if (!joystick)
|
||||
joystick = new Joystick(this);
|
||||
else
|
||||
joystick->close();
|
||||
|
||||
if (joystick && joystick->open(g.jsCtrl())) {
|
||||
int numAxes = std::min(joystick->numAxes, MAX_JOYSTICKS);
|
||||
for (int j=0; j<numAxes; j++) {
|
||||
@@ -720,8 +798,17 @@ void SimulatorDialog::setupJoysticks()
|
||||
|
||||
void SimulatorDialog::setupTimer()
|
||||
{
|
||||
if (timer) {
|
||||
timer->stop();
|
||||
disconnect(timer, 0, this, 0);
|
||||
disconnect(timer, 0, radioUiWidget, 0);
|
||||
timer->deleteLater();
|
||||
timer = NULL;
|
||||
}
|
||||
timer = new QTimer(this);
|
||||
connect(timer, SIGNAL(timeout()), this, SLOT(onTimerEvent()));
|
||||
connect(timer, SIGNAL(timeout()), radioUiWidget, SLOT(updateUi()));
|
||||
|
||||
timer->start(10);
|
||||
}
|
||||
|
||||
@@ -774,48 +861,51 @@ void SimulatorDialog::setValues()
|
||||
{
|
||||
static const int numGvars = firmware->getCapability(Gvars);
|
||||
static const int numFlightModes = firmware->getCapability(FlightModes);
|
||||
static QString phase_name;
|
||||
static TxOutputs prevOutputs;
|
||||
static int prevPhase = -1;
|
||||
int currentPhase;
|
||||
|
||||
TxOutputs outputs;
|
||||
simulator->getValues(outputs);
|
||||
|
||||
for (int i = 0; i < channelSliders.size() && i < CPN_MAX_CHNOUT; i++) {
|
||||
channelSliders[i]->setValue(qMin(1024, qMax(-1024, outputs.chans[i])));
|
||||
channelValues[i]->setText(QString("%1").arg((qreal)outputs.chans[i]*100/1024, 0, 'f', 1));
|
||||
}
|
||||
int currentPhase = simulator->getPhase();
|
||||
|
||||
for (int i = 0; i < logicalSwitchLabels.size() && i < CPN_MAX_CSW; i++) {
|
||||
if (prevOutputs.vsw[i] != outputs.vsw[i]) {
|
||||
// setStyleSheet() is very CPU time consuming, doing it only on the actual
|
||||
// switch state change brings down CPU usage time (for Taranis simulation) from 40% to 7% (Linux, one core usage)
|
||||
logicalSwitchLabels[i]->setStyleSheet(outputs.vsw[i] ? CSWITCH_ON : CSWITCH_OFF);
|
||||
// Outputs tab visible?
|
||||
if (ui->tabWidget->currentIndex() == 1) {
|
||||
for (int i = 0; i < channelSliders.size() && i < CPN_MAX_CHNOUT; i++) {
|
||||
channelSliders[i]->setValue(qMin(1024, qMax(-1024, outputs.chans[i])));
|
||||
channelValues[i]->setText(QString("%1").arg((qreal)outputs.chans[i]*100/1024, 0, 'f', 1));
|
||||
}
|
||||
|
||||
for (int i = 0; i < logicalSwitchLabels.size() && i < CPN_MAX_CSW; i++) {
|
||||
// setStyleSheet() is very CPU time consuming, do it only if the actual switch state changes
|
||||
if (prevOutputs.vsw[i] != outputs.vsw[i]) {
|
||||
logicalSwitchLabels[i]->setStyleSheet(outputs.vsw[i] ? CSWITCH_ON : CSWITCH_OFF);
|
||||
prevOutputs.vsw[i] = outputs.vsw[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int gv = 0; gv < numGvars; gv++) {
|
||||
for (int fm = 0; fm < numFlightModes; fm++) {
|
||||
if (prevPhase != lastPhase || prevOutputs.gvars[fm][gv] != outputs.gvars[fm][gv]) {
|
||||
// GVars tab visible?
|
||||
if (ui->tabWidget->currentIndex() == 2) {
|
||||
for (int gv = 0; gv < numGvars; gv++) {
|
||||
for (int fm = 0; fm < numFlightModes; fm++) {
|
||||
// same trick for GVARS, but this has far less effect on CPU usage as setStyleSheet()
|
||||
gvarValues[gv*numFlightModes+fm]->setText(QString((fm == lastPhase) ? "<b>%1</b>" : "%1").arg(outputs.gvars[fm][gv]));
|
||||
if (currentPhase != lastPhase || prevOutputs.gvars[fm][gv] != outputs.gvars[fm][gv]) {
|
||||
gvarValues[gv*numFlightModes+fm]->setText(QString((fm == lastPhase) ? "<b>%1</b>" : "%1").arg(outputs.gvars[fm][gv]));
|
||||
prevOutputs.gvars[fm][gv] = outputs.gvars[fm][gv];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// display current flight mode in window title
|
||||
currentPhase = simulator->getPhase();
|
||||
if (currentPhase != lastPhase) {
|
||||
lastPhase = currentPhase;
|
||||
phase_name = QString(simulator->getPhaseName(currentPhase));
|
||||
QString phase_name = QString(simulator->getPhaseName(currentPhase));
|
||||
if (phase_name.isEmpty())
|
||||
phase_name = QString::number(currentPhase);
|
||||
setWindowTitle(windowName + QString(" - Flight Mode %1").arg(phase_name));
|
||||
}
|
||||
|
||||
prevOutputs = outputs;
|
||||
prevPhase = lastPhase;
|
||||
}
|
||||
|
||||
// "get" values from this UI and send them to the firmware simulator.
|
||||
@@ -889,12 +979,8 @@ void SimulatorDialog::setTrims()
|
||||
|
||||
void SimulatorDialog::closeEvent(QCloseEvent *)
|
||||
{
|
||||
simulator->stop();
|
||||
timer->stop();
|
||||
SimulatorOptions opts = g.profile[radioProfileId].simulatorOptions();
|
||||
opts.windowGeometry = saveGeometry();
|
||||
opts.controlsState = saveRadioWidgetsState();
|
||||
g.profile[radioProfileId].simulatorOptions(opts);
|
||||
stop();
|
||||
saveState();
|
||||
if (saveTempRadioData)
|
||||
saveTempData();
|
||||
if (deleteTempRadioData)
|
||||
@@ -903,7 +989,6 @@ void SimulatorDialog::closeEvent(QCloseEvent *)
|
||||
|
||||
void SimulatorDialog::showEvent(QShowEvent *)
|
||||
{
|
||||
static bool firstShow = true;
|
||||
if (firstShow) {
|
||||
restoreGeometry(g.profile[radioProfileId].simulatorOptions().windowGeometry);
|
||||
|
||||
@@ -956,7 +1041,7 @@ void SimulatorDialog::onTimerEvent()
|
||||
setTrims();
|
||||
centerSticks();
|
||||
}
|
||||
radioUiWidget->timedUpdate(lcd_counter);
|
||||
|
||||
updateDebugOutput();
|
||||
}
|
||||
|
||||
@@ -989,6 +1074,7 @@ void SimulatorDialog::openTelemetrySimulator()
|
||||
// allow only one instance
|
||||
if (TelemetrySimu == 0) {
|
||||
TelemetrySimu = new TelemetrySimulator(this, simulator);
|
||||
TelemetrySimu->setAttribute(Qt::WA_DeleteOnClose);
|
||||
TelemetrySimu->show();
|
||||
connect(TelemetrySimu, &TelemetrySimulator::destroyed, [this](QObject *) {
|
||||
this->TelemetrySimu = NULL;
|
||||
@@ -1004,6 +1090,7 @@ void SimulatorDialog::openTrainerSimulator()
|
||||
// allow only one instance
|
||||
if (TrainerSimu == 0) {
|
||||
TrainerSimu = new TrainerSimulator(this, simulator);
|
||||
TrainerSimu->setAttribute(Qt::WA_DeleteOnClose);
|
||||
TrainerSimu->show();
|
||||
connect(TrainerSimu, &TrainerSimulator::destroyed, [this](QObject *) {
|
||||
this->TrainerSimu = NULL;
|
||||
@@ -1030,6 +1117,7 @@ void SimulatorDialog::openDebugOutput()
|
||||
if (!DebugOut) {
|
||||
DebugOut = new DebugOutput(this);
|
||||
DebugOut->traceCallback(traceBuffer);
|
||||
DebugOut->setAttribute(Qt::WA_DeleteOnClose);
|
||||
DebugOut->show();
|
||||
connect(DebugOut, &DebugOutput::destroyed, [this](QObject *) {
|
||||
this->DebugOut = NULL;
|
||||
|
||||
@@ -87,13 +87,18 @@ class SimulatorDialog : public QDialog
|
||||
bool useTempDataPath(bool deleteOnClose = true, bool saveOnClose = false);
|
||||
bool saveTempData();
|
||||
void deleteTempData();
|
||||
void saveState();
|
||||
void setUiAreaStyle(const QString & style);
|
||||
void traceCallback(const char * text);
|
||||
void start();
|
||||
|
||||
QString getSdPath() const { return sdCardPath; }
|
||||
QString getDataPath() const { return radioDataPath; }
|
||||
|
||||
public slots:
|
||||
void start();
|
||||
void stop();
|
||||
void restart();
|
||||
|
||||
private:
|
||||
void setupUi();
|
||||
void setupRadioWidgets();
|
||||
@@ -149,6 +154,7 @@ class SimulatorDialog : public QDialog
|
||||
bool deleteTempRadioData;
|
||||
bool saveTempRadioData;
|
||||
bool middleButtonPressed;
|
||||
bool firstShow;
|
||||
|
||||
#ifdef JOYSTICKS
|
||||
Joystick *joystick;
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>686</width>
|
||||
<height>557</height>
|
||||
<width>651</width>
|
||||
<height>528</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
@@ -232,125 +232,6 @@
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<property name="spacing">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btn_help">
|
||||
<property name="toolTip">
|
||||
<string>Show Help/Keymap (F1)</string>
|
||||
</property>
|
||||
<property name="statusTip">
|
||||
<string>Show Help/Keymap</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Keymap Help</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>F1</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btn_joystickDialog">
|
||||
<property name="toolTip">
|
||||
<string>Open the Joystick Settings window (F3)</string>
|
||||
</property>
|
||||
<property name="statusTip">
|
||||
<string>Joystick Configuration</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Joystick Config.</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>F3</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btn_telemSim">
|
||||
<property name="toolTip">
|
||||
<string>Open Telemetry Simulator window (F4)</string>
|
||||
</property>
|
||||
<property name="statusTip">
|
||||
<string>Telemetry Simulator</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Telemetry Sim.</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>F4</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btn_trainerSim">
|
||||
<property name="toolTip">
|
||||
<string>Open Trainer Simulator window (F5)</string>
|
||||
</property>
|
||||
<property name="statusTip">
|
||||
<string>Trainer Simulator</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Trainer Sim.</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>F5</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btn_debugConsole">
|
||||
<property name="toolTip">
|
||||
<string>Open Debug Console window (F6)</string>
|
||||
</property>
|
||||
<property name="statusTip">
|
||||
<string>Debug Console</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Debug Console</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>F6</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btn_luaReload">
|
||||
<property name="toolTip">
|
||||
<string>Reload Lua Scripts (F7)</string>
|
||||
</property>
|
||||
<property name="statusTip">
|
||||
<string>Reload Lua Scripts</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Lua Reload</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>F7</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btn_screenshot">
|
||||
<property name="toolTip">
|
||||
<string>Save a screenshot of the radio LCD screen (F8)</string>
|
||||
</property>
|
||||
<property name="statusTip">
|
||||
<string>LCD Screenshot</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>LCD Screenshot</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>F8</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QTabWidget" name="tabWidget">
|
||||
<property name="enabled">
|
||||
@@ -414,6 +295,185 @@ padding: 0;</string>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QWidget" name="buttonBox" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="buttonsLayout">
|
||||
<property name="spacing">
|
||||
<number>3</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="QPushButton" name="btn_help">
|
||||
<property name="toolTip">
|
||||
<string>Show Help/Keymap (F1)</string>
|
||||
</property>
|
||||
<property name="statusTip">
|
||||
<string>Show Help/Keymap</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Keymap</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>F1</string>
|
||||
</property>
|
||||
<property name="role" stdset="0">
|
||||
<string>help</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btn_joystickDialog">
|
||||
<property name="toolTip">
|
||||
<string>Open the Joystick Settings window (F3)</string>
|
||||
</property>
|
||||
<property name="statusTip">
|
||||
<string>Joystick Configuration</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Joystick Config.</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>F3</string>
|
||||
</property>
|
||||
<property name="role" stdset="0">
|
||||
<string>joystick</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btn_telemSim">
|
||||
<property name="toolTip">
|
||||
<string>Open Telemetry Simulator window (F4)</string>
|
||||
</property>
|
||||
<property name="statusTip">
|
||||
<string>Telemetry Simulator</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Telemetry Sim.</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>F4</string>
|
||||
</property>
|
||||
<property name="role" stdset="0">
|
||||
<string>telemetry</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btn_trainerSim">
|
||||
<property name="toolTip">
|
||||
<string>Open Trainer Simulator window (F5)</string>
|
||||
</property>
|
||||
<property name="statusTip">
|
||||
<string>Trainer Simulator</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Trainer Sim.</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>F5</string>
|
||||
</property>
|
||||
<property name="role" stdset="0">
|
||||
<string>trainer</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btn_debugConsole">
|
||||
<property name="toolTip">
|
||||
<string>Open Debug Console window (F6)</string>
|
||||
</property>
|
||||
<property name="statusTip">
|
||||
<string>Debug Console</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Debug Console</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>F6</string>
|
||||
</property>
|
||||
<property name="role" stdset="0">
|
||||
<string>debug</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btn_luaReload">
|
||||
<property name="toolTip">
|
||||
<string>Reload Lua Scripts (F7)</string>
|
||||
</property>
|
||||
<property name="statusTip">
|
||||
<string>Reload Lua Scripts</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Reload Lua</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>F7</string>
|
||||
</property>
|
||||
<property name="role" stdset="0">
|
||||
<string>reloadLua</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btn_screenshot">
|
||||
<property name="toolTip">
|
||||
<string>Save a screenshot of the radio LCD screen (F8)</string>
|
||||
</property>
|
||||
<property name="statusTip">
|
||||
<string>LCD Screenshot</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Screenshot</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>F8</string>
|
||||
</property>
|
||||
<property name="role" stdset="0">
|
||||
<string>lcdScreenshot</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btn_reloadSimu">
|
||||
<property name="toolTip">
|
||||
<string>Reload all radio data (F9)</string>
|
||||
</property>
|
||||
<property name="statusTip">
|
||||
<string>Reload Radio Data</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Reload Radio</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>F9</string>
|
||||
</property>
|
||||
<property name="role" stdset="0">
|
||||
<string>reloadradio</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources>
|
||||
|
||||
@@ -311,8 +311,6 @@ The default is configured in the chosen Radio Profile.</string>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
<zorder>groupBox</zorder>
|
||||
<zorder>buttonBox</zorder>
|
||||
</widget>
|
||||
<resources>
|
||||
<include location="../companion.qrc"/>
|
||||
|
||||
@@ -72,9 +72,7 @@ class LcdWidget : public QWidget
|
||||
|
||||
void setBackgroundColor(QColor color)
|
||||
{
|
||||
_r = color.red();
|
||||
_g = color.green();
|
||||
_b = color.blue();
|
||||
bgColor = color;
|
||||
}
|
||||
|
||||
void makeScreenshot(const QString & fileName)
|
||||
@@ -121,79 +119,87 @@ class LcdWidget : public QWidget
|
||||
unsigned char *previousBuf;
|
||||
|
||||
bool lightEnable;
|
||||
int _r, _g, _b;
|
||||
QColor bgColor;
|
||||
QColor bgDefaultColor;
|
||||
|
||||
inline void doPaint(QPainter & p)
|
||||
{
|
||||
QRgb rgb;
|
||||
uint16_t z;
|
||||
|
||||
if (!lcdBuf)
|
||||
return;
|
||||
|
||||
if (lcdDepth == 16) {
|
||||
for (int x=0; x<lcdWidth; x++) {
|
||||
for (int y=0; y<lcdHeight; y++) {
|
||||
uint16_t z = ((uint16_t *)lcdBuf)[y * lcdWidth + x];
|
||||
rgb = qRgb(255*((z&0xF800)>>11)/0x1F, 255*((z&0x07E0)>>5)/0x3F, 255*(z&0x001F)/0x1F);
|
||||
for (int x = 0; x < lcdWidth; x++) {
|
||||
for (int y = 0; y < lcdHeight; y++) {
|
||||
z = ((uint16_t *)lcdBuf)[y * lcdWidth + x];
|
||||
rgb = qRgb(255 * ((z & 0xF800) >> 11) / 0x1F,
|
||||
255 * ((z & 0x07E0) >> 5) / 0x3F,
|
||||
255 * (z & 0x001F) / 0x1F);
|
||||
p.setPen(rgb);
|
||||
p.drawPoint(x, y);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
else if (lcdDepth == 12) {
|
||||
for (int x=0; x<lcdWidth; x++) {
|
||||
for (int y=0; y<lcdHeight; y++) {
|
||||
uint16_t z = ((uint16_t *)lcdBuf)[y * lcdWidth + x];
|
||||
rgb = qRgb(255*((z&0xF00)>>8)/0x0f, 255*((z&0x0F0)>>4)/0x0f, 255*(z&0x00F)/0x0f);
|
||||
if (lcdDepth == 12) {
|
||||
for (int x = 0; x < lcdWidth; x++) {
|
||||
for (int y = 0; y < lcdHeight; y++) {
|
||||
z = ((uint16_t *)lcdBuf)[y * lcdWidth + x];
|
||||
rgb = qRgb(255 * ((z & 0xF00) >> 8) / 0x0F,
|
||||
255 * ((z & 0x0F0) >> 4) / 0x0F,
|
||||
255 * (z & 0x00F) / 0x0F);
|
||||
p.setPen(rgb);
|
||||
p.drawPoint(x, y);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
else {
|
||||
if (lightEnable)
|
||||
rgb = qRgb(_r, _g, _b);
|
||||
else
|
||||
rgb = bgDefaultColor.rgba();
|
||||
|
||||
p.setBackground(QBrush(rgb));
|
||||
p.eraseRect(0, 0, 2*lcdWidth, 2*lcdHeight);
|
||||
QColor bg;
|
||||
if (lightEnable)
|
||||
bg = bgColor;
|
||||
else
|
||||
bg = bgDefaultColor;
|
||||
|
||||
if (lcdBuf) {
|
||||
p.setBackground(QBrush(bg));
|
||||
p.eraseRect(0, 0, 2*lcdWidth, 2*lcdHeight);
|
||||
|
||||
if (lcdDepth == 1) {
|
||||
rgb = qRgb(0, 0, 0);
|
||||
p.setPen(rgb);
|
||||
p.setBrush(QBrush(rgb));
|
||||
}
|
||||
|
||||
uint16_t idx, mask;
|
||||
uint16_t previousDepth = 0xFF;
|
||||
|
||||
for (int y = 0; y < lcdHeight; y++) {
|
||||
idx = (y * lcdDepth / 8) * lcdWidth;
|
||||
mask = (1 << (y % 8));
|
||||
for (int x = 0; x < lcdWidth; x++, idx++) {
|
||||
if (lcdDepth == 1) {
|
||||
rgb = qRgb(0, 0, 0);
|
||||
if (lcdBuf[idx] & mask)
|
||||
p.drawRect(2 * x, 2 * y, 1, 1);
|
||||
continue;
|
||||
}
|
||||
// lcdDepth == 4
|
||||
z = (y & 1) ? (lcdBuf[idx] >> 4) : (lcdBuf[idx] & 0x0F);
|
||||
if (!z)
|
||||
continue;
|
||||
if (z != previousDepth) {
|
||||
previousDepth = z;
|
||||
rgb = qRgb(bg.red() - (z * bg.red()) / 15,
|
||||
bg.green() - (z * bg.green()) / 15,
|
||||
bg.blue() - (z * bg.blue()) / 15);
|
||||
p.setPen(rgb);
|
||||
p.setBrush(QBrush(rgb));
|
||||
}
|
||||
|
||||
unsigned int previousDepth = 0xFF;
|
||||
|
||||
for (int y=0; y<lcdHeight; y++) {
|
||||
unsigned int idx = (y*lcdDepth/8)*lcdWidth;
|
||||
unsigned int mask = (1 << (y%8));
|
||||
for (int x=0; x<lcdWidth; x++, idx++) {
|
||||
if (lcdDepth == 1) {
|
||||
if (lcdBuf[idx] & mask) {
|
||||
p.drawRect(2*x, 2*y, 1, 1);
|
||||
}
|
||||
}
|
||||
else {
|
||||
unsigned int z = (y & 1) ? (lcdBuf[idx] >> 4) : (lcdBuf[idx] & 0x0F);
|
||||
if (z) {
|
||||
if (z != previousDepth) {
|
||||
previousDepth = z;
|
||||
if (lightEnable)
|
||||
rgb = qRgb(_r-(z*_r)/15, _g-(z*_g)/15, _b-(z*_b)/15);
|
||||
else
|
||||
rgb = qRgb(161-(z*161)/15, 161-(z*161)/15, 161-(z*161)/15);
|
||||
p.setPen(rgb);
|
||||
p.setBrush(QBrush(rgb));
|
||||
}
|
||||
p.drawRect(2*x, 2*y, 1, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
p.drawRect(2*x, 2*y, 1, 1);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void paintEvent(QPaintEvent*)
|
||||
|
||||
@@ -68,29 +68,27 @@ class RadioKnobWidget : public RadioWidget
|
||||
|
||||
class KnobWidget : public QDial
|
||||
{
|
||||
friend class RadioKnobWidget;
|
||||
|
||||
public:
|
||||
|
||||
explicit KnobWidget(Board::PotType type, QWidget * parent = 0):
|
||||
QDial(parent),
|
||||
m_type(type),
|
||||
m_positions(type == Board::POT_MULTIPOS_SWITCH ? 5 : 0)
|
||||
QDial(parent)
|
||||
{
|
||||
setToolTip(tr("Right-double-click to reset to center."));
|
||||
setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
|
||||
setFixedSize(QSize(42, 42));
|
||||
setMinimum(-1024);
|
||||
setMaximum(1024);
|
||||
setNotchesVisible(true);
|
||||
if (m_positions) {
|
||||
if (type == Board::POT_MULTIPOS_SWITCH) {
|
||||
m_stepSize = 2048 / 5;
|
||||
// this is a bit of a hack to get the notch markers to display correctly
|
||||
// the actual notches/value are constrained in setValue()
|
||||
setSingleStep(2048 / m_positions / 10);
|
||||
setPageStep(2048 / m_positions);
|
||||
setSingleStep(m_stepSize / 10);
|
||||
setPageStep(m_stepSize);
|
||||
setNotchTarget(5.7);
|
||||
}
|
||||
else {
|
||||
m_stepSize = 1;
|
||||
setToolTip(tr("Right-double-click to reset to center."));
|
||||
setPageStep(128);
|
||||
setNotchTarget(64);
|
||||
}
|
||||
@@ -98,15 +96,15 @@ class RadioKnobWidget : public RadioWidget
|
||||
|
||||
void setValue(int value)
|
||||
{
|
||||
if (m_positions) {
|
||||
value = ((int)roundf((value + 1024) / (2048.0f / m_positions)) * (2048.0f / m_positions) - 1024);
|
||||
if (m_stepSize > 1) {
|
||||
value = (value + 1024) / m_stepSize * m_stepSize - 1024;
|
||||
}
|
||||
QDial::setValue(value);
|
||||
}
|
||||
|
||||
void mousePressEvent(QMouseEvent * event)
|
||||
{
|
||||
if (event->button() == Qt::RightButton && event->type() == QEvent::MouseButtonDblClick) {
|
||||
if (m_stepSize == 1 && event->button() == Qt::RightButton && event->type() == QEvent::MouseButtonDblClick) {
|
||||
setValue(0);
|
||||
event->accept();
|
||||
return;
|
||||
@@ -114,8 +112,21 @@ class RadioKnobWidget : public RadioWidget
|
||||
QDial::mousePressEvent(event);
|
||||
}
|
||||
|
||||
Board::PotType m_type;
|
||||
quint8 m_positions;
|
||||
void wheelEvent(QWheelEvent * event)
|
||||
{
|
||||
if (event->angleDelta().isNull())
|
||||
return;
|
||||
|
||||
if (m_stepSize > 1) {
|
||||
int numSteps = event->angleDelta().y() / 8 / 15 * m_stepSize; // one step per 15deg
|
||||
setValue(value() + numSteps);
|
||||
event->accept();
|
||||
return;
|
||||
}
|
||||
QDial::wheelEvent(event);
|
||||
}
|
||||
|
||||
quint16 m_stepSize;
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
@@ -25,7 +25,8 @@
|
||||
#include "boards.h"
|
||||
|
||||
#include <QSlider>
|
||||
#include <QDebug>
|
||||
#include <QTimer>
|
||||
#include <QToolButton>
|
||||
|
||||
class RadioSwitchWidget : public RadioWidget
|
||||
{
|
||||
@@ -50,27 +51,88 @@ class RadioSwitchWidget : public RadioWidget
|
||||
{
|
||||
m_type = RADIO_WIDGET_SWITCH;
|
||||
|
||||
QSlider * sl = new QSlider();
|
||||
sl->setOrientation(Qt::Vertical);
|
||||
sl->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
|
||||
sl->setFixedHeight(50);
|
||||
sl->setInvertedAppearance(true);
|
||||
sl->setInvertedControls(true);
|
||||
sl->setTickPosition(QSlider::TicksBothSides);
|
||||
sl->setPageStep(1);
|
||||
sl->setMinimum((swType == Board::SWITCH_3POS ? -1 : 0));
|
||||
sl->setMaximum(1);
|
||||
sl->setTickInterval(1);
|
||||
sl->setValue(m_value);
|
||||
m_slider = new QSlider();
|
||||
m_slider->setOrientation(Qt::Vertical);
|
||||
m_slider->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred);
|
||||
m_slider->setInvertedAppearance(true);
|
||||
m_slider->setInvertedControls(true);
|
||||
m_slider->setTickPosition(QSlider::TicksBothSides);
|
||||
m_slider->setPageStep(1);
|
||||
m_slider->setMinimum((swType == Board::SWITCH_3POS ? -1 : 0));
|
||||
m_slider->setMaximum(1);
|
||||
m_slider->setTickInterval(1);
|
||||
m_slider->setValue(m_value);
|
||||
|
||||
connect(sl, &QSlider::valueChanged, this, &RadioWidget::setValue);
|
||||
connect(this, &RadioWidget::valueChanged, sl, &QSlider::setValue);
|
||||
if (swType == Board::SWITCH_TOGGLE) {
|
||||
QIcon icon;
|
||||
icon.addFile(QStringLiteral(":/images/simulator/icons/8/lock-locked.png"), QSize(8, 8), QIcon::Normal, QIcon::On);
|
||||
icon.addFile(QStringLiteral(":/images/simulator/icons/8/lock-unlocked.png"), QSize(8, 8), QIcon::Normal, QIcon::Off);
|
||||
QToolButton * lockBtn = new QToolButton(this);
|
||||
lockBtn->setIcon(icon);
|
||||
lockBtn->setIconSize(QSize(8, 8));
|
||||
lockBtn->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
|
||||
lockBtn->setToolButtonStyle(Qt::ToolButtonIconOnly);
|
||||
lockBtn->setAutoRaise(true);
|
||||
lockBtn->setCheckable(true);
|
||||
lockBtn->setToolTip(tr("Latch/unlatch the momentary switch."));
|
||||
|
||||
setWidget(sl);
|
||||
QWidget * container = new QWidget(this);
|
||||
container->setFixedHeight(50);
|
||||
container->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
|
||||
QVBoxLayout * cl = new QVBoxLayout(container);
|
||||
cl->setContentsMargins(0, 0, 0, 0);
|
||||
cl->setSpacing(1);
|
||||
cl->addWidget(m_slider, 1, Qt::AlignHCenter);
|
||||
cl->addWidget(lockBtn, 0, Qt::AlignHCenter);
|
||||
|
||||
setWidget(container);
|
||||
|
||||
connect(lockBtn, &QToolButton::toggled, this, &RadioSwitchWidget::setToggleLocked);
|
||||
connect(m_slider, &QSlider::sliderReleased, this, &RadioSwitchWidget::onMomentaryReleased);
|
||||
connect(m_slider, &QSlider::valueChanged, this, &RadioSwitchWidget::onMomentaryReleased);
|
||||
connect(this, &RadioWidget::flagsChanged, lockBtn, &QToolButton::setChecked);
|
||||
}
|
||||
else {
|
||||
m_slider->setFixedHeight(50);
|
||||
setWidget(m_slider);
|
||||
}
|
||||
|
||||
connect(m_slider, &QSlider::valueChanged, this, &RadioWidget::setValue);
|
||||
connect(this, &RadioWidget::valueChanged, m_slider, &QSlider::setValue);
|
||||
|
||||
}
|
||||
|
||||
void setToggleLocked(bool lock)
|
||||
{
|
||||
if (m_flags != lock) {
|
||||
m_flags = lock;
|
||||
setValue((int)lock);
|
||||
emit flagsChanged(m_flags);
|
||||
}
|
||||
}
|
||||
|
||||
void resetToggle()
|
||||
{
|
||||
setValue(0);
|
||||
}
|
||||
|
||||
private slots:
|
||||
|
||||
void onMomentaryReleased()
|
||||
{
|
||||
if (!m_flags && !m_slider->isSliderDown())
|
||||
QTimer::singleShot(500, this, SLOT(onMomentaryTimeout()));
|
||||
}
|
||||
|
||||
void onMomentaryTimeout()
|
||||
{
|
||||
if (!m_flags)
|
||||
resetToggle();
|
||||
}
|
||||
|
||||
private:
|
||||
Board::SwitchType swType;
|
||||
QSlider * m_slider;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -134,7 +134,7 @@ QByteArray RadioWidget::getStateData() const
|
||||
|
||||
RadioWidget::RadioWidgetState RadioWidget::getState() const
|
||||
{
|
||||
return RadioWidgetState(quint8(m_type), qint8(m_index), qint16(m_value));;
|
||||
return RadioWidgetState(quint8(m_type), qint8(m_index), qint16(m_value), quint16(m_flags));;
|
||||
}
|
||||
|
||||
void RadioWidget::init()
|
||||
|
||||
@@ -261,6 +261,11 @@ int main(int argc, char *argv[])
|
||||
showMessage(QObject::tr("ERROR: Simulator %1 not found").arg(simOptions.firmwareId), QMessageBox::Critical);
|
||||
return finish(2);
|
||||
}
|
||||
SimulatorInterface * simulator = factory->create();
|
||||
if (!simulator) {
|
||||
showMessage(QObject::tr("ERROR: Failed to create simulator interface, possibly missing or bad library."), QMessageBox::Critical);
|
||||
return finish(2);
|
||||
}
|
||||
|
||||
current_firmware_variant = getFirmware(simOptions.firmwareId);
|
||||
|
||||
@@ -268,7 +273,7 @@ int main(int argc, char *argv[])
|
||||
g.id(profileId);
|
||||
g.simuLastProfId(profileId);
|
||||
|
||||
SimulatorDialog * dialog = new SimulatorDialog(NULL, factory->create(), SIMULATOR_FLAGS_STANDALONE);
|
||||
SimulatorDialog * dialog = new SimulatorDialog(NULL, simulator, SIMULATOR_FLAGS_STANDALONE);
|
||||
dialog->setRadioProfileId(profileId);
|
||||
dialog->setOptions(simOptions, true);
|
||||
dialog->start();
|
||||
@@ -277,6 +282,7 @@ int main(int argc, char *argv[])
|
||||
|
||||
g.id(oldProfId);
|
||||
dialog->deleteLater();
|
||||
delete simulator;
|
||||
|
||||
return finish(result);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user