2 * Copyright (C) 2016 The LibrePilot Project
3 * Contact: http://www.librepilot.org
5 * This file is part of LibrePilot GCS.
7 * LibrePilot GCS is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
12 * LibrePilot GCS is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with LibrePilot GCS. If not, see <http://www.gnu.org/licenses/>.
22 import "../js/common.js" as Utils
23 import "../js/uav.js" as UAV
27 property variant sceneSize
33 property real posEast_old
34 property real posNorth_old
35 property real total_distance
36 property real total_distance_km
38 property bool init_dist: false
40 function reset_distance() {
44 function compute_distance(posEast,posNorth) {
45 if (total_distance == 0 && !init_dist) { init_dist = "true"; posEast_old = posEast; posNorth_old = posNorth; }
46 if (posEast > posEast_old+3 || posEast < posEast_old - 3 || posNorth > posNorth_old + 3 || posNorth < posNorth_old - 3) {
47 total_distance += Math.sqrt(Math.pow((posEast - posEast_old ), 2) + Math.pow((posNorth - posNorth_old), 2));
48 total_distance_km = total_distance / 1000;
50 posEast_old = posEast;
51 posNorth_old = posNorth;
52 return total_distance;
62 sceneSize: info.sceneSize
63 elementName: "info-bg"
65 opacity: opaque ? 1 : 0.3
72 property real bar_width: (info_bg.height + info_bg.width) / 110
74 property variant gps_tooltip: "Altitude : " + UAV.gpsAltitude() + "m\n" +
75 "H/V/P DOP : " + UAV.gpsHdopInfo() +
76 [UAV.gpsSensorType() == "DJI" ? "" : "\n" + UAV.gpsSatsInView() + " Sats in view"]
83 property int minSatNumber : index
84 width: Math.round(bar_width)
91 x: Math.round((bar_width * 4.5) + (bar_width * 1.6 * index))
92 height: bar_width * index * 0.6
93 y: (bar_width * 8) - height
95 opacity: UAV.gpsNumSat() >= minSatNumber ? 1 : 0.4
99 SvgElementPositionItem {
100 sceneSize: info.sceneSize
101 elementName: "gps-mode-text"
108 text: [UAV.gpsNumSat() > 5 ? " " + UAV.gpsNumSat().toString() + " sats - " : ""] + UAV.gpsStatus()
109 anchors.centerIn: parent
110 font.pixelSize: parent.height*1.3
111 font.family: pt_bold.name
112 font.weight: Font.DemiBold
118 sceneSize: info.sceneSize
119 elementName: "gps-icon"
120 width: scaledBounds.width * sceneItem.width
121 height: scaledBounds.height * sceneItem.height
128 // Waypoint Info (Top)
129 // Only visible when PathPlan is active (WP loaded)
132 sceneSize: info.sceneSize
133 elementName: "waypoint-labels"
134 width: scaledBounds.width * sceneItem.width
135 height: scaledBounds.height * sceneItem.height
136 y: Math.floor(scaledBounds.y * sceneItem.height)
137 visible: UAV.isPathPlanValid()
140 SvgElementPositionItem {
141 sceneSize: info.sceneSize
142 elementName: "waypoint-heading-text"
143 width: scaledBounds.width * sceneItem.width
144 height: scaledBounds.height * sceneItem.height
145 y: Math.floor(scaledBounds.y * sceneItem.height)
146 visible: UAV.isPathPlanValid()
149 text: UAV.isPathPlanValid() ? " " + UAV.waypointHeading().toFixed(1) + "°" : " 0°"
150 anchors.centerIn: parent
155 pixelSize: Math.floor(parent.height * 1.5)
156 weight: Font.DemiBold
161 SvgElementPositionItem {
162 sceneSize: info.sceneSize
163 elementName: "waypoint-distance-text"
164 width: scaledBounds.width * sceneItem.width
165 height: scaledBounds.height * sceneItem.height
166 y: Math.floor(scaledBounds.y * sceneItem.height)
167 visible: UAV.isPathPlanValid()
170 text: UAV.isPathPlanValid() ? " " + UAV.waypointDistance().toFixed(0) + " m" : " 0 m"
171 anchors.centerIn: parent
176 pixelSize: Math.floor(parent.height * 1.5)
177 weight: Font.DemiBold
182 SvgElementPositionItem {
183 sceneSize: info.sceneSize
184 elementName: "waypoint-total-distance-text"
185 width: scaledBounds.width * sceneItem.width
186 height: scaledBounds.height * sceneItem.height
187 y: Math.floor(scaledBounds.y * sceneItem.height)
188 visible: UAV.isPathPlanValid()
190 MouseArea { id: total_dist_mouseArea; anchors.fill: parent; cursorShape: Qt.PointingHandCursor; onClicked: reset_distance()}
193 text: " "+total_distance.toFixed(0)+" m"
194 anchors.centerIn: parent
199 pixelSize: Math.floor(parent.height * 1.5)
200 weight: Font.DemiBold
205 interval: 1000; running: true; repeat: true;
206 onTriggered: { if (UAV.isGpsStatusFix3D()) compute_distance(positionState.east, positionState.north) }
210 SvgElementPositionItem {
211 sceneSize: info.sceneSize
212 elementName: "waypoint-eta-text"
213 width: scaledBounds.width * sceneItem.width
214 height: scaledBounds.height * sceneItem.height
215 y: Math.floor(scaledBounds.y * sceneItem.height)
216 visible: UAV.isPathPlanValid()
219 text: UAV.isPathPlanValid() ? Utils.estimatedTimeOfArrival(UAV.waypointDistance(), UAV.currentVelocity()) : "00:00:00"
220 anchors.centerIn: parent
225 pixelSize: Math.floor(parent.height * 1.5)
226 weight: Font.DemiBold
231 SvgElementPositionItem {
232 sceneSize: info.sceneSize
233 elementName: "waypoint-number-text"
234 width: scaledBounds.width * sceneItem.width
235 height: scaledBounds.height * sceneItem.height
236 y: Math.floor(scaledBounds.y * sceneItem.height)
237 visible: UAV.isPathPlanValid()
240 text: UAV.isPathPlanValid() ? UAV.currentWaypointActive() + " / " + UAV.waypointCount() : "0 / 0"
241 anchors.centerIn: parent
246 pixelSize: Math.floor(parent.height * 1.5)
247 weight: Font.DemiBold
252 SvgElementPositionItem {
253 sceneSize: info.sceneSize
254 elementName: "waypoint-mode-text"
255 width: scaledBounds.width * sceneItem.width
256 height: scaledBounds.height * sceneItem.height
257 y: Math.floor(scaledBounds.y * sceneItem.height)
258 visible: UAV.isPathPlanValid()
261 text: UAV.isPathPlanValid() ? UAV.pathModeDesired() : ""
262 anchors.centerIn: parent
267 pixelSize: Math.floor(parent.height * 1.5)
268 weight: Font.DemiBold
273 // Battery Info (Top)
274 // Only visible when PathPlan not active and Battery module enabled
276 SvgElementPositionItem {
277 id: topbattery_voltamp_bg
278 sceneSize: info.sceneSize
279 elementName: "topbattery-label-voltamp-bg"
281 width: scaledBounds.width * sceneItem.width
282 height: scaledBounds.height * sceneItem.height
283 y: scaledBounds.y * sceneItem.height
284 visible: (!UAV.isPathPlanValid() && UAV.batteryModuleEnabled())
288 color: (UAV.batteryNbCells() > 0) ? UAV.batteryAlarmColor() : "black"
294 sceneSize: info.sceneSize
295 elementName: "topbattery-labels"
296 width: scaledBounds.width * sceneItem.width
297 height: scaledBounds.height * sceneItem.height
298 y: Math.floor(scaledBounds.y * sceneItem.height)
299 visible: (!UAV.isPathPlanValid() && UAV.batteryModuleEnabled())
302 SvgElementPositionItem {
304 sceneSize: info.sceneSize
305 elementName: "topbattery-volt-text"
307 width: scaledBounds.width * sceneItem.width
308 height: scaledBounds.height * sceneItem.height
309 y: scaledBounds.y * sceneItem.height
310 visible: (!UAV.isPathPlanValid() && UAV.batteryModuleEnabled())
317 text: UAV.batteryVoltage()
318 anchors.centerIn: parent
322 pixelSize: Math.floor(parent.height * 0.6)
323 weight: Font.DemiBold
329 SvgElementPositionItem {
331 sceneSize: info.sceneSize
332 elementName: "topbattery-amp-text"
334 width: scaledBounds.width * sceneItem.width
335 height: scaledBounds.height * sceneItem.height
336 y: scaledBounds.y * sceneItem.height
337 visible: (!UAV.isPathPlanValid() && UAV.batteryModuleEnabled())
344 text: UAV.batteryCurrent()
345 anchors.centerIn: parent
349 pixelSize: Math.floor(parent.height * 0.6)
350 weight: Font.DemiBold
356 SvgElementPositionItem {
357 id: topbattery_milliamp
358 sceneSize: info.sceneSize
359 elementName: "topbattery-milliamp-text"
361 width: scaledBounds.width * sceneItem.width
362 height: scaledBounds.height * sceneItem.height
363 y: scaledBounds.y * sceneItem.height
364 visible: (!UAV.isPathPlanValid() && UAV.batteryModuleEnabled())
370 text: "Reset consumed energy"
374 id: reset_consumed_energy_mouseArea;
375 anchors.fill: parent;
376 cursorShape: Qt.PointingHandCursor;
377 onClicked: pfdContext.resetConsumedEnergy();
380 // Alarm based on estimatedFlightTime < 120s orange, < 60s red
381 color: UAV.estimatedTimeAlarmColor()
383 border.color: "white"
384 border.width: topbattery_volt.width * 0.01
385 radius: border.width * 4
388 text: UAV.batteryConsumedEnergy()
389 anchors.centerIn: parent
393 pixelSize: Math.floor(parent.height * 0.6)
394 weight: Font.DemiBold
401 // Only visible when PathPlan not active
404 sceneSize: info.sceneSize
405 elementName: "topbattery-total-distance-label"
406 width: scaledBounds.width * sceneItem.width
407 height: scaledBounds.height * sceneItem.height
408 y: Math.floor(scaledBounds.y * sceneItem.height)
409 visible: !UAV.isPathPlanValid()
412 SvgElementPositionItem {
413 sceneSize: info.sceneSize
414 elementName: "topbattery-total-distance-text"
415 width: scaledBounds.width * sceneItem.width
416 height: scaledBounds.height * sceneItem.height
417 y: Math.floor(scaledBounds.y * sceneItem.height)
418 visible: !UAV.isPathPlanValid()
421 text: "Reset distance counter"
424 MouseArea { id: total_dist_mouseArea2; anchors.fill: parent; cursorShape: Qt.PointingHandCursor; onClicked: reset_distance()}
427 text: total_distance > 1000 ? total_distance_km.toFixed(2) +" Km" : total_distance.toFixed(0)+" m"
428 anchors.right: parent.right
433 pixelSize: Math.floor(parent.height * 1)
434 weight: Font.DemiBold
439 interval: 1000; running: true; repeat: true;
440 onTriggered: { if (UAV.isGpsStatusFix3D()) compute_distance(positionState.east, positionState.north) }
445 // Home info (visible after arming)
450 elementName: "home-bg"
451 sceneSize: info.sceneSize
452 x: Math.floor(scaledBounds.x * sceneItem.width)
453 y: Math.floor(scaledBounds.y * sceneItem.height)
455 opacity: opaque ? 1 : 0.6
459 when: UAV.isTakeOffLocationValid()
460 PropertyChanges { target: home_bg; x: Math.floor(scaledBounds.x * sceneItem.width) - home_bg.width; }
463 transitions: Transition {
464 SequentialAnimation {
465 PropertyAnimation { property: "x"; duration: 800 }
470 SvgElementPositionItem {
471 sceneSize: info.sceneSize
472 id: home_heading_text
473 elementName: "home-heading-text"
474 width: scaledBounds.width * sceneItem.width
475 height: scaledBounds.height * sceneItem.height
476 y: Math.floor(scaledBounds.y * sceneItem.height)
479 name: "fading_heading"
480 when: UAV.isTakeOffLocationValid()
481 PropertyChanges { target: home_heading_text; x: Math.floor(scaledBounds.x * sceneItem.width) - home_bg.width; }
484 transitions: Transition {
485 SequentialAnimation {
486 PropertyAnimation { property: "x"; duration: 800 }
491 text: " " + UAV.homeHeading().toFixed(1) + "°"
492 anchors.centerIn: parent
496 pixelSize: parent.height * 1.2
501 SvgElementPositionItem {
502 sceneSize: info.sceneSize
503 id: home_distance_text
504 elementName: "home-distance-text"
505 width: scaledBounds.width * sceneItem.width
506 height: scaledBounds.height * sceneItem.height
507 y: Math.floor(scaledBounds.y * sceneItem.height)
510 name: "fading_distance"
511 when: UAV.isTakeOffLocationValid()
512 PropertyChanges { target: home_distance_text; x: Math.floor(scaledBounds.x * sceneItem.width) - home_bg.width; }
515 transitions: Transition {
516 SequentialAnimation {
517 PropertyAnimation { property: "x"; duration: 800 }
522 text: UAV.homeDistance().toFixed(0) + " m"
523 anchors.centerIn: parent
527 pixelSize: parent.height * 1.2
532 SvgElementPositionItem {
533 sceneSize: info.sceneSize
535 elementName: "home-eta-text"
536 width: scaledBounds.width * sceneItem.width
537 height: scaledBounds.height * sceneItem.height
538 y: Math.floor(scaledBounds.y * sceneItem.height)
541 name: "fading_distance"
542 when: UAV.isTakeOffLocationValid()
543 PropertyChanges { target: home_eta_text; x: Math.floor(scaledBounds.x * sceneItem.width) - home_bg.width; }
546 transitions: Transition {
547 SequentialAnimation {
548 PropertyAnimation { property: "x"; duration: 800 }
553 text: Utils.estimatedTimeOfArrival(UAV.homeDistance(), UAV.currentVelocity())
554 anchors.centerIn: parent
558 pixelSize: parent.height * 1.2
565 elementName: "info-border"
566 sceneSize: info.sceneSize
567 width: Math.floor(parent.width * 1.009)