Change QWidget to QML rendering method

This commit is contained in:
Alex Spataru 2021-12-18 01:37:48 -05:00
parent 8fc81d5be7
commit 15ef343432
44 changed files with 826 additions and 1724 deletions

View File

@ -41,18 +41,15 @@ TEMPLATE = app # Project template
TARGET = serial-studio # Set default target name
CONFIG += qtquickcompiler # Pre-compile QML interface
CONFIG += utf8_source # Source code encoding
QTPLUGIN += qsvg # Fixes issues with windeployqt
QT += xml
QT += sql
QT += svg
QT += core
QT += quick
QT += widgets
QT += serialport
QT += printsupport
QT += quickwidgets
QT += quickcontrols2
equals(QT_MAJOR_VERSION, 6) {
@ -65,49 +62,48 @@ DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x050F00
# Compiler options
#-----------------------------------------------------------------------------------------
CONFIG += c++11
CONFIG += silent
*g++*: {
QMAKE_CXXFLAGS_RELEASE -= -O1
QMAKE_CXXFLAGS_RELEASE -= -O2
QMAKE_CXXFLAGS_RELEASE *= -O3
QMAKE_CXXFLAGS_RELEASE *= -Ofast
QMAKE_CXXFLAGS_RELEASE *= -flto
}
*clang*: {
QMAKE_CXXFLAGS_RELEASE -= -O1
QMAKE_CXXFLAGS_RELEASE -= -O2
QMAKE_CXXFLAGS_RELEASE *= -O3
QMAKE_CXXFLAGS_RELEASE *= -Ofast
QMAKE_CXXFLAGS_RELEASE *= -flto
}
*msvc*: {
QMAKE_CXXFLAGS *= -MP
QMAKE_CXXFLAGS_RELEASE -= /O
QMAKE_CXXFLAGS_RELEASE *= /O2
QMAKE_CXXFLAGS_RELEASE *= /GL
INCLUDEPATH += $$OUT_PWD
INCLUDEPATH += $$OUT_PWD/debug
INCLUDEPATH += $$OUT_PWD/release
}
CONFIG += c++11
CONFIG += silent
#-----------------------------------------------------------------------------------------
# Unity build
#-----------------------------------------------------------------------------------------
CONFIG(release, debug|release) {
CONFIG += unity_build
}
CONFIG += ltcg
CONFIG(unity_build) {
CONFIG += ltcg # Enable linker optimization
DEFINES += UNITY_BUILD=1 # Enable unity build
DEFINES += UNITY_BUILD_INCLUDE_QML=0 # Do not optimize QtQuick compiler cache
SOURCES += src/SingleCompilationUnit.cpp # Include single compilation unit in code
*g++*: {
QMAKE_CXXFLAGS_RELEASE *= -Ofast
QMAKE_CXXFLAGS_RELEASE *= -flto
}
*clang*: {
QMAKE_CXXFLAGS_RELEASE *= -Ofast
QMAKE_CXXFLAGS_RELEASE *= -flto
}
*msvc*: {
QMAKE_CXXFLAGS_RELEASE *= /GL
}
}
#-----------------------------------------------------------------------------------------
@ -117,10 +113,6 @@ CONFIG(unity_build) {
#DEFINES += DISABLE_QSU # If enabled, QSimpleUpdater shall not be used by the app.
# This is the default behaviour for MinGW.
DEFINES += LAZY_WIDGETS # Compile-time option to reduce the CPU usage of the widgets.
# If disabled, widgets shall update title, units, value, etc.
# If enabled, widgets shall only update their value.
#-----------------------------------------------------------------------------------------
# Libraries
#-----------------------------------------------------------------------------------------
@ -202,24 +194,25 @@ HEADERS += \
src/Misc/Utilities.h \
src/Plugins/Server.h \
src/UI/Dashboard.h \
src/UI/WidgetLoader.h \
src/Widgets/Accelerometer.h \
src/Widgets/Bar.h \
src/Widgets/Common/AnalogGauge.h \
src/Widgets/Common/AttitudeIndicator.h \
src/Widgets/Common/BaseWidget.h \
src/Widgets/Common/ElidedLabel.h \
src/Widgets/Common/KLed.h \
src/Widgets/Compass.h \
src/Widgets/DataGroup.h \
src/Widgets/FFTPlot.h \
src/Widgets/GPS.h \
src/Widgets/Gauge.h \
src/Widgets/Gyroscope.h \
src/Widgets/LEDPanel.h \
src/Widgets/MultiPlot.h \
src/Widgets/Plot.h \
src/Widgets/Terminal.h
src/UI/DashboardWidget.h \
src/UI/DeclarativeWidget.h \
src/UI/Widgets/Terminal.h \
src/UI/Widgets/Accelerometer.h \
src/UI/Widgets/Bar.h \
src/UI/Widgets/Common/AnalogGauge.h \
src/UI/Widgets/Common/AttitudeIndicator.h \
src/UI/Widgets/Common/BaseWidget.h \
src/UI/Widgets/Common/ElidedLabel.h \
src/UI/Widgets/Common/KLed.h \
src/UI/Widgets/Compass.h \
src/UI/Widgets/DataGroup.h \
src/UI/Widgets/FFTPlot.h \
src/UI/Widgets/GPS.h \
src/UI/Widgets/Gauge.h \
src/UI/Widgets/Gyroscope.h \
src/UI/Widgets/LEDPanel.h \
src/UI/Widgets/MultiPlot.h \
src/UI/Widgets/Plot.h
SOURCES += \
src/CSV/Export.cpp \
@ -244,24 +237,25 @@ SOURCES += \
src/Misc/Utilities.cpp \
src/Plugins/Server.cpp \
src/UI/Dashboard.cpp \
src/UI/WidgetLoader.cpp \
src/Widgets/Accelerometer.cpp \
src/Widgets/Bar.cpp \
src/Widgets/Common/AnalogGauge.cpp \
src/Widgets/Common/AttitudeIndicator.cpp \
src/Widgets/Common/BaseWidget.cpp \
src/Widgets/Common/ElidedLabel.cpp \
src/Widgets/Common/KLed.cpp \
src/Widgets/Compass.cpp \
src/Widgets/DataGroup.cpp \
src/Widgets/FFTPlot.cpp \
src/Widgets/GPS.cpp \
src/Widgets/Gauge.cpp \
src/Widgets/Gyroscope.cpp \
src/Widgets/LEDPanel.cpp \
src/Widgets/MultiPlot.cpp \
src/Widgets/Plot.cpp \
src/Widgets/Terminal.cpp \
src/UI/DashboardWidget.cpp \
src/UI/DeclarativeWidget.cpp \
src/UI/Widgets/Terminal.cpp \
src/UI/Widgets/Accelerometer.cpp \
src/UI/Widgets/Bar.cpp \
src/UI/Widgets/Common/AnalogGauge.cpp \
src/UI/Widgets/Common/AttitudeIndicator.cpp \
src/UI/Widgets/Common/BaseWidget.cpp \
src/UI/Widgets/Common/ElidedLabel.cpp \
src/UI/Widgets/Common/KLed.cpp \
src/UI/Widgets/Compass.cpp \
src/UI/Widgets/DataGroup.cpp \
src/UI/Widgets/FFTPlot.cpp \
src/UI/Widgets/GPS.cpp \
src/UI/Widgets/Gauge.cpp \
src/UI/Widgets/Gyroscope.cpp \
src/UI/Widgets/LEDPanel.cpp \
src/UI/Widgets/MultiPlot.cpp \
src/UI/Widgets/Plot.cpp \
src/main.cpp
#-----------------------------------------------------------------------------------------

View File

@ -38,8 +38,8 @@ Item {
Widgets.Window {
id: window
anchors.fill: parent
title: loader.widgetTitle
icon.source: loader.widgetIcon
title: widget.widgetTitle
icon.source: widget.widgetIcon
headerDoubleClickEnabled: true
borderColor: Cpp_ThemeManager.widgetWindowBorder
onHeaderDoubleClicked: {
@ -49,8 +49,8 @@ Item {
externalWindowLoader.active = true
}
WidgetLoader {
id: loader
DashboardWidget {
id: widget
widgetIndex: root.widgetIndex
anchors {
fill: parent
@ -71,7 +71,7 @@ Item {
id: _window
minimumWidth: 640 + shadowMargin
minimumHeight: 480 + shadowMargin
title: externalLoader.widgetTitle
title: externalWidget.widgetTitle
extraFlags: Qt.WindowStaysOnTopHint
titlebarText: Cpp_ThemeManager.text
titlebarColor: Cpp_ThemeManager.widgetWindowBackground
@ -107,8 +107,8 @@ Item {
}
}
WidgetLoader {
id: externalLoader
DashboardWidget {
id: externalWidget
anchors.fill: parent
isExternalWindow: true
widgetIndex: root.widgetIndex

View File

@ -50,9 +50,8 @@
#include <Plugins/Server.h>
#include <UI/Dashboard.h>
#include <UI/WidgetLoader.h>
#include <Widgets/Terminal.h>
#include <UI/DashboardWidget.h>
#include <UI/Widgets/Terminal.h>
#include <QQuickWindow>
#include <QSimpleUpdater.h>
@ -139,7 +138,7 @@ void Misc::ModuleManager::registerQmlTypes()
qmlRegisterType<JSON::Group>("SerialStudio", 1, 0, "Group");
qmlRegisterType<JSON::Dataset>("SerialStudio", 1, 0, "Dataset");
qmlRegisterType<Widgets::Terminal>("SerialStudio", 1, 0, "Terminal");
qmlRegisterType<UI::WidgetLoader>("SerialStudio", 1, 0, "WidgetLoader");
qmlRegisterType<UI::DashboardWidget>("SerialStudio", 1, 0, "DashboardWidget");
}
/**

View File

@ -1,603 +0,0 @@
//
// Well, this will be a PITA to maintain. But we can implement some interesting
// optimizations by using this approach, for example this build approach can lead to
// faster code, because the compiler can do more aggressive optimizations on all the
// program's code.
//
// See these articles for more information:
// https://en.wikipedia.org/wiki/Single_Compilation_Unit
// https://en.wikipedia.org/wiki/Unity_build
// https://mesonbuild.com/Unity-builds.html
//
// TODOs:
// - Write a script that generates this file automagically
//
#if UNITY_BUILD
// clang-format off
//----------------------------------------------------------------------------------------
// Third-party library headers
//----------------------------------------------------------------------------------------
#include "qwt/src/qwt.h"
#include "qwt/src/qwt_abstract_scale_draw.h"
#include "qwt/src/qwt_bezier.h"
#include "qwt/src/qwt_clipper.h"
#include "qwt/src/qwt_color_map.h"
#include "qwt/src/qwt_column_symbol.h"
#include "qwt/src/qwt_date.h"
#include "qwt/src/qwt_date_scale_draw.h"
#include "qwt/src/qwt_date_scale_engine.h"
#include "qwt/src/qwt_dyngrid_layout.h"
#include "qwt/src/qwt_global.h"
#include "qwt/src/qwt_graphic.h"
#include "qwt/src/qwt_interval.h"
#include "qwt/src/qwt_interval_symbol.h"
#include "qwt/src/qwt_math.h"
#include "qwt/src/qwt_magnifier.h"
#include "qwt/src/qwt_null_paintdevice.h"
#include "qwt/src/qwt_painter.h"
#include "qwt/src/qwt_painter_command.h"
#include "qwt/src/qwt_panner.h"
#include "qwt/src/qwt_picker.h"
#include "qwt/src/qwt_picker_machine.h"
#include "qwt/src/qwt_pixel_matrix.h"
#include "qwt/src/qwt_point_3d.h"
#include "qwt/src/qwt_point_polar.h"
#include "qwt/src/qwt_round_scale_draw.h"
#include "qwt/src/qwt_scale_div.h"
#include "qwt/src/qwt_scale_draw.h"
#include "qwt/src/qwt_scale_engine.h"
#include "qwt/src/qwt_scale_map.h"
#include "qwt/src/qwt_spline.h"
#include "qwt/src/qwt_spline_basis.h"
#include "qwt/src/qwt_spline_parametrization.h"
#include "qwt/src/qwt_spline_local.h"
#include "qwt/src/qwt_spline_cubic.h"
#include "qwt/src/qwt_spline_pleasing.h"
#include "qwt/src/qwt_spline_polynomial.h"
#include "qwt/src/qwt_symbol.h"
#include "qwt/src/qwt_system_clock.h"
#include "qwt/src/qwt_text_engine.h"
#include "qwt/src/qwt_text_label.h"
#include "qwt/src/qwt_text.h"
#include "qwt/src/qwt_transform.h"
#include "qwt/src/qwt_widget_overlay.h"
#include "qwt/src/qwt_axis.h"
#include "qwt/src/qwt_axis_id.h"
#include "qwt/src/qwt_curve_fitter.h"
#include "qwt/src/qwt_spline_curve_fitter.h"
#include "qwt/src/qwt_weeding_curve_fitter.h"
#include "qwt/src/qwt_event_pattern.h"
#include "qwt/src/qwt_abstract_legend.h"
#include "qwt/src/qwt_legend.h"
#include "qwt/src/qwt_legend_data.h"
#include "qwt/src/qwt_legend_label.h"
#include "qwt/src/qwt_plot.h"
#include "qwt/src/qwt_plot_renderer.h"
#include "qwt/src/qwt_plot_curve.h"
#include "qwt/src/qwt_plot_dict.h"
#include "qwt/src/qwt_plot_directpainter.h"
#include "qwt/src/qwt_plot_graphicitem.h"
#include "qwt/src/qwt_plot_grid.h"
#include "qwt/src/qwt_plot_histogram.h"
#include "qwt/src/qwt_plot_item.h"
#include "qwt/src/qwt_plot_abstract_barchart.h"
#include "qwt/src/qwt_plot_barchart.h"
#include "qwt/src/qwt_plot_multi_barchart.h"
#include "qwt/src/qwt_plot_intervalcurve.h"
#include "qwt/src/qwt_plot_tradingcurve.h"
#include "qwt/src/qwt_plot_layout.h"
#include "qwt/src/qwt_plot_marker.h"
#include "qwt/src/qwt_plot_zoneitem.h"
#include "qwt/src/qwt_plot_textlabel.h"
#include "qwt/src/qwt_plot_rasteritem.h"
#include "qwt/src/qwt_plot_spectrogram.h"
#include "qwt/src/qwt_plot_spectrocurve.h"
#include "qwt/src/qwt_plot_scaleitem.h"
#include "qwt/src/qwt_plot_legenditem.h"
#include "qwt/src/qwt_plot_seriesitem.h"
#include "qwt/src/qwt_plot_shapeitem.h"
#include "qwt/src/qwt_plot_vectorfield.h"
#include "qwt/src/qwt_plot_abstract_canvas.h"
#include "qwt/src/qwt_plot_canvas.h"
#include "qwt/src/qwt_plot_panner.h"
#include "qwt/src/qwt_plot_picker.h"
#include "qwt/src/qwt_plot_zoomer.h"
#include "qwt/src/qwt_plot_magnifier.h"
#include "qwt/src/qwt_plot_rescaler.h"
#include "qwt/src/qwt_point_mapper.h"
#include "qwt/src/qwt_raster_data.h"
#include "qwt/src/qwt_matrix_raster_data.h"
#include "qwt/src/qwt_vectorfield_symbol.h"
#include "qwt/src/qwt_sampling_thread.h"
#include "qwt/src/qwt_samples.h"
#include "qwt/src/qwt_series_data.h"
#include "qwt/src/qwt_series_store.h"
#include "qwt/src/qwt_point_data.h"
#include "qwt/src/qwt_scale_widget.h"
#include "qwt/src/qwt_polar.h"
#include "qwt/src/qwt_polar_canvas.h"
#include "qwt/src/qwt_polar_curve.h"
#include "qwt/src/qwt_polar_fitter.h"
#include "qwt/src/qwt_polar_grid.h"
#include "qwt/src/qwt_polar_itemdict.h"
#include "qwt/src/qwt_polar_item.h"
#include "qwt/src/qwt_polar_layout.h"
#include "qwt/src/qwt_polar_magnifier.h"
#include "qwt/src/qwt_polar_marker.h"
#include "qwt/src/qwt_polar_panner.h"
#include "qwt/src/qwt_polar_picker.h"
#include "qwt/src/qwt_polar_plot.h"
#include "qwt/src/qwt_polar_renderer.h"
#include "qwt/src/qwt_polar_spectrogram.h"
#include "qwt/src/qwt_abstract_slider.h"
#include "qwt/src/qwt_abstract_scale.h"
#include "qwt/src/qwt_arrow_button.h"
#include "qwt/src/qwt_analog_clock.h"
#include "qwt/src/qwt_compass.h"
#include "qwt/src/qwt_compass_rose.h"
#include "qwt/src/qwt_counter.h"
#include "qwt/src/qwt_dial.h"
#include "qwt/src/qwt_dial_needle.h"
#include "qwt/src/qwt_knob.h"
#include "qwt/src/qwt_slider.h"
#include "qwt/src/qwt_thermo.h"
#include "qwt/src/qwt_wheel.h"
#include "qtcsv/include/qtcsv/qtcsv_global.h"
#include "qtcsv/include/qtcsv/writer.h"
#include "qtcsv/include/qtcsv/variantdata.h"
#include "qtcsv/include/qtcsv/stringdata.h"
#include "qtcsv/include/qtcsv/reader.h"
#include "qtcsv/include/qtcsv/abstractdata.h"
#include "qtcsv/sources/filechecker.h"
#include "qtcsv/sources/contentiterator.h"
#include "qtcsv/sources/symbols.h"
#include "qmqtt/src/mqtt/qmqtt.h"
#include "qmqtt/src/mqtt/qmqtt_client.h"
#include "qmqtt/src/mqtt/qmqtt_client_p.h"
#include "qmqtt/src/mqtt/qmqtt_frame.h"
#include "qmqtt/src/mqtt/qmqtt_global.h"
#include "qmqtt/src/mqtt/qmqtt_message.h"
#include "qmqtt/src/mqtt/qmqtt_message_p.h"
#include "qmqtt/src/mqtt/qmqtt_network_p.h"
#include "qmqtt/src/mqtt/qmqtt_networkinterface.h"
#include "qmqtt/src/mqtt/qmqtt_routedmessage.h"
#include "qmqtt/src/mqtt/qmqtt_router.h"
#include "qmqtt/src/mqtt/qmqtt_routesubscription.h"
#include "qmqtt/src/mqtt/qmqtt_socket_p.h"
#include "qmqtt/src/mqtt/qmqtt_socketinterface.h"
#include "qmqtt/src/mqtt/qmqtt_timer_p.h"
#include "qmqtt/src/mqtt/qmqtt_timerinterface.h"
#include "qmqtt/src/mqtt/qmqtt_ssl_socket_p.h"
#include "QRealFourier/fftreal/Array.h"
#include "QRealFourier/fftreal/Array.h"
#include "QRealFourier/fftreal/DynArray.h"
#include "QRealFourier/fftreal/DynArray.h"
#include "QRealFourier/fftreal/FFTReal.h"
#include "QRealFourier/fftreal/FFTReal.h"
#include "QRealFourier/fftreal/FFTRealFixLen.h"
#include "QRealFourier/fftreal/FFTRealFixLen.h"
#include "QRealFourier/fftreal/FFTRealFixLenParam.h"
#include "QRealFourier/fftreal/FFTRealPassDirect.h"
#include "QRealFourier/fftreal/FFTRealPassDirect.h"
#include "QRealFourier/fftreal/FFTRealPassInverse.h"
#include "QRealFourier/fftreal/FFTRealPassInverse.h"
#include "QRealFourier/fftreal/FFTRealSelect.h"
#include "QRealFourier/fftreal/FFTRealSelect.h"
#include "QRealFourier/fftreal/FFTRealUseTrigo.h"
#include "QRealFourier/fftreal/FFTRealUseTrigo.h"
#include "QRealFourier/fftreal/OscSinCos.h"
#include "QRealFourier/fftreal/OscSinCos.h"
#include "QRealFourier/fftreal/def.h"
#include "QRealFourier/headers/qcomplexnumber.h"
#include "QRealFourier/headers/qfouriercalculator.h"
#include "QRealFourier/headers/qfourierfixedcalculator.h"
#include "QRealFourier/headers/qfouriertransformer.h"
#include "QRealFourier/headers/qfouriervariablecalculator.h"
#include "QRealFourier/headers/qwindowfunction.h"
#include "QSimpleUpdater/include/QSimpleUpdater.h"
#include "QSimpleUpdater/src/Updater.h"
#include "QSimpleUpdater/src/Downloader.h"
#include "KDMacTouchBar/src/kdmactouchbar.h"
#include "KDMacTouchBar/src/kdmactouchbar_global.h"
#include "QMapControl/src/curve.h"
#include "QMapControl/src/geometry.h"
#include "QMapControl/src/imagemanager.h"
#include "QMapControl/src/layer.h"
#include "QMapControl/src/layermanager.h"
#include "QMapControl/src/linestring.h"
#include "QMapControl/src/mapadapter.h"
#include "QMapControl/src/mapcontrol.h"
#include "QMapControl/src/mapnetwork.h"
#include "QMapControl/src/point.h"
#include "QMapControl/src/tilemapadapter.h"
#include "QMapControl/src/wmsmapadapter.h"
#include "QMapControl/src/circlepoint.h"
#include "QMapControl/src/imagepoint.h"
#include "QMapControl/src/gps_position.h"
#include "QMapControl/src/osmmapadapter.h"
#include "QMapControl/src/maplayer.h"
#include "QMapControl/src/geometrylayer.h"
#include "QMapControl/src/googlemapadapter.h"
#include "QMapControl/src/openaerialmapadapter.h"
#include "QMapControl/src/fixedimageoverlay.h"
#include "QMapControl/src/emptymapadapter.h"
#include "QMapControl/src/arrowpoint.h"
#include "QMapControl/src/invisiblepoint.h"
#include "QMapControl/src/qmapcontrol_global.h"
#include "QMapControl/src/bingapimapadapter.h"
#include "QMapControl/src/googleapimapadapter.h"
//----------------------------------------------------------------------------------------
// App headers
//----------------------------------------------------------------------------------------
#include "AppInfo.h"
#include "DataTypes.h"
#include "CSV/Export.h"
#include "CSV/Player.h"
#include "IO/Checksum.h"
#include "IO/Console.h"
#include "IO/DataSources/Network.h"
#include "IO/DataSources/Serial.h"
#include "IO/Manager.h"
#include "JSON/Dataset.h"
#include "JSON/Editor.h"
#include "JSON/Frame.h"
#include "JSON/FrameInfo.h"
#include "JSON/Generator.h"
#include "JSON/Group.h"
#include "MQTT/Client.h"
#include "Misc/MacExtras.h"
#include "Misc/ModuleManager.h"
#include "Misc/ThemeManager.h"
#include "Misc/TimerEvents.h"
#include "Misc/Translator.h"
#include "Misc/Utilities.h"
#include "Plugins/Server.h"
#include "UI/Dashboard.h"
#include "UI/WidgetLoader.h"
#include "Widgets/Accelerometer.h"
#include "Widgets/Bar.h"
#include "Widgets/Common/AnalogGauge.h"
#include "Widgets/Common/AttitudeIndicator.h"
#include "Widgets/Common/BaseWidget.h"
#include "Widgets/Common/KLed.h"
#include "Widgets/Compass.h"
#include "Widgets/DataGroup.h"
#include "Widgets/FFTPlot.h"
#include "Widgets/GPS.h"
#include "Widgets/Gauge.h"
#include "Widgets/Gyroscope.h"
#include "Widgets/LEDPanel.h"
#include "Widgets/MultiPlot.h"
#include "Widgets/Plot.h"
#include "Widgets/Terminal.h"
//----------------------------------------------------------------------------------------
// Third-party source files (Qwt)
//----------------------------------------------------------------------------------------
#include "qwt/src/qwt.cpp"
#include "qwt/src/qwt_abstract_scale_draw.cpp"
#include "qwt/src/qwt_bezier.cpp"
#include "qwt/src/qwt_clipper.cpp"
#include "qwt/src/qwt_color_map.cpp"
#include "qwt/src/qwt_column_symbol.cpp"
#include "qwt/src/qwt_date.cpp"
#include "qwt/src/qwt_date_scale_draw.cpp"
#include "qwt/src/qwt_date_scale_engine.cpp"
#include "qwt/src/qwt_dyngrid_layout.cpp"
#include "qwt/src/qwt_event_pattern.cpp"
#include "qwt/src/qwt_graphic.cpp"
#include "qwt/src/qwt_interval.cpp"
#include "qwt/src/qwt_interval_symbol.cpp"
#include "qwt/src/qwt_math.cpp"
#include "qwt/src/qwt_magnifier.cpp"
#include "qwt/src/qwt_null_paintdevice.cpp"
#include "qwt/src/qwt_painter.cpp"
#include "qwt/src/qwt_painter_command.cpp"
#include "qwt/src/qwt_panner.cpp"
#include "qwt/src/qwt_picker.cpp"
#include "qwt/src/qwt_picker_machine.cpp"
#include "qwt/src/qwt_pixel_matrix.cpp"
#include "qwt/src/qwt_point_3d.cpp"
#include "qwt/src/qwt_point_polar.cpp"
#include "qwt/src/qwt_round_scale_draw.cpp"
#include "qwt/src/qwt_scale_div.cpp"
#include "qwt/src/qwt_scale_draw.cpp"
#include "qwt/src/qwt_scale_map.cpp"
#include "qwt/src/qwt_scale_engine.cpp"
#include "qwt/src/qwt_spline.cpp"
#include "qwt/src/qwt_spline_basis.cpp"
#include "qwt/src/qwt_spline_parametrization.cpp"
#include "qwt/src/qwt_spline_local.cpp"
#include "qwt/src/qwt_spline_cubic.cpp"
#include "qwt/src/qwt_spline_pleasing.cpp"
#include "qwt/src/qwt_spline_polynomial.cpp"
#include "qwt/src/qwt_symbol.cpp"
#include "qwt/src/qwt_system_clock.cpp"
#include "qwt/src/qwt_text_engine.cpp"
#include "qwt/src/qwt_text_label.cpp"
#include "qwt/src/qwt_text.cpp"
#include "qwt/src/qwt_transform.cpp"
#include "qwt/src/qwt_widget_overlay.cpp"
#include "qwt/src/qwt_curve_fitter.cpp"
#include "qwt/src/qwt_spline_curve_fitter.cpp"
#include "qwt/src/qwt_weeding_curve_fitter.cpp"
#include "qwt/src/qwt_abstract_legend.cpp"
#include "qwt/src/qwt_legend.cpp"
#include "qwt/src/qwt_legend_data.cpp"
#include "qwt/src/qwt_legend_label.cpp"
#include "qwt/src/qwt_plot.cpp"
#include "qwt/src/qwt_plot_renderer.cpp"
#include "qwt/src/qwt_plot_axis.cpp"
#include "qwt/src/qwt_plot_curve.cpp"
#include "qwt/src/qwt_plot_dict.cpp"
#include "qwt/src/qwt_plot_directpainter.cpp"
#include "qwt/src/qwt_plot_graphicitem.cpp"
#include "qwt/src/qwt_plot_grid.cpp"
#include "qwt/src/qwt_plot_histogram.cpp"
#include "qwt/src/qwt_plot_item.cpp"
#include "qwt/src/qwt_plot_abstract_barchart.cpp"
#include "qwt/src/qwt_plot_barchart.cpp"
#include "qwt/src/qwt_plot_multi_barchart.cpp"
#include "qwt/src/qwt_plot_intervalcurve.cpp"
#include "qwt/src/qwt_plot_zoneitem.cpp"
#include "qwt/src/qwt_plot_tradingcurve.cpp"
#include "qwt/src/qwt_plot_spectrogram.cpp"
#include "qwt/src/qwt_plot_spectrocurve.cpp"
#include "qwt/src/qwt_plot_scaleitem.cpp"
#include "qwt/src/qwt_plot_legenditem.cpp"
#include "qwt/src/qwt_plot_seriesitem.cpp"
#include "qwt/src/qwt_plot_shapeitem.cpp"
#include "qwt/src/qwt_plot_vectorfield.cpp"
#include "qwt/src/qwt_plot_marker.cpp"
#include "qwt/src/qwt_plot_textlabel.cpp"
#include "qwt/src/qwt_plot_layout.cpp"
#include "qwt/src/qwt_plot_abstract_canvas.cpp"
#include "qwt/src/qwt_plot_canvas.cpp"
#include "qwt/src/qwt_plot_panner.cpp"
#include "qwt/src/qwt_plot_rasteritem.cpp"
#include "qwt/src/qwt_plot_picker.cpp"
#include "qwt/src/qwt_plot_zoomer.cpp"
#include "qwt/src/qwt_plot_magnifier.cpp"
#include "qwt/src/qwt_plot_rescaler.cpp"
#include "qwt/src/qwt_point_mapper.cpp"
#include "qwt/src/qwt_raster_data.cpp"
#include "qwt/src/qwt_matrix_raster_data.cpp"
#include "qwt/src/qwt_vectorfield_symbol.cpp"
#include "qwt/src/qwt_sampling_thread.cpp"
#include "qwt/src/qwt_series_data.cpp"
#include "qwt/src/qwt_point_data.cpp"
#include "qwt/src/qwt_scale_widget.cpp"
#include "qwt/src/qwt_polar_canvas.cpp"
#include "qwt/src/qwt_polar_curve.cpp"
#include "qwt/src/qwt_polar_fitter.cpp"
#include "qwt/src/qwt_polar_grid.cpp"
#include "qwt/src/qwt_polar_item.cpp"
#include "qwt/src/qwt_polar_itemdict.cpp"
#include "qwt/src/qwt_polar_layout.cpp"
#include "qwt/src/qwt_polar_magnifier.cpp"
#include "qwt/src/qwt_polar_marker.cpp"
#include "qwt/src/qwt_polar_panner.cpp"
#include "qwt/src/qwt_polar_picker.cpp"
#include "qwt/src/qwt_polar_plot.cpp"
#include "qwt/src/qwt_polar_renderer.cpp"
#include "qwt/src/qwt_polar_spectrogram.cpp"
#include "qwt/src/qwt_abstract_slider.cpp"
#include "qwt/src/qwt_abstract_scale.cpp"
#include "qwt/src/qwt_arrow_button.cpp"
#include "qwt/src/qwt_analog_clock.cpp"
#include "qwt/src/qwt_compass.cpp"
#include "qwt/src/qwt_compass_rose.cpp"
#include "qwt/src/qwt_counter.cpp"
#include "qwt/src/qwt_dial.cpp"
#include "qwt/src/qwt_dial_needle.cpp"
#include "qwt/src/qwt_knob.cpp"
#include "qwt/src/qwt_slider.cpp"
#include "qwt/src/qwt_thermo.cpp"
#include "qwt/src/qwt_wheel.cpp"
//----------------------------------------------------------------------------------------
// Third-party source files (non-Qwt)
//----------------------------------------------------------------------------------------
#include "qtcsv/sources/writer.cpp"
#include "qtcsv/sources/variantdata.cpp"
#include "qtcsv/sources/stringdata.cpp"
#include "qtcsv/sources/reader.cpp"
#include "qtcsv/sources/contentiterator.cpp"
#include "qmqtt/src/mqtt/qmqtt_client.cpp"
#include "qmqtt/src/mqtt/qmqtt_client_p.cpp"
#include "qmqtt/src/mqtt/qmqtt_frame.cpp"
#include "qmqtt/src/mqtt/qmqtt_message.cpp"
#include "qmqtt/src/mqtt/qmqtt_network.cpp"
#include "qmqtt/src/mqtt/qmqtt_router.cpp"
#include "qmqtt/src/mqtt/qmqtt_routesubscription.cpp"
#include "qmqtt/src/mqtt/qmqtt_socket.cpp"
#include "qmqtt/src/mqtt/qmqtt_timer.cpp"
#include "qmqtt/src/mqtt/qmqtt_ssl_socket.cpp"
#include "QRealFourier/sources/qcomplexnumber.cpp"
#include "QRealFourier/sources/qfouriercalculator.cpp"
#include "QRealFourier/sources/qfourierfixedcalculator.cpp"
#include "QRealFourier/sources/qfouriertransformer.cpp"
#include "QRealFourier/sources/qfouriervariablecalculator.cpp"
#include "QRealFourier/sources/qwindowfunction.cpp"
#include "QSimpleUpdater/src/Updater.cpp"
#include "QSimpleUpdater/src/Downloader.cpp"
#include "QSimpleUpdater/src/QSimpleUpdater.cpp"
#include "QMapControl/src/curve.cpp"
#include "QMapControl/src/geometry.cpp"
#include "QMapControl/src/imagemanager.cpp"
#include "QMapControl/src/layer.cpp"
#include "QMapControl/src/layermanager.cpp"
#include "QMapControl/src/linestring.cpp"
#include "QMapControl/src/mapadapter.cpp"
#include "QMapControl/src/mapcontrol.cpp"
#include "QMapControl/src/mapnetwork.cpp"
#include "QMapControl/src/point.cpp"
#include "QMapControl/src/tilemapadapter.cpp"
#include "QMapControl/src/wmsmapadapter.cpp"
#include "QMapControl/src/circlepoint.cpp"
#include "QMapControl/src/imagepoint.cpp"
#include "QMapControl/src/gps_position.cpp"
#include "QMapControl/src/osmmapadapter.cpp"
#include "QMapControl/src/maplayer.cpp"
#include "QMapControl/src/geometrylayer.cpp"
#include "QMapControl/src/googlemapadapter.cpp"
#include "QMapControl/src/openaerialmapadapter.cpp"
#include "QMapControl/src/fixedimageoverlay.cpp"
#include "QMapControl/src/emptymapadapter.cpp"
#include "QMapControl/src/arrowpoint.cpp"
#include "QMapControl/src/invisiblepoint.cpp"
#include "QMapControl/src/bingapimapadapter.cpp"
#include "QMapControl/src/googleapimapadapter.cpp"
//----------------------------------------------------------------------------------------
// App source files
//----------------------------------------------------------------------------------------
#include "CSV/Export.cpp"
#include "CSV/Player.cpp"
#include "IO/Checksum.cpp"
#include "IO/Console.cpp"
#include "IO/DataSources/Network.cpp"
#include "IO/DataSources/Serial.cpp"
#include "IO/Manager.cpp"
#include "JSON/Dataset.cpp"
#include "JSON/Editor.cpp"
#include "JSON/Frame.cpp"
#include "JSON/FrameInfo.cpp"
#include "JSON/Generator.cpp"
#include "JSON/Group.cpp"
#include "MQTT/Client.cpp"
#include "Misc/MacExtras.cpp"
#include "Misc/ModuleManager.cpp"
#include "Misc/ThemeManager.cpp"
#include "Misc/TimerEvents.cpp"
#include "Misc/Translator.cpp"
#include "Misc/Utilities.cpp"
#include "Plugins/Server.cpp"
#include "UI/Dashboard.cpp"
#include "UI/WidgetLoader.cpp"
#include "Widgets/Accelerometer.cpp"
#include "Widgets/Bar.cpp"
#include "Widgets/Common/AnalogGauge.cpp"
#include "Widgets/Common/AttitudeIndicator.cpp"
#include "Widgets/Common/BaseWidget.cpp"
#include "Widgets/Common/KLed.cpp"
#include "Widgets/Compass.cpp"
#include "Widgets/DataGroup.cpp"
#include "Widgets/FFTPlot.cpp"
#include "Widgets/GPS.cpp"
#include "Widgets/Gauge.cpp"
#include "Widgets/Gyroscope.cpp"
#include "Widgets/LEDPanel.cpp"
#include "Widgets/MultiPlot.cpp"
#include "Widgets/Plot.cpp"
#include "Widgets/Terminal.cpp"
#include "main.cpp"
//----------------------------------------------------------------------------------------
// Meta object compiler code
//----------------------------------------------------------------------------------------
#include "moc_Accelerometer.cpp"
#include "moc_Bar.cpp"
#include "moc_BaseWidget.cpp"
#include "moc_Client.cpp"
#include "moc_Compass.cpp"
#include "moc_Console.cpp"
#include "moc_Dashboard.cpp"
#include "moc_WidgetLoader.cpp"
#include "moc_DataGroup.cpp"
#include "moc_Editor.cpp"
#include "moc_Export.cpp"
#include "moc_FFTPlot.cpp"
#include "moc_Gauge.cpp"
#include "moc_Generator.cpp"
#include "moc_GPS.cpp"
#include "moc_Gyroscope.cpp"
#include "moc_KLed.cpp"
#include "moc_LEDPanel.cpp"
#include "moc_MacExtras.cpp"
#include "moc_Manager.cpp"
#include "moc_ModuleManager.cpp"
#include "moc_MultiPlot.cpp"
#include "moc_Network.cpp"
#include "moc_Player.cpp"
#include "moc_Plot.cpp"
#include "moc_Serial.cpp"
#include "moc_Server.cpp"
#include "moc_Terminal.cpp"
#include "moc_ThemeManager.cpp"
#include "moc_TimerEvents.cpp"
#include "moc_Translator.cpp"
#include "moc_Utilities.cpp"
//----------------------------------------------------------------------------------------
// Meta object compiler code from third-party libraries
//----------------------------------------------------------------------------------------
#include "moc_qmqtt_networkinterface.cpp"
#include "moc_qmqtt_socketinterface.cpp"
#include "moc_qmqtt_timerinterface.cpp"
#ifdef Q_OS_MAC
#include "moc_kdmactouchbar.cpp"
#endif
//----------------------------------------------------------------------------------------
// QtQuickCompiler code
//----------------------------------------------------------------------------------------
#if UNITY_BUILD_INCLUDE_QML
#include "assets_qml_main_qml.cpp"
#include "assets_qml_Windows_Acknowledgements_qml.cpp"
#include "assets_qml_Windows_CsvPlayer_qml.cpp"
#include "assets_qml_Windows_MainWindow_qml.cpp"
#include "assets_qml_Windows_Donate_qml.cpp"
#include "assets_qml_Windows_JsonEditor_qml.cpp"
#include "assets_qml_Windows_About_qml.cpp"
#include "assets_qml_Widgets_JSONDropArea_qml.cpp"
#include "assets_qml_Widgets_Window_qml.cpp"
#include "assets_qml_Widgets_Shadow_qml.cpp"
#include "assets_qml_Widgets_Icon_qml.cpp"
#include "assets_qml_Widgets_LED_qml.cpp"
#include "assets_qml_Widgets_Terminal_qml.cpp"
#include "assets_qml_Panes_Console_qml.cpp"
#include "assets_qml_Panes_Dashboard_qml.cpp"
#include "assets_qml_Panes_Setup_qml.cpp"
#include "assets_qml_Panes_Toolbar_qml.cpp"
#include "assets_qml_Panes_SetupPanes_MQTT_qml.cpp"
#include "assets_qml_Panes_SetupPanes_Serial_qml.cpp"
#include "assets_qml_Panes_SetupPanes_Settings_qml.cpp"
#include "assets_qml_Panes_SetupPanes_Network_qml.cpp"
#include "assets_qml_PlatformDependent_DecentMenuItem_qml.cpp"
#include "assets_qml_PlatformDependent_Menubar_qml.cpp"
#include "assets_qml_PlatformDependent_MenubarMacOS_qml.cpp"
#include "assets_qml_PlatformDependent_WindowButton_qml.cpp"
#include "assets_qml_PlatformDependent_WindowBorder_qml.cpp"
#include "assets_qml_PlatformDependent_CustomWindow_qml.cpp"
#include "assets_qml_JsonEditor_JsonGroupDelegate_qml.cpp"
#include "assets_qml_JsonEditor_TreeView_qml.cpp"
#include "assets_qml_JsonEditor_Header_qml.cpp"
#include "assets_qml_JsonEditor_Footer_qml.cpp"
#include "assets_qml_JsonEditor_JsonDatasetDelegate_qml.cpp"
#include "assets_qml_JsonEditor_GroupEditor_qml.cpp"
#include "assets_qml_Dashboard_DashboardTitle_qml.cpp"
#include "assets_qml_Dashboard_ViewOptions_qml.cpp"
#include "assets_qml_Dashboard_WidgetGrid_qml.cpp"
#include "assets_qml_Dashboard_WidgetDelegate_qml.cpp"
#include "assets_qml_Dashboard_ViewOptionsDelegate_qml.cpp"
#include "assets_qml_Dashboard_WidgetModel_qml.cpp"
#include "qmlcache_loader.cpp"
#endif
// clang-format on
#endif

249
src/UI/DashboardWidget.cpp Normal file
View File

@ -0,0 +1,249 @@
/*
* Copyright (c) 2021 Alex Spataru <https://github.com/alex-spataru>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "DashboardWidget.h"
#include <Misc/ThemeManager.h>
#include <UI/Widgets/Bar.h>
#include <UI/Widgets/GPS.h>
#include <UI/Widgets/Plot.h>
#include <UI/Widgets/Gauge.h>
#include <UI/Widgets/Compass.h>
#include <UI/Widgets/FFTPlot.h>
#include <UI/Widgets/LEDPanel.h>
#include <UI/Widgets/DataGroup.h>
#include <UI/Widgets/Gyroscope.h>
#include <UI/Widgets/MultiPlot.h>
#include <UI/Widgets/Accelerometer.h>
namespace UI
{
/**
* Constructor function
*/
DashboardWidget::DashboardWidget(QQuickItem *parent)
: DeclarativeWidget(parent)
, m_index(-1)
, m_widgetVisible(false)
, m_isExternalWindow(false)
{
// clang-format off
connect(Dashboard::getInstance(), &Dashboard::widgetVisibilityChanged,
this, &DashboardWidget::updateWidgetVisible);
// clang-format on
}
/**
* Delete widget on class destruction
*/
DashboardWidget::~DashboardWidget()
{
if (m_dbWidget)
delete m_dbWidget;
}
/**
* Returns the global index of the widget (index of the current widget in relation to all
* registered widgets).
*/
int DashboardWidget::widgetIndex() const
{
return m_index;
}
/**
* Returns the relative index of the widget (e.g. index of a bar widget in relation to the
* total number of bar widgets).
*/
int DashboardWidget::relativeIndex() const
{
return UI::Dashboard::getInstance()->relativeIndex(widgetIndex());
}
/**
* Returns @c true if the QML interface should display this widget.
*/
bool DashboardWidget::widgetVisible() const
{
return m_widgetVisible;
}
/**
* Returns the path of the SVG icon to use with this widget
*/
QString DashboardWidget::widgetIcon() const
{
return UI::Dashboard::getInstance()->widgetIcon(widgetIndex());
}
/**
* Returns the appropiate window title for the given widget
*/
QString DashboardWidget::widgetTitle() const
{
if (widgetIndex() >= 0)
{
auto titles = UI::Dashboard::getInstance()->widgetTitles();
if (widgetIndex() < titles.count())
return titles.at(widgetIndex());
}
return tr("Invalid");
}
/**
* If set to @c true, then the widget visibility shall be controlled
* directly by the QML interface.
*
* If set to @c false, then the widget visbility shall be controlled
* by the UI::Dashboard class via the SIGNAL/SLOT system.
*/
bool DashboardWidget::isExternalWindow() const
{
return m_isExternalWindow;
}
/**
* Returns the type of the current widget (e.g. group, plot, bar, gauge, etc...)
*/
UI::Dashboard::WidgetType DashboardWidget::widgetType() const
{
return UI::Dashboard::getInstance()->widgetType(widgetIndex());
}
/**
* Changes the visibility & enabled status of the widget
*/
void DashboardWidget::setVisible(const bool visible)
{
if (m_dbWidget)
{
m_dbWidget->setEnabled(visible);
update();
}
}
/**
* Selects & configures the appropiate widget for the given @a index
*/
void DashboardWidget::setWidgetIndex(const int index)
{
if (index < UI::Dashboard::getInstance()->totalWidgetCount() && index >= 0)
{
// Update widget index
m_index = index;
// Delete previous widget
if (m_dbWidget)
delete m_dbWidget;
// Construct new widget
switch (widgetType())
{
case UI::Dashboard::WidgetType::Group:
m_dbWidget = new Widgets::DataGroup(relativeIndex());
break;
case UI::Dashboard::WidgetType::MultiPlot:
m_dbWidget = new Widgets::MultiPlot(relativeIndex());
break;
case UI::Dashboard::WidgetType::FFT:
m_dbWidget = new Widgets::FFTPlot(relativeIndex());
break;
case UI::Dashboard::WidgetType::Plot:
m_dbWidget = new Widgets::Plot(relativeIndex());
break;
case UI::Dashboard::WidgetType::Bar:
m_dbWidget = new Widgets::Bar(relativeIndex());
break;
case UI::Dashboard::WidgetType::Gauge:
m_dbWidget = new Widgets::Gauge(relativeIndex());
break;
case UI::Dashboard::WidgetType::Compass:
m_dbWidget = new Widgets::Compass(relativeIndex());
break;
case UI::Dashboard::WidgetType::Gyroscope:
m_dbWidget = new Widgets::Gyroscope(relativeIndex());
break;
case UI::Dashboard::WidgetType::Accelerometer:
m_dbWidget = new Widgets::Accelerometer(relativeIndex());
break;
case UI::Dashboard::WidgetType::GPS:
m_dbWidget = new Widgets::GPS(relativeIndex());
break;
case UI::Dashboard::WidgetType::LED:
m_dbWidget = new Widgets::LEDPanel(relativeIndex());
break;
default:
break;
}
// Configure widget
if (m_dbWidget)
{
setWidget(m_dbWidget);
updateWidgetVisible();
connect(m_dbWidget, &Widgets::DashboardWidgetBase::updated,
[=]() { update(); });
Q_EMIT widgetIndexChanged();
}
}
}
/**
* Changes the widget visibility controller source.
*
* If set to @c true, then the widget visibility shall be controlled
* directly by the QML interface.
*
* If set to @c false, then the widget visbility shall be controlled
* by the UI::Dashboard class via the SIGNAL/SLOT system.
*/
void DashboardWidget::setIsExternalWindow(const bool isWindow)
{
m_isExternalWindow = isWindow;
Q_EMIT isExternalWindowChanged();
}
/**
* Updates the visibility status of the current widget (this function is called
* automatically by the UI::Dashboard class via signals/slots).
*/
void DashboardWidget::updateWidgetVisible()
{
bool visible = UI::Dashboard::getInstance()->widgetVisible(widgetIndex());
if (widgetVisible() != visible && !isExternalWindow())
{
m_widgetVisible = visible;
if (m_dbWidget)
{
m_dbWidget->setEnabled(visible);
update();
}
Q_EMIT widgetVisibleChanged();
}
}
}

View File

@ -22,19 +22,33 @@
#pragma once
#include <QWidget>
#include <QObject>
#include <QPainter>
#include <QQuickPaintedItem>
#include <UI/Dashboard.h>
#include <UI/DeclarativeWidget.h>
namespace Widgets
{
/**
* @brief The DashboardWidgetBase class
*
* A simple QWidget with an additional @c update() signal, which is used by the
* @c UI::DashboardWidget to know when it should trigger a re-paint request to the scene
* render thread.
*/
class DashboardWidgetBase : public QWidget
{
Q_OBJECT
Q_SIGNALS:
void updated();
};
}
namespace UI
{
/**
* @brief The WidgetLoader class
* @brief The DashboardWidget class
*
* The @c WidgetLoader class acts as a man-in-the-middle between the QML user interface
* The @c DashboardWidget class acts as a man-in-the-middle between the QML UI
* and the C++ widgets. C++ widgets are loaded and initialized by this class, and all the
* QML/Qt events are re-routed to the widgets using this class. Finally, the C++ widget
* is "painted" on the QML interface in realtime, effectively allowing us to use QWidget
@ -51,14 +65,8 @@ namespace UI
* assets/qml/Dashboard/WidgetDelegate.qml
* assets/qml/Dashboard/WidgetLoader.qml
* assets/qml/Dashboard/WidgetGrid.qml
*
* Basic diagram explaining this approach:
*
* ---------------- --------------- --------------- ----------------
* | UI::Dashboard | <--> | QML Repeater | --> | WidgetLoader | <--> | Actual Widget |
* ---------------- --------------- --------------- ----------------
*/
class WidgetLoader : public QQuickPaintedItem
class DashboardWidget : public DeclarativeWidget
{
// clang-format off
Q_OBJECT
@ -92,12 +100,8 @@ Q_SIGNALS:
void isExternalWindowChanged();
public:
WidgetLoader(QQuickItem *parent = 0);
~WidgetLoader();
virtual bool event(QEvent *event) override;
virtual void paint(QPainter *painter) override;
virtual bool eventFilter(QObject *watched, QEvent *event) override;
DashboardWidget(QQuickItem *parent = 0);
~DashboardWidget();
int widgetIndex() const;
int relativeIndex() const;
@ -107,28 +111,18 @@ public:
bool isExternalWindow() const;
UI::Dashboard::WidgetType widgetType() const;
QWidget *widget() const;
public Q_SLOTS:
void setVisible(const bool visible);
void setWidgetIndex(const int index);
void setIsExternalWindow(const bool isWindow);
void processMouseHover(const bool containsMouse);
private Q_SLOTS:
void updateWidgetSize();
void updateWidgetVisible();
protected:
void processLeaveEvent(QEvent *event);
void processEnterEvent(QEnterEvent *event);
void processMouseEvents(QMouseEvent *event);
void processWheelEvents(QWheelEvent *event);
private:
int m_index;
bool m_widgetVisible;
bool m_isExternalWindow;
QPointer<QWidget> m_widget;
QPointer<Widgets::DashboardWidgetBase> m_dbWidget;
};
}

View File

@ -0,0 +1,172 @@
/*
* Copyright (c) 2020-2021 Alex Spataru <https://github.com/alex-spataru>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "DeclarativeWidget.h"
namespace UI
{
#define EXEC_EVENT(pointer, function, event) \
if (!pointer.isNull()) \
{ \
class PwnedWidget : public QWidget \
{ \
public: \
using QWidget::function; \
}; \
static_cast<PwnedWidget *>(pointer.data())->function(event); \
update(); \
}
DeclarativeWidget::DeclarativeWidget(QQuickItem *parent)
: QQuickPaintedItem(parent)
{
setAntialiasing(true);
setOpaquePainting(true);
setAcceptTouchEvents(true);
setFlag(ItemHasContents, true);
setFlag(ItemIsFocusScope, true);
setFlag(ItemAcceptsInputMethod, true);
setAcceptedMouseButtons(Qt::AllButtons);
// clang-format off
connect(this, &QQuickPaintedItem::widthChanged,
this, &UI::DeclarativeWidget::resizeWidget);
connect(this, &QQuickPaintedItem::heightChanged,
this, &UI::DeclarativeWidget::resizeWidget);
connect(this, &UI::DeclarativeWidget::widgetChanged, [=](){update();});
// clang-format on
}
QWidget *DeclarativeWidget::widget()
{
return m_widget;
}
void DeclarativeWidget::update(const QRect &rect)
{
if (widget())
{
m_pixmap = m_widget->grab();
QQuickPaintedItem::update(rect);
}
}
void DeclarativeWidget::paint(QPainter *painter)
{
if (painter)
painter->drawPixmap(0, 0, m_pixmap);
}
void DeclarativeWidget::keyPressEvent(QKeyEvent *event)
{
EXEC_EVENT(m_widget, keyPressEvent, event);
}
void DeclarativeWidget::keyReleaseEvent(QKeyEvent *event)
{
EXEC_EVENT(m_widget, keyReleaseEvent, event);
}
void DeclarativeWidget::inputMethodEvent(QInputMethodEvent *event)
{
EXEC_EVENT(m_widget, inputMethodEvent, event);
}
void DeclarativeWidget::focusInEvent(QFocusEvent *event)
{
EXEC_EVENT(m_widget, focusInEvent, event);
}
void DeclarativeWidget::focusOutEvent(QFocusEvent *event)
{
EXEC_EVENT(m_widget, focusOutEvent, event);
}
void DeclarativeWidget::mousePressEvent(QMouseEvent *event)
{
EXEC_EVENT(m_widget, mousePressEvent, event);
}
void DeclarativeWidget::mouseMoveEvent(QMouseEvent *event)
{
EXEC_EVENT(m_widget, mouseMoveEvent, event);
}
void DeclarativeWidget::mouseReleaseEvent(QMouseEvent *event)
{
EXEC_EVENT(m_widget, mouseReleaseEvent, event);
}
void DeclarativeWidget::mouseDoubleClickEvent(QMouseEvent *event)
{
EXEC_EVENT(m_widget, mouseDoubleClickEvent, event);
}
void DeclarativeWidget::wheelEvent(QWheelEvent *event)
{
EXEC_EVENT(m_widget, wheelEvent, event);
}
void DeclarativeWidget::dragEnterEvent(QDragEnterEvent *event)
{
EXEC_EVENT(m_widget, dragEnterEvent, event);
}
void DeclarativeWidget::dragMoveEvent(QDragMoveEvent *event)
{
EXEC_EVENT(m_widget, dragMoveEvent, event);
}
void DeclarativeWidget::dragLeaveEvent(QDragLeaveEvent *event)
{
EXEC_EVENT(m_widget, dragLeaveEvent, event);
}
void DeclarativeWidget::dropEvent(QDropEvent *event)
{
EXEC_EVENT(m_widget, dropEvent, event);
}
void DeclarativeWidget::resizeWidget()
{
if (widget())
{
if (width() > 0 && height() > 0)
{
widget()->setFixedSize(width(), height());
update();
}
}
}
void DeclarativeWidget::setWidget(QWidget *widget)
{
if (widget)
{
if (m_widget)
delete m_widget;
m_widget = widget;
Q_EMIT widgetChanged();
}
}
}

View File

@ -0,0 +1,74 @@
/*
* Copyright (c) 2020-2021 Alex Spataru <https://github.com/alex-spataru>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#pragma once
#include <QEvent>
#include <QWidget>
#include <QPainter>
#include <QQuickPaintedItem>
namespace UI
{
class DeclarativeWidget : public QQuickPaintedItem
{
Q_OBJECT
Q_PROPERTY(QWidget *widget READ widget WRITE setWidget NOTIFY widgetChanged)
Q_SIGNALS:
void widgetChanged();
public:
DeclarativeWidget(QQuickItem *parent = 0);
QWidget *widget();
void update(const QRect &rect = QRect());
virtual void paint(QPainter *painter) override;
virtual void keyPressEvent(QKeyEvent *event) override;
virtual void keyReleaseEvent(QKeyEvent *event) override;
virtual void inputMethodEvent(QInputMethodEvent *event) override;
virtual void focusInEvent(QFocusEvent *event) override;
virtual void focusOutEvent(QFocusEvent *event) override;
virtual void mousePressEvent(QMouseEvent *event) override;
virtual void mouseMoveEvent(QMouseEvent *event) override;
virtual void mouseReleaseEvent(QMouseEvent *event) override;
virtual void mouseDoubleClickEvent(QMouseEvent *event) override;
virtual void wheelEvent(QWheelEvent *event) override;
virtual void dragEnterEvent(QDragEnterEvent *event) override;
virtual void dragMoveEvent(QDragMoveEvent *event) override;
virtual void dragLeaveEvent(QDragLeaveEvent *event) override;
virtual void dropEvent(QDropEvent *event) override;
public Q_SLOTS:
void resizeWidget();
void setWidget(QWidget *widget);
private:
void execEvent(void *function, void *event);
private:
QPixmap m_pixmap;
QPointer<QWidget> m_widget;
};
}

View File

@ -1,471 +0,0 @@
/*
* Copyright (c) 2021 Alex Spataru <https://github.com/alex-spataru>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "Dashboard.h"
#include "WidgetLoader.h"
#include <QApplication>
#include <Widgets/Bar.h>
#include <Widgets/GPS.h>
#include <Widgets/Plot.h>
#include <Widgets/Gauge.h>
#include <Widgets/Compass.h>
#include <Widgets/FFTPlot.h>
#include <Widgets/LEDPanel.h>
#include <Widgets/DataGroup.h>
#include <Widgets/Gyroscope.h>
#include <Widgets/MultiPlot.h>
#include <Widgets/Accelerometer.h>
#include <Misc/ThemeManager.h>
namespace UI
{
/**
* Constructor function
*/
WidgetLoader::WidgetLoader(QQuickItem *parent)
: QQuickPaintedItem(parent)
, m_index(-1)
, m_widgetVisible(false)
, m_isExternalWindow(false)
{
// Set render flags
setAntialiasing(true);
setOpaquePainting(true);
setRenderTarget(FramebufferObject);
setPerformanceHints(FastFBOResizing);
setAcceptedMouseButtons(Qt::AllButtons);
// Set item flags
setFlag(ItemHasContents, true);
setFlag(ItemIsFocusScope, true);
setFlag(ItemAcceptsInputMethod, true);
setAcceptedMouseButtons(Qt::AllButtons);
// Resize widget to fit QML item size
connect(this, &QQuickPaintedItem::widthChanged, this,
&WidgetLoader::updateWidgetSize);
connect(this, &QQuickPaintedItem::heightChanged, this,
&WidgetLoader::updateWidgetSize);
// Automatically update the widget's visibility
connect(Dashboard::getInstance(), &Dashboard::widgetVisibilityChanged, this,
&WidgetLoader::updateWidgetVisible);
}
/**
* Delete widget on class destruction
*/
WidgetLoader::~WidgetLoader()
{
if (m_widget)
delete m_widget;
}
/**
* Handle application events manually
*/
bool WidgetLoader::event(QEvent *event)
{
// Check that widget exists
if (!m_widget)
return false;
// Process focus, wheel & mouse click/release events
switch (event->type())
{
case QEvent::FocusIn:
forceActiveFocus();
return QQuickPaintedItem::event(event);
break;
case QEvent::Wheel:
processWheelEvents(static_cast<QWheelEvent *>(event));
return true;
break;
case QEvent::MouseButtonPress:
case QEvent::MouseButtonRelease:
case QEvent::MouseButtonDblClick:
case QEvent::MouseMove:
processMouseEvents(static_cast<QMouseEvent *>(event));
return true;
break;
default:
break;
}
//
// Note: mouse enter/leave events must be processed directly with
// the help of a QML MouseArea
//
return QApplication::sendEvent(m_widget, event);
}
/**
* Render the widget on the given @a painter
*/
void WidgetLoader::paint(QPainter *painter)
{
if (m_widget && painter && isVisible())
m_widget->render(painter);
}
/**
* Custom event filter to manage redraw requests
*/
bool WidgetLoader::eventFilter(QObject *watched, QEvent *event)
{
if (!m_widget)
return false;
if (watched == m_widget)
{
switch (event->type())
{
case QEvent::Paint:
case QEvent::UpdateRequest:
update();
break;
default:
break;
}
}
return QQuickPaintedItem::eventFilter(watched, event);
}
/**
* Returns the global index of the widget (index of the current widget in relation to all
* registered widgets).
*/
int WidgetLoader::widgetIndex() const
{
return m_index;
}
/**
* Returns the relative index of the widget (e.g. index of a bar widget in relation to the
* total number of bar widgets).
*/
int WidgetLoader::relativeIndex() const
{
return UI::Dashboard::getInstance()->relativeIndex(widgetIndex());
}
/**
* Returns @c true if the QML interface should display this widget.
*/
bool WidgetLoader::widgetVisible() const
{
return m_widgetVisible;
}
/**
* Returns the path of the SVG icon to use with this widget
*/
QString WidgetLoader::widgetIcon() const
{
return UI::Dashboard::getInstance()->widgetIcon(widgetIndex());
}
/**
* Returns the appropiate window title for the given widget
*/
QString WidgetLoader::widgetTitle() const
{
if (widgetIndex() >= 0)
{
auto titles = UI::Dashboard::getInstance()->widgetTitles();
if (widgetIndex() < titles.count())
return titles.at(widgetIndex());
}
return tr("Invalid");
}
/**
* If set to @c true, then the widget visibility shall be controlled
* directly by the QML interface.
*
* If set to @c false, then the widget visbility shall be controlled
* by the UI::Dashboard class via the SIGNAL/SLOT system.
*/
bool WidgetLoader::isExternalWindow() const
{
return m_isExternalWindow;
}
/**
* Returns the type of the current widget (e.g. group, plot, bar, gauge, etc...)
*/
UI::Dashboard::WidgetType WidgetLoader::widgetType() const
{
return UI::Dashboard::getInstance()->widgetType(widgetIndex());
}
/**
* Returns a pointer to the current widget
*/
QWidget* WidgetLoader::widget() const
{
return m_widget;
}
/**
* Changes the visibility & enabled status of the widget
*/
void WidgetLoader::setVisible(const bool visible)
{
if (m_widget)
m_widget->setEnabled(visible);
}
/**
* Selects & configures the appropiate widget for the given @a index
*/
void WidgetLoader::setWidgetIndex(const int index)
{
if (index < UI::Dashboard::getInstance()->totalWidgetCount() && index >= 0)
{
// Update widget index
m_index = index;
// Delete previous widget
if (m_widget)
{
delete m_widget;
m_widget = nullptr;
}
// Construct new widget
switch (widgetType())
{
case UI::Dashboard::WidgetType::Group:
m_widget = new Widgets::DataGroup(relativeIndex());
break;
case UI::Dashboard::WidgetType::MultiPlot:
m_widget = new Widgets::MultiPlot(relativeIndex());
break;
case UI::Dashboard::WidgetType::FFT:
m_widget = new Widgets::FFTPlot(relativeIndex());
break;
case UI::Dashboard::WidgetType::Plot:
m_widget = new Widgets::Plot(relativeIndex());
break;
case UI::Dashboard::WidgetType::Bar:
m_widget = new Widgets::Bar(relativeIndex());
break;
case UI::Dashboard::WidgetType::Gauge:
m_widget = new Widgets::Gauge(relativeIndex());
break;
case UI::Dashboard::WidgetType::Compass:
m_widget = new Widgets::Compass(relativeIndex());
break;
case UI::Dashboard::WidgetType::Gyroscope:
m_widget = new Widgets::Gyroscope(relativeIndex());
break;
case UI::Dashboard::WidgetType::Accelerometer:
m_widget = new Widgets::Accelerometer(relativeIndex());
break;
case UI::Dashboard::WidgetType::GPS:
m_widget = new Widgets::GPS(relativeIndex());
break;
case UI::Dashboard::WidgetType::LED:
m_widget = new Widgets::LEDPanel(relativeIndex());
break;
default:
break;
}
// Allow widget to receive events from the QML interface
if (m_widget)
{
m_widget->setEnabled(true);
m_widget->installEventFilter(this);
Q_EMIT widgetIndexChanged();
updateWidgetVisible();
}
}
}
/**
* Changes the widget visibility controller source.
*
* If set to @c true, then the widget visibility shall be controlled
* directly by the QML interface.
*
* If set to @c false, then the widget visbility shall be controlled
* by the UI::Dashboard class via the SIGNAL/SLOT system.
*/
void WidgetLoader::setIsExternalWindow(const bool isWindow)
{
m_isExternalWindow = isWindow;
Q_EMIT isExternalWindowChanged();
}
/**
* This function must be called directly by a QML MouseArea item.
* Unfortunatelly, enter/leave events cannot be processed
* directly by the @c WidgetLoader::event(QEvent *event) function.
*/
void WidgetLoader::processMouseHover(const bool containsMouse)
{
if (containsMouse)
{
QEnterEvent event(QPoint(0, 0), QPoint(0, 0), QPoint(0, 0));
processEnterEvent(&event);
}
else
{
QEvent event(QEvent::Leave);
processLeaveEvent(&event);
}
}
/**
* Resizes the widget to fit inside the QML item.
*/
void WidgetLoader::updateWidgetSize()
{
if (m_widget && width() > 0 && height() > 0)
{
m_widget->setFixedSize(width(), height());
update();
}
}
/**
* Updates the visibility status of the current widget (this function is called
* automatically by the UI::Dashboard class via signals/slots).
*/
void WidgetLoader::updateWidgetVisible()
{
bool visible = UI::Dashboard::getInstance()->widgetVisible(widgetIndex());
if (widgetVisible() != visible && !isExternalWindow())
{
m_widgetVisible = visible;
if (m_widget)
m_widget->setEnabled(visible);
Q_EMIT widgetVisibleChanged();
}
}
/**
* Lets the widget handle the mouse leave events
*/
void WidgetLoader::processLeaveEvent(QEvent *event)
{
if (!m_widget)
return;
class Hack : public QWidget
{
public:
using QWidget::leaveEvent;
};
auto hack = static_cast<Hack *>(widget());
hack->leaveEvent(event);
update();
}
/**
* Lets the widget handle the mouse enter events
*/
void WidgetLoader::processEnterEvent(QEnterEvent *event)
{
if (!m_widget)
return;
class Hack : public QWidget
{
public:
using QWidget::enterEvent;
};
auto hack = static_cast<Hack *>(widget());
hack->enterEvent(event);
update();
}
/**
* Hack: calls the appropiate protected mouse event handler function of the widget item
*/
void WidgetLoader::processMouseEvents(QMouseEvent *event)
{
if (!m_widget)
return;
class Hack : public QWidget
{
public:
using QWidget::mouseDoubleClickEvent;
using QWidget::mouseMoveEvent;
using QWidget::mousePressEvent;
using QWidget::mouseReleaseEvent;
};
auto hack = static_cast<Hack *>(widget());
switch (event->type())
{
case QEvent::MouseButtonPress:
hack->mousePressEvent(event);
break;
case QEvent::MouseMove:
hack->mouseMoveEvent(event);
break;
case QEvent::MouseButtonRelease:
hack->mouseReleaseEvent(event);
break;
case QEvent::MouseButtonDblClick:
hack->mouseDoubleClickEvent(event);
break;
default:
break;
}
update();
}
/**
* Hack: calls the appropiate protected wheel event handler function of the widget item
*/
void WidgetLoader::processWheelEvents(QWheelEvent *event)
{
if (!m_widget)
return;
class Hack : public QWidget
{
public:
using QWidget::wheelEvent;
};
static_cast<Hack *>(widget())->wheelEvent(event);
update();
}
}

View File

@ -119,6 +119,9 @@ void Accelerometer::updateData()
m_gauge.setValue(G);
setValue(QString("%1 G").arg(
QString::number(G, 'f', UI::Dashboard::getInstance()->precision())));
// Repaint widget
Q_EMIT updated();
}
}
}

View File

@ -67,8 +67,7 @@ Bar::Bar(const int index)
m_thermo.setBorderWidth(1);
m_thermo.setFillBrush(QBrush(QColor(color)));
// Lazy widgets, get initial properties from dataset
#ifdef LAZY_WIDGETS
// Get initial properties from dataset
const auto dataset = UI::Dashboard::getInstance()->getBar(m_index);
if (dataset)
{
@ -76,7 +75,6 @@ Bar::Bar(const int index)
m_thermo.setAlarmEnabled(m_thermo.alarmLevel() > 0);
m_thermo.setScale(dataset->min(), dataset->max());
}
#endif
// Set widget pointer & disable auto resize
setWidget(&m_thermo, Qt::AlignHCenter, false);
@ -103,16 +101,14 @@ void Bar::updateData()
const auto dataset = UI::Dashboard::getInstance()->getBar(m_index);
if (dataset)
{
#ifndef LAZY_WIDGETS
m_thermo.setAlarmLevel(dataset->alarm());
m_thermo.setAlarmEnabled(m_thermo.alarmLevel() > 0);
m_thermo.setScale(dataset->min(), dataset->max());
#endif
const auto value = dataset->value().toDouble();
m_thermo.setValue(value);
setValue(QString("%1 %2").arg(
QString::number(value, 'f', UI::Dashboard::getInstance()->precision()),
dataset->units()));
// Repaint widget
Q_EMIT updated();
}
}

View File

@ -91,6 +91,8 @@ void BaseWidget::setWidget(QWidget *widget, const Qt::Alignment &alignment,
m_layout.setContentsMargins(24, 24, 24, 24);
setLayout(&m_layout);
}
Q_EMIT updated();
}
void BaseWidget::resizeEvent(QResizeEvent *event)
@ -139,8 +141,6 @@ void BaseWidget::resizeEvent(QResizeEvent *event)
// Accept event
event->accept();
// Emit resize signal
Q_EMIT resized();
}
}

