[Simulator] New main UI window, debug console, separate outputs window, more. (#4385)
* [package] Add QtSvg support DLLs for Windows. * [Simulator] Add images/css resources for new version; Create SimulatorIcon and SimulatorStyle classes; Build with SVG support, remove unused bitmaps. * [Simulator] Improve and simplify VirtualJoystickWidget resize event (sticks maintain X/Y position) & improve values layout w/out trims. * [Simulator] Refactor Trainer simulator to use VirtualJoystickWidget, gains lock/hold buttons and X/Y position readout. * [Simulator] More compact layout for Telemetry simulator, reduces min. width and adds scrolling columns to allow smaller window sizes. * [Simulator] Add new SimulatorMainWindow and RadioOutputsWidget UI classes. * [storage] Add non-persistent sessionId() to AppData for tracking currently active radio profile ID. * [Simulator] Major UI updates: * Use a MainWindow interface with dockable/floatable windows, proper toolbar & menu; * Persistent size/layout state of all windows/docks/etc between uses, per radio profile; * Completely separate radio Outputs window with configurable layout (also persistent between uses); * Translations now enabled in standalone Simulator, follows main Companion setting (they need a lot of updates); * New custom icons throughout, toolbar icon sizes adhere to user preference in Companion. * [Simulator] Debug Output console updates: * New filter feature with optional full RegEx support, can work in inclusive or exclusive modes (full help text is included in UI); * Up to 50 user-defined filters are saved to permanent settings, also a few predefined filters are provided; * Saves/restores the last filter used and if it was en/disabled; * Added word wrap and clear screen features; * Configurable scroll-back buffer size; * Increased efficiency & performance of the buffering/printing process. * [Simulator][OSX] Visual UI tweaks for OS X. * [Simulator] Fix some debug console settings not being restored properly. * [Simulator] Add ability to hide/show menu bar; Persist view state of menu bar and radio title bar; Reduce font size on OS X; Other small visual tweaks and improvements. * [build] Add QtSvg to Linux build scripts (a guess for Dockerfile). * [build] Fix for Qt 5.3. * Add OpenTx headers to new files. * [Companion][storage] Update GeneralSettings() initializer to use current sessionId for profile data retrieval, removes workaround for standalone Simulator being started with arbitrary profile; AppData: always update sessionId when global id() changes. * [X10] Fixes for new simulator
|
@ -70,7 +70,7 @@ install:
|
||||||
# - tar xjf gcc-arm-none-eabi-4_7-2013q3-20130916-linux.tar.bz2
|
# - 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
|
# - mv gcc-arm-none-eabi-4_7-2013q3 /opt/gcc-arm-none-eabi
|
||||||
fi
|
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:
|
script:
|
||||||
- ./tools/commit-tests.sh
|
- ./tools/commit-tests.sh
|
||||||
|
|
|
@ -49,8 +49,6 @@ endif()
|
||||||
if(SDL_FOUND)
|
if(SDL_FOUND)
|
||||||
include_directories(${SDL_INCLUDE_DIR})
|
include_directories(${SDL_INCLUDE_DIR})
|
||||||
add_definitions(-DJOYSTICKS)
|
add_definitions(-DJOYSTICKS)
|
||||||
else()
|
|
||||||
remove_definitions(-DSIMU_AUDIO)
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
add_definitions(-DSIMU)
|
add_definitions(-DSIMU)
|
||||||
|
@ -250,8 +248,6 @@ qt5_add_translation(companion_QM ${companion_TS})
|
||||||
qt5_add_resources(companion_RCC ${companion_RESOURCES})
|
qt5_add_resources(companion_RCC ${companion_RESOURCES})
|
||||||
add_custom_target(gen_qrc DEPENDS ${companion_RCC})
|
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_executable(${COMPANION_NAME} MACOSX_BUNDLE ${WIN_EXECUTABLE_TYPE} ${companion_SRCS} ${companion_RCC} ${companion_QM})
|
||||||
|
|
||||||
add_dependencies(${COMPANION_NAME} gen_qrc)
|
add_dependencies(${COMPANION_NAME} gen_qrc)
|
||||||
|
@ -282,9 +278,7 @@ if(WIN32)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
add_executable(${SIMULATOR_NAME} MACOSX_BUNDLE ${WIN_EXECUTABLE_TYPE} ${simu_SRCS} ${companion_RCC})
|
add_executable(${SIMULATOR_NAME} MACOSX_BUNDLE ${WIN_EXECUTABLE_TYPE} ${simu_SRCS} ${companion_RCC})
|
||||||
|
|
||||||
add_dependencies(${SIMULATOR_NAME} gen_qrc)
|
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})
|
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_target_property(QtCore_LOCATION Qt5::Core LOCATION)
|
||||||
get_filename_component(QT_DLL_DIR ${QtCore_LOCATION} PATH)
|
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)
|
set(INSTALL_TEMP_ICUDLL_FILES icudt54.dll icuin54.dll icuuc54.dll)
|
||||||
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
|
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||||
set(INSTALL_TEMP_QTDLL_SFX "d")
|
set(INSTALL_TEMP_QTDLL_SFX "d")
|
||||||
|
|
|
@ -12,8 +12,26 @@
|
||||||
<file>images/track.png</file>
|
<file>images/track.png</file>
|
||||||
<file>images/track0.png</file>
|
<file>images/track0.png</file>
|
||||||
<file>images/taranison.png</file>
|
<file>images/taranison.png</file>
|
||||||
<file>images/simulator/icons/8/lock-locked.png</file>
|
<file>images/simulator/icons/svg/camera.svg</file>
|
||||||
<file>images/simulator/icons/8/lock-unlocked.png</file>
|
<file>images/simulator/icons/svg/camera-active.svg</file>
|
||||||
|
<file>images/simulator/icons/svg/console.svg</file>
|
||||||
|
<file>images/simulator/icons/svg/eraser.svg</file>
|
||||||
|
<file>images/simulator/icons/svg/eraser-active.svg</file>
|
||||||
|
<file>images/simulator/icons/svg/info.svg</file>
|
||||||
|
<file>images/simulator/icons/svg/info-active.svg</file>
|
||||||
|
<file>images/simulator/icons/svg/joystick_settings.svg</file>
|
||||||
|
<file>images/simulator/icons/svg/joystick_settings-active.svg</file>
|
||||||
|
<file>images/simulator/icons/svg/toggle_lock.svg</file>
|
||||||
|
<file>images/simulator/icons/svg/toggle_lock-on.svg</file>
|
||||||
|
<file>images/simulator/icons/svg/radio_outputs.svg</file>
|
||||||
|
<file>images/simulator/icons/svg/reload_script.svg</file>
|
||||||
|
<file>images/simulator/icons/svg/reload_script-active.svg</file>
|
||||||
|
<file>images/simulator/icons/svg/restart.svg</file>
|
||||||
|
<file>images/simulator/icons/svg/restart-active.svg</file>
|
||||||
|
<file>images/simulator/icons/svg/telemetry.svg</file>
|
||||||
|
<file>images/simulator/icons/svg/trainer.svg</file>
|
||||||
|
<file>images/simulator/icons/svg/word_wrap.svg</file>
|
||||||
|
<file>images/simulator/icons/svg/word_wrap-active.svg</file>
|
||||||
<file>images/simulator/Horus/middle.png</file>
|
<file>images/simulator/Horus/middle.png</file>
|
||||||
<file>images/simulator/Horus/left.png</file>
|
<file>images/simulator/Horus/left.png</file>
|
||||||
<file>images/simulator/Horus/right.png</file>
|
<file>images/simulator/Horus/right.png</file>
|
||||||
|
@ -180,6 +198,8 @@
|
||||||
<file>images/library/10702.png</file>
|
<file>images/library/10702.png</file>
|
||||||
<file>images/library/10801.png</file>
|
<file>images/library/10801.png</file>
|
||||||
<file>images/library/10802.png</file>
|
<file>images/library/10802.png</file>
|
||||||
|
<file>themes/default/style.css</file>
|
||||||
|
<file>themes/default/style-osx.css</file>
|
||||||
<file>themes/monochrome/16/paintbrush.png</file>
|
<file>themes/monochrome/16/paintbrush.png</file>
|
||||||
<file>themes/monochrome/16/open.png</file>
|
<file>themes/monochrome/16/open.png</file>
|
||||||
<file>themes/monochrome/16/edit.png</file>
|
<file>themes/monochrome/16/edit.png</file>
|
||||||
|
|
|
@ -1120,23 +1120,23 @@ GeneralSettings::GeneralSettings()
|
||||||
strcpy(bluetoothName, "Taranis");
|
strcpy(bluetoothName, "Taranis");
|
||||||
}
|
}
|
||||||
|
|
||||||
templateSetup = g.profile[g.id()].channelOrder();
|
templateSetup = g.profile[g.sessionId()].channelOrder();
|
||||||
stickMode = g.profile[g.id()].defaultMode();
|
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);
|
int potsnum = getCurrentFirmware()->getCapability(Pots);
|
||||||
if (!t_calib.isEmpty()) {
|
if (!t_calib.isEmpty()) {
|
||||||
QString t_trainercalib=g.profile[g.id()].trainerCalib();
|
QString t_trainercalib=g.profile[g.sessionId()].trainerCalib();
|
||||||
int8_t t_txVoltageCalibration=(int8_t)g.profile[g.id()].txVoltageCalibration();
|
int8_t t_txVoltageCalibration=(int8_t)g.profile[g.sessionId()].txVoltageCalibration();
|
||||||
int8_t t_txCurrentCalibration=(int8_t)g.profile[g.id()].txCurrentCalibration();
|
int8_t t_txCurrentCalibration=(int8_t)g.profile[g.sessionId()].txCurrentCalibration();
|
||||||
int8_t t_PPM_Multiplier=(int8_t)g.profile[g.id()].ppmMultiplier();
|
int8_t t_PPM_Multiplier=(int8_t)g.profile[g.sessionId()].ppmMultiplier();
|
||||||
uint8_t t_stickMode=(uint8_t)g.profile[g.id()].gsStickMode();
|
uint8_t t_stickMode=(uint8_t)g.profile[g.sessionId()].gsStickMode();
|
||||||
uint8_t t_vBatWarn=(uint8_t)g.profile[g.id()].vBatWarn();
|
uint8_t t_vBatWarn=(uint8_t)g.profile[g.sessionId()].vBatWarn();
|
||||||
QString t_DisplaySet=g.profile[g.id()].display();
|
QString t_DisplaySet=g.profile[g.sessionId()].display();
|
||||||
QString t_BeeperSet=g.profile[g.id()].beeper();
|
QString t_BeeperSet=g.profile[g.sessionId()].beeper();
|
||||||
QString t_HapticSet=g.profile[g.id()].haptic();
|
QString t_HapticSet=g.profile[g.sessionId()].haptic();
|
||||||
QString t_SpeakerSet=g.profile[g.id()].speaker();
|
QString t_SpeakerSet=g.profile[g.sessionId()].speaker();
|
||||||
QString t_CountrySet=g.profile[g.id()].countryCode();
|
QString t_CountrySet=g.profile[g.sessionId()].countryCode();
|
||||||
|
|
||||||
if ((t_calib.length()==(CPN_MAX_STICKS+potsnum)*12) && (t_trainercalib.length()==16)) {
|
if ((t_calib.length()==(CPN_MAX_STICKS+potsnum)*12) && (t_trainercalib.length()==16)) {
|
||||||
QString Byte;
|
QString Byte;
|
||||||
|
|
|
@ -32,7 +32,7 @@
|
||||||
#include "appdata.h"
|
#include "appdata.h"
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
#include "modeledit/modeledit.h"
|
#include "modeledit/modeledit.h"
|
||||||
#include "simulatordialog.h"
|
#include "simulatormainwindow.h"
|
||||||
#include "storage/sdcard.h"
|
#include "storage/sdcard.h"
|
||||||
|
|
||||||
Stopwatch gStopwatch("global");
|
Stopwatch gStopwatch("global");
|
||||||
|
@ -823,7 +823,7 @@ void startSimulation(QWidget * parent, RadioData & radioData, int modelIdx)
|
||||||
simuData->setCurrentModel(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)) {
|
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()));
|
QMessageBox::critical(NULL, QObject::tr("Data Load Error"), QObject::tr("Error: Could not create temporary directory in '%1'").arg(QDir::tempPath()));
|
||||||
delete dialog;
|
delete dialog;
|
||||||
|
@ -831,12 +831,15 @@ void startSimulation(QWidget * parent, RadioData & radioData, int modelIdx)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
dialog->setRadioData(simuData);
|
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->start();
|
||||||
dialog->exec();
|
dialog->show();
|
||||||
delete dialog;
|
|
||||||
// TODO Horus tmp directory is deleted on simulator close OR we could use it to get back data from the simulation
|
QObject::connect(dialog, &SimulatorMainWindow::destroyed, [simuData] (void) {
|
||||||
delete simuData; // TODO same with simuData, could read it back and update the file data
|
// 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 {
|
else {
|
||||||
QMessageBox::warning(NULL,
|
QMessageBox::warning(NULL,
|
||||||
|
|
Before Width: | Height: | Size: 152 B |
Before Width: | Height: | Size: 154 B |
|
@ -0,0 +1 @@
|
||||||
|
<svg version="1.2" baseProfile="tiny" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M19 6h-1.586l-1-1c-.579-.579-1.595-1-2.414-1h-4c-.819 0-1.835.421-2.414 1l-1 1h-1.586c-1.654 0-3 1.346-3 3v8c0 1.654 1.346 3 3 3h14c1.654 0 3-1.346 3-3v-8c0-1.654-1.346-3-3-3zm-7 10c-1.933 0-3.5-1.568-3.5-3.5 0-1.934 1.567-3.5 3.5-3.5s3.5 1.566 3.5 3.5c0 1.932-1.567 3.5-3.5 3.5zm6-4.701c-.719 0-1.3-.58-1.3-1.299s.581-1.301 1.3-1.301 1.3.582 1.3 1.301-.581 1.299-1.3 1.299z"/></svg>
|
After Width: | Height: | Size: 508 B |
1
companion/src/images/simulator/icons/svg/camera.svg
Normal file
|
@ -0,0 +1 @@
|
||||||
|
<svg version="1.2" baseProfile="tiny" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M19 20h-14c-1.654 0-3-1.346-3-3v-8c0-1.654 1.346-3 3-3h1.586l1-1c.579-.579 1.596-1 2.414-1h4c.818 0 1.835.421 2.414 1l1 1h1.586c1.654 0 3 1.346 3 3v8c0 1.654-1.346 3-3 3zm-14-12c-.552 0-1 .448-1 1v8c0 .552.448 1 1 1h14c.552 0 1-.448 1-1v-8c0-.552-.448-1-1-1h-2c-.266 0-.52-.105-.707-.293l-1.293-1.293c-.201-.201-.715-.414-1-.414h-4c-.285 0-.799.213-1 .414l-1.293 1.293c-.187.188-.441.293-.707.293h-2zM12 10c1.379 0 2.5 1.121 2.5 2.5s-1.121 2.5-2.5 2.5-2.5-1.121-2.5-2.5 1.121-2.5 2.5-2.5m0-1c-1.934 0-3.5 1.566-3.5 3.5 0 1.932 1.566 3.5 3.5 3.5s3.5-1.568 3.5-3.5c0-1.934-1.566-3.5-3.5-3.5zM18 8.699c-.719 0-1.3.582-1.3 1.301s.581 1.299 1.3 1.299 1.3-.58 1.3-1.299-.581-1.301-1.3-1.301z"/></svg>
|
After Width: | Height: | Size: 819 B |
10
companion/src/images/simulator/icons/svg/console.svg
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" version="1.1" width="68" height="53" viewBox="-0.462891 -0.018555 68 53" id="svg2" xml:space="preserve"><metadata id="metadata14"><rdf:RDF><cc:Work rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata>
|
||||||
|
<defs id="defs4">
|
||||||
|
</defs>
|
||||||
|
<path d="M 60.37793,0 H 6.289551 C 2.81543,0 0,2.802734 0,6.260742 v 40.071289 c 0,3.458008 2.81543,6.260742 6.289551,6.260742 H 60.37793 c 3.473633,0 6.288086,-2.802734 6.288086,-6.260742 V 6.260742 C 66.666016,2.802734 63.851563,0 60.37793,0 z M 20.739258,5.193359 c 1.229492,0 2.226074,0.991699 2.226074,2.215332 0,1.224121 -0.996582,2.21582 -2.226074,2.21582 -1.229492,0 -2.226074,-0.991699 -2.226074,-2.21582 0,-1.223632 0.996582,-2.215332 2.226074,-2.215332 z m -6.660645,0 c 1.229492,0 2.226074,0.991699 2.226074,2.215332 0,1.224121 -0.996582,2.21582 -2.226074,2.21582 -1.229004,0 -2.226074,-0.991699 -2.226074,-2.21582 0,-1.223632 0.99707,-2.215332 2.226074,-2.215332 z m -6.67041,0 c 1.223633,0 2.215332,0.991699 2.215332,2.215332 0,1.224121 -0.991699,2.21582 -2.215332,2.21582 -1.223633,0 -2.215332,-0.991699 -2.215332,-2.21582 0,-1.223632 0.991699,-2.215332 2.215332,-2.215332 z M 64.444336,45.18457 c 0,2.962891 -2.22168,5.185547 -5.18457,5.185547 H 7.407715 c -2.963379,0 -5.185547,-2.222656 -5.185547,-5.185547 V 13.333496 c 0,0.0049 62.14502,0 62.222168,0 V 45.18457 z" id="path6" />
|
||||||
|
|
||||||
|
|
||||||
|
<path d="m 5.3691063,21.009388 0,6.863626 54.9094277,0 0,-6.863626 z m 0,13.727252 0,6.863625 34.3183947,0 0,-6.863625 z" id="path3386" /></svg>
|
After Width: | Height: | Size: 1.9 KiB |
12
companion/src/images/simulator/icons/svg/eraser-active.svg
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" version="1.2" width="64" height="64" viewBox="0 0 64 64" id="svg3254" xml:space="preserve"><metadata id="metadata11"><rdf:RDF><cc:Work rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs id="defs9" />
|
||||||
|
<g id="layer1">
|
||||||
|
<g transform="matrix(1.5756397,0,0,1.6644338,54.170963,-1788.6456)" id="g3219">
|
||||||
|
<g transform="matrix(0.63466286,0,0,0.60080491,-55.333181,1055.0231)" id="g3488">
|
||||||
|
<path d="M 90.122,87.857 H 62.31 L 90.594,59.568 c 2.043,-2.042 2.043,-5.366 0,-7.409 L 80.59,42.157 c -0.795,-0.796 -1.785,-1.26 -2.817,-1.436 0.002,0 -4.577,0.241 -8.999,0.744 -1.358,0.153 -2.492,0.923 -3.284,1.714 L 37.616,71.055 c -2.043,2.043 -2.043,5.365 0,7.407 l 10.003,10.003 c 0.982,0.984 2.296,1.527 3.691,1.527 0.109,0 6.752,-0.131 6.821,-0.135 0.335,-0.031 1.14,-0.123 1.14,-0.123 h 30.851 c 0.518,0 0.938,-0.421 0.938,-0.939 0.001,-0.517 -0.421,-0.938 -0.938,-0.938 z M 60.339,86.862 c -1.226,1.225 -3.218,1.225 -4.446,0 L 45.89,76.86 c -1.226,-1.228 -1.226,-3.222 0,-4.445 L 60.138,58.167 74.544,72.655 60.339,86.862 z M 72.661,42.961 75.489,42.73 60.095,58.125 57.737,57.887 72.661,42.961 z M 39.098,76.983 c -1.227,-1.227 -1.227,-3.221 0,-4.448 l 15.049,-15.049 3.346,0.359 -13.086,13.086 c -2.042,2.042 -2.042,5.368 0,7.409 l 9.508,9.508 c -0.152,0.003 -0.289,0.005 -0.435,0.008 H 50.904 C 50.222,87.768 49.59,87.475 49.099,86.983 l -10.001,-10 z" id="path3495" style="fill:#042fb5" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.8 KiB |
22
companion/src/images/simulator/icons/svg/eraser.svg
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" version="1.1" width="64" height="64" id="svg3254">
|
||||||
|
<defs id="defs3256" />
|
||||||
|
<metadata id="metadata3259">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title></dc:title>
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g id="layer1">
|
||||||
|
<g transform="matrix(1.5756397,0,0,1.6644338,54.170963,-1788.6456)" id="g3219" style="display:inline">
|
||||||
|
<g transform="matrix(0.63466286,0,0,0.60080491,-55.333181,1055.0231)" id="g3488">
|
||||||
|
<path d="M 90.121527,87.856832 H 62.310073 l 28.28445,-28.288377 c 2.042733,-2.042734 2.042733,-5.366031 0,-7.408767 L 80.591011,42.156731 c -0.795799,-0.795799 -1.785502,-1.260389 -2.817798,-1.4358 0.0017,5.61e-4 -4.576959,0.241542 -8.998683,0.744239 -1.35902,0.153556 -2.493313,0.923575 -3.284066,1.713768 l -27.874789,27.87647 c -2.042735,2.042734 -2.042735,5.364349 0,7.407085 L 47.618633,88.46601 c 0.982417,0.9841 2.296044,1.526587 3.691493,1.526587 0.108722,0 6.752515,-0.131138 6.821447,-0.1345 0.335131,-0.03137 1.139336,-0.122734 1.139336,-0.122734 h 30.850057 c 0.51783,0 0.939264,-0.421436 0.939264,-0.939266 0.0012,-0.517828 -0.420314,-0.939265 -0.938703,-0.939265 z M 60.338511,86.862085 c -1.225641,1.223959 -3.218499,1.223959 -4.445821,0 L 45.889735,76.860247 c -1.226203,-1.227882 -1.226203,-3.221858 0,-4.446378 L 60.13788,58.166282 74.542946,72.65541 60.338511,86.862085 z M 72.66105,42.961495 75.488937,42.730042 60.094728,58.12481 57.736476,57.886631 72.66105,42.961495 z M 39.097989,76.98298 c -1.226762,-1.226201 -1.226762,-3.220177 0,-4.44806 l 15.048988,-15.04899 3.346276,0.359231 -13.085832,13.085834 c -2.042737,2.042734 -2.042737,5.368272 0,7.408766 l 9.508103,9.508104 c -0.151875,0.0034 -0.288618,0.0052 -0.434887,0.0084 H 50.90438 C 50.222349,87.768285 49.590193,87.47462 49.099826,86.98257 L 39.097989,76.98299 z" id="path3495" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 2.2 KiB |
15
companion/src/images/simulator/icons/svg/info-active.svg
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" version="1.2" width="64" height="64" viewBox="0 0 64 64" id="svg3254" xml:space="preserve"><metadata id="metadata11"><rdf:RDF><cc:Work rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs id="defs9" />
|
||||||
|
|
||||||
|
<g id="layer1">
|
||||||
|
|
||||||
|
<g transform="matrix(1.5756397,0,0,1.6644338,54.170963,-1788.6456)" id="g3219">
|
||||||
|
<g transform="matrix(0.63466286,0,0,0.60080491,-55.333181,1055.0231)" id="g3488">
|
||||||
|
<path d="m 89.528,64.797 c 0,13.331 -10.805,24.134 -24.135,24.134 -13.33,0 -24.134,-10.804 -24.134,-24.134 0,-13.331 10.804,-24.135 24.134,-24.135 13.33,0 24.135,10.803 24.135,24.135 z" id="path3474" style="fill:none;stroke:#7d0297;stroke-width:6;stroke-miterlimit:10" />
|
||||||
|
<path d="m 68.948,59.507 -3.057,14.439 c -0.129,0.552 -0.17,0.976 -0.17,1.358 0,1.189 0.551,1.572 1.742,1.572 0.762,0 1.104,-0.126 1.358,-0.253 -0.214,3.014 -2.38,4.373 -4.673,4.373 -2.548,0 -4.544,-1.528 -4.544,-5.099 0,-0.804 0.128,-1.738 0.34,-2.76 l 2.889,-13.632 6.115,0.002 0,0 z m -1.91,-11.035 c 1.868,0 3.398,1.528 3.398,3.396 0,1.87 -1.531,3.357 -3.398,3.357 -1.87,0 -3.355,-1.487 -3.355,-3.357 -10e-4,-1.868 1.485,-3.396 3.355,-3.396 z" id="path3476" style="fill:#9b0297;stroke:#7d0297;stroke-miterlimit:10" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.6 KiB |
23
companion/src/images/simulator/icons/svg/info.svg
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" version="1.1" width="64" height="64" id="svg3254">
|
||||||
|
<defs id="defs3256" />
|
||||||
|
<metadata id="metadata3259">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title></dc:title>
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g id="layer1">
|
||||||
|
<g transform="matrix(1.5756397,0,0,1.6644338,54.170963,-1788.6456)" id="g3219" style="display:inline">
|
||||||
|
<g transform="matrix(0.63466286,0,0,0.60080491,-55.333181,1055.0231)" id="g3488">
|
||||||
|
<path d="m 89.527433,64.796857 c 0,13.330947 -10.804079,24.134502 -24.134474,24.134502 -13.329856,0 -24.133935,-10.803555 -24.133935,-24.134502 0,-13.330947 10.804079,-24.135039 24.133935,-24.135039 13.330395,0 24.134474,10.803554 24.134474,24.135039 z" id="path3474" style="fill:none;stroke:#000000;stroke-width:6;stroke-miterlimit:10" />
|
||||||
|
<path d="m 68.948411,59.507519 -3.057829,14.43917 c -0.128038,0.551959 -0.168924,0.975881 -0.168924,1.358917 0,1.189456 0.549807,1.572493 1.741952,1.572493 0.761768,0 1.103917,-0.126424 1.358378,-0.253385 -0.214113,3.013719 -2.379985,4.372636 -4.673358,4.372636 -2.54837,0 -4.544783,-1.528378 -4.544783,-5.097822 0,-0.804269 0.128038,-1.739264 0.339998,-2.760335 l 2.888907,-13.632212 h 6.115659 z M 67.037536,48.472098 c 1.868375,0 3.397828,1.527841 3.397828,3.395679 0,1.869991 -1.529991,3.357484 -3.397828,3.357484 -1.869988,0 -3.354789,-1.487493 -3.354789,-3.357484 -5.38e-4,-1.867838 1.484801,-3.395679 3.354789,-3.395679 z" id="path3476" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.9 KiB |
|
@ -0,0 +1,18 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" version="1.2" width="64" height="64" viewBox="0 0 64 64" id="svg3254" xml:space="preserve"><defs id="defs14" />
|
||||||
|
<g id="layer1">
|
||||||
|
<g transform="matrix(1.5756397,0,0,1.6644338,54.170963,-1788.6456)" id="g3219">
|
||||||
|
<path d="m -15.805,1110.28 c 0.028,-0.49 0.111,-1.315 0.185,-1.835 0.124,-0.872 0.086,-0.983 -0.492,-1.433 l -0.626,-0.488 -1.778,0.613 c -0.978,0.336 -1.851,0.593 -1.94,0.57 -0.209,-0.053 -2.69,-4.165 -2.633,-4.364 0.024,-0.084 0.698,-0.667 1.497,-1.297 l 1.454,-1.147 -0.125,-0.736 c -0.121,-0.715 -0.164,-0.754 -1.498,-1.329 -2.442,-1.053 -2.267,-0.627 -1.441,-3.512 l 0.721,-2.515 1.515,0.148 c 2.351,0.229 2.385,0.224 2.887,-0.387 0.461,-0.561 0.461,-0.563 -0.086,-2.002 -0.301,-0.793 -0.597,-1.58 -0.659,-1.749 -0.087,-0.24 0.416,-0.594 2.277,-1.604 l 2.389,-1.296 1.163,1.353 c 1.257,1.461 1.43,1.563 2.337,1.378 0.534,-0.108 0.666,-0.264 1.223,-1.445 1.103,-2.335 0.67,-2.168 3.638,-1.405 l 2.587,0.664 -0.083,1.073 c -0.045,0.59 -0.107,1.323 -0.136,1.629 -0.096,0.995 -0.056,1.161 0.365,1.491 0.662,0.52 0.897,0.508 2.701,-0.135 l 1.708,-0.608 1.334,2.195 c 0.734,1.207 1.316,2.259 1.294,2.337 -0.022,0.079 -0.683,0.649 -1.468,1.269 -1.428,1.125 -1.428,1.126 -1.332,1.817 0.104,0.75 0.136,0.774 2.283,1.7 l 1.385,0.597 -0.722,2.521 -0.723,2.52 -0.542,-0.037 c -0.299,-0.02 -1.117,-0.084 -1.819,-0.139 -1.469,-0.119 -1.685,-0.063 -2.141,0.568 -0.301,0.417 -0.273,0.62 0.286,2.103 0.341,0.902 0.595,1.724 0.566,1.827 -0.061,0.21 -4.383,2.584 -4.603,2.528 -0.079,-0.02 -0.697,-0.665 -1.372,-1.433 l -1.229,-1.397 -0.767,0.171 c -0.743,0.166 -0.792,0.221 -1.574,1.77 -0.444,0.88 -0.818,1.618 -0.83,1.642 -0.012,0.023 -1.194,-0.26 -2.627,-0.628 l -2.604,-0.669 0.055,-0.894 z m 4.699,-1.662 c 0.403,-0.767 0.767,-1.407 0.808,-1.42 0.042,-0.019 0.917,-0.124 1.947,-0.246 l 1.872,-0.222 1.078,1.219 1.077,1.219 0.773,-0.435 0.773,-0.435 -0.576,-1.473 -0.576,-1.472 1.224,-1.497 1.223,-1.496 1.603,0.143 1.602,0.145 0.291,-0.806 0.291,-0.805 -1.302,-0.573 c -0.716,-0.316 -1.401,-0.658 -1.521,-0.761 -0.12,-0.103 -0.33,-0.99 -0.467,-1.97 l -0.249,-1.781 1.26,-1.001 1.261,-1.001 -0.458,-0.73 -0.459,-0.73 -1.453,0.494 c -0.8,0.272 -1.54,0.473 -1.645,0.446 -0.335,-0.086 -2.939,-2.101 -3.011,-2.329 -0.038,-0.121 0,-0.833 0.083,-1.584 l 0.152,-1.365 -0.9,-0.231 -0.9,-0.231 -0.652,1.36 c -0.358,0.748 -0.76,1.401 -0.892,1.452 -0.293,0.114 -3.494,0.461 -3.709,0.404 -0.084,-0.022 -0.594,-0.55 -1.134,-1.173 l -0.98,-1.133 -0.802,0.42 -0.802,0.419 0.566,1.472 0.566,1.473 -0.474,0.566 c -0.26,0.311 -0.769,0.944 -1.129,1.406 -0.36,0.462 -0.808,0.868 -0.994,0.904 -0.186,0.035 -0.977,0.02 -1.758,-0.064 l -1.42,-0.127 -0.226,0.787 c -0.254,0.886 -0.301,0.836 1.483,1.596 l 1.282,0.546 0.283,1.875 0.283,1.875 -1.299,1.022 -1.299,1.023 0.363,0.629 c 0.199,0.347 0.453,0.654 0.563,0.682 0.111,0.028 0.865,-0.16 1.677,-0.421 l 1.476,-0.472 1.462,1.078 c 0.804,0.593 1.495,1.163 1.534,1.268 0.04,0.104 0.005,0.795 -0.077,1.535 -0.082,0.739 -0.109,1.411 -0.059,1.493 0.049,0.082 0.436,0.212 0.86,0.29 l 0.77,0.141 0.737,-1.398 z m -1.432,-4.941 c -2.207,-1.374 -3.184,-3.549 -2.667,-5.939 1.055,-4.879 7.628,-6.017 10.666,-1.848 0.253,0.348 0.578,1.186 0.721,1.863 0.468,2.204 -0.517,4.48 -2.466,5.699 -1.396,0.874 -2.844,1.122 -4.5,0.772 -0.73,-0.154 -1.518,-0.402 -1.754,-0.547 l 0,0 z m 3.043,-1.343 c 2.247,-0.02 3.962,-2.039 3.536,-4.18 -0.487,-2.451 -3.773,-3.601 -5.816,-2.036 -1.947,1.491 -1.879,4.26 0.138,5.587 0.793,0.522 1.176,0.635 2.143,0.628 l -10e-4,10e-4 z" id="path4448-4-4" style="fill:#007f00" />
|
||||||
|
<path d="m -24.424,1077.473 h 13.202 c 3.947,0 7.146,3.199 7.146,7.146 v 7.859 c 0,3.947 -3.199,7.146 -7.146,7.146 h -13.202 c -3.946,0 -7.146,-3.199 -7.146,-7.146 v -7.859 c 0,-3.947 3.199,-7.146 7.146,-7.146 z" id="rect3980-2-6" style="fill:#757575" />
|
||||||
|
<path d="m -24.761,1077.181 h 13.995 c 3.919,0 7.096,3.177 7.096,7.096 v 8.227 c 0,3.919 -3.177,7.096 -7.096,7.096 h -13.995 c -3.919,0 -7.096,-3.177 -7.096,-7.096 v -8.227 c 0,-3.919 3.177,-7.096 7.096,-7.096 z" id="rect3980-9" style="fill:none;stroke:#009100;stroke-width:1.23500001;stroke-linecap:round;stroke-linejoin:round" />
|
||||||
|
<g transform="matrix(1.4151129,0,0,1.4016181,-59.15926,-361.58526)" id="g4236-1">
|
||||||
|
|
||||||
|
<path d="m 34.219,1033.737 c 0,2.697 -2.186,4.884 -4.883,4.884 -2.697,0 -4.884,-2.186 -4.884,-4.884 0,-2.697 2.187,-4.884 4.884,-4.884 2.697,10e-4 4.883,2.187 4.883,4.884 z" id="path3984-8-3" style="fill:#008700;fill-opacity:1;stroke:#000100;stroke-width:0.38479999;stroke-linecap:round;stroke-linejoin:round" />
|
||||||
|
<path d="m 30.369,1028.415 -2.629,6.561 6.798,-2.771 -4.169,-3.79 z" id="path4007-7" style="fill:#ffffff" />
|
||||||
|
<path d="m 34.988,1030.354 c 0,1.421 -1.152,2.572 -2.574,2.572 -1.421,0 -2.574,-1.151 -2.574,-2.572 0,-1.421 1.152,-2.573 2.574,-2.573 1.421,10e-4 2.574,1.153 2.574,2.573 z" id="path4004-0" style="fill:#ffffff;stroke:#000000;stroke-width:0.43849999" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 5.1 KiB |
|
@ -0,0 +1,18 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" version="1.1" width="64" height="64" id="svg3254">
|
||||||
|
<defs id="defs3256" />
|
||||||
|
<g id="layer1">
|
||||||
|
<g transform="matrix(1.5756397,0,0,1.6644338,54.170963,-1788.6456)" id="g3219" style="display:inline">
|
||||||
|
<path d="m -15.804948,1110.2798 c 0.02792,-0.4898 0.111136,-1.3157 0.184859,-1.8355 0.123657,-0.8723 0.08577,-0.9827 -0.492201,-1.433 l -0.626209,-0.4877 -1.777652,0.6121 c -0.977654,0.3367 -1.850646,0.5934 -1.93993,0.5706 -0.209502,-0.053 -2.689644,-4.1649 -2.632607,-4.3638 0.02374,-0.084 0.697501,-0.6667 1.497265,-1.2975 l 1.454108,-1.1468 -0.124527,-0.7365 c -0.120885,-0.7155 -0.164131,-0.7535 -1.497938,-1.3292 -2.44191,-1.0527 -2.267523,-0.6268 -1.440666,-3.5118 l 0.720895,-2.5154 1.514864,0.1484 c 2.351578,0.2286 2.38512,0.2241 2.886555,-0.3865 0.46072,-0.5613 0.460632,-0.5632 -0.08611,-2.0025 -0.301026,-0.7927 -0.597509,-1.5798 -0.658862,-1.7492 -0.08688,-0.2399 0.415749,-0.5938 2.277221,-1.604 l 2.388763,-1.296 1.163547,1.3525 c 1.256899,1.4608 1.429425,1.5626 2.336111,1.3777 0.534545,-0.1079 0.6655389,-0.2639 1.2237319,-1.4449 1.103253,-2.3349 0.669842,-2.1676 3.63823,-1.4051 l 2.5864222,0.6644 -0.08233,1.0727 c -0.04525,0.5897 -0.106624,1.3225 -0.13632,1.6292 -0.09658,0.9949 -0.05598,1.1608 0.364627,1.491 0.662023,0.52 0.896696,0.5082 2.700966,-0.1353 l 1.7083605,-0.6084 1.3346706,2.1946 c 0.7340447,1.2072 1.3163479,2.2587 1.293957,2.3369 -0.022277,0.079 -0.6830622,0.6486 -1.4682671,1.2681 -1.4272235,1.1253 -1.4275789,1.126 -1.3315798,1.8165 0.1043322,0.7506 0.1364398,0.7747 2.2822984,1.7003 l 1.3858308,0.5978 -0.7223669,2.5201 -0.7223225,2.5202 -0.5422814,-0.037 c -0.298063,-0.02 -1.1164862,-0.084 -1.8185439,-0.139 -1.4690987,-0.1191 -1.6855317,-0.063 -2.1413967,0.5689 -0.301053,0.4164 -0.273356,0.6196 0.286068,2.1021 0.340623,0.9027 0.595434,1.7246 0.566195,1.8267 -0.06023,0.2102 -4.382702,2.5844 -4.602492,2.5278 -0.07857,-0.02 -0.6959462,-0.665 -1.3718942,-1.433 l -1.229018,-1.3965 -0.766457,0.1704 c -0.7422,0.1664 -0.792091,0.2214 -1.573926,1.7702 -0.4440739,0.8797 -0.8174139,1.6184 -0.8295809,1.6415 -0.01212,0.023 -1.193959,-0.2601 -2.626425,-0.6279 l -2.604472,-0.6689 z m 4.698467,-1.6615 c 0.403855,-0.7674 0.767853,-1.4066 0.808909,-1.4203 0.04113,-0.019 0.9169169,-0.1243 1.9464349,-0.2459 l 1.871875,-0.222 1.077619,1.2191 1.0776392,1.2188 0.773489,-0.4349 0.773546,-0.4351 -0.576268,-1.4725 -0.576236,-1.4723 1.223979,-1.4966 1.223979,-1.4964 1.602289,0.1426 1.6022575,0.1447 0.2911834,-0.8051 0.2911833,-0.8052 -1.3025821,-0.5732 c -0.7163951,-0.3152 -1.4008151,-0.6576 -1.5208931,-0.761 -0.120186,-0.1023 -0.330355,-0.9896 -0.467303,-1.9693 l -0.248971,-1.781 1.260465,-1.0013 1.260498,-1.0011 -0.4582964,-0.7303 -0.4582966,-0.73 -1.453181,0.4944 c -0.799225,0.2721 -1.539222,0.4726 -1.644418,0.4457 -0.334467,-0.086 -2.9395742,-2.1009 -3.0111132,-2.3288 -0.03776,-0.1207 -2.67e-4,-0.8331 0.08334,-1.5839 l 0.151989,-1.3651 -0.899838,-0.2311 -0.899838,-0.2312 -0.6519,1.3603 c -0.358534,0.7477 -0.760015,1.4012 -0.892146,1.4517 -0.292503,0.1138 -3.4946249,0.461 -3.7094449,0.4042 -0.08435,-0.022 -0.594311,-0.5499 -1.133242,-1.1734 l -0.979951,-1.1327 -0.802188,0.4195 -0.802183,0.4194 0.565688,1.4723 0.565656,1.4727 -0.473649,0.5663 c -0.260497,0.3113 -0.768691,0.9439 -1.129281,1.4055 -0.360602,0.4618 -0.807843,0.8684 -0.993907,0.9035 -0.186153,0.035 -0.977356,0.02 -1.758448,-0.064 l -1.420172,-0.1263 -0.225496,0.7868 c -0.254113,0.8864 -0.301382,0.8358 1.483423,1.5961 l 1.282044,0.5461 0.282546,1.8745 0.282558,1.875 -1.298844,1.022 -1.298875,1.0223 0.362538,0.6296 c 0.199386,0.3465 0.452953,0.653 0.563447,0.6813 0.110489,0.028 0.865211,-0.1591 1.677192,-0.4206 l 1.476309,-0.4724 1.462237,1.0779 c 0.804213,0.5929 1.494834,1.1635 1.534647,1.2682 0.03986,0.1047 0.0051,0.7951 -0.07726,1.5345 -0.08232,0.7394 -0.1092,1.4112 -0.05978,1.4929 0.04931,0.082 0.43654,0.2121 0.86019,0.2901 l 0.770373,0.141 z m -1.430842,-4.9409 c -2.207116,-1.3739 -3.183887,-3.5489 -2.667303,-5.9392 1.054562,-4.879 7.6275429,-6.0176 10.6654331,-1.8479 0.253141,0.3474 0.577949,1.1857 0.721795,1.8626 0.468134,2.2036 -0.516507,4.4794 -2.4659632,5.6991 -1.396417,0.8738 -2.844407,1.1219 -4.5005469,0.7719 -0.729507,-0.1537 -1.518069,-0.4011 -1.75356,-0.5459 z m 3.0421429,-1.3428 c 2.247258,-0.02 3.961584,-2.0393 3.53624,-4.1801 -0.486895,-2.451 -3.773255,-3.6015 -5.8168439,-2.0363 -1.947032,1.4913 -1.878862,4.2604 0.137582,5.5872 0.793779,0.5223 1.176595,0.6349 2.1432949,0.6282 z" id="path4448-4-4" style="fill:#000000;fill-opacity:1;display:inline" />
|
||||||
|
<rect width="27.494143" height="22.15127" ry="7.1462564" x="-31.570469" y="1077.4731" id="rect3980-2-6" style="fill:#757575;fill-opacity:1;stroke:none" />
|
||||||
|
<rect width="28.186502" height="22.418978" ry="7.0958796" x="-31.85692" y="1077.1814" id="rect3980-9" style="fill:none;stroke:#000100;stroke-width:1.23500371;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
|
||||||
|
<g transform="matrix(1.4151129,0,0,1.4016181,-59.15926,-361.58526)" id="g4236-1">
|
||||||
|
<path d="m -4.4642859,77.678574 a 4.2857141,4.2857141 0 1 1 -8.5714281,0 4.2857141,4.2857141 0 1 1 8.5714281,0 z" transform="matrix(1.13953,0,0,1.13953,39.306585,945.21999)" id="path3984-8-3" style="fill:#0c0000;fill-opacity:1;stroke:#000100;stroke-width:0.38477078;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
|
||||||
|
<path d="m 30.368507,1028.4151 -2.629324,6.5608 6.79834,-2.7712 z" id="path4007-7" style="fill:#ffffff;fill-opacity:1;stroke:none" />
|
||||||
|
<path d="m 34.987833,1030.3543 c 0,1.4208 -1.152235,2.5723 -2.573586,2.5723 -1.421352,0 -2.573587,-1.1515 -2.573587,-2.5723 0,-1.4207 1.152235,-2.5724 2.573587,-2.5724 1.421351,0 2.573586,1.1517 2.573586,2.5724 z" id="path4004-0" style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.43845785;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 6.1 KiB |
33
companion/src/images/simulator/icons/svg/radio_outputs.svg
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" version="1.1" width="64" height="64" id="svg3254">
|
||||||
|
<defs id="defs3256" />
|
||||||
|
<metadata id="metadata3259">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title></dc:title>
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g transform="matrix(1.1234718,0,0,1.1234718,-4.5608191,-1.4655251)" id="layer1">
|
||||||
|
<g transform="translate(-72.000133,-1072.4267)" id="g3209" style="display:inline">
|
||||||
|
<path d="m 99.349441,1094.4654 0,8.8551 -8.045911,0 0,22.5193 37.84818,0 0,-22.5193 -8.27712,0 0,-8.8551 -21.525149,0 z" id="rect5128-4-3" style="fill:none;stroke:#000000;stroke-width:3.11534309;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
|
||||||
|
<path d="m 100.09052,1103.3954 0,2.9404 20.02752,0 0.0179,-3.0711" id="path5261-5-2" style="fill:none;stroke:#000000;stroke-width:1.70797408;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
|
||||||
|
<g transform="translate(59.145039,46.442959)" id="g5674-3-35">
|
||||||
|
<path d="m 35.901786,1064.1033 0,12.0312 13.9375,0 0,-8.1562 -9,3.625 3.0625,-7.5 -8,0 z" id="rect5190-1-4-3-4" style="fill:#000000;fill-opacity:1;stroke:none" />
|
||||||
|
<path d="m 50.388469,1065.2434 c 0,1.7268 -1.39996,3.1264 -3.1269,3.1264 -1.72692,0 -3.12688,-1.3996 -3.12688,-3.1264 0,-1.7268 1.39996,-3.1266 3.12688,-3.1266 1.72694,0 3.1269,1.3998 3.1269,3.1266 z" id="path4004-69-7-4-5-5-7-1" style="fill:none;stroke:#000000;stroke-width:1.19000506;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
|
||||||
|
</g>
|
||||||
|
<g transform="translate(75.782819,46.495259)" id="g5674-0-8">
|
||||||
|
<path d="m 35.901786,1064.1033 0,12.0312 13.9375,0 0,-8.1562 -9,3.625 3.0625,-7.5 -8,0 z" id="rect5190-1-4-7-8" style="fill:#000000;fill-opacity:1;stroke:none" />
|
||||||
|
<path d="m 50.388469,1065.2434 c 0,1.7268 -1.39996,3.1264 -3.1269,3.1264 -1.72692,0 -3.12688,-1.3996 -3.12688,-3.1264 0,-1.7268 1.39996,-3.1266 3.12688,-3.1266 1.72694,0 3.1269,1.3998 3.1269,3.1266 z" id="path4004-69-7-4-5-5-0-9" style="fill:none;stroke:#000000;stroke-width:1.19000506;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<g transform="translate(-120.71403,-1067.1752)" id="g3138" style="display:inline">
|
||||||
|
<path d="m 144.85461,1081.6667 -4.46467,0 -3.88859,-3.8125 -3.85772,3.7822 -4.51611,0 8.43041,-8.2653 z" id="path3956-37" style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:0.89009798px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
|
||||||
|
<path d="m 145.06641,1091.87 -4.46467,0 -3.88858,-3.8125 -3.85772,3.7822 -4.51611,0 8.43041,-8.2653 z" id="path3956-3-0" style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:0.89009798px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 3.2 KiB |
|
@ -0,0 +1,13 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" version="1.2" width="64" height="64" viewBox="0 0 64 64" id="svg3254" xml:space="preserve"><metadata id="metadata10"><rdf:RDF><cc:Work rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs id="defs8" />
|
||||||
|
|
||||||
|
<g id="layer1">
|
||||||
|
|
||||||
|
<g transform="matrix(1.5756397,0,0,1.6644338,54.170963,-1788.6456)" id="g3219">
|
||||||
|
<path d="m -14.05,1077.797 c -9.455,0 -17.192,7.323 -17.192,16.275 0,8.951 7.736,16.275 17.192,16.275 4.727,0 9.112,-1.749 12.206,-4.719 l -3.095,-2.93 c -2.32,2.197 -5.545,3.58 -9.155,3.58 -7.135,0 -12.894,-5.452 -12.894,-12.206 0,-6.754 5.759,-12.206 12.894,-12.206 3.567,0 6.662,1.465 8.982,3.702 l -4.684,4.435 H 3.1 v -12.206 l -5.114,4.841 c -3.095,-2.93 -7.349,-4.841 -12.077,-4.841 h 0.041 z" id="path3441" style="fill:#002ad8" />
|
||||||
|
<path d="m -17.177,1085.626 c 2.553,-0.958 5.429,0.219 6.441,2.636 l -3.075,1.154 c -0.341,-0.815 -1.286,-1.202 -2.147,-0.879 -0.861,0.323 -1.27,1.218 -0.928,2.032 0.341,0.815 5.075,3.621 6.122,6.125 1.049,2.504 -0.232,5.14 -2.785,6.098 -2.553,0.958 -5.43,-0.219 -6.441,-2.637 l 3.075,-1.153 c 0.341,0.815 1.286,1.202 2.147,0.879 0.861,-0.323 1.27,-1.218 0.928,-2.032 -0.439,-1.048 -5.318,-4.204 -6.122,-6.125 -0.987,-2.359 0.232,-5.14 2.785,-6.098 l 0,0 z" id="path3452" style="fill:#002ad8" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.7 KiB |
21
companion/src/images/simulator/icons/svg/reload_script.svg
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" version="1.1" width="64" height="64" id="svg3254">
|
||||||
|
<defs id="defs3256" />
|
||||||
|
<metadata id="metadata3259">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title></dc:title>
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g id="layer1">
|
||||||
|
<g transform="matrix(1.5756397,0,0,1.6644338,54.170963,-1788.6456)" id="g3219" style="display:inline">
|
||||||
|
<path d="m -14.0496,1077.7967 c -9.455526,0 -17.191866,7.3233 -17.191866,16.2746 0,8.9506 7.73634,16.2746 17.191866,16.2746 4.7277622,0 9.1116881,-1.7493 12.2062302,-4.7194 l -3.0945421,-2.9297 c -2.3209027,2.1969 -5.5443771,3.5805 -9.1546711,3.5805 -7.134623,0 -12.893898,-5.4523 -12.893898,-12.206 0,-6.7545 5.759275,-12.206 12.893898,-12.206 3.567319,0 6.6618533,1.4649 8.9827563,3.7023 l -4.6847867,4.4351 H 3.0992902 v -12.206 l -5.1145825,4.8414 c -3.0945344,-2.9297 -7.3495203,-4.8414 -12.0772907,-4.8414 z" id="path3441" />
|
||||||
|
<path d="m -17.17734,1085.626 c 2.552571,-0.9574 5.429568,0.2195 6.44112,2.6363 l -3.075396,1.1539 c -0.341196,-0.8151 -1.285932,-1.2018 -2.147034,-0.8789 -0.86111,0.3231 -1.269543,1.2173 -0.928348,2.0325 0.341197,0.8151 5.074068,3.6209 6.122113,6.1244 1.0481409,2.5039 -0.232373,5.1401 -2.784956,6.0978 -2.552568,0.9575 -5.429564,-0.2194 -6.441212,-2.6365 l 3.075393,-1.1538 c 0.341197,0.815 1.28603,1.2019 2.147128,0.879 0.861114,-0.323 1.269453,-1.2176 0.928257,-2.0327 -0.438699,-1.0479 -5.317867,-4.2032 -6.122117,-6.1243 -0.987208,-2.3585 0.232468,-5.1399 2.785052,-6.0977 z" id="path3452" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.9 KiB |
13
companion/src/images/simulator/icons/svg/restart-active.svg
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" version="1.2" width="64" height="64" viewBox="0 0 64 64" id="svg3254" xml:space="preserve"><metadata id="metadata10"><rdf:RDF><cc:Work rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs id="defs8" />
|
||||||
|
|
||||||
|
<g id="layer1">
|
||||||
|
|
||||||
|
<g transform="matrix(1.5756397,0,0,1.6644338,54.170963,-1788.6456)" id="g3219">
|
||||||
|
<path d="m -14.747,1077.753 v 15.251 h 4.027 v -15.251 h -4.027 z" id="path3397" style="fill:#720000" />
|
||||||
|
<path d="m -28.493,1098.125 c 1.281,7.768 9.042,13.131 17.248,11.919 8.205,-1.212 13.871,-8.56 12.59,-16.328 -0.64,-3.884 -2.837,-7.249 -5.98,-9.389 l -2.266,2.939 c 2.328,1.609 4.033,4.07 4.522,7.036 0.966,5.861 -3.252,11.331 -9.443,12.245 -6.192,0.915 -11.97,-3.079 -12.936,-8.939 -0.483,-2.931 0.441,-5.671 2.178,-7.881 l 4.7,3.248 -1.746,-10.593 -11.19,1.653 5.131,3.546 c -2.267,2.939 -3.443,6.694 -2.803,10.578 l -0.005,-0.034 z" id="path3408" style="fill:#720000" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.3 KiB |
21
companion/src/images/simulator/icons/svg/restart.svg
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" version="1.1" width="64" height="64" id="svg3254">
|
||||||
|
<defs id="defs3256" />
|
||||||
|
<metadata id="metadata3259">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title></dc:title>
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g id="layer1">
|
||||||
|
<g transform="matrix(1.5756397,0,0,1.6644338,54.170963,-1788.6456)" id="g3219" style="display:inline">
|
||||||
|
<path d="m -14.746549,1077.7527 0,15.2513 4.027731,0 0,-15.2513 z" id="path3397" />
|
||||||
|
<path d="m -28.493102,1098.125 c 1.280572,7.768 9.04186,13.1318 17.247791,11.9196 8.205389,-1.2122 13.8717377,-8.5597 12.5911658,-16.3278 -0.64028535,-3.8839 -2.8375946,-7.2486 -5.9796213,-9.3887 l -2.2664742,2.9392 c 2.3282028,1.609 4.0331007,4.0698 4.5220467,7.036 0.9662505,5.8611 -3.2519743,11.331 -9.443375,12.2456 -6.192048,0.9148 -11.969592,-3.0784 -12.935843,-8.9396 -0.483125,-2.9307 0.440618,-5.6713 2.177425,-7.881 l 4.700237,3.248 -1.746236,-10.5928 -11.189608,1.653 5.130941,3.5462 c -2.266583,2.939 -3.442915,6.6935 -2.802629,10.5777 z" id="path3408" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.5 KiB |
22
companion/src/images/simulator/icons/svg/telemetry.svg
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" version="1.1" width="64" height="64" id="svg3254">
|
||||||
|
<defs id="defs3256" />
|
||||||
|
<metadata id="metadata3259">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title></dc:title>
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g id="layer1">
|
||||||
|
<g transform="matrix(1.5756397,0,0,1.6644338,54.170963,-1788.6456)" id="g3219" style="display:inline">
|
||||||
|
<g transform="matrix(0.63466286,0,0,0.60080491,-55.333181,1055.0231)" id="g3488">
|
||||||
|
<path d="M 60.353163,39.726048 57.225223,49.908485 52.034177,66.945769 51.83452,66.546458 51.235553,64.283694 H 38.723799 v 6.655188 h 7.720019 l 2.528972,7.720019 3.127938,9.783127 3.127939,-9.982783 5.191046,-16.637971 5.191049,16.637971 2.728627,8.917954 3.52725,-8.518642 3.926561,-9.783127 0.865176,1.863452 H 92.031861 V 64.283694 H 80.784593 L 78.25562,59.292302 74.928027,52.836768 72.199398,59.691615 69.07146,67.611288 63.481101,49.908485 60.353163,39.726048 z" id="path3506" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.4 KiB |
|
@ -0,0 +1,3 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="8" height="8" viewBox="0 0 8 8">
|
||||||
|
<path d="M3 0c-1.1 0-2 .9-2 2v1h-1v4h6v-4h-1v-1c0-1.1-.9-2-2-2zm0 1c.56 0 1 .44 1 1v1h-2v-1c0-.56.44-1 1-1z" transform="translate(1)" />
|
||||||
|
</svg>
|
After Width: | Height: | Size: 225 B |
3
companion/src/images/simulator/icons/svg/toggle_lock.svg
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="8" height="8" viewBox="0 0 8 8">
|
||||||
|
<path d="M3 0c-1.1 0-2 .9-2 2h1c0-.56.44-1 1-1s1 .44 1 1v2h-4v4h6v-4h-1v-2c0-1.1-.9-2-2-2z" transform="translate(1)" />
|
||||||
|
</svg>
|
After Width: | Height: | Size: 208 B |
35
companion/src/images/simulator/icons/svg/trainer.svg
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" version="1.1" width="64" height="64" id="svg3254">
|
||||||
|
<defs id="defs3256" />
|
||||||
|
<metadata id="metadata3259">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title></dc:title>
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g id="layer1">
|
||||||
|
<g transform="matrix(1.5756397,0,0,1.6644338,54.170963,-1788.6456)" id="g3219" style="display:inline">
|
||||||
|
<rect width="35.110096" height="17.12899" ry="5.0985756" x="-31.308317" y="1079.7126" id="rect3980-2-6" style="fill:#757575;fill-opacity:1;stroke:none" />
|
||||||
|
<rect width="35.110096" height="17.008244" ry="5.062634" x="-31.51074" y="1079.5045" id="rect3980-9" style="fill:none;stroke:#000100;stroke-width:1.23500371;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
|
||||||
|
<g transform="translate(-50.80414,53.000428)" id="g4236-1">
|
||||||
|
<path d="m -4.4642859,77.678574 a 4.2857141,4.2857141 0 1 1 -8.5714281,0 4.2857141,4.2857141 0 1 1 8.5714281,0 z" transform="matrix(1.13953,0,0,1.13953,39.306585,945.21999)" id="path3984-8-3" style="fill:#0c0000;fill-opacity:1;stroke:#000100;stroke-width:0.54189169;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
|
||||||
|
<path d="m 30.368507,1028.4151 -2.629324,6.5608 6.79834,-2.7712 z" id="path4007-7" style="fill:#ffffff;fill-opacity:1;stroke:none" />
|
||||||
|
<path d="m 34.753087,1030.3543 c 0,1.2916 -1.047136,2.3385 -2.338841,2.3385 -1.291706,0 -2.338842,-1.0469 -2.338842,-2.3385 0,-1.2916 1.047136,-2.3386 2.338842,-2.3386 1.291705,0 2.338841,1.047 2.338841,2.3386 z" id="path4004-0" style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.61750185;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
|
||||||
|
</g>
|
||||||
|
<g transform="translate(-35.406682,53.115808)" id="g4236-8-9">
|
||||||
|
<path d="m -4.4642859,77.678574 a 4.2857141,4.2857141 0 1 1 -8.5714281,0 4.2857141,4.2857141 0 1 1 8.5714281,0 z" transform="matrix(1.13953,0,0,1.13953,39.306585,945.21999)" id="path3984-8-7-6" style="fill:#0c0000;fill-opacity:1;stroke:#000100;stroke-width:0.54189169;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
|
||||||
|
<path d="m 30.368507,1028.4151 -2.629324,6.5608 6.79834,-2.7712 z" id="path4007-0-6" style="fill:#ffffff;fill-opacity:1;stroke:none" />
|
||||||
|
<path d="m 34.753087,1030.3543 c 0,1.2916 -1.047136,2.3385 -2.338841,2.3385 -1.291706,0 -2.338842,-1.0469 -2.338842,-2.3385 0,-1.2916 1.047136,-2.3386 2.338842,-2.3386 1.291705,0 2.338841,1.047 2.338841,2.3386 z" id="path4004-6-2" style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.61750185;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<g transform="matrix(1,0,0,-1,-92.41515,1131.1661)" id="g3138" style="display:inline">
|
||||||
|
<path d="m 144.85461,1081.6667 -4.46467,0 -3.88859,-3.8125 -3.85772,3.7822 -4.51611,0 8.43041,-8.2653 z" id="path3956-37" style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
|
||||||
|
<path d="m 145.06641,1091.87 -4.46467,0 -3.88858,-3.8125 -3.85772,3.7822 -4.51611,0 8.43041,-8.2653 z" id="path3956-3-0" style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 3.7 KiB |
|
@ -0,0 +1,11 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" version="1.2" width="64" height="64" viewBox="0 0 64 64" id="svg3254" xml:space="preserve"><metadata id="metadata9"><rdf:RDF><cc:Work rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs id="defs7" />
|
||||||
|
|
||||||
|
<g id="layer1">
|
||||||
|
<g transform="matrix(1.2799322,0,0,1.3520619,50.823596,-1446.5167)" id="g3219">
|
||||||
|
<path d="m -31.496,1077.031 v 4.123 H 3.353 v -4.123 h -34.849 z m 0,8.247 v 4.124 h 21.78 v -4.124 h -21.78 z m 0,12.371 v 4.124 H 3.353 v -4.124 h -34.849 z m 0,8.247 v 4.124 h 26.137 v -4.124 h -26.137 z" id="path3386" style="fill:#041eb5" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1,018 B |
20
companion/src/images/simulator/icons/svg/word_wrap.svg
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" version="1.1" width="64" height="64" id="svg3254">
|
||||||
|
<defs id="defs3256" />
|
||||||
|
<metadata id="metadata3259">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title></dc:title>
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g id="layer1">
|
||||||
|
<g transform="matrix(1.2799322,0,0,1.3520619,50.823596,-1446.5167)" id="g3219" style="display:inline">
|
||||||
|
<path d="m -31.495574,1077.0304 0,4.1237 34.8489745,0 0,-4.1237 z m 0,8.2474 0,4.1237 21.7806103,0 0,-4.1237 z m 0,12.3711 0,4.1237 34.8489745,0 0,-4.1237 z m 0,8.2474 0,4.1237 26.1367347,0 0,-4.1237 z" id="path3386" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1 KiB |
|
@ -1,12 +1,14 @@
|
||||||
set(simulation_SRCS
|
set(simulation_SRCS
|
||||||
debugoutput.cpp
|
debugoutput.cpp
|
||||||
|
radiooutputswidget.cpp
|
||||||
simulatordialog.cpp
|
simulatordialog.cpp
|
||||||
simulatorinterface.cpp
|
|
||||||
simulateduiwidget.cpp
|
simulateduiwidget.cpp
|
||||||
simulateduiwidget9X.cpp
|
simulateduiwidget9X.cpp
|
||||||
simulateduiwidgetX7.cpp
|
simulateduiwidgetX7.cpp
|
||||||
simulateduiwidgetX9.cpp
|
simulateduiwidgetX9.cpp
|
||||||
simulateduiwidgetX12.cpp
|
simulateduiwidgetX12.cpp
|
||||||
|
simulatorinterface.cpp
|
||||||
|
simulatormainwindow.cpp
|
||||||
simulatorstartupdialog.cpp
|
simulatorstartupdialog.cpp
|
||||||
telemetrysimu.cpp
|
telemetrysimu.cpp
|
||||||
trainersimu.cpp
|
trainersimu.cpp
|
||||||
|
@ -16,11 +18,13 @@ set(simulation_SRCS
|
||||||
|
|
||||||
set(simulation_UIS
|
set(simulation_UIS
|
||||||
debugoutput.ui
|
debugoutput.ui
|
||||||
|
radiooutputswidget.ui
|
||||||
simulatordialog.ui
|
simulatordialog.ui
|
||||||
simulateduiwidget9X.ui
|
simulateduiwidget9X.ui
|
||||||
simulateduiwidgetX7.ui
|
simulateduiwidgetX7.ui
|
||||||
simulateduiwidgetX9.ui
|
simulateduiwidgetX9.ui
|
||||||
simulateduiwidgetX12.ui
|
simulateduiwidgetX12.ui
|
||||||
|
simulatormainwindow.ui
|
||||||
simulatorstartupdialog.ui
|
simulatorstartupdialog.ui
|
||||||
telemetrysimu.ui
|
telemetrysimu.ui
|
||||||
trainersimu.ui
|
trainersimu.ui
|
||||||
|
@ -28,10 +32,12 @@ set(simulation_UIS
|
||||||
|
|
||||||
set(simulation_HDRS
|
set(simulation_HDRS
|
||||||
debugoutput.h
|
debugoutput.h
|
||||||
|
radiooutputswidget.h
|
||||||
radiouiaction.h
|
radiouiaction.h
|
||||||
simulateduiwidget.h
|
simulateduiwidget.h
|
||||||
# simulator.h
|
# simulator.h
|
||||||
simulatordialog.h
|
simulatordialog.h
|
||||||
|
simulatormainwindow.h
|
||||||
simulatorstartupdialog.h
|
simulatorstartupdialog.h
|
||||||
telemetrysimu.h
|
telemetrysimu.h
|
||||||
trainersimu.h
|
trainersimu.h
|
||||||
|
@ -77,4 +83,4 @@ qt5_wrap_ui(simulation_SRCS ${simulation_UIS})
|
||||||
qt5_wrap_cpp(simulation_SRCS ${simulation_HDRS})
|
qt5_wrap_cpp(simulation_SRCS ${simulation_HDRS})
|
||||||
|
|
||||||
add_library(simulation ${simulation_SRCS} ${simulation_HDRS})
|
add_library(simulation ${simulation_SRCS} ${simulation_HDRS})
|
||||||
qt5_use_modules(simulation Widgets Xml)
|
qt5_use_modules(simulation Core Widgets Svg)
|
||||||
|
|
|
@ -21,40 +21,361 @@
|
||||||
#include "debugoutput.h"
|
#include "debugoutput.h"
|
||||||
#include "ui_debugoutput.h"
|
#include "ui_debugoutput.h"
|
||||||
|
|
||||||
DebugOutput::DebugOutput(QWidget * parent):
|
#include "appdata.h"
|
||||||
QDialog(parent),
|
|
||||||
ui(new Ui::DebugOutput)
|
#include <QMessageBox>
|
||||||
|
#include <QScrollBar>
|
||||||
|
#include <QDebug>
|
||||||
|
|
||||||
|
#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);
|
ui->setupUi(this);
|
||||||
|
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
QFont newFont("Courier", 13);
|
QFont newFont("Courier", 13);
|
||||||
ui->Output->setFont(newFont);
|
ui->console->setFont(newFont);
|
||||||
ui->Output->setAttribute(Qt::WA_MacNormalSize);
|
|
||||||
#endif
|
|
||||||
#if defined WIN32 || !defined __GNUC__
|
|
||||||
QFont newFont("Courier", 9);
|
|
||||||
ui->Output->setFont(newFont);
|
|
||||||
#endif
|
#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()
|
DebugOutput::~DebugOutput()
|
||||||
{
|
{
|
||||||
|
traceCallbackInstance = 0;
|
||||||
|
stop();
|
||||||
|
saveState();
|
||||||
|
if (m_tmrDataPrint)
|
||||||
|
delete m_tmrDataPrint;
|
||||||
delete ui;
|
delete ui;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DebugOutput::traceCallback(const QString & text)
|
void DebugOutput::start()
|
||||||
{
|
{
|
||||||
// ui->Output->appendPlainText(text);
|
m_tmrDataPrint->start();
|
||||||
QTextCursor cursor(ui->Output->textCursor());
|
m_running = true;
|
||||||
|
}
|
||||||
|
|
||||||
// is the scrollbar at the end?
|
void DebugOutput::stop()
|
||||||
bool atEnd = (ui->Output->verticalScrollBar()->value() == ui->Output->verticalScrollBar()->maximum());
|
{
|
||||||
|
m_tmrDataPrint->stop();
|
||||||
|
m_running = false;
|
||||||
|
}
|
||||||
|
|
||||||
cursor.movePosition(QTextCursor::End, QTextCursor::MoveAnchor, 1);
|
void DebugOutput::saveState()
|
||||||
cursor.insertText(text);
|
{
|
||||||
|
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) {
|
QByteArray state;
|
||||||
ui->Output->verticalScrollBar()->triggerAction(QAbstractSlider::SliderToMaximum);
|
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 = \
|
||||||
|
"<html><head><style>kbd {background-color: ghostwhite; font-size: large; white-space: nowrap;}</style></head><body>"
|
||||||
|
"<p>The filter supports two syntax types: basic matching with common wildcards and well as full Perl-style (<code>pcre</code>) Regular Expressions.</p>"
|
||||||
|
"<p>By default a filter will only show lines which match (<b>inclusive</b>). To make an <b>exclusive</b> filter which removes matching lines, "
|
||||||
|
"prefix the filter expression with a <kbd>!</kbd> (exclamation mark).</p>"
|
||||||
|
"<p>To use <b>Regular Expressions</b> (RegEx), prefix the filter text with a <kbd>/</kbd> (slash) or <kbd>^</kbd> (up caret). "
|
||||||
|
"<ul>"
|
||||||
|
"<li>Put the <kbd>/</kbd> or <kbd>^</kbd> after the exclusive <kbd>!</kbd> indicator if you're using one.</li>"
|
||||||
|
"<li>By default the match is case-sensitive. To make it insensitive, add the typical <kbd>/i</kbd> (slash i) operator at the end of your RegEx.</li>"
|
||||||
|
"<li>If you use a caret (^) to denote a RegEx, it will become part of the Reg. Ex. (that is, matches from start of line).</li>"
|
||||||
|
"<li>If the RegEx is invalid, the filter edit field should show a red border and you will not be able to enable the filter.</li>"
|
||||||
|
"<li>A useful resource for testing REs (with a full reference) can be found at <a href=\"http://www.regexr.com/\">http://www.regexr.com/</a></li>"
|
||||||
|
"</ul></p>"
|
||||||
|
"<p>To use <b>basic matching</b> just type any text. Wildcards <kbd>*</kbd> (asterisk) matches any text and <kbd>?</kbd> (question mark) matches any single character."
|
||||||
|
"<ul>"
|
||||||
|
"<li>The match is always case-insensitive.</li>"
|
||||||
|
"<li>The match always starts from the beginning of a log line. To ignore characters at the start, use a leading <kbd>*</kbd> wildcard.</li>"
|
||||||
|
"<li>A trailing <kbd>*</kbd> is always implied (that is, matches anything to the end of the log line). To avoid this, use a RegEx.</li>"
|
||||||
|
"<li>You can match literal wildcard characters by prefixing them with a <kbd>\\</kbd> (backslash) character (eg. \"foo\\*bar\" matches \"foo*bar\").</li>"
|
||||||
|
"</ul></p>"
|
||||||
|
"<p>After <b>editing text</b>, press ENTER or TAB key (or click anywhere outside the box) to update the filter.</p>"
|
||||||
|
"<p>To <b>remove an entry</b> from the filter selector list, first choose it, and while in the line editor press <kbd>Shift-Delete</kbd> (or <kbd>Shift-Backspace</kbd>) key combination. "
|
||||||
|
"The default filters cannot be removed. Up to 50 filters are stored.</p>"
|
||||||
|
"</body></html>"
|
||||||
|
;
|
||||||
|
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<QComboBox *>(obj);
|
||||||
|
if (cb && cb->isEditable() && cb->currentIndex() > -1 && cb->currentData().toString() != "no_delete") {
|
||||||
|
if (event->type() == QEvent::KeyPress) {
|
||||||
|
QKeyEvent *keyEvent = static_cast<QKeyEvent *>(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);
|
||||||
|
}
|
||||||
|
|
|
@ -21,30 +21,76 @@
|
||||||
#ifndef _DEBUGOUTPUT_H_
|
#ifndef _DEBUGOUTPUT_H_
|
||||||
#define _DEBUGOUTPUT_H_
|
#define _DEBUGOUTPUT_H_
|
||||||
|
|
||||||
#include <QtWidgets>
|
#include "simulator.h"
|
||||||
#include "simulatorinterface.h"
|
#include "simulatorinterface.h"
|
||||||
|
|
||||||
|
#include <QMutex>
|
||||||
|
#include <QTimer>
|
||||||
|
#include <QValidator>
|
||||||
|
#include <QWidget>
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
class DebugOutput;
|
class DebugOutput;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class QAbstractButton;
|
||||||
|
|
||||||
class DebugOutput : public QDialog
|
using namespace Simulator;
|
||||||
|
|
||||||
|
class DebugOutput : public QWidget
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit DebugOutput(QWidget * parent);
|
explicit DebugOutput(QWidget * parent, SimulatorInterface * simulator);
|
||||||
virtual ~DebugOutput();
|
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:
|
protected:
|
||||||
|
|
||||||
private:
|
|
||||||
Ui::DebugOutput * ui;
|
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_
|
#endif // _DEBUGOUTPUT_H_
|
||||||
|
|
|
@ -1,15 +1,21 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<ui version="4.0">
|
<ui version="4.0">
|
||||||
<class>DebugOutput</class>
|
<class>DebugOutput</class>
|
||||||
<widget class="QDialog" name="DebugOutput">
|
<widget class="QWidget" name="DebugOutput">
|
||||||
<property name="geometry">
|
<property name="geometry">
|
||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>711</width>
|
<width>555</width>
|
||||||
<height>470</height>
|
<height>733</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
<property name="windowTitle">
|
<property name="windowTitle">
|
||||||
<string>Debug Output</string>
|
<string>Debug Output</string>
|
||||||
</property>
|
</property>
|
||||||
|
@ -18,30 +24,286 @@
|
||||||
<normaloff>:/icon.png</normaloff>:/icon.png</iconset>
|
<normaloff>:/icon.png</normaloff>:/icon.png</iconset>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QGridLayout" name="gridLayout">
|
<layout class="QGridLayout" name="gridLayout">
|
||||||
|
<property name="leftMargin">
|
||||||
|
<number>7</number>
|
||||||
|
</property>
|
||||||
|
<property name="topMargin">
|
||||||
|
<number>7</number>
|
||||||
|
</property>
|
||||||
|
<property name="rightMargin">
|
||||||
|
<number>7</number>
|
||||||
|
</property>
|
||||||
|
<property name="bottomMargin">
|
||||||
|
<number>7</number>
|
||||||
|
</property>
|
||||||
|
<property name="spacing">
|
||||||
|
<number>6</number>
|
||||||
|
</property>
|
||||||
<item row="0" column="0">
|
<item row="0" column="0">
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
<widget class="QWidget" name="widget" native="true">
|
||||||
<item>
|
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||||
<widget class="QPlainTextEdit" name="Output">
|
<property name="spacing">
|
||||||
<property name="font">
|
<number>7</number>
|
||||||
<font>
|
</property>
|
||||||
<family>Courier New</family>
|
<property name="leftMargin">
|
||||||
<pointsize>10</pointsize>
|
<number>0</number>
|
||||||
</font>
|
</property>
|
||||||
</property>
|
<property name="topMargin">
|
||||||
<property name="verticalScrollBarPolicy">
|
<number>0</number>
|
||||||
<enum>Qt::ScrollBarAlwaysOn</enum>
|
</property>
|
||||||
</property>
|
<property name="rightMargin">
|
||||||
<property name="lineWrapMode">
|
<number>0</number>
|
||||||
<enum>QPlainTextEdit::NoWrap</enum>
|
</property>
|
||||||
</property>
|
<property name="bottomMargin">
|
||||||
<property name="readOnly">
|
<number>0</number>
|
||||||
<bool>true</bool>
|
</property>
|
||||||
</property>
|
<item>
|
||||||
</widget>
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
</item>
|
<property name="spacing">
|
||||||
</layout>
|
<number>2</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<widget class="QToolButton" name="btnFilter">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string><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></string>
|
||||||
|
</property>
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string notr="true">padding: 0.15em</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Filter:</string>
|
||||||
|
</property>
|
||||||
|
<property name="iconSize">
|
||||||
|
<size>
|
||||||
|
<width>18</width>
|
||||||
|
<height>18</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="checkable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="toolButtonStyle">
|
||||||
|
<enum>Qt::ToolButtonTextOnly</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QComboBox" name="filterText">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>100</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string><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></string>
|
||||||
|
</property>
|
||||||
|
<property name="editable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="currentText">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="currentIndex">
|
||||||
|
<number>-1</number>
|
||||||
|
</property>
|
||||||
|
<property name="maxCount">
|
||||||
|
<number>50</number>
|
||||||
|
</property>
|
||||||
|
<property name="insertPolicy">
|
||||||
|
<enum>QComboBox::InsertAtTop</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeAdjustPolicy">
|
||||||
|
<enum>QComboBox::AdjustToMinimumContentsLength</enum>
|
||||||
|
</property>
|
||||||
|
<property name="minimumContentsLength">
|
||||||
|
<number>1</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QToolButton" name="btnShowFilterHelp">
|
||||||
|
<property name="text">
|
||||||
|
<string notr="true">H</string>
|
||||||
|
</property>
|
||||||
|
<property name="autoRaise">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="horizontalSpacer">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeType">
|
||||||
|
<enum>QSizePolicy::Preferred</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>10</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QFormLayout" name="formLayout">
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QLabel" name="label">
|
||||||
|
<property name="text">
|
||||||
|
<string>Buffer:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="1">
|
||||||
|
<widget class="QSpinBox" name="bufferSize">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Number of lines to keep in display.</string>
|
||||||
|
</property>
|
||||||
|
<property name="suffix">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="minimum">
|
||||||
|
<number>100</number>
|
||||||
|
</property>
|
||||||
|
<property name="maximum">
|
||||||
|
<number>999999</number>
|
||||||
|
</property>
|
||||||
|
<property name="singleStep">
|
||||||
|
<number>100</number>
|
||||||
|
</property>
|
||||||
|
<property name="value">
|
||||||
|
<number>10000</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QToolButton" name="btnWordWrap">
|
||||||
|
<property name="text">
|
||||||
|
<string notr="true">WW</string>
|
||||||
|
</property>
|
||||||
|
<property name="iconSize">
|
||||||
|
<size>
|
||||||
|
<width>16</width>
|
||||||
|
<height>16</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="checkable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="autoRaise">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QToolButton" name="btnClearScr">
|
||||||
|
<property name="text">
|
||||||
|
<string notr="true">C</string>
|
||||||
|
</property>
|
||||||
|
<property name="iconSize">
|
||||||
|
<size>
|
||||||
|
<width>16</width>
|
||||||
|
<height>16</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="autoRaise">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<widget class="QPlainTextEdit" name="console">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<family>Courier New</family>
|
||||||
|
<pointsize>10</pointsize>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="verticalScrollBarPolicy">
|
||||||
|
<enum>Qt::ScrollBarAlwaysOn</enum>
|
||||||
|
</property>
|
||||||
|
<property name="undoRedoEnabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="lineWrapMode">
|
||||||
|
<enum>QPlainTextEdit::NoWrap</enum>
|
||||||
|
</property>
|
||||||
|
<property name="readOnly">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="maximumBlockCount">
|
||||||
|
<number>10000</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
|
<action name="actionShowFilterHelp">
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="../companion.qrc">
|
||||||
|
<normaloff>:/images/simulator/icons/svg/info.svg</normaloff>:/images/simulator/icons/svg/info.svg</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Filter &Help</string>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Show information about using the filter.</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionWordWrap">
|
||||||
|
<property name="checkable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="../companion.qrc">
|
||||||
|
<normaloff>:/images/simulator/icons/svg/word_wrap.svg</normaloff>:/images/simulator/icons/svg/word_wrap.svg</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Word &Wrap</string>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Toggle word wrapping on/off.</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionClearScr">
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="../companion.qrc">
|
||||||
|
<normaloff>:/images/simulator/icons/svg/eraser.svg</normaloff>:/images/simulator/icons/svg/eraser.svg</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>&Clear</string>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Clear the output window of all text.</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
</widget>
|
</widget>
|
||||||
<resources>
|
<resources>
|
||||||
<include location="../companion.qrc"/>
|
<include location="../companion.qrc"/>
|
||||||
|
|
365
companion/src/simulation/radiooutputswidget.cpp
Normal file
|
@ -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<QLabel *, QSlider *>(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<int, QLabel *> 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<int, QPair<QLabel *, QSlider *> >::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<int, QLabel* >::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<int, QHash<int, QLabel *> >::const_iterator gv;
|
||||||
|
QHash<int, QLabel *>::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;
|
||||||
|
}
|
87
companion/src/simulation/radiooutputswidget.h
Normal file
|
@ -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 <QTimer>
|
||||||
|
#include <QWidget>
|
||||||
|
|
||||||
|
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<int, QPair<QLabel *, QSlider *> > m_channelsMap; // m_channelsMap[chanIndex] = {QLabel*, QSlider*}
|
||||||
|
QHash<int, QLabel *> m_logicSwitchMap; // m_logicSwitchMap[lsIndex] = QLabel*
|
||||||
|
QHash<int, QHash<int, QLabel *> > 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
|
440
companion/src/simulation/radiooutputswidget.ui
Normal file
|
@ -0,0 +1,440 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>RadioOutputsWidget</class>
|
||||||
|
<widget class="QWidget" name="RadioOutputsWidget">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>762</width>
|
||||||
|
<height>436</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Form</string>
|
||||||
|
</property>
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string notr="true"/>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<property name="spacing">
|
||||||
|
<number>5</number>
|
||||||
|
</property>
|
||||||
|
<property name="leftMargin">
|
||||||
|
<number>7</number>
|
||||||
|
</property>
|
||||||
|
<property name="topMargin">
|
||||||
|
<number>8</number>
|
||||||
|
</property>
|
||||||
|
<property name="rightMargin">
|
||||||
|
<number>7</number>
|
||||||
|
</property>
|
||||||
|
<property name="bottomMargin">
|
||||||
|
<number>7</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<widget class="QWidget" name="widget" native="true">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||||
|
<property name="spacing">
|
||||||
|
<number>6</number>
|
||||||
|
</property>
|
||||||
|
<property name="leftMargin">
|
||||||
|
<number>3</number>
|
||||||
|
</property>
|
||||||
|
<property name="topMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="rightMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="bottomMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_4">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>View:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QToolButton" name="btnLogiSw">
|
||||||
|
<property name="text">
|
||||||
|
<string>Logical Switches</string>
|
||||||
|
</property>
|
||||||
|
<property name="checkable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="checked">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="toolButtonStyle">
|
||||||
|
<enum>Qt::ToolButtonTextBesideIcon</enum>
|
||||||
|
</property>
|
||||||
|
<property name="autoRaise">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QToolButton" name="btnGlobalVars">
|
||||||
|
<property name="text">
|
||||||
|
<string>Global Variables</string>
|
||||||
|
</property>
|
||||||
|
<property name="checkable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="checked">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="toolButtonStyle">
|
||||||
|
<enum>Qt::ToolButtonTextBesideIcon</enum>
|
||||||
|
</property>
|
||||||
|
<property name="autoRaise">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QToolButton" name="btnChannels">
|
||||||
|
<property name="text">
|
||||||
|
<string>Channel Outputs</string>
|
||||||
|
</property>
|
||||||
|
<property name="checkable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="checked">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="toolButtonStyle">
|
||||||
|
<enum>Qt::ToolButtonTextBesideIcon</enum>
|
||||||
|
</property>
|
||||||
|
<property name="autoRaise">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="horizontalSpacer">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>40</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QSplitter" name="splitter">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<property name="childrenCollapsible">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<widget class="QWidget" name="logicalSwitchesWidget" native="true">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string notr="true"/>
|
||||||
|
</property>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_4">
|
||||||
|
<property name="spacing">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="leftMargin">
|
||||||
|
<number>1</number>
|
||||||
|
</property>
|
||||||
|
<property name="topMargin">
|
||||||
|
<number>1</number>
|
||||||
|
</property>
|
||||||
|
<property name="rightMargin">
|
||||||
|
<number>1</number>
|
||||||
|
</property>
|
||||||
|
<property name="bottomMargin">
|
||||||
|
<number>1</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Fixed" vsizetype="Minimum">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="midLineWidth">
|
||||||
|
<number>3</number>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>L
|
||||||
|
o
|
||||||
|
g
|
||||||
|
i
|
||||||
|
c</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignCenter</set>
|
||||||
|
</property>
|
||||||
|
<property name="wordWrap">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="heading" stdset="0">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QScrollArea" name="logicalSwitchesScroll">
|
||||||
|
<property name="frameShape">
|
||||||
|
<enum>QFrame::NoFrame</enum>
|
||||||
|
</property>
|
||||||
|
<property name="widgetResizable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<widget class="QWidget" name="scrollAreaWidgetContents_3">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>740</width>
|
||||||
|
<height>85</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<widget class="QWidget" name="globalVarsWidget" native="true">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>2</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||||
|
<property name="spacing">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="leftMargin">
|
||||||
|
<number>1</number>
|
||||||
|
</property>
|
||||||
|
<property name="topMargin">
|
||||||
|
<number>1</number>
|
||||||
|
</property>
|
||||||
|
<property name="rightMargin">
|
||||||
|
<number>1</number>
|
||||||
|
</property>
|
||||||
|
<property name="bottomMargin">
|
||||||
|
<number>1</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_3">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="midLineWidth">
|
||||||
|
<number>3</number>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>G
|
||||||
|
l
|
||||||
|
o
|
||||||
|
b
|
||||||
|
a
|
||||||
|
l</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignCenter</set>
|
||||||
|
</property>
|
||||||
|
<property name="wordWrap">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="heading" stdset="0">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QScrollArea" name="globalVarsScroll">
|
||||||
|
<property name="frameShape">
|
||||||
|
<enum>QFrame::NoFrame</enum>
|
||||||
|
</property>
|
||||||
|
<property name="widgetResizable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<widget class="QWidget" name="scrollAreaWidgetContents_2">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>739</width>
|
||||||
|
<height>101</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<widget class="QWidget" name="channelsWidget" native="true">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>3</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
|
<property name="spacing">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="leftMargin">
|
||||||
|
<number>1</number>
|
||||||
|
</property>
|
||||||
|
<property name="topMargin">
|
||||||
|
<number>1</number>
|
||||||
|
</property>
|
||||||
|
<property name="rightMargin">
|
||||||
|
<number>1</number>
|
||||||
|
</property>
|
||||||
|
<property name="bottomMargin">
|
||||||
|
<number>1</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_2">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="midLineWidth">
|
||||||
|
<number>3</number>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>C
|
||||||
|
h
|
||||||
|
a
|
||||||
|
n
|
||||||
|
n
|
||||||
|
e
|
||||||
|
l
|
||||||
|
s</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignCenter</set>
|
||||||
|
</property>
|
||||||
|
<property name="wordWrap">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="heading" stdset="0">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QScrollArea" name="channelsScroll">
|
||||||
|
<property name="frameShape">
|
||||||
|
<enum>QFrame::NoFrame</enum>
|
||||||
|
</property>
|
||||||
|
<property name="widgetResizable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<widget class="QWidget" name="scrollAreaWidgetContents">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>739</width>
|
||||||
|
<height>194</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections>
|
||||||
|
<connection>
|
||||||
|
<sender>btnChannels</sender>
|
||||||
|
<signal>toggled(bool)</signal>
|
||||||
|
<receiver>channelsWidget</receiver>
|
||||||
|
<slot>setVisible(bool)</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>236</x>
|
||||||
|
<y>19</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>346</x>
|
||||||
|
<y>435</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
<connection>
|
||||||
|
<sender>btnGlobalVars</sender>
|
||||||
|
<signal>toggled(bool)</signal>
|
||||||
|
<receiver>globalVarsWidget</receiver>
|
||||||
|
<slot>setVisible(bool)</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>157</x>
|
||||||
|
<y>19</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>346</x>
|
||||||
|
<y>275</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
<connection>
|
||||||
|
<sender>btnLogiSw</sender>
|
||||||
|
<signal>toggled(bool)</signal>
|
||||||
|
<receiver>logicalSwitchesWidget</receiver>
|
||||||
|
<slot>setVisible(bool)</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>62</x>
|
||||||
|
<y>19</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>346</x>
|
||||||
|
<y>114</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
</connections>
|
||||||
|
</ui>
|
|
@ -127,8 +127,10 @@ class RadioUiAction : public QObject
|
||||||
{
|
{
|
||||||
if (toggle(active)) {
|
if (toggle(active)) {
|
||||||
emit triggered(m_hwIndex, active);
|
emit triggered(m_hwIndex, active);
|
||||||
if (active)
|
if (active) {
|
||||||
emit pushed(m_hwIndex);
|
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 toggled(int index, bool active); // on programmatic or user interaction change
|
||||||
void triggered(int index, bool active); // on user interaction change only
|
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(int index); // only emitted on user interaction && when 'active' is true
|
||||||
|
void pushed();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // RADIOUIACTION_H
|
#endif // RADIOUIACTION_H
|
||||||
|
|
|
@ -40,7 +40,7 @@ SimulatedUIWidget::SimulatedUIWidget(SimulatorInterface * simulator, SimulatorDi
|
||||||
{
|
{
|
||||||
m_rotEncClickAction = addRadioUiAction(-1, 0, tr("Rotary encoder click"));
|
m_rotEncClickAction = addRadioUiAction(-1, 0, tr("Rotary encoder click"));
|
||||||
m_screenshotAction = addRadioUiAction(-1, Qt::Key_Print, tr("Take Screenshot"));
|
m_screenshotAction = addRadioUiAction(-1, Qt::Key_Print, tr("Take Screenshot"));
|
||||||
connect(m_screenshotAction, &RadioUiAction::pushed, this, &SimulatedUIWidget::saveScreenshot);
|
connect(m_screenshotAction, static_cast<void (RadioUiAction::*)(void)>(&RadioUiAction::pushed), this, &SimulatedUIWidget::captureScreenshot);
|
||||||
}
|
}
|
||||||
|
|
||||||
SimulatedUIWidget::~SimulatedUIWidget()
|
SimulatedUIWidget::~SimulatedUIWidget()
|
||||||
|
@ -114,9 +114,8 @@ void SimulatedUIWidget::updateUi()
|
||||||
} */
|
} */
|
||||||
}
|
}
|
||||||
|
|
||||||
void SimulatedUIWidget::saveScreenshot(int idx)
|
void SimulatedUIWidget::captureScreenshot()
|
||||||
{
|
{
|
||||||
Q_UNUSED(idx)
|
|
||||||
QString fileName = "";
|
QString fileName = "";
|
||||||
if (!g.snapToClpbrd()) {
|
if (!g.snapToClpbrd()) {
|
||||||
QString path = g.snapshotDir();
|
QString path = g.snapshotDir();
|
||||||
|
@ -124,7 +123,8 @@ void SimulatedUIWidget::saveScreenshot(int idx)
|
||||||
path = "./";
|
path = "./";
|
||||||
QDir dir(path);
|
QDir dir(path);
|
||||||
if (!dir.exists() || !dir.isReadable()) {
|
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;
|
return;
|
||||||
}
|
}
|
||||||
fileName += QString("%1/screenshot_%2.png").arg(dir.absolutePath(), QDateTime::currentDateTime().toString("yy-MM-dd_HH-mm-ss"));
|
fileName += QString("%1/screenshot_%2.png").arg(dir.absolutePath(), QDateTime::currentDateTime().toString("yy-MM-dd_HH-mm-ss"));
|
||||||
|
@ -180,12 +180,12 @@ void SimulatedUIWidget::setLcd(LcdWidget * lcd)
|
||||||
|
|
||||||
void SimulatedUIWidget::connectScrollActions()
|
void SimulatedUIWidget::connectScrollActions()
|
||||||
{
|
{
|
||||||
connect(m_scrollUpAction, &RadioUiAction::pushed, [this](void) {
|
connect(m_scrollUpAction, static_cast<void (RadioUiAction::*)(void)>(&RadioUiAction::pushed), [this](void) {
|
||||||
this->simulatorWheelEvent(-1);
|
this->simulatorWheelEvent(-1);
|
||||||
m_scrollUpAction->toggle(false);
|
m_scrollUpAction->toggle(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
connect(m_scrollDnAction, &RadioUiAction::pushed, [this](void) {
|
connect(m_scrollDnAction, static_cast<void (RadioUiAction::*)(void)>(&RadioUiAction::pushed), [this](void) {
|
||||||
simulatorWheelEvent(1);
|
simulatorWheelEvent(1);
|
||||||
m_scrollDnAction->toggle(false);
|
m_scrollDnAction->toggle(false);
|
||||||
});
|
});
|
||||||
|
|
|
@ -64,8 +64,7 @@ class SimulatedUIWidget : public QWidget
|
||||||
public slots:
|
public slots:
|
||||||
|
|
||||||
void updateUi();
|
void updateUi();
|
||||||
void saveScreenshot(int idx = -1);
|
void captureScreenshot();
|
||||||
void captureScreenshot() { saveScreenshot(); }
|
|
||||||
void simulatorWheelEvent(qint8 steps);
|
void simulatorWheelEvent(qint8 steps);
|
||||||
|
|
||||||
void wheelEvent(QWheelEvent *event);
|
void wheelEvent(QWheelEvent *event);
|
||||||
|
|
|
@ -24,16 +24,85 @@
|
||||||
#include <QColor>
|
#include <QColor>
|
||||||
#include <QDataStream>
|
#include <QDataStream>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
#include <QFile>
|
||||||
|
#include <QIcon>
|
||||||
#include <QPair>
|
#include <QPair>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
|
|
||||||
#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<QString, QString> keymapHelp_t;
|
namespace Simulator
|
||||||
|
{
|
||||||
|
|
||||||
}
|
typedef QPair<QString, QString> 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
|
struct SimulatorOptions
|
||||||
{
|
{
|
||||||
|
@ -54,14 +123,18 @@ struct SimulatorOptions
|
||||||
QString dataFile;
|
QString dataFile;
|
||||||
QString dataFolder;
|
QString dataFolder;
|
||||||
QString sdPath;
|
QString sdPath;
|
||||||
QByteArray windowGeometry;
|
QByteArray windowGeometry; // SimulatorMainWindow geometry
|
||||||
QList<QByteArray> controlsState; // saved switch/pot/stick settings
|
QList<QByteArray> controlsState; // saved switch/pot/stick settings
|
||||||
QColor lcdColor;
|
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)
|
friend QDataStream & operator << (QDataStream &out, const SimulatorOptions & o)
|
||||||
{
|
{
|
||||||
out << quint16(SIMULATOR_OPTIONS_VERSION) << o.startupDataType << o.firmwareId << o.dataFile << o.dataFolder
|
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;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,6 +143,8 @@ struct SimulatorOptions
|
||||||
if (o._version <= SIMULATOR_OPTIONS_VERSION) {
|
if (o._version <= SIMULATOR_OPTIONS_VERSION) {
|
||||||
in >> o._version >> o.startupDataType >> o.firmwareId >> o.dataFile >> o.dataFolder
|
in >> o._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;
|
||||||
|
if (o._version >= 2)
|
||||||
|
in >> o.windowState >> o.dbgConsoleState >> o.radioOutputsState;
|
||||||
}
|
}
|
||||||
return in;
|
return in;
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,6 @@
|
||||||
#include "ui_simulatordialog.h"
|
#include "ui_simulatordialog.h"
|
||||||
|
|
||||||
#include "appdata.h"
|
#include "appdata.h"
|
||||||
#include "debugoutput.h"
|
|
||||||
#include "radiofaderwidget.h"
|
#include "radiofaderwidget.h"
|
||||||
#include "radioknobwidget.h"
|
#include "radioknobwidget.h"
|
||||||
#include "radioswitchwidget.h"
|
#include "radioswitchwidget.h"
|
||||||
|
@ -31,8 +30,6 @@
|
||||||
#include "simulateduiwidget.h"
|
#include "simulateduiwidget.h"
|
||||||
#include "simulatorinterface.h"
|
#include "simulatorinterface.h"
|
||||||
#include "storage.h"
|
#include "storage.h"
|
||||||
#include "telemetrysimu.h"
|
|
||||||
#include "trainersimu.h"
|
|
||||||
#include "virtualjoystickwidget.h"
|
#include "virtualjoystickwidget.h"
|
||||||
#ifdef JOYSTICKS
|
#ifdef JOYSTICKS
|
||||||
#include "joystick.h"
|
#include "joystick.h"
|
||||||
|
@ -43,18 +40,8 @@
|
||||||
#include <QFile>
|
#include <QFile>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
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):
|
SimulatorDialog::SimulatorDialog(QWidget * parent, SimulatorInterface *simulator, quint8 flags):
|
||||||
QDialog(parent),
|
QWidget(parent),
|
||||||
ui(new Ui::SimulatorDialog),
|
ui(new Ui::SimulatorDialog),
|
||||||
simulator(simulator),
|
simulator(simulator),
|
||||||
firmware(getCurrentFirmware()),
|
firmware(getCurrentFirmware()),
|
||||||
|
@ -63,12 +50,8 @@ SimulatorDialog::SimulatorDialog(QWidget * parent, SimulatorInterface *simulator
|
||||||
radioUiWidget(NULL),
|
radioUiWidget(NULL),
|
||||||
vJoyLeft(NULL),
|
vJoyLeft(NULL),
|
||||||
vJoyRight(NULL),
|
vJoyRight(NULL),
|
||||||
TelemetrySimu(NULL),
|
|
||||||
TrainerSimu(NULL),
|
|
||||||
DebugOut(NULL),
|
|
||||||
m_board(getCurrentBoard()),
|
m_board(getCurrentBoard()),
|
||||||
flags(flags),
|
flags(flags),
|
||||||
radioProfileId(g.id()),
|
|
||||||
lastPhase(-1),
|
lastPhase(-1),
|
||||||
buttonPressed(0),
|
buttonPressed(0),
|
||||||
trimPressed(TRIM_NONE),
|
trimPressed(TRIM_NONE),
|
||||||
|
@ -78,40 +61,74 @@ SimulatorDialog::SimulatorDialog(QWidget * parent, SimulatorInterface *simulator
|
||||||
middleButtonPressed(false),
|
middleButtonPressed(false),
|
||||||
firstShow(true)
|
firstShow(true)
|
||||||
{
|
{
|
||||||
setWindowFlags(Qt::Window);
|
|
||||||
|
|
||||||
// install simulator TRACE hook
|
|
||||||
traceCallbackInstance = this;
|
|
||||||
simulator->installTraceHook(traceCb);
|
|
||||||
|
|
||||||
#ifdef JOYSTICKS
|
#ifdef JOYSTICKS
|
||||||
joystick = NULL;
|
joystick = NULL;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// defaults
|
// defaults
|
||||||
setRadioProfileId(radioProfileId);
|
setRadioProfileId(g.sessionId());
|
||||||
setSdPath(g.profile[radioProfileId].sdPath());
|
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()
|
SimulatorDialog::~SimulatorDialog()
|
||||||
{
|
{
|
||||||
traceCallbackInstance = 0;
|
shutdown();
|
||||||
|
|
||||||
if (timer) {
|
if (timer)
|
||||||
timer->stop();
|
|
||||||
timer->deleteLater();
|
timer->deleteLater();
|
||||||
}
|
|
||||||
if (radioUiWidget)
|
if (radioUiWidget)
|
||||||
radioUiWidget->deleteLater();
|
delete radioUiWidget;
|
||||||
if (vJoyLeft)
|
if (vJoyLeft)
|
||||||
vJoyLeft->deleteLater();
|
delete vJoyLeft;
|
||||||
if (vJoyRight)
|
if (vJoyRight)
|
||||||
vJoyRight->deleteLater();
|
delete vJoyRight;
|
||||||
#ifdef JOYSTICKS
|
#ifdef JOYSTICKS
|
||||||
if (joystick)
|
if (joystick)
|
||||||
joystick->deleteLater();
|
delete joystick;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
firmware = NULL; // Not sure we should delete this but at least release our pointer.
|
firmware = NULL; // Not sure we should delete this but at least release our pointer.
|
||||||
|
@ -125,13 +142,6 @@ SimulatorDialog::~SimulatorDialog()
|
||||||
* Public slots/setters
|
* Public slots/setters
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void SimulatorDialog::setRadioProfileId(int value)
|
|
||||||
{
|
|
||||||
radioProfileId = value;
|
|
||||||
if (simulator)
|
|
||||||
simulator->setVolumeGain(g.profile[radioProfileId].volumeGain());
|
|
||||||
}
|
|
||||||
|
|
||||||
void SimulatorDialog::setSdPath(const QString & sdPath)
|
void SimulatorDialog::setSdPath(const QString & sdPath)
|
||||||
{
|
{
|
||||||
setPaths(sdPath, radioDataPath);
|
setPaths(sdPath, radioDataPath);
|
||||||
|
@ -355,25 +365,20 @@ void SimulatorDialog::deleteTempData()
|
||||||
void SimulatorDialog::saveState()
|
void SimulatorDialog::saveState()
|
||||||
{
|
{
|
||||||
SimulatorOptions opts = g.profile[radioProfileId].simulatorOptions();
|
SimulatorOptions opts = g.profile[radioProfileId].simulatorOptions();
|
||||||
opts.windowGeometry = saveGeometry();
|
//opts.windowGeometry = saveGeometry();
|
||||||
opts.controlsState = saveRadioWidgetsState();
|
opts.controlsState = saveRadioWidgetsState();
|
||||||
g.profile[radioProfileId].simulatorOptions(opts);
|
g.profile[radioProfileId].simulatorOptions(opts);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SimulatorDialog::setUiAreaStyle(const QString & style)
|
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
|
if (radioUiWidget)
|
||||||
traceMutex.lock();
|
radioUiWidget->captureScreenshot();
|
||||||
// limit the size of list
|
|
||||||
if (traceList.size() < 1000) {
|
|
||||||
traceList.append(QString(text));
|
|
||||||
}
|
|
||||||
traceMutex.unlock();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -384,8 +389,6 @@ void SimulatorDialog::start()
|
||||||
{
|
{
|
||||||
setupRadioWidgets();
|
setupRadioWidgets();
|
||||||
setupJoysticks();
|
setupJoysticks();
|
||||||
setupOutputsDisplay();
|
|
||||||
setupGVarsDisplay();
|
|
||||||
restoreRadioWidgetsState();
|
restoreRadioWidgetsState();
|
||||||
|
|
||||||
if (startupData.isEmpty())
|
if (startupData.isEmpty())
|
||||||
|
@ -414,94 +417,30 @@ void SimulatorDialog::restart()
|
||||||
start();
|
start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SimulatorDialog::shutdown()
|
||||||
|
{
|
||||||
|
stop();
|
||||||
|
saveState();
|
||||||
|
if (saveTempRadioData)
|
||||||
|
saveTempData();
|
||||||
|
if (deleteTempRadioData)
|
||||||
|
deleteTempData();
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Setup
|
* Setup
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void SimulatorDialog::setupUi()
|
void SimulatorDialog::setRadioProfileId(int value)
|
||||||
{
|
{
|
||||||
ui->setupUi(this);
|
radioProfileId = value;
|
||||||
|
if (simulator)
|
||||||
windowName = tr("Simulating Radio (%1)").arg(firmware->getName());
|
simulator->setVolumeGain(g.profile[radioProfileId].volumeGain());
|
||||||
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<QPushButton *>()) {
|
|
||||||
role = btn->property("role").toString();
|
|
||||||
if ((role == "joystick" && !showJoystick) ||
|
|
||||||
(role == "telemetry" && !firmware->getCapability(Capability(SportTelemetry))) ||
|
|
||||||
(role == "reloadLua" && !firmware->getCapability(Capability(LuaInputsPerScript))) )
|
|
||||||
{
|
|
||||||
btn->hide();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (!btn->shortcut().isEmpty())
|
|
||||||
keymapHelp.append(keymapHelp_t(btn->shortcut().toString(QKeySequence::NativeText), btn->statusTip()));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SimulatorDialog::setupRadioWidgets()
|
void SimulatorDialog::setupRadioWidgets()
|
||||||
{
|
{
|
||||||
int i, midpos, aIdx, wval;
|
int i, midpos, aIdx;
|
||||||
QString wname;
|
QString wname;
|
||||||
Board::Type board = firmware->getBoard();
|
Board::Type board = firmware->getBoard();
|
||||||
|
|
||||||
|
@ -535,13 +474,12 @@ void SimulatorDialog::setupRadioWidgets()
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
swcfg = Board::SwitchType(radioSettings.switchConfig[i]);
|
swcfg = Board::SwitchType(radioSettings.switchConfig[i]);
|
||||||
wval = (swcfg == Board::SWITCH_3POS ? -1 : 0);
|
|
||||||
|
|
||||||
if ((wname = QString(radioSettings.switchName[i])).isEmpty()) {
|
if ((wname = QString(radioSettings.switchName[i])).isEmpty()) {
|
||||||
switchInfo = getSwitchInfo(board, i);
|
switchInfo = getSwitchInfo(board, i);
|
||||||
wname = QString(switchInfo.name);
|
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);
|
sw->setIndex(i);
|
||||||
ui->radioWidgetsHTLayout->addWidget(sw);
|
ui->radioWidgetsHTLayout->addWidget(sw);
|
||||||
switches.append(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; i<outputs; i++) {
|
|
||||||
QLabel * label = new QLabel(outputsWidget);
|
|
||||||
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(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; i<switches; i++) {
|
|
||||||
QFrame * swtch = createLogicalSwitch(outputsWidget, i, logicalSwitchLabels);
|
|
||||||
logicalSwitchesLayout->addWidget(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; fm<fmodes; fm++) {
|
|
||||||
QLabel * label = new QLabel(gvarsWidget);
|
|
||||||
label->setText(QString("FM%1").arg(fm));
|
|
||||||
label->setAlignment(Qt::AlignCenter);
|
|
||||||
gvarsLayout->addWidget(label, 0, fm+1);
|
|
||||||
}
|
|
||||||
for (int i=0; i<gvars; i++) {
|
|
||||||
QLabel * label = new QLabel(gvarsWidget);
|
|
||||||
label->setText(QString("GV%1").arg(i+1));
|
|
||||||
label->setAutoFillBackground(true);
|
|
||||||
if ((i % 2) ==0 ) {
|
|
||||||
label->setStyleSheet("QLabel { background-color: rgb(220, 220, 220) }");
|
|
||||||
}
|
|
||||||
gvarsLayout->addWidget(label, i+1, 0);
|
|
||||||
for (int fm=0; fm<fmodes; fm++) {
|
|
||||||
QLabel * value = new QLabel(gvarsWidget);
|
|
||||||
value->setAutoFillBackground(true);
|
|
||||||
value->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
|
|
||||||
if ((i % 2) ==0 ) {
|
|
||||||
value->setStyleSheet("QLabel { background-color: rgb(220, 220, 220) }");
|
|
||||||
}
|
|
||||||
value->setText("0");
|
|
||||||
gvarValues << value;
|
|
||||||
gvarsLayout->addWidget(value, i+1, fm+1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
QFrame * SimulatorDialog::createLogicalSwitch(QWidget * parent, int switchNo, QVector<QLabel *> & 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()
|
void SimulatorDialog::setupJoysticks()
|
||||||
{
|
{
|
||||||
#ifdef JOYSTICKS
|
#ifdef JOYSTICKS
|
||||||
|
@ -855,6 +627,16 @@ void SimulatorDialog::restoreRadioWidgetsState()
|
||||||
if (switchesMap.contains(switches[i]->getIndex()))
|
if (switchesMap.contains(switches[i]->getIndex()))
|
||||||
switches[i]->setStateData(switchesMap.value(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<QByteArray> SimulatorDialog::saveRadioWidgetsState()
|
QList<QByteArray> SimulatorDialog::saveRadioWidgetsState()
|
||||||
|
@ -877,44 +659,8 @@ QList<QByteArray> SimulatorDialog::saveRadioWidgetsState()
|
||||||
// Read various values from firmware simulator and populate values in this UI
|
// Read various values from firmware simulator and populate values in this UI
|
||||||
void SimulatorDialog::setValues()
|
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();
|
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) ? "<b>%1</b>" : "%1").arg(outputs.gvars[fm][gv]));
|
|
||||||
prevOutputs.gvars[fm][gv] = outputs.gvars[fm][gv];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// display current flight mode in window title
|
// display current flight mode in window title
|
||||||
if (currentPhase != lastPhase) {
|
if (currentPhase != lastPhase) {
|
||||||
lastPhase = currentPhase;
|
lastPhase = currentPhase;
|
||||||
|
@ -923,7 +669,6 @@ void SimulatorDialog::setValues()
|
||||||
phase_name = QString::number(currentPhase);
|
phase_name = QString::number(currentPhase);
|
||||||
setWindowTitle(windowName + QString(" - Flight Mode %1").arg(phase_name));
|
setWindowTitle(windowName + QString(" - Flight Mode %1").arg(phase_name));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// "get" values from this UI and send them to the firmware simulator.
|
// "get" values from this UI and send them to the firmware simulator.
|
||||||
|
@ -995,34 +740,16 @@ void SimulatorDialog::setTrims()
|
||||||
* Event handlers/private slots
|
* Event handlers/private slots
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void SimulatorDialog::closeEvent(QCloseEvent *)
|
//void SimulatorDialog::showEvent(QShowEvent *)
|
||||||
{
|
//{
|
||||||
stop();
|
// if (firstShow && isVisible()) {
|
||||||
saveState();
|
// firstShow = false;
|
||||||
if (saveTempRadioData)
|
// }
|
||||||
saveTempData();
|
//}
|
||||||
if (deleteTempRadioData)
|
|
||||||
deleteTempData();
|
|
||||||
}
|
|
||||||
|
|
||||||
void SimulatorDialog::showEvent(QShowEvent *)
|
//void SimulatorDialog::closeEvent(QCloseEvent *)
|
||||||
{
|
//{
|
||||||
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::mousePressEvent(QMouseEvent *event)
|
void SimulatorDialog::mousePressEvent(QMouseEvent *event)
|
||||||
{
|
{
|
||||||
|
@ -1059,8 +786,6 @@ void SimulatorDialog::onTimerEvent()
|
||||||
setTrims();
|
setTrims();
|
||||||
centerSticks();
|
centerSticks();
|
||||||
}
|
}
|
||||||
|
|
||||||
updateDebugOutput();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SimulatorDialog::onTrimPressed(int which)
|
void SimulatorDialog::onTrimPressed(int which)
|
||||||
|
@ -1087,111 +812,9 @@ void SimulatorDialog::centerSticks()
|
||||||
vJoyRight->centerStick();
|
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 += "<table cellspacing=4 cellpadding=0>";
|
|
||||||
helpText += tr("<tr><th>Key/Mouse</td><th>Action</td></tr>");
|
|
||||||
QString keyTemplate = "<tr><td align='center'><pre>%1</pre></td><td align='center'>%2</td></tr>";
|
|
||||||
foreach (keymapHelp_t pair, keymapHelp)
|
|
||||||
helpText += keyTemplate.arg(pair.first, pair.second);
|
|
||||||
helpText += "</table>";
|
|
||||||
|
|
||||||
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)
|
void SimulatorDialog::onjoystickAxisValueChanged(int axis, int value)
|
||||||
{
|
{
|
||||||
|
#ifdef JOYSTICKS
|
||||||
int stick;
|
int stick;
|
||||||
if (axis>=0 && axis<=8) {
|
if (axis>=0 && axis<=8) {
|
||||||
stick=jsmap[axis];
|
stick=jsmap[axis];
|
||||||
|
@ -1225,5 +848,5 @@ void SimulatorDialog::onjoystickAxisValueChanged(int axis, int value)
|
||||||
analogs[stick-5]->setValue(stickval);
|
analogs[stick-5]->setValue(stickval);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
|
|
|
@ -26,17 +26,11 @@
|
||||||
#include "radiodata.h"
|
#include "radiodata.h"
|
||||||
#include "simulator.h"
|
#include "simulator.h"
|
||||||
|
|
||||||
#include <QDialog>
|
#include <QWidget>
|
||||||
#include <QVector>
|
#include <QVector>
|
||||||
#include <QMutex>
|
|
||||||
|
|
||||||
#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 FLASH_DURATION 10
|
||||||
|
|
||||||
#define CSWITCH_ON "QLabel { background-color: #4CC417 }"
|
|
||||||
#define CSWITCH_OFF "QLabel { }"
|
|
||||||
#define CBEEP_ON "QLabel { background-color: #FF364E }"
|
#define CBEEP_ON "QLabel { background-color: #FF364E }"
|
||||||
#define CBEEP_OFF "QLabel { }"
|
#define CBEEP_OFF "QLabel { }"
|
||||||
|
|
||||||
|
@ -45,9 +39,6 @@ void traceCb(const char * text);
|
||||||
class Firmware;
|
class Firmware;
|
||||||
class SimulatorInterface;
|
class SimulatorInterface;
|
||||||
class SimulatedUIWidget;
|
class SimulatedUIWidget;
|
||||||
class TelemetrySimulator;
|
|
||||||
class TrainerSimulator;
|
|
||||||
class DebugOutput;
|
|
||||||
class RadioWidget;
|
class RadioWidget;
|
||||||
class RadioSwitchWidget;
|
class RadioSwitchWidget;
|
||||||
class VirtualJoystickWidget;
|
class VirtualJoystickWidget;
|
||||||
|
@ -57,7 +48,6 @@ class Joystick;
|
||||||
|
|
||||||
class QWidget;
|
class QWidget;
|
||||||
class QSlider;
|
class QSlider;
|
||||||
class QDial;
|
|
||||||
class QLabel;
|
class QLabel;
|
||||||
class QFrame;
|
class QFrame;
|
||||||
|
|
||||||
|
@ -67,7 +57,7 @@ namespace Ui {
|
||||||
|
|
||||||
using namespace Simulator;
|
using namespace Simulator;
|
||||||
|
|
||||||
class SimulatorDialog : public QDialog
|
class SimulatorDialog : public QWidget
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
|
@ -75,7 +65,6 @@ class SimulatorDialog : public QDialog
|
||||||
explicit SimulatorDialog(QWidget * parent, SimulatorInterface *simulator, quint8 flags=0);
|
explicit SimulatorDialog(QWidget * parent, SimulatorInterface *simulator, quint8 flags=0);
|
||||||
virtual ~SimulatorDialog();
|
virtual ~SimulatorDialog();
|
||||||
|
|
||||||
void setRadioProfileId(int value);
|
|
||||||
void setSdPath(const QString & sdPath);
|
void setSdPath(const QString & sdPath);
|
||||||
void setDataPath(const QString & dataPath);
|
void setDataPath(const QString & dataPath);
|
||||||
void setPaths(const QString & sdPath, const QString & dataPath);
|
void setPaths(const QString & sdPath, const QString & dataPath);
|
||||||
|
@ -89,23 +78,22 @@ class SimulatorDialog : public QDialog
|
||||||
void deleteTempData();
|
void deleteTempData();
|
||||||
void saveState();
|
void saveState();
|
||||||
void setUiAreaStyle(const QString & style);
|
void setUiAreaStyle(const QString & style);
|
||||||
void traceCallback(const char * text);
|
void captureScreenshot(bool);
|
||||||
|
void setupJoysticks();
|
||||||
|
|
||||||
QString getSdPath() const { return sdCardPath; }
|
QString getSdPath() const { return sdCardPath; }
|
||||||
QString getDataPath() const { return radioDataPath; }
|
QString getDataPath() const { return radioDataPath; }
|
||||||
|
QVector<keymapHelp_t> * getKeymapHelp() { return &keymapHelp; }
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void start();
|
void start();
|
||||||
void stop();
|
void stop();
|
||||||
void restart();
|
void restart();
|
||||||
|
void shutdown();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void setupUi();
|
void setRadioProfileId(int value);
|
||||||
void setupRadioWidgets();
|
void setupRadioWidgets();
|
||||||
void setupOutputsDisplay();
|
|
||||||
void setupGVarsDisplay();
|
|
||||||
void setupJoysticks();
|
|
||||||
QFrame * createLogicalSwitch(QWidget * parent, int switchNo, QVector<QLabel *> & labels);
|
|
||||||
void setupTimer();
|
void setupTimer();
|
||||||
void restoreRadioWidgetsState();
|
void restoreRadioWidgetsState();
|
||||||
QList<QByteArray> saveRadioWidgetsState();
|
QList<QByteArray> saveRadioWidgetsState();
|
||||||
|
@ -122,24 +110,14 @@ class SimulatorDialog : public QDialog
|
||||||
|
|
||||||
QTimer * timer;
|
QTimer * timer;
|
||||||
QString windowName;
|
QString windowName;
|
||||||
QString traceBuffer;
|
|
||||||
QMutex traceMutex;
|
|
||||||
QList<QString> traceList;
|
|
||||||
QVector<keymapHelp_t> keymapHelp;
|
QVector<keymapHelp_t> keymapHelp;
|
||||||
|
|
||||||
SimulatedUIWidget * radioUiWidget;
|
SimulatedUIWidget * radioUiWidget;
|
||||||
VirtualJoystickWidget * vJoyLeft;
|
VirtualJoystickWidget * vJoyLeft;
|
||||||
VirtualJoystickWidget * vJoyRight;
|
VirtualJoystickWidget * vJoyRight;
|
||||||
TelemetrySimulator * TelemetrySimu;
|
|
||||||
TrainerSimulator * TrainerSimu;
|
|
||||||
DebugOutput * DebugOut;
|
|
||||||
|
|
||||||
QVector<RadioSwitchWidget *> switches;
|
QVector<RadioSwitchWidget *> switches;
|
||||||
QVector<RadioWidget *> analogs;
|
QVector<RadioWidget *> analogs;
|
||||||
QVector<QLabel *> logicalSwitchLabels;
|
|
||||||
QVector<QSlider *> channelSliders;
|
|
||||||
QVector<QLabel *> channelValues;
|
|
||||||
QVector<QLabel *> gvarValues;
|
|
||||||
|
|
||||||
QString sdCardPath;
|
QString sdCardPath;
|
||||||
QString radioDataPath;
|
QString radioDataPath;
|
||||||
|
@ -163,8 +141,8 @@ class SimulatorDialog : public QDialog
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
private slots:
|
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 mousePressEvent(QMouseEvent *event);
|
||||||
virtual void mouseReleaseEvent(QMouseEvent *event);
|
virtual void mouseReleaseEvent(QMouseEvent *event);
|
||||||
virtual void wheelEvent(QWheelEvent *event);
|
virtual void wheelEvent(QWheelEvent *event);
|
||||||
|
@ -174,16 +152,7 @@ class SimulatorDialog : public QDialog
|
||||||
void onTrimReleased();
|
void onTrimReleased();
|
||||||
void onTrimSliderMoved(int which, int value);
|
void onTrimSliderMoved(int which, int value);
|
||||||
void centerSticks();
|
void centerSticks();
|
||||||
void openTelemetrySimulator();
|
|
||||||
void openTrainerSimulator();
|
|
||||||
void openJoystickDialog();
|
|
||||||
void openDebugOutput();
|
|
||||||
void updateDebugOutput();
|
|
||||||
void luaReload();
|
|
||||||
void showHelp();
|
|
||||||
#ifdef JOYSTICKS
|
|
||||||
void onjoystickAxisValueChanged(int axis, int value);
|
void onjoystickAxisValueChanged(int axis, int value);
|
||||||
#endif
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,17 +1,17 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<ui version="4.0">
|
<ui version="4.0">
|
||||||
<class>SimulatorDialog</class>
|
<class>SimulatorDialog</class>
|
||||||
<widget class="QDialog" name="SimulatorDialog">
|
<widget class="QWidget" name="SimulatorDialog">
|
||||||
<property name="geometry">
|
<property name="geometry">
|
||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>651</width>
|
<width>448</width>
|
||||||
<height>528</height>
|
<height>302</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="sizePolicy">
|
<property name="sizePolicy">
|
||||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
|
||||||
<horstretch>0</horstretch>
|
<horstretch>0</horstretch>
|
||||||
<verstretch>0</verstretch>
|
<verstretch>0</verstretch>
|
||||||
</sizepolicy>
|
</sizepolicy>
|
||||||
|
@ -23,29 +23,26 @@
|
||||||
<iconset resource="../companion.qrc">
|
<iconset resource="../companion.qrc">
|
||||||
<normaloff>:/icon.png</normaloff>:/icon.png</iconset>
|
<normaloff>:/icon.png</normaloff>:/icon.png</iconset>
|
||||||
</property>
|
</property>
|
||||||
<property name="sizeGripEnabled">
|
<property name="styleSheet">
|
||||||
<bool>true</bool>
|
<string notr="true"/>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QGridLayout" name="gridLayout_6">
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
<property name="leftMargin">
|
<property name="spacing">
|
||||||
<number>5</number>
|
|
||||||
</property>
|
|
||||||
<property name="topMargin">
|
|
||||||
<number>5</number>
|
|
||||||
</property>
|
|
||||||
<property name="rightMargin">
|
|
||||||
<number>5</number>
|
|
||||||
</property>
|
|
||||||
<property name="bottomMargin">
|
|
||||||
<number>5</number>
|
|
||||||
</property>
|
|
||||||
<property name="horizontalSpacing">
|
|
||||||
<number>0</number>
|
<number>0</number>
|
||||||
</property>
|
</property>
|
||||||
<property name="verticalSpacing">
|
<property name="leftMargin">
|
||||||
<number>3</number>
|
<number>0</number>
|
||||||
</property>
|
</property>
|
||||||
<item row="1" column="0">
|
<property name="topMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="rightMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="bottomMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
<widget class="QFrame" name="controlFrame">
|
<widget class="QFrame" name="controlFrame">
|
||||||
<property name="sizePolicy">
|
<property name="sizePolicy">
|
||||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||||
|
@ -54,7 +51,7 @@
|
||||||
</sizepolicy>
|
</sizepolicy>
|
||||||
</property>
|
</property>
|
||||||
<property name="frameShape">
|
<property name="frameShape">
|
||||||
<enum>QFrame::Panel</enum>
|
<enum>QFrame::StyledPanel</enum>
|
||||||
</property>
|
</property>
|
||||||
<property name="frameShadow">
|
<property name="frameShadow">
|
||||||
<enum>QFrame::Raised</enum>
|
<enum>QFrame::Raised</enum>
|
||||||
|
@ -62,414 +59,248 @@
|
||||||
<property name="lineWidth">
|
<property name="lineWidth">
|
||||||
<number>2</number>
|
<number>2</number>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QGridLayout" name="gridLayout">
|
<layout class="QGridLayout" name="gridLayout" rowstretch="1,4">
|
||||||
<property name="leftMargin">
|
<property name="leftMargin">
|
||||||
<number>5</number>
|
<number>5</number>
|
||||||
</property>
|
</property>
|
||||||
<property name="topMargin">
|
<property name="topMargin">
|
||||||
<number>7</number>
|
<number>0</number>
|
||||||
</property>
|
</property>
|
||||||
<property name="rightMargin">
|
<property name="rightMargin">
|
||||||
<number>5</number>
|
<number>5</number>
|
||||||
</property>
|
</property>
|
||||||
<property name="bottomMargin">
|
<property name="bottomMargin">
|
||||||
<number>6</number>
|
<number>7</number>
|
||||||
</property>
|
</property>
|
||||||
<property name="horizontalSpacing">
|
<property name="horizontalSpacing">
|
||||||
<number>6</number>
|
<number>0</number>
|
||||||
</property>
|
</property>
|
||||||
<property name="verticalSpacing">
|
<property name="verticalSpacing">
|
||||||
<number>5</number>
|
<number>10</number>
|
||||||
</property>
|
</property>
|
||||||
<item row="1" column="0">
|
<item row="0" column="0" colspan="2" alignment="Qt::AlignBottom">
|
||||||
<widget class="QWidget" name="leftStickWidget" native="true">
|
<widget class="QFrame" name="radioWidgetsHT">
|
||||||
<property name="sizePolicy">
|
<property name="sizePolicy">
|
||||||
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
|
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||||
<horstretch>0</horstretch>
|
<horstretch>0</horstretch>
|
||||||
<verstretch>0</verstretch>
|
<verstretch>0</verstretch>
|
||||||
</sizepolicy>
|
</sizepolicy>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
<property name="frameShape">
|
||||||
<property name="spacing">
|
<enum>QFrame::Panel</enum>
|
||||||
<number>0</number>
|
|
||||||
</property>
|
|
||||||
<property name="leftMargin">
|
|
||||||
<number>0</number>
|
|
||||||
</property>
|
|
||||||
<property name="topMargin">
|
|
||||||
<number>0</number>
|
|
||||||
</property>
|
|
||||||
<property name="rightMargin">
|
|
||||||
<number>0</number>
|
|
||||||
</property>
|
|
||||||
<property name="bottomMargin">
|
|
||||||
<number>0</number>
|
|
||||||
</property>
|
|
||||||
<item>
|
|
||||||
<layout class="QHBoxLayout" name="leftStickLayout">
|
|
||||||
<property name="spacing">
|
|
||||||
<number>0</number>
|
|
||||||
</property>
|
|
||||||
</layout>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="1" column="2">
|
|
||||||
<widget class="QWidget" name="rightStickWidget" native="true">
|
|
||||||
<property name="sizePolicy">
|
|
||||||
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
|
|
||||||
<horstretch>0</horstretch>
|
|
||||||
<verstretch>0</verstretch>
|
|
||||||
</sizepolicy>
|
|
||||||
</property>
|
</property>
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
<property name="frameShadow">
|
||||||
<property name="spacing">
|
<enum>QFrame::Raised</enum>
|
||||||
<number>0</number>
|
|
||||||
</property>
|
|
||||||
<property name="leftMargin">
|
|
||||||
<number>0</number>
|
|
||||||
</property>
|
|
||||||
<property name="topMargin">
|
|
||||||
<number>0</number>
|
|
||||||
</property>
|
|
||||||
<property name="rightMargin">
|
|
||||||
<number>0</number>
|
|
||||||
</property>
|
|
||||||
<property name="bottomMargin">
|
|
||||||
<number>0</number>
|
|
||||||
</property>
|
|
||||||
<item>
|
|
||||||
<layout class="QHBoxLayout" name="rightStickLayout">
|
|
||||||
<property name="spacing">
|
|
||||||
<number>0</number>
|
|
||||||
</property>
|
|
||||||
</layout>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="1" column="1">
|
|
||||||
<widget class="QWidget" name="radioWidgetsVC" native="true">
|
|
||||||
<property name="sizePolicy">
|
|
||||||
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
|
|
||||||
<horstretch>0</horstretch>
|
|
||||||
<verstretch>0</verstretch>
|
|
||||||
</sizepolicy>
|
|
||||||
</property>
|
</property>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_2" stretch="4,1">
|
<property name="midLineWidth">
|
||||||
<property name="spacing">
|
<number>0</number>
|
||||||
<number>0</number>
|
|
||||||
</property>
|
|
||||||
<property name="leftMargin">
|
|
||||||
<number>0</number>
|
|
||||||
</property>
|
|
||||||
<property name="topMargin">
|
|
||||||
<number>0</number>
|
|
||||||
</property>
|
|
||||||
<property name="rightMargin">
|
|
||||||
<number>0</number>
|
|
||||||
</property>
|
|
||||||
<property name="bottomMargin">
|
|
||||||
<number>0</number>
|
|
||||||
</property>
|
|
||||||
<item>
|
|
||||||
<layout class="QGridLayout" name="VCGridLayout">
|
|
||||||
<property name="horizontalSpacing">
|
|
||||||
<number>16</number>
|
|
||||||
</property>
|
|
||||||
<property name="verticalSpacing">
|
|
||||||
<number>9</number>
|
|
||||||
</property>
|
|
||||||
</layout>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<spacer name="verticalSpacer">
|
|
||||||
<property name="orientation">
|
|
||||||
<enum>Qt::Vertical</enum>
|
|
||||||
</property>
|
|
||||||
<property name="sizeType">
|
|
||||||
<enum>QSizePolicy::Expanding</enum>
|
|
||||||
</property>
|
|
||||||
<property name="sizeHint" stdset="0">
|
|
||||||
<size>
|
|
||||||
<width>0</width>
|
|
||||||
<height>20</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
</spacer>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="0" column="0" colspan="3">
|
|
||||||
<widget class="QWidget" name="radioWidgetsHT" native="true">
|
|
||||||
<property name="sizePolicy">
|
|
||||||
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
|
|
||||||
<horstretch>0</horstretch>
|
|
||||||
<verstretch>0</verstretch>
|
|
||||||
</sizepolicy>
|
|
||||||
</property>
|
</property>
|
||||||
<layout class="QHBoxLayout" name="radioWidgetsHTLayout">
|
<layout class="QHBoxLayout" name="radioWidgetsHTLayout">
|
||||||
<property name="spacing">
|
<property name="spacing">
|
||||||
<number>11</number>
|
<number>10</number>
|
||||||
</property>
|
</property>
|
||||||
<property name="leftMargin">
|
<property name="leftMargin">
|
||||||
<number>6</number>
|
<number>6</number>
|
||||||
</property>
|
</property>
|
||||||
<property name="topMargin">
|
<property name="topMargin">
|
||||||
<number>6</number>
|
<number>9</number>
|
||||||
</property>
|
</property>
|
||||||
<property name="rightMargin">
|
<property name="rightMargin">
|
||||||
<number>6</number>
|
<number>6</number>
|
||||||
</property>
|
</property>
|
||||||
<property name="bottomMargin">
|
<property name="bottomMargin">
|
||||||
<number>6</number>
|
<number>9</number>
|
||||||
</property>
|
</property>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item row="1" column="0" colspan="2">
|
||||||
|
<widget class="QFrame" name="controlsLower">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<layout class="QGridLayout" name="gridLayout_2">
|
||||||
|
<property name="leftMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="topMargin">
|
||||||
|
<number>7</number>
|
||||||
|
</property>
|
||||||
|
<property name="rightMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="bottomMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="horizontalSpacing">
|
||||||
|
<number>12</number>
|
||||||
|
</property>
|
||||||
|
<property name="verticalSpacing">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<item row="0" column="0" rowspan="2">
|
||||||
|
<widget class="QWidget" name="leftStickWidget" native="true">
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||||
|
<property name="spacing">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="leftMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="topMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="rightMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="bottomMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="leftStickLayout">
|
||||||
|
<property name="spacing">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="1">
|
||||||
|
<widget class="QWidget" name="radioWidgetsVC" native="true">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_2" stretch="3,1">
|
||||||
|
<property name="spacing">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="leftMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="topMargin">
|
||||||
|
<number>12</number>
|
||||||
|
</property>
|
||||||
|
<property name="rightMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="bottomMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<layout class="QGridLayout" name="VCGridLayout">
|
||||||
|
<property name="horizontalSpacing">
|
||||||
|
<number>16</number>
|
||||||
|
</property>
|
||||||
|
<property name="verticalSpacing">
|
||||||
|
<number>9</number>
|
||||||
|
</property>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="verticalSpacer">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeType">
|
||||||
|
<enum>QSizePolicy::Preferred</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>0</width>
|
||||||
|
<height>30</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="2" rowspan="2">
|
||||||
|
<widget class="QWidget" name="rightStickWidget" native="true">
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||||
|
<property name="spacing">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="leftMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="topMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="rightMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="bottomMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="rightStickLayout">
|
||||||
|
<property name="spacing">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
<zorder>leftStickWidget</zorder>
|
||||||
|
<zorder>rightStickWidget</zorder>
|
||||||
|
<zorder>radioWidgetsVC</zorder>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="3" column="0">
|
<item alignment="Qt::AlignBottom">
|
||||||
<widget class="QTabWidget" name="tabWidget">
|
<widget class="QWidget" name="radioUiWidget" native="true">
|
||||||
<property name="enabled">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
<property name="sizePolicy">
|
<property name="sizePolicy">
|
||||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
|
||||||
<horstretch>0</horstretch>
|
<horstretch>0</horstretch>
|
||||||
<verstretch>0</verstretch>
|
<verstretch>0</verstretch>
|
||||||
</sizepolicy>
|
</sizepolicy>
|
||||||
</property>
|
</property>
|
||||||
<property name="minimumSize">
|
|
||||||
<size>
|
|
||||||
<width>0</width>
|
|
||||||
<height>200</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
<property name="styleSheet">
|
<property name="styleSheet">
|
||||||
<string notr="true">QTabWidget::pane,
|
<string notr="true"/>
|
||||||
QStackedWidget {
|
|
||||||
padding: 0px;
|
|
||||||
margin: 0px;
|
|
||||||
}
|
|
||||||
QTabWidget::tab-bar{
|
|
||||||
margin-bottom: 0px;
|
|
||||||
padding-bottom: 0px;
|
|
||||||
}</string>
|
|
||||||
</property>
|
</property>
|
||||||
<property name="currentIndex">
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
<number>0</number>
|
|
||||||
</property>
|
|
||||||
<property name="documentMode">
|
|
||||||
<bool>false</bool>
|
|
||||||
</property>
|
|
||||||
<widget class="QWidget" name="radioUiTab">
|
|
||||||
<property name="styleSheet">
|
|
||||||
<string notr="true">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;</string>
|
|
||||||
</property>
|
|
||||||
<attribute name="title">
|
|
||||||
<string>Radio Simulator</string>
|
|
||||||
</attribute>
|
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_5">
|
|
||||||
<property name="spacing">
|
|
||||||
<number>0</number>
|
|
||||||
</property>
|
|
||||||
<property name="leftMargin">
|
|
||||||
<number>0</number>
|
|
||||||
</property>
|
|
||||||
<property name="topMargin">
|
|
||||||
<number>0</number>
|
|
||||||
</property>
|
|
||||||
<property name="rightMargin">
|
|
||||||
<number>0</number>
|
|
||||||
</property>
|
|
||||||
<property name="bottomMargin">
|
|
||||||
<number>0</number>
|
|
||||||
</property>
|
|
||||||
</layout>
|
|
||||||
</widget>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="0" column="0">
|
|
||||||
<widget class="QWidget" name="buttonBox" native="true">
|
|
||||||
<property name="sizePolicy">
|
|
||||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
|
||||||
<horstretch>0</horstretch>
|
|
||||||
<verstretch>0</verstretch>
|
|
||||||
</sizepolicy>
|
|
||||||
</property>
|
|
||||||
<layout class="QHBoxLayout" name="buttonsLayout">
|
|
||||||
<property name="spacing">
|
<property name="spacing">
|
||||||
<number>3</number>
|
<number>0</number>
|
||||||
</property>
|
</property>
|
||||||
<property name="leftMargin">
|
<property name="leftMargin">
|
||||||
<number>1</number>
|
<number>0</number>
|
||||||
</property>
|
</property>
|
||||||
<property name="topMargin">
|
<property name="topMargin">
|
||||||
<number>1</number>
|
<number>0</number>
|
||||||
</property>
|
</property>
|
||||||
<property name="rightMargin">
|
<property name="rightMargin">
|
||||||
<number>1</number>
|
<number>0</number>
|
||||||
</property>
|
</property>
|
||||||
<property name="bottomMargin">
|
<property name="bottomMargin">
|
||||||
<number>1</number>
|
<number>0</number>
|
||||||
</property>
|
</property>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QPushButton" name="btn_help">
|
<spacer name="radioUiTempSpacer">
|
||||||
<property name="toolTip">
|
<property name="orientation">
|
||||||
<string>Show Help/Keymap (F1)</string>
|
<enum>Qt::Vertical</enum>
|
||||||
</property>
|
</property>
|
||||||
<property name="statusTip">
|
<property name="sizeType">
|
||||||
<string>Show Help/Keymap</string>
|
<enum>QSizePolicy::Maximum</enum>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="sizeHint" stdset="0">
|
||||||
<string>Keymap</string>
|
<size>
|
||||||
|
<width>20</width>
|
||||||
|
<height>40</height>
|
||||||
|
</size>
|
||||||
</property>
|
</property>
|
||||||
<property name="shortcut">
|
</spacer>
|
||||||
<string>F1</string>
|
|
||||||
</property>
|
|
||||||
<property name="role" stdset="0">
|
|
||||||
<string>help</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QPushButton" name="btn_joystickDialog">
|
|
||||||
<property name="toolTip">
|
|
||||||
<string>Open the Joystick Settings window (F3)</string>
|
|
||||||
</property>
|
|
||||||
<property name="statusTip">
|
|
||||||
<string>Joystick Configuration</string>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>Joystick Config.</string>
|
|
||||||
</property>
|
|
||||||
<property name="shortcut">
|
|
||||||
<string>F3</string>
|
|
||||||
</property>
|
|
||||||
<property name="role" stdset="0">
|
|
||||||
<string>joystick</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QPushButton" name="btn_telemSim">
|
|
||||||
<property name="toolTip">
|
|
||||||
<string>Open Telemetry Simulator window (F4)</string>
|
|
||||||
</property>
|
|
||||||
<property name="statusTip">
|
|
||||||
<string>Telemetry Simulator</string>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>Telemetry Sim.</string>
|
|
||||||
</property>
|
|
||||||
<property name="shortcut">
|
|
||||||
<string>F4</string>
|
|
||||||
</property>
|
|
||||||
<property name="role" stdset="0">
|
|
||||||
<string>telemetry</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QPushButton" name="btn_trainerSim">
|
|
||||||
<property name="toolTip">
|
|
||||||
<string>Open Trainer Simulator window (F5)</string>
|
|
||||||
</property>
|
|
||||||
<property name="statusTip">
|
|
||||||
<string>Trainer Simulator</string>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>Trainer Sim.</string>
|
|
||||||
</property>
|
|
||||||
<property name="shortcut">
|
|
||||||
<string>F5</string>
|
|
||||||
</property>
|
|
||||||
<property name="role" stdset="0">
|
|
||||||
<string>trainer</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QPushButton" name="btn_debugConsole">
|
|
||||||
<property name="toolTip">
|
|
||||||
<string>Open Debug Console window (F6)</string>
|
|
||||||
</property>
|
|
||||||
<property name="statusTip">
|
|
||||||
<string>Debug Console</string>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>Debug Console</string>
|
|
||||||
</property>
|
|
||||||
<property name="shortcut">
|
|
||||||
<string>F6</string>
|
|
||||||
</property>
|
|
||||||
<property name="role" stdset="0">
|
|
||||||
<string>debug</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QPushButton" name="btn_luaReload">
|
|
||||||
<property name="toolTip">
|
|
||||||
<string>Reload Lua Scripts (F7)</string>
|
|
||||||
</property>
|
|
||||||
<property name="statusTip">
|
|
||||||
<string>Reload Lua Scripts</string>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>Reload Lua</string>
|
|
||||||
</property>
|
|
||||||
<property name="shortcut">
|
|
||||||
<string>F7</string>
|
|
||||||
</property>
|
|
||||||
<property name="role" stdset="0">
|
|
||||||
<string>reloadLua</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QPushButton" name="btn_screenshot">
|
|
||||||
<property name="toolTip">
|
|
||||||
<string>Save a screenshot of the radio LCD screen (F8)</string>
|
|
||||||
</property>
|
|
||||||
<property name="statusTip">
|
|
||||||
<string>LCD Screenshot</string>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>Screenshot</string>
|
|
||||||
</property>
|
|
||||||
<property name="shortcut">
|
|
||||||
<string>F8</string>
|
|
||||||
</property>
|
|
||||||
<property name="role" stdset="0">
|
|
||||||
<string>lcdScreenshot</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QPushButton" name="btn_reloadSimu">
|
|
||||||
<property name="toolTip">
|
|
||||||
<string>Reload all radio data (F9)</string>
|
|
||||||
</property>
|
|
||||||
<property name="statusTip">
|
|
||||||
<string>Reload Radio Data</string>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>Reload Radio</string>
|
|
||||||
</property>
|
|
||||||
<property name="shortcut">
|
|
||||||
<string>F9</string>
|
|
||||||
</property>
|
|
||||||
<property name="role" stdset="0">
|
|
||||||
<string>reloadradio</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
|
|
350
companion/src/simulation/simulatormainwindow.cpp
Normal file
|
@ -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 <QDebug>
|
||||||
|
|
||||||
|
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 += "<table cellspacing=4 cellpadding=0>";
|
||||||
|
helpText += tr("<tr><th>Key/Mouse</td><th>Action</td></tr>");
|
||||||
|
QString keyTemplate = "<tr><td align='center'><pre>%1</pre></td><td align='center'>%2</td></tr>";
|
||||||
|
foreach (keymapHelp_t pair, m_keymapHelp)
|
||||||
|
helpText += keyTemplate.arg(pair.first, pair.second);
|
||||||
|
helpText += "</table>";
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
99
companion/src/simulation/simulatormainwindow.h
Normal file
|
@ -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 <QDockWidget>
|
||||||
|
#include <QMainWindow>
|
||||||
|
#include <QPointer>
|
||||||
|
|
||||||
|
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<keymapHelp_t> m_keymapHelp;
|
||||||
|
int m_radioProfileId;
|
||||||
|
bool m_firstShow;
|
||||||
|
bool m_showRadioTitlebar;
|
||||||
|
bool m_showMenubar;
|
||||||
|
|
||||||
|
const static quint16 m_savedUiStateVersion;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // SIMULATORMAINWINDOW_H
|
183
companion/src/simulation/simulatormainwindow.ui
Normal file
|
@ -0,0 +1,183 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>SimulatorMainWindow</class>
|
||||||
|
<widget class="QMainWindow" name="SimulatorMainWindow">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>644</width>
|
||||||
|
<height>371</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>OpenTx Simulator</string>
|
||||||
|
</property>
|
||||||
|
<property name="windowIcon">
|
||||||
|
<iconset>
|
||||||
|
<normaloff>:/icon.png</normaloff>:/icon.png</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="dockNestingEnabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="dockOptions">
|
||||||
|
<set>QMainWindow::AllowNestedDocks|QMainWindow::AllowTabbedDocks|QMainWindow::AnimatedDocks</set>
|
||||||
|
</property>
|
||||||
|
<widget class="QWidget" name="centralwidget"/>
|
||||||
|
<widget class="QMenuBar" name="menubar">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>644</width>
|
||||||
|
<height>21</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="nativeMenuBar">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<widget class="QMenu" name="menuView">
|
||||||
|
<property name="title">
|
||||||
|
<string>View</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QMenu" name="menuReload">
|
||||||
|
<property name="title">
|
||||||
|
<string>Reload...</string>
|
||||||
|
</property>
|
||||||
|
<addaction name="actionReloadLua"/>
|
||||||
|
<addaction name="actionReloadRadioData"/>
|
||||||
|
</widget>
|
||||||
|
<widget class="QMenu" name="menuTools">
|
||||||
|
<property name="title">
|
||||||
|
<string>Tools</string>
|
||||||
|
</property>
|
||||||
|
<addaction name="actionScreenshot"/>
|
||||||
|
<addaction name="actionJoystickSettings"/>
|
||||||
|
<addaction name="actionShowKeymap"/>
|
||||||
|
</widget>
|
||||||
|
<addaction name="menuView"/>
|
||||||
|
<addaction name="menuReload"/>
|
||||||
|
<addaction name="menuTools"/>
|
||||||
|
</widget>
|
||||||
|
<widget class="QToolBar" name="toolBar">
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Toolbar</string>
|
||||||
|
</property>
|
||||||
|
<attribute name="toolBarArea">
|
||||||
|
<enum>LeftToolBarArea</enum>
|
||||||
|
</attribute>
|
||||||
|
<attribute name="toolBarBreak">
|
||||||
|
<bool>false</bool>
|
||||||
|
</attribute>
|
||||||
|
<addaction name="actionReloadLua"/>
|
||||||
|
<addaction name="actionReloadRadioData"/>
|
||||||
|
<addaction name="separator"/>
|
||||||
|
<addaction name="actionScreenshot"/>
|
||||||
|
<addaction name="actionJoystickSettings"/>
|
||||||
|
<addaction name="actionShowKeymap"/>
|
||||||
|
</widget>
|
||||||
|
<action name="actionReloadLua">
|
||||||
|
<property name="icon">
|
||||||
|
<iconset>
|
||||||
|
<normaloff>:/images/simulator/icons/svg/reload_script.svg</normaloff>:/images/simulator/icons/svg/reload_script.svg</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Reload Lua Scripts</string>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Reload the Lua environment on the simulated radio.</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>F7</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionReloadRadioData">
|
||||||
|
<property name="icon">
|
||||||
|
<iconset>
|
||||||
|
<normaloff>:/images/simulator/icons/svg/restart.svg</normaloff>:/images/simulator/icons/svg/restart.svg</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Reload Radio Data</string>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Reload all radio data without restarting the simulator.</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>F9</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionShowKeymap">
|
||||||
|
<property name="icon">
|
||||||
|
<iconset>
|
||||||
|
<normaloff>:/images/simulator/icons/svg/info.svg</normaloff>:/images/simulator/icons/svg/info.svg</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Key Mapping</string>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Show keyboard maping reference.</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>F1</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionJoystickSettings">
|
||||||
|
<property name="icon">
|
||||||
|
<iconset>
|
||||||
|
<normaloff>:/images/simulator/icons/svg/joystick_settings.svg</normaloff>:/images/simulator/icons/svg/joystick_settings.svg</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Joystick Settings</string>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Open joystick configuration settings dialog.</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>F3</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionScreenshot">
|
||||||
|
<property name="icon">
|
||||||
|
<iconset>
|
||||||
|
<normaloff>:/images/simulator/icons/svg/camera.svg</normaloff>:/images/simulator/icons/svg/camera.svg</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>LCD Screenshot</string>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Save a screenshot of the current simulated LCD screen.</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>F8</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionToggleRadioTitle">
|
||||||
|
<property name="checkable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Radio Titlebar</string>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string><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></string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionToggleMenuBar">
|
||||||
|
<property name="checkable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Menu Bar</string>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Show or hide the top menu bar.</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>Alt+M</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
|
@ -6,10 +6,16 @@
|
||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>488</width>
|
<width>550</width>
|
||||||
<height>219</height>
|
<height>217</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>550</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
<property name="windowTitle">
|
<property name="windowTitle">
|
||||||
<string>OpenTX Simulator - Startup Options</string>
|
<string>OpenTX Simulator - Startup Options</string>
|
||||||
</property>
|
</property>
|
||||||
|
@ -22,13 +28,28 @@
|
||||||
</property>
|
</property>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QGroupBox" name="groupBox">
|
<widget class="QGroupBox" name="groupBox">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
<property name="title">
|
<property name="title">
|
||||||
<string>Simulator Startup Options:</string>
|
<string>Simulator Startup Options:</string>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QFormLayout" name="layout_options">
|
<layout class="QFormLayout" name="layout_options">
|
||||||
|
<property name="sizeConstraint">
|
||||||
|
<enum>QLayout::SetNoConstraint</enum>
|
||||||
|
</property>
|
||||||
|
<property name="fieldGrowthPolicy">
|
||||||
|
<enum>QFormLayout::AllNonFixedFieldsGrow</enum>
|
||||||
|
</property>
|
||||||
<property name="labelAlignment">
|
<property name="labelAlignment">
|
||||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="formAlignment">
|
||||||
|
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
|
||||||
|
</property>
|
||||||
<property name="horizontalSpacing">
|
<property name="horizontalSpacing">
|
||||||
<number>5</number>
|
<number>5</number>
|
||||||
</property>
|
</property>
|
||||||
|
@ -56,6 +77,12 @@
|
||||||
</item>
|
</item>
|
||||||
<item row="0" column="1">
|
<item row="0" column="1">
|
||||||
<widget class="QComboBox" name="radioProfile">
|
<widget class="QComboBox" name="radioProfile">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string>Existing radio profiles are shown here.<br />
|
<string>Existing radio profiles are shown here.<br />
|
||||||
Create or edit profiles using the Companion application.</string>
|
Create or edit profiles using the Companion application.</string>
|
||||||
|
@ -71,6 +98,12 @@ Create or edit profiles using the Companion application.</string>
|
||||||
</item>
|
</item>
|
||||||
<item row="1" column="1">
|
<item row="1" column="1">
|
||||||
<widget class="QComboBox" name="radioType">
|
<widget class="QComboBox" name="radioType">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string>Existing radio simulators are shown here.<br />
|
<string>Existing radio simulators are shown here.<br />
|
||||||
The radio type specified in the selected profile is used by default.</string>
|
The radio type specified in the selected profile is used by default.</string>
|
||||||
|
@ -107,6 +140,12 @@ The radio type specified in the selected profile is used by default.</string>
|
||||||
</item>
|
</item>
|
||||||
<item row="3" column="1">
|
<item row="3" column="1">
|
||||||
<widget class="QWidget" name="wdgt_dataFile" native="true">
|
<widget class="QWidget" name="wdgt_dataFile" native="true">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
<layout class="QHBoxLayout" name="layout_dataFile" stretch="1,0">
|
<layout class="QHBoxLayout" name="layout_dataFile" stretch="1,0">
|
||||||
<property name="spacing">
|
<property name="spacing">
|
||||||
<number>4</number>
|
<number>4</number>
|
||||||
|
@ -140,7 +179,7 @@ The radio type specified in the selected profile is used by default.</string>
|
||||||
<string>...</string>
|
<string>...</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="icon">
|
<property name="icon">
|
||||||
<iconset resource="../companion.qrc">
|
<iconset>
|
||||||
<normaloff>:/themes/monoblue/16/open.png</normaloff>:/themes/monoblue/16/open.png</iconset>
|
<normaloff>:/themes/monoblue/16/open.png</normaloff>:/themes/monoblue/16/open.png</iconset>
|
||||||
</property>
|
</property>
|
||||||
<property name="toolButtonStyle">
|
<property name="toolButtonStyle">
|
||||||
|
@ -153,6 +192,12 @@ The radio type specified in the selected profile is used by default.</string>
|
||||||
</item>
|
</item>
|
||||||
<item row="4" column="1">
|
<item row="4" column="1">
|
||||||
<widget class="QWidget" name="wdgt_dataFolder" native="true">
|
<widget class="QWidget" name="wdgt_dataFolder" native="true">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
<layout class="QHBoxLayout" name="layout_dataFolder" stretch="1,0">
|
<layout class="QHBoxLayout" name="layout_dataFolder" stretch="1,0">
|
||||||
<property name="spacing">
|
<property name="spacing">
|
||||||
<number>4</number>
|
<number>4</number>
|
||||||
|
@ -186,7 +231,7 @@ New folder(s) with default radio/model will be created here if necessary.</strin
|
||||||
<string>...</string>
|
<string>...</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="icon">
|
<property name="icon">
|
||||||
<iconset resource="../companion.qrc">
|
<iconset>
|
||||||
<normaloff>:/themes/monoblue/16/open.png</normaloff>:/themes/monoblue/16/open.png</iconset>
|
<normaloff>:/themes/monoblue/16/open.png</normaloff>:/themes/monoblue/16/open.png</iconset>
|
||||||
</property>
|
</property>
|
||||||
<property name="toolButtonStyle">
|
<property name="toolButtonStyle">
|
||||||
|
@ -199,6 +244,12 @@ New folder(s) with default radio/model will be created here if necessary.</strin
|
||||||
</item>
|
</item>
|
||||||
<item row="5" column="1">
|
<item row="5" column="1">
|
||||||
<widget class="QWidget" name="wdgt_sdPath" native="true">
|
<widget class="QWidget" name="wdgt_sdPath" native="true">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
<layout class="QHBoxLayout" name="layout_sdPath" stretch="1,0">
|
<layout class="QHBoxLayout" name="layout_sdPath" stretch="1,0">
|
||||||
<property name="spacing">
|
<property name="spacing">
|
||||||
<number>4</number>
|
<number>4</number>
|
||||||
|
@ -232,7 +283,7 @@ The default is configured in the chosen Radio Profile.</string>
|
||||||
<string>...</string>
|
<string>...</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="icon">
|
<property name="icon">
|
||||||
<iconset resource="../companion.qrc">
|
<iconset>
|
||||||
<normaloff>:/themes/monoblue/16/open.png</normaloff>:/themes/monoblue/16/open.png</iconset>
|
<normaloff>:/themes/monoblue/16/open.png</normaloff>:/themes/monoblue/16/open.png</iconset>
|
||||||
</property>
|
</property>
|
||||||
<property name="toolButtonStyle">
|
<property name="toolButtonStyle">
|
||||||
|
@ -245,6 +296,12 @@ The default is configured in the chosen Radio Profile.</string>
|
||||||
</item>
|
</item>
|
||||||
<item row="2" column="1">
|
<item row="2" column="1">
|
||||||
<widget class="QWidget" name="wdgt_dataSource" native="true">
|
<widget class="QWidget" name="wdgt_dataSource" native="true">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string>Select which of the data sources (File/Folder/SD Card) you would like to start the simulator with.</string>
|
<string>Select which of the data sources (File/Folder/SD Card) you would like to start the simulator with.</string>
|
||||||
</property>
|
</property>
|
||||||
|
@ -312,9 +369,7 @@ The default is configured in the chosen Radio Profile.</string>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
<resources>
|
<resources/>
|
||||||
<include location="../companion.qrc"/>
|
|
||||||
</resources>
|
|
||||||
<connections>
|
<connections>
|
||||||
<connection>
|
<connection>
|
||||||
<sender>buttonBox</sender>
|
<sender>buttonBox</sender>
|
||||||
|
|
|
@ -25,24 +25,20 @@
|
||||||
#include "radio/src/telemetry/frsky.h"
|
#include "radio/src/telemetry/frsky.h"
|
||||||
|
|
||||||
TelemetrySimulator::TelemetrySimulator(QWidget * parent, SimulatorInterface * simulator):
|
TelemetrySimulator::TelemetrySimulator(QWidget * parent, SimulatorInterface * simulator):
|
||||||
QDialog(parent),
|
QWidget(parent),
|
||||||
ui(new Ui::TelemetrySimulator),
|
ui(new Ui::TelemetrySimulator),
|
||||||
simulator(simulator)
|
simulator(simulator)
|
||||||
{
|
{
|
||||||
ui->setupUi(this);
|
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 = new QTimer(this);
|
||||||
|
timer->setInterval(10);
|
||||||
connect(timer, SIGNAL(timeout()), this, SLOT(onTimerEvent()));
|
connect(timer, SIGNAL(timeout()), this, SLOT(onTimerEvent()));
|
||||||
|
|
||||||
logTimer = new QTimer(this);
|
logTimer = new QTimer(this);
|
||||||
connect(logTimer, SIGNAL(timeout()), this, SLOT(onLogTimerEvent()));
|
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->loadLogFile, SIGNAL(released()), this, SLOT(onLoadLogFile()));
|
||||||
connect(ui->play, SIGNAL(released()), this, SLOT(onPlay()));
|
connect(ui->play, SIGNAL(released()), this, SLOT(onPlay()));
|
||||||
connect(ui->rewind, SIGNAL(clicked()), this, SLOT(onRewind()));
|
connect(ui->rewind, SIGNAL(clicked()), this, SLOT(onRewind()));
|
||||||
|
@ -76,7 +72,7 @@ TelemetrySimulator::~TelemetrySimulator()
|
||||||
void TelemetrySimulator::onSimulateToggled(bool isChecked)
|
void TelemetrySimulator::onSimulateToggled(bool isChecked)
|
||||||
{
|
{
|
||||||
if (isChecked) {
|
if (isChecked) {
|
||||||
timer->start(10);
|
timer->start();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
timer->stop();
|
timer->stop();
|
||||||
|
@ -197,9 +193,6 @@ void TelemetrySimulator::showEvent(QShowEvent *event)
|
||||||
ui->rxbt_ratio->setValue(simulator->getSensorRatio(BATT_ID) / 10.0);
|
ui->rxbt_ratio->setValue(simulator->getSensorRatio(BATT_ID) / 10.0);
|
||||||
ui->A1_ratio->setValue(simulator->getSensorRatio(ADC1_ID) / 10.0);
|
ui->A1_ratio->setValue(simulator->getSensorRatio(ADC1_ID) / 10.0);
|
||||||
ui->A2_ratio->setValue(simulator->getSensorRatio(ADC2_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)
|
void setSportPacketCrc(uint8_t * packet)
|
||||||
|
@ -216,7 +209,7 @@ void setSportPacketCrc(uint8_t * packet)
|
||||||
//TRACE("crc set: %x", packet[FRSKY_SPORT_PACKET_SIZE-1]);
|
//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;
|
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)
|
bool generateSportPacket(uint8_t * packet, uint8_t dataId, uint8_t prim, uint16_t appId, uint32_t data)
|
||||||
{
|
{
|
||||||
if (dataId > 0x1B ) return false;
|
if (dataId > 0x1B ) return false;
|
||||||
|
|
||||||
// generate Data ID field
|
// generate Data ID field
|
||||||
uint8_t bit5 = getBit(0, dataId) ^ getBit(1, dataId) ^ getBit(2, dataId);
|
uint8_t bit5 = getBit(0, dataId) ^ getBit(1, dataId) ^ getBit(2, dataId);
|
||||||
uint8_t bit6 = getBit(2, dataId) ^ getBit(3, dataId) ^ getBit(4, 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
|
// encode the double values into telemetry format
|
||||||
encodeAllCells();
|
encodeAllCells();
|
||||||
|
|
||||||
// return the value for the current pair
|
// return the value for the current pair
|
||||||
uint32_t cellData = 0;
|
uint32_t cellData = 0;
|
||||||
if (nextCellNum >= numCells) {
|
if (nextCellNum >= numCells) {
|
||||||
nextCellNum = 0;
|
nextCellNum = 0;
|
||||||
|
@ -644,7 +637,7 @@ TelemetrySimulator::LogPlaybackController::LogPlaybackController(Ui::TelemetrySi
|
||||||
colToFuncMap.insert("AccX(g)", ACCX);
|
colToFuncMap.insert("AccX(g)", ACCX);
|
||||||
colToFuncMap.insert("AccY(g)", ACCY);
|
colToFuncMap.insert("AccY(g)", ACCY);
|
||||||
colToFuncMap.insert("AccZ(g)", ACCZ);
|
colToFuncMap.insert("AccZ(g)", ACCZ);
|
||||||
|
|
||||||
// ACCX Y and Z
|
// ACCX Y and Z
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -839,7 +832,7 @@ double TelemetrySimulator::LogPlaybackController::convertDegMin(QString input)
|
||||||
|
|
||||||
QString TelemetrySimulator::LogPlaybackController::convertGPS(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(' ');
|
QStringList lonLat = input.simplified().split(' ');
|
||||||
if (lonLat.count() < 2) {
|
if (lonLat.count() < 2) {
|
||||||
return ""; // invalid format
|
return ""; // invalid format
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
#define _TELEMETRYSIMU_H_
|
#define _TELEMETRYSIMU_H_
|
||||||
|
|
||||||
#include <QCloseEvent>
|
#include <QCloseEvent>
|
||||||
#include <QDialog>
|
#include <QWidget>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
#include <QDateTime>
|
#include <QDateTime>
|
||||||
#include <QtCore/qmath.h>
|
#include <QtCore/qmath.h>
|
||||||
|
@ -37,102 +37,19 @@ namespace Ui {
|
||||||
class TelemetrySimulator;
|
class TelemetrySimulator;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class TelemetrySimulator : public QWidget
|
||||||
class TelemetrySimulator : public QDialog
|
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
explicit TelemetrySimulator(QWidget * parent, SimulatorInterface * simulator);
|
explicit TelemetrySimulator(QWidget * parent, SimulatorInterface * simulator);
|
||||||
virtual ~TelemetrySimulator();
|
virtual ~TelemetrySimulator();
|
||||||
|
|
||||||
protected:
|
protected slots:
|
||||||
|
|
||||||
virtual void closeEvent(QCloseEvent *event);
|
virtual void closeEvent(QCloseEvent *event);
|
||||||
virtual void showEvent(QShowEvent *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<QString, CONVERT_TYPE> 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<DATA_TO_FUNC_XREF> 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 onSimulateToggled(bool isChecked);
|
||||||
void onTimerEvent();
|
void onTimerEvent();
|
||||||
void onLogTimerEvent();
|
void onLogTimerEvent();
|
||||||
|
@ -145,49 +62,138 @@ private:
|
||||||
void onPositionIndicatorChanged(int value);
|
void onPositionIndicatorChanged(int value);
|
||||||
void onReplayRateChanged(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<QString, CONVERT_TYPE> 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<DATA_TO_FUNC_XREF> supportedCols;
|
||||||
|
int32_t recordIndex;
|
||||||
|
bool stepping;
|
||||||
|
}; // LogPlaybackController
|
||||||
|
|
||||||
|
LogPlaybackController *logPlayback;
|
||||||
|
|
||||||
private: // private classes follow
|
|
||||||
class FlvssEmulator
|
class FlvssEmulator
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
uint32_t setAllCells_GetNextPair(double cellValues[6]);
|
uint32_t setAllCells_GetNextPair(double cellValues[6]);
|
||||||
static const uint32_t MAXCELLS = 6;
|
static const uint32_t MAXCELLS = 6;
|
||||||
private:
|
|
||||||
void encodeAllCells();
|
private:
|
||||||
void splitIntoCells(double totalVolts);
|
void encodeAllCells();
|
||||||
static uint32_t encodeCellPair(uint8_t cellNum, uint8_t firstCellNo, double cell1, double cell2);
|
void splitIntoCells(double totalVolts);
|
||||||
double cellFloats[6];
|
static uint32_t encodeCellPair(uint8_t cellNum, uint8_t firstCellNo, double cell1, double cell2);
|
||||||
uint32_t nextCellNum;
|
double cellFloats[6];
|
||||||
uint32_t numCells;
|
uint32_t nextCellNum;
|
||||||
uint32_t cellData1;
|
uint32_t numCells;
|
||||||
uint32_t cellData2;
|
uint32_t cellData1;
|
||||||
uint32_t cellData3;
|
uint32_t cellData2;
|
||||||
};
|
uint32_t cellData3;
|
||||||
|
}; // FlvssEmulator
|
||||||
|
|
||||||
class GPSEmulator
|
class GPSEmulator
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
GPSEmulator();
|
GPSEmulator();
|
||||||
uint32_t getNextPacketData(uint32_t packetType);
|
uint32_t getNextPacketData(uint32_t packetType);
|
||||||
void setGPSDateTime(QString dateTime);
|
void setGPSDateTime(QString dateTime);
|
||||||
void setGPSLatLon(QString latLon);
|
void setGPSLatLon(QString latLon);
|
||||||
void setGPSCourse(double course);
|
void setGPSCourse(double course);
|
||||||
void setGPSSpeedKMH(double speed);
|
void setGPSSpeedKMH(double speed);
|
||||||
void setGPSAltitude(double altitude);
|
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);
|
|
||||||
};
|
|
||||||
|
|
||||||
};
|
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_
|
#endif // _TELEMETRYSIMU_H_
|
||||||
|
|
||||||
|
|
|
@ -22,37 +22,45 @@
|
||||||
#include "trainersimu.h"
|
#include "trainersimu.h"
|
||||||
#include "ui_trainersimu.h"
|
#include "ui_trainersimu.h"
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
|
#include "virtualjoystickwidget.h"
|
||||||
#define GBALL_SIZE 20
|
|
||||||
#define RESX 512
|
|
||||||
|
|
||||||
TrainerSimulator::TrainerSimulator(QWidget * parent, SimulatorInterface * simulator):
|
TrainerSimulator::TrainerSimulator(QWidget * parent, SimulatorInterface * simulator):
|
||||||
QDialog(parent),
|
QWidget(parent),
|
||||||
ui(new Ui::TrainerSimulator),
|
ui(new Ui::TrainerSimulator),
|
||||||
simulator(simulator)
|
simulator(simulator)
|
||||||
{
|
{
|
||||||
ui->setupUi(this);
|
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
|
vJoyRight = new VirtualJoystickWidget(this, 'R', false);
|
||||||
setFixedSize(width(), height());
|
vJoyRight->setStickColor(Qt::cyan);
|
||||||
|
ui->rightStickLayout->addWidget(vJoyRight);
|
||||||
|
|
||||||
timer = new QTimer(this);
|
timer = new QTimer(this);
|
||||||
|
timer->setInterval(10);
|
||||||
connect(timer, SIGNAL(timeout()), this, SLOT(onTimerEvent()));
|
connect(timer, SIGNAL(timeout()), this, SLOT(onTimerEvent()));
|
||||||
}
|
}
|
||||||
|
|
||||||
TrainerSimulator::~TrainerSimulator()
|
TrainerSimulator::~TrainerSimulator()
|
||||||
{
|
{
|
||||||
timer->stop();
|
if (timer) {
|
||||||
|
timer->stop();
|
||||||
|
delete timer;
|
||||||
|
}
|
||||||
|
if (vJoyLeft)
|
||||||
|
delete vJoyLeft;
|
||||||
|
if (vJoyRight)
|
||||||
|
delete vJoyRight;
|
||||||
|
|
||||||
delete ui;
|
delete ui;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TrainerSimulator::showEvent(QShowEvent *event)
|
void TrainerSimulator::showEvent(QShowEvent *event)
|
||||||
{
|
{
|
||||||
timer->start(10);
|
timer->start();
|
||||||
event->accept();
|
event->accept();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -64,71 +72,13 @@ void TrainerSimulator::closeEvent(QCloseEvent *event)
|
||||||
|
|
||||||
void TrainerSimulator::centerSticks()
|
void TrainerSimulator::centerSticks()
|
||||||
{
|
{
|
||||||
if (leftStick->scene())
|
if (vJoyLeft)
|
||||||
nodeLeft->stepToCenter();
|
vJoyLeft->centerStick();
|
||||||
|
|
||||||
if (rightStick->scene())
|
if (vJoyRight)
|
||||||
nodeRight->stepToCenter();
|
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()
|
void TrainerSimulator::onTimerEvent()
|
||||||
{
|
{
|
||||||
centerSticks();
|
centerSticks();
|
||||||
|
@ -137,8 +87,15 @@ void TrainerSimulator::onTimerEvent()
|
||||||
|
|
||||||
void TrainerSimulator::setTrainerInputs()
|
void TrainerSimulator::setTrainerInputs()
|
||||||
{
|
{
|
||||||
simulator->setTrainerInput(0, int( 512* nodeLeft->getX())); // LEFT HORZ
|
if (!simulator)
|
||||||
simulator->setTrainerInput(1, int(-512* nodeLeft->getY())); // LEFT VERT
|
return;
|
||||||
simulator->setTrainerInput(2, int(-512*nodeRight->getY())); // RGHT VERT
|
|
||||||
simulator->setTrainerInput(3, int( 512*nodeRight->getX())); // RGHT HORZ
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -24,17 +24,17 @@
|
||||||
|
|
||||||
#include <QShowEvent>
|
#include <QShowEvent>
|
||||||
#include <QCloseEvent>
|
#include <QCloseEvent>
|
||||||
#include <QDialog>
|
#include <QWidget>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
#include "modeledit/node.h"
|
|
||||||
#include "simulatorinterface.h"
|
#include "simulatorinterface.h"
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
class TrainerSimulator;
|
class TrainerSimulator;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class VirtualJoystickWidget;
|
||||||
|
|
||||||
class TrainerSimulator : public QDialog
|
class TrainerSimulator : public QWidget
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
|
@ -43,26 +43,20 @@ class TrainerSimulator : public QDialog
|
||||||
virtual ~TrainerSimulator();
|
virtual ~TrainerSimulator();
|
||||||
|
|
||||||
|
|
||||||
protected:
|
protected slots:
|
||||||
virtual void showEvent(QShowEvent *event);
|
virtual void showEvent(QShowEvent *event);
|
||||||
virtual void closeEvent(QCloseEvent *event);
|
virtual void closeEvent(QCloseEvent *event);
|
||||||
|
void centerSticks();
|
||||||
|
void setTrainerInputs();
|
||||||
|
void onTimerEvent();
|
||||||
|
|
||||||
private:
|
protected:
|
||||||
Ui::TrainerSimulator * ui;
|
Ui::TrainerSimulator * ui;
|
||||||
QTimer * timer;
|
QTimer * timer;
|
||||||
SimulatorInterface *simulator;
|
SimulatorInterface *simulator;
|
||||||
|
|
||||||
QGraphicsView * leftStick, * rightStick;
|
VirtualJoystickWidget * vJoyLeft;
|
||||||
Node *nodeLeft;
|
VirtualJoystickWidget * vJoyRight;
|
||||||
Node *nodeRight;
|
|
||||||
|
|
||||||
void centerSticks();
|
|
||||||
void setupSticks();
|
|
||||||
void resizeEvent(QResizeEvent *event = 0);
|
|
||||||
void setTrainerInputs();
|
|
||||||
|
|
||||||
private slots:
|
|
||||||
void onTimerEvent();
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,94 +1,70 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<ui version="4.0">
|
<ui version="4.0">
|
||||||
<class>TrainerSimulator</class>
|
<class>TrainerSimulator</class>
|
||||||
<widget class="QDialog" name="TrainerSimulator">
|
<widget class="QWidget" name="TrainerSimulator">
|
||||||
<property name="geometry">
|
<property name="geometry">
|
||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>566</width>
|
<width>385</width>
|
||||||
<height>268</height>
|
<height>187</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
<property name="windowTitle">
|
<property name="windowTitle">
|
||||||
<string>Trainer simulator</string>
|
<string>Trainer simulator</string>
|
||||||
</property>
|
</property>
|
||||||
<widget class="QFrame" name="frame">
|
<layout class="QGridLayout" name="gridLayout">
|
||||||
<property name="geometry">
|
<item row="0" column="0">
|
||||||
<rect>
|
<widget class="QFrame" name="frame">
|
||||||
<x>0</x>
|
<property name="frameShape">
|
||||||
<y>0</y>
|
<enum>QFrame::Panel</enum>
|
||||||
<width>563</width>
|
</property>
|
||||||
<height>267</height>
|
<property name="frameShadow">
|
||||||
</rect>
|
<enum>QFrame::Raised</enum>
|
||||||
</property>
|
</property>
|
||||||
<property name="frameShape">
|
<property name="lineWidth">
|
||||||
<enum>QFrame::Panel</enum>
|
<number>2</number>
|
||||||
</property>
|
</property>
|
||||||
<property name="frameShadow">
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
<enum>QFrame::Raised</enum>
|
<property name="spacing">
|
||||||
</property>
|
<number>15</number>
|
||||||
<property name="lineWidth">
|
</property>
|
||||||
<number>2</number>
|
<property name="leftMargin">
|
||||||
</property>
|
<number>0</number>
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
</property>
|
||||||
<property name="margin">
|
<property name="topMargin">
|
||||||
<number>5</number>
|
<number>0</number>
|
||||||
</property>
|
</property>
|
||||||
<item>
|
<property name="rightMargin">
|
||||||
<layout class="QGridLayout" name="gridLayout_3">
|
<number>0</number>
|
||||||
<item row="0" column="1">
|
</property>
|
||||||
<spacer name="horizontalSpacer">
|
<property name="bottomMargin">
|
||||||
<property name="orientation">
|
<number>0</number>
|
||||||
<enum>Qt::Horizontal</enum>
|
</property>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="leftStickLayout">
|
||||||
|
<property name="spacing">
|
||||||
|
<number>0</number>
|
||||||
</property>
|
</property>
|
||||||
<property name="sizeType">
|
</layout>
|
||||||
<enum>QSizePolicy::Minimum</enum>
|
|
||||||
</property>
|
|
||||||
<property name="sizeHint" stdset="0">
|
|
||||||
<size>
|
|
||||||
<width>17</width>
|
|
||||||
<height>20</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
</spacer>
|
|
||||||
</item>
|
</item>
|
||||||
<item row="0" column="2">
|
<item>
|
||||||
<widget class="QGraphicsView" name="rightStick">
|
<layout class="QHBoxLayout" name="rightStickLayout">
|
||||||
<property name="minimumSize">
|
<property name="spacing">
|
||||||
<size>
|
<number>0</number>
|
||||||
<width>245</width>
|
|
||||||
<height>245</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
</property>
|
||||||
<property name="verticalScrollBarPolicy">
|
</layout>
|
||||||
<enum>Qt::ScrollBarAlwaysOff</enum>
|
|
||||||
</property>
|
|
||||||
<property name="horizontalScrollBarPolicy">
|
|
||||||
<enum>Qt::ScrollBarAlwaysOff</enum>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="0" column="0">
|
|
||||||
<widget class="QGraphicsView" name="leftStick">
|
|
||||||
<property name="minimumSize">
|
|
||||||
<size>
|
|
||||||
<width>245</width>
|
|
||||||
<height>245</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
<property name="verticalScrollBarPolicy">
|
|
||||||
<enum>Qt::ScrollBarAlwaysOff</enum>
|
|
||||||
</property>
|
|
||||||
<property name="horizontalScrollBarPolicy">
|
|
||||||
<enum>Qt::ScrollBarAlwaysOff</enum>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</widget>
|
||||||
</layout>
|
</item>
|
||||||
</widget>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
<resources/>
|
<resources/>
|
||||||
<connections/>
|
<connections/>
|
||||||
|
|
|
@ -47,7 +47,7 @@ class RadioFaderWidget : public RadioWidget
|
||||||
|
|
||||||
SliderWidget * sl = new SliderWidget(this);
|
SliderWidget * sl = new SliderWidget(this);
|
||||||
sl->setOrientation(Qt::Vertical);
|
sl->setOrientation(Qt::Vertical);
|
||||||
sl->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding);
|
sl->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred);
|
||||||
sl->setMinimumHeight(75);
|
sl->setMinimumHeight(75);
|
||||||
//sl->setMaximumHeight(75);
|
//sl->setMaximumHeight(75);
|
||||||
sl->setTickPosition(QSlider::TicksBothSides);
|
sl->setTickPosition(QSlider::TicksBothSides);
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
|
|
||||||
#include "radiowidget.h"
|
#include "radiowidget.h"
|
||||||
#include "boards.h"
|
#include "boards.h"
|
||||||
|
#include "simulator.h"
|
||||||
|
|
||||||
#include <QSlider>
|
#include <QSlider>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
|
@ -65,11 +66,8 @@ class RadioSwitchWidget : public RadioWidget
|
||||||
m_slider->setValue(m_value);
|
m_slider->setValue(m_value);
|
||||||
|
|
||||||
if (swType == Board::SWITCH_TOGGLE) {
|
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);
|
QToolButton * lockBtn = new QToolButton(this);
|
||||||
lockBtn->setIcon(icon);
|
lockBtn->setIcon(Simulator::SimulatorIcon("toggle_lock"));
|
||||||
lockBtn->setIconSize(QSize(8, 8));
|
lockBtn->setIconSize(QSize(8, 8));
|
||||||
lockBtn->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
|
lockBtn->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
|
||||||
lockBtn->setToolButtonStyle(Qt::ToolButtonIconOnly);
|
lockBtn->setToolButtonStyle(Qt::ToolButtonIconOnly);
|
||||||
|
@ -78,7 +76,7 @@ class RadioSwitchWidget : public RadioWidget
|
||||||
lockBtn->setToolTip(tr("Latch/unlatch the momentary switch."));
|
lockBtn->setToolTip(tr("Latch/unlatch the momentary switch."));
|
||||||
|
|
||||||
QWidget * container = new QWidget(this);
|
QWidget * container = new QWidget(this);
|
||||||
container->setFixedHeight(50);
|
container->setFixedHeight(56);
|
||||||
container->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
|
container->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
|
||||||
QVBoxLayout * cl = new QVBoxLayout(container);
|
QVBoxLayout * cl = new QVBoxLayout(container);
|
||||||
cl->setContentsMargins(0, 0, 0, 0);
|
cl->setContentsMargins(0, 0, 0, 0);
|
||||||
|
@ -94,7 +92,7 @@ class RadioSwitchWidget : public RadioWidget
|
||||||
connect(this, &RadioWidget::flagsChanged, lockBtn, &QToolButton::setChecked);
|
connect(this, &RadioWidget::flagsChanged, lockBtn, &QToolButton::setChecked);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
m_slider->setFixedHeight(50);
|
m_slider->setFixedHeight(56);
|
||||||
setWidget(m_slider);
|
setWidget(m_slider);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,9 @@
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#define GBALL_SIZE 20
|
||||||
|
#define RESX 1024
|
||||||
|
|
||||||
#include "virtualjoystickwidget.h"
|
#include "virtualjoystickwidget.h"
|
||||||
#include "constants.h"
|
#include "constants.h"
|
||||||
#include "sliderwidget.h"
|
#include "sliderwidget.h"
|
||||||
|
@ -50,7 +53,9 @@ VirtualJoystickWidget::VirtualJoystickWidget(QWidget *parent, QChar side, bool s
|
||||||
|
|
||||||
gv = new QGraphicsView(this);
|
gv = new QGraphicsView(this);
|
||||||
gv->setSizePolicy(sizePolicy);
|
gv->setSizePolicy(sizePolicy);
|
||||||
gv->setMinimumSize(QSize(150, 150));
|
gv->setMinimumSize(size);
|
||||||
|
// gv->setMaximumSize(size + size * 3);
|
||||||
|
// gv->setFixedSize(prefSize);
|
||||||
gv->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
gv->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||||
gv->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
gv->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||||
|
|
||||||
|
@ -88,6 +93,9 @@ VirtualJoystickWidget::VirtualJoystickWidget(QWidget *parent, QChar side, bool s
|
||||||
vTrimSlider = vTrimWidget->findChild<SliderWidget *>();
|
vTrimSlider = vTrimWidget->findChild<SliderWidget *>();
|
||||||
extraSize += QSize(vTrimWidget->sizeHint().width(), hTrimWidget->sizeHint().height());
|
extraSize += QSize(vTrimWidget->sizeHint().width(), hTrimWidget->sizeHint().height());
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
colvx = colvy = colvt;
|
||||||
|
}
|
||||||
|
|
||||||
if (showBtns) {
|
if (showBtns) {
|
||||||
QVBoxLayout * btnbox = new QVBoxLayout();
|
QVBoxLayout * btnbox = new QVBoxLayout();
|
||||||
|
@ -106,8 +114,17 @@ VirtualJoystickWidget::VirtualJoystickWidget(QWidget *parent, QChar side, bool s
|
||||||
if (showValues) {
|
if (showValues) {
|
||||||
QLayout * valX = createNodeValueLayout('X', nodeLabelX);
|
QLayout * valX = createNodeValueLayout('X', nodeLabelX);
|
||||||
QLayout * valY = createNodeValueLayout('Y', nodeLabelY);
|
QLayout * valY = createNodeValueLayout('Y', nodeLabelY);
|
||||||
layout->addLayout(valX, 2, colvx, 1, 1);
|
if (!showTrims) {
|
||||||
layout->addLayout(valY, 2, colvy, 1, 1);
|
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
|
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(xChanged()), this, SLOT(updateNodeValueLabels()));
|
||||||
connect(node, SIGNAL(yChanged()), this, SLOT(updateNodeValueLabels()));
|
connect(node, SIGNAL(yChanged()), this, SLOT(updateNodeValueLabels()));
|
||||||
|
|
||||||
setSize(prefSize);
|
setSize(prefSize, frameSize());
|
||||||
}
|
}
|
||||||
|
|
||||||
void VirtualJoystickWidget::setStickX(qreal x)
|
void VirtualJoystickWidget::setStickX(qreal x)
|
||||||
|
@ -144,12 +161,12 @@ void VirtualJoystickWidget::centerStick()
|
||||||
|
|
||||||
qreal VirtualJoystickWidget::getStickX()
|
qreal VirtualJoystickWidget::getStickX()
|
||||||
{
|
{
|
||||||
return node->getX();
|
return getStickPos().x();
|
||||||
}
|
}
|
||||||
|
|
||||||
qreal VirtualJoystickWidget::getStickY()
|
qreal VirtualJoystickWidget::getStickY()
|
||||||
{
|
{
|
||||||
return node->getY();
|
return getStickPos().y();
|
||||||
}
|
}
|
||||||
|
|
||||||
QPointF VirtualJoystickWidget::getStickPos()
|
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 thisAspectRatio = (float)size.width() / size.height();
|
||||||
float newGvSz, spacerSz;
|
float newGvSz, spacerSz;
|
||||||
|
@ -237,28 +269,24 @@ void VirtualJoystickWidget::setSize(QSize size)
|
||||||
layout->setColumnStretch(2, newGvSz);
|
layout->setColumnStretch(2, newGvSz);
|
||||||
layout->setRowStretch(1, 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->resize(newGvSz, newGvSz);
|
||||||
gv->updateGeometry();
|
gv->updateGeometry();
|
||||||
repositionNode();
|
|
||||||
//qDebug() << thisAspectRatio << size << newGvSz << spacerSz << extraSize << gv->geometry() << gv->contentsRect() << gv->frameRect() << getStickPos();
|
|
||||||
}
|
|
||||||
|
|
||||||
void VirtualJoystickWidget::repositionNode()
|
QRectF qr = (QRectF)gv->contentsRect();
|
||||||
{
|
qreal w = qr.width() - GBALL_SIZE;
|
||||||
QRect qr = gv->contentsRect();
|
qreal h = qr.height() - GBALL_SIZE;
|
||||||
qreal w = (qreal)qr.width() - GBALL_SIZE;
|
qreal cx = qr.width() / 2;
|
||||||
qreal h = (qreal)qr.height() - GBALL_SIZE;
|
qreal cy = qr.height() / 2;
|
||||||
qreal cx = (qreal)qr.width()/2;
|
qreal nodeX = node->getX();
|
||||||
qreal cy = (qreal)qr.height()/2;
|
qreal nodeY = node->getY();
|
||||||
|
|
||||||
scene->setSceneRect(-cx,-cy,w,h);
|
scene->setSceneRect(-cx,-cy,w,h);
|
||||||
|
|
||||||
QPointF p = node->pos();
|
node->setX(nodeX);
|
||||||
p.setX(qMin(cx, qMax(p.x(), -cx)));
|
node->setY(nodeY);
|
||||||
p.setY(qMin(cy, qMax(p.y(), -cy)));
|
|
||||||
node->setPos(p);
|
|
||||||
|
|
||||||
updateNodeValueLabels();
|
//qDebug() << thisAspectRatio << size << newGvSz << spacerSz << extraSize << gv->geometry() << gv->contentsRect() << gv->frameRect() << getStickPos();
|
||||||
}
|
}
|
||||||
|
|
||||||
QWidget *VirtualJoystickWidget::createTrimWidget(QChar type)
|
QWidget *VirtualJoystickWidget::createTrimWidget(QChar type)
|
||||||
|
@ -382,6 +410,7 @@ QLayout *VirtualJoystickWidget::createNodeValueLayout(QChar type, QLabel *& valL
|
||||||
val->setObjectName(QString("val_%1").arg(type));
|
val->setObjectName(QString("val_%1").arg(type));
|
||||||
val->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
|
val->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
|
||||||
val->setAlignment(Qt::AlignCenter);
|
val->setAlignment(Qt::AlignCenter);
|
||||||
|
val->setMinimumWidth(val->fontMetrics().width("-100 "));
|
||||||
QVBoxLayout * layout = new QVBoxLayout();
|
QVBoxLayout * layout = new QVBoxLayout();
|
||||||
layout->setContentsMargins(2, 2, 2, 2);
|
layout->setContentsMargins(2, 2, 2, 2);
|
||||||
layout->setSpacing(2);
|
layout->setSpacing(2);
|
||||||
|
|
|
@ -33,9 +33,6 @@
|
||||||
class Node;
|
class Node;
|
||||||
class SliderWidget;
|
class SliderWidget;
|
||||||
|
|
||||||
#define GBALL_SIZE 20
|
|
||||||
#define RESX 1024
|
|
||||||
|
|
||||||
class VirtualJoystickWidget : public QWidget
|
class VirtualJoystickWidget : public QWidget
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
@ -55,7 +52,7 @@ class VirtualJoystickWidget : public QWidget
|
||||||
FIX_Y
|
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 setStickX(qreal x);
|
||||||
void setStickY(qreal y);
|
void setStickY(qreal y);
|
||||||
|
@ -70,17 +67,10 @@ class VirtualJoystickWidget : public QWidget
|
||||||
int getTrimValue(int which);
|
int getTrimValue(int which);
|
||||||
|
|
||||||
void setStickConstraint(int which, bool active);
|
void setStickConstraint(int which, bool active);
|
||||||
|
void setStickColor(const QColor & color);
|
||||||
|
|
||||||
virtual QSize sizeHint() const
|
virtual QSize sizeHint() const;
|
||||||
{
|
virtual void resizeEvent(QResizeEvent *event);
|
||||||
return prefSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void resizeEvent(QResizeEvent *event)
|
|
||||||
{
|
|
||||||
QWidget::resizeEvent(event);
|
|
||||||
setSize(event->size());
|
|
||||||
}
|
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void trimButtonPressed(int which);
|
void trimButtonPressed(int which);
|
||||||
|
@ -94,8 +84,7 @@ class VirtualJoystickWidget : public QWidget
|
||||||
void updateNodeValueLabels();
|
void updateNodeValueLabels();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void setSize(QSize size);
|
void setSize(const QSize & size, const QSize &);
|
||||||
void repositionNode();
|
|
||||||
QWidget * createTrimWidget(QChar type);
|
QWidget * createTrimWidget(QChar type);
|
||||||
QPushButton * createButtonWidget(int type);
|
QPushButton * createButtonWidget(int type);
|
||||||
QLayout * createNodeValueLayout(QChar type, QLabel *& valLabel);
|
QLayout * createNodeValueLayout(QChar type, QLabel *& valLabel);
|
||||||
|
|
|
@ -19,13 +19,14 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
//#include <QTranslator>
|
#include <QTranslator>
|
||||||
|
#include <QLibraryInfo>
|
||||||
#include <QLocale>
|
#include <QLocale>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QTextStream>
|
#include <QTextStream>
|
||||||
#include <QDialog>
|
#include <QMessageBox>
|
||||||
#if defined(JOYSTICKS) || defined(SIMU_AUDIO)
|
#if defined(JOYSTICKS) || defined(SIMU_AUDIO)
|
||||||
#include <SDL.h>
|
#include <SDL.h>
|
||||||
#undef main
|
#undef main
|
||||||
|
@ -35,10 +36,11 @@
|
||||||
#include "constants.h"
|
#include "constants.h"
|
||||||
#include "eeprominterface.h"
|
#include "eeprominterface.h"
|
||||||
#include "simulator.h"
|
#include "simulator.h"
|
||||||
#include "simulatordialog.h"
|
#include "simulatormainwindow.h"
|
||||||
#include "simulatorstartupdialog.h"
|
#include "simulatorstartupdialog.h"
|
||||||
#include "storage.h"
|
#include "storage.h"
|
||||||
#include "qxtcommandoptions.h"
|
#include "qxtcommandoptions.h"
|
||||||
|
#include "version.h"
|
||||||
|
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
@ -50,21 +52,6 @@
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef __APPLE__
|
|
||||||
#include <QProxyStyle>
|
|
||||||
|
|
||||||
class MyProxyStyle : public QProxyStyle
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
void polish ( QWidget * w ) {
|
|
||||||
QMenu* mn = dynamic_cast<QMenu*>(w);
|
|
||||||
QPushButton* pb = dynamic_cast<QPushButton*>(w);
|
|
||||||
if(!(mn || pb) && !w->testAttribute(Qt::WA_MacNormalSize))
|
|
||||||
w->setAttribute(Qt::WA_MacSmallSize);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
using namespace Simulator;
|
using namespace Simulator;
|
||||||
|
|
||||||
int finish(int exitCode);
|
int finish(int exitCode);
|
||||||
|
@ -126,19 +113,12 @@ int main(int argc, char *argv[])
|
||||||
|
|
||||||
g.init();
|
g.init();
|
||||||
|
|
||||||
#ifdef __APPLE__
|
QTranslator companionTranslator;
|
||||||
app.setStyle(new MyProxyStyle);
|
companionTranslator.load(":/companion_" + g.locale());
|
||||||
#endif
|
|
||||||
|
|
||||||
/* QTranslator companionTranslator;
|
|
||||||
companionTranslator.load(":/companion_" + locale);
|
|
||||||
QTranslator qtTranslator;
|
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(&companionTranslator);
|
||||||
app.installTranslator(&qtTranslator);
|
app.installTranslator(&qtTranslator);
|
||||||
*/
|
|
||||||
|
|
||||||
// QTextCodec::setCodecForCStrings(QTextCodec::codecForName("UTF-8"));
|
|
||||||
|
|
||||||
#if defined(JOYSTICKS) || defined(SIMU_AUDIO)
|
#if defined(JOYSTICKS) || defined(SIMU_AUDIO)
|
||||||
uint32_t sdlFlags = 0;
|
uint32_t sdlFlags = 0;
|
||||||
|
@ -269,23 +249,20 @@ int main(int argc, char *argv[])
|
||||||
|
|
||||||
current_firmware_variant = getFirmware(simOptions.firmwareId);
|
current_firmware_variant = getFirmware(simOptions.firmwareId);
|
||||||
|
|
||||||
int oldProfId = g.id();
|
g.sessionId(profileId);
|
||||||
g.id(profileId);
|
|
||||||
g.simuLastProfId(profileId);
|
g.simuLastProfId(profileId);
|
||||||
|
|
||||||
int result = 1;
|
int result = 1;
|
||||||
SimulatorDialog * dialog = new SimulatorDialog(NULL, simulator, SIMULATOR_FLAGS_STANDALONE);
|
SimulatorMainWindow * mainWindow = new SimulatorMainWindow(NULL, simulator, SIMULATOR_FLAGS_STANDALONE);
|
||||||
dialog->setRadioProfileId(profileId);
|
if (mainWindow->setOptions(simOptions, true)) {
|
||||||
if (dialog->setOptions(simOptions, true)) {
|
mainWindow->start();
|
||||||
dialog->start();
|
mainWindow->show();
|
||||||
dialog->show();
|
|
||||||
result = app.exec();
|
result = app.exec();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
result = 3;
|
result = 3;
|
||||||
}
|
}
|
||||||
g.id(oldProfId);
|
delete mainWindow;
|
||||||
delete dialog;
|
|
||||||
delete simulator;
|
delete simulator;
|
||||||
|
|
||||||
return finish(result);
|
return finish(result);
|
||||||
|
|
|
@ -428,7 +428,9 @@ QString Profile::groupId()
|
||||||
// ** AppData class********************
|
// ** AppData class********************
|
||||||
|
|
||||||
// Get declarations
|
// Get declarations
|
||||||
QStringList AppData::recentFiles() { return _recentFiles; }
|
QStringList AppData::recentFiles() { return _recentFiles; }
|
||||||
|
QStringList AppData::simuDbgFilters() { return _simuDbgFilters; }
|
||||||
|
|
||||||
QByteArray AppData::mainWinGeo() { return _mainWinGeo; }
|
QByteArray AppData::mainWinGeo() { return _mainWinGeo; }
|
||||||
QByteArray AppData::mainWinState() { return _mainWinState; }
|
QByteArray AppData::mainWinState() { return _mainWinState; }
|
||||||
QByteArray AppData::modelEditGeo() { return _modelEditGeo; }
|
QByteArray AppData::modelEditGeo() { return _modelEditGeo; }
|
||||||
|
@ -475,9 +477,12 @@ int AppData::id() { return _id; }
|
||||||
int AppData::theme() { return _theme; }
|
int AppData::theme() { return _theme; }
|
||||||
int AppData::warningId() { return _warningId; }
|
int AppData::warningId() { return _warningId; }
|
||||||
int AppData::simuLastProfId() { return _simuLastProfId; }
|
int AppData::simuLastProfId() { return _simuLastProfId; }
|
||||||
|
int AppData::sessionId() { return _sessionId; }
|
||||||
|
|
||||||
// Set declarations
|
// Set declarations
|
||||||
void AppData::recentFiles (const QStringList x) { store(x, _recentFiles, "recentFileList" );}
|
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::mainWinGeo (const QByteArray x) { store(x, _mainWinGeo, "mainWindowGeometry" );}
|
||||||
void AppData::mainWinState (const QByteArray x) { store(x, _mainWinState, "mainWindowState" );}
|
void AppData::mainWinState (const QByteArray x) { store(x, _mainWinState, "mainWindowState" );}
|
||||||
void AppData::modelEditGeo (const QByteArray x) { store(x, _modelEditGeo, "modelEditGeometry" );}
|
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::iconSize (const int x) { store(x, _iconSize, "icon_size" );}
|
||||||
void AppData::historySize (const int x) { store(x, _historySize, "history_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::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::theme (const int x) { store(x, _theme, "theme" );}
|
||||||
void AppData::warningId (const int x) { store(x, _warningId, "warningId" );}
|
void AppData::warningId (const int x) { store(x, _warningId, "warningId" );}
|
||||||
void AppData::simuLastProfId (const int x) { store(x, _simuLastProfId, "simuLastProfId" );}
|
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
|
// Constructor
|
||||||
AppData::AppData()
|
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( _tempString, "settings_version" ,"220" ); // This is a version marker. Will be used to upgrade the settings later on.
|
||||||
|
|
||||||
getset( _recentFiles, "recentFileList" ,"" );
|
getset( _recentFiles, "recentFileList" ,"" );
|
||||||
|
getset( _simuDbgFilters, "simuDbgFilters" ,"" );
|
||||||
|
|
||||||
getset( _mainWinGeo, "mainWindowGeometry" ,"" );
|
getset( _mainWinGeo, "mainWindowGeometry" ,"" );
|
||||||
getset( _mainWinState, "mainWindowState" ,"" );
|
getset( _mainWinState, "mainWindowState" ,"" );
|
||||||
getset( _modelEditGeo, "modelEditGeometry" ,"" );
|
getset( _modelEditGeo, "modelEditGeometry" ,"" );
|
||||||
|
@ -722,6 +737,7 @@ void AppData::init()
|
||||||
getset( _warningId, "warningId" ,0 );
|
getset( _warningId, "warningId" ,0 );
|
||||||
getset( _simuLastProfId, "simuLastProfId" ,-1 );
|
getset( _simuLastProfId, "simuLastProfId" ,-1 );
|
||||||
|
|
||||||
|
sessionId(id());
|
||||||
}
|
}
|
||||||
|
|
||||||
QMap<int, QString> AppData::getActiveProfiles()
|
QMap<int, QString> AppData::getActiveProfiles()
|
||||||
|
|
|
@ -250,6 +250,8 @@ class AppData: protected CompStoreObj
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QStringList _recentFiles;
|
QStringList _recentFiles;
|
||||||
|
QStringList _simuDbgFilters;
|
||||||
|
|
||||||
QByteArray _mainWinGeo;
|
QByteArray _mainWinGeo;
|
||||||
QByteArray _mainWinState;
|
QByteArray _mainWinState;
|
||||||
QByteArray _modelEditGeo;
|
QByteArray _modelEditGeo;
|
||||||
|
@ -296,10 +298,14 @@ class AppData: protected CompStoreObj
|
||||||
int _theme;
|
int _theme;
|
||||||
int _warningId;
|
int _warningId;
|
||||||
int _simuLastProfId;
|
int _simuLastProfId;
|
||||||
|
// currently loaded radio profile ID, NOT saved to persistent storage
|
||||||
|
int _sessionId;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// All the get definitions
|
// All the get definitions
|
||||||
QStringList recentFiles();
|
QStringList recentFiles();
|
||||||
|
QStringList simuDbgFilters();
|
||||||
|
|
||||||
QByteArray mainWinGeo();
|
QByteArray mainWinGeo();
|
||||||
QByteArray mainWinState();
|
QByteArray mainWinState();
|
||||||
QByteArray modelEditGeo();
|
QByteArray modelEditGeo();
|
||||||
|
@ -347,9 +353,12 @@ class AppData: protected CompStoreObj
|
||||||
int theme();
|
int theme();
|
||||||
int warningId();
|
int warningId();
|
||||||
int simuLastProfId();
|
int simuLastProfId();
|
||||||
|
int sessionId();
|
||||||
|
|
||||||
// All the set definitions
|
// All the set definitions
|
||||||
void recentFiles (const QStringList x);
|
void recentFiles (const QStringList x);
|
||||||
|
void simuDbgFilters (const QStringList x);
|
||||||
|
|
||||||
void mainWinGeo (const QByteArray);
|
void mainWinGeo (const QByteArray);
|
||||||
void mainWinState (const QByteArray);
|
void mainWinState (const QByteArray);
|
||||||
void modelEditGeo (const QByteArray);
|
void modelEditGeo (const QByteArray);
|
||||||
|
@ -398,6 +407,7 @@ class AppData: protected CompStoreObj
|
||||||
void theme (const int);
|
void theme (const int);
|
||||||
void warningId (const int);
|
void warningId (const int);
|
||||||
void simuLastProfId (const int);
|
void simuLastProfId (const int);
|
||||||
|
void sessionId (const int);
|
||||||
|
|
||||||
// Constructor
|
// Constructor
|
||||||
AppData();
|
AppData();
|
||||||
|
|
31
companion/src/themes/default/style-osx.css
Normal file
|
@ -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));
|
||||||
|
}
|
77
companion/src/themes/default/style.css
Normal file
|
@ -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;
|
||||||
|
}
|
|
@ -123,6 +123,7 @@ Section "OpenTX Companion" SecDummy
|
||||||
File "@QT_DLL_DIR@\Qt5PrintSupport.dll"
|
File "@QT_DLL_DIR@\Qt5PrintSupport.dll"
|
||||||
File "@QT_DLL_DIR@\Qt5Network.dll"
|
File "@QT_DLL_DIR@\Qt5Network.dll"
|
||||||
File "@QT_DLL_DIR@\Qt5Multimedia.dll"
|
File "@QT_DLL_DIR@\Qt5Multimedia.dll"
|
||||||
|
File "@QT_DLL_DIR@\Qt5Svg.dll"
|
||||||
File "@QT_DLL_DIR@\Qt5Xml.dll"
|
File "@QT_DLL_DIR@\Qt5Xml.dll"
|
||||||
|
|
||||||
File "@SDL_DIR@\SDL.dll"
|
File "@SDL_DIR@\SDL.dll"
|
||||||
|
@ -137,6 +138,7 @@ Section "OpenTX Companion" SecDummy
|
||||||
|
|
||||||
SetOutPath "$INSTDIR\imageformats"
|
SetOutPath "$INSTDIR\imageformats"
|
||||||
File "@QT_DLL_DIR@\..\plugins\imageformats\qjpeg.dll"
|
File "@QT_DLL_DIR@\..\plugins\imageformats\qjpeg.dll"
|
||||||
|
File "@QT_DLL_DIR@\..\plugins\imageformats\qsvg.dll"
|
||||||
|
|
||||||
SetOutPath "$INSTDIR\mediaservice"
|
SetOutPath "$INSTDIR\mediaservice"
|
||||||
File "@QT_DLL_DIR@\..\plugins\mediaservice\dsengine.dll"
|
File "@QT_DLL_DIR@\..\plugins\mediaservice\dsengine.dll"
|
||||||
|
|
|
@ -18,6 +18,7 @@ RUN apt-get update && \
|
||||||
qtmultimedia5-dev \
|
qtmultimedia5-dev \
|
||||||
qttools5-dev \
|
qttools5-dev \
|
||||||
qttools5-dev-tools \
|
qttools5-dev-tools \
|
||||||
|
libqt5svg5-dev \
|
||||||
software-properties-common \
|
software-properties-common \
|
||||||
wget \
|
wget \
|
||||||
zip \
|
zip \
|
||||||
|
|