diff --git a/designsystems/fluent2/QskFluent2Skin.cpp b/designsystems/fluent2/QskFluent2Skin.cpp index 801a49f6..85b123e4 100644 --- a/designsystems/fluent2/QskFluent2Skin.cpp +++ b/designsystems/fluent2/QskFluent2Skin.cpp @@ -1450,10 +1450,14 @@ void Editor::setupSliderMetrics() setShadowMetrics( Q::Handle, { shadowSpread, 0.0 } ); - setBoxBorderMetrics( Q::Handle, 5 ); - setBoxBorderMetrics( Q::Handle | Q::Hovered, 4 ); - setBoxBorderMetrics( Q::Handle | Q::Pressed, 6 ); - setBoxBorderMetrics( Q::Handle | Q::Disabled, 6 ); + setBoxBorderMetrics( Q::Handle, 5_px ); + setBoxBorderMetrics( Q::Handle | Q::Hovered, 4_px ); + setBoxBorderMetrics( Q::Handle | Q::Pressed, 6_px ); + setBoxBorderMetrics( Q::Handle | Q::Disabled, 6_px ); + + setFlag( Q::Tick | A::Option, Qsk::Maybe ); + setStrutSize( Q::Tick | A::Horizontal, 1_px, -1 ); + setStrutSize( Q::Tick | A::Vertical, -1, 1_px ); } void Editor::setupSliderColors( @@ -1484,29 +1488,35 @@ void Editor::setupSliderColors( for ( auto state : { A::NoState, Q::Hovered, Q::Pressed, Q::Disabled } ) { - QRgb grooveColor, handleColor; + QRgb grooveColor, fillColor, handleColor; if ( state == A::NoState || state == Q::Hovered ) { grooveColor = pal.fillColor.controlStrong.defaultColor; + fillColor = pal.fillColor.accent.defaultColor; handleColor = pal.fillColor.accent.defaultColor; } else if ( state == Q::Pressed ) { grooveColor = pal.fillColor.controlStrong.defaultColor; handleColor = pal.fillColor.accent.tertiary; + fillColor = pal.fillColor.accent.defaultColor; } else if ( state == Q::Disabled ) { grooveColor = pal.fillColor.controlStrong.disabled; + fillColor = pal.fillColor.accent.disabled; handleColor = grooveColor; } grooveColor = rgbSolid( grooveColor, pal.background.solid.base ); setGradient( Q::Groove | section | state, grooveColor ); + setGradient( Q::Fill | section | state, fillColor ); setGradient( Q::Handle | section | state, handleColor ); } + + setGradient( Q::Tick, pal.fillColor.controlSolid.defaultColor ); } void Editor::setupSpinBoxMetrics() diff --git a/designsystems/material3/QskMaterial3Skin.cpp b/designsystems/material3/QskMaterial3Skin.cpp index 746493bd..e8f5ff49 100644 --- a/designsystems/material3/QskMaterial3Skin.cpp +++ b/designsystems/material3/QskMaterial3Skin.cpp @@ -906,7 +906,7 @@ void Editor::setupSlider() { using A = QskAspect; using Q = QskSlider; - using SK = QskMaterial3SliderSkinlet; + using SK = QskSliderSkinlet; const auto extentGroove = 16_dp; const auto extentPanel = 44_dp; @@ -937,6 +937,8 @@ void Editor::setupSlider() { QskStateCombination::CombinationNoState, Q::Focused | Q::Pressed } ); setGradient( Q::Tick | SK::Filled | Q::Disabled, m_pal.inverseOnSurface ); + setFlag( Q::Tick | A::Option, Qsk::Maybe ); + for ( const auto variation : { A::Horizontal, A::Vertical } ) { QSizeF handleSize( extentGroove, extentPanel ); diff --git a/designsystems/material3/QskMaterial3SliderSkinlet.cpp b/designsystems/material3/QskMaterial3SliderSkinlet.cpp index 7a743b2d..c05e8220 100644 --- a/designsystems/material3/QskMaterial3SliderSkinlet.cpp +++ b/designsystems/material3/QskMaterial3SliderSkinlet.cpp @@ -9,11 +9,6 @@ #include #include -#include - -// the color of stop indicators is different, when being on top of the filling -QSK_SYSTEM_STATE( QskMaterial3SliderSkinlet, Filled, QskAspect::FirstUserState >> 1 ) - using Q = QskSlider; static inline bool qskHasBoundaryTicks( const QskSlider* slider ) @@ -92,7 +87,7 @@ int QskMaterial3SliderSkinlet::sampleCount( const QskSkinnable* skinnable, { const auto slider = static_cast< const QskSlider* >( skinnable ); - if ( qskHasBoundaryTicks( slider ) ) + if ( ( slider->graduationPolicy() == Qsk::Maybe ) && !slider->isSnapping() ) { const bool hasOrigin = false; @@ -104,54 +99,42 @@ int QskMaterial3SliderSkinlet::sampleCount( const QskSkinnable* skinnable, return Inherited::sampleCount( skinnable, subControl ); } -QVariant QskMaterial3SliderSkinlet::sampleAt( const QskSkinnable* skinnable, - QskAspect::Subcontrol subControl, int index ) const +QVector< qreal > QskMaterial3SliderSkinlet::graduation( const QskSlider* slider ) const { - if ( subControl == Q::Tick ) + QVector< qreal > graduation; + + if ( ( slider->graduationPolicy() == Qsk::Maybe ) && !slider->isSnapping() ) { - const auto slider = static_cast< const QskSlider* >( skinnable ); + const bool hasOrigin = false; - if ( qskHasBoundaryTicks( slider ) ) + if ( hasOrigin ) { - switch( index ) - { - case 1: - return slider->minimum(); - - #if 0 - case 2: - return slider->origin(); - #endif - - default: - return slider->maximum(); - } - - return QVariant(); + graduation.reserve( 3 ); + graduation += slider->minimum(); +#if 1 + graduation += slider->maximum(); // origin !!! +#endif + graduation += slider->maximum(); + } + else + { + graduation.reserve( 1 ); + graduation += slider->maximum(); } } - - return Inherited::sampleAt( skinnable, subControl, index ); -} - -QskAspect::States QskMaterial3SliderSkinlet::sampleStates( - const QskSkinnable* skinnable, QskAspect::Subcontrol subControl, int index ) const -{ - auto states = Inherited::sampleStates( skinnable, subControl, index ); - - if ( subControl == Q::Tick ) + else { - const auto tickValue = sampleAt( skinnable, subControl, index ); - if ( tickValue.canConvert< qreal >() ) - { - const auto slider = static_cast< const QskSlider* >( skinnable ); + const auto g = Inherited::graduation( slider ); - if ( tickValue.value< qreal >() <= slider->value() ) - states |= QskMaterial3SliderSkinlet::Filled; - } + // adding the boundaries + + graduation.reserve( g.count() + 2 ); + graduation += slider->minimum(); + graduation += g; + graduation += slider->maximum(); } - return states; + return graduation; } #include "moc_QskMaterial3SliderSkinlet.cpp" diff --git a/designsystems/material3/QskMaterial3SliderSkinlet.h b/designsystems/material3/QskMaterial3SliderSkinlet.h index b5e6f8a9..807f2734 100644 --- a/designsystems/material3/QskMaterial3SliderSkinlet.h +++ b/designsystems/material3/QskMaterial3SliderSkinlet.h @@ -15,8 +15,6 @@ class QskMaterial3SliderSkinlet : QskSliderSkinlet using Inherited = QskSliderSkinlet; public: - QSK_STATES( Filled ) - Q_INVOKABLE QskMaterial3SliderSkinlet( QskSkin* = nullptr ); QRectF subControlRect( const QskSkinnable*, @@ -24,15 +22,11 @@ class QskMaterial3SliderSkinlet : QskSliderSkinlet int sampleCount( const QskSkinnable*, QskAspect::Subcontrol ) const override; - QVariant sampleAt( const QskSkinnable*, - QskAspect::Subcontrol, int index ) const override; - - QskAspect::States sampleStates( const QskSkinnable*, - QskAspect::Subcontrol, int ) const override; - protected: QSGNode* updateSubNode( const QskSkinnable*, quint8 nodeRole, QSGNode* ) const override; + + QVector< qreal > graduation( const QskSlider* ) const override; }; #endif diff --git a/src/controls/QskSlider.cpp b/src/controls/QskSlider.cpp index 7d5b2554..6c3253d5 100644 --- a/src/controls/QskSlider.cpp +++ b/src/controls/QskSlider.cpp @@ -9,8 +9,6 @@ #include "QskIntervalF.h" #include "QskEvent.h" -#include - QSK_SUBCONTROL( QskSlider, Panel ) QSK_SUBCONTROL( QskSlider, Groove ) QSK_SUBCONTROL( QskSlider, Fill ) @@ -25,26 +23,6 @@ static inline QskAspect qskAspectGraduationPolicy() return QskSlider::Tick | QskAspect::Option; } -static inline bool qskHasGraduation( const QskSlider* slider ) -{ - if ( slider->stepSize() ) - { - switch( slider->graduationPolicy() ) - { - case Qsk::Always: - return true; - - case Qsk::Maybe: - return slider->isSnapping(); - - case Qsk::Never: - return false; - } - } - - return false; -} - class QskSlider::PrivateData { public: @@ -131,26 +109,7 @@ void QskSlider::resetGraduationPolicy() Qsk::Policy QskSlider::graduationPolicy() const { - return flagHint< Qsk::Policy >( qskAspectGraduationPolicy(), Qsk::Maybe ); -} - -QVector< qreal > QskSlider::visualGraduation() const -{ - QVector< qreal > graduation; - - if ( qskHasGraduation( this ) ) - { - const auto n = qCeil( boundaryLength() / stepSize() ) + 1; - - graduation.reserve( n ); - - for ( int i = 0; i < n - 1; i++ ) - graduation += minimum() + i * stepSize(); - - graduation += maximum(); - } - - return graduation; + return flagHint< Qsk::Policy >( qskAspectGraduationPolicy(), Qsk::Never ); } void QskSlider::setTracking( bool on ) diff --git a/src/controls/QskSlider.h b/src/controls/QskSlider.h index fc89eac7..67b10c85 100644 --- a/src/controls/QskSlider.h +++ b/src/controls/QskSlider.h @@ -9,8 +9,6 @@ #include "QskBoundedValueInput.h" #include "QskNamespace.h" -#include - class QSK_EXPORT QskSlider : public QskBoundedValueInput { Q_OBJECT @@ -49,8 +47,6 @@ class QSK_EXPORT QskSlider : public QskBoundedValueInput void resetGraduationPolicy(); Qsk::Policy graduationPolicy() const; - virtual QVector< qreal > visualGraduation() const; - void setTracking( bool ); bool isTracking() const; diff --git a/src/controls/QskSliderSkinlet.cpp b/src/controls/QskSliderSkinlet.cpp index 7d2c6ed4..fdbec9e1 100644 --- a/src/controls/QskSliderSkinlet.cpp +++ b/src/controls/QskSliderSkinlet.cpp @@ -6,6 +6,13 @@ #include "QskSliderSkinlet.h" #include "QskSlider.h" #include "QskFunctions.h" +#include "QskIntervalF.h" + +#include +#include + +// the color of graduation ticks might different, when being on top of the filling +QSK_SYSTEM_STATE( QskSliderSkinlet, Filled, QskAspect::FirstUserState >> 1 ) using Q = QskSlider; @@ -38,6 +45,26 @@ static QRectF qskInnerRect( const QskSlider* slider, return r; } +static inline bool qskHasGraduation( const QskSlider* slider ) +{ + if ( slider->stepSize() ) + { + switch( slider->graduationPolicy() ) + { + case Qsk::Always: + return true; + + case Qsk::Maybe: + return slider->isSnapping(); + + case Qsk::Never: + return false; + } + } + + return false; +} + QskSliderSkinlet::QskSliderSkinlet( QskSkin* skin ) : Inherited( skin ) { @@ -103,7 +130,7 @@ int QskSliderSkinlet::sampleCount( const QskSkinnable* skinnable, if ( subControl == Q::Tick ) { const auto slider = static_cast< const QskSlider* >( skinnable ); - return slider->visualGraduation().count(); + return graduation( slider ).count(); } return Inherited::sampleCount( skinnable, subControl ); @@ -115,12 +142,32 @@ QVariant QskSliderSkinlet::sampleAt( const QskSkinnable* skinnable, if ( subControl == Q::Tick ) { const auto slider = static_cast< const QskSlider* >( skinnable ); - return slider->visualGraduation().value( index ); + return graduation( slider ).value( index ); } return Inherited::sampleAt( skinnable, subControl, index ); } +QskAspect::States QskSliderSkinlet::sampleStates( + const QskSkinnable* skinnable, QskAspect::Subcontrol subControl, int index ) const +{ + auto states = Inherited::sampleStates( skinnable, subControl, index ); + + if ( subControl == Q::Tick ) + { + const auto tickValue = sampleAt( skinnable, subControl, index ); + if ( tickValue.canConvert< qreal >() ) + { + const auto slider = static_cast< const QskSlider* >( skinnable ); + + if ( tickValue.value< qreal >() <= slider->value() ) + states |= Filled; + } + } + + return states; +} + QRectF QskSliderSkinlet::sampleRect( const QskSkinnable* skinnable, const QRectF& contentsRect, QskAspect::Subcontrol subControl, int index ) const @@ -229,23 +276,33 @@ QRectF QskSliderSkinlet::tickRect( const QskSlider* slider, const auto tickPos = slider->valueAsRatio( tickValue.value< qreal >() ); - const auto size = slider->strutSizeHint( Q::Tick ); const auto r = subControlRect( slider, contentsRect, Q::Scale ); - qreal x, y; + const auto padding = slider->paddingHint( Q::Scale ); + const auto size = slider->strutSizeHint( Q::Tick ); if( slider->orientation() == Qt::Horizontal ) { - x = tickPos * r.width() - 0.5 * size.width(); - y = 0.5 * ( r.height() - size.height() ); + const auto x = tickPos * r.width() - 0.5 * size.width(); + + QskIntervalF intv( padding.top(), r.height() - padding.bottom() ); + if ( size.height() >= 0.0 ) + intv.stretch( size.height() ); + + return QRectF( r.x() + x, r.y() + intv.lowerBound(), + size.width(), intv.length() ); } else { - y = r.height() - ( tickPos * r.height() ) - 0.5 * size.height(); - x = 0.5 * ( r.width() - size.width() ); - } + const auto y = tickPos * r.height() + 0.5 * size.height(); - return QRectF( r.x() + x, r.y() + y, size.width(), size.height() ); + QskIntervalF intv( padding.left(), r.width() - padding.right() ); + if ( size.width() >= 0.0 ) + intv.stretch( size.width() ); + + return QRectF( r.x() + intv.lowerBound(), r.bottom() - y, + intv.length(), size.height() ); + } } QSizeF QskSliderSkinlet::sizeHint( const QskSkinnable* skinnable, @@ -262,4 +319,28 @@ QSizeF QskSliderSkinlet::sizeHint( const QskSkinnable* skinnable, return hint; } +QVector< qreal > QskSliderSkinlet::graduation( const QskSlider* slider ) const +{ + QVector< qreal > graduation; + + if ( qskHasGraduation( slider ) ) + { + const auto from = slider->minimum(); + const auto to = slider->maximum(); + + auto step = slider->stepSize(); + if ( from > to ) + step = -step; + + const auto n = qCeil( ( to - from ) / step ) - 1; + + graduation.reserve( n ); + + for ( int i = 1; i <= n; i++ ) + graduation += from + i * step; + } + + return graduation; +} + #include "moc_QskSliderSkinlet.cpp" diff --git a/src/controls/QskSliderSkinlet.h b/src/controls/QskSliderSkinlet.h index 192e366b..6a6b6cba 100644 --- a/src/controls/QskSliderSkinlet.h +++ b/src/controls/QskSliderSkinlet.h @@ -17,6 +17,8 @@ class QSK_EXPORT QskSliderSkinlet : public QskSkinlet using Inherited = QskSkinlet; public: + QSK_STATES( Filled ) + enum NodeRole { PanelRole, @@ -45,6 +47,9 @@ class QSK_EXPORT QskSliderSkinlet : public QskSkinlet QVariant sampleAt( const QskSkinnable*, QskAspect::Subcontrol, int index ) const override; + QskAspect::States sampleStates( const QskSkinnable*, + QskAspect::Subcontrol, int ) const override; + protected: QSGNode* updateSubNode( const QskSkinnable*, quint8 nodeRole, QSGNode* ) const override; @@ -52,6 +57,8 @@ class QSK_EXPORT QskSliderSkinlet : public QskSkinlet QSGNode* updateSampleNode( const QskSkinnable*, QskAspect::Subcontrol, int index, QSGNode* ) const override; + virtual QVector< qreal > graduation( const QskSlider* ) const; + private: QRectF panelRect( const QskSlider*, const QRectF& ) const; QRectF fillRect( const QskSlider*, const QRectF& ) const;