View File

@ -26,9 +26,11 @@
#include <QWidget>
#include <QHBoxLayout>
#include <UI/DashboardWidget.h>
namespace Widgets
{
class BaseWidget : public QWidget
class BaseWidget : public DashboardWidgetBase
{
Q_OBJECT

View File

@ -101,6 +101,9 @@ void Compass::update()
text.prepend("0");
setValue(text);
// Repaint widget
Q_EMIT updated();
}
}
}

View File

@ -24,13 +24,22 @@
#include "UI/Dashboard.h"
#include "Misc/ThemeManager.h"
#include <QMouseEvent>
#include <QWheelEvent>
#include <QResizeEvent>
#include <QRegularExpression>
namespace Widgets
{
#define EXEC_EVENT(pointer, function, event) \
if (pointer) \
{ \
class PwnedWidget : public QScrollArea \
{ \
public: \
using QScrollArea::function; \
}; \
static_cast<PwnedWidget *>(pointer)->function(event); \
Q_EMIT updated(); \
}
/**
* Generates the user interface elements & layout
@ -109,10 +118,7 @@ DataGroup::DataGroup(const int index)
units->setStyleSheet(unitsQSS);
dicon->setStyleSheet(iconsQSS);
// Configure elide modes
// Lazy widgets, set label initial data
#ifdef LAZY_WIDGETS
// Set label initial data
auto set = group->getDataset(dataset);
if (set)
{
@ -120,7 +126,6 @@ DataGroup::DataGroup(const int index)
if (!set->units().isEmpty())
units->setText(QString("[%1]").arg(set->units()));
}
#endif
// Set icon text
dicon->setText("");
@ -150,7 +155,7 @@ DataGroup::DataGroup(const int index)
// Configure main layout
m_mainLayout = new QVBoxLayout(this);
m_mainLayout->addWidget(m_scrollArea);
m_mainLayout->setContentsMargins(12, 0, 0, 12);
m_mainLayout->setContentsMargins(0, 0, 0, 0);
setLayout(m_mainLayout);
// React to dashboard events
@ -208,11 +213,6 @@ void DataGroup::updateData()
dataset = group->getDataset(i);
if (dataset)
{
#ifndef LAZY_WIDGETS
m_titles.at(i)->setText(set->title());
if (!set->units().isEmpty())
m_units.at(i)->setText(QString("[%1]").arg(set->units()));
#endif
// Get dataset value
auto value = dataset->value();
@ -225,6 +225,9 @@ void DataGroup::updateData()
m_values.at(i)->setText(value + " ");
}
}
// Repaint widget
Q_EMIT updated();
}
/**
@ -253,61 +256,26 @@ void DataGroup::resizeEvent(QResizeEvent *event)
void DataGroup::wheelEvent(QWheelEvent *event)
{
class Hack : public QScrollArea
{
public:
using QWidget::wheelEvent;
};
auto hack = static_cast<Hack *>(m_scrollArea);
hack->wheelEvent(event);
EXEC_EVENT(m_scrollArea, wheelEvent, event);
}
void DataGroup::mouseMoveEvent(QMouseEvent *event)
{
class Hack : public QScrollArea
{
public:
using QWidget::mouseMoveEvent;
};
auto hack = static_cast<Hack *>(m_scrollArea);
hack->mouseMoveEvent(event);
EXEC_EVENT(m_scrollArea, mouseMoveEvent, event);
}
void DataGroup::mousePressEvent(QMouseEvent *event)
{
class Hack : public QScrollArea
{
public:
using QWidget::mousePressEvent;
};
auto hack = static_cast<Hack *>(m_scrollArea);
hack->mousePressEvent(event);
EXEC_EVENT(m_scrollArea, mousePressEvent, event);
}
void DataGroup::mouseReleaseEvent(QMouseEvent *event)
{
class Hack : public QScrollArea
{
public:
using QWidget::mouseReleaseEvent;
};
auto hack = static_cast<Hack *>(m_scrollArea);
hack->mouseReleaseEvent(event);
EXEC_EVENT(m_scrollArea, mouseReleaseEvent, event);
}
void DataGroup::mouseDoubleClickEvent(QMouseEvent *event)
{
class Hack : public QScrollArea
{
public:
using QWidget::mouseDoubleClickEvent;
};
auto hack = static_cast<Hack *>(m_scrollArea);
hack->mouseDoubleClickEvent(event);
EXEC_EVENT(m_scrollArea, mouseDoubleClickEvent, event);
}
}

View File

@ -22,16 +22,16 @@
#pragma once
#include <QWidget>
#include <QGridLayout>
#include <QVBoxLayout>
#include <QScrollArea>
#include <UI/DashboardWidget.h>
#include "Common/ElidedLabel.h"
namespace Widgets
{
class DataGroup : public QWidget
class DataGroup : public DashboardWidgetBase
{
Q_OBJECT

View File

@ -173,6 +173,9 @@ void FFTPlot::updateData()
m_transformer.rescale(m_fft);
m_curve.setSamples(m_fft, m_size);
m_plot.replot();
// Repaint widget
Q_EMIT updated();
}
}
}

View File

@ -27,12 +27,13 @@
#include <QVBoxLayout>
#include <QwtPlotCurve>
#include <QwtScaleEngine>
#include <UI/DashboardWidget.h>
#include "qfouriertransformer.h"
namespace Widgets
{
class FFTPlot : public QWidget
class FFTPlot : public DashboardWidgetBase
{
Q_OBJECT

View File

@ -84,7 +84,7 @@ GPS::GPS(const int index)
m_mapControl.setFrameShadow(QFrame::Plain);
m_mapControl.setFrameShape(QFrame::NoFrame);
m_mapControl.setMouseMode(qmapcontrol::MapControl::None);
m_mapControl.resize(QSize(width() - 25, height() - 33 - m_titleWidget.height()));
m_mapControl.resize(QSize(width() - 26, height() - 34 - m_titleWidget.height()));
qmapcontrol::TileMapAdapter *mapadapter = new qmapcontrol::OSMMapAdapter();
qmapcontrol::Layer *l = new qmapcontrol::Layer("Custom Layer", mapadapter,
qmapcontrol::Layer::MapLayer);
@ -156,6 +156,9 @@ void GPS::updateData()
m_label->setText(QString("<u>POS:</u><i> %1,%2</i>&nbsp;<u>ALT:</u><i> %3 m</i>")
.arg(latstr, lonstr, altstr));
// clang-format on
// Repaint widget
Q_EMIT updated();
}
/**
@ -165,7 +168,7 @@ void GPS::resizeEvent(QResizeEvent *event)
{
const auto width = event->size().width();
const auto height = event->size().height();
m_mapControl.resize(QSize(width - 25, height - 33 - m_titleWidget.height()));
m_mapControl.resize(QSize(width - 26, height - 34 - m_titleWidget.height()));
event->accept();
}

View File

@ -23,18 +23,18 @@
#pragma once
#include <QLabel>
#include <QWidget>
#include <QPushButton>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <mapcontrol.h>
#include <UI/DashboardWidget.h>
class QNetworkReply;
namespace Widgets
{
class GPS : public QWidget
class GPS : public DashboardWidgetBase
{
Q_OBJECT

View File

@ -57,11 +57,9 @@ Gauge::Gauge(const int index)
m_gauge.setFont(dash->monoFont());
// Set gauge scale
#ifdef LAZY_WIDGETS
auto dataset = dash->getGauge(m_index);
if (dataset)
m_gauge.setScale(dataset->min(), dataset->max());
#endif
// Set gauge palette
QPalette palette;
@ -93,14 +91,13 @@ void Gauge::updateData()
const auto dataset = UI::Dashboard::getInstance()->getGauge(m_index);
if (dataset)
{
#ifndef LAZY_WIDGETS
m_gauge.setScale(dataset->min(), dataset->max());
#endif
const auto value = dataset->value().toDouble();
m_gauge.setValue(dataset->value().toDouble());
setValue(QString("%1 %2").arg(
QString::number(value, 'f', UI::Dashboard::getInstance()->precision()),
dataset->units()));
Q_EMIT updated();
}
}
}

View File

@ -105,6 +105,8 @@ void Gyroscope::updateData()
m_gauge.setValue(pitch);
m_gauge.setGradient(roll / 360.0);
Q_EMIT updated();
}
}

View File

@ -24,8 +24,6 @@
#include "UI/Dashboard.h"
#include "Misc/ThemeManager.h"
#include <QMouseEvent>
#include <QWheelEvent>
#include <QResizeEvent>
namespace Widgets
@ -172,15 +170,15 @@ void LEDPanel::updateData()
dataset = group->getDataset(i);
if (dataset)
{
#ifndef LAZY_WIDGETS
m_titles.at(i)->setText(set->title());
#endif
// Get dataset value (we compare with 0.1 for low voltages)
const auto value = dataset->value().toDouble();
if (qAbs(value) < 0.10)
m_leds.at(i)->off();
else
m_leds.at(i)->on();
// Repaint widget
Q_EMIT updated();
}
}
}
@ -203,64 +201,4 @@ void LEDPanel::resizeEvent(QResizeEvent *event)
event->accept();
}
void LEDPanel::wheelEvent(QWheelEvent *event)
{
class Hack : public QScrollArea
{
public:
using QWidget::wheelEvent;
};
auto hack = static_cast<Hack *>(m_scrollArea);
hack->wheelEvent(event);
}
void LEDPanel::mouseMoveEvent(QMouseEvent *event)
{
class Hack : public QScrollArea
{
public:
using QWidget::mouseMoveEvent;
};
auto hack = static_cast<Hack *>(m_scrollArea);
hack->mouseMoveEvent(event);
}
void LEDPanel::mousePressEvent(QMouseEvent *event)
{
class Hack : public QScrollArea
{
public:
using QWidget::mousePressEvent;
};
auto hack = static_cast<Hack *>(m_scrollArea);
hack->mousePressEvent(event);
}
void LEDPanel::mouseReleaseEvent(QMouseEvent *event)
{
class Hack : public QScrollArea
{
public:
using QWidget::mouseReleaseEvent;
};
auto hack = static_cast<Hack *>(m_scrollArea);
hack->mouseReleaseEvent(event);
}
void LEDPanel::mouseDoubleClickEvent(QMouseEvent *event)
{
class Hack : public QScrollArea
{
public:
using QWidget::mouseDoubleClickEvent;
};
auto hack = static_cast<Hack *>(m_scrollArea);
hack->mouseDoubleClickEvent(event);
}
}

View File

@ -23,16 +23,17 @@
#pragma once
#include <QLabel>
#include <QWidget>
#include <QGridLayout>
#include <QVBoxLayout>
#include <QScrollArea>
#include <UI/DashboardWidget.h>
#include "Common/KLed.h"
namespace Widgets
{
class LEDPanel : public QWidget
class LEDPanel : public DashboardWidgetBase
{
Q_OBJECT
@ -45,11 +46,6 @@ private Q_SLOTS:
protected:
void resizeEvent(QResizeEvent *event);
void wheelEvent(QWheelEvent *event);
void mouseMoveEvent(QMouseEvent *event);
void mousePressEvent(QMouseEvent *event);
void mouseReleaseEvent(QMouseEvent *event);
void mouseDoubleClickEvent(QMouseEvent *event);
private:
int m_index;

View File

@ -179,7 +179,10 @@ void MultiPlot::updateData()
// Plot widget again
if (isEnabled())
{
m_plot.replot();
Q_EMIT updated();
}
}
/**
@ -205,5 +208,8 @@ void MultiPlot::updateRange()
for (int i = 0; i < group->datasetCount(); ++i)
if (m_curves.count() > i)
m_curves.at(i)->setSamples(*dash->xPlotValues(), m_yData[i]);
// Repaint widget
Q_EMIT updated();
}
}

View File

@ -23,18 +23,18 @@
#pragma once
#include <QwtPlot>
#include <QWidget>
#include <QwtLegend>
#include <QComboBox>
#include <QVBoxLayout>
#include <QwtPlotCurve>
#include <QwtScaleEngine>
#include "UI/Dashboard.h"
#include <UI/Dashboard.h>
#include <UI/DashboardWidget.h>
namespace Widgets
{
class MultiPlot : public QWidget
class MultiPlot : public DashboardWidgetBase
{
Q_OBJECT

View File

@ -205,6 +205,9 @@ void Plot::updateData()
// Replot graph
m_curve.setSamples(plotData->at(m_index));
m_plot.replot();
// Repaint widget
Q_EMIT updated();
}
}
@ -225,5 +228,8 @@ void Plot::updateRange()
// Redraw graph
m_curve.setSamples(*dash->xPlotValues(), tempYData);
m_plot.replot();
// Repaint widget
Q_EMIT updated();
}
}

View File

@ -27,10 +27,11 @@
#include <QVBoxLayout>
#include <QwtPlotCurve>
#include <QwtScaleEngine>
#include <UI/DashboardWidget.h>
namespace Widgets
{
class Plot : public QWidget
class Plot : public DashboardWidgetBase
{
Q_OBJECT

View File

@ -22,7 +22,6 @@
#include <QtMath>
#include <QScrollBar>
#include <QApplication>
#include <IO/Console.h>
#include <Misc/ThemeManager.h>
@ -35,53 +34,22 @@ namespace Widgets
// QML PlainTextEdit implementation
//----------------------------------------------------------------------------------------
/*
* NOTE: most of the Doxygen documentation comments where heavily based from the following
* URL https://doc.qt.io/qt-5/qplaintextedit.html. In some cases the comments are a
* simple copy-paste job. I am lazy and the Qt documentation is very good IMO.
*
* This class works by initializing a QPlainTextEdit widget, rendering it into the
* the painter of a QML item and handling keyboard/mouse events.
*
* The rest of the functions are just a wrapper around the functions of the
* QPlainTextEdit widget for increased QML-friendliness.
*/
/**
* Constructor function
*/
Terminal::Terminal(QQuickItem *parent)
: QQuickPaintedItem(parent)
: UI::DeclarativeWidget(parent)
, m_autoscroll(true)
, m_emulateVt100(false)
, m_copyAvailable(false)
, m_textEdit(new QPlainTextEdit)
{
// Set render flags
setAntialiasing(true);
setOpaquePainting(true);
setRenderTarget(FramebufferObject);
setPerformanceHints(FastFBOResizing);
setAcceptedMouseButtons(Qt::AllButtons);
m_escapeCodeHandler.setTextEdit(textEdit());
// Set item flags
setFlag(ItemHasContents, true);
setFlag(ItemIsFocusScope, true);
setFlag(ItemAcceptsInputMethod, true);
setAcceptedMouseButtons(Qt::AllButtons);
// Configure text edit widget
setScrollbarWidth(14);
textEdit()->installEventFilter(this);
// Set the QML item's implicit size
const auto hint = textEdit()->sizeHint();
setImplicitSize(hint.width(), hint.height());
// Set widget
setWidget(&m_textEdit);
// Setup default options
textEdit()->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
textEdit()->setSizeAdjustPolicy(QPlainTextEdit::AdjustToContents);
setScrollbarWidth(14);
m_textEdit.setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
m_textEdit.setSizeAdjustPolicy(QPlainTextEdit::AdjustToContents);
// Set widget palette
QPalette palette;
@ -95,90 +63,14 @@ Terminal::Terminal(QQuickItem *parent)
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
palette.setColor(QPalette::PlaceholderText, theme->consolePlaceholderText());
#endif
m_textEdit->setPalette(palette);
// Resize QPlainTextEdit to fit QML item
connect(this, &QQuickPaintedItem::widthChanged, this, &Terminal::updateWidgetSize);
connect(this, &QQuickPaintedItem::heightChanged, this, &Terminal::updateWidgetSize);
m_textEdit.setPalette(palette);
// Connect console signals (doing this on QML uses about 50% of UI thread time)
const auto console = IO::Console::getInstance();
connect(console, &IO::Console::stringReceived, this, &Terminal::insertText);
// React to widget events
connect(textEdit(), SIGNAL(copyAvailable(bool)), this, SLOT(setCopyAvailable(bool)));
// Draw widget
QTimer::singleShot(0, this, SLOT(update()));
}
/**
* Destructor function
*/
Terminal::~Terminal()
{
delete m_textEdit;
}
/**
* Handle application events manually
*/
bool Terminal::event(QEvent *event)
{
switch (event->type())
{
case QEvent::FocusIn:
forceActiveFocus();
return QQuickPaintedItem::event(event);
break;
case QEvent::Wheel:
processWheelEvents(static_cast<QWheelEvent *>(event));
return true;
break;
case QEvent::MouseButtonPress:
case QEvent::MouseButtonRelease:
case QEvent::MouseButtonDblClick:
case QEvent::MouseMove:
processMouseEvents(static_cast<QMouseEvent *>(event));
return true;
break;
default:
break;
}
return QApplication::sendEvent(textEdit(), event);
}
/**
* Render the text edit on the given @a painter
*/
void Terminal::paint(QPainter *painter)
{
if (m_textEdit && painter)
textEdit()->render(painter);
}
/**
* Custom event filter to manage redraw requests
*/
bool Terminal::eventFilter(QObject *watched, QEvent *event)
{
Q_ASSERT(m_textEdit);
if (watched == textEdit())
{
switch (event->type())
{
case QEvent::Paint:
case QEvent::UpdateRequest:
update();
break;
default:
break;
}
}
return QQuickPaintedItem::eventFilter(watched, event);
connect(&m_textEdit, SIGNAL(copyAvailable(bool)), this, SLOT(setCopyAvailable(bool)));
}
/**
@ -186,7 +78,7 @@ bool Terminal::eventFilter(QObject *watched, QEvent *event)
*/
QFont Terminal::font() const
{
return textEdit()->font();
return m_textEdit.font();
}
/**
@ -194,7 +86,7 @@ QFont Terminal::font() const
*/
QString Terminal::text() const
{
return textEdit()->toPlainText();
return m_textEdit.toPlainText();
}
/**
@ -202,7 +94,7 @@ QString Terminal::text() const
*/
bool Terminal::empty() const
{
return textEdit()->document()->isEmpty();
return m_textEdit.document()->isEmpty();
}
/**
@ -210,7 +102,7 @@ bool Terminal::empty() const
*/
bool Terminal::readOnly() const
{
return textEdit()->isReadOnly();
return m_textEdit.isReadOnly();
}
/**
@ -227,7 +119,7 @@ bool Terminal::autoscroll() const
*/
QPalette Terminal::palette() const
{
return textEdit()->palette();
return m_textEdit.palette();
}
/**
@ -236,7 +128,7 @@ QPalette Terminal::palette() const
*/
int Terminal::wordWrapMode() const
{
return static_cast<int>(textEdit()->wordWrapMode());
return static_cast<int>(m_textEdit.wordWrapMode());
}
/**
@ -244,7 +136,7 @@ int Terminal::wordWrapMode() const
*/
int Terminal::scrollbarWidth() const
{
return textEdit()->verticalScrollBar()->width();
return m_textEdit.verticalScrollBar()->width();
}
/**
@ -261,7 +153,7 @@ bool Terminal::copyAvailable() const
*/
bool Terminal::widgetEnabled() const
{
return textEdit()->isEnabled();
return m_textEdit.isEnabled();
}
/**
@ -272,7 +164,7 @@ bool Terminal::widgetEnabled() const
*/
bool Terminal::centerOnScroll() const
{
return textEdit()->centerOnScroll();
return m_textEdit.centerOnScroll();
}
/**
@ -291,7 +183,7 @@ bool Terminal::vt100emulation() const
*/
bool Terminal::undoRedoEnabled() const
{
return textEdit()->isUndoRedoEnabled();
return m_textEdit.isUndoRedoEnabled();
}
/**
@ -306,7 +198,7 @@ bool Terminal::undoRedoEnabled() const
*/
int Terminal::maximumBlockCount() const
{
return textEdit()->maximumBlockCount();
return m_textEdit.maximumBlockCount();
}
/**
@ -317,7 +209,7 @@ int Terminal::maximumBlockCount() const
*/
QString Terminal::placeholderText() const
{
return textEdit()->placeholderText();
return m_textEdit.placeholderText();
}
/**
@ -325,15 +217,7 @@ QString Terminal::placeholderText() const
*/
QTextDocument *Terminal::document() const
{
return textEdit()->document();
}
/**
* Returns the pointer to the text edit object
*/
QPlainTextEdit *Terminal::textEdit() const
{
return m_textEdit;
return m_textEdit.document();
}
/**
@ -341,7 +225,7 @@ QPlainTextEdit *Terminal::textEdit() const
*/
void Terminal::copy()
{
textEdit()->copy();
m_textEdit.copy();
}
/**
@ -349,7 +233,7 @@ void Terminal::copy()
*/
void Terminal::clear()
{
textEdit()->clear();
m_textEdit.clear();
updateScrollbarVisibility();
update();
@ -361,7 +245,7 @@ void Terminal::clear()
*/
void Terminal::selectAll()
{
textEdit()->selectAll();
m_textEdit.selectAll();
update();
}
@ -370,9 +254,9 @@ void Terminal::selectAll()
*/
void Terminal::clearSelection()
{
auto cursor = QTextCursor(textEdit()->document());
auto cursor = QTextCursor(m_textEdit.document());
cursor.clearSelection();
textEdit()->setTextCursor(cursor);
m_textEdit.setTextCursor(cursor);
updateScrollbarVisibility();
update();
}
@ -385,7 +269,7 @@ void Terminal::clearSelection()
*/
void Terminal::setReadOnly(const bool ro)
{
textEdit()->setReadOnly(ro);
m_textEdit.setReadOnly(ro);
update();
Q_EMIT readOnlyChanged();
@ -396,7 +280,7 @@ void Terminal::setReadOnly(const bool ro)
*/
void Terminal::setFont(const QFont &font)
{
textEdit()->setFont(font);
m_textEdit.setFont(font);
updateScrollbarVisibility();
update();
@ -411,7 +295,7 @@ void Terminal::setFont(const QFont &font)
*/
void Terminal::append(const QString &text)
{
textEdit()->appendPlainText(text);
m_textEdit.appendPlainText(text);
updateScrollbarVisibility();
if (autoscroll())
@ -429,7 +313,7 @@ void Terminal::append(const QString &text)
*/
void Terminal::setText(const QString &text)
{
textEdit()->setPlainText(text);
m_textEdit.setPlainText(text);
updateScrollbarVisibility();
if (autoscroll())
@ -444,7 +328,7 @@ void Terminal::setText(const QString &text)
*/
void Terminal::setScrollbarWidth(const int width)
{
auto bar = textEdit()->verticalScrollBar();
auto bar = m_textEdit.verticalScrollBar();
bar->setFixedWidth(width);
update();
@ -456,7 +340,7 @@ void Terminal::setScrollbarWidth(const int width)
*/
void Terminal::setPalette(const QPalette &palette)
{
textEdit()->setPalette(palette);
m_textEdit.setPalette(palette);
update();
Q_EMIT colorPaletteChanged();
@ -467,7 +351,7 @@ void Terminal::setPalette(const QPalette &palette)
*/
void Terminal::setWidgetEnabled(const bool enabled)
{
textEdit()->setEnabled(enabled);
m_textEdit.setEnabled(enabled);
update();
Q_EMIT widgetEnabledChanged();
@ -512,7 +396,7 @@ void Terminal::insertText(const QString &text)
*/
void Terminal::setWordWrapMode(const int mode)
{
textEdit()->setWordWrapMode(static_cast<QTextOption::WrapMode>(mode));
m_textEdit.setWordWrapMode(static_cast<QTextOption::WrapMode>(mode));
updateScrollbarVisibility();
update();
@ -527,7 +411,7 @@ void Terminal::setWordWrapMode(const int mode)
*/
void Terminal::setCenterOnScroll(const bool enabled)
{
textEdit()->setCenterOnScroll(enabled);
m_textEdit.setCenterOnScroll(enabled);
update();
Q_EMIT centerOnScrollChanged();
@ -549,7 +433,7 @@ void Terminal::setVt100Emulation(const bool enabled)
*/
void Terminal::setUndoRedoEnabled(const bool enabled)
{
textEdit()->setUndoRedoEnabled(enabled);
m_textEdit.setUndoRedoEnabled(enabled);
update();
Q_EMIT undoRedoEnabledChanged();
@ -561,7 +445,7 @@ void Terminal::setUndoRedoEnabled(const bool enabled)
*/
void Terminal::setPlaceholderText(const QString &text)
{
textEdit()->setPlaceholderText(text);
m_textEdit.setPlaceholderText(text);
update();
Q_EMIT placeholderTextChanged();
@ -573,9 +457,9 @@ void Terminal::setPlaceholderText(const QString &text)
void Terminal::scrollToBottom(const bool repaint)
{
// Get scrollbar pointer, calculate line count & visible text lines
auto *bar = textEdit()->verticalScrollBar();
auto lineCount = textEdit()->document()->blockCount();
auto visibleLines = qRound(height() / textEdit()->fontMetrics().height());
auto *bar = m_textEdit.verticalScrollBar();
auto lineCount = m_textEdit.document()->blockCount();
auto visibleLines = qRound(height() / m_textEdit.fontMetrics().height());
// Abort operation if control is not visible
if (visibleLines <= 0)
@ -606,38 +490,28 @@ void Terminal::scrollToBottom(const bool repaint)
*/
void Terminal::setMaximumBlockCount(const int maxBlockCount)
{
textEdit()->setMaximumBlockCount(maxBlockCount);
m_textEdit.setMaximumBlockCount(maxBlockCount);
update();
Q_EMIT maximumBlockCountChanged();
}
/**
* Resizes the text editor widget to fit inside the QML item.
*/
void Terminal::updateWidgetSize()
{
textEdit()->setFixedSize(width(), height());
updateScrollbarVisibility();
update();
}
/**
* Hides or shows the scrollbar
*/
void Terminal::updateScrollbarVisibility()
{
// Get current line count & visible lines
auto lineCount = textEdit()->document()->blockCount();
auto visibleLines = qCeil(height() / textEdit()->fontMetrics().height());
auto lineCount = m_textEdit.document()->blockCount();
auto visibleLines = qCeil(height() / m_textEdit.fontMetrics().height());
// Autoscroll enabled or text content is less than widget height
if (autoscroll() || visibleLines >= lineCount)
textEdit()->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
m_textEdit.setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
// Show the scrollbar if the text content is greater than the widget height
else
textEdit()->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
m_textEdit.setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
}
/**
@ -661,7 +535,7 @@ void Terminal::addText(const QString &text, const bool enableVt100)
textToInsert = vt100Processing(text);
// Add text at the end of the text document
QTextCursor cursor(textEdit()->document());
QTextCursor cursor(m_textEdit.document());
cursor.beginEditBlock();
cursor.movePosition(QTextCursor::End);
cursor.insertText(textToInsert);
@ -677,89 +551,6 @@ void Terminal::addText(const QString &text, const bool enableVt100)
Q_EMIT textChanged();
}
/**
* Hack: call the appropiate protected mouse event handler function of the QPlainTextEdit
* item depending on event type
*/
void Terminal::processMouseEvents(QMouseEvent *event)
{
// Subclass QPlainTextEdit so that we can call protected functions
class Hack : public QPlainTextEdit
{
public:
using QPlainTextEdit::mouseDoubleClickEvent;
using QPlainTextEdit::mouseMoveEvent;
using QPlainTextEdit::mousePressEvent;
using QPlainTextEdit::mouseReleaseEvent;
};
// Call appropiate function
auto hack = static_cast<Hack *>(textEdit());
switch (event->type())
{
case QEvent::MouseButtonPress:
hack->mousePressEvent(event);
break;
case QEvent::MouseMove:
hack->mouseMoveEvent(event);
break;
case QEvent::MouseButtonRelease:
hack->mouseReleaseEvent(event);
break;
case QEvent::MouseButtonDblClick:
hack->mouseDoubleClickEvent(event);
break;
default:
break;
}
}
/**
* Hack: call the protected wheel event handler function of the QPlainTextEdit item
*/
void Terminal::processWheelEvents(QWheelEvent *event)
{
// Subclass QPlainTextEdit so that we can call protected functions
class Hack : public QPlainTextEdit
{
public:
using QPlainTextEdit::wheelEvent;
};
// Call wheel event function only if linecount is larget than text height
auto lineCount = textEdit()->document()->blockCount();
auto visibleLines = qCeil(height() / textEdit()->fontMetrics().height());
if (lineCount > visibleLines)
{
// Call event
static_cast<Hack *>(textEdit())->wheelEvent(event);
// Disable autoscroll if we are scrolling upwards
if (autoscroll())
{
const auto delta = event->angleDelta();
const auto deltaY = delta.y();
if (deltaY > 0)
{
setAutoscroll(false);
update();
}
}
// Enable autoscroll if scrolling to bottom
else
{
const auto bar = textEdit()->verticalScrollBar();
if (bar->value() >= bar->maximum())
{
setAutoscroll(true);
update();
}
}
}
}
/**
* Processes the given @a data to remove the escape sequences from the text using code
* from Qt Creator output terminal. Check the next code block for more info.
@ -768,10 +559,10 @@ QString Terminal::vt100Processing(const QString &data)
{
auto formattedText = m_escapeCodeHandler.parseText(FormattedText(data));
const QString cleanLine = std::accumulate(
formattedText.begin(), formattedText.end(), QString(),
[](const FormattedText &t1, const FormattedText &t2) -> QString {
return t1.text + t2.text;
});
formattedText.begin(), formattedText.end(), QString(),
[](const FormattedText &t1, const FormattedText &t2) -> QString {
return t1.text + t2.text;
});
m_escapeCodeHandler.endFormatScope();
return cleanLine;
@ -785,12 +576,12 @@ QString Terminal::vt100Processing(const QString &data)
#define QTC_ASSERT(cond, action) \
if (Q_LIKELY(cond)) { } \
else \
{ \
action; \
} \
{ \
action; \
} \
do \
{ \
} while (0)
{ \
} while (0)
static QColor ansiColor(uint code)
{
@ -885,28 +676,28 @@ QVector<FormattedText> AnsiEscapeCodeHandler::parseText(const FormattedText &inp
{
switch (strippedText.at(1).toLatin1())
{
case '\\': // Unexpected terminator sequence.
Q_FALLTHROUGH();
case 'N':
case 'O': // Ignore unsupported single-character sequences.
strippedText.remove(0, 2);
break;
case ']':
m_alternateTerminator = QChar(7);
Q_FALLTHROUGH();
case 'P':
case 'X':
case '^':
case '_':
strippedText.remove(0, 2);
m_waitingForTerminator = true;
break;
default:
// not a control sequence
m_pendingText.clear();
outputData << FormattedText(strippedText.left(1), charFormat);
strippedText.remove(0, 1);
continue;
case '\\': // Unexpected terminator sequence.
Q_FALLTHROUGH();
case 'N':
case 'O': // Ignore unsupported single-character sequences.
strippedText.remove(0, 2);
break;
case ']':
m_alternateTerminator = QChar(7);
Q_FALLTHROUGH();
case 'P':
case 'X':
case '^':
case '_':
strippedText.remove(0, 2);
m_waitingForTerminator = true;
break;
default:
// not a control sequence
m_pendingText.clear();
outputData << FormattedText(strippedText.left(1), charFormat);
strippedText.remove(0, 1);
continue;
}
break;
}
@ -914,7 +705,8 @@ QVector<FormattedText> AnsiEscapeCodeHandler::parseText(const FormattedText &inp
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
m_pendingText += strippedText.midRef(0, escape.length());
#else
m_pendingText += QStringView{strippedText}.mid(0, escape.length()).toString();
m_pendingText
+= QStringView { strippedText }.mid(0, escape.length()).toString();
#endif
strippedText.remove(0, escape.length());
@ -968,9 +760,9 @@ QVector<FormattedText> AnsiEscapeCodeHandler::parseText(const FormattedText &inp
strNumber.clear();
}
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
m_pendingText += strippedText.midRef(0, 1);
m_pendingText += strippedText.midRef(0, 1);
#else
m_pendingText += QStringView{strippedText}.mid(0, 1).toString();
m_pendingText += QStringView { strippedText }.mid(0, 1).toString();
#endif
strippedText.remove(0, 1);
}
@ -1012,89 +804,89 @@ QVector<FormattedText> AnsiEscapeCodeHandler::parseText(const FormattedText &inp
{
switch (code)
{
case ResetFormat:
charFormat = input.format;
endFormatScope();
break;
case BoldText:
charFormat.setFontWeight(QFont::Bold);
setFormatScope(charFormat);
break;
case DefaultTextColor:
charFormat.setForeground(input.format.foreground());
setFormatScope(charFormat);
break;
case DefaultBackgroundColor:
charFormat.setBackground(input.format.background());
setFormatScope(charFormat);
break;
case RgbTextColor:
case RgbBackgroundColor:
// See http://en.wikipedia.org/wiki/ANSI_escape_code#Colors
if (++i >= numbers.size())
case ResetFormat:
charFormat = input.format;
endFormatScope();
break;
switch (numbers.at(i).toInt())
{
case 2:
// RGB set with format: 38;2;<r>;<g>;<b>
if ((i + 3) < numbers.size())
{
(code == RgbTextColor)
? charFormat.setForeground(
QColor(numbers.at(i + 1).toInt(),
numbers.at(i + 2).toInt(),
numbers.at(i + 3).toInt()))
: charFormat.setBackground(
QColor(numbers.at(i + 1).toInt(),
numbers.at(i + 2).toInt(),
numbers.at(i + 3).toInt()));
setFormatScope(charFormat);
}
i += 3;
break;
case 5:
// 256 color mode with format: 38;5;<i>
uint index = numbers.at(i + 1).toUInt();
QColor color;
if (index < 8)
{
// The first 8 colors are standard low-intensity
// ANSI colors.
color = ansiColor(index);
}
else if (index < 16)
{
// The next 8 colors are standard high-intensity
// ANSI colors.
color = ansiColor(index - 8).lighter(150);
}
else if (index < 232)
{
// The next 216 colors are a 6x6x6 RGB cube.
uint o = index - 16;
color = QColor((o / 36) * 51, ((o / 6) % 6) * 51,
(o % 6) * 51);
}
else
{
// The last 24 colors are a greyscale gradient.
int grey = int((index - 232) * 11);
color = QColor(grey, grey, grey);
}
if (code == RgbTextColor)
charFormat.setForeground(color);
else
charFormat.setBackground(color);
case BoldText:
charFormat.setFontWeight(QFont::Bold);
setFormatScope(charFormat);
++i;
break;
}
break;
default:
break;
case DefaultTextColor:
charFormat.setForeground(input.format.foreground());
setFormatScope(charFormat);
break;
case DefaultBackgroundColor:
charFormat.setBackground(input.format.background());
setFormatScope(charFormat);
break;
case RgbTextColor:
case RgbBackgroundColor:
// See http://en.wikipedia.org/wiki/ANSI_escape_code#Colors
if (++i >= numbers.size())
break;
switch (numbers.at(i).toInt())
{
case 2:
// RGB set with format: 38;2;<r>;<g>;<b>
if ((i + 3) < numbers.size())
{
(code == RgbTextColor)
? charFormat.setForeground(
QColor(numbers.at(i + 1).toInt(),
numbers.at(i + 2).toInt(),
numbers.at(i + 3).toInt()))
: charFormat.setBackground(
QColor(numbers.at(i + 1).toInt(),
numbers.at(i + 2).toInt(),
numbers.at(i + 3).toInt()));
setFormatScope(charFormat);
}
i += 3;
break;
case 5:
// 256 color mode with format: 38;5;<i>
uint index = numbers.at(i + 1).toUInt();
QColor color;
if (index < 8)
{
// The first 8 colors are standard low-intensity
// ANSI colors.
color = ansiColor(index);
}
else if (index < 16)
{
// The next 8 colors are standard high-intensity
// ANSI colors.
color = ansiColor(index - 8).lighter(150);
}
else if (index < 232)
{
// The next 216 colors are a 6x6x6 RGB cube.
uint o = index - 16;
color = QColor((o / 36) * 51, ((o / 6) % 6) * 51,
(o % 6) * 51);
}
else
{
// The last 24 colors are a greyscale gradient.
int grey = int((index - 232) * 11);
color = QColor(grey, grey, grey);
}
if (code == RgbTextColor)
charFormat.setForeground(color);
else
charFormat.setBackground(color);
setFormatScope(charFormat);
++i;
break;
}
break;
default:
break;
}
}
}

View File

@ -22,9 +22,8 @@
#pragma once
#include <QPainter>
#include <QPlainTextEdit>
#include <QQuickPaintedItem>
#include <UI/DeclarativeWidget.h>
namespace Widgets
{
@ -61,7 +60,7 @@ private:
bool m_waitingForTerminator = false;
};
class Terminal : public QQuickPaintedItem
class Terminal : public UI::DeclarativeWidget
{
// clang-format off
Q_OBJECT
@ -144,11 +143,6 @@ Q_SIGNALS:
public:
Terminal(QQuickItem *parent = 0);
~Terminal();
virtual bool event(QEvent *event) override;
virtual void paint(QPainter *painter) override;
virtual bool eventFilter(QObject *watched, QEvent *event) override;
QFont font() const;
QString text() const;
@ -166,9 +160,7 @@ public:
bool undoRedoEnabled() const;
int maximumBlockCount() const;
QString placeholderText() const;
QTextDocument *document() const;
QPlainTextEdit *textEdit() const;
public Q_SLOTS:
void copy();
@ -193,15 +185,10 @@ public Q_SLOTS:
void setMaximumBlockCount(const int maxBlockCount);
private Q_SLOTS:
void updateWidgetSize();
void updateScrollbarVisibility();
void setCopyAvailable(const bool yes);
void addText(const QString &text, const bool enableVt100);
protected:
void processMouseEvents(QMouseEvent *event);
void processWheelEvents(QWheelEvent *event);
private:
QString vt100Processing(const QString &data);
@ -209,7 +196,7 @@ private:
bool m_autoscroll;
bool m_emulateVt100;
bool m_copyAvailable;
QPointer<QPlainTextEdit> m_textEdit;
QPlainTextEdit m_textEdit;
AnsiEscapeCodeHandler m_escapeCodeHandler;
};
}

View File

@ -86,16 +86,6 @@ int main(int argc, char **argv)
QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
#endif
//
// Force non-threaded rendering to avoid ugly crashes.
//
// We need to do this because the only way to get QWidgets-based items to render on
// the QML interface is through the QQuickPaintedItem class, which can cause conflicts
// between the GUI and render threads when the rendered items need to work with
// signals/slots.
//
QApplication::setAttribute(Qt::AA_UseOpenGLES);
// Init. application
QApplication app(argc, argv);
app.setApplicationName(APP_NAME);