Skip to content
Snippets Groups Projects
PlanView.qml 52.2 KiB
Newer Older
  • Learn to ignore specific revisions
  • /****************************************************************************
     *
     *   (c) 2009-2016 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
     *
     * QGroundControl is licensed according to the terms in the file
     * COPYING.md in the root of the source code directory.
     *
     ****************************************************************************/
    
    Don Gagne's avatar
    Don Gagne committed
    
    
    import QtQuick          2.3
    import QtQuick.Controls 1.2
    
    Don Gagne's avatar
    Don Gagne committed
    import QtQuick.Dialogs  1.2
    
    import QtLocation       5.3
    import QtPositioning    5.3
    import QtQuick.Layouts  1.2
    
    import QtQuick.Window   2.2
    
    Don Gagne's avatar
    Don Gagne committed
    
    
    import QGroundControl                   1.0
    import QGroundControl.FlightMap         1.0
    import QGroundControl.ScreenTools       1.0
    import QGroundControl.Controls          1.0
    import QGroundControl.FactSystem        1.0
    import QGroundControl.FactControls      1.0
    import QGroundControl.Palette           1.0
    import QGroundControl.Controllers       1.0
    import QGroundControl.ShapeFileHelper   1.0
    import QGroundControl.Airspace          1.0
    import QGroundControl.Airmap            1.0
    
    Don Gagne's avatar
    Don Gagne committed
    
    
    DonLakeFlyer's avatar
     
    DonLakeFlyer committed
        id: _root
    
    Gus Grubba's avatar
    Gus Grubba committed
        property bool planControlColapsed: false
    
    
        readonly property int   _decimalPlaces:             8
        readonly property real  _margin:                    ScreenTools.defaultFontPixelHeight * 0.5
    
    DonLakeFlyer's avatar
     
    DonLakeFlyer committed
        readonly property real  _toolsMargin:               ScreenTools.defaultFontPixelWidth * 0.75
    
    Gus Grubba's avatar
    Gus Grubba committed
        readonly property real  _radius:                    ScreenTools.defaultFontPixelWidth  * 0.5
    
        readonly property real  _rightPanelWidth:           Math.min(parent.width / 3, ScreenTools.defaultFontPixelWidth * 30)
        readonly property var   _defaultVehicleCoordinate:  QtPositioning.coordinate(37.803784, -122.462276)
        readonly property bool  _waypointsOnlyMode:         QGroundControl.corePlugin.options.missionWaypointsOnly
    
    Gus Grubba's avatar
    Gus Grubba committed
        property bool   _airspaceEnabled:                    QGroundControl.airmapSupported ? (QGroundControl.settingsManager.airMapSettings.enableAirMap.rawValue && QGroundControl.airspaceManager.connected): false
    
    Gus Grubba's avatar
    Gus Grubba committed
        property var    _missionController:                 _planMasterController.missionController
        property var    _geoFenceController:                _planMasterController.geoFenceController
        property var    _rallyPointController:              _planMasterController.rallyPointController
        property var    _visualItems:                       _missionController.visualItems
        property bool   _lightWidgetBorders:                editorMap.isSatelliteMap
        property bool   _addWaypointOnClick:                false
        property bool   _addROIOnClick:                     false
        property bool   _singleComplexItem:                 _missionController.complexMissionItemNames.length === 1
    
    Gus Grubba's avatar
    Gus Grubba committed
        property int    _editingLayer:                      bar.currentIndex ? _layers[bar.currentIndex] : _layerMission
    
    Gus Grubba's avatar
    Gus Grubba committed
        property int    _toolStripBottom:                   toolStrip.height + toolStrip.y
    
        property var    _appSettings:                       QGroundControl.settingsManager.appSettings
    
    Gus Grubba's avatar
    Gus Grubba committed
        readonly property var       _layers:                [_layerMission, _layerGeoFence, _layerRallyPoints]
    
    
        readonly property int       _layerMission:              1
        readonly property int       _layerGeoFence:             2
        readonly property int       _layerRallyPoints:          3
        readonly property string    _armedVehicleUploadPrompt:  qsTr("Vehicle is currently armed. Do you want to upload the mission to the vehicle?")
    
    DonLakeFlyer's avatar
     
    DonLakeFlyer committed
        function mapCenter() {
    
            var coordinate = editorMap.center
    
            coordinate.latitude  = coordinate.latitude.toFixed(_decimalPlaces)
    
            coordinate.longitude = coordinate.longitude.toFixed(_decimalPlaces)
    
            coordinate.altitude  = coordinate.altitude.toFixed(_decimalPlaces)
    
    DonLakeFlyer's avatar
     
    DonLakeFlyer committed
            return coordinate
        }
    
    
            if(_airspaceEnabled) {
                var coordinateNW = editorMap.toCoordinate(Qt.point(0,0), false /* clipToViewPort */)
                var coordinateSE = editorMap.toCoordinate(Qt.point(width,height), false /* clipToViewPort */)
                if(coordinateNW.isValid && coordinateSE.isValid) {
    
                    QGroundControl.airspaceManager.setROI(coordinateNW, coordinateSE, true /*planView*/, reset)
    
        property bool _firstMissionLoadComplete:    false
        property bool _firstFenceLoadComplete:      false
        property bool _firstRallyLoadComplete:      false
        property bool _firstLoadComplete:           false
    
    
        MapFitFunctions {
    
            id:                         mapFitFunctions  // The name for this id cannot be changed without breaking references outside of this code. Beware!
    
            map:                        editorMap
            usePlannedHomePosition:     true
    
            planMasterController:       _planMasterController
    
            if(QGroundControl.airmapSupported) {
    
                if(_airspaceEnabled) {
                    planControlColapsed = QGroundControl.airspaceManager.airspaceVisible
    
                } else {
                    planControlColapsed = false
                }
    
    Gus Grubba's avatar
    Gus Grubba committed
                planControlColapsed = false
            }
        }
    
    
    DonLakeFlyer's avatar
     
    DonLakeFlyer committed
        onVisibleChanged: {
            if (visible && !_planMasterController.containsItems) {
                toolStrip.simulateClick(toolStrip.fileButtonIndex)
            }
        }
    
    
    DonLakeFlyer's avatar
    DonLakeFlyer committed
        Connections {
    
    Gus Grubba's avatar
    Gus Grubba committed
            target: _appSettings ? _appSettings.defaultMissionItemAltitude : null
    
    DonLakeFlyer's avatar
    DonLakeFlyer committed
            onRawValueChanged: {
                if (_visualItems.count > 1) {
    
                    mainWindow.showComponentDialog(applyNewAltitude, qsTr("Apply new alititude"), mainWindow.showDialogDefaultWidth, StandardButton.Yes | StandardButton.No)
    
    DonLakeFlyer's avatar
    DonLakeFlyer committed
                }
            }
        }
    
        Component {
            id: applyNewAltitude
            QGCViewMessage {
                message:    qsTr("You have changed the default altitude for mission items. Would you like to apply that altitude to all the items in the current mission?")
                function accept() {
                    hideDialog()
    
                    _missionController.applyDefaultMissionAltitude()
    
        Component {
            id: activeMissionUploadDialogComponent
            QGCViewDialog {
                Column {
                    anchors.fill:   parent
                    spacing:        ScreenTools.defaultFontPixelHeight
                    QGCLabel {
                        width:      parent.width
                        wrapMode:   Text.WordWrap
                        text:       qsTr("Your vehicle is currently flying a mission. In order to upload a new or modified mission the current mission will be paused.")
                    }
                    QGCLabel {
                        width:      parent.width
                        wrapMode:   Text.WordWrap
                        text:       qsTr("After the mission is uploaded you can adjust the current waypoint and start the mission.")
                    }
                    QGCButton {
                        text:       qsTr("Pause and Upload")
                        onClicked: {
    
    Gus Grubba's avatar
    Gus Grubba committed
                            activeVehicle.flightMode = activeVehicle.pauseFlightMode
    
                            _planMasterController.sendToVehicle()
    
    Gus Grubba's avatar
    Gus Grubba committed
        Connections {
    
            target: QGroundControl.airspaceManager
    
            onAirspaceVisibleChanged: {
    
                planControlColapsed = QGroundControl.airspaceManager.airspaceVisible
    
        Component {
            id: noItemForKML
            QGCViewMessage {
                message:    qsTr("You need at least one item to create a KML.")
            }
        }
    
    
        PlanMasterController {
    
    Gus Grubba's avatar
    Gus Grubba committed
            id: _planMasterController
    
            Component.onCompleted: {
    
                _planMasterController.start(false /* flyView */)
    
    DonLakeFlyer's avatar
     
    DonLakeFlyer committed
                _missionController.setCurrentPlanViewSeqNum(0, true)
    
    Gus Grubba's avatar
    Gus Grubba committed
                mainWindow.planMasterControllerPlan = _planMasterController
    
    DonLakeFlyer's avatar
     
    DonLakeFlyer committed
            function waitingOnIncompleteDataMessage(save) {
                var saveOrUpload = save ? qsTr("Save") : qsTr("Upload")
                mainWindow.showMessageDialog(qsTr("Unable to %1").arg(saveOrUpload), qsTr("Plan has incomplete items. Complete all items and %1 again.").arg(saveOrUpload))
            }
    
            function waitingOnTerrainDataMessage(save) {
                var saveOrUpload = save ? qsTr("Save") : qsTr("Upload")
                mainWindow.showMessageDialog(qsTr("Unable to %1").arg(saveOrUpload), qsTr("Plan is waiting on terrain data from server for correct altitude values."))
            }
    
            function checkReadyForSaveUpload(save) {
                if (readyForSaveState() == VisualMissionItem.NotReadyForSaveData) {
                    waitingOnIncompleteDataMessage(save)
                    return false
                } else if (readyForSaveState() == VisualMissionItem.NotReadyForSaveTerrain) {
                    waitingOnTerrainDataMessage(save)
                    return false
                }
                return true
    
            function upload() {
    
    DonLakeFlyer's avatar
     
    DonLakeFlyer committed
                if (!checkReadyForSaveUpload(false /* save */)) {
    
    Gus Grubba's avatar
    Gus Grubba committed
                if (activeVehicle && activeVehicle.armed && activeVehicle.flightMode === activeVehicle.missionFlightMode) {
    
                    mainWindow.showComponentDialog(activeMissionUploadDialogComponent, qsTr("Plan Upload"), mainWindow.showDialogDefaultWidth, StandardButton.Cancel)
    
                } else {
    
            function loadFromSelectedFile() {
    
                fileDialog.title =          qsTr("Select Plan File")
    
    DonLakeFlyer's avatar
    DonLakeFlyer committed
                fileDialog.planFiles =      true
    
                fileDialog.selectExisting = true
    
    Gus Grubba's avatar
    Gus Grubba committed
                fileDialog.nameFilters =    _planMasterController.loadNameFilters
    
                fileDialog.fileExtension =  _appSettings.planFileExtension
                fileDialog.fileExtension2 = _appSettings.missionFileExtension
    
            }
    
            function saveToSelectedFile() {
    
    DonLakeFlyer's avatar
     
    DonLakeFlyer committed
                if (!checkReadyForSaveUpload(true /* save */)) {
    
                fileDialog.title =          qsTr("Save Plan")
    
                fileDialog.planFiles =      true
    
                fileDialog.selectExisting = false
    
    Gus Grubba's avatar
    Gus Grubba committed
                fileDialog.nameFilters =    _planMasterController.saveNameFilters
    
                fileDialog.fileExtension =  _appSettings.planFileExtension
                fileDialog.fileExtension2 = _appSettings.missionFileExtension
    
            function fitViewportToItems() {
    
                mapFitFunctions.fitMapViewportToMissionItems()
    
    
            function saveKmlToSelectedFile() {
    
    DonLakeFlyer's avatar
     
    DonLakeFlyer committed
                if (!checkReadyForSaveUpload(true /* save */)) {
    
                fileDialog.title =          qsTr("Save KML")
    
                fileDialog.planFiles =      false
    
                fileDialog.selectExisting = false
    
                fileDialog.nameFilters =    ShapeFileHelper.fileDialogKMLFilters
                fileDialog.fileExtension =  _appSettings.kmlFileExtension
    
                fileDialog.fileExtension2 = ""
    
                fileDialog.openForSave()
            }
    
        Connections {
            target: _missionController
    
    Don Gagne's avatar
     
    Don Gagne committed
    
    
            onNewItemsFromVehicle: {
    
    Gus Grubba's avatar
    Gus Grubba committed
                if (_visualItems && _visualItems.count !== 1) {
    
                    mapFitFunctions.fitMapViewportToMissionItems()
                }
    
    DonLakeFlyer's avatar
     
    DonLakeFlyer committed
                _missionController.setCurrentPlanViewSeqNum(0, true)
    
    DonLakeFlyer's avatar
     
    DonLakeFlyer committed
        function insertSimpleItemAfterCurrent(coordinate) {
            var nextIndex = _missionController.currentPlanViewVIIndex + 1
            _missionController.insertSimpleMissionItem(coordinate, nextIndex, true /* makeCurrentItem */)
        }
    
        function insertROIAfterCurrent(coordinate) {
            var nextIndex = _missionController.currentPlanViewVIIndex + 1
            _missionController.insertROIMissionItem(coordinate, nextIndex, true /* makeCurrentItem */)
            _addROIOnClick = false
    
    DonLakeFlyer's avatar
     
    DonLakeFlyer committed
        function insertCancelROIAfterCurrent() {
            var nextIndex = _missionController.currentPlanViewVIIndex + 1
            _missionController.insertCancelROIMissionItem(nextIndex, true /* makeCurrentItem */)
    
    DonLakeFlyer's avatar
     
    DonLakeFlyer committed
        function insertComplexItemAfterCurrent(complexItemName) {
            var nextIndex = _missionController.currentPlanViewVIIndex + 1
            _missionController.insertComplexMissionItem(complexItemName, mapCenter(), nextIndex, true /* makeCurrentItem */)
        }
    
    
    DonLakeFlyer's avatar
     
    DonLakeFlyer committed
        function selectNextNotReady() {
            var foundCurrent = false
            for (var i=0; i<_missionController.visualItems.count; i++) {
                var vmi = _missionController.visualItems.get(i)
                if (vmi.readyForSaveState === VisualMissionItem.NotReadyForSaveData) {
    
    DonLakeFlyer's avatar
     
    DonLakeFlyer committed
                    _missionController.setCurrentPlanViewSeqNum(vmi.sequenceNumber, true)
    
    DonLakeFlyer's avatar
     
    DonLakeFlyer committed
                    break
                }
            }
        }
    
    
        property int _moveDialogMissionItemIndex
    
    
    Gus Grubba's avatar
    Gus Grubba committed
            folder:         _appSettings ? _appSettings.missionSavePath : ""
    
            property bool planFiles: true    ///< true: working with plan files, false: working with kml file
    
    
                if (planFiles) {
    
    Gus Grubba's avatar
    Gus Grubba committed
                    _planMasterController.saveToFile(file)
    
                } else {
    
    Gus Grubba's avatar
    Gus Grubba committed
                    _planMasterController.saveToKml(file)
    
    DonLakeFlyer's avatar
     
    DonLakeFlyer committed
                _planMasterController.loadFromFile(file)
                _planMasterController.fitViewportToItems()
                _missionController.setCurrentPlanViewSeqNum(0, true)
    
        Component {
            id: moveDialog
            QGCViewDialog {
                function accept() {
                    var toIndex = toCombo.currentIndex
    
    Gus Grubba's avatar
    Gus Grubba committed
                    if (toIndex === 0) {
    
                    _missionController.moveMissionItem(_moveDialogMissionItemIndex, toIndex)
    
                    hideDialog()
                }
                Column {
                    anchors.left:   parent.left
                    anchors.right:  parent.right
                    spacing:        ScreenTools.defaultFontPixelHeight
    
                    QGCLabel {
                        anchors.left:   parent.left
                        anchors.right:  parent.right
                        wrapMode:       Text.WordWrap
    
                        text:           qsTr("Move the selected mission item to the be after following mission item:")
    
                        model:          _visualItems.count
    
                        currentIndex:   _moveDialogMissionItemIndex
                    }
                }
            }
        }
    
    
    Don Gagne's avatar
    Don Gagne committed
            id:             panel
    
            anchors.fill:   parent
    
    Don Gagne's avatar
    Don Gagne committed
    
    
            FlightMap {
    
                id:                         editorMap
                anchors.fill:               parent
                mapName:                    "MissionEditor"
                allowGCSLocationCenter:     true
                allowVehicleLocationCenter: true
    
    Don Gagne's avatar
    Don Gagne committed
    
    
                // This is the center rectangle of the map which is not obscured by tools
    
    DonLakeFlyer's avatar
     
    DonLakeFlyer committed
                property rect centerViewport:   Qt.rect(_leftToolWidth + _margin, _toolsMargin, editorMap.width - _leftToolWidth - _rightToolWidth - (_margin * 2), mapScale.y - _margin - _toolsMargin)
    
    Don Gagne's avatar
     
    Don Gagne committed
                property real _leftToolWidth:       toolStrip.x + toolStrip.width
                property real _rightToolWidth:      rightPanel.width + rightPanel.anchors.rightMargin
    
                readonly property real animationDuration: 500
    
                // Initial map position duplicates Fly view position
                Component.onCompleted: editorMap.center = QGroundControl.flightMapPosition
    
                Behavior on zoomLevel {
                    NumberAnimation {
                        duration:       editorMap.animationDuration
                        easing.type:    Easing.InOutQuad
                    }
                }
    
                QGCMapPalette { id: mapPal; lightColors: editorMap.isSatelliteMap }
    
    
                onZoomLevelChanged: updateAirspace(false)
                onCenterChanged:    updateAirspace(false)
    
                MouseArea {
                    anchors.fill: parent
                    onClicked: {
    
                        // Take focus to close any previous editing
                        editorMap.focus = true
    
                        var coordinate = editorMap.toCoordinate(Qt.point(mouse.x, mouse.y), false /* clipToViewPort */)
                        coordinate.latitude = coordinate.latitude.toFixed(_decimalPlaces)
                        coordinate.longitude = coordinate.longitude.toFixed(_decimalPlaces)
                        coordinate.altitude = coordinate.altitude.toFixed(_decimalPlaces)
    
                        switch (_editingLayer) {
                        case _layerMission:
                            if (_addWaypointOnClick) {
    
    DonLakeFlyer's avatar
     
    DonLakeFlyer committed
                                insertSimpleItemAfterCurrent(coordinate)
    
                            } else if (_addROIOnClick) {
                                _addROIOnClick = false
    
    DonLakeFlyer's avatar
     
    DonLakeFlyer committed
                                insertROIAfterCurrent(coordinate)
    
    DonLakeFlyer's avatar
     
    DonLakeFlyer committed
    
    
                            break
                        case _layerRallyPoints:
    
    Gus Grubba's avatar
    Gus Grubba committed
                            if (_rallyPointController.supported && _addWaypointOnClick) {
    
                                _rallyPointController.addPoint(coordinate)
    
    Don Gagne's avatar
    Don Gagne committed
                        }
    
                // Add the mission item visuals to the map
                Repeater {
    
                    model: _editingLayer == _layerMission ? _missionController.visualItems : undefined
    
                    delegate: MissionItemMapVisual {
                        map:        editorMap
    
    DonLakeFlyer's avatar
     
    DonLakeFlyer committed
                        onClicked:  _missionController.setCurrentPlanViewSeqNum(sequenceNumber, false)
    
                        visible:    _editingLayer == _layerMission
    
                // Add lines between waypoints
                MissionLineView {
    
    DonLakeFlyer's avatar
     
    DonLakeFlyer committed
                    showSpecialVisual:  _missionController.isROIBeginCurrentItem
                    model:              _editingLayer == _layerMission ? _missionController.waypointLines : undefined
    
    Don Gagne's avatar
     
    Don Gagne committed
                MapItemView {
                    model: _editingLayer == _layerMission ? _missionController.directionArrows : undefined
    
                    delegate: MapLineArrow {
                        fromCoord:      object ? object.coordinate1 : undefined
                        toCoord:        object ? object.coordinate2 : undefined
    
    Don Gagne's avatar
     
    Don Gagne committed
                        arrowPosition:  3
                        z:              QGroundControl.zOrderWaypointLines + 1
                    }
                }
    
                // UI for splitting the current segment
                MapQuickItem {
                    id:             splitSegmentItem
                    anchorPoint.x:  sourceItem.width / 2
                    anchorPoint.y:  sourceItem.height / 2
                    z:              QGroundControl.zOrderWaypointLines + 1
    
    DonLakeFlyer's avatar
     
    DonLakeFlyer committed
                    visible:        _editingLayer == _layerMission
    
    Don Gagne's avatar
     
    Don Gagne committed
    
                    sourceItem: SplitIndicator {
    
    DonLakeFlyer's avatar
     
    DonLakeFlyer committed
                        onClicked:  _missionController.insertSimpleMissionItem(splitSegmentItem.coordinate,
                                                                               _missionController.currentPlanViewVIIndex,
                                                                               true /* makeCurrentItem */)
    
    Don Gagne's avatar
     
    Don Gagne committed
                    }
    
                    function _updateSplitCoord() {
                        if (_missionController.splitSegment) {
                            var distance = _missionController.splitSegment.coordinate1.distanceTo(_missionController.splitSegment.coordinate2)
                            var azimuth = _missionController.splitSegment.coordinate1.azimuthTo(_missionController.splitSegment.coordinate2)
                            splitSegmentItem.coordinate = _missionController.splitSegment.coordinate1.atDistanceAndAzimuth(distance / 2, azimuth)
                        } else {
                            coordinate = QtPositioning.coordinate()
                        }
                    }
    
                    Connections {
                        target:                 _missionController
                        onSplitSegmentChanged:  splitSegmentItem._updateSplitCoord()
                    }
    
                    Connections {
                        target:                 _missionController.splitSegment
                        onCoordinate1Changed:   splitSegmentItem._updateSplitCoord()
                        onCoordinate2Changed:   splitSegmentItem._updateSplitCoord()
    
    Don Gagne's avatar
     
    Don Gagne committed
                    }
                }
    
    
                // Add the vehicles to the map
                MapItemView {
                    model: QGroundControl.multiVehicleManager.vehicles
                    delegate:
                        VehicleMapItem {
                        vehicle:        object
                        coordinate:     object.coordinate
    
                        map:            editorMap
    
                        size:           ScreenTools.defaultFontPixelHeight * 3
                        z:              QGroundControl.zOrderMapItems - 1
    
                GeoFenceMapVisuals {
                    map:                    editorMap
    
                    myGeoFenceController:   _geoFenceController
    
                    interactive:            _editingLayer == _layerGeoFence
    
                    homePosition:           _missionController.plannedHomePosition
    
                    planView:               true
                }
    
                RallyPointMapVisuals {
                    map:                    editorMap
    
                    myRallyPointController: _rallyPointController
    
                    interactive:            _editingLayer == _layerRallyPoints
                    planView:               true
    
                // Airspace overlap support
                MapItemView {
    
                    model:              _airspaceEnabled && QGroundControl.airspaceManager.airspaceVisible ? QGroundControl.airspaceManager.airspaces.circles : []
    
                    delegate: MapCircle {
                        center:         object.center
                        radius:         object.radius
    
                        color:          object.color
    
    Gus Grubba's avatar
    Gus Grubba committed
                        border.color:   object.lineColor
                        border.width:   object.lineWidth
    
                    model:              _airspaceEnabled && QGroundControl.airspaceManager.airspaceVisible ? QGroundControl.airspaceManager.airspaces.polygons : []
    
                    delegate: MapPolygon {
                        path:           object.polygon
    
                        color:          object.color
    
    Gus Grubba's avatar
    Gus Grubba committed
                        border.color:   object.lineColor
                        border.width:   object.lineWidth
    
            //-----------------------------------------------------------
            // Left tool strip
    
    Gus Grubba's avatar
    Gus Grubba committed
            ToolStrip {
    
    DonLakeFlyer's avatar
     
    DonLakeFlyer committed
                anchors.margins:    _toolsMargin
    
                anchors.left:       parent.left
                anchors.top:        parent.top
                z:                  QGroundControl.zOrderWidgets
    
    DonLakeFlyer's avatar
     
    DonLakeFlyer committed
                maxHeight:          parent.height - toolStrip.y
    
    DonLakeFlyer's avatar
     
    DonLakeFlyer committed
                //readonly property int flyButtonIndex:       0
                readonly property int fileButtonIndex:      0
                readonly property int takeoffButtonIndex:   1
                readonly property int waypointButtonIndex:  2
                readonly property int roiButtonIndex:       3
                readonly property int patternButtonIndex:   4
                readonly property int landButtonIndex:      5
                readonly property int centerButtonIndex:    6
    
    DonLakeFlyer's avatar
     
    DonLakeFlyer committed
    
    
    DonLakeFlyer's avatar
     
    DonLakeFlyer committed
                property bool _isRallyLayer:    _editingLayer == _layerRallyPoints
                property bool _isMissionLayer:  _editingLayer == _layerMission
    
    Gus Grubba's avatar
    Gus Grubba committed
                model: [
    
    DonLakeFlyer's avatar
     
    DonLakeFlyer committed
                    /*{
    
    Gus Grubba's avatar
    Gus Grubba committed
                        name:               qsTr("Fly"),
                        iconSource:         "/qmlimages/PaperPlane.svg",
                        buttonEnabled:      true,
                        buttonVisible:      true,
    
    DonLakeFlyer's avatar
     
    DonLakeFlyer committed
                    },*/
    
    Gus Grubba's avatar
    Gus Grubba committed
                        name:               qsTr("File"),
                        iconSource:         "/qmlimages/MapSync.svg",
                        buttonEnabled:      !_planMasterController.syncInProgress,
                        buttonVisible:      true,
                        showAlternateIcon:  _planMasterController.dirty,
                        alternateIconSource:"/qmlimages/MapSyncChanged.svg",
                        dropPanelComponent: syncDropPanel
                    },
    
    DonLakeFlyer's avatar
     
    DonLakeFlyer committed
                    {
                        name:               qsTr("Takeoff"),
                        iconSource:         "/res/takeoff.svg",
                        buttonEnabled:      _missionController.isInsertTakeoffValid,
    
    DonLakeFlyer's avatar
     
    DonLakeFlyer committed
                        buttonVisible:      _isMissionLayer
    
    DonLakeFlyer's avatar
     
    DonLakeFlyer committed
                    },
    
    Gus Grubba's avatar
    Gus Grubba committed
                    {
                        name:               _editingLayer == _layerRallyPoints ? qsTr("Rally Point") : qsTr("Waypoint"),
                        iconSource:         "/qmlimages/MapAddMission.svg",
    
    DonLakeFlyer's avatar
     
    DonLakeFlyer committed
                        buttonEnabled:      _isRallyLayer ? true : _missionController.flyThroughCommandsAllowed,
                        buttonVisible:      _isRallyLayer || _isMissionLayer,
    
    Gus Grubba's avatar
    Gus Grubba committed
                        toggle:             true,
                        checked:            _addWaypointOnClick
                    },
                    {
    
    DonLakeFlyer's avatar
     
    DonLakeFlyer committed
                        name:               _missionController.isROIActive ? qsTr("Cancel ROI") : qsTr("ROI"),
    
    Gus Grubba's avatar
    Gus Grubba committed
                        iconSource:         "/qmlimages/MapAddMission.svg",
                        buttonEnabled:      true,
    
    DonLakeFlyer's avatar
     
    DonLakeFlyer committed
                        buttonVisible:      _isMissionLayer,
    
    DonLakeFlyer's avatar
     
    DonLakeFlyer committed
                        toggle:             !_missionController.isROIActive
    
    Gus Grubba's avatar
    Gus Grubba committed
                    },
                    {
                        name:               _singleComplexItem ? _missionController.complexMissionItemNames[0] : qsTr("Pattern"),
                        iconSource:         "/qmlimages/MapDrawShape.svg",
    
    DonLakeFlyer's avatar
     
    DonLakeFlyer committed
                        buttonEnabled:      _missionController.flyThroughCommandsAllowed,
                        buttonVisible:      _isMissionLayer,
    
    Gus Grubba's avatar
    Gus Grubba committed
                        dropPanelComponent: _singleComplexItem ? undefined : patternDropPanel
                    },
    
    DonLakeFlyer's avatar
     
    DonLakeFlyer committed
                    {
                        name:               _planMasterController.controllerVehicle.fixedWing ? qsTr("Land") : qsTr("Return"),
                        iconSource:         "/res/rtl.svg",
                        buttonEnabled:      _missionController.isInsertLandValid,
    
    DonLakeFlyer's avatar
     
    DonLakeFlyer committed
                        buttonVisible:      _isMissionLayer
    
    DonLakeFlyer's avatar
     
    DonLakeFlyer committed
                    },
    
    Gus Grubba's avatar
    Gus Grubba committed
                    {
                        name:               qsTr("Center"),
                        iconSource:         "/qmlimages/MapCenter.svg",
                        buttonEnabled:      true,
                        buttonVisible:      true,
                        dropPanelComponent: centerMapDropPanel
                    }
                ]
    
    DonLakeFlyer's avatar
     
    DonLakeFlyer committed
                function allAddClickBoolsOff() {
                    _addROIOnClick =        false
                    _addWaypointOnClick =   false
                }
    
    
    Gus Grubba's avatar
    Gus Grubba committed
                onClicked: {
                    switch (index) {
    
    DonLakeFlyer's avatar
     
    DonLakeFlyer committed
                    /*case flyButtonIndex:
    
                        mainWindow.showFlyView()
    
    DonLakeFlyer's avatar
     
    DonLakeFlyer committed
                        break*/
    
    DonLakeFlyer's avatar
     
    DonLakeFlyer committed
                    case takeoffButtonIndex:
    
    DonLakeFlyer's avatar
     
    DonLakeFlyer committed
                        allAddClickBoolsOff()
    
    DonLakeFlyer's avatar
     
    DonLakeFlyer committed
                        _missionController.insertTakeoffItem(mapCenter(), _missionController.currentMissionIndex, true /* makeCurrentItem */)
                        break
                    case waypointButtonIndex:
    
    DonLakeFlyer's avatar
     
    DonLakeFlyer committed
                        if (_addWaypointOnClick) {
                            allAddClickBoolsOff()
    
    Gus Grubba's avatar
    Gus Grubba committed
                            setChecked(index, false)
                        } else {
    
    DonLakeFlyer's avatar
     
    DonLakeFlyer committed
                            allAddClickBoolsOff()
    
                            _addWaypointOnClick = checked
    
    Gus Grubba's avatar
    Gus Grubba committed
                        }
                        break
    
    DonLakeFlyer's avatar
     
    DonLakeFlyer committed
                    case roiButtonIndex:
    
    DonLakeFlyer's avatar
     
    DonLakeFlyer committed
                        if (_addROIOnClick) {
                            allAddClickBoolsOff()
                            setChecked(index, false)
    
    DonLakeFlyer's avatar
     
    DonLakeFlyer committed
                        } else {
    
    DonLakeFlyer's avatar
     
    DonLakeFlyer committed
                            allAddClickBoolsOff()
                            if (_missionController.isROIActive) {
                                insertCancelROIAfterCurrent()
                            } else {
                                _addROIOnClick = checked
                            }
    
    DonLakeFlyer's avatar
     
    DonLakeFlyer committed
                        }
    
    Gus Grubba's avatar
    Gus Grubba committed
                        break
    
    DonLakeFlyer's avatar
     
    DonLakeFlyer committed
                    case patternButtonIndex:
    
    DonLakeFlyer's avatar
     
    DonLakeFlyer committed
                        allAddClickBoolsOff()
    
    Gus Grubba's avatar
    Gus Grubba committed
                        if (_singleComplexItem) {
    
    DonLakeFlyer's avatar
     
    DonLakeFlyer committed
                            insertComplexItemAfterCurrent(_missionController.complexMissionItemNames[0])
    
    Gus Grubba's avatar
    Gus Grubba committed
                        }
                        break
    
    DonLakeFlyer's avatar
     
    DonLakeFlyer committed
                    case landButtonIndex:
    
    DonLakeFlyer's avatar
     
    DonLakeFlyer committed
                        allAddClickBoolsOff()
    
    DonLakeFlyer's avatar
     
    DonLakeFlyer committed
                        _missionController.insertLandItem(mapCenter(), _missionController.currentMissionIndex, true /* makeCurrentItem */)
                        break
    
    DonLakeFlyer's avatar
     
    DonLakeFlyer committed
    
                onDropped: {
                    allAddClickBoolsOff()
                }
    
    Gus Grubba's avatar
    Gus Grubba committed
            }
    
    Gus Grubba's avatar
    Gus Grubba committed
            //-----------------------------------------------------------
    
            // Right pane for mission editing controls
            Rectangle {
                id:                 rightPanel
    
                height:             parent.height
    
                width:              _rightPanelWidth
                color:              qgcPal.window
    
                opacity:            planExpanded.visible ? 0.2 : 0
    
    Gus Grubba's avatar
    Gus Grubba committed
                anchors.bottom:     parent.bottom
                anchors.right:      parent.right
    
    DonLakeFlyer's avatar
     
    DonLakeFlyer committed
                anchors.rightMargin: _toolsMargin
    
    Gus Grubba's avatar
    Gus Grubba committed
            //-------------------------------------------------------
            // Right Panel Controls
    
    Gus Grubba's avatar
    Gus Grubba committed
                anchors.fill:           rightPanel
    
    DonLakeFlyer's avatar
     
    DonLakeFlyer committed
                anchors.topMargin:      _toolsMargin
    
    Gus Grubba's avatar
    Gus Grubba committed
                DeadMouseArea {
                    anchors.fill:   parent
                }
    
    Gus Grubba's avatar
    Gus Grubba committed
                Column {
                    id:                 rightControls
    
    Gus Grubba's avatar
    Gus Grubba committed
                    spacing:            ScreenTools.defaultFontPixelHeight * 0.5
    
                    anchors.left:       parent.left
                    anchors.right:      parent.right
    
    Gus Grubba's avatar
    Gus Grubba committed
                    anchors.top:        parent.top
                    //-------------------------------------------------------
                    // Airmap Airspace Control
                    AirspaceControl {
    
    Gus Grubba's avatar
    Gus Grubba committed
                        id:             airspaceControl
                        width:          parent.width
    
    Gus Grubba's avatar
    Gus Grubba committed
                    //-------------------------------------------------------
                    // Mission Controls (Colapsed)
                    Rectangle {
                        width:      parent.width
    
    Gus Grubba's avatar
    Gus Grubba committed
                        height:     planControlColapsed ? colapsedRow.height + ScreenTools.defaultFontPixelHeight : 0
    
    Gus Grubba's avatar
    Gus Grubba committed
                        color:      qgcPal.missionItemEditor
                        radius:     _radius
    
                        visible:    planControlColapsed && _airspaceEnabled
    
    Gus Grubba's avatar
    Gus Grubba committed
                        Row {
                            id:                     colapsedRow
                            spacing:                ScreenTools.defaultFontPixelWidth
                            anchors.left:           parent.left
                            anchors.leftMargin:     ScreenTools.defaultFontPixelWidth
                            anchors.verticalCenter: parent.verticalCenter
                            QGCColoredImage {
    
                                width:              height
                                height:             ScreenTools.defaultFontPixelWidth * 2.5
                                sourceSize.height:  height
                                source:             "qrc:/res/waypoint.svg"
                                color:              qgcPal.text
    
    Gus Grubba's avatar
    Gus Grubba committed
                                anchors.verticalCenter: parent.verticalCenter
                            }
                            QGCLabel {
    
                                text:               qsTr("Plan")
                                color:              qgcPal.text
    
    Gus Grubba's avatar
    Gus Grubba committed
                                anchors.verticalCenter: parent.verticalCenter
    
    Gus Grubba's avatar
    Gus Grubba committed
                        QGCColoredImage {
                            width:                  height
                            height:                 ScreenTools.defaultFontPixelWidth * 2.5
                            sourceSize.height:      height
    
                            source:                 QGroundControl.airmapSupported ? "qrc:/airmap/expand.svg" : ""
    
                            color:                  "white"
    
                            visible:                QGroundControl.airmapSupported
    
    Gus Grubba's avatar
    Gus Grubba committed
                            anchors.right:          parent.right
                            anchors.rightMargin:    ScreenTools.defaultFontPixelWidth
                            anchors.verticalCenter: parent.verticalCenter
                        }
                        MouseArea {
                            anchors.fill:   parent
    
                            enabled:        QGroundControl.airmapSupported
    
    Gus Grubba's avatar
    Gus Grubba committed
                            onClicked: {
    
                                QGroundControl.airspaceManager.airspaceVisible = false
    
    Gus Grubba's avatar
    Gus Grubba committed
                    }
    
    Gus Grubba's avatar
    Gus Grubba committed
                    //-------------------------------------------------------
                    // Mission Controls (Expanded)
                    Rectangle {
                        id:         planExpanded
                        width:      parent.width
    
    Gus Grubba's avatar
    Gus Grubba committed
                        height:     (!planControlColapsed || !_airspaceEnabled) ? bar.height + ScreenTools.defaultFontPixelHeight : 0
    
    Gus Grubba's avatar
    Gus Grubba committed
                        color:      qgcPal.missionItemEditor
                        radius:     _radius
    
    Gus Grubba's avatar
    Gus Grubba committed
                        visible:    (!planControlColapsed || !_airspaceEnabled) && QGroundControl.corePlugin.options.enablePlanViewSelector
    
    Gus Grubba's avatar
    Gus Grubba committed
                        Item {
    
    Gus Grubba's avatar
    Gus Grubba committed
                            height:             bar.height
    
    Gus Grubba's avatar
    Gus Grubba committed
                            anchors.left:       parent.left
                            anchors.right:      parent.right
    
    Gus Grubba's avatar
    Gus Grubba committed
                            anchors.margins:    ScreenTools.defaultFontPixelWidth
    
    Gus Grubba's avatar
    Gus Grubba committed
                            anchors.verticalCenter: parent.verticalCenter
    
    Gus Grubba's avatar
    Gus Grubba committed
                            QGCTabBar {
                                id:             bar
                                width:          parent.width
                                anchors.centerIn: parent
                                Component.onCompleted: {
                                    currentIndex = 0
                                }
                                QGCTabButton {
                                    text:       qsTr("Mission")
                                }
                                QGCTabButton {
                                    text:       qsTr("Fence")
                                    enabled:    _geoFenceController.supported
                                }
                                QGCTabButton {
                                    text:       qsTr("Rally")
                                    enabled:    _rallyPointController.supported
    
    Gus Grubba's avatar
    Gus Grubba committed
                                }
                            }
                        }
                    }
                }
                //-------------------------------------------------------
                // Mission Item Editor
                Item {
                    id:                     missionItemEditor
                    anchors.left:           parent.left
                    anchors.right:          parent.right
                    anchors.top:            rightControls.bottom
    
    Gus Grubba's avatar
    Gus Grubba committed
                    anchors.topMargin:      ScreenTools.defaultFontPixelHeight * 0.25
    
    Gus Grubba's avatar
    Gus Grubba committed
                    anchors.bottom:         parent.bottom
                    anchors.bottomMargin:   ScreenTools.defaultFontPixelHeight * 0.25
                    visible:                _editingLayer == _layerMission && !planControlColapsed
                    QGCListView {
    
    Gus Grubba's avatar
    Gus Grubba committed
                        id:                 missionItemEditorListView
                        anchors.fill:       parent
                        spacing:            ScreenTools.defaultFontPixelHeight / 4
                        orientation:        ListView.Vertical
                        model:              _missionController.visualItems
                        cacheBuffer:        Math.max(height * 2, 0)
                        clip:               true
    
    DonLakeFlyer's avatar
     
    DonLakeFlyer committed
                        currentIndex:       _missionController.currentPlanViewSeqNum
    
    Gus Grubba's avatar
    Gus Grubba committed
                        highlightMoveDuration: 250
    
    Gus Grubba's avatar
    Gus Grubba committed
                        visible:            _editingLayer == _layerMission && !planControlColapsed
    
    Gus Grubba's avatar
    Gus Grubba committed
                        //-- List Elements
                        delegate: MissionItemEditor {
    
    Gus Grubba's avatar
    Gus Grubba committed
                            map:            editorMap
    
    Gus Grubba's avatar
    Gus Grubba committed
                            masterController:  _planMasterController
    
    Gus Grubba's avatar
    Gus Grubba committed
                            missionItem:    object
                            width:          parent.width
                            readOnly:       false
    
    DonLakeFlyer's avatar
     
    DonLakeFlyer committed
                            onClicked:      _missionController.setCurrentPlanViewSeqNum(object.sequenceNumber, false)
    
    Gus Grubba's avatar
    Gus Grubba committed
                            onRemove: {
                                var removeIndex = index
                                _missionController.removeMissionItem(removeIndex)
                                if (removeIndex >= _missionController.visualItems.count) {
                                    removeIndex--
                                }
    
    DonLakeFlyer's avatar
     
    DonLakeFlyer committed
                                _missionController.setCurrentPlanViewSeqNum(removeIndex, true)
    
    DonLakeFlyer's avatar
     
    DonLakeFlyer committed
                            onSelectNextNotReadyItem:   selectNextNotReady()
    
    Gus Grubba's avatar
    Gus Grubba committed
                        }
                    }
                }
                // GeoFence Editor
                GeoFenceEditor {
                    anchors.top:            rightControls.bottom
    
    Gus Grubba's avatar
    Gus Grubba committed
                    anchors.topMargin:      ScreenTools.defaultFontPixelHeight * 0.25
    
    Don Gagne's avatar
     
    Don Gagne committed
                    anchors.bottom:         parent.bottom
    
    Gus Grubba's avatar
    Gus Grubba committed
                    anchors.left:           parent.left
                    anchors.right:          parent.right
                    myGeoFenceController:   _geoFenceController
                    flightMap:              editorMap
                    visible:                _editingLayer == _layerGeoFence
                }
                // Rally Point Editor
                RallyPointEditorHeader {
                    id:                     rallyPointHeader
                    anchors.top:            rightControls.bottom
    
    Gus Grubba's avatar
    Gus Grubba committed
                    anchors.topMargin:      ScreenTools.defaultFontPixelHeight * 0.25
    
    Gus Grubba's avatar
    Gus Grubba committed
                    anchors.left:           parent.left
                    anchors.right:          parent.right
                    visible:                _editingLayer == _layerRallyPoints
                    controller:             _rallyPointController
                }
                RallyPointItemEditor {
                    id:                     rallyPointEditor
                    anchors.top:            rallyPointHeader.bottom
    
    Gus Grubba's avatar
    Gus Grubba committed
                    anchors.topMargin:      ScreenTools.defaultFontPixelHeight * 0.25
    
    Gus Grubba's avatar
    Gus Grubba committed
                    anchors.left:           parent.left
                    anchors.right:          parent.right
                    visible:                _editingLayer == _layerRallyPoints && _rallyPointController.points.count
                    rallyPoint:             _rallyPointController.currentRallyPoint
                    controller:             _rallyPointController
    
    Gus Grubba's avatar
    Gus Grubba committed
            }
    
    
            MissionItemStatus {
                id:                 waypointValuesDisplay
    
    DonLakeFlyer's avatar
     
    DonLakeFlyer committed
                anchors.margins:    _toolsMargin
                anchors.left:       toolStrip.right
                anchors.bottom:     mapScale.top
    
                height:             ScreenTools.defaultFontPixelHeight * 7
    
    DonLakeFlyer's avatar
     
    DonLakeFlyer committed
                maxWidth:           rightPanel.x - x - anchors.margins
    
                missionItems:       _missionController.visualItems
    
    DonLakeFlyer's avatar
     
    DonLakeFlyer committed
                visible:            _internalVisible && _editingLayer === _layerMission && QGroundControl.corePlugin.options.showMissionStatus
    
    Don Gagne's avatar
     
    Don Gagne committed
    
                property bool _internalVisible: false
    
                function toggleVisible() {
                    _internalVisible = !_internalVisible
                }
    
    DonLakeFlyer's avatar
     
    DonLakeFlyer committed
    
    
            MapScale {
                id:                     mapScale
                anchors.margins:        _toolsMargin
                anchors.bottom:         parent.bottom
                anchors.left:           toolStrip.right
                mapControl:             editorMap
                buttonsOnLeft:          true
                terrainButtonVisible:   _editingLayer === _layerMission
                terrainButtonChecked:   waypointValuesDisplay.visible
                onTerrainButtonClicked: waypointValuesDisplay.toggleVisible()
            }
    
        Component {
            id: syncLoadFromVehicleOverwrite
            QGCViewMessage {
                id:         syncLoadFromVehicleCheck
    
    Don Gagne's avatar
    Don Gagne committed
                message:   qsTr("You have unsaved/unsent changes. Loading from the Vehicle will lose these changes. Are you sure you want to load from the Vehicle?")
    
                function accept() {
                    hideDialog()
    
    Gus Grubba's avatar
    Gus Grubba committed
                    _planMasterController.loadFromVehicle()
    
                }
            }
        }
    
        Component {
            id: syncLoadFromFileOverwrite
            QGCViewMessage {
                id:         syncLoadFromVehicleCheck
    
    DonLakeFlyer's avatar
    DonLakeFlyer committed
                message:   qsTr("You have unsaved/unsent changes. Loading from a file will lose these changes. Are you sure you want to load from a file?")
    
                function accept() {
                    hideDialog()
    
    Gus Grubba's avatar
    Gus Grubba committed
                    _planMasterController.loadFromSelectedFile()
    
    DonLakeFlyer's avatar
     
    DonLakeFlyer committed
        property var createPlanRemoveAllPromptDialogMapCenter
        property var createPlanRemoveAllPromptDialogPlanCreator
    
    DonLakeFlyer's avatar
     
    DonLakeFlyer committed
            id: createPlanRemoveAllPromptDialog
    
            QGCViewMessage {
    
    DonLakeFlyer's avatar
     
    DonLakeFlyer committed
                message: qsTr("Are you sure you want to remove current plan and create a new plan? ")
    
                function accept() {
    
    DonLakeFlyer's avatar
     
    DonLakeFlyer committed
                    createPlanRemoveAllPromptDialogPlanCreator.createPlan(createPlanRemoveAllPromptDialogMapCenter)
    
        Component {
            id: clearVehicleMissionDialog
            QGCViewMessage {
                message: qsTr("Are you sure you want to remove all mission items and clear the mission from the vehicle?")
                function accept() {
    
    Gus Grubba's avatar
    Gus Grubba committed
                    _planMasterController.removeAllFromVehicle()
    
    DonLakeFlyer's avatar
     
    DonLakeFlyer committed
                    _missionController.setCurrentPlanViewSeqNum(0, true)
    
        //- ToolStrip DropPanel Components
    
        Component {
            id: centerMapDropPanel
    
            CenterMapDropPanel {
                map:            editorMap
                fitFunctions:   mapFitFunctions
            }
        }
    
    
        Component {
            id: patternDropPanel
    
            ColumnLayout {
                spacing:    ScreenTools.defaultFontPixelWidth * 0.5
    
                QGCLabel { text: qsTr("Create complex pattern:") }
    
                Repeater {
    
                    model: _missionController.complexMissionItemNames
    
    
                    QGCButton {
                        text:               modelData
                        Layout.fillWidth:   true
    
                        onClicked: {
    
    DonLakeFlyer's avatar
     
    DonLakeFlyer committed
                            insertComplexItemAfterCurrent(modelData)
    
                            dropPanel.hide()
                        }
                    }
                }
            } // Column
        }
    
            id: syncDropPanel
    
    DonLakeFlyer's avatar
     
    DonLakeFlyer committed
            ColumnLayout {
    
                id:         columnHolder
                spacing:    _margin
    
                property string _overwriteText: (_editingLayer == _layerMission) ? qsTr("Mission overwrite") : ((_editingLayer == _layerGeoFence) ? qsTr("GeoFence overwrite") : qsTr("Rally Points overwrite"))
    
                QGCLabel {
    
    DonLakeFlyer's avatar
     
    DonLakeFlyer committed
                    id:                 unsavedChangedLabel
    
    DonLakeFlyer's avatar
     
    DonLakeFlyer committed
                    Layout.fillWidth:   true
                    wrapMode:           Text.WordWrap
                    text:               activeVehicle ?
                                            qsTr("You have unsaved changes. You should upload to your vehicle, or save to a file.") :
                                            qsTr("You have unsaved changes.")
                    visible:            _planMasterController.dirty
                }
    
                SectionHeader {
                    id:                 createSection
                    Layout.fillWidth:   true