From 66085ea41f0c708f5f3e7dfd62365493c4f2ac7b Mon Sep 17 00:00:00 2001 From: Uwe Rathmann Date: Wed, 27 Nov 2024 16:27:57 +0100 Subject: [PATCH] QskSlider::origin implemented --- designsystems/material3/QskMaterial3Skin.cpp | 1 + .../material3/QskMaterial3SliderSkinlet.cpp | 20 +++++- examples/gallery/inputs/InputPage.cpp | 8 +++ src/controls/QskSlider.cpp | 47 ++++++++++++++ src/controls/QskSlider.h | 11 ++++ src/controls/QskSliderSkinlet.cpp | 61 ++++++++++++++++--- 6 files changed, 138 insertions(+), 10 deletions(-) diff --git a/designsystems/material3/QskMaterial3Skin.cpp b/designsystems/material3/QskMaterial3Skin.cpp index 2db15dcc..db9e355a 100644 --- a/designsystems/material3/QskMaterial3Skin.cpp +++ b/designsystems/material3/QskMaterial3Skin.cpp @@ -937,6 +937,7 @@ void Editor::setupSlider() { QskStateCombination::CombinationNoState, Q::Focused | Q::Pressed } ); setGradient( Q::Tick | SK::Filled | Q::Disabled, m_pal.inverseOnSurface ); + setFlag( Q::Fill | A::Option, Qsk::Maybe ); setFlag( Q::Tick | A::Option, Qsk::Maybe ); for ( const auto variation : { A::Horizontal, A::Vertical } ) diff --git a/designsystems/material3/QskMaterial3SliderSkinlet.cpp b/designsystems/material3/QskMaterial3SliderSkinlet.cpp index 0ba56ba0..afb4e3bc 100644 --- a/designsystems/material3/QskMaterial3SliderSkinlet.cpp +++ b/designsystems/material3/QskMaterial3SliderSkinlet.cpp @@ -8,9 +8,15 @@ #include #include #include +#include using Q = QskSlider; +static inline bool qskHasOrigin( const QskSlider* slider ) +{ + return !qskFuzzyCompare( slider->origin(), slider->minimum() ); +} + QskMaterial3SliderSkinlet::QskMaterial3SliderSkinlet( QskSkin* skin ) : Inherited( skin ) { @@ -97,8 +103,18 @@ QVector< qreal > QskMaterial3SliderSkinlet::graduation( const QskSlider* slider if ( policy != Qsk::Never ) { - graduation.reserve( 1 ); - graduation += slider->maximum(); + if ( qskHasOrigin( slider ) ) + { + graduation.reserve( 3 ); + graduation += slider->minimum(); + graduation += slider->origin(); + graduation += slider->maximum(); + } + else + { + graduation.reserve( 1 ); + graduation += slider->maximum(); + } } } diff --git a/examples/gallery/inputs/InputPage.cpp b/examples/gallery/inputs/InputPage.cpp index e5e69a76..40bf4349 100644 --- a/examples/gallery/inputs/InputPage.cpp +++ b/examples/gallery/inputs/InputPage.cpp @@ -98,6 +98,7 @@ InputPage::InputPage( QQuickItem* parent ) { Slider* continous; Slider* discrete; + Slider* centered; } sliders[2]; for ( int i = 0; i < 2; i++ ) @@ -106,6 +107,11 @@ InputPage::InputPage( QQuickItem* parent ) sliders[i].continous = new Slider( orientation, Slider::Continuous ); sliders[i].discrete = new Slider( orientation, Slider::Discrete ); + + auto slider = new Slider( orientation, Slider::Continuous ); + slider->setOrigin( slider->minimum() + + 0.5 * ( slider->maximum() - slider->minimum() ) ); + sliders[i].centered = slider; } auto spinBox = new QskSpinBox( 0.0, 100.0, 1.0 ); @@ -120,6 +126,7 @@ InputPage::InputPage( QQuickItem* parent ) vBox->addItem( sliders[0].continous ); vBox->addItem( sliders[0].discrete ); + vBox->addItem( sliders[0].centered ); vBox->addItem( inputBox ); vBox->addItem( spinBox ); @@ -127,6 +134,7 @@ InputPage::InputPage( QQuickItem* parent ) mainBox->setSpacing( 30 ); mainBox->addItem( sliders[1].continous ); mainBox->addItem( sliders[1].discrete ); + mainBox->addItem( sliders[1].centered ); mainBox->addItem( vBox ); auto inputs = findChildren< QskBoundedValueInput* >(); diff --git a/src/controls/QskSlider.cpp b/src/controls/QskSlider.cpp index 0311f5e5..82c935e0 100644 --- a/src/controls/QskSlider.cpp +++ b/src/controls/QskSlider.cpp @@ -7,6 +7,7 @@ #include "QskAnimationHint.h" #include "QskAspect.h" #include "QskEvent.h" +#include "QskFunctions.h" QSK_SUBCONTROL( QskSlider, Panel ) QSK_SUBCONTROL( QskSlider, Groove ) @@ -62,6 +63,7 @@ class QskSlider::PrivateData public: PrivateData( Qt::Orientation orientation ) : pressedValue( 0 ) + , hasOrigin( false ) , tracking( true ) , moving( false ) , orientation( orientation ) @@ -70,6 +72,10 @@ class QskSlider::PrivateData QPointF pressedPos; qreal pressedValue; + + qreal origin = 0.0; + + bool hasOrigin : 1; bool tracking : 1; bool moving : 1; uint orientation : 2; @@ -126,6 +132,40 @@ Qt::Orientation QskSlider::orientation() const return static_cast< Qt::Orientation >( m_data->orientation ); } +void QskSlider::setOrigin( qreal origin ) +{ + if ( isComponentComplete() ) + origin = boundedValue( origin ); + + if( !m_data->hasOrigin || !qskFuzzyCompare( m_data->origin, origin ) ) + { + m_data->hasOrigin = true; + m_data->origin = origin; + + update(); + Q_EMIT originChanged( origin ); + } +} + +void QskSlider::resetOrigin() +{ + if ( m_data->hasOrigin ) + { + m_data->hasOrigin = false; + + update(); + Q_EMIT originChanged( origin() ); + } +} + +qreal QskSlider::origin() const +{ + if ( m_data->hasOrigin ) + return boundedValue( m_data->origin ); + + return minimum(); +} + QskAspect::Variation QskSlider::effectiveVariation() const { return static_cast< QskAspect::Variation >( m_data->orientation ); @@ -145,6 +185,13 @@ bool QskSlider::isTracking() const return m_data->tracking; } +void QskSlider::componentComplete() +{ + Inherited::componentComplete(); + if ( m_data->hasOrigin ) + m_data->origin = boundedValue( m_data->origin ); +} + void QskSlider::aboutToShow() { setPositionHint( Handle, valueAsRatio() ); diff --git a/src/controls/QskSlider.h b/src/controls/QskSlider.h index 2c102c56..79eb5c21 100644 --- a/src/controls/QskSlider.h +++ b/src/controls/QskSlider.h @@ -21,6 +21,9 @@ class QSK_EXPORT QskSlider : public QskBoundedValueInput Q_PROPERTY( bool tracking READ isTracking WRITE setTracking NOTIFY trackingChanged ) + Q_PROPERTY( qreal origin READ origin + WRITE setOrigin RESET resetOrigin NOTIFY originChanged ) + Q_PROPERTY( qreal handlePosition READ handlePosition ) using Inherited = QskBoundedValueInput; @@ -39,6 +42,9 @@ class QSK_EXPORT QskSlider : public QskBoundedValueInput void setOrientation( Qt::Orientation ); Qt::Orientation orientation() const; + void resetOrigin(); + qreal origin() const; + void setTracking( bool ); bool isTracking() const; @@ -46,10 +52,14 @@ class QSK_EXPORT QskSlider : public QskBoundedValueInput QskAspect::Variation effectiveVariation() const override; + public Q_SLOTS: + void setOrigin( qreal ); + Q_SIGNALS: void pressedChanged( bool ); void orientationChanged( Qt::Orientation ); void trackingChanged( bool ); + void originChanged( qreal ); protected: void mousePressEvent( QMouseEvent* ) override; @@ -57,6 +67,7 @@ class QSK_EXPORT QskSlider : public QskBoundedValueInput void mouseReleaseEvent( QMouseEvent* ) override; void aboutToShow() override; + void componentComplete() override; private: void moveHandle(); diff --git a/src/controls/QskSliderSkinlet.cpp b/src/controls/QskSliderSkinlet.cpp index 5d1e709f..d9bedf91 100644 --- a/src/controls/QskSliderSkinlet.cpp +++ b/src/controls/QskSliderSkinlet.cpp @@ -6,6 +6,7 @@ #include "QskSliderSkinlet.h" #include "QskSlider.h" #include "QskFunctions.h" +#include "QskIntervalF.h" #include #include @@ -22,6 +23,24 @@ static inline qreal qskSubcontrolExtent( return skinnable->metric( subControl | QskAspect::Size, -1.0 ); } +static inline bool qskHasFilling( const QskSlider* slider ) +{ + const auto policy = slider->flagHint< Qsk::Policy >( + Q::Fill | QskAspect::Option, Qsk::Always ); + + switch( policy ) + { + case Qsk::Never: + return false; + + case Qsk::Maybe: + return qskFuzzyCompare( slider->origin(), slider->minimum() ); + + default: + return true; + } +} + static QRectF qskInnerRect( const QskSlider* slider, const QRectF& contentsRect, QskAspect::Subcontrol subControl ) { @@ -153,14 +172,17 @@ QskAspect::States QskSliderSkinlet::sampleStates( { auto states = Inherited::sampleStates( skinnable, subControl, index ); - if ( subControl == Q::Tick ) + const auto slider = static_cast< const QskSlider* >( skinnable ); + + if ( subControl == Q::Tick && qskHasFilling( slider ) ) { const auto tickValue = sampleAt( skinnable, subControl, index ); if ( tickValue.canConvert< qreal >() ) { - const auto slider = static_cast< const QskSlider* >( skinnable ); + const auto intv = QskIntervalF::normalized( + slider->origin(), slider->value() ); - if ( tickValue.value< qreal >() <= slider->value() ) + if ( intv.contains( tickValue.value< qreal >() ) ) states |= Filled; } } @@ -206,9 +228,15 @@ QRectF QskSliderSkinlet::panelRect( const auto alignment = slider->alignmentHint( Q::Panel ); if ( slider->orientation() == Qt::Horizontal ) - r = qskAlignedRectF( r, r.width(), extent, alignment & Qt::AlignVertical_Mask ); + { + r = qskAlignedRectF( r, r.width(), + extent, alignment & Qt::AlignVertical_Mask ); + } else - r = qskAlignedRectF( r, extent, r.height(), alignment & Qt::AlignHorizontal_Mask ); + { + r = qskAlignedRectF( r, extent, r.height(), + alignment & Qt::AlignHorizontal_Mask ); + } } return r; @@ -217,16 +245,33 @@ QRectF QskSliderSkinlet::panelRect( QRectF QskSliderSkinlet::fillRect( const QskSlider* slider, const QRectF& contentsRect ) const { - const auto pos = qBound( 0.0, slider->handlePosition(), 1.0 ); + if ( !qskHasFilling( slider ) ) + return QRectF(); + + auto pos1 = slider->valueAsRatio( slider->origin() ); + auto pos2 = qBound( 0.0, slider->handlePosition(), 1.0 ); + + if ( pos1 > pos2 ) + qSwap( pos1, pos2 ); auto r = qskInnerRect( slider, contentsRect, QskSlider::Fill ); auto scaleRect = subControlRect( slider, contentsRect, Q::Scale ); if ( slider->orientation() == Qt::Horizontal ) - r.setRight( scaleRect.left() + pos * scaleRect.width() ); + { + if ( !qFuzzyIsNull( pos1 ) ) + r.setLeft( scaleRect.left() + pos1 * scaleRect.width() ); + + r.setRight( scaleRect.left() + pos2 * scaleRect.width() ); + } else - r.setTop( scaleRect.bottom() - pos * scaleRect.height() ); + { + if ( !qFuzzyIsNull( pos1 ) ) + r.setBottom( scaleRect.bottom() - pos1 * scaleRect.height() ); + + r.setTop( scaleRect.bottom() - pos2 * scaleRect.height() ); + } return r; }