From c27ea6d5d7e4ddb00c4c4f6ef76c2a2259cf836b Mon Sep 17 00:00:00 2001 From: srcejon Date: Sat, 6 Apr 2024 11:45:37 +0100 Subject: [PATCH] VOR localizer: Get it working on Qt6. --- plugins/feature/vorlocalizer/map.qrc | 2 + .../vorlocalizer/map/ModifiedMapView.qml | 178 ++++++++++++++++++ plugins/feature/vorlocalizer/map/map_6.qml | 156 +++++++++++++++ .../feature/vorlocalizer/vorlocalizergui.cpp | 9 + 4 files changed, 345 insertions(+) create mode 100644 plugins/feature/vorlocalizer/map/ModifiedMapView.qml create mode 100644 plugins/feature/vorlocalizer/map/map_6.qml diff --git a/plugins/feature/vorlocalizer/map.qrc b/plugins/feature/vorlocalizer/map.qrc index f5985ce53..1fec0ef98 100644 --- a/plugins/feature/vorlocalizer/map.qrc +++ b/plugins/feature/vorlocalizer/map.qrc @@ -1,7 +1,9 @@ map/map.qml + map/map_6.qml map/MapStation.qml + map/ModifiedMapView.qml map/antenna.png map/VOR.png map/VOR-DME.png diff --git a/plugins/feature/vorlocalizer/map/ModifiedMapView.qml b/plugins/feature/vorlocalizer/map/ModifiedMapView.qml new file mode 100644 index 000000000..2aa266940 --- /dev/null +++ b/plugins/feature/vorlocalizer/map/ModifiedMapView.qml @@ -0,0 +1,178 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +import QtQuick +import QtLocation as QL +import QtPositioning as QP +import Qt.labs.animation +/*! + \qmltype MapView + \inqmlmodule QtLocation + \brief An interactive map viewer component. + + MapView wraps a Map and adds the typical interactive features: + changing the zoom level, panning and tilting the map. + + The implementation is a QML assembly of smaller building blocks that are + available separately. In case you want to make changes in your own version + of this component, you can copy the QML, which is installed into the + \c qml/QtLocation module directory, and modify it as needed. + + \sa Map +*/ +Item { + /*! + \qmlproperty Map MapView::map + + This property provides access to the underlying Map instance. + */ + property alias map: map + + /*! + \qmlproperty real minimumZoomLevel + + The minimum zoom level according to the size of the view. + + \sa Map::minimumZoomLevel + */ + property real minimumZoomLevel: map.minimumZoomLevel + + /*! + \qmlproperty real maximumZoomLevel + + The maximum valid zoom level for the map. + + \sa Map::maximumZoomLevel + */ + property real maximumZoomLevel: map.maximumZoomLevel + + // -------------------------------- + // implementation + id: root + Component.onCompleted: map.resetPinchMinMax() + + QL.Map { + id: map + width: parent.width + height: parent.height + tilt: tiltHandler.persistentTranslation.y / -5 + property bool pinchAdjustingZoom: false + + BoundaryRule on zoomLevel { + id: br + minimum: map.minimumZoomLevel + maximum: map.maximumZoomLevel + } + + onZoomLevelChanged: { + br.returnToBounds(); + if (!pinchAdjustingZoom) resetPinchMinMax() + } + + function resetPinchMinMax() { + pinch.persistentScale = 1 + pinch.scaleAxis.minimum = Math.pow(2, root.minimumZoomLevel - map.zoomLevel + 1) + pinch.scaleAxis.maximum = Math.pow(2, root.maximumZoomLevel - map.zoomLevel - 1) + } + + PinchHandler { + id: pinch + target: null + property real rawBearing: 0 + property QP.geoCoordinate startCentroid + onActiveChanged: if (active) { + flickAnimation.stop() + pinch.startCentroid = map.toCoordinate(pinch.centroid.position, false) + } else { + flickAnimation.restart(centroid.velocity) + map.resetPinchMinMax() + } + onScaleChanged: (delta) => { + map.pinchAdjustingZoom = true + map.zoomLevel += Math.log2(delta) + map.alignCoordinateToPoint(pinch.startCentroid, pinch.centroid.position) + map.pinchAdjustingZoom = false + } + onRotationChanged: (delta) => { + pinch.rawBearing -= delta + // snap to 0° if we're close enough + map.bearing = (Math.abs(pinch.rawBearing) < 5) ? 0 : pinch.rawBearing + map.alignCoordinateToPoint(pinch.startCentroid, pinch.centroid.position) + } + grabPermissions: PointerHandler.TakeOverForbidden + } + WheelHandler { + id: wheel + // workaround for QTBUG-87646 / QTBUG-112394 / QTBUG-112432: + // Magic Mouse pretends to be a trackpad but doesn't work with PinchHandler + // and we don't yet distinguish mice and trackpads on Wayland either + acceptedDevices: Qt.platform.pluginName === "cocoa" || Qt.platform.pluginName === "wayland" + ? PointerDevice.Mouse | PointerDevice.TouchPad + : PointerDevice.Mouse + onWheel: (event) => { + const loc = map.toCoordinate(wheel.point.position) + switch (event.modifiers) { + case Qt.NoModifier: + // jonb - Changed to make more like Qt5 + //map.zoomLevel += event.angleDelta.y / 120 + map.zoomLevel += event.angleDelta.y / 1000 + break + case Qt.ShiftModifier: + map.bearing += event.angleDelta.y / 15 + break + case Qt.ControlModifier: + map.tilt += event.angleDelta.y / 15 + break + } + map.alignCoordinateToPoint(loc, wheel.point.position) + } + } + DragHandler { + id: drag + signal flickStarted // for autotests only + signal flickEnded + target: null + onTranslationChanged: (delta) => map.pan(-delta.x, -delta.y) + onActiveChanged: if (active) { + flickAnimation.stop() + } else { + flickAnimation.restart(centroid.velocity) + } + } + + property vector3d animDest + onAnimDestChanged: if (flickAnimation.running) { + const delta = Qt.vector2d(animDest.x - flickAnimation.animDestLast.x, animDest.y - flickAnimation.animDestLast.y) + map.pan(-delta.x, -delta.y) + flickAnimation.animDestLast = animDest + } + + Vector3dAnimation on animDest { + id: flickAnimation + property vector3d animDestLast + from: Qt.vector3d(0, 0, 0) + duration: 500 + easing.type: Easing.OutQuad + onStarted: drag.flickStarted() + onStopped: drag.flickEnded() + + function restart(vel) { + stop() + map.animDest = Qt.vector3d(0, 0, 0) + animDestLast = Qt.vector3d(0, 0, 0) + to = Qt.vector3d(vel.x / duration * 100, vel.y / duration * 100, 0) + start() + } + } + + DragHandler { + id: tiltHandler + minimumPointCount: 2 + maximumPointCount: 2 + target: null + xAxis.enabled: false + grabPermissions: PointerHandler.TakeOverForbidden + onActiveChanged: if (active) flickAnimation.stop() + } + } +} diff --git a/plugins/feature/vorlocalizer/map/map_6.qml b/plugins/feature/vorlocalizer/map/map_6.qml new file mode 100644 index 000000000..a0e60095e --- /dev/null +++ b/plugins/feature/vorlocalizer/map/map_6.qml @@ -0,0 +1,156 @@ +import QtQuick 2.14 +import QtQuick.Window 2.14 +import QtLocation 6.5 +import QtPositioning 6.5 + +Item { + id: qmlMap + property int vorZoomLevel: 11 + property string mapProvider: "osm" + property variant mapPtr + property string requestedMapType + property variant guiPtr + + function createMap(pluginParameters, requestedMap, gui) { + requestedMapType = requestedMap + guiPtr = gui + + var paramString = "" + for (var prop in pluginParameters) { + var parameter = 'PluginParameter { name: "' + prop + '"; value: "' + pluginParameters[prop] + '"}' + paramString = paramString + parameter + } + var pluginString = 'import QtLocation 6.5; Plugin{ name:"' + mapProvider + '"; ' + paramString + '}' + var plugin = Qt.createQmlObject (pluginString, qmlMap) + + if (mapPtr) { + // Objects aren't destroyed immediately, so don't call findChild("map") + mapPtr.destroy() + mapPtr = null + } + mapPtr = actualMapComponent.createObject(page) + mapPtr.map.plugin = plugin + mapPtr.map.forceActiveFocus() + return mapPtr + } + + Item { + id: page + anchors.fill: parent + } + + Component { + id: actualMapComponent + + ModifiedMapView { + id: mapView + objectName: "mapView" + anchors.fill: parent + map.center: QtPositioning.coordinate(51.5, 0.125) // London + map.zoomLevel: 10 + map.objectName: "map" + // not in 6 + //gesture.enabled: true + //gesture.acceptedGestures: MapGestureArea.PinchGesture | MapGestureArea.PanGesture + + MapItemView { + model: vorModel + delegate: vorRadialComponent + parent: mapView.map + } + + MapStation { + id: station + objectName: "station" + stationName: "Home" + } + + MapItemView { + model: vorModel + delegate: vorComponent + parent: mapView.map + } + + map.onZoomLevelChanged: { + if (map.zoomLevel > 11) { + station.zoomLevel = map.zoomLevel + vorZoomLevel = map.zoomLevel + } else { + station.zoomLevel = 11 + vorZoomLevel = 11 + } + } + + map.onSupportedMapTypesChanged : { + for (var i = 0; i < map.supportedMapTypes.length; i++) { + if (requestedMapType == map.supportedMapTypes[i].name) { + map.activeMapType = map.supportedMapTypes[i] + } + } + } + } + } + + Component { + id: vorRadialComponent + MapPolyline { + line.width: 2 + line.color: 'gray' + path: vorRadial + } + } + + Component { + id: vorComponent + MapQuickItem { + id: vor + anchorPoint.x: image.width/2 + anchorPoint.y: bubble.height/2 + coordinate: position + zoomLevel: vorZoomLevel + + sourceItem: Grid { + columns: 1 + Grid { + horizontalItemAlignment: Grid.AlignHCenter + verticalItemAlignment: Grid.AlignVCenter + columnSpacing: 5 + layer.enabled: true + layer.smooth: true + Image { + id: image + source: vorImage + MouseArea { + anchors.fill: parent + hoverEnabled: true + onDoubleClicked: (mouse) => { + selected = !selected + } + } + } + Rectangle { + id: bubble + color: bubbleColour + border.width: 1 + width: text.width + 5 + height: text.height + 5 + radius: 5 + Text { + id: text + anchors.centerIn: parent + text: vorData + } + MouseArea { + anchors.fill: parent + hoverEnabled: true + onDoubleClicked: (mouse) => { + selected = !selected + } + } + } + } + } + } + } + +} diff --git a/plugins/feature/vorlocalizer/vorlocalizergui.cpp b/plugins/feature/vorlocalizer/vorlocalizergui.cpp index bae749c47..45aa3a76b 100644 --- a/plugins/feature/vorlocalizer/vorlocalizergui.cpp +++ b/plugins/feature/vorlocalizer/vorlocalizergui.cpp @@ -1041,6 +1041,11 @@ void VORLocalizerGUI::applyMapSettings() m_azEl.setLocation(stationLatitude, stationLongitude, stationAltitude); QQuickItem *item = ui->map->rootObject(); + if (!item) + { + qCritical("VORLocalizerGUI::applyMapSettings: Map not found. Are all required Qt plugins installed?"); + return; + } QObject *object = item->findChild("map"); QGeoCoordinate coords; @@ -1146,7 +1151,11 @@ VORLocalizerGUI::VORLocalizerGUI(PluginAPI* pluginAPI, FeatureUISet *featureUISe ui->map->setAttribute(Qt::WA_AcceptTouchEvents, true); ui->map->rootContext()->setContextProperty("vorModel", &m_vorModel); +#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) ui->map->setSource(QUrl(QStringLiteral("qrc:/demodvor/map/map.qml"))); +#else + ui->map->setSource(QUrl(QStringLiteral("qrc:/demodvor/map/map_6.qml"))); +#endif m_muteIcon.addPixmap(QPixmap("://sound_off.png"), QIcon::Normal, QIcon::On); m_muteIcon.addPixmap(QPixmap("://sound_on.png"), QIcon::Normal, QIcon::Off);