From 328e6a9e6f6475b447f737b345363bdb851f348c Mon Sep 17 00:00:00 2001 From: Uwe Rathmann Date: Fri, 14 Apr 2023 12:44:49 +0200 Subject: [PATCH] QskArcNode as composite of fill/border nodes --- src/controls/QskSkinlet.cpp | 15 +---- src/nodes/QskArcNode.cpp | 111 +++++++++++++++++++++++++++++++++--- src/nodes/QskArcNode.h | 2 + 3 files changed, 107 insertions(+), 21 deletions(-) diff --git a/src/controls/QskSkinlet.cpp b/src/controls/QskSkinlet.cpp index b57387be..ad371f2b 100644 --- a/src/controls/QskSkinlet.cpp +++ b/src/controls/QskSkinlet.cpp @@ -205,25 +205,16 @@ static inline QSGNode* qskUpdateBoxNode( static inline QSGNode* qskUpdateArcNode( const QskSkinnable*, QSGNode* node, const QRectF& rect, - const QskGradient& fillGradient, const QskArcMetrics& metrics ) + const QskGradient& gradient, const QskArcMetrics& metrics ) { - if ( rect.isEmpty() ) - return nullptr; - - const auto rx = 0.5 * rect.width(); - const auto ry = 0.5 * rect.height(); - - const auto absoluteMetrics = metrics.toAbsolute( rx, ry ); - - if ( !qskIsArcVisible( absoluteMetrics, fillGradient ) ) + if ( rect.isEmpty() || !qskIsArcVisible( metrics, gradient ) ) return nullptr; auto arcNode = static_cast< QskArcNode* >( node ); - if ( arcNode == nullptr ) arcNode = new QskArcNode(); - arcNode->setArcData( rect, absoluteMetrics, fillGradient ); + arcNode->setArcData( rect, metrics, gradient ); return arcNode; } diff --git a/src/nodes/QskArcNode.cpp b/src/nodes/QskArcNode.cpp index fee133a2..914760e4 100644 --- a/src/nodes/QskArcNode.cpp +++ b/src/nodes/QskArcNode.cpp @@ -6,16 +6,21 @@ #include "QskArcNode.h" #include "QskArcRenderer.h" #include "QskArcMetrics.h" +#include "QskMargins.h" #include "QskGradient.h" #include "QskGradientDirection.h" +#include "QskShapeNode.h" +#include "QskStrokeNode.h" +#include "QskSGNode.h" +#include #include #define LINEAR_GRADIENT_HACK 1 #if LINEAR_GRADIENT_HACK -static inline QskGradient buildGradient( QskGradient::Type type, +static inline QskGradient qskBuildGradient( QskGradient::Type type, const QRectF& rect, const QskArcMetrics& metrics, const QskGradientStops& stops ) { @@ -63,8 +68,9 @@ static inline QskGradient buildGradient( QskGradient::Type type, #endif -static inline QskGradient effectiveGradient( const QRectF& rect, - const QskArcMetrics& metrics, const QskGradient& gradient ) +static inline QskGradient qskEffectiveGradient( + const QskGradient& gradient, const QRectF& rect, + const QskArcMetrics& metrics ) { if ( !gradient.isMonochrome() ) { @@ -91,7 +97,7 @@ static inline QskGradient effectiveGradient( const QRectF& rect, const auto type = gradient.linearDirection().isHorizontal() ? QskGradient::Conic : QskGradient::Radial; - return buildGradient( type, rect, metrics, gradient.stops() ); + return qskBuildGradient( type, rect, metrics, gradient.stops() ); } #endif } @@ -99,6 +105,29 @@ static inline QskGradient effectiveGradient( const QRectF& rect, return gradient; } +static inline QskArcMetrics qskEffectiveMetrics( + const QskArcMetrics& metrics, const QRectF& rect ) +{ + if ( metrics.sizeMode() == Qt::RelativeSize ) + { + const auto rx = 0.5 * rect.width(); + const auto ry = 0.5 * rect.height(); + + return metrics.toAbsolute( rx, ry ); + } + + return metrics; +} + +static inline QRectF qskEffectiveRect( + const QRectF& rect, const qreal borderWidth ) +{ + if ( borderWidth <= 0.0 ) + return rect; + + return qskValidOrEmptyInnerRect( rect, QskMargins( 0.5 * borderWidth ) ); +} + QskArcNode::QskArcNode() { } @@ -108,10 +137,74 @@ QskArcNode::~QskArcNode() } void QskArcNode::setArcData( const QRectF& rect, - const QskArcMetrics& metrics, const QskGradient& gradient ) + const QskArcMetrics& arcMetrics, const QskGradient& fillGradient ) { - const auto path = QskArcRenderer::arcPath( rect, metrics ); - - updateNode( path, QTransform(), rect, - effectiveGradient( rect, metrics, gradient ) ); + setArcData( rect, arcMetrics, 0.0, QColor(), fillGradient ); +} + +void QskArcNode::setArcData( const QRectF& rect, const QskArcMetrics& arcMetrics, + qreal borderWidth, const QColor borderColor, const QskGradient& fillGradient ) +{ + enum NodeRole + { + FillRole, + BorderRole + }; + + const auto metrics = qskEffectiveMetrics( arcMetrics, rect ); + const auto gradient = qskEffectiveGradient( fillGradient, rect, metrics ); + + auto fillNode = static_cast< QskShapeNode* >( + QskSGNode::findChildNode( this, FillRole ) ); + + auto borderNode = static_cast< QskStrokeNode* >( + QskSGNode::findChildNode( this, BorderRole ) ); + + const auto arcRect = qskEffectiveRect( rect, borderWidth ); + if ( arcRect.isEmpty() ) + { + delete fillNode; + delete borderNode; + + return; + } + + const auto path = QskArcRenderer::arcPath( arcRect, metrics ); + + if ( gradient.isVisible() && !metrics.isNull() ) + { + if ( fillNode == nullptr ) + { + fillNode = new QskShapeNode; + QskSGNode::setNodeRole( fillNode, FillRole ); + + prependChildNode( fillNode ); + } + + fillNode->updateNode( path, QTransform(), arcRect, gradient ); + } + else + { + delete fillNode; + } + + if ( borderWidth > 0.0 && borderColor.alpha() > 0 ) + { + if ( borderNode == nullptr ) + { + borderNode = new QskStrokeNode; + QskSGNode::setNodeRole( borderNode, BorderRole ); + + appendChildNode( borderNode ); + } + + QPen pen( borderColor, borderWidth ); + pen.setCapStyle( Qt::FlatCap ); + + borderNode->updateNode( path, QTransform(), pen ); + } + else + { + delete borderNode; + } } diff --git a/src/nodes/QskArcNode.h b/src/nodes/QskArcNode.h index a74a3b96..00a42d93 100644 --- a/src/nodes/QskArcNode.h +++ b/src/nodes/QskArcNode.h @@ -23,6 +23,8 @@ class QSK_EXPORT QskArcNode : public QskShapeNode ~QskArcNode() override; void setArcData( const QRectF&, const QskArcMetrics&, const QskGradient& ); + void setArcData( const QRectF&, const QskArcMetrics&, + qreal borderWidth, const QColor borderColor, const QskGradient& ); }; #endif