ongoing work on QskDrawer

This commit is contained in:
Uwe Rathmann 2023-10-05 15:13:47 +02:00
parent eff3641c4c
commit 7294d5a01e
3 changed files with 151 additions and 62 deletions

View File

@ -230,6 +230,7 @@ namespace
{ {
auto drawer = new Drawer( parentItem() ); auto drawer = new Drawer( parentItem() );
drawer->setSizePolicy( Qt::Horizontal, QskSizePolicy::Fixed );
drawer->setEdge( Qt::RightEdge ); drawer->setEdge( Qt::RightEdge );
auto burger = new QskPushButton( "", this ); auto burger = new QskPushButton( "", this );

View File

@ -7,15 +7,104 @@
#include <QskAnimationHint.h> #include <QskAnimationHint.h>
#include <QskQuick.h> #include <QskQuick.h>
QSK_QT_PRIVATE_BEGIN
#include <private/qquickitem_p.h>
#include <private/qquickitemchangelistener_p.h>
QSK_QT_PRIVATE_END
QSK_SUBCONTROL( QskDrawer, Panel ) QSK_SUBCONTROL( QskDrawer, Panel )
QSK_SUBCONTROL( QskDrawer, Overlay ) 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 class QskDrawer::PrivateData
{ {
public: public:
QskControl* content = nullptr; QskControl* content = nullptr;
QskBox* contentBox = nullptr; Box* contentBox = nullptr;
Qt::Edge edge = Qt::LeftEdge; Qt::Edge edge = Qt::LeftEdge;
GeometryListener* listener = nullptr;
}; };
QskDrawer::QskDrawer( QQuickItem* parentItem ) QskDrawer::QskDrawer( QQuickItem* parentItem )
@ -26,23 +115,28 @@ QskDrawer::QskDrawer( QQuickItem* parentItem )
setPopupFlag( PopupFlag::CloseOnPressOutside, true ); setPopupFlag( PopupFlag::CloseOnPressOutside, true );
m_data->contentBox = new QskBox(this); m_data->contentBox = new Box(this);
m_data->contentBox->setSubcontrolProxy( QskBox::Panel, Panel );
m_data->contentBox->setPanel( true );
setSubcontrolProxy( Inherited::Overlay, Overlay ); setSubcontrolProxy( Inherited::Overlay, Overlay );
setFaderAspect( Panel | QskAspect::Metric ); setFaderAspect( Panel | QskAspect::Position | QskAspect::Metric );
connect(this, &QskDrawer::closed, this, [this]() { connect( this, &QskDrawer::closed,
startTransition( Panel | QskAspect::Metric, this, [this]() { startFading( false ); } );
animationHint( Panel | QskAspect::Position ),
0.0, 1.0 ); /*
}); 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() QskDrawer::~QskDrawer()
{ {
delete m_data->listener;
} }
Qt::Edge QskDrawer::edge() const Qt::Edge QskDrawer::edge() const
@ -69,70 +163,58 @@ void QskDrawer::setContent( QskControl* content )
m_data->content = 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() void QskDrawer::updateLayout()
{ {
if ( !isOpen() && !isFading() ) if ( !( isOpen() || isFading() ) )
return; return;
const auto padding = paddingHint( Panel ); const auto targetRect = qskItemRect( parentItem() );
const auto size = qskConstrainedItemSize( this, targetRect.size() );
auto contentSize = m_data->content->preferredSize(); const auto rect = qskDrawerRect( targetRect,
contentSize = contentSize.grownBy( padding ); m_data->edge, metric( faderAspect() ), size );
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 ) );
qskSetItemGeometry( m_data->contentBox, rect );
Inherited::updateLayout(); Inherited::updateLayout();
} }
void QskDrawer::aboutToShow() void QskDrawer::aboutToShow()
{ {
startTransition( Panel | QskAspect::Metric, startFading( true );
animationHint( Panel | QskAspect::Position ), 1.0, 0.0 );
Inherited::aboutToShow(); 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" #include "moc_QskDrawer.cpp"

View File

@ -21,6 +21,7 @@ class QSK_EXPORT QskDrawer : public QskPopup
void setEdge( Qt::Edge ); void setEdge( Qt::Edge );
Qt::Edge edge() const; Qt::Edge edge() const;
QRectF layoutRectForSize( const QSizeF& ) const override;
void updateLayout() override; void updateLayout() override;
void setContent( QskControl* ); void setContent( QskControl* );
@ -30,8 +31,13 @@ class QSK_EXPORT QskDrawer : public QskPopup
protected: protected:
void aboutToShow() override; void aboutToShow() override;
void itemChange( ItemChange, const ItemChangeData& ) override;
QSizeF layoutSizeHint( Qt::SizeHint, const QSizeF& ) const override;
private: private:
void startFading( bool );
class PrivateData; class PrivateData;
std::unique_ptr< PrivateData > m_data; std::unique_ptr< PrivateData > m_data;
}; };