diff --git a/qgroundcontrol.qrc b/qgroundcontrol.qrc index 079b5a43ae32bea57fd12ba230a79afbf830e860..44fb871fffebc3dda3aa01aff5de7e92ada82940 100644 --- a/qgroundcontrol.qrc +++ b/qgroundcontrol.qrc @@ -194,12 +194,16 @@ src/FlightDisplay/FlightDisplayViewMap.qml src/FlightDisplay/FlightDisplayViewVideo.qml src/FlightDisplay/FlightDisplayViewWidgets.qml + src/FlightDisplay/FlyViewAirspaceIndicator.qml + src/FlightDisplay/FlyViewMissionCompleteDialog.qml + src/FlightDisplay/FlyViewPreFlightChecklistPopup.qml src/FlightDisplay/FlyViewToolStrip.qml src/FlightDisplay/GuidedActionConfirm.qml src/FlightDisplay/GuidedActionList.qml src/FlightDisplay/GuidedActionsController.qml src/FlightDisplay/GuidedAltitudeSlider.qml src/FlightDisplay/MultiVehicleList.qml + src/FlightDisplay/MultiVehiclePanel.qml src/FlightDisplay/PreFlightBatteryCheck.qml src/FlightDisplay/PreFlightGPSCheck.qml src/FlightDisplay/PreFlightRCCheck.qml diff --git a/src/FlightDisplay/FlightDisplayView.qml b/src/FlightDisplay/FlightDisplayView.qml index 5fe943593c399b2b0ccb0472476334a26449944a..e16dae0504a6ccae0ab30e47bfc4e0b20c56f9b0 100644 --- a/src/FlightDisplay/FlightDisplayView.qml +++ b/src/FlightDisplay/FlightDisplayView.qml @@ -7,10 +7,10 @@ * ****************************************************************************/ -import QtQuick 2.11 +import QtQuick 2.12 import QtQuick.Controls 2.4 import QtQuick.Dialogs 1.3 -import QtQuick.Layouts 1.11 +import QtQuick.Layouts 1.12 import QtLocation 5.3 import QtPositioning 5.3 @@ -39,17 +39,14 @@ Item { } } - property bool activeVehicleJoystickEnabled: activeVehicle ? activeVehicle.joystickEnabled : false - property bool mainIsMap: QGroundControl.videoManager.hasVideo ? QGroundControl.loadBoolGlobalSetting(_mainIsMapKey, true) : true - property bool isBackgroundDark: mainIsMap ? (mainWindow.flightDisplayMap ? mainWindow.flightDisplayMap.isSatelliteMap : true) : true + property bool mainIsMap: QGroundControl.videoManager.hasVideo ? QGroundControl.loadBoolGlobalSetting(_mainIsMapKey, true) : true + property bool isBackgroundDark: mainIsMap ? (mainWindow.flightDisplayMap ? mainWindow.flightDisplayMap.isSatelliteMap : true) : true + property var _activeVehicle: QGroundControl.multiVehicleManager.activeVehicle property var _missionController: _planController.missionController property var _geoFenceController: _planController.geoFenceController property var _rallyPointController: _planController.rallyPointController property bool _isPipVisible: QGroundControl.videoManager.hasVideo ? QGroundControl.loadBoolGlobalSetting(_PIPVisibleKey, true) : false - property bool _useChecklist: QGroundControl.settingsManager.appSettings.useChecklist.rawValue && QGroundControl.corePlugin.options.preFlightChecklistUrl.toString().length - property bool _enforceChecklist: _useChecklist && QGroundControl.settingsManager.appSettings.enforceChecklist.rawValue - property bool _checklistComplete: activeVehicle && (activeVehicle.checkListState === Vehicle.CheckListPassed) property real _margins: ScreenTools.defaultFontPixelWidth / 2 property real _pipSize: mainWindow.width * 0.2 property alias _guidedController: guidedActionsController @@ -59,24 +56,10 @@ Item { property real _guidedZOrder: _flightVideoPipControl.z + 1 property real _toolsMargin: ScreenTools.defaultFontPixelWidth * 0.75 - readonly property string _mapName: "FlightDisplayView" - readonly property string _showMapBackgroundKey: "/showMapBackground" - readonly property string _mainIsMapKey: "MainFlyWindowIsMap" - readonly property string _PIPVisibleKey: "IsPIPVisible" - - Timer { - id: checklistPopupTimer - interval: 1000 - repeat: false - onTriggered: { - if (visible && !_checklistComplete) { - checklistDropPanel.open() - } - else { - checklistDropPanel.close() - } - } - } + readonly property string _mapName: "FlightDisplayView" + readonly property string _showMapBackgroundKey: "/showMapBackground" + readonly property string _mainIsMapKey: "MainFlyWindowIsMap" + readonly property string _PIPVisibleKey: "IsPIPVisible" function setStates() { QGroundControl.saveBoolGlobalSetting(_mainIsMapKey, mainIsMap) @@ -110,153 +93,23 @@ Item { return true; } - function showPreflightChecklistIfNeeded () { - if (activeVehicle && !_checklistComplete && _enforceChecklist) { - checklistPopupTimer.restart() - } - } - + // Signal routing Connections { - target: _missionController - onResumeMissionUploadFail: guidedActionsController.confirmAction(guidedActionsController.actionResumeMissionUploadFail) - } - - Connections { - target: mainWindow - onArmVehicle: _guidedController.confirmAction(_guidedController.actionArm) - onDisarmVehicle: { - if (_guidedController.showEmergenyStop) { - _guidedController.confirmAction(_guidedController.actionEmergencyStop) - } else { - _guidedController.confirmAction(_guidedController.actionDisarm) - } - } - onVtolTransitionToFwdFlight: _guidedController.confirmAction(_guidedController.actionVtolTransitionToFwdFlight) - onVtolTransitionToMRFlight: _guidedController.confirmAction(_guidedController.actionVtolTransitionToMRFlight) - onFlightDisplayMapChanged: setStates() + target: mainWindow + onFlightDisplayMapChanged: setStates() } Component.onCompleted: { if(QGroundControl.corePlugin.options.flyViewOverlay.toString().length) { flyViewOverlay.source = QGroundControl.corePlugin.options.flyViewOverlay } - if(QGroundControl.corePlugin.options.preFlightChecklistUrl.toString().length) { - checkList.source = QGroundControl.corePlugin.options.preFlightChecklistUrl - } - } - - // The following code is used to track vehicle states for showing the mission complete dialog - property bool vehicleArmed: activeVehicle ? activeVehicle.armed : true // true here prevents pop up from showing during shutdown - property bool vehicleWasArmed: false - property bool vehicleInMissionFlightMode: activeVehicle ? (activeVehicle.flightMode === activeVehicle.missionFlightMode) : false - property bool vehicleWasInMissionFlightMode: false - property bool showMissionCompleteDialog: vehicleWasArmed && vehicleWasInMissionFlightMode && - (_missionController.containsItems || _geoFenceController.containsItems || _rallyPointController.containsItems || - (activeVehicle ? activeVehicle.cameraTriggerPoints.count !== 0 : false)) - - onVehicleArmedChanged: { - if (vehicleArmed) { - vehicleWasArmed = true - vehicleWasInMissionFlightMode = vehicleInMissionFlightMode - } else { - if (showMissionCompleteDialog) { - mainWindow.showComponentDialog(missionCompleteDialogComponent, qsTr("Flight Plan complete"), mainWindow.showDialogDefaultWidth, StandardButton.Close) - } - vehicleWasArmed = false - vehicleWasInMissionFlightMode = false - } } - onVehicleInMissionFlightModeChanged: { - if (vehicleInMissionFlightMode && vehicleArmed) { - vehicleWasInMissionFlightMode = true - } - } - - Component { - id: missionCompleteDialogComponent - - QGCViewDialog { - property var activeVehicleCopy: activeVehicle - onActiveVehicleCopyChanged: - if (!activeVehicleCopy) { - hideDialog() - } - - QGCFlickable { - anchors.fill: parent - contentHeight: column.height - - ColumnLayout { - id: column - anchors.margins: _margins - anchors.left: parent.left - anchors.right: parent.right - spacing: ScreenTools.defaultFontPixelHeight - - QGCLabel { - Layout.fillWidth: true - text: qsTr("%1 Images Taken").arg(activeVehicle.cameraTriggerPoints.count) - horizontalAlignment: Text.AlignHCenter - visible: activeVehicle.cameraTriggerPoints.count !== 0 - } - - QGCButton { - Layout.fillWidth: true - text: qsTr("Remove plan from vehicle") - visible: !activeVehicle.connectionLost// && !activeVehicle.apmFirmware // ArduPilot has a bug somewhere with mission clear - onClicked: { - _planController.removeAllFromVehicle() - hideDialog() - } - } - - QGCButton { - Layout.fillWidth: true - Layout.alignment: Qt.AlignHCenter - text: qsTr("Leave plan on vehicle") - onClicked: hideDialog() - } - - Rectangle { - Layout.fillWidth: true - color: qgcPal.text - height: 1 - } - - ColumnLayout { - Layout.fillWidth: true - spacing: ScreenTools.defaultFontPixelHeight - visible: !activeVehicle.connectionLost && _guidedController.showResumeMission - - QGCButton { - Layout.fillWidth: true - Layout.alignment: Qt.AlignHCenter - text: qsTr("Resume Mission From Waypoint %1").arg(_guidedController._resumeMissionIndex) - - onClicked: { - _guidedController.executeAction(_guidedController.actionResumeMission, null, null) - hideDialog() - } - } - - QGCLabel { - Layout.fillWidth: true - wrapMode: Text.WordWrap - text: qsTr("Resume Mission will rebuild the current mission from the last flown waypoint and upload it to the vehicle for the next flight.") - } - } - - QGCLabel { - Layout.fillWidth: true - wrapMode: Text.WordWrap - color: qgcPal.warningText - text: qsTr("If you are changing batteries for Resume Mission do not disconnect from the vehicle.") - visible: _guidedController.showResumeMission - } - } - } - } + FlyViewMissionCompleteDialog { + missionController: _missionController + geoFenceController: _geoFenceController + rallyPointController: _rallyPointController + guidedController: _guidedController } Window { @@ -280,17 +133,17 @@ Item { * Such approach was the only one to avoid a crash for windows users */ Timer { - id: videoPopUpTimer - interval: 2000; - running: false; - repeat: false - onTriggered: { - // If state is popup, the next one will be popup-finished - if (_flightVideo.state == "popup") { - _flightVideo.state = "popup-finished" - } - QGroundControl.videoManager.startVideo() - } + id: videoPopUpTimer + interval: 2000; + running: false; + repeat: false + onTriggered: { + // If state is popup, the next one will be popup-finished + if (_flightVideo.state == "popup") { + _flightVideo.state = "popup-finished" + } + QGroundControl.videoManager.startVideo() + } } QGCMapPalette { id: mapPal; lightColors: mainIsMap ? mainWindow.flightDisplayMap.isSatelliteMap : true } @@ -328,10 +181,9 @@ Item { id: _fMap anchors.fill: parent guidedActionsController: _guidedController - missionController: _planController + planMasterController: _planController flightWidgets: flightDisplayViewWidgets rightPanelWidth: ScreenTools.defaultFontPixelHeight * 9 - multiVehicleView: !singleVehicleView.checked scaleState: (mainIsMap && flyViewOverlay.item) ? (flyViewOverlay.item.scaleState ? flyViewOverlay.item.scaleState : "bottomMode") : "bottomMode" Component.onCompleted: { mainWindow.flightDisplayMap = _fMap @@ -474,26 +326,14 @@ Item { } } - Row { - id: singleMultiSelector - anchors.topMargin: ScreenTools.toolbarHeight + _toolsMargin - anchors.rightMargin: _toolsMargin - anchors.right: parent.right - spacing: ScreenTools.defaultFontPixelWidth - z: _mapAndVideo.z + 4 - visible: QGroundControl.multiVehicleManager.vehicles.count > 1 && QGroundControl.corePlugin.options.enableMultiVehicleList - - QGCRadioButton { - id: singleVehicleView - text: qsTr("Single") - checked: true - textColor: mapPal.text - } - - QGCRadioButton { - text: qsTr("Multi-Vehicle") - textColor: mapPal.text - } + MultiVehiclePanel { + id: singleMultiSelector + anchors.margins: _toolsMargin + anchors.top: parent.top + anchors.right: parent.right + z: _mapAndVideo.z + 4 + availableHeight: mainWindow.availableHeight - (anchors.margins * 2) + guidedActionsController: _guidedController } FlightDisplayViewWidgets { @@ -506,7 +346,7 @@ Item { anchors.top: singleMultiSelector.visible? singleMultiSelector.bottom : undefined useLightColors: isBackgroundDark missionController: _missionController - visible: singleVehicleView.checked && !QGroundControl.videoManager.fullScreen + visible: singleMultiSelector.singleVehiclePanel && !QGroundControl.videoManager.fullScreen } //------------------------------------------------------------------------- @@ -521,36 +361,25 @@ Item { anchors.bottom: parent.bottom } - MultiVehicleList { - anchors.margins: _toolsMargin - anchors.top: singleMultiSelector.bottom - anchors.right: parent.right - anchors.bottom: parent.bottom - width: ScreenTools.defaultFontPixelWidth * 30 - visible: !singleVehicleView.checked && !QGroundControl.videoManager.fullScreen && QGroundControl.corePlugin.options.enableMultiVehicleList - z: _mapAndVideo.z + 4 - guidedActionsController: _guidedController - } - //-- Virtual Joystick Loader { id: virtualJoystickMultiTouch z: _mapAndVideo.z + 5 width: parent.width - (_flightVideoPipControl.width / 2) height: Math.min(mainWindow.height * 0.25, ScreenTools.defaultFontPixelWidth * 16) - visible: (_virtualJoystick ? _virtualJoystick.value : false) && !QGroundControl.videoManager.fullScreen && !(activeVehicle ? activeVehicle.highLatencyLink : false) + visible: (_virtualJoystick ? _virtualJoystick.value : false) && !QGroundControl.videoManager.fullScreen && !(_activeVehicle ? _activeVehicle.highLatencyLink : false) anchors.bottom: _flightVideoPipControl.top anchors.bottomMargin: ScreenTools.defaultFontPixelHeight * 2 anchors.horizontalCenter: flightDisplayViewWidgets.horizontalCenter source: "qrc:/qml/VirtualJoystick.qml" - active: (_virtualJoystick ? _virtualJoystick.value : false) && !(activeVehicle ? activeVehicle.highLatencyLink : false) + active: (_virtualJoystick ? _virtualJoystick.value : false) && !(_activeVehicle ? _activeVehicle.highLatencyLink : false) property bool useLightColors: isBackgroundDark // The default behaviour is not centralized throttle property bool centralizeThrottle: _virtualJoystickCentralized ? _virtualJoystickCentralized.value : false - property Fact _virtualJoystick: QGroundControl.settingsManager.appSettings.virtualJoystick - property Fact _virtualJoystickCentralized: QGroundControl.settingsManager.appSettings.virtualJoystickCentralized + property Fact _virtualJoystick: QGroundControl.settingsManager.appSettings.virtualJoystick + property Fact _virtualJoystickCentralized: QGroundControl.settingsManager.appSettings.virtualJoystickCentralized } FlyViewToolStrip { @@ -565,8 +394,10 @@ Item { maxHeight: parent.height - toolStrip.y + (_flightVideo.visible ? (_flightVideo.y - parent.height) : 0) guidedActionsController: _guidedController guidedActionList: _guidedList - preFlightCheckList: checklistDropPanel - visible: (activeVehicle ? activeVehicle.guidedModeSupported : true) && !QGroundControl.videoManager.fullScreen + usePreFlightChecklist: preFlightChecklistPopup.useChecklist + visible: (_activeVehicle ? _activeVehicle.guidedModeSupported : true) && !QGroundControl.videoManager.fullScreen + + onDisplayPreFlightChecklist: preFlightChecklistPopup.open() } GuidedActionsController { @@ -612,84 +443,16 @@ Item { } } - //-- Airspace Indicator - Rectangle { - id: airspaceIndicator - width: airspaceRow.width + (ScreenTools.defaultFontPixelWidth * 3) - height: airspaceRow.height * 1.25 - color: qgcPal.globalTheme === QGCPalette.Light ? Qt.rgba(1,1,1,0.95) : Qt.rgba(0,0,0,0.75) - visible: QGroundControl.airmapSupported && mainIsMap && flightPermit && flightPermit !== AirspaceFlightPlanProvider.PermitNone - radius: 3 - border.width: 1 - border.color: qgcPal.globalTheme === QGCPalette.Light ? Qt.rgba(0,0,0,0.35) : Qt.rgba(1,1,1,0.35) - anchors.top: parent.top - anchors.topMargin: ScreenTools.toolbarHeight + (ScreenTools.defaultFontPixelHeight * 0.25) - anchors.horizontalCenter: parent.horizontalCenter - Row { - id: airspaceRow - spacing: ScreenTools.defaultFontPixelWidth - anchors.centerIn: parent - QGCLabel { text: airspaceIndicator.providerName+":"; anchors.verticalCenter: parent.verticalCenter; } - QGCLabel { - text: { - if(airspaceIndicator.flightPermit) { - if(airspaceIndicator.flightPermit === AirspaceFlightPlanProvider.PermitPending) - return qsTr("Approval Pending") - if(airspaceIndicator.flightPermit === AirspaceFlightPlanProvider.PermitAccepted || airspaceIndicator.flightPermit === AirspaceFlightPlanProvider.PermitNotRequired) - return qsTr("Flight Approved") - if(airspaceIndicator.flightPermit === AirspaceFlightPlanProvider.PermitRejected) - return qsTr("Flight Rejected") - } - return "" - } - color: { - if(airspaceIndicator.flightPermit) { - if(airspaceIndicator.flightPermit === AirspaceFlightPlanProvider.PermitPending) - return qgcPal.colorOrange - if(airspaceIndicator.flightPermit === AirspaceFlightPlanProvider.PermitAccepted || airspaceIndicator.flightPermit === AirspaceFlightPlanProvider.PermitNotRequired) - return qgcPal.colorGreen - } - return qgcPal.colorRed - } - anchors.verticalCenter: parent.verticalCenter; - } - } - property var flightPermit: QGroundControl.airmapSupported ? QGroundControl.airspaceManager.flightPlan.flightPermitStatus : null - property string providerName: QGroundControl.airspaceManager.providerName + FlyViewAirspaceIndicator { + anchors.top: parent.top + anchors.topMargin: ScreenTools.defaultFontPixelHeight * 0.25 + anchors.horizontalCenter: parent.horizontalCenter + show: mainIsMap } - //-- Checklist GUI - Popup { - id: checklistDropPanel - x: toolStrip.x + toolStrip.width + (ScreenTools.defaultFontPixelWidth * 2) - y: toolStrip.y - height: checkList.height - width: checkList.width - modal: true - focus: true - closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside - background: Rectangle { - anchors.fill: parent - color: Qt.rgba(0,0,0,0) - clip: true - } - - Loader { - id: checkList - anchors.centerIn: parent - } - - property alias checkListItem: checkList.item - - Connections { - target: checkList.item - onAllChecksPassedChanged: { - if (target.allChecksPassed) - { - checklistPopupTimer.restart() - } - } - } + FlyViewPreFlightChecklistPopup { + id: preFlightChecklistPopup + x: toolStrip.x + toolStrip.width + (ScreenTools.defaultFontPixelWidth * 2) + y: toolStrip.y } - } diff --git a/src/FlightDisplay/FlightDisplayViewMap.qml b/src/FlightDisplay/FlightDisplayViewMap.qml index e34e79cf5f34aee014bfaaadea33d3ba39c59f85..458ead5cc32e2a397270e149db4a554c176fba82 100644 --- a/src/FlightDisplay/FlightDisplayViewMap.qml +++ b/src/FlightDisplay/FlightDisplayViewMap.qml @@ -39,13 +39,13 @@ FlightMap { property var guidedActionsController property var flightWidgets property var rightPanelWidth - property var multiVehicleView ///< true: multi-vehicle view, false: single vehicle view - property var missionController: null + property var planMasterController property rect centerViewport: Qt.rect(0, 0, width, height) - property var _geoFenceController: missionController.geoFenceController - property var _rallyPointController: missionController.rallyPointController + property var _planMasterController: planMasterController + property var _geoFenceController: planMasterController.geoFenceController + property var _rallyPointController: planMasterController.rallyPointController property var _activeVehicleCoordinate: activeVehicle ? activeVehicle.coordinate : QtPositioning.coordinate() property real _toolButtonTopMargin: parent.height - mainWindow.height + (ScreenTools.defaultFontPixelHeight / 2) property bool _airspaceEnabled: QGroundControl.airmapSupported ? (QGroundControl.settingsManager.airMapSettings.enableAirMap.rawValue && QGroundControl.airspaceManager.connected): false @@ -200,10 +200,10 @@ FlightMap { QGCMapPalette { id: mapPal; lightColors: isSatelliteMap } Connections { - target: missionController + target: _missionController ignoreUnknownSignals: true onNewItemsFromVehicle: { - var visualItems = missionController.visualItems + var visualItems = _missionController.visualItems if (visualItems && visualItems.count !== 1) { mapFitFunctions.fitMapViewportToMissionItems() firstVehiclePositionReceived = true @@ -215,7 +215,7 @@ FlightMap { id: mapFitFunctions // The name for this id cannot be changed without breaking references outside of this code. Beware! map: mainWindow.flightDisplayMap usePlannedHomePosition: false - planMasterController: missionController + planMasterController: _planMasterController property real leftToolWidth: toolStrip.x + toolStrip.width } @@ -271,10 +271,10 @@ FlightMap { model: QGroundControl.multiVehicleManager.vehicles PlanMapItems { - map: flightMap - largeMapView: mainIsMap - masterController: masterController - vehicle: _vehicle + map: flightMap + largeMapView: mainIsMap + planMasterController: _planMasterController + vehicle: _vehicle property var _vehicle: object diff --git a/src/FlightDisplay/FlyViewAirspaceIndicator.qml b/src/FlightDisplay/FlyViewAirspaceIndicator.qml new file mode 100644 index 0000000000000000000000000000000000000000..91a2585ef8904d97e71f6d61326dd168ff31019b --- /dev/null +++ b/src/FlightDisplay/FlyViewAirspaceIndicator.qml @@ -0,0 +1,66 @@ +/**************************************************************************** + * + * (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 2.12 +import QtQuick.Controls 2.4 + +import QGroundControl 1.0 +import QGroundControl.Airspace 1.0 +import QGroundControl.Controls 1.0 +import QGroundControl.Palette 1.0 +import QGroundControl.ScreenTools 1.0 + +Rectangle { + id: _root + width: airspaceRow.width + (ScreenTools.defaultFontPixelWidth * 3) + height: airspaceRow.height * 1.25 + color: qgcPal.globalTheme === QGCPalette.Light ? Qt.rgba(1,1,1,0.95) : Qt.rgba(0,0,0,0.75) + visible: show && QGroundControl.airmapSupported && _flightPermit && _flightPermit !== AirspaceFlightPlanProvider.PermitNone + radius: 3 + border.width: 1 + border.color: qgcPal.globalTheme === QGCPalette.Light ? Qt.rgba(0,0,0,0.35) : Qt.rgba(1,1,1,0.35) + + property bool show: false + + property var _flightPermit: QGroundControl.airmapSupported ? QGroundControl.airspaceManager.flightPlan.flightPermitStatus : null + property string _providerName: QGroundControl.airspaceManager.providerName + + QGCPalette { id: qgcPal; colorGroupEnabled: enabled } + + Row { + id: airspaceRow + spacing: ScreenTools.defaultFontPixelWidth + anchors.centerIn: parent + + QGCLabel { text: _providerName+":"; anchors.verticalCenter: parent.verticalCenter; } + QGCLabel { + text: { + if(_flightPermit) { + if(_flightPermit === AirspaceFlightPlanProvider.PermitPending) + return qsTr("Approval Pending") + if(_flightPermit === AirspaceFlightPlanProvider.PermitAccepted || _flightPermit === AirspaceFlightPlanProvider.PermitNotRequired) + return qsTr("Flight Approved") + if(_flightPermit === AirspaceFlightPlanProvider.PermitRejected) + return qsTr("Flight Rejected") + } + return "" + } + color: { + if(_flightPermit) { + if(_flightPermit === AirspaceFlightPlanProvider.PermitPending) + return qgcPal.colorOrange + if(_flightPermit === AirspaceFlightPlanProvider.PermitAccepted || _flightPermit === AirspaceFlightPlanProvider.PermitNotRequired) + return qgcPal.colorGreen + } + return qgcPal.colorRed + } + anchors.verticalCenter: parent.verticalCenter; + } + } +} diff --git a/src/FlightDisplay/FlyViewMissionCompleteDialog.qml b/src/FlightDisplay/FlyViewMissionCompleteDialog.qml new file mode 100644 index 0000000000000000000000000000000000000000..3cffe428061e04de4d5d91147536b6a8ef74da48 --- /dev/null +++ b/src/FlightDisplay/FlyViewMissionCompleteDialog.qml @@ -0,0 +1,143 @@ +/**************************************************************************** + * + * (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 2.12 +import QtQuick.Controls 2.4 +import QtQuick.Dialogs 1.3 +import QtQuick.Layouts 1.12 + +import QGroundControl 1.0 +import QGroundControl.Controls 1.0 +import QGroundControl.Palette 1.0 +import QGroundControl.ScreenTools 1.0 + +/// Dialog which shows up when a flight completes. Prompts the user for things like whether they should remove the plan from the vehicle. +Item { + visible: false + + property var missionController + property var geoFenceController + property var rallyPointController + property var guidedController + + // The following code is used to track vehicle states for showing the mission complete dialog + property var _activeVehicle: QGroundControl.multiVehicleManager.activeVehicle + property bool _vehicleArmed: _activeVehicle ? _activeVehicle.armed : true // true here prevents pop up from showing during shutdown + property bool _vehicleWasArmed: false + property bool _vehicleInMissionFlightMode: _activeVehicle ? (_activeVehicle.flightMode === _activeVehicle.missionFlightMode) : false + property bool _vehicleWasInMissionFlightMode: false + property bool _showMissionCompleteDialog: _vehicleWasArmed && _vehicleWasInMissionFlightMode && + (missionController.containsItems || geoFenceController.containsItems || rallyPointController.containsItems || + (_activeVehicle ? _activeVehicle.cameraTriggerPoints.count !== 0 : false)) + + on_VehicleArmedChanged: { + if (_vehicleArmed) { + _vehicleWasArmed = true + _vehicleWasInMissionFlightMode = _vehicleInMissionFlightMode + } else { + if (_showMissionCompleteDialog) { + mainWindow.showComponentDialog(missionCompleteDialogComponent, qsTr("Flight Plan complete"), mainWindow.showDialogDefaultWidth, StandardButton.Close) + } + _vehicleWasArmed = false + _vehicleWasInMissionFlightMode = false + } + } + + on_VehicleInMissionFlightModeChanged: { + if (_vehicleInMissionFlightMode && _vehicleArmed) { + _vehicleWasInMissionFlightMode = true + } + } + + Component { + id: missionCompleteDialogComponent + + QGCViewDialog { + property var activeVehicleCopy: _activeVehicle + onActiveVehicleCopyChanged: + if (!activeVehicleCopy) { + hideDialog() + } + + QGCFlickable { + anchors.fill: parent + contentHeight: column.height + + ColumnLayout { + id: column + anchors.margins: _margins + anchors.left: parent.left + anchors.right: parent.right + spacing: ScreenTools.defaultFontPixelHeight + + QGCLabel { + Layout.fillWidth: true + text: qsTr("%1 Images Taken").arg(_activeVehicle.cameraTriggerPoints.count) + horizontalAlignment: Text.AlignHCenter + visible: _activeVehicle.cameraTriggerPoints.count !== 0 + } + + QGCButton { + Layout.fillWidth: true + text: qsTr("Remove plan from vehicle") + visible: !_activeVehicle.connectionLost// && !_activeVehicle.apmFirmware // ArduPilot has a bug somewhere with mission clear + onClicked: { + _planController.removeAllFromVehicle() + hideDialog() + } + } + + QGCButton { + Layout.fillWidth: true + Layout.alignment: Qt.AlignHCenter + text: qsTr("Leave plan on vehicle") + onClicked: hideDialog() + } + + Rectangle { + Layout.fillWidth: true + color: qgcPal.text + height: 1 + } + + ColumnLayout { + Layout.fillWidth: true + spacing: ScreenTools.defaultFontPixelHeight + visible: !_activeVehicle.connectionLost && guidedController.showResumeMission + + QGCButton { + Layout.fillWidth: true + Layout.alignment: Qt.AlignHCenter + text: qsTr("Resume Mission From Waypoint %1").arg(guidedController._resumeMissionIndex) + + onClicked: { + guidedController.executeAction(guidedController.actionResumeMission, null, null) + hideDialog() + } + } + + QGCLabel { + Layout.fillWidth: true + wrapMode: Text.WordWrap + text: qsTr("Resume Mission will rebuild the current mission from the last flown waypoint and upload it to the vehicle for the next flight.") + } + } + + QGCLabel { + Layout.fillWidth: true + wrapMode: Text.WordWrap + color: qgcPal.warningText + text: qsTr("If you are changing batteries for Resume Mission do not disconnect from the vehicle.") + visible: guidedController.showResumeMission + } + } + } + } + } +} diff --git a/src/FlightDisplay/FlyViewPreFlightChecklistPopup.qml b/src/FlightDisplay/FlyViewPreFlightChecklistPopup.qml new file mode 100644 index 0000000000000000000000000000000000000000..22c4ba05c324056d701a721e8a3a8725ed913fc1 --- /dev/null +++ b/src/FlightDisplay/FlyViewPreFlightChecklistPopup.qml @@ -0,0 +1,80 @@ +/**************************************************************************** + * + * (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 2.11 +import QtQuick.Controls 2.4 + +import QGroundControl 1.0 +import QGroundControl.Vehicle 1.0 + +/// Popup container for preflight checklists +Popup { + id: _root + height: checkList.height + width: checkList.width + modal: true + focus: true + closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside + background: Rectangle { + anchors.fill: parent + color: Qt.rgba(0,0,0,0) + clip: true + } + + property bool useChecklist: QGroundControl.settingsManager.appSettings.useChecklist.rawValue && QGroundControl.corePlugin.options.preFlightChecklistUrl.toString().length + + property var _activeVehicle: QGroundControl.multiVehicleManager.activeVehicle + property bool _enforceChecklist: useChecklist && QGroundControl.settingsManager.appSettings.enforceChecklist.rawValue + property bool _checklistComplete: _activeVehicle && (_activeVehicle.checkListState === Vehicle.CheckListPassed) + + on_ActiveVehicleChanged: _showPreFlightChecklistIfNeeded() + + Connections { + target: mainWindow + onShowPreFlightChecklistIfNeeded: _root._showPreFlightChecklistIfNeeded() + } + + function _showPreFlightChecklistIfNeeded() { + if (_activeVehicle && !_checklistComplete && _enforceChecklist) { + popupTimer.restart() + } + } + + Timer { + id: popupTimer + interval: 1000 + repeat: false + onTriggered: { + // FIXME: What was the visible check in here for + if (!_checklistComplete) { + console.log("open", _root.width, _root.height) + _root.open() + } else { + _root.close() + } + } + } + + Loader { + id: checkList + anchors.centerIn: parent + source: QGroundControl.corePlugin.options.preFlightChecklistUrl + } + + property alias checkListItem: checkList.item + + Connections { + target: checkList.item + onAllChecksPassedChanged: { + if (target.allChecksPassed) { + popupTimer.restart() + } + } + } +} diff --git a/src/FlightDisplay/FlyViewToolStrip.qml b/src/FlightDisplay/FlyViewToolStrip.qml index f1c0b2152bfad540df585c110666df6d7106d4d3..674dd31271e37fd0c76a44f747220c80296ba2b3 100644 --- a/src/FlightDisplay/FlyViewToolStrip.qml +++ b/src/FlightDisplay/FlyViewToolStrip.qml @@ -13,9 +13,11 @@ import QGroundControl.Controls 1.0 ToolStrip { title: qsTr("Fly") - property var guidedActionsController - property var guidedActionList - property var preFlightCheckList + property var guidedActionsController + property var guidedActionList + property bool usePreFlightChecklist + + signal displayPreFlightChecklist property bool _anyActionAvailable: guidedActionsController.showStartMission || guidedActionsController.showResumeMission || guidedActionsController.showChangeAlt || guidedActionsController.showLandAbort property var _actionModel: [ @@ -49,8 +51,8 @@ ToolStrip { { name: "Checklist", iconSource: "/qmlimages/check.svg", - buttonVisible: _useChecklist, - buttonEnabled: _useChecklist && activeVehicle && !activeVehicle.armed, + buttonVisible: usePreFlightChecklist, + buttonEnabled: usePreFlightChecklist && activeVehicle && !activeVehicle.armed, }, { name: guidedActionsController.takeoffTitle, @@ -91,7 +93,7 @@ ToolStrip { onClicked: { if(index === 0) { - preFlightCheckList.open() + displayPreFlightChecklist() } else { guidedActionsController.closeAll() var action = model[index].action diff --git a/src/FlightDisplay/GuidedActionsController.qml b/src/FlightDisplay/GuidedActionsController.qml index 5e8e46b3c7e14893ec107ff3a7f33ee06c0457e9..d434bc717831b8046c04f0e3ad7342f54a8b7cd6 100644 --- a/src/FlightDisplay/GuidedActionsController.qml +++ b/src/FlightDisplay/GuidedActionsController.qml @@ -239,6 +239,40 @@ Item { _vehicleInMissionMode = activeVehicle ? _flightMode === activeVehicle.missionFlightMode : false // Must be last to get correct signalling for showStartMission popups } + Connections { + target: missionController + onResumeMissionUploadFail: confirmAction(actionResumeMissionUploadFail) + } + + Connections { + target: mainWindow + onArmVehicleRequest: armVehicleRequest() + onDisarmVehicleRequest: disarmVehicleRequest() + onVtolTransitionToFwdFlightRequest: vtolTransitionToFwdFlightRequest() + onVtolTransitionToMRFlightRequest: vtolTransitionToMRFlightRequest() + } + + function armVehicleRequest() { + confirmAction(actionArm) + } + + function disarmVehicleRequest() { + if (showEmergenyStop) { + confirmAction(actionEmergencyStop) + } else { + confirmAction(actionDisarm) + } + + } + + function vtolTransitionToFwdFlightRequest() { + confirmAction(actionVtolTransitionToFwdFlight) + } + + function vtolTransitionToMRFlightRequest() { + confirmAction(actionVtolTransitionToMRFlight) + } + function closeAll() { confirmDialog.visible = false actionList.visible = false diff --git a/src/FlightDisplay/MultiVehiclePanel.qml b/src/FlightDisplay/MultiVehiclePanel.qml new file mode 100644 index 0000000000000000000000000000000000000000..f82d1640c6d988bfbfef04aeb9422e3e085e9bf1 --- /dev/null +++ b/src/FlightDisplay/MultiVehiclePanel.qml @@ -0,0 +1,55 @@ +/**************************************************************************** + * + * (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 2.12 +import QtQuick.Controls 2.4 +import QtQuick.Layouts 1.12 + +import QGroundControl 1.0 +import QGroundControl.Controls 1.0 +import QGroundControl.FlightDisplay 1.0 +import QGroundControl.ScreenTools 1.0 + +/// Multi vehicle panel for Fly View +Item { + id: _root + width: ScreenTools.defaultFontPixelWidth * 30 + height: singleVehiclePanel ? selectorRow.height : availableHeight + visible: QGroundControl.multiVehicleManager.vehicles.count > 1 && QGroundControl.corePlugin.options.enableMultiVehicleList + + property alias singleVehiclePanel: singleVehicleView.checked + property real availableHeight + property var guidedActionsController + + Row { + id: selectorRow + spacing: ScreenTools.defaultFontPixelWidth + + QGCRadioButton { + id: singleVehicleView + text: qsTr("Single") + checked: true + textColor: mapPal.text + } + + QGCRadioButton { + text: qsTr("Multi-Vehicle") + textColor: mapPal.text + } + } + + MultiVehicleList { + anchors.topMargin: ScreenTools.defaultFontPixelHeight / 2 + anchors.top: selectorRow.bottom + anchors.bottom: parent.bottom + width: parent.width + visible: !singleVehiclePanel && !QGroundControl.videoManager.fullScreen && QGroundControl.corePlugin.options.enableMultiVehicleList + guidedActionsController: _root.guidedActionsController + } +} diff --git a/src/FlightDisplay/PreFlightCheckList.qml b/src/FlightDisplay/PreFlightCheckList.qml index 1a81e0672888afdbaae78bd1e42f447cd0f31cf6..98121447ee315d9b1784bb648f0dcdc765a363ec 100644 --- a/src/FlightDisplay/PreFlightCheckList.qml +++ b/src/FlightDisplay/PreFlightCheckList.qml @@ -19,7 +19,7 @@ import QGroundControl.Vehicle 1.0 Rectangle { width: mainColumn.width + ScreenTools.defaultFontPixelWidth * 3 - height: Math.min(availableHeight - (_verticalMargin * 2), mainColumn.height + ScreenTools.defaultFontPixelHeight) + height: Math.min(mainWindow.availableHeight - (_verticalMargin * 2), mainColumn.height + ScreenTools.defaultFontPixelHeight) color: qgcPal.windowShade radius: 3 diff --git a/src/FlightMap/MapItems/PlanMapItems.qml b/src/FlightMap/MapItems/PlanMapItems.qml index 975685cf5eed68a2a0ad021e46155e2fe843edd4..58993356866192fbcc2848b79b7c0acc34885966 100644 --- a/src/FlightMap/MapItems/PlanMapItems.qml +++ b/src/FlightMap/MapItems/PlanMapItems.qml @@ -20,10 +20,10 @@ import QGroundControl.FlightMap 1.0 Item { id: _root - property var map ///< Map control to show items on - property bool largeMapView ///< true: map takes up entire view, false: map is in small window - property var masterController ///< Reference to PlanMasterController for vehicle - property var vehicle ///< Vehicle associated with these items + property var map ///< Map control to show items on + property bool largeMapView ///< true: map takes up entire view, false: map is in small window + property var planMasterController ///< Reference to PlanMasterController for vehicle + property var vehicle ///< Vehicle associated with these items property var _map: map property var _vehicle: vehicle diff --git a/src/QmlControls/QGroundControl/FlightDisplay/qmldir b/src/QmlControls/QGroundControl/FlightDisplay/qmldir index d52aaeadfff7fe61c2c567b34d9e85f38ebf82c5..13b819ecab511db2b571e7e9b0519b2824a14068 100644 --- a/src/QmlControls/QGroundControl/FlightDisplay/qmldir +++ b/src/QmlControls/QGroundControl/FlightDisplay/qmldir @@ -1,18 +1,22 @@ Module QGroundControl.FlightDisplay -FlightDisplayView 1.0 FlightDisplayView.qml -FlightDisplayViewMap 1.0 FlightDisplayViewMap.qml -FlightDisplayViewVideo 1.0 FlightDisplayViewVideo.qml -FlightDisplayViewWidgets 1.0 FlightDisplayViewWidgets.qml -FlyViewToolStrip 1.0 FlyViewToolStrip.qml -GuidedActionConfirm 1.0 GuidedActionConfirm.qml -GuidedActionList 1.0 GuidedActionList.qml -GuidedActionsController 1.0 GuidedActionsController.qml -GuidedAltitudeSlider 1.0 GuidedAltitudeSlider.qml -MultiVehicleList 1.0 MultiVehicleList.qml -PreFlightBatteryCheck 1.0 PreFlightBatteryCheck.qml -PreFlightGPSCheck 1.0 PreFlightGPSCheck.qml -PreFlightRCCheck 1.0 PreFlightRCCheck.qml -PreFlightSensorsHealthCheck 1.0 PreFlightSensorsHealthCheck.qml -PreFlightSoundCheck 1.0 PreFlightSoundCheck.qml -TerrainProgress 1.0 TerrainProgress.qml +FlightDisplayView 1.0 FlightDisplayView.qml +FlightDisplayViewMap 1.0 FlightDisplayViewMap.qml +FlightDisplayViewVideo 1.0 FlightDisplayViewVideo.qml +FlightDisplayViewWidgets 1.0 FlightDisplayViewWidgets.qml +FlyViewAirspaceIndicator 1.0 FlyViewAirspaceIndicator.qml +FlyViewMissionCompleteDialog 1.0 FlyViewMissionCompleteDialog.qml +FlyViewPreFlightChecklistPopup 1.0 FlyViewPreFlightChecklistPopup.qml +FlyViewToolStrip 1.0 FlyViewToolStrip.qml +GuidedActionConfirm 1.0 GuidedActionConfirm.qml +GuidedActionList 1.0 GuidedActionList.qml +GuidedActionsController 1.0 GuidedActionsController.qml +GuidedAltitudeSlider 1.0 GuidedAltitudeSlider.qml +MultiVehicleList 1.0 MultiVehicleList.qml +MultiVehiclePanel 1.0 MultiVehiclePanel.qml +PreFlightBatteryCheck 1.0 PreFlightBatteryCheck.qml +PreFlightGPSCheck 1.0 PreFlightGPSCheck.qml +PreFlightRCCheck 1.0 PreFlightRCCheck.qml +PreFlightSensorsHealthCheck 1.0 PreFlightSensorsHealthCheck.qml +PreFlightSoundCheck 1.0 PreFlightSoundCheck.qml +TerrainProgress 1.0 TerrainProgress.qml diff --git a/src/ui/MainRootWindow.qml b/src/ui/MainRootWindow.qml index 12dd6d896d28c678db7e55eb52d2f36bfa857287..6e295cb72c0019ec08b34903bb5cd19e923194f8 100644 --- a/src/ui/MainRootWindow.qml +++ b/src/ui/MainRootWindow.qml @@ -32,7 +32,7 @@ ApplicationWindow { Component.onCompleted: { //-- Full screen on mobile or tiny screens - if(ScreenTools.isMobile || Screen.height / ScreenTools.realPixelDensity < 120) { + if (ScreenTools.isMobile || Screen.height / ScreenTools.realPixelDensity < 120) { mainWindow.showFullScreen() } else { width = ScreenTools.isMobile ? Screen.width : Math.min(250 * Screen.pixelDensity, Screen.width) @@ -40,8 +40,10 @@ ApplicationWindow { } // Startup experience wizard and provide the source using QGCCorePlugin - if(QGroundControl.settingsManager.appSettings.firstTimeStart.value) { + if (QGroundControl.settingsManager.appSettings.firstTimeStart.value) { startupPopup.open() + } else { + showPreFlightChecklistIfNeeded() } } @@ -78,10 +80,11 @@ ApplicationWindow { //------------------------------------------------------------------------- //-- Actions - signal armVehicle - signal disarmVehicle - signal vtolTransitionToFwdFlight - signal vtolTransitionToMRFlight + signal armVehicleRequest + signal disarmVehicleRequest + signal vtolTransitionToFwdFlightRequest + signal vtolTransitionToMRFlightRequest + signal showPreFlightChecklistIfNeeded //------------------------------------------------------------------------- //-- Global Scope Functions @@ -120,9 +123,8 @@ ApplicationWindow { function showFlyView() { if (!flightView.visible) { - flightView.showPreflightChecklistIfNeeded() + mainWindow.showPreFlightChecklistIfNeeded() } - viewSwitch(false) flightView.visible = true } @@ -694,32 +696,32 @@ ApplicationWindow { //-- Startup PopUp wizard Popup { - id: startupPopup - anchors.centerIn: parent + id: startupPopup + anchors.centerIn: parent + width: Math.min(startupWizard.implicitWidth, mainWindow.width - 2 * startupPopup._horizontalSpacing) + height: Math.min(startupWizard.implicitHeight, mainWindow.availableHeight - 2 * startupPopup._verticalSpacing) + modal: true + focus: true + closePolicy: (startupWizard && startupWizard.forceKeepingOpen !== undefined && startupWizard.forceKeepingOpen) ? Popup.NoAutoClose : Popup.CloseOnEscape | Popup.CloseOnPressOutside - width: Math.min(startupWizard.implicitWidth, mainWindow.width - 2 * startupPopup._horizontalSpacing) - height: Math.min(startupWizard.implicitHeight, mainWindow.availableHeight - 2 * startupPopup._verticalSpacing) + onClosed: mainWindow.showPreFlightChecklistIfNeeded() property real _horizontalSpacing: ScreenTools.defaultFontPixelWidth * 5 property real _verticalSpacing: ScreenTools.defaultFontPixelHeight * 2 - modal: true - focus: true - closePolicy: (startupWizard && startupWizard.forceKeepingOpen !== undefined && startupWizard.forceKeepingOpen) ? Popup.NoAutoClose : Popup.CloseOnEscape | Popup.CloseOnPressOutside - Connections { - target: startupWizard - onCloseView: startupPopup.close() + target: startupWizard + onCloseView: startupPopup.close() } background: Rectangle { radius: ScreenTools.defaultFontPixelHeight * 0.5 - color: qgcPal.window + color: qgcPal.window } StartupWizard { - id: startupWizard - anchors.fill: parent + id: startupWizard + anchors.fill: parent } } } diff --git a/src/ui/toolbar/ArmedIndicator.qml b/src/ui/toolbar/ArmedIndicator.qml index d4f0282e2dcd4c375c5b61c1222a16cd142d1929..02d7d55c04dc82dec1f46cfe5adca66309d05759 100644 --- a/src/ui/toolbar/ArmedIndicator.qml +++ b/src/ui/toolbar/ArmedIndicator.qml @@ -34,9 +34,9 @@ QGCComboBox { onActivated: { if (index == 0) { - mainWindow.armVehicle() + mainWindow.armVehicleRequest() } else { - mainWindow.disarmVehicle() + mainWindow.disarmVehicleRequest() } currentIndex = -1 } diff --git a/src/ui/toolbar/VTOLModeIndicator.qml b/src/ui/toolbar/VTOLModeIndicator.qml index 578c73d2af7529a0180fdcc499ec42bee19945f6..1282bd33c08dbd0be66bf8ff25e6a288465c57f2 100644 --- a/src/ui/toolbar/VTOLModeIndicator.qml +++ b/src/ui/toolbar/VTOLModeIndicator.qml @@ -35,11 +35,11 @@ QGCComboBox { onActivated: { if (index == 0) { if (_fwdFlight) { - mainWindow.vtolTransitionToMRFlight() + mainWindow.vtolTransitionToMRFlightRequest() } } else { if (!_fwdFlight) { - mainWindow.vtolTransitionToFwdFlight() + mainWindow.vtolTransitionToFwdFlightRequest() } } currentIndex = -1