From 826f01d24344a0868ddba68cf9b623fdb5ddde94 Mon Sep 17 00:00:00 2001 From: dogmaphobic Date: Sat, 11 Apr 2015 01:04:26 -0400 Subject: [PATCH] Map Display Tweaks --- qgroundcontrol.qrc | 3 + src/QtLocationPlugin/qgeomapreplyqgc.cpp | 12 ++ .../qgeotiledmappingmanagerengineqgc.cpp | 5 +- src/ui/flightdisplay/FlightDisplay.qml | 2 + .../flightdisplay/components/QGCMapBackground.qml | 166 +++++++++++++++++++-- src/ui/flightdisplay/components/QGCSlider.qml | 124 +++++++++++++++ src/ui/flightdisplay/components/qmldir | 1 + src/ui/flightdisplay/components/scale.png | Bin 0 -> 15451 bytes src/ui/flightdisplay/components/scale_end.png | Bin 0 -> 14988 bytes 9 files changed, 302 insertions(+), 11 deletions(-) create mode 100644 src/ui/flightdisplay/components/QGCSlider.qml create mode 100644 src/ui/flightdisplay/components/scale.png create mode 100644 src/ui/flightdisplay/components/scale_end.png diff --git a/qgroundcontrol.qrc b/qgroundcontrol.qrc index 38d3168..ceaef77 100644 --- a/qgroundcontrol.qrc +++ b/qgroundcontrol.qrc @@ -99,6 +99,7 @@ src/ui/flightdisplay/components/QGCMapBackground.qml src/ui/flightdisplay/components/QGCPitchWidget.qml src/ui/flightdisplay/components/QGCSpeedWidget.qml + src/ui/flightdisplay/components/QGCSlider.qml src/ui/flightdisplay/components/compass.svg src/ui/flightdisplay/components/compassNeedle.svg src/ui/flightdisplay/components/crossHair.svg @@ -106,6 +107,8 @@ src/ui/flightdisplay/components/rollDialWhite.svg src/ui/flightdisplay/components/rollPointer.svg src/ui/flightdisplay/components/rollPointerWhite.svg + src/ui/flightdisplay/components/scale.png + src/ui/flightdisplay/components/scale_end.png diff --git a/src/QtLocationPlugin/qgeomapreplyqgc.cpp b/src/QtLocationPlugin/qgeomapreplyqgc.cpp index 7fad5e7..fda5efe 100644 --- a/src/QtLocationPlugin/qgeomapreplyqgc.cpp +++ b/src/QtLocationPlugin/qgeomapreplyqgc.cpp @@ -86,10 +86,16 @@ void QGeoMapReplyQGC::replyDestroyed() void QGeoMapReplyQGC::networkReplyFinished() { if (!m_reply) + { + qWarning() << "NULL Map request reply"; return; + } if (m_reply->error() != QNetworkReply::NoError) + { + qWarning() << "Map request reply error:" << m_reply->error(); return; + } QByteArray a = m_reply->readAll(); setMapImageData(a); @@ -131,10 +137,16 @@ void QGeoMapReplyQGC::networkReplyFinished() void QGeoMapReplyQGC::networkReplyError(QNetworkReply::NetworkError error) { if (!m_reply) + { + qWarning() << "NULL Map request error"; return; + } if (error != QNetworkReply::OperationCanceledError) + { setError(QGeoTiledMapReply::CommunicationError, m_reply->errorString()); + qWarning() << "Map request reply error:" << m_reply->errorString(); + } setFinished(true); m_reply->deleteLater(); diff --git a/src/QtLocationPlugin/qgeotiledmappingmanagerengineqgc.cpp b/src/QtLocationPlugin/qgeotiledmappingmanagerengineqgc.cpp index ae5cd85..bce55cc 100644 --- a/src/QtLocationPlugin/qgeotiledmappingmanagerengineqgc.cpp +++ b/src/QtLocationPlugin/qgeotiledmappingmanagerengineqgc.cpp @@ -58,8 +58,9 @@ QGeoTiledMappingManagerEngineQGC::QGeoTiledMappingManagerEngineQGC(const QVarian : QGeoTiledMappingManagerEngine() { QGeoCameraCapabilities cameraCaps; - cameraCaps.setMinimumZoomLevel(0.0); - cameraCaps.setMaximumZoomLevel(22.0); + cameraCaps.setMinimumZoomLevel(2.0); + cameraCaps.setMaximumZoomLevel(20.0); + cameraCaps.setSupportsBearing(true); setCameraCapabilities(cameraCaps); setTileSize(QSize(256, 256)); diff --git a/src/ui/flightdisplay/FlightDisplay.qml b/src/ui/flightdisplay/FlightDisplay.qml index 3793782..b1dc013 100644 --- a/src/ui/flightdisplay/FlightDisplay.qml +++ b/src/ui/flightdisplay/FlightDisplay.qml @@ -200,6 +200,7 @@ Rectangle { } } + /* MenuItem { text: "Map Always Points North" checkable: true @@ -210,6 +211,7 @@ Rectangle { flightDisplay.saveSetting("mapAlwaysPointsNorth", setBool(mapBackground.alwaysNorth)); } } + */ Menu { id: mapTypeMenu diff --git a/src/ui/flightdisplay/components/QGCMapBackground.qml b/src/ui/flightdisplay/components/QGCMapBackground.qml index 1323174..20132ad 100644 --- a/src/ui/flightdisplay/components/QGCMapBackground.qml +++ b/src/ui/flightdisplay/components/QGCMapBackground.qml @@ -31,11 +31,13 @@ import QtQuick 2.4 import QtPositioning 5.3 import QtLocation 5.3 +import QGroundControl.HUDControls 1.0 + Rectangle { id: root property real latitude: 37.803784 property real longitude : -122.462276 - property real zoomLevel: 12 + property real zoomLevel: (map.maximumZoomLevel - map.minimumZoomLevel) / 2 property real heading: 0 property bool alwaysNorth: true property alias mapItem: map @@ -46,7 +48,7 @@ Rectangle { function adjustSize() { if(root.visible) { - if(alwaysNorth) { + if(true /*alwaysNorth*/) { map.width = root.width; map.height = root.height; } else { @@ -60,6 +62,25 @@ Rectangle { } } + function formatDistance(meters) + { + var dist = Math.round(meters) + if (dist > 1000 ){ + if (dist > 100000){ + dist = Math.round(dist / 1000) + } + else{ + dist = Math.round(dist / 100) + dist = dist / 10 + } + dist = dist + " km" + } + else{ + dist = dist + " m" + } + return dist + } + Plugin { id: mapPlugin name: "QGroundControl" @@ -67,26 +88,153 @@ Rectangle { Map { id: map - property real lon: (longitude > -180.1 && longitude < 180.1) ? longitude : 0 - property real lat: (latitude > -180.1 && latitude < 180.1) ? latitude : 0 + property real lon: (longitude >= -180 && longitude <= 180) ? longitude : 0 + property real lat: (latitude >= -90 && latitude <= 90) ? latitude : 0 + property variant scaleLengths: [5, 10, 25, 50, 100, 150, 250, 500, 1000, 2000, 5000, 10000, 20000, 50000, 100000, 200000, 500000, 1000000, 2000000] plugin: mapPlugin width: 1 height: 1 - zoomLevel: zoomLevel + zoomLevel: root.zoomLevel anchors.centerIn: parent center: map.visible ? QtPositioning.coordinate(lat, lon) : QtPositioning.coordinate(0,0) + /* transform: Rotation { origin.x: map.width / 2 origin.y: map.height / 2 angle: map.visible ? (alwaysNorth ? 0 : -heading) : 0 } + */ gesture.flickDeceleration: 3000 gesture.enabled: true + + onWidthChanged: { + scaleTimer.restart() + } + + onHeightChanged: { + scaleTimer.restart() + } + + onZoomLevelChanged:{ + scaleTimer.restart() + } + + function calculateScale() { + var coord1, coord2, dist, text, f + f = 0 + coord1 = map.toCoordinate(Qt.point(0,scale.y)) + coord2 = map.toCoordinate(Qt.point(0+scaleImage.sourceSize.width,scale.y)) + dist = Math.round(coord1.distanceTo(coord2)) + if (dist === 0) { + // not visible + } else { + for (var i = 0; i < scaleLengths.length-1; i++) { + if (dist < (scaleLengths[i] + scaleLengths[i+1]) / 2 ) { + f = scaleLengths[i] / dist + dist = scaleLengths[i] + break; + } + } + if (f === 0) { + f = dist / scaleLengths[i] + dist = scaleLengths[i] + } + } + text = formatDistance(dist) + scaleImage.width = (scaleImage.sourceSize.width * f) - 2 * scaleImageLeft.sourceSize.width + scaleText.text = text + } } - onVisibleChanged: adjustSize(); - onWidthChanged: adjustSize(); - onHeightChanged: adjustSize(); - onAlwaysNorthChanged: adjustSize(); + QGCSlider { + id: zoomSlider; + minimum: map.minimumZoomLevel; + maximum: map.maximumZoomLevel; + opacity: 1 + visible: parent.visible + z: map.z + 3 + anchors { + bottom: parent.bottom; + bottomMargin: 15; rightMargin: 20; leftMargin: 20 + left: parent.left + } + width: parent.width - anchors.rightMargin - anchors.leftMargin + value: map.zoomLevel + Binding { + target: zoomSlider; property: "value"; value: map.zoomLevel + } + onValueChanged: { + map.zoomLevel = value + } + } + + Item { + id: scale + parent: zoomSlider.parent + visible: scaleText.text != "0 m" + z: map.z + 2 + opacity: 1 + anchors { + bottom: zoomSlider.top; + bottomMargin: 8; + left: zoomSlider.left + } + Image { + id: scaleImageLeft + source: "/qml/scale_end.png" + anchors.bottom: parent.bottom + anchors.left: parent.left + } + Image { + id: scaleImage + source: "/qml/scale.png" + anchors.bottom: parent.bottom + anchors.left: scaleImageLeft.right + } + Image { + id: scaleImageRight + source: "/qml/scale_end.png" + anchors.bottom: parent.bottom + anchors.left: scaleImage.right + } + Text { + id: scaleText + color: "white" + font.weight: Font.DemiBold + horizontalAlignment: Text.AlignHCenter + anchors.bottom: parent.bottom + anchors.left: parent.left + anchors.bottomMargin: 8 + text: "0 m" + } + Component.onCompleted: { + map.calculateScale(); + } + } + Timer { + id: scaleTimer + interval: 100 + running: false + repeat: false + onTriggered: { + map.calculateScale() + } + } + + onVisibleChanged: { + adjustSize(); + } + + onAlwaysNorthChanged: { + adjustSize(); + } + + onWidthChanged: { + adjustSize(); + } + + onHeightChanged: { + adjustSize(); + } } diff --git a/src/ui/flightdisplay/components/QGCSlider.qml b/src/ui/flightdisplay/components/QGCSlider.qml new file mode 100644 index 0000000..93fc898 --- /dev/null +++ b/src/ui/flightdisplay/components/QGCSlider.qml @@ -0,0 +1,124 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 + +Item { + id: slider; + height: 10 + property real value // value is read/write. + property real minimum: 0 + property real maximum: 1 + property int length: width - handle.width + + Rectangle { + anchors.fill: parent + border.width: 1; + border.color: "lightgrey" + radius: 8 + color: "white" + opacity: 1 + } + + Rectangle { + anchors.left: parent.left + anchors.leftMargin: 4 + anchors.top: parent.top + anchors.topMargin: (parent.height - height)/2 + height: 3 + width: handle.x - x + color: "#1c94fc" + } + + + Rectangle { + id: labelRect + width: label.width + height: label.height + 4 + radius: 4 + smooth: true + color: "white" + border.color: "lightgrey" + anchors.bottom: handle.top + anchors.bottomMargin: 4 + x: Math.max(Math.min(handle.x + (handle.width - width )/2, slider.width - width),0) + visible: mouseRegion.pressed + Text{ + id: label + color: "darkgrey" + text: slider.value.toFixed(2) + width: font.pointSize * 3.5 + anchors.horizontalCenter: labelRect.horizontalCenter + horizontalAlignment: Text.AlignHCenter + anchors.baseline: parent.bottom + anchors.baselineOffset: -6 + font.pixelSize: 14 + } + } + + Rectangle { + id: handle; + smooth: true + width: 26; + y: (slider.height - height)/2; + x: (slider.value - slider.minimum) * slider.length / (slider.maximum - slider.minimum) + + height: width; radius: width/2 + gradient: normalGradient + border.width: 2 + border.color: "white" + + Gradient { + id: normalGradient + GradientStop { position: 0.0; color: "#b0b0b0" } + GradientStop { position: 0.66; color: "#909090" } + GradientStop { position: 1.0; color: "#545454" } + } + + MouseArea { + id: mouseRegion + hoverEnabled: false + anchors.fill: parent; drag.target: parent + drag.axis: Drag.XAxis; drag.minimumX: 0; drag.maximumX: slider.length + preventStealing: true + onPositionChanged: { slider.value = (slider.maximum - slider.minimum) * handle.x / slider.length + slider.minimum; } + } + } +} diff --git a/src/ui/flightdisplay/components/qmldir b/src/ui/flightdisplay/components/qmldir index cda9932..647204b 100644 --- a/src/ui/flightdisplay/components/qmldir +++ b/src/ui/flightdisplay/components/qmldir @@ -8,3 +8,4 @@ QGCCurrentSpeed 1.0 QGCCurrentSpeed.qml QGCMapBackground 1.0 QGCMapBackground.qml QGCPitchWidget 1.0 QGCPitchWidget.qml QGCSpeedWidget 1.0 QGCSpeedWidget.qml +QGCSlider 1.0 QGCSlider.qml \ No newline at end of file diff --git a/src/ui/flightdisplay/components/scale.png b/src/ui/flightdisplay/components/scale.png new file mode 100644 index 0000000000000000000000000000000000000000..703d3a201d429a32b14fc5357b4c5d6167329b07 GIT binary patch literal 15451 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 GdFL