Commit 8ce30794 authored by Don Gagne's avatar Don Gagne

Merge pull request #1848 from DonLakeFlyer/MissionEditor

Mission editor (WIP)
parents 0a770c97 69f27141
......@@ -144,6 +144,7 @@ INCLUDEPATH += \
src/input \
src/Joystick \
src/lib/qmapcontrol \
src/MissionEditor \
src/QmlControls \
src/uas \
src/ui \
......@@ -244,6 +245,7 @@ HEADERS += \
src/Joystick/JoystickManager.h \
src/LogCompressor.h \
src/MG.h \
src/MissionEditor/MissionEditor.h \
src/QGC.h \
src/QGCApplication.h \
src/QGCComboBox.h \
......@@ -381,6 +383,7 @@ SOURCES += \
src/Joystick/JoystickManager.cc \
src/LogCompressor.cc \
src/main.cc \
src/MissionEditor/MissionEditor.cc \
src/QGC.cc \
src/QGCApplication.cc \
src/QGCComboBox.cc \
......
......@@ -100,6 +100,7 @@
<file alias="QGroundControl/Controls/ModeSwitchDisplay.qml">src/QmlControls/ModeSwitchDisplay.qml</file>
<file alias="QGroundControl/Controls/MissionItemIndexLabel.qml">src/QmlControls/MissionItemIndexLabel.qml</file>
<file alias="QGroundControl/Controls/MissionItemSummary.qml">src/QmlControls/MissionItemSummary.qml</file>
<file alias="QGroundControl/Controls/MissionItemEditor.qml">src/QmlControls/MissionItemEditor.qml</file>
<!-- Vehicle Setup -->
<file alias="SetupView.qml">src/VehicleSetup/SetupView.qml</file>
......@@ -128,6 +129,7 @@
<file alias="FlightDisplayView.qml">src/FlightDisplay/FlightDisplayView.qml</file>
<file alias="FlightDisplayWidget.qml">src/FlightDisplay/FlightDisplayWidget.qml</file>
<file alias="MapDisplay.qml">src/ui/mapdisplay/MapDisplay.qml</file>
<file alias="MissionEditor.qml">src/MissionEditor/MissionEditor.qml</file>
<!-- FlightMap module -->
<file alias="QGroundControl/FlightMap/qmldir">src/FlightMap/qmldir</file>
......@@ -150,7 +152,7 @@
<file alias="QGroundControl/FlightMap/QGCWaypointEditor.qml">src/FlightMap/Widgets/QGCWaypointEditor.qml</file>
<!-- FlightMap MapQuickItems -->
<file alias="QGroundControl/FlightMap/MissionMapItem.qml">src/FlightMap/MapItems/MissionMapItem.qml</file>
<file alias="QGroundControl/FlightMap/MissionItemIndicator.qml">src/FlightMap/MapItems/MissionItemIndicator.qml</file>
<file alias="QGroundControl/FlightMap/VehicleMapItem.qml">src/FlightMap/MapItems/VehicleMapItem.qml</file>
</qresource>
......
......@@ -95,8 +95,10 @@ Item {
model: multiVehicleManager.activeVehicle ? multiVehicleManager.activeVehicle.missionItems : 0
delegate:
MissionMapItem {
missionItem: object
MissionItemIndicator {
label: object.sequenceNumber
isCurrentItem: object.isCurrentItem
coordinate: object.coordinate
}
}
......
......@@ -76,13 +76,13 @@ Map {
Menu {
id: mapTypeMenu
title: "Map Type..."
enabled: root.visible
enabled: _map.visible
ExclusiveGroup { id: currMapType }
function setCurrentMap(mapID) {
for (var i = 0; i < _map.supportedMapTypes.length; i++) {
if (mapID === _map.supportedMapTypes[i].name) {
_map.activeMapType = _map.supportedMapTypes[i]
multiVehicleManager.saveSetting(root.mapName + "/currentMapType", mapID);
multiVehicleManager.saveSetting(_map.mapName + "/currentMapType", mapID);
return;
}
}
......@@ -100,7 +100,7 @@ Map {
var mapID = ''
if (_map.supportedMapTypes.length > 0)
mapID = _map.activeMapType.name;
mapID = multiVehicleManager.loadSetting(root.mapName + "/currentMapType", mapID);
mapID = multiVehicleManager.loadSetting(_map.mapName + "/currentMapType", mapID);
for (var i = 0; i < _map.supportedMapTypes.length; i++) {
var name = _map.supportedMapTypes[i].name;
addMap(name, mapID === name);
......
......@@ -30,14 +30,14 @@ import QGroundControl.Vehicle 1.0
/// Marker for displaying a mission item on the map
MapQuickItem {
property var missionItem ///< Mission Item object
property alias label: _label.label
property alias isCurrentItem: _label.isCurrentItem
anchorPoint.x: sourceItem.width / 2
anchorPoint.y: sourceItem.height / 2
coordinate: missionItem.coordinate
sourceItem:
MissionItemIndexLabel {
missionItemIndex: missionItem.id
id: _label
}
}
......@@ -21,4 +21,4 @@ QGCWaypointEditor 1.0 QGCWaypointEditor.qml
# MapQuickItems
VehicleMapItem 1.0 VehicleMapItem.qml
MissionMapItem 1.0 MissionMapItem.qml
MissionItemIndicator 1.0 MissionItemIndicator.qml
/*=====================================================================
QGroundControl Open Source Ground Control Station
(c) 2009, 2015 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
This file is part of the QGROUNDCONTROL project
QGROUNDCONTROL is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
QGROUNDCONTROL is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with QGROUNDCONTROL. If not, see <http://www.gnu.org/licenses/>.
======================================================================*/
#include "MissionEditor.h"
#include "ScreenToolsController.h"
#include <QQmlContext>
#include <QQmlEngine>
#include <QSettings>
const char* MissionEditor::_settingsGroup = "MissionEditor";
MissionEditor::MissionEditor(QWidget *parent)
: QGCQmlWidgetHolder(parent)
{
setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
// Get rid of layout default margins
QLayout* pl = layout();
if(pl) {
pl->setContentsMargins(0,0,0,0);
}
#ifndef __android__
setMinimumWidth( 31 * ScreenToolsController::defaultFontPixelSize_s());
setMinimumHeight(33 * ScreenToolsController::defaultFontPixelSize_s());
#endif
setContextPropertyObject("controller", this);
setSource(QUrl::fromUserInput("qrc:/qml/MissionEditor.qml"));
}
MissionEditor::~MissionEditor()
{
}
void MissionEditor::saveSetting(const QString &name, const QString& value)
{
QSettings settings;
settings.beginGroup(_settingsGroup);
settings.setValue(name, value);
}
QString MissionEditor::loadSetting(const QString &name, const QString& defaultValue)
{
QSettings settings;
settings.beginGroup(_settingsGroup);
return settings.value(name, defaultValue).toString();
}
void MissionEditor::addMissionItem(QGeoCoordinate coordinate)
{
MissionItem * newItem = new MissionItem(this, _missionItems.count(), coordinate);
if (_missionItems.count() == 0) {
newItem->setCommand(MavlinkQmlSingleton::MAV_CMD_NAV_TAKEOFF);
}
qDebug() << "MissionItem" << newItem->coordinate();
_missionItems.append(newItem);
}
/*=====================================================================
QGroundControl Open Source Ground Control Station
(c) 2009, 2015 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
This file is part of the QGROUNDCONTROL project
QGROUNDCONTROL is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
QGROUNDCONTROL is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with QGROUNDCONTROL. If not, see <http://www.gnu.org/licenses/>.
======================================================================*/
#ifndef MissionEditor_H
#define MissionEditor_H
#include "QGCQmlWidgetHolder.h"
#include "QmlObjectListModel.h"
class MissionEditor : public QGCQmlWidgetHolder
{
Q_OBJECT
public:
MissionEditor(QWidget* parent = NULL);
~MissionEditor();
Q_PROPERTY(QmlObjectListModel* missionItems READ missionItemsModel CONSTANT)
Q_INVOKABLE void addMissionItem(QGeoCoordinate coordinate);
Q_INVOKABLE void saveSetting (const QString &key, const QString& value);
Q_INVOKABLE QString loadSetting (const QString &key, const QString& defaultValue);
// Property accessors
QmlObjectListModel* missionItemsModel(void) { return &_missionItems; }
private:
QmlObjectListModel _missionItems;
static const char* _settingsGroup;
};
#endif
/*=====================================================================
QGroundControl Open Source Ground Control Station
(c) 2009, 2015 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
This file is part of the QGROUNDCONTROL project
QGROUNDCONTROL is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
QGROUNDCONTROL is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with QGROUNDCONTROL. If not, see <http://www.gnu.org/licenses/>.
======================================================================*/
import QtQuick 2.4
import QtQuick.Controls 1.3
import QtQuick.Dialogs 1.2
import QtLocation 5.3
import QtPositioning 5.3
import QGroundControl.FlightMap 1.0
import QGroundControl.ScreenTools 1.0
import QGroundControl.Controls 1.0
import QGroundControl.Palette 1.0
/// Mission Editor
Item {
// For some reason we can't have FlightMap as the top level control. If you do that it doesn't draw.
// So we have an Item at the top to work around that.
readonly property real _defaultLatitude: 37.803784
readonly property real _defaultLongitude: -122.462276
readonly property int _decimalPlaces: 7
FlightMap {
id: editorMap
anchors.fill: parent
mapName: "MissionEditor"
latitude: _defaultLatitude
longitude: _defaultLongitude
QGCLabel { text: "WIP: Non functional"; font.pixelSize: ScreenTools.largeFontPixelSize }
MouseArea {
anchors.fill: parent
onClicked: {
var coordinate = editorMap.toCoordinate(Qt.point(mouse.x, mouse.y))
coordinate.latitude = coordinate.latitude.toFixed(_decimalPlaces)
coordinate.longitude = coordinate.longitude.toFixed(_decimalPlaces)
coordinate.altitude = 0
controller.addMissionItem(coordinate)
}
}
// Add the mission items to the map
MapItemView {
model: controller.missionItems
delegate:
MissionItemIndicator {
label: object.sequenceNumber
isCurrentItem: object.isCurrentItem
coordinate: object.coordinate
Component.onCompleted: console.log("Indicator", object.coordinate)
}
}
// Mission item list
ListView {
id: missionItemSummaryList
anchors.margins: ScreenTools.defaultFontPixelHeight
anchors.top: parent.top
anchors.bottom: editorMap.mapWidgets.top
anchors.right: parent.right
width: ScreenTools.defaultFontPixelWidth * 30
spacing: ScreenTools.defaultFontPixelHeight / 2
orientation: ListView.Vertical
model: controller.missionItems
property real _maxItemHeight: 0
delegate:
MissionItemEditor {
missionItem: object
}
}
Column {
id: controlWidgets
anchors.margins: ScreenTools.defaultFontPixelWidth
anchors.right: parent.left
anchors.bottom: parent.top
spacing: ScreenTools.defaultFontPixelWidth / 2
QGCButton {
id: addMode
text: "+"
checkable: true
}
}
}
}
This diff is collapsed.
......@@ -39,76 +39,84 @@ class MissionItem : public QObject
Q_OBJECT
public:
MissionItem(
QObject *parent = 0,
quint16 id = 0,
double x = 0.0,
double y = 0.0,
double z = 0.0,
double param1 = 0.0,
double param2 = 0.0,
double param3 = 0.0,
double param4 = 0.0,
bool autocontinue = true,
bool current = false,
int frame = MAV_FRAME_GLOBAL,
int action = MAV_CMD_NAV_WAYPOINT,
const QString& description=QString(""));
MissionItem(QObject *parent = 0,
int sequenceNumber = 0,
QGeoCoordinate coordiante = QGeoCoordinate(),
double param1 = 0.0,
double param2 = 0.0,
double param3 = 0.0,
double param4 = 0.0,
bool autocontinue = true,
bool isCurrentItem = false,
int frame = MAV_FRAME_GLOBAL,
int action = MAV_CMD_NAV_WAYPOINT);
MissionItem(const MissionItem& other);
~MissionItem();
const MissionItem& operator=(const MissionItem& other);
Q_PROPERTY(bool hasCoordinate READ hasCoordinate NOTIFY hasCoordinateChanged)
Q_PROPERTY(QGeoCoordinate coordinate READ coordinate NOTIFY coordinateChanged)
Q_PROPERTY(QString commandName READ commandName NOTIFY commandNameChanged)
Q_PROPERTY(MavlinkQmlSingleton::Qml_MAV_CMD command READ command WRITE setCommand NOTIFY commandChanged)
Q_PROPERTY(int sequenceNumber READ sequenceNumber WRITE setSequenceNumber NOTIFY sequenceNumberChanged)
Q_PROPERTY(bool isCurrentItem READ isCurrentItem WRITE setIsCurrentItem NOTIFY isCurrentItemChanged)
Q_PROPERTY(bool specifiesCoordinate READ specifiesCoordinate NOTIFY specifiesCoordinateChanged)
Q_PROPERTY(QGeoCoordinate coordinate READ coordinate WRITE setCoordinate NOTIFY coordinateChanged)
Q_PROPERTY(double yaw READ yaw WRITE setYaw NOTIFY yawChanged)
Q_PROPERTY(QStringList commandNames READ commandNames CONSTANT)
Q_PROPERTY(QString commandName READ commandName NOTIFY commandChanged)
Q_PROPERTY(QStringList valueLabels READ valueLabels NOTIFY commandChanged)
Q_PROPERTY(QStringList valueStrings READ valueStrings NOTIFY valueStringsChanged)
Q_PROPERTY(int commandByIndex READ commandByIndex WRITE setCommandByIndex NOTIFY commandChanged)
Q_PROPERTY(MavlinkQmlSingleton::Qml_MAV_CMD command READ command WRITE setCommand NOTIFY commandChanged)
// Property accesors
int sequenceNumber(void) const { return _sequenceNumber; }
void setSequenceNumber(int sequenceNumber);
bool isCurrentItem(void) const { return _isCurrentItem; }
void setIsCurrentItem(bool isCurrentItem);
Q_PROPERTY(double longitude READ longitude NOTIFY longitudeChanged)
Q_PROPERTY(double latitude READ latitude NOTIFY latitudeChanged)
Q_PROPERTY(double altitude READ altitude NOTIFY altitudeChanged)
Q_PROPERTY(quint16 id READ id CONSTANT)
bool specifiesCoordinate(void) const;
Q_PROPERTY(QStringList valueLabels READ valueLabels NOTIFY commandChanged)
Q_PROPERTY(QStringList valueStrings READ valueStrings NOTIFY valueStringsChanged)
QGeoCoordinate coordinate(void) const { return _coordinate; }
void setCoordinate(const QGeoCoordinate& coordinate);
QStringList commandNames(void);
QString commandName(void);
double latitude() { return _x; }
double longitude() { return _y; }
double altitude() { return _z; }
quint16 id() { return _id; }
int commandByIndex(void);
void setCommandByIndex(int index);
MavlinkQmlSingleton::Qml_MAV_CMD command(void) { return (MavlinkQmlSingleton::Qml_MAV_CMD)getAction(); };
void setCommand(MavlinkQmlSingleton::Qml_MAV_CMD command) { setAction(command); }
QStringList valueLabels(void);
QStringList valueStrings(void);
// C++ only methods
quint16 getId() const {
return _id;
}
double getX() const {
return _x;
}
double getY() const {
return _y;
}
double getZ() const {
return _z;
}
double getLatitude() const {
return _x;
}
double getLongitude() const {
return _y;
}
double getAltitude() const {
return _z;
}
double getYaw() const {
return _yaw;
}
double latitude(void) const { return _coordinate.latitude(); }
double longitude(void) const { return _coordinate.longitude(); }
double altitude(void) const { return _coordinate.altitude(); }
void setLatitude(double latitude);
void setLongitude(double longitude);
void setAltitude(double altitude);
double x(void) const { return latitude(); }
double y(void) const { return longitude(); }
double z(void) const { return altitude(); }
void setX(double x);
void setY(double y);
void setZ(double z);
double yaw(void) const { return _yaw; }
void setYaw(double yaw);
bool getAutoContinue() const {
return _autocontinue;
}
bool getCurrent() const {
return _current;
}
double getLoiterOrbit() const {
return _orbit;
}
......@@ -128,16 +136,16 @@ public:
return _orbit;
}
double getParam4() const {
return _yaw;
return yaw();
}
double getParam5() const {
return _x;
return latitude();
}
double getParam6() const {
return _y;
return longitude();
}
double getParam7() const {
return _z;
return altitude();
}
int getTurns() const {
return _param1;
......@@ -150,13 +158,6 @@ public:
int getAction() const {
return _action;
}
const QString& getName() const {
return _name;
}
const QString& getDescription() const {
return _description;
}
/** @brief Returns true if x, y, z contain reasonable navigation data */
bool isNavigationType();
......@@ -166,47 +167,24 @@ public:
void save(QTextStream &saveStream);
bool load(QTextStream &loadStream);
bool hasCoordinate(void);
QGeoCoordinate coordinate(void);
QString commandName(void);
signals:
void sequenceNumberChanged(int sequenceNumber);
void specifiesCoordinateChanged(bool specifiesCoordinate);
void isCurrentItemChanged(bool isCurrentItem);
void coordinateChanged(const QGeoCoordinate& coordinate);
void yawChanged(double yaw);
/** @brief Announces a change to the waypoint data */
void changed(MissionItem* wp);
MavlinkQmlSingleton::Qml_MAV_CMD command(void) { return (MavlinkQmlSingleton::Qml_MAV_CMD)getAction(); };
void setCommand(MavlinkQmlSingleton::Qml_MAV_CMD command) { setAction(command); }
QStringList valueLabels(void);
QStringList valueStrings(void);
void commandNameChanged(QString type);
void commandChanged(MavlinkQmlSingleton::Qml_MAV_CMD command);
void valueLabelsChanged(QStringList valueLabels);
void valueStringsChanged(QStringList valueStrings);
protected:
quint16 _id;
double _x;
double _y;
double _z;
double _yaw;
int _frame;
int _action;
bool _autocontinue;
bool _current;
double _orbit;
double _param1;
double _param2;
int _turns;
QString _name;
QString _description;
quint64 _reachedTime;
public:
void setId (quint16 _id);
void setX (double _x);
void setY (double _y);
void setZ (double _z);
void setLatitude (double lat);
void setLongitude (double lon);
void setAltitude (double alt);
/** @brief Yaw angle in COMPASS DEGREES: 0-360 */
void setYaw (int _yaw);
/** @brief Yaw angle in COMPASS DEGREES: 0-360 */
void setYaw (double _yaw);
/** @brief Set the waypoint action */
void setAction (int _action);
void setFrame (int _frame);
......@@ -234,22 +212,30 @@ public:
emit changed(this);
}
signals:
/** @brief Announces a change to the waypoint data */
void changed(MissionItem* wp);
void latitudeChanged ();
void longitudeChanged ();
void altitudeChanged ();
void hasCoordinateChanged(bool hasCoordinate);
void coordinateChanged(void);
void commandNameChanged(QString type);
void commandChanged(MavlinkQmlSingleton::Qml_MAV_CMD command);
void valueLabelsChanged(QStringList valueLabels);
void valueStringsChanged(QStringList valueStrings);
private:
QString _oneDecimalString(double value);
private:
typedef struct {
MAV_CMD command;
const char* name;
} MavCmd2Name_t;
int _sequenceNumber;
QGeoCoordinate _coordinate;
double _yaw;
int _frame;
int _action;
bool _autocontinue;
bool _isCurrentItem;
double _orbit;
double _param1;
double _param2;
int _turns;
quint64 _reachedTime;
static const int _cMavCmd2Name = 9;
static const MavCmd2Name_t _rgMavCmd2Name[_cMavCmd2Name];
};
#endif
import QtQuick 2.2
import QtQuick.Controls 1.2
import QtQuick.Controls.Styles 1.2
import QGroundControl.ScreenTools 1.0
import QGroundControl.Vehicle 1.0
/// Mission item edit control
Rectangle {
property var missionItem
width: _editFieldWidth + (ScreenTools.defaultFontPixelWidth * 10)
height: _valueColumn.y + _valueColumn.height + (radius / 2)
border.width: 2
border.color: "white"
color: "white"
radius: ScreenTools.defaultFontPixelWidth
readonly property real _editFieldWidth: ScreenTools.defaultFontPixelWidth * 13
MissionItemIndexLabel {
id: _label
anchors.top: parent.top
anchors.right: parent.right
isCurrentItem: missionItem.isCurrentItem
label: missionItem.sequenceNumber
}
QGCComboBox {
id: _commandCombo
anchors.margins: parent.radius / 2
anchors.left: parent.left
anchors.right: _label.left
anchors.top: parent.top
currentIndex: missionItem.commandByIndex
model: missionItem.commandNames
onActivated: missionItem.commandByIndex = index
}
Column {
id: _coordinateColumn
anchors.left: parent.left
anchors.right: parent.right
visible: missionItem.specifiesCoordinate
}
QGCTextField {
id: _latitudeField
anchors.margins: parent.radius / 2
anchors.top: _commandCombo.bottom
anchors.right: parent.right
width: _editFieldWidth
text: missionItem.coordinate.latitude
visible: missionItem.specifiesCoordinate
onAccepted: missionItem.coordinate.latitude = text
}
QGCTextField {
id: _longitudeField
anchors.margins: parent.radius / 2
anchors.top: _latitudeField.bottom
anchors.right: parent.right
width: _editFieldWidth
text: missionItem.coordinate.longitude
visible: missionItem.specifiesCoordinate
onAccepted: missionItem.coordinate.longtitude = text
}
QGCTextField {
id: _altitudeField
anchors.margins: parent.radius / 2
anchors.top: _longitudeField.bottom