Commit 558b23f8 authored by Don Gagne's avatar Don Gagne

AutoPilot plugin restructuring for better QML support

- properties now hand off of main “autopilot” object in qml
- Added support for summary items through qml
parent b82bfe84
import QtQuick 2.2
import QtQuick.Controls 1.2
import QGroundControl.FactSystem 1.0
TextInput {
property Fact fact
text: fact.value
font.family: "Helvetica"
font.pointSize: 24
color: "red"
focus: true
onAccepted: { fact.value = text; }
}
import QtQuick 2.2
import QtQuick.Controls 1.2
import QtQuick.Controls.Styles 1.2
Button {
text: "Button"
property bool setupComplete: false
property var summaryModel: ListModel {
ListElement { name: "Row 1"; state: "State 1" }
ListElement { name: "Row 2"; state: "State 2" }
ListElement { name: "Row 3"; state: "State 3" }
}
style: ButtonStyle {
id: buttonStyle
background: Rectangle {
id: innerRect
readonly property real titleHeight: 30
//property alias summaryModel: summaryList.model
border.color: "#888"
radius: 10
color: control.activeFocus ? "#47b" : "white"
opacity: control.hovered || control.activeFocus ? 1 : 0.75
Behavior on opacity {NumberAnimation{ duration: 100 }}
Text {
id: titleBar
width: parent.width
height: parent.titleHeight
verticalAlignment: TextEdit.AlignVCenter
horizontalAlignment: TextEdit.AlignHCenter
text: control.text
font.pixelSize: 12
Rectangle {
id: setupIndicator
property bool setupComplete: true
readonly property real indicatorRadius: 6
x: parent.width - (indicatorRadius * 2) - 5
y: (parent.height - (indicatorRadius * 2)) / 2
width: indicatorRadius * 2
height: indicatorRadius * 2
radius: indicatorRadius
color: control.setupComplete ? "green" : "red"
}
}
Rectangle {
width: parent.width
height: parent.height - parent.titleHeight
y: parent.titleHeight
border.color: "#888"
gradient: Gradient {
GradientStop { position: 0; color: "#ffffff" }
GradientStop { position: 1; color: "#000000" }
}
ListView {
id: summaryList
anchors.fill: parent
model: control.summaryModel
delegate: Row {
Text { text: modelData.name }
Text { text: modelData.state }
}
}
}
}
label: Item {}
}
}
/*
Rectangle {
readonly property real titleHeight: 30
property alias title: titleBar.text
property alias setupComplete: setupIndicator.setupComplete
//property alias summaryModel: summaryList.model
border.color: "#888"
radius: 10
gradient: Gradient {
GradientStop { position: 0 ; color: "#cccccc" }
GradientStop { position: 1 ; color: "#aaa" }
}
Text {
id: titleBar
width: parent.width
height: parent.titleHeight
verticalAlignment: TextEdit.AlignVCenter
horizontalAlignment: TextEdit.AlignHCenter
text: qsTr("TITLE")
font.pixelSize: 12
Rectangle {
id: setupIndicator
property bool setupComplete: true
readonly property real indicatorRadius: 6
x: parent.width - (indicatorRadius * 2) - 5
y: (parent.height - (indicatorRadius * 2)) / 2
width: indicatorRadius * 2
height: indicatorRadius * 2
radius: indicatorRadius
color: setupComplete ? "green" : "red"
}
}
Rectangle {
width: parent.width
height: parent.height - parent.titleHeight
y: parent.titleHeight
border.color: "#888"
gradient: Gradient {
GradientStop {
position: 0
color: "#ffffff"
}
GradientStop {
position: 1
color: "#000000"
}
}
ListView {
id: summaryList
anchors.fill: parent
model: ListModel {
ListElement { name: "Row 1"; state: "State 1" }
ListElement { name: "Row 2"; state: "State 2" }
ListElement { name: "Row 3"; state: "State 3" }
}
delegate: Row { Text { text: modelData.name } Text { text: modelData.state } }
}
}
}
*/
\ No newline at end of file
Module QGroundControl.FactControls
FactTextInput 1.0 FactTextInput.qml
\ No newline at end of file
SetupButton 1.0 SetupButton.qml
\ No newline at end of file
......@@ -48,18 +48,14 @@ class AutoPilotPlugin : public QObject
Q_OBJECT
public:
/// @brief Returns the list of VehicleComponent objects associated with the AutoPilot.
virtual QList<VehicleComponent*> getVehicleComponents(void) const = 0;
Q_PROPERTY(QVariantMap parameters READ parameters CONSTANT)
Q_PROPERTY(QVariantList components READ components CONSTANT)
Q_PROPERTY(QUrl setupBackgroundImage READ setupBackgroundImage CONSTANT)
/// Returns the parameter facts for the specified UAS.
///
/// Key is parameter name. Get Fact object like this: _mapParameterName2Variant["RC_MAP_THROTTLE"].value<Fact*>().
/// You should not request parameter facts until the plugin reports that it is ready.
virtual const QVariantMap& parameterFacts(void) const = 0;
/// Adds the FactSystem properties to the Qml context. You should not call
/// this method until the plugin reports that it is ready.
virtual void addFactsToQmlContext(QQmlContext* context) const = 0;
// Property accessors
virtual const QVariantList& components(void) = 0;
virtual const QVariantMap& parameters(void) = 0;
virtual QUrl setupBackgroundImage(void) = 0;
/// Returns true if the plugin is ready for use
virtual bool pluginIsReady(void) const = 0;
......@@ -72,8 +68,9 @@ signals:
void pluginReady(void);
protected:
// All access to AutoPilotPugin objects is through getInstanceForAutoPilotPlugin
/// All access to AutoPilotPugin objects is through getInstanceForAutoPilotPlugin
AutoPilotPlugin(QObject* parent = NULL) : QObject(parent) { }
};
#endif
......@@ -32,12 +32,6 @@ GenericAutoPilotPlugin::GenericAutoPilotPlugin(UASInterface* uas, QObject* paren
Q_UNUSED(uas);
}
QList<VehicleComponent*> GenericAutoPilotPlugin::getVehicleComponents(void) const
{
// Generic autopilot has no configurable components
return QList<VehicleComponent*>();
}
QList<AutoPilotPluginManager::FullMode_t> GenericAutoPilotPlugin::getModes(void)
{
AutoPilotPluginManager::FullMode_t fullMode;
......@@ -83,13 +77,20 @@ QString GenericAutoPilotPlugin::getShortModeText(uint8_t baseMode, uint32_t cust
return mode;
}
void GenericAutoPilotPlugin::addFactsToQmlContext(QQmlContext* context) const
void GenericAutoPilotPlugin::clearStaticData(void)
{
Q_UNUSED(context);
// No Static data yet
}
const QVariantList& GenericAutoPilotPlugin::components(void)
{
static QVariantList staticList;
Q_ASSERT_X(false, "Not yet implemented", "");
return staticList;
}
const QVariantMap& GenericAutoPilotPlugin::parameterFacts(void) const
const QVariantMap& GenericAutoPilotPlugin::parameters(void)
{
static QVariantMap staticMap;
......@@ -97,7 +98,10 @@ const QVariantMap& GenericAutoPilotPlugin::parameterFacts(void) const
return staticMap;
}
void GenericAutoPilotPlugin::clearStaticData(void)
QUrl GenericAutoPilotPlugin::setupBackgroundImage(void)
{
// No Static data yet
static QUrl url;
Q_ASSERT_X(false, "Not yet implemented", "");
return url;
}
......@@ -40,14 +40,16 @@ public:
GenericAutoPilotPlugin(UASInterface* uas, QObject* parent = NULL);
// Overrides from AutoPilotPlugin
virtual QList<VehicleComponent*> getVehicleComponents(void) const ;
virtual void addFactsToQmlContext(QQmlContext* context) const;
virtual const QVariantMap& parameterFacts(void) const;
virtual bool pluginIsReady(void) const { return true; }
virtual QUrl setupBackgroundImage(void);
virtual const QVariantList& components(void);
virtual const QVariantMap& parameters(void);
static QList<AutoPilotPluginManager::FullMode_t> getModes(void);
static QString getShortModeText(uint8_t baseMode, uint32_t customMode);
static void clearStaticData(void);
protected:
};
#endif
......@@ -26,6 +26,7 @@
#include "AirframeComponent.h"
#include "QGCPX4AirframeConfig.h"
#include "VehicleComponentSummaryItem.h"
/// @brief Parameters which signal a change in setupComplete state
static const char* triggerParams[] = { "SYS_AUTOSTART", NULL };
......@@ -161,56 +162,65 @@ QWidget* AirframeComponent::setupWidget(void) const
return new QGCPX4AirframeConfig;
}
QList<QStringList> AirframeComponent::summaryItems(void) const
const QVariantList& AirframeComponent::summaryItems(void)
{
QVariant value;
QStringList row;
QList<QStringList> items;
// Fill the items on first reference
// FIXME: These items are not live
row << "System ID:";
if (_paramMgr->getParameterValue(_paramMgr->getDefaultComponentId(), "MAV_SYS_ID", value)) {
if (value.toInt() == 0) {
row << "Setup required";
if (!_summaryItems.count()) {
QString name;
QString state;
QVariant value;
name = "System ID:";
if (_paramMgr->getParameterValue(_paramMgr->getDefaultComponentId(), "MAV_SYS_ID", value)) {
if (value.toInt() == 0) {
state = "Setup required";
} else {
state = value.toString();
}
} else {
row << value.toString();
// Why is the parameter missing?
Q_ASSERT(false);
}
} else {
// Why is the parameter missing?
Q_ASSERT(false);
}
items << row;
row.clear();
row << "Airframe:";
if (_paramMgr->getParameterValue(_paramMgr->getDefaultComponentId(), "SYS_AUTOSTART", value)) {
if (value.toInt() == 0) {
row << "Setup required";
VehicleComponentSummaryItem* item = new VehicleComponentSummaryItem(name, state, this);
_summaryItems.append(QVariant::fromValue(item));
name = "Airframe:";
if (_paramMgr->getParameterValue(_paramMgr->getDefaultComponentId(), "SYS_AUTOSTART", value)) {
if (value.toInt() == 0) {
state = "Setup required";
} else {
state = value.toString();
}
} else {
row << value.toString();
// Why is the parameter missing?
Q_ASSERT(false);
}
} else {
// Why is the parameter missing?
Q_ASSERT(false);
}
items << row;
row.clear();
row << "Type:";
if (_paramMgr->getParameterValue(_paramMgr->getDefaultComponentId(), "MAV_TYPE", value)) {
int index = value.toInt();
item = new VehicleComponentSummaryItem(name, state, this);
_summaryItems.append(QVariant::fromValue(item));
if (index < 0 || index >= (int)cMavTypes) {
row << "Unknown";
name = "Type:";
if (_paramMgr->getParameterValue(_paramMgr->getDefaultComponentId(), "MAV_TYPE", value)) {
int index = value.toInt();
if (index < 0 || index >= (int)cMavTypes) {
state = "Unknown";
} else {
state = mavTypeInfo[index].description;
}
} else {
row << mavTypeInfo[index].description;
// Why is the parameter missing?
Q_ASSERT(false);
state = "Unknown";
}
} else {
// Why is the parameter missing?
Q_ASSERT(false);
row << "Unknown";
item = new VehicleComponentSummaryItem(name, state, this);
_summaryItems.append(QVariant::fromValue(item));
}
items << row;
return items;
return _summaryItems;
}
......@@ -49,10 +49,11 @@ public:
virtual QString setupStateDescription(void) const;
virtual QWidget* setupWidget(void) const;
virtual QStringList paramFilterList(void) const;
virtual QList<QStringList> summaryItems(void) const;
virtual const QVariantList& summaryItems(void);
private:
const QString _name;
const QString _name;
QVariantList _summaryItems;
};
#endif
......@@ -6,27 +6,28 @@
<rect>
<x>0</x>
<y>0</y>
<width>831</width>
<height>1286</height>
<width>642</width>
<height>645</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>642</width>
<height>645</height>
</size>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="label_8">
<property name="font">
<font>
<pointsize>22</pointsize>
</font>
</property>
<property name="text">
<string>This implementation is a work in progress. Visuals are meant to be functional only. Active display of switch positions is not yet implemented. If this entire screen is disabled, you must do a Radio Calibration before settings Flight Modes.</string>
</property>
......@@ -205,19 +206,6 @@
</attribute>
</widget>
</item>
<item>
<spacer name="verticalSpacer_3">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item row="1" column="1">
......
......@@ -26,6 +26,7 @@
#include "FlightModesComponent.h"
#include "FlightModeConfig.h"
#include "VehicleComponentSummaryItem.h"
/// @brief Parameters which signal a change in setupComplete state
static const char* triggerParams[] = { "RC_MAP_MODE_SW", NULL };
......@@ -116,41 +117,44 @@ QWidget* FlightModesComponent::setupWidget(void) const
return new FlightModeConfig();
}
QList<QStringList> FlightModesComponent::summaryItems(void) const
const QVariantList& FlightModesComponent::summaryItems(void)
{
QList<QStringList> items;
// Create summary items for each mode switch
for (size_t i=0; i<cSwitchList; i++) {
QVariant value;
QStringList row;
row << switchList[i].name;
if (!_summaryItems.count()) {
// Create summary items for each mode switch
if (_paramMgr->getParameterValue(_paramMgr->getDefaultComponentId(), switchList[i].param, value)) {
int chan = value.toInt();
for (size_t i=0; i<cSwitchList; i++) {
QString name;
QString state;
QVariant value;
name = switchList[i].name;
if (chan == 0) {
// Switch is not mapped
if (i == 0) {
// Mode switch is required
Q_ASSERT(strcmp(switchList[0].param, "RC_MAP_MODE_SW") == 0);
row << "Setup required";
if (_paramMgr->getParameterValue(_paramMgr->getDefaultComponentId(), switchList[i].param, value)) {
int chan = value.toInt();
if (chan == 0) {
// Switch is not mapped
if (i == 0) {
// Mode switch is required
Q_ASSERT(strcmp(switchList[0].param, "RC_MAP_MODE_SW") == 0);
state = "Setup required";
} else {
state = "None";
}
} else {
row << "None";
state = tr("Chan %1").arg(chan);
}
} else {
row << tr("Chan %1").arg(chan);
// Why is the parameter missing?
Q_ASSERT(false);
state = "Unknown";
}
} else {
// Why is the parameter missing?
Q_ASSERT(false);
row << "Unknown";
VehicleComponentSummaryItem* item = new VehicleComponentSummaryItem(name, state, this);
_summaryItems.append(QVariant::fromValue(item));
}
items << row;
}
return items;
return _summaryItems;
}
......@@ -49,10 +49,11 @@ public:
virtual QString setupStateDescription(void) const;
virtual QWidget* setupWidget(void) const;
virtual QStringList paramFilterList(void) const;
virtual QList<QStringList> summaryItems(void) const;
virtual const QVariantList& summaryItems(void);
private:
const QString _name;
const QString _name;
QVariantList _summaryItems;
};
#endif
......@@ -86,33 +86,6 @@ PX4AutoPilotPlugin::~PX4AutoPilotPlugin()
PX4ParameterFacts::deleteParameterFactMetaData();
}
QList<VehicleComponent*> PX4AutoPilotPlugin::getVehicleComponents(void) const
{
Q_ASSERT(_uas);
QList<VehicleComponent*> components;
VehicleComponent* component;
component = new AirframeComponent(_uas);
Q_CHECK_PTR(component);
components.append(component);
component = new RadioComponent(_uas);
Q_CHECK_PTR(component);
components.append(component);
component = new FlightModesComponent(_uas);
Q_CHECK_PTR(component);
components.append(component);
component = new SensorsComponent(_uas);
Q_CHECK_PTR(component);
components.append(component);
return components;
}
QList<AutoPilotPluginManager::FullMode_t> PX4AutoPilotPlugin::getModes(void)
{
union px4_custom_mode px4_cm;
......@@ -206,15 +179,6 @@ QString PX4AutoPilotPlugin::getShortModeText(uint8_t baseMode, uint32_t customMo
return mode;
}
void PX4AutoPilotPlugin::addFactsToQmlContext(QQmlContext* context) const
{
Q_ASSERT(context);
Q_ASSERT(_parameterFacts->factsAreReady());
context->setContextProperty("parameters", _parameterFacts->factMap());
}
void PX4AutoPilotPlugin::clearStaticData(void)
{
PX4ParameterFacts::clearStaticData();
......@@ -224,3 +188,40 @@ bool PX4AutoPilotPlugin::pluginIsReady(void) const
{
return _parameterFacts->factsAreReady();
}
const QVariantList& PX4AutoPilotPlugin::components(void)
{
if (_components.count() == 0) {
VehicleComponent* component;
Q_ASSERT(_uas);
component = new AirframeComponent(_uas);
Q_CHECK_PTR(component);
_components.append(QVariant::fromValue(component));
component = new RadioComponent(_uas);
Q_CHECK_PTR(component);
_components.append(QVariant::fromValue(component));
component = new FlightModesComponent(_uas);
Q_CHECK_PTR(component);
_components.append(QVariant::fromValue(component));
component = new SensorsComponent(_uas);
Q_CHECK_PTR(component);
_components.append(QVariant::fromValue(component));
}
return _components;
}
const QVariantMap& PX4AutoPilotPlugin::parameters(void)
{
return _parameterFacts->factMap();
}
QUrl PX4AutoPilotPlugin::setupBackgroundImage(void)
{
return QUrl::fromUserInput("qrc:/qml/px4fmu_2.x.png");
}
......@@ -29,6 +29,8 @@
#include "UASInterface.h"
#include "PX4ParameterFacts.h"
#include <QImage>
/// @file
/// @brief This is the PX4 specific implementation of the AutoPilot class.
/// @author Don Gagne <don@thegagnes.com>
......@@ -42,10 +44,10 @@ public:
~PX4AutoPilotPlugin();
// Overrides from AutoPilotPlugin
virtual QList<VehicleComponent*> getVehicleComponents(void) const ;
virtual void addFactsToQmlContext(QQmlContext* context) const;
virtual const QVariantMap& parameterFacts(void) const { return _parameterFacts->factMap(); }
virtual bool pluginIsReady(void) const;
virtual const QVariantList& components(void);
virtual const QVariantMap& parameters(void);
virtual QUrl setupBackgroundImage(void);
static QList<AutoPilotPluginManager::FullMode_t> getModes(void);
static QString getShortModeText(uint8_t baseMode, uint32_t customMode);
......@@ -55,6 +57,7 @@ private:
UASInterface* _uas;
PX4ParameterFacts* _parameterFacts;
bool _pluginReady;
QVariantList _components;
};
#endif
......@@ -26,6 +26,7 @@
#include "RadioComponent.h"
#include "PX4RCCalibration.h"
#include "VehicleComponentSummaryItem.h"
/// @brief Parameters which signal a change in setupComplete state
static const char* triggerParams[] = { "RC_MAP_MODE_SW", NULL };
......@@ -100,48 +101,54 @@ QWidget* RadioComponent::setupWidget(void) const
return new PX4RCCalibration;
}
QList<QStringList> RadioComponent::summaryItems(void) const