MissionEditor.qml 40.3 KB
Newer Older
1 2 3 4 5 6 7 8
/****************************************************************************
 *
 *   (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
9 10


Don Gagne's avatar
Don Gagne committed
11 12 13 14 15
import QtQuick          2.4
import QtQuick.Controls 1.3
import QtQuick.Dialogs  1.2
import QtLocation       5.3
import QtPositioning    5.3
dogmaphobic's avatar
dogmaphobic committed
16
import QtQuick.Layouts  1.2
Don Gagne's avatar
Don Gagne committed
17

18
import QGroundControl               1.0
Don Gagne's avatar
Don Gagne committed
19 20 21 22
import QGroundControl.FlightMap     1.0
import QGroundControl.ScreenTools   1.0
import QGroundControl.Controls      1.0
import QGroundControl.Palette       1.0
Don Gagne's avatar
Don Gagne committed
23
import QGroundControl.Mavlink       1.0
24
import QGroundControl.Controllers   1.0
Don Gagne's avatar
Don Gagne committed
25 26

/// Mission Editor
Don Gagne's avatar
Don Gagne committed
27

Don Gagne's avatar
Don Gagne committed
28
QGCView {
29 30
    id:         _root

31
    viewPanel:          panel
Don Gagne's avatar
Don Gagne committed
32

33
    // zOrder comes from the Loader in MainWindow.qml
Gus Grubba's avatar
Gus Grubba committed
34
    z: QGroundControl.zOrderTopMost
35

36 37 38 39 40 41 42 43
    readonly property int       _decimalPlaces:         8
    readonly property real      _horizontalMargin:      ScreenTools.defaultFontPixelWidth  / 2
    readonly property real      _margin:                ScreenTools.defaultFontPixelHeight * 0.5
    readonly property var       _activeVehicle:         QGroundControl.multiVehicleManager.activeVehicle
    readonly property real      _rightPanelWidth:       Math.min(parent.width / 3, ScreenTools.defaultFontPixelWidth * 30)
    readonly property real      _rightPanelOpacity:     0.8
    readonly property int       _toolButtonCount:       6
    readonly property real      _toolButtonTopMargin:   parent.height - ScreenTools.availableHeight + (ScreenTools.defaultFontPixelHeight / 2)
44
    readonly property var       _defaultVehicleCoordinate:   QtPositioning.coordinate(37.803784, -122.462276)
45

46
    property var    _visualItems:           missionController.visualItems
Don Gagne's avatar
Don Gagne committed
47
    property var    _currentMissionItem
48
    property int    _currentMissionIndex:   0
49 50
    property bool   _firstVehiclePosition:  true
    property var    activeVehiclePosition:  _activeVehicle ? _activeVehicle.coordinate : QtPositioning.coordinate()
51
    property bool   _lightWidgetBorders:    editorMap.isSatelliteMap
52

53 54 55 56 57 58 59
    /// The controller which should be called for load/save, send to/from vehicle calls
    property var _syncDropDownController: missionController

    readonly property int _layerMission:        1
    readonly property int _layerGeoFence:       2
    property int _editingLayer: _layerMission

60
    onActiveVehiclePositionChanged: updateMapToVehiclePosition()
61

62
    Connections {
63
        target: QGroundControl.multiVehicleManager
64 65 66 67 68 69

        onActiveVehicleChanged: {
            // When the active vehicle changes we need to allow the first vehicle position to move the map again
            _firstVehiclePosition = true
            updateMapToVehiclePosition()
        }
70
    }
71 72

    function updateMapToVehiclePosition() {
73
        if (_activeVehicle && _activeVehicle.coordinateValid && _activeVehicle.coordinate.isValid && _firstVehiclePosition) {
74 75
            _firstVehiclePosition = false
            editorMap.center = _activeVehicle.coordinate
76 77 78
        }
    }

79 80 81 82 83 84 85 86 87 88
    function normalizeLat(lat) {
        // Normalize latitude to range: 0 to 180, S to N
        return lat + 90.0
    }

    function normalizeLon(lon) {
        // Normalize longitude to range: 0 to 360, W to E
        return lon  + 180.0
    }

89
    /// Fix the map viewport to the current mission items.
90
    function fitViewportToMissionItems() {
91 92
        if (_visualItems.count == 1) {
            editorMap.center = _visualItems.get(0).coordinate
93
        } else {
94
            var missionItem = _visualItems.get(0)
95 96 97 98 99
            var north = normalizeLat(missionItem.coordinate.latitude)
            var south = north
            var east = normalizeLon(missionItem.coordinate.longitude)
            var west = east

100 101
            for (var i=1; i<_visualItems.count; i++) {
                missionItem = _visualItems.get(i)
102

103
                if (missionItem.specifiesCoordinate && !missionItem.isStandaloneCoordinate) {
104 105 106 107 108 109 110 111
                    var lat = normalizeLat(missionItem.coordinate.latitude)
                    var lon = normalizeLon(missionItem.coordinate.longitude)

                    north = Math.max(north, lat)
                    south = Math.min(south, lat)
                    east = Math.max(east, lon)
                    west = Math.min(west, lon)
                }
112
            }
113
            editorMap.visibleRegion = QtPositioning.rectangle(QtPositioning.coordinate(north - 90.0, west - 180.0), QtPositioning.coordinate(south - 90.0, east - 180.0))
114 115 116
        }
    }

117
    MissionController {
118
        id: missionController
119

120 121
        Component.onCompleted: {
            start(true /* editMode */)
