From 1b4be3bc23290ca5580b9fa233791c1fe68bdd95 Mon Sep 17 00:00:00 2001 From: Uwe Rathmann Date: Tue, 3 Aug 2021 15:02:33 +0200 Subject: [PATCH] layout code in QskSwitchButtonSkinlet improved - still some way to go until the switch is perfectly themable and looks like in the material specs --- skins/material/QskMaterialSkin.cpp | 39 +++--- skins/squiek/QskSquiekSkin.cpp | 33 +++-- src/controls/QskSwitchButtonSkinlet.cpp | 163 ++++++++++++++---------- src/controls/QskSwitchButtonSkinlet.h | 8 +- 4 files changed, 146 insertions(+), 97 deletions(-) diff --git a/skins/material/QskMaterialSkin.cpp b/skins/material/QskMaterialSkin.cpp index 3f4262ab..5f247b85 100644 --- a/skins/material/QskMaterialSkin.cpp +++ b/skins/material/QskMaterialSkin.cpp @@ -492,36 +492,43 @@ void Editor::setupSwitchButton() using A = QskAspect; using Q = QskSwitchButton; - const qreal radius = qskDpiScaled( 18 ); - const qreal knopLength = radius - 4; + const qreal radius = qskDpiScaled( 10 ); + const qreal handleSize = 2 * radius; + + setBoxShape( Q::Groove, 100, Qt::RelativeSize ); + + const QSizeF grooveSize( 3.4 * radius, 1.2 * radius ); + setStrutSize( Q::Groove | A::Horizontal, grooveSize ); + setStrutSize( Q::Groove | A::Vertical, grooveSize.transposed() ); + + setGradient( Q::Groove, m_pal.darker125 ); + setGradient( Q::Groove | Q::Checkable | Q::Disabled, m_pal.lighter150 ); + setGradient( Q::Groove | Q::Checkable | Q::Checked, m_pal.darker200 ); - setBoxShape( Q::Groove, radius); - setStrutSize( Q::Groove, 3.4 * radius, 2 * radius ); - setColor( Q::Groove, m_pal.accentColor ); setBoxBorderColors( Q::Groove, m_pal.darker200 ); - setColor( Q::Groove | Q::Disabled, m_pal.lighter125 ); setBoxBorderMetrics( Q::Groove, 2 ); setBoxBorderColors( Q::Groove | Q::Disabled, m_pal.darker125 ); - setBoxShape( Q::Handle, knopLength ); - setMetric( Q::Handle | A::Size,knopLength ); - setGradient( Q::Handle, QskGradient( Qt::Vertical, m_pal.lighter150, m_pal.lighter125 ) ); + setBoxShape( Q::Handle, 100, Qt::RelativeSize ); + setStrutSize( Q::Handle, handleSize, handleSize ); setBoxBorderMetrics( Q::Handle, 2 ); - setColor( Q::Handle | Q::Disabled, m_pal.lighter125 ); + + setGradient( Q::Handle, QskGradient( Qt::Vertical, m_pal.lighter150, m_pal.lighter125 ) ); + setGradient( Q::Handle | Q::Checkable | Q::Checked, m_pal.accentColor ); + + setGradient( Q::Handle | Q::Disabled, m_pal.lighter125 ); setBoxBorderColors( Q::Handle, m_pal.darker200 ); setBoxBorderColors( Q::Handle | Q::Disabled, m_pal.darker125 ); for( auto state : { A::NoState, Q::Disabled } ) { - auto aspect = Q::Handle | state | A::Position; + auto aspect = Q::Handle | Q::Checkable | state | A::Position; - setMetric( aspect | Q::Checked, 0 ); - setMetric( aspect, 1 ); - - aspect = Q::Groove | state | A::Color; - setColor( aspect | Q::Checked, m_pal.baseColor); + setMetric( aspect, 0 ); + setMetric( aspect | Q::Checked, 1 ); } + setAnimation( Q::Handle | A::Color, qskDuration ); setAnimation( Q::Handle | A::Metric, qskDuration ); setAnimation( Q::Groove | A::Color, qskDuration ); } diff --git a/skins/squiek/QskSquiekSkin.cpp b/skins/squiek/QskSquiekSkin.cpp index 24249640..5b48b984 100644 --- a/skins/squiek/QskSquiekSkin.cpp +++ b/skins/squiek/QskSquiekSkin.cpp @@ -859,33 +859,38 @@ void Editor::setupSwitchButton() using Q = QskSwitchButton; const qreal radius = qskDpiScaled( 18 ); - const qreal handleLength = radius - 4; + const qreal handleSize = 2 * ( radius - 2 ); + + setBoxShape( Q::Groove, 100, Qt::RelativeSize ); + + const QSizeF grooveSize( 3.4 * radius, 2 * radius ); + setStrutSize( Q::Groove | A::Horizontal, grooveSize ); + setStrutSize( Q::Groove | A::Vertical, grooveSize.transposed() ); + + setGradient( Q::Groove, m_pal.theme ); + setGradient( Q::Groove | Q::Checkable | Q::Checked, m_pal.highlighted ); + setGradient( Q::Groove | Q::Checkable | Q::Disabled, m_pal.lighter150 ); - setBoxShape( Q::Groove, radius); - setStrutSize( Q::Groove, 3.4 * radius, 2 * radius ); - setColor( Q::Groove, m_pal.highlighted ); setBoxBorderColors( Q::Groove | Q::Disabled, m_pal.theme ); - setColor( Q::Groove | Q::Disabled, m_pal.lighter110 ); setBoxBorderMetrics( Q::Groove, 2 ); setBoxBorderColors( Q::Groove, m_pal.darker200 ); - setBoxShape( Q::Handle, handleLength ); - setMetric( Q::Handle | A::Size, handleLength ); + setBoxShape( Q::Handle, 100, Qt::RelativeSize ); + setStrutSize( Q::Handle, handleSize, handleSize ); + setGradient( Q::Handle, QskGradient( Qt::Vertical, m_pal.lighter150, m_pal.lighter110 ) ); + setGradient( Q::Handle | Q::Disabled, m_pal.lighter110 ); + setBoxBorderMetrics( Q::Handle, 2 ); - setColor(Q::Handle | Q::Disabled, m_pal.lighter110 ); setBoxBorderColors( Q::Handle, m_pal.darker200 ); setBoxBorderColors( Q::Handle | Q::Disabled, m_pal.theme ); for( auto state : { A::NoState, Q::Disabled } ) { - auto aspect = Q::Handle | state | A::Position; + auto aspect = Q::Handle | Q::Checkable | state | A::Position; - setMetric( aspect | Q::Checked, 0 ); - setMetric( aspect, 1 ); - - aspect = Q::Groove | state | A::Color; - setColor( aspect | Q::Checked, m_pal.baseActive); + setMetric( aspect, 0 ); + setMetric( aspect | Q::Checked, 1 ); } setAnimation( Q::Handle | A::Metric, qskDuration ); diff --git a/src/controls/QskSwitchButtonSkinlet.cpp b/src/controls/QskSwitchButtonSkinlet.cpp index f2813fcc..57e5bcdb 100644 --- a/src/controls/QskSwitchButtonSkinlet.cpp +++ b/src/controls/QskSwitchButtonSkinlet.cpp @@ -7,6 +7,23 @@ #include "QskSwitchButtonSkinlet.h" #include "QskSGNode.h" +static inline qreal qskEffectivePosition( const QskSwitchButton* switchButton ) +{ + auto pos = switchButton->metric( QskSwitchButton::Handle | QskAspect::Position ); + pos = qBound( 0.0, pos, 1.0 ); + + if( switchButton->isInverted() ) + pos = 1.0 - pos; + + if ( switchButton->orientation() == Qt::Horizontal ) + { + if( switchButton->layoutMirroring() ) + pos = 1.0 - pos; + } + + return pos; +} + QskSwitchButtonSkinlet::QskSwitchButtonSkinlet( QskSkin* skin ) : Inherited( skin ) { @@ -18,94 +35,38 @@ QskSwitchButtonSkinlet::~QskSwitchButtonSkinlet() } QRectF QskSwitchButtonSkinlet::subControlRect( const QskSkinnable* skinnable, - const QRectF& contentsRect, QskAspect::Subcontrol subControl) const + const QRectF& contentsRect, QskAspect::Subcontrol subControl ) const { using Q = QskSwitchButton; - const auto switchButton = static_cast< const Q* >( skinnable ); if ( subControl == Q::Handle ) { - const auto diameter = 2 * skinnable->metric( Q::Handle | QskAspect::Size ); - const auto grooveSize = skinnable->strutSizeHint( Q::Groove ); - - auto position = skinnable->metric( Q::Handle | QskAspect::Position ); - if( switchButton->isInverted() ) - position = 1.0 - position; - - auto rect = QRectF( 0, 0, diameter, diameter ); - - if( switchButton->orientation() == Qt::Vertical ) - { - if( diameter < grooveSize.height() ) - rect.moveLeft( ( grooveSize.height() - diameter ) / 2 ); - - rect.moveTop( ( grooveSize.height() - diameter ) / 2 - + position * ( grooveSize.width() - diameter - - ( grooveSize.height() - diameter ) ) ); - } - else - { - if( switchButton->layoutMirroring() ) - position = 1.0 - position; - - if( diameter < grooveSize.height() ) - rect.moveTop( ( grooveSize.height() - diameter ) / 2 ); - - rect.moveLeft( ( grooveSize.height() - diameter ) / 2 - + position * ( grooveSize.width() - diameter - - ( grooveSize.height() - diameter ) ) ); - } - - return rect; + return handleRect( skinnable, contentsRect ); } if ( subControl == Q::Groove ) { - auto diameter = 2 * skinnable->metric( Q::Handle | QskAspect::Size ); - const auto grooveSize = skinnable->strutSizeHint( Q::Groove ); - - auto result = contentsRect; - result.setSize( grooveSize ); - - if( switchButton->orientation() == Qt::Vertical ) - { - if( grooveSize.height() < diameter ) - result.moveLeft( ( diameter - result.height() ) / 2 ); - - return result.transposed(); - } - else - { - if( grooveSize.height() < diameter ) - result.moveTop( ( diameter - result.height() ) / 2 ); - - return result; - } + return grooveRect( skinnable, contentsRect ); } return Inherited::subControlRect( skinnable, contentsRect, subControl ); } QSizeF QskSwitchButtonSkinlet::sizeHint( const QskSkinnable* skinnable, - Qt::SizeHint, const QSizeF&) const + Qt::SizeHint which, const QSizeF& ) const { - using Q = QskSwitchButton; + if ( which != Qt::PreferredSize ) + return QSizeF(); - const auto switchButton = static_cast< const Q* >( skinnable ); - const auto diameter = 2 * skinnable->metric( Q::Handle | QskAspect::Size ); - - auto hint = skinnable->strutSizeHint( Q::Groove ); - hint = hint.expandedTo( QSizeF( diameter, diameter ) ); - - if( switchButton->orientation() == Qt::Vertical ) - hint.transpose(); + auto hint = skinnable->strutSizeHint( QskSwitchButton::Groove ); + hint = hint.expandedTo( skinnable->strutSizeHint( QskSwitchButton::Handle ) ); return hint; } QSGNode* QskSwitchButtonSkinlet::updateSubNode( const QskSkinnable* skinnable, - quint8 nodeRole, QSGNode* node) const + quint8 nodeRole, QSGNode* node ) const { using Q = QskSwitchButton; @@ -121,4 +82,76 @@ QSGNode* QskSwitchButtonSkinlet::updateSubNode( const QskSkinnable* skinnable, return Inherited::updateSubNode( skinnable, nodeRole, node ); } +QRectF QskSwitchButtonSkinlet::grooveRect( + const QskSkinnable* skinnable, const QRectF& contentsRect ) const +{ + using Q = QskSwitchButton; + + const auto switchButton = static_cast< const Q* >( skinnable ); + + auto size = skinnable->strutSizeHint( Q::Groove ); + + if ( switchButton->orientation() == Qt::Vertical ) + { + if ( size.height() < 0.0 ) + { + const auto handleSize = skinnable->strutSizeHint( Q::Handle ); + size.setHeight( 2 * handleSize.height() ); + } + } + else + { + if ( size.width() < 0.0 ) + { + const auto handleSize = skinnable->strutSizeHint( Q::Handle ); + size.setWidth( 2 * handleSize.width() ); + } + } + + size = size.expandedTo( QSize( 0.0, 0.0 ) ); + + QRectF r; + r.setSize( size ); + r.moveCenter( contentsRect.center() ); + + return r; +} + +QRectF QskSwitchButtonSkinlet::handleRect( + const QskSkinnable* skinnable, const QRectF& contentsRect ) const +{ + using Q = QskSwitchButton; + + const auto switchButton = static_cast< const Q* >( skinnable ); + + const auto grooveRect = subControlRect( skinnable, contentsRect, Q::Groove ); + const auto pos = qskEffectivePosition( switchButton ); + const auto size = skinnable->strutSizeHint( Q::Handle ); + + qreal cx, cy; + + if( switchButton->orientation() == Qt::Vertical ) + { + const qreal y0 = grooveRect.y() + 0.5 * size.height(); + const qreal h = grooveRect.height() - size.height(); + + cx = grooveRect.x() + 0.5 * grooveRect.width(); + cy = y0 + pos * h; + } + else + { + const qreal x0 = grooveRect.x() + 0.5 * size.width(); + const qreal w = grooveRect.width() - size.width(); + + cx = x0 + pos * w; + cy = grooveRect.y() + 0.5 * grooveRect.height(); + } + + QRectF r; + r.setSize( size ); + r.moveCenter( QPointF( cx, cy ) ); + + return r; +} + #include "moc_QskSwitchButtonSkinlet.cpp" diff --git a/src/controls/QskSwitchButtonSkinlet.h b/src/controls/QskSwitchButtonSkinlet.h index 9c08aa09..e4cbe4fb 100644 --- a/src/controls/QskSwitchButtonSkinlet.h +++ b/src/controls/QskSwitchButtonSkinlet.h @@ -21,11 +21,11 @@ class QSK_EXPORT QskSwitchButtonSkinlet : public QskSkinlet HandleRole }; - Q_INVOKABLE QskSwitchButtonSkinlet( QskSkin* parent = nullptr ); + Q_INVOKABLE QskSwitchButtonSkinlet( QskSkin* = nullptr ); ~QskSwitchButtonSkinlet() override; QRectF subControlRect( const QskSkinnable*, - const QRectF& rect, QskAspect::Subcontrol ) const override; + const QRectF&, QskAspect::Subcontrol ) const override; QSizeF sizeHint( const QskSkinnable*, Qt::SizeHint, const QSizeF& ) const override; @@ -33,6 +33,10 @@ class QSK_EXPORT QskSwitchButtonSkinlet : public QskSkinlet protected: QSGNode* updateSubNode( const QskSkinnable*, quint8 nodeRole, QSGNode* ) const override; + + private: + QRectF grooveRect( const QskSkinnable*, const QRectF& ) const; + QRectF handleRect( const QskSkinnable*, const QRectF& ) const; }; #endif