From 1aba5c4b1add3fb4eee7f9dcb807814039e0ccef Mon Sep 17 00:00:00 2001 From: DoinLakeFlyer Date: Sun, 12 Apr 2020 14:20:50 -0700 Subject: [PATCH] Initial support for value ranges --- qgroundcontrol.pro | 2 + src/FlightMap/Widgets/InstrumentValue.cc | 414 ++++++++++++++++++ src/FlightMap/Widgets/InstrumentValue.h | 173 ++++++++ src/FlightMap/Widgets/ValuePageWidget.qml | 369 +++++++++++++++- .../Widgets/ValuesWidgetController.cc | 238 +--------- .../Widgets/ValuesWidgetController.h | 101 +---- src/QmlControls/QGCPopupDialogContainer.qml | 6 +- 7 files changed, 966 insertions(+), 337 deletions(-) create mode 100644 src/FlightMap/Widgets/InstrumentValue.cc create mode 100644 src/FlightMap/Widgets/InstrumentValue.h diff --git a/qgroundcontrol.pro b/qgroundcontrol.pro index c21df165c..1523185f6 100644 --- a/qgroundcontrol.pro +++ b/qgroundcontrol.pro @@ -571,6 +571,7 @@ HEADERS += \ src/Camera/QGCCameraManager.h \ src/CmdLineOptParser.h \ src/FirmwarePlugin/PX4/px4_custom_mode.h \ + src/FlightMap/Widgets/InstrumentValue.h \ src/FlightMap/Widgets/ValuesWidgetController.h \ src/FollowMe/FollowMe.h \ src/Joystick/Joystick.h \ @@ -778,6 +779,7 @@ SOURCES += \ src/Camera/QGCCameraIO.cc \ src/Camera/QGCCameraManager.cc \ src/CmdLineOptParser.cc \ + src/FlightMap/Widgets/InstrumentValue.cc \ src/FlightMap/Widgets/ValuesWidgetController.cc \ src/FollowMe/FollowMe.cc \ src/Joystick/Joystick.cc \ diff --git a/src/FlightMap/Widgets/InstrumentValue.cc b/src/FlightMap/Widgets/InstrumentValue.cc new file mode 100644 index 000000000..f1ea598f1 --- /dev/null +++ b/src/FlightMap/Widgets/InstrumentValue.cc @@ -0,0 +1,414 @@ +/**************************************************************************** + * + * (c) 2009-2020 QGROUNDCONTROL PROJECT + * + * QGroundControl is licensed according to the terms in the file + * COPYING.md in the root of the source code directory. + * + ****************************************************************************/ + + +#include "InstrumentValue.h" +#include "QGCApplication.h" +#include "QGCCorePlugin.h" + +#include + +const char* InstrumentValue::_versionKey = "version"; +const char* InstrumentValue::_factGroupNameKey = "groupName"; +const char* InstrumentValue::_factNameKey = "factName"; +const char* InstrumentValue::_labelKey = "label"; +const char* InstrumentValue::_fontSizeKey = "fontSize"; +const char* InstrumentValue::_showUnitsKey = "showUnits"; +const char* InstrumentValue::_iconKey = "icon"; +const char* InstrumentValue::_iconPositionKey = "iconPosition"; +const char* InstrumentValue::_rangeTypeKey = "rangeType"; +const char* InstrumentValue::_rangeValuesKey = "rangeValues"; +const char* InstrumentValue::_rangeColorsKey = "rangeColors"; +const char* InstrumentValue::_rangeIconsKey = "rangeIcons"; +const char* InstrumentValue::_rangeOpacitiesKey = "rangeOpacities"; +const char* InstrumentValue::_vehicleFactGroupName = "Vehicle"; + +QStringList InstrumentValue::_iconNames; + +// Important: The indices of these strings must match the InstrumentValue::IconPosition enumconst QStringList InstrumentValue::_iconPositionNames +const QStringList InstrumentValue::_iconPositionNames = { + QT_TRANSLATE_NOOP("InstrumentValue", "Above"), + QT_TRANSLATE_NOOP("InstrumentValue", "Left"), +}; + +// Important: The indices of these strings must match the InstrumentValue::FontSize enum +const QStringList InstrumentValue::_fontSizeNames = { + QT_TRANSLATE_NOOP("InstrumentValue", "Default"), + QT_TRANSLATE_NOOP("InstrumentValue", "Small"), + QT_TRANSLATE_NOOP("InstrumentValue", "Medium"), + QT_TRANSLATE_NOOP("InstrumentValue", "Large"), +}; + +// Important: The indices of these strings must match the InstrumentValue::RangeType enum +const QStringList InstrumentValue::_rangeTypeNames = { + QT_TRANSLATE_NOOP("InstrumentValue", "None"), + QT_TRANSLATE_NOOP("InstrumentValue", "Color"), + QT_TRANSLATE_NOOP("InstrumentValue", "Opacity"), + QT_TRANSLATE_NOOP("InstrumentValue", "Icon"), +}; + +InstrumentValue::InstrumentValue(Vehicle* activeVehicle, FontSize fontSize, QmlObjectListModel* rowModel) + : QObject (rowModel) + , _activeVehicle(activeVehicle) + , _rowModel (rowModel) + , _fontSize (fontSize) +{ + if (_iconNames.isEmpty()) { + QDir iconDir(":/InstrumentValueIcons/"); + _iconNames = iconDir.entryList(); + } + + activeVehicleChanged(_activeVehicle); + connect(this, &InstrumentValue::rangeTypeChanged, this, &InstrumentValue::_resetRangeInfo); +} + +void InstrumentValue::activeVehicleChanged(Vehicle* activeVehicle) +{ + _activeVehicle = activeVehicle; + + _factGroupNames.clear(); + _factGroupNames = _activeVehicle->factGroupNames(); + for (QString& name: _factGroupNames) { + name[0] = name[0].toUpper(); + } + _factGroupNames.prepend(_vehicleFactGroupName); + emit factGroupNamesChanged(_factGroupNames); + + if (_fact) { + _fact = nullptr; + + FactGroup* factGroup = nullptr; + if (_factGroupName == _vehicleFactGroupName) { + factGroup = _activeVehicle; + } else { + factGroup = _activeVehicle->getFactGroup(_factGroupName); + } + + if (factGroup) { + _fact = factGroup->getFact(_factName); + } + emit factChanged(_fact); + } +} + +void InstrumentValue::setFact(const QString& factGroupName, const QString& factName) +{ + if (_fact) { + _fact = nullptr; + } + + FactGroup* factGroup = nullptr; + if (factGroupName == _vehicleFactGroupName) { + factGroup = _activeVehicle; + } else { + factGroup = _activeVehicle->getFactGroup(factGroupName); + } + + _factValueNames.clear(); + _factValueNames = factGroup->factNames(); + for (QString& name: _factValueNames) { + name[0] = name[0].toUpper(); + } + + QString nonEmptyFactName; + if (factGroup) { + if (factName.isEmpty()) { + nonEmptyFactName = _factValueNames[0]; + } else { + nonEmptyFactName = factName; + } + _fact = factGroup->getFact(nonEmptyFactName); + } + + if (_fact) { + _factGroupName = factGroupName; + _factName = nonEmptyFactName; + } else { + _factName.clear(); + _factGroupName.clear(); + } + + emit factChanged (_fact); + emit factNameChanged (_factName); + emit factGroupNameChanged (_factGroupName); + emit factValueNamesChanged (_factValueNames); +} + +void InstrumentValue::_setFontSize(FontSize fontSize) +{ + if (fontSize != _fontSize) { + _fontSize = fontSize; + emit fontSizeChanged(fontSize); + } +} + +void InstrumentValue::setFontSize(FontSize fontSize) +{ + _setFontSize(fontSize); + + // All other items in row must change to match + for (int i=0; i<_rowModel->count(); i++) { + InstrumentValue* instrumentValue = _rowModel->value(i); + if (instrumentValue != this) { + instrumentValue->_setFontSize(fontSize); + } + } +} + +void InstrumentValue::saveToSettings(QSettings& settings) const +{ + settings.setValue(_versionKey, 1); + settings.setValue(_labelKey, _label); + settings.setValue(_fontSizeKey, _fontSize); + settings.setValue(_showUnitsKey, _showUnits); + settings.setValue(_iconKey, _icon); + settings.setValue(_iconPositionKey, _iconPosition); + settings.setValue(_rangeTypeKey, _rangeType); + + if (_rangeType != NoRangeInfo) { + settings.setValue(_rangeValuesKey, _rangeValues); + } + + switch (_rangeType) { + case NoRangeInfo: + break; + case ColorRange: + settings.setValue(_rangeColorsKey, _rangeColors); + break; + case OpacityRange: + settings.setValue(_rangeOpacitiesKey, _rangeOpacities); + break; + case IconSelectRange: + settings.setValue(_rangeIconsKey, _rangeIcons); + break; + } + + if (_fact) { + settings.setValue(_factGroupNameKey, _factGroupName); + settings.setValue(_factNameKey, _factName); + } else { + settings.setValue(_factGroupNameKey, ""); + settings.setValue(_factNameKey, ""); + } +} + +void InstrumentValue::readFromSettings(const QSettings& settings) +{ + _factGroupName = settings.value(_factGroupNameKey, QString()).toString(); + _label = settings.value(_labelKey, QString()).toString(); + _fontSize = settings.value(_fontSizeKey, DefaultFontSize).value(); + _showUnits = settings.value(_showUnitsKey, true).toBool(); + _icon = settings.value(_iconKey, QString()).toString(); + _iconPosition = settings.value(_iconPositionKey, IconLeft).value(); + _rangeType = settings.value(_rangeTypeKey, NoRangeInfo).value(); + + // Do this now, since the signal will cause _resetRangeInfo to be called trashing values + emit rangeTypeChanged(_rangeType); + + _rangeValues.clear(); + _rangeColors.clear(); + _rangeOpacities.clear(); + _rangeIcons.clear(); + if (_rangeType != NoRangeInfo) { + _rangeValues = settings.value(_rangeValuesKey).value(); + } + switch (_rangeType) { + case NoRangeInfo: + break; + case ColorRange: + _rangeColors = settings.value(_rangeColorsKey).value(); + break; + case OpacityRange: + _rangeOpacities = settings.value(_rangeOpacitiesKey).value(); + break; + case IconSelectRange: + _rangeIcons = settings.value(_rangeIconsKey).value(); + break; + } + + QString factName = settings.value(_factNameKey).toString(); + if (!factName.isEmpty()) { + setFact(_factGroupName, factName); + } + + emit factChanged (_fact); + emit factGroupNameChanged (_factGroupName); + emit labelChanged (_label); + emit fontSizeChanged (_fontSize); + emit showUnitsChanged (_showUnits); + emit iconChanged (_icon); + emit iconPositionChanged (_iconPosition); + emit rangeValuesChanged (_rangeValues); + emit rangeColorsChanged (_rangeColors); + emit rangeOpacitiesChanged (_rangeOpacities); + emit rangeIconsChanged (_rangeIcons); +} + +void InstrumentValue::setLabel(const QString& label) +{ + if (label != _label) { + _label = label; + emit labelChanged(label); + } +} + +void InstrumentValue::setShowUnits(bool showUnits) +{ + if (showUnits != _showUnits) { + _showUnits = showUnits; + emit showUnitsChanged(showUnits); + } +} + +void InstrumentValue::clearFact(void) +{ + _fact = nullptr; + _factGroupName.clear(); + _label.clear(); + _icon.clear(); + _showUnits = true; + + emit factChanged (_fact); + emit factGroupNameChanged (_factGroupName); + emit labelChanged (_label); + emit iconChanged (_icon); + emit showUnitsChanged (_showUnits); +} + +void InstrumentValue::setIcon(const QString& icon) +{ + if (icon != _icon) { + _icon = icon; + emit iconChanged(_icon); + } +} + +void InstrumentValue::setIconPosition(IconPosition iconPosition) +{ + if (iconPosition != _iconPosition) { + _iconPosition = iconPosition; + emit iconPositionChanged(iconPosition); + } +} + +void InstrumentValue::setRangeType(RangeType rangeType) +{ + if (rangeType != _rangeType) { + _rangeType = rangeType; + emit rangeTypeChanged(rangeType); + } +} + +void InstrumentValue::setRangeValues(const QVariantList& rangeValues) +{ + _rangeValues = rangeValues; + emit rangeValuesChanged(rangeValues); +} + +void InstrumentValue::setRangeColors (const QVariantList& rangeColors) +{ + _rangeColors = rangeColors; + emit rangeColorsChanged(rangeColors); +} + +void InstrumentValue::setRangeIcons(const QVariantList& rangeIcons) +{ + _rangeIcons = rangeIcons; + emit rangeIconsChanged(rangeIcons); +} + +void InstrumentValue::setRangeOpacities(const QVariantList& rangeOpacities) +{ + _rangeOpacities = rangeOpacities; + emit rangeOpacitiesChanged(rangeOpacities); +} + +void InstrumentValue::_resetRangeInfo(void) +{ + _rangeValues.clear(); + _rangeColors.clear(); + _rangeOpacities.clear(); + _rangeIcons.clear(); + + if (_rangeType != NoRangeInfo) { + _rangeValues = { 0.0, 100.0 }; + } + for (int i=0; i<_rangeValues.count() + 1; i++) { + switch (_rangeType) { + case NoRangeInfo: + break; + case ColorRange: + _rangeColors.append(QColor("green")); + break; + case OpacityRange: + _rangeOpacities.append(1.0); + break; + case IconSelectRange: + _rangeIcons.append(_iconNames[0]); + break; + } + } + + emit rangeValuesChanged (_rangeValues); + emit rangeColorsChanged (_rangeColors); + emit rangeOpacitiesChanged (_rangeOpacities); + emit rangeIconsChanged (_rangeIcons); +} + +void InstrumentValue::addRangeValue(void) +{ + _rangeValues.append(_rangeValues.last().toDouble() + 1); + + switch (_rangeType) { + case NoRangeInfo: + break; + case ColorRange: + _rangeColors.append(QColor("green")); + break; + case OpacityRange: + _rangeOpacities.append(1.0); + break; + case IconSelectRange: + _rangeIcons.append(_iconNames[0]); + break; + } + + emit rangeValuesChanged (_rangeValues); + emit rangeColorsChanged (_rangeColors); + emit rangeOpacitiesChanged (_rangeOpacities); + emit rangeIconsChanged (_rangeIcons); +} + +void InstrumentValue::removeRangeValue(int index) +{ + if (_rangeValues.count() < 2 || index <0 || index >= _rangeValues.count()) { + return; + } + + _rangeValues.removeAt(index); + + switch (_rangeType) { + case NoRangeInfo: + break; + case ColorRange: + _rangeColors.removeAt(index + 1); + break; + case OpacityRange: + _rangeOpacities.removeAt(index + 1); + break; + case IconSelectRange: + _rangeIcons.removeAt(index + 1); + break; + } + + emit rangeValuesChanged (_rangeValues); + emit rangeColorsChanged (_rangeColors); + emit rangeOpacitiesChanged (_rangeOpacities); + emit rangeIconsChanged (_rangeIcons); +} diff --git a/src/FlightMap/Widgets/InstrumentValue.h b/src/FlightMap/Widgets/InstrumentValue.h new file mode 100644 index 000000000..6bda21b29 --- /dev/null +++ b/src/FlightMap/Widgets/InstrumentValue.h @@ -0,0 +1,173 @@ +/**************************************************************************** + * + * (c) 2009-2020 QGROUNDCONTROL PROJECT + * + * QGroundControl is licensed according to the terms in the file + * COPYING.md in the root of the source code directory. + * + ****************************************************************************/ + +#pragma once + +#include "FactSystem.h" +#include "QmlObjectListModel.h" +#include "QGCApplication.h" + +#include + +class InstrumentValue : public QObject +{ + Q_OBJECT + +public: + enum FontSize { + DefaultFontSize=0, + SmallFontSize, + MediumFontSize, + LargeFontSize, + }; + Q_ENUMS(FontSize) + + enum IconPosition { + IconAbove = 0, + IconLeft, + }; + Q_ENUMS(IconPosition) + + enum RangeType { + NoRangeInfo = 0, + ColorRange, + OpacityRange, + IconSelectRange, + }; + Q_ENUMS(RangeType) + + InstrumentValue(Vehicle* activeVehicle, FontSize fontSize, QmlObjectListModel* rowModel); + + Q_PROPERTY(QStringList factGroupNames MEMBER _factGroupNames NOTIFY factGroupNamesChanged) + Q_PROPERTY(QStringList factValueNames MEMBER _factValueNames NOTIFY factValueNamesChanged) + Q_PROPERTY(QString factGroupName MEMBER _factGroupName NOTIFY factGroupNameChanged) + Q_PROPERTY(QString factName MEMBER _factName NOTIFY factNameChanged) + Q_PROPERTY(Fact* fact READ fact NOTIFY factChanged) + Q_PROPERTY(QString label READ label WRITE setLabel NOTIFY labelChanged) + Q_PROPERTY(QString icon READ icon WRITE setIcon NOTIFY iconChanged) ///< If !isEmpty icon will be show instead of label + Q_PROPERTY(IconPosition iconPosition READ iconPosition WRITE setIconPosition NOTIFY iconPositionChanged) + Q_PROPERTY(QStringList iconPositionNames MEMBER _iconPositionNames CONSTANT) + Q_PROPERTY(QStringList iconNames MEMBER _iconNames CONSTANT) + Q_PROPERTY(FontSize fontSize READ fontSize WRITE setFontSize NOTIFY fontSizeChanged) + Q_PROPERTY(QStringList fontSizeNames MEMBER _fontSizeNames CONSTANT) + Q_PROPERTY(bool showUnits READ showUnits WRITE setShowUnits NOTIFY showUnitsChanged) + Q_PROPERTY(QStringList rangeTypeNames MEMBER _rangeTypeNames CONSTANT) + Q_PROPERTY(RangeType rangeType READ rangeType WRITE setRangeType NOTIFY rangeTypeChanged) + Q_PROPERTY(QVariantList rangeValues READ rangeValues WRITE setRangeValues NOTIFY rangeValuesChanged) + Q_PROPERTY(QVariantList rangeColors READ rangeColors WRITE setRangeColors NOTIFY rangeColorsChanged) + Q_PROPERTY(QVariantList rangeIcons READ rangeIcons WRITE setRangeIcons NOTIFY rangeIconsChanged) + Q_PROPERTY(QVariantList rangeOpacities READ rangeOpacities WRITE setRangeOpacities NOTIFY rangeOpacitiesChanged) + + Q_INVOKABLE void setFact (const QString& factGroupName, const QString& factName); + Q_INVOKABLE void clearFact (void); + Q_INVOKABLE bool isValidColor (const QColor& color) { return color.isValid(); } + Q_INVOKABLE QColor invalidColor (void) { return QColor(); } + Q_INVOKABLE void addRangeValue (void); + Q_INVOKABLE void removeRangeValue(int index); + + Fact* fact (void) { return _fact; } + FontSize fontSize (void) const { return _fontSize; } + QString label (void) const { return _label; } + bool showUnits (void) const { return _showUnits; } + QString icon (void) const { return _icon; } + IconPosition iconPosition (void) const { return _iconPosition; } + RangeType rangeType (void) const { return _rangeType; } + QVariantList rangeValues (void) const { return _rangeValues; } + QVariantList rangeColors (void) const { return _rangeColors; } + QVariantList rangeIcons (void) const { return _rangeIcons; } + QVariantList rangeOpacities (void) const { return _rangeOpacities; } + void setFontSize (FontSize fontSize); + void setLabel (const QString& label); + void setShowUnits (bool showUnits); + void setIcon (const QString& icon); + void setIconPosition (IconPosition iconPosition); + void setRangeType (RangeType rangeType); + void setRangeValues (const QVariantList& rangeValues); + void setRangeColors (const QVariantList& rangeColors); + void setRangeIcons (const QVariantList& rangeIcons); + void setRangeOpacities (const QVariantList& rangeOpacities); + void activeVehicleChanged (Vehicle* activeVehicle); + void saveToSettings (QSettings& settings) const; + void readFromSettings (const QSettings& settings); + +signals: + void factChanged (Fact* fact); + void factNameChanged (const QString& factName); + void factGroupNameChanged (const QString& factGroup); + void labelChanged (QString label); + void fontSizeChanged (FontSize fontSize); + void showUnitsChanged (bool showUnits); + void iconChanged (const QString& icon); + void iconPositionChanged (IconPosition iconPosition); + void factGroupNamesChanged (const QStringList& factGroupNames); + void factValueNamesChanged (const QStringList& factValueNames); + void rangeTypeChanged (RangeType rangeType); + void rangeValuesChanged (const QVariantList& rangeValues); + void rangeColorsChanged (const QVariantList& rangeColors); + void rangeIconsChanged (const QVariantList& rangeIcons); + void rangeOpacitiesChanged (const QVariantList& rangeOpacities); + +private slots: + void _resetRangeInfo (void); + +private: + void _setFontSize (FontSize fontSize); + + Vehicle* _activeVehicle = nullptr; + QmlObjectListModel* _rowModel = nullptr; + Fact* _fact = nullptr; + QString _factName; + QString _factGroupName; + QString _label; + bool _showUnits = true; + FontSize _fontSize = DefaultFontSize; + QString _icon; + IconPosition _iconPosition = IconLeft; + QStringList _factGroupNames; + QStringList _factValueNames; + + // Ranges allow you to specifiy semantics to apply when a value is within a certain range. + // The limits for each section of the range are specified in _rangeValues. With the first + // element indicating a range from that value to -infinity and the last element indicating + // a range from the value to +infinity. + // + // The semantics to apply are defined by the _rangeType value. With the semantic lists having + // a specific value for each section of the range. There should be _rangeValues.count() + 2 + // semantic values in the apppropriate list. + RangeType _rangeType = NoRangeInfo; + QVariantList _rangeValues; ///< double values which indicate range setpoints + QVariantList _rangeColors; ///< QColor + QVariantList _rangeIcons; ///< QString resource name + QVariantList _rangeOpacities; /// double opacity value + + // These are user facing string for the various enums. + static const QStringList _rangeTypeNames; + static const QStringList _iconPositionNames; + static QStringList _iconNames; + static const QStringList _fontSizeNames; + + static const char* _versionKey; + static const char* _factGroupNameKey; + static const char* _factNameKey; + static const char* _labelKey; + static const char* _fontSizeKey; + static const char* _showUnitsKey; + static const char* _iconKey; + static const char* _iconPositionKey; + static const char* _rangeTypeKey; + static const char* _rangeValuesKey; + static const char* _rangeColorsKey; + static const char* _rangeIconsKey; + static const char* _rangeOpacitiesKey; + static const char* _vehicleFactGroupName; +}; + +Q_DECLARE_METATYPE(InstrumentValue::FontSize) +Q_DECLARE_METATYPE(InstrumentValue::IconPosition) +Q_DECLARE_METATYPE(InstrumentValue::RangeType) diff --git a/src/FlightMap/Widgets/ValuePageWidget.qml b/src/FlightMap/Widgets/ValuePageWidget.qml index 19320257d..531a4aeaa 100644 --- a/src/FlightMap/Widgets/ValuePageWidget.qml +++ b/src/FlightMap/Widgets/ValuePageWidget.qml @@ -8,7 +8,7 @@ ****************************************************************************/ import QtQuick 2.12 -import QtQuick.Dialogs 1.2 +import QtQuick.Dialogs 1.3 import QtQuick.Layouts 1.2 import QtQuick.Controls 2.5 import QtQml 2.12 @@ -325,7 +325,9 @@ Column { onClicked: { _valueDialogInstrumentValue.label = "" _valueDialogInstrumentValue.icon = _valueDialogInstrumentValue.iconNames[0] - mainWindow.showPopupDialog(iconDialog, qsTr("Select Icon"), StandardButton.Close) + iconPickerDialogIcon = _valueDialogInstrumentValue.icon + iconPickerDialogUpdateIconFunction = function(icon){ _valueDialogInstrumentValue.icon = icon } + mainWindow.showPopupDialog(iconPickerDialog, qsTr("Select Icon"), StandardButton.Close) } } @@ -343,7 +345,11 @@ Column { MouseArea { anchors.fill: parent - onClicked: mainWindow.showPopupDialog(iconDialog, qsTr("Select Icon"), StandardButton.Close) + onClicked: { + iconPickerDialogIcon = _valueDialogInstrumentValue.icon + iconPickerDialogUpdateIconFunction = function(icon){ _valueDialogInstrumentValue.icon = icon } + mainWindow.showPopupDialog(iconPickerDialog, qsTr("Select Icon"), StandardButton.Close) + } } } @@ -378,7 +384,6 @@ Column { QGCComboBox { id: fontSizeCombo - Layout.columnSpan: 2 model: _valueDialogInstrumentValue.fontSizeNames currentIndex: _valueDialogInstrumentValue.fontSize sizeToContents: true @@ -386,19 +391,65 @@ Column { } QGCCheckBox { - Layout.columnSpan: 3 text: qsTr("Show Units") checked: _valueDialogInstrumentValue.showUnits onClicked: _valueDialogInstrumentValue.showUnits = checked } + + QGCLabel { text: qsTr("Range") } + + QGCComboBox { + id: rangeTypeCombo + Layout.columnSpan: 2 + model: _valueDialogInstrumentValue.rangeTypeNames + currentIndex: _valueDialogInstrumentValue.rangeType + sizeToContents: true + onActivated: _valueDialogInstrumentValue.rangeType = index + } + + Loader { + id: rangeLoader + Layout.columnSpan: 3 + Layout.fillWidth: true + Layout.preferredWidth: item ? item.width : 0 + Layout.preferredHeight: item ? item.height : 0 + + function updateSourceComponent() { + switch (_valueDialogInstrumentValue.rangeType) { + case InstrumentValue.NoRangeInfo: + sourceComponent = undefined + break + case InstrumentValue.ColorRange: + sourceComponent = colorRangeDialog + break + case InstrumentValue.OpacityRange: + sourceComponent = opacityRangeDialog + break + case InstrumentValue.IconSelectRange: + sourceComponent = iconRangeDialog + break + } + } + + Component.onCompleted: updateSourceComponent() + + Connections { + target: _valueDialogInstrumentValue + onRangeTypeChanged: rangeLoader.updateSourceComponent() + } + + } } } } + property string iconPickerDialogIcon + property var iconPickerDialogUpdateIconFunction Component { - id: iconDialog + id: iconPickerDialog QGCPopupDialog { + GridLayout { columns: 10 columnSpacing: 0 @@ -412,7 +463,7 @@ Column { width: height color: currentSelection ? qgcPal.text : qgcPal.window - property bool currentSelection: _valueDialogInstrumentValue.icon == modelData + property bool currentSelection: iconPickerDialogIcon == modelData QGCColoredImage { anchors.centerIn: parent @@ -428,7 +479,8 @@ Column { MouseArea { anchors.fill: parent onClicked: { - _valueDialogInstrumentValue.icon = modelData + iconPickerDialogIcon = modelData + iconPickerDialogUpdateIconFunction(modelData) hideDialog() } } @@ -438,4 +490,305 @@ Column { } } } + + Component { + id: colorRangeDialog + + Item { + width: childrenRect.width + height: childrenRect.height + + function updateRangeValue(index, text) { + var newValues = _valueDialogInstrumentValue.rangeValues + newValues[index] = parseFloat(text) + _valueDialogInstrumentValue.rangeValues = newValues + } + + function updateColorValue(index, color) { + var newColors = _valueDialogInstrumentValue.rangeColors + newColors[index] = color + _valueDialogInstrumentValue.rangeColors = newColors + } + + ColorDialog { + id: colorPickerDialog + modality: Qt.ApplicationModal + currentColor: _valueDialogInstrumentValue.rangeColors[colorIndex] + onAccepted: updateColorValue(colorIndex, color) + + property int colorIndex: 0 + } + + Column { + id: mainColumn + spacing: ScreenTools.defaultFontPixelHeight / 2 + + QGCLabel { + width: rowLayout.width + text: qsTr("Specify the color you want to apply based on value ranges. The color will be applied to the icon if available, otherwise to the value itself.") + wrapMode: Text.WordWrap + } + + Row { + id: rowLayout + spacing: _margins + + Column { + anchors.verticalCenter: parent.verticalCenter + spacing: _margins + + Repeater { + model: _valueDialogInstrumentValue.rangeValues.length + + QGCButton { + width: ScreenTools.implicitTextFieldHeight + height: width + text: qsTr("-") + onClicked: _valueDialogInstrumentValue.removeRangeValue(index) + } + } + } + + Column { + anchors.verticalCenter: parent.verticalCenter + spacing: _margins + + Repeater { + model: _valueDialogInstrumentValue.rangeValues.length + + QGCTextField { + text: _valueDialogInstrumentValue.rangeValues[index] + onEditingFinished: updateRangeValue(index, text) + } + } + } + + Column { + spacing: _margins + Repeater { + model: _valueDialogInstrumentValue.rangeColors + + QGCCheckBox { + height: ScreenTools.implicitTextFieldHeight + checked: _valueDialogInstrumentValue.isValidColor(_valueDialogInstrumentValue.rangeColors[index]) + onClicked: updateColorValue(index, checked ? "green" : _valueDialogInstrumentValue.invalidColor()) + } + } + } + + Column { + spacing: _margins + Repeater { + model: _valueDialogInstrumentValue.rangeColors + + Rectangle { + width: ScreenTools.implicitTextFieldHeight + height: width + border.color: qgcPal.text + color: _valueDialogInstrumentValue.isValidColor(modelData) ? modelData : qgcPal.text + + MouseArea { + anchors.fill: parent + onClicked: { + colorPickerDialog.colorIndex = index + colorPickerDialog.open() + } + } + } + } + } + } + + QGCButton { + text: qsTr("Add Row") + onClicked: _valueDialogInstrumentValue.addRangeValue() + } + } + } + } + + Component { + id: iconRangeDialog + + Item { + width: childrenRect.width + height: childrenRect.height + + function updateRangeValue(index, text) { + var newValues = _valueDialogInstrumentValue.rangeValues + newValues[index] = parseFloat(text) + _valueDialogInstrumentValue.rangeValues = newValues + } + + function updateIconValue(index, icon) { + var newIcons = _valueDialogInstrumentValue.rangeIcons + newIcons[index] = icon + _valueDialogInstrumentValue.rangeIcons = newIcons + } + + Column { + id: mainColumn + spacing: ScreenTools.defaultFontPixelHeight / 2 + + QGCLabel { + width: rowLayout.width + text: qsTr("Specify the icon you want to display based on value ranges.") + wrapMode: Text.WordWrap + } + + Row { + id: rowLayout + spacing: _margins + + Column { + anchors.verticalCenter: parent.verticalCenter + spacing: _margins + + Repeater { + model: _valueDialogInstrumentValue.rangeValues.length + + QGCButton { + width: ScreenTools.implicitTextFieldHeight + height: width + text: qsTr("-") + onClicked: _valueDialogInstrumentValue.removeRangeValue(index) + } + } + } + + Column { + anchors.verticalCenter: parent.verticalCenter + spacing: _margins + + Repeater { + model: _valueDialogInstrumentValue.rangeValues.length + + QGCTextField { + text: _valueDialogInstrumentValue.rangeValues[index] + onEditingFinished: updateRangeValue(index, text) + } + } + } + + Column { + spacing: _margins + + Repeater { + model: _valueDialogInstrumentValue.rangeIcons + + QGCColoredImage { + height: ScreenTools.implicitTextFieldHeight + width: height + source: "/InstrumentValueIcons/" + modelData + sourceSize.height: height + fillMode: Image.PreserveAspectFit + mipmap: true + smooth: true + color: qgcPal.text + + MouseArea { + anchors.fill: parent + onClicked: { + iconPickerDialogIcon = modelData + iconPickerDialogUpdateIconFunction = function(icon){ updateIconValue(index, icon) } + mainWindow.showPopupDialog(iconPickerDialog, qsTr("Select Icon"), StandardButton.Close) + } + } + } + } + } + } + + QGCButton { + text: qsTr("Add Row") + onClicked: _valueDialogInstrumentValue.addRangeValue() + } + } + } + } + + Component { + id: opacityRangeDialog + + Item { + width: childrenRect.width + height: childrenRect.height + + function updateRangeValue(index, text) { + var newValues = _valueDialogInstrumentValue.rangeValues + newValues[index] = parseFloat(text) + _valueDialogInstrumentValue.rangeValues = newValues + } + + function updateOpacityValue(index, opacity) { + var newOpacities = _valueDialogInstrumentValue.rangeOpacities + newOpacities[index] = opacity + _valueDialogInstrumentValue.rangeOpacities = newOpacities + } + + Column { + id: mainColumn + spacing: ScreenTools.defaultFontPixelHeight / 2 + + QGCLabel { + width: rowLayout.width + text: qsTr("Specify the icon opacity you want based on value ranges.") + wrapMode: Text.WordWrap + } + + Row { + id: rowLayout + spacing: _margins + + Column { + anchors.verticalCenter: parent.verticalCenter + spacing: _margins + + Repeater { + model: _valueDialogInstrumentValue.rangeValues.length + + QGCButton { + width: ScreenTools.implicitTextFieldHeight + height: width + text: qsTr("-") + onClicked: _valueDialogInstrumentValue.removeRangeValue(index) + } + } + } + + Column { + anchors.verticalCenter: parent.verticalCenter + spacing: _margins + + Repeater { + model: _valueDialogInstrumentValue.rangeValues + + QGCTextField { + text: modelData + onEditingFinished: updateRangeValue(index, text) + } + } + } + + Column { + spacing: _margins + + Repeater { + model: _valueDialogInstrumentValue.rangeOpacities + + QGCTextField { + text: modelData + onEditingFinished: updateOpacityValue(index, text) + } + } + } + } + + QGCButton { + text: qsTr("Add Row") + onClicked: _valueDialogInstrumentValue.addRangeValue() + } + } + } + } } diff --git a/src/FlightMap/Widgets/ValuesWidgetController.cc b/src/FlightMap/Widgets/ValuesWidgetController.cc index 9bff80ff8..65fb21d04 100644 --- a/src/FlightMap/Widgets/ValuesWidgetController.cc +++ b/src/FlightMap/Widgets/ValuesWidgetController.cc @@ -7,7 +7,6 @@ * ****************************************************************************/ - #include "ValuesWidgetController.h" #include "QGCApplication.h" #include "QGCCorePlugin.h" @@ -22,31 +21,6 @@ const char* ValuesWidgetController::_deprecatedGroupKey = "ValuesWidget" const char* ValuesWidgetController::_deprecatedLargeValuesKey = "large"; const char* ValuesWidgetController::_deprecatedSmallValuesKey = "small"; -const char* InstrumentValue::_factGroupNameKey = "groupName"; -const char* InstrumentValue::_factNameKey = "factName"; -const char* InstrumentValue::_labelKey = "label"; -const char* InstrumentValue::_fontSizeKey = "fontSize"; -const char* InstrumentValue::_showUnitsKey = "showUnits"; -const char* InstrumentValue::_iconKey = "icon"; -const char* InstrumentValue::_iconPositionKey = "iconPosition"; -const char* InstrumentValue::_vehicleFactGroupName = "Vehicle"; - -QStringList InstrumentValue::_iconNames; - -// Important: The indices of these strings must match the InstrumentValue::IconPosition enumconst QStringList InstrumentValue::_iconPositionNames = { -const QStringList InstrumentValue::_iconPositionNames = { - QT_TRANSLATE_NOOP("InstrumentValue", "Above"), - QT_TRANSLATE_NOOP("InstrumentValue", "Left"), -}; - -// Important: The indices of these strings must match the InstrumentValue::FontSize enum -const QStringList InstrumentValue::_fontSizeNames = { - QT_TRANSLATE_NOOP("InstrumentValue", "Default"), - QT_TRANSLATE_NOOP("InstrumentValue", "Small"), - QT_TRANSLATE_NOOP("InstrumentValue", "Medium"), - QT_TRANSLATE_NOOP("InstrumentValue", "Large"), -}; - ValuesWidgetController::ValuesWidgetController(bool forDefaultSettingsCreation) : _valuesModel(new QmlObjectListModel(this)) { @@ -64,13 +38,18 @@ ValuesWidgetController::ValuesWidgetController(bool forDefaultSettingsCreation) void ValuesWidgetController::_connectSignalsToController(InstrumentValue* value, ValuesWidgetController* controller) { - connect(value, &InstrumentValue::factNameChanged, controller, &ValuesWidgetController::_saveSettings); - connect(value, &InstrumentValue::factGroupNameChanged, controller, &ValuesWidgetController::_saveSettings); - connect(value, &InstrumentValue::labelChanged, controller, &ValuesWidgetController::_saveSettings); - connect(value, &InstrumentValue::fontSizeChanged, controller, &ValuesWidgetController::_saveSettings); - connect(value, &InstrumentValue::showUnitsChanged, controller, &ValuesWidgetController::_saveSettings); - connect(value, &InstrumentValue::iconChanged, controller, &ValuesWidgetController::_saveSettings); - connect(value, &InstrumentValue::iconPositionChanged, controller, &ValuesWidgetController::_saveSettings); + connect(value, &InstrumentValue::factNameChanged, controller, &ValuesWidgetController::_saveSettings); + connect(value, &InstrumentValue::factGroupNameChanged, controller, &ValuesWidgetController::_saveSettings); + connect(value, &InstrumentValue::labelChanged, controller, &ValuesWidgetController::_saveSettings); + connect(value, &InstrumentValue::fontSizeChanged, controller, &ValuesWidgetController::_saveSettings); + connect(value, &InstrumentValue::showUnitsChanged, controller, &ValuesWidgetController::_saveSettings); + connect(value, &InstrumentValue::iconChanged, controller, &ValuesWidgetController::_saveSettings); + connect(value, &InstrumentValue::iconPositionChanged, controller, &ValuesWidgetController::_saveSettings); + connect(value, &InstrumentValue::rangeTypeChanged, controller, &ValuesWidgetController::_saveSettings); + connect(value, &InstrumentValue::rangeValuesChanged, controller, &ValuesWidgetController::_saveSettings); + connect(value, &InstrumentValue::rangeColorsChanged, controller, &ValuesWidgetController::_saveSettings); + connect(value, &InstrumentValue::rangeOpacitiesChanged, controller, &ValuesWidgetController::_saveSettings); + connect(value, &InstrumentValue::rangeIconsChanged, controller, &ValuesWidgetController::_saveSettings); } InstrumentValue* ValuesWidgetController::_createNewInstrumentValueWorker(Vehicle* activeVehicle, InstrumentValue::FontSize fontSize, QmlObjectListModel* rowModel) @@ -341,196 +320,3 @@ QString ValuesWidgetController::_pascalCase(const QString& text) { return text[0].toUpper() + text.right(text.length() - 1); } - -InstrumentValue::InstrumentValue(Vehicle* activeVehicle, FontSize fontSize, QmlObjectListModel* rowModel) - : QObject (rowModel) - , _activeVehicle(activeVehicle) - , _rowModel (rowModel) - , _fontSize (fontSize) -{ - if (_iconNames.isEmpty()) { - QDir iconDir(":/InstrumentValueIcons/"); - _iconNames = iconDir.entryList(); - } - - activeVehicleChanged(_activeVehicle); -} - -void InstrumentValue::activeVehicleChanged(Vehicle* activeVehicle) -{ - _activeVehicle = activeVehicle; - - _factGroupNames.clear(); - _factGroupNames = _activeVehicle->factGroupNames(); - for (QString& name: _factGroupNames) { - name[0] = name[0].toUpper(); - } - _factGroupNames.prepend(_vehicleFactGroupName); - emit factGroupNamesChanged(_factGroupNames); - - if (_fact) { - _fact = nullptr; - - FactGroup* factGroup = nullptr; - if (_factGroupName == _vehicleFactGroupName) { - factGroup = _activeVehicle; - } else { - factGroup = _activeVehicle->getFactGroup(_factGroupName); - } - - if (factGroup) { - _fact = factGroup->getFact(_factName); - } - emit factChanged(_fact); - } -} - -void InstrumentValue::setFact(const QString& factGroupName, const QString& factName) -{ - if (_fact) { - _fact = nullptr; - } - - FactGroup* factGroup = nullptr; - if (factGroupName == _vehicleFactGroupName) { - factGroup = _activeVehicle; - } else { - factGroup = _activeVehicle->getFactGroup(factGroupName); - } - - _factValueNames.clear(); - _factValueNames = factGroup->factNames(); - for (QString& name: _factValueNames) { - name[0] = name[0].toUpper(); - } - - QString nonEmptyFactName; - if (factGroup) { - if (factName.isEmpty()) { - nonEmptyFactName = _factValueNames[0]; - } else { - nonEmptyFactName = factName; - } - _fact = factGroup->getFact(nonEmptyFactName); - } - - if (_fact) { - _factGroupName = factGroupName; - _factName = nonEmptyFactName; - } else { - _factName.clear(); - _factGroupName.clear(); - } - - emit factChanged (_fact); - emit factNameChanged (_factName); - emit factGroupNameChanged (_factGroupName); - emit factValueNamesChanged (_factValueNames); -} - -void InstrumentValue::_setFontSize(FontSize fontSize) -{ - if (fontSize != _fontSize) { - _fontSize = fontSize; - emit fontSizeChanged(fontSize); - } -} - -void InstrumentValue::setFontSize(FontSize fontSize) -{ - _setFontSize(fontSize); - - // All other items in row must change to match - for (int i=0; i<_rowModel->count(); i++) { - InstrumentValue* instrumentValue = _rowModel->value(i); - if (instrumentValue != this) { - instrumentValue->_setFontSize(fontSize); - } - } -} - -void InstrumentValue::saveToSettings(QSettings& settings) const -{ - if (_fact) { - settings.setValue(_factGroupNameKey, _factGroupName); - settings.setValue(_factNameKey, _factName); - } else { - settings.setValue(_factGroupNameKey, ""); - settings.setValue(_factNameKey, ""); - } - settings.setValue(_labelKey, _label); - settings.setValue(_fontSizeKey, _fontSize); - settings.setValue(_showUnitsKey, _showUnits); - settings.setValue(_iconKey, _icon); - settings.setValue(_iconPositionKey, _iconPosition); -} - -void InstrumentValue::readFromSettings(const QSettings& settings) -{ - _factGroupName = settings.value(_factGroupNameKey).toString(); - _label = settings.value(_labelKey).toString(); - _fontSize = settings.value(_fontSizeKey, DefaultFontSize).value(); - _showUnits = settings.value(_showUnitsKey, true).toBool(); - _icon = settings.value(_iconKey).toString(); - _iconPosition = settings.value(_iconPositionKey, IconLeft).value(); - - QString factName = settings.value(_factNameKey).toString(); - if (!factName.isEmpty()) { - setFact(_factGroupName, factName); - } - - emit factChanged (_fact); - emit factGroupNameChanged (_factGroupName); - emit labelChanged (_label); - emit fontSizeChanged (_fontSize); - emit showUnitsChanged (_showUnits); - emit iconChanged (_icon); - emit iconPositionChanged (_iconPosition); -} - -void InstrumentValue::setLabel(const QString& label) -{ - if (label != _label) { - _label = label; - emit labelChanged(label); - } -} - -void InstrumentValue::setShowUnits(bool showUnits) -{ - if (showUnits != _showUnits) { - _showUnits = showUnits; - emit showUnitsChanged(showUnits); - } -} - -void InstrumentValue::clearFact(void) -{ - _fact = nullptr; - _factGroupName.clear(); - _label.clear(); - _icon.clear(); - _showUnits = true; - - emit factChanged (_fact); - emit factGroupNameChanged (_factGroupName); - emit labelChanged (_label); - emit iconChanged (_icon); - emit showUnitsChanged (_showUnits); -} - -void InstrumentValue::setIcon(const QString& icon) -{ - if (icon != _icon) { - _icon = icon; - emit iconChanged(_icon); - } -} - -void InstrumentValue::setIconPosition(IconPosition iconPosition) -{ - if (iconPosition != _iconPosition) { - _iconPosition = iconPosition; - emit iconPositionChanged(iconPosition); - } -} diff --git a/src/FlightMap/Widgets/ValuesWidgetController.h b/src/FlightMap/Widgets/ValuesWidgetController.h index 60126940f..2965e5541 100644 --- a/src/FlightMap/Widgets/ValuesWidgetController.h +++ b/src/FlightMap/Widgets/ValuesWidgetController.h @@ -12,109 +12,10 @@ #include "FactSystem.h" #include "QmlObjectListModel.h" #include "QGCApplication.h" +#include "InstrumentValue.h" #include -class ValuesWidgetController; - -class InstrumentValue : public QObject -{ - Q_OBJECT - -public: - enum FontSize { - DefaultFontSize=0, - SmallFontSize, - MediumFontSize, - LargeFontSize - }; - Q_ENUMS(FontSize) - - enum IconPosition { - IconAbove = 0, - IconLeft - }; - Q_ENUMS(IconPosition) - - InstrumentValue(Vehicle* activeVehicle, FontSize fontSize, QmlObjectListModel* rowModel); - - Q_PROPERTY(QStringList factGroupNames MEMBER _factGroupNames NOTIFY factGroupNamesChanged) - Q_PROPERTY(QStringList factValueNames MEMBER _factValueNames NOTIFY factValueNamesChanged) - Q_PROPERTY(QString factGroupName MEMBER _factGroupName NOTIFY factGroupNameChanged) - Q_PROPERTY(QString factName MEMBER _factName NOTIFY factNameChanged) - Q_PROPERTY(Fact* fact READ fact NOTIFY factChanged) - Q_PROPERTY(QString label READ label WRITE setLabel NOTIFY labelChanged) - Q_PROPERTY(QString icon READ icon WRITE setIcon NOTIFY iconChanged) ///< If !isEmpty icon will be show instead of label - Q_PROPERTY(IconPosition iconPosition READ iconPosition WRITE setIconPosition NOTIFY iconPositionChanged) - Q_PROPERTY(QStringList iconPositionNames MEMBER _iconPositionNames CONSTANT) - Q_PROPERTY(QStringList iconNames MEMBER _iconNames CONSTANT) - Q_PROPERTY(FontSize fontSize READ fontSize WRITE setFontSize NOTIFY fontSizeChanged) - Q_PROPERTY(QStringList fontSizeNames MEMBER _fontSizeNames CONSTANT) - Q_PROPERTY(bool showUnits READ showUnits WRITE setShowUnits NOTIFY showUnitsChanged) - - Q_INVOKABLE void setFact(const QString& factGroupName, const QString& factName); - Q_INVOKABLE void clearFact(void); - - Fact* fact (void) { return _fact; } - FontSize fontSize (void) const { return _fontSize; } - QString label (void) const { return _label; } - bool showUnits (void) const { return _showUnits; } - QString icon (void) const { return _icon; } - IconPosition iconPosition (void) const { return _iconPosition; } - void setFontSize (FontSize fontSize); - void setLabel (const QString& label); - void setShowUnits (bool showUnits); - void setIcon (const QString& icon); - void setIconPosition (IconPosition iconPosition); - void activeVehicleChanged (Vehicle* activeVehicle); - void saveToSettings (QSettings& settings) const; - void readFromSettings (const QSettings& settings); - -signals: - void factChanged (Fact* fact); - void factNameChanged (const QString& factName); - void factGroupNameChanged (const QString& factGroup); - void labelChanged (QString label); - void fontSizeChanged (FontSize fontSize); - void showUnitsChanged (bool showUnits); - void iconChanged (const QString& icon); - void iconPositionChanged (IconPosition iconPosition); - void factGroupNamesChanged (const QStringList& factGroupNames); - void factValueNamesChanged (const QStringList& factValueNames); - -private: - void _setFontSize (FontSize fontSize); - - Vehicle* _activeVehicle = nullptr; - QmlObjectListModel* _rowModel = nullptr; - Fact* _fact = nullptr; - QString _factName; - QString _factGroupName; - QString _label; - bool _showUnits = true; - FontSize _fontSize = DefaultFontSize; - QString _icon; - IconPosition _iconPosition = IconLeft; - QStringList _factGroupNames; - QStringList _factValueNames; - - static const QStringList _iconPositionNames; - static QStringList _iconNames; - static const QStringList _fontSizeNames; - - static const char* _factGroupNameKey; - static const char* _factNameKey; - static const char* _labelKey; - static const char* _fontSizeKey; - static const char* _showUnitsKey; - static const char* _iconKey; - static const char* _iconPositionKey; - static const char* _vehicleFactGroupName; -}; - -Q_DECLARE_METATYPE(InstrumentValue::FontSize) -Q_DECLARE_METATYPE(InstrumentValue::IconPosition) - class ValuesWidgetController : public QObject { Q_OBJECT diff --git a/src/QmlControls/QGCPopupDialogContainer.qml b/src/QmlControls/QGCPopupDialogContainer.qml index 4a2b6d665..c9441d85f 100644 --- a/src/QmlControls/QGCPopupDialogContainer.qml +++ b/src/QmlControls/QGCPopupDialogContainer.qml @@ -156,9 +156,9 @@ Popup { } Item { - id: item - width: dialogComponentLoader.width + (_contentMargin * 2) - height: dialogComponentLoader.height + _contentMargin + id: item + Layout.preferredWidth: dialogComponentLoader.width + (_contentMargin * 2) + Layout.preferredHeight: dialogComponentLoader.height + _contentMargin Loader { id: dialogComponentLoader -- 2.22.0