From ecc71b4479244bae8f1b8d45a342f882ce078525 Mon Sep 17 00:00:00 2001 From: Nyall Dawson Date: Thu, 14 Mar 2024 14:54:43 +1000 Subject: [PATCH] Add fixed range width option to QgsElevationControllerWidget --- .../qgselevationcontrollerwidget.sip.in | 18 ++++++++++ .../qgselevationcontrollerwidget.sip.in | 18 ++++++++++ .../qgselevationcontrollerwidget.cpp | 36 ++++++++++++++++++- .../elevation/qgselevationcontrollerwidget.h | 19 ++++++++++ .../test_qgselevationcontrollerwidget.py | 14 ++++++++ 5 files changed, 104 insertions(+), 1 deletion(-) diff --git a/python/PyQt6/gui/auto_generated/elevation/qgselevationcontrollerwidget.sip.in b/python/PyQt6/gui/auto_generated/elevation/qgselevationcontrollerwidget.sip.in index 4e13daf0fb3..b56b575fa87 100644 --- a/python/PyQt6/gui/auto_generated/elevation/qgselevationcontrollerwidget.sip.in +++ b/python/PyQt6/gui/auto_generated/elevation/qgselevationcontrollerwidget.sip.in @@ -59,6 +59,15 @@ Returns a reference to the slider component of the widget. %Docstring Returns a reference to the widget's configuration menu, which can be used to add actions to the menu. +%End + + double fixedRangeWidth() const; +%Docstring +Returns the fixed range width, or -1 if no fixed width is set. + +A fixed width forces the selected elevation range to have a matching width. + +.. seealso:: :py:func:`setFixedRangeWidth` %End public slots: @@ -77,6 +86,15 @@ Sets the current visible ``range`` for the widget. Sets the limits of the elevation range which can be selected by the widget. .. seealso:: :py:func:`rangeLimits` +%End + + void setFixedRangeWidth( double width ); +%Docstring +Sets the fixed range ``width``. Set to -1 if no fixed width is desired. + +A fixed width forces the selected elevation range to have a matching width. + +.. seealso:: :py:func:`fixedRangeWidth` %End signals: diff --git a/python/gui/auto_generated/elevation/qgselevationcontrollerwidget.sip.in b/python/gui/auto_generated/elevation/qgselevationcontrollerwidget.sip.in index 4e13daf0fb3..b56b575fa87 100644 --- a/python/gui/auto_generated/elevation/qgselevationcontrollerwidget.sip.in +++ b/python/gui/auto_generated/elevation/qgselevationcontrollerwidget.sip.in @@ -59,6 +59,15 @@ Returns a reference to the slider component of the widget. %Docstring Returns a reference to the widget's configuration menu, which can be used to add actions to the menu. +%End + + double fixedRangeWidth() const; +%Docstring +Returns the fixed range width, or -1 if no fixed width is set. + +A fixed width forces the selected elevation range to have a matching width. + +.. seealso:: :py:func:`setFixedRangeWidth` %End public slots: @@ -77,6 +86,15 @@ Sets the current visible ``range`` for the widget. Sets the limits of the elevation range which can be selected by the widget. .. seealso:: :py:func:`rangeLimits` +%End + + void setFixedRangeWidth( double width ); +%Docstring +Sets the fixed range ``width``. Set to -1 if no fixed width is desired. + +A fixed width forces the selected elevation range to have a matching width. + +.. seealso:: :py:func:`fixedRangeWidth` %End signals: diff --git a/src/gui/elevation/qgselevationcontrollerwidget.cpp b/src/gui/elevation/qgselevationcontrollerwidget.cpp index 09bc0480a71..b9abca42d17 100644 --- a/src/gui/elevation/qgselevationcontrollerwidget.cpp +++ b/src/gui/elevation/qgselevationcontrollerwidget.cpp @@ -102,7 +102,20 @@ QgsDoubleRange QgsElevationControllerWidget::range() const if ( snappedLower == mSlider->lowerValue() && snappedUpper == mSlider->upperValue() ) return mCurrentRange; - return QgsDoubleRange( mSlider->lowerValue() / mSliderPrecision, mSlider->upperValue() / mSliderPrecision ); + const QgsDoubleRange sliderRange( mSlider->lowerValue() / mSliderPrecision, mSlider->upperValue() / mSliderPrecision ); + if ( mFixedRangeWidth >= 0 ) + { + // adjust range so that it has exactly the fixed width (given slider int precision the slider range + // will not have the exact fixed width) + if ( sliderRange.upper() + mFixedRangeWidth <= mRangeLimits.upper() ) + return QgsDoubleRange( sliderRange.lower(), sliderRange.lower() + mFixedRangeWidth ); + else + return QgsDoubleRange( sliderRange.upper() - mFixedRangeWidth, sliderRange.upper() ); + } + else + { + return sliderRange; + } } QgsDoubleRange QgsElevationControllerWidget::rangeLimits() const @@ -180,6 +193,27 @@ void QgsElevationControllerWidget::updateWidgetMask() setMask( reg ); } +double QgsElevationControllerWidget::fixedRangeWidth() const +{ + return mFixedRangeWidth; +} + +void QgsElevationControllerWidget::setFixedRangeWidth( double width ) +{ + if ( width == mFixedRangeWidth ) + return; + + mFixedRangeWidth = width; + if ( mFixedRangeWidth < 0 ) + { + mSlider->setFixedRangeWidth( -1 ); + } + else + { + mSlider->setFixedRangeWidth( static_cast< int >( std::round( mFixedRangeWidth * mSliderPrecision ) ) ); + } +} + // // QgsElevationControllerLabels // diff --git a/src/gui/elevation/qgselevationcontrollerwidget.h b/src/gui/elevation/qgselevationcontrollerwidget.h index d308c2a4827..425538a756f 100644 --- a/src/gui/elevation/qgselevationcontrollerwidget.h +++ b/src/gui/elevation/qgselevationcontrollerwidget.h @@ -97,6 +97,15 @@ class GUI_EXPORT QgsElevationControllerWidget : public QWidget */ QMenu *menu(); + /** + * Returns the fixed range width, or -1 if no fixed width is set. + * + * A fixed width forces the selected elevation range to have a matching width. + * + * \see setFixedRangeWidth() + */ + double fixedRangeWidth() const; + public slots: /** @@ -114,6 +123,15 @@ class GUI_EXPORT QgsElevationControllerWidget : public QWidget */ void setRangeLimits( const QgsDoubleRange &limits ); + /** + * Sets the fixed range \a width. Set to -1 if no fixed width is desired. + * + * A fixed width forces the selected elevation range to have a matching width. + * + * \see fixedRangeWidth() + */ + void setFixedRangeWidth( double width ); + signals: /** @@ -134,6 +152,7 @@ class GUI_EXPORT QgsElevationControllerWidget : public QWidget QgsElevationControllerLabels *mSliderLabels = nullptr; QgsDoubleRange mRangeLimits; QgsDoubleRange mCurrentRange; + double mFixedRangeWidth = -1; int mBlockSliderChanges = 0; double mSliderPrecision = 100; diff --git a/tests/src/python/test_qgselevationcontrollerwidget.py b/tests/src/python/test_qgselevationcontrollerwidget.py index 7b4c999b124..e155898de07 100644 --- a/tests/src/python/test_qgselevationcontrollerwidget.py +++ b/tests/src/python/test_qgselevationcontrollerwidget.py @@ -108,6 +108,20 @@ class TestQgsElevationControllerWidget(QgisTestCase): self.assertAlmostEqual(w.range().lower(), 459.644, 3) self.assertAlmostEqual(w.range().upper(), 729.495, 3) + def testFixedRangeWidth(self): + """ + Test that fixed range width is correctly handled + """ + w = QgsElevationControllerWidget() + w.setRangeLimits(QgsDoubleRange(100.5, 1000)) + w.setFixedRangeWidth(10.0001) + self.assertEqual(w.fixedRangeWidth(), 10.0001) + w.setRange(QgsDoubleRange(130.3, 920.6)) + self.assertAlmostEqual(w.range().upper() - w.range().lower(), 10.0001, 6) + + w.slider().setLowerValue(50) + self.assertAlmostEqual(w.range().upper() - w.range().lower(), 10.0001, 6) + def test_project_interaction(self): """ Test interaction of widget with project