diff --git a/.travis.yml b/.travis.yml
index f36cb420d..b733d57fb 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -70,7 +70,7 @@ install:
# - tar xjf gcc-arm-none-eabi-4_7-2013q3-20130916-linux.tar.bz2
# - mv gcc-arm-none-eabi-4_7-2013q3 /opt/gcc-arm-none-eabi
fi
- - sudo apt-get install -qq qt${QT_BASE}base qt${QT_BASE}multimedia qt${QT_BASE}tools; source /opt/qt${QT_BASE}/bin/qt${QT_BASE}-env.sh
+ - sudo apt-get install -qq qt${QT_BASE}base qt${QT_BASE}multimedia qt${QT_BASE}svg qt${QT_BASE}tools; source /opt/qt${QT_BASE}/bin/qt${QT_BASE}-env.sh
script:
- ./tools/commit-tests.sh
diff --git a/companion/src/CMakeLists.txt b/companion/src/CMakeLists.txt
index f4a1a8297..ebc6ed137 100644
--- a/companion/src/CMakeLists.txt
+++ b/companion/src/CMakeLists.txt
@@ -49,8 +49,6 @@ endif()
if(SDL_FOUND)
include_directories(${SDL_INCLUDE_DIR})
add_definitions(-DJOYSTICKS)
-else()
- remove_definitions(-DSIMU_AUDIO)
endif()
add_definitions(-DSIMU)
@@ -250,8 +248,6 @@ qt5_add_translation(companion_QM ${companion_TS})
qt5_add_resources(companion_RCC ${companion_RESOURCES})
add_custom_target(gen_qrc DEPENDS ${companion_RCC})
-add_definitions(-DQT_TRANSLATIONS_DIR="${QT_TRANSLATIONS_DIR}")
-
add_executable(${COMPANION_NAME} MACOSX_BUNDLE ${WIN_EXECUTABLE_TYPE} ${companion_SRCS} ${companion_RCC} ${companion_QM})
add_dependencies(${COMPANION_NAME} gen_qrc)
@@ -282,9 +278,7 @@ if(WIN32)
endif()
add_executable(${SIMULATOR_NAME} MACOSX_BUNDLE ${WIN_EXECUTABLE_TYPE} ${simu_SRCS} ${companion_RCC})
-
add_dependencies(${SIMULATOR_NAME} gen_qrc)
-qt5_use_modules(${SIMULATOR_NAME} Core Widgets Multimedia)
target_link_libraries(${SIMULATOR_NAME} PRIVATE simulation common shared storage qxtcommandoptions ${PTHREAD_LIBRARY} ${SDL_LIBRARY} ${WIN_LINK_LIBRARIES})
@@ -343,7 +337,7 @@ elseif(WIN32)
get_target_property(QtCore_LOCATION Qt5::Core LOCATION)
get_filename_component(QT_DLL_DIR ${QtCore_LOCATION} PATH)
- set(INSTALL_TEMP_QTDLL_FILES Qt5Core Qt5Gui Qt5Widgets Qt5Xml Qt5Network Qt5PrintSupport Qt5Multimedia)
+ set(INSTALL_TEMP_QTDLL_FILES Qt5Core Qt5Gui Qt5Widgets Qt5Xml Qt5Network Qt5PrintSupport Qt5Multimedia Qt5Svg)
set(INSTALL_TEMP_ICUDLL_FILES icudt54.dll icuin54.dll icuuc54.dll)
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
set(INSTALL_TEMP_QTDLL_SFX "d")
diff --git a/companion/src/companion.qrc b/companion/src/companion.qrc
index 79e040620..848007feb 100644
--- a/companion/src/companion.qrc
+++ b/companion/src/companion.qrc
@@ -12,8 +12,26 @@
images/track.png
images/track0.png
images/taranison.png
- images/simulator/icons/8/lock-locked.png
- images/simulator/icons/8/lock-unlocked.png
+ images/simulator/icons/svg/camera.svg
+ images/simulator/icons/svg/camera-active.svg
+ images/simulator/icons/svg/console.svg
+ images/simulator/icons/svg/eraser.svg
+ images/simulator/icons/svg/eraser-active.svg
+ images/simulator/icons/svg/info.svg
+ images/simulator/icons/svg/info-active.svg
+ images/simulator/icons/svg/joystick_settings.svg
+ images/simulator/icons/svg/joystick_settings-active.svg
+ images/simulator/icons/svg/toggle_lock.svg
+ images/simulator/icons/svg/toggle_lock-on.svg
+ images/simulator/icons/svg/radio_outputs.svg
+ images/simulator/icons/svg/reload_script.svg
+ images/simulator/icons/svg/reload_script-active.svg
+ images/simulator/icons/svg/restart.svg
+ images/simulator/icons/svg/restart-active.svg
+ images/simulator/icons/svg/telemetry.svg
+ images/simulator/icons/svg/trainer.svg
+ images/simulator/icons/svg/word_wrap.svg
+ images/simulator/icons/svg/word_wrap-active.svg
images/simulator/Horus/middle.png
images/simulator/Horus/left.png
images/simulator/Horus/right.png
@@ -180,6 +198,8 @@
images/library/10702.png
images/library/10801.png
images/library/10802.png
+ themes/default/style.css
+ themes/default/style-osx.css
themes/monochrome/16/paintbrush.png
themes/monochrome/16/open.png
themes/monochrome/16/edit.png
diff --git a/companion/src/eeprominterface.cpp b/companion/src/eeprominterface.cpp
index 71328b4f3..2addd91d4 100644
--- a/companion/src/eeprominterface.cpp
+++ b/companion/src/eeprominterface.cpp
@@ -1120,23 +1120,23 @@ GeneralSettings::GeneralSettings()
strcpy(bluetoothName, "Taranis");
}
- templateSetup = g.profile[g.id()].channelOrder();
- stickMode = g.profile[g.id()].defaultMode();
+ templateSetup = g.profile[g.sessionId()].channelOrder();
+ stickMode = g.profile[g.sessionId()].defaultMode();
- QString t_calib = g.profile[g.id()].stickPotCalib();
+ QString t_calib = g.profile[g.sessionId()].stickPotCalib();
int potsnum = getCurrentFirmware()->getCapability(Pots);
if (!t_calib.isEmpty()) {
- QString t_trainercalib=g.profile[g.id()].trainerCalib();
- int8_t t_txVoltageCalibration=(int8_t)g.profile[g.id()].txVoltageCalibration();
- int8_t t_txCurrentCalibration=(int8_t)g.profile[g.id()].txCurrentCalibration();
- int8_t t_PPM_Multiplier=(int8_t)g.profile[g.id()].ppmMultiplier();
- uint8_t t_stickMode=(uint8_t)g.profile[g.id()].gsStickMode();
- uint8_t t_vBatWarn=(uint8_t)g.profile[g.id()].vBatWarn();
- QString t_DisplaySet=g.profile[g.id()].display();
- QString t_BeeperSet=g.profile[g.id()].beeper();
- QString t_HapticSet=g.profile[g.id()].haptic();
- QString t_SpeakerSet=g.profile[g.id()].speaker();
- QString t_CountrySet=g.profile[g.id()].countryCode();
+ QString t_trainercalib=g.profile[g.sessionId()].trainerCalib();
+ int8_t t_txVoltageCalibration=(int8_t)g.profile[g.sessionId()].txVoltageCalibration();
+ int8_t t_txCurrentCalibration=(int8_t)g.profile[g.sessionId()].txCurrentCalibration();
+ int8_t t_PPM_Multiplier=(int8_t)g.profile[g.sessionId()].ppmMultiplier();
+ uint8_t t_stickMode=(uint8_t)g.profile[g.sessionId()].gsStickMode();
+ uint8_t t_vBatWarn=(uint8_t)g.profile[g.sessionId()].vBatWarn();
+ QString t_DisplaySet=g.profile[g.sessionId()].display();
+ QString t_BeeperSet=g.profile[g.sessionId()].beeper();
+ QString t_HapticSet=g.profile[g.sessionId()].haptic();
+ QString t_SpeakerSet=g.profile[g.sessionId()].speaker();
+ QString t_CountrySet=g.profile[g.sessionId()].countryCode();
if ((t_calib.length()==(CPN_MAX_STICKS+potsnum)*12) && (t_trainercalib.length()==16)) {
QString Byte;
diff --git a/companion/src/helpers.cpp b/companion/src/helpers.cpp
index ca616a221..82495c51f 100644
--- a/companion/src/helpers.cpp
+++ b/companion/src/helpers.cpp
@@ -32,7 +32,7 @@
#include "appdata.h"
#include "helpers.h"
#include "modeledit/modeledit.h"
-#include "simulatordialog.h"
+#include "simulatormainwindow.h"
#include "storage/sdcard.h"
Stopwatch gStopwatch("global");
@@ -823,7 +823,7 @@ void startSimulation(QWidget * parent, RadioData & radioData, int modelIdx)
simuData->setCurrentModel(modelIdx);
}
- SimulatorDialog * dialog = new SimulatorDialog(parent, simulator, flags);
+ SimulatorMainWindow * dialog = new SimulatorMainWindow(parent, simulator, flags);
if (IS_HORUS(getCurrentBoard()) && !dialog->useTempDataPath(true)) {
QMessageBox::critical(NULL, QObject::tr("Data Load Error"), QObject::tr("Error: Could not create temporary directory in '%1'").arg(QDir::tempPath()));
delete dialog;
@@ -831,12 +831,15 @@ void startSimulation(QWidget * parent, RadioData & radioData, int modelIdx)
return;
}
dialog->setRadioData(simuData);
- qDebug() << __FILE__ << __LINE__ << "Starting" << getCurrentFirmware()->getName() << "simulation with SD path" << dialog->getSdPath() << "and models/settings path" << dialog->getDataPath();
+ dialog->setWindowModality(Qt::ApplicationModal);
+ dialog->setAttribute(Qt::WA_DeleteOnClose);
dialog->start();
- dialog->exec();
- delete dialog;
- // TODO Horus tmp directory is deleted on simulator close OR we could use it to get back data from the simulation
- delete simuData; // TODO same with simuData, could read it back and update the file data
+ dialog->show();
+
+ QObject::connect(dialog, &SimulatorMainWindow::destroyed, [simuData] (void) {
+ // TODO simuData and Horus tmp directory is deleted on simulator close OR we could use it to get back data from the simulation
+ delete simuData;
+ });
}
else {
QMessageBox::warning(NULL,
diff --git a/companion/src/images/simulator/icons/8/lock-locked.png b/companion/src/images/simulator/icons/8/lock-locked.png
deleted file mode 100644
index fef8198a3..000000000
Binary files a/companion/src/images/simulator/icons/8/lock-locked.png and /dev/null differ
diff --git a/companion/src/images/simulator/icons/8/lock-unlocked.png b/companion/src/images/simulator/icons/8/lock-unlocked.png
deleted file mode 100644
index 27195e0e4..000000000
Binary files a/companion/src/images/simulator/icons/8/lock-unlocked.png and /dev/null differ
diff --git a/companion/src/images/simulator/icons/svg/camera-active.svg b/companion/src/images/simulator/icons/svg/camera-active.svg
new file mode 100644
index 000000000..11858cd98
--- /dev/null
+++ b/companion/src/images/simulator/icons/svg/camera-active.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/companion/src/images/simulator/icons/svg/camera.svg b/companion/src/images/simulator/icons/svg/camera.svg
new file mode 100644
index 000000000..24e159004
--- /dev/null
+++ b/companion/src/images/simulator/icons/svg/camera.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/companion/src/images/simulator/icons/svg/console.svg b/companion/src/images/simulator/icons/svg/console.svg
new file mode 100644
index 000000000..9ce925a6e
--- /dev/null
+++ b/companion/src/images/simulator/icons/svg/console.svg
@@ -0,0 +1,10 @@
+
+
+
+image/svg+xml
+
+
+
+
+
+
\ No newline at end of file
diff --git a/companion/src/images/simulator/icons/svg/eraser-active.svg b/companion/src/images/simulator/icons/svg/eraser-active.svg
new file mode 100644
index 000000000..8b529097c
--- /dev/null
+++ b/companion/src/images/simulator/icons/svg/eraser-active.svg
@@ -0,0 +1,12 @@
+
+
+
+image/svg+xml
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/companion/src/images/simulator/icons/svg/eraser.svg b/companion/src/images/simulator/icons/svg/eraser.svg
new file mode 100644
index 000000000..f7fe40f63
--- /dev/null
+++ b/companion/src/images/simulator/icons/svg/eraser.svg
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
+
+ image/svg+xml
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/companion/src/images/simulator/icons/svg/info-active.svg b/companion/src/images/simulator/icons/svg/info-active.svg
new file mode 100644
index 000000000..142f05adf
--- /dev/null
+++ b/companion/src/images/simulator/icons/svg/info-active.svg
@@ -0,0 +1,15 @@
+
+
+
+image/svg+xml
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/companion/src/images/simulator/icons/svg/info.svg b/companion/src/images/simulator/icons/svg/info.svg
new file mode 100644
index 000000000..85f9f6e73
--- /dev/null
+++ b/companion/src/images/simulator/icons/svg/info.svg
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
+ image/svg+xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/companion/src/images/simulator/icons/svg/joystick_settings-active.svg b/companion/src/images/simulator/icons/svg/joystick_settings-active.svg
new file mode 100644
index 000000000..504b8d0a8
--- /dev/null
+++ b/companion/src/images/simulator/icons/svg/joystick_settings-active.svg
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/companion/src/images/simulator/icons/svg/joystick_settings.svg b/companion/src/images/simulator/icons/svg/joystick_settings.svg
new file mode 100644
index 000000000..709113b4f
--- /dev/null
+++ b/companion/src/images/simulator/icons/svg/joystick_settings.svg
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/companion/src/images/simulator/icons/svg/radio_outputs.svg b/companion/src/images/simulator/icons/svg/radio_outputs.svg
new file mode 100644
index 000000000..bba407aea
--- /dev/null
+++ b/companion/src/images/simulator/icons/svg/radio_outputs.svg
@@ -0,0 +1,33 @@
+
+
+
+
+
+
+
+
+ image/svg+xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/companion/src/images/simulator/icons/svg/reload_script-active.svg b/companion/src/images/simulator/icons/svg/reload_script-active.svg
new file mode 100644
index 000000000..cc8576d64
--- /dev/null
+++ b/companion/src/images/simulator/icons/svg/reload_script-active.svg
@@ -0,0 +1,13 @@
+
+
+
+image/svg+xml
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/companion/src/images/simulator/icons/svg/reload_script.svg b/companion/src/images/simulator/icons/svg/reload_script.svg
new file mode 100644
index 000000000..c561fc4b0
--- /dev/null
+++ b/companion/src/images/simulator/icons/svg/reload_script.svg
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+ image/svg+xml
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/companion/src/images/simulator/icons/svg/restart-active.svg b/companion/src/images/simulator/icons/svg/restart-active.svg
new file mode 100644
index 000000000..031008c58
--- /dev/null
+++ b/companion/src/images/simulator/icons/svg/restart-active.svg
@@ -0,0 +1,13 @@
+
+
+
+image/svg+xml
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/companion/src/images/simulator/icons/svg/restart.svg b/companion/src/images/simulator/icons/svg/restart.svg
new file mode 100644
index 000000000..95ee5b5ca
--- /dev/null
+++ b/companion/src/images/simulator/icons/svg/restart.svg
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+ image/svg+xml
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/companion/src/images/simulator/icons/svg/telemetry.svg b/companion/src/images/simulator/icons/svg/telemetry.svg
new file mode 100644
index 000000000..6adfbeb07
--- /dev/null
+++ b/companion/src/images/simulator/icons/svg/telemetry.svg
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
+
+ image/svg+xml
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/companion/src/images/simulator/icons/svg/toggle_lock-on.svg b/companion/src/images/simulator/icons/svg/toggle_lock-on.svg
new file mode 100644
index 000000000..ef54f3aa2
--- /dev/null
+++ b/companion/src/images/simulator/icons/svg/toggle_lock-on.svg
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/companion/src/images/simulator/icons/svg/toggle_lock.svg b/companion/src/images/simulator/icons/svg/toggle_lock.svg
new file mode 100644
index 000000000..7f78a6f38
--- /dev/null
+++ b/companion/src/images/simulator/icons/svg/toggle_lock.svg
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/companion/src/images/simulator/icons/svg/trainer.svg b/companion/src/images/simulator/icons/svg/trainer.svg
new file mode 100644
index 000000000..3bb8e4d70
--- /dev/null
+++ b/companion/src/images/simulator/icons/svg/trainer.svg
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+
+
+ image/svg+xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/companion/src/images/simulator/icons/svg/word_wrap-active.svg b/companion/src/images/simulator/icons/svg/word_wrap-active.svg
new file mode 100644
index 000000000..4a5fffbe2
--- /dev/null
+++ b/companion/src/images/simulator/icons/svg/word_wrap-active.svg
@@ -0,0 +1,11 @@
+
+
+
+image/svg+xml
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/companion/src/images/simulator/icons/svg/word_wrap.svg b/companion/src/images/simulator/icons/svg/word_wrap.svg
new file mode 100644
index 000000000..a6abd2061
--- /dev/null
+++ b/companion/src/images/simulator/icons/svg/word_wrap.svg
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+ image/svg+xml
+
+
+
+
+
+
+
+
+
+
+
diff --git a/companion/src/simulation/CMakeLists.txt b/companion/src/simulation/CMakeLists.txt
index 6514b6283..eddba8ea6 100644
--- a/companion/src/simulation/CMakeLists.txt
+++ b/companion/src/simulation/CMakeLists.txt
@@ -1,12 +1,14 @@
set(simulation_SRCS
debugoutput.cpp
+ radiooutputswidget.cpp
simulatordialog.cpp
- simulatorinterface.cpp
simulateduiwidget.cpp
simulateduiwidget9X.cpp
simulateduiwidgetX7.cpp
simulateduiwidgetX9.cpp
simulateduiwidgetX12.cpp
+ simulatorinterface.cpp
+ simulatormainwindow.cpp
simulatorstartupdialog.cpp
telemetrysimu.cpp
trainersimu.cpp
@@ -16,11 +18,13 @@ set(simulation_SRCS
set(simulation_UIS
debugoutput.ui
+ radiooutputswidget.ui
simulatordialog.ui
simulateduiwidget9X.ui
simulateduiwidgetX7.ui
simulateduiwidgetX9.ui
simulateduiwidgetX12.ui
+ simulatormainwindow.ui
simulatorstartupdialog.ui
telemetrysimu.ui
trainersimu.ui
@@ -28,10 +32,12 @@ set(simulation_UIS
set(simulation_HDRS
debugoutput.h
+ radiooutputswidget.h
radiouiaction.h
simulateduiwidget.h
# simulator.h
simulatordialog.h
+ simulatormainwindow.h
simulatorstartupdialog.h
telemetrysimu.h
trainersimu.h
@@ -77,4 +83,4 @@ qt5_wrap_ui(simulation_SRCS ${simulation_UIS})
qt5_wrap_cpp(simulation_SRCS ${simulation_HDRS})
add_library(simulation ${simulation_SRCS} ${simulation_HDRS})
-qt5_use_modules(simulation Widgets Xml)
+qt5_use_modules(simulation Core Widgets Svg)
diff --git a/companion/src/simulation/debugoutput.cpp b/companion/src/simulation/debugoutput.cpp
index 8cfb3d52a..f894767df 100644
--- a/companion/src/simulation/debugoutput.cpp
+++ b/companion/src/simulation/debugoutput.cpp
@@ -21,40 +21,361 @@
#include "debugoutput.h"
#include "ui_debugoutput.h"
-DebugOutput::DebugOutput(QWidget * parent):
- QDialog(parent),
- ui(new Ui::DebugOutput)
+#include "appdata.h"
+
+#include
+#include
+#include
+
+#define DEBUG_OUTPUT_STATE_VERSION 1
+
+extern AppData g; // ensure what "g" means
+
+DebugOutput * traceCallbackInstance = 0;
+const int DebugOutput::m_dataBufferMaxSize = 100; // lines of text (this is not the display buffer)
+const int DebugOutput::m_dataPrintFreqDefault = 10; // ms
+const quint16 DebugOutput::m_savedViewStateVersion = 1;
+
+void traceCb(const char * text)
+{
+ // divert C callback into simulator instance
+ if (traceCallbackInstance) {
+ traceCallbackInstance->traceCallback(text);
+ }
+}
+
+DebugOutput::DebugOutput(QWidget * parent, SimulatorInterface *simulator):
+ QWidget(parent),
+ ui(new Ui::DebugOutput),
+ m_simulator(simulator),
+ m_tmrDataPrint(new QTimer()),
+ m_dataBuffer(QByteArray()),
+ m_radioProfileId(g.sessionId()),
+ m_dataPrintFreq(m_dataPrintFreqDefault),
+ m_running(false),
+ m_filterExclude(true)
{
ui->setupUi(this);
#ifdef __APPLE__
QFont newFont("Courier", 13);
- ui->Output->setFont(newFont);
- ui->Output->setAttribute(Qt::WA_MacNormalSize);
-#endif
-#if defined WIN32 || !defined __GNUC__
- QFont newFont("Courier", 9);
- ui->Output->setFont(newFont);
+ ui->console->setFont(newFont);
#endif
+
+ // TODO : allow selecting multiple filters, but needs to be efficient at output stage
+
+ QStringList stockFilters;
+ stockFilters << "^lua[A-Z].*";
+ stockFilters << "/(error|warning|-(E|W)-)/i";
+ stockFilters << "!^(GC Use|(play|load|write|find(True)?)File|convert(To|From)Simu|\\tfound( in map)?:|eeprom |f_[a-z]+\\(|(push|(p|P)op(up)?|chain)? ?Menu( .+ display)?|RamBackup).+$";
+
+ foreach (const QString & fltr, stockFilters)
+ ui->filterText->addItem(fltr, "no_delete");
+
+ ui->filterText->setValidator(new DebugOutputFilterValidator(ui->filterText));
+ ui->filterText->installEventFilter(new DeleteComboBoxItemEventFilter());
+
+ ui->actionShowFilterHelp->setIcon(SimulatorIcon("info"));
+ ui->actionWordWrap->setIcon(SimulatorIcon("word_wrap"));
+ ui->actionClearScr->setIcon(SimulatorIcon("eraser"));
+
+ ui->btnShowFilterHelp->setDefaultAction(ui->actionShowFilterHelp);
+ ui->btnWordWrap->setDefaultAction(ui->actionWordWrap);
+ ui->btnClearScr->setDefaultAction(ui->actionClearScr);
+
+ restoreState();
+
+ ui->bufferSize->setValue(ui->console->maximumBlockCount());
+
+ // install simulator TRACE hook
+ traceCallbackInstance = this;
+ m_simulator->installTraceHook(traceCb);
+
+ m_tmrDataPrint->setInterval(m_dataPrintFreq);
+
+ connect(ui->filterText, &QComboBox::currentTextChanged, this, &DebugOutput::onFilterTextChanged);
+ connect(m_tmrDataPrint, &QTimer::timeout, this, &DebugOutput::processBytesReceived);
}
DebugOutput::~DebugOutput()
{
+ traceCallbackInstance = 0;
+ stop();
+ saveState();
+ if (m_tmrDataPrint)
+ delete m_tmrDataPrint;
delete ui;
}
-void DebugOutput::traceCallback(const QString & text)
+void DebugOutput::start()
{
- // ui->Output->appendPlainText(text);
- QTextCursor cursor(ui->Output->textCursor());
+ m_tmrDataPrint->start();
+ m_running = true;
+}
- // is the scrollbar at the end?
- bool atEnd = (ui->Output->verticalScrollBar()->value() == ui->Output->verticalScrollBar()->maximum());
+void DebugOutput::stop()
+{
+ m_tmrDataPrint->stop();
+ m_running = false;
+}
- cursor.movePosition(QTextCursor::End, QTextCursor::MoveAnchor, 1);
- cursor.insertText(text);
+void DebugOutput::saveState()
+{
+ QStringList filters;
+ for (int i = 0; i < ui->filterText->count(); ++i) {
+ if (!ui->filterText->itemText(i).isEmpty() && ui->filterText->itemData(i).toString() != "no_delete")
+ filters << ui->filterText->itemText(i);
+ }
+ g.simuDbgFilters(filters);
- if (atEnd) {
- ui->Output->verticalScrollBar()->triggerAction(QAbstractSlider::SliderToMaximum);
+ QByteArray state;
+ QDataStream stream(&state, QIODevice::WriteOnly);
+ stream << m_savedViewStateVersion
+ << (qint16)ui->filterText->currentIndex() << (qint32)ui->console->maximumBlockCount()
+ << ui->btnFilter->isChecked() << ui->actionWordWrap->isChecked();
+
+ SimulatorOptions opts = g.profile[m_radioProfileId].simulatorOptions();
+ opts.dbgConsoleState = state;
+ g.profile[m_radioProfileId].simulatorOptions(opts);
+}
+
+void DebugOutput::restoreState()
+{
+ quint16 ver = 0;
+ qint16 fci = -1;
+ qint32 mbc = 10000;
+ bool flten = false, wwen = false;
+ QByteArray state = g.profile[m_radioProfileId].simulatorOptions().dbgConsoleState;
+ QDataStream stream(state);
+
+ stream >> ver;
+ if (ver && ver <= m_savedViewStateVersion)
+ stream >> fci >> mbc >> flten >> wwen;
+
+ ui->filterText->insertItems(0, g.simuDbgFilters());
+ ui->filterText->setCurrentIndex(fci);
+ ui->btnFilter->setChecked(flten);
+ ui->console->setMaximumBlockCount(mbc);
+ ui->actionWordWrap->setChecked(wwen);
+ onFilterTextEdited();
+}
+
+void DebugOutput::traceCallback(const char * text)
+{
+ const static QRegExp blank("^[\\r\\n]+$");
+ bool isBlank;
+
+ if (!m_running)
+ return;
+
+ QString line(text);
+ isBlank = line.contains(blank);
+
+ m_mtxDataBuffer.lock();
+ if (isBlank && m_dataBuffer.size())
+ m_dataBuffer[m_dataBuffer.size()-1] += line;
+ else
+ m_dataBuffer.append(text);
+ if (m_dataBuffer.size() > m_dataBufferMaxSize) {
+ m_dataBuffer.removeFirst();
+ qDebug() << __FILE__ << __LINE__ << "Line buffer overflow! size >" << m_dataBufferMaxSize;
+ }
+ m_mtxDataBuffer.unlock();
+}
+
+void DebugOutput::processBytesReceived()
+{
+ QString text;
+ bool fltMatch;
+ const QTextCursor savedCursor(ui->console->textCursor());
+ const int sbValue = ui->console->verticalScrollBar()->value();
+ const bool sbAtBottom = (sbValue == ui->console->verticalScrollBar()->maximum());
+
+ m_tmrDataPrint->stop();
+ while (m_dataBuffer.size() > 1) {
+ m_mtxDataBuffer.lock();
+ text = m_dataBuffer.takeFirst();
+ m_mtxDataBuffer.unlock();
+ // filter
+ if (ui->btnFilter->isChecked()) {
+ fltMatch = text.contains(m_filterRegEx);
+ if ((m_filterExclude && fltMatch) || (!m_filterExclude && !fltMatch)) {
+ continue;
+ }
+ }
+ ui->console->moveCursor(QTextCursor::End);
+ ui->console->textCursor().insertText(text);
+ if (sbAtBottom) {
+ ui->console->moveCursor(QTextCursor::End);
+ ui->console->verticalScrollBar()->setValue(ui->console->verticalScrollBar()->maximum());
+ }
+ else {
+ ui->console->setTextCursor(savedCursor);
+ ui->console->verticalScrollBar()->setValue(sbValue);
+ }
+ QCoreApplication::processEvents();
+ }
+ m_tmrDataPrint->start();
+}
+
+/*
+ * UI handlers
+ */
+
+void DebugOutput::onFilterTextEdited()
+{
+ const QString fText = ui->filterText->currentText();
+ if (fText.isEmpty()) {
+ ui->btnFilter->setChecked(false);
+ m_filterRegEx = QRegularExpression();
+ return;
+ }
+
+ m_filterRegEx = makeRegEx(fText, &m_filterExclude);
+
+ if (m_filterRegEx.isValid()) {
+ //ui->btnFilter->setChecked(true);
+ ui->filterText->setStyleSheet("");
+ }
+ else {
+ ui->btnFilter->setChecked(false);
+ m_filterRegEx = QRegularExpression();
+ ui->filterText->setStyleSheet("background-color: rgba(255, 205, 185, 200);");
}
}
+
+void DebugOutput::onFilterTextChanged(const QString &)
+{
+ onFilterTextEdited();
+}
+
+void DebugOutput::on_bufferSize_editingFinished()
+{
+ ui->console->setMaximumBlockCount(ui->bufferSize->value());
+}
+
+void DebugOutput::on_actionWordWrap_toggled(bool checked)
+{
+ ui->console->setLineWrapMode(checked ? QPlainTextEdit::WidgetWidth : QPlainTextEdit::NoWrap);
+}
+
+void DebugOutput::on_actionClearScr_triggered()
+{
+ ui->console->clear();
+}
+
+void DebugOutput::on_actionShowFilterHelp_triggered()
+{
+ // TODO : find some place better for this.
+ QString help = \
+ ""
+ "The filter supports two syntax types: basic matching with common wildcards and well as full Perl-style (pcre) Regular Expressions.
"
+ "By default a filter will only show lines which match (inclusive ). To make an exclusive filter which removes matching lines, "
+ "prefix the filter expression with a ! (exclamation mark).
"
+ "To use Regular Expressions (RegEx), prefix the filter text with a / (slash) or ^ (up caret). "
+ "
"
+ "Put the / or ^ after the exclusive ! indicator if you're using one. "
+ "By default the match is case-sensitive. To make it insensitive, add the typical /i (slash i) operator at the end of your RegEx. "
+ "If you use a caret (^) to denote a RegEx, it will become part of the Reg. Ex. (that is, matches from start of line). "
+ "If the RegEx is invalid, the filter edit field should show a red border and you will not be able to enable the filter. "
+ "A useful resource for testing REs (with a full reference) can be found at http://www.regexr.com/ "
+ "
"
+ "To use basic matching just type any text. Wildcards * (asterisk) matches any text and ? (question mark) matches any single character."
+ "
"
+ "The match is always case-insensitive. "
+ "The match always starts from the beginning of a log line. To ignore characters at the start, use a leading * wildcard. "
+ "A trailing * is always implied (that is, matches anything to the end of the log line). To avoid this, use a RegEx. "
+ "You can match literal wildcard characters by prefixing them with a \\ (backslash) character (eg. \"foo\\*bar\" matches \"foo*bar\"). "
+ " "
+ "After editing text , press ENTER or TAB key (or click anywhere outside the box) to update the filter.
"
+ "To remove an entry from the filter selector list, first choose it, and while in the line editor press Shift-Delete (or Shift-Backspace ) key combination. "
+ "The default filters cannot be removed. Up to 50 filters are stored.
"
+ ""
+ ;
+ QMessageBox * msgbox = new QMessageBox(QMessageBox::NoIcon, tr("Debug Console Filter Help"), help, QMessageBox::Ok, this);
+ msgbox->exec();
+}
+
+
+// static
+QRegularExpression DebugOutput::makeRegEx(const QString & input, bool * isExlusive)
+{
+ QString output(input);
+ QRegularExpression re;
+ QRegularExpression::PatternOptions reFlags = QRegularExpression::DontCaptureOption;
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 4, 0))
+ reFlags |= QRegularExpression::OptimizeOnFirstUsageOption;
+#endif
+
+ if (input.left(1) == "!") {
+ output.remove(0, 1);
+ if (isExlusive)
+ *isExlusive = true;
+ }
+ else if (isExlusive) {
+ *isExlusive = false;
+ }
+ // regex?
+ if (output.left(1) == "/" || output.left(1) == "^") {
+ if (output.left(1) == "/")
+ output.remove(0, 1);
+ // check for case-insensitive flag at end ("/.../i")
+ if (output.endsWith("/i")) {
+ output.chop(2);
+ reFlags |= QRegularExpression::CaseInsensitiveOption;
+ }
+ else if (output.endsWith("/")) {
+ output.chop(1);
+ }
+ re.setPattern(output);
+ }
+ // no, convert arbitrary string to regex
+ else {
+ output.replace(QRegExp("^\\\\/"), "/"); // remove escape before fwd-slash ("\/...")
+ // escape all special chars except * and ?
+ output.replace(QRegExp("(\\\\|\\.|\\+|\\^|\\$|\\||\\)|\\(|\\]|\\[|\\}|\\{)"), "\\\\1");
+ output.replace("\\*", "\x30").replace("\\?", "\x31"); // save escaped wildcard chars
+ output.replace("*", ".*").replace("?", "."); // convert common wildcards
+ output.replace("\x30", "\\\\*").replace("\x31", "\\\\?"); // replace escaped wildcard chars
+ output.prepend("^"); // match from start of line; .append("$"); // match whole line
+ reFlags |= QRegularExpression::CaseInsensitiveOption;
+ re.setPattern(output);
+ }
+ // TODO : user option?
+ re.setPatternOptions(reFlags);
+ return re;
+}
+
+
+/*
+ * Filter input validator for RegEx syntax.
+ */
+
+QValidator::State DebugOutputFilterValidator::validate(QString & input, int &) const
+{
+ QRegularExpression re = DebugOutput::makeRegEx(input);
+ if (re.isValid())
+ return QValidator::Acceptable;
+ else
+ return QValidator::Intermediate;
+}
+
+/*
+ * Event filter for editable QComboBox to allow deleting items with Shift-Delete/Backspace
+ */
+
+bool DeleteComboBoxItemEventFilter::eventFilter(QObject *obj, QEvent *event)
+{
+ QComboBox * cb = dynamic_cast(obj);
+ if (cb && cb->isEditable() && cb->currentIndex() > -1 && cb->currentData().toString() != "no_delete") {
+ if (event->type() == QEvent::KeyPress) {
+ QKeyEvent *keyEvent = static_cast(event);
+ if ((keyEvent->key() == Qt::Key::Key_Delete || keyEvent->key() == Qt::Key::Key_Backspace) && keyEvent->modifiers() == Qt::ShiftModifier) {
+ cb->removeItem(cb->currentIndex());
+ cb->setCurrentIndex(-1);
+ return true;
+ }
+ }
+ }
+ return QObject::eventFilter(obj, event);
+}
diff --git a/companion/src/simulation/debugoutput.h b/companion/src/simulation/debugoutput.h
index ec9745162..5e60c9ac4 100644
--- a/companion/src/simulation/debugoutput.h
+++ b/companion/src/simulation/debugoutput.h
@@ -21,30 +21,76 @@
#ifndef _DEBUGOUTPUT_H_
#define _DEBUGOUTPUT_H_
-#include
+#include "simulator.h"
#include "simulatorinterface.h"
+#include
+#include
+#include
+#include
+
namespace Ui {
class DebugOutput;
}
+class QAbstractButton;
-class DebugOutput : public QDialog
+using namespace Simulator;
+
+class DebugOutput : public QWidget
{
Q_OBJECT
public:
- explicit DebugOutput(QWidget * parent);
+ explicit DebugOutput(QWidget * parent, SimulatorInterface * simulator);
virtual ~DebugOutput();
- void traceCallback(const QString & text);
+ void start();
+ void stop();
+ void traceCallback(const char * text);
+
+ static QRegularExpression makeRegEx(const QString & input, bool * isExlusive = NULL);
+
+ protected slots:
+ void saveState();
+ void restoreState();
+ void processBytesReceived();
+ void onFilterTextEdited();
+ void onFilterTextChanged(const QString &);
+ void on_bufferSize_editingFinished();
+ void on_actionWordWrap_toggled(bool checked);
+ void on_actionClearScr_triggered();
+ void on_actionShowFilterHelp_triggered();
protected:
-
- private:
Ui::DebugOutput * ui;
+ SimulatorInterface * m_simulator;
+ QTimer * m_tmrDataPrint;
+ QStringList m_dataBuffer;
+ QMutex m_mtxDataBuffer;
+ QRegularExpression m_filterRegEx;
- private slots:
+ int m_radioProfileId;
+ int m_dataPrintFreq;
+ bool m_running;
+ bool m_filterExclude;
+ const static int m_dataBufferMaxSize;
+ const static int m_dataPrintFreqDefault;
+ const static quint16 m_savedViewStateVersion;
+};
+
+class DebugOutputFilterValidator : public QValidator
+{
+ public:
+ DebugOutputFilterValidator(QObject *parent = Q_NULLPTR) : QValidator(parent) { }
+ virtual State validate(QString & input, int &) const;
+};
+
+class DeleteComboBoxItemEventFilter : public QObject
+{
+ Q_OBJECT
+ protected:
+ bool eventFilter(QObject *obj, QEvent *event);
};
#endif // _DEBUGOUTPUT_H_
diff --git a/companion/src/simulation/debugoutput.ui b/companion/src/simulation/debugoutput.ui
index f14929b02..9a1fce02e 100644
--- a/companion/src/simulation/debugoutput.ui
+++ b/companion/src/simulation/debugoutput.ui
@@ -1,15 +1,21 @@
DebugOutput
-
+
0
0
- 711
- 470
+ 555
+ 733
+
+
+ 0
+ 0
+
+
Debug Output
@@ -18,30 +24,286 @@
:/icon.png :/icon.png
+
+ 7
+
+
+ 7
+
+
+ 7
+
+
+ 7
+
+
+ 6
+
-
-
- -
-
-
-
- Courier New
- 10
-
-
-
- Qt::ScrollBarAlwaysOn
-
-
- QPlainTextEdit::NoWrap
-
-
- true
-
-
-
-
+
+
+
+ 7
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+ -
+
+
+ 2
+
+ -
+
+
+ <html><head/><body><p>Enable or disable the filter. If the button won't stay enabled, it is likely there is a syntax error in the Regular Expression entered.</p></body></html>
+
+
+ padding: 0.15em
+
+
+ Filter:
+
+
+
+ 18
+ 18
+
+
+
+ true
+
+
+ Qt::ToolButtonTextOnly
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 100
+ 0
+
+
+
+ <html><head/><body><p>Enter filter text here. Click the help/info button for details about using the filter. </p><p>
+To <b>remove a remembered entry</b> from the filter list, first choose it, and then press <code>Shift-Delete</code> (or <code>Shift-Backspace</code>) key combination.</p></body></html>
+
+
+ true
+
+
+
+
+
+ -1
+
+
+ 50
+
+
+ QComboBox::InsertAtTop
+
+
+ QComboBox::AdjustToMinimumContentsLength
+
+
+ 1
+
+
+
+ -
+
+
+ H
+
+
+ true
+
+
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+ QSizePolicy::Preferred
+
+
+
+ 10
+ 20
+
+
+
+
+ -
+
+ -
+
+
+ Buffer:
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Number of lines to keep in display.
+
+
+
+
+
+ 100
+
+
+ 999999
+
+
+ 100
+
+
+ 10000
+
+
+
+
+
+ -
+
+
+ WW
+
+
+
+ 16
+ 16
+
+
+
+ true
+
+
+ true
+
+
+
+ -
+
+
+ C
+
+
+
+ 16
+ 16
+
+
+
+ true
+
+
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ Courier New
+ 10
+
+
+
+ Qt::ScrollBarAlwaysOn
+
+
+ false
+
+
+ QPlainTextEdit::NoWrap
+
+
+ true
+
+
+ 10000
+
+
+
+
+
+ :/images/simulator/icons/svg/info.svg :/images/simulator/icons/svg/info.svg
+
+
+ Filter &Help
+
+
+ Show information about using the filter.
+
+
+
+
+ true
+
+
+
+ :/images/simulator/icons/svg/word_wrap.svg :/images/simulator/icons/svg/word_wrap.svg
+
+
+ Word &Wrap
+
+
+ Toggle word wrapping on/off.
+
+
+
+
+
+ :/images/simulator/icons/svg/eraser.svg :/images/simulator/icons/svg/eraser.svg
+
+
+ &Clear
+
+
+ Clear the output window of all text.
+
+
diff --git a/companion/src/simulation/radiooutputswidget.cpp b/companion/src/simulation/radiooutputswidget.cpp
new file mode 100644
index 000000000..86162fc71
--- /dev/null
+++ b/companion/src/simulation/radiooutputswidget.cpp
@@ -0,0 +1,365 @@
+/*
+ * Copyright (C) OpenTX
+ *
+ * Based on code named
+ * th9x - http://code.google.com/p/th9x
+ * er9x - http://code.google.com/p/er9x
+ * gruvin9x - http://code.google.com/p/gruvin9x
+ *
+ * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include "radiooutputswidget.h"
+#include "ui_radiooutputswidget.h"
+
+#include "appdata.h"
+#include "constants.h"
+#include "eeprominterface.h"
+#include "radiodata.h"
+#include "simulator.h"
+#include "simulatorinterface.h"
+
+extern AppData g; // ensure what "g" means
+
+const int RadioOutputsWidget::m_dataUpdateFreqDefault = 10; // ms
+const quint16 RadioOutputsWidget::m_savedViewStateVersion = 1;
+
+RadioOutputsWidget::RadioOutputsWidget(SimulatorInterface * simulator, Firmware * firmware, QWidget *parent) :
+ QWidget(parent),
+ m_simulator(simulator),
+ m_firmware(firmware),
+ m_tmrUpdateData(new QTimer),
+ m_radioProfileId(g.sessionId()),
+ m_started(false),
+ ui(new Ui::RadioOutputsWidget)
+{
+ ui->setupUi(this);
+
+ restoreState();
+
+ m_dataUpdateFreq = m_dataUpdateFreqDefault;
+ m_tmrUpdateData->setInterval(m_dataUpdateFreq);
+
+ connect(m_tmrUpdateData, &QTimer::timeout, this, &RadioOutputsWidget::setValues);
+}
+
+RadioOutputsWidget::~RadioOutputsWidget()
+{
+ stop();
+ saveState();
+ if (m_tmrUpdateData)
+ delete m_tmrUpdateData;
+ delete ui;
+}
+
+void RadioOutputsWidget::changeEvent(QEvent *e)
+{
+ QWidget::changeEvent(e);
+ switch (e->type()) {
+ case QEvent::LanguageChange:
+ ui->retranslateUi(this);
+ break;
+ default:
+ break;
+ }
+}
+
+void RadioOutputsWidget::showEvent(QShowEvent * event)
+{
+ if (m_started)
+ m_tmrUpdateData->start();
+}
+
+void RadioOutputsWidget::hideEvent(QHideEvent * event)
+{
+ m_tmrUpdateData->stop();
+}
+
+void RadioOutputsWidget::start()
+{
+ setupChannelsDisplay();
+ setupGVarsDisplay();
+ setupLsDisplay();
+ m_tmrUpdateData->start();
+ m_started = true;
+}
+
+void RadioOutputsWidget::stop()
+{
+ m_tmrUpdateData->stop();
+ m_started = false;
+}
+
+void RadioOutputsWidget::restart()
+{
+ stop();
+ start();
+}
+
+void RadioOutputsWidget::saveState()
+{
+ QByteArray state;
+ QDataStream stream(&state, QIODevice::WriteOnly);
+ stream << m_savedViewStateVersion
+ << ui->btnLogiSw->isChecked() << ui->btnGlobalVars->isChecked() << ui->btnChannels->isChecked()
+ << ui->splitter->saveState();
+
+ SimulatorOptions opts = g.profile[m_radioProfileId].simulatorOptions();
+ opts.radioOutputsState = state;
+ g.profile[m_radioProfileId].simulatorOptions(opts);
+}
+
+void RadioOutputsWidget::restoreState()
+{
+ quint16 ver = 0;
+ QByteArray splitterState;
+ bool ls = true, gv = true, ch = true;
+ QByteArray state = g.profile[m_radioProfileId].simulatorOptions().radioOutputsState;
+ QDataStream stream(state);
+
+ stream >> ver;
+ if (ver && ver <= m_savedViewStateVersion)
+ stream >> ls >> gv >> ch >> splitterState;
+
+ ui->btnLogiSw->setChecked(ls);
+ ui->btnGlobalVars->setChecked(gv);
+ ui->btnChannels->setChecked(ch);
+ if (!splitterState.isEmpty())
+ ui->splitter->restoreState(splitterState);
+}
+
+
+void RadioOutputsWidget::setupChannelsDisplay()
+{
+ int outputs = std::min(32, m_firmware->getCapability(Capability(Outputs)));
+
+ // delete old widgets if already exist
+ m_channelsMap.clear();
+
+ QWidget * oldChanW = ui->channelsScroll->takeWidget();
+ if (oldChanW)
+ oldChanW->deleteLater();
+
+ if (!outputs)
+ return;
+
+ QWidget * channelsWidget = new QWidget();
+ QGridLayout * channelsLayout = new QGridLayout(channelsWidget);
+ channelsLayout->setHorizontalSpacing(4);
+ channelsLayout->setVerticalSpacing(3);
+ channelsLayout->setContentsMargins(5, 5, 5, 5);
+
+ ui->channelsScroll->setWidget(channelsWidget);
+
+ // populate outputs
+ int column = 0;
+ for (int i=0; i < outputs; i++) {
+ QLabel * label = new QLabel(channelsWidget);
+ label->setText(" " + RawSource(SOURCE_TYPE_CH, i).toString() + " ");
+ label->setAlignment(Qt::AlignCenter);
+ label->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
+ channelsLayout->addWidget(label, 0, column, 1, 1);
+
+ QSlider * slider = new QSlider(channelsWidget);
+ slider->setEnabled(false);
+ slider->setMinimum(-1024);
+ slider->setMaximum(1024);
+ slider->setPageStep(128);
+ slider->setTracking(false);
+ slider->setOrientation(Qt::Vertical);
+ slider->setInvertedAppearance(false);
+ slider->setTickPosition(QSlider::TicksRight);
+ slider->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred);
+ channelsLayout->addWidget(slider, 2, column, 1, 1);
+ channelsLayout->setAlignment(slider, Qt::AlignHCenter);
+
+ QLabel * value = new QLabel(channelsWidget);
+ value->setMinimumSize(QSize(value->fontMetrics().size(Qt::TextSingleLine, "-100.0").width(), 0));
+ value->setAlignment(Qt::AlignCenter);
+ value->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
+ channelsLayout->addWidget(value, 1, column, 1, 1);
+
+ ++column;
+
+ m_channelsMap.insert(i, QPair(value, slider));
+ }
+}
+
+void RadioOutputsWidget::setupGVarsDisplay()
+{
+ int gvars = m_firmware->getCapability(Capability(Gvars));
+ int fmodes = m_firmware->getCapability(Capability(FlightModes));
+
+ // delete old widgets if already exist
+ m_globalVarsMap.clear();
+
+ QWidget * oldGv = ui->globalVarsScroll->takeWidget();
+ if (oldGv)
+ oldGv->deleteLater();
+
+ if (!gvars)
+ return;
+
+ QWidget * gvarsWidget = new QWidget();
+ QGridLayout * gvarsLayout = new QGridLayout(gvarsWidget);
+ gvarsLayout->setContentsMargins(5, 5, 5, 5);
+ gvarsLayout->setHorizontalSpacing(6);
+ gvarsLayout->setVerticalSpacing(3);
+ ui->globalVarsScroll->setWidget(gvarsWidget);
+
+ QPalette::ColorRole bgrole = QPalette::AlternateBase;
+ for (int fm=0; fm < fmodes; fm++) {
+ QLabel * label = new QLabel(gvarsWidget);
+ label->setText(QString("FM%1").arg(fm));
+ label->setAlignment(Qt::AlignCenter);
+ label->setBackgroundRole(bgrole);
+ gvarsLayout->addWidget(label, 0, fm+1);
+ }
+ QHash fmMap;
+ for (int gv=0; gv < gvars; gv++) {
+ bgrole = ((gv % 2) ? QPalette::Background : QPalette::AlternateBase);
+ QLabel * label = new QLabel(gvarsWidget);
+ label->setText(QString("GV%1").arg(gv+1));
+ label->setAutoFillBackground(true);
+ label->setBackgroundRole(bgrole);
+ gvarsLayout->addWidget(label, gv+1, 0);
+ for (int fm=0; fm < fmodes; fm++) {
+ QLabel * value = new QLabel(gvarsWidget);
+ value->setAutoFillBackground(true);
+ value->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
+ value->setBackgroundRole(bgrole);
+ value->setText("0");
+ value->setStyleSheet("padding-right: .06em;");
+ gvarsLayout->addWidget(value, gv+1, fm+1);
+
+ fmMap.insert(fm, value);
+ }
+ m_globalVarsMap.insert(gv, fmMap);
+ }
+}
+
+void RadioOutputsWidget::setupLsDisplay()
+{
+ int switches = m_firmware->getCapability(LogicalSwitches);
+
+ // delete old widgets if already exist
+ m_logicSwitchMap.clear();
+
+ QWidget * oldLsW = ui->logicalSwitchesScroll->takeWidget();
+ if (oldLsW)
+ oldLsW->deleteLater();
+
+ if (!switches)
+ return;
+
+ QWidget * logicalSwitches = new QWidget();
+ logicalSwitches->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Maximum);
+ QGridLayout * logicalSwitchesLayout = new QGridLayout(logicalSwitches);
+ logicalSwitchesLayout->setHorizontalSpacing(3);
+ logicalSwitchesLayout->setVerticalSpacing(2);
+ logicalSwitchesLayout->setContentsMargins(5, 5, 5, 5);
+ ui->logicalSwitchesScroll->setWidget(logicalSwitches);
+
+ // populate logical switches
+ int rows = switches / (switches > 16 ? 4 : 2);
+ for (int i=0; i < switches; i++) {
+ QLabel * lsLbl = new QLabel;
+ logicalSwitchesLayout->addWidget(createLogicalSwitch(logicalSwitches, i, lsLbl), i / rows, i % rows, 1, 1);
+ m_logicSwitchMap.insert(i, lsLbl);
+ }
+}
+
+QWidget * RadioOutputsWidget::createLogicalSwitch(QWidget * parent, int switchNo, QLabel * label)
+{
+ QFrame * swtch = new QFrame(parent);
+ swtch->setAutoFillBackground(true);
+ swtch->setFrameShape(QFrame::Panel);
+ swtch->setFrameShadow(QFrame::Raised);
+ swtch->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
+ swtch->setMaximumHeight(18);
+ QVBoxLayout * layout = new QVBoxLayout(swtch);
+ layout->setContentsMargins(2, 0, 2, 0);
+ if (label) {
+ QFont font;
+ font.setPointSize(8);
+ label->setParent(swtch);
+ label->setFont(font);
+ label->setText(RawSwitch(SWITCH_TYPE_VIRTUAL, switchNo+1).toString());
+ label->setAlignment(Qt::AlignCenter);
+ label->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
+ label->setAutoFillBackground(true);
+ layout->addWidget(label);
+ }
+ return swtch;
+}
+
+// Read various values from firmware simulator and populate values in this UI
+void RadioOutputsWidget::setValues()
+{
+ static int lastPhase = 0;
+ static TxOutputs prevOutputs = TxOutputs();
+ int currentPhase;
+ TxOutputs outputs;
+
+ m_simulator->getValues(outputs);
+ currentPhase = m_simulator->getPhase();
+
+ if (ui->channelsWidget->isVisible()) {
+ QHash >::const_iterator ch;
+ for (ch = m_channelsMap.constBegin(); ch != m_channelsMap.constEnd(); ++ch) {
+ if (ch.key() >= CPN_MAX_CHNOUT)
+ continue;
+ ch.value().first->setText(QString("%1%").arg(outputs.chans[ch.key()] * 100 / 1024));
+ ch.value().second->setValue(qMin(1024, qMax(-1024, outputs.chans[ch.key()])));
+ }
+ }
+
+ if (ui->logicalSwitchesWidget->isVisible()) {
+ QHash::const_iterator ls;
+ for (ls = m_logicSwitchMap.constBegin(); ls != m_logicSwitchMap.constEnd(); ++ls) {
+ if (ls.key() >= CPN_MAX_CSW || prevOutputs.vsw[ls.key()] == outputs.vsw[ls.key()])
+ continue;
+ ls.value()->setBackgroundRole(outputs.vsw[ls.key()] ? QPalette::Highlight : QPalette::Background);
+ prevOutputs.vsw[ls.key()] = outputs.vsw[ls.key()];
+ }
+ }
+
+ if (ui->globalVarsWidget->isVisible()) {
+ QFont font;
+ QPalette::ColorRole bgrole;
+ QHash >::const_iterator gv;
+ QHash::const_iterator fm;
+ for (gv = m_globalVarsMap.constBegin(); gv != m_globalVarsMap.constEnd(); ++gv) {
+ if (gv.key() >= CPN_MAX_GVARS)
+ continue;
+ for (fm = gv.value().constBegin(); fm != gv.value().constEnd(); ++fm) {
+ if (fm.key() >= CPN_MAX_FLIGHT_MODES)
+ continue;
+ if (currentPhase != lastPhase || prevOutputs.gvars[fm.key()][gv.key()] != outputs.gvars[fm.key()][gv.key()]) {
+ font = fm.value()->font();
+ bgrole = ((gv.key() % 2) ? QPalette::Background : QPalette::AlternateBase);
+ if (fm.key() == lastPhase) {
+ font.setBold(true);
+ bgrole = QPalette::Highlight;
+ }
+ fm.value()->setText(QString::number(outputs.gvars[fm.key()][gv.key()]));
+ fm.value()->setFont(font);
+ fm.value()->setBackgroundRole(bgrole);
+ prevOutputs.gvars[fm.key()][gv.key()] = outputs.gvars[fm.key()][gv.key()];
+ }
+ }
+ }
+ }
+
+ if (currentPhase != lastPhase)
+ lastPhase = currentPhase;
+}
diff --git a/companion/src/simulation/radiooutputswidget.h b/companion/src/simulation/radiooutputswidget.h
new file mode 100644
index 000000000..972577cb5
--- /dev/null
+++ b/companion/src/simulation/radiooutputswidget.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) OpenTX
+ *
+ * Based on code named
+ * th9x - http://code.google.com/p/th9x
+ * er9x - http://code.google.com/p/er9x
+ * gruvin9x - http://code.google.com/p/gruvin9x
+ *
+ * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef RADIOOUTPUTSWIDGET_H
+#define RADIOOUTPUTSWIDGET_H
+
+#include "simulator.h"
+
+#include
+#include
+
+namespace Ui {
+class RadioOutputsWidget;
+}
+
+class Firmware;
+class SimulatorInterface;
+
+class QFrame;
+class QLabel;
+class QSlider;
+
+using namespace Simulator;
+
+class RadioOutputsWidget : public QWidget
+{
+ Q_OBJECT
+
+ public:
+ explicit RadioOutputsWidget(SimulatorInterface * simulator, Firmware * firmware, QWidget * parent = 0);
+ ~RadioOutputsWidget();
+
+ void start();
+ void stop();
+ void restart();
+
+ protected slots:
+ void saveState();
+ void restoreState();
+ void setValues();
+ void showEvent(QShowEvent *event);
+ void hideEvent(QHideEvent *event);
+
+ protected:
+ void changeEvent(QEvent *e);
+ void setupChannelsDisplay();
+ void setupLsDisplay();
+ void setupGVarsDisplay();
+ QWidget * createLogicalSwitch(QWidget * parent, int switchNo, QLabel * label);
+
+ SimulatorInterface * m_simulator;
+ Firmware * m_firmware;
+ QTimer * m_tmrUpdateData;
+
+ QHash > m_channelsMap; // m_channelsMap[chanIndex] = {QLabel*, QSlider*}
+ QHash m_logicSwitchMap; // m_logicSwitchMap[lsIndex] = QLabel*
+ QHash > m_globalVarsMap; // m_globalVarsMap[gvarIndex][fmodeIndex] = QLabel*
+
+ int m_radioProfileId;
+ int m_dataUpdateFreq;
+ bool m_started;
+
+ const static int m_dataUpdateFreqDefault;
+ const static quint16 m_savedViewStateVersion;
+
+ private:
+ Ui::RadioOutputsWidget * ui;
+};
+
+#endif // RADIOOUTPUTSWIDGET_H
diff --git a/companion/src/simulation/radiooutputswidget.ui b/companion/src/simulation/radiooutputswidget.ui
new file mode 100644
index 000000000..94888173c
--- /dev/null
+++ b/companion/src/simulation/radiooutputswidget.ui
@@ -0,0 +1,440 @@
+
+
+ RadioOutputsWidget
+
+
+
+ 0
+ 0
+ 762
+ 436
+
+
+
+ Form
+
+
+
+
+
+
+ 5
+
+
+ 7
+
+
+ 8
+
+
+ 7
+
+
+ 7
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 6
+
+
+ 3
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ View:
+
+
+
+ -
+
+
+ Logical Switches
+
+
+ true
+
+
+ true
+
+
+ Qt::ToolButtonTextBesideIcon
+
+
+ true
+
+
+
+ -
+
+
+ Global Variables
+
+
+ true
+
+
+ true
+
+
+ Qt::ToolButtonTextBesideIcon
+
+
+ true
+
+
+
+ -
+
+
+ Channel Outputs
+
+
+ true
+
+
+ true
+
+
+ Qt::ToolButtonTextBesideIcon
+
+
+ true
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+ false
+
+
+
+
+ 0
+ 0
+
+
+
+
+
+
+
+ 0
+
+
+ 1
+
+
+ 1
+
+
+ 1
+
+
+ 1
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ 3
+
+
+ L
+o
+g
+i
+c
+
+
+ Qt::AlignCenter
+
+
+ true
+
+
+ true
+
+
+
+ -
+
+
+ QFrame::NoFrame
+
+
+ true
+
+
+
+
+ 0
+ 0
+ 740
+ 85
+
+
+
+
+
+
+
+
+
+
+ 0
+ 2
+
+
+
+
+
+
+
+ 0
+
+
+ 1
+
+
+ 1
+
+
+ 1
+
+
+ 1
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ 3
+
+
+ G
+l
+o
+b
+a
+l
+
+
+ Qt::AlignCenter
+
+
+ true
+
+
+ true
+
+
+
+ -
+
+
+ QFrame::NoFrame
+
+
+ true
+
+
+
+
+ 0
+ 0
+ 739
+ 101
+
+
+
+
+
+
+
+
+
+
+ 0
+ 3
+
+
+
+
+ 0
+
+
+ 1
+
+
+ 1
+
+
+ 1
+
+
+ 1
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ 3
+
+
+ C
+h
+a
+n
+n
+e
+l
+s
+
+
+ Qt::AlignCenter
+
+
+ true
+
+
+ true
+
+
+
+ -
+
+
+ QFrame::NoFrame
+
+
+ true
+
+
+
+
+ 0
+ 0
+ 739
+ 194
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ btnChannels
+ toggled(bool)
+ channelsWidget
+ setVisible(bool)
+
+
+ 236
+ 19
+
+
+ 346
+ 435
+
+
+
+
+ btnGlobalVars
+ toggled(bool)
+ globalVarsWidget
+ setVisible(bool)
+
+
+ 157
+ 19
+
+
+ 346
+ 275
+
+
+
+
+ btnLogiSw
+ toggled(bool)
+ logicalSwitchesWidget
+ setVisible(bool)
+
+
+ 62
+ 19
+
+
+ 346
+ 114
+
+
+
+
+
diff --git a/companion/src/simulation/radiouiaction.h b/companion/src/simulation/radiouiaction.h
index 61bfb0ec0..cc3a4b5e1 100644
--- a/companion/src/simulation/radiouiaction.h
+++ b/companion/src/simulation/radiouiaction.h
@@ -127,8 +127,10 @@ class RadioUiAction : public QObject
{
if (toggle(active)) {
emit triggered(m_hwIndex, active);
- if (active)
+ if (active) {
emit pushed(m_hwIndex);
+ emit pushed();
+ }
}
}
@@ -146,6 +148,7 @@ class RadioUiAction : public QObject
void toggled(int index, bool active); // on programmatic or user interaction change
void triggered(int index, bool active); // on user interaction change only
void pushed(int index); // only emitted on user interaction && when 'active' is true
+ void pushed();
};
#endif // RADIOUIACTION_H
diff --git a/companion/src/simulation/simulateduiwidget.cpp b/companion/src/simulation/simulateduiwidget.cpp
index 58f89a660..17cd1bd59 100644
--- a/companion/src/simulation/simulateduiwidget.cpp
+++ b/companion/src/simulation/simulateduiwidget.cpp
@@ -40,7 +40,7 @@ SimulatedUIWidget::SimulatedUIWidget(SimulatorInterface * simulator, SimulatorDi
{
m_rotEncClickAction = addRadioUiAction(-1, 0, tr("Rotary encoder click"));
m_screenshotAction = addRadioUiAction(-1, Qt::Key_Print, tr("Take Screenshot"));
- connect(m_screenshotAction, &RadioUiAction::pushed, this, &SimulatedUIWidget::saveScreenshot);
+ connect(m_screenshotAction, static_cast(&RadioUiAction::pushed), this, &SimulatedUIWidget::captureScreenshot);
}
SimulatedUIWidget::~SimulatedUIWidget()
@@ -114,9 +114,8 @@ void SimulatedUIWidget::updateUi()
} */
}
-void SimulatedUIWidget::saveScreenshot(int idx)
+void SimulatedUIWidget::captureScreenshot()
{
- Q_UNUSED(idx)
QString fileName = "";
if (!g.snapToClpbrd()) {
QString path = g.snapshotDir();
@@ -124,7 +123,8 @@ void SimulatedUIWidget::saveScreenshot(int idx)
path = "./";
QDir dir(path);
if (!dir.exists() || !dir.isReadable()) {
- m_simuDialog->traceCallback("SIMULATOR ERROR - Cannot open screenshot folder, check your settings.\n");
+// m_simulator->traceCallback("SIMULATOR ERROR - Cannot open screenshot folder, check your settings.\n");
+ qDebug() << "SIMULATOR ERROR - Cannot open screenshot folder, check your settings.";
return;
}
fileName += QString("%1/screenshot_%2.png").arg(dir.absolutePath(), QDateTime::currentDateTime().toString("yy-MM-dd_HH-mm-ss"));
@@ -180,12 +180,12 @@ void SimulatedUIWidget::setLcd(LcdWidget * lcd)
void SimulatedUIWidget::connectScrollActions()
{
- connect(m_scrollUpAction, &RadioUiAction::pushed, [this](void) {
+ connect(m_scrollUpAction, static_cast(&RadioUiAction::pushed), [this](void) {
this->simulatorWheelEvent(-1);
m_scrollUpAction->toggle(false);
});
- connect(m_scrollDnAction, &RadioUiAction::pushed, [this](void) {
+ connect(m_scrollDnAction, static_cast(&RadioUiAction::pushed), [this](void) {
simulatorWheelEvent(1);
m_scrollDnAction->toggle(false);
});
diff --git a/companion/src/simulation/simulateduiwidget.h b/companion/src/simulation/simulateduiwidget.h
index e60d8674b..49e97f8a4 100644
--- a/companion/src/simulation/simulateduiwidget.h
+++ b/companion/src/simulation/simulateduiwidget.h
@@ -64,8 +64,7 @@ class SimulatedUIWidget : public QWidget
public slots:
void updateUi();
- void saveScreenshot(int idx = -1);
- void captureScreenshot() { saveScreenshot(); }
+ void captureScreenshot();
void simulatorWheelEvent(qint8 steps);
void wheelEvent(QWheelEvent *event);
diff --git a/companion/src/simulation/simulator.h b/companion/src/simulation/simulator.h
index b4ac07868..c756b7d1a 100644
--- a/companion/src/simulation/simulator.h
+++ b/companion/src/simulation/simulator.h
@@ -24,16 +24,85 @@
#include
#include
#include
+#include
+#include
#include
#include
-#define SIMULATOR_OPTIONS_VERSION 1
+#define SIMULATOR_FLAGS_NOTX 0x01 // simulating a single model from Companion
+#define SIMULATOR_FLAGS_STANDALONE 0x02 // started from stanalone simulator
-namespace Simulator {
+#define SIMULATOR_OPTIONS_VERSION 2
-typedef QPair keymapHelp_t;
+namespace Simulator
+{
-}
+ typedef QPair keymapHelp_t;
+
+ class SimulatorStyle
+ {
+ public:
+ SimulatorStyle() { }
+ static QString const basePath() { return ":/themes/default"; }
+ static QString const styleSheet()
+ {
+ QString css;
+ QFile fh(QString("%1/style.css").arg(basePath()));
+ if (fh.open(QFile::ReadOnly | QFile::Text)) {
+ css = fh.readAll();
+ fh.close();
+ }
+#ifdef __APPLE__
+ fh.setFileName(QString("%1/style-osx.css").arg(basePath()));
+ if (fh.open(QFile::ReadOnly | QFile::Text)) {
+ css.append(fh.readAll());
+ fh.close();
+ }
+#endif
+ return css;
+ }
+ }; // SimulatorStyle
+
+ class SimulatorIcon : public QIcon
+ {
+ public:
+ SimulatorIcon(const QString & baseImage)
+ {
+ QString baseFile = QString("%1/%2").arg(basePath(), baseImage);
+ addFile(QString("%1.svg").arg(baseFile));
+
+ QString addfile = QString("%1-on.svg").arg(baseFile);
+ if (QFile(addfile).exists())
+ addFile(addfile, QSize(), QIcon::Normal, QIcon::On);
+
+ addfile = QString("%1-active.svg").arg(baseFile);
+ if (QFile(addfile).exists())
+ addFile(addfile, QSize(), QIcon::Active, QIcon::Off);
+
+ addfile = QString("%1-disabled.svg").arg(baseFile);
+ if (QFile(addfile).exists())
+ addFile(addfile, QSize(), QIcon::Disabled, QIcon::Off);
+ }
+
+ static QString const basePath() { return ":/images/simulator/icons/svg"; }
+
+ static QSize const toolbarIconSize(int setting)
+ {
+ switch(setting) {
+ case 0:
+ return QSize(16, 16);
+ case 2:
+ return QSize(32, 32);
+ case 3:
+ return QSize(48, 48);
+ case 1:
+ default:
+ return QSize(24, 24);
+ }
+ }
+ }; // class SimulatorIcon
+
+} // namespace Simulator
struct SimulatorOptions
{
@@ -54,14 +123,18 @@ struct SimulatorOptions
QString dataFile;
QString dataFolder;
QString sdPath;
- QByteArray windowGeometry;
+ QByteArray windowGeometry; // SimulatorMainWindow geometry
QList controlsState; // saved switch/pot/stick settings
QColor lcdColor;
+ // added in v2
+ QByteArray windowState; // SimulatorMainWindow dock/toolbar/options UI state
+ QByteArray dbgConsoleState; // DebugOutput UI state
+ QByteArray radioOutputsState; // RadioOutputsWidget UI state
friend QDataStream & operator << (QDataStream &out, const SimulatorOptions & o)
{
out << quint16(SIMULATOR_OPTIONS_VERSION) << o.startupDataType << o.firmwareId << o.dataFile << o.dataFolder
- << o.sdPath << o.windowGeometry << o.controlsState << o.lcdColor;
+ << o.sdPath << o.windowGeometry << o.controlsState << o.lcdColor << o.windowState << o.dbgConsoleState << o.radioOutputsState;
return out;
}
@@ -70,6 +143,8 @@ struct SimulatorOptions
if (o._version <= SIMULATOR_OPTIONS_VERSION) {
in >> o._version >> o.startupDataType >> o.firmwareId >> o.dataFile >> o.dataFolder
>> o.sdPath >> o.windowGeometry >> o.controlsState >> o.lcdColor;
+ if (o._version >= 2)
+ in >> o.windowState >> o.dbgConsoleState >> o.radioOutputsState;
}
return in;
}
diff --git a/companion/src/simulation/simulatordialog.cpp b/companion/src/simulation/simulatordialog.cpp
index b8101690d..36ea286e9 100644
--- a/companion/src/simulation/simulatordialog.cpp
+++ b/companion/src/simulation/simulatordialog.cpp
@@ -22,7 +22,6 @@
#include "ui_simulatordialog.h"
#include "appdata.h"
-#include "debugoutput.h"
#include "radiofaderwidget.h"
#include "radioknobwidget.h"
#include "radioswitchwidget.h"
@@ -31,8 +30,6 @@
#include "simulateduiwidget.h"
#include "simulatorinterface.h"
#include "storage.h"
-#include "telemetrysimu.h"
-#include "trainersimu.h"
#include "virtualjoystickwidget.h"
#ifdef JOYSTICKS
#include "joystick.h"
@@ -43,18 +40,8 @@
#include
#include
-SimulatorDialog * traceCallbackInstance = 0;
-
-void traceCb(const char * text)
-{
- // divert C callback into simulator instance
- if (traceCallbackInstance) {
- traceCallbackInstance->traceCallback(text);
- }
-}
-
SimulatorDialog::SimulatorDialog(QWidget * parent, SimulatorInterface *simulator, quint8 flags):
- QDialog(parent),
+ QWidget(parent),
ui(new Ui::SimulatorDialog),
simulator(simulator),
firmware(getCurrentFirmware()),
@@ -63,12 +50,8 @@ SimulatorDialog::SimulatorDialog(QWidget * parent, SimulatorInterface *simulator
radioUiWidget(NULL),
vJoyLeft(NULL),
vJoyRight(NULL),
- TelemetrySimu(NULL),
- TrainerSimu(NULL),
- DebugOut(NULL),
m_board(getCurrentBoard()),
flags(flags),
- radioProfileId(g.id()),
lastPhase(-1),
buttonPressed(0),
trimPressed(TRIM_NONE),
@@ -78,40 +61,74 @@ SimulatorDialog::SimulatorDialog(QWidget * parent, SimulatorInterface *simulator
middleButtonPressed(false),
firstShow(true)
{
- setWindowFlags(Qt::Window);
-
- // install simulator TRACE hook
- traceCallbackInstance = this;
- simulator->installTraceHook(traceCb);
#ifdef JOYSTICKS
joystick = NULL;
#endif
// defaults
- setRadioProfileId(radioProfileId);
+ setRadioProfileId(g.sessionId());
setSdPath(g.profile[radioProfileId].sdPath());
- setupUi();
+ ui->setupUi(this);
+
+ windowName = tr("Radio Simulator (%1)").arg(firmware->getName());
+ setWindowTitle(windowName);
+
+ switch(m_board) {
+ case Board::BOARD_TARANIS_X7 :
+ radioUiWidget = new SimulatedUIWidgetX7(simulator, this);
+ break;
+ case Board::BOARD_TARANIS_X9D :
+ case Board::BOARD_TARANIS_X9DP :
+ case Board::BOARD_TARANIS_X9E :
+ radioUiWidget = new SimulatedUIWidgetX9(simulator, this);
+ break;
+ case Board::BOARD_X12S:
+ case Board::BOARD_X10:
+ radioUiWidget = new SimulatedUIWidgetX12(simulator, this);
+ break;
+ default:
+ radioUiWidget = new SimulatedUIWidget9X(simulator, this);
+ break;
+ }
+
+ foreach (keymapHelp_t item, *radioUiWidget->getKeymapHelp())
+ keymapHelp.append(item);
+
+ ui->radioUiWidget->layout()->removeItem(ui->radioUiTempSpacer);
+ ui->radioUiWidget->layout()->addWidget(radioUiWidget);
+
+ vJoyLeft = new VirtualJoystickWidget(this, 'L');
+ ui->leftStickLayout->addWidget(vJoyLeft);
+
+ vJoyRight = new VirtualJoystickWidget(this, 'R');
+ ui->rightStickLayout->addWidget(vJoyRight);
+
+ connect(vJoyLeft, SIGNAL(trimButtonPressed(int)), this, SLOT(onTrimPressed(int)));
+ connect(vJoyLeft, SIGNAL(trimButtonReleased()), this, SLOT(onTrimReleased()));
+ connect(vJoyLeft, SIGNAL(trimSliderMoved(int,int)), this, SLOT(onTrimSliderMoved(int,int)));
+
+ connect(vJoyRight, SIGNAL(trimButtonPressed(int)), this, SLOT(onTrimPressed(int)));
+ connect(vJoyRight, SIGNAL(trimButtonReleased()), this, SLOT(onTrimReleased()));
+ connect(vJoyRight, SIGNAL(trimSliderMoved(int,int)), this, SLOT(onTrimSliderMoved(int,int)));
}
SimulatorDialog::~SimulatorDialog()
{
- traceCallbackInstance = 0;
+ shutdown();
- if (timer) {
- timer->stop();
+ if (timer)
timer->deleteLater();
- }
if (radioUiWidget)
- radioUiWidget->deleteLater();
+ delete radioUiWidget;
if (vJoyLeft)
- vJoyLeft->deleteLater();
+ delete vJoyLeft;
if (vJoyRight)
- vJoyRight->deleteLater();
+ delete vJoyRight;
#ifdef JOYSTICKS
if (joystick)
- joystick->deleteLater();
+ delete joystick;
#endif
firmware = NULL; // Not sure we should delete this but at least release our pointer.
@@ -125,13 +142,6 @@ SimulatorDialog::~SimulatorDialog()
* Public slots/setters
*/
-void SimulatorDialog::setRadioProfileId(int value)
-{
- radioProfileId = value;
- if (simulator)
- simulator->setVolumeGain(g.profile[radioProfileId].volumeGain());
-}
-
void SimulatorDialog::setSdPath(const QString & sdPath)
{
setPaths(sdPath, radioDataPath);
@@ -355,25 +365,20 @@ void SimulatorDialog::deleteTempData()
void SimulatorDialog::saveState()
{
SimulatorOptions opts = g.profile[radioProfileId].simulatorOptions();
- opts.windowGeometry = saveGeometry();
+ //opts.windowGeometry = saveGeometry();
opts.controlsState = saveRadioWidgetsState();
g.profile[radioProfileId].simulatorOptions(opts);
}
void SimulatorDialog::setUiAreaStyle(const QString & style)
{
- ui->radioUiTab->setStyleSheet(style);
+ ui->radioUiWidget->setStyleSheet(style);
}
-void SimulatorDialog::traceCallback(const char * text)
+void SimulatorDialog::captureScreenshot(bool)
{
- // this function is called from other threads
- traceMutex.lock();
- // limit the size of list
- if (traceList.size() < 1000) {
- traceList.append(QString(text));
- }
- traceMutex.unlock();
+ if (radioUiWidget)
+ radioUiWidget->captureScreenshot();
}
/*
@@ -384,8 +389,6 @@ void SimulatorDialog::start()
{
setupRadioWidgets();
setupJoysticks();
- setupOutputsDisplay();
- setupGVarsDisplay();
restoreRadioWidgetsState();
if (startupData.isEmpty())
@@ -414,94 +417,30 @@ void SimulatorDialog::restart()
start();
}
+void SimulatorDialog::shutdown()
+{
+ stop();
+ saveState();
+ if (saveTempRadioData)
+ saveTempData();
+ if (deleteTempRadioData)
+ deleteTempData();
+}
+
/*
* Setup
*/
-void SimulatorDialog::setupUi()
+void SimulatorDialog::setRadioProfileId(int value)
{
- ui->setupUi(this);
-
- windowName = tr("Simulating Radio (%1)").arg(firmware->getName());
- setWindowTitle(windowName);
-
- switch(m_board) {
- case Board::BOARD_TARANIS_X7:
- radioUiWidget = new SimulatedUIWidgetX7(simulator, this);
- break;
- case Board::BOARD_TARANIS_X9D:
- case Board::BOARD_TARANIS_X9DP:
- case Board::BOARD_TARANIS_X9E:
- radioUiWidget = new SimulatedUIWidgetX9(simulator, this);
- break;
- case Board::BOARD_X12S:
- case Board::BOARD_X10:
- radioUiWidget = new SimulatedUIWidgetX12(simulator, this);
- break;
- default:
- radioUiWidget = new SimulatedUIWidget9X(simulator, this);
- break;
- }
-
- foreach (keymapHelp_t item, *radioUiWidget->getKeymapHelp()) {
- keymapHelp.append(item);
- }
-
- ui->radioUiTab->layout()->addWidget(radioUiWidget);
- ui->tabWidget->setTabText(0, firmware->getName());
- ui->tabWidget->setFixedHeight(radioUiWidget->height() + ui->tabWidget->tabBar()->height() - 8);
-
- vJoyLeft = new VirtualJoystickWidget(this, 'L');
- ui->leftStickLayout->addWidget(vJoyLeft);
-
- vJoyRight = new VirtualJoystickWidget(this, 'R');
- ui->rightStickLayout->addWidget(vJoyRight);
-
- ui->tabWidget->setCurrentIndex(flags & SIMULATOR_FLAGS_NOTX);
-
- connect(vJoyLeft, SIGNAL(trimButtonPressed(int)), this, SLOT(onTrimPressed(int)));
- connect(vJoyLeft, SIGNAL(trimButtonReleased()), this, SLOT(onTrimReleased()));
- connect(vJoyLeft, SIGNAL(trimSliderMoved(int,int)), this, SLOT(onTrimSliderMoved(int,int)));
-
- connect(vJoyRight, SIGNAL(trimButtonPressed(int)), this, SLOT(onTrimPressed(int)));
- connect(vJoyRight, SIGNAL(trimButtonReleased()), this, SLOT(onTrimReleased()));
- connect(vJoyRight, SIGNAL(trimSliderMoved(int,int)), this, SLOT(onTrimSliderMoved(int,int)));
-
- connect(ui->btn_help, SIGNAL(released()), this, SLOT(showHelp()));
- connect(ui->btn_joystickDialog, SIGNAL(released()), this, SLOT(openJoystickDialog()));
- connect(ui->btn_telemSim, SIGNAL(released()), this, SLOT(openTelemetrySimulator()));
- connect(ui->btn_trainerSim, SIGNAL(released()), this, SLOT(openTrainerSimulator()));
- 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()));
- connect(ui->btn_reloadSimu, SIGNAL(released()), this, SLOT(restart()));
-
-#ifdef JOYSTICKS
- bool showJoystick = true;
-#else
- bool showJoystick = false;
-#endif
-
- // 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()));
- }
-
+ radioProfileId = value;
+ if (simulator)
+ simulator->setVolumeGain(g.profile[radioProfileId].volumeGain());
}
void SimulatorDialog::setupRadioWidgets()
{
- int i, midpos, aIdx, wval;
+ int i, midpos, aIdx;
QString wname;
Board::Type board = firmware->getBoard();
@@ -535,13 +474,12 @@ void SimulatorDialog::setupRadioWidgets()
continue;
swcfg = Board::SwitchType(radioSettings.switchConfig[i]);
- wval = (swcfg == Board::SWITCH_3POS ? -1 : 0);
if ((wname = QString(radioSettings.switchName[i])).isEmpty()) {
switchInfo = getSwitchInfo(board, i);
wname = QString(switchInfo.name);
}
- RadioSwitchWidget * sw = new RadioSwitchWidget(swcfg, wname, wval, ui->radioWidgetsHT);
+ RadioSwitchWidget * sw = new RadioSwitchWidget(swcfg, wname, -1, ui->radioWidgetsHT);
sw->setIndex(i);
ui->radioWidgetsHTLayout->addWidget(sw);
switches.append(sw);
@@ -593,172 +531,6 @@ void SimulatorDialog::setupRadioWidgets()
}
}
-void SimulatorDialog::setupOutputsDisplay()
-{
- // setup Outputs tab
- 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);
- gridLayout->setContentsMargins(5, 3, 5, 3);
- // logical switches area
- QWidget * logicalSwitches = new QWidget(outputsWidget);
- logicalSwitches->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Maximum);
- QGridLayout * logicalSwitchesLayout = new QGridLayout(logicalSwitches);
- logicalSwitchesLayout->setHorizontalSpacing(3);
- logicalSwitchesLayout->setVerticalSpacing(2);
- logicalSwitchesLayout->setContentsMargins(0, 0, 0, 0);
- gridLayout->addWidget(logicalSwitches, 0, 0, 1, 1);
- // channels area
- QScrollArea * scrollArea = new QScrollArea(outputsWidget);
- QSizePolicy sp(QSizePolicy::Expanding, QSizePolicy::Preferred);
- sp.setHorizontalStretch(0);
- sp.setVerticalStretch(0);
- scrollArea->setSizePolicy(sp);
- scrollArea->setWidgetResizable(true);
- QWidget * channelsWidget = new QWidget();
- QGridLayout * channelsLayout = new QGridLayout(channelsWidget);
- channelsLayout->setHorizontalSpacing(4);
- channelsLayout->setVerticalSpacing(3);
- channelsLayout->setContentsMargins(0, 0, 0, 3);
- scrollArea->setWidget(channelsWidget);
- gridLayout->addWidget(scrollArea, 1, 0, 1, 1);
-
- ui->tabWidget->insertTab(1, outputsWidget, QString(tr("Outputs")));
-
- // populate outputs
- int outputs = std::min(32, firmware->getCapability(Outputs));
- int column = 0;
- for (int i=0; isetText(" " + RawSource(SOURCE_TYPE_CH, i).toString() + " ");
- label->setAlignment(Qt::AlignCenter);
- label->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
- channelsLayout->addWidget(label, 0, column, 1, 1);
-
- QSlider * slider = new QSlider(outputsWidget);
- slider->setEnabled(false);
- slider->setMinimum(-1024);
- slider->setMaximum(1024);
- slider->setPageStep(128);
- slider->setTracking(false);
- slider->setOrientation(Qt::Vertical);
- slider->setInvertedAppearance(false);
- slider->setTickPosition(QSlider::TicksRight);
- slider->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred);
-
- QLabel * value = new QLabel(outputsWidget);
- value->setMinimumSize(QSize(value->fontMetrics().size(Qt::TextSingleLine, "-100.0").width(), 0));
- value->setAlignment(Qt::AlignCenter);
- value->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
- channelValues << value;
- channelsLayout->addWidget(value, 1, column, 1, 1);
-
- channelSliders << slider;
- channelsLayout->addWidget(slider, 2, column++, 1, 1);
- channelsLayout->setAlignment(slider, Qt::AlignHCenter);
- }
-
- // populate logical switches
- int switches = firmware->getCapability(LogicalSwitches);
- int rows = switches / (switches > 16 ? 4 : 2);
- for (int i=0; iaddWidget(swtch, i / rows, i % rows, 1, 1);
- }
-}
-
-void SimulatorDialog::setupGVarsDisplay()
-{
- // setup GVars tab
-
- 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) }");
- }
- 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);
- }
- }
-}
-
-QFrame * SimulatorDialog::createLogicalSwitch(QWidget * parent, int switchNo, QVector & labels)
-{
- QFrame * swtch = new QFrame(parent);
- swtch->setAutoFillBackground(true);
- swtch->setFrameShape(QFrame::Panel);
- swtch->setFrameShadow(QFrame::Raised);
- swtch->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
- swtch->setMaximumHeight(18);
- QVBoxLayout * layout = new QVBoxLayout(swtch);
- layout->setContentsMargins(2, 0, 2, 0);
- QFont font;
- font.setPointSize(8);
- QLabel * label = new QLabel(swtch);
- label->setFont(font);
- label->setText(RawSwitch(SWITCH_TYPE_VIRTUAL, switchNo+1).toString());
- label->setAlignment(Qt::AlignCenter);
- label->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
- labels << label;
- layout->addWidget(label);
- return swtch;
-}
-
void SimulatorDialog::setupJoysticks()
{
#ifdef JOYSTICKS
@@ -855,6 +627,16 @@ void SimulatorDialog::restoreRadioWidgetsState()
if (switchesMap.contains(switches[i]->getIndex()))
switches[i]->setStateData(switchesMap.value(switches[i]->getIndex()));
}
+
+ // Set throttle stick down and locked, side depends on mode
+ if (radioSettings.stickMode & 1) {
+ vJoyLeft->setStickConstraint(VirtualJoystickWidget::HOLD_Y, true);
+ vJoyLeft->setStickY(1);
+ }
+ else {
+ vJoyRight->setStickConstraint(VirtualJoystickWidget::HOLD_Y, true);
+ vJoyRight->setStickY(1);
+ }
}
QList SimulatorDialog::saveRadioWidgetsState()
@@ -877,44 +659,8 @@ QList SimulatorDialog::saveRadioWidgetsState()
// Read various values from firmware simulator and populate values in this UI
void SimulatorDialog::setValues()
{
- static const int numGvars = firmware->getCapability(Gvars);
- static const int numFlightModes = firmware->getCapability(FlightModes);
- static TxOutputs prevOutputs;
-
- TxOutputs outputs;
- simulator->getValues(outputs);
-
int currentPhase = simulator->getPhase();
- // 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];
- }
- }
- }
-
- // 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()
- 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
if (currentPhase != lastPhase) {
lastPhase = currentPhase;
@@ -923,7 +669,6 @@ void SimulatorDialog::setValues()
phase_name = QString::number(currentPhase);
setWindowTitle(windowName + QString(" - Flight Mode %1").arg(phase_name));
}
-
}
// "get" values from this UI and send them to the firmware simulator.
@@ -995,34 +740,16 @@ void SimulatorDialog::setTrims()
* Event handlers/private slots
*/
-void SimulatorDialog::closeEvent(QCloseEvent *)
-{
- stop();
- saveState();
- if (saveTempRadioData)
- saveTempData();
- if (deleteTempRadioData)
- deleteTempData();
-}
+//void SimulatorDialog::showEvent(QShowEvent *)
+//{
+// if (firstShow && isVisible()) {
+// firstShow = false;
+// }
+//}
-void SimulatorDialog::showEvent(QShowEvent *)
-{
- if (firstShow) {
- restoreGeometry(g.profile[radioProfileId].simulatorOptions().windowGeometry);
-
- // The stick position needs to be set after the final show event, otherwise resizes during dialog creation will screw it up.
- if (radioSettings.stickMode & 1) {
- vJoyLeft->setStickConstraint(VirtualJoystickWidget::HOLD_Y, true);
- vJoyLeft->setStickY(1);
- }
- else {
- vJoyRight->setStickConstraint(VirtualJoystickWidget::HOLD_Y, true);
- vJoyRight->setStickY(1);
- }
-
- firstShow = false;
- }
-}
+//void SimulatorDialog::closeEvent(QCloseEvent *)
+//{
+//}
void SimulatorDialog::mousePressEvent(QMouseEvent *event)
{
@@ -1059,8 +786,6 @@ void SimulatorDialog::onTimerEvent()
setTrims();
centerSticks();
}
-
- updateDebugOutput();
}
void SimulatorDialog::onTrimPressed(int which)
@@ -1087,111 +812,9 @@ void SimulatorDialog::centerSticks()
vJoyRight->centerStick();
}
-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;
- });
- }
- else if (!TelemetrySimu->isVisible()) {
- TelemetrySimu->show();
- }
-}
-
-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;
- });
- }
- else if (!TrainerSimu->isVisible()) {
- TrainerSimu->show();
- }
-}
-
-void SimulatorDialog::openJoystickDialog()
-{
-#ifdef JOYSTICKS
- joystickDialog * jd = new joystickDialog(this);
- if (jd->exec() == QDialog::Accepted)
- setupJoysticks();
- jd->deleteLater();
-#endif
-}
-
-void SimulatorDialog::openDebugOutput()
-{
- // allow only one instance, but install signal handler to catch dialog destruction just in case
- 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;
- });
- }
- else if (!DebugOut->isVisible()) {
- DebugOut->show();
- }
-}
-
-void SimulatorDialog::updateDebugOutput()
-{
- traceMutex.lock();
- while (!traceList.isEmpty()) {
- QString text = traceList.takeFirst();
- traceBuffer.append(text);
- // limit the size of traceBuffer
- if (traceBuffer.size() > 10*1024) {
- traceBuffer.remove(0, 1*1024);
- }
- if (DebugOut) {
- DebugOut->traceCallback(QString(text));
- }
- }
- traceMutex.unlock();
-}
-
-void SimulatorDialog::luaReload()
-{
- // force a reload of the lua environment
- simulator->setLuaStateReloadPermanentScripts();
-}
-
-void SimulatorDialog::showHelp()
-{
- QString helpText = tr("Simulator Controls:");
- helpText += "";
- helpText += tr("Key/Mouse Action ");
- QString keyTemplate = "%1 %2 ";
- foreach (keymapHelp_t pair, keymapHelp)
- helpText += keyTemplate.arg(pair.first, pair.second);
- helpText += "
";
-
- QMessageBox * msgBox = new QMessageBox(this);
- msgBox->setAttribute(Qt::WA_DeleteOnClose);
- msgBox->setWindowFlags(msgBox->windowFlags() | Qt::WindowStaysOnTopHint);
- msgBox->setStandardButtons( QMessageBox::Ok );
- msgBox->setWindowTitle(tr("Simulator Help"));
- msgBox->setText(helpText);
- msgBox->setModal(false);
- msgBox->show();
-}
-
-#ifdef JOYSTICKS
void SimulatorDialog::onjoystickAxisValueChanged(int axis, int value)
{
+#ifdef JOYSTICKS
int stick;
if (axis>=0 && axis<=8) {
stick=jsmap[axis];
@@ -1225,5 +848,5 @@ void SimulatorDialog::onjoystickAxisValueChanged(int axis, int value)
analogs[stick-5]->setValue(stickval);
}
}
-}
#endif
+}
diff --git a/companion/src/simulation/simulatordialog.h b/companion/src/simulation/simulatordialog.h
index 9a2bca1a9..e2dc55cef 100644
--- a/companion/src/simulation/simulatordialog.h
+++ b/companion/src/simulation/simulatordialog.h
@@ -26,17 +26,11 @@
#include "radiodata.h"
#include "simulator.h"
-#include
+#include
#include
-#include
-
-#define SIMULATOR_FLAGS_NOTX 0x01 // simulating a single model from Companion
-#define SIMULATOR_FLAGS_STANDALONE 0x02 // started from stanalone simulator
#define FLASH_DURATION 10
-#define CSWITCH_ON "QLabel { background-color: #4CC417 }"
-#define CSWITCH_OFF "QLabel { }"
#define CBEEP_ON "QLabel { background-color: #FF364E }"
#define CBEEP_OFF "QLabel { }"
@@ -45,9 +39,6 @@ void traceCb(const char * text);
class Firmware;
class SimulatorInterface;
class SimulatedUIWidget;
-class TelemetrySimulator;
-class TrainerSimulator;
-class DebugOutput;
class RadioWidget;
class RadioSwitchWidget;
class VirtualJoystickWidget;
@@ -57,7 +48,6 @@ class Joystick;
class QWidget;
class QSlider;
-class QDial;
class QLabel;
class QFrame;
@@ -67,7 +57,7 @@ namespace Ui {
using namespace Simulator;
-class SimulatorDialog : public QDialog
+class SimulatorDialog : public QWidget
{
Q_OBJECT
@@ -75,7 +65,6 @@ class SimulatorDialog : public QDialog
explicit SimulatorDialog(QWidget * parent, SimulatorInterface *simulator, quint8 flags=0);
virtual ~SimulatorDialog();
- void setRadioProfileId(int value);
void setSdPath(const QString & sdPath);
void setDataPath(const QString & dataPath);
void setPaths(const QString & sdPath, const QString & dataPath);
@@ -89,23 +78,22 @@ class SimulatorDialog : public QDialog
void deleteTempData();
void saveState();
void setUiAreaStyle(const QString & style);
- void traceCallback(const char * text);
+ void captureScreenshot(bool);
+ void setupJoysticks();
QString getSdPath() const { return sdCardPath; }
QString getDataPath() const { return radioDataPath; }
+ QVector * getKeymapHelp() { return &keymapHelp; }
public slots:
void start();
void stop();
void restart();
+ void shutdown();
private:
- void setupUi();
+ void setRadioProfileId(int value);
void setupRadioWidgets();
- void setupOutputsDisplay();
- void setupGVarsDisplay();
- void setupJoysticks();
- QFrame * createLogicalSwitch(QWidget * parent, int switchNo, QVector & labels);
void setupTimer();
void restoreRadioWidgetsState();
QList saveRadioWidgetsState();
@@ -122,24 +110,14 @@ class SimulatorDialog : public QDialog
QTimer * timer;
QString windowName;
- QString traceBuffer;
- QMutex traceMutex;
- QList traceList;
QVector keymapHelp;
SimulatedUIWidget * radioUiWidget;
VirtualJoystickWidget * vJoyLeft;
VirtualJoystickWidget * vJoyRight;
- TelemetrySimulator * TelemetrySimu;
- TrainerSimulator * TrainerSimu;
- DebugOutput * DebugOut;
QVector switches;
QVector analogs;
- QVector logicalSwitchLabels;
- QVector channelSliders;
- QVector channelValues;
- QVector gvarValues;
QString sdCardPath;
QString radioDataPath;
@@ -163,8 +141,8 @@ class SimulatorDialog : public QDialog
#endif
private slots:
- virtual void closeEvent(QCloseEvent *);
- virtual void showEvent(QShowEvent *);
+ //virtual void showEvent(QShowEvent *);
+ //virtual void closeEvent(QCloseEvent *);
virtual void mousePressEvent(QMouseEvent *event);
virtual void mouseReleaseEvent(QMouseEvent *event);
virtual void wheelEvent(QWheelEvent *event);
@@ -174,16 +152,7 @@ class SimulatorDialog : public QDialog
void onTrimReleased();
void onTrimSliderMoved(int which, int value);
void centerSticks();
- void openTelemetrySimulator();
- void openTrainerSimulator();
- void openJoystickDialog();
- void openDebugOutput();
- void updateDebugOutput();
- void luaReload();
- void showHelp();
-#ifdef JOYSTICKS
void onjoystickAxisValueChanged(int axis, int value);
-#endif
};
diff --git a/companion/src/simulation/simulatordialog.ui b/companion/src/simulation/simulatordialog.ui
index 62bd4c713..181f4da1d 100644
--- a/companion/src/simulation/simulatordialog.ui
+++ b/companion/src/simulation/simulatordialog.ui
@@ -1,17 +1,17 @@
SimulatorDialog
-
+
0
0
- 651
- 528
+ 448
+ 302
-
+
0
0
@@ -23,29 +23,26 @@
:/icon.png :/icon.png
-
- true
+
+
-
-
- 5
-
-
- 5
-
-
- 5
-
-
- 5
-
-
+
+
0
-
- 3
+
+ 0
- -
+
+ 0
+
+
+ 0
+
+
+ 0
+
+ -
@@ -54,7 +51,7 @@
- QFrame::Panel
+ QFrame::StyledPanel
QFrame::Raised
@@ -62,414 +59,248 @@
2
-
+
5
- 7
+ 0
5
- 6
+ 7
- 6
+ 0
- 5
+ 10
- -
-
+ -
+
-
+
0
0
-
-
- 0
-
-
- 0
-
-
- 0
-
-
- 0
-
-
- 0
-
- -
-
-
- 0
-
-
-
-
-
-
- -
-
-
-
- 0
- 0
-
+
+ QFrame::Panel
-
-
- 0
-
-
- 0
-
-
- 0
-
-
- 0
-
-
- 0
-
- -
-
-
- 0
-
-
-
-
-
-
- -
-
-
-
- 0
- 0
-
+
+ QFrame::Raised
-
-
- 0
-
-
- 0
-
-
- 0
-
-
- 0
-
-
- 0
-
- -
-
-
- 16
-
-
- 9
-
-
-
- -
-
-
- Qt::Vertical
-
-
- QSizePolicy::Expanding
-
-
-
- 0
- 20
-
-
-
-
-
-
-
- -
-
-
-
- 0
- 0
-
+
+ 0
- 11
+ 10
6
- 6
+ 9
6
- 6
+ 9
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 0
+
+
+ 7
+
+
+ 0
+
+
+ 0
+
+
+ 12
+
+
+ 0
+
+ -
+
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+ -
+
+
+ 0
+
+
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 0
+
+
+ 0
+
+
+ 12
+
+
+ 0
+
+
+ 0
+
+ -
+
+
+ 16
+
+
+ 9
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+ QSizePolicy::Preferred
+
+
+
+ 0
+ 30
+
+
+
+
+
+
+
+ -
+
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+ -
+
+
+ 0
+
+
+
+
+
+
+
+ leftStickWidget
+ rightStickWidget
+ radioWidgetsVC
+
+
- -
-
-
- true
-
+ -
+
-
+
0
0
-
-
- 0
- 200
-
-
- QTabWidget::pane,
-QStackedWidget {
- padding: 0px;
- margin: 0px;
-}
-QTabWidget::tab-bar{
- margin-bottom: 0px;
- padding-bottom: 0px;
-}
+
-
- 0
-
-
- false
-
-
-
- background-color: qlineargradient(spread:reflect, x1:0.22, y1:0, x2:0.55065, y2:0.54, stop:0 rgba(7, 7, 7, 250), stop:0.864407 rgba(66, 66, 66, 255));
-margin: 0;
-padding: 0;
-
-
- Radio Simulator
-
-
-
- 0
-
-
- 0
-
-
- 0
-
-
- 0
-
-
- 0
-
-
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
+
- 3
+ 0
- 1
+ 0
- 1
+ 0
- 1
+ 0
- 1
+ 0
-
-
-
- Show Help/Keymap (F1)
+
+
+ Qt::Vertical
-
- Show Help/Keymap
+
+ QSizePolicy::Maximum
-
- Keymap
+
+
+ 20
+ 40
+
-
- 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/simulatormainwindow.cpp b/companion/src/simulation/simulatormainwindow.cpp
new file mode 100644
index 000000000..b57a02479
--- /dev/null
+++ b/companion/src/simulation/simulatormainwindow.cpp
@@ -0,0 +1,350 @@
+/*
+ * Copyright (C) OpenTX
+ *
+ * Based on code named
+ * th9x - http://code.google.com/p/th9x
+ * er9x - http://code.google.com/p/er9x
+ * gruvin9x - http://code.google.com/p/gruvin9x
+ *
+ * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include "simulatormainwindow.h"
+#include "ui_simulatormainwindow.h"
+
+#include "appdata.h"
+#include "debugoutput.h"
+#include "radiooutputswidget.h"
+#include "simulatordialog.h"
+#include "simulatorinterface.h"
+#include "telemetrysimu.h"
+#include "trainersimu.h"
+#ifdef JOYSTICKS
+#include "joystickdialog.h"
+#endif
+
+#include
+
+extern AppData g; // ensure what "g" means
+
+const quint16 SimulatorMainWindow::m_savedUiStateVersion = 1;
+
+SimulatorMainWindow::SimulatorMainWindow(QWidget *parent, SimulatorInterface * simulator, quint8 flags, Qt::WindowFlags wflags) :
+ QMainWindow(parent, wflags),
+ m_simulator(simulator),
+ ui(new Ui::SimulatorMainWindow),
+ m_simulatorWidget(NULL),
+ m_consoleWidget(NULL),
+ m_outputsWidget(NULL),
+ m_simulatorDockWidget(NULL),
+ m_consoleDockWidget(NULL),
+ m_telemetryDockWidget(NULL),
+ m_trainerDockWidget(NULL),
+ m_outputsDockWidget(NULL),
+ m_radioProfileId(g.sessionId()),
+ m_firstShow(true),
+ m_showRadioTitlebar(true),
+ m_showMenubar(true)
+{
+ ui->setupUi(this);
+ ui->centralwidget->hide();
+
+//#if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0))
+// setDockOptions(dockOptions() | QMainWindow::GroupedDragging);
+//#endif
+
+ setCorner(Qt::BottomLeftCorner, Qt::LeftDockWidgetArea);
+
+ m_simulatorWidget = new SimulatorDialog(this, m_simulator, flags);
+
+ m_simulatorDockWidget = new QDockWidget(m_simulatorWidget->windowTitle(), this);
+ m_simulatorDockWidget->setObjectName("RADIO_SIMULATOR");
+ m_simulatorDockWidget->setWidget(m_simulatorWidget);
+ m_simulatorDockWidget->setFeatures(QDockWidget::DockWidgetMovable | QDockWidget::DockWidgetFloatable);
+ addDockWidget(Qt::BottomDockWidgetArea, m_simulatorDockWidget);
+ // setCentralWidget(m_simulatorWidget);
+
+ createDockWidgets();
+
+ ui->actionReloadLua->setIcon(SimulatorIcon("reload_script"));
+ ui->actionReloadRadioData->setIcon(SimulatorIcon("restart"));
+ ui->actionJoystickSettings->setIcon(SimulatorIcon("joystick_settings"));
+ ui->actionScreenshot->setIcon(SimulatorIcon("camera"));
+ ui->actionShowKeymap->setIcon(SimulatorIcon("info"));
+ ui->actionToggleRadioTitle->setIcon(ui->toolBar->toggleViewAction()->icon());
+ ui->actionToggleMenuBar->setIcon(ui->toolBar->toggleViewAction()->icon());
+
+ ui->toolBar->toggleViewAction()->setShortcut(tr("Alt+T"));
+ ui->toolBar->setIconSize(SimulatorIcon::toolbarIconSize(g.iconSize()));
+ ui->toolBar->insertSeparator(ui->actionReloadLua);
+
+ // add these to this window directly to maintain shorcuts when menubar is hidden
+ addAction(ui->toolBar->toggleViewAction());
+ addAction(ui->actionToggleMenuBar);
+
+ ui->menuView->addSeparator();
+ ui->menuView->addAction(ui->toolBar->toggleViewAction());
+ ui->menuView->addAction(ui->actionToggleMenuBar);
+ ui->menuView->addAction(ui->actionToggleRadioTitle);
+
+ // Hide some actions based on board capabilities.
+ Firmware * firmware = getCurrentFirmware();
+ if(!firmware->getCapability(Capability(LuaInputsPerScript)))
+ ui->actionReloadLua->setDisabled(true);
+ if (!firmware->getCapability(Capability(SportTelemetry)))
+ m_telemetryDockWidget->toggleViewAction()->setDisabled(true);
+#ifndef JOYSTICKS
+ ui->actionJoystickSettings->setDisabled(true);
+#endif
+
+ // Add radio-specific help text from simulator widget
+ foreach (keymapHelp_t item, *m_simulatorWidget->getKeymapHelp())
+ m_keymapHelp.append(item);
+
+ restoreUiState();
+
+ setStyleSheet(SimulatorStyle::styleSheet());
+
+ connect(ui->actionShowKeymap, &QAction::triggered, this, &SimulatorMainWindow::showHelp);
+ connect(ui->actionJoystickSettings, &QAction::triggered, this, &SimulatorMainWindow::openJoystickDialog);
+ connect(ui->actionReloadLua, &QAction::triggered, this, &SimulatorMainWindow::luaReload);
+ connect(ui->actionToggleRadioTitle, &QAction::toggled, this, &SimulatorMainWindow::showRadioTitlebar);
+ connect(ui->actionToggleMenuBar, &QAction::toggled, this, &SimulatorMainWindow::toggleMenuBar);
+ if (m_simulatorWidget) {
+ connect(ui->actionScreenshot, &QAction::triggered, m_simulatorWidget, &SimulatorDialog::captureScreenshot);
+ connect(ui->actionReloadRadioData, &QAction::triggered, m_simulatorWidget, &SimulatorDialog::restart);
+ }
+ if (m_outputsWidget)
+ connect(ui->actionReloadRadioData, &QAction::triggered, m_outputsWidget, &RadioOutputsWidget::restart);
+
+ // this sets the radio widget to a fixed width while docked, freeform while floating
+ connect(m_simulatorDockWidget, &QDockWidget::topLevelChanged, [this](bool top) {
+ if (top)
+ m_simulatorWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
+ else
+ m_simulatorWidget->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Preferred);
+ });
+
+}
+
+SimulatorMainWindow::~SimulatorMainWindow()
+{
+ delete ui;
+}
+
+void SimulatorMainWindow::closeEvent(QCloseEvent *)
+{
+ saveUiState();
+
+ if (m_consoleDockWidget)
+ delete m_consoleDockWidget;
+ if (m_telemetryDockWidget)
+ delete m_telemetryDockWidget;
+ if (m_trainerDockWidget)
+ delete m_trainerDockWidget;
+ if (m_outputsDockWidget)
+ delete m_outputsDockWidget;
+ if (m_simulatorDockWidget)
+ delete m_simulatorDockWidget;
+}
+
+void SimulatorMainWindow::changeEvent(QEvent *e)
+{
+ QMainWindow::changeEvent(e);
+ switch (e->type()) {
+ case QEvent::LanguageChange:
+ ui->retranslateUi(this);
+ break;
+ default:
+ break;
+ }
+}
+
+QMenu* SimulatorMainWindow::createPopupMenu(){
+ QMenu * menu = QMainWindow::createPopupMenu();
+ menu->addAction(ui->actionToggleMenuBar);
+ menu->addAction(ui->actionToggleRadioTitle);
+ return menu;
+}
+
+void SimulatorMainWindow::saveUiState()
+{
+ QByteArray state;
+ QDataStream stream(&state, QIODevice::WriteOnly);
+ stream << m_savedUiStateVersion << saveState() << m_showMenubar << m_showRadioTitlebar;
+
+ SimulatorOptions opts = g.profile[m_radioProfileId].simulatorOptions();
+ opts.windowState = state;
+ opts.windowGeometry = saveGeometry();
+ g.profile[m_radioProfileId].simulatorOptions(opts);
+}
+
+void SimulatorMainWindow::restoreUiState()
+{
+ quint16 ver = 0;
+ QByteArray windowState;
+ QByteArray state = g.profile[m_radioProfileId].simulatorOptions().windowState;
+ QDataStream stream(state);
+
+ stream >> ver;
+ if (ver && ver <= m_savedUiStateVersion)
+ stream >> windowState >> m_showMenubar >> m_showRadioTitlebar;
+
+ restoreState(windowState);
+ restoreGeometry(g.profile[m_radioProfileId].simulatorOptions().windowGeometry);
+ showRadioTitlebar(m_showRadioTitlebar);
+ toggleMenuBar(m_showMenubar);
+}
+
+bool SimulatorMainWindow::setRadioData(RadioData * radioData)
+{
+ return m_simulatorWidget->setRadioData(radioData);
+}
+
+bool SimulatorMainWindow::useTempDataPath(bool deleteOnClose, bool saveOnClose)
+{
+ return m_simulatorWidget->useTempDataPath(deleteOnClose, saveOnClose);
+}
+
+bool SimulatorMainWindow::setOptions(SimulatorOptions & options, bool withSave)
+{
+ return m_simulatorWidget->setOptions(options, withSave);
+}
+
+void SimulatorMainWindow::start()
+{
+ if (m_consoleWidget)
+ m_consoleWidget->start();
+ if (m_simulatorWidget)
+ m_simulatorWidget->start();
+ if (m_outputsWidget)
+ m_outputsWidget->start();
+}
+
+void SimulatorMainWindow::createDockWidgets()
+{
+ if (!m_outputsDockWidget) {
+ SimulatorIcon icon("radio_outputs");
+ m_outputsDockWidget = new QDockWidget(tr("Radio Outputs"), this);
+ m_outputsWidget = new RadioOutputsWidget(m_simulator, getCurrentFirmware(), this);
+ m_outputsWidget->setWindowIcon(icon);
+ m_outputsDockWidget->setWidget(m_outputsWidget);
+ m_outputsDockWidget->setObjectName("OUTPUTS");
+ addTool(m_outputsDockWidget, Qt::BottomDockWidgetArea, icon, QKeySequence(tr("F2")));
+ }
+
+ if (!m_telemetryDockWidget) {
+ SimulatorIcon icon("telemetry");
+ m_telemetryDockWidget = new QDockWidget(tr("Telemetry Simulator"), this);
+ TelemetrySimulator * telem = new TelemetrySimulator(this, m_simulator);
+ telem->setWindowIcon(icon);
+ m_telemetryDockWidget->setWidget(telem);
+ m_telemetryDockWidget->setObjectName("TELEMETRY_SIMULATOR");
+ addTool(m_telemetryDockWidget, Qt::LeftDockWidgetArea, icon, QKeySequence(tr("F4")));
+ }
+
+ if (!m_trainerDockWidget) {
+ SimulatorIcon icon("trainer");
+ m_trainerDockWidget = new QDockWidget(tr("Trainer Simulator"), this);
+ TrainerSimulator * trainer = new TrainerSimulator(this, m_simulator);
+ trainer->setWindowIcon(icon);
+ m_trainerDockWidget->setWidget(trainer);
+ m_trainerDockWidget->setObjectName("TRAINER_SIMULATOR");
+ addTool(m_trainerDockWidget, Qt::TopDockWidgetArea, icon, QKeySequence(tr("F5")));
+ }
+
+ if (!m_consoleDockWidget) {
+ SimulatorIcon icon("console");
+ m_consoleDockWidget = new QDockWidget(tr("Debug Output"), this);
+ m_consoleWidget = new DebugOutput(this, m_simulator);
+ m_consoleWidget->setWindowIcon(icon);
+ m_consoleDockWidget->setWidget(m_consoleWidget);
+ m_consoleDockWidget->setObjectName("CONSOLE");
+ addTool(m_consoleDockWidget, Qt::RightDockWidgetArea, icon, QKeySequence(tr("F6")));
+ }
+}
+
+void SimulatorMainWindow::addTool(QDockWidget * widget, Qt::DockWidgetArea area, QIcon icon, QKeySequence shortcut)
+{
+ QAction* tempAction = widget->toggleViewAction();
+ tempAction->setIcon(icon);
+ tempAction->setShortcut(shortcut);
+ ui->menuView->addAction(tempAction);
+ ui->toolBar->insertAction(ui->actionReloadLua, tempAction);
+ widget->setAllowedAreas(Qt::AllDockWidgetAreas);
+ widget->setWindowIcon(icon);
+ addDockWidget(area, widget);
+ widget->hide();
+ widget->setFloating(true);
+}
+
+void SimulatorMainWindow::showRadioTitlebar(bool show)
+{
+ m_showRadioTitlebar = show;
+ if (show) {
+ QWidget * w = m_simulatorDockWidget->titleBarWidget();
+ if (w)
+ w->deleteLater();
+ m_simulatorDockWidget->setTitleBarWidget(0);
+ }
+ else {
+ m_simulatorDockWidget->setTitleBarWidget(new QWidget());
+ }
+ if (ui->actionToggleRadioTitle->isChecked() != show)
+ ui->actionToggleRadioTitle->setChecked(show);
+
+}
+
+void SimulatorMainWindow::toggleMenuBar(bool show)
+{
+ m_showMenubar = show;
+ ui->menubar->setVisible(show);
+ if (ui->actionToggleMenuBar->isChecked() != show)
+ ui->actionToggleMenuBar->setChecked(show);
+}
+
+void SimulatorMainWindow::luaReload(bool)
+{
+ // force a reload of the lua environment
+ if (m_simulator)
+ m_simulator->setLuaStateReloadPermanentScripts();
+}
+
+void SimulatorMainWindow::openJoystickDialog(bool)
+{
+#ifdef JOYSTICKS
+ joystickDialog * jd = new joystickDialog(this);
+ if (jd->exec() == QDialog::Accepted && m_simulatorWidget)
+ m_simulatorWidget->setupJoysticks();
+ jd->deleteLater();
+#endif
+}
+
+void SimulatorMainWindow::showHelp(bool show)
+{
+ QString helpText = tr("Simulator Controls:");
+ helpText += "";
+ helpText += tr("Key/Mouse Action ");
+ QString keyTemplate = "%1 %2 ";
+ foreach (keymapHelp_t pair, m_keymapHelp)
+ helpText += keyTemplate.arg(pair.first, pair.second);
+ helpText += "
";
+
+ QMessageBox * msgBox = new QMessageBox(this);
+ msgBox->setAttribute(Qt::WA_DeleteOnClose);
+ msgBox->setWindowFlags(msgBox->windowFlags() | Qt::WindowStaysOnTopHint);
+ msgBox->setStandardButtons( QMessageBox::Ok );
+ msgBox->setWindowTitle(tr("Simulator Help"));
+ msgBox->setText(helpText);
+ msgBox->setModal(false);
+ msgBox->show();
+}
diff --git a/companion/src/simulation/simulatormainwindow.h b/companion/src/simulation/simulatormainwindow.h
new file mode 100644
index 000000000..db5bba39e
--- /dev/null
+++ b/companion/src/simulation/simulatormainwindow.h
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) OpenTX
+ *
+ * Based on code named
+ * th9x - http://code.google.com/p/th9x
+ * er9x - http://code.google.com/p/er9x
+ * gruvin9x - http://code.google.com/p/gruvin9x
+ *
+ * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef SIMULATORMAINWINDOW_H
+#define SIMULATORMAINWINDOW_H
+
+#include "simulator.h"
+
+#include
+#include
+#include
+
+class DebugOutput;
+class RadioData;
+class RadioOutputsWidget;
+class SimulatorDialog;
+class SimulatorInterface;
+class TrainerSimulator;
+class TelemetrySimulator;
+
+class QKeySequence;
+
+namespace Ui {
+class SimulatorMainWindow;
+}
+
+using namespace Simulator;
+
+class SimulatorMainWindow : public QMainWindow
+{
+ Q_OBJECT
+
+ public:
+ explicit SimulatorMainWindow(QWidget * parent, SimulatorInterface * simulator, quint8 flags=0, Qt::WindowFlags wflags = Qt::WindowFlags());
+ ~SimulatorMainWindow();
+
+ bool setRadioData(RadioData * radioData);
+ bool useTempDataPath(bool deleteOnClose = true, bool saveOnClose = false);
+ bool setOptions(SimulatorOptions & options, bool withSave = true);
+ QMenu * createPopupMenu();
+
+ public slots:
+ void start();
+ void showRadioTitlebar(bool show);
+ void toggleMenuBar(bool show);
+
+ protected slots:
+ virtual void closeEvent(QCloseEvent *);
+ virtual void changeEvent(QEvent *e);
+ void restoreUiState();
+ void saveUiState();
+ void luaReload(bool);
+ void openJoystickDialog(bool);
+ void showHelp(bool show);
+
+ protected:
+ void createDockWidgets();
+ void addTool(QDockWidget * widget, Qt::DockWidgetArea area, QIcon icon = QIcon(), QKeySequence shortcut = QKeySequence());
+
+ SimulatorInterface * m_simulator;
+
+ Ui::SimulatorMainWindow * ui;
+ SimulatorDialog * m_simulatorWidget;
+ DebugOutput * m_consoleWidget;
+ RadioOutputsWidget * m_outputsWidget;
+
+ QDockWidget * m_simulatorDockWidget;
+ QDockWidget * m_consoleDockWidget;
+ QDockWidget * m_telemetryDockWidget;
+ QDockWidget * m_trainerDockWidget;
+ QDockWidget * m_outputsDockWidget;
+
+ QVector m_keymapHelp;
+ int m_radioProfileId;
+ bool m_firstShow;
+ bool m_showRadioTitlebar;
+ bool m_showMenubar;
+
+ const static quint16 m_savedUiStateVersion;
+};
+
+#endif // SIMULATORMAINWINDOW_H
diff --git a/companion/src/simulation/simulatormainwindow.ui b/companion/src/simulation/simulatormainwindow.ui
new file mode 100644
index 000000000..1520cd34c
--- /dev/null
+++ b/companion/src/simulation/simulatormainwindow.ui
@@ -0,0 +1,183 @@
+
+
+ SimulatorMainWindow
+
+
+
+ 0
+ 0
+ 644
+ 371
+
+
+
+ OpenTx Simulator
+
+
+
+ :/icon.png :/icon.png
+
+
+ true
+
+
+ QMainWindow::AllowNestedDocks|QMainWindow::AllowTabbedDocks|QMainWindow::AnimatedDocks
+
+
+
+
+
+ Toolbar
+
+
+ LeftToolBarArea
+
+
+ false
+
+
+
+
+
+
+
+
+
+
+
+ :/images/simulator/icons/svg/reload_script.svg :/images/simulator/icons/svg/reload_script.svg
+
+
+ Reload Lua Scripts
+
+
+ Reload the Lua environment on the simulated radio.
+
+
+ F7
+
+
+
+
+
+ :/images/simulator/icons/svg/restart.svg :/images/simulator/icons/svg/restart.svg
+
+
+ Reload Radio Data
+
+
+ Reload all radio data without restarting the simulator.
+
+
+ F9
+
+
+
+
+
+ :/images/simulator/icons/svg/info.svg :/images/simulator/icons/svg/info.svg
+
+
+ Key Mapping
+
+
+ Show keyboard maping reference.
+
+
+ F1
+
+
+
+
+
+ :/images/simulator/icons/svg/joystick_settings.svg :/images/simulator/icons/svg/joystick_settings.svg
+
+
+ Joystick Settings
+
+
+ Open joystick configuration settings dialog.
+
+
+ F3
+
+
+
+
+
+ :/images/simulator/icons/svg/camera.svg :/images/simulator/icons/svg/camera.svg
+
+
+ LCD Screenshot
+
+
+ Save a screenshot of the current simulated LCD screen.
+
+
+ F8
+
+
+
+
+ true
+
+
+ Radio Titlebar
+
+
+ <html><head/><body><p>The title bar on the main radio window allows you to undock it or move it around separately from the other windows. Hiding the title makes a more compact and streamlined appearance.</p></body></html>
+
+
+
+
+ true
+
+
+ Menu Bar
+
+
+ Show or hide the top menu bar.
+
+
+ Alt+M
+
+
+
+
+
+
diff --git a/companion/src/simulation/simulatorstartupdialog.ui b/companion/src/simulation/simulatorstartupdialog.ui
index de6ac01c0..ba97d2c75 100644
--- a/companion/src/simulation/simulatorstartupdialog.ui
+++ b/companion/src/simulation/simulatorstartupdialog.ui
@@ -6,10 +6,16 @@
0
0
- 488
- 219
+ 550
+ 217
+
+
+ 550
+ 0
+
+
OpenTX Simulator - Startup Options
@@ -22,13 +28,28 @@
-
+
+
+ 0
+ 0
+
+
Simulator Startup Options:
+
+ QLayout::SetNoConstraint
+
+
+ QFormLayout::AllNonFixedFieldsGrow
+
Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+ Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop
+
5
@@ -56,6 +77,12 @@
-
+
+
+ 0
+ 0
+
+
Existing radio profiles are shown here.<br />
Create or edit profiles using the Companion application.
@@ -71,6 +98,12 @@ Create or edit profiles using the Companion application.
-
+
+
+ 0
+ 0
+
+
Existing radio simulators are shown here.<br />
The radio type specified in the selected profile is used by default.
@@ -107,6 +140,12 @@ The radio type specified in the selected profile is used by default.
-
+
+
+ 0
+ 0
+
+
4
@@ -140,7 +179,7 @@ The radio type specified in the selected profile is used by default.
...
-
+
:/themes/monoblue/16/open.png :/themes/monoblue/16/open.png
@@ -153,6 +192,12 @@ The radio type specified in the selected profile is used by default.
-
+
+
+ 0
+ 0
+
+
4
@@ -186,7 +231,7 @@ New folder(s) with default radio/model will be created here if necessary....
-
+
:/themes/monoblue/16/open.png :/themes/monoblue/16/open.png
@@ -199,6 +244,12 @@ New folder(s) with default radio/model will be created here if necessary.
-
+
+
+ 0
+ 0
+
+
4
@@ -232,7 +283,7 @@ The default is configured in the chosen Radio Profile.
...
-
+
:/themes/monoblue/16/open.png :/themes/monoblue/16/open.png
@@ -245,6 +296,12 @@ The default is configured in the chosen Radio Profile.
-
+
+
+ 0
+ 0
+
+
Select which of the data sources (File/Folder/SD Card) you would like to start the simulator with.
@@ -312,9 +369,7 @@ The default is configured in the chosen Radio Profile.
-
-
-
+
buttonBox
diff --git a/companion/src/simulation/telemetrysimu.cpp b/companion/src/simulation/telemetrysimu.cpp
index 8ca0eca9b..46ff5f3e9 100644
--- a/companion/src/simulation/telemetrysimu.cpp
+++ b/companion/src/simulation/telemetrysimu.cpp
@@ -25,24 +25,20 @@
#include "radio/src/telemetry/frsky.h"
TelemetrySimulator::TelemetrySimulator(QWidget * parent, SimulatorInterface * simulator):
- QDialog(parent),
+ QWidget(parent),
ui(new Ui::TelemetrySimulator),
simulator(simulator)
{
ui->setupUi(this);
- QPoint dialogCenter = mapToGlobal(rect().center());
- QPoint parentWindowCenter = parent->window()->mapToGlobal(
- parent->window()->rect().center());
- move(parentWindowCenter - dialogCenter);
-
timer = new QTimer(this);
+ timer->setInterval(10);
connect(timer, SIGNAL(timeout()), this, SLOT(onTimerEvent()));
logTimer = new QTimer(this);
connect(logTimer, SIGNAL(timeout()), this, SLOT(onLogTimerEvent()));
- connect(ui->Simulate, SIGNAL(clicked(bool)), this, SLOT(onSimulateToggled(bool)));
+ connect(ui->Simulate, SIGNAL(toggled(bool)), this, SLOT(onSimulateToggled(bool)));
connect(ui->loadLogFile, SIGNAL(released()), this, SLOT(onLoadLogFile()));
connect(ui->play, SIGNAL(released()), this, SLOT(onPlay()));
connect(ui->rewind, SIGNAL(clicked()), this, SLOT(onRewind()));
@@ -76,7 +72,7 @@ TelemetrySimulator::~TelemetrySimulator()
void TelemetrySimulator::onSimulateToggled(bool isChecked)
{
if (isChecked) {
- timer->start(10);
+ timer->start();
}
else {
timer->stop();
@@ -197,9 +193,6 @@ void TelemetrySimulator::showEvent(QShowEvent *event)
ui->rxbt_ratio->setValue(simulator->getSensorRatio(BATT_ID) / 10.0);
ui->A1_ratio->setValue(simulator->getSensorRatio(ADC1_ID) / 10.0);
ui->A2_ratio->setValue(simulator->getSensorRatio(ADC2_ID) / 10.0);
-
- ui->Simulate->setChecked(true);
- onSimulateToggled(true); // not sure why this doesn't fire automatically
}
void setSportPacketCrc(uint8_t * packet)
@@ -216,7 +209,7 @@ void setSportPacketCrc(uint8_t * packet)
//TRACE("crc set: %x", packet[FRSKY_SPORT_PACKET_SIZE-1]);
}
-uint8_t getBit(uint8_t position, uint8_t value)
+uint8_t getBit(uint8_t position, uint8_t value)
{
return (value & (uint8_t)(1 << position)) ? 1 : 0;
}
@@ -224,7 +217,7 @@ uint8_t getBit(uint8_t position, uint8_t value)
bool generateSportPacket(uint8_t * packet, uint8_t dataId, uint8_t prim, uint16_t appId, uint32_t data)
{
if (dataId > 0x1B ) return false;
-
+
// generate Data ID field
uint8_t bit5 = getBit(0, dataId) ^ getBit(1, dataId) ^ getBit(2, dataId);
uint8_t bit6 = getBit(2, dataId) ^ getBit(3, dataId) ^ getBit(4, dataId);
@@ -483,7 +476,7 @@ uint32_t TelemetrySimulator::FlvssEmulator::setAllCells_GetNextPair(double cellV
// encode the double values into telemetry format
encodeAllCells();
- // return the value for the current pair
+ // return the value for the current pair
uint32_t cellData = 0;
if (nextCellNum >= numCells) {
nextCellNum = 0;
@@ -644,7 +637,7 @@ TelemetrySimulator::LogPlaybackController::LogPlaybackController(Ui::TelemetrySi
colToFuncMap.insert("AccX(g)", ACCX);
colToFuncMap.insert("AccY(g)", ACCY);
colToFuncMap.insert("AccZ(g)", ACCZ);
-
+
// ACCX Y and Z
}
@@ -839,7 +832,7 @@ double TelemetrySimulator::LogPlaybackController::convertDegMin(QString input)
QString TelemetrySimulator::LogPlaybackController::convertGPS(QString input)
{
- // input format is DDmm.mmmmH DDDmm.mmmmH (longitude latitude - degrees (2 places) minutes (2 places) decimal minutes (4 places))
+ // input format is DDmm.mmmmH DDDmm.mmmmH (longitude latitude - degrees (2 places) minutes (2 places) decimal minutes (4 places))
QStringList lonLat = input.simplified().split(' ');
if (lonLat.count() < 2) {
return ""; // invalid format
diff --git a/companion/src/simulation/telemetrysimu.h b/companion/src/simulation/telemetrysimu.h
index b7387f39a..bd0096ba8 100644
--- a/companion/src/simulation/telemetrysimu.h
+++ b/companion/src/simulation/telemetrysimu.h
@@ -22,7 +22,7 @@
#define _TELEMETRYSIMU_H_
#include
-#include
+#include
#include
#include
#include
@@ -37,102 +37,19 @@ namespace Ui {
class TelemetrySimulator;
}
-
-class TelemetrySimulator : public QDialog
+class TelemetrySimulator : public QWidget
{
Q_OBJECT
public:
+
explicit TelemetrySimulator(QWidget * parent, SimulatorInterface * simulator);
virtual ~TelemetrySimulator();
- protected:
+ protected slots:
+
virtual void closeEvent(QCloseEvent *event);
virtual void showEvent(QShowEvent *event);
-
- private:
- class LogPlaybackController
- {
- public:
- LogPlaybackController(Ui::TelemetrySimulator * ui);
- bool isReady();
- void loadLogFile();
- void play();
- void stop();
- void rewind();
- void stepForward(bool focusOnStop);
- void stepBack();
- void updatePositionLabel(int32_t percentage);
- void setUiDataValues();
- double logFrequency; // in seconds
- private:
- enum CONVERT_TYPE {
- RXBT_V,
- RSSI,
- SWR,
- A1,
- A2,
- A3,
- A4,
- T1_DEGC,
- T1_DEGF,
- T2_DEGC,
- T2_DEGF,
- RPM,
- FUEL,
- VSPD_MS,
- VSPD_FS,
- ALT_FEET,
- ALT_METERS,
- FASV,
- FASC,
- CELS_GRE,
- ASPD_KTS,
- ASPD_KMH,
- ASPD_MPH,
- GALT_FEET,
- GALT_METERS,
- GSPD_KNTS,
- GSPD_KMH,
- GSPD_MPH,
- GHDG_DEG,
- GDATE,
- G_LATLON,
- ACCX,
- ACCY,
- ACCZ,
- FUEL_QTY,
- };
- QMap colToFuncMap; // contains all 'known' column headings and how they are to be processed
- Ui::TelemetrySimulator * ui;
- struct DATA_TO_FUNC_XREF {
- CONVERT_TYPE functionIndex;
- int32_t dataIndex;
- };
- QStringList csvRecords; // contents of the log file (one string per line);
- QStringList columnNames;
- QList supportedCols;
- int32_t recordIndex;
- double convertFeetToMeters(QString input);
- double convertFahrenheitToCelsius(QString input);
- QString convertGPSDate(QString input);
- QString convertGPS(QString input);
- void addColumnHash(QString key, CONVERT_TYPE functionIndex);
- double convertDegMin(QString input);
- bool stepping;
- QDateTime parseTransmittterTimestamp(QString row);
- void calcLogFrequency();
- };
-
-private:
- Ui::TelemetrySimulator * ui;
- QTimer * timer;
- QTimer * logTimer;
- SimulatorInterface *simulator;
- void generateTelemetryFrame();
- TelemetrySimulator::LogPlaybackController *logPlayback;
-
- private slots:
void onSimulateToggled(bool isChecked);
void onTimerEvent();
void onLogTimerEvent();
@@ -145,49 +62,138 @@ private:
void onPositionIndicatorChanged(int value);
void onReplayRateChanged(int value);
+ protected:
+
+ Ui::TelemetrySimulator * ui;
+ QTimer * timer;
+ QTimer * logTimer;
+ SimulatorInterface *simulator;
+ void generateTelemetryFrame();
+
+ // protected classes follow
+
+ class LogPlaybackController
+ {
+ public:
+ LogPlaybackController(Ui::TelemetrySimulator * ui);
+ bool isReady();
+ void loadLogFile();
+ void play();
+ void stop();
+ void rewind();
+ void stepForward(bool focusOnStop);
+ void stepBack();
+ void updatePositionLabel(int32_t percentage);
+ void setUiDataValues();
+ double logFrequency; // in seconds
+
+ private:
+ enum CONVERT_TYPE {
+ RXBT_V,
+ RSSI,
+ SWR,
+ A1,
+ A2,
+ A3,
+ A4,
+ T1_DEGC,
+ T1_DEGF,
+ T2_DEGC,
+ T2_DEGF,
+ RPM,
+ FUEL,
+ VSPD_MS,
+ VSPD_FS,
+ ALT_FEET,
+ ALT_METERS,
+ FASV,
+ FASC,
+ CELS_GRE,
+ ASPD_KTS,
+ ASPD_KMH,
+ ASPD_MPH,
+ GALT_FEET,
+ GALT_METERS,
+ GSPD_KNTS,
+ GSPD_KMH,
+ GSPD_MPH,
+ GHDG_DEG,
+ GDATE,
+ G_LATLON,
+ ACCX,
+ ACCY,
+ ACCZ,
+ FUEL_QTY,
+ };
+
+ struct DATA_TO_FUNC_XREF {
+ CONVERT_TYPE functionIndex;
+ int32_t dataIndex;
+ };
+
+ double convertFeetToMeters(QString input);
+ double convertFahrenheitToCelsius(QString input);
+ QString convertGPSDate(QString input);
+ QString convertGPS(QString input);
+ void addColumnHash(QString key, CONVERT_TYPE functionIndex);
+ double convertDegMin(QString input);
+ QDateTime parseTransmittterTimestamp(QString row);
+ void calcLogFrequency();
+
+ QMap colToFuncMap; // contains all 'known' column headings and how they are to be processed
+ Ui::TelemetrySimulator * ui;
+ QStringList csvRecords; // contents of the log file (one string per line);
+ QStringList columnNames;
+ QList supportedCols;
+ int32_t recordIndex;
+ bool stepping;
+ }; // LogPlaybackController
+
+ LogPlaybackController *logPlayback;
- private: // private classes follow
class FlvssEmulator
{
- public:
+ public:
uint32_t setAllCells_GetNextPair(double cellValues[6]);
static const uint32_t MAXCELLS = 6;
- private:
- void encodeAllCells();
- void splitIntoCells(double totalVolts);
- static uint32_t encodeCellPair(uint8_t cellNum, uint8_t firstCellNo, double cell1, double cell2);
- double cellFloats[6];
- uint32_t nextCellNum;
- uint32_t numCells;
- uint32_t cellData1;
- uint32_t cellData2;
- uint32_t cellData3;
- };
+
+ private:
+ void encodeAllCells();
+ void splitIntoCells(double totalVolts);
+ static uint32_t encodeCellPair(uint8_t cellNum, uint8_t firstCellNo, double cell1, double cell2);
+ double cellFloats[6];
+ uint32_t nextCellNum;
+ uint32_t numCells;
+ uint32_t cellData1;
+ uint32_t cellData2;
+ uint32_t cellData3;
+ }; // FlvssEmulator
class GPSEmulator
{
- public:
- GPSEmulator();
- uint32_t getNextPacketData(uint32_t packetType);
- void setGPSDateTime(QString dateTime);
- void setGPSLatLon(QString latLon);
- void setGPSCourse(double course);
- void setGPSSpeedKMH(double speed);
- void setGPSAltitude(double altitude);
- private:
- QDateTime dt;
- bool sendLat;
- bool sendDate;
- double lat;
- double lon;
- double course;
- double speedKNTS;
- double altitude; // in meters
- uint32_t encodeLatLon(double latLon, bool isLat);
- uint32_t encodeDateTime(uint8_t yearOrHour, uint8_t monthOrMinute, uint8_t dayOrSecond, bool isDate);
- };
+ public:
+ GPSEmulator();
+ uint32_t getNextPacketData(uint32_t packetType);
+ void setGPSDateTime(QString dateTime);
+ void setGPSLatLon(QString latLon);
+ void setGPSCourse(double course);
+ void setGPSSpeedKMH(double speed);
+ void setGPSAltitude(double altitude);
-};
+ private:
+ QDateTime dt;
+ bool sendLat;
+ bool sendDate;
+ double lat;
+ double lon;
+ double course;
+ double speedKNTS;
+ double altitude; // in meters
+ uint32_t encodeLatLon(double latLon, bool isLat);
+ uint32_t encodeDateTime(uint8_t yearOrHour, uint8_t monthOrMinute, uint8_t dayOrSecond, bool isDate);
+ }; // GPSEmulator
+
+}; // TelemetrySimulator
#endif // _TELEMETRYSIMU_H_
diff --git a/companion/src/simulation/telemetrysimu.ui b/companion/src/simulation/telemetrysimu.ui
index 0c897fb1c..fbc909e2a 100644
--- a/companion/src/simulation/telemetrysimu.ui
+++ b/companion/src/simulation/telemetrysimu.ui
@@ -1,13 +1,13 @@
TelemetrySimulator
-
+
0
0
- 759
- 539
+ 715
+ 484
@@ -18,1777 +18,2943 @@
Telemetry Simulator
-
-
-
- 10
- 50
- 101
- 31
-
+
+
+ 7
-
-
- 12
-
+
+ 7
-
- When enabled, sends any non-blank values as simulated telemetry data.
+
+ 7
-
- Simulate
+
+ 6
-
-
-
-
- 120
- 10
- 621
- 111
-
+
+ 10
-
-
- 8
-
+
+ 7
-
- Replay SD Log File
-
-
- Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop
-
-
-
-
- 410
- 10
- 201
- 33
-
-
-
-
- QLayout::SetMinimumSize
+ -
+
+
+
+ 0
+ 0
+
- -
-
-
- false
-
-
-
- 30
- 16777215
-
-
-
- Qt::StrongFocus
-
-
- |>
-
-
- false
-
-
- true
-
-
- false
-
-
-
- -
-
-
- false
-
-
-
- 30
- 16777215
-
-
-
- Qt::StrongFocus
-
-
- <|
-
-
- false
-
-
- true
-
-
- false
-
-
-
- -
-
-
- false
-
-
-
- 0
- 0
-
-
-
-
- 30
- 16777215
-
-
-
- Qt::StrongFocus
-
-
- >
-
-
- true
-
-
- true
-
-
- false
-
-
-
- -
-
-
- false
-
-
-
- 0
- 0
-
-
-
-
- 30
- 16777215
-
-
-
- Qt::StrongFocus
-
-
- <-
-
-
- false
-
-
- true
-
-
- false
-
-
- false
-
-
-
- -
-
-
- false
-
-
-
- 30
- 16777215
-
-
-
- Qt::StrongFocus
-
-
- X
-
-
- true
-
-
- true
-
-
- false
-
-
-
-
-
-
-
-
- 100
- 30
- 201
- 21
-
-
-
-
- 8
-
-
-
- No Log File Currently Loaded
-
-
-
-
-
- 10
- 30
- 75
- 23
-
-
-
- Load
-
-
- false
-
-
-
-
- false
-
-
-
- 410
- 50
- 201
- 16
-
-
-
- Qt::Horizontal
-
-
-
-
- false
-
-
-
- 150
- 70
- 161
- 22
-
-
-
- 8
-
-
- 1
-
-
- 4
-
-
- Qt::Horizontal
-
-
-
-
-
- 140
- 90
- 181
- 20
-
-
-
-
- 8
-
-
-
- Replay rate (1/5 -> 5x)
-
-
- Qt::AlignCenter
-
-
-
-
-
- 410
- 70
- 191
- 31
-
-
-
-
- 8
-
-
-
- Qt::LeftToRight
-
-
- Row #
-Timestamp
-
-
- Qt::AlignCenter
-
-
-
-
-
-
- 10
- 130
- 741
- 401
-
-
-
- -
-
-
-
- 8
-
+
+
+ 12
+
+
+
+ When enabled, sends any non-blank values as simulated telemetry data.
+
+
+ Simulate
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 8
+
+
+
+ Replay SD Log File
+
+
+ Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop
+
+
+
+ 0
-
- RxBt
+
+ 3
-
-
- -
-
-
-
- 8
-
+
+ 0
-
-
- -
-
- -
-
+ -
+
8
-
- 2
+
+ Replay rate
+
+
+ Qt::AlignCenter
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Load
+
+
+ false
+
+
+
+ -
+
+
+ false
+
+
+
+ 0
+ 0
+
- 16777215.000000000000000
+ 8
-
- 0.100000000000000
+
+ 1
- 5.200000000000000
+ 4
+
+
+ Qt::Horizontal
- -
-
-
-
- 8
-
+ -
+
+
+ 4
-
- 2
-
-
- 16777215.000000000000000
-
-
- 0.100000000000000
-
-
-
-
-
- -
-
-
-
- 8
-
-
-
- V / ratio
-
-
-
- -
-
-
-
- 8
-
-
-
- <html><head/><body><p><br/></p></body></html>
-
-
- VFAS
-
-
-
- -
-
-
-
- 8
-
-
-
-
- -
-
-
-
- 8
-
-
-
- 2
-
-
- -16777215.000000000000000
-
-
- 16777215.000000000000000
-
-
- 0.100000000000000
-
-
-
- -
-
-
-
- 8
-
-
-
- Volts
-
-
-
- -
-
-
-
- 8
-
-
-
- RSSI
-
-
-
- -
-
-
-
- 8
-
-
-
-
- -
-
-
-
- 8
-
-
-
- 75
-
-
-
- -
-
-
-
- 8
-
-
-
- Db
-
-
-
- -
-
-
-
- 8
-
-
-
- <html><head/><body><p><br/></p></body></html>
-
-
- Curr
-
-
-
- -
-
-
-
- 8
-
-
-
-
- -
-
-
-
- 8
-
-
-
- 1
-
-
- -16777215.000000000000000
-
-
- 16777215.000000000000000
-
-
- 0.100000000000000
-
-
-
- -
-
-
-
- 8
-
-
-
- Amps
-
-
-
- -
-
-
-
- 8
-
-
-
- SWR
-
-
-
- -
-
-
-
- 8
-
-
-
-
- -
-
-
-
- 8
-
-
-
- 30
-
-
-
- -
-
-
-
- 8
-
-
-
- <html><head/><body><p><br/></p></body></html>
-
-
- Cels
-
-
-
- -
-
-
-
- 8
-
-
-
-
- -
-
- -
-
-
-
- 8
-
-
-
- 0.100000000000000
-
-
-
- -
-
-
-
- 8
-
-
-
- 0.100000000000000
-
-
-
- -
-
-
-
- 8
-
-
-
- 0.100000000000000
-
-
-
- -
-
-
-
- 8
-
-
-
- 0.100000000000000
-
-
+ -
+
+
+ QLayout::SetMinimumSize
+
+ -
+
+
+ false
+
+
+
+ 30
+ 16777215
+
+
+
+ Qt::StrongFocus
+
+
+ |>
+
+
+ false
+
+
+ true
+
+
+ false
+
+
+
+ -
+
+
+ false
+
+
+
+ 30
+ 16777215
+
+
+
+ Qt::StrongFocus
+
+
+ <|
+
+
+ false
+
+
+ true
+
+
+ false
+
+
+
+ -
+
+
+ false
+
+
+
+ 0
+ 0
+
+
+
+
+ 30
+ 16777215
+
+
+
+ Qt::StrongFocus
+
+
+ >
+
+
+ true
+
+
+ true
+
+
+ false
+
+
+
+ -
+
+
+ false
+
+
+
+ 0
+ 0
+
+
+
+
+ 30
+ 16777215
+
+
+
+ Qt::StrongFocus
+
+
+ <-
+
+
+ false
+
+
+ true
+
+
+ false
+
+
+ false
+
+
+
+ -
+
+
+ false
+
+
+
+ 30
+ 16777215
+
+
+
+ Qt::StrongFocus
+
+
+ X
+
+
+ true
+
+
+ true
+
+
+ false
+
+
+
+
+
+ -
+
+
+ false
+
+
+ Qt::Horizontal
+
+
+
+ -
+
+
+
+ 8
+
+
+
+ Qt::LeftToRight
+
+
+ Row #
+Timestamp
+
+
+ Qt::AlignCenter
+
+
+
+
-
-
-
-
- 8
-
+
+
+
+ 0
+ 0
+
-
- 0.100000000000000
+
+ 1/5x
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
- -
-
+ -
+
+
+
+ 0
+ 0
+
+
+
+ 5x
+
+
+
+ -
+
8
-
- 0.100000000000000
+
+ No Log File Currently Loaded
-
- -
-
-
-
- 8
-
+
+
+ -
+
+
+
+ 0
+ 1
+
+
+
+
+ 16
-
- Volts
+
+ 0
-
-
- -
-
-
-
- 8
-
+
+ 0
-
- A1
+
+ 0
-
-
- -
-
-
-
- 8
-
+
+ 0
-
-
- -
-
-
-
-
-
- 8
-
+
+
+
+ 0
+ 0
+
-
- 2
+
+ QFrame::NoFrame
-
- 16777215.000000000000000
+
+ Qt::ScrollBarAlwaysOff
-
- 0.100000000000000
+
+ true
+
+ Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop
+
+
+
+
+ 0
+ 0
+ 346
+ 370
+
+
+
+
+ 0
+ 0
+
+
+
+
+ 0
+
+
+ 0
+
+
+ 4
+
+
+ 0
+
+
+ 3
+
+
+ 5
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 8
+
+
+
+ -16777215
+
+
+ 16777215
+
+
+ 1
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 45
+ 0
+
+
+
+
+ 45
+ 16777215
+
+
+
+
+ 8
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 8
+
+
+
+ SWR
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 8
+
+
+
+ A2
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 45
+ 0
+
+
+
+
+ 45
+ 16777215
+
+
+
+
+ 8
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 8
+
+
+
+ V / ratio
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 45
+ 0
+
+
+
+
+ 45
+ 16777215
+
+
+
+
+ 8
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 8
+
+
+
+ 30
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 8
+
+
+
+ 75
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 45
+ 0
+
+
+
+
+ 45
+ 16777215
+
+
+
+
+ 8
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 8
+
+
+
+ Db
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 45
+ 0
+
+
+
+
+ 45
+ 16777215
+
+
+
+
+ 8
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 8
+
+
+
+ V / ratio
+
+
+
+ -
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 8
+
+
+
+ 2
+
+
+ 99.000000000000000
+
+
+ 0.100000000000000
+
+
+ 5.200000000000000
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 8
+
+
+
+ 2
+
+
+ 99.000000000000000
+
+
+ 0.100000000000000
+
+
+
+
+
+ -
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 8
+
+
+
+ 2
+
+
+ 999.000000000000000
+
+
+ 0.100000000000000
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 8
+
+
+
+ 2
+
+
+ 999.000000000000000
+
+
+ 0.100000000000000
+
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 8
+
+
+
+ RxBt
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 8
+
+
+
+ A1
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 45
+ 0
+
+
+
+
+ 45
+ 16777215
+
+
+
+
+ 8
+
+
+
+
+ -
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 8
+
+
+
+ 2
+
+
+ 999.000000000000000
+
+
+ 0.100000000000000
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 8
+
+
+
+ 2
+
+
+ 999.000000000000000
+
+
+ 0.100000000000000
+
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 8
+
+
+
+ V / ratio
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 8
+
+
+
+ 16777215
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 8
+
+
+
+ <html><head/><body><p><br/></p></body></html>
+
+
+ Tmp1
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 8
+
+
+
+ A3
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 45
+ 0
+
+
+
+
+ 45
+ 16777215
+
+
+
+
+ 8
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 45
+ 0
+
+
+
+
+ 45
+ 16777215
+
+
+
+
+ 8
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 8
+
+
+
+ A4
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 8
+
+
+
+ RSSI
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 8
+
+
+
+ 16777215
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 8
+
+
+
+ <html><head/><body><p><br/></p></body></html>
+
+
+ Tmp2
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 45
+ 0
+
+
+
+
+ 45
+ 16777215
+
+
+
+
+ 8
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 8
+
+
+
+ RPM
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 45
+ 0
+
+
+
+
+ 45
+ 16777215
+
+
+
+
+ 8
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 8
+
+
+
+ 100000
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 8
+
+
+
+ Fuel
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 45
+ 0
+
+
+
+
+ 45
+ 16777215
+
+
+
+
+ 8
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 8
+
+
+
+ °C
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 8
+
+
+
+ 2147483647
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 8
+
+
+
+ ml
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 8
+
+
+
+ Deg. C
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 8
+
+
+
+ 65535
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 8
+
+
+
+ RPM
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 8
+
+
+
+ %
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 8
+
+
+
+ Meters
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 45
+ 0
+
+
+
+
+ 45
+ 16777215
+
+
+
+
+ 8
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 8
+
+
+
+ 2
+
+
+ -16777215.000000000000000
+
+
+ 16777215.000000000000000
+
+
+ 0.100000000000000
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 8
+
+
+
+ <html><head/><body><p><br/></p></body></html>
+
+
+ Alt
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 45
+ 0
+
+
+
+
+ 45
+ 16777215
+
+
+
+
+ 8
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 8
+
+
+
+ 2
+
+
+ -16777215.000000000000000
+
+
+ 16777215.000000000000000
+
+
+ 0.100000000000000
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 8
+
+
+
+ -16777215
+
+
+ 16777215
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 45
+ 0
+
+
+
+
+ 45
+ 16777215
+
+
+
+
+ 8
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 8
+
+
+
+ <html><head/><body><p><br/></p></body></html>
+
+
+ VSpd
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 8
+
+
+
+ m/s
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 8
+
+
+
+ Fuel Qty
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 40
+
+
+
+
+
+
-
-
-
-
- 8
-
+
+
+
+ 0
+ 0
+
-
- 2
+
+ QFrame::NoFrame
-
- 16777215.000000000000000
+
+ Qt::ScrollBarAlwaysOff
-
- 0.100000000000000
+
+ true
+
+ Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop
+
+
+
+
+ 0
+ 0
+ 339
+ 370
+
+
+
+
+ 0
+ 0
+
+
+
+
+ 0
+
+
+ 0
+
+
+ 4
+
+
+ 0
+
+
+ 3
+
+
+ 5
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 8
+
+
+
+ km/h
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 8
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 8
+
+
+
+ <html><head/><body><p><br/></p></body></html>
+
+
+ VFAS
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 45
+ 0
+
+
+
+
+ 45
+ 16777215
+
+
+
+
+ 8
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 8
+
+
+
+ <html><head/><body><p><br/></p></body></html>
+
+
+ Hdg
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 45
+ 0
+
+
+
+
+ 45
+ 16777215
+
+
+
+
+ 8
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 8
+
+
+
+ <html><head/><body><p><br/></p></body></html>
+
+
+ ASpd
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 8
+
+
+
+ G
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 45
+ 0
+
+
+
+
+ 45
+ 16777215
+
+
+
+
+ 8
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 45
+ 0
+
+
+
+
+ 45
+ 16777215
+
+
+
+
+ 8
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 8
+
+
+
+ km/h
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 8
+
+
+
+ <html><head/><body><p><br/></p></body></html>
+
+
+ GPS
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 45
+ 0
+
+
+
+
+ 45
+ 16777215
+
+
+
+
+ 8
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 45
+ 0
+
+
+
+
+ 45
+ 16777215
+
+
+
+
+ 8
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 8
+
+
+
+ 2
+
+
+ -16777215.000000000000000
+
+
+ 16777215.000000000000000
+
+
+ 0.100000000000000
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 8
+
+
+
+ 2
+
+
+ -16777215.000000000000000
+
+
+ 16777215.000000000000000
+
+
+ 0.100000000000000
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 8
+
+
+
+ Lat,Lon
+(dec.deg.)
+
+
+ false
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 45
+ 0
+
+
+
+
+ 45
+ 16777215
+
+
+
+
+ 8
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 8
+
+
+
+ 2
+
+
+ -16777215.000000000000000
+
+
+ 16777215.000000000000000
+
+
+ 0.100000000000000
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 8
+
+
+
+ AccX
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 8
+
+
+
+ 2
+
+
+ -16777215.000000000000000
+
+
+ 16777215.000000000000000
+
+
+ 0.100000000000000
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 8
+
+
+
+ dd-MM-yyyy
+hh:mm:ss
+
+
+ false
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 45
+ 0
+
+
+
+
+ 45
+ 16777215
+
+
+
+
+ 8
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 8
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 45
+ 0
+
+
+
+
+ 45
+ 16777215
+
+
+
+
+ 8
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 8
+
+
+
+ <html><head/><body><p><br/></p></body></html>
+
+
+ Date
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 8
+
+
+
+ Amps
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 8
+
+
+
+ G
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 8
+
+
+
+ AccZ
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 8
+
+
+
+ 2
+
+
+ -16777215.000000000000000
+
+
+ 16777215.000000000000000
+
+
+ 0.100000000000000
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 8
+
+
+
+ <html><head/><body><p><br/></p></body></html>
+
+
+ GAlt
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 8
+
+
+
+ 2
+
+
+ -16777215.000000000000000
+
+
+ 16777215.000000000000000
+
+
+ 0.100000000000000
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 45
+ 0
+
+
+
+
+ 45
+ 16777215
+
+
+
+
+ 8
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 8
+
+
+
+ 1
+
+
+ -16777215.000000000000000
+
+
+ 16777215.000000000000000
+
+
+ 0.100000000000000
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 8
+
+
+
+ Volts
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 8
+
+
+
+ <html><head/><body><p><br/></p></body></html>
+
+
+ Cels
+
+
+
+ -
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 8
+
+
+
+ 0.100000000000000
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 8
+
+
+
+ 0.100000000000000
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 8
+
+
+
+ 0.100000000000000
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 8
+
+
+
+ 0.100000000000000
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 8
+
+
+
+ 0.100000000000000
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 8
+
+
+
+ 0.100000000000000
+
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 8
+
+
+
+ <html><head/><body><p><br/></p></body></html>
+
+
+ Curr
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 45
+ 0
+
+
+
+
+ 45
+ 16777215
+
+
+
+
+ 8
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 8
+
+
+
+ Volts
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 8
+
+
+
+ AccY
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 8
+
+
+
+ Meters
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 45
+ 0
+
+
+
+
+ 45
+ 16777215
+
+
+
+
+ 8
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 8
+
+
+
+ 1
+
+
+ -16777215.000000000000000
+
+
+ 16777215.000000000000000
+
+
+ 0.100000000000000
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 8
+
+
+
+ <html><head/><body><p><br/></p></body></html>
+
+
+ GSpd
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 8
+
+
+
+ Degrees
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 8
+
+
+
+ 2
+
+
+ -16777215.000000000000000
+
+
+ 16777215.000000000000000
+
+
+ 0.100000000000000
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 8
+
+
+
+ G
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 40
+
+
+
+
+
+
-
- -
-
-
-
- 8
-
-
-
- V / ratio
-
-
-
- -
-
-
-
- 8
-
-
-
- A2
-
-
-
- -
-
-
-
- 8
-
-
-
-
- -
-
- -
-
-
-
- 8
-
-
-
- 2
-
-
- 16777215.000000000000000
-
-
- 0.100000000000000
-
-
-
- -
-
-
-
- 8
-
-
-
- 2
-
-
- 16777215.000000000000000
-
-
- 0.100000000000000
-
-
-
-
-
- -
-
-
-
- 8
-
-
-
- V / ratio
-
-
-
- -
-
-
-
- 8
-
-
-
- <html><head/><body><p><br/></p></body></html>
-
-
- ASpd
-
-
-
- -
-
-
-
- 8
-
-
-
-
- -
-
-
-
- 8
-
-
-
- 2
-
-
- -16777215.000000000000000
-
-
- 16777215.000000000000000
-
-
- 0.100000000000000
-
-
-
- -
-
-
-
- 8
-
-
-
- km/h
-
-
-
- -
-
-
-
- 8
-
-
-
- A3
-
-
-
- -
-
-
-
- 8
-
-
-
-
- -
-
-
-
- 8
-
-
-
- 16777215
-
-
-
- -
-
-
-
- 8
-
-
-
- <html><head/><body><p><br/></p></body></html>
-
-
- GAlt
-
-
-
- -
-
-
-
- 8
-
-
-
-
- -
-
-
-
- 8
-
-
-
- 2
-
-
- -16777215.000000000000000
-
-
- 16777215.000000000000000
-
-
- 0.100000000000000
-
-
-
- -
-
-
-
- 8
-
-
-
- Meters
-
-
-
- -
-
-
-
- 8
-
-
-
- A4
-
-
-
- -
-
-
-
- 8
-
-
-
-
- -
-
-
-
- 8
-
-
-
- 16777215
-
-
-
- -
-
-
-
- 8
-
-
-
- <html><head/><body><p><br/></p></body></html>
-
-
- GSpd
-
-
-
- -
-
-
-
- 8
-
-
-
-
- -
-
-
-
- 8
-
-
-
- 1
-
-
- -16777215.000000000000000
-
-
- 16777215.000000000000000
-
-
- 0.100000000000000
-
-
-
- -
-
-
-
- 8
-
-
-
- km/h
-
-
-
- -
-
-
-
- 8
-
-
-
- <html><head/><body><p><br/></p></body></html>
-
-
- Tmp1
-
-
-
- -
-
-
-
- 8
-
-
-
-
- -
-
-
-
- 8
-
-
-
- -16777215
-
-
- 16777215
-
-
- 1
-
-
-
- -
-
-
-
- 8
-
-
-
- Deg. C
-
-
-
- -
-
-
-
- 8
-
-
-
- <html><head/><body><p><br/></p></body></html>
-
-
- Hdg
-
-
-
- -
-
-
-
- 8
-
-
-
-
- -
-
-
-
- 8
-
-
-
- 2
-
-
- -16777215.000000000000000
-
-
- 16777215.000000000000000
-
-
- 0.100000000000000
-
-
-
- -
-
-
-
- 8
-
-
-
- Degrees
-
-
-
- -
-
-
-
- 8
-
-
-
- <html><head/><body><p><br/></p></body></html>
-
-
- Tmp2
-
-
-
- -
-
-
-
- 8
-
-
-
-
- -
-
-
-
- 8
-
-
-
- -16777215
-
-
- 16777215
-
-
-
- -
-
-
-
- 8
-
-
-
- °C
-
-
-
- -
-
-
-
- 8
-
-
-
- <html><head/><body><p><br/></p></body></html>
-
-
- Date
-
-
-
- -
-
-
-
- 8
-
-
-
-
- -
-
-
-
- 8
-
-
-
-
- -
-
-
-
- 8
-
-
-
- dd-MM-yyyy hh:mm:ss
-
-
-
- -
-
-
-
- 8
-
-
-
- RPM
-
-
-
- -
-
-
-
- 8
-
-
-
-
- -
-
-
-
- 8
-
-
-
- 2147483647
-
-
-
- -
-
-
-
- 8
-
-
-
- RPM
-
-
-
- -
-
-
-
- 8
-
-
-
- <html><head/><body><p><br/></p></body></html>
-
-
- GPS
-
-
-
- -
-
-
-
- 8
-
-
-
-
- -
-
-
-
- 8
-
-
-
-
- -
-
-
-
- 8
-
-
-
- Lat,Lon (dec.deg.)
-
-
-
- -
-
-
-
- 8
-
-
-
- Fuel
-
-
-
- -
-
-
-
- 8
-
-
-
-
- -
-
-
-
- 8
-
-
-
- 65535
-
-
-
- -
-
-
-
- 8
-
-
-
- %
-
-
-
- -
-
-
-
- 8
-
-
-
- AccX
-
-
-
- -
-
-
-
- 8
-
-
-
-
- -
-
-
-
- 8
-
-
-
- 2
-
-
- -16777215.000000000000000
-
-
- 16777215.000000000000000
-
-
- 0.100000000000000
-
-
-
- -
-
-
-
- 8
-
-
-
- G
-
-
-
- -
-
-
-
- 8
-
-
-
- Fuel Qty
-
-
-
- -
-
-
-
- 8
-
-
-
-
- -
-
-
-
- 8
-
-
-
- 100000.000000000000000
-
-
-
- -
-
-
-
- 8
-
-
-
- ml
-
-
-
- -
-
-
-
- 8
-
-
-
- AccY
-
-
-
- -
-
-
-
- 8
-
-
-
-
- -
-
-
-
- 8
-
-
-
- 2
-
-
- -16777215.000000000000000
-
-
- 16777215.000000000000000
-
-
- 0.100000000000000
-
-
-
- -
-
-
-
- 8
-
-
-
- G
-
-
-
- -
-
-
-
- 8
-
-
-
- <html><head/><body><p><br/></p></body></html>
-
-
- VSpd
-
-
-
- -
-
-
-
- 8
-
-
-
-
- -
-
-
-
- 8
-
-
-
- 2
-
-
- -16777215.000000000000000
-
-
- 16777215.000000000000000
-
-
- 0.100000000000000
-
-
-
- -
-
-
-
- 8
-
-
-
- m/s
-
-
-
- -
-
-
-
- 8
-
-
-
- AccZ
-
-
-
- -
-
-
-
- 8
-
-
-
-
- -
-
-
-
- 8
-
-
-
- 2
-
-
- -16777215.000000000000000
-
-
- 16777215.000000000000000
-
-
- 0.100000000000000
-
-
-
- -
-
-
-
- 8
-
-
-
- G
-
-
-
- -
-
-
-
- 8
-
-
-
- <html><head/><body><p><br/></p></body></html>
-
-
- Alt
-
-
-
- -
-
-
-
- 8
-
-
-
-
- -
-
-
-
- 8
-
-
-
- 2
-
-
- -16777215.000000000000000
-
-
- 16777215.000000000000000
-
-
- 0.100000000000000
-
-
-
- -
-
-
-
- 8
-
-
-
- Meters
-
-
-
+
+
-
Simulate
@@ -1851,12 +3017,6 @@ Timestamp
gps_time
gpsll_inst
gps_latlon
- accx_inst
- accx
- accy_inst
- accy
- accz_inst
- accz
fuel_qty_inst
fuel_qty
diff --git a/companion/src/simulation/trainersimu.cpp b/companion/src/simulation/trainersimu.cpp
index 9e245b3b8..50a506669 100644
--- a/companion/src/simulation/trainersimu.cpp
+++ b/companion/src/simulation/trainersimu.cpp
@@ -22,37 +22,45 @@
#include "trainersimu.h"
#include "ui_trainersimu.h"
#include "helpers.h"
-
-#define GBALL_SIZE 20
-#define RESX 512
+#include "virtualjoystickwidget.h"
TrainerSimulator::TrainerSimulator(QWidget * parent, SimulatorInterface * simulator):
- QDialog(parent),
+ QWidget(parent),
ui(new Ui::TrainerSimulator),
simulator(simulator)
{
ui->setupUi(this);
- leftStick = ui->leftStick;
- rightStick = ui->rightStick;
- setupSticks();
+ vJoyLeft = new VirtualJoystickWidget(this, 'L', false);
+ vJoyLeft->setStickColor(Qt::cyan);
+ ui->leftStickLayout->addWidget(vJoyLeft);
- // resize(0, 0); // to force min height, min width
- setFixedSize(width(), height());
+ vJoyRight = new VirtualJoystickWidget(this, 'R', false);
+ vJoyRight->setStickColor(Qt::cyan);
+ ui->rightStickLayout->addWidget(vJoyRight);
timer = new QTimer(this);
+ timer->setInterval(10);
connect(timer, SIGNAL(timeout()), this, SLOT(onTimerEvent()));
}
TrainerSimulator::~TrainerSimulator()
{
- timer->stop();
+ if (timer) {
+ timer->stop();
+ delete timer;
+ }
+ if (vJoyLeft)
+ delete vJoyLeft;
+ if (vJoyRight)
+ delete vJoyRight;
+
delete ui;
}
void TrainerSimulator::showEvent(QShowEvent *event)
{
- timer->start(10);
+ timer->start();
event->accept();
}
@@ -64,71 +72,13 @@ void TrainerSimulator::closeEvent(QCloseEvent *event)
void TrainerSimulator::centerSticks()
{
- if (leftStick->scene())
- nodeLeft->stepToCenter();
+ if (vJoyLeft)
+ vJoyLeft->centerStick();
- if (rightStick->scene())
- nodeRight->stepToCenter();
+ if (vJoyRight)
+ vJoyRight->centerStick();
}
-void TrainerSimulator::setupSticks()
-{
- QGraphicsScene *leftScene = new QGraphicsScene(leftStick);
- leftScene->setItemIndexMethod(QGraphicsScene::NoIndex);
- leftStick->setScene(leftScene);
-
- // leftStick->scene()->addLine(0,10,20,30);
-
- QGraphicsScene *rightScene = new QGraphicsScene(rightStick);
- rightScene->setItemIndexMethod(QGraphicsScene::NoIndex);
- rightStick->setScene(rightScene);
-
- // rightStick->scene()->addLine(0,10,20,30);
-
- nodeLeft = new Node();
- nodeLeft->setPos(-GBALL_SIZE/2,-GBALL_SIZE/2);
- nodeLeft->setBallSize(GBALL_SIZE);
- leftScene->addItem(nodeLeft);
-
- nodeRight = new Node();
- nodeRight->setPos(-GBALL_SIZE/2,-GBALL_SIZE/2);
- nodeRight->setBallSize(GBALL_SIZE);
- rightScene->addItem(nodeRight);
-}
-
-void TrainerSimulator::resizeEvent(QResizeEvent *event)
-{
- if (leftStick->scene()) {
- QRect qr = leftStick->contentsRect();
- qreal w = (qreal)qr.width() - GBALL_SIZE;
- qreal h = (qreal)qr.height() - GBALL_SIZE;
- qreal cx = (qreal)qr.width()/2;
- qreal cy = (qreal)qr.height()/2;
- leftStick->scene()->setSceneRect(-cx,-cy,w,h);
-
- QPointF p = nodeLeft->pos();
- p.setX(qMin(cx, qMax(p.x(), -cx)));
- p.setY(qMin(cy, qMax(p.y(), -cy)));
- nodeLeft->setPos(p);
- }
-
- if (rightStick->scene()) {
- QRect qr = rightStick->contentsRect();
- qreal w = (qreal)qr.width() - GBALL_SIZE;
- qreal h = (qreal)qr.height() - GBALL_SIZE;
- qreal cx = (qreal)qr.width()/2;
- qreal cy = (qreal)qr.height()/2;
- rightStick->scene()->setSceneRect(-cx,-cy,w,h);
-
- QPointF p = nodeRight->pos();
- p.setX(qMin(cx, qMax(p.x(), -cx)));
- p.setY(qMin(cy, qMax(p.y(), -cy)));
- nodeRight->setPos(p);
- }
- QDialog::resizeEvent(event);
-}
-
-
void TrainerSimulator::onTimerEvent()
{
centerSticks();
@@ -137,8 +87,15 @@ void TrainerSimulator::onTimerEvent()
void TrainerSimulator::setTrainerInputs()
{
- simulator->setTrainerInput(0, int( 512* nodeLeft->getX())); // LEFT HORZ
- simulator->setTrainerInput(1, int(-512* nodeLeft->getY())); // LEFT VERT
- simulator->setTrainerInput(2, int(-512*nodeRight->getY())); // RGHT VERT
- simulator->setTrainerInput(3, int( 512*nodeRight->getX())); // RGHT HORZ
-}
\ No newline at end of file
+ if (!simulator)
+ return;
+
+ if (vJoyLeft) {
+ simulator->setTrainerInput(0, int( 512 * vJoyLeft->getStickX())); // LEFT HORZ
+ simulator->setTrainerInput(1, int(-512 * vJoyLeft->getStickY())); // LEFT VERT
+ }
+ if (vJoyRight) {
+ simulator->setTrainerInput(2, int(-512 * vJoyRight->getStickY())); // RGHT VERT
+ simulator->setTrainerInput(3, int( 512 * vJoyRight->getStickX())); // RGHT HORZ
+ }
+}
diff --git a/companion/src/simulation/trainersimu.h b/companion/src/simulation/trainersimu.h
index 94826086c..520df6d6c 100644
--- a/companion/src/simulation/trainersimu.h
+++ b/companion/src/simulation/trainersimu.h
@@ -24,17 +24,17 @@
#include
#include
-#include
+#include
#include
-#include "modeledit/node.h"
#include "simulatorinterface.h"
namespace Ui {
class TrainerSimulator;
}
+class VirtualJoystickWidget;
-class TrainerSimulator : public QDialog
+class TrainerSimulator : public QWidget
{
Q_OBJECT
@@ -43,26 +43,20 @@ class TrainerSimulator : public QDialog
virtual ~TrainerSimulator();
- protected:
+ protected slots:
virtual void showEvent(QShowEvent *event);
virtual void closeEvent(QCloseEvent *event);
+ void centerSticks();
+ void setTrainerInputs();
+ void onTimerEvent();
- private:
+ protected:
Ui::TrainerSimulator * ui;
QTimer * timer;
SimulatorInterface *simulator;
- QGraphicsView * leftStick, * rightStick;
- Node *nodeLeft;
- Node *nodeRight;
-
- void centerSticks();
- void setupSticks();
- void resizeEvent(QResizeEvent *event = 0);
- void setTrainerInputs();
-
- private slots:
- void onTimerEvent();
+ VirtualJoystickWidget * vJoyLeft;
+ VirtualJoystickWidget * vJoyRight;
};
diff --git a/companion/src/simulation/trainersimu.ui b/companion/src/simulation/trainersimu.ui
index d4e0ca2b5..a01c8c35e 100644
--- a/companion/src/simulation/trainersimu.ui
+++ b/companion/src/simulation/trainersimu.ui
@@ -1,94 +1,70 @@
TrainerSimulator
-
+
0
0
- 566
- 268
+ 385
+ 187
+
+
+ 0
+ 0
+
+
Trainer simulator
-
-
-
- 0
- 0
- 563
- 267
-
-
-
- QFrame::Panel
-
-
- QFrame::Raised
-
-
- 2
-
-
-
- 5
-
- -
-
- -
-
-
- Qt::Horizontal
+
+ -
+
+
+ QFrame::Panel
+
+
+ QFrame::Raised
+
+
+ 2
+
+
+
+ 15
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+ -
+
+
+ 0
-
- QSizePolicy::Minimum
-
-
-
- 17
- 20
-
-
-
+
- -
-
-
-
- 245
- 245
-
+ -
+
+
+ 0
-
- Qt::ScrollBarAlwaysOff
-
-
- Qt::ScrollBarAlwaysOff
-
-
-
- -
-
-
-
- 245
- 245
-
-
-
- Qt::ScrollBarAlwaysOff
-
-
- Qt::ScrollBarAlwaysOff
-
-
+
-
-
-
+
+
+
diff --git a/companion/src/simulation/widgets/radiofaderwidget.h b/companion/src/simulation/widgets/radiofaderwidget.h
index fda81a7a4..3d1fe52c7 100644
--- a/companion/src/simulation/widgets/radiofaderwidget.h
+++ b/companion/src/simulation/widgets/radiofaderwidget.h
@@ -47,7 +47,7 @@ class RadioFaderWidget : public RadioWidget
SliderWidget * sl = new SliderWidget(this);
sl->setOrientation(Qt::Vertical);
- sl->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding);
+ sl->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred);
sl->setMinimumHeight(75);
//sl->setMaximumHeight(75);
sl->setTickPosition(QSlider::TicksBothSides);
diff --git a/companion/src/simulation/widgets/radioswitchwidget.h b/companion/src/simulation/widgets/radioswitchwidget.h
index bc1d22e0d..45c50d710 100644
--- a/companion/src/simulation/widgets/radioswitchwidget.h
+++ b/companion/src/simulation/widgets/radioswitchwidget.h
@@ -23,6 +23,7 @@
#include "radiowidget.h"
#include "boards.h"
+#include "simulator.h"
#include
#include
@@ -65,11 +66,8 @@ class RadioSwitchWidget : public RadioWidget
m_slider->setValue(m_value);
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->setIcon(Simulator::SimulatorIcon("toggle_lock"));
lockBtn->setIconSize(QSize(8, 8));
lockBtn->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
lockBtn->setToolButtonStyle(Qt::ToolButtonIconOnly);
@@ -78,7 +76,7 @@ class RadioSwitchWidget : public RadioWidget
lockBtn->setToolTip(tr("Latch/unlatch the momentary switch."));
QWidget * container = new QWidget(this);
- container->setFixedHeight(50);
+ container->setFixedHeight(56);
container->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
QVBoxLayout * cl = new QVBoxLayout(container);
cl->setContentsMargins(0, 0, 0, 0);
@@ -94,7 +92,7 @@ class RadioSwitchWidget : public RadioWidget
connect(this, &RadioWidget::flagsChanged, lockBtn, &QToolButton::setChecked);
}
else {
- m_slider->setFixedHeight(50);
+ m_slider->setFixedHeight(56);
setWidget(m_slider);
}
diff --git a/companion/src/simulation/widgets/virtualjoystickwidget.cpp b/companion/src/simulation/widgets/virtualjoystickwidget.cpp
index 0697100a9..9242b01c4 100644
--- a/companion/src/simulation/widgets/virtualjoystickwidget.cpp
+++ b/companion/src/simulation/widgets/virtualjoystickwidget.cpp
@@ -18,6 +18,9 @@
* GNU General Public License for more details.
*/
+#define GBALL_SIZE 20
+#define RESX 1024
+
#include "virtualjoystickwidget.h"
#include "constants.h"
#include "sliderwidget.h"
@@ -50,7 +53,9 @@ VirtualJoystickWidget::VirtualJoystickWidget(QWidget *parent, QChar side, bool s
gv = new QGraphicsView(this);
gv->setSizePolicy(sizePolicy);
- gv->setMinimumSize(QSize(150, 150));
+ gv->setMinimumSize(size);
+// gv->setMaximumSize(size + size * 3);
+// gv->setFixedSize(prefSize);
gv->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
gv->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
@@ -88,6 +93,9 @@ VirtualJoystickWidget::VirtualJoystickWidget(QWidget *parent, QChar side, bool s
vTrimSlider = vTrimWidget->findChild();
extraSize += QSize(vTrimWidget->sizeHint().width(), hTrimWidget->sizeHint().height());
}
+ else {
+ colvx = colvy = colvt;
+ }
if (showBtns) {
QVBoxLayout * btnbox = new QVBoxLayout();
@@ -106,8 +114,17 @@ VirtualJoystickWidget::VirtualJoystickWidget(QWidget *parent, QChar side, bool s
if (showValues) {
QLayout * valX = createNodeValueLayout('X', nodeLabelX);
QLayout * valY = createNodeValueLayout('Y', nodeLabelY);
- layout->addLayout(valX, 2, colvx, 1, 1);
- layout->addLayout(valY, 2, colvy, 1, 1);
+ if (!showTrims) {
+ QVBoxLayout * vertXY = new QVBoxLayout();
+ vertXY->addLayout(valX);
+ vertXY->addLayout(valY);
+ layout->addLayout(vertXY, 1, colvx, 1, 1);
+ extraSize += QSize(nodeLabelX->sizeHint().width(), 0);
+ }
+ else {
+ layout->addLayout(valX, 2, colvx, 1, 1);
+ layout->addLayout(valY, 2, colvy, 1, 1);
+ }
}
layout->addItem(new QSpacerItem(0, 0), 0, 0, 1, 5); // r0 c0-4: top v spacer
@@ -119,7 +136,7 @@ VirtualJoystickWidget::VirtualJoystickWidget(QWidget *parent, QChar side, bool s
connect(node, SIGNAL(xChanged()), this, SLOT(updateNodeValueLabels()));
connect(node, SIGNAL(yChanged()), this, SLOT(updateNodeValueLabels()));
- setSize(prefSize);
+ setSize(prefSize, frameSize());
}
void VirtualJoystickWidget::setStickX(qreal x)
@@ -144,12 +161,12 @@ void VirtualJoystickWidget::centerStick()
qreal VirtualJoystickWidget::getStickX()
{
- return node->getX();
+ return getStickPos().x();
}
qreal VirtualJoystickWidget::getStickY()
{
- return node->getY();
+ return getStickPos().y();
}
QPointF VirtualJoystickWidget::getStickPos()
@@ -205,7 +222,22 @@ void VirtualJoystickWidget::setStickConstraint(int which, bool active)
}
}
-void VirtualJoystickWidget::setSize(QSize size)
+void VirtualJoystickWidget::setStickColor(const QColor & color)
+{
+ node->setColor(color);
+}
+
+QSize VirtualJoystickWidget::sizeHint() const {
+ return prefSize;
+}
+
+void VirtualJoystickWidget::resizeEvent(QResizeEvent * event)
+{
+ QWidget::resizeEvent(event);
+ setSize(event->size(), event->oldSize());
+}
+
+void VirtualJoystickWidget::setSize(const QSize & size, const QSize &)
{
float thisAspectRatio = (float)size.width() / size.height();
float newGvSz, spacerSz;
@@ -237,28 +269,24 @@ void VirtualJoystickWidget::setSize(QSize size)
layout->setColumnStretch(2, newGvSz);
layout->setRowStretch(1, newGvSz);
- prefSize = QSize(newGvSz + extraSize.width(), newGvSz + extraSize.height());
+ //prefSize = QSize(newGvSz + extraSize.width(), newGvSz + extraSize.height());
gv->resize(newGvSz, newGvSz);
gv->updateGeometry();
- repositionNode();
- //qDebug() << thisAspectRatio << size << newGvSz << spacerSz << extraSize << gv->geometry() << gv->contentsRect() << gv->frameRect() << getStickPos();
-}
-void VirtualJoystickWidget::repositionNode()
-{
- QRect qr = gv->contentsRect();
- qreal w = (qreal)qr.width() - GBALL_SIZE;
- qreal h = (qreal)qr.height() - GBALL_SIZE;
- qreal cx = (qreal)qr.width()/2;
- qreal cy = (qreal)qr.height()/2;
+ QRectF qr = (QRectF)gv->contentsRect();
+ qreal w = qr.width() - GBALL_SIZE;
+ qreal h = qr.height() - GBALL_SIZE;
+ qreal cx = qr.width() / 2;
+ qreal cy = qr.height() / 2;
+ qreal nodeX = node->getX();
+ qreal nodeY = node->getY();
+
scene->setSceneRect(-cx,-cy,w,h);
- QPointF p = node->pos();
- p.setX(qMin(cx, qMax(p.x(), -cx)));
- p.setY(qMin(cy, qMax(p.y(), -cy)));
- node->setPos(p);
+ node->setX(nodeX);
+ node->setY(nodeY);
- updateNodeValueLabels();
+ //qDebug() << thisAspectRatio << size << newGvSz << spacerSz << extraSize << gv->geometry() << gv->contentsRect() << gv->frameRect() << getStickPos();
}
QWidget *VirtualJoystickWidget::createTrimWidget(QChar type)
@@ -382,6 +410,7 @@ QLayout *VirtualJoystickWidget::createNodeValueLayout(QChar type, QLabel *& valL
val->setObjectName(QString("val_%1").arg(type));
val->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
val->setAlignment(Qt::AlignCenter);
+ val->setMinimumWidth(val->fontMetrics().width("-100 "));
QVBoxLayout * layout = new QVBoxLayout();
layout->setContentsMargins(2, 2, 2, 2);
layout->setSpacing(2);
diff --git a/companion/src/simulation/widgets/virtualjoystickwidget.h b/companion/src/simulation/widgets/virtualjoystickwidget.h
index 4bbf1ba93..478f6398e 100644
--- a/companion/src/simulation/widgets/virtualjoystickwidget.h
+++ b/companion/src/simulation/widgets/virtualjoystickwidget.h
@@ -33,9 +33,6 @@
class Node;
class SliderWidget;
-#define GBALL_SIZE 20
-#define RESX 1024
-
class VirtualJoystickWidget : public QWidget
{
Q_OBJECT
@@ -55,7 +52,7 @@ class VirtualJoystickWidget : public QWidget
FIX_Y
};
- explicit VirtualJoystickWidget(QWidget * parent = NULL, QChar side = 'L', bool showTrims = true, bool showBtns = true, bool showValues = true, QSize size = QSize(245, 245));
+ explicit VirtualJoystickWidget(QWidget * parent = NULL, QChar side = 'L', bool showTrims = true, bool showBtns = true, bool showValues = true, QSize size = QSize(125, 125));
void setStickX(qreal x);
void setStickY(qreal y);
@@ -70,17 +67,10 @@ class VirtualJoystickWidget : public QWidget
int getTrimValue(int which);
void setStickConstraint(int which, bool active);
+ void setStickColor(const QColor & color);
- virtual QSize sizeHint() const
- {
- return prefSize;
- }
-
- virtual void resizeEvent(QResizeEvent *event)
- {
- QWidget::resizeEvent(event);
- setSize(event->size());
- }
+ virtual QSize sizeHint() const;
+ virtual void resizeEvent(QResizeEvent *event);
signals:
void trimButtonPressed(int which);
@@ -94,8 +84,7 @@ class VirtualJoystickWidget : public QWidget
void updateNodeValueLabels();
protected:
- void setSize(QSize size);
- void repositionNode();
+ void setSize(const QSize & size, const QSize &);
QWidget * createTrimWidget(QChar type);
QPushButton * createButtonWidget(int type);
QLayout * createNodeValueLayout(QChar type, QLabel *& valLabel);
diff --git a/companion/src/simulator.cpp b/companion/src/simulator.cpp
index af5dcad53..bad157b03 100644
--- a/companion/src/simulator.cpp
+++ b/companion/src/simulator.cpp
@@ -19,13 +19,14 @@
*/
#include
-//#include
+#include
+#include
#include
#include
#include
#include
#include
-#include
+#include
#if defined(JOYSTICKS) || defined(SIMU_AUDIO)
#include
#undef main
@@ -35,10 +36,11 @@
#include "constants.h"
#include "eeprominterface.h"
#include "simulator.h"
-#include "simulatordialog.h"
+#include "simulatormainwindow.h"
#include "simulatorstartupdialog.h"
#include "storage.h"
#include "qxtcommandoptions.h"
+#include "version.h"
#ifdef WIN32
#include
@@ -50,21 +52,6 @@
#include
#endif
-#ifdef __APPLE__
-#include
-
-class MyProxyStyle : public QProxyStyle
- {
- public:
- void polish ( QWidget * w ) {
- QMenu* mn = dynamic_cast(w);
- QPushButton* pb = dynamic_cast(w);
- if(!(mn || pb) && !w->testAttribute(Qt::WA_MacNormalSize))
- w->setAttribute(Qt::WA_MacSmallSize);
- }
- };
-#endif
-
using namespace Simulator;
int finish(int exitCode);
@@ -126,19 +113,12 @@ int main(int argc, char *argv[])
g.init();
-#ifdef __APPLE__
- app.setStyle(new MyProxyStyle);
-#endif
-
- /* QTranslator companionTranslator;
- companionTranslator.load(":/companion_" + locale);
+ QTranslator companionTranslator;
+ companionTranslator.load(":/companion_" + g.locale());
QTranslator qtTranslator;
- qtTranslator.load((QString)"qt_" + locale.left(2), QLibraryInfo::location(QLibraryInfo::TranslationsPath));
+ qtTranslator.load((QString)"qt_" + g.locale().left(2), QLibraryInfo::location(QLibraryInfo::TranslationsPath));
app.installTranslator(&companionTranslator);
app.installTranslator(&qtTranslator);
-*/
-
- // QTextCodec::setCodecForCStrings(QTextCodec::codecForName("UTF-8"));
#if defined(JOYSTICKS) || defined(SIMU_AUDIO)
uint32_t sdlFlags = 0;
@@ -269,23 +249,20 @@ int main(int argc, char *argv[])
current_firmware_variant = getFirmware(simOptions.firmwareId);
- int oldProfId = g.id();
- g.id(profileId);
+ g.sessionId(profileId);
g.simuLastProfId(profileId);
int result = 1;
- SimulatorDialog * dialog = new SimulatorDialog(NULL, simulator, SIMULATOR_FLAGS_STANDALONE);
- dialog->setRadioProfileId(profileId);
- if (dialog->setOptions(simOptions, true)) {
- dialog->start();
- dialog->show();
+ SimulatorMainWindow * mainWindow = new SimulatorMainWindow(NULL, simulator, SIMULATOR_FLAGS_STANDALONE);
+ if (mainWindow->setOptions(simOptions, true)) {
+ mainWindow->start();
+ mainWindow->show();
result = app.exec();
}
else {
result = 3;
}
- g.id(oldProfId);
- delete dialog;
+ delete mainWindow;
delete simulator;
return finish(result);
diff --git a/companion/src/storage/appdata.cpp b/companion/src/storage/appdata.cpp
index ffe84efac..10a1a5e8a 100644
--- a/companion/src/storage/appdata.cpp
+++ b/companion/src/storage/appdata.cpp
@@ -428,7 +428,9 @@ QString Profile::groupId()
// ** AppData class********************
// Get declarations
-QStringList AppData::recentFiles() { return _recentFiles; }
+QStringList AppData::recentFiles() { return _recentFiles; }
+QStringList AppData::simuDbgFilters() { return _simuDbgFilters; }
+
QByteArray AppData::mainWinGeo() { return _mainWinGeo; }
QByteArray AppData::mainWinState() { return _mainWinState; }
QByteArray AppData::modelEditGeo() { return _modelEditGeo; }
@@ -475,9 +477,12 @@ int AppData::id() { return _id; }
int AppData::theme() { return _theme; }
int AppData::warningId() { return _warningId; }
int AppData::simuLastProfId() { return _simuLastProfId; }
+int AppData::sessionId() { return _sessionId; }
// Set declarations
void AppData::recentFiles (const QStringList x) { store(x, _recentFiles, "recentFileList" );}
+void AppData::simuDbgFilters (const QStringList x) { store(x, _simuDbgFilters, "simuDbgFilters" );}
+
void AppData::mainWinGeo (const QByteArray x) { store(x, _mainWinGeo, "mainWindowGeometry" );}
void AppData::mainWinState (const QByteArray x) { store(x, _mainWinState, "mainWindowState" );}
void AppData::modelEditGeo (const QByteArray x) { store(x, _modelEditGeo, "modelEditGeometry" );}
@@ -520,11 +525,19 @@ void AppData::generalEditTab (const int x) { store(x, _generalEditTab,
void AppData::iconSize (const int x) { store(x, _iconSize, "icon_size" );}
void AppData::historySize (const int x) { store(x, _historySize, "history_size" );}
void AppData::jsCtrl (const int x) { store(x, _jsCtrl, "js_ctrl" );}
-void AppData::id (const int x) { store(x, _id, "profileId" );}
void AppData::theme (const int x) { store(x, _theme, "theme" );}
void AppData::warningId (const int x) { store(x, _warningId, "warningId" );}
void AppData::simuLastProfId (const int x) { store(x, _simuLastProfId, "simuLastProfId" );}
+void AppData::id(const int x)
+{
+ store(x, _id, "profileId");
+ sessionId(x);
+}
+
+// currently loaded radio profile ID, NOT saved to persistent storage
+void AppData::sessionId (const int x) { _sessionId = x; }
+
// Constructor
AppData::AppData()
{
@@ -667,6 +680,8 @@ void AppData::init()
getset( _tempString, "settings_version" ,"220" ); // This is a version marker. Will be used to upgrade the settings later on.
getset( _recentFiles, "recentFileList" ,"" );
+ getset( _simuDbgFilters, "simuDbgFilters" ,"" );
+
getset( _mainWinGeo, "mainWindowGeometry" ,"" );
getset( _mainWinState, "mainWindowState" ,"" );
getset( _modelEditGeo, "modelEditGeometry" ,"" );
@@ -722,6 +737,7 @@ void AppData::init()
getset( _warningId, "warningId" ,0 );
getset( _simuLastProfId, "simuLastProfId" ,-1 );
+ sessionId(id());
}
QMap AppData::getActiveProfiles()
diff --git a/companion/src/storage/appdata.h b/companion/src/storage/appdata.h
index 4328a4aa1..ba0a1781d 100644
--- a/companion/src/storage/appdata.h
+++ b/companion/src/storage/appdata.h
@@ -250,6 +250,8 @@ class AppData: protected CompStoreObj
private:
QStringList _recentFiles;
+ QStringList _simuDbgFilters;
+
QByteArray _mainWinGeo;
QByteArray _mainWinState;
QByteArray _modelEditGeo;
@@ -296,10 +298,14 @@ class AppData: protected CompStoreObj
int _theme;
int _warningId;
int _simuLastProfId;
+ // currently loaded radio profile ID, NOT saved to persistent storage
+ int _sessionId;
public:
// All the get definitions
QStringList recentFiles();
+ QStringList simuDbgFilters();
+
QByteArray mainWinGeo();
QByteArray mainWinState();
QByteArray modelEditGeo();
@@ -347,9 +353,12 @@ class AppData: protected CompStoreObj
int theme();
int warningId();
int simuLastProfId();
+ int sessionId();
// All the set definitions
void recentFiles (const QStringList x);
+ void simuDbgFilters (const QStringList x);
+
void mainWinGeo (const QByteArray);
void mainWinState (const QByteArray);
void modelEditGeo (const QByteArray);
@@ -398,6 +407,7 @@ class AppData: protected CompStoreObj
void theme (const int);
void warningId (const int);
void simuLastProfId (const int);
+ void sessionId (const int);
// Constructor
AppData();
diff --git a/companion/src/themes/default/style-osx.css b/companion/src/themes/default/style-osx.css
new file mode 100644
index 000000000..bd7e14c46
--- /dev/null
+++ b/companion/src/themes/default/style-osx.css
@@ -0,0 +1,31 @@
+
+* {
+ font-size: 11pt;
+}
+
+QToolButton {
+ border: .05em solid #8f8f91;
+ border-radius: .3em;
+ background-color: white;
+ font-size: 12pt;
+}
+
+QToolButton[autoRaise="true"] {
+ border: .05em solid transparent;
+ background-color: transparent;
+}
+
+QToolButton:hover {
+ border-color: black;
+ background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 rgba(77, 77, 77, 35), stop:1 rgba(149, 149, 149, 10));
+}
+
+QToolButton:checked {
+ border-color: black;
+ background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 rgba(77, 77, 77, 85), stop:1 rgba(149, 149, 149, 50));
+}
+
+QToolButton:pressed {
+ color: white;
+ background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 rgba(77, 77, 77, 165), stop:1 rgba(77, 77, 77, 255));
+}
diff --git a/companion/src/themes/default/style.css b/companion/src/themes/default/style.css
new file mode 100644
index 000000000..2236a6973
--- /dev/null
+++ b/companion/src/themes/default/style.css
@@ -0,0 +1,77 @@
+
+/*
+ MainWindow separators and Splitter
+*/
+QMainWindow::separator,
+QSplitter::handle {
+ border: .05em solid palette(dark);
+}
+
+QMainWindow::separator:horizontal {
+ height: .15em;
+ margin: .2em 0em;
+ border-left: 0;
+ border-right: 0;
+}
+
+QMainWindow::separator:vertical {
+ width: .15em;
+ margin: 0em .2em;
+ border-top: 0;
+ border-bottom: 0;
+}
+
+QSplitter[orientation="1"]::handle,
+QSplitter[orientation="1"] QSplitterHandle {
+ margin: 0em .15em 0em;
+ max-width: .15em;
+ min-width: .15em;
+ border-top: 0;
+ border-bottom: 0;
+}
+
+QSplitter[orientation="2"]::handle,
+QSplitter[orientation="2"] QSplitterHandle {
+ margin: .15em 0em 0em;
+ max-height: .15em;
+ min-height: .15em;
+ border-left: 0;
+ border-right: 0;
+}
+
+QSplitterHandle:hover {}
+
+QMainWindow::separator:hover,
+QSplitter::handle:hover {
+ background-color: palette(highlight);
+}
+
+
+/*
+ Specific UI class styles
+*/
+
+/* default radio "case" background */
+SimulatorDialog > QWidget {
+ background-color: qlineargradient(spread:reflect, x1:0, y1:0, x2:0, y2:1, stop:0 rgba(242, 242, 242, 255), stop:0.757062 rgba(222, 220, 220, 255), stop:1 rgba(232, 230, 230, 255));
+}
+/* radio LCD/controls area under "case" */
+SimulatorDialog #radioUiWidget {
+ background-color: qlineargradient(spread:reflect, x1:0.22, y1:0, x2:0.55065, y2:0.54, stop:0 rgba(7, 7, 7, 250), stop:0.864407 rgba(66, 66, 66, 255));
+ margin: 0;
+ padding: 0;
+}
+
+
+/* outputs display splitter areas (channels, logical switches, global vars) */
+RadioOutputsWidget > QSplitter > QWidget {
+ border: 1px solid #a1a1a1;
+}
+/* vertical headings with the area names */
+RadioOutputsWidget QLabel[heading=true] {
+ background-color: qlineargradient(spread:reflect, x1:0.22, y1:0, x2:0.5, y2:0.55, stop:0 rgba(20, 20, 20, 250), stop:0.85 rgba(86, 86, 86, 255));
+ color: rgb(248, 248, 248);
+ border-color: rgb(180, 180, 180);
+ padding: 0.8em 0.45em;
+ font-size: 8pt;
+}
diff --git a/companion/targets/windows/companion-vs.nsi.in b/companion/targets/windows/companion-vs.nsi.in
index 159a92953..1fcda2ea3 100644
--- a/companion/targets/windows/companion-vs.nsi.in
+++ b/companion/targets/windows/companion-vs.nsi.in
@@ -123,6 +123,7 @@ Section "OpenTX Companion" SecDummy
File "@QT_DLL_DIR@\Qt5PrintSupport.dll"
File "@QT_DLL_DIR@\Qt5Network.dll"
File "@QT_DLL_DIR@\Qt5Multimedia.dll"
+ File "@QT_DLL_DIR@\Qt5Svg.dll"
File "@QT_DLL_DIR@\Qt5Xml.dll"
File "@SDL_DIR@\SDL.dll"
@@ -137,6 +138,7 @@ Section "OpenTX Companion" SecDummy
SetOutPath "$INSTDIR\imageformats"
File "@QT_DLL_DIR@\..\plugins\imageformats\qjpeg.dll"
+ File "@QT_DLL_DIR@\..\plugins\imageformats\qsvg.dll"
SetOutPath "$INSTDIR\mediaservice"
File "@QT_DLL_DIR@\..\plugins\mediaservice\dsengine.dll"
diff --git a/radio/util/Dockerfile b/radio/util/Dockerfile
index 507c175d0..a0cd18bbc 100644
--- a/radio/util/Dockerfile
+++ b/radio/util/Dockerfile
@@ -18,6 +18,7 @@ RUN apt-get update && \
qtmultimedia5-dev \
qttools5-dev \
qttools5-dev-tools \
+ libqt5svg5-dev \
software-properties-common \
wget \
zip \