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 <QskControl.h>
#include <QskDrawer.h> #include <QskDrawer.h>
#include <QskPushButton.h> #include <QskPushButton.h>
#include <QskFocusIndicator.h>
#include <QskWindow.h> #include <QskWindow.h>
#include <QskEvent.h> #include <QskEvent.h>
#include <QskAnimationHint.h> #include <QskAnimationHint.h>
@ -30,31 +31,32 @@ namespace
content->setAutoLayoutChildren( true ); content->setAutoLayoutChildren( true );
content->setMargins( 20 ); 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 ) switch( edge )
{ {
case Qt::LeftEdge: case Qt::LeftEdge:
content->setBackgroundColor( QskRgb::Tomato ); content->setBackgroundColor( QskRgb::Tomato );
content->setFixedWidth( 100 );
break; break;
case Qt::RightEdge: case Qt::RightEdge:
content->setFixedWidth( 200 ); content->setFixedWidth( 1.5 * size.width() );
content->setBackgroundColor( QskRgb::Orchid ); content->setBackgroundColor( QskRgb::Orchid );
break; break;
case Qt::TopEdge: case Qt::TopEdge:
content->setFixedHeight( 100 );
content->setBackgroundColor( QskRgb::Chartreuse ); content->setBackgroundColor( QskRgb::Chartreuse );
break; break;
case Qt::BottomEdge: case Qt::BottomEdge:
content->setFixedHeight( 200 ); content->setFixedHeight( 2 * size.height() );
content->setBackgroundColor( QskRgb::Wheat ); content->setBackgroundColor( QskRgb::Wheat );
break; 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 ); SkinnyShortcut::enable( SkinnyShortcut::AllShortcuts );
QskWindow window; QskWindow window;
window.addItem( new QskFocusIndicator() );
window.addItem( new MainBox() ); window.addItem( new MainBox() );
window.resize( 600, 600 ); window.resize( 600, 600 );
window.show(); window.show();

View File

@ -51,44 +51,6 @@ static bool qskCheckDirection( Qt::Edge edge, const QskPanGesture* gesture )
return false; 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 namespace
{ {
class GestureRecognizer : public QskPanGestureRecognizer class GestureRecognizer : public QskPanGestureRecognizer
@ -231,24 +193,6 @@ qreal QskDrawer::dragMargin() const
return m_data->dragMargin; 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 ) void QskDrawer::gestureEvent( QskGestureEvent* event )
{ {
if ( event->gesture()->type() == QskGesture::Pan ) if ( event->gesture()->type() == QskGesture::Pan )

View File

@ -42,8 +42,6 @@ class QSK_EXPORT QskDrawer : public QskSlideIn
void interactiveChanged( bool ); void interactiveChanged( bool );
protected: protected:
bool event( QEvent* ) override;
void itemChange( ItemChange, const ItemChangeData& ) override; void itemChange( ItemChange, const ItemChangeData& ) override;
void gestureEvent( QskGestureEvent* ) override; void gestureEvent( QskGestureEvent* ) override;

View File

@ -76,20 +76,28 @@ static inline QVariant qskAligned05( const QVariant& value )
#endif #endif
static inline bool qskCheckReceiverThread( const QObject* receiver ) static inline void qskSendAnimatorEvent(
const QskAspect aspect, int index, bool on, QObject* receiver )
{
const auto state = on ? QskAnimatorEvent::Started : QskAnimatorEvent::Terminated;
const auto thread = receiver->thread();
if ( thread && ( thread != QThread::currentThread() ) )
{ {
/* /*
QskInputPanelSkinlet changes the skin state, what leads to QskInputPanelSkinlet changes the skin state, what leads to
sending events from the wrong thread. Until we have fixed it sending events from the wrong thread. We can't use
let's block sending the event to avoid running into assertions QCoreApplication::sendEvent then, TODO ...
in QCoreApplication::sendEvent
*/ */
const QThread* thread = receiver->thread(); auto event = new QskAnimatorEvent( aspect, index, state );
if ( thread == nullptr ) QCoreApplication::postEvent( receiver, event );
return true; }
else
return ( thread == QThread::currentThread() ); {
QskAnimatorEvent event( aspect, index, state );
QCoreApplication::sendEvent( receiver, &event );
}
} }
QskHintAnimator::QskHintAnimator() noexcept QskHintAnimator::QskHintAnimator() noexcept
@ -338,11 +346,7 @@ void QskHintAnimatorTable::start( QskControl* control,
animator->start(); animator->start();
if ( qskCheckReceiverThread( control ) ) qskSendAnimatorEvent( aspect, index, true, control );
{
QskAnimatorEvent event( aspect, index, QskAnimatorEvent::Started );
QCoreApplication::sendEvent( control, &event );
}
} }
const QskHintAnimator* QskHintAnimatorTable::animator( QskAspect aspect, int index ) const const QskHintAnimator* QskHintAnimatorTable::animator( QskAspect aspect, int index ) const
@ -390,15 +394,7 @@ bool QskHintAnimatorTable::cleanup()
it = animators.erase( it ); it = animators.erase( it );
if ( control ) if ( control )
{ qskSendAnimatorEvent( aspect, index, false, control );
if ( qskCheckReceiverThread( control ) )
{
auto event = new QskAnimatorEvent(
aspect, index, QskAnimatorEvent::Terminated );
QCoreApplication::postEvent( control, event );
}
}
} }
else else
{ {

View File

@ -4,14 +4,14 @@
*****************************************************************************/ *****************************************************************************/
#include "QskSlideIn.h" #include "QskSlideIn.h"
#include "QskAnimationHint.h" #include "QskQuick.h"
QSK_QT_PRIVATE_BEGIN QSK_QT_PRIVATE_BEGIN
#include <private/qquickitem_p.h> #include <private/qquickitem_p.h>
#include <private/qquickitemchangelistener_p.h> #include <private/qquickitemchangelistener_p.h>
QSK_QT_PRIVATE_END 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(); const auto ratio = 1.0 - slideIn->transitioningFactor();
@ -21,59 +21,44 @@ static QPointF qskSlideInTranslation( const QskSlideIn* slideIn )
switch( slideIn->edge() ) switch( slideIn->edge() )
{ {
case Qt::LeftEdge: case Qt::LeftEdge:
dx = -ratio * slideIn->width(); dx = -ratio * size.width();
break; break;
case Qt::RightEdge: case Qt::RightEdge:
dx = ratio * slideIn->width(); dx = ratio * size.width();
break; break;
case Qt::TopEdge: case Qt::TopEdge:
dy = -ratio * slideIn->height(); dy = -ratio * size.height();
break; break;
case Qt::BottomEdge: case Qt::BottomEdge:
dy = ratio * slideIn->height(); dy = ratio * size.height();
break; break;
} }
return QPointF( dx, dy ); 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 ) switch( edge )
{ {
case Qt::LeftEdge: case Qt::LeftEdge:
r.setLeft( rect.left() ); return QRectF( r.left(), r.top(), sz.width(), r.height() );
break;
case Qt::RightEdge: case Qt::RightEdge:
r.setRight( rect.right() ); return QRectF( r.right() - sz.width(), r.top(), sz.width(), r.height() );
break;
case Qt::TopEdge: case Qt::TopEdge:
r.setTop( rect.top() ); return QRectF( r.left(), r.top(), r.width(), sz.height() );
break;
case Qt::BottomEdge: case Qt::BottomEdge:
r.setBottom( rect.bottom() ); return QRectF( r.left(), r.bottom() - sz.height(), r.width(), sz.height() );
break;
} }
return r; return QRectF();
} }
namespace namespace
@ -106,8 +91,7 @@ namespace
private: private:
void adjust() void adjust()
{ {
QEvent event( QEvent::PolishRequest ); m_adjustedItem->polish();
QCoreApplication::sendEvent( m_adjustedItem, &event );
} }
void setEnabled( bool on ) void setEnabled( bool on )
@ -159,7 +143,7 @@ QskSlideIn::QskSlideIn( QQuickItem* parentItem )
setPlacementPolicy( QskPlacementPolicy::Ignore ); setPlacementPolicy( QskPlacementPolicy::Ignore );
connect( this, &QskPopup::transitioningChanged, connect( this, &QskPopup::transitioningChanged,
this, &QskSlideIn::setClip ); this, &QQuickItem::setClip );
} }
QskSlideIn::~QskSlideIn() QskSlideIn::~QskSlideIn()
@ -197,17 +181,89 @@ void QskSlideIn::itemChange( QQuickItem::ItemChange change,
} }
} }
QRectF QskSlideIn::clipRect() const void QskSlideIn::updateResources()
{ {
if ( !isTransitioning() ) Inherited::updateResources();
return Inherited::clipRect();
return qskUnboundedClipRect( rect(), edge() ); /*
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() );
r.translate( qskSlideInTranslation( this, r.size() ) );
setGeometry( r );
}
} }
QRectF QskSlideIn::layoutRectForSize( const QSizeF& size ) const QRectF QskSlideIn::clipRect() const
{ {
return QRectF( qskSlideInTranslation( this ), size ); 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" #include "moc_QskSlideIn.cpp"

View File

@ -25,12 +25,12 @@ class QSK_EXPORT QskSlideIn : public QskPopup
void setAdjustingToParentGeometry( bool on ); void setAdjustingToParentGeometry( bool on );
bool isAdjustingToParentGeometry() const; bool isAdjustingToParentGeometry() const;
QRectF layoutRectForSize( const QSizeF& ) const override;
protected: protected:
QskSlideIn( QQuickItem* = nullptr ); QskSlideIn( QQuickItem* = nullptr );
void itemChange( ItemChange, const ItemChangeData& ) override; void itemChange( ItemChange, const ItemChangeData& ) override;
void updateResources() override;
void updateNode( QSGNode* ) override;
private: private:
class PrivateData; class PrivateData;