QskViewportChange events added ( using the QQuickItem::ItemObservesViewport

concept )
This commit is contained in:
Uwe Rathmann 2025-01-06 14:40:48 +01:00
parent 70cc744ba2
commit 4f91034745
8 changed files with 130 additions and 70 deletions

View File

@ -26,8 +26,6 @@
#include <cstdlib>
#define HIDE_NODES 1
const int gridSize = 20;
const int thumbnailSize = 150;
@ -81,18 +79,6 @@ class Thumbnail : public QskPushButton
setStrutSizeHint( QskPushButton::Icon, -1, -1 );
}
#if 0
void mousePressEvent( QMouseEvent* event ) override
{
/*
ignore events: to check if the pan gesture recoognizer of the scroll
area works, when the event arrives as regular event
( not via childMouseEventFilter )
*/
event->setAccepted( false );
}
#endif
private:
QskGraphic thumbnailGraphic( const QColor& color,
int shape, const QSizeF& size ) const
@ -124,54 +110,67 @@ class IconGrid : public QskLinearBox
IconGrid( QQuickItem* parentItem = nullptr )
: QskLinearBox( Qt::Horizontal, gridSize, parentItem )
{
#if QT_VERSION >= QT_VERSION_CHECK( 6, 3, 0 )
setFlag( QQuickItem::ItemObservesViewport, true );
#endif
setMargins( 20 );
setSpacing( 20 );
for ( int col = 0; col < gridSize; col++ )
{
for ( int row = 0; row < gridSize; row++ )
( void ) new Thumbnail( randomColor(), randomShape(), this );
{
auto thumbnail = new Thumbnail( randomColor(), randomShape(), this );
thumbnail->setPlacementPolicy( Qsk::Hidden, QskPlacementPolicy::Reserve );
thumbnail->setVisible( false );
}
}
#if HIDE_NODES
setSize( sizeConstraint() );
}
protected:
void viewportChangeEvent( QskViewportChangeEvent* ) override
{
if ( isEmpty() )
return;
/*
When having too many nodes, the scene graph becomes horribly slow.
So we explicitely hide all items outside the visible area
( see updateVisibilities below ) and make use of the DeferredUpdate and
CleanupOnVisibility features of QskItem.
*/
setSize( sizeConstraint() );
updateLayout(); // so that every item has its initial geometry
for ( int i = 0; i < elementCount(); i++ )
{
if ( auto control = qskControlCast( itemAtIndex( i ) ) )
{
// to support the optimizations in ScrollArea::updateVisibilities
control->setPlacementPolicy( Qsk::Hidden, QskPlacementPolicy::Reserve );
control->setVisible( false );
}
}
QQuickItem* item;
#if QT_VERSION >= QT_VERSION_CHECK( 6, 3, 0 )
item = viewportItem();
#else
for ( item = parentItem(); item && !item->clip(); item = item->parentItem() );
#endif
}
#if HIDE_NODES
void updateVisibilities( const QRectF& viewPort )
{
if ( !isEmpty() && viewPort != m_viewPort )
if ( item )
{
setItemsVisible( m_viewPort, false );
setItemsVisible( viewPort, true );
auto r = item->clipRect();
r.moveTo( mapFromItem( item, r.topLeft() ) );
m_viewPort = viewPort;
const auto viewPort = this->viewPort( r );
if ( m_viewPort != viewPort )
{
setItemsVisible( m_viewPort, false );
setItemsVisible( viewPort, true );
m_viewPort = viewPort;
}
}
}
private:
void setItemsVisible( const QRectF& rect, bool on )
QRect viewPort( const QRectF& rect ) const
{
const auto dim = dimension();
// we know, that all items have the same size
const auto itemSize = itemAtIndex( 0 )->size();
@ -181,9 +180,16 @@ class IconGrid : public QskLinearBox
const int colMin = rect.left() / ( itemSize.width() + spacing() );
const int colMax = rect.right() / ( itemSize.height() + spacing() );
for ( int row = rowMin; row <= rowMax; row++ )
return QRect( colMin, rowMin, colMax - colMin + 1, rowMax - rowMin + 1 );
}
void setItemsVisible( const QRect& viewPort, bool on )
{
const auto dim = dimension();
for ( int row = viewPort.top(); row <= viewPort.bottom(); row++ )
{
for ( int col = colMin; col <= colMax; col++ )
for ( int col = viewPort.left(); col <= viewPort.right(); col++ )
{
if ( auto item = itemAtIndex( row * dim + col ) )
item->setVisible( on );
@ -191,8 +197,7 @@ class IconGrid : public QskLinearBox
}
}
QRectF m_viewPort;
#endif
QRect m_viewPort;
};
class ScrollArea : public QskScrollArea
@ -218,29 +223,6 @@ class ScrollArea : public QskScrollArea
setBoxShapeHint( HorizontalScrollHandle, 8 );
setFlickRecognizerTimeout( 300 );
connect( this, &QskScrollView::scrollPosChanged,
this, &ScrollArea::updateVisibilities );
}
protected:
void geometryChangeEvent( QskGeometryChangeEvent* event ) override
{
QskScrollArea::geometryChangeEvent( event );
updateVisibilities();
}
private:
void updateVisibilities()
{
#if HIDE_NODES
const auto box = static_cast< IconGrid* >( scrolledItem() );
if ( box )
{
const QRectF viewPort( scrollPos(), viewContentsRect().size() );
box->updateVisibilities( viewPort );
}
#endif
}
};
@ -291,7 +273,7 @@ int main( int argc, char* argv[] )
scrollArea->setScrolledItem( iconGrid );
#if 0
// for testing nested gestures
// for testing nested gestures
auto swipeView = new QskSwipeView();
swipeView->addItem( scrollArea );

