diff options
author | Shawn Rutledge <shawn.rutledge@qt.io> | 2022-10-19 22:18:37 +0200 |
---|---|---|
committer | Shawn Rutledge <shawn.rutledge@qt.io> | 2022-10-27 00:19:04 +0200 |
commit | 8a3c523dd9aea6c55db4b479de566624e2692435 (patch) | |
tree | 5c6cbe17bd39dc360b0a2c320fd0f6b9dcffe476 /tests/auto/quick/qquickflickable/tst_qquickflickable.cpp | |
parent | 99e4a2e3c5e8e0f43b601857878867561602490d (diff) |
Ensure Flickable.flickEnded signal is emitted after flick-then-drag
hData and vData's flicking flags could get set to false in two places:
movementEnding(), which would also emit flickEnded(); or in
maybeBeginDrag(), which did not emit flickEnded(). So if the user did a
quick flick-flick-flick sequence, usually the flick would be restarted,
and movementEnding would emit the signal after motion stopped. But if
the user dragged too slowly the final time, the flick would not be
restarted, and movementEnding() did not emit flickEnded() because the
two flicking flags were already false. At the time the final drag
starts, we don't know if the user is going to drag fast enough to
qualify as a flick, so that's probably why maybeBeginDrag() doesn't
emit flickEnded(). But information is lost by setting the flicking
flags to false there.
So to make the flickStarted() and flickEnded() signals more symmetric,
we also need flags to remember that when the drag began, there was
residual momentum (it was already flicking). Then movementEnding() can
emit flickEnded() after movement has stopped, which is more consistent
with what the user should expect: all's well that ends well, even if it
started more than once.
It seems the intention was always that flickEnded() means the whole
sequence of flicks and drags had ended; so give a hint in the docs.
Declare the wasFlicking locals const, as a drive-by.
The bool bitfields in AxisData are converted to uint for proper packing
on MSVC.
Fixes: QTBUG-103620
Change-Id: I363aa3a0d95e1fff21b4b09f22e88e51b88c7c16
Reviewed-by: Richard Moe Gustavsen <richard.gustavsen@qt.io>
(cherry picked from commit c9b8acba0e49a4d461183d069d12cbf18dfebe41)
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Diffstat (limited to 'tests/auto/quick/qquickflickable/tst_qquickflickable.cpp')
-rw-r--r-- | tests/auto/quick/qquickflickable/tst_qquickflickable.cpp | 75 |
1 files changed, 75 insertions, 0 deletions
diff --git a/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp b/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp index c088be4566..a6fb0fcb59 100644 --- a/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp +++ b/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp @@ -207,6 +207,7 @@ private slots: void movingAndDragging_data(); void flickOnRelease(); void pressWhileFlicking(); + void dragWhileFlicking(); void disabled(); void flickVelocity(); void margins(); @@ -1483,6 +1484,8 @@ void tst_qquickflickable::pressWhileFlicking() QSignalSpy hFlickSpy(flickable, SIGNAL(flickingHorizontallyChanged())); QSignalSpy vFlickSpy(flickable, SIGNAL(flickingVerticallyChanged())); QSignalSpy flickSpy(flickable, SIGNAL(flickingChanged())); + QSignalSpy flickStartSpy(flickable, &QQuickFlickable::flickStarted); + QSignalSpy flickEndSpy(flickable, &QQuickFlickable::flickEnded); // flick then press while it is still moving // flicking == false, moving == true; @@ -1500,6 +1503,8 @@ void tst_qquickflickable::pressWhileFlicking() QCOMPARE(vFlickSpy.count(), 1); QCOMPARE(hFlickSpy.count(), 0); QCOMPARE(flickSpy.count(), 1); + QCOMPARE(flickStartSpy.count(), 1); + QCOMPARE(flickEndSpy.count(), 0); QTest::mousePress(window.data(), Qt::LeftButton, Qt::NoModifier, QPoint(20, 50)); QTRY_VERIFY(!flickable->isFlicking()); @@ -1512,6 +1517,76 @@ void tst_qquickflickable::pressWhileFlicking() QVERIFY(!flickable->isFlickingVertically()); QTRY_VERIFY(!flickable->isMoving()); QVERIFY(!flickable->isMovingVertically()); + QCOMPARE(flickStartSpy.size(), 1); + QCOMPARE(flickEndSpy.size(), 1); + // Stop on a full pixel after user interaction + QCOMPARE(flickable->contentX(), (qreal)qRound(flickable->contentX())); +} + +void tst_qquickflickable::dragWhileFlicking() +{ + QQuickView window; + QVERIFY(QQuickTest::showView(window, testFileUrl("flickable03.qml"))); + + QQuickFlickable *flickable = qobject_cast<QQuickFlickable*>(window.rootObject()); + QVERIFY(flickable != nullptr); + + QSignalSpy vMoveSpy(flickable, &QQuickFlickable::movingVerticallyChanged); + QSignalSpy hMoveSpy(flickable, &QQuickFlickable::movingHorizontallyChanged); + QSignalSpy moveSpy(flickable, &QQuickFlickable::movingChanged); + QSignalSpy hFlickSpy(flickable, &QQuickFlickable::flickingHorizontallyChanged); + QSignalSpy vFlickSpy(flickable, &QQuickFlickable::flickingVerticallyChanged); + QSignalSpy flickSpy(flickable, &QQuickFlickable::flickingChanged); + QSignalSpy flickStartSpy(flickable, &QQuickFlickable::flickStarted); + QSignalSpy flickEndSpy(flickable, &QQuickFlickable::flickEnded); + + // flick first, let it keep moving + flick(&window, QPoint(20,190), QPoint(20, 50), 200); + QVERIFY(flickable->verticalVelocity() > 0.0); + QTRY_VERIFY(flickable->isFlicking()); + QVERIFY(flickable->isFlickingVertically()); + QCOMPARE(flickable->isFlickingHorizontally(), false); + QVERIFY(flickable->isMoving()); + QVERIFY(flickable->isMovingVertically()); + QCOMPARE(flickable->isMovingHorizontally(), false); + QCOMPARE(vMoveSpy.size(), 1); + QCOMPARE(hMoveSpy.size(), 0); + QCOMPARE(moveSpy.size(), 1); + QCOMPARE(vFlickSpy.size(), 1); + QCOMPARE(hFlickSpy.size(), 0); + QCOMPARE(flickSpy.size(), 1); + QCOMPARE(flickStartSpy.size(), 1); + QCOMPARE(flickEndSpy.size(), 0); + + // then drag slowly while it's still flicking and moving + const int dragStepDelay = 100; + QTest::mousePress(&window, Qt::LeftButton, Qt::NoModifier, QPoint(20, 70)); + QTRY_COMPARE(flickable->isFlicking(), false); + QCOMPARE(flickable->isFlickingVertically(), false); + QVERIFY(flickable->isMoving()); + QVERIFY(flickable->isMovingVertically()); + + for (int y = 70; y > 50; y -= 5) { + QTest::mouseMove(&window, QPoint(20, y), dragStepDelay); + QVERIFY(flickable->isMoving()); + QVERIFY(flickable->isMovingVertically()); + // Flickable's timeline is real-time, so spoofing timestamps isn't enough + QTest::qWait(dragStepDelay); + } + + QTest::mouseRelease(&window, Qt::LeftButton, Qt::NoModifier, QPoint(20, 50), dragStepDelay); + + QCOMPARE(flickable->isFlicking(), false); + QCOMPARE(flickable->isFlickingVertically(), false); + QTRY_COMPARE(flickable->isMoving(), false); + QCOMPARE(flickable->isMovingVertically(), false); + QCOMPARE(flickStartSpy.size(), 1); + QCOMPARE(flickEndSpy.size(), 1); + QCOMPARE(vMoveSpy.size(), 2); + QCOMPARE(hMoveSpy.size(), 0); + QCOMPARE(moveSpy.size(), 2); + QCOMPARE(vFlickSpy.size(), 2); + QCOMPARE(hFlickSpy.size(), 0); // Stop on a full pixel after user interaction QCOMPARE(flickable->contentX(), (qreal)qRound(flickable->contentX())); } |