From 5976d7c1c9dc738125f5459245cd19fd01ab0bfe Mon Sep 17 00:00:00 2001 From: Don Gagne Date: Mon, 30 Dec 2024 10:11:54 -0800 Subject: [PATCH] Added horizontal value slider support --- custom-example/qgroundcontrol.qrc | 1 - qgroundcontrol.qrc | 2 +- src/Comms/MockLink/PX4MockLink.params | 6 +- src/FactSystem/FactControls/CMakeLists.txt | 34 --- .../FactControls/LabelledFactSlider.qml | 38 --- .../APM/APMBatteryIndicator.qml | 29 +- .../APM/APMMainStatusIndicatorContentItem.qml | 9 +- .../PX4/PX4BatteryIndicator.qml | 26 +- .../PX4/PX4FlightModeIndicator.qml | 122 ++++---- .../PX4/PX4MainStatusIndicatorContentItem.qml | 11 +- src/FlightDisplay/GuidedValueSlider.qml | 2 +- src/QmlControls/FactSlider.qml | 79 +---- src/QmlControls/LabelledSlider.qml | 7 +- .../QGroundControl/Controls/qmldir | 1 + .../QGroundControl/FactControls/qmldir | 1 - src/QmlControls/ToolIndicatorPage.qml | 14 +- src/QmlControls/ValueSlider.qml | 287 ++++++++++++++++++ src/Settings/RTK.SettingsGroup.json | 2 +- src/UI/MainRootWindow.qml | 2 +- src/UI/toolbar/BatteryIndicator.qml | 1 + src/UI/toolbar/GPSIndicatorPage.qml | 98 +++--- 21 files changed, 448 insertions(+), 324 deletions(-) delete mode 100644 src/FactSystem/FactControls/LabelledFactSlider.qml create mode 100644 src/QmlControls/ValueSlider.qml diff --git a/custom-example/qgroundcontrol.qrc b/custom-example/qgroundcontrol.qrc index bee99370487..1bf64ae9462 100644 --- a/custom-example/qgroundcontrol.qrc +++ b/custom-example/qgroundcontrol.qrc @@ -220,7 +220,6 @@ ../src/FactSystem/FactControls/FactValueSlider.qml ../src/FactSystem/FactControls/LabelledFactComboBox.qml ../src/FactSystem/FactControls/LabelledFactTextField.qml - ../src/FactSystem/FactControls/LabelledFactSlider.qml ../src/QmlControls/QGroundControl/FactControls/qmldir ../src/FlightDisplay/FlightDisplayViewVideo.qml ../src/FlightDisplay/FlyView.qml diff --git a/qgroundcontrol.qrc b/qgroundcontrol.qrc index 0a2385c64f1..17419754262 100644 --- a/qgroundcontrol.qrc +++ b/qgroundcontrol.qrc @@ -204,6 +204,7 @@ src/PlanView/TransectStyleComplexItemStats.qml src/PlanView/TransectStyleComplexItemTabBar.qml src/PlanView/TransectStyleComplexItemTerrainFollow.qml + src/QmlControls/ValueSlider.qml src/QmlControls/VehicleRotationCal.qml src/QmlControls/VehicleSummaryRow.qml src/PlanView/VTOLLandingPatternMapVisual.qml @@ -220,7 +221,6 @@ src/FactSystem/FactControls/FactValueSlider.qml src/FactSystem/FactControls/LabelledFactComboBox.qml src/FactSystem/FactControls/LabelledFactTextField.qml - src/FactSystem/FactControls/LabelledFactSlider.qml src/QmlControls/QGroundControl/FactControls/qmldir src/FlightDisplay/CustomGuidedActionsController.qml src/FlightDisplay/FlightDisplayViewVideo.qml diff --git a/src/Comms/MockLink/PX4MockLink.params b/src/Comms/MockLink/PX4MockLink.params index 2a9822adcfb..7dc95d5c9df 100644 --- a/src/Comms/MockLink/PX4MockLink.params +++ b/src/Comms/MockLink/PX4MockLink.params @@ -10,9 +10,9 @@ 1 1 BAT1_CAPACITY -1.000000000000000000 9 1 1 BAT1_CNT_V_CURR 0.000805664050858468 9 1 1 BAT1_CNT_V_VOLT 0.000805664050858468 9 -1 1 BAT1_CRIT_THR 0.070000000298023224 9 -1 1 BAT1_EMERGEN_THR 0.050000000745058060 9 -1 1 BAT1_LOW_THR 0.150000005960464478 9 +1 1 BAT_CRIT_THR 0.070000000298023224 9 +1 1 BAT_EMERGEN_THR 0.050000000745058060 9 +1 1 BAT_LOW_THR 0.150000005960464478 9 1 1 BAT1_N_CELLS 3 6 1 1 BAT1_R_INTERNAL -1.000000000000000000 9 1 1 BAT1_SOURCE 0 6 diff --git a/src/FactSystem/FactControls/CMakeLists.txt b/src/FactSystem/FactControls/CMakeLists.txt index 4fc7457f8e2..ff1b3c62498 100644 --- a/src/FactSystem/FactControls/CMakeLists.txt +++ b/src/FactSystem/FactControls/CMakeLists.txt @@ -18,37 +18,3 @@ target_link_libraries(FactControls ) target_include_directories(FactControls INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}) - -# qt_add_qml_module(FactControls -# URI QGroundControl.FactControls -# VERSION 1.0 -# QML_FILES -# AltitudeFactTextField.qml -# FactBitmask.qml -# FactCheckBox.qml -# FactCheckBoxSlider.qml -# FactComboBox.qml -# FactLabel.qml -# FactTextField.qml -# FactTextFieldGrid.qml -# FactTextFieldRow.qml -# FactTextFieldSlider.qml -# FactValueSlider.qml -# LabelledFactComboBox.qml -# LabelledFactSlider.qml -# LabelledFactTextField.qml -# OUTPUT_TARGETS FactControls_targets -# IMPORT_PATH ${QT_QML_OUTPUT_DIRECTORY} -# IMPORTS -# QtQuick -# QtQuick.Controls -# QtQuick.Dialogs -# QtQuick.Layouts -# QGroundControl -# QGroundControl.Palette -# QGroundControl.Controls -# QGroundControl.FactSystem -# QGroundControl.ScreenTools -# DEPENDENCIES -# QtCore -# ) \ No newline at end of file diff --git a/src/FactSystem/FactControls/LabelledFactSlider.qml b/src/FactSystem/FactControls/LabelledFactSlider.qml deleted file mode 100644 index 968b34360be..00000000000 --- a/src/FactSystem/FactControls/LabelledFactSlider.qml +++ /dev/null @@ -1,38 +0,0 @@ -/**************************************************************************** - * - * (c) 2009-2022 QGROUNDCONTROL PROJECT - * - * QGroundControl is licensed according to the terms in the file - * COPYING.md in the root of the source code directory. - * - ****************************************************************************/ - -import QtQuick -import QtQuick.Layouts - -import QGroundControl.Controls -import QGroundControl.ScreenTools -import QGroundControl.FactSystem -import QGroundControl.FactControls - -RowLayout { - property alias label: label.text - property alias fact: factSlider.fact - property alias from: factSlider.from - property alias to: factSlider.to - property real sliderPreferredWidth: -1 - enabled: fact - - spacing: ScreenTools.defaultFontPixelWidth * 2 - - QGCLabel { - id: label - Layout.fillWidth: true - } - - FactSlider { - id: factSlider - Layout.preferredWidth: sliderPreferredWidth - } -} - diff --git a/src/FirmwarePlugin/APM/APMBatteryIndicator.qml b/src/FirmwarePlugin/APM/APMBatteryIndicator.qml index b3cf7a04572..718bec8c3bc 100644 --- a/src/FirmwarePlugin/APM/APMBatteryIndicator.qml +++ b/src/FirmwarePlugin/APM/APMBatteryIndicator.qml @@ -27,6 +27,7 @@ BatteryIndicator { FactPanelController { id: controller } property Fact batt1Monitor: controller.getParameterFact(-1, "BATT_MONITOR") + property string disabledString: qsTr("- disabled") SettingsGroupLayout { Layout.fillWidth: true @@ -39,16 +40,22 @@ BatteryIndicator { indexModel: false } - LabelledFactTextField { + FactSlider { Layout.fillWidth: true - label: qsTr("Voltage Trigger") + label: qsTr("Voltage Trigger") + (value == 0 ? disabledString : "") fact: controller.getParameterFact(-1, "BATT_LOW_VOLT") + from: 0 + to: 100 + majorTickStepSize: 5 } - LabelledFactTextField { + FactSlider { Layout.fillWidth: true - label: qsTr("mAh Trigger") + label: qsTr("mAh Trigger") + (value == 0 ? disabledString : "") fact: controller.getParameterFact(-1, "BATT_LOW_MAH") + from: 0 + to: 30000 + majorTickStepSize: 1000 } } @@ -63,16 +70,22 @@ BatteryIndicator { indexModel: false } - LabelledFactTextField { + FactSlider { Layout.fillWidth: true - label: qsTr("Voltage Trigger") + label: qsTr("Voltage Trigger") + (value == 0 ? disabledString : "") fact: controller.getParameterFact(-1, "BATT_CRT_VOLT") + from: 0 + to: 100 + majorTickStepSize: 5 } - LabelledFactTextField { + FactSlider { Layout.fillWidth: true - label: qsTr("mAh Trigger") + label: qsTr("mAh Trigger") + (value == 0 ? disabledString : "") fact: controller.getParameterFact(-1, "BATT_CRT_MAH") + from: 0 + to: 30000 + majorTickStepSize: 1000 } } } diff --git a/src/FirmwarePlugin/APM/APMMainStatusIndicatorContentItem.qml b/src/FirmwarePlugin/APM/APMMainStatusIndicatorContentItem.qml index c179935738b..134d7d873a6 100644 --- a/src/FirmwarePlugin/APM/APMMainStatusIndicatorContentItem.qml +++ b/src/FirmwarePlugin/APM/APMMainStatusIndicatorContentItem.qml @@ -25,7 +25,7 @@ ColumnLayout { FactPanelController { id: controller } SettingsGroupLayout { - heading: qsTr("GCS Failsafe") + heading: qsTr("Ground Control Data Link Failsafe") Layout.fillWidth: true LabelledFactComboBox { @@ -34,11 +34,12 @@ ColumnLayout { indexModel: false } - LabelledFactSlider { + FactSlider { Layout.fillWidth: true - label: qsTr("Timeout") + Layout.preferredWidth: ScreenTools.defaultFontPixelWidth * 20 + label: qsTr("Loss Timeout") fact: controller.getParameterFact(-1, "FS_GCS_TIMEOUT") - sliderPreferredWidth: ScreenTools.defaultFontPixelWidth * 20 + majorTickStepSize: 5 } } diff --git a/src/FirmwarePlugin/PX4/PX4BatteryIndicator.qml b/src/FirmwarePlugin/PX4/PX4BatteryIndicator.qml index 9682ddfebc2..4233541ba0f 100644 --- a/src/FirmwarePlugin/PX4/PX4BatteryIndicator.qml +++ b/src/FirmwarePlugin/PX4/PX4BatteryIndicator.qml @@ -25,33 +25,35 @@ BatteryIndicator { expandedPageComponent: Component { SettingsGroupLayout { Layout.fillWidth: true - heading: qsTr("Low Battery") + heading: qsTr("Low Battery Failsafe") FactPanelController { id: controller } - LabelledFactSlider { + LabelledFactComboBox { + label: qsTr("Action") + fact: controller.getParameterFact(-1, "COM_LOW_BAT_ACT") + indexModel: false + } + + FactSlider { Layout.fillWidth: true - Layout.preferredWidth: ScreenTools.defaultFontPixelWidth * 20 label: qsTr("Warning Level") fact: controller.getParameterFact(-1, "BAT_LOW_THR") + majorTickStepSize: 5 } - LabelledFactSlider { + FactSlider { Layout.fillWidth: true - label: qsTr("Failsafe Level") + label: qsTr("Critical Level") fact: controller.getParameterFact(-1, "BAT_CRIT_THR") + majorTickStepSize: 5 } - LabelledFactSlider { + FactSlider { Layout.fillWidth: true label: qsTr("Emergency Level") fact: controller.getParameterFact(-1, "BAT_EMERGEN_THR") - } - - LabelledFactComboBox { - label: qsTr("Failsafe Action") - fact: controller.getParameterFact(-1, "COM_LOW_BAT_ACT") - indexModel: false + majorTickStepSize: 5 } } } diff --git a/src/FirmwarePlugin/PX4/PX4FlightModeIndicator.qml b/src/FirmwarePlugin/PX4/PX4FlightModeIndicator.qml index 9bf943aca5e..e3a1eddd147 100644 --- a/src/FirmwarePlugin/PX4/PX4FlightModeIndicator.qml +++ b/src/FirmwarePlugin/PX4/PX4FlightModeIndicator.qml @@ -34,44 +34,30 @@ FlightModeIndicator { property Fact mpc_z_vel_all: controller.getParameterFact(-1, "MPC_Z_VEL_ALL", false) property var qgcPal: QGroundControl.globalPalette property real margins: ScreenTools.defaultFontPixelHeight - property real sliderWidth: ScreenTools.defaultFontPixelWidth * 25 + property real sliderWidth: ScreenTools.defaultFontPixelWidth * 40 FactPanelController { id: controller } SettingsGroupLayout { Layout.fillWidth: true - LabelledFactSlider { + FactSlider { Layout.fillWidth: true + Layout.preferredWidth: sliderWidth label: qsTr("RTL Altitude") fact: controller.getParameterFact(-1, "RTL_RETURN_ALT") to: fact.maxIsDefaultForType ? QGroundControl.unitsConversion.metersToAppSettingsVerticalDistanceUnits(121.92) : fact.max - sliderPreferredWidth: sliderWidth + majorTickStepSize: 10 } - LabelledFactSlider { + FactSlider { Layout.fillWidth: true label: qsTr("Land Descent Rate") fact: mpcLandSpeedFact to: fact.maxIsDefaultForType ? QGroundControl.unitsConversion.metersToAppSettingsVerticalDistanceUnits(4) : fact.max - sliderPreferredWidth: sliderWidth + majorTickStepSize: 0.5 visible: mpcLandSpeedFact && controller.vehicle && !controller.vehicle.fixedWing } - - RowLayout { - Layout.fillWidth: true - spacing: ScreenTools.defaultFontPixelWidth * 2 - visible: precisionLandingFact - - QGCLabel { - Layout.fillWidth: true; - text: qsTr("Precision Landing") - } - FactComboBox { - fact: precisionLandingFact - indexModel: false - } - } } SettingsGroupLayout { @@ -79,7 +65,7 @@ FlightModeIndicator { visible: sys_vehicle_resp ColumnLayout { - Layout.fillWidth: true + Layout.fillWidth: true QGCCheckBoxSlider { id: responsivenessCheckBox @@ -96,37 +82,32 @@ FlightModeIndicator { } } - QGCLabel { + FactSlider { Layout.fillWidth: true enabled: responsivenessCheckBox.checked + fact: sys_vehicle_resp + from: 0.01 + to: 1 + majorTickStepSize: 0.1 + } + + QGCLabel { + Layout.preferredWidth: sliderWidth + enabled: responsivenessCheckBox.checked text: qsTr("A higher value makes the vehicle react faster. Be aware that this affects braking as well, and a combination of slow responsiveness with high maximum velocity will lead to long braking distances.") font.pointSize: ScreenTools.smallFontPointSize wrapMode: QGCLabel.WordWrap } QGCLabel { - Layout.fillWidth: true - visible: sys_vehicle_resp && sys_vehicle_resp.value > 0.8 + Layout.preferredWidth: sliderWidth color: qgcPal.warningText text: qsTr("Warning: a high responsiveness requires a vehicle with large thrust-to-weight ratio. The vehicle might lose altitude otherwise.") font.pointSize: ScreenTools.smallFontPointSize wrapMode: QGCLabel.WordWrap - } - - FactSlider { - Layout.fillWidth: true - enabled: responsivenessCheckBox.checked - fact: sys_vehicle_resp - from: 0.01 - to: 1 - stepSize: 0.01 + visible: sys_vehicle_resp && sys_vehicle_resp.value > 0.8 } } - Item { - Layout.fillWidth: true - height: 1 - } - ColumnLayout { Layout.fillWidth: true visible: mpc_xy_vel_all @@ -152,56 +133,59 @@ FlightModeIndicator { fact: mpc_xy_vel_all from: 0.5 to: 20 - stepSize: 0.5 + majorTickStepSize: 0.5 } + } - Item { - Layout.fillWidth: true - height: 1 - } + ColumnLayout { + Layout.fillWidth: true + visible: mpc_z_vel_all - ColumnLayout { + QGCCheckBoxSlider { + id: zVelCheckBox Layout.fillWidth: true - visible: mpc_z_vel_all - - QGCCheckBoxSlider { - id: zVelCheckBox - Layout.fillWidth: true - text: qsTr("Overall Vertical Velocity (m/s)") - checked: mpc_z_vel_all && mpc_z_vel_all.value >= 0 - - onClicked: { - if (checked) { - mpc_z_vel_all.value = Math.abs(mpc_z_vel_all.value) - } else { - mpc_z_vel_all.value = -Math.abs(mpc_z_vel_all.value) - } + text: qsTr("Overall Vertical Velocity (m/s)") + checked: mpc_z_vel_all && mpc_z_vel_all.value >= 0 + + onClicked: { + if (checked) { + mpc_z_vel_all.value = Math.abs(mpc_z_vel_all.value) + } else { + mpc_z_vel_all.value = -Math.abs(mpc_z_vel_all.value) } } + } - FactSlider { - Layout.fillWidth: true - enabled: zVelCheckBox.checked - fact: mpc_z_vel_all - from: 0.2 - to: 8 - stepSize: 0.2 - } + FactSlider { + Layout.fillWidth: true + enabled: zVelCheckBox.checked + fact: mpc_z_vel_all + from: 0.2 + to: 8 + majorTickStepSize: 0.5 } } } SettingsGroupLayout { Layout.fillWidth: true - heading: qsTr("Mission Turning Radius") - headingDescription: qsTr("Increasing this leads to rounder turns in missions (corner cutting). Use the minimum value for accurate corner tracking.") + showDividers: false FactSlider { Layout.fillWidth: true + label: qsTr("Mission Turning Radius") fact: controller.getParameterFact(-1, "NAV_ACC_RAD") from: 2 to: 16 - stepSize: 0.5 + majorTickStepSize: 2 + } + + QGCLabel { + Layout.fillWidth: true + Layout.preferredWidth: sliderWidth + text: qsTr("Increasing this leads to rounder turns in missions (corner cutting). Use the minimum value for accurate corner tracking.") + font.pointSize: ScreenTools.smallFontPointSize + wrapMode: QGCLabel.WordWrap } } } diff --git a/src/FirmwarePlugin/PX4/PX4MainStatusIndicatorContentItem.qml b/src/FirmwarePlugin/PX4/PX4MainStatusIndicatorContentItem.qml index dbf7c2f8a04..6b6d10a8e42 100644 --- a/src/FirmwarePlugin/PX4/PX4MainStatusIndicatorContentItem.qml +++ b/src/FirmwarePlugin/PX4/PX4MainStatusIndicatorContentItem.qml @@ -25,7 +25,7 @@ ColumnLayout { FactPanelController { id: controller } SettingsGroupLayout { - heading: qsTr("Ground Control Data Link Loss") + heading: qsTr("Ground Control Data Link Failsafe") Layout.fillWidth: true RowLayout { @@ -34,7 +34,7 @@ ColumnLayout { QGCLabel { Layout.fillWidth: true; - text: qsTr("Failsafe Action") + text: qsTr("Action") } FactComboBox { id: failsafeActionCombo @@ -43,11 +43,12 @@ ColumnLayout { } } - LabelledFactSlider { + FactSlider { Layout.fillWidth: true - label: qsTr("Data Link Loss Timeout") + Layout.preferredWidth: ScreenTools.defaultFontPixelWidth * 40 + label: qsTr("Loss Timeout") fact: controller.getParameterFact(-1, "COM_DL_LOSS_T") - sliderPreferredWidth: ScreenTools.defaultFontPixelWidth * 20 + majorTickStepSize: 5 } } } diff --git a/src/FlightDisplay/GuidedValueSlider.qml b/src/FlightDisplay/GuidedValueSlider.qml index 1b992c0e305..71ba8f96062 100644 --- a/src/FlightDisplay/GuidedValueSlider.qml +++ b/src/FlightDisplay/GuidedValueSlider.qml @@ -287,7 +287,7 @@ Item { Connections { target: control - on_sliderValueChanged: sliderValueTextField.visible = false + on_SliderValueChanged: sliderValueTextField.visible = false } } } diff --git a/src/QmlControls/FactSlider.qml b/src/QmlControls/FactSlider.qml index 56359ebcd97..0536d022efe 100644 --- a/src/QmlControls/FactSlider.qml +++ b/src/QmlControls/FactSlider.qml @@ -11,33 +11,26 @@ import QtQuick import QtQuick.Controls import QtQuick.Layouts +import QGroundControl.Controls import QGroundControl.FactSystem import QGroundControl.Palette import QGroundControl.ScreenTools -Slider { +ValueSlider { id: control value: _fact.value from: _fact.min to: _fact.max - stepSize: isNaN(_fact.increment) ? 0 : _fact.increment - snapMode: stepSize ? Slider.SnapAlways : Slider.NoSnap - live: true - bottomPadding: sliderValueLabel.contentHeight - leftPadding: 0 - rightPadding: 0 - enabled: fact + unitsString: _fact.units + decimalPlaces: _fact.decimalPlaces - property Fact fact: undefined - property bool showUnits: true + required property Fact fact - property bool _loadComplete: false property real _minMaxVisibilityPadding: ScreenTools.defaultFontPixelWidth property Fact _nullFact: Fact { } property Fact _fact: fact ? fact : _nullFact Component.onCompleted: { - _loadComplete = true if (fact && fact.minIsDefaultForType && fact.min == from) { console.error("FactSlider: Fact is minIsDefaultForType", _fact.name) } @@ -46,10 +39,6 @@ Slider { } } - function valuePlusUnits(valueString) { - return valueString + (showUnits ? " " + _fact.units : "") - } - Timer { id: updateTimer interval: 1000 @@ -59,65 +48,9 @@ Slider { } onValueChanged: { - if (_loadComplete && enabled) { + if (enabled) { // We don't want to spam the vehicle with parameter updates updateTimer.restart() } } - - QGCPalette { - id: qgcPal - colorGroupEnabled: control.enabled - } - - background: Item { - implicitWidth: ScreenTools.defaultFontPixelWidth * 40 - implicitHeight: ScreenTools.defaultFontPixelHeight + sliderValueLabel.contentHeight - - Rectangle { - id: sliderBar - x: control.leftPadding - y: control.topPadding + (control.availableHeight / 2) - (height / 2) - height: ScreenTools.defaultFontPixelHeight / 3 - width: control.availableWidth - radius: height / 2 - color: qgcPal.button - } - - QGCLabel { - text: control.from.toFixed(_fact.decimalPlaces) - visible: fact && sliderValueLabel.x > x + contentWidth + _minMaxVisibilityPadding - anchors { - left: parent.left - bottom: parent.bottom - } - } - - QGCLabel { - text: control.to.toFixed(_fact.decimalPlaces) - visible: fact && sliderValueLabel.x + sliderValueLabel.contentWidth < x - _minMaxVisibilityPadding - anchors { - right: parent.right - bottom: parent.bottom - } - } - - QGCLabel { - id: sliderValueLabel - anchors.bottom: parent.bottom - x: control.leftPadding + (control.visualPosition * (control.availableWidth - width)) - text: fact ? valuePlusUnits(control.value.toFixed(control._fact.decimalPlaces)) : qsTr("N/A") - horizontalAlignment: Text.AlignHCenter - } - } - - handle: Rectangle { - x: control.leftPadding + control.visualPosition * (control.availableWidth - width) - y: control.topPadding + control.availableHeight / 2 - height / 2 - implicitWidth: implicitHeight - implicitHeight: ScreenTools.defaultFontPixelHeight - radius: implicitHeight / 2 - color: qgcPal.button - border.color: qgcPal.buttonText - } } diff --git a/src/QmlControls/LabelledSlider.qml b/src/QmlControls/LabelledSlider.qml index 961ecfbad34..cefb7890623 100644 --- a/src/QmlControls/LabelledSlider.qml +++ b/src/QmlControls/LabelledSlider.qml @@ -15,9 +15,8 @@ import QGroundControl.ScreenTools RowLayout { property alias label: label.text - property alias fact: factSlider.fact - property alias from: factSlider.from - property alias to: factSlider.to + property alias from: slider.from + property alias to: slider.to property real sliderPreferredWidth: -1 spacing: ScreenTools.defaultFontPixelWidth * 2 @@ -28,7 +27,7 @@ RowLayout { } QGCSlider { - id: factSlider + id: slider Layout.preferredWidth: sliderPreferredWidth } } diff --git a/src/QmlControls/QGroundControl/Controls/qmldir b/src/QmlControls/QGroundControl/Controls/qmldir index 2c00d53431c..e9315938a57 100644 --- a/src/QmlControls/QGroundControl/Controls/qmldir +++ b/src/QmlControls/QGroundControl/Controls/qmldir @@ -123,6 +123,7 @@ TransectStyleComplexItemTerrainFollow 1.0 TransectStyleComplexItemTerrainFollo TransectStyleMapVisuals 1.0 TransectStyleMapVisuals.qml ToolStrip 1.0 ToolStrip.qml ToolStripHoverButton 1.0 ToolStripHoverButton.qml +ValueSlider 1.0 ValueSlider.qml VehicleRotationCal 1.0 VehicleRotationCal.qml VehicleSummaryRow 1.0 VehicleSummaryRow.qml MAVLinkChart 1.0 MAVLinkChart.qml diff --git a/src/QmlControls/QGroundControl/FactControls/qmldir b/src/QmlControls/QGroundControl/FactControls/qmldir index ef9a028d6b5..e176873ca17 100644 --- a/src/QmlControls/QGroundControl/FactControls/qmldir +++ b/src/QmlControls/QGroundControl/FactControls/qmldir @@ -13,4 +13,3 @@ FactValueSlider 1.0 FactValueSlider.qml FactTextFieldSlider 1.0 FactTextFieldSlider.qml LabelledFactComboBox 1.0 LabelledFactComboBox.qml LabelledFactTextField 1.0 LabelledFactTextField.qml -LabelledFactSlider 1.0 LabelledFactSlider.qml diff --git a/src/QmlControls/ToolIndicatorPage.qml b/src/QmlControls/ToolIndicatorPage.qml index cd6f2256ab1..1a8b87c0909 100644 --- a/src/QmlControls/ToolIndicatorPage.qml +++ b/src/QmlControls/ToolIndicatorPage.qml @@ -18,7 +18,7 @@ import QGroundControl.ScreenTools RowLayout { id: control - spacing: _margins + spacing: ScreenTools.defaultFontPixelWidth property bool showExpand: false // Controls whether the expand widget is shown or not property bool waitForParameters: false // UI won't show until parameters are ready @@ -30,12 +30,10 @@ RowLayout { property bool expanded: false property var drawer - property var activeVehicle: QGroundControl.multiVehicleManager.vehicle property bool parametersReady: QGroundControl.multiVehicleManager.parameterReadyVehicleAvailable - property real _margins: ScreenTools.defaultFontPixelHeight - property bool _loadPages: !waitForParameters || parametersReady + property bool _loadPages: !waitForParameters || parametersReady QGCLabel { text: qsTr("Waiting for parameters...") @@ -50,14 +48,6 @@ RowLayout { property var pageProperties: control.pageProperties } - Rectangle { - id: divider - Layout.preferredWidth: visible ? 1 : -1 - Layout.fillHeight: true - border.color: Qt.darker(QGroundControl.globalPalette.text, 4) - visible: expanded - } - Loader { id: expandedItemLoader Layout.alignment: Qt.AlignTop diff --git a/src/QmlControls/ValueSlider.qml b/src/QmlControls/ValueSlider.qml new file mode 100644 index 00000000000..97c4b0c69d1 --- /dev/null +++ b/src/QmlControls/ValueSlider.qml @@ -0,0 +1,287 @@ +/**************************************************************************** + * + * (c) 2009-2020 QGROUNDCONTROL PROJECT + * + * QGroundControl is licensed according to the terms in the file + * COPYING.md in the root of the source code directory. + * + ****************************************************************************/ + +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts + +import QGroundControl +import QGroundControl.Controls +import QGroundControl.Vehicle +import QGroundControl.Palette +import QGroundControl.ScreenTools +import QGroundControl.SettingsManager + +Control { + id: control + + property real value: 0 + property real from: 0 + property real to: 100 + property string unitsString + property string label + + required property int decimalPlaces + required property real majorTickStepSize + + property int _tickValueDecimalPlaces: countDecimalPlaces(majorTickStepSize) + + property real _indicatorCenterPos: width / 2 + + property real _majorTickSpacing: ScreenTools.defaultFontPixelWidth * 6 + + property real _majorTickSize: valueIndicator.pointerSize + valueIndicator.indicatorValueMargins + property real _tickValueEdgeMargin: ScreenTools.defaultFontPixelWidth / 2 + property real _minorTickSize: _majorTickSize / 2 + property real _sliderValuePerPixel: majorTickStepSize / _majorTickSpacing + + property int _minorTickValueStep: majorTickStepSize / 2 + + //property real _sliderValue: _firstPixelValue + ((sliderFlickable.contentX + _indicatorCenterPos) * _sliderValuePerPixel) + + // Calculate the full range of the slider. We have been given a min/max but that is for clamping the selected slider values. + // We need expand that range to take into account additional values that must be displayed above/below the value indicator + // when it is at min/max. + + // Add additional major ticks above/below min/max to ensure we can display the full visual range of the slider + property int _majorTicksVisibleBeyondIndicator: Math.ceil(_indicatorCenterPos / _majorTickSpacing) + property int _majorTicksExtentsAdjustment: _majorTicksVisibleBeyondIndicator * majorTickStepSize + + // Calculate the min/max for the full slider range + property int _majorTickMinValue: Math.floor((from - _majorTicksExtentsAdjustment) / majorTickStepSize) * majorTickStepSize + property int _majorTickMaxValue: Math.floor((to + _majorTicksExtentsAdjustment) / majorTickStepSize) * majorTickStepSize + + // Now calculate the position we draw the first tick mark such that we are not allowed to flick above the max value + property real _firstTickPixelOffset: _indicatorCenterPos - ((from - _majorTickMinValue) / _sliderValuePerPixel) + property real _firstPixelValue: _majorTickMinValue - (_firstTickPixelOffset * _sliderValuePerPixel) + + property int _cMajorTicks: (_majorTickMaxValue - _majorTickMinValue) / majorTickStepSize + 1 + + // Calculate the slider width such that we can flick through the full range of the slider + property real _sliderContentSize: ((to - _firstPixelValue) / _sliderValuePerPixel) + (sliderFlickable.width - _indicatorCenterPos) + + property bool _loadComplete: false + + property var qgcPal: QGroundControl.globalPalette + + Component.onCompleted: { + _recalcSliderPos(false) + _loadComplete = true + } + + onWidthChanged: { + if (_loadComplete) { + _recalcSliderPos() + } + } + + function countDecimalPlaces(number) { + const numberString = number.toString() + if (numberString.includes('.')) { + return numberString.split('.')[1].length + } else { + return 0 + } + } + + function _recalcSliderPos(animate = true) { + // Position the slider such that the indicator is pointing to the current value + var contentX = ((value - _firstPixelValue) / _sliderValuePerPixel) - _indicatorCenterPos + if (animate) { + flickableAnimation.from = sliderFlickable.contentX + flickableAnimation.to = contentX + flickableAnimation.start() + } else { + sliderFlickable.contentX = contentX + } + } + + function _clampedSliderValue(value) { + return Math.min(Math.max(value, from), to).toFixed(decimalPlaces) + } + + QGCPalette { + id: qgcPal + colorGroupEnabled: control.enabled + } + + background: Item { + implicitHeight: _majorTickSize + tickValueMargin + ScreenTools.defaultFontPixelHeight + + property real tickValueMargin: ScreenTools.defaultFontPixelHeight / 3 + + DeadMouseArea { + anchors.fill: parent + } + + QGCFlickable { + id: sliderFlickable + anchors.fill: parent + contentWidth: sliderContainer.width + contentHeight: sliderContainer.height + flickableDirection: Flickable.HorizontalFlick + + onContentXChanged: { + if (dragging) { + value = _firstPixelValue + ((sliderFlickable.contentX + _indicatorCenterPos) * _sliderValuePerPixel) + } + } + + PropertyAnimation on contentX { + id: flickableAnimation + duration: 500 + from: fromValue + to: toValue + easing.type: Easing.OutCubic + running: false + + property real fromValue + property real toValue + } + + Item { + id: sliderContainer + width: _sliderContentSize + height: sliderFlickable.height + + // Major tick marks + Repeater { + model: _cMajorTicks + + Item { + width: 1 + height: sliderContainer.height + x: _majorTickSpacing * index + _firstTickPixelOffset + opacity: tickValue < from || tickValue > to ? 0.5 : 1 + + property real tickValue: _majorTickMinValue + (majorTickStepSize * index) + + Rectangle { + id: majorTickMark + width: 1 + height: _majorTickSize + color: qgcPal.text + } + + QGCLabel { + anchors.bottomMargin: _tickValueEdgeMargin + anchors.bottom: parent.bottom + anchors.horizontalCenter: majorTickMark.horizontalCenter + text: parent.tickValue.toFixed(_tickValueDecimalPlaces) + } + } + } + + // Minor tick marks + Repeater { + model: _cMajorTicks * 2 + + Rectangle { + x: _majorTickSpacing / 2 * index + + _firstTickPixelOffset + width: 1 + height: _minorTickSize + color: qgcPal.text + opacity: tickValue < from || tickValue > to ? 0.5 : 1 + visible: index % 2 === 1 + + property real tickValue: _majorTickMaxValue - ((majorTickStepSize / 2) * index) + } + } + } + } + + Rectangle { + id: labelItemBackground + width: labelItem.contentWidth + height: labelItem.contentHeight + color: qgcPal.window + opacity: 0.8 + } + + QGCLabel { + id: labelItem + anchors.left: labelItemBackground.left + anchors.top: labelItemBackground.top + text: label + } + } + + contentItem: Item { + implicitHeight: valueIndicator.height + + Canvas { + id: valueIndicator + anchors.horizontalCenter: parent.horizontalCenter + width: Math.max(valueLabel.contentWidth + (indicatorValueMargins * 2), pointerSize * 2 + 2) + height: valueLabel.contentHeight + (indicatorValueMargins * 2) + pointerSize + + property real indicatorValueMargins: ScreenTools.defaultFontPixelWidth / 2 + property real indicatorHeight: valueLabel.contentHeight + property real pointerSize: ScreenTools.defaultFontPixelWidth + + onPaint: { + var ctx = getContext("2d") + ctx.strokeStyle = qgcPal.text + ctx.fillStyle = qgcPal.window + ctx.lineWidth = 1 + ctx.beginPath() + ctx.moveTo(width / 2, 0) + ctx.lineTo(width / 2 + pointerSize, pointerSize) + ctx.lineTo(width - 1, pointerSize) + ctx.lineTo(width - 1, height - 1) + ctx.lineTo(1, height - 1) + ctx.lineTo(1, pointerSize) + ctx.lineTo(width / 2 - pointerSize, pointerSize) + ctx.closePath() + ctx.fill() + ctx.stroke() + } + + QGCLabel { + id: valueLabel + anchors.bottomMargin: parent.indicatorValueMargins + anchors.bottom: parent.bottom + anchors.horizontalCenter: parent.horizontalCenter + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignBottom + text: _clampedSliderValue(value) + (unitsString !== "" ? " " + unitsString : "") + } + + QGCMouseArea { + anchors.fill: parent + onClicked: { + sliderValueTextField.text = _clampedSliderValue(value) + sliderValueTextField.visible = true + sliderValueTextField.forceActiveFocus() + } + } + + QGCTextField { + id: sliderValueTextField + anchors.topMargin: valueIndicator.pointerSize + anchors.fill: parent + showUnits: true + unitsLabel: unitsString + visible: false + + onEditingFinished: { + visible = false + focus = false + value = _clampedSliderValue(parseFloat(text)) + _recalcSliderPos() + } + + Connections { + target: control + onValueChanged: sliderValueTextField.visible = false + } + } + } + } +} diff --git a/src/Settings/RTK.SettingsGroup.json b/src/Settings/RTK.SettingsGroup.json index df798d21f9e..9c4ca70e124 100644 --- a/src/Settings/RTK.SettingsGroup.json +++ b/src/Settings/RTK.SettingsGroup.json @@ -18,7 +18,7 @@ }, { "name": "surveyInMinObservationDuration", - "shortDesc": "Minimum observation time", + "shortDesc": "Min observation time", "longDesc": "Defines the minimum amount of observation time for the position calculation.", "type": "Uint32", "default": 180, diff --git a/src/UI/MainRootWindow.qml b/src/UI/MainRootWindow.qml index 7a100c393ab..2a9b1ab6241 100644 --- a/src/UI/MainRootWindow.qml +++ b/src/UI/MainRootWindow.qml @@ -797,7 +797,7 @@ ApplicationWindow { contentItem: QGCFlickable { id: indicatorDrawerLoaderFlickable implicitWidth: Math.min(mainWindow.contentItem.width - (2 * indicatorDrawer._margins) - (indicatorDrawer.padding * 2), indicatorDrawerLoader.width) - implicitHeight: Math.min(mainWindow.contentItem.height - (2 * indicatorDrawer._margins) - (indicatorDrawer.padding * 2), indicatorDrawerLoader.height) + implicitHeight: Math.min(mainWindow.contentItem.height - ScreenTools.toolbarHeight - (2 * indicatorDrawer._margins) - (indicatorDrawer.padding * 2), indicatorDrawerLoader.height) contentWidth: indicatorDrawerLoader.width contentHeight: indicatorDrawerLoader.height diff --git a/src/UI/toolbar/BatteryIndicator.qml b/src/UI/toolbar/BatteryIndicator.qml index 62df9061c17..e5274c296b3 100644 --- a/src/UI/toolbar/BatteryIndicator.qml +++ b/src/UI/toolbar/BatteryIndicator.qml @@ -297,6 +297,7 @@ Item { FactPanelController { id: controller } Loader { + Layout.fillWidth: true sourceComponent: expandedPageComponent } diff --git a/src/UI/toolbar/GPSIndicatorPage.qml b/src/UI/toolbar/GPSIndicatorPage.qml index b6a498ce020..63a0651e000 100644 --- a/src/UI/toolbar/GPSIndicatorPage.qml +++ b/src/UI/toolbar/GPSIndicatorPage.qml @@ -94,7 +94,7 @@ ToolIndicatorPage { SettingsGroupLayout { heading: qsTr("RTK GPS Settings") - property real sliderWidth: ScreenTools.defaultFontPixelWidth * 32 // Size is tuned so expanded page fits Herelink screen without horiz scrolling + property real sliderWidth: ScreenTools.defaultFontPixelWidth * 40 FactCheckBoxSlider { Layout.fillWidth: true @@ -103,89 +103,75 @@ ToolIndicatorPage { visible: fact.visible } - FactCheckBoxSlider { - Layout.fillWidth: true - text: qsTr("Perform Survey-In") - fact: rtkSettings.useFixedBasePosition - checkedValue: false - uncheckedValue: true - visible: rtkSettings.useFixedBasePosition.visible - } + RowLayout { + visible: rtkSettings.useFixedBasePosition.visible - LabelledFactSlider { - sliderPreferredWidth: sliderWidth - label: rtkSettings.surveyInAccuracyLimit.shortDescription - fact: QGroundControl.settingsManager.rtkSettings.surveyInAccuracyLimit - visible: rtkSettings.surveyInAccuracyLimit.visible - enabled: !useFixedPosition + QGCRadioButton { + text: qsTr("Survey-In") + checked: !useFixedPosition + onClicked: rtkSettings.useFixedBasePosition.rawValue = false + } - Component.onCompleted: console.log("increment", fact.increment) + QGCRadioButton { + text: qsTr("Specify position") + checked: useFixedPosition + onClicked: rtkSettings.useFixedBasePosition.rawValue = true + } } - LabelledFactSlider { - sliderPreferredWidth: sliderWidth - label: rtkSettings.surveyInMinObservationDuration.shortDescription - fact: rtkSettings.surveyInMinObservationDuration - visible: rtkSettings.surveyInMinObservationDuration.visible - enabled: !useFixedPosition + FactSlider { + Layout.fillWidth: true + Layout.preferredWidth: sliderWidth + label: qsTr("Accuracy (u-blox only)") + fact: QGroundControl.settingsManager.rtkSettings.surveyInAccuracyLimit + majorTickStepSize: 0.1 + visible: !useFixedPosition && rtkSettings.surveyInAccuracyLimit.visible } - FactCheckBoxSlider { - Layout.columnSpan: 3 - Layout.fillWidth: true - text: qsTr("Use Specified Base Position") - fact: rtkSettings.useFixedBasePosition - visible: rtkSettings.useFixedBasePosition.visible + FactSlider { + Layout.fillWidth: true + Layout.preferredWidth: sliderWidth + label: qsTr("Min Duration") + fact: rtkSettings.surveyInMinObservationDuration + majorTickStepSize: 10 + visible: !useFixedPosition && rtkSettings.surveyInMinObservationDuration.visible } LabelledFactTextField { label: rtkSettings.fixedBasePositionLatitude.shortDescription fact: rtkSettings.fixedBasePositionLatitude - visible: rtkSettings.fixedBasePositionLatitude.visible - enabled: useFixedPosition + visible: useFixedPosition && rtkSettings.fixedBasePositionLatitude.visible } LabelledFactTextField { label: rtkSettings.fixedBasePositionLongitude.shortDescription fact: rtkSettings.fixedBasePositionLongitude - visible: rtkSettings.fixedBasePositionLongitude.visible - enabled: useFixedPosition + visible: useFixedPosition && rtkSettings.fixedBasePositionLongitude.visible } LabelledFactTextField { label: rtkSettings.fixedBasePositionAltitude.shortDescription fact: rtkSettings.fixedBasePositionAltitude - visible: rtkSettings.fixedBasePositionAltitude.visible - enabled: useFixedPosition + visible: useFixedPosition && rtkSettings.fixedBasePositionAltitude.visible } LabelledFactTextField { label: rtkSettings.fixedBasePositionAccuracy.shortDescription fact: rtkSettings.fixedBasePositionAccuracy - visible: rtkSettings.fixedBasePositionAccuracy.visible - enabled: useFixedPosition + visible: useFixedPosition && rtkSettings.fixedBasePositionAccuracy.visible } - RowLayout { - spacing: ScreenTools.defaultFontPixelWidth - - QGCLabel { - Layout.fillWidth: true; - text: qsTr("Current Base Position") - enabled: saveBasePositionButton.enabled - } - - QGCButton { - id: saveBasePositionButton - text: enabled ? qsTr("Save") : qsTr("Not Yet Valid") - enabled: QGroundControl.gpsRtk.valid.value - - onClicked: { - rtkSettings.fixedBasePositionLatitude.rawValue = QGroundControl.gpsRtk.currentLatitude.rawValue - rtkSettings.fixedBasePositionLongitude.rawValue = QGroundControl.gpsRtk.currentLongitude.rawValue - rtkSettings.fixedBasePositionAltitude.rawValue = QGroundControl.gpsRtk.currentAltitude.rawValue - rtkSettings.fixedBasePositionAccuracy.rawValue = QGroundControl.gpsRtk.currentAccuracy.rawValue - } + LabelledButton { + label: qsTr("Current Base Position") + buttonText: enabled ? qsTr("Save") : qsTr("Not Yet Valid") + visible: useFixedPosition + enabled: QGroundControl.gpsRtk.valid.value + + onClicked: { + rtkSettings.fixedBasePositionLatitude.rawValue = QGroundControl.gpsRtk.currentLatitude.rawValue + rtkSettings.fixedBasePositionLongitude.rawValue = QGroundControl.gpsRtk.currentLongitude.rawValue + rtkSettings.fixedBasePositionAltitude.rawValue = QGroundControl.gpsRtk.currentAltitude.rawValue + rtkSettings.fixedBasePositionAccuracy.rawValue = QGroundControl.gpsRtk.currentAccuracy.rawValue } } }