diff --git a/.travis.yml b/.travis.yml index c42feb37c27c4d0838c27aaafbc3585071fc76ce..a87e984ec72da807ed970d0b66ad1a61b21ee191 100644 --- a/.travis.yml +++ b/.travis.yml @@ -83,7 +83,7 @@ install: # android dependencies: qt, gstreamer, android-ndk - if [ "${SPEC}" = "android-g++" ]; then - wget --quiet http://www.grubba.com/gstreamer-1.0-android-universal-1.14.4.tar.bz2 && + wget --quiet https://s3-us-west-2.amazonaws.com/qgroundcontrol/dependencies/gstreamer-1.0-android-universal-1.14.4.tar.bz2 && tar jxf gstreamer-1.0-android-universal-1.14.4.tar.bz2 -C ${TRAVIS_BUILD_DIR} && wget --quiet https://s3-us-west-2.amazonaws.com/qgroundcontrol/dependencies/Qt5.11.0-android_armv7-min.tar.bz2 && tar jxf Qt5.11.0-android_armv7-min.tar.bz2 -C /tmp && diff --git a/QGCExternalLibs.pri b/QGCExternalLibs.pri index 656935fd5e3de5d6fe0d8eb7c428fdd178cded0c..0c9fc138827a5d1a33f70fa9b519c68ace018bd3 100644 --- a/QGCExternalLibs.pri +++ b/QGCExternalLibs.pri @@ -132,6 +132,16 @@ MacBuild { -lSDL2 } +AndroidBuild { + contains(QT_ARCH, arm) { + ANDROID_EXTRA_LIBS += $$BASEDIR/libs/AndroidOpenSSL/arch-armeabi-v7a/lib/libcrypto.so + ANDROID_EXTRA_LIBS += $$BASEDIR/libs/AndroidOpenSSL/arch-armeabi-v7a/lib/libssl.so + } else { + ANDROID_EXTRA_LIBS += $$BASEDIR/libs/AndroidOpenSSL/arch-x86/lib/libcrypto.so + ANDROID_EXTRA_LIBS += $$BASEDIR/libs/AndroidOpenSSL/arch-x86/lib/libssl.so + } +} + # # [OPTIONAL] Zeroconf for UDP links # diff --git a/android/AndroidManifest.xml b/android/AndroidManifest.xml index beddd03b6cc1420a604282d0812968789c0eb244..b696cd71962d92d408efa6679437f250db30a301 100644 --- a/android/AndroidManifest.xml +++ b/android/AndroidManifest.xml @@ -71,6 +71,8 @@ + + diff --git a/libs/AndroidOpenSSL/README.md b/libs/AndroidOpenSSL/README.md new file mode 100644 index 0000000000000000000000000000000000000000..3ba978a556b2f9d72aed99cda64f455a0f218d80 --- /dev/null +++ b/libs/AndroidOpenSSL/README.md @@ -0,0 +1 @@ +These OpenSLL libraries foir Android are built using the scripts found here: https://github.com/esutton/android-openssl \ No newline at end of file diff --git a/libs/AndroidOpenSSL/arch-armeabi-v7a/lib/libcrypto.a b/libs/AndroidOpenSSL/arch-armeabi-v7a/lib/libcrypto.a new file mode 100644 index 0000000000000000000000000000000000000000..40c26e62fee2e255809fe7f31913b9c2485ee0de Binary files /dev/null and b/libs/AndroidOpenSSL/arch-armeabi-v7a/lib/libcrypto.a differ diff --git a/libs/AndroidOpenSSL/arch-armeabi-v7a/lib/libcrypto.so b/libs/AndroidOpenSSL/arch-armeabi-v7a/lib/libcrypto.so new file mode 100755 index 0000000000000000000000000000000000000000..293c784ebeaff80890ce95bc1e826506165a2d61 Binary files /dev/null and b/libs/AndroidOpenSSL/arch-armeabi-v7a/lib/libcrypto.so differ diff --git a/libs/AndroidOpenSSL/arch-armeabi-v7a/lib/libssl.a b/libs/AndroidOpenSSL/arch-armeabi-v7a/lib/libssl.a new file mode 100644 index 0000000000000000000000000000000000000000..f077c80d04df19f7879b84a55f8db0783045d724 Binary files /dev/null and b/libs/AndroidOpenSSL/arch-armeabi-v7a/lib/libssl.a differ diff --git a/libs/AndroidOpenSSL/arch-armeabi-v7a/lib/libssl.so b/libs/AndroidOpenSSL/arch-armeabi-v7a/lib/libssl.so new file mode 100755 index 0000000000000000000000000000000000000000..805a33e63dbb3b093b18df02c9ba7995da9c2b74 Binary files /dev/null and b/libs/AndroidOpenSSL/arch-armeabi-v7a/lib/libssl.so differ diff --git a/libs/AndroidOpenSSL/arch-x86/lib/libcrypto.a b/libs/AndroidOpenSSL/arch-x86/lib/libcrypto.a new file mode 100644 index 0000000000000000000000000000000000000000..6a8dae43c4453b9bf8d7c4d7b2e73f9c5050563c Binary files /dev/null and b/libs/AndroidOpenSSL/arch-x86/lib/libcrypto.a differ diff --git a/libs/AndroidOpenSSL/arch-x86/lib/libcrypto.so b/libs/AndroidOpenSSL/arch-x86/lib/libcrypto.so new file mode 100755 index 0000000000000000000000000000000000000000..75525b60c05e870135bc706face52a3698305dc3 Binary files /dev/null and b/libs/AndroidOpenSSL/arch-x86/lib/libcrypto.so differ diff --git a/libs/AndroidOpenSSL/arch-x86/lib/libssl.a b/libs/AndroidOpenSSL/arch-x86/lib/libssl.a new file mode 100644 index 0000000000000000000000000000000000000000..15d038f70cf06767f7efb3e3960ad35ac497c44a Binary files /dev/null and b/libs/AndroidOpenSSL/arch-x86/lib/libssl.a differ diff --git a/libs/AndroidOpenSSL/arch-x86/lib/libssl.so b/libs/AndroidOpenSSL/arch-x86/lib/libssl.so new file mode 100755 index 0000000000000000000000000000000000000000..17a1d6bda8ad6e3354f55f897bb2d380a3da0512 Binary files /dev/null and b/libs/AndroidOpenSSL/arch-x86/lib/libssl.so differ diff --git a/libs/mavlink/include/mavlink/v2.0 b/libs/mavlink/include/mavlink/v2.0 index c38176a0a63556815ea117c6877ce2dd18739231..90d9b285e01fe8bfa3b4e8868ca71c5537d43302 160000 --- a/libs/mavlink/include/mavlink/v2.0 +++ b/libs/mavlink/include/mavlink/v2.0 @@ -1 +1 @@ -Subproject commit c38176a0a63556815ea117c6877ce2dd18739231 +Subproject commit 90d9b285e01fe8bfa3b4e8868ca71c5537d43302 diff --git a/src/FirmwarePlugin/APM/APMFirmwarePlugin.h b/src/FirmwarePlugin/APM/APMFirmwarePlugin.h index 69a153ccd244ac33a72e05c37101f24fd40fd9c3..bac34679a75151a1e54e6f5e002e7603784a2a3f 100644 --- a/src/FirmwarePlugin/APM/APMFirmwarePlugin.h +++ b/src/FirmwarePlugin/APM/APMFirmwarePlugin.h @@ -84,6 +84,7 @@ public: QString flightMode (uint8_t base_mode, uint32_t custom_mode) const override; bool setFlightMode (const QString& flightMode, uint8_t* base_mode, uint32_t* custom_mode) override; bool isGuidedMode (const Vehicle* vehicle) const override; + QString gotoFlightMode (void) const override { return QStringLiteral("Guided"); } QString rtlFlightMode (void) const override { return QString("RTL"); } QString missionFlightMode (void) const override { return QString("Auto"); } void pauseVehicle (Vehicle* vehicle) override; diff --git a/src/FirmwarePlugin/FirmwarePlugin.cc b/src/FirmwarePlugin/FirmwarePlugin.cc index 057aca88f1604da82e3a5e34daa7bd08a7641b8e..db2a86969394f52d3033e41e4e42a1e4d2c43960 100644 --- a/src/FirmwarePlugin/FirmwarePlugin.cc +++ b/src/FirmwarePlugin/FirmwarePlugin.cc @@ -757,3 +757,8 @@ int FirmwarePlugin::versionCompare(Vehicle* vehicle, QString& compare) int patch = versionNumbers[2].toInt(); return versionCompare(vehicle, major, minor, patch); } + +QString FirmwarePlugin::gotoFlightMode(void) const +{ + return QString(); +} diff --git a/src/FirmwarePlugin/FirmwarePlugin.h b/src/FirmwarePlugin/FirmwarePlugin.h index d5c442b164a0fa21cafb74fd7c6842a16512c3ca..81d2d2abcd7e0e9a4fc87b1142ae2756b4c70a6b 100644 --- a/src/FirmwarePlugin/FirmwarePlugin.h +++ b/src/FirmwarePlugin/FirmwarePlugin.h @@ -114,6 +114,9 @@ public: /// Returns whether the vehicle is in guided mode or not. virtual bool isGuidedMode(const Vehicle* vehicle) const; + /// Returns the flight mode which the vehicle will be in if it is performing a goto location + virtual QString gotoFlightMode(void) const; + /// Set guided flight mode virtual void setGuidedMode(Vehicle* vehicle, bool guidedMode); diff --git a/src/FirmwarePlugin/PX4/PX4FirmwarePlugin.h b/src/FirmwarePlugin/PX4/PX4FirmwarePlugin.h index fa2a4e8796a7fb35687396ec533aa2e75bbe2e2a..2c8059b61361edacda90a4d1d17947de254c05d3 100644 --- a/src/FirmwarePlugin/PX4/PX4FirmwarePlugin.h +++ b/src/FirmwarePlugin/PX4/PX4FirmwarePlugin.h @@ -42,6 +42,7 @@ public: QString rtlFlightMode (void) const override { return _rtlFlightMode; } QString landFlightMode (void) const override { return _landingFlightMode; } QString takeControlFlightMode (void) const override { return _manualFlightMode; } + QString gotoFlightMode (void) const override { return _holdFlightMode; } void pauseVehicle (Vehicle* vehicle) override; void guidedModeRTL (Vehicle* vehicle) override; void guidedModeLand (Vehicle* vehicle) override; diff --git a/src/FlightDisplay/FlightDisplayView.qml b/src/FlightDisplay/FlightDisplayView.qml index 7cc04b763e788e02ab56289f02c501a60e77d220..6c60bb2ab9e5ed8334a36eb6b8259d29bb9bfea5 100644 --- a/src/FlightDisplay/FlightDisplayView.qml +++ b/src/FlightDisplay/FlightDisplayView.qml @@ -488,13 +488,13 @@ QGCView { exclusiveGroup: multiVehicleSelectorGroup text: qsTr("Single") checked: true - color: mapPal.text + textColor: mapPal.text } QGCRadioButton { exclusiveGroup: multiVehicleSelectorGroup text: qsTr("Multi-Vehicle") - color: mapPal.text + textColor: mapPal.text } } diff --git a/src/FlightDisplay/FlightDisplayViewMap.qml b/src/FlightDisplay/FlightDisplayViewMap.qml index 788c2f21273ee2e2606d179ebec1434e419fcc8f..ce8a6eaf72a965739f22a9131934921f7a22c5d7 100644 --- a/src/FlightDisplay/FlightDisplayViewMap.qml +++ b/src/FlightDisplay/FlightDisplayViewMap.qml @@ -295,6 +295,7 @@ FlightMap { } } + // GoTo Location visuals MapQuickItem { id: gotoLocationItem visible: false @@ -308,6 +309,22 @@ FlightMap { label: qsTr("Goto here", "Goto here waypoint") } + property bool inGotoFlightMode: _activeVehicle ? _activeVehicle.flightMode === _activeVehicle.gotoFlightMode : false + property var activeVehicle: _activeVehicle + + onInGotoFlightModeChanged: { + if (!inGotoFlightMode && visible) { + // Hide goto indicator when vehicle falls out of guided mode + visible = false + } + } + + onActiveVehicleChanged: { + if (!_activeVehicle) { + visible = false + } + } + function show(coord) { gotoLocationItem.coordinate = coord gotoLocationItem.visible = true @@ -316,10 +333,17 @@ FlightMap { function hide() { gotoLocationItem.visible = false } - } - // Orbit visuals + function actionConfirmed() { + // We leave the indicator visible. The handling for onInGuidedModeChanged will hide it. + } + + function actionCancelled() { + hide() + } + } + // Orbit editing visuals QGCMapCircleVisuals { id: orbitMapCircle mapControl: parent @@ -328,9 +352,16 @@ FlightMap { property alias center: _mapCircle.center property alias clockwiseRotation: _mapCircle.clockwiseRotation + property var activeVehicle: _activeVehicle readonly property real defaultRadius: 30 + onActiveVehicleChanged: { + if (!_activeVehicle) { + visible = false + } + } + function show(coord) { _mapCircle.radius.rawValue = defaultRadius orbitMapCircle.center = coord @@ -341,6 +372,15 @@ FlightMap { orbitMapCircle.visible = false } + function actionConfirmed() { + // Live orbit status is handled by telemetry so we hide here and telemetry will show again. + hide() + } + + function actionCancelled() { + hide() + } + function radius() { return _mapCircle.radius.rawValue } @@ -357,7 +397,6 @@ FlightMap { } // Orbit telemetry visuals - QGCMapCircleVisuals { id: orbitTelemetryCircle mapControl: parent @@ -395,7 +434,7 @@ FlightMap { onTriggered: { gotoLocationItem.show(clickMenu.coord) orbitMapCircle.hide() - guidedActionsController.confirmAction(guidedActionsController.actionGoto, clickMenu.coord) + guidedActionsController.confirmAction(guidedActionsController.actionGoto, clickMenu.coord, gotoLocationItem) } } @@ -406,7 +445,7 @@ FlightMap { onTriggered: { orbitMapCircle.show(clickMenu.coord) gotoLocationItem.hide() - guidedActionsController.confirmAction(guidedActionsController.actionOrbit, clickMenu.coord) + guidedActionsController.confirmAction(guidedActionsController.actionOrbit, clickMenu.coord, orbitMapCircle) } } } diff --git a/src/FlightDisplay/GuidedActionConfirm.qml b/src/FlightDisplay/GuidedActionConfirm.qml index 8d36d74dc1a6688ef0e13d1164add68302237ec9..177e1944ad82a013cb151b143173a44f30027e75 100644 --- a/src/FlightDisplay/GuidedActionConfirm.qml +++ b/src/FlightDisplay/GuidedActionConfirm.qml @@ -34,16 +34,14 @@ Rectangle { property int action property var actionData property bool hideTrigger: false + property var mapIndicator property real _margins: ScreenTools.defaultFontPixelWidth property bool _emergencyAction: action === guidedController.actionEmergencyStop onHideTriggerChanged: { if (hideTrigger) { - hideTrigger = false - altitudeSlider.visible = false - visibleTimer.stop() - visible = false + confirmCancelled() } } @@ -57,6 +55,17 @@ Rectangle { } } + function confirmCancelled() { + altitudeSlider.visible = false + visible = false + hideTrigger = false + visibleTimer.stop() + if (mapIndicator) { + mapIndicator.actionCancelled() + mapIndicator = undefined + } + } + Timer { id: visibleTimer interval: 1000 @@ -107,12 +116,10 @@ Rectangle { } hideTrigger = false guidedController.executeAction(_root.action, _root.actionData, altitudeChange) - } - - onReject: { - altitudeSlider.visible = false - _root.visible = false - hideTrigger = false + if (mapIndicator) { + mapIndicator.actionConfirmed() + mapIndicator = undefined + } } } } @@ -127,12 +134,10 @@ Rectangle { source: "/res/XDelete.svg" fillMode: Image.PreserveAspectFit color: qgcPal.text + QGCMouseArea { fillItem: parent - onClicked: { - altitudeSlider.visible = false - _root.visible = false - } + onClicked: confirmCancelled() } } } diff --git a/src/FlightDisplay/GuidedActionsController.qml b/src/FlightDisplay/GuidedActionsController.qml index 58b3b68cfc4940d94c595079ceefe2cd70445f00..c099ed669c21dbabb532d645bce9cd9e7bf2e303 100644 --- a/src/FlightDisplay/GuidedActionsController.qml +++ b/src/FlightDisplay/GuidedActionsController.qml @@ -209,12 +209,13 @@ Item { } // Called when an action is about to be executed in order to confirm - function confirmAction(actionCode, actionData) { + function confirmAction(actionCode, actionData, mapIndicator) { var showImmediate = true closeAll() confirmDialog.action = actionCode confirmDialog.actionData = actionData confirmDialog.hideTrigger = true + confirmDialog.mapIndicator = mapIndicator _actionData = actionData switch (actionCode) { case actionArm: @@ -385,7 +386,6 @@ Item { break case actionOrbit: _activeVehicle.guidedModeOrbit(orbitMapCircle.center, orbitMapCircle.radius() * (orbitMapCircle.clockwiseRotation ? 1 : -1), _activeVehicle.altitudeAMSL.rawValue + actionAltitudeChange) - orbitMapCircle.hide() break case actionLandAbort: _activeVehicle.abortLanding(50) // hardcoded value for climbOutAltitude that is currently ignored diff --git a/src/FlightDisplay/VideoManager.cc b/src/FlightDisplay/VideoManager.cc index 6a05f3c5e6d7c06888d258fb92a9e20b3001e524..49b7be4e64a3367fdc03db1a9d69ba400c86bf41 100644 --- a/src/FlightDisplay/VideoManager.cc +++ b/src/FlightDisplay/VideoManager.cc @@ -35,6 +35,7 @@ QGC_LOGGING_CATEGORY(VideoManagerLog, "VideoManagerLog") VideoManager::VideoManager(QGCApplication* app, QGCToolbox* toolbox) : QGCTool(app, toolbox) { + _streamInfo = {}; } //----------------------------------------------------------------------------- @@ -164,7 +165,8 @@ VideoManager::isGStreamer() videoSource == VideoSettings::videoSourceUDP || videoSource == VideoSettings::videoSourceRTSP || videoSource == VideoSettings::videoSourceAuto || - videoSource == VideoSettings::videoSourceTCP; + videoSource == VideoSettings::videoSourceTCP || + videoSource == VideoSettings::videoSourceMPEGTS; #else return false; #endif @@ -197,14 +199,33 @@ VideoManager::_updateSettings() { if(!_videoSettings || !_videoReceiver) return; - if (_videoSettings->videoSource()->rawValue().toString() == VideoSettings::videoSourceUDP) + QString source = _videoSettings->videoSource()->rawValue().toString(); + if (source == VideoSettings::videoSourceUDP) _videoReceiver->setUri(QStringLiteral("udp://0.0.0.0:%1").arg(_videoSettings->udpPort()->rawValue().toInt())); - else if (_videoSettings->videoSource()->rawValue().toString() == VideoSettings::videoSourceRTSP) + else if (source == VideoSettings::videoSourceMPEGTS) + _videoReceiver->setUri(QStringLiteral("mpegts://0.0.0.0:%1").arg(_videoSettings->udpPort()->rawValue().toInt())); + else if (source == VideoSettings::videoSourceRTSP) _videoReceiver->setUri(_videoSettings->rtspUrl()->rawValue().toString()); - else if (_videoSettings->videoSource()->rawValue().toString() == VideoSettings::videoSourceTCP) + else if (source == VideoSettings::videoSourceTCP) _videoReceiver->setUri(QStringLiteral("tcp://%1").arg(_videoSettings->tcpUrl()->rawValue().toString())); - else if (isAutoStream()) - _videoReceiver->setUri(QString(_streamInfo.uri)); + //-- Auto discovery + else if (isAutoStream()) { + switch(_streamInfo.type) { + case VIDEO_STREAM_TYPE_RTSP: + case VIDEO_STREAM_TYPE_TCP_MPEG: + _videoReceiver->setUri(QString(_streamInfo.uri)); + break; + case VIDEO_STREAM_TYPE_RTPUDP: + _videoReceiver->setUri(QStringLiteral("udp://0.0.0.0:%1").arg(atoi(_streamInfo.uri))); + break; + case VIDEO_STREAM_TYPE_MPEG_TS_H264: + _videoReceiver->setUri(QStringLiteral("mpegts://0.0.0.0:%1").arg(atoi(_streamInfo.uri))); + break; + default: + _videoReceiver->setUri(QString(_streamInfo.uri)); + break; + } + } } //----------------------------------------------------------------------------- @@ -212,6 +233,7 @@ void VideoManager::_restartVideo() { #if defined(QGC_GST_STREAMING) + qCDebug(VideoManagerLog) << "Restart video streaming"; if(!_videoReceiver) return; _videoReceiver->stop(); @@ -240,7 +262,7 @@ VideoManager::_setActiveVehicle(Vehicle* vehicle) MAV_CMD_REQUEST_VIDEO_STREAM_INFORMATION, // Command id false, // ShowError 1, // First camera only - 0); // Reserved (Set to 0) + 1); // Request video stream information } } diff --git a/src/FlightDisplay/VideoManager.h b/src/FlightDisplay/VideoManager.h index 7fa28c42e305f38ca7c42cbf389c17fcf24d4d64..a21d1391be8305f390cd0ea525dff919b0b0b314 100644 --- a/src/FlightDisplay/VideoManager.h +++ b/src/FlightDisplay/VideoManager.h @@ -61,7 +61,7 @@ public: #endif void setfullScreen (bool f) { _fullScreen = f; emit fullScreenChanged(); } - void setIsTaisync (bool t) { _isTaisync = t; emit isTaisyncChanged(); } + void setIsTaisync (bool t) { _isTaisync = t; emit isTaisyncChanged(); } // Override from QGCTool void setToolbox (QGCToolbox *toolbox); diff --git a/src/MissionManager/CameraCalc.FactMetaData.json b/src/MissionManager/CameraCalc.FactMetaData.json index 9860f5491bae0df69b62cdacc79424f00a83fcc6..2addaa89c990419b58f481d0eba245f4507e8792 100644 --- a/src/MissionManager/CameraCalc.FactMetaData.json +++ b/src/MissionManager/CameraCalc.FactMetaData.json @@ -18,7 +18,7 @@ "min": 0.1, "units": "m", "decimalPlaces": 2, - "defaultValue": 10.0 + "defaultValue": 50.0 }, { "name": "ImageDensity", @@ -27,7 +27,7 @@ "min": 0, "units": "cm/px", "decimalPlaces": 1, - "defaultValue": 25 + "defaultValue": 1.2 }, { "name": "FrontalOverlap", diff --git a/src/MissionManager/CameraCalc.cc b/src/MissionManager/CameraCalc.cc index 5f15bb25e1c19e379ac03eb10c70d7cc349a7d27..c775c1b76f9733b486b2469b95fa21dc6b2557a7 100644 --- a/src/MissionManager/CameraCalc.cc +++ b/src/MissionManager/CameraCalc.cc @@ -127,8 +127,8 @@ void CameraCalc::_cameraNameChanged(void) // These values are unknown for these types fixedOrientation()->setRawValue(false); minTriggerInterval()->setRawValue(0); - if (isManualCamera()) { - valueSetIsDistance()->setRawValue(false); + if (isManualCamera() && !valueSetIsDistance()->rawValue().toBool()) { + valueSetIsDistance()->setRawValue(true); } } else { qWarning() << "Internal Error: Not known camera, but now manual or custom either"; diff --git a/src/MissionManager/FixedWingLandingComplexItem.cc b/src/MissionManager/FixedWingLandingComplexItem.cc index 9e26762f0332e6b622ed682d05efdf99fa656ce4..813205af6c6bf11a3d9caf4a7a2d500d0d1794ec 100644 --- a/src/MissionManager/FixedWingLandingComplexItem.cc +++ b/src/MissionManager/FixedWingLandingComplexItem.cc @@ -373,7 +373,7 @@ bool FixedWingLandingComplexItem::scanForItem(QmlObjectListModel* visualItems, b MissionItem& missionItemLand = item->missionItem(); if (missionItemLand.command() != MAV_CMD_NAV_LAND || !(missionItemLand.frame() == MAV_FRAME_GLOBAL_RELATIVE_ALT || missionItemLand.frame() == MAV_FRAME_GLOBAL) || - missionItemLand.param1() != 0 || missionItemLand.param2() != 0 || missionItemLand.param3() != 0 || missionItemLand.param4() == 1.0) { + missionItemLand.param1() != 0 || missionItemLand.param2() != 0 || missionItemLand.param3() != 0 || missionItemLand.param4() != 0) { return false; } MAV_FRAME landPointFrame = missionItemLand.frame(); @@ -414,6 +414,7 @@ bool FixedWingLandingComplexItem::scanForItem(QmlObjectListModel* visualItems, b } MissionItem& missionItemDoLandStart = item->missionItem(); if (missionItemDoLandStart.command() != MAV_CMD_DO_LAND_START || + missionItemDoLandStart.frame() != MAV_FRAME_MISSION || missionItemDoLandStart.param1() != 0 || missionItemDoLandStart.param2() != 0 || missionItemDoLandStart.param3() != 0 || missionItemDoLandStart.param4() != 0|| missionItemDoLandStart.param5() != 0|| missionItemDoLandStart.param6() != 0) { return false; } diff --git a/src/MissionManager/MissionController.cc b/src/MissionManager/MissionController.cc index f03b8fa837c947d70dd6cab72f7c2a71e1e1419a..90bebf479071fd73593f1c01c367a7eece4486fa 100644 --- a/src/MissionManager/MissionController.cc +++ b/src/MissionManager/MissionController.cc @@ -29,6 +29,7 @@ #include "QGCQGeoCoordinate.h" #include "PlanMasterController.h" #include "KML.h" +#include "QGCCorePlugin.h" #ifndef __mobile__ #include "MainWindow.h" @@ -55,23 +56,24 @@ const char* MissionController::_jsonMavAutopilotKey = "MAV_AUTOPILOT"; const int MissionController::_missionFileVersion = 2; +const QString MissionController::patternFWLandingName (tr("Fixed Wing Landing")); +const QString MissionController::patternStructureScanName (tr("Structure Scan")); +const QString MissionController::patternCorridorScanName (tr("Corridor Scan")); + MissionController::MissionController(PlanMasterController* masterController, QObject *parent) - : PlanElementController (masterController, parent) - , _missionManager (_managerVehicle->missionManager()) - , _missionItemCount (0) - , _visualItems (nullptr) - , _settingsItem (nullptr) - , _firstItemsFromVehicle (false) - , _itemsRequested (false) - , _inRecalcSequence (false) - , _surveyMissionItemName (tr("Survey")) - , _fwLandingMissionItemName (tr("Fixed Wing Landing")) - , _structureScanMissionItemName (tr("Structure Scan")) - , _corridorScanMissionItemName (tr("Corridor Scan")) - , _appSettings (qgcApp()->toolbox()->settingsManager()->appSettings()) - , _progressPct (0) - , _currentPlanViewIndex (-1) - , _currentPlanViewItem (nullptr) + : PlanElementController (masterController, parent) + , _missionManager (_managerVehicle->missionManager()) + , _missionItemCount (0) + , _visualItems (nullptr) + , _settingsItem (nullptr) + , _firstItemsFromVehicle (false) + , _itemsRequested (false) + , _inRecalcSequence (false) + , _surveyMissionItemName (tr("Survey")) + , _appSettings (qgcApp()->toolbox()->settingsManager()->appSettings()) + , _progressPct (0) + , _currentPlanViewIndex (-1) + , _currentPlanViewItem (nullptr) { _resetMissionFlightStatus(); managerVehicleChanged(_managerVehicle); @@ -414,11 +416,11 @@ int MissionController::insertComplexMissionItem(QString itemName, QGeoCoordinate if (itemName == _surveyMissionItemName) { newItem = new SurveyComplexItem(_controllerVehicle, _flyView, QString() /* kmlFile */, _visualItems /* parent */); newItem->setCoordinate(mapCenterCoordinate); - } else if (itemName == _fwLandingMissionItemName) { + } else if (itemName == patternFWLandingName) { newItem = new FixedWingLandingComplexItem(_controllerVehicle, _flyView, _visualItems /* parent */); - } else if (itemName == _structureScanMissionItemName) { + } else if (itemName == patternStructureScanName) { newItem = new StructureScanComplexItem(_controllerVehicle, _flyView, QString() /* kmlFile */, _visualItems /* parent */); - } else if (itemName == _corridorScanMissionItemName) { + } else if (itemName == patternCorridorScanName) { newItem = new CorridorScanComplexItem(_controllerVehicle, _flyView, QString() /* kmlFile */, _visualItems /* parent */); } else { qWarning() << "Internal error: Unknown complex item:" << itemName; @@ -434,9 +436,9 @@ int MissionController::insertComplexMissionItemFromKMLOrSHP(QString itemName, QS if (itemName == _surveyMissionItemName) { newItem = new SurveyComplexItem(_controllerVehicle, _flyView, file, _visualItems); - } else if (itemName == _structureScanMissionItemName) { + } else if (itemName == patternStructureScanName) { newItem = new StructureScanComplexItem(_controllerVehicle, _flyView, file, _visualItems); - } else if (itemName == _corridorScanMissionItemName) { + } else if (itemName == patternCorridorScanName) { newItem = new CorridorScanComplexItem(_controllerVehicle, _flyView, file, _visualItems); } else { qWarning() << "Internal error: Unknown complex item:" << itemName; @@ -1951,15 +1953,15 @@ QStringList MissionController::complexMissionItemNames(void) const QStringList complexItems; complexItems.append(_surveyMissionItemName); - complexItems.append(_corridorScanMissionItemName); + complexItems.append(patternCorridorScanName); if (_controllerVehicle->fixedWing()) { - complexItems.append(_fwLandingMissionItemName); + complexItems.append(patternFWLandingName); } if (_controllerVehicle->multiRotor() || _controllerVehicle->vtol()) { - complexItems.append(_structureScanMissionItemName); + complexItems.append(patternStructureScanName); } - return complexItems; + return qgcApp()->toolbox()->corePlugin()->complexMissionItemNames(_controllerVehicle, complexItems); } void MissionController::resumeMission(int resumeIndex) diff --git a/src/MissionManager/MissionController.h b/src/MissionManager/MissionController.h index 02747b6c9341eafd67a1d15083e1161ce0d580f1..6fa6e19efba2e9ec37dbe9ade2db2c656d7a3709 100644 --- a/src/MissionManager/MissionController.h +++ b/src/MissionManager/MissionController.h @@ -175,8 +175,8 @@ public: VisualMissionItem* currentPlanViewItem (void) const; double progressPct (void) const { return _progressPct; } QString surveyComplexItemName (void) const { return _surveyMissionItemName; } - QString corridorScanComplexItemName (void) const { return _corridorScanMissionItemName; } - QString structureScanComplexItemName(void) const { return _structureScanMissionItemName; } + QString corridorScanComplexItemName (void) const { return patternCorridorScanName; } + QString structureScanComplexItemName(void) const { return patternStructureScanName; } int missionItemCount (void) const { return _missionItemCount; } int currentMissionIndex (void) const; @@ -194,6 +194,12 @@ public: int batteryChangePoint (void) const { return _missionFlightStatus.batteryChangePoint; } ///< -1 for not supported, 0 for not needed int batteriesRequired (void) const { return _missionFlightStatus.batteriesRequired; } ///< -1 for not supported + // These are the names shown in the UI for the pattern items. They are public so custom builds can remove the ones + // they don't want through the QGCCorePlugin:: + static const QString patternFWLandingName; + static const QString patternStructureScanName; + static const QString patternCorridorScanName; + signals: void visualItemsChanged (void); void waypointLinesChanged (void); @@ -285,9 +291,6 @@ private: bool _inRecalcSequence; MissionFlightStatus_t _missionFlightStatus; QString _surveyMissionItemName; - QString _fwLandingMissionItemName; - QString _structureScanMissionItemName; - QString _corridorScanMissionItemName; AppSettings* _appSettings; double _progressPct; int _currentPlanViewIndex; diff --git a/src/MissionManager/QGCMapCircle.Facts.json b/src/MissionManager/QGCMapCircle.Facts.json index f2ded5e5efea285b70279064ba7ed926e4d11456..2f496fa1d48a4054595d39c758f136c9beea4c09 100644 --- a/src/MissionManager/QGCMapCircle.Facts.json +++ b/src/MissionManager/QGCMapCircle.Facts.json @@ -3,7 +3,7 @@ "name": "Radius", "shortDescription": "Radius for geofence circle.", "type": "double", - "decimalPlaces": 2, + "decimalPlaces": 1, "min": 0.1, "units": "m" } diff --git a/src/PlanView/GeoFenceEditor.qml b/src/PlanView/GeoFenceEditor.qml index b5d12f23fa91c6da37496d6f63449f237c50361f..9788aea347a030ac59dbf6733fea0080641d8e02 100644 --- a/src/PlanView/GeoFenceEditor.qml +++ b/src/PlanView/GeoFenceEditor.qml @@ -10,13 +10,9 @@ import QGroundControl.FactControls 1.0 QGCFlickable { id: root - width: availableWidth - height: availableHeight - contentHeight: editorColumn.height + contentHeight: geoFenceEditorRect.height clip: true - property real availableWidth - property real availableHeight property var myGeoFenceController property var flightMap @@ -24,317 +20,290 @@ QGCFlickable { readonly property real _margin: ScreenTools.defaultFontPixelWidth / 2 readonly property real _radius: ScreenTools.defaultFontPixelWidth / 2 - Column { - id: editorColumn + Rectangle { + id: geoFenceEditorRect anchors.left: parent.left anchors.right: parent.right + height: geoFenceItems.y + geoFenceItems.height + (_margin * 2) + radius: _radius + color: qgcPal.missionItemEditor + + QGCLabel { + id: geoFenceLabel + anchors.margins: _margin + anchors.left: parent.left + anchors.top: parent.top + text: qsTr("GeoFence") + anchors.leftMargin: ScreenTools.defaultFontPixelWidth + } Rectangle { - id: geoFenceEditorRect - width: parent.width - height: geoFenceItems.y + geoFenceItems.height + (_margin * 2) - radius: _radius - color: qgcPal.missionItemEditor - - QGCLabel { - id: geoFenceLabel + id: geoFenceItems + anchors.margins: _margin + anchors.left: parent.left + anchors.right: parent.right + anchors.top: geoFenceLabel.bottom + height: fenceColumn.y + fenceColumn.height + (_margin * 2) + color: qgcPal.windowShadeDark + radius: _radius + + Column { + id: fenceColumn anchors.margins: _margin - anchors.left: parent.left anchors.top: parent.top - text: qsTr("GeoFence") - anchors.leftMargin: ScreenTools.defaultFontPixelWidth - } - - Rectangle { - id: geoFenceItems - anchors.margins: _margin anchors.left: parent.left anchors.right: parent.right - anchors.top: geoFenceLabel.bottom - height: fenceColumn.y + fenceColumn.height + (_margin * 2) - color: qgcPal.windowShadeDark - radius: _radius + spacing: ScreenTools.defaultFontPixelHeight / 2 - Column { - id: fenceColumn - anchors.margins: _margin - anchors.top: parent.top + QGCLabel { anchors.left: parent.left anchors.right: parent.right - spacing: ScreenTools.defaultFontPixelHeight / 2 - - QGCLabel { - anchors.left: parent.left - anchors.right: parent.right - wrapMode: Text.WordWrap - font.pointSize: myGeoFenceController.supported ? ScreenTools.smallFontPointSize : ScreenTools.defaultFontPointSize - text: myGeoFenceController.supported ? - qsTr("GeoFencing allows you to set a virtual ‘fence’ around the area you want to fly in.") : - qsTr("This vehicle does not support GeoFence.") - } + wrapMode: Text.WordWrap + font.pointSize: myGeoFenceController.supported ? ScreenTools.smallFontPointSize : ScreenTools.defaultFontPointSize + text: myGeoFenceController.supported ? + qsTr("GeoFencing allows you to set a virtual ‘fence’ around the area you want to fly in.") : + qsTr("This vehicle does not support GeoFence.") + } - Column { - anchors.left: parent.left - anchors.right: parent.right - spacing: ScreenTools.defaultFontPixelHeight / 2 - visible: myGeoFenceController.supported + Column { + anchors.left: parent.left + anchors.right: parent.right + spacing: ScreenTools.defaultFontPixelHeight / 2 + visible: myGeoFenceController.supported - Repeater { - model: myGeoFenceController.params + Repeater { + model: myGeoFenceController.params - Item { - width: fenceColumn.width - height: textField.height + Item { + width: fenceColumn.width + height: textField.height - property bool showCombo: modelData.enumStrings.length > 0 + property bool showCombo: modelData.enumStrings.length > 0 - QGCLabel { - id: textFieldLabel - anchors.baseline: textField.baseline - text: myGeoFenceController.paramLabels[index] - } + QGCLabel { + id: textFieldLabel + anchors.baseline: textField.baseline + text: myGeoFenceController.paramLabels[index] + } - FactTextField { - id: textField - anchors.right: parent.right - width: _editFieldWidth - showUnits: true - fact: modelData - visible: !parent.showCombo - } + FactTextField { + id: textField + anchors.right: parent.right + width: _editFieldWidth + showUnits: true + fact: modelData + visible: !parent.showCombo + } - FactComboBox { - id: comboField - anchors.right: parent.right - width: _editFieldWidth - indexModel: false - fact: showCombo ? modelData : _nullFact - visible: parent.showCombo + FactComboBox { + id: comboField + anchors.right: parent.right + width: _editFieldWidth + indexModel: false + fact: showCombo ? modelData : _nullFact + visible: parent.showCombo - property var _nullFact: Fact { } - } + property var _nullFact: Fact { } } } + } - SectionHeader { - id: insertSection - text: qsTr("Insert GeoFence") - } + SectionHeader { + id: insertSection + text: qsTr("Insert GeoFence") + } - QGCButton { - anchors.left: parent.left - anchors.right: parent.right - text: qsTr("Polygon Fence") + QGCButton { + anchors.left: parent.left + anchors.right: parent.right + text: qsTr("Polygon Fence") - onClicked: { - var rect = Qt.rect(flightMap.centerViewport.x, flightMap.centerViewport.y, flightMap.centerViewport.width, flightMap.centerViewport.height) - var topLeftCoord = flightMap.toCoordinate(Qt.point(rect.x, rect.y), false /* clipToViewPort */) - var bottomRightCoord = flightMap.toCoordinate(Qt.point(rect.x + rect.width, rect.y + rect.height), false /* clipToViewPort */) - myGeoFenceController.addInclusionPolygon(topLeftCoord, bottomRightCoord) - } + onClicked: { + var rect = Qt.rect(flightMap.centerViewport.x, flightMap.centerViewport.y, flightMap.centerViewport.width, flightMap.centerViewport.height) + var topLeftCoord = flightMap.toCoordinate(Qt.point(rect.x, rect.y), false /* clipToViewPort */) + var bottomRightCoord = flightMap.toCoordinate(Qt.point(rect.x + rect.width, rect.y + rect.height), false /* clipToViewPort */) + myGeoFenceController.addInclusionPolygon(topLeftCoord, bottomRightCoord) } + } - QGCButton { - anchors.left: parent.left - anchors.right: parent.right - text: qsTr("Circular Fence") + QGCButton { + anchors.left: parent.left + anchors.right: parent.right + text: qsTr("Circular Fence") - onClicked: { - var rect = Qt.rect(flightMap.centerViewport.x, flightMap.centerViewport.y, flightMap.centerViewport.width, flightMap.centerViewport.height) - var topLeftCoord = flightMap.toCoordinate(Qt.point(rect.x, rect.y), false /* clipToViewPort */) - var bottomRightCoord = flightMap.toCoordinate(Qt.point(rect.x + rect.width, rect.y + rect.height), false /* clipToViewPort */) - myGeoFenceController.addInclusionCircle(topLeftCoord, bottomRightCoord) - } + onClicked: { + var rect = Qt.rect(flightMap.centerViewport.x, flightMap.centerViewport.y, flightMap.centerViewport.width, flightMap.centerViewport.height) + var topLeftCoord = flightMap.toCoordinate(Qt.point(rect.x, rect.y), false /* clipToViewPort */) + var bottomRightCoord = flightMap.toCoordinate(Qt.point(rect.x + rect.width, rect.y + rect.height), false /* clipToViewPort */) + myGeoFenceController.addInclusionCircle(topLeftCoord, bottomRightCoord) } + } - SectionHeader { - id: polygonSection - text: qsTr("Polygon Fences") - } + SectionHeader { + id: polygonSection + text: qsTr("Polygon Fences") + } + + QGCLabel { + text: qsTr("None") + visible: polygonSection.checked && myGeoFenceController.polygons.count === 0 + } + + GridLayout { + anchors.left: parent.left + anchors.right: parent.right + columns: 3 + flow: GridLayout.TopToBottom + visible: polygonSection.checked && myGeoFenceController.polygons.count > 0 QGCLabel { - text: qsTr("None") - visible: polygonSection.checked && myGeoFenceController.polygons.count === 0 + text: qsTr("Inclusion") + Layout.column: 0 + Layout.alignment: Qt.AlignHCenter } - GridLayout { - anchors.left: parent.left - anchors.right: parent.right - columns: 3 - flow: GridLayout.TopToBottom - visible: polygonSection.checked && myGeoFenceController.polygons.count > 0 + Repeater { + model: myGeoFenceController.polygons - QGCLabel { - text: qsTr("Inclusion") - Layout.column: 0 + QGCCheckBox { + checked: object.inclusion + onClicked: object.inclusion = checked Layout.alignment: Qt.AlignHCenter } + } - Repeater { - model: myGeoFenceController.polygons + QGCLabel { + text: qsTr("Edit") + Layout.column: 1 + Layout.alignment: Qt.AlignHCenter + } - QGCCheckBox { - checked: object.inclusion - onClicked: object.inclusion = checked - Layout.alignment: Qt.AlignHCenter - } - } + Repeater { + model: myGeoFenceController.polygons - QGCLabel { - text: qsTr("Edit") - Layout.column: 1 + QGCRadioButton { + checked: _interactive Layout.alignment: Qt.AlignHCenter - } - - Repeater { - model: myGeoFenceController.polygons - - QGCRadioButton { - checked: _interactive - Layout.alignment: Qt.AlignHCenter - property bool _interactive: object.interactive + property bool _interactive: object.interactive - on_InteractiveChanged: checked = _interactive + on_InteractiveChanged: checked = _interactive - onClicked: { - myGeoFenceController.clearAllInteractive() - object.interactive = checked - } + onClicked: { + myGeoFenceController.clearAllInteractive() + object.interactive = checked } } + } - QGCLabel { - text: qsTr("Delete") - Layout.column: 2 - Layout.alignment: Qt.AlignHCenter - } + QGCLabel { + text: qsTr("Delete") + Layout.column: 2 + Layout.alignment: Qt.AlignHCenter + } - Repeater { - model: myGeoFenceController.polygons + Repeater { + model: myGeoFenceController.polygons - QGCColoredImage { - width: ScreenTools.defaultFontPixelHeight - height: width - sourceSize.height: width - source: "/res/XDelete.svg" - fillMode: Image.PreserveAspectFit - color: qgcPal.text - Layout.alignment: Qt.AlignHCenter + QGCButton { + text: qsTr("Del") + Layout.alignment: Qt.AlignHCenter + onClicked: myGeoFenceController.deletePolygon(index) + } + } + } // GridLayout - property int _polygonIndex: index + SectionHeader { + id: circleSection + text: qsTr("Circular Fences") + } - QGCMouseArea { - fillItem: parent - onClicked: myGeoFenceController.deletePolygon(parent._polygonIndex) - } - } - } - } // GridLayout + QGCLabel { + text: qsTr("None") + visible: circleSection.checked && myGeoFenceController.circles.count === 0 + } - SectionHeader { - id: circleSection - text: qsTr("Circular Fences") - } + GridLayout { + anchors.left: parent.left + anchors.right: parent.right + columns: 4 + flow: GridLayout.TopToBottom + visible: polygonSection.checked && myGeoFenceController.circles.count > 0 QGCLabel { - text: qsTr("None") - visible: circleSection.checked && myGeoFenceController.circles.count === 0 + text: qsTr("Inclusion") + Layout.column: 0 + Layout.alignment: Qt.AlignHCenter } - GridLayout { - anchors.left: parent.left - anchors.right: parent.right - columns: 4 - flow: GridLayout.TopToBottom - visible: polygonSection.checked && myGeoFenceController.circles.count > 0 + Repeater { + model: myGeoFenceController.circles - QGCLabel { - text: qsTr("Inclusion") - Layout.column: 0 + QGCCheckBox { + checked: object.inclusion + onClicked: object.inclusion = checked Layout.alignment: Qt.AlignHCenter } + } - Repeater { - model: myGeoFenceController.circles + QGCLabel { + text: qsTr("Edit") + Layout.column: 1 + Layout.alignment: Qt.AlignHCenter + } - QGCCheckBox { - checked: object.inclusion - onClicked: object.inclusion = checked - Layout.alignment: Qt.AlignHCenter - } - } + Repeater { + model: myGeoFenceController.circles - QGCLabel { - text: qsTr("Edit") - Layout.column: 1 + QGCRadioButton { + checked: _interactive Layout.alignment: Qt.AlignHCenter - } - - Repeater { - model: myGeoFenceController.circles - QGCRadioButton { - checked: _interactive - Layout.alignment: Qt.AlignHCenter + property bool _interactive: object.interactive - property bool _interactive: object.interactive + on_InteractiveChanged: checked = _interactive - on_InteractiveChanged: checked = _interactive - - onClicked: { - myGeoFenceController.clearAllInteractive() - object.interactive = checked - } + onClicked: { + myGeoFenceController.clearAllInteractive() + object.interactive = checked } } + } - QGCLabel { - text: qsTr("Radius") - Layout.column: 2 - Layout.alignment: Qt.AlignHCenter - } - - Repeater { - model: myGeoFenceController.circles + QGCLabel { + text: qsTr("Radius") + Layout.column: 2 + Layout.alignment: Qt.AlignHCenter + } - FactTextField { - fact: object.radius - Layout.fillWidth: true - Layout.alignment: Qt.AlignHCenter - } - } + Repeater { + model: myGeoFenceController.circles - QGCLabel { - text: qsTr("Delete") - Layout.column: 3 + FactTextField { + fact: object.radius + Layout.fillWidth: true Layout.alignment: Qt.AlignHCenter } + } - Repeater { - model: myGeoFenceController.circles - - QGCColoredImage { - width: ScreenTools.defaultFontPixelHeight - height: width - sourceSize.height: width - source: "/res/XDelete.svg" - fillMode: Image.PreserveAspectFit - color: qgcPal.text - Layout.alignment: Qt.AlignHCenter + QGCLabel { + text: qsTr("Delete") + Layout.column: 3 + Layout.alignment: Qt.AlignHCenter + } - property int _circleIndex: index + Repeater { + model: myGeoFenceController.circles - QGCMouseArea { - fillItem: parent - onClicked: myGeoFenceController.deleteCircle(parent._polygonIndex) - } - } + QGCButton { + text: qsTr("Del") + Layout.alignment: Qt.AlignHCenter + onClicked: myGeoFenceController.deleteCircle(index) } - } // GridLayout - } + } + } // GridLayout } } - } // Rectangle - } + } + } // Rectangle } diff --git a/src/PlanView/MissionItemEditor.qml b/src/PlanView/MissionItemEditor.qml index 511e6898f6353e67ab2f2bf655912cba40839eea..694eecb93db4c8f62d9d8f3db7d6efb0f07e46fa 100644 --- a/src/PlanView/MissionItemEditor.qml +++ b/src/PlanView/MissionItemEditor.qml @@ -15,7 +15,7 @@ import QGroundControl.Palette 1.0 /// Mission item edit control Rectangle { id: _root - height: editorLoader.y + (editorLoader.visible ? editorLoader.height : 0) + (_margin * 2) + height: editorLoader.visible ? (editorLoader.y + editorLoader.height + (_margin * 2)) : (commandPicker.y + commandPicker.height + _margin / 2) color: _currentItem ? qgcPal.missionItemEditor : qgcPal.windowShade radius: _radius @@ -90,8 +90,7 @@ Rectangle { sourceSize.height: _hamburgerSize source: "qrc:/qmlimages/Hamburger.svg" visible: missionItem.isCurrentItem && missionItem.sequenceNumber !== 0 - color: qgcPal.windowShade - + color: qgcPal.text } QGCMouseArea { diff --git a/src/PlanView/PlanView.qml b/src/PlanView/PlanView.qml index d03f08d4fb1825175370c4664414084355281469..15f81051084a0e17a4f27c23f544907f47fe33a4 100644 --- a/src/PlanView/PlanView.qml +++ b/src/PlanView/PlanView.qml @@ -760,14 +760,6 @@ QGCView { anchors.left: parent.left anchors.leftMargin: ScreenTools.defaultFontPixelWidth readonly property real _buttonRadius: ScreenTools.defaultFontPixelHeight * 0.75 - QGCColoredImage { - width: height - height: ScreenTools.defaultFontPixelWidth * 2.5 - sourceSize.height: height - source: "qrc:/res/waypoint.svg" - color: qgcPal.text - anchors.verticalCenter: parent.verticalCenter - } QGCLabel { text: qsTr("Plan") color: qgcPal.text @@ -831,7 +823,7 @@ QGCView { QGCListView { id: missionItemEditorListView anchors.fill: parent - spacing: ScreenTools.defaultFontPixelHeight * 0.5 + spacing: ScreenTools.defaultFontPixelHeight / 4 orientation: ListView.Vertical model: _missionController.visualItems cacheBuffer: Math.max(height * 2, 0) @@ -865,9 +857,9 @@ QGCView { GeoFenceEditor { anchors.top: rightControls.bottom anchors.topMargin: ScreenTools.defaultFontPixelHeight * 0.5 + anchors.bottom: parent.bottom anchors.left: parent.left anchors.right: parent.right - availableHeight: ScreenTools.availableHeight myGeoFenceController: _geoFenceController flightMap: editorMap visible: _editingLayer == _layerGeoFence diff --git a/src/PlanView/RallyPointItemEditor.qml b/src/PlanView/RallyPointItemEditor.qml index a85c84b7395e8898ab4dff84c681e420f8bb921c..9ec63847a3e4b813db249765b7d25f4d98126362 100644 --- a/src/PlanView/RallyPointItemEditor.qml +++ b/src/PlanView/RallyPointItemEditor.qml @@ -50,7 +50,7 @@ Rectangle { color: _outerTextColor } - Image { + QGCColoredImage { id: hamburger anchors.rightMargin: _margin anchors.right: parent.right @@ -59,6 +59,7 @@ Rectangle { height: width sourceSize.height: height source: "qrc:/qmlimages/Hamburger.svg" + color: qgcPal.text MouseArea { anchors.fill: parent diff --git a/src/PlanView/SimpleItemEditor.qml b/src/PlanView/SimpleItemEditor.qml index be5f0659955ade1daa21308a9c5f29980da6a784..e638b45aa3a9102cc24f19951b864eaa7b8e20de 100644 --- a/src/PlanView/SimpleItemEditor.qml +++ b/src/PlanView/SimpleItemEditor.qml @@ -18,23 +18,46 @@ Rectangle { color: qgcPal.windowShadeDark radius: _radius - property bool _specifiesAltitude: missionItem.specifiesAltitude - property real _margin: ScreenTools.defaultFontPixelHeight / 2 - property bool _supportsTerrainFrame: missionItem - readonly property int _altModeRelative: 0 readonly property int _altModeAbsolute: 1 readonly property int _altModeAboveTerrain: 2 readonly property int _altModeTerrainFrame: 3 - ExclusiveGroup { - id: altRadios - onCurrentChanged: { - altModeLabel.text = Qt.binding(function() { return current.helpText }) - missionItem.altitudeMode = current.altModeValue + property bool _specifiesAltitude: missionItem.specifiesAltitude + property real _margin: ScreenTools.defaultFontPixelHeight / 2 + property bool _supportsTerrainFrame: missionItem + + property string _altModeRelativeHelpText: qsTr("Altitude relative to home altitude") + property string _altModeAbsoluteHelpText: qsTr("Altitude above mean sea level") + property string _altModeAboveTerrainHelpText: qsTr("Altitude above terrain\nActual AMSL altitude: %1 %2").arg(missionItem.amslAltAboveTerrain.valueString).arg(missionItem.amslAltAboveTerrain.units) + property string _altModeTerrainFrameHelpText: qsTr("Using terrain reference frame") + + function updateAltitudeModeText() { + if (missionItem.altitudeMode === _altModeRelative) { + altModeLabel.text = qsTr("Altitude") + altModeHelp.text = _altModeRelativeHelpText + } else if (missionItem.altitudeMode === _altModeAbsolute) { + altModeLabel.text = qsTr("Above Mean Sea Level") + altModeHelp.text = _altModeAbsoluteHelpText + } else if (missionItem.altitudeMode === _altModeAboveTerrain) { + altModeLabel.text = qsTr("Above Terrain") + altModeHelp.text = Qt.binding(function() { return _altModeAboveTerrainHelpText }) + } else if (missionItem.altitudeMode === _altModeTerrainFrame) { + altModeLabel.text = qsTr("Terrain Frame") + altModeHelp.text = _altModeTerrainFrameHelpText + } else { + altModeLabel.text = qsTr("Internal Error") + altModeHelp.text = "" } } + Component.onCompleted: updateAltitudeModeText() + + Connections { + target: missionItem + onAltitudeModeChanged: updateAltitudeModeText() + } + Column { id: valuesColumn anchors.margins: _margin @@ -97,56 +120,70 @@ Rectangle { anchors.right: parent.right spacing: _margin - QGCLabel { - font.pointSize: ScreenTools.smallFontPointSize - text: qsTr("Altitude") - } - - RowLayout { - QGCRadioButton { - text: qsTr("Rel") - exclusiveGroup: altRadios - checked: missionItem.altitudeMode === altModeValue - - readonly property int altModeValue: _altModeRelative - readonly property string helpText: qsTr("Relative to home altitude") - } - QGCRadioButton { - text: qsTr("AMSL") - exclusiveGroup: altRadios - checked: missionItem.altitudeMode === altModeValue - visible: QGroundControl.corePlugin.options.showMissionAbsoluteAltitude || missionItem.altitudeMode === altModeValue - - readonly property int altModeValue: _altModeAbsolute - readonly property string helpText: qsTr("Above Mean Sea Level") + Item { + width: altHamburger.x + altHamburger.width + height: altModeLabel.height + + QGCLabel { id: altModeLabel } + + QGCColoredImage { + id: altHamburger + anchors.leftMargin: ScreenTools.defaultFontPixelWidth / 4 + anchors.left: altModeLabel.right + anchors.top: altModeLabel.top + width: height + height: altModeLabel.height + sourceSize.height: height + source: "qrc:/qmlimages/Hamburger.svg" + color: qgcPal.text } - QGCRadioButton { - text: qsTr("AGL") - exclusiveGroup: altRadios - checked: missionItem.altitudeMode === altModeValue - readonly property int altModeValue: _altModeAboveTerrain - property string helpText: qsTr("Calculated from terrain data\nAMSL Alt ") + missionItem.amslAltAboveTerrain.valueString + " " + missionItem.amslAltAboveTerrain.units + QGCMouseArea { + anchors.fill: parent + onClicked: altHamburgerMenu.popup() } - QGCRadioButton { - text: qsTr("TerrF") - exclusiveGroup: altRadios - checked: missionItem.altitudeMode === altModeValue - visible: missionItem.altitudeMode === altModeValue - - readonly property int altModeValue: _altModeTerrainFrame - readonly property string helpText: qsTr("Using terrain reference frame") + + Menu { + id: altHamburgerMenu + + MenuItem { + text: qsTr("Altitude Relative To Home") + checkable: true + checked: missionItem.altitudeMode === _altModeRelative + onTriggered: missionItem.altitudeMode = _altModeRelative + } + + MenuItem { + text: qsTr("Altitude Above Mean Sea Level") + checkable: true + checked: missionItem.altitudeMode === _altModeAbsolute + visible: QGroundControl.corePlugin.options.showMissionAbsoluteAltitude + onTriggered: missionItem.altitudeMode = _altModeAbsolute + } + + MenuItem { + text: qsTr("Altitude Above Terrain") + checkable: true + checked: missionItem.altitudeMode === _altModeAboveTerrain + onTriggered: missionItem.altitudeMode = _altModeAboveTerrain + } + + MenuItem { + text: qsTr("Terrain Frame") + checkable: true + checked: missionItem.altitudeMode === _altModeTerrainFrame + visible: missionItem.altitudeMode === _altModeTerrainFrame + onTriggered: missionItem.altitudeMode = _altModeTerrainFrame + } } } - FactValueSlider { - fact: missionItem.altitude - digitCount: 3 - incrementSlots: 1 + FactTextField { + fact: missionItem.altitude } QGCLabel { - id: altModeLabel + id: altModeHelp anchors.left: parent.left anchors.right: parent.right wrapMode: Text.WordWrap diff --git a/src/PositionManager/PositionManager.cpp b/src/PositionManager/PositionManager.cpp index 146749ca34ae0cbc0cc39227dcaaa3d304cee0fc..09f485142162f1ca634be70045d1fec08b4edda7 100644 --- a/src/PositionManager/PositionManager.cpp +++ b/src/PositionManager/PositionManager.cpp @@ -36,7 +36,6 @@ void QGCPositionManager::setToolbox(QGCToolbox *toolbox) if(!_defaultSource) { //-- Otherwise, create a default one _defaultSource = QGeoPositionInfoSource::createDefaultSource(this); - qDebug() << _defaultSource; } _simulatedSource = new SimulatedPosition(); diff --git a/src/QmlControls/QGCCheckBox.qml b/src/QmlControls/QGCCheckBox.qml index 5dbfb55053e844a1024289677258c1220353def7..9292f7cac49612d985d5a9f73bddd115efa6682f 100644 --- a/src/QmlControls/QGCCheckBox.qml +++ b/src/QmlControls/QGCCheckBox.qml @@ -6,96 +6,50 @@ import QGroundControl.Palette 1.0 import QGroundControl.ScreenTools 1.0 CheckBox { - activeFocusOnPress: true + property color textColor: _qgcPal.text + property bool textBold: false + property real textFontPointSize: ScreenTools.defaultFontPointSize + + property var _qgcPal: QGCPalette { colorGroupEnabled: enabled } + property bool _noText: text === "" + property real _radius: ScreenTools.defaultFontPixelHeight * 0.16 - property var __qgcPal: QGCPalette { colorGroupEnabled: enabled } + activeFocusOnPress: true style: CheckBoxStyle { label: Item { - implicitWidth: text.implicitWidth + 2 - implicitHeight: ScreenTools.implicitCheckBoxHeight + implicitWidth: _noText ? 0 : text.implicitWidth + ScreenTools.defaultFontPixelWidth * 0.25 + implicitHeight: _noText ? 0 : Math.max(text.implicitHeight, ScreenTools.checkBoxIndicatorSize) baselineOffset: text.baselineOffset - Rectangle { - anchors.margins: -1 - anchors.leftMargin: -3 - anchors.rightMargin: -3 - anchors.fill: text - visible: control.activeFocus - height: 6 - radius: 3 - color: "#224f9fef" - border.color: "#47b" - opacity: 0.6 - } - Text { - id: text - text: control.text - antialiasing: true - font.pointSize: ScreenTools.defaultFontPointSize - font.family: ScreenTools.normalFontFamily - color: control.__qgcPal.text - anchors.verticalCenter: parent.verticalCenter + id: text + text: control.text + font.pointSize: textFontPointSize + font.bold: control.textBold + color: control.textColor + anchors.centerIn: parent } - } // label + } indicator: Item { implicitWidth: ScreenTools.checkBoxIndicatorSize implicitHeight: implicitWidth Rectangle { - anchors.fill: parent - anchors.bottomMargin: -1 - color: "#44ffffff" - radius: baserect.radius - } - - Rectangle { - id: baserect - property var enabledGradient: Gradient { - GradientStop {color: "#eee" ; position: 0} - GradientStop {color: control.pressed ? "#eee" : "#fff" ; position: 0.1} - GradientStop {color: "#fff" ; position: 1} - } - property var disabledGradient: Gradient { - GradientStop {color: "#999" ; position: 0} - GradientStop {color: __qgcPal.textField ; position: 0.1} - GradientStop {color: __qgcPal.textField ; position: 0.9} - GradientStop {color: "#999" ; position: 1} - } - gradient: control.enabled ? enabledGradient : disabledGradient - - - radius: ScreenTools.defaultFontPixelHeight * 0.16 - anchors.fill: parent - border.color: control.activeFocus ? "#47b" : "#999" - opacity: control.enabled ? 1 : 0.5 - } - - Image { - source: "/qmlimages/check.png" - opacity: control.checkedState === Qt.Checked ? control.enabled ? 1 : 0.5 : 0 - anchors.centerIn: parent - anchors.verticalCenterOffset: 1 - Behavior on opacity {NumberAnimation {duration: 80}} - } - - Rectangle { - anchors.fill: parent - anchors.margins: Math.round(baserect.radius) - antialiasing: true - gradient: Gradient { - GradientStop {color: control.pressed ? "#555" : "#999" ; position: 0} - GradientStop {color: "#555" ; position: 1} + anchors.fill: parent + radius: _radius + border.color: "black" + opacity: control.checkedState === Qt.PartiallyChecked ? 0.5 : 1 + + Rectangle { + anchors.margins: parent.height / 4 + anchors.fill: parent + radius: _radius + color: "black" + visible: control.checkedState === Qt.Checked } - radius: baserect.radius - 1 - anchors.centerIn: parent - anchors.alignWhenCentered: true - border.color: "#222" - Behavior on opacity {NumberAnimation {duration: 80}} - opacity: control.checkedState === Qt.PartiallyChecked ? control.enabled ? 1 : 0.5 : 0 } - } // indicator - } // style + } + } } diff --git a/src/QmlControls/QGCMouseArea.qml b/src/QmlControls/QGCMouseArea.qml index b58eb3498b2b518bf336cd559ebfb3e21017f383..e1a9f2c532ceddcec1b990212844d90bb58e28c1 100644 --- a/src/QmlControls/QGCMouseArea.qml +++ b/src/QmlControls/QGCMouseArea.qml @@ -1,4 +1,4 @@ -import QtQuick 2.3 +import QtQuick 2.11 import QGroundControl 1.0 import QGroundControl.ScreenTools 1.0 diff --git a/src/QmlControls/QGCRadioButton.qml b/src/QmlControls/QGCRadioButton.qml index e28d327e349a19888d2d12f3690048e77e90ce34..79792d386e99e27002a31f4806ddc9b391d36b3f 100644 --- a/src/QmlControls/QGCRadioButton.qml +++ b/src/QmlControls/QGCRadioButton.qml @@ -6,41 +6,30 @@ import QGroundControl.Palette 1.0 import QGroundControl.ScreenTools 1.0 RadioButton { - property var color: qgcPal.text ///< Text color - property int textStyle: Text.Normal - property color textStyleColor: qgcPal.text - property bool textBold: false - property var qgcPal: QGCPalette { colorGroupEnabled: enabled } + property color textColor: _qgcPal.text + property bool textBold: false + property real textFontPointSize: ScreenTools.defaultFontPointSize + + property var _qgcPal: QGCPalette { colorGroupEnabled: enabled } + + property bool _noText: text === "" + + activeFocusOnPress: true style: RadioButtonStyle { + spacing: _noText ? 0 : ScreenTools.defaultFontPixelWidth / 2 + label: Item { - implicitWidth: text.implicitWidth + ScreenTools.defaultFontPixelWidth * 0.25 - implicitHeight: ScreenTools.implicitRadioButtonHeight + implicitWidth: _noText ? 0 : text.implicitWidth + ScreenTools.defaultFontPixelWidth * 0.25 + implicitHeight: _noText ? 0 : Math.max(text.implicitHeight, ScreenTools.radioButtonIndicatorSize) baselineOffset: text.y + text.baselineOffset - Rectangle { - anchors.fill: text - anchors.margins: -1 - anchors.leftMargin: -3 - anchors.rightMargin:-3 - visible: control.activeFocus - height: ScreenTools.defaultFontPixelWidth * 0.25 - radius: height * 0.5 - color: "#224f9fef" - border.color: "#47b" - opacity: 0.6 - } - Text { id: text text: control.text - font.pointSize: ScreenTools.defaultFontPointSize - font.family: ScreenTools.normalFontFamily + font.pointSize: textFontPointSize font.bold: control.textBold - antialiasing: true - color: control.color - style: control.textStyle - styleColor: control.textStyleColor + color: control.textColor anchors.centerIn: parent } } @@ -49,9 +38,9 @@ RadioButton { width: ScreenTools.radioButtonIndicatorSize height: width color: "white" - border.color: control.qgcPal.text - antialiasing: true + border.color: "black" radius: height / 2 + opacity: control.enabled ? 1 : 0.5 Rectangle { anchors.centerIn: parent @@ -60,7 +49,7 @@ RadioButton { antialiasing: true radius: height / 2 color: "black" - opacity: control.checked ? (control.enabled ? 1 : 0.5) : 0 + visible: control.checked } } } diff --git a/src/QmlControls/SliderSwitch.qml b/src/QmlControls/SliderSwitch.qml index 2fcf738dc6c88df66e0d67bba9f29b1e01ee10f3..112223a47d6d63c9a72307d855ca7d4d0bb54d7e 100644 --- a/src/QmlControls/SliderSwitch.qml +++ b/src/QmlControls/SliderSwitch.qml @@ -14,7 +14,6 @@ Rectangle { color: qgcPal.windowShade signal accept ///< Action confirmed - signal reject ///< Action rejected property string confirmText ///< Text for slider property alias fontPointSize: label.font.pointSize ///< Point size for text @@ -70,12 +69,6 @@ Rectangle { property bool dragActive: drag.active property real _dragOffset: 1 - //Component.onCompleted: console.log(height, ScreenTools.minTouchPixels) - - onPressed: { - mouse.x - } - onDragActiveChanged: { if (!sliderDragArea.drag.active) { if (slider.x > _maxXDrag - _border) { diff --git a/src/QmlControls/ToolStrip.qml b/src/QmlControls/ToolStrip.qml index 10d6eba22ac32d44b79c2861f8f5160ceacc7153..4ab074dec41af5aa55b7fbb1223924932477b427 100644 --- a/src/QmlControls/ToolStrip.qml +++ b/src/QmlControls/ToolStrip.qml @@ -7,8 +7,8 @@ * ****************************************************************************/ -import QtQuick 2.3 -import QtQuick.Controls 1.2 +import QtQuick 2.11 +import QtQuick.Controls 1.4 import QGroundControl.ScreenTools 1.0 import QGroundControl.Palette 1.0 @@ -17,7 +17,7 @@ Rectangle { id: _root color: qgcPal.window width: ScreenTools.isMobile ? ScreenTools.minTouchPixels : ScreenTools.defaultFontPixelWidth * 7 - height: buttonStripColumn.height + (buttonStripColumn.anchors.margins * 2) + height: toolStripColumn.height + (toolStripColumn.anchors.margins * 2) radius: _radius border.width: 1 border.color: qgcPal.globalTheme === QGCPalette.Light ? Qt.rgba(0,0,0,0.35) : Qt.rgba(1,1,1,0.35) @@ -35,9 +35,7 @@ Rectangle { readonly property real _radius: ScreenTools.defaultFontPixelWidth / 2 readonly property real _margin: ScreenTools.defaultFontPixelWidth / 2 - readonly property real _buttonSpacing: ScreenTools.defaultFontPixelWidth - - property bool _showOptionalElements: !ScreenTools.isTinyScreen + readonly property real _buttonSpacing: ScreenTools.defaultFontPixelHeight / 4 QGCPalette { id: qgcPal } ExclusiveGroup { id: dropButtonsExclusiveGroup } @@ -57,129 +55,141 @@ Rectangle { } Column { - id: buttonStripColumn + id: toolStripColumn anchors.margins: ScreenTools.defaultFontPixelWidth / 2 anchors.top: parent.top anchors.left: parent.left anchors.right: parent.right + spacing: _buttonSpacing QGCLabel { anchors.horizontalCenter: parent.horizontalCenter text: title - visible: _showOptionalElements + font.pointSize: ScreenTools.smallFontPointSize } - Item { width: 1; height: _buttonSpacing; visible: _showOptionalElements } - Rectangle { anchors.left: parent.left anchors.right: parent.right height: 1 color: qgcPal.text - visible: _showOptionalElements } - Repeater { - id: repeater - - delegate: Column { - id: buttonColumn - width: buttonStripColumn.width - visible: _root.buttonVisible ? _root.buttonVisible[index] : true - - property bool checked: false - property ExclusiveGroup exclusiveGroup: dropButtonsExclusiveGroup - - QGCPalette { id: _repeaterPal; colorGroupEnabled: _buttonEnabled } - - property bool _buttonEnabled: _root.buttonEnabled ? _root.buttonEnabled[index] : true - property var _iconSource: modelData.iconSource - property var _alternateIconSource: modelData.alternateIconSource - property var _source: (_root.showAlternateIcon && _root.showAlternateIcon[index]) ? _alternateIconSource : _iconSource - property bool rotateImage: _root.rotateImage ? _root.rotateImage[index] : false - property bool animateImage: _root.animateImage ? _root.animateImage[index] : false - - onExclusiveGroupChanged: { - if (exclusiveGroup) { - exclusiveGroup.bindCheckable(buttonColumn) - } - } - - onRotateImageChanged: { - if (rotateImage) { - imageRotation.running = true - } else { - imageRotation.running = false - button.rotation = 0 - } - } - - onAnimateImageChanged: { - if (animateImage) { - opacityAnimation.running = true - } else { - opacityAnimation.running = false - button.opacity = 1 + Column { + anchors.left: parent.left + anchors.right: parent.right + spacing: _buttonSpacing + + Repeater { + id: repeater + + delegate: FocusScope { + id: scope + width: toolStripColumn.width + height: buttonRect.height + visible: _root.buttonVisible ? _root.buttonVisible[index] : true + + property bool checked: false + property ExclusiveGroup exclusiveGroup: dropButtonsExclusiveGroup + + property bool _buttonEnabled: _root.buttonEnabled ? _root.buttonEnabled[index] : true + property var _iconSource: modelData.iconSource + property var _alternateIconSource: modelData.alternateIconSource + property var _source: (_root.showAlternateIcon && _root.showAlternateIcon[index]) ? _alternateIconSource : _iconSource + property bool rotateImage: _root.rotateImage ? _root.rotateImage[index] : false + property bool animateImage: _root.animateImage ? _root.animateImage[index] : false + property bool _hovered: false + property bool _showHighlight: checked || (_buttonEnabled && _hovered) + + QGCPalette { id: _repeaterPal; colorGroupEnabled: _buttonEnabled } + + onExclusiveGroupChanged: { + if (exclusiveGroup) { + exclusiveGroup.bindCheckable(scope) + } } - } - Item { - width: 1 - height: _buttonSpacing - visible: index == 0 ? _showOptionalElements : true - } + onRotateImageChanged: { + if (rotateImage) { + imageRotation.running = true + } else { + imageRotation.running = false + buttonImage.rotation = 0 + } + } - FocusScope { - id: scope - anchors.left: parent.left - anchors.right: parent.right - height: width * 0.8 + onAnimateImageChanged: { + if (animateImage) { + opacityAnimation.running = true + } else { + opacityAnimation.running = false + buttonImage.opacity = 1 + } + } Rectangle { - anchors.fill: parent - color: checked ? _repeaterPal.buttonHighlight : _repeaterPal.button - - QGCColoredImage { - id: button - height: parent.height - width: height - anchors.centerIn: parent - source: _source - sourceSize.height: height - fillMode: Image.PreserveAspectFit - mipmap: true - smooth: true - color: checked ? _repeaterPal.buttonHighlightText : _repeaterPal.buttonText - - RotationAnimation on rotation { - id: imageRotation - loops: Animation.Infinite - from: 0 - to: 360 - duration: 500 - running: false + id: buttonRect + anchors.left: parent.left + anchors.right: parent.right + height: buttonColumn.height + color: _showHighlight ? _repeaterPal.buttonHighlight : _repeaterPal.window + + Column { + id: buttonColumn + anchors.left: parent.left + anchors.right: parent.right + spacing: -buttonImage.height / 8 + + QGCColoredImage { + id: buttonImage + anchors.left: parent.left + anchors.right: parent.right + height: width * 0.8 + //anchors.centerIn: parent + source: _source + sourceSize.height: height + fillMode: Image.PreserveAspectFit + mipmap: true + smooth: true + color: _showHighlight ? _repeaterPal.buttonHighlightText : _repeaterPal.text + + RotationAnimation on rotation { + id: imageRotation + loops: Animation.Infinite + from: 0 + to: 360 + duration: 500 + running: false + } + + NumberAnimation on opacity { + id: opacityAnimation + running: false + from: 0 + to: 1.0 + loops: Animation.Infinite + duration: 2000 + } } - NumberAnimation on opacity { - id: opacityAnimation - running: false - from: 0 - to: 1.0 - loops: Animation.Infinite - duration: 2000 + QGCLabel { + id: buttonLabel + anchors.horizontalCenter: parent.horizontalCenter + font.pointSize: ScreenTools.smallFontPointSize + text: modelData.name + color: _showHighlight ? _repeaterPal.buttonHighlightText : _repeaterPal.text + enabled: _buttonEnabled } - } + } // Column QGCMouseArea { - // Size of mouse area is expanded to make touch easier - anchors.leftMargin: -buttonStripColumn.anchors.margins - anchors.rightMargin: -buttonStripColumn.anchors.margins - anchors.left: parent.left - anchors.right: parent.right - anchors.top: parent.top - height: parent.height + (_showOptionalElements? buttonLabel.height + buttonColumn.spacing : 0) - visible: _buttonEnabled - preventStealing: true + anchors.fill: parent + visible: _buttonEnabled + hoverEnabled: true + preventStealing: true + + onContainsMouseChanged: _hovered = containsMouse + onContainsPressChanged: _hovered = containsPress onClicked: { scope.focus = true @@ -205,23 +215,8 @@ Rectangle { } } } - } - } - - Item { - width: 1 - height: ScreenTools.defaultFontPixelHeight * 0.25 - visible: _showOptionalElements - } - - QGCLabel { - id: buttonLabel - anchors.horizontalCenter: parent.horizontalCenter - font.pointSize: ScreenTools.smallFontPointSize - text: modelData.name - visible: _showOptionalElements - enabled: _buttonEnabled - } + } // Rectangle + } // FocusScope } } } diff --git a/src/Settings/VideoSettings.cc b/src/Settings/VideoSettings.cc index 8be433f2537defd557eea08872be6cb3e727d312..16ea77d446c64445a64662ba733c9f32bc4a52e2 100644 --- a/src/Settings/VideoSettings.cc +++ b/src/Settings/VideoSettings.cc @@ -25,6 +25,7 @@ const char* VideoSettings::videoSourceAuto = "Automatic Video Stream"; const char* VideoSettings::videoSourceRTSP = "RTSP Video Stream"; const char* VideoSettings::videoSourceUDP = "UDP Video Stream"; const char* VideoSettings::videoSourceTCP = "TCP-MPEG2 Video Stream"; +const char* VideoSettings::videoSourceMPEGTS = "MPEG-TS (h.264) Video Stream"; DECLARE_SETTINGGROUP(Video, "Video") { @@ -40,6 +41,7 @@ DECLARE_SETTINGGROUP(Video, "Video") videoSourceList.append(videoSourceUDP); #endif videoSourceList.append(videoSourceTCP); + videoSourceList.append(videoSourceMPEGTS); #endif #ifndef QGC_DISABLE_UVC QList cameras = QCameraInfo::availableCameras(); @@ -150,6 +152,11 @@ bool VideoSettings::streamConfigured(void) qCDebug(VideoManagerLog) << "Testing configuration for TCP Stream:" << tcpUrl()->rawValue().toString(); return !tcpUrl()->rawValue().toString().isEmpty(); } + //-- If MPEG-TS, check if port is set + if(vSource == videoSourceMPEGTS) { + qCDebug(VideoManagerLog) << "Testing configuration for MPEG-TS Stream:" << udpPort()->rawValue().toInt(); + return udpPort()->rawValue().toInt() != 0; + } //-- If Auto, check for received URL if(vSource == videoSourceAuto) { qCDebug(VideoManagerLog) << "Testing configuration for Auto Stream:" << qgcApp()->toolbox()->videoManager()->autoURL(); diff --git a/src/Settings/VideoSettings.h b/src/Settings/VideoSettings.h index d0002fd0c07e14a88f11e991ef542069b3280b19..ff560235851f9de52338eb4514335725def43b85 100644 --- a/src/Settings/VideoSettings.h +++ b/src/Settings/VideoSettings.h @@ -40,12 +40,14 @@ public: Q_PROPERTY(QString rtspVideoSource READ rtspVideoSource CONSTANT) Q_PROPERTY(QString udpVideoSource READ udpVideoSource CONSTANT) Q_PROPERTY(QString tcpVideoSource READ tcpVideoSource CONSTANT) + Q_PROPERTY(QString mpegtsVideoSource READ mpegtsVideoSource CONSTANT) bool streamConfigured (); QString autoVideoSource () { return videoSourceAuto; } QString rtspVideoSource () { return videoSourceRTSP; } QString udpVideoSource () { return videoSourceUDP; } QString tcpVideoSource () { return videoSourceTCP; } + QString mpegtsVideoSource () { return videoSourceMPEGTS; } static const char* videoSourceNoVideo; static const char* videoDisabled; @@ -53,6 +55,7 @@ public: static const char* videoSourceRTSP; static const char* videoSourceAuto; static const char* videoSourceTCP; + static const char* videoSourceMPEGTS; signals: void streamConfiguredChanged (); diff --git a/src/Vehicle/Vehicle.cc b/src/Vehicle/Vehicle.cc index f8cd2b75dcc4d1e2b2c5dc77c488bda6486e5cd3..4b9b33ef6e71b62d3c19c916f666fd761cffff64 100644 --- a/src/Vehicle/Vehicle.cc +++ b/src/Vehicle/Vehicle.cc @@ -2962,6 +2962,11 @@ bool Vehicle::takeoffVehicleSupported() const return _firmwarePlugin->isCapable(this, FirmwarePlugin::TakeoffVehicleCapability); } +QString Vehicle::gotoFlightMode() const +{ + return _firmwarePlugin->gotoFlightMode(); +} + void Vehicle::guidedModeRTL(void) { if (!guidedModeSupported()) { diff --git a/src/Vehicle/Vehicle.h b/src/Vehicle/Vehicle.h index 4afdb3b6cb3f8267a9cf97caafa13d4dd36cedf3..b330984442289aba2681bde17bca3ad7ae07baf1 100644 --- a/src/Vehicle/Vehicle.h +++ b/src/Vehicle/Vehicle.h @@ -636,13 +636,14 @@ public: Q_PROPERTY(QGCMapCircle* orbitMapCircle READ orbitMapCircle CONSTANT) // Vehicle state used for guided control - Q_PROPERTY(bool flying READ flying NOTIFY flyingChanged) ///< Vehicle is flying - Q_PROPERTY(bool landing READ landing NOTIFY landingChanged) ///< Vehicle is in landing pattern (DO_LAND_START) - Q_PROPERTY(bool guidedMode READ guidedMode WRITE setGuidedMode NOTIFY guidedModeChanged) ///< Vehicle is in Guided mode and can respond to guided commands - Q_PROPERTY(bool guidedModeSupported READ guidedModeSupported CONSTANT) ///< Guided mode commands are supported by this vehicle - Q_PROPERTY(bool pauseVehicleSupported READ pauseVehicleSupported CONSTANT) ///< Pause vehicle command is supported - Q_PROPERTY(bool orbitModeSupported READ orbitModeSupported CONSTANT) ///< Orbit mode is supported by this vehicle - Q_PROPERTY(bool takeoffVehicleSupported READ takeoffVehicleSupported CONSTANT) ///< Guided takeoff supported + Q_PROPERTY(bool flying READ flying NOTIFY flyingChanged) ///< Vehicle is flying + Q_PROPERTY(bool landing READ landing NOTIFY landingChanged) ///< Vehicle is in landing pattern (DO_LAND_START) + Q_PROPERTY(bool guidedMode READ guidedMode WRITE setGuidedMode NOTIFY guidedModeChanged) ///< Vehicle is in Guided mode and can respond to guided commands + Q_PROPERTY(bool guidedModeSupported READ guidedModeSupported CONSTANT) ///< Guided mode commands are supported by this vehicle + Q_PROPERTY(bool pauseVehicleSupported READ pauseVehicleSupported CONSTANT) ///< Pause vehicle command is supported + Q_PROPERTY(bool orbitModeSupported READ orbitModeSupported CONSTANT) ///< Orbit mode is supported by this vehicle + Q_PROPERTY(bool takeoffVehicleSupported READ takeoffVehicleSupported CONSTANT) ///< Guided takeoff supported + Q_PROPERTY(QString gotoFlightMode READ gotoFlightMode CONSTANT) ///< Flight mode vehicle is in while performing goto Q_PROPERTY(ParameterManager* parameterManager READ parameterManager CONSTANT) @@ -761,10 +762,11 @@ public: /// @param percent 0-no power, 100-full power Q_INVOKABLE void motorTest(int motor, int percent); - bool guidedModeSupported (void) const; - bool pauseVehicleSupported (void) const; - bool orbitModeSupported (void) const; - bool takeoffVehicleSupported(void) const; + bool guidedModeSupported (void) const; + bool pauseVehicleSupported (void) const; + bool orbitModeSupported (void) const; + bool takeoffVehicleSupported (void) const; + QString gotoFlightMode (void) const; // Property accessors diff --git a/src/VideoStreaming/VideoReceiver.cc b/src/VideoStreaming/VideoReceiver.cc index a50436afe5afeee19ea0d3122381f43a772ecfdd..3ff914693a145ff8322ec56e4e5e03a423cc6ebe 100644 --- a/src/VideoStreaming/VideoReceiver.cc +++ b/src/VideoStreaming/VideoReceiver.cc @@ -239,9 +239,10 @@ VideoReceiver::start() #else bool isTaisyncUSB = false; #endif - bool isUdp = _uri.contains("udp://") && !isTaisyncUSB; - bool isRtsp = _uri.contains("rtsp://") && !isTaisyncUSB; - bool isTCP = _uri.contains("tcp://") && !isTaisyncUSB; + bool isUdp = _uri.contains("udp://") && !isTaisyncUSB; + bool isRtsp = _uri.contains("rtsp://") && !isTaisyncUSB; + bool isTCP = _uri.contains("tcp://") && !isTaisyncUSB; + bool isMPEGTS = _uri.contains("mpegts://") && !isTaisyncUSB; if (!isTaisyncUSB && _uri.isEmpty()) { qCritical() << "VideoReceiver::start() failed because URI is not specified"; @@ -281,7 +282,7 @@ VideoReceiver::start() break; } - if(isUdp || isTaisyncUSB) { + if(isUdp || isMPEGTS || isTaisyncUSB) { dataSource = gst_element_factory_make("udpsrc", "udp-source"); } else if(isTCP) { dataSource = gst_element_factory_make("tcpclientsrc", "tcpclient-source"); @@ -309,24 +310,26 @@ VideoReceiver::start() } else if(isTCP) { QUrl url(_uri); g_object_set(static_cast(dataSource), "host", qPrintable(url.host()), "port", url.port(), nullptr ); + } else if(isMPEGTS) { + QUrl url(_uri); + g_object_set(static_cast(dataSource), "port", url.port(), nullptr); } else { g_object_set(static_cast(dataSource), "location", qPrintable(_uri), "latency", 17, "udp-reconnect", 1, "timeout", _udpReconnect_us, NULL); } - // Currently, we expect H264 when using anything except for TCP. Long term we may want this to be settable - if (isTCP) { - if ((demux = gst_element_factory_make("tsdemux", "mpeg2-ts-demuxer")) == nullptr) { + if (isTCP || isMPEGTS) { + if ((demux = gst_element_factory_make("tsdemux", "mpeg-ts-demuxer")) == nullptr) { qCritical() << "VideoReceiver::start() failed. Error with gst_element_factory_make('tsdemux')"; break; } } else { if(!isTaisyncUSB) { if ((demux = gst_element_factory_make("rtph264depay", "rtp-h264-depacketizer")) == nullptr) { - qCritical() << "VideoReceiver::start() failed. Error with gst_element_factory_make('rtph264depay')"; - break; + qCritical() << "VideoReceiver::start() failed. Error with gst_element_factory_make('rtph264depay')"; + break; + } } } - } if ((parser = gst_element_factory_make("h264parse", "h264-parser")) == nullptr) { qCritical() << "VideoReceiver::start() failed. Error with gst_element_factory_make('h264parse')"; @@ -374,13 +377,13 @@ VideoReceiver::start() qCritical() << "Unable to link Taisync USB elements."; break; } - } else if (isTCP) { + } else if (isTCP || isMPEGTS) { if(!gst_element_link(dataSource, demux)) { - qCritical() << "Unable to link TCP dataSource to Demux."; + qCritical() << "Unable to link TCP/MPEG-TS dataSource to Demux."; break; } if(!gst_element_link_many(parser, _tee, queue, decoder, queue1, _videoSink, nullptr)) { - qCritical() << "Unable to link TCP pipline to parser."; + qCritical() << "Unable to link TCP/MPEG-TS pipline to parser."; break; } g_signal_connect(demux, "pad-added", G_CALLBACK(newPadCB), parser); @@ -469,7 +472,7 @@ VideoReceiver::start() void VideoReceiver::stop() { - if(!qgcApp()->runningUnitTests()) { + if(qgcApp()->runningUnitTests()) { return; } #if defined(QGC_GST_STREAMING) diff --git a/src/VideoStreaming/VideoStreaming.cc b/src/VideoStreaming/VideoStreaming.cc index 265d6ecaeac69805668090d83ea3e170711ac8a9..cd02747e7a87ee4789fa939890dc641e22ae8de7 100644 --- a/src/VideoStreaming/VideoStreaming.cc +++ b/src/VideoStreaming/VideoStreaming.cc @@ -130,11 +130,13 @@ void initializeVideoStreaming(int &argc, char* argv[], char* logpath, char* debu #else //-- Generic initialization if (logpath) { + QString gstDebugFile = QString("%1/%2").arg(logpath).arg("gstreamer-log.txt"); + qDebug() << "GStreamer debug output:" << gstDebugFile; if (debuglevel) { qputenv("GST_DEBUG", debuglevel); } qputenv("GST_DEBUG_NO_COLOR", "1"); - qputenv("GST_DEBUG_FILE", QString("%1/%2").arg(logpath).arg("gstreamer-log.txt").toUtf8()); + qputenv("GST_DEBUG_FILE", gstDebugFile.toUtf8()); qputenv("GST_DEBUG_DUMP_DOT_DIR", logpath); } GError* error = nullptr; diff --git a/src/api/QGCCorePlugin.h b/src/api/QGCCorePlugin.h index 13deb754b36299775f9001bf4a08d3d2f348fb2c..a4812577ec933c2593e3647e866efb722b113ad0 100644 --- a/src/api/QGCCorePlugin.h +++ b/src/api/QGCCorePlugin.h @@ -139,6 +139,11 @@ public: /// Custom builds must override to provide their own location. virtual QString stableDownloadLocation(void) const { return QString("qgroundcontrol.com"); } + /// Returns the complex mission items to display in the Plan UI + /// @param complexMissionItemNames Default set of complex items + /// @return Complex items to be made available to user + virtual QStringList complexMissionItemNames(Vehicle* vehicle, const QStringList& complexMissionItemNames) { Q_UNUSED(vehicle); return complexMissionItemNames; } + bool showTouchAreas(void) const { return _showTouchAreas; } bool showAdvancedUI(void) const { return _showAdvancedUI; } void setShowTouchAreas(bool show); diff --git a/src/ui/preferences/GeneralSettings.qml b/src/ui/preferences/GeneralSettings.qml index fdb49133e4eca3d21567d10792f5011780fabc91..2a906c2cc44f64d193a255b512126ac86226936a 100644 --- a/src/ui/preferences/GeneralSettings.qml +++ b/src/ui/preferences/GeneralSettings.qml @@ -37,7 +37,7 @@ QGCView { property Fact _userBrandImageIndoor: QGroundControl.settingsManager.brandImageSettings.userBrandImageIndoor property Fact _userBrandImageOutdoor: QGroundControl.settingsManager.brandImageSettings.userBrandImageOutdoor property real _labelWidth: ScreenTools.defaultFontPixelWidth * 20 - property real _comboFieldWidth: ScreenTools.defaultFontPixelWidth * 25 + property real _comboFieldWidth: ScreenTools.defaultFontPixelWidth * 28 property real _valueFieldWidth: ScreenTools.defaultFontPixelWidth * 10 property Fact _mapProvider: QGroundControl.settingsManager.flightMapSettings.mapProvider property Fact _mapType: QGroundControl.settingsManager.flightMapSettings.mapType @@ -51,6 +51,7 @@ QGCView { property bool _isUDP: _isGst && _videoSource === QGroundControl.settingsManager.videoSettings.udpVideoSource property bool _isRTSP: _isGst && _videoSource === QGroundControl.settingsManager.videoSettings.rtspVideoSource property bool _isTCP: _isGst && _videoSource === QGroundControl.settingsManager.videoSettings.tcpVideoSource + property bool _isMPEGTS: _isGst && _videoSource === QGroundControl.settingsManager.videoSettings.mpegtsVideoSource readonly property real _internalWidthRatio: 0.8 @@ -707,7 +708,6 @@ QGCView { Layout.fillWidth: false Layout.fillHeight: false columns: 2 - QGCLabel { text: qsTr("Video Source") visible: QGroundControl.settingsManager.videoSettings.videoSource.visible @@ -722,12 +722,12 @@ QGCView { QGCLabel { text: qsTr("UDP Port") - visible: _isUDP && QGroundControl.settingsManager.videoSettings.udpPort.visible + visible: (_isUDP || _isMPEGTS) && QGroundControl.settingsManager.videoSettings.udpPort.visible } FactTextField { Layout.preferredWidth: _comboFieldWidth fact: QGroundControl.settingsManager.videoSettings.udpPort - visible: _isUDP && QGroundControl.settingsManager.videoSettings.udpPort.visible + visible: (_isUDP || _isMPEGTS) && QGroundControl.settingsManager.videoSettings.udpPort.visible } QGCLabel {