diff options
author | Ulf Hermann <ulf.hermann@qt.io> | 2022-03-02 13:36:05 +0100 |
---|---|---|
committer | Ulf Hermann <ulf.hermann@qt.io> | 2022-03-02 23:17:27 +0100 |
commit | 247efb9a343a14bb12805e56e4950919071d9395 (patch) | |
tree | f972799055582f5038cfca469dc31607418cc447 | |
parent | 2c410317b6077fdcfb2cdeb4b730c1b0c544147e (diff) |
QQuickAnchorChanges: Keep geometry bindings on reverse() and rewind()
This is in line with what we do in other reverse() and rewind() methods.
Unfortunately we need to dig deep into the QQuickItem internals in order
to get all the flags and callbacks right.
Pick-to: 6.2 6.3
Fixes: QTBUG-101186
Change-Id: Icde1a1b2dab1b9cab5adcbc28485a7526a8ac2b7
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
-rw-r--r-- | src/quick/items/qquickitem.h | 1 | ||||
-rw-r--r-- | src/quick/items/qquickstateoperations.cpp | 59 | ||||
-rw-r--r-- | tests/auto/quick/qquickstates/data/anchorRewind.qml | 31 | ||||
-rw-r--r-- | tests/auto/quick/qquickstates/tst_qquickstates.cpp | 24 |
4 files changed, 100 insertions, 15 deletions
diff --git a/src/quick/items/qquickitem.h b/src/quick/items/qquickitem.h index 197d891b2a..2fdb0f00c8 100644 --- a/src/quick/items/qquickitem.h +++ b/src/quick/items/qquickitem.h @@ -477,6 +477,7 @@ private: friend class QSGRenderer; friend class QAccessibleQuickItem; friend class QQuickAccessibleAttached; + friend class QQuickAnchorChanges; Q_DISABLE_COPY(QQuickItem) Q_DECLARE_PRIVATE(QQuickItem) }; diff --git a/src/quick/items/qquickstateoperations.cpp b/src/quick/items/qquickstateoperations.cpp index d8380af756..719c682769 100644 --- a/src/quick/items/qquickstateoperations.cpp +++ b/src/quick/items/qquickstateoperations.cpp @@ -1094,6 +1094,7 @@ void QQuickAnchorChanges::reverse() QQuickAnchors::Anchors stateHAnchors = d->anchorSet->d_func()->usedAnchors & QQuickAnchors::Horizontal_Mask; QQuickAnchors::Anchors origHAnchors = targetPrivate->anchors()->usedAnchors() & QQuickAnchors::Horizontal_Mask; + const QRectF oldGeometry(d->target->position(), d->target->size()); bool stateSetWidth = (stateHAnchors && stateHAnchors != QQuickAnchors::LeftAnchor && stateHAnchors != QQuickAnchors::RightAnchor && @@ -1102,8 +1103,11 @@ void QQuickAnchorChanges::reverse() origHAnchors != QQuickAnchors::LeftAnchor && origHAnchors != QQuickAnchors::RightAnchor && origHAnchors != QQuickAnchors::HCenterAnchor); - if (d->origWidth.isValid() && stateSetWidth && !origSetWidth) - d->target->setWidth(d->origWidth.value); + if (d->origWidth.isValid() && stateSetWidth && !origSetWidth && !qt_is_nan(d->origWidth)) { + targetPrivate->widthValidFlag = true; + if (targetPrivate->width != d->origWidth) + targetPrivate->width.setValueBypassingBindings(d->origWidth); + } bool stateSetHeight = (stateVAnchors && stateVAnchors != QQuickAnchors::TopAnchor && @@ -1115,14 +1119,23 @@ void QQuickAnchorChanges::reverse() origVAnchors != QQuickAnchors::BottomAnchor && origVAnchors != QQuickAnchors::VCenterAnchor && origVAnchors != QQuickAnchors::BaselineAnchor); - if (d->origHeight.isValid() && stateSetHeight && !origSetHeight) - d->target->setHeight(d->origHeight.value); + if (d->origHeight.isValid() && stateSetHeight && !origSetHeight && !!qt_is_nan(d->origHeight)) { + targetPrivate->heightValidFlag = true; + if (targetPrivate->height != d->origHeight) + targetPrivate->height.setValueBypassingBindings(d->origHeight); + } + + if (stateHAnchors && !origHAnchors && !qt_is_nan(d->origX) && d->origX != targetPrivate->x) + targetPrivate->x.setValueBypassingBindings(d->origX); - if (stateHAnchors && !origHAnchors) - d->target->setX(d->origX); + if (stateVAnchors && !origVAnchors && !qt_is_nan(d->origY) && d->origY != targetPrivate->y) + targetPrivate->y.setValueBypassingBindings(d->origY); - if (stateVAnchors && !origVAnchors) - d->target->setY(d->origY); + const QRectF newGeometry(d->target->position(), d->target->size()); + if (newGeometry != oldGeometry) { + targetPrivate->dirty(QQuickItemPrivate::Position); + d->target->geometryChange(newGeometry, oldGeometry); + } } QQuickStateActionEvent::EventType QQuickAnchorChanges::type() const @@ -1316,15 +1329,31 @@ void QQuickAnchorChanges::rewind() return; QQuickItemPrivate *targetPrivate = QQuickItemPrivate::get(d->target); + const QRectF oldGeometry(d->target->position(), d->target->size()); + + // Restore previous values (but not previous bindings, i.e. anchors). + // Also, don't drop any new bindings. + if (!qt_is_nan(d->rewindX) && d->rewindX != targetPrivate->x) + targetPrivate->x.setValueBypassingBindings(d->rewindX); + if (!qt_is_nan(d->rewindY) && d->rewindY != targetPrivate->y) + targetPrivate->y.setValueBypassingBindings(d->rewindY); + + if (targetPrivate->widthValid() && !qt_is_nan(d->rewindWidth)) { + targetPrivate->widthValidFlag = true; + if (d->rewindWidth != targetPrivate->width) + targetPrivate->width.setValueBypassingBindings(d->rewindWidth); + } - //restore previous values (but not previous bindings, i.e. anchors) - d->target->setX(d->rewindX); - d->target->setY(d->rewindY); - if (targetPrivate->widthValid()) { - d->target->setWidth(d->rewindWidth); + if (targetPrivate->heightValid() && !qt_is_nan(d->rewindHeight)) { + targetPrivate->heightValidFlag = true; + if (d->rewindHeight != targetPrivate->height) + targetPrivate->height.setValueBypassingBindings(d->rewindHeight); } - if (targetPrivate->heightValid()) { - d->target->setHeight(d->rewindHeight); + + const QRectF newGeometry(d->target->position(), d->target->size()); + if (newGeometry != oldGeometry) { + targetPrivate->dirty(QQuickItemPrivate::Position); + d->target->geometryChange(newGeometry, oldGeometry); } } diff --git a/tests/auto/quick/qquickstates/data/anchorRewind.qml b/tests/auto/quick/qquickstates/data/anchorRewind.qml new file mode 100644 index 0000000000..740c94cf42 --- /dev/null +++ b/tests/auto/quick/qquickstates/data/anchorRewind.qml @@ -0,0 +1,31 @@ +import QtQuick + +Item { + width: 400 + height: 400 + Item { + id: outer + anchors.fill: parent + Item { + id: inner + width: parent.width / 2 + height: parent.height / 2 + anchors.left: parent.right + anchors.top: parent.bottom + } + states: [ + State { + when: true + AnchorChanges { + target: inner + anchors.left: outer.left + anchors.top: outer.top + } + } + ] + transitions: Transition { + AnchorAnimation {} + } + } +} + diff --git a/tests/auto/quick/qquickstates/tst_qquickstates.cpp b/tests/auto/quick/qquickstates/tst_qquickstates.cpp index 788b9c68ec..d6814bd057 100644 --- a/tests/auto/quick/qquickstates/tst_qquickstates.cpp +++ b/tests/auto/quick/qquickstates/tst_qquickstates.cpp @@ -206,6 +206,7 @@ private slots: void bindableProperties(); void parentChangeInvolvingBindings(); void deferredProperties(); + void rewindAnchorChange(); }; void tst_qquickstates::initTestCase() @@ -1954,6 +1955,29 @@ void tst_qquickstates::deferredProperties() QCOMPARE(root->height(), 100.0); } +void tst_qquickstates::rewindAnchorChange() +{ + QQmlEngine engine; + QQmlComponent c(&engine, testFileUrl("anchorRewind.qml")); + QVERIFY2(c.isReady(), qPrintable(c.errorString())); + QScopedPointer<QObject> root(c.create()); + QVERIFY(root); + + QQmlContext *context = qmlContext(root.data()); + QVERIFY(context); + + QObject *inner = context->objectForName(QStringLiteral("inner")); + QVERIFY(inner); + + QQuickItem *innerRect = qobject_cast<QQuickItem *>(inner); + QVERIFY(innerRect); + + QTRY_COMPARE(innerRect->x(), 0); + QTRY_COMPARE(innerRect->y(), 0); + QTRY_COMPARE(innerRect->width(), 200); + QTRY_COMPARE(innerRect->height(), 200); +} + QTEST_MAIN(tst_qquickstates) #include "tst_qquickstates.moc" |