diff --git a/examples/frames/Frame.cpp b/examples/frames/Frame.cpp index 57bd7637..e859070b 100644 --- a/examples/frames/Frame.cpp +++ b/examples/frames/Frame.cpp @@ -10,7 +10,7 @@ #include #include #include -#include +#include static inline qreal effectiveRadius( const QRectF& rect, qreal percentage ) { @@ -100,7 +100,7 @@ void Frame::updateNode( QSGNode* parentNode ) const quint8 nodeRole = 0; auto node = static_cast< QskBoxNode* >( - QskSkinlet::findNodeByRole( parentNode, nodeRole ) ); + QskSGNode::findChildNode( parentNode, nodeRole ) ); const QRectF rect = contentsRect(); if ( rect.isEmpty() ) @@ -112,7 +112,7 @@ void Frame::updateNode( QSGNode* parentNode ) if ( node == nullptr ) { node = new QskBoxNode; - QskSkinlet::setNodeRole( node, nodeRole ); + QskSGNode::setNodeRole( node, nodeRole ); } updateFrameNode( rect, node ); diff --git a/src/controls/QskListViewSkinlet.cpp b/src/controls/QskListViewSkinlet.cpp index eb39616c..a13e42db 100644 --- a/src/controls/QskListViewSkinlet.cpp +++ b/src/controls/QskListViewSkinlet.cpp @@ -8,6 +8,7 @@ #include "QskColorFilter.h" #include "QskGraphic.h" +#include "QskSGNode.h" #include #include @@ -431,6 +432,8 @@ QSGTransformNode* QskListViewSkinlet::updateForegroundNode( QSGNode* QskListViewSkinlet::updateCellNode( const QskListView* listView, QSGNode* contentNode, const QRectF& rect, int row, int col ) const { + using namespace QskSGNode; + QSGNode* newNode = nullptr; #if 1 diff --git a/src/controls/QskPageIndicatorSkinlet.cpp b/src/controls/QskPageIndicatorSkinlet.cpp index f7bea195..c03a73ab 100644 --- a/src/controls/QskPageIndicatorSkinlet.cpp +++ b/src/controls/QskPageIndicatorSkinlet.cpp @@ -7,6 +7,7 @@ #include "QskPageIndicator.h" #include "QskBoxNode.h" +#include "QskSGNode.h" QskPageIndicatorSkinlet::QskPageIndicatorSkinlet( QskSkin* skin ) : QskSkinlet( skin ) @@ -162,7 +163,7 @@ QSGNode* QskPageIndicatorSkinlet::updateBulletsNode( } // if count has decreased we need to remove superfluous nodes - removeTraillingNodes( node, bulletNode ); + QskSGNode::removeAllChildNodesAfter( node, bulletNode ); return node; } diff --git a/src/controls/QskScrollArea.cpp b/src/controls/QskScrollArea.cpp index c935c745..7eb9dc84 100644 --- a/src/controls/QskScrollArea.cpp +++ b/src/controls/QskScrollArea.cpp @@ -8,6 +8,7 @@ #include "QskQuick.h" #include "QskScrollViewSkinlet.h" #include "QskBoxBorderMetrics.h" +#include "QskSGNode.h" QSK_QT_PRIVATE_BEGIN #include @@ -322,7 +323,7 @@ namespace { auto node = const_cast< QSGNode* >( qskPaintNode( scrollArea() ) ); if ( node ) - node = QskSkinlet::findNodeByRole( node, QskScrollViewSkinlet::ContentsRootRole ); + node = QskSGNode::findChildNode( node, QskScrollViewSkinlet::ContentsRootRole ); if ( node && node->type() == QSGNode::ClipNodeType ) return static_cast< QSGClipNode* >( node ); diff --git a/src/controls/QskScrollViewSkinlet.cpp b/src/controls/QskScrollViewSkinlet.cpp index debb4715..2d230d7f 100644 --- a/src/controls/QskScrollViewSkinlet.cpp +++ b/src/controls/QskScrollViewSkinlet.cpp @@ -8,6 +8,7 @@ #include "QskAspect.h" #include "QskQuick.h" +#include "QskSGNode.h" #include @@ -129,8 +130,8 @@ QSGNode* QskScrollViewSkinlet::updateContentsRootNode( if ( clipNode == nullptr ) return nullptr; - QSGNode* oldContentsNode = findNodeByRole( clipNode, ContentsRootRole ); - QSGNode* contentsNode = updateContentsNode( scrollView, oldContentsNode ); + auto oldContentsNode = QskSGNode::findChildNode( clipNode, ContentsRootRole ); + auto contentsNode = updateContentsNode( scrollView, oldContentsNode ); if ( contentsNode ) { @@ -141,7 +142,7 @@ QSGNode* QskScrollViewSkinlet::updateContentsRootNode( For those situations we need to set a node role, that we can decide which child of the clip node needs to be replaced. */ - setNodeRole( contentsNode, ContentsRootRole ); + QskSGNode::setNodeRole( contentsNode, ContentsRootRole ); if ( contentsNode->parent() != clipNode ) clipNode->appendChildNode( contentsNode ); @@ -169,7 +170,7 @@ QSGNode* QskScrollViewSkinlet::contentsNode( const QskScrollView* scrollView ) QSGNode* node = const_cast< QSGNode* >( qskPaintNode( scrollView ) ); if ( node ) { - node = findNodeByRole( node, ContentsRootRole ); + node = QskSGNode::findChildNode( node, ContentsRootRole ); if ( node ) { node = node->firstChild(); diff --git a/src/controls/QskSkinlet.cpp b/src/controls/QskSkinlet.cpp index ce859c88..644320d2 100644 --- a/src/controls/QskSkinlet.cpp +++ b/src/controls/QskSkinlet.cpp @@ -17,47 +17,14 @@ #include "QskGradient.h" #include "QskGraphicNode.h" #include "QskGraphic.h" +#include "QskSGNode.h" #include "QskTextColors.h" #include "QskTextNode.h" #include "QskTextOptions.h" -#include #include #include -static const int qskBackgroundRole = 254; -static const int qskDebugRole = 253; - -static inline QSGNode::Flags qskNodeFlags( quint8 nodeRole ) -{ - return static_cast< QSGNode::Flags >( ( nodeRole + 1 ) << 8 ); -} - -static inline quint8 qskRole( const QSGNode* node ) -{ - return static_cast< quint8 >( ( ( node->flags() & 0x0ffff ) >> 8 ) - 1 ); -} - -static inline void qskSetRole( quint8 nodeRole, QSGNode* node ) -{ - const QSGNode::Flags flags = qskNodeFlags( nodeRole ); - node->setFlags( node->flags() | flags ); -} - -static inline QSGNode* qskFindNodeByFlag( QSGNode* parent, int nodeRole ) -{ - auto node = parent->firstChild(); - while ( node ) - { - if ( qskRole( node ) == nodeRole ) - return node; - - node = node->nextSibling(); - } - - return nullptr; -} - static inline QRectF qskSubControlRect( const QskSkinlet* skinlet, const QskSkinnable* skinnable, QskAspect::Subcontrol subControl ) { @@ -200,6 +167,8 @@ const QVector< quint8 >& QskSkinlet::nodeRoles() const void QskSkinlet::updateNode( QskSkinnable* skinnable, QSGNode* parentNode ) const { + using namespace QskSGNode; + QSGNode* oldNode; QSGNode* newNode; @@ -207,35 +176,35 @@ void QskSkinlet::updateNode( QskSkinnable* skinnable, QSGNode* parentNode ) cons { // background - oldNode = qskFindNodeByFlag( parentNode, qskBackgroundRole ); + oldNode = findChildNode( parentNode, BackgroundRole ); newNode = nullptr; if ( control->autoFillBackground() ) newNode = updateBackgroundNode( control, oldNode ); - insertRemoveNodes( parentNode, oldNode, newNode, qskBackgroundRole ); + replaceChildNode( BackgroundRole, parentNode, oldNode, newNode ); // debug - oldNode = qskFindNodeByFlag( parentNode, qskDebugRole ); + oldNode = findChildNode( parentNode, DebugRole ); newNode = nullptr; if ( control->testControlFlag( QskControl::DebugForceBackground ) ) newNode = updateDebugNode( control, oldNode ); - insertRemoveNodes( parentNode, oldNode, newNode, qskDebugRole ); + replaceChildNode( DebugRole, parentNode, oldNode, newNode ); } for ( int i = 0; i < m_data->nodeRoles.size(); i++ ) { const auto nodeRole = m_data->nodeRoles[ i ]; - Q_ASSERT( nodeRole <= 245 ); // reserving 10 roles + Q_ASSERT( nodeRole < FirstReservedRole ); - oldNode = qskFindNodeByFlag( parentNode, nodeRole ); + oldNode = QskSGNode::findChildNode( parentNode, nodeRole ); newNode = updateSubNode( skinnable, nodeRole, oldNode ); - insertRemoveNodes( parentNode, oldNode, newNode, nodeRole ); + replaceChildNode( nodeRole, parentNode, oldNode, newNode ); } } @@ -262,9 +231,7 @@ QSGNode* QskSkinlet::updateDebugNode( const QskControl* control, QSGNode* node ) const { if ( control->size().isEmpty() ) - { return nullptr; - } auto rectNode = static_cast< QSGSimpleRectNode* >( node ); if ( rectNode == nullptr ) @@ -290,125 +257,24 @@ QSGNode* QskSkinlet::updateDebugNode( rectNode->setColor( color ); } - const QRectF r = control->rect(); + const auto r = control->rect(); if ( rectNode->rect() != r ) rectNode->setRect( r ); return rectNode; } -void QskSkinlet::insertRemoveNodes( QSGNode* parentNode, - QSGNode* oldNode, QSGNode* newNode, quint8 nodeRole ) const +void QskSkinlet::replaceChildNode( quint8 role, + QSGNode* parentNode, QSGNode* oldNode, QSGNode* newNode ) const { - if ( newNode && newNode->parent() != parentNode ) - { - qskSetRole( nodeRole, newNode ); - - switch ( nodeRole ) - { - case qskBackgroundRole: - { - parentNode->prependChildNode( newNode ); - break; - } - case qskDebugRole: - { - QSGNode* firstNode = parentNode->firstChild(); - - if ( firstNode && ( qskRole( firstNode ) == qskBackgroundRole ) ) - parentNode->insertChildNodeAfter( newNode, firstNode ); - else - parentNode->prependChildNode( newNode ); - - break; - } - default: - { - insertNodeSorted( newNode, parentNode ); - } - } - } - - if ( oldNode && oldNode != newNode ) - { - parentNode->removeChildNode( oldNode ); - if ( oldNode->flags() & QSGNode::OwnedByParent ) - delete oldNode; - } -} - -void QskSkinlet::insertNodeSorted( QSGNode* node, QSGNode* parentNode ) const -{ - QSGNode* sibling = nullptr; - - if ( parentNode->childCount() > 0 ) - { - const int nodePos = m_data->nodeRoles.indexOf( qskRole( node ) ); - - // in most cases we are appending, so let's start at the end - - for ( QSGNode* childNode = parentNode->lastChild(); - childNode != nullptr; childNode = childNode->previousSibling() ) - { - const auto childNodeRole = qskRole( childNode ); - if ( childNodeRole == qskBackgroundRole ) - { - sibling = childNode; - } - else - { - /* - Imperformant implementation, but as the number of roles is - usually < 5 we don't introduce some sort of support for faster lookups - */ - - const int index = m_data->nodeRoles.indexOf( qskRole( childNode ) ); - if ( index >= 0 && index < nodePos ) - sibling = childNode; - } - - if ( sibling != nullptr ) - break; - } - } - - if ( sibling ) - parentNode->insertChildNodeAfter( node, sibling ); - else - parentNode->prependChildNode( node ); -} - -void QskSkinlet::removeTraillingNodes( QSGNode* node, QSGNode* child ) -{ - if ( node && child ) - { - while ( auto sibling = child->nextSibling() ) - { - node->removeChildNode( sibling ); - delete sibling; - } - } -} - -void QskSkinlet::setNodeRole( QSGNode* node, quint8 nodeRole ) -{ - qskSetRole( nodeRole, node ); -} - -quint8 QskSkinlet::nodeRole( const QSGNode* node ) -{ - return node ? qskRole( node ) : 0; -} - -QSGNode* QskSkinlet::findNodeByRole( QSGNode* parent, quint8 nodeRole ) -{ - return qskFindNodeByFlag( parent, nodeRole ); + QskSGNode::replaceChildNode( + m_data->nodeRoles, role, parentNode, oldNode, newNode ); } QSGNode* QskSkinlet::updateBoxNode( const QskSkinnable* skinnable, QSGNode* node, QskAspect::Subcontrol subControl ) const { - const QRectF rect = qskSubControlRect( this, skinnable, subControl ); + const auto rect = qskSubControlRect( this, skinnable, subControl ); return updateBoxNode( skinnable, node, rect, subControl ); } @@ -425,9 +291,9 @@ QSGNode* QskSkinlet::updateBoxNode( const QskSkinnable* skinnable, { using namespace QskAspect; - const QMarginsF margins = skinnable->marginsHint( subControl | Margin ); + const auto margins = skinnable->marginsHint( subControl | Margin ); - const QRectF boxRect = rect.marginsRemoved( margins ); + const auto boxRect = rect.marginsRemoved( margins ); if ( boxRect.isEmpty() ) return nullptr; @@ -454,7 +320,7 @@ QSGNode* QskSkinlet::updateBoxNode( const QskSkinnable* skinnable, QSGNode* QskSkinlet::updateBoxClipNode( const QskSkinnable* skinnable, QSGNode* node, QskAspect::Subcontrol subControl ) const { - const QRectF rect = qskSubControlRect( this, skinnable, subControl ); + const auto rect = qskSubControlRect( this, skinnable, subControl ); return updateBoxClipNode( skinnable, node, rect, subControl ); } @@ -467,9 +333,9 @@ QSGNode* QskSkinlet::updateBoxClipNode( const QskSkinnable* skinnable, if ( clipNode == nullptr ) clipNode = new QskBoxClipNode(); - const QMarginsF margins = skinnable->marginsHint( subControl | Margin ); + const auto margins = skinnable->marginsHint( subControl | Margin ); - const QRectF clipRect = rect.marginsRemoved( margins ); + const auto clipRect = rect.marginsRemoved( margins ); if ( clipRect.isEmpty() ) { clipNode->setIsRectangular( true ); @@ -502,7 +368,7 @@ QSGNode* QskSkinlet::updateTextNode( if ( textNode == nullptr ) textNode = new QskTextNode(); - auto colors = qskTextColors( skinnable, subControl ); + const auto colors = qskTextColors( skinnable, subControl ); auto textStyle = Qsk::Normal; if ( colors.styleColor.alpha() == 0 ) @@ -542,7 +408,7 @@ QSGNode* QskSkinlet::updateTextNode( const QString& text, const QskTextOptions& textOptions, QskAspect::Subcontrol subControl ) const { - const QRectF rect = qskSubControlRect( this, skinnable, subControl ); + const auto rect = qskSubControlRect( this, skinnable, subControl ); const auto alignment = skinnable->flagHint< Qt::Alignment >( QskAspect::Alignment | subControl, Qt::AlignLeft ); @@ -555,9 +421,9 @@ QSGNode* QskSkinlet::updateGraphicNode( const QskGraphic& graphic, QskAspect::Subcontrol subcontrol, Qt::Orientations mirrored ) const { - const QRectF rect = qskSubControlRect( this, skinnable, subcontrol ); + const auto rect = qskSubControlRect( this, skinnable, subcontrol ); - const Qt::Alignment alignment = skinnable->flagHint< Qt::Alignment >( + const auto alignment = skinnable->flagHint< Qt::Alignment >( subcontrol | QskAspect::Alignment, Qt::AlignCenter ); const auto colorFilter = skinnable->effectiveGraphicFilter( subcontrol ); @@ -574,10 +440,10 @@ QSGNode* QskSkinlet::updateGraphicNode( if ( graphic.isNull() ) return nullptr; - const QSizeF size = graphic.defaultSize().scaled( + const auto size = graphic.defaultSize().scaled( rect.size(), Qt::KeepAspectRatio ); - const QRectF r = qskAlignedRectF( rect, size.width(), size.height(), alignment ); + const auto r = qskAlignedRectF( rect, size.width(), size.height(), alignment ); return qskUpdateGraphicNode( skinnable, node, graphic, colorFilter, r, mirrored ); } diff --git a/src/controls/QskSkinlet.h b/src/controls/QskSkinlet.h index 2ecbba4c..dc219dc4 100644 --- a/src/controls/QskSkinlet.h +++ b/src/controls/QskSkinlet.h @@ -47,12 +47,6 @@ class QSK_EXPORT QskSkinlet void setOwnedBySkinnable( bool on ); bool isOwnedBySkinnable() const; - static void setNodeRole( QSGNode* node, quint8 nodeRole ); - static quint8 nodeRole( const QSGNode* node ); - static void removeTraillingNodes( QSGNode* node, QSGNode* child ); - - static QSGNode* findNodeByRole( QSGNode* parent, quint8 nodeRole ); - static QSGNode* updateBoxNode( const QskSkinnable*, QSGNode*, const QRectF&, QskAspect::Subcontrol ); @@ -102,12 +96,10 @@ class QSK_EXPORT QskSkinlet const QskGraphic&, QskAspect::Subcontrol, Qt::Orientations mirrored = Qt::Orientations() ) const; - void insertRemoveNodes( QSGNode* parentNode, - QSGNode* oldNode, QSGNode* newNode, quint8 nodeRole ) const; + void replaceChildNode( quint8 nodeRole, QSGNode* parentNode, + QSGNode* oldNode, QSGNode* newNode ) const; private: - void insertNodeSorted( QSGNode* node, QSGNode* parentNode ) const; - class PrivateData; std::unique_ptr< PrivateData > m_data; }; diff --git a/src/nodes/QskSGNode.cpp b/src/nodes/QskSGNode.cpp new file mode 100644 index 00000000..c6d73439 --- /dev/null +++ b/src/nodes/QskSGNode.cpp @@ -0,0 +1,140 @@ +/****************************************************************************** + * QSkinny - Copyright (C) 2016 Uwe Rathmann + * This file may be used under the terms of the QSkinny License, Version 1.0 + *****************************************************************************/ + +#include "QskSGNode.h" + +static inline void qskRemoveChildNode( QSGNode* parent, QSGNode* child ) +{ + parent->removeChildNode( child ); + + if ( child->flags() & QSGNode::OwnedByParent ) + delete child; + +} + +static inline void qskRemoveAllChildNodesAfter( QSGNode* parent, QSGNode* child ) +{ + while ( auto sibling = parent->lastChild() ) + { + if ( sibling == child ) + return; + + qskRemoveChildNode( parent, sibling ); + } +} + +static void qskInsertChildSorted( QSGNode* parent, QSGNode* child, + const QVector< quint8 >& roles ) +{ + QSGNode* sibling = nullptr; + + if ( parent->childCount() > 0 ) + { + using namespace QskSGNode; + + const int nodePos = roles.indexOf( nodeRole( child ) ); + + // in most cases we are appending, so let's start at the end + + for ( auto childNode = parent->lastChild(); + childNode != nullptr; childNode = childNode->previousSibling() ) + { + const auto childNodeRole = nodeRole( childNode ); + if ( childNodeRole == BackgroundRole ) + { + sibling = childNode; + } + else + { + /* + Imperformant implementation, but as the number of roles is + usually < 5 we don't introduce some sort of support for faster lookups + */ + + const int index = roles.indexOf( nodeRole( childNode ) ); + if ( index >= 0 && index < nodePos ) + sibling = childNode; + } + + if ( sibling != nullptr ) + break; + } + } + + if ( sibling ) + parent->insertChildNodeAfter( child, sibling ); + else + parent->prependChildNode( child ); +} + +QSGNode* QskSGNode::findChildNode( QSGNode* parent, quint8 role ) +{ + auto node = parent->firstChild(); + while ( node ) + { + if ( nodeRole( node ) == role ) + return node; + + node = node->nextSibling(); + } + + return nullptr; +} + +void QskSGNode::removeAllChildNodesAfter( QSGNode* parent, QSGNode* child ) +{ + if ( parent && child && child->parent() == parent ) + qskRemoveAllChildNodesAfter( parent, child ); +} + +void QskSGNode::removeAllChildNodesFrom( QSGNode* parent, QSGNode* child ) +{ + if ( parent && child && child->parent() == parent ) + { + qskRemoveAllChildNodesAfter( parent, child ); + qskRemoveChildNode( parent, child ); + } +} + +void QskSGNode::replaceChildNode( + const QVector< quint8 >& roles, quint8 role, + QSGNode* parentNode, QSGNode* oldNode, QSGNode* newNode ) +{ + if ( newNode && newNode->parent() != parentNode ) + { + setNodeRole( newNode, role ); + + switch ( role ) + { + case BackgroundRole: + { + parentNode->prependChildNode( newNode ); + break; + } + case DebugRole: + { + auto firstNode = parentNode->firstChild(); + + if ( firstNode && ( nodeRole( firstNode ) == BackgroundRole ) ) + parentNode->insertChildNodeAfter( newNode, firstNode ); + else + parentNode->prependChildNode( newNode ); + + break; + } + default: + { + qskInsertChildSorted( parentNode, newNode, roles ); + } + } + } + + if ( oldNode && oldNode != newNode ) + { + parentNode->removeChildNode( oldNode ); + if ( oldNode->flags() & QSGNode::OwnedByParent ) + delete oldNode; + } +} diff --git a/src/nodes/QskSGNode.h b/src/nodes/QskSGNode.h new file mode 100644 index 00000000..04a389f3 --- /dev/null +++ b/src/nodes/QskSGNode.h @@ -0,0 +1,77 @@ +/****************************************************************************** + * QSkinny - Copyright (C) 2016 Uwe Rathmann + * This file may be used under the terms of the QSkinny License, Version 1.0 + *****************************************************************************/ + +#ifndef QSK_SG_NODE_H +#define QSK_SG_NODE_H + +#include "QskGlobal.h" +#include + +namespace QskSGNode +{ + enum Role : quint8 + { + FirstReservedRole = 0xff - 10, + + DebugRole = 0xff - 2, + BackgroundRole, + + NoRole + }; + + inline QSGNode::Flags nodeRoleFlags( quint8 role ) + { + return static_cast< QSGNode::Flags >( ( role + 1 ) << 8 ); + } + + inline quint8 nodeRole( QSGNode::Flags flags ) + { + return static_cast< quint8 >( ( ( flags & 0x0ffff ) >> 8 ) - 1 ); + } + + inline quint8 nodeRole( const QSGNode* node ) + { + return node ? nodeRole( node->flags() ) : 0xff; + } + + inline void setNodeRole( QSGNode* node, quint8 role ) + { + if ( node ) + node->setFlags( node->flags() | nodeRoleFlags( role ) ); + } + + QSK_EXPORT QSGNode* findChildNode( QSGNode* parent, quint8 role ); + + // nodeRoles: sort order + QSK_EXPORT void replaceChildNode( + const QVector< quint8 >& roles, quint8 role, + QSGNode* parentNode, QSGNode* oldNode, QSGNode* newNode ); + + // without child + QSK_EXPORT void removeAllChildNodesAfter( QSGNode* parent, QSGNode* child ); + + // including child + QSK_EXPORT void removeAllChildNodesFrom( QSGNode* parent, QSGNode* child ); + + template< typename Node > + inline Node* createNode( quint8 role ) + { + auto node = new Node(); + setNodeRole( node, role ); + + return node; + } + + template< typename Node > + inline Node* appendChildNode( QSGNode* parent, quint8 role ) + { + auto node = createNode< Node >( role ); + parent->appendChildNode( node ); + + return node; + } +} + +#endif diff --git a/src/src.pro b/src/src.pro index 13d63a12..174c1e0c 100644 --- a/src/src.pro +++ b/src/src.pro @@ -92,6 +92,7 @@ HEADERS += \ nodes/QskPaintedNode.h \ nodes/QskPlainTextRenderer.h \ nodes/QskRichTextRenderer.h \ + nodes/QskSGNode.h \ nodes/QskTextNode.h \ nodes/QskTextRenderer.h \ nodes/QskTextureNode.h \ @@ -109,6 +110,7 @@ SOURCES += \ nodes/QskPaintedNode.cpp \ nodes/QskPlainTextRenderer.cpp \ nodes/QskRichTextRenderer.cpp \ + nodes/QskSGNode.cpp \ nodes/QskTextNode.cpp \ nodes/QskTextRenderer.cpp \ nodes/QskTextureNode.cpp \