6import Qt.labs.animation
9import QGroundControl.Controls
10import QGroundControl.FlightMap
15 plugin: Plugin { name: "QGroundControl" }
16 opacity: 0.99 // https://bugreports.qt.io/browse/QTBUG-82185
18 property string mapName: 'defaultMap'
19 property bool isSatelliteMap: activeMapType.name.indexOf("Satellite") > -1 || activeMapType.name.indexOf("Hybrid") > -1
20 property var gcsPosition: QGroundControl.qgcPositionManger.gcsPosition
21 property real gcsHeading: QGroundControl.qgcPositionManger.gcsHeading
22 property bool allowGCSLocationCenter: false ///< true: map will center/zoom to gcs location one time
23 property bool allowVehicleLocationCenter: false ///< true: map will center/zoom to vehicle location one time
24 property bool firstGCSPositionReceived: false ///< true: first gcs position update was responded to
25 property bool firstVehiclePositionReceived: false ///< true: first vehicle position update was responded to
26 property bool planView: false ///< true: map being using for Plan view, items should be draggable
28 property var _activeVehicle: QGroundControl.multiVehicleManager.activeVehicle
29 property var _activeVehicleCoordinate: _activeVehicle ? _activeVehicle.coordinate : QtPositioning.coordinate()
31 function setVisibleRegion(region) {
32 // TODO: Is this still necessary with Qt 5.11?
33 // This works around a bug on Qt where if you set a visibleRegion and then the user moves or zooms the map
34 // and then you set the same visibleRegion the map will not move/scale appropriately since it thinks there
37 _map.visibleRegion = QtPositioning.rectangle(QtPositioning.coordinate(0, 0), QtPositioning.coordinate(0, 0))
38 _map.visibleRegion = region
39 if (_map.zoomLevel > maxZoomLevel) {
40 _map.zoomLevel = maxZoomLevel
44 function _possiblyCenterToVehiclePosition() {
45 if (!firstVehiclePositionReceived && allowVehicleLocationCenter && _activeVehicleCoordinate.isValid) {
46 firstVehiclePositionReceived = true
47 center = _activeVehicleCoordinate
48 zoomLevel = QGroundControl.flightMapInitialZoom
52 function centerToSpecifiedLocation() {
53 specifyMapPositionDialogFactory.open()
56 QGCPopupDialogFactory {
57 id: specifyMapPositionDialogFactory
59 dialogComponent: specifyMapPositionDialog
63 id: specifyMapPositionDialog
65 title: qsTr("Specify Position")
67 onCoordinateChanged: center = coordinate
71 // Center map to gcs location
72 onGcsPositionChanged: {
73 if (gcsPosition.isValid && allowGCSLocationCenter && !firstGCSPositionReceived && !firstVehiclePositionReceived) {
74 firstGCSPositionReceived = true
75 //-- Only center on gsc if we have no vehicle (and we are supposed to do so)
76 var _activeVehicleCoordinate = _activeVehicle ? _activeVehicle.coordinate : QtPositioning.coordinate()
77 if(QGroundControl.settingsManager.flyViewSettings.keepMapCenteredOnVehicle.rawValue || !_activeVehicleCoordinate.isValid)
82 function updateActiveMapType() {
83 var settings = QGroundControl.settingsManager.flightMapSettings
84 var fullMapName = settings.mapProvider.value + " " + settings.mapType.value
86 for (var i = 0; i < _map.supportedMapTypes.length; i++) {
87 if (fullMapName === _map.supportedMapTypes[i].name) {
88 _map.activeMapType = _map.supportedMapTypes[i]
94 on_ActiveVehicleCoordinateChanged: _possiblyCenterToVehiclePosition()
99 _possiblyCenterToVehiclePosition()
104 target: QGroundControl.settingsManager.flightMapSettings.mapType
105 function onRawValueChanged() { updateActiveMapType() }
109 target: QGroundControl.settingsManager.flightMapSettings.mapProvider
110 function onRawValueChanged() { updateActiveMapType() }
115 signal mapClicked(var position)
116 signal mapRightClicked(var position)
117 signal mapPressAndHold(var position)
123 property var pinchStartCentroid
127 pinchStartCentroid = _map.toCoordinate(pinchHandler.centroid.position, false)
130 onScaleChanged: (delta) => {
131 let newZoomLevel = Math.max(_map.zoomLevel + Math.log2(delta), 0)
132 _map.zoomLevel = newZoomLevel
133 _map.alignCoordinateToPoint(pinchStartCentroid, pinchHandler.centroid.position)
138 // workaround for QTBUG-87646 / QTBUG-112394 / QTBUG-112432:
139 // Magic Mouse pretends to be a trackpad but doesn't work with PinchHandler
140 // and we don't yet distinguish mice and trackpads on Wayland either
141 acceptedDevices: Qt.platform.pluginName === "cocoa" || Qt.platform.pluginName === "wayland" ?
142 PointerDevice.Mouse | PointerDevice.TouchPad : PointerDevice.Mouse
143 rotationScale: 1 / 120
144 property: "zoomLevel"
148 // We specifically do not use a DragHandler for panning. It just causes too many problems if you overlay anything else like a Flickable above it.
149 // Causes all sorts of crazy problems where dragging/scrolling no longerr works on items above in the hierarchy.
150 // Since we are using a MouseArea we also can't use TapHandler for clicks. So we handle that here as well.
151 MultiPointTouchArea {
154 maximumTouchPoints: 1
157 property bool dragActive: false
158 property real lastMouseX
159 property real lastMouseY
160 property bool isPressed: false
161 property bool pressAndHold: false
163 onPressed: (touchPoints) => {
164 lastMouseX = touchPoints[0].x
165 lastMouseY = touchPoints[0].y
168 pressAndHoldTimer.start()
171 onGestureStarted: (gesture) => {
177 onUpdated: (touchPoints) => {
179 let deltaX = touchPoints[0].x - lastMouseX
180 let deltaY = touchPoints[0].y - lastMouseY
181 if (Math.abs(deltaX) >= 1.0 || Math.abs(deltaY) >= 1.0) {
182 _map.pan(lastMouseX - touchPoints[0].x, lastMouseY - touchPoints[0].y)
183 lastMouseX = touchPoints[0].x
184 lastMouseY = touchPoints[0].y
189 onReleased: (touchPoints) => {
191 pressAndHoldTimer.stop()
193 _map.pan(lastMouseX - touchPoints[0].x, lastMouseY - touchPoints[0].y)
196 } else if (!pressAndHold) {
197 mapClicked(Qt.point(touchPoints[0].x, touchPoints[0].y))
203 id: pressAndHoldTimer
204 interval: 600 // hold duration in ms
208 if (multiTouchArea.isPressed && !multiTouchArea.dragActive) {
209 multiTouchArea.pressAndHold = true
210 mapPressAndHold(Qt.point(multiTouchArea.lastMouseX, multiTouchArea.lastMouseY))
218 acceptedButtons: Qt.RightButton
219 propagateComposedEvents: true
221 onPressed: (mouseEvent) => {
222 if (mouseEvent.button === Qt.RightButton) {
223 mapRightClicked(Qt.point(mouseEvent.x, mouseEvent.y))
228 /// Ground Station location
230 anchorPoint.x: sourceItem.width / 2
231 anchorPoint.y: sourceItem.height / 2
232 visible: gcsPosition.isValid
233 coordinate: gcsPosition
237 source: isNaN(gcsHeading) ? "/res/QGCLogoFull.svg" : "/res/QGCLogoArrow.svg"
240 fillMode: Image.PreserveAspectFit
241 height: ScreenTools.defaultFontPixelHeight * (isNaN(gcsHeading) ? 1.75 : 2.5 )
242 sourceSize.height: height
243 transform: Rotation {
244 origin.x: mapItemImage.width / 2
245 origin.y: mapItemImage.height / 2
246 angle: isNaN(gcsHeading) ? 0 : gcsHeading