diff --git a/skins/material3/QskMaterial3Skin.cpp b/skins/material3/QskMaterial3Skin.cpp index 429e23a9..8e3449b8 100644 --- a/skins/material3/QskMaterial3Skin.cpp +++ b/skins/material3/QskMaterial3Skin.cpp @@ -476,8 +476,6 @@ void Editor::setupPushButton() setGradient( Q::Panel | Q::Pressed, focusColor ); - // we cannot use relative size here because the rect changes size during the animation: - setBoxShape( Q::Ripple, 15.5 ); setGradient( Q::Ripple, stateLayerColor( m_pal.onPrimary, m_pal.hoverOpacity ) ); setColor( Q::Text, m_pal.onPrimary ); diff --git a/src/controls/QskPushButtonSkinlet.cpp b/src/controls/QskPushButtonSkinlet.cpp index 6ba8d47d..b40e1989 100644 --- a/src/controls/QskPushButtonSkinlet.cpp +++ b/src/controls/QskPushButtonSkinlet.cpp @@ -10,6 +10,7 @@ #include "QskGraphic.h" #include "QskTextOptions.h" #include "QskFunctions.h" +#include "QskSGNode.h" #include #include @@ -38,40 +39,26 @@ QskPushButtonSkinlet::~QskPushButtonSkinlet() = default; QRectF QskPushButtonSkinlet::subControlRect( const QskSkinnable* skinnable, const QRectF& contentsRect, QskAspect::Subcontrol subControl ) const { - using Q = QskPushButton; - const auto button = static_cast< const QskPushButton* >( skinnable ); - if ( subControl == Q::Text ) + if ( subControl == QskPushButton::Text ) { return textRect( button, contentsRect ); } - else if ( subControl == Q::Graphic ) + + if ( subControl == QskPushButton::Graphic ) { return graphicRect( button, contentsRect ); } - else if ( subControl == Q::Panel ) + + if ( subControl == QskPushButton::Panel ) { return contentsRect; } - else if ( subControl == Q::Ripple ) + + if ( subControl == QskPushButton::Ripple ) { - const auto ratio = button->metric( Q::Ripple | QskAspect::Size ); - if ( ratio <= 0.0 ) - return QRectF(); - - const auto clickPos = button->effectiveSkinHint( - Q::Ripple | QskAspect::Metric | QskAspect::Position ).toPointF(); - - const auto w = contentsRect.width() * ratio; - const auto h = contentsRect.height() * ratio; - const auto x = clickPos.x() - w; - const auto y = clickPos.y() - h; - - const QRectF r( x, y, w * 2, h * 2 ); - - const auto clipRect = subControlRect( skinnable, contentsRect, Q::Panel ); - return r.intersected( clipRect ); + return rippleRect( button, contentsRect ); } return Inherited::subControlRect( skinnable, contentsRect, subControl ); @@ -91,7 +78,7 @@ QSGNode* QskPushButtonSkinlet::updateSubNode( case RippleRole: { - return updateBoxNode( button, node, QskPushButton::Ripple ); + return updateRippleNode( button, node ); } case TextRole: @@ -201,6 +188,29 @@ QRectF QskPushButtonSkinlet::graphicRect( return r; } +QRectF QskPushButtonSkinlet::rippleRect( + const QskPushButton* button, const QRectF& contentsRect ) const +{ + using Q = QskPushButton; + + const auto ratio = button->metric( Q::Ripple | QskAspect::Size ); + if ( ratio <= 0.0 ) + return QRectF(); + + const auto pos = button->effectiveSkinHint( + Q::Ripple | QskAspect::Metric | QskAspect::Position ).toPointF(); + + const auto w = contentsRect.width() * ratio; + const auto h = contentsRect.height() * ratio; + const auto x = pos.x() - w; + const auto y = pos.y() - h; + + const QRectF r( x, y, w * 2, h * 2 ); + + const auto clipRect = subControlRect( button, contentsRect, Q::Panel ); + return r.intersected( clipRect ); +} + QSGNode* QskPushButtonSkinlet::updateTextNode( const QskPushButton* button, QSGNode* node ) const { @@ -218,6 +228,34 @@ QSGNode* QskPushButtonSkinlet::updateTextNode( button->text(), button->textOptions(), Q::Text ); } +QSGNode* QskPushButtonSkinlet::updateRippleNode( + const QskPushButton* button, QSGNode* node ) const +{ + using Q = QskPushButton; + + const auto rippleRect = button->subControlRect( Q::Ripple ); + if ( rippleRect.isEmpty() ) + return nullptr; + + auto clipNode = updateBoxClipNode( button, node, + button->subControlRect( Q::Panel ), Q::Panel ); + + if ( clipNode ) + { + auto boxNode = QskSGNode::findChildNode( clipNode, RippleRole ); + boxNode = updateBoxNode( button, boxNode, rippleRect, Q::Ripple ); + + if ( boxNode == nullptr ) + return nullptr; + + QskSGNode::setNodeRole( boxNode, RippleRole ); + if ( boxNode->parent() != clipNode ) + clipNode->appendChildNode( boxNode ); + } + + return clipNode; +} + QSizeF QskPushButtonSkinlet::sizeHint( const QskSkinnable* skinnable, Qt::SizeHint which, const QSizeF& ) const { diff --git a/src/controls/QskPushButtonSkinlet.h b/src/controls/QskPushButtonSkinlet.h index 7fb2c56c..2147a1d1 100644 --- a/src/controls/QskPushButtonSkinlet.h +++ b/src/controls/QskPushButtonSkinlet.h @@ -43,8 +43,10 @@ class QSK_EXPORT QskPushButtonSkinlet : public QskSkinlet private: QRectF textRect( const QskPushButton*, const QRectF& ) const; QRectF graphicRect( const QskPushButton*, const QRectF& ) const; + QRectF rippleRect( const QskPushButton*, const QRectF& ) const; QSGNode* updateTextNode( const QskPushButton*, QSGNode* ) const; + QSGNode* updateRippleNode( const QskPushButton*, QSGNode* ) const; }; #endif