diff --git a/qgroundcontrol.qrc b/qgroundcontrol.qrc
index 9960752..9fe698a 100644
--- a/qgroundcontrol.qrc
+++ b/qgroundcontrol.qrc
@@ -94,6 +94,8 @@
src/QmlControls/SubMenuButton.qml
src/QmlControls/VehicleRotationCal.qml
src/QmlControls/VehicleSummaryRow.qml
+ src/QmlControls/ToolStrip.qml
+ src/QmlControls/DropPanel.qml
src/ViewWidgets/ViewWidget.qml
src/FactSystem/FactControls/FactBitmask.qml
src/FactSystem/FactControls/FactCheckBox.qml
@@ -111,6 +113,8 @@
src/FlightDisplay/MultiVehicleList.qml
src/FlightDisplay/qmldir
src/FlightMap/Widgets/CenterMapDropButton.qml
+ src/FlightMap/Widgets/CenterMapDropPanel.qml
+ src/FlightMap/Widgets/MapFitFunctions.qml
src/FlightMap/FlightMap.qml
src/FlightMap/Widgets/InstrumentSwipeView.qml
src/FlightMap/MapScale.qml
diff --git a/src/FlightMap/Widgets/CenterMapDropPanel.qml b/src/FlightMap/Widgets/CenterMapDropPanel.qml
new file mode 100644
index 0000000..fe3a43b
--- /dev/null
+++ b/src/FlightMap/Widgets/CenterMapDropPanel.qml
@@ -0,0 +1,103 @@
+/****************************************************************************
+ *
+ * (c) 2009-2016 QGROUNDCONTROL PROJECT
+ *
+ * QGroundControl is licensed according to the terms in the file
+ * COPYING.md in the root of the source code directory.
+ *
+ ****************************************************************************/
+
+import QtQuick 2.4
+import QtQuick.Controls 1.3
+import QtQuick.Layouts 1.2
+import QtPositioning 5.3
+
+import QGroundControl 1.0
+import QGroundControl.ScreenTools 1.0
+import QGroundControl.Controls 1.0
+import QGroundControl.Palette 1.0
+
+ColumnLayout {
+ id: root
+ spacing: ScreenTools.defaultFontPixelWidth * 0.5
+
+ property var map
+ property var fitFunctions
+ property bool showMission: true
+ property bool showAllItems: true
+ property bool showFollowVehicle: false
+ property bool followVehicle: false
+
+ property var _activeVehicle: QGroundControl.multiVehicleManager.activeVehicle
+
+ QGCLabel { text: qsTr("Center map on:") }
+
+ QGCButton {
+ text: qsTr("Mission")
+ Layout.fillWidth: true
+ visible: showMission
+ enabled: !followVehicleCheckBox.checked
+
+ onClicked: {
+ dropPanel.hide()
+ fitFunctions.fitMapViewportToMissionItems()
+ }
+ }
+
+ QGCButton {
+ text: qsTr("All items")
+ Layout.fillWidth: true
+ visible: showAllItems
+ enabled: !followVehicleCheckBox.checked
+
+ onClicked: {
+ dropPanel.hide()
+ fitFunctions.fitMapViewportToAllItems()
+ }
+ }
+
+ QGCButton {
+ text: qsTr("Home")
+ Layout.fillWidth: true
+ enabled: !followVehicleCheckBox.checked
+
+ onClicked: {
+ dropPanel.hide()
+ map.center = fitFunctions.fitHomePosition()
+ }
+ }
+
+ QGCButton {
+ text: qsTr("Current Location")
+ Layout.fillWidth: true
+ enabled: mainWindow.gcsPosition.isValid && !followVehicleCheckBox.checked
+
+ onClicked: {
+ dropPanel.hide()
+ map.center = mainWindow.gcsPosition
+ }
+ }
+
+ QGCButton {
+ text: qsTr("Vehicle")
+ Layout.fillWidth: true
+ enabled: _activeVehicle && _activeVehicle.latitude != 0 && _activeVehicle.longitude != 0 && !followVehicleCheckBox.checked
+
+ onClicked: {
+ dropPanel.hide()
+ map.center = activeVehicle.coordinate
+ }
+ }
+
+ QGCCheckBox {
+ id: followVehicleCheckBox
+ text: qsTr("Follow Vehicle")
+ checked: followVehicle
+ visible: showFollowVehicle
+
+ onClicked: {
+ dropPanel.hide()
+ _root.followVehicle = checked
+ }
+ }
+} // Column
diff --git a/src/FlightMap/Widgets/MapFitFunctions.qml b/src/FlightMap/Widgets/MapFitFunctions.qml
new file mode 100644
index 0000000..dc76a54
--- /dev/null
+++ b/src/FlightMap/Widgets/MapFitFunctions.qml
@@ -0,0 +1,144 @@
+/****************************************************************************
+ *
+ * (c) 2009-2016 QGROUNDCONTROL PROJECT
+ *
+ * QGroundControl is licensed according to the terms in the file
+ * COPYING.md in the root of the source code directory.
+ *
+ ****************************************************************************/
+
+import QtQuick 2.4
+import QtPositioning 5.3
+
+import QGroundControl 1.0
+
+/// Set of functions for fitting the map viewpoer to a specific constraint
+Item {
+ property var map
+ property rect mapFitViewport
+ property bool usePlannedHomePosition ///< true: planned home position used for calculations, false: vehicle home position use for calculations
+ property var mapGeoFenceController
+ property var mapMissionController
+ property var mapRallyPointController
+
+ property var _activeVehicle: QGroundControl.multiVehicleManager.activeVehicle
+
+ function fitHomePosition() {
+ var homePosition = QtPositioning.coordinate()
+ var activeVehicle = QGroundControl.multiVehicleManager.activeVehicle
+ if (usePlannedHomePosition) {
+ homePosition = mapMissionController.visualItems.get(0).coordinate
+ } else if (activeVehicle) {
+ homePosition = activeVehicle.homePosition
+ }
+ return homePosition
+ }
+
+ /// Normalize latitude to range: 0 to 180, S to N
+ function normalizeLat(lat) {
+ return lat + 90.0
+ }
+
+ /// Normalize longitude to range: 0 to 360, W to E
+ function normalizeLon(lon) {
+ return lon + 180.0
+ }
+
+ /// Fits the visible region of the map to inclues all of the specified coordinates. If no coordinates
+ /// are specified the map will center to fitHomePosition()
+ function fitMapViewportToAllCoordinates(coordList) {
+ if (coordList.length == 0) {
+ map.center = fitHomePosition()
+ return
+ }
+
+ // Create the normalized lat/lon corners for the coordinate bounding rect from the list of coordinates
+ var north = normalizeLat(coordList[0].latitude)
+ var south = north
+ var east = normalizeLon(coordList[0].longitude)
+ var west = east
+ for (var i=1; i 2) {
+ for (var i=0; i
+ *
+ * QGroundControl is licensed according to the terms in the file
+ * COPYING.md in the root of the source code directory.
+ *
+ ****************************************************************************/
+
+import QtQuick 2.4
+import QtQuick.Controls 1.2
+import QtQuick.Controls.Styles 1.2
+
+import QGroundControl 1.0
+import QGroundControl.ScreenTools 1.0
+import QGroundControl.Palette 1.0
+
+Item {
+ id: _root
+ z: QGroundControl.zOrderWidgets
+ visible: false
+
+ signal clicked()
+ property real radius: ScreenTools.isMobile ? ScreenTools.defaultFontPixelHeight * 1.75 : ScreenTools.defaultFontPixelHeight * 1.25
+ property real viewportMargins: 0
+ property real topMargin: parent.height - ScreenTools.availableHeight
+ property var toolStrip
+
+
+ width: radius * 2
+ height: radius * 2
+
+ // Should be an enum but that get's into the whole problem of creating a singleton which isn't worth the effort
+ readonly property int dropLeft: 1
+ readonly property int dropRight: 2
+ readonly property int dropUp: 3
+ readonly property int dropDown: 4
+
+ readonly property real _arrowBaseWidth: radius // Width of long side of arrow
+ readonly property real _arrowPointHeight: radius * 0.666 // Height is long side to point
+ readonly property real _dropCornerRadius: ScreenTools.defaultFontPixelWidth * 0.5
+ readonly property real _dropCornerRadiusX2: _dropCornerRadius * 2
+ readonly property real _dropMargin: _dropCornerRadius
+ readonly property real _dropMarginX2: _dropMargin * 2
+
+ property var _dropEdgeTopPoint
+ property real _dropEdgeHeight
+ property alias _dropDownComponent: dropDownLoader.sourceComponent
+ property real _viewportMaxLeft: -x + viewportMargins
+ property real _viewportMaxRight: parent.width - (viewportMargins * 2) - x
+ property real _viewportMaxTop: -y + viewportMargins + topMargin
+ property real _viewportMaxBottom: parent.height - (viewportMargins * 2) - y
+
+ function show(panelEdgeTopPoint, panelEdgeHeight, panelComponent) {
+ _dropEdgeTopPoint = panelEdgeTopPoint
+ _dropEdgeHeight = panelEdgeHeight
+ _dropDownComponent = panelComponent
+ _calcPositions()
+ visible = true
+ }
+
+ function hide() {
+ if (visible) {
+ visible = false
+ _dropDownComponent = undefined
+ toolStrip.uncheckAll()
+ }
+ }
+
+ function _calcPositions() {
+ var dropComponentWidth = dropDownLoader.item.width
+ var dropComponentHeight = dropDownLoader.item.height
+ var dropRectWidth = dropComponentWidth + _dropMarginX2
+ var dropRectHeight = dropComponentHeight + _dropMarginX2
+
+ dropItemHolderRect.width = dropRectWidth
+ dropItemHolderRect.height = dropRectHeight
+
+ dropDownItem.width = dropComponentWidth + _dropMarginX2
+ dropDownItem.height = dropComponentHeight + _dropMarginX2
+
+ dropDownItem.width += _arrowPointHeight
+
+ dropDownItem.y = _dropEdgeTopPoint.y -(dropDownItem.height / 2) + radius
+
+ dropItemHolderRect.y = 0
+
+ dropDownItem.x = _dropEdgeTopPoint.x + _dropMargin
+ dropItemHolderRect.x = _arrowPointHeight
+
+ // Validate that dropdown is within viewport
+ dropDownItem.y = Math.max(dropDownItem.y, _viewportMaxTop)
+ dropDownItem.y = Math.min(dropDownItem.y + dropDownItem.height, _viewportMaxBottom) - dropDownItem.height
+
+ // Arrow points
+ arrowCanvas.arrowPoint.y = (_dropEdgeTopPoint.y + radius) - dropDownItem.y
+ arrowCanvas.arrowPoint.x = 0
+ arrowCanvas.arrowBase1.x = _arrowPointHeight
+ arrowCanvas.arrowBase1.y = arrowCanvas.arrowPoint.y - (_arrowBaseWidth / 2)
+ arrowCanvas.arrowBase2.x = arrowCanvas.arrowBase1.x
+ arrowCanvas.arrowBase2.y = arrowCanvas.arrowBase1.y + _arrowBaseWidth
+ arrowCanvas.requestPaint()
+ } // function - _calcPositions
+
+ QGCPalette { id: qgcPal }
+
+ /*
+ MouseArea {
+ x: _viewportMaxLeft
+ y: _viewportMaxTop
+ width: _viewportMaxRight -_viewportMaxLeft
+ height: _viewportMaxBottom - _viewportMaxTop
+ visible: checked
+ onClicked: {
+ checked = false
+ _root.clicked()
+ }
+ }*/
+
+ Item {
+ id: dropDownItem
+
+ Canvas {
+ id: arrowCanvas
+ anchors.fill: parent
+
+ property var arrowPoint: Qt.point(0, 0)
+ property var arrowBase1: Qt.point(0, 0)
+ property var arrowBase2: Qt.point(0, 0)
+
+ onPaint: {
+ var context = getContext("2d")
+ context.reset()
+ context.beginPath()
+
+ context.moveTo(dropItemHolderRect.x, dropItemHolderRect.y)
+ context.lineTo(dropItemHolderRect.x + dropItemHolderRect.width, dropItemHolderRect.y)
+ context.lineTo(dropItemHolderRect.x + dropItemHolderRect.width, dropItemHolderRect.y + dropItemHolderRect.height)
+ context.lineTo(dropItemHolderRect.x, dropItemHolderRect.y + dropItemHolderRect.height)
+ context.lineTo(arrowBase2.x, arrowBase2.y)
+ context.lineTo(arrowPoint.x, arrowPoint.y)
+ context.lineTo(arrowBase1.x, arrowBase1.y)
+ context.lineTo(dropItemHolderRect.x, dropItemHolderRect.y)
+ context.closePath()
+ context.fillStyle = qgcPal.windowShade
+ context.fill()
+ }
+ } // Canvas - arrowCanvas
+
+ Item {
+ id: dropItemHolderRect
+
+ Loader {
+ id: dropDownLoader
+ x: _dropMargin
+ y: _dropMargin
+
+ property var dropPanel: _root
+ }
+ }
+ } // Item - dropDownItem
+}
diff --git a/src/QmlControls/QGroundControl.Controls.qmldir b/src/QmlControls/QGroundControl.Controls.qmldir
index c33e30f..eed1fdc 100644
--- a/src/QmlControls/QGroundControl.Controls.qmldir
+++ b/src/QmlControls/QGroundControl.Controls.qmldir
@@ -4,6 +4,7 @@ AnalyzePage 1.0 AnalyzePage.qml
AppMessages 1.0 AppMessages.qml
ClickableColor 1.0 ClickableColor.qml
DropButton 1.0 DropButton.qml
+DropPanel 1.0 DropPanel.qml
ExclusiveGroupItem 1.0 ExclusiveGroupItem.qml
FactSliderPanel 1.0 FactSliderPanel.qml
FlightModeDropdown 1.0 FlightModeDropdown.qml
@@ -49,6 +50,7 @@ SetupPage 1.0 SetupPage.qml
SignalStrength 1.0 SignalStrength.qml
SliderSwitch 1.0 SliderSwitch.qml
SubMenuButton 1.0 SubMenuButton.qml
+ToolStrip 1.0 ToolStrip.qml
VehicleRotationCal 1.0 VehicleRotationCal.qml
VehicleSummaryRow 1.0 VehicleSummaryRow.qml
ViewWidget 1.0 ViewWidget.qml
diff --git a/src/QmlControls/ToolStrip.qml b/src/QmlControls/ToolStrip.qml
new file mode 100644
index 0000000..9c2e7c3
--- /dev/null
+++ b/src/QmlControls/ToolStrip.qml
@@ -0,0 +1,183 @@
+/****************************************************************************
+ *
+ * (c) 2009-2016 QGROUNDCONTROL PROJECT
+ *
+ * QGroundControl is licensed according to the terms in the file
+ * COPYING.md in the root of the source code directory.
+ *
+ ****************************************************************************/
+
+import QtQuick 2.4
+import QtQuick.Controls 1.2
+
+import QGroundControl.ScreenTools 1.0
+import QGroundControl.Palette 1.0
+
+Rectangle {
+ id: _root
+ color: qgcPal.window
+ width: ScreenTools.defaultFontPixelWidth * 6
+ height: buttonStripColumn.height + (buttonStripColumn.anchors.margins * 2)
+ radius: _radius
+
+ property string title: "Title"
+ property alias model: repeater.model
+ property var showAlternateIcon
+ property var rotateImage
+ property var buttonEnabled
+
+ signal clicked(int index, bool checked)
+
+ readonly property real _radius: ScreenTools.defaultFontPixelWidth / 2
+ readonly property real _margin: ScreenTools.defaultFontPixelWidth / 2
+ readonly property real _buttonSpacing: ScreenTools.defaultFontPixelWidth
+
+ ExclusiveGroup {
+ id: dropButtonsExclusiveGroup
+ }
+
+ function uncheckAll() {
+ dropButtonsExclusiveGroup.current = null
+ // Signal all toggles as off
+ for (var i=0; i