122
            setCurrentItem(0)
123 124
        }

125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
        function loadFromSelectedFile() {
            if (ScreenTools.isMobile) {
                _root.showDialog(mobileFilePicker, qsTr("Select Mission File"), _root.showDialogDefaultWidth, StandardButton.Yes | StandardButton.Cancel)
            } else {
                missionController.loadFromFilePicker()
                fitViewportToMissionItems()
                _currentMissionItem = _visualItems.get(0)
            }
        }

        function saveToSelectedFile() {
            if (ScreenTools.isMobile) {
                _root.showDialog(mobileFileSaver, qsTr("Save Mission File"), _root.showDialogDefaultWidth, StandardButton.Save | StandardButton.Cancel)
            } else {
                missionController.saveToFilePicker()
            }
        }

        onVisualItemsChanged: {
            itemDragger.clearItem()
        }
146

147 148 149 150 151
        onNewItemsFromVehicle: {
            fitViewportToMissionItems()
            _currentMissionItem = _visualItems.get(0)
        }
    }
152

153 154
    GeoFenceController {
        id: geoFenceController
155

156
        Component.onCompleted: start(true /* editMode */)
157 158 159 160 161 162

        onFenceSupportedChanged: {
            if (!fenceSupported && _editingLayer == _layerGeoFence) {
                _editingLayer = _layerMission
            }
        }
163
    }
164

165
    QGCPalette { id: qgcPal; colorGroupEnabled: enabled }
Don Gagne's avatar
Don Gagne committed
166

167 168 169 170 171 172
    ExclusiveGroup {
        id: _mapTypeButtonsExclusiveGroup
    }

    ExclusiveGroup {
        id: _dropButtonsExclusiveGroup
173 174
    }

175
    function setCurrentItem(sequenceNumber) {
Don Gagne's avatar
Don Gagne committed
176
        _currentMissionItem = undefined
177
        for (var i=0; i<_visualItems.count; i++) {
178 179 180
            var visualItem = _visualItems.get(i)
            if (visualItem.sequenceNumber == sequenceNumber) {
                _currentMissionItem = visualItem
Don Gagne's avatar
Don Gagne committed
181
                _currentMissionItem.isCurrentItem = true
182
                _currentMissionIndex = i
Don Gagne's avatar
Don Gagne committed
183
            } else {
184
                visualItem.isCurrentItem = false
Don Gagne's avatar
Don Gagne committed
185
            }
186 187 188
        }
    }

189 190
    property int _moveDialogMissionItemIndex

191 192 193
    Component {
        id: mobileFilePicker

Don Gagne's avatar
Don Gagne committed
194
        QGCMobileFileDialog {
195 196 197
            openDialog:         true
            fileExtension:      QGroundControl.missionFileExtension
            onFilenameReturned: _syncDropDownController.loadFromfile(filename)
198 199 200 201 202 203
        }
    }

    Component {
        id: mobileFileSaver

Don Gagne's avatar
Don Gagne committed
204
        QGCMobileFileDialog {
205 206 207
            openDialog:         false
            fileExtension:      QGroundControl.missionFileExtension
            onFilenameReturned: _syncDropDownController.saveToFile()
208 209 210
        }
    }

211 212 213 214 215 216 217 218 219 220
    Component {
        id: moveDialog

        QGCViewDialog {
            function accept() {
                var toIndex = toCombo.currentIndex

                if (toIndex == 0) {
                    toIndex = 1
                }
221
                missionController.moveMissionItem(_moveDialogMissionItemIndex, toIndex)
222 223 224 225 226 227 228 229 230 231 232 233
                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
234
                    text:           qsTr("Move the selected mission item to the be after following mission item:")
235 236 237 238
                }

                QGCComboBox {
                    id:             toCombo
239
                    model:          _visualItems.count
240 241 242 243 244 245
                    currentIndex:   _moveDialogMissionItemIndex
                }
            }
        }
    }

