/****************************************************************************** * QSkinny - Copyright (C) 2016 Uwe Rathmann * SPDX-License-Identifier: BSD-3-Clause *****************************************************************************/ #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 ); } void QskSGNode::setParentNode( QSGNode* node, QSGNode* parent ) { if ( node ) { auto oldParent = node->parent(); if ( oldParent != parent ) { if ( oldParent ) oldParent->removeChildNode( node ); if ( parent ) parent->appendChildNode( node ); } } } QSGNode* QskSGNode::findChildNode( QSGNode* parent, quint8 role ) { auto node = parent->firstChild(); while ( node ) { if ( nodeRole( node ) == role ) return node; node = node->nextSibling(); } return nullptr; } bool QskSGNode::removeChildNode( QSGNode* parent, quint8 role ) { if ( auto node = findChildNode( parent, role ) ) { qskRemoveChildNode( parent, node ); return true; } return false; } 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; } } void QskSGNode::resetGeometry( QSGGeometryNode* node ) { if ( node ) { if ( auto g = node->geometry() ) { if ( g->vertexCount() > 0 || g->indexCount() > 0 ) { g->allocate( 0, 0 ); node->markDirty( QSGNode::DirtyGeometry ); } } } }