diff --git a/qgroundcontrol.qrc b/qgroundcontrol.qrc
index 61516930996..492659b9a6a 100644
--- a/qgroundcontrol.qrc
+++ b/qgroundcontrol.qrc
@@ -133,6 +133,7 @@
src/PlanView/MissionItemStatus.qml
src/QmlControls/ModeSwitchDisplay.qml
src/QmlControls/MultiRotorMotorDisplay.qml
+ src/QmlControls/MvPanelPage.qml
src/QmlControls/OfflineMapButton.qml
src/QtLocationPlugin/QMLControl/OfflineMapEditor.qml
src/UI/preferences/OfflineMapInfo.qml
@@ -168,12 +169,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
@@ -351,6 +354,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..332ee4af10b 100644
--- a/src/FlightDisplay/FlyViewTopRightColumnLayout.qml
+++ b/src/FlightDisplay/FlyViewTopRightColumnLayout.qml
@@ -20,28 +20,7 @@ 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
- }
- }
+ property bool mvPanelVisible: false
TerrainProgress {
Layout.alignment: Qt.AlignTop
@@ -54,7 +33,7 @@ ColumnLayout {
Loader {
id: photoVideoControlLoader
Layout.alignment: Qt.AlignTop | Qt.AlignRight
- sourceComponent: globals.activeVehicle && _showSingleVehicleUI ? photoVideoControlComponent : undefined
+ sourceComponent: globals.activeVehicle && !mvPanelVisible ? photoVideoControlComponent : undefined
property real rightEdgeCenterInset: visible ? parent.width - x : 0
@@ -65,10 +44,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..af4a00aaf90
--- /dev/null
+++ b/src/FlightDisplay/FlyViewTopRightPanel.qml
@@ -0,0 +1,213 @@
+/****************************************************************************
+ *
+ * (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.Controls
+import QGroundControl.FlightDisplay
+import QGroundControl.FlightMap
+import QGroundControl.Palette
+import QGroundControl.ScreenTools
+
+
+Item {
+
+ property bool panelVisible: togglePanelBtn.checked
+ property alias toggleBtn: togglePanelBtn
+
+ Rectangle {
+ id: topRightPanel
+ anchors.fill: parent
+ color: qgcPal.toolbarBackground
+ visible: !QGroundControl.videoManager.fullScreen && togglePanelBtn.checked
+ clip: true
+
+ QGCPalette { id: qgcPal }
+
+ MultiVehicleList {
+ id: multiVehicleList
+ anchors.top: parent.top
+ anchors.bottom: parent.verticalCenter
+ anchors.right: parent.right
+ anchors.left: parent.left
+ anchors.margins: ScreenTools.defaultFontPixelHeight / 2
+
+ Rectangle {
+ anchors.fill: parent
+
+ gradient: Gradient {
+ orientation: Gradient.Vertical
+
+ GradientStop { position: 0.95; color: "transparent" }
+ GradientStop { position: 1.0; color: topRightPanel.color }
+ }
+
+ Rectangle {
+ anchors.left: parent.left
+ anchors.right: parent.right
+ anchors.bottom: parent.bottom
+ height: 1
+ color: QGroundControl.globalPalette.groupBorder
+ }
+ }
+
+ }
+
+ QGCSwipeView {
+ id: swipePages
+ anchors.top: parent.verticalCenter
+ anchors.bottom: parent.bottom
+ anchors.right: parent.right
+ anchors.left: parent.left
+
+ MvPanelPage {
+ id: buttonsPage
+
+ ColumnLayout {
+ anchors.right: parent.right
+ anchors.left: parent.left
+ anchors.verticalCenter: parent.verticalCenter
+ anchors.bottomMargin: ScreenTools.defaultFontPixelHeight * 3
+ spacing: ScreenTools.defaultFontPixelHeight / 2
+
+ 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()
+ Layout.preferredWidth: ScreenTools.defaultFontPixelHeight * 5
+ }
+
+ QGCButton {
+ text: qsTr("Deselect All")
+ enabled: multiVehicleList.selectedVehicles && multiVehicleList.selectedVehicles.count > 0
+ onClicked: multiVehicleList.deselectAll()
+ Layout.preferredWidth: ScreenTools.defaultFontPixelHeight * 5
+
+ }
+ }
+
+
+ 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 {
+
+ // 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
+ anchors.bottomMargin: ScreenTools.defaultFontPixel
+ sourceComponent: globals.activeVehicle && togglePanelBtn.checked ? photoVideoControlComponent : undefined
+
+ property real rightEdgeCenterInset: visible ? parent.width - x : 0
+
+ Component {
+ id: photoVideoControlComponent
+
+ PhotoVideoControl {
+ }
+ }
+ }
+ } // Page 2
+ }
+
+ QGCPageIndicator {
+ id: pageIndicator
+ count: swipePages.count
+ currentIndex: swipePages.currentIndex
+ anchors.horizontalCenter: parent.horizontalCenter
+ anchors.bottom: parent.bottom
+ anchors.bottomMargin: togglePanelBtn.height
+
+ 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
+ }
+ }
+ }
+
+ QGCButton {
+ id: togglePanelBtn
+ anchors.top: parent.top
+ anchors.horizontalCenter: parent.horizontalCenter
+ anchors.topMargin: topRightPanel.visible ? parent.height : 0
+ width: _rightPanelWidth / 5
+ height: _rightPanelWidth / 18
+ checkable: true
+
+ background: Rectangle {
+ radius: parent.height / 2
+ color: qgcPal.toolbarBackground
+ border.color: parent.checked ? QGroundControl.globalPalette.groupBorder : qgcPal.text
+ border.width: 1
+ }
+ }
+}
diff --git a/src/FlightDisplay/FlyViewWidgetLayer.qml b/src/FlightDisplay/FlyViewWidgetLayer.qml
index 55f8341dc3c..8638557e198 100644
--- a/src/FlightDisplay/FlyViewWidgetLayer.qml
+++ b/src/FlightDisplay/FlyViewWidgetLayer.qml
@@ -46,7 +46,7 @@ Item {
property real _margins: ScreenTools.defaultFontPixelWidth / 2
property real _toolsMargin: ScreenTools.defaultFontPixelWidth * 0.75
property rect _centerViewport: Qt.rect(0, 0, width, height)
- property real _rightPanelWidth: ScreenTools.defaultFontPixelWidth * 30
+ property real _rightPanelWidth: ScreenTools.defaultFontPixelWidth * 40
property alias _gripperMenu: gripperOptions
property real _layoutMargin: ScreenTools.defaultFontPixelWidth * 0.75
property bool _layoutSpacing: ScreenTools.defaultFontPixelWidth
@@ -59,24 +59,39 @@ 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.rightMargin: _layoutMargin
+ width: _rightPanelWidth
+ height: _rightPanelWidth * 1.75
+
+ property real topEdgeRightInset: height + _layoutMargin
+ property real rightEdgeTopInset: width + _layoutMargin
+ property real rightEdgeCenterInset: rightEdgeTopInset
+ }
+
FlyViewTopRightColumnLayout {
id: topRightColumnLayout
anchors.margins: _layoutMargin
- anchors.top: parent.top
+ anchors.top: topRightPanel.top
anchors.bottom: bottomRightRowLayout.top
anchors.right: parent.right
+ anchors.topMargin: topRightPanel.toggleBtn.height + _toolsMargin
spacing: _layoutSpacing
+ mvPanelVisible: topRightPanel.panelVisible
property real topEdgeRightInset: childrenRect.height + _layoutMargin
property real rightEdgeTopInset: width + _layoutMargin
diff --git a/src/FlightDisplay/GuidedActionsController.qml b/src/FlightDisplay/GuidedActionsController.qml
index 7328690aef3..e374cc54005 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
+
+
property var _activeVehicle: QGroundControl.multiVehicleManager.activeVehicle
property var _flyViewSettings: QGroundControl.settingsManager.flyViewSettings
@@ -405,6 +414,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
@@ -418,6 +432,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
@@ -437,7 +456,7 @@ Item {
break;
case actionMVStartMission:
confirmDialog.title = mvStartMissionTitle
- confirmDialog.message = startMissionMessage
+ confirmDialog.message = mvStartMissionMessage
confirmDialog.hideTrigger = true
break;
case actionContinueMission:
@@ -562,7 +581,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)
@@ -583,20 +602,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
@@ -624,9 +658,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..310294942ca 100644
--- a/src/FlightDisplay/MultiVehicleList.qml
+++ b/src/FlightDisplay/MultiVehicleList.qml
@@ -19,66 +19,103 @@ 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
+ 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
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
+ 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 +126,91 @@ 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) ? 1 : 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
+ id: innerColumn
+ anchors.margins: _margin
+ spacing: _margin
- QGCLabel {
- Layout.alignment: Qt.AlignTop
- text: _vehicle ? _vehicle.id : ""
- color: _textColor
+ QGCCompassWidget {
+ id: compassWidget
+ size: _widgetHeight
+ usedByMultipleVehicleList: true
+ vehicle: _vehicle
}
- 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
- }
+ QGCLabel {
+ text: " | "
+ font.pointSize: ScreenTools.largeFontPointSize
+ color: qgcPal.text
+ Layout.alignment: Qt.AlignHCenter
}
- QGCCompassWidget {
- size: _widgetHeight
- usedByMultipleVehicleList: true
- vehicle: _vehicle
+ QGCLabel {
+ text: _vehicle ? _vehicle.id : ""
+ font.pointSize: ScreenTools.largeFontPointSize
+ color: qgcPal.text
+ Layout.alignment: Qt.AlignHCenter
}
- 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
- }
+ ColumnLayout {
+ spacing: _margin
+ Layout.rightMargin: compassWidget.width / 4
+ Layout.alignment: Qt.AlignCenter
- QGCButton {
- text: qsTr("Start Mission")
- visible: _vehicle && _vehicle.armed && _vehicle.flightMode !== _vehicle.missionFlightMode
- onClicked: _vehicle.startMission()
- }
+ FlightModeMenu {
+ Layout.alignment: Qt.AlignHCenter
+ font.pointSize: ScreenTools.largeFontPointSize
+ color: qgcPal.text
+ currentVehicle: _vehicle
+ }
- QGCButton {
- text: qsTr("Pause")
- visible: _vehicle && _vehicle.armed && _vehicle.pauseVehicleSupported
- onClicked: _vehicle.pauseVehicle()
+ QGCLabel {
+ Layout.alignment: Qt.AlignHCenter
+ text: _vehicle && _vehicle.armed ? qsTr("Armed") : qsTr("Disarmed")
+ color: qgcPal.text
+ }
}
+ }
+ }
- QGCButton {
- text: qsTr("RTL")
- visible: _vehicle && _vehicle.armed && _vehicle.flightMode !== _vehicle.rtlFlightMode
- onClicked: _vehicle.flightMode = _vehicle.rtlFlightMode
- }
+ QGCMouseArea {
+ anchors.fill: parent
+ onClicked: singleClickTimer.start()
+ onDoubleClicked: {
+ singleClickTimer.stop()
+ QGroundControl.multiVehicleManager.activeVehicle = _vehicle
+ }
- QGCButton {
- text: qsTr("Take control")
- visible: _vehicle && _vehicle.armed && _vehicle.flightMode !== _vehicle.takeControlFlightMode
- onClicked: _vehicle.flightMode = _vehicle.takeControlFlightMode
- }
- } // Row
- } // ColumnLayout
- } // delegate - Rectangle
- } // QGCListView
-} // Item
+ Timer {
+ id: singleClickTimer
+ interval: 20
+ running: false
+ repeat: false
+ onTriggered: 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..18c81c2456e 100644
--- a/src/FlightMap/Widgets/QGCCompassWidget.qml
+++ b/src/FlightMap/Widgets/QGCCompassWidget.qml
@@ -21,12 +21,15 @@ 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 _defaultSize: usedByMultipleVehicleList ? ScreenTools.defaultFontPixelHeight * 3 : ScreenTools.defaultFontPixelHeight * 10
property real _sizeRatio: 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
@@ -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..dd51a30b985
--- /dev/null
+++ b/src/QmlControls/MvPanelPage.qml
@@ -0,0 +1,33 @@
+import QtQuick
+import QtQuick.Controls
+
+import QGroundControl
+import QGroundControl.ScreenTools
+import QGroundControl.Palette
+
+Item {
+ property bool showBorder: true
+ property real contentMargin: _margins * 2
+ default property alias contentChildren: contentContainer.data
+
+ property real _margins: ScreenTools.defaultFontPixelHeight / 2
+
+ Rectangle {
+ color: "transparent"
+ x: _margins
+ y: _margins
+ height: parent.height - _margins * 2
+ width: parent.width - _margins * 2
+ border.color: QGroundControl.globalPalette.groupBorder
+ border.width: showBorder ? 1 : 0
+ radius: ScreenTools.defaultFontPixelHeight / 2
+
+
+ Item {
+ id: contentContainer
+ anchors.fill: parent
+ anchors.margins: _margins
+ }
+ }
+
+}
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 816f521baca..258a668db60 100644
--- a/src/QmlControls/QGroundControl/Controls/qmldir
+++ b/src/QmlControls/QGroundControl/Controls/qmldir
@@ -55,6 +55,7 @@ MissionItemMapVisual 1.0 MissionItemMapVisual.qml
MissionItemStatus 1.0 MissionItemStatus.qml
ModeSwitchDisplay 1.0 ModeSwitchDisplay.qml
MultiRotorMotorDisplay 1.0 MultiRotorMotorDisplay.qml
+MvPanelPage 1.0 MvPanelPage.qml
OfflineMapButton 1.0 OfflineMapButton.qml
OfflineMapEditor 1.0 OfflineMapEditor.qml
OfflineMapInfo 1.0 OfflineMapInfo.qml
@@ -89,10 +90,12 @@ QGCMovableItem 1.0 QGCMovableItem.qml
QGCOptionsComboBox 1.0 QGCOptionsComboBox.qml
PipView 1.0 PipView.qml
PipState 1.0 PipState.qml
+QGCPageIndicator 1.0 QGCPageIndicator.qml
QGCPopupDialog 1.0 QGCPopupDialog.qml
QGCRadioButton 1.0 QGCRadioButton.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 4340d2b3e96..ffff9bc2914 100644
--- a/src/QmlControls/QGroundControl/FlightDisplay/qmldir
+++ b/src/QmlControls/QGroundControl/FlightDisplay/qmldir
@@ -12,6 +12,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
FlyViewInsetViewer 1.0 FlyViewInsetViewer.qml
diff --git a/src/Vehicle/MultiVehicleManager.cc b/src/Vehicle/MultiVehicleManager.cc
index 48231e1ba75..5ef6c2b951f 100644
--- a/src/Vehicle/MultiVehicleManager.cc
+++ b/src/Vehicle/MultiVehicleManager.cc
@@ -327,6 +327,41 @@ QString MultiVehicleManager::loadSetting(const QString &name, const QString& def
return settings.value(name, defaultValue).toString();
}
+void MultiVehicleManager::selectVehicle(int vehicleId)
+{
+ if(!_vehicleSelected(vehicleId)) {
+ Vehicle* vehicle = getVehicleById(vehicleId);
+ _selectedVehicles.append(vehicle);
+ }
+}
+
+void MultiVehicleManager::deselectVehicle(int vehicleId)
+{
+ for (int i=0; i<_selectedVehicles.count(); i++) {
+ Vehicle* vehicle = qobject_cast(_selectedVehicles[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* vehicle = qobject_cast(_selectedVehicles[i]);
+ if (vehicle->id() == vehicleId) {
+ return true;
+ }
+ }
+ return false;
+}
+
Vehicle* MultiVehicleManager::getVehicleById(int vehicleId)
{
for (int i=0; i< _vehicles.count(); i++) {
diff --git a/src/Vehicle/MultiVehicleManager.h b/src/Vehicle/MultiVehicleManager.h
index be09b4b6298..5b12ba3b4f5 100644
--- a/src/Vehicle/MultiVehicleManager.h
+++ b/src/Vehicle/MultiVehicleManager.h
@@ -43,6 +43,7 @@ class MultiVehicleManager : public QGCTool
Q_PROPERTY(bool parameterReadyVehicleAvailable READ parameterReadyVehicleAvailable 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 gcsHeartbeatEnabled WRITE setGcsHeartbeatEnabled NOTIFY gcsHeartBeatEnabledChanged)
Q_PROPERTY(Vehicle* offlineEditingVehicle READ offlineEditingVehicle CONSTANT)
Q_PROPERTY(QGeoCoordinate lastKnownLocation READ lastKnownLocation NOTIFY lastKnownLocationChanged) //< Current vehicles last know location
@@ -50,6 +51,9 @@ class MultiVehicleManager : public QGCTool
// Methods
Q_INVOKABLE Vehicle* getVehicleById(int vehicleId);
+ Q_INVOKABLE void selectVehicle(int vehicleId);
+ Q_INVOKABLE void deselectVehicle(int vehicleId);
+ Q_INVOKABLE void deselectAllVehicles();
// Property accessors
@@ -61,6 +65,7 @@ class MultiVehicleManager : public QGCTool
void setActiveVehicle(Vehicle* vehicle);
QmlObjectListModel* vehicles(void) { return &_vehicles; }
+ QmlObjectListModel* selectedVehicles(void) { return &_selectedVehicles; }
bool gcsHeartbeatEnabled(void) const { return _gcsHeartbeatEnabled; }
void setGcsHeartbeatEnabled(bool gcsHeartBeatEnabled);
@@ -96,6 +101,7 @@ private slots:
private:
bool _vehicleExists(int vehicleId);
+ bool _vehicleSelected(int vehicleId);
bool _activeVehicleAvailable; ///< true: An active vehicle is available
bool _parameterReadyVehicleAvailable; ///< true: An active vehicle with ready parameters is available
@@ -108,6 +114,7 @@ private slots:
QList _ignoreVehicleIds; ///< List of vehicle id for which we ignore further communication
QmlObjectListModel _vehicles;
+ QmlObjectListModel _selectedVehicles;
FirmwarePluginManager* _firmwarePluginManager;
MAVLinkProtocol* _mavlinkProtocol;