diff --git a/qgroundcontrol.qrc b/qgroundcontrol.qrc index 4562dd999d3ab310a55ad9752991aa9c2c27dd3f..13ebdb73d24a7c8c67565a9aaa7d6080780fbbb9 100644 --- a/qgroundcontrol.qrc +++ b/qgroundcontrol.qrc @@ -100,7 +100,9 @@ src/ui/qmlcommon/qmldir src/ui/qmlcommon/QGCAltitudeWidget.qml src/ui/qmlcommon/QGCAttitudeWidget.qml + src/ui/qmlcommon/QGCAttitudeInstrument.qml src/ui/qmlcommon/QGCCompass.qml + src/ui/qmlcommon/QGCCompassInstrument.qml src/ui/qmlcommon/QGCCurrentAltitude.qml src/ui/qmlcommon/QGCCurrentSpeed.qml src/ui/qmlcommon/QGCMapBackground.qml @@ -109,19 +111,24 @@ src/ui/qmlcommon/QGCSlider.qml src/ui/qmlcommon/QGCWaypointEditor.qml src/ui/qmlcommon/QGCMapToolButton.qml + src/ui/qmlcommon/QGCArtificialHorizon.qml src/ui/qmlcommon/compass.svg src/ui/qmlcommon/compassNeedle.svg src/ui/qmlcommon/crossHair.svg - src/ui/qmlcommon/rollDial.svg src/ui/qmlcommon/rollDialWhite.svg - src/ui/qmlcommon/rollPointer.svg src/ui/qmlcommon/rollPointerWhite.svg src/ui/qmlcommon/scale.png src/ui/qmlcommon/scale_end.png src/ui/qmlcommon/buttonLeft.svg src/ui/qmlcommon/buttonRight.svg src/ui/qmlcommon/buttonHome.svg + src/ui/qmlcommon/buttonMore.svg + src/ui/qmlcommon/attitudeInstrument.svg + src/ui/qmlcommon/attitudeDial.svg + src/ui/qmlcommon/attitudePointer.svg + src/ui/qmlcommon/compassInstrumentAirplane.svg + src/ui/qmlcommon/compassInstrumentDial.svg diff --git a/src/QtLocationPlugin/OpenPilotMaps.h b/src/QtLocationPlugin/OpenPilotMaps.h index ba8e8d4ae12176e254bb892593d80351c9873f94..a8fc609ded8214c5c5fc3b0acda5bb61fab851bf 100644 --- a/src/QtLocationPlugin/OpenPilotMaps.h +++ b/src/QtLocationPlugin/OpenPilotMaps.h @@ -38,6 +38,8 @@ This file is part of the QGROUNDCONTROL project #include #include +#define MAX_MAP_ZOOM (20.0) + namespace OpenPilot { enum MapType diff --git a/src/QtLocationPlugin/qgeomapreplyqgc.cpp b/src/QtLocationPlugin/qgeomapreplyqgc.cpp index fda5efee978d30458b1df7b592849283fb3f07e6..0801de86a172a7cfc59e392d003b54517d2e73e4 100644 --- a/src/QtLocationPlugin/qgeomapreplyqgc.cpp +++ b/src/QtLocationPlugin/qgeomapreplyqgc.cpp @@ -53,9 +53,17 @@ QGeoMapReplyQGC::QGeoMapReplyQGC(QNetworkReply *reply, const QGeoTileSpec &spec, : QGeoTiledMapReply(spec, parent) , m_reply(reply) { - connect(m_reply, SIGNAL(finished()), this, SLOT(networkReplyFinished())); - connect(m_reply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(networkReplyError(QNetworkReply::NetworkError))); - connect(m_reply, SIGNAL(destroyed()), this, SLOT(replyDestroyed())); + if(!reply) + { + setError(QGeoTiledMapReply::UnknownError, "Invalid tile request"); + setFinished(true); + } + else + { + connect(m_reply, SIGNAL(finished()), this, SLOT(networkReplyFinished())); + connect(m_reply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(networkReplyError(QNetworkReply::NetworkError))); + connect(m_reply, SIGNAL(destroyed()), this, SLOT(replyDestroyed())); + } } QGeoMapReplyQGC::~QGeoMapReplyQGC() diff --git a/src/QtLocationPlugin/qgeotiledmappingmanagerengineqgc.cpp b/src/QtLocationPlugin/qgeotiledmappingmanagerengineqgc.cpp index bce55cc94d5d7bb4083142496c188ef4cced1873..51b613d70125105c896aa34a836f72261d6d432f 100644 --- a/src/QtLocationPlugin/qgeotiledmappingmanagerengineqgc.cpp +++ b/src/QtLocationPlugin/qgeotiledmappingmanagerengineqgc.cpp @@ -59,7 +59,7 @@ QGeoTiledMappingManagerEngineQGC::QGeoTiledMappingManagerEngineQGC(const QVarian { QGeoCameraCapabilities cameraCaps; cameraCaps.setMinimumZoomLevel(2.0); - cameraCaps.setMaximumZoomLevel(20.0); + cameraCaps.setMaximumZoomLevel(MAX_MAP_ZOOM); cameraCaps.setSupportsBearing(true); setCameraCapabilities(cameraCaps); diff --git a/src/ui/flightdisplay/FlightDisplay.qml b/src/ui/flightdisplay/FlightDisplay.qml index 4bbc1be1bb99e1202b36972df191ea7f2f3c1a67..98c395f5ad5c04352afa7b16477a56738a930ebd 100644 --- a/src/ui/flightdisplay/FlightDisplay.qml +++ b/src/ui/flightdisplay/FlightDisplay.qml @@ -40,6 +40,10 @@ Rectangle { property real roll: isNaN(flightDisplay.roll) ? 0 : flightDisplay.roll property real pitch: isNaN(flightDisplay.pitch) ? 0 : flightDisplay.pitch + property bool showPitchIndicator: true + property bool showAttitudeIndicator: true + property bool showCompass: true + function getBool(value) { return value === '0' ? false : true; } @@ -48,61 +52,116 @@ Rectangle { return value ? "1" : "0"; } + function adjustSizes() { + var dist = 85 + var wide = 160 + var minw = 496 + if(root.width > minw) + { + attitudeInstrument.size = wide; + attitudeInstrument.x = dist + compassInstrument.size = wide; + compassInstrument.x = root.width - wide - dist + } else { + var factor = (root.width / minw); + var ndist = dist * factor; + var nwide = wide * factor; + if (ndist < 0) + ndist = 0; + attitudeInstrument.size = nwide; + compassInstrument.size = nwide; + attitudeInstrument.x = ndist; + compassInstrument.x = root.width - nwide - ndist; + } + } + Component.onCompleted: { mapBackground.visible = getBool(flightDisplay.loadSetting("showMapBackground", "0")); mapBackground.alwaysNorth = getBool(flightDisplay.loadSetting("mapAlwaysPointsNorth", "0")); - attitudeWidget.visible = getBool(flightDisplay.loadSetting("showAttitudeWidget", "1")); - attitudeWidget.displayBackground = getBool(flightDisplay.loadSetting("showAttitudeBackground", "1")); - pitchWidget.visible = getBool(flightDisplay.loadSetting("showPitchWidget", "1")); + showAttitudeIndicator = getBool(flightDisplay.loadSetting("showAttitudeIndicator", "1")); + showPitchIndicator = getBool(flightDisplay.loadSetting("showPitchWidget", "1")); + showCompass = getBool(flightDisplay.loadSetting("showCompass", "1")); altitudeWidget.visible = getBool(flightDisplay.loadSetting("showAltitudeWidget", "1")); speedWidget.visible = getBool(flightDisplay.loadSetting("showSpeedWidget", "1")); - compassIndicator.visible = getBool(flightDisplay.loadSetting("showCompassIndicator", "1")); currentSpeed.showAirSpeed = getBool(flightDisplay.loadSetting("showCurrentAirSpeed", "1")); currentSpeed.showGroundSpeed = getBool(flightDisplay.loadSetting("showCurrentGroundSpeed", "1")); currentAltitude.showClimbRate = getBool(flightDisplay.loadSetting("showCurrentClimbRate", "1")); currentAltitude.showAltitude = getBool(flightDisplay.loadSetting("showCurrentAltitude", "1")); mapTypeMenu.update(); - } - - Rectangle { - id: windowBackground - anchors.fill: parent - anchors.centerIn: parent - visible: !attitudeWidget.visible && !mapBackground.visible - color: Qt.hsla(0.25, 0.5, 0.45) - z: 0 + adjustSizes(); } Menu { id: contextMenu MenuItem { - text: "Main Attitude Indicators" + text: "Map Background" checkable: true - checked: attitudeWidget.visible + checked: mapBackground.visible onTriggered: { - attitudeWidget.visible = !attitudeWidget.visible; - flightDisplay.saveSetting("showAttitudeWidget", setBool(attitudeWidget.visible)); + mapBackground.visible = !mapBackground.visible; + flightDisplay.saveSetting("showMapBackground", setBool(mapBackground.visible)); } } + /* MenuItem { - text: "Display Attitude Background" + text: "Map Always Points North" checkable: true - checked: attitudeWidget.displayBackground + checked: mapBackground.alwaysNorth onTriggered: { - attitudeWidget.displayBackground = !attitudeWidget.displayBackground; - flightDisplay.saveSetting("showAttitudeBackground", setBool(attitudeWidget.displayBackground)); + mapBackground.alwaysNorth = !mapBackground.alwaysNorth; + flightDisplay.saveSetting("mapAlwaysPointsNorth", setBool(mapBackground.alwaysNorth)); } } + */ + + Menu { + id: mapTypeMenu + title: "Map Type..." + ExclusiveGroup { id: currentMapType } + function setCurrentMap(map) { + for (var i = 0; i < mapBackground.mapItem.supportedMapTypes.length; i++) { + if (map === mapBackground.mapItem.supportedMapTypes[i].name) { + mapBackground.mapItem.activeMapType = mapBackground.mapItem.supportedMapTypes[i] + flightDisplay.saveSetting("currentMapType", map); + return; + } + } + } + function addMap(map, checked) { + var mItem = mapTypeMenu.addItem(map); + mItem.checkable = true + mItem.checked = checked + mItem.exclusiveGroup = currentMapType + var menuSlot = function() {setCurrentMap(map);}; + mItem.triggered.connect(menuSlot); + } + function update() { + clear() + var map = '' + if (mapBackground.mapItem.supportedMapTypes.length > 0) + map = mapBackground.mapItem.activeMapType.name; + map = flightDisplay.loadSetting("currentMapType", map); + for (var i = 0; i < mapBackground.mapItem.supportedMapTypes.length; i++) { + var name = mapBackground.mapItem.supportedMapTypes[i].name; + addMap(name, map === name); + } + if(map != '') + setCurrentMap(map); + } + } + + MenuSeparator {} MenuItem { text: "Pitch Indicator" - checkable: true - checked: pitchWidget.visible + checkable: true + checked: showPitchIndicator + enabled: !mapBackground.visible onTriggered: { pitchWidget.visible = !pitchWidget.visible; @@ -179,73 +238,22 @@ Rectangle { MenuItem { text: "Compass" checkable: true - checked: compassIndicator.visible - onTriggered: - { - compassIndicator.visible = !compassIndicator.visible; - flightDisplay.saveSetting("showCompassIndicator", setBool(compassIndicator.visible)); - } - } - - MenuSeparator {} - - MenuItem { - text: "Map Background" - checkable: true - checked: mapBackground.visible + checked: showCompass onTriggered: { - mapBackground.visible = !mapBackground.visible; - flightDisplay.saveSetting("showMapBackground", setBool(mapBackground.visible)); + showCompass = !showCompass; + flightDisplay.saveSetting("showCompass", setBool(showCompass)); } } - /* MenuItem { - text: "Map Always Points North" + text: "Attitude Indicator" checkable: true - checked: mapBackground.alwaysNorth + checked: showAttitudeIndicator onTriggered: { - mapBackground.alwaysNorth = !mapBackground.alwaysNorth; - flightDisplay.saveSetting("mapAlwaysPointsNorth", setBool(mapBackground.alwaysNorth)); - } - } - */ - - Menu { - id: mapTypeMenu - title: "Map Type..." - ExclusiveGroup { id: currentMapType } - function setCurrentMap(map) { - for (var i = 0; i < mapBackground.mapItem.supportedMapTypes.length; i++) { - if (map === mapBackground.mapItem.supportedMapTypes[i].name) { - mapBackground.mapItem.activeMapType = mapBackground.mapItem.supportedMapTypes[i] - flightDisplay.saveSetting("currentMapType", map); - return; - } - } - } - function addMap(map, checked) { - var mItem = mapTypeMenu.addItem(map); - mItem.checkable = true - mItem.checked = checked - mItem.exclusiveGroup = currentMapType - var menuSlot = function() {setCurrentMap(map);}; - mItem.triggered.connect(menuSlot); - } - function update() { - clear() - var map = '' - if (mapBackground.mapItem.supportedMapTypes.length > 0) - map = mapBackground.mapItem.activeMapType.name; - map = flightDisplay.loadSetting("currentMapType", map); - for (var i = 0; i < mapBackground.mapItem.supportedMapTypes.length; i++) { - var name = mapBackground.mapItem.supportedMapTypes[i].name; - addMap(name, map === name); - } - if(map != '') - setCurrentMap(map); + showAttitudeIndicator = !showAttitudeIndicator; + flightDisplay.saveSetting("showAttitudeIndicator", setBool(showAttitudeIndicator)); } } @@ -255,12 +263,12 @@ Rectangle { text: "Restore Defaults" onTriggered: { - attitudeWidget.visible = true; - flightDisplay.saveSetting("showAttitudeWidget", setBool(attitudeWidget.visible)); - attitudeWidget.displayBackground = true; - flightDisplay.saveSetting("showAttitudeBackground", setBool(attitudeWidget.displayBackground)); - pitchWidget.visible = true; - flightDisplay.saveSetting("showPitchWidget", setBool(pitchWidget.visible)); + showPitchIndicator = true; + flightDisplay.saveSetting("showPitchWidget", setBool(showPitchIndicator)); + showAttitudeIndicator = true; + flightDisplay.saveSetting("showAttitudeIndicator", setBool(showAttitudeIndicator)); + showCompass = true; + flightDisplay.saveSetting("showCompass", setBool(showCompass)); altitudeWidget.visible = true; flightDisplay.saveSetting("showAltitudeWidget", setBool(altitudeWidget.visible)); currentAltitude.showAltitude = true; @@ -273,8 +281,6 @@ Rectangle { flightDisplay.saveSetting("showCurrentAirSpeed", setBool(currentSpeed.showAirSpeed)); currentSpeed.showGroundSpeed = true; flightDisplay.saveSetting("showCurrentGroundSpeed", setBool(currentSpeed.showGroundSpeed)); - compassIndicator.visible = true; - flightDisplay.saveSetting("showCompassIndicator", setBool(compassIndicator.visible)); mapBackground.visible = false; flightDisplay.saveSetting("showMapBackground", setBool(mapBackground.visible)); mapBackground.alwaysNorth = false; @@ -285,13 +291,13 @@ Rectangle { } QGCMapBackground { - id: mapBackground - anchors.fill: parent - visible: false - heading: isNaN(flightDisplay.heading) ? 0 : flightDisplay.heading - latitude: flightDisplay.latitude - longitude: flightDisplay.longitude - z: 5 + id: mapBackground + anchors.fill: parent + heading: 0 // isNaN(flightDisplay.heading) ? 0 : flightDisplay.heading + latitude: mapBackground.visible ? ((flightDisplay.latitude === 0) ? 37.803784 : flightDisplay.latitude) : 37.803784 + longitude: mapBackground.visible ? ((flightDisplay.longitude === 0) ? -122.462276 : flightDisplay.longitude) : -122.462276 + interactive: !flightDisplay.mavPresent + z: 10 } QGCAttitudeWidget { @@ -299,44 +305,35 @@ Rectangle { anchors.centerIn: parent rollAngle: roll pitchAngle: pitch - useWhite: !mapBackground.visible - backgroundOpacity: mapBackground.visible ? 0.25 : 1.0 + visible: !mapBackground.visible && showAttitudeIndicator z: 10 } QGCPitchWidget { - id: pitchWidget + id: pitchWidget + visible: showPitchIndicator && !mapBackground.visible anchors.verticalCenter: parent.verticalCenter - pitchAngle: pitch - rollAngle: roll - color: mapBackground.visible ? Qt.rgba(0,0,0,0.5) : Qt.rgba(0,0,0,0) - opacity: mapBackground.visible ? 1 : 0.75 - z: mapBackground.visible ? 20 : 25 - } - - Image { - anchors.centerIn: parent - source: "/qml/crossHair.svg" - mipmap: true - width: 260 - fillMode: Image.PreserveAspectFit - z: mapBackground.visible ? 25 : 20 + pitchAngle: pitch + rollAngle: roll + color: Qt.rgba(0,0,0,0) + size: 120 + z: 30 } QGCAltitudeWidget { - id: altitudeWidget - anchors.right: parent.right - width: 60 - altitude: flightDisplay.altitudeWGS84 - z: 30 + id: altitudeWidget + anchors.right: parent.right + width: 60 + altitude: flightDisplay.altitudeWGS84 + z: 30 } QGCSpeedWidget { - id: speedWidget - anchors.left: parent.left - width: 60 - speed: flightDisplay.groundSpeed - z: 40 + id: speedWidget + anchors.left: parent.left + width: 60 + speed: flightDisplay.groundSpeed + z: 40 } QGCCurrentSpeed { @@ -364,22 +361,68 @@ Rectangle { } QGCCompass { - id: compassIndicator - y: root.height * 0.7 - anchors.horizontalCenter: parent.horizontalCenter - heading: isNaN(flightDisplay.heading) ? 0 : flightDisplay.heading - z: 70 + id: compassIndicator + y: root.height * 0.7 + x: root.width * 0.5 - 60 + width: 120 + height: 120 + heading: isNaN(flightDisplay.heading) ? 0 : flightDisplay.heading + visible: !mapBackground.visible && showCompass + z: 70 } - MouseArea { - anchors.fill: parent - acceptedButtons: Qt.RightButton - onClicked: { - if (mouse.button == Qt.RightButton) - { - contextMenu.popup() + QGCCompassInstrument { + id: compassInstrument + y: 5 + x: 85 + size: 160 + heading: isNaN(flightDisplay.heading) ? 0 : flightDisplay.heading + visible: mapBackground.visible && showCompass + z: 70 + } + + QGCAttitudeInstrument { + id: attitudeInstrument + y: 5 + x: root.width - 160 - 85 + size: 160 + rollAngle: roll + pitchAngle: pitch + visible: mapBackground.visible && showAttitudeIndicator + z: 80 + } + + // Button at upper left corner + Item { + id: optionsButton + x: 5 + y: 5 + width: 30 + height: 30 + opacity: 0.85 + z: 1000 + Image { + id: buttomImg + anchors.fill: parent + source: "/qml/buttonMore.svg" + mipmap: true + smooth: true + antialiasing: true + fillMode: Image.PreserveAspectFit + } + MouseArea { + anchors.fill: parent + acceptedButtons: Qt.LeftButton + onClicked: { + if (mouse.button == Qt.LeftButton) + { + contextMenu.popup() + } } } - z: 100 + } + + onWidthChanged: { + adjustSizes(); } } diff --git a/src/ui/flightdisplay/QGCFlightDisplay.cc b/src/ui/flightdisplay/QGCFlightDisplay.cc index 89faeaa6aa416bab374961f11308d47bbced2355..2e3df90964f451c07fb28e32d7d7b822a8d08425 100644 --- a/src/ui/flightdisplay/QGCFlightDisplay.cc +++ b/src/ui/flightdisplay/QGCFlightDisplay.cc @@ -67,8 +67,8 @@ QGCFlightDisplay::QGCFlightDisplay(QWidget *parent) if(pl) { pl->setContentsMargins(0,0,0,0); } - setMinimumWidth(270); - setMinimumHeight(300); + setMinimumWidth(380); + setMinimumHeight(360); setContextPropertyObject("flightDisplay", this); setSource(QUrl::fromUserInput("qrc:/qml/FlightDisplay.qml")); setVisible(true); @@ -114,6 +114,7 @@ void QGCFlightDisplay::_forgetUAS(UASInterface* uas) disconnect(_mav, &UASInterface::NavigationControllerDataChanged, this, &QGCFlightDisplay::_updateNavigationControllerData); } _mav = NULL; + emit mavPresentChanged(); } void QGCFlightDisplay::_setActiveUAS(UASInterface* uas) @@ -136,6 +137,7 @@ void QGCFlightDisplay::_setActiveUAS(UASInterface* uas) // Set new UAS _mav = uas; } + emit mavPresentChanged(); } void QGCFlightDisplay::_updateAttitude(UASInterface*, double roll, double pitch, double yaw, quint64) diff --git a/src/ui/flightdisplay/QGCFlightDisplay.h b/src/ui/flightdisplay/QGCFlightDisplay.h index f39b2a7dec7ed57bf851466c79ebe60b92277ee4..7b3d3c66d3bf6b3d0515918417a51a448119dbdb 100644 --- a/src/ui/flightdisplay/QGCFlightDisplay.h +++ b/src/ui/flightdisplay/QGCFlightDisplay.h @@ -53,6 +53,7 @@ public: Q_PROPERTY(bool repaintRequested READ repaintRequested NOTIFY repaintRequestedChanged) Q_PROPERTY(float latitude READ latitude NOTIFY latitudeChanged) Q_PROPERTY(float longitude READ longitude NOTIFY longitudeChanged) + Q_PROPERTY(bool mavPresent READ mavPresent NOTIFY mavPresentChanged) Q_INVOKABLE void saveSetting (const QString &key, const QString& value); Q_INVOKABLE QString loadSetting (const QString &key, const QString& defaultValue); @@ -69,6 +70,7 @@ public: float latitude () { return _latitude; } float longitude () { return _longitude; } bool repaintRequested () { return true; } + bool mavPresent () { return _mav != NULL; } /** @brief Start updating widget */ void showEvent(QShowEvent* event); @@ -88,6 +90,7 @@ signals: void repaintRequestedChanged(); void latitudeChanged (); void longitudeChanged (); + void mavPresentChanged (); private slots: /** @brief Attitude from main autopilot / system state */ diff --git a/src/ui/mapdisplay/MapDisplay.qml b/src/ui/mapdisplay/MapDisplay.qml index 2dae4400f4e606ed585e9f53b8abe14dfa3d5b75..bbf608ea7056e7f104c7641a5f54c156c161ca7a 100644 --- a/src/ui/mapdisplay/MapDisplay.qml +++ b/src/ui/mapdisplay/MapDisplay.qml @@ -33,6 +33,7 @@ import QtQuick.Controls.Styles 1.2 import QtQuick.Layouts 1.1 import QGroundControl.Palette 1.0 +import QGroundControl.Controls 1.0 import QGroundControl.FlightControls 1.0 Rectangle { diff --git a/src/ui/qmlcommon/QGCAltitudeWidget.qml b/src/ui/qmlcommon/QGCAltitudeWidget.qml index d1021cbcd12968a2075655c8b5e797f9d0ba5b04..60ecd7cd764727aada219ff1beb28be796c6cba7 100644 --- a/src/ui/qmlcommon/QGCAltitudeWidget.qml +++ b/src/ui/qmlcommon/QGCAltitudeWidget.qml @@ -63,9 +63,7 @@ Rectangle { } anchors.verticalCenter: parent.verticalCenter - - height: parent.height * 0.75 > 280 ? 280 : parent.height * 0.75 - clip: true + height: parent.height * 0.65 > 280 ? 280 : parent.height * 0.65 smooth: true radius: 5 border.color: Qt.rgba(1,1,1,0.25) @@ -74,34 +72,42 @@ Rectangle { GradientStop { position: 0.5; color: Qt.rgba(0,0,0,0.25) } GradientStop { position: 1.0; color: Qt.rgba(0,0,0,0.65) } } - Column{ - id: col - width: parent.width + Rectangle { + id: clipRect + height: parent.height - 5 + width: parent.width + clip: true + color: Qt.rgba(0,0,0,0); anchors.verticalCenter: parent.verticalCenter - spacing: _reticleSpacing - Repeater { - model: _speedArray - anchors.left: parent.left - Rectangle { - property int _alt: modelData - width: (_alt % 10 === 0) ? 10 : 15 - height: _reticleHeight - color: Qt.rgba(1,1,1,0.35) - Text { - visible: (_alt % 10 === 0) - x: 20 - anchors.verticalCenter: parent.verticalCenter - antialiasing: true - font.weight: Font.DemiBold - text: _alt - color: _alt < 0 ? "#f8983a" : "white" - style: Text.Outline - styleColor: Qt.rgba(0,0,0,0.25) + Column{ + id: col + width: parent.width + anchors.verticalCenter: parent.verticalCenter + spacing: _reticleSpacing + Repeater { + model: _speedArray + anchors.left: parent.left + Rectangle { + property int _alt: modelData + width: (_alt % 10 === 0) ? 10 : 15 + height: _reticleHeight + color: Qt.rgba(1,1,1,0.35) + Text { + visible: (_alt % 10 === 0) + x: 20 + anchors.verticalCenter: parent.verticalCenter + antialiasing: true + font.weight: Font.DemiBold + text: _alt + color: _alt < 0 ? "#f8983a" : "white" + style: Text.Outline + styleColor: Qt.rgba(0,0,0,0.25) + } } } - } - transform: Translate { - y: ((altitude - _currentCenter) * _reticleSlot / 5) - (_reticleSlot / 2) + transform: Translate { + y: ((altitude - _currentCenter) * _reticleSlot / 5) - (_reticleSlot / 2) + } } } } diff --git a/src/ui/qmlcommon/QGCArtificialHorizon.qml b/src/ui/qmlcommon/QGCArtificialHorizon.qml new file mode 100644 index 0000000000000000000000000000000000000000..921254348f75cd4ae9a00608382a7399d235a19f --- /dev/null +++ b/src/ui/qmlcommon/QGCArtificialHorizon.qml @@ -0,0 +1,78 @@ +/*===================================================================== + +QGroundControl Open Source Ground Control Station + +(c) 2009, 2015 QGROUNDCONTROL PROJECT + +This file is part of the QGROUNDCONTROL project + + QGROUNDCONTROL is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + QGROUNDCONTROL is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with QGROUNDCONTROL. If not, see . + +======================================================================*/ + +/** + * @file + * @brief QGC Artificial Horizon + * @author Gus Grubba + */ + +import QtQuick 2.4 + +Item { + id: root + property real rollAngle : 0 + property real pitchAngle: 0 + clip: true + anchors.fill: parent + Item { + id: artificialHorizon + width: root.width * 4 + height: root.height * 4 + anchors.centerIn: parent + Rectangle { + id: sky + anchors.fill: parent + smooth: true + antialiasing: true + gradient: Gradient { + GradientStop { position: 0.25; color: Qt.hsla(0.6, 1.0, 0.25) } + GradientStop { position: 0.5; color: Qt.hsla(0.6, 0.5, 0.55) } + } + } + Rectangle { + id: ground + height: sky.height / 2 + anchors { + left: sky.left; + right: sky.right; + bottom: sky.bottom + } + smooth: true + antialiasing: true + gradient: Gradient { + GradientStop { position: 0.0; color: Qt.hsla(0.25, 0.5, 0.45) } + GradientStop { position: 0.25; color: Qt.hsla(0.25, 0.75, 0.25) } + } + } + transform: [ + Translate { + y: root.visible ? pitchAngle * 4 : 0 + }, + Rotation { + origin.x: artificialHorizon.width / 2 + origin.y: artificialHorizon.height / 2 + angle: root.visible ? -rollAngle : 0 + }] + } +} diff --git a/src/ui/qmlcommon/QGCAttitudeInstrument.qml b/src/ui/qmlcommon/QGCAttitudeInstrument.qml new file mode 100644 index 0000000000000000000000000000000000000000..034a6810b8b113db7c2516aa0e258224803da1db --- /dev/null +++ b/src/ui/qmlcommon/QGCAttitudeInstrument.qml @@ -0,0 +1,104 @@ +/*===================================================================== + +QGroundControl Open Source Ground Control Station + +(c) 2009, 2015 QGROUNDCONTROL PROJECT + +This file is part of the QGROUNDCONTROL project + + QGROUNDCONTROL is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + QGROUNDCONTROL is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with QGROUNDCONTROL. If not, see . + +======================================================================*/ + +/** + * @file + * @brief QGC Attitude Instrument + * @author Gus Grubba + */ + +import QtQuick 2.4 + +Item { + id: root + property real rollAngle : 0 + property real pitchAngle: 0 + property real size: 100 + + width: size + height: size + + //---------------------------------------------------- + //-- Artificial Horizon + QGCArtificialHorizon { + rollAngle: root.rollAngle + pitchAngle: root.pitchAngle + } + //---------------------------------------------------- + //-- Pointer + Image { + id: pointer + source: "/qml/attitudePointer.svg" + width: root.width + mipmap: true + fillMode: Image.PreserveAspectFit + anchors.bottom: parent.bottom + anchors.horizontalCenter: parent.horizontalCenter + } + //---------------------------------------------------- + //-- Instrument Dial + Image { + id: instrumentDial + source: "/qml/attitudeDial.svg" + mipmap: true + width: root.width + fillMode: Image.PreserveAspectFit + anchors.bottom: parent.bottom + anchors.horizontalCenter: parent.horizontalCenter + transform: Rotation { + origin.x: root.width / 2 + origin.y: root.height / 2 + angle: -rollAngle + } + } + //---------------------------------------------------- + //-- Pitch + QGCPitchWidget { + id: pitchWidget + size: parent.width * 0.65 + anchors.verticalCenter: parent.verticalCenter + pitchAngle: root.pitchAngle + rollAngle: root.rollAngle + color: Qt.rgba(0,0,0,0) + } + //---------------------------------------------------- + //-- Cross Hair + Image { + id: crossHair + anchors.centerIn: parent + source: "/qml/crossHair.svg" + mipmap: true + width: parent.width * 0.75 + fillMode: Image.PreserveAspectFit + } + //---------------------------------------------------- + //-- Instrument Pannel + Image { + id: pannel + width: parent.width + source: "/qml/attitudeInstrument.svg" + mipmap: true + fillMode: Image.PreserveAspectFit + anchors.centerIn: parent + } +} diff --git a/src/ui/qmlcommon/QGCAttitudeWidget.qml b/src/ui/qmlcommon/QGCAttitudeWidget.qml index 02a563ce411d70e2ffdf9cfb9c2871f577147911..7702b8defa66caa5091208806cafe83aec0c4131 100644 --- a/src/ui/qmlcommon/QGCAttitudeWidget.qml +++ b/src/ui/qmlcommon/QGCAttitudeWidget.qml @@ -23,7 +23,7 @@ This file is part of the QGROUNDCONTROL project /** * @file - * @brief QGC Main Flight Display + * @brief QGC Attitude Widget * @author Gus Grubba */ @@ -33,86 +33,43 @@ Item { id: root property real rollAngle : 0 property real pitchAngle: 0 - property real backgroundOpacity: 1 - property bool displayBackground: true - property bool useWhite: true anchors.fill: parent - Item { - id: background - width: parent.width * 4 - height: parent.height * 4 - anchors.centerIn: parent - - Rectangle { - anchors.fill: parent - color: Qt.rgba(0,0,0,0) - visible: displayBackground - - Rectangle { - id: sky - visible: displayBackground - anchors.fill: parent - smooth: true - antialiasing: true - gradient: Gradient { - GradientStop { position: 0.25; color: Qt.hsla(0.6, 1.0, 0.25, backgroundOpacity) } - GradientStop { position: 0.5; color: Qt.hsla(0.6, 0.5, 0.75, backgroundOpacity) } - } - } - - Rectangle { - id: ground - visible: displayBackground - height: sky.height / 2 - anchors { - left: sky.left; - right: sky.right; - bottom: sky.bottom - } - smooth: true - antialiasing: true - gradient: Gradient { - GradientStop { position: 0.0; color: Qt.hsla(0.25, 0.5, 0.45, backgroundOpacity) } - GradientStop { position: 0.25; color: Qt.hsla(0.25, 0.75, 0.25, backgroundOpacity) } - } - } - - transform: [ - Translate { - y: (root.visible && root.displayBackground) ? pitchAngle * 4 : 0 - }, - Rotation { - origin.x: background.width / 2 - origin.y: background.height / 2 - angle: (root.visible && root.displayBackground) ? -rollAngle : 0 - }] - } - + QGCArtificialHorizon { + rollAngle: root.rollAngle + pitchAngle: root.pitchAngle } Image { id: rollDial anchors { bottom: root.verticalCenter; horizontalCenter: parent.horizontalCenter} - source: useWhite ? "/qml/rollDialWhite.svg" : "/qml/rollDial.svg" + source: "/qml/rollDialWhite.svg" mipmap: true width: 260 fillMode: Image.PreserveAspectFit transform: Rotation { origin.x: rollDial.width / 2 origin.y: rollDial.height - angle: -rollAngle + angle: -rollAngle } } Image { id: pointer anchors { bottom: root.verticalCenter; horizontalCenter: parent.horizontalCenter} - source: useWhite ? "/qml/rollPointerWhite.svg" : "/qml/rollPointer.svg" - smooth: true - width: rollDial.width - fillMode: Image.PreserveAspectFit + source: "/qml/rollPointerWhite.svg" + mipmap: true + width: rollDial.width + fillMode: Image.PreserveAspectFit } + Image { + id: crossHair + anchors.centerIn: parent + source: "/qml/crossHair.svg" + mipmap: true + width: 260 + fillMode: Image.PreserveAspectFit + } } diff --git a/src/ui/qmlcommon/QGCCompass.qml b/src/ui/qmlcommon/QGCCompass.qml index 08195a0019f7439d4e13263fb253a269a433d31f..2db3fd7dad61819c731cc645be6226cbf3272e97 100644 --- a/src/ui/qmlcommon/QGCCompass.qml +++ b/src/ui/qmlcommon/QGCCompass.qml @@ -31,8 +31,6 @@ import QtQuick 2.4 Item { id: root - width: 120 - height: width property real heading : 0 Image { id: compass diff --git a/src/ui/qmlcommon/QGCCompassInstrument.qml b/src/ui/qmlcommon/QGCCompassInstrument.qml new file mode 100644 index 0000000000000000000000000000000000000000..d51d92aef31ef4403307b608909ac51a2efbf073 --- /dev/null +++ b/src/ui/qmlcommon/QGCCompassInstrument.qml @@ -0,0 +1,83 @@ +/*===================================================================== + +QGroundControl Open Source Ground Control Station + +(c) 2009, 2015 QGROUNDCONTROL PROJECT + +This file is part of the QGROUNDCONTROL project + + QGROUNDCONTROL is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + QGROUNDCONTROL is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with QGROUNDCONTROL. If not, see . + +======================================================================*/ + +/** + * @file + * @brief QGC Compass + * @author Gus Grubba + */ + +import QtQuick 2.4 +import QGroundControl.ScreenTools 1.0 + +Item { + property ScreenTools screenTools: ScreenTools { } + id: root + property real heading: 0 + property real size: 120 + property real _fontSize: screenTools.dpiAdjustedPointSize(size * 12 / 120) + width: size + height: size + Rectangle { + id: compassBack + anchors.fill: parent + color: "#212121" + } + Image { + id: pointer + source: "/qml/compassInstrumentAirplane.svg" + mipmap: true + width: root.width * 0.75 + fillMode: Image.PreserveAspectFit + anchors.centerIn: parent + transform: Rotation { + origin.x: pointer.width / 2 + origin.y: pointer.height / 2 + angle: -heading + } + } + Image { + id: compassDial + source: "/qml/compassInstrumentDial.svg" + mipmap: true + width: root.width + fillMode: Image.PreserveAspectFit + anchors.centerIn: parent + } + Rectangle { + anchors.centerIn: root + width: size * 0.35 + height: size * 0.2 + border.color: Qt.rgba(1,1,1,0.15) + color: Qt.rgba(0,0,0,0.65) + Text { + text: heading.toFixed(0) + font.weight: Font.DemiBold + font.pointSize: _fontSize < 1 ? 1 : _fontSize; + color: "white" + anchors.centerIn: parent + } + } +} + + diff --git a/src/ui/qmlcommon/QGCMapBackground.qml b/src/ui/qmlcommon/QGCMapBackground.qml index c4c9c0d3b31c7ca6d86db9d101f83a6372221715..7f4d0ff240f111a8937741f943a0c84dec2761fa 100644 --- a/src/ui/qmlcommon/QGCMapBackground.qml +++ b/src/ui/qmlcommon/QGCMapBackground.qml @@ -37,9 +37,10 @@ Rectangle { id: root property real latitude: 37.803784 property real longitude : -122.462276 - property real zoomLevel: 15 + property real zoomLevel: 18 property real heading: 0 property bool alwaysNorth: true + property bool interactive: true property alias mapItem: map color: Qt.rgba(0,0,0,0) @@ -95,8 +96,11 @@ Rectangle { height: 1 zoomLevel: root.zoomLevel anchors.centerIn: parent - center: map.visible ? QtPositioning.coordinate(lat, lon) : QtPositioning.coordinate(0,0) + center: QtPositioning.coordinate(lat, lon) /* + // There is a bug currently in Qt where it fails to render a map taller than 6 tiles high. Until + // that's fixed, we can't rotate the map as it would require a larger map, which can easely grow + // larger than 6 tiles high. transform: Rotation { origin.x: map.width / 2 origin.y: map.height / 2 @@ -104,7 +108,7 @@ Rectangle { } */ gesture.flickDeceleration: 3000 - gesture.enabled: true + gesture.enabled: root.interactive onWidthChanged: { scaleTimer.restart() @@ -118,6 +122,10 @@ Rectangle { scaleTimer.restart() } + Component.onCompleted: { + map.zoomLevel = 18 + } + function calculateScale() { var coord1, coord2, dist, text, f f = 0 diff --git a/src/ui/qmlcommon/QGCPitchWidget.qml b/src/ui/qmlcommon/QGCPitchWidget.qml index bc3fe51bd2d30f888e79aa73185978dce69abbc6..d0ab4e619e8c5109b59b977314e0afc5dc5159a0 100644 --- a/src/ui/qmlcommon/QGCPitchWidget.qml +++ b/src/ui/qmlcommon/QGCPitchWidget.qml @@ -28,15 +28,21 @@ This file is part of the QGROUNDCONTROL project */ import QtQuick 2.1 +import QGroundControl.ScreenTools 1.0 Rectangle { - property real pitchAngle: 0 - property real rollAngle: 0 - property real _reticleHeight: 1 - property real _reticleSpacing: 17 - property real _reticleSlot: _reticleSpacing + _reticleHeight - height: 110 - width: 120 + property ScreenTools screenTools: ScreenTools { } + property real pitchAngle: 0 + property real rollAngle: 0 + property real size: 120 + property real _reticleHeight: 1 + property real _reticleSpacing: size * 0.15 + property real _reticleSlot: _reticleSpacing + _reticleHeight + property real _longDash: size * 0.40 + property real _shortDash: size * 0.25 + property real _fontSize: screenTools.dpiAdjustedPointSize(size * 11 / 120); + height: size * 0.9 + width: size radius: 8 anchors.horizontalCenter: parent.horizontalCenter anchors.verticalCenter: parent.verticalCenter @@ -53,27 +59,29 @@ Rectangle { Rectangle { property int _pitch: -(modelData * 5 - 90) anchors.horizontalCenter: parent.horizontalCenter - width: (_pitch % 10) === 0 ? 50 : 30 + width: (_pitch % 10) === 0 ? _longDash : _shortDash height: _reticleHeight color: "white" antialiasing: true smooth: true Text { anchors.horizontalCenter: parent.horizontalCenter - anchors.horizontalCenterOffset: -40 + anchors.horizontalCenterOffset: -(_longDash * 0.8) anchors.verticalCenter: parent.verticalCenter smooth: true font.weight: Font.DemiBold + font.pointSize: _fontSize < 1 ? 1 : _fontSize; text: _pitch color: "white" visible: (_pitch != 0) && ((_pitch % 10) === 0) } Text { anchors.horizontalCenter: parent.horizontalCenter - anchors.horizontalCenterOffset: 40 + anchors.horizontalCenterOffset: (_longDash * 0.8) anchors.verticalCenter: parent.verticalCenter smooth: true font.weight: Font.DemiBold + font.pointSize: _fontSize < 1 ? 1 : _fontSize; text: _pitch color: "white" visible: (_pitch != 0) && ((_pitch % 10) === 0) @@ -87,7 +95,7 @@ Rectangle { } transform: [ Rotation { - origin.x: width / 2 + origin.x: width / 2 origin.y: height / 2 angle: -rollAngle } diff --git a/src/ui/qmlcommon/QGCSpeedWidget.qml b/src/ui/qmlcommon/QGCSpeedWidget.qml index 764e873d8ffa5383a25b5e3e7f8bb378b71d70bd..02e41d19ebff29323b8ee5082d2ebcb3a0634ea2 100644 --- a/src/ui/qmlcommon/QGCSpeedWidget.qml +++ b/src/ui/qmlcommon/QGCSpeedWidget.qml @@ -37,12 +37,9 @@ Rectangle { property real _reticleSpacing: 10 property real _reticleHeight: 2 property real _reticleSlot: _reticleSpacing + _reticleHeight - anchors.verticalCenter: parent.verticalCenter - z:10 - height: parent.height * 0.75 > 280 ? 280 : parent.height * 0.75 - clip: true + height: parent.height * 0.65 > 280 ? 280 : parent.height * 0.65 smooth: true radius: 5 border.color: Qt.rgba(1,1,1,0.25) @@ -51,35 +48,43 @@ Rectangle { GradientStop { position: 0.5; color: Qt.rgba(0,0,0,0.25) } GradientStop { position: 1.0; color: Qt.rgba(0,0,0,0.65) } } - Column{ - id: col - width: parent.width + Rectangle { + id: clipRect + height: parent.height - 5 + width: parent.width + clip: true + color: Qt.rgba(0,0,0,0); anchors.verticalCenter: parent.verticalCenter - spacing: _reticleSpacing - Repeater { - model: 40 - Rectangle { - property int _speed: -(index - 20) - width: (_speed % 5 === 0) ? 10 : 15 - anchors.right: parent.right - height: _reticleHeight - color: Qt.rgba(1,1,1,0.35) - Text { - visible: (_speed % 5 === 0) - anchors.horizontalCenter: parent.horizontalCenter - anchors.horizontalCenterOffset: -30 - anchors.verticalCenter: parent.verticalCenter - antialiasing: true - font.weight: Font.DemiBold - text: _speed - color: _speed < 0 ? "#f8983a" : "white" - style: Text.Outline - styleColor: Qt.rgba(0,0,0,0.25) + Column{ + id: col + width: parent.width + anchors.verticalCenter: parent.verticalCenter + spacing: _reticleSpacing + Repeater { + model: 40 + Rectangle { + property int _speed: -(index - 20) + width: (_speed % 5 === 0) ? 10 : 15 + anchors.right: parent.right + height: _reticleHeight + color: Qt.rgba(1,1,1,0.35) + Text { + visible: (_speed % 5 === 0) + anchors.horizontalCenter: parent.horizontalCenter + anchors.horizontalCenterOffset: -30 + anchors.verticalCenter: parent.verticalCenter + antialiasing: true + font.weight: Font.DemiBold + text: _speed + color: _speed < 0 ? "#f8983a" : "white" + style: Text.Outline + styleColor: Qt.rgba(0,0,0,0.25) + } } } - } - transform: Translate { - y: (speed * _reticleSlot) - (_reticleSlot / 2) + transform: Translate { + y: (speed * _reticleSlot) - (_reticleSlot / 2) + } } } } diff --git a/src/ui/qmlcommon/attitudeDial.svg b/src/ui/qmlcommon/attitudeDial.svg new file mode 100644 index 0000000000000000000000000000000000000000..1e74c332107021d7d1e2319c22e44d2a03132dc9 --- /dev/null +++ b/src/ui/qmlcommon/attitudeDial.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + diff --git a/src/ui/qmlcommon/attitudeInstrument.svg b/src/ui/qmlcommon/attitudeInstrument.svg new file mode 100644 index 0000000000000000000000000000000000000000..b5a4940d902c2887ff71d6ac61cc9193ba427d41 --- /dev/null +++ b/src/ui/qmlcommon/attitudeInstrument.svg @@ -0,0 +1,7 @@ + + + + + diff --git a/src/ui/qmlcommon/attitudePointer.svg b/src/ui/qmlcommon/attitudePointer.svg new file mode 100644 index 0000000000000000000000000000000000000000..50bdbdedf83a97154e814997cbda8743b9c2bf3c --- /dev/null +++ b/src/ui/qmlcommon/attitudePointer.svg @@ -0,0 +1,7 @@ + + + + + + diff --git a/src/ui/qmlcommon/buttonMore.svg b/src/ui/qmlcommon/buttonMore.svg new file mode 100644 index 0000000000000000000000000000000000000000..f19e27ff1d2055cffd7b421e68aff96ebec46aae --- /dev/null +++ b/src/ui/qmlcommon/buttonMore.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + diff --git a/src/ui/qmlcommon/compassInstrumentAirplane.svg b/src/ui/qmlcommon/compassInstrumentAirplane.svg new file mode 100644 index 0000000000000000000000000000000000000000..5fdc728643a4717abace682c31d7d4c61d97bfdf --- /dev/null +++ b/src/ui/qmlcommon/compassInstrumentAirplane.svg @@ -0,0 +1,9 @@ + + + + + diff --git a/src/ui/qmlcommon/compassInstrumentDial.svg b/src/ui/qmlcommon/compassInstrumentDial.svg new file mode 100644 index 0000000000000000000000000000000000000000..f265280b1905c2387d805fbf0ed70ed2a6efe3b5 --- /dev/null +++ b/src/ui/qmlcommon/compassInstrumentDial.svg @@ -0,0 +1,84 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/ui/qmlcommon/qmldir b/src/ui/qmlcommon/qmldir index 02d05968ee69b57e66d966ae4efe28d87a907927..6bd91f6d99d9a4061f043766c4580c8743325b02 100644 --- a/src/ui/qmlcommon/qmldir +++ b/src/ui/qmlcommon/qmldir @@ -10,4 +10,7 @@ QGCPitchWidget 1.0 QGCPitchWidget.qml QGCSpeedWidget 1.0 QGCSpeedWidget.qml QGCSlider 1.0 QGCSlider.qml QGCWaypointEditor 1.0 QGCWaypointEditor.qml -QGCMapToolButton 1.0 QGCMapToolButton.qml \ No newline at end of file +QGCMapToolButton 1.0 QGCMapToolButton.qml +QGCAttitudeInstrument 1.0 QGCAttitudeInstrument.qml +QGCCompassInstrument 1.0 QGCCompassInstrument.qml +QGCArtificialHorizon 1.0 QGCArtificialHorizon.qml diff --git a/src/ui/qmlcommon/rollDial.svg b/src/ui/qmlcommon/rollDial.svg deleted file mode 100644 index 6225276b06b30dc53ed8a2963273473f94d74b2b..0000000000000000000000000000000000000000 --- a/src/ui/qmlcommon/rollDial.svg +++ /dev/null @@ -1,32 +0,0 @@ - - - - - 00 - 15 - 30 - 45 - 60 - 15 - 30 - 45 - 60 - - - - - - - - - - - - - - - - - diff --git a/src/ui/qmlcommon/rollPointer.svg b/src/ui/qmlcommon/rollPointer.svg deleted file mode 100644 index 4bb1551a46b96d7160733bc3dc8aab7cc2867117..0000000000000000000000000000000000000000 --- a/src/ui/qmlcommon/rollPointer.svg +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - - - - - - - -