Warning, /utilities/kirogi/src/ui/FlightControls.qml is written in an unsupported language. File is not indexed.
0001 /* 0002 * Copyright 2019 Eike Hein <hein@kde.org> 0003 * 0004 * This program is free software; you can redistribute it and/or 0005 * modify it under the terms of the GNU General Public License as 0006 * published by the Free Software Foundation; either version 2 of 0007 * the License or (at your option) version 3 or any later version 0008 * accepted by the membership of KDE e.V. (or its successor approved 0009 * by the membership of KDE e.V.), which shall act as a proxy 0010 * defined in Section 14 of version 3 of the license. 0011 * 0012 * This program is distributed in the hope that it will be useful, 0013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0015 * GNU General Public License for more details. 0016 * 0017 * You should have received a copy of the GNU General Public License 0018 * along with this program. If not, see <http://www.gnu.org/licenses/>. 0019 */ 0020 0021 import QtQuick 2.12 0022 import QtQuick.Controls 2.12 as QQC2 0023 0024 import org.kde.kirigami 2.6 as Kirigami 0025 0026 import org.kde.kirogi 0.1 as Kirogi 0027 import org.kde.kirogi.video 0.1 as KirogiVideo 0028 0029 Kirigami.Page { 0030 id: page 0031 0032 LayoutMirroring.enabled: false 0033 LayoutMirroring.childrenInherit: true 0034 0035 readonly property int yardstick: Math.min(parent.width, parent.height) 0036 readonly property bool touched: leftTouchPoint.active || rightTouchPoint.active 0037 0038 property alias gamepad: gamepadLoader.item 0039 0040 leftPadding: 0 0041 rightPadding: 0 0042 topPadding: 0 0043 bottomPadding: 0 0044 0045 Connections { 0046 target: kirogi 0047 0048 onCurrentPageChanged: updatePilotingState() 0049 onCurrentVehicleChanged: updatePilotingState() 0050 onReadyChanged: updatePilotingState() 0051 } 0052 0053 function updatePilotingState() { 0054 var vehicle = kirogi.currentVehicle; 0055 0056 if (!vehicle || !vehicle.ready) { 0057 return; 0058 } 0059 0060 vehicle.setPiloting(kirogi.currentPage == page); 0061 0062 if (kirogi.currentPage == page && !kirogi.currentVehicle.videoStreamEnabled 0063 && vehicle.isActionSupported(Kirogi.AbstractVehicle.ToggleVideoStream)) { 0064 vehicle.requestEnableVideoStream(true); 0065 } 0066 } 0067 0068 function setNewStickPosition() { 0069 if (kirogi.currentVehicle) { 0070 kirogi.currentVehicle.pilot(rightDPad.axisX, rightDPad.axisY, leftDPad.axisX, leftDPad.axisY); 0071 } 0072 } 0073 0074 VideoElement { 0075 anchors.fill: parent 0076 } 0077 0078 // FIXME TODO: This is a workaround around the org.kde.desktop+Breeze style engine 0079 // hijacking drag on the window. 0080 TapHandler { 0081 enabled: !Kirigami.Settings.isMobile 0082 } 0083 0084 Item { 0085 anchors.left: parent.left 0086 0087 width: parent.width / 2 0088 height: parent.height 0089 0090 0091 PointHandler { 0092 id: leftTouchPoint 0093 0094 enabled: inputMode.selectedMode == 0 || kirogiSettings.alwaysShowDPads 0095 0096 grabPermissions: PointerHandler.ApprovesTakeOverByAnything | PointerHandler.ApprovesCancellation 0097 } 0098 } 0099 0100 Item { 0101 anchors.right: parent.right 0102 0103 width: parent.width / 2 0104 height: parent.height 0105 0106 PointHandler { 0107 id: rightTouchPoint 0108 0109 enabled: inputMode.selectedMode == 0 || kirogiSettings.alwaysShowDPads 0110 } 0111 } 0112 0113 TouchButton { 0114 id: leftButton 0115 0116 anchors.top: leftPillBox.bottom 0117 anchors.topMargin: Math.round(leftPillBox.y * 1.5) 0118 anchors.left: parent.left 0119 anchors.leftMargin: leftPillBox.y 0120 0121 icon: kirogi.currentVehicle ? kirogi.currentVehicle.iconName : "uav" 0122 toolTipText: i18nc("%1 = Keyboard shortcut", "Drone (%1)", vehiclePageAction.shortcut) 0123 0124 onTapped: switchApplicationPage(vehiclePage) 0125 } 0126 0127 PillBox { 0128 id: launchButton 0129 0130 anchors.horizontalCenter: parent.horizontalCenter 0131 anchors.top: parent.top 0132 anchors.topMargin: Kirigami.Units.smallSpacing 0133 0134 width: Math.min(launchButtonLabel.implicitWidth + Kirigami.Units.smallSpacing * 4, 0135 rightPillBox.x - leftPillBox.x - leftPillBox.width - (leftPillBox.x * 2)) 0136 height: 2 * Math.round((leftPillBox.height * 1.12) / 2); 0137 0138 readonly property var __color: { 0139 if (launchButtonMouseArea.containsMouse) { 0140 return Kirigami.Theme.hoverColor; 0141 } 0142 0143 if (kirogi.connected) { 0144 if (kirogi.flying) { 0145 return "red"; 0146 } else if (kirogi.ready) { 0147 return "green"; 0148 } else { 0149 return "yellow"; 0150 } 0151 } 0152 0153 return "red"; 0154 } 0155 0156 backgroundColor: "dark" + __color 0157 backgroundOpacity: 0.4 0158 0159 borderWidth: 2 0160 borderRadius: height / 4 0161 borderColor: launchButtonLabel.color 0162 0163 Text { 0164 id: launchButtonLabel 0165 0166 anchors.fill: parent 0167 0168 font.pixelSize: parent.height * 0.7 0169 font.bold: true 0170 color: launchButton.__color 0171 0172 horizontalAlignment: Text.AlignHCenter 0173 verticalAlignment: Text.AlignVCenter 0174 0175 elide: Text.ElideRight 0176 0177 text: { 0178 if (kirogi.connected) { 0179 if (kirogi.flying) { 0180 return i18n("LAND"); 0181 } else if (kirogi.ready) { 0182 return i18n("TAKE OFF"); 0183 } else { 0184 return i18n("PREPARING") 0185 } 0186 } 0187 0188 return i18n("DISCONNECTED"); 0189 } 0190 0191 Behavior on color { 0192 enabled: !launchButtonMouseArea.pressed 0193 0194 ColorAnimation { duration: Kirigami.Units.shortDuration } 0195 } 0196 } 0197 0198 MouseArea { 0199 id: launchButtonMouseArea 0200 0201 anchors.fill: parent 0202 0203 enabled: kirogi.ready 0204 hoverEnabled: enabled 0205 0206 onClicked: { 0207 if (kirogi.flying) { 0208 kirogi.currentVehicle.requestLand(); 0209 } else { 0210 kirogi.currentVehicle.requestTakeOff(); 0211 } 0212 } 0213 } 0214 } 0215 0216 TouchButton { 0217 id: rightButton 0218 0219 anchors.top: rightPillBox.bottom 0220 anchors.topMargin: leftButton.anchors.topMargin 0221 anchors.right: parent.right 0222 anchors.rightMargin: leftButton.anchors.leftMargin 0223 0224 icon: "map-flat" 0225 toolTipText: i18nc("%1 = Keyboard shortcut", "Navigation Map (%1)", navigationMapPageAction.shortcut) 0226 0227 onTapped: switchApplicationPage(navigationMapPage) 0228 } 0229 0230 ModeRocker { 0231 id: flightMode 0232 0233 enabled: kirogi.ready 0234 0235 anchors.left: parent.left 0236 anchors.verticalCenter: shotButton.verticalCenter 0237 0238 selectedMode: { 0239 if (kirogi.ready) { 0240 if (kirogi.currentVehicle.performanceMode == Kirogi.AbstractVehicle.FilmPerformance) { 0241 return 0; 0242 } else if (kirogi.currentVehicle.performanceMode == Kirogi.AbstractVehicle.SportPerformance) { 0243 return 1; 0244 } 0245 } 0246 0247 return -1; 0248 } 0249 0250 firstLabelText: i18n("FILM") 0251 firstToolTipText: i18n("Fly Slow") 0252 0253 secondLabelText: i18n("SPORT") 0254 secondToolTipText: i18n("Fly Fast") 0255 0256 onModeTapped: { 0257 if (selectedMode == mode) { 0258 return; 0259 } 0260 0261 if (mode == 0) { 0262 kirogi.currentVehicle.requestPerformanceMode(Kirogi.AbstractVehicle.FilmPerformance); 0263 } else if (mode == 1) { 0264 kirogi.currentVehicle.requestPerformanceMode(Kirogi.AbstractVehicle.SportPerformance); 0265 } 0266 } 0267 0268 Component.onCompleted: { 0269 var handleWidth = kirogi.LayoutMirroring.enabled ? parent.width - globalDrawer.handle.x 0270 : globalDrawer.handle.x + globalDrawer.handle.width; 0271 anchors.leftMargin = globalDrawer.modal ? handleWidth + leftPillBox.y : leftPillBox.y; 0272 } 0273 } 0274 0275 ModeRocker { 0276 id: inputMode 0277 0278 visible: gamepad && gamepad.connected && !kirogiSettings.alwaysShowDPads 0279 0280 anchors.verticalCenter: shotButton.verticalCenter 0281 anchors.left: flightMode.right 0282 anchors.leftMargin: leftPillBox.y 0283 0284 firstLabelText: i18n("SCREEN") 0285 firstIconSource: Kirigami.Settings.isMobile ? "phone-symbolic" : "computer-symbolic" 0286 firstToolTipText: i18n("Use Virtual D-Pads") 0287 0288 secondLabelText: i18n("CONTROLLER") 0289 secondIconSource: "folder-games-symbolic" 0290 secondToolTipText: i18n("Use Gamepad Controller") 0291 0292 showLabels: false 0293 showIcons: true 0294 0295 // If there is no gamepad connected, the user will not be able to change back to virtual joystick mode. 0296 // It's necessary to force the virtual joystick as default if no joystick is connected. 0297 selectedMode: gamepad.connected ? kirogiSettings.lastInputMode : 0 0298 0299 onModeTapped: { 0300 selectedMode = mode; 0301 kirogiSettings.lastInputMode = selectedMode; 0302 } 0303 0304 } 0305 0306 ModeRocker { 0307 id: shotMode 0308 0309 enabled: kirogi.ready 0310 0311 anchors.right: shotButton.right 0312 anchors.rightMargin: shotButton.width / 2 0313 anchors.verticalCenter: shotButton.verticalCenter 0314 0315 width: (implicitWidth + shotButton.width / 2) - Kirigami.Units.largeSpacing 0316 0317 property int requestedMode: 0 0318 0319 firstModeEnabled: enabled && kirogi.currentVehicle.isActionSupported(Kirogi.AbstractVehicle.RecordVideo) 0320 secondModeEnabled: enabled && kirogi.currentVehicle.isActionSupported(Kirogi.AbstractVehicle.TakePicture) 0321 0322 firstLabelText: i18n("VIDEO") 0323 firstIconSource: "emblem-videos-symbolic" 0324 firstToolTipText: i18n("Record Videos") 0325 0326 secondLabelText: i18n("PHOTO") 0327 secondIconSource: "emblem-photos-symbolic" 0328 secondToolTipText: i18n("Take Photos") 0329 0330 showLabels: false 0331 showIcons: true 0332 0333 selectedMode: kirogi.ready ? requestedMode : -1 0334 0335 onModeTapped: requestedMode = mode 0336 } 0337 0338 TouchButton { 0339 id: shotButton 0340 0341 enabled: { 0342 if (!kirogi.ready) { 0343 return false; 0344 } 0345 0346 if ((shotMode.selectedMode == 0 && !kirogi.currentVehicle.isActionSupported(Kirogi.AbstractVehicle.RecordVideo)) 0347 || (shotMode.selectedMode == 1 && (!kirogi.currentVehicle.isActionSupported(Kirogi.AbstractVehicle.TakePicture) 0348 || !kirogi.currentVehicle.canTakePicture))) { 0349 return false; 0350 } 0351 0352 return true; 0353 } 0354 0355 anchors.right: parent.right 0356 anchors.rightMargin: flightMode.anchors.leftMargin 0357 anchors.bottom: parent.bottom 0358 anchors.bottomMargin: launchButton.anchors.topMargin 0359 0360 icon: "media-record-symbolic" 0361 iconColor: shotMode.selectedMode == 0 && (kirogi.currentVehicle && kirogi.currentVehicle.isRecordingVideo) ? "red" : "white" 0362 toolTipText: { 0363 if (shotMode.selectedMode) { 0364 return i18n("Take Photo"); 0365 } else if (kirogi.currentVehicle && kirogi.currentVehicle.isRecordingVideo) { 0366 return i18n("Stop Recording Video"); 0367 } 0368 0369 return i18n("Record Video"); 0370 } 0371 0372 onTapped: { 0373 if (!kirogi.ready) { 0374 return; 0375 } 0376 0377 if (shotMode.selectedMode == 0) { 0378 kirogi.currentVehicle.requestAction(Kirogi.AbstractVehicle.RecordVideo); 0379 } else if (shotMode.selectedMode == 1) { 0380 kirogi.currentVehicle.requestAction(Kirogi.AbstractVehicle.TakePicture); 0381 } 0382 } 0383 } 0384 0385 TouchDPad { 0386 id: leftDPad 0387 0388 visible: inputMode.selectedMode == 0 || kirogiSettings.alwaysShowDPads || (gamepad && !gamepad.connected) 0389 0390 anchors.left: parent.left 0391 anchors.leftMargin: yardstick * 0.18 0392 anchors.bottom: parent.bottom 0393 anchors.bottomMargin: yardstick * 0.20 0394 0395 width: Math.min(yardstick * 0.45, parent.width / 4) 0396 height: width 0397 0398 leftIcon: "edit-undo" 0399 leftToolTipText: i18n("Turn Left") 0400 rightIcon: "edit-redo" 0401 rightToolTipText: i18n("Turn Right") 0402 topIcon: "arrow-up" 0403 topToolTipText: i18n("Move Up") 0404 bottomIcon: "arrow-down" 0405 bottomToolTipText: i18n("Move Down") 0406 0407 onXChanged: moved = aboutToMove 0408 0409 onAxisXChanged: setNewStickPosition() 0410 onAxisYChanged: setNewStickPosition() 0411 0412 touchPos: { 0413 if (moved && leftTouchPoint) { 0414 var xDifference = 0; 0415 0416 if (leftTouchPoint.point.scenePosition.x > leftTouchPoint.point.scenePressPosition.x) { 0417 xDifference = xDifference + Math.abs(leftTouchPoint.point.scenePressPosition.x - leftTouchPoint.point.scenePosition.x); 0418 } else { 0419 xDifference = xDifference - Math.abs(leftTouchPoint.point.scenePressPosition.x - leftTouchPoint.point.scenePosition.x) 0420 } 0421 0422 var x = leftDPad.x + leftDPad.width / 2 + xDifference; 0423 0424 var yDifference = 0; 0425 0426 if (leftTouchPoint.point.scenePosition.y > leftTouchPoint.point.scenePressPosition.y) { 0427 yDifference = yDifference + Math.abs(leftTouchPoint.point.scenePressPosition.y - leftTouchPoint.point.scenePosition.y); 0428 } else { 0429 yDifference = yDifference - Math.abs(leftTouchPoint.point.scenePressPosition.y - leftTouchPoint.point.scenePosition.y) 0430 } 0431 0432 var y = leftDPad.y + leftDPad.height / 2 + yDifference; 0433 0434 return parent.mapToItem(leftDPad, x, y); 0435 } 0436 0437 return null; 0438 } 0439 0440 states: [ 0441 State { 0442 name: "inactive" 0443 0444 AnchorChanges { 0445 target: leftDPad 0446 0447 anchors.left: parent.left 0448 anchors.bottom: parent.bottom 0449 } 0450 0451 PropertyChanges { 0452 target: leftDPad 0453 0454 aboutToMove: false 0455 moved: false 0456 } 0457 }, 0458 State { 0459 name: "active" 0460 0461 when: leftTouchPoint.active 0462 0463 AnchorChanges { 0464 target: leftDPad 0465 0466 anchors.left: undefined 0467 anchors.bottom: undefined 0468 } 0469 0470 PropertyChanges { 0471 target: leftDPad 0472 0473 aboutToMove: true 0474 x: Math.min((parent.width / 2) - width, Math.max(0, leftTouchPoint.point.scenePressPosition.x - width / 2)) 0475 y: Math.min(parent.height - height, Math.max(0, leftTouchPoint.point.scenePressPosition.y - height / 2)) 0476 } 0477 } 0478 ] 0479 } 0480 0481 TouchDPad { 0482 id: rightDPad 0483 0484 visible: leftDPad.visible 0485 0486 width: leftDPad.height 0487 height: width 0488 0489 anchors.right: parent.right 0490 anchors.rightMargin: leftDPad.anchors.leftMargin 0491 anchors.bottom: parent.bottom 0492 anchors.bottomMargin: leftDPad.anchors.bottomMargin 0493 0494 leftIcon: "go-previous" 0495 leftToolTipText: i18n("Move Left") 0496 rightIcon: "go-next" 0497 rightToolTipText: i18n("Move Right") 0498 topIcon: "go-up" 0499 topToolTipText: i18n("Move Forward") 0500 bottomIcon: "go-down" 0501 bottomToolTipText: i18n("Move Backward") 0502 0503 onXChanged: moved = aboutToMove 0504 0505 onAxisXChanged: setNewStickPosition() 0506 onAxisYChanged: setNewStickPosition() 0507 0508 touchPos: { 0509 if (moved && rightTouchPoint.active) { 0510 var xDifference = 0; 0511 0512 if (rightTouchPoint.point.scenePosition.x > rightTouchPoint.point.scenePressPosition.x) { 0513 xDifference = xDifference + Math.abs(rightTouchPoint.point.scenePressPosition.x - rightTouchPoint.point.scenePosition.x); 0514 } else { 0515 xDifference = xDifference - Math.abs(rightTouchPoint.point.scenePressPosition.x - rightTouchPoint.point.scenePosition.x) 0516 } 0517 0518 var x = rightDPad.x + rightDPad.width / 2 + xDifference; 0519 0520 var yDifference = 0; 0521 0522 if (rightTouchPoint.point.scenePosition.y > rightTouchPoint.point.scenePressPosition.y) { 0523 yDifference = yDifference + Math.abs(rightTouchPoint.point.scenePressPosition.y - rightTouchPoint.point.scenePosition.y); 0524 } else { 0525 yDifference = yDifference - Math.abs(rightTouchPoint.point.scenePressPosition.y - rightTouchPoint.point.scenePosition.y) 0526 } 0527 0528 var y = rightDPad.y + rightDPad.height / 2 + yDifference; 0529 0530 return parent.mapToItem(rightDPad, x, y); 0531 } 0532 0533 return null; 0534 } 0535 0536 states: [ 0537 State { 0538 name: "inactive" 0539 0540 AnchorChanges { 0541 target: rightDPad 0542 0543 anchors.left: parent.right 0544 anchors.bottom: parent.bottom 0545 } 0546 0547 PropertyChanges { 0548 target: rightDPad 0549 0550 aboutToMove: false 0551 moved: false 0552 } 0553 }, 0554 State { 0555 name: "active" 0556 0557 when: rightTouchPoint.active 0558 AnchorChanges { 0559 target: rightDPad 0560 0561 anchors.right: undefined 0562 anchors.bottom: undefined 0563 } 0564 0565 PropertyChanges { 0566 target: rightDPad 0567 0568 aboutToMove: true 0569 x: Math.max(parent.width / 2, Math.min(parent.width - width, rightTouchPoint.point.scenePressPosition.x - width / 2)) 0570 y: Math.min(parent.height - height, Math.max(0, rightTouchPoint.point.scenePressPosition.y - height / 2)) 0571 } 0572 } 0573 ] 0574 } 0575 0576 PillBox { 0577 id: leftPillBox 0578 0579 anchors.verticalCenter: launchButton.verticalCenter 0580 anchors.left: parent.left 0581 anchors.leftMargin: y 0582 0583 width: leftPillBoxContents.implicitWidth + Kirigami.Units.largeSpacing * 4 0584 height: 2 * Math.round((Math.max(Kirigami.Units.iconSizes.small, fontMetrics.height) + Kirigami.Units.smallSpacing * 3) / 2); 0585 0586 Row { 0587 id: leftPillBoxContents 0588 0589 anchors.horizontalCenter: parent.horizontalCenter 0590 0591 height: parent.height 0592 0593 spacing: Kirigami.Units.largeSpacing 0594 0595 Kirigami.Icon { 0596 anchors.verticalCenter: parent.verticalCenter 0597 0598 width: Kirigami.Units.iconSizes.small 0599 height: width 0600 0601 color: "white" 0602 smooth: true 0603 isMask: true 0604 0605 source: "speedometer" 0606 } 0607 0608 QQC2.Label { 0609 anchors.verticalCenter: parent.verticalCenter 0610 0611 width: kirogi.currentVehicle ? Math.round(Math.max(implicitWidth, fontMetrics.tightBoundingRect(i18n("%1 m/s", "0.0")).width)) 0612 : Math.round(implicitWidth) 0613 0614 color: "white" 0615 0616 horizontalAlignment: Text.AlignRight 0617 0618 text: { 0619 if(kirogi.currentVehicle) { 0620 return i18n("%1 m/s", kirogi.flying ? kirogi.currentVehicle.speed : "0"); 0621 } 0622 0623 return i18n("– m/s"); 0624 } 0625 } 0626 0627 PillBoxSeparator {} 0628 0629 Kirigami.Icon { 0630 anchors.verticalCenter: parent.verticalCenter 0631 0632 width: Kirigami.Units.iconSizes.small 0633 height: width 0634 0635 color: "white" 0636 smooth: true 0637 isMask: true 0638 0639 source: "kruler-west" 0640 } 0641 0642 QQC2.Label { 0643 anchors.verticalCenter: parent.verticalCenter 0644 0645 width: kirogi.ready ? Math.round(Math.max(implicitWidth, fontMetrics.tightBoundingRect(i18n("%1 m", "0.0")).width)) 0646 : Math.round(implicitWidth) 0647 0648 color: "white" 0649 0650 horizontalAlignment: Text.AlignRight 0651 0652 text: { 0653 if (kirogi.currentVehicle) { 0654 return i18n("%1 m", kirogi.currentVehicle.altitude.toFixed(2)) 0655 } 0656 0657 return i18n("– m"); 0658 } 0659 } 0660 0661 PillBoxSeparator {} 0662 0663 Kirigami.Icon { 0664 anchors.verticalCenter: parent.verticalCenter 0665 0666 width: Kirigami.Units.iconSizes.small 0667 height: width 0668 0669 color: "white" 0670 smooth: true 0671 isMask: true 0672 0673 source: "kruler-south" 0674 } 0675 0676 QQC2.Label { 0677 anchors.verticalCenter: parent.verticalCenter 0678 0679 width: kirogi.currentVehicle ? Math.round(Math.max(implicitWidth, fontMetrics.tightBoundingRect(i18n("%1 m", "0.0")).width)) 0680 : Math.round(implicitWidth) 0681 0682 color: "white" 0683 0684 horizontalAlignment: Text.AlignRight 0685 0686 text: { 0687 if (kirogi.currentVehicle && kirogi.currentVehicle.distance >= 0) { 0688 return i18n("%1 m", kirogi.currentVehicle.distance.toFixed(1)); 0689 } 0690 0691 if (kirogi.distance !== 0) { 0692 return i18n("%1 m", kirogi.distance.toFixed(1)); 0693 } 0694 0695 return i18n("– m"); 0696 } 0697 } 0698 } 0699 } 0700 0701 PillBox { 0702 id: rightPillBox 0703 0704 anchors.verticalCenter: launchButton.verticalCenter 0705 anchors.right: parent.right 0706 anchors.rightMargin: leftPillBox.anchors.leftMargin 0707 0708 width: rightPillBoxContents.implicitWidth + Kirigami.Units.largeSpacing * 4 0709 height: leftPillBox.height 0710 0711 Row { 0712 id: rightPillBoxContents 0713 0714 x: Kirigami.Units.largeSpacing 0715 0716 anchors.horizontalCenter: parent.horizontalCenter 0717 0718 height: parent.height 0719 0720 spacing: Kirigami.Units.largeSpacing 0721 0722 Kirigami.Icon { 0723 anchors.verticalCenter: parent.verticalCenter 0724 0725 width: Kirigami.Units.iconSizes.small 0726 height: width 0727 0728 color: "white" 0729 smooth: true 0730 isMask: true 0731 0732 source: "clock" 0733 } 0734 0735 QQC2.Label { 0736 anchors.verticalCenter: parent.verticalCenter 0737 0738 width: kirogi.currentVehicle ? Math.round(Math.max(implicitWidth, fontMetrics.tightBoundingRect(i18n("%1 m", "0:00")).width)) 0739 : Math.round(implicitWidth) 0740 0741 color: "white" 0742 0743 horizontalAlignment: Text.AlignRight 0744 0745 text: { 0746 if (kirogi.ready) { 0747 var time = kirogi.flying ? kirogi.currentVehicle.flightTime : 0; 0748 return i18n("%1 min", (time - (time %= 60)) / 60 + (9 < time ?':':':0') + time); 0749 } 0750 0751 return i18n("– min"); 0752 } 0753 } 0754 0755 PillBoxSeparator {} 0756 0757 Kirigami.Icon { 0758 anchors.verticalCenter: parent.verticalCenter 0759 0760 width: Kirigami.Units.iconSizes.small 0761 height: width 0762 0763 color: "white" 0764 smooth: true 0765 isMask: kirogi.currentVehicle 0766 0767 source: { 0768 if (kirogi.currentVehicle) { 0769 if (kirogi.currentVehicle.signalStrength === 0) { 0770 return "network-wireless-connected-00"; 0771 } else if (kirogi.currentVehicle.signalStrength < 25) { 0772 return "network-wireless-connected-25"; 0773 } else if (kirogi.currentVehicle.signalStrength < 50) { 0774 return "network-wireless-connected-50"; 0775 } else if (kirogi.currentVehicle.signalStrength < 75) { 0776 return "network-wireless-connected-75"; 0777 } else if (kirogi.currentVehicle.signalStrength <= 100) { 0778 return "network-wireless-connected-100"; 0779 } 0780 } 0781 0782 if (kirogi.connected) { 0783 return "network-wireless-acquiring"; 0784 } 0785 0786 return "network-wireless-disconnected"; 0787 } 0788 } 0789 0790 QQC2.Label { 0791 anchors.verticalCenter: parent.verticalCenter 0792 0793 width: kirogi.currentVehicle ? Math.round(Math.max(implicitWidth, fontMetrics.tightBoundingRect(i18n("%1%", 00)).width)) 0794 : Math.round(implicitWidth) 0795 0796 color: "white" 0797 0798 horizontalAlignment: Text.AlignRight 0799 0800 text: kirogi.currentVehicle ? i18n("%1%", kirogi.currentVehicle.signalStrength) : i18n("N/A") 0801 } 0802 0803 PillBoxSeparator {} 0804 0805 Kirigami.Icon { 0806 anchors.verticalCenter: parent.verticalCenter 0807 0808 width: Kirigami.Units.iconSizes.small 0809 height: width 0810 0811 color: "white" 0812 smooth: true 0813 isMask: kirogi.currentVehicle 0814 0815 source: { 0816 if (kirogi.currentVehicle) { 0817 var roundedBatteryLevel = Math.round(kirogi.currentVehicle.batteryLevel / 10); 0818 return "battery-" + roundedBatteryLevel.toString().padStart(2, "0") + "0"; 0819 } 0820 0821 return "battery-missing"; 0822 } 0823 } 0824 0825 QQC2.Label { 0826 anchors.verticalCenter: parent.verticalCenter 0827 0828 width: kirogi.currentVehicle ? Math.round(Math.max(implicitWidth, fontMetrics.tightBoundingRect(i18n("%1%", 00)).width)) 0829 : Math.round(implicitWidth) 0830 0831 color: "white" 0832 0833 horizontalAlignment: Text.AlignRight 0834 0835 text: kirogi.currentVehicle ? i18n("%1%", kirogi.currentVehicle.batteryLevel) : i18n("N/A") 0836 } 0837 } 0838 } 0839 0840 PitchBar { 0841 id: pitchBar 0842 0843 anchors.centerIn: parent 0844 0845 width: 25 0846 height: parent.height * 0.6 0847 0848 pitch: kirogi.currentVehicle ? kirogi.currentVehicle.pitch * (180/Math.PI) : 0.0 0849 } 0850 0851 VirtualHorizon { 0852 id: virtualHorizon 0853 0854 anchors.centerIn: pitchBar 0855 0856 width: 110 0857 0858 roll: kirogi.currentVehicle ? kirogi.currentVehicle.roll * (180/Math.PI) : 0 0859 } 0860 0861 YawBar { 0862 id: yawBar 0863 0864 anchors.bottom: inputMode.visible ? inputMode.top : parent.bottom 0865 anchors.horizontalCenter: parent.horizontalCenter 0866 width: parent.width / 2 0867 0868 tickWidth: 10 0869 0870 yaw: kirogi.currentVehicle ? kirogi.currentVehicle.yaw * (180 / Math.PI) : 0 0871 } 0872 0873 VehicleActionsDrawer { 0874 enabled: kirogi.currentPage == page // FIXME TODO: Why doesn't come down from page.enabled? 0875 0876 width: Kirigami.Units.gridUnit * 19 0877 0878 edge: kirogi.LayoutMirroring.enabled ? Qt.LeftEdge : Qt.RightEdge 0879 0880 handleClosedIcon.source: "configure" 0881 } 0882 0883 Loader { 0884 id: gamepadLoader 0885 0886 source: "Gamepad.qml" 0887 asynchronous: true 0888 0889 // FIXME TODO: QtGamepad currently causes performance problems on 0890 // Android (blocking multi-tasking) that need to be investigated. 0891 active: !Kirigami.Settings.isMobile 0892 } 0893 }