diff options
author | Jan Arve Sæther <jan-arve.saether@qt.io> | 2022-09-02 14:24:19 +0200 |
---|---|---|
committer | Qt Cherry-pick Bot <cherrypick_bot@qt-project.org> | 2022-09-27 21:32:17 +0000 |
commit | 7ade61593424910a63085cef8203feb4bae4ec06 (patch) | |
tree | fad2b8420e7f61c86069e365fbe7321f1f8dac04 | |
parent | 74e7f9ccc5a16103ac0c667ce4b49503b55d377b (diff) |
Do not listen to baselineOffset changes unless really needed
For some controls, (e.g. TextInput and Text) we can get changes in
baseline offset when they change their height. These changes will
invalidate the layout and generate a polish event.
This means that during a rearrange of a layout with TextInput children, it
might change the height of its children. This might change the baselineOffset
of these children, which again will cause the layout to have to be invalidated
(and rearranged again) This double-loop is unnecessary if the layout is not
supposed to align these items by their baselines, so we add some conditions to
see if we really need to connect to the baselineOffsetChanged() signal.
This also fixes a bug observed in the color dialog, where the
semi-recursiveness described above lead to a problem with that the alpha
TextField of the RGBA color input was *not* laid out by the parent RowLayout
Fixes: QTBUG-105899
Change-Id: If66b4bbde6a37c962b157e166c883ba20ff24c21
Reviewed-by: Oliver Eftevaag <oliver.eftevaag@qt.io>
(cherry picked from commit 1fe641c50defed77590e2eba9d33e6c3746fa832)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
-rw-r--r-- | src/quicklayouts/qquicklayout.cpp | 16 | ||||
-rw-r--r-- | src/quicklayouts/qquicklayout_p.h | 2 | ||||
-rw-r--r-- | src/quicklayouts/qquicklinearlayout.cpp | 1 | ||||
-rw-r--r-- | tests/auto/quick/qquicklayouts/data/tst_gridlayout.qml | 50 |
4 files changed, 67 insertions, 2 deletions
diff --git a/src/quicklayouts/qquicklayout.cpp b/src/quicklayouts/qquicklayout.cpp index 701a83de42..80fea6923a 100644 --- a/src/quicklayouts/qquicklayout.cpp +++ b/src/quicklayouts/qquicklayout.cpp @@ -790,6 +790,18 @@ void QQuickLayout::componentComplete() d->m_isReady = true; } +void QQuickLayout::maybeSubscribeToBaseLineOffsetChanges(QQuickItem *item) +{ + QQuickLayoutAttached *info = attachedLayoutObject(item, false); + if (info) { + if (info->alignment() == Qt::AlignBaseline && static_cast<QQuickLayout*>(item->parentItem()) == this) { + qmlobject_connect(item, QQuickItem, SIGNAL(baselineOffsetChanged(qreal)), this, QQuickLayout, SLOT(invalidateSenderItem())); + } else { + qmlobject_disconnect(item, QQuickItem, SIGNAL(baselineOffsetChanged(qreal)), this, QQuickLayout, SLOT(invalidateSenderItem())); + } + } +} + void QQuickLayout::invalidate(QQuickItem * /*childItem*/) { Q_D(QQuickLayout); @@ -864,7 +876,7 @@ void QQuickLayout::itemChange(ItemChange change, const ItemChangeData &value) if (change == ItemChildAddedChange) { Q_D(QQuickLayout); QQuickItem *item = value.item; - qmlobject_connect(item, QQuickItem, SIGNAL(baselineOffsetChanged(qreal)), this, QQuickLayout, SLOT(invalidateSenderItem())); + maybeSubscribeToBaseLineOffsetChanges(item); QQuickItemPrivate::get(item)->addItemChangeListener(this, changeTypes); d->m_hasItemChangeListeners = true; qCDebug(lcQuickLayouts) << "ChildAdded" << item; @@ -872,7 +884,7 @@ void QQuickLayout::itemChange(ItemChange change, const ItemChangeData &value) invalidate(); } else if (change == ItemChildRemovedChange) { QQuickItem *item = value.item; - qmlobject_disconnect(item, QQuickItem, SIGNAL(baselineOffsetChanged(qreal)), this, QQuickLayout, SLOT(invalidateSenderItem())); + maybeSubscribeToBaseLineOffsetChanges(item); QQuickItemPrivate::get(item)->removeItemChangeListener(this, changeTypes); qCDebug(lcQuickLayouts) << "ChildRemoved" << item; if (isReady()) diff --git a/src/quicklayouts/qquicklayout_p.h b/src/quicklayouts/qquicklayout_p.h index 921be97f44..2eb1c2c362 100644 --- a/src/quicklayouts/qquicklayout_p.h +++ b/src/quicklayouts/qquicklayout_p.h @@ -121,6 +121,8 @@ public: void itemDestroyed(QQuickItem *item) override; void itemVisibilityChanged(QQuickItem *item) override; + void maybeSubscribeToBaseLineOffsetChanges(QQuickItem *item); + Q_INVOKABLE void _q_dumpLayoutTree() const; void dumpLayoutTreeRecursive(int level, QString &buf) const; diff --git a/src/quicklayouts/qquicklinearlayout.cpp b/src/quicklayouts/qquicklinearlayout.cpp index c7b0e66e04..1a8cc4e7ae 100644 --- a/src/quicklayouts/qquicklinearlayout.cpp +++ b/src/quicklayouts/qquicklinearlayout.cpp @@ -318,6 +318,7 @@ void QQuickGridLayoutBase::setAlignment(QQuickItem *item, Qt::Alignment alignmen { Q_D(QQuickGridLayoutBase); d->engine.setAlignment(item, alignment); + maybeSubscribeToBaseLineOffsetChanges(item); } QQuickGridLayoutBase::~QQuickGridLayoutBase() diff --git a/tests/auto/quick/qquicklayouts/data/tst_gridlayout.qml b/tests/auto/quick/qquicklayouts/data/tst_gridlayout.qml index 1df04a11e8..52ad3b478d 100644 --- a/tests/auto/quick/qquicklayouts/data/tst_gridlayout.qml +++ b/tests/auto/quick/qquicklayouts/data/tst_gridlayout.qml @@ -586,6 +586,56 @@ Item { tryCompare(layout.children[4], "y", 60); } + Component { + id: layout_alignBaseline_Component + GridLayout { + columns: 2 + columnSpacing: 0 + rowSpacing: 0 + TextInput { + property var itemRect: [x, y, width, height] + text: "red" + baselineOffset: 7 + color: "red" + verticalAlignment: TextInput.AlignVCenter + Layout.preferredWidth: 50 + Layout.preferredHeight: 10 + Layout.fillHeight: true + } + TextInput { + property var itemRect: [x, y, width, height] + text: "green" + baselineOffset: 7 + color: "green" + verticalAlignment: TextInput.AlignVCenter + Layout.preferredWidth: 50 + Layout.preferredHeight: 10 + Layout.fillHeight: true + } + + } + } + + function test_alignBaseline_dont_always_invalidate() + { + var layout = createTemporaryObject(layout_alignBaseline_Component, container); + waitForItemPolished(layout) + layout.height = 20 + // Adjusting height on an item that uses Qt.AlignBaseline might adjust the baseline + // Test if we don't get excessive number of polish() events because of baseline changes + // (In this case, we don't want to align by the baseline) + compare(isPolishScheduled(layout), false) + waitForItemPolished(layout) + var c0 = layout.children[0] + c0.Layout.alignment = Qt.AlignBaseline + var c1 = layout.children[1] + c1.Layout.alignment = Qt.AlignBaseline + + // We want to align by baseline => expect a polish event + compare(isPolishScheduled(layout), true) + waitForItemPolished(layout) + } + Component { id: layout_rightToLeft_Component |