diff --git a/.travis.yml b/.travis.yml
index e947b1240..1d9fd6014 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -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:
diff --git a/companion/src/companion.qrc b/companion/src/companion.qrc
index e9eb212ce..79e040620 100644
--- a/companion/src/companion.qrc
+++ b/companion/src/companion.qrc
@@ -11,7 +11,9 @@
images/maps.png
images/track.png
images/track0.png
- images/taranison.png
+ images/taranison.png
+ images/simulator/icons/8/lock-locked.png
+ images/simulator/icons/8/lock-unlocked.png
images/simulator/Horus/middle.png
images/simulator/Horus/left.png
images/simulator/Horus/right.png
diff --git a/companion/src/images/simulator/icons/8/lock-locked.png b/companion/src/images/simulator/icons/8/lock-locked.png
new file mode 100644
index 000000000..fef8198a3
Binary files /dev/null and b/companion/src/images/simulator/icons/8/lock-locked.png differ
diff --git a/companion/src/images/simulator/icons/8/lock-unlocked.png b/companion/src/images/simulator/icons/8/lock-unlocked.png
new file mode 100644
index 000000000..27195e0e4
Binary files /dev/null and b/companion/src/images/simulator/icons/8/lock-unlocked.png differ
diff --git a/companion/src/images/simulator/icons/credits.txt b/companion/src/images/simulator/icons/credits.txt
new file mode 100644
index 000000000..c191ff14a
--- /dev/null
+++ b/companion/src/images/simulator/icons/credits.txt
@@ -0,0 +1 @@
+Open Iconic collection, used under MIT License. https://github.com/iconic/open-iconic
diff --git a/companion/src/simulation/simulateduiwidget.cpp b/companion/src/simulation/simulateduiwidget.cpp
index b0c8e48a7..58f89a660 100644
--- a/companion/src/simulation/simulateduiwidget.cpp
+++ b/companion/src/simulation/simulateduiwidget.cpp
@@ -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);
}
diff --git a/companion/src/simulation/simulateduiwidget.h b/companion/src/simulation/simulateduiwidget.h
index 243784709..0415acbd1 100644
--- a/companion/src/simulation/simulateduiwidget.h
+++ b/companion/src/simulation/simulateduiwidget.h
@@ -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);
diff --git a/companion/src/simulation/simulatordialog.cpp b/companion/src/simulation/simulatordialog.cpp
index be19a248b..14379dae8 100644
--- a/companion/src/simulation/simulatordialog.cpp
+++ b/companion/src/simulation/simulatordialog.cpp
@@ -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 : 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()) {
+ 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; fmsetText(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; fmsetText(QString("FM%1").arg(fm));
+ label->setAlignment(Qt::AlignCenter);
+ gvarsLayout->addWidget(label, 0, fm+1);
+ }
+ for (int i=0; isetText(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; isetText(QString("GV%1").arg(i+1));
- label->setAutoFillBackground(true);
+ gvarsLayout->addWidget(label, i+1, 0);
+ for (int fm=0; fmsetAutoFillBackground(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; fmsetAutoFillBackground(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; jstop();
+ 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) ? "%1" : "%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) ? "%1" : "%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;
diff --git a/companion/src/simulation/simulatordialog.h b/companion/src/simulation/simulatordialog.h
index 0d4bda80a..8dcd456a3 100644
--- a/companion/src/simulation/simulatordialog.h
+++ b/companion/src/simulation/simulatordialog.h
@@ -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;
diff --git a/companion/src/simulation/simulatordialog.ui b/companion/src/simulation/simulatordialog.ui
index 9b1d48e9c..62bd4c713 100644
--- a/companion/src/simulation/simulatordialog.ui
+++ b/companion/src/simulation/simulatordialog.ui
@@ -6,8 +6,8 @@
0
0
- 686
- 557
+ 651
+ 528
@@ -232,125 +232,6 @@
- -
-
-
- 3
-
-
-
-
-
- Show Help/Keymap (F1)
-
-
- Show Help/Keymap
-
-
- Keymap Help
-
-
- F1
-
-
-
- -
-
-
- Open the Joystick Settings window (F3)
-
-
- Joystick Configuration
-
-
- Joystick Config.
-
-
- F3
-
-
-
- -
-
-
- Open Telemetry Simulator window (F4)
-
-
- Telemetry Simulator
-
-
- Telemetry Sim.
-
-
- F4
-
-
-
- -
-
-
- Open Trainer Simulator window (F5)
-
-
- Trainer Simulator
-
-
- Trainer Sim.
-
-
- F5
-
-
-
- -
-
-
- Open Debug Console window (F6)
-
-
- Debug Console
-
-
- Debug Console
-
-
- F6
-
-
-
- -
-
-
- Reload Lua Scripts (F7)
-
-
- Reload Lua Scripts
-
-
- Lua Reload
-
-
- F7
-
-
-
- -
-
-
- Save a screenshot of the radio LCD screen (F8)
-
-
- LCD Screenshot
-
-
- LCD Screenshot
-
-
- F8
-
-
-
-
-
-
@@ -414,6 +295,185 @@ padding: 0;
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 3
+
+
+ 1
+
+
+ 1
+
+
+ 1
+
+
+ 1
+
+
-
+
+
+ Show Help/Keymap (F1)
+
+
+ Show Help/Keymap
+
+
+ Keymap
+
+
+ F1
+
+
+ help
+
+
+
+ -
+
+
+ Open the Joystick Settings window (F3)
+
+
+ Joystick Configuration
+
+
+ Joystick Config.
+
+
+ F3
+
+
+ joystick
+
+
+
+ -
+
+
+ Open Telemetry Simulator window (F4)
+
+
+ Telemetry Simulator
+
+
+ Telemetry Sim.
+
+
+ F4
+
+
+ telemetry
+
+
+
+ -
+
+
+ Open Trainer Simulator window (F5)
+
+
+ Trainer Simulator
+
+
+ Trainer Sim.
+
+
+ F5
+
+
+ trainer
+
+
+
+ -
+
+
+ Open Debug Console window (F6)
+
+
+ Debug Console
+
+
+ Debug Console
+
+
+ F6
+
+
+ debug
+
+
+
+ -
+
+
+ Reload Lua Scripts (F7)
+
+
+ Reload Lua Scripts
+
+
+ Reload Lua
+
+
+ F7
+
+
+ reloadLua
+
+
+
+ -
+
+
+ Save a screenshot of the radio LCD screen (F8)
+
+
+ LCD Screenshot
+
+
+ Screenshot
+
+
+ F8
+
+
+ lcdScreenshot
+
+
+
+ -
+
+
+ Reload all radio data (F9)
+
+
+ Reload Radio Data
+
+
+ Reload Radio
+
+
+ F9
+
+
+ reloadradio
+
+
+
+
+
+
diff --git a/companion/src/simulation/simulatorstartupdialog.ui b/companion/src/simulation/simulatorstartupdialog.ui
index 0f342ebae..de6ac01c0 100644
--- a/companion/src/simulation/simulatorstartupdialog.ui
+++ b/companion/src/simulation/simulatorstartupdialog.ui
@@ -311,8 +311,6 @@ The default is configured in the chosen Radio Profile.
- groupBox
- buttonBox
diff --git a/companion/src/simulation/widgets/lcdwidget.h b/companion/src/simulation/widgets/lcdwidget.h
index b52b0de30..863edf7d2 100644
--- a/companion/src/simulation/widgets/lcdwidget.h
+++ b/companion/src/simulation/widgets/lcdwidget.h
@@ -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>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>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> 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*)
diff --git a/companion/src/simulation/widgets/radioknobwidget.h b/companion/src/simulation/widgets/radioknobwidget.h
index 9c27d6b38..9f0c4e19c 100644
--- a/companion/src/simulation/widgets/radioknobwidget.h
+++ b/companion/src/simulation/widgets/radioknobwidget.h
@@ -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;
};
};
diff --git a/companion/src/simulation/widgets/radioswitchwidget.h b/companion/src/simulation/widgets/radioswitchwidget.h
index 2302cb8f3..c1f3310fc 100644
--- a/companion/src/simulation/widgets/radioswitchwidget.h
+++ b/companion/src/simulation/widgets/radioswitchwidget.h
@@ -25,7 +25,8 @@
#include "boards.h"
#include
-#include
+#include
+#include
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;
};
diff --git a/companion/src/simulation/widgets/radiowidget.cpp b/companion/src/simulation/widgets/radiowidget.cpp
index 7885383df..f87522234 100644
--- a/companion/src/simulation/widgets/radiowidget.cpp
+++ b/companion/src/simulation/widgets/radiowidget.cpp
@@ -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()
diff --git a/companion/src/simulator.cpp b/companion/src/simulator.cpp
index bc9d2bc9d..44b73a05c 100644
--- a/companion/src/simulator.cpp
+++ b/companion/src/simulator.cpp
@@ -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);
}