diff --git a/qgroundcontrol.qrc b/qgroundcontrol.qrc index 38d3168b786574fe67e0cd58ecd5fed8f8e130fd..ceaef775b7eeb740c5c167b81dae3f40735c7a38 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 7fad5e718b9ef978b0227bf1718ddfdd05a14bea..fda5efee978d30458b1df7b592849283fb3f07e6 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 ae5cd8565d7a4748eee7436743850b9e25aa6eae..bce55cc94d5d7bb4083142496c188ef4cced1873 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 3793782a62c1eb8044a31f6db53710fe4c22ff8b..b1dc01379375014a6a00e7f66bbd1e48a5a13f44 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 13231740c5c535c868801b0ec4f72355503804e4..20132ad30134590ffebf3491e1da4f4a76d9a8f7 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 0000000000000000000000000000000000000000..93fc8989b137fd191761daca6e4e81e83feb53cb --- /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 cda9932d45b6f7072fa1316f0ca45978c063803a..647204bec712a6259276d70d6ff521dbcda811c6 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 Binary files /dev/null and b/src/ui/flightdisplay/components/scale.png differ diff --git a/src/ui/flightdisplay/components/scale_end.png b/src/ui/flightdisplay/components/scale_end.png new file mode 100644 index 0000000000000000000000000000000000000000..1a7ed9af826c0cecf2c17f2b9a77b6decac6a1fe Binary files /dev/null and b/src/ui/flightdisplay/components/scale_end.png differ