diff --git a/qgroundcontrol.qrc b/qgroundcontrol.qrc index e3e0b17..bf57edb 100644 --- a/qgroundcontrol.qrc +++ b/qgroundcontrol.qrc @@ -138,6 +138,7 @@ <file alias="QGroundControl/FactControls/FactTextField.qml">src/FactSystem/FactControls/FactTextField.qml</file> <file alias="QGroundControl/FactControls/FactTextFieldGrid.qml">src/FactSystem/FactControls/FactTextFieldGrid.qml</file> <file alias="QGroundControl/FactControls/FactTextFieldRow.qml">src/FactSystem/FactControls/FactTextFieldRow.qml</file> + <file alias="QGroundControl/FactControls/FactValueSlider.qml">src/FactSystem/FactControls/FactValueSlider.qml</file> <file alias="QGroundControl/FactControls/qmldir">src/FactSystem/FactControls/qmldir</file> <file alias="QGroundControl/FlightDisplay/FlightDisplayView.qml">src/FlightDisplay/FlightDisplayView.qml</file> <file alias="QGroundControl/FlightDisplay/FlightDisplayViewMap.qml">src/FlightDisplay/FlightDisplayViewMap.qml</file> diff --git a/src/AutoPilotPlugins/PX4/PX4TuningComponentCopter.qml b/src/AutoPilotPlugins/PX4/PX4TuningComponentCopter.qml index d3d8782..2b780bf 100644 --- a/src/AutoPilotPlugins/PX4/PX4TuningComponentCopter.qml +++ b/src/AutoPilotPlugins/PX4/PX4TuningComponentCopter.qml @@ -32,6 +32,11 @@ SetupPage { showAdvanced = !ScreenTools.isMobile } + FactPanelController { + id: controller + factPanel: tuningPage.viewPanel + } + // Standard tuning page FactSliderPanel { width: availableWidth @@ -238,11 +243,6 @@ SetupPage { resetGraphs() } - FactPanelController { - id: controller - factPanel: tuningPage.viewPanel - } - ExclusiveGroup { id: tuneTypeRadios } diff --git a/src/AutoPilotPlugins/PX4/PX4TuningComponentVTOL.qml b/src/AutoPilotPlugins/PX4/PX4TuningComponentVTOL.qml index 3feb7ca..297f175 100644 --- a/src/AutoPilotPlugins/PX4/PX4TuningComponentVTOL.qml +++ b/src/AutoPilotPlugins/PX4/PX4TuningComponentVTOL.qml @@ -27,24 +27,6 @@ SetupPage { sliderModel: ListModel { ListElement { - title: qsTr("Hover Roll sensitivity") - description: qsTr("Slide to the left to make roll control during hover faster and more accurate. Slide to the right if roll oscillates or is too twitchy.") - param: "MC_ROLL_TC" - min: 0.15 - max: 0.25 - step: 0.01 - } - - ListElement { - title: qsTr("Hover Pitch sensitivity") - description: qsTr("Slide to the left to make pitch control during hover faster and more accurate. Slide to the right if pitch oscillates or is too twitchy.") - param: "MC_PITCH_TC" - min: 0.15 - max: 0.25 - step: 0.01 - } - - ListElement { title: qsTr("Plane Roll sensitivity") description: qsTr("Slide to the left to make roll control faster and more accurate. Slide to the right if roll oscillates or is too twitchy.") param: "FW_R_TC" diff --git a/src/FactSystem/Fact.cc b/src/FactSystem/Fact.cc index 3afce17..309b3fd 100644 --- a/src/FactSystem/Fact.cc +++ b/src/FactSystem/Fact.cc @@ -643,6 +643,16 @@ double Fact::increment(void) const return std::numeric_limits<double>::quiet_NaN(); } +double Fact::cookedIncrement(void) const +{ + if (_metaData) { + return _metaData->cookedIncrement(); + } else { + qWarning() << kMissingMetadata << name(); + } + return std::numeric_limits<double>::quiet_NaN(); +} + bool Fact::hasControl(void) const { if (_metaData) { diff --git a/src/FactSystem/Fact.h b/src/FactSystem/Fact.h index cc0336e..6257bb3 100644 --- a/src/FactSystem/Fact.h +++ b/src/FactSystem/Fact.h @@ -66,7 +66,7 @@ public: Q_PROPERTY(bool valueEqualsDefault READ valueEqualsDefault NOTIFY valueChanged) Q_PROPERTY(QString valueString READ cookedValueString NOTIFY valueChanged) Q_PROPERTY(QString enumOrValueString READ enumOrValueString NOTIFY valueChanged) - Q_PROPERTY(double increment READ increment CONSTANT) + Q_PROPERTY(double increment READ cookedIncrement CONSTANT) Q_PROPERTY(bool typeIsString READ typeIsString CONSTANT) Q_PROPERTY(bool typeIsBool READ typeIsBool CONSTANT) Q_PROPERTY(bool hasControl READ hasControl CONSTANT) @@ -116,6 +116,7 @@ public: bool rebootRequired (void) const; QString enumOrValueString (void); // This is not const, since an unknown value can modify the enum lists double increment (void) const; + double cookedIncrement (void) const; bool typeIsString (void) const { return type() == FactMetaData::valueTypeString; } bool typeIsBool (void) const { return type() == FactMetaData::valueTypeBool; } bool hasControl (void) const; diff --git a/src/FactSystem/FactControls/FactValueSlider.qml b/src/FactSystem/FactControls/FactValueSlider.qml new file mode 100644 index 0000000..f94db51 --- /dev/null +++ b/src/FactSystem/FactControls/FactValueSlider.qml @@ -0,0 +1,134 @@ +import QtQuick 2.3 +import QtQuick.Controls 1.2 + +import QGroundControl.Palette 1.0 +import QGroundControl.ScreenTools 1.0 +import QGroundControl.Controls 1.0 +import QGroundControl.FactSystem 1.0 + +Rectangle { + height: _itemHeight + width: _totalSlots * _itemWidth + color: qgcPal.textField + + property Fact fact: undefined + property int digitCount: 4 ///< The number of digits to show for each value + property int incrementSlots: 1 ///< The number of visible slots to left/right of center value + + property int _totalDigitCount: digitCount + 1 + fact.units.length + property real _margins: (ScreenTools.implicitTextFieldHeight - ScreenTools.defaultFontPixelHeight) / 2 + property real _increment: fact.increment + property real _value: fact.value + property int _decimalPlaces: fact.decimalPlaces + property string _units: fact.units + property real _prevValue: _value - _increment + property real _nextValue: _value + _increment + property real _itemWidth: (_totalDigitCount * ScreenTools.defaultFontPixelWidth) + (_margins * 2) + property real _itemHeight: ScreenTools.implicitTextFieldHeight + property var _valueModel + property int _totalSlots: (incrementSlots * 2) + 1 + property int _currentIndex: _totalSlots / 2 + property int _currentRelativeIndex: _currentIndex + property int _prevIncrementSlots: incrementSlots + property int _nextIncrementSlots: incrementSlots + property int _selectionWidth: 3 + + QGCPalette { id: qgcPal; colorGroupEnabled: parent.enabled } + QGCPalette { id: qgcPalDisabled; colorGroupEnabled: false } + + function firstVisibleIndex() { + return valueListView.contentX / _itemWidth + } + + function recalcRelativeIndex() { + _currentRelativeIndex = _currentIndex - firstVisibleIndex() + _prevIncrementSlots = _currentRelativeIndex + _nextIncrementSlots = _totalSlots - _currentRelativeIndex - 1 + } + + Component.onCompleted: { + var currentValue = _value + _valueModel = [ _value.toFixed(_decimalPlaces) ] + + var addCount = 0 + var minValue = fact.min + currentValue -= _increment + while (currentValue >= minValue) { + _valueModel.unshift(currentValue.toFixed(_decimalPlaces)) + currentValue -= _increment + addCount++ + } + + var maxValue = fact.max + currentValue = _value + _increment + while (currentValue <= maxValue) { + _valueModel.push(currentValue.toFixed(_decimalPlaces)) + currentValue += _increment + } + + _currentIndex = addCount + valueListView.model = _valueModel + valueListView.positionViewAtIndex(_currentIndex, ListView.Center) + recalcRelativeIndex() + } + + QGCListView { + id: valueListView + anchors.fill: parent + orientation: ListView.Horizontal + snapMode: ListView.SnapToItem + clip: true + + delegate: QGCLabel { + width: _itemWidth + height: _itemHeight + verticalAlignment: Text.AlignVCenter + horizontalAlignment: Text.AlignHCenter + text: modelData + " " + _units + color: qgcPal.textFieldText + + MouseArea { + anchors.fill: parent + onClicked: { + _currentIndex = index + valueListView.positionViewAtIndex(_currentIndex, ListView.Center) + recalcRelativeIndex() + fact.value = valueListView.model[_currentIndex] + } + } + } + + onMovementEnded: { + _currentIndex = firstVisibleIndex() + _currentRelativeIndex + fact.value = model[_currentIndex] + } + } + + Rectangle { + id: leftOverlay + width: _itemWidth * _prevIncrementSlots + height: _itemHeight + color: qgcPal.textField + opacity: 0.5 + } + + Rectangle { + width: _itemWidth * _nextIncrementSlots + height: _itemHeight + anchors.right: parent.right + color: qgcPal.textField + opacity: 0.5 + } + + Rectangle { + x: _currentRelativeIndex * _itemWidth - _borderWidth + y: -_borderWidth + width: _itemWidth + (_borderWidth * 2) + height: _itemHeight + (_borderWidth * 2) + border.width: _borderWidth + border.color: qgcPal.brandingBlue + color: "transparent" + + readonly property int _borderWidth: 3 + } +} diff --git a/src/FactSystem/FactControls/qmldir b/src/FactSystem/FactControls/qmldir index 6bf7d23..02efebb 100644 --- a/src/FactSystem/FactControls/qmldir +++ b/src/FactSystem/FactControls/qmldir @@ -8,3 +8,4 @@ FactPanel 1.0 FactPanel.qml FactTextField 1.0 FactTextField.qml FactTextFieldGrid 1.0 FactTextFieldGrid.qml FactTextFieldRow 1.0 FactTextFieldRow.qml +FactValueSlider 1.0 FactValueSlider.qml diff --git a/src/FactSystem/FactMetaData.cc b/src/FactSystem/FactMetaData.cc index 167c681..b726c60 100644 --- a/src/FactSystem/FactMetaData.cc +++ b/src/FactSystem/FactMetaData.cc @@ -973,6 +973,11 @@ QString FactMetaData::appSettingsAreaUnitsString(void) } } +double FactMetaData::cookedIncrement(void) const +{ + return _rawTranslator(this->increment()).toDouble(); +} + int FactMetaData::decimalPlaces(void) const { int actualDecimalPlaces = defaultDecimalPlaces; diff --git a/src/FactSystem/FactMetaData.h b/src/FactSystem/FactMetaData.h index 4b298ca..8f99bb3 100644 --- a/src/FactSystem/FactMetaData.h +++ b/src/FactSystem/FactMetaData.h @@ -112,6 +112,7 @@ public: /// Amount to increment value when used in controls such as spin button or slider with detents. /// NaN for no increment available. double increment (void) const { return _increment; } + double cookedIncrement (void) const; Translator rawTranslator (void) const { return _rawTranslator; } Translator cookedTranslator (void) const { return _cookedTranslator; } diff --git a/src/QmlControls/FactSliderPanel.qml b/src/QmlControls/FactSliderPanel.qml index 98f037c..ac4cc10 100644 --- a/src/QmlControls/FactSliderPanel.qml +++ b/src/QmlControls/FactSliderPanel.qml @@ -41,18 +41,6 @@ Column { QGCPalette { id: palette; colorGroupEnabled: enabled } - Component.onCompleted: { - // Qml Sliders have a strange behavior in which they first set Slider::value to some internal - // setting and then set Slider::value to the bound properties value. If you have an onValueChanged - // handler which updates your property with the new value, this first value change will trash - // your bound values. In order to work around this we don't set the values into the Sliders until - // after Qml load is done. We also don't track value changes until Qml load completes. - for (var i=0; i<sliderModel.count; i++) { - sliderRepeater.itemAt(i).sliderValue = controller.getParameterFact(-1, sliderModel.get(i).param).value - } - _loadComplete = true - } - Column { id: sliderOuterColumn anchors.left: parent.left @@ -70,54 +58,31 @@ Column { height: sliderColumn.y + sliderColumn.height + _margins color: palette.windowShade - property alias sliderValue: slider.value - Column { id: sliderColumn anchors.margins: _margins anchors.left: parent.left anchors.right: parent.right anchors.top: sliderRect.top + spacing: _margins QGCLabel { text: title font.family: ScreenTools.demiboldFontFamily } + FactValueSlider { + digitCount: fact.maxString.length + incrementSlots: 3 + fact: controller.getParameterFact(-1, param) + } + QGCLabel { text: description anchors.left: parent.left anchors.right: parent.right wrapMode: Text.WordWrap } - - Slider { - id: slider - anchors.left: parent.left - anchors.right: parent.right - minimumValue: min - maximumValue: max - stepSize: isNaN(fact.increment) ? step : fact.increment - tickmarksEnabled: true - activeFocusOnPress: true - - property Fact fact: controller.getParameterFact(-1, param) - - onValueChanged: { - if (_loadComplete) { - fact.value = value - } - } - - // Block wheel events - MouseArea { - anchors.fill: parent - acceptedButtons: Qt.NoButton - onWheel: { - wheel.accepted = true - } - } - } // Slider } // Column } // Rectangle } // Repeater