diff --git a/qgroundcontrol.qrc b/qgroundcontrol.qrc index e611bc24437b9990df83b279040248dead77d67d..ccabc9be31c3c8ebd738baa43a49810da4170be0 100644 --- a/qgroundcontrol.qrc +++ b/qgroundcontrol.qrc @@ -32,6 +32,8 @@ src/QmlControls/VehicleSummaryRow.qml src/QmlControls/arrow-down.png src/ViewWidgets/ViewWidget.qml + src/QmlControls/ViewWithDialog.qml + src/QmlControls/ParameterEditor.qml src/ViewWidgets/ParameterEditorWidget.qml diff --git a/src/AutoPilotPlugins/PX4/AirframeComponent.qml b/src/AutoPilotPlugins/PX4/AirframeComponent.qml index b7a483768cb5fddbde800432d810d2127cc4fdcc..37a58d2f3d72328f61d26c0d956965a2126e1e0d 100644 --- a/src/AutoPilotPlugins/PX4/AirframeComponent.qml +++ b/src/AutoPilotPlugins/PX4/AirframeComponent.qml @@ -24,6 +24,7 @@ import QtQuick 2.2 import QtQuick.Controls 1.2 import QtQuick.Controls.Styles 1.2 +import QtQuick.Dialogs 1.2 import QGroundControl.FactSystem 1.0 import QGroundControl.FactControls 1.0 @@ -31,132 +32,190 @@ import QGroundControl.Palette 1.0 import QGroundControl.Controls 1.0 import QGroundControl.Controllers 1.0 -FactPanel { - id: panel +ViewWithDialog { + viewComponent: view - AirframeComponentController { id: controller; factPanel: panel } + Component { + id: view - Rectangle { - anchors.fill: parent + FactPanel { + id: panel + anchors.fill: parent - QGCPalette { id: qgcPal; colorGroupEnabled: true } + signal showDialog(Component component, string title, int charWidth, int buttons) + signal hideDialog - color: qgcPal.window + function doWorkAfterComponentCompleted() { + if (controller.showCustomConfigPanel) { + panel.showDialog(customConfigDialog, "Custom Airframe Config", 50, StandardButton.Reset) + } + } - Column { - anchors.fill: parent + AirframeComponentController { + id: controller + factPanel: panel + } - QGCLabel { - text: "AIRFRAME CONFIG" - font.pointSize: 20 + Component { + id: customConfigDialog + + QGCLabel { + id: customConfigPanel + anchors.fill: parent + wrapMode: Text.WordWrap + text: "Your vehicle is using a custom airframe configuration. " + + "This configuration can only be modified through the Parameter Editor.\n\n" + + "If you want to Reset your airframe configuration and select a standard configuration, click 'Reset' above." + + signal hideDialog + + Fact { id: sys_autostart; name: "SYS_AUTOSTART" } + + function accept() { + sys_autostart.value = 0 + customConfigPanel.hideDialog() + } + } } - Item { height: 20; width: 10 } // spacer + Rectangle { + anchors.fill: parent + + QGCPalette { id: qgcPal; colorGroupEnabled: true } + + color: qgcPal.window + + QGCLabel { + id: header + width: parent.width + font.pointSize: 20 + text: "AIRFRAME CONFIG" + } - Row { - width: parent.width + Item { + id: headingSpacer + anchors.top: header.bottom + height: 20 + width: 20 + } QGCLabel { - width: parent.width - applyButton.width - text: "Select you airframe type and specific vehicle bellow. Click 'Apply and Restart' when ready and your vehicle will be disconnected, rebooted to the new settings and re-connected." - wrapMode: Text.WordWrap + anchors.top: headingSpacer.bottom + width: parent.width - applyButton.width - 5 + text: "Select you airframe type and specific vehicle bellow. Click 'Apply and Restart' when ready and your vehicle will be disconnected, rebooted to the new settings and re-connected." + wrapMode: Text.WordWrap } QGCButton { - id: applyButton - text: "Apply and Restart" + id: applyButton + anchors.top: headingSpacer.bottom + anchors.right: parent.right + text: "Apply and Restart" + onClicked: { controller.changeAutostart() } } - } - Item { height: 20; width: 10 } // spacer + Item { + id: lastSpacer + anchors.top: applyButton.bottom + height: 20 + width: 10 + } - Flow { - width: parent.width - spacing: 10 + ScrollView { + id: scroll + anchors.top: lastSpacer.bottom + anchors.bottom: parent.bottom + width: parent.width + horizontalScrollBarPolicy: Qt.ScrollBarAlwaysOff - ExclusiveGroup { - id: airframeTypeExclusive - } + Flow { + width: scroll.width + spacing: 10 - Repeater { - model: controller.airframeTypes + ExclusiveGroup { + id: airframeTypeExclusive + } - // Outer summary item rectangle - Rectangle { - readonly property real titleHeight: 30 - readonly property real innerMargin: 10 + Repeater { + model: controller.airframeTypes - width: 250 - height: 200 - color: qgcPal.windowShade + // Outer summary item rectangle + Rectangle { + readonly property real titleHeight: 30 + readonly property real innerMargin: 10 - Rectangle { - id: title - width: parent.width - height: parent.titleHeight - color: qgcPal.windowShadeDark + width: 250 + height: 200 + color: qgcPal.windowShade - Text { - anchors.fill: parent + Rectangle { + id: title + width: parent.width + height: parent.titleHeight + color: qgcPal.windowShadeDark - color: qgcPal.buttonText - font.pixelSize: 12 - text: modelData.name + Text { + anchors.fill: parent - verticalAlignment: TextEdit.AlignVCenter - horizontalAlignment: TextEdit.AlignHCenter - } - } + color: qgcPal.buttonText + font.pixelSize: 12 + text: modelData.name - Image { - id: image - x: innerMargin - width: parent.width - (innerMargin * 2) - height: parent.height - title.height - combo.height - (innerMargin * 3) - anchors.topMargin: innerMargin - anchors.top: title.bottom + verticalAlignment: TextEdit.AlignVCenter + horizontalAlignment: TextEdit.AlignHCenter + } + } - source: modelData.imageResource - fillMode: Image.PreserveAspectFit - smooth: true + Image { + id: image + x: innerMargin + width: parent.width - (innerMargin * 2) + height: parent.height - title.height - combo.height - (innerMargin * 3) + anchors.topMargin: innerMargin + anchors.top: title.bottom - } + source: modelData.imageResource + fillMode: Image.PreserveAspectFit + smooth: true - QGCCheckBox { - id: airframeCheckBox - anchors.bottom: image.bottom - anchors.right: image.right - checked: modelData.name == controller.currentAirframeType - exclusiveGroup: airframeTypeExclusive + } - onCheckedChanged: { - if (checked && combo.currentIndex != -1) { - controller.autostartId = modelData.airframes[combo.currentIndex].autostartId + QGCCheckBox { + id: airframeCheckBox + anchors.bottom: image.bottom + anchors.right: image.right + checked: modelData.name == controller.currentAirframeType + exclusiveGroup: airframeTypeExclusive + + onCheckedChanged: { + if (checked && combo.currentIndex != -1) { + controller.autostartId = modelData.airframes[combo.currentIndex].autostartId + } + } } - } - } - QGCComboBox { - id: combo - objectName: modelData.airframeType + "ComboBox" - x: innerMargin - anchors.topMargin: innerMargin - anchors.top: image.bottom - width: parent.width - (innerMargin * 2) - model: modelData.airframes - currentIndex: (modelData.name == controller.currentAirframeType) ? controller.currentVehicleIndex : 0 - - onCurrentIndexChanged: { - if (airframeCheckBox.checked) { - controller.autostartId = modelData.airframes[currentIndex].autostartId + QGCComboBox { + id: combo + objectName: modelData.airframeType + "ComboBox" + x: innerMargin + anchors.topMargin: innerMargin + anchors.top: image.bottom + width: parent.width - (innerMargin * 2) + model: modelData.airframes + currentIndex: (modelData.name == controller.currentAirframeType) ? controller.currentVehicleIndex : 0 + + onCurrentIndexChanged: { + if (airframeCheckBox.checked) { + controller.autostartId = modelData.airframes[currentIndex].autostartId + } + } } } - } - } - } - } - - } - } + } // Repeater - summary boxes + } // Flow - summary boxes + } // Scroll View - summary boxes + } // Rectangle - background + } // FactPanel + } // Component - View } \ No newline at end of file diff --git a/src/AutoPilotPlugins/PX4/AirframeComponentController.cc b/src/AutoPilotPlugins/PX4/AirframeComponentController.cc index d0c9bf04ece1c34ab82147523d22b140fd623f1d..2cc1386f495f8e507e68f9e59310695ae2c91bd0 100644 --- a/src/AutoPilotPlugins/PX4/AirframeComponentController.cc +++ b/src/AutoPilotPlugins/PX4/AirframeComponentController.cc @@ -40,7 +40,8 @@ bool AirframeComponentController::_typesRegistered = false; AirframeComponentController::AirframeComponentController(void) : _uas(NULL), _currentVehicleIndex(0), - _autostartId(0) + _autostartId(0), + _showCustomConfigPanel(false) { _uas = UASManager::instance()->getActiveUAS(); Q_ASSERT(_uas); @@ -82,10 +83,9 @@ AirframeComponentController::AirframeComponentController(void) : _airframeTypes.append(QVariant::fromValue(airframeType)); } - if (_autostartId != 0) { - // FIXME: Should be a user error - Q_UNUSED(autostartFound); - Q_ASSERT(autostartFound); + if (_autostartId != 0 && !autostartFound) { + _showCustomConfigPanel = true; + emit showCustomConfigPanelChanged(true); } } diff --git a/src/AutoPilotPlugins/PX4/AirframeComponentController.h b/src/AutoPilotPlugins/PX4/AirframeComponentController.h index 0e8b5ced752de8125c2e5edb4e33985f9df32d9d..79cfdcbf8105171b4ccf8983560c9edfcd68c1d8 100644 --- a/src/AutoPilotPlugins/PX4/AirframeComponentController.h +++ b/src/AutoPilotPlugins/PX4/AirframeComponentController.h @@ -44,6 +44,8 @@ public: AirframeComponentController(void); ~AirframeComponentController(); + Q_PROPERTY(bool showCustomConfigPanel MEMBER _showCustomConfigPanel NOTIFY showCustomConfigPanelChanged) + Q_PROPERTY(QVariantList airframeTypes MEMBER _airframeTypes CONSTANT) Q_PROPERTY(QString currentAirframeType MEMBER _currentAirframeType CONSTANT) @@ -59,6 +61,7 @@ public: signals: void autostartIdChanged(int newAutostartId); + void showCustomConfigPanelChanged(bool show); private: static bool _typesRegistered; @@ -69,6 +72,7 @@ private: QString _currentVehicleName; int _currentVehicleIndex; int _autostartId; + bool _showCustomConfigPanel; }; class Airframe : public QObject diff --git a/src/QmlControls/ViewWithDialog.qml b/src/QmlControls/ViewWithDialog.qml new file mode 100644 index 0000000000000000000000000000000000000000..61d64c41bbaffb4c7b3c0a5eded26a3af23570d8 --- /dev/null +++ b/src/QmlControls/ViewWithDialog.qml @@ -0,0 +1,221 @@ +/*===================================================================== + + QGroundControl Open Source Ground Control Station + + (c) 2009 - 2015 QGROUNDCONTROL PROJECT + + This file is part of the QGROUNDCONTROL project + + QGROUNDCONTROL is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + QGROUNDCONTROL is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with QGROUNDCONTROL. If not, see . + + ======================================================================*/ + +/// @file +/// @author Don Gagne + +import QtQuick 2.3 +import QtQuick.Controls 1.3 +import QtQuick.Dialogs 1.2 + +import QGroundControl.Controls 1.0 +import QGroundControl.Palette 1.0 +import QGroundControl.ScreenTools 1.0 +import QGroundControl.FactSystem 1.0 +import QGroundControl.FactControls 1.0 + +Item { + property Component viewComponent + + function __showDialog(component, title, charWidth, buttons) { + __acceptButton.visible = false + __rejectButton.visible = false + __dialogCharWidth = charWidth + __dialogTitle = title + + if (buttons & StandardButton.Ok) { + __acceptButton.text = "Ok" + __acceptButton.visible = true + } else if (buttons & StandardButton.Open) { + __acceptButton.text = "Open" + __acceptButton.visible = true + } else if (buttons & StandardButton.Save) { + __acceptButton.text = "Save" + __acceptButton.visible = true + } else if (buttons & StandardButton.Cancel) { + __rejectButton.text = "Cancel" + __rejectButton.visible = true + } else if (buttons & StandardButton.Close) { + __rejectButton.text = "Cancel" + __rejectButton.visible = true + } else if (buttons & StandardButton.Apply) { + __acceptButton.text = "Apply" + __acceptButton.visible = true + } else if (buttons & StandardButton.Open) { + __acceptButton.text = "Open" + __acceptButton.visible = true + } else if (buttons & StandardButton.SaveAll) { + __acceptButton.text = "Save All" + __acceptButton.visible = true + } else if (buttons & StandardButton.Yes) { + __acceptButton.text = "Yes" + __acceptButton.visible = true + } else if (buttons & StandardButton.YesToAll) { + __acceptButton.text = "Yes to All" + __acceptButton.visible = true + } else if (buttons & StandardButton.No) { + __rejectButton.text = "No" + __rejectButton.visible = true + } else if (buttons & StandardButton.NoToAll) { + __rejectButton.text = "No to All" + __rejectButton.visible = true + } else if (buttons & StandardButton.Abort) { + __rejectButton.text = "Abort" + __rejectButton.visible = true + } else if (buttons & StandardButton.Retry) { + __acceptButton.text = "Retry" + __acceptButton.visible = true + } else if (buttons & StandardButton.Reset) { + __acceptButton.text = "Reset" + __acceptButton.visible = true + } else if (buttons & StandardButton.RestoreToDefaults) { + __acceptButton.text = "Restore to Defaults" + __acceptButton.visible = true + } else if (buttons & StandardButton.Ignore) { + __acceptButton.text = "Ignore" + __acceptButton.visible = true + } + __dialogComponent = component + __viewPanel.enabled = false + __dialogOverlay.visible = true + } + + function __hideDialog() { + __dialogComponent = null + __viewPanel.enabled = true + __dialogOverlay.visible = false + } + + QGCPalette { id: __qgcPal; colorGroupEnabled: true } + QGCLabel { id: __textMeasure; text: "X"; visible: false } + + property real __textHeight: __textMeasure.contentHeight + property real __textWidth: __textMeasure.contentWidth + + /// The width of the dialog panel in characters + property int __dialogCharWidth: 75 + + /// The title for the dialog panel + property string __dialogTitle + + property Component __dialogComponent + + Component.onCompleted: __viewPanel.item.doWorkAfterComponentCompleted() + + Connections { + target: __viewPanel.item + + onShowDialog: __showDialog(component, title, charWidth, buttons) + onHideDialog: __hideDialog() + } + + Connections { + target: __dialogComponentLoader.item + + onHideDialog: __hideDialog() + } + + Loader { + id: __viewPanel + anchors.fill: parent + focus: true + sourceComponent: viewComponent + } + + Item { + id: __dialogOverlay + visible: false + anchors.fill: parent + z: 5000 + + // This covers the parent with an transparent section + Rectangle { + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.left: parent.left + anchors.right: __dialogPanel.left + opacity: 0.80 + color: __qgcPal.window + } + + // This is the main dialog panel which is anchored to the right edge + Rectangle { + id: __dialogPanel + width: __textWidth * __dialogCharWidth + height: parent.height + anchors.right: parent.right + color: __qgcPal.windowShadeDark + + Rectangle { + id: __header + width: parent.width + height: __acceptButton.height + color: __qgcPal.windowShade + + function __hidePanel() { + __fullPanel.visible = false + } + + QGCLabel { + x: __textWidth + height: parent.height + verticalAlignment: Text.AlignVCenter + text: __dialogTitle + } + + QGCButton { + id: __rejectButton + anchors.right: __acceptButton.left + anchors.bottom: parent.bottom + + onClicked: __dialogComponentLoader.item.reject() + } + + QGCButton { + id: __acceptButton + anchors.right: parent.right + primary: true + + onClicked: __dialogComponentLoader.item.accept() + } + } + + Item { + id: __spacer + width: 10 + height: 10 + anchors.top: __header.bottom + } + + Loader { + id: __dialogComponentLoader + anchors.margins: 5 + anchors.left: parent.left + anchors.right: parent.right + anchors.top: __spacer.bottom + anchors.bottom: parent.bottom + sourceComponent: __dialogComponent + } + } // Rectangle - Dialog panel + } // Item - Dialog overlay +} \ No newline at end of file diff --git a/src/QmlControls/qmldir b/src/QmlControls/qmldir index b62af1bcbd73ebb6588a628c0514fd3f90f65902..a588343b36f613226ad807df77765cea3020797e 100644 --- a/src/QmlControls/qmldir +++ b/src/QmlControls/qmldir @@ -16,4 +16,5 @@ VehicleRotationCal 1.0 VehicleRotationCal.qml VehicleSummaryRow 1.0 VehicleSummaryRow.qml ParameterEditor 1.0 ParameterEditor.qml ViewWidget 1.0 ViewWidget.qml +ViewWithDialog 1.0 ViewWithDialog.qml