aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorUlf Hermann <ulf.hermann@qt.io>2022-03-02 13:36:05 +0100
committerUlf Hermann <ulf.hermann@qt.io>2022-03-02 23:17:27 +0100
commit247efb9a343a14bb12805e56e4950919071d9395 (patch)
treef972799055582f5038cfca469dc31607418cc447
parent2c410317b6077fdcfb2cdeb4b730c1b0c544147e (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.h1
-rw-r--r--src/quick/items/qquickstateoperations.cpp59
-rw-r--r--tests/auto/quick/qquickstates/data/anchorRewind.qml31
-rw-r--r--tests/auto/quick/qquickstates/tst_qquickstates.cpp24
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"