From 4afe56990b317d74f74a2ff18a4db02b6098397f Mon Sep 17 00:00:00 2001 From: Uwe Rathmann Date: Fri, 27 Oct 2023 07:58:27 +0200 Subject: [PATCH] much easier implementation used - the only hack is about updating the clip node manually for each updatePaintNode --- playground/drawer/main.cpp | 17 ++-- src/controls/QskDrawer.cpp | 56 ------------- src/controls/QskDrawer.h | 2 - src/controls/QskHintAnimator.cpp | 48 ++++++----- src/controls/QskSlideIn.cpp | 132 ++++++++++++++++++++++--------- src/controls/QskSlideIn.h | 4 +- 6 files changed, 128 insertions(+), 131 deletions(-) diff --git a/playground/drawer/main.cpp b/playground/drawer/main.cpp index 119e7066..02acfa0d 100644 --- a/playground/drawer/main.cpp +++ b/playground/drawer/main.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -30,31 +31,32 @@ namespace content->setAutoLayoutChildren( true ); content->setMargins( 20 ); + auto button = new QskPushButton( "Push Me", content ); + button->setSizePolicy( QskSizePolicy::Fixed, QskSizePolicy::Fixed ); + button->setLayoutAlignmentHint( Qt::AlignCenter ); + + const auto size = content->sizeHint(); + switch( edge ) { case Qt::LeftEdge: content->setBackgroundColor( QskRgb::Tomato ); - content->setFixedWidth( 100 ); break; case Qt::RightEdge: - content->setFixedWidth( 200 ); + content->setFixedWidth( 1.5 * size.width() ); content->setBackgroundColor( QskRgb::Orchid ); break; case Qt::TopEdge: - content->setFixedHeight( 100 ); content->setBackgroundColor( QskRgb::Chartreuse ); break; case Qt::BottomEdge: - content->setFixedHeight( 200 ); + content->setFixedHeight( 2 * size.height() ); content->setBackgroundColor( QskRgb::Wheat ); break; } - - auto button = new QskPushButton( "Push Me", content ); - button->setPreferredHeight( 100 ); } }; @@ -127,6 +129,7 @@ int main( int argc, char* argv[] ) SkinnyShortcut::enable( SkinnyShortcut::AllShortcuts ); QskWindow window; + window.addItem( new QskFocusIndicator() ); window.addItem( new MainBox() ); window.resize( 600, 600 ); window.show(); diff --git a/src/controls/QskDrawer.cpp b/src/controls/QskDrawer.cpp index b12f12ee..ed54ddbe 100644 --- a/src/controls/QskDrawer.cpp +++ b/src/controls/QskDrawer.cpp @@ -51,44 +51,6 @@ static bool qskCheckDirection( Qt::Edge edge, const QskPanGesture* gesture ) return false; } -static inline QRectF qskAlignedToEdge( - const QRectF& rect, const QSizeF& size, Qt::Edge edge ) -{ - QRectF r( 0.0, 0.0, size.width(), size.height() ); - - switch( 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; - } - } - - return r; -} - namespace { class GestureRecognizer : public QskPanGestureRecognizer @@ -231,24 +193,6 @@ qreal QskDrawer::dragMargin() const return m_data->dragMargin; } -bool QskDrawer::event( QEvent* event ) -{ - if ( event->type() == QEvent::PolishRequest ) - { - if ( const auto item = parentItem() ) - { - auto r = qskItemRect( item ); - r = qskAlignedToEdge( r, sizeConstraint( Qt::PreferredSize ), edge() ); - - setGeometry( r ); - - return true; - } - } - - return Inherited::event( event ); -} - void QskDrawer::gestureEvent( QskGestureEvent* event ) { if ( event->gesture()->type() == QskGesture::Pan ) diff --git a/src/controls/QskDrawer.h b/src/controls/QskDrawer.h index e3c6e89d..eec8ef89 100644 --- a/src/controls/QskDrawer.h +++ b/src/controls/QskDrawer.h @@ -42,8 +42,6 @@ class QSK_EXPORT QskDrawer : public QskSlideIn void interactiveChanged( bool ); protected: - bool event( QEvent* ) override; - void itemChange( ItemChange, const ItemChangeData& ) override; void gestureEvent( QskGestureEvent* ) override; diff --git a/src/controls/QskHintAnimator.cpp b/src/controls/QskHintAnimator.cpp index d9dc82f0..cec53ccd 100644 --- a/src/controls/QskHintAnimator.cpp +++ b/src/controls/QskHintAnimator.cpp @@ -76,20 +76,28 @@ static inline QVariant qskAligned05( const QVariant& value ) #endif -static inline bool qskCheckReceiverThread( const QObject* receiver ) +static inline void qskSendAnimatorEvent( + const QskAspect aspect, int index, bool on, QObject* receiver ) { - /* - QskInputPanelSkinlet changes the skin state, what leads to - sending events from the wrong thread. Until we have fixed it - let's block sending the event to avoid running into assertions - in QCoreApplication::sendEvent - */ + const auto state = on ? QskAnimatorEvent::Started : QskAnimatorEvent::Terminated; - const QThread* thread = receiver->thread(); - if ( thread == nullptr ) - return true; - - return ( thread == QThread::currentThread() ); + const auto thread = receiver->thread(); + if ( thread && ( thread != QThread::currentThread() ) ) + { + /* + QskInputPanelSkinlet changes the skin state, what leads to + sending events from the wrong thread. We can't use + QCoreApplication::sendEvent then, TODO ... + */ + + auto event = new QskAnimatorEvent( aspect, index, state ); + QCoreApplication::postEvent( receiver, event ); + } + else + { + QskAnimatorEvent event( aspect, index, state ); + QCoreApplication::sendEvent( receiver, &event ); + } } QskHintAnimator::QskHintAnimator() noexcept @@ -338,11 +346,7 @@ void QskHintAnimatorTable::start( QskControl* control, animator->start(); - if ( qskCheckReceiverThread( control ) ) - { - QskAnimatorEvent event( aspect, index, QskAnimatorEvent::Started ); - QCoreApplication::sendEvent( control, &event ); - } + qskSendAnimatorEvent( aspect, index, true, control ); } const QskHintAnimator* QskHintAnimatorTable::animator( QskAspect aspect, int index ) const @@ -390,15 +394,7 @@ bool QskHintAnimatorTable::cleanup() it = animators.erase( it ); if ( control ) - { - if ( qskCheckReceiverThread( control ) ) - { - auto event = new QskAnimatorEvent( - aspect, index, QskAnimatorEvent::Terminated ); - - QCoreApplication::postEvent( control, event ); - } - } + qskSendAnimatorEvent( aspect, index, false, control ); } else { diff --git a/src/controls/QskSlideIn.cpp b/src/controls/QskSlideIn.cpp index d622d759..9734fc83 100644 --- a/src/controls/QskSlideIn.cpp +++ b/src/controls/QskSlideIn.cpp @@ -4,14 +4,14 @@ *****************************************************************************/ #include "QskSlideIn.h" -#include "QskAnimationHint.h" +#include "QskQuick.h" QSK_QT_PRIVATE_BEGIN #include #include QSK_QT_PRIVATE_END -static QPointF qskSlideInTranslation( const QskSlideIn* slideIn ) +static QPointF qskSlideInTranslation( const QskSlideIn* slideIn, const QSizeF& size ) { const auto ratio = 1.0 - slideIn->transitioningFactor(); @@ -21,59 +21,44 @@ static QPointF qskSlideInTranslation( const QskSlideIn* slideIn ) switch( slideIn->edge() ) { case Qt::LeftEdge: - dx = -ratio * slideIn->width(); + dx = -ratio * size.width(); break; case Qt::RightEdge: - dx = ratio * slideIn->width(); + dx = ratio * size.width(); break; case Qt::TopEdge: - dy = -ratio * slideIn->height(); + dy = -ratio * size.height(); break; case Qt::BottomEdge: - dy = ratio * slideIn->height(); + dy = ratio * size.height(); break; } return QPointF( dx, dy ); } -static inline QRectF qskUnboundedClipRect( const QRectF& rect, Qt::Edge edge ) +static inline QRectF qskAlignedToEdge( + const QRectF& r, const QSizeF& sz, Qt::Edge edge ) { - /* - When sliding we want to clip against the edge, where the drawer - slides in/out. However the size of the slidein 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. - */ - constexpr qreal d = 1e6; - - QRectF r( -d, -d, 2.0 * d, 2.0 * d ); - switch( edge ) { case Qt::LeftEdge: - r.setLeft( rect.left() ); - break; + return QRectF( r.left(), r.top(), sz.width(), r.height() ); case Qt::RightEdge: - r.setRight( rect.right() ); - break; + return QRectF( r.right() - sz.width(), r.top(), sz.width(), r.height() ); case Qt::TopEdge: - r.setTop( rect.top() ); - break; + return QRectF( r.left(), r.top(), r.width(), sz.height() ); case Qt::BottomEdge: - r.setBottom( rect.bottom() ); - break; + return QRectF( r.left(), r.bottom() - sz.height(), r.width(), sz.height() ); } - return r; + return QRectF(); } namespace @@ -106,8 +91,7 @@ namespace private: void adjust() { - QEvent event( QEvent::PolishRequest ); - QCoreApplication::sendEvent( m_adjustedItem, &event ); + m_adjustedItem->polish(); } void setEnabled( bool on ) @@ -159,7 +143,7 @@ QskSlideIn::QskSlideIn( QQuickItem* parentItem ) setPlacementPolicy( QskPlacementPolicy::Ignore ); connect( this, &QskPopup::transitioningChanged, - this, &QskSlideIn::setClip ); + this, &QQuickItem::setClip ); } QskSlideIn::~QskSlideIn() @@ -197,17 +181,89 @@ void QskSlideIn::itemChange( QQuickItem::ItemChange change, } } -QRectF QskSlideIn::clipRect() const +void QskSlideIn::updateResources() { - if ( !isTransitioning() ) - return Inherited::clipRect(); + Inherited::updateResources(); + + /* + 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() ); - return qskUnboundedClipRect( rect(), edge() ); + r.translate( qskSlideInTranslation( this, r.size() ) ); + setGeometry( r ); + } } -QRectF QskSlideIn::layoutRectForSize( const QSizeF& size ) const -{ - return QRectF( qskSlideInTranslation( this ), size ); +QRectF QskSlideIn::clipRect() const +{ + if ( isTransitioning() && parentItem() ) + { + // parent rectangle translated into the coordinate system of the slideIn + const QRectF rect( -position(), parentItem()->size() ); + + /* + 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; + + QRectF r( -d, -d, 2.0 * d, 2.0 * d ); + + switch( edge() ) + { + case Qt::LeftEdge: + r.setLeft( rect.left() ); + break; + + case Qt::RightEdge: + r.setRight( rect.right() ); + break; + + case Qt::TopEdge: + r.setTop( rect.top() ); + break; + + case Qt::BottomEdge: + r.setBottom( rect.bottom() ); + break; + } + + return r; + } + + return Inherited::clipRect(); +} + +void QskSlideIn::updateNode( QSGNode* node ) +{ + if ( isTransitioning() && clip() ) + { + if ( auto clipNode = QQuickItemPrivate::get( this )->clipNode() ) + { + /* + The clipRect is changing while transitioning. 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 ); } #include "moc_QskSlideIn.cpp" diff --git a/src/controls/QskSlideIn.h b/src/controls/QskSlideIn.h index 37a72979..ab41cf1e 100644 --- a/src/controls/QskSlideIn.h +++ b/src/controls/QskSlideIn.h @@ -25,12 +25,12 @@ class QSK_EXPORT QskSlideIn : public QskPopup void setAdjustingToParentGeometry( bool on ); bool isAdjustingToParentGeometry() const; - QRectF layoutRectForSize( const QSizeF& ) const override; - protected: QskSlideIn( QQuickItem* = nullptr ); void itemChange( ItemChange, const ItemChangeData& ) override; + void updateResources() override; + void updateNode( QSGNode* ) override; private: class PrivateData;