From 6b43231ca20ef148cf1858c5054ebf220f90ee17 Mon Sep 17 00:00:00 2001 From: Peter Hartmann Date: Sun, 5 Feb 2023 13:45:29 +0100 Subject: [PATCH] segmented bar: Add splash rect and style for M3 --- skins/material3/QskMaterial3Skin.cpp | 7 +++ src/controls/QskPushButton.cpp | 1 + src/controls/QskSegmentedBar.cpp | 12 +++++ src/controls/QskSegmentedBar.h | 2 +- src/controls/QskSegmentedBarSkinlet.cpp | 70 ++++++++++++++++++++++++- src/controls/QskSegmentedBarSkinlet.h | 4 ++ 6 files changed, 93 insertions(+), 3 deletions(-) diff --git a/skins/material3/QskMaterial3Skin.cpp b/skins/material3/QskMaterial3Skin.cpp index 95abc1cc..a1a404de 100644 --- a/skins/material3/QskMaterial3Skin.cpp +++ b/skins/material3/QskMaterial3Skin.cpp @@ -571,6 +571,13 @@ void Editor::setupSegmentedBar() setBoxBorderColors( Q::Cursor, Qt::transparent ); } + { + // Splash + setBoxShape( Q::Splash, 20_dp ); + setGradient( Q::Splash, stateLayerColor( m_pal.onSecondaryContainer, m_pal.pressedOpacity ) ); + setAnimation( Q::Splash | A::Color, qskDuration ); + } + { // Text diff --git a/src/controls/QskPushButton.cpp b/src/controls/QskPushButton.cpp index fc495d22..862872f2 100644 --- a/src/controls/QskPushButton.cpp +++ b/src/controls/QskPushButton.cpp @@ -306,6 +306,7 @@ void QskPushButton::mousePressEvent( QMouseEvent* event ) using A = QskAspect; const auto hint = animationHint( Splash | A::Color ); + if( hint.isValid() ) { setPositionHint( Splash, qskMousePosition( event ).x() ); diff --git a/src/controls/QskSegmentedBar.cpp b/src/controls/QskSegmentedBar.cpp index 0dc68537..78ab401f 100644 --- a/src/controls/QskSegmentedBar.cpp +++ b/src/controls/QskSegmentedBar.cpp @@ -10,12 +10,14 @@ #include "QskEvent.h" #include "QskSkinlet.h" #include "QskAspect.h" +#include "QskAnimationHint.h" #include #include #include QSK_SUBCONTROL( QskSegmentedBar, Panel ) +QSK_SUBCONTROL( QskSegmentedBar, Splash ) QSK_SUBCONTROL( QskSegmentedBar, Segment ) QSK_SUBCONTROL( QskSegmentedBar, Separator ) QSK_SUBCONTROL( QskSegmentedBar, Cursor ) @@ -148,6 +150,8 @@ QskAspect::Variation QskSegmentedBar::effectiveVariation() const void QskSegmentedBar::mousePressEvent( QMouseEvent* event ) { + using A = QskAspect; + const int index = indexAtPosition( qskMousePosition( event ) ); if( isSegmentEnabled( index ) ) @@ -163,6 +167,14 @@ void QskSegmentedBar::mousePressEvent( QMouseEvent* event ) } } } + + const auto hint = animationHint( Splash | A::Color ); + + if( hint.isValid() ) + { + setSkinHint( Splash | A::Metric | A::Position, event->pos() ); + startTransition( Splash | A::Metric | A::Size, hint, 0.0, 1.0 ); + } } void QskSegmentedBar::mouseUngrabEvent() diff --git a/src/controls/QskSegmentedBar.h b/src/controls/QskSegmentedBar.h index 252513fd..c48e6b66 100644 --- a/src/controls/QskSegmentedBar.h +++ b/src/controls/QskSegmentedBar.h @@ -36,7 +36,7 @@ class QSK_EXPORT QskSegmentedBar : public QskControl using Inherited = QskControl; public: - QSK_SUBCONTROLS( Panel, Segment, Separator, Cursor, Text, Icon ) + QSK_SUBCONTROLS( Panel, Splash, Segment, Separator, Cursor, Text, Icon ) QSK_STATES( Selected, Minimum, Maximum ) QskSegmentedBar( QQuickItem* parent = nullptr ); diff --git a/src/controls/QskSegmentedBarSkinlet.cpp b/src/controls/QskSegmentedBarSkinlet.cpp index 8581dbcf..4632f746 100644 --- a/src/controls/QskSegmentedBarSkinlet.cpp +++ b/src/controls/QskSegmentedBarSkinlet.cpp @@ -10,6 +10,7 @@ #include "QskGraphic.h" #include "QskColorFilter.h" #include "QskFunctions.h" +#include "QskSGNode.h" #include "QskSkin.h" #include "QskStandardSymbol.h" #include "QskSubcontrolLayoutEngine.h" @@ -66,8 +67,8 @@ namespace QskSegmentedBarSkinlet::QskSegmentedBarSkinlet( QskSkin* skin ) : Inherited( skin ) { - setNodeRoles( { PanelRole, SegmentRole, - SeparatorRole, CursorRole, TextRole, IconRole } ); + setNodeRoles( { PanelRole, SegmentRole, SeparatorRole, + CursorRole, SplashRole, TextRole, IconRole } ); } QskSegmentedBarSkinlet::~QskSegmentedBarSkinlet() = default; @@ -86,6 +87,9 @@ QRectF QskSegmentedBarSkinlet::subControlRect( if( subControl == Q::Cursor ) return cursorRect( bar, contentsRect ); + if( subControl == Q::Splash ) + return splashRect( bar, contentsRect ); + return Inherited::subControlRect( skinnable, contentsRect, subControl ); } @@ -120,6 +124,35 @@ QRectF QskSegmentedBarSkinlet::cursorRect( return cursorRect; } +QRectF QskSegmentedBarSkinlet::splashRect( + const QskSegmentedBar* bar, const QRectF& contentsRect ) const +{ + using Q = QskSegmentedBar; + + QRectF rect; + + const auto ratio = bar->metric( Q::Splash | QskAspect::Size ); + + if ( ratio > 0.0 ) + { + const auto pos = bar->effectiveSkinHint( + Q::Splash | QskAspect::Metric | QskAspect::Position ).toPointF(); + + const int index = bar->indexAtPosition( pos ); + + if( index >= 0 && index < bar->count() ) + { + const auto sr = segmentRect( bar, contentsRect, index ); + rect = sr; + rect.setSize( { 2.0 * rect.width() * ratio, rect.height() * 2.0 } ); + rect.moveCenter( pos ); + rect = rect.intersected( sr ); + } + } + + return rect; +} + QRectF QskSegmentedBarSkinlet::segmentRect( const QskSegmentedBar* bar, const QRectF& contentsRect, int index ) const { @@ -183,11 +216,16 @@ QSGNode* QskSegmentedBarSkinlet::updateSubNode( { using Q = QskSegmentedBar; + const auto bar = static_cast< const QskSegmentedBar* >( skinnable ); + switch( nodeRole ) { case CursorRole: return updateBoxNode( skinnable, node, Q::Cursor ); + case SplashRole: + return updateSplashNode( bar, node ); + case PanelRole: return updateBoxNode( skinnable, node, Q::Panel ); @@ -387,4 +425,32 @@ QSGNode* QskSegmentedBarSkinlet::updateSampleNode( const QskSkinnable* skinnable return Inherited::updateSampleNode( skinnable, subControl, index, node ); } +QSGNode* QskSegmentedBarSkinlet::updateSplashNode( + const QskSegmentedBar* bar, QSGNode* node ) const +{ + using Q = QskSegmentedBar; + + const auto splashRect = bar->subControlRect( Q::Splash ); + if ( splashRect.isEmpty() ) + return nullptr; + + auto clipNode = updateBoxClipNode( bar, node, + bar->subControlRect( Q::Cursor ), Q::Cursor ); + + if ( clipNode ) + { + auto boxNode = QskSGNode::findChildNode( clipNode, SplashRole ); + boxNode = updateBoxNode( bar, boxNode, splashRect, Q::Splash ); + + if ( boxNode == nullptr ) + return nullptr; + + QskSGNode::setNodeRole( boxNode, SplashRole ); + if ( boxNode->parent() != clipNode ) + clipNode->appendChildNode( boxNode ); + } + + return clipNode; +} + #include "moc_QskSegmentedBarSkinlet.cpp" diff --git a/src/controls/QskSegmentedBarSkinlet.h b/src/controls/QskSegmentedBarSkinlet.h index a2a0a055..15fa1d39 100644 --- a/src/controls/QskSegmentedBarSkinlet.h +++ b/src/controls/QskSegmentedBarSkinlet.h @@ -23,6 +23,7 @@ class QSK_EXPORT QskSegmentedBarSkinlet : public QskSkinlet SegmentRole, SeparatorRole, CursorRole, + SplashRole, TextRole, IconRole, @@ -60,6 +61,9 @@ class QSK_EXPORT QskSegmentedBarSkinlet : public QskSkinlet QRectF segmentRect( const QskSegmentedBar*, const QRectF&, int index ) const; QRectF separatorRect( const QskSegmentedBar*, const QRectF&, int index ) const; QRectF cursorRect( const QskSegmentedBar*, const QRectF& ) const; + QRectF splashRect( const QskSegmentedBar*, const QRectF& ) const; + + QSGNode* updateSplashNode( const QskSegmentedBar*, QSGNode* ) const; }; #endif