Fix binding loop and polish issue in quick layout

The quick layout item cause binding loop issue when layout item size
were updated in-between polish. This has been fixed by not updating
layout size hint during rearrange.

But there is polish issue due to child item not being invalidated
and this skips corresponding item box size calculation. This patch
invalidate all the items in the rearrange list of the layout and
finally, invalidate engine and layout.

Fixes: QTBUG-117899
Fixes: QTBUG-118511
Change-Id: I1e318335ce8b5268d878b48a02a089d703bb90ad
Reviewed-by: Jan Arve Sæther <jan-arve.saether@qt.io>
(cherry picked from commit 9ad9d05f26)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
(cherry picked from commit a1d5514289)
(cherry picked from commit 1570bd5f8e)
This commit is contained in:
Santhosh Kumar 2023-10-25 16:29:07 +02:00 committed by Qt Cherry-pick Bot
parent 2e3e3adf0f
commit e3022f58fd
3 changed files with 81 additions and 8 deletions

View File

@ -921,7 +921,7 @@ void QQuickLayout::geometryChange(const QRectF &newGeometry, const QRectF &oldGe
{
Q_D(QQuickLayout);
QQuickItem::geometryChange(newGeometry, oldGeometry);
if (d->m_disableRearrange || !isReady())
if (invalidated() || d->m_disableRearrange || !isReady())
return;
qCDebug(lcQuickLayouts) << "QQuickLayout::geometryChange" << newGeometry << oldGeometry;

View File

@ -457,10 +457,6 @@ void QQuickGridLayoutBase::rearrange(const QSizeF &size)
return;
}
// Should normally not be needed, but there might be an incoming window resize event that we
// will process before we process updatePolish()
ensureLayoutItemsUpdated(QQuickLayout::ApplySizeHints | QQuickLayout::Recursive);
d->m_rearranging = true;
qCDebug(lcQuickLayouts) << objectName() << "QQuickGridLayoutBase::rearrange()" << size;
Qt::LayoutDirection visualDir = effectiveLayoutDirection();
@ -479,9 +475,14 @@ void QQuickGridLayoutBase::rearrange(const QSizeF &size)
d->engine.setGeometries(QRectF(QPointF(0,0), size), d->styleInfo);
d->m_rearranging = false;
for (QQuickItem *invalid : std::as_const(d->m_invalidateAfterRearrange))
invalidate(invalid);
d->m_invalidateAfterRearrange.clear();
if (d->m_invalidateAfterRearrange.size() > 0) {
for (QQuickItem *invalid : std::as_const(d->m_invalidateAfterRearrange)) {
if (QQuickGridLayoutItem *layoutItem = d->engine.findLayoutItem(invalid))
layoutItem->invalidate();
}
invalidate();
d->m_invalidateAfterRearrange.clear();
}
}
/**********************************

View File

@ -1177,6 +1177,78 @@ Item {
compare(row.implicitWidth, 2);
}
Component {
id: sizeHintBindingLoopComp
Item {
        id: root
        anchors.fill: parent
property var customWidth: 100
        RowLayout {
            id: col
Item {
                id: item
                implicitHeight: 80
               implicitWidth: Math.max(col2.implicitWidth, root.customWidth + 20)
ColumnLayout {
                    id: col2
                    width: parent.width
                 Item {
                        id: rect
                        implicitWidth: root.customWidth
                        implicitHeight: 80
                  }
                }
            }
}
}
}
function test_sizeHintBindingLoopIssue() {
var item = createTemporaryObject(sizeHintBindingLoopComp, container)
waitForRendering(item)
item.customWidth += 10
waitForRendering(item)
verify(!BindingLoopDetector.bindingLoopDetected, "Detected binding loop")
BindingLoopDetector.reset()
}
Component {
id: polishLayoutItemComp
Item {
anchors.fill: parent
implicitHeight: contentLayout.implicitHeight
implicitWidth: contentLayout.implicitWidth
property alias textLayout: contentLayout
RowLayout {
width: parent.width
height: parent.height
ColumnLayout {
id: contentLayout
Layout.alignment: Qt.AlignHCenter | Qt.AlignTop
Layout.maximumWidth: 200
Repeater {
model: 2
Text {
Layout.fillWidth: true
text: "This is a long text causing line breaks to show the bug."
wrapMode: Text.Wrap
}
}
Item {
Layout.fillHeight: true
}
}
}
}
}
function test_polishLayoutItemIssue() {
var rootItem = createTemporaryObject(polishLayoutItemComp, container)
waitForRendering(rootItem)
var textItem = rootItem.textLayout.children[1]
verify(textItem.y >= rootItem.textLayout.children[0].height)
}
Component {
id: rearrangeNestedLayouts_Component
RowLayout {