Commit 0adf8caa authored by Don Gagne's avatar Don Gagne

Mission Editor usability changes

parent 92cc42a1
...@@ -70,6 +70,7 @@ ...@@ -70,6 +70,7 @@
<file alias="Help.svg">src/FlightMap/Images/Help.svg</file> <file alias="Help.svg">src/FlightMap/Images/Help.svg</file>
<file alias="MapCenter.svg">src/FlightMap/Images/MapCenter.svg</file> <file alias="MapCenter.svg">src/FlightMap/Images/MapCenter.svg</file>
<file alias="MapSync.svg">src/FlightMap/Images/MapSync.svg</file> <file alias="MapSync.svg">src/FlightMap/Images/MapSync.svg</file>
<file alias="MapSyncChanged.svg">src/FlightMap/Images/MapSyncChanged.svg</file>
<file alias="MapType.svg">src/FlightMap/Images/MapType.svg</file> <file alias="MapType.svg">src/FlightMap/Images/MapType.svg</file>
<file alias="MapHome.svg">src/FlightMap/Images/MapHome.svg</file> <file alias="MapHome.svg">src/FlightMap/Images/MapHome.svg</file>
<file alias="MapAddMission.svg">src/FlightMap/Images/MapAddMission.svg</file> <file alias="MapAddMission.svg">src/FlightMap/Images/MapAddMission.svg</file>
......
...@@ -55,15 +55,14 @@ Item { ...@@ -55,15 +55,14 @@ Item {
property var _activeVehicle: multiVehicleManager.activeVehicle property var _activeVehicle: multiVehicleManager.activeVehicle
readonly property real _defaultLatitude: 37.803784 readonly property var _defaultVehicleCoordinate: QtPositioning.coordinate(37.803784, -122.462276)
readonly property real _defaultLongitude: -122.462276 readonly property real _defaultRoll: 0
readonly property real _defaultRoll: 0 readonly property real _defaultPitch: 0
readonly property real _defaultPitch: 0 readonly property real _defaultHeading: 0
readonly property real _defaultHeading: 0 readonly property real _defaultAltitudeWGS84: 0
readonly property real _defaultAltitudeWGS84: 0 readonly property real _defaultGroundSpeed: 0
readonly property real _defaultGroundSpeed: 0 readonly property real _defaultAirSpeed: 0
readonly property real _defaultAirSpeed: 0 readonly property real _defaultClimbRate: 0
readonly property real _defaultClimbRate: 0
readonly property string _mapName: "FlightDisplayView" readonly property string _mapName: "FlightDisplayView"
readonly property string _showMapBackgroundKey: "/showMapBackground" readonly property string _showMapBackgroundKey: "/showMapBackground"
...@@ -72,8 +71,7 @@ Item { ...@@ -72,8 +71,7 @@ Item {
property real _pitch: _activeVehicle ? (isNaN(_activeVehicle.pitch) ? _defaultPitch : _activeVehicle.pitch) : _defaultPitch property real _pitch: _activeVehicle ? (isNaN(_activeVehicle.pitch) ? _defaultPitch : _activeVehicle.pitch) : _defaultPitch
property real _heading: _activeVehicle ? (isNaN(_activeVehicle.heading) ? _defaultHeading : _activeVehicle.heading) : _defaultHeading property real _heading: _activeVehicle ? (isNaN(_activeVehicle.heading) ? _defaultHeading : _activeVehicle.heading) : _defaultHeading
property real _latitude: _activeVehicle ? ((_activeVehicle.latitude === 0) ? _defaultLatitude : _activeVehicle.latitude) : _defaultLatitude property var _vehicleCoordinate: _activeVehicle ? _activeVehicle.coordinate : _defaultVehicleCoordinate
property real _longitude: _activeVehicle ? ((_activeVehicle.longitude === 0) ? _defaultLongitude : _activeVehicle.longitude) : _defaultLongitude
property real _altitudeWGS84: _activeVehicle ? _activeVehicle.altitudeWGS84 : _defaultAltitudeWGS84 property real _altitudeWGS84: _activeVehicle ? _activeVehicle.altitudeWGS84 : _defaultAltitudeWGS84
property real _groundSpeed: _activeVehicle ? _activeVehicle.groundSpeed : _defaultGroundSpeed property real _groundSpeed: _activeVehicle ? _activeVehicle.groundSpeed : _defaultGroundSpeed
...@@ -82,14 +80,20 @@ Item { ...@@ -82,14 +80,20 @@ Item {
property bool _showMap: getBool(QGroundControl.flightMapSettings.loadMapSetting(flightMap.mapName, _showMapBackgroundKey, "1")) property bool _showMap: getBool(QGroundControl.flightMapSettings.loadMapSetting(flightMap.mapName, _showMapBackgroundKey, "1"))
FlightDisplayViewController { id: _controller; } FlightDisplayViewController { id: _controller }
ExclusiveGroup { ExclusiveGroup {
id: _dropButtonsExclusiveGroup id: _dropButtonsExclusiveGroup
} }
// Validate _showMap setting // Validate _showMap setting
Component.onCompleted: _setShowMap(_showMap) Component.onCompleted: {
// We have to be careful to not reference root properties in a function which is in a subcomponent
// until the root component has completed loading. Otherwise you get undefined references.
flightMap.rootLoadCompleted = true
flightMap.updateMapPosition(true /* force */)
_setShowMap(_showMap)
}
function getBool(value) { function getBool(value) {
return value === '0' ? false : true; return value === '0' ? false : true;
...@@ -104,24 +108,24 @@ Item { ...@@ -104,24 +108,24 @@ Item {
QGroundControl.flightMapSettings.saveMapSetting(flightMap.mapName, _showMapBackgroundKey, setBool(_showMap)) QGroundControl.flightMapSettings.saveMapSetting(flightMap.mapName, _showMapBackgroundKey, setBool(_showMap))
} }
FlightMap { FlightMap {
id: flightMap id: flightMap
anchors.fill: parent anchors.fill: parent
mapName: _mapName mapName: _mapName
visible: _showMap visible: _showMap
latitude: root._defaultCoordinate.latitude
longitude: root._defaultCoordinate.longitude
property real rootLatitude: root._latitude property var rootVehicleCoordinate: _vehicleCoordinate
property real rootLongitude: root._longitude property bool rootLoadCompleted: false
Component.onCompleted: updateMapPosition(true /* force */)
onRootLatitudeChanged: updateMapPosition(false /* force */) onRootVehicleCoordinateChanged: updateMapPosition(false /* force */)
onRootLongitudeChanged: updateMapPosition(false /* force */)
function updateMapPosition(force) { function updateMapPosition(force) {
if (_followVehicle || force) { if ((_followVehicle || force) && rootLoadCompleted) {
latitude = root._latitude flightMap.latitude = root._vehicleCoordinate.latitude
longitude = root._longitude flightMap.longitude = root._vehicleCoordinate.longitude
} }
} }
......
...@@ -59,10 +59,13 @@ Map { ...@@ -59,10 +59,13 @@ Map {
readonly property real zOrderWidgets: 100 ///< z order value to widgets, for example: zoom controls, hud widgetss readonly property real zOrderWidgets: 100 ///< z order value to widgets, for example: zoom controls, hud widgetss
readonly property real zOrderMapItems: 50 ///< z order value for map items, for example: mission item indicators readonly property real zOrderMapItems: 50 ///< z order value for map items, for example: mission item indicators
zoomLevel: 18 readonly property real maxZoomLevel: 20
center: QtPositioning.coordinate(lat, lon)
gesture.flickDeceleration: 3000 zoomLevel: 18
gesture.enabled: interactive center: QtPositioning.coordinate(lat, lon)
gesture.flickDeceleration: 3000
gesture.enabled: interactive
gesture.activeGestures: MapGestureArea.ZoomGesture | MapGestureArea.PanGesture | MapGestureArea.FlickGesture
plugin: Plugin { name: "QGroundControl" } plugin: Plugin { name: "QGroundControl" }
...@@ -295,11 +298,4 @@ Map { ...@@ -295,11 +298,4 @@ Map {
} }
} }
*/ */
MouseArea {
//-- TODO: Check if this is still needed when we switch to 5.5.1
//-- Workaround for QTBUG-46388 (Pinch zoom doesn't work without it on mobile)
anchors.fill: parent
}
} // Map } // Map
...@@ -45,9 +45,13 @@ QGCView { ...@@ -45,9 +45,13 @@ QGCView {
readonly property int _decimalPlaces: 7 readonly property int _decimalPlaces: 7
readonly property real _horizontalMargin: ScreenTools.defaultFontPixelWidth / 2 readonly property real _horizontalMargin: ScreenTools.defaultFontPixelWidth / 2
readonly property real _verticalMargin: ScreenTools.defaultFontPixelHeight / 2 readonly property real _margin: ScreenTools.defaultFontPixelHeight / 2
readonly property var _activeVehicle: multiVehicleManager.activeVehicle readonly property var _activeVehicle: multiVehicleManager.activeVehicle
readonly property real _editFieldWidth: ScreenTools.defaultFontPixelWidth * 16 readonly property real _editFieldWidth: ScreenTools.defaultFontPixelWidth * 16
readonly property real _rightPanelWidth: ScreenTools.defaultFontPixelWidth * 30
readonly property real _rightPanelOpacity: 0.8
readonly property int _toolButtonCount: 6
readonly property int _addMissionItemsButtonAutoOffTimeout: 10000
property var _missionItems: _controller.missionItems property var _missionItems: _controller.missionItems
...@@ -59,9 +63,11 @@ QGCView { ...@@ -59,9 +63,11 @@ QGCView {
property var liveHomePositionAvailable: _controller.liveHomePositionAvailable property var liveHomePositionAvailable: _controller.liveHomePositionAvailable
property var homePosition: offlineHomePosition // live or offline depending on state property var homePosition: offlineHomePosition // live or offline depending on state
property bool _syncNeeded: _controller.missionItems.dirty
MissionEditorController { id: _controller } MissionEditorController { id: _controller }
QGCPalette { id: _qgcPal; colorGroupEnabled: enabled } QGCPalette { id: qgcPal; colorGroupEnabled: enabled }
ExclusiveGroup { ExclusiveGroup {
id: _mapTypeButtonsExclusiveGroup id: _mapTypeButtonsExclusiveGroup
...@@ -69,7 +75,6 @@ QGCView { ...@@ -69,7 +75,6 @@ QGCView {
ExclusiveGroup { ExclusiveGroup {
id: _dropButtonsExclusiveGroup id: _dropButtonsExclusiveGroup
onCurrentChanged: console.log("Current button", current)
} }
function setCurrentItem(index) { function setCurrentItem(index) {
...@@ -107,10 +112,7 @@ QGCView { ...@@ -107,10 +112,7 @@ QGCView {
FlightMap { FlightMap {
id: editorMap id: editorMap
anchors.left: parent.left anchors.fill: parent
anchors.right: missionItemView.left
anchors.top: parent.top
anchors.bottom: parent.bottom
mapName: "MissionEditor" mapName: "MissionEditor"
Component.onCompleted: { Component.onCompleted: {
...@@ -118,6 +120,29 @@ QGCView { ...@@ -118,6 +120,29 @@ QGCView {
longitude = homePosition.longitude longitude = homePosition.longitude
} }
readonly property real animationDuration: 500
Behavior on zoomLevel {
NumberAnimation {
duration: editorMap.animationDuration
easing.type: Easing.InOutQuad
}
}
Behavior on latitude {
NumberAnimation {
duration: editorMap.animationDuration
easing.type: Easing.InOutQuad
}
}
Behavior on longitude {
NumberAnimation {
duration: editorMap.animationDuration
easing.type: Easing.InOutQuad
}
}
MouseArea { MouseArea {
anchors.fill: parent anchors.fill: parent
...@@ -130,245 +155,95 @@ QGCView { ...@@ -130,245 +155,95 @@ QGCView {
offlineHomePosition = coordinate offlineHomePosition = coordinate
} else if (addMissionItemsButton.checked) { } else if (addMissionItemsButton.checked) {
var index = _controller.addMissionItem(coordinate) var index = _controller.addMissionItem(coordinate)
addMissionItemsButtonAutoOffTimer.start()
setCurrentItem(index) setCurrentItem(index)
} else {
editorMap.zoomLevel = editorMap.maxZoomLevel - 2
} }
} }
} }
Rectangle { // We use this item to support dragging since dragging a MapQuickItem just doesn't seem to work
anchors.horizontalCenter: parent.horizontalCenter Item {
anchors.bottom: parent.bottom id: itemEditor
width: parent.width * 0.75 x: missionItemIndicator ? (missionItemIndicator.x + missionItemIndicator.anchorPoint.x - (itemEditor.width / 2)) : 100
height: syncNeededText.height + (ScreenTools.defaultFontPixelWidth * 2) y: missionItemIndicator ? (missionItemIndicator.y + missionItemIndicator.anchorPoint.y - (itemEditor.height / 2)) : 100
border.width: 1 width: ScreenTools.defaultFontPixelHeight * 7
border.color: "white" height: ScreenTools.defaultFontPixelHeight * 7
color: "black" visible: false
opacity: 0.75 z: editorMap.zOrderMapItems + 1 // Above item icons
visible: _controller.missionItems.dirty
property var missionItem
QGCLabel { property var missionItemIndicator
id: syncNeededText property real heading: missionItem ? missionItem.heading : 0
anchors.margins: ScreenTools.defaultFontPixelWidth
anchors.top: parent.top Drag.active: itemDrag.drag.active
anchors.left: parent.left Drag.hotSpot.x: width / 2
anchors.right: parent.right Drag.hotSpot.y: height / 2
wrapMode: Text.WordWrap
horizontalAlignment: Text.AlignHCenter MissionItemIndexLabel {
verticalAlignment: Text.AlignVCenter x: (itemEditor.width / 2) - (width / 2)
font.pixelSize: ScreenTools.mediumFontPixelSize y: (itemEditor.height / 2) - (height / 2)
text: "You have unsaved changes. Be sure to use the Sync tool to save when ready." label: itemEditor.missionItemIndicator ? itemEditor.missionItemIndicator.label : ""
} isCurrentItem: true
}
RoundButton {
id: addMissionItemsButton
anchors.rightMargin: ScreenTools.defaultFontPixelWidth
anchors.right: homePositionManagerButton.left
anchors.top: helpButton.top
buttonImage: "/qmlimages/MapAddMission.svg"
exclusiveGroup: _dropButtonsExclusiveGroup
}
RoundButton {
id: homePositionManagerButton
anchors.rightMargin: ScreenTools.defaultFontPixelWidth
anchors.right: centerMapButton.left
anchors.top: helpButton.top
buttonImage: "/qmlimages/MapHome.svg"
exclusiveGroup: _dropButtonsExclusiveGroup
}
DropButton {
id: centerMapButton
anchors.rightMargin: ScreenTools.defaultFontPixelWidth
anchors.right: syncButton.left
anchors.top: helpButton.top
dropDirection: dropDown
buttonImage: "/qmlimages/MapCenter.svg"
viewportMargins: ScreenTools.defaultFontPixelWidth / 2
exclusiveGroup: _dropButtonsExclusiveGroup
dropDownComponent: Component {
Row {
spacing: ScreenTools.defaultFontPixelWidth
QGCButton {
text: "Home"
onClicked: {
centerMapButton.hideDropDown()
editorMap.center = QtPositioning.coordinate(homePosition.latitude, homePosition.longitude)
}
}
QGCButton {
text: "Vehicle"
enabled: activeVehicle && activeVehicle.latitude != 0 && activeVehicle.longitude != 0
property var activeVehicle: multiVehicleManager.activeVehicle
onClicked: {
centerMapButton.hideDropDown()
editorMap.latitude = activeVehicle.latitude
editorMap.longitude = activeVehicle.longitude
}
}
/*
This code will need to wait for Qml 5.5 support since Map.visibleRegion is only in Qt 5.5
QGCButton {
text: "All Items"
onClicked: {
centerMapButton.hideDropDown()
// Begin with only the home position in the region
var region = QtPositioning.rectangle(QtPositioning.coordinate(homePosition.latitude, homePosition.longitude),
QtPositioning.coordinate(homePosition.latitude, homePosition.longitude))
// Now expand the region to include all mission items
for (var i=0; i<_missionItems.count; i++) {
var missionItem = _missionItems.get(i)
region.topLeft.latitude = Math.max(missionItem.coordinate.latitude, region.topLeft.latitude)
region.topLeft.longitude = Math.min(missionItem.coordinate.longitude, region.topLeft.longitude)
region.topRight.latitude = Math.max(missionItem.coordinate.latitude, region.topRight.latitude)
region.topRight.longitude = Math.max(missionItem.coordinate.longitude, region.topRight.longitude)
region.bottomLeft.latitude = Math.min(missionItem.coordinate.latitude, region.bottomLeft.latitude)
region.bottomLeft.longitude = Math.min(missionItem.coordinate.longitude, region.bottomLeft.longitude)
region.bottomRight.latitude = Math.min(missionItem.coordinate.latitude, region.bottomRight.latitude)
region.bottomRight.longitude = Math.max(missionItem.coordinate.longitude, region.bottomRight.longitude)
}
editorMap.visibleRegion = region
}
}
*/
}
}
}
DropButton {
id: syncButton
anchors.rightMargin: ScreenTools.defaultFontPixelWidth
anchors.right: mapTypeButton.left
anchors.top: helpButton.top
dropDirection: dropDown
buttonImage: "/qmlimages/MapSync.svg"
viewportMargins: ScreenTools.defaultFontPixelWidth / 2
exclusiveGroup: _dropButtonsExclusiveGroup
dropDownComponent: Component {
Row {
spacing: ScreenTools.defaultFontPixelWidth
QGCButton {
text: "Load from vehicle"
enabled: _activeVehicle && !_activeVehicle.missionManager.inProgress
onClicked: {
syncButton.hideDropDown()
_controller.getMissionItems()
}
}
QGCButton {
text: "Save to vehicle"
enabled: _activeVehicle && !_activeVehicle.missionManager.inProgress
onClicked: {
syncButton.hideDropDown()
_controller.setMissionItems()
}
}
QGCButton {
text: "Load from file..."
onClicked: {
syncButton.hideDropDown()
_controller.loadMissionFromFile()
}
}
QGCButton {
text: "Save to file..."
onClicked: {
syncButton.hideDropDown()
_controller.saveMissionToFile()
}
}
}
} }
}
DropButton {
id: mapTypeButton
anchors.rightMargin: ScreenTools.defaultFontPixelWidth
anchors.right: helpButton.left
anchors.top: helpButton.top
dropDirection: dropDown
buttonImage: "/qmlimages/MapType.svg"
viewportMargins: ScreenTools.defaultFontPixelWidth / 2
exclusiveGroup: _dropButtonsExclusiveGroup
dropDownComponent: Component { MouseArea {
Row { id: itemDrag
spacing: ScreenTools.defaultFontPixelWidth anchors.fill: parent
drag.target: parent
Repeater { property bool dragActive: drag.active
model: QGroundControl.flightMapSettings.mapTypes
QGCButton { onDragActiveChanged: {
checkable: true if (!drag.active) {
checked: editorMap.mapType == text var point = Qt.point(itemEditor.x + (itemEditor.width / 2), itemEditor.y + (itemEditor.height / 2))
text: modelData itemEditor.missionItem.coordinate = editorMap.toCoordinate(point)
exclusiveGroup: _mapTypeButtonsExclusiveGroup
onClicked: {
editorMap.mapType = text
checked = true
mapTypeButton.hideDropDown()
}
}
} }
} }
} }
} }
RoundButton {
id: helpButton
anchors.margins: ScreenTools.defaultFontPixelWidth
anchors.right: parent.right
anchors.top: parent.top
buttonImage: "/qmlimages/Help.svg"
exclusiveGroup: _dropButtonsExclusiveGroup
}
// Add the mission items to the map // Add the mission items to the map
MapItemView { MapItemView {
model: _controller.missionItems model: _controller.missionItems
delegate: delegate:
MissionItemIndicator { MissionItemIndicator {
id: itemIndicator id: itemIndicator
label: object.sequenceNumber == 0 ? (liveHomePositionAvailable ? "H" : "F") : object.sequenceNumber label: object.sequenceNumber == 0 ? (liveHomePositionAvailable ? "H" : "F") : object.sequenceNumber
isCurrentItem: !homePositionManagerButton.checked && object.isCurrentItem isCurrentItem: !homePositionManagerButton.checked && object.isCurrentItem
coordinate: object.coordinate coordinate: object.coordinate
z: 2 z: editorMap.zOrderMapItems
visible: object.specifiesCoordinate visible: object.specifiesCoordinate
onClicked: { onClicked: setCurrentItem(object.sequenceNumber)
setCurrentItem(object.sequenceNumber)
missionItemEditorButton.checked Connections {
target: object
onIsCurrentItemChanged: {
if (isCurrentItem) {
// Setup our drag item
if (object.sequenceNumber != 0) {
itemEditor.visible = true
itemEditor.missionItem = Qt.binding(function() { return object })
itemEditor.missionItemIndicator = Qt.binding(function() { return itemIndicator })
} else {
itemEditor.visible = false
itemEditor.missionItem = undefined
itemEditor.missionItemIndicator = undefined
}
// Zoom the map and move to the new position
editorMap.zoomLevel = editorMap.maxZoomLevel
editorMap.latitude = object.coordinate.latitude
editorMap.longitude = object.coordinate.longitude
}
}
} }
// These are the non-coordinate child mission items attached to this item
Row { Row {
anchors.top: parent.top anchors.top: parent.top
anchors.left: parent.right anchors.left: parent.right
...@@ -400,8 +275,8 @@ QGCView { ...@@ -400,8 +275,8 @@ QGCView {
delegate: delegate:
MapPolyline { MapPolyline {
line.width: 3 line.width: 3
line.color: _qgcPal.mapButtonHighlight line.color: qgcPal.mapButtonHighlight
z: 1 z: editorMap.zOrderMapItems - 1 // Under item indicators
path: [ path: [
{ latitude: object.coordinate1.latitude, longitude: object.coordinate1.longitude }, { latitude: object.coordinate1.latitude, longitude: object.coordinate1.longitude },
...@@ -410,346 +285,341 @@ QGCView { ...@@ -410,346 +285,341 @@ QGCView {
} }
} }
Column { // Mission Item Editor
id: controlWidgets
anchors.margins: ScreenTools.defaultFontPixelWidth
anchors.right: parent.left
anchors.bottom: parent.top
spacing: ScreenTools.defaultFontPixelWidth / 2
QGCButton {
id: addMode
text: "+"
checkable: true
}
}
} // FlightMap
Rectangle {
id: missionItemView
anchors.right: parent.right
anchors.top: parent.top
anchors.bottom: parent.bottom
width: ScreenTools.defaultFontPixelWidth * 30
color: _qgcPal.window
Item { Item {
anchors.margins: _verticalMargin id: missionItemEditor
anchors.fill: parent anchors.top: parent.top
anchors.bottom: parent.bottom
// Mission Item Editor anchors.right: parent.right
Item { width: _rightPanelWidth
id: missionItemEditor visible: !helpButton.checked && !homePositionManagerButton.checked && _missionItems.count > 1
opacity: _rightPanelOpacity
z: editorMap.zOrderTopMost
ListView {
id: missionItemSummaryList
anchors.fill: parent anchors.fill: parent
visible: !helpButton.checked && !homePositionManagerButton.checked && _missionItems.count > 1 spacing: _margin / 2
orientation: ListView.Vertical
ListView { model: _controller.canEdit ? _controller.missionItems : 0
id: missionItemSummaryList
anchors.fill: parent property real _maxItemHeight: 0
spacing: _verticalMargin
orientation: ListView.Vertical delegate:
model: _controller.canEdit ? _controller.missionItems : 0 MissionItemEditor {
missionItem: object
property real _maxItemHeight: 0 width: parent.width
readOnly: object.sequenceNumber == 0 && liveHomePositionAvailable
delegate:
MissionItemEditor { onClicked: setCurrentItem(object.sequenceNumber)
missionItem: object
width: parent.width onRemove: {
readOnly: object.sequenceNumber == 0 && liveHomePositionAvailable var newCurrentItem = object.sequenceNumber - 1
_controller.removeMissionItem(object.sequenceNumber)
onClicked: setCurrentItem(object.sequenceNumber) if (_missionItems.count > 1) {
newCurrentItem = Math.min(_missionItems.count - 1, newCurrentItem)
onRemove: { setCurrentItem(newCurrentItem)
var newCurrentItem = object.sequenceNumber - 1
_controller.removeMissionItem(object.sequenceNumber)
if (_missionItems.count > 1) {
newCurrentItem = Math.min(_missionItems.count - 1, newCurrentItem)
setCurrentItem(newCurrentItem)
}
}
} }
} // ListView }
QGCLabel {
anchors.fill: parent
visible: !_controller.canEdit
wrapMode: Text.WordWrap
text: "The set of mission items you have loaded cannot be edited by QGroundControl. " +
"You will only be able to save these to a file, or send them to a vehicle."
} }
} // Item - Mission Item editor } // ListView
// Home Position Manager QGCLabel {
Item {
id: homePositionManager
anchors.fill: parent anchors.fill: parent
visible: homePositionManagerButton.checked visible: !_controller.canEdit
wrapMode: Text.WordWrap
text: "The set of mission items you have loaded cannot be edited by QGroundControl. " +
"You will only be able to save these to a file, or send them to a vehicle."
}
} // Item - Mission Item editor
Column { // Home Position Manager
anchors.fill: parent Rectangle {
visible: !liveHomePositionAvailable id: homePositionManager
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.right: parent.right
width: _rightPanelWidth
visible: homePositionManagerButton.checked
color: qgcPal.window
opacity: _rightPanelOpacity
z: editorMap.zOrderTopMost
Column {
anchors.margins: _margin
anchors.fill: parent
visible: !liveHomePositionAvailable
QGCLabel { QGCLabel {
font.pixelSize: ScreenTools.mediumFontPixelSize font.pixelSize: ScreenTools.mediumFontPixelSize
text: "Flying Field Manager" text: "Flying Field Manager"
} }
Item { Item {
width: 10 width: 10
height: ScreenTools.defaultFontPixelHeight height: ScreenTools.defaultFontPixelHeight
} }
QGCLabel { QGCLabel {
width: parent.width width: parent.width
wrapMode: Text.WordWrap wrapMode: Text.WordWrap
text: "This is used to save locations associated with your flying field for use while creating missions with no vehicle connection." text: "This is used to save locations associated with your flying field for use while creating missions with no vehicle connection."
} }
Item { Item {
width: 10 width: 10
height: ScreenTools.defaultFontPixelHeight height: ScreenTools.defaultFontPixelHeight
} }
QGCLabel { QGCLabel {
text: "Select field to use:" text: "Select field to use:"
} }
QGCComboBox { QGCComboBox {
id: homePosCombo id: homePosCombo
width: parent.width width: parent.width
textRole: "text" textRole: "text"
model: _homePositionManager.homePositions model: _homePositionManager.homePositions
onCurrentIndexChanged: { onCurrentIndexChanged: {
if (currentIndex != -1) { if (currentIndex != -1) {
var homePos = _homePositionManager.homePositions.get(currentIndex) var homePos = _homePositionManager.homePositions.get(currentIndex)
_homePositionName = homePos.name _homePositionName = homePos.name
offlineHomePosition = homePos.coordinate offlineHomePosition = homePos.coordinate
editorMap.latitude = offlineHomePosition.latitude editorMap.latitude = offlineHomePosition.latitude
editorMap.longitude = offlineHomePosition.longitude editorMap.longitude = offlineHomePosition.longitude
}
} }
} }
}
Item { Item {
width: 10 width: 10
height: ScreenTools.defaultFontPixelHeight height: ScreenTools.defaultFontPixelHeight
} }
QGCLabel {
width: parent.width
wrapMode: Text.WordWrap
text: "To add a new flying field, click on the Map to set the position. " +
"Then give it a new name and click Add/Update. " +
"To change the current field position, click on the Map to set the new position. " +
"Then click Add/Update without changing the name."
}
Item { QGCLabel {
width: 10 width: parent.width
height: ScreenTools.defaultFontPixelHeight / 3 wrapMode: Text.WordWrap
} text: "To add a new flying field, click on the Map to set the position. " +
"Then give it a new name and click Add/Update. " +
"To change the current field position, click on the Map to set the new position. " +
"Then click Add/Update without changing the name."
}
Item { Item {
width: parent.width width: 10
height: nameField.height height: ScreenTools.defaultFontPixelHeight / 3
}
QGCLabel { Item {
anchors.baseline: nameField.baseline width: parent.width
text: "Name:" height: nameField.height
}
QGCTextField { QGCLabel {
id: nameField anchors.baseline: nameField.baseline
anchors.right: parent.right text: "Name:"
width: _editFieldWidth
text: _homePositionName
}
} }
Item { QGCTextField {
width: 10 id: nameField
height: ScreenTools.defaultFontPixelHeight / 3 anchors.right: parent.right
width: _editFieldWidth
text: _homePositionName
} }
}
Item { Item {
width: parent.width width: 10
height: offlineLatitudeField.height height: ScreenTools.defaultFontPixelHeight / 3
}
QGCLabel { Item {
anchors.baseline: offlineLatitudeField.baseline width: parent.width
text: "Lat:" height: offlineLatitudeField.height
}
QGCTextField { QGCLabel {
id: offlineLatitudeField anchors.baseline: offlineLatitudeField.baseline
anchors.right: parent.right text: "Lat:"
width: _editFieldWidth
text: offlineHomePosition.latitude
}
} }
Item { QGCTextField {
width: 10 id: offlineLatitudeField
height: ScreenTools.defaultFontPixelHeight / 3 anchors.right: parent.right
width: _editFieldWidth
text: offlineHomePosition.latitude
} }
}
Item { Item {
width: parent.width width: 10
height: offlineLongitudeField.height height: ScreenTools.defaultFontPixelHeight / 3
}
QGCLabel { Item {
anchors.baseline: offlineLongitudeField.baseline width: parent.width
text: "Lon:" height: offlineLongitudeField.height
}
QGCTextField { QGCLabel {
id: offlineLongitudeField anchors.baseline: offlineLongitudeField.baseline
anchors.right: parent.right text: "Lon:"
width: _editFieldWidth
text: offlineHomePosition.longitude
}
} }
Item { QGCTextField {
width: 10 id: offlineLongitudeField
height: ScreenTools.defaultFontPixelHeight / 3 anchors.right: parent.right
width: _editFieldWidth
text: offlineHomePosition.longitude
} }
}
Item { Item {
width: parent.width width: 10
height: offlineAltitudeField.height height: ScreenTools.defaultFontPixelHeight / 3
}
QGCLabel { Item {
anchors.baseline: offlineAltitudeField.baseline width: parent.width
text: "Alt:" height: offlineAltitudeField.height
}
QGCTextField { QGCLabel {
id: offlineAltitudeField anchors.baseline: offlineAltitudeField.baseline
anchors.right: parent.right text: "Alt:"
width: _editFieldWidth
text: offlineHomePosition.altitude
}
} }
Item { QGCTextField {
width: 10 id: offlineAltitudeField
height: ScreenTools.defaultFontPixelHeight anchors.right: parent.right
width: _editFieldWidth
text: offlineHomePosition.altitude
} }
}
Row { Item {
spacing: ScreenTools.defaultFontPixelWidth width: 10
height: ScreenTools.defaultFontPixelHeight
QGCButton { }
text: "Add/Update"
onClicked: { Row {
offlineHomePosition = QtPositioning.coordinate(latitudeField.text, longitudeField.text, altitudeField.text) spacing: ScreenTools.defaultFontPixelWidth
_homePositionManager.updateHomePosition(nameField.text, offlineHomePosition)
homePosCombo.currentIndex = homePosCombo.find(nameField.text)
}
}
QGCButton { QGCButton {
text: "Delete" text: "Add/Update"
onClicked: { onClicked: {
homePosCombo.currentIndex = -1 offlineHomePosition = QtPositioning.coordinate(latitudeField.text, longitudeField.text, altitudeField.text)
_homePositionManager.deleteHomePosition(nameField.text) _homePositionManager.updateHomePosition(nameField.text, offlineHomePosition)
homePosCombo.currentIndex = 0 homePosCombo.currentIndex = homePosCombo.find(nameField.text)
var homePos = _homePositionManager.homePositions.get(0)
_homePositionName = homePos.name
offlineHomePosition = homePos.coordinate
}
} }
} }
} // Column - Offline view
Column { QGCButton {
anchors.fill: parent text: "Delete"
visible: liveHomePositionAvailable
QGCLabel { onClicked: {
font.pixelSize: ScreenTools.mediumFontPixelSize homePosCombo.currentIndex = -1
text: "Vehicle Home Position" _homePositionManager.deleteHomePosition(nameField.text)
homePosCombo.currentIndex = 0
var homePos = _homePositionManager.homePositions.get(0)
_homePositionName = homePos.name
offlineHomePosition = homePos.coordinate
}
} }
}
} // Column - Offline view
Item { Column {
width: 10 anchors.margins: _margin
height: ScreenTools.defaultFontPixelHeight anchors.fill: parent
} visible: liveHomePositionAvailable
Item { QGCLabel {
width: parent.width font.pixelSize: ScreenTools.mediumFontPixelSize
height: liveLatitudeField.height text: "Vehicle Home Position"
}
QGCLabel { Item {
anchors.baseline: liveLatitudeField.baseline width: 10
text: "Lat:" height: ScreenTools.defaultFontPixelHeight
} }
QGCLabel { Item {
id: liveLatitudeField width: parent.width
anchors.right: parent.right height: liveLatitudeField.height
width: _editFieldWidth
text: liveHomePosition.latitude QGCLabel {
} anchors.baseline: liveLatitudeField.baseline
text: "Lat:"
} }
Item { QGCLabel {
width: 10 id: liveLatitudeField
height: ScreenTools.defaultFontPixelHeight / 3 anchors.right: parent.right
width: _editFieldWidth
text: liveHomePosition.latitude
} }
}
Item { Item {
width: parent.width width: 10
height: liveLongitudeField.height height: ScreenTools.defaultFontPixelHeight / 3
}
QGCLabel { Item {
anchors.baseline: liveLongitudeField.baseline width: parent.width
text: "Lon:" height: liveLongitudeField.height
}
QGCLabel { QGCLabel {
id: liveLongitudeField anchors.baseline: liveLongitudeField.baseline
anchors.right: parent.right text: "Lon:"
width: _editFieldWidth
text: liveHomePosition.longitude
}
} }
Item { QGCLabel {
width: 10 id: liveLongitudeField
height: ScreenTools.defaultFontPixelHeight / 3 anchors.right: parent.right
width: _editFieldWidth
text: liveHomePosition.longitude
} }
}
Item { Item {
width: parent.width width: 10
height: liveAltitudeField.height height: ScreenTools.defaultFontPixelHeight / 3
}
QGCLabel { Item {
anchors.baseline: liveAltitudeField.baseline width: parent.width
text: "Alt:" height: liveAltitudeField.height
}
QGCLabel { QGCLabel {
id: liveAltitudeField anchors.baseline: liveAltitudeField.baseline
anchors.right: parent.right text: "Alt:"
width: _editFieldWidth
text: liveHomePosition.altitude
}
} }
} // Column - Online view
} // Item - Home Position Manager QGCLabel {
id: liveAltitudeField
anchors.right: parent.right
width: _editFieldWidth
text: liveHomePosition.altitude
}
}
} // Column - Online view
} // Item - Home Position Manager
// Help Panel
Rectangle {
id: helpPanel
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.right: parent.right
width: _rightPanelWidth
visible: !homePositionManagerButton.checked && (_missionItems.count == 1 || helpButton.checked)
color: qgcPal.window
opacity: _rightPanelOpacity
z: editorMap.zOrderTopMost
// Help Panel
Item { Item {
id: helpPanel anchors.margins: _margin
anchors.fill: parent anchors.fill: parent
visible: !homePositionManagerButton.checked && (_missionItems.count == 1 || helpButton.checked)
QGCLabel { QGCLabel {
id: helpTitle id: helpTitle
...@@ -876,9 +746,210 @@ QGCView { ...@@ -876,9 +746,210 @@ QGCView {
text: "<b>Map Type</b><br>" + text: "<b>Map Type</b><br>" +
"Map type options." "Map type options."
} }
} // Item - Help Panel } // Item - margin
} // Item } // Item - Help Panel
} // Rectangle - mission item list
RoundButton {
id: addMissionItemsButton
anchors.margins: _margin
anchors.left: parent.left
y: (parent.height - (_toolButtonCount * height) - ((_toolButtonCount - 1) * _margin)) / 2
buttonImage: "/qmlimages/MapAddMission.svg"
exclusiveGroup: _dropButtonsExclusiveGroup
onCheckedChanged: {
if (checked) {
addMissionItemsButtonAutoOffTimer.start()
} else {
addMissionItemsButtonAutoOffTimer.stop()
}
}
Timer {
id: addMissionItemsButtonAutoOffTimer
interval: _addMissionItemsButtonAutoOffTimeout
repeat: false
onTriggered: addMissionItemsButton.checked = false
}
}
RoundButton {
id: homePositionManagerButton
anchors.margins: _margin
anchors.left: parent.left
anchors.top: addMissionItemsButton.bottom
buttonImage: "/qmlimages/MapHome.svg"
exclusiveGroup: _dropButtonsExclusiveGroup
z: editorMap.zOrderWidgets
}
DropButton {
id: centerMapButton
anchors.margins: _margin
anchors.left: parent.left
anchors.top: homePositionManagerButton.bottom
dropDirection: dropRight
buttonImage: "/qmlimages/MapCenter.svg"
viewportMargins: ScreenTools.defaultFontPixelWidth / 2
exclusiveGroup: _dropButtonsExclusiveGroup
z: editorMap.zOrderWidgets
dropDownComponent: Component {
Column {
QGCLabel { text: "Center map:" }
Row {
spacing: ScreenTools.defaultFontPixelWidth
QGCButton {
text: "Home"
onClicked: {
centerMapButton.hideDropDown()
editorMap.center = QtPositioning.coordinate(homePosition.latitude, homePosition.longitude)
}
}
QGCButton {
text: "Vehicle"
enabled: activeVehicle && activeVehicle.latitude != 0 && activeVehicle.longitude != 0
property var activeVehicle: multiVehicleManager.activeVehicle
onClicked: {
centerMapButton.hideDropDown()
editorMap.latitude = activeVehicle.latitude
editorMap.longitude = activeVehicle.longitude
}
}
}
}
}
}
DropButton {
id: syncButton
anchors.margins: _margin
anchors.left: parent.left
anchors.top: centerMapButton.bottom
dropDirection: dropRight
buttonImage: _syncNeeded ? "/qmlimages/MapSyncChanged.svg" : "/qmlimages/MapSync.svg"
viewportMargins: ScreenTools.defaultFontPixelWidth / 2
exclusiveGroup: _dropButtonsExclusiveGroup
z: editorMap.zOrderWidgets
dropDownComponent: Component {
Column {
id: columnHolder
spacing: _margin
QGCLabel {
width: columnHolder.width
wrapMode: Text.WordWrap
text: _syncNeeded ?
"You have unsaved changed to you mission. You should send to your vehicle, or save to a file:" :
"Sync:"
}
Row {
spacing: ScreenTools.defaultFontPixelWidth
QGCButton {
text: "Send to vehicle"
enabled: _activeVehicle && !_activeVehicle.missionManager.inProgress
onClicked: {
syncButton.hideDropDown()
_controller.setMissionItems()
}
}
QGCButton {
text: "Load from vehicle"
enabled: _activeVehicle && !_activeVehicle.missionManager.inProgress
onClicked: {
syncButton.hideDropDown()
_controller.getMissionItems()
}
}
}
Row {
spacing: ScreenTools.defaultFontPixelWidth
QGCButton {
text: "Save to file..."
onClicked: {
syncButton.hideDropDown()
_controller.saveMissionToFile()
}
}
QGCButton {
text: "Load from file..."
onClicked: {
syncButton.hideDropDown()
_controller.loadMissionFromFile()
}
}
}
}
}
}
DropButton {
id: mapTypeButton
anchors.margins: _margin
anchors.left: parent.left
anchors.top: syncButton.bottom
dropDirection: dropRight
buttonImage: "/qmlimages/MapType.svg"
viewportMargins: ScreenTools.defaultFontPixelWidth / 2
exclusiveGroup: _dropButtonsExclusiveGroup
z: editorMap.zOrderWidgets
dropDownComponent: Component {
Column {
QGCLabel { text: "Map type:" }
Row {
spacing: ScreenTools.defaultFontPixelWidth
Repeater {
model: QGroundControl.flightMapSettings.mapTypes
QGCButton {
checkable: true
checked: editorMap.mapType == text
text: modelData
exclusiveGroup: _mapTypeButtonsExclusiveGroup
onClicked: {
editorMap.mapType = text
checked = true
mapTypeButton.hideDropDown()
}
}
}
}
}
}
}
RoundButton {
id: helpButton
anchors.margins: _margin
anchors.left: parent.left
anchors.top: mapTypeButton.bottom
buttonImage: "/qmlimages/Help.svg"
exclusiveGroup: _dropButtonsExclusiveGroup
z: editorMap.zOrderWidgets
}
} // FlightMap
} // Item - split view container } // Item - split view container
} // QGCViewPanel } // QGCViewPanel
} // QGCVIew } // QGCVIew
...@@ -103,14 +103,15 @@ int MissionEditorController::addMissionItem(QGeoCoordinate coordinate) ...@@ -103,14 +103,15 @@ int MissionEditorController::addMissionItem(QGeoCoordinate coordinate)
if (!_canEdit) { if (!_canEdit) {
qWarning() << "addMissionItem called with _canEdit == false"; qWarning() << "addMissionItem called with _canEdit == false";
} }
// Coordinate will come through without altitude
coordinate.setAltitude(MissionItem::defaultAltitude);
MissionItem * newItem = new MissionItem(this, _missionItems->count(), coordinate, MAV_CMD_NAV_WAYPOINT); MissionItem * newItem = new MissionItem(this, _missionItems->count(), coordinate, MAV_CMD_NAV_WAYPOINT);
_initMissionItem(newItem); _initMissionItem(newItem);
newItem->setAltitude(30);
if (_missionItems->count() == 1) { if (_missionItems->count() == 1) {
newItem->setCommand(MavlinkQmlSingleton::MAV_CMD_NAV_TAKEOFF); newItem->setCommand(MavlinkQmlSingleton::MAV_CMD_NAV_TAKEOFF);
} }
qDebug() << "MissionItem" << newItem->coordinate();
_missionItems->append(newItem); _missionItems->append(newItem);
_recalcAll(); _recalcAll();
......
...@@ -36,6 +36,13 @@ This file is part of the QGROUNDCONTROL project ...@@ -36,6 +36,13 @@ This file is part of the QGROUNDCONTROL project
QGC_LOGGING_CATEGORY(MissionItemLog, "MissionItemLog") QGC_LOGGING_CATEGORY(MissionItemLog, "MissionItemLog")
const double MissionItem::defaultPitch = 15.0;
const double MissionItem::defaultHeading = 0.0;
const double MissionItem::defaultAltitude = 25.0;
const double MissionItem::defaultAcceptanceRadius = 3.0;
const double MissionItem::defaultLoiterOrbitRadius = 10.0;
const double MissionItem::defaultLoiterTurns = 1.0;
QDebug operator<<(QDebug dbg, const MissionItem& missionItem) QDebug operator<<(QDebug dbg, const MissionItem& missionItem)
{ {
QDebugStateSaver saver(dbg); QDebugStateSaver saver(dbg);
...@@ -82,14 +89,14 @@ MissionItem::MissionItem(QObject* parent, ...@@ -82,14 +89,14 @@ MissionItem::MissionItem(QObject* parent,
, _autocontinue(autocontinue) , _autocontinue(autocontinue)
, _isCurrentItem(isCurrentItem) , _isCurrentItem(isCurrentItem)
, _reachedTime(0) , _reachedTime(0)
, _yawRadiansFact(NULL) , _headingDegreesFact(NULL)
,_dirty(false) ,_dirty(false)
, _homePositionSpecialCase(false) , _homePositionSpecialCase(false)
{ {
_latitudeFact = new Fact(0, "Latitude:", FactMetaData::valueTypeDouble, this); _latitudeFact = new Fact(0, "Latitude:", FactMetaData::valueTypeDouble, this);
_longitudeFact = new Fact(0, "Longitude:", FactMetaData::valueTypeDouble, this); _longitudeFact = new Fact(0, "Longitude:", FactMetaData::valueTypeDouble, this);
_altitudeFact = new Fact(0, "Altitude:", FactMetaData::valueTypeDouble, this); _altitudeFact = new Fact(0, "Altitude:", FactMetaData::valueTypeDouble, this);
_yawRadiansFact = new Fact(0, "Heading:", FactMetaData::valueTypeDouble, this); _headingDegreesFact = new Fact(0, "Heading:", FactMetaData::valueTypeDouble, this);
_loiterOrbitRadiusFact = new Fact(0, "Radius:", FactMetaData::valueTypeDouble, this); _loiterOrbitRadiusFact = new Fact(0, "Radius:", FactMetaData::valueTypeDouble, this);
_param1Fact = new Fact(0, QString(), FactMetaData::valueTypeDouble, this); _param1Fact = new Fact(0, QString(), FactMetaData::valueTypeDouble, this);
_param2Fact = new Fact(0, QString(), FactMetaData::valueTypeDouble, this); _param2Fact = new Fact(0, QString(), FactMetaData::valueTypeDouble, this);
...@@ -100,7 +107,7 @@ MissionItem::MissionItem(QObject* parent, ...@@ -100,7 +107,7 @@ MissionItem::MissionItem(QObject* parent,
setCoordinate(coordinate); setCoordinate(coordinate);
setParam1(param1); setParam1(param1);
setParam2(param2); setParam2(param2);
setYawRadians(param4); _setYawRadians(param4);
setLoiterOrbitRadius(param3); setLoiterOrbitRadius(param3);
// FIXME: Need to fill out more meta data // FIXME: Need to fill out more meta data
...@@ -114,8 +121,8 @@ MissionItem::MissionItem(QObject* parent, ...@@ -114,8 +121,8 @@ MissionItem::MissionItem(QObject* parent,
FactMetaData* altitudeMetaData = new FactMetaData(FactMetaData::valueTypeDouble, _altitudeFact); FactMetaData* altitudeMetaData = new FactMetaData(FactMetaData::valueTypeDouble, _altitudeFact);
altitudeMetaData->setUnits("meters"); altitudeMetaData->setUnits("meters");
FactMetaData* yawMetaData = new FactMetaData(FactMetaData::valueTypeDouble, _yawRadiansFact); FactMetaData* headingMetaData = new FactMetaData(FactMetaData::valueTypeDouble, _headingDegreesFact);
yawMetaData->setUnits("deg"); headingMetaData->setUnits("deg");
_pitchMetaData = new FactMetaData(FactMetaData::valueTypeDouble, this); _pitchMetaData = new FactMetaData(FactMetaData::valueTypeDouble, this);
_pitchMetaData->setUnits("deg"); _pitchMetaData->setUnits("deg");
...@@ -147,23 +154,10 @@ MissionItem::MissionItem(QObject* parent, ...@@ -147,23 +154,10 @@ MissionItem::MissionItem(QObject* parent,
_latitudeFact->setMetaData(latitudeMetaData); _latitudeFact->setMetaData(latitudeMetaData);
_longitudeFact->setMetaData(longitudeMetaData); _longitudeFact->setMetaData(longitudeMetaData);
_altitudeFact->setMetaData(altitudeMetaData); _altitudeFact->setMetaData(altitudeMetaData);
_yawRadiansFact->setMetaData(yawMetaData); _headingDegreesFact->setMetaData(headingMetaData);
_loiterOrbitRadiusFact->setMetaData(loiterOrbitRadiusMetaData); _loiterOrbitRadiusFact->setMetaData(loiterOrbitRadiusMetaData);
// Connect to valueChanged to track dirty state _connectSignals();
connect(_latitudeFact, &Fact::valueChanged, this, &MissionItem::_factValueChanged);
connect(_longitudeFact, &Fact::valueChanged, this, &MissionItem::_factValueChanged);
connect(_altitudeFact, &Fact::valueChanged, this, &MissionItem::_factValueChanged);
connect(_yawRadiansFact, &Fact::valueChanged, this, &MissionItem::_factValueChanged);
connect(_loiterOrbitRadiusFact, &Fact::valueChanged, this, &MissionItem::_factValueChanged);
connect(_param1Fact, &Fact::valueChanged, this, &MissionItem::_factValueChanged);
connect(_param2Fact, &Fact::valueChanged, this, &MissionItem::_factValueChanged);
connect(_altitudeRelativeToHomeFact, &Fact::valueChanged, this, &MissionItem::_factValueChanged);
// Connect valueChanged signals so we can output coordinateChanged signal
connect(_latitudeFact, &Fact::valueChanged, this, &MissionItem::_coordinateFactChanged);
connect(_longitudeFact, &Fact::valueChanged, this, &MissionItem::_coordinateFactChanged);
connect(_altitudeFact, &Fact::valueChanged, this, &MissionItem::_coordinateFactChanged);
} }
MissionItem::MissionItem(const MissionItem& other, QObject* parent) MissionItem::MissionItem(const MissionItem& other, QObject* parent)
...@@ -172,7 +166,7 @@ MissionItem::MissionItem(const MissionItem& other, QObject* parent) ...@@ -172,7 +166,7 @@ MissionItem::MissionItem(const MissionItem& other, QObject* parent)
_latitudeFact = new Fact(this); _latitudeFact = new Fact(this);
_longitudeFact = new Fact(this); _longitudeFact = new Fact(this);
_altitudeFact = new Fact(this); _altitudeFact = new Fact(this);
_yawRadiansFact = new Fact(this); _headingDegreesFact = new Fact(this);
_loiterOrbitRadiusFact = new Fact(this); _loiterOrbitRadiusFact = new Fact(this);
_param1Fact = new Fact(this); _param1Fact = new Fact(this);
_param2Fact = new Fact(this); _param2Fact = new Fact(this);
...@@ -188,26 +182,9 @@ MissionItem::MissionItem(const MissionItem& other, QObject* parent) ...@@ -188,26 +182,9 @@ MissionItem::MissionItem(const MissionItem& other, QObject* parent)
_jumpSequenceMetaData = new FactMetaData(this); _jumpSequenceMetaData = new FactMetaData(this);
_jumpRepeatMetaData = new FactMetaData(this); _jumpRepeatMetaData = new FactMetaData(this);
// Connect to valueChanged to track dirty state _connectSignals();
connect(_latitudeFact, &Fact::valueChanged, this, &MissionItem::_factValueChanged);
connect(_longitudeFact, &Fact::valueChanged, this, &MissionItem::_factValueChanged);
connect(_altitudeFact, &Fact::valueChanged, this, &MissionItem::_factValueChanged);
connect(_yawRadiansFact, &Fact::valueChanged, this, &MissionItem::_factValueChanged);
connect(_loiterOrbitRadiusFact, &Fact::valueChanged, this, &MissionItem::_factValueChanged);
connect(_param1Fact, &Fact::valueChanged, this, &MissionItem::_factValueChanged);
connect(_param2Fact, &Fact::valueChanged, this, &MissionItem::_factValueChanged);
connect(_altitudeRelativeToHomeFact, &Fact::valueChanged, this, &MissionItem::_factValueChanged);
// Connect valueChanged signals so we can output coordinateChanged signal
connect(_latitudeFact, &Fact::valueChanged, this, &MissionItem::_coordinateFactChanged);
connect(_longitudeFact, &Fact::valueChanged, this, &MissionItem::_coordinateFactChanged);
connect(_altitudeFact, &Fact::valueChanged, this, &MissionItem::_coordinateFactChanged);
*this = other;
}
MissionItem::~MissionItem() *this = other;
{
} }
const MissionItem& MissionItem::operator=(const MissionItem& other) const MissionItem& MissionItem::operator=(const MissionItem& other)
...@@ -221,15 +198,15 @@ const MissionItem& MissionItem::operator=(const MissionItem& other) ...@@ -221,15 +198,15 @@ const MissionItem& MissionItem::operator=(const MissionItem& other)
_altitudeRelativeToHomeFact = other._altitudeRelativeToHomeFact; _altitudeRelativeToHomeFact = other._altitudeRelativeToHomeFact;
_dirty = other._dirty; _dirty = other._dirty;
_homePositionSpecialCase = other._homePositionSpecialCase; _homePositionSpecialCase = other._homePositionSpecialCase;
*_latitudeFact = *other._latitudeFact; *_latitudeFact = *other._latitudeFact;
*_longitudeFact = *other._longitudeFact; *_longitudeFact = *other._longitudeFact;
*_altitudeFact = *other._altitudeFact; *_altitudeFact = *other._altitudeFact;
*_yawRadiansFact = *other._yawRadiansFact; *_headingDegreesFact = *other._headingDegreesFact;
*_loiterOrbitRadiusFact = *other._loiterOrbitRadiusFact; *_loiterOrbitRadiusFact = *other._loiterOrbitRadiusFact;
*_param1Fact = *other._param1Fact; *_param1Fact = *other._param1Fact;
*_param2Fact = *other._param2Fact; *_param2Fact = *other._param2Fact;
*_pitchMetaData = *other._pitchMetaData; *_pitchMetaData = *other._pitchMetaData;
*_acceptanceRadiusMetaData = *other._acceptanceRadiusMetaData; *_acceptanceRadiusMetaData = *other._acceptanceRadiusMetaData;
*_holdTimeMetaData = *other._holdTimeMetaData; *_holdTimeMetaData = *other._holdTimeMetaData;
...@@ -238,10 +215,34 @@ const MissionItem& MissionItem::operator=(const MissionItem& other) ...@@ -238,10 +215,34 @@ const MissionItem& MissionItem::operator=(const MissionItem& other)
*_delaySecondsMetaData = *other._delaySecondsMetaData; *_delaySecondsMetaData = *other._delaySecondsMetaData;
*_jumpSequenceMetaData = *other._jumpSequenceMetaData; *_jumpSequenceMetaData = *other._jumpSequenceMetaData;
*_jumpRepeatMetaData = *other._jumpRepeatMetaData; *_jumpRepeatMetaData = *other._jumpRepeatMetaData;
return *this; return *this;
} }
void MissionItem::_connectSignals(void)
{
// Connect to valueChanged to track dirty state
connect(_latitudeFact, &Fact::valueChanged, this, &MissionItem::_factValueChanged);
connect(_longitudeFact, &Fact::valueChanged, this, &MissionItem::_factValueChanged);
connect(_altitudeFact, &Fact::valueChanged, this, &MissionItem::_factValueChanged);
connect(_headingDegreesFact, &Fact::valueChanged, this, &MissionItem::_factValueChanged);
connect(_loiterOrbitRadiusFact, &Fact::valueChanged, this, &MissionItem::_factValueChanged);
connect(_param1Fact, &Fact::valueChanged, this, &MissionItem::_factValueChanged);
connect(_param2Fact, &Fact::valueChanged, this, &MissionItem::_factValueChanged);
connect(_altitudeRelativeToHomeFact, &Fact::valueChanged, this, &MissionItem::_factValueChanged);
// Connect valueChanged signals so we can output coordinateChanged signal
connect(_latitudeFact, &Fact::valueChanged, this, &MissionItem::_coordinateFactChanged);
connect(_longitudeFact, &Fact::valueChanged, this, &MissionItem::_coordinateFactChanged);
connect(_altitudeFact, &Fact::valueChanged, this, &MissionItem::_coordinateFactChanged);
connect(_headingDegreesFact, &Fact::valueChanged, this, &MissionItem::_headingDegreesFactChanged);
}
MissionItem::~MissionItem()
{
}
bool MissionItem::isNavigationType() bool MissionItem::isNavigationType()
{ {
return (_command < MavlinkQmlSingleton::MAV_CMD_NAV_LAST); return (_command < MavlinkQmlSingleton::MAV_CMD_NAV_LAST);
...@@ -254,7 +255,7 @@ void MissionItem::save(QTextStream &saveStream) ...@@ -254,7 +255,7 @@ void MissionItem::save(QTextStream &saveStream)
position = position.arg(y(), 0, 'g', 18); position = position.arg(y(), 0, 'g', 18);
position = position.arg(z(), 0, 'g', 18); position = position.arg(z(), 0, 'g', 18);
QString parameters("%1\t%2\t%3\t%4"); QString parameters("%1\t%2\t%3\t%4");
parameters = parameters.arg(param1(), 0, 'g', 18).arg(param2(), 0, 'g', 18).arg(loiterOrbitRadius(), 0, 'g', 18).arg(yawRadians(), 0, 'g', 18); parameters = parameters.arg(param1(), 0, 'g', 18).arg(param2(), 0, 'g', 18).arg(loiterOrbitRadius(), 0, 'g', 18).arg(_yawRadians(), 0, 'g', 18);
// FORMAT: <INDEX> <CURRENT WP> <COORD FRAME> <COMMAND> <PARAM1> <PARAM2> <PARAM3> <PARAM4> <PARAM5/X/LONGITUDE> <PARAM6/Y/LATITUDE> <PARAM7/Z/ALTITUDE> <AUTOCONTINUE> <DESCRIPTION> // FORMAT: <INDEX> <CURRENT WP> <COORD FRAME> <COMMAND> <PARAM1> <PARAM2> <PARAM3> <PARAM4> <PARAM5/X/LONGITUDE> <PARAM6/Y/LATITUDE> <PARAM7/Z/ALTITUDE> <AUTOCONTINUE> <DESCRIPTION>
// as documented here: http://qgroundcontrol.org/waypoint_protocol // as documented here: http://qgroundcontrol.org/waypoint_protocol
saveStream << this->sequenceNumber() << "\t" << this->isCurrentItem() << "\t" << this->frame() << "\t" << this->command() << "\t" << parameters << "\t" << position << "\t" << this->autoContinue() << "\r\n"; //"\t" << this->getDescription() << "\r\n"; saveStream << this->sequenceNumber() << "\t" << this->isCurrentItem() << "\t" << this->frame() << "\t" << this->command() << "\t" << parameters << "\t" << position << "\t" << this->autoContinue() << "\r\n"; //"\t" << this->getDescription() << "\r\n";
...@@ -271,7 +272,7 @@ bool MissionItem::load(QTextStream &loadStream) ...@@ -271,7 +272,7 @@ bool MissionItem::load(QTextStream &loadStream)
setParam1(wpParams[4].toDouble()); setParam1(wpParams[4].toDouble());
setParam2(wpParams[5].toDouble()); setParam2(wpParams[5].toDouble());
setLoiterOrbitRadius(wpParams[6].toDouble()); setLoiterOrbitRadius(wpParams[6].toDouble());
setYawRadians(wpParams[7].toDouble()); _setYawRadians(wpParams[7].toDouble());
setLatitude(wpParams[8].toDouble()); setLatitude(wpParams[8].toDouble());
setLongitude(wpParams[9].toDouble()); setLongitude(wpParams[9].toDouble());
setAltitude(wpParams[10].toDouble()); setAltitude(wpParams[10].toDouble());
...@@ -351,11 +352,27 @@ void MissionItem::setAction(int /*MAV_CMD*/ action) ...@@ -351,11 +352,27 @@ void MissionItem::setAction(int /*MAV_CMD*/ action)
// Fix defaults according to WP type // Fix defaults according to WP type
if (_command == MavlinkQmlSingleton::MAV_CMD_NAV_TAKEOFF) { switch (_command) {
// We default to 15 degrees minimum takeoff pitch case MavlinkQmlSingleton::MAV_CMD_NAV_TAKEOFF:
setParam1(15.0); setParam1(defaultPitch);
break;
case MavlinkQmlSingleton::MAV_CMD_NAV_WAYPOINT:
setAcceptanceRadius(defaultAcceptanceRadius);
break;
case MavlinkQmlSingleton::MAV_CMD_NAV_LOITER_UNLIM:
case MavlinkQmlSingleton::MAV_CMD_NAV_LOITER_TIME:
setLoiterOrbitRadius(defaultLoiterOrbitRadius);
break;
case MavlinkQmlSingleton::MAV_CMD_NAV_LOITER_TURNS:
setLoiterOrbitRadius(defaultLoiterOrbitRadius);
setParam1(defaultLoiterTurns);
break;
default:
break;
} }
setHeadingDegrees(defaultHeading);
setAltitude(defaultAltitude);
if (specifiesCoordinate()) { if (specifiesCoordinate()) {
if (_frame != MAV_FRAME_GLOBAL && _frame != MAV_FRAME_GLOBAL_RELATIVE_ALT) { if (_frame != MAV_FRAME_GLOBAL && _frame != MAV_FRAME_GLOBAL_RELATIVE_ALT) {
setFrame(MAV_FRAME_GLOBAL_RELATIVE_ALT); setFrame(MAV_FRAME_GLOBAL_RELATIVE_ALT);
...@@ -438,7 +455,7 @@ void MissionItem::setParam3(double param3) ...@@ -438,7 +455,7 @@ void MissionItem::setParam3(double param3)
void MissionItem::setParam4(double param4) void MissionItem::setParam4(double param4)
{ {
setYawRadians(param4); _setYawRadians(param4);
} }
void MissionItem::setParam5(double param5) void MissionItem::setParam5(double param5)
...@@ -526,6 +543,46 @@ QString MissionItem::commandName(void) ...@@ -526,6 +543,46 @@ QString MissionItem::commandName(void)
return type; return type;
} }
QString MissionItem::commandDescription(void)
{
QString description;
switch (_command) {
case MAV_CMD_NAV_WAYPOINT:
description = "Travel to a position in 3D space.";
break;
case MAV_CMD_NAV_LOITER_UNLIM:
description = "Travel to a position and Loiter around the specified radius indefinitely.";
break;
case MAV_CMD_NAV_LOITER_TURNS:
description = "Travel to a position and Loiter around the specified radius for a number of turns.";
break;
case MAV_CMD_NAV_LOITER_TIME:
description = "Travel to a position and Loiter around the specified radius for an amount of time.";
break;
case MAV_CMD_NAV_RETURN_TO_LAUNCH:
description = "Send the vehicle back to the home position set when armed.";
break;
case MAV_CMD_NAV_LAND:
description = "Land vehicle at the current location.";
break;
case MAV_CMD_NAV_TAKEOFF:
description = "Lift off from the ground and travel to the specified position.";
break;
case MAV_CMD_CONDITION_DELAY:
description = "Delay";
break;
case MAV_CMD_DO_JUMP:
description = "Jump To Command";
break;
default:
description = QString("Unknown (%1)").arg(_command);
break;
}
return description;
}
QStringList MissionItem::valueLabels(void) QStringList MissionItem::valueLabels(void)
{ {
QStringList labels; QStringList labels;
...@@ -590,24 +647,24 @@ QStringList MissionItem::valueStrings(void) ...@@ -590,24 +647,24 @@ QStringList MissionItem::valueStrings(void)
switch (_command) { switch (_command) {
case MAV_CMD_NAV_WAYPOINT: case MAV_CMD_NAV_WAYPOINT:
list << _oneDecimalString(_altitudeFact->value().toDouble()) << _oneDecimalString(yawDegrees()) << _oneDecimalString(param2()) << _oneDecimalString(param1()); list << _oneDecimalString(_altitudeFact->value().toDouble()) << _oneDecimalString(headingDegrees()) << _oneDecimalString(param2()) << _oneDecimalString(param1());
break; break;
case MAV_CMD_NAV_LOITER_UNLIM: case MAV_CMD_NAV_LOITER_UNLIM:
list << _oneDecimalString(yawRadians() * (180.0 / M_PI)) << _oneDecimalString(loiterOrbitRadius()); list << _oneDecimalString(headingDegrees()) << _oneDecimalString(loiterOrbitRadius());
break; break;
case MAV_CMD_NAV_LOITER_TURNS: case MAV_CMD_NAV_LOITER_TURNS:
list << _oneDecimalString(yawRadians() * (180.0 / M_PI)) << _oneDecimalString(loiterOrbitRadius()) << _oneDecimalString(param1()); list << _oneDecimalString(headingDegrees()) << _oneDecimalString(loiterOrbitRadius()) << _oneDecimalString(param1());
break; break;
case MAV_CMD_NAV_LOITER_TIME: case MAV_CMD_NAV_LOITER_TIME:
list << _oneDecimalString(yawRadians() * (180.0 / M_PI)) << _oneDecimalString(loiterOrbitRadius()) << _oneDecimalString(param1()); list << _oneDecimalString(headingDegrees()) << _oneDecimalString(loiterOrbitRadius()) << _oneDecimalString(param1());
break; break;
case MAV_CMD_NAV_RETURN_TO_LAUNCH: case MAV_CMD_NAV_RETURN_TO_LAUNCH:
break; break;
case MAV_CMD_NAV_LAND: case MAV_CMD_NAV_LAND:
list << _oneDecimalString(_altitudeFact->value().toDouble()) << _oneDecimalString(yawRadians() * (180.0 / M_PI)); list << _oneDecimalString(_altitudeFact->value().toDouble()) << _oneDecimalString(headingDegrees());
break; break;
case MAV_CMD_NAV_TAKEOFF: case MAV_CMD_NAV_TAKEOFF:
list << _oneDecimalString(_altitudeFact->value().toDouble()) << _oneDecimalString(yawRadians() * (180.0 / M_PI)) << _oneDecimalString(param1()); list << _oneDecimalString(_altitudeFact->value().toDouble()) << _oneDecimalString(headingDegrees()) << _oneDecimalString(param1());
break; break;
case MAV_CMD_CONDITION_DELAY: case MAV_CMD_CONDITION_DELAY:
list << _oneDecimalString(param1()); list << _oneDecimalString(param1());
...@@ -659,59 +716,38 @@ QmlObjectListModel* MissionItem::textFieldFacts(void) ...@@ -659,59 +716,38 @@ QmlObjectListModel* MissionItem::textFieldFacts(void)
switch ((MAV_CMD)_command) { switch ((MAV_CMD)_command) {
case MAV_CMD_NAV_WAYPOINT: case MAV_CMD_NAV_WAYPOINT:
_param2Fact->_setName("Radius:");
_param2Fact->setMetaData(_acceptanceRadiusMetaData);
_param1Fact->_setName("Hold:"); _param1Fact->_setName("Hold:");
_param1Fact->setMetaData(_holdTimeMetaData); _param1Fact->setMetaData(_holdTimeMetaData);
model->append(_latitudeFact);
model->append(_longitudeFact);
model->append(_altitudeFact); model->append(_altitudeFact);
if (!_homePositionSpecialCase) { if (!_homePositionSpecialCase) {
model->append(_yawRadiansFact);
model->append(_param2Fact);
model->append(_param1Fact); model->append(_param1Fact);
} }
break; break;
case MAV_CMD_NAV_LOITER_UNLIM: case MAV_CMD_NAV_LOITER_UNLIM:
model->append(_latitudeFact);
model->append(_longitudeFact);
model->append(_altitudeFact); model->append(_altitudeFact);
model->append(_yawRadiansFact);
model->append(_loiterOrbitRadiusFact); model->append(_loiterOrbitRadiusFact);
break; break;
case MAV_CMD_NAV_LOITER_TURNS: case MAV_CMD_NAV_LOITER_TURNS:
_param1Fact->_setName("Turns:"); _param1Fact->_setName("Turns:");
_param1Fact->setMetaData(_loiterTurnsMetaData); _param1Fact->setMetaData(_loiterTurnsMetaData);
model->append(_latitudeFact);
model->append(_longitudeFact);
model->append(_altitudeFact); model->append(_altitudeFact);
model->append(_yawRadiansFact);
model->append(_loiterOrbitRadiusFact); model->append(_loiterOrbitRadiusFact);
model->append(_param1Fact); model->append(_param1Fact);
break; break;
case MAV_CMD_NAV_LOITER_TIME: case MAV_CMD_NAV_LOITER_TIME:
_param1Fact->_setName("Seconds:"); _param1Fact->_setName("Seconds:");
_param1Fact->setMetaData(_loiterSecondsMetaData); _param1Fact->setMetaData(_loiterSecondsMetaData);
model->append(_latitudeFact);
model->append(_longitudeFact);
model->append(_altitudeFact); model->append(_altitudeFact);
model->append(_yawRadiansFact);
model->append(_loiterOrbitRadiusFact); model->append(_loiterOrbitRadiusFact);
model->append(_param1Fact); model->append(_param1Fact);
break; break;
case MAV_CMD_NAV_LAND: case MAV_CMD_NAV_LAND:
model->append(_latitudeFact);
model->append(_longitudeFact);
model->append(_altitudeFact); model->append(_altitudeFact);
model->append(_yawRadiansFact);
break; break;
case MAV_CMD_NAV_TAKEOFF: case MAV_CMD_NAV_TAKEOFF:
_param1Fact->_setName("Pitch:"); _param1Fact->_setName("Pitch:");
_param1Fact->setMetaData(_pitchMetaData); _param1Fact->setMetaData(_pitchMetaData);
model->append(_latitudeFact);
model->append(_longitudeFact);
model->append(_altitudeFact); model->append(_altitudeFact);
model->append(_yawRadiansFact);
model->append(_param1Fact); model->append(_param1Fact);
break; break;
case MAV_CMD_CONDITION_DELAY: case MAV_CMD_CONDITION_DELAY:
...@@ -730,6 +766,11 @@ QmlObjectListModel* MissionItem::textFieldFacts(void) ...@@ -730,6 +766,11 @@ QmlObjectListModel* MissionItem::textFieldFacts(void)
default: default:
break; break;
} }
if (specifiesHeading()) {
model->append(_headingDegreesFact);
}
return model; return model;
} }
...@@ -768,30 +809,30 @@ QmlObjectListModel* MissionItem::checkboxFacts(void) ...@@ -768,30 +809,30 @@ QmlObjectListModel* MissionItem::checkboxFacts(void)
return model; return model;
} }
double MissionItem::yawRadians(void) const double MissionItem::headingDegrees(void) const
{ {
return _yawRadiansFact->value().toDouble(); return _headingDegreesFact->value().toDouble();
} }
void MissionItem::setYawRadians(double yaw) void MissionItem::setHeadingDegrees(double headingDegrees)
{ {
if (yawRadians() != yaw) if (_headingDegreesFact->value().toDouble() != headingDegrees) {
{ _headingDegreesFact->setValue(headingDegrees);
_yawRadiansFact->setValue(yaw);
emit changed(this); emit changed(this);
emit valueStringsChanged(valueStrings()); emit valueStringsChanged(valueStrings());
emit headingDegreesChanged(headingDegrees);
} }
} }
double MissionItem::yawDegrees(void) const double MissionItem::_yawRadians(void) const
{ {
return yawRadians() * (180.0 / M_PI); return _headingDegreesFact->value().toDouble() * (M_PI / 180.0);
} }
void MissionItem::setYawDegrees(double yaw) void MissionItem::_setYawRadians(double yawRadians)
{ {
setYawRadians(yaw * (M_PI / 180.0)); setHeadingDegrees(yawRadians * (180 / M_PI));
} }
QGeoCoordinate MissionItem::coordinate(void) const QGeoCoordinate MissionItem::coordinate(void) const
...@@ -854,3 +895,19 @@ void MissionItem::_coordinateFactChanged(QVariant value) ...@@ -854,3 +895,19 @@ void MissionItem::_coordinateFactChanged(QVariant value)
Q_UNUSED(value); Q_UNUSED(value);
emit coordinateChanged(coordinate()); emit coordinateChanged(coordinate());
} }
bool MissionItem::specifiesHeading(void) const
{
switch ((MAV_CMD)_command) {
case MAV_CMD_NAV_LAND:
case MAV_CMD_NAV_TAKEOFF:
return true;
default:
return false;
}
}
void MissionItem::_headingDegreesFactChanged(QVariant value)
{
emit headingDegreesChanged(value.toDouble());
}
...@@ -50,9 +50,9 @@ public: ...@@ -50,9 +50,9 @@ public:
QGeoCoordinate coordiante = QGeoCoordinate(), QGeoCoordinate coordiante = QGeoCoordinate(),
int action = MAV_CMD_NAV_WAYPOINT, int action = MAV_CMD_NAV_WAYPOINT,
double param1 = 0.0, double param1 = 0.0,
double param2 = 0.0, double param2 = defaultAcceptanceRadius,
double param3 = 0.0, double param3 = defaultLoiterOrbitRadius,
double param4 = 0.0, double param4 = defaultHeading,
bool autocontinue = true, bool autocontinue = true,
bool isCurrentItem = false, bool isCurrentItem = false,
int frame = MAV_FRAME_GLOBAL_RELATIVE_ALT); int frame = MAV_FRAME_GLOBAL_RELATIVE_ALT);
...@@ -67,10 +67,16 @@ public: ...@@ -67,10 +67,16 @@ public:
Q_PROPERTY(int sequenceNumber READ sequenceNumber WRITE setSequenceNumber NOTIFY sequenceNumberChanged) Q_PROPERTY(int sequenceNumber READ sequenceNumber WRITE setSequenceNumber NOTIFY sequenceNumberChanged)
Q_PROPERTY(bool isCurrentItem READ isCurrentItem WRITE setIsCurrentItem NOTIFY isCurrentItemChanged) Q_PROPERTY(bool isCurrentItem READ isCurrentItem WRITE setIsCurrentItem NOTIFY isCurrentItemChanged)
Q_PROPERTY(bool specifiesCoordinate READ specifiesCoordinate NOTIFY commandChanged) Q_PROPERTY(bool specifiesCoordinate READ specifiesCoordinate NOTIFY commandChanged)
Q_PROPERTY(QGeoCoordinate coordinate READ coordinate WRITE setCoordinate NOTIFY coordinateChanged) Q_PROPERTY(QGeoCoordinate coordinate READ coordinate WRITE setCoordinate NOTIFY coordinateChanged)
Q_PROPERTY(bool specifiesHeading READ specifiesHeading NOTIFY commandChanged)
Q_PROPERTY(double heading READ headingDegrees WRITE setHeadingDegrees NOTIFY headingDegreesChanged)
Q_PROPERTY(QStringList commandNames READ commandNames CONSTANT) Q_PROPERTY(QStringList commandNames READ commandNames CONSTANT)
Q_PROPERTY(QString commandName READ commandName NOTIFY commandChanged) Q_PROPERTY(QString commandName READ commandName NOTIFY commandChanged)
Q_PROPERTY(QString commandDescription READ commandDescription NOTIFY commandChanged)
Q_PROPERTY(QStringList valueLabels READ valueLabels NOTIFY commandChanged) Q_PROPERTY(QStringList valueLabels READ valueLabels NOTIFY commandChanged)
Q_PROPERTY(QStringList valueStrings READ valueStrings NOTIFY valueStringsChanged) Q_PROPERTY(QStringList valueStrings READ valueStrings NOTIFY valueStringsChanged)
Q_PROPERTY(int commandByIndex READ commandByIndex WRITE setCommandByIndex NOTIFY commandChanged) Q_PROPERTY(int commandByIndex READ commandByIndex WRITE setCommandByIndex NOTIFY commandChanged)
...@@ -88,12 +94,16 @@ public: ...@@ -88,12 +94,16 @@ public:
void setIsCurrentItem(bool isCurrentItem); void setIsCurrentItem(bool isCurrentItem);
bool specifiesCoordinate(void) const; bool specifiesCoordinate(void) const;
QGeoCoordinate coordinate(void) const; QGeoCoordinate coordinate(void) const;
void setCoordinate(const QGeoCoordinate& coordinate); void setCoordinate(const QGeoCoordinate& coordinate);
bool specifiesHeading(void) const;
double headingDegrees(void) const;
void setHeadingDegrees(double headingDegrees);
QStringList commandNames(void); QStringList commandNames(void);
QString commandName(void); QString commandName(void);
QString commandDescription(void);
int commandByIndex(void); int commandByIndex(void);
void setCommandByIndex(int index); void setCommandByIndex(int index);
...@@ -107,9 +117,6 @@ public: ...@@ -107,9 +117,6 @@ public:
QmlObjectListModel* textFieldFacts(void); QmlObjectListModel* textFieldFacts(void);
QmlObjectListModel* checkboxFacts(void); QmlObjectListModel* checkboxFacts(void);
double yawDegrees(void) const;
void setYawDegrees(double yaw);
bool dirty(void) { return _dirty; } bool dirty(void) { return _dirty; }
void setDirty(bool dirty); void setDirty(bool dirty);
...@@ -136,9 +143,6 @@ public: ...@@ -136,9 +143,6 @@ public:
void setY(double y); void setY(double y);
void setZ(double z); void setZ(double z);
double yawRadians(void) const;
void setYawRadians(double yaw);
bool autoContinue() const { bool autoContinue() const {
return _autocontinue; return _autocontinue;
} }
...@@ -161,7 +165,7 @@ public: ...@@ -161,7 +165,7 @@ public:
return loiterOrbitRadius(); return loiterOrbitRadius();
} }
double param4() const { double param4() const {
return yawRadians(); return _yawRadians();
} }
double param5() const { double param5() const {
return latitude(); return latitude();
...@@ -189,11 +193,19 @@ public: ...@@ -189,11 +193,19 @@ public:
bool load(QTextStream &loadStream); bool load(QTextStream &loadStream);
void setHomePositionSpecialCase(bool homePositionSpecialCase) { _homePositionSpecialCase = homePositionSpecialCase; } void setHomePositionSpecialCase(bool homePositionSpecialCase) { _homePositionSpecialCase = homePositionSpecialCase; }
static const double defaultPitch;
static const double defaultHeading;
static const double defaultAltitude;
static const double defaultAcceptanceRadius;
static const double defaultLoiterOrbitRadius;
static const double defaultLoiterTurns;
signals: signals:
void sequenceNumberChanged(int sequenceNumber); void sequenceNumberChanged(int sequenceNumber);
void isCurrentItemChanged(bool isCurrentItem); void isCurrentItemChanged(bool isCurrentItem);
void coordinateChanged(const QGeoCoordinate& coordinate); void coordinateChanged(const QGeoCoordinate& coordinate);
void headingDegreesChanged(double heading);
void dirtyChanged(bool dirty); void dirtyChanged(bool dirty);
/** @brief Announces a change to the waypoint data */ /** @brief Announces a change to the waypoint data */
...@@ -234,9 +246,13 @@ public: ...@@ -234,9 +246,13 @@ public:
private slots: private slots:
void _factValueChanged(QVariant value); void _factValueChanged(QVariant value);
void _coordinateFactChanged(QVariant value); void _coordinateFactChanged(QVariant value);
void _headingDegreesFactChanged(QVariant value);
private: private:
QString _oneDecimalString(double value); QString _oneDecimalString(double value);
void _connectSignals(void);
double _yawRadians(void) const;
void _setYawRadians(double yawRadians);
private: private:
typedef struct { typedef struct {
...@@ -254,7 +270,7 @@ private: ...@@ -254,7 +270,7 @@ private:
Fact* _latitudeFact; Fact* _latitudeFact;
Fact* _longitudeFact; Fact* _longitudeFact;
Fact* _altitudeFact; Fact* _altitudeFact;
Fact* _yawRadiansFact; Fact* _headingDegreesFact;
Fact* _loiterOrbitRadiusFact; Fact* _loiterOrbitRadiusFact;
Fact* _param1Fact; Fact* _param1Fact;
Fact* _param2Fact; Fact* _param2Fact;
......
...@@ -224,7 +224,7 @@ Item { ...@@ -224,7 +224,7 @@ Item {
context.lineTo(dropItemHolderRect.x, dropItemHolderRect.y) context.lineTo(dropItemHolderRect.x, dropItemHolderRect.y)
context.closePath() context.closePath()
context.fillStyle = qgcPal.button context.fillStyle = qgcPal.windowShade
context.fill() context.fill()
} }
} // Canvas - arrowCanvas } // Canvas - arrowCanvas
......
...@@ -19,34 +19,26 @@ Rectangle { ...@@ -19,34 +19,26 @@ Rectangle {
signal clicked signal clicked
signal remove signal remove
height: missionItem.isCurrentItem ? height: innerItem.height + (_margin * 2)
(missionItem.textFieldFacts.count * (measureTextField.height + _margin)) +
(missionItem.checkboxFacts.count * (measureCheckbox.height + _margin)) +
commandPicker.height + (deleteButton.visible ? deleteButton.height : 0) + (_margin * 9) :
commandPicker.height + (_margin * 2)
color: missionItem.isCurrentItem ? qgcPal.buttonHighlight : qgcPal.windowShade color: missionItem.isCurrentItem ? qgcPal.buttonHighlight : qgcPal.windowShade
radius: _radius
readonly property real _editFieldWidth: ScreenTools.defaultFontPixelWidth * 16 readonly property real _editFieldWidth: ScreenTools.defaultFontPixelWidth * 16
readonly property real _margin: ScreenTools.defaultFontPixelWidth / 3 readonly property real _margin: ScreenTools.defaultFontPixelWidth / 2
readonly property real _radius: ScreenTools.defaultFontPixelWidth / 2
QGCPalette { QGCPalette {
id: qgcPal id: qgcPal
colorGroupEnabled: enabled colorGroupEnabled: enabled
} }
QGCTextField {
id: measureTextField
visible: false
}
QGCCheckBox {
id: measureCheckbox
visible: false
}
Item { Item {
id: innerItem
anchors.margins: _margin anchors.margins: _margin
anchors.fill: parent anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
height: valuesRect.visible ? valuesRect.y + valuesRect.height : valuesRect.y
MissionItemIndexLabel { MissionItemIndexLabel {
id: label id: label
...@@ -69,7 +61,7 @@ Rectangle { ...@@ -69,7 +61,7 @@ Rectangle {
anchors.right: parent.right anchors.right: parent.right
currentIndex: missionItem.commandByIndex currentIndex: missionItem.commandByIndex
model: missionItem.commandNames model: missionItem.commandNames
visible: missionItem.sequenceNumber != 0 // Item 0 is home position, can't change item type visible: missionItem.sequenceNumber != 0 && missionItem.isCurrentItem
onActivated: missionItem.commandByIndex = index onActivated: missionItem.commandByIndex = index
} }
...@@ -77,30 +69,36 @@ Rectangle { ...@@ -77,30 +69,36 @@ Rectangle {
Rectangle { Rectangle {
anchors.fill: commandPicker anchors.fill: commandPicker
color: qgcPal.button color: qgcPal.button
visible: missionItem.sequenceNumber == 0 // Item 0 is home position, can't change item type visible: !commandPicker.visible
QGCLabel { QGCLabel {
id: homeLabel id: homeLabel
anchors.leftMargin: ScreenTools.defaultFontPixelWidth anchors.leftMargin: ScreenTools.defaultFontPixelWidth
anchors.fill: parent anchors.fill: parent
verticalAlignment: Text.AlignVCenter verticalAlignment: Text.AlignVCenter
text: "Home" text: missionItem.sequenceNumber == 0 ? "Home" : missionItem.commandName
color: qgcPal.buttonText color: qgcPal.buttonText
} }
} }
Rectangle { Rectangle {
id: valuesRect
anchors.topMargin: _margin anchors.topMargin: _margin
anchors.top: commandPicker.bottom anchors.top: commandPicker.bottom
anchors.bottom: parent.bottom
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
height: valuesItem.height
color: qgcPal.windowShadeDark color: qgcPal.windowShadeDark
visible: missionItem.isCurrentItem visible: missionItem.isCurrentItem
radius: _radius
Item { Item {
id: valuesItem
anchors.margins: _margin anchors.margins: _margin
anchors.fill: parent anchors.left: parent.left
anchors.right: parent.right
anchors.top: parent.top
height: valuesColumn.height + _margin
Column { Column {
id: valuesColumn id: valuesColumn
...@@ -109,6 +107,12 @@ Rectangle { ...@@ -109,6 +107,12 @@ Rectangle {
anchors.top: parent.top anchors.top: parent.top
spacing: _margin spacing: _margin
QGCLabel {
width: parent.width
wrapMode: Text.WordWrap
text: missionItem.commandDescription
}
Repeater { Repeater {
model: missionItem.textFieldFacts model: missionItem.textFieldFacts
...@@ -140,11 +144,6 @@ Rectangle { ...@@ -140,11 +144,6 @@ Rectangle {
} }
} }
Item {
width: 10
height: missionItem.textFieldFacts.count ? _margin : 0
}
Repeater { Repeater {
model: missionItem.checkboxFacts model: missionItem.checkboxFacts
...@@ -154,28 +153,6 @@ Rectangle { ...@@ -154,28 +153,6 @@ Rectangle {
fact: object fact: object
} }
} }
Item {
width: 10
height: missionItem.checkboxFacts.count ? _margin : 0
}
Row {
width: parent.width
spacing: _margin
readonly property real buttonWidth: (width - (_margin * 2)) / 3
QGCButton {
id: deleteButton
width: parent.buttonWidth
text: "Delete"
visible: !readOnly
onClicked: _root.remove()
}
}
} // Column } // Column
} // Item } // Item
} // Rectangle } // Rectangle
......
...@@ -13,7 +13,7 @@ Rectangle { ...@@ -13,7 +13,7 @@ Rectangle {
QGCPalette { id: qgcPal } QGCPalette { id: qgcPal }
width: ScreenTools.defaultFontPixelHeight * 1.5 width: ScreenTools.mediumFontPixelSize * 1.5
height: width height: width
radius: width / 2 radius: width / 2
border.width: 2 border.width: 2
...@@ -32,5 +32,6 @@ Rectangle { ...@@ -32,5 +32,6 @@ Rectangle {
horizontalAlignment: Text.AlignHCenter horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter verticalAlignment: Text.AlignVCenter
color: "white" color: "white"
font.pixelSize: ScreenTools.mediumFontPixelSize
} }
} }
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