antizipate scrollbars before resizing the content item

This commit is contained in:
Uwe Rathmann 2020-07-03 13:51:02 +02:00
parent 94b2aec272
commit 90bfc14a00

View File

@ -7,6 +7,7 @@
#include "QskEvent.h" #include "QskEvent.h"
#include "QskQuick.h" #include "QskQuick.h"
#include "QskScrollViewSkinlet.h" #include "QskScrollViewSkinlet.h"
#include "QskBoxBorderMetrics.h"
QSK_QT_PRIVATE_BEGIN QSK_QT_PRIVATE_BEGIN
#include <private/qquickclipnode_p.h> #include <private/qquickclipnode_p.h>
@ -15,6 +16,83 @@ QSK_QT_PRIVATE_BEGIN
#include <private/qquickwindow_p.h> #include <private/qquickwindow_p.h>
QSK_QT_PRIVATE_END QSK_QT_PRIVATE_END
static inline bool qskNeedsScrollBars(
qreal available, qreal required, Qt::ScrollBarPolicy policy )
{
if ( policy == Qt::ScrollBarAsNeeded )
return required > available;
else
return policy == Qt::ScrollBarAlwaysOn;
}
static inline QSizeF qskPanelInnerSize( const QskScrollView* scrollView )
{
auto size = scrollView->subControlRect( QskScrollView::Panel ).size();
const auto borderMetrics = scrollView->boxBorderMetricsHint( QskScrollView::Viewport );
const qreal bw = 2 * borderMetrics.widthAt( Qt::TopEdge );
size.setWidth( qMax( size.width() - bw, 0.0 ) );
size.setHeight( qMax( size.height() - bw, 0.0 ) );
return size;
}
static inline QSizeF qskScrolledItemSize( const QskScrollView* scrollView,
const QQuickItem* item, const QSizeF& boundingSize )
{
QSizeF outerSize = boundingSize;
const qreal spacing = scrollView->metric( QskScrollView::Panel | QskAspect::Spacing );
const auto sbV = scrollView->metric( QskScrollView::VerticalScrollBar | QskAspect::Size );
const auto sbH = scrollView->metric( QskScrollView::HorizontalScrollBar | QskAspect::Size );
const auto policyH = scrollView->horizontalScrollBarPolicy();
const auto policyV = scrollView->verticalScrollBarPolicy();
auto itemSize = qskConstrainedItemSize( item, outerSize );
bool needScrollBarV = qskNeedsScrollBars( outerSize.height(), itemSize.height(), policyV );
bool needScrollBarH = qskNeedsScrollBars( outerSize.width(), itemSize.width(), policyH );
bool hasScrollBarV = needScrollBarV;
// Vertical/Horizonal scroll bars might depend on each other
if ( needScrollBarV )
{
outerSize.rwidth() -= sbV + spacing;
itemSize = qskConstrainedItemSize( item, outerSize );
if ( !needScrollBarH )
{
needScrollBarH = qskNeedsScrollBars(
outerSize.width(), itemSize.width(), policyH );
}
}
if ( needScrollBarH )
{
outerSize.rheight() -= sbH + spacing;
itemSize = qskConstrainedItemSize( item, outerSize );
if ( !hasScrollBarV )
{
needScrollBarV = qskNeedsScrollBars(
outerSize.height(), itemSize.height(), policyV );
}
}
if ( needScrollBarV )
{
outerSize.rwidth() -= sbV + spacing;
itemSize = qskConstrainedItemSize( item, outerSize );
}
return itemSize;
}
namespace namespace
{ {
class ViewportClipNode final : public QQuickDefaultClipNode class ViewportClipNode final : public QQuickDefaultClipNode
@ -124,6 +202,11 @@ class QskScrollAreaClipItem final : public QskControl, public QQuickItemChangeLi
return scrollArea()->subControlRect( QskScrollView::Viewport ); return scrollArea()->subControlRect( QskScrollView::Viewport );
} }
inline void setItemSizeChangedEnabled( bool on )
{
m_isSizeChangedEnabled = on;
}
protected: protected:
bool event( QEvent* event ) override; bool event( QEvent* event ) override;
@ -134,7 +217,7 @@ class QskScrollAreaClipItem final : public QskControl, public QQuickItemChangeLi
void itemGeometryChanged( QQuickItem*, void itemGeometryChanged( QQuickItem*,
QQuickGeometryChange change, const QRectF& ) override QQuickGeometryChange change, const QRectF& ) override
{ {
if ( change.sizeChange() ) if ( m_isSizeChangedEnabled && change.sizeChange() )
scrollArea()->polish(); scrollArea()->polish();
} }
@ -142,7 +225,7 @@ class QskScrollAreaClipItem final : public QskControl, public QQuickItemChangeLi
void itemGeometryChanged( QQuickItem*, void itemGeometryChanged( QQuickItem*,
const QRectF& newRect, const QRectF& oldRect ) override const QRectF& newRect, const QRectF& oldRect ) override
{ {
if ( oldRect.size() != newRect.size() ) if ( m_isSizeChangedEnabled && ( oldRect.size() != newRect.size() ) )
scrollArea()->polish(); scrollArea()->polish();
} }
#endif #endif
@ -161,6 +244,8 @@ class QskScrollAreaClipItem final : public QskControl, public QQuickItemChangeLi
} }
const QSGClipNode* viewPortClipNode() const; const QSGClipNode* viewPortClipNode() const;
bool m_isSizeChangedEnabled = true;
}; };
QskScrollAreaClipItem::QskScrollAreaClipItem( QskScrollArea* scrollArea ) QskScrollAreaClipItem::QskScrollAreaClipItem( QskScrollArea* scrollArea )
@ -371,39 +456,38 @@ void QskScrollArea::adjustItem()
{ {
setScrollableSize( QSizeF() ); setScrollableSize( QSizeF() );
setScrollPos( QPointF() ); setScrollPos( QPointF() );
return;
} }
else
if ( m_data->isItemResizable )
{ {
if ( m_data->isItemResizable ) QSizeF itemSize;
const auto viewSize = qskPanelInnerSize( this );
if ( !viewSize.isEmpty() )
{ {
auto size = viewContentsRect().size(); // we have to anticipate the scrollbars
if ( size.isEmpty() ) itemSize = qskScrolledItemSize( this, item, viewSize );
{
size = QSizeF( 0.0, 0.0 );
}
else
{
/*
For optional scrollbars the available space also depends
on wether the adjustedSize results in scroll bars. For the
moment we ignore this and start with a simplified code. TODO ...
*/
size = qskConstrainedItemSize( item, size );
}
item->setSize( size );
} }
m_data->enableAutoTranslation( this, false ); if ( itemSize.isEmpty() )
itemSize = QSizeF( 0.0, 0.0 );
setScrollableSize( QSizeF( item->width(), item->height() ) );
setScrollPos( scrollPos() );
m_data->enableAutoTranslation( this, true ); m_data->clipItem->setItemSizeChangedEnabled( false );
item->setSize( itemSize );
translateItem(); m_data->clipItem->setItemSizeChangedEnabled( true );
} }
m_data->enableAutoTranslation( this, false );
setScrollableSize( QSizeF( item->width(), item->height() ) );
setScrollPos( scrollPos() );
m_data->enableAutoTranslation( this, true );
translateItem();
} }
void QskScrollArea::setItemResizable( bool on ) void QskScrollArea::setItemResizable( bool on )