QskScrollArea::layoutSizeHint added

This commit is contained in:
Uwe Rathmann 2021-10-01 13:42:56 +02:00
parent e0cdc8d768
commit 18dfd907fe
2 changed files with 67 additions and 17 deletions

View File

@ -180,6 +180,20 @@ namespace
namespace
{
/*
When doing scene graph composition it is easy to insert a clip node
somewhere below the paint node to have all items on the viewport being clipped.
This is how it is done f.e. for the list boxes.
But when having QQuickItems on the viewport we run into a fundamental limitation
of the Qt/Quick design: node subtrees for the children have to be in parallel to
the paint node.
We work around this problem, by inserting an extra item between the scroll area
and the scrollable item. This item replaces its default clip node by its own node,
that references the geometry of the viewport clip node.
*/
class ClipItem final : public QskControl, public QQuickItemChangeListener
{
// when inheriting from QskControl we participate in node cleanups
@ -231,16 +245,16 @@ namespace
void itemGeometryChanged( QQuickItem*,
QQuickGeometryChange change, const QRectF& ) override
{
if ( m_isSizeChangedEnabled && change.sizeChange() )
scrollArea()->polish();
if ( change.sizeChange() )
scrolledItemGeometryChange();
}
#else
void itemGeometryChanged( QQuickItem*,
const QRectF& newRect, const QRectF& oldRect ) override
{
if ( m_isSizeChangedEnabled && ( oldRect.size() != newRect.size() ) )
scrollArea()->polish();
if ( oldRect.size() != newRect.size() )
scrolledItemGeometryChange();
}
#endif
@ -257,6 +271,22 @@ namespace
return static_cast< const QskScrollArea* >( parentItem() );
}
inline void scrolledItemGeometryChange()
{
if ( m_isSizeChangedEnabled )
{
auto area = scrollArea();
area->polish();
if ( !area->isItemResizable() )
{
// in this mode the size hint depends on it
area->resetImplicitSize();
}
}
}
const QSGClipNode* viewPortClipNode() const;
bool m_isSizeChangedEnabled = true;
@ -426,19 +456,6 @@ class QskScrollArea::PrivateData
bool isItemFocusClipping : 1;
};
/*
When doing scene graph composition it is quite easy to insert a clip node
somewhere below the paint node to have all items on the viewport being clipped.
This is how it is done f.e. for the list boxes.
But when having QQuickItems on the viewport we run into a fundamental limitation
of the Qt/Quick design: node subtrees for the children have to be in parallel to
the paint node.
We work around this problem, by inserting an extra item between the scroll area
and the scrollable item. This item replaces its default clip node by its own node,
that references the geometry of the viewport clip node.
*/
QskScrollArea::QskScrollArea( QQuickItem* parentItem )
: Inherited( parentItem )
@ -448,6 +465,8 @@ QskScrollArea::QskScrollArea( QQuickItem* parentItem )
m_data->clipItem = new ClipItem( this );
m_data->enableAutoTranslation( this, true );
initSizePolicy( QskSizePolicy::Ignored, QskSizePolicy::Ignored );
}
QskScrollArea::~QskScrollArea()
@ -464,6 +483,36 @@ void QskScrollArea::updateLayout()
adjustItem();
}
QSizeF QskScrollArea::layoutSizeHint( Qt::SizeHint which, const QSizeF& constraint ) const
{
if ( which == Qt::PreferredSize )
{
if ( const auto contentItem = scrolledItem() )
{
QSizeF hint;
if ( m_data->isItemResizable )
{
hint = qskSizeConstraint( contentItem, which, constraint );
}
else
{
hint = qskItemSize( contentItem );
}
if ( verticalScrollBarPolicy() != Qt::ScrollBarAlwaysOff )
hint.rwidth() += metric( VerticalScrollBar | QskAspect::Size );
if ( horizontalScrollBarPolicy() != Qt::ScrollBarAlwaysOff )
hint.rheight() += metric( HorizontalScrollBar | QskAspect::Size );
return hint;
}
}
return Inherited::layoutSizeHint( which, constraint );
}
void QskScrollArea::adjustItem()
{
auto item = m_data->clipItem->scrolledItem();

View File

@ -42,6 +42,7 @@ class QSK_EXPORT QskScrollArea : public QskScrollView
protected:
void updateLayout() override;
QSizeF layoutSizeHint( Qt::SizeHint, const QSizeF& ) const override;
private:
void translateItem();