diff --git a/designsystems/fluent2/QskFluent2Skin.cpp b/designsystems/fluent2/QskFluent2Skin.cpp index 7243d379..801a49f6 100644 --- a/designsystems/fluent2/QskFluent2Skin.cpp +++ b/designsystems/fluent2/QskFluent2Skin.cpp @@ -1505,7 +1505,6 @@ void Editor::setupSliderColors( grooveColor = rgbSolid( grooveColor, pal.background.solid.base ); setGradient( Q::Groove | section | state, grooveColor ); - setGradient( Q::Fill | section | state, grooveColor ); setGradient( Q::Handle | section | state, handleColor ); } } diff --git a/designsystems/material3/CMakeLists.txt b/designsystems/material3/CMakeLists.txt index 051e8ed9..7a7573f3 100644 --- a/designsystems/material3/CMakeLists.txt +++ b/designsystems/material3/CMakeLists.txt @@ -3,11 +3,26 @@ # SPDX-License-Identifier: BSD-3-Clause ############################################################################ -set(SOURCES - QskMaterial3Global.h QskMaterial3Skin.h QskMaterial3Skin.cpp - QskMaterial3SkinFactory.h QskMaterial3SkinFactory.cpp +list(APPEND HEADERS + QskMaterial3Global.h QskMaterial3Skin.h QskMaterial3SkinFactory.h ) + +list(APPEND PRIVATE_HEADERS + QskMaterial3SliderSkinlet.h +) + +list(APPEND SOURCES + QskMaterial3Skin.cpp + QskMaterial3SkinFactory.cpp + QskMaterial3SliderSkinlet.cpp +) + qt_add_resources(SOURCES QskMaterial3Icons.qrc) -qsk_add_plugin(material3skin skins QskMaterial3SkinFactory ${SOURCES}) -set_target_properties(material3skin PROPERTIES DEFINE_SYMBOL QSK_MATERIAL3_MAKEDLL ) +qsk_add_plugin(material3skin skins QskMaterial3SkinFactory + ${SOURCES} ${HEADERS} ${PRIVATE_HEADERS} +) + +set_target_properties(material3skin PROPERTIES + DEFINE_SYMBOL QSK_MATERIAL3_MAKEDLL +) diff --git a/designsystems/material3/QskMaterial3Skin.cpp b/designsystems/material3/QskMaterial3Skin.cpp index 4f2b3184..8f42df72 100644 --- a/designsystems/material3/QskMaterial3Skin.cpp +++ b/designsystems/material3/QskMaterial3Skin.cpp @@ -9,6 +9,7 @@ */ #include "QskMaterial3Skin.h" +#include "QskMaterial3SliderSkinlet.h" #include @@ -906,40 +907,56 @@ void Editor::setupSlider() using A = QskAspect; using Q = QskSlider; - const QSizeF sliderSize( 48_dp, 44_dp ); - setStrutSize( Q::Panel | A::Horizontal, sliderSize ); - setStrutSize( Q::Panel | A::Vertical, sliderSize.transposed() ); + const auto extentGroove = 16_dp; + const auto extentPanel = 44_dp; - setBoxShape( Q::Groove | A::Horizontal, { 0, 100, 0, 100, Qt::RelativeSize } ); - setBoxShape( Q::Groove | A::Vertical, { 100, 100, 0, 0, Qt::RelativeSize } ); - setMetric( Q::Groove | A::Size, 16_dp ); - setMargin( Q::Groove | A::Horizontal, { 6_dp, 0, 0, 0 } ); - setMargin( Q::Groove | A::Vertical, {0, 0, 0, 6_dp } ); + setStrutSize( Q::Panel | A::Horizontal, 3 * extentGroove, extentPanel ); + setStrutSize( Q::Panel | A::Vertical, extentPanel, 3 * extentGroove ); + + setMetric( Q::Groove | A::Size, extentGroove ); + setMetric( Q::Fill | A::Size, extentGroove ); setGradient( Q::Groove, m_pal.primaryContainer ); setGradient( Q::Groove | Q::Disabled, m_pal.onSurface12 ); - setBoxShape( Q::Fill | A::Horizontal, { 100, 0, 100, 0, Qt::RelativeSize } ); - setBoxShape( Q::Fill | A::Vertical, { 0, 0, 100, 100, Qt::RelativeSize } ); - setMetric( Q::Fill | A::Size, 16_dp ); - setMargin( Q::Fill | A::Horizontal, { 0, 0, 6_dp, 0 } ); - setMargin( Q::Fill | A::Vertical, {0, 6_dp, 0, 0 } ); - setGradient( Q::Fill, m_pal.primary ); setGradient( Q::Fill | Q::Disabled, m_pal.onSurface38 ); setBoxShape( Q::Handle, 100, Qt::RelativeSize ); - setBoxBorderMetrics( Q::Handle, 0 ); + setBoxShape( Q::Groove, 100, Qt::RelativeSize ); + setBoxShape( Q::Fill, 100, Qt::RelativeSize ); - const QSizeF handleSize( 4_dp, 44_dp ); - const QSizeF handleSizeFocusedPressed( 2_dp, 44_dp ); - setStrutSize( Q::Handle | A::Horizontal, handleSize ); - setStrutSize( Q::Handle | A::Horizontal, handleSizeFocusedPressed, - { QskStateCombination::Combination, Q::Focused | Q::Pressed } ); + setStrutSize( Q::Ticks, { 4_dp, 4_dp } ); + setBoxShape( Q::Ticks, 100, Qt::RelativeSize ); - setStrutSize( Q::Handle | A::Vertical, handleSize.transposed() ); - setStrutSize( Q::Handle | A::Vertical, handleSizeFocusedPressed.transposed(), + setGradient( Q::Ticks, m_pal.primary ); + setGradient( Q::Ticks | Q::Disabled, m_pal.onSurface ); + + setGradient( Q::Ticks | Q::Filled, m_pal.secondaryContainer ); + setGradient( Q::Ticks | Q::Filled, m_pal.secondaryContainer, { QskStateCombination::Combination, Q::Focused | Q::Pressed } ); + setGradient( Q::Ticks | Q::Filled | Q::Disabled, m_pal.inverseOnSurface ); + + for ( const auto variation : { A::Horizontal, A::Vertical } ) + { + QSizeF handleSize( extentGroove, extentPanel ); + QskMargins margin1{ 6_dp, 0_dp }; + QskMargins margin2{ 7_dp, 0_dp }; + + if ( variation == A::Vertical ) + { + handleSize = handleSize.transposed(); + margin1 = margin1.rotated(); + margin2 = margin2.rotated(); + } + + const auto aspect = Q::Handle | variation; + + setStrutSize( aspect, handleSize ); + setMargin( aspect, margin1 ); + setMargin( aspect, margin2, + { QskStateCombination::Combination, Q::Focused | Q::Pressed } ); + } setGradient( Q::Handle, m_pal.primary ); setGradient( Q::Handle | Q::Pressed, m_pal.primary ); @@ -947,23 +964,6 @@ void Editor::setupSlider() const auto disabledColor = flattenedColor( m_pal.onSurface, m_pal.background, 0.38 ); setGradient( Q::Handle | Q::Disabled, disabledColor ); - for( auto indicator : { Q::GrooveStopIndicators, Q::FillStopIndicators } ) - { - setStrutSize( indicator, { 4_dp, 4_dp } ); - setBoxShape( indicator, 100, Qt::RelativeSize ); - } - - const auto p = 6_dp; - setPadding( Q::GrooveStopIndicators | A::Horizontal, { p, 0, p, 0 } ); - setPadding( Q::GrooveStopIndicators | A::Vertical, { 0, p, 0, p } ); - setPadding( Q::FillStopIndicators | A::Horizontal, { p, 0, p, 0 } ); - setPadding( Q::FillStopIndicators | A::Vertical, { 0, p, 0, p } ); - - setGradient( Q::GrooveStopIndicators, m_pal.primary ); - setGradient( Q::GrooveStopIndicators | Q::Disabled, m_pal.onSurface ); - setGradient( Q::FillStopIndicators, m_pal.secondaryContainer ); - setGradient( Q::FillStopIndicators | Q::Disabled, m_pal.inverseOnSurface ); - // move the handle smoothly when using keys setAnimation( Q::Handle | A::Metric | A::Position, 2 * qskDuration ); setAnimation( Q::Handle | A::Metric | A::Position | Q::Pressed, 0 ); @@ -1594,6 +1594,7 @@ qreal QskMaterial3Theme::stateOpacity( int state ) const QskMaterial3Skin::QskMaterial3Skin( QObject* parent ) : Inherited( parent ) { + declareSkinlet< QskSlider, QskMaterial3SliderSkinlet >(); } QskMaterial3Skin::~QskMaterial3Skin() diff --git a/designsystems/material3/QskMaterial3SliderSkinlet.cpp b/designsystems/material3/QskMaterial3SliderSkinlet.cpp new file mode 100644 index 00000000..a364326f --- /dev/null +++ b/designsystems/material3/QskMaterial3SliderSkinlet.cpp @@ -0,0 +1,227 @@ +/****************************************************************************** + * QSkinny - Copyright (C) The authors + * SPDX-License-Identifier: BSD-3-Clause + *****************************************************************************/ + +#include "QskMaterial3SliderSkinlet.h" + +#include +#include +#include + +using Q = QskSlider; + +static inline bool qskHasOrigin( const QskSlider* ) +{ + return false; // TODO +} + +qreal qskTickValue( const QskSlider* slider, int index ) +{ + if( slider->snap() ) + return slider->minimum() + index * slider->stepSize(); + + if ( qskHasOrigin( slider ) ) + { + switch( index ) + { + case 0: + return slider->minimum(); + +#if 0 + case 1: + return slider->origin(); +#endif + } + } + + return slider->maximum(); +} + +namespace +{ + class ClipNode : public QSGClipNode + { + public: + ClipNode() + : m_geometry( QSGGeometry::defaultAttributes_Point2D(), 0 ) + { + m_geometry.setDrawingMode( QSGGeometry::DrawTriangleStrip ); + setGeometry( &m_geometry ); + } + + void setRegion( const QRectF& boundingRect, const QRectF& rect ) + { + if ( ( rect == clipRect() ) && ( m_boundingRect == boundingRect ) ) + return; + + setIsRectangular( false ); + setClipRect( rect ); + + m_geometry.allocate( 2 * 5 ); // 2 points per line + + const auto l = reinterpret_cast< QskVertex::Line* >( m_geometry.vertexData() ); + l[0].setLine( boundingRect.topLeft(), rect.topLeft() ); + l[1].setLine( boundingRect.topRight(), rect.topRight() ); + l[2].setLine( boundingRect.bottomRight(), rect.bottomRight() ); + l[3].setLine( boundingRect.bottomLeft(), rect.bottomLeft() ); + l[4] = l[0]; + + m_geometry.markVertexDataDirty(); + markDirty( QSGNode::DirtyGeometry ); + } + + private: + QRectF m_boundingRect; + QSGGeometry m_geometry; + }; +} + +QskMaterial3SliderSkinlet::QskMaterial3SliderSkinlet( QskSkin* skin ) + : Inherited( skin ) +{ +} + +QRectF QskMaterial3SliderSkinlet::subControlRect( const QskSkinnable* skinnable, + const QRectF& contentsRect, QskAspect::Subcontrol subControl ) const +{ + if ( subControl == Q::Scale ) + { + auto r = Inherited::subControlRect( skinnable, contentsRect, Q::Scale ); + + const auto handleSize = skinnable->strutSizeHint( Q::Handle ); + + const auto slider = static_cast< const QskSlider* >( skinnable ); + if( slider->orientation() == Qt::Horizontal ) + { + const auto m = 0.5 * handleSize.width(); + r.adjust( m, 0.0, -m, 0.0 ); + } + { + const auto m = 0.5 * handleSize.height(); + r.adjust( 0.0, m, 0.0, -m ); + } + + return r; + } + + return Inherited::subControlRect( skinnable, contentsRect, subControl ); +} + +QSGNode* QskMaterial3SliderSkinlet::updateSubNode( + const QskSkinnable* skinnable, quint8 nodeRole, QSGNode* node ) const +{ + switch( nodeRole ) + { + case GrooveRole: + case FillRole: + { + auto clippedNode = QskSGNode::findChildNode( node, nodeRole ); + clippedNode = Inherited::updateSubNode( skinnable, nodeRole, clippedNode ); + + if ( clippedNode ) + { + const auto slider = static_cast< const QskSlider* >( skinnable ); + + auto clipNode = QskSGNode::ensureNode< ClipNode >( node ); + + clipNode->setRegion( + slider->subControlRect( Q::Panel ), + slider->subControlRect( Q::Handle ) + ); + + QskSGNode::setNodeRole( clippedNode, nodeRole ); + QskSGNode::setParentNode( clippedNode, clipNode ); + + return clipNode; + } + + return nullptr; + } + + case TicksRole: + { + return updateSeriesNode( skinnable, Q::Ticks, node ); + } + } + + return Inherited::updateSubNode( skinnable, nodeRole, node ); +} + +int QskMaterial3SliderSkinlet::sampleCount( const QskSkinnable* skinnable, + QskAspect::Subcontrol subControl ) const +{ + if ( subControl == Q::Ticks ) + { + const auto slider = static_cast< const QskSlider* >( skinnable ); + + if( slider->snap() ) + return qCeil( slider->boundaryLength() / slider->stepSize() ) + 1; + + // min/origin/max or max + return qskHasOrigin( slider ) ? 3 : 1; + } + + return Inherited::sampleCount( skinnable, subControl ); +} + +QRectF QskMaterial3SliderSkinlet::sampleRect( + const QskSkinnable* skinnable, const QRectF& contentsRect, + QskAspect::Subcontrol subControl, int index ) const +{ + if ( subControl != Q::Ticks ) + return Inherited::sampleRect( skinnable, contentsRect, subControl, index ); + + const auto slider = static_cast< const QskSlider* >( skinnable ); + + const auto tickPos = slider->valueAsRatio( qskTickValue( slider, index ) ); + + const auto size = skinnable->strutSizeHint( Q::Ticks ); + const auto r = subControlRect( skinnable, contentsRect, Q::Scale ); + + qreal x, y; + + if( slider->orientation() == Qt::Horizontal ) + { + x = tickPos * r.width() - 0.5 * size.width(); + y = 0.5 * ( r.height() - size.height() ); + } + else + { + y = r.height() - ( tickPos * r.height() ) - 0.5 * size.height(); + x = 0.5 * ( r.width() - size.width() ); + } + + return QRectF( r.x() + x, r.y() + y, size.width(), size.height() ); +} + +QskAspect::States QskMaterial3SliderSkinlet::sampleStates( + const QskSkinnable* skinnable, QskAspect::Subcontrol subControl, int index ) const +{ + auto states = Inherited::sampleStates( skinnable, subControl, index ); + + if ( subControl == Q::Ticks ) + { + const auto slider = static_cast< const QskSlider* >( skinnable ); + if ( qskTickValue( slider, index ) <= slider->value() ) + states |= Q::Filled; + } + + return states; +} + +QSGNode* QskMaterial3SliderSkinlet::updateSampleNode( const QskSkinnable* skinnable, + QskAspect::Subcontrol subControl, int index, QSGNode* node ) const +{ + if ( subControl == Q::Ticks ) + { + const auto slider = static_cast< const QskSlider* >( skinnable ); + const auto rect = sampleRect( slider, slider->contentsRect(), subControl, index ); + + return updateBoxNode( skinnable, node, rect, subControl ); + } + + return Inherited::updateSampleNode( skinnable, subControl, index, node ); +} + +#include "moc_QskMaterial3SliderSkinlet.cpp" diff --git a/designsystems/material3/QskMaterial3SliderSkinlet.h b/designsystems/material3/QskMaterial3SliderSkinlet.h new file mode 100644 index 00000000..8bd3b1ae --- /dev/null +++ b/designsystems/material3/QskMaterial3SliderSkinlet.h @@ -0,0 +1,39 @@ +/****************************************************************************** + * QSkinny - Copyright (C) The authors + * SPDX-License-Identifier: BSD-3-Clause + *****************************************************************************/ + +#ifndef QSK_MATERIAL3_SLIDER_SKINLET_H +#define QSK_MATERIAL3_SLIDER_SKINLET_H + +#include + +class QskMaterial3SliderSkinlet : QskSliderSkinlet +{ + Q_GADGET + + using Inherited = QskSliderSkinlet; + + public: + Q_INVOKABLE QskMaterial3SliderSkinlet( QskSkin* = nullptr ); + + QRectF subControlRect( const QskSkinnable*, + const QRectF& rect, QskAspect::Subcontrol ) const override; + + int sampleCount( const QskSkinnable*, QskAspect::Subcontrol ) const override; + + QRectF sampleRect( const QskSkinnable*, + const QRectF&, 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; + + QSGNode* updateSampleNode( const QskSkinnable*, + QskAspect::Subcontrol, int index, QSGNode* ) const override; +}; + +#endif diff --git a/src/controls/QskSlider.cpp b/src/controls/QskSlider.cpp index 4549a369..53b072f2 100644 --- a/src/controls/QskSlider.cpp +++ b/src/controls/QskSlider.cpp @@ -13,11 +13,11 @@ QSK_SUBCONTROL( QskSlider, Panel ) QSK_SUBCONTROL( QskSlider, Groove ) QSK_SUBCONTROL( QskSlider, Fill ) QSK_SUBCONTROL( QskSlider, Scale ) +QSK_SUBCONTROL( QskSlider, Ticks ) QSK_SUBCONTROL( QskSlider, Handle ) -QSK_SUBCONTROL( QskSlider, GrooveStopIndicators ) -QSK_SUBCONTROL( QskSlider, FillStopIndicators ) QSK_SYSTEM_STATE( QskSlider, Pressed, QskAspect::FirstSystemState << 2 ) +QSK_SYSTEM_STATE( QskSlider, Filled, QskAspect::FirstSystemState << 3 ) class QskSlider::PrivateData { diff --git a/src/controls/QskSlider.h b/src/controls/QskSlider.h index 1cf63d83..23e328d4 100644 --- a/src/controls/QskSlider.h +++ b/src/controls/QskSlider.h @@ -25,9 +25,8 @@ class QSK_EXPORT QskSlider : public QskBoundedValueInput using Inherited = QskBoundedValueInput; public: - QSK_SUBCONTROLS( Panel, Groove, Fill, Scale, Handle, - GrooveStopIndicators, FillStopIndicators ) - QSK_STATES( Pressed ) + QSK_SUBCONTROLS( Panel, Groove, Fill, Scale, Ticks, Handle ) + QSK_STATES( Pressed, Filled ) explicit QskSlider( QQuickItem* parent = nullptr ); explicit QskSlider( Qt::Orientation, QQuickItem* parent = nullptr ); diff --git a/src/controls/QskSliderSkinlet.cpp b/src/controls/QskSliderSkinlet.cpp index 92d5e09d..6c8474fc 100644 --- a/src/controls/QskSliderSkinlet.cpp +++ b/src/controls/QskSliderSkinlet.cpp @@ -5,232 +5,14 @@ #include "QskSliderSkinlet.h" #include "QskSlider.h" - -#include "QskAspect.h" -#include "QskBoxBorderMetrics.h" #include "QskFunctions.h" -#include -#include - using Q = QskSlider; -namespace +static QRectF qskInnerRect( const QskSlider* slider, + const QRectF& contentsRect, QskAspect::Subcontrol subControl ) { - inline QRectF qskInnerPanelRect( - const QskSlider* slider, const QRectF& contentsRect ) - { - #if 1 - auto padding = slider->paddingHint( Q::Panel ); - padding += slider->boxBorderMetricsHint( Q::Panel ).widths(); - - auto r = slider->subControlRect( contentsRect, Q::Panel ); - r = r.marginsRemoved( padding ); - #else - r = slider->subControlContentsRect( contentsRect, Q::Panel ); - #endif - - return r; - } - - QRectF qskInnerValueRect( const QskSlider* slider, const QRectF& contentsRect ) - { - // For M3 the stop indicators have some padding related to the groove (and fill), - // so we use the rect between first and last stop indicator as authoritative for - // indicators, handle etc. - const auto grooveIndicatorMargins = slider->paddingHint( Q::GrooveStopIndicators ); - const auto r = qskInnerPanelRect( slider, contentsRect ).marginsRemoved( grooveIndicatorMargins ); - return r; - } -} - -QskSliderSkinlet::QskSliderSkinlet( QskSkin* skin ) - : Inherited( skin ) -{ - setNodeRoles( { - PanelRole, - GrooveRole, - FillRole, - FillStopIndicatorsRole, - GrooveStopIndicatorsRole, - HandleRole - } ); -} - -QskSliderSkinlet::~QskSliderSkinlet() -{ -} - -QRectF QskSliderSkinlet::subControlRect( const QskSkinnable* skinnable, - const QRectF& contentsRect, QskAspect::Subcontrol subControl ) const -{ - const auto slider = static_cast< const QskSlider* >( skinnable ); - - if ( subControl == Q::Panel ) - { - return panelRect( slider, contentsRect ); - } - - if ( subControl == Q::Groove ) - { - return grooveRect( slider, contentsRect ); - } - - if ( subControl == Q::Fill ) - { - return fillRect( slider, contentsRect ); - } - - if ( subControl == Q::Handle ) - { - return handleRect( slider, contentsRect ); - } - - if ( subControl == Q::Scale ) - { - return scaleRect( slider, contentsRect ); - } - - return Inherited::subControlRect( skinnable, contentsRect, subControl ); -} - -int QskSliderSkinlet::sampleCount( const QskSkinnable* skinnable, - QskAspect::Subcontrol subControl ) const -{ - const auto slider = static_cast< const QskSlider* >( skinnable ); - - if( slider->snap() ) - { - const auto num = qCeil( slider->boundaryLength() / slider->stepSize() ) + 1; - return num; - } - else - { - return ( subControl == Q::GrooveStopIndicators ) ? 1 : 0; - } -} - -QRectF QskSliderSkinlet::sampleRect( - const QskSkinnable* skinnable, const QRectF& contentsRect, - QskAspect::Subcontrol subControl, int index ) const -{ - const auto slider = static_cast< const QskSlider* >( skinnable ); - - auto r = qskInnerValueRect( slider, contentsRect ); - - const auto size = slider->strutSizeHint( subControl ); - - const auto filledPoints = qFloor( ( slider->value() - slider->minimum() ) / slider->stepSize() ); - - if( slider->snap()) - { - if( slider->snap() - && ( ( index >= filledPoints && subControl == Q::FillStopIndicators ) - || ( index < filledPoints && subControl == Q::GrooveStopIndicators ) ) ) - { - return {}; - } - } - - const auto pos = slider->snap() ? slider->minimum() + index * slider->stepSize() : slider->maximum(); - - if( slider->orientation() == Qt::Horizontal ) - { - r.setTop( r.center().y() - size.height() / 2 ); - const auto x = r.left() + slider->valueAsRatio( pos ) * r.width() - size.width() / 2; - r.setLeft( x ); - } - else - { - r.setLeft( r.center().x() - size.width() / 2 ); - const auto y = r.bottom() - slider->valueAsRatio( pos ) * r.height() - size.height() / 2; - r.setTop( y ); - } - - r.setHeight( size.height() ); - r.setWidth( size.width() ); - - return r; -} - -QskAspect::States QskSliderSkinlet::sampleStates( const QskSkinnable*, QskAspect::Subcontrol, int ) const -{ - return {}; -} - -QSGNode* QskSliderSkinlet::updateSubNode( - const QskSkinnable* skinnable, quint8 nodeRole, QSGNode* node ) const -{ - const auto slider = static_cast< const QskSlider* >( skinnable ); - - switch ( nodeRole ) - { - case PanelRole: - { - return updateBoxNode( slider, node, Q::Panel ); - } - - case GrooveRole: - { - return updateBoxNode( slider, node, Q::Groove ); - } - - case FillRole: - { - return updateBoxNode( slider, node, Q::Fill ); - } - - case GrooveStopIndicatorsRole: - { - return updateSeriesNode( slider, Q::GrooveStopIndicators, node ); - } - - case FillStopIndicatorsRole: - { - return updateSeriesNode( slider, Q::FillStopIndicators, node ); - } - - case HandleRole: - { - return updateBoxNode( slider, node, Q::Handle ); - } - } - - return Inherited::updateSubNode( skinnable, nodeRole, node ); -} - -QSGNode* QskSliderSkinlet::updateSampleNode( const QskSkinnable* skinnable, - QskAspect::Subcontrol subControl, int index, QSGNode* node ) const -{ - const auto slider = static_cast< const QskSlider* >( skinnable ); - const auto rect = sampleRect( slider, slider->contentsRect(), subControl, index ); - - return updateBoxNode( skinnable, node, rect, subControl ); -} - -QRectF QskSliderSkinlet::panelRect( - const QskSlider* slider, const QRectF& contentsRect ) const -{ - auto r = contentsRect; - - const qreal size = slider->metric( Q::Panel | QskAspect::Size ); // 0: no hint - if ( size > 0 && size < r.height() ) - { - const auto alignment = slider->alignmentHint( Q::Panel ); - - if ( slider->orientation() == Qt::Horizontal ) - r = qskAlignedRectF( r, r.width(), size, alignment & Qt::AlignVertical_Mask ); - else - r = qskAlignedRectF( r, size, r.height(), alignment & Qt::AlignHorizontal_Mask ); - } - - return r; -} - -QRectF QskSliderSkinlet::innerRect( const QskSlider* slider, - const QRectF& contentsRect, QskAspect::Subcontrol subControl ) const -{ - auto r = qskInnerPanelRect( slider, contentsRect ); + auto r = slider->subControlContentsRect( contentsRect, Q::Panel ); QskSkinHintStatus status; @@ -256,52 +38,96 @@ QRectF QskSliderSkinlet::innerRect( const QskSlider* slider, return r; } -QRectF QskSliderSkinlet::grooveRect( - const QskSlider* slider, const QRectF& contentsRect ) const +QskSliderSkinlet::QskSliderSkinlet( QskSkin* skin ) + : Inherited( skin ) { - const auto r = qskInnerPanelRect( slider, contentsRect ); - auto grooveRect = innerRect( slider, contentsRect, Q::Groove ); - const auto handleRect = slider->subControlRect( Q::Handle ); - - if ( slider->orientation() == Qt::Horizontal ) - { - grooveRect.setLeft( handleRect.right() ); - grooveRect.setRight( r.right() ); - } - else - { - grooveRect.setBottom( handleRect.top() ); - grooveRect.setTop( r.top() ); - } - - return grooveRect; + setNodeRoles( { PanelRole, GrooveRole, FillRole, TicksRole, HandleRole } ); } -QRectF QskSliderSkinlet::scaleRect( - const QskSlider* slider, const QRectF& rect ) const +QskSliderSkinlet::~QskSliderSkinlet() { - return innerRect( slider, rect, Q::Groove ); +} + +QRectF QskSliderSkinlet::subControlRect( const QskSkinnable* skinnable, + const QRectF& contentsRect, QskAspect::Subcontrol subControl ) const +{ + const auto slider = static_cast< const QskSlider* >( skinnable ); + + if ( subControl == Q::Panel ) + return panelRect( slider, contentsRect ); + + if ( subControl == Q::Groove ) + return qskInnerRect( slider, contentsRect, Q::Groove ); + + if ( subControl == Q::Fill ) + return fillRect( slider, contentsRect ); + + if ( subControl == Q::Scale ) + return subControlRect( skinnable, contentsRect, Q::Groove ); + + if ( subControl == Q::Handle ) + return handleRect( slider, contentsRect ); + + return Inherited::subControlRect( skinnable, contentsRect, subControl ); +} + +QSGNode* QskSliderSkinlet::updateSubNode( + const QskSkinnable* skinnable, quint8 nodeRole, QSGNode* node ) const +{ + const auto slider = static_cast< const QskSlider* >( skinnable ); + + switch ( nodeRole ) + { + case PanelRole: + return updateBoxNode( slider, node, Q::Panel ); + + case GrooveRole: + return updateBoxNode( slider, node, Q::Groove ); + + case FillRole: + return updateBoxNode( slider, node, Q::Fill ); + + case HandleRole: + return updateBoxNode( slider, node, Q::Handle ); + } + + return Inherited::updateSubNode( skinnable, nodeRole, node ); +} + +QRectF QskSliderSkinlet::panelRect( + const QskSlider* slider, const QRectF& contentsRect ) const +{ + auto r = contentsRect; + + const qreal size = slider->metric( Q::Panel | QskAspect::Size ); // 0: no hint + if ( size > 0 && size < r.height() ) + { + const auto alignment = slider->alignmentHint( Q::Panel ); + + if ( slider->orientation() == Qt::Horizontal ) + r = qskAlignedRectF( r, r.width(), size, alignment & Qt::AlignVertical_Mask ); + else + r = qskAlignedRectF( r, size, r.height(), alignment & Qt::AlignHorizontal_Mask ); + } + + return r; } QRectF QskSliderSkinlet::fillRect( const QskSlider* slider, const QRectF& contentsRect ) const { - const auto r = qskInnerPanelRect( slider, contentsRect ); - const auto handleRect = slider->subControlRect( Q::Handle ); + const auto pos = qBound( 0.0, slider->handlePosition(), 1.0 ); + + auto r = qskInnerRect( slider, contentsRect, QskSlider::Fill ); + + auto scaleRect = subControlRect( slider, contentsRect, Q::Scale ); - auto fillRect = innerRect( slider, contentsRect, Q::Fill ); if ( slider->orientation() == Qt::Horizontal ) - { - fillRect.setLeft( r.left() ); - fillRect.setRight( handleRect.left() ); - } + r.setRight( scaleRect.left() + pos * scaleRect.width() ); else - { - fillRect.setBottom( r.bottom() ); - fillRect.setTop( handleRect.bottom() ); - } + r.setTop( scaleRect.bottom() - pos * scaleRect.height() ); - return fillRect; + return r; } QRectF QskSliderSkinlet::handleRect( @@ -310,7 +136,7 @@ QRectF QskSliderSkinlet::handleRect( auto handleSize = slider->strutSizeHint( Q::Handle ); const auto pos = qBound( 0.0, slider->handlePosition(), 1.0 ); - const auto r = qskInnerValueRect( slider, contentsRect ); + const auto r = subControlRect( slider, contentsRect, Q::Scale ); auto center = r.center(); if ( slider->orientation() == Qt::Horizontal ) @@ -346,15 +172,10 @@ QSizeF QskSliderSkinlet::sizeHint( const QskSkinnable* skinnable, if ( which != Qt::PreferredSize ) return QSizeF(); - const auto panelHint = skinnable->strutSizeHint( Q::Panel ); - const auto grooveHint = skinnable->strutSizeHint( Q::Groove ); - const auto fillHint = skinnable->strutSizeHint( Q::Fill ); - const auto handleHint = skinnable->strutSizeHint( Q::Handle ); - - auto hint = panelHint; - hint = hint.expandedTo( grooveHint ); - hint = hint.expandedTo( fillHint ); - hint = hint.expandedTo( handleHint ); + auto hint = skinnable->strutSizeHint( Q::Panel ); + hint = hint.expandedTo( skinnable->strutSizeHint( Q::Groove ) ); + hint = hint.expandedTo( skinnable->strutSizeHint( Q::Fill ) ); + hint = hint.expandedTo( skinnable->strutSizeHint( Q::Handle ) ); return hint; } diff --git a/src/controls/QskSliderSkinlet.h b/src/controls/QskSliderSkinlet.h index 2eaf27d9..b88f4af8 100644 --- a/src/controls/QskSliderSkinlet.h +++ b/src/controls/QskSliderSkinlet.h @@ -22,8 +22,7 @@ class QSK_EXPORT QskSliderSkinlet : public QskSkinlet PanelRole, GrooveRole, FillRole, - GrooveStopIndicatorsRole, - FillStopIndicatorsRole, + TicksRole, HandleRole, RoleCount @@ -38,29 +37,14 @@ class QSK_EXPORT QskSliderSkinlet : public QskSkinlet QSizeF sizeHint( const QskSkinnable*, Qt::SizeHint, const QSizeF& ) const override; - int sampleCount( const QskSkinnable*, QskAspect::Subcontrol ) const override; - - QRectF sampleRect( const QskSkinnable*, - const QRectF&, 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; - QSGNode* updateSampleNode( const QskSkinnable*, - QskAspect::Subcontrol, int index, QSGNode* ) const override; - private: QRectF panelRect( const QskSlider*, const QRectF& ) const; - QRectF grooveRect( const QskSlider*, const QRectF& ) const; QRectF fillRect( const QskSlider*, const QRectF& ) const; QRectF handleRect( const QskSlider*, const QRectF& ) const; - QRectF scaleRect( const QskSlider*, const QRectF& ) const; - - QRectF innerRect( const QskSlider*, const QRectF&, QskAspect::Subcontrol ) const; }; #endif