QGroundControl
Ground Control Station for MAVLink Drones
Loading...
Searching...
No Matches
MainStatusIndicator.qml
Go to the documentation of this file.
1import QtQuick
2import QtQuick.Layouts
3
4import QGroundControl
5import QGroundControl.Controls
6
7RowLayout {
8 id: control
9 spacing: ScreenTools.defaultFontPixelWidth
10
11 property var _activeVehicle: QGroundControl.multiVehicleManager.activeVehicle
12 property bool _armed: _activeVehicle ? _activeVehicle.armed : false
13 property real _margins: ScreenTools.defaultFontPixelWidth
14 property real _spacing: ScreenTools.defaultFontPixelWidth / 2
15 property bool _allowForceArm: false
16 property bool _healthAndArmingChecksSupported: _activeVehicle ? _activeVehicle.healthAndArmingCheckReport.supported : false
17 property bool _vehicleFlies: _activeVehicle ? _activeVehicle.airShip || _activeVehicle.fixedWing || _activeVehicle.vtol || _activeVehicle.multiRotor : false
18 property var _vehicleInAir: _activeVehicle ? _activeVehicle.flying || _activeVehicle.landing : false
19 property bool _vtolInFWDFlight: _activeVehicle ? _activeVehicle.vtolInFwdFlight : false
20
21 function dropMainStatusIndicator() {
22 let overallStatusComponent = _activeVehicle ? overallStatusIndicatorPage : overallStatusOfflineIndicatorPage
23 mainWindow.showIndicatorDrawer(overallStatusComponent, control)
24 }
25
26 QGCPalette { id: qgcPal }
27
28 QGCLabel {
29 id: mainStatusLabel
30 Layout.fillHeight: true
31 Layout.preferredWidth: contentWidth + (vehicleMessagesIcon.visible ? vehicleMessagesIcon.width + control.spacing : 0)
32 verticalAlignment: Text.AlignVCenter
33 text: mainStatusText()
34 color: qgcPal.text
35 font.pointSize: ScreenTools.largeFontPointSize
36
37 property string _commLostText: qsTr("Comms Lost")
38 property string _readyToFlyText: qsTr("Ready")
39 property string _notReadyToFlyText: qsTr("Not Ready")
40 property string _disconnectedText: qsTr("Disconnected - Click to manually connect")
41 property string _armedText: qsTr("Armed")
42 property string _flyingText: qsTr("Flying")
43 property string _landingText: qsTr("Landing")
44
45 function mainStatusText() {
46 var statusText
47 if (_activeVehicle) {
48 if (_communicationLost) {
49 _mainStatusBGColor = "red"
50 return mainStatusLabel._commLostText
51 }
52 if (_activeVehicle.armed) {
53 _mainStatusBGColor = "green"
54
55 if (_healthAndArmingChecksSupported) {
56 if (_activeVehicle.healthAndArmingCheckReport.canArm) {
57 if (_activeVehicle.healthAndArmingCheckReport.hasWarningsOrErrors) {
58 _mainStatusBGColor = "yellow"
59 }
60 } else {
61 _mainStatusBGColor = "red"
62 }
63 }
64
65 if (_activeVehicle.flying) {
66 return mainStatusLabel._flyingText
67 } else if (_activeVehicle.landing) {
68 return mainStatusLabel._landingText
69 } else {
70 return mainStatusLabel._armedText
71 }
72 } else {
73 if (_healthAndArmingChecksSupported) {
74 if (_activeVehicle.healthAndArmingCheckReport.canArm) {
75 if (_activeVehicle.healthAndArmingCheckReport.hasWarningsOrErrors) {
76 _mainStatusBGColor = "yellow"
77 } else {
78 _mainStatusBGColor = "green"
79 }
80 return mainStatusLabel._readyToFlyText
81 } else {
82 _mainStatusBGColor = "red"
83 return mainStatusLabel._notReadyToFlyText
84 }
85 } else if (_activeVehicle.readyToFlyAvailable) {
86 if (_activeVehicle.readyToFly) {
87 _mainStatusBGColor = "green"
88 return mainStatusLabel._readyToFlyText
89 } else {
90 _mainStatusBGColor = "yellow"
91 return mainStatusLabel._notReadyToFlyText
92 }
93 } else {
94 // Best we can do is determine readiness based on AutoPilot component setup and health indicators from SYS_STATUS
95 if (_activeVehicle.allSensorsHealthy && _activeVehicle.autopilotPlugin.setupComplete) {
96 _mainStatusBGColor = "green"
97 return mainStatusLabel._readyToFlyText
98 } else {
99 _mainStatusBGColor = "yellow"
100 return mainStatusLabel._notReadyToFlyText
101 }
102 }
103 }
104 } else {
105 _mainStatusBGColor = qgcPal.brandingPurple
106 return mainStatusLabel._disconnectedText
107 }
108 }
109
110 QGCColoredImage {
111 id: vehicleMessagesIcon
112 anchors.verticalCenter: parent.verticalCenter
113 anchors.right: parent.right
114 width: ScreenTools.defaultFontPixelWidth * 2
115 height: width
116 source: "/res/VehicleMessages.png"
117 color: getIconColor()
118 sourceSize.width: width
119 fillMode: Image.PreserveAspectFit
120 visible: _activeVehicle && _activeVehicle.messageCount > 0
121
122 function getIconColor() {
123 let iconColor = qgcPal.text
124 if (_activeVehicle) {
125 if (_activeVehicle.messageTypeWarning) {
126 iconColor = qgcPal.colorOrange
127 } else if (_activeVehicle.messageTypeError) {
128 iconColor = qgcPal.colorRed
129 }
130 }
131 return iconColor
132 }
133 }
134
135 QGCMouseArea {
136 anchors.fill: parent
137 onClicked: dropMainStatusIndicator()
138 }
139 }
140
141 QGCLabel {
142 id: vtolModeLabel
143 Layout.fillHeight: true
144 verticalAlignment: Text.AlignVCenter
145 text: _vtolInFWDFlight ? qsTr("FW(vtol)") : qsTr("MR(vtol)")
146 color: qgcPal.text
147 font.pointSize: _vehicleInAir ? ScreenTools.largeFontPointSize : ScreenTools.defaultFontPointSize
148 visible: _activeVehicle && _activeVehicle.vtol
149
150 QGCMouseArea {
151 anchors.fill: parent
152 onClicked: {
153 if (_vehicleInAir) {
154 mainWindow.showIndicatorDrawer(vtolTransitionIndicatorPage)
155 }
156 }
157 }
158 }
159
160 Component {
161 id: overallStatusOfflineIndicatorPage
162
163 MainStatusIndicatorOfflinePage {
164 Component.onCompleted: mainWindow.suppressCriticalVehicleMessages = true
165 Component.onDestruction: mainWindow.suppressCriticalVehicleMessages = false
166 }
167 }
168
169 Component {
170 id: overallStatusIndicatorPage
171
172 ToolIndicatorPage {
173 showExpand: true
174 waitForParameters: false
175 expandedComponentWaitForParameters: true
176 contentComponent: mainStatusContentComponent
177 expandedComponent: mainStatusExpandedComponent
178
179 Component.onCompleted: mainWindow.suppressCriticalVehicleMessages = true
180 Component.onDestruction: mainWindow.suppressCriticalVehicleMessages = false
181 }
182 }
183
184 Component {
185 id: mainStatusContentComponent
186
187 ColumnLayout {
188 id: mainLayout
189 spacing: _spacing
190
191 property bool parametersReady: QGroundControl.multiVehicleManager.parameterReadyVehicleAvailable
192
193 RowLayout {
194 spacing: ScreenTools.defaultFontPixelWidth
195 visible: parametersReady
196
197 QGCDelayButton {
198 enabled: _armed || !_healthAndArmingChecksSupported || _activeVehicle.healthAndArmingCheckReport.canArm
199 text: _armed ? qsTr("Disarm") : (control._allowForceArm ? qsTr("Force Arm") : qsTr("Arm"))
200
201 onActivated: {
202 if (_armed) {
203 _activeVehicle.armed = false
204 } else {
205 if (_allowForceArm) {
206 _allowForceArm = false
207 _activeVehicle.forceArm()
208 } else {
209 _activeVehicle.armed = true
210 }
211 }
212 mainWindow.closeIndicatorDrawer()
213 }
214 }
215
216 LabelledComboBox {
217 id: primaryLinkCombo
218 Layout.alignment: Qt.AlignTop
219 label: qsTr("Primary Link")
220 alternateText: _primaryLinkName
221 visible: _activeVehicle && _activeVehicle.vehicleLinkManager.linkNames.length > 1
222
223 property var _rgLinkNames: _activeVehicle ? _activeVehicle.vehicleLinkManager.linkNames : [ ]
224 property var _rgLinkStatus: _activeVehicle ? _activeVehicle.vehicleLinkManager.linkStatuses : [ ]
225 property string _primaryLinkName: _activeVehicle ? _activeVehicle.vehicleLinkManager.primaryLinkName : ""
226
227 function updateComboModel() {
228 let linkModel = []
229 for (let i = 0; i < _rgLinkNames.length; i++) {
230 let linkStatus = _rgLinkStatus[i]
231 linkModel.push(_rgLinkNames[i] + (linkStatus === "" ? "" : " " + _rgLinkStatus[i]))
232 }
233 primaryLinkCombo.model = linkModel
234 primaryLinkCombo.currentIndex = -1
235 }
236
237 Component.onCompleted: updateComboModel()
238 on_RgLinkNamesChanged: updateComboModel()
239 on_RgLinkStatusChanged: updateComboModel()
240
241 onActivated: (index) => {
242 _activeVehicle.vehicleLinkManager.primaryLinkName = _rgLinkNames[index]; currentIndex = -1
243 mainWindow.closeIndicatorDrawer()
244 }
245 }
246 }
247
248 SettingsGroupLayout {
249 //Layout.fillWidth: true
250 heading: qsTr("Vehicle Messages")
251
252 VehicleMessageList {
253 id: vehicleMessageList
254 visible: !noMessages
255 }
256
257 QGCLabel {
258 text: qsTr("No new vehicle messages")
259 visible: vehicleMessageList.noMessages
260 }
261 }
262
263 SettingsGroupLayout {
264 //Layout.fillWidth: true
265 heading: qsTr("Sensor Status")
266 visible: parametersReady && !_healthAndArmingChecksSupported
267
268 GridLayout {
269 rowSpacing: _spacing
270 columnSpacing: _spacing
271 rows: _activeVehicle.sysStatusSensorInfo.sensorNames.length
272 flow: GridLayout.TopToBottom
273
274 Repeater {
275 model: _activeVehicle.sysStatusSensorInfo.sensorNames
276 QGCLabel { text: modelData }
277 }
278
279 Repeater {
280 model: _activeVehicle.sysStatusSensorInfo.sensorStatus
281 QGCLabel { text: modelData }
282 }
283 }
284 }
285
286 SettingsGroupLayout {
287 //Layout.fillWidth: true
288 heading: qsTr("Overall Status")
289 visible: parametersReady && _healthAndArmingChecksSupported && _activeVehicle.healthAndArmingCheckReport.problemsForCurrentMode.count > 0
290
291 // List health and arming checks
292 Repeater {
293 model: _activeVehicle ? _activeVehicle.healthAndArmingCheckReport.problemsForCurrentMode : null
294 delegate: listdelegate
295 }
296 }
297
298 Component {
299 id: listdelegate
300
301 Column {
302 Row {
303 spacing: ScreenTools.defaultFontPixelHeight
304
305 QGCLabel {
306 id: message
307 text: object.message
308 textFormat: TextEdit.RichText
309 color: object.severity == 'error' ? qgcPal.colorRed : object.severity == 'warning' ? qgcPal.colorOrange : qgcPal.text
310 MouseArea {
311 anchors.fill: parent
312 onClicked: {
313 if (object.description != "")
314 object.expanded = !object.expanded
315 }
316 }
317 }
318
319 QGCColoredImage {
320 id: arrowDownIndicator
321 anchors.verticalCenter: parent.verticalCenter
322 height: 1.5 * ScreenTools.defaultFontPixelWidth
323 width: height
324 source: "/qmlimages/arrow-down.png"
325 color: qgcPal.text
326 visible: object.description != ""
327 MouseArea {
328 anchors.fill: parent
329 onClicked: object.expanded = !object.expanded
330 }
331 }
332 }
333
334 QGCLabel {
335 id: description
336 text: object.description
337 textFormat: TextEdit.RichText
338 clip: true
339 visible: object.expanded
340
341 property var fact: null
342
343 onLinkActivated: (link) => {
344 if (link.startsWith('param://')) {
345 var paramName = link.substr(8);
346 fact = controller.getParameterFact(-1, paramName, true)
347 if (fact != null) {
348 paramEditorDialogFactory.open()
349 }
350 } else {
351 Qt.openUrlExternally(link);
352 }
353 }
354
355 FactPanelController {
356 id: controller
357 }
358
359 QGCPopupDialogFactory {
360 id: paramEditorDialogFactory
361
362 dialogComponent: paramEditorDialogComponent
363 }
364
365 Component {
366 id: paramEditorDialogComponent
367
368 ParameterEditorDialog {
369 title: qsTr("Edit Parameter")
370 fact: description.fact
371 destroyOnClose: true
372 }
373 }
374 }
375 }
376 }
377 }
378 }
379
380 Component {
381 id: mainStatusExpandedComponent
382
383 ColumnLayout {
384 Layout.preferredWidth: ScreenTools.defaultFontPixelWidth * 60
385 spacing: margins / 2
386
387 property real margins: ScreenTools.defaultFontPixelHeight
388
389 Loader {
390 Layout.fillWidth: true
391 source: _activeVehicle.expandedToolbarIndicatorSource("MainStatus")
392 }
393
394 SettingsGroupLayout {
395 Layout.fillWidth: true
396 heading: qsTr("Force Arm")
397 headingDescription: qsTr("Force arming bypasses pre-arm checks. Use with caution.")
398 visible: _activeVehicle && !_armed
399
400 QGCCheckBoxSlider {
401 Layout.fillWidth: true
402 text: qsTr("Allow Force Arm")
403 checked: false
404 onClicked: _allowForceArm = true
405 }
406 }
407
408 SettingsGroupLayout {
409 Layout.fillWidth: true
410 visible: QGroundControl.corePlugin.showAdvancedUI
411
412 GridLayout {
413 columns: 2
414 rowSpacing: ScreenTools.defaultFontPixelHeight / 2
415 columnSpacing: ScreenTools.defaultFontPixelWidth *2
416 Layout.fillWidth: true
417
418 QGCLabel { Layout.fillWidth: true; text: qsTr("Vehicle Parameters") }
419 QGCButton {
420 text: qsTr("Configure")
421 onClicked: {
422 mainWindow.showVehicleConfigParametersPage()
423 mainWindow.closeIndicatorDrawer()
424 }
425 }
426
427 QGCLabel { Layout.fillWidth: true; text: qsTr("Vehicle Configuration") }
428 QGCButton {
429 text: qsTr("Configure")
430 onClicked: {
431 mainWindow.showVehicleConfig()
432 mainWindow.closeIndicatorDrawer()
433 }
434 }
435 }
436 }
437 }
438 }
439}