diff --git a/qgroundcontrol.qrc b/qgroundcontrol.qrc
index e3e0b17f03ec774a1b7620674f2b9a65e967f25f..bf57edb25869f8b7509718a723e229ae89b3b8f6 100644
--- a/qgroundcontrol.qrc
+++ b/qgroundcontrol.qrc
@@ -138,6 +138,7 @@
src/FactSystem/FactControls/FactTextField.qml
src/FactSystem/FactControls/FactTextFieldGrid.qml
src/FactSystem/FactControls/FactTextFieldRow.qml
+ src/FactSystem/FactControls/FactValueSlider.qml
src/FactSystem/FactControls/qmldir
src/FlightDisplay/FlightDisplayView.qml
src/FlightDisplay/FlightDisplayViewMap.qml
diff --git a/src/AutoPilotPlugins/PX4/PX4TuningComponentCopter.qml b/src/AutoPilotPlugins/PX4/PX4TuningComponentCopter.qml
index d3d87822806636510fefe1034468d461cfbc1a8e..2b780bf0842cb88a46bc4e30785865fd71eca576 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 3feb7ca67e7c0c25474fb51ccc0a3244b15d1ea4..297f175b3fa9a3ed3f5db70e8b690458f6d131bf 100644
--- a/src/AutoPilotPlugins/PX4/PX4TuningComponentVTOL.qml
+++ b/src/AutoPilotPlugins/PX4/PX4TuningComponentVTOL.qml
@@ -26,24 +26,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.")
diff --git a/src/FactSystem/Fact.cc b/src/FactSystem/Fact.cc
index 3afce178fd287c5a40d106ffde28be1d9a1b8c1d..309b3fd0fbeffddbcb13d63ab5d15d85fd3e19a8 100644
--- a/src/FactSystem/Fact.cc
+++ b/src/FactSystem/Fact.cc
@@ -643,6 +643,16 @@ double Fact::increment(void) const
return std::numeric_limits::quiet_NaN();
}
+double Fact::cookedIncrement(void) const
+{
+ if (_metaData) {
+ return _metaData->cookedIncrement();
+ } else {
+ qWarning() << kMissingMetadata << name();
+ }
+ return std::numeric_limits::quiet_NaN();
+}
+
bool Fact::hasControl(void) const
{
if (_metaData) {
diff --git a/src/FactSystem/Fact.h b/src/FactSystem/Fact.h
index cc0336ee80de34e289b58ae89fc77d5a51bc86c5..6257bb399143c22a667cc6088a4386b5fb0b403b 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 0000000000000000000000000000000000000000..f94db519768d33f21d0c6d9714f159b85d6d6373
--- /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 6bf7d2359c1bfc007565d9bea2571d2754b128a5..02efebba4da263b96e4b77562d843e954197717e 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 167c68101f4ef653021a07b11cdd00eacbbf03b3..b726c6038dbcad382a69eb9854423194984fdf9a 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 4b298ca2422b2407b6b9c3b0fc5e814fc48756f8..8f99bb3f40b5957faad7a7fb8dfa2ed95792eef2 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 98f037ca1b9f529b3aa209ea95504eabd4c78bf7..ac4cc10d722d69cda79475f30eefd20087e0eca9 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