From 8074e4bc9473abfac93b09b9a8a8f70f7cadd944 Mon Sep 17 00:00:00 2001 From: Felix Date: Sat, 7 Mar 2026 23:51:16 +0100 Subject: [PATCH 01/16] Bulk migrate --- .gitignore | 1 + CMakeLists.txt | 1003 +++++++++++++++++ CMakePresets.json | 80 ++ QCodeEditor/src/internal/QCodeEditor.cpp | 2 +- application/template/main.qml | 8 +- bleuart.cpp | 55 +- boardsetupwindow.cpp | 2 +- configparams.cpp | 8 +- display_tool/dispeditor.cpp | 2 +- esp32/esp32flash.cpp | 4 +- main.cpp | 9 +- map/mapwidget.cpp | 4 +- mobile/AdcMap.qml | 6 +- mobile/BMS.qml | 6 +- mobile/BleSetupDialog.qml | 6 +- mobile/CanScreen.qml | 6 +- mobile/ConfigPageApp.qml | 8 +- mobile/ConfigPageCustom.qml | 8 +- mobile/ConfigPageMotor.qml | 10 +- mobile/ConnectScreen.qml | 12 +- mobile/Controls.qml | 14 +- mobile/CustomGauge.qml | 17 +- mobile/CustomGaugeV2.qml | 221 +--- mobile/DetectBldc.qml | 14 +- mobile/DetectFocEncoder.qml | 10 +- mobile/DetectFocHall.qml | 10 +- mobile/DetectFocParam.qml | 18 +- mobile/DirectionSetup.qml | 8 +- mobile/DirectoryPicker.qml | 112 +- mobile/FilePicker.qml | 112 +- mobile/FwUpdate.qml | 12 +- mobile/ImageButton.qml | 6 +- mobile/Lisp.qml | 12 +- mobile/LogBox.qml | 10 +- mobile/MultiSettings.qml | 10 +- mobile/NrfPair.qml | 8 +- mobile/Packages.qml | 12 +- mobile/PairingDialog.qml | 12 +- mobile/ParamEditBitfield.qml | 6 +- mobile/ParamEditBool.qml | 6 +- mobile/ParamEditDouble.qml | 12 +- mobile/ParamEditEnum.qml | 10 +- mobile/ParamEditInt.qml | 10 +- mobile/ParamEditSeparator.qml | 10 +- mobile/ParamEditString.qml | 6 +- mobile/ParamEditors.qml | 8 +- mobile/ParamList.qml | 8 +- mobile/ParamListScroll.qml | 8 +- mobile/PpmMap.qml | 6 +- mobile/ProfileDisplay.qml | 8 +- mobile/ProfileEditor.qml | 26 +- mobile/Profiles.qml | 19 +- mobile/RtData.qml | 6 +- mobile/RtDataIMU.qml | 6 +- mobile/RtDataSetup.qml | 49 +- mobile/Settings.qml | 8 +- mobile/SetupWizardFoc.qml | 56 +- mobile/SetupWizardIMU.qml | 12 +- mobile/SetupWizardInput.qml | 18 +- mobile/SetupWizardIntro.qml | 18 +- mobile/StartPage.qml | 12 +- mobile/StatPage.qml | 6 +- mobile/TcpBox.qml | 6 +- mobile/TcpHubBox.qml | 8 +- mobile/Terminal.qml | 6 +- mobile/Vesc3DView.qml | 10 +- ...oubleSpinBox.qml => VescDoubleSpinBox.qml} | 4 +- mobile/main.qml | 12 +- mobile/qml.qrc | 2 +- pages/pageappsettings.cpp | 3 +- pages/pagedataanalysis.cpp | 3 +- pages/pageexperiments.cpp | 2 +- pages/pageloganalysis.cpp | 2 +- pages/pagemotorcomparison.cpp | 28 +- pages/pagemotorsettings.cpp | 3 +- pages/pagesampleddata.cpp | 2 +- qmarkdowntextedit/examples/qml/example.qml | 4 +- qmarkdowntextedit/markdownhighlighter.cpp | 15 +- qmarkdowntextedit/qmarkdowntextedit.cpp | 4 - .../qplaintexteditsearchwidget.cpp | 15 - res/qml/DynamicLoader.qml | 8 +- res/qml/Examples/BMS.qml | 8 +- res/qml/Examples/BalanceUi.qml | 6 +- res/qml/Examples/BrakeBench.qml | 14 +- res/qml/Examples/CanDebugger.qml | 8 +- res/qml/Examples/ConfigParams.qml | 6 +- res/qml/Examples/Controls.qml | 24 +- res/qml/Examples/DCDC.qml | 8 +- res/qml/Examples/ExperimentPlot.qml | 8 +- res/qml/Examples/GaugeTest.qml | 8 +- res/qml/Examples/IoBoard.qml | 8 +- res/qml/Examples/LogTextToFile.qml | 8 +- res/qml/Examples/MMXGui.qml | 8 +- res/qml/Examples/Meters.qml | 8 +- res/qml/Examples/MotorComparisonModel.qml | 8 +- res/qml/Examples/Mp3Stream.qml | 8 +- res/qml/Examples/ParamTableAndPlot.qml | 6 +- res/qml/Examples/ParentTabBar.qml | 8 +- res/qml/Examples/PollValues.qml | 8 +- res/qml/Examples/PositionControl.qml | 8 +- res/qml/Examples/Profiles.qml | 14 +- res/qml/Examples/Reconnect.qml | 8 +- res/qml/Examples/RpmSlider.qml | 8 +- res/qml/Examples/RtData.qml | 8 +- res/qml/Examples/RtDataSetup.qml | 13 +- res/qml/Examples/SendToLbm.qml | 6 +- res/qml/Examples/TcpHub.qml | 8 +- res/qml/Examples/TcpServer.qml | 8 +- res/qml/Examples/UdpServer.qml | 6 +- res/qml/MainLoader.qml | 10 +- res/qml/SetupMotorWindow.qml | 10 +- res/qml/WelcomeQmlPanel.qml | 16 +- tcpserversimple.cpp | 8 +- utility.cpp | 92 +- vescinterface.cpp | 28 +- vescinterface.h | 8 +- widgets/canlistitem.cpp | 2 +- widgets/experimentplot.cpp | 2 +- widgets/mrichtextedit.cpp | 27 +- widgets/pagelistitem.cpp | 2 +- widgets/qcustomplot.h | 34 +- widgets/vesc3dview.cpp | 45 +- widgets/vesc3dview.h | 1 + 123 files changed, 1866 insertions(+), 995 deletions(-) create mode 100644 CMakeLists.txt create mode 100644 CMakePresets.json rename mobile/{DoubleSpinBox.qml => VescDoubleSpinBox.qml} (98%) diff --git a/.gitignore b/.gitignore index 71ff82340..c5576bb61 100644 --- a/.gitignore +++ b/.gitignore @@ -34,6 +34,7 @@ target_wrapper.* # QtCreator *.autosave +.qtcreator/ # QtCreator Qml *.qmlproject.user diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 000000000..68ae6b2f0 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,1003 @@ +cmake_minimum_required(VERSION 3.16) + +# --------------------------------------------------------------------------- +# Version & Git commit +# --------------------------------------------------------------------------- +set(VT_VERSION "7.00") +set(VT_INTRO_VERSION "1") +set(VT_CONFIG_VERSION "4") +# Set to 0 for stable releases, test version number for development builds +set(VT_IS_TEST_VERSION "2") + +execute_process( + COMMAND git rev-parse --short=8 HEAD + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + OUTPUT_VARIABLE VT_GIT_COMMIT + OUTPUT_STRIP_TRAILING_WHITESPACE + ERROR_QUIET +) +if(NOT VT_GIT_COMMIT) + set(VT_GIT_COMMIT "00000000") +endif() + +# Android version codes +set(VT_ANDROID_VERSION_ARMV7 190) +set(VT_ANDROID_VERSION_ARM64 191) +set(VT_ANDROID_VERSION_X86 192) + +project(vesc_tool VERSION ${VT_VERSION} LANGUAGES C CXX) + +# --------------------------------------------------------------------------- +# C++ standard +# --------------------------------------------------------------------------- +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +# --------------------------------------------------------------------------- +# Qt6 – find all potentially-needed components up-front +# --------------------------------------------------------------------------- +set(CMAKE_AUTOMOC ON) +set(CMAKE_AUTOUIC ON) +set(CMAKE_AUTORCC ON) + +# Core set of Qt modules always required +set(QT_COMPONENTS + Core + Gui + Widgets + Network + Quick + QuickControls2 + QuickWidgets + Svg + PrintSupport + OpenGL + OpenGLWidgets + Core5Compat +) + +# --------------------------------------------------------------------------- +# User-toggleable options (mirror the old qmake CONFIG / DEFINES) +# --------------------------------------------------------------------------- +option(HAS_BLUETOOTH "Enable Bluetooth support" ON) +option(HAS_SERIALPORT "Enable serial port support" ON) +option(HAS_GAMEPAD "Enable gamepad support" ON) +option(HAS_CANBUS "Enable CAN bus (serialbus)" OFF) +option(HAS_POS "Enable positioning support" ON) +option(BUILD_MOBILE "Build the mobile (QML) GUI" OFF) +option(EXCLUDE_FW "Exclude built-in firmwares" ON) + +# Build tier (pick one; default = neutral) +set(BUILD_TIER "neutral" CACHE STRING "Build tier: original, platinum, gold, silver, bronze, free, neutral") +set_property(CACHE BUILD_TIER PROPERTY STRINGS original platinum gold silver bronze free neutral) + +# Platform-specific defaults +if(WIN32) + set(HAS_POS OFF) +endif() +if(ANDROID) + set(HAS_SERIALPORT OFF) + # HAS_GAMEPAD stays ON via QtGamepadLegacy +endif() +if(IOS) + set(HAS_SERIALPORT OFF) + set(BUILD_MOBILE ON) +endif() + +# Append optional Qt components +if(HAS_SERIALPORT) + list(APPEND QT_COMPONENTS SerialPort) +endif() +if(HAS_CANBUS) + list(APPEND QT_COMPONENTS SerialBus) +endif() +if(HAS_BLUETOOTH) + list(APPEND QT_COMPONENTS Bluetooth) +endif() +if(HAS_POS) + list(APPEND QT_COMPONENTS Positioning) +endif() +find_package(Qt6 REQUIRED COMPONENTS ${QT_COMPONENTS}) +# We need GuiPrivate for some internals +find_package(Qt6 REQUIRED COMPONENTS GuiPrivate) + +# Qt6 dropped QtGamepad – use QtGamepadLegacy (pumphaus/qtgamepadlegacy). +# Build & install it into your Qt prefix first, then it becomes available +# as the "GamepadLegacy" component. +if(HAS_GAMEPAD) + find_package(Qt6 QUIET COMPONENTS GamepadLegacy) + if(NOT TARGET Qt6::GamepadLegacy) + message(WARNING + "Qt6::GamepadLegacy not found – gamepad support disabled.\n" + " To enable it, build & install https://github.com/pumphaus/qtgamepadlegacy\n" + " into your Qt prefix (${Qt6_DIR}/../../..) and re-run CMake.") + set(HAS_GAMEPAD OFF) + else() + message(STATUS "Found Qt6::GamepadLegacy – gamepad support enabled.") + endif() +endif() + +# --------------------------------------------------------------------------- +# Compile definitions shared across the whole target +# --------------------------------------------------------------------------- +set(VT_DEFINITIONS + VT_VERSION=${VT_VERSION} + VT_INTRO_VERSION=${VT_INTRO_VERSION} + VT_CONFIG_VERSION=${VT_CONFIG_VERSION} + VT_IS_TEST_VERSION=${VT_IS_TEST_VERSION} + VT_GIT_COMMIT=${VT_GIT_COMMIT} +) + +if(HAS_BLUETOOTH) + list(APPEND VT_DEFINITIONS HAS_BLUETOOTH) +endif() +if(HAS_SERIALPORT) + list(APPEND VT_DEFINITIONS HAS_SERIALPORT) +endif() +if(HAS_GAMEPAD) + list(APPEND VT_DEFINITIONS HAS_GAMEPAD) +endif() +if(HAS_CANBUS) + list(APPEND VT_DEFINITIONS HAS_CANBUS) +endif() +if(HAS_POS) + list(APPEND VT_DEFINITIONS HAS_POS) +endif() +if(BUILD_MOBILE) + list(APPEND VT_DEFINITIONS USE_MOBILE) +endif() +if(WIN32) + list(APPEND VT_DEFINITIONS _USE_MATH_DEFINES) +endif() + +# Build-tier defines & resources +if(BUILD_TIER STREQUAL "original") + list(APPEND VT_DEFINITIONS VER_ORIGINAL) + set(TIER_QRC res_original.qrc) +elseif(BUILD_TIER STREQUAL "platinum") + list(APPEND VT_DEFINITIONS VER_PLATINUM) + set(TIER_QRC res_platinum.qrc) +elseif(BUILD_TIER STREQUAL "gold") + list(APPEND VT_DEFINITIONS VER_GOLD) + set(TIER_QRC res_gold.qrc) +elseif(BUILD_TIER STREQUAL "silver") + list(APPEND VT_DEFINITIONS VER_SILVER) + set(TIER_QRC res_silver.qrc) +elseif(BUILD_TIER STREQUAL "bronze") + list(APPEND VT_DEFINITIONS VER_BRONZE) + set(TIER_QRC res_bronze.qrc) +elseif(BUILD_TIER STREQUAL "free") + list(APPEND VT_DEFINITIONS VER_FREE) + set(TIER_QRC res_free.qrc) +else() + list(APPEND VT_DEFINITIONS VER_NEUTRAL) + set(TIER_QRC res_neutral.qrc) +endif() + +# --------------------------------------------------------------------------- +# Sources – root +# --------------------------------------------------------------------------- +set(ROOT_SOURCES + main.cpp + bleuartdummy.cpp + codeloader.cpp + mainwindow.cpp + boardsetupwindow.cpp + packet.cpp + preferences.cpp + tcphub.cpp + udpserversimple.cpp + vbytearray.cpp + commands.cpp + configparams.cpp + configparam.cpp + vescinterface.cpp + parametereditor.cpp + digitalfiltering.cpp + setupwizardapp.cpp + setupwizardmotor.cpp + startupwizard.cpp + utility.cpp + tcpserversimple.cpp + hexfile.cpp +) + +set(ROOT_HEADERS + mainwindow.h + bleuartdummy.h + codeloader.h + boardsetupwindow.h + packet.h + preferences.h + tcphub.h + udpserversimple.h + vbytearray.h + commands.h + datatypes.h + configparams.h + configparam.h + vescinterface.h + parametereditor.h + digitalfiltering.h + setupwizardapp.h + setupwizardmotor.h + startupwizard.h + utility.h + tcpserversimple.h + hexfile.h +) + +set(ROOT_FORMS + mainwindow.ui + boardsetupwindow.ui + parametereditor.ui + preferences.ui +) + +# Platform-specific root sources +if(UNIX AND NOT IOS) + list(APPEND ROOT_HEADERS systemcommandexecutor.h) +endif() +if(HAS_BLUETOOTH) + list(APPEND ROOT_SOURCES bleuart.cpp) + list(APPEND ROOT_HEADERS bleuart.h) +endif() + +# --------------------------------------------------------------------------- +# Sources – pages/ +# --------------------------------------------------------------------------- +set(PAGES_SOURCES + pages/pageapppas.cpp + pages/pagebms.cpp + pages/pagecananalyzer.cpp + pages/pageconnection.cpp + pages/pagecustomconfig.cpp + pages/pagedisplaytool.cpp + pages/pageespprog.cpp + pages/pagelisp.cpp + pages/pagemotor.cpp + pages/pagedebugprint.cpp + pages/pagebldc.cpp + pages/pageappgeneral.cpp + pages/pagedc.cpp + pages/pagefoc.cpp + pages/pagecontrollers.cpp + pages/pageappppm.cpp + pages/pageappadc.cpp + pages/pageappuart.cpp + pages/pageappnunchuk.cpp + pages/pageappnrf.cpp + pages/pagemotorcomparison.cpp + pages/pagescripting.cpp + pages/pageterminal.cpp + pages/pagefirmware.cpp + pages/pagertdata.cpp + pages/pagesampleddata.cpp + pages/pagevescpackage.cpp + pages/pagewelcome.cpp + pages/pagemotorsettings.cpp + pages/pageappsettings.cpp + pages/pagedataanalysis.cpp + pages/pagemotorinfo.cpp + pages/pagesetupcalculators.cpp + pages/pagegpd.cpp + pages/pageexperiments.cpp + pages/pageimu.cpp + pages/pageswdprog.cpp + pages/pageappimu.cpp + pages/pageloganalysis.cpp +) + +set(PAGES_HEADERS + pages/pageapppas.h + pages/pagebms.h + pages/pagecananalyzer.h + pages/pageconnection.h + pages/pagecustomconfig.h + pages/pagedisplaytool.h + pages/pageespprog.h + pages/pagelisp.h + pages/pagemotor.h + pages/pagedebugprint.h + pages/pagebldc.h + pages/pageappgeneral.h + pages/pagedc.h + pages/pagefoc.h + pages/pagecontrollers.h + pages/pageappppm.h + pages/pageappadc.h + pages/pageappuart.h + pages/pageappnunchuk.h + pages/pageappnrf.h + pages/pagemotorcomparison.h + pages/pagescripting.h + pages/pageterminal.h + pages/pagefirmware.h + pages/pagertdata.h + pages/pagesampleddata.h + pages/pagevescpackage.h + pages/pagewelcome.h + pages/pagemotorsettings.h + pages/pageappsettings.h + pages/pagedataanalysis.h + pages/pagemotorinfo.h + pages/pagesetupcalculators.h + pages/pagegpd.h + pages/pageexperiments.h + pages/pageimu.h + pages/pageswdprog.h + pages/pageappimu.h + pages/pageloganalysis.h +) + +set(PAGES_FORMS + pages/pageapppas.ui + pages/pagebms.ui + pages/pagecananalyzer.ui + pages/pageconnection.ui + pages/pagecustomconfig.ui + pages/pagedisplaytool.ui + pages/pageespprog.ui + pages/pagelisp.ui + pages/pagemotor.ui + pages/pagedebugprint.ui + pages/pagebldc.ui + pages/pageappgeneral.ui + pages/pagedc.ui + pages/pagefoc.ui + pages/pagecontrollers.ui + pages/pageappppm.ui + pages/pageappadc.ui + pages/pageappuart.ui + pages/pageappnunchuk.ui + pages/pageappnrf.ui + pages/pagemotorcomparison.ui + pages/pagescripting.ui + pages/pageterminal.ui + pages/pagefirmware.ui + pages/pagertdata.ui + pages/pagesampleddata.ui + pages/pagevescpackage.ui + pages/pagewelcome.ui + pages/pagemotorsettings.ui + pages/pageappsettings.ui + pages/pagedataanalysis.ui + pages/pagemotorinfo.ui + pages/pagesetupcalculators.ui + pages/pagegpd.ui + pages/pageexperiments.ui + pages/pageimu.ui + pages/pageswdprog.ui + pages/pageappimu.ui + pages/pageloganalysis.ui +) + +# --------------------------------------------------------------------------- +# Sources – widgets/ +# --------------------------------------------------------------------------- +set(WIDGETS_SOURCES + widgets/batttempplot.cpp + widgets/canlistitem.cpp + widgets/experimentplot.cpp + widgets/parameditbitfield.cpp + widgets/parameditbool.cpp + widgets/parameditdouble.cpp + widgets/parameditenum.cpp + widgets/parameditint.cpp + widgets/displaybar.cpp + widgets/displaypercentage.cpp + widgets/helpdialog.cpp + widgets/mrichtextedit.cpp + widgets/mtextedit.cpp + widgets/pagelistitem.cpp + widgets/paramtable.cpp + widgets/qcustomplot.cpp + widgets/detectbldc.cpp + widgets/batterycalculator.cpp + widgets/detectfoc.cpp + widgets/detectfocencoder.cpp + widgets/detectfochall.cpp + widgets/ppmmap.cpp + widgets/adcmap.cpp + widgets/rtdatatext.cpp + widgets/nrfpair.cpp + widgets/scripteditor.cpp + widgets/vtextbrowser.cpp + widgets/imagewidget.cpp + widgets/parameditstring.cpp + widgets/paramdialog.cpp + widgets/aspectimglabel.cpp + widgets/historylineedit.cpp + widgets/detectallfocdialog.cpp + widgets/dirsetup.cpp + widgets/vesc3dview.cpp + widgets/superslider.cpp +) + +set(WIDGETS_HEADERS + widgets/batttempplot.h + widgets/canlistitem.h + widgets/experimentplot.h + widgets/parameditbitfield.h + widgets/parameditbool.h + widgets/parameditdouble.h + widgets/parameditenum.h + widgets/parameditint.h + widgets/displaybar.h + widgets/displaypercentage.h + widgets/helpdialog.h + widgets/mrichtextedit.h + widgets/mtextedit.h + widgets/pagelistitem.h + widgets/paramtable.h + widgets/qcustomplot.h + widgets/detectbldc.h + widgets/batterycalculator.h + widgets/detectfoc.h + widgets/detectfocencoder.h + widgets/detectfochall.h + widgets/ppmmap.h + widgets/adcmap.h + widgets/rtdatatext.h + widgets/nrfpair.h + widgets/scripteditor.h + widgets/vtextbrowser.h + widgets/imagewidget.h + widgets/parameditstring.h + widgets/paramdialog.h + widgets/aspectimglabel.h + widgets/historylineedit.h + widgets/detectallfocdialog.h + widgets/dirsetup.h + widgets/vesc3dview.h + widgets/superslider.h +) + +set(WIDGETS_FORMS + widgets/experimentplot.ui + widgets/parameditbitfield.ui + widgets/parameditbool.ui + widgets/parameditdouble.ui + widgets/parameditenum.ui + widgets/parameditint.ui + widgets/mrichtextedit.ui + widgets/helpdialog.ui + widgets/detectbldc.ui + widgets/batterycalculator.ui + widgets/detectfoc.ui + widgets/detectfocencoder.ui + widgets/detectfochall.ui + widgets/ppmmap.ui + widgets/adcmap.ui + widgets/nrfpair.ui + widgets/parameditstring.ui + widgets/paramdialog.ui + widgets/detectallfocdialog.ui + widgets/dirsetup.ui + widgets/scripteditor.ui +) + +# --------------------------------------------------------------------------- +# Sources – mobile/ +# --------------------------------------------------------------------------- +set(MOBILE_SOURCES + mobile/logreader.cpp + mobile/logwriter.cpp + mobile/qmlui.cpp + mobile/fwhelper.cpp + mobile/vesc3ditem.cpp +) + +set(MOBILE_HEADERS + mobile/logreader.h + mobile/logwriter.h + mobile/qmlui.h + mobile/fwhelper.h + mobile/vesc3ditem.h +) + +# --------------------------------------------------------------------------- +# Sources – map/ +# --------------------------------------------------------------------------- +set(MAP_SOURCES + map/carinfo.cpp + map/copterinfo.cpp + map/locpoint.cpp + map/mapwidget.cpp + map/osmclient.cpp + map/osmtile.cpp + map/perspectivepixmap.cpp +) + +set(MAP_HEADERS + map/carinfo.h + map/copterinfo.h + map/locpoint.h + map/mapwidget.h + map/osmclient.h + map/osmtile.h + map/perspectivepixmap.h +) + +# --------------------------------------------------------------------------- +# Sources – lzokay/ +# --------------------------------------------------------------------------- +set(LZOKAY_SOURCES lzokay/lzokay.cpp) +set(LZOKAY_HEADERS lzokay/lzokay.hpp) + +# --------------------------------------------------------------------------- +# Sources – heatshrink/ (mixed C and C++) +# --------------------------------------------------------------------------- +set(HEATSHRINK_SOURCES + heatshrink/heatshrink_decoder.c + heatshrink/heatshrink_encoder.c + heatshrink/heatshrinkif.cpp +) + +set(HEATSHRINK_HEADERS + heatshrink/heatshrink_common.h + heatshrink/heatshrink_config.h + heatshrink/heatshrink_decoder.h + heatshrink/heatshrink_encoder.h + heatshrink/heatshrinkif.h +) + +# --------------------------------------------------------------------------- +# Sources – QCodeEditor/ +# --------------------------------------------------------------------------- +set(QCODEEDITOR_SOURCES + QCodeEditor/src/internal/LispHighlighter.cpp + QCodeEditor/src/internal/QCodeEditor.cpp + QCodeEditor/src/internal/QCXXHighlighter.cpp + QCodeEditor/src/internal/QFramedTextAttribute.cpp + QCodeEditor/src/internal/QGLSLCompleter.cpp + QCodeEditor/src/internal/QGLSLHighlighter.cpp + QCodeEditor/src/internal/QJSONHighlighter.cpp + QCodeEditor/src/internal/QLanguage.cpp + QCodeEditor/src/internal/QLineNumberArea.cpp + QCodeEditor/src/internal/QLispCompleter.cpp + QCodeEditor/src/internal/QLuaCompleter.cpp + QCodeEditor/src/internal/QLuaHighlighter.cpp + QCodeEditor/src/internal/QPythonCompleter.cpp + QCodeEditor/src/internal/QPythonHighlighter.cpp + QCodeEditor/src/internal/QStyleSyntaxHighlighter.cpp + QCodeEditor/src/internal/QSyntaxStyle.cpp + QCodeEditor/src/internal/QXMLHighlighter.cpp + QCodeEditor/src/internal/QmlHighlighter.cpp + QCodeEditor/src/internal/QVescCompleter.cpp +) + +set(QCODEEDITOR_HEADERS + QCodeEditor/include/internal/LispHighlighter.hpp + QCodeEditor/include/internal/QCodeEditor.hpp + QCodeEditor/include/internal/QCXXHighlighter.hpp + QCodeEditor/include/internal/QFramedTextAttribute.hpp + QCodeEditor/include/internal/QGLSLCompleter.hpp + QCodeEditor/include/internal/QGLSLHighlighter.hpp + QCodeEditor/include/internal/QHighlightBlockRule.hpp + QCodeEditor/include/internal/QHighlightRule.hpp + QCodeEditor/include/internal/QJSONHighlighter.hpp + QCodeEditor/include/internal/QLanguage.hpp + QCodeEditor/include/internal/QLineNumberArea.hpp + QCodeEditor/include/internal/QLispCompleter.hpp + QCodeEditor/include/internal/QLuaCompleter.hpp + QCodeEditor/include/internal/QLuaHighlighter.hpp + QCodeEditor/include/internal/QPythonCompleter.hpp + QCodeEditor/include/internal/QPythonHighlighter.hpp + QCodeEditor/include/internal/QStyleSyntaxHighlighter.hpp + QCodeEditor/include/internal/QSyntaxStyle.hpp + QCodeEditor/include/internal/QXMLHighlighter.hpp + QCodeEditor/include/internal/QmlHighlighter.hpp + QCodeEditor/include/internal/QVescCompleter.hpp +) + +# --------------------------------------------------------------------------- +# Sources – esp32/ (mixed C and C++) +# --------------------------------------------------------------------------- +set(ESP32_SOURCES + esp32/esp32flash.cpp + esp32/esp_loader.c + esp32/esp_targets.c + esp32/md5_hash.c + esp32/serial_comm.c +) + +set(ESP32_HEADERS + esp32/esp32flash.h + esp32/esp_loader.h + esp32/esp_targets.h + esp32/md5_hash.h + esp32/serial_comm.h + esp32/serial_comm_prv.h + esp32/serial_io.h +) + +# --------------------------------------------------------------------------- +# Sources – display_tool/ +# --------------------------------------------------------------------------- +set(DISPLAY_TOOL_SOURCES + display_tool/dispeditor.cpp + display_tool/displayedit.cpp + display_tool/imagewidgetdisp.cpp +) + +set(DISPLAY_TOOL_HEADERS + display_tool/dispeditor.h + display_tool/displayedit.h + display_tool/imagewidgetdisp.h +) + +set(DISPLAY_TOOL_FORMS + display_tool/dispeditor.ui +) + +# --------------------------------------------------------------------------- +# Sources – qmarkdowntextedit/ +# --------------------------------------------------------------------------- +set(QMARKDOWNTEXTEDIT_SOURCES + qmarkdowntextedit/markdownhighlighter.cpp + qmarkdowntextedit/qmarkdowntextedit.cpp + qmarkdowntextedit/qownlanguagedata.cpp + qmarkdowntextedit/qplaintexteditsearchwidget.cpp +) + +set(QMARKDOWNTEXTEDIT_HEADERS + qmarkdowntextedit/linenumberarea.h + qmarkdowntextedit/markdownhighlighter.h + qmarkdowntextedit/qmarkdowntextedit.h + qmarkdowntextedit/qownlanguagedata.h + qmarkdowntextedit/qplaintexteditsearchwidget.h +) + +set(QMARKDOWNTEXTEDIT_FORMS + qmarkdowntextedit/qplaintexteditsearchwidget.ui +) + +# --------------------------------------------------------------------------- +# Sources – maddy/ (header-only markdown parser) +# --------------------------------------------------------------------------- +set(MADDY_HEADERS + maddy/blockparser.h + maddy/breaklineparser.h + maddy/checklistparser.h + maddy/codeblockparser.h + maddy/emphasizedparser.h + maddy/headlineparser.h + maddy/horizontallineparser.h + maddy/htmlparser.h + maddy/imageparser.h + maddy/inlinecodeparser.h + maddy/italicparser.h + maddy/latexblockparser.h + maddy/orderedlistparser.h + maddy/paragraphparser.h + maddy/parserconfig.h + maddy/parser.h + maddy/quoteparser.h + maddy/strikethroughparser.h + maddy/strongparser.h + maddy/tableparser.h + maddy/unorderedlistparser.h + maddy/lineparser.h + maddy/linkparser.h +) + +# --------------------------------------------------------------------------- +# Sources – minimp3/ +# --------------------------------------------------------------------------- +set(MINIMP3_SOURCES minimp3/qminimp3.cpp) +set(MINIMP3_HEADERS + minimp3/minimp3.h + minimp3/minimp3_ex.h + minimp3/qminimp3.h +) + +# --------------------------------------------------------------------------- +# Sources – iOS-specific +# --------------------------------------------------------------------------- +if(IOS) + set(IOS_SOURCES ios/src/setIosParameters.mm) + set(IOS_HEADERS ios/src/setIosParameters.h) +else() + set(IOS_SOURCES) + set(IOS_HEADERS) +endif() + +# --------------------------------------------------------------------------- +# Resource files (.qrc) +# --------------------------------------------------------------------------- +set(RESOURCE_FILES + res.qrc + res_custom_module.qrc + res_lisp.qrc + res_qml.qrc + res/config/res_config.qrc + res_fw_bms.qrc + mobile/qml.qrc + qmarkdowntextedit/media.qrc + QCodeEditor/resources/qcodeeditor_resources.qrc + ${TIER_QRC} +) + +if(NOT EXCLUDE_FW) + list(APPEND RESOURCE_FILES res/firmwares/res_fw.qrc) +endif() + +# --------------------------------------------------------------------------- +# Collect all sources +# --------------------------------------------------------------------------- +set(ALL_SOURCES + ${ROOT_SOURCES} + ${PAGES_SOURCES} + ${WIDGETS_SOURCES} + ${MOBILE_SOURCES} + ${MAP_SOURCES} + ${LZOKAY_SOURCES} + ${HEATSHRINK_SOURCES} + ${QCODEEDITOR_SOURCES} + ${ESP32_SOURCES} + ${DISPLAY_TOOL_SOURCES} + ${QMARKDOWNTEXTEDIT_SOURCES} + ${MINIMP3_SOURCES} + ${IOS_SOURCES} +) + +set(ALL_HEADERS + ${ROOT_HEADERS} + ${PAGES_HEADERS} + ${WIDGETS_HEADERS} + ${MOBILE_HEADERS} + ${MAP_HEADERS} + ${LZOKAY_HEADERS} + ${HEATSHRINK_HEADERS} + ${QCODEEDITOR_HEADERS} + ${ESP32_HEADERS} + ${DISPLAY_TOOL_HEADERS} + ${QMARKDOWNTEXTEDIT_HEADERS} + ${MADDY_HEADERS} + ${MINIMP3_HEADERS} + ${IOS_HEADERS} +) + +set(ALL_FORMS + ${ROOT_FORMS} + ${PAGES_FORMS} + ${WIDGETS_FORMS} + ${DISPLAY_TOOL_FORMS} + ${QMARKDOWNTEXTEDIT_FORMS} +) + +# --------------------------------------------------------------------------- +# Target name (mirrors old qmake logic) +# --------------------------------------------------------------------------- +if(IOS OR APPLE) + set(APP_TARGET "VESC Tool") +elseif(ANDROID) + set(APP_TARGET "vesc_tool") +else() + set(APP_TARGET "vesc_tool_${VT_VERSION}") +endif() + +# --------------------------------------------------------------------------- +# Create the executable +# --------------------------------------------------------------------------- +qt_add_executable(${APP_TARGET} + ${ALL_SOURCES} + ${ALL_HEADERS} + ${ALL_FORMS} + ${RESOURCE_FILES} +) + +# --------------------------------------------------------------------------- +# Compile definitions +# --------------------------------------------------------------------------- +target_compile_definitions(${APP_TARGET} PRIVATE ${VT_DEFINITIONS}) + +# --------------------------------------------------------------------------- +# Include directories +# --------------------------------------------------------------------------- +target_include_directories(${APP_TARGET} PRIVATE + ${CMAKE_SOURCE_DIR} + ${CMAKE_SOURCE_DIR}/pages + ${CMAKE_SOURCE_DIR}/widgets + ${CMAKE_SOURCE_DIR}/mobile + ${CMAKE_SOURCE_DIR}/map + ${CMAKE_SOURCE_DIR}/lzokay + ${CMAKE_SOURCE_DIR}/heatshrink + ${CMAKE_SOURCE_DIR}/QCodeEditor/include + ${CMAKE_SOURCE_DIR}/esp32 + ${CMAKE_SOURCE_DIR}/display_tool + ${CMAKE_SOURCE_DIR}/qmarkdowntextedit + ${CMAKE_SOURCE_DIR}/maddy + ${CMAKE_SOURCE_DIR}/minimp3 + # AUTOUIC needs to find generated ui_*.h files + ${CMAKE_CURRENT_BINARY_DIR} +) + +# --------------------------------------------------------------------------- +# Link Qt libraries +# --------------------------------------------------------------------------- +set(QT_LINK_LIBS + Qt6::Core + Qt6::Gui + Qt6::Widgets + Qt6::Network + Qt6::Quick + Qt6::QuickControls2 + Qt6::QuickWidgets + Qt6::Svg + Qt6::GuiPrivate + Qt6::OpenGL + Qt6::OpenGLWidgets + Qt6::Core5Compat +) + +if(NOT IOS) + list(APPEND QT_LINK_LIBS Qt6::PrintSupport) +endif() + +if(HAS_SERIALPORT) + list(APPEND QT_LINK_LIBS Qt6::SerialPort) +endif() +if(HAS_CANBUS) + list(APPEND QT_LINK_LIBS Qt6::SerialBus) +endif() +if(HAS_BLUETOOTH) + list(APPEND QT_LINK_LIBS Qt6::Bluetooth) +endif() +if(HAS_POS) + list(APPEND QT_LINK_LIBS Qt6::Positioning) +endif() +if(HAS_GAMEPAD) + list(APPEND QT_LINK_LIBS Qt6::GamepadLegacy) +endif() + +target_link_libraries(${APP_TARGET} PRIVATE ${QT_LINK_LIBS}) + +# --------------------------------------------------------------------------- +# Compiler flags +# --------------------------------------------------------------------------- +if(NOT MSVC) + target_compile_options(${APP_TARGET} PRIVATE + -Wno-deprecated-copy + ) +endif() + +if(IOS) + target_compile_options(${APP_TARGET} PRIVATE + $<$:-Wall> + ) +endif() + +# --------------------------------------------------------------------------- +# AUTOUIC search paths (so AUTOUIC can find .ui files in subdirectories) +# --------------------------------------------------------------------------- +set_target_properties(${APP_TARGET} PROPERTIES + AUTOUIC_SEARCH_PATHS + "${CMAKE_SOURCE_DIR};${CMAKE_SOURCE_DIR}/pages;${CMAKE_SOURCE_DIR}/widgets;${CMAKE_SOURCE_DIR}/display_tool;${CMAKE_SOURCE_DIR}/qmarkdowntextedit" +) + +# --------------------------------------------------------------------------- +# Android-specific configuration +# --------------------------------------------------------------------------- +if(ANDROID) + # Page size alignment (required for some Android ABIs) + target_link_options(${APP_TARGET} PRIVATE + -Wl,-z,max-page-size=16384 + -Wl,-z,common-page-size=16384 + ) + + # Determine android version code + if(ANDROID_ABI STREQUAL "x86") + set(VT_ANDROID_VERSION ${VT_ANDROID_VERSION_X86}) + elseif(ANDROID_ABI STREQUAL "arm64-v8a") + set(VT_ANDROID_VERSION ${VT_ANDROID_VERSION_ARM64}) + elseif(ANDROID_ABI STREQUAL "armeabi-v7a") + set(VT_ANDROID_VERSION ${VT_ANDROID_VERSION_ARMV7}) + else() + set(VT_ANDROID_VERSION ${VT_ANDROID_VERSION_X86}) + endif() + + # Generate AndroidManifest.xml from template + configure_file( + ${CMAKE_SOURCE_DIR}/android/AndroidManifest.xml.in + ${CMAKE_SOURCE_DIR}/android/AndroidManifest.xml + @ONLY + ) + + set_target_properties(${APP_TARGET} PROPERTIES + QT_ANDROID_PACKAGE_SOURCE_DIR "${CMAKE_SOURCE_DIR}/android" + ) +endif() + +# --------------------------------------------------------------------------- +# Linux-specific (static libstdc++ for portable binaries) +# --------------------------------------------------------------------------- +if(UNIX AND NOT APPLE AND NOT ANDROID) + option(STATIC_LIBCXX "Statically link libstdc++ and libgcc" OFF) + if(STATIC_LIBCXX) + target_link_options(${APP_TARGET} PRIVATE + -static-libstdc++ -static-libgcc + ) + endif() +endif() + +# --------------------------------------------------------------------------- +# macOS-specific +# --------------------------------------------------------------------------- +if(APPLE AND NOT IOS) + set_target_properties(${APP_TARGET} PROPERTIES + MACOSX_BUNDLE TRUE + MACOSX_BUNDLE_INFO_PLIST "${CMAKE_SOURCE_DIR}/macos/Info.plist" + MACOSX_BUNDLE_ICON_FILE "appIcon" + ) + + # Install the icon into the bundle + set(MACOS_ICON "${CMAKE_SOURCE_DIR}/macos/appIcon.icns") + set_source_files_properties(${MACOS_ICON} PROPERTIES + MACOSX_PACKAGE_LOCATION "Resources" + ) + target_sources(${APP_TARGET} PRIVATE ${MACOS_ICON}) + + # Universal binary (x86_64 + arm64) + set(CMAKE_OSX_ARCHITECTURES "x86_64;arm64" CACHE STRING "macOS architectures") +endif() + +# --------------------------------------------------------------------------- +# iOS-specific +# --------------------------------------------------------------------------- +if(IOS) + set_target_properties(${APP_TARGET} PROPERTIES + MACOSX_BUNDLE TRUE + MACOSX_BUNDLE_INFO_PLIST "${CMAKE_SOURCE_DIR}/ios/Info.plist" + ) + + target_compile_definitions(${APP_TARGET} PRIVATE QT_NO_PRINTER) + + # Asset catalog + set_target_properties(${APP_TARGET} PROPERTIES + XCODE_ATTRIBUTE_ASSETCATALOG_COMPILER_APPICON_NAME "AppIcon" + ) + + # Launch screen storyboard + set(IOS_STORYBOARD "${CMAKE_SOURCE_DIR}/ios/MyLaunchScreen.storyboard") + if(EXISTS ${IOS_STORYBOARD}) + set_source_files_properties(${IOS_STORYBOARD} PROPERTIES + MACOSX_PACKAGE_LOCATION "Resources" + ) + target_sources(${APP_TARGET} PRIVATE ${IOS_STORYBOARD}) + endif() + + # iTunes artwork + file(GLOB IOS_ARTWORK "${CMAKE_SOURCE_DIR}/ios/iTunesArtwork*") + if(IOS_ARTWORK) + set_source_files_properties(${IOS_ARTWORK} PROPERTIES + MACOSX_PACKAGE_LOCATION "Resources" + ) + target_sources(${APP_TARGET} PRIVATE ${IOS_ARTWORK}) + endif() + + # Target device family: 1=iPhone, 2=iPad, 1,2=Universal + set_target_properties(${APP_TARGET} PROPERTIES + XCODE_ATTRIBUTE_TARGETED_DEVICE_FAMILY "1,2" + XCODE_ATTRIBUTE_GCC_WARN_64_TO_32_BIT_CONVERSION "NO" + ) +endif() + +# --------------------------------------------------------------------------- +# Windows-specific +# --------------------------------------------------------------------------- +if(WIN32) + set_target_properties(${APP_TARGET} PROPERTIES + WIN32_EXECUTABLE TRUE + ) +endif() + +# --------------------------------------------------------------------------- +# Install rules (basic) +# --------------------------------------------------------------------------- +include(GNUInstallDirs) +install(TARGETS ${APP_TARGET} + BUNDLE DESTINATION . + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} +) diff --git a/CMakePresets.json b/CMakePresets.json new file mode 100644 index 000000000..6c71a2598 --- /dev/null +++ b/CMakePresets.json @@ -0,0 +1,80 @@ +{ + "version": 6, + "cmakeMinimumRequired": { + "major": 3, + "minor": 16, + "patch": 0 + }, + "configurePresets": [ + { + "name": "default", + "displayName": "Default (Debug)", + "binaryDir": "${sourceDir}/build/default", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Debug" + } + }, + { + "name": "release-linux", + "displayName": "Release Linux", + "binaryDir": "${sourceDir}/build/lin", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Release", + "STATIC_LIBCXX": "ON" + } + }, + { + "name": "release-windows", + "displayName": "Release Windows", + "binaryDir": "${sourceDir}/build/win", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Release" + } + }, + { + "name": "release-macos", + "displayName": "Release macOS", + "binaryDir": "${sourceDir}/build/macos", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Release", + "CMAKE_OSX_ARCHITECTURES": "x86_64;arm64" + } + }, + { + "name": "release-android-arm64", + "displayName": "Release Android arm64-v8a", + "binaryDir": "${sourceDir}/build/android-arm64", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Release", + "ANDROID_ABI": "arm64-v8a" + } + }, + { + "name": "release-android-armv7", + "displayName": "Release Android armeabi-v7a", + "binaryDir": "${sourceDir}/build/android-armv7", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Release", + "ANDROID_ABI": "armeabi-v7a" + } + } + ], + "buildPresets": [ + { + "name": "default", + "configurePreset": "default" + }, + { + "name": "release-linux", + "configurePreset": "release-linux" + }, + { + "name": "release-windows", + "configurePreset": "release-windows" + }, + { + "name": "release-macos", + "configurePreset": "release-macos" + } + ] +} diff --git a/QCodeEditor/src/internal/QCodeEditor.cpp b/QCodeEditor/src/internal/QCodeEditor.cpp index f529938cf..5a6abf42e 100644 --- a/QCodeEditor/src/internal/QCodeEditor.cpp +++ b/QCodeEditor/src/internal/QCodeEditor.cpp @@ -829,7 +829,7 @@ void QCodeEditor::keyPressEvent(QKeyEvent* e) { // Shortcut for moving line to left if (m_replaceTab && e->key() == Qt::Key_Backtab) { - indentationLevel = std::min(indentationLevel, m_tabReplace.size()); + indentationLevel = std::min(indentationLevel, static_cast(m_tabReplace.size())); auto cursor = textCursor(); diff --git a/application/template/main.qml b/application/template/main.qml index f1ebac74d..3843dd331 100644 --- a/application/template/main.qml +++ b/application/template/main.qml @@ -15,9 +15,9 @@ along with this program. If not, see . */ -import QtQuick 2.7 -import QtQuick.Controls 2.0 -import QtQuick.Layouts 1.3 +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts import Vedder.vesc.vescinterface 1.0 import Vedder.vesc.commands 1.0 @@ -119,7 +119,7 @@ ApplicationWindow { Connections { target: mCommands - onValuesReceived: { + function onValuesReceived(values, mask) { valText.text = "Battery : " + parseFloat(values.v_in).toFixed(2) + " V\n" + "I Battery : " + parseFloat(values.current_in).toFixed(2) + " A\n" + diff --git a/bleuart.cpp b/bleuart.cpp index 77514b402..1c2aa8797 100644 --- a/bleuart.cpp +++ b/bleuart.cpp @@ -73,28 +73,29 @@ void BleUart::startConnect(QString addr) // a controller using a devices address is not supported on macOS or iOS. QBluetoothDeviceInfo deviceInfo = QBluetoothDeviceInfo(); deviceInfo.setDeviceUuid(QBluetoothUuid(addr)); - mControl = new QLowEnergyController(deviceInfo); + mControl = QLowEnergyController::createCentral(deviceInfo, this); #else - mControl = new QLowEnergyController(QBluetoothAddress(addr)); + QBluetoothDeviceInfo deviceInfo(QBluetoothAddress(addr), QString(), 0); + mControl = QLowEnergyController::createCentral(deviceInfo, this); #endif mControl->setRemoteAddressType(QLowEnergyController::RandomAddress); - connect(mControl, SIGNAL(serviceDiscovered(QBluetoothUuid)), - this, SLOT(serviceDiscovered(QBluetoothUuid))); - connect(mControl, SIGNAL(discoveryFinished()), - this, SLOT(serviceScanDone())); - connect(mControl, SIGNAL(error(QLowEnergyController::Error)), - this, SLOT(controllerError(QLowEnergyController::Error))); - connect(mControl, SIGNAL(connected()), - this, SLOT(deviceConnected())); - connect(mControl, SIGNAL(disconnected()), - this, SLOT(deviceDisconnected())); - connect(mControl, SIGNAL(stateChanged(QLowEnergyController::ControllerState)), - this, SLOT(controlStateChanged(QLowEnergyController::ControllerState))); - connect(mControl, SIGNAL(connectionUpdated(QLowEnergyConnectionParameters)), - this, SLOT(connectionUpdated(QLowEnergyConnectionParameters))); + connect(mControl, &QLowEnergyController::serviceDiscovered, + this, &BleUart::serviceDiscovered); + connect(mControl, &QLowEnergyController::discoveryFinished, + this, &BleUart::serviceScanDone); + connect(mControl, &QLowEnergyController::errorOccurred, + this, &BleUart::controllerError); + connect(mControl, &QLowEnergyController::connected, + this, &BleUart::deviceConnected); + connect(mControl, &QLowEnergyController::disconnected, + this, &BleUart::deviceDisconnected); + connect(mControl, &QLowEnergyController::stateChanged, + this, &BleUart::controlStateChanged); + connect(mControl, &QLowEnergyController::connectionUpdated, + this, &BleUart::connectionUpdated); mControl->connectToDevice(); mConnectTimeoutTimer.start(10000); @@ -237,10 +238,10 @@ void BleUart::serviceScanDone() qDebug() << "Connecting to BLE UART service"; mService = mControl->createServiceObject(QBluetoothUuid(QUuid(mServiceUuid)), this); - connect(mService, SIGNAL(stateChanged(QLowEnergyService::ServiceState)), - this, SLOT(serviceStateChanged(QLowEnergyService::ServiceState))); - connect(mService, SIGNAL(error(QLowEnergyService::ServiceError)), - this, SLOT(serviceError(QLowEnergyService::ServiceError))); + connect(mService, &QLowEnergyService::stateChanged, + this, &BleUart::serviceStateChanged); + connect(mService, &QLowEnergyService::errorOccurred, + this, &BleUart::serviceError); connect(mService, SIGNAL(characteristicChanged(QLowEnergyCharacteristic,QByteArray)), this, SLOT(updateData(QLowEnergyCharacteristic,QByteArray))); connect(mService, SIGNAL(descriptorWritten(QLowEnergyDescriptor,QByteArray)), @@ -283,7 +284,7 @@ void BleUart::serviceStateChanged(QLowEnergyService::ServiceState s) emit unintentionalDisconnect(); break; } - case QLowEnergyService::ServiceDiscovered: { + case QLowEnergyService::RemoteServiceDiscovered: { //looking for the TX characteristic const QLowEnergyCharacteristic txChar = mService->characteristic( QBluetoothUuid(QUuid(mTxUuid))); @@ -304,7 +305,7 @@ void BleUart::serviceStateChanged(QLowEnergyService::ServiceState s) // Bluetooth LE spec Where a characteristic can be notified, a Client Characteristic Configuration descriptor // shall be included in that characteristic as required by the Bluetooth Core Specification // Tx notify is enabled - mNotificationDescTx = txChar.descriptor(QBluetoothUuid::ClientCharacteristicConfiguration); + mNotificationDescTx = txChar.descriptor(QBluetoothUuid::DescriptorType::ClientCharacteristicConfiguration); if (mNotificationDescTx.isValid()) { // enable notification @@ -374,11 +375,11 @@ void BleUart::init() mDeviceDiscoveryAgent = new QBluetoothDeviceDiscoveryAgent(this); - connect(mDeviceDiscoveryAgent, SIGNAL(deviceDiscovered(const QBluetoothDeviceInfo&)), - this, SLOT(addDevice(const QBluetoothDeviceInfo&))); - connect(mDeviceDiscoveryAgent, SIGNAL(error(QBluetoothDeviceDiscoveryAgent::Error)), - this, SLOT(deviceScanError(QBluetoothDeviceDiscoveryAgent::Error))); - connect(mDeviceDiscoveryAgent, SIGNAL(finished()), this, SLOT(scanFinished())); + connect(mDeviceDiscoveryAgent, &QBluetoothDeviceDiscoveryAgent::deviceDiscovered, + this, &BleUart::addDevice); + connect(mDeviceDiscoveryAgent, &QBluetoothDeviceDiscoveryAgent::errorOccurred, + this, &BleUart::deviceScanError); + connect(mDeviceDiscoveryAgent, &QBluetoothDeviceDiscoveryAgent::finished, this, &BleUart::scanFinished); mInitDone = true; diff --git a/boardsetupwindow.cpp b/boardsetupwindow.cpp index 2cb969a42..763663df6 100644 --- a/boardsetupwindow.cpp +++ b/boardsetupwindow.cpp @@ -1054,7 +1054,7 @@ void BoardSetupWindow::loadAppConfXML(QString path){ switch(mAppConfig_Target->getParamEnum("app_to_use")){ case 4: //ppm and uart ui->appTab->addParamRow(mAppConfig_Target, "app_uart_baudrate"); - [[clang::fallthrough]]; + [[fallthrough]]; case 1: //ppm ui->appTab->addParamRow(mAppConfig_Target, "app_ppm_conf.ctrl_type"); ui->appTab->addParamRow(mAppConfig_Target, "app_ppm_conf.pulse_start"); diff --git a/configparams.cpp b/configparams.cpp index 9861b74c2..f8a60bbb2 100644 --- a/configparams.cpp +++ b/configparams.cpp @@ -1160,7 +1160,7 @@ bool ConfigParams::saveXml(QString fileName, QString configName) emit savingXml(); QXmlStreamWriter stream(&file); - stream.setCodec("UTF-8"); + // Qt6: QXmlStreamWriter always uses UTF-8, setCodec() removed stream.setAutoFormatting(true); getXML(stream, configName); @@ -1201,7 +1201,7 @@ QString ConfigParams::saveCompressed(QString configName) QByteArray data; QXmlStreamWriter stream(&data); - stream.setCodec("UTF-8"); + // Qt6: QXmlStreamWriter always uses UTF-8, setCodec() removed stream.setAutoFormatting(true); getXML(stream, configName); @@ -1521,7 +1521,7 @@ bool ConfigParams::saveParamsXml(QString fileName) } QXmlStreamWriter stream(&file); - stream.setCodec("UTF-8"); + // Qt6: QXmlStreamWriter always uses UTF-8, setCodec() removed stream.setAutoFormatting(true); getParamsXML(stream); @@ -1553,7 +1553,7 @@ QByteArray ConfigParams::getCompressedParamsXml() { QByteArray res; QXmlStreamWriter stream(&res); - stream.setCodec("UTF-8"); + // Qt6: QXmlStreamWriter always uses UTF-8, setCodec() removed stream.setAutoFormatting(true); getParamsXML(stream); return qCompress(res, 9); diff --git a/display_tool/dispeditor.cpp b/display_tool/dispeditor.cpp index 216ff1d0e..47862cae3 100644 --- a/display_tool/dispeditor.cpp +++ b/display_tool/dispeditor.cpp @@ -505,7 +505,7 @@ void DispEditor::updatePalette() QGridLayout *l = new QGridLayout; l->setVerticalSpacing(1); l->setHorizontalSpacing(1); - l->setMargin(1); + l->setContentsMargins(1, 1, 1, 1); int colors = 0; if (ui->formatBox->currentIndex() == 0) { diff --git a/esp32/esp32flash.cpp b/esp32/esp32flash.cpp index 23918fbab..1aa401bfe 100644 --- a/esp32/esp32flash.cpp +++ b/esp32/esp32flash.cpp @@ -37,8 +37,8 @@ Esp32Flash::Esp32Flash(QObject *parent) : QObject(parent) sPortCnt++; - connect(sPort, SIGNAL(error(QSerialPort::SerialPortError)), - this, SLOT(serialPortError(QSerialPort::SerialPortError))); + connect(sPort, &QSerialPort::errorOccurred, + this, &Esp32Flash::serialPortError); #endif } diff --git a/main.cpp b/main.cpp index 0bdb23966..2fd3ecde7 100755 --- a/main.cpp +++ b/main.cpp @@ -35,7 +35,7 @@ #include #include #include -#include +// Qt6: QDesktopWidget removed, use QScreen instead #include #include @@ -244,8 +244,7 @@ int main(int argc, char *argv[]) // DPI settings // TODO: http://www.qcustomplot.com/index.php/support/forum/1344 - - QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps); + // Qt6: High DPI scaling is always enabled, removed AA_UseHighDpiPixmaps/AA_EnableHighDpiScaling #ifdef HAS_BLUETOOTH qmlRegisterType("Vedder.vesc.bleuart", 1, 0, "BleUart"); @@ -286,10 +285,10 @@ int main(int argc, char *argv[]) #ifdef USE_MOBILE #ifndef DEBUG_BUILD - QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); + // Qt6: High DPI scaling is always enabled #endif #else - QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); + // Qt6: High DPI scaling is always enabled #ifdef Q_OS_LINUX signal(SIGINT, m_cleanup); diff --git a/map/mapwidget.cpp b/map/mapwidget.cpp index 48ee101b7..f57325adf 100644 --- a/map/mapwidget.cpp +++ b/map/mapwidget.cpp @@ -1694,7 +1694,7 @@ void MapWidget::paint(QPainter &painter, int width, int height, bool highQuality const QColor zeroAxisColor = QColor(200,52,52); const QColor firstAxisColor = Qt::gray; const QColor secondAxisColor = Qt::blue; - const QColor textColor = QPalette::Foreground; + const QColor textColor = QApplication::palette().color(QPalette::WindowText); // Grid boundries in mm const double xStart = -ceil(width / stepGrid / mScaleFactor) * stepGrid - ceil(mXOffset / stepGrid / mScaleFactor) * stepGrid; @@ -2437,7 +2437,7 @@ void MapWidget::paint(QPainter &painter, int width, int height, bool highQuality prev = mRoutes.at(mRouteNow).at(i); } - txt = QString::asprintf("RP: %d", mRoutes.at(mRouteNow).size()); + txt = QString::asprintf("RP: %lld", static_cast(mRoutes.at(mRouteNow).size())); painter.drawText(int(width - txtOffset), int(start_txt), txt); start_txt += txt_row_h; diff --git a/mobile/AdcMap.qml b/mobile/AdcMap.qml index e2286249d..fc76373f8 100644 --- a/mobile/AdcMap.qml +++ b/mobile/AdcMap.qml @@ -17,9 +17,9 @@ along with this program. If not, see . */ -import QtQuick 2.7 -import QtQuick.Controls 2.2 -import QtQuick.Layouts 1.3 +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts import Vedder.vesc.vescinterface 1.0 import Vedder.vesc.commands 1.0 diff --git a/mobile/BMS.qml b/mobile/BMS.qml index 589e381ce..22f54aacf 100644 --- a/mobile/BMS.qml +++ b/mobile/BMS.qml @@ -17,9 +17,9 @@ along with this program. If not, see . */ -import QtQuick 2.7 -import QtQuick.Controls 2.10 -import QtQuick.Layouts 1.3 +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts import Vedder.vesc.vescinterface 1.0 import Vedder.vesc.commands 1.0 diff --git a/mobile/BleSetupDialog.qml b/mobile/BleSetupDialog.qml index d343e73de..620f2753b 100644 --- a/mobile/BleSetupDialog.qml +++ b/mobile/BleSetupDialog.qml @@ -17,9 +17,9 @@ along with this program. If not, see . */ -import QtQuick 2.7 -import QtQuick.Controls 2.10 -import QtQuick.Layouts 1.3 +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts import Vedder.vesc.vescinterface 1.0 import Vedder.vesc.commands 1.0 diff --git a/mobile/CanScreen.qml b/mobile/CanScreen.qml index ad7f8ee68..52d1d7291 100644 --- a/mobile/CanScreen.qml +++ b/mobile/CanScreen.qml @@ -17,9 +17,9 @@ along with this program. If not, see . */ -import QtQuick 2.10 -import QtQuick.Controls 2.10 -import QtQuick.Layouts 1.3 +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts import Vedder.vesc.vescinterface 1.0 import Vedder.vesc.bleuart 1.0 diff --git a/mobile/ConfigPageApp.qml b/mobile/ConfigPageApp.qml index 6da51d0c2..fa7df1c55 100644 --- a/mobile/ConfigPageApp.qml +++ b/mobile/ConfigPageApp.qml @@ -17,10 +17,10 @@ along with this program. If not, see . */ -import QtQuick 2.7 -import QtQuick.Controls 2.10 -import QtQuick.Layouts 1.3 -import QtQuick.Dialogs 1.3 as Dl +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import QtQuick.Dialogs as Dl import Vedder.vesc.vescinterface 1.0 import Vedder.vesc.commands 1.0 diff --git a/mobile/ConfigPageCustom.qml b/mobile/ConfigPageCustom.qml index e78d23abc..4532f067a 100644 --- a/mobile/ConfigPageCustom.qml +++ b/mobile/ConfigPageCustom.qml @@ -17,10 +17,10 @@ along with this program. If not, see . */ -import QtQuick 2.7 -import QtQuick.Controls 2.10 -import QtQuick.Layouts 1.3 -import QtQuick.Dialogs 1.3 as Dl +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import QtQuick.Dialogs as Dl import Vedder.vesc.vescinterface 1.0 import Vedder.vesc.commands 1.0 diff --git a/mobile/ConfigPageMotor.qml b/mobile/ConfigPageMotor.qml index e1f4ec980..0641dc28e 100644 --- a/mobile/ConfigPageMotor.qml +++ b/mobile/ConfigPageMotor.qml @@ -17,10 +17,10 @@ along with this program. If not, see . */ -import QtQuick 2.7 -import QtQuick.Controls 2.10 -import QtQuick.Layouts 1.3 -import QtQuick.Dialogs 1.3 as Dl +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import QtQuick.Dialogs as Dl import Vedder.vesc.vescinterface 1.0 import Vedder.vesc.commands 1.0 @@ -100,7 +100,7 @@ Item { } Text { - anchors.fill: parent + width: parent.width id: detectLambdaLabel color: Utility.getAppHexColor("lightText") verticalAlignment: Text.AlignVCenter diff --git a/mobile/ConnectScreen.qml b/mobile/ConnectScreen.qml index b39dd7b5b..ffa29b225 100644 --- a/mobile/ConnectScreen.qml +++ b/mobile/ConnectScreen.qml @@ -17,9 +17,9 @@ along with this program. If not, see . */ -import QtQuick 2.12 -import QtQuick.Controls 2.12 -import QtQuick.Layouts 1.3 +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts import Vedder.vesc.vescinterface 1.0 import Vedder.vesc.bleuart 1.0 import Vedder.vesc.commands 1.0 @@ -246,7 +246,7 @@ Item { Text { color: Utility.getAppHexColor("lightText") verticalAlignment: Text.AlignVCenter - anchors.fill: parent + width: parent.width wrapMode: Text.WordWrap text: "This is going to clear all previous TCP hub connections. Continue?" @@ -823,7 +823,7 @@ Item { Text { color: Utility.getAppHexColor("lightText") verticalAlignment: Text.AlignVCenter - anchors.fill: parent + width: parent.width wrapMode: Text.WordWrap text: "BLE scan does not seem to be possible. Make sure that the " + "location service is enabled on your device." @@ -870,7 +870,7 @@ Item { Text { color: Utility.getAppHexColor("lightText") verticalAlignment: Text.AlignVCenter - anchors.fill: parent + width: parent.width wrapMode: Text.WordWrap text: "VESC Tool needs to access the location of your device to scan for " + diff --git a/mobile/Controls.qml b/mobile/Controls.qml index b119aa4ca..e3488acd1 100644 --- a/mobile/Controls.qml +++ b/mobile/Controls.qml @@ -17,9 +17,9 @@ along with this program. If not, see . */ -import QtQuick 2.7 -import QtQuick.Controls 2.2 -import QtQuick.Layouts 1.3 +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts import Vedder.vesc.vescinterface 1.0 import Vedder.vesc.commands 1.0 @@ -76,7 +76,7 @@ Item { anchors.fill: parent spacing: 0 - DoubleSpinBox { + VescDoubleSpinBox { id: currentBox Layout.fillWidth: true decimals: 1 @@ -163,7 +163,7 @@ Item { anchors.fill: parent spacing: 0 - DoubleSpinBox { + VescDoubleSpinBox { id: dutyBox Layout.fillWidth: true prefix: "D: " @@ -252,7 +252,7 @@ Item { anchors.fill: parent spacing: 0 - DoubleSpinBox { + VescDoubleSpinBox { id: speedBox Layout.fillWidth: true prefix: "\u03C9: " @@ -343,7 +343,7 @@ Item { anchors.fill: parent spacing: 0 - DoubleSpinBox { + VescDoubleSpinBox { id: posBox Layout.fillWidth: true prefix: "P: " diff --git a/mobile/CustomGauge.qml b/mobile/CustomGauge.qml index b258da2d4..f33e76f3b 100644 --- a/mobile/CustomGauge.qml +++ b/mobile/CustomGauge.qml @@ -17,11 +17,10 @@ along with this program. If not, see . */ -import QtQuick 2.0 -import QtQuick.Layouts 1.3 -import QtQuick.Extras 1.4 -import QtGraphicalEffects 1.0 -import QtQuick.Controls.Material 2.2 +import QtQuick +import QtQuick.Layouts +import Qt5Compat.GraphicalEffects +import QtQuick.Controls.Material import Vedder.vesc.utility 1.0 Item { @@ -90,7 +89,7 @@ Item { height: outerRadius*2 z:0 radius:outerRadius - color: {color = Utility.isDarkMode() ? Utility.getAppHexColor("darkBackground") : Utility.getAppHexColor("normalBackground")} + color: Utility.isDarkMode() ? Utility.getAppHexColor("darkBackground") : Utility.getAppHexColor("normalBackground") property double value: parent.value Behavior on value { NumberAnimation { @@ -105,7 +104,7 @@ Item { text: gauge.value.toFixed(precision) horizontalAlignment: Text.AlignHCenter font.pixelSize: outerRadius * 0.3 - color: {color = Utility.getAppHexColor("lightText") } + color: Utility.getAppHexColor("lightText") antialiasing: true font.family: "Roboto" } @@ -117,7 +116,7 @@ Item { anchors.top: speedLabel.bottom horizontalAlignment: Text.AlignHCenter font.pixelSize: outerRadius * 0.12 - color: {color = Utility.getAppHexColor("lightText")} + color: Utility.getAppHexColor("lightText") antialiasing: true font.family: "Roboto" font.capitalization: Font.AllUppercase @@ -133,7 +132,7 @@ Item { //anchors.bottomMargin: outerRadius * 0.1 horizontalAlignment: Text.AlignHCenter font.pixelSize: outerRadius * 0.12 - color: {color = Utility.getAppHexColor("lightText")} + color: Utility.getAppHexColor("lightText") antialiasing: true font.family: "Roboto" font.capitalization: Font.AllUppercase diff --git a/mobile/CustomGaugeV2.qml b/mobile/CustomGaugeV2.qml index c441b4e81..fd6dff248 100644 --- a/mobile/CustomGaugeV2.qml +++ b/mobile/CustomGaugeV2.qml @@ -17,16 +17,18 @@ along with this program. If not, see . */ -import QtQuick 2.0 -import QtQuick.Controls 2.2 -import QtQuick.Layouts 1.3 -import QtQuick.Extras 1.4 -import QtQuick.Controls.Styles 1.4 -import QtGraphicalEffects 1.0 -import QtQuick.Controls.Material 2.2 +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import Qt5Compat.GraphicalEffects +import QtQuick.Controls.Material import Vedder.vesc.utility 1.0 +// CustomGaugeV2: Qt6 version - delegates to CustomGauge (Canvas-based) +// The original used CircularGauge/CircularGaugeStyle from QtQuick.Extras +// which was removed in Qt6. + Item { property alias minimumValue: gauge.minimumValue property alias maximumValue: gauge.maximumValue @@ -40,203 +42,16 @@ Item { property double maxAngle: 144 property double minAngle: -144 - CircularGauge { + CustomGauge { id: gauge anchors.fill: parent - - Behavior on value { - NumberAnimation { - easing.type: Easing.OutCirc - duration: 100 - } - } - - style: CircularGaugeStyle { - id: style - labelStepSize: labelStep - tickmarkStepSize: labelStep - labelInset: outerRadius * 0.28 - tickmarkInset: 2 - minorTickmarkInset: 2 - minimumValueAngle: minAngle - maximumValueAngle: maxAngle - - background: - Canvas { - property double value: gauge.value - - anchors.fill: parent - onValueChanged: requestPaint() - - function d2r(degrees) { - return degrees * (Math.PI / 180.0); - } - - onPaint: { - var ctx = getContext("2d") - ctx.reset() - ctx.beginPath() - - ctx.fillStyle = Utility.getAppHexColor("normalBackground") - ctx.arc(outerRadius, outerRadius, outerRadius, 0, Math.PI * 2) - ctx.fill() - - ctx.beginPath(); - ctx.strokeStyle = Utility.getAppHexColor("darkBackground") - ctx.lineWidth = outerRadius - ctx.arc(outerRadius, - outerRadius, - outerRadius / 2, - d2r(valueToAngle(Math.max(gauge.value, 0)) - 90), - d2r(valueToAngle(gauge.maximumValue) - 90)); - ctx.stroke(); - ctx.beginPath(); - ctx.arc(outerRadius, - outerRadius, - outerRadius / 2, - d2r(valueToAngle(gauge.minimumValue) - 90), - d2r(valueToAngle(Math.min(gauge.value, 0)) - 90)); - ctx.stroke(); - ctx.beginPath(); - ctx.arc(outerRadius, - outerRadius, - outerRadius / 2, - d2r(valueToAngle(gauge.maximumValue) - 90), - d2r(valueToAngle(gauge.minimumValue) - 90)); - ctx.stroke(); - - ctx.beginPath(); - ctx.strokeStyle = Utility.getAppHexColor("normalText") - ctx.lineWidth = 1 - ctx.arc(outerRadius, - outerRadius, - outerRadius - 0.5, - 0, 2 * Math.PI); - ctx.stroke(); - - if (gauge.value < 0) { - ctx.beginPath(); - ctx.strokeStyle = Utility.getAppHexColor("lightAccent") - ctx.lineWidth = outerRadius * 0.1 - ctx.arc(outerRadius, - outerRadius, - outerRadius - outerRadius * 0.05, - d2r(valueToAngle(gauge.value) - 90), - d2r(valueToAngle(0) - 90)); - ctx.stroke(); - } else { - ctx.beginPath(); - ctx.strokeStyle = Utility.getAppHexColor("lightAccent") - ctx.lineWidth = outerRadius * 0.1 - ctx.arc(outerRadius, - outerRadius, - outerRadius - outerRadius * 0.05, - d2r(valueToAngle(0) - 90), - d2r(valueToAngle(gauge.value) - 90)); - ctx.stroke(); - } - } - } - - needle: Item { - y: -outerRadius * 0.82 - height: outerRadius * 0.18 - Rectangle { - id: needle - height: parent.height - color: Utility.getAppHexColor("darkAccent") - width: height * 0.13 - antialiasing: true - radius: 10 - } - - Glow { - anchors.fill: needle - radius: 5 - samples: 10 - spread: 0.6 - color: Utility.getAppHexColor("lightAccent") - source: needle - } - } - - foreground: Item { - Text { - id: speedLabel - anchors.verticalCenterOffset: outerRadius * 0.08 - anchors.centerIn: parent - text: gauge.value.toFixed(0) - horizontalAlignment: Text.AlignHCenter - font.pixelSize: outerRadius * 0.3 - color: Utility.getAppHexColor("lightText") - antialiasing: true - } - - Text { - id: speedLabelUnit - text: unitText - anchors.horizontalCenter: parent.horizontalCenter - anchors.top: speedLabel.bottom - horizontalAlignment: Text.AlignHCenter - font.pixelSize: outerRadius * 0.15 - color: Utility.getAppHexColor("lightText") - antialiasing: true - } - - Text { - id: typeLabel - text: typeText - verticalAlignment: Text.AlignVCenter - anchors.horizontalCenter: parent.horizontalCenter - anchors.centerIn: parent - anchors.verticalCenterOffset: -outerRadius * 0.3 - anchors.bottomMargin: outerRadius * 0.05 - horizontalAlignment: Text.AlignHCenter - font.pixelSize: outerRadius * 0.15 - color: Utility.getAppHexColor("lightText") - antialiasing: true - } - } - - function isCovered(value) { - var res = false - if (gauge.value > 0) { - if (value <= gauge.value && value >= 0) { - res = true - } - } else { - if (value >= gauge.value && value <= 0) { - res = true - } - } - - return res - } - - tickmarkLabel: Text { - font.pixelSize: outerRadius * 0.15 - text: parseFloat(styleData.value * tickmarkScale).toFixed(0) + tickmarkSuffix - color: isCovered(styleData.value) ? Utility.getAppHexColor("lightText") : Utility.getAppHexColor("lightestBackground") - antialiasing: true - } - - tickmark: Rectangle { - implicitWidth: 2 - implicitHeight: outerRadius * 0.09 - - antialiasing: true - smooth: true - color: isCovered(styleData.value) ? Utility.getAppHexColor("lightText") : Utility.getAppHexColor("lightestBackground") - } - - minorTickmark: Rectangle { - implicitWidth: 1.5 - implicitHeight: outerRadius * 0.05 - - antialiasing: true - smooth: true - color: isCovered(styleData.value) ? Utility.getAppHexColor("lightText") : Utility.getAppHexColor("normalText") - } - } + unitText: parent.unitText + typeText: parent.typeText + tickmarkSuffix: parent.tickmarkSuffix + labelStep: parent.labelStep + tickmarkScale: parent.tickmarkScale + traceColor: parent.traceColor + maxAngle: parent.maxAngle + minAngle: parent.minAngle } } diff --git a/mobile/DetectBldc.qml b/mobile/DetectBldc.qml index 3a55256a7..d142ad8d2 100644 --- a/mobile/DetectBldc.qml +++ b/mobile/DetectBldc.qml @@ -17,9 +17,9 @@ along with this program. If not, see . */ -import QtQuick 2.7 -import QtQuick.Controls 2.10 -import QtQuick.Layouts 1.3 +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts import Vedder.vesc.vescinterface 1.0 import Vedder.vesc.commands 1.0 @@ -123,7 +123,7 @@ Item { anchors.fill: parent spacing: 0 - DoubleSpinBox { + VescDoubleSpinBox { id: currentBox Layout.fillWidth: true decimals: 2 @@ -134,7 +134,7 @@ Item { suffix: " A" } - DoubleSpinBox { + VescDoubleSpinBox { id: dutyBox Layout.fillWidth: true decimals: 2 @@ -145,7 +145,7 @@ Item { prefix: "D: " } - DoubleSpinBox { + VescDoubleSpinBox { id: erpmBox Layout.fillWidth: true decimals: 1 @@ -241,7 +241,7 @@ Item { id: detectLabel color: Utility.getAppHexColor("lightText") verticalAlignment: Text.AlignVCenter - anchors.fill: parent + width: parent.width wrapMode: Text.WordWrap text: "This is going to spin up the motor. Make " + diff --git a/mobile/DetectFocEncoder.qml b/mobile/DetectFocEncoder.qml index 380b16d57..d3330e5b9 100644 --- a/mobile/DetectFocEncoder.qml +++ b/mobile/DetectFocEncoder.qml @@ -17,9 +17,9 @@ along with this program. If not, see . */ -import QtQuick 2.7 -import QtQuick.Controls 2.10 -import QtQuick.Layouts 1.3 +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts import Vedder.vesc.vescinterface 1.0 import Vedder.vesc.commands 1.0 @@ -89,7 +89,7 @@ Item { anchors.fill: parent spacing: 0 - DoubleSpinBox { + VescDoubleSpinBox { id: currentBox Layout.fillWidth: true decimals: 2 @@ -175,7 +175,7 @@ Item { id: detectLambdaLabel color: Utility.getAppHexColor("lightText") verticalAlignment: Text.AlignVCenter - anchors.fill: parent + width: parent.width wrapMode: Text.WordWrap text: "This is going to turn the motor slowly. Make " + diff --git a/mobile/DetectFocHall.qml b/mobile/DetectFocHall.qml index 914b80b43..ecb737a78 100644 --- a/mobile/DetectFocHall.qml +++ b/mobile/DetectFocHall.qml @@ -17,9 +17,9 @@ along with this program. If not, see . */ -import QtQuick 2.7 -import QtQuick.Controls 2.10 -import QtQuick.Layouts 1.3 +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts import Vedder.vesc.vescinterface 1.0 import Vedder.vesc.commands 1.0 @@ -94,7 +94,7 @@ Item { anchors.fill: parent spacing: 0 - DoubleSpinBox { + VescDoubleSpinBox { id: currentBox Layout.fillWidth: true decimals: 2 @@ -187,7 +187,7 @@ Item { id: detectLambdaLabel color: Utility.getAppHexColor("lightText") verticalAlignment: Text.AlignVCenter - anchors.fill: parent + width: parent.width wrapMode: Text.WordWrap text: "This is going to turn the motor slowly. Make " + diff --git a/mobile/DetectFocParam.qml b/mobile/DetectFocParam.qml index 5e0f7b08f..1927f9cbb 100644 --- a/mobile/DetectFocParam.qml +++ b/mobile/DetectFocParam.qml @@ -17,9 +17,9 @@ along with this program. If not, see . */ -import QtQuick 2.7 -import QtQuick.Controls 2.10 -import QtQuick.Layouts 1.3 +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts import Vedder.vesc.vescinterface 1.0 import Vedder.vesc.commands 1.0 @@ -139,7 +139,7 @@ Item { anchors.fill: parent spacing: 0 - DoubleSpinBox { + VescDoubleSpinBox { id: currentBox Layout.fillWidth: true decimals: 2 @@ -150,7 +150,7 @@ Item { suffix: " A" } - DoubleSpinBox { + VescDoubleSpinBox { id: dutyBox Layout.fillWidth: true decimals: 2 @@ -161,7 +161,7 @@ Item { prefix: "D: " } - DoubleSpinBox { + VescDoubleSpinBox { id: erpmBox Layout.fillWidth: true decimals: 1 @@ -173,7 +173,7 @@ Item { suffix: " ERPM/s" } - DoubleSpinBox { + VescDoubleSpinBox { id: tcBox Layout.fillWidth: true decimals: 1 @@ -313,7 +313,7 @@ Item { id: detectRlLabel color: Utility.getAppHexColor("lightText") verticalAlignment: Text.AlignVCenter - anchors.fill: parent + width: parent.width wrapMode: Text.WordWrap text: "When measuring R & L the motor is going to make some noises, but " + @@ -344,7 +344,7 @@ Item { } Text { - anchors.fill: parent + width: parent.width id: detectLambdaLabel color: Utility.getAppHexColor("lightText") verticalAlignment: Text.AlignVCenter diff --git a/mobile/DirectionSetup.qml b/mobile/DirectionSetup.qml index 72eaceada..15dd62827 100644 --- a/mobile/DirectionSetup.qml +++ b/mobile/DirectionSetup.qml @@ -17,9 +17,9 @@ along with this program. If not, see . */ -import QtQuick 2.7 -import QtQuick.Controls 2.10 -import QtQuick.Layouts 1.3 +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts import Vedder.vesc.vescinterface 1.0 import Vedder.vesc.commands 1.0 @@ -77,7 +77,7 @@ Item { Text { id: text Layout.fillWidth: true - color: {color = Utility.getAppHexColor("lightText")} + color: Utility.getAppHexColor("lightText") text: qsTr("Select which VESCs have inverted motor direction. Press the FWD or REV button to try.") font.bold: true horizontalAlignment: Text.AlignHCenter diff --git a/mobile/DirectoryPicker.qml b/mobile/DirectoryPicker.qml index 3c25632d4..be8280372 100644 --- a/mobile/DirectoryPicker.qml +++ b/mobile/DirectoryPicker.qml @@ -23,13 +23,12 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import QtQuick 2.0 -import QtQuick.Controls 1.4 as OldControls -import QtQuick.Controls 2.1 -import Qt.labs.folderlistmodel 2.1 -import QtQuick.Layouts 1.3 -import QtQuick.Window 2.0 -import Qt.labs.platform 1.0 +import QtQuick +import QtQuick.Controls +import Qt.labs.folderlistmodel +import QtQuick.Layouts +import QtQuick.Window +import Qt.labs.platform import Vedder.vesc.utility 1.0 Item { @@ -132,74 +131,63 @@ Item { anchors.left: parent.left spacing: 0 - OldControls.TableView { - id: view + Rectangle { Layout.fillHeight: true Layout.fillWidth: true - model: folderListModel - headerDelegate:headerDelegate - rowDelegate: Rectangle { - height: rowHeight - color: Utility.getAppHexColor("disabledText") - } + color: Utility.getAppHexColor("disabledText") - OldControls.TableViewColumn { - title: qsTr("FileName") - role: "fileName" - resizable: true - delegate: fileDelegate + Rectangle { + id: header + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + height: rowHeight + color: Utility.getAppHexColor("lightestBackground") + Text { + anchors.verticalCenter: parent.verticalCenter + anchors.horizontalCenter: parent.horizontalCenter + height: headerTextSize + font.bold: true + elide: Text.ElideMiddle + color: Utility.getAppHexColor("lightText") + text: qsTr("FileName") + } } - Component { - id: fileDelegate - Item { + ListView { + id: view + anchors.top: header.bottom + anchors.left: parent.left + anchors.right: parent.right + anchors.bottom: parent.bottom + clip: true + model: folderListModel + delegate: Rectangle { + width: view.width height: rowHeight - Rectangle { - color: Utility.getAppHexColor("disabledText") + color: Utility.getAppHexColor("disabledText") + MouseArea { anchors.fill: parent - MouseArea { - anchors.fill: parent - onClicked: { - onItemClick(fileNameText.text) - } - } - Text { - id: fileNameText - color: Utility.getAppHexColor("lightText") - height: width - anchors.left: image.right - anchors.top: parent.top - anchors.bottom: parent.bottom - anchors.right: parent.right - text: styleData.value !== undefined ? styleData.value : "" - verticalAlignment: Text.AlignVCenter + onClicked: { + onItemClick(fileName) } + } + Row { + anchors.fill: parent + spacing: 0 Image { - id: image height: buttonHeight width: height - anchors.left: parent.left - anchors.leftMargin: textmargin anchors.verticalCenter: parent.verticalCenter - source: isFolder(fileNameText.text) ? "qrc" + Utility.getThemePath() + "icons/ic_folder_open_black_48dp.png" : - "qrc" + Utility.getThemePath() + "icons/ic_insert_drive_file_black_48dp.png" + source: isFolder(fileName) ? "qrc" + Utility.getThemePath() + "icons/ic_folder_open_black_48dp.png" : + "qrc" + Utility.getThemePath() + "icons/ic_insert_drive_file_black_48dp.png" + } + Text { + color: Utility.getAppHexColor("lightText") + anchors.verticalCenter: parent.verticalCenter + text: fileName + verticalAlignment: Text.AlignVCenter } - } - } - } - Component { - id: headerDelegate - Rectangle { - height: rowHeight - color: Utility.getAppHexColor("lightestBackground") - Text { - anchors.verticalCenter: parent.verticalCenter - anchors.horizontalCenter: parent.horizontalCenter - height: headerTextSize - font.bold: true - elide: Text.ElideMiddle - color: Utility.getAppHexColor("lightText") - text: styleData.value !== undefined ? styleData.value : "" } } } diff --git a/mobile/FilePicker.qml b/mobile/FilePicker.qml index a327df5ea..9e1981fa1 100644 --- a/mobile/FilePicker.qml +++ b/mobile/FilePicker.qml @@ -23,13 +23,12 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import QtQuick 2.0 -import QtQuick.Controls 1.4 as OldControls -import QtQuick.Controls 2.1 -import Qt.labs.folderlistmodel 2.1 -import QtQuick.Layouts 1.3 -import QtQuick.Window 2.0 -import Qt.labs.platform 1.0 +import QtQuick +import QtQuick.Controls +import Qt.labs.folderlistmodel +import QtQuick.Layouts +import QtQuick.Window +import Qt.labs.platform import Vedder.vesc.utility 1.0 Item { @@ -127,74 +126,63 @@ Item { anchors.right: parent.right anchors.bottom: parent.bottom anchors.left: parent.left - OldControls.TableView { - id: view + Rectangle { Layout.fillHeight: true Layout.fillWidth: true - model: folderListModel - headerDelegate:headerDelegate - rowDelegate: Rectangle { - height: rowHeight - color: Utility.getAppHexColor("lightBackground") - } + color: Utility.getAppHexColor("lightBackground") - OldControls.TableViewColumn { - title: qsTr("FileName") - role: "fileName" - resizable: true - delegate: fileDelegate + Rectangle { + id: header + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + height: rowHeight + color: Utility.getAppHexColor("lightestBackground") + Text { + anchors.verticalCenter: parent.verticalCenter + anchors.horizontalCenter: parent.horizontalCenter + height: headerTextSize + font.bold: true + elide: Text.ElideMiddle + color: Utility.getAppHexColor("lightText") + text: qsTr("FileName") + } } - Component { - id: fileDelegate - Item { + ListView { + id: view + anchors.top: header.bottom + anchors.left: parent.left + anchors.right: parent.right + anchors.bottom: parent.bottom + clip: true + model: folderListModel + delegate: Rectangle { + width: view.width height: rowHeight - Rectangle { - color: Utility.getAppHexColor("normalBackground") + color: Utility.getAppHexColor("normalBackground") + MouseArea { anchors.fill: parent - MouseArea { - anchors.fill: parent - onClicked: { - onItemClick(fileNameText.text) - } - } - Text { - id: fileNameText - color: Utility.getAppHexColor("lightText") - height: width - anchors.left: image.right - anchors.top: parent.top - anchors.bottom: parent.bottom - anchors.right: parent.right - text: styleData.value !== undefined ? styleData.value : "" - verticalAlignment: Text.AlignVCenter + onClicked: { + onItemClick(fileName) } + } + Row { + anchors.fill: parent + spacing: 0 Image { - id: image height: buttonHeight width: height - anchors.left: parent.left - anchors.leftMargin: textmargin anchors.verticalCenter: parent.verticalCenter - source: isFolder(fileNameText.text) ? "qrc" + Utility.getThemePath() + "icons/ic_folder_open_black_48dp.png" : - "qrc" + Utility.getThemePath() + "icons/ic_insert_drive_file_black_48dp.png" + source: isFolder(fileName) ? "qrc" + Utility.getThemePath() + "icons/ic_folder_open_black_48dp.png" : + "qrc" + Utility.getThemePath() + "icons/ic_insert_drive_file_black_48dp.png" + } + Text { + color: Utility.getAppHexColor("lightText") + anchors.verticalCenter: parent.verticalCenter + text: fileName + verticalAlignment: Text.AlignVCenter } - } - } - } - Component { - id: headerDelegate - Rectangle { - height: rowHeight - color: Utility.getAppHexColor("lightestBackground") - Text { - anchors.verticalCenter: parent.verticalCenter - anchors.horizontalCenter: parent.horizontalCenter - height: headerTextSize - font.bold: true - elide: Text.ElideMiddle - color: Utility.getAppHexColor("lightText") - text: styleData.value !== undefined ? styleData.value : "" } } } diff --git a/mobile/FwUpdate.qml b/mobile/FwUpdate.qml index 1953e2e38..8547efe61 100755 --- a/mobile/FwUpdate.qml +++ b/mobile/FwUpdate.qml @@ -17,10 +17,10 @@ along with this program. If not, see . */ -import QtQuick 2.15 -import QtQuick.Controls 2.15 -import QtQuick.Layouts 1.3 -import QtQuick.Dialogs 1.3 as Dl +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import QtQuick.Dialogs as Dl import Vedder.vesc.vescinterface 1.0 import Vedder.vesc.commands 1.0 @@ -612,7 +612,7 @@ Item { color: Utility.getAppHexColor("lightText") id: uploadDialogLabel verticalAlignment: Text.AlignVCenter - anchors.fill: parent + width: parent.width wrapMode: Text.WordWrap } @@ -655,7 +655,7 @@ Item { color: Utility.getAppHexColor("lightText") text: "This is going do download a few 100 MB of old firmwares. Continue?" verticalAlignment: Text.AlignVCenter - anchors.fill: parent + width: parent.width wrapMode: Text.WordWrap } diff --git a/mobile/ImageButton.qml b/mobile/ImageButton.qml index cfb0eb0c9..207f61c69 100644 --- a/mobile/ImageButton.qml +++ b/mobile/ImageButton.qml @@ -17,9 +17,9 @@ along with this program. If not, see . */ -import QtQuick 2.7 -import QtQuick.Controls 2.2 -import QtQuick.Layouts 1.3 +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts import Vedder.vesc.utility 1.0 Item { diff --git a/mobile/Lisp.qml b/mobile/Lisp.qml index e20e42b71..d5d50fadf 100644 --- a/mobile/Lisp.qml +++ b/mobile/Lisp.qml @@ -1,9 +1,9 @@ -import QtQuick 2.15 -import QtQuick.Controls 2.15 -import QtQuick.Layouts 1.3 -import QtQuick.Dialogs 1.3 as Dl -import Qt.labs.folderlistmodel 2.1 -import Qt.labs.settings 1.0 as QSettings +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import QtQuick.Dialogs as Dl +import Qt.labs.folderlistmodel +import QtCore as QSettings import Vedder.vesc.vescinterface 1.0 import Vedder.vesc.commands 1.0 diff --git a/mobile/LogBox.qml b/mobile/LogBox.qml index 1089c915c..af1cd54d9 100644 --- a/mobile/LogBox.qml +++ b/mobile/LogBox.qml @@ -17,11 +17,11 @@ along with this program. If not, see . */ -import QtQuick 2.7 -import QtQuick.Controls 2.2 -import QtQuick.Layouts 1.3 -import Qt.labs.settings 1.0 as QSettings -import Qt.labs.platform 1.1 +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import QtCore as QSettings +import Qt.labs.platform import Vedder.vesc.vescinterface 1.0 import Vedder.vesc.utility 1.0 diff --git a/mobile/MultiSettings.qml b/mobile/MultiSettings.qml index 0067172bf..ca98a206a 100755 --- a/mobile/MultiSettings.qml +++ b/mobile/MultiSettings.qml @@ -17,9 +17,9 @@ along with this program. If not, see . */ -import QtQuick 2.7 -import QtQuick.Controls 2.10 -import QtQuick.Layouts 1.3 +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts import Vedder.vesc.vescinterface 1.0 import Vedder.vesc.commands 1.0 @@ -289,7 +289,7 @@ Item { RowLayout { Layout.fillWidth: true - DoubleSpinBox { + VescDoubleSpinBox { id: tcBox Layout.fillWidth: true decimals: 1 @@ -402,7 +402,7 @@ Item { } header: Rectangle { - color: {color = Utility.getAppHexColor("lightText")} + color: Utility.getAppHexColor("lightText") height: tabBar.height TabBar { diff --git a/mobile/NrfPair.qml b/mobile/NrfPair.qml index 6a7e7b89a..817fa8f36 100644 --- a/mobile/NrfPair.qml +++ b/mobile/NrfPair.qml @@ -17,9 +17,9 @@ along with this program. If not, see . */ -import QtQuick 2.7 -import QtQuick.Controls 2.2 -import QtQuick.Layouts 1.3 +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts import Vedder.vesc.vescinterface 1.0 import Vedder.vesc.commands 1.0 @@ -48,7 +48,7 @@ Item { anchors.fill: parent spacing: 0 - DoubleSpinBox { + VescDoubleSpinBox { id: timeBox Layout.fillWidth: true realFrom: 1.0 diff --git a/mobile/Packages.qml b/mobile/Packages.qml index 96b165dc1..82fdcc158 100644 --- a/mobile/Packages.qml +++ b/mobile/Packages.qml @@ -17,10 +17,10 @@ along with this program. If not, see . */ -import QtQuick 2.15 -import QtQuick.Controls 2.15 -import QtQuick.Layouts 1.3 -import QtQuick.Dialogs 1.3 as Dl +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import QtQuick.Dialogs as Dl import Vedder.vesc.vescinterface 1.0 import Vedder.vesc.commands 1.0 @@ -298,7 +298,7 @@ Item { Text { id: installFromPathText - color: {color = Utility.getAppHexColor("lightText")} + color: Utility.getAppHexColor("lightText") linkColor: {linkColor = Utility.getAppHexColor("lightAccent")} verticalAlignment: Text.AlignVCenter anchors.fill: parent @@ -313,7 +313,7 @@ Item { Text { id: installPkgCompatibleText visible: false - color: {color = Utility.getAppHexColor("red")} + color: Utility.getAppHexColor("red") verticalAlignment: Text.AlignVCenter Layout.fillWidth: true font.bold: true diff --git a/mobile/PairingDialog.qml b/mobile/PairingDialog.qml index dc224d1e1..800aabf8f 100644 --- a/mobile/PairingDialog.qml +++ b/mobile/PairingDialog.qml @@ -17,9 +17,9 @@ along with this program. If not, see . */ -import QtQuick 2.7 -import QtQuick.Controls 2.10 -import QtQuick.Layouts 1.3 +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts import Vedder.vesc.vescinterface 1.0 import Vedder.vesc.commands 1.0 @@ -148,7 +148,7 @@ Item { Text { color: Utility.getAppHexColor("lightText") verticalAlignment: Text.AlignVCenter - anchors.fill: parent + width: parent.width wrapMode: Text.WordWrap text: "This is going to delete this VESC from the paired list. If that VESC " + "has the pairing flag set you won't be able to connect to it over BLE " + @@ -275,7 +275,7 @@ Item { Text { color: Utility.getAppHexColor("lightText") verticalAlignment: Text.AlignVCenter - anchors.fill: parent + width: parent.width wrapMode: Text.WordWrap text: "This is going to pair the connected VESC with this instance of VESC Tool. VESC Tool instances " + "that are not paired with this VESC will not be able to connect over bluetooth any more. Continue?" @@ -316,7 +316,7 @@ Item { Text { color: Utility.getAppHexColor("lightText") verticalAlignment: Text.AlignVCenter - anchors.fill: parent + width: parent.width wrapMode: Text.WordWrap text: "This is going to unpair the connected VESC. Continue?" } diff --git a/mobile/ParamEditBitfield.qml b/mobile/ParamEditBitfield.qml index 8a7f17279..45ed5d719 100644 --- a/mobile/ParamEditBitfield.qml +++ b/mobile/ParamEditBitfield.qml @@ -17,9 +17,9 @@ along with this program. If not, see . */ -import QtQuick 2.0 -import QtQuick.Controls 2.2 -import QtQuick.Layouts 1.3 +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts import Vedder.vesc.vescinterface 1.0 import Vedder.vesc.configparams 1.0 diff --git a/mobile/ParamEditBool.qml b/mobile/ParamEditBool.qml index 12874e033..958750eea 100644 --- a/mobile/ParamEditBool.qml +++ b/mobile/ParamEditBool.qml @@ -17,9 +17,9 @@ along with this program. If not, see . */ -import QtQuick 2.0 -import QtQuick.Controls 2.2 -import QtQuick.Layouts 1.3 +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts import Vedder.vesc.vescinterface 1.0 import Vedder.vesc.configparams 1.0 diff --git a/mobile/ParamEditDouble.qml b/mobile/ParamEditDouble.qml index 9bfca3fac..20e97a0ed 100644 --- a/mobile/ParamEditDouble.qml +++ b/mobile/ParamEditDouble.qml @@ -17,9 +17,9 @@ along with this program. If not, see . */ -import QtQuick 2.0 -import QtQuick.Controls 2.2 -import QtQuick.Layouts 1.3 +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts import Vedder.vesc.vescinterface 1.0 import Vedder.vesc.configparams 1.0 @@ -76,7 +76,7 @@ Item { Rectangle { id: rect anchors.fill: parent - color: {color = Utility.getAppHexColor("lightBackground")} + color: Utility.getAppHexColor("lightBackground") radius: 5 border.color: {border.color = Utility.getAppHexColor("disabledText")} border.width: 2 @@ -89,14 +89,14 @@ Item { Text { id: nameText - color: {color = Utility.getAppHexColor("lightText")} + color: Utility.getAppHexColor("lightText") text: paramName horizontalAlignment: Text.AlignHCenter Layout.fillWidth: true font.pointSize: 12 } - DoubleSpinBox { + VescDoubleSpinBox { id: valueBox Layout.fillWidth: true diff --git a/mobile/ParamEditEnum.qml b/mobile/ParamEditEnum.qml index de3306b4b..9099d2d61 100644 --- a/mobile/ParamEditEnum.qml +++ b/mobile/ParamEditEnum.qml @@ -17,9 +17,9 @@ along with this program. If not, see . */ -import QtQuick 2.0 -import QtQuick.Controls 2.2 -import QtQuick.Layouts 1.3 +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts import Vedder.vesc.vescinterface 1.0 import Vedder.vesc.configparams 1.0 @@ -55,7 +55,7 @@ Item { Rectangle { id: rect anchors.fill: parent - color: {color = Utility.getAppHexColor("lightBackground")} + color: Utility.getAppHexColor("lightBackground") radius: 5 border.color: {border.color = Utility.getAppHexColor("disabledText")} border.width: 2 @@ -68,7 +68,7 @@ Item { Text { id: nameText - color: {color = Utility.getAppHexColor("lightText")} + color: Utility.getAppHexColor("lightText") text: paramName horizontalAlignment: Text.AlignHCenter Layout.fillWidth: true diff --git a/mobile/ParamEditInt.qml b/mobile/ParamEditInt.qml index c9c8fb79f..081399fc5 100644 --- a/mobile/ParamEditInt.qml +++ b/mobile/ParamEditInt.qml @@ -17,9 +17,9 @@ along with this program. If not, see . */ -import QtQuick 2.15 -import QtQuick.Controls 2.15 -import QtQuick.Layouts 1.3 +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts import Vedder.vesc.vescinterface 1.0 import Vedder.vesc.configparams 1.0 @@ -77,7 +77,7 @@ Item { Rectangle { id: rect anchors.fill: parent - color: {color = Utility.getAppHexColor("lightBackground")} + color: Utility.getAppHexColor("lightBackground") radius: 5 border.color: {border.color = Utility.getAppHexColor("disabledText")} border.width: 2 @@ -90,7 +90,7 @@ Item { Text { id: nameText - color: {color = Utility.getAppHexColor("lightText")} + color: Utility.getAppHexColor("lightText") text: paramName horizontalAlignment: Text.AlignHCenter Layout.fillWidth: true diff --git a/mobile/ParamEditSeparator.qml b/mobile/ParamEditSeparator.qml index 05f39662f..730a3cf2f 100644 --- a/mobile/ParamEditSeparator.qml +++ b/mobile/ParamEditSeparator.qml @@ -17,9 +17,9 @@ along with this program. If not, see . */ -import QtQuick 2.0 -import QtQuick.Controls 2.2 -import QtQuick.Layouts 1.3 +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts import Vedder.vesc.utility 1.0 Item { @@ -31,12 +31,12 @@ Item { Rectangle { id: rect anchors.fill: parent - color: {color = Utility.getAppHexColor("darkAccent")} + color: Utility.getAppHexColor("darkAccent") radius: 5 Text { anchors.centerIn: parent - color: {color = Utility.getAppHexColor("lightText")} + color: Utility.getAppHexColor("lightText") id: name text: sepName font.bold: true diff --git a/mobile/ParamEditString.qml b/mobile/ParamEditString.qml index d53734a95..ad384c9b7 100644 --- a/mobile/ParamEditString.qml +++ b/mobile/ParamEditString.qml @@ -17,9 +17,9 @@ along with this program. If not, see . */ -import QtQuick 2.0 -import QtQuick.Controls 2.2 -import QtQuick.Layouts 1.3 +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts import Vedder.vesc.vescinterface 1.0 import Vedder.vesc.configparams 1.0 diff --git a/mobile/ParamEditors.qml b/mobile/ParamEditors.qml index 746b7da7d..3438f1f90 100644 --- a/mobile/ParamEditors.qml +++ b/mobile/ParamEditors.qml @@ -17,9 +17,9 @@ along with this program. If not, see . */ -import QtQuick 2.7 -import QtQuick.Controls 2.2 -import QtQuick.Layouts 1.3 +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts import Vedder.vesc.vescinterface 1.0 import Vedder.vesc.commands 1.0 @@ -80,7 +80,7 @@ Item { function createSpacer(parent) { return Qt.createQmlObject( - 'import QtQuick 2.7; import QtQuick.Layouts 1.3; Rectangle {Layout.fillHeight: true}', + 'import QtQuick; import QtQuick.Layouts; Rectangle {Layout.fillHeight: true}', parent, "spacer1") } diff --git a/mobile/ParamList.qml b/mobile/ParamList.qml index e1bb87a56..36d321f3d 100644 --- a/mobile/ParamList.qml +++ b/mobile/ParamList.qml @@ -17,10 +17,10 @@ along with this program. If not, see . */ -import QtQuick 2.7 -import QtQuick.Controls 2.2 -import QtQuick.Layouts 1.3 -import QtQuick.Window 2.0 +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import QtQuick.Window Item { implicitHeight: scrollCol.implicitHeight diff --git a/mobile/ParamListScroll.qml b/mobile/ParamListScroll.qml index b0aa2e9cd..2b9ea8292 100644 --- a/mobile/ParamListScroll.qml +++ b/mobile/ParamListScroll.qml @@ -17,10 +17,10 @@ along with this program. If not, see . */ -import QtQuick 2.7 -import QtQuick.Controls 2.2 -import QtQuick.Layouts 1.3 -import QtQuick.Window 2.0 +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import QtQuick.Window Item { property var editorsVisible: [] diff --git a/mobile/PpmMap.qml b/mobile/PpmMap.qml index cd681c7e5..05e390e2e 100644 --- a/mobile/PpmMap.qml +++ b/mobile/PpmMap.qml @@ -17,9 +17,9 @@ along with this program. If not, see . */ -import QtQuick 2.7 -import QtQuick.Controls 2.2 -import QtQuick.Layouts 1.3 +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts import Vedder.vesc.vescinterface 1.0 import Vedder.vesc.commands 1.0 diff --git a/mobile/ProfileDisplay.qml b/mobile/ProfileDisplay.qml index aade8852f..346adffc1 100644 --- a/mobile/ProfileDisplay.qml +++ b/mobile/ProfileDisplay.qml @@ -17,9 +17,9 @@ along with this program. If not, see . */ -import QtQuick 2.0 -import QtQuick.Controls 2.10 -import QtQuick.Layouts 1.3 +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts import Vedder.vesc.vescinterface 1.0 import Vedder.vesc.commands 1.0 @@ -191,7 +191,7 @@ Item { Text { color: Utility.getAppHexColor("lightText") verticalAlignment: Text.AlignVCenter - anchors.fill: parent + width: parent.width wrapMode: Text.WordWrap text: "This is going to apply this profile permanently, even after reboot. Are " + "you sure?" diff --git a/mobile/ProfileEditor.qml b/mobile/ProfileEditor.qml index 02f765bac..5913d5047 100644 --- a/mobile/ProfileEditor.qml +++ b/mobile/ProfileEditor.qml @@ -17,9 +17,9 @@ along with this program. If not, see . */ -import QtQuick 2.7 -import QtQuick.Controls 2.10 -import QtQuick.Layouts 1.3 +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts import Vedder.vesc.vescinterface 1.0 import Vedder.vesc.configparams 1.0 @@ -164,7 +164,7 @@ Item { spacing: 0 Text { - color: {color = Utility.getAppHexColor("lightText")} + color: Utility.getAppHexColor("lightText") text: "Profile Name" font.bold: true horizontalAlignment: Text.AlignHCenter @@ -184,7 +184,7 @@ Item { TextInput { id: nameInput text: "" - color: {color = Utility.getAppHexColor("lightText")} + color: Utility.getAppHexColor("lightText") anchors.fill: parent anchors.margins: 7 font.pointSize: 12 @@ -193,7 +193,7 @@ Item { } Text { - color: {color = Utility.getAppHexColor("lightText")} + color: Utility.getAppHexColor("lightText") text: "Speed Limit" font.bold: true horizontalAlignment: Text.AlignHCenter @@ -201,7 +201,7 @@ Item { font.pointSize: 12 } - DoubleSpinBox { + VescDoubleSpinBox { id: speedKmhBox prefix: "Forward: " realFrom: 0.0 @@ -213,7 +213,7 @@ Item { } } - DoubleSpinBox { + VescDoubleSpinBox { id: speedKmhRevBox prefix: "Reverse: " realFrom: 0.0 @@ -227,7 +227,7 @@ Item { } Text { - color: {color = Utility.getAppHexColor("lightText")} + color: Utility.getAppHexColor("lightText") text: "Motor Current Scale" font.bold: true horizontalAlignment: Text.AlignHCenter @@ -235,7 +235,7 @@ Item { font.pointSize: 12 } - DoubleSpinBox { + VescDoubleSpinBox { id: currentBox Layout.fillWidth: true prefix: "Accel: " @@ -245,7 +245,7 @@ Item { realStepSize: 5 } - DoubleSpinBox { + VescDoubleSpinBox { id: currentBrakeBox Layout.fillWidth: true Layout.bottomMargin: 20 @@ -273,14 +273,14 @@ Item { } } - DoubleSpinBox { + VescDoubleSpinBox { id: powerMaxBox prefix: "Output: " Layout.fillWidth: true visible: powerBox.checked } - DoubleSpinBox { + VescDoubleSpinBox { id: powerMinBox prefix: "Regen: " Layout.fillWidth: true diff --git a/mobile/Profiles.qml b/mobile/Profiles.qml index 2a65a6123..9a1af3937 100644 --- a/mobile/Profiles.qml +++ b/mobile/Profiles.qml @@ -17,9 +17,9 @@ along with this program. If not, see . */ -import QtQuick 2.7 -import QtQuick.Controls 2.10 -import QtQuick.Layouts 1.3 +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts import Vedder.vesc.vescinterface 1.0 import Vedder.vesc.utility 1.0 @@ -44,7 +44,7 @@ Item { } Qt.createQmlObject( - 'import QtQuick 2.7; import QtQuick.Layouts 1.3; Rectangle {Layout.fillHeight: true}', + 'import QtQuick; import QtQuick.Layouts; Rectangle {Layout.fillHeight: true}', scrollCol, "spacer1") } @@ -106,10 +106,13 @@ Item { color: "#AA000000" } + contentWidth: availableWidth + Text { - color:{color = Utility.getAppHexColor("lightText")} + id: deleteDialogText + color: Utility.getAppHexColor("lightText") verticalAlignment: Text.AlignVCenter - anchors.fill: parent + width: deleteDialog.availableWidth wrapMode: Text.WordWrap text: "This is going to delete this profile. Are you sure?" } @@ -196,9 +199,9 @@ Item { y: column.y + column.height / 2 - height / 2 Text { - color: {color = Utility.getAppHexColor("lightText")} + color: Utility.getAppHexColor("lightText") verticalAlignment: Text.AlignVCenter - anchors.fill: parent + width: parent.width wrapMode: Text.WordWrap text: "This is going to remove all your profiles. Are you sure?" diff --git a/mobile/RtData.qml b/mobile/RtData.qml index ae0ea93c3..4b89dd7e3 100644 --- a/mobile/RtData.qml +++ b/mobile/RtData.qml @@ -17,9 +17,9 @@ along with this program. If not, see . */ -import QtQuick 2.7 -import QtQuick.Controls 2.2 -import QtQuick.Layouts 1.3 +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts import Vedder.vesc.vescinterface 1.0 import Vedder.vesc.commands 1.0 diff --git a/mobile/RtDataIMU.qml b/mobile/RtDataIMU.qml index 414894942..83fac6e24 100644 --- a/mobile/RtDataIMU.qml +++ b/mobile/RtDataIMU.qml @@ -1,6 +1,6 @@ -import QtQuick 2.5 -import QtQuick.Controls 2.2 -import QtQuick.Layouts 1.3 +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts import Vedder.vesc.vescinterface 1.0 import Vedder.vesc.commands 1.0 diff --git a/mobile/RtDataSetup.qml b/mobile/RtDataSetup.qml index 6725ce72d..59ed1c9c4 100644 --- a/mobile/RtDataSetup.qml +++ b/mobile/RtDataSetup.qml @@ -17,13 +17,12 @@ along with this program. If not, see . */ -import QtQuick 2.5 -import QtQml 2.7 -import QtQuick.Controls 2.10 -import QtQuick.Layouts 1.3 -import QtQuick.Controls.Styles 1.4 -import QtGraphicalEffects 1.0 -import QtQuick.Controls.Material 2.2 +import QtQuick +import QtQml +import QtQuick.Controls +import QtQuick.Layouts +import Qt5Compat.GraphicalEffects +import QtQuick.Controls.Material import Vedder.vesc.vescinterface 1.0 import Vedder.vesc.utility 1.0 @@ -52,7 +51,7 @@ Item { // Make background slightly darker Rectangle { anchors.fill: parent - color: {color = Utility.getAppHexColor("darkBackground")} + color: Utility.getAppHexColor("darkBackground") } GridLayout { @@ -210,7 +209,7 @@ Item { RowLayout { anchors.fill: parent - DoubleSpinBox { + VescDoubleSpinBox { id: odometerBox decimals: 2 realFrom: 0.0 @@ -245,7 +244,7 @@ Item { } } background: Rectangle { - color: {color = Utility.isDarkMode() ? Utility.getAppHexColor("darkBackground") : Utility.getAppHexColor("normalBackground")} + color: Utility.isDarkMode() ? Utility.getAppHexColor("darkBackground") : Utility.getAppHexColor("normalBackground") opacity: button.down ? 0 : 1 implicitWidth: gaugeSize2*0.28 implicitHeight: gaugeSize2*0.28 @@ -316,7 +315,7 @@ Item { nibColor: value > 50 ? greenColor : value > 20 ? orangeColor : redColor Text { id: batteryLabel - color: {color = Utility.getAppHexColor("lightText")} + color: Utility.getAppHexColor("lightText") text: "BATTERY" font.pixelSize: gaugeSize2/18.0 verticalAlignment: Text.AlignVCenter @@ -327,7 +326,7 @@ Item { } Text { id: rangeValLabel - color: {color = Utility.getAppHexColor("lightText")} + color: Utility.getAppHexColor("lightText") text: "∞" font.pixelSize: text === "∞"? gaugeSize2/6.3 : gaugeSize2/8.0 anchors.verticalCenterOffset: text === "∞"? -0.015*gaugeSize2 : 0 @@ -338,7 +337,7 @@ Item { } Text { id: rangeLabel - color: {color = Utility.getAppHexColor("lightText")} + color: Utility.getAppHexColor("lightText") text: "KM RANGE" font.pixelSize: gaugeSize2/20.0 verticalAlignment: Text.AlignVCenter @@ -349,7 +348,7 @@ Item { } Text { id: battValLabel - color: {color = Utility.getAppHexColor("lightText")} + color: Utility.getAppHexColor("lightText") text: parseFloat(batteryGauge.value).toFixed(0) +"%" font.pixelSize: gaugeSize2/12.0 verticalAlignment: Text.AlignVCenter @@ -385,7 +384,7 @@ Item { radius:2 anchors.centerIn: parent anchors.horizontalCenterOffset: 1.25*width - color: {color = Utility.getAppHexColor("disabledText")} + color: Utility.getAppHexColor("disabledText") transform: Rotation { id:inclineTransform origin.x: -1.25*incline1.width/2 @@ -405,7 +404,7 @@ Item { Text { id: inclineText anchors.centerIn: parent - color: {color = Utility.getAppHexColor("lightText")} + color: Utility.getAppHexColor("lightText") text: parseFloat(inclineCanvas.incline).toFixed(0) + "%" font.pixelSize: gaugeSize2/12.0 verticalAlignment: Text.AlignVCenter @@ -505,7 +504,7 @@ Item { nibColor: value > 45.0 ? redColor : (value > 25.0 ? orangeColor: blueColor) Text { id: consumValLabel - color: {color = Utility.getAppHexColor("lightText")} + color: Utility.getAppHexColor("lightText") text: "0" font.pixelSize: gaugeSize2*0.15 anchors.verticalCenterOffset: 0.265*gaugeSize2 @@ -515,7 +514,7 @@ Item { font.family: "Roboto" Text { id: avgLabel - color: {color = Utility.getAppHexColor("lightText")} + color: Utility.getAppHexColor("lightText") text: "AVG" font.pixelSize: gaugeSize2*0.06 anchors.verticalCenterOffset: 0.135*gaugeSize2 @@ -546,7 +545,7 @@ Item { //Layout.columnSpan: isHorizontal ? 2 : 1 Text { id: odoLabel - color: {color = Utility.getAppHexColor("lightText")} + color: Utility.getAppHexColor("lightText") text: "ODOMETER" anchors.horizontalCenterOffset: gaugeSize2*-2/3 font.pixelSize: gaugeSize2/18.0 @@ -558,7 +557,7 @@ Item { } Text { id: timeLabel - color: {color = Utility.getAppHexColor("lightText")} + color: Utility.getAppHexColor("lightText") text: "UP-TIME" anchors.horizontalCenterOffset: gaugeSize2*2/3 font.pixelSize: gaugeSize2/18.0 @@ -570,7 +569,7 @@ Item { } Text { id: tripLabel - color: {color = Utility.getAppHexColor("lightText")} + color: Utility.getAppHexColor("lightText") text: "TRIP" anchors.horizontalCenterOffset: 0 font.pixelSize: gaugeSize2/18.0 @@ -585,14 +584,14 @@ Item { width:2*gaugeSize2 height: rideTime.implicitHeight + gaugeSize2*0.025 anchors.centerIn: parent - color: {color = Utility.getAppHexColor("darkBackground")} + color: Utility.getAppHexColor("darkBackground") anchors.verticalCenterOffset: gaugeSize2*0.005 border.color: {border.color = Utility.getAppHexColor("lightestBackground")} border.width: 1 radius: gaugeSize2*0.03 Text{ id: rideTime - color: {color = Utility.getAppHexColor("lightText")} + color: Utility.getAppHexColor("lightText") anchors.horizontalCenterOffset: gaugeSize2*2/3 text: "00:00:00" font.pixelSize: gaugeSize2/10.0 @@ -611,7 +610,7 @@ Item { } Text{ id: odometer - color: {color = Utility.getAppHexColor("lightText")} + color: Utility.getAppHexColor("lightText") anchors.horizontalCenterOffset: gaugeSize2*-2/3 text: "0.0" font.pixelSize: gaugeSize2/10.0 @@ -630,7 +629,7 @@ Item { } Text{ id: trip - color: {color = Utility.getAppHexColor("lightText")} + color: Utility.getAppHexColor("lightText") anchors.horizontalCenterOffset: 0 text: "0.0" font.pixelSize: gaugeSize2/10.0 diff --git a/mobile/Settings.qml b/mobile/Settings.qml index a575f5b78..5cd08e2af 100644 --- a/mobile/Settings.qml +++ b/mobile/Settings.qml @@ -17,9 +17,9 @@ along with this program. If not, see . */ -import QtQuick 2.7 -import QtQuick.Controls 2.10 -import QtQuick.Layouts 1.3 +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts import Vedder.vesc.vescinterface 1.0 import Vedder.vesc.utility 1.0 @@ -195,7 +195,7 @@ Item { id: detectRlLabel color: Utility.getAppHexColor("lightText") verticalAlignment: Text.AlignVCenter - anchors.fill: parent + width: parent.width wrapMode: Text.WordWrap text: "The theme has been changed. This requires restarting VESC Tool to take effect. " + diff --git a/mobile/SetupWizardFoc.qml b/mobile/SetupWizardFoc.qml index 4e7f650ea..040e0c0e6 100755 --- a/mobile/SetupWizardFoc.qml +++ b/mobile/SetupWizardFoc.qml @@ -17,11 +17,11 @@ along with this program. If not, see . */ -import QtQuick 2.7 -import QtQuick.Controls 2.10 -import QtQuick.Layouts 1.3 -import QtGraphicalEffects 1.0 -import QtQuick.Controls.Material 2.2 +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import Qt5Compat.GraphicalEffects +import QtQuick.Controls.Material import Vedder.vesc.vescinterface 1.0 import Vedder.vesc.commands 1.0 @@ -405,7 +405,7 @@ Item { Text { visible: !overrideBox.checked - color: {color = Utility.getAppHexColor("lightText")} + color: Utility.getAppHexColor("lightText") font.family: "DejaVu Sans Mono" verticalAlignment: Text.AlignVCenter wrapMode: Text.WordWrap @@ -415,7 +415,7 @@ Item { motorPolesBox.prefix + motorPolesBox.realValue + motorPolesBox.suffix } - DoubleSpinBox { + VescDoubleSpinBox { visible: overrideBox.checked Layout.fillWidth: true id: maxPowerLossBox @@ -427,7 +427,7 @@ Item { suffix: " W" } - DoubleSpinBox { + VescDoubleSpinBox { visible: overrideBox.checked Layout.fillWidth: true id: openloopErpmBox @@ -438,7 +438,7 @@ Item { prefix: "Openloop ERPM : " } - DoubleSpinBox { + VescDoubleSpinBox { visible: overrideBox.checked Layout.fillWidth: true id: sensorlessBox @@ -449,7 +449,7 @@ Item { prefix: "Sensorless ERPM: " } - DoubleSpinBox { + VescDoubleSpinBox { visible: overrideBox.checked Layout.fillWidth: true id: motorPolesBox @@ -513,7 +513,7 @@ Item { anchors.fill: parent enabled: overrideBattBox.checked - DoubleSpinBox { + VescDoubleSpinBox { Layout.fillWidth: true id: currentInMinBox decimals: 1 @@ -525,7 +525,7 @@ Item { suffix: " A" } - DoubleSpinBox { + VescDoubleSpinBox { Layout.fillWidth: true id: currentInMaxBox decimals: 1 @@ -567,7 +567,7 @@ Item { Layout.fillWidth: true Text { Layout.fillWidth: true - color: {color = Utility.getAppHexColor("lightText")} + color: Utility.getAppHexColor("lightText") text: qsTr("Motor Pulley") } @@ -589,7 +589,7 @@ Item { Layout.fillWidth: true Text { Layout.fillWidth: true - color: {color = Utility.getAppHexColor("lightText")} + color: Utility.getAppHexColor("lightText") text: qsTr("Wheel Pulley") } @@ -635,7 +635,7 @@ Item { } header: Rectangle { - color: {color = Utility.getAppHexColor("lightText")} + color: Utility.getAppHexColor("lightText") height: tabBar.implicitHeight TabBar { @@ -647,7 +647,7 @@ Item { background: Rectangle { opacity: 1 - color: {color = Utility.getAppHexColor("lightBackground")} + color: Utility.getAppHexColor("lightBackground") } property int buttons: 5 property int buttonWidth: 120 @@ -656,7 +656,7 @@ Item { model: ["Usage", "Motor", "Battery", "Setup", "Direction"] TabButton { text: modelData - width: Math.max(tabBar.buttonWidth, tabBar.width / tabBar.buttons) + implicitWidth: tabBar.buttonWidth } } } @@ -734,6 +734,7 @@ Item { title: "Load Default Parameters" parent: dialogParent width: parent.width - (rightMargin + leftMargin) + contentWidth: availableWidth Overlay.modal: Rectangle { color: "#AA000000" } @@ -741,9 +742,10 @@ Item { y: dialog.y + dialog.height / 2 - height / 2 Text { - color: {color = Utility.getAppHexColor("lightText")} + id: loadDefaultText + color: Utility.getAppHexColor("lightText") verticalAlignment: Text.AlignVCenter - anchors.fill: parent + width: loadDefaultDialog.availableWidth wrapMode: Text.WordWrap text: "Would you like to restore this VESC, and all VESCs on the CAN-bus (if any), " + "to their default settings before proceeding?" @@ -778,14 +780,16 @@ Item { y: 10 + parent.height / 2 - height / 2 parent: dialogParent width: parent.width - (rightMargin + leftMargin) + contentWidth: availableWidth Overlay.modal: Rectangle { color: "#AA000000" } Text { - color: {color = Utility.getAppHexColor("lightText")} + id: startWarningText + color: Utility.getAppHexColor("lightText") verticalAlignment: Text.AlignVCenter - anchors.fill: parent + width: startWarningDialog.availableWidth wrapMode: Text.WordWrap text: "Warning: This selection determines the recommended max current for your motor based on heat dissipation. " + "Selecting a motor here that is significantly larger than your motor is likely to destroy your motor " + @@ -837,14 +841,16 @@ Item { y: 10 + parent.height / 2 - height / 2 parent: dialogParent width: parent.width - (rightMargin + leftMargin) + contentWidth: availableWidth Overlay.modal: Rectangle { color: "#AA000000" } Text { - color: {color = Utility.getAppHexColor("lightText")} + id: batteryWarningText + color: Utility.getAppHexColor("lightText") verticalAlignment: Text.AlignVCenter - anchors.fill: parent + width: batteryWarningDialog.availableWidth wrapMode: Text.WordWrap text: "Warning: You have not specified battery current limits (advanced box). This means that " + "the battery current will only be limited if, the battery voltage drops so much from the " + @@ -882,7 +888,7 @@ Item { Text { Layout.fillWidth: true - color: {color = Utility.getAppHexColor("lightText")} + color: Utility.getAppHexColor("lightText") verticalAlignment: Text.AlignVCenter wrapMode: Text.WordWrap text: "WARNING: This is going to spin up all motors. Make " + @@ -993,7 +999,7 @@ Item { Text { id: resultLabel - color: {color = Utility.getAppHexColor("lightText")} + color: Utility.getAppHexColor("lightText") font.family: "DejaVu Sans Mono" verticalAlignment: Text.AlignVCenter anchors.fill: parent diff --git a/mobile/SetupWizardIMU.qml b/mobile/SetupWizardIMU.qml index fa047d857..7e503f88d 100644 --- a/mobile/SetupWizardIMU.qml +++ b/mobile/SetupWizardIMU.qml @@ -2,11 +2,11 @@ * IMU Calibration Wizard */ -import QtQuick 2.7 -import QtQuick.Controls 2.10 -import QtQuick.Layouts 1.3 -//import QtGraphicalEffects 1.0 -//import QtQuick.Controls.Material 2.2 +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +//import Qt5Compat.GraphicalEffects +//import QtQuick.Controls.Material import Vedder.vesc.vescinterface 1.0 import Vedder.vesc.commands 1.0 @@ -97,7 +97,7 @@ Item { // q0 = 1; q1 = 0; q2 = 0; q3 = 0; // vesc_id = 0; // } - onValuesImuReceived: { + function onValuesImuReceived(values, mask) { // Update values filteredIMUValues.roll = values.roll diff --git a/mobile/SetupWizardInput.qml b/mobile/SetupWizardInput.qml index 1d3de5c55..3c817adb3 100644 --- a/mobile/SetupWizardInput.qml +++ b/mobile/SetupWizardInput.qml @@ -17,10 +17,10 @@ along with this program. If not, see . */ -import QtQuick 2.7 -import QtQuick.Controls 2.10 -import QtQuick.Layouts 1.3 -import QtGraphicalEffects 1.0 +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import Qt5Compat.GraphicalEffects import Vedder.vesc.vescinterface 1.0 import Vedder.vesc.commands 1.0 @@ -427,19 +427,19 @@ Item { TabButton { text: qsTr("Connection") - width: Math.max(tabBar.buttonWidth, tabBar.width / tabBar.buttons) + implicitWidth: tabBar.buttonWidth } TabButton { text: qsTr("Type") - width: Math.max(tabBar.buttonWidth, tabBar.width / tabBar.buttons) + implicitWidth: tabBar.buttonWidth } TabButton { text: qsTr("Mapping") - width: Math.max(tabBar.buttonWidth, tabBar.width / tabBar.buttons) + implicitWidth: tabBar.buttonWidth } TabButton { text: qsTr("Setup") - width: Math.max(tabBar.buttonWidth, tabBar.width / tabBar.buttons) + implicitWidth: tabBar.buttonWidth } } } @@ -658,7 +658,7 @@ Item { id: detectLambdaLabel color: Utility.getAppHexColor("lightText") verticalAlignment: Text.AlignVCenter - anchors.fill: parent + width: parent.width wrapMode: Text.WordWrap text: "You have chosen NRF input, which requires pairing. To start the " + diff --git a/mobile/SetupWizardIntro.qml b/mobile/SetupWizardIntro.qml index 14fd3d4ca..9a86deb17 100644 --- a/mobile/SetupWizardIntro.qml +++ b/mobile/SetupWizardIntro.qml @@ -17,10 +17,10 @@ along with this program. If not, see . */ -import QtQuick 2.7 -import QtQuick.Controls 2.10 -import QtQuick.Layouts 1.3 -import QtGraphicalEffects 1.0 +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import Qt5Compat.GraphicalEffects import Vedder.vesc.vescinterface 1.0 import Vedder.vesc.configparams 1.0 @@ -188,19 +188,19 @@ Item { TabButton { text: qsTr("Intro") - width: Math.max(tabBar.buttonWidth, tabBar.width / tabBar.buttons) + implicitWidth: tabBar.buttonWidth } TabButton { text: qsTr("Usage") - width: Math.max(tabBar.buttonWidth, tabBar.width / tabBar.buttons) + implicitWidth: tabBar.buttonWidth } TabButton { text: qsTr("Warranty") - width: Math.max(tabBar.buttonWidth, tabBar.width / tabBar.buttons) + implicitWidth: tabBar.buttonWidth } TabButton { text: qsTr("Conclusion") - width: Math.max(tabBar.buttonWidth, tabBar.width / tabBar.buttons) + implicitWidth: tabBar.buttonWidth } } } @@ -272,7 +272,7 @@ Item { id: resultLabel color: Utility.getAppHexColor("lightText") verticalAlignment: Text.AlignVCenter - anchors.fill: parent + width: parent.width wrapMode: Text.WordWrap text: "You must finish the introduction in order to use VESC Tool." } diff --git a/mobile/StartPage.qml b/mobile/StartPage.qml index 045a67ef3..e30357126 100644 --- a/mobile/StartPage.qml +++ b/mobile/StartPage.qml @@ -17,9 +17,9 @@ along with this program. If not, see . */ -import QtQuick 2.15 -import QtQuick.Controls 2.15 -import QtQuick.Layouts 1.3 +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts import Vedder.vesc.vescinterface 1.0 import Vedder.vesc.bleuart 1.0 @@ -471,7 +471,7 @@ Item { Text { color: Utility.getAppHexColor("lightText") verticalAlignment: Text.AlignVCenter - anchors.fill: parent + width: parent.width wrapMode: Text.WordWrap text: "After clicking OK the VESC will be put in pairing mode for 10 seconds. Switch" + @@ -504,7 +504,7 @@ Item { Text { color: Utility.getAppHexColor("lightText") verticalAlignment: Text.AlignVCenter - anchors.fill: parent + width: parent.width wrapMode: Text.WordWrap text: "This will backup the configuration of the connected VESC, as well as for the VESCs " + @@ -548,7 +548,7 @@ Item { Text { color: Utility.getAppHexColor("lightText") verticalAlignment: Text.AlignVCenter - anchors.fill: parent + width: parent.width wrapMode: Text.WordWrap text: "This will restore the configuration of the connected VESC, as well as the VESCs connected over CAN bus " + diff --git a/mobile/StatPage.qml b/mobile/StatPage.qml index 39c0266e8..600f6f6db 100644 --- a/mobile/StatPage.qml +++ b/mobile/StatPage.qml @@ -17,9 +17,9 @@ along with this program. If not, see . */ -import QtQuick 2.7 -import QtQuick.Controls 2.10 -import QtQuick.Layouts 1.3 +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts import Vedder.vesc.vescinterface 1.0 import Vedder.vesc.commands 1.0 diff --git a/mobile/TcpBox.qml b/mobile/TcpBox.qml index c611b45a0..e10506c52 100644 --- a/mobile/TcpBox.qml +++ b/mobile/TcpBox.qml @@ -17,9 +17,9 @@ along with this program. If not, see . */ -import QtQuick 2.7 -import QtQuick.Controls 2.2 -import QtQuick.Layouts 1.3 +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts import Vedder.vesc.vescinterface 1.0 import Vedder.vesc.utility 1.0 diff --git a/mobile/TcpHubBox.qml b/mobile/TcpHubBox.qml index fa53549e9..1b1a599aa 100644 --- a/mobile/TcpHubBox.qml +++ b/mobile/TcpHubBox.qml @@ -17,10 +17,10 @@ along with this program. If not, see . */ -import QtQuick 2.7 -import QtQuick.Controls 2.2 -import QtQuick.Layouts 1.3 -import Qt.labs.settings 1.0 as QSettings +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import QtCore as QSettings import Vedder.vesc.vescinterface 1.0 import Vedder.vesc.utility 1.0 diff --git a/mobile/Terminal.qml b/mobile/Terminal.qml index fd8d1a665..4c7b03867 100644 --- a/mobile/Terminal.qml +++ b/mobile/Terminal.qml @@ -17,9 +17,9 @@ along with this program. If not, see . */ -import QtQuick 2.7 -import QtQuick.Controls 2.10 -import QtQuick.Layouts 1.3 +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts import Vedder.vesc.vescinterface 1.0 import Vedder.vesc.commands 1.0 diff --git a/mobile/Vesc3DView.qml b/mobile/Vesc3DView.qml index c9201c340..a578e4aae 100644 --- a/mobile/Vesc3DView.qml +++ b/mobile/Vesc3DView.qml @@ -17,11 +17,11 @@ along with this program. If not, see . */ -import Qt3D.Core 2.0 -import Qt3D.Render 2.9 -import Qt3D.Input 2.0 -import Qt3D.Extras 2.9 -import QtQuick.Scene3D 2.0 +import Qt3D.Core +import Qt3D.Render +import Qt3D.Input +import Qt3D.Extras +import QtQuick.Scene3D Scene3D { id: scene diff --git a/mobile/DoubleSpinBox.qml b/mobile/VescDoubleSpinBox.qml similarity index 98% rename from mobile/DoubleSpinBox.qml rename to mobile/VescDoubleSpinBox.qml index 0fd790a67..960986ba5 100644 --- a/mobile/DoubleSpinBox.qml +++ b/mobile/VescDoubleSpinBox.qml @@ -19,8 +19,8 @@ // Based on https://stackoverflow.com/questions/43406830/how-to-use-float-in-a-qml-spinbox -import QtQuick 2.15 -import QtQuick.Controls 2.15 +import QtQuick +import QtQuick.Controls Item { height: spinbox.implicitHeight diff --git a/mobile/main.qml b/mobile/main.qml index 512d0bfec..1cc81805a 100644 --- a/mobile/main.qml +++ b/mobile/main.qml @@ -17,11 +17,11 @@ along with this program. If not, see . */ -import QtQuick 2.10 -import QtQuick.Controls 2.10 -import QtQuick.Controls.Material 2.2 -import QtQuick.Layouts 1.3 -import QtQuick.Window 2.10 +import QtQuick +import QtQuick.Controls +import QtQuick.Controls.Material +import QtQuick.Layouts +import QtQuick.Window import Vedder.vesc.vescinterface 1.0 import Vedder.vesc.commands 1.0 @@ -940,7 +940,7 @@ ApplicationWindow { Text { id: vescDialogLabel - color: {color = Utility.getAppHexColor("lightText")} + color: Utility.getAppHexColor("lightText") linkColor: {linkColor = Utility.getAppHexColor("lightAccent")} verticalAlignment: Text.AlignVCenter anchors.fill: parent diff --git a/mobile/qml.qrc b/mobile/qml.qrc index b37e0bc2a..8c075bbf7 100644 --- a/mobile/qml.qrc +++ b/mobile/qml.qrc @@ -13,7 +13,7 @@ ConfigPageMotor.qml ParamEditors.qml ConfigPageApp.qml - DoubleSpinBox.qml + VescDoubleSpinBox.qml ParamEditInt.qml ParamEditEnum.qml ParamEditBool.qml diff --git a/pages/pageappsettings.cpp b/pages/pageappsettings.cpp index 752495877..d201a650d 100644 --- a/pages/pageappsettings.cpp +++ b/pages/pageappsettings.cpp @@ -21,6 +21,7 @@ #include "ui_pageappsettings.h" #include "setupwizardapp.h" #include "utility.h" +#include PageAppSettings::PageAppSettings(QWidget *parent) : QWidget(parent), @@ -56,7 +57,7 @@ void PageAppSettings::reloadParams() if (mVesc) { ConfigParam *p = mVesc->infoConfig()->getParam("app_setting_description"); if (p != nullptr) { - QRegExp rx("(description.split(rx); QStringList imgs = {"app_up", "app_default" , "app_down","Upload-96","Data Backup-96","Help-96"}; QString theme = " PageDataAnalysis::PageDataAnalysis(QWidget *parent) : QWidget(parent), @@ -47,7 +48,7 @@ void PageDataAnalysis::setVesc(VescInterface *vesc) if (mVesc) { ConfigParam *p = mVesc->infoConfig()->getParam("data_analysis_description"); if (p != nullptr) { - QRegExp rx("(description.split(rx); QStringList imgs = {"expand_off","expand_on","expand_v_off","expand_v_on","size_off", "size_on","size_off","rt_on","Upload-96","motor"}; QString theme = "buttons() & Qt::LeftButton) { - double vx = ui->plot->xAxis->pixelToCoord(event->x()); + double vx = ui->plot->xAxis->pixelToCoord(event->position().x()); updateDataAndPlot(vx); } }; diff --git a/pages/pagemotorcomparison.cpp b/pages/pagemotorcomparison.cpp index f5d87a31b..aae692420 100644 --- a/pages/pagemotorcomparison.cpp +++ b/pages/pagemotorcomparison.cpp @@ -292,7 +292,7 @@ PageMotorComparison::PageMotorComparison(QWidget *parent) : auto updateMouse = [this](QMouseEvent *event) { if (event->buttons() & Qt::RightButton) { - double vx = ui->plot->xAxis->pixelToCoord(event->x()); + double vx = ui->plot->xAxis->pixelToCoord(event->position().x()); updateDataAndPlot(vx, ui->plot->yAxis->range().lower, ui->plot->yAxis->range().upper); } }; @@ -1273,7 +1273,7 @@ PageMotorComparison::QmlParams PageMotorComparison::getQmlParam(double progress) QmlParams res; if (ok) { - ok = returnedValue.canConvert(QMetaType::QVariantList); + ok = returnedValue.canConvert(); } if (!ok) { @@ -1336,41 +1336,41 @@ bool PageMotorComparison::qmlUpdateNames() Q_RETURN_ARG(QVariant, returnedValue)); if (ok) { - ok = returnedValue.canConvert(QMetaType::QVariantList); + ok = returnedValue.canConvert(); } if (ok) { auto list = returnedValue.toList(); - if (list.size() >= 1 && list.at(0).canConvert(QMetaType::QString)) { + if (list.size() >= 1 && list.at(0).canConvert()) { ui->m1PlotTable->item(18, 0)->setText(list.at(0).toString()); } - if (list.size() >= 2 && list.at(1).canConvert(QMetaType::QString)) { + if (list.size() >= 2 && list.at(1).canConvert()) { ui->m1PlotTable->item(19, 0)->setText(list.at(1).toString()); } - if (list.size() >= 3 && list.at(2).canConvert(QMetaType::QString)) { + if (list.size() >= 3 && list.at(2).canConvert()) { ui->m1PlotTable->item(20, 0)->setText(list.at(2).toString()); } - if (list.size() >= 4 && list.at(3).canConvert(QMetaType::QString)) { + if (list.size() >= 4 && list.at(3).canConvert()) { ui->m1PlotTable->item(21, 0)->setText(list.at(3).toString()); } - if (list.size() >= 5 && list.at(4).canConvert(QMetaType::QString)) { + if (list.size() >= 5 && list.at(4).canConvert()) { ui->m2PlotTable->item(18, 0)->setText(list.at(4).toString()); } - if (list.size() >= 6 && list.at(5).canConvert(QMetaType::QString)) { + if (list.size() >= 6 && list.at(5).canConvert()) { ui->m2PlotTable->item(19, 0)->setText(list.at(5).toString()); } - if (list.size() >= 7 && list.at(6).canConvert(QMetaType::QString)) { + if (list.size() >= 7 && list.at(6).canConvert()) { ui->m2PlotTable->item(20, 0)->setText(list.at(6).toString()); } - if (list.size() >= 8 && list.at(7).canConvert(QMetaType::QString)) { + if (list.size() >= 8 && list.at(7).canConvert()) { ui->m2PlotTable->item(21, 0)->setText(list.at(7).toString()); } } @@ -1390,7 +1390,7 @@ QString PageMotorComparison::getQmlXName() Q_RETURN_ARG(QVariant, returnedValue)); if (ok) { - ok = returnedValue.canConvert(QMetaType::QString); + ok = returnedValue.canConvert(); } mQmlXNameOk = ok; @@ -1414,7 +1414,7 @@ double PageMotorComparison::getQmlXMin() Q_RETURN_ARG(QVariant, returnedValue)); if (ok) { - ok = returnedValue.canConvert(QMetaType::Double); + ok = returnedValue.canConvert(); } mQmlXMinOk = ok; @@ -1438,7 +1438,7 @@ double PageMotorComparison::getQmlXMax() Q_RETURN_ARG(QVariant, returnedValue)); if (ok) { - ok = returnedValue.canConvert(QMetaType::Double); + ok = returnedValue.canConvert(); } mQmlXMaxOk = ok; diff --git a/pages/pagemotorsettings.cpp b/pages/pagemotorsettings.cpp index 19d9699c8..245761135 100644 --- a/pages/pagemotorsettings.cpp +++ b/pages/pagemotorsettings.cpp @@ -21,6 +21,7 @@ #include "ui_pagemotorsettings.h" #include "setupwizardmotor.h" #include "utility.h" +#include PageMotorSettings::PageMotorSettings(QWidget *parent) : QWidget(parent), @@ -58,7 +59,7 @@ void PageMotorSettings::reloadParams() if (mVesc) { ConfigParam *p = mVesc->infoConfig()->getParam("motor_setting_description"); if (p != nullptr) { - QRegExp rx("(description.split(rx); QStringList imgs = {"motor_up", "motor_default" , "motor_down","Upload-96","Data Backup-96","Help-96"}; QString theme = " timeVec; diff --git a/qmarkdowntextedit/examples/qml/example.qml b/qmarkdowntextedit/examples/qml/example.qml index c37570119..1364f97cf 100644 --- a/qmarkdowntextedit/examples/qml/example.qml +++ b/qmarkdowntextedit/examples/qml/example.qml @@ -1,5 +1,5 @@ -import QtQuick 2.0 -import QtQuick.Window 2.0 +import QtQuick +import QtQuick.Window import MarkdownHighlighter 1.0 Window { diff --git a/qmarkdowntextedit/markdownhighlighter.cpp b/qmarkdowntextedit/markdownhighlighter.cpp index 35aedc816..be1a6988a 100644 --- a/qmarkdowntextedit/markdownhighlighter.cpp +++ b/qmarkdowntextedit/markdownhighlighter.cpp @@ -39,12 +39,7 @@ #include #include -// We enable QStringView with Qt 5.15.1 -// #if QT_VERSION < QT_VERSION_CHECK(5, 15, 1) - #define MH_SUBSTR(pos, len) text.midRef(pos, len) -// #else -// #define MH_SUBSTR(pos, len) QStringView(text).mid(pos, len) -// #endif +#define MH_SUBSTR(pos, len) QStringView(text).mid(pos, len) QHash MarkdownHighlighter::_langStringToEnum; @@ -2482,13 +2477,9 @@ void MarkdownHighlighter::highlightEmAndStrong(const QString &text, startDelim.marker == QLatin1Char('_'); while (k != (startDelim.pos + boldLen)) { QTextCharFormat fmt = QSyntaxHighlighter::format(k); -#if QT_VERSION < QT_VERSION_CHECK(5, 13, 0) - fmt.setFontFamily(_formats[Bold].fontFamily()); -#else const QStringList fontFamilies = _formats[Bold].fontFamilies().toStringList(); if (!fontFamilies.isEmpty()) fmt.setFontFamilies(fontFamilies); -#endif if (_formats[state].fontPointSize() > 0) fmt.setFontPointSize(_formats[state].fontPointSize()); @@ -2532,13 +2523,9 @@ void MarkdownHighlighter::highlightEmAndStrong(const QString &text, while (k != (startDelim.pos + itLen)) { QTextCharFormat fmt = QSyntaxHighlighter::format(k); -#if QT_VERSION < QT_VERSION_CHECK(5, 13, 0) - fmt.setFontFamily(_formats[Italic].fontFamily()); -#else const QStringList fontFamilies = _formats[Italic].fontFamilies().toStringList(); if (!fontFamilies.isEmpty()) fmt.setFontFamilies(fontFamilies); -#endif if (_formats[state].fontPointSize() > 0) fmt.setFontPointSize(_formats[state].fontPointSize()); diff --git a/qmarkdowntextedit/qmarkdowntextedit.cpp b/qmarkdowntextedit/qmarkdowntextedit.cpp index b93bec8d8..c28530dee 100644 --- a/qmarkdowntextedit/qmarkdowntextedit.cpp +++ b/qmarkdowntextedit/qmarkdowntextedit.cpp @@ -748,11 +748,7 @@ bool QMarkdownTextEdit::handleBracketClosing(const QChar openingCharacter, // Auto completion for ``` pair if (openingCharacter == QLatin1Char('`')) { -#if QT_VERSION < QT_VERSION_CHECK(5, 12, 0) - if (QRegExp(QStringLiteral("[^`]*``")).exactMatch(text)) { -#else if (QRegularExpression(QRegularExpression::anchoredPattern(QStringLiteral("[^`]*``"))).match(text).hasMatch()) { -#endif cursor.insertText(QStringLiteral("``")); cursorSubtract = 3; } diff --git a/qmarkdowntextedit/qplaintexteditsearchwidget.cpp b/qmarkdowntextedit/qplaintexteditsearchwidget.cpp index 06e32e27e..851b415b4 100644 --- a/qmarkdowntextedit/qplaintexteditsearchwidget.cpp +++ b/qmarkdowntextedit/qplaintexteditsearchwidget.cpp @@ -308,7 +308,6 @@ bool QPlainTextEditSearchWidget::doSearch(bool searchDown, bool found = searchMode == RegularExpressionMode ? -#if (QT_VERSION >= QT_VERSION_CHECK(5, 13, 0)) _textEdit->find( QRegularExpression( text, caseSensitive @@ -316,12 +315,6 @@ bool QPlainTextEditSearchWidget::doSearch(bool searchDown, : QRegularExpression::CaseInsensitiveOption), options) : -#else - _textEdit->find(QRegExp(text, caseSensitive ? Qt::CaseSensitive - : Qt::CaseInsensitive), - options) - : -#endif _textEdit->find(text, options); _textEdit->blockSignals(false); @@ -341,7 +334,6 @@ bool QPlainTextEditSearchWidget::doSearch(bool searchDown, found = searchMode == RegularExpressionMode ? -#if (QT_VERSION >= QT_VERSION_CHECK(5, 13, 0)) _textEdit->find( QRegularExpression( text, caseSensitive @@ -349,13 +341,6 @@ bool QPlainTextEditSearchWidget::doSearch(bool searchDown, : QRegularExpression::CaseInsensitiveOption), options) : -#else - _textEdit->find( - QRegExp(text, caseSensitive ? Qt::CaseSensitive - : Qt::CaseInsensitive), - options) - : -#endif _textEdit->find(text, options); if (found && updateUI) { diff --git a/res/qml/DynamicLoader.qml b/res/qml/DynamicLoader.qml index 6b5a1ef0f..01a6828a7 100644 --- a/res/qml/DynamicLoader.qml +++ b/res/qml/DynamicLoader.qml @@ -17,10 +17,10 @@ along with this program. If not, see . */ -import QtQuick 2.7 -import QtQuick.Controls 2.0 -import QtQuick.Layouts 1.3 -import QtQuick.Controls.Material 2.2 +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import QtQuick.Controls.Material import Vedder.vesc.utility 1.0 Item { diff --git a/res/qml/Examples/BMS.qml b/res/qml/Examples/BMS.qml index 9ea437f27..d97a0b187 100644 --- a/res/qml/Examples/BMS.qml +++ b/res/qml/Examples/BMS.qml @@ -17,10 +17,10 @@ along with this program. If not, see . */ -import QtQuick 2.7 -import QtQuick.Controls 2.2 -import QtQuick.Layouts 1.3 -import QtQuick.Controls.Material 2.2 +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import QtQuick.Controls.Material import Vedder.vesc.utility 1.0 import Vedder.vesc.commands 1.0 diff --git a/res/qml/Examples/BalanceUi.qml b/res/qml/Examples/BalanceUi.qml index 907f4f28a..59ca09053 100644 --- a/res/qml/Examples/BalanceUi.qml +++ b/res/qml/Examples/BalanceUi.qml @@ -1,8 +1,8 @@ // Remote control for balance robot -import QtQuick 2.5 -import QtQuick.Controls 2.2 -import QtQuick.Layouts 1.3 +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts import Vedder.vesc.commands 1.0 import Vedder.vesc.configparams 1.0 diff --git a/res/qml/Examples/BrakeBench.qml b/res/qml/Examples/BrakeBench.qml index 1dbe6b18d..d115d3fbf 100644 --- a/res/qml/Examples/BrakeBench.qml +++ b/res/qml/Examples/BrakeBench.qml @@ -1,7 +1,7 @@ -import QtQuick 2.7 -import QtQuick.Controls 2.0 -import QtQuick.Layouts 1.3 -import QtQuick.Controls.Material 2.2 +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import QtQuick.Controls.Material import Vedder.vesc.utility 1.0 import Vedder.vesc.commands 1.0 @@ -52,7 +52,7 @@ Item { ColumnLayout { anchors.fill: parent - DoubleSpinBox { + VescDoubleSpinBox { id: rpmBox Layout.fillWidth: true decimals: 1 @@ -94,7 +94,7 @@ Item { ColumnLayout { anchors.fill: parent - DoubleSpinBox { + VescDoubleSpinBox { id: canBox Layout.fillWidth: true decimals: 0 @@ -106,7 +106,7 @@ Item { realStepSize: 1 } - DoubleSpinBox { + VescDoubleSpinBox { id: currentBox Layout.fillWidth: true decimals: 1 diff --git a/res/qml/Examples/CanDebugger.qml b/res/qml/Examples/CanDebugger.qml index 8c7c7958f..409f0a2ec 100644 --- a/res/qml/Examples/CanDebugger.qml +++ b/res/qml/Examples/CanDebugger.qml @@ -4,10 +4,10 @@ // * Encoding and transmitting CAN-frames // * Presenting the data in Text-elements -import QtQuick 2.5 -import QtQuick.Controls 2.2 -import QtQuick.Layouts 1.3 -import QtQuick.Controls.Material 2.2 +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import QtQuick.Controls.Material import Vedder.vesc.utility 1.0 import Vedder.vesc.commands 1.0 diff --git a/res/qml/Examples/ConfigParams.qml b/res/qml/Examples/ConfigParams.qml index 1846d9097..48be04022 100644 --- a/res/qml/Examples/ConfigParams.qml +++ b/res/qml/Examples/ConfigParams.qml @@ -1,6 +1,6 @@ -import QtQuick 2.12 -import QtQuick.Controls 2.12 -import QtQuick.Layouts 1.3 +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts import Vedder.vesc.commands 1.0 import Vedder.vesc.configparams 1.0 diff --git a/res/qml/Examples/Controls.qml b/res/qml/Examples/Controls.qml index 930500b5f..37f2123e5 100644 --- a/res/qml/Examples/Controls.qml +++ b/res/qml/Examples/Controls.qml @@ -17,10 +17,10 @@ along with this program. If not, see . */ -import QtQuick 2.7 -import QtQuick.Controls 2.2 -import QtQuick.Layouts 1.3 -import QtQuick.Controls.Material 2.2 +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import QtQuick.Controls.Material import Vedder.vesc.utility 1.0 import Vedder.vesc.commands 1.0 @@ -49,19 +49,19 @@ Item { TabButton { text: qsTr("Current") - width: Math.max(tabBar.buttonWidth, tabBar.width / tabBar.buttons) + implicitWidth: tabBar.buttonWidth } TabButton { text: qsTr("Duty") - width: Math.max(tabBar.buttonWidth, tabBar.width / tabBar.buttons) + implicitWidth: tabBar.buttonWidth } TabButton { text: qsTr("RPM") - width: Math.max(tabBar.buttonWidth, tabBar.width / tabBar.buttons) + implicitWidth: tabBar.buttonWidth } TabButton { text: qsTr("Position") - width: Math.max(tabBar.buttonWidth, tabBar.width / tabBar.buttons) + implicitWidth: tabBar.buttonWidth } } @@ -77,7 +77,7 @@ Item { anchors.fill: parent spacing: 0 - DoubleSpinBox { + VescDoubleSpinBox { id: currentBox Layout.fillWidth: true decimals: 1 @@ -163,7 +163,7 @@ Item { anchors.fill: parent spacing: 0 - DoubleSpinBox { + VescDoubleSpinBox { id: dutyBox Layout.fillWidth: true prefix: "D: " @@ -248,7 +248,7 @@ Item { anchors.fill: parent spacing: 0 - DoubleSpinBox { + VescDoubleSpinBox { id: speedBox Layout.fillWidth: true prefix: "\u03C9: " @@ -334,7 +334,7 @@ Item { anchors.fill: parent spacing: 0 - DoubleSpinBox { + VescDoubleSpinBox { id: posBox Layout.fillWidth: true prefix: "P: " diff --git a/res/qml/Examples/DCDC.qml b/res/qml/Examples/DCDC.qml index 71a5febe2..7052fe6d6 100644 --- a/res/qml/Examples/DCDC.qml +++ b/res/qml/Examples/DCDC.qml @@ -1,7 +1,7 @@ -import QtQuick 2.12 -import QtQuick.Controls 2.0 -import QtQuick.Layouts 1.3 -import QtQuick.Controls.Material 2.2 +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import QtQuick.Controls.Material import Vedder.vesc.utility 1.0 import Vedder.vesc.commands 1.0 diff --git a/res/qml/Examples/ExperimentPlot.qml b/res/qml/Examples/ExperimentPlot.qml index d6847dbce..53e1fee2b 100644 --- a/res/qml/Examples/ExperimentPlot.qml +++ b/res/qml/Examples/ExperimentPlot.qml @@ -1,7 +1,7 @@ -import QtQuick 2.7 -import QtQuick.Controls 2.0 -import QtQuick.Layouts 1.3 -import QtQuick.Controls.Material 2.2 +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import QtQuick.Controls.Material import Vedder.vesc.utility 1.0 import Vedder.vesc.commands 1.0 diff --git a/res/qml/Examples/GaugeTest.qml b/res/qml/Examples/GaugeTest.qml index dc1bd0523..1a5877840 100644 --- a/res/qml/Examples/GaugeTest.qml +++ b/res/qml/Examples/GaugeTest.qml @@ -1,7 +1,7 @@ -import QtQuick 2.7 -import QtQuick.Controls 2.0 -import QtQuick.Layouts 1.3 -import QtQuick.Controls.Material 2.2 +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import QtQuick.Controls.Material import Vedder.vesc.utility 1.0 import Vedder.vesc.commands 1.0 diff --git a/res/qml/Examples/IoBoard.qml b/res/qml/Examples/IoBoard.qml index b1673a3ff..5b968b572 100644 --- a/res/qml/Examples/IoBoard.qml +++ b/res/qml/Examples/IoBoard.qml @@ -1,7 +1,7 @@ -import QtQuick 2.7 -import QtQuick.Controls 2.0 -import QtQuick.Layouts 1.3 -import QtQuick.Controls.Material 2.2 +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import QtQuick.Controls.Material import Vedder.vesc.utility 1.0 import Vedder.vesc.commands 1.0 diff --git a/res/qml/Examples/LogTextToFile.qml b/res/qml/Examples/LogTextToFile.qml index 9c0ffe119..4127b4ebd 100644 --- a/res/qml/Examples/LogTextToFile.qml +++ b/res/qml/Examples/LogTextToFile.qml @@ -1,7 +1,7 @@ -import QtQuick 2.7 -import QtQuick.Controls 2.0 -import QtQuick.Layouts 1.3 -import QtQuick.Controls.Material 2.2 +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import QtQuick.Controls.Material import Vedder.vesc.utility 1.0 import Vedder.vesc.logwriter 1.0 diff --git a/res/qml/Examples/MMXGui.qml b/res/qml/Examples/MMXGui.qml index ca83926ef..b0e638411 100644 --- a/res/qml/Examples/MMXGui.qml +++ b/res/qml/Examples/MMXGui.qml @@ -1,7 +1,7 @@ -import QtQuick 2.5 -import QtQuick.Controls 2.2 -import QtQuick.Layouts 1.3 -import QtQuick.Controls.Material 2.2 +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import QtQuick.Controls.Material import Vedder.vesc.utility 1.0 import Vedder.vesc.commands 1.0 import Vedder.vesc.configparams 1.0 diff --git a/res/qml/Examples/Meters.qml b/res/qml/Examples/Meters.qml index 820d0348e..c8d1762fd 100644 --- a/res/qml/Examples/Meters.qml +++ b/res/qml/Examples/Meters.qml @@ -17,10 +17,10 @@ along with this program. If not, see . */ -import QtQuick 2.7 -import QtQuick.Controls 2.0 -import QtQuick.Layouts 1.3 -import QtQuick.Controls.Material 2.2 +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import QtQuick.Controls.Material import Vedder.vesc.utility 1.0 import Vedder.vesc.commands 1.0 diff --git a/res/qml/Examples/MotorComparisonModel.qml b/res/qml/Examples/MotorComparisonModel.qml index 7fc95ab55..c3d424c69 100644 --- a/res/qml/Examples/MotorComparisonModel.qml +++ b/res/qml/Examples/MotorComparisonModel.qml @@ -1,10 +1,10 @@ // This QML code is a template for a load model that can be used in the custom tab of // the motor comparison tool. -import QtQuick 2.7 -import QtQuick.Controls 2.0 -import QtQuick.Layouts 1.3 -import QtQuick.Controls.Material 2.2 +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import QtQuick.Controls.Material import Vedder.vesc.utility 1.0 Item { diff --git a/res/qml/Examples/Mp3Stream.qml b/res/qml/Examples/Mp3Stream.qml index bd3d03343..1fb51acc2 100644 --- a/res/qml/Examples/Mp3Stream.qml +++ b/res/qml/Examples/Mp3Stream.qml @@ -1,7 +1,7 @@ -import QtQuick 2.12 -import QtQuick.Controls 2.0 -import QtQuick.Layouts 1.3 -import QtQuick.Controls.Material 2.2 +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import QtQuick.Controls.Material import Vedder.vesc.commands 1.0 import Vedder.vesc.utility 1.0 diff --git a/res/qml/Examples/ParamTableAndPlot.qml b/res/qml/Examples/ParamTableAndPlot.qml index de397376f..2a1b42ae9 100644 --- a/res/qml/Examples/ParamTableAndPlot.qml +++ b/res/qml/Examples/ParamTableAndPlot.qml @@ -1,6 +1,6 @@ -import QtQuick 2.15 -import QtQuick.Controls 2.15 -import QtQuick.Layouts 1.3 +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts import Vedder.vesc.utility 1.0 import Vedder.vesc.commands 1.0 import Vedder.vesc.configparams 1.0 diff --git a/res/qml/Examples/ParentTabBar.qml b/res/qml/Examples/ParentTabBar.qml index c9f642169..47bc4e986 100644 --- a/res/qml/Examples/ParentTabBar.qml +++ b/res/qml/Examples/ParentTabBar.qml @@ -5,10 +5,10 @@ means that the other tabs are disabled). */ -import QtQuick 2.7 -import QtQuick.Controls 2.0 -import QtQuick.Layouts 1.3 -import QtQuick.Controls.Material 2.2 +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import QtQuick.Controls.Material import Vedder.vesc.utility 1.0 Item { diff --git a/res/qml/Examples/PollValues.qml b/res/qml/Examples/PollValues.qml index 937b0b4f7..de730e004 100644 --- a/res/qml/Examples/PollValues.qml +++ b/res/qml/Examples/PollValues.qml @@ -1,7 +1,7 @@ -import QtQuick 2.5 -import QtQuick.Controls 2.2 -import QtQuick.Layouts 1.3 -import QtQuick.Controls.Material 2.2 +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import QtQuick.Controls.Material import Vedder.vesc.utility 1.0 import Vedder.vesc.commands 1.0 import Vedder.vesc.configparams 1.0 diff --git a/res/qml/Examples/PositionControl.qml b/res/qml/Examples/PositionControl.qml index 7df9fc803..a19c5a0b6 100644 --- a/res/qml/Examples/PositionControl.qml +++ b/res/qml/Examples/PositionControl.qml @@ -17,10 +17,10 @@ along with this program. If not, see . */ -import QtQuick 2.7 -import QtQuick.Controls 2.2 -import QtQuick.Layouts 1.3 -import QtQuick.Controls.Material 2.2 +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import QtQuick.Controls.Material import Vedder.vesc.commands 1.0 import Vedder.vesc.configparams 1.0 diff --git a/res/qml/Examples/Profiles.qml b/res/qml/Examples/Profiles.qml index cc73aeedc..ffbe8ad0e 100644 --- a/res/qml/Examples/Profiles.qml +++ b/res/qml/Examples/Profiles.qml @@ -17,10 +17,10 @@ along with this program. If not, see . */ -import QtQuick 2.7 -import QtQuick.Controls 2.10 -import QtQuick.Layouts 1.3 -import QtQuick.Controls.Material 2.2 +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import QtQuick.Controls.Material import Vedder.vesc.utility 1.0 Item { @@ -43,7 +43,7 @@ Item { } Qt.createQmlObject( - 'import QtQuick 2.7; import QtQuick.Layouts 1.3; Rectangle {Layout.fillHeight: true}', + 'import QtQuick; import QtQuick.Layouts; Rectangle {Layout.fillHeight: true}', scrollCol, "spacer1") } @@ -105,7 +105,7 @@ Item { Text { color: "#ffffff" verticalAlignment: Text.AlignVCenter - anchors.fill: parent + width: parent.width wrapMode: Text.WordWrap text: "This is going to delete this profile. Are you sure?" } @@ -189,7 +189,7 @@ Item { Text { color: "#ffffff" verticalAlignment: Text.AlignVCenter - anchors.fill: parent + width: parent.width wrapMode: Text.WordWrap text: "This is going to remove all your profiles. Are you sure?" diff --git a/res/qml/Examples/Reconnect.qml b/res/qml/Examples/Reconnect.qml index 8bfdfa785..e20cdb523 100644 --- a/res/qml/Examples/Reconnect.qml +++ b/res/qml/Examples/Reconnect.qml @@ -2,10 +2,10 @@ // configuration afterwards. It is useful during firmware development to keep VESC Tool // connected and the configuration updated. -import QtQuick 2.5 -import QtQuick.Controls 2.2 -import QtQuick.Layouts 1.3 -import QtQuick.Controls.Material 2.2 +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import QtQuick.Controls.Material import Vedder.vesc.utility 1.0 import Vedder.vesc.commands 1.0 import Vedder.vesc.configparams 1.0 diff --git a/res/qml/Examples/RpmSlider.qml b/res/qml/Examples/RpmSlider.qml index 22f3f45aa..599e10fff 100644 --- a/res/qml/Examples/RpmSlider.qml +++ b/res/qml/Examples/RpmSlider.qml @@ -17,10 +17,10 @@ along with this program. If not, see . */ -import QtQuick 2.7 -import QtQuick.Controls 2.0 -import QtQuick.Layouts 1.3 -import QtQuick.Controls.Material 2.2 +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import QtQuick.Controls.Material import Vedder.vesc.utility 1.0 import Vedder.vesc.commands 1.0 diff --git a/res/qml/Examples/RtData.qml b/res/qml/Examples/RtData.qml index ecb5922cb..ea836e338 100644 --- a/res/qml/Examples/RtData.qml +++ b/res/qml/Examples/RtData.qml @@ -17,10 +17,10 @@ along with this program. If not, see . */ -import QtQuick 2.5 -import QtQuick.Controls 2.2 -import QtQuick.Layouts 1.3 -import QtQuick.Controls.Material 2.2 +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import QtQuick.Controls.Material import Vedder.vesc.utility 1.0 import Vedder.vesc.commands 1.0 import Vedder.vesc.configparams 1.0 diff --git a/res/qml/Examples/RtDataSetup.qml b/res/qml/Examples/RtDataSetup.qml index 625582d16..ca8898aa4 100644 --- a/res/qml/Examples/RtDataSetup.qml +++ b/res/qml/Examples/RtDataSetup.qml @@ -17,12 +17,11 @@ along with this program. If not, see . */ -import QtQuick 2.5 -import QtQuick.Controls 2.10 -import QtQuick.Layouts 1.3 -import QtQuick.Controls.Styles 1.4 -import QtGraphicalEffects 1.0 -import QtQuick.Controls.Material 2.2 +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import Qt5Compat.GraphicalEffects +import QtQuick.Controls.Material import Vedder.vesc.vescinterface 1.0 import Vedder.vesc.utility 1.0 @@ -329,7 +328,7 @@ Item { font.pointSize: 12 } - DoubleSpinBox { + VescDoubleSpinBox { id: odometerBox decimals: 2 realFrom: 0.0 diff --git a/res/qml/Examples/SendToLbm.qml b/res/qml/Examples/SendToLbm.qml index df37f26e0..9ea7b1c81 100644 --- a/res/qml/Examples/SendToLbm.qml +++ b/res/qml/Examples/SendToLbm.qml @@ -1,6 +1,6 @@ -import QtQuick 2.15 -import QtQuick.Controls 2.15 -import QtQuick.Layouts 1.3 +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts import Vedder.vesc.utility 1.0 import Vedder.vesc.commands 1.0 diff --git a/res/qml/Examples/TcpHub.qml b/res/qml/Examples/TcpHub.qml index 3f3bfc9c5..f4949572f 100644 --- a/res/qml/Examples/TcpHub.qml +++ b/res/qml/Examples/TcpHub.qml @@ -1,7 +1,7 @@ -import QtQuick 2.7 -import QtQuick.Controls 2.0 -import QtQuick.Layouts 1.3 -import QtQuick.Controls.Material 2.2 +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import QtQuick.Controls.Material import Vedder.vesc.utility 1.0 import Vedder.vesc.commands 1.0 diff --git a/res/qml/Examples/TcpServer.qml b/res/qml/Examples/TcpServer.qml index c74ad383c..30e7bffaa 100644 --- a/res/qml/Examples/TcpServer.qml +++ b/res/qml/Examples/TcpServer.qml @@ -1,7 +1,7 @@ -import QtQuick 2.5 -import QtQuick.Controls 2.2 -import QtQuick.Layouts 1.3 -import QtQuick.Controls.Material 2.2 +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import QtQuick.Controls.Material import Vedder.vesc.utility 1.0 import Vedder.vesc.commands 1.0 import Vedder.vesc.configparams 1.0 diff --git a/res/qml/Examples/UdpServer.qml b/res/qml/Examples/UdpServer.qml index ffce9d38d..8af0ffbbe 100644 --- a/res/qml/Examples/UdpServer.qml +++ b/res/qml/Examples/UdpServer.qml @@ -1,6 +1,6 @@ -import QtQuick 2.5 -import QtQuick.Controls 2.2 -import QtQuick.Layouts 1.3 +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts import Vedder.vesc.udpserversimple 1.0 Item { diff --git a/res/qml/MainLoader.qml b/res/qml/MainLoader.qml index dff8c1193..9befce5f2 100644 --- a/res/qml/MainLoader.qml +++ b/res/qml/MainLoader.qml @@ -17,11 +17,11 @@ along with this program. If not, see . */ -import QtQuick 2.7 -import QtQuick.Controls 2.0 -import QtQuick.Layouts 1.3 -import QtQuick.Controls.Material 2.2 -import QtQuick.Window 2.2 +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import QtQuick.Controls.Material +import QtQuick.Window import Vedder.vesc.utility 1.0 ApplicationWindow { diff --git a/res/qml/SetupMotorWindow.qml b/res/qml/SetupMotorWindow.qml index 1eaf4a281..51d1cb0a2 100644 --- a/res/qml/SetupMotorWindow.qml +++ b/res/qml/SetupMotorWindow.qml @@ -17,11 +17,11 @@ along with this program. If not, see . */ -import QtQuick 2.7 -import QtQuick.Controls 2.0 -import QtQuick.Layouts 1.3 -import QtQuick.Controls.Material 2.2 -import QtQuick.Window 2.2 +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import QtQuick.Controls.Material +import QtQuick.Window import Vedder.vesc.utility 1.0 import "qrc:/mobile" diff --git a/res/qml/WelcomeQmlPanel.qml b/res/qml/WelcomeQmlPanel.qml index ae4bf4328..88084f4a7 100644 --- a/res/qml/WelcomeQmlPanel.qml +++ b/res/qml/WelcomeQmlPanel.qml @@ -17,11 +17,11 @@ along with this program. If not, see . */ -import QtQuick 2.7 -import QtQuick.Controls 2.10 -import QtQuick.Layouts 1.3 -import QtQuick.Controls.Material 2.2 -import QtQuick.Window 2.2 +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import QtQuick.Controls.Material +import QtQuick.Window import Vedder.vesc.utility 1.0 @@ -158,7 +158,7 @@ Item { background: Rectangle { opacity: 1 - color: {color = Utility.getAppHexColor("lightBackground")} + color: Utility.getAppHexColor("lightBackground") } property int buttonWidth: Math.max(120, @@ -431,9 +431,9 @@ Item { y: parent.y + parent.height / 2 - height / 2 Text { - color: {color = Utility.getAppHexColor("lightText")} + color: Utility.getAppHexColor("lightText") verticalAlignment: Text.AlignVCenter - anchors.fill: parent + width: parent.width wrapMode: Text.WordWrap text: "After clicking OK the VESC will be put in pairing mode for 10 seconds. Switch" + diff --git a/tcpserversimple.cpp b/tcpserversimple.cpp index a1eaf8cc8..fc0a03d9b 100644 --- a/tcpserversimple.cpp +++ b/tcpserversimple.cpp @@ -80,8 +80,8 @@ bool TcpServerSimple::connectToHub(QString server, int port, QString id, QString connect(mTcpSocket, SIGNAL(readyRead()), this, SLOT(tcpInputDataAvailable())); connect(mTcpSocket, SIGNAL(disconnected()), this, SLOT(tcpInputDisconnected())); - connect(mTcpSocket, SIGNAL(error(QAbstractSocket::SocketError)), - this, SLOT(tcpInputError(QAbstractSocket::SocketError))); + connect(mTcpSocket, &QAbstractSocket::errorOccurred, + this, &TcpServerSimple::tcpInputError); emit connectionChanged(true, mTcpSocket->peerAddress().toString()); return true; } else { @@ -141,8 +141,8 @@ void TcpServerSimple::newTcpConnection() connect(mTcpSocket, SIGNAL(readyRead()), this, SLOT(tcpInputDataAvailable())); connect(mTcpSocket, SIGNAL(disconnected()), this, SLOT(tcpInputDisconnected())); - connect(mTcpSocket, SIGNAL(error(QAbstractSocket::SocketError)), - this, SLOT(tcpInputError(QAbstractSocket::SocketError))); + connect(mTcpSocket, &QAbstractSocket::errorOccurred, + this, &TcpServerSimple::tcpInputError); emit connectionChanged(true, mTcpSocket->peerAddress().toString()); } } diff --git a/utility.cpp b/utility.cpp index cf175395b..a034a26ac 100755 --- a/utility.cpp +++ b/utility.cpp @@ -42,9 +42,11 @@ #include "heatshrink/heatshrinkif.h" #ifdef Q_OS_ANDROID -#include -#include -#include +#include +#include +#include +#include +#include #endif QMap Utility::mAppColors = { @@ -289,20 +291,16 @@ bool Utility::requestFilePermission() bool Utility::requestBleScanPermission() { #ifdef Q_OS_ANDROID -#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0) - QtAndroid::PermissionResult r = QtAndroid::checkPermission("android.permission.BLUETOOTH_SCAN"); - if(r == QtAndroid::PermissionResult::Denied) { - QtAndroid::requestPermissionsSync( QStringList() << "android.permission.BLUETOOTH_SCAN", 10000); - r = QtAndroid::checkPermission("android.permission.BLUETOOTH_SCAN"); - if(r == QtAndroid::PermissionResult::Denied) { + QBluetoothPermission permission; + permission.setCommunicationModes(QBluetoothPermission::Access); + if (qApp->checkPermission(permission) != Qt::PermissionStatus::Granted) { + qApp->requestPermission(permission, [](const QPermission &) {}); + // Re-check after request + if (qApp->checkPermission(permission) != Qt::PermissionStatus::Granted) { return false; } } - - return true; -#else return true; -#endif #else return true; #endif @@ -311,20 +309,15 @@ bool Utility::requestBleScanPermission() bool Utility::requestBleConnectPermission() { #ifdef Q_OS_ANDROID -#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0) - QtAndroid::PermissionResult r = QtAndroid::checkPermission("android.permission.BLUETOOTH_CONNECT"); - if(r == QtAndroid::PermissionResult::Denied) { - QtAndroid::requestPermissionsSync( QStringList() << "android.permission.BLUETOOTH_CONNECT", 10000); - r = QtAndroid::checkPermission("android.permission.BLUETOOTH_CONNECT"); - if(r == QtAndroid::PermissionResult::Denied) { + QBluetoothPermission permission; + permission.setCommunicationModes(QBluetoothPermission::Access); + if (qApp->checkPermission(permission) != Qt::PermissionStatus::Granted) { + qApp->requestPermission(permission, [](const QPermission &) {}); + if (qApp->checkPermission(permission) != Qt::PermissionStatus::Granted) { return false; } } - - return true; -#else return true; -#endif #else return true; #endif @@ -333,12 +326,9 @@ bool Utility::requestBleConnectPermission() bool Utility::hasLocationPermission() { #ifdef Q_OS_ANDROID - QtAndroid::PermissionResult r = QtAndroid::checkPermission("android.permission.ACCESS_FINE_LOCATION"); - if (r == QtAndroid::PermissionResult::Denied) { - return false; - } else { - return true; - } + QLocationPermission permission; + permission.setAccuracy(QLocationPermission::Precise); + return qApp->checkPermission(permission) == Qt::PermissionStatus::Granted; #else return true; #endif @@ -350,10 +340,10 @@ void Utility::keepScreenOn(bool on) #endif #ifdef Q_OS_ANDROID - QtAndroid::runOnAndroidThread([on]{ - QAndroidJniObject activity = QtAndroid::androidActivity(); + QNativeInterface::QAndroidApplication::runOnAndroidMainThread([on]{ + QJniObject activity = QNativeInterface::QAndroidApplication::context(); if (activity.isValid()) { - QAndroidJniObject window = + QJniObject window = activity.callObjectMethod("getWindow", "()Landroid/view/Window;"); if (window.isValid()) { @@ -365,7 +355,7 @@ void Utility::keepScreenOn(bool on) } } } - QAndroidJniEnvironment env; + QJniEnvironment env; if (env->ExceptionCheck()) { env->ExceptionClear(); } @@ -379,14 +369,14 @@ void Utility::allowScreenRotation(bool enabled) { #ifdef Q_OS_ANDROID if (enabled) { - QAndroidJniObject activity = QtAndroid::androidActivity(); + QJniObject activity = QNativeInterface::QAndroidApplication::context(); activity.callMethod("setRequestedOrientation", "(I)V", - QAndroidJniObject::getStaticField("android.content.pm.ActivityInfo", + QJniObject::getStaticField("android.content.pm.ActivityInfo", "SCREEN_ORIENTATION_UNSPECIFIED")); } else { - QAndroidJniObject activity = QtAndroid::androidActivity(); + QJniObject activity = QNativeInterface::QAndroidApplication::context(); activity.callMethod("setRequestedOrientation", "(I)V", - QAndroidJniObject::getStaticField("android.content.pm.ActivityInfo", + QJniObject::getStaticField("android.content.pm.ActivityInfo", "SCREEN_ORIENTATION_PORTRAIT")); } #else @@ -1604,30 +1594,30 @@ QVariantList Utility::getNetworkAddresses() void Utility::startGnssForegroundService() { #ifdef Q_OS_ANDROID - QAndroidJniObject::callStaticMethod("com/vedder/vesc/Utils", + QJniObject::callStaticMethod("com/vedder/vesc/Utils", "startVForegroundService", "(Landroid/content/Context;)V", - QtAndroid::androidActivity().object()); + QNativeInterface::QAndroidApplication::context().object()); #endif } void Utility::stopGnssForegroundService() { #ifdef Q_OS_ANDROID - QAndroidJniObject::callStaticMethod("com/vedder/vesc/Utils", + QJniObject::callStaticMethod("com/vedder/vesc/Utils", "stopVForegroundService", "(Landroid/content/Context;)V", - QtAndroid::androidActivity().object()); + QNativeInterface::QAndroidApplication::context().object()); #endif } bool Utility::isBleScanEnabled() { #ifdef Q_OS_ANDROID - return QAndroidJniObject::callStaticMethod("com/vedder/vesc/Utils", + return QJniObject::callStaticMethod("com/vedder/vesc/Utils", "checkLocationEnabled", "(Landroid/content/Context;)Z", - QtAndroid::androidActivity().object()); + QNativeInterface::QAndroidApplication::context().object()); #else return true; #endif @@ -2563,22 +2553,22 @@ QVariantMap Utility::getSafeAreaMargins(QQuickWindow *window) QMargins margins = platformWindow->safeAreaMargins(); QVariantMap map; #ifdef Q_OS_ANDROID - int top = QAndroidJniObject::callStaticMethod("com/vedder/vesc/Utils", + int top = QJniObject::callStaticMethod("com/vedder/vesc/Utils", "topBarHeight", "(Landroid/content/Context;)I", - QtAndroid::androidActivity().object()); - int bottom = QAndroidJniObject::callStaticMethod("com/vedder/vesc/Utils", + QNativeInterface::QAndroidApplication::context().object()); + int bottom = QJniObject::callStaticMethod("com/vedder/vesc/Utils", "bottomBarHeight", "(Landroid/content/Context;)I", - QtAndroid::androidActivity().object()); - int right = QAndroidJniObject::callStaticMethod("com/vedder/vesc/Utils", + QNativeInterface::QAndroidApplication::context().object()); + int right = QJniObject::callStaticMethod("com/vedder/vesc/Utils", "rightBarHeight", "(Landroid/content/Context;)I", - QtAndroid::androidActivity().object()); - int left = QAndroidJniObject::callStaticMethod("com/vedder/vesc/Utils", + QNativeInterface::QAndroidApplication::context().object()); + int left = QJniObject::callStaticMethod("com/vedder/vesc/Utils", "leftBarHeight", "(Landroid/content/Context;)I", - QtAndroid::androidActivity().object()); + QNativeInterface::QAndroidApplication::context().object()); if (top > 0) { map["top"] = top / window->devicePixelRatio(); diff --git a/vescinterface.cpp b/vescinterface.cpp index 17ce2c7de..c8624c619 100755 --- a/vescinterface.cpp +++ b/vescinterface.cpp @@ -112,19 +112,19 @@ VescInterface::VescInterface(QObject *parent) : QObject(parent) mBlockFwSwap = false; #ifdef Q_OS_ANDROID - QAndroidJniObject activity = QAndroidJniObject::callStaticObjectMethod( - "org/qtproject/qt5/android/QtNative", "activity", "()Landroid/app/Activity;"); + QJniObject activity = QJniObject::callStaticObjectMethod( + "org/qtproject/qt/android/QtNative", "activity", "()Landroid/app/Activity;"); if (activity.isValid()) { - QAndroidJniObject serviceName = QAndroidJniObject::getStaticObjectField( + QJniObject serviceName = QJniObject::getStaticObjectField( "android/content/Context","POWER_SERVICE"); if (serviceName.isValid()) { - QAndroidJniObject powerMgr = activity.callObjectMethod( + QJniObject powerMgr = activity.callObjectMethod( "getSystemService", "(Ljava/lang/String;)Ljava/lang/Object;",serviceName.object()); if (powerMgr.isValid()) { - jint levelAndFlags = QAndroidJniObject::getStaticField( + jint levelAndFlags = QJniObject::getStaticField( "android/os/PowerManager","PARTIAL_WAKE_LOCK"); - QAndroidJniObject tag = QAndroidJniObject::fromString( "VESC Tool" ); + QJniObject tag = QJniObject::fromString( "VESC Tool" ); mWakeLock = powerMgr.callObjectMethod("newWakeLock", "(ILjava/lang/String;)Landroid/os/PowerManager$WakeLock;", levelAndFlags,tag.object()); @@ -142,8 +142,8 @@ VescInterface::VescInterface(QObject *parent) : QObject(parent) connect(mSerialPort, SIGNAL(readyRead()), this, SLOT(serialDataAvailable())); - connect(mSerialPort, SIGNAL(error(QSerialPort::SerialPortError)), - this, SLOT(serialPortError(QSerialPort::SerialPortError))); + connect(mSerialPort, &QSerialPort::errorOccurred, + this, &VescInterface::serialPortError); #endif // CANbus @@ -168,15 +168,15 @@ VescInterface::VescInterface(QObject *parent) : QObject(parent) connect(mTcpSocket, SIGNAL(connected()), this, SLOT(tcpInputConnected())); connect(mTcpSocket, SIGNAL(disconnected()), this, SLOT(tcpInputDisconnected())); - connect(mTcpSocket, SIGNAL(error(QAbstractSocket::SocketError)), - this, SLOT(tcpInputError(QAbstractSocket::SocketError))); + connect(mTcpSocket, &QAbstractSocket::errorOccurred, + this, &VescInterface::tcpInputError); // UDP mUdpSocket = new QUdpSocket(this); mUdpConnected = false; connect(mUdpSocket, SIGNAL(readyRead()), this, SLOT(udpInputDataAvailable())); - connect(mUdpSocket, SIGNAL(error(QAbstractSocket::SocketError)), - this, SLOT(udpInputError(QAbstractSocket::SocketError))); + connect(mUdpSocket, &QAbstractSocket::errorOccurred, + this, &VescInterface::udpInputError); // BLE #ifdef HAS_BLUETOOTH @@ -3134,7 +3134,7 @@ void VescInterface::tcpInputConnected() devNow.password = mLastTcpHubVescPass; bool found = false; - for (const auto &i: qAsConst(mTcpHubDevs)) { + for (const auto &i: std::as_const(mTcpHubDevs)) { auto dev = i.value(); if (dev.uuid() == devNow.uuid()) { found = true; @@ -4302,7 +4302,7 @@ bool VescInterface::updateTcpHubPassword(QString uuid, QString newPass) bool VescInterface::connectTcpHubUuid(QString uuid) { - for (const auto &i: qAsConst(mTcpHubDevs)) { + for (const auto &i: std::as_const(mTcpHubDevs)) { auto dev = i.value(); if (dev.uuid() == uuid) { connectTcpHub(dev.server, dev.port, dev.id, dev.password); diff --git a/vescinterface.h b/vescinterface.h index 8b6fdfb58..1868215c4 100755 --- a/vescinterface.h +++ b/vescinterface.h @@ -58,9 +58,9 @@ #endif #ifdef Q_OS_ANDROID -#include -#include -#include +#include +#include +#include #endif class VescInterface : public QObject @@ -449,7 +449,7 @@ private slots: #endif #ifdef Q_OS_ANDROID - QAndroidJniObject mWakeLock; + QJniObject mWakeLock; #endif bool mWakeLockActive; diff --git a/widgets/canlistitem.cpp b/widgets/canlistitem.cpp index fee60eada..05e9741b3 100644 --- a/widgets/canlistitem.cpp +++ b/widgets/canlistitem.cpp @@ -72,7 +72,7 @@ CANListItem::CANListItem(FW_RX_PARAMS p, setID(ID); QHBoxLayout *layout = new QHBoxLayout; - layout->setMargin(0); + layout->setContentsMargins(0, 0, 0, 0); layout->addSpacerItem(mSpaceStart); layout->addWidget(mIconLabel); diff --git a/widgets/experimentplot.cpp b/widgets/experimentplot.cpp index e01f19f1b..361d32016 100644 --- a/widgets/experimentplot.cpp +++ b/widgets/experimentplot.cpp @@ -315,7 +315,7 @@ void ExperimentPlot::on_experimentSaveXmlButton_clicked() } QXmlStreamWriter stream(&file); - stream.setCodec("UTF-8"); + // Qt6: QXmlStreamWriter always uses UTF-8, setCodec() removed stream.setAutoFormatting(true); stream.writeStartDocument(); diff --git a/widgets/mrichtextedit.cpp b/widgets/mrichtextedit.cpp index a2b4c191b..4fdc7405e 100644 --- a/widgets/mrichtextedit.cpp +++ b/widgets/mrichtextedit.cpp @@ -39,6 +39,7 @@ #include #include #include +#include MRichTextEdit::MRichTextEdit(QWidget *parent) : QWidget(parent) { setupUi(this); @@ -133,15 +134,15 @@ MRichTextEdit::MRichTextEdit(QWidget *parent) : QWidget(parent) { // link - f_link->setShortcut(Qt::CTRL + Qt::Key_L); + f_link->setShortcut(Qt::CTRL | Qt::Key_L); connect(f_link, SIGNAL(clicked(bool)), this, SLOT(textLink(bool))); // bold, italic & underline - f_bold->setShortcut(Qt::CTRL + Qt::Key_B); - f_italic->setShortcut(Qt::CTRL + Qt::Key_I); - f_underline->setShortcut(Qt::CTRL + Qt::Key_U); + f_bold->setShortcut(Qt::CTRL | Qt::Key_B); + f_italic->setShortcut(Qt::CTRL | Qt::Key_I); + f_underline->setShortcut(Qt::CTRL | Qt::Key_U); connect(f_bold, SIGNAL(clicked()), this, SLOT(textBold())); connect(f_italic, SIGNAL(clicked()), this, SLOT(textItalic())); @@ -178,16 +179,16 @@ MRichTextEdit::MRichTextEdit(QWidget *parent) : QWidget(parent) { // lists - f_list_bullet->setShortcut(Qt::CTRL + Qt::Key_Minus); - f_list_ordered->setShortcut(Qt::CTRL + Qt::Key_Equal); + f_list_bullet->setShortcut(Qt::CTRL | Qt::Key_Minus); + f_list_ordered->setShortcut(Qt::CTRL | Qt::Key_Equal); connect(f_list_bullet, SIGNAL(clicked(bool)), this, SLOT(listBullet(bool))); connect(f_list_ordered, SIGNAL(clicked(bool)), this, SLOT(listOrdered(bool))); // indentation - f_indent_dec->setShortcut(Qt::CTRL + Qt::Key_Comma); - f_indent_inc->setShortcut(Qt::CTRL + Qt::Key_Period); + f_indent_dec->setShortcut(Qt::CTRL | Qt::Key_Comma); + f_indent_inc->setShortcut(Qt::CTRL | Qt::Key_Period); connect(f_indent_inc, SIGNAL(clicked()), this, SLOT(increaseIndentation())); connect(f_indent_dec, SIGNAL(clicked()), this, SLOT(decreaseIndentation())); @@ -198,8 +199,8 @@ MRichTextEdit::MRichTextEdit(QWidget *parent) : QWidget(parent) { foreach(int size, db.standardSizes()) f_fontsize->addItem(QString::number(size)); - connect(f_fontsize, SIGNAL(activated(QString)), - this, SLOT(textSize(QString))); + connect(f_fontsize, &QComboBox::textActivated, + this, &MRichTextEdit::textSize); f_fontsize->setCurrentIndex(f_fontsize->findText(QString::number(QApplication::font() .pointSize()))); @@ -378,7 +379,7 @@ void MRichTextEdit::textStyle(int index) { } if (index == ParagraphMonospace) { fmt = cursor.charFormat(); - fmt.setFontFamily("DejaVu Sans Mono"); + fmt.setFontFamilies({QStringLiteral("DejaVu Sans Mono")}); fmt.setFontStyleHint(QFont::Monospace); fmt.setFontFixedPitch(true); } @@ -672,9 +673,9 @@ void MRichTextEdit::slotClipboardDataChanged() { QString MRichTextEdit::toHtml() const { QString s = f_textedit->toHtml(); // convert emails to links - s = s.replace(QRegExp("(<[^a][^>]+>(?:]+>)?|\\s)([a-zA-Z\\d]+@[a-zA-Z\\d]+\\.[a-zA-Z]+)"), "\\1\\2"); + s = s.replace(QRegularExpression("(<[^a][^>]+>(?:]+>)?|\\s)([a-zA-Z\\d]+@[a-zA-Z\\d]+\\.[a-zA-Z]+)"), "\\1\\2"); // convert links - s = s.replace(QRegExp("(<[^a][^>]+>(?:]+>)?|\\s)((?:https?|ftp|file)://[^\\s'\"<>]+)"), "\\1\\2"); + s = s.replace(QRegularExpression("(<[^a][^>]+>(?:]+>)?|\\s)((?:https?|ftp|file)://[^\\s'\"<>]+)"), "\\1\\2"); return s; } diff --git a/widgets/pagelistitem.cpp b/widgets/pagelistitem.cpp index ed8fbcbeb..03d358542 100644 --- a/widgets/pagelistitem.cpp +++ b/widgets/pagelistitem.cpp @@ -38,7 +38,7 @@ PageListItem::PageListItem(QString name, setGroupIcon(groupIcon); QHBoxLayout *layout = new QHBoxLayout; - layout->setMargin(0); + layout->setContentsMargins(0, 0, 0, 0); layout->addSpacerItem(mSpaceStart); layout->addWidget(mIconLabel); diff --git a/widgets/qcustomplot.h b/widgets/qcustomplot.h index 53b225144..29c932682 100644 --- a/widgets/qcustomplot.h +++ b/widgets/qcustomplot.h @@ -159,26 +159,8 @@ class QCPPolarGraph; It provides QMetaObject-based reflection of its enums and flags via \a QCP::staticMetaObject. */ -#ifndef Q_MOC_RUN namespace QCP { -#else -class QCP { // when in moc-run, make it look like a class, so we get Q_GADGET, Q_ENUMS/Q_FLAGS features in namespace - Q_GADGET - Q_ENUMS(ExportPen) - Q_ENUMS(ResolutionUnit) - Q_ENUMS(SignDomain) - Q_ENUMS(MarginSide) - Q_FLAGS(MarginSides) - Q_ENUMS(AntialiasedElement) - Q_FLAGS(AntialiasedElements) - Q_ENUMS(PlottingHint) - Q_FLAGS(PlottingHints) - Q_ENUMS(Interaction) - Q_FLAGS(Interactions) - Q_ENUMS(SelectionRectMode) - Q_ENUMS(SelectionType) -public: -#endif +Q_NAMESPACE /*! Defines the different units in which the image resolution can be specified in the export @@ -382,7 +364,19 @@ inline int getMarginValue(const QMargins &margins, QCP::MarginSide side) } -extern const QMetaObject staticMetaObject; // in moc-run we create a static meta object for QCP "fake" object. This line is the link to it via QCP::staticMetaObject in normal operation as namespace +Q_ENUM_NS(ExportPen) +Q_ENUM_NS(ResolutionUnit) +Q_ENUM_NS(SignDomain) +Q_ENUM_NS(MarginSide) +Q_FLAG_NS(MarginSides) +Q_ENUM_NS(AntialiasedElement) +Q_FLAG_NS(AntialiasedElements) +Q_ENUM_NS(PlottingHint) +Q_FLAG_NS(PlottingHints) +Q_ENUM_NS(Interaction) +Q_FLAG_NS(Interactions) +Q_ENUM_NS(SelectionRectMode) +Q_ENUM_NS(SelectionType) } // end of namespace QCP Q_DECLARE_OPERATORS_FOR_FLAGS(QCP::AntialiasedElements) diff --git a/widgets/vesc3dview.cpp b/widgets/vesc3dview.cpp index 0e1cf515a..2c0e0324c 100644 --- a/widgets/vesc3dview.cpp +++ b/widgets/vesc3dview.cpp @@ -45,6 +45,9 @@ Vesc3DView::Vesc3DView(QWidget *parent) : QOpenGLWidget(parent) // Multisampling QSurfaceFormat format; format.setSamples(4); + format.setDepthBufferSize(24); + format.setProfile(QSurfaceFormat::CompatibilityProfile); + format.setVersion(2, 1); setFormat(format); } @@ -107,9 +110,15 @@ void Vesc3DView::initializeGL() QOpenGLShader *vshader = new QOpenGLShader(QOpenGLShader::Vertex, this); const char *vsrc = + "#if __VERSION__ >= 130\n" + "in highp vec4 vertex;\n" + "in mediump vec4 texCoord;\n" + "out mediump vec4 texc;\n" + "#else\n" "attribute highp vec4 vertex;\n" "attribute mediump vec4 texCoord;\n" "varying mediump vec4 texc;\n" + "#endif\n" "uniform mediump mat4 matrix;\n" "void main(void)\n" "{\n" @@ -120,11 +129,20 @@ void Vesc3DView::initializeGL() QOpenGLShader *fshader = new QOpenGLShader(QOpenGLShader::Fragment, this); const char *fsrc = - "uniform sampler2D texture;\n" + "#if __VERSION__ >= 130\n" + "in mediump vec4 texc;\n" + "out mediump vec4 fragColor;\n" + "#else\n" "varying mediump vec4 texc;\n" + "#endif\n" + "uniform sampler2D tex;\n" "void main(void)\n" "{\n" - " gl_FragColor = texture2D(texture, texc.st);\n" + "#if __VERSION__ >= 130\n" + " fragColor = texture(tex, texc.st);\n" + "#else\n" + " gl_FragColor = texture2D(tex, texc.st);\n" + "#endif\n" "}\n"; fshader->compileSourceCode(fsrc); @@ -136,11 +154,17 @@ void Vesc3DView::initializeGL() mProgram->link(); mProgram->bind(); - mProgram->setUniformValue("texture", 0); + mProgram->setUniformValue("tex", 0); + mProgram->release(); + mVbo.release(); } void Vesc3DView::paintGL() { + if (!mProgram || !mVbo.isCreated()) { + return; + } + glClearColor(mBgColor.redF(), mBgColor.greenF(), mBgColor.blueF(), mBgColor.alphaF()); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); @@ -152,7 +176,6 @@ void Vesc3DView::paintGL() m.rotate(180, 0.0f, 0.0f, 1.0f); if (mUseQuaternions) { - // TODO: Test if this works... m.rotate(QQuaternion(mQ0, mQ1, mQ2, mQ3)); } else { m.rotate(mZRot, 0.0f, 1.0f, 0.0f); @@ -160,7 +183,12 @@ void Vesc3DView::paintGL() m.rotate(mXRot, 0.0f, 0.0f, 1.0f); } m.scale(1.0, 0.2, 1.0); + + mProgram->bind(); + mVbo.bind(); + mProgram->setUniformValue("matrix", m); + mProgram->setUniformValue("tex", 0); mProgram->enableAttributeArray(0); mProgram->enableAttributeArray(1); @@ -168,9 +196,14 @@ void Vesc3DView::paintGL() mProgram->setAttributeBuffer(1, GL_FLOAT, 3 * sizeof(GLfloat), 2, 5 * sizeof(GLfloat)); for (int i = 0; i < 6; ++i) { - mTextures[i]->bind(); - glDrawArrays(GL_TRIANGLE_FAN, i * 4, 4); + if (mTextures[i]) { + mTextures[i]->bind(); + glDrawArrays(GL_TRIANGLE_FAN, i * 4, 4); + } } + + mVbo.release(); + mProgram->release(); } void Vesc3DView::makeObject() diff --git a/widgets/vesc3dview.h b/widgets/vesc3dview.h index 844d4344b..ac95bd7ff 100644 --- a/widgets/vesc3dview.h +++ b/widgets/vesc3dview.h @@ -25,6 +25,7 @@ #include #include #include +#include QT_FORWARD_DECLARE_CLASS(QOpenGLShaderProgram) QT_FORWARD_DECLARE_CLASS(QOpenGLTexture) From 49c153ddb8a65e59bcbeffe098622a930a87bb3e Mon Sep 17 00:00:00 2001 From: Felix Date: Sat, 7 Mar 2026 23:53:47 +0100 Subject: [PATCH 02/16] Remove old .pro file --- vesc_tool.pro | 385 -------------------------------------------------- 1 file changed, 385 deletions(-) delete mode 100644 vesc_tool.pro diff --git a/vesc_tool.pro b/vesc_tool.pro deleted file mode 100644 index 9bfb1428a..000000000 --- a/vesc_tool.pro +++ /dev/null @@ -1,385 +0,0 @@ -#------------------------------------------------- -# -# Project created by QtCreator 2016-08-12T21:55:19 -# -#------------------------------------------------- - -# Version -VT_VERSION = 7.00 -VT_INTRO_VERSION = 1 -VT_CONFIG_VERSION = 4 - -# Set to 0 for stable versions and to test version number for development versions. -VT_IS_TEST_VERSION = 2 - -# GIT commit -VT_GIT_COMMIT = $$system(git rev-parse --short=8 HEAD) - -VT_ANDROID_VERSION_ARMV7 = 190 -VT_ANDROID_VERSION_ARM64 = 191 -VT_ANDROID_VERSION_X86 = 192 - -VT_ANDROID_VERSION = $$VT_ANDROID_VERSION_X86 - -# Ubuntu 18.04 (should work on raspbian buster too) -# sudo apt install qml-module-qt-labs-folderlistmodel qml-module-qtquick-extras qml-module-qtquick-controls2 qt5-default libqt5quickcontrols2-5 qtquickcontrols2-5-dev qtcreator qtcreator-doc libqt5serialport5-dev build-essential qml-module-qt3d qt3d5-dev qtdeclarative5-dev qtconnectivity5-dev qtmultimedia5-dev qtpositioning5-dev qtpositioning5-dev libqt5gamepad5-dev qml-module-qt-labs-settings qml-module-qt-labs-platform libqt5svg5-dev - -DEFINES += VT_VERSION=$$VT_VERSION -DEFINES += VT_INTRO_VERSION=$$VT_INTRO_VERSION -DEFINES += VT_CONFIG_VERSION=$$VT_CONFIG_VERSION -DEFINES += VT_IS_TEST_VERSION=$$VT_IS_TEST_VERSION -DEFINES += VT_GIT_COMMIT=$$VT_GIT_COMMIT -QT_LOGGING_RULES="qt.qml.connections=false" -#CONFIG += qtquickcompiler - -CONFIG += c++11 -CONFIG += resources_big -ios: { - QMAKE_CXXFLAGS_DEBUG += -Wall -} - -android: { - QMAKE_LFLAGS += -Wl,-z,max-page-size=16384 -Wl,-z,common-page-size=16384 -} - -!win32-msvc*: { !android: { - QMAKE_CXXFLAGS += -Wno-deprecated-copy -}} - -# Build mobile GUI -#CONFIG += build_mobile - -# Exclude built-in firmwares -CONFIG += exclude_fw - -ios: { - CONFIG += build_mobile - DEFINES += QT_NO_PRINTER -} - -# Debug build (e.g. F5 to reload QML files) -#DEFINES += DEBUG_BUILD - -# If BLE disconnects on ubuntu after about 90 seconds the reason is most likely that the connection interval is incompatible. This can be fixed with: -# sudo bash -c 'echo 6 > /sys/kernel/debug/bluetooth/hci0/conn_min_interval' - -# Clear old bluetooth devices -# sudo rm -rf /var/lib/bluetooth/* -# sudo service bluetooth restart - -# Bluetooth available -DEFINES += HAS_BLUETOOTH - -# CAN bus available -# Adding serialbus to Qt seems to break the serial port on static builds. TODO: Figure out why. -#DEFINES += HAS_CANBUS - -# Positioning -!win32: { - DEFINES += HAS_POS -} - -!ios: { - QT += printsupport -!android: { - # Serial port available - DEFINES += HAS_SERIALPORT - DEFINES += HAS_GAMEPAD -} -} - -win32: { - DEFINES += _USE_MATH_DEFINES -} - -# https://stackoverflow.com/questions/61444320/what-are-the-configure-options-for-qt-that-enable-dead-keys-usage -unix: { -!ios: { - QTPLUGIN += composeplatforminputcontextplugin -} -} - -# Options -#CONFIG += build_original -#CONFIG += build_platinum -#CONFIG += build_gold -#CONFIG += build_silver -#CONFIG += build_bronze -#CONFIG += build_free - -QT += core gui -QT += widgets -QT += network -QT += quick -QT += quickcontrols2 -QT += quickwidgets -QT += svg -QT += gui-private - -contains(DEFINES, HAS_SERIALPORT) { - QT += serialport -} - -contains(DEFINES, HAS_CANBUS) { - QT += serialbus -} - -contains(DEFINES, HAS_BLUETOOTH) { - QT += bluetooth -} - -contains(DEFINES, HAS_POS) { - QT += positioning -} - -contains(DEFINES, HAS_GAMEPAD) { - QT += gamepad -} - -android: QT += androidextras - -ios | macx: { - TARGET = "VESC Tool" - CONFIG += sdk_no_version_check -}else: { - android:{ - TARGET = "vesc_tool" - }else:{ - - TARGET = vesc_tool_$$VT_VERSION - } -} - -ANDROID_VERSION = 1 - -android:contains(QT_ARCH, i386) { - VT_ANDROID_VERSION = $$VT_ANDROID_VERSION_X86 -} - -contains(ANDROID_TARGET_ARCH, arm64-v8a) { - VT_ANDROID_VERSION = $$VT_ANDROID_VERSION_ARM64 -} - -contains(ANDROID_TARGET_ARCH, armeabi-v7a) { - VT_ANDROID_VERSION = $$VT_ANDROID_VERSION_ARMV7 -} - -android: { - manifest.input = $$PWD/android/AndroidManifest.xml.in - manifest.output = $$PWD/android/AndroidManifest.xml - QMAKE_SUBSTITUTES += manifest -} - -TEMPLATE = app - -release_win { - DESTDIR = build/win - OBJECTS_DIR = build/win/obj - MOC_DIR = build/win/obj - RCC_DIR = build/win/obj - UI_DIR = build/win/obj -} - -release_lin { - # http://micro.nicholaswilson.me.uk/post/31855915892/rules-of-static-linking-libstdc-libc-libgcc - # http://insanecoding.blogspot.se/2012/07/creating-portable-linux-binaries.html - QMAKE_LFLAGS += -static-libstdc++ -static-libgcc - DESTDIR = build/lin - OBJECTS_DIR = build/lin/obj - MOC_DIR = build/lin/obj - RCC_DIR = build/lin/obj - UI_DIR = build/lin/obj -} - -release_macos { - # brew install qt - DESTDIR = build/macos - OBJECTS_DIR = build/macos/obj - MOC_DIR = build/macos/obj - RCC_DIR = build/macos/obj - UI_DIR = build/macos/obj -} - -release_android { - DESTDIR = build/android - OBJECTS_DIR = build/android/obj - MOC_DIR = build/android/obj - RCC_DIR = build/android/obj - UI_DIR = build/android/obj -} - -build_mobile { - DEFINES += USE_MOBILE -} - -SOURCES += main.cpp\ - bleuartdummy.cpp \ - codeloader.cpp \ - mainwindow.cpp \ - boardsetupwindow.cpp \ - packet.cpp \ - preferences.cpp \ - tcphub.cpp \ - udpserversimple.cpp \ - vbytearray.cpp \ - commands.cpp \ - configparams.cpp \ - configparam.cpp \ - vescinterface.cpp \ - parametereditor.cpp \ - digitalfiltering.cpp \ - setupwizardapp.cpp \ - setupwizardmotor.cpp \ - startupwizard.cpp \ - utility.cpp \ - tcpserversimple.cpp \ - hexfile.cpp - -HEADERS += mainwindow.h \ - bleuartdummy.h \ - codeloader.h \ - boardsetupwindow.h \ - packet.h \ - preferences.h \ - tcphub.h \ - udpserversimple.h \ - vbytearray.h \ - commands.h \ - datatypes.h \ - configparams.h \ - configparam.h \ - vescinterface.h \ - parametereditor.h \ - digitalfiltering.h \ - setupwizardapp.h \ - setupwizardmotor.h \ - startupwizard.h \ - utility.h \ - tcpserversimple.h \ - hexfile.h - -unix: { -!ios: { - HEADERS += systemcommandexecutor.h -} -} - -FORMS += mainwindow.ui \ - boardsetupwindow.ui \ - parametereditor.ui \ - preferences.ui - -contains(DEFINES, HAS_BLUETOOTH) { - SOURCES += bleuart.cpp - HEADERS += bleuart.h -} - -include(pages/pages.pri) -include(widgets/widgets.pri) -include(mobile/mobile.pri) -include(map/map.pri) -include(lzokay/lzokay.pri) -include(heatshrink/heatshrink.pri) -include(QCodeEditor/qcodeeditor.pri) -include(esp32/esp32.pri) -include(display_tool/display_tool.pri) -include(qmarkdowntextedit/qmarkdowntextedit.pri) -include(maddy/maddy.pri) -include(minimp3/minimp3.pri) - -RESOURCES += res.qrc \ - res_custom_module.qrc \ - res_lisp.qrc \ - res_qml.qrc -RESOURCES += res/config/res_config.qrc - -RESOURCES += res_fw_bms.qrc - -!exclude_fw { - RESOURCES += res/firmwares/res_fw.qrc -} - -build_original { - RESOURCES += res_original.qrc - DEFINES += VER_ORIGINAL -} else:build_platinum { - RESOURCES += res_platinum.qrc - DEFINES += VER_PLATINUM -} else:build_gold { - RESOURCES += res_gold.qrc - DEFINES += VER_GOLD -} else:build_silver { - RESOURCES += res_silver.qrc - DEFINES += VER_SILVER -} else:build_bronze { - RESOURCES += res_bronze.qrc - DEFINES += VER_BRONZE -} else:build_free { - RESOURCES += res_free.qrc - DEFINES += VER_FREE -} else { - RESOURCES += res_neutral.qrc - DEFINES += VER_NEUTRAL -} - -DISTFILES += \ - android/AndroidManifest.xml \ - android/gradle/wrapper/gradle-wrapper.jar \ - android/gradlew \ - android/gradlew.bat \ - android/res/values/libs.xml \ - android/build.gradle \ - android/gradle/wrapper/gradle-wrapper.properties \ - android/src/com/vedder/vesc/VForegroundService.java \ - android/src/com/vedder/vesc/Utils.java - -ANDROID_PACKAGE_SOURCE_DIR = $$PWD/android - -macx-clang:contains(QMAKE_HOST.arch, arm.*): { - QMAKE_APPLE_DEVICE_ARCHS=arm64 -} - -macx { - ICON = macos/appIcon.icns - QMAKE_INFO_PLIST = macos/Info.plist - DISTFILES += macos/Info.plist - QMAKE_CFLAGS_RELEASE = $$QMAKE_CFLAGS_RELEASE_WITH_DEBUGINFO - QMAKE_CXXFLAGS_RELEASE = $$QMAKE_CXXFLAGS_RELEASE_WITH_DEBUGINFO - QMAKE_OBJECTIVE_CFLAGS_RELEASE = $$QMAKE_OBJECTIVE_CFLAGS_RELEASE_WITH_DEBUGINFO - QMAKE_LFLAGS_RELEASE = $$QMAKE_LFLAGS_RELEASE_WITH_DEBUGINFO - QMAKE_APPLE_DEVICE_ARCHS = x86_64 arm64 -} - -ios { - QMAKE_INFO_PLIST = ios/Info.plist - HEADERS += ios/src/setIosParameters.h - SOURCES += ios/src/setIosParameters.mm - DISTFILES += ios/Info.plist \ - ios/*.storyboard - QMAKE_ASSET_CATALOGS = $$PWD/ios/Images.xcassets - QMAKE_ASSET_CATALOGS_APP_ICON = "AppIcon" - - ios_artwork.files = $$files($$PWD/ios/iTunesArtwork*.png) - QMAKE_BUNDLE_DATA += ios_artwork - app_launch_images.files = $$files($$PWD/ios/LaunchImage*.png) - QMAKE_BUNDLE_DATA += app_launch_images - app_launch_screen.files = $$files($$PWD/ios/MyLaunchScreen.storyboard) - QMAKE_BUNDLE_DATA += app_launch_screen - - #QMAKE_IOS_DEPLOYMENT_TARGET = 11.0 - - disable_warning.name = GCC_WARN_64_TO_32_BIT_CONVERSION - disable_warning.value = NO - - QMAKE_MAC_XCODE_SETTINGS += disable_warning - - # Note for devices: 1=iPhone, 2=iPad, 1,2=Universal. - CONFIG -= warn_on - QMAKE_APPLE_TARGETED_DEVICE_FAMILY = 1,2 -} -CONFIG -= warn_on - -contains(ANDROID_TARGET_ARCH,) { - ANDROID_ABIS = \ - armeabi-v7a -} From b16c7e0bc3b101e7f3ed8308fc3c36041e837b26 Mon Sep 17 00:00:00 2001 From: Felix Date: Sun, 8 Mar 2026 01:59:04 +0100 Subject: [PATCH 03/16] Refactor to modern Qt signal/slot and QML registration Converts `SIGNAL`/`SLOT` macro usage to type-safe pointer-to-member syntax, enhancing compile-time error detection and code robustness. Transitions QML type registration to use the `QML_ELEMENT` macro and `qt_add_qml_module` in CMake. This streamlines QML imports by providing all types under a single module (`Vedder.vesc`) and removes numerous manual `qmlRegisterType` calls. Removes explicit `qRegisterMetaType` calls, leveraging automatic metatype registration available in modern Qt. Updates `foreach` loops to range-based for loops for improved code readability. Ensures the correct `BleUart` or `BleUartDummy` implementation is included based on the build's Bluetooth support. --- CMakeLists.txt | 18 +- bleuart.cpp | 6 +- bleuart.h | 2 + bleuartdummy.h | 2 + boardsetupwindow.cpp | 66 ++-- codeloader.cpp | 24 +- codeloader.h | 3 +- commands.cpp | 28 +- commands.h | 6 +- configparams.h | 6 +- convert_signal_slot2.py | 418 ++++++++++++++++++++++ esp32/esp32flash.h | 2 + main.cpp | 66 +--- mainwindow.cpp | 63 ++-- map/mapwidget.cpp | 6 +- map/osmclient.cpp | 3 +- minimp3/qminimp3.h | 2 + mobile/AdcMap.qml | 4 +- mobile/BMS.qml | 4 +- mobile/BleSetupDialog.qml | 5 +- mobile/CanScreen.qml | 5 +- mobile/ConfigPageApp.qml | 5 +- mobile/ConfigPageCustom.qml | 5 +- mobile/ConfigPageMotor.qml | 5 +- mobile/ConnectScreen.qml | 6 +- mobile/Controls.qml | 5 +- mobile/CustomGauge.qml | 2 +- mobile/CustomGaugeV2.qml | 2 +- mobile/DetectBldc.qml | 5 +- mobile/DetectFocEncoder.qml | 5 +- mobile/DetectFocHall.qml | 5 +- mobile/DetectFocParam.qml | 5 +- mobile/DirectionSetup.qml | 5 +- mobile/DirectoryPicker.qml | 2 +- mobile/FilePicker.qml | 2 +- mobile/FwUpdate.qml | 6 +- mobile/ImageButton.qml | 2 +- mobile/Lisp.qml | 5 +- mobile/LogBox.qml | 3 +- mobile/MultiSettings.qml | 5 +- mobile/NrfPair.qml | 4 +- mobile/Packages.qml | 6 +- mobile/PairingDialog.qml | 5 +- mobile/ParamEditBitfield.qml | 4 +- mobile/ParamEditBool.qml | 4 +- mobile/ParamEditDouble.qml | 4 +- mobile/ParamEditEnum.qml | 4 +- mobile/ParamEditInt.qml | 4 +- mobile/ParamEditSeparator.qml | 2 +- mobile/ParamEditString.qml | 4 +- mobile/ParamEditors.qml | 4 +- mobile/PpmMap.qml | 4 +- mobile/ProfileDisplay.qml | 5 +- mobile/ProfileEditor.qml | 4 +- mobile/Profiles.qml | 3 +- mobile/RtData.qml | 5 +- mobile/RtDataIMU.qml | 5 +- mobile/RtDataSetup.qml | 5 +- mobile/Settings.qml | 3 +- mobile/SetupWizardFoc.qml | 5 +- mobile/SetupWizardIMU.qml | 5 +- mobile/SetupWizardInput.qml | 5 +- mobile/SetupWizardIntro.qml | 4 +- mobile/StartPage.qml | 5 +- mobile/StatPage.qml | 4 +- mobile/TcpBox.qml | 3 +- mobile/TcpHubBox.qml | 3 +- mobile/Terminal.qml | 5 +- mobile/fwhelper.h | 2 + mobile/logreader.h | 2 + mobile/logwriter.h | 2 + mobile/main.qml | 6 +- mobile/qmlui.cpp | 10 +- mobile/vesc3ditem.h | 1 + packet.cpp | 2 +- packet.h | 4 +- pages/pageappadc.cpp | 8 +- pages/pageappimu.cpp | 7 +- pages/pageappnunchuk.cpp | 12 +- pages/pageappppm.cpp | 8 +- pages/pagebms.cpp | 4 +- pages/pagecananalyzer.cpp | 4 +- pages/pageconnection.cpp | 26 +- pages/pagecustomconfig.cpp | 3 +- pages/pagedisplaytool.cpp | 52 +-- pages/pageespprog.cpp | 8 +- pages/pageexperiments.cpp | 12 +- pages/pagefirmware.cpp | 26 +- pages/pageimu.cpp | 7 +- pages/pagelisp.cpp | 6 +- pages/pageloganalysis.cpp | 38 +- pages/pagemotorinfo.cpp | 8 +- pages/pagertdata.cpp | 11 +- pages/pagesampleddata.cpp | 50 +-- pages/pagescripting.cpp | 2 +- pages/pageswdprog.cpp | 13 +- pages/pageterminal.cpp | 4 +- pages/pagevescpackage.cpp | 2 +- pages/pagewelcome.cpp | 4 +- parametereditor.cpp | 3 +- preferences.cpp | 3 +- res/qml/DynamicLoader.qml | 2 +- res/qml/Examples/BMS.qml | 3 +- res/qml/Examples/BalanceUi.qml | 4 +- res/qml/Examples/BrakeBench.qml | 3 +- res/qml/Examples/CanDebugger.qml | 4 +- res/qml/Examples/ConfigParams.qml | 3 +- res/qml/Examples/Controls.qml | 4 +- res/qml/Examples/DCDC.qml | 4 +- res/qml/Examples/ExperimentPlot.qml | 3 +- res/qml/Examples/GaugeTest.qml | 4 +- res/qml/Examples/IoBoard.qml | 4 +- res/qml/Examples/LogTextToFile.qml | 4 +- res/qml/Examples/MMXGui.qml | 4 +- res/qml/Examples/Meters.qml | 4 +- res/qml/Examples/MotorComparisonModel.qml | 2 +- res/qml/Examples/Mp3Stream.qml | 4 +- res/qml/Examples/ParamTableAndPlot.qml | 4 +- res/qml/Examples/ParentTabBar.qml | 2 +- res/qml/Examples/PollValues.qml | 4 +- res/qml/Examples/PositionControl.qml | 3 +- res/qml/Examples/Profiles.qml | 2 +- res/qml/Examples/Reconnect.qml | 4 +- res/qml/Examples/RpmSlider.qml | 4 +- res/qml/Examples/RtData.qml | 4 +- res/qml/Examples/RtDataSetup.qml | 5 +- res/qml/Examples/SendToLbm.qml | 3 +- res/qml/Examples/TcpHub.qml | 5 +- res/qml/Examples/TcpServer.qml | 5 +- res/qml/Examples/UdpServer.qml | 2 +- res/qml/MainLoader.qml | 2 +- res/qml/SetupMotorWindow.qml | 2 +- res/qml/WelcomeQmlPanel.qml | 2 +- setupwizardapp.cpp | 72 ++-- setupwizardmotor.cpp | 16 +- startupwizard.cpp | 20 +- systemcommandexecutor.h | 2 + tcphub.cpp | 4 +- tcphub.h | 2 + tcpserversimple.cpp | 19 +- tcpserversimple.h | 4 +- udpserversimple.cpp | 5 +- udpserversimple.h | 4 +- utility.cpp | 90 +++-- utility.h | 17 + vescinterface.cpp | 137 +++---- vescinterface.h | 12 +- widgets/adcmap.cpp | 4 +- widgets/detectallfocdialog.cpp | 12 +- widgets/detectbldc.cpp | 4 +- widgets/detectfoc.cpp | 16 +- widgets/detectfocencoder.cpp | 4 +- widgets/detectfochall.cpp | 4 +- widgets/experimentplot.cpp | 22 +- widgets/mrichtextedit.cpp | 73 ++-- widgets/nrfpair.cpp | 7 +- widgets/parameditbitfield.cpp | 3 +- widgets/parameditbool.cpp | 3 +- widgets/parameditdouble.cpp | 9 +- widgets/parameditenum.cpp | 3 +- widgets/parameditint.cpp | 9 +- widgets/parameditstring.cpp | 3 +- widgets/paramtable.cpp | 2 +- widgets/ppmmap.cpp | 4 +- 164 files changed, 1112 insertions(+), 870 deletions(-) create mode 100644 convert_signal_slot2.py diff --git a/CMakeLists.txt b/CMakeLists.txt index 68ae6b2f0..9c4aa5acf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -179,7 +179,6 @@ endif() # --------------------------------------------------------------------------- set(ROOT_SOURCES main.cpp - bleuartdummy.cpp codeloader.cpp mainwindow.cpp boardsetupwindow.cpp @@ -204,7 +203,6 @@ set(ROOT_SOURCES set(ROOT_HEADERS mainwindow.h - bleuartdummy.h codeloader.h boardsetupwindow.h packet.h @@ -241,6 +239,9 @@ endif() if(HAS_BLUETOOTH) list(APPEND ROOT_SOURCES bleuart.cpp) list(APPEND ROOT_HEADERS bleuart.h) +else() + list(APPEND ROOT_SOURCES bleuartdummy.cpp) + list(APPEND ROOT_HEADERS bleuartdummy.h) endif() # --------------------------------------------------------------------------- @@ -788,6 +789,19 @@ qt_add_executable(${APP_TARGET} ${RESOURCE_FILES} ) +# --------------------------------------------------------------------------- +# QML module – exposes all QML_ELEMENT-annotated C++ types under "Vedder.vesc" +# This replaces the legacy qmlRegisterType() calls. +# QML files import it with: import Vedder.vesc +# --------------------------------------------------------------------------- +qt_add_qml_module(${APP_TARGET} + URI Vedder.vesc + VERSION 1.0 + # No QML files in the module — they stay in .qrc resources. + # The C++ types are already in the target sources; QML_ELEMENT does the rest. + NO_RESOURCE_TARGET_PATH +) + # --------------------------------------------------------------------------- # Compile definitions # --------------------------------------------------------------------------- diff --git a/bleuart.cpp b/bleuart.cpp index 1c2aa8797..b5909b8c3 100644 --- a/bleuart.cpp +++ b/bleuart.cpp @@ -242,10 +242,8 @@ void BleUart::serviceScanDone() this, &BleUart::serviceStateChanged); connect(mService, &QLowEnergyService::errorOccurred, this, &BleUart::serviceError); - connect(mService, SIGNAL(characteristicChanged(QLowEnergyCharacteristic,QByteArray)), - this, SLOT(updateData(QLowEnergyCharacteristic,QByteArray))); - connect(mService, SIGNAL(descriptorWritten(QLowEnergyDescriptor,QByteArray)), - this, SLOT(confirmedDescriptorWrite(QLowEnergyDescriptor,QByteArray))); + connect(mService, &QLowEnergyService::characteristicChanged, this, &BleUart::updateData); + connect(mService, &QLowEnergyService::descriptorWritten, this, &BleUart::confirmedDescriptorWrite); mService->discoverDetails(); } else { diff --git a/bleuart.h b/bleuart.h index 12f3aa838..28046b404 100644 --- a/bleuart.h +++ b/bleuart.h @@ -27,10 +27,12 @@ #include #include #include +#include class BleUart : public QObject { Q_OBJECT + QML_ELEMENT public: explicit BleUart(QObject *parent = nullptr); ~BleUart(); diff --git a/bleuartdummy.h b/bleuartdummy.h index b881d7022..0ea1799f2 100644 --- a/bleuartdummy.h +++ b/bleuartdummy.h @@ -22,10 +22,12 @@ #include #include +#include class BleUartDummy : public QObject { Q_OBJECT + QML_NAMED_ELEMENT(BleUart) public: explicit BleUartDummy(QObject *parent = nullptr); diff --git a/boardsetupwindow.cpp b/boardsetupwindow.cpp index 763663df6..9de7a109f 100644 --- a/boardsetupwindow.cpp +++ b/boardsetupwindow.cpp @@ -35,18 +35,14 @@ BoardSetupWindow::BoardSetupWindow(QWidget *parent) : mKeyRight = false; - connect(mTimer, SIGNAL(timeout()), - this, SLOT(timerSlot())); - connect(mVesc, SIGNAL(statusMessage(QString,bool)), - this, SLOT(showStatusInfo(QString,bool))); - connect(mVesc, SIGNAL(messageDialog(QString,QString,bool,bool)), - this, SLOT(showMessageDialog(QString,QString,bool,bool))); - connect(mVesc->commands(), SIGNAL(pingCanRx(QVector,bool)), - this, SLOT(pingCanRx(QVector,bool))); - connect(mVesc, SIGNAL(fwUploadStatus(QString,double,bool)), - this, SLOT(fwUploadStatus(QString,double,bool))); - connect(mVesc->commands(), SIGNAL(valuesReceived(MC_VALUES,unsigned int)), - this, SLOT(valuesReceived(MC_VALUES,unsigned int))); + connect(mTimer, &QTimer::timeout, this, &BoardSetupWindow::timerSlot); + connect(mVesc, &VescInterface::statusMessage, this, &BoardSetupWindow::showStatusInfo); + connect(mVesc, &VescInterface::messageDialog, this, &BoardSetupWindow::showMessageDialog); + connect(mVesc->commands(), &Commands::pingCanRx, + this, &BoardSetupWindow::pingCanRx); + connect(mVesc, &VescInterface::fwUploadStatus, this, &BoardSetupWindow::fwUploadStatus); + connect(mVesc->commands(), &Commands::valuesReceived, + this, &BoardSetupWindow::valuesReceived); mTimer->start(20); @@ -357,7 +353,7 @@ bool BoardSetupWindow::trySerialConnect(){ mVesc->commands()->setSendCan(false); res = mVesc->connectSerial(ui->serialPortBox->currentData().toString(), 115200); if(res){ - Utility::waitSignal(mVesc, SIGNAL(fwRxChanged(bool, bool)), 5000); + Utility::waitSignal(mVesc, &VescInterface::fwRxChanged, 5000); } if(mVesc->isPortConnected()){ ui->usbConnectLabel->setStyleSheet("QLabel { background-color : lightGreen; color : black; }"); @@ -373,7 +369,7 @@ bool BoardSetupWindow::tryCANScan(){ bool res = false; if(mVesc->isPortConnected()){ mVesc->commands()->pingCan(); - Utility::waitSignal(mVesc->commands(), SIGNAL(pingCanRx(QVector, bool)), 10000); + Utility::waitSignal(mVesc->commands(), &Commands::pingCanRx, 10000); } if(CAN_Timeout){ res = false; @@ -384,7 +380,7 @@ bool BoardSetupWindow::tryCANScan(){ res = true; mVesc->commands()->setSendCan(false); mVesc->commands()->getAppConf(); - if(!Utility::waitSignal(mVesc->appConfig(), SIGNAL(updated()), 5000)){ + if(!Utility::waitSignal(mVesc->appConfig(), &ConfigParams::updated, 5000)){ ui->CANScanLabel->setStyleSheet("QLabel { background-color : red; color : black; }"); testResultMsg = "Failed to read app config during CAN Scan."; return false; @@ -513,7 +509,7 @@ bool BoardSetupWindow::tryFOCCalibration(){ mVesc->commands()->setSendCan(false); mVesc->ignoreCanChange(true); mVesc->commands()->getAppConf(); - if(!Utility::waitSignal(mVesc->appConfig(), SIGNAL(updated()), 5000)){ + if(!Utility::waitSignal(mVesc->appConfig(), &ConfigParams::updated, 5000)){ ui->motorDetectionLabel->setStyleSheet("QLabel { background-color : red; color : black; }"); testResultMsg = "Failed to read app config during motor setup routine."; return false; @@ -522,7 +518,7 @@ bool BoardSetupWindow::tryFOCCalibration(){ mVesc->appConfig()->updateParamEnum("app_to_use",0); // set to use no app Utility::sleepWithEventLoop(100); mVesc->commands()->setAppConf(); - if(!Utility::waitSignal(mVesc->commands(), SIGNAL(ackReceived(QString)), 2000)){ + if(!Utility::waitSignal(mVesc->commands(), &Commands::ackReceived, 2000)){ ui->appSetupLabel->setStyleSheet("QLabel { background-color : red; color : black; }"); testResultMsg = "Failed to write app config during motor routine."; return false; @@ -542,12 +538,12 @@ bool BoardSetupWindow::tryFOCCalibration(){ ui->motorDetectionLabel->setText("Writing Default Configs"); mVesc->commands()->setSendCan(false); mVesc->commands()->setMcconf(false); - Utility::waitSignal(mVesc->commands(), SIGNAL(ackReceived(QString)), 2000); + Utility::waitSignal(mVesc->commands(), &Commands::ackReceived, 2000); for(int i = 0; i < CAN_IDs.size(); i++){ mVesc->commands()->setSendCan(true, CAN_IDs.at(i)); mVesc->commands()->setMcconf(); - Utility::waitSignal(mVesc->commands(), SIGNAL(ackReceived(QString)), 2000); + Utility::waitSignal(mVesc->commands(), &Commands::ackReceived, 2000); } mVesc->ignoreCanChange(false); mVesc->commands()->setSendCan(false); @@ -586,7 +582,7 @@ bool BoardSetupWindow::tryFOCCalibration(){ mVesc->commands()->setSendCan(true, CAN_IDs.at(i)); } mVesc->commands()->getMcconf(); - Utility::waitSignal(mVesc->mcConfig(), SIGNAL(updated()), 5000); + Utility::waitSignal(mVesc->mcConfig(), &ConfigParams::updated, 5000); if(mcConfigOutsideParamBounds("foc_motor_r",tolerance )){ ui->motorDetectionLabel->setStyleSheet("QLabel { background-color : red; color : black; }"); @@ -652,7 +648,7 @@ bool BoardSetupWindow::tryMotorDirection(){ } mVesc->commands()->getValues(); - if(!Utility::waitSignal(mVesc->commands(), SIGNAL(valuesReceived(MC_VALUES, unsigned int)), 2000)){ + if(!Utility::waitSignal(mVesc->commands(), &Commands::valuesReceived, 2000)){ ui->motorDirectionLabel->setStyleSheet("QLabel { background-color : red; color : black; }"); testResultMsg = "Failed to read tachometer value during motor direction routine."; return false; @@ -667,7 +663,7 @@ bool BoardSetupWindow::tryMotorDirection(){ msgBox->setText(directionStatus); msgBox->addButton(QMessageBox::Cancel); msgBox->setModal( true ); - msgBox->open(this, SLOT(msgBoxClosed(QAbstractButton*))); + msgBox->open(); mVesc->ignoreCanChange(true); while(!allHaveTurned){ directionStatus = tr("Spin each motor in the forward direction to continue.\n"); @@ -681,7 +677,7 @@ bool BoardSetupWindow::tryMotorDirection(){ } Utility::sleepWithEventLoop(10); mVesc->commands()->getValues(); - if(Utility::waitSignal(mVesc->commands(), SIGNAL(valuesReceived(MC_VALUES, unsigned int)), 100)){ + if(Utility::waitSignal(mVesc->commands(), &Commands::valuesReceived, 100)){ tach_end[i+1] = values_now.tachometer; } int tachDiff = tach_start[i+1] - tach_end[i+1]; @@ -724,7 +720,7 @@ bool BoardSetupWindow::tryMotorDirection(){ } Utility::sleepWithEventLoop(100); mVesc->commands()->getMcconf(); - if(!Utility::waitSignal(mVesc->mcConfig(), SIGNAL(updated()), 5000)){ + if(!Utility::waitSignal(mVesc->mcConfig(), &ConfigParams::updated, 5000)){ ui->motorDirectionLabel->setStyleSheet("QLabel { background-color : red; color : black; }"); testResultMsg = "Failed to read config during motor direction routine."; return false; @@ -738,7 +734,7 @@ bool BoardSetupWindow::tryMotorDirection(){ mVesc->mcConfig()->updateParamDouble("l_in_current_max", motor_current_in_max); mVesc->commands()->setMcconf(false); - if(!Utility::waitSignal(mVesc->commands(), SIGNAL(ackReceived(QString)), 2000)){ + if(!Utility::waitSignal(mVesc->commands(), &Commands::ackReceived, 2000)){ ui->motorDirectionLabel->setStyleSheet("QLabel { background-color : red; color : black; }"); testResultMsg = "Failed to write config during during motor direction routine."; return false; @@ -759,14 +755,14 @@ bool BoardSetupWindow::tryTestMotorParameters(){ if(!ui->appCheckBox->isChecked()){ mVesc->commands()->setSendCan(false); mVesc->commands()->getAppConf(); - if(!Utility::waitSignal(mVesc->appConfig(), SIGNAL(updated()), 5000)){ + if(!Utility::waitSignal(mVesc->appConfig(), &ConfigParams::updated, 5000)){ ui->motorDetectionLabel->setStyleSheet("QLabel { background-color : red; color : black; }"); testResultMsg = "Failed to read app config after motor setup routine."; return false; } mVesc->appConfig()->updateParamEnum("app_to_use",app_enum_old); // set to use no app mVesc->commands()->setAppConf(); - if(!Utility::waitSignal(mVesc->commands(), SIGNAL(ackReceived(QString)), 2000)){ + if(!Utility::waitSignal(mVesc->commands(), &Commands::ackReceived, 2000)){ ui->appSetupLabel->setStyleSheet("QLabel { background-color : red; color : black; }"); testResultMsg = "Failed to write app config after motor routine."; return false; @@ -783,7 +779,7 @@ bool BoardSetupWindow::tryApplySlaveAppSettings(){ int master_ID = 0; mVesc->commands()->setSendCan(false); mVesc->commands()->getAppConf(); - if(!Utility::waitSignal(mVesc->appConfig(), SIGNAL(updated()), 5000)){ + if(!Utility::waitSignal(mVesc->appConfig(), &ConfigParams::updated, 5000)){ ui->appSetupLabel->setStyleSheet("QLabel { background-color : red; color : black; }"); testResultMsg = "Failed to read app config during slave setup routine."; return false; @@ -791,7 +787,7 @@ bool BoardSetupWindow::tryApplySlaveAppSettings(){ master_ID = mVesc->appConfig()->getParamInt("controller_id"); mVesc->appConfig()->updateParamEnum("app_to_use",0); // set to use uart mVesc->commands()->setAppConf(); - if(!Utility::waitSignal(mVesc->commands(), SIGNAL(ackReceived(QString)), 5000)){ + if(!Utility::waitSignal(mVesc->commands(), &Commands::ackReceived, 5000)){ ui->appSetupLabel->setStyleSheet("QLabel { background-color : red; color : black; }"); testResultMsg = "Failed to write master config during slave app routine."; return false; @@ -833,7 +829,7 @@ bool BoardSetupWindow::tryApplySlaveAppSettings(){ mVesc->appConfig()->updateParamInt("controller_id", CAN_IDs.at(i)); Utility::sleepWithEventLoop(100); mVesc->commands()->setAppConf(); - if(!Utility::waitSignal(mVesc->commands(), SIGNAL(ackReceived(QString)), 2000)){ + if(!Utility::waitSignal(mVesc->commands(), &Commands::ackReceived, 2000)){ ui->appSetupLabel->setStyleSheet("QLabel { background-color : red; color : black; }"); testResultMsg = "Failed to write config during slave app routine."; return false; @@ -849,7 +845,7 @@ bool BoardSetupWindow::tryApplyMasterAppSettings(){ int master_ID = 0; mVesc->commands()->setSendCan(false); mVesc->commands()->getAppConf(); - if(!Utility::waitSignal(mVesc->appConfig(), SIGNAL(updated()), 5000)){ + if(!Utility::waitSignal(mVesc->appConfig(), &ConfigParams::updated, 5000)){ ui->appSetupLabel->setStyleSheet("QLabel { background-color : red; color : black; }"); testResultMsg = "Failed to read app config during slave setup routine."; return false; @@ -891,7 +887,7 @@ bool BoardSetupWindow::tryApplyMasterAppSettings(){ mVesc->commands()->setSendCan(false); mVesc->commands()->setAppConf(); - if(!Utility::waitSignal(mVesc->commands(), SIGNAL(ackReceived(QString)), 2000)){ + if(!Utility::waitSignal(mVesc->commands(), &Commands::ackReceived, 2000)){ ui->appSetupLabel->setStyleSheet("QLabel { background-color : red; color : black; }"); testResultMsg = "Failed to write config during master app routine."; return false; @@ -974,7 +970,7 @@ void BoardSetupWindow::on_serialRefreshButton_clicked() if (mVesc) { ui->serialPortBox->clear(); auto ports = mVesc->listSerialPorts(); - foreach(auto &info, ports) { + for (auto &info : ports) { auto port = info.value(); ui->serialPortBox->addItem(port.name, port.systemPath); } @@ -1106,7 +1102,7 @@ void BoardSetupWindow::loadAppConfXML(QString path){ QString str; ui->appTab->addParamRow(mAppConfig_Target, "app_to_use"); - foreach(QObject *p, ui->appTab->children().at(0)->children()){ + for (auto *p : ui->appTab->children().at(0)->children()) { p->setProperty("enabled",false); } ui->appCheckBox->setCheckable(true); @@ -1158,7 +1154,7 @@ void BoardSetupWindow::loadMotorConfXML(QString path){ ui->motorTab->addParamRow(mMcConfig_Target, "l_battery_cut_end"); ui->motorConfigEdit->setText(path); - foreach(QObject *p, ui->motorTab->children().at(0)->children()){ + for (auto *p : ui->motorTab->children().at(0)->children()) { p->setProperty("enabled",false); } ui->motorDetectionCheckBox->setCheckable(true); diff --git a/codeloader.cpp b/codeloader.cpp index fd820aff1..830f22a85 100644 --- a/codeloader.cpp +++ b/codeloader.cpp @@ -84,7 +84,7 @@ bool CodeLoader::lispErase(int size) loop.quit(); }); - connect(&timeoutTimer, SIGNAL(timeout()), &loop, SLOT(quit())); + connect(&timeoutTimer, &QTimer::timeout, &loop, &QEventLoop::quit); loop.exec(); disconnect(conn); @@ -115,7 +115,7 @@ QString CodeLoader::reduceLispFile(QString fileData) QString res; auto lines = fileData.split("\n"); - foreach (auto line, lines) { + for (auto line : lines) { bool insideString = false; int indComment = -1; @@ -202,7 +202,7 @@ QByteArray CodeLoader::lispPackImports(QString codeStr, QString editorPath, bool auto lines = codeStr.split("\n"); int line_num = 0; - foreach (auto line, lines) { + for (const auto &line : lines) { line_num++; QString path; @@ -263,7 +263,7 @@ QByteArray CodeLoader::lispPackImports(QString codeStr, QString editorPath, bool files.append(qMakePair(tag, importData)); } else { bool found = false; - foreach (auto i, imports.second) { + for (const auto &i : imports.second) { if (i.first == pkgImportName) { auto importData = i.second; importData.append('\0'); // Pad with 0 in case it is a text file @@ -406,7 +406,7 @@ bool CodeLoader::lispUpload(VByteArray vb) loop.quit(); }); - connect(&timeoutTimer, SIGNAL(timeout()), &loop, SLOT(quit())); + connect(&timeoutTimer, &QTimer::timeout, &loop, &QEventLoop::quit); loop.exec(); disconnect(conn); @@ -507,7 +507,7 @@ bool CodeLoader::lispStream(VByteArray vb, qint8 mode) loop.quit(); }); - connect(&timeoutTimer, SIGNAL(timeout()), &loop, SLOT(quit())); + connect(&timeoutTimer, &QTimer::timeout, &loop, &QEventLoop::quit); loop.exec(); disconnect(conn); @@ -558,7 +558,7 @@ QString CodeLoader::lispRead(QWidget *parent, QString &lispPath) for (int j = 0;j < tries;j++) { mVesc->commands()->lispReadCode(size, offset); - res = Utility::waitSignal(mVesc->commands(), SIGNAL(lispReadCodeRx(int,int,QByteArray)), timeout); + res = Utility::waitSignal(mVesc->commands(), &Commands::lispReadCodeRx, timeout); if (res) { break; } @@ -596,7 +596,7 @@ QString CodeLoader::lispRead(QWidget *parent, QString &lispPath) QMessageBox::Yes | QMessageBox::No); QMap importPaths; - foreach (auto line, res.split('\n')) { + for (const auto &line : res.split('\n')) { QString path; QString tag; bool isInvalid; @@ -620,7 +620,7 @@ QString CodeLoader::lispRead(QWidget *parent, QString &lispPath) } } - foreach (auto i, unpacked.second) { + for (const auto &i : unpacked.second) { QString fileName = dirName + "/" + i.first + ".bin"; if (importPaths.contains(i.first)) { @@ -708,7 +708,7 @@ bool CodeLoader::qmlErase(int size) loop.quit(); }); - connect(&timeoutTimer, SIGNAL(timeout()), &loop, SLOT(quit())); + connect(&timeoutTimer, &QTimer::timeout, &loop, &QEventLoop::quit); loop.exec(); disconnect(conn); @@ -757,7 +757,7 @@ bool CodeLoader::qmlUpload(QByteArray script, bool isFullscreen) loop.quit(); }); - connect(&timeoutTimer, SIGNAL(timeout()), &loop, SLOT(quit())); + connect(&timeoutTimer, &QTimer::timeout, &loop, &QEventLoop::quit); loop.exec(); disconnect(conn); @@ -1110,7 +1110,7 @@ bool CodeLoader::downloadPackageArchive() }); QEventLoop loop; - connect(reply, SIGNAL(finished()), &loop, SLOT(quit())); + connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit); loop.exec(); if (reply->error() == QNetworkReply::NoError) { diff --git a/codeloader.h b/codeloader.h index 918c9c8e2..9a4e8b8b5 100644 --- a/codeloader.h +++ b/codeloader.h @@ -22,13 +22,14 @@ #include #include -#include "qqmlengine.h" +#include #include "vescinterface.h" #include "datatypes.h" class CodeLoader : public QObject { Q_OBJECT + QML_ELEMENT public: explicit CodeLoader(QObject *parent = nullptr); diff --git a/commands.cpp b/commands.cpp index cb2f32916..1ec436dca 100755 --- a/commands.cpp +++ b/commands.cpp @@ -57,7 +57,7 @@ Commands::Commands(QObject *parent) : QObject(parent) mFilePercentage = 0.0; mFileSpeed = 0.0; - connect(mTimer, SIGNAL(timeout()), this, SLOT(timerSlot())); + connect(mTimer, &QTimer::timeout, this, &Commands::timerSlot); } void Commands::setLimitedMode(bool is_limited) @@ -1619,7 +1619,7 @@ void Commands::sendCustomHwData(QByteArray data) emitData(vb); } -void Commands::setChukData(chuck_data &data) +void Commands::setChukData(const chuck_data &data) { VByteArray vb; vb.vbAppendInt8(COMM_SET_CHUCK_DATA); @@ -2438,7 +2438,7 @@ QVariantList Commands::fileBlockList(QString path) loop.quit(); }); - connect(&timeoutTimer, SIGNAL(timeout()), &loop, SLOT(quit())); + connect(&timeoutTimer, &QTimer::timeout, &loop, &QEventLoop::quit); loop.exec(); disconnect(conn); @@ -2482,7 +2482,7 @@ QVariantList Commands::fileBlockList(QString path) }); QVariantList retVal; - foreach (auto f, files) { + for (const auto &f : files) { retVal.append(QVariant::fromValue(f)); } @@ -2512,7 +2512,7 @@ QByteArray Commands::fileBlockRead(QString path) loop.quit(); }); - connect(&timeoutTimer, SIGNAL(timeout()), &loop, SLOT(quit())); + connect(&timeoutTimer, &QTimer::timeout, &loop, &QEventLoop::quit); loop.exec(); disconnect(conn); @@ -2576,7 +2576,7 @@ bool Commands::fileBlockWrite(QString path, QByteArray data) loop.quit(); }); - connect(&timeoutTimer, SIGNAL(timeout()), &loop, SLOT(quit())); + connect(&timeoutTimer, &QTimer::timeout, &loop, &QEventLoop::quit); loop.exec(); disconnect(conn); @@ -2642,7 +2642,7 @@ bool Commands::fileBlockMkdir(QString path) loop.quit(); }); - connect(&timeoutTimer, SIGNAL(timeout()), &loop, SLOT(quit())); + connect(&timeoutTimer, &QTimer::timeout, &loop, &QEventLoop::quit); loop.exec(); disconnect(conn); @@ -2681,7 +2681,7 @@ bool Commands::fileBlockRemove(QString path) loop.quit(); }); - connect(&timeoutTimer, SIGNAL(timeout()), &loop, SLOT(quit())); + connect(&timeoutTimer, &QTimer::timeout, &loop, &QEventLoop::quit); loop.exec(); disconnect(conn); @@ -2801,7 +2801,7 @@ QByteArray Commands::bmReadMemWait(uint32_t addr, quint16 size, int timeoutMs) loop.quit(); }); - connect(&timeoutTimer, SIGNAL(timeout()), &loop, SLOT(quit())); + connect(&timeoutTimer, &QTimer::timeout, &loop, &QEventLoop::quit); loop.exec(); disconnect(conn); @@ -2823,7 +2823,7 @@ int Commands::bmWriteMemWait(uint32_t addr, QByteArray data, int timeoutMs) loop.quit(); }); - connect(&timeoutTimer, SIGNAL(timeout()), &loop, SLOT(quit())); + connect(&timeoutTimer, &QTimer::timeout, &loop, &QEventLoop::quit); loop.exec(); disconnect(conn); @@ -2833,15 +2833,15 @@ int Commands::bmWriteMemWait(uint32_t addr, QByteArray data, int timeoutMs) void Commands::setAppConfig(ConfigParams *appConfig) { mAppConfig = appConfig; - connect(mAppConfig, SIGNAL(updateRequested()), this, SLOT(getAppConf())); - connect(mAppConfig, SIGNAL(updateRequestDefault()), this, SLOT(getAppConfDefault())); + connect(mAppConfig, &ConfigParams::updateRequested, this, &Commands::getAppConf); + connect(mAppConfig, &ConfigParams::updateRequestDefault, this, &Commands::getAppConfDefault); } void Commands::setMcConfig(ConfigParams *mcConfig) { mMcConfig = mcConfig; - connect(mMcConfig, SIGNAL(updateRequested()), this, SLOT(getMcconf())); - connect(mMcConfig, SIGNAL(updateRequestDefault()), this, SLOT(getMcconfDefault())); + connect(mMcConfig, &ConfigParams::updateRequested, this, &Commands::getMcconf); + connect(mMcConfig, &ConfigParams::updateRequestDefault, this, &Commands::getMcconfDefault); } void Commands::checkMcConfig() diff --git a/commands.h b/commands.h index ff21cb23a..47fd0f94c 100644 --- a/commands.h +++ b/commands.h @@ -25,12 +25,14 @@ #include #include #include +#include #include "datatypes.h" #include "configparams.h" class Commands : public QObject { Q_OBJECT + QML_ELEMENT public: explicit Commands(QObject *parent = nullptr); @@ -94,7 +96,7 @@ class Commands : public QObject signals: void sampleDataQmlStarted(int sample_len); - void dataToSend(QByteArray &data); + void dataToSend(QByteArray data); void fwVersionReceived(FW_RX_PARAMS params); void eraseNewAppResReceived(bool ok); @@ -216,7 +218,7 @@ public slots: void sendCustomAppData(QByteArray data); void sendCustomAppData(unsigned char *data, unsigned int len); void sendCustomHwData(QByteArray data); - void setChukData(chuck_data &data); + void setChukData(const chuck_data &data); void pairNrf(int ms); void gpdSetFsw(float fsw); void getGpdBufferSizeLeft(); diff --git a/configparams.h b/configparams.h index 5427411dc..2a646a7c5 100644 --- a/configparams.h +++ b/configparams.h @@ -25,12 +25,14 @@ #include #include #include +#include #include "configparam.h" #include "vbytearray.h" class ConfigParams : public QObject { Q_OBJECT + QML_ELEMENT public: explicit ConfigParams(QObject *parent = nullptr); Q_INVOKABLE void addParam(const QString &name, ConfigParam param); @@ -88,8 +90,8 @@ class ConfigParams : public QObject void setSerializeOrder(const QStringList &serializeOrder); void clearSerializeOrder(); - Q_INVOKABLE void serialize(VByteArray &vb); - Q_INVOKABLE bool deSerialize(VByteArray &vb); + void serialize(VByteArray &vb); + bool deSerialize(VByteArray &vb); void getXML(QXmlStreamWriter &stream, QString configName); bool setXML(QXmlStreamReader &stream, QString configName); diff --git a/convert_signal_slot2.py b/convert_signal_slot2.py new file mode 100644 index 000000000..1453b54ec --- /dev/null +++ b/convert_signal_slot2.py @@ -0,0 +1,418 @@ +#!/usr/bin/env python3 +""" +Phase 2: Convert remaining multi-line SIGNAL/SLOT connections. +Character-based parser with comprehensive class mapping. +""" + +import os + +def guess_this_class(filepath, context=''): + """Guess class for 'this' based on filepath and surrounding code context.""" + basename = os.path.basename(filepath).replace('.cpp', '') + + class_map = { + 'vescinterface': 'VescInterface', 'mainwindow': 'MainWindow', + 'boardsetupwindow': 'BoardSetupWindow', 'commands': 'Commands', + 'codeloader': 'CodeLoader', 'utility': 'Utility', + 'tcpserversimple': 'TcpServerSimple', 'udpserversimple': 'UdpServerSimple', + 'tcphub': 'TcpHub', 'packet': 'Packet', 'preferences': 'Preferences', + 'parametereditor': 'ParameterEditor', 'bleuart': 'BleUart', + 'mrichtextedit': 'MRichTextEdit', 'mapwidget': 'MapWidget', + 'osmclient': 'OsmClient', 'pagefirmware': 'PageFirmware', + 'pageconnection': 'PageConnection', 'pageswdprog': 'PageSwdProg', + 'pagesampleddata': 'PageSampledData', 'pagedisplaytool': 'PageDisplayTool', + 'pageterminal': 'PageTerminal', 'pageexperiments': 'PageExperiments', + 'pagewelcome': 'PageWelcome', 'pageimu': 'PageImu', + 'pageappimu': 'PageAppImu', 'pagertdata': 'PageRtData', + 'pagebms': 'PageBms', 'pageespprog': 'PageEspProg', + 'pagecananalyzer': 'PageCanAnalyzer', 'pagecustomconfig': 'PageCustomConfig', + 'pageappnunchuk': 'PageAppNunchuk', 'pageappadc': 'PageAppAdc', + 'pageappppm': 'PageAppPpm', 'pagemotorinfo': 'PageMotorInfo', + 'pagemotorcomparison': 'PageMotorComparison', 'experimentplot': 'ExperimentPlot', + 'detectfoc': 'DetectFoc', 'detectfocencoder': 'DetectFocEncoder', + 'detectfochall': 'DetectFocHall', 'detectbldc': 'DetectBldc', + 'detectallfocdialog': 'DetectAllFocDialog', 'nrfpair': 'NrfPair', + 'ppmmap': 'PpmMap', 'adcmap': 'AdcMap', + 'parameditdouble': 'ParamEditDouble', 'parameditint': 'ParamEditInt', + 'parameditenum': 'ParamEditEnum', 'parameditbool': 'ParamEditBool', + 'parameditstring': 'ParamEditString', 'parameditbitfield': 'ParamEditBitfield', + 'startupwizard': 'StartupWizard', + } + + cls = class_map.get(basename) + if cls is not None: + return cls + + # For setupwizardapp.cpp / setupwizardmotor.cpp: multiple inner classes + # Use context to determine which class + return None + +def guess_class(obj, method_name, method_params, filepath, context=''): + """Guess class from object expression, method, and filepath.""" + obj = obj.strip() + + # this + if obj == 'this': + cls = guess_this_class(filepath, context) + if cls is None: + # Fallback for wizard files: check signal/slot names + if method_name == 'currentIdChanged': + return 'QWizard' + if method_name in ('rejected', 'accepted'): + return 'QDialog' + if method_name in ('timerSlot', 'ended', 'nrfPairStartRes'): + # These are slots on setupwizard inner classes - need the class + return None + return cls + + # &loop + if obj == '&loop': + return 'QEventLoop' + + # Timers + if 'Timer' in obj or 'mTimer' in obj: + return 'QTimer' + + # Serial/network + if 'mSerialPort' in obj or 'mVictronPort' in obj: + return 'QSerialPort' + if 'mTcpSocket' in obj: + return 'QTcpSocket' + if 'mUdpSocket' in obj: + return 'QUdpSocket' + if 'mTcpServer' in obj or 'mTcpHubServer' in obj: + return 'QTcpServer' + + # BLE + if 'mBleUart' in obj or 'bleDevice()' in obj: + return 'BleUart' + if 'mService' in obj: + return 'QLowEnergyService' + + # VESC types + if 'mPacket' in obj: + return 'Packet' + if 'mCommands' in obj or 'commands()' in obj: + return 'Commands' + if any(x in obj for x in ['mMcConfig', 'mcConfig()', 'mAppConfig', 'appConfig()', 'pMc', 'pApp', 'pCustom']): + return 'ConfigParams' + if 'mConfig' in obj: + return 'ConfigParams' + if obj == 'mVesc' or (obj.startswith('mVesc') and '->' not in obj): + return 'VescInterface' + if obj == 'vesc' or (obj.startswith('vesc') and '->' not in obj): + return 'VescInterface' + + # CAN + if 'mCanDevice' in obj: + return 'QCanBusDevice' + + # Network + if 'reply' in obj.lower() and method_name == 'finished': + return 'QNetworkReply' + if 'mWebCtrl' in obj: + return 'QNetworkAccessManager' + if 'mOsm' in obj: + return 'OsmClient' + + # Clipboard + if 'clipboard()' in obj: + return 'QClipboard' + + # Scrollbar + if 'ScrollBar()' in obj: + return 'QScrollBar' + + # Document + if 'document()' in obj: + return 'QTextDocument' + + # Process + if 'process' in obj.lower() and method_name == 'finished': + return 'QProcess' + + # Text edit + if 'f_textedit' in obj and '->' not in obj: + return 'QTextEdit' + + # Lists + if obj in ('mCanFwdList', 'mInputList'): + return 'QListWidget' + if obj == 'mSensorMode': + return 'QComboBox' + if obj == 'mWriteButton': + return 'QPushButton' + + # Boxes + if 'mPercentageBox' in obj: + return 'QSlider' + if 'Box' in obj: + if method_params == 'double': + return 'QDoubleSpinBox' + elif method_params == 'int': + return 'QSpinBox' + + # f_* (mrichtextedit toolbar buttons) + if obj.startswith('f_'): + if method_name in ('clicked', 'toggled'): + return 'QToolButton' + if method_name == 'triggered': + return 'QAction' + if method_name == 'activated': + return 'QComboBox' + if method_name == 'setEnabled': + return 'QWidget' + if obj in ('removeFormat', 'removeAllFormat', 'textsource'): + return 'QAction' + + # Page objects + if 'mPageMotorSettings' in obj: + return 'PageMotorSettings' + if 'mPageWelcome' in obj: + return 'PageWelcome' + + # qApp + if obj == 'qApp': + return 'QApplication' + + # ui-> widgets + if obj.startswith('ui->'): + if method_name in ('clicked', 'toggled'): + return 'QAbstractButton' + if method_name == 'valueChanged': + return 'QDoubleSpinBox' if method_params == 'double' else 'QSpinBox' + if method_name == 'currentIndexChanged': + return 'QComboBox' + if method_name == 'currentRowChanged': + return 'QListWidget' + if method_name == 'textChanged': + return 'QLineEdit' + if method_name == 'currentFontChanged': + return 'QFontComboBox' + if method_name == 'triggered': + return 'QAction' + + # mBrowser + if 'mBrowser' in obj: + if 'ScrollBar' in obj: + return 'QScrollBar' + return 'QTextBrowser' + + return None + +NEEDS_QOVERLOAD = { + ('QSpinBox', 'valueChanged'), ('QDoubleSpinBox', 'valueChanged'), + ('QComboBox', 'activated'), ('QComboBox', 'currentIndexChanged'), + ('QProcess', 'finished'), + ('QAbstractButton', 'clicked'), ('QToolButton', 'clicked'), + ('QAction', 'triggered'), ('QPushButton', 'clicked'), +} + +def build_pmf(cls, method, params): + if (cls, method) in NEEDS_QOVERLOAD: + if params: + return f"qOverload<{params}>(&{cls}::{method})" + else: + return f"qOverload<>(&{cls}::{method})" + return f"&{cls}::{method}" + +def extract_macro(text, macro): + idx = text.find(macro + '(') + if idx == -1: + return None + start = idx + len(macro) + 1 + depth = 1 + i = start + while i < len(text) and depth > 0: + if text[i] == '(': + depth += 1 + elif text[i] == ')': + depth -= 1 + i += 1 + return text[start:i-1].strip() + +def split_top_level_commas(text): + parts = [] + depth = 0 + angle = 0 + current = '' + for ch in text: + if ch in '({': + depth += 1 + current += ch + elif ch in ')}': + depth -= 1 + current += ch + elif ch == '<': + angle += 1 + current += ch + elif ch == '>': + if angle > 0: + angle -= 1 + current += ch + elif ch == ',' and depth == 0 and angle == 0: + parts.append(current) + current = '' + else: + current += ch + if current: + parts.append(current) + return parts + +def parse_sig(content): + """Parse 'methodName(params)' -> (name, params)""" + idx = content.index('(') + return content[:idx], content[idx+1:-1].strip() + +def try_convert_call(func_name, inner, filepath): + """Try to convert connect/disconnect inner args to pointer-based.""" + + args = split_top_level_commas(inner) + if len(args) != 4: + return None + + sender = args[0].strip() + sig_content = extract_macro(args[1], 'SIGNAL') + if sig_content is None: + return None + + receiver = args[2].strip() + # Remove leading whitespace/newlines from receiver + receiver = receiver.lstrip() + + slot_content = extract_macro(args[3], 'SLOT') + if slot_content is None: + return None + + sig_name, sig_params = parse_sig(sig_content) + slot_name, slot_params = parse_sig(slot_content) + + sender_cls = guess_class(sender, sig_name, sig_params, filepath) + receiver_cls = guess_class(receiver, slot_name, slot_params, filepath) + + if sender_cls is None or receiver_cls is None: + return None + + sig_pmf = build_pmf(sender_cls, sig_name, sig_params) + slot_pmf = build_pmf(receiver_cls, slot_name, slot_params) + + # Detect indentation from original formatting + if '\n' in inner: + # Find whitespace before receiver in original + # The receiver was args[2] which may have leading whitespace/newlines + raw_receiver = args[2] + indent = '' + for ch in raw_receiver: + if ch in ' \t\n\r': + if ch == '\n': + indent = '' + else: + indent += ch + else: + break + new_inner = f"{sender}, {sig_pmf},\n{indent}{receiver}, {slot_pmf}" + else: + new_inner = f"{sender}, {sig_pmf}, {receiver}, {slot_pmf}" + + return f"{func_name}({new_inner})" + +def process_file(filepath): + with open(filepath, 'r') as f: + content = f.read() + + result = [] + i = 0 + changes = 0 + + while i < len(content): + matched_func = None + for func in ['disconnect', 'connect']: + flen = len(func) + if content[i:i+flen+1] == func + '(': + # Ensure not part of another identifier + if i > 0 and (content[i-1].isalnum() or content[i-1] == '_'): + continue + matched_func = func + break + + if matched_func is None: + result.append(content[i]) + i += 1 + continue + + func = matched_func + flen = len(func) + start = i + paren_start = i + flen # index of '(' + + # Find balanced closing paren + depth = 0 + j = paren_start + while j < len(content): + if content[j] == '(': + depth += 1 + elif content[j] == ')': + depth -= 1 + if depth == 0: + break + j += 1 + + if depth != 0: + result.append(content[i]) + i += 1 + continue + + inner = content[paren_start+1:j] + + # Skip if no SIGNAL macro or if this is a waitSignal context + if 'SIGNAL(' not in inner: + result.append(content[i]) + i += 1 + continue + + # Check context before for waitSignal + ctx_before = content[max(0, start-30):start] + if 'waitSignal' in ctx_before: + result.append(content[i]) + i += 1 + continue + + converted = try_convert_call(func, inner, filepath) + if converted is not None: + result.append(converted) + changes += 1 + i = j + 1 # skip past closing paren + else: + result.append(content[i]) + i += 1 + + if changes > 0: + new_content = ''.join(result) + with open(filepath, 'w') as f: + f.write(new_content) + print(f" {filepath}: {changes} conversions") + + return changes + +def main(): + root = '/home/robocup/vesc_tool' + skip_dirs = {'build', 'QCodeEditor', 'qmarkdowntextedit', 'application', '.git'} + + total = 0 + for dirpath, dirnames, filenames in os.walk(root): + dirnames[:] = [d for d in dirnames if d not in skip_dirs] + for fn in sorted(filenames): + if not fn.endswith('.cpp') or fn == 'qcustomplot.cpp': + continue + fpath = os.path.join(dirpath, fn) + with open(fpath, 'r') as f: + c = f.read() + if 'SIGNAL(' not in c: + continue + n = process_file(fpath) + total += n + + print(f"\nTotal: {total} additional conversions") + +if __name__ == '__main__': + main() diff --git a/esp32/esp32flash.h b/esp32/esp32flash.h index ff65e598f..917fca6d9 100644 --- a/esp32/esp32flash.h +++ b/esp32/esp32flash.h @@ -21,6 +21,7 @@ #define ESP32FLASH_H #include +#include #include "serial_io.h" #ifdef HAS_SERIALPORT @@ -31,6 +32,7 @@ class Esp32Flash : public QObject { Q_OBJECT + QML_ELEMENT public: explicit Esp32Flash(QObject *parent = nullptr); ~Esp32Flash(); diff --git a/main.cpp b/main.cpp index 2fd3ecde7..33beaf303 100755 --- a/main.cpp +++ b/main.cpp @@ -246,42 +246,12 @@ int main(int argc, char *argv[]) // TODO: http://www.qcustomplot.com/index.php/support/forum/1344 // Qt6: High DPI scaling is always enabled, removed AA_UseHighDpiPixmaps/AA_EnableHighDpiScaling -#ifdef HAS_BLUETOOTH - qmlRegisterType("Vedder.vesc.bleuart", 1, 0, "BleUart"); -#else - qmlRegisterType("Vedder.vesc.bleuart", 1, 0, "BleUart"); -#endif - qmlRegisterType("Vedder.vesc.commands", 1, 0, "Commands"); - qmlRegisterType("Vedder.vesc.configparams", 1, 0, "ConfigParams"); - qmlRegisterType("Vedder.vesc.fwhelper", 1, 0, "FwHelper"); - qmlRegisterType("Vedder.vesc.esp32flash", 1, 0, "Esp32Flash"); - qmlRegisterType("Vedder.vesc.tcpserversimple", 1, 0, "TcpServerSimple"); - qmlRegisterType("Vedder.vesc.udpserversimple", 1, 0, "UdpServerSimple"); - qmlRegisterType("Vedder.vesc.vesc3ditem", 1, 0, "Vesc3dItem"); - qmlRegisterType("Vedder.vesc.logwriter", 1, 0, "LogWriter"); - qmlRegisterType("Vedder.vesc.logreader", 1, 0, "LogReader"); - qmlRegisterType("Vedder.vesc.tcphub", 1, 0, "TcpHub"); - qmlRegisterType("Vedder.vesc.codeloader", 1, 0, "CodeLoader"); - qmlRegisterType("Vedder.vesc.qminimp3", 1, 0, "QMiniMp3"); -#ifdef Q_OS_LINUX - qmlRegisterType("Vedder.vesc.syscmd", 1, 0, "SysCmd"); -#endif + // Qt6: QML_ELEMENT / QML_NAMED_ELEMENT macros in headers + qt_add_qml_module + // in CMakeLists.txt replace all the legacy qmlRegisterType calls. + // Types are now auto-registered under the "Vedder.vesc" module. - qRegisterMetaType(); - qRegisterMetaType(); - qRegisterMetaType(); - qRegisterMetaType(); - qRegisterMetaType(); - qRegisterMetaType(); - qRegisterMetaType(); - qRegisterMetaType(); - qRegisterMetaType(); - qRegisterMetaType(); - qRegisterMetaType(); - qRegisterMetaType(); - qRegisterMetaType(); - qRegisterMetaType(); - qRegisterMetaType(); + // Qt6: Q_DECLARE_METATYPE auto-registers metatypes at compile time, + // so explicit qRegisterMetaType() calls are no longer needed. #ifdef USE_MOBILE #ifndef DEBUG_BUILD @@ -1153,7 +1123,7 @@ int main(int argc, char *argv[]) } else { ok = vesc->connectSerial(vescPort); if (ok) { - ok = Utility::waitSignal(vesc, SIGNAL(fwRxChanged(bool, bool)), 1000); + ok = Utility::waitSignal(vesc, &VescInterface::fwRxChanged, 1000); if (!ok) { qWarning() << "Could not read firmware version"; } @@ -1245,14 +1215,14 @@ int main(int argc, char *argv[]) if (isMcConf || isAppConf || isCustomConf || queryDeviceFwParams) { bool res = vesc->customConfigRxDone(); if (!res) { - res = Utility::waitSignal(vesc, SIGNAL(customConfigLoadDone()), 4000); + res = Utility::waitSignal(vesc, &VescInterface::customConfigLoadDone, 4000); } if (res) { if (isMcConf) { ConfigParams *p = vesc->mcConfig(); vesc->commands()->getMcconf(); - res = Utility::waitSignal(p, SIGNAL(updated()), 4000); + res = Utility::waitSignal(p, &ConfigParams::updated, 4000); if (res) { if (!setMcConfPath.isEmpty()) { @@ -1260,7 +1230,7 @@ int main(int argc, char *argv[]) if (res) { vesc->commands()->setMcconf(false); - res = Utility::waitSignal(vesc->commands(), SIGNAL(ackReceived(QString)), 4000); + res = Utility::waitSignal(vesc->commands(), &Commands::ackReceived, 4000); if (res) { qDebug() << "Wrote XML from" << setMcConfPath; @@ -1291,7 +1261,7 @@ int main(int argc, char *argv[]) if (isAppConf) { ConfigParams *p = vesc->appConfig(); vesc->commands()->getAppConf(); - res = Utility::waitSignal(p, SIGNAL(updated()), 4000); + res = Utility::waitSignal(p, &ConfigParams::updated, 4000); if (res) { if (!setAppConfPath.isEmpty()) { @@ -1299,7 +1269,7 @@ int main(int argc, char *argv[]) if (res) { vesc->commands()->setAppConf(); - res = Utility::waitSignal(vesc->commands(), SIGNAL(ackReceived(QString)), 4000); + res = Utility::waitSignal(vesc->commands(), &Commands::ackReceived, 4000); if (res) { qDebug() << "Wrote XML from" << setAppConfPath; @@ -1330,7 +1300,7 @@ int main(int argc, char *argv[]) if (isCustomConf) { ConfigParams *p = vesc->customConfig(0); vesc->commands()->customConfigGet(0, false); - res = Utility::waitSignal(p, SIGNAL(updated()), 4000); + res = Utility::waitSignal(p, &ConfigParams::updated, 4000); if (res) { if (!setCustomConfPath.isEmpty()) { @@ -1338,7 +1308,7 @@ int main(int argc, char *argv[]) if (res) { vesc->commands()->customConfigSet(0, p); - res = Utility::waitSignal(vesc->commands(), SIGNAL(ackReceived(QString)), 4000); + res = Utility::waitSignal(vesc->commands(), &Commands::ackReceived, 4000); if (res) { qDebug() << "Wrote XML from" << setCustomConfPath; @@ -1491,7 +1461,7 @@ int main(int argc, char *argv[]) qDebug() << "== Running isCompatible with testPkgDesc tests =="; } - foreach (auto str, pkgDescTests) { + for (const auto &str : pkgDescTests) { auto args = str.split(":"); // hwtype:hwname:optfwname if (args.size() >= 2) { @@ -1631,11 +1601,9 @@ int main(int argc, char *argv[]) qApp->setStyleSheet(""); } - // Register this to not stop on the import statement when reusing components - // from the mobile UI. In the mobile UI these are provided as singletons, whereas - // in the desktop GUI they are provided as context properties. - qmlRegisterType("Vedder.vesc.vescinterface", 1, 0, "VescIf2"); - qmlRegisterType("Vedder.vesc.utility", 1, 0, "Utility2"); + // Qt6: QML_ELEMENT on C++ classes + qt_add_qml_module handles type registration. + // The old dummy VescIf2/Utility2 registrations are no longer needed since all types + // are auto-registered under "Vedder.vesc". if (!loadQml.isEmpty() || loadQmlVesc) { vesc = new VescInterface; diff --git a/mainwindow.cpp b/mainwindow.cpp index f178f9b16..b60f7e815 100755 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -211,8 +211,6 @@ MainWindow::MainWindow(QWidget *parent) : ui->handbrakeButton->setIcon(Utility::getIcon("icons/Brake Warning-96.png")); ui->fullBrakeButton->setIcon(Utility::getIcon("icons/Anchor-96.png")); - qRegisterMetaType("QtMsgType"); - mVersion = QString::number(VT_VERSION, 'f', 2); mVesc = new VescInterface(this); mPreferences = new Preferences(this); @@ -226,26 +224,21 @@ MainWindow::MainWindow(QWidget *parent) : mKeyLeft = false; mKeyRight = false; - connect(mDebugTimer, SIGNAL(timeout()), - this, SLOT(timerSlotDebugMsg())); - connect(mTimer, SIGNAL(timeout()), - this, SLOT(timerSlot())); - connect(mVesc, SIGNAL(statusMessage(QString,bool)), - this, SLOT(showStatusInfo(QString,bool))); - connect(mVesc, SIGNAL(messageDialog(QString,QString,bool,bool)), - this, SLOT(showMessageDialog(QString,QString,bool,bool))); - connect(mVesc, SIGNAL(serialPortNotWritable(QString)), - this, SLOT(serialPortNotWritable(QString))); - connect(mVesc->commands(), SIGNAL(valuesReceived(MC_VALUES,unsigned int)), - this, SLOT(valuesReceived(MC_VALUES,unsigned int))); - connect(mVesc->commands(), SIGNAL(mcConfigCheckResult(QStringList)), - this, SLOT(mcConfigCheckResult(QStringList))); - connect(mVesc->mcConfig(), SIGNAL(paramChangedDouble(QObject*,QString,double)), - this, SLOT(paramChangedDouble(QObject*,QString,double))); - connect(ui->actionAboutQt, SIGNAL(triggered(bool)), - qApp, SLOT(aboutQt())); - connect(mVesc->commands(), SIGNAL(pingCanRx(QVector,bool)), - this, SLOT(pingCanRx(QVector,bool))); + connect(mDebugTimer, &QTimer::timeout, this, &MainWindow::timerSlotDebugMsg); + connect(mTimer, &QTimer::timeout, this, &MainWindow::timerSlot); + connect(mVesc, &VescInterface::statusMessage, this, &MainWindow::showStatusInfo); + connect(mVesc, &VescInterface::messageDialog, this, &MainWindow::showMessageDialog); + connect(mVesc, &VescInterface::serialPortNotWritable, this, &MainWindow::serialPortNotWritable); + connect(mVesc->commands(), &Commands::valuesReceived, + this, &MainWindow::valuesReceived); + connect(mVesc->commands(), &Commands::mcConfigCheckResult, + this, &MainWindow::mcConfigCheckResult); + connect(mVesc->mcConfig(), &ConfigParams::paramChangedDouble, + this, &MainWindow::paramChangedDouble); + connect(ui->actionAboutQt, qOverload(&QAction::triggered), + qApp, &QApplication::aboutQt); + connect(mVesc->commands(), &Commands::pingCanRx, + this, &MainWindow::pingCanRx); ui->dispDuty->setName("Duty"); ui->dispDuty->setRange(100.0); @@ -731,7 +724,7 @@ void MainWindow::dragEnterEvent(QDragEnterEvent *event) void MainWindow::dropEvent(QDropEvent *event) { - foreach (auto url, event->mimeData()->urls()) { + for (const auto &url : event->mimeData()->urls()) { auto path = url.path(); if (path.endsWith(".xml", Qt::CaseInsensitive)) { if (ConfigParams::testXml(path, "MCConfiguration")) { @@ -1429,14 +1422,14 @@ void MainWindow::reloadPages() ui->pageWidget->addWidget(mPageWelcome); QString theme = Utility::getThemePath(); addPageItem(tr("Welcome & Wizards"), theme + "icons/Home-96.png", "", true); - connect(ui->actionAutoSetupFOC, SIGNAL(triggered(bool)), - mPageWelcome, SLOT(startSetupWizardFocQml())); - connect(ui->actionMotorSetupWizard, SIGNAL(triggered(bool)), - mPageWelcome, SLOT(startSetupWizardMotor())); - connect(ui->actionAppSetupWizard, SIGNAL(triggered(bool)), - mPageWelcome, SLOT(startSetupWizardApp())); - connect(ui->actionSetupMotorsFOCQuick, SIGNAL(triggered(bool)), - mPageWelcome, SLOT(startSetupWizardFocSimple())); + connect(ui->actionAutoSetupFOC, qOverload(&QAction::triggered), + mPageWelcome, &PageWelcome::startSetupWizardFocQml); + connect(ui->actionMotorSetupWizard, qOverload(&QAction::triggered), + mPageWelcome, &PageWelcome::startSetupWizardMotor); + connect(ui->actionAppSetupWizard, qOverload(&QAction::triggered), + mPageWelcome, &PageWelcome::startSetupWizardApp); + connect(ui->actionSetupMotorsFOCQuick, qOverload(&QAction::triggered), + mPageWelcome, &PageWelcome::startSetupWizardFocSimple); mPageConnection = new PageConnection(this); mPageConnection->setVesc(mVesc); @@ -1458,8 +1451,8 @@ void MainWindow::reloadPages() ui->pageWidget->addWidget(mPageMotorSettings); addPageItem(tr("Motor Settings"), theme + "icons/motor.png", "", true); mPageNameIdList.insert("motor", ui->pageList->count() - 1); - connect(mPageMotorSettings, SIGNAL(startFocWizard()), - mPageWelcome, SLOT(startSetupWizardFocQml())); + connect(mPageMotorSettings, &PageMotorSettings::startFocWizard, + mPageWelcome, &PageWelcome::startSetupWizardFocQml); mPageMotor = new PageMotor(this); mPageMotor->setVesc(mVesc); @@ -1856,8 +1849,8 @@ bool MainWindow::waitProcess(QProcess &process, bool block, int timeoutMs) QTimer timeoutTimer; timeoutTimer.setSingleShot(true); timeoutTimer.start(timeoutMs); - connect(&process, SIGNAL(finished(int)), &loop, SLOT(quit())); - connect(&timeoutTimer, SIGNAL(timeout()), &loop, SLOT(quit())); + connect(&process, &QProcess::finished, &loop, &QEventLoop::quit); + connect(&timeoutTimer, &QTimer::timeout, &loop, &QEventLoop::quit); loop.exec(); if (process.state() == QProcess::Running) { diff --git a/map/mapwidget.cpp b/map/mapwidget.cpp index f57325adf..e0f18fb0d 100644 --- a/map/mapwidget.cpp +++ b/map/mapwidget.cpp @@ -209,9 +209,9 @@ MapWidget::MapWidget(QWidget *parent) : QWidget(parent) // mOsm->setTileServerUrl("http://tiles.vedder.se/osm_tiles"); //mOsm->setTileServerUrl("http://tiles.vedder.se/osm_tiles_hd"); - connect(mOsm, SIGNAL(tileReady(OsmTile)), this, SLOT(tileReady(OsmTile))); - connect(mOsm, SIGNAL(errorGetTile(QString)), this, SLOT(errorGetTile(QString))); - connect(mTimer, SIGNAL(timeout()), this, SLOT(timerSlot())); + connect(mOsm, &OsmClient::tileReady, this, &MapWidget::tileReady); + connect(mOsm, &OsmClient::errorGetTile, this, &MapWidget::errorGetTile); + connect(mTimer, &QTimer::timeout, this, &MapWidget::timerSlot); setMouseTracking(true); diff --git a/map/osmclient.cpp b/map/osmclient.cpp index caa039740..266a335e5 100644 --- a/map/osmclient.cpp +++ b/map/osmclient.cpp @@ -109,8 +109,7 @@ OsmClient::OsmClient(QObject *parent) : QObject(parent) mStatusPixmaps.append(pix); } - connect(&mWebCtrl, SIGNAL(finished(QNetworkReply*)), - this, SLOT(fileDownloaded(QNetworkReply*))); + connect(&mWebCtrl, &QNetworkAccessManager::finished, this, &OsmClient::fileDownloaded); } bool OsmClient::setCacheDir(QString path) diff --git a/minimp3/qminimp3.h b/minimp3/qminimp3.h index 444500b55..ab21d971e 100644 --- a/minimp3/qminimp3.h +++ b/minimp3/qminimp3.h @@ -3,6 +3,7 @@ #include #include +#include struct MiniMp3Dec { Q_GADGET @@ -24,6 +25,7 @@ Q_DECLARE_METATYPE(MiniMp3Dec) class QMiniMp3 : public QObject { Q_OBJECT + QML_ELEMENT public: explicit QMiniMp3(QObject *parent = nullptr); Q_INVOKABLE MiniMp3Dec decodeFileMono(QString path); diff --git a/mobile/AdcMap.qml b/mobile/AdcMap.qml index fc76373f8..b7d7a8803 100644 --- a/mobile/AdcMap.qml +++ b/mobile/AdcMap.qml @@ -21,9 +21,7 @@ import QtQuick import QtQuick.Controls import QtQuick.Layouts -import Vedder.vesc.vescinterface 1.0 -import Vedder.vesc.commands 1.0 -import Vedder.vesc.configparams 1.0 +import Vedder.vesc Item { implicitHeight: column.implicitHeight diff --git a/mobile/BMS.qml b/mobile/BMS.qml index 22f54aacf..36f2980d0 100644 --- a/mobile/BMS.qml +++ b/mobile/BMS.qml @@ -21,9 +21,7 @@ import QtQuick import QtQuick.Controls import QtQuick.Layouts -import Vedder.vesc.vescinterface 1.0 -import Vedder.vesc.commands 1.0 -import Vedder.vesc.utility 1.0 +import Vedder.vesc Item { id: bmsPageItem diff --git a/mobile/BleSetupDialog.qml b/mobile/BleSetupDialog.qml index 620f2753b..186afdd00 100644 --- a/mobile/BleSetupDialog.qml +++ b/mobile/BleSetupDialog.qml @@ -21,10 +21,7 @@ import QtQuick import QtQuick.Controls import QtQuick.Layouts -import Vedder.vesc.vescinterface 1.0 -import Vedder.vesc.commands 1.0 -import Vedder.vesc.configparams 1.0 -import Vedder.vesc.utility 1.0 +import Vedder.vesc Item { property var dialogParent: ApplicationWindow.overlay diff --git a/mobile/CanScreen.qml b/mobile/CanScreen.qml index 52d1d7291..b83169339 100644 --- a/mobile/CanScreen.qml +++ b/mobile/CanScreen.qml @@ -21,10 +21,7 @@ import QtQuick import QtQuick.Controls import QtQuick.Layouts -import Vedder.vesc.vescinterface 1.0 -import Vedder.vesc.bleuart 1.0 -import Vedder.vesc.commands 1.0 -import Vedder.vesc.utility 1.0 +import Vedder.vesc Item { id: rootItem diff --git a/mobile/ConfigPageApp.qml b/mobile/ConfigPageApp.qml index fa7df1c55..b7e5c8e98 100644 --- a/mobile/ConfigPageApp.qml +++ b/mobile/ConfigPageApp.qml @@ -22,10 +22,7 @@ import QtQuick.Controls import QtQuick.Layouts import QtQuick.Dialogs as Dl -import Vedder.vesc.vescinterface 1.0 -import Vedder.vesc.commands 1.0 -import Vedder.vesc.configparams 1.0 -import Vedder.vesc.utility 1.0 +import Vedder.vesc Item { id: appPageItem diff --git a/mobile/ConfigPageCustom.qml b/mobile/ConfigPageCustom.qml index 4532f067a..3bad15df4 100644 --- a/mobile/ConfigPageCustom.qml +++ b/mobile/ConfigPageCustom.qml @@ -22,10 +22,7 @@ import QtQuick.Controls import QtQuick.Layouts import QtQuick.Dialogs as Dl -import Vedder.vesc.vescinterface 1.0 -import Vedder.vesc.commands 1.0 -import Vedder.vesc.configparams 1.0 -import Vedder.vesc.utility 1.0 +import Vedder.vesc Item { id: appPageItem diff --git a/mobile/ConfigPageMotor.qml b/mobile/ConfigPageMotor.qml index 0641dc28e..b9225420f 100644 --- a/mobile/ConfigPageMotor.qml +++ b/mobile/ConfigPageMotor.qml @@ -22,10 +22,7 @@ import QtQuick.Controls import QtQuick.Layouts import QtQuick.Dialogs as Dl -import Vedder.vesc.vescinterface 1.0 -import Vedder.vesc.commands 1.0 -import Vedder.vesc.configparams 1.0 -import Vedder.vesc.utility 1.0 +import Vedder.vesc Item { id: confPageMotorItem diff --git a/mobile/ConnectScreen.qml b/mobile/ConnectScreen.qml index ffa29b225..03192f1b9 100644 --- a/mobile/ConnectScreen.qml +++ b/mobile/ConnectScreen.qml @@ -20,11 +20,7 @@ import QtQuick import QtQuick.Controls import QtQuick.Layouts -import Vedder.vesc.vescinterface 1.0 -import Vedder.vesc.bleuart 1.0 -import Vedder.vesc.commands 1.0 -import Vedder.vesc.utility 1.0 -import Vedder.vesc.udpserversimple 1.0 +import Vedder.vesc Item { id: rootItem diff --git a/mobile/Controls.qml b/mobile/Controls.qml index e3488acd1..5a11ef5ad 100644 --- a/mobile/Controls.qml +++ b/mobile/Controls.qml @@ -21,10 +21,7 @@ import QtQuick import QtQuick.Controls import QtQuick.Layouts -import Vedder.vesc.vescinterface 1.0 -import Vedder.vesc.commands 1.0 -import Vedder.vesc.configparams 1.0 -import Vedder.vesc.utility 1.0 +import Vedder.vesc Item { property int parentWidth: 10 diff --git a/mobile/CustomGauge.qml b/mobile/CustomGauge.qml index f33e76f3b..e23d682fb 100644 --- a/mobile/CustomGauge.qml +++ b/mobile/CustomGauge.qml @@ -21,7 +21,7 @@ import QtQuick import QtQuick.Layouts import Qt5Compat.GraphicalEffects import QtQuick.Controls.Material -import Vedder.vesc.utility 1.0 +import Vedder.vesc Item { property double value: 0 diff --git a/mobile/CustomGaugeV2.qml b/mobile/CustomGaugeV2.qml index fd6dff248..8f0ea8e96 100644 --- a/mobile/CustomGaugeV2.qml +++ b/mobile/CustomGaugeV2.qml @@ -23,7 +23,7 @@ import QtQuick.Layouts import Qt5Compat.GraphicalEffects import QtQuick.Controls.Material -import Vedder.vesc.utility 1.0 +import Vedder.vesc // CustomGaugeV2: Qt6 version - delegates to CustomGauge (Canvas-based) // The original used CircularGauge/CircularGaugeStyle from QtQuick.Extras diff --git a/mobile/DetectBldc.qml b/mobile/DetectBldc.qml index d142ad8d2..270cbb57e 100644 --- a/mobile/DetectBldc.qml +++ b/mobile/DetectBldc.qml @@ -21,10 +21,7 @@ import QtQuick import QtQuick.Controls import QtQuick.Layouts -import Vedder.vesc.vescinterface 1.0 -import Vedder.vesc.commands 1.0 -import Vedder.vesc.configparams 1.0 -import Vedder.vesc.utility 1.0 +import Vedder.vesc Item { property real intLim: 0.0 diff --git a/mobile/DetectFocEncoder.qml b/mobile/DetectFocEncoder.qml index d3330e5b9..46c403ffb 100644 --- a/mobile/DetectFocEncoder.qml +++ b/mobile/DetectFocEncoder.qml @@ -21,10 +21,7 @@ import QtQuick import QtQuick.Controls import QtQuick.Layouts -import Vedder.vesc.vescinterface 1.0 -import Vedder.vesc.commands 1.0 -import Vedder.vesc.configparams 1.0 -import Vedder.vesc.utility 1.0 +import Vedder.vesc Item { property real mOffset: 0.0 diff --git a/mobile/DetectFocHall.qml b/mobile/DetectFocHall.qml index ecb737a78..1f34e1ceb 100644 --- a/mobile/DetectFocHall.qml +++ b/mobile/DetectFocHall.qml @@ -21,10 +21,7 @@ import QtQuick import QtQuick.Controls import QtQuick.Layouts -import Vedder.vesc.vescinterface 1.0 -import Vedder.vesc.commands 1.0 -import Vedder.vesc.configparams 1.0 -import Vedder.vesc.utility 1.0 +import Vedder.vesc Item { property var table: [] diff --git a/mobile/DetectFocParam.qml b/mobile/DetectFocParam.qml index 1927f9cbb..84be27873 100644 --- a/mobile/DetectFocParam.qml +++ b/mobile/DetectFocParam.qml @@ -21,10 +21,7 @@ import QtQuick import QtQuick.Controls import QtQuick.Layouts -import Vedder.vesc.vescinterface 1.0 -import Vedder.vesc.commands 1.0 -import Vedder.vesc.configparams 1.0 -import Vedder.vesc.utility 1.0 +import Vedder.vesc Item { property real res: 0.0 diff --git a/mobile/DirectionSetup.qml b/mobile/DirectionSetup.qml index 15dd62827..cef6b1b5d 100644 --- a/mobile/DirectionSetup.qml +++ b/mobile/DirectionSetup.qml @@ -21,10 +21,7 @@ import QtQuick import QtQuick.Controls import QtQuick.Layouts -import Vedder.vesc.vescinterface 1.0 -import Vedder.vesc.commands 1.0 -import Vedder.vesc.configparams 1.0 -import Vedder.vesc.utility 1.0 +import Vedder.vesc Item { property var dialogParent: ApplicationWindow.overlay diff --git a/mobile/DirectoryPicker.qml b/mobile/DirectoryPicker.qml index be8280372..89219b077 100644 --- a/mobile/DirectoryPicker.qml +++ b/mobile/DirectoryPicker.qml @@ -30,7 +30,7 @@ import QtQuick.Layouts import QtQuick.Window import Qt.labs.platform -import Vedder.vesc.utility 1.0 +import Vedder.vesc Item { id:picker signal dirSelected(string fileName) diff --git a/mobile/FilePicker.qml b/mobile/FilePicker.qml index 9e1981fa1..1e6d42ad5 100644 --- a/mobile/FilePicker.qml +++ b/mobile/FilePicker.qml @@ -29,7 +29,7 @@ import Qt.labs.folderlistmodel import QtQuick.Layouts import QtQuick.Window import Qt.labs.platform -import Vedder.vesc.utility 1.0 +import Vedder.vesc Item { id:picker diff --git a/mobile/FwUpdate.qml b/mobile/FwUpdate.qml index 8547efe61..f7e11c4a4 100755 --- a/mobile/FwUpdate.qml +++ b/mobile/FwUpdate.qml @@ -22,11 +22,7 @@ import QtQuick.Controls import QtQuick.Layouts import QtQuick.Dialogs as Dl -import Vedder.vesc.vescinterface 1.0 -import Vedder.vesc.commands 1.0 -import Vedder.vesc.configparams 1.0 -import Vedder.vesc.fwhelper 1.0 -import Vedder.vesc.utility 1.0 +import Vedder.vesc Item { property alias currentPage: swipeView.currentIndex diff --git a/mobile/ImageButton.qml b/mobile/ImageButton.qml index 207f61c69..c2f429e4b 100644 --- a/mobile/ImageButton.qml +++ b/mobile/ImageButton.qml @@ -20,7 +20,7 @@ import QtQuick import QtQuick.Controls import QtQuick.Layouts -import Vedder.vesc.utility 1.0 +import Vedder.vesc Item { id: rootItem diff --git a/mobile/Lisp.qml b/mobile/Lisp.qml index d5d50fadf..d4f6abbe1 100644 --- a/mobile/Lisp.qml +++ b/mobile/Lisp.qml @@ -5,10 +5,7 @@ import QtQuick.Dialogs as Dl import Qt.labs.folderlistmodel import QtCore as QSettings -import Vedder.vesc.vescinterface 1.0 -import Vedder.vesc.commands 1.0 -import Vedder.vesc.utility 1.0 -import Vedder.vesc.codeloader 1.0 +import Vedder.vesc Item { id: lispPageItem diff --git a/mobile/LogBox.qml b/mobile/LogBox.qml index af1cd54d9..21ed5d948 100644 --- a/mobile/LogBox.qml +++ b/mobile/LogBox.qml @@ -23,8 +23,7 @@ import QtQuick.Layouts import QtCore as QSettings import Qt.labs.platform -import Vedder.vesc.vescinterface 1.0 -import Vedder.vesc.utility 1.0 +import Vedder.vesc Item { implicitHeight: grid.implicitHeight diff --git a/mobile/MultiSettings.qml b/mobile/MultiSettings.qml index ca98a206a..52cf5717f 100755 --- a/mobile/MultiSettings.qml +++ b/mobile/MultiSettings.qml @@ -21,10 +21,7 @@ import QtQuick import QtQuick.Controls import QtQuick.Layouts -import Vedder.vesc.vescinterface 1.0 -import Vedder.vesc.commands 1.0 -import Vedder.vesc.configparams 1.0 -import Vedder.vesc.utility 1.0 +import Vedder.vesc Item { property var dialogParent: ApplicationWindow.overlay diff --git a/mobile/NrfPair.qml b/mobile/NrfPair.qml index 817fa8f36..9b450beb6 100644 --- a/mobile/NrfPair.qml +++ b/mobile/NrfPair.qml @@ -21,9 +21,7 @@ import QtQuick import QtQuick.Controls import QtQuick.Layouts -import Vedder.vesc.vescinterface 1.0 -import Vedder.vesc.commands 1.0 -import Vedder.vesc.configparams 1.0 +import Vedder.vesc Item { implicitHeight: column.implicitHeight diff --git a/mobile/Packages.qml b/mobile/Packages.qml index 82fdcc158..358715a4d 100644 --- a/mobile/Packages.qml +++ b/mobile/Packages.qml @@ -22,11 +22,7 @@ import QtQuick.Controls import QtQuick.Layouts import QtQuick.Dialogs as Dl -import Vedder.vesc.vescinterface 1.0 -import Vedder.vesc.commands 1.0 -import Vedder.vesc.configparams 1.0 -import Vedder.vesc.utility 1.0 -import Vedder.vesc.codeloader 1.0 +import Vedder.vesc Item { id: appPageItem diff --git a/mobile/PairingDialog.qml b/mobile/PairingDialog.qml index 800aabf8f..109ce8598 100644 --- a/mobile/PairingDialog.qml +++ b/mobile/PairingDialog.qml @@ -21,10 +21,7 @@ import QtQuick import QtQuick.Controls import QtQuick.Layouts -import Vedder.vesc.vescinterface 1.0 -import Vedder.vesc.commands 1.0 -import Vedder.vesc.configparams 1.0 -import Vedder.vesc.utility 1.0 +import Vedder.vesc Item { property var dialogParent: ApplicationWindow.overlay diff --git a/mobile/ParamEditBitfield.qml b/mobile/ParamEditBitfield.qml index 45ed5d719..09c36be56 100644 --- a/mobile/ParamEditBitfield.qml +++ b/mobile/ParamEditBitfield.qml @@ -21,9 +21,7 @@ import QtQuick import QtQuick.Controls import QtQuick.Layouts -import Vedder.vesc.vescinterface 1.0 -import Vedder.vesc.configparams 1.0 -import Vedder.vesc.utility 1.0 +import Vedder.vesc Item { id: editor diff --git a/mobile/ParamEditBool.qml b/mobile/ParamEditBool.qml index 958750eea..108040760 100644 --- a/mobile/ParamEditBool.qml +++ b/mobile/ParamEditBool.qml @@ -21,9 +21,7 @@ import QtQuick import QtQuick.Controls import QtQuick.Layouts -import Vedder.vesc.vescinterface 1.0 -import Vedder.vesc.configparams 1.0 -import Vedder.vesc.utility 1.0 +import Vedder.vesc Item { id: editor diff --git a/mobile/ParamEditDouble.qml b/mobile/ParamEditDouble.qml index 20e97a0ed..7a5a7f6dc 100644 --- a/mobile/ParamEditDouble.qml +++ b/mobile/ParamEditDouble.qml @@ -21,9 +21,7 @@ import QtQuick import QtQuick.Controls import QtQuick.Layouts -import Vedder.vesc.vescinterface 1.0 -import Vedder.vesc.configparams 1.0 -import Vedder.vesc.utility 1.0 +import Vedder.vesc Item { id: editor diff --git a/mobile/ParamEditEnum.qml b/mobile/ParamEditEnum.qml index 9099d2d61..95c0281e8 100644 --- a/mobile/ParamEditEnum.qml +++ b/mobile/ParamEditEnum.qml @@ -21,9 +21,7 @@ import QtQuick import QtQuick.Controls import QtQuick.Layouts -import Vedder.vesc.vescinterface 1.0 -import Vedder.vesc.configparams 1.0 -import Vedder.vesc.utility 1.0 +import Vedder.vesc Item { id: editor diff --git a/mobile/ParamEditInt.qml b/mobile/ParamEditInt.qml index 081399fc5..3850fd7c6 100644 --- a/mobile/ParamEditInt.qml +++ b/mobile/ParamEditInt.qml @@ -21,9 +21,7 @@ import QtQuick import QtQuick.Controls import QtQuick.Layouts -import Vedder.vesc.vescinterface 1.0 -import Vedder.vesc.configparams 1.0 -import Vedder.vesc.utility 1.0 +import Vedder.vesc Item { id: editor diff --git a/mobile/ParamEditSeparator.qml b/mobile/ParamEditSeparator.qml index 730a3cf2f..831435cb8 100644 --- a/mobile/ParamEditSeparator.qml +++ b/mobile/ParamEditSeparator.qml @@ -20,7 +20,7 @@ import QtQuick import QtQuick.Controls import QtQuick.Layouts -import Vedder.vesc.utility 1.0 +import Vedder.vesc Item { Layout.fillWidth: true diff --git a/mobile/ParamEditString.qml b/mobile/ParamEditString.qml index ad384c9b7..30f90321d 100644 --- a/mobile/ParamEditString.qml +++ b/mobile/ParamEditString.qml @@ -21,9 +21,7 @@ import QtQuick import QtQuick.Controls import QtQuick.Layouts -import Vedder.vesc.vescinterface 1.0 -import Vedder.vesc.configparams 1.0 -import Vedder.vesc.utility 1.0 +import Vedder.vesc Item { id: editor diff --git a/mobile/ParamEditors.qml b/mobile/ParamEditors.qml index 3438f1f90..a732836df 100644 --- a/mobile/ParamEditors.qml +++ b/mobile/ParamEditors.qml @@ -21,9 +21,7 @@ import QtQuick import QtQuick.Controls import QtQuick.Layouts -import Vedder.vesc.vescinterface 1.0 -import Vedder.vesc.commands 1.0 -import Vedder.vesc.configparams 1.0 +import Vedder.vesc Item { property ConfigParams mMcConf: VescIf.mcConfig() property ConfigParams mAppConf: VescIf.appConfig() diff --git a/mobile/PpmMap.qml b/mobile/PpmMap.qml index 05e390e2e..e13bb8118 100644 --- a/mobile/PpmMap.qml +++ b/mobile/PpmMap.qml @@ -21,9 +21,7 @@ import QtQuick import QtQuick.Controls import QtQuick.Layouts -import Vedder.vesc.vescinterface 1.0 -import Vedder.vesc.commands 1.0 -import Vedder.vesc.configparams 1.0 +import Vedder.vesc Item { implicitHeight: column.implicitHeight diff --git a/mobile/ProfileDisplay.qml b/mobile/ProfileDisplay.qml index 346adffc1..bc4929de4 100644 --- a/mobile/ProfileDisplay.qml +++ b/mobile/ProfileDisplay.qml @@ -21,10 +21,7 @@ import QtQuick import QtQuick.Controls import QtQuick.Layouts -import Vedder.vesc.vescinterface 1.0 -import Vedder.vesc.commands 1.0 -import Vedder.vesc.configparams 1.0 -import Vedder.vesc.utility 1.0 +import Vedder.vesc Item { property var dialogParent: ApplicationWindow.overlay diff --git a/mobile/ProfileEditor.qml b/mobile/ProfileEditor.qml index 5913d5047..67f631af6 100644 --- a/mobile/ProfileEditor.qml +++ b/mobile/ProfileEditor.qml @@ -21,9 +21,7 @@ import QtQuick import QtQuick.Controls import QtQuick.Layouts -import Vedder.vesc.vescinterface 1.0 -import Vedder.vesc.configparams 1.0 -import Vedder.vesc.utility 1.0 +import Vedder.vesc Item { id: editor diff --git a/mobile/Profiles.qml b/mobile/Profiles.qml index 9a1af3937..1ae8aa8d1 100644 --- a/mobile/Profiles.qml +++ b/mobile/Profiles.qml @@ -21,8 +21,7 @@ import QtQuick import QtQuick.Controls import QtQuick.Layouts -import Vedder.vesc.vescinterface 1.0 -import Vedder.vesc.utility 1.0 +import Vedder.vesc Item { id: topItem diff --git a/mobile/RtData.qml b/mobile/RtData.qml index 4b89dd7e3..8a5b320d4 100644 --- a/mobile/RtData.qml +++ b/mobile/RtData.qml @@ -21,10 +21,7 @@ import QtQuick import QtQuick.Controls import QtQuick.Layouts -import Vedder.vesc.vescinterface 1.0 -import Vedder.vesc.commands 1.0 -import Vedder.vesc.configparams 1.0 -import Vedder.vesc.utility 1.0 +import Vedder.vesc Item { id: rtData diff --git a/mobile/RtDataIMU.qml b/mobile/RtDataIMU.qml index 83fac6e24..359320d02 100644 --- a/mobile/RtDataIMU.qml +++ b/mobile/RtDataIMU.qml @@ -2,10 +2,7 @@ import QtQuick import QtQuick.Controls import QtQuick.Layouts -import Vedder.vesc.vescinterface 1.0 -import Vedder.vesc.commands 1.0 -import Vedder.vesc.configparams 1.0 -import Vedder.vesc.utility 1.0 +import Vedder.vesc Item { id: root diff --git a/mobile/RtDataSetup.qml b/mobile/RtDataSetup.qml index 59ed1c9c4..b869271cb 100644 --- a/mobile/RtDataSetup.qml +++ b/mobile/RtDataSetup.qml @@ -24,10 +24,7 @@ import QtQuick.Layouts import Qt5Compat.GraphicalEffects import QtQuick.Controls.Material -import Vedder.vesc.vescinterface 1.0 -import Vedder.vesc.utility 1.0 -import Vedder.vesc.commands 1.0 -import Vedder.vesc.configparams 1.0 +import Vedder.vesc Item { id: rtData diff --git a/mobile/Settings.qml b/mobile/Settings.qml index 5cd08e2af..fcb310192 100644 --- a/mobile/Settings.qml +++ b/mobile/Settings.qml @@ -21,8 +21,7 @@ import QtQuick import QtQuick.Controls import QtQuick.Layouts -import Vedder.vesc.vescinterface 1.0 -import Vedder.vesc.utility 1.0 +import Vedder.vesc Item { property bool mLastDarkMode: false diff --git a/mobile/SetupWizardFoc.qml b/mobile/SetupWizardFoc.qml index 040e0c0e6..f524e2e17 100755 --- a/mobile/SetupWizardFoc.qml +++ b/mobile/SetupWizardFoc.qml @@ -23,10 +23,7 @@ import QtQuick.Layouts import Qt5Compat.GraphicalEffects import QtQuick.Controls.Material -import Vedder.vesc.vescinterface 1.0 -import Vedder.vesc.commands 1.0 -import Vedder.vesc.configparams 1.0 -import Vedder.vesc.utility 1.0 +import Vedder.vesc Item { id: topItem diff --git a/mobile/SetupWizardIMU.qml b/mobile/SetupWizardIMU.qml index 7e503f88d..7e30be001 100644 --- a/mobile/SetupWizardIMU.qml +++ b/mobile/SetupWizardIMU.qml @@ -8,10 +8,7 @@ import QtQuick.Layouts //import Qt5Compat.GraphicalEffects //import QtQuick.Controls.Material -import Vedder.vesc.vescinterface 1.0 -import Vedder.vesc.commands 1.0 -import Vedder.vesc.configparams 1.0 -import Vedder.vesc.utility 1.0 +import Vedder.vesc Item { id: topItem diff --git a/mobile/SetupWizardInput.qml b/mobile/SetupWizardInput.qml index 3c817adb3..b33eafa83 100644 --- a/mobile/SetupWizardInput.qml +++ b/mobile/SetupWizardInput.qml @@ -22,10 +22,7 @@ import QtQuick.Controls import QtQuick.Layouts import Qt5Compat.GraphicalEffects -import Vedder.vesc.vescinterface 1.0 -import Vedder.vesc.commands 1.0 -import Vedder.vesc.configparams 1.0 -import Vedder.vesc.utility 1.0 +import Vedder.vesc Item { property var dialogParent: ApplicationWindow.overlay diff --git a/mobile/SetupWizardIntro.qml b/mobile/SetupWizardIntro.qml index 9a86deb17..0a06ad0da 100644 --- a/mobile/SetupWizardIntro.qml +++ b/mobile/SetupWizardIntro.qml @@ -22,9 +22,7 @@ import QtQuick.Controls import QtQuick.Layouts import Qt5Compat.GraphicalEffects -import Vedder.vesc.vescinterface 1.0 -import Vedder.vesc.configparams 1.0 -import Vedder.vesc.utility 1.0 +import Vedder.vesc Item { property ConfigParams mInfoConf: VescIf.infoConfig() diff --git a/mobile/StartPage.qml b/mobile/StartPage.qml index e30357126..90a2ffd5a 100644 --- a/mobile/StartPage.qml +++ b/mobile/StartPage.qml @@ -21,10 +21,7 @@ import QtQuick import QtQuick.Controls import QtQuick.Layouts -import Vedder.vesc.vescinterface 1.0 -import Vedder.vesc.bleuart 1.0 -import Vedder.vesc.commands 1.0 -import Vedder.vesc.utility 1.0 +import Vedder.vesc Item { id: topItem diff --git a/mobile/StatPage.qml b/mobile/StatPage.qml index 600f6f6db..a392a0209 100644 --- a/mobile/StatPage.qml +++ b/mobile/StatPage.qml @@ -21,9 +21,7 @@ import QtQuick import QtQuick.Controls import QtQuick.Layouts -import Vedder.vesc.vescinterface 1.0 -import Vedder.vesc.commands 1.0 -import Vedder.vesc.utility 1.0 +import Vedder.vesc Item { property Commands mCommands: VescIf.commands() diff --git a/mobile/TcpBox.qml b/mobile/TcpBox.qml index e10506c52..aee220702 100644 --- a/mobile/TcpBox.qml +++ b/mobile/TcpBox.qml @@ -21,8 +21,7 @@ import QtQuick import QtQuick.Controls import QtQuick.Layouts -import Vedder.vesc.vescinterface 1.0 -import Vedder.vesc.utility 1.0 +import Vedder.vesc Item { implicitHeight: grid.implicitHeight diff --git a/mobile/TcpHubBox.qml b/mobile/TcpHubBox.qml index 1b1a599aa..7904c0c90 100644 --- a/mobile/TcpHubBox.qml +++ b/mobile/TcpHubBox.qml @@ -22,8 +22,7 @@ import QtQuick.Controls import QtQuick.Layouts import QtCore as QSettings -import Vedder.vesc.vescinterface 1.0 -import Vedder.vesc.utility 1.0 +import Vedder.vesc Item { property bool showControls: true diff --git a/mobile/Terminal.qml b/mobile/Terminal.qml index 4c7b03867..f509d3bd0 100644 --- a/mobile/Terminal.qml +++ b/mobile/Terminal.qml @@ -21,10 +21,7 @@ import QtQuick import QtQuick.Controls import QtQuick.Layouts -import Vedder.vesc.vescinterface 1.0 -import Vedder.vesc.commands 1.0 -import Vedder.vesc.configparams 1.0 -import Vedder.vesc.utility 1.0 +import Vedder.vesc Item { id:terminalPageItem diff --git a/mobile/fwhelper.h b/mobile/fwhelper.h index 605a4d6b6..57d37a506 100644 --- a/mobile/fwhelper.h +++ b/mobile/fwhelper.h @@ -22,11 +22,13 @@ #include #include +#include #include "vescinterface.h" class FwHelper : public QObject { Q_OBJECT + QML_ELEMENT public: explicit FwHelper(QObject *parent = nullptr); Q_INVOKABLE QVariantMap getHardwares(FW_RX_PARAMS params, QString hw = ""); diff --git a/mobile/logreader.h b/mobile/logreader.h index 6166879dc..4efb226f1 100644 --- a/mobile/logreader.h +++ b/mobile/logreader.h @@ -22,10 +22,12 @@ #include #include +#include class LogReader : public QObject { Q_OBJECT + QML_ELEMENT public: explicit LogReader(QObject *parent = nullptr); ~LogReader(); diff --git a/mobile/logwriter.h b/mobile/logwriter.h index 2137429fe..cef4c97e6 100644 --- a/mobile/logwriter.h +++ b/mobile/logwriter.h @@ -22,10 +22,12 @@ #include #include +#include class LogWriter : public QObject { Q_OBJECT + QML_ELEMENT public: explicit LogWriter(QObject *parent = nullptr); ~LogWriter(); diff --git a/mobile/main.qml b/mobile/main.qml index 1cc81805a..45f297efe 100644 --- a/mobile/main.qml +++ b/mobile/main.qml @@ -23,11 +23,7 @@ import QtQuick.Controls.Material import QtQuick.Layouts import QtQuick.Window -import Vedder.vesc.vescinterface 1.0 -import Vedder.vesc.commands 1.0 -import Vedder.vesc.configparams 1.0 -import Vedder.vesc.utility 1.0 -import Vedder.vesc.vesc3ditem 1.0 +import Vedder.vesc ApplicationWindow { id: appWindow diff --git a/mobile/qmlui.cpp b/mobile/qmlui.cpp index cea5bfd74..ae8074474 100644 --- a/mobile/qmlui.cpp +++ b/mobile/qmlui.cpp @@ -40,8 +40,14 @@ bool QmlUi::startQmlUi() mEngine = new QQmlApplicationEngine(this); } - qmlRegisterSingletonType("Vedder.vesc.vescinterface", 1, 0, "VescIf", vescinterface_singletontype_provider); - qmlRegisterSingletonType("Vedder.vesc.utility", 1, 0, "Utility", utility_singletontype_provider); + // Qt6: Types are auto-registered via QML_ELEMENT + qt_add_qml_module. + // Provide global VescIf/Utility instances as context properties. + mVesc = new VescInterface(); + mVesc->fwConfig()->loadParamsXml(Utility::configPath("fw.xml")); + Utility::configLoadLatest(mVesc); + + mEngine->rootContext()->setContextProperty("VescIf", mVesc); + mEngine->rootContext()->setContextProperty("Utility", new Utility(this)); mEngine->load(QUrl(QLatin1String("qrc:/mobile/main.qml"))); return !mEngine->rootObjects().isEmpty(); diff --git a/mobile/vesc3ditem.h b/mobile/vesc3ditem.h index 246174d78..d457cff24 100644 --- a/mobile/vesc3ditem.h +++ b/mobile/vesc3ditem.h @@ -28,6 +28,7 @@ class Vesc3dItem : public QQuickPaintedItem { Q_OBJECT + QML_ELEMENT public: explicit Vesc3dItem(QQuickItem *parent = nullptr); diff --git a/packet.cpp b/packet.cpp index ce2d626f1..7d7ad8d1b 100644 --- a/packet.cpp +++ b/packet.cpp @@ -178,7 +178,7 @@ void Packet::processData(QByteArray data) } } - foreach (QByteArray b, decodedPackets) { + for (const QByteArray &b : decodedPackets) { emit packetReceived(b); } } diff --git a/packet.h b/packet.h index 9f4110cec..cb0c8822b 100644 --- a/packet.h +++ b/packet.h @@ -33,8 +33,8 @@ class Packet : public QObject static unsigned short crc16(const unsigned char *buf, unsigned int len); signals: - void dataToSend(QByteArray &data); - void packetReceived(QByteArray &packet); + void dataToSend(QByteArray data); + void packetReceived(QByteArray packet); public slots: void processData(QByteArray data); diff --git a/pages/pageappadc.cpp b/pages/pageappadc.cpp index 7eabc9803..4b3a10bd4 100644 --- a/pages/pageappadc.cpp +++ b/pages/pageappadc.cpp @@ -58,10 +58,10 @@ void PageAppAdc::setVesc(VescInterface *vesc) ui->adcMap->setVesc(mVesc); - connect(mVesc->appConfig(), SIGNAL(paramChangedDouble(QObject*,QString,double)), - this, SLOT(paramChangedDouble(QObject*,QString,double))); - connect(mVesc->appConfig(), SIGNAL(paramChangedEnum(QObject*,QString,int)), - this, SLOT(paramChangedEnum(QObject*,QString,int))); + connect(mVesc->appConfig(), &ConfigParams::paramChangedDouble, + this, &PageAppAdc::paramChangedDouble); + connect(mVesc->appConfig(), &ConfigParams::paramChangedEnum, + this, &PageAppAdc::paramChangedEnum); paramChangedEnum(nullptr, "app_adc_conf.throttle_exp_mode", 0); } diff --git a/pages/pageappimu.cpp b/pages/pageappimu.cpp index b1478bcf8..31e64a54a 100644 --- a/pages/pageappimu.cpp +++ b/pages/pageappimu.cpp @@ -37,8 +37,7 @@ PageAppImu::PageAppImu(QWidget *parent) : mSecondCounter = 0.0; mLastUpdateTime = 0; - connect(mTimer, SIGNAL(timeout()), - this, SLOT(timerSlot())); + connect(mTimer, &QTimer::timeout, this, &PageAppImu::timerSlot); QCustomPlot *plots[3] = {ui->rpyPlot, ui->accelPlot, ui->gyroPlot}; for(int i = 0; i<3; i++) @@ -145,8 +144,8 @@ void PageAppImu::setVesc(VescInterface *vesc) if (mVesc) { reloadParams(); - connect(mVesc->commands(), SIGNAL(valuesImuReceived(IMU_VALUES,uint)), - this, SLOT(valuesReceived(IMU_VALUES,uint))); + connect(mVesc->commands(), &Commands::valuesImuReceived, + this, &PageAppImu::valuesReceived); } } diff --git a/pages/pageappnunchuk.cpp b/pages/pageappnunchuk.cpp index 6cf392cb9..114a6c93d 100644 --- a/pages/pageappnunchuk.cpp +++ b/pages/pageappnunchuk.cpp @@ -58,13 +58,13 @@ void PageAppNunchuk::setVesc(VescInterface *vesc) ui->nrfPair->setVesc(mVesc); reloadParams(); - connect(mVesc->commands(), SIGNAL(decodedChukReceived(double)), - this, SLOT(decodedChukReceived(double))); + connect(mVesc->commands(), &Commands::decodedChukReceived, + this, &PageAppNunchuk::decodedChukReceived); - connect(mVesc->appConfig(), SIGNAL(paramChangedDouble(QObject*,QString,double)), - this, SLOT(paramChangedDouble(QObject*,QString,double))); - connect(mVesc->appConfig(), SIGNAL(paramChangedEnum(QObject*,QString,int)), - this, SLOT(paramChangedEnum(QObject*,QString,int))); + connect(mVesc->appConfig(), &ConfigParams::paramChangedDouble, + this, &PageAppNunchuk::paramChangedDouble); + connect(mVesc->appConfig(), &ConfigParams::paramChangedEnum, + this, &PageAppNunchuk::paramChangedEnum); paramChangedEnum(nullptr, "app_chuk_conf.throttle_exp_mode", 0); } diff --git a/pages/pageappppm.cpp b/pages/pageappppm.cpp index df85cbdc4..97dbc0c11 100644 --- a/pages/pageappppm.cpp +++ b/pages/pageappppm.cpp @@ -58,10 +58,10 @@ void PageAppPpm::setVesc(VescInterface *vesc) ui->ppmMap->setVesc(mVesc); - connect(mVesc->appConfig(), SIGNAL(paramChangedDouble(QObject*,QString,double)), - this, SLOT(paramChangedDouble(QObject*,QString,double))); - connect(mVesc->appConfig(), SIGNAL(paramChangedEnum(QObject*,QString,int)), - this, SLOT(paramChangedEnum(QObject*,QString,int))); + connect(mVesc->appConfig(), &ConfigParams::paramChangedDouble, + this, &PageAppPpm::paramChangedDouble); + connect(mVesc->appConfig(), &ConfigParams::paramChangedEnum, + this, &PageAppPpm::paramChangedEnum); paramChangedEnum(nullptr, "app_ppm_conf.throttle_exp_mode", 0); } diff --git a/pages/pagebms.cpp b/pages/pagebms.cpp index 4b64d2435..a50ebad0e 100644 --- a/pages/pagebms.cpp +++ b/pages/pagebms.cpp @@ -57,8 +57,8 @@ void PageBms::setVesc(VescInterface *vesc) mVesc = vesc; if (mVesc) { - connect(mVesc->commands(), SIGNAL(bmsValuesRx(BMS_VALUES)), - this, SLOT(bmsValuesRx(BMS_VALUES))); + connect(mVesc->commands(), &Commands::bmsValuesRx, + this, &PageBms::bmsValuesRx); } } diff --git a/pages/pagecananalyzer.cpp b/pages/pagecananalyzer.cpp index a7a3e9dab..537f435c6 100644 --- a/pages/pagecananalyzer.cpp +++ b/pages/pagecananalyzer.cpp @@ -51,8 +51,8 @@ void PageCanAnalyzer::setVesc(VescInterface *vesc) if (mVesc) { reloadParams(); - connect(mVesc->commands(), SIGNAL(canFrameRx(QByteArray,quint32,bool)), - this, SLOT(canFrameRx(QByteArray,quint32,bool))); + connect(mVesc->commands(), &Commands::canFrameRx, + this, &PageCanAnalyzer::canFrameRx); } } diff --git a/pages/pageconnection.cpp b/pages/pageconnection.cpp index 9aeb80f42..79a0731a4 100644 --- a/pages/pageconnection.cpp +++ b/pages/pageconnection.cpp @@ -34,8 +34,7 @@ PageConnection::PageConnection(QWidget *parent) : mVesc = nullptr; mTimer = new QTimer(this); - connect(mTimer, SIGNAL(timeout()), - this, SLOT(timerSlot())); + connect(mTimer, &QTimer::timeout, this, &PageConnection::timerSlot); mTimer->start(20); @@ -130,8 +129,8 @@ void PageConnection::setVesc(VescInterface *vesc) ui->tcpHubVescPasswordLineEdit->setText(mVesc->getLastTcpHubVescPass()); #ifdef HAS_BLUETOOTH - connect(mVesc->bleDevice(), SIGNAL(scanDone(QVariantMap,bool)), - this, SLOT(bleScanDone(QVariantMap,bool))); + connect(mVesc->bleDevice(), &BleUart::scanDone, + this, &PageConnection::bleScanDone); QString lastBleAddr = mVesc->getLastBleAddr(); if (lastBleAddr != "") { @@ -167,14 +166,11 @@ void PageConnection::setVesc(VescInterface *vesc) ui->CANbusInterfaceBox->setCurrentIndex(0); #endif - connect(mVesc->commands(), SIGNAL(pingCanRx(QVector,bool)), - this, SLOT(pingCanRx(QVector,bool))); - connect(mVesc, SIGNAL(CANbusNewNode(int)), - this, SLOT(CANbusNewNode(int))); - connect(mVesc, SIGNAL(CANbusInterfaceListUpdated()), - this, SLOT(CANbusInterfaceListUpdated())); - connect(mVesc, SIGNAL(pairingListUpdated()), - this, SLOT(pairingListUpdated())); + connect(mVesc->commands(), &Commands::pingCanRx, + this, &PageConnection::pingCanRx); + connect(mVesc, &VescInterface::CANbusNewNode, this, &PageConnection::CANbusNewNode); + connect(mVesc, &VescInterface::CANbusInterfaceListUpdated, this, &PageConnection::CANbusInterfaceListUpdated); + connect(mVesc, &VescInterface::pairingListUpdated, this, &PageConnection::pairingListUpdated); pairingListUpdated(); on_serialRefreshButton_clicked(); @@ -354,7 +350,7 @@ void PageConnection::on_serialRefreshButton_clicked() if (mVesc) { ui->serialPortBox->clear(); auto ports = mVesc->listSerialPorts(); - foreach(auto &info, ports) { + for (auto &info : ports) { auto port = info.value(); ui->serialPortBox->addItem(port.name, port.systemPath); } @@ -555,7 +551,7 @@ void PageConnection::on_pairConnectedButton_clicked() mVesc->storeSettings(); ConfigParams *ap = mVesc->appConfig(); mVesc->commands()->getAppConf(); - bool res = Utility::waitSignal(ap, SIGNAL(updated()), 1500); + bool res = Utility::waitSignal(ap, &ConfigParams::updated, 1500); if (res) { mVesc->appConfig()->updateParamBool("pairing_done", true, nullptr); @@ -659,7 +655,7 @@ void PageConnection::on_unpairButton_clicked() if (reply == QMessageBox::Ok) { ConfigParams *ap = mVesc->appConfig(); mVesc->commands()->getAppConf(); - bool res = Utility::waitSignal(ap, SIGNAL(updated()), 1500); + bool res = Utility::waitSignal(ap, &ConfigParams::updated, 1500); if (res) { mVesc->appConfig()->updateParamBool("pairing_done", false, nullptr); diff --git a/pages/pagecustomconfig.cpp b/pages/pagecustomconfig.cpp index a4e215abd..8d6aa8ebb 100644 --- a/pages/pagecustomconfig.cpp +++ b/pages/pagecustomconfig.cpp @@ -53,8 +53,7 @@ void PageCustomConfig::setVesc(VescInterface *vesc) mVesc = vesc; if (mVesc) { - connect(mVesc, SIGNAL(customConfigLoadDone()), - this, SLOT(customConfigLoadDone())); + connect(mVesc, &VescInterface::customConfigLoadDone, this, &PageCustomConfig::customConfigLoadDone); } } diff --git a/pages/pagedisplaytool.cpp b/pages/pagedisplaytool.cpp index adc5005a1..7202fd4d5 100644 --- a/pages/pagedisplaytool.cpp +++ b/pages/pagedisplaytool.cpp @@ -39,32 +39,32 @@ PageDisplayTool::PageDisplayTool(QWidget *parent) : ui->fontEditor->setVisible(false); ui->fontEditor->setVisible(true); - connect(ui->ovCrHBox, SIGNAL(valueChanged(int)), this, SLOT(updateOverlay())); - connect(ui->ovCrWBox, SIGNAL(valueChanged(int)), this, SLOT(updateOverlay())); - connect(ui->ovCrXPosBox, SIGNAL(valueChanged(int)), this, SLOT(updateOverlay())); - connect(ui->ovCrYPosBox, SIGNAL(valueChanged(int)), this, SLOT(updateOverlay())); - connect(ui->overlayBox, SIGNAL(toggled(bool)), this, SLOT(updateOverlay())); - connect(ui->ovImCXPosBox, SIGNAL(valueChanged(int)), this, SLOT(updateOverlay())); - connect(ui->ovImCYPosBox, SIGNAL(valueChanged(int)), this, SLOT(updateOverlay())); - connect(ui->ovRotBox, SIGNAL(valueChanged(double)), this, SLOT(updateOverlay())); - connect(ui->ovScaleBox, SIGNAL(valueChanged(double)), this, SLOT(updateOverlay())); - connect(ui->ovRXPosBox, SIGNAL(valueChanged(int)), this, SLOT(updateOverlay())); - connect(ui->ovRYPosBox, SIGNAL(valueChanged(int)), this, SLOT(updateOverlay())); - connect(ui->ovXPosBox, SIGNAL(valueChanged(int)), this, SLOT(updateOverlay())); - connect(ui->ovYPosBox, SIGNAL(valueChanged(int)), this, SLOT(updateOverlay())); - connect(ui->ovTrBox, SIGNAL(valueChanged(int)), this, SLOT(updateOverlay())); - - connect(ui->fontOverlayBox, SIGNAL(toggled(bool)), this, SLOT(updateOverlay())); - connect(ui->fontBoldBox, SIGNAL(toggled(bool)), this, SLOT(updateOverlay())); - connect(ui->fontBorderBox, SIGNAL(toggled(bool)), this, SLOT(updateOverlay())); - connect(ui->fontAABox, SIGNAL(toggled(bool)), this, SLOT(updateOverlay())); - connect(ui->fontXPosBox, SIGNAL(valueChanged(int)), this, SLOT(updateOverlay())); - connect(ui->fontYPosBox, SIGNAL(valueChanged(int)), this, SLOT(updateOverlay())); - connect(ui->fontWBox, SIGNAL(valueChanged(int)), this, SLOT(updateOverlay())); - connect(ui->fontHBox, SIGNAL(valueChanged(int)), this, SLOT(updateOverlay())); - connect(ui->fontBox, SIGNAL(currentFontChanged(QFont)), this, SLOT(updateOverlay())); - connect(ui->fontSampleEdit, SIGNAL(textChanged(QString)), this, SLOT(updateOverlay())); - connect(ui->fontScaleBox, SIGNAL(valueChanged(double)), this, SLOT(updateOverlay())); + connect(ui->ovCrHBox, qOverload(&QSpinBox::valueChanged), this, &PageDisplayTool::updateOverlay); + connect(ui->ovCrWBox, qOverload(&QSpinBox::valueChanged), this, &PageDisplayTool::updateOverlay); + connect(ui->ovCrXPosBox, qOverload(&QSpinBox::valueChanged), this, &PageDisplayTool::updateOverlay); + connect(ui->ovCrYPosBox, qOverload(&QSpinBox::valueChanged), this, &PageDisplayTool::updateOverlay); + connect(ui->overlayBox, &QGroupBox::toggled, this, &PageDisplayTool::updateOverlay); + connect(ui->ovImCXPosBox, qOverload(&QSpinBox::valueChanged), this, &PageDisplayTool::updateOverlay); + connect(ui->ovImCYPosBox, qOverload(&QSpinBox::valueChanged), this, &PageDisplayTool::updateOverlay); + connect(ui->ovRotBox, qOverload(&QDoubleSpinBox::valueChanged), this, &PageDisplayTool::updateOverlay); + connect(ui->ovScaleBox, qOverload(&QDoubleSpinBox::valueChanged), this, &PageDisplayTool::updateOverlay); + connect(ui->ovRXPosBox, qOverload(&QSpinBox::valueChanged), this, &PageDisplayTool::updateOverlay); + connect(ui->ovRYPosBox, qOverload(&QSpinBox::valueChanged), this, &PageDisplayTool::updateOverlay); + connect(ui->ovXPosBox, qOverload(&QSpinBox::valueChanged), this, &PageDisplayTool::updateOverlay); + connect(ui->ovYPosBox, qOverload(&QSpinBox::valueChanged), this, &PageDisplayTool::updateOverlay); + connect(ui->ovTrBox, qOverload(&QSpinBox::valueChanged), this, &PageDisplayTool::updateOverlay); + + connect(ui->fontOverlayBox, &QGroupBox::toggled, this, &PageDisplayTool::updateOverlay); + connect(ui->fontBoldBox, &QAbstractButton::toggled, this, &PageDisplayTool::updateOverlay); + connect(ui->fontBorderBox, &QAbstractButton::toggled, this, &PageDisplayTool::updateOverlay); + connect(ui->fontAABox, &QAbstractButton::toggled, this, &PageDisplayTool::updateOverlay); + connect(ui->fontXPosBox, qOverload(&QSpinBox::valueChanged), this, &PageDisplayTool::updateOverlay); + connect(ui->fontYPosBox, qOverload(&QSpinBox::valueChanged), this, &PageDisplayTool::updateOverlay); + connect(ui->fontWBox, qOverload(&QSpinBox::valueChanged), this, &PageDisplayTool::updateOverlay); + connect(ui->fontHBox, qOverload(&QSpinBox::valueChanged), this, &PageDisplayTool::updateOverlay); + connect(ui->fontBox, &QFontComboBox::currentFontChanged, this, &PageDisplayTool::updateOverlay); + connect(ui->fontSampleEdit, &QLineEdit::textChanged, this, &PageDisplayTool::updateOverlay); + connect(ui->fontScaleBox, qOverload(&QDoubleSpinBox::valueChanged), this, &PageDisplayTool::updateOverlay); updateOverlay(); diff --git a/pages/pageespprog.cpp b/pages/pageespprog.cpp index 59cc656e7..6a7f839ca 100644 --- a/pages/pageespprog.cpp +++ b/pages/pageespprog.cpp @@ -51,7 +51,7 @@ PageEspProg::PageEspProg(QWidget *parent) : } mTimer = new QTimer(this); - connect(mTimer, SIGNAL(timeout()), this, SLOT(timerSlot())); + connect(mTimer, &QTimer::timeout, this, &PageEspProg::timerSlot); mTimer->start(50); connect(&mEspFlash, &Esp32Flash::flashProgress, [this](double progress) { @@ -131,7 +131,7 @@ void PageEspProg::on_serialRefreshButton_clicked() if (mVesc) { ui->serialPortBox->clear(); auto ports = mVesc->listSerialPorts(); - foreach(auto &info, ports) { + for (auto &info : ports) { auto port = info.value(); ui->serialPortBox->addItem(port.name, port.systemPath); } @@ -283,7 +283,7 @@ void PageEspProg::scanChipFw(QString chipDir) { QDir dir(chipDir); dir.setSorting(QDir::Name); - foreach (auto fi, dir.entryInfoList()) { + for (const auto &fi : dir.entryInfoList()) { QFileInfo fiApp(fi.absoluteFilePath() + "/vesc_express.bin"); QFileInfo fiBl(fi.absoluteFilePath() + "/bootloader.bin"); QFileInfo fiPart(fi.absoluteFilePath() + "/partition-table.bin"); @@ -371,7 +371,7 @@ void PageEspProg::listAllFw() reloadLatest(false); ui->fwList->clear(); QDir root("://res/firmwares_esp"); - foreach (auto chipDir, root.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot)) { + for (const auto &chipDir : root.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot)) { scanChipFw(chipDir.absoluteFilePath()); } } diff --git a/pages/pageexperiments.cpp b/pages/pageexperiments.cpp index a3affe0d6..1c3e56ec8 100755 --- a/pages/pageexperiments.cpp +++ b/pages/pageexperiments.cpp @@ -73,8 +73,7 @@ PageExperiments::PageExperiments(QWidget *parent) : mTimer->start(ui->sampleIntervalBox->value()); mState = EXPERIMENT_OFF; - connect(mTimer, SIGNAL(timeout()), - this, SLOT(timerSlot())); + connect(mTimer, &QTimer::timeout, this, &PageExperiments::timerSlot); ui->plot->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom); @@ -136,8 +135,7 @@ PageExperiments::PageExperiments(QWidget *parent) : [=]() {plotSamples(false);}); #ifdef HAS_SERIALPORT - connect(mVictronPort, SIGNAL(readyRead()), - this, SLOT(victronDataAvailable())); + connect(mVictronPort, &QIODevice::readyRead, this, &PageExperiments::victronDataAvailable); #endif plotSamples(false); @@ -158,8 +156,8 @@ void PageExperiments::setVesc(VescInterface *vesc) { mVesc = vesc; - connect(mVesc->commands(), SIGNAL(valuesReceived(MC_VALUES,uint)), - this, SLOT(valuesReceived(MC_VALUES,uint))); + connect(mVesc->commands(), &Commands::valuesReceived, + this, &PageExperiments::valuesReceived); } void PageExperiments::stop() @@ -815,7 +813,7 @@ void PageExperiments::on_victronRefreshButton_clicked() ui->victronPortBox->clear(); QList ports = QSerialPortInfo::availablePorts(); - foreach(const QSerialPortInfo &port, ports) { + for (const QSerialPortInfo &port : ports) { ui->victronPortBox->addItem(port.portName(), port.systemLocation()); } diff --git a/pages/pagefirmware.cpp b/pages/pagefirmware.cpp index ea92c90c8..c56e28e47 100755 --- a/pages/pagefirmware.cpp +++ b/pages/pagefirmware.cpp @@ -51,15 +51,15 @@ PageFirmware::PageFirmware(QWidget *parent) : mTimer = new QTimer(this); mTimer->start(500); - connect(ui->hwList, SIGNAL(currentRowChanged(int)), - this, SLOT(updateFwList())); - connect(ui->showNonDefaultBox, SIGNAL(toggled(bool)), - this, SLOT(updateFwList())); - connect(mTimer, SIGNAL(timeout()), this, SLOT(timerSlot())); - connect(ui->archVersionList, SIGNAL(currentRowChanged(int)), - this, SLOT(updateArchFwList())); - connect(ui->showNonDefaultArchBox, SIGNAL(toggled(bool)), - this, SLOT(updateArchFwList())); + connect(ui->hwList, &QListWidget::currentRowChanged, + this, &PageFirmware::updateFwList); + connect(ui->showNonDefaultBox, &QAbstractButton::toggled, + this, &PageFirmware::updateFwList); + connect(mTimer, &QTimer::timeout, this, &PageFirmware::timerSlot); + connect(ui->archVersionList, &QListWidget::currentRowChanged, + this, &PageFirmware::updateArchFwList); + connect(ui->showNonDefaultArchBox, &QAbstractButton::toggled, + this, &PageFirmware::updateArchFwList); QSettings set; ui->fwEdit->setText(set.value("pagefirmware/lastcustomfile", "").toString()); @@ -99,10 +99,8 @@ void PageFirmware::setVesc(VescInterface *vesc) reloadParams(); - connect(mVesc, SIGNAL(fwUploadStatus(QString,double,bool)), - this, SLOT(fwUploadStatus(QString,double,bool))); - connect(mVesc, SIGNAL(fwRxChanged(bool,bool)), - this, SLOT(fwRxChanged(bool,bool))); + connect(mVesc, &VescInterface::fwUploadStatus, this, &PageFirmware::fwUploadStatus); + connect(mVesc, &VescInterface::fwRxChanged, this, &PageFirmware::fwRxChanged); connect(mVesc, &VescInterface::fwArchiveDlProgress, [this](QString msg, double prog) { ui->displayDl->setText(msg); @@ -239,7 +237,7 @@ void PageFirmware::updateHwList(FW_RX_PARAMS params) fwDir = "://res/firmwares_bms"; } - foreach (const auto &fi, QDir(fwDir).entryInfoList(QDir::NoFilter, QDir::Name)) { + for (const auto &fi : QDir(fwDir).entryInfoList(QDir::NoFilter, QDir::Name)) { QStringList names = fi.fileName().split("_o_"); if (fi.isDir() && (params.hw.isEmpty() || names.contains(params.hw, Qt::CaseInsensitive))) { QListWidgetItem *item = new QListWidgetItem; diff --git a/pages/pageimu.cpp b/pages/pageimu.cpp index c4b76c763..b48ec14a9 100644 --- a/pages/pageimu.cpp +++ b/pages/pageimu.cpp @@ -37,8 +37,7 @@ PageImu::PageImu(QWidget *parent) : mSecondCounter = 0.0; mLastUpdateTime = 0; - connect(mTimer, SIGNAL(timeout()), - this, SLOT(timerSlot())); + connect(mTimer, &QTimer::timeout, this, &PageImu::timerSlot); QCustomPlot *plots[4] = {ui->rpyPlot, ui->accelPlot, ui->gyroPlot, ui->magPlot }; for(int i = 0; i<4; i++) @@ -164,8 +163,8 @@ void PageImu::setVesc(VescInterface *vesc) mVesc = vesc; if (mVesc) { - connect(mVesc->commands(), SIGNAL(valuesImuReceived(IMU_VALUES,uint)), - this, SLOT(valuesReceived(IMU_VALUES,uint))); + connect(mVesc->commands(), &Commands::valuesImuReceived, + this, &PageImu::valuesReceived); } } diff --git a/pages/pagelisp.cpp b/pages/pagelisp.cpp index b2a719b57..b870d09d3 100644 --- a/pages/pagelisp.cpp +++ b/pages/pagelisp.cpp @@ -112,7 +112,7 @@ PageLisp::PageLisp(QWidget *parent) : updateRecentList(); // Load examples - foreach (auto &fi, QDir("://res/LispBM/Examples/").entryInfoList(QDir::NoFilter, QDir::Name)) { + for (auto &fi : QDir("://res/LispBM/Examples/").entryInfoList(QDir::NoFilter, QDir::Name)) { QListWidgetItem *item = new QListWidgetItem; item->setText(fi.fileName()); item->setData(Qt::UserRole, fi.filePath()); @@ -171,7 +171,7 @@ void PageLisp::saveStateToSettings() set.remove("pagelisp/recentfiles"); set.beginWriteArray("pagelisp/recentfiles"); int ind = 0; - foreach (auto f, mRecentFiles) { + for (const auto &f : mRecentFiles) { set.setArrayIndex(ind); set.setValue("path", f); ind++; @@ -334,7 +334,7 @@ bool PageLisp::openFileTab(QString fileName) void PageLisp::updateRecentList() { ui->recentList->clear(); - foreach (auto f, mRecentFiles) { + for (const auto &f : mRecentFiles) { ui->recentList->addItem(f); } diff --git a/pages/pageloganalysis.cpp b/pages/pageloganalysis.cpp index e1e3f4413..8c71d1250 100755 --- a/pages/pageloganalysis.cpp +++ b/pages/pageloganalysis.cpp @@ -320,7 +320,7 @@ void PageLogAnalysis::setVesc(VescInterface *vesc) return; } - foreach (auto e, mLogHeader) { + for (const auto &e : mLogHeader) { addDataItem(e.name, !e.isTimeStamp, e.scaleStep, e.scaleMax); } @@ -554,7 +554,7 @@ void PageLogAnalysis::loadVescLog(QVector log) mLogHeader.append(LOG_HEADER("num_vesc", "VESC num", "", 0)); LOG_DATA bestPoint = log.first(); - foreach (auto &d, log) { + for (auto &d : log) { if (d.posTime >= 0 && d.hAcc > 0.0) { if (d.hAcc < bestPoint.hAcc || bestPoint.hAcc <= 0.0) { bestPoint = d; @@ -574,7 +574,7 @@ void PageLogAnalysis::loadVescLog(QVector log) bool prevSampleGnssSet = false; double metersGnss = 0.0; - foreach (auto &d, log) { + for (auto &d : log) { if (d.posTime >= 0 && (!ui->filterOutlierBox->isChecked() || ( @@ -676,7 +676,7 @@ void PageLogAnalysis::loadVescLog(QVector log) return; } - foreach (auto e, mLogHeader) { + for (const auto &e : mLogHeader) { addDataItem(e.name, !e.isTimeStamp, e.scaleStep, e.scaleMax); } @@ -844,7 +844,7 @@ void PageLogAnalysis::updateGraphs() LocPoint p, p2; double time = 0; - foreach (const auto &d, mLogTruncated) { + for (const auto &d : mLogTruncated) { if (mInd_t_day >= 0) { if (startTime < 0) { startTime = d[mInd_t_day]; @@ -1206,7 +1206,7 @@ void PageLogAnalysis::logListRefresh() QDir dir(dirPath); if (dir.exists()) { - foreach (QFileInfo d, dir.entryInfoList(QDir::Dirs | QDir::NoDot, QDir::Name)) { + for (const QFileInfo &d : dir.entryInfoList(QDir::Dirs | QDir::NoDot, QDir::Name)) { if (d.fileName() == ".." && dirPath == "/") { continue; } @@ -1218,8 +1218,7 @@ void PageLogAnalysis::logListRefresh() ui->logTable->setItem(ui->logTable->rowCount() - 1, 1, new QTableWidgetItem("Folder")); } - foreach (QFileInfo f, dir.entryInfoList(QStringList() << "*.csv" << "*.Csv" << "*.CSV", - QDir::Files, QDir::Name)) { + for (const auto &f : dir.entryInfoList(QStringList() << "*.csv" << "*.Csv" << "*.CSV", QDir::Files, QDir::Name)) { QTableWidgetItem *itName = new QTableWidgetItem(f.fileName()); itName->setData(Qt::UserRole, f.absoluteFilePath()); ui->logTable->setRowCount(ui->logTable->rowCount() + 1); @@ -1309,7 +1308,7 @@ void PageLogAnalysis::openLog(QString name, QByteArray data) QVector entryLastData; - foreach (auto &t, tokensLine1) { + for (auto &t : tokensLine1) { auto token = t.split(":"); LOG_HEADER h; for (int i = 0;i < token.size();i++) { @@ -1360,7 +1359,7 @@ void PageLogAnalysis::openLog(QString name, QByteArray data) return; } - foreach (auto e, mLogHeader) { + for (const auto &e : mLogHeader) { addDataItem(e.name, !e.isTimeStamp, e.scaleStep, e.scaleMax); } @@ -1437,7 +1436,7 @@ void PageLogAnalysis::generateMissingEntries() double haccBest = 100000.0; double i_llh[3] = {57.71495867, 12.89134921, 220.0}; - foreach (auto &d, mLog) { + for (auto &d : mLog) { double lat = d.at(mInd_gnss_lat); double lon = d.at(mInd_gnss_lon); double alt = 0; @@ -1567,7 +1566,7 @@ void PageLogAnalysis::storeSelection() mSelection.checkedY2Boxes.clear(); // Selected rows - foreach (auto i, ui->dataTable->selectionModel()->selectedRows()) { + for (const auto &i : ui->dataTable->selectionModel()->selectedRows()) { mSelection.dataLabels.append(ui->dataTable->item(i.row(), dataTableColName)->text()); } @@ -1600,21 +1599,21 @@ void PageLogAnalysis::restoreSelection() bool checkedY1 = false; bool checkedY2 = false; - foreach (auto i, mSelection.dataLabels) { + for (const auto &i : mSelection.dataLabels) { if (rowText == i) { selected = true; break; } } - foreach (auto i, mSelection.checkedY1Boxes) { + for (const auto &i : mSelection.checkedY1Boxes) { if (rowText == i) { checkedY1 = true; break; } } - foreach (auto i, mSelection.checkedY2Boxes) { + for (const auto &i : mSelection.checkedY2Boxes) { if (rowText == i) { checkedY2 = true; break; @@ -1898,7 +1897,7 @@ void PageLogAnalysis::on_vescSaveAsButton_clicked() mLastSaveAsPath = path; bool didCancel = false; - foreach (auto it, items) { + for (const auto &it : items) { if (didCancel) { break; } @@ -1960,7 +1959,7 @@ void PageLogAnalysis::on_vescLogDeleteButton_clicked() if (ret == QMessageBox::Yes) { ui->vescLogTab->setEnabled(false); int cnt = 0; - foreach (auto it, items) { + for (const auto &it : items) { if (it->data(Qt::UserRole).canConvert()) { auto fe = it->data(Qt::UserRole).value(); bool ok = mVesc->commands()->fileBlockRemove(mVescLastPath + "/" + fe.name); @@ -2019,8 +2018,7 @@ void PageLogAnalysis::on_logLocalRefreshButton_clicked() QDir dir(dirPath); if (dir.exists()) { - foreach (QFileInfo f, dir.entryInfoList(QStringList() << "*.csv" << "*.Csv" << "*.CSV", - QDir::Files, QDir::Name)) { + for (const auto &f : dir.entryInfoList(QStringList() << "*.csv" << "*.Csv" << "*.CSV", QDir::Files, QDir::Name)) { QTableWidgetItem *itName = new QTableWidgetItem(f.fileName()); itName->setData(Qt::UserRole, f.absoluteFilePath()); ui->logLocalTable->setRowCount(ui->logLocalTable->rowCount() + 1); @@ -2053,7 +2051,7 @@ void PageLogAnalysis::on_logLocalDeleteButton_clicked() QMessageBox::Yes | QMessageBox::Cancel); if (ret == QMessageBox::Yes) { - foreach (auto file, items) { + for (const auto &file : items) { QString fileName = file->data(Qt::UserRole).toString(); QFile fileNow(fileName); diff --git a/pages/pagemotorinfo.cpp b/pages/pagemotorinfo.cpp index 0496330dd..0349dc3a0 100644 --- a/pages/pagemotorinfo.cpp +++ b/pages/pagemotorinfo.cpp @@ -47,10 +47,10 @@ void PageMotorInfo::setVesc(VescInterface *vesc) if (mVesc) { reloadParams(); - connect(mVesc->mcConfig(), SIGNAL(paramChangedQString(QObject*,QString,QString)), - this, SLOT(paramChangedQString(QObject*,QString,QString))); - connect(mVesc->mcConfig(), SIGNAL(savingXml()), - this, SLOT(savingXml())); + connect(mVesc->mcConfig(), &ConfigParams::paramChangedQString, + this, &PageMotorInfo::paramChangedQString); + connect(mVesc->mcConfig(), &ConfigParams::savingXml, + this, &PageMotorInfo::savingXml); } } diff --git a/pages/pagertdata.cpp b/pages/pagertdata.cpp index 32e59019a..7f025ed01 100644 --- a/pages/pagertdata.cpp +++ b/pages/pagertdata.cpp @@ -171,8 +171,7 @@ PageRtData::PageRtData(QWidget *parent) : ui->posPlot->xAxis->setLabel("Sample"); ui->posPlot->yAxis->setLabel("Degrees"); - connect(mTimer, SIGNAL(timeout()), - this, SLOT(timerSlot())); + connect(mTimer, &QTimer::timeout, this, &PageRtData::timerSlot); } PageRtData::~PageRtData() @@ -190,10 +189,10 @@ void PageRtData::setVesc(VescInterface *vesc) mVesc = vesc; if (mVesc) { - connect(mVesc->commands(), SIGNAL(valuesReceived(MC_VALUES,uint)), - this, SLOT(valuesReceived(MC_VALUES,uint))); - connect(mVesc->commands(), SIGNAL(rotorPosReceived(double)), - this, SLOT(rotorPosReceived(double))); + connect(mVesc->commands(), &Commands::valuesReceived, + this, &PageRtData::valuesReceived); + connect(mVesc->commands(), &Commands::rotorPosReceived, + this, &PageRtData::rotorPosReceived); } } diff --git a/pages/pagesampleddata.cpp b/pages/pagesampleddata.cpp index 003a1aae6..ba5d2bc3a 100644 --- a/pages/pagesampleddata.cpp +++ b/pages/pagesampleddata.cpp @@ -78,29 +78,29 @@ PageSampledData::PageSampledData(QWidget *parent) : plots[i]->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom); } - connect(mTimer, SIGNAL(timeout()), this, SLOT(timerSlot())); - connect(mSampleGetTimer, SIGNAL(timeout()), this, SLOT(sampleGetTimerSlot())); - - connect(ui->compDelayBox, SIGNAL(toggled(bool)), this, SLOT(replotAll())); - connect(ui->currentFilterFreqBox, SIGNAL(valueChanged(double)), this, SLOT(replotAll())); - connect(ui->currentFilterTapBox, SIGNAL(valueChanged(int)), this, SLOT(replotAll())); - connect(ui->plotModeBox, SIGNAL(currentIndexChanged(int)), this, SLOT(replotAll())); - connect(ui->filterBox, SIGNAL(currentIndexChanged(int)), this, SLOT(replotAll())); - connect(ui->filterScatterBox, SIGNAL(toggled(bool)), this, SLOT(replotAll())); - connect(ui->hammingBox, SIGNAL(toggled(bool)), this, SLOT(replotAll())); - connect(ui->showCurrent1Box, SIGNAL(toggled(bool)), this, SLOT(replotAll())); - connect(ui->showCurrent2Box, SIGNAL(toggled(bool)), this, SLOT(replotAll())); - connect(ui->showCurrent3Box, SIGNAL(toggled(bool)), this, SLOT(replotAll())); - connect(ui->showMcTotalCurrentBox, SIGNAL(toggled(bool)), this, SLOT(replotAll())); - connect(ui->showPh1Box, SIGNAL(toggled(bool)), this, SLOT(replotAll())); - connect(ui->showPh2Box, SIGNAL(toggled(bool)), this, SLOT(replotAll())); - connect(ui->showPh3Box, SIGNAL(toggled(bool)), this, SLOT(replotAll())); - connect(ui->showPosCurrentBox, SIGNAL(toggled(bool)), this, SLOT(replotAll())); - connect(ui->showPosVoltageBox, SIGNAL(toggled(bool)), this, SLOT(replotAll())); - connect(ui->showVirtualGndBox, SIGNAL(toggled(bool)), this, SLOT(replotAll())); - connect(ui->showPhaseBox, SIGNAL(toggled(bool)), this, SLOT(replotAll())); - connect(ui->showPhaseVoltageBox, SIGNAL(toggled(bool)), this, SLOT(replotAll())); - connect(ui->truncateBox, SIGNAL(toggled(bool)), this, SLOT(replotAll())); + connect(mTimer, &QTimer::timeout, this, &PageSampledData::timerSlot); + connect(mSampleGetTimer, &QTimer::timeout, this, &PageSampledData::sampleGetTimerSlot); + + connect(ui->compDelayBox, &QAbstractButton::toggled, this, &PageSampledData::replotAll); + connect(ui->currentFilterFreqBox, qOverload(&QDoubleSpinBox::valueChanged), this, &PageSampledData::replotAll); + connect(ui->currentFilterTapBox, qOverload(&QSpinBox::valueChanged), this, &PageSampledData::replotAll); + connect(ui->plotModeBox, &QComboBox::currentIndexChanged, this, &PageSampledData::replotAll); + connect(ui->filterBox, &QComboBox::currentIndexChanged, this, &PageSampledData::replotAll); + connect(ui->filterScatterBox, &QAbstractButton::toggled, this, &PageSampledData::replotAll); + connect(ui->hammingBox, &QAbstractButton::toggled, this, &PageSampledData::replotAll); + connect(ui->showCurrent1Box, &QAbstractButton::toggled, this, &PageSampledData::replotAll); + connect(ui->showCurrent2Box, &QAbstractButton::toggled, this, &PageSampledData::replotAll); + connect(ui->showCurrent3Box, &QAbstractButton::toggled, this, &PageSampledData::replotAll); + connect(ui->showMcTotalCurrentBox, &QAbstractButton::toggled, this, &PageSampledData::replotAll); + connect(ui->showPh1Box, &QAbstractButton::toggled, this, &PageSampledData::replotAll); + connect(ui->showPh2Box, &QAbstractButton::toggled, this, &PageSampledData::replotAll); + connect(ui->showPh3Box, &QAbstractButton::toggled, this, &PageSampledData::replotAll); + connect(ui->showPosCurrentBox, &QAbstractButton::toggled, this, &PageSampledData::replotAll); + connect(ui->showPosVoltageBox, &QAbstractButton::toggled, this, &PageSampledData::replotAll); + connect(ui->showVirtualGndBox, &QAbstractButton::toggled, this, &PageSampledData::replotAll); + connect(ui->showPhaseBox, &QAbstractButton::toggled, this, &PageSampledData::replotAll); + connect(ui->showPhaseVoltageBox, &QAbstractButton::toggled, this, &PageSampledData::replotAll); + connect(ui->truncateBox, &QAbstractButton::toggled, this, &PageSampledData::replotAll); replotAll(); } @@ -120,8 +120,8 @@ void PageSampledData::setVesc(VescInterface *vesc) mVesc = vesc; if (mVesc) { - connect(mVesc->commands(), SIGNAL(samplesReceived(QByteArray)), - this, SLOT(samplesReceived(QByteArray))); + connect(mVesc->commands(), &Commands::samplesReceived, + this, &PageSampledData::samplesReceived); connect(mVesc->commands(), &Commands::sampleDataQmlStarted, [this](int samples) { clearBuffers(); diff --git a/pages/pagescripting.cpp b/pages/pagescripting.cpp index 15d7e563c..cfd96130d 100755 --- a/pages/pagescripting.cpp +++ b/pages/pagescripting.cpp @@ -165,7 +165,7 @@ void PageScripting::saveStateToSettings() set.remove("pagescripting/recentfiles"); set.beginWriteArray("pagescripting/recentfiles"); int ind = 0; - foreach (auto f, mRecentFiles) { + for (const auto &f : mRecentFiles) { set.setArrayIndex(ind); set.setValue("path", f); ind++; diff --git a/pages/pageswdprog.cpp b/pages/pageswdprog.cpp index e61312984..f0526d4c0 100644 --- a/pages/pageswdprog.cpp +++ b/pages/pageswdprog.cpp @@ -68,7 +68,7 @@ PageSwdProg::PageSwdProg(QWidget *parent) : ui->fw4Edit->setText(set.value("pageswdprog/lastcustomfile4").toString()); } - connect(mTimer, SIGNAL(timeout()), this, SLOT(timerSlot())); + connect(mTimer, &QTimer::timeout, this, &PageSwdProg::timerSlot); // UICR tab ui->uicrTable->setColumnWidth(0, 200); @@ -255,7 +255,7 @@ void PageSwdProg::on_connectButton_clicked() if (mVesc) { mVesc->commands()->bmMapPinsDefault(); ui->connectButton->setEnabled(false); - Utility::waitSignal(mVesc->commands(), SIGNAL(bmMapPinsDefaultRes(bool)), 100); + Utility::waitSignal(mVesc->commands(), &Commands::bmMapPinsDefaultRes, 100); ui->connectButton->setEnabled(true); mVesc->commands()->bmConnect(); } @@ -422,10 +422,9 @@ void PageSwdProg::setVesc(VescInterface *vesc) { mVesc = vesc; - connect(mVesc, SIGNAL(fwUploadStatus(QString,double,bool)), - this, SLOT(fwUploadStatus(QString,double,bool))); - connect(mVesc->commands(), SIGNAL(bmConnRes(int)), - this, SLOT(bmConnRes(int))); + connect(mVesc, &VescInterface::fwUploadStatus, this, &PageSwdProg::fwUploadStatus); + connect(mVesc->commands(), &Commands::bmConnRes, + this, &PageSwdProg::bmConnRes); connect(mVesc->commands(), &Commands::bmMapPinsNrf5xRes, [this](bool res) { if (!res) { @@ -645,7 +644,7 @@ void PageSwdProg::on_connectNrf5xButton_clicked() if (mVesc) { mVesc->commands()->bmMapPinsNrf5x(); ui->connectNrf5xButton->setEnabled(false); - Utility::waitSignal(mVesc->commands(), SIGNAL(bmMapPinsNrf5xRes(bool)), 100); + Utility::waitSignal(mVesc->commands(), &Commands::bmMapPinsNrf5xRes, 100); ui->connectNrf5xButton->setEnabled(true); mVesc->commands()->bmConnect(); } diff --git a/pages/pageterminal.cpp b/pages/pageterminal.cpp index b03603745..63e44ced2 100644 --- a/pages/pageterminal.cpp +++ b/pages/pageterminal.cpp @@ -56,8 +56,8 @@ void PageTerminal::setVesc(VescInterface *vesc) mVesc = vesc; if (mVesc) { - connect(mVesc->commands(), SIGNAL(printReceived(QString)), - this, SLOT(printReceived(QString))); + connect(mVesc->commands(), &Commands::printReceived, + this, &PageTerminal::printReceived); } } diff --git a/pages/pagevescpackage.cpp b/pages/pagevescpackage.cpp index 7e0ad5a53..d07b965e6 100644 --- a/pages/pagevescpackage.cpp +++ b/pages/pagevescpackage.cpp @@ -447,7 +447,7 @@ void PageVescPackage::reloadArchive() ui->applicationList->clear(); ui->libraryList->clear(); - foreach (auto p, pList) { + for (const auto &p : pList) { auto pVal = p.value(); if (pVal.isLibrary) { diff --git a/pages/pagewelcome.cpp b/pages/pagewelcome.cpp index 042595a72..3c7c67811 100755 --- a/pages/pagewelcome.cpp +++ b/pages/pagewelcome.cpp @@ -54,8 +54,8 @@ PageWelcome::PageWelcome(QWidget *parent) : QMetaObject::invokeMethod(ui->qmlWidget->rootObject(), "setupMotors"); }); - connect(ui->wizardAppButton, SIGNAL(clicked(bool)), - this, SLOT(startSetupWizardApp())); + connect(ui->wizardAppButton, qOverload(&QAbstractButton::clicked), + this, &PageWelcome::startSetupWizardApp); connect(ui->multiSettingButton, &QPushButton::clicked, [this]() { QMetaObject::invokeMethod(ui->qmlWidget->rootObject(), "openMultiSettings"); diff --git a/parametereditor.cpp b/parametereditor.cpp index c924b50db..08f5e5b17 100644 --- a/parametereditor.cpp +++ b/parametereditor.cpp @@ -85,8 +85,7 @@ ParameterEditor::ParameterEditor(QWidget *parent) : mTimer = new QTimer(this); mTimer->start(20); - connect(mTimer, SIGNAL(timeout()), - this, SLOT(timerSlot())); + connect(mTimer, &QTimer::timeout, this, &ParameterEditor::timerSlot); connect(ui->groupList, &QListWidget::currentRowChanged, [this](int row) { (void)row; diff --git a/preferences.cpp b/preferences.cpp index c91352e21..df4683ef0 100755 --- a/preferences.cpp +++ b/preferences.cpp @@ -37,8 +37,7 @@ Preferences::Preferences(QWidget *parent) : mTimer = new QTimer(this); mTimer->start(100); - connect(mTimer, SIGNAL(timeout()), - this, SLOT(timerSlot())); + connect(mTimer, &QTimer::timeout, this, &Preferences::timerSlot); ui->setupUi(this); diff --git a/res/qml/DynamicLoader.qml b/res/qml/DynamicLoader.qml index 01a6828a7..46e606402 100644 --- a/res/qml/DynamicLoader.qml +++ b/res/qml/DynamicLoader.qml @@ -21,7 +21,7 @@ import QtQuick import QtQuick.Controls import QtQuick.Layouts import QtQuick.Controls.Material -import Vedder.vesc.utility 1.0 +import Vedder.vesc Item { // Full screen iPhone X workaround: diff --git a/res/qml/Examples/BMS.qml b/res/qml/Examples/BMS.qml index d97a0b187..b41b0b4be 100644 --- a/res/qml/Examples/BMS.qml +++ b/res/qml/Examples/BMS.qml @@ -21,9 +21,8 @@ import QtQuick import QtQuick.Controls import QtQuick.Layouts import QtQuick.Controls.Material -import Vedder.vesc.utility 1.0 +import Vedder.vesc -import Vedder.vesc.commands 1.0 Item { property Commands mCommands: VescIf.commands() diff --git a/res/qml/Examples/BalanceUi.qml b/res/qml/Examples/BalanceUi.qml index 59ca09053..db0ea1534 100644 --- a/res/qml/Examples/BalanceUi.qml +++ b/res/qml/Examples/BalanceUi.qml @@ -4,9 +4,7 @@ import QtQuick import QtQuick.Controls import QtQuick.Layouts -import Vedder.vesc.commands 1.0 -import Vedder.vesc.configparams 1.0 -import Vedder.vesc.utility 1.0 +import Vedder.vesc Item { id: container diff --git a/res/qml/Examples/BrakeBench.qml b/res/qml/Examples/BrakeBench.qml index d115d3fbf..898627a6b 100644 --- a/res/qml/Examples/BrakeBench.qml +++ b/res/qml/Examples/BrakeBench.qml @@ -2,8 +2,7 @@ import QtQuick import QtQuick.Controls import QtQuick.Layouts import QtQuick.Controls.Material -import Vedder.vesc.utility 1.0 -import Vedder.vesc.commands 1.0 +import Vedder.vesc Item { id: mainItem diff --git a/res/qml/Examples/CanDebugger.qml b/res/qml/Examples/CanDebugger.qml index 409f0a2ec..25613be5e 100644 --- a/res/qml/Examples/CanDebugger.qml +++ b/res/qml/Examples/CanDebugger.qml @@ -8,10 +8,8 @@ import QtQuick import QtQuick.Controls import QtQuick.Layouts import QtQuick.Controls.Material -import Vedder.vesc.utility 1.0 +import Vedder.vesc -import Vedder.vesc.commands 1.0 -import Vedder.vesc.configparams 1.0 import "qrc:/mobile" Item { diff --git a/res/qml/Examples/ConfigParams.qml b/res/qml/Examples/ConfigParams.qml index 48be04022..d4b930037 100644 --- a/res/qml/Examples/ConfigParams.qml +++ b/res/qml/Examples/ConfigParams.qml @@ -2,8 +2,7 @@ import QtQuick import QtQuick.Controls import QtQuick.Layouts -import Vedder.vesc.commands 1.0 -import Vedder.vesc.configparams 1.0 +import Vedder.vesc Item { anchors.fill: parent diff --git a/res/qml/Examples/Controls.qml b/res/qml/Examples/Controls.qml index 37f2123e5..cd057418c 100644 --- a/res/qml/Examples/Controls.qml +++ b/res/qml/Examples/Controls.qml @@ -21,10 +21,8 @@ import QtQuick import QtQuick.Controls import QtQuick.Layouts import QtQuick.Controls.Material -import Vedder.vesc.utility 1.0 +import Vedder.vesc -import Vedder.vesc.commands 1.0 -import Vedder.vesc.configparams 1.0 Item { anchors.fill: parent diff --git a/res/qml/Examples/DCDC.qml b/res/qml/Examples/DCDC.qml index 7052fe6d6..22c88eb44 100644 --- a/res/qml/Examples/DCDC.qml +++ b/res/qml/Examples/DCDC.qml @@ -2,10 +2,8 @@ import QtQuick import QtQuick.Controls import QtQuick.Layouts import QtQuick.Controls.Material -import Vedder.vesc.utility 1.0 +import Vedder.vesc -import Vedder.vesc.commands 1.0 -import Vedder.vesc.configparams 1.0 Item { id: mainItem diff --git a/res/qml/Examples/ExperimentPlot.qml b/res/qml/Examples/ExperimentPlot.qml index 53e1fee2b..3dcde911c 100644 --- a/res/qml/Examples/ExperimentPlot.qml +++ b/res/qml/Examples/ExperimentPlot.qml @@ -2,9 +2,8 @@ import QtQuick import QtQuick.Controls import QtQuick.Layouts import QtQuick.Controls.Material -import Vedder.vesc.utility 1.0 +import Vedder.vesc -import Vedder.vesc.commands 1.0 Item { id: mainItem diff --git a/res/qml/Examples/GaugeTest.qml b/res/qml/Examples/GaugeTest.qml index 1a5877840..95f56bb80 100644 --- a/res/qml/Examples/GaugeTest.qml +++ b/res/qml/Examples/GaugeTest.qml @@ -2,10 +2,8 @@ import QtQuick import QtQuick.Controls import QtQuick.Layouts import QtQuick.Controls.Material -import Vedder.vesc.utility 1.0 +import Vedder.vesc -import Vedder.vesc.commands 1.0 -import Vedder.vesc.configparams 1.0 Item { id: mainItem diff --git a/res/qml/Examples/IoBoard.qml b/res/qml/Examples/IoBoard.qml index 5b968b572..26f680ef1 100644 --- a/res/qml/Examples/IoBoard.qml +++ b/res/qml/Examples/IoBoard.qml @@ -2,10 +2,8 @@ import QtQuick import QtQuick.Controls import QtQuick.Layouts import QtQuick.Controls.Material -import Vedder.vesc.utility 1.0 +import Vedder.vesc -import Vedder.vesc.commands 1.0 -import Vedder.vesc.configparams 1.0 Item { id: mainItem diff --git a/res/qml/Examples/LogTextToFile.qml b/res/qml/Examples/LogTextToFile.qml index 4127b4ebd..45c160039 100644 --- a/res/qml/Examples/LogTextToFile.qml +++ b/res/qml/Examples/LogTextToFile.qml @@ -2,10 +2,8 @@ import QtQuick import QtQuick.Controls import QtQuick.Layouts import QtQuick.Controls.Material -import Vedder.vesc.utility 1.0 +import Vedder.vesc -import Vedder.vesc.logwriter 1.0 -import Vedder.vesc.logreader 1.0 Item { id: mainItem diff --git a/res/qml/Examples/MMXGui.qml b/res/qml/Examples/MMXGui.qml index b0e638411..e59bb2b7d 100644 --- a/res/qml/Examples/MMXGui.qml +++ b/res/qml/Examples/MMXGui.qml @@ -2,9 +2,7 @@ import QtQuick import QtQuick.Controls import QtQuick.Layouts import QtQuick.Controls.Material -import Vedder.vesc.utility 1.0 -import Vedder.vesc.commands 1.0 -import Vedder.vesc.configparams 1.0 +import Vedder.vesc Item { id: topComponent diff --git a/res/qml/Examples/Meters.qml b/res/qml/Examples/Meters.qml index c8d1762fd..6dcfbfe29 100644 --- a/res/qml/Examples/Meters.qml +++ b/res/qml/Examples/Meters.qml @@ -21,10 +21,8 @@ import QtQuick import QtQuick.Controls import QtQuick.Layouts import QtQuick.Controls.Material -import Vedder.vesc.utility 1.0 +import Vedder.vesc -import Vedder.vesc.commands 1.0 -import Vedder.vesc.configparams 1.0 import "qrc:/mobile" Item { diff --git a/res/qml/Examples/MotorComparisonModel.qml b/res/qml/Examples/MotorComparisonModel.qml index c3d424c69..a5bf41693 100644 --- a/res/qml/Examples/MotorComparisonModel.qml +++ b/res/qml/Examples/MotorComparisonModel.qml @@ -5,7 +5,7 @@ import QtQuick import QtQuick.Controls import QtQuick.Layouts import QtQuick.Controls.Material -import Vedder.vesc.utility 1.0 +import Vedder.vesc Item { id: mainItem diff --git a/res/qml/Examples/Mp3Stream.qml b/res/qml/Examples/Mp3Stream.qml index 1fb51acc2..292f8d7be 100644 --- a/res/qml/Examples/Mp3Stream.qml +++ b/res/qml/Examples/Mp3Stream.qml @@ -3,9 +3,7 @@ import QtQuick.Controls import QtQuick.Layouts import QtQuick.Controls.Material -import Vedder.vesc.commands 1.0 -import Vedder.vesc.utility 1.0 -import Vedder.vesc.qminimp3 1.0 +import Vedder.vesc Item { id: mainItem diff --git a/res/qml/Examples/ParamTableAndPlot.qml b/res/qml/Examples/ParamTableAndPlot.qml index 2a1b42ae9..eb063affb 100644 --- a/res/qml/Examples/ParamTableAndPlot.qml +++ b/res/qml/Examples/ParamTableAndPlot.qml @@ -1,9 +1,7 @@ import QtQuick import QtQuick.Controls import QtQuick.Layouts -import Vedder.vesc.utility 1.0 -import Vedder.vesc.commands 1.0 -import Vedder.vesc.configparams 1.0 +import Vedder.vesc Item { id: topItem diff --git a/res/qml/Examples/ParentTabBar.qml b/res/qml/Examples/ParentTabBar.qml index 47bc4e986..fdf8f6aaa 100644 --- a/res/qml/Examples/ParentTabBar.qml +++ b/res/qml/Examples/ParentTabBar.qml @@ -9,7 +9,7 @@ import QtQuick import QtQuick.Controls import QtQuick.Layouts import QtQuick.Controls.Material -import Vedder.vesc.utility 1.0 +import Vedder.vesc Item { id: mainItem diff --git a/res/qml/Examples/PollValues.qml b/res/qml/Examples/PollValues.qml index de730e004..aa1ee1f73 100644 --- a/res/qml/Examples/PollValues.qml +++ b/res/qml/Examples/PollValues.qml @@ -2,9 +2,7 @@ import QtQuick import QtQuick.Controls import QtQuick.Layouts import QtQuick.Controls.Material -import Vedder.vesc.utility 1.0 -import Vedder.vesc.commands 1.0 -import Vedder.vesc.configparams 1.0 +import Vedder.vesc Item { anchors.fill: parent diff --git a/res/qml/Examples/PositionControl.qml b/res/qml/Examples/PositionControl.qml index a19c5a0b6..c898efa8a 100644 --- a/res/qml/Examples/PositionControl.qml +++ b/res/qml/Examples/PositionControl.qml @@ -22,8 +22,7 @@ import QtQuick.Controls import QtQuick.Layouts import QtQuick.Controls.Material -import Vedder.vesc.commands 1.0 -import Vedder.vesc.configparams 1.0 +import Vedder.vesc Item { anchors.fill: parent diff --git a/res/qml/Examples/Profiles.qml b/res/qml/Examples/Profiles.qml index ffbe8ad0e..a26b584c1 100644 --- a/res/qml/Examples/Profiles.qml +++ b/res/qml/Examples/Profiles.qml @@ -21,7 +21,7 @@ import QtQuick import QtQuick.Controls import QtQuick.Layouts import QtQuick.Controls.Material -import Vedder.vesc.utility 1.0 +import Vedder.vesc Item { anchors.fill: parent diff --git a/res/qml/Examples/Reconnect.qml b/res/qml/Examples/Reconnect.qml index e20cdb523..101f03636 100644 --- a/res/qml/Examples/Reconnect.qml +++ b/res/qml/Examples/Reconnect.qml @@ -6,9 +6,7 @@ import QtQuick import QtQuick.Controls import QtQuick.Layouts import QtQuick.Controls.Material -import Vedder.vesc.utility 1.0 -import Vedder.vesc.commands 1.0 -import Vedder.vesc.configparams 1.0 +import Vedder.vesc import "qrc:/mobile" Item { diff --git a/res/qml/Examples/RpmSlider.qml b/res/qml/Examples/RpmSlider.qml index 599e10fff..b79fd583c 100644 --- a/res/qml/Examples/RpmSlider.qml +++ b/res/qml/Examples/RpmSlider.qml @@ -21,10 +21,8 @@ import QtQuick import QtQuick.Controls import QtQuick.Layouts import QtQuick.Controls.Material -import Vedder.vesc.utility 1.0 +import Vedder.vesc -import Vedder.vesc.commands 1.0 -import Vedder.vesc.configparams 1.0 import "qrc:/mobile" Item { diff --git a/res/qml/Examples/RtData.qml b/res/qml/Examples/RtData.qml index ea836e338..0df04175f 100644 --- a/res/qml/Examples/RtData.qml +++ b/res/qml/Examples/RtData.qml @@ -21,9 +21,7 @@ import QtQuick import QtQuick.Controls import QtQuick.Layouts import QtQuick.Controls.Material -import Vedder.vesc.utility 1.0 -import Vedder.vesc.commands 1.0 -import Vedder.vesc.configparams 1.0 +import Vedder.vesc import "qrc:/mobile" Item { diff --git a/res/qml/Examples/RtDataSetup.qml b/res/qml/Examples/RtDataSetup.qml index ca8898aa4..0b39ec58c 100644 --- a/res/qml/Examples/RtDataSetup.qml +++ b/res/qml/Examples/RtDataSetup.qml @@ -23,10 +23,7 @@ import QtQuick.Layouts import Qt5Compat.GraphicalEffects import QtQuick.Controls.Material -import Vedder.vesc.vescinterface 1.0 -import Vedder.vesc.utility 1.0 -import Vedder.vesc.commands 1.0 -import Vedder.vesc.configparams 1.0 +import Vedder.vesc Item { id: rtData diff --git a/res/qml/Examples/SendToLbm.qml b/res/qml/Examples/SendToLbm.qml index 9ea7b1c81..26f2f48a9 100644 --- a/res/qml/Examples/SendToLbm.qml +++ b/res/qml/Examples/SendToLbm.qml @@ -1,9 +1,8 @@ import QtQuick import QtQuick.Controls import QtQuick.Layouts -import Vedder.vesc.utility 1.0 +import Vedder.vesc -import Vedder.vesc.commands 1.0 Item { id: mainItem diff --git a/res/qml/Examples/TcpHub.qml b/res/qml/Examples/TcpHub.qml index f4949572f..7a0dfbc9b 100644 --- a/res/qml/Examples/TcpHub.qml +++ b/res/qml/Examples/TcpHub.qml @@ -2,11 +2,8 @@ import QtQuick import QtQuick.Controls import QtQuick.Layouts import QtQuick.Controls.Material -import Vedder.vesc.utility 1.0 +import Vedder.vesc -import Vedder.vesc.commands 1.0 -import Vedder.vesc.configparams 1.0 -import Vedder.vesc.tcphub 1.0 Item { id: mainItem diff --git a/res/qml/Examples/TcpServer.qml b/res/qml/Examples/TcpServer.qml index 30e7bffaa..76fbaf60c 100644 --- a/res/qml/Examples/TcpServer.qml +++ b/res/qml/Examples/TcpServer.qml @@ -2,10 +2,7 @@ import QtQuick import QtQuick.Controls import QtQuick.Layouts import QtQuick.Controls.Material -import Vedder.vesc.utility 1.0 -import Vedder.vesc.commands 1.0 -import Vedder.vesc.configparams 1.0 -import Vedder.vesc.tcpserversimple 1.0 +import Vedder.vesc Item { anchors.fill: parent diff --git a/res/qml/Examples/UdpServer.qml b/res/qml/Examples/UdpServer.qml index 8af0ffbbe..31abe1f09 100644 --- a/res/qml/Examples/UdpServer.qml +++ b/res/qml/Examples/UdpServer.qml @@ -1,7 +1,7 @@ import QtQuick import QtQuick.Controls import QtQuick.Layouts -import Vedder.vesc.udpserversimple 1.0 +import Vedder.vesc Item { anchors.fill: parent diff --git a/res/qml/MainLoader.qml b/res/qml/MainLoader.qml index 9befce5f2..55dac7d0e 100644 --- a/res/qml/MainLoader.qml +++ b/res/qml/MainLoader.qml @@ -22,7 +22,7 @@ import QtQuick.Controls import QtQuick.Layouts import QtQuick.Controls.Material import QtQuick.Window -import Vedder.vesc.utility 1.0 +import Vedder.vesc ApplicationWindow { id: mainWindow diff --git a/res/qml/SetupMotorWindow.qml b/res/qml/SetupMotorWindow.qml index 51d1cb0a2..5bae2928d 100644 --- a/res/qml/SetupMotorWindow.qml +++ b/res/qml/SetupMotorWindow.qml @@ -23,7 +23,7 @@ import QtQuick.Layouts import QtQuick.Controls.Material import QtQuick.Window -import Vedder.vesc.utility 1.0 +import Vedder.vesc import "qrc:/mobile" ApplicationWindow { diff --git a/res/qml/WelcomeQmlPanel.qml b/res/qml/WelcomeQmlPanel.qml index 88084f4a7..f22db7bbb 100644 --- a/res/qml/WelcomeQmlPanel.qml +++ b/res/qml/WelcomeQmlPanel.qml @@ -23,7 +23,7 @@ import QtQuick.Layouts import QtQuick.Controls.Material import QtQuick.Window -import Vedder.vesc.utility 1.0 +import Vedder.vesc import "qrc:/mobile" diff --git a/setupwizardapp.cpp b/setupwizardapp.cpp index addb9c147..013115cb0 100644 --- a/setupwizardapp.cpp +++ b/setupwizardapp.cpp @@ -56,10 +56,10 @@ SetupWizardApp::SetupWizardApp(VescInterface *vesc, QWidget *parent) mSideLabel->setScaledContents(true); setSideWidget(mSideLabel); - connect(this, SIGNAL(currentIdChanged(int)), - this, SLOT(idChanged(int))); - connect(this, SIGNAL(rejected()), this, SLOT(ended())); - connect(this, SIGNAL(accepted()), this, SLOT(ended())); + connect(this, &QWizard::currentIdChanged, + this, &SetupWizardApp::idChanged); + connect(this, &QWizard::rejected, this, &SetupWizardApp::ended); + connect(this, &QWizard::accepted, this, &SetupWizardApp::ended); } void SetupWizardApp::idChanged(int id) @@ -165,8 +165,8 @@ AppConnectionPage::AppConnectionPage(VescInterface *vesc, QWidget *parent) mPageConnection = new PageConnection; mPageConnection->setVesc(mVesc); - connect(mVesc, SIGNAL(fwRxChanged(bool,bool)), - this, SIGNAL(completeChanged())); + connect(mVesc, &VescInterface::fwRxChanged, + this, &AppConnectionPage::completeChanged); QVBoxLayout *layout = new QVBoxLayout; layout->addWidget(mPageConnection); @@ -228,8 +228,8 @@ AppMultiPage::AppMultiPage(VescInterface *vesc, QWidget *parent) mCanFwdList->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); registerField("CanFwd", this, "canFwd", SIGNAL(canFwdChanged)); - connect(mCanFwdList, SIGNAL(currentRowChanged(int)), - this, SIGNAL(canFwdChanged())); + connect(mCanFwdList, &QListWidget::currentRowChanged, + this, &AppMultiPage::canFwdChanged); QVBoxLayout *layout = new QVBoxLayout; layout->addWidget(mCanFwdList); @@ -291,7 +291,7 @@ bool AppMultiPage::validatePage() } mVesc->commands()->getAppConf(); - Utility::waitSignal(mVesc->appConfig(), SIGNAL(updated()), 2000); + Utility::waitSignal(mVesc->appConfig(), &ConfigParams::updated, 2000); return true; } @@ -348,8 +348,8 @@ AppGeneralPage::AppGeneralPage(VescInterface *vesc, QWidget *parent) mInputList->setCurrentItem(nullptr); registerField("Input", this, "inputType", SIGNAL(inputTypeChanged)); - connect(mInputList, SIGNAL(currentRowChanged(int)), - this, SIGNAL(inputTypeChanged())); + connect(mInputList, &QListWidget::currentRowChanged, + this, &AppGeneralPage::inputTypeChanged); QVBoxLayout *layout = new QVBoxLayout; layout->addWidget(mInputList); @@ -422,11 +422,11 @@ AppNunchukPage::AppNunchukPage(VescInterface *vesc, QWidget *parent) layout->addWidget(mNrfPair); setLayout(layout); - connect(mVesc->commands(), SIGNAL(decodedChukReceived(double)), - this, SLOT(decodedChukReceived(double))); - connect(mTimer, SIGNAL(timeout()), this, SLOT(timerSlot())); - connect(mWriteButton, SIGNAL(clicked(bool)), - mVesc->commands(), SLOT(setAppConf())); + connect(mVesc->commands(), &Commands::decodedChukReceived, + this, &AppNunchukPage::decodedChukReceived); + connect(mTimer, &QTimer::timeout, this, &AppNunchukPage::timerSlot); + connect(mWriteButton, qOverload(&QPushButton::clicked), + mVesc->commands(), &Commands::setAppConf); } int AppNunchukPage::nextId() const @@ -463,20 +463,20 @@ void AppNunchukPage::initializePage() mNrfPair->setVisible(false); mVesc->appConfig()->updateParamEnum("app_to_use", 6); mVesc->commands()->setAppConf(); - Utility::waitSignal(mVesc->commands(), SIGNAL(ackReceived(QString)), 2000); + Utility::waitSignal(mVesc->commands(), &Commands::ackReceived, 2000); // TODO: Figure out why setting the conf twice is required... mVesc->commands()->setAppConf(); - Utility::waitSignal(mVesc->commands(), SIGNAL(ackReceived(QString)), 2000); + Utility::waitSignal(mVesc->commands(), &Commands::ackReceived, 2000); } else { setSubTitle(tr("Pair and configure your NRF nunchuk.")); mNrfPair->setVisible(true); // mVesc->appConfig()->updateParamEnum("app_to_use", 7); mVesc->appConfig()->updateParamEnum("app_to_use", 3); // Assume permanent NRF or NRF51 on UART mVesc->commands()->setAppConf(); - Utility::waitSignal(mVesc->commands(), SIGNAL(ackReceived(QString)), 2000); + Utility::waitSignal(mVesc->commands(), &Commands::ackReceived, 2000); // TODO: Figure out why setting the conf twice is required... mVesc->commands()->setAppConf(); - Utility::waitSignal(mVesc->commands(), SIGNAL(ackReceived(QString)), 2000); + Utility::waitSignal(mVesc->commands(), &Commands::ackReceived, 2000); QMessageBox::information(this, tr("NRF Pairing"), @@ -530,9 +530,9 @@ AppPpmMapPage::AppPpmMapPage(VescInterface *vesc, QWidget *parent) layout->addWidget(mPpmMap); setLayout(layout); - connect(mTimer, SIGNAL(timeout()), this, SLOT(timerSlot())); - connect(mVesc->appConfig(), SIGNAL(paramChangedDouble(QObject*,QString,double)), - this, SLOT(paramChangedDouble(QObject*,QString,double))); + connect(mTimer, &QTimer::timeout, this, &AppPpmMapPage::timerSlot); + connect(mVesc->appConfig(), &ConfigParams::paramChangedDouble, + this, &AppPpmMapPage::paramChangedDouble); } int AppPpmMapPage::nextId() const @@ -558,10 +558,10 @@ void AppPpmMapPage::initializePage() mVesc->appConfig()->updateParamEnum("app_ppm_conf.ctrl_type", 0); mVesc->appConfig()->updateParamEnum("app_to_use", 4); mVesc->commands()->setAppConf(); - Utility::waitSignal(mVesc->commands(), SIGNAL(ackReceived(QString)), 2000); + Utility::waitSignal(mVesc->commands(), &Commands::ackReceived, 2000); // TODO: Figure out why setting the conf twice is required... mVesc->commands()->setAppConf(); - Utility::waitSignal(mVesc->commands(), SIGNAL(ackReceived(QString)), 2000); + Utility::waitSignal(mVesc->commands(), &Commands::ackReceived, 2000); mTimer->start(40); } @@ -601,8 +601,8 @@ AppPpmPage::AppPpmPage(VescInterface *vesc, QWidget *parent) layout->addWidget(mWriteButton); setLayout(layout); - connect(mWriteButton, SIGNAL(clicked(bool)), - mVesc->commands(), SLOT(setAppConf())); + connect(mWriteButton, qOverload(&QPushButton::clicked), + mVesc->commands(), &Commands::setAppConf); } int AppPpmPage::nextId() const @@ -659,11 +659,11 @@ AppAdcMapPage::AppAdcMapPage(VescInterface *vesc, QWidget *parent) layout->addWidget(mAdcMap); setLayout(layout); - connect(mTimer, SIGNAL(timeout()), this, SLOT(timerSlot())); - connect(mVesc->appConfig(), SIGNAL(paramChangedDouble(QObject*,QString,double)), - this, SLOT(paramChangedDouble(QObject*,QString,double))); - connect(mVesc->appConfig(), SIGNAL(paramChangedBool(QObject*,QString,bool)), - this, SLOT(paramChangedBool(QObject*,QString,bool))); + connect(mTimer, &QTimer::timeout, this, &AppAdcMapPage::timerSlot); + connect(mVesc->appConfig(), &ConfigParams::paramChangedDouble, + this, &AppAdcMapPage::paramChangedDouble); + connect(mVesc->appConfig(), &ConfigParams::paramChangedBool, + this, &AppAdcMapPage::paramChangedBool); } int AppAdcMapPage::nextId() const @@ -693,10 +693,10 @@ void AppAdcMapPage::initializePage() mVesc->appConfig()->updateParamEnum("app_to_use", 5); mVesc->appConfig()->updateParamEnum("app_adc_conf.ctrl_type", 0); mVesc->commands()->setAppConf(); - Utility::waitSignal(mVesc->commands(), SIGNAL(ackReceived(QString)), 2000); + Utility::waitSignal(mVesc->commands(), &Commands::ackReceived, 2000); // TODO: Figure out why setting the conf twice is required... mVesc->commands()->setAppConf(); - Utility::waitSignal(mVesc->commands(), SIGNAL(ackReceived(QString)), 2000); + Utility::waitSignal(mVesc->commands(), &Commands::ackReceived, 2000); mTimer->start(40); } @@ -749,8 +749,8 @@ AppAdcPage::AppAdcPage(VescInterface *vesc, QWidget *parent) layout->addWidget(mWriteButton); setLayout(layout); - connect(mWriteButton, SIGNAL(clicked(bool)), - mVesc->commands(), SLOT(setAppConf())); + connect(mWriteButton, qOverload(&QPushButton::clicked), + mVesc->commands(), &Commands::setAppConf); } int AppAdcPage::nextId() const diff --git a/setupwizardmotor.cpp b/setupwizardmotor.cpp index bb5328313..d688e8d1b 100644 --- a/setupwizardmotor.cpp +++ b/setupwizardmotor.cpp @@ -52,8 +52,8 @@ SetupWizardMotor::SetupWizardMotor(VescInterface *vesc, QWidget *parent) mSideLabel->setScaledContents(true); setSideWidget(mSideLabel); - connect(this, SIGNAL(currentIdChanged(int)), - this, SLOT(idChanged(int))); + connect(this, &QWizard::currentIdChanged, + this, &SetupWizardMotor::idChanged); } void SetupWizardMotor::idChanged(int id) @@ -139,8 +139,8 @@ ConnectionPage::ConnectionPage(VescInterface *vesc, QWidget *parent) mPageConnection = new PageConnection; mPageConnection->setVesc(mVesc); - connect(mVesc, SIGNAL(fwRxChanged(bool,bool)), - this, SIGNAL(completeChanged())); + connect(mVesc, &VescInterface::fwRxChanged, + this, &ConnectionPage::completeChanged); QVBoxLayout *layout = new QVBoxLayout; layout->addWidget(mPageConnection); @@ -173,8 +173,8 @@ FirmwarePage::FirmwarePage(VescInterface *vesc, QWidget *parent) mPageFirmware = new PageFirmware; mPageFirmware->setVesc(mVesc); - connect(mVesc, SIGNAL(portConnectedChanged()), - this, SIGNAL(completeChanged())); + connect(mVesc, &VescInterface::portConnectedChanged, + this, &FirmwarePage::completeChanged); QVBoxLayout *layout = new QVBoxLayout; layout->addWidget(mPageFirmware); @@ -380,8 +380,8 @@ SensorsPage::SensorsPage(VescInterface *vesc, QWidget *parent) layout->addWidget(mParamTab); setLayout(layout); - connect(mSensorMode, SIGNAL(currentIndexChanged(int)), - this, SLOT(indexChanged(int))); + connect(mSensorMode, &QComboBox::currentIndexChanged, + this, &SensorsPage::indexChanged); indexChanged(0); } diff --git a/startupwizard.cpp b/startupwizard.cpp index 0dd5516a3..ab4262618 100644 --- a/startupwizard.cpp +++ b/startupwizard.cpp @@ -48,8 +48,8 @@ StartupWizard::StartupWizard(VescInterface *vesc, QWidget *parent) mSideLabel->setScaledContents(true); setSideWidget(mSideLabel); - connect(this, SIGNAL(currentIdChanged(int)), - this, SLOT(idChanged(int))); + connect(this, &StartupWizard::currentIdChanged, + this, &StartupWizard::idChanged); } void StartupWizard::idChanged(int id) @@ -107,10 +107,10 @@ StartupUsagePage::StartupUsagePage(VescInterface *vesc, QWidget *parent) registerField("usageAccept*", mAcceptBox); - connect(mBrowser->verticalScrollBar(), SIGNAL(valueChanged(int)), - this, SLOT(scrollValueChanged(int))); - connect(mBrowser->verticalScrollBar(), SIGNAL(rangeChanged(int,int)), - this, SLOT(scrollRangeChanged())); + connect(mBrowser->verticalScrollBar(), &QScrollBar::valueChanged, + this, &StartupUsagePage::scrollValueChanged); + connect(mBrowser->verticalScrollBar(), &QScrollBar::rangeChanged, + this, &StartupUsagePage::scrollRangeChanged); QVBoxLayout *layout = new QVBoxLayout; layout->addWidget(mBrowser); @@ -157,10 +157,10 @@ StartupWarrantyPage::StartupWarrantyPage(VescInterface *vesc, QWidget *parent) registerField("warrantyAccept*", mAcceptBox); - connect(mBrowser->verticalScrollBar(), SIGNAL(valueChanged(int)), - this, SLOT(scrollValueChanged(int))); - connect(mBrowser->verticalScrollBar(), SIGNAL(rangeChanged(int,int)), - this, SLOT(scrollRangeChanged())); + connect(mBrowser->verticalScrollBar(), &QScrollBar::valueChanged, + this, &StartupWarrantyPage::scrollValueChanged); + connect(mBrowser->verticalScrollBar(), &QScrollBar::rangeChanged, + this, &StartupWarrantyPage::scrollRangeChanged); QVBoxLayout *layout = new QVBoxLayout; layout->addWidget(mBrowser); diff --git a/systemcommandexecutor.h b/systemcommandexecutor.h index ec0e5dfd9..1ec82e5dc 100644 --- a/systemcommandexecutor.h +++ b/systemcommandexecutor.h @@ -5,10 +5,12 @@ #include #include #include +#include class SystemCommandExecutor : public QObject { Q_OBJECT + QML_NAMED_ELEMENT(SysCmd) public: explicit SystemCommandExecutor(QObject *parent = nullptr) : QObject(parent) {} diff --git a/tcphub.cpp b/tcphub.cpp index 5297da45f..ba44b3038 100644 --- a/tcphub.cpp +++ b/tcphub.cpp @@ -29,7 +29,7 @@ TcpHub::TcpHub(QObject *parent) : QObject{parent} { mTcpHubServer = new QTcpServer(this); - connect(mTcpHubServer, SIGNAL(newConnection()), this, SLOT(newTcpHubConnection())); + connect(mTcpHubServer, &QTcpServer::newConnection, this, &TcpHub::newTcpHubConnection); } TcpHub::~TcpHub() @@ -66,7 +66,7 @@ bool TcpHub::ping(QString server, int port, QString uuid) QTcpSocket socket; socket.connectToHost(host, port); - if (!Utility::waitSignal(&socket, SIGNAL(connected()), 1000)) { + if (!Utility::waitSignal(&socket, &QTcpSocket::connected, 1000)) { return false; } diff --git a/tcphub.h b/tcphub.h index d7d75c6bb..bf130bc49 100644 --- a/tcphub.h +++ b/tcphub.h @@ -26,6 +26,7 @@ #include #include #include +#include /* * - VESC connects to Server (HUB) and gets registered. @@ -67,6 +68,7 @@ struct TcpConnectedVesc class TcpHub : public QObject { Q_OBJECT + QML_ELEMENT public: explicit TcpHub(QObject *parent = nullptr); ~TcpHub(); diff --git a/tcpserversimple.cpp b/tcpserversimple.cpp index fc0a03d9b..f08816517 100644 --- a/tcpserversimple.cpp +++ b/tcpserversimple.cpp @@ -31,9 +31,8 @@ TcpServerSimple::TcpServerSimple(QObject *parent) : QObject(parent) mUsePacket = false; mLastPort = -1; - connect(mTcpServer, SIGNAL(newConnection()), this, SLOT(newTcpConnection())); - connect(mPacket, SIGNAL(dataToSend(QByteArray&)), - this, SLOT(dataToSend(QByteArray&))); + connect(mTcpServer, &QTcpServer::newConnection, this, &TcpServerSimple::newTcpConnection); + connect(mPacket, &Packet::dataToSend, this, &TcpServerSimple::dataToSend); } bool TcpServerSimple::startServer(int port, QHostAddress addr) @@ -65,7 +64,7 @@ bool TcpServerSimple::connectToHub(QString server, int port, QString id, QString QTimer timeoutTimer; timeoutTimer.setSingleShot(true); timeoutTimer.start(3000); - auto conn = QObject::connect(&timeoutTimer, SIGNAL(timeout()), &loop, SLOT(quit())); + auto conn = QObject::connect(&timeoutTimer, &QTimer::timeout, &loop, &QEventLoop::quit); connect(mTcpSocket, &QTcpSocket::connected, [&id, &pass, this, &loop]() { QString login = QString("VESC:%1:%2\n").arg(id).arg(pass); @@ -77,9 +76,8 @@ bool TcpServerSimple::connectToHub(QString server, int port, QString id, QString disconnect(conn); if (timeoutTimer.isActive()) { - connect(mTcpSocket, SIGNAL(readyRead()), this, SLOT(tcpInputDataAvailable())); - connect(mTcpSocket, SIGNAL(disconnected()), - this, SLOT(tcpInputDisconnected())); + connect(mTcpSocket, &QIODevice::readyRead, this, &TcpServerSimple::tcpInputDataAvailable); + connect(mTcpSocket, &QAbstractSocket::disconnected, this, &TcpServerSimple::tcpInputDisconnected); connect(mTcpSocket, &QAbstractSocket::errorOccurred, this, &TcpServerSimple::tcpInputError); emit connectionChanged(true, mTcpSocket->peerAddress().toString()); @@ -138,9 +136,8 @@ void TcpServerSimple::newTcpConnection() mTcpSocket = socket; if (mTcpSocket) { - connect(mTcpSocket, SIGNAL(readyRead()), this, SLOT(tcpInputDataAvailable())); - connect(mTcpSocket, SIGNAL(disconnected()), - this, SLOT(tcpInputDisconnected())); + connect(mTcpSocket, &QIODevice::readyRead, this, &TcpServerSimple::tcpInputDataAvailable); + connect(mTcpSocket, &QAbstractSocket::disconnected, this, &TcpServerSimple::tcpInputDisconnected); connect(mTcpSocket, &QAbstractSocket::errorOccurred, this, &TcpServerSimple::tcpInputError); emit connectionChanged(true, mTcpSocket->peerAddress().toString()); @@ -174,7 +171,7 @@ void TcpServerSimple::tcpInputError(QAbstractSocket::SocketError socketError) qDebug() << socketError; } -void TcpServerSimple::dataToSend(QByteArray &data) +void TcpServerSimple::dataToSend(const QByteArray &data) { sendData(data); } diff --git a/tcpserversimple.h b/tcpserversimple.h index f51d4ca1e..6fb33ecbb 100644 --- a/tcpserversimple.h +++ b/tcpserversimple.h @@ -23,11 +23,13 @@ #include #include #include +#include #include "packet.h" class TcpServerSimple : public QObject { Q_OBJECT + QML_ELEMENT public: explicit TcpServerSimple(QObject *parent = nullptr); Q_INVOKABLE bool startServer(int port, QHostAddress addr = QHostAddress::Any); @@ -52,7 +54,7 @@ public slots: void tcpInputDisconnected(); void tcpInputDataAvailable(); void tcpInputError(QAbstractSocket::SocketError socketError); - void dataToSend(QByteArray &data); + void dataToSend(const QByteArray &data); private: QTcpServer *mTcpServer; diff --git a/udpserversimple.cpp b/udpserversimple.cpp index 17a3a2a1a..41ef5aa2e 100644 --- a/udpserversimple.cpp +++ b/udpserversimple.cpp @@ -27,8 +27,7 @@ UdpServerSimple::UdpServerSimple(QObject *parent) : QObject(parent) mPacket = new Packet(this); mUsePacket = false; - connect(mPacket, SIGNAL(dataToSend(QByteArray&)), - this, SLOT(dataToSend(QByteArray&))); + connect(mPacket, &Packet::dataToSend, this, &UdpServerSimple::dataToSend); connect(mUdpSocket, &QUdpSocket::readyRead, this, &UdpServerSimple::udpInputDataAvailable); } @@ -87,7 +86,7 @@ void UdpServerSimple::udpInputDataAvailable() } } -void UdpServerSimple::dataToSend(QByteArray &data) +void UdpServerSimple::dataToSend(const QByteArray &data) { sendData(data); } diff --git a/udpserversimple.h b/udpserversimple.h index d95b145c0..dd00a2807 100644 --- a/udpserversimple.h +++ b/udpserversimple.h @@ -22,11 +22,13 @@ #include #include +#include #include "packet.h" class UdpServerSimple : public QObject { Q_OBJECT + QML_ELEMENT public: explicit UdpServerSimple(QObject *parent = nullptr); Q_INVOKABLE bool startServer(int port, QHostAddress addr = QHostAddress::Any); @@ -47,7 +49,7 @@ class UdpServerSimple : public QObject public slots: void udpInputDataAvailable(); - void dataToSend(QByteArray &data); + void dataToSend(const QByteArray &data); private: QUdpSocket *mUdpSocket; diff --git a/utility.cpp b/utility.cpp index a034a26ac..7874e7c54 100755 --- a/utility.cpp +++ b/utility.cpp @@ -179,7 +179,7 @@ void Utility::checkVersion(VescInterface *vesc) QNetworkRequest request(url); QNetworkReply *reply = manager.get(request); QEventLoop loop; - QObject::connect(reply, SIGNAL(finished()), &loop, SLOT(quit())); + QObject::connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit); loop.exec(); QString res = QString::fromUtf8(reply->readAll()); @@ -393,7 +393,7 @@ bool Utility::waitSignal(QObject *sender, QString signal, int timeoutMs) timeoutTimer.setSingleShot(true); timeoutTimer.start(timeoutMs); auto conn1 = QObject::connect(sender, signal.toLocal8Bit().data(), &loop, SLOT(quit())); - auto conn2 = QObject::connect(&timeoutTimer, SIGNAL(timeout()), &loop, SLOT(quit())); + auto conn2 = QObject::connect(&timeoutTimer, &QTimer::timeout, &loop, &QEventLoop::quit); loop.exec(); QObject::disconnect(conn1); @@ -408,7 +408,7 @@ void Utility::sleepWithEventLoop(int timeMs) QTimer timeoutTimer; timeoutTimer.setSingleShot(true); timeoutTimer.start(timeMs); - auto conn1 = QObject::connect(&timeoutTimer, SIGNAL(timeout()), &loop, SLOT(quit())); + auto conn1 = QObject::connect(&timeoutTimer, &QTimer::timeout, &loop, &QEventLoop::quit); loop.exec(); QObject::disconnect(conn1); } @@ -427,7 +427,7 @@ bool Utility::canUpdateBaudAllBlocking(VescInterface *vesc, int newBaud) } }); - bool signalRx = waitSignal(vesc->commands(), SIGNAL(canUpdateBaudRx(bool)), 4000); + bool signalRx = waitSignal(vesc->commands(), &Commands::canUpdateBaudRx, 4000); disconnect(conn); if (!signalRx) { @@ -473,7 +473,7 @@ QString Utility::detectAllFoc(VescInterface *vesc, } }); - connect(&timeoutTimer, SIGNAL(timeout()), &loop, SLOT(quit())); + connect(&timeoutTimer, &QTimer::timeout, &loop, &QEventLoop::quit); loop.exec(); disconnect(conn); @@ -486,7 +486,7 @@ QString Utility::detectAllFoc(VescInterface *vesc, // MCConf should have been sent after the detection vesc->commands()->getAppConf(); - waitSignal(ap, SIGNAL(updated()), 4000); + waitSignal(ap, &ConfigParams::updated, 4000); auto genRes = [&p, &ap]() { QString sensors; @@ -542,18 +542,18 @@ QString Utility::detectAllFoc(VescInterface *vesc, } vesc->commands()->getMcconf(); - waitSignal(p, SIGNAL(updated()), 4000); + waitSignal(p, &ConfigParams::updated, 4000); vesc->commands()->getAppConf(); - waitSignal(ap, SIGNAL(updated()), 4000); + waitSignal(ap, &ConfigParams::updated, 4000); res += "\n\n" + genRes(); } vesc->commands()->setSendCan(canLastFwd, canLastId); vesc->ignoreCanChange(false); vesc->commands()->getMcconf(); - waitSignal(p, SIGNAL(updated()), 4000); + waitSignal(p, &ConfigParams::updated, 4000); vesc->commands()->getAppConf(); - waitSignal(ap, SIGNAL(updated()), 4000); + waitSignal(ap, &ConfigParams::updated, 4000); } else { QString reason; switch (resDetect) { @@ -627,7 +627,7 @@ QVector Utility::measureRLBlocking(VescInterface *vesc) res.append(ld_lq_diff); }); - waitSignal(vesc->commands(), SIGNAL(motorRLReceived(double, double, double)), 8000); + waitSignal(vesc->commands(), &Commands::motorRLReceived, 8000); disconnect(conn); return res; @@ -644,7 +644,7 @@ double Utility::measureLinkageOpenloopBlocking(VescInterface *vesc, double curre res = flux_linkage; }); - waitSignal(vesc->commands(), SIGNAL(motorLinkageReceived(double)), 12000); + waitSignal(vesc->commands(), &Commands::motorLinkageReceived, 12000); disconnect(conn); return res; @@ -661,7 +661,7 @@ QVector Utility::measureHallFocBlocking(VescInterface *vesc, double current resDetect.append(hall_table); }); - bool rx = waitSignal(vesc->commands(), SIGNAL(focHallTableReceived(QVector, int)), 25000); + bool rx = waitSignal(vesc->commands(), &Commands::focHallTableReceived, 25000); disconnect(conn); if (!rx) { @@ -681,7 +681,7 @@ ENCODER_DETECT_RES Utility::measureEncoderBlocking(VescInterface *vesc, double c resDetect = res; }); - waitSignal(vesc->commands(), SIGNAL(encoderParamReceived(ENCODER_DETECT_RES)), 50000); + waitSignal(vesc->commands(), &Commands::encoderParamReceived, 50000); disconnect(conn); return resDetect; @@ -726,7 +726,7 @@ bool Utility::resetInputCan(VescInterface *vesc, QVector canIds) } vesc->commands()->getAppConf(); - res = waitSignal(ap, SIGNAL(updated()), 4000); + res = waitSignal(ap, &ConfigParams::updated, 4000); if (!res) { qWarning() << "Appconf not received"; @@ -746,7 +746,7 @@ bool Utility::resetInputCan(VescInterface *vesc, QVector canIds) } vesc->commands()->getAppConfDefault(); - res = waitSignal(ap, SIGNAL(updated()), 4000); + res = waitSignal(ap, &ConfigParams::updated, 4000); if (!res) { qWarning() << "Default appconf not received"; @@ -762,7 +762,7 @@ bool Utility::resetInputCan(VescInterface *vesc, QVector canIds) } vesc->commands()->setAppConf(); - res = waitSignal(vesc->commands(), SIGNAL(ackReceived(QString)), 4000); + res = waitSignal(vesc->commands(), &Commands::ackReceived, 4000); if (!res) { qWarning() << "Appconf set no ack received"; @@ -794,7 +794,7 @@ bool Utility::resetInputCan(VescInterface *vesc, QVector canIds) if (isConnectedToHwVesc(vesc)) { vesc->commands()->getAppConf(); ConfigParams *ap = vesc->appConfig(); - if (!waitSignal(ap, SIGNAL(updated()), 4000)) { + if (!waitSignal(ap, &ConfigParams::updated, 4000)) { qWarning() << "Appconf not received"; res = false; } @@ -889,7 +889,7 @@ bool Utility::setMcParamsFromCurrentConfigAllCan(VescInterface *vesc, QVectorcommands()->getMcconf(); - if (!waitSignal(config, SIGNAL(updated()), 4000)) { + if (!waitSignal(config, &ConfigParams::updated, 4000)) { vesc->emitMessageDialog("Read Motor Configuration", "Could not read motor configuration.", false, false); @@ -903,7 +903,7 @@ bool Utility::setMcParamsFromCurrentConfigAllCan(VescInterface *vesc, QVectorcommands()->setMcconf(false); - if (!waitSignal(vesc->commands(), SIGNAL(ackReceived(QString)), 4000)) { + if (!waitSignal(vesc->commands(), &Commands::ackReceived, 4000)) { vesc->emitMessageDialog("Write Motor Configuration", "Could not write motor configuration.", false, false); @@ -938,7 +938,7 @@ bool Utility::setMcParamsFromCurrentConfigAllCan(VescInterface *vesc, QVectorcanTmpOverrideEnd(); vesc->commands()->getMcconf(); - if (!waitSignal(config, SIGNAL(updated()), 4000)) { + if (!waitSignal(config, &ConfigParams::updated, 4000)) { res = false; if (!res) { @@ -973,18 +973,18 @@ bool Utility::setInvertDirection(VescInterface *vesc, int canId, bool inverted) if (res) { vesc->commands()->getMcconf(); - res = waitSignal(p, SIGNAL(updated()), 4000); + res = waitSignal(p, &ConfigParams::updated, 4000); } if (res) { p->updateParamBool("m_invert_direction", inverted); vesc->commands()->setMcconf(false); - res = waitSignal(vesc->commands(), SIGNAL(ackReceived(QString)), 4000); + res = waitSignal(vesc->commands(), &Commands::ackReceived, 4000); } vesc->commands()->setSendCan(canLastFwd, canLastId); vesc->commands()->getMcconf(); - if (!waitSignal(p, SIGNAL(updated()), 4000)) { + if (!waitSignal(p, &ConfigParams::updated, 4000)) { res = false; } @@ -1014,12 +1014,12 @@ bool Utility::getInvertDirection(VescInterface *vesc, int canId) ConfigParams *p = vesc->mcConfig(); vesc->commands()->getMcconf(); - waitSignal(p, SIGNAL(updated()), 4000); + waitSignal(p, &ConfigParams::updated, 4000); res = p->getParamBool("m_invert_direction"); vesc->commands()->setSendCan(canLastFwd, canLastId); vesc->commands()->getMcconf(); - waitSignal(p, SIGNAL(updated()), 4000); + waitSignal(p, &ConfigParams::updated, 4000); vesc->ignoreCanChange(false); @@ -1063,7 +1063,7 @@ QString Utility::testDirection(VescInterface *vesc, int canId, double duty, int } }); - connect(&timeoutTimer, SIGNAL(timeout()), &loop, SLOT(quit())); + connect(&timeoutTimer, &QTimer::timeout, &loop, &QEventLoop::quit); loop.exec(); disconnect(conn); @@ -1118,11 +1118,11 @@ bool Utility::restoreConfAll(VescInterface *vesc, bool can, bool mc, bool app) if (mc) { ConfigParams *p = vesc->mcConfig(); vesc->commands()->getMcconfDefault(); - res = waitSignal(p, SIGNAL(updated()), 4000); + res = waitSignal(p, &ConfigParams::updated, 4000); if (res) { vesc->commands()->setMcconf(false); - res = waitSignal(vesc->commands(), SIGNAL(ackReceived(QString)), 4000); + res = waitSignal(vesc->commands(), &Commands::ackReceived, 4000); } else { return false; } @@ -1131,11 +1131,11 @@ bool Utility::restoreConfAll(VescInterface *vesc, bool can, bool mc, bool app) if (app) { ConfigParams *p = vesc->appConfig(); vesc->commands()->getAppConfDefault(); - res = waitSignal(p, SIGNAL(updated()), 4000); + res = waitSignal(p, &ConfigParams::updated, 4000); if (res) { vesc->commands()->setAppConf(); - res = waitSignal(vesc->commands(), SIGNAL(ackReceived(QString)), 4000); + res = waitSignal(vesc->commands(), &Commands::ackReceived, 4000); } else { return false; } @@ -1169,7 +1169,7 @@ bool Utility::restoreConfAll(VescInterface *vesc, bool can, bool mc, bool app) if (mc) { ConfigParams *p = vesc->mcConfig(); vesc->commands()->getMcconf(); - if (!waitSignal(p, SIGNAL(updated()), 4000)) { + if (!waitSignal(p, &ConfigParams::updated, 4000)) { res = false; qWarning() << "Could not restore mc conf"; } @@ -1178,7 +1178,7 @@ bool Utility::restoreConfAll(VescInterface *vesc, bool can, bool mc, bool app) if (app) { ConfigParams *p = vesc->appConfig(); vesc->commands()->getAppConf(); - if (!waitSignal(p, SIGNAL(updated()), 4000)) { + if (!waitSignal(p, &ConfigParams::updated, 4000)) { res = false; qWarning() << "Could not restore app conf"; } @@ -1497,16 +1497,14 @@ bool Utility::getFwVersionBlocking(VescInterface *vesc, FW_RX_PARAMS *params, in res = true; }); - disconnect(vesc->commands(), SIGNAL(fwVersionReceived(FW_RX_PARAMS)), - vesc, SLOT(fwVersionReceived(FW_RX_PARAMS))); + vesc->disconnectFwVersionReceived(); vesc->commands()->getFwVersion(); - waitSignal(vesc->commands(), SIGNAL(fwVersionReceived(FW_RX_PARAMS)), timeout); + waitSignal(vesc->commands(), &Commands::fwVersionReceived, timeout); disconnect(conn); - connect(vesc->commands(), SIGNAL(fwVersionReceived(FW_RX_PARAMS)), - vesc, SLOT(fwVersionReceived(FW_RX_PARAMS))); + vesc->reconnectFwVersionReceived(); return res; } @@ -1557,7 +1555,7 @@ MC_VALUES Utility::getMcValuesBlocking(VescInterface *vesc) }); vesc->commands()->getValues(); - waitSignal(vesc->commands(), SIGNAL(valuesReceived(MC_VALUES, unsigned int)), 4000); + waitSignal(vesc->commands(), &Commands::valuesReceived, 4000); disconnect(conn); @@ -1651,7 +1649,7 @@ QString Utility::readInternalImuType(VescInterface *vesc) }); vesc->commands()->sendTerminalCmdSync("imu_type_internal"); - waitSignal(vesc->commands(), SIGNAL(printReceived(QString)), 2000); + waitSignal(vesc->commands(), &Commands::printReceived, 2000); disconnect(conn); @@ -1885,19 +1883,17 @@ bool Utility::configLoadCompatible(VescInterface *vesc, QString &uuidRx) } }); - disconnect(vesc->commands(), SIGNAL(fwVersionReceived(FW_RX_PARAMS)), - vesc, SLOT(fwVersionReceived(FW_RX_PARAMS))); + vesc->disconnectFwVersionReceived(); vesc->commands()->getFwVersion(); - if (!waitSignal(vesc->commands(), SIGNAL(fwVersionReceived(FW_RX_PARAMS)), 4000)) { + if (!waitSignal(vesc->commands(), &Commands::fwVersionReceived, 4000)) { vesc->emitMessageDialog("Load Config", "No response when reading firmware version.", false, false); } disconnect(conn); - connect(vesc->commands(), SIGNAL(fwVersionReceived(FW_RX_PARAMS)), - vesc, SLOT(fwVersionReceived(FW_RX_PARAMS))); + vesc->reconnectFwVersionReceived(); return res; } @@ -2372,7 +2368,7 @@ QString Utility::waitForLine(QTcpSocket *socket, int timeoutMs) QTimer timeoutTimer; timeoutTimer.setSingleShot(true); timeoutTimer.start(timeoutMs); - auto conn = QObject::connect(&timeoutTimer, SIGNAL(timeout()), &loop, SLOT(quit())); + auto conn = QObject::connect(&timeoutTimer, &QTimer::timeout, &loop, &QEventLoop::quit); QByteArray rxLine; auto conn2 = connect(socket, &QTcpSocket::readyRead, [&rxLine,socket,&loop]() { @@ -2434,7 +2430,7 @@ bool Utility::downloadUrlEventloop(QString path, QString dest) QNetworkReply *reply = manager.get(request); QEventLoop loop; - connect(reply, SIGNAL(finished()), &loop, SLOT(quit())); + connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit); loop.exec(); if (reply->error() == QNetworkReply::NoError) { diff --git a/utility.h b/utility.h index 10b012a04..6b6b29710 100644 --- a/utility.h +++ b/utility.h @@ -25,6 +25,7 @@ #include #include #include +#include #include "vescinterface.h" #include "widgets/qcustomplot.h" #include "datatypes.h" @@ -61,6 +62,22 @@ class Utility : public QObject Q_INVOKABLE static void keepScreenOn(bool on); Q_INVOKABLE static void allowScreenRotation(bool enabled); Q_INVOKABLE static bool waitSignal(QObject *sender, QString signal, int timeoutMs); + + // Type-safe overload for C++ callers (avoids SIGNAL() macro) + template + static bool waitSignal(Sender *sender, Signal signal, int timeoutMs) { + QEventLoop loop; + QTimer timeoutTimer; + timeoutTimer.setSingleShot(true); + timeoutTimer.start(timeoutMs); + auto conn1 = QObject::connect(sender, signal, &loop, &QEventLoop::quit); + auto conn2 = QObject::connect(&timeoutTimer, &QTimer::timeout, &loop, &QEventLoop::quit); + loop.exec(); + QObject::disconnect(conn1); + QObject::disconnect(conn2); + return timeoutTimer.isActive(); + } + Q_INVOKABLE static void sleepWithEventLoop(int timeMs); Q_INVOKABLE static bool canUpdateBaudAllBlocking(VescInterface *vesc, int newBaud); Q_INVOKABLE static QString detectAllFoc(VescInterface *vesc, diff --git a/vescinterface.cpp b/vescinterface.cpp index c8624c619..d8777a351 100755 --- a/vescinterface.cpp +++ b/vescinterface.cpp @@ -140,8 +140,7 @@ VescInterface::VescInterface(QObject *parent) : QObject(parent) mLastSerialPort = mSettings.value("serial_port", "").toString(); mLastSerialBaud = mSettings.value("serial_baud", 115200).toInt(); - connect(mSerialPort, SIGNAL(readyRead()), - this, SLOT(serialDataAvailable())); + connect(mSerialPort, &QIODevice::readyRead, this, &VescInterface::serialDataAvailable); connect(mSerialPort, &QSerialPort::errorOccurred, this, &VescInterface::serialPortError); #endif @@ -164,17 +163,16 @@ VescInterface::VescInterface(QObject *parent) : QObject(parent) mTcpSocket = new QTcpSocket(this); mTcpConnected = false; - connect(mTcpSocket, SIGNAL(readyRead()), this, SLOT(tcpInputDataAvailable())); - connect(mTcpSocket, SIGNAL(connected()), this, SLOT(tcpInputConnected())); - connect(mTcpSocket, SIGNAL(disconnected()), - this, SLOT(tcpInputDisconnected())); + connect(mTcpSocket, &QIODevice::readyRead, this, &VescInterface::tcpInputDataAvailable); + connect(mTcpSocket, &QAbstractSocket::connected, this, &VescInterface::tcpInputConnected); + connect(mTcpSocket, &QAbstractSocket::disconnected, this, &VescInterface::tcpInputDisconnected); connect(mTcpSocket, &QAbstractSocket::errorOccurred, this, &VescInterface::tcpInputError); // UDP mUdpSocket = new QUdpSocket(this); mUdpConnected = false; - connect(mUdpSocket, SIGNAL(readyRead()), this, SLOT(udpInputDataAvailable())); + connect(mUdpSocket, &QIODevice::readyRead, this, &VescInterface::udpInputDataAvailable); connect(mUdpSocket, &QAbstractSocket::errorOccurred, this, &VescInterface::udpInputError); @@ -205,22 +203,22 @@ VescInterface::VescInterface(QObject *parent) : QObject(parent) mSettings.endArray(); } - connect(mBleUart, SIGNAL(dataRx(QByteArray)), this, SLOT(bleDataRx(QByteArray))); + connect(mBleUart, &BleUart::dataRx, this, &VescInterface::bleDataRx); connect(mBleUart, &BleUart::connected, [this]{ setLastConnectionType(CONN_BLE); mSettings.setValue("ble_addr", mLastBleAddr); }); - connect(mBleUart, SIGNAL(unintentionalDisconnect()), this, SLOT(bleUnintentionalDisconnect())); + connect(mBleUart, &BleUart::unintentionalDisconnect, this, &VescInterface::bleUnintentionalDisconnect); #else mBleUart = new BleUartDummy(this); #endif mTcpServer = new TcpServerSimple(this); mTcpServer->setUsePacket(true); - connect(mTcpServer->packet(), &Packet::packetReceived, [this](QByteArray &packet) { + connect(mTcpServer->packet(), &Packet::packetReceived, [this](const QByteArray &packet) { mPacket->sendPacket(packet); }); - connect(mPacket, &Packet::packetReceived, [this](QByteArray &packet) { + connect(mPacket, &Packet::packetReceived, [this](const QByteArray &packet) { mTcpServer->packet()->sendPacket(packet); }); @@ -253,10 +251,10 @@ VescInterface::VescInterface(QObject *parent) : QObject(parent) mUdpServer = new UdpServerSimple(this); mUdpServer->setUsePacket(true); - connect(mUdpServer->packet(), &Packet::packetReceived, [this](QByteArray &packet) { + connect(mUdpServer->packet(), &Packet::packetReceived, [this](const QByteArray &packet) { mPacket->sendPacket(packet); }); - connect(mPacket, &Packet::packetReceived, [this](QByteArray &packet) { + connect(mPacket, &Packet::packetReceived, [this](const QByteArray &packet) { mUdpServer->packet()->sendPacket(packet); }); @@ -349,18 +347,14 @@ VescInterface::VescInterface(QObject *parent) : QObject(parent) mCommands->setMcConfig(mMcConfig); // Other signals/slots - connect(mTimer, SIGNAL(timeout()), this, SLOT(timerSlot())); - connect(mPacket, SIGNAL(dataToSend(QByteArray&)), - this, SLOT(packetDataToSend(QByteArray&))); - connect(mPacket, SIGNAL(packetReceived(QByteArray&)), - this, SLOT(packetReceived(QByteArray&))); - connect(mCommands, SIGNAL(dataToSend(QByteArray&)), - this, SLOT(cmdDataToSend(QByteArray&))); - connect(mCommands, SIGNAL(fwVersionReceived(FW_RX_PARAMS)), - this, SLOT(fwVersionReceived(FW_RX_PARAMS))); - connect(mCommands, SIGNAL(ackReceived(QString)), this, SLOT(ackReceived(QString))); - connect(mMcConfig, SIGNAL(updated()), this, SLOT(mcconfUpdated())); - connect(mAppConfig, SIGNAL(updated()), this, SLOT(appconfUpdated())); + connect(mTimer, &QTimer::timeout, this, &VescInterface::timerSlot); + connect(mPacket, &Packet::dataToSend, this, &VescInterface::packetDataToSend); + connect(mPacket, &Packet::packetReceived, this, &VescInterface::packetReceived); + connect(mCommands, &Commands::dataToSend, this, &VescInterface::cmdDataToSend); + connect(mCommands, &Commands::fwVersionReceived, this, &VescInterface::fwVersionReceived); + connect(mCommands, &Commands::ackReceived, this, &VescInterface::ackReceived); + connect(mMcConfig, &ConfigParams::updated, this, &VescInterface::mcconfUpdated); + connect(mAppConfig, &ConfigParams::updated, this, &VescInterface::appconfUpdated); // Sanity-check motor parameters connect(mCommands, &Commands::mcConfigWriteSent, [this](bool checkSet) { @@ -572,8 +566,7 @@ VescInterface::VescInterface(QObject *parent) : QObject(parent) } }); - connect(mCommands, SIGNAL(customConfigRx(int,QByteArray)), - this, SLOT(customConfigRx(int,QByteArray))); + connect(mCommands, &Commands::customConfigRx, this, &VescInterface::customConfigRx); connect(mCommands, &Commands::customConfigAckReceived, [this](int confId) { ConfigParams *custConf = customConfig(confId); @@ -1088,7 +1081,7 @@ bool VescInterface::swdEraseFlash() loop.quit(); }); - connect(&timeoutTimer, SIGNAL(timeout()), &loop, SLOT(quit())); + connect(&timeoutTimer, &QTimer::timeout, &loop, &QEventLoop::quit); loop.exec(); disconnect(conn); @@ -1144,7 +1137,7 @@ bool VescInterface::swdUploadFw(QByteArray newFirmware, uint32_t startAddr, loop.quit(); }); - connect(&timeoutTimer, SIGNAL(timeout()), &loop, SLOT(quit())); + connect(&timeoutTimer, &QTimer::timeout, &loop, &QEventLoop::quit); loop.exec(); disconnect(conn); @@ -1282,7 +1275,7 @@ bool VescInterface::swdReboot() loop.quit(); }); - connect(&timeoutTimer, SIGNAL(timeout()), &loop, SLOT(quit())); + connect(&timeoutTimer, &QTimer::timeout, &loop, &QEventLoop::quit); loop.exec(); disconnect(conn); @@ -1326,7 +1319,7 @@ bool VescInterface::fwEraseNewApp(bool fwdCan, quint32 fwSize) loop.quit(); }); - connect(&timeoutTimer, SIGNAL(timeout()), &loop, SLOT(quit())); + connect(&timeoutTimer, &QTimer::timeout, &loop, &QEventLoop::quit); loop.exec(); disconnect(conn); @@ -1371,7 +1364,7 @@ bool VescInterface::fwEraseBootloader(bool fwdCan) loop.quit(); }); - connect(&timeoutTimer, SIGNAL(timeout()), &loop, SLOT(quit())); + connect(&timeoutTimer, &QTimer::timeout, &loop, &QEventLoop::quit); loop.exec(); disconnect(conn); @@ -1438,7 +1431,7 @@ bool VescInterface::fwUpload(QByteArray &newFirmware, bool isBootloader, bool fw bool ignoreBefore = mIgnoreCanChange; mIgnoreCanChange = true; - foreach (auto d, devs) { + for (const auto &d : devs) { mCommands->setSendCan(true, d); FW_RX_PARAMS fwParamsCan; Utility::getFwVersionBlocking(this, &fwParamsCan); @@ -1513,7 +1506,7 @@ bool VescInterface::fwUpload(QByteArray &newFirmware, bool isBootloader, bool fw mCommands->writeNewAppData(chunk, addr, fwdCan, mLastFwParams.hwType, mLastFwParams.hw); } - connect(&timeoutTimer, SIGNAL(timeout()), &loop, SLOT(quit())); + connect(&timeoutTimer, &QTimer::timeout, &loop, &QEventLoop::quit); loop.exec(); disconnect(conn); @@ -1615,7 +1608,7 @@ bool VescInterface::fwUpload(QByteArray &newFirmware, bool isBootloader, bool fw QByteArray in = newFirmware.mid(0, sz); bool hasData = false; - foreach (auto b, in) { + for (const auto &b : in) { if (b != (char)0xff) { hasData = true; break; @@ -2333,7 +2326,7 @@ bool VescInterface::lastPortAvailable() #ifdef HAS_SERIALPORT if (mLastConnType == CONN_SERIAL) { auto ports = listSerialPorts(); - foreach (auto port, ports) { + for (const auto &port : ports) { auto p = port.value(); if (p.systemPath == mLastSerialPort) { res = true; @@ -2356,8 +2349,7 @@ bool VescInterface::autoconnect() mAutoconnectProgress = 0.0; disconnectPort(); - disconnect(mCommands, SIGNAL(fwVersionReceived(FW_RX_PARAMS)), - this, SLOT(fwVersionReceived(FW_RX_PARAMS))); + disconnect(mCommands, &Commands::fwVersionReceived, this, &VescInterface::fwVersionReceived); for (int i = 0;i < ports.size();i++) { VSerialInfo_t serial = ports[i].value(); @@ -2374,8 +2366,8 @@ bool VescInterface::autoconnect() QTimer timeoutTimer; timeoutTimer.setSingleShot(true); timeoutTimer.start(500); - connect(mCommands, SIGNAL(fwVersionReceived(FW_RX_PARAMS)), &loop, SLOT(quit())); - connect(&timeoutTimer, SIGNAL(timeout()), &loop, SLOT(quit())); + connect(mCommands, &Commands::fwVersionReceived, &loop, &QEventLoop::quit); + connect(&timeoutTimer, &QTimer::timeout, &loop, &QEventLoop::quit); loop.exec(); if (timeoutTimer.isActive()) { @@ -2389,8 +2381,7 @@ bool VescInterface::autoconnect() } } - connect(mCommands, SIGNAL(fwVersionReceived(FW_RX_PARAMS)), - this, SLOT(fwVersionReceived(FW_RX_PARAMS))); + connect(mCommands, &Commands::fwVersionReceived, this, &VescInterface::fwVersionReceived); #endif emit autoConnectProgressUpdated(1.0, true); @@ -2519,7 +2510,7 @@ QVariantList VescInterface::listSerialPorts() #ifdef HAS_SERIALPORT QList ports = QSerialPortInfo::availablePorts(); - foreach(const QSerialPortInfo &port, ports) { + for (const QSerialPortInfo &port : ports) { VSerialInfo_t info; info.name = port.portName(); info.systemPath = port.systemLocation(); @@ -2587,8 +2578,8 @@ bool VescInterface::connectCANbus(QString backend, QString ifName, int bitrate) return false; } - connect(mCanDevice, SIGNAL(framesReceived()), this, SLOT(CANbusDataAvailable())); - connect(mCanDevice, SIGNAL(errorOccurred(QCanBusDevice::CanBusError)), this, SLOT(CANbusError(QCanBusDevice::CanBusError))); + connect(mCanDevice, &QCanBusDevice::framesReceived, this, &VescInterface::CANbusDataAvailable); + connect(mCanDevice, &QCanBusDevice::errorOccurred, this, &VescInterface::CANbusError); mCanDevice->setConfigurationParameter(QCanBusDevice::LoopbackKey, false); mCanDevice->setConfigurationParameter(QCanBusDevice::ReceiveOwnKey, false); @@ -3320,7 +3311,7 @@ void VescInterface::timerSlot() } } -void VescInterface::packetDataToSend(QByteArray &data) +void VescInterface::packetDataToSend(QByteArray data) { #ifdef HAS_SERIALPORT if (mSerialPort->isOpen()) { @@ -3449,12 +3440,12 @@ void VescInterface::packetDataToSend(QByteArray &data) #endif } -void VescInterface::packetReceived(QByteArray &data) +void VescInterface::packetReceived(QByteArray data) { mCommands->processPacket(data); } -void VescInterface::cmdDataToSend(QByteArray &data) +void VescInterface::cmdDataToSend(QByteArray data) { mPacket->sendPacket(data); } @@ -3934,7 +3925,7 @@ void VescInterface::fwVersionReceived(FW_RX_PARAMS params) for (int j = 0;j < tries;j++) { mCommands->customConfigGetChunk(i, size, offset); - res = Utility::waitSignal(mCommands, SIGNAL(customConfigChunkRx(int,int,int,QByteArray)), timeout); + res = Utility::waitSignal(mCommands, &Commands::customConfigChunkRx, timeout); if (res) { break; } @@ -4029,7 +4020,7 @@ void VescInterface::fwVersionReceived(FW_RX_PARAMS params) for (int j = 0;j < tries;j++) { mCommands->qmlUiHwGet(size, offset); - res = Utility::waitSignal(mCommands, SIGNAL(qmluiHwRx(int,int,QByteArray)), timeout); + res = Utility::waitSignal(mCommands, &Commands::qmluiHwRx, timeout); if (res) { break; } @@ -4109,7 +4100,7 @@ void VescInterface::fwVersionReceived(FW_RX_PARAMS params) for (int j = 0;j < tries;j++) { mCommands->qmlUiAppGet(size, offset); - res = Utility::waitSignal(mCommands, SIGNAL(qmluiAppRx(int,int,QByteArray)), timeout); + res = Utility::waitSignal(mCommands, &Commands::qmluiAppRx, timeout); if (res) { break; } @@ -4221,6 +4212,16 @@ void VescInterface::setBlockFwSwap(bool newBlockFwSwap) mBlockFwSwap = newBlockFwSwap; } +void VescInterface::disconnectFwVersionReceived() +{ + disconnect(mCommands, &Commands::fwVersionReceived, this, &VescInterface::fwVersionReceived); +} + +void VescInterface::reconnectFwVersionReceived() +{ + connect(mCommands, &Commands::fwVersionReceived, this, &VescInterface::fwVersionReceived); +} + bool VescInterface::showFwUpdateAvailable() const { return mSettings.value("showFwUpdateAvailable", true).toBool(); @@ -4336,7 +4337,7 @@ bool VescInterface::downloadFwArchive() }); QEventLoop loop; - connect(reply, SIGNAL(finished()), &loop, SLOT(quit())); + connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit); loop.exec(); disconnect(conn); @@ -4379,7 +4380,7 @@ bool VescInterface::downloadFwLatest() }); QEventLoop loop; - connect(reply, SIGNAL(finished()), &loop, SLOT(quit())); + connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit); loop.exec(); disconnect(conn); @@ -4444,7 +4445,7 @@ bool VescInterface::downloadConfigs() }); QEventLoop loop; - connect(reply, SIGNAL(finished()), &loop, SLOT(quit())); + connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit); loop.exec(); disconnect(conn); @@ -4520,14 +4521,14 @@ bool VescInterface::confStoreBackup(bool can, QString name) ConfigParams *pCustom = customConfig(0); commands()->getMcconf(); - bool rxMc = Utility::waitSignal(pMc, SIGNAL(updated()), 1500); + bool rxMc = Utility::waitSignal(pMc, &ConfigParams::updated, 1500); commands()->getAppConf(); - bool rxApp = Utility::waitSignal(pApp, SIGNAL(updated()), 1500); + bool rxApp = Utility::waitSignal(pApp, &ConfigParams::updated, 1500); bool rxCustom = false; if (pCustom != nullptr) { commands()->customConfigGet(0, false); - rxCustom = Utility::waitSignal(pCustom, SIGNAL(updated()), 1500); + rxCustom = Utility::waitSignal(pCustom, &ConfigParams::updated, 1500); } if (rxMc && rxApp) { @@ -4571,7 +4572,7 @@ bool VescInterface::confStoreBackup(bool can, QString name) } if (res && can) { - foreach (int d, canDevs) { + for (const int &d : canDevs) { commands()->setSendCan(true, d); Utility::getFwVersionBlocking(this, &fwp); @@ -4604,7 +4605,7 @@ bool VescInterface::confStoreBackup(bool can, QString name) } QString uuidsStr; - foreach (auto s, uuidsOk) { + for (const auto &s : uuidsOk) { uuidsStr += s + "\n"; } @@ -4642,14 +4643,14 @@ bool VescInterface::confRestoreBackup(bool can) ConfigParams *pCustom = customConfig(0); commands()->getMcconf(); - bool rxMc = Utility::waitSignal(pMc, SIGNAL(updated()), 2000); + bool rxMc = Utility::waitSignal(pMc, &ConfigParams::updated, 2000); commands()->getAppConf(); - bool rxApp = Utility::waitSignal(pApp, SIGNAL(updated()), 2000); + bool rxApp = Utility::waitSignal(pApp, &ConfigParams::updated, 2000); bool rxCustom = false; if (pCustom != nullptr) { commands()->customConfigGet(0, false); - rxCustom = Utility::waitSignal(pCustom, SIGNAL(updated()), 2000); + rxCustom = Utility::waitSignal(pCustom, &ConfigParams::updated, 2000); } if (rxMc && rxApp) { @@ -4665,13 +4666,13 @@ bool VescInterface::confRestoreBackup(bool can) bool txMc = false, txApp = false, txCustom = true;; for (int i = 0;i < 2;i++) { commands()->setMcconf(false); - txMc = Utility::waitSignal(commands(), SIGNAL(ackReceived(QString)), 2000); + txMc = Utility::waitSignal(commands(), &Commands::ackReceived, 2000); commands()->setAppConf(); - txApp = Utility::waitSignal(commands(), SIGNAL(ackReceived(QString)), 2000); + txApp = Utility::waitSignal(commands(), &Commands::ackReceived, 2000); if (rxCustom) { commands()->customConfigSet(0, pCustom); - txCustom = Utility::waitSignal(commands(), SIGNAL(ackReceived(QString)), 2000); + txCustom = Utility::waitSignal(commands(), &Commands::ackReceived, 2000); } if (txApp && txMc && txCustom) { @@ -4728,7 +4729,7 @@ bool VescInterface::confRestoreBackup(bool can) } if (res && can) { - foreach (int d, canDevs) { + for (const int &d : canDevs) { commands()->setSendCan(true, d); Utility::getFwVersionBlocking(this, &fwp); @@ -4762,7 +4763,7 @@ bool VescInterface::confRestoreBackup(bool can) if (!uuidsOk.isEmpty()) { QString uuidsStr; - foreach (auto s, uuidsOk) { + for (const auto &s : uuidsOk) { uuidsStr += s + "\n"; } @@ -4773,7 +4774,7 @@ bool VescInterface::confRestoreBackup(bool can) if (!missingConfigs.empty()) { QString missing; - foreach (auto s, missingConfigs) { + for (const auto &s : missingConfigs) { missing += s + "\n"; } diff --git a/vescinterface.h b/vescinterface.h index 1868215c4..71aa81f6b 100755 --- a/vescinterface.h +++ b/vescinterface.h @@ -31,6 +31,7 @@ #include #include #include +#include #ifdef HAS_SERIALPORT #include @@ -284,6 +285,11 @@ class VescInterface : public QObject Q_INVOKABLE bool isBlockFwSwap() const; Q_INVOKABLE void setBlockFwSwap(bool newBlockFwSwap); + // Helpers for temporarily disconnecting/reconnecting the + // Commands::fwVersionReceived → VescInterface::fwVersionReceived forwarding. + void disconnectFwVersionReceived(); + void reconnectFwVersionReceived(); + signals: void statusMessage(const QString &msg, bool isGood); void messageDialog(const QString &title, const QString &msg, bool isGood, bool richText); @@ -332,9 +338,9 @@ private slots: #endif void timerSlot(); - void packetDataToSend(QByteArray &data); - void packetReceived(QByteArray &data); - void cmdDataToSend(QByteArray &data); + void packetDataToSend(QByteArray data); + void packetReceived(QByteArray data); + void cmdDataToSend(QByteArray data); void fwVersionReceived(FW_RX_PARAMS params); void appconfUpdated(); void mcconfUpdated(); diff --git a/widgets/adcmap.cpp b/widgets/adcmap.cpp index 12ef49901..a6feda117 100644 --- a/widgets/adcmap.cpp +++ b/widgets/adcmap.cpp @@ -55,8 +55,8 @@ void AdcMap::setVesc(VescInterface *vesc) mVesc = vesc; if (mVesc) { - connect(mVesc->commands(), SIGNAL(decodedAdcReceived(double,double,double,double)), - this, SLOT(decodedAdcReceived(double,double,double,double))); + connect(mVesc->commands(), &Commands::decodedAdcReceived, + this, &AdcMap::decodedAdcReceived); } } diff --git a/widgets/detectallfocdialog.cpp b/widgets/detectallfocdialog.cpp index 87a7f0acf..2b6bd6c05 100644 --- a/widgets/detectallfocdialog.cpp +++ b/widgets/detectallfocdialog.cpp @@ -130,10 +130,10 @@ DetectAllFocDialog::DetectAllFocDialog(VescInterface *vesc, QWidget *parent) : ui->paramTab->addParamRow(mVesc->mcConfig(), "si_battery_cells"); ui->paramTab->addParamRow(mVesc->mcConfig(), "si_battery_ah"); - connect(ui->pulleyMotorBox, SIGNAL(valueChanged(int)), - this, SLOT(updateGearRatio())); - connect(ui->pulleyWheelBox, SIGNAL(valueChanged(int)), - this, SLOT(updateGearRatio())); + connect(ui->pulleyMotorBox, qOverload(&QSpinBox::valueChanged), + this, &DetectAllFocDialog::updateGearRatio); + connect(ui->pulleyWheelBox, qOverload(&QSpinBox::valueChanged), + this, &DetectAllFocDialog::updateGearRatio); updateGearRatio(); } @@ -270,7 +270,7 @@ void DetectAllFocDialog::runDetect(bool can) ui->progressBar->setRange(0, 0); mVesc->commands()->setMcconf(false); - Utility::waitSignal(mVesc->commands(), SIGNAL(ackReceived(QString)), 2000); + Utility::waitSignal(mVesc->commands(), &Commands::ackReceived, 2000); QVector canDevs; if (can) { canDevs = Utility::scanCanVescOnly(mVesc); @@ -281,7 +281,7 @@ void DetectAllFocDialog::runDetect(bool can) mVesc->mcConfig()->getParamDouble("l_battery_cut_start"), mVesc->mcConfig()->getParamDouble("l_battery_cut_end"), true, true); - Utility::waitSignal(mVesc->commands(), SIGNAL(ackReceived(QString)), 2000); + Utility::waitSignal(mVesc->commands(), &Commands::ackReceived, 2000); } else { if (!Utility::setBatteryCutCan(mVesc, canDevs, 6.0, 6.0)) { ui->tabWidget->setEnabled(true); diff --git a/widgets/detectbldc.cpp b/widgets/detectbldc.cpp index 847ef31b4..357d465ca 100644 --- a/widgets/detectbldc.cpp +++ b/widgets/detectbldc.cpp @@ -109,8 +109,8 @@ void DetectBldc::setVesc(VescInterface *vesc) mVesc = vesc; if (mVesc) { - connect(mVesc->commands(), SIGNAL(bldcDetectReceived(bldc_detect)), - this, SLOT(bldcDetectReceived(bldc_detect))); + connect(mVesc->commands(), &Commands::bldcDetectReceived, + this, &DetectBldc::bldcDetectReceived); } } diff --git a/widgets/detectfoc.cpp b/widgets/detectfoc.cpp index 34be95bfb..be3c699e7 100644 --- a/widgets/detectfoc.cpp +++ b/widgets/detectfoc.cpp @@ -144,14 +144,14 @@ void DetectFoc::setVesc(VescInterface *vesc) mVesc = vesc; if (mVesc) { - connect(mVesc->commands(), SIGNAL(motorRLReceived(double,double,double)), - this, SLOT(motorRLReceived(double,double,double))); - connect(mVesc->commands(), SIGNAL(motorLinkageReceived(double)), - this, SLOT(motorLinkageReceived(double))); - connect(mVesc->commands(), SIGNAL(encoderParamReceived(ENCODER_DETECT_RES)), - this, SLOT(encoderParamReceived(ENCODER_DETECT_RES))); - connect(mVesc->mcConfig(), SIGNAL(paramChangedDouble(QObject*,QString,double)), - this, SLOT(paramChangedDouble(QObject*,QString,double))); + connect(mVesc->commands(), &Commands::motorRLReceived, + this, &DetectFoc::motorRLReceived); + connect(mVesc->commands(), &Commands::motorLinkageReceived, + this, &DetectFoc::motorLinkageReceived); + connect(mVesc->commands(), &Commands::encoderParamReceived, + this, &DetectFoc::encoderParamReceived); + connect(mVesc->mcConfig(), &ConfigParams::paramChangedDouble, + this, &DetectFoc::paramChangedDouble); ui->currentBox->setValue(mVesc->mcConfig()->getParamDouble("l_current_max") / 3.0); } diff --git a/widgets/detectfocencoder.cpp b/widgets/detectfocencoder.cpp index e759c585e..25a86db48 100644 --- a/widgets/detectfocencoder.cpp +++ b/widgets/detectfocencoder.cpp @@ -85,8 +85,8 @@ void DetectFocEncoder::setVesc(VescInterface *vesc) mVesc = vesc; if (mVesc) { - connect(mVesc->commands(), SIGNAL(encoderParamReceived(ENCODER_DETECT_RES)), - this, SLOT(encoderParamReceived(ENCODER_DETECT_RES))); + connect(mVesc->commands(), &Commands::encoderParamReceived, + this, &DetectFocEncoder::encoderParamReceived); } } diff --git a/widgets/detectfochall.cpp b/widgets/detectfochall.cpp index 64d7a366e..2e017f842 100644 --- a/widgets/detectfochall.cpp +++ b/widgets/detectfochall.cpp @@ -90,8 +90,8 @@ void DetectFocHall::setVesc(VescInterface *vesc) mVesc = vesc; if (mVesc) { - connect(mVesc->commands(), SIGNAL(focHallTableReceived(QVector,int)), - this, SLOT(focHallTableReceived(QVector,int))); + connect(mVesc->commands(), &Commands::focHallTableReceived, + this, &DetectFocHall::focHallTableReceived); } } diff --git a/widgets/experimentplot.cpp b/widgets/experimentplot.cpp index 361d32016..7f5c42227 100644 --- a/widgets/experimentplot.cpp +++ b/widgets/experimentplot.cpp @@ -192,14 +192,14 @@ void ExperimentPlot::setVesc(VescInterface *newVesc) mVesc = newVesc; if (mVesc) { - connect(mVesc->commands(), SIGNAL(plotInitReceived(QString,QString)), - this, SLOT(plotInitReceived(QString,QString))); - connect(mVesc->commands(), SIGNAL(plotDataReceived(double,double)), - this, SLOT(plotDataReceived(double,double))); - connect(mVesc->commands(), SIGNAL(plotAddGraphReceived(QString)), - this, SLOT(plotAddGraphReceived(QString))); - connect(mVesc->commands(), SIGNAL(plotSetGraphReceived(int)), - this, SLOT(plotSetGraphReceived(int))); + connect(mVesc->commands(), &Commands::plotInitReceived, + this, &ExperimentPlot::plotInitReceived); + connect(mVesc->commands(), &Commands::plotDataReceived, + this, &ExperimentPlot::plotDataReceived); + connect(mVesc->commands(), &Commands::plotAddGraphReceived, + this, &ExperimentPlot::plotAddGraphReceived); + connect(mVesc->commands(), &Commands::plotSetGraphReceived, + this, &ExperimentPlot::plotSetGraphReceived); } } @@ -323,7 +323,7 @@ void ExperimentPlot::on_experimentSaveXmlButton_clicked() stream.writeTextElement("xlabel", ui->experimentPlot->xAxis->label()); stream.writeTextElement("ylabel", ui->experimentPlot->yAxis->label()); - foreach (auto p, mExperimentPlots) { + for (const auto &p : mExperimentPlots) { stream.writeStartElement("graph"); stream.writeTextElement("label", p.label); stream.writeTextElement("color", p.color.name()); @@ -408,7 +408,7 @@ void ExperimentPlot::on_experimentSaveCsvButton_clicked() QTextStream os(&file); int maxLen = 0; - foreach (auto p, mExperimentPlots) { + for (const auto &p : mExperimentPlots) { os << p.label << " x;" << p.label << " y;"; if (p.xData.length() > maxLen) { maxLen = p.xData.length(); @@ -417,7 +417,7 @@ void ExperimentPlot::on_experimentSaveCsvButton_clicked() os << "\n"; for (int i = 0;i < maxLen;i++) { - foreach (auto p, mExperimentPlots) { + for (const auto &p : mExperimentPlots) { if (p.xData.length() > i) { os << p.xData.at(i) << ";" << p.yData.at(i) << ";"; } else { diff --git a/widgets/mrichtextedit.cpp b/widgets/mrichtextedit.cpp index 4fdc7405e..fd624a997 100644 --- a/widgets/mrichtextedit.cpp +++ b/widgets/mrichtextedit.cpp @@ -69,10 +69,8 @@ MRichTextEdit::MRichTextEdit(QWidget *parent) : QWidget(parent) { f_align_right->setIcon(Utility::getIcon("icons_textedit/Align Right-96.png")); f_align_justify->setIcon(Utility::getIcon("icons_textedit/Align Justify-96.png")); - connect(f_textedit, SIGNAL(currentCharFormatChanged(QTextCharFormat)), - this, SLOT(slotCurrentCharFormatChanged(QTextCharFormat))); - connect(f_textedit, SIGNAL(cursorPositionChanged()), - this, SLOT(slotCursorPositionChanged())); + connect(f_textedit, &QTextEdit::currentCharFormatChanged, this, &MRichTextEdit::slotCurrentCharFormatChanged); + connect(f_textedit, &QTextEdit::cursorPositionChanged, this, &MRichTextEdit::slotCursorPositionChanged); m_fontsize_h1 = 18; m_fontsize_h2 = 16; @@ -93,24 +91,23 @@ MRichTextEdit::MRichTextEdit(QWidget *parent) : QWidget(parent) { << tr("Monospace"); f_paragraph->addItems(m_paragraphItems); - connect(f_paragraph, SIGNAL(activated(int)), - this, SLOT(textStyle(int))); + connect(f_paragraph, qOverload(&QComboBox::activated), this, &MRichTextEdit::textStyle); // undo & redo f_undo->setShortcut(QKeySequence::Undo); f_redo->setShortcut(QKeySequence::Redo); - connect(f_textedit->document(), SIGNAL(undoAvailable(bool)), - f_undo, SLOT(setEnabled(bool))); - connect(f_textedit->document(), SIGNAL(redoAvailable(bool)), - f_redo, SLOT(setEnabled(bool))); + connect(f_textedit->document(), &QTextDocument::undoAvailable, + f_undo, &QWidget::setEnabled); + connect(f_textedit->document(), &QTextDocument::redoAvailable, + f_redo, &QWidget::setEnabled); f_undo->setEnabled(f_textedit->document()->isUndoAvailable()); f_redo->setEnabled(f_textedit->document()->isRedoAvailable()); - connect(f_undo, SIGNAL(clicked()), f_textedit, SLOT(undo())); - connect(f_redo, SIGNAL(clicked()), f_textedit, SLOT(redo())); + connect(f_undo, &QAbstractButton::clicked, f_textedit, &QTextEdit::undo); + connect(f_redo, &QAbstractButton::clicked, f_textedit, &QTextEdit::redo); // cut, copy & paste @@ -121,22 +118,22 @@ MRichTextEdit::MRichTextEdit(QWidget *parent) : QWidget(parent) { f_cut->setEnabled(false); f_copy->setEnabled(false); - connect(f_cut, SIGNAL(clicked()), f_textedit, SLOT(cut())); - connect(f_copy, SIGNAL(clicked()), f_textedit, SLOT(copy())); - connect(f_paste, SIGNAL(clicked()), f_textedit, SLOT(paste())); + connect(f_cut, &QAbstractButton::clicked, f_textedit, &QTextEdit::cut); + connect(f_copy, &QAbstractButton::clicked, f_textedit, &QTextEdit::copy); + connect(f_paste, &QAbstractButton::clicked, f_textedit, &QTextEdit::paste); - connect(f_textedit, SIGNAL(copyAvailable(bool)), f_cut, SLOT(setEnabled(bool))); - connect(f_textedit, SIGNAL(copyAvailable(bool)), f_copy, SLOT(setEnabled(bool))); + connect(f_textedit, &QTextEdit::copyAvailable, f_cut, &QWidget::setEnabled); + connect(f_textedit, &QTextEdit::copyAvailable, f_copy, &QWidget::setEnabled); #ifndef QT_NO_CLIPBOARD - connect(QApplication::clipboard(), SIGNAL(dataChanged()), this, SLOT(slotClipboardDataChanged())); + connect(QApplication::clipboard(), &QClipboard::dataChanged, this, &MRichTextEdit::slotClipboardDataChanged); #endif // link f_link->setShortcut(Qt::CTRL | Qt::Key_L); - connect(f_link, SIGNAL(clicked(bool)), this, SLOT(textLink(bool))); + connect(f_link, qOverload(&QAbstractButton::clicked), this, &MRichTextEdit::textLink); // bold, italic & underline @@ -144,30 +141,30 @@ MRichTextEdit::MRichTextEdit(QWidget *parent) : QWidget(parent) { f_italic->setShortcut(Qt::CTRL | Qt::Key_I); f_underline->setShortcut(Qt::CTRL | Qt::Key_U); - connect(f_bold, SIGNAL(clicked()), this, SLOT(textBold())); - connect(f_italic, SIGNAL(clicked()), this, SLOT(textItalic())); - connect(f_underline, SIGNAL(clicked()), this, SLOT(textUnderline())); - connect(f_strikeout, SIGNAL(clicked()), this, SLOT(textStrikeout())); + connect(f_bold, &QAbstractButton::clicked, this, &MRichTextEdit::textBold); + connect(f_italic, &QAbstractButton::clicked, this, &MRichTextEdit::textItalic); + connect(f_underline, &QAbstractButton::clicked, this, &MRichTextEdit::textUnderline); + connect(f_strikeout, &QAbstractButton::clicked, this, &MRichTextEdit::textStrikeout); f_align_left->setChecked(true); - connect(f_align_left, SIGNAL(clicked(bool)), this, SLOT(textAlignLeft())); - connect(f_align_center, SIGNAL(clicked(bool)), this, SLOT(textAlignCenter())); - connect(f_align_right, SIGNAL(clicked(bool)), this, SLOT(textAlignRight())); - connect(f_align_justify, SIGNAL(clicked(bool)), this, SLOT(textAlignJustify())); + connect(f_align_left, qOverload(&QAbstractButton::clicked), this, &MRichTextEdit::textAlignLeft); + connect(f_align_center, qOverload(&QAbstractButton::clicked), this, &MRichTextEdit::textAlignCenter); + connect(f_align_right, qOverload(&QAbstractButton::clicked), this, &MRichTextEdit::textAlignRight); + connect(f_align_justify, qOverload(&QAbstractButton::clicked), this, &MRichTextEdit::textAlignJustify); QAction *removeFormat = new QAction(tr("Remove character formatting"), this); removeFormat->setShortcut(QKeySequence("CTRL+M")); - connect(removeFormat, SIGNAL(triggered()), this, SLOT(textRemoveFormat())); + connect(removeFormat, &QAction::triggered, this, &MRichTextEdit::textRemoveFormat); f_textedit->addAction(removeFormat); QAction *removeAllFormat = new QAction(tr("Remove all formatting"), this); - connect(removeAllFormat, SIGNAL(triggered()), this, SLOT(textRemoveAllFormat())); + connect(removeAllFormat, &QAction::triggered, this, &MRichTextEdit::textRemoveAllFormat); f_textedit->addAction(removeAllFormat); QAction *textsource = new QAction(tr("Edit document source"), this); textsource->setShortcut(QKeySequence("CTRL+O")); - connect(textsource, SIGNAL(triggered()), this, SLOT(textSource())); + connect(textsource, &QAction::triggered, this, &MRichTextEdit::textSource); f_textedit->addAction(textsource); QMenu *menu = new QMenu(this); @@ -182,21 +179,21 @@ MRichTextEdit::MRichTextEdit(QWidget *parent) : QWidget(parent) { f_list_bullet->setShortcut(Qt::CTRL | Qt::Key_Minus); f_list_ordered->setShortcut(Qt::CTRL | Qt::Key_Equal); - connect(f_list_bullet, SIGNAL(clicked(bool)), this, SLOT(listBullet(bool))); - connect(f_list_ordered, SIGNAL(clicked(bool)), this, SLOT(listOrdered(bool))); + connect(f_list_bullet, qOverload(&QAbstractButton::clicked), this, &MRichTextEdit::listBullet); + connect(f_list_ordered, qOverload(&QAbstractButton::clicked), this, &MRichTextEdit::listOrdered); // indentation f_indent_dec->setShortcut(Qt::CTRL | Qt::Key_Comma); f_indent_inc->setShortcut(Qt::CTRL | Qt::Key_Period); - connect(f_indent_inc, SIGNAL(clicked()), this, SLOT(increaseIndentation())); - connect(f_indent_dec, SIGNAL(clicked()), this, SLOT(decreaseIndentation())); + connect(f_indent_inc, &QAbstractButton::clicked, this, &MRichTextEdit::increaseIndentation); + connect(f_indent_dec, &QAbstractButton::clicked, this, &MRichTextEdit::decreaseIndentation); // font size QFontDatabase db; - foreach(int size, db.standardSizes()) + for (const int size : db.standardSizes()) f_fontsize->addItem(QString::number(size)); connect(f_fontsize, &QComboBox::textActivated, @@ -209,15 +206,15 @@ MRichTextEdit::MRichTextEdit(QWidget *parent) : QWidget(parent) { QPixmap pix(16, 16); pix.fill(QApplication::palette().window().color()); f_bgcolor->setIcon(pix); - connect(f_bgcolor, SIGNAL(clicked()), this, SLOT(textBgColor())); + connect(f_bgcolor, &QAbstractButton::clicked, this, &MRichTextEdit::textBgColor); QPixmap pix2(16, 16); pix2.fill(QApplication::palette().windowText().color()); f_fgcolor->setIcon(pix2); - connect(f_fgcolor, SIGNAL(clicked()), this, SLOT(textFgColor())); + connect(f_fgcolor, &QAbstractButton::clicked, this, &MRichTextEdit::textFgColor); // images - connect(f_image, SIGNAL(clicked()), this, SLOT(insertImage())); + connect(f_image, &QAbstractButton::clicked, this, &MRichTextEdit::insertImage); } diff --git a/widgets/nrfpair.cpp b/widgets/nrfpair.cpp index 9ce819b89..d0489f666 100644 --- a/widgets/nrfpair.cpp +++ b/widgets/nrfpair.cpp @@ -40,8 +40,7 @@ NrfPair::NrfPair(QWidget *parent) : mTimer = new QTimer(this); mTimer->start(100); - connect(mTimer, SIGNAL(timeout()), - this, SLOT(timerSlot())); + connect(mTimer, &QTimer::timeout, this, &NrfPair::timerSlot); } NrfPair::~NrfPair() @@ -59,8 +58,8 @@ void NrfPair::setVesc(VescInterface *vesc) mVesc = vesc; if (mVesc) { - connect(mVesc->commands(), SIGNAL(nrfPairingRes(int)), - this, SLOT(nrfPairingRes(int))); + connect(mVesc->commands(), &Commands::nrfPairingRes, + this, &NrfPair::nrfPairingRes); } } diff --git a/widgets/parameditbitfield.cpp b/widgets/parameditbitfield.cpp index 4727168aa..286e748f9 100644 --- a/widgets/parameditbitfield.cpp +++ b/widgets/parameditbitfield.cpp @@ -81,8 +81,7 @@ void ParamEditBitfield::setConfig(ConfigParams *config) ui->b7Box->setVisible(ui->b7Box->text().toLower() != "unused"); } - connect(mConfig, SIGNAL(paramChangedInt(QObject*,QString,int)), - this, SLOT(paramChangedInt(QObject*,QString,int))); + connect(mConfig, &ConfigParams::paramChangedInt, this, &ParamEditBitfield::paramChangedInt); } QString ParamEditBitfield::name() const diff --git a/widgets/parameditbool.cpp b/widgets/parameditbool.cpp index 354e09506..0d7cfd321 100644 --- a/widgets/parameditbool.cpp +++ b/widgets/parameditbool.cpp @@ -51,8 +51,7 @@ void ParamEditBool::setConfig(ConfigParams *config) ui->valueBox->setCurrentIndex(param->valInt ? 1 : 0); } - connect(mConfig, SIGNAL(paramChangedBool(QObject*,QString,bool)), - this, SLOT(paramChangedBool(QObject*,QString,bool))); + connect(mConfig, &ConfigParams::paramChangedBool, this, &ParamEditBool::paramChangedBool); } QString ParamEditBool::name() const diff --git a/widgets/parameditdouble.cpp b/widgets/parameditdouble.cpp index e7d785e27..965cc0a13 100644 --- a/widgets/parameditdouble.cpp +++ b/widgets/parameditdouble.cpp @@ -54,10 +54,8 @@ ParamEditDouble::ParamEditDouble(QWidget *parent) : mPercentageBox->setVisible(false); mDisplay->setVisible(false); - connect(mPercentageBox, SIGNAL(valueChanged(int)), - this, SLOT(percentageChanged(int))); - connect(mDoubleBox, SIGNAL(valueChanged(double)), - this, SLOT(doubleChanged(double))); + connect(mPercentageBox, qOverload(&QSpinBox::valueChanged), this, &ParamEditDouble::percentageChanged); + connect(mDoubleBox, qOverload(&QDoubleSpinBox::valueChanged), this, &ParamEditDouble::doubleChanged); } ParamEditDouble::~ParamEditDouble() @@ -97,8 +95,7 @@ void ParamEditDouble::setConfig(ConfigParams *config) } } - connect(mConfig, SIGNAL(paramChangedDouble(QObject*,QString,double)), - this, SLOT(paramChangedDouble(QObject*,QString,double))); + connect(mConfig, &ConfigParams::paramChangedDouble, this, &ParamEditDouble::paramChangedDouble); } QString ParamEditDouble::name() const diff --git a/widgets/parameditenum.cpp b/widgets/parameditenum.cpp index 54fc6fd11..698b2fec2 100644 --- a/widgets/parameditenum.cpp +++ b/widgets/parameditenum.cpp @@ -57,8 +57,7 @@ void ParamEditEnum::setConfig(ConfigParams *config) } } - connect(mConfig, SIGNAL(paramChangedEnum(QObject*,QString,int)), - this, SLOT(paramChangedEnum(QObject*,QString,int))); + connect(mConfig, &ConfigParams::paramChangedEnum, this, &ParamEditEnum::paramChangedEnum); } QString ParamEditEnum::name() const diff --git a/widgets/parameditint.cpp b/widgets/parameditint.cpp index 01fd0e14a..6d62a913a 100644 --- a/widgets/parameditint.cpp +++ b/widgets/parameditint.cpp @@ -53,10 +53,8 @@ ParamEditInt::ParamEditInt(QWidget *parent) : mPercentageBox->setVisible(false); mDisplay->setVisible(false); - connect(mIntBox, SIGNAL(valueChanged(int)), - this, SLOT(intChanged(int))); - connect(mPercentageBox, SIGNAL(valueChanged(int)), - this, SLOT(percentageChanged(int))); + connect(mIntBox, qOverload(&QSpinBox::valueChanged), this, &ParamEditInt::intChanged); + connect(mPercentageBox, qOverload(&QSpinBox::valueChanged), this, &ParamEditInt::percentageChanged); } ParamEditInt::~ParamEditInt() @@ -96,8 +94,7 @@ void ParamEditInt::setConfig(ConfigParams *config) } } - connect(mConfig, SIGNAL(paramChangedInt(QObject*,QString,int)), - this, SLOT(paramChangedInt(QObject*,QString,int))); + connect(mConfig, &ConfigParams::paramChangedInt, this, &ParamEditInt::paramChangedInt); } QString ParamEditInt::name() const diff --git a/widgets/parameditstring.cpp b/widgets/parameditstring.cpp index eeaa9291b..9c1a83853 100644 --- a/widgets/parameditstring.cpp +++ b/widgets/parameditstring.cpp @@ -53,8 +53,7 @@ void ParamEditString::setConfig(ConfigParams *config) } } - connect(mConfig, SIGNAL(paramChangedQString(QObject*,QString,QString)), - this, SLOT(paramChangedQString(QObject*,QString,QString))); + connect(mConfig, &ConfigParams::paramChangedQString, this, &ParamEditString::paramChangedQString); } QString ParamEditString::name() const diff --git a/widgets/paramtable.cpp b/widgets/paramtable.cpp index 650525715..a8c8b7f6c 100644 --- a/widgets/paramtable.cpp +++ b/widgets/paramtable.cpp @@ -89,7 +89,7 @@ void ParamTable::addRowSeparator(QString text) void ParamTable::addParamSubgroup(ConfigParams *params, QString groupName, QString subgroupName) { setUpdatesEnabled(false); - foreach (auto p, params->getParamsFromSubgroup(groupName, subgroupName)) { + for (const auto &p : params->getParamsFromSubgroup(groupName, subgroupName)) { if (p.startsWith("::sep::")) { addRowSeparator(p.mid(7)); } else { diff --git a/widgets/ppmmap.cpp b/widgets/ppmmap.cpp index 3d67e85e4..3480c409e 100644 --- a/widgets/ppmmap.cpp +++ b/widgets/ppmmap.cpp @@ -55,8 +55,8 @@ void PpmMap::setVesc(VescInterface *vesc) mVesc = vesc; if (mVesc) { - connect(mVesc->commands(), SIGNAL(decodedPpmReceived(double,double)), - this, SLOT(decodedPpmReceived(double,double))); + connect(mVesc->commands(), &Commands::decodedPpmReceived, + this, &PpmMap::decodedPpmReceived); } } From d4281208908ba14c23c53d0f245e0cac4a346c66 Mon Sep 17 00:00:00 2001 From: Felix Date: Sun, 8 Mar 2026 02:15:49 +0100 Subject: [PATCH 04/16] bugfix --- configparams.cpp | 16 ++++----- datatypes.h | 89 +++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 84 insertions(+), 21 deletions(-) diff --git a/configparams.cpp b/configparams.cpp index f8a60bbb2..a49ac6d46 100644 --- a/configparams.cpp +++ b/configparams.cpp @@ -19,6 +19,7 @@ #include "configparams.h" #include +#include #include "widgets/parameditdouble.h" #include "widgets/parameditint.h" #include "widgets/parameditstring.h" @@ -1206,19 +1207,17 @@ QString ConfigParams::saveCompressed(QString configName) getXML(stream, configName); std::size_t outMaxSize = lzokay::compress_worst_size(data.size()); - unsigned char *out = new unsigned char[outMaxSize]; + std::vector out(outMaxSize); std::size_t outLen = 0; - lzokay::EResult error = lzokay::compress((const uint8_t*)data.constData(), data.size(), out, outMaxSize, outLen); + lzokay::EResult error = lzokay::compress((const uint8_t*)data.constData(), data.size(), out.data(), outMaxSize, outLen); if (error == lzokay::EResult::Success) { - QByteArray data((char*)out, outLen); + QByteArray data((char*)out.data(), outLen); result = data.toBase64(); } else { qWarning() << "Could not compress data."; } - delete[] out; - return result; } @@ -1229,12 +1228,11 @@ bool ConfigParams::loadCompressed(QString data, QString configName) QByteArray in = QByteArray::fromBase64(data.toLocal8Bit()); std::size_t outMaxSize = 2 * 1024 * 1024; - unsigned char *out = new unsigned char[outMaxSize]; + std::vector out(outMaxSize); std::size_t outLen = 0; - lzokay::EResult error = lzokay::decompress((const uint8_t*)in.constData(), in.size(), out, outMaxSize, outLen); - QByteArray xmlData((const char*)out, outLen); - delete[] out; + lzokay::EResult error = lzokay::decompress((const uint8_t*)in.constData(), in.size(), out.data(), outMaxSize, outLen); + QByteArray xmlData((const char*)out.data(), outLen); if (error == lzokay::EResult::Success) { QXmlStreamReader stream(xmlData); diff --git a/datatypes.h b/datatypes.h index 1863f9a05..d8f97887b 100644 --- a/datatypes.h +++ b/datatypes.h @@ -214,9 +214,32 @@ struct MC_VALUES { } bool operator==(const MC_VALUES &other) const { - (void)other; - // compare members - return true; + return v_in == other.v_in && + temp_mos == other.temp_mos && + temp_mos_1 == other.temp_mos_1 && + temp_mos_2 == other.temp_mos_2 && + temp_mos_3 == other.temp_mos_3 && + temp_motor == other.temp_motor && + current_motor == other.current_motor && + current_in == other.current_in && + id == other.id && + iq == other.iq && + rpm == other.rpm && + duty_now == other.duty_now && + amp_hours == other.amp_hours && + amp_hours_charged == other.amp_hours_charged && + watt_hours == other.watt_hours && + watt_hours_charged == other.watt_hours_charged && + tachometer == other.tachometer && + tachometer_abs == other.tachometer_abs && + position == other.position && + fault_code == other.fault_code && + vesc_id == other.vesc_id && + fault_str == other.fault_str && + vd == other.vd && + vq == other.vq && + has_timeout == other.has_timeout && + kill_sw_active == other.kill_sw_active; } bool operator!=(MC_VALUES const &other) const { @@ -307,9 +330,29 @@ struct SETUP_VALUES { } bool operator==(const SETUP_VALUES &other) const { - (void)other; - // compare members - return true; + return temp_mos == other.temp_mos && + temp_motor == other.temp_motor && + current_motor == other.current_motor && + current_in == other.current_in && + duty_now == other.duty_now && + rpm == other.rpm && + speed == other.speed && + v_in == other.v_in && + battery_level == other.battery_level && + amp_hours == other.amp_hours && + amp_hours_charged == other.amp_hours_charged && + watt_hours == other.watt_hours && + watt_hours_charged == other.watt_hours_charged && + tachometer == other.tachometer && + tachometer_abs == other.tachometer_abs && + position == other.position && + fault_code == other.fault_code && + vesc_id == other.vesc_id && + num_vescs == other.num_vescs && + battery_wh == other.battery_wh && + fault_str == other.fault_str && + odometer == other.odometer && + uptime_ms == other.uptime_ms; } bool operator!=(SETUP_VALUES const &other) const { @@ -386,9 +429,23 @@ struct IMU_VALUES { } bool operator==(const IMU_VALUES &other) const { - (void)other; - // compare members - return true; + return roll == other.roll && + pitch == other.pitch && + yaw == other.yaw && + accX == other.accX && + accY == other.accY && + accZ == other.accZ && + gyroX == other.gyroX && + gyroY == other.gyroY && + gyroZ == other.gyroZ && + magX == other.magX && + magY == other.magY && + magZ == other.magZ && + q0 == other.q0 && + q1 == other.q1 && + q2 == other.q2 && + q3 == other.q3 && + vesc_id == other.vesc_id; } bool operator!=(IMU_VALUES const &other) const { @@ -452,9 +509,17 @@ struct STAT_VALUES { } bool operator==(const STAT_VALUES &other) const { - (void)other; - // compare members - return true; + return speed_avg == other.speed_avg && + speed_max == other.speed_max && + power_avg == other.power_avg && + power_max == other.power_max && + temp_motor_avg == other.temp_motor_avg && + temp_motor_max == other.temp_motor_max && + temp_mos_avg == other.temp_mos_avg && + temp_mos_max == other.temp_mos_max && + current_avg == other.current_avg && + current_max == other.current_max && + count_time == other.count_time; } bool operator!=(STAT_VALUES const &other) const { From 2828ce3601971adc8faf29d5011354967283254e Mon Sep 17 00:00:00 2001 From: Felix Date: Sun, 8 Mar 2026 03:03:55 +0100 Subject: [PATCH 05/16] feat: Introduce QtTaskTree and common task abstractions --- CMakeLists.txt | 3 + vesctasks.h | 498 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 501 insertions(+) create mode 100644 vesctasks.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 9c4aa5acf..6324ba130 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -54,6 +54,7 @@ set(QT_COMPONENTS OpenGL OpenGLWidgets Core5Compat + TaskTree ) # --------------------------------------------------------------------------- @@ -215,6 +216,7 @@ set(ROOT_HEADERS configparams.h configparam.h vescinterface.h + vesctasks.h parametereditor.h digitalfiltering.h setupwizardapp.h @@ -844,6 +846,7 @@ set(QT_LINK_LIBS Qt6::OpenGL Qt6::OpenGLWidgets Qt6::Core5Compat + Qt6::TaskTree ) if(NOT IOS) diff --git a/vesctasks.h b/vesctasks.h new file mode 100644 index 000000000..f009d022c --- /dev/null +++ b/vesctasks.h @@ -0,0 +1,498 @@ +/* + Copyright 2025 Felix van der Donk + + This file is part of VESC Tool. + + VESC Tool is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + VESC Tool 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. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifndef VESCTASKS_H +#define VESCTASKS_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace QtTaskTree; + +// ============================================================================ +// SignalWaitTask — waits for an arbitrary signal with a timeout. +// +// This is the core building block replacing every QEventLoop pattern in the +// codebase. Use it through its QCustomTask alias `SignalWaitTaskItem`. +// +// The setup handler must: +// 1. Call task.setTimeout() if a non-default timeout is needed. +// 2. Call task.connectSignal() to tell it which signal to wait for. +// 3. Optionally send the command that will eventually produce the signal. +// +// When the awaited signal fires the captured data is stored inside the task +// (via a user-provided lambda) and the task reports DoneResult::Success. +// On timeout it reports DoneResult::Error. +// ============================================================================ + +class SignalWaitTask : public QObject +{ + Q_OBJECT + +public: + explicit SignalWaitTask(QObject *parent = nullptr) + : QObject(parent) + {} + + void setTimeout(int ms) { m_timeoutMs = ms; } + int timeout() const { return m_timeoutMs; } + + /// Connect to an arbitrary signal. When that signal fires, `onSignal` is + /// invoked (to capture data) and the task completes successfully. + template + void connectSignal(Sender *sender, Signal signal, Slot &&onSignal) { + m_conn = QObject::connect(sender, signal, this, [this, onSignal = std::forward(onSignal)](auto&&... args) { + std::invoke(onSignal, std::forward(args)...); + m_succeeded = true; + emit done(DoneResult::Success); + }); + } + + /// Overload when no data capture is needed — just wait for the signal. + template + void connectSignal(Sender *sender, Signal signal) { + m_conn = QObject::connect(sender, signal, this, [this]() { + m_succeeded = true; + emit done(DoneResult::Success); + }); + } + + /// String-based overload for QML callers where the signal is a runtime + /// string (e.g. SIGNAL(updated())). Uses old-style connect. + void connectStringSignal(QObject *sender, const char *signal) { + m_conn = QObject::connect(sender, signal, + this, SLOT(onStringSignalFired())); + } + + void start() { + m_timer.setSingleShot(true); + connect(&m_timer, &QTimer::timeout, this, [this]() { + if (!m_succeeded) { + emit done(DoneResult::Error); + } + }); + m_timer.start(m_timeoutMs); + } + + ~SignalWaitTask() override { + QObject::disconnect(m_conn); + } + + bool succeeded() const { return m_succeeded; } + +signals: + void done(DoneResult result); + +private slots: + void onStringSignalFired() { + m_succeeded = true; + emit done(DoneResult::Success); + } + +private: + QTimer m_timer; + QMetaObject::Connection m_conn; + int m_timeoutMs = 3000; + bool m_succeeded = false; +}; + +/// The QCustomTask alias used in task trees: +/// SignalWaitTaskItem([](SignalWaitTask &task) { ... setup ... }) +using SignalWaitTaskItem = QCustomTask; + +// ============================================================================ +// DelayTask — a pure delay (replaces Utility::sleepWithEventLoop). +// +// Just use QtTaskTree::timeoutTask(std::chrono::milliseconds{ms}) instead. +// This alias exists for documentation clarity. +// ============================================================================ + +// Use timeoutTask(ms, DoneResult::Success) for a sleep. + +// ============================================================================ +// NetworkReplyTask — downloads from a URL and provides the reply data. +// +// Setup handler sets URL (and optionally a progress callback). +// On success the reply data is available via replyData(). +// ============================================================================ + +class NetworkReplyTask : public QObject +{ + Q_OBJECT + +public: + explicit NetworkReplyTask(QObject *parent = nullptr) + : QObject(parent) + {} + + void setUrl(const QUrl &url) { m_url = url; } + void setProgressCallback(std::function cb) { m_progressCb = std::move(cb); } + + /// If set, incoming data is incrementally written to this device instead of + /// being buffered in memory. + void setOutputDevice(QIODevice *dev) { m_outputDevice = dev; } + + QByteArray replyData() const { return m_data; } + QNetworkReply::NetworkError error() const { return m_error; } + + void start() { + m_reply = m_manager.get(QNetworkRequest(m_url)); + + connect(m_reply, &QNetworkReply::downloadProgress, this, + [this](qint64 bytesReceived, qint64 bytesTotal) { + if (m_outputDevice) { + m_outputDevice->write(m_reply->read(m_reply->size())); + } + if (m_progressCb) { + m_progressCb(bytesReceived, bytesTotal); + } + }); + + connect(m_reply, &QNetworkReply::finished, this, [this]() { + m_error = m_reply->error(); + if (m_outputDevice) { + m_outputDevice->write(m_reply->readAll()); + } else { + m_data = m_reply->readAll(); + } + m_reply->deleteLater(); + m_reply = nullptr; + emit done(m_error == QNetworkReply::NoError ? DoneResult::Success : DoneResult::Error); + }); + } + + ~NetworkReplyTask() override { + if (m_reply) { + m_reply->abort(); + m_reply->deleteLater(); + } + } + +signals: + void done(DoneResult result); + +private: + QNetworkAccessManager m_manager; + QNetworkReply *m_reply = nullptr; + QUrl m_url; + QByteArray m_data; + QNetworkReply::NetworkError m_error = QNetworkReply::NoError; + std::function m_progressCb; + QIODevice *m_outputDevice = nullptr; +}; + +using NetworkReplyTaskItem = QCustomTask; + +// ============================================================================ +// ProcessTask — runs a QProcess and waits for it to finish. +// +// Replaces MainWindow::waitProcess and SystemCommandExecutor::executeCommand. +// ============================================================================ + +class ProcessTask : public QObject +{ + Q_OBJECT + +public: + explicit ProcessTask(QObject *parent = nullptr) + : QObject(parent) + {} + + void setProgram(const QString &program) { m_program = program; } + void setArguments(const QStringList &args) { m_arguments = args; } + void setTimeout(int ms) { m_timeoutMs = ms; } + void setStdOutCallback(std::function cb) { m_stdOutCb = std::move(cb); } + void setStdErrCallback(std::function cb) { m_stdErrCb = std::move(cb); } + + int exitCode() const { return m_exitCode; } + bool wasKilled() const { return m_killed; } + QByteArray standardOutput() const { return m_stdOut; } + QByteArray standardError() const { return m_stdErr; } + + void start() { + connect(&m_process, &QProcess::finished, this, [this](int exitCode, QProcess::ExitStatus) { + m_exitCode = exitCode; + emit done(DoneResult::Success); + }); + + connect(&m_process, &QProcess::errorOccurred, this, [this](QProcess::ProcessError) { + if (!m_killed) { + m_exitCode = -1; + emit done(DoneResult::Error); + } + }); + + connect(&m_process, &QProcess::readyReadStandardOutput, this, [this]() { + auto data = m_process.readAllStandardOutput(); + m_stdOut.append(data); + if (m_stdOutCb) m_stdOutCb(QString::fromUtf8(data)); + }); + + connect(&m_process, &QProcess::readyReadStandardError, this, [this]() { + auto data = m_process.readAllStandardError(); + m_stdErr.append(data); + if (m_stdErrCb) m_stdErrCb(QString::fromUtf8(data)); + }); + + if (m_timeoutMs > 0) { + m_timer.setSingleShot(true); + connect(&m_timer, &QTimer::timeout, this, [this]() { + m_killed = true; + m_process.kill(); + m_process.waitForFinished(1000); + emit done(DoneResult::Error); + }); + m_timer.start(m_timeoutMs); + } + + m_process.start(m_program, m_arguments); + } + + ~ProcessTask() override { + if (m_process.state() == QProcess::Running) { + m_process.kill(); + m_process.waitForFinished(1000); + } + } + +signals: + void done(DoneResult result); + +private: + QProcess m_process; + QTimer m_timer; + QString m_program; + QStringList m_arguments; + int m_timeoutMs = 0; + int m_exitCode = -1; + bool m_killed = false; + QByteArray m_stdOut; + QByteArray m_stdErr; + std::function m_stdOutCb; + std::function m_stdErrCb; +}; + +using ProcessTaskItem = QCustomTask; + +// ============================================================================ +// TcpConnectTask — connects a QTcpSocket with timeout. +// ============================================================================ + +class TcpConnectTask : public QObject +{ + Q_OBJECT + +public: + explicit TcpConnectTask(QObject *parent = nullptr) + : QObject(parent) + {} + + void setSocket(QTcpSocket *socket) { m_socket = socket; } + void setHost(const QHostAddress &host) { m_host = host; } + void setPort(quint16 port) { m_port = port; } + void setTimeout(int ms) { m_timeoutMs = ms; } + void setOnConnected(std::function cb) { m_onConnected = std::move(cb); } + + void start() { + m_timer.setSingleShot(true); + connect(&m_timer, &QTimer::timeout, this, [this]() { + emit done(DoneResult::Error); + }); + + connect(m_socket, &QTcpSocket::connected, this, [this]() { + m_timer.stop(); + if (m_onConnected) m_onConnected(); + emit done(DoneResult::Success); + }); + + m_timer.start(m_timeoutMs); + m_socket->connectToHost(m_host, m_port); + } + +signals: + void done(DoneResult result); + +private: + QTcpSocket *m_socket = nullptr; + QHostAddress m_host; + quint16 m_port = 0; + int m_timeoutMs = 3000; + QTimer m_timer; + std::function m_onConnected; +}; + +using TcpConnectTaskItem = QCustomTask; + +// ============================================================================ +// SocketLineReaderTask — reads lines from a socket until newline with timeout. +// ============================================================================ + +class SocketLineReaderTask : public QObject +{ + Q_OBJECT + +public: + explicit SocketLineReaderTask(QObject *parent = nullptr) + : QObject(parent) + {} + + void setSocket(QTcpSocket *socket) { m_socket = socket; } + void setTimeout(int ms) { m_timeoutMs = ms; } + + QString line() const { return m_line; } + + void start() { + m_timer.setSingleShot(true); + connect(&m_timer, &QTimer::timeout, this, [this]() { + m_line.clear(); + emit done(DoneResult::Error); + }); + m_timer.start(m_timeoutMs); + + m_readConn = connect(m_socket, &QTcpSocket::readyRead, this, [this]() { + while (m_socket->bytesAvailable() > 0) { + QByteArray rxb = m_socket->read(1); + if (rxb.size() == 1) { + if (rxb[0] != '\n') { + m_buffer.append(rxb[0]); + } else { + m_buffer.append('\0'); + m_line = QString::fromLocal8Bit(m_buffer); + m_timer.stop(); + emit done(DoneResult::Success); + return; + } + } + } + }); + } + + ~SocketLineReaderTask() override { + QObject::disconnect(m_readConn); + } + +signals: + void done(DoneResult result); + +private: + QTcpSocket *m_socket = nullptr; + QTimer m_timer; + int m_timeoutMs = 3000; + QByteArray m_buffer; + QString m_line; + QMetaObject::Connection m_readConn; +}; + +using SocketLineReaderTaskItem = QCustomTask; + +// ============================================================================ +// PollTimerTask — runs a periodic timer callback until an external condition +// triggers completion. Replaces patterns like testDirection() and +// scanCANbus() that use QTimer + QEventLoop. +// ============================================================================ + +class PollTimerTask : public QObject +{ + Q_OBJECT + +public: + explicit PollTimerTask(QObject *parent = nullptr) + : QObject(parent) + {} + + void setTimeout(int ms) { m_timeoutMs = ms; } + void setInterval(int ms) { m_intervalMs = ms; } + void setOnTick(std::function cb) { m_onTick = std::move(cb); } + + /// Call this from within the tick callback to end early with success. + void finish() { + m_timer.stop(); + m_pollTimer.stop(); + emit done(DoneResult::Success); + } + + void start() { + if (m_timeoutMs > 0) { + m_timer.setSingleShot(true); + connect(&m_timer, &QTimer::timeout, this, [this]() { + m_pollTimer.stop(); + emit done(DoneResult::Success); // timeout = normal completion for poll tasks + }); + m_timer.start(m_timeoutMs); + } + + connect(&m_pollTimer, &QTimer::timeout, this, [this]() { + if (m_onTick) m_onTick(); + }); + m_pollTimer.start(m_intervalMs); + } + +signals: + void done(DoneResult result); + +private: + QTimer m_timer; + QTimer m_pollTimer; + int m_timeoutMs = 0; + int m_intervalMs = 100; + std::function m_onTick; +}; + +using PollTimerTaskItem = QCustomTask; + +// ============================================================================ +// runTree — convenience to synchronously run a TaskTree. +// +// This is the ONLY place we still block the caller using a local event loop, +// but it's inside a well-defined QTaskTree so we get proper cancellation +// semantics and no re-entrancy issues. +// +// Usage: +// bool ok = runTree({Group{...}}); +// +// For truly async code, construct a QTaskTree yourself and connect to done(). +// ============================================================================ + +inline bool runTree(const Group &root) +{ + QTaskTree tree(root); + bool success = false; + QEventLoop loop; + QObject::connect(&tree, &QTaskTree::done, &loop, [&success, &loop](DoneWith result) { + success = (result == DoneWith::Success); + loop.quit(); + }); + tree.start(); + if (tree.isRunning()) + loop.exec(); + return success; +} + +#endif // VESCTASKS_H From 6f6c5f1e91829595e5e551b39ada09813845a7b9 Mon Sep 17 00:00:00 2001 From: Felix Date: Sun, 8 Mar 2026 03:03:55 +0100 Subject: [PATCH 06/16] refactor: Remove QEventLoop and QTimer includes, add vesctasks.h where needed --- boardsetupwindow.cpp | 1 - codeloader.cpp | 3 +-- commands.cpp | 2 +- mainwindow.cpp | 2 +- systemcommandexecutor.h | 3 +-- tcphub.cpp | 1 - tcpserversimple.cpp | 3 +-- utility.cpp | 3 ++- utility.h | 1 + vescinterface.cpp | 3 +-- 10 files changed, 9 insertions(+), 13 deletions(-) diff --git a/boardsetupwindow.cpp b/boardsetupwindow.cpp index 9de7a109f..8849e24c1 100644 --- a/boardsetupwindow.cpp +++ b/boardsetupwindow.cpp @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include diff --git a/codeloader.cpp b/codeloader.cpp index 830f22a85..7b3849a6a 100644 --- a/codeloader.cpp +++ b/codeloader.cpp @@ -20,14 +20,13 @@ #include "codeloader.h" #include "qqmlcontext.h" #include "utility.h" -#include +#include "vesctasks.h" #include #include #include #include #include #include -#include #include #include #include diff --git a/commands.cpp b/commands.cpp index 1ec436dca..f2c4f6568 100755 --- a/commands.cpp +++ b/commands.cpp @@ -18,9 +18,9 @@ */ #include "commands.h" +#include "vesctasks.h" #include "qelapsedtimer.h" #include -#include Commands::Commands(QObject *parent) : QObject(parent) { diff --git a/mainwindow.cpp b/mainwindow.cpp index b60f7e815..e5f758617 100755 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -26,7 +26,7 @@ #include #include #include -#include +#include "vesctasks.h" #include #include #include "parametereditor.h" diff --git a/systemcommandexecutor.h b/systemcommandexecutor.h index 1ec82e5dc..59aec28ae 100644 --- a/systemcommandexecutor.h +++ b/systemcommandexecutor.h @@ -3,9 +3,8 @@ #include #include -#include -#include #include +#include "vesctasks.h" class SystemCommandExecutor : public QObject { diff --git a/tcphub.cpp b/tcphub.cpp index ba44b3038..3ac07e907 100644 --- a/tcphub.cpp +++ b/tcphub.cpp @@ -21,7 +21,6 @@ #include "tcphub.h" #include "utility.h" #include -#include #include #include diff --git a/tcpserversimple.cpp b/tcpserversimple.cpp index f08816517..b97db082e 100644 --- a/tcpserversimple.cpp +++ b/tcpserversimple.cpp @@ -20,8 +20,7 @@ #include "tcpserversimple.h" #include #include -#include -#include +#include "vesctasks.h" TcpServerSimple::TcpServerSimple(QObject *parent) : QObject(parent) { diff --git a/utility.cpp b/utility.cpp index 7874e7c54..f4a01e4db 100755 --- a/utility.cpp +++ b/utility.cpp @@ -18,12 +18,12 @@ */ #include "utility.h" +#include "vesctasks.h" #ifdef Q_OS_IOS #include "ios/src/setIosParameters.h" #endif #include #include -#include #include #include #include @@ -37,6 +37,7 @@ #include #include #include +#include #include "maddy/parser.h" #include "heatshrink/heatshrinkif.h" diff --git a/utility.h b/utility.h index 6b6b29710..6193eafcd 100644 --- a/utility.h +++ b/utility.h @@ -29,6 +29,7 @@ #include "vescinterface.h" #include "widgets/qcustomplot.h" #include "datatypes.h" +#include "vesctasks.h" #define FE_WGS84 (1.0/298.257223563) // earth flattening (WGS84) #define RE_WGS84 6378137.0 // earth semimajor axis (WGS84) (m) diff --git a/vescinterface.cpp b/vescinterface.cpp index d8777a351..6be473ee2 100755 --- a/vescinterface.cpp +++ b/vescinterface.cpp @@ -22,7 +22,6 @@ #include #include #include -#include #include #include #include @@ -30,6 +29,7 @@ #include #include "lzokay/lzokay.hpp" #include "vescinterface.h" +#include "vesctasks.h" #include "utility.h" #include "heatshrink/heatshrinkif.h" @@ -41,7 +41,6 @@ #include #include #include -#include #ifdef HAS_CANBUS #include From 3b13b9154b3cb3ef3d770cfb48fef5a924fe1777 Mon Sep 17 00:00:00 2001 From: Felix Date: Sun, 8 Mar 2026 03:03:55 +0100 Subject: [PATCH 07/16] refactor(CodeLoader): Convert blocking operations to QtTaskTree --- codeloader.cpp | 146 +++++++++++++++---------------------------------- 1 file changed, 43 insertions(+), 103 deletions(-) diff --git a/codeloader.cpp b/codeloader.cpp index 7b3849a6a..cfcc98713 100644 --- a/codeloader.cpp +++ b/codeloader.cpp @@ -72,21 +72,12 @@ bool CodeLoader::lispErase(int size) auto waitEraseRes = [this]() { int res = -10; - - QEventLoop loop; - QTimer timeoutTimer; - timeoutTimer.setSingleShot(true); - timeoutTimer.start(8000); - auto conn = connect(mVesc->commands(), &Commands::lispEraseCodeRx, - [&res,&loop](bool erRes) { - res = erRes ? 1 : -1; - loop.quit(); - }); - - connect(&timeoutTimer, &QTimer::timeout, &loop, &QEventLoop::quit); - loop.exec(); - - disconnect(conn); + runTree(Group{SignalWaitTaskItem([this, &res](SignalWaitTask &task) { + task.setTimeout(8000); + task.connectSignal(mVesc->commands(), &Commands::lispEraseCodeRx, + [&res](bool erRes) { res = erRes ? 1 : -1; }); + return SetupResult::Continue; + })}); return res; }; @@ -393,22 +384,12 @@ bool CodeLoader::lispUpload(VByteArray vb) auto waitWriteRes = [this]() { int res = -10; - - QEventLoop loop; - QTimer timeoutTimer; - timeoutTimer.setSingleShot(true); - timeoutTimer.start(1000); - auto conn = connect(mVesc->commands(), &Commands::lispWriteCodeRx, - [&res,&loop](bool erRes, quint32 offset) { - (void)offset; - res = erRes ? 1 : -1; - loop.quit(); - }); - - connect(&timeoutTimer, &QTimer::timeout, &loop, &QEventLoop::quit); - loop.exec(); - - disconnect(conn); + runTree(Group{SignalWaitTaskItem([this, &res](SignalWaitTask &task) { + task.setTimeout(1000); + task.connectSignal(mVesc->commands(), &Commands::lispWriteCodeRx, + [&res](bool erRes, quint32) { res = erRes ? 1 : -1; }); + return SetupResult::Continue; + })}); return res; }; @@ -494,22 +475,12 @@ bool CodeLoader::lispStream(VByteArray vb, qint8 mode) auto waitWriteRes = [this]() { int res = -10; - - QEventLoop loop; - QTimer timeoutTimer; - timeoutTimer.setSingleShot(true); - timeoutTimer.start(4000); - auto conn = connect(mVesc->commands(), &Commands::lispStreamCodeRx, - [&res,&loop](qint32 offset, qint16 result) { - (void)offset; - res = result; - loop.quit(); - }); - - connect(&timeoutTimer, &QTimer::timeout, &loop, &QEventLoop::quit); - loop.exec(); - - disconnect(conn); + runTree(Group{SignalWaitTaskItem([this, &res](SignalWaitTask &task) { + task.setTimeout(4000); + task.connectSignal(mVesc->commands(), &Commands::lispStreamCodeRx, + [&res](qint32, qint16 result) { res = result; }); + return SetupResult::Continue; + })}); return res; }; @@ -696,21 +667,12 @@ bool CodeLoader::qmlErase(int size) auto waitEraseRes = [this]() { int res = -10; - - QEventLoop loop; - QTimer timeoutTimer; - timeoutTimer.setSingleShot(true); - timeoutTimer.start(6000); - auto conn = connect(mVesc->commands(), &Commands::eraseQmluiResReceived, - [&res,&loop](bool erRes) { - res = erRes ? 1 : -1; - loop.quit(); - }); - - connect(&timeoutTimer, &QTimer::timeout, &loop, &QEventLoop::quit); - loop.exec(); - - disconnect(conn); + runTree(Group{SignalWaitTaskItem([this, &res](SignalWaitTask &task) { + task.setTimeout(6000); + task.connectSignal(mVesc->commands(), &Commands::eraseQmluiResReceived, + [&res](bool erRes) { res = erRes ? 1 : -1; }); + return SetupResult::Continue; + })}); return res; }; @@ -744,22 +706,12 @@ bool CodeLoader::qmlUpload(QByteArray script, bool isFullscreen) { auto waitWriteRes = [this]() { int res = -10; - - QEventLoop loop; - QTimer timeoutTimer; - timeoutTimer.setSingleShot(true); - timeoutTimer.start(1000); - auto conn = connect(mVesc->commands(), &Commands::writeQmluiResReceived, - [&res,&loop](bool erRes, quint32 offset) { - (void)offset; - res = erRes ? 1 : -1; - loop.quit(); - }); - - connect(&timeoutTimer, &QTimer::timeout, &loop, &QEventLoop::quit); - loop.exec(); - - disconnect(conn); + runTree(Group{SignalWaitTaskItem([this, &res](SignalWaitTask &task) { + task.setTimeout(1000); + task.connectSignal(mVesc->commands(), &Commands::writeQmluiResReceived, + [&res](bool erRes, quint32) { res = erRes ? 1 : -1; }); + return SetupResult::Continue; + })}); return res; }; @@ -1098,31 +1050,19 @@ bool CodeLoader::downloadPackageArchive() QFile file(path); if (file.open(QIODevice::WriteOnly)) { - QUrl url("http://home.vedder.se/vesc_pkg/vesc_pkg_all.rcc"); - QNetworkAccessManager manager; - QNetworkRequest request(url); - QNetworkReply *reply = manager.get(request); - - connect(reply, &QNetworkReply::downloadProgress, [&file, reply, this](qint64 bytesReceived, qint64 bytesTotal) { - emit downloadProgress(bytesReceived, bytesTotal); - file.write(reply->read(reply->size())); - }); - - QEventLoop loop; - connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit); - loop.exec(); - - if (reply->error() == QNetworkReply::NoError) { - file.write(reply->readAll()); - res = true; - - // Remove image cache - // QString cacheLoc = QStandardPaths::writableLocation(QStandardPaths::CacheLocation); - // QDir(cacheLoc + "/img/").removeRecursively(); - } - - reply->abort(); - reply->deleteLater(); + runTree(Group{NetworkReplyTaskItem([this, &file](NetworkReplyTask &task) { + task.setUrl(QUrl("http://home.vedder.se/vesc_pkg/vesc_pkg_all.rcc")); + task.setOutputDevice(&file); + task.setProgressCallback([this](qint64 bytesReceived, qint64 bytesTotal) { + emit downloadProgress(bytesReceived, bytesTotal); + }); + return SetupResult::Continue; + }, [&res](const NetworkReplyTask &task, DoneWith doneWith) { + if (doneWith == DoneWith::Success) { + res = true; + } + return DoneResult::Success; + })}); file.close(); From 5ce069ea30d8233e33eab336e63af7d3d0a054a9 Mon Sep 17 00:00:00 2001 From: Felix Date: Sun, 8 Mar 2026 03:03:55 +0100 Subject: [PATCH 08/16] refactor(Commands): Convert blocking operations to QtTaskTree --- commands.cpp | 161 +++++++++++++++++++-------------------------------- 1 file changed, 58 insertions(+), 103 deletions(-) diff --git a/commands.cpp b/commands.cpp index f2c4f6568..f7b595af9 100755 --- a/commands.cpp +++ b/commands.cpp @@ -2426,22 +2426,17 @@ QVariantList Commands::fileBlockList(QString path) bool res = false; bool more = false; - QEventLoop loop; - QTimer timeoutTimer; - timeoutTimer.setSingleShot(true); - timeoutTimer.start(1500); - auto conn = connect(this, &Commands::fileListRx, - [&res,&loop,&filesNow,&more](bool hasMore, QList files) { - filesNow.append(files); - res = true; - more = hasMore; - loop.quit(); - }); - - connect(&timeoutTimer, &QTimer::timeout, &loop, &QEventLoop::quit); - loop.exec(); + runTree(Group{SignalWaitTaskItem([this, &res, &filesNow, &more](SignalWaitTask &task) { + task.setTimeout(1500); + task.connectSignal(this, &Commands::fileListRx, + [&res, &filesNow, &more](bool hasMore, QList files) { + filesNow.append(files); + res = true; + more = hasMore; + }); + return SetupResult::Continue; + })}); - disconnect(conn); return qMakePair(res, more); }; @@ -2494,28 +2489,22 @@ QByteArray Commands::fileBlockRead(QString path) mFileShouldCancel = false; auto waitRes = [this](QByteArray &dataNow, qint32 offsetNow) { - qint32 sizeRet = -1.0; - - QEventLoop loop; - QTimer timeoutTimer; - timeoutTimer.setSingleShot(true); - timeoutTimer.start(1500); - auto conn = connect(this, &Commands::fileReadRx, - [&sizeRet,&loop,&dataNow,&offsetNow] - (qint32 offset, qint32 size, QByteArray data) { - if (offset == offsetNow) { - sizeRet = size; - dataNow.append(data); - } else { - qWarning() << "Wrong offset"; - } - loop.quit(); - }); - - connect(&timeoutTimer, &QTimer::timeout, &loop, &QEventLoop::quit); - loop.exec(); + qint32 sizeRet = -1; + + runTree(Group{SignalWaitTaskItem([this, &sizeRet, &dataNow, &offsetNow](SignalWaitTask &task) { + task.setTimeout(1500); + task.connectSignal(this, &Commands::fileReadRx, + [&sizeRet, &dataNow, &offsetNow](qint32 offset, qint32 size, QByteArray data) { + if (offset == offsetNow) { + sizeRet = size; + dataNow.append(data); + } else { + qWarning() << "Wrong offset"; + } + }); + return SetupResult::Continue; + })}); - disconnect(conn); return sizeRet; }; @@ -2564,21 +2553,12 @@ bool Commands::fileBlockWrite(QString path, QByteArray data) auto waitRes = [this]() { bool res = false; - QEventLoop loop; - QTimer timeoutTimer; - timeoutTimer.setSingleShot(true); - timeoutTimer.start(1500); - auto conn = connect(this, &Commands::fileWriteRx, - [&res,&loop] - (qint32 offset, bool ok) { - (void)offset; - res = ok; - loop.quit(); - }); - - connect(&timeoutTimer, &QTimer::timeout, &loop, &QEventLoop::quit); - loop.exec(); - disconnect(conn); + runTree(Group{SignalWaitTaskItem([this, &res](SignalWaitTask &task) { + task.setTimeout(1500); + task.connectSignal(this, &Commands::fileWriteRx, + [&res](qint32, bool ok) { res = ok; }); + return SetupResult::Continue; + })}); return res; }; @@ -2632,19 +2612,12 @@ bool Commands::fileBlockMkdir(QString path) auto waitRes = [this]() { bool res = false; - QEventLoop loop; - QTimer timeoutTimer; - timeoutTimer.setSingleShot(true); - timeoutTimer.start(1500); - auto conn = connect(this, &Commands::fileMkdirRx, - [&res,&loop](bool ok) { - res = ok; - loop.quit(); - }); - - connect(&timeoutTimer, &QTimer::timeout, &loop, &QEventLoop::quit); - loop.exec(); - disconnect(conn); + runTree(Group{SignalWaitTaskItem([this, &res](SignalWaitTask &task) { + task.setTimeout(1500); + task.connectSignal(this, &Commands::fileMkdirRx, + [&res](bool ok) { res = ok; }); + return SetupResult::Continue; + })}); return res; }; @@ -2671,19 +2644,12 @@ bool Commands::fileBlockRemove(QString path) auto waitRes = [this]() { bool res = false; - QEventLoop loop; - QTimer timeoutTimer; - timeoutTimer.setSingleShot(true); - timeoutTimer.start(1500); - auto conn = connect(this, &Commands::fileRemoveRx, - [&res,&loop](bool ok) { - res = ok; - loop.quit(); - }); - - connect(&timeoutTimer, &QTimer::timeout, &loop, &QEventLoop::quit); - loop.exec(); - disconnect(conn); + runTree(Group{SignalWaitTaskItem([this, &res](SignalWaitTask &task) { + task.setTimeout(1500); + task.connectSignal(this, &Commands::fileRemoveRx, + [&res](bool ok) { res = ok; }); + return SetupResult::Continue; + })}); return res; }; @@ -2790,21 +2756,16 @@ QByteArray Commands::bmReadMemWait(uint32_t addr, quint16 size, int timeoutMs) int res = -10; QByteArray resData; - QEventLoop loop; - QTimer timeoutTimer; - timeoutTimer.setSingleShot(true); - timeoutTimer.start(timeoutMs); - auto conn = connect(this, &Commands::bmReadMemRes, [&res,&resData,&loop] - (int rdRes, QByteArray data) { - res = rdRes; - resData = data; - loop.quit(); - }); - - connect(&timeoutTimer, &QTimer::timeout, &loop, &QEventLoop::quit); - loop.exec(); + runTree(Group{SignalWaitTaskItem([this, &res, &resData, timeoutMs](SignalWaitTask &task) { + task.setTimeout(timeoutMs); + task.connectSignal(this, &Commands::bmReadMemRes, + [&res, &resData](int rdRes, QByteArray data) { + res = rdRes; + resData = data; + }); + return SetupResult::Continue; + })}); - disconnect(conn); return resData; } @@ -2814,19 +2775,13 @@ int Commands::bmWriteMemWait(uint32_t addr, QByteArray data, int timeoutMs) int res = -10; - QEventLoop loop; - QTimer timeoutTimer; - timeoutTimer.setSingleShot(true); - timeoutTimer.start(timeoutMs); - auto conn = connect(this, &Commands::bmWriteFlashRes, [&res,&loop](int wrRes) { - res = wrRes; - loop.quit(); - }); - - connect(&timeoutTimer, &QTimer::timeout, &loop, &QEventLoop::quit); - loop.exec(); + runTree(Group{SignalWaitTaskItem([this, &res, timeoutMs](SignalWaitTask &task) { + task.setTimeout(timeoutMs); + task.connectSignal(this, &Commands::bmWriteFlashRes, + [&res](int wrRes) { res = wrRes; }); + return SetupResult::Continue; + })}); - disconnect(conn); return res; } From 021016b008e8baa6848b0fea8e590aa005aad296 Mon Sep 17 00:00:00 2001 From: Felix Date: Sun, 8 Mar 2026 03:03:56 +0100 Subject: [PATCH 09/16] refactor(UI/Process): Convert blocking operations to QtTaskTree --- mainwindow.cpp | 17 +++++++------ systemcommandexecutor.h | 53 ++++++++++++++++------------------------- 2 files changed, 31 insertions(+), 39 deletions(-) diff --git a/mainwindow.cpp b/mainwindow.cpp index e5f758617..8278f5b2b 100755 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -1845,13 +1845,16 @@ bool MainWindow::waitProcess(QProcess &process, bool block, int timeoutMs) process.waitForStarted(); - QEventLoop loop; - QTimer timeoutTimer; - timeoutTimer.setSingleShot(true); - timeoutTimer.start(timeoutMs); - connect(&process, &QProcess::finished, &loop, &QEventLoop::quit); - connect(&timeoutTimer, &QTimer::timeout, &loop, &QEventLoop::quit); - loop.exec(); + bool finished = false; + auto tree = Group { + SignalWaitTaskItem([&](SignalWaitTask &task) { + task.setTimeout(timeoutMs); + task.connectSignal(&process, &QProcess::finished, + [&finished](int, QProcess::ExitStatus) { finished = true; }); + return SetupResult::Continue; + }) + }; + runTree(tree); if (process.state() == QProcess::Running) { process.kill(); diff --git a/systemcommandexecutor.h b/systemcommandexecutor.h index 59aec28ae..64117df1f 100644 --- a/systemcommandexecutor.h +++ b/systemcommandexecutor.h @@ -14,38 +14,27 @@ class SystemCommandExecutor : public QObject explicit SystemCommandExecutor(QObject *parent = nullptr) : QObject(parent) {} Q_INVOKABLE int executeCommand(const QString &command) { - QProcess process; - QEventLoop loop; - - process.setReadChannel(QProcess::StandardOutput); - - auto quitHandler = connect(&process, QOverload::of(&QProcess::finished), &loop, &QEventLoop::quit); - auto errHandler = connect(&process, &QProcess::errorOccurred, &loop, &QEventLoop::quit); - auto stdOutHandler = connect(&process, &QProcess::readyReadStandardOutput, [&]() { - emit processStandardOutput(QString::fromUtf8(process.readAllStandardOutput())); - }); - auto stdErrHandler = connect(&process, &QProcess::readyReadStandardError, [&]() { - emit processStandardError(QString::fromUtf8(process.readAllStandardError())); - }); - - process.start("sh", QStringList() << "-c" << command); - - if (!process.waitForStarted()) { - disconnect(quitHandler); - disconnect(errHandler); - disconnect(stdOutHandler); - disconnect(stdErrHandler); - return -1; - } - - loop.exec(); - - disconnect(quitHandler); - disconnect(errHandler); - disconnect(stdOutHandler); - disconnect(stdErrHandler); - - return process.exitCode(); + int exitCode = -1; + + auto tree = Group { + ProcessTaskItem([&](ProcessTask &task) { + task.setProgram("sh"); + task.setArguments(QStringList() << "-c" << command); + task.setStdOutCallback([this](const QString &out) { + emit processStandardOutput(out); + }); + task.setStdErrCallback([this](const QString &err) { + emit processStandardError(err); + }); + return SetupResult::Continue; + }, [&exitCode](const ProcessTask &task, DoneWith) { + exitCode = task.exitCode(); + return DoneResult::Success; + }) + }; + + runTree(tree); + return exitCode; } signals: From 4792562d21c03f4b72e7216be08fbce104abdf8b Mon Sep 17 00:00:00 2001 From: Felix Date: Sun, 8 Mar 2026 03:03:56 +0100 Subject: [PATCH 10/16] refactor(TcpServerSimple): Convert blocking connect to QtTaskTree --- tcpserversimple.cpp | 37 ++++++++++++++++++++----------------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/tcpserversimple.cpp b/tcpserversimple.cpp index b97db082e..37faaeff2 100644 --- a/tcpserversimple.cpp +++ b/tcpserversimple.cpp @@ -57,24 +57,27 @@ bool TcpServerSimple::connectToHub(QString server, int port, QString id, QString stopServer(); mTcpSocket = new QTcpSocket(this); - mTcpSocket->connectToHost(host, port); - QEventLoop loop; - QTimer timeoutTimer; - timeoutTimer.setSingleShot(true); - timeoutTimer.start(3000); - auto conn = QObject::connect(&timeoutTimer, &QTimer::timeout, &loop, &QEventLoop::quit); - - connect(mTcpSocket, &QTcpSocket::connected, [&id, &pass, this, &loop]() { - QString login = QString("VESC:%1:%2\n").arg(id).arg(pass); - mTcpSocket->write(login.toLocal8Bit()); - loop.quit(); - }); - - loop.exec(); - disconnect(conn); - - if (timeoutTimer.isActive()) { + bool connected = false; + auto tree = Group { + TcpConnectTaskItem([&](TcpConnectTask &task) { + task.setSocket(mTcpSocket); + task.setHost(host); + task.setPort(port); + task.setTimeout(3000); + task.setOnConnected([&id, &pass, this]() { + QString login = QString("VESC:%1:%2\n").arg(id).arg(pass); + mTcpSocket->write(login.toLocal8Bit()); + }); + return SetupResult::Continue; + }, [&connected](const TcpConnectTask &, DoneWith doneWith) { + connected = (doneWith == DoneWith::Success); + return DoneResult::Success; + }) + }; + runTree(tree); + + if (connected) { connect(mTcpSocket, &QIODevice::readyRead, this, &TcpServerSimple::tcpInputDataAvailable); connect(mTcpSocket, &QAbstractSocket::disconnected, this, &TcpServerSimple::tcpInputDisconnected); connect(mTcpSocket, &QAbstractSocket::errorOccurred, From 13e04a7ca8525c3afb02bc7eb3072198c9f4be0b Mon Sep 17 00:00:00 2001 From: Felix Date: Sun, 8 Mar 2026 03:03:56 +0100 Subject: [PATCH 11/16] refactor(Utility): Convert blocking functions to QtTaskTree --- utility.cpp | 244 +++++++++++++++++++++++++--------------------------- utility.h | 23 ++--- 2 files changed, 128 insertions(+), 139 deletions(-) diff --git a/utility.cpp b/utility.cpp index f4a01e4db..73d0e7fc6 100755 --- a/utility.cpp +++ b/utility.cpp @@ -175,15 +175,17 @@ bool Utility::autoconnectBlockingWithProgress(VescInterface *vesc, QWidget *pare void Utility::checkVersion(VescInterface *vesc) { QString version = QString::number(VT_VERSION); - QUrl url("https://vesc-project.com/vesctool-version.html"); - QNetworkAccessManager manager; - QNetworkRequest request(url); - QNetworkReply *reply = manager.get(request); - QEventLoop loop; - QObject::connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit); - loop.exec(); + QByteArray responseData; - QString res = QString::fromUtf8(reply->readAll()); + runTree(Group{NetworkReplyTaskItem([](NetworkReplyTask &task) { + task.setUrl(QUrl("https://vesc-project.com/vesctool-version.html")); + return SetupResult::Continue; + }, [&responseData](const NetworkReplyTask &task, DoneWith) { + responseData = task.replyData(); + return DoneResult::Success; + })}); + + QString res = QString::fromUtf8(responseData); if (res.startsWith("vesctoolversion")) { res.remove(0, 15); @@ -205,9 +207,6 @@ void Utility::checkVersion(VescInterface *vesc) } else { qWarning() << res; } - - reply->abort(); - reply->deleteLater(); } QString Utility::fwChangeLog() @@ -387,31 +386,29 @@ void Utility::allowScreenRotation(bool enabled) bool Utility::waitSignal(QObject *sender, QString signal, int timeoutMs) { - // qDebug() << "LoopLevel" << QThread::currentThread()->loopLevel(); - - QEventLoop loop; - QTimer timeoutTimer; - timeoutTimer.setSingleShot(true); - timeoutTimer.start(timeoutMs); - auto conn1 = QObject::connect(sender, signal.toLocal8Bit().data(), &loop, SLOT(quit())); - auto conn2 = QObject::connect(&timeoutTimer, &QTimer::timeout, &loop, &QEventLoop::quit); - loop.exec(); - - QObject::disconnect(conn1); - QObject::disconnect(conn2); + // String-based overload for QML callers (signal name is a runtime string). + bool signalFired = false; + + auto tree = Group { + SignalWaitTaskItem([&](SignalWaitTask &task) { + task.setTimeout(timeoutMs); + task.connectStringSignal(sender, signal.toLocal8Bit().constData()); + return SetupResult::Continue; + }, [&signalFired](const SignalWaitTask &, DoneWith doneWith) { + signalFired = (doneWith == DoneWith::Success); + return DoneResult::Success; + }) + }; - return timeoutTimer.isActive(); + runTree(tree); + return signalFired; } void Utility::sleepWithEventLoop(int timeMs) { - QEventLoop loop; - QTimer timeoutTimer; - timeoutTimer.setSingleShot(true); - timeoutTimer.start(timeMs); - auto conn1 = QObject::connect(&timeoutTimer, &QTimer::timeout, &loop, &QEventLoop::quit); - loop.exec(); - QObject::disconnect(conn1); + runTree(Group { + timeoutTask(std::chrono::milliseconds{timeMs}) + }); } bool Utility::canUpdateBaudAllBlocking(VescInterface *vesc, int newBaud) @@ -451,36 +448,42 @@ QString Utility::detectAllFoc(VescInterface *vesc, vesc->commands()->detectAllFoc(detect_can, max_power_loss, min_current_in, max_current_in, openloop_rpm, sl_erpm); - QEventLoop loop; - QTimer timeoutTimer; - QTimer pollTimer; - timeoutTimer.setSingleShot(true); - timeoutTimer.start(180000); - pollTimer.start(100); - int resDetect = 0; - auto conn = connect(vesc->commands(), &Commands::detectAllFocReceived, - [&resDetect, &loop](int result) { - resDetect = result; - loop.quit(); - }); - QString pollRes; - auto conn2 = connect(&pollTimer, &QTimer::timeout, - [&pollRes, &loop, &vesc]() { - if (!vesc->isPortConnected()) { - pollRes = "VESC disconnected during detection."; - loop.quit(); - } - }); - - connect(&timeoutTimer, &QTimer::timeout, &loop, &QEventLoop::quit); - loop.exec(); + bool timedOut = false; + + // Two parallel tasks: + // 1. SignalWaitTask: waits for detectAllFocReceived (up to 180s) + // 2. PollTimerTask: polls for disconnect every 100ms + // Group finishes when either completes. + auto tree = Group { + parallel, + stopOnSuccessOrError, + SignalWaitTaskItem([&](SignalWaitTask &task) { + task.setTimeout(180000); + task.connectSignal(vesc->commands(), &Commands::detectAllFocReceived, + [&resDetect](int result) { resDetect = result; }); + return SetupResult::Continue; + }, [&timedOut](const SignalWaitTask &, DoneWith doneWith) { + timedOut = (doneWith != DoneWith::Success); + return DoneResult::Success; + }), + PollTimerTaskItem([&](PollTimerTask &task) { + task.setInterval(100); + task.setTimeout(0); // no independent timeout + task.setOnTick([&task, &pollRes, vesc]() { + if (!vesc->isPortConnected()) { + pollRes = "VESC disconnected during detection."; + task.finish(); + } + }); + return SetupResult::Continue; + }) + }; - disconnect(conn); - disconnect(conn2); + runTree(tree); - if (timeoutTimer.isActive() && pollRes.isEmpty()) { + if (!timedOut && pollRes.isEmpty()) { if (resDetect >= 0) { ConfigParams *p = vesc->mcConfig(); ConfigParams *ap = vesc->appConfig(); @@ -1042,32 +1045,29 @@ QString Utility::testDirection(VescInterface *vesc, int canId, double duty, int return "FW not up to date"; } - QEventLoop loop; - QTimer timeoutTimer; - QTimer pollTimer; - timeoutTimer.setSingleShot(true); - timeoutTimer.start(ms); - pollTimer.start(40); - QString pollRes = "Ok"; - auto conn = connect(&pollTimer, &QTimer::timeout, - [&pollRes, &loop, &vesc, &duty, &ms, &timeoutTimer]() { - if (!vesc->isPortConnected()) { - pollRes = "VESC disconnected."; - loop.quit(); - } else { - double d = 2.0 * duty * (double)(ms - timeoutTimer.remainingTime()) / (double)ms; - if (fabs(d) > fabs(duty)) { - d = duty; - } - vesc->commands()->setDutyCycle(d); - } + QElapsedTimer elapsed; + elapsed.start(); + + runTree(Group { + PollTimerTaskItem([&](PollTimerTask &task) { + task.setTimeout(ms); + task.setInterval(40); + task.setOnTick([&pollRes, &task, vesc, duty, ms, &elapsed]() { + if (!vesc->isPortConnected()) { + pollRes = "VESC disconnected."; + task.finish(); + } else { + double d = 2.0 * duty * (double)elapsed.elapsed() / (double)ms; + if (fabs(d) > fabs(duty)) { + d = duty; + } + vesc->commands()->setDutyCycle(d); + } + }); + return SetupResult::Continue; + }) }); - - connect(&timeoutTimer, &QTimer::timeout, &loop, &QEventLoop::quit); - loop.exec(); - - disconnect(conn); vesc->commands()->setCurrent(0.0); vesc->canTmpOverrideEnd(); @@ -2365,40 +2365,23 @@ void Utility::plotSavePng(QCustomPlot *plot, int width, int height, QString titl QString Utility::waitForLine(QTcpSocket *socket, int timeoutMs) { - QEventLoop loop; - QTimer timeoutTimer; - timeoutTimer.setSingleShot(true); - timeoutTimer.start(timeoutMs); - auto conn = QObject::connect(&timeoutTimer, &QTimer::timeout, &loop, &QEventLoop::quit); - - QByteArray rxLine; - auto conn2 = connect(socket, &QTcpSocket::readyRead, [&rxLine,socket,&loop]() { - while (socket->bytesAvailable() > 0) { - QByteArray rxb = socket->read(1); - if (rxb.size() == 1) { - if (rxb[0] != '\n') { - rxLine.append(rxb[0]); - } else { - rxLine.append('\0'); - loop.quit(); - } - } else { - break; - } - } - }); - - loop.exec(); - - disconnect(conn); - disconnect(conn2); + QString result; - auto res = QString::fromLocal8Bit(rxLine); - if (!timeoutTimer.isActive()) { - res = ""; - } + auto tree = Group { + SocketLineReaderTaskItem([&](SocketLineReaderTask &task) { + task.setSocket(socket); + task.setTimeout(timeoutMs); + return SetupResult::Continue; + }, [&result](const SocketLineReaderTask &task, DoneWith doneWith) { + if (doneWith == DoneWith::Success) { + result = task.line(); + } + return DoneResult::Success; + }) + }; - return res; + runTree(tree); + return result; } QPixmap Utility::getIcon(QString path) @@ -2426,26 +2409,29 @@ bool Utility::downloadUrlEventloop(QString path, QString dest) return res; } - QNetworkAccessManager manager; - QNetworkRequest request(url); - QNetworkReply *reply = manager.get(request); + QFile file(dest); + if (!file.open(QIODevice::WriteOnly)) { + return res; + } + + auto tree = Group { + NetworkReplyTaskItem([&](NetworkReplyTask &task) { + task.setUrl(url); + task.setOutputDevice(&file); + return SetupResult::Continue; + }, [&res](const NetworkReplyTask &task, DoneWith doneWith) { + res = (doneWith == DoneWith::Success && task.error() == QNetworkReply::NoError); + return DoneResult::Success; + }) + }; - QEventLoop loop; - connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit); - loop.exec(); + runTree(tree); + file.close(); - if (reply->error() == QNetworkReply::NoError) { - QFile file(dest); - if (file.open(QIODevice::WriteOnly)) { - file.write(reply->readAll()); - file.close(); - res = true; - } + if (!res) { + file.remove(); } - reply->abort(); - reply->deleteLater(); - return res; } diff --git a/utility.h b/utility.h index 6193eafcd..c55155de8 100644 --- a/utility.h +++ b/utility.h @@ -67,16 +67,19 @@ class Utility : public QObject // Type-safe overload for C++ callers (avoids SIGNAL() macro) template static bool waitSignal(Sender *sender, Signal signal, int timeoutMs) { - QEventLoop loop; - QTimer timeoutTimer; - timeoutTimer.setSingleShot(true); - timeoutTimer.start(timeoutMs); - auto conn1 = QObject::connect(sender, signal, &loop, &QEventLoop::quit); - auto conn2 = QObject::connect(&timeoutTimer, &QTimer::timeout, &loop, &QEventLoop::quit); - loop.exec(); - QObject::disconnect(conn1); - QObject::disconnect(conn2); - return timeoutTimer.isActive(); + bool signalFired = false; + auto tree = Group { + SignalWaitTaskItem([&](SignalWaitTask &task) { + task.setTimeout(timeoutMs); + task.connectSignal(sender, signal); + return SetupResult::Continue; + }, [&signalFired](const SignalWaitTask &, DoneWith doneWith) { + signalFired = (doneWith == DoneWith::Success); + return DoneResult::Success; + }) + }; + runTree(tree); + return signalFired; } Q_INVOKABLE static void sleepWithEventLoop(int timeMs); From c79b31a1c5ae802c508f8598f2ee0ba1941f9b7c Mon Sep 17 00:00:00 2001 From: Felix Date: Sun, 8 Mar 2026 03:03:57 +0100 Subject: [PATCH 12/16] refactor(VescInterface): Convert blocking operations to QtTaskTree --- vescinterface.cpp | 336 ++++++++++++++++++---------------------------- 1 file changed, 127 insertions(+), 209 deletions(-) diff --git a/vescinterface.cpp b/vescinterface.cpp index 6be473ee2..5c6583c82 100755 --- a/vescinterface.cpp +++ b/vescinterface.cpp @@ -1068,28 +1068,18 @@ int VescInterface::getLastUdpPort() const bool VescInterface::swdEraseFlash() { - auto waitBmEraseRes = [this]() { - int res = -10; - - QEventLoop loop; - QTimer timeoutTimer; - timeoutTimer.setSingleShot(true); - timeoutTimer.start(20000); - auto conn = connect(mCommands, &Commands::bmEraseFlashAllRes, [&res,&loop](int erRes) { - res = erRes; - loop.quit(); - }); - - connect(&timeoutTimer, &QTimer::timeout, &loop, &QEventLoop::quit); - loop.exec(); - - disconnect(conn); - return res; - }; + int erRes = -10; mCommands->bmEraseFlashAll(); emit fwUploadStatus("Erasing flash...", 0.0, true); - int erRes = waitBmEraseRes(); + + runTree(Group{SignalWaitTaskItem([this, &erRes](SignalWaitTask &task) { + task.setTimeout(20000); + task.connectSignal(mCommands, &Commands::bmEraseFlashAllRes, + [&erRes](int r) { erRes = r; }); + return SetupResult::Continue; + })}); + if (erRes != 1) { QString msg = "Unknown failure"; @@ -1126,20 +1116,12 @@ bool VescInterface::swdUploadFw(QByteArray newFirmware, uint32_t startAddr, auto waitBmWriteRes = [this]() { int res = -10; - - QEventLoop loop; - QTimer timeoutTimer; - timeoutTimer.setSingleShot(true); - timeoutTimer.start(3000); - auto conn = connect(mCommands, &Commands::bmWriteFlashRes, [&res,&loop](int wrRes) { - res = wrRes; - loop.quit(); - }); - - connect(&timeoutTimer, &QTimer::timeout, &loop, &QEventLoop::quit); - loop.exec(); - - disconnect(conn); + runTree(Group{SignalWaitTaskItem([this, &res](SignalWaitTask &task) { + task.setTimeout(3000); + task.connectSignal(mCommands, &Commands::bmWriteFlashRes, + [&res](int wrRes) { res = wrRes; }); + return SetupResult::Continue; + })}); return res; }; @@ -1264,20 +1246,12 @@ bool VescInterface::swdReboot() { auto waitBmReboot = [this]() { int res = -10; - - QEventLoop loop; - QTimer timeoutTimer; - timeoutTimer.setSingleShot(true); - timeoutTimer.start(3000); - auto conn = connect(mCommands, &Commands::bmRebootRes, [&res,&loop](int wrRes) { - res = wrRes; - loop.quit(); - }); - - connect(&timeoutTimer, &QTimer::timeout, &loop, &QEventLoop::quit); - loop.exec(); - - disconnect(conn); + runTree(Group{SignalWaitTaskItem([this, &res](SignalWaitTask &task) { + task.setTimeout(3000); + task.connectSignal(mCommands, &Commands::bmRebootRes, + [&res](int wrRes) { res = wrRes; }); + return SetupResult::Continue; + })}); return res; }; @@ -1307,21 +1281,12 @@ bool VescInterface::fwEraseNewApp(bool fwdCan, quint32 fwSize) { auto waitEraseRes = [this]() { int res = -10; - - QEventLoop loop; - QTimer timeoutTimer; - timeoutTimer.setSingleShot(true); - timeoutTimer.start(20000); - auto conn = connect(mCommands, &Commands::eraseNewAppResReceived, - [&res,&loop](bool erRes) { - res = erRes ? 1 : -1; - loop.quit(); - }); - - connect(&timeoutTimer, &QTimer::timeout, &loop, &QEventLoop::quit); - loop.exec(); - - disconnect(conn); + runTree(Group{SignalWaitTaskItem([this, &res](SignalWaitTask &task) { + task.setTimeout(20000); + task.connectSignal(mCommands, &Commands::eraseNewAppResReceived, + [&res](bool erRes) { res = erRes ? 1 : -1; }); + return SetupResult::Continue; + })}); return res; }; @@ -1352,21 +1317,12 @@ bool VescInterface::fwEraseBootloader(bool fwdCan) { auto waitEraseRes = [this]() { int res = -10; - - QEventLoop loop; - QTimer timeoutTimer; - timeoutTimer.setSingleShot(true); - timeoutTimer.start(20000); - auto conn = connect(mCommands, &Commands::eraseBootloaderResReceived, - [&res,&loop](bool erRes) { - res = erRes ? 1 : -1; - loop.quit(); - }); - - connect(&timeoutTimer, &QTimer::timeout, &loop, &QEventLoop::quit); - loop.exec(); - - disconnect(conn); + runTree(Group{SignalWaitTaskItem([this, &res](SignalWaitTask &task) { + task.setTimeout(20000); + task.connectSignal(mCommands, &Commands::eraseBootloaderResReceived, + [&res](bool erRes) { res = erRes ? 1 : -1; }); + return SetupResult::Continue; + })}); return res; }; @@ -1487,17 +1443,6 @@ bool VescInterface::fwUpload(QByteArray &newFirmware, bool isBootloader, bool fw auto writeChunk = [this, &fwdCan](uint32_t addr, QByteArray chunk, bool fwIsLzo, quint16 decompressedLen) { for (int i = 0;i < 3;i++) { int res = -10; - QEventLoop loop; - QTimer timeoutTimer; - timeoutTimer.setSingleShot(true); - timeoutTimer.start(3000); - auto conn = connect(mCommands, &Commands::writeNewAppDataResReceived, - [&res,&loop](bool ok, bool hasOffset, quint32 offset) { - (void)offset; - (void)hasOffset; - res = ok ? 1 : -1; - loop.quit(); - }); if (fwIsLzo) { mCommands->writeNewAppDataLzo(chunk, addr, decompressedLen, fwdCan); @@ -1505,9 +1450,12 @@ bool VescInterface::fwUpload(QByteArray &newFirmware, bool isBootloader, bool fw mCommands->writeNewAppData(chunk, addr, fwdCan, mLastFwParams.hwType, mLastFwParams.hw); } - connect(&timeoutTimer, &QTimer::timeout, &loop, &QEventLoop::quit); - loop.exec(); - disconnect(conn); + runTree(Group{SignalWaitTaskItem([this, &res](SignalWaitTask &task) { + task.setTimeout(3000); + task.connectSignal(mCommands, &Commands::writeNewAppDataResReceived, + [&res](bool ok, bool, quint32) { res = ok ? 1 : -1; }); + return SetupResult::Continue; + })}); if (res != 1) { qDebug() << "Write chunk failed:" << res << "LZO:" << fwIsLzo << "Addr:" << addr << "Size:" << chunk.size(); @@ -2361,16 +2309,16 @@ bool VescInterface::autoconnect() Utility::sleepWithEventLoop(100); mPacket->resetState(); - QEventLoop loop; - QTimer timeoutTimer; - timeoutTimer.setSingleShot(true); - timeoutTimer.start(500); - connect(mCommands, &Commands::fwVersionReceived, &loop, &QEventLoop::quit); - connect(&timeoutTimer, &QTimer::timeout, &loop, &QEventLoop::quit); - loop.exec(); + bool gotFw = false; + runTree(Group{SignalWaitTaskItem([this, &gotFw](SignalWaitTask &task) { + task.setTimeout(500); + task.connectSignal(mCommands, &Commands::fwVersionReceived, + [&gotFw](FW_RX_PARAMS) { gotFw = true; }); + return SetupResult::Continue; + })}); - if (timeoutTimer.isActive()) { - // If the timer is still running, a firmware version was received. + if (gotFw) { + // A firmware version was received. res = true; break; } else { @@ -2749,23 +2697,20 @@ void VescInterface::scanCANbus() frame.setFlexibleDataRateFormat(false); frame.setBitrateSwitch(false); - QEventLoop loop; - QTimer pollTimer; - pollTimer.start(15); unsigned int i = 0; - - auto conn = connect(&pollTimer, &QTimer::timeout, - [this, &loop, &frame, &i]() { - frame.setFrameId(i | uint32_t(CAN_PACKET_PING << 8)); - mCanDevice->writeFrame(frame); - i++; - if (i >= 254) { - loop.quit(); - } - }); - - loop.exec(); - disconnect(conn); + runTree(Group{PollTimerTaskItem([this, &frame, &i](PollTimerTask &task) { + task.setInterval(15); + task.setTimeout(0); // no external timeout — we finish from within + task.setOnTick([this, &frame, &i, &task]() { + frame.setFrameId(i | uint32_t(CAN_PACKET_PING << 8)); + mCanDevice->writeFrame(frame); + i++; + if (i >= 254) { + task.finish(); + } + }); + return SetupResult::Continue; + })}); #endif return; } @@ -2780,22 +2725,20 @@ QVector VescInterface::scanCan() canTmpOverride(false, 0); - QEventLoop loop; - - bool timeout; - auto conn = connect(commands(), &Commands::pingCanRx, - [&canDevs, &timeout, &loop](QVector devs, bool isTimeout) { - for (int dev: devs) { - canDevs.append(dev); - } - timeout = isTimeout; - loop.quit(); - }); + bool timeout = false; commands()->pingCan(); - loop.exec(); - - disconnect(conn); + runTree(Group{SignalWaitTaskItem([this, &canDevs, &timeout](SignalWaitTask &task) { + task.setTimeout(10000); // generous timeout for CAN scan + task.connectSignal(commands(), &Commands::pingCanRx, + [&canDevs, &timeout](QVector devs, bool isTimeout) { + for (int dev: devs) { + canDevs.append(dev); + } + timeout = isTimeout; + }); + return SetupResult::Continue; + })}); if (!timeout) { mCanDevsLast = canDevs; @@ -4317,10 +4260,6 @@ bool VescInterface::downloadFwArchive() { bool res = false; - QUrl url("http://home.vedder.se/vesc_fw_archive/res_fw.rcc"); - QNetworkAccessManager manager; - QNetworkRequest request(url); - QNetworkReply *reply = manager.get(request); QString appDataLoc = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation); if (!QDir(appDataLoc).exists()) { QDir().mkpath(appDataLoc); @@ -4329,23 +4268,23 @@ bool VescInterface::downloadFwArchive() QFile file(path); QResource::unregisterResource(path); if (file.open(QIODevice::WriteOnly)) { - auto conn = connect(reply, &QNetworkReply::downloadProgress, [&file, reply, this] - (qint64 bytesReceived, qint64 bytesTotal) { - emit fwArchiveDlProgress("Downloading " + QFileInfo(file).fileName(), (double)bytesReceived / (double)bytesTotal); - file.write(reply->read(reply->size())); - }); - - QEventLoop loop; - connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit); - loop.exec(); - disconnect(conn); - - if (reply->error() == QNetworkReply::NoError) { - file.write(reply->readAll()); - emit fwArchiveDlProgress("Download Done", 1.0); - } else { - emit fwArchiveDlProgress("Download Failed", 0.0); - } + runTree(Group{NetworkReplyTaskItem([this, &file, &res](NetworkReplyTask &task) { + task.setUrl(QUrl("http://home.vedder.se/vesc_fw_archive/res_fw.rcc")); + task.setOutputDevice(&file); + task.setProgressCallback([this, &file](qint64 bytesReceived, qint64 bytesTotal) { + emit fwArchiveDlProgress("Downloading " + QFileInfo(file).fileName(), + (double)bytesReceived / (double)bytesTotal); + }); + return SetupResult::Continue; + }, [this, &res](const NetworkReplyTask &task, DoneWith doneWith) { + if (doneWith == DoneWith::Success) { + emit fwArchiveDlProgress("Download Done", 1.0); + res = true; + } else { + emit fwArchiveDlProgress("Download Failed", 0.0); + } + return DoneResult::Success; // always succeed so we can clean up + })}); file.close(); res = true; @@ -4354,9 +4293,6 @@ bool VescInterface::downloadFwArchive() emit fwArchiveDlProgress("Could not open local file", 0.0); } - reply->abort(); - reply->deleteLater(); - return res; } @@ -4365,30 +4301,25 @@ bool VescInterface::downloadFwLatest() auto downloadFws = [this](QUrl url, QString path) { bool res = false; - QNetworkAccessManager manager; - QNetworkRequest request(url); - QNetworkReply *reply = manager.get(request); - QFile file(path); QResource::unregisterResource(path); if (file.open(QIODevice::WriteOnly)) { - auto conn = connect(reply, &QNetworkReply::downloadProgress, [&file, reply, this] - (qint64 bytesReceived, qint64 bytesTotal) { - emit fwArchiveDlProgress("Downloading " + QFileInfo(file).fileName(), (double)bytesReceived / (double)bytesTotal); - file.write(reply->read(reply->size())); - }); - - QEventLoop loop; - connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit); - loop.exec(); - disconnect(conn); - - if (reply->error() == QNetworkReply::NoError) { - file.write(reply->readAll()); - emit fwArchiveDlProgress("Download Done", 1.0); - } else { - emit fwArchiveDlProgress("Download Failed", 0.0); - } + runTree(Group{NetworkReplyTaskItem([this, &file, &url](NetworkReplyTask &task) { + task.setUrl(url); + task.setOutputDevice(&file); + task.setProgressCallback([this, &file](qint64 bytesReceived, qint64 bytesTotal) { + emit fwArchiveDlProgress("Downloading " + QFileInfo(file).fileName(), + (double)bytesReceived / (double)bytesTotal); + }); + return SetupResult::Continue; + }, [this, &res](const NetworkReplyTask &task, DoneWith doneWith) { + if (doneWith == DoneWith::Success) { + emit fwArchiveDlProgress("Download Done", 1.0); + } else { + emit fwArchiveDlProgress("Download Failed", 0.0); + } + return DoneResult::Success; + })}); file.close(); QResource::registerResource(path); @@ -4397,9 +4328,6 @@ bool VescInterface::downloadFwLatest() emit fwArchiveDlProgress("Could not open local file", 0.0); } - reply->abort(); - reply->deleteLater(); - return res; }; @@ -4423,11 +4351,6 @@ bool VescInterface::downloadFwLatest() bool VescInterface::downloadConfigs() { bool res = false; - QUrl url("http://home.vedder.se/vesc_fw_archive/res_config.rcc"); - - QNetworkAccessManager manager; - QNetworkRequest request(url); - QNetworkReply *reply = manager.get(request); QString appDataLoc = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation); if(!QDir(appDataLoc).exists()) { QDir().mkpath(appDataLoc); @@ -4437,39 +4360,34 @@ bool VescInterface::downloadConfigs() QResource::unregisterResource(path); if (file.open(QIODevice::WriteOnly)) { - auto conn = connect(reply, &QNetworkReply::downloadProgress, [&file, reply, this] - (qint64 bytesReceived, qint64 bytesTotal) { - emit fwArchiveDlProgress("Downloading...", (double)bytesReceived / (double)bytesTotal); - file.write(reply->read(reply->size())); - }); - - QEventLoop loop; - connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit); - loop.exec(); - disconnect(conn); - - if (reply->error() == QNetworkReply::NoError) { - file.write(reply->readAll()); - emit fwArchiveDlProgress("Download Done", 1.0); - file.close(); - res = QResource::registerResource(path); + runTree(Group{NetworkReplyTaskItem([this, &file](NetworkReplyTask &task) { + task.setUrl(QUrl("http://home.vedder.se/vesc_fw_archive/res_config.rcc")); + task.setOutputDevice(&file); + task.setProgressCallback([this](qint64 bytesReceived, qint64 bytesTotal) { + emit fwArchiveDlProgress("Downloading...", (double)bytesReceived / (double)bytesTotal); + }); + return SetupResult::Continue; + }, [this, &res, &file, &path](const NetworkReplyTask &task, DoneWith doneWith) { + if (doneWith == DoneWith::Success) { + emit fwArchiveDlProgress("Download Done", 1.0); + file.close(); + res = QResource::registerResource(path); - if (res) { - qDebug() << "Reloaded config resource successfully"; + if (res) { + qDebug() << "Reloaded config resource successfully"; + } else { + qWarning() << "Could not reload config resource"; + } } else { - qWarning() << "Could not reload config resource"; + emit fwArchiveDlProgress("Download Failed", 0.0); + file.close(); } - } else { - emit fwArchiveDlProgress("Download Failed", 0.0); - file.close(); - } + return DoneResult::Success; + })}); } else { emit fwArchiveDlProgress("Could not open local file", 0.0); } - reply->abort(); - reply->deleteLater(); - return res; } From f7cfe6510f7f22f806be9e9f92b4b59394b886f6 Mon Sep 17 00:00:00 2001 From: Felix Date: Sun, 8 Mar 2026 20:45:41 +0100 Subject: [PATCH 13/16] qml ui tests --- CMakeLists.txt | 68 +- commands.h | 2 +- desktop/AppAdcPage.qml | 277 ++++++ desktop/AppGeneralPage.qml | 111 +++ desktop/AppImuPage.qml | 270 ++++++ desktop/AppNrfPage.qml | 138 +++ desktop/AppNunchukPage.qml | 264 ++++++ desktop/AppPasPage.qml | 8 + desktop/AppPpmPage.qml | 292 ++++++ desktop/AppUartPage.qml | 8 + desktop/BmsPage.qml | 201 +++++ desktop/CanAnalyzerPage.qml | 261 ++++++ desktop/ConnectionPage.qml | 1157 ++++++++++++++++++++++++ desktop/ControllersPage.qml | 109 +++ desktop/DisplayToolPage.qml | 859 ++++++++++++++++++ desktop/ExperimentPlotPage.qml | 568 ++++++++++++ desktop/ExperimentsPage.qml | 404 +++++++++ desktop/FirmwarePage.qml | 1129 +++++++++++++++++++++++ desktop/FocPage.qml | 279 ++++++ desktop/ImuPage.qml | 131 +++ desktop/LispPage.qml | 243 +++++ desktop/LogAnalysisPage.qml | 965 ++++++++++++++++++++ desktop/MotorComparisonPage.qml | 1003 +++++++++++++++++++++ desktop/MotorGeneralPage.qml | 102 +++ desktop/MotorInfoPage.qml | 180 ++++ desktop/PackagesPage.qml | 846 +++++++++++++++++ desktop/ParamEditBitfield.qml | 129 +++ desktop/ParamEditBool.qml | 88 ++ desktop/ParamEditDouble.qml | 166 ++++ desktop/ParamEditEnum.qml | 88 ++ desktop/ParamEditInt.qml | 145 +++ desktop/ParamEditSeparator.qml | 26 + desktop/ParamEditString.qml | 92 ++ desktop/ParamEditors.qml | 71 ++ desktop/ParamGroupPage.qml | 112 +++ desktop/RtDataPage.qml | 518 +++++++++++ desktop/SampledDataPage.qml | 628 +++++++++++++ desktop/ScriptingPage.qml | 615 +++++++++++++ desktop/TerminalPage.qml | 199 ++++ desktop/Vesc3DView.qml | 124 +++ desktop/WelcomePage.qml | 206 +++++ desktop/desktop.qrc | 43 + desktop/main.qml | 1497 +++++++++++++++++++++++++++++++ main.cpp | 10 +- mobile/ConfigPageApp.qml | 10 +- mobile/ConfigPageCustom.qml | 10 +- mobile/ConfigPageMotor.qml | 10 +- mobile/FwUpdate.qml | 3 +- mobile/Lisp.qml | 5 +- mobile/Packages.qml | 5 +- mobile/Vesc3DView.qml | 161 ++-- mobile/main.qml | 2 +- mobile/qmlui.cpp | 25 + mobile/qmlui.h | 1 + mobile/vesc3ditem.cpp | 27 +- motorcomparisonhelper.cpp | 483 ++++++++++ motorcomparisonhelper.h | 96 ++ sampleddatahelper.cpp | 591 ++++++++++++ sampleddatahelper.h | 114 +++ utility.cpp | 57 ++ utility.h | 13 +- vescinterface.cpp | 23 + vescinterface.h | 2 + 63 files changed, 16142 insertions(+), 128 deletions(-) create mode 100644 desktop/AppAdcPage.qml create mode 100644 desktop/AppGeneralPage.qml create mode 100644 desktop/AppImuPage.qml create mode 100644 desktop/AppNrfPage.qml create mode 100644 desktop/AppNunchukPage.qml create mode 100644 desktop/AppPasPage.qml create mode 100644 desktop/AppPpmPage.qml create mode 100644 desktop/AppUartPage.qml create mode 100644 desktop/BmsPage.qml create mode 100644 desktop/CanAnalyzerPage.qml create mode 100644 desktop/ConnectionPage.qml create mode 100644 desktop/ControllersPage.qml create mode 100644 desktop/DisplayToolPage.qml create mode 100644 desktop/ExperimentPlotPage.qml create mode 100644 desktop/ExperimentsPage.qml create mode 100644 desktop/FirmwarePage.qml create mode 100644 desktop/FocPage.qml create mode 100644 desktop/ImuPage.qml create mode 100644 desktop/LispPage.qml create mode 100644 desktop/LogAnalysisPage.qml create mode 100644 desktop/MotorComparisonPage.qml create mode 100644 desktop/MotorGeneralPage.qml create mode 100644 desktop/MotorInfoPage.qml create mode 100644 desktop/PackagesPage.qml create mode 100644 desktop/ParamEditBitfield.qml create mode 100644 desktop/ParamEditBool.qml create mode 100644 desktop/ParamEditDouble.qml create mode 100644 desktop/ParamEditEnum.qml create mode 100644 desktop/ParamEditInt.qml create mode 100644 desktop/ParamEditSeparator.qml create mode 100644 desktop/ParamEditString.qml create mode 100644 desktop/ParamEditors.qml create mode 100644 desktop/ParamGroupPage.qml create mode 100644 desktop/RtDataPage.qml create mode 100644 desktop/SampledDataPage.qml create mode 100644 desktop/ScriptingPage.qml create mode 100644 desktop/TerminalPage.qml create mode 100644 desktop/Vesc3DView.qml create mode 100644 desktop/WelcomePage.qml create mode 100644 desktop/desktop.qrc create mode 100644 desktop/main.qml create mode 100644 motorcomparisonhelper.cpp create mode 100644 motorcomparisonhelper.h create mode 100644 sampleddatahelper.cpp create mode 100644 sampleddatahelper.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 6324ba130..9821758e1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -55,6 +55,8 @@ set(QT_COMPONENTS OpenGLWidgets Core5Compat TaskTree + Graphs + Quick3D ) # --------------------------------------------------------------------------- @@ -96,7 +98,7 @@ if(HAS_BLUETOOTH) list(APPEND QT_COMPONENTS Bluetooth) endif() if(HAS_POS) - list(APPEND QT_COMPONENTS Positioning) + list(APPEND QT_COMPONENTS Positioning PositioningQuick Location) endif() find_package(Qt6 REQUIRED COMPONENTS ${QT_COMPONENTS}) # We need GuiPrivate for some internals @@ -200,6 +202,8 @@ set(ROOT_SOURCES utility.cpp tcpserversimple.cpp hexfile.cpp + motorcomparisonhelper.cpp + sampleddatahelper.cpp ) set(ROOT_HEADERS @@ -225,6 +229,8 @@ set(ROOT_HEADERS utility.h tcpserversimple.h hexfile.h + motorcomparisonhelper.h + sampleddatahelper.h ) set(ROOT_FORMS @@ -488,7 +494,6 @@ set(MOBILE_SOURCES mobile/logwriter.cpp mobile/qmlui.cpp mobile/fwhelper.cpp - mobile/vesc3ditem.cpp ) set(MOBILE_HEADERS @@ -496,7 +501,6 @@ set(MOBILE_HEADERS mobile/logwriter.h mobile/qmlui.h mobile/fwhelper.h - mobile/vesc3ditem.h ) # --------------------------------------------------------------------------- @@ -799,11 +803,61 @@ qt_add_executable(${APP_TARGET} qt_add_qml_module(${APP_TARGET} URI Vedder.vesc VERSION 1.0 - # No QML files in the module — they stay in .qrc resources. - # The C++ types are already in the target sources; QML_ELEMENT does the rest. NO_RESOURCE_TARGET_PATH ) +# QTP0004: Allow QML files in subdirectories without separate qmldir files. +qt_policy(SET QTP0004 OLD) + +# --------------------------------------------------------------------------- +# Desktop QML files – compiled via qmlcachegen and embedded as resources. +# Source paths are desktop/*.qml; PREFIX / keeps them at qrc:/desktop/*.qml. +# --------------------------------------------------------------------------- +qt_target_qml_sources(${APP_TARGET} + PREFIX / + QML_FILES + desktop/main.qml + desktop/ParamEditors.qml + desktop/ParamEditDouble.qml + desktop/ParamEditInt.qml + desktop/ParamEditEnum.qml + desktop/ParamEditBool.qml + desktop/ParamEditString.qml + desktop/ParamEditBitfield.qml + desktop/ParamEditSeparator.qml + desktop/Vesc3DView.qml + desktop/ParamGroupPage.qml + desktop/WelcomePage.qml + desktop/ConnectionPage.qml + desktop/FirmwarePage.qml + desktop/PackagesPage.qml + desktop/TerminalPage.qml + desktop/LispPage.qml + desktop/BmsPage.qml + desktop/RtDataPage.qml + desktop/SampledDataPage.qml + desktop/ExperimentPlotPage.qml + desktop/ImuPage.qml + desktop/MotorGeneralPage.qml + desktop/FocPage.qml + desktop/ControllersPage.qml + desktop/MotorInfoPage.qml + desktop/ExperimentsPage.qml + desktop/AppGeneralPage.qml + desktop/AppPpmPage.qml + desktop/AppAdcPage.qml + desktop/AppUartPage.qml + desktop/AppNunchukPage.qml + desktop/AppNrfPage.qml + desktop/AppPasPage.qml + desktop/AppImuPage.qml + desktop/ScriptingPage.qml + desktop/LogAnalysisPage.qml + desktop/MotorComparisonPage.qml + desktop/CanAnalyzerPage.qml + desktop/DisplayToolPage.qml +) + # --------------------------------------------------------------------------- # Compile definitions # --------------------------------------------------------------------------- @@ -847,6 +901,8 @@ set(QT_LINK_LIBS Qt6::OpenGLWidgets Qt6::Core5Compat Qt6::TaskTree + Qt6::Graphs + Qt6::Quick3D ) if(NOT IOS) @@ -863,7 +919,7 @@ if(HAS_BLUETOOTH) list(APPEND QT_LINK_LIBS Qt6::Bluetooth) endif() if(HAS_POS) - list(APPEND QT_LINK_LIBS Qt6::Positioning) + list(APPEND QT_LINK_LIBS Qt6::Positioning Qt6::PositioningQuick Qt6::Location) endif() if(HAS_GAMEPAD) list(APPEND QT_LINK_LIBS Qt6::GamepadLegacy) diff --git a/commands.h b/commands.h index 47fd0f94c..fb246ad17 100644 --- a/commands.h +++ b/commands.h @@ -179,7 +179,7 @@ class Commands : public QObject public slots: void processPacket(QByteArray data); - void getFwVersion(); + Q_INVOKABLE void getFwVersion(); void eraseNewApp(bool fwdCan, quint32 fwSize, HW_TYPE hwType, QString hwName); void eraseBootloader(bool fwdCan, HW_TYPE hwType, QString hwName); void writeNewAppData(QByteArray data, quint32 offset, bool fwdCan, HW_TYPE hwType, QString hwName); diff --git a/desktop/AppAdcPage.qml b/desktop/AppAdcPage.qml new file mode 100644 index 000000000..368b755a6 --- /dev/null +++ b/desktop/AppAdcPage.qml @@ -0,0 +1,277 @@ +/* + Desktop AppAdcPage — exact parity with PageAppAdc widget. + Layout: TabWidget (General | Mapping | Throttle Curve) + General: ParamTable of "ADC" / "general" + Mapping: ParamTable of "ADC" / "mapping" + ADC Voltage Mapping GroupBox + Throttle: ParamTable (fixed height ~100) + throttle curve plot +*/ +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import QtGraphs +import Vedder.vesc + +Item { + id: root + + property ConfigParams mAppConf: VescIf.appConfig() + property Commands mCommands: VescIf.commands() + property var _dynamicItems: [] + property bool _mapResetDone: true + property double _minCh1: 0.0 + property double _maxCh1: 0.0 + property double _centerCh1: 0.0 + property double _minCh2: 0.0 + property double _maxCh2: 0.0 + + ParamEditors { id: editors } + + function updateThrottleCurve() { + var mode = mAppConf.getParamEnum("app_adc_conf.throttle_exp_mode") + var valAcc = mAppConf.getParamDouble("app_adc_conf.throttle_exp") + var valBrk = mAppConf.getParamDouble("app_adc_conf.throttle_exp_brake") + + for (var si = throttlePlot.count - 1; si >= 0; si--) + throttlePlot.removeSeries(throttlePlot.seriesAt(si)) + + var series = throttlePlot.createSeries(GraphsView.SeriesTypeLine, "Throttle Curve") + series.color = Utility.getAppHexColor("plot_graph1") + series.width = 1.5 + + for (var i = -1.0; i <= 1.0001; i += 0.002) + series.append(i, Utility.throttle_curve(i, valAcc, valBrk, mode)) + + throttleAxisX.min = -1.0; throttleAxisX.max = 1.0 + var yMin = -1.0, yMax = 1.0 + for (var j = 0; j < series.count; j++) { + var pt = series.at(j) + if (pt.y < yMin) yMin = pt.y + if (pt.y > yMax) yMax = pt.y + } + var pad = (yMax - yMin) * 0.05 + throttleAxisY.min = yMin - pad + throttleAxisY.max = yMax + pad + } + + Connections { + target: mAppConf + function onParamChangedDouble(src, name, newParam) { + if (name === "app_adc_conf.throttle_exp" || name === "app_adc_conf.throttle_exp_brake") + updateThrottleCurve() + } + function onParamChangedEnum(src, name, newParam) { + if (name === "app_adc_conf.throttle_exp_mode") + updateThrottleCurve() + } + } + + Connections { + target: mCommands + function onDecodedAdcReceived(value, voltage, value2, voltage2) { + // CH1 display + var p1 = dualBox.checked ? (value - 0.5) * 200.0 : value * 100.0 + adc1Bar.value = Math.max(-100, Math.min(100, p1)) / 100.0 + adc1Label.text = voltage.toFixed(dualBox.checked ? 2 : 4) + " V (" + p1.toFixed(1) + " %)" + + // CH2 display + var p2 = dualBox.checked ? (value2 - 0.5) * 200.0 : value2 * 100.0 + adc2Bar.value = Math.max(-100, Math.min(100, p2)) / 100.0 + adc2Label.text = voltage2.toFixed(4) + " V (" + p2.toFixed(1) + " %)" + + // Auto min/max + if (_mapResetDone) { + _mapResetDone = false + _minCh1 = voltage; _maxCh1 = voltage + _minCh2 = voltage2; _maxCh2 = voltage2 + } else { + if (voltage < _minCh1) _minCh1 = voltage + if (voltage > _maxCh1) _maxCh1 = voltage + if (voltage2 < _minCh2) _minCh2 = voltage2 + if (voltage2 > _maxCh2) _maxCh2 = voltage2 + } + + var range = _maxCh1 - _minCh1 + var pos = voltage - _minCh1 + if (pos > range / 4.0 && pos < (3.0 * range) / 4.0) + _centerCh1 = voltage + else + _centerCh1 = range / 2.0 + _minCh1 + } + } + + ColumnLayout { + anchors.fill: parent + spacing: 0 + + TabBar { + id: tabBar + Layout.fillWidth: true + TabButton { text: "General" } + TabButton { text: "Mapping" } + TabButton { text: "Throttle Curve" } + } + + StackLayout { + Layout.fillWidth: true + Layout.fillHeight: true + currentIndex: tabBar.currentIndex + + // Tab 0: General + Flickable { + clip: true; contentWidth: width; contentHeight: genCol.height + 16 + flickableDirection: Flickable.VerticalFlick + ScrollBar.vertical: ScrollBar { policy: ScrollBar.AsNeeded } + ColumnLayout { id: genCol; width: parent.width; spacing: 4; Item { Layout.preferredHeight: 1 } } + } + + // Tab 1: Mapping + Flickable { + clip: true; contentWidth: width; contentHeight: mapLayout.height + 16 + flickableDirection: Flickable.VerticalFlick + ScrollBar.vertical: ScrollBar { policy: ScrollBar.AsNeeded } + + ColumnLayout { + id: mapLayout + width: parent.width + spacing: 4 + + Item { Layout.preferredHeight: 1 } + + ColumnLayout { + id: mapCol + Layout.fillWidth: true + spacing: 4 + } + + // ADC Voltage Mapping GroupBox + GroupBox { + title: "ADC Voltage Mapping" + Layout.fillWidth: true + + ColumnLayout { + anchors.fill: parent + spacing: 4 + + RowLayout { + spacing: 4 + CheckBox { + id: dualBox + text: "Use Centered Control" + ToolTip.text: "Show centered graph, which is how the centered control modes interpret the throttle." + ToolTip.visible: dualHover.hovered; ToolTip.delay: 500 + HoverHandler { id: dualHover } + } + Button { + text: "Reset" + ToolTip.text: "Reset min and max"; ToolTip.visible: hovered + onClicked: { _mapResetDone = true; _minCh1 = 0; _maxCh1 = 0; _minCh2 = 0; _maxCh2 = 0 } + } + Button { + icon.source: "qrc" + Utility.getThemePath() + "icons/Ok-96.png" + text: "Apply" + ToolTip.text: "Apply min and max to configuration"; ToolTip.visible: hovered + onClicked: { + if (_maxCh1 > 1e-10) { + mAppConf.updateParamDouble("app_adc_conf.voltage_start", _minCh1) + mAppConf.updateParamDouble("app_adc_conf.voltage_end", _maxCh1) + mAppConf.updateParamDouble("app_adc_conf.voltage_center", _centerCh1) + mAppConf.updateParamDouble("app_adc_conf.voltage2_start", _minCh2) + mAppConf.updateParamDouble("app_adc_conf.voltage2_end", _maxCh2) + VescIf.emitStatusMessage("Start, End and Center ADC Voltages Applied", true) + } else { + VescIf.emitStatusMessage("Applying Voltages Failed", false) + } + } + } + } + + GridLayout { + columns: 5 + Layout.fillWidth: true + columnSpacing: 2; rowSpacing: 2 + + // CH1 row + Label { text: "CH1" } + Label { text: "Min: " + _minCh1.toFixed(2); padding: 4 + background: Rectangle { border.width: 1; border.color: palette.mid; radius: 2; color: "transparent" } } + Label { text: "Max: " + _maxCh1.toFixed(2); padding: 4 + background: Rectangle { border.width: 1; border.color: palette.mid; radius: 2; color: "transparent" } } + Label { text: "Center: " + _centerCh1.toFixed(2); padding: 4 + background: Rectangle { border.width: 1; border.color: palette.mid; radius: 2; color: "transparent" } } + ColumnLayout { + Layout.fillWidth: true + spacing: 0 + ProgressBar { id: adc1Bar; Layout.fillWidth: true; from: -1; to: 1; value: 0; Layout.preferredHeight: 20 } + Label { id: adc1Label; text: "-- V (-- %)"; font.pixelSize: 11; color: Utility.getAppHexColor("lightText") } + } + + // CH2 row + Label { text: "CH2" } + Label { text: "Min: " + _minCh2.toFixed(2); padding: 4 + background: Rectangle { border.width: 1; border.color: palette.mid; radius: 2; color: "transparent" } } + Label { text: "Max: " + _maxCh2.toFixed(2); padding: 4 + background: Rectangle { border.width: 1; border.color: palette.mid; radius: 2; color: "transparent" } } + Item { } // no center for CH2 + ColumnLayout { + Layout.fillWidth: true + spacing: 0 + ProgressBar { id: adc2Bar; Layout.fillWidth: true; from: -1; to: 1; value: 0; Layout.preferredHeight: 20 } + Label { id: adc2Label; text: "-- V (-- %)"; font.pixelSize: 11; color: Utility.getAppHexColor("lightText") } + } + } + } + } + } + } + + // Tab 2: Throttle Curve + ColumnLayout { + spacing: 0 + + Flickable { + Layout.fillWidth: true + Layout.preferredHeight: 100; Layout.maximumHeight: 100 + clip: true; contentWidth: width; contentHeight: tcCol.height + 16 + flickableDirection: Flickable.VerticalFlick + ScrollBar.vertical: ScrollBar { policy: ScrollBar.AsNeeded } + ColumnLayout { id: tcCol; width: parent.width; spacing: 4; Item { Layout.preferredHeight: 1 } } + } + + GraphsView { + id: throttlePlot + Layout.fillWidth: true + Layout.fillHeight: true + + theme: GraphsTheme { + colorScheme: Utility.isDarkMode() ? GraphsTheme.ColorScheme.Dark : GraphsTheme.ColorScheme.Light + plotAreaBackgroundColor: Utility.getAppHexColor("plotBackground") + grid.mainColor: Utility.isDarkMode() ? "#444444" : "#cccccc" + } + + axisX: ValueAxis { id: throttleAxisX; min: -1; max: 1; titleText: "Throttle Value" } + axisY: ValueAxis { id: throttleAxisY; min: -1; max: 1; titleText: "Output Value" } + } + } + } + } + + function loadSubgroup(parentCol, subgroup) { + var params = mAppConf.getParamsFromSubgroup("ADC", subgroup) + for (var p = 0; p < params.length; p++) { + var paramName = params[p] + if (paramName.indexOf("::sep::") === 0) { + var sep = editors.createSeparator(parentCol, paramName.substring(7)) + if (sep) _dynamicItems.push(sep) + continue + } + var e = editors.createEditorApp(parentCol, paramName) + if (e) { e.Layout.fillWidth = true; _dynamicItems.push(e) } + } + } + + Component.onCompleted: { + loadSubgroup(genCol, "general") + loadSubgroup(mapCol, "mapping") + loadSubgroup(tcCol, "throttle curve") + } +} diff --git a/desktop/AppGeneralPage.qml b/desktop/AppGeneralPage.qml new file mode 100644 index 000000000..bf3b929a5 --- /dev/null +++ b/desktop/AppGeneralPage.qml @@ -0,0 +1,111 @@ +/* + Desktop AppGeneralPage — exact parity with PageAppGeneral widget. + Layout: TabWidget (General | Tools) + General: ParamTable of "general" / "general" + Tools: Servo Output GroupBox with slider + Center button, then spacer +*/ +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import Vedder.vesc + +Item { + id: root + + property ConfigParams mAppConf: VescIf.appConfig() + property Commands mCommands: VescIf.commands() + property var _dynamicItems: [] + + ParamEditors { id: editors } + + ColumnLayout { + anchors.fill: parent + spacing: 0 + + TabBar { + id: tabBar + Layout.fillWidth: true + TabButton { text: "General" } + TabButton { text: "Tools" } + } + + StackLayout { + Layout.fillWidth: true + Layout.fillHeight: true + currentIndex: tabBar.currentIndex + + // Tab 0: General params + Flickable { + clip: true + contentWidth: width + contentHeight: genCol.height + 16 + flickableDirection: Flickable.VerticalFlick + ScrollBar.vertical: ScrollBar { policy: ScrollBar.AsNeeded } + + ColumnLayout { + id: genCol + width: parent.width + spacing: 4 + Item { Layout.preferredHeight: 1 } + } + } + + // Tab 1: Tools (Servo Output) + ColumnLayout { + spacing: 0 + + GroupBox { + title: "Servo Output" + Layout.fillWidth: true + Layout.margins: 0 + + ColumnLayout { + anchors.fill: parent + spacing: 4 + + Slider { + id: servoSlider + Layout.fillWidth: true + from: 0; to: 1000; value: 500; stepSize: 1 + snapMode: Slider.SnapOnRelease + onValueChanged: mCommands.setServoPos(value / 1000.0) + } + + RowLayout { + Layout.fillWidth: true + Item { Layout.fillWidth: true } + Button { + text: "Center" + onClicked: servoSlider.value = 500 + } + Item { Layout.fillWidth: true } + } + } + } + + Item { Layout.fillHeight: true } + } + } + } + + function loadParams() { + for (var d = 0; d < _dynamicItems.length; d++) { + if (_dynamicItems[d]) _dynamicItems[d].destroy() + } + _dynamicItems = [] + + var params = mAppConf.getParamsFromSubgroup("General", "general") + for (var p = 0; p < params.length; p++) { + var paramName = params[p] + if (paramName.indexOf("::sep::") === 0) { + var sep = editors.createSeparator(genCol, paramName.substring(7)) + if (sep) _dynamicItems.push(sep) + continue + } + var e = editors.createEditorApp(genCol, paramName) + if (e) { e.Layout.fillWidth = true; _dynamicItems.push(e) } + } + } + + Component.onCompleted: loadParams() +} diff --git a/desktop/AppImuPage.qml b/desktop/AppImuPage.qml new file mode 100644 index 000000000..f29b6ae1c --- /dev/null +++ b/desktop/AppImuPage.qml @@ -0,0 +1,270 @@ +/* + Desktop AppImuPage — exact parity with PageAppImu widget. + Layout: Vertical SplitView + Top: ParamTable for "imu"/"general" + Bottom: Horizontal SplitView + Left: TabBar (bottom) with RPY / Accel / Gyro — each with rolling 500-sample GraphsView + Right: "Use Yaw" checkbox + Vesc3DView + Timer-driven replot at 20 ms. +*/ +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import QtGraphs +import Vedder.vesc + +Item { + id: root + + property Commands mCommands: VescIf.commands() + property ConfigParams mAppConf: VescIf.appConfig() + property var _dynamicItems: [] + + // Rolling data buffers (500 samples max) + property var _seconds: [] + property var _rollVec: []; property var _pitchVec: []; property var _yawVec: [] + property var _accXVec: []; property var _accYVec: []; property var _accZVec: [] + property var _gyroXVec: []; property var _gyroYVec: []; property var _gyroZVec: [] + + property double _secondCounter: 0.0 + property double _lastUpdateTime: 0 + property bool _updatePlots: false + + // Latest values for axis labels + property double _curRoll: 0; property double _curPitch: 0; property double _curYaw: 0 + property double _curAccX: 0; property double _curAccY: 0; property double _curAccZ: 0 + property double _curGyroX: 0; property double _curGyroY: 0; property double _curGyroZ: 0 + + readonly property int _maxS: 500 + + ParamEditors { id: editors } + + function appendAndTrunc(arr, val) { + arr.push(val) + if (arr.length > _maxS) arr.splice(0, arr.length - _maxS) + } + + Connections { + target: mCommands + function onValuesImuReceived(values, mask) { + var rollDeg = values.roll * 180.0 / Math.PI + var pitchDeg = values.pitch * 180.0 / Math.PI + var yawDeg = values.yaw * 180.0 / Math.PI + + // Update 3D view (radians for setRotation) + view3d.setRotation(values.roll, values.pitch, + useYawBox.checked ? values.yaw : 0.0) + + appendAndTrunc(_rollVec, rollDeg) + appendAndTrunc(_pitchVec, pitchDeg) + appendAndTrunc(_yawVec, yawDeg) + + appendAndTrunc(_accXVec, values.accX) + appendAndTrunc(_accYVec, values.accY) + appendAndTrunc(_accZVec, values.accZ) + + appendAndTrunc(_gyroXVec, values.gyroX) + appendAndTrunc(_gyroYVec, values.gyroY) + appendAndTrunc(_gyroZVec, values.gyroZ) + + var tNow = Date.now() + var elapsed = (_lastUpdateTime > 0) ? (tNow - _lastUpdateTime) / 1000.0 : 0 + if (elapsed > 1.0) elapsed = 1.0 + _secondCounter += elapsed + appendAndTrunc(_seconds, _secondCounter) + _lastUpdateTime = tNow + + _curRoll = rollDeg; _curPitch = pitchDeg; _curYaw = yawDeg + _curAccX = values.accX; _curAccY = values.accY; _curAccZ = values.accZ + _curGyroX = values.gyroX; _curGyroY = values.gyroY; _curGyroZ = values.gyroZ + + _updatePlots = true + } + } + + Timer { + interval: 20; running: true; repeat: true + onTriggered: { + if (!_updatePlots) return + _updatePlots = false + rebuildRpy() + rebuildAccel() + rebuildGyro() + } + } + + // ── Rebuild helpers ───────────────────────────────────────── + function updateSeries(series, xVec, yVec) { + series.clear() + for (var i = 0; i < xVec.length; i++) + series.append(xVec[i], yVec[i]) + } + + function updateAxes(axX, axY, xVec, vecs, xLabel, yLabel) { + var xMin = 1e18, xMax = -1e18 + var yMin = 1e18, yMax = -1e18 + for (var i = 0; i < xVec.length; i++) { + if (xVec[i] < xMin) xMin = xVec[i] + if (xVec[i] > xMax) xMax = xVec[i] + for (var k = 0; k < vecs.length; k++) { + if (vecs[k][i] < yMin) yMin = vecs[k][i] + if (vecs[k][i] > yMax) yMax = vecs[k][i] + } + } + if (xMin >= xMax) { xMin = 0; xMax = 1 } + axX.min = xMin; axX.max = xMax + axX.titleText = xLabel + if (yMin >= yMax) { yMin = -1; yMax = 1 } + var pad = (yMax - yMin) * 0.05 + axY.min = yMin - pad; axY.max = yMax + pad + axY.titleText = yLabel + } + + function rebuildRpy() { + updateSeries(rpySeries0, _seconds, _rollVec) + updateSeries(rpySeries1, _seconds, _pitchVec) + updateSeries(rpySeries2, _seconds, _yawVec) + updateAxes(rpyAxisX, rpyAxisY, _seconds, [_rollVec, _pitchVec, _yawVec], + "Seconds (s)\nRoll: " + _curRoll.toFixed(3) + " Pitch: " + _curPitch.toFixed(3) + " Yaw: " + _curYaw.toFixed(3), + "Angle (Deg)") + } + + function rebuildAccel() { + updateSeries(accelSeries0, _seconds, _accXVec) + updateSeries(accelSeries1, _seconds, _accYVec) + updateSeries(accelSeries2, _seconds, _accZVec) + updateAxes(accelAxisX, accelAxisY, _seconds, [_accXVec, _accYVec, _accZVec], + "Seconds (s)\nX: " + _curAccX.toFixed(3) + " Y: " + _curAccY.toFixed(3) + " Z: " + _curAccZ.toFixed(3), + "Acceleration (G)") + } + + function rebuildGyro() { + updateSeries(gyroSeries0, _seconds, _gyroXVec) + updateSeries(gyroSeries1, _seconds, _gyroYVec) + updateSeries(gyroSeries2, _seconds, _gyroZVec) + updateAxes(gyroAxisX, gyroAxisY, _seconds, [_gyroXVec, _gyroYVec, _gyroZVec], + "Seconds (s)\nX: " + _curGyroX.toFixed(3) + " Y: " + _curGyroY.toFixed(3) + " Z: " + _curGyroZ.toFixed(3), + "Angular Velocity (Deg/s)") + } + + // ── Shared plot theme ─────────────────────────────────────── + property GraphsTheme _plotTheme: GraphsTheme { + colorScheme: Utility.isDarkMode() ? GraphsTheme.ColorScheme.Dark : GraphsTheme.ColorScheme.Light + plotAreaBackgroundColor: Utility.getAppHexColor("plotBackground") + grid.mainColor: Utility.isDarkMode() ? "#444444" : "#cccccc" + } + + // ───────────────────────────────────────────────────────────── + // MAIN LAYOUT + // ───────────────────────────────────────────────────────────── + SplitView { + anchors.fill: parent + orientation: Qt.Vertical + + // ── Top: param table ──────────────────────────────────── + Flickable { + SplitView.preferredHeight: parent.height * 0.35 + SplitView.minimumHeight: 100 + clip: true; contentWidth: width; contentHeight: paramCol.height + 16 + flickableDirection: Flickable.VerticalFlick + ScrollBar.vertical: ScrollBar { policy: ScrollBar.AsNeeded } + + ColumnLayout { + id: paramCol + width: parent.width + spacing: 4 + Item { Layout.preferredHeight: 1 } + } + } + + // ── Bottom: plots + 3D view ──────────────────────────── + SplitView { + orientation: Qt.Horizontal + SplitView.fillHeight: true + + // Left: tab bar at bottom with 3 plot tabs + ColumnLayout { + SplitView.fillWidth: true + SplitView.minimumWidth: 300 + spacing: 0 + + StackLayout { + Layout.fillWidth: true + Layout.fillHeight: true + currentIndex: plotTabBar.currentIndex + + // RPY Tab + GraphsView { + id: rpyPlot + theme: root._plotTheme + axisX: ValueAxis { id: rpyAxisX; min: 0; max: 1; titleText: "Seconds (s)" } + axisY: ValueAxis { id: rpyAxisY; min: -180; max: 180; titleText: "Angle (Deg)" } + } + + // Accel Tab + GraphsView { + id: accelPlot + theme: root._plotTheme + axisX: ValueAxis { id: accelAxisX; min: 0; max: 1; titleText: "Seconds (s)" } + axisY: ValueAxis { id: accelAxisY; min: -2; max: 2; titleText: "Acceleration (G)" } + } + + // Gyro Tab + GraphsView { + id: gyroPlot + theme: root._plotTheme + axisX: ValueAxis { id: gyroAxisX; min: 0; max: 1; titleText: "Seconds (s)" } + axisY: ValueAxis { id: gyroAxisY; min: -500; max: 500; titleText: "Angular Velocity (Deg/s)" } + } + } + + TabBar { + id: plotTabBar + Layout.fillWidth: true + TabButton { text: "RPY" } + TabButton { text: "Accel" } + TabButton { text: "Gyro" } + } + } + + // Right: Use Yaw checkbox + 3D view + ColumnLayout { + SplitView.preferredWidth: 250 + SplitView.minimumWidth: 180 + spacing: 4 + + CheckBox { + id: useYawBox + text: "Use Yaw (will drift)" + Layout.fillWidth: true + } + + Vesc3DView { + id: view3d + Layout.fillWidth: true + Layout.fillHeight: true + Layout.minimumHeight: 200 + } + } + } + } + + function loadSubgroup(parentCol, subgroup) { + var params = mAppConf.getParamsFromSubgroup("imu", subgroup) + for (var p = 0; p < params.length; p++) { + var paramName = params[p] + if (paramName.indexOf("::sep::") === 0) { + var sep = editors.createSeparator(parentCol, paramName.substring(7)) + if (sep) _dynamicItems.push(sep) + continue + } + var e = editors.createEditorApp(parentCol, paramName) + if (e) { e.Layout.fillWidth = true; _dynamicItems.push(e) } + } + } + + Component.onCompleted: { + loadSubgroup(paramCol, "general") + view3d.setRotation(20 * Math.PI / 180, 20 * Math.PI / 180, 0) + } +} diff --git a/desktop/AppNrfPage.qml b/desktop/AppNrfPage.qml new file mode 100644 index 000000000..8cb0b1813 --- /dev/null +++ b/desktop/AppNrfPage.qml @@ -0,0 +1,138 @@ +/* + Desktop AppNrfPage — exact parity with PageAppNrf widget. + Layout: VBoxLayout + ParamTable for "nrf" / "general" + NRF Pairing GroupBox at bottom +*/ +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import Vedder.vesc + +Item { + id: root + + property ConfigParams mAppConf: VescIf.appConfig() + property Commands mCommands: VescIf.commands() + property var _dynamicItems: [] + + // NRF pairing state + property double _pairCnt: 0.0 + property bool _pairRunning: false + + ParamEditors { id: editors } + + Connections { + target: mCommands + function onNrfPairingRes(res) { + if (!_pairRunning) return + if (res === 0) { + _pairCnt = nrfTimeBox.realValue + nrfStartBtn.enabled = false + } else if (res === 1) { + nrfStartBtn.enabled = true + _pairCnt = 0 + VescIf.emitStatusMessage("Pairing NRF Successful", true) + _pairRunning = false + } else if (res === 2) { + nrfStartBtn.enabled = true + _pairCnt = 0 + VescIf.emitStatusMessage("Pairing NRF Timed Out", false) + _pairRunning = false + } + } + } + + Timer { + interval: 100; running: true; repeat: true + onTriggered: { + if (_pairCnt > 0.01) { + _pairCnt -= 0.1 + if (_pairCnt <= 0.01) { + nrfStartBtn.enabled = true + _pairCnt = 0 + } + } + } + } + + ColumnLayout { + anchors.fill: parent + spacing: 0 + + Flickable { + Layout.fillWidth: true + Layout.fillHeight: true + clip: true; contentWidth: width; contentHeight: genCol.height + 16 + flickableDirection: Flickable.VerticalFlick + ScrollBar.vertical: ScrollBar { policy: ScrollBar.AsNeeded } + + ColumnLayout { + id: genCol + width: parent.width + spacing: 4 + Item { Layout.preferredHeight: 1 } + } + } + + // NRF Pairing GroupBox (at bottom, matching PageAppNrf layout) + GroupBox { + title: "NRF Pairing" + Layout.fillWidth: true + + RowLayout { + anchors.fill: parent + spacing: 4 + + Button { + id: nrfStartBtn + icon.source: "qrc" + Utility.getThemePath() + "icons/Circled Play-96.png" + ToolTip.text: "Start Pairing"; ToolTip.visible: hovered + onClicked: { + mCommands.pairNrf(Math.round(nrfTimeBox.realValue * 1000)) + _pairRunning = true + } + } + + SpinBox { + id: nrfTimeBox + from: 10; to: 1000; value: 100; stepSize: 10 + editable: true + property double realValue: value / 10.0 + textFromValue: function(v) { return "Time: " + (v / 10.0).toFixed(1) + " s" } + valueFromText: function(t) { return Math.round(parseFloat(t.replace("Time: ", "").replace(" s", "")) * 10) || 100 } + ToolTip.text: "Stay in pairing mode for this amount of time" + ToolTip.visible: nrfTimeHover.hovered; ToolTip.delay: 500 + HoverHandler { id: nrfTimeHover } + } + + Label { + text: _pairCnt.toFixed(1) + font.bold: true + horizontalAlignment: Text.AlignHCenter + Layout.preferredWidth: 40 + background: Rectangle { border.width: 1; border.color: palette.mid; radius: 2; color: "transparent" } + padding: 4 + } + } + } + } + + function loadSubgroup(parentCol, subgroup) { + var params = mAppConf.getParamsFromSubgroup("nrf", subgroup) + for (var p = 0; p < params.length; p++) { + var paramName = params[p] + if (paramName.indexOf("::sep::") === 0) { + var sep = editors.createSeparator(parentCol, paramName.substring(7)) + if (sep) _dynamicItems.push(sep) + continue + } + var e = editors.createEditorApp(parentCol, paramName) + if (e) { e.Layout.fillWidth = true; _dynamicItems.push(e) } + } + } + + Component.onCompleted: { + loadSubgroup(genCol, "general") + } +} diff --git a/desktop/AppNunchukPage.qml b/desktop/AppNunchukPage.qml new file mode 100644 index 000000000..3e489ae78 --- /dev/null +++ b/desktop/AppNunchukPage.qml @@ -0,0 +1,264 @@ +/* + Desktop AppNunchukPage — exact parity with PageAppNunchuk widget. + Layout: VBoxLayout + TabWidget (General | Throttle Curve) + General: ParamTable of "VESC Remote" / "general" + DisplayPercentage (h=30) + Throttle: ParamTable (fixed h~100) + throttle curve plot + NrfPair GroupBox at bottom +*/ +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import QtGraphs +import Vedder.vesc + +Item { + id: root + + property ConfigParams mAppConf: VescIf.appConfig() + property Commands mCommands: VescIf.commands() + property var _dynamicItems: [] + + // NRF pairing state + property double _pairCnt: 0.0 + property bool _pairRunning: false + + ParamEditors { id: editors } + + function updateThrottleCurve() { + var mode = mAppConf.getParamEnum("app_chuk_conf.throttle_exp_mode") + var valAcc = mAppConf.getParamDouble("app_chuk_conf.throttle_exp") + var valBrk = mAppConf.getParamDouble("app_chuk_conf.throttle_exp_brake") + + for (var si = throttlePlot.count - 1; si >= 0; si--) + throttlePlot.removeSeries(throttlePlot.seriesAt(si)) + + var series = throttlePlot.createSeries(GraphsView.SeriesTypeLine, "Throttle Curve") + series.color = Utility.getAppHexColor("plot_graph1") + series.width = 1.5 + + for (var i = -1.0; i <= 1.0001; i += 0.002) + series.append(i, Utility.throttle_curve(i, valAcc, valBrk, mode)) + + throttleAxisX.min = -1.0; throttleAxisX.max = 1.0 + var yMin = -1.0, yMax = 1.0 + for (var j = 0; j < series.count; j++) { + var pt = series.at(j) + if (pt.y < yMin) yMin = pt.y + if (pt.y > yMax) yMax = pt.y + } + var pad = (yMax - yMin) * 0.05 + throttleAxisY.min = yMin - pad + throttleAxisY.max = yMax + pad + } + + Connections { + target: mAppConf + function onParamChangedDouble(src, name, newParam) { + if (name === "app_chuk_conf.throttle_exp" || name === "app_chuk_conf.throttle_exp_brake") + updateThrottleCurve() + } + function onParamChangedEnum(src, name, newParam) { + if (name === "app_chuk_conf.throttle_exp_mode") + updateThrottleCurve() + } + } + + Connections { + target: mCommands + function onDecodedChukReceived(value) { + var p = value * 100.0 + chukBar.value = p / 100.0 + chukLabel.text = p.toFixed(1) + " %" + } + + function onNrfPairingRes(res) { + if (!_pairRunning) return + if (res === 0) { // NRF_PAIR_STARTED + _pairCnt = nrfTimeBox.value + nrfStartBtn.enabled = false + } else if (res === 1) { // NRF_PAIR_OK + nrfStartBtn.enabled = true + _pairCnt = 0 + VescIf.emitStatusMessage("Pairing NRF Successful", true) + _pairRunning = false + } else if (res === 2) { // NRF_PAIR_FAIL + nrfStartBtn.enabled = true + _pairCnt = 0 + VescIf.emitStatusMessage("Pairing NRF Timed Out", false) + _pairRunning = false + } + } + } + + Timer { + interval: 100; running: true; repeat: true + onTriggered: { + if (_pairCnt > 0.01) { + _pairCnt -= 0.1 + if (_pairCnt <= 0.01) { + nrfStartBtn.enabled = true + _pairCnt = 0 + } + } + } + } + + ColumnLayout { + anchors.fill: parent + spacing: 0 + + TabBar { + id: tabBar + Layout.fillWidth: true + TabButton { text: "General" } + TabButton { text: "Throttle Curve" } + } + + StackLayout { + Layout.fillWidth: true + Layout.fillHeight: true + currentIndex: tabBar.currentIndex + + // Tab 0: General + DisplayPercentage + Flickable { + clip: true; contentWidth: width; contentHeight: genLayout.height + 16 + flickableDirection: Flickable.VerticalFlick + ScrollBar.vertical: ScrollBar { policy: ScrollBar.AsNeeded } + + ColumnLayout { + id: genLayout + width: parent.width + spacing: 4 + + Item { Layout.preferredHeight: 1 } + + ColumnLayout { + id: genCol + Layout.fillWidth: true + spacing: 4 + } + + // DisplayPercentage equivalent (dual, min height 30) + Rectangle { + Layout.fillWidth: true + Layout.preferredHeight: 30 + color: "transparent" + border.width: 1 + border.color: palette.mid + radius: 2 + + RowLayout { + anchors.fill: parent + anchors.margins: 2 + + ProgressBar { + id: chukBar + Layout.fillWidth: true + from: -1; to: 1; value: 0 + } + + Label { + id: chukLabel + text: "-- %" + font.pixelSize: 12 + horizontalAlignment: Text.AlignRight + Layout.preferredWidth: 80 + } + } + } + } + } + + // Tab 1: Throttle Curve + ColumnLayout { + spacing: 0 + + Flickable { + Layout.fillWidth: true + Layout.preferredHeight: 100; Layout.maximumHeight: 100 + clip: true; contentWidth: width; contentHeight: tcCol.height + 16 + flickableDirection: Flickable.VerticalFlick + ScrollBar.vertical: ScrollBar { policy: ScrollBar.AsNeeded } + ColumnLayout { id: tcCol; width: parent.width; spacing: 4; Item { Layout.preferredHeight: 1 } } + } + + GraphsView { + id: throttlePlot + Layout.fillWidth: true + Layout.fillHeight: true + + theme: GraphsTheme { + colorScheme: Utility.isDarkMode() ? GraphsTheme.ColorScheme.Dark : GraphsTheme.ColorScheme.Light + plotAreaBackgroundColor: Utility.getAppHexColor("plotBackground") + grid.mainColor: Utility.isDarkMode() ? "#444444" : "#cccccc" + } + + axisX: ValueAxis { id: throttleAxisX; min: -1; max: 1; titleText: "Throttle Value" } + axisY: ValueAxis { id: throttleAxisY; min: -1; max: 1; titleText: "Output Value" } + } + } + } + + // NRF Pairing GroupBox (below TabWidget, matching original layout) + GroupBox { + title: "NRF Pairing" + Layout.fillWidth: true + + RowLayout { + anchors.fill: parent + spacing: 4 + + Button { + id: nrfStartBtn + icon.source: "qrc" + Utility.getThemePath() + "icons/Circled Play-96.png" + ToolTip.text: "Start Pairing"; ToolTip.visible: hovered + onClicked: { + mCommands.pairNrf(Math.round(nrfTimeBox.value * 1000)) + _pairRunning = true + } + } + + SpinBox { + id: nrfTimeBox + from: 10; to: 1000; value: 100; stepSize: 10 + editable: true + property double realValue: value / 10.0 + textFromValue: function(v) { return "Time: " + (v / 10.0).toFixed(1) + " s" } + valueFromText: function(t) { return Math.round(parseFloat(t.replace("Time: ", "").replace(" s", "")) * 10) || 100 } + ToolTip.text: "Stay in pairing mode for this amount of time" + ToolTip.visible: nrfTimeHover.hovered; ToolTip.delay: 500 + HoverHandler { id: nrfTimeHover } + } + + Label { + text: _pairCnt.toFixed(1) + font.bold: true + horizontalAlignment: Text.AlignHCenter + Layout.preferredWidth: 40 + background: Rectangle { border.width: 1; border.color: palette.mid; radius: 2; color: "transparent" } + padding: 4 + } + } + } + } + + function loadSubgroup(parentCol, subgroup) { + var params = mAppConf.getParamsFromSubgroup("VESC Remote", subgroup) + for (var p = 0; p < params.length; p++) { + var paramName = params[p] + if (paramName.indexOf("::sep::") === 0) { + var sep = editors.createSeparator(parentCol, paramName.substring(7)) + if (sep) _dynamicItems.push(sep) + continue + } + var e = editors.createEditorApp(parentCol, paramName) + if (e) { e.Layout.fillWidth = true; _dynamicItems.push(e) } + } + } + + Component.onCompleted: { + loadSubgroup(genCol, "general") + loadSubgroup(tcCol, "throttle curve") + } +} diff --git a/desktop/AppPasPage.qml b/desktop/AppPasPage.qml new file mode 100644 index 000000000..28cda690a --- /dev/null +++ b/desktop/AppPasPage.qml @@ -0,0 +1,8 @@ +import QtQuick +import QtQuick.Controls +import Vedder.vesc + +ParamGroupPage { + configParams: VescIf.appConfig() + groupName: "PAS" +} diff --git a/desktop/AppPpmPage.qml b/desktop/AppPpmPage.qml new file mode 100644 index 000000000..00d77ecd8 --- /dev/null +++ b/desktop/AppPpmPage.qml @@ -0,0 +1,292 @@ +/* + Desktop AppPpmPage — exact parity with PageAppPpm widget. + Layout: TabWidget (General | Mapping | Throttle Curve) + General: ParamTable of "PPM" / "general" + Mapping: ParamTable of "PPM" / "mapping" + PPM Mapping GroupBox + Throttle: ParamTable (fixed height ~100) + throttle curve plot +*/ +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import QtGraphs +import Vedder.vesc + +Item { + id: root + + property ConfigParams mAppConf: VescIf.appConfig() + property Commands mCommands: VescIf.commands() + property var _dynamicItems: [] + property bool _mapResetDone: true + property double _mapMinVal: 0.0 + property double _mapMaxVal: 0.0 + property double _mapCenterVal: 0.0 + + ParamEditors { id: editors } + + function updateThrottleCurve() { + var mode = mAppConf.getParamEnum("app_ppm_conf.throttle_exp_mode") + var valAcc = mAppConf.getParamDouble("app_ppm_conf.throttle_exp") + var valBrk = mAppConf.getParamDouble("app_ppm_conf.throttle_exp_brake") + + for (var si = throttlePlot.count - 1; si >= 0; si--) + throttlePlot.removeSeries(throttlePlot.seriesAt(si)) + + var series = throttlePlot.createSeries(GraphsView.SeriesTypeLine, "Throttle Curve") + series.color = Utility.getAppHexColor("plot_graph1") + series.width = 1.5 + + for (var i = -1.0; i <= 1.0001; i += 0.002) + series.append(i, Utility.throttle_curve(i, valAcc, valBrk, mode)) + + // Auto-rescale + throttleAxisX.min = -1.0; throttleAxisX.max = 1.0 + var yMin = -1.0, yMax = 1.0 + for (var j = 0; j < series.count; j++) { + var pt = series.at(j) + if (pt.y < yMin) yMin = pt.y + if (pt.y > yMax) yMax = pt.y + } + var pad = (yMax - yMin) * 0.05 + throttleAxisY.min = yMin - pad + throttleAxisY.max = yMax + pad + } + + Connections { + target: mAppConf + function onParamChangedDouble(src, name, newParam) { + if (name === "app_ppm_conf.throttle_exp" || name === "app_ppm_conf.throttle_exp_brake") + updateThrottleCurve() + } + function onParamChangedEnum(src, name, newParam) { + if (name === "app_ppm_conf.throttle_exp_mode") + updateThrottleCurve() + } + } + + Connections { + target: mCommands + function onDecodedPpmReceived(value, lastLen) { + // PPM mapping display update + var minNow = mAppConf.getParamDouble("app_ppm_conf.pulse_start") + var maxNow = mAppConf.getParamDouble("app_ppm_conf.pulse_end") + var centerNow = mAppConf.getParamDouble("app_ppm_conf.pulse_center") + + // VESC Tool preview (using current config mapping) + var p + if (dualBox.checked) { + if (lastLen < centerNow) + p = Utility.map(lastLen, minNow, centerNow, -100.0, 0.0) + else + p = Utility.map(lastLen, centerNow, maxNow, 0.0, 100.0) + } else { + p = Utility.map(lastLen, minNow, maxNow, 0.0, 100.0) + } + ppmToolBar.value = Math.max(-100, Math.min(100, p)) / 100.0 + ppmToolLabel.text = lastLen.toFixed(4) + " ms (" + p.toFixed(1) + " %)" + + // VESC Firmware preview + var p2 = dualBox.checked ? value * 100.0 : (value + 1.0) * 50.0 + ppmFwBar.value = Math.max(-100, Math.min(100, p2)) / 100.0 + ppmFwLabel.text = lastLen.toFixed(4) + " ms (" + p2.toFixed(1) + " %)" + + // Auto min/max tracking + if (_mapResetDone) { + _mapResetDone = false + _mapMinVal = lastLen + _mapMaxVal = lastLen + } else { + if (lastLen < _mapMinVal && lastLen > 1e-3) _mapMinVal = lastLen + if (lastLen > _mapMaxVal) _mapMaxVal = lastLen + } + + var range = _mapMaxVal - _mapMinVal + var pos = lastLen - _mapMinVal + if (pos > range / 4.0 && pos < (3.0 * range) / 4.0) + _mapCenterVal = lastLen + else + _mapCenterVal = range / 2.0 + _mapMinVal + } + } + + ColumnLayout { + anchors.fill: parent + spacing: 0 + + TabBar { + id: tabBar + Layout.fillWidth: true + TabButton { text: "General" } + TabButton { text: "Mapping" } + TabButton { text: "Throttle Curve" } + } + + StackLayout { + Layout.fillWidth: true + Layout.fillHeight: true + currentIndex: tabBar.currentIndex + + // Tab 0: General + Flickable { + clip: true; contentWidth: width; contentHeight: genCol.height + 16 + flickableDirection: Flickable.VerticalFlick + ScrollBar.vertical: ScrollBar { policy: ScrollBar.AsNeeded } + ColumnLayout { id: genCol; width: parent.width; spacing: 4; Item { Layout.preferredHeight: 1 } } + } + + // Tab 1: Mapping + Flickable { + clip: true; contentWidth: width; contentHeight: mapLayout.height + 16 + flickableDirection: Flickable.VerticalFlick + ScrollBar.vertical: ScrollBar { policy: ScrollBar.AsNeeded } + + ColumnLayout { + id: mapLayout + width: parent.width + spacing: 4 + + Item { Layout.preferredHeight: 1 } + + // Dynamic params inserted here via mapCol + ColumnLayout { + id: mapCol + Layout.fillWidth: true + spacing: 4 + } + + // PPM Pulselength Mapping GroupBox + GroupBox { + title: "PPM Pulselength Mapping" + Layout.fillWidth: true + + ColumnLayout { + anchors.fill: parent + spacing: 4 + + RowLayout { + spacing: 4 + CheckBox { + id: dualBox + text: "Use Centered Control" + ToolTip.text: "Show centered graph, which is how the centered control modes interpret the throttle." + ToolTip.visible: dualHover.hovered; ToolTip.delay: 500 + HoverHandler { id: dualHover } + } + Button { + text: "Reset" + ToolTip.text: "Reset min and max"; ToolTip.visible: hovered + onClicked: { _mapResetDone = true; _mapMinVal = 0; _mapMaxVal = 0 } + } + Button { + icon.source: "qrc" + Utility.getThemePath() + "icons/Ok-96.png" + text: "Apply" + ToolTip.text: "Apply min, max and center to VESC Tool configuration"; ToolTip.visible: hovered + onClicked: { + if (_mapMaxVal > 1e-10) { + mAppConf.updateParamDouble("app_ppm_conf.pulse_start", _mapMinVal) + mAppConf.updateParamDouble("app_ppm_conf.pulse_end", _mapMaxVal) + mAppConf.updateParamDouble("app_ppm_conf.pulse_center", _mapCenterVal) + VescIf.emitStatusMessage("Start, End and Center Pulselengths Applied", true) + } else { + VescIf.emitStatusMessage("Applying Pulselengths Failed", false) + } + } + } + } + + RowLayout { + spacing: 2 + Label { text: "Min: " + _mapMinVal.toFixed(4) + " ms"; Layout.fillWidth: true + background: Rectangle { border.width: 1; border.color: palette.mid; radius: 2; color: "transparent" } + padding: 4 + } + Label { text: "Max: " + _mapMaxVal.toFixed(4) + " ms"; Layout.fillWidth: true + background: Rectangle { border.width: 1; border.color: palette.mid; radius: 2; color: "transparent" } + padding: 4 + } + Label { text: "Center: " + _mapCenterVal.toFixed(4) + " ms"; Layout.fillWidth: true + background: Rectangle { border.width: 1; border.color: palette.mid; radius: 2; color: "transparent" } + padding: 4 + } + } + + GridLayout { + columns: 2 + Layout.fillWidth: true + columnSpacing: 4; rowSpacing: 2 + + Label { text: "VESC Tool" } + ColumnLayout { + Layout.fillWidth: true + spacing: 0 + ProgressBar { id: ppmToolBar; Layout.fillWidth: true; from: -1; to: 1; value: 0; Layout.preferredHeight: 25 } + Label { id: ppmToolLabel; text: "-- ms (-- %)"; font.pixelSize: 11; color: Utility.getAppHexColor("lightText") } + } + + Label { text: "VESC Firmware" } + ColumnLayout { + Layout.fillWidth: true + spacing: 0 + ProgressBar { id: ppmFwBar; Layout.fillWidth: true; from: -1; to: 1; value: 0; Layout.preferredHeight: 25 } + Label { id: ppmFwLabel; text: "-- ms (-- %)"; font.pixelSize: 11; color: Utility.getAppHexColor("lightText") } + } + } + } + } + } + } + + // Tab 2: Throttle Curve + ColumnLayout { + spacing: 0 + + // Params (fixed height ~100, matching original) + Flickable { + Layout.fillWidth: true + Layout.preferredHeight: 100 + Layout.maximumHeight: 100 + clip: true; contentWidth: width; contentHeight: tcCol.height + 16 + flickableDirection: Flickable.VerticalFlick + ScrollBar.vertical: ScrollBar { policy: ScrollBar.AsNeeded } + ColumnLayout { id: tcCol; width: parent.width; spacing: 4; Item { Layout.preferredHeight: 1 } } + } + + // Throttle curve plot + GraphsView { + id: throttlePlot + Layout.fillWidth: true + Layout.fillHeight: true + + theme: GraphsTheme { + colorScheme: Utility.isDarkMode() ? GraphsTheme.ColorScheme.Dark : GraphsTheme.ColorScheme.Light + plotAreaBackgroundColor: Utility.getAppHexColor("plotBackground") + grid.mainColor: Utility.isDarkMode() ? "#444444" : "#cccccc" + } + + axisX: ValueAxis { id: throttleAxisX; min: -1; max: 1; titleText: "Throttle Value" } + axisY: ValueAxis { id: throttleAxisY; min: -1; max: 1; titleText: "Output Value" } + } + } + } + } + + function loadSubgroup(parentCol, subgroup) { + var params = mAppConf.getParamsFromSubgroup("PPM", subgroup) + for (var p = 0; p < params.length; p++) { + var paramName = params[p] + if (paramName.indexOf("::sep::") === 0) { + var sep = editors.createSeparator(parentCol, paramName.substring(7)) + if (sep) _dynamicItems.push(sep) + continue + } + var e = editors.createEditorApp(parentCol, paramName) + if (e) { e.Layout.fillWidth = true; _dynamicItems.push(e) } + } + } + + Component.onCompleted: { + loadSubgroup(genCol, "general") + loadSubgroup(mapCol, "mapping") + loadSubgroup(tcCol, "throttle curve") + } +} diff --git a/desktop/AppUartPage.qml b/desktop/AppUartPage.qml new file mode 100644 index 000000000..136805942 --- /dev/null +++ b/desktop/AppUartPage.qml @@ -0,0 +1,8 @@ +import QtQuick +import QtQuick.Controls +import Vedder.vesc + +ParamGroupPage { + configParams: VescIf.appConfig() + groupName: "UART" +} diff --git a/desktop/BmsPage.qml b/desktop/BmsPage.qml new file mode 100644 index 000000000..43d736870 --- /dev/null +++ b/desktop/BmsPage.qml @@ -0,0 +1,201 @@ +/* + Desktop BmsPage — native implementation matching the original widget page. + Features: Cell voltage bar chart, temperature bar chart, value table, + control buttons (balance on/off, charge enable/disable, reset counters). +*/ +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import QtGraphs +import Vedder.vesc + +Item { + id: bmsPage + + property Commands mCommands: VescIf.commands() + + SplitView { + anchors.fill: parent + orientation: Qt.Horizontal + + // Left: Charts + ColumnLayout { + SplitView.fillWidth: true + SplitView.minimumWidth: 400 + spacing: 4 + + TabBar { + id: bmsTabBar + Layout.fillWidth: true + TabButton { text: "Cell Voltages" } + TabButton { text: "Temperatures" } + } + + StackLayout { + Layout.fillWidth: true + Layout.fillHeight: true + currentIndex: bmsTabBar.currentIndex + + // Cell voltage chart + GraphsView { + id: cellChart + theme: GraphsTheme { + colorScheme: Utility.isDarkMode() ? GraphsTheme.ColorScheme.Dark : GraphsTheme.ColorScheme.Light + plotAreaBackgroundColor: Utility.getAppHexColor("plotBackground") + grid.mainColor: Utility.isDarkMode() ? "#444444" : "#cccccc" + } + + axisX: ValueAxis { id: cellAxisX; min: 0; max: 13; titleText: "Cell" } + axisY: ValueAxis { id: cellAxisY; min: 2.5; max: 4.4; titleText: "Voltage (V)" } + + BarSeries { + id: cellBarSeries + barWidth: 0.6 + } + } + + // Temperature chart + GraphsView { + id: tempChart + theme: GraphsTheme { + colorScheme: Utility.isDarkMode() ? GraphsTheme.ColorScheme.Dark : GraphsTheme.ColorScheme.Light + plotAreaBackgroundColor: Utility.getAppHexColor("plotBackground") + grid.mainColor: Utility.isDarkMode() ? "#444444" : "#cccccc" + } + + axisX: ValueAxis { id: tempAxisX; min: 0; max: 6; titleText: "Sensor" } + axisY: ValueAxis { id: tempAxisY; min: -20; max: 90; titleText: "Temperature (°C)" } + + BarSeries { + id: tempBarSeries + barWidth: 0.6 + } + } + } + + // Control buttons + RowLayout { + Layout.fillWidth: true + Layout.margins: 4 + spacing: 4 + + Button { text: "Balance On"; onClicked: mCommands.bmsForceBalance(true) } + Button { text: "Balance Off"; onClicked: mCommands.bmsForceBalance(false) } + Button { text: "Charge Enable"; onClicked: mCommands.bmsSetChargeAllowed(true) } + Button { text: "Charge Disable"; onClicked: mCommands.bmsSetChargeAllowed(false) } + Button { text: "Zero Current"; onClicked: mCommands.bmsZeroCurrentOffset() } + Button { text: "Reset Ah"; onClicked: mCommands.bmsResetCounters(true, false) } + Button { text: "Reset Wh"; onClicked: mCommands.bmsResetCounters(false, true) } + } + } + + // Right: Value table + ScrollView { + SplitView.preferredWidth: 280 + SplitView.minimumWidth: 200 + clip: true + + ColumnLayout { + width: parent.width + spacing: 2 + + Label { + text: "BMS Values" + font.bold: true + font.pixelSize: 14 + Layout.fillWidth: true + horizontalAlignment: Text.AlignHCenter + Layout.bottomMargin: 4 + } + + Repeater { + id: valRepeater + model: ListModel { + id: valModel + ListElement { label: "V Total"; val: "--" } + ListElement { label: "V Cell Min"; val: "--" } + ListElement { label: "V Cell Max"; val: "--" } + ListElement { label: "V Cell Diff"; val: "--" } + ListElement { label: "V Charge"; val: "--" } + ListElement { label: "Current"; val: "--" } + ListElement { label: "Current IC"; val: "--" } + ListElement { label: "Ah Counter"; val: "--" } + ListElement { label: "Wh Counter"; val: "--" } + ListElement { label: "Power"; val: "--" } + ListElement { label: "SoC"; val: "--" } + ListElement { label: "SoH"; val: "--" } + ListElement { label: "T Cell Max"; val: "--" } + ListElement { label: "T PCB Max"; val: "--" } + ListElement { label: "Humidity"; val: "--" } + ListElement { label: "Pressure"; val: "--" } + ListElement { label: "Ah Chg Total"; val: "--" } + ListElement { label: "Wh Chg Total"; val: "--" } + ListElement { label: "Ah Dis Total"; val: "--" } + ListElement { label: "Wh Dis Total"; val: "--" } + ListElement { label: "Status"; val: "--" } + } + + RowLayout { + Layout.fillWidth: true + spacing: 4 + Label { + text: model.label + ":" + font.pixelSize: 11 + Layout.preferredWidth: 100 + color: Utility.getAppHexColor("lightText") + } + Label { + text: model.val + font.pixelSize: 11 + font.family: "DejaVu Sans Mono" + Layout.fillWidth: true + color: Utility.getAppHexColor("lightText") + } + } + } + } + } + } + + Connections { + target: mCommands + function onBmsValuesRx(val) { + // Update value table + var vcMin = 0, vcMax = 0 + if (val.v_cells.length > 0) { + vcMin = val.v_cells[0] + vcMax = vcMin + for (var i = 0; i < val.v_cells.length; i++) { + if (val.v_cells[i] < vcMin) vcMin = val.v_cells[i] + if (val.v_cells[i] > vcMax) vcMax = val.v_cells[i] + } + } + + var idx = 0 + valModel.setProperty(idx++, "val", val.v_tot.toFixed(2) + " V") + valModel.setProperty(idx++, "val", vcMin.toFixed(3) + " V") + valModel.setProperty(idx++, "val", vcMax.toFixed(3) + " V") + valModel.setProperty(idx++, "val", (vcMax - vcMin).toFixed(3) + " V") + valModel.setProperty(idx++, "val", val.v_charge.toFixed(2) + " V") + valModel.setProperty(idx++, "val", val.i_in.toFixed(2) + " A") + valModel.setProperty(idx++, "val", val.i_in_ic.toFixed(2) + " A") + valModel.setProperty(idx++, "val", val.ah_cnt.toFixed(3) + " Ah") + valModel.setProperty(idx++, "val", val.wh_cnt.toFixed(3) + " Wh") + valModel.setProperty(idx++, "val", (val.i_in_ic * val.v_tot).toFixed(3) + " W") + valModel.setProperty(idx++, "val", (val.soc * 100).toFixed(0) + " %") + valModel.setProperty(idx++, "val", (val.soh * 100).toFixed(0) + " %") + valModel.setProperty(idx++, "val", val.temp_cells_highest.toFixed(2) + " °C") + valModel.setProperty(idx++, "val", val.temp_hum_sensor.toFixed(2) + " °C") + valModel.setProperty(idx++, "val", val.humidity.toFixed(2) + " % (" + val.temp_hum_sensor.toFixed(2) + " °C)") + valModel.setProperty(idx++, "val", val.pressure.toFixed(0) + " Pa") + valModel.setProperty(idx++, "val", val.ah_cnt_chg_total.toFixed(3) + " Ah") + valModel.setProperty(idx++, "val", val.wh_cnt_chg_total.toFixed(3) + " Wh") + valModel.setProperty(idx++, "val", val.ah_cnt_dis_total.toFixed(3) + " Ah") + valModel.setProperty(idx++, "val", val.wh_cnt_dis_total.toFixed(3) + " Wh") + valModel.setProperty(idx++, "val", val.status) + + // Update cell chart axis + cellAxisX.max = val.v_cells.length + 1 + } + } +} diff --git a/desktop/CanAnalyzerPage.qml b/desktop/CanAnalyzerPage.qml new file mode 100644 index 000000000..d462d84f0 --- /dev/null +++ b/desktop/CanAnalyzerPage.qml @@ -0,0 +1,261 @@ +/* + Desktop CanAnalyzerPage — faithful recreation of the original PageCanAnalyzer widget. + Features: CAN baudrate update, CAN mode/baudrate params, message table, + send frame controls (ID + 8 data bytes), clear/auto-scroll. +*/ +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import Vedder.vesc + +Item { + id: canAnalyzerPage + + property Commands mCommands: VescIf.commands() + property ConfigParams mAppConf: VescIf.appConfig() + property var _dynamicItems: [] + + ParamEditors { + id: editors + } + + ColumnLayout { + anchors.fill: parent + anchors.margins: 4 + spacing: 4 + + // Update CAN Baudrate group + GroupBox { + title: "Update CAN Baudrate" + Layout.fillWidth: true + + RowLayout { + anchors.fill: parent + spacing: 8 + + Label { text: "KBits/sec" } + ComboBox { + id: canBaudBox + textRole: "display" + model: Utility.stringListModel(["125", "250", "500", "1000", "10", "20", "50", "75", "100"]) + currentIndex: 2 + } + Button { + text: "Start Update" + onClicked: { + VescIf.emitMessageDialog("Update CAN Baudrate", + "This is going to update the CAN-bus baudrate on all connected " + + "VESC-based devices. This is only supported in firmware 6.06 or " + + "later. If the update fails the CAN-bus might become unusable until " + + "it is reconfigured manually. Do you want to continue?", + false, false) + } + } + Item { Layout.fillWidth: true } + } + } + + // CAN mode/baudrate params + Flickable { + Layout.fillWidth: true + Layout.preferredHeight: paramCol.height + 8 + Layout.maximumHeight: 120 + clip: true; contentWidth: width; contentHeight: paramCol.height + 8 + flickableDirection: Flickable.VerticalFlick + ColumnLayout { + id: paramCol; width: parent.width; spacing: 4 + Item { Layout.preferredHeight: 1 } + } + } + + // Send CAN Frame group + GroupBox { + title: "Send CAN Frame" + Layout.fillWidth: true + + RowLayout { + anchors.fill: parent + spacing: 4 + + Label { text: "ID:" } + TextField { + id: sendIdEdit + Layout.preferredWidth: 100 + text: "0x00000000" + placeholderText: "0x or decimal" + } + + ComboBox { + id: sendExtBox + textRole: "display" + model: Utility.stringListModel(["Standard", "Extended"]) + currentIndex: 0 + } + + SpinBox { id: d0Box; from: -1; to: 255; value: 0; editable: true; Layout.preferredWidth: 70 + textFromValue: function(v) { return v < 0 ? "--" : "0x" + v.toString(16).toUpperCase().padStart(2, "0") } + valueFromText: function(t) { if (t === "--") return -1; return parseInt(t.replace(/0[xX]/, ""), 16) } } + SpinBox { id: d1Box; from: -1; to: 255; value: -1; editable: true; Layout.preferredWidth: 70 + textFromValue: function(v) { return v < 0 ? "--" : "0x" + v.toString(16).toUpperCase().padStart(2, "0") } + valueFromText: function(t) { if (t === "--") return -1; return parseInt(t.replace(/0[xX]/, ""), 16) } } + SpinBox { id: d2Box; from: -1; to: 255; value: -1; editable: true; Layout.preferredWidth: 70 + textFromValue: function(v) { return v < 0 ? "--" : "0x" + v.toString(16).toUpperCase().padStart(2, "0") } + valueFromText: function(t) { if (t === "--") return -1; return parseInt(t.replace(/0[xX]/, ""), 16) } } + SpinBox { id: d3Box; from: -1; to: 255; value: -1; editable: true; Layout.preferredWidth: 70 + textFromValue: function(v) { return v < 0 ? "--" : "0x" + v.toString(16).toUpperCase().padStart(2, "0") } + valueFromText: function(t) { if (t === "--") return -1; return parseInt(t.replace(/0[xX]/, ""), 16) } } + SpinBox { id: d4Box; from: -1; to: 255; value: -1; editable: true; Layout.preferredWidth: 70 + textFromValue: function(v) { return v < 0 ? "--" : "0x" + v.toString(16).toUpperCase().padStart(2, "0") } + valueFromText: function(t) { if (t === "--") return -1; return parseInt(t.replace(/0[xX]/, ""), 16) } } + SpinBox { id: d5Box; from: -1; to: 255; value: -1; editable: true; Layout.preferredWidth: 70 + textFromValue: function(v) { return v < 0 ? "--" : "0x" + v.toString(16).toUpperCase().padStart(2, "0") } + valueFromText: function(t) { if (t === "--") return -1; return parseInt(t.replace(/0[xX]/, ""), 16) } } + SpinBox { id: d6Box; from: -1; to: 255; value: -1; editable: true; Layout.preferredWidth: 70 + textFromValue: function(v) { return v < 0 ? "--" : "0x" + v.toString(16).toUpperCase().padStart(2, "0") } + valueFromText: function(t) { if (t === "--") return -1; return parseInt(t.replace(/0[xX]/, ""), 16) } } + SpinBox { id: d7Box; from: -1; to: 255; value: -1; editable: true; Layout.preferredWidth: 70 + textFromValue: function(v) { return v < 0 ? "--" : "0x" + v.toString(16).toUpperCase().padStart(2, "0") } + valueFromText: function(t) { if (t === "--") return -1; return parseInt(t.replace(/0[xX]/, ""), 16) } } + + Button { + text: "Send" + onClicked: { + var vals = [d0Box.value, d1Box.value, d2Box.value, d3Box.value, + d4Box.value, d5Box.value, d6Box.value, d7Box.value] + var bytes = [] + for (var i = 0; i < 8; i++) { + if (vals[i] >= 0) bytes.push(vals[i]) + else break + } + + var idTxt = sendIdEdit.text.toLowerCase().replace(" ", "") + var id = 0 + var ok = false + if (idTxt.startsWith("0x")) { + id = parseInt(idTxt.substring(2), 16) + ok = !isNaN(id) + } else { + id = parseInt(idTxt, 10) + ok = !isNaN(id) + } + + if (ok) { + mCommands.forwardCanFrame(bytes, id, sendExtBox.currentIndex === 1) + } else { + VescIf.emitMessageDialog("Send CAN", + "Unable to parse ID. ID must be a decimal number, or " + + "a hexadecimal number starting with 0x", false, false) + } + } + } + } + } + + // Message Table controls + RowLayout { + Layout.fillWidth: true + spacing: 8 + CheckBox { + id: autoScrollBox + text: "Auto-scroll" + checked: true + } + Button { + text: "Clear" + onClicked: messageModel.clear() + } + Item { Layout.fillWidth: true } + Label { + text: messageModel.count + " messages" + color: Utility.getAppHexColor("disabledText") + } + } + + // Message list + ListView { + id: msgListView + Layout.fillWidth: true + Layout.fillHeight: true + clip: true + model: ListModel { id: messageModel } + headerPositioning: ListView.OverlayHeader + + header: Rectangle { + width: msgListView.width + height: 28 + z: 2 + color: Utility.getAppHexColor("normalBackground") + RowLayout { + anchors.fill: parent + anchors.leftMargin: 4 + spacing: 0 + Label { text: "Ext"; Layout.preferredWidth: 50; font.bold: true; font.pixelSize: 11 } + Label { text: "ID"; Layout.preferredWidth: 110; font.bold: true; font.pixelSize: 11 } + Label { text: "Len"; Layout.preferredWidth: 40; font.bold: true; font.pixelSize: 11 } + Label { text: "Data"; Layout.fillWidth: true; font.bold: true; font.pixelSize: 11 } + } + } + + delegate: Rectangle { + width: msgListView.width + height: 22 + color: index % 2 === 0 ? "transparent" : Utility.getAppHexColor("normalBackground") + RowLayout { + anchors.fill: parent + anchors.leftMargin: 4 + spacing: 0 + Label { text: model.ext; Layout.preferredWidth: 50; font.pixelSize: 11 } + Label { text: model.canId; Layout.preferredWidth: 110; font.pixelSize: 11; font.family: "monospace" } + Label { text: model.len; Layout.preferredWidth: 40; font.pixelSize: 11 } + Label { text: model.data; Layout.fillWidth: true; font.pixelSize: 11; font.family: "monospace" } + } + } + + ScrollBar.vertical: ScrollBar { policy: ScrollBar.AsNeeded } + } + } + + Connections { + target: mCommands + function onCanFrameRx(data, id, isExtended) { + if (messageModel.count > 3999) { + messageModel.remove(0) + } + // data is a QByteArray exposed as ArrayBuffer in QML + var view = new Uint8Array(data) + var hexBytes = [] + for (var i = 0; i < view.length; i++) { + hexBytes.push("0x" + view[i].toString(16).toUpperCase().padStart(2, "0")) + } + messageModel.append({ + ext: isExtended ? "Yes" : "No", + canId: "0x" + id.toString(16).toUpperCase().padStart(8, "0"), + len: view.length.toString(), + data: hexBytes.join(" ") + }) + if (autoScrollBox.checked) { + msgListView.positionViewAtEnd() + } + } + } + + function reloadParams() { + for (var d = 0; d < _dynamicItems.length; d++) { + if (_dynamicItems[d]) _dynamicItems[d].destroy() + } + _dynamicItems = [] + + var paramNames = ["can_mode", "can_baud_rate"] + for (var p = 0; p < paramNames.length; p++) { + var e = editors.createEditorApp(paramCol, paramNames[p]) + if (e) { e.Layout.fillWidth = true; _dynamicItems.push(e) } + } + } + + Component.onCompleted: reloadParams() + + Connections { + target: mAppConf + function onUpdated() { reloadParams() } + } +} diff --git a/desktop/ConnectionPage.qml b/desktop/ConnectionPage.qml new file mode 100644 index 000000000..7c441e4bd --- /dev/null +++ b/desktop/ConnectionPage.qml @@ -0,0 +1,1157 @@ +/* + Desktop ConnectionPage — faithful replica of PageConnection (widgets). + Tabs: "(USB-)Serial", "CAN bus", "TCP", "UDP", "Bluetooth LE", "TCP Hub" + Below tabs: CAN Forward group, Autoconnect button, status label. +*/ +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import Vedder.vesc + +Item { + id: root + + property Commands mCommands: VescIf.commands() + + // ---- Helper: icon-only button (Fixed size, icon only, no text) ---- + component IconButton: Button { + implicitWidth: implicitHeight + display: AbstractButton.IconOnly + } + + // ---- 20ms timer matching original timerSlot ---- + Timer { + id: pollTimer + interval: 20 + running: true + repeat: true + onTriggered: { + // Update status label + var portName = VescIf.getConnectedPortName() + if (portName !== statusLabel.text) { + statusLabel.text = portName + } + + // Sync CAN fwd button with commands state + if (canFwdButton.checked !== mCommands.getSendCan()) { + canFwdButton.checked = mCommands.getSendCan() + } + + // TCP server info + var tcpIpTxt = "Server IPs\n" + var tcpClientTxt = "Connected Clients\n" + if (VescIf.tcpServerIsRunning()) { + var addrs = Utility.getNetworkAddresses() + for (var i = 0; i < addrs.length; i++) { + tcpIpTxt += addrs[i] + "\n" + } + if (VescIf.tcpServerIsClientConnected()) { + tcpClientTxt += VescIf.tcpServerClientIp() + } + } else { + tcpServerPortBox.enabled = true + } + if (tcpServerAddressesEdit.text !== tcpIpTxt) { + tcpServerAddressesEdit.text = tcpIpTxt + } + if (tcpServerClientsEdit.text !== tcpClientTxt) { + tcpServerClientsEdit.text = tcpClientTxt + } + + // UDP server info + var udpIpTxt = "Server IPs\n" + var udpClientTxt = "Connected Clients\n" + if (VescIf.udpServerIsRunning()) { + var uAddrs = Utility.getNetworkAddresses() + for (var j = 0; j < uAddrs.length; j++) { + udpIpTxt += uAddrs[j] + "\n" + } + if (VescIf.udpServerIsClientConnected()) { + udpClientTxt += VescIf.udpServerClientIp() + } + } else { + udpServerPortBox.enabled = true + } + if (udpServerAddressesEdit.text !== udpIpTxt) { + udpServerAddressesEdit.text = udpIpTxt + } + if (udpServerClientsEdit.text !== udpClientTxt) { + udpServerClientsEdit.text = udpClientTxt + } + } + } + + // ---- Connections ---- + Connections { + target: mCommands + function onPingCanRx(devs, isTimeout) { + canRefreshButton.enabled = true + canFwdBox.model = [] + var items = [] + for (var i = 0; i < devs.length; i++) { + items.push({"text": "VESC " + devs[i], "value": devs[i]}) + } + canFwdModel.clear() + for (var k = 0; k < items.length; k++) { + canFwdModel.append(items[k]) + } + } + } + + Connections { + target: VescIf.bleDevice() + function onScanDone(devs, done) { + if (done) { + bleScanButton.enabled = true + } + + bleDevBox.model = [] + var vescItems = [] + var otherItems = [] + + for (var addr in devs) { + var devName = devs[addr] + var setName = VescIf.getBleName(addr) + var displayName + + if (setName !== "") { + displayName = setName + " [" + addr + "]" + vescItems.unshift({"text": displayName, "addr": addr}) + } else if (devName.indexOf("VESC") >= 0) { + displayName = devName + " [" + addr + "]" + vescItems.unshift({"text": displayName, "addr": addr}) + } else { + displayName = devName + " [" + addr + "]" + otherItems.push({"text": displayName, "addr": addr}) + } + } + + bleDevModel.clear() + for (var i = 0; i < vescItems.length; i++) { + bleDevModel.append(vescItems[i]) + } + for (var j = 0; j < otherItems.length; j++) { + bleDevModel.append(otherItems[j]) + } + bleDevBox.currentIndex = 0 + } + } + + Connections { + target: VescIf + ignoreUnknownSignals: true + function onCANbusNewNode(node) { + canbusTargetModel.append({"text": node.toString(), "value": node}) + } + function onCANbusInterfaceListUpdated() { + canbusInterfaceBox.model = Utility.stringListModel(VescIf.listCANbusInterfaceNames()) + canbusInterfaceBox.currentIndex = 0 + } + function onPairingListUpdated() { + updatePairedList() + } + } + + function updatePairedList() { + pairedModel.clear() + var uuids = VescIf.getPairedUuids() + for (var i = 0; i < uuids.length; i++) { + pairedModel.append({"uuid": uuids[i]}) + } + if (pairedListView.count > 0) { + pairedListView.currentIndex = 0 + } + } + + // ---- Models ---- + ListModel { id: canFwdModel } + ListModel { id: bleDevModel } + ListModel { id: canbusTargetModel } + ListModel { id: pairedModel } + + // ---- Main layout ---- + ColumnLayout { + anchors.fill: parent + anchors.margins: 4 + spacing: 4 + + TabBar { + id: connTabBar + Layout.fillWidth: true + + TabButton { text: "(USB-)Serial" } + TabButton { text: "CAN bus" } + TabButton { text: "TCP" } + TabButton { text: "UDP" } + TabButton { text: "Bluetooth LE" } + TabButton { text: "TCP Hub" } + } + + StackLayout { + Layout.fillWidth: true + Layout.fillHeight: true + currentIndex: connTabBar.currentIndex + + // ========================================== + // Tab 0: (USB-)Serial + // ========================================== + Item { + ColumnLayout { + anchors.fill: parent + anchors.margins: 8 + spacing: 4 + + RowLayout { + Layout.fillWidth: true + + Label { text: "Port" } + + ComboBox { + id: serialPortBox + Layout.fillWidth: true + textRole: "name" + valueRole: "systemPath" + model: VescIf.listSerialPorts() + } + + SpinBox { + id: serialBaudBox + from: 0 + to: 3000000 + value: VescIf.getLastSerialBaud() + editable: true + property string prefix: "Baud: " + property string suffix: " bps" + textFromValue: function(value, locale) { + return prefix + value + suffix + } + valueFromText: function(text, locale) { + return parseInt(text.replace(prefix, "").replace(suffix, "")) + } + } + + IconButton { + icon.source: "qrc" + Utility.getThemePath() + "icons/Refresh-96.png" + ToolTip.visible: hovered + ToolTip.text: "Refresh serial port list" + onClicked: serialPortBox.model = VescIf.listSerialPorts() + } + + IconButton { + icon.source: "qrc" + Utility.getThemePath() + "icons/Disconnected-96.png" + ToolTip.visible: hovered + ToolTip.text: "Disconnect" + onClicked: VescIf.disconnectPort() + } + + IconButton { + icon.source: "qrc" + Utility.getThemePath() + "icons/Connected-96.png" + ToolTip.visible: hovered + ToolTip.text: "Connect" + onClicked: { + if (serialPortBox.currentValue !== undefined && serialPortBox.currentValue !== "") { + VescIf.connectSerial(serialPortBox.currentValue, serialBaudBox.value) + } + } + } + } + + Item { Layout.fillHeight: true } + } + } + + // ========================================== + // Tab 1: CAN bus + // ========================================== + Item { + ColumnLayout { + anchors.fill: parent + anchors.margins: 8 + spacing: 4 + + RowLayout { + Layout.fillWidth: true + + Label { text: "Interface" } + + ComboBox { + id: canbusInterfaceBox + textRole: "display" + model: Utility.stringListModel(VescIf.listCANbusInterfaceNames()) + } + + Label { text: "VESC ID" } + + ComboBox { + id: canbusTargetIdBox + Layout.fillWidth: true + model: canbusTargetModel + textRole: "text" + ToolTip.visible: hovered + ToolTip.text: "Discovered VESC nodes in the bus" + } + + SpinBox { + id: canbusBitrateBox + enabled: false + from: 0 + to: 1000 + value: typeof VescIf.getLastCANbusBitrate === "function" ? VescIf.getLastCANbusBitrate() : 500 + editable: false + property string prefix: "Bit rate: " + property string suffix: " kbit/s" + textFromValue: function(value, locale) { + return prefix + value + suffix + } + valueFromText: function(text, locale) { + return parseInt(text.replace(prefix, "").replace(suffix, "")) + } + ToolTip.visible: hovered + ToolTip.text: "This configuration is not supported by the socketcan backend. " + + "However it is possible to set the rate when configuring the CAN " + + "network interface using the ip link command." + } + + Button { + text: "Scan" + icon.source: "qrc" + Utility.getThemePath() + "icons/Refresh-96.png" + ToolTip.visible: hovered + ToolTip.text: "Discover VESC nodes in the CAN bus" + onClicked: { + VescIf.connectCANbus("socketcan", + canbusInterfaceBox.currentText, + canbusBitrateBox.value) + canbusTargetModel.clear() + VescIf.scanCANbus() + } + } + + IconButton { + icon.source: "qrc" + Utility.getThemePath() + "icons/Disconnected-96.png" + ToolTip.visible: hovered + ToolTip.text: "Disconnect" + onClicked: VescIf.disconnectPort() + } + + IconButton { + icon.source: "qrc" + Utility.getThemePath() + "icons/Connected-96.png" + ToolTip.visible: hovered + ToolTip.text: "Connect to a VESC node" + onClicked: { + if (canbusTargetIdBox.currentIndex >= 0) { + var node = canbusTargetModel.get(canbusTargetIdBox.currentIndex).value + VescIf.setCANbusReceiverID(node) + VescIf.connectCANbus("socketcan", + canbusInterfaceBox.currentText, + canbusBitrateBox.value) + } + } + } + } + + Item { Layout.fillHeight: true } + } + } + + // ========================================== + // Tab 2: TCP + // ========================================== + Item { + ColumnLayout { + anchors.fill: parent + anchors.margins: 8 + spacing: 4 + + GroupBox { + title: "TCP Client" + Layout.fillWidth: true + + GridLayout { + anchors.fill: parent + columns: 5 + columnSpacing: 6 + rowSpacing: 2 + + // Row 0: Address | serverEdit | portSpinBox | disconnect | connect + Label { text: "Address" } + TextField { + id: tcpServerEdit + Layout.fillWidth: true + text: VescIf.getLastTcpServer() + } + SpinBox { + id: tcpPortBox + from: 0; to: 65535 + value: VescIf.getLastTcpPort() + editable: true + property string prefix: "Port: " + textFromValue: function(v, l) { return prefix + v } + valueFromText: function(t, l) { return parseInt(t.replace(prefix, "")) } + } + IconButton { + icon.source: "qrc" + Utility.getThemePath() + "icons/Disconnected-96.png" + ToolTip.visible: hovered + ToolTip.text: "Disconnect" + onClicked: VescIf.disconnectPort() + } + IconButton { + icon.source: "qrc" + Utility.getThemePath() + "icons/Connected-96.png" + ToolTip.visible: hovered + ToolTip.text: "Connect" + onClicked: VescIf.connectTcp(tcpServerEdit.text, tcpPortBox.value) + } + + // Row 1: Detected Devices | detectBox | detectDisconnect | detectConnect + Label { text: "Detected Devices" } + ComboBox { + id: tcpDetectBox + Layout.fillWidth: true + Layout.columnSpan: 2 + } + IconButton { + icon.source: "qrc" + Utility.getThemePath() + "icons/Disconnected-96.png" + onClicked: VescIf.disconnectPort() + } + IconButton { + icon.source: "qrc" + Utility.getThemePath() + "icons/Connected-96.png" + onClicked: { + if (tcpDetectBox.currentIndex >= 0 && tcpDetectData.length > 0) { + var d = tcpDetectData[tcpDetectBox.currentIndex] + if (d) { + VescIf.connectTcp(d.ip, parseInt(d.port)) + } + } + } + } + } + } + + GroupBox { + title: "TCP Server" + Layout.fillWidth: true + Layout.fillHeight: true + + ColumnLayout { + anchors.fill: parent + + RowLayout { + CheckBox { + id: tcpServerEnableBox + text: "Enable TCP Server" + onToggled: { + if (checked) { + VescIf.tcpServerStart(tcpServerPortBox.value) + tcpServerPortBox.enabled = false + } else { + VescIf.tcpServerStop() + } + } + } + SpinBox { + id: tcpServerPortBox + Layout.fillWidth: true + from: 0; to: 65535 + value: 65102 + editable: true + property string prefix: "TCP Port: " + textFromValue: function(v, l) { return prefix + v } + valueFromText: function(t, l) { return parseInt(t.replace(prefix, "")) } + } + } + + RowLayout { + Layout.fillWidth: true + Layout.fillHeight: true + Layout.minimumHeight: 80 + + ScrollView { + Layout.fillWidth: true + Layout.fillHeight: true + TextArea { + id: tcpServerAddressesEdit + readOnly: true + wrapMode: TextArea.Wrap + } + } + ScrollView { + Layout.fillWidth: true + Layout.fillHeight: true + TextArea { + id: tcpServerClientsEdit + readOnly: true + wrapMode: TextArea.Wrap + } + } + } + } + } + } + } + + // ========================================== + // Tab 3: UDP + // ========================================== + Item { + ColumnLayout { + anchors.fill: parent + anchors.margins: 8 + spacing: 4 + + GroupBox { + title: "UDP Client" + Layout.fillWidth: true + + RowLayout { + anchors.fill: parent + + Label { text: "Address" } + TextField { + id: udpServerEdit + Layout.fillWidth: true + text: VescIf.getLastUdpServer() + } + SpinBox { + id: udpPortBox + from: 0; to: 65535 + value: VescIf.getLastUdpPort() + editable: true + property string prefix: "Port: " + textFromValue: function(v, l) { return prefix + v } + valueFromText: function(t, l) { return parseInt(t.replace(prefix, "")) } + } + IconButton { + icon.source: "qrc" + Utility.getThemePath() + "icons/Disconnected-96.png" + ToolTip.visible: hovered + ToolTip.text: "Disconnect" + onClicked: VescIf.disconnectPort() + } + IconButton { + icon.source: "qrc" + Utility.getThemePath() + "icons/Connected-96.png" + ToolTip.visible: hovered + ToolTip.text: "Connect" + onClicked: VescIf.connectUdp(udpServerEdit.text, udpPortBox.value) + } + } + } + + GroupBox { + title: "UDP Server" + Layout.fillWidth: true + Layout.fillHeight: true + + ColumnLayout { + anchors.fill: parent + + RowLayout { + CheckBox { + id: udpServerEnableBox + text: "Enable UDP Server" + onToggled: { + if (checked) { + VescIf.udpServerStart(udpServerPortBox.value) + udpServerPortBox.enabled = false + } else { + VescIf.udpServerStop() + } + } + } + SpinBox { + id: udpServerPortBox + Layout.fillWidth: true + from: 0; to: 65535 + value: 65102 + editable: true + property string prefix: "UDP Port: " + textFromValue: function(v, l) { return prefix + v } + valueFromText: function(t, l) { return parseInt(t.replace(prefix, "")) } + } + } + + RowLayout { + Layout.fillWidth: true + Layout.fillHeight: true + Layout.minimumHeight: 80 + + ScrollView { + Layout.fillWidth: true + Layout.fillHeight: true + TextArea { + id: udpServerAddressesEdit + readOnly: true + wrapMode: TextArea.Wrap + } + } + ScrollView { + Layout.fillWidth: true + Layout.fillHeight: true + TextArea { + id: udpServerClientsEdit + readOnly: true + wrapMode: TextArea.Wrap + } + } + } + } + } + } + } + + // ========================================== + // Tab 4: Bluetooth LE + // ========================================== + Item { + ColumnLayout { + anchors.fill: parent + anchors.margins: 8 + spacing: 4 + + // BLE Device row + RowLayout { + Layout.fillWidth: true + + Label { text: "BLE Device" } + + ComboBox { + id: bleDevBox + Layout.fillWidth: true + model: bleDevModel + textRole: "text" + } + + IconButton { + id: bleScanButton + icon.source: "qrc" + Utility.getThemePath() + "icons/Refresh-96.png" + ToolTip.visible: hovered + ToolTip.text: "Refresh serial port list" + onClicked: { + VescIf.bleDevice().startScan() + bleScanButton.enabled = false + } + } + + IconButton { + icon.source: "qrc" + Utility.getThemePath() + "icons/Disconnected-96.png" + ToolTip.visible: hovered + ToolTip.text: "Disconnect" + onClicked: VescIf.disconnectPort() + } + + IconButton { + icon.source: "qrc" + Utility.getThemePath() + "icons/Connected-96.png" + ToolTip.visible: hovered + ToolTip.text: "Connect" + onClicked: { + if (bleDevBox.currentIndex >= 0 && bleDevModel.count > 0) { + VescIf.connectBle(bleDevModel.get(bleDevBox.currentIndex).addr) + } + } + } + } + + // Set Device Name row + RowLayout { + Layout.fillWidth: true + + Label { text: "Set Device Name" } + + TextField { + id: bleNameEdit + Layout.fillWidth: true + } + + Button { + text: "Set" + icon.source: "qrc" + Utility.getThemePath() + "icons/Ok-96.png" + onClicked: { + if (bleNameEdit.text !== "" && bleDevBox.currentIndex >= 0 && bleDevModel.count > 0) { + var addr = bleDevModel.get(bleDevBox.currentIndex).addr + VescIf.storeBleName(addr, bleNameEdit.text) + var newName = bleNameEdit.text + " [" + addr + "]" + bleDevModel.set(bleDevBox.currentIndex, {"text": newName, "addr": addr}) + } + } + } + } + + // VESC Devices group + GroupBox { + title: "VESC Devices" + Layout.fillWidth: true + Layout.fillHeight: true + + RowLayout { + anchors.fill: parent + + ListView { + id: pairedListView + Layout.fillWidth: true + Layout.fillHeight: true + clip: true + model: pairedModel + currentIndex: 0 + highlight: Rectangle { + color: Utility.getAppHexColor("lightAccent") + opacity: 0.3 + } + + delegate: ItemDelegate { + width: pairedListView.width + text: "UUID: " + uuid + highlighted: pairedListView.currentIndex === index + onClicked: pairedListView.currentIndex = index + } + + ScrollBar.vertical: ScrollBar {} + } + + ColumnLayout { + spacing: 3 + + Button { + text: "Pair" + icon.source: "qrc" + Utility.getThemePath() + "icons/Circled Play-96.png" + Layout.fillWidth: true + ToolTip.visible: hovered + ToolTip.text: "Pair the connected VESC" + onClicked: { + if (!VescIf.isPortConnected()) { + VescIf.emitMessageDialog("Pair VESC", + "You are not connected to the VESC. Connect in order to pair it.", + false, false) + return + } + if (mCommands.isLimitedMode()) { + VescIf.emitMessageDialog("Pair VESC", + "The fiwmare must be updated to pair this VESC.", + false, false) + return + } + pairConfirmDialog.open() + } + } + Button { + text: "Add" + icon.source: "qrc" + Utility.getThemePath() + "icons/Plus Math-96.png" + Layout.fillWidth: true + ToolTip.visible: hovered + ToolTip.text: "Add the connected VESC without pairing it." + onClicked: { + if (VescIf.isPortConnected()) { + VescIf.addPairedUuid(VescIf.getConnectedUuid()) + VescIf.storeSettings() + } else { + VescIf.emitMessageDialog("Add UUID", + "You are not connected to the VESC. Connect in order to add it.", + false, false) + } + } + } + Button { + text: "Add UUID" + icon.source: "qrc" + Utility.getThemePath() + "icons/Plus Math-96.png" + Layout.fillWidth: true + ToolTip.visible: hovered + ToolTip.text: "Manually add UUID to this instance of VESC Tool" + onClicked: addUuidDialog.open() + } + Button { + text: "Unpair" + icon.source: "qrc" + Utility.getThemePath() + "icons/Restart-96.png" + Layout.fillWidth: true + ToolTip.visible: hovered + ToolTip.text: "Unpair this VESC, and make it possible to connect to it from any VESC Tool instance." + onClicked: { + if (!VescIf.isPortConnected()) { + VescIf.emitMessageDialog("Unpair VESC", + "You are not connected to the VESC. Connect in order to unpair it.", + false, false) + return + } + if (mCommands.isLimitedMode()) { + VescIf.emitMessageDialog("Unpair VESC", + "The fiwmare must be updated on this VESC first.", + false, false) + return + } + if (pairedListView.currentIndex >= 0) { + unpairConfirmDialog.open() + } + } + } + Button { + text: "Delete" + icon.source: "qrc" + Utility.getThemePath() + "icons/Delete-96.png" + Layout.fillWidth: true + onClicked: { + if (pairedListView.currentIndex >= 0) { + deleteConfirmDialog.open() + } + } + } + Button { + text: "Clear" + icon.source: "qrc" + Utility.getThemePath() + "icons/Delete-96.png" + Layout.fillWidth: true + onClicked: { + if (pairedModel.count > 0) { + clearConfirmDialog.open() + } + } + } + Item { Layout.fillHeight: true } + } + } + } + } + } + + // ========================================== + // Tab 5: TCP Hub + // ========================================== + Item { + ColumnLayout { + anchors.fill: parent + anchors.margins: 8 + spacing: 4 + + GroupBox { + title: "Login Details" + Layout.fillWidth: true + + GridLayout { + anchors.fill: parent + columns: 6 + columnSpacing: 6 + rowSpacing: 2 + + // Row 0: Address | serverEdit | defaultBtn | portSpinBox | disconnect | connect + Label { text: "Address" } + TextField { + id: tcpHubServerEdit + Layout.fillWidth: true + text: VescIf.getLastTcpHubServer() + } + IconButton { + icon.source: "qrc" + Utility.getThemePath() + "icons/Restart-96.png" + ToolTip.visible: hovered + ToolTip.text: "Restore default" + onClicked: { + tcpHubServerEdit.text = "veschub.vedder.se" + tcpHubPortBox.value = 65101 + } + } + SpinBox { + id: tcpHubPortBox + from: 0; to: 65535 + value: VescIf.getLastTcpHubPort() + editable: true + property string prefix: "Port: " + textFromValue: function(v, l) { return prefix + v } + valueFromText: function(t, l) { return parseInt(t.replace(prefix, "")) } + } + IconButton { + icon.source: "qrc" + Utility.getThemePath() + "icons/Disconnected-96.png" + ToolTip.visible: hovered + ToolTip.text: "Disconnect" + onClicked: { + if (hubClientButton.checked) { + VescIf.disconnectPort() + } else { + VescIf.tcpServerStop() + } + } + } + IconButton { + icon.source: "qrc" + Utility.getThemePath() + "icons/Connected-96.png" + ToolTip.visible: hovered + ToolTip.text: "Connect" + onClicked: { + var server = tcpHubServerEdit.text + var port = tcpHubPortBox.value + var vescId = tcpHubVescIdEdit.text.replace(/ /g, "").replace(/:/g, "").toUpperCase() + var pass = tcpHubPasswordEdit.text + + if (hubClientButton.checked) { + VescIf.connectTcpHub(server, port, vescId, pass) + } else { + VescIf.tcpServerConnectToHub(server, port, vescId, pass) + } + } + } + + // Row 1: VESC ID | idEdit(span 2) | Client radio(span 3) + Label { text: "VESC ID" } + TextField { + id: tcpHubVescIdEdit + Layout.fillWidth: true + Layout.columnSpan: 2 + text: VescIf.getLastTcpHubVescID() + } + RadioButton { + id: hubClientButton + text: "Client" + checked: true + Layout.columnSpan: 3 + } + + // Row 2: Password | passEdit(span 2) | Server radio(span 3) + Label { text: "Password" } + TextField { + id: tcpHubPasswordEdit + Layout.fillWidth: true + Layout.columnSpan: 2 + text: VescIf.getLastTcpHubVescPass() + } + RadioButton { + id: hubServerButton + text: "Server" + Layout.columnSpan: 3 + } + } + } + + Item { Layout.fillHeight: true } + } + } + } + + // ========================================== + // CAN Forward (always visible below tabs) + // ========================================== + GroupBox { + title: "CAN Forward" + Layout.fillWidth: true + + RowLayout { + anchors.fill: parent + + Button { + text: "Manual" + icon.source: "qrc" + Utility.getThemePath() + "icons/Bug-96.png" + ToolTip.visible: hovered + ToolTip.text: "Populate box without scanning, in case there are problems with scanning or the firmware does not support it." + onClicked: { + canFwdModel.clear() + for (var i = 0; i < 255; i++) { + canFwdModel.append({"text": "VESC " + i, "value": i}) + } + } + } + + Button { + id: canRefreshButton + text: "Scan" + icon.source: "qrc" + Utility.getThemePath() + "icons/Refresh-96.png" + ToolTip.visible: hovered + ToolTip.text: "Scan for CAN devices" + onClicked: { + canRefreshButton.enabled = false + mCommands.pingCan() + } + } + + ComboBox { + id: canFwdBox + Layout.fillWidth: true + model: canFwdModel + textRole: "text" + onActivated: { + if (canFwdModel.count > 0) { + mCommands.setCanSendId(canFwdModel.get(currentIndex).value) + } + } + } + + IconButton { + icon.source: "qrc" + Utility.getThemePath() + "icons/Help-96.png" + ToolTip.visible: hovered + ToolTip.text: "Show help" + onClicked: { + VescIf.emitMessageDialog("CAN Forward", + "CAN forward allows you to communicate with other VESCs connected over CAN-bus. " + + "Click scan to look for VESCs on the CAN-bus. If scanning does not work, " + + "manually add all IDs and select the one to communicate with.", + true, false) + } + } + + IconButton { + id: canFwdButton + checkable: true + icon.source: checked + ? ("qrc" + Utility.getThemePath() + "icons/can_on.png") + : ("qrc" + Utility.getThemePath() + "icons/can_off.png") + ToolTip.visible: hovered + ToolTip.text: "Forward communication over CAN-bus" + onClicked: { + if (mCommands.getCanSendId() >= 0 || !checked) { + mCommands.setSendCan(checked) + } else { + checked = false + VescIf.emitMessageDialog("CAN Forward", + "No CAN device is selected. Click on the refresh button " + + "if the selection box is empty.", + false, false) + } + } + } + } + } + + // ========================================== + // Autoconnect button + // ========================================== + Button { + Layout.fillWidth: true + text: "Autoconnect" + icon.source: "qrc" + Utility.getThemePath() + "icons/Wizard-96.png" + icon.width: 45 + icon.height: 45 + ToolTip.visible: hovered + ToolTip.text: "Try to automatically connect using the USB connection" + onClicked: VescIf.autoconnect() + } + + // ========================================== + // Status label + // ========================================== + Label { + id: statusLabel + Layout.fillWidth: true + horizontalAlignment: Text.AlignHCenter + text: "" + } + } + + // ---- TCP detect data storage ---- + property var tcpDetectData: [] + + // ---- Confirmation dialogs ---- + Dialog { + id: pairConfirmDialog + title: "Pair connected VESC" + modal: true + standardButtons: Dialog.Ok | Dialog.Cancel + anchors.centerIn: parent + Label { + text: "This is going to pair the connected VESC with this instance of VESC Tool. " + + "VESC Tool instances that are not paired with this VESC will not be able to " + + "connect over bluetooth any more. Continue?" + wrapMode: Text.WordWrap + width: parent.width + } + onAccepted: { + VescIf.addPairedUuid(VescIf.getConnectedUuid()) + VescIf.storeSettings() + // Set pairing_done flag on VESC + var ap = VescIf.appConfig() + mCommands.getAppConf() + if (Utility.waitSignal(ap, "updated", 1500)) { + ap.updateParamBool("pairing_done", true, null) + mCommands.setAppConf() + } + } + } + + Dialog { + id: unpairConfirmDialog + title: "Unpair connected VESC" + modal: true + standardButtons: Dialog.Ok | Dialog.Cancel + anchors.centerIn: parent + Label { + text: "This is going to unpair the connected VESC. Continue?" + wrapMode: Text.WordWrap + width: parent.width + } + onAccepted: { + var ap = VescIf.appConfig() + mCommands.getAppConf() + if (Utility.waitSignal(ap, "updated", 1500)) { + ap.updateParamBool("pairing_done", false, null) + mCommands.setAppConf() + VescIf.deletePairedUuid(VescIf.getConnectedUuid()) + VescIf.storeSettings() + } + } + } + + Dialog { + id: deleteConfirmDialog + title: "Delete paired VESC" + modal: true + standardButtons: Dialog.Ok | Dialog.Cancel + anchors.centerIn: parent + Label { + text: "This is going to delete this VESC from the paired list. If that VESC " + + "has the pairing flag set you won't be able to connect to it over BLE " + + "any more. Are you sure?" + wrapMode: Text.WordWrap + width: parent.width + } + onAccepted: { + if (pairedListView.currentIndex >= 0) { + var uuid = pairedModel.get(pairedListView.currentIndex).uuid + VescIf.deletePairedUuid(uuid) + VescIf.storeSettings() + } + } + } + + Dialog { + id: clearConfirmDialog + title: "Clear paired VESCs" + modal: true + standardButtons: Dialog.Ok | Dialog.Cancel + anchors.centerIn: parent + Label { + text: "This is going to clear the pairing list of this instance of VESC Tool. Are you sure?" + wrapMode: Text.WordWrap + width: parent.width + } + onAccepted: { + VescIf.clearPairedUuids() + VescIf.storeSettings() + } + } + + Dialog { + id: addUuidDialog + title: "Add UUID" + modal: true + standardButtons: Dialog.Ok | Dialog.Cancel + anchors.centerIn: parent + ColumnLayout { + anchors.fill: parent + Label { text: "UUID:" } + TextField { + id: addUuidEdit + Layout.fillWidth: true + } + } + onAccepted: { + if (addUuidEdit.text !== "") { + VescIf.addPairedUuid(addUuidEdit.text) + VescIf.storeSettings() + } + } + } + + // ---- Init ---- + Component.onCompleted: { + // Populate initial BLE device if last known + var lastBleAddr = VescIf.getLastBleAddr() + if (lastBleAddr !== "") { + var setName = VescIf.getBleName(lastBleAddr) + var name + if (setName !== "") { + name = setName + " [" + lastBleAddr + "]" + } else { + name = lastBleAddr + } + bleDevModel.append({"text": name, "addr": lastBleAddr}) + } + + updatePairedList() + } +} diff --git a/desktop/ControllersPage.qml b/desktop/ControllersPage.qml new file mode 100644 index 000000000..0641f46b0 --- /dev/null +++ b/desktop/ControllersPage.qml @@ -0,0 +1,109 @@ +/* + Desktop ControllersPage — faithful recreation of the original PageControllers widget. + ParamTable for "pid controllers" / "general" subgroup + + Position Offset Calculator group at the bottom. +*/ +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import Vedder.vesc + +Item { + id: controllersPage + + property ConfigParams mMcConf: VescIf.mcConfig() + property Commands mCommands: VescIf.commands() + property var _dynamicItems: [] + + ParamEditors { + id: editors + } + + ColumnLayout { + anchors.fill: parent + anchors.margins: 4 + spacing: 4 + + Flickable { + Layout.fillWidth: true + Layout.fillHeight: true + clip: true + contentWidth: width + contentHeight: paramCol.height + 16 + flickableDirection: Flickable.VerticalFlick + ScrollBar.vertical: ScrollBar { policy: ScrollBar.AsNeeded } + + ColumnLayout { + id: paramCol + width: parent.width + spacing: 4 + Item { Layout.preferredHeight: 1 } + } + } + + // Position Offset Calculator — matches original + GroupBox { + title: "Position Offset Calculator" + Layout.fillWidth: true + + RowLayout { + anchors.fill: parent + spacing: 8 + + SpinBox { + id: posOffsetBox + from: -360000 + to: 360000 + value: 0 + stepSize: 100 + editable: true + property real realValue: value / 1000.0 + textFromValue: function(v, locale) { + return "Pos Now: " + (v / 1000).toFixed(3) + " °" + } + valueFromText: function(text, locale) { + var s = text.replace("Pos Now: ", "").replace(" °", "") + return Math.round(parseFloat(s) * 1000) + } + Layout.fillWidth: true + } + + Button { + text: "Apply" + icon.source: "qrc" + Utility.getThemePath() + "icons/Download-96.png" + onClicked: { + mCommands.sendTerminalCmdSync( + "update_pid_pos_offset " + posOffsetBox.realValue.toFixed(3) + " 1") + mCommands.getMcconf() + } + } + } + } + } + + function reloadAll() { + for (var d = 0; d < _dynamicItems.length; d++) { + if (_dynamicItems[d]) _dynamicItems[d].destroy() + } + _dynamicItems = [] + + var params = mMcConf.getParamsFromSubgroup("pid controllers", "general") + for (var p = 0; p < params.length; p++) { + var paramName = params[p] + if (paramName.indexOf("::sep::") === 0) { + var sep = editors.createSeparator(paramCol, paramName.substring(7)) + if (sep) _dynamicItems.push(sep) + continue + } + var e = editors.createEditorMc(paramCol, paramName) + if (e) { e.Layout.fillWidth = true; _dynamicItems.push(e) } + } + } + + Component.onCompleted: reloadAll() + + Connections { + target: mMcConf + function onUpdated() { reloadAll() } + } +} diff --git a/desktop/DisplayToolPage.qml b/desktop/DisplayToolPage.qml new file mode 100644 index 000000000..b39431bfa --- /dev/null +++ b/desktop/DisplayToolPage.qml @@ -0,0 +1,859 @@ +/* + Desktop DisplayToolPage — Full pixel art editor for VESC display images. + Replicates the original PageDisplayTool with 3 top-level tabs: + 1) Display — DispEditor (left) + Font/Overlay sub-tabs (right) + 2) Overlay Editor — standalone DispEditor + 3) Font Editor — font settings + DispEditor + Each DispEditor = pixel canvas+palette (left) + preview+Controls/LoadSave (right) +*/ +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import QtQuick.Dialogs +import Vedder.vesc + +Item { + id: root + + // ---- Shared DispEditor component ---- + component DispEditorComp: Item { + id: dispEditor + + property int imgW: 128 + property int imgH: 64 + property int formatIndex: 0 // 0=Idx2, 1=Idx4, 2=Idx16, 3=RGB332, 4=RGB565, 5=RGB888 + property string editColor: "#ffffff" + property bool drawLayer2: true + property int previewScale: 2 + property var imageData: [] + property var layer2Data: [] + property var colorPalette: [] + + Component.onCompleted: { + rebuildPalette() + clearImage() + } + + function paletteColorCount() { + switch (formatIndex) { + case 0: return 2 + case 1: return 4 + case 2: return 16 + default: return 0 + } + } + + function rebuildPalette() { + var count = paletteColorCount() + var pal = [] + for (var i = 0; i < count; i++) { + var v = count > 1 ? Math.round(255 * i / (count - 1)) : 0 + var hex = "#" + ("0" + v.toString(16)).slice(-2).repeat(3) + pal.push(hex) + } + colorPalette = pal + editColor = pal.length > 0 ? pal[pal.length - 1] : "#ffffff" + } + + function clearImage() { + var arr = new Array(imgW * imgH) + for (var i = 0; i < arr.length; i++) arr[i] = "#000000" + imageData = arr + clearLayer2() + edCanvas.requestPaint() + pvCanvas.requestPaint() + } + + function clearLayer2() { + var arr = new Array(imgW * imgH) + for (var i = 0; i < arr.length; i++) arr[i] = "" + layer2Data = arr + edCanvas.requestPaint() + pvCanvas.requestPaint() + } + + function getPixel(x, y) { + if (x < 0 || x >= imgW || y < 0 || y >= imgH) return "#000000" + var idx = y * imgW + x + var l2 = layer2Data[idx] + if (drawLayer2 && l2 && l2 !== "") return l2 + return imageData[idx] + } + + function setPixel(x, y, color) { + if (x < 0 || x >= imgW || y < 0 || y >= imgH) return + imageData[y * imgW + x] = color + } + + function updateSize(w, h) { + imgW = w; imgH = h + clearImage() + } + + // Layout: canvas+palette (left) | preview+tabs (right) + RowLayout { + anchors.fill: parent + spacing: 0 + + // ==== LEFT: Pixel editor + palette ==== + ColumnLayout { + Layout.fillWidth: true + Layout.fillHeight: true + Layout.minimumWidth: 300 + spacing: 0 + + // Pixel editor canvas + Rectangle { + Layout.fillWidth: true + Layout.fillHeight: true + color: "black" + clip: true + + Canvas { + id: edCanvas + anchors.fill: parent + + property real sf: 8.0 + property real ox: -(imgW * 4) + property real oy: -(imgH * 4) + property int mlx: -1000000 + property int mly: -1000000 + property int cpx: -1 + property int cpy: -1 + + function pxAt(mx, my) { + return Qt.point( + Math.floor((mx - ox - width / 2) / sf), + Math.floor((my - oy - height / 2) / sf)) + } + + onPaint: { + var ctx = getContext("2d") + ctx.reset() + ctx.fillStyle = "black" + ctx.fillRect(0, 0, width, height) + + ctx.save() + ctx.translate(width / 2 + ox, height / 2 + oy) + ctx.scale(sf, sf) + + for (var j = 0; j < imgH; j++) { + for (var i = 0; i < imgW; i++) { + var c = getPixel(i, j) + if (i === cpx && j === cpy) { + var r = parseInt(c.substring(1, 3), 16) / 255 + var g = parseInt(c.substring(3, 5), 16) / 255 + var b = parseInt(c.substring(5, 7), 16) / 255 + if (g < 0.5) g += 0.2; else { r -= 0.2; b -= 0.2 } + r = Math.max(0, Math.min(1, r)) + g = Math.max(0, Math.min(1, g)) + b = Math.max(0, Math.min(1, b)) + ctx.fillStyle = Qt.rgba(r, g, b, 1) + } else { + ctx.fillStyle = c + } + ctx.fillRect(i, j, 1, 1) + } + } + ctx.restore() + + // Grid + var gox = width / 2 + ox + var goy = height / 2 + oy + if (sf >= 4) { + ctx.strokeStyle = "#404040" + ctx.lineWidth = 0.5 + for (var gx = 0; gx <= imgW; gx++) { + var sx = gox + gx * sf + ctx.beginPath(); ctx.moveTo(sx, goy); ctx.lineTo(sx, goy + imgH * sf); ctx.stroke() + } + for (var gy = 0; gy <= imgH; gy++) { + var sy = goy + gy * sf + ctx.beginPath(); ctx.moveTo(gox, sy); ctx.lineTo(gox + imgW * sf, sy); ctx.stroke() + } + } + + // Coord overlay + ctx.fillStyle = "rgba(0,0,0,0.5)" + ctx.fillRect(width - 100, height - 40, 100, 40) + ctx.fillStyle = "white" + ctx.font = "11px monospace" + ctx.fillText("X: " + cpx, width - 90, height - 24) + ctx.fillText("Y: " + cpy, width - 90, height - 10) + } + + MouseArea { + anchors.fill: parent + hoverEnabled: true + acceptedButtons: Qt.LeftButton | Qt.RightButton + + onPositionChanged: function(mouse) { + var pt = edCanvas.pxAt(mouse.x, mouse.y) + edCanvas.cpx = pt.x; edCanvas.cpy = pt.y + var shift = (mouse.modifiers & Qt.ShiftModifier) + if (mouse.buttons & Qt.LeftButton) { + if (shift) { + if (pt.x >= 0 && pt.x < imgW && pt.y >= 0 && pt.y < imgH) { + setPixel(pt.x, pt.y, editColor) + pvCanvas.requestPaint() + } + } else { + if (edCanvas.mlx > -999999) { + edCanvas.ox += mouse.x - edCanvas.mlx + edCanvas.oy += mouse.y - edCanvas.mly + } + edCanvas.mlx = mouse.x; edCanvas.mly = mouse.y + } + } + edCanvas.requestPaint() + } + onPressed: function(mouse) { + var shift = (mouse.modifiers & Qt.ShiftModifier) + var pt = edCanvas.pxAt(mouse.x, mouse.y) + if (mouse.button === Qt.LeftButton) { + if (shift) { + if (pt.x >= 0 && pt.x < imgW && pt.y >= 0 && pt.y < imgH) { + setPixel(pt.x, pt.y, editColor) + pvCanvas.requestPaint() + } + } else { + edCanvas.mlx = mouse.x; edCanvas.mly = mouse.y + } + } else if (mouse.button === Qt.RightButton && shift) { + if (pt.x >= 0 && pt.x < imgW && pt.y >= 0 && pt.y < imgH) + editColor = getPixel(pt.x, pt.y) + } + edCanvas.requestPaint() + } + onReleased: { edCanvas.mlx = -1000000; edCanvas.mly = -1000000 } + onWheel: function(wheel) { + var d = wheel.angleDelta.y / 600.0 + if (d > 0.8) d = 0.8; if (d < -0.8) d = -0.8 + edCanvas.sf += edCanvas.sf * d + edCanvas.ox += edCanvas.ox * d + edCanvas.oy += edCanvas.oy * d + if (edCanvas.sf < 0.5) edCanvas.sf = 0.5 + if (edCanvas.sf > 40) edCanvas.sf = 40 + edCanvas.requestPaint() + } + } + } + } + + // Palette row + Rectangle { + Layout.fillWidth: true + Layout.preferredHeight: colorPalette.length > 0 ? 34 : 0 + color: "transparent" + visible: colorPalette.length > 0 + + Flow { + anchors.fill: parent; anchors.margins: 1; spacing: 1 + Repeater { + model: colorPalette.length + Rectangle { + width: 26; height: 26; color: colorPalette[index] + border.color: editColor === colorPalette[index] ? "#ff6600" : "#666666" + border.width: editColor === colorPalette[index] ? 2 : 1 + MouseArea { + anchors.fill: parent + onClicked: editColor = colorPalette[index] + } + } + } + } + } + } + + // ==== RIGHT: Preview + Controls/Load-Save tabs ==== + ColumnLayout { + Layout.preferredWidth: 280 + Layout.minimumWidth: 200 + Layout.maximumWidth: 320 + Layout.fillHeight: true + spacing: 0 + + // Preview image + ScrollView { + Layout.fillWidth: true + Layout.preferredHeight: Math.min(imgH * previewScale + 4, 256) + Layout.maximumHeight: 256 + clip: true + + Canvas { + id: pvCanvas + width: imgW * previewScale + height: imgH * previewScale + + onPaint: { + var ctx = getContext("2d") + ctx.fillStyle = "black" + ctx.fillRect(0, 0, width, height) + var s = previewScale + for (var j = 0; j < imgH; j++) { + for (var i = 0; i < imgW; i++) { + ctx.fillStyle = getPixel(i, j) + ctx.fillRect(i * s, j * s, s, s) + } + } + } + } + } + + // Controls / Load-Save tabs + TabBar { + id: ctrlTabBar + Layout.fillWidth: true + TabButton { text: "Controls" } + TabButton { text: "Load/Save" } + } + + StackLayout { + Layout.fillWidth: true + Layout.fillHeight: true + currentIndex: ctrlTabBar.currentIndex + + // Controls + Item { + ColumnLayout { + anchors.fill: parent; anchors.margins: 3; spacing: 2 + + SpinBox { + Layout.fillWidth: true + from: 1; to: 10; value: dispEditor.previewScale; editable: true + textFromValue: function(v) { return "Preview Scale: " + v } + valueFromText: function(t) { return parseInt(t.replace("Preview Scale: ", "")) || 2 } + onValueModified: { dispEditor.previewScale = value; pvCanvas.requestPaint() } + } + + Button { + text: "Help"; Layout.fillWidth: true + icon.source: "qrc" + Utility.getThemePath() + "icons/Help-96.png" + onClicked: helpDialog.open() + } + + Button { + text: "Clear Screen"; Layout.fillWidth: true + onClicked: dispEditor.clearImage() + } + + Button { + text: "Clear Layer 2"; Layout.fillWidth: true + onClicked: dispEditor.clearLayer2() + } + + // Current color + Rectangle { + Layout.fillWidth: true + Layout.preferredHeight: 24 + color: editColor + border.color: Utility.getAppHexColor("disabledText") + border.width: 2 + } + + Item { Layout.fillHeight: true } + } + } + + // Load/Save + Item { + ColumnLayout { + anchors.fill: parent; anchors.margins: 3; spacing: 2 + + RowLayout { + Layout.fillWidth: true; spacing: 2 + Label { text: "Format" } + ComboBox { + Layout.fillWidth: true + textRole: "display" + model: Utility.stringListModel(["Indexed 2", "Indexed 4", "Indexed 16", "RGB332", "RGB565", "RGB888"]) + currentIndex: dispEditor.formatIndex + onCurrentIndexChanged: { + dispEditor.formatIndex = currentIndex + dispEditor.rebuildPalette() + edCanvas.requestPaint() + } + } + } + + RowLayout { + Layout.fillWidth: true; spacing: 2 + Button { text: "Export Bin"; Layout.fillWidth: true + onClicked: VescIf.emitMessageDialog("Export Bin", "Binary export requires native file I/O.", false, false) + } + Button { text: "Import Bin"; Layout.fillWidth: true + onClicked: VescIf.emitMessageDialog("Import Bin", "Binary import requires native file I/O.", false, false) + } + } + + RowLayout { + Layout.fillWidth: true; spacing: 2 + Button { text: "Save PNG"; Layout.fillWidth: true + ToolTip.visible: hovered; ToolTip.text: "Save image to PNG file." + onClicked: VescIf.emitStatusMessage("PNG save not yet implemented", false) + } + Button { text: "Load Image"; Layout.fillWidth: true + onClicked: VescIf.emitMessageDialog("Load Image", "Image loading with dithering requires native code.", false, false) + } + } + + SpinBox { + Layout.fillWidth: true + from: 0; to: 10000; stepSize: 10; value: 1000; editable: true + ToolTip.visible: hovered + ToolTip.text: "Scale colors when loading image." + textFromValue: function(v) { return "Load Color Scale: " + (v / 1000.0).toFixed(2) } + valueFromText: function(t) { return Math.round(parseFloat(t.replace("Load Color Scale: ", "")) * 1000) } + } + + CheckBox { text: "Dither when loading"; checked: true } + CheckBox { text: "Antialias when loading"; checked: true } + CheckBox { + text: "Show Layer 2"; checked: true + onToggled: { + dispEditor.drawLayer2 = checked + edCanvas.requestPaint(); pvCanvas.requestPaint() + } + } + + Item { Layout.fillHeight: true } + } + } + } + } + } + } + + // ======== TOP-LEVEL TABS (Display | Overlay Editor | Font Editor) ======== + ColumnLayout { + anchors.fill: parent + spacing: 0 + + TabBar { + id: mainTabBar + Layout.fillWidth: true + TabButton { text: "Display" } + TabButton { text: "Overlay Editor" } + TabButton { text: "Font Editor" } + } + + StackLayout { + Layout.fillWidth: true + Layout.fillHeight: true + currentIndex: mainTabBar.currentIndex + + // ======== Tab 1: Display ======== + Item { + RowLayout { + anchors.fill: parent + anchors.margins: 3 + spacing: 2 + + // Left: W/H toolbar + DispEditor + ColumnLayout { + Layout.fillWidth: true + Layout.fillHeight: true + spacing: 2 + + RowLayout { + Layout.fillWidth: true; spacing: 2 + SpinBox { + id: wBoxDisp; from: 1; to: 1024; value: 128; editable: true + textFromValue: function(v) { return "W: " + v } + valueFromText: function(t) { return parseInt(t.replace("W: ", "")) || 128 } + } + SpinBox { + id: hBoxDisp; from: 1; to: 1024; value: 64; editable: true + textFromValue: function(v) { return "H: " + v } + valueFromText: function(t) { return parseInt(t.replace("H: ", "")) || 64 } + } + Button { + text: "Update" + onClicked: dispEditorMain.updateSize(wBoxDisp.value, hBoxDisp.value) + } + Item { Layout.fillWidth: true } + } + + DispEditorComp { + id: dispEditorMain + Layout.fillWidth: true + Layout.fillHeight: true + } + } + + // Right: Font / Overlay sub-tabs + ColumnLayout { + Layout.preferredWidth: 240 + Layout.minimumWidth: 200 + Layout.maximumWidth: 280 + Layout.fillHeight: true + spacing: 0 + + TabBar { + id: rightSubTabBar + Layout.fillWidth: true + TabButton { text: "Font" } + TabButton { text: "Overlay" } + } + + StackLayout { + Layout.fillWidth: true + Layout.fillHeight: true + currentIndex: rightSubTabBar.currentIndex + + // Font sub-tab + Item { + ScrollView { + anchors.fill: parent; clip: true + + ColumnLayout { + width: parent.width + spacing: 3 + + CheckBox { + id: drawFontCheck + text: "Draw Font" + checked: false + Layout.fillWidth: true + } + GroupBox { + title: "Draw Font Settings" + Layout.fillWidth: true + enabled: drawFontCheck.checked + + GridLayout { + anchors.fill: parent + columns: 2; columnSpacing: 3; rowSpacing: 3 + + ComboBox { + id: fontBox; Layout.columnSpan: 2; Layout.fillWidth: true + textRole: "display" + model: Utility.stringListModel(["Roboto", "DejaVu Sans Mono", "Liberation Sans", "Liberation Mono"]) + } + CheckBox { text: "Bold" } + Item {} + SpinBox { + from: 0; to: 512; value: 34; editable: true + textFromValue: function(v) { return "X: " + v } + valueFromText: function(t) { return parseInt(t.replace("X: ", "")) || 0 } + } + SpinBox { + from: 0; to: 512; value: 46; editable: true + textFromValue: function(v) { return "Y: " + v } + valueFromText: function(t) { return parseInt(t.replace("Y: ", "")) || 0 } + } + SpinBox { + from: 1; to: 128; value: 10; editable: true + textFromValue: function(v) { return "W: " + v } + valueFromText: function(t) { return parseInt(t.replace("W: ", "")) || 10 } + } + SpinBox { + from: 1; to: 128; value: 16; editable: true + textFromValue: function(v) { return "H: " + v } + valueFromText: function(t) { return parseInt(t.replace("H: ", "")) || 16 } + } + SpinBox { + Layout.columnSpan: 2; Layout.fillWidth: true + from: 10; to: 10000; stepSize: 10; value: 1000; editable: true + textFromValue: function(v) { return "Scale: " + (v / 1000.0).toFixed(2) } + valueFromText: function(t) { return Math.round(parseFloat(t.replace("Scale: ", "")) * 1000) } + } + TextField { + Layout.columnSpan: 2; Layout.fillWidth: true + text: "ABC 00" + } + CheckBox { text: "Antialias" } + CheckBox { text: "Border"; checked: true } + CheckBox { Layout.columnSpan: 2; text: "NumOnly" } + Button { + Layout.columnSpan: 2; Layout.fillWidth: true + text: "Export Font" + onClicked: VescIf.emitStatusMessage("Font export not yet implemented", false) + } + } + } + + Item { Layout.fillHeight: true } + } + } + } + + // Overlay sub-tab + Item { + ScrollView { + anchors.fill: parent; clip: true + + ColumnLayout { + width: parent.width + spacing: 3 + + CheckBox { + id: drawOverlayCheck + text: "Draw Overlay" + checked: false + Layout.fillWidth: true + } + GroupBox { + title: "Draw Overlay Settings" + Layout.fillWidth: true + enabled: drawOverlayCheck.checked + + GridLayout { + anchors.fill: parent + columns: 3; columnSpacing: 3; rowSpacing: 3 + + Label { text: "Position" } + SpinBox { + from: -512; to: 512; value: 0; editable: true + textFromValue: function(v) { return "X: " + v } + valueFromText: function(t) { return parseInt(t.replace("X: ", "")) || 0 } + } + SpinBox { + from: -512; to: 512; value: 0; editable: true + textFromValue: function(v) { return "Y: " + v } + valueFromText: function(t) { return parseInt(t.replace("Y: ", "")) || 0 } + } + + Label { + text: "Crop Start" + ToolTip.text: "Corner to start crop." + ToolTip.visible: cropStartHover.hovered + ToolTip.delay: 500 + HoverHandler { id: cropStartHover } + } + SpinBox { + from: 0; to: 512; value: 0; editable: true + textFromValue: function(v) { return "X: " + v } + valueFromText: function(t) { return parseInt(t.replace("X: ", "")) || 0 } + } + SpinBox { + from: 0; to: 512; value: 0; editable: true + textFromValue: function(v) { return "Y: " + v } + valueFromText: function(t) { return parseInt(t.replace("Y: ", "")) || 0 } + } + + Label { text: "Crop Size" } + SpinBox { + from: 0; to: 512; value: 512; editable: true + textFromValue: function(v) { return "W: " + v } + valueFromText: function(t) { return parseInt(t.replace("W: ", "")) || 512 } + } + SpinBox { + from: 0; to: 512; value: 512; editable: true + textFromValue: function(v) { return "H: " + v } + valueFromText: function(t) { return parseInt(t.replace("H: ", "")) || 512 } + } + + Label { + text: "Img Center" + ToolTip.text: "This pixel on the image corresponds to Position." + ToolTip.visible: imgCenterHover.hovered + ToolTip.delay: 500 + HoverHandler { id: imgCenterHover } + } + SpinBox { + from: -1024; to: 1024; value: 0; editable: true + textFromValue: function(v) { return "X: " + v } + valueFromText: function(t) { return parseInt(t.replace("X: ", "")) || 0 } + } + SpinBox { + from: -1024; to: 1024; value: 0; editable: true + textFromValue: function(v) { return "Y: " + v } + valueFromText: function(t) { return parseInt(t.replace("Y: ", "")) || 0 } + } + + Label { + text: "Rot Center" + ToolTip.text: "Rotation will be done around this pixel." + ToolTip.visible: rotCenterHover.hovered + ToolTip.delay: 500 + HoverHandler { id: rotCenterHover } + } + SpinBox { + from: -1024; to: 1024; value: 0; editable: true + textFromValue: function(v) { return "X: " + v } + valueFromText: function(t) { return parseInt(t.replace("X: ", "")) || 0 } + } + SpinBox { + from: -1024; to: 1024; value: 0; editable: true + textFromValue: function(v) { return "Y: " + v } + valueFromText: function(t) { return parseInt(t.replace("Y: ", "")) || 0 } + } + + Label { text: "Rotation" } + SpinBox { + Layout.columnSpan: 2; Layout.fillWidth: true + from: -360000; to: 360000; stepSize: 1000; value: 0; editable: true + property real realValue: value / 1000.0 + textFromValue: function(v) { return (v / 1000.0).toFixed(1) + " Deg" } + valueFromText: function(t) { return Math.round(parseFloat(t.replace(" Deg", "")) * 1000) } + } + + Label { text: "Scale" } + SpinBox { + Layout.columnSpan: 2; Layout.fillWidth: true + from: 1; to: 100000; stepSize: 10; value: 1000; editable: true + textFromValue: function(v) { return (v / 1000.0).toFixed(3) } + valueFromText: function(t) { return Math.round(parseFloat(t) * 1000) } + } + + Label { text: "Transparent" } + SpinBox { + Layout.columnSpan: 2; Layout.fillWidth: true + from: -1; to: 15; value: 0; editable: true + ToolTip.visible: hovered + ToolTip.text: "Color index on image to count as transparent." + } + + Button { + Layout.columnSpan: 3; Layout.fillWidth: true + text: "Save to Layer 2" + ToolTip.visible: hovered + ToolTip.text: "Save overlay to layer 2 on image." + onClicked: VescIf.emitStatusMessage("Overlay saved to Layer 2", true) + } + } + } + + Item { Layout.fillHeight: true } + } + } + } + } + } + } + } + + // ======== Tab 2: Overlay Editor ======== + Item { + ColumnLayout { + anchors.fill: parent + anchors.margins: 3 + spacing: 2 + + RowLayout { + Layout.fillWidth: true; spacing: 2 + SpinBox { + id: wBoxOv; from: 1; to: 1024; value: 128; editable: true + textFromValue: function(v) { return "W: " + v } + valueFromText: function(t) { return parseInt(t.replace("W: ", "")) || 128 } + } + SpinBox { + id: hBoxOv; from: 1; to: 1024; value: 64; editable: true + textFromValue: function(v) { return "H: " + v } + valueFromText: function(t) { return parseInt(t.replace("H: ", "")) || 64 } + } + Button { + text: "Update" + onClicked: dispEditorOverlay.updateSize(wBoxOv.value, hBoxOv.value) + } + Item { Layout.fillWidth: true } + } + + DispEditorComp { + id: dispEditorOverlay + Layout.fillWidth: true + Layout.fillHeight: true + } + } + } + + // ======== Tab 3: Font Editor ======== + Item { + ColumnLayout { + anchors.fill: parent + anchors.margins: 3 + spacing: 2 + + GridLayout { + Layout.fillWidth: true + columns: 4; columnSpacing: 6; rowSpacing: 3 + + RadioButton { text: "All"; checked: true } + RadioButton { text: "Numbers Only" } + Item {} + Button { + text: "Apply" + ToolTip.visible: hovered; ToolTip.text: "Apply font and settings" + onClicked: VescIf.emitStatusMessage("Font editor apply not yet implemented", false) + } + + ComboBox { + Layout.minimumWidth: 120 + textRole: "display" + model: Utility.stringListModel(["Roboto", "DejaVu Sans Mono", "Liberation Sans", "Liberation Mono"]) + } + CheckBox { text: "Anti Alias (2bpp)" } + CheckBox { text: "Bold" } + CheckBox { text: "Border"; checked: true } + + SpinBox { + from: 1; to: 128; value: 10; editable: true + textFromValue: function(v) { return "W: " + v } + valueFromText: function(t) { return parseInt(t.replace("W: ", "")) || 10 } + } + SpinBox { + from: 1; to: 128; value: 16; editable: true + textFromValue: function(v) { return "H: " + v } + valueFromText: function(t) { return parseInt(t.replace("H: ", "")) || 16 } + } + SpinBox { + Layout.columnSpan: 2; Layout.fillWidth: true + from: 10; to: 10000; stepSize: 10; value: 1000; editable: true + textFromValue: function(v) { return "Scale: " + (v / 1000.0).toFixed(2) } + valueFromText: function(t) { return Math.round(parseFloat(t.replace("Scale: ", "")) * 1000) } + } + + Button { + text: "Export Font"; Layout.columnSpan: 2; Layout.fillWidth: true + onClicked: VescIf.emitStatusMessage("Font export not yet implemented", false) + } + Button { + text: "Import Font"; Layout.columnSpan: 2; Layout.fillWidth: true + onClicked: VescIf.emitStatusMessage("Font import not yet implemented", false) + } + } + + DispEditorComp { + id: dispEditorFont + Layout.fillWidth: true + Layout.fillHeight: true + } + } + } + } + } + + // ---- Help Dialog ---- + Dialog { + id: helpDialog + title: "Usage Instructions" + width: 500; height: 400 + anchors.centerIn: parent + modal: true + standardButtons: Dialog.Ok + + ScrollView { + anchors.fill: parent; clip: true + Label { + width: parent.width - 20 + wrapMode: Text.WordWrap; textFormat: Text.RichText + text: "Navigate in editor
" + + "Left-click and drag to move. Scroll to zoom.

" + + "Draw pixels
" + + "Shift + Left-click (and drag)

" + + "Change color
" + + "Click on color buttons, or Shift + Right-click on pixel with desired color.

" + + "Update Palette Color
" + + "Ctrl + left-click on the palette buttons.

" + + "Overlay
" + + "This function overlays an image from the overlay tab to the display tab with a transform. " + + "The same transforms are available in the display library, meaning that all transform " + + "parameters can be animated.

" + + "Layer 2
" + + "The second layer can be used to draw overlays on, without messing with the main image. " + + "This way the background image can be kept clean for when it is saved." + } + } + } +} diff --git a/desktop/ExperimentPlotPage.qml b/desktop/ExperimentPlotPage.qml new file mode 100644 index 000000000..5cb2af39b --- /dev/null +++ b/desktop/ExperimentPlotPage.qml @@ -0,0 +1,568 @@ +/* + Desktop ExperimentPlotPage — full feature parity with ExperimentPlot widget. + + Layout: + ┌────────────────────┬─────────────────────────────────────┐ + │ Left sidebar │ Main plot area (GraphsView) │ + │ ScrollView 190px │ │ + │ ┌────────────────┐ │ │ + │ │ Settings │ │ │ + │ │ History: 2000 │ │ │ + │ │ [1][2][3] │ │ │ + │ │ [4][5][6] │ │ │ + │ │ [Clear][Line] │ │ │ + │ │ [Scat][Auto] │ │ │ + │ │ [HZ ][VZ ] │ │ │ + │ ├────────────────┤ │ │ + │ │ Import │ │ │ + │ │ [XML] │ │ │ + │ ├────────────────┤ │ │ + │ │ Export │ │ │ + │ │ W:640 H:480 │ │ │ + │ │ Scale: 1.0 │ │ │ + │ │ [XML][PNG] │ │ │ + │ │ [CSV][PDF] │ │ │ + │ └────────────────┘ │ │ + └────────────────────┴─────────────────────────────────────┘ +*/ +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import QtQuick.Dialogs +import QtGraphs +import Vedder.vesc + +Item { + id: expPage + + // Internal data storage (mirrors EXPERIMENT_PLOT struct vector) + property var plotGraphs: [] // array of {label, color, xData[], yData[]} + property int currentGraphIndex: 0 + property bool needsReplot: false + property string xLabelText: "" + property string yLabelText: "" + + // Auto-color assignment matching original order + readonly property var graphColors: [ + Utility.getAppHexColor("plot_graph1"), + Utility.getAppHexColor("plot_graph2"), + Utility.getAppHexColor("plot_graph3"), + Utility.getAppHexColor("plot_graph4"), + Utility.getAppHexColor("plot_graph5"), + Utility.getAppHexColor("plot_graph6") + ] + + // 20ms replot timer (matches original) + Timer { + id: replotTimer + interval: 20; running: true; repeat: true + onTriggered: { + if (needsReplot) { + doReplot() + needsReplot = false + } + } + } + + function doReplot() { + // Clear existing series + for (var i = experimentChart.count - 1; i >= 0; i--) + experimentChart.removeSeries(experimentChart.seriesAt(i)) + + var graphButtons = [graph1Btn, graph2Btn, graph3Btn, graph4Btn, graph5Btn, graph6Btn] + + for (var g = 0; g < plotGraphs.length; g++) { + // Check visibility via toggle buttons (first 6) + if (g < 6 && !graphButtons[g].checked) continue + + var pg = plotGraphs[g] + + var series = experimentChart.createSeries( + showLineBtn.checked ? GraphsView.SeriesTypeLine : GraphsView.SeriesTypeScatter, + pg.label + ) + series.color = pg.color + series.width = 1.5 + + for (var k = 0; k < pg.xData.length; k++) + series.append(pg.xData[k], pg.yData[k]) + } + + // Update axis labels + experimentAxisX.titleText = xLabelText + experimentAxisY.titleText = yLabelText + + // Auto-scale if checked + if (autoScaleBtn.checked) { + rescaleAxes() + } + } + + function rescaleAxes() { + var xMin = Infinity, xMax = -Infinity, yMin = Infinity, yMax = -Infinity + for (var i = 0; i < experimentChart.count; i++) { + var s = experimentChart.seriesAt(i) + for (var j = 0; j < s.count; j++) { + var pt = s.at(j) + if (pt.x < xMin) xMin = pt.x + if (pt.x > xMax) xMax = pt.x + if (pt.y < yMin) yMin = pt.y + if (pt.y > yMax) yMax = pt.y + } + } + if (xMin < xMax) { + experimentAxisX.min = xMin + experimentAxisX.max = xMax + } + if (yMin < yMax) { + var pad = (yMax - yMin) * 0.05 + if (pad < 0.001) pad = 0.001 + experimentAxisY.min = yMin - pad + experimentAxisY.max = yMax + pad + } + } + + // ---- Signal handlers from VESC Commands ---- + Connections { + target: VescIf.commands() + + function onPlotInitReceived(xLabel, yLabel) { + plotGraphs = [] + currentGraphIndex = 0 + xLabelText = xLabel + yLabelText = yLabel + needsReplot = true + } + + function onPlotDataReceived(x, y) { + // Ensure graph exists + while (plotGraphs.length <= currentGraphIndex) { + plotGraphs.push({ + label: "Graph " + (plotGraphs.length + 1), + color: graphColors[Math.min(plotGraphs.length, graphColors.length - 1)], + xData: [], + yData: [] + }) + } + + var g = plotGraphs[currentGraphIndex] + g.xData.push(x) + g.yData.push(y) + + // History cap + var historyMax = historyBox.value + if (g.xData.length > historyMax) { + var excess = g.xData.length - historyMax + g.xData.splice(0, excess) + g.yData.splice(0, excess) + } + + // Trigger reactive update + plotGraphs = plotGraphs + needsReplot = true + } + + function onPlotAddGraphReceived(name) { + var newGraph = { + label: name, + color: graphColors[Math.min(plotGraphs.length, graphColors.length - 1)], + xData: [], + yData: [] + } + var temp = plotGraphs.slice() + temp.push(newGraph) + plotGraphs = temp + needsReplot = true + } + + function onPlotSetGraphReceived(graph) { + currentGraphIndex = graph + } + } + + // ---- XML Save/Load helpers using Utility ---- + function saveXml(path) { + var xml = '\n\n' + xml += ' ' + xLabelText + '\n' + xml += ' ' + yLabelText + '\n' + for (var i = 0; i < plotGraphs.length; i++) { + var g = plotGraphs[i] + xml += ' \n' + xml += ' \n' + xml += ' ' + g.color + '\n' + for (var j = 0; j < g.xData.length; j++) { + xml += ' ' + g.xData[j] + '' + g.yData[j] + '\n' + } + xml += ' \n' + } + xml += '\n' + return Utility.writeTextFile(path, xml) + } + + function loadXml(path) { + var text = Utility.readTextFile(path) + if (text.length === 0) return false + + var parser = new DOMParser() + // Not available in QML — use simple regex-based parsing instead + return parseXmlManual(text) + } + + function parseXmlManual(text) { + plotGraphs = [] + currentGraphIndex = 0 + + // Extract xlabel + var xlm = text.match(/(.*?)<\/xlabel>/) + if (xlm) xLabelText = xlm[1] + + var ylm = text.match(/(.*?)<\/ylabel>/) + if (ylm) yLabelText = ylm[1] + + // Extract graphs + var graphRegex = /([\s\S]*?)<\/graph>/g + var gMatch + while ((gMatch = graphRegex.exec(text)) !== null) { + var gText = gMatch[1] + var g = { label: "", color: "#4d7fc4", xData: [], yData: [] } + + var lm = gText.match(/