diff --git a/qgroundcontrol.qrc b/qgroundcontrol.qrc
index dd64f5fdfbe..b07c1254636 100644
--- a/qgroundcontrol.qrc
+++ b/qgroundcontrol.qrc
@@ -127,6 +127,7 @@
src/QmlControls/MissionItemIndexLabel.qml
src/PlanView/MissionItemMapVisual.qml
src/PlanView/MissionItemStatus.qml
+ src/QmlControls/MvPanelPage.qml
src/QmlControls/OfflineMapButton.qml
src/QtLocationPlugin/QMLControl/OfflineMapEditor.qml
src/UI/preferences/OfflineMapInfo.qml
@@ -161,12 +162,14 @@
src/QmlControls/QGCMenuSeparator.qml
src/QmlControls/QGCMouseArea.qml
src/QmlControls/QGCMovableItem.qml
+ src/QmlControls/QGCPageIndicator.qml
src/QmlControls/QGCPopupDialog.qml
src/QmlControls/PipView.qml
src/QmlControls/PipState.qml
src/QmlControls/QGCRadioButton.qml
src/QmlControls/QGCSimpleMessageDialog.qml
src/QmlControls/QGCSlider.qml
+ src/QmlControls/QGCSwipeView.qml
src/QmlControls/QGCSwitch.qml
src/QmlControls/QGCTabBar.qml
src/QmlControls/QGCTabButton.qml
@@ -342,6 +345,7 @@
src/Viewer3D/Viewer3DQml/Models3D/Line3D.qml
src/Viewer3D/Viewer3DQml/Models3D/Viewer3DVehicleItems.qml
src/Viewer3D/Viewer3DQml/Viewer3DProgressBar.qml
+ src/FlightDisplay/FlyViewTopRightPanel.qml
src/FirstRunPromptDialogs/UnitsFirstRunPrompt.qml
diff --git a/src/FlightDisplay/FlyViewTopRightColumnLayout.qml b/src/FlightDisplay/FlyViewTopRightColumnLayout.qml
index 9a7b8197215..245267b534b 100644
--- a/src/FlightDisplay/FlyViewTopRightColumnLayout.qml
+++ b/src/FlightDisplay/FlyViewTopRightColumnLayout.qml
@@ -20,29 +20,6 @@ import QGroundControl.ScreenTools
ColumnLayout {
width: _rightPanelWidth
- RowLayout {
- id: multiVehiclePanelSelector
- Layout.alignment: Qt.AlignTop
- spacing: ScreenTools.defaultFontPixelWidth
- visible: QGroundControl.multiVehicleManager.vehicles.count > 1 && QGroundControl.corePlugin.options.flyView.showMultiVehicleList
-
- QGCMapPalette { id: mapPal; lightColors: true }
-
- QGCRadioButton {
- id: singleVehicleRadio
- text: qsTr("Single")
- checked: _showSingleVehicleUI
- onClicked: _showSingleVehicleUI = true
- textColor: mapPal.text
- }
-
- QGCRadioButton {
- text: qsTr("Multi-Vehicle")
- textColor: mapPal.text
- onClicked: _showSingleVehicleUI = false
- }
- }
-
TerrainProgress {
Layout.alignment: Qt.AlignTop
Layout.preferredWidth: _rightPanelWidth
@@ -54,7 +31,7 @@ ColumnLayout {
Loader {
id: photoVideoControlLoader
Layout.alignment: Qt.AlignTop | Qt.AlignRight
- sourceComponent: globals.activeVehicle && _showSingleVehicleUI ? photoVideoControlComponent : undefined
+ sourceComponent: globals.activeVehicle ? photoVideoControlComponent : undefined
property real rightEdgeCenterInset: visible ? parent.width - x : 0
@@ -65,10 +42,4 @@ ColumnLayout {
}
}
}
-
- MultiVehicleList {
- Layout.preferredWidth: _rightPanelWidth
- Layout.fillHeight: true
- visible: !_showSingleVehicleUI
- }
}
diff --git a/src/FlightDisplay/FlyViewTopRightPanel.qml b/src/FlightDisplay/FlyViewTopRightPanel.qml
new file mode 100644
index 00000000000..2a8a10c010c
--- /dev/null
+++ b/src/FlightDisplay/FlyViewTopRightPanel.qml
@@ -0,0 +1,252 @@
+/****************************************************************************
+ *
+ * (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.Layouts
+
+import QGroundControl
+import QGroundControl.FactSystem
+import QGroundControl.FactControls
+import QGroundControl.Controls
+import QGroundControl.FlightDisplay
+import QGroundControl.FlightMap
+import QGroundControl.Palette
+import QGroundControl.ScreenTools
+
+
+Rectangle {
+ id: topRightPanel
+ width: contentWidth
+ height: Math.max(contentHeight, minimumHeight)
+ color: qgcPal.toolbarBackground
+ radius: ScreenTools.defaultFontPixelHeight / 2
+ visible: !QGroundControl.videoManager.fullScreen && _multipleVehicles && _settingEnableMVPanel
+ clip: true
+
+ property bool _settingEnableMVPanel: QGroundControl.settingsManager.appSettings.enableMultiVehiclePanel.value
+ property bool _multipleVehicles: QGroundControl.multiVehicleManager.vehicles.count > 1
+ property var vehicles: QGroundControl.multiVehicleManager.vehicles
+ property var selectedVehicles: QGroundControl.multiVehicleManager.selectedVehicles
+ property real contentWidth: Math.max(
+ multiVehicleList.implicitWidth,
+ swipeViewContainer.implicitWidth
+ ) + ScreenTools.defaultFontPixelHeight
+ property real contentHeight: Math.min(
+ maximumHeight,
+ topRightPanelColumnLayout.implicitHeight + topRightPanelColumnLayout.spacing * ( topRightPanelColumnLayout.children.length - 1)
+ )
+ property real minimumHeight: selectedVehiclesLabel.height + swipeViewContainer.height
+ property real maximumHeight
+
+ QGCPalette { id: qgcPal }
+
+ ColumnLayout {
+ id: topRightPanelColumnLayout
+ anchors.fill: parent
+ anchors.margins: ScreenTools.defaultFontPixelHeight / 2
+ spacing: ScreenTools.defaultFontPixelHeight / 2
+
+ QGCLabel {
+ id: selectedVehiclesLabel
+ text: {
+ let ids = Array.from({length: selectedVehicles.count}, (_, i) =>
+ selectedVehicles.get(i).id
+ ).sort((a, b) => a - b)
+ .join(", ")
+ return qsTr("Selected: ") + ids
+ }
+ }
+
+ MultiVehicleList {
+ id: multiVehicleList
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ implicitHeight: multiVehicleList.innerColumnHeight * vehicles.count - _margins * 3
+
+ Rectangle {
+ anchors.fill: parent
+ visible: topRightPanel.height === maximumHeight
+
+ Rectangle {
+ anchors.left: parent.left
+ anchors.right: parent.right
+ anchors.top: parent.top
+ anchors.margins: 0
+ height: 1
+ color: QGroundControl.globalPalette.groupBorder
+ }
+
+ gradient: Gradient {
+ orientation: Gradient.Vertical
+ GradientStop { position: 0.00; color: topRightPanel.color }
+ GradientStop { position: 0.05; color: "transparent" }
+
+ GradientStop { position: 0.95; color: "transparent" }
+ GradientStop { position: 1.00; color: topRightPanel.color }
+ }
+
+ Rectangle {
+ anchors.left: parent.left
+ anchors.right: parent.right
+ anchors.bottom: parent.bottom
+ anchors.margins: 0
+ height: 1
+ color: QGroundControl.globalPalette.groupBorder
+ }
+ }
+
+ }
+
+ Rectangle {
+ id: swipeViewContainer
+ Layout.fillWidth: true
+ implicitHeight: swipePages.implicitHeight
+ implicitWidth: swipePages.implicitWidth
+ color: "transparent"
+
+ QGCSwipeView {
+ id: swipePages
+ anchors.fill: parent
+ spacing: ScreenTools.defaultFontPixelHeight
+ implicitHeight: Math.max(buttonsPage.implicitHeight, photoVideoPage.implicitHeight)
+ implicitWidth: Math.max(buttonsPage.implicitWidth, photoVideoPage.implicitWidth)
+
+ MvPanelPage {
+ id: buttonsPage
+ implicitHeight: buttonsColumnLayout.implicitHeight + ScreenTools.defaultFontPixelHeight * 2
+ implicitWidth: buttonsColumnLayout.implicitWidth + ScreenTools.defaultFontPixelHeight * 2
+
+ ColumnLayout {
+ id: buttonsColumnLayout
+ anchors.right: parent.right
+ anchors.left: parent.left
+ anchors.verticalCenter: parent.verticalCenter
+ spacing: ScreenTools.defaultFontPixelHeight / 2
+ implicitHeight: Math.max(selectionRowLayout.height, actionRowLayout.height) + ScreenTools.defaultFontPixelHeight * 2
+ implicitWidth: Math.max(selectionRowLayout.width, actionRowLayout.width) + ScreenTools.defaultFontPixelHeight * 4
+
+ QGCLabel {
+ text: qsTr("Multi Vehicle Selection")
+ Layout.alignment: Qt.AlignHCenter
+ }
+
+ RowLayout {
+ id: selectionRowLayout
+ Layout.alignment: Qt.AlignHCenter
+
+ QGCButton {
+ text: qsTr("Select All")
+ enabled: multiVehicleList.selectedVehicles && multiVehicleList.selectedVehicles.count !== QGroundControl.multiVehicleManager.vehicles.count
+ onClicked: multiVehicleList.selectAll()
+ }
+
+ QGCButton {
+ text: qsTr("Deselect All")
+ enabled: multiVehicleList.selectedVehicles && multiVehicleList.selectedVehicles.count > 0
+ onClicked: multiVehicleList.deselectAll()
+ }
+
+ }
+
+
+ QGCLabel {
+ text: qsTr("Multi Vehicle Actions")
+ Layout.alignment: Qt.AlignHCenter
+ }
+
+ RowLayout {
+ id: actionRowLayout
+ Layout.alignment: Qt.AlignHCenter
+
+ QGCButton {
+ text: qsTr("Arm")
+ enabled: multiVehicleList.armAvailable()
+ onClicked: _guidedController.confirmAction(_guidedController.actionMVArm)
+ Layout.preferredWidth: ScreenTools.defaultFontPixelHeight * 2.75
+ leftPadding: 0
+ rightPadding: 0
+ }
+
+ QGCButton {
+ text: qsTr("Disarm")
+ enabled: multiVehicleList.disarmAvailable()
+ onClicked: _guidedController.confirmAction(_guidedController.actionMVDisarm)
+ Layout.preferredWidth: ScreenTools.defaultFontPixelHeight * 2.75
+ leftPadding: 0
+ rightPadding: 0
+ }
+
+ QGCButton {
+ text: qsTr("Start")
+ enabled: multiVehicleList.startAvailable()
+ onClicked: _guidedController.confirmAction(_guidedController.actionMVStartMission)
+ Layout.preferredWidth: ScreenTools.defaultFontPixelHeight * 2.75
+ leftPadding: 0
+ rightPadding: 0
+ }
+
+ QGCButton {
+ text: qsTr("Pause")
+ enabled: multiVehicleList.pauseAvailable()
+ onClicked: _guidedController.confirmAction(_guidedController.actionMVPause)
+ Layout.preferredWidth: ScreenTools.defaultFontPixelHeight * 2.75
+ leftPadding: 0
+ rightPadding: 0
+ }
+ }
+ }
+ } // Page 1
+
+ MvPanelPage {
+
+ id: photoVideoPage
+ implicitHeight: photoVideoControlLoader.implicitHeight + ScreenTools.defaultFontPixelHeight * 2
+ implicitWidth: photoVideoControlLoader.implicitWidth + ScreenTools.defaultFontPixelHeight * 2
+
+ // We use a Loader to load the photoVideoControlComponent only when the active vehicle is not null
+ // This make it easier to implement PhotoVideoControl without having to check for the mavlink camera
+ // to be null all over the place
+
+ Loader {
+ id: photoVideoControlLoader
+ anchors.horizontalCenter: parent.horizontalCenter
+ sourceComponent: globals.activeVehicle ? photoVideoControlComponent : undefined
+
+ property real rightEdgeCenterInset: visible ? parent.width - x : 0
+
+ Component {
+ id: photoVideoControlComponent
+
+ PhotoVideoControl {
+ }
+ }
+ }
+ } // Page 2
+ } // QGCSwipeView
+
+ QGCPageIndicator {
+ id: pageIndicator
+ count: swipePages.count
+ currentIndex: swipePages.currentIndex
+ anchors.bottom: parent.bottom
+ anchors.horizontalCenter: parent.horizontalCenter
+ anchors.margins: ScreenTools.defaultFontPixelHeight / 4
+
+ delegate: Rectangle {
+ height: ScreenTools.defaultFontPixelHeight / 2
+ width: height
+ radius: width / 2
+ color: model.index === pageIndicator.currentIndex ? qgcPal.text : qgcPal.button
+ opacity: model.index === pageIndicator.currentIndex ? 0.9 : 0.3
+ }
+ }
+ }
+ }
+}
+
diff --git a/src/FlightDisplay/FlyViewWidgetLayer.qml b/src/FlightDisplay/FlyViewWidgetLayer.qml
index 870e8d7dca7..851ec3a5414 100644
--- a/src/FlightDisplay/FlyViewWidgetLayer.qml
+++ b/src/FlightDisplay/FlyViewWidgetLayer.qml
@@ -59,17 +59,30 @@ Item {
leftEdgeTopInset: toolStrip.leftEdgeTopInset
leftEdgeCenterInset: toolStrip.leftEdgeCenterInset
leftEdgeBottomInset: virtualJoystickMultiTouch.visible ? virtualJoystickMultiTouch.leftEdgeBottomInset : parentToolInsets.leftEdgeBottomInset
- rightEdgeTopInset: topRightColumnLayout.rightEdgeTopInset
- rightEdgeCenterInset: topRightColumnLayout.rightEdgeCenterInset
+ rightEdgeTopInset: topRightPanel.rightEdgeTopInset
+ rightEdgeCenterInset: topRightPanel.rightEdgeCenterInset
rightEdgeBottomInset: bottomRightRowLayout.rightEdgeBottomInset
topEdgeLeftInset: toolStrip.topEdgeLeftInset
topEdgeCenterInset: mapScale.topEdgeCenterInset
- topEdgeRightInset: topRightColumnLayout.topEdgeRightInset
+ topEdgeRightInset: topRightPanel.topEdgeRightInset
bottomEdgeLeftInset: virtualJoystickMultiTouch.visible ? virtualJoystickMultiTouch.bottomEdgeLeftInset : parentToolInsets.bottomEdgeLeftInset
bottomEdgeCenterInset: bottomRightRowLayout.bottomEdgeCenterInset
bottomEdgeRightInset: virtualJoystickMultiTouch.visible ? virtualJoystickMultiTouch.bottomEdgeRightInset : bottomRightRowLayout.bottomEdgeRightInset
}
+ FlyViewTopRightPanel {
+ id: topRightPanel
+ anchors.top: parent.top
+ anchors.right: parent.right
+ anchors.topMargin: _layoutMargin
+ anchors.rightMargin: _layoutMargin
+ maximumHeight: parent.height - (bottomRightRowLayout.height + _margins * 5)
+
+ property real topEdgeRightInset: height + _layoutMargin
+ property real rightEdgeTopInset: width + _layoutMargin
+ property real rightEdgeCenterInset: rightEdgeTopInset
+ }
+
FlyViewTopRightColumnLayout {
id: topRightColumnLayout
anchors.margins: _layoutMargin
@@ -77,6 +90,7 @@ Item {
anchors.bottom: bottomRightRowLayout.top
anchors.right: parent.right
spacing: _layoutSpacing
+ visible: !topRightPanel.visible
property real topEdgeRightInset: childrenRect.height + _layoutMargin
property real rightEdgeTopInset: width + _layoutMargin
diff --git a/src/FlightDisplay/GuidedActionsController.qml b/src/FlightDisplay/GuidedActionsController.qml
index a8381956a6d..75df33d8b53 100644
--- a/src/FlightDisplay/GuidedActionsController.qml
+++ b/src/FlightDisplay/GuidedActionsController.qml
@@ -34,8 +34,10 @@ Item {
readonly property string emergencyStopTitle: qsTr("EMERGENCY STOP")
readonly property string armTitle: qsTr("Arm")
+ readonly property string mvArmTitle: qsTr("Arm (MV)")
readonly property string forceArmTitle: qsTr("Force Arm")
readonly property string disarmTitle: qsTr("Disarm")
+ readonly property string mvDisarmTitle: qsTr("Disarm (MV)")
readonly property string rtlTitle: qsTr("Return")
readonly property string takeoffTitle: qsTr("Takeoff")
readonly property string gripperTitle: qsTr("Gripper Function")
@@ -62,12 +64,15 @@ Item {
readonly property string changeHeadingTitle: qsTr("Change Heading")
readonly property string armMessage: qsTr("Arm the vehicle.")
+ readonly property string mvArmMessage: qsTr("Arm selected vehicles.")
readonly property string forceArmMessage: qsTr("WARNING: This will force arming of the vehicle bypassing any safety checks.")
readonly property string disarmMessage: qsTr("Disarm the vehicle")
+ readonly property string mvDisarmMessage: qsTr("Disarm selected vehicles.")
readonly property string emergencyStopMessage: qsTr("WARNING: THIS WILL STOP ALL MOTORS. IF VEHICLE IS CURRENTLY IN THE AIR IT WILL CRASH.")
readonly property string takeoffMessage: qsTr("Takeoff from ground and hold position.")
- readonly property string gripperMessage: qsTr("Grab or Release the cargo")
+ readonly property string gripperMessage: qsTr("Grab or Release the cargo")
readonly property string startMissionMessage: qsTr("Takeoff from ground and start the current mission.")
+ readonly property string mvStartMissionMessage: qsTr("Takeoff from ground and start the current mission for selected vehicles.")
readonly property string continueMissionMessage: qsTr("Continue the mission from the current waypoint.")
readonly property string resumeMissionUploadFailMessage: qsTr("Upload of resume mission failed. Confirm to retry upload")
readonly property string landMessage: qsTr("Land the vehicle at the current position.")
@@ -80,7 +85,7 @@ Item {
readonly property string orbitMessage: qsTr("Orbit the vehicle around the specified location.")
readonly property string landAbortMessage: qsTr("Abort the landing sequence.")
readonly property string pauseMessage: qsTr("Pause the vehicle at it's current position, adjusting altitude up or down as needed.")
- readonly property string mvPauseMessage: qsTr("Pause all vehicles at their current position.")
+ readonly property string mvPauseMessage: qsTr("Pause selected vehicles at their current position.")
readonly property string vtolTransitionFwdMessage: qsTr("Transition VTOL to fixed wing flight.")
readonly property string vtolTransitionMRMessage: qsTr("Transition VTOL to multi-rotor flight.")
readonly property string roiMessage: qsTr("Make the specified location a Region Of Interest.")
@@ -119,6 +124,10 @@ Item {
readonly property int actionSetEstimatorOrigin: 28
readonly property int actionSetFlightMode: 29
readonly property int actionChangeHeading: 30
+ readonly property int actionMVArm: 31
+ readonly property int actionMVDisarm: 32
+
+
readonly property int customActionStart: 10000 // Custom actions ids should start here so that they don't collide with the built in actions
@@ -417,6 +426,11 @@ Item {
confirmDialog.message = armMessage
confirmDialog.hideTrigger = Qt.binding(function() { return !showArm })
break;
+ case actionMVArm:
+ confirmDialog.title = mvArmTitle
+ confirmDialog.message = mvArmMessage
+ confirmDialog.hideTrigger = true
+ break;
case actionForceArm:
confirmDialog.title = forceArmTitle
confirmDialog.message = forceArmMessage
@@ -430,6 +444,11 @@ Item {
confirmDialog.message = disarmMessage
confirmDialog.hideTrigger = Qt.binding(function() { return !showDisarm })
break;
+ case actionMVDisarm:
+ confirmDialog.title = mvDisarmTitle
+ confirmDialog.message = mvDisarmMessage
+ confirmDialog.hideTrigger = true
+ break;
case actionEmergencyStop:
confirmDialog.title = emergencyStopTitle
confirmDialog.message = emergencyStopMessage
@@ -449,7 +468,7 @@ Item {
break;
case actionMVStartMission:
confirmDialog.title = mvStartMissionTitle
- confirmDialog.message = startMissionMessage
+ confirmDialog.message = mvStartMissionMessage
confirmDialog.hideTrigger = true
break;
case actionContinueMission:
@@ -576,7 +595,7 @@ Item {
// Executes the specified action
function executeAction(actionCode, actionData, sliderOutputValue, optionChecked) {
var i;
- var rgVehicle;
+ var selectedVehicles;
switch (actionCode) {
case actionRTL:
_activeVehicle.guidedModeRTL(optionChecked)
@@ -597,20 +616,35 @@ Item {
_activeVehicle.startMission()
break
case actionMVStartMission:
- rgVehicle = QGroundControl.multiVehicleManager.vehicles
- for (i = 0; i < rgVehicle.count; i++) {
- rgVehicle.get(i).startMission()
+ selectedVehicles = QGroundControl.multiVehicleManager.selectedVehicles
+ for (i = 0; i < selectedVehicles.count; i++) {
+ var vehicle = selectedVehicles.get(i)
+ if (vehicle.armed === true){
+ vehicle.startMission()
+ }
}
break
case actionArm:
_activeVehicle.armed = true
break
+ case actionMVArm:
+ selectedVehicles = QGroundControl.multiVehicleManager.selectedVehicles
+ for (i = 0; i < selectedVehicles.count; i++) {
+ selectedVehicles.get(i).armed = true
+ }
+ break
case actionForceArm:
_activeVehicle.forceArm()
break
case actionDisarm:
_activeVehicle.armed = false
break
+ case actionMVDisarm:
+ selectedVehicles = QGroundControl.multiVehicleManager.selectedVehicles
+ for (i = 0; i < selectedVehicles.count; i++) {
+ selectedVehicles.get(i).armed = false
+ }
+ break
case actionEmergencyStop:
_activeVehicle.emergencyStop()
break
@@ -638,9 +672,9 @@ Item {
_activeVehicle.guidedModeChangeAltitude(altitudeChangeInMeters, true /* pauseVehicle */)
break
case actionMVPause:
- rgVehicle = QGroundControl.multiVehicleManager.vehicles
- for (i = 0; i < rgVehicle.count; i++) {
- rgVehicle.get(i).pauseVehicle()
+ selectedVehicles = QGroundControl.multiVehicleManager.selectedVehicles
+ for (i = 0; i < selectedVehicles.count; i++) {
+ selectedVehicles.get(i).pauseVehicle()
}
break
case actionVtolTransitionToFwdFlight:
diff --git a/src/FlightDisplay/MultiVehicleList.qml b/src/FlightDisplay/MultiVehicleList.qml
index 73b2e56f7ae..95376cd702e 100644
--- a/src/FlightDisplay/MultiVehicleList.qml
+++ b/src/FlightDisplay/MultiVehicleList.qml
@@ -19,66 +19,102 @@ import QGroundControl.Vehicle
import QGroundControl.FlightMap
Item {
- property real _margin: ScreenTools.defaultFontPixelWidth / 2
- property real _widgetHeight: ScreenTools.defaultFontPixelHeight * 3
- property color _textColor: "black"
- property real _rectOpacity: 0.8
- property var _guidedController: globals.guidedControllerFlyView
-
- QGCPalette { id: qgcPal }
-
- Rectangle {
- id: mvCommands
- anchors.left: parent.left
- anchors.right: parent.right
- height: mvCommandsColumn.height + (_margin *2)
- color: qgcPal.missionItemEditor
- opacity: _rectOpacity
- radius: _margin
-
- DeadMouseArea {
- anchors.fill: parent
+ property real _margin: ScreenTools.defaultFontPixelWidth / 2
+ property real _widgetHeight: ScreenTools.defaultFontPixelHeight * 2
+ property var _guidedController: globals.guidedControllerFlyView
+ property var _activeVehicleColor: "green"
+ property var _activeVehicle: QGroundControl.multiVehicleManager.activeVehicle
+ property var selectedVehicles: QGroundControl.multiVehicleManager.selectedVehicles
+
+ property real innerColumnHeight
+
+ function armAvailable() {
+ for (var i = 0; i < selectedVehicles.count; i++) {
+ var vehicle = selectedVehicles.get(i)
+ if (vehicle.armed === false) {
+ return true
+ }
}
+ return false
+ }
- Column {
- id: mvCommandsColumn
- anchors.margins: _margin
- anchors.top: parent.top
- anchors.left: parent.left
- anchors.right: parent.right
- spacing: _margin
-
- QGCLabel {
- anchors.left: parent.left
- anchors.right: parent.right
- text: qsTr("The following commands will be applied to all vehicles")
- color: _textColor
- wrapMode: Text.WordWrap
- font.pointSize: ScreenTools.smallFontPointSize
+
+ function disarmAvailable() {
+ for (var i = 0; i < selectedVehicles.count; i++) {
+ var vehicle = selectedVehicles.get(i)
+ if (vehicle.armed === true) {
+ return true
}
+ }
+ return false
+ }
- Row {
- spacing: _margin
+ function startAvailable() {
+ for (var i = 0; i < selectedVehicles.count; i++) {
+ var vehicle = selectedVehicles.get(i)
+ if (vehicle.armed === true && vehicle.flightMode !== vehicle.missionFlightMode){
+ return true
+ }
+ }
+ return false
+ }
- QGCButton {
- text: qsTr("Pause")
- onClicked: _guidedController.confirmAction(_guidedController.actionMVPause)
- }
+ function pauseAvailable() {
+ for (var i = 0; i < selectedVehicles.count; i++) {
+ var vehicle = selectedVehicles.get(i)
+ if (vehicle.armed === true && vehicle.pauseVehicleSupported) {
+ return true
+ }
+ }
+ return false
+ }
- QGCButton {
- text: qsTr("Start Mission")
- onClicked: _guidedController.confirmAction(_guidedController.actionMVStartMission)
- }
+ function selectVehicle(vehicleId) {
+ QGroundControl.multiVehicleManager.selectVehicle(vehicleId)
+ }
+
+ function deselectVehicle(vehicleId) {
+ QGroundControl.multiVehicleManager.deselectVehicle(vehicleId)
+ }
+
+ function toggleSelect(vehicleId) {
+ if (!vehicleSelected(vehicleId)) {
+ selectVehicle(vehicleId)
+ } else {
+ deselectVehicle(vehicleId)
+ }
+ }
+
+ function selectAll() {
+ var vehicles = QGroundControl.multiVehicleManager.vehicles
+ for (var i = 0; i < vehicles.count; i++) {
+ var vehicle = vehicles.get(i)
+ var vehicleId = vehicle.id
+ if (!vehicleSelected(vehicleId)) {
+ selectVehicle(vehicleId)
+ }
+ }
+ }
+
+ function deselectAll() {
+ QGroundControl.multiVehicleManager.deselectAllVehicles()
+ }
+
+ function vehicleSelected(vehicleId) {
+ for (var i = 0; i < selectedVehicles.count; i++ ) {
+ var currentId = selectedVehicles.get(i).id
+ if (vehicleId === currentId) {
+ return true
}
}
+ return false
}
QGCListView {
- id: missionItemEditorListView
+ id: vehicleList
anchors.left: parent.left
anchors.right: parent.right
- anchors.topMargin: _margin
- anchors.top: mvCommands.bottom
+ anchors.top: parent.top
anchors.bottom: parent.bottom
spacing: ScreenTools.defaultFontPixelHeight / 2
orientation: ListView.Vertical
@@ -89,95 +125,80 @@ Item {
property real _cacheBuffer: height * 2
delegate: Rectangle {
- width: missionItemEditorListView.width
- height: innerColumn.y + innerColumn.height + _margin
- color: qgcPal.missionItemEditor
- opacity: _rectOpacity
- radius: _margin
+ width: vehicleList.width
+ height: innerColumn.y + innerColumn.height + _margin
+ color: QGroundControl.multiVehicleManager.activeVehicle == _vehicle ? _activeVehicleColor : qgcPal.button
+ radius: _margin
+ border.width: _vehicle && vehicleSelected(_vehicle.id) ? 2 : 0
+ border.color: qgcPal.text
property var _vehicle: object
- ColumnLayout {
- id: innerColumn
- anchors.margins: _margin
- anchors.top: parent.top
- anchors.left: parent.left
- anchors.right: parent.left
- spacing: _margin
+ Rectangle {
+ height: parent.height
+ width: innerColumn.width
+ anchors.horizontalCenter: parent.horizontalCenter
+ color: "transparent"
RowLayout {
- Layout.fillWidth: true
-
- QGCLabel {
- Layout.alignment: Qt.AlignTop
- text: _vehicle ? _vehicle.id : ""
- color: _textColor
- }
-
- ColumnLayout {
- Layout.alignment: Qt.AlignCenter
- spacing: _margin
-
- FlightModeMenu {
- Layout.alignment: Qt.AlignHCenter
- font.pointSize: ScreenTools.largeFontPointSize
- color: _textColor
- currentVehicle: _vehicle
- }
-
- QGCLabel {
- Layout.alignment: Qt.AlignHCenter
- text: _vehicle && _vehicle.armed ? qsTr("Armed") : qsTr("Disarmed")
- color: _textColor
- }
- }
+ id: innerColumn
+ anchors.margins: _margin
+ spacing: _margin
+ onHeightChanged: { innerColumnHeight = height + _margin * 2 + spacing * 2 }
QGCCompassWidget {
- size: _widgetHeight
- usedByMultipleVehicleList: true
- vehicle: _vehicle
+ id: compassWidget
+ size: _widgetHeight
+ usedByMultipleVehicleList: true
+ vehicle: _vehicle
}
- QGCAttitudeWidget {
- size: _widgetHeight
- vehicle: _vehicle
+ QGCLabel {
+ text: " | "
+ font.pointSize: ScreenTools.largeFontPointSize
+ color: qgcPal.text
+ Layout.alignment: Qt.AlignHCenter
}
- } // RowLayout
- Row {
- spacing: ScreenTools.defaultFontPixelWidth
-
- QGCButton {
- text: qsTr("Arm")
- visible: _vehicle && !_vehicle.armed
- onClicked: _vehicle.armed = true
+ QGCLabel {
+ text: _vehicle ? _vehicle.id : ""
+ font.pointSize: ScreenTools.largeFontPointSize
+ color: qgcPal.text
+ Layout.alignment: Qt.AlignHCenter
}
- QGCButton {
- text: qsTr("Start Mission")
- visible: _vehicle && _vehicle.armed && _vehicle.flightMode !== _vehicle.missionFlightMode
- onClicked: _vehicle.startMission()
+ QGCLabel {
+ text: " | "
+ font.pointSize: ScreenTools.largeFontPointSize
+ color: qgcPal.text
+ Layout.alignment: Qt.AlignHCenter
}
- QGCButton {
- text: qsTr("Pause")
- visible: _vehicle && _vehicle.armed && _vehicle.pauseVehicleSupported
- onClicked: _vehicle.pauseVehicle()
- }
+ ColumnLayout {
+ spacing: _margin
+ Layout.rightMargin: compassWidget.width / 4
+ Layout.alignment: Qt.AlignCenter
- QGCButton {
- text: qsTr("RTL")
- visible: _vehicle && _vehicle.armed && _vehicle.flightMode !== _vehicle.rtlFlightMode
- onClicked: _vehicle.flightMode = _vehicle.rtlFlightMode
- }
+ FlightModeMenu {
+ Layout.alignment: Qt.AlignHCenter
+ font.pointSize: ScreenTools.largeFontPointSize
+ color: qgcPal.text
+ currentVehicle: _vehicle
+ }
- QGCButton {
- text: qsTr("Take control")
- visible: _vehicle && _vehicle.armed && _vehicle.flightMode !== _vehicle.takeControlFlightMode
- onClicked: _vehicle.flightMode = _vehicle.takeControlFlightMode
+ QGCLabel {
+ Layout.alignment: Qt.AlignHCenter
+ text: _vehicle && _vehicle.armed ? qsTr("Armed") : qsTr("Disarmed")
+ color: qgcPal.text
+ }
}
- } // Row
- } // ColumnLayout
- } // delegate - Rectangle
- } // QGCListView
-} // Item
+ }
+ }
+
+ QGCMouseArea {
+ anchors.fill: parent
+ onClicked: toggleSelect(_vehicle.id)
+ }
+ }
+ }
+}
diff --git a/src/FlightMap/Widgets/CompassHeadingIndicator.qml b/src/FlightMap/Widgets/CompassHeadingIndicator.qml
index 4be55228c2e..110f4172eca 100644
--- a/src/FlightMap/Widgets/CompassHeadingIndicator.qml
+++ b/src/FlightMap/Widgets/CompassHeadingIndicator.qml
@@ -23,6 +23,7 @@ Canvas {
property real compassSize
property real heading
+ property bool simplified: false
property var _qgcPal: QGroundControl.globalPalette
@@ -33,7 +34,7 @@ Canvas {
onPaint: {
var ctx = getContext("2d")
- ctx.strokeStyle = _qgcPal.text
+ ctx.strokeStyle = simplified ? "#EE3424" : _qgcPal.text
ctx.fillStyle = "#EE3424"
ctx.lineWidth = 1
ctx.beginPath()
diff --git a/src/FlightMap/Widgets/QGCCompassWidget.qml b/src/FlightMap/Widgets/QGCCompassWidget.qml
index 55ae9ad2b0a..1255edc82be 100644
--- a/src/FlightMap/Widgets/QGCCompassWidget.qml
+++ b/src/FlightMap/Widgets/QGCCompassWidget.qml
@@ -21,13 +21,16 @@ Rectangle {
height: size
radius: width / 2
color: qgcPal.window
+ border.color: qgcPal.text
+ border.width: usedByMultipleVehicleList ? 1 : 0
+ opacity: vehicle && usedByMultipleVehicleList && !vehicle.armed ? 0.5 : 1
property real size: _defaultSize
property var vehicle: null
property bool usedByMultipleVehicleList: false
- property real _defaultSize: ScreenTools.defaultFontPixelHeight * (10)
- property real _sizeRatio: ScreenTools.isTinyScreen ? (size / _defaultSize) * 0.5 : size / _defaultSize
+ property real _defaultSize: usedByMultipleVehicleList ? ScreenTools.defaultFontPixelHeight * 3 : ScreenTools.defaultFontPixelHeight * 10
+ property real _sizeRatio: (usedByMultipleVehicleList || ScreenTools.isTinyScreen) ? (size / _defaultSize) * 0.5 : size / _defaultSize
property int _fontSize: ScreenTools.defaultFontPointSize * _sizeRatio < 8 ? 8 : ScreenTools.defaultFontPointSize * _sizeRatio
property real _heading: vehicle ? vehicle.heading.rawValue : 0
property real _headingToHome: vehicle ? vehicle.headingToHome.rawValue : 0
@@ -36,7 +39,7 @@ Rectangle {
property real _courseOverGround: vehicle ? vehicle.gps.courseOverGround.rawValue : 0
property var _flyViewSettings: QGroundControl.settingsManager.flyViewSettings
property bool _showAdditionalIndicators: _flyViewSettings.showAdditionalIndicatorsCompass.value && !usedByMultipleVehicleList
- property bool _lockNoseUpCompass: _flyViewSettings.lockNoseUpCompass.value
+ property bool _lockNoseUpCompass: _flyViewSettings.lockNoseUpCompass.value && !usedByMultipleVehicleList
function showCOG(){
if (_groundSpeed < 0.5) {
@@ -75,12 +78,14 @@ Rectangle {
}
CompassDial {
- anchors.fill: parent
+ anchors.fill: parent
+ visible: !usedByMultipleVehicleList
}
CompassHeadingIndicator {
compassSize: size
heading: _heading
+ simplified: usedByMultipleVehicleList
}
Image {
@@ -144,7 +149,7 @@ Rectangle {
QGCLabel {
anchors.horizontalCenter: parent.horizontalCenter
y: size * 0.74
- text: vehicle ? _heading.toFixed(0) + "°" : ""
+ text: vehicle && !usedByMultipleVehicleList ? _heading.toFixed(0) + "°" : ""
horizontalAlignment: Text.AlignHCenter
}
}
diff --git a/src/QmlControls/MvPanelPage.qml b/src/QmlControls/MvPanelPage.qml
new file mode 100644
index 00000000000..9c35438eb6b
--- /dev/null
+++ b/src/QmlControls/MvPanelPage.qml
@@ -0,0 +1,28 @@
+import QtQuick
+import QtQuick.Controls
+
+import QGroundControl
+import QGroundControl.ScreenTools
+import QGroundControl.Palette
+
+Item {
+ property bool showBorder: true
+ property real contentMargin: ScreenTools.defaultFontPixelHeight
+ default property alias contentChildren: contentContainer.data
+
+ Rectangle {
+ color: "transparent"
+ anchors.fill: parent
+ border.color: QGroundControl.globalPalette.groupBorder
+ border.width: showBorder ? 1 : 0
+ radius: ScreenTools.defaultFontPixelHeight / 3
+
+ Item {
+ id: contentContainer
+ anchors.fill: parent
+ anchors.margins: contentMargin / 2
+ anchors.bottomMargin: contentMargin * 2
+ }
+ }
+
+}
diff --git a/src/QmlControls/QGCPageIndicator.qml b/src/QmlControls/QGCPageIndicator.qml
new file mode 100644
index 00000000000..a4eef9bb535
--- /dev/null
+++ b/src/QmlControls/QGCPageIndicator.qml
@@ -0,0 +1,6 @@
+import QtQuick
+import QtQuick.Controls
+
+PageIndicator {
+
+}
diff --git a/src/QmlControls/QGCSwipeView.qml b/src/QmlControls/QGCSwipeView.qml
new file mode 100644
index 00000000000..f6fae4e9da7
--- /dev/null
+++ b/src/QmlControls/QGCSwipeView.qml
@@ -0,0 +1,7 @@
+import QtQuick
+import QtQuick.Controls
+
+
+SwipeView {
+
+}
diff --git a/src/QmlControls/QGroundControl/Controls/qmldir b/src/QmlControls/QGroundControl/Controls/qmldir
index 142d5eb1061..3f15ed111b5 100644
--- a/src/QmlControls/QGroundControl/Controls/qmldir
+++ b/src/QmlControls/QGroundControl/Controls/qmldir
@@ -49,6 +49,7 @@ MissionItemEditor 1.0 MissionItemEditor.qml
MissionItemIndexLabel 1.0 MissionItemIndexLabel.qml
MissionItemMapVisual 1.0 MissionItemMapVisual.qml
MissionItemStatus 1.0 MissionItemStatus.qml
+MvPanelPage 1.0 MvPanelPage.qml
OfflineMapButton 1.0 OfflineMapButton.qml
OfflineMapEditor 1.0 OfflineMapEditor.qml
OfflineMapInfo 1.0 OfflineMapInfo.qml
@@ -84,11 +85,13 @@ QGCMenuSeparator 1.0 QGCMenuSeparator.qml
QGCMouseArea 1.0 QGCMouseArea.qml
QGCMovableItem 1.0 QGCMovableItem.qml
QGCOptionsComboBox 1.0 QGCOptionsComboBox.qml
+QGCPageIndicator 1.0 QGCPageIndicator.qml
QGCPopupDialog 1.0 QGCPopupDialog.qml
QGCRadioButton 1.0 QGCRadioButton.qml
QGCRoundButton 1.0 QGCRoundButton.qml
QGCSimpleMessageDialog 1.0 QGCSimpleMessageDialog.qml
QGCSlider 1.0 QGCSlider.qml
+QGCSwipeView 1.0 QGCSwipeView.qml
QGCSwitch 1.0 QGCSwitch.qml
QGCTabBar 1.0 QGCTabBar.qml
QGCTabButton 1.0 QGCTabButton.qml
diff --git a/src/QmlControls/QGroundControl/FlightDisplay/qmldir b/src/QmlControls/QGroundControl/FlightDisplay/qmldir
index 888f82ab0f1..79d0a3c817f 100644
--- a/src/QmlControls/QGroundControl/FlightDisplay/qmldir
+++ b/src/QmlControls/QGroundControl/FlightDisplay/qmldir
@@ -16,6 +16,7 @@ FlyViewToolBarIndicators 1.0 FlyViewToolBarIndicators.qml
FlyViewToolStrip 1.0 FlyViewToolStrip.qml
FlyViewToolStripActionList 1.0 FlyViewToolStripActionList.qml
FlyViewTopRightColumnLayout 1.0 FlyViewTopRightColumnLayout.qml
+FlyViewTopRightPanel 1.0 FlyViewTopRightPanel.qml
FlyViewVideo 1.0 FlyViewVideo.qml
FlyViewWidgetLayer 1.0 FlyViewWidgetLayer.qml
GripperMenu 1.0 GripperMenu.qml
diff --git a/src/Settings/App.SettingsGroup.json b/src/Settings/App.SettingsGroup.json
index 3f1b3412584..17a585f0f95 100644
--- a/src/Settings/App.SettingsGroup.json
+++ b/src/Settings/App.SettingsGroup.json
@@ -138,6 +138,13 @@
"type": "bool",
"default": false
},
+{
+ "name": "enableMultiVehiclePanel",
+ "shortDesc": "Enable Multi-Vehicle Panel",
+ "longDesc": "Enable Multi-Vehicle Panel when multiple vehicles are connected.",
+ "type": "bool",
+ "default": true
+},
{
"name": "appFontPointSize",
"shortDesc": "Application font size",
diff --git a/src/Settings/AppSettings.cc b/src/Settings/AppSettings.cc
index daae122795a..708c23e08a3 100644
--- a/src/Settings/AppSettings.cc
+++ b/src/Settings/AppSettings.cc
@@ -157,6 +157,7 @@ DECLARE_SETTINGSFACT(AppSettings, savePath)
DECLARE_SETTINGSFACT(AppSettings, androidSaveToSDCard)
DECLARE_SETTINGSFACT(AppSettings, useChecklist)
DECLARE_SETTINGSFACT(AppSettings, enforceChecklist)
+DECLARE_SETTINGSFACT(AppSettings, enableMultiVehiclePanel)
DECLARE_SETTINGSFACT(AppSettings, mapboxToken)
DECLARE_SETTINGSFACT(AppSettings, mapboxAccount)
DECLARE_SETTINGSFACT(AppSettings, mapboxStyle)
diff --git a/src/Settings/AppSettings.h b/src/Settings/AppSettings.h
index c6a10f9693f..63e7216920f 100644
--- a/src/Settings/AppSettings.h
+++ b/src/Settings/AppSettings.h
@@ -43,6 +43,7 @@ class AppSettings : public SettingsGroup
DEFINE_SETTINGFACT(androidSaveToSDCard)
DEFINE_SETTINGFACT(useChecklist)
DEFINE_SETTINGFACT(enforceChecklist)
+ DEFINE_SETTINGFACT(enableMultiVehiclePanel)
DEFINE_SETTINGFACT(mapboxToken)
DEFINE_SETTINGFACT(mapboxAccount)
DEFINE_SETTINGFACT(mapboxStyle)
diff --git a/src/UI/preferences/FlyViewSettings.qml b/src/UI/preferences/FlyViewSettings.qml
index 560982c0188..3e07a88a050 100644
--- a/src/UI/preferences/FlyViewSettings.qml
+++ b/src/UI/preferences/FlyViewSettings.qml
@@ -28,6 +28,7 @@ SettingsPage {
property var _customMavlinkActionsSettings: _settingsManager.customMavlinkActionsSettings
property Fact _virtualJoystick: _settingsManager.appSettings.virtualJoystick
property Fact _virtualJoystickAutoCenterThrottle: _settingsManager.appSettings.virtualJoystickAutoCenterThrottle
+ property Fact _enableMultiVehiclePanel: _settingsManager.appSettings.enableMultiVehiclePanel
property Fact _showAdditionalIndicatorsCompass: _flyViewSettings.showAdditionalIndicatorsCompass
property Fact _lockNoseUpCompass: _flyViewSettings.lockNoseUpCompass
property Fact _guidedMinimumAltitude: _flyViewSettings.guidedMinimumAltitude
@@ -69,6 +70,13 @@ SettingsPage {
property Fact _enforceChecklist: _settingsManager.appSettings.enforceChecklist
}
+ FactCheckBoxSlider {
+ Layout.fillWidth: true
+ text: qsTr("Enable Multi-Vehicle Panel")
+ fact: _enableMultiVehiclePanel
+ visible: _enableMultiVehiclePanel.visible
+ }
+
FactCheckBoxSlider {
Layout.fillWidth: true
text: qsTr("Keep Map Centered On Vehicle")
diff --git a/src/UI/toolbar/MultiVehicleSelector.qml b/src/UI/toolbar/MultiVehicleSelector.qml
index 215e07efb6a..5881dd1baa6 100644
--- a/src/UI/toolbar/MultiVehicleSelector.qml
+++ b/src/UI/toolbar/MultiVehicleSelector.qml
@@ -7,61 +7,112 @@
*
****************************************************************************/
-
import QtQuick
import QtQuick.Controls
+import QtQuick.Layouts
import QGroundControl
+import QGroundControl.FactSystem
+import QGroundControl.FactControls
import QGroundControl.Controls
import QGroundControl.MultiVehicleManager
import QGroundControl.ScreenTools
import QGroundControl.Palette
-//-------------------------------------------------------------------------
-//-- Multiple Vehicle Selector
-QGCComboBox {
- anchors.verticalCenter: parent.verticalCenter
- font.pointSize: ScreenTools.mediumFontPointSize
- currentIndex: -1
- sizeToContents: true
- model: _vehicleModel
-
- property bool showIndicator: _multipleVehicles
+RowLayout {
+ id: control
+ spacing: 0
- property var _activeVehicle: QGroundControl.multiVehicleManager.activeVehicle
- property bool _multipleVehicles: QGroundControl.multiVehicleManager.vehicles.count > 1
- property var _vehicleModel: [ ]
+ property bool showIndicator: _multipleVehicles
+ property var _activeVehicle: QGroundControl.multiVehicleManager.activeVehicle
+ property bool _multipleVehicles: QGroundControl.multiVehicleManager.vehicles.count > 1
+ property var _vehicleModel: [ ]
Connections {
target: QGroundControl.multiVehicleManager.vehicles
- onCountChanged: _updateVehicleModel()
+ onCountChanged: _updateVehicleModel()
}
Component.onCompleted: _updateVehicleModel()
on_ActiveVehicleChanged: _updateVehicleModel()
+ RowLayout {
+ Layout.fillWidth: true
+
+ QGCColoredImage {
+ width: ScreenTools.defaultFontPixelWidth * 4
+ height: ScreenTools.defaultFontPixelHeight * 1.33
+ fillMode: Image.PreserveAspectFit
+ mipmap: true
+ color: qgcPal.text
+ source: "/InstrumentValueIcons/airplane.svg"
+ }
+
+ QGCLabel {
+ text: _activeVehicle ? qsTr("Vehicle") + " " + _activeVehicle.id : qsTr("N/A")
+ font.pointSize: ScreenTools.mediumFontPointSize
+ Layout.alignment: Qt.AlignCenter
+
+ MouseArea {
+ anchors.fill: parent
+ onClicked: mainWindow.showIndicatorDrawer(vehicleSelectorDrawer, control)
+ }
+ }
+ }
+
+ Component {
+ id: vehicleSelectorDrawer
+
+ ToolIndicatorPage {
+ showExpand: true
+
+ contentComponent: Component {
+ ColumnLayout {
+ spacing: ScreenTools.defaultFontPixelWidth / 2
+
+ Repeater {
+ model: _vehicleModel
+
+ QGCButton {
+ text: modelData
+ Layout.fillWidth: true
+
+ onClicked: {
+ var vehicleId = modelData.split(" ")[1]
+ var vehicle = QGroundControl.multiVehicleManager.getVehicleById(vehicleId)
+ QGroundControl.multiVehicleManager.activeVehicle = vehicle
+ mainWindow.closeIndicatorDrawer()
+ }
+ }
+ }
+ }
+ }
+
+ expandedComponent: Component {
+ SettingsGroupLayout {
+ Layout.fillWidth: true
+
+ FactCheckBoxSlider {
+ Layout.fillWidth: true
+ text: qsTr("Enable Multi-Vehicle Panel")
+ fact: _enableMultiVehiclePanel
+ visible: _enableMultiVehiclePanel.visible
+
+ property Fact _enableMultiVehiclePanel: QGroundControl.settingsManager.appSettings.enableMultiVehiclePanel
+ }
+ }
+ }
+ }
+ }
+
function _updateVehicleModel() {
- var newCurrentIndex = -1
var newModel = [ ]
if (_multipleVehicles) {
for (var i = 0; i < QGroundControl.multiVehicleManager.vehicles.count; i++) {
var vehicle = QGroundControl.multiVehicleManager.vehicles.get(i)
newModel.push(qsTr("Vehicle") + " " + vehicle.id)
-
- if (vehicle.id === _activeVehicle.id) {
- newCurrentIndex = i
- }
}
}
- currentIndex = -1
_vehicleModel = newModel
- currentIndex = newCurrentIndex
- }
-
- onActivated: (index) => {
- var vehicleId = textAt(index).split(" ")[1]
- var vehicle = QGroundControl.multiVehicleManager.getVehicleById(vehicleId)
- QGroundControl.multiVehicleManager.activeVehicle = vehicle
}
}
-
diff --git a/src/Vehicle/MultiVehicleManager.cc b/src/Vehicle/MultiVehicleManager.cc
index 52cf5418f53..060cc8f71e8 100644
--- a/src/Vehicle/MultiVehicleManager.cc
+++ b/src/Vehicle/MultiVehicleManager.cc
@@ -42,6 +42,7 @@ MultiVehicleManager::MultiVehicleManager(QObject *parent)
, _gcsHeartbeatTimer(new QTimer(this))
, _offlineEditingVehicle(new Vehicle(Vehicle::MAV_AUTOPILOT_TRACK, Vehicle::MAV_TYPE_TRACK, this))
, _vehicles(new QmlObjectListModel(this))
+ , _selectedVehicles(new QmlObjectListModel(this))
{
// qCDebug(MultiVehicleManagerLog) << Q_FUNC_INFO << this;
}
@@ -206,6 +207,8 @@ void MultiVehicleManager::_deleteVehiclePhase1(Vehicle *vehicle)
qCWarning(MultiVehicleManagerLog) << "Vehicle not found in map!";
}
+ deselectVehicle(vehicle->id());
+
_setActiveVehicleAvailable(false);
_setParameterReadyVehicleAvailable(false);
emit vehicleRemoved(vehicle);
@@ -333,6 +336,42 @@ void MultiVehicleManager::_sendGCSHeartbeat()
}
}
+void MultiVehicleManager::selectVehicle(int vehicleId)
+{
+ if(!_vehicleSelected(vehicleId)) {
+ Vehicle *const vehicle = getVehicleById(vehicleId);
+ _selectedVehicles->append(vehicle);
+ return;
+ }
+}
+
+void MultiVehicleManager::deselectVehicle(int vehicleId)
+{
+ for (int i = 0; i < _selectedVehicles->count(); i++) {
+ Vehicle *const vehicle = qobject_cast(_selectedVehicles->get(i));
+ if (vehicle->id() == vehicleId) {
+ _selectedVehicles->removeAt(i);
+ return;
+ }
+ }
+}
+
+void MultiVehicleManager::deselectAllVehicles()
+{
+ _selectedVehicles->clear();
+}
+
+bool MultiVehicleManager::_vehicleSelected(int vehicleId)
+{
+ for (int i = 0; i < _selectedVehicles->count(); i++) {
+ Vehicle *const vehicle = qobject_cast(_selectedVehicles->get(i));
+ if (vehicle->id() == vehicleId) {
+ return true;
+ }
+ }
+ return false;
+}
+
Vehicle *MultiVehicleManager::getVehicleById(int vehicleId) const
{
for (int i = 0; i < _vehicles->count(); i++) {
diff --git a/src/Vehicle/MultiVehicleManager.h b/src/Vehicle/MultiVehicleManager.h
index fc4cf5057d4..389754d42a0 100644
--- a/src/Vehicle/MultiVehicleManager.h
+++ b/src/Vehicle/MultiVehicleManager.h
@@ -33,6 +33,7 @@ class MultiVehicleManager : public QObject
Q_PROPERTY(bool parameterReadyVehicleAvailable READ _getParameterReadyVehicleAvailable NOTIFY parameterReadyVehicleAvailableChanged)
Q_PROPERTY(Vehicle *activeVehicle READ activeVehicle WRITE setActiveVehicle NOTIFY activeVehicleChanged)
Q_PROPERTY(QmlObjectListModel *vehicles READ vehicles CONSTANT)
+ Q_PROPERTY(QmlObjectListModel *selectedVehicles READ selectedVehicles CONSTANT)
Q_PROPERTY(bool gcsHeartBeatEnabled READ _getGcsHeartbeatEnabled WRITE _setGcsHeartbeatEnabled NOTIFY gcsHeartBeatEnabledChanged)
Q_PROPERTY(Vehicle *offlineEditingVehicle READ offlineEditingVehicle CONSTANT)
@@ -45,7 +46,11 @@ class MultiVehicleManager : public QObject
void init();
Q_INVOKABLE Vehicle *getVehicleById(int vehicleId) const;
+ Q_INVOKABLE void selectVehicle(int vehicleId);
+ Q_INVOKABLE void deselectVehicle(int vehicleId);
+ Q_INVOKABLE void deselectAllVehicles();
QmlObjectListModel *vehicles() const { return _vehicles; }
+ QmlObjectListModel *selectedVehicles() const { return _selectedVehicles; }
Vehicle *offlineEditingVehicle() const { return _offlineEditingVehicle; }
Vehicle *activeVehicle() const { return _activeVehicle; }
void setActiveVehicle(Vehicle *vehicle);
@@ -69,6 +74,7 @@ private slots:
private:
bool _vehicleExists(int vehicleId);
+ bool _vehicleSelected(int vehicleId);
void _setActiveVehicle(Vehicle *vehicle);
bool _getGcsHeartbeatEnabled() const { return _gcsHeartbeatEnabled; }
void _setGcsHeartbeatEnabled(bool gcsHeartBeatEnabled);
@@ -80,6 +86,7 @@ private slots:
QTimer *_gcsHeartbeatTimer = nullptr; ///< Timer to emit heartbeats
Vehicle *_offlineEditingVehicle = nullptr; ///< Disconnected vechicle used for offline editing
QmlObjectListModel *_vehicles = nullptr;
+ QmlObjectListModel *_selectedVehicles = nullptr;
bool _activeVehicleAvailable = false; ///< true: An active vehicle is available
bool _gcsHeartbeatEnabled = false; ///< Enabled/disable heartbeat emission
bool _parameterReadyVehicleAvailable = false; ///< true: An active vehicle with ready parameters is available