From 1339a5f4cbdb4bafdf3988e8d91a8719901b19f9 Mon Sep 17 00:00:00 2001 From: Uwe Rathmann Date: Mon, 13 Jun 2022 17:01:15 +0200 Subject: [PATCH] shadows added to the box model --- examples/iotdashboard/LightDisplaySkinlet.cpp | 1 - examples/iotdashboard/ShadowedBox.cpp | 1 - playground/shadows/ShadowedBox.cpp | 137 ++---------------- playground/shadows/ShadowedBox.h | 38 ++--- playground/shadows/main.cpp | 14 +- src/common/QskBoxHints.cpp | 16 +- src/common/QskBoxHints.h | 9 +- src/controls/QskSkinlet.cpp | 38 +++-- src/controls/QskSkinnable.cpp | 3 +- src/nodes/QskBoxShadowNode.cpp | 4 +- src/nodes/QskBoxShadowNode.h | 3 +- src/nodes/QskShadedBoxNode.cpp | 58 ++++++++ src/nodes/QskShadedBoxNode.h | 34 +++++ src/src.pro | 2 + 14 files changed, 174 insertions(+), 184 deletions(-) create mode 100644 src/nodes/QskShadedBoxNode.cpp create mode 100644 src/nodes/QskShadedBoxNode.h diff --git a/examples/iotdashboard/LightDisplaySkinlet.cpp b/examples/iotdashboard/LightDisplaySkinlet.cpp index 56b5e154..865ae2b5 100644 --- a/examples/iotdashboard/LightDisplaySkinlet.cpp +++ b/examples/iotdashboard/LightDisplaySkinlet.cpp @@ -150,7 +150,6 @@ QSGNode* LightDisplaySkinlet::updateSubNode( shadowNode->setShape( grooveRect.width() / 2 ); shadowNode->setBlurRadius( shadowMetrics.blurRadius() ); shadowNode->setColor( display->shadowColor() ); - shadowNode->setClipRect( grooveRect ); shadowNode->updateGeometry(); diff --git a/examples/iotdashboard/ShadowedBox.cpp b/examples/iotdashboard/ShadowedBox.cpp index 80d79143..de723f20 100644 --- a/examples/iotdashboard/ShadowedBox.cpp +++ b/examples/iotdashboard/ShadowedBox.cpp @@ -59,7 +59,6 @@ namespace shadowNode->setShape( box->shape() ); shadowNode->setBlurRadius( shadowMetrics.blurRadius() ); shadowNode->setColor( box->shadowColor() ); - shadowNode->setClipRect( r ); shadowNode->updateGeometry(); diff --git a/playground/shadows/ShadowedBox.cpp b/playground/shadows/ShadowedBox.cpp index ded28d06..f9c29cd6 100644 --- a/playground/shadows/ShadowedBox.cpp +++ b/playground/shadows/ShadowedBox.cpp @@ -5,92 +5,15 @@ #include "ShadowedBox.h" -#include -#include -#include -#include -#include #include -#include - -namespace -{ - class Skinlet : public QskSkinlet - { - public: - enum NodeRole { ShadowRole, PanelRole }; - - Skinlet() - { - setOwnedBySkinnable( true ); - setNodeRoles( { ShadowRole, PanelRole } ); - } - - QRectF subControlRect( const QskSkinnable*, - const QRectF& contentsRect, QskAspect::Subcontrol subControl ) const override - { - if ( subControl == ShadowedBox::Panel ) - { - return contentsRect; - } - - return QRectF(); - } - - QSGNode* updateSubNode( const QskSkinnable* skinnable, - quint8 nodeRole, QSGNode* node ) const override - { - const auto box = static_cast< const ShadowedBox* >( skinnable ); - - const auto r = box->subControlRect( ShadowedBox::Panel ); - if ( r.isEmpty() ) - return nullptr; - - switch ( nodeRole ) - { - case ShadowRole: - { - const auto& shadowMetrics = box->shadow(); - - auto shadowNode = QskSGNode::ensureNode< QskBoxShadowNode >( node ); - - shadowNode->setRect( shadowMetrics.shadowRect( r ) ); - shadowNode->setShape( box->shape() ); - shadowNode->setBlurRadius( shadowMetrics.blurRadius() ); - shadowNode->setColor( box->shadowColor() ); - shadowNode->setClipRect( r ); - - shadowNode->updateGeometry(); - - return shadowNode; - } - case PanelRole: - { - auto boxNode = static_cast< QskBoxNode* >( node ); - if ( boxNode == nullptr ) - boxNode = new QskBoxNode(); - - const auto r = box->subControlRect( ShadowedBox::Panel ); - - boxNode->setBoxData( r, box->shape(), box->borderWidth(), - box->borderColor(), box->gradient() ); - - return boxNode; - } - } - - return nullptr; - } - }; -} - -QSK_SUBCONTROL( ShadowedBox, Panel ) +#include +#include +#include +#include ShadowedBox::ShadowedBox( QQuickItem* parentItem ) - : QskControl( parentItem ) + : QskBox( true, parentItem ) { - setFlag( QQuickItem::ItemHasContents, true ); - setSkinlet( new Skinlet() ); } ShadowedBox::~ShadowedBox() @@ -99,68 +22,32 @@ ShadowedBox::~ShadowedBox() void ShadowedBox::setShadow( const QskShadowMetrics& shadow ) { - m_shadow = shadow; - update(); -} - -const QskShadowMetrics& ShadowedBox::shadow() const -{ - return m_shadow; + setShadowMetricsHint( Panel, shadow ); } void ShadowedBox::setShadowColor( const QColor& color ) { - m_shadowColor = color; - update(); -} - -QColor ShadowedBox::shadowColor() const -{ - return m_shadowColor; + setShadowColorHint( Panel, color ); } void ShadowedBox::setGradient( const QskGradient& gradient ) { - m_gradient = gradient; - update(); -} - -const QskGradient& ShadowedBox::gradient() const -{ - return m_gradient; + setGradientHint( Panel, gradient ); } void ShadowedBox::setShape( const QskBoxShapeMetrics& shape ) { - m_shape = shape; - update(); -} - -const QskBoxShapeMetrics& ShadowedBox::shape() const -{ - return m_shape; + setBoxShapeHint( Panel, shape ); } void ShadowedBox::setBorderWidth( qreal width ) { - m_borderWidth = qMax( width, 0.0 ); - update(); + setBoxBorderMetricsHint( Panel, width ); } -qreal ShadowedBox::borderWidth() const +void ShadowedBox::setBorderColors( const QskBoxBorderColors& colors ) { - return m_borderWidth; -} - -void ShadowedBox::setBorderColor( const QColor& color ) -{ - m_borderColor = color; - update(); -} - -QColor ShadowedBox::borderColor() const -{ - return m_borderColor; + setBoxBorderColorsHint( Panel, colors ); } #include "moc_ShadowedBox.cpp" diff --git a/playground/shadows/ShadowedBox.h b/playground/shadows/ShadowedBox.h index 4f8b8dab..d3232b7d 100644 --- a/playground/shadows/ShadowedBox.h +++ b/playground/shadows/ShadowedBox.h @@ -5,47 +5,27 @@ #pragma once -#include -#include -#include +#include class QskGradient; +class QskShadowMetrics; +class QskBoxShapeMetrics; +class QskBoxBorderColors; -class ShadowedBox : public QskControl +class ShadowedBox : public QskBox { Q_OBJECT public: - QSK_SUBCONTROLS( Panel ) - ShadowedBox(QQuickItem* parent = nullptr); ~ShadowedBox() override; - void setShadow( const QskShadowMetrics& ); - const QskShadowMetrics& shadow() const; - - void setGradient( const QskGradient& ); - const QskGradient& gradient() const; - - void setShadowColor( const QColor& ); - QColor shadowColor() const; - void setShape( const QskBoxShapeMetrics& ); - const QskBoxShapeMetrics& shape() const; + void setGradient( const QskGradient& ); void setBorderWidth( qreal width ); - qreal borderWidth() const; + void setBorderColors( const QskBoxBorderColors& ); - void setBorderColor( const QColor& ); - QColor borderColor() const; - - private: - QskShadowMetrics m_shadow; - QColor m_shadowColor = Qt::black; - - QskGradient m_gradient; - QskBoxShapeMetrics m_shape; - - qreal m_borderWidth = 0.0; - QColor m_borderColor = Qt::black; + void setShadow( const QskShadowMetrics& ); + void setShadowColor( const QColor& ); }; diff --git a/playground/shadows/main.cpp b/playground/shadows/main.cpp index 90faf9cd..e1bd51a4 100644 --- a/playground/shadows/main.cpp +++ b/playground/shadows/main.cpp @@ -5,15 +5,19 @@ #include "ShadowedBox.h" -#include - -#include #include #include #include -#include #include +#include +#include +#include +#include + +#include +#include + class Box : public ShadowedBox { public: @@ -39,7 +43,7 @@ class Box : public ShadowedBox setShape( QskBoxShapeMetrics( 40, 10, 15, 5 ) ); setBorderWidth( w ); - setBorderColor( Qt::blue ); + setBorderColors( Qt::blue ); } }; diff --git a/src/common/QskBoxHints.cpp b/src/common/QskBoxHints.cpp index 9f18e9f7..f657e72f 100644 --- a/src/common/QskBoxHints.cpp +++ b/src/common/QskBoxHints.cpp @@ -4,6 +4,7 @@ *****************************************************************************/ #include "QskBoxHints.h" +#include "QskRgbValue.h" QskBoxHints::QskBoxHints() { @@ -11,18 +12,22 @@ QskBoxHints::QskBoxHints() QskBoxHints::QskBoxHints( const QskBoxShapeMetrics& shape, const QskBoxBorderMetrics& borderMetrics, - const QskBoxBorderColors& borderColors, const QskGradient& gradient ) + const QskBoxBorderColors& borderColors, const QskGradient& gradient, + const QskShadowMetrics& shadowMetrics, const QColor& shadowColor ) : shape( shape ) , borderMetrics( borderMetrics ) , borderColors( borderColors ) , gradient( gradient ) + , shadowMetrics( shadowMetrics ) + , shadowColor( shadowColor ) { } QskBoxHints QskBoxHints::toAbsolute( const QSizeF& size ) const noexcept { return QskBoxHints( shape.toAbsolute( size ), - borderMetrics.toAbsolute( size ), borderColors, gradient ); + borderMetrics.toAbsolute( size ), borderColors, gradient, + shadowMetrics.toAbsolute( size ), shadowColor ); } QskBoxHints QskBoxHints::interpolated( @@ -32,7 +37,9 @@ QskBoxHints QskBoxHints::interpolated( shape.interpolated( to.shape, value ), borderMetrics.interpolated( to.borderMetrics, value ), borderColors.interpolated( to.borderColors, value ), - gradient.interpolated( to.gradient, value ) ); + gradient.interpolated( to.gradient, value ), + shadowMetrics.interpolated( to.shadowMetrics, value ), + QskRgb::interpolated( shadowColor, to.shadowColor, value ) ); } #ifndef QT_NO_DEBUG_STREAM @@ -42,7 +49,8 @@ QskBoxHints QskBoxHints::interpolated( QDebug operator<<( QDebug debug, const QskBoxHints& hints ) { debug << hints.shape << hints.borderMetrics - << hints.borderColors << hints.gradient; + << hints.borderColors << hints.gradient << hints.shadowMetrics + << hints.shadowColor; return debug; } diff --git a/src/common/QskBoxHints.h b/src/common/QskBoxHints.h index 839b5b62..48b07550 100644 --- a/src/common/QskBoxHints.h +++ b/src/common/QskBoxHints.h @@ -9,7 +9,9 @@ #include "QskBoxBorderMetrics.h" #include "QskBoxBorderColors.h" #include "QskBoxShapeMetrics.h" +#include "QskShadowMetrics.h" #include "QskGradient.h" +#include class QSK_EXPORT QskBoxHints { @@ -19,11 +21,14 @@ class QSK_EXPORT QskBoxHints Q_PROPERTY( QskBoxBorderMetrics borderMetrics MEMBER borderMetrics ) Q_PROPERTY( QskBoxBorderColors borderColors MEMBER borderColors ) Q_PROPERTY( QskGradient gradient MEMBER gradient ) + Q_PROPERTY( QskShadowMetrics shadowMetrics MEMBER shadowMetrics ) + Q_PROPERTY( QColor shadowColor MEMBER shadowColor ) public: QskBoxHints(); QskBoxHints( const QskBoxShapeMetrics&, const QskBoxBorderMetrics&, - const QskBoxBorderColors&, const QskGradient& ); + const QskBoxBorderColors&, const QskGradient&, + const QskShadowMetrics&, const QColor& ); QskBoxHints toAbsolute( const QSizeF& ) const noexcept; @@ -34,6 +39,8 @@ class QSK_EXPORT QskBoxHints QskBoxBorderMetrics borderMetrics; QskBoxBorderColors borderColors; QskGradient gradient; + QskShadowMetrics shadowMetrics; + QColor shadowColor; }; #ifndef QT_NO_DEBUG_STREAM diff --git a/src/controls/QskSkinlet.cpp b/src/controls/QskSkinlet.cpp index 29fc172b..fbb7359e 100644 --- a/src/controls/QskSkinlet.cpp +++ b/src/controls/QskSkinlet.cpp @@ -12,6 +12,7 @@ #include "QskBoxBorderMetrics.h" #include "QskBoxClipNode.h" #include "QskBoxNode.h" +#include "QskShadedBoxNode.h" #include "QskBoxShapeMetrics.h" #include "QskBoxHints.h" #include "QskColorFilter.h" @@ -166,26 +167,30 @@ static inline QskTextColors qskTextColors( return c; } -static inline QSGNode* qskUpdateBoxNode( +static inline QSGNode* qskUpdateShadedBoxNode( const QskSkinnable*, QSGNode* node, const QRectF& rect, const QskBoxShapeMetrics& shape, const QskBoxBorderMetrics& borderMetrics, - const QskBoxBorderColors& borderColors, const QskGradient& gradient ) + const QskBoxBorderColors& borderColors, const QskGradient& gradient, + const QskShadowMetrics& shadowMetrics, const QColor& shadowColor ) { if ( rect.isEmpty() ) return nullptr; - const auto absoluteMetrics = borderMetrics.toAbsolute( rect.size() ); + const auto size = rect.size(); + + const auto absoluteMetrics = borderMetrics.toAbsolute( size ); if ( qskIsBoxVisible( absoluteMetrics, borderColors, gradient ) ) { - auto boxNode = static_cast< QskBoxNode* >( node ); + auto boxNode = static_cast< QskShadedBoxNode* >( node ); if ( boxNode == nullptr ) - boxNode = new QskBoxNode(); + boxNode = new QskShadedBoxNode(); - const auto absoluteShape = shape.toAbsolute( rect.size() ); + const auto absoluteShape = shape.toAbsolute( size ); + const auto absoluteShadowMetrics = shadowMetrics.toAbsolute( size ); - boxNode->setBoxData( rect, absoluteShape, - absoluteMetrics, borderColors, gradient ); + boxNode->setBoxData( rect, absoluteShape, absoluteMetrics, + borderColors, gradient, absoluteShadowMetrics, shadowColor ); return boxNode; } @@ -402,9 +407,12 @@ QSGNode* QskSkinlet::updateBoxNode( const QskSkinnable* skinnable, const auto borderMetrics = skinnable->boxBorderMetricsHint( subControl ); const auto borderColors = skinnable->boxBorderColorsHint( subControl ); const auto shape = skinnable->boxShapeHint( subControl ); + const auto shadowMetrics = skinnable->shadowMetricsHint( subControl ); + const auto shadowColor = skinnable->shadowColorHint( subControl ); - return qskUpdateBoxNode( skinnable, node, - boxRect, shape, borderMetrics, borderColors, fillGradient ); + return qskUpdateShadedBoxNode( skinnable, node, + boxRect, shape, borderMetrics, borderColors, fillGradient, + shadowMetrics, shadowColor ); } QSGNode* QskSkinlet::updateBoxNode( @@ -412,15 +420,17 @@ QSGNode* QskSkinlet::updateBoxNode( const QskBoxShapeMetrics& shape, const QskBoxBorderMetrics& borderMetrics, const QskBoxBorderColors& borderColors, const QskGradient& fillGradient ) { - return qskUpdateBoxNode( skinnable, node, - rect, shape, borderMetrics, borderColors, fillGradient ); + return qskUpdateShadedBoxNode( skinnable, node, + rect, shape, borderMetrics, borderColors, fillGradient, + QskShadowMetrics(), QColor() ); } QSGNode* QskSkinlet::updateBoxNode( const QskSkinnable* skinnable, QSGNode* node, const QRectF& rect, const QskBoxHints& hints ) { - return qskUpdateBoxNode( skinnable, node, rect, - hints.shape, hints.borderMetrics, hints.borderColors, hints.gradient ); + return qskUpdateShadedBoxNode( skinnable, node, rect, + hints.shape, hints.borderMetrics, hints.borderColors, hints.gradient, + hints.shadowMetrics, hints.shadowColor ); } QSGNode* QskSkinlet::updateInterpolatedBoxNode( diff --git a/src/controls/QskSkinnable.cpp b/src/controls/QskSkinnable.cpp index 269f5f87..e3fad4ff 100644 --- a/src/controls/QskSkinnable.cpp +++ b/src/controls/QskSkinnable.cpp @@ -613,7 +613,8 @@ QskBoxHints QskSkinnable::boxHints( QskAspect aspect ) const { return QskBoxHints( boxShapeHint( aspect ), boxBorderMetricsHint( aspect ), - boxBorderColorsHint( aspect ), gradientHint( aspect ) ); + boxBorderColorsHint( aspect ), gradientHint( aspect ), + shadowMetricsHint( aspect ), shadowColorHint( aspect ) ); } bool QskSkinnable::setArcMetricsHint( diff --git a/src/nodes/QskBoxShadowNode.cpp b/src/nodes/QskBoxShadowNode.cpp index 94e0af65..0c519c79 100644 --- a/src/nodes/QskBoxShadowNode.cpp +++ b/src/nodes/QskBoxShadowNode.cpp @@ -346,10 +346,10 @@ void QskBoxShadowNode::setBlurRadius( qreal blurRadius ) } } -void QskBoxShadowNode::setClipRect( const QRectF& ) +void QskBoxShadowNode::setClipShape( const QskBoxShapeMetrics& ) { /* - Usually only the parts, that are not covered by the related rectangle + Usually only the parts, that are not covered by the related box should be painted. TODO ... */ } diff --git a/src/nodes/QskBoxShadowNode.h b/src/nodes/QskBoxShadowNode.h index e3af8aa3..25f09a10 100644 --- a/src/nodes/QskBoxShadowNode.h +++ b/src/nodes/QskBoxShadowNode.h @@ -25,8 +25,9 @@ class QSK_EXPORT QskBoxShadowNode : public QSGGeometryNode void setColor( const QColor& ); void setBlurRadius( qreal ); + void setClipShape( const QskBoxShapeMetrics& ); + void updateGeometry(); - void setClipRect( const QRectF& ); private: Q_DECLARE_PRIVATE( QskBoxShadowNode ) diff --git a/src/nodes/QskShadedBoxNode.cpp b/src/nodes/QskShadedBoxNode.cpp new file mode 100644 index 00000000..83e0d132 --- /dev/null +++ b/src/nodes/QskShadedBoxNode.cpp @@ -0,0 +1,58 @@ +/****************************************************************************** + * QSkinny - Copyright (C) 2016 Uwe Rathmann + * This file may be used under the terms of the QSkinny License, Version 1.0 + *****************************************************************************/ + +#include "QskShadedBoxNode.h" +#include "QskBoxShadowNode.h" +#include "QskShadowMetrics.h" +#include + +QskShadedBoxNode::QskShadedBoxNode() +{ + m_boxNode.setFlag( QSGNode::OwnedByParent, false ); + appendChildNode( &m_boxNode ); +} + +QskShadedBoxNode::~QskShadedBoxNode() +{ +} + +void QskShadedBoxNode::setBoxData( const QRectF& rect, + const QskBoxShapeMetrics& shape, const QskBoxBorderMetrics& borderMetrics, + const QskBoxBorderColors& borderColors, const QskGradient& gradient, + const QskShadowMetrics& shadowMetrics, const QColor& shadowColor ) +{ + m_boxNode.setBoxData( rect, shape, borderMetrics, borderColors, gradient ); + setShadowData( rect, shape, shadowMetrics, shadowColor ); +} + +void QskShadedBoxNode::setShadowData( + const QRectF& rect, const QskBoxShapeMetrics& shape, + const QskShadowMetrics& metrics, const QColor& color ) +{ + if ( metrics.isNull() || !color.isValid() || color.alpha() == 0 ) + { + if ( m_shadowNode ) + { + removeChildNode( m_shadowNode ); + delete m_shadowNode; + m_shadowNode = nullptr; + } + } + else + { + if ( m_shadowNode == nullptr ) + { + m_shadowNode = new QskBoxShadowNode(); + insertChildNodeBefore( m_shadowNode, &m_boxNode ); + } + + m_shadowNode->setRect( metrics.shadowRect( rect ) ); + m_shadowNode->setShape( shape ); + m_shadowNode->setBlurRadius( metrics.blurRadius() ); + m_shadowNode->setClipShape( shape ); + + m_shadowNode->updateGeometry(); + } +} diff --git a/src/nodes/QskShadedBoxNode.h b/src/nodes/QskShadedBoxNode.h new file mode 100644 index 00000000..cfff372f --- /dev/null +++ b/src/nodes/QskShadedBoxNode.h @@ -0,0 +1,34 @@ +/****************************************************************************** + * QSkinny - Copyright (C) 2016 Uwe Rathmann + * This file may be used under the terms of the QSkinny License, Version 1.0 + *****************************************************************************/ + +#ifndef QSK_SHADED_BOX_NODE_H +#define QSK_SHADED_BOX_NODE_H + +#include "QskGlobal.h" +#include "QskBoxNode.h" + +class QskBoxShadowNode; +class QskShadowMetrics; + +class QSK_EXPORT QskShadedBoxNode : public QSGNode +{ + public: + QskShadedBoxNode(); + ~QskShadedBoxNode() override; + + void setBoxData( const QRectF&, + const QskBoxShapeMetrics&, const QskBoxBorderMetrics&, + const QskBoxBorderColors&, const QskGradient&, + const QskShadowMetrics&, const QColor& shadowColor ); + + private: + void setShadowData( const QRectF&, const QskBoxShapeMetrics&, + const QskShadowMetrics&, const QColor& ); + + QskBoxNode m_boxNode; + QskBoxShadowNode* m_shadowNode = nullptr; +}; + +#endif diff --git a/src/src.pro b/src/src.pro index 904bf604..dbc58db8 100644 --- a/src/src.pro +++ b/src/src.pro @@ -110,6 +110,7 @@ HEADERS += \ nodes/QskRichTextRenderer.h \ nodes/QskScaleRenderer.h \ nodes/QskSGNode.h \ + nodes/QskShadedBoxNode.h \ nodes/QskTextNode.h \ nodes/QskTextRenderer.h \ nodes/QskTextureRenderer.h \ @@ -131,6 +132,7 @@ SOURCES += \ nodes/QskRichTextRenderer.cpp \ nodes/QskScaleRenderer.cpp \ nodes/QskSGNode.cpp \ + nodes/QskShadedBoxNode.cpp \ nodes/QskTextNode.cpp \ nodes/QskTextRenderer.cpp \ nodes/QskTextureRenderer.cpp \