much easier implementation used - the only hack is about updating the

clip node manually for each updatePaintNode
This commit is contained in:
Uwe Rathmann 2023-10-27 07:58:27 +02:00
parent a9621f19ed
commit 4afe56990b
6 changed files with 128 additions and 131 deletions

View File

@ -9,6 +9,7 @@
#include <QskControl.h>
#include <QskDrawer.h>
#include <QskPushButton.h>
#include <QskFocusIndicator.h>
#include <QskWindow.h>
#include <QskEvent.h>
#include <QskAnimationHint.h>
@ -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();

View File

@ -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 )

View File

@ -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;

View File

@ -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
{

View File

@ -4,14 +4,14 @@
*****************************************************************************/
#include "QskSlideIn.h"
#include "QskAnimationHint.h"
#include "QskQuick.h"
QSK_QT_PRIVATE_BEGIN
#include <private/qquickitem_p.h>
#include <private/qquickitemchangelistener_p.h>
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"

View File

@ -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;