From 1ab236de9fc76de6576ae662dd3e9a31583073cd Mon Sep 17 00:00:00 2001 From: Uwe Rathmann Date: Fri, 3 Nov 2023 18:13:24 +0100 Subject: [PATCH] better fading support for popups, being used in QskDrawer/QskMenu/QskSubWindow --- skins/fluent2/QskFluent2Skin.cpp | 23 +-- skins/material3/QskMaterial3Skin.cpp | 10 +- skins/squiek/QskSquiekSkin.cpp | 16 +- src/CMakeLists.txt | 4 +- src/controls/QskDrawer.cpp | 259 +++++++++++++-------------- src/controls/QskDrawer.h | 18 +- src/controls/QskDrawerSkinlet.cpp | 45 +++++ src/controls/QskDrawerSkinlet.h | 40 +++++ src/controls/QskMenu.cpp | 70 +++++++- src/controls/QskMenu.h | 8 +- src/controls/QskMenuSkinlet.cpp | 16 +- src/controls/QskPopup.cpp | 94 +++++----- src/controls/QskPopup.h | 14 +- src/controls/QskPopupSkinlet.cpp | 38 +++- src/controls/QskSkin.cpp | 4 + src/controls/QskSubWindow.cpp | 11 ++ src/controls/QskSubWindow.h | 3 + src/controls/QskSubWindowSkinlet.cpp | 12 ++ src/dialogs/QskDialog.cpp | 27 +-- src/nodes/QskSlideInNode.cpp | 146 --------------- src/nodes/QskSlideInNode.h | 33 ---- 21 files changed, 454 insertions(+), 437 deletions(-) create mode 100644 src/controls/QskDrawerSkinlet.cpp create mode 100644 src/controls/QskDrawerSkinlet.h delete mode 100644 src/nodes/QskSlideInNode.cpp delete mode 100644 src/nodes/QskSlideInNode.h diff --git a/skins/fluent2/QskFluent2Skin.cpp b/skins/fluent2/QskFluent2Skin.cpp index e1e114ff..4f5de05d 100644 --- a/skins/fluent2/QskFluent2Skin.cpp +++ b/skins/fluent2/QskFluent2Skin.cpp @@ -623,13 +623,14 @@ void Editor::setupDrawerMetrics() using Q = QskDrawer; using A = QskAspect; -#if 1 - setAnimation( Q::Panel | A::Metric | A::Position, 200 ); -#endif + setAnimation( Q::Panel | A::Position, 300, QEasingCurve::OutCubic ); } -void Editor::setupDrawerColors( QskAspect::Section, const QskFluent2Theme& ) +void Editor::setupDrawerColors( + QskAspect::Section section, const QskFluent2Theme& theme ) { + setGradient( QskDrawer::Panel | section, + theme.palette.background.solid.base ); } void Editor::setupFocusIndicatorMetrics() @@ -759,13 +760,7 @@ void Editor::setupMenuMetrics() setStrutSize( Q::Icon, 12, 12 ); setPadding( Q::Icon, { 8, 8, 0, 8 } ); -#if 1 - setPosition( Q::Panel, 1 ); - setPosition( Q::Panel | QskPopup::Closed, 0 ); - - // copied from Mat3 - what are the correct values for Fluent2 ??? - setAnimation( Q::Panel | A::Metric, 150 ); -#endif + setAnimation( Q::Panel | A::Position, 100 ); } void Editor::setupMenuColors( @@ -876,9 +871,11 @@ void Editor::setupPageIndicatorColors( void Editor::setupPopup( const QskFluent2Theme& theme ) { using Q = QskPopup; + using A = QskAspect; const auto& pal = theme.palette; + setHint( Q::Overlay | A::Style, true ); setGradient( Q::Overlay, pal.background.overlay.defaultColor ); } @@ -1885,6 +1882,8 @@ void Editor::setupSwitchButtonColors( void Editor::setupSubWindow( const QskFluent2Theme& theme ) { using Q = QskSubWindow; + using A = QskAspect; + const auto& pal = theme.palette; setPadding( Q::Panel, { 0, 31, 0, 0 } ); @@ -1902,6 +1901,8 @@ void Editor::setupSubWindow( const QskFluent2Theme& theme ) setColor( Q::TitleBarText, pal.fillColor.text.primary ); setAlignment( Q::TitleBarText, Qt::AlignLeft ); setTextOptions( Q::TitleBarText, Qt::ElideRight, QskTextOptions::NoWrap ); + + setAnimation( Q::Panel | A::Position, 300, QEasingCurve::OutCubic ); } void Editor::setupVirtualKeyboardMetrics() diff --git a/skins/material3/QskMaterial3Skin.cpp b/skins/material3/QskMaterial3Skin.cpp index f5780f04..8443dbf5 100644 --- a/skins/material3/QskMaterial3Skin.cpp +++ b/skins/material3/QskMaterial3Skin.cpp @@ -378,11 +378,9 @@ void Editor::setupMenu() setColor( Q::Text, m_pal.onSurface ); setFontRole( Q::Text, QskMaterial3Skin::M3BodyMedium ); - setPosition( Q::Panel, 1 ); - setPosition( Q::Panel | QskPopup::Closed, 0 ); - - setAnimation( Q::Panel | A::Metric, 150 ); setAnimation( Q::Cursor | A::Position | A::Metric, 75, QEasingCurve::OutCubic ); + + setAnimation( Q::Panel | A::Position, 75 ); } void Editor::setupTextLabel() @@ -811,7 +809,8 @@ void Editor::setupDrawer() using Q = QskDrawer; using A = QskAspect; - setAnimation( Q::Panel | A::Metric | A::Position, qskDuration ); + setGradient( Q::Panel, m_pal.background ); + setAnimation( Q::Panel | A::Position, 300, QEasingCurve::OutCubic ); } void Editor::setupSlider() @@ -1261,6 +1260,7 @@ void Editor::setupSubWindow() for ( auto subControl : { Q::Panel, Q::TitleBarPanel, Q::TitleBarText } ) setAnimation( subControl | A::Color, qskDuration ); + setAnimation( Q::Panel | A::Position, qskDuration, QEasingCurve::OutCubic ); } QskMaterial3Theme::QskMaterial3Theme( QskSkin::ColorScheme colorScheme ) diff --git a/skins/squiek/QskSquiekSkin.cpp b/skins/squiek/QskSquiekSkin.cpp index f92ba16a..19530b32 100644 --- a/skins/squiek/QskSquiekSkin.cpp +++ b/skins/squiek/QskSquiekSkin.cpp @@ -409,7 +409,7 @@ void Editor::setupPopup() using Q = QskPopup; setHint( Q::Overlay | A::Style, true ); - setGradient( Q::Overlay, QColor( 220, 220, 220, 150 ) ); + setGradient( Q::Overlay, qRgba( 220, 220, 220, 150 ) ); } void Editor::setupMenu() @@ -446,11 +446,8 @@ void Editor::setupMenu() setGraphicRole( Q::Icon | Q::Disabled, DisabledSymbol ); setGraphicRole( Q::Icon | Q::Selected, CursorSymbol ); - setPosition( Q::Panel, 1 ); - setPosition( Q::Panel | QskPopup::Closed, 0 ); - - setAnimation( Q::Panel | A::Metric, 150 ); setAnimation( Q::Cursor | A::Position | A::Metric, 75, QEasingCurve::OutCubic ); + setAnimation( Q::Panel | A::Position, 100 ); } void Editor::setupTextLabel() @@ -761,10 +758,11 @@ void Editor::setupDialogButtonBox() void Editor::setupDrawer() { - using A = QskAspect; using Q = QskDrawer; + using A = QskAspect; - setAnimation( Q::Panel | A::Metric | A::Position, qskDuration ); + setPanel( Q::Panel, Plain ); + setAnimation( Q::Panel | A::Position, 300, QEasingCurve::OutCubic ); } void Editor::setupTabButton() @@ -1126,8 +1124,12 @@ void Editor::setupSubWindow() setAlignment( Q::TitleBarText, Qt::AlignLeft | Qt::AlignVCenter ); +#if 1 for ( auto subControl : { Q::Panel, Q::TitleBarPanel, Q::TitleBarText } ) setAnimation( subControl | A::Color, qskDuration ); +#endif + + setAnimation( Q::Panel | A::Position, qskDuration, QEasingCurve::OutCubic ); } void Editor::setupSpinBox() diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 7ce13c74..a2f36047 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -115,7 +115,6 @@ list(APPEND HEADERS nodes/QskRichTextRenderer.h nodes/QskScaleRenderer.h nodes/QskSGNode.h - nodes/QskSlideInNode.h nodes/QskStrokeNode.h nodes/QskStippledLineRenderer.h nodes/QskShapeNode.h @@ -147,7 +146,6 @@ list(APPEND SOURCES nodes/QskRichTextRenderer.cpp nodes/QskScaleRenderer.cpp nodes/QskSGNode.cpp - nodes/QskSlideInNode.cpp nodes/QskStrokeNode.cpp nodes/QskStippledLineRenderer.cpp nodes/QskShapeNode.cpp @@ -178,6 +176,7 @@ list(APPEND HEADERS controls/QskComboBoxSkinlet.h controls/QskControl.h controls/QskDrawer.h + controls/QskDrawerSkinlet.h controls/QskEvent.h controls/QskFlickAnimator.h controls/QskFocusIndicator.h @@ -281,6 +280,7 @@ list(APPEND SOURCES controls/QskControlPrivate.cpp controls/QskDirtyItemFilter.cpp controls/QskDrawer.cpp + controls/QskDrawerSkinlet.cpp controls/QskEvent.cpp controls/QskFlickAnimator.cpp controls/QskFocusIndicator.cpp diff --git a/src/controls/QskDrawer.cpp b/src/controls/QskDrawer.cpp index 4793cdab..87890a8d 100644 --- a/src/controls/QskDrawer.cpp +++ b/src/controls/QskDrawer.cpp @@ -5,7 +5,6 @@ #include "QskDrawer.h" #include "QskAspect.h" -#include "QskAnimationHint.h" #include "QskQuick.h" #include "QskEvent.h" @@ -20,10 +19,6 @@ QSK_QT_PRIVATE_BEGIN #include QSK_QT_PRIVATE_END -/* - Only used for the sliding in animation. Do we want to - introduce a specific panel as background ??? - */ QSK_SUBCONTROL( QskDrawer, Panel ) static inline qreal qskDefaultDragMargin() @@ -63,77 +58,60 @@ static bool qskCheckDirection( Qt::Edge edge, const QskPanGesture* gesture ) return false; } -static void qskLayoutDrawer( const QRectF& rect, QskDrawer* drawer ) +static inline QRectF qskAlignedToEdge( + const QRectF& r, const QSizeF& sz, Qt::Edge edge ) { - const auto size = qskSizeConstraint( drawer, Qt::PreferredSize ); + switch( edge ) + { + case Qt::LeftEdge: + return QRectF( r.left(), r.top(), sz.width(), r.height() ); - QRectF r( 0.0, 0.0, size.width(), size.height() ); + case Qt::RightEdge: + return QRectF( r.right() - sz.width(), r.top(), sz.width(), r.height() ); + + case Qt::TopEdge: + return QRectF( r.left(), r.top(), r.width(), sz.height() ); + + case Qt::BottomEdge: + return QRectF( r.left(), r.bottom() - sz.height(), r.width(), sz.height() ); + } + + return QRectF(); +} + +static QPointF qskDrawerTranslation( const QskDrawer* drawer, const QSizeF& size ) +{ + const auto ratio = 1.0 - drawer->fadingFactor(); + + auto dx = 0.0; + auto dy = 0.0; switch( drawer->edge() ) { case Qt::LeftEdge: - { - r.setHeight( rect.height() ); - r.moveRight( rect.left() + size.width() ); - break; - } - case Qt::RightEdge: - { - r.setHeight( rect.height() ); - r.moveLeft( rect.right() - size.width() ); - break; - } - - case Qt::TopEdge: - { - r.setWidth( rect.width() ); - r.moveBottom( rect.top() + size.height() ); - break; - } - - case Qt::BottomEdge: - { - r.setWidth( rect.width() ); - r.moveTop( rect.bottom() - size.height() ); - break; - } - } - - drawer->setGeometry( r ); -} - -static inline QRectF qskSlidingRect( - const QSizeF& size, Qt::Edge edge, qreal ratio ) -{ - auto x = 0.0; - auto y = 0.0; - - ratio = 1.0 - ratio; - - switch( edge ) - { - case Qt::LeftEdge: - x = -ratio * size.width(); + dx = -ratio * size.width(); break; case Qt::RightEdge: - x = ratio * size.width(); + dx = ratio * size.width(); break; case Qt::TopEdge: - y = -ratio * size.height(); + dy = -ratio * size.height(); break; case Qt::BottomEdge: - y = ratio * size.height(); + dy = ratio * size.height(); break; } - return QRectF( x, y, size.width(), size.height() ); + return QPointF( dx, dy ); } namespace { + // Using an eventFilter for QskEvent::GeometryChange instead ??? + class GeometryListener final : public QQuickItemChangeListener { public: @@ -160,14 +138,7 @@ namespace private: void adjust() { -#if 0 - const auto pos = m_adjustedItem->mapFromItem( m_item, QPointF() ); - qskSetItemGeometry( m_adjustedItem, - pos.x(), pos.y(), m_item->width(), m_item->height() ); -#else - qskLayoutDrawer( QRectF( QPointF(), m_item->size() ), - qobject_cast< QskDrawer* >( m_adjustedItem ) ); -#endif + m_adjustedItem->polish(); } void setEnabled( bool on ) @@ -184,10 +155,7 @@ namespace QQuickItem* m_item; QQuickItem* m_adjustedItem; }; -} -namespace -{ class GestureRecognizer : public QskPanGestureRecognizer { using Inherited = QskPanGestureRecognizer; @@ -204,7 +172,7 @@ namespace bool isAcceptedPos( const QPointF& pos ) const override { auto drawer = qobject_cast< const QskDrawer* >( targetItem() ); - if ( drawer->isTransitioning() ) + if ( drawer->isFading() ) return false; auto rect = qskItemRect( watchedItem() ); @@ -243,6 +211,11 @@ namespace class QskDrawer::PrivateData { public: + PrivateData( Qt::Edge edge ) + : edge( edge ) + { + } + inline void resetListener( QskDrawer* drawer ) { delete listener; @@ -252,37 +225,39 @@ class QskDrawer::PrivateData listener = new GeometryListener( drawer->parentItem(), drawer ); } - Qt::Edge edge = Qt::LeftEdge; - GestureRecognizer* gestureRecognizer = nullptr; GeometryListener* listener = nullptr; + GestureRecognizer* gestureRecognizer = nullptr; qreal dragMargin = qskDefaultDragMargin(); + Qt::Edge edge; }; QskDrawer::QskDrawer( QQuickItem* parentItem ) + : QskDrawer( Qt::LeftEdge, parentItem ) +{ +} + +QskDrawer::QskDrawer( Qt::Edge edge, QQuickItem* parentItem ) : Inherited ( parentItem ) - , m_data( new PrivateData ) + , m_data( new PrivateData( edge ) ) { #if 1 setZ( 1 ); #endif - setAutoLayoutChildren( true ); - setInteractive( true ); - setPopupFlag( PopupFlag::CloseOnPressOutside, true ); - setTransitionAspect( Panel | QskAspect::Position | QskAspect::Metric ); /* - The drawer wants to be on top of the parent - not being + A drawer wants to be on top of its parent - not being layouted into its layoutRect(). So we opt out and do the layout updates manually. */ setPlacementPolicy( QskPlacementPolicy::Ignore ); - m_data->resetListener( this ); - connect( this, &QskPopup::openChanged, this, &QskDrawer::setSliding ); - connect( this, &QskPopup::transitioningChanged, this, &QskDrawer::setIntermediate ); + setAutoLayoutChildren( true ); + setInteractive( true ); + + connect( this, &QskPopup::fadingChanged, this, &QQuickItem::setClip ); } QskDrawer::~QskDrawer() @@ -374,18 +349,6 @@ void QskDrawer::gestureEvent( QskGestureEvent* event ) Inherited::gestureEvent( event ); } -QRectF QskDrawer::layoutRectForSize( const QSizeF& size ) const -{ - qreal ratio; - - if ( isTransitioning() ) - ratio = metric( transitionAspect() ); - else - ratio = isOpen() ? 1.0 : 0.0; - - return qskSlidingRect( size, m_data->edge, ratio ); -} - void QskDrawer::itemChange( QQuickItem::ItemChange change, const QQuickItem::ItemChangeData& value ) { @@ -409,74 +372,96 @@ void QskDrawer::itemChange( QQuickItem::ItemChange change, } } -void QskDrawer::setSliding( bool on ) +void QskDrawer::updateResources() { - const qreal from = on ? 0.0 : 1.0; - const qreal to = on ? 1.0 : 0.0; + Inherited::updateResources(); - const auto aspect = transitionAspect(); + /* + Adjusting the geometry to the parent needs to be done before + the layouting of the children ( -> autoLayoutChildren ) is done. + So we are using this hook even if it is not about resources: TODO ... + */ + if ( const auto item = parentItem() ) + { + auto r = qskItemRect( item ); + r = qskAlignedToEdge( r, sizeConstraint( Qt::PreferredSize ), edge() ); - auto hint = animationHint( aspect ); - hint.updateFlags = QskAnimationHint::UpdatePolish; + r.translate( qskDrawerTranslation( this, r.size() ) ); + setGeometry( r ); + } +} - startTransition( aspect, hint, from, to ); +void QskDrawer::updateNode( QSGNode* node ) +{ + if ( isFading() && clip() ) + { + if ( auto clipNode = QQuickItemPrivate::get( this )->clipNode() ) + { + /* + The clipRect is changing while fading. Couldn't + find a way how to trigger updates - maybe be enabling/disabling + the clip. So we do the updates manually. TODO ... + */ + const auto r = clipRect(); + if ( r != clipNode->rect() ) + { + clipNode->setRect( r ); + clipNode->update(); + } + } + } + + Inherited::updateNode( node ); } QRectF QskDrawer::clipRect() const { - if ( !isTransitioning() ) - return Inherited::clipRect(); - - /* - When fading we want to clip against the edge, where the drawer - slides in/out. However the size of the drawer is often smaller than the - one of the parent and we would clip the overlay node - and all content, that is located outside the drawer geometry. - - So we expand the clip rectangle to "unbounded" at the other edges. - - Note, that clipping against "rounded" rectangles can't be done - properly by overloading clipRect. We would have to manipulate the clip node - manually - like it is done in QskScrollArea. TODO .. - */ - constexpr qreal d = std::numeric_limits< short >::max(); - - QRectF r( -d, -d, 2.0 * d, 2.0 * d ); - - switch( m_data->edge ) + if ( isFading() && parentItem() ) { - case Qt::LeftEdge: - r.setLeft( 0.0 ); - break; + /* + We might not fit into our parent and our children not + into our rect. So we want to have a clip against the + edge, where the drawer slides in/out only. + Otherwise we would have unwanted effects, when clipping gets + disabled once the transition is over. + */ + constexpr qreal d = 1e6; - case Qt::RightEdge: - r.setRight( width() ); - break; + QRectF r( -d, -d, 2.0 * d, 2.0 * d ); - case Qt::TopEdge: - r.setTop( 0.0 ); - break; + switch( edge() ) + { + case Qt::LeftEdge: + r.setLeft( -x() ); + break; - case Qt::BottomEdge: - r.setBottom( height() ); - break; + case Qt::RightEdge: + r.setRight( parentItem()->width() - x() ); + break; + + case Qt::TopEdge: + r.setTop( -y() ); + break; + + case Qt::BottomEdge: + r.setBottom( parentItem()->height() - y() ); + break; + } + + return r; } - return r; + return Inherited::clipRect(); } -void QskDrawer::setIntermediate( bool on ) +QskAspect QskDrawer::fadingAspect() const { - setClip( on ); - Q_EMIT focusIndicatorRectChanged(); + return QskDrawer::Panel | QskAspect::Position; } -QRectF QskDrawer::focusIndicatorRect() const +QRectF QskDrawer::layoutRectForSize( const QSizeF& size ) const { - if ( isTransitioning() ) - return QRectF(); - - return Inherited::focusIndicatorRect(); + return subControlContentsRect( size, Panel ); } #include "moc_QskDrawer.cpp" diff --git a/src/controls/QskDrawer.h b/src/controls/QskDrawer.h index f8aada41..b6c852f2 100644 --- a/src/controls/QskDrawer.h +++ b/src/controls/QskDrawer.h @@ -7,7 +7,6 @@ #define QSK_DRAWER_H #include "QskPopup.h" -#include class QSK_EXPORT QskDrawer : public QskPopup { @@ -27,6 +26,8 @@ class QSK_EXPORT QskDrawer : public QskPopup QSK_SUBCONTROLS( Panel ) QskDrawer( QQuickItem* = nullptr ); + QskDrawer( Qt::Edge, QQuickItem* = nullptr ); + ~QskDrawer() override; void setEdge( Qt::Edge ); @@ -39,10 +40,10 @@ class QSK_EXPORT QskDrawer : public QskPopup void resetDragMargin(); qreal dragMargin() const; - QRectF layoutRectForSize( const QSizeF& ) const override; - QRectF clipRect() const override; - QRectF focusIndicatorRect() const override; + QskAspect fadingAspect() const override; + + QRectF layoutRectForSize( const QSizeF& ) const override; Q_SIGNALS: void edgeChanged( Qt::Edge ); @@ -50,14 +51,13 @@ class QSK_EXPORT QskDrawer : public QskPopup void interactiveChanged( bool ); protected: - void itemChange( ItemChange, const ItemChangeData& ) override; void gestureEvent( QskGestureEvent* ) override; + void itemChange( ItemChange, const ItemChangeData& ) override; + + void updateResources() override; + void updateNode( QSGNode* ) override; private: - void setSliding( bool ); - - void setIntermediate( bool ); - class PrivateData; std::unique_ptr< PrivateData > m_data; }; diff --git a/src/controls/QskDrawerSkinlet.cpp b/src/controls/QskDrawerSkinlet.cpp new file mode 100644 index 00000000..e10f5923 --- /dev/null +++ b/src/controls/QskDrawerSkinlet.cpp @@ -0,0 +1,45 @@ +/****************************************************************************** + * QSkinny - Copyright (C) 2016 Uwe Rathmann + * SPDX-License-Identifier: BSD-3-Clause + *****************************************************************************/ + +#include "QskDrawerSkinlet.h" +#include "QskDrawer.h" + +QskDrawerSkinlet::QskDrawerSkinlet( QskSkin* skin ) + : Inherited( skin ) +{ + appendNodeRoles( { PanelRole } ); +} + +QskDrawerSkinlet::~QskDrawerSkinlet() = default; + +QRectF QskDrawerSkinlet::subControlRect( + const QskSkinnable* skinnable, const QRectF& contentsRect, + QskAspect::Subcontrol subControl ) const +{ + if ( subControl == QskDrawer::Panel ) + return contentsRect; + + return Inherited::subControlRect( skinnable, contentsRect, subControl ); +} + +QSGNode* QskDrawerSkinlet::updateSubNode( + const QskSkinnable* skinnable, quint8 nodeRole, QSGNode* node ) const +{ + if ( nodeRole == PanelRole ) + return updateBoxNode( skinnable, node, QskDrawer::Panel ); + + return Inherited::updateSubNode( skinnable, nodeRole, node ); +} + +QSizeF QskDrawerSkinlet::sizeHint( const QskSkinnable* skinnable, + Qt::SizeHint which, const QSizeF& constraint ) const +{ + if ( which == Qt::PreferredSize ) + return skinnable->strutSizeHint( QskDrawer::Panel ); + + return Inherited::sizeHint( skinnable, which, constraint ); +} + +#include "moc_QskDrawerSkinlet.cpp" diff --git a/src/controls/QskDrawerSkinlet.h b/src/controls/QskDrawerSkinlet.h new file mode 100644 index 00000000..b6d1c771 --- /dev/null +++ b/src/controls/QskDrawerSkinlet.h @@ -0,0 +1,40 @@ +/****************************************************************************** + * QSkinny - Copyright (C) 2016 Uwe Rathmann + * SPDX-License-Identifier: BSD-3-Clause + *****************************************************************************/ + +#ifndef QSK_DRAWER_SKINLET_H +#define QSK_DRAWER_SKINLET_H + +#include "QskPopupSkinlet.h" + +class QSK_EXPORT QskDrawerSkinlet : public QskPopupSkinlet +{ + Q_GADGET + + using Inherited = QskPopupSkinlet; + + public: + enum NodeRole + { + ContentsRole = Inherited::RoleCount, + PanelRole, + + RoleCount + }; + + Q_INVOKABLE QskDrawerSkinlet( QskSkin* = nullptr ); + ~QskDrawerSkinlet() override; + + QRectF subControlRect( const QskSkinnable*, + const QRectF&, QskAspect::Subcontrol ) const override; + + QSizeF sizeHint( const QskSkinnable*, + Qt::SizeHint, const QSizeF& ) const override; + + protected: + QSGNode* updateSubNode( const QskSkinnable*, + quint8 nodeRole, QSGNode* ) const override; +}; + +#endif diff --git a/src/controls/QskMenu.cpp b/src/controls/QskMenu.cpp index ba86d66c..e3af5707 100644 --- a/src/controls/QskMenu.cpp +++ b/src/controls/QskMenu.cpp @@ -18,7 +18,10 @@ #include #include -QSK_SUBCONTROL( QskMenu, Overlay ) +QSK_QT_PRIVATE_BEGIN +#include +QSK_QT_PRIVATE_END + QSK_SUBCONTROL( QskMenu, Panel ) QSK_SUBCONTROL( QskMenu, Segment ) QSK_SUBCONTROL( QskMenu, Cursor ) @@ -58,20 +61,23 @@ QskMenu::QskMenu( QQuickItem* parent ) , m_data( new PrivateData ) { setModal( true ); - setTransitionAspect( QskMenu::Panel | QskAspect::Position | QskAspect::Metric ); setPopupFlag( QskPopup::CloseOnPressOutside, true ); setPopupFlag( QskPopup::DeleteOnClose, true ); + setPlacementPolicy( QskPlacementPolicy::Ignore ); setSubcontrolProxy( Inherited::Overlay, Overlay ); initSizePolicy( QskSizePolicy::Fixed, QskSizePolicy::Fixed ); // we hide the focus indicator while sliding - connect( this, &QskMenu::transitioningChanged, this, - &QskControl::focusIndicatorRectChanged ); + connect( this, &QskPopup::fadingChanged, + this, &QskControl::focusIndicatorRectChanged ); - connect( this, &QskMenu::opened, this, + connect( this, &QskPopup::fadingChanged, + this, &QQuickItem::setClip ); + + connect( this, &QskPopup::opened, this, [this]() { m_data->triggeredIndex = -1; } ); setAcceptHoverEvents( true ); @@ -81,6 +87,17 @@ QskMenu::~QskMenu() { } +QRectF QskMenu::clipRect() const +{ + if ( isFading() ) + { + constexpr qreal d = 1e6; + return QRectF( -d, m_data->origin.y() - y(), 2.0 * d, d ); + } + + return Inherited::clipRect(); +} + #if 1 // has no effect as we do not offer submenus yet. TODO ... @@ -263,6 +280,40 @@ QString QskMenu::triggeredText() const return optionAt( m_data->triggeredIndex ).text(); } +void QskMenu::updateResources() +{ + qreal dy = 0.0; + if ( isFading() ) + dy = ( 1.0 - fadingFactor() ) * height(); + + setPosition( m_data->origin.x(), m_data->origin.y() - dy ); + + Inherited::updateResources(); +} + +void QskMenu::updateNode( QSGNode* node ) +{ + if ( isFading() && clip() ) + { + if ( auto clipNode = QQuickItemPrivate::get( this )->clipNode() ) + { + /* + The clipRect is changing while fading. Couldn't + find a way how to trigger updates - maybe be enabling/disabling + the clip. So we do the updates manually. TODO ... + */ + const auto r = clipRect(); + if ( r != clipNode->rect() ) + { + clipNode->setRect( r ); + clipNode->update(); + } + } + } + + Inherited::updateNode( node ); +} + void QskMenu::keyPressEvent( QKeyEvent* event ) { if( m_data->currentIndex < 0 ) @@ -435,7 +486,7 @@ void QskMenu::mouseReleaseEvent( QMouseEvent* event ) void QskMenu::aboutToShow() { - setGeometry( QRectF( m_data->origin, sizeConstraint() ) ); + setSize( sizeConstraint() ); if ( m_data->currentIndex < 0 ) { @@ -448,7 +499,7 @@ void QskMenu::aboutToShow() QRectF QskMenu::focusIndicatorRect() const { - if ( isTransitioning() ) + if ( isFading() ) return QRectF(); if( currentIndex() >= 0 ) @@ -492,6 +543,11 @@ void QskMenu::trigger( int index ) } } +QskAspect QskMenu::fadingAspect() const +{ + return QskMenu::Panel | QskAspect::Position; +} + int QskMenu::exec() { (void) execPopup(); diff --git a/src/controls/QskMenu.h b/src/controls/QskMenu.h index bc4cb2ca..b0042455 100644 --- a/src/controls/QskMenu.h +++ b/src/controls/QskMenu.h @@ -37,7 +37,7 @@ class QSK_EXPORT QskMenu : public QskPopup using Inherited = QskPopup; public: - QSK_SUBCONTROLS( Overlay, Panel, Segment, Cursor, Text, Icon, Separator ) + QSK_SUBCONTROLS( Panel, Segment, Cursor, Text, Icon, Separator ) QSK_STATES( Selected, Pressed ) QskMenu( QQuickItem* parentItem = nullptr ); @@ -81,6 +81,9 @@ class QSK_EXPORT QskMenu : public QskPopup bool isPressed() const; + QRectF clipRect() const override; + QskAspect fadingAspect() const override; + Q_INVOKABLE int exec(); Q_SIGNALS: @@ -115,6 +118,9 @@ class QSK_EXPORT QskMenu : public QskPopup void aboutToShow() override; void trigger( int ); + void updateResources() override; + void updateNode( QSGNode* ) override; + private: void traverse( int steps ); diff --git a/src/controls/QskMenuSkinlet.cpp b/src/controls/QskMenuSkinlet.cpp index 13be2b34..dae18d89 100644 --- a/src/controls/QskMenuSkinlet.cpp +++ b/src/controls/QskMenuSkinlet.cpp @@ -15,7 +15,6 @@ #include "QskLabelData.h" #include "QskSGNode.h" -#include "QskSlideInNode.h" #include #include @@ -223,26 +222,13 @@ QSGNode* QskMenuSkinlet::updateSubNode( { 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->transitionAspect() ); - slideInNode->updateTranslation( rect, Qt::TopEdge, progress ); - - auto contentsNode = updateContentsNode( popup, slideInNode->contentsNode() ); - slideInNode->setContentsNode( contentsNode ); - - return slideInNode; + return updateContentsNode( popup, node ); } } diff --git a/src/controls/QskPopup.cpp b/src/controls/QskPopup.cpp index d993cc51..45e73c91 100644 --- a/src/controls/QskPopup.cpp +++ b/src/controls/QskPopup.cpp @@ -76,6 +76,23 @@ static bool qskReplayMousePress() return false; } +static void qskStartFading( QskPopup* popup, bool on ) +{ + const auto aspect = popup->fadingAspect(); + + auto hint = popup->animationHint( aspect ); + + if ( hint.isValid() ) + { + hint.updateFlags = QskAnimationHint::UpdatePolish | QskAnimationHint::UpdateNode; + + const qreal from = on ? 0.0 : 1.0; + const qreal to = on ? 1.0 : 0.0; + + popup->startTransition( aspect, hint, from, to ); + } +} + namespace { class InputGrabber final : public QskInputGrabber @@ -139,7 +156,6 @@ class QskPopup::PrivateData InputGrabber* inputGrabber = nullptr; uint priority = 0; - QskAspect transitionAspect; int flags : 4; bool isModal : 1; @@ -217,9 +233,11 @@ void QskPopup::setOpen( bool on ) else Q_EMIT closed(); - if ( isTransitioning() ) + qskStartFading( this, on ); + + if ( isFading() ) { - Q_EMIT transitioningChanged( true ); + Q_EMIT fadingChanged( true ); } else { @@ -238,9 +256,22 @@ bool QskPopup::isOpen() const return !hasSkinState( QskPopup::Closed ); } -bool QskPopup::isTransitioning() const +QskAspect QskPopup::fadingAspect() const { - return runningHintAnimator( m_data->transitionAspect ) != nullptr; + return QskAspect(); +} + +bool QskPopup::isFading() const +{ + return runningHintAnimator( fadingAspect() ) != nullptr; +} + +qreal QskPopup::fadingFactor() const +{ + if ( auto animator = runningHintAnimator( fadingAspect() ) ) + return animator->currentValue().value< qreal >(); + + return isOpen() ? 1.0 : 0.0; } QRectF QskPopup::overlayRect() const @@ -291,44 +322,23 @@ void QskPopup::updateInputGrabber() } } -QskAspect QskPopup::transitionAspect() const -{ - return m_data->transitionAspect; -} - -void QskPopup::setTransitionAspect( QskAspect aspect ) -{ - auto transitionAspect = aspect; - transitionAspect.clearStates(); // animated values are always stateless - - if ( transitionAspect == m_data->transitionAspect ) - return; - - if ( isTransitioning() ) - { - // stop the running animation TODO ... - } - - m_data->transitionAspect = transitionAspect; -} - bool QskPopup::isTransitionAccepted( QskAspect aspect ) const { - if ( isVisible() ) + if ( isVisible() && !isInitiallyPainted() ) { + /* + Usually we suppress transitions, when a control has never been + painted before as there is no valid starting point. Popups are + different as we want to have smooth fade/slide appearances. + */ if ( ( aspect.value() == 0 ) ) - { - return true; - } - - if ( aspect == m_data->transitionAspect ) return true; - if ( aspect.isColor() ) - { - if ( aspect.subControl() == effectiveSubcontrol( QskPopup::Overlay ) ) - return true; - } + if ( aspect.subControl() == effectiveSubcontrol( fadingAspect().subControl() ) ) + return true; + + if ( aspect.subControl() == effectiveSubcontrol( QskPopup::Overlay ) ) + return true; } return Inherited::isTransitionAccepted( aspect ); @@ -475,7 +485,7 @@ bool QskPopup::event( QEvent* event ) const auto animatorEvent = static_cast< QskAnimatorEvent* >( event ); if ( ( animatorEvent->state() == QskAnimatorEvent::Terminated ) - && ( animatorEvent->aspect() == m_data->transitionAspect ) ) + && ( animatorEvent->aspect() == fadingAspect() ) ) { if ( !isOpen() ) { @@ -485,7 +495,7 @@ bool QskPopup::event( QEvent* event ) deleteLater(); } - Q_EMIT transitioningChanged( false ); + Q_EMIT fadingChanged( false ); } break; @@ -633,7 +643,7 @@ int QskPopup::execPopup() */ connect( popup, &QObject::destroyed, this, &EventLoop::reject ); - connect( popup, &QskPopup::transitioningChanged, this, &EventLoop::maybeQuit ); + connect( popup, &QskPopup::fadingChanged, this, &EventLoop::maybeQuit ); connect( popup, &QskPopup::openChanged, this, &EventLoop::maybeQuit ); } @@ -648,7 +658,7 @@ int QskPopup::execPopup() { if ( auto popup = qobject_cast< const QskPopup* >( parent() ) ) { - if ( popup->isOpen() || popup->isTransitioning() ) + if ( popup->isOpen() || popup->isFading() ) return; } @@ -656,7 +666,7 @@ int QskPopup::execPopup() } }; - if ( isOpen() || isTransitioning() ) + if ( isOpen() || isFading() ) { qWarning() << "QskPopup::exec: popup is already opened"; return -1; diff --git a/src/controls/QskPopup.h b/src/controls/QskPopup.h index ff1201b2..caf66346 100644 --- a/src/controls/QskPopup.h +++ b/src/controls/QskPopup.h @@ -14,7 +14,7 @@ class QSK_EXPORT QskPopup : public QskControl Q_PROPERTY( bool open READ isOpen WRITE setOpen NOTIFY openChanged ) Q_PROPERTY( bool modal READ isModal WRITE setModal NOTIFY modalChanged ) - Q_PROPERTY( bool transitioning READ isTransitioning NOTIFY transitioningChanged ) + Q_PROPERTY( bool fading READ isFading NOTIFY fadingChanged ) Q_PROPERTY( bool overlay READ hasOverlay WRITE setOverlay RESET resetOverlay NOTIFY overlayChanged ) @@ -56,15 +56,13 @@ class QSK_EXPORT QskPopup : public QskControl void setPriority( uint ); uint priority() const; - // transitions between open/closed states - QskAspect transitionAspect() const; - void setTransitionAspect( QskAspect ); - - bool isTransitioning() const; - bool isOpen() const; bool isClosed() const; + bool isFading() const; + qreal fadingFactor() const; + virtual QskAspect fadingAspect() const; + virtual QRectF overlayRect() const; public Q_SLOTS: @@ -78,7 +76,7 @@ class QSK_EXPORT QskPopup : public QskControl void opened(); void closed(); void openChanged( bool ); - void transitioningChanged( bool ); + void fadingChanged( bool ); void modalChanged( bool ); void overlayChanged( bool ); diff --git a/src/controls/QskPopupSkinlet.cpp b/src/controls/QskPopupSkinlet.cpp index d3777785..b989dc1e 100644 --- a/src/controls/QskPopupSkinlet.cpp +++ b/src/controls/QskPopupSkinlet.cpp @@ -5,6 +5,12 @@ #include "QskPopupSkinlet.h" #include "QskPopup.h" +#include "QskRgbValue.h" + +static inline QRgb qskInterpolatedRgb( QRgb rgb, qreal factor ) +{ + return QskRgb::toTransparent( rgb, qRound( factor * qAlpha( rgb ) ) ); +} QskPopupSkinlet::QskPopupSkinlet( QskSkin* skin ) : Inherited( skin ) @@ -28,13 +34,43 @@ QRectF QskPopupSkinlet::subControlRect( const QskSkinnable* skinnable, QSGNode* QskPopupSkinlet::updateSubNode( const QskSkinnable* skinnable, quint8 nodeRole, QSGNode* node ) const { + const auto popup = static_cast< const QskPopup* >( skinnable ); + switch ( nodeRole ) { case OverlayRole: - return updateBoxNode( skinnable, node, QskPopup::Overlay ); + return updateOverlayNode( popup, node ); } return Inherited::updateSubNode( skinnable, nodeRole, node ); } +QSGNode* QskPopupSkinlet::updateOverlayNode( + const QskPopup* popup, QSGNode* node ) const +{ + using Q = QskPopup; + + const auto factor = popup->fadingFactor(); + if ( factor <= 0.0 ) + return nullptr; + + const auto rect = popup->subControlRect( Q::Overlay ); + if ( rect.isEmpty() ) + return nullptr; + + auto gradient = popup->gradientHint( Q::Overlay ); + + if ( gradient.isVisible() && factor != 1.0 ) + { + auto stops = gradient.stops(); + + for ( auto& stop : stops ) + stop.setRgb( qskInterpolatedRgb( stop.rgb(), factor ) ); + + gradient.setStops( stops ); + } + + return updateBoxNode( popup, node, rect, gradient, QskPopup::Overlay ); +} + #include "moc_QskPopupSkinlet.cpp" diff --git a/src/controls/QskSkin.cpp b/src/controls/QskSkin.cpp index a24a212f..a791eb05 100644 --- a/src/controls/QskSkin.cpp +++ b/src/controls/QskSkin.cpp @@ -32,6 +32,9 @@ #include "QskComboBox.h" #include "QskComboBoxSkinlet.h" +#include "QskDrawer.h" +#include "QskDrawerSkinlet.h" + #include "QskFocusIndicator.h" #include "QskFocusIndicatorSkinlet.h" @@ -160,6 +163,7 @@ QskSkin::QskSkin( QObject* parent ) declareSkinlet< QskBox, QskBoxSkinlet >(); declareSkinlet< QskCheckBox, QskCheckBoxSkinlet >(); declareSkinlet< QskComboBox, QskComboBoxSkinlet >(); + declareSkinlet< QskDrawer, QskDrawerSkinlet >(); declareSkinlet< QskFocusIndicator, QskFocusIndicatorSkinlet >(); declareSkinlet< QskGraphicLabel, QskGraphicLabelSkinlet >(); declareSkinlet< QskListView, QskListViewSkinlet >(); diff --git a/src/controls/QskSubWindow.cpp b/src/controls/QskSubWindow.cpp index c278a889..229b4000 100644 --- a/src/controls/QskSubWindow.cpp +++ b/src/controls/QskSubWindow.cpp @@ -253,4 +253,15 @@ void QskSubWindow::itemChange( QQuickItem::ItemChange change, } } +void QskSubWindow::updateResources() +{ + setOpacity( fadingFactor() ); + Inherited::updateResources(); +} + +QskAspect QskSubWindow::fadingAspect() const +{ + return QskSubWindow::Panel | QskAspect::Position; +} + #include "moc_QskSubWindow.cpp" diff --git a/src/controls/QskSubWindow.h b/src/controls/QskSubWindow.h index 47d08e5f..42afd11b 100644 --- a/src/controls/QskSubWindow.h +++ b/src/controls/QskSubWindow.h @@ -83,6 +83,7 @@ class QSK_EXPORT QskSubWindow : public QskPopup QRectF titleBarRect() const; QRectF layoutRectForSize( const QSizeF& ) const override; + QskAspect fadingAspect() const override; Q_SIGNALS: void decorationsChanged( Decorations ); @@ -95,6 +96,8 @@ class QSK_EXPORT QskSubWindow : public QskPopup bool event( QEvent* ) override; void updateLayout() override; + void updateResources() override; + QSizeF layoutSizeHint( Qt::SizeHint, const QSizeF& ) const override; void itemChange( QQuickItem::ItemChange, diff --git a/src/controls/QskSubWindowSkinlet.cpp b/src/controls/QskSubWindowSkinlet.cpp index beea972b..84e9a571 100644 --- a/src/controls/QskSubWindowSkinlet.cpp +++ b/src/controls/QskSubWindowSkinlet.cpp @@ -94,6 +94,18 @@ QSGNode* QskSubWindowSkinlet::updateSubNode( return nullptr; } + case OverlayRole: + { + /* + Overloading QskPopupSkinlet: as the opacity of the subwindow already + depends on the fadingFactor we do not want the additional opacity + adjustments for the overlay node. + Maybe we should have a flag that indicates if the popup does + opacity or geometry transitions, when fading TODO ... + */ + updateBoxNode( subWindow, node, Q::Overlay ); + break; + } } return Inherited::updateSubNode( skinnable, nodeRole, node ); diff --git a/src/dialogs/QskDialog.cpp b/src/dialogs/QskDialog.cpp index cb1b5da7..d75b5b4e 100644 --- a/src/dialogs/QskDialog.cpp +++ b/src/dialogs/QskDialog.cpp @@ -77,6 +77,7 @@ static void qskSetupSubWindow( const QString& title, QskDialog::Actions actions, QskDialog::Action defaultAction, QskDialogSubWindow* subWindow ) { + subWindow->setPopupFlag( QskPopup::DeleteOnClose ); subWindow->setModal( true ); subWindow->setWindowTitle( title ); subWindow->setDialogActions( actions ); @@ -128,14 +129,14 @@ static QskDialog::Action qskMessageSubWindow( const QString& text, int symbolType, QskDialog::Actions actions, QskDialog::Action defaultAction ) { - QskMessageSubWindow subWindow( window->contentItem() ); - subWindow.setSymbolType( symbolType ); - subWindow.setText( text ); + auto subWindow = new QskMessageSubWindow( window->contentItem() ); + subWindow->setSymbolType( symbolType ); + subWindow->setText( text ); - qskSetupSubWindow( title, actions, defaultAction, &subWindow ); - ( void ) subWindow.exec(); + qskSetupSubWindow( title, actions, defaultAction, subWindow ); + ( void ) subWindow->exec(); - auto clickedAction = subWindow.clickedAction(); + auto clickedAction = subWindow->clickedAction(); if ( clickedAction == QskDialog::NoAction ) { // dialog might have been closed by the window menu @@ -172,16 +173,16 @@ static QString qskSelectSubWindow( QskDialog::Actions actions, QskDialog::Action defaultAction, const QStringList& entries, int selectedRow ) { - QskSelectionSubWindow subWindow( window->contentItem() ); - subWindow.setInfoText( text ); - subWindow.setEntries( entries ); - subWindow.setSelectedRow( selectedRow ); + auto subWindow = new QskSelectionSubWindow( window->contentItem() ); + subWindow->setInfoText( text ); + subWindow->setEntries( entries ); + subWindow->setSelectedRow( selectedRow ); QString selectedEntry; - qskSetupSubWindow( title, actions, defaultAction, &subWindow ); - if ( subWindow.exec() == QskDialog::Accepted ) - selectedEntry = subWindow.selectedEntry(); + qskSetupSubWindow( title, actions, defaultAction, subWindow ); + if ( subWindow->exec() == QskDialog::Accepted ) + selectedEntry = subWindow->selectedEntry(); return selectedEntry; } diff --git a/src/nodes/QskSlideInNode.cpp b/src/nodes/QskSlideInNode.cpp deleted file mode 100644 index 24590845..00000000 --- a/src/nodes/QskSlideInNode.cpp +++ /dev/null @@ -1,146 +0,0 @@ -/****************************************************************************** - * 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 - 1.0 ) * 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 deleted file mode 100644 index 532663f2..00000000 --- a/src/nodes/QskSlideInNode.h +++ /dev/null @@ -1,33 +0,0 @@ -/****************************************************************************** - * 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