Commit 4466d289 authored by Philipp Oettershagen's avatar Philipp Oettershagen

Automated preflight checklist: Initial commit. Note that this requires an...

Automated preflight checklist: Initial commit. Note that this requires an autopilot firmware that writes the respective health flags in the SYS_STATUS mavlink message
parent 95be320c
......@@ -171,6 +171,7 @@
<file alias="APM/BrandImageSub">src/FirmwarePlugin/APM/APMBrandImageSub.png</file>
<file alias="PX4/BrandImage">src/FirmwarePlugin/PX4/PX4BrandImage.png</file>
<file alias="subVehicleArrowOpaque.png">src/FlightMap/Images/sub.png</file>
<file alias="check.svg">resources/check.svg</file>
</qresource>
<qresource prefix="/res">
<file alias="action.svg">resources/action.svg</file>
......
......@@ -87,6 +87,7 @@
<file alias="QGroundControl/Controls/ParameterEditorDialog.qml">src/QmlControls/ParameterEditorDialog.qml</file>
<file alias="QGroundControl/Controls/PlanToolBar.qml">src/PlanView/PlanToolBar.qml</file>
<file alias="QGroundControl/Controls/QGCButton.qml">src/QmlControls/QGCButton.qml</file>
<file alias="QGroundControl/Controls/QGCCheckListItem.qml">src/QmlControls/QGCCheckListItem.qml</file>
<file alias="QGroundControl/Controls/QGCCheckBox.qml">src/QmlControls/QGCCheckBox.qml</file>
<file alias="QGroundControl/Controls/QGCColoredImage.qml">src/QmlControls/QGCColoredImage.qml</file>
<file alias="QGroundControl/Controls/QGCComboBox.qml">src/QmlControls/QGCComboBox.qml</file>
......
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Generator: Adobe Illustrator 19.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg
xmlns:osb="http://www.openswatchbook.org/uri/2009/osb"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
version="1.1"
id="Layer_1"
x="0px"
y="0px"
viewBox="0 0 72 72"
style="enable-background:new 0 0 72 72;"
xml:space="preserve"
inkscape:version="0.91 r13725"
sodipodi:docname="check.svg"><metadata
id="metadata3416"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title /></cc:Work></rdf:RDF></metadata><defs
id="defs3414"><linearGradient
id="linearGradient4141"
osb:paint="solid"><stop
style="stop-color:#ffffff;stop-opacity:1;"
offset="0"
id="stop4143" /></linearGradient><linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4141"
id="linearGradient4145"
x1="48.508473"
y1="58.423729"
x2="79.322032"
y2="58.423729"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.8414091,0,0,2.2407508,-82.18242,-94.289127)" /></defs><sodipodi:namedview
pagecolor="#000000"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1855"
inkscape:window-height="1056"
id="namedview3412"
showgrid="false"
inkscape:zoom="3.2777778"
inkscape:cx="-54.305085"
inkscape:cy="36"
inkscape:window-x="65"
inkscape:window-y="24"
inkscape:window-maximized="1"
inkscape:current-layer="Layer_1" /><style
type="text/css"
id="style3406">
.st0{fill:#66BD59;stroke:#FFFFFF;stroke-width:5;stroke-miterlimit:10;}
.st1{fill:none;stroke:#FFFFFF;stroke-width:5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;}
</style><polyline
class="st1"
points="55.1,19.8 30.2,52.2 16.9,36.5 "
id="polyline3410"
transform="matrix(0.85559226,0,0,0.85559226,5.1269823,8.2041673)"
style="fill:none;stroke:#ffffff;stroke-width:5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10" /><style
id="style3419"
type="text/css">
.st0{fill:none;stroke:#FFFFFF;stroke-width:3;stroke-miterlimit:10;}
.st1{fill:none;stroke:#FFFFFF;stroke-width:8;stroke-miterlimit:10;}
.st2{fill:#FFFFFF;}
</style><circle
style="fill:none;stroke:url(#linearGradient4145);stroke-width:3.25963402;stroke-miterlimit:4;stroke-dasharray:none"
id="path3339"
cx="35.5117"
cy="36.62389"
r="28.370182" /></svg>
\ No newline at end of file
......@@ -504,8 +504,8 @@ QGCView {
z: _panel.z + 4
title: qsTr("Fly")
maxHeight: (_flightVideo.visible ? _flightVideo.y : parent.height) - toolStrip.y
buttonVisible: [ _guidedController.showTakeoff || !_guidedController.showLand, _guidedController.showLand && !_guidedController.showTakeoff, true, true, true, _guidedController.smartShotsAvailable ]
buttonEnabled: [ _guidedController.showTakeoff, _guidedController.showLand, _guidedController.showRTL, _guidedController.showPause, _anyActionAvailable, _anySmartShotAvailable ]
buttonVisible: [ QGroundControl.settingsManager.appSettings.useChecklist.rawValue, _guidedController.showTakeoff || !_guidedController.showLand, _guidedController.showLand && !_guidedController.showTakeoff, true, true, true, _guidedController.smartShotsAvailable ]
buttonEnabled: [ QGroundControl.settingsManager.appSettings.useChecklist.rawValue, _guidedController.showTakeoff, _guidedController.showLand, _guidedController.showRTL, _guidedController.showPause, _anyActionAvailable, _anySmartShotAvailable ]
property bool _anyActionAvailable: _guidedController.showStartMission || _guidedController.showResumeMission || _guidedController.showChangeAlt || _guidedController.showLandAbort
property bool _anySmartShotAvailable: _guidedController.showOrbit
......@@ -551,6 +551,11 @@ QGCView {
]
model: [
{
name: "Checklist",
iconSource: "/qmlimages/check.svg",
dropPanelComponent: checklistDropPanel
},
{
name: _guidedController.takeoffTitle,
iconSource: "/res/takeoff.svg",
......@@ -677,4 +682,292 @@ QGCView {
visible: false
}
}
}
Component {
id: checklistDropPanel
Rectangle {
id: checklist
width: mainColumn.width + (ScreenTools.defaultFontPixelWidth * 4)
height: (headerColumn.height+mainColumn.height) * 1.07
color: qgcPal.windowShade
radius: 20
enabled: QGroundControl.multiVehicleManager.vehicles.count > 0;
onBatPercentRemainingChanged: {if(_initialized) buttonBattery.updateItem();}
onGpsLockChanged: {buttonSensors.updateItem();}
// Connections
Connections {
target: _activeVehicle
onUnhealthySensorsChanged: checklist.onUnhealthySensorsChanged();
}
Connections {
target: QGroundControl.multiVehicleManager
onActiveVehicleChanged: checklist.onActiveVehicleChanged();
onActiveVehicleAvailableChanged: {}
}
Connections {
target: QGroundControl.settingsManager.appSettings.audioMuted
onValueChanged: buttonSoundOutput.updateItem(); //TODO(philippoe): We are binding to a signal which is explicitly marked as "only for QT internal use" here.
}
Component.onCompleted: {
if(QGroundControl.multiVehicleManager.vehicles.count > 0) {
onActiveVehicleChanged();
_initialized=true;
}
}
function updateVehicleDependentItems() {
buttonSensors.updateItem();
buttonBattery.updateItem();
buttonRC.updateItem();
buttonEstimator.updateItem();
}
function onActiveVehicleChanged() {
buttonSoundOutput.updateItem(); // Just updated here for initialization once we connect to a vehicle
onUnhealthySensorsChanged(); // The health states could all have changed - need to update them.
}
function onUnhealthySensorsChanged() {
var unhealthySensorsStr = _activeVehicle.unhealthySensors;
// Set to healthy per default
for(var i=0;i<32;i++) _healthFlags[i]=true;
for(i=0;i<unhealthySensorsStr.length;i++) { // TODO (philippoe): This is terrible, having this data available in the form of a bitfield would be much better than a string list!
switch(unhealthySensorsStr[i]) {
case "Gyro": _healthFlags[0]=false; break;
case "Accelerometer": _healthFlags[1]=false; break;
case "Magnetometer": _healthFlags[2]=false; break;
case "Absolute pressure": _healthFlags[3]=false; break;
case "Differential pressure": _healthFlags[4]=false; break;
case "GPS": _healthFlags[5]=false; break;
case "Optical flow": _healthFlags[6]=false; break;
case "Computer vision position":_healthFlags[7]=false; break;
case "Laser based position": _healthFlags[8]=false; break;
case "External ground truth": _healthFlags[9]=false; break;
case "Angular rate control": _healthFlags[10]=false; break;
case "Attitude stabilization": _healthFlags[11]=false; break;
case "Yaw position": _healthFlags[12]=false; break;
case "Z/altitude control": _healthFlags[13]=false; break;
case "X/Y position control": _healthFlags[14]=false; break;
case "Motor outputs / control": _healthFlags[15]=false; break;
case "RC receiver": _healthFlags[16]=false; break;
case "Gyro 2": _healthFlags[17]=false; break;
case "Accelerometer 2": _healthFlags[18]=false; break;
case "Magnetometer 2": _healthFlags[19]=false; break;
case "GeoFence": _healthFlags[20]=false; break;
case "AHRS": _healthFlags[21]=false; break;
case "Terrain": _healthFlags[22]=false; break;
case "Motors reversed": _healthFlags[23]=false; break;
case "Logging": _healthFlags[24]=false; break;
case "Battery": _healthFlags[25]=false; break;
default:
}
}
updateVehicleDependentItems();
}
Column {
id: headerColumn
x: 2*ScreenTools.defaultFontPixelWidth
y: 2*ScreenTools.defaultFontPixelWidth
width: 320
spacing: 8
// Header/title of checklist
QGCLabel {anchors.horizontalCenter: parent.horizontalCenter ; font.pointSize: ScreenTools.mediumFontPointSize ; text: _activeVehicle ? qsTr("Pre-flight checklist")+" (MAV ID:"+_activeVehicle.id+")" : qsTr("Pre-flight checklist (awaiting vehicle...)");}
Rectangle {anchors.left:parent.left ; anchors.right:parent.right ; height:1 ; color:qgcPal.text}
}
Column {
id: mainColumn
x: 2*ScreenTools.defaultFontPixelWidth
anchors.top:headerColumn.bottom
anchors.topMargin:ScreenTools.defaultFontPixelWidth
width: 320
spacing: 6
enabled : QGroundControl.multiVehicleManager.vehicles.count > 0;
opacity : 0.2+0.8*(QGroundControl.multiVehicleManager.vehicles.count > 0);
// Checklist items: Standard
QGCCheckListItem {
id: buttonHardware
name: "Hardware"
defaulttext: "Props mounted? Wings secured? Tail secured?"
}
QGCCheckListItem {
id: buttonBattery
name: "Battery"
pendingtext: "Healthy & charged > 40%. Battery connector firmly plugged?"
function updateItem() {
if (!_activeVehicle) {
_state = 0;
} else {
if (checklist._healthFlags[25] && batPercentRemaining>=40.0) _state = 1+3*(_nrClicked>0);
else {
if(!checklist._healthFlags[25]) buttonBattery.failuretext="Not healthy. Check console.";
else if(batPercentRemaining<40.0) buttonBattery.failuretext="Low (below 40%). Please recharge.";
buttonBattery._state = 3;
}
}
}
}
QGCCheckListItem {
id: buttonSensors
name: "Sensors"
function updateItem() {
if (!_activeVehicle) {
_state = 0;
} else {
if(checklist._healthFlags[0] &&
checklist._healthFlags[1] &&
checklist._healthFlags[2] &&
checklist._healthFlags[3] &&
checklist._healthFlags[4] &&
checklist._healthFlags[5]) {
if(!gpsLock) {
buttonSensors.pendingtext="Pending. Waiting for GPS lock.";
buttonSensors._state=1;
} else {
_state = 4; // All OK
}
} else {
if(!checklist._healthFlags[0]) failuretext="Failure. Gyroscope issues. Check console.";
else if(!checklist._healthFlags[1]) failuretext="Failure. Accelerometer issues. Check console.";
else if(!checklist._healthFlags[2]) failuretext="Failure. Magnetometer issues. Check console.";
else if(!checklist._healthFlags[3]) failuretext="Failure. Barometer issues. Check console.";
else if(!checklist._healthFlags[4]) failuretext="Failure. Airspeed sensor issues. Check console.";
else if(!checklist._healthFlags[5]) failuretext="Failure. No valid or low quality GPS signal. Check console.";
_state = 3;
}
}
}
}
QGCCheckListItem {
id: buttonRC
name: "Radio Control"
pendingtext: "Receiving signal. Perform range test & confirm."
failuretext: "No signal or invalid autopilot-RC config. Check RC and console."
function updateItem() {
if (!_activeVehicle) {
_state = 0;
} else {
if (_healthFlags[16]) {_state = 1+3*(_nrClicked>0);}
else {_state = 3;}
}
}
}
QGCCheckListItem {
id: buttonEstimator
name: "Global position estimate"
function updateItem() {
if (!_activeVehicle) {
_state = 0;
} else {
if (_healthFlags[21]) {_state = 4;}
else {_state = 3;}
}
}
}
// Arming header
//Rectangle {anchors.left:parent.left ; anchors.right:parent.right ; height:1 ; color:qgcPal.text}
QGCLabel {anchors.horizontalCenter:parent.horizontalCenter ; text:qsTr("<i>Please arm the vehicle here.</i>")}
//Rectangle {anchors.left:parent.left ; anchors.right:parent.right ; height:1 ; color:qgcPal.text}
QGCCheckListItem {
id: buttonActuators
name: "Actuators"
group: 1
defaulttext: "Move all control surfaces. Did they work properly?"
}
QGCCheckListItem {
id: buttonMotors
name: "Motors"
group: 1
defaulttext: "Propellers free? Then throttle up gently. Working properly?"
}
QGCCheckListItem {
id: buttonMission
name: "Mission"
group: 1
defaulttext: "Please confirm mission is valid (waypoints valid, no terrain collision)."
}
QGCCheckListItem {
id: buttonSoundOutput
name: "Sound output"
group: 1
pendingtext: "QGC audio output enabled. System audio output enabled, too?"
failuretext: "Failure, QGC audio output is disabled. Please enable it under application settings->general to hear audio warnings!"
function updateItem() {
if (!_activeVehicle) {
_state = 0;
} else {
if (QGroundControl.settingsManager.appSettings.audioMuted.rawValue) {_state = 3;_nrClicked=0;}
else {_state = 1+3*(_nrClicked>0);}
}
}
}
// Directly before launch header
//Rectangle {anchors.left:parent.left ; anchors.right:parent.right ; height:1 ; color:qgcPal.text}
QGCLabel {anchors.horizontalCenter:parent.horizontalCenter ; text:qsTr("<i>Last preparations before launch</i>") ; opacity : 0.2+0.8*(_checkState >= 2);}
//Rectangle {anchors.left:parent.left ; anchors.right:parent.right ; height:1 ; color:qgcPal.text}
QGCCheckListItem {
id: buttonPayload
name: "Payload"
group: 2
defaulttext: "Configured and started?"
pendingtext: "Payload lid closed?"
}
QGCCheckListItem {
id: buttonWeather
name: "Wind & weather"
group: 2
defaulttext: "OK for your platform?"
pendingtext: "Launching into the wind?"
}
QGCCheckListItem {
id: buttonFlightAreaFree
name: "Flight area"
group: 2
defaulttext: "Launch area and path free of obstacles/people?"
}
} // Column
property bool _initialized:false
property var _healthFlags: []
property int _checkState: _activeVehicle ? (_activeVehicle.armed ? 1 + (buttonActuators._state + buttonMotors._state + buttonMission._state + buttonSoundOutput._state) / 4 / 4 : 0) : 0 ; // Shows progress of checks inside the checklist - unlocks next check steps in groups
property bool gpsLock: _activeVehicle ? _activeVehicle.gps.lock.rawValue>=3 : 0
property var batPercentRemaining: _activeVehicle ? _activeVehicle.battery.getFact("percentRemaining").value : 0
// TODO: Having access to MAVLINK enums (or at least QML consts) would be much cleaner than the code below
property int subsystem_type_gyro : 1
property int subsystem_type_acc : 2
property int subsystem_type_mag : 4
property int subsystem_type_abspressure : 8
property int subsystem_type_diffpressure : 16
property int subsystem_type_gps : 32
property int subsystem_type_positioncontrol : 16384
property int subsystem_type_motorcontrol : 32768
property int subsystem_type_rcreceiver : 65536
property int subsystem_type_ahrs : 2097152
property int subsystem_type_terrain : 4194304
property int subsystem_type_reversemotor : 8388608
property int subsystem_type_logging : 16777216
property int subsystem_type_sensorbattery : 33554432
property int subsystem_type_rangefinder : 67108864
} //Rectangle
} //Component
} //QGC View
......@@ -64,7 +64,7 @@ Item {
}
if (visible) {
visible = false
_dropDownComponent = undefined
//_dropDownComponent = undefined //TODO (philippoe) such that drop down component state is not deleted - check with don gagne whether this is necessary
toolStrip.uncheckAll()
}
}
......
import QtQuick 2.3
import QtQuick.Controls 1.2
import QtQuick.Controls.Styles 1.4
import QGroundControl 1.0
import QGroundControl.Palette 1.0
import QGroundControl.ScreenTools 1.0
QGCButton {
property string name: ""
property int _state: 0
property var _color: qgcPal.button;//qgcPal.windowShade;//qgcPal.windowShadeDark;//Qt.rgba(0.5,0.5,0.5,1) //qgcPal.window;//
property int _nrClicked: 0
property int group: 0
property string defaulttext: "Not checked yet"
property string pendingtext: ""
property string failuretext: "Failure. Check console."
property string _text: qsTr(name)+ ": " + qsTr(defaulttext)
enabled : (_activeVehicle==null || _activeVehicle.connectionLost) ? false : _checkState>=group
opacity : (_activeVehicle==null || _activeVehicle.connectionLost) ? 0.4 : 0.2+0.8*(_checkState >= group);
width: parent.width
style: ButtonStyle {
background: Rectangle {color:_color; border.color: qgcPal.button; radius:3}
label: Label {
text: _text
wrapMode: Text.WordWrap
horizontalAlignment: Text.AlignHCenter
color: _state>0 ? qgcPal.mapWidgetBorderLight : qgcPal.buttonText
}
}
onClicked: {
if(_state<2) _nrClicked=_nrClicked+1; //Only allow click-counter to increase when not failed yet
updateItem();
}
onPendingtextChanged: { if(_state==1) {getTextFromState(); getColorFromState();} }
onFailuretextChanged: { if(_state==3) {getTextFromState(); getColorFromState();} }
on_StateChanged: { getTextFromState(); getColorFromState(); }
// onEnabledChanged: { //Dont do this for now, because if we only accidentially lose connection, we don't want to delete the checklist state. Instead, we'd need to detect a re-connect, maybe based on the timesincesystemstart (i.e. when it decreases)?
// if(enabled==false && group > 0) {
// // Reset all check list items of group > 0 if it is disabled again (which e.g. happens after a vehicle reboot or disarm).
// _nrClicked = 0;
// _state = 0;
// }
// }
function updateItem() {
// This is the default updateFunction. It assumes the item is a MANUAL check list item, i.e. one that
// only requires user clicks (one click if pendingtext="", two clicks otherwise) for completion.
//if(_nrClicked>0) _state = 4;
if(_nrClicked===1) {
if(pendingtext.length === 0) _state = 4;
else _state = 1;
} else if(_nrClicked>1) _state = 4;
getTextFromState();
getColorFromState();
}
function getTextFromState() {
if(_state === 0) {_text= qsTr(name) + ": " + qsTr(defaulttext)} // Not checked yet
else if(_state === 1) {_text= "<b>"+qsTr(name)+"</b>" +": " + qsTr(pendingtext)} // Pending
else if(_state === 2) {_text= "<b>"+qsTr(name)+"</b>" +": " + qsTr("Minor problem")} // Small problem or need further user action to resolve
else if(_state === 3) {_text= "<b>"+qsTr(name)+"</b>" +": " + qsTr(failuretext)} // Big problem
else {_text= "<b>"+qsTr(name)+"</b>" +": " + qsTr("OK")} // All OK
}
function getColorFromState() {
if(_state === 0) {_color=qgcPal.button} // Not checked yet
else if(_state === 1) {_color=Qt.rgba(0.9,0.47,0.2,1)} // Pending
else if(_state === 2) {_color=Qt.rgba(1.0,0.6,0.2,1)} // Small problem or need further user action to resolve
else if(_state === 3) {_color=Qt.rgba(0.92,0.22,0.22,1)} // Big problem
else {_color=Qt.rgba(0.27,0.67,0.42,1)} // All OK
}
}
......@@ -34,6 +34,7 @@ ParameterEditor 1.0 ParameterEditor.qml
ParameterEditorDialog 1.0 ParameterEditorDialog.qml
PlanToolBar 1.0 PlanToolBar.qml
QGCButton 1.0 QGCButton.qml
QGCCheckListItem 1.0 QGCCheckListItem.qml
QGCCheckBox 1.0 QGCCheckBox.qml
QGCColoredImage 1.0 QGCColoredImage.qml
QGCComboBox 1.0 QGCComboBox.qml
......
......@@ -117,6 +117,13 @@
"type": "bool",
"defaultValue": false
},
{
"name": "UseChecklist",
"shortDescription": "Use preflight checklist",
"longDescription": "If this option is enabled the preflight checklist will be used.",
"type": "bool",
"defaultValue": false
},
{
"name": "BaseDeviceFontPointSize",
"shortDescription": "Application font size",
......
......@@ -33,6 +33,7 @@ const char* AppSettings::indoorPaletteName = "StyleIs
const char* AppSettings::showLargeCompassName = "ShowLargeCompass";
const char* AppSettings::savePathName = "SavePath";
const char* AppSettings::autoLoadMissionsName = "AutoLoadMissions";
const char* AppSettings::useChecklistName = "UseChecklist";
const char* AppSettings::mapboxTokenName = "MapboxToken";
const char* AppSettings::esriTokenName = "EsriToken";
const char* AppSettings::defaultFirmwareTypeName = "DefaultFirmwareType";
......@@ -75,6 +76,7 @@ AppSettings::AppSettings(QObject* parent)
, _showLargeCompassFact (NULL)
, _savePathFact (NULL)
, _autoLoadMissionsFact (NULL)
, _useChecklistFact (NULL)
, _mapboxTokenFact (NULL)
, _esriTokenFact (NULL)
, _defaultFirmwareTypeFact (NULL)
......@@ -220,6 +222,15 @@ Fact* AppSettings::audioMuted(void)
return _audioMutedFact;
}
Fact* AppSettings::useChecklist(void)
{
if (!_useChecklistFact) {
_useChecklistFact = _createSettingsFact(useChecklistName);
}
return _useChecklistFact;
}
Fact* AppSettings::appFontPointSize(void)
{
if (!_appFontPointSizeFact) {
......
......@@ -37,6 +37,7 @@ public:
Q_PROPERTY(Fact* showLargeCompass READ showLargeCompass CONSTANT)
Q_PROPERTY(Fact* savePath READ savePath CONSTANT)
Q_PROPERTY(Fact* autoLoadMissions READ autoLoadMissions CONSTANT)
Q_PROPERTY(Fact* useChecklist READ useChecklist CONSTANT)
Q_PROPERTY(Fact* mapboxToken READ mapboxToken CONSTANT)
Q_PROPERTY(Fact* esriToken READ esriToken CONSTANT)
Q_PROPERTY(Fact* defaultFirmwareType READ defaultFirmwareType CONSTANT)
......@@ -75,6 +76,7 @@ public:
Fact* showLargeCompass (void);
Fact* savePath (void);
Fact* autoLoadMissions (void);
Fact* useChecklist (void);
Fact* mapboxToken (void);
Fact* esriToken (void);
Fact* defaultFirmwareType (void);
......@@ -110,6 +112,7 @@ public:
static const char* showLargeCompassName;
static const char* savePathName;
static const char* autoLoadMissionsName;
static const char* useChecklistName;
static const char* mapboxTokenName;
static const char* esriTokenName;
static const char* defaultFirmwareTypeName;
......@@ -160,6 +163,7 @@ private:
SettingsFact* _showLargeCompassFact;
SettingsFact* _savePathFact;
SettingsFact* _autoLoadMissionsFact;
SettingsFact* _useChecklistFact;
SettingsFact* _mapboxTokenFact;
SettingsFact* _esriTokenFact;
SettingsFact* _defaultFirmwareTypeFact;
......
......@@ -411,6 +411,16 @@ QGCView {
}
}
}
//-----------------------------------------------------------------
//-- Checklist Settings
FactCheckBox {
text: qsTr("Use preflight checklist")
fact: _useChecklist
visible: _useChecklist.visible
property Fact _useChecklist: QGroundControl.settingsManager.appSettings.useChecklist
}
}
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment