Commit 2356cc56 authored by Don Gagne's avatar Don Gagne

Allow GenFenceManager to specify QML for fence editor

parent 238e4d19
......@@ -271,9 +271,15 @@
<file alias="APMParameterFactMetaData.Copter.3.4.xml">src/FirmwarePlugin/APM/APMParameterFactMetaData.Copter.3.4.xml</file>
<file alias="APMParameterFactMetaData.Rover.3.0.xml">src/FirmwarePlugin/APM/APMParameterFactMetaData.Rover.3.0.xml</file>
<file alias="APMParameterFactMetaData.Sub.3.4.xml">src/FirmwarePlugin/APM/APMParameterFactMetaData.Sub.3.4.xml</file>
<file alias="CopterGeoFenceEditor.qml">src/FirmwarePlugin/APM/CopterGeoFenceEditor.qml</file>
<file alias="PlaneGeoFenceEditor.qml">src/FirmwarePlugin/APM/PlaneGeoFenceEditor.qml</file>
</qresource>
<qresource prefix="/FirmwarePlugin">
<file alias="GeoFenceEditor.qml">src/FirmwarePlugin/GeoFenceEditor.qml</file>
</qresource>
<qresource prefix="/FirmwarePlugin/PX4">
<file alias="PX4ParameterFactMetaData.xml">src/FirmwarePlugin/PX4/PX4ParameterFactMetaData.xml</file>
<file alias="PX4GeoFenceEditor.qml">src/FirmwarePlugin/PX4/PX4GeoFenceEditor.qml</file>
</qresource>
<qresource prefix="/opengl">
<file>resources/opengl/buglist.json</file>
......
......@@ -593,7 +593,8 @@ size_t FactMetaData::typeToSize(ValueType_t type)
/// Set translators according to app settings
void FactMetaData::_setAppSettingsTranslators(void)
{
if (!_enumStrings.count()) {
// We can only translate between real numbers
if (!_enumStrings.count() && (type() == valueTypeDouble || type() == valueTypeFloat)) {
for (size_t i=0; i<sizeof(_rgAppSettingsTranslations)/sizeof(_rgAppSettingsTranslations[0]); i++) {
const AppSettingsTranslation_s* pAppSettingsTranslation = &_rgAppSettingsTranslations[i];
......
......@@ -314,3 +314,10 @@ bool APMGeoFenceManager::polygonSupported(void) const
return false;
}
QString APMGeoFenceManager::editorQml(void) const
{
return _vehicle->multiRotor() ?
QStringLiteral("qrc:/FirmwarePlugin/APM/CopterGeoFenceEditor.qml") :
QStringLiteral("qrc:/FirmwarePlugin/APM/PlaneGeoFenceEditor.qml");
}
......@@ -33,6 +33,7 @@ public:
float circleRadius (void) const final;
QVariantList params (void) const final { return _params; }
QStringList paramLabels (void) const final { return _paramLabels; }
QString editorQml (void) const final;
private slots:
void _mavlinkMessageReceived(const mavlink_message_t& message);
......
import QtQuick 2.2
import QtQuick.Controls 1.2
import QGroundControl 1.0
import QGroundControl.ScreenTools 1.0
import QGroundControl.Controls 1.0
import QGroundControl.FactControls 1.0
import QGroundControl.Palette 1.0
import QGroundControl.FlightMap 1.0
import QGroundControl.FactSystem 1.0
Column {
id: editorColumn
width: availableWidth
spacing: _margin
//property real availableWidth - Available width for control - Must be passed in from Loader
readonly property real _margin: ScreenTools.defaultFontPixelWidth / 2
readonly property real _editFieldWidth: Math.min(width - _margin * 2, ScreenTools.defaultFontPixelWidth * 15)
QGCLabel {
anchors.left: parent.left
anchors.right: parent.right
wrapMode: Text.WordWrap
text: qsTr("Click in map to set breach return point.")
visible: geoFenceController.breachReturnSupported
}
QGCLabel { text: qsTr("Fence Settings:") }
Rectangle {
anchors.left: parent.left
anchors.right: parent.right
height: 1
color: qgcPal.text
}
QGCLabel {
text: qsTr("Must be connected to Vehicle to change fence settings.")
visible: !QGroundControl.multiVehicleManager.activeVehicle
}
Repeater {
model: geoFenceController.params
Item {
width: editorColumn.width
height: textField.height
QGCLabel {
id: textFieldLabel
anchors.baseline: textField.baseline
text: geoFenceController.paramLabels[index]
}
FactTextField {
id: textField
anchors.right: parent.right
width: _editFieldWidth
showUnits: true
fact: modelData
visible: !comboField.visible
}
FactComboBox {
id: comboField
anchors.right: parent.right
width: _editFieldWidth
indexModel: false
fact: visible ? modelData : _nullFact
visible: modelData.enumStrings.length
property var _nullFact: Fact { }
}
}
}
QGCMapPolygonControls {
anchors.left: parent.left
anchors.right: parent.right
flightMap: editorMap
polygon: root.polygon
sectionLabel: qsTr("Fence Polygon:")
visible: geoFenceController.polygonSupported
}
}
import QtQuick 2.2
import QtQuick.Controls 1.2
import QGroundControl 1.0
import QGroundControl.ScreenTools 1.0
import QGroundControl.Controls 1.0
import QGroundControl.FactControls 1.0
import QGroundControl.Palette 1.0
import QGroundControl.FlightMap 1.0
import QGroundControl.FactSystem 1.0
Column {
id: editorColumn
width: availableWidth
spacing: _margin
//property real availableWidth - Available width for control - Must be passed in from Loader
readonly property real _margin: ScreenTools.defaultFontPixelWidth / 2
readonly property real _editFieldWidth: Math.min(width - _margin * 2, ScreenTools.defaultFontPixelWidth * 15)
property Fact fenceAction: factController.getParameterFact(-1, "FENCE_ACTION")
property Fact fenceMinAlt: factController.getParameterFact(-1, "FENCE_MINALT")
property Fact fenceMaxAlt: factController.getParameterFact(-1, "FENCE_MAXALT")
property Fact fenceRetAlt: factController.getParameterFact(-1, "FENCE_RETALT")
property Fact fenceAutoEnable: factController.getParameterFact(-1, "FENCE_AUTOENABLE")
property Fact fenceRetRally: factController.getParameterFact(-1, "FENCE_RET_RALLY")
FactPanelController {
id: factController
factPanel: qgcView.viewPanel
}
Connections {
target: fenceAction
onValueChanged: actionCombo.recalcSelection()
}
Connections {
target: fenceRetRally
onValueChanged: actionCombo.recalcSelection()
}
QGCLabel { text: qsTr("Fence Settings:") }
Rectangle {
anchors.left: parent.left
anchors.right: parent.right
height: 1
color: qgcPal.text
}
QGCLabel { text: qsTr("Action on fence breach:") }
QGCComboBox {
id: actionCombo
anchors.leftMargin: ScreenTools.defaultFontPixelWidth
anchors.left: parent.left
anchors.right: parent.right
model: ListModel {
id: actionModel
ListElement { text: qsTr("None"); actionValue: 0; retRallyValue: 0 }
ListElement { text: qsTr("Report only"); actionValue: 2; retRallyValue: 0 }
ListElement { text: qsTr("Fly to breach return point"); actionValue: 1; retRallyValue: 0 }
ListElement { text: qsTr("Fly to breach return point (throttle control)"); actionValue: 3; retRallyValue: 0 }
ListElement { text: qsTr("Fly to nearest rally point"); actionValue: 4; retRallyValue: 1 }
}
onActivated: {
fenceAction.value = actionModel.get(index).actionValue
fenceRetRally.value = actionModel.get(index).retRallyValue
}
function recalcSelection() {
if (fenceAction.value != 0 && fenceRetRally.value == 1) {
actionCombo.currentIndex = 4
} else {
switch (fenceAction.value) {
case 0:
actionCombo.currentIndex = 0
break
case 1:
actionCombo.currentIndex = 2
break
case 2:
actionCombo.currentIndex = 1
break
case 3:
actionCombo.currentIndex = 3
break
case 4:
actionCombo.currentIndex = 4
break
case 0:
default:
actionCombo.currentIndex = 0
break
}
}
}
}
Item { width: 1; height: 1 }
QGCCheckBox {
id: minAltFenceCheckBox
text: qsTr("Minimum altitude fence")
checked: fenceMinAlt.value > 0
onClicked: fenceMinAlt.value = checked ? 10 : 0
}
Row {
anchors.margins: ScreenTools.defaultFontPixelWidth
anchors.left: parent.left
spacing: _margin
QGCLabel {
anchors.baseline: fenceAltMinField.baseline
text: qsTr("Min Altitude:")
}
FactTextField {
id: fenceAltMinField
showUnits: true
fact: fenceMinAlt
enabled: minAltFenceCheckBox.checked
width: _editFieldWidth
}
}
Item { width: 1; height: 1 }
QGCCheckBox {
id: maxAltFenceCheckBox
text: qsTr("Maximum altitude fence")
checked: fenceMaxAlt.value > 0
onClicked: fenceMaxAlt.value = checked ? 100 : 0
}
Row {
anchors.margins: ScreenTools.defaultFontPixelWidth
anchors.left: parent.left
spacing: _margin
QGCLabel {
anchors.baseline: fenceAltMaxField.baseline
text: qsTr("Max Altitude:")
}
FactTextField {
id: fenceAltMaxField
showUnits: true
fact: fenceMaxAlt
enabled: maxAltFenceCheckBox.checked
width: _editFieldWidth
}
}
Item { width: 1; height: 1 }
QGCLabel { text: qsTr("Breach return point:") }
QGCLabel {
anchors.margins: ScreenTools.defaultFontPixelWidth
anchors.left: parent.left
anchors.right: parent.right
wrapMode: Text.WordWrap
text: qsTr("Click in map to set breach return location.")
}
Row {
anchors.margins: ScreenTools.defaultFontPixelWidth
anchors.left: parent.left
spacing: _margin
QGCLabel {
anchors.baseline: retAltField.baseline
text: qsTr("Return Alt:")
}
FactTextField {
id: retAltField
showUnits: true
fact: fenceRetAlt
width: _editFieldWidth
}
}
Item { width: 1; height: 1 }
FactCheckBox {
text: qsTr("Auto-Enable after takeoff")
fact: fenceAutoEnable
}
QGCLabel {
anchors.margins: ScreenTools.defaultFontPixelWidth
anchors.left: parent.left
anchors.right: parent.right
wrapMode: Text.WordWrap
font.pointSize: ScreenTools.smallFontPointSize
text: qsTr("If checked, the aircraft will start with the fence disabled. After an autonomous takeoff completes the fences will automatically enable. When the autonomous mission arrives at a landing waypoint the fence automatically disables.")
}
/*
FENCE_ACTION - the action to take on fence breach. This defaults to zero which disables geo-fencing. Set it to 1 to enable geo-fencing and fly to the return point on fence breach. Set to 2 to report a breach to the GCS but take no other action. Set to 3 to have the plane head to the return point on breach, but the pilot will maintain manual throttle control in this case.
FENCE_MINALT - the minimum altitude in meters. If this is zero then you will not have a minimum altitude.
FENCE_MAXALT - the maximum altitude in meters. If this is zero then you will not have a maximum altitude.
FENCE_CHANNEL - the RC input channel to watch for enabling the geo-fence. This defaults to zero, which disables geo-fencing. You should set it to a spare RC input channel that is connected to a two position switch on your transmitter. Fencing will be enabled when this channel goes above a PWM value of 1750. If your transmitter supports it it is also a good idea to enable audible feedback when this channel is enabled (a beep every few seconds), so you can tell if the fencing is enabled without looking down.
FENCE_TOTAL - the number of points in your fence (the return point plus the enclosed boundary). This should be set for you by the planner when you create the fence.
FENCE_RETALT - the altitude the aircraft will fly at when flying to the return point and when loitering at the return point (in meters). Note that when FENCE_RET_RALLY is set to 1 this parameter is ignored and the loiter altitude of the closest Rally Point is used instead. If this parameter is zero and FENCE_RET_RALLY is also zero, the midpoint of the FENCE_MAXALT and FENCE_MINALT parameters is used as the return altitude.
FENCE_AUTOENABLE - if set to 1, the aircraft will boot with the fence disabled. After an autonomous takeoff completes the fences will automatically enable. When the autonomous mission arrives at a landing waypoint the fence automatically disables.
FENCE_RET_RALLY - if set to 1 the aircraft will head to the nearest Rally Point rather than the fence return point when the fence is breached. Note that the loiter altitude of the Rally Point is used as the return altitude.
*/
QGCMapPolygonControls {
anchors.left: parent.left
anchors.right: parent.right
flightMap: editorMap
polygon: root.polygon
sectionLabel: qsTr("Fence Polygon:")
}
}
import QtQuick 2.2
import QtQuick.Controls 1.2
import QGroundControl 1.0
import QGroundControl.ScreenTools 1.0
import QGroundControl.Controls 1.0
import QGroundControl.FactControls 1.0
import QGroundControl.Palette 1.0
import QGroundControl.FlightMap 1.0
import QGroundControl.FactSystem 1.0
QGCLabel {
width: availableWidth
wrapMode: Text.WordWrap
text: qsTr("This vehicle does tno support GeoFence.")
//property var contoller - controller - Must be passed in from Loader
//property real availableWidth - Available width for control - Must be passed in from Loader
}
import QtQuick 2.2
import QtQuick.Controls 1.2
import QGroundControl 1.0
import QGroundControl.ScreenTools 1.0
import QGroundControl.Controls 1.0
import QGroundControl.FactControls 1.0
import QGroundControl.Palette 1.0
import QGroundControl.FlightMap 1.0
import QGroundControl.FactSystem 1.0
import QGroundControl.Controllers 1.0
Column {
id: editorColumn
width: availableWidth
spacing: _margin
//property real availableWidth - Available width for control - Must be passed in from Loader
readonly property real _margin: ScreenTools.defaultFontPixelWidth / 2
readonly property real _editFieldWidth: Math.min(width - _margin * 2, ScreenTools.defaultFontPixelWidth * 15)
property Fact _fenceAction: factController.getParameterFact(-1, "GF_ACTION")
property Fact _fenceRadius: factController.getParameterFact(-1, "GF_MAX_HOR_DIST")
property Fact _fenceAlt: factController.getParameterFact(-1, "GF_MAX_VER_DIST")
FactPanelController {
id: factController
factPanel: qgcView.viewPanel
}
QGCLabel { text: qsTr("Fence Settings:") }
Rectangle {
anchors.left: parent.left
anchors.right: parent.right
height: 1
color: qgcPal.text
}
QGCLabel { text: qsTr("Action on fence breach:") }
FactComboBox {
anchors.margins: ScreenTools.defaultFontPixelWidth
anchors.left: parent.left
width: _editFieldWidth
fact: _fenceAction
indexModel: false
}
Item { width: 1; height: 1 }
QGCCheckBox {
id: circleFenceCheckBox
text: qsTr("Circular fence around home pos")
checked: _fenceRadius.value > 0
onClicked: _fenceRadius.value = checked ? 100 : 0
}
Row {
anchors.margins: ScreenTools.defaultFontPixelWidth
anchors.left: parent.left
spacing: _margin
QGCLabel {
anchors.baseline: fenceRadiusField.baseline
text: qsTr("Radius:")
}
FactTextField {
id: fenceRadiusField
showUnits: true
fact: _fenceRadius
enabled: circleFenceCheckBox.checked
width: _editFieldWidth
}
}
Item { width: 1; height: 1 }
QGCCheckBox {
id: maxAltFenceCheckBox
text: qsTr("Maximum altitude fence")
checked: _fenceAlt.value > 0
onClicked: _fenceAlt.value = checked ? 100 : 0
}
Row {
anchors.margins: ScreenTools.defaultFontPixelWidth
anchors.left: parent.left
spacing: _margin
QGCLabel {
anchors.baseline: fenceAltMaxField.baseline
text: qsTr("Altitude:")
}
FactTextField {
id: fenceAltMaxField
showUnits: true
fact: _fenceAlt
enabled: maxAltFenceCheckBox.checked
width: _editFieldWidth
}
}
}
......@@ -28,6 +28,7 @@ public:
float circleRadius (void) const final;
QVariantList params (void) const final { return _params; }
QStringList paramLabels (void) const final { return _paramLabels; }
QString editorQml (void) const final { return QStringLiteral("qrc:/FirmwarePlugin/PX4/PX4GeoFenceEditor.qml"); }
private slots:
void _circleRadiusRawValueChanged(QVariant value);
......
......@@ -4,10 +4,6 @@ import QtQuick.Controls 1.2
import QGroundControl 1.0
import QGroundControl.ScreenTools 1.0
import QGroundControl.Controls 1.0
import QGroundControl.FactControls 1.0
import QGroundControl.Palette 1.0
import QGroundControl.FlightMap 1.0
import QGroundControl.FactSystem 1.0
QGCFlickable {
id: root
......@@ -54,83 +50,29 @@ QGCFlickable {
anchors.left: parent.left
anchors.right: parent.right
anchors.top: geoFenceLabel.bottom
height: editorColumn.height + (_margin * 2)
height: editorLoader.y + editorLoader.height + (_margin * 2)
color: qgcPal.windowShadeDark
radius: _radius
Column {
id: editorColumn
QGCLabel {
id: geoLabel
anchors.margins: _margin
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
spacing: _margin
QGCLabel {
anchors.left: parent.left
anchors.right: parent.right
wrapMode: Text.WordWrap
text: qsTr("Click in map to set breach return point.")
visible: geoFenceController.breachReturnSupported
}
QGCLabel { text: qsTr("Fence Settings:") }
Rectangle {
anchors.left: parent.left
anchors.right: parent.right
height: 1
color: qgcPal.text
}
QGCLabel {
text: qsTr("Must be connected to Vehicle to change fence settings.")
visible: !QGroundControl.multiVehicleManager.activeVehicle
}
Repeater {
model: geoFenceController.params
Item {
width: editorColumn.width
height: textField.height
QGCLabel {
id: textFieldLabel
anchors.baseline: textField.baseline
text: geoFenceController.paramLabels[index]
}
FactTextField {
id: textField
anchors.right: parent.right
width: _editFieldWidth
showUnits: true
fact: modelData
visible: !comboField.visible
}
FactComboBox {
id: comboField
anchors.right: parent.right
width: _editFieldWidth
indexModel: false
fact: visible ? modelData : _nullFact
visible: modelData.enumStrings.length
wrapMode: Text.WordWrap
font.pointSize: ScreenTools.smallFontPointSize
text: qsTr("GeoFencing allows you to set a virtual ‘fence’ around the area you want to fly in.")
}
property var _nullFact: Fact { }
}
}
}
Loader {
id: editorLoader
anchors.margins: _margin
anchors.top: geoLabel.bottom
anchors.left: parent.left
source: geoFenceController.editorQml
QGCMapPolygonControls {
anchors.left: parent.left
anchors.right: parent.right
flightMap: editorMap
polygon: root.polygon
sectionLabel: qsTr("Fence Polygon:")
visible: geoFenceController.polygonSupported
}
property real availableWidth: parent.width - (_margin * 2)
}
}
}
......
......@@ -26,9 +26,8 @@ import QGroundControl.Controllers 1.0
/// Mission Editor
QGCView {
id: _root
viewPanel: panel
id: qgcView
viewPanel: panel
// zOrder comes from the Loader in MainWindow.qml
z: QGroundControl.zOrderTopMost
......@@ -124,7 +123,7 @@ QGCView {
function loadFromSelectedFile() {
if (ScreenTools.isMobile) {
_root.showDialog(mobileFilePicker, qsTr("Select Mission File"), _root.showDialogDefaultWidth, StandardButton.Yes | StandardButton.Cancel)
qgcView.showDialog(mobileFilePicker, qsTr("Select Mission File"), qgcView.showDialogDefaultWidth, StandardButton.Yes | StandardButton.Cancel)
} else {
missionController.loadFromFilePicker()
fitViewportToMissionItems()
......@@ -134,7 +133,7 @@ QGCView {
function saveToSelectedFile() {
if (ScreenTools.isMobile) {
_root.showDialog(mobileFileSaver, qsTr("Save Mission File"), _root.showDialogDefaultWidth, StandardButton.Save | StandardButton.Cancel)
qgcView.showDialog(mobileFileSaver, qsTr("Save Mission File"), qgcView.showDialogDefaultWidth, StandardButton.Save | StandardButton.Cancel)
} else {
missionController.saveToFilePicker()
}
......@@ -255,7 +254,7 @@ QGCView {
FlightMap {
id: editorMap
height: _root.height
height: qgcView.height
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.right: parent.right
......@@ -548,7 +547,6 @@ QGCView {
delegate: MissionItemEditor {
missionItem: object
width: parent.width
qgcView: _root
readOnly: false
onClicked: setCurrentItem(object.sequenceNumber)
......@@ -892,7 +890,7 @@ QGCView {
onClicked: {
syncButton.hideDropDown()
if (_syncDropDownController.dirty) {
_root.showDialog(syncLoadFromVehicleOverwrite, columnHolder._overwriteText, _root.showDialogDefaultWidth, StandardButton.Yes | StandardButton.Cancel)
qgcView.showDialog(syncLoadFromVehicleOverwrite, columnHolder._overwriteText, qgcView.showDialogDefaultWidth, StandardButton.Yes | StandardButton.Cancel)
} else {
_syncDropDownController.loadFromVehicle()
}
......@@ -916,7 +914,7 @@ QGCView {
onClicked: {
syncButton.hideDropDown()
if (_syncDropDownController.dirty) {
_root.showDialog(syncLoadFromFileOverwrite, columnHolder._overwriteText, _root.showDialogDefaultWidth, StandardButton.Yes | StandardButton.Cancel)
qgcView.showDialog(syncLoadFromFileOverwrite, columnHolder._overwriteText, qgcView.showDialogDefaultWidth, StandardButton.Yes | StandardButton.Cancel)
} else {
_syncDropDownController.loadFromSelectedFile()
}
......@@ -929,7 +927,7 @@ QGCView {
onClicked: {
syncButton.hideDropDown()
_syncDropDownController.removeAll()
_root.showDialog(removeAllPromptDialog, qsTr("Remove all"), _root.showDialogDefaultWidth, StandardButton.Yes | StandardButton.No)
qgcView.showDialog(removeAllPromptDialog, qsTr("Remove all"), qgcView.showDialogDefaultWidth, StandardButton.Yes | StandardButton.No)
}
}
}
......
......@@ -59,6 +59,7 @@ void GeoFenceController::_signalAll(void)
emit circleRadiusChanged(circleRadius());
emit paramsChanged(params());
emit paramLabelsChanged(paramLabels());
emit editorQmlChanged(editorQml());
}
void GeoFenceController::_activeVehicleBeingRemoved(Vehicle* vehicle)
......@@ -254,3 +255,13 @@ QStringList GeoFenceController::paramLabels(void) const
return QStringList();
}
}
QString GeoFenceController::editorQml(void) const
{
if (_activeVehicle) {
return _activeVehicle->geoFenceManager()->editorQml();
} else {
// FIXME: Offline editing support
return QString();
}
}
......@@ -36,6 +36,7 @@ public:
Q_PROPERTY(QGeoCoordinate breachReturnPoint READ breachReturnPoint WRITE setBreachReturnPoint NOTIFY breachReturnPointChanged)
Q_PROPERTY(QVariantList params READ params NOTIFY paramsChanged)
Q_PROPERTY(QStringList paramLabels READ paramLabels NOTIFY paramLabelsChanged)
Q_PROPERTY(QString editorQml READ editorQml NOTIFY editorQmlChanged)
void start (bool editMode) final;
void loadFromVehicle (void) final;
......@@ -58,6 +59,7 @@ public:
QGeoCoordinate breachReturnPoint (void) const { return _breachReturnPoint; }