8import QGroundControl.Controls
9import QGroundControl.FactControls
10import QGroundControl.FlyView
11import QGroundControl.FlightMap
12import QGroundControl.PlanView
13import QGroundControl.Toolbar
15/// @brief Native QML top level window
16/// All properties defined here are visible to all QML pages.
20 // The special casing for android prevents white bars from showing up on the edges of the screen with newer android versions
21 flags: Qt.Window | (ScreenTools.isAndroid ? Qt.ExpandedClientAreaHint | Qt.NoTitleBarBackgroundHint : 0)
23 // Qt 6.9+ auto-sets ApplicationWindow padding to the display safe-area insets on mobile,
24 // which insets our full-bleed content and leaves a blank strip along the screen edge.
25 // QGC draws edge-to-edge and manages its own insets, so zero the padding.
31 Component.onCompleted: {
32 // Start the sequence of first run prompt(s)
33 firstRunPromptManager.nextPrompt()
36 /// Saves main window position and size and re-opens it in the same position and size next time
37 MainWindowSavedState {
42 id: firstRunPromptManager
44 property var currentDialog: null
45 property var rgPromptIds: QGroundControl.corePlugin.firstRunPromptsToShow()
46 property int nextPromptIdIndex: 0
48 function clearNextPromptSignal() {
50 currentDialog.closed.disconnect(nextPrompt)
54 function nextPrompt() {
55 if (nextPromptIdIndex < rgPromptIds.length) {
56 var component = Qt.createComponent(QGroundControl.corePlugin.firstRunPromptResource(rgPromptIds[nextPromptIdIndex]));
57 currentDialog = component.createObject(mainWindow)
58 currentDialog.closed.connect(nextPrompt)
63 showPreFlightChecklistIfNeeded()
68 readonly property real _topBottomMargins: ScreenTools.defaultFontPixelHeight * 0.5
70 //-------------------------------------------------------------------------
71 //-- Global Scope Variables
76 readonly property var activeVehicle: QGroundControl.multiVehicleManager.activeVehicle
77 readonly property real defaultTextHeight: ScreenTools.defaultFontPixelHeight
78 readonly property real defaultTextWidth: ScreenTools.defaultFontPixelWidth
79 readonly property var planMasterControllerFlyView: flyView.planController
80 readonly property var guidedControllerFlyView: flyView.guidedController
82 // Number of QGCTextField's with validation errors. Used to prevent closing panels with validation errors.
83 property int validationErrorCount: 0
85 // Set to a non-empty string to block navigation with a custom reason (e.g. during calibration)
86 property string navigationBlockedReason: ""
88 // Property to manage RemoteID quick access to settings page
89 property bool commingFromRIDIndicator: false
92 /// Default color palette used throughout the UI
93 QGCPalette { id: qgcPal; colorGroupEnabled: true }
95 //-------------------------------------------------------------------------
98 signal armVehicleRequest
99 signal forceArmVehicleRequest
100 signal disarmVehicleRequest
101 signal vtolTransitionToFwdFlightRequest
102 signal vtolTransitionToMRFlightRequest
103 signal showPreFlightChecklistIfNeeded
105 //-------------------------------------------------------------------------
106 //-- Global Scope Functions
108 // This function is used to prevent view switching if there are validation errors
109 function allowViewSwitch(previousValidationErrorCount = 0, showErrorOnDisallow = true) {
110 // Check for explicit navigation block (e.g. calibration in progress)
111 if (globals.navigationBlockedReason !== "") {
112 if (showErrorOnDisallow) {
113 validationErrorToast.text = globals.navigationBlockedReason
114 if (validationErrorToast.visible) {
115 validationErrorToast.close()
117 validationErrorToast.open()
121 // Run validation on active focus control to ensure it is valid before switching views
122 if (mainWindow.activeFocusControl instanceof FactTextField) {
123 mainWindow.activeFocusControl._onEditingFinished()
125 var allowed = globals.validationErrorCount <= previousValidationErrorCount
126 if (!allowed && showErrorOnDisallow) {
127 validationErrorToast.text = qsTr("Please correct the invalid value before continuing")
128 if (validationErrorToast.visible) {
129 validationErrorToast.close()
131 validationErrorToast.open()
136 function showPlanView() {
137 flyView.visible = false
138 planView.visible = true
139 toolDrawer.visible = false
142 function showFlyView() {
143 flyView.visible = true
144 planView.visible = false
145 toolDrawer.visible = false
148 function showTool(toolTitle, toolSource, toolIcon) {
149 toolDrawer.backIcon = flyView.visible ? "/qmlimages/PaperPlane.svg" : "/qmlimages/Plan.svg"
150 toolDrawer.toolTitle = toolTitle
151 toolDrawer.toolSource = toolSource
152 toolDrawer.toolIcon = toolIcon
153 toolDrawer.visible = true
156 function showAnalyzeTool() {
157 showTool(qsTr("Analyze Tools"), "qrc:/qml/QGroundControl/AnalyzeView/AnalyzeView.qml", "/qmlimages/Analyze.svg")
160 function showVehicleConfig() {
161 showTool(qsTr("Vehicle Configuration"), "qrc:/qml/QGroundControl/VehicleSetup/VehicleConfigView.qml", "/qmlimages/Gears.svg")
164 function showVehicleConfigParametersPage() {
166 toolDrawerLoader.item.showParametersPanel()
169 function showKnownVehicleComponentConfigPage(knownVehicleComponent) {
171 let vehicleComponent = globals.activeVehicle.autopilotPlugin.findKnownVehicleComponent(knownVehicleComponent)
172 if (vehicleComponent) {
173 toolDrawerLoader.item.showVehicleComponentPanel(vehicleComponent)
177 function showSettingsTool(settingsPage = "") {
178 showTool(qsTr("Application Settings"), "qrc:/qml/QGroundControl/Controls/AppSettings.qml", "/res/QGCLogoWhite")
179 if (settingsPage !== "") {
180 toolDrawerLoader.item.showSettingsPage(settingsPage)
184 //-------------------------------------------------------------------------
185 //-- Global simple message dialog
187 function _showMessageDialogWorker(owner, dialogTitle, dialogText, buttons = Dialog.Ok, acceptFunction = null, closeFunction = null, bypassNavigationCheck = false) {
188 let dialog = simpleMessageDialogComponent.createObject(owner, { title: dialogTitle, text: dialogText, buttons: buttons, acceptFunction: acceptFunction, closeFunction: closeFunction, bypassNavigationCheck: bypassNavigationCheck })
192 // This variant is only meant to be called by QGCApplication
193 function _showMessageDialog(dialogTitle, dialogText) {
194 _showMessageDialogWorker(mainWindow, dialogTitle, dialogText)
198 target: QGroundControl
200 function onShowMessageDialogRequested(owner, title, text, buttons, acceptFunction, closeFunction) {
201 _showMessageDialogWorker(owner, title, text, buttons, acceptFunction, closeFunction)
206 id: simpleMessageDialogComponent
208 QGCSimpleMessageDialog {
212 property bool _forceClose: false
213 property bool suppressCriticalVehicleMessages: false
215 function finishCloseProcess() {
217 // For some reason on the Qml side Qt doesn't automatically disconnect a signal when an object is destroyed.
218 // So we have to do it ourselves otherwise the signal flows through on app shutdown to an object which no longer exists.
219 firstRunPromptManager.clearNextPromptSignal()
220 QGroundControl.linkManager.shutdown()
221 QGroundControl.videoManager.stopVideo();
225 // Check for things which should prevent the app from closing
226 // Returns true if it is OK to close
227 readonly property int _skipUnsavedMissionCheckMask: 0x01
228 readonly property int _skipPendingParameterWritesCheckMask: 0x02
229 readonly property int _skipActiveConnectionsCheckMask: 0x04
230 property int _closeChecksToSkip: 0
231 property bool _reentrantCloseGuard: false
232 function performCloseChecks() {
233 if (!(_closeChecksToSkip & _skipUnsavedMissionCheckMask) && !checkForUnsavedMission()) {
236 if (!(_closeChecksToSkip & _skipPendingParameterWritesCheckMask) && !checkForPendingParameterWrites()) {
239 if (!(_closeChecksToSkip & _skipActiveConnectionsCheckMask) && !checkForActiveConnections()) {
246 function checkForUnsavedMission() {
247 // Only warn when edits are neither saved to disk nor uploaded to the vehicle.
248 // If either happened the edits are recoverable, so closing loses nothing.
249 // With no active vehicle an upload can't have happened, so treat the plan as
250 // not uploaded regardless of dirtyForUpload.
251 if (planView._planMasterController.dirtyForSave &&
252 (planView._planMasterController.dirtyForUpload || !QGroundControl.multiVehicleManager.activeVehicle)) {
254 _reentrantCloseGuard = true
255 _showMessageDialogWorker(mainWindow, qsTr("Unsaved Mission"),
256 qsTr("You have a mission edit in progress which has not been saved/uploaded. If you close you will lose changes. Are you sure you want to close?"),
257 Dialog.Yes | Dialog.No,
258 function() { accepted = true; _closeChecksToSkip |= _skipUnsavedMissionCheckMask; performCloseChecks() },
259 function() { if (!accepted) _reentrantCloseGuard = false },
260 true /* bypassNavigationCheck */)
267 function checkForPendingParameterWrites() {
268 for (var index=0; index<QGroundControl.multiVehicleManager.vehicles.count; index++) {
269 if (QGroundControl.multiVehicleManager.vehicles.get(index).parameterManager.pendingWrites) {
271 _reentrantCloseGuard = true
272 _showMessageDialogWorker(mainWindow, qsTr("Pending Parameter Updates"),
273 qsTr("You have pending parameter updates to a vehicle. If you close you will lose changes. Are you sure you want to close?"),
274 Dialog.Yes | Dialog.No,
275 function() { accepted = true; _closeChecksToSkip |= _skipPendingParameterWritesCheckMask; performCloseChecks() },
276 function() { if (!accepted) _reentrantCloseGuard = false },
277 true /* bypassNavigationCheck */)
284 function checkForActiveConnections() {
285 if (QGroundControl.multiVehicleManager.activeVehicle) {
287 _reentrantCloseGuard = true
288 _showMessageDialogWorker(mainWindow, qsTr("Active Vehicle Connections"),
289 qsTr("There are still active connections to vehicles. Are you sure you want to exit?"),
290 Dialog.Yes | Dialog.No,
291 function() { accepted = true; _closeChecksToSkip |= _skipActiveConnectionsCheckMask; performCloseChecks() },
292 function() { if (!accepted) _reentrantCloseGuard = false },
293 true /* bypassNavigationCheck */)
300 onClosing: (close) => {
302 if (_reentrantCloseGuard) {
303 close.accepted = false
306 _closeChecksToSkip = 0
307 close.accepted = performCloseChecks()
311 background: Rectangle {
313 color: QGroundControl.globalPalette.window
316 // Disabled under the tool drawer: pointer handlers (e.g. GeoMap DragHandler) still get presses through it and steal drags
319 objectName: "mainView_fly"
321 enabled: !toolDrawer.visible
326 objectName: "mainView_plan"
329 enabled: !toolDrawer.visible
332 footer: LogReplayStatusBar {
333 visible: QGroundControl.settingsManager.flyViewSettings.showLogReplayStatusBar.rawValue
337 id: showTouchAreasNotification
338 title: qsTr("Debug Touch Areas")
339 text: qsTr("Touch Area display toggled")
340 buttons: MessageDialog.Ok
344 id: advancedModeOnConfirmation
345 title: qsTr("Advanced Mode")
346 text: QGroundControl.corePlugin.showAdvancedUIMessage
347 buttons: MessageDialog.Yes | MessageDialog.No
348 onButtonClicked: function (button, role) {
349 if (button === MessageDialog.Yes) {
350 QGroundControl.corePlugin.showAdvancedUI = true
356 id: advancedModeOffConfirmation
357 title: qsTr("Advanced Mode")
358 text: qsTr("Turn off Advanced Mode?")
359 buttons: MessageDialog.Yes | MessageDialog.No
360 onButtonClicked: function (button, role) {
361 if (button === MessageDialog.Yes) {
362 QGroundControl.corePlugin.showAdvancedUI = false
367 function showToolSelectDialog() {
368 if (mainWindow.allowViewSwitch()) {
369 mainWindow.showIndicatorDrawer(toolSelectComponent, null)
373 // Toast notification shown when a view switch is blocked by a validation error
375 id: validationErrorToast
376 x: (mainWindow.width - width) / 2
377 y: mainWindow.height - height - ScreenTools.defaultFontPixelHeight * 3
379 closePolicy: Popup.NoAutoClose
380 text: qsTr("Please correct the invalid value before continuing")
382 background: Rectangle {
383 color: qgcPal.alertBackground
384 radius: ScreenTools.defaultFontPixelWidth / 2
387 contentItem: QGCLabel {
388 text: validationErrorToast.text
389 color: qgcPal.alertText
394 id: toolSelectComponent
402 objectName: "mainView_toolDrawer"
407 property var backIcon
408 property string toolTitle
409 property alias toolSource: toolDrawerLoader.source
410 property var toolIcon
413 if (!toolDrawer.visible) {
414 toolDrawerLoader.source = ""
418 // This need to block click event leakage to underlying map.
424 id: toolDrawerToolbar
425 anchors.left: parent.left
426 anchors.right: parent.right
427 anchors.top: parent.top
428 height: ScreenTools.toolbarHeight
429 color: qgcPal.toolbarBackground
432 id: toolDrawerToolbarLayout
433 anchors.leftMargin: ScreenTools.defaultFontPixelWidth
434 anchors.left: parent.left
435 anchors.top: parent.top
436 anchors.bottom: parent.bottom
437 spacing: ScreenTools.defaultFontPixelWidth
441 objectName: "toolbar_qgcLogo"
442 height: parent.height
443 icon.source: "/res/QGCLogoFull.svg"
445 onClicked: mainWindow.showToolSelectDialog()
449 id: toolbarDrawerText
450 text: toolDrawer.toolTitle
451 font.pointSize: ScreenTools.largeFontPointSize
458 anchors.left: parent.left
459 anchors.right: parent.right
460 anchors.top: toolDrawerToolbar.bottom
461 anchors.bottom: parent.bottom
465 //-------------------------------------------------------------------------
466 //-- Critical Vehicle Message Popup
468 function showCriticalVehicleMessage(message) {
469 if (suppressCriticalVehicleMessages) {
472 if (criticalVehicleMessagePopup.visible) {
473 // Once a message is held back, later ones are too so the shown messages stay in order
474 if (!criticalVehicleMessagePopup.additionalCriticalMessagesReceived && criticalVehicleMessagePopup.appendMessageIfRoom(message)) {
475 criticalVehicleMessageDismissTimer.restart()
476 } else if (!criticalVehicleMessagePopup.additionalCriticalMessagesReceived) {
477 // When the user closes the popup drop the message indicator tool so they can see the rest.
478 criticalVehicleMessagePopup.additionalCriticalMessagesReceived = true
479 // Leave time to act on the new "Click to see more" prompt
480 criticalVehicleMessageDismissTimer.restart()
482 } else if (QGroundControl.videoManager.fullScreen) {
483 criticalVehicleMessagePopup.additionalCriticalMessagesReceived = true
485 criticalVehicleMessagePopup.criticalVehicleMessage = message
486 criticalVehicleMessagePopup.shownMessageCount = 1
487 criticalVehicleMessagePopup.additionalCriticalMessagesReceived = false
488 criticalVehicleMessagePopup.open()
492 // No focus and no Escape handler: either would steal keys from whatever the user is typing in.
494 id: criticalVehicleMessagePopup
495 objectName: "criticalVehicleMessage_popup"
496 y: ScreenTools.toolbarHeight + ScreenTools.defaultFontPixelHeight - topInset
497 x: Math.round((mainWindow.width - width) * 0.5)
498 width: mainWindow.width * 0.55
499 height: criticalVehicleMessageText.contentHeight + _chromeHeight
500 topInset: vehicleWarningHeading.height / 2
501 topPadding: padding + topInset
503 closePolicy: Popup.CloseOnPressOutside
505 property alias criticalVehicleMessage: criticalVehicleMessageText.text
506 property bool additionalCriticalMessagesReceived: false
507 property int shownMessageCount: 0
508 readonly property int maxShownMessages: 5
510 readonly property real _chromeHeight: topInset + ScreenTools.defaultFontPixelHeight
511 readonly property real _maxHeight: mainWindow.height - y - ScreenTools.defaultFontPixelHeight
513 function appendMessageIfRoom(message) {
514 if (shownMessageCount >= maxShownMessages) {
517 const previousMessages = criticalVehicleMessage
518 criticalVehicleMessage += "<br/>" + message
519 if (criticalVehicleMessageText.contentHeight + _chromeHeight > _maxHeight) {
520 criticalVehicleMessage = previousMessages
527 function acknowledge() {
529 if (additionalCriticalMessagesReceived) {
530 additionalCriticalMessagesReceived = false
531 flyView.dropMainStatusIndicatorTool()
535 background: Rectangle {
536 color: qgcPal.alertBackground
537 radius: ScreenTools.defaultFontPixelHeight * 0.5
538 border.color: qgcPal.alertBorder
542 id: vehicleWarningHeading
543 objectName: "criticalVehicleMessage_heading"
544 anchors.horizontalCenter: parent.horizontalCenter
545 anchors.top: parent.top
546 anchors.topMargin: -(height / 2)
547 color: qgcPal.alertBackground
548 radius: ScreenTools.defaultFontPixelHeight * 0.25
549 border.color: qgcPal.alertBorder
551 width: Math.min(vehicleWarningLabel.implicitWidth + _margins, parent.width - ScreenTools.defaultFontPixelHeight)
552 height: vehicleWarningLabel.contentHeight + _margins
554 property real _margins: ScreenTools.defaultFontPixelHeight * 0.25
557 id: vehicleWarningLabel
558 anchors.centerIn: parent
559 width: parent.width - parent._margins
560 horizontalAlignment: Text.AlignHCenter
561 elide: Text.ElideRight
562 text: criticalVehicleMessagePopup.additionalCriticalMessagesReceived ?
563 qsTr("Vehicle Alert - Click to see more") :
564 qsTr("Vehicle Alert")
565 font.pointSize: ScreenTools.smallFontPointSize
566 color: qgcPal.alertText
570 // Extends over the heading's overhang so clicking the heading acknowledges too
573 anchors.topMargin: -criticalVehicleMessagePopup.topInset
574 onClicked: criticalVehicleMessagePopup.acknowledge()
579 id: criticalVehicleMessageText
580 objectName: "criticalVehicleMessage_text"
581 width: criticalVehicleMessagePopup.width - ScreenTools.defaultFontPixelHeight
582 anchors.centerIn: parent
583 wrapMode: Text.WordWrap
584 color: qgcPal.alertText
585 textFormat: TextEdit.RichText
588 // Plain close, not acknowledge(): a timeout must not drop the status indicator drawer.
590 id: criticalVehicleMessageDismissTimer
591 objectName: "criticalVehicleMessage_dismissTimer"
593 running: criticalVehicleMessagePopup.visible
594 onTriggered: criticalVehicleMessagePopup.close()
598 //-------------------------------------------------------------------------
599 //-- Indicator Drawer
601 function showIndicatorDrawer(drawerComponent, indicatorItem) {
602 indicatorDrawer.sourceComponent = drawerComponent
603 indicatorDrawer.indicatorItem = indicatorItem
604 indicatorDrawer.open()
607 function closeIndicatorDrawer() {
608 indicatorDrawer.close()
611 // Fires before the active vehicle is cleared, so drawer contents never see it go null
613 target: QGroundControl.multiVehicleManager
614 function onActiveVehicleAvailableChanged(activeVehicleAvailable) {
615 if (!activeVehicleAvailable) {
616 closeIndicatorDrawer()
624 y: ScreenTools.toolbarHeight + _margins
629 padding: _margins * 2
633 closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside
635 property var sourceComponent
636 property var indicatorItem
638 property bool _expanded: false
639 property real _margins: ScreenTools.defaultFontPixelHeight / 4
640 property bool _fillWindow: indicatorDrawerLoader.item ? indicatorDrawerLoader.item.fillWindow === true : false
642 function calcXPosition() {
647 var xCenter = indicatorItem.mapToItem(mainWindow.contentItem, indicatorItem.width / 2, 0).x
648 return Math.max(_margins, Math.min(xCenter - (contentItem.implicitWidth / 2), mainWindow.contentItem.width - contentItem.implicitWidth - _margins - (indicatorDrawer.padding * 2) - (ScreenTools.defaultFontPixelHeight / 2)))
656 indicatorDrawerLoader.sourceComponent = indicatorDrawer.sourceComponent
660 indicatorItem = undefined
661 indicatorDrawerLoader.sourceComponent = undefined
668 color: QGroundControl.globalPalette.window
669 radius: indicatorDrawer._margins
674 objectName: "indicatorDrawerExpandButton"
675 anchors.horizontalCenter: backgroundRect.right
676 anchors.verticalCenter: backgroundRect.top
677 width: ScreenTools.largeFontPixelHeight
680 color: QGroundControl.globalPalette.button
681 border.color: QGroundControl.globalPalette.buttonText
682 visible: indicatorDrawerLoader.item && indicatorDrawerLoader.item._showExpand && !indicatorDrawer._expanded
685 anchors.centerIn: parent
687 color: QGroundControl.globalPalette.buttonText
692 onClicked: indicatorDrawer._expanded = true
697 contentItem: QGCFlickable {
698 id: indicatorDrawerLoaderFlickable
699 implicitWidth: indicatorDrawer._fillWindow ? _availableWidth : Math.min(_availableWidth, indicatorDrawerLoader.width)
700 implicitHeight: indicatorDrawer._fillWindow ? _availableHeight : Math.min(_availableHeight, indicatorDrawerLoader.height)
701 contentWidth: indicatorDrawerLoader.width
702 contentHeight: indicatorDrawerLoader.height
704 property real _availableWidth: mainWindow.contentItem.width - (2 * indicatorDrawer._margins) - (indicatorDrawer.padding * 2)
705 property real _availableHeight: mainWindow.contentItem.height - ScreenTools.toolbarHeight - (2 * indicatorDrawer._margins) - (indicatorDrawer.padding * 2)
708 id: indicatorDrawerLoader
709 objectName: "indicatorDrawerLoader"
710 width: indicatorDrawer._fillWindow ? indicatorDrawerLoaderFlickable.width : undefined
713 target: indicatorDrawerLoader.item
715 value: indicatorDrawer._expanded
719 target: indicatorDrawerLoader.item
721 value: indicatorDrawer
727 // Analyze page items (both in-panel and popped-out windows) are created with mainWindow as their
728 // QObject parent so their lifetime is not tied to AnalyzeView. This lets a popped-out window
729 // survive AnalyzeView being unloaded from the tool drawer.
731 // Tracks the analyze page item currently shown inside AnalyzeView's panel (not popped out).
732 // null when no page is loaded or the item has been handed off to a popup window.
733 property var _inPanelAnalyzePage: null
735 // Called by AnalyzeView.Component.onDestruction to destroy the in-panel item while
736 // panelContainer is still alive.
737 function destroyInPanelAnalyzePage() {
738 if (_inPanelAnalyzePage) {
739 _inPanelAnalyzePage.destroy()
740 _inPanelAnalyzePage = null
744 // Called by AnalyzeView to create an analyze page item owned by mainWindow.
745 // The caller sets the visual parent to panelContainer after creation.
746 function createAnalyzePage(source) {
747 if (_inPanelAnalyzePage) {
748 _inPanelAnalyzePage.destroy()
749 _inPanelAnalyzePage = null
751 var component = Qt.createComponent(source)
752 if (component.status !== Component.Ready) {
753 console.warn("createAnalyzePage failed source:", source, "errorString:", component.errorString())
756 _inPanelAnalyzePage = component.createObject(mainWindow)
757 return _inPanelAnalyzePage
760 // Called by AnalyzeView when the in-panel item is handed off to a popup window.
761 // Clears _inPanelAnalyzePage so destroyInPanelAnalyzePage() does not destroy it
762 // when AnalyzeView is torn down.
763 function analyzePageMovedToPopup() {
764 _inPanelAnalyzePage = null
767 function createWindowedAnalyzePage(title, source, requiresVehicle, existingItem) {
768 var windowedPage = windowedAnalyzePage.createObject(mainWindow)
769 windowedPage.title = title
770 windowedPage.requiresVehicle = requiresVehicle
772 windowedPage.adoptItem(existingItem)
774 windowedPage.source = source
776 windowedPage.visible = true
780 id: windowedAnalyzePage
783 width: ScreenTools.defaultFontPixelWidth * 100
784 height: ScreenTools.defaultFontPixelHeight * 40
787 property alias source: loader.source
788 property bool requiresVehicle: false
790 function adoptItem(item) {
791 loader.visible = false
793 item.parent = contentRect
794 item.anchors.fill = contentRect
800 target: QGroundControl.multiVehicleManager
801 function onActiveVehicleChanged() {
802 if (requiresVehicle) {
810 color: QGroundControl.globalPalette.window
816 onLoaded: item.popped = true
822 // Destroy any reparented children (not owned by loader)
823 for (var i = contentRect.children.length - 1; i >= 0; i--) {
824 var child = contentRect.children[i]
825 if (child !== loader) {
830 Qt.callLater(destroy)