moving ClipItem to namespace

This commit is contained in:
Uwe Rathmann 2020-10-25 17:40:29 +01:00
parent 1228518e6a
commit 571f532307
1 changed files with 189 additions and 186 deletions

View File

@ -175,212 +175,215 @@ namespace
}; };
} }
class QskScrollAreaClipItem final : public QskControl, public QQuickItemChangeListener namespace
{ {
// when inheriting from QskControl we participate in node cleanups class ClipItem final : public QskControl, public QQuickItemChangeListener
using Inherited = QskControl;
public:
QskScrollAreaClipItem( QskScrollArea* );
virtual ~QskScrollAreaClipItem();
void enableGeometryListener( bool on );
QQuickItem* scrolledItem() const
{ {
auto children = childItems(); // when inheriting from QskControl we participate in node cleanups
return children.isEmpty() ? nullptr : children.first(); using Inherited = QskControl;
}
bool contains( const QPointF& pos ) const override public:
{ ClipItem( QskScrollArea* );
return clipRect().contains( pos ); virtual ~ClipItem();
}
QRectF clipRect() const override void enableGeometryListener( bool on );
{
return scrollArea()->subControlRect( QskScrollView::Viewport );
}
inline void setItemSizeChangedEnabled( bool on ) QQuickItem* scrolledItem() const
{
m_isSizeChangedEnabled = on;
}
protected:
bool event( QEvent* event ) override;
void itemChange( ItemChange, const ItemChangeData& ) override;
void geometryChanged( const QRectF&, const QRectF& ) override;
#if QT_VERSION >= QT_VERSION_CHECK( 5, 8, 0 )
void itemGeometryChanged( QQuickItem*,
QQuickGeometryChange change, const QRectF& ) override
{
if ( m_isSizeChangedEnabled && change.sizeChange() )
scrollArea()->polish();
}
#else
void itemGeometryChanged( QQuickItem*,
const QRectF& newRect, const QRectF& oldRect ) override
{
if ( m_isSizeChangedEnabled && ( oldRect.size() != newRect.size() ) )
scrollArea()->polish();
}
#endif
void updateNode( QSGNode* ) override;
private:
inline QskScrollArea* scrollArea()
{
return static_cast< QskScrollArea* >( parentItem() );
}
inline const QskScrollArea* scrollArea() const
{
return static_cast< const QskScrollArea* >( parentItem() );
}
const QSGClipNode* viewPortClipNode() const;
bool m_isSizeChangedEnabled = true;
};
QskScrollAreaClipItem::QskScrollAreaClipItem( QskScrollArea* scrollArea )
: Inherited( scrollArea )
{
setObjectName( QStringLiteral( "QskScrollAreaClipItem" ) );
setClip( true );
}
QskScrollAreaClipItem::~QskScrollAreaClipItem()
{
enableGeometryListener( false );
}
void QskScrollAreaClipItem::updateNode( QSGNode* )
{
auto* d = QQuickItemPrivate::get( this );
if ( QQuickItemPrivate::get( scrollArea() )->dirtyAttributes &
QQuickItemPrivate::ContentUpdateMask )
{
/*
The update order depends on who calls update first and we
have to handle being called before a new clip node has
been created by the scrollview.
But better invalidate the unguarded clip geometry until then ...
*/
auto clipNode = d->clipNode();
if ( clipNode && !clipNode->isRectangular() )
{ {
clipNode->setIsRectangular( true ); auto children = childItems();
clipNode->setGeometry( nullptr ); return children.isEmpty() ? nullptr : children.first();
} }
// in the next cycle we will find a valid clip bool contains( const QPointF& pos ) const override
update(); {
return; return clipRect().contains( pos );
} }
auto clipNode = d->clipNode(); QRectF clipRect() const override
{
return scrollArea()->subControlRect( QskScrollView::Viewport );
}
if ( clipNode && !( clipNode->flags() & QSGNode::OwnsMaterial ) ) inline void setItemSizeChangedEnabled( bool on )
{
m_isSizeChangedEnabled = on;
}
protected:
bool event( QEvent* event ) override;
void itemChange( ItemChange, const ItemChangeData& ) override;
void geometryChanged( const QRectF&, const QRectF& ) override;
#if QT_VERSION >= QT_VERSION_CHECK( 5, 8, 0 )
void itemGeometryChanged( QQuickItem*,
QQuickGeometryChange change, const QRectF& ) override
{
if ( m_isSizeChangedEnabled && change.sizeChange() )
scrollArea()->polish();
}
#else
void itemGeometryChanged( QQuickItem*,
const QRectF& newRect, const QRectF& oldRect ) override
{
if ( m_isSizeChangedEnabled && ( oldRect.size() != newRect.size() ) )
scrollArea()->polish();
}
#endif
void updateNode( QSGNode* ) override;
private:
inline QskScrollArea* scrollArea()
{
return static_cast< QskScrollArea* >( parentItem() );
}
inline const QskScrollArea* scrollArea() const
{
return static_cast< const QskScrollArea* >( parentItem() );
}
const QSGClipNode* viewPortClipNode() const;
bool m_isSizeChangedEnabled = true;
};
ClipItem::ClipItem( QskScrollArea* scrollArea )
: Inherited( scrollArea )
{ {
// Replace the clip node being inserted from QQuickWindow setObjectName( QStringLiteral( "QskScrollAreaClipItem" ) );
setClip( true );
auto parentNode = clipNode->parent();
auto node = new ViewportClipNode();
parentNode->appendChildNode( node );
clipNode->reparentChildNodesTo( node );
parentNode->removeChildNode( clipNode );
if ( clipNode->flags() & QSGNode::OwnedByParent )
delete clipNode;
d->extra->clipNode = clipNode = node;
Q_ASSERT( clipNode == QQuickItemPrivate::get( this )->clipNode() );
} }
if ( clipNode ) ClipItem::~ClipItem()
{
/*
Update the clip node with the geometry of the clip node
of the viewport of the scrollview.
*/
auto viewClipNode = static_cast< ViewportClipNode* >( clipNode );
viewClipNode->copyFrom( viewPortClipNode() );
}
}
const QSGClipNode* QskScrollAreaClipItem::viewPortClipNode() const
{
auto node = const_cast< QSGNode* >( qskPaintNode( scrollArea() ) );
if ( node )
node = QskSkinlet::findNodeByRole( node, QskScrollViewSkinlet::ContentsRootRole );
if ( node && node->type() == QSGNode::ClipNodeType )
return static_cast< QSGClipNode* >( node );
return nullptr;
}
void QskScrollAreaClipItem::geometryChanged(
const QRectF& newRect, const QRectF& oldRect )
{
Inherited::geometryChanged( newRect, oldRect );
if ( newRect.size() != oldRect.size() )
{
// we need to restore the clip node
update();
}
}
void QskScrollAreaClipItem::itemChange(
QQuickItem::ItemChange change, const QQuickItem::ItemChangeData& value )
{
if ( change == QQuickItem::ItemChildAddedChange )
{
enableGeometryListener( true );
}
else if ( change == QQuickItem::ItemChildRemovedChange )
{ {
enableGeometryListener( false ); enableGeometryListener( false );
} }
Inherited::itemChange( change, value ); void ClipItem::updateNode( QSGNode* )
}
void QskScrollAreaClipItem::enableGeometryListener( bool on )
{
auto item = scrolledItem();
if ( item )
{ {
// we might also be interested in ImplicitWidth/ImplicitHeight auto* d = QQuickItemPrivate::get( this );
const QQuickItemPrivate::ChangeTypes types = QQuickItemPrivate::Geometry;
QQuickItemPrivate* p = QQuickItemPrivate::get( item ); if ( QQuickItemPrivate::get( scrollArea() )->dirtyAttributes &
if ( on ) QQuickItemPrivate::ContentUpdateMask )
p->addItemChangeListener( this, types ); {
else /*
p->removeItemChangeListener( this, types ); The update order depends on who calls update first and we
} have to handle being called before a new clip node has
} been created by the scrollview.
But better invalidate the unguarded clip geometry until then ...
*/
auto clipNode = d->clipNode();
if ( clipNode && !clipNode->isRectangular() )
{
clipNode->setIsRectangular( true );
clipNode->setGeometry( nullptr );
}
bool QskScrollAreaClipItem::event( QEvent* event ) // in the next cycle we will find a valid clip
{ update();
if ( event->type() == QEvent::LayoutRequest ) return;
{ }
if ( scrollArea()->isItemResizable() )
scrollArea()->polish(); auto clipNode = d->clipNode();
if ( clipNode && !( clipNode->flags() & QSGNode::OwnsMaterial ) )
{
// Replace the clip node being inserted from QQuickWindow
auto parentNode = clipNode->parent();
auto node = new ViewportClipNode();
parentNode->appendChildNode( node );
clipNode->reparentChildNodesTo( node );
parentNode->removeChildNode( clipNode );
if ( clipNode->flags() & QSGNode::OwnedByParent )
delete clipNode;
d->extra->clipNode = clipNode = node;
Q_ASSERT( clipNode == QQuickItemPrivate::get( this )->clipNode() );
}
if ( clipNode )
{
/*
Update the clip node with the geometry of the clip node
of the viewport of the scrollview.
*/
auto viewClipNode = static_cast< ViewportClipNode* >( clipNode );
viewClipNode->copyFrom( viewPortClipNode() );
}
} }
return Inherited::event( event ); const QSGClipNode* ClipItem::viewPortClipNode() const
{
auto node = const_cast< QSGNode* >( qskPaintNode( scrollArea() ) );
if ( node )
node = QskSkinlet::findNodeByRole( node, QskScrollViewSkinlet::ContentsRootRole );
if ( node && node->type() == QSGNode::ClipNodeType )
return static_cast< QSGClipNode* >( node );
return nullptr;
}
void ClipItem::geometryChanged(
const QRectF& newRect, const QRectF& oldRect )
{
Inherited::geometryChanged( newRect, oldRect );
if ( newRect.size() != oldRect.size() )
{
// we need to restore the clip node
update();
}
}
void ClipItem::itemChange(
QQuickItem::ItemChange change, const QQuickItem::ItemChangeData& value )
{
if ( change == QQuickItem::ItemChildAddedChange )
{
enableGeometryListener( true );
}
else if ( change == QQuickItem::ItemChildRemovedChange )
{
enableGeometryListener( false );
}
Inherited::itemChange( change, value );
}
void ClipItem::enableGeometryListener( bool on )
{
auto item = scrolledItem();
if ( item )
{
// we might also be interested in ImplicitWidth/ImplicitHeight
const QQuickItemPrivate::ChangeTypes types = QQuickItemPrivate::Geometry;
QQuickItemPrivate* p = QQuickItemPrivate::get( item );
if ( on )
p->addItemChangeListener( this, types );
else
p->removeItemChangeListener( this, types );
}
}
bool ClipItem::event( QEvent* event )
{
if ( event->type() == QEvent::LayoutRequest )
{
if ( scrollArea()->isItemResizable() )
scrollArea()->polish();
}
return Inherited::event( event );
}
} }
class QskScrollArea::PrivateData class QskScrollArea::PrivateData
@ -405,7 +408,7 @@ class QskScrollArea::PrivateData
} }
} }
QskScrollAreaClipItem* clipItem = nullptr; ClipItem* clipItem = nullptr;
bool isItemResizable : 1; bool isItemResizable : 1;
}; };
@ -430,7 +433,7 @@ QskScrollArea::QskScrollArea( QQuickItem* parentItem )
{ {
setPolishOnResize( true ); setPolishOnResize( true );
m_data->clipItem = new QskScrollAreaClipItem( this ); m_data->clipItem = new ClipItem( this );
m_data->enableAutoTranslation( this, true ); m_data->enableAutoTranslation( this, true );
} }