From 7294d5a01e56a222e322ddf603f8386e9ac322ce Mon Sep 17 00:00:00 2001 From: Uwe Rathmann Date: Thu, 5 Oct 2023 15:13:47 +0200 Subject: [PATCH] ongoing work on QskDrawer --- examples/gallery/main.cpp | 1 + src/controls/QskDrawer.cpp | 206 ++++++++++++++++++++++++++----------- src/controls/QskDrawer.h | 6 ++ 3 files changed, 151 insertions(+), 62 deletions(-) diff --git a/examples/gallery/main.cpp b/examples/gallery/main.cpp index b074c299..2978469d 100644 --- a/examples/gallery/main.cpp +++ b/examples/gallery/main.cpp @@ -230,6 +230,7 @@ namespace { auto drawer = new Drawer( parentItem() ); + drawer->setSizePolicy( Qt::Horizontal, QskSizePolicy::Fixed ); drawer->setEdge( Qt::RightEdge ); auto burger = new QskPushButton( "≡", this ); diff --git a/src/controls/QskDrawer.cpp b/src/controls/QskDrawer.cpp index 905a5987..bc3ebe30 100644 --- a/src/controls/QskDrawer.cpp +++ b/src/controls/QskDrawer.cpp @@ -7,15 +7,104 @@ #include #include +QSK_QT_PRIVATE_BEGIN +#include +#include +QSK_QT_PRIVATE_END + QSK_SUBCONTROL( QskDrawer, Panel ) QSK_SUBCONTROL( QskDrawer, Overlay ) +static QRectF qskDrawerRect( const QRectF& rect, + Qt::Edge edge, qreal pos, const QSizeF& size ) +{ + QRectF r( 0.0, 0.0, size.width(), size.height() ); + + const auto progress = pos = 1.0 - pos; + + switch( edge ) + { + case Qt::LeftEdge: + { + r.moveRight( rect.left() + progress * size.width() ); + break; + } + case Qt::RightEdge: + { + r.moveLeft( rect.right() - progress * size.width() ); + break; + } + + case Qt::TopEdge: + { + r.moveBottom( rect.top() + progress * size.height() ); + break; + } + + case Qt::BottomEdge: + { + r.moveTop( rect.bottom() - progress * size.height() ); + break; + } + } + + return r; +} + +namespace +{ + class GeometryListener final : public QQuickItemChangeListener + { + public: + GeometryListener( QskDrawer* drawer ) + : m_drawer( drawer ) + { + if ( drawer->parentItem() ) + { + auto d = QQuickItemPrivate::get( drawer->parentItem() ); + d->addItemChangeListener( this, QQuickItemPrivate::Geometry ); + } + } + + private: + void itemGeometryChanged( QQuickItem*, + QQuickGeometryChange, const QRectF& ) override + { + m_drawer->polish(); + } + + private: + QskDrawer* m_drawer = nullptr; + }; + + class Box : public QskBox + { + using Inherited = QskBox; + + public: + Box( QskDrawer* drawer ) + : QskBox( drawer ) + { + setSubcontrolProxy( QskBox::Panel, Panel ); + setPanel( true ); + setAutoLayoutChildren( true ); + +#if 0 + setBackgroundColor( Qt::darkCyan ); + setMargins( 20 ); +#endif + } + }; +} + class QskDrawer::PrivateData { public: QskControl* content = nullptr; - QskBox* contentBox = nullptr; + Box* contentBox = nullptr; Qt::Edge edge = Qt::LeftEdge; + + GeometryListener* listener = nullptr; }; QskDrawer::QskDrawer( QQuickItem* parentItem ) @@ -26,23 +115,28 @@ QskDrawer::QskDrawer( QQuickItem* parentItem ) setPopupFlag( PopupFlag::CloseOnPressOutside, true ); - m_data->contentBox = new QskBox(this); - m_data->contentBox->setSubcontrolProxy( QskBox::Panel, Panel ); - m_data->contentBox->setPanel( true ); + m_data->contentBox = new Box(this); setSubcontrolProxy( Inherited::Overlay, Overlay ); - setFaderAspect( Panel | QskAspect::Metric ); + setFaderAspect( Panel | QskAspect::Position | QskAspect::Metric ); - connect(this, &QskDrawer::closed, this, [this]() { - startTransition( Panel | QskAspect::Metric, - animationHint( Panel | QskAspect::Position ), - 0.0, 1.0 ); - }); + connect( this, &QskDrawer::closed, + this, [this]() { startFading( false ); } ); + + /* + The drawer wants to be on top of the parent - not being + layouted into its layoutRect(). So we opt out and do + the layout updates manually. + */ + setPlacementPolicy( QskPlacementPolicy::Ignore ); + if ( parentItem ) + m_data->listener = new GeometryListener( this ); } QskDrawer::~QskDrawer() { + delete m_data->listener; } Qt::Edge QskDrawer::edge() const @@ -69,70 +163,58 @@ void QskDrawer::setContent( QskControl* content ) m_data->content = content; } +QSizeF QskDrawer::layoutSizeHint( + Qt::SizeHint which, const QSizeF& constraint ) const +{ + // we need to handle QEvent::LayoutRequest + return m_data->contentBox->effectiveSizeHint( which, constraint ); +} + +QRectF QskDrawer::layoutRectForSize( const QSizeF& size ) const +{ + return Inherited::layoutRectForSize( size ); +} + void QskDrawer::updateLayout() { - if ( !isOpen() && !isFading() ) + if ( !( isOpen() || isFading() ) ) return; - const auto padding = paddingHint( Panel ); + const auto targetRect = qskItemRect( parentItem() ); + const auto size = qskConstrainedItemSize( this, targetRect.size() ); - auto contentSize = m_data->content->preferredSize(); - contentSize = contentSize.grownBy( padding ); - - const auto parentSize = parentItem()->size(); - - switch( m_data->edge ) - { - case Qt::Edge::LeftEdge: - { - qreal x = metric( faderAspect() ) * contentSize.width() * -1.0; - - qskSetItemGeometry( m_data->contentBox, - x, 0, contentSize.width(), parentSize.height() ); - break; - } - case Qt::Edge::RightEdge: - { - qreal x = ( metric( faderAspect() ) * contentSize.width() ) - + parentSize.width() - contentSize.width(); - - qskSetItemGeometry( m_data->contentBox, - x, 0, contentSize.width(), parentSize.height() ); - break; - } - - case Qt::Edge::TopEdge: - { - qreal y = metric( faderAspect() ) * contentSize.height(); - - qskSetItemGeometry( m_data->contentBox, - 0, -y, parentSize.width(), contentSize.height() ); - break; - } - - case Qt::Edge::BottomEdge: - { - qreal y = metric( faderAspect() ) * contentSize.height() + parentSize.height() - - contentSize.height(); - - qskSetItemGeometry( m_data->contentBox, - 0, y, parentSize.width(), contentSize.height() ); - break; - } - } - - m_data->content->setGeometry( QPointF( padding.left(), padding.top() ), - m_data->contentBox->size().shrunkBy( padding ) ); + const auto rect = qskDrawerRect( targetRect, + m_data->edge, metric( faderAspect() ), size ); + qskSetItemGeometry( m_data->contentBox, rect ); Inherited::updateLayout(); } void QskDrawer::aboutToShow() { - startTransition( Panel | QskAspect::Metric, - animationHint( Panel | QskAspect::Position ), 1.0, 0.0 ); - + startFading( true ); Inherited::aboutToShow(); } +void QskDrawer::itemChange( QQuickItem::ItemChange change, + const QQuickItem::ItemChangeData& value ) +{ + Inherited::itemChange( change, value ); + + if ( change == QQuickItem::ItemParentHasChanged ) + { + delete m_data->listener; + m_data->listener = new GeometryListener( this ); + } +} + +void QskDrawer::startFading( bool open ) +{ + const auto from = open ? 1.0 : 0.0; + const auto to = open ? 0.0 : 1.0; + + const auto hint = animationHint( Panel | QskAspect::Position ); + startTransition( faderAspect(), hint, from, to ); +} + #include "moc_QskDrawer.cpp" diff --git a/src/controls/QskDrawer.h b/src/controls/QskDrawer.h index 442f95e7..313760d5 100644 --- a/src/controls/QskDrawer.h +++ b/src/controls/QskDrawer.h @@ -21,6 +21,7 @@ class QSK_EXPORT QskDrawer : public QskPopup void setEdge( Qt::Edge ); Qt::Edge edge() const; + QRectF layoutRectForSize( const QSizeF& ) const override; void updateLayout() override; void setContent( QskControl* ); @@ -30,8 +31,13 @@ class QSK_EXPORT QskDrawer : public QskPopup protected: void aboutToShow() override; + void itemChange( ItemChange, const ItemChangeData& ) override; + + QSizeF layoutSizeHint( Qt::SizeHint, const QSizeF& ) const override; private: + void startFading( bool ); + class PrivateData; std::unique_ptr< PrivateData > m_data; };