View File

@ -189,6 +189,7 @@ QskEvent* QskEvent::clone() const
}
#endif
// -- QskGeometryChangeEvent
QskGeometryChangeEvent::QskGeometryChangeEvent(
@ -216,6 +217,19 @@ bool QskGeometryChangeEvent::isMoved() const
( m_rect.y() != m_oldRect.y() );
}
// -- QskViewportChangeEvent
QskViewportChangeEvent::QskViewportChangeEvent( QQuickItem* modifiedParent )
: QskEvent( QskEvent::ViewportChange )
, m_modifiedParent( modifiedParent )
{
}
QskViewportChangeEvent* QskViewportChangeEvent::clone() const
{
return new QskViewportChangeEvent( *this );
}
// -- QskWindowChangeEvent
QskWindowChangeEvent::QskWindowChangeEvent(

View File

@ -37,6 +37,7 @@ class QSK_EXPORT QskEvent : public QEvent
NoEvent = 53800,
GeometryChange,
ViewportChange,
WindowChange,
/*
@ -85,6 +86,22 @@ class QSK_EXPORT QskGeometryChangeEvent : public QskEvent
QRectF m_oldRect;
};
class QSK_EXPORT QskViewportChangeEvent : public QskEvent
{
public:
QskViewportChangeEvent( QQuickItem* );
inline QQuickItem* modifiedParent() const { return m_modifiedParent; }
QskViewportChangeEvent* clone() const override;
protected:
QSK_EVENT_DISABLE_COPY( QskViewportChangeEvent )
private:
QQuickItem* m_modifiedParent;
};
class QSK_EXPORT QskWindowChangeEvent : public QskEvent
{
public:

View File

@ -781,6 +781,11 @@ bool QskItem::event( QEvent* event )
changeEvent( event );
return true;
}
case QskEvent::ViewportChange:
{
viewportChangeEvent( static_cast< QskViewportChangeEvent* >( event ) );
return true;
}
case QskEvent::GeometryChange:
{
geometryChangeEvent( static_cast< QskGeometryChangeEvent* >( event ) );
@ -858,6 +863,11 @@ void QskItem::windowChangeEvent( QskWindowChangeEvent* )
{
}
void QskItem::viewportChangeEvent( QskViewportChangeEvent* event )
{
event->ignore();
}
void QskItem::geometryChangeEvent( QskGeometryChangeEvent* )
{
}

View File

@ -11,6 +11,7 @@
class QskItemPrivate;
class QskGeometryChangeEvent;
class QskViewportChangeEvent;
class QskWindowChangeEvent;
class QSK_EXPORT QskItem : public QQuickItem
@ -154,6 +155,7 @@ class QSK_EXPORT QskItem : public QQuickItem
virtual void changeEvent( QEvent* );
virtual void geometryChangeEvent( QskGeometryChangeEvent* );
virtual void viewportChangeEvent( QskViewportChangeEvent* );
virtual void windowChangeEvent( QskWindowChangeEvent* );
void mouseUngrabEvent() override;

View File

@ -6,6 +6,7 @@
#include "QskItemPrivate.h"
#include "QskTreeNode.h"
#include "QskSetup.h"
#include "QskEvent.h"
static inline void qskSendEventTo( QObject* object, QEvent::Type type )
{
@ -251,8 +252,24 @@ QSGTransformNode* QskItemPrivate::createTransformNode()
return new QskItemNode();
}
/*
Can we do something useful with overloading:
#if QT_VERSION >= QT_VERSION_CHECK( 6, 3, 0 )
- QQuickItemPrivate::transformChanged
*/
bool QskItemPrivate::transformChanged( QQuickItem* transformedItem )
{
bool accepted = false;
if ( q_func()->flags() & QQuickItem::ItemObservesViewport )
{
QskViewportChangeEvent event( transformedItem );
QCoreApplication::sendEvent( q_func(), &event );
accepted = event.isAccepted();
}
accepted |= Inherited::transformChanged( transformedItem );
return accepted;
}
#endif

View File

@ -45,6 +45,10 @@ class QskItemPrivate : public QQuickItemPrivate
void setImplicitSize( qreal width, qreal height, bool doNotify );
virtual QSizeF implicitSizeHint() const = 0;
#if QT_VERSION >= QT_VERSION_CHECK( 6, 3, 0 )
bool transformChanged( QQuickItem* ) override final;
#endif
private:
Q_DECLARE_PUBLIC( QskItem )

View File

@ -245,6 +245,8 @@ namespace
{
if ( change.sizeChange() )
scrolledItemGeometryChange();
viewportChanged();
}
void updateNode( QSGNode* ) override;
@ -287,6 +289,17 @@ namespace
const QSGClipNode* viewPortClipNode() const;
void viewportChanged()
{
#if QT_VERSION < QT_VERSION_CHECK( 6, 3, 0 )
if ( auto item = scrollArea()->scrolledItem() )
{
QskViewportChangeEvent ev( this );
QCoreApplication::sendEvent( item, &ev );
}
#endif
}
bool m_isSizeChangedEnabled = true;
};
@ -422,6 +435,7 @@ namespace
{
// we need to restore the clip node
update();
viewportChanged();
}
}