diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 237d1577..7ce13c74 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -115,6 +115,7 @@ list(APPEND HEADERS nodes/QskRichTextRenderer.h nodes/QskScaleRenderer.h nodes/QskSGNode.h + nodes/QskSlideInNode.h nodes/QskStrokeNode.h nodes/QskStippledLineRenderer.h nodes/QskShapeNode.h @@ -146,6 +147,7 @@ list(APPEND SOURCES nodes/QskRichTextRenderer.cpp nodes/QskScaleRenderer.cpp nodes/QskSGNode.cpp + nodes/QskSlideInNode.cpp nodes/QskStrokeNode.cpp nodes/QskStippledLineRenderer.cpp nodes/QskShapeNode.cpp diff --git a/src/controls/QskMenuSkinlet.cpp b/src/controls/QskMenuSkinlet.cpp index 0629b137..d75323a9 100644 --- a/src/controls/QskMenuSkinlet.cpp +++ b/src/controls/QskMenuSkinlet.cpp @@ -9,12 +9,14 @@ #include "QskGraphic.h" #include "QskColorFilter.h" #include "QskTextOptions.h" -#include "QskSGNode.h" #include "QskFunctions.h" #include "QskMargins.h" #include "QskFunctions.h" #include "QskLabelData.h" +#include "QskSGNode.h" +#include "QskSlideInNode.h" + #include #include @@ -209,11 +211,44 @@ QskMenuSkinlet::QskMenuSkinlet( QskSkin* skin ) : Inherited( skin ) , m_data( new PrivateData() ) { - appendNodeRoles( { PanelRole } ); + appendNodeRoles( { ContentsRole, PanelRole } ); } QskMenuSkinlet::~QskMenuSkinlet() = default; +QSGNode* QskMenuSkinlet::updateSubNode( + const QskSkinnable* skinnable, quint8 nodeRole, QSGNode* node ) const +{ + switch ( nodeRole ) + { + case ContentsRole: + { + /* + QskSlideInNode works for controls made of nodes - not for + containers of other quick items. TODO ... + */ + + const auto popup = static_cast< const QskPopup* >( skinnable ); + + auto rect = popup->contentsRect(); + if ( rect.isEmpty() ) + return nullptr; + + auto slideInNode = QskSGNode::ensureNode< QskSlideInNode >( node ); + + const auto progress = popup->metric( popup->faderAspect() ); + slideInNode->updateTranslation( rect, Qt::TopEdge, progress ); + + auto contentsNode = updateContentsNode( popup, slideInNode->contentsNode() ); + slideInNode->setContentsNode( contentsNode ); + + return slideInNode; + } + } + + return Inherited::updateSubNode( skinnable, nodeRole, node ); +} + QRectF QskMenuSkinlet::cursorRect( const QskSkinnable* skinnable, const QRectF& contentsRect, int index ) const { @@ -407,7 +442,8 @@ QskAspect::States QskMenuSkinlet::sampleStates( } } - const auto cursorPos = menu->effectiveSkinHint( Q::Segment | Q::Hovered | A::Metric | A::Position ).toPointF(); + const auto cursorPos = menu->effectiveSkinHint( + Q::Segment | Q::Hovered | A::Metric | A::Position ).toPointF(); if( !cursorPos.isNull() && menu->indexAtPosition( cursorPos ) == index ) { diff --git a/src/controls/QskMenuSkinlet.h b/src/controls/QskMenuSkinlet.h index 4ebe5284..34a3c0b5 100644 --- a/src/controls/QskMenuSkinlet.h +++ b/src/controls/QskMenuSkinlet.h @@ -20,7 +20,9 @@ class QSK_EXPORT QskMenuSkinlet : public QskPopupSkinlet public: enum NodeRole { - PanelRole = QskPopupSkinlet::RoleCount, + ContentsRole = Inherited::RoleCount, + PanelRole, + RoleCount }; @@ -48,7 +50,10 @@ class QSK_EXPORT QskMenuSkinlet : public QskPopupSkinlet Qt::SizeHint, const QSizeF& ) const override; protected: - QSGNode* updateContentsNode( const QskPopup*, QSGNode* ) const override; + QSGNode* updateSubNode( const QskSkinnable*, + quint8 nodeRole, QSGNode* ) const override; + + QSGNode* updateContentsNode( const QskPopup*, QSGNode* ) const; QSGNode* updateMenuNode( const QskSkinnable*, QSGNode* ) const; QSGNode* updateSampleNode( const QskSkinnable*, diff --git a/src/controls/QskPopupSkinlet.cpp b/src/controls/QskPopupSkinlet.cpp index 70cf300e..07dbb53c 100644 --- a/src/controls/QskPopupSkinlet.cpp +++ b/src/controls/QskPopupSkinlet.cpp @@ -5,108 +5,11 @@ #include "QskPopupSkinlet.h" #include "QskPopup.h" -#include "QskSGNode.h" - -#include -#include -#include - -namespace -{ - class RootNode : public QSGNode - { - public: - ~RootNode() override - { - delete m_clipNode; - delete m_transformNode; - delete m_contentsNode; - } - - void setClipRect( const QRectF& rect ) - { - if ( m_clipNode == nullptr ) - { - m_clipNode = new QSGClipNode(); - m_clipNode->setFlag( QSGNode::OwnedByParent, false ); - m_clipNode->setIsRectangular( true ); - } - - m_clipNode->setClipRect( rect ); - } - - void resetClip() - { - delete m_clipNode; - m_clipNode = nullptr; - } - - void setTranslation( qreal dx, qreal dy ) - { - if ( dx != 0.0 || dy != 0.0 ) - { - if ( m_transformNode == nullptr ) - { - m_transformNode = new QSGTransformNode(); - m_transformNode->setFlag( QSGNode::OwnedByParent, false ); - } - - QTransform transform; - transform.translate( dx, dy ); - - m_transformNode->setMatrix( transform ); - } - else - { - delete m_transformNode; - m_transformNode = nullptr; - } - } - - void setContentsNode( QSGNode* contentsNode ) - { - if ( m_contentsNode != contentsNode ) - { - if ( contentsNode ) - contentsNode->setFlag( QSGNode::OwnedByParent, false ); - - delete m_contentsNode; - m_contentsNode = contentsNode; - } - } - - void rearrangeNodes() - { - const std::initializer_list< QSGNode* > nodes = - { m_clipNode, m_transformNode, m_contentsNode }; - - QSGNode* parentNode = this; - for ( auto node : nodes ) - { - if ( node ) - { - QskSGNode::setParentNode( node, parentNode ); - parentNode = node; - } - } - } - - inline QSGNode* contentsNode() - { - return m_contentsNode; - } - - private: - QSGClipNode* m_clipNode = nullptr; - QSGTransformNode* m_transformNode = nullptr; - QSGNode* m_contentsNode = nullptr; - }; -} QskPopupSkinlet::QskPopupSkinlet( QskSkin* skin ) : Inherited( skin ) { - appendNodeRoles( { OverlayRole, ContentsRole } ); + appendNodeRoles( { OverlayRole } ); } QskPopupSkinlet::~QskPopupSkinlet() = default; @@ -131,48 +34,9 @@ QSGNode* QskPopupSkinlet::updateSubNode( { case OverlayRole: return updateBoxNode( skinnable, node, QskPopup::Overlay ); - - case ContentsRole: - return updateExtraNode( popup, node ); } return Inherited::updateSubNode( skinnable, nodeRole, node ); } -QSGNode* QskPopupSkinlet::updateExtraNode( const QskPopup* popup, QSGNode* node ) const -{ - auto cr = popup->contentsRect(); - if ( cr.isEmpty() ) - return nullptr; - - auto rootNode = QskSGNode::ensureNode< RootNode >( node ); - - const auto faderProgress = popup->metric( popup->faderAspect() ); - if ( faderProgress > 0.0 && faderProgress <= 1.0 ) - { - auto clipRect = QRectF( popup->mapFromScene( QPointF() ), popup->window()->size() ); - clipRect.setTop( cr.top() ); - - rootNode->setClipRect( clipRect ); - } - else - { - rootNode->resetClip(); - } - - rootNode->setTranslation( 0.0, -faderProgress * cr.height() ); - - auto contentsNode = updateContentsNode( popup, rootNode->contentsNode() ); - rootNode->setContentsNode( contentsNode ); - - rootNode->rearrangeNodes(); - - return rootNode; -} - -QSGNode* QskPopupSkinlet::updateContentsNode( const QskPopup*, QSGNode* ) const -{ - return nullptr; -} - #include "moc_QskPopupSkinlet.cpp" diff --git a/src/controls/QskPopupSkinlet.h b/src/controls/QskPopupSkinlet.h index 076f86f9..ecd3a758 100644 --- a/src/controls/QskPopupSkinlet.h +++ b/src/controls/QskPopupSkinlet.h @@ -20,8 +20,6 @@ class QSK_EXPORT QskPopupSkinlet : public QskSkinlet enum NodeRole { OverlayRole, - ContentsRole, - RoleCount }; @@ -35,10 +33,7 @@ class QSK_EXPORT QskPopupSkinlet : public QskSkinlet QSGNode* updateSubNode( const QskSkinnable*, quint8 nodeRole, QSGNode* ) const override; - virtual QSGNode* updateContentsNode( const QskPopup*, QSGNode* ) const; - private: - QSGNode* updateExtraNode( const QskPopup*, QSGNode* ) const; QSGNode* updateOverlayNode( const QskPopup*, QSGNode* ) const; }; diff --git a/src/nodes/QskSlideInNode.cpp b/src/nodes/QskSlideInNode.cpp new file mode 100644 index 00000000..6c77b366 --- /dev/null +++ b/src/nodes/QskSlideInNode.cpp @@ -0,0 +1,146 @@ +/****************************************************************************** + * QSkinny - Copyright (C) 2016 Uwe Rathmann + * SPDX-License-Identifier: BSD-3-Clause + *****************************************************************************/ + +#include "QskSlideInNode.h" +#include "QskSGNode.h" +#include + +QSK_QT_PRIVATE_BEGIN +#include +QSK_QT_PRIVATE_END + +class QskSlideInNodePrivate final : public QSGNodePrivate +{ + public: + ~QskSlideInNodePrivate() + { + delete clipNode; + delete transformNode; + delete contentsNode; + } + + void reparentContentNode( QskSlideInNode* node ) + { + if ( contentsNode ) + { + QSGNode* parentNode = transformNode; + + if ( parentNode == nullptr ) + parentNode = clipNode; + + if ( parentNode == nullptr ) + parentNode = node; + + QskSGNode::setParentNode( contentsNode, parentNode ); + } + } + + QSGClipNode* clipNode = nullptr; + QSGTransformNode* transformNode = nullptr; + QSGNode* contentsNode = nullptr; +}; + +QskSlideInNode::QskSlideInNode() + : QSGNode( *new QskSlideInNodePrivate, QSGNode::BasicNodeType ) +{ +} + +QskSlideInNode::~QskSlideInNode() = default; + +void QskSlideInNode::updateTranslation( const QRectF& rect, + Qt::Edge edge, qreal progress ) +{ + Q_UNUSED( edge ); // TODO ... + + Q_D( QskSlideInNode ); + + { + // clipping + + if ( progress > 0.0 && progress <= 1.0 ) + { + if ( d->clipNode == nullptr ) + { + d->clipNode = new QSGClipNode(); + d->clipNode->setFlag( QSGNode::OwnedByParent, false ); + d->clipNode->setIsRectangular( true ); + } + + d->clipNode->setClipRect( rect ); + + } + else + { + delete d->clipNode; + d->clipNode = nullptr; + } + + if ( d->clipNode ) + QskSGNode::setParentNode( d->clipNode, this ); + } + + { + // translation + + qreal dx = 0.0; + qreal dy = -progress* rect.height(); + + if ( dx != 0.0 || dy != 0.0 ) + { + if ( d->transformNode == nullptr ) + { + d->transformNode = new QSGTransformNode(); + d->transformNode->setFlag( QSGNode::OwnedByParent, false ); + } + + QTransform transform; + transform.translate( dx, dy ); + + d->transformNode->setMatrix( transform ); + } + else + { + delete d->transformNode; + d->transformNode = nullptr; + } + + if ( d->transformNode ) + { + QSGNode* parentNode = d->clipNode; + if ( parentNode == nullptr ) + parentNode = this; + + QskSGNode::setParentNode( d->transformNode, parentNode ); + } + } + + d->reparentContentNode( this ); +} + +void QskSlideInNode::setContentsNode( QSGNode* node ) +{ + Q_D( QskSlideInNode ); + + if ( d->contentsNode == node ) + return; + + if ( node ) + node->setFlag( QSGNode::OwnedByParent, false ); + + delete d->contentsNode; + d->contentsNode = node; + + d->reparentContentNode( this ); +} + +QSGNode* QskSlideInNode::contentsNode() +{ + return d_func()->contentsNode; +} + +const QSGNode* QskSlideInNode::contentsNode() const +{ + return d_func()->contentsNode; +} diff --git a/src/nodes/QskSlideInNode.h b/src/nodes/QskSlideInNode.h new file mode 100644 index 00000000..532663f2 --- /dev/null +++ b/src/nodes/QskSlideInNode.h @@ -0,0 +1,33 @@ +/****************************************************************************** + * QSkinny - Copyright (C) 2016 Uwe Rathmann + * SPDX-License-Identifier: BSD-3-Clause + *****************************************************************************/ + +#ifndef QSK_SLIDE_IN_NODE_H +#define QSK_SLIDE_IN_NODE_H + +#include "QskGlobal.h" + +#include +#include + +class QskSlideInNodePrivate; + +class QSK_EXPORT QskSlideInNode : public QSGNode +{ + public: + QskSlideInNode(); + ~QskSlideInNode() override; + + void updateTranslation( const QRectF&, Qt::Edge, qreal progress ); + + void setContentsNode( QSGNode* ); + + QSGNode* contentsNode(); + const QSGNode* contentsNode() const; + + private: + Q_DECLARE_PRIVATE( QskSlideInNode ) +}; + +#endif