From 9ed891e2e804e73c4daf8a9636b4a1d651df2f0e Mon Sep 17 00:00:00 2001 From: Peter Hartmann Date: Mon, 13 May 2024 16:11:03 +0200 Subject: [PATCH] QskSlider: Add label container and text ... as required by M3 Resolves #391 --- designsystems/material3/QskMaterial3Skin.cpp | 17 ++++- examples/gallery/inputs/InputPage.cpp | 2 + src/controls/QskSlider.cpp | 2 + src/controls/QskSlider.h | 2 +- src/controls/QskSliderSkinlet.cpp | 69 +++++++++++++++++++- src/controls/QskSliderSkinlet.h | 5 ++ 6 files changed, 94 insertions(+), 3 deletions(-) diff --git a/designsystems/material3/QskMaterial3Skin.cpp b/designsystems/material3/QskMaterial3Skin.cpp index 82ff1ddb8..a7b7c6c45 100644 --- a/designsystems/material3/QskMaterial3Skin.cpp +++ b/designsystems/material3/QskMaterial3Skin.cpp @@ -874,6 +874,21 @@ void Editor::setupSlider() const auto disabledColor = flattenedColor( m_pal.onSurface, m_pal.background, 0.38 ); setGradient( Q::Handle | Q::Disabled, disabledColor ); + for( const auto state : { Q::Focused, Q::Pressed } ) + { + setStrutSize( Q::LabelContainer | state, 48_dp, 44_dp, + { QskStateCombination::CombinationNoState, Q::Hovered } ); + } + + setBoxShape( Q::LabelContainer, 100, Qt::RelativeSize ); + setGradient( Q::LabelContainer, m_pal.inverseSurface ); + setMargin( Q::LabelContainer | A::Horizontal, { 0, 0, 0, 4_dp } ); + setMargin( Q::LabelContainer | A::Vertical, { 4_dp, 0, 0, 0 } ); + + setFontRole( Q::LabelText, LabelMedium ); + setColor( Q::LabelText, m_pal.inverseOnSurface ); + setAlignment( Q::LabelText, Qt::AlignCenter ); + // 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 ); @@ -1471,7 +1486,7 @@ static inline QFont createFont( int size, int lineHeight, } checkFont = false; } - + font.setPixelSize( pixelSize ); if ( spacing > 0.0 ) diff --git a/examples/gallery/inputs/InputPage.cpp b/examples/gallery/inputs/InputPage.cpp index 8f41c9128..e5be225b7 100644 --- a/examples/gallery/inputs/InputPage.cpp +++ b/examples/gallery/inputs/InputPage.cpp @@ -79,6 +79,8 @@ InputPage::InputPage( QQuickItem* parent ) auto inputBox = new InputBox(); auto gridBox = new QskGridBox( this ); + gridBox->setSpacing( 30 ); + gridBox->setMargins( 30 ); gridBox->addItem( sliderV, 0, 0, -1, 1 ); gridBox->addItem( sliderH, 0, 1, 1, -1 ); diff --git a/src/controls/QskSlider.cpp b/src/controls/QskSlider.cpp index 1c3822fbe..fd865c03c 100644 --- a/src/controls/QskSlider.cpp +++ b/src/controls/QskSlider.cpp @@ -15,6 +15,8 @@ QSK_SUBCONTROL( QskSlider, Fill ) QSK_SUBCONTROL( QskSlider, Scale ) QSK_SUBCONTROL( QskSlider, Handle ) QSK_SUBCONTROL( QskSlider, Ripple ) +QSK_SUBCONTROL( QskSlider, LabelContainer ) +QSK_SUBCONTROL( QskSlider, LabelText ) QSK_SYSTEM_STATE( QskSlider, Pressed, QskAspect::FirstSystemState << 2 ) diff --git a/src/controls/QskSlider.h b/src/controls/QskSlider.h index 908e96f83..eb50c2609 100644 --- a/src/controls/QskSlider.h +++ b/src/controls/QskSlider.h @@ -25,7 +25,7 @@ class QSK_EXPORT QskSlider : public QskBoundedValueInput using Inherited = QskBoundedValueInput; public: - QSK_SUBCONTROLS( Panel, Groove, Fill, Scale, Handle, Ripple ) + QSK_SUBCONTROLS( Panel, Groove, Fill, Scale, Handle, Ripple, LabelContainer, LabelText ) QSK_STATES( Pressed ) explicit QskSlider( QQuickItem* parent = nullptr ); diff --git a/src/controls/QskSliderSkinlet.cpp b/src/controls/QskSliderSkinlet.cpp index 1b6810d68..7a1a161c5 100644 --- a/src/controls/QskSliderSkinlet.cpp +++ b/src/controls/QskSliderSkinlet.cpp @@ -10,6 +10,8 @@ #include "QskBoxBorderMetrics.h" #include "QskFunctions.h" +#include + static inline QRectF qskInnerPanelRect( const QskSlider* slider, const QRectF& contentsRect ) { @@ -31,7 +33,7 @@ static inline QRectF qskInnerPanelRect( QskSliderSkinlet::QskSliderSkinlet( QskSkin* skin ) : Inherited( skin ) { - setNodeRoles( { PanelRole, GrooveRole, FillRole, HandleRole, RippleRole } ); + setNodeRoles( { PanelRole, GrooveRole, FillRole, HandleRole, RippleRole, LabelContainerRole, LabelTextRole } ); } QskSliderSkinlet::~QskSliderSkinlet() @@ -73,6 +75,16 @@ QRectF QskSliderSkinlet::subControlRect( const QskSkinnable* skinnable, return rippleRect( slider, contentsRect ); } + if ( subControl == QskSlider::LabelContainer ) + { + return labelContainerRect( slider, contentsRect ); + } + + if ( subControl == QskSlider::LabelText ) + { + return labelContainerRect( slider, contentsRect ); + } + return Inherited::subControlRect( skinnable, contentsRect, subControl ); } @@ -107,6 +119,17 @@ QSGNode* QskSliderSkinlet::updateSubNode( { return updateBoxNode( slider, node, QskSlider::Ripple ); } + + case LabelContainerRole: + { + return updateBoxNode( slider, node, QskSlider::LabelContainer ); + } + + case LabelTextRole: + { + const auto text = labelValue( slider ); + return updateTextNode( slider, node, text, QskSlider::LabelText ); + } } return Inherited::updateSubNode( skinnable, nodeRole, node ); @@ -263,6 +286,45 @@ QRectF QskSliderSkinlet::rippleRect( return r; } +QRectF QskSliderSkinlet::labelContainerRect( + const QskSlider* slider, const QRectF& rect ) const +{ + auto size = slider->strutSizeHint( QskSlider::LabelContainer ); + + if( size.isEmpty() ) + { + return {}; + } + + QFontMetricsF fm( slider->effectiveFont( QskSlider::LabelText ) ); + const auto w = qskHorizontalAdvance( fm, labelValue( slider ) ); + + const auto padding = slider->paddingHint( QskSlider::LabelContainer ); + const auto h = fm.height() + padding.top() + padding.bottom(); + + size = size.expandedTo( { w, h } ); + + const auto hr = subControlRect( slider, rect, QskSlider::Handle ); + const auto margins = slider->marginHint( QskSlider::LabelContainer ); + + qreal x, y; + + if( slider->orientation() == Qt::Horizontal ) + { + x = hr.center().x() - size.width() / 2; + y = hr.top() - margins.bottom() - size.height(); + } + else + { + x = hr.left() - size.width() - margins.left(); + y = hr.center().y() - size.height() / 2; + } + + const QRectF r( x, y, size.width(), size.height() ); + + return r; +} + QSizeF QskSliderSkinlet::sizeHint( const QskSkinnable* skinnable, Qt::SizeHint which, const QSizeF& ) const { @@ -282,4 +344,9 @@ QSizeF QskSliderSkinlet::sizeHint( const QskSkinnable* skinnable, return hint; } +QString QskSliderSkinlet::labelValue( const QskSlider* slider ) const +{ + return QString::number( slider->value(), 'f', 1 ); +} + #include "moc_QskSliderSkinlet.cpp" diff --git a/src/controls/QskSliderSkinlet.h b/src/controls/QskSliderSkinlet.h index 170e13c61..9306bd256 100644 --- a/src/controls/QskSliderSkinlet.h +++ b/src/controls/QskSliderSkinlet.h @@ -24,6 +24,8 @@ class QSK_EXPORT QskSliderSkinlet : public QskSkinlet FillRole, HandleRole, RippleRole, + LabelContainerRole, + LabelTextRole, RoleCount }; @@ -48,8 +50,11 @@ class QSK_EXPORT QskSliderSkinlet : public QskSkinlet QRectF handleRect( const QskSlider*, const QRectF& ) const; QRectF scaleRect( const QskSlider*, const QRectF& ) const; QRectF rippleRect( const QskSlider*, const QRectF& ) const; + QRectF labelContainerRect( const QskSlider*, const QRectF& ) const; QRectF innerRect( const QskSlider*, const QRectF&, QskAspect::Subcontrol ) const; + + QString labelValue( const QskSlider* ) const; }; #endif