Don Gagne's avatar
Don Gagne committed
246 247
    QGCViewPanel {
        id:             panel
248 249 250 251
        height:         ScreenTools.availableHeight
        anchors.bottom: parent.bottom
        anchors.left:   parent.left
        anchors.right:  parent.right
Don Gagne's avatar
Don Gagne committed
252

Don Gagne's avatar
Don Gagne committed
253
        Item {
Don Gagne's avatar
Don Gagne committed
254 255
            anchors.fill: parent

Don Gagne's avatar
Don Gagne committed
256 257
            FlightMap {
                id:             editorMap
258 259 260 261
                height:         _root.height
                anchors.bottom: parent.bottom
                anchors.left:   parent.left
                anchors.right:  parent.right
Don Gagne's avatar
Don Gagne committed
262
                mapName:        "MissionEditor"
263

264 265
                readonly property real animationDuration: 500

266 267 268
                // Initial map position duplicates Fly view position
                Component.onCompleted: editorMap.center = QGroundControl.flightMapPosition

269 270 271 272 273 274 275
                Behavior on zoomLevel {
                    NumberAnimation {
                        duration:       editorMap.animationDuration
                        easing.type:    Easing.InOutQuad
                    }
                }

276 277
                QGCMapPalette { id: mapPal; lightColors: editorMap.isSatelliteMap }

Don Gagne's avatar
Don Gagne committed
278
                MouseArea {
279 280
                    //-- It's a whole lot faster to just fill parent and deal with top offset below
                    //   than computing the coordinate offset.
Don Gagne's avatar
Don Gagne committed
281 282
                    anchors.fill: parent
                    onClicked: {
283 284
                        //-- Don't pay attention to items beneath the toolbar.
                        var topLimit = parent.height - ScreenTools.availableHeight
285 286 287 288 289 290 291 292 293 294 295
                        if(mouse.y < topLimit) {
                            return
                        }

                        var coordinate = editorMap.toCoordinate(Qt.point(mouse.x, mouse.y))
                        coordinate.latitude = coordinate.latitude.toFixed(_decimalPlaces)
                        coordinate.longitude = coordinate.longitude.toFixed(_decimalPlaces)
                        coordinate.altitude = coordinate.altitude.toFixed(_decimalPlaces)

                        switch (_editingLayer) {
                        case _layerMission:
296
                            if (addMissionItemsButton.checked) {
297
                                var sequenceNumber = missionController.insertSimpleMissionItem(coordinate, missionController.visualItems.count)
298 299
                                setCurrentItem(sequenceNumber)
                            }
300 301 302 303
                            break
                        case _layerGeoFence:
                            geoFenceController.breachReturnPoint = coordinate
                            break
304
                        }
Don Gagne's avatar
Don Gagne committed
305
                    }
Don Gagne's avatar
Don Gagne committed
306
                }
Don Gagne's avatar
Don Gagne committed
307

308
                // We use this item to support dragging since dragging a MapQuickItem just doesn't seem to work
Don Gagne's avatar
Don Gagne committed
309 310 311 312
                Rectangle {
                    id:             itemDragger
                    x:              missionItemIndicator ? (missionItemIndicator.x + missionItemIndicator.anchorPoint.x - (itemDragger.width / 2)) : 100
                    y:              missionItemIndicator ? (missionItemIndicator.y + missionItemIndicator.anchorPoint.y - (itemDragger.height / 2)) : 100
313 314
                    width:          ScreenTools.defaultFontPixelHeight * 2
                    height:         ScreenTools.defaultFontPixelHeight * 2
Don Gagne's avatar
Don Gagne committed
315 316 317
                    color:          "transparent"
                    visible:        false
                    z:              QGroundControl.zOrderMapItems + 1    // Above item icons
318 319 320

                    property var    missionItem
                    property var    missionItemIndicator
321 322 323 324 325 326 327 328 329 330 331 332 333 334 335
                    property bool   preventCoordinateBindingLoop: false

                    onXChanged: liveDrag()
                    onYChanged: liveDrag()

                    function liveDrag() {
                        if (!itemDragger.preventCoordinateBindingLoop && Drag.active) {
                            var point = Qt.point(itemDragger.x + (itemDragger.width  / 2), itemDragger.y + (itemDragger.height / 2))
                            var coordinate = editorMap.toCoordinate(point)
                            coordinate.altitude = itemDragger.missionItem.coordinate.altitude
                            itemDragger.preventCoordinateBindingLoop = true
                            itemDragger.missionItem.coordinate = coordinate
                            itemDragger.preventCoordinateBindingLoop = false
                        }
                    }
Don Gagne's avatar
Don Gagne committed
336

337
                    function clearItem() {
Don Gagne's avatar
Don Gagne committed
338 339 340 341 342
                        itemDragger.visible = false
                        itemDragger.missionItem = undefined
                        itemDragger.missionItemIndicator = undefined
                    }

343 344 345 346 347 348 349 350
                    Drag.active:    itemDrag.drag.active
                    Drag.hotSpot.x: width  / 2
                    Drag.hotSpot.y: height / 2

                    MouseArea {
                        id:             itemDrag
                        anchors.fill:   parent
                        drag.target:    parent
Don Gagne's avatar
Don Gagne committed
351 352 353 354
                        drag.minimumX:  0
                        drag.minimumY:  0
                        drag.maximumX:  itemDragger.parent.width - parent.width
                        drag.maximumY:  itemDragger.parent.height - parent.height
Don Gagne's avatar
Don Gagne committed
355
                    }
356
                }
357

358
                // Add the complex mission item polygon to the map
359
                MapItemView {
360 361
                    model: _editingLayer == _layerMission ? missionController.complexVisualItems : undefined

Don Gagne's avatar
Don Gagne committed
362
                    delegate: MapPolygon {
363 364 365 366 367 368
                        color:      'green'
                        path:       object.polygonPath
                        opacity:    0.5
                    }
                }

369 370
                // Add the complex mission item grid to the map
                MapItemView {
371
                    model: _editingLayer == _layerMission ? missionController.complexVisualItems : undefined
372 373 374

                    delegate: MapPolyline {
                        line.color: "white"
375
                        line.width: 2
376 377 378 379
                        path:       object.gridPoints
                    }
                }

380 381
                // Add the complex mission item exit coordinates
                MapItemView {
382
                    model: _editingLayer == _layerMission ? missionController.complexVisualItems : undefined
383 384 385 386 387 388 389 390 391 392 393 394 395
                    delegate:   exitCoordinateComponent
                }

                Component {
                    id: exitCoordinateComponent

                    MissionItemIndicator {
                        coordinate:     object.exitCoordinate
                        z:              QGroundControl.zOrderMapItems
                        missionItem:    object
                        sequenceNumber: object.lastSequenceNumber
                        visible:        object.specifiesCoordinate
                    }
Don Gagne's avatar
Don Gagne committed
396 397
                }

398 399
                // Add the simple mission items to the map
                MapItemView {
400
                    model:      _editingLayer == _layerMission ? missionController.visualItems : undefined
401 402 403
                    delegate:   missionItemComponent
                }

Don Gagne's avatar
Don Gagne committed
404
                Component {
405
                    id: missionItemComponent
Don Gagne's avatar
Don Gagne committed
406 407 408 409

                    MissionItemIndicator {
                        id:             itemIndicator
                        coordinate:     object.coordinate
410
                        visible:        object.specifiesCoordinate
Don Gagne's avatar
Don Gagne committed
411
                        z:              QGroundControl.zOrderMapItems
412
                        missionItem:    object
413
                        sequenceNumber: object.sequenceNumber
Don Gagne's avatar
Don Gagne committed
414

415 416 417
                        //-- If you don't want to allow selecting items beneath the
                        //   toolbar, the code below has to check and see if mouse.y
                        //   is greater than (map.height - ScreenTools.availableHeight)
Don Gagne's avatar
Don Gagne committed
418 419
                        onClicked: setCurrentItem(object.sequenceNumber)

420 421
                        function updateItemIndicator() {
                            if (object.isCurrentItem && itemIndicator.visible && object.specifiesCoordinate && object.isSimpleItem) {
422 423 424 425
                                // Setup our drag item
                                itemDragger.visible = true
                                itemDragger.missionItem = Qt.binding(function() { return object })
                                itemDragger.missionItemIndicator = Qt.binding(function() { return itemIndicator })
Don Gagne's avatar
Don Gagne committed
426 427 428
                            }
                        }

429 430 431
                        Connections {
                            target: object

432 433
                            onIsCurrentItemChanged:         updateItemIndicator()
                            onSpecifiesCoordinateChanged:   updateItemIndicator()
434 435
                        }

Don Gagne's avatar
Don Gagne committed
436 437 438 439 440 441 442 443 444
                        // These are the non-coordinate child mission items attached to this item
                        Row {
                            anchors.top:    parent.top
                            anchors.left:   parent.right

                            Repeater {
                                model: object.childItems

                                delegate: MissionItemIndexLabel {
445
                                    label:          object.abbreviation
Don Gagne's avatar
Don Gagne committed
446 447 448 449 450 451 452 453
                                    isCurrentItem:  object.isCurrentItem
                                    z:              2

                                    onClicked: setCurrentItem(object.sequenceNumber)
                                }
                            }
                        }
                    }
454 455 456
                }

                // Add lines between waypoints
457
                MissionLineView {
458
                    model:      _editingLayer == _layerMission ? missionController.waypointLines : undefined
Don Gagne's avatar
Don Gagne committed
459 460
                }

Don Gagne's avatar
Don Gagne committed
461 462
                // Add the vehicles to the map
                MapItemView {
463
                    model: QGroundControl.multiVehicleManager.vehicles
Don Gagne's avatar
Don Gagne committed
464 465 466 467 468 469 470 471 472 473
                    delegate:
                        VehicleMapItem {
                                vehicle:        object
                                coordinate:     object.coordinate
                                isSatellite:    editorMap.isSatelliteMap
                                size:           ScreenTools.defaultFontPixelHeight * 5
                                z:              QGroundControl.zOrderMapItems - 1
                        }
                }

474
                // Mission Item Editor
Don Gagne's avatar
Don Gagne committed
475
                Item {
476
                    id:             missionItemEditor
477
                    height:         ScreenTools.availableHeight
478 479 480 481
                    anchors.bottom: parent.bottom
                    anchors.right:  parent.right
                    width:          _rightPanelWidth
                    opacity:        _rightPanelOpacity
Gus Grubba's avatar
Gus Grubba committed
482
                    z:              QGroundControl.zOrderTopMost
483
                    visible:        _editingLayer == _layerMission
484

Don Gagne's avatar
Don Gagne committed
485 486 487 488 489 490 491
                    MouseArea {
                         // This MouseArea prevents the Map below it from getting Mouse events. Without this
                         // things like mousewheel will scroll the Flickable and then scroll the map as well.
                         anchors.fill:       editorListView
                         onWheel:            wheel.accepted = true
                     }

492
                    ListView {
493 494 495 496
                        id:             editorListView
                        anchors.left:   parent.left
                        anchors.right:  parent.right
                        anchors.top:    parent.top
497
                        height:         parent.height
498 499
                        spacing:        _margin / 2
                        orientation:    ListView.Vertical
500
                        model:          missionController.visualItems
501
                        cacheBuffer:    height * 2
502
                        clip:           true
503
                        currentIndex:   _currentMissionIndex
504 505
                        highlightMoveDuration: 250

506
                        delegate: MissionItemEditor {
507 508
                            missionItem:    object
                            width:          parent.width
Don Gagne's avatar
Don Gagne committed
509
                            qgcView:        _root
510
                            readOnly:       false
511 512 513 514

                            onClicked:  setCurrentItem(object.sequenceNumber)

                            onRemove: {
515
                                itemDragger.clearItem()
516
                                missionController.removeMissionItem(index)
517 518
                            }

519
                            onInsert: {
520
                                var sequenceNumber = missionController.insertSimpleMissionItem(editorMap.center, insertAfterIndex)
521 522 523
                                setCurrentItem(sequenceNumber)
                            }

524
                            onMoveHomeToMapCenter: _visualItems.get(0).coordinate = editorMap.center
525
                        }
526 527 528
                    } // ListView
                } // Item - Mission Item editor

529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545
                // GeoFence Editor
                Loader {
                    anchors.topMargin:  parent.height - ScreenTools.availableHeight
                    anchors.top:        parent.top
                    anchors.right:      parent.right
                    opacity:            _rightPanelOpacity
                    z:                  QGroundControl.zOrderTopMost
                    source:             _editingLayer == _layerGeoFence ? "qrc:/qml/GeoFenceEditor.qml" : ""

                    property real availableWidth:   _rightPanelWidth
                    property real availableHeight:  ScreenTools.availableHeight
                }

                // GeoFence polygon
                MapPolygon {
                    border.color:   "#80FF0000"
                    border.width:   3
546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562
                    path:           geoFenceController.polygonSupported ? geoFenceController.polygon.path : undefined
                }

                // GeoFence circle
                MapCircle {
                    border.color:   "#80FF0000"
                    border.width:   3
                    center:         missionController.plannedHomePosition
                    radius:         geoFenceController.circleSupported ? geoFenceController.circleRadius : 0
                }

                // GeoFence circle
                MapCircle {
                    border.color:   "#80FF0000"
                    border.width:   3
                    center:         missionController.plannedHomePosition
                    radius:         geoFenceController.circleSupported ? geoFenceController.circleRadius : 0
563 564 565 566 567 568
                }

                // GeoFence breach return point
                MapQuickItem {
                    anchorPoint:    Qt.point(sourceItem.width / 2, sourceItem.height / 2)
                    coordinate:     geoFenceController.breachReturnPoint
569 570
                    visible:        geoFenceController.breachReturnSupported
                    sourceItem:     MissionItemIndexLabel { label: "F" }
571 572
                }

573 574 575 576 577 578 579 580 581 582 583
                //-- Dismiss Drop Down (if any)
                MouseArea {
                    anchors.fill:   parent
                    enabled:        _dropButtonsExclusiveGroup.current != null
                    onClicked: {
                        if(_dropButtonsExclusiveGroup.current)
                            _dropButtonsExclusiveGroup.current.checked = false
                        _dropButtonsExclusiveGroup.current = null
                    }
                }

584 585 586 587 588 589 590 591 592 593
                QGCLabel {
                    id:         planLabel
                    text:       qsTr("Plan")
                    color:      mapPal.text
                    visible:    !ScreenTools.isShortScreen
                    anchors.topMargin:          _toolButtonTopMargin
                    anchors.horizontalCenter:   toolColumn.horizontalCenter
                    anchors.top:                parent.top
                }

594 595
                //-- Vertical Tool Buttons
                Column {
596
                    id:                 toolColumn
597 598
                    anchors.topMargin:  ScreenTools.isShortScreen ? _toolButtonTopMargin : ScreenTools.defaultFontPixelHeight / 2
                    anchors.leftMargin: ScreenTools.defaultFontPixelHeight
599
                    anchors.left:       parent.left
600
                    anchors.top:        ScreenTools.isShortScreen ? parent.top : planLabel.bottom
601
                    spacing:            ScreenTools.defaultFontPixelHeight
Don Gagne's avatar
Don Gagne committed
602
                    z:                  QGroundControl.zOrderWidgets
603

604 605 606 607 608 609
                    DropButton {
                        id:                 layerButton
                        dropDirection:      dropRight
                        viewportMargins:    ScreenTools.defaultFontPixelWidth / 2
                        exclusiveGroup:     _dropButtonsExclusiveGroup
                        lightBorders:       _lightWidgetBorders
610
                        visible:            geoFenceController.fenceSupported
611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644

                        dropDownComponent: Component {
                            Column {
                                spacing: ScreenTools.defaultFontPixelWidth * 0.5

                                QGCLabel { text: qsTr("Editing Layer:") }

                                Row {
                                    spacing: ScreenTools.defaultFontPixelWidth

                                    QGCButton {
                                        text: qsTr("Mission")

                                        onClicked: {
                                            layerButton.hideDropDown()
                                            _editingLayer = _layerMission
                                            _syncDropDownController = missionController
                                        }
                                    }

                                    QGCButton {
                                        text: qsTr("GeoFence")

                                        onClicked: {
                                            layerButton.hideDropDown()
                                            _editingLayer = _layerGeoFence
                                            _syncDropDownController = geoFenceController
                                        }
                                    }
                                }
                            }
                        }
                    }

645
                    RoundButton {
646 647 648
                        id:             addMissionItemsButton
                        buttonImage:    "/qmlimages/MapAddMission.svg"
                        lightBorders:   _lightWidgetBorders
649
                        visible:        _editingLayer == _layerMission
650 651
                    }

652
                    RoundButton {
653 654 655
                        id:             addShapeButton
                        buttonImage:    "/qmlimages/MapDrawShape.svg"
                        lightBorders:   _lightWidgetBorders
656
                        visible:        _editingLayer == _layerMission
657 658 659 660 661 662

                        onClicked: {
                            var coordinate = editorMap.center
                            coordinate.latitude = coordinate.latitude.toFixed(_decimalPlaces)
                            coordinate.longitude = coordinate.longitude.toFixed(_decimalPlaces)
                            coordinate.altitude = coordinate.altitude.toFixed(_decimalPlaces)
663
                            var sequenceNumber = missionController.insertComplexMissionItem(coordinate, missionController.visualItems.count)
664
                            setCurrentItem(sequenceNumber)
665
                            checked = false
666
                            addMissionItemsButton.checked = false
667 668 669
                        }
                    }

670 671 672
                    DropButton {
                        id:                 syncButton
                        dropDirection:      dropRight
673
                        buttonImage:        _syncDropDownController.dirty ? "/qmlimages/MapSyncChanged.svg" : "/qmlimages/MapSync.svg"
674 675 676
                        viewportMargins:    ScreenTools.defaultFontPixelWidth / 2
                        exclusiveGroup:     _dropButtonsExclusiveGroup
                        dropDownComponent:  syncDropDownComponent
677 678
                        enabled:            !_syncDropDownController.syncInProgress
                        rotateImage:        _syncDropDownController.syncInProgress
679
                        lightBorders:       _lightWidgetBorders
680 681
                    }

682 683 684 685 686 687
                    DropButton {
                        id:                 centerMapButton
                        dropDirection:      dropRight
                        buttonImage:        "/qmlimages/MapCenter.svg"
                        viewportMargins:    ScreenTools.defaultFontPixelWidth / 2
                        exclusiveGroup:     _dropButtonsExclusiveGroup
688
                        lightBorders:       _lightWidgetBorders
689

690 691
                        dropDownComponent: Component {
                            Column {
dogmaphobic's avatar
dogmaphobic committed
692
                                spacing: ScreenTools.defaultFontPixelWidth * 0.5
693
                                QGCLabel { text: qsTr("Center map:") }
694 695 696
                                Row {
                                    spacing: ScreenTools.defaultFontPixelWidth
                                    QGCButton {
697
                                        text: qsTr("Home")
dogmaphobic's avatar
dogmaphobic committed
698
                                        width:  ScreenTools.defaultFontPixelWidth * 10
699 700
                                        onClicked: {
                                            centerMapButton.hideDropDown()
701
                                            editorMap.center = missionController.visualItems.get(0).coordinate
702
                                        }
703
                                    }
704
                                    QGCButton {
705
                                        text: qsTr("Mission")
dogmaphobic's avatar
dogmaphobic committed
706
                                        width:  ScreenTools.defaultFontPixelWidth * 10
707 708 709 710
                                        onClicked: {
                                            centerMapButton.hideDropDown()
                                            fitViewportToMissionItems()
                                        }
711
                                    }
712
                                    QGCButton {
713
                                        text:       qsTr("Vehicle")
dogmaphobic's avatar
dogmaphobic committed
714
                                        width:      ScreenTools.defaultFontPixelWidth * 10
715
                                        enabled:    activeVehicle && activeVehicle.latitude != 0 && activeVehicle.longitude != 0
716
                                        property var activeVehicle: _activeVehicle
717 718
                                        onClicked: {
                                            centerMapButton.hideDropDown()
719
                                            editorMap.center = activeVehicle.coordinate
720
                                        }
721 722 723 724 725 726
                                    }
                                }
                            }
                        }
                    }

727 728 729 730 731 732
                    DropButton {
                        id:                 mapTypeButton
                        dropDirection:      dropRight
                        buttonImage:        "/qmlimages/MapType.svg"
                        viewportMargins:    ScreenTools.defaultFontPixelWidth / 2
                        exclusiveGroup:     _dropButtonsExclusiveGroup
733
                        lightBorders:       _lightWidgetBorders
734 735 736

                        dropDownComponent: Component {
                            Column {
dogmaphobic's avatar
dogmaphobic committed
737
                                spacing: _margin
738
                                QGCLabel { text: qsTr("Map type:") }
739 740 741 742
                                Row {
                                    spacing: ScreenTools.defaultFontPixelWidth
                                    Repeater {
                                        model: QGroundControl.flightMapSettings.mapTypes
743

744 745
                                        QGCButton {
                                            checkable:      true
746
                                            checked:        QGroundControl.flightMapSettings.mapType === text
747 748 749
                                            text:           modelData
                                            exclusiveGroup: _mapTypeButtonsExclusiveGroup
                                            onClicked: {
750
                                                QGroundControl.flightMapSettings.mapType = text
751 752 753
                                                checked = true
                                                mapTypeButton.hideDropDown()
                                            }
754 755 756 757 758 759 760
                                        }
                                    }
                                }
                            }
                        }
                    }

761 762
                    //-- Zoom Map In
                    RoundButton {
763 764 765 766 767
                        id:             mapZoomPlus
                        visible:        !ScreenTools.isTinyScreen && !ScreenTools.isShortScreen
                        buttonImage:    "/qmlimages/ZoomPlus.svg"
                        lightBorders:   _lightWidgetBorders

768 769 770 771 772 773 774 775 776
                        onClicked: {
                            if(editorMap)
                                editorMap.zoomLevel += 0.5
                            checked = false
                        }
                    }

                    //-- Zoom Map Out
                    RoundButton {
777 778 779 780
                        id:             mapZoomMinus
                        visible:        !ScreenTools.isTinyScreen && !ScreenTools.isShortScreen
                        buttonImage:    "/qmlimages/ZoomMinus.svg"
                        lightBorders:   _lightWidgetBorders
781 782 783 784 785 786
                        onClicked: {
                            if(editorMap)
                                editorMap.zoomLevel -= 0.5
                            checked = false
                        }
                    }
787
                }
788

789 790 791 792 793 794 795 796 797
                MapScale {
                    anchors.margins:    ScreenTools.defaultFontPixelHeight * (0.66)
                    anchors.bottom:     waypointValuesDisplay.visible ? waypointValuesDisplay.top : parent.bottom
                    anchors.left:       parent.left
                    z:                  QGroundControl.zOrderWidgets
                    mapControl:         editorMap
                    visible:            !ScreenTools.isTinyScreen
                }

798
                MissionItemStatus {
799 800 801 802 803 804 805 806 807 808 809 810 811
                    id:                     waypointValuesDisplay
                    anchors.margins:        ScreenTools.defaultFontPixelWidth
                    anchors.left:           parent.left
                    anchors.bottom:         parent.bottom
                    z:                      QGroundControl.zOrderTopMost
                    currentMissionItem:     _currentMissionItem
                    missionItems:           missionController.visualItems
                    expandedWidth:          missionItemEditor.x - (ScreenTools.defaultFontPixelWidth * 2)
                    missionDistance:        missionController.missionDistance
                    missionMaxTelemetry:    missionController.missionMaxTelemetry
                    cruiseDistance:         missionController.cruiseDistance
                    hoverDistance:          missionController.hoverDistance
                    visible:                _editingLayer == _layerMission && !ScreenTools.isShortScreen
812
                }
813
            } // FlightMap
Don Gagne's avatar
Don Gagne committed
814 815
        } // Item - split view container
    } // QGCViewPanel
