aboutsummaryrefslogtreecommitdiffstats
path: root/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tests/auto/quick/qquickflickable/tst_qquickflickable.cpp')
-rw-r--r--tests/auto/quick/qquickflickable/tst_qquickflickable.cpp1359
1 files changed, 1071 insertions, 288 deletions
diff --git a/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp b/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp
index b7a1848949..b003511356 100644
--- a/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp
+++ b/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp
@@ -1,53 +1,33 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-#include <qtest.h>
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#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/qguiapplication_p.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 "../../shared/util.h"
-#include "../shared/geometrytestutil.h"
-#include "../shared/viewtestutil.h"
-#include "../shared/visualtestutil.h"
+#include <QtGui/qpa/qplatformintegration.h>
+#include <QtQuickTestUtils/private/qmlutils_p.h>
+#include <QtQuickTestUtils/private/geometrytestutils_p.h>
+#include <QtQuickTestUtils/private/viewtestutils_p.h>
+#include <QtQuickTestUtils/private/visualtestutils_p.h>
#include <qpa/qwindowsysteminterface.h>
Q_LOGGING_CATEGORY(lcTests, "qt.quick.tests")
-using namespace QQuickViewTestUtil;
-using namespace QQuickVisualTestUtil;
+using namespace QQuickViewTestUtils;
+using namespace QQuickVisualTestUtils;
// an abstract Slider which only handles touch events
class TouchDragArea : public QQuickItem
@@ -95,7 +75,7 @@ public:
protected:
void touchEvent(QTouchEvent *ev) override
{
- QCOMPARE(ev->points().count(), 1);
+ QCOMPARE(ev->points().size(), 1);
auto touchpoint = ev->points().first();
switch (touchpoint.state()) {
case QEventPoint::State::Pressed:
@@ -142,11 +122,38 @@ 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
public:
tst_qquickflickable()
+ : QQmlDataTest(QT_QMLTEST_DATADIR)
{}
private slots:
@@ -160,6 +167,7 @@ private slots:
void rebound();
void maximumFlickVelocity();
void flickDeceleration();
+ void pressDelay_data();
void pressDelay();
void nestedPressDelay();
void filterReplayedPress();
@@ -169,6 +177,7 @@ private slots:
void returnToBounds();
void returnToBounds_data();
void wheel();
+ void wheelBackwards();
void trackpad();
void nestedTrackpad();
void movingAndFlicking();
@@ -177,6 +186,7 @@ private slots:
void movingAndDragging_data();
void flickOnRelease();
void pressWhileFlicking();
+ void dragWhileFlicking();
void disabled();
void flickVelocity();
void margins();
@@ -189,6 +199,7 @@ private slots:
void stopAtBounds();
void stopAtBounds_data();
void nestedMouseAreaUsingTouch();
+ void nestedMouseAreaPropagateComposedEvents();
void nestedSliderUsingTouch();
void nestedSliderUsingTouch_data();
void pressDelayWithLoader();
@@ -205,16 +216,40 @@ private slots:
void synchronousDrag();
void visibleAreaBinding();
void parallelTouch();
+ void ignoreNonLeftMouseButtons();
+ void ignoreNonLeftMouseButtons_data();
+ void receiveTapOutsideContentItem();
+ void flickWhenRotated_data();
+ void flickWhenRotated();
+ void flickAndReleaseOutsideBounds();
+ void scrollingWithFractionalExtentSize_data();
+ void scrollingWithFractionalExtentSize();
+ void setContentPositionWhileDragging_data();
+ void setContentPositionWhileDragging();
+ void coalescedMove();
+ void onlyOneMove();
+ void proportionalWheelScrolling();
+ void touchCancel();
+ void pixelAlignedEndPoints();
private:
void flickWithTouch(QQuickWindow *window, const QPoint &from, const QPoint &to);
QPointingDevice *touchDevice = QTest::createTouchDevice();
+ const QPointingDevice *mouseDevice = new QPointingDevice(
+ "test mouse", 1000, QInputDevice::DeviceType::Mouse, QPointingDevice::PointerType::Generic,
+ QInputDevice::Capability::Position | QInputDevice::Capability::Hover | QInputDevice::Capability::Scroll,
+ 1, 5, QString(), QPointingDeviceUniqueId(), this);
};
void tst_qquickflickable::initTestCase()
{
+#ifdef Q_OS_ANDROID
+ QSKIP("test crashes at unknown location in Android");
+#endif
QQmlDataTest::initTestCase();
qmlRegisterType<TouchDragArea>("Test",1,0,"TouchDragArea");
+ touchDevice->setParent(this); // avoid leak
+ QWindowSystemInterface::registerInputDevice(mouseDevice);
}
void tst_qquickflickable::cleanup()
@@ -335,27 +370,27 @@ void tst_qquickflickable::boundsBehavior()
flickable->setBoundsBehavior(QQuickFlickable::DragAndOvershootBounds);
QCOMPARE(flickable->boundsBehavior(), QQuickFlickable::DragAndOvershootBounds);
- QCOMPARE(spy.count(),1);
+ QCOMPARE(spy.size(),1);
flickable->setBoundsBehavior(QQuickFlickable::DragAndOvershootBounds);
- QCOMPARE(spy.count(),1);
+ QCOMPARE(spy.size(),1);
flickable->setBoundsBehavior(QQuickFlickable::DragOverBounds);
QCOMPARE(flickable->boundsBehavior(), QQuickFlickable::DragOverBounds);
- QCOMPARE(spy.count(),2);
+ QCOMPARE(spy.size(),2);
flickable->setBoundsBehavior(QQuickFlickable::DragOverBounds);
- QCOMPARE(spy.count(),2);
+ QCOMPARE(spy.size(),2);
flickable->setBoundsBehavior(QQuickFlickable::StopAtBounds);
QCOMPARE(flickable->boundsBehavior(), QQuickFlickable::StopAtBounds);
- QCOMPARE(spy.count(),3);
+ QCOMPARE(spy.size(),3);
flickable->setBoundsBehavior(QQuickFlickable::StopAtBounds);
- QCOMPARE(spy.count(),3);
+ QCOMPARE(spy.size(),3);
flickable->setBoundsBehavior(QQuickFlickable::OvershootBounds);
QCOMPARE(flickable->boundsBehavior(), QQuickFlickable::OvershootBounds);
- QCOMPARE(spy.count(),4);
+ QCOMPARE(spy.size(),4);
flickable->setBoundsBehavior(QQuickFlickable::OvershootBounds);
- QCOMPARE(spy.count(),4);
+ QCOMPARE(spy.size(),4);
delete flickable;
}
@@ -365,8 +400,8 @@ void tst_qquickflickable::rebound()
QScopedPointer<QQuickView> window(new QQuickView);
window->setSource(testFileUrl("rebound.qml"));
QTRY_COMPARE(window->status(), QQuickView::Ready);
- QQuickViewTestUtil::centerOnScreen(window.data());
- QQuickViewTestUtil::moveMouseAway(window.data());
+ QQuickViewTestUtils::centerOnScreen(window.data());
+ QQuickViewTestUtils::moveMouseAway(window.data());
window->show();
QVERIFY(QTest::qWaitForWindowActive(window.data()));
@@ -388,23 +423,23 @@ void tst_qquickflickable::rebound()
flick(window.data(), QPoint(20,20), QPoint(120,120), 200);
QTRY_COMPARE(window->rootObject()->property("transitionsStarted").toInt(), 2);
- QCOMPARE(hMoveSpy.count(), 1);
- QCOMPARE(vMoveSpy.count(), 1);
- QCOMPARE(movementStartedSpy.count(), 1);
- QCOMPARE(movementEndedSpy.count(), 0);
+ QCOMPARE(hMoveSpy.size(), 1);
+ QCOMPARE(vMoveSpy.size(), 1);
+ QCOMPARE(movementStartedSpy.size(), 1);
+ QCOMPARE(movementEndedSpy.size(), 0);
QVERIFY(rebound->running());
QTRY_VERIFY(!flickable->isMoving());
QCOMPARE(flickable->contentX(), 0.0);
QCOMPARE(flickable->contentY(), 0.0);
- QCOMPARE(hMoveSpy.count(), 2);
- QCOMPARE(vMoveSpy.count(), 2);
- QCOMPARE(movementStartedSpy.count(), 1);
- QCOMPARE(movementEndedSpy.count(), 1);
+ QCOMPARE(hMoveSpy.size(), 2);
+ QCOMPARE(vMoveSpy.size(), 2);
+ QCOMPARE(movementStartedSpy.size(), 1);
+ QCOMPARE(movementEndedSpy.size(), 1);
QCOMPARE(window->rootObject()->property("transitionsStarted").toInt(), 2);
QVERIFY(!rebound->running());
- QCOMPARE(reboundSpy.count(), 2);
+ QCOMPARE(reboundSpy.size(), 2);
hMoveSpy.clear();
vMoveSpy.clear();
@@ -420,19 +455,19 @@ void tst_qquickflickable::rebound()
QVERIFY(flickable->isMoving());
QTRY_VERIFY(window->rootObject()->property("transitionsStarted").toInt() >= 1);
- QCOMPARE(hMoveSpy.count(), 1);
- QCOMPARE(vMoveSpy.count(), 1);
- QCOMPARE(movementStartedSpy.count(), 1);
+ QCOMPARE(hMoveSpy.size(), 1);
+ QCOMPARE(vMoveSpy.size(), 1);
+ QCOMPARE(movementStartedSpy.size(), 1);
QTRY_VERIFY(!flickable->isMoving());
QCOMPARE(flickable->contentX(), 0.0);
// moving started/stopped signals should only have been emitted once,
// and when they are, all transitions should have finished
- QCOMPARE(hMoveSpy.count(), 2);
- QCOMPARE(vMoveSpy.count(), 2);
- QCOMPARE(movementStartedSpy.count(), 1);
- QCOMPARE(movementEndedSpy.count(), 1);
+ QCOMPARE(hMoveSpy.size(), 2);
+ QCOMPARE(vMoveSpy.size(), 2);
+ QCOMPARE(movementStartedSpy.size(), 1);
+ QCOMPARE(movementEndedSpy.size(), 1);
hMoveSpy.clear();
vMoveSpy.clear();
@@ -447,16 +482,16 @@ void tst_qquickflickable::rebound()
flick(window.data(), QPoint(20,20), QPoint(120,120), 200);
QCOMPARE(window->rootObject()->property("transitionsStarted").toInt(), 0);
- QCOMPARE(hMoveSpy.count(), 1);
- QCOMPARE(vMoveSpy.count(), 1);
- QCOMPARE(movementStartedSpy.count(), 1);
- QCOMPARE(movementEndedSpy.count(), 0);
+ QCOMPARE(hMoveSpy.size(), 1);
+ QCOMPARE(vMoveSpy.size(), 1);
+ QCOMPARE(movementStartedSpy.size(), 1);
+ QCOMPARE(movementEndedSpy.size(), 0);
QTRY_VERIFY(!flickable->isMoving());
- QCOMPARE(hMoveSpy.count(), 2);
- QCOMPARE(vMoveSpy.count(), 2);
- QCOMPARE(movementStartedSpy.count(), 1);
- QCOMPARE(movementEndedSpy.count(), 1);
+ QCOMPARE(hMoveSpy.size(), 2);
+ QCOMPARE(vMoveSpy.size(), 2);
+ QCOMPARE(movementStartedSpy.size(), 1);
+ QCOMPARE(movementEndedSpy.size(), 1);
QCOMPARE(window->rootObject()->property("transitionsStarted").toInt(), 0);
}
@@ -473,9 +508,9 @@ void tst_qquickflickable::maximumFlickVelocity()
flickable->setMaximumFlickVelocity(2.0);
QCOMPARE(flickable->maximumFlickVelocity(), 2.0);
- QCOMPARE(spy.count(),1);
+ QCOMPARE(spy.size(),1);
flickable->setMaximumFlickVelocity(2.0);
- QCOMPARE(spy.count(),1);
+ QCOMPARE(spy.size(),1);
delete flickable;
}
@@ -493,52 +528,61 @@ void tst_qquickflickable::flickDeceleration()
flickable->setFlickDeceleration(2.0);
QCOMPARE(flickable->flickDeceleration(), 2.0);
- QCOMPARE(spy.count(),1);
+ QCOMPARE(spy.size(),1);
flickable->setFlickDeceleration(2.0);
- QCOMPARE(spy.count(),1);
+ QCOMPARE(spy.size(),1);
delete flickable;
}
+void tst_qquickflickable::pressDelay_data()
+{
+ QTest::addColumn<const QPointingDevice *>("device");
+ const QPointingDevice *constTouchDevice = touchDevice;
+
+ QTest::newRow("mouse") << mouseDevice;
+ QTest::newRow("touch") << constTouchDevice;
+}
+
void tst_qquickflickable::pressDelay()
{
- QScopedPointer<QQuickView> window(new QQuickView);
- window->setSource(testFileUrl("pressDelay.qml"));
- QTRY_COMPARE(window->status(), QQuickView::Ready);
- QQuickViewTestUtil::centerOnScreen(window.data());
- QQuickViewTestUtil::moveMouseAway(window.data());
- window->show();
- QVERIFY(QTest::qWaitForWindowActive(window.data()));
- QVERIFY(window->rootObject() != nullptr);
+ QFETCH(const QPointingDevice *, device);
- QQuickFlickable *flickable = qobject_cast<QQuickFlickable*>(window->rootObject());
- QSignalSpy spy(flickable, SIGNAL(pressDelayChanged()));
+ QQuickView window;
+ QVERIFY(QQuickTest::showView(window, testFileUrl("pressDelay.qml")));
+ QQuickFlickable *flickable = qobject_cast<QQuickFlickable*>(window.rootObject());
QVERIFY(flickable);
- QCOMPARE(flickable->pressDelay(), 100);
+ QQuickMouseArea *mouseArea = flickable->findChild<QQuickMouseArea*>();
+ QSignalSpy clickedSpy(mouseArea, &QQuickMouseArea::clicked);
+ // Test the pressDelay property itself
+ QSignalSpy pressDelayChangedSpy(flickable, &QQuickFlickable::pressDelayChanged);
+ QCOMPARE(flickable->pressDelay(), 100);
flickable->setPressDelay(200);
QCOMPARE(flickable->pressDelay(), 200);
- QCOMPARE(spy.count(),1);
+ QCOMPARE(pressDelayChangedSpy.size(), 1);
flickable->setPressDelay(200);
- QCOMPARE(spy.count(),1);
+ QCOMPARE(pressDelayChangedSpy.size(), 1);
- QQuickItem *mouseArea = window->rootObject()->findChild<QQuickItem*>("mouseArea");
- QSignalSpy clickedSpy(mouseArea, SIGNAL(clicked(QQuickMouseEvent*)));
- moveAndPress(window.data(), QPoint(150, 150));
+ // Test the press delay
+ QPoint p(150, 150);
+ if (device->type() == QInputDevice::DeviceType::Mouse)
+ QQuickTest::pointerMove(device, &window, 0, p);
+ QQuickTest::pointerPress(device, &window, 0, p);
// The press should not occur immediately
- QVERIFY(!mouseArea->property("pressed").toBool());
+ QCOMPARE(mouseArea->isPressed(), false);
// But, it should occur eventually
- QTRY_VERIFY(mouseArea->property("pressed").toBool());
+ QTRY_VERIFY(mouseArea->isPressed());
- QCOMPARE(clickedSpy.count(),0);
+ QCOMPARE(clickedSpy.size(), 0);
// On release the clicked signal should be emitted
- QTest::mouseRelease(window.data(), Qt::LeftButton, Qt::NoModifier, QPoint(150, 150));
- QCOMPARE(clickedSpy.count(),1);
+ QQuickTest::pointerRelease(device, &window, 0, p);
+ QCOMPARE(clickedSpy.size(), 1);
// Press and release position should match
QCOMPARE(flickable->property("pressX").toReal(), flickable->property("releaseX").toReal());
@@ -546,38 +590,44 @@ void tst_qquickflickable::pressDelay()
// Test a quick tap within the pressDelay timeout
+ p = QPoint(180, 180);
clickedSpy.clear();
- moveAndPress(window.data(), QPoint(180, 180));
+ if (device->type() == QInputDevice::DeviceType::Mouse)
+ QQuickTest::pointerMove(device, &window, 0, p);
+ QQuickTest::pointerPress(device, &window, 0, p);
// The press should not occur immediately
- QVERIFY(!mouseArea->property("pressed").toBool());
+ QCOMPARE(mouseArea->isPressed(), false);
+ QCOMPARE(clickedSpy.size(), 0);
- QCOMPARE(clickedSpy.count(),0);
-
- // On release the press, release and clicked signal should be emitted
- QTest::mouseRelease(window.data(), Qt::LeftButton, Qt::NoModifier, QPoint(180, 180));
- QCOMPARE(clickedSpy.count(),1);
+ // On release, the press, release and clicked signal should be emitted
+ QQuickTest::pointerRelease(device, &window, 0, p);
+ QCOMPARE(clickedSpy.size(), 1);
// Press and release position should match
QCOMPARE(flickable->property("pressX").toReal(), flickable->property("releaseX").toReal());
QCOMPARE(flickable->property("pressY").toReal(), flickable->property("releaseY").toReal());
- // QTBUG-31168
- moveAndPress(window.data(), QPoint(150, 110));
+ // Test flick after press (QTBUG-31168)
+ QPoint startPosition(150, 110);
+ p = QPoint(150, 190);
+ clickedSpy.clear();
+ if (device->type() == QInputDevice::DeviceType::Mouse)
+ QQuickTest::pointerMove(device, &window, 0, startPosition);
+ QQuickTest::pointerPress(device, &window, 0, startPosition);
// The press should not occur immediately
- QVERIFY(!mouseArea->property("pressed").toBool());
+ QCOMPARE(mouseArea->isPressed(), false);
+ QQuickTest::pointerMove(device, &window, 0, p);
- QTest::mouseMove(window.data(), QPoint(150, 190));
+ // Since we moved past the drag threshold, we should never receive the press
+ QCOMPARE(mouseArea->isPressed(), false);
+ QTRY_COMPARE(mouseArea->isPressed(), false);
- // As we moved pass the drag threshold, we should never receive the press
- QVERIFY(!mouseArea->property("pressed").toBool());
- QTRY_VERIFY(!mouseArea->property("pressed").toBool());
-
- // On release the clicked signal should *not* be emitted
- QTest::mouseRelease(window.data(), Qt::LeftButton, Qt::NoModifier, QPoint(150, 190));
- QCOMPARE(clickedSpy.count(),1);
+ // On release, the clicked signal should *not* be emitted
+ QQuickTest::pointerRelease(device, &window, 0, p);
+ QCOMPARE(clickedSpy.size(), 0);
}
// QTBUG-17361
@@ -586,8 +636,8 @@ void tst_qquickflickable::nestedPressDelay()
QScopedPointer<QQuickView> window(new QQuickView);
window->setSource(testFileUrl("nestedPressDelay.qml"));
QTRY_COMPARE(window->status(), QQuickView::Ready);
- QQuickViewTestUtil::centerOnScreen(window.data());
- QQuickViewTestUtil::moveMouseAway(window.data());
+ QQuickViewTestUtils::centerOnScreen(window.data());
+ QQuickViewTestUtils::moveMouseAway(window.data());
window->show();
QVERIFY(QTest::qWaitForWindowActive(window.data()));
QVERIFY(window->rootObject() != nullptr);
@@ -666,8 +716,8 @@ void tst_qquickflickable::filterReplayedPress()
QScopedPointer<QQuickView> window(new QQuickView);
window->setSource(testFileUrl("nestedPressDelay.qml"));
QTRY_COMPARE(window->status(), QQuickView::Ready);
- QQuickViewTestUtil::centerOnScreen(window.data());
- QQuickViewTestUtil::moveMouseAway(window.data());
+ QQuickViewTestUtils::centerOnScreen(window.data());
+ QQuickViewTestUtils::moveMouseAway(window.data());
window->show();
QVERIFY(QTest::qWaitForWindowActive(window.data()));
QVERIFY(window->rootObject() != nullptr);
@@ -709,8 +759,8 @@ void tst_qquickflickable::nestedClickThenFlick()
QScopedPointer<QQuickView> window(new QQuickView);
window->setSource(testFileUrl("nestedClickThenFlick.qml"));
QTRY_COMPARE(window->status(), QQuickView::Ready);
- QQuickViewTestUtil::centerOnScreen(window.data());
- QQuickViewTestUtil::moveMouseAway(window.data());
+ QQuickViewTestUtils::centerOnScreen(window.data());
+ QQuickViewTestUtils::moveMouseAway(window.data());
window->show();
QVERIFY(QTest::qWaitForWindowActive(window.data()));
QVERIFY(window->rootObject() != nullptr);
@@ -761,19 +811,19 @@ void tst_qquickflickable::flickableDirection()
flickable->setFlickableDirection(QQuickFlickable::HorizontalAndVerticalFlick);
QCOMPARE(flickable->flickableDirection(), QQuickFlickable::HorizontalAndVerticalFlick);
- QCOMPARE(spy.count(),1);
+ QCOMPARE(spy.size(),1);
flickable->setFlickableDirection(QQuickFlickable::AutoFlickDirection);
QCOMPARE(flickable->flickableDirection(), QQuickFlickable::AutoFlickDirection);
- QCOMPARE(spy.count(),2);
+ QCOMPARE(spy.size(),2);
flickable->setFlickableDirection(QQuickFlickable::HorizontalFlick);
QCOMPARE(flickable->flickableDirection(), QQuickFlickable::HorizontalFlick);
- QCOMPARE(spy.count(),3);
+ QCOMPARE(spy.size(),3);
flickable->setFlickableDirection(QQuickFlickable::HorizontalFlick);
QCOMPARE(flickable->flickableDirection(), QQuickFlickable::HorizontalFlick);
- QCOMPARE(spy.count(),3);
+ QCOMPARE(spy.size(),3);
delete flickable;
}
@@ -846,7 +896,7 @@ void tst_qquickflickable::returnToBounds()
QTRY_COMPARE(obj->contentY(), 0.);
QVERIFY(!rebound->running());
- QCOMPARE(reboundSpy.count(), setRebound ? 2 : 0);
+ QCOMPARE(reboundSpy.size(), setRebound ? 2 : 0);
}
void tst_qquickflickable::returnToBounds_data()
@@ -869,6 +919,7 @@ void tst_qquickflickable::wheel()
QVERIFY(flick != nullptr);
QQuickFlickablePrivate *fp = QQuickFlickablePrivate::get(flick);
QSignalSpy moveEndSpy(flick, SIGNAL(movementEnded()));
+ quint64 timestamp = 10;
// test a vertical flick
{
@@ -876,16 +927,18 @@ void tst_qquickflickable::wheel()
QWheelEvent event(pos, window->mapToGlobal(pos), QPoint(), QPoint(0,-120),
Qt::NoButton, Qt::NoModifier, Qt::NoScrollPhase, false);
event.setAccepted(false);
+ event.setTimestamp(timestamp);
QGuiApplication::sendEvent(window.data(), &event);
}
QTRY_VERIFY(flick->contentY() > 0);
QCOMPARE(flick->contentX(), qreal(0));
- QTRY_COMPARE(moveEndSpy.count(), 1);
+ QTRY_COMPARE(moveEndSpy.size(), 1);
QCOMPARE(fp->velocityTimeline.isActive(), false);
QCOMPARE(fp->timeline.isActive(), false);
QTest::qWait(50); // make sure that onContentYChanged won't sneak in again
+ timestamp += 50;
QCOMPARE(flick->property("movementsAfterEnd").value<int>(), 0); // QTBUG-55886
// get ready to test horizontal flick
@@ -899,20 +952,61 @@ void tst_qquickflickable::wheel()
QPoint pos(200, 200);
QWheelEvent event(pos, window->mapToGlobal(pos), QPoint(), QPoint(-120,0),
Qt::NoButton, Qt::NoModifier, Qt::NoScrollPhase, false);
-
event.setAccepted(false);
+ event.setTimestamp(timestamp);
QGuiApplication::sendEvent(window.data(), &event);
}
QTRY_VERIFY(flick->contentX() > 0);
QCOMPARE(flick->contentY(), qreal(0));
- QTRY_COMPARE(moveEndSpy.count(), 2);
+ QTRY_COMPARE(moveEndSpy.size(), 2);
QCOMPARE(fp->velocityTimeline.isActive(), false);
QCOMPARE(fp->timeline.isActive(), false);
QTest::qWait(50); // make sure that onContentXChanged won't sneak in again
QCOMPARE(flick->property("movementsAfterEnd").value<int>(), 0); // QTBUG-55886
}
+void tst_qquickflickable::wheelBackwards() // (QTBUG-121349)
+{
+ QQuickView window;
+ QVERIFY(QQuickTest::showView(window, testFileUrl("wheel.qml")));
+ QQuickFlickable *flick = window.rootObject()->findChild<QQuickFlickable*>("flick");
+ QVERIFY(flick);
+ QSignalSpy moveEndSpy(flick, SIGNAL(movementEnded()));
+ quint64 timestamp = 10;
+ const QPoint pos(200, 200);
+
+ // attempting to scroll vertically "backwards" beyond extents does not initiate overshoot
+ {
+ QWheelEvent event(pos, window.mapToGlobal(pos), QPoint(), QPoint(0, 120),
+ Qt::NoButton, Qt::NoModifier, Qt::NoScrollPhase, false);
+ event.setAccepted(false);
+ event.setTimestamp(timestamp++);
+ QGuiApplication::sendEvent(&window, &event);
+ }
+ QCOMPARE(flick->contentY(), qreal(0));
+ QCOMPARE(flick->isMoving(), false);
+ QCOMPARE(moveEndSpy.size(), 0);
+
+ // get ready to test horizontal wheel
+ flick->setContentY(0); // which triggers movementEnded again
+ flick->setProperty("movementsAfterEnd", 0);
+ flick->setProperty("ended", false);
+ QCOMPARE(flick->contentY(), qreal(0));
+
+ // attempting to scroll horizontally "backwards" beyond extents does not initiate overshoot
+ {
+ QWheelEvent event(pos, window.mapToGlobal(pos), QPoint(), QPoint(120, 0),
+ Qt::NoButton, Qt::NoModifier, Qt::NoScrollPhase, false);
+ event.setAccepted(false);
+ event.setTimestamp(timestamp);
+ QGuiApplication::sendEvent(&window, &event);
+ }
+ QCOMPARE(flick->contentX(), qreal(0));
+ QCOMPARE(flick->isMoving(), false);
+ QCOMPARE(moveEndSpy.size(), 0);
+}
+
void tst_qquickflickable::trackpad()
{
QScopedPointer<QQuickView> window(new QQuickView);
@@ -925,11 +1019,13 @@ void tst_qquickflickable::trackpad()
QVERIFY(flick != nullptr);
QSignalSpy moveEndSpy(flick, SIGNAL(movementEnded()));
QPoint pos(200, 200);
+ quint64 timestamp = 10;
{
QWheelEvent event(pos, window->mapToGlobal(pos), QPoint(0,-100), QPoint(0,-120),
Qt::NoButton, Qt::NoModifier, Qt::ScrollBegin, false);
event.setAccepted(false);
+ event.setTimestamp(timestamp++);
QGuiApplication::sendEvent(window.data(), &event);
}
@@ -943,6 +1039,7 @@ void tst_qquickflickable::trackpad()
QWheelEvent event(pos, window->mapToGlobal(pos), QPoint(-100,0), QPoint(-120,0),
Qt::NoButton, Qt::NoModifier, Qt::ScrollUpdate, false);
event.setAccepted(false);
+ event.setTimestamp(timestamp++);
QGuiApplication::sendEvent(window.data(), &event);
}
@@ -953,10 +1050,11 @@ void tst_qquickflickable::trackpad()
QWheelEvent event(pos, window->mapToGlobal(pos), QPoint(0,0), QPoint(0,0),
Qt::NoButton, Qt::NoModifier, Qt::ScrollEnd, false);
event.setAccepted(false);
+ event.setTimestamp(timestamp++);
QGuiApplication::sendEvent(window.data(), &event);
}
- QTRY_COMPARE(moveEndSpy.count(), 1); // QTBUG-55871
+ QTRY_COMPARE(moveEndSpy.size(), 1); // QTBUG-55871
QCOMPARE(flick->property("movementsAfterEnd").value<int>(), 0); // QTBUG-55886
}
@@ -993,7 +1091,7 @@ void tst_qquickflickable::nestedTrackpad()
event.setTimestamp(timestamp++);
QGuiApplication::sendEvent(&window, &event);
}
- QTRY_COMPARE(innerMoveEndSpy.count(), 1);
+ QTRY_COMPARE(innerMoveEndSpy.size(), 1);
innerFlickable->setContentX(0);
QCOMPARE(innerFlickable->contentX(), qreal(0));
@@ -1017,7 +1115,7 @@ void tst_qquickflickable::nestedTrackpad()
event.setTimestamp(timestamp++);
QGuiApplication::sendEvent(&window, &event);
}
- QTRY_COMPARE(outerMoveEndSpy.count(), 1);
+ QTRY_COMPARE(outerMoveEndSpy.size(), 1);
}
void tst_qquickflickable::movingAndFlicking_data()
@@ -1055,8 +1153,8 @@ void tst_qquickflickable::movingAndFlicking()
QScopedPointer<QQuickView> window(new QQuickView);
window->setSource(testFileUrl("flickable03.qml"));
QTRY_COMPARE(window->status(), QQuickView::Ready);
- QQuickViewTestUtil::centerOnScreen(window.data());
- QQuickViewTestUtil::moveMouseAway(window.data());
+ QQuickViewTestUtils::centerOnScreen(window.data());
+ QQuickViewTestUtils::moveMouseAway(window.data());
window->show();
QVERIFY(QTest::qWaitForWindowActive(window.data()));
QVERIFY(window->rootObject() != nullptr);
@@ -1089,15 +1187,15 @@ void tst_qquickflickable::movingAndFlicking()
QCOMPARE(flickable->property("movingInContentX").value<bool>(), true);
QCOMPARE(flickable->property("movingInContentY").value<bool>(), true);
- QCOMPARE(moveSpy.count(), 1);
- QCOMPARE(vMoveSpy.count(), verticalEnabled ? 1 : 0);
- QCOMPARE(hMoveSpy.count(), horizontalEnabled ? 1 : 0);
- QCOMPARE(flickSpy.count(), 1);
- QCOMPARE(vFlickSpy.count(), verticalEnabled ? 1 : 0);
- QCOMPARE(hFlickSpy.count(), horizontalEnabled ? 1 : 0);
+ QCOMPARE(moveSpy.size(), 1);
+ QCOMPARE(vMoveSpy.size(), verticalEnabled ? 1 : 0);
+ QCOMPARE(hMoveSpy.size(), horizontalEnabled ? 1 : 0);
+ QCOMPARE(flickSpy.size(), 1);
+ QCOMPARE(vFlickSpy.size(), verticalEnabled ? 1 : 0);
+ QCOMPARE(hFlickSpy.size(), horizontalEnabled ? 1 : 0);
- QCOMPARE(moveStartSpy.count(), 1);
- QCOMPARE(flickStartSpy.count(), 1);
+ QCOMPARE(moveStartSpy.size(), 1);
+ QCOMPARE(flickStartSpy.size(), 1);
// wait for any motion to end
QTRY_VERIFY(!flickable->isMoving());
@@ -1108,17 +1206,17 @@ void tst_qquickflickable::movingAndFlicking()
QVERIFY(!flickable->isFlickingHorizontally());
QVERIFY(!flickable->isFlickingVertically());
- QCOMPARE(moveSpy.count(), 2);
- QCOMPARE(vMoveSpy.count(), verticalEnabled ? 2 : 0);
- QCOMPARE(hMoveSpy.count(), horizontalEnabled ? 2 : 0);
- QCOMPARE(flickSpy.count(), 2);
- QCOMPARE(vFlickSpy.count(), verticalEnabled ? 2 : 0);
- QCOMPARE(hFlickSpy.count(), horizontalEnabled ? 2 : 0);
+ QCOMPARE(moveSpy.size(), 2);
+ QCOMPARE(vMoveSpy.size(), verticalEnabled ? 2 : 0);
+ QCOMPARE(hMoveSpy.size(), horizontalEnabled ? 2 : 0);
+ QCOMPARE(flickSpy.size(), 2);
+ QCOMPARE(vFlickSpy.size(), verticalEnabled ? 2 : 0);
+ QCOMPARE(hFlickSpy.size(), horizontalEnabled ? 2 : 0);
- QCOMPARE(moveStartSpy.count(), 1);
- QCOMPARE(moveEndSpy.count(), 1);
- QCOMPARE(flickStartSpy.count(), 1);
- QCOMPARE(flickEndSpy.count(), 1);
+ QCOMPARE(moveStartSpy.size(), 1);
+ QCOMPARE(moveEndSpy.size(), 1);
+ QCOMPARE(flickStartSpy.size(), 1);
+ QCOMPARE(flickEndSpy.size(), 1);
// Stop on a full pixel after user interaction
if (verticalEnabled)
@@ -1145,17 +1243,17 @@ void tst_qquickflickable::movingAndFlicking()
QCOMPARE(flickable->isFlickingHorizontally(), horizontalEnabled);
QCOMPARE(flickable->isFlickingVertically(), verticalEnabled);
- QCOMPARE(moveSpy.count(), 1);
- QCOMPARE(vMoveSpy.count(), verticalEnabled ? 1 : 0);
- QCOMPARE(hMoveSpy.count(), horizontalEnabled ? 1 : 0);
- QCOMPARE(flickSpy.count(), 1);
- QCOMPARE(vFlickSpy.count(), verticalEnabled ? 1 : 0);
- QCOMPARE(hFlickSpy.count(), horizontalEnabled ? 1 : 0);
+ QCOMPARE(moveSpy.size(), 1);
+ QCOMPARE(vMoveSpy.size(), verticalEnabled ? 1 : 0);
+ QCOMPARE(hMoveSpy.size(), horizontalEnabled ? 1 : 0);
+ QCOMPARE(flickSpy.size(), 1);
+ QCOMPARE(vFlickSpy.size(), verticalEnabled ? 1 : 0);
+ QCOMPARE(hFlickSpy.size(), horizontalEnabled ? 1 : 0);
- QCOMPARE(moveStartSpy.count(), 1);
- QCOMPARE(moveEndSpy.count(), 0);
- QCOMPARE(flickStartSpy.count(), 1);
- QCOMPARE(flickEndSpy.count(), 0);
+ QCOMPARE(moveStartSpy.size(), 1);
+ QCOMPARE(moveEndSpy.size(), 0);
+ QCOMPARE(flickStartSpy.size(), 1);
+ QCOMPARE(flickEndSpy.size(), 0);
// wait for any motion to end
QTRY_VERIFY(!flickable->isMoving());
@@ -1166,17 +1264,17 @@ void tst_qquickflickable::movingAndFlicking()
QVERIFY(!flickable->isFlickingHorizontally());
QVERIFY(!flickable->isFlickingVertically());
- QCOMPARE(moveSpy.count(), 2);
- QCOMPARE(vMoveSpy.count(), verticalEnabled ? 2 : 0);
- QCOMPARE(hMoveSpy.count(), horizontalEnabled ? 2 : 0);
- QCOMPARE(flickSpy.count(), 2);
- QCOMPARE(vFlickSpy.count(), verticalEnabled ? 2 : 0);
- QCOMPARE(hFlickSpy.count(), horizontalEnabled ? 2 : 0);
+ QCOMPARE(moveSpy.size(), 2);
+ QCOMPARE(vMoveSpy.size(), verticalEnabled ? 2 : 0);
+ QCOMPARE(hMoveSpy.size(), horizontalEnabled ? 2 : 0);
+ QCOMPARE(flickSpy.size(), 2);
+ QCOMPARE(vFlickSpy.size(), verticalEnabled ? 2 : 0);
+ QCOMPARE(hFlickSpy.size(), horizontalEnabled ? 2 : 0);
- QCOMPARE(moveStartSpy.count(), 1);
- QCOMPARE(moveEndSpy.count(), 1);
- QCOMPARE(flickStartSpy.count(), 1);
- QCOMPARE(flickEndSpy.count(), 1);
+ QCOMPARE(moveStartSpy.size(), 1);
+ QCOMPARE(moveEndSpy.size(), 1);
+ QCOMPARE(flickStartSpy.size(), 1);
+ QCOMPARE(flickEndSpy.size(), 1);
QCOMPARE(flickable->contentX(), 0.0);
QCOMPARE(flickable->contentY(), 0.0);
@@ -1218,8 +1316,8 @@ void tst_qquickflickable::movingAndDragging()
QScopedPointer<QQuickView> window(new QQuickView);
window->setSource(testFileUrl("flickable03.qml"));
QTRY_COMPARE(window->status(), QQuickView::Ready);
- QQuickViewTestUtil::centerOnScreen(window.data());
- QQuickViewTestUtil::moveMouseAway(window.data());
+ QQuickViewTestUtils::centerOnScreen(window.data());
+ QQuickViewTestUtils::moveMouseAway(window.data());
window->show();
QVERIFY(QTest::qWaitForWindowActive(window.data()));
QVERIFY(window->rootObject() != nullptr);
@@ -1257,26 +1355,26 @@ void tst_qquickflickable::movingAndDragging()
QCOMPARE(flickable->property("draggingInContentX").value<bool>(), true);
QCOMPARE(flickable->property("draggingInContentY").value<bool>(), true);
- QCOMPARE(moveSpy.count(), 1);
- QCOMPARE(vMoveSpy.count(), verticalEnabled ? 1 : 0);
- QCOMPARE(hMoveSpy.count(), horizontalEnabled ? 1 : 0);
- QCOMPARE(dragSpy.count(), 1);
- QCOMPARE(vDragSpy.count(), verticalEnabled ? 1 : 0);
- QCOMPARE(hDragSpy.count(), horizontalEnabled ? 1 : 0);
+ QCOMPARE(moveSpy.size(), 1);
+ QCOMPARE(vMoveSpy.size(), verticalEnabled ? 1 : 0);
+ QCOMPARE(hMoveSpy.size(), horizontalEnabled ? 1 : 0);
+ QCOMPARE(dragSpy.size(), 1);
+ QCOMPARE(vDragSpy.size(), verticalEnabled ? 1 : 0);
+ QCOMPARE(hDragSpy.size(), horizontalEnabled ? 1 : 0);
- QCOMPARE(moveStartSpy.count(), 1);
- QCOMPARE(dragStartSpy.count(), 1);
+ QCOMPARE(moveStartSpy.size(), 1);
+ QCOMPARE(dragStartSpy.size(), 1);
QTest::mouseRelease(window.data(), Qt::LeftButton, Qt::NoModifier, moveFrom + moveByWithoutSnapBack*3);
QVERIFY(!flickable->isDragging());
QVERIFY(!flickable->isDraggingHorizontally());
QVERIFY(!flickable->isDraggingVertically());
- QCOMPARE(dragSpy.count(), 2);
- QCOMPARE(vDragSpy.count(), verticalEnabled ? 2 : 0);
- QCOMPARE(hDragSpy.count(), horizontalEnabled ? 2 : 0);
- QCOMPARE(dragStartSpy.count(), 1);
- QCOMPARE(dragEndSpy.count(), 1);
+ QCOMPARE(dragSpy.size(), 2);
+ QCOMPARE(vDragSpy.size(), verticalEnabled ? 2 : 0);
+ QCOMPARE(hDragSpy.size(), horizontalEnabled ? 2 : 0);
+ QCOMPARE(dragStartSpy.size(), 1);
+ QCOMPARE(dragEndSpy.size(), 1);
// Don't test whether moving finished because a flick could occur
// wait for any motion to end
@@ -1288,17 +1386,17 @@ void tst_qquickflickable::movingAndDragging()
QVERIFY(!flickable->isDraggingHorizontally());
QVERIFY(!flickable->isDraggingVertically());
- QCOMPARE(dragSpy.count(), 2);
- QCOMPARE(vDragSpy.count(), verticalEnabled ? 2 : 0);
- QCOMPARE(hDragSpy.count(), horizontalEnabled ? 2 : 0);
- QCOMPARE(moveSpy.count(), 2);
- QCOMPARE(vMoveSpy.count(), verticalEnabled ? 2 : 0);
- QCOMPARE(hMoveSpy.count(), horizontalEnabled ? 2 : 0);
+ QCOMPARE(dragSpy.size(), 2);
+ QCOMPARE(vDragSpy.size(), verticalEnabled ? 2 : 0);
+ QCOMPARE(hDragSpy.size(), horizontalEnabled ? 2 : 0);
+ QCOMPARE(moveSpy.size(), 2);
+ QCOMPARE(vMoveSpy.size(), verticalEnabled ? 2 : 0);
+ QCOMPARE(hMoveSpy.size(), horizontalEnabled ? 2 : 0);
- QCOMPARE(dragStartSpy.count(), 1);
- QCOMPARE(dragEndSpy.count(), 1);
- QCOMPARE(moveStartSpy.count(), 1);
- QCOMPARE(moveEndSpy.count(), 1);
+ QCOMPARE(dragStartSpy.size(), 1);
+ QCOMPARE(dragEndSpy.size(), 1);
+ QCOMPARE(moveStartSpy.size(), 1);
+ QCOMPARE(moveEndSpy.size(), 1);
// Stop on a full pixel after user interaction
if (verticalEnabled)
@@ -1328,17 +1426,17 @@ void tst_qquickflickable::movingAndDragging()
QCOMPARE(flickable->isDraggingHorizontally(), horizontalEnabled);
QCOMPARE(flickable->isDraggingVertically(), verticalEnabled);
- QCOMPARE(moveSpy.count(), 1);
- QCOMPARE(vMoveSpy.count(), verticalEnabled ? 1 : 0);
- QCOMPARE(hMoveSpy.count(), horizontalEnabled ? 1 : 0);
- QCOMPARE(dragSpy.count(), 1);
- QCOMPARE(vDragSpy.count(), verticalEnabled ? 1 : 0);
- QCOMPARE(hDragSpy.count(), horizontalEnabled ? 1 : 0);
+ QCOMPARE(moveSpy.size(), 1);
+ QCOMPARE(vMoveSpy.size(), verticalEnabled ? 1 : 0);
+ QCOMPARE(hMoveSpy.size(), horizontalEnabled ? 1 : 0);
+ QCOMPARE(dragSpy.size(), 1);
+ QCOMPARE(vDragSpy.size(), verticalEnabled ? 1 : 0);
+ QCOMPARE(hDragSpy.size(), horizontalEnabled ? 1 : 0);
- QCOMPARE(moveStartSpy.count(), 1);
- QCOMPARE(moveEndSpy.count(), 0);
- QCOMPARE(dragStartSpy.count(), 1);
- QCOMPARE(dragEndSpy.count(), 0);
+ QCOMPARE(moveStartSpy.size(), 1);
+ QCOMPARE(moveEndSpy.size(), 0);
+ QCOMPARE(dragStartSpy.size(), 1);
+ QCOMPARE(dragEndSpy.size(), 0);
QTest::mouseRelease(window.data(), Qt::LeftButton, Qt::NoModifier, moveFrom + moveByWithSnapBack*3);
@@ -1350,15 +1448,15 @@ void tst_qquickflickable::movingAndDragging()
QVERIFY(!flickable->isDraggingHorizontally());
QVERIFY(!flickable->isDraggingVertically());
- QCOMPARE(moveSpy.count(), 1);
- QCOMPARE(vMoveSpy.count(), verticalEnabled ? 1 : 0);
- QCOMPARE(hMoveSpy.count(), horizontalEnabled ? 1 : 0);
- QCOMPARE(dragSpy.count(), 2);
- QCOMPARE(vDragSpy.count(), verticalEnabled ? 2 : 0);
- QCOMPARE(hDragSpy.count(), horizontalEnabled ? 2 : 0);
+ QCOMPARE(moveSpy.size(), 1);
+ QCOMPARE(vMoveSpy.size(), verticalEnabled ? 1 : 0);
+ QCOMPARE(hMoveSpy.size(), horizontalEnabled ? 1 : 0);
+ QCOMPARE(dragSpy.size(), 2);
+ QCOMPARE(vDragSpy.size(), verticalEnabled ? 2 : 0);
+ QCOMPARE(hDragSpy.size(), horizontalEnabled ? 2 : 0);
- QCOMPARE(moveStartSpy.count(), 1);
- QCOMPARE(moveEndSpy.count(), 0);
+ QCOMPARE(moveStartSpy.size(), 1);
+ QCOMPARE(moveEndSpy.size(), 0);
// wait for any motion to end
QTRY_VERIFY(!flickable->isMoving());
@@ -1369,17 +1467,17 @@ void tst_qquickflickable::movingAndDragging()
QVERIFY(!flickable->isDraggingHorizontally());
QVERIFY(!flickable->isDraggingVertically());
- QCOMPARE(moveSpy.count(), 2);
- QCOMPARE(vMoveSpy.count(), verticalEnabled ? 2 : 0);
- QCOMPARE(hMoveSpy.count(), horizontalEnabled ? 2 : 0);
- QCOMPARE(dragSpy.count(), 2);
- QCOMPARE(vDragSpy.count(), verticalEnabled ? 2 : 0);
- QCOMPARE(hDragSpy.count(), horizontalEnabled ? 2 : 0);
+ QCOMPARE(moveSpy.size(), 2);
+ QCOMPARE(vMoveSpy.size(), verticalEnabled ? 2 : 0);
+ QCOMPARE(hMoveSpy.size(), horizontalEnabled ? 2 : 0);
+ QCOMPARE(dragSpy.size(), 2);
+ QCOMPARE(vDragSpy.size(), verticalEnabled ? 2 : 0);
+ QCOMPARE(hDragSpy.size(), horizontalEnabled ? 2 : 0);
- QCOMPARE(moveStartSpy.count(), 1);
- QCOMPARE(moveEndSpy.count(), 1);
- QCOMPARE(dragStartSpy.count(), 1);
- QCOMPARE(dragEndSpy.count(), 1);
+ QCOMPARE(moveStartSpy.size(), 1);
+ QCOMPARE(moveEndSpy.size(), 1);
+ QCOMPARE(dragStartSpy.size(), 1);
+ QCOMPARE(dragEndSpy.size(), 1);
QCOMPARE(flickable->contentX(), 0.0);
QCOMPARE(flickable->contentY(), 0.0);
@@ -1407,7 +1505,7 @@ void tst_qquickflickable::flickOnRelease()
QTest::mouseMove(window.data(), QPoint(50, 10), 10);
QTest::mouseRelease(window.data(), Qt::LeftButton, Qt::NoModifier, QPoint(50, 10), 10);
- QCOMPARE(vFlickSpy.count(), 1);
+ QCOMPARE(vFlickSpy.size(), 1);
// wait for any motion to end
QTRY_VERIFY(!flickable->isMoving());
@@ -1421,8 +1519,8 @@ void tst_qquickflickable::pressWhileFlicking()
QScopedPointer<QQuickView> window(new QQuickView);
window->setSource(testFileUrl("flickable03.qml"));
QTRY_COMPARE(window->status(), QQuickView::Ready);
- QQuickViewTestUtil::centerOnScreen(window.data());
- QQuickViewTestUtil::moveMouseAway(window.data());
+ QQuickViewTestUtils::centerOnScreen(window.data());
+ QQuickViewTestUtils::moveMouseAway(window.data());
window->show();
QVERIFY(QTest::qWaitForWindowActive(window.data()));
QVERIFY(window->rootObject() != nullptr);
@@ -1436,6 +1534,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;
@@ -1447,12 +1547,14 @@ void tst_qquickflickable::pressWhileFlicking()
QVERIFY(flickable->isMoving());
QVERIFY(flickable->isMovingVertically());
QVERIFY(!flickable->isMovingHorizontally());
- QCOMPARE(vMoveSpy.count(), 1);
- QCOMPARE(hMoveSpy.count(), 0);
- QCOMPARE(moveSpy.count(), 1);
- QCOMPARE(vFlickSpy.count(), 1);
- QCOMPARE(hFlickSpy.count(), 0);
- QCOMPARE(flickSpy.count(), 1);
+ 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);
QTest::mousePress(window.data(), Qt::LeftButton, Qt::NoModifier, QPoint(20, 50));
QTRY_VERIFY(!flickable->isFlicking());
@@ -1465,6 +1567,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()));
}
@@ -1502,8 +1674,8 @@ void tst_qquickflickable::flickVelocity()
QScopedPointer<QQuickView> window(new QQuickView);
window->setSource(testFileUrl("flickable03.qml"));
QTRY_COMPARE(window->status(), QQuickView::Ready);
- QQuickViewTestUtil::centerOnScreen(window.data());
- QQuickViewTestUtil::moveMouseAway(window.data());
+ QQuickViewTestUtils::centerOnScreen(window.data());
+ QQuickViewTestUtils::moveMouseAway(window.data());
window->show();
QVERIFY(QTest::qWaitForWindowActive(window.data()));
QVERIFY(window->rootObject() != nullptr);
@@ -1546,8 +1718,8 @@ void tst_qquickflickable::margins()
QScopedPointer<QQuickView> window(new QQuickView);
window->setSource(testFileUrl("margins.qml"));
QTRY_COMPARE(window->status(), QQuickView::Ready);
- QQuickViewTestUtil::centerOnScreen(window.data());
- QQuickViewTestUtil::moveMouseAway(window.data());
+ QQuickViewTestUtils::centerOnScreen(window.data());
+ QQuickViewTestUtils::moveMouseAway(window.data());
window->setTitle(QTest::currentTestFunction());
window->show();
QVERIFY(QTest::qWaitForWindowActive(window.data()));
@@ -1610,8 +1782,8 @@ void tst_qquickflickable::cancelOnHide()
QScopedPointer<QQuickView> window(new QQuickView);
window->setSource(testFileUrl("hide.qml"));
QTRY_COMPARE(window->status(), QQuickView::Ready);
- QQuickViewTestUtil::centerOnScreen(window.data());
- QQuickViewTestUtil::moveMouseAway(window.data());
+ QQuickViewTestUtils::centerOnScreen(window.data());
+ QQuickViewTestUtils::moveMouseAway(window.data());
window->show();
QVERIFY(QTest::qWaitForWindowActive(window.data()));
QVERIFY(window->rootObject());
@@ -1629,8 +1801,8 @@ void tst_qquickflickable::cancelOnMouseGrab()
QScopedPointer<QQuickView> window(new QQuickView);
window->setSource(testFileUrl("cancel.qml"));
QTRY_COMPARE(window->status(), QQuickView::Ready);
- QQuickViewTestUtil::centerOnScreen(window.data());
- QQuickViewTestUtil::moveMouseAway(window.data());
+ QQuickViewTestUtils::centerOnScreen(window.data());
+ QQuickViewTestUtils::moveMouseAway(window.data());
window->show();
QVERIFY(QTest::qWaitForWindowActive(window.data()));
QVERIFY(window->rootObject() != nullptr);
@@ -1653,7 +1825,8 @@ void tst_qquickflickable::cancelOnMouseGrab()
QQuickItem *item = window->rootObject()->findChild<QQuickItem*>("row");
auto mouse = QPointingDevice::primaryPointingDevice();
auto mousePriv = QPointingDevicePrivate::get(const_cast<QPointingDevice *>(mouse));
- QMouseEvent fakeMouseEv(QEvent::MouseMove, QPoint(130, 100), Qt::NoButton, Qt::LeftButton, Qt::NoModifier, mouse);
+ QMouseEvent fakeMouseEv(QEvent::MouseMove, QPoint(130, 100), QPoint(130, 100),
+ Qt::NoButton, Qt::LeftButton, Qt::NoModifier, mouse);
mousePriv->setExclusiveGrabber(&fakeMouseEv, fakeMouseEv.points().first(), item);
QTRY_COMPARE(flickable->contentX(), 0.);
@@ -1669,8 +1842,8 @@ void tst_qquickflickable::clickAndDragWhenTransformed()
QScopedPointer<QQuickView> view(new QQuickView);
view->setSource(testFileUrl("transformedFlickable.qml"));
QTRY_COMPARE(view->status(), QQuickView::Ready);
- QQuickViewTestUtil::centerOnScreen(view.data());
- QQuickViewTestUtil::moveMouseAway(view.data());
+ QQuickVisualTestUtils::centerOnScreen(view.data());
+ QQuickVisualTestUtils::moveMouseAway(view.data());
view->show();
QVERIFY(QTest::qWaitForWindowActive(view.data()));
QVERIFY(view->rootObject() != nullptr);
@@ -1688,7 +1861,8 @@ void tst_qquickflickable::clickAndDragWhenTransformed()
QTRY_COMPARE(flickable->property("itemPressed").toBool(), true);
QTest::mouseRelease(view.data(), Qt::LeftButton, Qt::NoModifier, QPoint(200, 200));
- const int threshold = qApp->styleHints()->startDragDistance();
+ // drag threshold is scaled according to the scene scaling
+ const int threshold = qApp->styleHints()->startDragDistance() * flickable->parentItem()->scale();
// drag outside bounds
moveAndPress(view.data(), QPoint(160, 160));
@@ -1701,10 +1875,18 @@ void tst_qquickflickable::clickAndDragWhenTransformed()
// drag inside bounds
moveAndPress(view.data(), QPoint(200, 140));
+ QCOMPARE(flickable->keepMouseGrab(), false);
QTest::qWait(10);
+ // Flickable should get interested in dragging when the drag is beyond the
+ // threshold distance along the hypoteneuse of the 45° rotation
+ const int deltaPastRotatedThreshold = threshold * 1.414 + 1;
+ QTest::mouseMove(view.data(), QPoint(200 + deltaPastRotatedThreshold, 140));
+ qCDebug(lcTests) << "transformed flickable dragging yet?" << flickable->isDragging() <<
+ "after dragging by" << deltaPastRotatedThreshold << "past scaled threshold" << threshold;
+ QCOMPARE(flickable->isDragging(), false); // Flickable never grabs on the first drag past the threshold
+ QCOMPARE(flickable->keepMouseGrab(), true); // but it plans to do it next time!
QTest::mouseMove(view.data(), QPoint(200 + threshold * 2, 140));
- QTest::mouseMove(view.data(), QPoint(200 + threshold * 3, 140));
- QCOMPARE(flickable->isDragging(), true);
+ QCOMPARE(flickable->isDragging(), true); // it grabs only during the second drag past the threshold
QCOMPARE(flickable->property("itemPressed").toBool(), false);
moveAndRelease(view.data(), QPoint(220, 140));
}
@@ -1714,8 +1896,8 @@ void tst_qquickflickable::flickTwiceUsingTouches()
QScopedPointer<QQuickView> window(new QQuickView);
window->setSource(testFileUrl("longList.qml"));
QTRY_COMPARE(window->status(), QQuickView::Ready);
- QQuickViewTestUtil::centerOnScreen(window.data());
- QQuickViewTestUtil::moveMouseAway(window.data());
+ QQuickViewTestUtils::centerOnScreen(window.data());
+ QQuickViewTestUtils::moveMouseAway(window.data());
window->show();
QVERIFY(window->rootObject() != nullptr);
QVERIFY(QTest::qWaitForWindowActive(window.data()));
@@ -1795,8 +1977,8 @@ void tst_qquickflickable::nestedStopAtBounds()
QQuickView view;
view.setSource(testFileUrl("nestedStopAtBounds.qml"));
QTRY_COMPARE(view.status(), QQuickView::Ready);
- QQuickViewTestUtil::centerOnScreen(&view);
- QQuickViewTestUtil::moveMouseAway(&view);
+ QQuickVisualTestUtils::centerOnScreen(&view);
+ QQuickVisualTestUtils::moveMouseAway(&view);
view.show();
view.requestActivate();
QVERIFY(QTest::qWaitForWindowActive(&view));
@@ -1838,7 +2020,7 @@ void tst_qquickflickable::nestedStopAtBounds()
moveAndPress(&view, position);
if (waitForPressDelay) {
QVERIFY(innerFiltering); // isPressed will never be true if the mouse area isn't enabled.
- QTRY_VERIFY(mouseArea->pressed());
+ QTRY_VERIFY(mouseArea->isPressed());
}
axis += invert ? threshold * 2 : -threshold * 2;
@@ -1949,8 +2131,8 @@ void tst_qquickflickable::stopAtBounds()
QQuickView view;
view.setSource(testFileUrl("stopAtBounds.qml"));
QTRY_COMPARE(view.status(), QQuickView::Ready);
- QQuickViewTestUtil::centerOnScreen(&view);
- QQuickViewTestUtil::moveMouseAway(&view);
+ QQuickVisualTestUtils::centerOnScreen(&view);
+ QQuickVisualTestUtils::moveMouseAway(&view);
view.show();
view.requestActivate();
QVERIFY(QTest::qWaitForWindowActive(&view));
@@ -1998,10 +2180,10 @@ void tst_qquickflickable::stopAtBounds()
else
QCOMPARE(transpose ? flickable->isAtYBeginning() : flickable->isAtXBeginning(), false);
- QCOMPARE(atXBeginningChangedSpy.count(), (!transpose && !invert) ? 1 : 0);
- QCOMPARE(atYBeginningChangedSpy.count(), ( transpose && !invert) ? 1 : 0);
- QCOMPARE(atXEndChangedSpy.count(), (!transpose && invert) ? 1 : 0);
- QCOMPARE(atYEndChangedSpy.count(), ( transpose && invert) ? 1 : 0);
+ QCOMPARE(atXBeginningChangedSpy.size(), (!transpose && !invert) ? 1 : 0);
+ QCOMPARE(atYBeginningChangedSpy.size(), ( transpose && !invert) ? 1 : 0);
+ QCOMPARE(atXEndChangedSpy.size(), (!transpose && invert) ? 1 : 0);
+ QCOMPARE(atYEndChangedSpy.size(), ( transpose && invert) ? 1 : 0);
// Drag away from the aligned boundary again.
// None of the mouse movements will position the view at the boundary exactly,
@@ -2035,7 +2217,7 @@ void tst_qquickflickable::stopAtBounds()
else
flick(&view, QPoint(120,120), QPoint(20,20), 100);
- QVERIFY(flickSignal.count() > 0);
+ QVERIFY(flickSignal.size() > 0);
if (transpose) {
if (invert)
QTRY_COMPARE(flickable->isAtYBeginning(), true);
@@ -2054,8 +2236,8 @@ void tst_qquickflickable::nestedMouseAreaUsingTouch()
QScopedPointer<QQuickView> window(new QQuickView);
window->setSource(testFileUrl("nestedmousearea.qml"));
QTRY_COMPARE(window->status(), QQuickView::Ready);
- QQuickViewTestUtil::centerOnScreen(window.data());
- QQuickViewTestUtil::moveMouseAway(window.data());
+ QQuickViewTestUtils::centerOnScreen(window.data());
+ QQuickViewTestUtils::moveMouseAway(window.data());
window->show();
QVERIFY(window->rootObject() != nullptr);
QVERIFY(QTest::qWaitForWindowActive(window.data()));
@@ -2074,6 +2256,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");
@@ -2100,8 +2303,8 @@ void tst_qquickflickable::nestedSliderUsingTouch()
QScopedPointer<QQuickView> windowPtr(window);
windowPtr->setSource(testFileUrl("nestedSlider.qml"));
QTRY_COMPARE(window->status(), QQuickView::Ready);
- QQuickViewTestUtil::centerOnScreen(window);
- QQuickViewTestUtil::moveMouseAway(window);
+ QQuickVisualTestUtils::centerOnScreen(window);
+ QQuickVisualTestUtils::moveMouseAway(window);
window->show();
QVERIFY(QTest::qWaitForWindowActive(window));
QVERIFY(window->rootObject() != nullptr);
@@ -2124,7 +2327,7 @@ void tst_qquickflickable::nestedSliderUsingTouch()
QTest::touchEvent(window, touchDevice).move(0, p0, window);
QQuickTouchUtils::flush(window);
}
- QCOMPARE(tda->active(), keepMouseGrab | keepTouchGrab);
+ QCOMPARE(tda->active(), keepMouseGrab || keepTouchGrab);
QTest::touchEvent(window, touchDevice).release(0, p0, window);
QQuickTouchUtils::flush(window);
QTRY_COMPARE(tda->touchPointStates.first(), QEventPoint::State::Pressed);
@@ -2139,8 +2342,8 @@ void tst_qquickflickable::pressDelayWithLoader()
QScopedPointer<QQuickView> window(new QQuickView);
window->setSource(testFileUrl("pressDelayWithLoader.qml"));
QTRY_COMPARE(window->status(), QQuickView::Ready);
- QQuickViewTestUtil::centerOnScreen(window.data());
- QQuickViewTestUtil::moveMouseAway(window.data());
+ QQuickViewTestUtils::centerOnScreen(window.data());
+ QQuickViewTestUtils::moveMouseAway(window.data());
window->show();
QVERIFY(QTest::qWaitForWindowActive(window.data()));
QVERIFY(window->rootObject() != nullptr);
@@ -2156,8 +2359,8 @@ void tst_qquickflickable::movementFromProgrammaticFlick()
QScopedPointer<QQuickView> window(new QQuickView);
window->setSource(testFileUrl("movementSignals.qml"));
QTRY_COMPARE(window->status(), QQuickView::Ready);
- QQuickViewTestUtil::centerOnScreen(window.data());
- QQuickViewTestUtil::moveMouseAway(window.data());
+ QQuickViewTestUtils::centerOnScreen(window.data());
+ QQuickViewTestUtils::moveMouseAway(window.data());
window->show();
QVERIFY(QTest::qWaitForWindowActive(window.data()));
@@ -2185,22 +2388,22 @@ void tst_qquickflickable::contentSize()
flickable.setWidth(100);
QCOMPARE(flickable.width(), qreal(100));
QCOMPARE(flickable.contentWidth(), qreal(-1.0));
- QCOMPARE(cwspy.count(), 0);
+ QCOMPARE(cwspy.size(), 0);
flickable.setContentWidth(10);
QCOMPARE(flickable.width(), qreal(100));
QCOMPARE(flickable.contentWidth(), qreal(10));
- QCOMPARE(cwspy.count(), 1);
+ QCOMPARE(cwspy.size(), 1);
flickable.setHeight(100);
QCOMPARE(flickable.height(), qreal(100));
QCOMPARE(flickable.contentHeight(), qreal(-1.0));
- QCOMPARE(chspy.count(), 0);
+ QCOMPARE(chspy.size(), 0);
flickable.setContentHeight(10);
QCOMPARE(flickable.height(), qreal(100));
QCOMPARE(flickable.contentHeight(), qreal(10));
- QCOMPARE(chspy.count(), 1);
+ QCOMPARE(chspy.size(), 1);
}
// QTBUG-53726
@@ -2209,8 +2412,8 @@ void tst_qquickflickable::ratios_smallContent()
QScopedPointer<QQuickView> window(new QQuickView);
window->setSource(testFileUrl("ratios_smallContent.qml"));
QTRY_COMPARE(window->status(), QQuickView::Ready);
- QQuickViewTestUtil::centerOnScreen(window.data());
- QQuickViewTestUtil::moveMouseAway(window.data());
+ QQuickViewTestUtils::centerOnScreen(window.data());
+ QQuickViewTestUtils::moveMouseAway(window.data());
window->setTitle(QTest::currentTestFunction());
window->show();
QVERIFY(QTest::qWaitForWindowExposed(window.data()));
@@ -2235,8 +2438,8 @@ void tst_qquickflickable::contentXYNotTruncatedToInt()
QScopedPointer<QQuickView> window(new QQuickView);
window->setSource(testFileUrl("contentXY.qml"));
QTRY_COMPARE(window->status(), QQuickView::Ready);
- QQuickViewTestUtil::centerOnScreen(window.data());
- QQuickViewTestUtil::moveMouseAway(window.data());
+ QQuickViewTestUtils::centerOnScreen(window.data());
+ QQuickViewTestUtils::moveMouseAway(window.data());
window->show();
QVERIFY(QTest::qWaitForWindowActive(window.data()));
@@ -2255,8 +2458,8 @@ void tst_qquickflickable::keepGrab()
QScopedPointer<QQuickView> window(new QQuickView);
window->setSource(testFileUrl("keepGrab.qml"));
QTRY_COMPARE(window->status(), QQuickView::Ready);
- QQuickViewTestUtil::centerOnScreen(window.data());
- QQuickViewTestUtil::moveMouseAway(window.data());
+ QQuickViewTestUtils::centerOnScreen(window.data());
+ QQuickViewTestUtils::moveMouseAway(window.data());
window->show();
QVERIFY(QTest::qWaitForWindowActive(window.data()));
@@ -2302,6 +2505,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"));
@@ -2311,6 +2515,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);
@@ -2357,7 +2562,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)) {
@@ -2426,7 +2631,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)) {
@@ -2459,29 +2664,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()
@@ -2550,8 +2779,8 @@ void tst_qquickflickable::synchronousDrag()
QQuickView *window = scopedWindow.data();
window->setSource(testFileUrl("longList.qml"));
QTRY_COMPARE(window->status(), QQuickView::Ready);
- QQuickViewTestUtil::centerOnScreen(window);
- QQuickViewTestUtil::moveMouseAway(window);
+ QQuickVisualTestUtils::centerOnScreen(window);
+ QQuickVisualTestUtils::moveMouseAway(window);
window->show();
QVERIFY(window->rootObject() != nullptr);
QVERIFY(QTest::qWaitForWindowActive(window));
@@ -2649,6 +2878,560 @@ void tst_qquickflickable::parallelTouch() // QTBUG-30840
QTRY_VERIFY(!flickable2->isMoving());
}
+void tst_qquickflickable::ignoreNonLeftMouseButtons() // QTBUG-96909
+{
+ QFETCH(Qt::MouseButton, otherButton);
+ const int threshold = qApp->styleHints()->startDragDistance();
+ QQuickView view;
+ view.setSource(testFileUrl("dragon.qml"));
+ view.show();
+ view.requestActivate();
+ QQuickFlickable *flickable = static_cast<QQuickFlickable *>(view.rootObject());
+ QSignalSpy dragSpy(flickable, &QQuickFlickable::draggingChanged);
+
+ // Drag with left button
+ QPoint p1(100, 100);
+ moveAndPress(&view, p1);
+ for (int i = 0; i < 8; ++i) {
+ p1 -= QPoint(threshold, threshold);
+ QTest::mouseMove(&view, p1, 50);
+ }
+ QVERIFY(flickable->isDragging());
+ QCOMPARE(dragSpy.size(), 1);
+
+ // Press other button too, then release left button: dragging changes to false
+ QTest::mousePress(&view, otherButton);
+ QTest::mouseRelease(&view, Qt::LeftButton);
+ QTRY_COMPARE(flickable->isDragging(), false);
+ QCOMPARE(dragSpy.size(), 2);
+
+ // Drag further with the other button held: Flickable ignores it
+ for (int i = 0; i < 8; ++i) {
+ p1 -= QPoint(threshold, threshold);
+ QTest::mouseMove(&view, p1, 50);
+ }
+ QCOMPARE(flickable->isDragging(), false);
+ QCOMPARE(dragSpy.size(), 2);
+
+ // Release other button: nothing happens
+ QTest::mouseRelease(&view, otherButton);
+ QCOMPARE(dragSpy.size(), 2);
+}
+
+void tst_qquickflickable::ignoreNonLeftMouseButtons_data()
+{
+ QTest::addColumn<Qt::MouseButton>("otherButton");
+
+ QTest::newRow("right") << Qt::RightButton;
+ 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.size(), 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.size(), 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::flickAndReleaseOutsideBounds() // QTBUG-104987
+{
+ // Check that flicking works when the mouse release happens
+ // outside the bounds of the flickable (and the flick started on top
+ // of a TapHandler that has a passive grab).
+ QQuickView window;
+ QVERIFY(QQuickTest::showView(window, testFileUrl("flickableWithTapHandler.qml")));
+ QQuickItem *rootItem = window.rootObject();
+ QVERIFY(rootItem);
+ QQuickFlickable *flickable = rootItem->findChild<QQuickFlickable*>();
+ QVERIFY(flickable);
+ QQuickItem *childItem = flickable->findChild<QQuickItem*>("childItem");
+ QVERIFY(childItem);
+
+ QVERIFY(flickable->isAtYBeginning());
+
+ // Startpoint is on top of the tapHandler, while the endpoint is outside the flickable
+ const QPointF startPos = childItem->mapToGlobal(QPoint(10, 10));
+ const QPointF endPos = flickable->mapToGlobal(QPoint(10, -10));
+ const QPoint globalStartPos = window.mapFromGlobal(startPos).toPoint();
+ const QPoint globalEndPos = window.mapFromGlobal(endPos).toPoint();
+ const qreal dragDistance = 20;
+
+ // Note: here we need to initiate a flick using raw events, rather than
+ // flickable.flick(), since we're testing if the mouse events takes the
+ // correct path to starts a flick (among passive and exclusive grabbers, combined
+ // with childMouseEventFilter()).
+ QTest::mousePress(&window, Qt::LeftButton, Qt::NoModifier, globalStartPos);
+ QTest::mouseMove(&window, globalStartPos - QPoint(0, dragDistance / 2));
+ QTest::mouseMove(&window, globalStartPos - QPoint(0, dragDistance));
+ QTest::mouseMove(&window, globalEndPos);
+ QTest::mouseRelease(&window, Qt::LeftButton, Qt::NoModifier, globalEndPos);
+
+ // Ensure that the content item ends up being moved more than what we dragged
+ QTRY_VERIFY(flickable->contentY() > dragDistance * 2);
+}
+
+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());
+}
+
+void tst_qquickflickable::coalescedMove()
+{
+ QQuickView *window = new QQuickView;
+ QScopedPointer<QQuickView> windowPtr(window);
+ windowPtr->setSource(testFileUrl("flickable03.qml"));
+ QTRY_COMPARE(window->status(), QQuickView::Ready);
+ QQuickVisualTestUtils::centerOnScreen(window);
+ QQuickVisualTestUtils::moveMouseAway(window);
+ window->show();
+ QVERIFY(QTest::qWaitForWindowActive(window));
+ QVERIFY(window->rootObject() != nullptr);
+
+ QQuickFlickable *flickable = qobject_cast<QQuickFlickable*>(window->rootObject());
+ QVERIFY(flickable != nullptr);
+
+ QSignalSpy movementStartedSpy(flickable, SIGNAL(movementStarted()));
+ QSignalSpy movementEndedSpy(flickable, SIGNAL(movementEnded()));
+ QSignalSpy flickStartedSpy(flickable, SIGNAL(flickStarted()));
+ QSignalSpy flickEndedSpy(flickable, SIGNAL(flickEnded()));
+
+ QTest::touchEvent(window, touchDevice).press(0, {10, 10}).commit();
+
+ QTest::touchEvent(window, touchDevice).move(0, {10, 40}).commit();
+
+ QTest::touchEvent(window, touchDevice).move(0, {10, 100}).commit();
+
+ QTest::touchEvent(window, touchDevice).release(0, {10, 150}).commit();
+ QQuickTouchUtils::flush(window);
+
+ QTRY_VERIFY(!flickable->isMoving());
+
+ QCOMPARE(movementStartedSpy.size(), 1);
+ QCOMPARE(flickStartedSpy.size(), 1);
+ QCOMPARE(movementEndedSpy.size(), 1);
+ QCOMPARE(flickEndedSpy.size(), 1);
+}
+
+void tst_qquickflickable::onlyOneMove()
+{
+ QQuickView *window = new QQuickView;
+ QScopedPointer<QQuickView> windowPtr(window);
+ windowPtr->setSource(testFileUrl("flickable03.qml"));
+ QTRY_COMPARE(window->status(), QQuickView::Ready);
+ QQuickVisualTestUtils::centerOnScreen(window);
+ QQuickVisualTestUtils::moveMouseAway(window);
+ window->show();
+ QVERIFY(QTest::qWaitForWindowActive(window));
+ QVERIFY(window->rootObject() != nullptr);
+
+ QQuickFlickable *flickable = qobject_cast<QQuickFlickable*>(window->rootObject());
+ QVERIFY(flickable != nullptr);
+
+ QSignalSpy movementStartedSpy(flickable, SIGNAL(movementStarted()));
+ QSignalSpy movementEndedSpy(flickable, SIGNAL(movementEnded()));
+ QSignalSpy flickStartedSpy(flickable, SIGNAL(flickStarted()));
+ QSignalSpy flickEndedSpy(flickable, SIGNAL(flickEnded()));
+
+ QTest::touchEvent(window, touchDevice).press(0, {10, 10}).commit();
+ QQuickTouchUtils::flush(window);
+
+ QTest::touchEvent(window, touchDevice).move(0, {10, 100}).commit();
+ QQuickTouchUtils::flush(window);
+
+ QTest::touchEvent(window, touchDevice).release(0, {10, 200}).commit();
+ QQuickTouchUtils::flush(window);
+
+ QTRY_VERIFY(!flickable->isMoving());
+
+ QCOMPARE(movementStartedSpy.size(), 1);
+ QCOMPARE(flickStartedSpy.size(), 1);
+ QCOMPARE(movementEndedSpy.size(), 1);
+ QCOMPARE(flickEndedSpy.size(), 1);
+}
+
+void tst_qquickflickable::proportionalWheelScrolling() // QTBUG-106338 etc.
+{
+ QQuickView window;
+ QVERIFY(QQuickTest::showView(window, testFileUrl("wheel.qml")));
+ QQuickViewTestUtils::centerOnScreen(&window);
+ QVERIFY(window.isVisible());
+ QQuickItem *rootItem = window.rootObject();
+ QVERIFY(rootItem);
+ QQuickFlickable *flickable = rootItem->findChild<QQuickFlickable *>();
+ QVERIFY(flickable);
+
+ QVERIFY(!flickable->property("ended").value<bool>());
+
+ QPointF pos(flickable->x() + flickable->width() / 2, flickable->y() + flickable->height() / 2);
+ QPoint angleDelta(0, -120);
+ QWheelEvent wheelEvent(pos, window.mapToGlobal(pos), QPoint(), angleDelta,
+ Qt::NoButton, Qt::NoModifier, Qt::NoScrollPhase, false);
+
+ QGuiApplication::sendEvent(&window, &wheelEvent);
+ qApp->processEvents();
+
+ // Verify that scrolling is proportional to the wheel delta
+ QVERIFY(flickable->isMovingVertically());
+ QTRY_VERIFY(!flickable->isMovingVertically());
+
+ // The current movement formula being used is: delta / 120 * wheelScrollLines * 24
+ const int defaultWheelDecel = 15000;
+ bool wheelDecelerationEnvSet = false;
+ const int wheelDecelerationEnv = qEnvironmentVariableIntValue("QT_QUICK_FLICKABLE_WHEEL_DECELERATION", &wheelDecelerationEnvSet);
+ const qreal wheelDecel = wheelDecelerationEnvSet ? wheelDecelerationEnv : defaultWheelDecel;
+ const bool proportionalWheel = wheelDecel >= 15000;
+ qCDebug(lcTests) << "platform wheel decel" << defaultWheelDecel
+ << "env wheel decel" << wheelDecelerationEnv
+ << "expect proportional scrolling?" << proportionalWheel;
+ const qreal expectedMovementFromWheelClick = qAbs(angleDelta.y()) / 120 * qApp->styleHints()->wheelScrollLines() * 24;
+
+ if (proportionalWheel)
+ QCOMPARE(flickable->contentY(), expectedMovementFromWheelClick);
+
+ QVERIFY(flickable->property("ended").value<bool>());
+ QCOMPARE(flickable->property("movementsAfterEnd").value<int>(), 0);
+
+ flickable->setProperty("ended", QVariant::fromValue(false));
+ flickable->setContentY(0);
+
+ // Verify that multiple wheel events in a row won't accumulate the scroll distance, before the timeline completes
+ wheelEvent.setTimestamp(wheelEvent.timestamp() + 2000);
+ QGuiApplication::sendEvent(&window, &wheelEvent);
+
+ wheelEvent.setTimestamp(wheelEvent.timestamp() + 10);
+ QGuiApplication::sendEvent(&window, &wheelEvent);
+
+ wheelEvent.setTimestamp(wheelEvent.timestamp() + 10);
+ QGuiApplication::sendEvent(&window, &wheelEvent);
+
+ qApp->processEvents();
+
+ QVERIFY(flickable->isMovingVertically());
+ QTRY_VERIFY(!flickable->isMovingVertically());
+
+ if (proportionalWheel) {
+ QVERIFY2(flickable->contentY() >= expectedMovementFromWheelClick, "The contentItem moved shorter than expected from a wheelEvent");
+ QCOMPARE_LT(flickable->contentY(), expectedMovementFromWheelClick * 3);
+ }
+
+ QVERIFY(flickable->property("ended").value<bool>());
+ QCOMPARE(flickable->property("movementsAfterEnd").value<int>(), 0);
+}
+
+void tst_qquickflickable::touchCancel()
+{
+ QQuickView window;
+ QVERIFY(QQuickTest::showView(window, testFileUrl("flickable03.qml")));
+ QQuickViewTestUtils::centerOnScreen(&window);
+ QVERIFY(window.isVisible());
+
+ QQuickFlickable *flickable = qobject_cast<QQuickFlickable*>(window.rootObject());
+ QVERIFY(flickable != nullptr);
+
+ QSignalSpy movementStartedSpy(flickable, SIGNAL(movementStarted()));
+ QSignalSpy movementEndedSpy(flickable, SIGNAL(movementEnded()));
+
+ int touchPosY = 10;
+ QTest::touchEvent(&window, touchDevice).press(0, {10, touchPosY}).commit();
+ QQuickTouchUtils::flush(&window);
+
+ for (int i = 0; i < 3; ++i) {
+ touchPosY += qApp->styleHints()->startDragDistance();
+ QTest::touchEvent(&window, touchDevice).move(0, {10, touchPosY}).commit();
+ QQuickTouchUtils::flush(&window);
+ }
+
+ QTRY_COMPARE(movementStartedSpy.size(), 1);
+ QWindowSystemInterface::handleTouchCancelEvent(nullptr, touchDevice);
+ QTRY_COMPARE(movementEndedSpy.size(), 1);
+}
+
+void tst_qquickflickable::pixelAlignedEndPoints()
+{
+ QQuickView window;
+ QVERIFY(QQuickTest::showView(window, testFileUrl("endpoints.qml")));
+ QQuickViewTestUtils::centerOnScreen(&window);
+ QVERIFY(window.isVisible());
+ QQuickItem *rootItem = window.rootObject();
+ QVERIFY(rootItem);
+ QQuickFlickable *flickable = qobject_cast<QQuickFlickable*>(rootItem);
+ QVERIFY(flickable);
+ flickable->setPixelAligned(true);
+ QVERIFY(flickable->isAtYBeginning());
+
+ QSignalSpy isAtEndSpy(flickable, &QQuickFlickable::atYEndChanged);
+ QSignalSpy isAtBeginningSpy(flickable, &QQuickFlickable::atYBeginningChanged);
+
+ flickable->setContentY(199.99);
+ QCOMPARE(flickable->contentY(), 200);
+ QVERIFY(!flickable->isAtYBeginning());
+ QVERIFY(flickable->isAtYEnd());
+ QCOMPARE(isAtEndSpy.count(), 1);
+ QCOMPARE(isAtBeginningSpy.count(), 1);
+
+ flickable->setContentY(0.01);
+ QCOMPARE(flickable->contentY(), 0);
+ QVERIFY(flickable->isAtYBeginning());
+ QVERIFY(!flickable->isAtYEnd());
+ QCOMPARE(isAtEndSpy.count(), 2);
+ QCOMPARE(isAtBeginningSpy.count(), 2);}
+
QTEST_MAIN(tst_qquickflickable)
#include "tst_qquickflickable.moc"