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> #include <cstdlib>
#define HIDE_NODES 1
const int gridSize = 20; const int gridSize = 20;
const int thumbnailSize = 150; const int thumbnailSize = 150;
@ -81,18 +79,6 @@ class Thumbnail : public QskPushButton
setStrutSizeHint( QskPushButton::Icon, -1, -1 ); 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: private:
QskGraphic thumbnailGraphic( const QColor& color, QskGraphic thumbnailGraphic( const QColor& color,
int shape, const QSizeF& size ) const int shape, const QSizeF& size ) const
@ -124,41 +110,55 @@ class IconGrid : public QskLinearBox
IconGrid( QQuickItem* parentItem = nullptr ) IconGrid( QQuickItem* parentItem = nullptr )
: QskLinearBox( Qt::Horizontal, gridSize, parentItem ) : QskLinearBox( Qt::Horizontal, gridSize, parentItem )
{ {
#if QT_VERSION >= QT_VERSION_CHECK( 6, 3, 0 )
setFlag( QQuickItem::ItemObservesViewport, true );
#endif
setMargins( 20 ); setMargins( 20 );
setSpacing( 20 ); setSpacing( 20 );
for ( int col = 0; col < gridSize; col++ ) for ( int col = 0; col < gridSize; col++ )
{ {
for ( int row = 0; row < gridSize; row++ ) 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. When having too many nodes, the scene graph becomes horribly slow.
So we explicitely hide all items outside the visible area So we explicitely hide all items outside the visible area
( see updateVisibilities below ) and make use of the DeferredUpdate and ( see updateVisibilities below ) and make use of the DeferredUpdate and
CleanupOnVisibility features of QskItem. CleanupOnVisibility features of QskItem.
*/ */
setSize( sizeConstraint() );
updateLayout(); // so that every item has its initial geometry
for ( int i = 0; i < elementCount(); i++ ) QQuickItem* item;
{
if ( auto control = qskControlCast( itemAtIndex( i ) ) ) #if QT_VERSION >= QT_VERSION_CHECK( 6, 3, 0 )
{ item = viewportItem();
// to support the optimizations in ScrollArea::updateVisibilities #else
control->setPlacementPolicy( Qsk::Hidden, QskPlacementPolicy::Reserve ); for ( item = parentItem(); item && !item->clip(); item = item->parentItem() );
control->setVisible( false );
}
}
#endif #endif
}
#if HIDE_NODES if ( item )
void updateVisibilities( const QRectF& viewPort )
{ {
if ( !isEmpty() && viewPort != m_viewPort ) auto r = item->clipRect();
r.moveTo( mapFromItem( item, r.topLeft() ) );
const auto viewPort = this->viewPort( r );
if ( m_viewPort != viewPort )
{ {
setItemsVisible( m_viewPort, false ); setItemsVisible( m_viewPort, false );
setItemsVisible( viewPort, true ); setItemsVisible( viewPort, true );
@ -166,12 +166,11 @@ class IconGrid : public QskLinearBox
m_viewPort = viewPort; m_viewPort = viewPort;
} }
} }
}
private: 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 // we know, that all items have the same size
const auto itemSize = itemAtIndex( 0 )->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 colMin = rect.left() / ( itemSize.width() + spacing() );
const int colMax = rect.right() / ( itemSize.height() + 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 )
{ {
for ( int col = colMin; col <= colMax; col++ ) const auto dim = dimension();
for ( int row = viewPort.top(); row <= viewPort.bottom(); row++ )
{
for ( int col = viewPort.left(); col <= viewPort.right(); col++ )
{ {
if ( auto item = itemAtIndex( row * dim + col ) ) if ( auto item = itemAtIndex( row * dim + col ) )
item->setVisible( on ); item->setVisible( on );
@ -191,8 +197,7 @@ class IconGrid : public QskLinearBox
} }
} }
QRectF m_viewPort; QRect m_viewPort;
#endif
}; };
class ScrollArea : public QskScrollArea class ScrollArea : public QskScrollArea
@ -218,29 +223,6 @@ class ScrollArea : public QskScrollArea
setBoxShapeHint( HorizontalScrollHandle, 8 ); setBoxShapeHint( HorizontalScrollHandle, 8 );
setFlickRecognizerTimeout( 300 ); 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
} }
}; };

View File

@ -189,6 +189,7 @@ QskEvent* QskEvent::clone() const
} }
#endif #endif
// -- QskGeometryChangeEvent // -- QskGeometryChangeEvent
QskGeometryChangeEvent::QskGeometryChangeEvent( QskGeometryChangeEvent::QskGeometryChangeEvent(
@ -216,6 +217,19 @@ bool QskGeometryChangeEvent::isMoved() const
( m_rect.y() != m_oldRect.y() ); ( 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::QskWindowChangeEvent( QskWindowChangeEvent::QskWindowChangeEvent(

View File

@ -37,6 +37,7 @@ class QSK_EXPORT QskEvent : public QEvent
NoEvent = 53800, NoEvent = 53800,
GeometryChange, GeometryChange,
ViewportChange,
WindowChange, WindowChange,
/* /*
@ -85,6 +86,22 @@ class QSK_EXPORT QskGeometryChangeEvent : public QskEvent
QRectF m_oldRect; 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 class QSK_EXPORT QskWindowChangeEvent : public QskEvent
{ {
public: public:

View File

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

View File

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

View File

@ -6,6 +6,7 @@
#include "QskItemPrivate.h" #include "QskItemPrivate.h"
#include "QskTreeNode.h" #include "QskTreeNode.h"
#include "QskSetup.h" #include "QskSetup.h"
#include "QskEvent.h"
static inline void qskSendEventTo( QObject* object, QEvent::Type type ) static inline void qskSendEventTo( QObject* object, QEvent::Type type )
{ {
@ -251,8 +252,24 @@ QSGTransformNode* QskItemPrivate::createTransformNode()
return new QskItemNode(); return new QskItemNode();
} }
/* #if QT_VERSION >= QT_VERSION_CHECK( 6, 3, 0 )
Can we do something useful with overloading:
- 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 ); void setImplicitSize( qreal width, qreal height, bool doNotify );
virtual QSizeF implicitSizeHint() const = 0; virtual QSizeF implicitSizeHint() const = 0;
#if QT_VERSION >= QT_VERSION_CHECK( 6, 3, 0 )
bool transformChanged( QQuickItem* ) override final;
#endif
private: private:
Q_DECLARE_PUBLIC( QskItem ) Q_DECLARE_PUBLIC( QskItem )

View File

@ -245,6 +245,8 @@ namespace
{ {
if ( change.sizeChange() ) if ( change.sizeChange() )
scrolledItemGeometryChange(); scrolledItemGeometryChange();
viewportChanged();
} }
void updateNode( QSGNode* ) override; void updateNode( QSGNode* ) override;
@ -287,6 +289,17 @@ namespace
const QSGClipNode* viewPortClipNode() const; 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; bool m_isSizeChangedEnabled = true;
}; };
@ -422,6 +435,7 @@ namespace
{ {
// we need to restore the clip node // we need to restore the clip node
update(); update();
viewportChanged();
} }
} }