816

817 818 819 820
    Component {
        id: syncLoadFromVehicleOverwrite
        QGCViewMessage {
            id:         syncLoadFromVehicleCheck
821
            message:   qsTr("You have unsaved/unsent mission changes. Loading the mission from the Vehicle will lose these changes. Are you sure you want to load the mission from the Vehicle?")
822 823
            function accept() {
                hideDialog()
824
                loadFromVehicle()
825 826 827 828 829 830 831 832
            }
        }
    }

    Component {
        id: syncLoadFromFileOverwrite
        QGCViewMessage {
            id:         syncLoadFromVehicleCheck
833
            message:   qsTr("You have unsaved/unsent mission changes. Loading a mission from a file will lose these changes. Are you sure you want to load a mission from a file?")
834 835
            function accept() {
                hideDialog()
836
                loadFromFile()
837 838 839 840
            }
        }
    }

841 842 843
    Component {
        id: removeAllPromptDialog
        QGCViewMessage {
844
            message: qsTr("Are you sure you want to delete all mission items?")
845 846
            function accept() {
                itemDragger.clearItem()
847
                missionController.removeAll()
848 849 850 851 852
                hideDialog()
            }
        }
    }

853 854
    Component {
        id: syncDropDownComponent
855

856 857 858
        Column {
            id:         columnHolder
            spacing:    _margin
859

860
            QGCLabel {
dogmaphobic's avatar
dogmaphobic committed
861
                width:      sendSaveGrid.width
862
                wrapMode:   Text.WordWrap
863
                text:       _syncDropDownController.dirty ?
864
                                qsTr("You have unsaved changes to your mission. You should send to your vehicle, or save to a file:") :
865
                                qsTr("Sync:")
866
            }
867

dogmaphobic's avatar
dogmaphobic committed
868 869 870 871 872 873
            GridLayout {
                id:                 sendSaveGrid
                columns:            2
                anchors.margins:    _margin
                rowSpacing:         _margin
                columnSpacing:      ScreenTools.defaultFontPixelWidth
874

875
                QGCButton {
dogmaphobic's avatar
dogmaphobic committed
876 877
                    text:               qsTr("Send To Vehicle")
                    Layout.fillWidth:   true
878
                    enabled:            _activeVehicle && !_syncDropDownController.syncInProgress
879 880
                    onClicked: {
                        syncButton.hideDropDown()
881
                        _syncDropDownController.sendToVehicle()
882 883
                    }
                }
884

885
                QGCButton {
dogmaphobic's avatar
dogmaphobic committed
886 887
                    text:               qsTr("Load From Vehicle")
                    Layout.fillWidth:   true
888
                    enabled:            _activeVehicle && !_syncDropDownController.syncInProgress
889 890
                    onClicked: {
                        syncButton.hideDropDown()
891
                        if (_syncDropDownController.dirty) {
892
                            _root.showDialog(syncLoadFromVehicleOverwrite, qsTr("Mission overwrite"), _root.showDialogDefaultWidth, StandardButton.Yes | StandardButton.Cancel)
893
                        } else {
894
                            _syncDropDownController.loadFromVehicle()
895
                        }
896 897
                    }
                }
898

899
                QGCButton {
dogmaphobic's avatar
dogmaphobic committed
900 901
                    text:               qsTr("Save To File...")
                    Layout.fillWidth:   true
902
                    enabled:            !_syncDropDownController.syncInProgress
903 904
                    onClicked: {
                        syncButton.hideDropDown()
905
                        _syncDropDownController.saveToSelectedFile()
906 907
                    }
                }
908

909
                QGCButton {
dogmaphobic's avatar
dogmaphobic committed
910 911
                    text:               qsTr("Load From File...")
                    Layout.fillWidth:   true
912
                    enabled:            !_syncDropDownController.syncInProgress
913 914
                    onClicked: {
                        syncButton.hideDropDown()
915
                        if (_syncDropDownController.dirty) {
916
                            _root.showDialog(syncLoadFromFileOverwrite, qsTr("Mission overwrite"), _root.showDialogDefaultWidth, StandardButton.Yes | StandardButton.Cancel)
917
                        } else {
918
                            _syncDropDownController.loadFromSelectedFile()
919
                        }
920 921
                    }
                }
922

dogmaphobic's avatar
dogmaphobic committed
923 924 925 926 927
                QGCButton {
                    text:               qsTr("Remove All")
                    Layout.fillWidth:   true
                    onClicked:  {
                        syncButton.hideDropDown()
928
                        _syncDropDownController.removeAll()
dogmaphobic's avatar
dogmaphobic committed
929 930
                        _root.showDialog(removeAllPromptDialog, qsTr("Delete all"), _root.showDialogDefaultWidth, StandardButton.Yes | StandardButton.No)
                    }
931 932
                }
            }
933 934
        }
    }
Don Gagne's avatar
Don Gagne committed
935
} // QGCVIew