| /**************************************************************************** |
| ** |
| ** Copyright (C) 2016 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> |
| #include <QtTest/QSignalSpy> |
| #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 <math.h> |
| #include "../../shared/util.h" |
| #include "../shared/geometrytestutil.h" |
| #include "../shared/viewtestutil.h" |
| #include "../shared/visualtestutil.h" |
| |
| #include <qpa/qwindowsysteminterface.h> |
| |
| using namespace QQuickViewTestUtil; |
| using namespace QQuickVisualTestUtil; |
| |
| // an abstract Slider which only handles touch events |
| class TouchDragArea : public QQuickItem |
| { |
| Q_OBJECT |
| Q_PROPERTY(QPointF pos READ pos NOTIFY posChanged) |
| Q_PROPERTY(bool active READ active NOTIFY activeChanged) |
| Q_PROPERTY(bool keepMouseGrab READ keepMouseGrab WRITE setKeepMouseGrab NOTIFY keepMouseGrabChanged) |
| Q_PROPERTY(bool keepTouchGrab READ keepTouchGrab WRITE setKeepTouchGrab NOTIFY keepTouchGrabChanged) |
| |
| public: |
| TouchDragArea(QQuickItem *parent = nullptr) |
| : QQuickItem(parent) |
| , touchEvents(0) |
| , touchUpdates(0) |
| , touchReleases(0) |
| , ungrabs(0) |
| , m_active(false) |
| { |
| #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) |
| setAcceptTouchEvents(true); |
| #else |
| setAcceptedMouseButtons(Qt::LeftButton); // not really, but we want touch events |
| #endif |
| } |
| |
| QPointF pos() const { return m_pos; } |
| |
| bool active() const { return m_active; } |
| |
| void setKeepMouseGrab(bool keepMouseGrab) |
| { |
| QQuickItem::setKeepMouseGrab(keepMouseGrab); |
| emit keepMouseGrabChanged(); |
| } |
| |
| void setKeepTouchGrab(bool keepTouchGrab) |
| { |
| QQuickItem::setKeepTouchGrab(keepTouchGrab); |
| emit keepTouchGrabChanged(); |
| } |
| |
| int touchEvents; |
| int touchUpdates; |
| int touchReleases; |
| int ungrabs; |
| QVector<Qt::TouchPointState> touchPointStates; |
| |
| protected: |
| void touchEvent(QTouchEvent *ev) override |
| { |
| QCOMPARE(ev->touchPoints().count(), 1); |
| auto touchpoint = ev->touchPoints().first(); |
| switch (touchpoint.state()) { |
| case Qt::TouchPointPressed: |
| QVERIFY(!m_active); |
| m_active = true; |
| emit activeChanged(); |
| grabTouchPoints(QVector<int>() << touchpoint.id()); |
| break; |
| case Qt::TouchPointMoved: |
| ++touchUpdates; |
| break; |
| case Qt::TouchPointReleased: |
| QVERIFY(m_active); |
| m_active = false; |
| ++touchReleases; |
| emit activeChanged(); |
| case Qt::TouchPointStationary: |
| break; |
| } |
| touchPointStates << touchpoint.state(); |
| ++touchEvents; |
| m_pos = touchpoint.pos(); |
| emit posChanged(); |
| } |
| |
| void touchUngrabEvent() override |
| { |
| ++ungrabs; |
| QVERIFY(m_active); |
| emit ungrabbed(); |
| m_active = false; |
| emit activeChanged(); |
| } |
| |
| signals: |
| void ungrabbed(); |
| void posChanged(); |
| void keepMouseGrabChanged(); |
| void keepTouchGrabChanged(); |
| void activeChanged(); |
| |
| private: |
| QPointF m_pos; |
| bool m_active; |
| }; |
| |
| class tst_qquickflickable : public QQmlDataTest |
| { |
| Q_OBJECT |
| public: |
| tst_qquickflickable() |
| : touchDevice(QTest::createTouchDevice()) |
| {} |
| |
| private slots: |
| void initTestCase() override; |
| void create(); |
| void horizontalViewportSize(); |
| void verticalViewportSize(); |
| void visibleAreaRatiosUpdate(); |
| void properties(); |
| void boundsBehavior(); |
| void rebound(); |
| void maximumFlickVelocity(); |
| void flickDeceleration(); |
| void pressDelay(); |
| void nestedPressDelay(); |
| void filterReplayedPress(); |
| void nestedClickThenFlick(); |
| void flickableDirection(); |
| void resizeContent(); |
| void returnToBounds(); |
| void returnToBounds_data(); |
| void wheel(); |
| void trackpad(); |
| void movingAndFlicking(); |
| void movingAndFlicking_data(); |
| void movingAndDragging(); |
| void movingAndDragging_data(); |
| void flickOnRelease(); |
| void pressWhileFlicking(); |
| void disabled(); |
| void flickVelocity(); |
| void margins(); |
| void cancelOnHide(); |
| void cancelOnMouseGrab(); |
| void clickAndDragWhenTransformed(); |
| void flickTwiceUsingTouches(); |
| void nestedStopAtBounds(); |
| void nestedStopAtBounds_data(); |
| void stopAtBounds(); |
| void stopAtBounds_data(); |
| void nestedMouseAreaUsingTouch(); |
| void nestedSliderUsingTouch(); |
| void nestedSliderUsingTouch_data(); |
| void pressDelayWithLoader(); |
| void movementFromProgrammaticFlick(); |
| void cleanup(); |
| void contentSize(); |
| void ratios_smallContent(); |
| void contentXYNotTruncatedToInt(); |
| void keepGrab(); |
| void overshoot(); |
| void overshoot_data(); |
| void overshoot_reentrant(); |
| void synchronousDrag_data(); |
| void synchronousDrag(); |
| void visibleAreaBinding(); |
| |
| private: |
| void flickWithTouch(QQuickWindow *window, const QPoint &from, const QPoint &to); |
| QTouchDevice *touchDevice; |
| }; |
| |
| void tst_qquickflickable::initTestCase() |
| { |
| QQmlDataTest::initTestCase(); |
| qmlRegisterType<TouchDragArea>("Test",1,0,"TouchDragArea"); |
| } |
| |
| void tst_qquickflickable::cleanup() |
| { |
| QVERIFY(QGuiApplication::topLevelWindows().isEmpty()); |
| } |
| |
| void tst_qquickflickable::create() |
| { |
| QQmlEngine engine; |
| QQmlComponent c(&engine, testFileUrl("flickable01.qml")); |
| QQuickFlickable *obj = qobject_cast<QQuickFlickable*>(c.createWithInitialProperties({{"setRebound", false}})); |
| |
| QVERIFY(obj != nullptr); |
| QCOMPARE(obj->isAtXBeginning(), true); |
| QCOMPARE(obj->isAtXEnd(), false); |
| QCOMPARE(obj->isAtYBeginning(), true); |
| QCOMPARE(obj->isAtYEnd(), false); |
| QCOMPARE(obj->contentX(), 0.); |
| QCOMPARE(obj->contentY(), 0.); |
| |
| QCOMPARE(obj->horizontalVelocity(), 0.); |
| QCOMPARE(obj->verticalVelocity(), 0.); |
| |
| QCOMPARE(obj->isInteractive(), true); |
| QCOMPARE(obj->boundsBehavior(), QQuickFlickable::DragAndOvershootBounds); |
| QCOMPARE(obj->pressDelay(), 0); |
| QCOMPARE(obj->maximumFlickVelocity(), 2500.); |
| |
| delete obj; |
| } |
| |
| void tst_qquickflickable::horizontalViewportSize() |
| { |
| QQmlEngine engine; |
| QQmlComponent c(&engine, testFileUrl("flickable02.qml")); |
| QQuickFlickable *obj = qobject_cast<QQuickFlickable*>(c.create()); |
| |
| QVERIFY(obj != nullptr); |
| QCOMPARE(obj->contentWidth(), 800.); |
| QCOMPARE(obj->contentHeight(), 300.); |
| QCOMPARE(obj->isAtXBeginning(), true); |
| QCOMPARE(obj->isAtXEnd(), false); |
| QCOMPARE(obj->isAtYBeginning(), true); |
| QCOMPARE(obj->isAtYEnd(), false); |
| |
| delete obj; |
| } |
| |
| void tst_qquickflickable::verticalViewportSize() |
| { |
| QQmlEngine engine; |
| QQmlComponent c(&engine, testFileUrl("flickable03.qml")); |
| QQuickFlickable *obj = qobject_cast<QQuickFlickable*>(c.create()); |
| |
| QVERIFY(obj != nullptr); |
| QCOMPARE(obj->contentWidth(), 200.); |
| QCOMPARE(obj->contentHeight(), 6000.); |
| QCOMPARE(obj->isAtXBeginning(), true); |
| QCOMPARE(obj->isAtXEnd(), false); |
| QCOMPARE(obj->isAtYBeginning(), true); |
| QCOMPARE(obj->isAtYEnd(), false); |
| |
| delete obj; |
| } |
| |
| void tst_qquickflickable::visibleAreaRatiosUpdate() |
| { |
| QQmlEngine engine; |
| QQmlComponent c(&engine, testFileUrl("ratios.qml")); |
| QQuickItem *obj = qobject_cast<QQuickItem*>(c.create()); |
| |
| QVERIFY(obj != nullptr); |
| // check initial ratio values |
| QCOMPARE(obj->property("heightRatioIs").toDouble(), obj->property("heightRatioShould").toDouble()); |
| QCOMPARE(obj->property("widthRatioIs").toDouble(), obj->property("widthRatioShould").toDouble()); |
| // change flickable geometry so that flicking is enabled (content size > flickable size) |
| obj->setProperty("forceNoFlicking", false); |
| QCOMPARE(obj->property("heightRatioIs").toDouble(), obj->property("heightRatioShould").toDouble()); |
| QCOMPARE(obj->property("widthRatioIs").toDouble(), obj->property("widthRatioShould").toDouble()); |
| // change flickable geometry so that flicking is disabled (content size == flickable size) |
| obj->setProperty("forceNoFlicking", true); |
| QCOMPARE(obj->property("heightRatioIs").toDouble(), obj->property("heightRatioShould").toDouble()); |
| QCOMPARE(obj->property("widthRatioIs").toDouble(), obj->property("widthRatioShould").toDouble()); |
| |
| delete obj; |
| } |
| |
| void tst_qquickflickable::properties() |
| { |
| QQmlEngine engine; |
| QQmlComponent c(&engine, testFileUrl("flickable04.qml")); |
| QQuickFlickable *obj = qobject_cast<QQuickFlickable*>(c.create()); |
| |
| QVERIFY(obj != nullptr); |
| QCOMPARE(obj->isInteractive(), false); |
| QCOMPARE(obj->boundsBehavior(), QQuickFlickable::StopAtBounds); |
| QCOMPARE(obj->pressDelay(), 200); |
| QCOMPARE(obj->maximumFlickVelocity(), 2000.); |
| |
| QVERIFY(!obj->property("ok").toBool()); |
| QMetaObject::invokeMethod(obj, "check"); |
| QVERIFY(obj->property("ok").toBool()); |
| |
| delete obj; |
| } |
| |
| void tst_qquickflickable::boundsBehavior() |
| { |
| QQmlEngine engine; |
| QQmlComponent component(&engine); |
| component.setData("import QtQuick 2.0; Flickable { boundsBehavior: Flickable.StopAtBounds }", QUrl::fromLocalFile("")); |
| QQuickFlickable *flickable = qobject_cast<QQuickFlickable*>(component.create()); |
| QSignalSpy spy(flickable, SIGNAL(boundsBehaviorChanged())); |
| |
| QVERIFY(flickable); |
| QCOMPARE(flickable->boundsBehavior(), QQuickFlickable::StopAtBounds); |
| |
| flickable->setBoundsBehavior(QQuickFlickable::DragAndOvershootBounds); |
| QCOMPARE(flickable->boundsBehavior(), QQuickFlickable::DragAndOvershootBounds); |
| QCOMPARE(spy.count(),1); |
| flickable->setBoundsBehavior(QQuickFlickable::DragAndOvershootBounds); |
| QCOMPARE(spy.count(),1); |
| |
| flickable->setBoundsBehavior(QQuickFlickable::DragOverBounds); |
| QCOMPARE(flickable->boundsBehavior(), QQuickFlickable::DragOverBounds); |
| QCOMPARE(spy.count(),2); |
| flickable->setBoundsBehavior(QQuickFlickable::DragOverBounds); |
| QCOMPARE(spy.count(),2); |
| |
| flickable->setBoundsBehavior(QQuickFlickable::StopAtBounds); |
| QCOMPARE(flickable->boundsBehavior(), QQuickFlickable::StopAtBounds); |
| QCOMPARE(spy.count(),3); |
| flickable->setBoundsBehavior(QQuickFlickable::StopAtBounds); |
| QCOMPARE(spy.count(),3); |
| |
| flickable->setBoundsBehavior(QQuickFlickable::OvershootBounds); |
| QCOMPARE(flickable->boundsBehavior(), QQuickFlickable::OvershootBounds); |
| QCOMPARE(spy.count(),4); |
| flickable->setBoundsBehavior(QQuickFlickable::OvershootBounds); |
| QCOMPARE(spy.count(),4); |
| |
| delete flickable; |
| } |
| |
| 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()); |
| |
| window->show(); |
| QVERIFY(QTest::qWaitForWindowActive(window.data())); |
| QVERIFY(window->rootObject() != nullptr); |
| |
| QQuickFlickable *flickable = qobject_cast<QQuickFlickable*>(window->rootObject()); |
| QVERIFY(flickable != nullptr); |
| |
| QQuickTransition *rebound = window->rootObject()->findChild<QQuickTransition*>("rebound"); |
| QVERIFY(rebound); |
| QSignalSpy reboundSpy(rebound, SIGNAL(runningChanged())); |
| |
| QSignalSpy movementStartedSpy(flickable, SIGNAL(movementStarted())); |
| QSignalSpy movementEndedSpy(flickable, SIGNAL(movementEnded())); |
| QSignalSpy vMoveSpy(flickable, SIGNAL(movingVerticallyChanged())); |
| QSignalSpy hMoveSpy(flickable, SIGNAL(movingHorizontallyChanged())); |
| |
| // flick and test the transition is run |
| 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); |
| 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(window->rootObject()->property("transitionsStarted").toInt(), 2); |
| QVERIFY(!rebound->running()); |
| QCOMPARE(reboundSpy.count(), 2); |
| |
| hMoveSpy.clear(); |
| vMoveSpy.clear(); |
| movementStartedSpy.clear(); |
| movementEndedSpy.clear(); |
| window->rootObject()->setProperty("transitionsStarted", 0); |
| window->rootObject()->setProperty("transitionsFinished", 0); |
| |
| // flick and trigger the transition multiple times |
| // (moving signals are emitted as soon as the first transition starts) |
| flick(window.data(), QPoint(20,20), QPoint(120,120), 50); // both x and y will bounce back |
| flick(window.data(), QPoint(20,120), QPoint(120,20), 50); // only x will bounce back |
| |
| QVERIFY(flickable->isMoving()); |
| QTRY_VERIFY(window->rootObject()->property("transitionsStarted").toInt() >= 1); |
| QCOMPARE(hMoveSpy.count(), 1); |
| QCOMPARE(vMoveSpy.count(), 1); |
| QCOMPARE(movementStartedSpy.count(), 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); |
| |
| hMoveSpy.clear(); |
| vMoveSpy.clear(); |
| movementStartedSpy.clear(); |
| movementEndedSpy.clear(); |
| window->rootObject()->setProperty("transitionsStarted", 0); |
| window->rootObject()->setProperty("transitionsFinished", 0); |
| |
| // disable and the default transition should run |
| // (i.e. moving but transition->running = false) |
| window->rootObject()->setProperty("transitionEnabled", false); |
| |
| 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); |
| |
| QTRY_VERIFY(!flickable->isMoving()); |
| QCOMPARE(hMoveSpy.count(), 2); |
| QCOMPARE(vMoveSpy.count(), 2); |
| QCOMPARE(movementStartedSpy.count(), 1); |
| QCOMPARE(movementEndedSpy.count(), 1); |
| QCOMPARE(window->rootObject()->property("transitionsStarted").toInt(), 0); |
| } |
| |
| void tst_qquickflickable::maximumFlickVelocity() |
| { |
| QQmlEngine engine; |
| QQmlComponent component(&engine); |
| component.setData("import QtQuick 2.0; Flickable { maximumFlickVelocity: 1.0; }", QUrl::fromLocalFile("")); |
| QQuickFlickable *flickable = qobject_cast<QQuickFlickable*>(component.create()); |
| QSignalSpy spy(flickable, SIGNAL(maximumFlickVelocityChanged())); |
| |
| QVERIFY(flickable); |
| QCOMPARE(flickable->maximumFlickVelocity(), 1.0); |
| |
| flickable->setMaximumFlickVelocity(2.0); |
| QCOMPARE(flickable->maximumFlickVelocity(), 2.0); |
| QCOMPARE(spy.count(),1); |
| flickable->setMaximumFlickVelocity(2.0); |
| QCOMPARE(spy.count(),1); |
| |
| delete flickable; |
| } |
| |
| void tst_qquickflickable::flickDeceleration() |
| { |
| QQmlEngine engine; |
| QQmlComponent component(&engine); |
| component.setData("import QtQuick 2.0; Flickable { flickDeceleration: 1.0; }", QUrl::fromLocalFile("")); |
| QQuickFlickable *flickable = qobject_cast<QQuickFlickable*>(component.create()); |
| QSignalSpy spy(flickable, SIGNAL(flickDecelerationChanged())); |
| |
| QVERIFY(flickable); |
| QCOMPARE(flickable->flickDeceleration(), 1.0); |
| |
| flickable->setFlickDeceleration(2.0); |
| QCOMPARE(flickable->flickDeceleration(), 2.0); |
| QCOMPARE(spy.count(),1); |
| flickable->setFlickDeceleration(2.0); |
| QCOMPARE(spy.count(),1); |
| |
| delete flickable; |
| } |
| |
| 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); |
| |
| QQuickFlickable *flickable = qobject_cast<QQuickFlickable*>(window->rootObject()); |
| QSignalSpy spy(flickable, SIGNAL(pressDelayChanged())); |
| |
| QVERIFY(flickable); |
| QCOMPARE(flickable->pressDelay(), 100); |
| |
| flickable->setPressDelay(200); |
| QCOMPARE(flickable->pressDelay(), 200); |
| QCOMPARE(spy.count(),1); |
| flickable->setPressDelay(200); |
| QCOMPARE(spy.count(),1); |
| |
| QQuickItem *mouseArea = window->rootObject()->findChild<QQuickItem*>("mouseArea"); |
| QSignalSpy clickedSpy(mouseArea, SIGNAL(clicked(QQuickMouseEvent*))); |
| |
| moveAndPress(window.data(), QPoint(150, 150)); |
| |
| // The press should not occur immediately |
| QVERIFY(!mouseArea->property("pressed").toBool()); |
| |
| // But, it should occur eventually |
| QTRY_VERIFY(mouseArea->property("pressed").toBool()); |
| |
| QCOMPARE(clickedSpy.count(),0); |
| |
| // On release the clicked signal should be emitted |
| QTest::mouseRelease(window.data(), Qt::LeftButton, Qt::NoModifier, QPoint(150, 150)); |
| QCOMPARE(clickedSpy.count(),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()); |
| |
| |
| // Test a quick tap within the pressDelay timeout |
| clickedSpy.clear(); |
| moveAndPress(window.data(), QPoint(180, 180)); |
| |
| // The press should not occur immediately |
| QVERIFY(!mouseArea->property("pressed").toBool()); |
| |
| 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); |
| |
| // 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)); |
| |
| // The press should not occur immediately |
| QVERIFY(!mouseArea->property("pressed").toBool()); |
| |
| QTest::mouseMove(window.data(), QPoint(150, 190)); |
| |
| // 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); |
| } |
| |
| // QTBUG-17361 |
| 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()); |
| window->show(); |
| QVERIFY(QTest::qWaitForWindowActive(window.data())); |
| QVERIFY(window->rootObject() != nullptr); |
| |
| QQuickFlickable *outer = qobject_cast<QQuickFlickable*>(window->rootObject()); |
| QVERIFY(outer != nullptr); |
| |
| QQuickFlickable *inner = window->rootObject()->findChild<QQuickFlickable*>("innerFlickable"); |
| QVERIFY(inner != nullptr); |
| |
| moveAndPress(window.data(), QPoint(150, 150)); |
| // the MouseArea is not pressed immediately |
| QVERIFY(!outer->property("pressed").toBool()); |
| QVERIFY(!inner->property("pressed").toBool()); |
| |
| // The inner pressDelay will prevail (50ms, vs. 10sec) |
| // QTRY_VERIFY() has 5sec timeout, so will timeout well within 10sec. |
| QTRY_VERIFY(outer->property("pressed").toBool()); |
| |
| QTest::mouseMove(window.data(), QPoint(130, 150)); |
| QTest::mouseMove(window.data(), QPoint(110, 150)); |
| QTest::mouseMove(window.data(), QPoint(90, 150)); |
| |
| QVERIFY(!outer->property("moving").toBool()); |
| QVERIFY(!outer->property("dragging").toBool()); |
| QVERIFY(inner->property("moving").toBool()); |
| QVERIFY(inner->property("dragging").toBool()); |
| |
| QTest::mouseRelease(window.data(), Qt::LeftButton, Qt::NoModifier, QPoint(150, 150)); |
| |
| QVERIFY(!inner->property("dragging").toBool()); |
| QTRY_VERIFY(!inner->property("moving").toBool()); |
| |
| // Dragging inner Flickable should work |
| moveAndPress(window.data(), QPoint(80, 150)); |
| // the MouseArea is not pressed immediately |
| QVERIFY(!outer->property("pressed").toBool()); |
| QVERIFY(!inner->property("pressed").toBool()); |
| |
| QTest::mouseMove(window.data(), QPoint(60, 150)); |
| QTest::mouseMove(window.data(), QPoint(40, 150)); |
| QTest::mouseMove(window.data(), QPoint(20, 150)); |
| |
| QVERIFY(inner->property("moving").toBool()); |
| QVERIFY(inner->property("dragging").toBool()); |
| QVERIFY(!outer->property("moving").toBool()); |
| QVERIFY(!outer->property("dragging").toBool()); |
| |
| QTest::mouseRelease(window.data(), Qt::LeftButton, Qt::NoModifier, QPoint(20, 150)); |
| |
| QVERIFY(!inner->property("dragging").toBool()); |
| QTRY_VERIFY(!inner->property("moving").toBool()); |
| |
| // Dragging the MouseArea in the inner Flickable should move the inner Flickable |
| moveAndPress(window.data(), QPoint(150, 150)); |
| // the MouseArea is not pressed immediately |
| QVERIFY(!outer->property("pressed").toBool()); |
| |
| QTest::mouseMove(window.data(), QPoint(130, 150)); |
| QTest::mouseMove(window.data(), QPoint(110, 150)); |
| QTest::mouseMove(window.data(), QPoint(90, 150)); |
| |
| QVERIFY(!outer->property("moving").toBool()); |
| QVERIFY(!outer->property("dragging").toBool()); |
| QVERIFY(inner->property("moving").toBool()); |
| QVERIFY(inner->property("dragging").toBool()); |
| |
| QTest::mouseRelease(window.data(), Qt::LeftButton, Qt::NoModifier, QPoint(90, 150)); |
| |
| QVERIFY(!inner->property("dragging").toBool()); |
| QTRY_VERIFY(!inner->property("moving").toBool()); |
| } |
| |
| 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()); |
| window->show(); |
| QVERIFY(QTest::qWaitForWindowActive(window.data())); |
| QVERIFY(window->rootObject() != nullptr); |
| |
| QQuickFlickable *outer = qobject_cast<QQuickFlickable*>(window->rootObject()); |
| QVERIFY(outer != nullptr); |
| |
| QQuickFlickable *inner = window->rootObject()->findChild<QQuickFlickable*>("innerFlickable"); |
| QVERIFY(inner != nullptr); |
| |
| QQuickItem *filteringMouseArea = outer->findChild<QQuickItem *>("filteringMouseArea"); |
| QVERIFY(filteringMouseArea); |
| |
| moveAndPress(window.data(), QPoint(150, 150)); |
| // the MouseArea filtering the Flickable is pressed immediately. |
| QCOMPARE(filteringMouseArea->property("pressed").toBool(), true); |
| |
| // Some event causes the mouse area to set keepMouseGrab. |
| filteringMouseArea->setKeepMouseGrab(true); |
| QCOMPARE(filteringMouseArea->keepMouseGrab(), true); |
| |
| // The inner pressDelay will prevail (50ms, vs. 10sec) |
| // QTRY_VERIFY() has 5sec timeout, so will timeout well within 10sec. |
| QTRY_VERIFY(outer->property("pressed").toBool()); |
| |
| // The replayed press event isn't delivered to parent items of the |
| // flickable with the press delay, and the state of the parent mouse |
| // area is therefore unaffected. |
| QCOMPARE(filteringMouseArea->property("pressed").toBool(), true); |
| QCOMPARE(filteringMouseArea->keepMouseGrab(), true); |
| |
| QTest::mouseRelease(window.data(), Qt::LeftButton, Qt::NoModifier, QPoint(150, 150)); |
| } |
| |
| |
| // QTBUG-37316 |
| 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()); |
| window->show(); |
| QVERIFY(QTest::qWaitForWindowActive(window.data())); |
| QVERIFY(window->rootObject() != nullptr); |
| |
| QQuickFlickable *outer = qobject_cast<QQuickFlickable*>(window->rootObject()); |
| QVERIFY(outer != nullptr); |
| |
| QQuickFlickable *inner = window->rootObject()->findChild<QQuickFlickable*>("innerFlickable"); |
| QVERIFY(inner != nullptr); |
| |
| moveAndPress(window.data(), QPoint(150, 150)); |
| |
| // the MouseArea is not pressed immediately |
| QVERIFY(!outer->property("pressed").toBool()); |
| QTRY_VERIFY(outer->property("pressed").toBool()); |
| |
| QTest::mouseRelease(window.data(), Qt::LeftButton, Qt::NoModifier, QPoint(150, 150)); |
| |
| QVERIFY(!outer->property("pressed").toBool()); |
| |
| // Dragging inner Flickable should work |
| moveAndPress(window.data(), QPoint(80, 150)); |
| // the MouseArea is not pressed immediately |
| |
| QVERIFY(!outer->property("pressed").toBool()); |
| |
| QTest::mouseMove(window.data(), QPoint(80, 148)); |
| QTest::mouseMove(window.data(), QPoint(80, 140)); |
| QTest::mouseMove(window.data(), QPoint(80, 120)); |
| QTest::mouseMove(window.data(), QPoint(80, 100)); |
| |
| QVERIFY(!outer->property("moving").toBool()); |
| QVERIFY(inner->property("moving").toBool()); |
| |
| QTest::mouseRelease(window.data(), Qt::LeftButton, Qt::NoModifier, QPoint(80, 100)); |
| } |
| |
| void tst_qquickflickable::flickableDirection() |
| { |
| QQmlEngine engine; |
| QQmlComponent component(&engine); |
| component.setData("import QtQuick 2.0; Flickable { flickableDirection: Flickable.VerticalFlick; }", QUrl::fromLocalFile("")); |
| QQuickFlickable *flickable = qobject_cast<QQuickFlickable*>(component.create()); |
| QSignalSpy spy(flickable, SIGNAL(flickableDirectionChanged())); |
| |
| QVERIFY(flickable); |
| QCOMPARE(flickable->flickableDirection(), QQuickFlickable::VerticalFlick); |
| |
| flickable->setFlickableDirection(QQuickFlickable::HorizontalAndVerticalFlick); |
| QCOMPARE(flickable->flickableDirection(), QQuickFlickable::HorizontalAndVerticalFlick); |
| QCOMPARE(spy.count(),1); |
| |
| flickable->setFlickableDirection(QQuickFlickable::AutoFlickDirection); |
| QCOMPARE(flickable->flickableDirection(), QQuickFlickable::AutoFlickDirection); |
| QCOMPARE(spy.count(),2); |
| |
| flickable->setFlickableDirection(QQuickFlickable::HorizontalFlick); |
| QCOMPARE(flickable->flickableDirection(), QQuickFlickable::HorizontalFlick); |
| QCOMPARE(spy.count(),3); |
| |
| flickable->setFlickableDirection(QQuickFlickable::HorizontalFlick); |
| QCOMPARE(flickable->flickableDirection(), QQuickFlickable::HorizontalFlick); |
| QCOMPARE(spy.count(),3); |
| |
| delete flickable; |
| } |
| |
| // QtQuick 1.1 |
| void tst_qquickflickable::resizeContent() |
| { |
| QQmlEngine engine; |
| QQmlComponent c(&engine, testFileUrl("resize.qml")); |
| QQuickItem *root = qobject_cast<QQuickItem*>(c.createWithInitialProperties({{"setRebound", false}})); |
| QQuickFlickable *obj = findItem<QQuickFlickable>(root, "flick"); |
| |
| QVERIFY(obj != nullptr); |
| QCOMPARE(obj->contentX(), 0.); |
| QCOMPARE(obj->contentY(), 0.); |
| QCOMPARE(obj->contentWidth(), 300.); |
| QCOMPARE(obj->contentHeight(), 300.); |
| |
| QQuickFlickablePrivate *fp = QQuickFlickablePrivate::get(obj); |
| QSizeChangeListener sizeListener(fp->contentItem); |
| |
| QMetaObject::invokeMethod(root, "resizeContent"); |
| for (const QSize sizeOnGeometryChanged : sizeListener) { |
| // Check that we have the correct size on all signals |
| QCOMPARE(sizeOnGeometryChanged, QSize(600, 600)); |
| } |
| |
| QCOMPARE(obj->contentX(), 100.); |
| QCOMPARE(obj->contentY(), 100.); |
| QCOMPARE(obj->contentWidth(), 600.); |
| QCOMPARE(obj->contentHeight(), 600.); |
| |
| delete root; |
| } |
| |
| void tst_qquickflickable::returnToBounds() |
| { |
| QFETCH(bool, setRebound); |
| |
| QScopedPointer<QQuickView> window(new QQuickView); |
| |
| window->setInitialProperties({{"setRebound", setRebound}}); |
| window->setSource(testFileUrl("resize.qml")); |
| window->show(); |
| QVERIFY(QTest::qWaitForWindowActive(window.data())); |
| QVERIFY(window->rootObject() != nullptr); |
| QQuickFlickable *obj = findItem<QQuickFlickable>(window->rootObject(), "flick"); |
| |
| QQuickTransition *rebound = window->rootObject()->findChild<QQuickTransition*>("rebound"); |
| QVERIFY(rebound); |
| QSignalSpy reboundSpy(rebound, SIGNAL(runningChanged())); |
| |
| QVERIFY(obj != nullptr); |
| QCOMPARE(obj->contentX(), 0.); |
| QCOMPARE(obj->contentY(), 0.); |
| QCOMPARE(obj->contentWidth(), 300.); |
| QCOMPARE(obj->contentHeight(), 300.); |
| |
| obj->setContentX(100); |
| obj->setContentY(400); |
| QTRY_COMPARE(obj->contentX(), 100.); |
| QTRY_COMPARE(obj->contentY(), 400.); |
| |
| QMetaObject::invokeMethod(window->rootObject(), "returnToBounds"); |
| |
| if (setRebound) |
| QTRY_VERIFY(rebound->running()); |
| |
| QTRY_COMPARE(obj->contentX(), 0.); |
| QTRY_COMPARE(obj->contentY(), 0.); |
| |
| QVERIFY(!rebound->running()); |
| QCOMPARE(reboundSpy.count(), setRebound ? 2 : 0); |
| } |
| |
| void tst_qquickflickable::returnToBounds_data() |
| { |
| QTest::addColumn<bool>("setRebound"); |
| |
| QTest::newRow("with bounds transition") << true; |
| QTest::newRow("with bounds transition") << false; |
| } |
| |
| void tst_qquickflickable::wheel() |
| { |
| QScopedPointer<QQuickView> window(new QQuickView); |
| window->setSource(testFileUrl("wheel.qml")); |
| window->show(); |
| QVERIFY(QTest::qWaitForWindowActive(window.data())); |
| QVERIFY(window->rootObject() != nullptr); |
| |
| QQuickFlickable *flick = window->rootObject()->findChild<QQuickFlickable*>("flick"); |
| QVERIFY(flick != nullptr); |
| QQuickFlickablePrivate *fp = QQuickFlickablePrivate::get(flick); |
| QSignalSpy moveEndSpy(flick, SIGNAL(movementEnded())); |
| |
| // test a vertical flick |
| { |
| QPoint pos(200, 200); |
| QWheelEvent event(pos, window->mapToGlobal(pos), QPoint(), QPoint(0,-120), |
| Qt::NoButton, Qt::NoModifier, Qt::NoScrollPhase, false); |
| event.setAccepted(false); |
| QGuiApplication::sendEvent(window.data(), &event); |
| } |
| |
| QTRY_VERIFY(flick->contentY() > 0); |
| QCOMPARE(flick->contentX(), qreal(0)); |
| |
| QTRY_COMPARE(moveEndSpy.count(), 1); |
| QCOMPARE(fp->velocityTimeline.isActive(), false); |
| QCOMPARE(fp->timeline.isActive(), false); |
| QTest::qWait(50); // make sure that onContentYChanged won't sneak in again |
| QCOMPARE(flick->property("movementsAfterEnd").value<int>(), 0); // QTBUG-55886 |
| |
| // get ready to test horizontal flick |
| flick->setContentY(0); // which triggers movementEnded again |
| flick->setProperty("movementsAfterEnd", 0); |
| flick->setProperty("ended", false); |
| QCOMPARE(flick->contentY(), qreal(0)); |
| |
| // test a horizontal flick |
| { |
| QPoint pos(200, 200); |
| QWheelEvent event(pos, window->mapToGlobal(pos), QPoint(), QPoint(-120,0), |
| Qt::NoButton, Qt::NoModifier, Qt::NoScrollPhase, false); |
| |
| event.setAccepted(false); |
| QGuiApplication::sendEvent(window.data(), &event); |
| } |
| |
| QTRY_VERIFY(flick->contentX() > 0); |
| QCOMPARE(flick->contentY(), qreal(0)); |
| QTRY_COMPARE(moveEndSpy.count(), 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::trackpad() |
| { |
| QScopedPointer<QQuickView> window(new QQuickView); |
| window->setSource(testFileUrl("wheel.qml")); |
| window->show(); |
| QVERIFY(QTest::qWaitForWindowActive(window.data())); |
| QVERIFY(window->rootObject() != nullptr); |
| |
| QQuickFlickable *flick = window->rootObject()->findChild<QQuickFlickable*>("flick"); |
| QVERIFY(flick != nullptr); |
| QSignalSpy moveEndSpy(flick, SIGNAL(movementEnded())); |
| QPoint pos(200, 200); |
| |
| { |
| QWheelEvent event(pos, window->mapToGlobal(pos), QPoint(0,-100), QPoint(0,-120), |
| Qt::NoButton, Qt::NoModifier, Qt::ScrollBegin, false); |
| event.setAccepted(false); |
| QGuiApplication::sendEvent(window.data(), &event); |
| } |
| |
| QTRY_VERIFY(flick->contentY() > 0); |
| QCOMPARE(flick->contentX(), qreal(0)); |
| |
| flick->setContentY(0); |
| QCOMPARE(flick->contentY(), qreal(0)); |
| |
| { |
| QWheelEvent event(pos, window->mapToGlobal(pos), QPoint(-100,0), QPoint(-120,0), |
| Qt::NoButton, Qt::NoModifier, Qt::ScrollUpdate, false); |
| event.setAccepted(false); |
| QGuiApplication::sendEvent(window.data(), &event); |
| } |
| |
| QTRY_VERIFY(flick->contentX() > 0); |
| QCOMPARE(flick->contentY(), qreal(0)); |
| |
| { |
| QWheelEvent event(pos, window->mapToGlobal(pos), QPoint(0,0), QPoint(0,0), |
| Qt::NoButton, Qt::NoModifier, Qt::ScrollEnd, false); |
| event.setAccepted(false); |
| QGuiApplication::sendEvent(window.data(), &event); |
| } |
| |
| QTRY_COMPARE(moveEndSpy.count(), 1); // QTBUG-55871 |
| QCOMPARE(flick->property("movementsAfterEnd").value<int>(), 0); // QTBUG-55886 |
| } |
| |
| void tst_qquickflickable::movingAndFlicking_data() |
| { |
| QTest::addColumn<bool>("verticalEnabled"); |
| QTest::addColumn<bool>("horizontalEnabled"); |
| QTest::addColumn<QPoint>("flickToWithoutSnapBack"); |
| QTest::addColumn<QPoint>("flickToWithSnapBack"); |
| |
| QTest::newRow("vertical") |
| << true << false |
| << QPoint(50, 100) |
| << QPoint(50, 300); |
| |
| QTest::newRow("horizontal") |
| << false << true |
| << QPoint(-50, 200) |
| << QPoint(150, 200); |
| |
| QTest::newRow("both") |
| << true << true |
| << QPoint(-50, 100) |
| << QPoint(150, 300); |
| } |
| |
| void tst_qquickflickable::movingAndFlicking() |
| { |
| QFETCH(bool, verticalEnabled); |
| QFETCH(bool, horizontalEnabled); |
| QFETCH(QPoint, flickToWithoutSnapBack); |
| QFETCH(QPoint, flickToWithSnapBack); |
| |
| const QPoint flickFrom(50, 200); // centre |
| |
| QScopedPointer<QQuickView> window(new QQuickView); |
| window->setSource(testFileUrl("flickable03.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); |
| |
| QQuickFlickable *flickable = qobject_cast<QQuickFlickable*>(window->rootObject()); |
| QVERIFY(flickable != nullptr); |
| |
| QSignalSpy vMoveSpy(flickable, SIGNAL(movingVerticallyChanged())); |
| QSignalSpy hMoveSpy(flickable, SIGNAL(movingHorizontallyChanged())); |
| QSignalSpy moveSpy(flickable, SIGNAL(movingChanged())); |
| QSignalSpy vFlickSpy(flickable, SIGNAL(flickingVerticallyChanged())); |
| QSignalSpy hFlickSpy(flickable, SIGNAL(flickingHorizontallyChanged())); |
| QSignalSpy flickSpy(flickable, SIGNAL(flickingChanged())); |
| |
| QSignalSpy moveStartSpy(flickable, SIGNAL(movementStarted())); |
| QSignalSpy moveEndSpy(flickable, SIGNAL(movementEnded())); |
| QSignalSpy flickStartSpy(flickable, SIGNAL(flickStarted())); |
| QSignalSpy flickEndSpy(flickable, SIGNAL(flickEnded())); |
| |
| // do a flick that keeps the view within the bounds |
| flick(window.data(), flickFrom, flickToWithoutSnapBack, 200); |
| |
| QTRY_VERIFY(flickable->isMoving()); |
| QCOMPARE(flickable->isMovingHorizontally(), horizontalEnabled); |
| QCOMPARE(flickable->isMovingVertically(), verticalEnabled); |
| QVERIFY(flickable->isFlicking()); |
| QCOMPARE(flickable->isFlickingHorizontally(), horizontalEnabled); |
| QCOMPARE(flickable->isFlickingVertically(), verticalEnabled); |
| // contentX/contentY are either unchanged, or moving is true when the value changed. |
| 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(moveStartSpy.count(), 1); |
| QCOMPARE(flickStartSpy.count(), 1); |
| |
| // wait for any motion to end |
| QTRY_VERIFY(!flickable->isMoving()); |
| |
| QVERIFY(!flickable->isMovingHorizontally()); |
| QVERIFY(!flickable->isMovingVertically()); |
| QVERIFY(!flickable->isFlicking()); |
| 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(moveStartSpy.count(), 1); |
| QCOMPARE(moveEndSpy.count(), 1); |
| QCOMPARE(flickStartSpy.count(), 1); |
| QCOMPARE(flickEndSpy.count(), 1); |
| |
| // Stop on a full pixel after user interaction |
| if (verticalEnabled) |
| QCOMPARE(flickable->contentY(), (qreal)qRound(flickable->contentY())); |
| if (horizontalEnabled) |
| QCOMPARE(flickable->contentX(), (qreal)qRound(flickable->contentX())); |
| |
| // clear for next flick |
| vMoveSpy.clear(); hMoveSpy.clear(); moveSpy.clear(); |
| vFlickSpy.clear(); hFlickSpy.clear(); flickSpy.clear(); |
| moveStartSpy.clear(); moveEndSpy.clear(); |
| flickStartSpy.clear(); flickEndSpy.clear(); |
| |
| // do a flick that flicks the view out of bounds |
| flickable->setContentX(0); |
| flickable->setContentY(0); |
| QTRY_VERIFY(!flickable->isMoving()); |
| flick(window.data(), flickFrom, flickToWithSnapBack, 10); |
| |
| QTRY_VERIFY(flickable->isMoving()); |
| QCOMPARE(flickable->isMovingHorizontally(), horizontalEnabled); |
| QCOMPARE(flickable->isMovingVertically(), verticalEnabled); |
| QVERIFY(flickable->isFlicking()); |
| 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(moveStartSpy.count(), 1); |
| QCOMPARE(moveEndSpy.count(), 0); |
| QCOMPARE(flickStartSpy.count(), 1); |
| QCOMPARE(flickEndSpy.count(), 0); |
| |
| // wait for any motion to end |
| QTRY_VERIFY(!flickable->isMoving()); |
| |
| QVERIFY(!flickable->isMovingHorizontally()); |
| QVERIFY(!flickable->isMovingVertically()); |
| QVERIFY(!flickable->isFlicking()); |
| 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(moveStartSpy.count(), 1); |
| QCOMPARE(moveEndSpy.count(), 1); |
| QCOMPARE(flickStartSpy.count(), 1); |
| QCOMPARE(flickEndSpy.count(), 1); |
| |
| QCOMPARE(flickable->contentX(), 0.0); |
| QCOMPARE(flickable->contentY(), 0.0); |
| } |
| |
| |
| void tst_qquickflickable::movingAndDragging_data() |
| { |
| QTest::addColumn<bool>("verticalEnabled"); |
| QTest::addColumn<bool>("horizontalEnabled"); |
| QTest::addColumn<QPoint>("moveByWithoutSnapBack"); |
| QTest::addColumn<QPoint>("moveByWithSnapBack"); |
| |
| QTest::newRow("vertical") |
| << true << false |
| << QPoint(0, -10) |
| << QPoint(0, 20); |
| |
| QTest::newRow("horizontal") |
| << false << true |
| << QPoint(-10, 0) |
| << QPoint(20, 0); |
| |
| QTest::newRow("both") |
| << true << true |
| << QPoint(-10, -10) |
| << QPoint(20, 20); |
| } |
| |
| void tst_qquickflickable::movingAndDragging() |
| { |
| QFETCH(bool, verticalEnabled); |
| QFETCH(bool, horizontalEnabled); |
| QFETCH(QPoint, moveByWithoutSnapBack); |
| QFETCH(QPoint, moveByWithSnapBack); |
| |
| const QPoint moveFrom(50, 200); // centre |
| |
| QScopedPointer<QQuickView> window(new QQuickView); |
| window->setSource(testFileUrl("flickable03.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); |
| |
| QQuickFlickable *flickable = qobject_cast<QQuickFlickable*>(window->rootObject()); |
| QVERIFY(flickable != nullptr); |
| |
| QSignalSpy vDragSpy(flickable, SIGNAL(draggingVerticallyChanged())); |
| QSignalSpy hDragSpy(flickable, SIGNAL(draggingHorizontallyChanged())); |
| QSignalSpy dragSpy(flickable, SIGNAL(draggingChanged())); |
| QSignalSpy vMoveSpy(flickable, SIGNAL(movingVerticallyChanged())); |
| QSignalSpy hMoveSpy(flickable, SIGNAL(movingHorizontallyChanged())); |
| QSignalSpy moveSpy(flickable, SIGNAL(movingChanged())); |
| |
| QSignalSpy dragStartSpy(flickable, SIGNAL(dragStarted())); |
| QSignalSpy dragEndSpy(flickable, SIGNAL(dragEnded())); |
| QSignalSpy moveStartSpy(flickable, SIGNAL(movementStarted())); |
| QSignalSpy moveEndSpy(flickable, SIGNAL(movementEnded())); |
| |
| // start the drag |
| moveAndPress(window.data(), moveFrom); |
| QTest::mouseMove(window.data(), moveFrom + moveByWithoutSnapBack); |
| QTest::mouseMove(window.data(), moveFrom + moveByWithoutSnapBack*2); |
| QTest::mouseMove(window.data(), moveFrom + moveByWithoutSnapBack*3); |
| |
| QTRY_VERIFY(flickable->isMoving()); |
| QCOMPARE(flickable->isMovingHorizontally(), horizontalEnabled); |
| QCOMPARE(flickable->isMovingVertically(), verticalEnabled); |
| QVERIFY(flickable->isDragging()); |
| QCOMPARE(flickable->isDraggingHorizontally(), horizontalEnabled); |
| QCOMPARE(flickable->isDraggingVertically(), verticalEnabled); |
| // contentX/contentY are either unchanged, or moving and dragging are true when the value changes. |
| QCOMPARE(flickable->property("movingInContentX").value<bool>(), true); |
| QCOMPARE(flickable->property("movingInContentY").value<bool>(), true); |
| 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(moveStartSpy.count(), 1); |
| QCOMPARE(dragStartSpy.count(), 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); |
| // Don't test whether moving finished because a flick could occur |
| |
| // wait for any motion to end |
| QTRY_VERIFY(!flickable->isMoving()); |
| |
| QVERIFY(!flickable->isMovingHorizontally()); |
| QVERIFY(!flickable->isMovingVertically()); |
| 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(moveSpy.count(), 2); |
| QCOMPARE(vMoveSpy.count(), verticalEnabled ? 2 : 0); |
| QCOMPARE(hMoveSpy.count(), horizontalEnabled ? 2 : 0); |
| |
| QCOMPARE(dragStartSpy.count(), 1); |
| QCOMPARE(dragEndSpy.count(), 1); |
| QCOMPARE(moveStartSpy.count(), 1); |
| QCOMPARE(moveEndSpy.count(), 1); |
| |
| // Stop on a full pixel after user interaction |
| if (verticalEnabled) |
| QCOMPARE(flickable->contentY(), (qreal)qRound(flickable->contentY())); |
| if (horizontalEnabled) |
| QCOMPARE(flickable->contentX(), (qreal)qRound(flickable->contentX())); |
| |
| // clear for next drag |
| vMoveSpy.clear(); hMoveSpy.clear(); moveSpy.clear(); |
| vDragSpy.clear(); hDragSpy.clear(); dragSpy.clear(); |
| moveStartSpy.clear(); moveEndSpy.clear(); |
| dragStartSpy.clear(); dragEndSpy.clear(); |
| |
| // do a drag that drags the view out of bounds |
| flickable->setContentX(0); |
| flickable->setContentY(0); |
| QTRY_VERIFY(!flickable->isMoving()); |
| moveAndPress(window.data(), moveFrom); |
| QTest::mouseMove(window.data(), moveFrom + moveByWithSnapBack); |
| QTest::mouseMove(window.data(), moveFrom + moveByWithSnapBack*2); |
| QTest::mouseMove(window.data(), moveFrom + moveByWithSnapBack*3); |
| |
| QVERIFY(flickable->isMoving()); |
| QCOMPARE(flickable->isMovingHorizontally(), horizontalEnabled); |
| QCOMPARE(flickable->isMovingVertically(), verticalEnabled); |
| QVERIFY(flickable->isDragging()); |
| 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(moveStartSpy.count(), 1); |
| QCOMPARE(moveEndSpy.count(), 0); |
| QCOMPARE(dragStartSpy.count(), 1); |
| QCOMPARE(dragEndSpy.count(), 0); |
| |
| QTest::mouseRelease(window.data(), Qt::LeftButton, Qt::NoModifier, moveFrom + moveByWithSnapBack*3); |
| |
| // should now start snapping back to bounds (moving but not dragging) |
| QVERIFY(flickable->isMoving()); |
| QCOMPARE(flickable->isMovingHorizontally(), horizontalEnabled); |
| QCOMPARE(flickable->isMovingVertically(), verticalEnabled); |
| QVERIFY(!flickable->isDragging()); |
| 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(moveStartSpy.count(), 1); |
| QCOMPARE(moveEndSpy.count(), 0); |
| |
| // wait for any motion to end |
| QTRY_VERIFY(!flickable->isMoving()); |
| |
| QVERIFY(!flickable->isMovingHorizontally()); |
| QVERIFY(!flickable->isMovingVertically()); |
| QVERIFY(!flickable->isDragging()); |
| 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(moveStartSpy.count(), 1); |
| QCOMPARE(moveEndSpy.count(), 1); |
| QCOMPARE(dragStartSpy.count(), 1); |
| QCOMPARE(dragEndSpy.count(), 1); |
| |
| QCOMPARE(flickable->contentX(), 0.0); |
| QCOMPARE(flickable->contentY(), 0.0); |
| } |
| |
| void tst_qquickflickable::flickOnRelease() |
| { |
| QScopedPointer<QQuickView> window(new QQuickView); |
| window->setSource(testFileUrl("flickable03.qml")); |
| window->show(); |
| QVERIFY(QTest::qWaitForWindowActive(window.data())); |
| QVERIFY(window->rootObject() != nullptr); |
| |
| QQuickFlickable *flickable = qobject_cast<QQuickFlickable*>(window->rootObject()); |
| QVERIFY(flickable != nullptr); |
| |
| // Vertical with a quick press-move-release: should cause a flick in release. |
| QSignalSpy vFlickSpy(flickable, SIGNAL(flickingVerticallyChanged())); |
| // Use something that generates a huge velocity just to make it testable. |
| // In practice this feature matters on touchscreen devices where the |
| // underlying drivers will hopefully provide a pre-calculated velocity |
| // (based on more data than what the UI gets), thus making this use case |
| // working even with small movements. |
| moveAndPress(window.data(), QPoint(50, 300)); |
| QTest::mouseMove(window.data(), QPoint(50, 10), 10); |
| QTest::mouseRelease(window.data(), Qt::LeftButton, Qt::NoModifier, QPoint(50, 10), 10); |
| |
| QCOMPARE(vFlickSpy.count(), 1); |
| |
| // wait for any motion to end |
| QTRY_VERIFY(!flickable->isMoving()); |
| |
| // Stop on a full pixel after user interaction |
| QCOMPARE(flickable->contentY(), (qreal)qRound(flickable->contentY())); |
| } |
| |
| 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()); |
| window->show(); |
| QVERIFY(QTest::qWaitForWindowActive(window.data())); |
| QVERIFY(window->rootObject() != nullptr); |
| |
| QQuickFlickable *flickable = qobject_cast<QQuickFlickable*>(window->rootObject()); |
| QVERIFY(flickable != nullptr); |
| |
| QSignalSpy vMoveSpy(flickable, SIGNAL(movingVerticallyChanged())); |
| QSignalSpy hMoveSpy(flickable, SIGNAL(movingHorizontallyChanged())); |
| QSignalSpy moveSpy(flickable, SIGNAL(movingChanged())); |
| QSignalSpy hFlickSpy(flickable, SIGNAL(flickingHorizontallyChanged())); |
| QSignalSpy vFlickSpy(flickable, SIGNAL(flickingVerticallyChanged())); |
| QSignalSpy flickSpy(flickable, SIGNAL(flickingChanged())); |
| |
| // flick then press while it is still moving |
| // flicking == false, moving == true; |
| flick(window.data(), QPoint(20,190), QPoint(20, 50), 200); |
| QVERIFY(flickable->verticalVelocity() > 0.0); |
| QTRY_VERIFY(flickable->isFlicking()); |
| QVERIFY(flickable->isFlickingVertically()); |
| QVERIFY(!flickable->isFlickingHorizontally()); |
| 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); |
| |
| QTest::mousePress(window.data(), Qt::LeftButton, Qt::NoModifier, QPoint(20, 50)); |
| QTRY_VERIFY(!flickable->isFlicking()); |
| QVERIFY(!flickable->isFlickingVertically()); |
| QVERIFY(flickable->isMoving()); |
| QVERIFY(flickable->isMovingVertically()); |
| |
| QTest::mouseRelease(window.data(), Qt::LeftButton, Qt::NoModifier, QPoint(20,50)); |
| QVERIFY(!flickable->isFlicking()); |
| QVERIFY(!flickable->isFlickingVertically()); |
| QTRY_VERIFY(!flickable->isMoving()); |
| QVERIFY(!flickable->isMovingVertically()); |
| // Stop on a full pixel after user interaction |
| QCOMPARE(flickable->contentX(), (qreal)qRound(flickable->contentX())); |
| } |
| |
| void tst_qquickflickable::disabled() |
| { |
| QScopedPointer<QQuickView> window(new QQuickView); |
| window->setSource(testFileUrl("disabled.qml")); |
| window->show(); |
| QVERIFY(QTest::qWaitForWindowActive(window.data())); |
| QVERIFY(window->rootObject() != nullptr); |
| |
| QQuickFlickable *flick = window->rootObject()->findChild<QQuickFlickable*>("flickable"); |
| QVERIFY(flick != nullptr); |
| |
| moveAndPress(window.data(), QPoint(50, 90)); |
| |
| QTest::mouseMove(window.data(), QPoint(50, 80)); |
| QTest::mouseMove(window.data(), QPoint(50, 70)); |
| QTest::mouseMove(window.data(), QPoint(50, 60)); |
| |
| QVERIFY(!flick->isMoving()); |
| |
| QTest::mouseRelease(window.data(), Qt::LeftButton, Qt::NoModifier, QPoint(50, 60)); |
| |
| // verify that mouse clicks on other elements still work (QTBUG-20584) |
| moveAndPress(window.data(), QPoint(50, 10)); |
| QTest::mouseRelease(window.data(), Qt::LeftButton, Qt::NoModifier, QPoint(50, 10)); |
| |
| QTRY_VERIFY(window->rootObject()->property("clicked").toBool()); |
| } |
| |
| 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()); |
| window->show(); |
| QVERIFY(QTest::qWaitForWindowActive(window.data())); |
| QVERIFY(window->rootObject() != nullptr); |
| |
| QQuickFlickable *flickable = qobject_cast<QQuickFlickable*>(window->rootObject()); |
| QVERIFY(flickable != nullptr); |
| |
| // flick up |
| flick(window.data(), QPoint(20,190), QPoint(20, 50), 200); |
| QVERIFY(flickable->verticalVelocity() > 0.0); |
| QTRY_COMPARE(flickable->verticalVelocity(), 0.0); |
| |
| // flick down |
| flick(window.data(), QPoint(20,10), QPoint(20, 140), 200); |
| QTRY_VERIFY(flickable->verticalVelocity() < 0.0); |
| QTRY_COMPARE(flickable->verticalVelocity(), 0.0); |
| |
| #ifdef Q_OS_MAC |
| QSKIP("boost doesn't work on OS X"); |
| return; |
| #endif |
| |
| // Flick multiple times and verify that flick acceleration is applied. |
| QQuickFlickablePrivate *fp = QQuickFlickablePrivate::get(flickable); |
| bool boosted = false; |
| for (int i = 0; i < 6; ++i) { |
| flick(window.data(), QPoint(20,390), QPoint(20, 50), 100); |
| boosted |= fp->flickBoost > 1.0; |
| } |
| QVERIFY(boosted); |
| |
| // Flick in opposite direction -> boost cancelled. |
| flick(window.data(), QPoint(20,10), QPoint(20, 340), 200); |
| QTRY_VERIFY(flickable->verticalVelocity() < 0.0); |
| QCOMPARE(fp->flickBoost, 1.0); |
| } |
| |
| 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()); |
| window->setTitle(QTest::currentTestFunction()); |
| window->show(); |
| QVERIFY(QTest::qWaitForWindowActive(window.data())); |
| QQuickItem *root = window->rootObject(); |
| QVERIFY(root); |
| QQuickFlickable *obj = qobject_cast<QQuickFlickable*>(root); |
| QVERIFY(obj != nullptr); |
| |
| // starting state |
| QCOMPARE(obj->contentX(), -40.); |
| QCOMPARE(obj->contentY(), -20.); |
| QCOMPARE(obj->contentWidth(), 1600.); |
| QCOMPARE(obj->contentHeight(), 600.); |
| QCOMPARE(obj->originX(), 0.); |
| QCOMPARE(obj->originY(), 0.); |
| |
| // Reduce left margin |
| obj->setLeftMargin(30); |
| QTRY_COMPARE(obj->contentX(), -30.); |
| |
| // Reduce top margin |
| obj->setTopMargin(20); |
| QTRY_COMPARE(obj->contentY(), -20.); |
| |
| // position to the far right, including margin |
| obj->setContentX(1600 + 50 - obj->width()); |
| obj->returnToBounds(); |
| QTRY_COMPARE(obj->contentX(), 1600. + 50. - obj->width()); |
| |
| // position beyond the far right, including margin |
| obj->setContentX(1600 + 50 - obj->width() + 1.); |
| obj->returnToBounds(); |
| QTRY_COMPARE(obj->contentX(), 1600. + 50. - obj->width()); |
| |
| // Reduce right margin |
| obj->setRightMargin(40); |
| QTRY_COMPARE(obj->contentX(), 1600. + 40. - obj->width()); |
| QCOMPARE(obj->contentWidth(), 1600.); |
| |
| // position to the far bottom, including margin |
| obj->setContentY(600 + 30 - obj->height()); |
| obj->returnToBounds(); |
| QTRY_COMPARE(obj->contentY(), 600. + 30. - obj->height()); |
| |
| // position beyond the far bottom, including margin |
| obj->setContentY(600 + 30 - obj->height() + 1.); |
| obj->returnToBounds(); |
| QTRY_COMPARE(obj->contentY(), 600. + 30. - obj->height()); |
| |
| // Reduce bottom margin |
| obj->setBottomMargin(20); |
| QTRY_COMPARE(obj->contentY(), 600. + 20. - obj->height()); |
| QCOMPARE(obj->contentHeight(), 600.); |
| |
| delete root; |
| } |
| |
| 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()); |
| window->show(); |
| QVERIFY(QTest::qWaitForWindowActive(window.data())); |
| QVERIFY(window->rootObject()); |
| |
| QQuickFlickable *flickable = qobject_cast<QQuickFlickable*>(window->rootObject()); |
| QVERIFY(flickable); |
| |
| QTest::mouseDClick(window.data(), Qt::LeftButton); |
| QVERIFY(!flickable->isVisible()); |
| QVERIFY(!QQuickFlickablePrivate::get(flickable)->pressed); |
| } |
| |
| 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()); |
| window->show(); |
| QVERIFY(QTest::qWaitForWindowActive(window.data())); |
| QVERIFY(window->rootObject() != nullptr); |
| |
| QQuickFlickable *flickable = qobject_cast<QQuickFlickable*>(window->rootObject()); |
| QVERIFY(flickable != nullptr); |
| |
| moveAndPress(window.data(), QPoint(10, 10)); |
| // drag out of bounds |
| QTest::mouseMove(window.data(), QPoint(50, 50)); |
| QTest::mouseMove(window.data(), QPoint(100, 100)); |
| QTest::mouseMove(window.data(), QPoint(150, 150)); |
| |
| QVERIFY(flickable->contentX() != 0); |
| QVERIFY(flickable->contentY() != 0); |
| QVERIFY(flickable->isMoving()); |
| QVERIFY(flickable->isDragging()); |
| |
| // grabbing mouse will cancel flickable interaction. |
| QQuickItem *item = window->rootObject()->findChild<QQuickItem*>("row"); |
| item->grabMouse(); |
| |
| QTRY_COMPARE(flickable->contentX(), 0.); |
| QTRY_COMPARE(flickable->contentY(), 0.); |
| QTRY_VERIFY(!flickable->isMoving()); |
| QTRY_VERIFY(!flickable->isDragging()); |
| |
| moveAndRelease(window.data(), QPoint(50, 10)); |
| |
| } |
| |
| 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()); |
| view->show(); |
| QVERIFY(QTest::qWaitForWindowActive(view.data())); |
| QVERIFY(view->rootObject() != nullptr); |
| |
| QQuickFlickable *flickable = view->rootObject()->findChild<QQuickFlickable*>("flickable"); |
| QVERIFY(flickable != nullptr); |
| |
| // click outside child rect |
| moveAndPress(view.data(), QPoint(190, 190)); |
| QTRY_COMPARE(flickable->property("itemPressed").toBool(), false); |
| QTest::mouseRelease(view.data(), Qt::LeftButton, Qt::NoModifier, QPoint(190, 190)); |
| |
| // click inside child rect |
| moveAndPress(view.data(), QPoint(200, 200)); |
| 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 outside bounds |
| moveAndPress(view.data(), QPoint(160, 160)); |
| QTest::qWait(10); |
| QTest::mouseMove(view.data(), QPoint(160 + threshold * 2, 160)); |
| QTest::mouseMove(view.data(), QPoint(160 + threshold * 3, 160)); |
| QCOMPARE(flickable->isDragging(), false); |
| QCOMPARE(flickable->property("itemPressed").toBool(), false); |
| moveAndRelease(view.data(), QPoint(180, 160)); |
| |
| // drag inside bounds |
| moveAndPress(view.data(), QPoint(200, 140)); |
| QTest::qWait(10); |
| QTest::mouseMove(view.data(), QPoint(200 + threshold * 2, 140)); |
| QTest::mouseMove(view.data(), QPoint(200 + threshold * 3, 140)); |
| QCOMPARE(flickable->isDragging(), true); |
| QCOMPARE(flickable->property("itemPressed").toBool(), false); |
| moveAndRelease(view.data(), QPoint(220, 140)); |
| } |
| |
| 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()); |
| window->show(); |
| QVERIFY(window->rootObject() != nullptr); |
| QVERIFY(QTest::qWaitForWindowActive(window.data())); |
| |
| QQuickFlickable *flickable = qobject_cast<QQuickFlickable*>(window->rootObject()); |
| QVERIFY(flickable != nullptr); |
| |
| QCOMPARE(flickable->contentY(), 0.0f); |
| flickWithTouch(window.data(), QPoint(100, 400), QPoint(100, 240)); |
| |
| qreal contentYAfterFirstFlick = flickable->contentY(); |
| qDebug() << "contentYAfterFirstFlick " << contentYAfterFirstFlick; |
| QVERIFY(contentYAfterFirstFlick > 50.0f); |
| // Wait until view stops moving |
| QTRY_VERIFY(!flickable->isMoving()); |
| |
| flickWithTouch(window.data(), QPoint(100, 400), QPoint(100, 240)); |
| |
| // In the original bug, that second flick would cause Flickable to halt immediately |
| qreal contentYAfterSecondFlick = flickable->contentY(); |
| qDebug() << "contentYAfterSecondFlick " << contentYAfterSecondFlick; |
| QTRY_VERIFY(contentYAfterSecondFlick > (contentYAfterFirstFlick + 80.0f)); |
| } |
| |
| void tst_qquickflickable::flickWithTouch(QQuickWindow *window, const QPoint &from, const QPoint &to) |
| { |
| QTest::touchEvent(window, touchDevice).press(0, from, window); |
| QQuickTouchUtils::flush(window); |
| |
| QPoint diff = to - from; |
| for (int i = 1; i <= 8; ++i) { |
| QTest::touchEvent(window, touchDevice).move(0, from + i*diff/8, window); |
| QQuickTouchUtils::flush(window); |
| } |
| QTest::touchEvent(window, touchDevice).release(0, to, window); |
| QQuickTouchUtils::flush(window); |
| } |
| |
| void tst_qquickflickable::nestedStopAtBounds_data() |
| { |
| QTest::addColumn<bool>("transpose"); |
| QTest::addColumn<bool>("invert"); |
| QTest::addColumn<int>("boundsBehavior"); |
| QTest::addColumn<qreal>("margin"); |
| QTest::addColumn<bool>("innerFiltering"); |
| QTest::addColumn<int>("pressDelay"); |
| QTest::addColumn<bool>("waitForPressDelay"); |
| |
| QTest::newRow("left,stop") << false << false << int(QQuickFlickable::StopAtBounds) << qreal(0) << false << 0 << false; |
| QTest::newRow("right,stop") << false << true << int(QQuickFlickable::StopAtBounds) << qreal(0) << false << 0 << false; |
| QTest::newRow("top,stop") << true << false << int(QQuickFlickable::StopAtBounds) << qreal(0) << false << 0 << false; |
| QTest::newRow("bottom,stop") << true << true << int(QQuickFlickable::StopAtBounds) << qreal(0) << false << 0 << false; |
| QTest::newRow("left,over") << false << false << int(QQuickFlickable::DragOverBounds) << qreal(0) << false << 0 << false; |
| QTest::newRow("right,over") << false << true << int(QQuickFlickable::DragOverBounds) << qreal(0) << false << 0 << false; |
| QTest::newRow("top,over") << true << false << int(QQuickFlickable::DragOverBounds) << qreal(0) << false << 0 << false; |
| QTest::newRow("bottom,over") << true << true << int(QQuickFlickable::DragOverBounds) << qreal(0) << false << 0 << false; |
| |
| QTest::newRow("left,stop,margin") << false << false << int(QQuickFlickable::StopAtBounds) << qreal(20) << false << 0 << false; |
| QTest::newRow("right,stop,margin") << false << true << int(QQuickFlickable::StopAtBounds) << qreal(20) << false << 0 << false; |
| QTest::newRow("top,stop,margin") << true << false << int(QQuickFlickable::StopAtBounds) << qreal(20) << false << 0 << false; |
| QTest::newRow("bottom,stop,margin") << true << true << int(QQuickFlickable::StopAtBounds) << qreal(20) << false << 0 << false; |
| |
| QTest::newRow("left,stop,after press delay") << false << false << int(QQuickFlickable::StopAtBounds) << qreal(0) << true << 50 << true; |
| QTest::newRow("left,stop,before press delay") << false << false << int(QQuickFlickable::StopAtBounds) << qreal(0) << true << 50 << false; |
| } |
| |
| void tst_qquickflickable::nestedStopAtBounds() |
| { |
| QFETCH(bool, transpose); |
| QFETCH(bool, invert); |
| QFETCH(int, boundsBehavior); |
| QFETCH(qreal, margin); |
| QFETCH(bool, innerFiltering); |
| QFETCH(int, pressDelay); |
| QFETCH(bool, waitForPressDelay); |
| |
| QQuickView view; |
| view.setSource(testFileUrl("nestedStopAtBounds.qml")); |
| QTRY_COMPARE(view.status(), QQuickView::Ready); |
| QQuickViewTestUtil::centerOnScreen(&view); |
| QQuickViewTestUtil::moveMouseAway(&view); |
| view.show(); |
| view.requestActivate(); |
| QVERIFY(QTest::qWaitForWindowActive(&view)); |
| QVERIFY(view.rootObject()); |
| |
| QQuickFlickable *outer = qobject_cast<QQuickFlickable*>(view.rootObject()); |
| QVERIFY(outer); |
| |
| QQuickFlickable *inner = outer->findChild<QQuickFlickable*>("innerFlickable"); |
| QVERIFY(inner); |
| inner->setFlickableDirection(transpose ? QQuickFlickable::VerticalFlick : QQuickFlickable::HorizontalFlick); |
| inner->setBoundsBehavior(QQuickFlickable::BoundsBehavior(boundsBehavior)); |
| |
| invert ? inner->setRightMargin(margin) : inner->setLeftMargin(margin); |
| invert ? inner->setBottomMargin(margin) : inner->setTopMargin(margin); |
| |
| inner->setContentX(invert ? -margin : 100 - margin); |
| inner->setContentY(invert ? -margin : 100 - margin); |
| inner->setContentWidth(400 - margin); |
| inner->setContentHeight(400 - margin); |
| |
| QCOMPARE(inner->isAtXBeginning(), invert); |
| QCOMPARE(inner->isAtXEnd(), !invert); |
| QCOMPARE(inner->isAtYBeginning(), invert); |
| QCOMPARE(inner->isAtYEnd(), !invert); |
| |
| inner->setPressDelay(pressDelay); |
| |
| QQuickMouseArea *mouseArea = inner->findChild<QQuickMouseArea *>("mouseArea"); |
| QVERIFY(mouseArea); |
| mouseArea->setEnabled(innerFiltering); |
| |
| const int threshold = qApp->styleHints()->startDragDistance(); |
| |
| QPoint position(200, 200); |
| int &axis = transpose ? position.ry() : position.rx(); |
| |
| // drag toward the aligned boundary. Outer flickable dragged. |
| moveAndPress(&view, position); |
| if (waitForPressDelay) { |
| QVERIFY(innerFiltering); // isPressed will never be true if the mouse area isn't enabled. |
| QTRY_VERIFY(mouseArea->pressed()); |
| } |
| |
| axis += invert ? threshold * 2 : -threshold * 2; |
| QTest::mouseMove(&view, position); |
| axis += invert ? threshold : -threshold; |
| QTest::mouseMove(&view, position); |
| QCOMPARE(outer->isDragging(), true); |
| QCOMPARE(outer->isMoving(), true); |
| QCOMPARE(inner->isDragging(), false); |
| QCOMPARE(inner->isMoving(), false); |
| QTest::mouseRelease(&view, Qt::LeftButton, Qt::NoModifier, position); |
| |
| QVERIFY(!outer->isDragging()); |
| QTRY_VERIFY(!outer->isMoving()); |
| QVERIFY(!inner->isDragging()); |
| QVERIFY(!inner->isMoving()); |
| |
| axis = 200; |
| outer->setContentX(50); |
| outer->setContentY(50); |
| |
| // drag away from the aligned boundary. Inner flickable dragged. |
| moveAndPress(&view, position); |
| QTest::qWait(10); |
| axis += invert ? -threshold * 2 : threshold * 2; |
| QTest::mouseMove(&view, position); |
| axis += invert ? -threshold : threshold; |
| QTest::mouseMove(&view, position); |
| QCOMPARE(outer->isDragging(), false); |
| QCOMPARE(outer->isMoving(), false); |
| QCOMPARE(inner->isDragging(), true); |
| QCOMPARE(inner->isMoving(), true); |
| QTest::mouseRelease(&view, Qt::LeftButton, Qt::NoModifier, position); |
| |
| QVERIFY(!inner->isDragging()); |
| QTRY_VERIFY(!inner->isMoving()); |
| QVERIFY(!outer->isDragging()); |
| QVERIFY(!outer->isMoving()); |
| |
| axis = 200; |
| inner->setContentX(-margin); |
| inner->setContentY(-margin); |
| inner->setContentWidth(inner->width() - margin); |
| inner->setContentHeight(inner->height() - margin); |
| |
| // Drag inner with equal size and contentSize |
| moveAndPress(&view, position); |
| QTest::qWait(10); |
| axis += invert ? -threshold * 2 : threshold * 2; |
| QTest::mouseMove(&view, position); |
| axis += invert ? -threshold : threshold; |
| QTest::mouseMove(&view, position); |
| QCOMPARE(outer->isDragging(), true); |
| QCOMPARE(outer->isMoving(), true); |
| QCOMPARE(inner->isDragging(), false); |
| QCOMPARE(inner->isMoving(), false); |
| QTest::mouseRelease(&view, Qt::LeftButton, Qt::NoModifier, position); |
| |
| QVERIFY(!outer->isDragging()); |
| QTRY_VERIFY(!outer->isMoving()); |
| QVERIFY(!inner->isDragging()); |
| QVERIFY(!inner->isMoving()); |
| |
| axis = 200; |
| inner->setContentX(-margin); |
| inner->setContentY(-margin); |
| inner->setContentWidth(inner->width() - 100); |
| inner->setContentHeight(inner->height() - 100); |
| |
| // Drag inner with size greater than contentSize |
| moveAndPress(&view, position); |
| QTest::qWait(10); |
| axis += invert ? -threshold * 2 : threshold * 2; |
| QTest::mouseMove(&view, position); |
| axis += invert ? -threshold : threshold; |
| QTest::mouseMove(&view, position); |
| QCOMPARE(outer->isDragging(), true); |
| QCOMPARE(outer->isMoving(), true); |
| QCOMPARE(inner->isDragging(), false); |
| QCOMPARE(inner->isMoving(), false); |
| QTest::mouseRelease(&view, Qt::LeftButton, Qt::NoModifier, position); |
| |
| QVERIFY(!outer->isDragging()); |
| QTRY_VERIFY(!outer->isMoving()); |
| QVERIFY(!inner->isDragging()); |
| QVERIFY(!inner->isMoving()); |
| } |
| |
| void tst_qquickflickable::stopAtBounds_data() |
| { |
| QTest::addColumn<bool>("transpose"); |
| QTest::addColumn<bool>("invert"); |
| QTest::addColumn<bool>("pixelAligned"); |
| |
| QTest::newRow("left") << false << false << false; |
| QTest::newRow("right") << false << true << false; |
| QTest::newRow("top") << true << false << false; |
| QTest::newRow("bottom") << true << true << false; |
| QTest::newRow("left,pixelAligned") << false << false << true; |
| QTest::newRow("right,pixelAligned") << false << true << true; |
| QTest::newRow("top,pixelAligned") << true << false << true; |
| QTest::newRow("bottom,pixelAligned") << true << true << true; |
| } |
| |
| void tst_qquickflickable::stopAtBounds() |
| { |
| QFETCH(bool, transpose); |
| QFETCH(bool, invert); |
| QFETCH(bool, pixelAligned); |
| |
| QQuickView view; |
| view.setSource(testFileUrl("stopAtBounds.qml")); |
| QTRY_COMPARE(view.status(), QQuickView::Ready); |
| QQuickViewTestUtil::centerOnScreen(&view); |
| QQuickViewTestUtil::moveMouseAway(&view); |
| view.show(); |
| view.requestActivate(); |
| QVERIFY(QTest::qWaitForWindowActive(&view)); |
| QVERIFY(view.rootObject()); |
| |
| QQuickFlickable *flickable = qobject_cast<QQuickFlickable*>(view.rootObject()); |
| QVERIFY(flickable); |
| |
| if (transpose) |
| flickable->setContentY(invert ? 100 : 0); |
| else |
| flickable->setContentX(invert ? 100 : 0); |
| flickable->setPixelAligned(pixelAligned); |
| |
| const int threshold = qApp->styleHints()->startDragDistance(); |
| |
| QPoint position(200, 200); |
| int &axis = transpose ? position.ry() : position.rx(); |
| |
| // drag away from the aligned boundary. View should not move |
| moveAndPress(&view, position); |
| QTest::qWait(10); |
| for (int i = 0; i < 3; ++i) { |
| axis += invert ? -threshold : threshold; |
| QTest::mouseMove(&view, position); |
| } |
| QCOMPARE(flickable->isDragging(), false); |
| if (invert) |
| QCOMPARE(transpose ? flickable->isAtYEnd() : flickable->isAtXEnd(), true); |
| else |
| QCOMPARE(transpose ? flickable->isAtYBeginning() : flickable->isAtXBeginning(), true); |
| |
| QSignalSpy atXBeginningChangedSpy(flickable, &QQuickFlickable::atXBeginningChanged); |
| QSignalSpy atYBeginningChangedSpy(flickable, &QQuickFlickable::atYBeginningChanged); |
| QSignalSpy atXEndChangedSpy(flickable, &QQuickFlickable::atXEndChanged); |
| QSignalSpy atYEndChangedSpy(flickable, &QQuickFlickable::atYEndChanged); |
| // drag back towards boundary |
| for (int i = 0; i < 24; ++i) { |
| axis += invert ? threshold / 3 : -threshold / 3; |
| QTest::mouseMove(&view, position); |
| } |
| QTRY_COMPARE(flickable->isDragging(), true); |
| if (invert) |
| QCOMPARE(transpose ? flickable->isAtYEnd() : flickable->isAtXEnd(), false); |
| 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); |
| |
| // Drag away from the aligned boundary again. |
| // None of the mouse movements will position the view at the boundary exactly, |
| // but the view should end up aligned on the boundary |
| for (int i = 0; i < 5; ++i) { |
| axis += invert ? -threshold * 2 : threshold * 2; |
| QTest::mouseMove(&view, position); |
| } |
| QCOMPARE(flickable->isDragging(), true); |
| |
| // we should have hit the boundary and stopped |
| if (invert) { |
| QCOMPARE(transpose ? flickable->isAtYEnd() : flickable->isAtXEnd(), true); |
| QCOMPARE(transpose ? flickable->contentY() : flickable->contentX(), 100.0); |
| } else { |
| QCOMPARE(transpose ? flickable->isAtYBeginning() : flickable->isAtXBeginning(), true); |
| QCOMPARE(transpose ? flickable->contentY() : flickable->contentX(), 0.0); |
| } |
| |
| QTest::mouseRelease(&view, Qt::LeftButton, Qt::NoModifier, position); |
| |
| if (transpose) { |
| flickable->setContentY(invert ? 100 : 0); |
| } else { |
| flickable->setContentX(invert ? 100 : 0); |
| } |
| |
| QSignalSpy flickSignal(flickable, SIGNAL(flickingChanged())); |
| if (invert) |
| flick(&view, QPoint(20,20), QPoint(120,120), 100); |
| else |
| flick(&view, QPoint(120,120), QPoint(20,20), 100); |
| |
| QVERIFY(flickSignal.count() > 0); |
| if (transpose) { |
| if (invert) |
| QTRY_COMPARE(flickable->isAtYBeginning(), true); |
| else |
| QTRY_COMPARE(flickable->isAtYEnd(), true); |
| } else { |
| if (invert) |
| QTRY_COMPARE(flickable->isAtXBeginning(), true); |
| else |
| QTRY_COMPARE(flickable->isAtXEnd(), true); |
| } |
| } |
| |
| 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()); |
| 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 not have moved |
| QCOMPARE(flickable->contentY(), 50.0); |
| |
| // draggable item should have moved up |
| QQuickItem *nested = window->rootObject()->findChild<QQuickItem*>("nested"); |
| QVERIFY(nested->y() < 100.0); |
| } |
| |
| void tst_qquickflickable::nestedSliderUsingTouch_data() |
| { |
| QTest::addColumn<bool>("keepMouseGrab"); |
| QTest::addColumn<bool>("keepTouchGrab"); |
| QTest::addColumn<int>("minUpdates"); |
| QTest::addColumn<int>("releases"); |
| QTest::addColumn<int>("ungrabs"); |
| |
| QTest::newRow("keepBoth") << true << true << 8 << 1 << 0; |
| QTest::newRow("keepMouse") << true << false << 8 << 1 << 0; |
| QTest::newRow("keepTouch") << false << true << 8 << 1 << 0; |
| QTest::newRow("keepNeither") << false << false << 5 << 0 << 1; |
| } |
| |
| void tst_qquickflickable::nestedSliderUsingTouch() |
| { |
| QFETCH(bool, keepMouseGrab); |
| QFETCH(bool, keepTouchGrab); |
| QFETCH(int, minUpdates); |
| QFETCH(int, releases); |
| QFETCH(int, ungrabs); |
| |
| QQuickView *window = new QQuickView; |
| QScopedPointer<QQuickView> windowPtr(window); |
| windowPtr->setSource(testFileUrl("nestedSlider.qml")); |
| QTRY_COMPARE(window->status(), QQuickView::Ready); |
| QQuickViewTestUtil::centerOnScreen(window); |
| QQuickViewTestUtil::moveMouseAway(window); |
| window->show(); |
| QVERIFY(QTest::qWaitForWindowActive(window)); |
| QVERIFY(window->rootObject() != nullptr); |
| |
| QQuickFlickable *flickable = qobject_cast<QQuickFlickable*>(window->rootObject()); |
| QVERIFY(flickable); |
| |
| TouchDragArea *tda = flickable->findChild<TouchDragArea*>("drag"); |
| QVERIFY(tda); |
| |
| // Drag down and a little to the right: flickable will steal the grab only if tda allows it |
| const int dragThreshold = qApp->styleHints()->startDragDistance(); |
| tda->setKeepMouseGrab(keepMouseGrab); |
| tda->setKeepTouchGrab(keepTouchGrab); |
| QPoint p0 = tda->mapToScene(QPoint(20, 20)).toPoint(); |
| QTest::touchEvent(window, touchDevice).press(0, p0, window); |
| QQuickTouchUtils::flush(window); |
| for (int i = 0; i < 8; ++i) { |
| p0 += QPoint(dragThreshold / 6, dragThreshold / 4); |
| QTest::touchEvent(window, touchDevice).move(0, p0, window); |
| QQuickTouchUtils::flush(window); |
| } |
| QCOMPARE(tda->active(), !ungrabs); |
| QTest::touchEvent(window, touchDevice).release(0, p0, window); |
| QQuickTouchUtils::flush(window); |
| QTRY_COMPARE(tda->touchPointStates.first(), Qt::TouchPointPressed); |
| QTRY_VERIFY(tda->touchUpdates >= minUpdates); |
| QTRY_COMPARE(tda->touchReleases, releases); |
| QTRY_COMPARE(tda->ungrabs, ungrabs); |
| } |
| |
| // QTBUG-31328 |
| 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()); |
| window->show(); |
| QVERIFY(QTest::qWaitForWindowActive(window.data())); |
| QVERIFY(window->rootObject() != nullptr); |
| |
| // do not crash |
| moveAndPress(window.data(), QPoint(150, 150)); |
| QTest::mouseRelease(window.data(), Qt::LeftButton, Qt::NoModifier, QPoint(150, 150)); |
| } |
| |
| // QTBUG-34507 |
| 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()); |
| window->show(); |
| QVERIFY(QTest::qWaitForWindowActive(window.data())); |
| |
| QQuickFlickable *flickable = qobject_cast<QQuickFlickable*>(window->rootObject()); |
| QVERIFY(flickable != nullptr); |
| |
| // verify that the signals for movement and flicking are called in the right order |
| flickable->flick(0, -1000); |
| QTRY_COMPARE(flickable->property("signalString").toString(), QString("msfsfeme")); |
| } |
| |
| // QTBUG_35038 |
| void tst_qquickflickable::contentSize() |
| { |
| QQuickFlickable flickable; |
| QCOMPARE(flickable.contentWidth(), qreal(-1)); |
| QCOMPARE(flickable.contentHeight(), qreal(-1)); |
| |
| QSignalSpy cwspy(&flickable, SIGNAL(contentWidthChanged())); |
| QVERIFY(cwspy.isValid()); |
| |
| QSignalSpy chspy(&flickable, SIGNAL(contentHeightChanged())); |
| QVERIFY(chspy.isValid()); |
| |
| flickable.setWidth(100); |
| QCOMPARE(flickable.width(), qreal(100)); |
| QCOMPARE(flickable.contentWidth(), qreal(-1.0)); |
| QCOMPARE(cwspy.count(), 0); |
| |
| flickable.setContentWidth(10); |
| QCOMPARE(flickable.width(), qreal(100)); |
| QCOMPARE(flickable.contentWidth(), qreal(10)); |
| QCOMPARE(cwspy.count(), 1); |
| |
| flickable.setHeight(100); |
| QCOMPARE(flickable.height(), qreal(100)); |
| QCOMPARE(flickable.contentHeight(), qreal(-1.0)); |
| QCOMPARE(chspy.count(), 0); |
| |
| flickable.setContentHeight(10); |
| QCOMPARE(flickable.height(), qreal(100)); |
| QCOMPARE(flickable.contentHeight(), qreal(10)); |
| QCOMPARE(chspy.count(), 1); |
| } |
| |
| // QTBUG-53726 |
| 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()); |
| window->setTitle(QTest::currentTestFunction()); |
| window->show(); |
| QVERIFY(QTest::qWaitForWindowExposed(window.data())); |
| QQuickItem *root = window->rootObject(); |
| QVERIFY(root); |
| QQuickFlickable *obj = qobject_cast<QQuickFlickable*>(root); |
| QVERIFY(obj != nullptr); |
| |
| //doublecheck the item, as specified by contentWidth/Height, fits in the view |
| //use tryCompare to allow a bit of stabilization in component's properties |
| QTRY_COMPARE(obj->leftMargin() + obj->contentWidth() + obj->rightMargin() <= obj->width(), true); |
| QTRY_COMPARE(obj->topMargin() + obj->contentHeight() + obj->bottomMargin() <= obj->height(), true); |
| |
| //the whole item fits in the flickable, heightRatio should be 1 |
| QCOMPARE(obj->property("heightRatioIs").toDouble(), 1.); |
| QCOMPARE(obj->property("widthRatioIs").toDouble(), 1.); |
| } |
| |
| // QTBUG-48018 |
| 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()); |
| window->show(); |
| QVERIFY(QTest::qWaitForWindowActive(window.data())); |
| |
| QQuickFlickable *flickable = qobject_cast<QQuickFlickable*>(window->rootObject()); |
| QVERIFY(flickable); |
| |
| flickable->setContentX(1e10); |
| flick(window.data(), QPoint(200, 100), QPoint(100, 100), 50); |
| |
| // make sure we are not clipped at 2^31 |
| QVERIFY(flickable->contentX() > qreal(1e10)); |
| } |
| |
| 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()); |
| window->show(); |
| QVERIFY(QTest::qWaitForWindowActive(window.data())); |
| |
| QQuickFlickable *flickable = qobject_cast<QQuickFlickable*>(window->rootObject()); |
| QVERIFY(flickable); |
| |
| QQuickMouseArea *ma = flickable->findChild<QQuickMouseArea*>("ma"); |
| QVERIFY(ma); |
| ma->setPreventStealing(true); |
| |
| QPoint pos(250, 250); |
| moveAndPress(window.data(), pos); |
| for (int i = 0; i < 6; ++i) { |
| pos += QPoint(10, 10); |
| QTest::mouseMove(window.data(), pos); |
| QTest::qWait(10); |
| } |
| QTest::mouseRelease(window.data(), Qt::LeftButton, Qt::NoModifier, QPoint(310, 310)); |
| QTest::qWait(10); |
| |
| QCOMPARE(flickable->contentX(), 0.0); |
| QCOMPARE(flickable->contentY(), 0.0); |
| |
| ma->setPreventStealing(false); |
| |
| pos = QPoint(250, 250); |
| moveAndPress(window.data(), pos); |
| for (int i = 0; i < 6; ++i) { |
| pos += QPoint(10, 10); |
| QTest::mouseMove(window.data(), pos); |
| QTest::qWait(10); |
| } |
| QTest::mouseRelease(window.data(), Qt::LeftButton, Qt::NoModifier, QPoint(310, 310)); |
| QTest::qWait(10); |
| |
| QVERIFY(flickable->contentX() != 0.0); |
| QVERIFY(flickable->contentY() != 0.0); |
| } |
| |
| Q_DECLARE_METATYPE(QQuickFlickable::BoundsBehavior) |
| |
| void tst_qquickflickable::overshoot() |
| { |
| QFETCH(QQuickFlickable::BoundsBehavior, boundsBehavior); |
| QFETCH(int, boundsMovement); |
| |
| QScopedPointer<QQuickView> window(new QQuickView); |
| window->setSource(testFileUrl("overshoot.qml")); |
| window->show(); |
| |
| QVERIFY(QTest::qWaitForWindowExposed(window.data())); |
| |
| QQuickFlickable *flickable = qobject_cast<QQuickFlickable*>(window->rootObject()); |
| QVERIFY(flickable); |
| |
| QCOMPARE(flickable->width(), 200.0); |
| QCOMPARE(flickable->height(), 200.0); |
| QCOMPARE(flickable->contentWidth(), 400.0); |
| QCOMPARE(flickable->contentHeight(), 400.0); |
| |
| flickable->setBoundsBehavior(boundsBehavior); |
| flickable->setBoundsMovement(QQuickFlickable::BoundsMovement(boundsMovement)); |
| |
| // drag past the beginning |
| QTest::mousePress(window.data(), Qt::LeftButton, Qt::NoModifier, QPoint(10, 10)); |
| QTest::mouseMove(window.data(), QPoint(20, 20)); |
| QTest::mouseMove(window.data(), QPoint(30, 30)); |
| QTest::mouseMove(window.data(), QPoint(40, 40)); |
| QTest::mouseRelease(window.data(), Qt::LeftButton, Qt::NoModifier, QPoint(50, 50)); |
| |
| if ((boundsMovement == QQuickFlickable::FollowBoundsBehavior) && (boundsBehavior & QQuickFlickable::DragOverBounds)) { |
| QVERIFY(flickable->property("minContentX").toReal() < 0.0); |
| QVERIFY(flickable->property("minContentY").toReal() < 0.0); |
| } else { |
| QCOMPARE(flickable->property("minContentX").toReal(), 0.0); |
| QCOMPARE(flickable->property("minContentY").toReal(), 0.0); |
| } |
| if (boundsBehavior & QQuickFlickable::DragOverBounds) { |
| QVERIFY(flickable->property("minHorizontalOvershoot").toReal() < 0.0); |
| QVERIFY(flickable->property("minVerticalOvershoot").toReal() < 0.0); |
| } else { |
| QCOMPARE(flickable->property("minHorizontalOvershoot").toReal(), 0.0); |
| QCOMPARE(flickable->property("minVerticalOvershoot").toReal(), 0.0); |
| } |
| if (bool(boundsMovement == QQuickFlickable::FollowBoundsBehavior) == bool(boundsBehavior & QQuickFlickable::DragOverBounds)) { |
| QCOMPARE(flickable->property("minContentX").toReal(), |
| flickable->property("minHorizontalOvershoot").toReal()); |
| QCOMPARE(flickable->property("minContentY").toReal(), |
| flickable->property("minVerticalOvershoot").toReal()); |
| } |
| QCOMPARE(flickable->property("maxContentX").toReal(), 0.0); |
| QCOMPARE(flickable->property("maxContentY").toReal(), 0.0); |
| QCOMPARE(flickable->property("maxHorizontalOvershoot").toReal(), 0.0); |
| QCOMPARE(flickable->property("maxVerticalOvershoot").toReal(), 0.0); |
| |
| flickable->setContentX(20.0); |
| flickable->setContentY(20.0); |
| QMetaObject::invokeMethod(flickable, "reset"); |
| |
| // flick past the beginning |
| flick(window.data(), QPoint(10, 10), QPoint(50, 50), 100); |
| QTRY_VERIFY(!flickable->property("flicking").toBool()); |
| |
| if ((boundsMovement == QQuickFlickable::FollowBoundsBehavior) && (boundsBehavior & QQuickFlickable::OvershootBounds)) { |
| QVERIFY(flickable->property("minContentX").toReal() < 0.0); |
| QVERIFY(flickable->property("minContentY").toReal() < 0.0); |
| } else { |
| QCOMPARE(flickable->property("minContentX").toReal(), 0.0); |
| QCOMPARE(flickable->property("minContentY").toReal(), 0.0); |
| } |
| if (boundsBehavior & QQuickFlickable::OvershootBounds) { |
| QVERIFY(flickable->property("minHorizontalOvershoot").toReal() < 0.0); |
| QVERIFY(flickable->property("minVerticalOvershoot").toReal() < 0.0); |
| } else { |
| QCOMPARE(flickable->property("minHorizontalOvershoot").toReal(), 0.0); |
| QCOMPARE(flickable->property("minVerticalOvershoot").toReal(), 0.0); |
| } |
| if ((boundsMovement == QQuickFlickable::FollowBoundsBehavior) == (boundsBehavior & QQuickFlickable::OvershootBounds)) { |
| QCOMPARE(flickable->property("minContentX").toReal(), |
| flickable->property("minHorizontalOvershoot").toReal()); |
| QCOMPARE(flickable->property("minContentY").toReal(), |
| flickable->property("minVerticalOvershoot").toReal()); |
| } |
| QCOMPARE(flickable->property("maxContentX").toReal(), 20.0); |
| QCOMPARE(flickable->property("maxContentY").toReal(), 20.0); |
| QCOMPARE(flickable->property("maxHorizontalOvershoot").toReal(), 0.0); |
| QCOMPARE(flickable->property("maxVerticalOvershoot").toReal(), 0.0); |
| |
| flickable->setContentX(200.0); |
| flickable->setContentY(200.0); |
| QMetaObject::invokeMethod(flickable, "reset"); |
| |
| // drag past the end |
| QTest::mousePress(window.data(), Qt::LeftButton, Qt::NoModifier, QPoint(50, 50)); |
| QTest::mouseMove(window.data(), QPoint(40, 40)); |
| QTest::mouseMove(window.data(), QPoint(30, 30)); |
| QTest::mouseMove(window.data(), QPoint(20, 20)); |
| QTest::mouseRelease(window.data(), Qt::LeftButton, Qt::NoModifier, QPoint(10, 10)); |
| |
| if ((boundsMovement == QQuickFlickable::FollowBoundsBehavior) && (boundsBehavior & QQuickFlickable::DragOverBounds)) { |
| QVERIFY(flickable->property("maxContentX").toReal() > 200.0); |
| QVERIFY(flickable->property("maxContentX").toReal() > 200.0); |
| } else { |
| QCOMPARE(flickable->property("maxContentX").toReal(), 200.0); |
| QCOMPARE(flickable->property("maxContentY").toReal(), 200.0); |
| } |
| if (boundsBehavior & QQuickFlickable::DragOverBounds) { |
| QVERIFY(flickable->property("maxHorizontalOvershoot").toReal() > 0.0); |
| QVERIFY(flickable->property("maxVerticalOvershoot").toReal() > 0.0); |
| } else { |
| QCOMPARE(flickable->property("maxHorizontalOvershoot").toReal(), 0.0); |
| QCOMPARE(flickable->property("maxVerticalOvershoot").toReal(), 0.0); |
| } |
| if ((boundsMovement == QQuickFlickable::FollowBoundsBehavior) == (boundsBehavior & QQuickFlickable::DragOverBounds)) { |
| QCOMPARE(flickable->property("maxContentX").toReal() - 200.0, |
| flickable->property("maxHorizontalOvershoot").toReal()); |
| QCOMPARE(flickable->property("maxContentY").toReal() - 200.0, |
| flickable->property("maxVerticalOvershoot").toReal()); |
| } |
| QCOMPARE(flickable->property("minContentX").toReal(), 200.0); |
| QCOMPARE(flickable->property("minContentY").toReal(), 200.0); |
| QCOMPARE(flickable->property("minHorizontalOvershoot").toReal(), 0.0); |
| QCOMPARE(flickable->property("minVerticalOvershoot").toReal(), 0.0); |
| |
| flickable->setContentX(180.0); |
| flickable->setContentY(180.0); |
| QMetaObject::invokeMethod(flickable, "reset"); |
| |
| // flick past the end |
| flick(window.data(), QPoint(50, 50), QPoint(10, 10), 100); |
| QTRY_VERIFY(!flickable->property("flicking").toBool()); |
| |
| if ((boundsMovement == QQuickFlickable::FollowBoundsBehavior) && (boundsBehavior & QQuickFlickable::OvershootBounds)) { |
| QVERIFY(flickable->property("maxContentX").toReal() > 200.0); |
| QVERIFY(flickable->property("maxContentY").toReal() > 200.0); |
| } else { |
| QCOMPARE(flickable->property("maxContentX").toReal(), 200.0); |
| QCOMPARE(flickable->property("maxContentY").toReal(), 200.0); |
| } |
| if (boundsBehavior & QQuickFlickable::OvershootBounds) { |
| QVERIFY(flickable->property("maxHorizontalOvershoot").toReal() > 0.0); |
| QVERIFY(flickable->property("maxVerticalOvershoot").toReal() > 0.0); |
| } else { |
| QCOMPARE(flickable->property("maxHorizontalOvershoot").toReal(), 0.0); |
| QCOMPARE(flickable->property("maxVerticalOvershoot").toReal(), 0.0); |
| } |
| if ((boundsMovement == QQuickFlickable::FollowBoundsBehavior) == (boundsBehavior & QQuickFlickable::OvershootBounds)) { |
| QCOMPARE(flickable->property("maxContentX").toReal() - 200.0, |
| flickable->property("maxHorizontalOvershoot").toReal()); |
| QCOMPARE(flickable->property("maxContentY").toReal() - 200.0, |
| flickable->property("maxVerticalOvershoot").toReal()); |
| } |
| QCOMPARE(flickable->property("minContentX").toReal(), 180.0); |
| QCOMPARE(flickable->property("minContentY").toReal(), 180.0); |
| QCOMPARE(flickable->property("minHorizontalOvershoot").toReal(), 0.0); |
| QCOMPARE(flickable->property("minVerticalOvershoot").toReal(), 0.0); |
| } |
| |
| void tst_qquickflickable::overshoot_data() |
| { |
| QTest::addColumn<QQuickFlickable::BoundsBehavior>("boundsBehavior"); |
| QTest::addColumn<int>("boundsMovement"); |
| |
| QTest::newRow("StopAtBounds,FollowBoundsBehavior") |
| << QQuickFlickable::BoundsBehavior(QQuickFlickable::StopAtBounds) |
| << int(QQuickFlickable::FollowBoundsBehavior); |
| QTest::newRow("DragOverBounds,FollowBoundsBehavior") |
| << QQuickFlickable::BoundsBehavior(QQuickFlickable::DragOverBounds) |
| << int(QQuickFlickable::FollowBoundsBehavior); |
| QTest::newRow("OvershootBounds,FollowBoundsBehavior") |
| << QQuickFlickable::BoundsBehavior(QQuickFlickable::OvershootBounds) |
| << int(QQuickFlickable::FollowBoundsBehavior); |
| QTest::newRow("DragAndOvershootBounds,FollowBoundsBehavior") |
| << QQuickFlickable::BoundsBehavior(QQuickFlickable::DragAndOvershootBounds) |
| << int(QQuickFlickable::FollowBoundsBehavior); |
| |
| QTest::newRow("DragOverBounds,StopAtBounds") |
| << QQuickFlickable::BoundsBehavior(QQuickFlickable::DragOverBounds) |
| << int(QQuickFlickable::StopAtBounds); |
| QTest::newRow("OvershootBounds,StopAtBounds") |
| << QQuickFlickable::BoundsBehavior(QQuickFlickable::OvershootBounds) |
| << int(QQuickFlickable::StopAtBounds); |
| QTest::newRow("DragAndOvershootBounds,StopAtBounds") |
| << QQuickFlickable::BoundsBehavior(QQuickFlickable::DragAndOvershootBounds) |
| << int(QQuickFlickable::StopAtBounds); |
| } |
| |
| void tst_qquickflickable::overshoot_reentrant() |
| { |
| QScopedPointer<QQuickView> window(new QQuickView); |
| window->setSource(testFileUrl("overshoot_reentrant.qml")); |
| window->show(); |
| |
| QVERIFY(QTest::qWaitForWindowExposed(window.data())); |
| |
| QQuickFlickable *flickable = qobject_cast<QQuickFlickable*>(window->rootObject()); |
| QVERIFY(flickable); |
| |
| // horizontal |
| flickable->setContentX(-10.0); |
| QCOMPARE(flickable->contentX(), -10.0); |
| QCOMPARE(flickable->horizontalOvershoot(), -10.0); |
| |
| flickable->setProperty("contentPosAdjustment", -5.0); |
| flickable->setContentX(-20.0); |
| QCOMPARE(flickable->contentX(), -25.0); |
| QCOMPARE(flickable->horizontalOvershoot(), -25.0); |
| |
| flickable->setContentX(210); |
| QCOMPARE(flickable->contentX(), 210.0); |
| QCOMPARE(flickable->horizontalOvershoot(), 10.0); |
| |
| flickable->setProperty("contentPosAdjustment", 5.0); |
| flickable->setContentX(220.0); |
| QCOMPARE(flickable->contentX(), 225.0); |
| QCOMPARE(flickable->horizontalOvershoot(), 25.0); |
| |
| // vertical |
| flickable->setContentY(-10.0); |
| QCOMPARE(flickable->contentY(), -10.0); |
| QCOMPARE(flickable->verticalOvershoot(), -10.0); |
| |
| flickable->setProperty("contentPosAdjustment", -5.0); |
| flickable->setContentY(-20.0); |
| QCOMPARE(flickable->contentY(), -25.0); |
| QCOMPARE(flickable->verticalOvershoot(), -25.0); |
| |
| flickable->setContentY(210); |
| QCOMPARE(flickable->contentY(), 210.0); |
| QCOMPARE(flickable->verticalOvershoot(), 10.0); |
| |
| flickable->setProperty("contentPosAdjustment", 5.0); |
| flickable->setContentY(220.0); |
| QCOMPARE(flickable->contentY(), 225.0); |
| QCOMPARE(flickable->verticalOvershoot(), 25.0); |
| } |
| |
| void tst_qquickflickable::synchronousDrag_data() |
| { |
| QTest::addColumn<bool>("synchronousDrag"); |
| |
| QTest::newRow("default") << false; |
| QTest::newRow("synch") << true; |
| } |
| |
| void tst_qquickflickable::synchronousDrag() |
| { |
| QFETCH(bool, synchronousDrag); |
| |
| QScopedPointer<QQuickView> scopedWindow(new QQuickView); |
| QQuickView *window = scopedWindow.data(); |
| window->setSource(testFileUrl("longList.qml")); |
| QTRY_COMPARE(window->status(), QQuickView::Ready); |
| QQuickViewTestUtil::centerOnScreen(window); |
| QQuickViewTestUtil::moveMouseAway(window); |
| window->show(); |
| QVERIFY(window->rootObject() != nullptr); |
| QVERIFY(QTest::qWaitForWindowActive(window)); |
| |
| QQuickFlickable *flickable = qobject_cast<QQuickFlickable*>(window->rootObject()); |
| QVERIFY(flickable != nullptr); |
| QCOMPARE(flickable->synchronousDrag(), false); |
| flickable->setSynchronousDrag(synchronousDrag); |
| |
| QPoint p1(100, 100); |
| QPoint p2(95, 95); |
| QPoint p3(70, 70); |
| QPoint p4(50, 50); |
| QPoint p5(30, 30); |
| QCOMPARE(flickable->contentY(), 0.0f); |
| |
| // Drag via mouse |
| moveAndPress(window, p1); |
| QTest::mouseMove(window, p2); |
| QTest::mouseMove(window, p3); |
| QTest::mouseMove(window, p4); |
| QCOMPARE(flickable->contentY(), synchronousDrag ? 50.0f : 0.0f); |
| QTest::mouseMove(window, p5); |
| if (!synchronousDrag) |
| QVERIFY(flickable->contentY() < 50.0f); |
| QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p5); |
| |
| // Reset to initial condition |
| flickable->setContentY(0); |
| |
| // Drag via touch |
| QTest::touchEvent(window, touchDevice).press(0, p1, window); |
| QQuickTouchUtils::flush(window); |
| QTest::touchEvent(window, touchDevice).move(0, p2, window); |
| QQuickTouchUtils::flush(window); |
| QTest::touchEvent(window, touchDevice).move(0, p3, window); |
| QQuickTouchUtils::flush(window); |
| QTest::touchEvent(window, touchDevice).move(0, p4, window); |
| QQuickTouchUtils::flush(window); |
| QCOMPARE(flickable->contentY(), synchronousDrag ? 50.0f : 0.0f); |
| QTest::touchEvent(window, touchDevice).move(0, p5, window); |
| QQuickTouchUtils::flush(window); |
| if (!synchronousDrag) |
| QVERIFY(flickable->contentY() < 50.0f); |
| QTest::touchEvent(window, touchDevice).release(0, p5, window); |
| } |
| |
| // QTBUG-81098: tests that a binding to visibleArea doesn't result |
| // in a division-by-zero exception (when exceptions are enabled). |
| void tst_qquickflickable::visibleAreaBinding() |
| { |
| QScopedPointer<QQuickView> window(new QQuickView); |
| window->setSource(testFileUrl("visibleAreaBinding.qml")); |
| QTRY_COMPARE(window->status(), QQuickView::Ready); |
| // Shouldn't crash. |
| } |
| |
| QTEST_MAIN(tst_qquickflickable) |
| |
| #include "tst_qquickflickable.moc" |