diff options
Diffstat (limited to 'tests/auto/quick/qquickflickable/tst_qquickflickable.cpp')
-rw-r--r-- | tests/auto/quick/qquickflickable/tst_qquickflickable.cpp | 448 |
1 files changed, 438 insertions, 10 deletions
diff --git a/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp b/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp index 315b6d4fca..51020672b7 100644 --- a/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp +++ b/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp @@ -26,16 +26,19 @@ ** ****************************************************************************/ #include <qtest.h> +#include <QtTest/QtTest> #include <QtTest/QSignalSpy> +#include <QtQuick/qquickview.h> +#include <QtQuickTest/QtQuickTest> #include <QtGui/QStyleHints> #include <QtQml/qqmlengine.h> #include <QtQml/qqmlcomponent.h> -#include <QtQuick/qquickview.h> #include <private/qquickflickable_p.h> #include <private/qquickflickable_p_p.h> #include <private/qquickmousearea_p.h> #include <private/qquicktransition_p.h> #include <private/qqmlvaluetype_p.h> +#include <private/qquicktaphandler_p.h> #include <math.h> #include <QtQuickTestUtils/private/qmlutils_p.h> #include <QtQuickTestUtils/private/geometrytestutils_p.h> @@ -142,6 +145,32 @@ private: bool m_active; }; +class FlickableWithExtents : public QQuickFlickable +{ +public: + qreal extent = 10; + + qreal minXExtent() const override + { + return QQuickFlickable::minXExtent() + extent; + } + + qreal maxXExtent() const override + { + return QQuickFlickable::maxXExtent() + extent; + } + + qreal minYExtent() const override + { + return QQuickFlickable::minYExtent() + extent; + } + + qreal maxYExtent() const override + { + return QQuickFlickable::maxYExtent() + extent; + } +}; + class tst_qquickflickable : public QQmlDataTest { Q_OBJECT @@ -178,6 +207,7 @@ private slots: void movingAndDragging_data(); void flickOnRelease(); void pressWhileFlicking(); + void dragWhileFlicking(); void disabled(); void flickVelocity(); void margins(); @@ -190,6 +220,7 @@ private slots: void stopAtBounds(); void stopAtBounds_data(); void nestedMouseAreaUsingTouch(); + void nestedMouseAreaPropagateComposedEvents(); void nestedSliderUsingTouch(); void nestedSliderUsingTouch_data(); void pressDelayWithLoader(); @@ -208,6 +239,13 @@ private slots: void parallelTouch(); void ignoreNonLeftMouseButtons(); void ignoreNonLeftMouseButtons_data(); + void receiveTapOutsideContentItem(); + void flickWhenRotated_data(); + void flickWhenRotated(); + void scrollingWithFractionalExtentSize_data(); + void scrollingWithFractionalExtentSize(); + void setContentPositionWhileDragging_data(); + void setContentPositionWhileDragging(); private: void flickWithTouch(QQuickWindow *window, const QPoint &from, const QPoint &to); @@ -1446,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; @@ -1463,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()); @@ -1475,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())); } @@ -2093,6 +2205,27 @@ void tst_qquickflickable::nestedMouseAreaUsingTouch() QVERIFY(nested->y() < 100.0); } +void tst_qquickflickable::nestedMouseAreaPropagateComposedEvents() +{ + QScopedPointer<QQuickView> window(new QQuickView); + window->setSource(testFileUrl("nestedmouseareapce.qml")); + QTRY_COMPARE(window->status(), QQuickView::Ready); + QQuickViewTestUtils::centerOnScreen(window.data()); + QQuickViewTestUtils::moveMouseAway(window.data()); + window->show(); + QVERIFY(window->rootObject() != nullptr); + QVERIFY(QTest::qWaitForWindowActive(window.data())); + + QQuickFlickable *flickable = qobject_cast<QQuickFlickable*>(window->rootObject()); + QVERIFY(flickable != nullptr); + + QCOMPARE(flickable->contentY(), 50.0f); + flickWithTouch(window.data(), QPoint(100, 300), QPoint(100, 200)); + + // flickable should have moved + QVERIFY(!qFuzzyCompare(flickable->contentY(), 50.0)); +} + void tst_qquickflickable::nestedSliderUsingTouch_data() { QTest::addColumn<bool>("keepMouseGrab"); @@ -2321,6 +2454,7 @@ void tst_qquickflickable::overshoot() { QFETCH(QQuickFlickable::BoundsBehavior, boundsBehavior); QFETCH(int, boundsMovement); + QFETCH(bool, pixelAligned); QScopedPointer<QQuickView> window(new QQuickView); window->setSource(testFileUrl("overshoot.qml")); @@ -2330,6 +2464,7 @@ void tst_qquickflickable::overshoot() QQuickFlickable *flickable = qobject_cast<QQuickFlickable*>(window->rootObject()); QVERIFY(flickable); + flickable->setPixelAligned(pixelAligned); QCOMPARE(flickable->width(), 200.0); QCOMPARE(flickable->height(), 200.0); @@ -2376,7 +2511,7 @@ void tst_qquickflickable::overshoot() QMetaObject::invokeMethod(flickable, "reset"); // flick past the beginning - flick(window.data(), QPoint(10, 10), QPoint(50, 50), 100); + flick(window.data(), QPoint(10, 10), QPoint(50, 50), 50); QTRY_VERIFY(!flickable->property("flicking").toBool()); if ((boundsMovement == QQuickFlickable::FollowBoundsBehavior) && (boundsBehavior & QQuickFlickable::OvershootBounds)) { @@ -2445,7 +2580,7 @@ void tst_qquickflickable::overshoot() QMetaObject::invokeMethod(flickable, "reset"); // flick past the end - flick(window.data(), QPoint(50, 50), QPoint(10, 10), 100); + flick(window.data(), QPoint(50, 50), QPoint(10, 10), 50); QTRY_VERIFY(!flickable->property("flicking").toBool()); if ((boundsMovement == QQuickFlickable::FollowBoundsBehavior) && (boundsBehavior & QQuickFlickable::OvershootBounds)) { @@ -2478,29 +2613,53 @@ void tst_qquickflickable::overshoot_data() { QTest::addColumn<QQuickFlickable::BoundsBehavior>("boundsBehavior"); QTest::addColumn<int>("boundsMovement"); + QTest::addColumn<bool>("pixelAligned"); QTest::newRow("StopAtBounds,FollowBoundsBehavior") << QQuickFlickable::BoundsBehavior(QQuickFlickable::StopAtBounds) - << int(QQuickFlickable::FollowBoundsBehavior); + << int(QQuickFlickable::FollowBoundsBehavior) << false; QTest::newRow("DragOverBounds,FollowBoundsBehavior") << QQuickFlickable::BoundsBehavior(QQuickFlickable::DragOverBounds) - << int(QQuickFlickable::FollowBoundsBehavior); + << int(QQuickFlickable::FollowBoundsBehavior) << false; QTest::newRow("OvershootBounds,FollowBoundsBehavior") << QQuickFlickable::BoundsBehavior(QQuickFlickable::OvershootBounds) - << int(QQuickFlickable::FollowBoundsBehavior); + << int(QQuickFlickable::FollowBoundsBehavior) << false; QTest::newRow("DragAndOvershootBounds,FollowBoundsBehavior") << QQuickFlickable::BoundsBehavior(QQuickFlickable::DragAndOvershootBounds) - << int(QQuickFlickable::FollowBoundsBehavior); + << int(QQuickFlickable::FollowBoundsBehavior) << false; QTest::newRow("DragOverBounds,StopAtBounds") << QQuickFlickable::BoundsBehavior(QQuickFlickable::DragOverBounds) - << int(QQuickFlickable::StopAtBounds); + << int(QQuickFlickable::StopAtBounds) << false; QTest::newRow("OvershootBounds,StopAtBounds") << QQuickFlickable::BoundsBehavior(QQuickFlickable::OvershootBounds) - << int(QQuickFlickable::StopAtBounds); + << int(QQuickFlickable::StopAtBounds) << false; QTest::newRow("DragAndOvershootBounds,StopAtBounds") << QQuickFlickable::BoundsBehavior(QQuickFlickable::DragAndOvershootBounds) - << int(QQuickFlickable::StopAtBounds); + << int(QQuickFlickable::StopAtBounds) << false; + + QTest::newRow("StopAtBounds,FollowBoundsBehavior,pixelAligned") + << QQuickFlickable::BoundsBehavior(QQuickFlickable::StopAtBounds) + << int(QQuickFlickable::FollowBoundsBehavior) << true; + QTest::newRow("DragOverBounds,FollowBoundsBehavior,pixelAligned") + << QQuickFlickable::BoundsBehavior(QQuickFlickable::DragOverBounds) + << int(QQuickFlickable::FollowBoundsBehavior) << true; + QTest::newRow("OvershootBounds,FollowBoundsBehavior,pixelAligned") + << QQuickFlickable::BoundsBehavior(QQuickFlickable::OvershootBounds) + << int(QQuickFlickable::FollowBoundsBehavior) << true; + QTest::newRow("DragAndOvershootBounds,FollowBoundsBehavior,pixelAligned") + << QQuickFlickable::BoundsBehavior(QQuickFlickable::DragAndOvershootBounds) + << int(QQuickFlickable::FollowBoundsBehavior) << true; + + QTest::newRow("DragOverBounds,StopAtBounds,pixelAligned") + << QQuickFlickable::BoundsBehavior(QQuickFlickable::DragOverBounds) + << int(QQuickFlickable::StopAtBounds) << true; + QTest::newRow("OvershootBounds,StopAtBounds,pixelAligned") + << QQuickFlickable::BoundsBehavior(QQuickFlickable::OvershootBounds) + << int(QQuickFlickable::StopAtBounds) << true; + QTest::newRow("DragAndOvershootBounds,StopAtBounds,pixelAligned") + << QQuickFlickable::BoundsBehavior(QQuickFlickable::DragAndOvershootBounds) + << int(QQuickFlickable::StopAtBounds) << true; } void tst_qquickflickable::overshoot_reentrant() @@ -2716,6 +2875,275 @@ void tst_qquickflickable::ignoreNonLeftMouseButtons_data() QTest::newRow("middle") << Qt::MiddleButton; } +void tst_qquickflickable::receiveTapOutsideContentItem() +{ + // Check that if we add a TapHandler handler to a flickable, we + // can tap on the whole flickable area inside it, which includes + // the extents in addition to the content item. + QQuickView window; + window.resize(200, 200); + FlickableWithExtents flickable; + flickable.setParentItem(window.contentItem()); + flickable.setWidth(200); + flickable.setHeight(200); + flickable.setContentWidth(100); + flickable.setContentHeight(100); + + window.show(); + QVERIFY(QTest::qWaitForWindowActive(&window)); + + QQuickTapHandler tapHandler(&flickable); + QSignalSpy clickedSpy(&tapHandler, SIGNAL(tapped(QEventPoint, Qt::MouseButton))); + + // Tap outside the content item in the top-left corner + QTest::mouseClick(&window, Qt::LeftButton, {}, QPoint(5, 5)); + QCOMPARE(clickedSpy.count(), 1); + + // Tap outside the content item in the bottom-right corner + const QPoint bottomRight(flickable.contentItem()->width() + 5, flickable.contentItem()->height() + 5); + QTest::mouseClick(&window, Qt::LeftButton, {}, bottomRight); + QCOMPARE(clickedSpy.count(), 2); +} + +void tst_qquickflickable::flickWhenRotated_data() +{ + QTest::addColumn<qreal>("rootRotation"); + QTest::addColumn<qreal>("flickableRotation"); + QTest::addColumn<qreal>("scale"); + + static constexpr qreal rotations[] = { 0, 30, 90, 180, 270 }; + static constexpr qreal scales[] = { 0.3, 1, 1.5 }; + + for (const auto pr : rotations) { + for (const auto fr : rotations) { + if (pr <= 90) { + for (const auto s : scales) + QTest::addRow("parent: %g, flickable: %g, scale: %g", pr, fr, s) << pr << fr << s; + } else { + // don't bother trying every scale with every set of rotations, to save time + QTest::addRow("parent: %g, flickable: %g, scale: 1", pr, fr) << pr << fr << qreal(1); + } + } + } +} + +void tst_qquickflickable::flickWhenRotated() // QTBUG-99639 +{ + QFETCH(qreal, rootRotation); + QFETCH(qreal, flickableRotation); + QFETCH(qreal, scale); + + QQuickView window; + QVERIFY(QQuickTest::showView(window, testFileUrl("rotatedFlickable.qml"))); + QQuickItem *rootItem = window.rootObject(); + QVERIFY(rootItem); + QQuickFlickable *flickable = rootItem->findChild<QQuickFlickable*>(); + QVERIFY(flickable); + + rootItem->setRotation(rootRotation); + flickable->setRotation(flickableRotation); + rootItem->setScale(scale); + QVERIFY(flickable->isAtYBeginning()); + + // Flick in Y direction in Flickable's coordinate system and check how much it moved + const QPointF startPoint = flickable->mapToGlobal(QPoint(20, 180)); + const QPointF endPoint = flickable->mapToGlobal(QPoint(20, 40)); + flick(&window, window.mapFromGlobal(startPoint).toPoint(), window.mapFromGlobal(endPoint).toPoint(), 100); + QTRY_VERIFY(flickable->isMoving()); + QTRY_VERIFY(!flickable->isMoving()); + qCDebug(lcTests) << "flicking from" << startPoint << "to" << endPoint << ": ended at contentY" << flickable->contentY(); + // usually flickable->contentY() is at 275 or very close + QVERIFY(!flickable->isAtYBeginning()); +} + + +void tst_qquickflickable::scrollingWithFractionalExtentSize_data() +{ + QTest::addColumn<QByteArray>("property"); + QTest::addColumn<bool>("isYAxis"); + QTest::addColumn<bool>("atBeginning"); + QTest::addColumn<QQuickFlickable::BoundsBehaviorFlag>("boundsBehaviour"); + + QTest::newRow("minyextent") << QByteArray("topMargin") << true << true << QQuickFlickable::StopAtBounds; + QTest::newRow("maxyextent") << QByteArray("bottomMargin") << true << false << QQuickFlickable::StopAtBounds; + QTest::newRow("minxextent") << QByteArray("leftMargin") << false << true << QQuickFlickable::StopAtBounds; + QTest::newRow("maxxextent") << QByteArray("rightMargin") << false << false << QQuickFlickable::StopAtBounds; + + QTest::newRow("minyextent") << QByteArray("topMargin") << true << true << QQuickFlickable::DragAndOvershootBounds; + QTest::newRow("maxyextent") << QByteArray("bottomMargin") << true << false << QQuickFlickable::DragAndOvershootBounds; + QTest::newRow("minxextent") << QByteArray("leftMargin") << false << true << QQuickFlickable::DragAndOvershootBounds; + QTest::newRow("maxxextent") << QByteArray("rightMargin") << false << false << QQuickFlickable::DragAndOvershootBounds; +} + +void tst_qquickflickable::scrollingWithFractionalExtentSize() // QTBUG-101268 +{ + QFETCH(QByteArray, property); + QFETCH(bool, isYAxis); + QFETCH(bool, atBeginning); + QFETCH(QQuickFlickable::BoundsBehaviorFlag, boundsBehaviour); + + QQuickView window; + QVERIFY(QQuickTest::showView(window, testFileUrl("fractionalExtent.qml"))); + QQuickItem *rootItem = window.rootObject(); + QVERIFY(rootItem); + QQuickFlickable *flickable = qobject_cast<QQuickFlickable *>(rootItem); + QVERIFY(flickable); + flickable->setBoundsBehavior(boundsBehaviour); + + qreal value = 100.5; + flickable->setProperty(property.constData(), 100.5); + if (isYAxis) + flickable->setContentY(atBeginning ? -value : value + qAbs(flickable->height() - flickable->contentHeight())); + else + flickable->setContentX(atBeginning ? -value : value + qAbs(flickable->width() - flickable->contentWidth())); + + if (isYAxis) { + QVERIFY(atBeginning ? flickable->isAtYBeginning() : flickable->isAtYEnd()); + QVERIFY(!flickable->isMovingVertically()); + } else { + QVERIFY(atBeginning ? flickable->isAtXBeginning() : flickable->isAtXEnd()); + QVERIFY(!flickable->isMovingHorizontally()); + } + + QPointF pos(flickable->x() + flickable->width() / 2, flickable->y() + flickable->height() / 2); + QPoint angleDelta(isYAxis ? 0 : (atBeginning ? -50 : 50), isYAxis ? (atBeginning ? -50 : 50) : 0); + + QWheelEvent wheelEvent1(pos, window.mapToGlobal(pos), QPoint(), angleDelta, + Qt::NoButton, Qt::NoModifier, Qt::NoScrollPhase, false); + + QGuiApplication::sendEvent(&window, &wheelEvent1); + qApp->processEvents(); + if (isYAxis) { + QVERIFY(flickable->isMovingVertically()); + QTRY_VERIFY(!flickable->isMovingVertically()); + QVERIFY(!(atBeginning ? flickable->isAtYBeginning() : flickable->isAtYEnd())); + } else { + QVERIFY(flickable->isMovingHorizontally()); + QTRY_VERIFY(!flickable->isMovingHorizontally()); + QVERIFY(!(atBeginning ? flickable->isAtXBeginning() : flickable->isAtXEnd())); + } + + QWheelEvent wheelEvent2(pos, window.mapToGlobal(pos), QPoint(), -angleDelta, + Qt::NoButton, Qt::NoModifier, Qt::NoScrollPhase, false); + wheelEvent2.setTimestamp(wheelEvent1.timestamp() + 10); + + QGuiApplication::sendEvent(&window, &wheelEvent2); + qApp->processEvents(); + + if (isYAxis) { + QVERIFY(flickable->isMovingVertically()); + QTRY_VERIFY(!flickable->isMovingVertically()); + QVERIFY(atBeginning ? flickable->isAtYBeginning() : flickable->isAtYEnd()); + } else { + QVERIFY(flickable->isMovingHorizontally()); + QTRY_VERIFY(!flickable->isMovingHorizontally()); + QVERIFY(atBeginning ? flickable->isAtXBeginning() : flickable->isAtXEnd()); + } +} + +void tst_qquickflickable::setContentPositionWhileDragging_data() +{ + QTest::addColumn<bool>("isHorizontal"); + QTest::addColumn<int>("newPos"); + QTest::addColumn<int>("newExtent"); + QTest::newRow("horizontal, setContentX") << true << 0 << -1; + QTest::newRow("vertical, setContentY") << false << 0 << -1; + QTest::newRow("horizontal, setContentWidth") << true << -1 << 200; + QTest::newRow("vertical, setContentHeight") << false << -1 << 200; +} + +void tst_qquickflickable::setContentPositionWhileDragging() // QTBUG-104966 +{ + QFETCH(bool, isHorizontal); + QFETCH(int, newPos); + QFETCH(int, newExtent); + QQuickView window; + QVERIFY(QQuickTest::showView(window, testFileUrl("contentPosWhileDragging.qml"))); + QQuickViewTestUtils::centerOnScreen(&window); + QVERIFY(window.isVisible()); + QQuickItem *rootItem = window.rootObject(); + QVERIFY(rootItem); + QQuickFlickable *flickable = rootItem->findChild<QQuickFlickable *>(); + QVERIFY(flickable); + + const auto contentPos = [flickable]() -> QPoint { + return QPoint(flickable->contentX(), flickable->contentY()); + }; + const qreal threshold = + qApp->styleHints()->startDragDistance() * flickable->parentItem()->scale(); + const QPoint thresholdPnt(qRound(threshold), qRound(threshold)); + const auto flickableCenterPos = flickable->mapToScene({flickable->width() / 2, flickable->height() / 2}).toPoint(); + + // Drag the mouse until we have surpassed the mouse drag threshold and a drag is initiated + // by checking for flickable->isDragging() + QPoint pos = flickableCenterPos; + QQuickViewTestUtils::moveAndPress(&window, pos); + int j = 1; + QVERIFY(!flickable->isDragging()); + while (!flickable->isDragging()) { + pos = flickableCenterPos - QPoint(j, j); + QTest::mouseMove(&window, pos); + j++; + } + + // Now we have entered the drag state + QVERIFY(flickable->isDragging()); + QCOMPARE(flickable->contentX(), 0); + QCOMPARE(flickable->contentY(), 0); + QVERIFY(flickable->width() > 0); + QVERIFY(flickable->height() > 0); + + + const int moveLength = 50; + const QPoint unitDelta(isHorizontal ? 1 : 0, isHorizontal ? 0 : 1); + const QPoint moveDelta = unitDelta * moveLength; + + pos -= 3*moveDelta; + QTest::mouseMove(&window, pos); + // Should be positive because we drag in the opposite direction + QCOMPARE(contentPos(), 3 * moveDelta); + QPoint expectedContentPos; + + // Set the content item position back to zero *while dragging* (!!) + if (newPos >= 0) { + if (isHorizontal) { + flickable->setContentX(newPos); + } else { + flickable->setContentY(newPos); + } + // Continue dragging + pos -= moveDelta; + expectedContentPos = moveDelta; + } else if (newExtent >= 0) { + // ...or reduce the content size be be less than current (contentX, contentY) position + // This forces the content item to move. + // contentY: 150 + // 320 - 150 = 170 pixels down to bottom + // Now reduce contentHeight to 200 + // since we are at the bottom, and the flickable is 100 pixels tall, contentY must land + // at newExtent - 100. + + if (isHorizontal) { + flickable->setContentWidth(newExtent); + } else { + flickable->setContentHeight(newExtent); + } + // Assumption is that the contentItem is aligned to the bottom of the flickable + // We therefore cannot scroll/flick it further down. Drag it up towards the top instead + // (by moving mouse down). + pos += moveDelta; + expectedContentPos = unitDelta * (newExtent - (isHorizontal ? flickable->width() : flickable->height())); + } + + QTest::mouseMove(&window, pos); + + // Make sure that the contentItem was only dragged the delta in mouse movement since the last + // setContentX/Y() call. + QCOMPARE(contentPos(), expectedContentPos); + QTest::mouseRelease(&window, Qt::LeftButton, Qt::NoModifier, pos); + QVERIFY(!flickable->isDragging()); +} + QTEST_MAIN(tst_qquickflickable) #include "tst_qquickflickable.moc" |