[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
|
||||
# - mv gcc-arm-none-eabi-4_7-2013q3 /opt/gcc-arm-none-eabi
|
||||
fi
|
||||
- sudo apt-get install -qq qt${QT_BASE}base qt${QT_BASE}multimedia qt${QT_BASE}tools; source /opt/qt${QT_BASE}/bin/qt${QT_BASE}-env.sh
|
||||
- sudo apt-get install -qq qt${QT_BASE}base qt${QT_BASE}multimedia qt${QT_BASE}svg qt${QT_BASE}tools; source /opt/qt${QT_BASE}/bin/qt${QT_BASE}-env.sh
|
||||
|
||||
script:
|
||||
- ./tools/commit-tests.sh
|
||||
|
|
|
@ -49,8 +49,6 @@ endif()
|
|||
if(SDL_FOUND)
|
||||
include_directories(${SDL_INCLUDE_DIR})
|
||||
add_definitions(-DJOYSTICKS)
|
||||
else()
|
||||
remove_definitions(-DSIMU_AUDIO)
|
||||
endif()
|
||||
|
||||
add_definitions(-DSIMU)
|
||||
|
@ -250,8 +248,6 @@ qt5_add_translation(companion_QM ${companion_TS})
|
|||
qt5_add_resources(companion_RCC ${companion_RESOURCES})
|
||||
add_custom_target(gen_qrc DEPENDS ${companion_RCC})
|
||||
|
||||
add_definitions(-DQT_TRANSLATIONS_DIR="${QT_TRANSLATIONS_DIR}")
|
||||
|
||||
add_executable(${COMPANION_NAME} MACOSX_BUNDLE ${WIN_EXECUTABLE_TYPE} ${companion_SRCS} ${companion_RCC} ${companion_QM})
|
||||
|
||||
add_dependencies(${COMPANION_NAME} gen_qrc)
|
||||
|
@ -282,9 +278,7 @@ if(WIN32)
|
|||
endif()
|
||||
|
||||
add_executable(${SIMULATOR_NAME} MACOSX_BUNDLE ${WIN_EXECUTABLE_TYPE} ${simu_SRCS} ${companion_RCC})
|
||||
|
||||
add_dependencies(${SIMULATOR_NAME} gen_qrc)
|
||||
qt5_use_modules(${SIMULATOR_NAME} Core Widgets Multimedia)
|
||||
|
||||
target_link_libraries(${SIMULATOR_NAME} PRIVATE simulation common shared storage qxtcommandoptions ${PTHREAD_LIBRARY} ${SDL_LIBRARY} ${WIN_LINK_LIBRARIES})
|
||||
|
||||
|
@ -343,7 +337,7 @@ elseif(WIN32)
|
|||
|
||||
get_target_property(QtCore_LOCATION Qt5::Core LOCATION)
|
||||
get_filename_component(QT_DLL_DIR ${QtCore_LOCATION} PATH)
|
||||
set(INSTALL_TEMP_QTDLL_FILES Qt5Core Qt5Gui Qt5Widgets Qt5Xml Qt5Network Qt5PrintSupport Qt5Multimedia)
|
||||
set(INSTALL_TEMP_QTDLL_FILES Qt5Core Qt5Gui Qt5Widgets Qt5Xml Qt5Network Qt5PrintSupport Qt5Multimedia Qt5Svg)
|
||||
set(INSTALL_TEMP_ICUDLL_FILES icudt54.dll icuin54.dll icuuc54.dll)
|
||||
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
set(INSTALL_TEMP_QTDLL_SFX "d")
|
||||
|
|
|
@ -12,8 +12,26 @@
|
|||
<file>images/track.png</file>
|
||||
<file>images/track0.png</file>
|
||||
<file>images/taranison.png</file>
|
||||
<file>images/simulator/icons/8/lock-locked.png</file>
|
||||
<file>images/simulator/icons/8/lock-unlocked.png</file>
|
||||
<file>images/simulator/icons/svg/camera.svg</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/left.png</file>
|
||||
<file>images/simulator/Horus/right.png</file>
|
||||
|
@ -180,6 +198,8 @@
|
|||
<file>images/library/10702.png</file>
|
||||
<file>images/library/10801.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/open.png</file>
|
||||
<file>themes/monochrome/16/edit.png</file>
|
||||
|
|
|
@ -1120,23 +1120,23 @@ GeneralSettings::GeneralSettings()
|
|||
strcpy(bluetoothName, "Taranis");
|
||||
}
|
||||
|
||||
templateSetup = g.profile[g.id()].channelOrder();
|
||||
stickMode = g.profile[g.id()].defaultMode();
|
||||
templateSetup = g.profile[g.sessionId()].channelOrder();
|
||||
stickMode = g.profile[g.sessionId()].defaultMode();
|
||||
|
||||
QString t_calib = g.profile[g.id()].stickPotCalib();
|
||||
QString t_calib = g.profile[g.sessionId()].stickPotCalib();
|
||||
int potsnum = getCurrentFirmware()->getCapability(Pots);
|
||||
if (!t_calib.isEmpty()) {
|
||||
QString t_trainercalib=g.profile[g.id()].trainerCalib();
|
||||
int8_t t_txVoltageCalibration=(int8_t)g.profile[g.id()].txVoltageCalibration();
|
||||
int8_t t_txCurrentCalibration=(int8_t)g.profile[g.id()].txCurrentCalibration();
|
||||
int8_t t_PPM_Multiplier=(int8_t)g.profile[g.id()].ppmMultiplier();
|
||||
uint8_t t_stickMode=(uint8_t)g.profile[g.id()].gsStickMode();
|
||||
uint8_t t_vBatWarn=(uint8_t)g.profile[g.id()].vBatWarn();
|
||||
QString t_DisplaySet=g.profile[g.id()].display();
|
||||
QString t_BeeperSet=g.profile[g.id()].beeper();
|
||||
QString t_HapticSet=g.profile[g.id()].haptic();
|
||||
QString t_SpeakerSet=g.profile[g.id()].speaker();
|
||||
QString t_CountrySet=g.profile[g.id()].countryCode();
|
||||
QString t_trainercalib=g.profile[g.sessionId()].trainerCalib();
|
||||
int8_t t_txVoltageCalibration=(int8_t)g.profile[g.sessionId()].txVoltageCalibration();
|
||||
int8_t t_txCurrentCalibration=(int8_t)g.profile[g.sessionId()].txCurrentCalibration();
|
||||
int8_t t_PPM_Multiplier=(int8_t)g.profile[g.sessionId()].ppmMultiplier();
|
||||
uint8_t t_stickMode=(uint8_t)g.profile[g.sessionId()].gsStickMode();
|
||||
uint8_t t_vBatWarn=(uint8_t)g.profile[g.sessionId()].vBatWarn();
|
||||
QString t_DisplaySet=g.profile[g.sessionId()].display();
|
||||
QString t_BeeperSet=g.profile[g.sessionId()].beeper();
|
||||
QString t_HapticSet=g.profile[g.sessionId()].haptic();
|
||||
QString t_SpeakerSet=g.profile[g.sessionId()].speaker();
|
||||
QString t_CountrySet=g.profile[g.sessionId()].countryCode();
|
||||
|
||||
if ((t_calib.length()==(CPN_MAX_STICKS+potsnum)*12) && (t_trainercalib.length()==16)) {
|
||||
QString Byte;
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
#include "appdata.h"
|
||||
#include "helpers.h"
|
||||
#include "modeledit/modeledit.h"
|
||||
#include "simulatordialog.h"
|
||||
#include "simulatormainwindow.h"
|
||||
#include "storage/sdcard.h"
|
||||
|
||||
Stopwatch gStopwatch("global");
|
||||
|
@ -823,7 +823,7 @@ void startSimulation(QWidget * parent, RadioData & radioData, int modelIdx)
|
|||
simuData->setCurrentModel(modelIdx);
|
||||
}
|
||||
|
||||
SimulatorDialog * dialog = new SimulatorDialog(parent, simulator, flags);
|
||||
SimulatorMainWindow * dialog = new SimulatorMainWindow(parent, simulator, flags);
|
||||
if (IS_HORUS(getCurrentBoard()) && !dialog->useTempDataPath(true)) {
|
||||
QMessageBox::critical(NULL, QObject::tr("Data Load Error"), QObject::tr("Error: Could not create temporary directory in '%1'").arg(QDir::tempPath()));
|
||||
delete dialog;
|
||||
|
@ -831,12 +831,15 @@ void startSimulation(QWidget * parent, RadioData & radioData, int modelIdx)
|
|||
return;
|
||||
}
|
||||
dialog->setRadioData(simuData);
|
||||
qDebug() << __FILE__ << __LINE__ << "Starting" << getCurrentFirmware()->getName() << "simulation with SD path" << dialog->getSdPath() << "and models/settings path" << dialog->getDataPath();
|
||||
dialog->setWindowModality(Qt::ApplicationModal);
|
||||
dialog->setAttribute(Qt::WA_DeleteOnClose);
|
||||
dialog->start();
|
||||
dialog->exec();
|
||||
delete dialog;
|
||||
// TODO Horus tmp directory is deleted on simulator close OR we could use it to get back data from the simulation
|
||||
delete simuData; // TODO same with simuData, could read it back and update the file data
|
||||
dialog->show();
|
||||
|
||||
QObject::connect(dialog, &SimulatorMainWindow::destroyed, [simuData] (void) {
|
||||
// TODO simuData and Horus tmp directory is deleted on simulator close OR we could use it to get back data from the simulation
|
||||
delete simuData;
|
||||
});
|
||||
}
|
||||
else {
|
||||
QMessageBox::warning(NULL,
|
||||
|
|
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
|
||||
debugoutput.cpp
|
||||
radiooutputswidget.cpp
|
||||
simulatordialog.cpp
|
||||
simulatorinterface.cpp
|
||||
simulateduiwidget.cpp
|
||||
simulateduiwidget9X.cpp
|
||||
simulateduiwidgetX7.cpp
|
||||
simulateduiwidgetX9.cpp
|
||||
simulateduiwidgetX12.cpp
|
||||
simulatorinterface.cpp
|
||||
simulatormainwindow.cpp
|
||||
simulatorstartupdialog.cpp
|
||||
telemetrysimu.cpp
|
||||
trainersimu.cpp
|
||||
|
@ -16,11 +18,13 @@ set(simulation_SRCS
|
|||
|
||||
set(simulation_UIS
|
||||
debugoutput.ui
|
||||
radiooutputswidget.ui
|
||||
simulatordialog.ui
|
||||
simulateduiwidget9X.ui
|
||||
simulateduiwidgetX7.ui
|
||||
simulateduiwidgetX9.ui
|
||||
simulateduiwidgetX12.ui
|
||||
simulatormainwindow.ui
|
||||
simulatorstartupdialog.ui
|
||||
telemetrysimu.ui
|
||||
trainersimu.ui
|
||||
|
@ -28,10 +32,12 @@ set(simulation_UIS
|
|||
|
||||
set(simulation_HDRS
|
||||
debugoutput.h
|
||||
radiooutputswidget.h
|
||||
radiouiaction.h
|
||||
simulateduiwidget.h
|
||||
# simulator.h
|
||||
simulatordialog.h
|
||||
simulatormainwindow.h
|
||||
simulatorstartupdialog.h
|
||||
telemetrysimu.h
|
||||
trainersimu.h
|
||||
|
@ -77,4 +83,4 @@ qt5_wrap_ui(simulation_SRCS ${simulation_UIS})
|
|||
qt5_wrap_cpp(simulation_SRCS ${simulation_HDRS})
|
||||
|
||||
add_library(simulation ${simulation_SRCS} ${simulation_HDRS})
|
||||
qt5_use_modules(simulation Widgets Xml)
|
||||
qt5_use_modules(simulation Core Widgets Svg)
|
||||
|
|
|
@ -21,40 +21,361 @@
|
|||
#include "debugoutput.h"
|
||||
#include "ui_debugoutput.h"
|
||||
|
||||
DebugOutput::DebugOutput(QWidget * parent):
|
||||
QDialog(parent),
|
||||
ui(new Ui::DebugOutput)
|
||||
#include "appdata.h"
|
||||
|
||||
#include <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);
|
||||
|
||||
#ifdef __APPLE__
|
||||
QFont newFont("Courier", 13);
|
||||
ui->Output->setFont(newFont);
|
||||
ui->Output->setAttribute(Qt::WA_MacNormalSize);
|
||||
#endif
|
||||
#if defined WIN32 || !defined __GNUC__
|
||||
QFont newFont("Courier", 9);
|
||||
ui->Output->setFont(newFont);
|
||||
ui->console->setFont(newFont);
|
||||
#endif
|
||||
|
||||
// TODO : allow selecting multiple filters, but needs to be efficient at output stage
|
||||
|
||||
QStringList stockFilters;
|
||||
stockFilters << "^lua[A-Z].*";
|
||||
stockFilters << "/(error|warning|-(E|W)-)/i";
|
||||
stockFilters << "!^(GC Use|(play|load|write|find(True)?)File|convert(To|From)Simu|\\tfound( in map)?:|eeprom |f_[a-z]+\\(|(push|(p|P)op(up)?|chain)? ?Menu( .+ display)?|RamBackup).+$";
|
||||
|
||||
foreach (const QString & fltr, stockFilters)
|
||||
ui->filterText->addItem(fltr, "no_delete");
|
||||
|
||||
ui->filterText->setValidator(new DebugOutputFilterValidator(ui->filterText));
|
||||
ui->filterText->installEventFilter(new DeleteComboBoxItemEventFilter());
|
||||
|
||||
ui->actionShowFilterHelp->setIcon(SimulatorIcon("info"));
|
||||
ui->actionWordWrap->setIcon(SimulatorIcon("word_wrap"));
|
||||
ui->actionClearScr->setIcon(SimulatorIcon("eraser"));
|
||||
|
||||
ui->btnShowFilterHelp->setDefaultAction(ui->actionShowFilterHelp);
|
||||
ui->btnWordWrap->setDefaultAction(ui->actionWordWrap);
|
||||
ui->btnClearScr->setDefaultAction(ui->actionClearScr);
|
||||
|
||||
restoreState();
|
||||
|
||||
ui->bufferSize->setValue(ui->console->maximumBlockCount());
|
||||
|
||||
// install simulator TRACE hook
|
||||
traceCallbackInstance = this;
|
||||
m_simulator->installTraceHook(traceCb);
|
||||
|
||||
m_tmrDataPrint->setInterval(m_dataPrintFreq);
|
||||
|
||||
connect(ui->filterText, &QComboBox::currentTextChanged, this, &DebugOutput::onFilterTextChanged);
|
||||
connect(m_tmrDataPrint, &QTimer::timeout, this, &DebugOutput::processBytesReceived);
|
||||
}
|
||||
|
||||
DebugOutput::~DebugOutput()
|
||||
{
|
||||
traceCallbackInstance = 0;
|
||||
stop();
|
||||
saveState();
|
||||
if (m_tmrDataPrint)
|
||||
delete m_tmrDataPrint;
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void DebugOutput::traceCallback(const QString & text)
|
||||
void DebugOutput::start()
|
||||
{
|
||||
// ui->Output->appendPlainText(text);
|
||||
QTextCursor cursor(ui->Output->textCursor());
|
||||
m_tmrDataPrint->start();
|
||||
m_running = true;
|
||||
}
|
||||
|
||||
// is the scrollbar at the end?
|
||||
bool atEnd = (ui->Output->verticalScrollBar()->value() == ui->Output->verticalScrollBar()->maximum());
|
||||
void DebugOutput::stop()
|
||||
{
|
||||
m_tmrDataPrint->stop();
|
||||
m_running = false;
|
||||
}
|
||||
|
||||
cursor.movePosition(QTextCursor::End, QTextCursor::MoveAnchor, 1);
|
||||
cursor.insertText(text);
|
||||
void DebugOutput::saveState()
|
||||
{
|
||||
QStringList filters;
|
||||
for (int i = 0; i < ui->filterText->count(); ++i) {
|
||||
if (!ui->filterText->itemText(i).isEmpty() && ui->filterText->itemData(i).toString() != "no_delete")
|
||||
filters << ui->filterText->itemText(i);
|
||||
}
|
||||
g.simuDbgFilters(filters);
|
||||
|
||||
if (atEnd) {
|
||||
ui->Output->verticalScrollBar()->triggerAction(QAbstractSlider::SliderToMaximum);
|
||||
QByteArray state;
|
||||
QDataStream stream(&state, QIODevice::WriteOnly);
|
||||
stream << m_savedViewStateVersion
|
||||
<< (qint16)ui->filterText->currentIndex() << (qint32)ui->console->maximumBlockCount()
|
||||
<< ui->btnFilter->isChecked() << ui->actionWordWrap->isChecked();
|
||||
|
||||
SimulatorOptions opts = g.profile[m_radioProfileId].simulatorOptions();
|
||||
opts.dbgConsoleState = state;
|
||||
g.profile[m_radioProfileId].simulatorOptions(opts);
|
||||
}
|
||||
|
||||
void DebugOutput::restoreState()
|
||||
{
|
||||
quint16 ver = 0;
|
||||
qint16 fci = -1;
|
||||
qint32 mbc = 10000;
|
||||
bool flten = false, wwen = false;
|
||||
QByteArray state = g.profile[m_radioProfileId].simulatorOptions().dbgConsoleState;
|
||||
QDataStream stream(state);
|
||||
|
||||
stream >> ver;
|
||||
if (ver && ver <= m_savedViewStateVersion)
|
||||
stream >> fci >> mbc >> flten >> wwen;
|
||||
|
||||
ui->filterText->insertItems(0, g.simuDbgFilters());
|
||||
ui->filterText->setCurrentIndex(fci);
|
||||
ui->btnFilter->setChecked(flten);
|
||||
ui->console->setMaximumBlockCount(mbc);
|
||||
ui->actionWordWrap->setChecked(wwen);
|
||||
onFilterTextEdited();
|
||||
}
|
||||
|
||||
void DebugOutput::traceCallback(const char * text)
|
||||
{
|
||||
const static QRegExp blank("^[\\r\\n]+$");
|
||||
bool isBlank;
|
||||
|
||||
if (!m_running)
|
||||
return;
|
||||
|
||||
QString line(text);
|
||||
isBlank = line.contains(blank);
|
||||
|
||||
m_mtxDataBuffer.lock();
|
||||
if (isBlank && m_dataBuffer.size())
|
||||
m_dataBuffer[m_dataBuffer.size()-1] += line;
|
||||
else
|
||||
m_dataBuffer.append(text);
|
||||
if (m_dataBuffer.size() > m_dataBufferMaxSize) {
|
||||
m_dataBuffer.removeFirst();
|
||||
qDebug() << __FILE__ << __LINE__ << "Line buffer overflow! size >" << m_dataBufferMaxSize;
|
||||
}
|
||||
m_mtxDataBuffer.unlock();
|
||||
}
|
||||
|
||||
void DebugOutput::processBytesReceived()
|
||||
{
|
||||
QString text;
|
||||
bool fltMatch;
|
||||
const QTextCursor savedCursor(ui->console->textCursor());
|
||||
const int sbValue = ui->console->verticalScrollBar()->value();
|
||||
const bool sbAtBottom = (sbValue == ui->console->verticalScrollBar()->maximum());
|
||||
|
||||
m_tmrDataPrint->stop();
|
||||
while (m_dataBuffer.size() > 1) {
|
||||
m_mtxDataBuffer.lock();
|
||||
text = m_dataBuffer.takeFirst();
|
||||
m_mtxDataBuffer.unlock();
|
||||
// filter
|
||||
if (ui->btnFilter->isChecked()) {
|
||||
fltMatch = text.contains(m_filterRegEx);
|
||||
if ((m_filterExclude && fltMatch) || (!m_filterExclude && !fltMatch)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
ui->console->moveCursor(QTextCursor::End);
|
||||
ui->console->textCursor().insertText(text);
|
||||
if (sbAtBottom) {
|
||||
ui->console->moveCursor(QTextCursor::End);
|
||||
ui->console->verticalScrollBar()->setValue(ui->console->verticalScrollBar()->maximum());
|
||||
}
|
||||
else {
|
||||
ui->console->setTextCursor(savedCursor);
|
||||
ui->console->verticalScrollBar()->setValue(sbValue);
|
||||
}
|
||||
QCoreApplication::processEvents();
|
||||
}
|
||||
m_tmrDataPrint->start();
|
||||
}
|
||||
|
||||
/*
|
||||
* UI handlers
|
||||
*/
|
||||
|
||||
void DebugOutput::onFilterTextEdited()
|
||||
{
|
||||
const QString fText = ui->filterText->currentText();
|
||||
if (fText.isEmpty()) {
|
||||
ui->btnFilter->setChecked(false);
|
||||
m_filterRegEx = QRegularExpression();
|
||||
return;
|
||||
}
|
||||
|
||||
m_filterRegEx = makeRegEx(fText, &m_filterExclude);
|
||||
|
||||
if (m_filterRegEx.isValid()) {
|
||||
//ui->btnFilter->setChecked(true);
|
||||
ui->filterText->setStyleSheet("");
|
||||
}
|
||||
else {
|
||||
ui->btnFilter->setChecked(false);
|
||||
m_filterRegEx = QRegularExpression();
|
||||
ui->filterText->setStyleSheet("background-color: rgba(255, 205, 185, 200);");
|
||||
}
|
||||
}
|
||||
|
||||
void DebugOutput::onFilterTextChanged(const QString &)
|
||||
{
|
||||
onFilterTextEdited();
|
||||
}
|
||||
|
||||
void DebugOutput::on_bufferSize_editingFinished()
|
||||
{
|
||||
ui->console->setMaximumBlockCount(ui->bufferSize->value());
|
||||
}
|
||||
|
||||
void DebugOutput::on_actionWordWrap_toggled(bool checked)
|
||||
{
|
||||
ui->console->setLineWrapMode(checked ? QPlainTextEdit::WidgetWidth : QPlainTextEdit::NoWrap);
|
||||
}
|
||||
|
||||
void DebugOutput::on_actionClearScr_triggered()
|
||||
{
|
||||
ui->console->clear();
|
||||
}
|
||||
|
||||
void DebugOutput::on_actionShowFilterHelp_triggered()
|
||||
{
|
||||
// TODO : find some place better for this.
|
||||
QString help = \
|
||||
"<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_
|
||||
#define _DEBUGOUTPUT_H_
|
||||
|
||||
#include <QtWidgets>
|
||||
#include "simulator.h"
|
||||
#include "simulatorinterface.h"
|
||||
|
||||
#include <QMutex>
|
||||
#include <QTimer>
|
||||
#include <QValidator>
|
||||
#include <QWidget>
|
||||
|
||||
namespace Ui {
|
||||
class DebugOutput;
|
||||
}
|
||||
|
||||
class QAbstractButton;
|
||||
|
||||
class DebugOutput : public QDialog
|
||||
using namespace Simulator;
|
||||
|
||||
class DebugOutput : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit DebugOutput(QWidget * parent);
|
||||
explicit DebugOutput(QWidget * parent, SimulatorInterface * simulator);
|
||||
virtual ~DebugOutput();
|
||||
void traceCallback(const QString & text);
|
||||
void start();
|
||||
void stop();
|
||||
void traceCallback(const char * text);
|
||||
|
||||
static QRegularExpression makeRegEx(const QString & input, bool * isExlusive = NULL);
|
||||
|
||||
protected slots:
|
||||
void saveState();
|
||||
void restoreState();
|
||||
void processBytesReceived();
|
||||
void onFilterTextEdited();
|
||||
void onFilterTextChanged(const QString &);
|
||||
void on_bufferSize_editingFinished();
|
||||
void on_actionWordWrap_toggled(bool checked);
|
||||
void on_actionClearScr_triggered();
|
||||
void on_actionShowFilterHelp_triggered();
|
||||
|
||||
protected:
|
||||
|
||||
private:
|
||||
Ui::DebugOutput * ui;
|
||||
SimulatorInterface * m_simulator;
|
||||
QTimer * m_tmrDataPrint;
|
||||
QStringList m_dataBuffer;
|
||||
QMutex m_mtxDataBuffer;
|
||||
QRegularExpression m_filterRegEx;
|
||||
|
||||
private slots:
|
||||
int m_radioProfileId;
|
||||
int m_dataPrintFreq;
|
||||
bool m_running;
|
||||
bool m_filterExclude;
|
||||
|
||||
const static int m_dataBufferMaxSize;
|
||||
const static int m_dataPrintFreqDefault;
|
||||
const static quint16 m_savedViewStateVersion;
|
||||
};
|
||||
|
||||
class DebugOutputFilterValidator : public QValidator
|
||||
{
|
||||
public:
|
||||
DebugOutputFilterValidator(QObject *parent = Q_NULLPTR) : QValidator(parent) { }
|
||||
virtual State validate(QString & input, int &) const;
|
||||
};
|
||||
|
||||
class DeleteComboBoxItemEventFilter : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
protected:
|
||||
bool eventFilter(QObject *obj, QEvent *event);
|
||||
};
|
||||
|
||||
#endif // _DEBUGOUTPUT_H_
|
||||
|
|
|
@ -1,15 +1,21 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>DebugOutput</class>
|
||||
<widget class="QDialog" name="DebugOutput">
|
||||
<widget class="QWidget" name="DebugOutput">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>711</width>
|
||||
<height>470</height>
|
||||
<width>555</width>
|
||||
<height>733</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Debug Output</string>
|
||||
</property>
|
||||
|
@ -18,30 +24,286 @@
|
|||
<normaloff>:/icon.png</normaloff>:/icon.png</iconset>
|
||||
</property>
|
||||
<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">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QPlainTextEdit" name="Output">
|
||||
<property name="font">
|
||||
<font>
|
||||
<family>Courier New</family>
|
||||
<pointsize>10</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="verticalScrollBarPolicy">
|
||||
<enum>Qt::ScrollBarAlwaysOn</enum>
|
||||
</property>
|
||||
<property name="lineWrapMode">
|
||||
<enum>QPlainTextEdit::NoWrap</enum>
|
||||
</property>
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
<widget class="QWidget" name="widget" native="true">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<property name="spacing">
|
||||
<number>7</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="horizontalLayout">
|
||||
<property name="spacing">
|
||||
<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>
|
||||
</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>
|
||||
<resources>
|
||||
<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)) {
|
||||
emit triggered(m_hwIndex, active);
|
||||
if (active)
|
||||
if (active) {
|
||||
emit pushed(m_hwIndex);
|
||||
emit pushed();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -146,6 +148,7 @@ class RadioUiAction : public QObject
|
|||
void toggled(int index, bool active); // on programmatic or user interaction change
|
||||
void triggered(int index, bool active); // on user interaction change only
|
||||
void pushed(int index); // only emitted on user interaction && when 'active' is true
|
||||
void pushed();
|
||||
};
|
||||
|
||||
#endif // RADIOUIACTION_H
|
||||
|
|
|
@ -40,7 +40,7 @@ SimulatedUIWidget::SimulatedUIWidget(SimulatorInterface * simulator, SimulatorDi
|
|||
{
|
||||
m_rotEncClickAction = addRadioUiAction(-1, 0, tr("Rotary encoder click"));
|
||||
m_screenshotAction = addRadioUiAction(-1, Qt::Key_Print, tr("Take Screenshot"));
|
||||
connect(m_screenshotAction, &RadioUiAction::pushed, this, &SimulatedUIWidget::saveScreenshot);
|
||||
connect(m_screenshotAction, static_cast<void (RadioUiAction::*)(void)>(&RadioUiAction::pushed), this, &SimulatedUIWidget::captureScreenshot);
|
||||
}
|
||||
|
||||
SimulatedUIWidget::~SimulatedUIWidget()
|
||||
|
@ -114,9 +114,8 @@ void SimulatedUIWidget::updateUi()
|
|||
} */
|
||||
}
|
||||
|
||||
void SimulatedUIWidget::saveScreenshot(int idx)
|
||||
void SimulatedUIWidget::captureScreenshot()
|
||||
{
|
||||
Q_UNUSED(idx)
|
||||
QString fileName = "";
|
||||
if (!g.snapToClpbrd()) {
|
||||
QString path = g.snapshotDir();
|
||||
|
@ -124,7 +123,8 @@ void SimulatedUIWidget::saveScreenshot(int idx)
|
|||
path = "./";
|
||||
QDir dir(path);
|
||||
if (!dir.exists() || !dir.isReadable()) {
|
||||
m_simuDialog->traceCallback("SIMULATOR ERROR - Cannot open screenshot folder, check your settings.\n");
|
||||
// m_simulator->traceCallback("SIMULATOR ERROR - Cannot open screenshot folder, check your settings.\n");
|
||||
qDebug() << "SIMULATOR ERROR - Cannot open screenshot folder, check your settings.";
|
||||
return;
|
||||
}
|
||||
fileName += QString("%1/screenshot_%2.png").arg(dir.absolutePath(), QDateTime::currentDateTime().toString("yy-MM-dd_HH-mm-ss"));
|
||||
|
@ -180,12 +180,12 @@ void SimulatedUIWidget::setLcd(LcdWidget * lcd)
|
|||
|
||||
void SimulatedUIWidget::connectScrollActions()
|
||||
{
|
||||
connect(m_scrollUpAction, &RadioUiAction::pushed, [this](void) {
|
||||
connect(m_scrollUpAction, static_cast<void (RadioUiAction::*)(void)>(&RadioUiAction::pushed), [this](void) {
|
||||
this->simulatorWheelEvent(-1);
|
||||
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);
|
||||
m_scrollDnAction->toggle(false);
|
||||
});
|
||||
|
|
|
@ -64,8 +64,7 @@ class SimulatedUIWidget : public QWidget
|
|||
public slots:
|
||||
|
||||
void updateUi();
|
||||
void saveScreenshot(int idx = -1);
|
||||
void captureScreenshot() { saveScreenshot(); }
|
||||
void captureScreenshot();
|
||||
void simulatorWheelEvent(qint8 steps);
|
||||
|
||||
void wheelEvent(QWheelEvent *event);
|
||||
|
|
|
@ -24,16 +24,85 @@
|
|||
#include <QColor>
|
||||
#include <QDataStream>
|
||||
#include <QDebug>
|
||||
#include <QFile>
|
||||
#include <QIcon>
|
||||
#include <QPair>
|
||||
#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
|
||||
{
|
||||
|
@ -54,14 +123,18 @@ struct SimulatorOptions
|
|||
QString dataFile;
|
||||
QString dataFolder;
|
||||
QString sdPath;
|
||||
QByteArray windowGeometry;
|
||||
QByteArray windowGeometry; // SimulatorMainWindow geometry
|
||||
QList<QByteArray> controlsState; // saved switch/pot/stick settings
|
||||
QColor lcdColor;
|
||||
// added in v2
|
||||
QByteArray windowState; // SimulatorMainWindow dock/toolbar/options UI state
|
||||
QByteArray dbgConsoleState; // DebugOutput UI state
|
||||
QByteArray radioOutputsState; // RadioOutputsWidget UI state
|
||||
|
||||
friend QDataStream & operator << (QDataStream &out, const SimulatorOptions & o)
|
||||
{
|
||||
out << quint16(SIMULATOR_OPTIONS_VERSION) << o.startupDataType << o.firmwareId << o.dataFile << o.dataFolder
|
||||
<< o.sdPath << o.windowGeometry << o.controlsState << o.lcdColor;
|
||||
<< o.sdPath << o.windowGeometry << o.controlsState << o.lcdColor << o.windowState << o.dbgConsoleState << o.radioOutputsState;
|
||||
return out;
|
||||
}
|
||||
|
||||
|
@ -70,6 +143,8 @@ struct SimulatorOptions
|
|||
if (o._version <= SIMULATOR_OPTIONS_VERSION) {
|
||||
in >> o._version >> o.startupDataType >> o.firmwareId >> o.dataFile >> o.dataFolder
|
||||
>> o.sdPath >> o.windowGeometry >> o.controlsState >> o.lcdColor;
|
||||
if (o._version >= 2)
|
||||
in >> o.windowState >> o.dbgConsoleState >> o.radioOutputsState;
|
||||
}
|
||||
return in;
|
||||
}
|
||||
|
|
|
@ -22,7 +22,6 @@
|
|||
#include "ui_simulatordialog.h"
|
||||
|
||||
#include "appdata.h"
|
||||
#include "debugoutput.h"
|
||||
#include "radiofaderwidget.h"
|
||||
#include "radioknobwidget.h"
|
||||
#include "radioswitchwidget.h"
|
||||
|
@ -31,8 +30,6 @@
|
|||
#include "simulateduiwidget.h"
|
||||
#include "simulatorinterface.h"
|
||||
#include "storage.h"
|
||||
#include "telemetrysimu.h"
|
||||
#include "trainersimu.h"
|
||||
#include "virtualjoystickwidget.h"
|
||||
#ifdef JOYSTICKS
|
||||
#include "joystick.h"
|
||||
|
@ -43,18 +40,8 @@
|
|||
#include <QFile>
|
||||
#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):
|
||||
QDialog(parent),
|
||||
QWidget(parent),
|
||||
ui(new Ui::SimulatorDialog),
|
||||
simulator(simulator),
|
||||
firmware(getCurrentFirmware()),
|
||||
|
@ -63,12 +50,8 @@ SimulatorDialog::SimulatorDialog(QWidget * parent, SimulatorInterface *simulator
|
|||
radioUiWidget(NULL),
|
||||
vJoyLeft(NULL),
|
||||
vJoyRight(NULL),
|
||||
TelemetrySimu(NULL),
|
||||
TrainerSimu(NULL),
|
||||
DebugOut(NULL),
|
||||
m_board(getCurrentBoard()),
|
||||
flags(flags),
|
||||
radioProfileId(g.id()),
|
||||
lastPhase(-1),
|
||||
buttonPressed(0),
|
||||
trimPressed(TRIM_NONE),
|
||||
|
@ -78,40 +61,74 @@ SimulatorDialog::SimulatorDialog(QWidget * parent, SimulatorInterface *simulator
|
|||
middleButtonPressed(false),
|
||||
firstShow(true)
|
||||
{
|
||||
setWindowFlags(Qt::Window);
|
||||
|
||||
// install simulator TRACE hook
|
||||
traceCallbackInstance = this;
|
||||
simulator->installTraceHook(traceCb);
|
||||
|
||||
#ifdef JOYSTICKS
|
||||
joystick = NULL;
|
||||
#endif
|
||||
|
||||
// defaults
|
||||
setRadioProfileId(radioProfileId);
|
||||
setRadioProfileId(g.sessionId());
|
||||
setSdPath(g.profile[radioProfileId].sdPath());
|
||||
|
||||
setupUi();
|
||||
ui->setupUi(this);
|
||||
|
||||
windowName = tr("Radio Simulator (%1)").arg(firmware->getName());
|
||||
setWindowTitle(windowName);
|
||||
|
||||
switch(m_board) {
|
||||
case Board::BOARD_TARANIS_X7 :
|
||||
radioUiWidget = new SimulatedUIWidgetX7(simulator, this);
|
||||
break;
|
||||
case Board::BOARD_TARANIS_X9D :
|
||||
case Board::BOARD_TARANIS_X9DP :
|
||||
case Board::BOARD_TARANIS_X9E :
|
||||
radioUiWidget = new SimulatedUIWidgetX9(simulator, this);
|
||||
break;
|
||||
case Board::BOARD_X12S:
|
||||
case Board::BOARD_X10:
|
||||
radioUiWidget = new SimulatedUIWidgetX12(simulator, this);
|
||||
break;
|
||||
default:
|
||||
radioUiWidget = new SimulatedUIWidget9X(simulator, this);
|
||||
break;
|
||||
}
|
||||
|
||||
foreach (keymapHelp_t item, *radioUiWidget->getKeymapHelp())
|
||||
keymapHelp.append(item);
|
||||
|
||||
ui->radioUiWidget->layout()->removeItem(ui->radioUiTempSpacer);
|
||||
ui->radioUiWidget->layout()->addWidget(radioUiWidget);
|
||||
|
||||
vJoyLeft = new VirtualJoystickWidget(this, 'L');
|
||||
ui->leftStickLayout->addWidget(vJoyLeft);
|
||||
|
||||
vJoyRight = new VirtualJoystickWidget(this, 'R');
|
||||
ui->rightStickLayout->addWidget(vJoyRight);
|
||||
|
||||
connect(vJoyLeft, SIGNAL(trimButtonPressed(int)), this, SLOT(onTrimPressed(int)));
|
||||
connect(vJoyLeft, SIGNAL(trimButtonReleased()), this, SLOT(onTrimReleased()));
|
||||
connect(vJoyLeft, SIGNAL(trimSliderMoved(int,int)), this, SLOT(onTrimSliderMoved(int,int)));
|
||||
|
||||
connect(vJoyRight, SIGNAL(trimButtonPressed(int)), this, SLOT(onTrimPressed(int)));
|
||||
connect(vJoyRight, SIGNAL(trimButtonReleased()), this, SLOT(onTrimReleased()));
|
||||
connect(vJoyRight, SIGNAL(trimSliderMoved(int,int)), this, SLOT(onTrimSliderMoved(int,int)));
|
||||
}
|
||||
|
||||
SimulatorDialog::~SimulatorDialog()
|
||||
{
|
||||
traceCallbackInstance = 0;
|
||||
shutdown();
|
||||
|
||||
if (timer) {
|
||||
timer->stop();
|
||||
if (timer)
|
||||
timer->deleteLater();
|
||||
}
|
||||
if (radioUiWidget)
|
||||
radioUiWidget->deleteLater();
|
||||
delete radioUiWidget;
|
||||
if (vJoyLeft)
|
||||
vJoyLeft->deleteLater();
|
||||
delete vJoyLeft;
|
||||
if (vJoyRight)
|
||||
vJoyRight->deleteLater();
|
||||
delete vJoyRight;
|
||||
#ifdef JOYSTICKS
|
||||
if (joystick)
|
||||
joystick->deleteLater();
|
||||
delete joystick;
|
||||
#endif
|
||||
|
||||
firmware = NULL; // Not sure we should delete this but at least release our pointer.
|
||||
|
@ -125,13 +142,6 @@ SimulatorDialog::~SimulatorDialog()
|
|||
* Public slots/setters
|
||||
*/
|
||||
|
||||
void SimulatorDialog::setRadioProfileId(int value)
|
||||
{
|
||||
radioProfileId = value;
|
||||
if (simulator)
|
||||
simulator->setVolumeGain(g.profile[radioProfileId].volumeGain());
|
||||
}
|
||||
|
||||
void SimulatorDialog::setSdPath(const QString & sdPath)
|
||||
{
|
||||
setPaths(sdPath, radioDataPath);
|
||||
|
@ -355,25 +365,20 @@ void SimulatorDialog::deleteTempData()
|
|||
void SimulatorDialog::saveState()
|
||||
{
|
||||
SimulatorOptions opts = g.profile[radioProfileId].simulatorOptions();
|
||||
opts.windowGeometry = saveGeometry();
|
||||
//opts.windowGeometry = saveGeometry();
|
||||
opts.controlsState = saveRadioWidgetsState();
|
||||
g.profile[radioProfileId].simulatorOptions(opts);
|
||||
}
|
||||
|
||||
void SimulatorDialog::setUiAreaStyle(const QString & style)
|
||||
{
|
||||
ui->radioUiTab->setStyleSheet(style);
|
||||
ui->radioUiWidget->setStyleSheet(style);
|
||||
}
|
||||
|
||||
void SimulatorDialog::traceCallback(const char * text)
|
||||
void SimulatorDialog::captureScreenshot(bool)
|
||||
{
|
||||
// this function is called from other threads
|
||||
traceMutex.lock();
|
||||
// limit the size of list
|
||||
if (traceList.size() < 1000) {
|
||||
traceList.append(QString(text));
|
||||
}
|
||||
traceMutex.unlock();
|
||||
if (radioUiWidget)
|
||||
radioUiWidget->captureScreenshot();
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -384,8 +389,6 @@ void SimulatorDialog::start()
|
|||
{
|
||||
setupRadioWidgets();
|
||||
setupJoysticks();
|
||||
setupOutputsDisplay();
|
||||
setupGVarsDisplay();
|
||||
restoreRadioWidgetsState();
|
||||
|
||||
if (startupData.isEmpty())
|
||||
|
@ -414,94 +417,30 @@ void SimulatorDialog::restart()
|
|||
start();
|
||||
}
|
||||
|
||||
void SimulatorDialog::shutdown()
|
||||
{
|
||||
stop();
|
||||
saveState();
|
||||
if (saveTempRadioData)
|
||||
saveTempData();
|
||||
if (deleteTempRadioData)
|
||||
deleteTempData();
|
||||
}
|
||||
|
||||
/*
|
||||
* Setup
|
||||
*/
|
||||
|
||||
void SimulatorDialog::setupUi()
|
||||
void SimulatorDialog::setRadioProfileId(int value)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
windowName = tr("Simulating Radio (%1)").arg(firmware->getName());
|
||||
setWindowTitle(windowName);
|
||||
|
||||
switch(m_board) {
|
||||
case Board::BOARD_TARANIS_X7:
|
||||
radioUiWidget = new SimulatedUIWidgetX7(simulator, this);
|
||||
break;
|
||||
case Board::BOARD_TARANIS_X9D:
|
||||
case Board::BOARD_TARANIS_X9DP:
|
||||
case Board::BOARD_TARANIS_X9E:
|
||||
radioUiWidget = new SimulatedUIWidgetX9(simulator, this);
|
||||
break;
|
||||
case Board::BOARD_X12S:
|
||||
case Board::BOARD_X10:
|
||||
radioUiWidget = new SimulatedUIWidgetX12(simulator, this);
|
||||
break;
|
||||
default:
|
||||
radioUiWidget = new SimulatedUIWidget9X(simulator, this);
|
||||
break;
|
||||
}
|
||||
|
||||
foreach (keymapHelp_t item, *radioUiWidget->getKeymapHelp()) {
|
||||
keymapHelp.append(item);
|
||||
}
|
||||
|
||||
ui->radioUiTab->layout()->addWidget(radioUiWidget);
|
||||
ui->tabWidget->setTabText(0, firmware->getName());
|
||||
ui->tabWidget->setFixedHeight(radioUiWidget->height() + ui->tabWidget->tabBar()->height() - 8);
|
||||
|
||||
vJoyLeft = new VirtualJoystickWidget(this, 'L');
|
||||
ui->leftStickLayout->addWidget(vJoyLeft);
|
||||
|
||||
vJoyRight = new VirtualJoystickWidget(this, 'R');
|
||||
ui->rightStickLayout->addWidget(vJoyRight);
|
||||
|
||||
ui->tabWidget->setCurrentIndex(flags & SIMULATOR_FLAGS_NOTX);
|
||||
|
||||
connect(vJoyLeft, SIGNAL(trimButtonPressed(int)), this, SLOT(onTrimPressed(int)));
|
||||
connect(vJoyLeft, SIGNAL(trimButtonReleased()), this, SLOT(onTrimReleased()));
|
||||
connect(vJoyLeft, SIGNAL(trimSliderMoved(int,int)), this, SLOT(onTrimSliderMoved(int,int)));
|
||||
|
||||
connect(vJoyRight, SIGNAL(trimButtonPressed(int)), this, SLOT(onTrimPressed(int)));
|
||||
connect(vJoyRight, SIGNAL(trimButtonReleased()), this, SLOT(onTrimReleased()));
|
||||
connect(vJoyRight, SIGNAL(trimSliderMoved(int,int)), this, SLOT(onTrimSliderMoved(int,int)));
|
||||
|
||||
connect(ui->btn_help, SIGNAL(released()), this, SLOT(showHelp()));
|
||||
connect(ui->btn_joystickDialog, SIGNAL(released()), this, SLOT(openJoystickDialog()));
|
||||
connect(ui->btn_telemSim, SIGNAL(released()), this, SLOT(openTelemetrySimulator()));
|
||||
connect(ui->btn_trainerSim, SIGNAL(released()), this, SLOT(openTrainerSimulator()));
|
||||
connect(ui->btn_debugConsole, SIGNAL(released()), this, SLOT(openDebugOutput()));
|
||||
connect(ui->btn_luaReload, SIGNAL(released()), this, SLOT(luaReload()));
|
||||
connect(ui->btn_screenshot, SIGNAL(released()), radioUiWidget, SLOT(captureScreenshot()));
|
||||
connect(ui->btn_reloadSimu, SIGNAL(released()), this, SLOT(restart()));
|
||||
|
||||
#ifdef JOYSTICKS
|
||||
bool showJoystick = true;
|
||||
#else
|
||||
bool showJoystick = false;
|
||||
#endif
|
||||
|
||||
// Hide some main UI buttons based on board capabilities, and add keymap help texts.
|
||||
QString role;
|
||||
foreach (QPushButton * btn, ui->buttonBox->findChildren<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()));
|
||||
}
|
||||
|
||||
radioProfileId = value;
|
||||
if (simulator)
|
||||
simulator->setVolumeGain(g.profile[radioProfileId].volumeGain());
|
||||
}
|
||||
|
||||
void SimulatorDialog::setupRadioWidgets()
|
||||
{
|
||||
int i, midpos, aIdx, wval;
|
||||
int i, midpos, aIdx;
|
||||
QString wname;
|
||||
Board::Type board = firmware->getBoard();
|
||||
|
||||
|
@ -535,13 +474,12 @@ void SimulatorDialog::setupRadioWidgets()
|
|||
continue;
|
||||
|
||||
swcfg = Board::SwitchType(radioSettings.switchConfig[i]);
|
||||
wval = (swcfg == Board::SWITCH_3POS ? -1 : 0);
|
||||
|
||||
if ((wname = QString(radioSettings.switchName[i])).isEmpty()) {
|
||||
switchInfo = getSwitchInfo(board, i);
|
||||
wname = QString(switchInfo.name);
|
||||
}
|
||||
RadioSwitchWidget * sw = new RadioSwitchWidget(swcfg, wname, wval, ui->radioWidgetsHT);
|
||||
RadioSwitchWidget * sw = new RadioSwitchWidget(swcfg, wname, -1, ui->radioWidgetsHT);
|
||||
sw->setIndex(i);
|
||||
ui->radioWidgetsHTLayout->addWidget(sw);
|
||||
switches.append(sw);
|
||||
|
@ -593,172 +531,6 @@ void SimulatorDialog::setupRadioWidgets()
|
|||
}
|
||||
}
|
||||
|
||||
void SimulatorDialog::setupOutputsDisplay()
|
||||
{
|
||||
// setup Outputs tab
|
||||
QWidget * outputsWidget;
|
||||
|
||||
// delete old widget if already exists
|
||||
if (ui->tabWidget->count() > 1 && ui->tabWidget->widget(1)->objectName() == "RadioOutputsWidget") {
|
||||
outputsWidget = ui->tabWidget->widget(1);
|
||||
ui->tabWidget->removeTab(1);
|
||||
outputsWidget->deleteLater();
|
||||
outputsWidget = NULL;
|
||||
}
|
||||
|
||||
channelValues.clear();
|
||||
channelSliders.clear();
|
||||
logicalSwitchLabels.clear();
|
||||
|
||||
outputsWidget = new QWidget();
|
||||
outputsWidget->setObjectName("RadioOutputsWidget");
|
||||
QGridLayout * gridLayout = new QGridLayout(outputsWidget);
|
||||
gridLayout->setHorizontalSpacing(0);
|
||||
gridLayout->setVerticalSpacing(3);
|
||||
gridLayout->setContentsMargins(5, 3, 5, 3);
|
||||
// logical switches area
|
||||
QWidget * logicalSwitches = new QWidget(outputsWidget);
|
||||
logicalSwitches->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Maximum);
|
||||
QGridLayout * logicalSwitchesLayout = new QGridLayout(logicalSwitches);
|
||||
logicalSwitchesLayout->setHorizontalSpacing(3);
|
||||
logicalSwitchesLayout->setVerticalSpacing(2);
|
||||
logicalSwitchesLayout->setContentsMargins(0, 0, 0, 0);
|
||||
gridLayout->addWidget(logicalSwitches, 0, 0, 1, 1);
|
||||
// channels area
|
||||
QScrollArea * scrollArea = new QScrollArea(outputsWidget);
|
||||
QSizePolicy sp(QSizePolicy::Expanding, QSizePolicy::Preferred);
|
||||
sp.setHorizontalStretch(0);
|
||||
sp.setVerticalStretch(0);
|
||||
scrollArea->setSizePolicy(sp);
|
||||
scrollArea->setWidgetResizable(true);
|
||||
QWidget * channelsWidget = new QWidget();
|
||||
QGridLayout * channelsLayout = new QGridLayout(channelsWidget);
|
||||
channelsLayout->setHorizontalSpacing(4);
|
||||
channelsLayout->setVerticalSpacing(3);
|
||||
channelsLayout->setContentsMargins(0, 0, 0, 3);
|
||||
scrollArea->setWidget(channelsWidget);
|
||||
gridLayout->addWidget(scrollArea, 1, 0, 1, 1);
|
||||
|
||||
ui->tabWidget->insertTab(1, outputsWidget, QString(tr("Outputs")));
|
||||
|
||||
// populate outputs
|
||||
int outputs = std::min(32, firmware->getCapability(Outputs));
|
||||
int column = 0;
|
||||
for (int i=0; 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()
|
||||
{
|
||||
#ifdef JOYSTICKS
|
||||
|
@ -855,6 +627,16 @@ void SimulatorDialog::restoreRadioWidgetsState()
|
|||
if (switchesMap.contains(switches[i]->getIndex()))
|
||||
switches[i]->setStateData(switchesMap.value(switches[i]->getIndex()));
|
||||
}
|
||||
|
||||
// Set throttle stick down and locked, side depends on mode
|
||||
if (radioSettings.stickMode & 1) {
|
||||
vJoyLeft->setStickConstraint(VirtualJoystickWidget::HOLD_Y, true);
|
||||
vJoyLeft->setStickY(1);
|
||||
}
|
||||
else {
|
||||
vJoyRight->setStickConstraint(VirtualJoystickWidget::HOLD_Y, true);
|
||||
vJoyRight->setStickY(1);
|
||||
}
|
||||
}
|
||||
|
||||
QList<QByteArray> SimulatorDialog::saveRadioWidgetsState()
|
||||
|
@ -877,44 +659,8 @@ QList<QByteArray> SimulatorDialog::saveRadioWidgetsState()
|
|||
// Read various values from firmware simulator and populate values in this UI
|
||||
void SimulatorDialog::setValues()
|
||||
{
|
||||
static const int numGvars = firmware->getCapability(Gvars);
|
||||
static const int numFlightModes = firmware->getCapability(FlightModes);
|
||||
static TxOutputs prevOutputs;
|
||||
|
||||
TxOutputs outputs;
|
||||
simulator->getValues(outputs);
|
||||
|
||||
int currentPhase = simulator->getPhase();
|
||||
|
||||
// Outputs tab visible?
|
||||
if (ui->tabWidget->currentIndex() == 1) {
|
||||
for (int i = 0; i < channelSliders.size() && i < CPN_MAX_CHNOUT; i++) {
|
||||
channelSliders[i]->setValue(qMin(1024, qMax(-1024, outputs.chans[i])));
|
||||
channelValues[i]->setText(QString("%1").arg((qreal)outputs.chans[i]*100/1024, 0, 'f', 1));
|
||||
}
|
||||
|
||||
for (int i = 0; i < logicalSwitchLabels.size() && i < CPN_MAX_CSW; i++) {
|
||||
// setStyleSheet() is very CPU time consuming, do it only if the actual switch state changes
|
||||
if (prevOutputs.vsw[i] != outputs.vsw[i]) {
|
||||
logicalSwitchLabels[i]->setStyleSheet(outputs.vsw[i] ? CSWITCH_ON : CSWITCH_OFF);
|
||||
prevOutputs.vsw[i] = outputs.vsw[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// GVars tab visible?
|
||||
if (ui->tabWidget->currentIndex() == 2) {
|
||||
for (int gv = 0; gv < numGvars; gv++) {
|
||||
for (int fm = 0; fm < numFlightModes; fm++) {
|
||||
// same trick for GVARS, but this has far less effect on CPU usage as setStyleSheet()
|
||||
if (currentPhase != lastPhase || prevOutputs.gvars[fm][gv] != outputs.gvars[fm][gv]) {
|
||||
gvarValues[gv*numFlightModes+fm]->setText(QString((fm == lastPhase) ? "<b>%1</b>" : "%1").arg(outputs.gvars[fm][gv]));
|
||||
prevOutputs.gvars[fm][gv] = outputs.gvars[fm][gv];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// display current flight mode in window title
|
||||
if (currentPhase != lastPhase) {
|
||||
lastPhase = currentPhase;
|
||||
|
@ -923,7 +669,6 @@ void SimulatorDialog::setValues()
|
|||
phase_name = QString::number(currentPhase);
|
||||
setWindowTitle(windowName + QString(" - Flight Mode %1").arg(phase_name));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// "get" values from this UI and send them to the firmware simulator.
|
||||
|
@ -995,34 +740,16 @@ void SimulatorDialog::setTrims()
|
|||
* Event handlers/private slots
|
||||
*/
|
||||
|
||||
void SimulatorDialog::closeEvent(QCloseEvent *)
|
||||
{
|
||||
stop();
|
||||
saveState();
|
||||
if (saveTempRadioData)
|
||||
saveTempData();
|
||||
if (deleteTempRadioData)
|
||||
deleteTempData();
|
||||
}
|
||||
//void SimulatorDialog::showEvent(QShowEvent *)
|
||||
//{
|
||||
// if (firstShow && isVisible()) {
|
||||
// firstShow = false;
|
||||
// }
|
||||
//}
|
||||
|
||||
void SimulatorDialog::showEvent(QShowEvent *)
|
||||
{
|
||||
if (firstShow) {
|
||||
restoreGeometry(g.profile[radioProfileId].simulatorOptions().windowGeometry);
|
||||
|
||||
// The stick position needs to be set after the final show event, otherwise resizes during dialog creation will screw it up.
|
||||
if (radioSettings.stickMode & 1) {
|
||||
vJoyLeft->setStickConstraint(VirtualJoystickWidget::HOLD_Y, true);
|
||||
vJoyLeft->setStickY(1);
|
||||
}
|
||||
else {
|
||||
vJoyRight->setStickConstraint(VirtualJoystickWidget::HOLD_Y, true);
|
||||
vJoyRight->setStickY(1);
|
||||
}
|
||||
|
||||
firstShow = false;
|
||||
}
|
||||
}
|
||||
//void SimulatorDialog::closeEvent(QCloseEvent *)
|
||||
//{
|
||||
//}
|
||||
|
||||
void SimulatorDialog::mousePressEvent(QMouseEvent *event)
|
||||
{
|
||||
|
@ -1059,8 +786,6 @@ void SimulatorDialog::onTimerEvent()
|
|||
setTrims();
|
||||
centerSticks();
|
||||
}
|
||||
|
||||
updateDebugOutput();
|
||||
}
|
||||
|
||||
void SimulatorDialog::onTrimPressed(int which)
|
||||
|
@ -1087,111 +812,9 @@ void SimulatorDialog::centerSticks()
|
|||
vJoyRight->centerStick();
|
||||
}
|
||||
|
||||
void SimulatorDialog::openTelemetrySimulator()
|
||||
{
|
||||
// allow only one instance
|
||||
if (TelemetrySimu == 0) {
|
||||
TelemetrySimu = new TelemetrySimulator(this, simulator);
|
||||
TelemetrySimu->setAttribute(Qt::WA_DeleteOnClose);
|
||||
TelemetrySimu->show();
|
||||
connect(TelemetrySimu, &TelemetrySimulator::destroyed, [this](QObject *) {
|
||||
this->TelemetrySimu = NULL;
|
||||
});
|
||||
}
|
||||
else if (!TelemetrySimu->isVisible()) {
|
||||
TelemetrySimu->show();
|
||||
}
|
||||
}
|
||||
|
||||
void SimulatorDialog::openTrainerSimulator()
|
||||
{
|
||||
// allow only one instance
|
||||
if (TrainerSimu == 0) {
|
||||
TrainerSimu = new TrainerSimulator(this, simulator);
|
||||
TrainerSimu->setAttribute(Qt::WA_DeleteOnClose);
|
||||
TrainerSimu->show();
|
||||
connect(TrainerSimu, &TrainerSimulator::destroyed, [this](QObject *) {
|
||||
this->TrainerSimu = NULL;
|
||||
});
|
||||
}
|
||||
else if (!TrainerSimu->isVisible()) {
|
||||
TrainerSimu->show();
|
||||
}
|
||||
}
|
||||
|
||||
void SimulatorDialog::openJoystickDialog()
|
||||
{
|
||||
#ifdef JOYSTICKS
|
||||
joystickDialog * jd = new joystickDialog(this);
|
||||
if (jd->exec() == QDialog::Accepted)
|
||||
setupJoysticks();
|
||||
jd->deleteLater();
|
||||
#endif
|
||||
}
|
||||
|
||||
void SimulatorDialog::openDebugOutput()
|
||||
{
|
||||
// allow only one instance, but install signal handler to catch dialog destruction just in case
|
||||
if (!DebugOut) {
|
||||
DebugOut = new DebugOutput(this);
|
||||
DebugOut->traceCallback(traceBuffer);
|
||||
DebugOut->setAttribute(Qt::WA_DeleteOnClose);
|
||||
DebugOut->show();
|
||||
connect(DebugOut, &DebugOutput::destroyed, [this](QObject *) {
|
||||
this->DebugOut = NULL;
|
||||
});
|
||||
}
|
||||
else if (!DebugOut->isVisible()) {
|
||||
DebugOut->show();
|
||||
}
|
||||
}
|
||||
|
||||
void SimulatorDialog::updateDebugOutput()
|
||||
{
|
||||
traceMutex.lock();
|
||||
while (!traceList.isEmpty()) {
|
||||
QString text = traceList.takeFirst();
|
||||
traceBuffer.append(text);
|
||||
// limit the size of traceBuffer
|
||||
if (traceBuffer.size() > 10*1024) {
|
||||
traceBuffer.remove(0, 1*1024);
|
||||
}
|
||||
if (DebugOut) {
|
||||
DebugOut->traceCallback(QString(text));
|
||||
}
|
||||
}
|
||||
traceMutex.unlock();
|
||||
}
|
||||
|
||||
void SimulatorDialog::luaReload()
|
||||
{
|
||||
// force a reload of the lua environment
|
||||
simulator->setLuaStateReloadPermanentScripts();
|
||||
}
|
||||
|
||||
void SimulatorDialog::showHelp()
|
||||
{
|
||||
QString helpText = tr("Simulator Controls:");
|
||||
helpText += "<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)
|
||||
{
|
||||
#ifdef JOYSTICKS
|
||||
int stick;
|
||||
if (axis>=0 && axis<=8) {
|
||||
stick=jsmap[axis];
|
||||
|
@ -1225,5 +848,5 @@ void SimulatorDialog::onjoystickAxisValueChanged(int axis, int value)
|
|||
analogs[stick-5]->setValue(stickval);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -26,17 +26,11 @@
|
|||
#include "radiodata.h"
|
||||
#include "simulator.h"
|
||||
|
||||
#include <QDialog>
|
||||
#include <QWidget>
|
||||
#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 CSWITCH_ON "QLabel { background-color: #4CC417 }"
|
||||
#define CSWITCH_OFF "QLabel { }"
|
||||
#define CBEEP_ON "QLabel { background-color: #FF364E }"
|
||||
#define CBEEP_OFF "QLabel { }"
|
||||
|
||||
|
@ -45,9 +39,6 @@ void traceCb(const char * text);
|
|||
class Firmware;
|
||||
class SimulatorInterface;
|
||||
class SimulatedUIWidget;
|
||||
class TelemetrySimulator;
|
||||
class TrainerSimulator;
|
||||
class DebugOutput;
|
||||
class RadioWidget;
|
||||
class RadioSwitchWidget;
|
||||
class VirtualJoystickWidget;
|
||||
|
@ -57,7 +48,6 @@ class Joystick;
|
|||
|
||||
class QWidget;
|
||||
class QSlider;
|
||||
class QDial;
|
||||
class QLabel;
|
||||
class QFrame;
|
||||
|
||||
|
@ -67,7 +57,7 @@ namespace Ui {
|
|||
|
||||
using namespace Simulator;
|
||||
|
||||
class SimulatorDialog : public QDialog
|
||||
class SimulatorDialog : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
|
@ -75,7 +65,6 @@ class SimulatorDialog : public QDialog
|
|||
explicit SimulatorDialog(QWidget * parent, SimulatorInterface *simulator, quint8 flags=0);
|
||||
virtual ~SimulatorDialog();
|
||||
|
||||
void setRadioProfileId(int value);
|
||||
void setSdPath(const QString & sdPath);
|
||||
void setDataPath(const QString & dataPath);
|
||||
void setPaths(const QString & sdPath, const QString & dataPath);
|
||||
|
@ -89,23 +78,22 @@ class SimulatorDialog : public QDialog
|
|||
void deleteTempData();
|
||||
void saveState();
|
||||
void setUiAreaStyle(const QString & style);
|
||||
void traceCallback(const char * text);
|
||||
void captureScreenshot(bool);
|
||||
void setupJoysticks();
|
||||
|
||||
QString getSdPath() const { return sdCardPath; }
|
||||
QString getDataPath() const { return radioDataPath; }
|
||||
QVector<keymapHelp_t> * getKeymapHelp() { return &keymapHelp; }
|
||||
|
||||
public slots:
|
||||
void start();
|
||||
void stop();
|
||||
void restart();
|
||||
void shutdown();
|
||||
|
||||
private:
|
||||
void setupUi();
|
||||
void setRadioProfileId(int value);
|
||||
void setupRadioWidgets();
|
||||
void setupOutputsDisplay();
|
||||
void setupGVarsDisplay();
|
||||
void setupJoysticks();
|
||||
QFrame * createLogicalSwitch(QWidget * parent, int switchNo, QVector<QLabel *> & labels);
|
||||
void setupTimer();
|
||||
void restoreRadioWidgetsState();
|
||||
QList<QByteArray> saveRadioWidgetsState();
|
||||
|
@ -122,24 +110,14 @@ class SimulatorDialog : public QDialog
|
|||
|
||||
QTimer * timer;
|
||||
QString windowName;
|
||||
QString traceBuffer;
|
||||
QMutex traceMutex;
|
||||
QList<QString> traceList;
|
||||
QVector<keymapHelp_t> keymapHelp;
|
||||
|
||||
SimulatedUIWidget * radioUiWidget;
|
||||
VirtualJoystickWidget * vJoyLeft;
|
||||
VirtualJoystickWidget * vJoyRight;
|
||||
TelemetrySimulator * TelemetrySimu;
|
||||
TrainerSimulator * TrainerSimu;
|
||||
DebugOutput * DebugOut;
|
||||
|
||||
QVector<RadioSwitchWidget *> switches;
|
||||
QVector<RadioWidget *> analogs;
|
||||
QVector<QLabel *> logicalSwitchLabels;
|
||||
QVector<QSlider *> channelSliders;
|
||||
QVector<QLabel *> channelValues;
|
||||
QVector<QLabel *> gvarValues;
|
||||
|
||||
QString sdCardPath;
|
||||
QString radioDataPath;
|
||||
|
@ -163,8 +141,8 @@ class SimulatorDialog : public QDialog
|
|||
#endif
|
||||
|
||||
private slots:
|
||||
virtual void closeEvent(QCloseEvent *);
|
||||
virtual void showEvent(QShowEvent *);
|
||||
//virtual void showEvent(QShowEvent *);
|
||||
//virtual void closeEvent(QCloseEvent *);
|
||||
virtual void mousePressEvent(QMouseEvent *event);
|
||||
virtual void mouseReleaseEvent(QMouseEvent *event);
|
||||
virtual void wheelEvent(QWheelEvent *event);
|
||||
|
@ -174,16 +152,7 @@ class SimulatorDialog : public QDialog
|
|||
void onTrimReleased();
|
||||
void onTrimSliderMoved(int which, int value);
|
||||
void centerSticks();
|
||||
void openTelemetrySimulator();
|
||||
void openTrainerSimulator();
|
||||
void openJoystickDialog();
|
||||
void openDebugOutput();
|
||||
void updateDebugOutput();
|
||||
void luaReload();
|
||||
void showHelp();
|
||||
#ifdef JOYSTICKS
|
||||
void onjoystickAxisValueChanged(int axis, int value);
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -1,17 +1,17 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>SimulatorDialog</class>
|
||||
<widget class="QDialog" name="SimulatorDialog">
|
||||
<widget class="QWidget" name="SimulatorDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>651</width>
|
||||
<height>528</height>
|
||||
<width>448</width>
|
||||
<height>302</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
|
@ -23,29 +23,26 @@
|
|||
<iconset resource="../companion.qrc">
|
||||
<normaloff>:/icon.png</normaloff>:/icon.png</iconset>
|
||||
</property>
|
||||
<property name="sizeGripEnabled">
|
||||
<bool>true</bool>
|
||||
<property name="styleSheet">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_6">
|
||||
<property name="leftMargin">
|
||||
<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">
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="verticalSpacing">
|
||||
<number>3</number>
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</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">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
|
@ -54,7 +51,7 @@
|
|||
</sizepolicy>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::Panel</enum>
|
||||
<enum>QFrame::StyledPanel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
|
@ -62,414 +59,248 @@
|
|||
<property name="lineWidth">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<layout class="QGridLayout" name="gridLayout" rowstretch="1,4">
|
||||
<property name="leftMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>7</number>
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>6</number>
|
||||
<number>7</number>
|
||||
</property>
|
||||
<property name="horizontalSpacing">
|
||||
<number>6</number>
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="verticalSpacing">
|
||||
<number>5</number>
|
||||
<number>10</number>
|
||||
</property>
|
||||
<item row="1" column="0">
|
||||
<widget class="QWidget" name="leftStickWidget" native="true">
|
||||
<item row="0" column="0" colspan="2" alignment="Qt::AlignBottom">
|
||||
<widget class="QFrame" name="radioWidgetsHT">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<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="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 name="frameShape">
|
||||
<enum>QFrame::Panel</enum>
|
||||
</property>
|
||||
<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>
|
||||
<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 name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2" stretch="4,1">
|
||||
<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="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 name="midLineWidth">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="radioWidgetsHTLayout">
|
||||
<property name="spacing">
|
||||
<number>11</number>
|
||||
<number>10</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>6</number>
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>6</number>
|
||||
<number>9</number>
|
||||
</property>
|
||||
</layout>
|
||||
</widget>
|
||||
</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>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QTabWidget" name="tabWidget">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<item alignment="Qt::AlignBottom">
|
||||
<widget class="QWidget" name="radioUiWidget" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>200</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">QTabWidget::pane,
|
||||
QStackedWidget {
|
||||
padding: 0px;
|
||||
margin: 0px;
|
||||
}
|
||||
QTabWidget::tab-bar{
|
||||
margin-bottom: 0px;
|
||||
padding-bottom: 0px;
|
||||
}</string>
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<property name="currentIndex">
|
||||
<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">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<property name="spacing">
|
||||
<number>3</number>
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>1</number>
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>1</number>
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>1</number>
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>1</number>
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btn_help">
|
||||
<property name="toolTip">
|
||||
<string>Show Help/Keymap (F1)</string>
|
||||
<spacer name="radioUiTempSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="statusTip">
|
||||
<string>Show Help/Keymap</string>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Maximum</enum>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Keymap</string>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>F1</string>
|
||||
</property>
|
||||
<property name="role" stdset="0">
|
||||
<string>help</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btn_joystickDialog">
|
||||
<property name="toolTip">
|
||||
<string>Open the Joystick Settings window (F3)</string>
|
||||
</property>
|
||||
<property name="statusTip">
|
||||
<string>Joystick Configuration</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Joystick Config.</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>F3</string>
|
||||
</property>
|
||||
<property name="role" stdset="0">
|
||||
<string>joystick</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btn_telemSim">
|
||||
<property name="toolTip">
|
||||
<string>Open Telemetry Simulator window (F4)</string>
|
||||
</property>
|
||||
<property name="statusTip">
|
||||
<string>Telemetry Simulator</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Telemetry Sim.</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>F4</string>
|
||||
</property>
|
||||
<property name="role" stdset="0">
|
||||
<string>telemetry</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btn_trainerSim">
|
||||
<property name="toolTip">
|
||||
<string>Open Trainer Simulator window (F5)</string>
|
||||
</property>
|
||||
<property name="statusTip">
|
||||
<string>Trainer Simulator</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Trainer Sim.</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>F5</string>
|
||||
</property>
|
||||
<property name="role" stdset="0">
|
||||
<string>trainer</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btn_debugConsole">
|
||||
<property name="toolTip">
|
||||
<string>Open Debug Console window (F6)</string>
|
||||
</property>
|
||||
<property name="statusTip">
|
||||
<string>Debug Console</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Debug Console</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>F6</string>
|
||||
</property>
|
||||
<property name="role" stdset="0">
|
||||
<string>debug</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btn_luaReload">
|
||||
<property name="toolTip">
|
||||
<string>Reload Lua Scripts (F7)</string>
|
||||
</property>
|
||||
<property name="statusTip">
|
||||
<string>Reload Lua Scripts</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Reload Lua</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>F7</string>
|
||||
</property>
|
||||
<property name="role" stdset="0">
|
||||
<string>reloadLua</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btn_screenshot">
|
||||
<property name="toolTip">
|
||||
<string>Save a screenshot of the radio LCD screen (F8)</string>
|
||||
</property>
|
||||
<property name="statusTip">
|
||||
<string>LCD Screenshot</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Screenshot</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>F8</string>
|
||||
</property>
|
||||
<property name="role" stdset="0">
|
||||
<string>lcdScreenshot</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btn_reloadSimu">
|
||||
<property name="toolTip">
|
||||
<string>Reload all radio data (F9)</string>
|
||||
</property>
|
||||
<property name="statusTip">
|
||||
<string>Reload Radio Data</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Reload Radio</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>F9</string>
|
||||
</property>
|
||||
<property name="role" stdset="0">
|
||||
<string>reloadradio</string>
|
||||
</property>
|
||||
</widget>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</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>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>488</width>
|
||||
<height>219</height>
|
||||
<width>550</width>
|
||||
<height>217</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>550</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>OpenTX Simulator - Startup Options</string>
|
||||
</property>
|
||||
|
@ -22,13 +28,28 @@
|
|||
</property>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Simulator Startup Options:</string>
|
||||
</property>
|
||||
<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">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="formAlignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
|
||||
</property>
|
||||
<property name="horizontalSpacing">
|
||||
<number>5</number>
|
||||
</property>
|
||||
|
@ -56,6 +77,12 @@
|
|||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QComboBox" name="radioProfile">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Existing radio profiles are shown here.<br />
|
||||
Create or edit profiles using the Companion application.</string>
|
||||
|
@ -71,6 +98,12 @@ Create or edit profiles using the Companion application.</string>
|
|||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QComboBox" name="radioType">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Existing radio simulators are shown here.<br />
|
||||
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 row="3" column="1">
|
||||
<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">
|
||||
<property name="spacing">
|
||||
<number>4</number>
|
||||
|
@ -140,7 +179,7 @@ The radio type specified in the selected profile is used by default.</string>
|
|||
<string>...</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../companion.qrc">
|
||||
<iconset>
|
||||
<normaloff>:/themes/monoblue/16/open.png</normaloff>:/themes/monoblue/16/open.png</iconset>
|
||||
</property>
|
||||
<property name="toolButtonStyle">
|
||||
|
@ -153,6 +192,12 @@ The radio type specified in the selected profile is used by default.</string>
|
|||
</item>
|
||||
<item row="4" column="1">
|
||||
<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">
|
||||
<property name="spacing">
|
||||
<number>4</number>
|
||||
|
@ -186,7 +231,7 @@ New folder(s) with default radio/model will be created here if necessary.</strin
|
|||
<string>...</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../companion.qrc">
|
||||
<iconset>
|
||||
<normaloff>:/themes/monoblue/16/open.png</normaloff>:/themes/monoblue/16/open.png</iconset>
|
||||
</property>
|
||||
<property name="toolButtonStyle">
|
||||
|
@ -199,6 +244,12 @@ New folder(s) with default radio/model will be created here if necessary.</strin
|
|||
</item>
|
||||
<item row="5" column="1">
|
||||
<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">
|
||||
<property name="spacing">
|
||||
<number>4</number>
|
||||
|
@ -232,7 +283,7 @@ The default is configured in the chosen Radio Profile.</string>
|
|||
<string>...</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../companion.qrc">
|
||||
<iconset>
|
||||
<normaloff>:/themes/monoblue/16/open.png</normaloff>:/themes/monoblue/16/open.png</iconset>
|
||||
</property>
|
||||
<property name="toolButtonStyle">
|
||||
|
@ -245,6 +296,12 @@ The default is configured in the chosen Radio Profile.</string>
|
|||
</item>
|
||||
<item row="2" column="1">
|
||||
<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">
|
||||
<string>Select which of the data sources (File/Folder/SD Card) you would like to start the simulator with.</string>
|
||||
</property>
|
||||
|
@ -312,9 +369,7 @@ The default is configured in the chosen Radio Profile.</string>
|
|||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources>
|
||||
<include location="../companion.qrc"/>
|
||||
</resources>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
|
|
|
@ -25,24 +25,20 @@
|
|||
#include "radio/src/telemetry/frsky.h"
|
||||
|
||||
TelemetrySimulator::TelemetrySimulator(QWidget * parent, SimulatorInterface * simulator):
|
||||
QDialog(parent),
|
||||
QWidget(parent),
|
||||
ui(new Ui::TelemetrySimulator),
|
||||
simulator(simulator)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
QPoint dialogCenter = mapToGlobal(rect().center());
|
||||
QPoint parentWindowCenter = parent->window()->mapToGlobal(
|
||||
parent->window()->rect().center());
|
||||
move(parentWindowCenter - dialogCenter);
|
||||
|
||||
timer = new QTimer(this);
|
||||
timer->setInterval(10);
|
||||
connect(timer, SIGNAL(timeout()), this, SLOT(onTimerEvent()));
|
||||
|
||||
logTimer = new QTimer(this);
|
||||
connect(logTimer, SIGNAL(timeout()), this, SLOT(onLogTimerEvent()));
|
||||
|
||||
connect(ui->Simulate, SIGNAL(clicked(bool)), this, SLOT(onSimulateToggled(bool)));
|
||||
connect(ui->Simulate, SIGNAL(toggled(bool)), this, SLOT(onSimulateToggled(bool)));
|
||||
connect(ui->loadLogFile, SIGNAL(released()), this, SLOT(onLoadLogFile()));
|
||||
connect(ui->play, SIGNAL(released()), this, SLOT(onPlay()));
|
||||
connect(ui->rewind, SIGNAL(clicked()), this, SLOT(onRewind()));
|
||||
|
@ -76,7 +72,7 @@ TelemetrySimulator::~TelemetrySimulator()
|
|||
void TelemetrySimulator::onSimulateToggled(bool isChecked)
|
||||
{
|
||||
if (isChecked) {
|
||||
timer->start(10);
|
||||
timer->start();
|
||||
}
|
||||
else {
|
||||
timer->stop();
|
||||
|
@ -197,9 +193,6 @@ void TelemetrySimulator::showEvent(QShowEvent *event)
|
|||
ui->rxbt_ratio->setValue(simulator->getSensorRatio(BATT_ID) / 10.0);
|
||||
ui->A1_ratio->setValue(simulator->getSensorRatio(ADC1_ID) / 10.0);
|
||||
ui->A2_ratio->setValue(simulator->getSensorRatio(ADC2_ID) / 10.0);
|
||||
|
||||
ui->Simulate->setChecked(true);
|
||||
onSimulateToggled(true); // not sure why this doesn't fire automatically
|
||||
}
|
||||
|
||||
void setSportPacketCrc(uint8_t * packet)
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
#define _TELEMETRYSIMU_H_
|
||||
|
||||
#include <QCloseEvent>
|
||||
#include <QDialog>
|
||||
#include <QWidget>
|
||||
#include <QTimer>
|
||||
#include <QDateTime>
|
||||
#include <QtCore/qmath.h>
|
||||
|
@ -37,102 +37,19 @@ namespace Ui {
|
|||
class TelemetrySimulator;
|
||||
}
|
||||
|
||||
|
||||
class TelemetrySimulator : public QDialog
|
||||
class TelemetrySimulator : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
explicit TelemetrySimulator(QWidget * parent, SimulatorInterface * simulator);
|
||||
virtual ~TelemetrySimulator();
|
||||
|
||||
protected:
|
||||
protected slots:
|
||||
|
||||
virtual void closeEvent(QCloseEvent *event);
|
||||
virtual void showEvent(QShowEvent *event);
|
||||
|
||||
private:
|
||||
class LogPlaybackController
|
||||
{
|
||||
public:
|
||||
LogPlaybackController(Ui::TelemetrySimulator * ui);
|
||||
bool isReady();
|
||||
void loadLogFile();
|
||||
void play();
|
||||
void stop();
|
||||
void rewind();
|
||||
void stepForward(bool focusOnStop);
|
||||
void stepBack();
|
||||
void updatePositionLabel(int32_t percentage);
|
||||
void setUiDataValues();
|
||||
double logFrequency; // in seconds
|
||||
private:
|
||||
enum CONVERT_TYPE {
|
||||
RXBT_V,
|
||||
RSSI,
|
||||
SWR,
|
||||
A1,
|
||||
A2,
|
||||
A3,
|
||||
A4,
|
||||
T1_DEGC,
|
||||
T1_DEGF,
|
||||
T2_DEGC,
|
||||
T2_DEGF,
|
||||
RPM,
|
||||
FUEL,
|
||||
VSPD_MS,
|
||||
VSPD_FS,
|
||||
ALT_FEET,
|
||||
ALT_METERS,
|
||||
FASV,
|
||||
FASC,
|
||||
CELS_GRE,
|
||||
ASPD_KTS,
|
||||
ASPD_KMH,
|
||||
ASPD_MPH,
|
||||
GALT_FEET,
|
||||
GALT_METERS,
|
||||
GSPD_KNTS,
|
||||
GSPD_KMH,
|
||||
GSPD_MPH,
|
||||
GHDG_DEG,
|
||||
GDATE,
|
||||
G_LATLON,
|
||||
ACCX,
|
||||
ACCY,
|
||||
ACCZ,
|
||||
FUEL_QTY,
|
||||
};
|
||||
QMap<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 onTimerEvent();
|
||||
void onLogTimerEvent();
|
||||
|
@ -145,49 +62,138 @@ private:
|
|||
void onPositionIndicatorChanged(int value);
|
||||
void onReplayRateChanged(int value);
|
||||
|
||||
protected:
|
||||
|
||||
Ui::TelemetrySimulator * ui;
|
||||
QTimer * timer;
|
||||
QTimer * logTimer;
|
||||
SimulatorInterface *simulator;
|
||||
void generateTelemetryFrame();
|
||||
|
||||
// protected classes follow
|
||||
|
||||
class LogPlaybackController
|
||||
{
|
||||
public:
|
||||
LogPlaybackController(Ui::TelemetrySimulator * ui);
|
||||
bool isReady();
|
||||
void loadLogFile();
|
||||
void play();
|
||||
void stop();
|
||||
void rewind();
|
||||
void stepForward(bool focusOnStop);
|
||||
void stepBack();
|
||||
void updatePositionLabel(int32_t percentage);
|
||||
void setUiDataValues();
|
||||
double logFrequency; // in seconds
|
||||
|
||||
private:
|
||||
enum CONVERT_TYPE {
|
||||
RXBT_V,
|
||||
RSSI,
|
||||
SWR,
|
||||
A1,
|
||||
A2,
|
||||
A3,
|
||||
A4,
|
||||
T1_DEGC,
|
||||
T1_DEGF,
|
||||
T2_DEGC,
|
||||
T2_DEGF,
|
||||
RPM,
|
||||
FUEL,
|
||||
VSPD_MS,
|
||||
VSPD_FS,
|
||||
ALT_FEET,
|
||||
ALT_METERS,
|
||||
FASV,
|
||||
FASC,
|
||||
CELS_GRE,
|
||||
ASPD_KTS,
|
||||
ASPD_KMH,
|
||||
ASPD_MPH,
|
||||
GALT_FEET,
|
||||
GALT_METERS,
|
||||
GSPD_KNTS,
|
||||
GSPD_KMH,
|
||||
GSPD_MPH,
|
||||
GHDG_DEG,
|
||||
GDATE,
|
||||
G_LATLON,
|
||||
ACCX,
|
||||
ACCY,
|
||||
ACCZ,
|
||||
FUEL_QTY,
|
||||
};
|
||||
|
||||
struct DATA_TO_FUNC_XREF {
|
||||
CONVERT_TYPE functionIndex;
|
||||
int32_t dataIndex;
|
||||
};
|
||||
|
||||
double convertFeetToMeters(QString input);
|
||||
double convertFahrenheitToCelsius(QString input);
|
||||
QString convertGPSDate(QString input);
|
||||
QString convertGPS(QString input);
|
||||
void addColumnHash(QString key, CONVERT_TYPE functionIndex);
|
||||
double convertDegMin(QString input);
|
||||
QDateTime parseTransmittterTimestamp(QString row);
|
||||
void calcLogFrequency();
|
||||
|
||||
QMap<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
|
||||
{
|
||||
public:
|
||||
public:
|
||||
uint32_t setAllCells_GetNextPair(double cellValues[6]);
|
||||
static const uint32_t MAXCELLS = 6;
|
||||
private:
|
||||
void encodeAllCells();
|
||||
void splitIntoCells(double totalVolts);
|
||||
static uint32_t encodeCellPair(uint8_t cellNum, uint8_t firstCellNo, double cell1, double cell2);
|
||||
double cellFloats[6];
|
||||
uint32_t nextCellNum;
|
||||
uint32_t numCells;
|
||||
uint32_t cellData1;
|
||||
uint32_t cellData2;
|
||||
uint32_t cellData3;
|
||||
};
|
||||
|
||||
private:
|
||||
void encodeAllCells();
|
||||
void splitIntoCells(double totalVolts);
|
||||
static uint32_t encodeCellPair(uint8_t cellNum, uint8_t firstCellNo, double cell1, double cell2);
|
||||
double cellFloats[6];
|
||||
uint32_t nextCellNum;
|
||||
uint32_t numCells;
|
||||
uint32_t cellData1;
|
||||
uint32_t cellData2;
|
||||
uint32_t cellData3;
|
||||
}; // FlvssEmulator
|
||||
|
||||
class GPSEmulator
|
||||
{
|
||||
public:
|
||||
GPSEmulator();
|
||||
uint32_t getNextPacketData(uint32_t packetType);
|
||||
void setGPSDateTime(QString dateTime);
|
||||
void setGPSLatLon(QString latLon);
|
||||
void setGPSCourse(double course);
|
||||
void setGPSSpeedKMH(double speed);
|
||||
void setGPSAltitude(double altitude);
|
||||
private:
|
||||
QDateTime dt;
|
||||
bool sendLat;
|
||||
bool sendDate;
|
||||
double lat;
|
||||
double lon;
|
||||
double course;
|
||||
double speedKNTS;
|
||||
double altitude; // in meters
|
||||
uint32_t encodeLatLon(double latLon, bool isLat);
|
||||
uint32_t encodeDateTime(uint8_t yearOrHour, uint8_t monthOrMinute, uint8_t dayOrSecond, bool isDate);
|
||||
};
|
||||
public:
|
||||
GPSEmulator();
|
||||
uint32_t getNextPacketData(uint32_t packetType);
|
||||
void setGPSDateTime(QString dateTime);
|
||||
void setGPSLatLon(QString latLon);
|
||||
void setGPSCourse(double course);
|
||||
void setGPSSpeedKMH(double speed);
|
||||
void setGPSAltitude(double altitude);
|
||||
|
||||
};
|
||||
private:
|
||||
QDateTime dt;
|
||||
bool sendLat;
|
||||
bool sendDate;
|
||||
double lat;
|
||||
double lon;
|
||||
double course;
|
||||
double speedKNTS;
|
||||
double altitude; // in meters
|
||||
uint32_t encodeLatLon(double latLon, bool isLat);
|
||||
uint32_t encodeDateTime(uint8_t yearOrHour, uint8_t monthOrMinute, uint8_t dayOrSecond, bool isDate);
|
||||
}; // GPSEmulator
|
||||
|
||||
}; // TelemetrySimulator
|
||||
|
||||
#endif // _TELEMETRYSIMU_H_
|
||||
|
||||
|
|
|
@ -22,37 +22,45 @@
|
|||
#include "trainersimu.h"
|
||||
#include "ui_trainersimu.h"
|
||||
#include "helpers.h"
|
||||
|
||||
#define GBALL_SIZE 20
|
||||
#define RESX 512
|
||||
#include "virtualjoystickwidget.h"
|
||||
|
||||
TrainerSimulator::TrainerSimulator(QWidget * parent, SimulatorInterface * simulator):
|
||||
QDialog(parent),
|
||||
QWidget(parent),
|
||||
ui(new Ui::TrainerSimulator),
|
||||
simulator(simulator)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
leftStick = ui->leftStick;
|
||||
rightStick = ui->rightStick;
|
||||
|
||||
setupSticks();
|
||||
vJoyLeft = new VirtualJoystickWidget(this, 'L', false);
|
||||
vJoyLeft->setStickColor(Qt::cyan);
|
||||
ui->leftStickLayout->addWidget(vJoyLeft);
|
||||
|
||||
// resize(0, 0); // to force min height, min width
|
||||
setFixedSize(width(), height());
|
||||
vJoyRight = new VirtualJoystickWidget(this, 'R', false);
|
||||
vJoyRight->setStickColor(Qt::cyan);
|
||||
ui->rightStickLayout->addWidget(vJoyRight);
|
||||
|
||||
timer = new QTimer(this);
|
||||
timer->setInterval(10);
|
||||
connect(timer, SIGNAL(timeout()), this, SLOT(onTimerEvent()));
|
||||
}
|
||||
|
||||
TrainerSimulator::~TrainerSimulator()
|
||||
{
|
||||
timer->stop();
|
||||
if (timer) {
|
||||
timer->stop();
|
||||
delete timer;
|
||||
}
|
||||
if (vJoyLeft)
|
||||
delete vJoyLeft;
|
||||
if (vJoyRight)
|
||||
delete vJoyRight;
|
||||
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void TrainerSimulator::showEvent(QShowEvent *event)
|
||||
{
|
||||
timer->start(10);
|
||||
timer->start();
|
||||
event->accept();
|
||||
}
|
||||
|
||||
|
@ -64,71 +72,13 @@ void TrainerSimulator::closeEvent(QCloseEvent *event)
|
|||
|
||||
void TrainerSimulator::centerSticks()
|
||||
{
|
||||
if (leftStick->scene())
|
||||
nodeLeft->stepToCenter();
|
||||
if (vJoyLeft)
|
||||
vJoyLeft->centerStick();
|
||||
|
||||
if (rightStick->scene())
|
||||
nodeRight->stepToCenter();
|
||||
if (vJoyRight)
|
||||
vJoyRight->centerStick();
|
||||
}
|
||||
|
||||
void TrainerSimulator::setupSticks()
|
||||
{
|
||||
QGraphicsScene *leftScene = new QGraphicsScene(leftStick);
|
||||
leftScene->setItemIndexMethod(QGraphicsScene::NoIndex);
|
||||
leftStick->setScene(leftScene);
|
||||
|
||||
// leftStick->scene()->addLine(0,10,20,30);
|
||||
|
||||
QGraphicsScene *rightScene = new QGraphicsScene(rightStick);
|
||||
rightScene->setItemIndexMethod(QGraphicsScene::NoIndex);
|
||||
rightStick->setScene(rightScene);
|
||||
|
||||
// rightStick->scene()->addLine(0,10,20,30);
|
||||
|
||||
nodeLeft = new Node();
|
||||
nodeLeft->setPos(-GBALL_SIZE/2,-GBALL_SIZE/2);
|
||||
nodeLeft->setBallSize(GBALL_SIZE);
|
||||
leftScene->addItem(nodeLeft);
|
||||
|
||||
nodeRight = new Node();
|
||||
nodeRight->setPos(-GBALL_SIZE/2,-GBALL_SIZE/2);
|
||||
nodeRight->setBallSize(GBALL_SIZE);
|
||||
rightScene->addItem(nodeRight);
|
||||
}
|
||||
|
||||
void TrainerSimulator::resizeEvent(QResizeEvent *event)
|
||||
{
|
||||
if (leftStick->scene()) {
|
||||
QRect qr = leftStick->contentsRect();
|
||||
qreal w = (qreal)qr.width() - GBALL_SIZE;
|
||||
qreal h = (qreal)qr.height() - GBALL_SIZE;
|
||||
qreal cx = (qreal)qr.width()/2;
|
||||
qreal cy = (qreal)qr.height()/2;
|
||||
leftStick->scene()->setSceneRect(-cx,-cy,w,h);
|
||||
|
||||
QPointF p = nodeLeft->pos();
|
||||
p.setX(qMin(cx, qMax(p.x(), -cx)));
|
||||
p.setY(qMin(cy, qMax(p.y(), -cy)));
|
||||
nodeLeft->setPos(p);
|
||||
}
|
||||
|
||||
if (rightStick->scene()) {
|
||||
QRect qr = rightStick->contentsRect();
|
||||
qreal w = (qreal)qr.width() - GBALL_SIZE;
|
||||
qreal h = (qreal)qr.height() - GBALL_SIZE;
|
||||
qreal cx = (qreal)qr.width()/2;
|
||||
qreal cy = (qreal)qr.height()/2;
|
||||
rightStick->scene()->setSceneRect(-cx,-cy,w,h);
|
||||
|
||||
QPointF p = nodeRight->pos();
|
||||
p.setX(qMin(cx, qMax(p.x(), -cx)));
|
||||
p.setY(qMin(cy, qMax(p.y(), -cy)));
|
||||
nodeRight->setPos(p);
|
||||
}
|
||||
QDialog::resizeEvent(event);
|
||||
}
|
||||
|
||||
|
||||
void TrainerSimulator::onTimerEvent()
|
||||
{
|
||||
centerSticks();
|
||||
|
@ -137,8 +87,15 @@ void TrainerSimulator::onTimerEvent()
|
|||
|
||||
void TrainerSimulator::setTrainerInputs()
|
||||
{
|
||||
simulator->setTrainerInput(0, int( 512* nodeLeft->getX())); // LEFT HORZ
|
||||
simulator->setTrainerInput(1, int(-512* nodeLeft->getY())); // LEFT VERT
|
||||
simulator->setTrainerInput(2, int(-512*nodeRight->getY())); // RGHT VERT
|
||||
simulator->setTrainerInput(3, int( 512*nodeRight->getX())); // RGHT HORZ
|
||||
if (!simulator)
|
||||
return;
|
||||
|
||||
if (vJoyLeft) {
|
||||
simulator->setTrainerInput(0, int( 512 * vJoyLeft->getStickX())); // LEFT HORZ
|
||||
simulator->setTrainerInput(1, int(-512 * vJoyLeft->getStickY())); // LEFT VERT
|
||||
}
|
||||
if (vJoyRight) {
|
||||
simulator->setTrainerInput(2, int(-512 * vJoyRight->getStickY())); // RGHT VERT
|
||||
simulator->setTrainerInput(3, int( 512 * vJoyRight->getStickX())); // RGHT HORZ
|
||||
}
|
||||
}
|
|
@ -24,17 +24,17 @@
|
|||
|
||||
#include <QShowEvent>
|
||||
#include <QCloseEvent>
|
||||
#include <QDialog>
|
||||
#include <QWidget>
|
||||
#include <QTimer>
|
||||
#include "modeledit/node.h"
|
||||
#include "simulatorinterface.h"
|
||||
|
||||
namespace Ui {
|
||||
class TrainerSimulator;
|
||||
}
|
||||
|
||||
class VirtualJoystickWidget;
|
||||
|
||||
class TrainerSimulator : public QDialog
|
||||
class TrainerSimulator : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
|
@ -43,26 +43,20 @@ class TrainerSimulator : public QDialog
|
|||
virtual ~TrainerSimulator();
|
||||
|
||||
|
||||
protected:
|
||||
protected slots:
|
||||
virtual void showEvent(QShowEvent *event);
|
||||
virtual void closeEvent(QCloseEvent *event);
|
||||
void centerSticks();
|
||||
void setTrainerInputs();
|
||||
void onTimerEvent();
|
||||
|
||||
private:
|
||||
protected:
|
||||
Ui::TrainerSimulator * ui;
|
||||
QTimer * timer;
|
||||
SimulatorInterface *simulator;
|
||||
|
||||
QGraphicsView * leftStick, * rightStick;
|
||||
Node *nodeLeft;
|
||||
Node *nodeRight;
|
||||
|
||||
void centerSticks();
|
||||
void setupSticks();
|
||||
void resizeEvent(QResizeEvent *event = 0);
|
||||
void setTrainerInputs();
|
||||
|
||||
private slots:
|
||||
void onTimerEvent();
|
||||
VirtualJoystickWidget * vJoyLeft;
|
||||
VirtualJoystickWidget * vJoyRight;
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -1,94 +1,70 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>TrainerSimulator</class>
|
||||
<widget class="QDialog" name="TrainerSimulator">
|
||||
<widget class="QWidget" name="TrainerSimulator">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>566</width>
|
||||
<height>268</height>
|
||||
<width>385</width>
|
||||
<height>187</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Trainer simulator</string>
|
||||
</property>
|
||||
<widget class="QFrame" name="frame">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>563</width>
|
||||
<height>267</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::Panel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
<property name="lineWidth">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<property name="margin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<item>
|
||||
<layout class="QGridLayout" name="gridLayout_3">
|
||||
<item row="0" column="1">
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QFrame" name="frame">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::Panel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
<property name="lineWidth">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<property name="spacing">
|
||||
<number>15</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>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Minimum</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>17</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="QGraphicsView" name="rightStick">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>245</width>
|
||||
<height>245</height>
|
||||
</size>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="rightStickLayout">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="verticalScrollBarPolicy">
|
||||
<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>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
|
|
|
@ -47,7 +47,7 @@ class RadioFaderWidget : public RadioWidget
|
|||
|
||||
SliderWidget * sl = new SliderWidget(this);
|
||||
sl->setOrientation(Qt::Vertical);
|
||||
sl->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding);
|
||||
sl->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred);
|
||||
sl->setMinimumHeight(75);
|
||||
//sl->setMaximumHeight(75);
|
||||
sl->setTickPosition(QSlider::TicksBothSides);
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
|
||||
#include "radiowidget.h"
|
||||
#include "boards.h"
|
||||
#include "simulator.h"
|
||||
|
||||
#include <QSlider>
|
||||
#include <QTimer>
|
||||
|
@ -65,11 +66,8 @@ class RadioSwitchWidget : public RadioWidget
|
|||
m_slider->setValue(m_value);
|
||||
|
||||
if (swType == Board::SWITCH_TOGGLE) {
|
||||
QIcon icon;
|
||||
icon.addFile(QStringLiteral(":/images/simulator/icons/8/lock-locked.png"), QSize(8, 8), QIcon::Normal, QIcon::On);
|
||||
icon.addFile(QStringLiteral(":/images/simulator/icons/8/lock-unlocked.png"), QSize(8, 8), QIcon::Normal, QIcon::Off);
|
||||
QToolButton * lockBtn = new QToolButton(this);
|
||||
lockBtn->setIcon(icon);
|
||||
lockBtn->setIcon(Simulator::SimulatorIcon("toggle_lock"));
|
||||
lockBtn->setIconSize(QSize(8, 8));
|
||||
lockBtn->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
|
||||
lockBtn->setToolButtonStyle(Qt::ToolButtonIconOnly);
|
||||
|
@ -78,7 +76,7 @@ class RadioSwitchWidget : public RadioWidget
|
|||
lockBtn->setToolTip(tr("Latch/unlatch the momentary switch."));
|
||||
|
||||
QWidget * container = new QWidget(this);
|
||||
container->setFixedHeight(50);
|
||||
container->setFixedHeight(56);
|
||||
container->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
|
||||
QVBoxLayout * cl = new QVBoxLayout(container);
|
||||
cl->setContentsMargins(0, 0, 0, 0);
|
||||
|
@ -94,7 +92,7 @@ class RadioSwitchWidget : public RadioWidget
|
|||
connect(this, &RadioWidget::flagsChanged, lockBtn, &QToolButton::setChecked);
|
||||
}
|
||||
else {
|
||||
m_slider->setFixedHeight(50);
|
||||
m_slider->setFixedHeight(56);
|
||||
setWidget(m_slider);
|
||||
}
|
||||
|
||||
|
|
|
@ -18,6 +18,9 @@
|
|||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#define GBALL_SIZE 20
|
||||
#define RESX 1024
|
||||
|
||||
#include "virtualjoystickwidget.h"
|
||||
#include "constants.h"
|
||||
#include "sliderwidget.h"
|
||||
|
@ -50,7 +53,9 @@ VirtualJoystickWidget::VirtualJoystickWidget(QWidget *parent, QChar side, bool s
|
|||
|
||||
gv = new QGraphicsView(this);
|
||||
gv->setSizePolicy(sizePolicy);
|
||||
gv->setMinimumSize(QSize(150, 150));
|
||||
gv->setMinimumSize(size);
|
||||
// gv->setMaximumSize(size + size * 3);
|
||||
// gv->setFixedSize(prefSize);
|
||||
gv->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||
gv->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||
|
||||
|
@ -88,6 +93,9 @@ VirtualJoystickWidget::VirtualJoystickWidget(QWidget *parent, QChar side, bool s
|
|||
vTrimSlider = vTrimWidget->findChild<SliderWidget *>();
|
||||
extraSize += QSize(vTrimWidget->sizeHint().width(), hTrimWidget->sizeHint().height());
|
||||
}
|
||||
else {
|
||||
colvx = colvy = colvt;
|
||||
}
|
||||
|
||||
if (showBtns) {
|
||||
QVBoxLayout * btnbox = new QVBoxLayout();
|
||||
|
@ -106,8 +114,17 @@ VirtualJoystickWidget::VirtualJoystickWidget(QWidget *parent, QChar side, bool s
|
|||
if (showValues) {
|
||||
QLayout * valX = createNodeValueLayout('X', nodeLabelX);
|
||||
QLayout * valY = createNodeValueLayout('Y', nodeLabelY);
|
||||
layout->addLayout(valX, 2, colvx, 1, 1);
|
||||
layout->addLayout(valY, 2, colvy, 1, 1);
|
||||
if (!showTrims) {
|
||||
QVBoxLayout * vertXY = new QVBoxLayout();
|
||||
vertXY->addLayout(valX);
|
||||
vertXY->addLayout(valY);
|
||||
layout->addLayout(vertXY, 1, colvx, 1, 1);
|
||||
extraSize += QSize(nodeLabelX->sizeHint().width(), 0);
|
||||
}
|
||||
else {
|
||||
layout->addLayout(valX, 2, colvx, 1, 1);
|
||||
layout->addLayout(valY, 2, colvy, 1, 1);
|
||||
}
|
||||
}
|
||||
|
||||
layout->addItem(new QSpacerItem(0, 0), 0, 0, 1, 5); // r0 c0-4: top v spacer
|
||||
|
@ -119,7 +136,7 @@ VirtualJoystickWidget::VirtualJoystickWidget(QWidget *parent, QChar side, bool s
|
|||
connect(node, SIGNAL(xChanged()), this, SLOT(updateNodeValueLabels()));
|
||||
connect(node, SIGNAL(yChanged()), this, SLOT(updateNodeValueLabels()));
|
||||
|
||||
setSize(prefSize);
|
||||
setSize(prefSize, frameSize());
|
||||
}
|
||||
|
||||
void VirtualJoystickWidget::setStickX(qreal x)
|
||||
|
@ -144,12 +161,12 @@ void VirtualJoystickWidget::centerStick()
|
|||
|
||||
qreal VirtualJoystickWidget::getStickX()
|
||||
{
|
||||
return node->getX();
|
||||
return getStickPos().x();
|
||||
}
|
||||
|
||||
qreal VirtualJoystickWidget::getStickY()
|
||||
{
|
||||
return node->getY();
|
||||
return getStickPos().y();
|
||||
}
|
||||
|
||||
QPointF VirtualJoystickWidget::getStickPos()
|
||||
|
@ -205,7 +222,22 @@ void VirtualJoystickWidget::setStickConstraint(int which, bool active)
|
|||
}
|
||||
}
|
||||
|
||||
void VirtualJoystickWidget::setSize(QSize size)
|
||||
void VirtualJoystickWidget::setStickColor(const QColor & color)
|
||||
{
|
||||
node->setColor(color);
|
||||
}
|
||||
|
||||
QSize VirtualJoystickWidget::sizeHint() const {
|
||||
return prefSize;
|
||||
}
|
||||
|
||||
void VirtualJoystickWidget::resizeEvent(QResizeEvent * event)
|
||||
{
|
||||
QWidget::resizeEvent(event);
|
||||
setSize(event->size(), event->oldSize());
|
||||
}
|
||||
|
||||
void VirtualJoystickWidget::setSize(const QSize & size, const QSize &)
|
||||
{
|
||||
float thisAspectRatio = (float)size.width() / size.height();
|
||||
float newGvSz, spacerSz;
|
||||
|
@ -237,28 +269,24 @@ void VirtualJoystickWidget::setSize(QSize size)
|
|||
layout->setColumnStretch(2, newGvSz);
|
||||
layout->setRowStretch(1, newGvSz);
|
||||
|
||||
prefSize = QSize(newGvSz + extraSize.width(), newGvSz + extraSize.height());
|
||||
//prefSize = QSize(newGvSz + extraSize.width(), newGvSz + extraSize.height());
|
||||
gv->resize(newGvSz, newGvSz);
|
||||
gv->updateGeometry();
|
||||
repositionNode();
|
||||
//qDebug() << thisAspectRatio << size << newGvSz << spacerSz << extraSize << gv->geometry() << gv->contentsRect() << gv->frameRect() << getStickPos();
|
||||
}
|
||||
|
||||
void VirtualJoystickWidget::repositionNode()
|
||||
{
|
||||
QRect qr = gv->contentsRect();
|
||||
qreal w = (qreal)qr.width() - GBALL_SIZE;
|
||||
qreal h = (qreal)qr.height() - GBALL_SIZE;
|
||||
qreal cx = (qreal)qr.width()/2;
|
||||
qreal cy = (qreal)qr.height()/2;
|
||||
QRectF qr = (QRectF)gv->contentsRect();
|
||||
qreal w = qr.width() - GBALL_SIZE;
|
||||
qreal h = qr.height() - GBALL_SIZE;
|
||||
qreal cx = qr.width() / 2;
|
||||
qreal cy = qr.height() / 2;
|
||||
qreal nodeX = node->getX();
|
||||
qreal nodeY = node->getY();
|
||||
|
||||
scene->setSceneRect(-cx,-cy,w,h);
|
||||
|
||||
QPointF p = node->pos();
|
||||
p.setX(qMin(cx, qMax(p.x(), -cx)));
|
||||
p.setY(qMin(cy, qMax(p.y(), -cy)));
|
||||
node->setPos(p);
|
||||
node->setX(nodeX);
|
||||
node->setY(nodeY);
|
||||
|
||||
updateNodeValueLabels();
|
||||
//qDebug() << thisAspectRatio << size << newGvSz << spacerSz << extraSize << gv->geometry() << gv->contentsRect() << gv->frameRect() << getStickPos();
|
||||
}
|
||||
|
||||
QWidget *VirtualJoystickWidget::createTrimWidget(QChar type)
|
||||
|
@ -382,6 +410,7 @@ QLayout *VirtualJoystickWidget::createNodeValueLayout(QChar type, QLabel *& valL
|
|||
val->setObjectName(QString("val_%1").arg(type));
|
||||
val->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
|
||||
val->setAlignment(Qt::AlignCenter);
|
||||
val->setMinimumWidth(val->fontMetrics().width("-100 "));
|
||||
QVBoxLayout * layout = new QVBoxLayout();
|
||||
layout->setContentsMargins(2, 2, 2, 2);
|
||||
layout->setSpacing(2);
|
||||
|
|
|
@ -33,9 +33,6 @@
|
|||
class Node;
|
||||
class SliderWidget;
|
||||
|
||||
#define GBALL_SIZE 20
|
||||
#define RESX 1024
|
||||
|
||||
class VirtualJoystickWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
@ -55,7 +52,7 @@ class VirtualJoystickWidget : public QWidget
|
|||
FIX_Y
|
||||
};
|
||||
|
||||
explicit VirtualJoystickWidget(QWidget * parent = NULL, QChar side = 'L', bool showTrims = true, bool showBtns = true, bool showValues = true, QSize size = QSize(245, 245));
|
||||
explicit VirtualJoystickWidget(QWidget * parent = NULL, QChar side = 'L', bool showTrims = true, bool showBtns = true, bool showValues = true, QSize size = QSize(125, 125));
|
||||
|
||||
void setStickX(qreal x);
|
||||
void setStickY(qreal y);
|
||||
|
@ -70,17 +67,10 @@ class VirtualJoystickWidget : public QWidget
|
|||
int getTrimValue(int which);
|
||||
|
||||
void setStickConstraint(int which, bool active);
|
||||
void setStickColor(const QColor & color);
|
||||
|
||||
virtual QSize sizeHint() const
|
||||
{
|
||||
return prefSize;
|
||||
}
|
||||
|
||||
virtual void resizeEvent(QResizeEvent *event)
|
||||
{
|
||||
QWidget::resizeEvent(event);
|
||||
setSize(event->size());
|
||||
}
|
||||
virtual QSize sizeHint() const;
|
||||
virtual void resizeEvent(QResizeEvent *event);
|
||||
|
||||
signals:
|
||||
void trimButtonPressed(int which);
|
||||
|
@ -94,8 +84,7 @@ class VirtualJoystickWidget : public QWidget
|
|||
void updateNodeValueLabels();
|
||||
|
||||
protected:
|
||||
void setSize(QSize size);
|
||||
void repositionNode();
|
||||
void setSize(const QSize & size, const QSize &);
|
||||
QWidget * createTrimWidget(QChar type);
|
||||
QPushButton * createButtonWidget(int type);
|
||||
QLayout * createNodeValueLayout(QChar type, QLabel *& valLabel);
|
||||
|
|
|
@ -19,13 +19,14 @@
|
|||
*/
|
||||
|
||||
#include <QApplication>
|
||||
//#include <QTranslator>
|
||||
#include <QTranslator>
|
||||
#include <QLibraryInfo>
|
||||
#include <QLocale>
|
||||
#include <QString>
|
||||
#include <QDir>
|
||||
#include <QDebug>
|
||||
#include <QTextStream>
|
||||
#include <QDialog>
|
||||
#include <QMessageBox>
|
||||
#if defined(JOYSTICKS) || defined(SIMU_AUDIO)
|
||||
#include <SDL.h>
|
||||
#undef main
|
||||
|
@ -35,10 +36,11 @@
|
|||
#include "constants.h"
|
||||
#include "eeprominterface.h"
|
||||
#include "simulator.h"
|
||||
#include "simulatordialog.h"
|
||||
#include "simulatormainwindow.h"
|
||||
#include "simulatorstartupdialog.h"
|
||||
#include "storage.h"
|
||||
#include "qxtcommandoptions.h"
|
||||
#include "version.h"
|
||||
|
||||
#ifdef WIN32
|
||||
#include <windows.h>
|
||||
|
@ -50,21 +52,6 @@
|
|||
#include <unistd.h>
|
||||
#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;
|
||||
|
||||
int finish(int exitCode);
|
||||
|
@ -126,19 +113,12 @@ int main(int argc, char *argv[])
|
|||
|
||||
g.init();
|
||||
|
||||
#ifdef __APPLE__
|
||||
app.setStyle(new MyProxyStyle);
|
||||
#endif
|
||||
|
||||
/* QTranslator companionTranslator;
|
||||
companionTranslator.load(":/companion_" + locale);
|
||||
QTranslator companionTranslator;
|
||||
companionTranslator.load(":/companion_" + g.locale());
|
||||
QTranslator qtTranslator;
|
||||
qtTranslator.load((QString)"qt_" + locale.left(2), QLibraryInfo::location(QLibraryInfo::TranslationsPath));
|
||||
qtTranslator.load((QString)"qt_" + g.locale().left(2), QLibraryInfo::location(QLibraryInfo::TranslationsPath));
|
||||
app.installTranslator(&companionTranslator);
|
||||
app.installTranslator(&qtTranslator);
|
||||
*/
|
||||
|
||||
// QTextCodec::setCodecForCStrings(QTextCodec::codecForName("UTF-8"));
|
||||
|
||||
#if defined(JOYSTICKS) || defined(SIMU_AUDIO)
|
||||
uint32_t sdlFlags = 0;
|
||||
|
@ -269,23 +249,20 @@ int main(int argc, char *argv[])
|
|||
|
||||
current_firmware_variant = getFirmware(simOptions.firmwareId);
|
||||
|
||||
int oldProfId = g.id();
|
||||
g.id(profileId);
|
||||
g.sessionId(profileId);
|
||||
g.simuLastProfId(profileId);
|
||||
|
||||
int result = 1;
|
||||
SimulatorDialog * dialog = new SimulatorDialog(NULL, simulator, SIMULATOR_FLAGS_STANDALONE);
|
||||
dialog->setRadioProfileId(profileId);
|
||||
if (dialog->setOptions(simOptions, true)) {
|
||||
dialog->start();
|
||||
dialog->show();
|
||||
SimulatorMainWindow * mainWindow = new SimulatorMainWindow(NULL, simulator, SIMULATOR_FLAGS_STANDALONE);
|
||||
if (mainWindow->setOptions(simOptions, true)) {
|
||||
mainWindow->start();
|
||||
mainWindow->show();
|
||||
result = app.exec();
|
||||
}
|
||||
else {
|
||||
result = 3;
|
||||
}
|
||||
g.id(oldProfId);
|
||||
delete dialog;
|
||||
delete mainWindow;
|
||||
delete simulator;
|
||||
|
||||
return finish(result);
|
||||
|
|
|
@ -428,7 +428,9 @@ QString Profile::groupId()
|
|||
// ** AppData class********************
|
||||
|
||||
// Get declarations
|
||||
QStringList AppData::recentFiles() { return _recentFiles; }
|
||||
QStringList AppData::recentFiles() { return _recentFiles; }
|
||||
QStringList AppData::simuDbgFilters() { return _simuDbgFilters; }
|
||||
|
||||
QByteArray AppData::mainWinGeo() { return _mainWinGeo; }
|
||||
QByteArray AppData::mainWinState() { return _mainWinState; }
|
||||
QByteArray AppData::modelEditGeo() { return _modelEditGeo; }
|
||||
|
@ -475,9 +477,12 @@ int AppData::id() { return _id; }
|
|||
int AppData::theme() { return _theme; }
|
||||
int AppData::warningId() { return _warningId; }
|
||||
int AppData::simuLastProfId() { return _simuLastProfId; }
|
||||
int AppData::sessionId() { return _sessionId; }
|
||||
|
||||
// Set declarations
|
||||
void AppData::recentFiles (const QStringList x) { store(x, _recentFiles, "recentFileList" );}
|
||||
void AppData::simuDbgFilters (const QStringList x) { store(x, _simuDbgFilters, "simuDbgFilters" );}
|
||||
|
||||
void AppData::mainWinGeo (const QByteArray x) { store(x, _mainWinGeo, "mainWindowGeometry" );}
|
||||
void AppData::mainWinState (const QByteArray x) { store(x, _mainWinState, "mainWindowState" );}
|
||||
void AppData::modelEditGeo (const QByteArray x) { store(x, _modelEditGeo, "modelEditGeometry" );}
|
||||
|
@ -520,11 +525,19 @@ void AppData::generalEditTab (const int x) { store(x, _generalEditTab,
|
|||
void AppData::iconSize (const int x) { store(x, _iconSize, "icon_size" );}
|
||||
void AppData::historySize (const int x) { store(x, _historySize, "history_size" );}
|
||||
void AppData::jsCtrl (const int x) { store(x, _jsCtrl, "js_ctrl" );}
|
||||
void AppData::id (const int x) { store(x, _id, "profileId" );}
|
||||
void AppData::theme (const int x) { store(x, _theme, "theme" );}
|
||||
void AppData::warningId (const int x) { store(x, _warningId, "warningId" );}
|
||||
void AppData::simuLastProfId (const int x) { store(x, _simuLastProfId, "simuLastProfId" );}
|
||||
|
||||
void AppData::id(const int x)
|
||||
{
|
||||
store(x, _id, "profileId");
|
||||
sessionId(x);
|
||||
}
|
||||
|
||||
// currently loaded radio profile ID, NOT saved to persistent storage
|
||||
void AppData::sessionId (const int x) { _sessionId = x; }
|
||||
|
||||
// Constructor
|
||||
AppData::AppData()
|
||||
{
|
||||
|
@ -667,6 +680,8 @@ void AppData::init()
|
|||
getset( _tempString, "settings_version" ,"220" ); // This is a version marker. Will be used to upgrade the settings later on.
|
||||
|
||||
getset( _recentFiles, "recentFileList" ,"" );
|
||||
getset( _simuDbgFilters, "simuDbgFilters" ,"" );
|
||||
|
||||
getset( _mainWinGeo, "mainWindowGeometry" ,"" );
|
||||
getset( _mainWinState, "mainWindowState" ,"" );
|
||||
getset( _modelEditGeo, "modelEditGeometry" ,"" );
|
||||
|
@ -722,6 +737,7 @@ void AppData::init()
|
|||
getset( _warningId, "warningId" ,0 );
|
||||
getset( _simuLastProfId, "simuLastProfId" ,-1 );
|
||||
|
||||
sessionId(id());
|
||||
}
|
||||
|
||||
QMap<int, QString> AppData::getActiveProfiles()
|
||||
|
|
|
@ -250,6 +250,8 @@ class AppData: protected CompStoreObj
|
|||
|
||||
private:
|
||||
QStringList _recentFiles;
|
||||
QStringList _simuDbgFilters;
|
||||
|
||||
QByteArray _mainWinGeo;
|
||||
QByteArray _mainWinState;
|
||||
QByteArray _modelEditGeo;
|
||||
|
@ -296,10 +298,14 @@ class AppData: protected CompStoreObj
|
|||
int _theme;
|
||||
int _warningId;
|
||||
int _simuLastProfId;
|
||||
// currently loaded radio profile ID, NOT saved to persistent storage
|
||||
int _sessionId;
|
||||
|
||||
public:
|
||||
// All the get definitions
|
||||
QStringList recentFiles();
|
||||
QStringList simuDbgFilters();
|
||||
|
||||
QByteArray mainWinGeo();
|
||||
QByteArray mainWinState();
|
||||
QByteArray modelEditGeo();
|
||||
|
@ -347,9 +353,12 @@ class AppData: protected CompStoreObj
|
|||
int theme();
|
||||
int warningId();
|
||||
int simuLastProfId();
|
||||
int sessionId();
|
||||
|
||||
// All the set definitions
|
||||
void recentFiles (const QStringList x);
|
||||
void simuDbgFilters (const QStringList x);
|
||||
|
||||
void mainWinGeo (const QByteArray);
|
||||
void mainWinState (const QByteArray);
|
||||
void modelEditGeo (const QByteArray);
|
||||
|
@ -398,6 +407,7 @@ class AppData: protected CompStoreObj
|
|||
void theme (const int);
|
||||
void warningId (const int);
|
||||
void simuLastProfId (const int);
|
||||
void sessionId (const int);
|
||||
|
||||
// Constructor
|
||||
AppData();
|
||||
|
|
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@\Qt5Network.dll"
|
||||
File "@QT_DLL_DIR@\Qt5Multimedia.dll"
|
||||
File "@QT_DLL_DIR@\Qt5Svg.dll"
|
||||
File "@QT_DLL_DIR@\Qt5Xml.dll"
|
||||
|
||||
File "@SDL_DIR@\SDL.dll"
|
||||
|
@ -137,6 +138,7 @@ Section "OpenTX Companion" SecDummy
|
|||
|
||||
SetOutPath "$INSTDIR\imageformats"
|
||||
File "@QT_DLL_DIR@\..\plugins\imageformats\qjpeg.dll"
|
||||
File "@QT_DLL_DIR@\..\plugins\imageformats\qsvg.dll"
|
||||
|
||||
SetOutPath "$INSTDIR\mediaservice"
|
||||
File "@QT_DLL_DIR@\..\plugins\mediaservice\dsengine.dll"
|
||||
|
|
|
@ -18,6 +18,7 @@ RUN apt-get update && \
|
|||
qtmultimedia5-dev \
|
||||
qttools5-dev \
|
||||
qttools5-dev-tools \
|
||||
libqt5svg5-dev \
|
||||
software-properties-common \
|
||||
wget \
|
||||
zip \
|
||||
|
|