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.windowTransparentText
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.windowTransparentText
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.windowTransparentText
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 }
165
166 Component {
167 id: overallStatusIndicatorPage
168
169 ToolIndicatorPage {
170 showExpand: true
171 waitForParameters: false
172 expandedComponentWaitForParameters: true
173 contentComponent: mainStatusContentComponent
174 expandedComponent: mainStatusExpandedComponent
175 }
176 }
177
178 Component {
179 id: mainStatusContentComponent
180
181 ColumnLayout {
182 id: mainLayout
183 spacing: _spacing
184
185 property bool parametersReady: QGroundControl.multiVehicleManager.parameterReadyVehicleAvailable
186
187 RowLayout {
188 spacing: ScreenTools.defaultFontPixelWidth
189 visible: parametersReady
190
191 QGCDelayButton {
192 enabled: _armed || !_healthAndArmingChecksSupported || _activeVehicle.healthAndArmingCheckReport.canArm
193 text: _armed ? qsTr("Disarm") : (control._allowForceArm ? qsTr("Force Arm") : qsTr("Arm"))
194
195 onActivated: {
196 if (_armed) {
197 _activeVehicle.armed = false
198 } else {
199 if (_allowForceArm) {
200 _allowForceArm = false
201 _activeVehicle.forceArm()
202 } else {
203 _activeVehicle.armed = true
204 }
205 }
206 mainWindow.closeIndicatorDrawer()
207 }
208 }
209
210 LabelledComboBox {
211 id: primaryLinkCombo
212 Layout.alignment: Qt.AlignTop
213 label: qsTr("Primary Link")
214 alternateText: _primaryLinkName
215 visible: _activeVehicle && _activeVehicle.vehicleLinkManager.linkNames.length > 1
216
217 property var _rgLinkNames: _activeVehicle ? _activeVehicle.vehicleLinkManager.linkNames : [ ]
218 property var _rgLinkStatus: _activeVehicle ? _activeVehicle.vehicleLinkManager.linkStatuses : [ ]
219 property string _primaryLinkName: _activeVehicle ? _activeVehicle.vehicleLinkManager.primaryLinkName : ""
220
221 function updateComboModel() {
222 let linkModel = []
223 for (let i = 0; i < _rgLinkNames.length; i++) {
224 let linkStatus = _rgLinkStatus[i]
225 linkModel.push(_rgLinkNames[i] + (linkStatus === "" ? "" : " " + _rgLinkStatus[i]))
226 }
227 primaryLinkCombo.model = linkModel
228 primaryLinkCombo.currentIndex = -1
229 }
230
231 Component.onCompleted: updateComboModel()
232 on_RgLinkNamesChanged: updateComboModel()
233 on_RgLinkStatusChanged: updateComboModel()
234
235 onActivated: (index) => {
236 _activeVehicle.vehicleLinkManager.primaryLinkName = _rgLinkNames[index]; currentIndex = -1
237 mainWindow.closeIndicatorDrawer()
238 }
239 }
240 }
241
242 SettingsGroupLayout {
243 //Layout.fillWidth: true
244 heading: qsTr("Vehicle Messages")
245
246 VehicleMessageList {
247 id: vehicleMessageList
248 visible: !noMessages
249 }
250
251 QGCLabel {
252 text: qsTr("No new vehicle messages")
253 visible: vehicleMessageList.noMessages
254 }
255 }
256
257 SettingsGroupLayout {
258 //Layout.fillWidth: true
259 heading: qsTr("Sensor Status")
260 visible: parametersReady && !_healthAndArmingChecksSupported
261
262 GridLayout {
263 rowSpacing: _spacing
264 columnSpacing: _spacing
265 rows: _activeVehicle.sysStatusSensorInfo.sensorNames.length
266 flow: GridLayout.TopToBottom
267
268 Repeater {
269 model: _activeVehicle.sysStatusSensorInfo.sensorNames
270 QGCLabel { text: modelData }
271 }
272
273 Repeater {
274 model: _activeVehicle.sysStatusSensorInfo.sensorStatus
275 QGCLabel { text: modelData }
276 }
277 }
278 }
279
280 SettingsGroupLayout {
281 //Layout.fillWidth: true
282 heading: qsTr("Overall Status")
283 visible: parametersReady && _healthAndArmingChecksSupported && _activeVehicle.healthAndArmingCheckReport.problemsForCurrentMode.count > 0
284
285 // List health and arming checks
286 Repeater {
287 model: _activeVehicle ? _activeVehicle.healthAndArmingCheckReport.problemsForCurrentMode : null
288 delegate: listdelegate
289 }
290 }
291
292 Component {
293 id: listdelegate
294
295 Column {
296 Row {
297 spacing: ScreenTools.defaultFontPixelHeight
298
299 QGCLabel {
300 id: message
301 text: object.message
302 textFormat: TextEdit.RichText
303 color: object.severity == 'error' ? qgcPal.colorRed : object.severity == 'warning' ? qgcPal.colorOrange : qgcPal.text
304 MouseArea {
305 anchors.fill: parent
306 onClicked: {
307 if (object.description != "")
308 object.expanded = !object.expanded
309 }
310 }
311 }
312
313 QGCColoredImage {
314 id: arrowDownIndicator
315 anchors.verticalCenter: parent.verticalCenter
316 height: 1.5 * ScreenTools.defaultFontPixelWidth
317 width: height
318 source: "/qmlimages/arrow-down.png"
319 color: qgcPal.text
320 visible: object.description != ""
321 MouseArea {
322 anchors.fill: parent
323 onClicked: object.expanded = !object.expanded
324 }
325 }
326 }
327
328 QGCLabel {
329 id: description
330 text: object.description
331 textFormat: TextEdit.RichText
332 clip: true
333 visible: object.expanded
334
335 property var fact: null
336
337 onLinkActivated: (link) => {
338 if (link.startsWith('param://')) {
339 var paramName = link.substr(8);
340 fact = controller.getParameterFact(-1, paramName, true)
341 if (fact != null) {
342 paramEditorDialogFactory.open()
343 }
344 } else {
345 Qt.openUrlExternally(link);
346 }
347 }
348
349 FactPanelController {
350 id: controller
351 }
352
353 QGCPopupDialogFactory {
354 id: paramEditorDialogFactory
355
356 dialogComponent: paramEditorDialogComponent
357 }
358
359 Component {
360 id: paramEditorDialogComponent
361
362 ParameterEditorDialog {
363 title: qsTr("Edit Parameter")
364 fact: description.fact
365 destroyOnClose: true
366 }
367 }
368 }
369 }
370 }
371 }
372 }
373
374 Component {
375 id: mainStatusExpandedComponent
376
377 ColumnLayout {
378 Layout.preferredWidth: ScreenTools.defaultFontPixelWidth * 60
379 spacing: margins / 2
380
381 property real margins: ScreenTools.defaultFontPixelHeight
382
383 Loader {
384 Layout.fillWidth: true
385 source: _activeVehicle.expandedToolbarIndicatorSource("MainStatus")
386 }
387
388 SettingsGroupLayout {
389 Layout.fillWidth: true
390 heading: qsTr("Force Arm")
391 headingDescription: qsTr("Force arming bypasses pre-arm checks. Use with caution.")
392 visible: _activeVehicle && !_armed
393
394 QGCCheckBoxSlider {
395 Layout.fillWidth: true
396 text: qsTr("Allow Force Arm")
397 checked: false
398 onClicked: _allowForceArm = true
399 }
400 }
401
402 SettingsGroupLayout {
403 Layout.fillWidth: true
404 visible: QGroundControl.corePlugin.showAdvancedUI
405
406 GridLayout {
407 columns: 2
408 rowSpacing: ScreenTools.defaultFontPixelHeight / 2
409 columnSpacing: ScreenTools.defaultFontPixelWidth *2
410 Layout.fillWidth: true
411
412 QGCLabel { Layout.fillWidth: true; text: qsTr("Vehicle Parameters") }
413 QGCButton {
414 text: qsTr("Configure")
415 onClicked: {
416 mainWindow.showVehicleConfigParametersPage()
417 mainWindow.closeIndicatorDrawer()
418 }
419 }
420
421 QGCLabel { Layout.fillWidth: true; text: qsTr("Vehicle Configuration") }
422 QGCButton {
423 text: qsTr("Configure")
424 onClicked: {
425 mainWindow.showVehicleConfig()
426 mainWindow.closeIndicatorDrawer()
427 }
428 }
429 }
430 }
431 }
432 }
433}