diff --git a/qgroundcontrol.qrc b/qgroundcontrol.qrc index 788b6aa60edae6cb15ff5961c453cb32fcdc7f18..86f057428863dbe6e4dfbc9ee1329942174a1278 100644 --- a/qgroundcontrol.qrc +++ b/qgroundcontrol.qrc @@ -70,6 +70,7 @@ src/FlightMap/Images/Help.svg src/FlightMap/Images/MapCenter.svg src/FlightMap/Images/MapSync.svg + src/FlightMap/Images/MapSyncChanged.svg src/FlightMap/Images/MapType.svg src/FlightMap/Images/MapHome.svg src/FlightMap/Images/MapAddMission.svg diff --git a/src/FlightDisplay/FlightDisplayView.qml b/src/FlightDisplay/FlightDisplayView.qml index 2731316e8f6198188cfdea4254736288339a4ae5..6565ef69804e94e42ae86cb8fc1e65d7dd9185e2 100644 --- a/src/FlightDisplay/FlightDisplayView.qml +++ b/src/FlightDisplay/FlightDisplayView.qml @@ -55,15 +55,14 @@ Item { property var _activeVehicle: multiVehicleManager.activeVehicle - readonly property real _defaultLatitude: 37.803784 - readonly property real _defaultLongitude: -122.462276 - readonly property real _defaultRoll: 0 - readonly property real _defaultPitch: 0 - readonly property real _defaultHeading: 0 - readonly property real _defaultAltitudeWGS84: 0 - readonly property real _defaultGroundSpeed: 0 - readonly property real _defaultAirSpeed: 0 - readonly property real _defaultClimbRate: 0 + readonly property var _defaultVehicleCoordinate: QtPositioning.coordinate(37.803784, -122.462276) + readonly property real _defaultRoll: 0 + readonly property real _defaultPitch: 0 + readonly property real _defaultHeading: 0 + readonly property real _defaultAltitudeWGS84: 0 + readonly property real _defaultGroundSpeed: 0 + readonly property real _defaultAirSpeed: 0 + readonly property real _defaultClimbRate: 0 readonly property string _mapName: "FlightDisplayView" readonly property string _showMapBackgroundKey: "/showMapBackground" @@ -72,8 +71,7 @@ Item { property real _pitch: _activeVehicle ? (isNaN(_activeVehicle.pitch) ? _defaultPitch : _activeVehicle.pitch) : _defaultPitch property real _heading: _activeVehicle ? (isNaN(_activeVehicle.heading) ? _defaultHeading : _activeVehicle.heading) : _defaultHeading - property real _latitude: _activeVehicle ? ((_activeVehicle.latitude === 0) ? _defaultLatitude : _activeVehicle.latitude) : _defaultLatitude - property real _longitude: _activeVehicle ? ((_activeVehicle.longitude === 0) ? _defaultLongitude : _activeVehicle.longitude) : _defaultLongitude + property var _vehicleCoordinate: _activeVehicle ? _activeVehicle.coordinate : _defaultVehicleCoordinate property real _altitudeWGS84: _activeVehicle ? _activeVehicle.altitudeWGS84 : _defaultAltitudeWGS84 property real _groundSpeed: _activeVehicle ? _activeVehicle.groundSpeed : _defaultGroundSpeed @@ -82,14 +80,20 @@ Item { property bool _showMap: getBool(QGroundControl.flightMapSettings.loadMapSetting(flightMap.mapName, _showMapBackgroundKey, "1")) - FlightDisplayViewController { id: _controller; } + FlightDisplayViewController { id: _controller } ExclusiveGroup { id: _dropButtonsExclusiveGroup } // 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) { return value === '0' ? false : true; @@ -104,24 +108,24 @@ Item { QGroundControl.flightMapSettings.saveMapSetting(flightMap.mapName, _showMapBackgroundKey, setBool(_showMap)) } + FlightMap { id: flightMap anchors.fill: parent mapName: _mapName visible: _showMap + latitude: root._defaultCoordinate.latitude + longitude: root._defaultCoordinate.longitude - property real rootLatitude: root._latitude - property real rootLongitude: root._longitude - - Component.onCompleted: updateMapPosition(true /* force */) + property var rootVehicleCoordinate: _vehicleCoordinate + property bool rootLoadCompleted: false - onRootLatitudeChanged: updateMapPosition(false /* force */) - onRootLongitudeChanged: updateMapPosition(false /* force */) + onRootVehicleCoordinateChanged: updateMapPosition(false /* force */) function updateMapPosition(force) { - if (_followVehicle || force) { - latitude = root._latitude - longitude = root._longitude + if ((_followVehicle || force) && rootLoadCompleted) { + flightMap.latitude = root._vehicleCoordinate.latitude + flightMap.longitude = root._vehicleCoordinate.longitude } } diff --git a/src/FlightMap/FlightMap.qml b/src/FlightMap/FlightMap.qml index 3f1d1c028d756b1342cc680987c76ede5433452f..fa696a392fd9873e7969f4dd1186b089dbbac9c3 100644 --- a/src/FlightMap/FlightMap.qml +++ b/src/FlightMap/FlightMap.qml @@ -59,10 +59,13 @@ Map { 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 - zoomLevel: 18 - center: QtPositioning.coordinate(lat, lon) - gesture.flickDeceleration: 3000 - gesture.enabled: interactive + readonly property real maxZoomLevel: 20 + + zoomLevel: 18 + center: QtPositioning.coordinate(lat, lon) + gesture.flickDeceleration: 3000 + gesture.enabled: interactive + gesture.activeGestures: MapGestureArea.ZoomGesture | MapGestureArea.PanGesture | MapGestureArea.FlickGesture plugin: Plugin { name: "QGroundControl" } @@ -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 diff --git a/src/MissionEditor/MissionEditor.qml b/src/MissionEditor/MissionEditor.qml index 5107ef5ace2114a8951814ee379b239016db09e5..4002f7af3b9f260a12b8f614d86f7ee17e29245a 100644 --- a/src/MissionEditor/MissionEditor.qml +++ b/src/MissionEditor/MissionEditor.qml @@ -45,9 +45,13 @@ QGCView { readonly property int _decimalPlaces: 7 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 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 @@ -59,9 +63,11 @@ QGCView { property var liveHomePositionAvailable: _controller.liveHomePositionAvailable property var homePosition: offlineHomePosition // live or offline depending on state + property bool _syncNeeded: _controller.missionItems.dirty + MissionEditorController { id: _controller } - QGCPalette { id: _qgcPal; colorGroupEnabled: enabled } + QGCPalette { id: qgcPal; colorGroupEnabled: enabled } ExclusiveGroup { id: _mapTypeButtonsExclusiveGroup @@ -69,7 +75,6 @@ QGCView { ExclusiveGroup { id: _dropButtonsExclusiveGroup - onCurrentChanged: console.log("Current button", current) } function setCurrentItem(index) { @@ -107,10 +112,7 @@ QGCView { FlightMap { id: editorMap - anchors.left: parent.left - anchors.right: missionItemView.left - anchors.top: parent.top - anchors.bottom: parent.bottom + anchors.fill: parent mapName: "MissionEditor" Component.onCompleted: { @@ -118,6 +120,29 @@ QGCView { 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 { anchors.fill: parent @@ -130,245 +155,95 @@ QGCView { offlineHomePosition = coordinate } else if (addMissionItemsButton.checked) { var index = _controller.addMissionItem(coordinate) + addMissionItemsButtonAutoOffTimer.start() setCurrentItem(index) + } else { + editorMap.zoomLevel = editorMap.maxZoomLevel - 2 } } } - Rectangle { - anchors.horizontalCenter: parent.horizontalCenter - anchors.bottom: parent.bottom - width: parent.width * 0.75 - height: syncNeededText.height + (ScreenTools.defaultFontPixelWidth * 2) - border.width: 1 - border.color: "white" - color: "black" - opacity: 0.75 - visible: _controller.missionItems.dirty - - QGCLabel { - id: syncNeededText - anchors.margins: ScreenTools.defaultFontPixelWidth - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right - wrapMode: Text.WordWrap - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - font.pixelSize: ScreenTools.mediumFontPixelSize - text: "You have unsaved changes. Be sure to use the Sync tool to save when ready." - } - } - - 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() - } - } - } + // We use this item to support dragging since dragging a MapQuickItem just doesn't seem to work + Item { + id: itemEditor + x: missionItemIndicator ? (missionItemIndicator.x + missionItemIndicator.anchorPoint.x - (itemEditor.width / 2)) : 100 + y: missionItemIndicator ? (missionItemIndicator.y + missionItemIndicator.anchorPoint.y - (itemEditor.height / 2)) : 100 + width: ScreenTools.defaultFontPixelHeight * 7 + height: ScreenTools.defaultFontPixelHeight * 7 + visible: false + z: editorMap.zOrderMapItems + 1 // Above item icons + + property var missionItem + property var missionItemIndicator + property real heading: missionItem ? missionItem.heading : 0 + + Drag.active: itemDrag.drag.active + Drag.hotSpot.x: width / 2 + Drag.hotSpot.y: height / 2 + + MissionItemIndexLabel { + x: (itemEditor.width / 2) - (width / 2) + y: (itemEditor.height / 2) - (height / 2) + label: itemEditor.missionItemIndicator ? itemEditor.missionItemIndicator.label : "" + isCurrentItem: true } - } - - 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 { - Row { - spacing: ScreenTools.defaultFontPixelWidth + MouseArea { + id: itemDrag + anchors.fill: parent + drag.target: parent - Repeater { - model: QGroundControl.flightMapSettings.mapTypes + property bool dragActive: drag.active - QGCButton { - checkable: true - checked: editorMap.mapType == text - text: modelData - exclusiveGroup: _mapTypeButtonsExclusiveGroup - - onClicked: { - editorMap.mapType = text - checked = true - mapTypeButton.hideDropDown() - } - } + onDragActiveChanged: { + if (!drag.active) { + var point = Qt.point(itemEditor.x + (itemEditor.width / 2), itemEditor.y + (itemEditor.height / 2)) + itemEditor.missionItem.coordinate = editorMap.toCoordinate(point) } } } } - 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 MapItemView { model: _controller.missionItems - + delegate: MissionItemIndicator { id: itemIndicator label: object.sequenceNumber == 0 ? (liveHomePositionAvailable ? "H" : "F") : object.sequenceNumber isCurrentItem: !homePositionManagerButton.checked && object.isCurrentItem coordinate: object.coordinate - z: 2 + z: editorMap.zOrderMapItems visible: object.specifiesCoordinate - onClicked: { - setCurrentItem(object.sequenceNumber) - missionItemEditorButton.checked + onClicked: setCurrentItem(object.sequenceNumber) + + 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 { anchors.top: parent.top anchors.left: parent.right @@ -400,8 +275,8 @@ QGCView { delegate: MapPolyline { line.width: 3 - line.color: _qgcPal.mapButtonHighlight - z: 1 + line.color: qgcPal.mapButtonHighlight + z: editorMap.zOrderMapItems - 1 // Under item indicators path: [ { latitude: object.coordinate1.latitude, longitude: object.coordinate1.longitude }, @@ -410,346 +285,341 @@ QGCView { } } - 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 - } - } - } // FlightMap - - Rectangle { - id: missionItemView - anchors.right: parent.right - anchors.top: parent.top - anchors.bottom: parent.bottom - width: ScreenTools.defaultFontPixelWidth * 30 - color: _qgcPal.window - + // Mission Item Editor Item { - anchors.margins: _verticalMargin - anchors.fill: parent - - // Mission Item Editor - Item { - id: missionItemEditor + id: missionItemEditor + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.right: parent.right + width: _rightPanelWidth + visible: !helpButton.checked && !homePositionManagerButton.checked && _missionItems.count > 1 + opacity: _rightPanelOpacity + z: editorMap.zOrderTopMost + + ListView { + id: missionItemSummaryList anchors.fill: parent - visible: !helpButton.checked && !homePositionManagerButton.checked && _missionItems.count > 1 - - ListView { - id: missionItemSummaryList - anchors.fill: parent - spacing: _verticalMargin - orientation: ListView.Vertical - model: _controller.canEdit ? _controller.missionItems : 0 - - property real _maxItemHeight: 0 - - delegate: - MissionItemEditor { - missionItem: object - width: parent.width - readOnly: object.sequenceNumber == 0 && liveHomePositionAvailable - - onClicked: setCurrentItem(object.sequenceNumber) - - onRemove: { - var newCurrentItem = object.sequenceNumber - 1 - _controller.removeMissionItem(object.sequenceNumber) - if (_missionItems.count > 1) { - newCurrentItem = Math.min(_missionItems.count - 1, newCurrentItem) - setCurrentItem(newCurrentItem) - } - } + spacing: _margin / 2 + orientation: ListView.Vertical + model: _controller.canEdit ? _controller.missionItems : 0 + + property real _maxItemHeight: 0 + + delegate: + MissionItemEditor { + missionItem: object + width: parent.width + readOnly: object.sequenceNumber == 0 && liveHomePositionAvailable + + onClicked: setCurrentItem(object.sequenceNumber) + + onRemove: { + 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 - Item { - id: homePositionManager + QGCLabel { 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 { - anchors.fill: parent - visible: !liveHomePositionAvailable + // Home Position Manager + Rectangle { + 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 { - font.pixelSize: ScreenTools.mediumFontPixelSize - text: "Flying Field Manager" - } + QGCLabel { + font.pixelSize: ScreenTools.mediumFontPixelSize + text: "Flying Field Manager" + } - Item { - width: 10 - height: ScreenTools.defaultFontPixelHeight - } + Item { + width: 10 + height: ScreenTools.defaultFontPixelHeight + } - QGCLabel { - width: parent.width - wrapMode: Text.WordWrap - text: "This is used to save locations associated with your flying field for use while creating missions with no vehicle connection." - } + QGCLabel { + width: parent.width + wrapMode: Text.WordWrap + text: "This is used to save locations associated with your flying field for use while creating missions with no vehicle connection." + } - Item { - width: 10 - height: ScreenTools.defaultFontPixelHeight - } + Item { + width: 10 + height: ScreenTools.defaultFontPixelHeight + } - QGCLabel { - text: "Select field to use:" - } + QGCLabel { + text: "Select field to use:" + } - QGCComboBox { - id: homePosCombo - width: parent.width - textRole: "text" - model: _homePositionManager.homePositions - - onCurrentIndexChanged: { - if (currentIndex != -1) { - var homePos = _homePositionManager.homePositions.get(currentIndex) - _homePositionName = homePos.name - offlineHomePosition = homePos.coordinate - editorMap.latitude = offlineHomePosition.latitude - editorMap.longitude = offlineHomePosition.longitude - } + QGCComboBox { + id: homePosCombo + width: parent.width + textRole: "text" + model: _homePositionManager.homePositions + + onCurrentIndexChanged: { + if (currentIndex != -1) { + var homePos = _homePositionManager.homePositions.get(currentIndex) + _homePositionName = homePos.name + offlineHomePosition = homePos.coordinate + editorMap.latitude = offlineHomePosition.latitude + editorMap.longitude = offlineHomePosition.longitude } } + } - Item { - width: 10 - 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 { + width: 10 + height: ScreenTools.defaultFontPixelHeight + } - Item { - width: 10 - height: ScreenTools.defaultFontPixelHeight / 3 - } + 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 { - width: parent.width - height: nameField.height + Item { + width: 10 + height: ScreenTools.defaultFontPixelHeight / 3 + } - QGCLabel { - anchors.baseline: nameField.baseline - text: "Name:" - } + Item { + width: parent.width + height: nameField.height - QGCTextField { - id: nameField - anchors.right: parent.right - width: _editFieldWidth - text: _homePositionName - } + QGCLabel { + anchors.baseline: nameField.baseline + text: "Name:" } - Item { - width: 10 - height: ScreenTools.defaultFontPixelHeight / 3 + QGCTextField { + id: nameField + anchors.right: parent.right + width: _editFieldWidth + text: _homePositionName } + } - Item { - width: parent.width - height: offlineLatitudeField.height + Item { + width: 10 + height: ScreenTools.defaultFontPixelHeight / 3 + } - QGCLabel { - anchors.baseline: offlineLatitudeField.baseline - text: "Lat:" - } + Item { + width: parent.width + height: offlineLatitudeField.height - QGCTextField { - id: offlineLatitudeField - anchors.right: parent.right - width: _editFieldWidth - text: offlineHomePosition.latitude - } + QGCLabel { + anchors.baseline: offlineLatitudeField.baseline + text: "Lat:" } - Item { - width: 10 - height: ScreenTools.defaultFontPixelHeight / 3 + QGCTextField { + id: offlineLatitudeField + anchors.right: parent.right + width: _editFieldWidth + text: offlineHomePosition.latitude } + } - Item { - width: parent.width - height: offlineLongitudeField.height + Item { + width: 10 + height: ScreenTools.defaultFontPixelHeight / 3 + } - QGCLabel { - anchors.baseline: offlineLongitudeField.baseline - text: "Lon:" - } + Item { + width: parent.width + height: offlineLongitudeField.height - QGCTextField { - id: offlineLongitudeField - anchors.right: parent.right - width: _editFieldWidth - text: offlineHomePosition.longitude - } + QGCLabel { + anchors.baseline: offlineLongitudeField.baseline + text: "Lon:" } - Item { - width: 10 - height: ScreenTools.defaultFontPixelHeight / 3 + QGCTextField { + id: offlineLongitudeField + anchors.right: parent.right + width: _editFieldWidth + text: offlineHomePosition.longitude } + } - Item { - width: parent.width - height: offlineAltitudeField.height + Item { + width: 10 + height: ScreenTools.defaultFontPixelHeight / 3 + } - QGCLabel { - anchors.baseline: offlineAltitudeField.baseline - text: "Alt:" - } + Item { + width: parent.width + height: offlineAltitudeField.height - QGCTextField { - id: offlineAltitudeField - anchors.right: parent.right - width: _editFieldWidth - text: offlineHomePosition.altitude - } + QGCLabel { + anchors.baseline: offlineAltitudeField.baseline + text: "Alt:" } - Item { - width: 10 - height: ScreenTools.defaultFontPixelHeight + QGCTextField { + id: offlineAltitudeField + anchors.right: parent.right + width: _editFieldWidth + text: offlineHomePosition.altitude } + } - Row { - spacing: ScreenTools.defaultFontPixelWidth - - QGCButton { - text: "Add/Update" + Item { + width: 10 + height: ScreenTools.defaultFontPixelHeight + } - onClicked: { - offlineHomePosition = QtPositioning.coordinate(latitudeField.text, longitudeField.text, altitudeField.text) - _homePositionManager.updateHomePosition(nameField.text, offlineHomePosition) - homePosCombo.currentIndex = homePosCombo.find(nameField.text) - } - } + Row { + spacing: ScreenTools.defaultFontPixelWidth - QGCButton { - text: "Delete" + QGCButton { + text: "Add/Update" - onClicked: { - homePosCombo.currentIndex = -1 - _homePositionManager.deleteHomePosition(nameField.text) - homePosCombo.currentIndex = 0 - var homePos = _homePositionManager.homePositions.get(0) - _homePositionName = homePos.name - offlineHomePosition = homePos.coordinate - } + onClicked: { + offlineHomePosition = QtPositioning.coordinate(latitudeField.text, longitudeField.text, altitudeField.text) + _homePositionManager.updateHomePosition(nameField.text, offlineHomePosition) + homePosCombo.currentIndex = homePosCombo.find(nameField.text) } } - } // Column - Offline view - Column { - anchors.fill: parent - visible: liveHomePositionAvailable + QGCButton { + text: "Delete" - QGCLabel { - font.pixelSize: ScreenTools.mediumFontPixelSize - text: "Vehicle Home Position" + onClicked: { + homePosCombo.currentIndex = -1 + _homePositionManager.deleteHomePosition(nameField.text) + homePosCombo.currentIndex = 0 + var homePos = _homePositionManager.homePositions.get(0) + _homePositionName = homePos.name + offlineHomePosition = homePos.coordinate + } } + } + } // Column - Offline view - Item { - width: 10 - height: ScreenTools.defaultFontPixelHeight - } + Column { + anchors.margins: _margin + anchors.fill: parent + visible: liveHomePositionAvailable - Item { - width: parent.width - height: liveLatitudeField.height + QGCLabel { + font.pixelSize: ScreenTools.mediumFontPixelSize + text: "Vehicle Home Position" + } - QGCLabel { - anchors.baseline: liveLatitudeField.baseline - text: "Lat:" - } + Item { + width: 10 + height: ScreenTools.defaultFontPixelHeight + } - QGCLabel { - id: liveLatitudeField - anchors.right: parent.right - width: _editFieldWidth - text: liveHomePosition.latitude - } + Item { + width: parent.width + height: liveLatitudeField.height + + QGCLabel { + anchors.baseline: liveLatitudeField.baseline + text: "Lat:" } - Item { - width: 10 - height: ScreenTools.defaultFontPixelHeight / 3 + QGCLabel { + id: liveLatitudeField + anchors.right: parent.right + width: _editFieldWidth + text: liveHomePosition.latitude } + } - Item { - width: parent.width - height: liveLongitudeField.height + Item { + width: 10 + height: ScreenTools.defaultFontPixelHeight / 3 + } - QGCLabel { - anchors.baseline: liveLongitudeField.baseline - text: "Lon:" - } + Item { + width: parent.width + height: liveLongitudeField.height - QGCLabel { - id: liveLongitudeField - anchors.right: parent.right - width: _editFieldWidth - text: liveHomePosition.longitude - } + QGCLabel { + anchors.baseline: liveLongitudeField.baseline + text: "Lon:" } - Item { - width: 10 - height: ScreenTools.defaultFontPixelHeight / 3 + QGCLabel { + id: liveLongitudeField + anchors.right: parent.right + width: _editFieldWidth + text: liveHomePosition.longitude } + } - Item { - width: parent.width - height: liveAltitudeField.height + Item { + width: 10 + height: ScreenTools.defaultFontPixelHeight / 3 + } - QGCLabel { - anchors.baseline: liveAltitudeField.baseline - text: "Alt:" - } + Item { + width: parent.width + height: liveAltitudeField.height - QGCLabel { - id: liveAltitudeField - anchors.right: parent.right - width: _editFieldWidth - text: liveHomePosition.altitude - } + QGCLabel { + anchors.baseline: liveAltitudeField.baseline + text: "Alt:" } - } // 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 { - id: helpPanel - anchors.fill: parent - visible: !homePositionManagerButton.checked && (_missionItems.count == 1 || helpButton.checked) + anchors.margins: _margin + anchors.fill: parent QGCLabel { id: helpTitle @@ -876,9 +746,210 @@ QGCView { text: "Map Type
" + "Map type options." } - } // Item - Help Panel - } // Item - } // Rectangle - mission item list + } // Item - margin + } // Item - Help Panel + + 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 } // QGCViewPanel } // QGCVIew diff --git a/src/MissionEditor/MissionEditorController.cc b/src/MissionEditor/MissionEditorController.cc index a15a7f24381a107bfd915cb6bdf6f3ab1ac25d5a..0f4691a01a7f71b001f7399931dead5f1c512505 100644 --- a/src/MissionEditor/MissionEditorController.cc +++ b/src/MissionEditor/MissionEditorController.cc @@ -103,14 +103,15 @@ int MissionEditorController::addMissionItem(QGeoCoordinate coordinate) if (!_canEdit) { 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); _initMissionItem(newItem); - newItem->setAltitude(30); if (_missionItems->count() == 1) { newItem->setCommand(MavlinkQmlSingleton::MAV_CMD_NAV_TAKEOFF); } - qDebug() << "MissionItem" << newItem->coordinate(); _missionItems->append(newItem); _recalcAll(); diff --git a/src/MissionItem.cc b/src/MissionItem.cc index f3a02fa23df83d05d2cf22979a8930965f2f244e..4ce5e21524cc27e4dc9fa830f29c92b148646d7b 100644 --- a/src/MissionItem.cc +++ b/src/MissionItem.cc @@ -36,6 +36,13 @@ This file is part of the QGROUNDCONTROL project 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) { QDebugStateSaver saver(dbg); @@ -82,14 +89,14 @@ MissionItem::MissionItem(QObject* parent, , _autocontinue(autocontinue) , _isCurrentItem(isCurrentItem) , _reachedTime(0) - , _yawRadiansFact(NULL) + , _headingDegreesFact(NULL) ,_dirty(false) , _homePositionSpecialCase(false) { _latitudeFact = new Fact(0, "Latitude:", FactMetaData::valueTypeDouble, this); _longitudeFact = new Fact(0, "Longitude:", 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); _param1Fact = new Fact(0, QString(), FactMetaData::valueTypeDouble, this); _param2Fact = new Fact(0, QString(), FactMetaData::valueTypeDouble, this); @@ -100,7 +107,7 @@ MissionItem::MissionItem(QObject* parent, setCoordinate(coordinate); setParam1(param1); setParam2(param2); - setYawRadians(param4); + _setYawRadians(param4); setLoiterOrbitRadius(param3); // FIXME: Need to fill out more meta data @@ -114,8 +121,8 @@ MissionItem::MissionItem(QObject* parent, FactMetaData* altitudeMetaData = new FactMetaData(FactMetaData::valueTypeDouble, _altitudeFact); altitudeMetaData->setUnits("meters"); - FactMetaData* yawMetaData = new FactMetaData(FactMetaData::valueTypeDouble, _yawRadiansFact); - yawMetaData->setUnits("deg"); + FactMetaData* headingMetaData = new FactMetaData(FactMetaData::valueTypeDouble, _headingDegreesFact); + headingMetaData->setUnits("deg"); _pitchMetaData = new FactMetaData(FactMetaData::valueTypeDouble, this); _pitchMetaData->setUnits("deg"); @@ -147,23 +154,10 @@ MissionItem::MissionItem(QObject* parent, _latitudeFact->setMetaData(latitudeMetaData); _longitudeFact->setMetaData(longitudeMetaData); _altitudeFact->setMetaData(altitudeMetaData); - _yawRadiansFact->setMetaData(yawMetaData); + _headingDegreesFact->setMetaData(headingMetaData); _loiterOrbitRadiusFact->setMetaData(loiterOrbitRadiusMetaData); - // 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(_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); + _connectSignals(); } MissionItem::MissionItem(const MissionItem& other, QObject* parent) @@ -172,7 +166,7 @@ MissionItem::MissionItem(const MissionItem& other, QObject* parent) _latitudeFact = new Fact(this); _longitudeFact = new Fact(this); _altitudeFact = new Fact(this); - _yawRadiansFact = new Fact(this); + _headingDegreesFact = new Fact(this); _loiterOrbitRadiusFact = new Fact(this); _param1Fact = new Fact(this); _param2Fact = new Fact(this); @@ -188,26 +182,9 @@ MissionItem::MissionItem(const MissionItem& other, QObject* parent) _jumpSequenceMetaData = new FactMetaData(this); _jumpRepeatMetaData = new FactMetaData(this); - // 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(_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; -} + _connectSignals(); -MissionItem::~MissionItem() -{ + *this = other; } const MissionItem& MissionItem::operator=(const MissionItem& other) @@ -221,15 +198,15 @@ const MissionItem& MissionItem::operator=(const MissionItem& other) _altitudeRelativeToHomeFact = other._altitudeRelativeToHomeFact; _dirty = other._dirty; _homePositionSpecialCase = other._homePositionSpecialCase; - + *_latitudeFact = *other._latitudeFact; *_longitudeFact = *other._longitudeFact; *_altitudeFact = *other._altitudeFact; - *_yawRadiansFact = *other._yawRadiansFact; + *_headingDegreesFact = *other._headingDegreesFact; *_loiterOrbitRadiusFact = *other._loiterOrbitRadiusFact; *_param1Fact = *other._param1Fact; *_param2Fact = *other._param2Fact; - + *_pitchMetaData = *other._pitchMetaData; *_acceptanceRadiusMetaData = *other._acceptanceRadiusMetaData; *_holdTimeMetaData = *other._holdTimeMetaData; @@ -238,10 +215,34 @@ const MissionItem& MissionItem::operator=(const MissionItem& other) *_delaySecondsMetaData = *other._delaySecondsMetaData; *_jumpSequenceMetaData = *other._jumpSequenceMetaData; *_jumpRepeatMetaData = *other._jumpRepeatMetaData; - + 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() { return (_command < MavlinkQmlSingleton::MAV_CMD_NAV_LAST); @@ -254,7 +255,7 @@ void MissionItem::save(QTextStream &saveStream) position = position.arg(y(), 0, 'g', 18); position = position.arg(z(), 0, 'g', 18); 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: // 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"; @@ -271,7 +272,7 @@ bool MissionItem::load(QTextStream &loadStream) setParam1(wpParams[4].toDouble()); setParam2(wpParams[5].toDouble()); setLoiterOrbitRadius(wpParams[6].toDouble()); - setYawRadians(wpParams[7].toDouble()); + _setYawRadians(wpParams[7].toDouble()); setLatitude(wpParams[8].toDouble()); setLongitude(wpParams[9].toDouble()); setAltitude(wpParams[10].toDouble()); @@ -351,11 +352,27 @@ void MissionItem::setAction(int /*MAV_CMD*/ action) // Fix defaults according to WP type - if (_command == MavlinkQmlSingleton::MAV_CMD_NAV_TAKEOFF) { - // We default to 15 degrees minimum takeoff pitch - setParam1(15.0); + switch (_command) { + case MavlinkQmlSingleton::MAV_CMD_NAV_TAKEOFF: + 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 (_frame != MAV_FRAME_GLOBAL && _frame != MAV_FRAME_GLOBAL_RELATIVE_ALT) { setFrame(MAV_FRAME_GLOBAL_RELATIVE_ALT); @@ -438,7 +455,7 @@ void MissionItem::setParam3(double param3) void MissionItem::setParam4(double param4) { - setYawRadians(param4); + _setYawRadians(param4); } void MissionItem::setParam5(double param5) @@ -526,6 +543,46 @@ QString MissionItem::commandName(void) 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."; + break; + case MAV_CMD_NAV_LAND: + description = "Land vehicle at the specified location."; + break; + case MAV_CMD_NAV_TAKEOFF: + description = "Take off from the ground and travel towards 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 labels; @@ -590,24 +647,24 @@ QStringList MissionItem::valueStrings(void) switch (_command) { 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; case MAV_CMD_NAV_LOITER_UNLIM: - list << _oneDecimalString(yawRadians() * (180.0 / M_PI)) << _oneDecimalString(loiterOrbitRadius()); + list << _oneDecimalString(headingDegrees()) << _oneDecimalString(loiterOrbitRadius()); break; 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; 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; case MAV_CMD_NAV_RETURN_TO_LAUNCH: break; case MAV_CMD_NAV_LAND: - list << _oneDecimalString(_altitudeFact->value().toDouble()) << _oneDecimalString(yawRadians() * (180.0 / M_PI)); + list << _oneDecimalString(_altitudeFact->value().toDouble()) << _oneDecimalString(headingDegrees()); break; 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; case MAV_CMD_CONDITION_DELAY: list << _oneDecimalString(param1()); @@ -659,59 +716,38 @@ QmlObjectListModel* MissionItem::textFieldFacts(void) switch ((MAV_CMD)_command) { case MAV_CMD_NAV_WAYPOINT: - _param2Fact->_setName("Radius:"); - _param2Fact->setMetaData(_acceptanceRadiusMetaData); _param1Fact->_setName("Hold:"); _param1Fact->setMetaData(_holdTimeMetaData); - model->append(_latitudeFact); - model->append(_longitudeFact); model->append(_altitudeFact); if (!_homePositionSpecialCase) { - model->append(_yawRadiansFact); - model->append(_param2Fact); model->append(_param1Fact); } break; case MAV_CMD_NAV_LOITER_UNLIM: - model->append(_latitudeFact); - model->append(_longitudeFact); model->append(_altitudeFact); - model->append(_yawRadiansFact); model->append(_loiterOrbitRadiusFact); break; case MAV_CMD_NAV_LOITER_TURNS: _param1Fact->_setName("Turns:"); _param1Fact->setMetaData(_loiterTurnsMetaData); - model->append(_latitudeFact); - model->append(_longitudeFact); model->append(_altitudeFact); - model->append(_yawRadiansFact); model->append(_loiterOrbitRadiusFact); model->append(_param1Fact); break; case MAV_CMD_NAV_LOITER_TIME: _param1Fact->_setName("Seconds:"); _param1Fact->setMetaData(_loiterSecondsMetaData); - model->append(_latitudeFact); - model->append(_longitudeFact); model->append(_altitudeFact); - model->append(_yawRadiansFact); model->append(_loiterOrbitRadiusFact); model->append(_param1Fact); break; case MAV_CMD_NAV_LAND: - model->append(_latitudeFact); - model->append(_longitudeFact); model->append(_altitudeFact); - model->append(_yawRadiansFact); break; case MAV_CMD_NAV_TAKEOFF: _param1Fact->_setName("Pitch:"); _param1Fact->setMetaData(_pitchMetaData); - model->append(_latitudeFact); - model->append(_longitudeFact); model->append(_altitudeFact); - model->append(_yawRadiansFact); model->append(_param1Fact); break; case MAV_CMD_CONDITION_DELAY: @@ -730,6 +766,11 @@ QmlObjectListModel* MissionItem::textFieldFacts(void) default: break; } + + if (specifiesHeading()) { + model->append(_headingDegreesFact); + } + return model; } @@ -768,30 +809,30 @@ QmlObjectListModel* MissionItem::checkboxFacts(void) 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) - { - _yawRadiansFact->setValue(yaw); + if (_headingDegreesFact->value().toDouble() != headingDegrees) { + _headingDegreesFact->setValue(headingDegrees); emit changed(this); 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 @@ -854,3 +895,19 @@ void MissionItem::_coordinateFactChanged(QVariant value) Q_UNUSED(value); 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()); +} diff --git a/src/MissionItem.h b/src/MissionItem.h index 09c57ade62aa1dec30b87fa42f664af39a48d450..382c3d8c48c0ab44bd4717e6089667c878933f3e 100644 --- a/src/MissionItem.h +++ b/src/MissionItem.h @@ -50,9 +50,9 @@ public: QGeoCoordinate coordiante = QGeoCoordinate(), int action = MAV_CMD_NAV_WAYPOINT, double param1 = 0.0, - double param2 = 0.0, - double param3 = 0.0, - double param4 = 0.0, + double param2 = defaultAcceptanceRadius, + double param3 = defaultLoiterOrbitRadius, + double param4 = defaultHeading, bool autocontinue = true, bool isCurrentItem = false, int frame = MAV_FRAME_GLOBAL_RELATIVE_ALT); @@ -67,10 +67,16 @@ public: 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 commandChanged) 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(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 valueStrings READ valueStrings NOTIFY valueStringsChanged) Q_PROPERTY(int commandByIndex READ commandByIndex WRITE setCommandByIndex NOTIFY commandChanged) @@ -88,12 +94,19 @@ public: void setIsCurrentItem(bool isCurrentItem); bool specifiesCoordinate(void) const; - QGeoCoordinate coordinate(void) const; void setCoordinate(const QGeoCoordinate& coordinate); + bool specifiesHeading(void) const; + double headingDegrees(void) const; + void setHeadingDegrees(double headingDegrees); + + // This is public for unit testing + double _yawRadians(void) const; + QStringList commandNames(void); QString commandName(void); + QString commandDescription(void); int commandByIndex(void); void setCommandByIndex(int index); @@ -107,9 +120,6 @@ public: QmlObjectListModel* textFieldFacts(void); QmlObjectListModel* checkboxFacts(void); - double yawDegrees(void) const; - void setYawDegrees(double yaw); - bool dirty(void) { return _dirty; } void setDirty(bool dirty); @@ -136,9 +146,6 @@ public: void setY(double y); void setZ(double z); - double yawRadians(void) const; - void setYawRadians(double yaw); - bool autoContinue() const { return _autocontinue; } @@ -161,7 +168,7 @@ public: return loiterOrbitRadius(); } double param4() const { - return yawRadians(); + return _yawRadians(); } double param5() const { return latitude(); @@ -189,11 +196,19 @@ public: bool load(QTextStream &loadStream); 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: void sequenceNumberChanged(int sequenceNumber); void isCurrentItemChanged(bool isCurrentItem); void coordinateChanged(const QGeoCoordinate& coordinate); + void headingDegreesChanged(double heading); void dirtyChanged(bool dirty); /** @brief Announces a change to the waypoint data */ @@ -234,9 +249,12 @@ public: private slots: void _factValueChanged(QVariant value); void _coordinateFactChanged(QVariant value); + void _headingDegreesFactChanged(QVariant value); private: QString _oneDecimalString(double value); + void _connectSignals(void); + void _setYawRadians(double yawRadians); private: typedef struct { @@ -254,7 +272,7 @@ private: Fact* _latitudeFact; Fact* _longitudeFact; Fact* _altitudeFact; - Fact* _yawRadiansFact; + Fact* _headingDegreesFact; Fact* _loiterOrbitRadiusFact; Fact* _param1Fact; Fact* _param2Fact; diff --git a/src/MissionItemTest.cc b/src/MissionItemTest.cc index 59d590450843b4997ad99b76c90af821dd15cf50..b19582b1a4c66f24d7786b5ecbe77c6ba3798716 100644 --- a/src/MissionItemTest.cc +++ b/src/MissionItemTest.cc @@ -27,63 +27,46 @@ UT_REGISTER_TEST(MissionItemTest) const MissionItemTest::ItemInfo_t MissionItemTest::_rgItemInfo[] = { - { 1, QGeoCoordinate(-10.0, -20.0, -30.0), MAV_CMD_NAV_WAYPOINT, 10.0, 20.0, 30.0, 40.0, true, false, MAV_FRAME_GLOBAL_RELATIVE_ALT }, - { 1, QGeoCoordinate(-10.0, -20.0, -30.0), MAV_CMD_NAV_LOITER_UNLIM, 10.0, 20.0, 30.0, 40.0, true, false, MAV_FRAME_GLOBAL_RELATIVE_ALT }, - { 1, QGeoCoordinate(-10.0, -20.0, -30.0), MAV_CMD_NAV_LOITER_TURNS, 10.0, 20.0, 30.0, 40.0, true, false, MAV_FRAME_GLOBAL_RELATIVE_ALT }, - { 1, QGeoCoordinate(-10.0, -20.0, -30.0), MAV_CMD_NAV_LOITER_TIME, 10.0, 20.0, 30.0, 40.0, true, false, MAV_FRAME_GLOBAL_RELATIVE_ALT }, - { 1, QGeoCoordinate(-10.0, -20.0, -30.0), MAV_CMD_NAV_LAND, 10.0, 20.0, 30.0, 40.0, true, false, MAV_FRAME_GLOBAL_RELATIVE_ALT }, - { 1, QGeoCoordinate(-10.0, -20.0, -30.0), MAV_CMD_NAV_TAKEOFF, 10.0, 20.0, 30.0, 40.0, true, false, MAV_FRAME_GLOBAL_RELATIVE_ALT }, - { 1, QGeoCoordinate(-10.0, -20.0, -30.0), MAV_CMD_CONDITION_DELAY, 10.0, 20.0, 30.0, 40.0, true, false, MAV_FRAME_MISSION }, - { 1, QGeoCoordinate(-10.0, -20.0, -30.0), MAV_CMD_DO_JUMP, 10.0, 20.0, 30.0, 40.0, true, false, MAV_FRAME_MISSION }, + { 1, QGeoCoordinate(-10.0, -20.0, -30.0), MAV_CMD_NAV_WAYPOINT, 10.0, 20.0, 30.0, 1.0, true, false, MAV_FRAME_GLOBAL_RELATIVE_ALT }, + { 1, QGeoCoordinate(-10.0, -20.0, -30.0), MAV_CMD_NAV_LOITER_UNLIM, 10.0, 20.0, 30.0, 1.0, true, false, MAV_FRAME_GLOBAL_RELATIVE_ALT }, + { 1, QGeoCoordinate(-10.0, -20.0, -30.0), MAV_CMD_NAV_LOITER_TURNS, 10.0, 20.0, 30.0, 1.0, true, false, MAV_FRAME_GLOBAL_RELATIVE_ALT }, + { 1, QGeoCoordinate(-10.0, -20.0, -30.0), MAV_CMD_NAV_LOITER_TIME, 10.0, 20.0, 30.0, 1.0, true, false, MAV_FRAME_GLOBAL_RELATIVE_ALT }, + { 1, QGeoCoordinate(-10.0, -20.0, -30.0), MAV_CMD_NAV_LAND, 10.0, 20.0, 30.0, 1.0, true, false, MAV_FRAME_GLOBAL_RELATIVE_ALT }, + { 1, QGeoCoordinate(-10.0, -20.0, -30.0), MAV_CMD_NAV_TAKEOFF, 10.0, 20.0, 30.0, 1.0, true, false, MAV_FRAME_GLOBAL_RELATIVE_ALT }, + { 1, QGeoCoordinate(-10.0, -20.0, -30.0), MAV_CMD_CONDITION_DELAY, 10.0, 20.0, 30.0, 1.0, true, false, MAV_FRAME_MISSION }, + { 1, QGeoCoordinate(-10.0, -20.0, -30.0), MAV_CMD_DO_JUMP, 10.0, 20.0, 30.0, 1.0, true, false, MAV_FRAME_MISSION }, }; const MissionItemTest::FactValue_t MissionItemTest::_rgFactValuesWaypoint[] = { - { "Latitude:", -10.0 }, - { "Longitude:", -20.0 }, { "Altitude:", -30.0 }, - { "Heading:", 40.0 }, - { "Radius:", 20.0 }, { "Hold:", 10.0 }, }; const MissionItemTest::FactValue_t MissionItemTest::_rgFactValuesLoiterUnlim[] = { - { "Latitude:", -10.0 }, - { "Longitude:", -20.0 }, { "Altitude:", -30.0 }, - { "Heading:", 40.0 }, { "Radius:", 30.0 }, }; const MissionItemTest::FactValue_t MissionItemTest::_rgFactValuesLoiterTurns[] = { - { "Latitude:", -10.0 }, - { "Longitude:", -20.0 }, { "Altitude:", -30.0 }, - { "Heading:", 40.0 }, { "Radius:", 30.0 }, { "Turns:", 10.0 }, }; const MissionItemTest::FactValue_t MissionItemTest::_rgFactValuesLoiterTime[] = { - { "Latitude:", -10.0 }, - { "Longitude:", -20.0 }, { "Altitude:", -30.0 }, - { "Heading:", 40.0 }, { "Radius:", 30.0 }, { "Seconds:", 10.0 }, }; const MissionItemTest::FactValue_t MissionItemTest::_rgFactValuesLand[] = { - { "Latitude:", -10.0 }, - { "Longitude:", -20.0 }, { "Altitude:", -30.0 }, - { "Heading:", 40.0 }, + { "Heading:", 1.0 }, }; const MissionItemTest::FactValue_t MissionItemTest::_rgFactValuesTakeoff[] = { - { "Latitude:", -10.0 }, - { "Longitude:", -20.0 }, { "Altitude:", -30.0 }, - { "Heading:", 40.0 }, + { "Heading:", 1.0 }, { "Pitch:", 10.0 }, }; @@ -97,14 +80,14 @@ const MissionItemTest::FactValue_t MissionItemTest::_rgFactValuesDoJump[] = { }; const MissionItemTest::ItemExpected_t MissionItemTest::_rgItemExpected[] = { - { "1\t0\t3\t16\t10\t20\t30\t40\t-10\t-20\t-30\t1\r\n", sizeof(MissionItemTest::_rgFactValuesWaypoint)/sizeof(MissionItemTest::_rgFactValuesWaypoint[0]), MissionItemTest::_rgFactValuesWaypoint }, - { "1\t0\t3\t17\t10\t20\t30\t40\t-10\t-20\t-30\t1\r\n", sizeof(MissionItemTest::_rgFactValuesLoiterUnlim)/sizeof(MissionItemTest::_rgFactValuesLoiterUnlim[0]), MissionItemTest::_rgFactValuesLoiterUnlim }, - { "1\t0\t3\t18\t10\t20\t30\t40\t-10\t-20\t-30\t1\r\n", sizeof(MissionItemTest::_rgFactValuesLoiterTurns)/sizeof(MissionItemTest::_rgFactValuesLoiterTurns[0]), MissionItemTest::_rgFactValuesLoiterTurns }, - { "1\t0\t3\t19\t10\t20\t30\t40\t-10\t-20\t-30\t1\r\n", sizeof(MissionItemTest::_rgFactValuesLoiterTime)/sizeof(MissionItemTest::_rgFactValuesLoiterTime[0]), MissionItemTest::_rgFactValuesLoiterTime }, - { "1\t0\t3\t21\t10\t20\t30\t40\t-10\t-20\t-30\t1\r\n", sizeof(MissionItemTest::_rgFactValuesLand)/sizeof(MissionItemTest::_rgFactValuesLand[0]), MissionItemTest::_rgFactValuesLand }, - { "1\t0\t3\t22\t10\t20\t30\t40\t-10\t-20\t-30\t1\r\n", sizeof(MissionItemTest::_rgFactValuesTakeoff)/sizeof(MissionItemTest::_rgFactValuesTakeoff[0]), MissionItemTest::_rgFactValuesTakeoff }, - { "1\t0\t2\t112\t10\t20\t30\t40\t-10\t-20\t-30\t1\r\n", sizeof(MissionItemTest::_rgFactValuesConditionDelay)/sizeof(MissionItemTest::_rgFactValuesConditionDelay[0]), MissionItemTest::_rgFactValuesConditionDelay }, - { "1\t0\t2\t177\t10\t20\t30\t40\t-10\t-20\t-30\t1\r\n", sizeof(MissionItemTest::_rgFactValuesDoJump)/sizeof(MissionItemTest::_rgFactValuesDoJump[0]), MissionItemTest::_rgFactValuesDoJump }, + { "1\t0\t3\t16\t10\t20\t30\t1\t-10\t-20\t-30\t1\r\n", sizeof(MissionItemTest::_rgFactValuesWaypoint)/sizeof(MissionItemTest::_rgFactValuesWaypoint[0]), MissionItemTest::_rgFactValuesWaypoint }, + { "1\t0\t3\t17\t10\t20\t30\t1\t-10\t-20\t-30\t1\r\n", sizeof(MissionItemTest::_rgFactValuesLoiterUnlim)/sizeof(MissionItemTest::_rgFactValuesLoiterUnlim[0]), MissionItemTest::_rgFactValuesLoiterUnlim }, + { "1\t0\t3\t18\t10\t20\t30\t1\t-10\t-20\t-30\t1\r\n", sizeof(MissionItemTest::_rgFactValuesLoiterTurns)/sizeof(MissionItemTest::_rgFactValuesLoiterTurns[0]), MissionItemTest::_rgFactValuesLoiterTurns }, + { "1\t0\t3\t19\t10\t20\t30\t1\t-10\t-20\t-30\t1\r\n", sizeof(MissionItemTest::_rgFactValuesLoiterTime)/sizeof(MissionItemTest::_rgFactValuesLoiterTime[0]), MissionItemTest::_rgFactValuesLoiterTime }, + { "1\t0\t3\t21\t10\t20\t30\t1\t-10\t-20\t-30\t1\r\n", sizeof(MissionItemTest::_rgFactValuesLand)/sizeof(MissionItemTest::_rgFactValuesLand[0]), MissionItemTest::_rgFactValuesLand }, + { "1\t0\t3\t22\t10\t20\t30\t1\t-10\t-20\t-30\t1\r\n", sizeof(MissionItemTest::_rgFactValuesTakeoff)/sizeof(MissionItemTest::_rgFactValuesTakeoff[0]), MissionItemTest::_rgFactValuesTakeoff }, + { "1\t0\t2\t112\t10\t20\t30\t1\t-10\t-20\t-30\t1\r\n", sizeof(MissionItemTest::_rgFactValuesConditionDelay)/sizeof(MissionItemTest::_rgFactValuesConditionDelay[0]), MissionItemTest::_rgFactValuesConditionDelay }, + { "1\t0\t2\t177\t10\t20\t30\t1\t-10\t-20\t-30\t1\r\n", sizeof(MissionItemTest::_rgFactValuesDoJump)/sizeof(MissionItemTest::_rgFactValuesDoJump[0]), MissionItemTest::_rgFactValuesDoJump }, }; MissionItemTest::MissionItemTest(void) @@ -149,7 +132,11 @@ void MissionItemTest::_test(void) if (factValue->name == fact->name()) { qDebug() << factValue->name; - QCOMPARE(fact->value().toDouble(), factValue->value); + if (strcmp(factValue->name, "Heading:") == 0) { + QCOMPARE(fact->value().toDouble() * (M_PI / 180.0), item->_yawRadians()); + } else { + QCOMPARE(fact->value().toDouble(), factValue->value); + } factCount ++; found = true; break; @@ -158,6 +145,7 @@ void MissionItemTest::_test(void) QVERIFY(found); } + qDebug() << info->command; QCOMPARE(factCount, expected->cFactValues); // Validate that loading is working correctly diff --git a/src/QmlControls/DropButton.qml b/src/QmlControls/DropButton.qml index acd67352d94fdce6e426cdd80afec0f5ddfa455b..493f12a6a6724aa6d37424fe66a46d2c9f9a20ec 100644 --- a/src/QmlControls/DropButton.qml +++ b/src/QmlControls/DropButton.qml @@ -224,7 +224,7 @@ Item { context.lineTo(dropItemHolderRect.x, dropItemHolderRect.y) context.closePath() - context.fillStyle = qgcPal.button + context.fillStyle = qgcPal.windowShade context.fill() } } // Canvas - arrowCanvas diff --git a/src/QmlControls/MissionItemEditor.qml b/src/QmlControls/MissionItemEditor.qml index b4c6f0e828a3bd2f685d07004a018687ca1ca1e9..3c7cb04d84908410807040a5523522cd239665bd 100644 --- a/src/QmlControls/MissionItemEditor.qml +++ b/src/QmlControls/MissionItemEditor.qml @@ -19,34 +19,26 @@ Rectangle { signal clicked signal remove - height: missionItem.isCurrentItem ? - (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) + height: innerItem.height + (_margin * 2) color: missionItem.isCurrentItem ? qgcPal.buttonHighlight : qgcPal.windowShade + radius: _radius 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 { id: qgcPal colorGroupEnabled: enabled } - QGCTextField { - id: measureTextField - visible: false - } - - QGCCheckBox { - id: measureCheckbox - visible: false - } - Item { + id: innerItem 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 { id: label @@ -69,7 +61,7 @@ Rectangle { anchors.right: parent.right currentIndex: missionItem.commandByIndex 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 } @@ -77,30 +69,36 @@ Rectangle { Rectangle { anchors.fill: commandPicker color: qgcPal.button - visible: missionItem.sequenceNumber == 0 // Item 0 is home position, can't change item type + visible: !commandPicker.visible QGCLabel { id: homeLabel anchors.leftMargin: ScreenTools.defaultFontPixelWidth anchors.fill: parent verticalAlignment: Text.AlignVCenter - text: "Home" + text: missionItem.sequenceNumber == 0 ? "Home" : missionItem.commandName color: qgcPal.buttonText } } Rectangle { + id: valuesRect anchors.topMargin: _margin anchors.top: commandPicker.bottom - anchors.bottom: parent.bottom anchors.left: parent.left anchors.right: parent.right + height: valuesItem.height color: qgcPal.windowShadeDark visible: missionItem.isCurrentItem + radius: _radius Item { + id: valuesItem anchors.margins: _margin - anchors.fill: parent + anchors.left: parent.left + anchors.right: parent.right + anchors.top: parent.top + height: valuesColumn.height + _margin Column { id: valuesColumn @@ -109,6 +107,12 @@ Rectangle { anchors.top: parent.top spacing: _margin + QGCLabel { + width: parent.width + wrapMode: Text.WordWrap + text: missionItem.commandDescription + } + Repeater { model: missionItem.textFieldFacts @@ -140,11 +144,6 @@ Rectangle { } } - Item { - width: 10 - height: missionItem.textFieldFacts.count ? _margin : 0 - } - Repeater { model: missionItem.checkboxFacts @@ -154,28 +153,6 @@ Rectangle { 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 } // Item } // Rectangle diff --git a/src/QmlControls/MissionItemIndexLabel.qml b/src/QmlControls/MissionItemIndexLabel.qml index 1c6f6b03d93d39387c3b3b3f2bf80a4954e67ba3..dcbb577ad45ed9aae282c4a406b655d60333bc1b 100644 --- a/src/QmlControls/MissionItemIndexLabel.qml +++ b/src/QmlControls/MissionItemIndexLabel.qml @@ -13,7 +13,7 @@ Rectangle { QGCPalette { id: qgcPal } - width: ScreenTools.defaultFontPixelHeight * 1.5 + width: ScreenTools.mediumFontPixelSize * 1.5 height: width radius: width / 2 border.width: 2 @@ -32,5 +32,6 @@ Rectangle { horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter color: "white" + font.pixelSize: ScreenTools.mediumFontPixelSize } } diff --git a/src/ui/MainWindow.qml b/src/ui/MainWindow.qml index 0fe81f924e419331162b5a8c6da50e6184f934ac..83bc3ff67f5d2a1b80acce2cdc499a68520001a8 100644 --- a/src/ui/MainWindow.qml +++ b/src/ui/MainWindow.qml @@ -72,7 +72,7 @@ FlightDisplayView { onShowSetupFirmware: setupViewLoader.item.showFirmwarePanel() onShowSetupParameters: setupViewLoader.item.showParametersPanel() onShowSetupSummary: setupViewLoader.item.showSummaryPanel() - onShowSetupVehicleComponent: setupViewLoader.item.showVehicleComponentPanel(vechicleComponent) + onShowSetupVehicleComponent: setupViewLoader.item.showVehicleComponentPanel(vehicleComponent) } MainToolBar {