****************************************************************************/
#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/qquicktransition_p.h>
#include <private/qqmlvaluetype_p.h>
#include <math.h>
#include "../../shared/util.h"
void verticalViewportSize();
void properties();
void boundsBehavior();
+ void rebound();
void maximumFlickVelocity();
void flickDeceleration();
void pressDelay();
void flickableDirection();
void resizeContent();
void returnToBounds();
+ void returnToBounds_data();
void wheel();
+ void movingAndFlicking();
+ void movingAndFlicking_data();
void movingAndDragging();
+ void movingAndDragging_data();
+ void flickOnRelease();
+ void pressWhileFlicking();
void disabled();
void flickVelocity();
void margins();
- void cancel();
+ void cancelOnMouseGrab();
+ void clickAndDragWhenTransformed();
private:
QQmlEngine engine;
QCOMPARE(spy.count(),3);
}
+void tst_qquickflickable::rebound()
+{
+#ifdef Q_OS_MAC
+ QSKIP("Producing flicks on Mac CI impossible due to timing problems");
+#endif
+
+ QQuickView *window = new QQuickView;
+ window->setSource(testFileUrl("rebound.qml"));
+ window->show();
+ window->requestActivateWindow();
+ QVERIFY(window->rootObject() != 0);
+
+ QQuickFlickable *flickable = qobject_cast<QQuickFlickable*>(window->rootObject());
+ QVERIFY(flickable != 0);
+
+ 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, 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, QPoint(20,20), QPoint(120,120), 200); // both x and y will bounce back
+ flick(window, QPoint(20,120), QPoint(120,20), 200); // only x will bounce back
+
+ QVERIFY(flickable->isMoving());
+ QVERIFY(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, 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);
+
+ delete window;
+}
+
void tst_qquickflickable::maximumFlickVelocity()
{
QQmlComponent component(&engine);
// QTBUG-17361
void tst_qquickflickable::nestedPressDelay()
{
- QQuickView *canvas = new QQuickView;
- canvas->setSource(testFileUrl("nestedPressDelay.qml"));
- canvas->show();
- canvas->requestActivateWindow();
- QVERIFY(canvas->rootObject() != 0);
+ QQuickView *window = new QQuickView;
+ window->setSource(testFileUrl("nestedPressDelay.qml"));
+ window->show();
+ window->requestActivateWindow();
+ QVERIFY(window->rootObject() != 0);
- QQuickFlickable *outer = qobject_cast<QQuickFlickable*>(canvas->rootObject());
+ QQuickFlickable *outer = qobject_cast<QQuickFlickable*>(window->rootObject());
QVERIFY(outer != 0);
- QQuickFlickable *inner = canvas->rootObject()->findChild<QQuickFlickable*>("innerFlickable");
+ QQuickFlickable *inner = window->rootObject()->findChild<QQuickFlickable*>("innerFlickable");
QVERIFY(inner != 0);
- QTest::mousePress(canvas, Qt::LeftButton, 0, QPoint(150, 150));
+ QTest::mousePress(window, Qt::LeftButton, 0, QPoint(150, 150));
// the MouseArea is not pressed immediately
QVERIFY(outer->property("pressed").toBool() == false);
// QTRY_VERIFY() has 5sec timeout, so will timeout well within 10sec.
QTRY_VERIFY(outer->property("pressed").toBool() == true);
- QTest::mouseRelease(canvas, Qt::LeftButton, 0, QPoint(150, 150));
+ QTest::mouseRelease(window, Qt::LeftButton, 0, QPoint(150, 150));
- delete canvas;
+ delete window;
}
void tst_qquickflickable::flickableDirection()
delete root;
}
-// QtQuick 1.1
void tst_qquickflickable::returnToBounds()
{
- QQmlEngine engine;
- QQmlComponent c(&engine, testFileUrl("resize.qml"));
- QQuickItem *root = qobject_cast<QQuickItem*>(c.create());
- QQuickFlickable *obj = findItem<QQuickFlickable>(root, "flick");
+ QFETCH(bool, setRebound);
+
+ QQuickView *window = new QQuickView;
+ window->rootContext()->setContextProperty("setRebound", setRebound);
+ window->setSource(testFileUrl("resize.qml"));
+ QVERIFY(window->rootObject() != 0);
+ QQuickFlickable *obj = findItem<QQuickFlickable>(window->rootObject(), "flick");
+
+ QQuickTransition *rebound = window->rootObject()->findChild<QQuickTransition*>("rebound");
+ QVERIFY(rebound);
+ QSignalSpy reboundSpy(rebound, SIGNAL(runningChanged()));
QVERIFY(obj != 0);
QCOMPARE(obj->contentX(), 0.);
QTRY_COMPARE(obj->contentX(), 100.);
QTRY_COMPARE(obj->contentY(), 400.);
- QMetaObject::invokeMethod(root, "returnToBounds");
+ QMetaObject::invokeMethod(window->rootObject(), "returnToBounds");
+
+ if (setRebound)
+ QTRY_VERIFY(rebound->running());
QTRY_COMPARE(obj->contentX(), 0.);
QTRY_COMPARE(obj->contentY(), 0.);
- delete root;
+ QVERIFY(!rebound->running());
+ QCOMPARE(reboundSpy.count(), setRebound ? 2 : 0);
+
+ delete window;
+}
+
+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()
{
- QQuickView *canvas = new QQuickView;
- canvas->setSource(testFileUrl("wheel.qml"));
- canvas->show();
- canvas->requestActivateWindow();
- QVERIFY(canvas->rootObject() != 0);
+ QQuickView *window = new QQuickView;
+ window->setSource(testFileUrl("wheel.qml"));
+ window->show();
+ window->requestActivateWindow();
+ QVERIFY(window->rootObject() != 0);
- QQuickFlickable *flick = canvas->rootObject()->findChild<QQuickFlickable*>("flick");
+ QQuickFlickable *flick = window->rootObject()->findChild<QQuickFlickable*>("flick");
QVERIFY(flick != 0);
{
- QWheelEvent event(QPoint(200, 200), -120, Qt::NoButton, Qt::NoModifier, Qt::Vertical);
+ QPoint pos(200, 200);
+ QWheelEvent event(pos, window->mapToGlobal(pos), QPoint(), QPoint(0,-120), -120, Qt::Vertical, Qt::NoButton, Qt::NoModifier);
event.setAccepted(false);
- QGuiApplication::sendEvent(canvas, &event);
+ QGuiApplication::sendEvent(window, &event);
}
QTRY_VERIFY(flick->contentY() > 0);
QVERIFY(flick->contentY() == 0);
{
- QWheelEvent event(QPoint(200, 200), -120, Qt::NoButton, Qt::NoModifier, Qt::Horizontal);
+ QPoint pos(200, 200);
+ QWheelEvent event(pos, window->mapToGlobal(pos), QPoint(), QPoint(-120,0), -120, Qt::Horizontal, Qt::NoButton, Qt::NoModifier);
+
event.setAccepted(false);
- QGuiApplication::sendEvent(canvas, &event);
+ QGuiApplication::sendEvent(window, &event);
}
QTRY_VERIFY(flick->contentX() > 0);
QVERIFY(flick->contentY() == 0);
- delete canvas;
+ delete window;
+}
+
+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()
+{
+#ifdef Q_OS_MAC
+ QSKIP("Producing flicks on Mac CI impossible due to timing problems");
+#endif
+
+ QFETCH(bool, verticalEnabled);
+ QFETCH(bool, horizontalEnabled);
+ QFETCH(QPoint, flickToWithoutSnapBack);
+ QFETCH(QPoint, flickToWithSnapBack);
+
+ const QPoint flickFrom(50, 200); // centre
+
+ QQuickView *window = new QQuickView;
+ window->setSource(testFileUrl("flickable03.qml"));
+ window->show();
+ window->requestActivateWindow();
+ QTest::qWaitForWindowActive(window);
+ QVERIFY(window->rootObject() != 0);
+
+ QQuickFlickable *flickable = qobject_cast<QQuickFlickable*>(window->rootObject());
+ QVERIFY(flickable != 0);
+
+ 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, flickFrom, flickToWithoutSnapBack, 200);
+
+ QVERIFY(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(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, flickFrom, flickToWithSnapBack, 200);
+
+ QVERIFY(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);
+
+ delete window;
+}
+
+
+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()
{
- QQuickView *canvas = new QQuickView;
- canvas->setSource(testFileUrl("flickable03.qml"));
- canvas->show();
- canvas->requestActivateWindow();
- QTest::qWaitForWindowShown(canvas);
- QVERIFY(canvas->rootObject() != 0);
-
- QQuickFlickable *flickable = qobject_cast<QQuickFlickable*>(canvas->rootObject());
+ QFETCH(bool, verticalEnabled);
+ QFETCH(bool, horizontalEnabled);
+ QFETCH(QPoint, moveByWithoutSnapBack);
+ QFETCH(QPoint, moveByWithSnapBack);
+
+ const QPoint moveFrom(50, 200); // centre
+
+ QQuickView *window = new QQuickView;
+ window->setSource(testFileUrl("flickable03.qml"));
+ window->show();
+ window->requestActivateWindow();
+ QTest::qWaitForWindowShown(window);
+ QVERIFY(window->rootObject() != 0);
+
+ QQuickFlickable *flickable = qobject_cast<QQuickFlickable*>(window->rootObject());
QVERIFY(flickable != 0);
QSignalSpy vDragSpy(flickable, SIGNAL(draggingVerticallyChanged()));
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()));
- //Vertical
- QTest::mousePress(canvas, Qt::LeftButton, 0, QPoint(50, 90));
-
- QTest::mouseMove(canvas, QPoint(50, 80));
- QTest::mouseMove(canvas, QPoint(50, 70));
- QTest::mouseMove(canvas, QPoint(50, 60));
-
- QMouseEvent moveEvent(QEvent::MouseMove, QPoint(50, 80), Qt::LeftButton, Qt::LeftButton, 0);
+ // start the drag
+ QTest::mousePress(window, Qt::LeftButton, 0, moveFrom);
+ QTest::mouseMove(window, moveFrom + moveByWithoutSnapBack);
+ QTest::mouseMove(window, moveFrom + moveByWithoutSnapBack*2);
+ QTest::mouseMove(window, moveFrom + moveByWithoutSnapBack*3);
- QVERIFY(!flickable->isDraggingHorizontally());
- QVERIFY(flickable->isDraggingVertically());
+ QVERIFY(flickable->isMoving());
+ QCOMPARE(flickable->isMovingHorizontally(), horizontalEnabled);
+ QCOMPARE(flickable->isMovingVertically(), verticalEnabled);
QVERIFY(flickable->isDragging());
- QCOMPARE(vDragSpy.count(), 1);
- QCOMPARE(dragSpy.count(), 1);
- QCOMPARE(hDragSpy.count(), 0);
- QCOMPARE(dragStartSpy.count(), 1);
- QCOMPARE(dragEndSpy.count(), 0);
+ QCOMPARE(flickable->isDraggingHorizontally(), horizontalEnabled);
+ QCOMPARE(flickable->isDraggingVertically(), verticalEnabled);
- QVERIFY(!flickable->isMovingHorizontally());
- QVERIFY(flickable->isMovingVertically());
- QVERIFY(flickable->isMoving());
- QCOMPARE(vMoveSpy.count(), 1);
QCOMPARE(moveSpy.count(), 1);
- QCOMPARE(hMoveSpy.count(), 0);
+ 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(canvas, Qt::LeftButton, 0, QPoint(50, 60));
+ QTest::mouseRelease(window, Qt::LeftButton, 0, moveFrom + moveByWithoutSnapBack*3);
- QTRY_VERIFY(!flickable->isDraggingVertically());
QVERIFY(!flickable->isDragging());
- QCOMPARE(vDragSpy.count(), 2);
+ QVERIFY(!flickable->isDraggingHorizontally());
+ QVERIFY(!flickable->isDraggingVertically());
QCOMPARE(dragSpy.count(), 2);
- QCOMPARE(hDragSpy.count(), 0);
+ 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() == false);
+ 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());
+ QTest::mousePress(window, Qt::LeftButton, 0, moveFrom);
+ QTest::mouseMove(window, moveFrom + moveByWithSnapBack);
+ QTest::mouseMove(window, moveFrom + moveByWithSnapBack*2);
+ QTest::mouseMove(window, 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, Qt::LeftButton, 0, 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);
+
+ delete window;
+}
+
+void tst_qquickflickable::flickOnRelease()
+{
+#ifdef Q_OS_MAC
+ QSKIP("Producing flicks on Mac CI impossible due to timing problems");
+#endif
+ QQuickView *window = new QQuickView;
+ window->setSource(testFileUrl("flickable03.qml"));
+ window->show();
+ window->requestActivateWindow();
+ QTest::qWaitForWindowShown(window);
+ QVERIFY(window->rootObject() != 0);
+
+ QQuickFlickable *flickable = qobject_cast<QQuickFlickable*>(window->rootObject());
+ QVERIFY(flickable != 0);
+
// 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.
// 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.
- QTest::mousePress(canvas, Qt::LeftButton, 0, QPoint(50, 10));
- QTest::mouseMove(canvas, QPoint(50, 300), 10);
- QTest::mouseRelease(canvas, Qt::LeftButton, 0, QPoint(50, 100), 10);
+ QTest::mousePress(window, Qt::LeftButton, 0, QPoint(50, 300));
+ QTest::mouseMove(window, QPoint(50, 10), 10);
+ QTest::mouseRelease(window, Qt::LeftButton, 0, QPoint(50, 10), 10);
QCOMPARE(vFlickSpy.count(), 1);
// wait for any motion to end
QTRY_VERIFY(flickable->isMoving() == false);
- //Horizontal
- vDragSpy.clear();
- hDragSpy.clear();
- dragSpy.clear();
- vMoveSpy.clear();
- hMoveSpy.clear();
- moveSpy.clear();
- dragStartSpy.clear();
- dragEndSpy.clear();
-
- QTest::mousePress(canvas, Qt::LeftButton, 0, QPoint(90, 50));
-
- QTest::mouseMove(canvas, QPoint(80, 50));
- QTest::mouseMove(canvas, QPoint(70, 50));
- QTest::mouseMove(canvas, QPoint(60, 50));
-
- QVERIFY(!flickable->isDraggingVertically());
- QVERIFY(flickable->isDraggingHorizontally());
- QVERIFY(flickable->isDragging());
- QCOMPARE(vDragSpy.count(), 0);
- QCOMPARE(dragSpy.count(), 1);
- QCOMPARE(hDragSpy.count(), 1);
- QCOMPARE(dragStartSpy.count(), 1);
- QCOMPARE(dragEndSpy.count(), 0);
-
- QVERIFY(!flickable->isMovingVertically());
- QVERIFY(flickable->isMovingHorizontally());
- QVERIFY(flickable->isMoving());
- QCOMPARE(vMoveSpy.count(), 0);
- QCOMPARE(moveSpy.count(), 1);
- QCOMPARE(hMoveSpy.count(), 1);
-
- QTest::mouseRelease(canvas, Qt::LeftButton, 0, QPoint(60, 50));
+ // Stop on a full pixel after user interaction
+ QCOMPARE(flickable->contentY(), (qreal)qRound(flickable->contentY()));
- QTRY_VERIFY(!flickable->isDraggingHorizontally());
- QVERIFY(!flickable->isDragging());
- QCOMPARE(vDragSpy.count(), 0);
- QCOMPARE(dragSpy.count(), 2);
- QCOMPARE(hDragSpy.count(), 2);
- QCOMPARE(dragStartSpy.count(), 1);
- QCOMPARE(dragEndSpy.count(), 1);
- // Don't test moving because a flick could occur
+ delete window;
+}
+void tst_qquickflickable::pressWhileFlicking()
+{
#ifdef Q_OS_MAC
QSKIP("Producing flicks on Mac CI impossible due to timing problems");
#endif
- QTRY_VERIFY(!flickable->isMoving());
+ QQuickView *window = new QQuickView;
+ window->setSource(testFileUrl("flickable03.qml"));
+ window->show();
+ window->requestActivateWindow();
+ QTest::qWaitForWindowShown(window);
+ QVERIFY(window->rootObject() != 0);
- vMoveSpy.clear();
- hMoveSpy.clear();
- moveSpy.clear();
- vFlickSpy.clear();
+ QQuickFlickable *flickable = qobject_cast<QQuickFlickable*>(window->rootObject());
+ QVERIFY(flickable != 0);
+
+ 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(canvas, QPoint(20,190), QPoint(20, 50), 200);
+ flick(window, QPoint(20,190), QPoint(20, 50), 200);
QVERIFY(flickable->verticalVelocity() > 0.0);
QVERIFY(flickable->isFlicking());
QVERIFY(flickable->isFlickingVertically());
QCOMPARE(hFlickSpy.count(), 0);
QCOMPARE(flickSpy.count(), 1);
- QTest::mousePress(canvas, Qt::LeftButton, 0, QPoint(20, 50));
+ QTest::mousePress(window, Qt::LeftButton, 0, QPoint(20, 50));
QTRY_VERIFY(!flickable->isFlicking());
QVERIFY(!flickable->isFlickingVertically());
QVERIFY(flickable->isMoving());
QVERIFY(flickable->isMovingVertically());
- QTest::mouseRelease(canvas, Qt::LeftButton, 0, QPoint(20,50));
+ QTest::mouseRelease(window, Qt::LeftButton, 0, 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()));
- delete canvas;
+ delete window;
}
void tst_qquickflickable::disabled()
{
- QQuickView *canvas = new QQuickView;
- canvas->setSource(testFileUrl("disabled.qml"));
- canvas->show();
- canvas->requestActivateWindow();
- QVERIFY(canvas->rootObject() != 0);
+ QQuickView *window = new QQuickView;
+ window->setSource(testFileUrl("disabled.qml"));
+ window->show();
+ window->requestActivateWindow();
+ QVERIFY(window->rootObject() != 0);
- QQuickFlickable *flick = canvas->rootObject()->findChild<QQuickFlickable*>("flickable");
+ QQuickFlickable *flick = window->rootObject()->findChild<QQuickFlickable*>("flickable");
QVERIFY(flick != 0);
- QTest::mousePress(canvas, Qt::LeftButton, 0, QPoint(50, 90));
+ QTest::mousePress(window, Qt::LeftButton, 0, QPoint(50, 90));
- QTest::mouseMove(canvas, QPoint(50, 80));
- QTest::mouseMove(canvas, QPoint(50, 70));
- QTest::mouseMove(canvas, QPoint(50, 60));
+ QTest::mouseMove(window, QPoint(50, 80));
+ QTest::mouseMove(window, QPoint(50, 70));
+ QTest::mouseMove(window, QPoint(50, 60));
QVERIFY(flick->isMoving() == false);
- QTest::mouseRelease(canvas, Qt::LeftButton, 0, QPoint(50, 60));
+ QTest::mouseRelease(window, Qt::LeftButton, 0, QPoint(50, 60));
// verify that mouse clicks on other elements still work (QTBUG-20584)
- QTest::mousePress(canvas, Qt::LeftButton, 0, QPoint(50, 10));
- QTest::mouseRelease(canvas, Qt::LeftButton, 0, QPoint(50, 10));
+ QTest::mousePress(window, Qt::LeftButton, 0, QPoint(50, 10));
+ QTest::mouseRelease(window, Qt::LeftButton, 0, QPoint(50, 10));
- QTRY_VERIFY(canvas->rootObject()->property("clicked").toBool() == true);
+ QTRY_VERIFY(window->rootObject()->property("clicked").toBool() == true);
}
void tst_qquickflickable::flickVelocity()
QSKIP("Producing flicks on Mac CI impossible due to timing problems");
#endif
- QQuickView *canvas = new QQuickView;
- canvas->setSource(testFileUrl("flickable03.qml"));
- canvas->show();
- canvas->requestActivateWindow();
- QVERIFY(canvas->rootObject() != 0);
+ QQuickView *window = new QQuickView;
+ window->setSource(testFileUrl("flickable03.qml"));
+ window->show();
+ window->requestActivateWindow();
+ QVERIFY(window->rootObject() != 0);
- QQuickFlickable *flickable = qobject_cast<QQuickFlickable*>(canvas->rootObject());
+ QQuickFlickable *flickable = qobject_cast<QQuickFlickable*>(window->rootObject());
QVERIFY(flickable != 0);
// flick up
- flick(canvas, QPoint(20,190), QPoint(20, 50), 200);
+ flick(window, QPoint(20,190), QPoint(20, 50), 200);
QVERIFY(flickable->verticalVelocity() > 0.0);
QTRY_VERIFY(flickable->verticalVelocity() == 0.0);
// flick down
- flick(canvas, QPoint(20,10), QPoint(20, 140), 200);
+ flick(window, QPoint(20,10), QPoint(20, 140), 200);
QVERIFY(flickable->verticalVelocity() < 0.0);
QTRY_VERIFY(flickable->verticalVelocity() == 0.0);
QQuickFlickablePrivate *fp = QQuickFlickablePrivate::get(flickable);
bool boosted = false;
for (int i = 0; i < 6; ++i) {
- flick(canvas, QPoint(20,390), QPoint(20, 50), 100);
+ flick(window, QPoint(20,390), QPoint(20, 50), 100);
boosted |= fp->flickBoost > 1.0;
}
QVERIFY(boosted);
// Flick in opposite direction -> boost cancelled.
- flick(canvas, QPoint(20,10), QPoint(20, 340), 200);
+ flick(window, QPoint(20,10), QPoint(20, 340), 200);
QTRY_VERIFY(flickable->verticalVelocity() < 0.0);
QVERIFY(fp->flickBoost == 1.0);
- delete canvas;
+ delete window;
}
void tst_qquickflickable::margins()
QCOMPARE(obj->contentY(), -20.);
QCOMPARE(obj->contentWidth(), 1600.);
QCOMPARE(obj->contentHeight(), 600.);
- QCOMPARE(obj->xOrigin(), 0.);
- QCOMPARE(obj->yOrigin(), 0.);
+ QCOMPARE(obj->originX(), 0.);
+ QCOMPARE(obj->originY(), 0.);
// Reduce left margin
obj->setLeftMargin(30);
delete root;
}
-void tst_qquickflickable::cancel()
+void tst_qquickflickable::cancelOnMouseGrab()
{
- QQuickView *canvas = new QQuickView;
- canvas->setSource(testFileUrl("cancel.qml"));
- canvas->show();
- canvas->requestActivateWindow();
- QVERIFY(canvas->rootObject() != 0);
+ QQuickView *window = new QQuickView;
+ window->setSource(testFileUrl("cancel.qml"));
+ window->show();
+ window->requestActivateWindow();
+ QVERIFY(window->rootObject() != 0);
- QQuickFlickable *flickable = qobject_cast<QQuickFlickable*>(canvas->rootObject());
+ QQuickFlickable *flickable = qobject_cast<QQuickFlickable*>(window->rootObject());
QVERIFY(flickable != 0);
- QTest::mousePress(canvas, Qt::LeftButton, 0, QPoint(10, 10));
+ QTest::mousePress(window, Qt::LeftButton, 0, QPoint(10, 10));
// drag out of bounds
- QTest::mouseMove(canvas, QPoint(50, 50));
- QTest::mouseMove(canvas, QPoint(100, 100));
- QTest::mouseMove(canvas, QPoint(150, 150));
+ QTest::mouseMove(window, QPoint(50, 50));
+ QTest::mouseMove(window, QPoint(100, 100));
+ QTest::mouseMove(window, QPoint(150, 150));
QVERIFY(flickable->contentX() != 0);
QVERIFY(flickable->contentY() != 0);
QVERIFY(flickable->isDragging());
// grabbing mouse will cancel flickable interaction.
- QQuickItem *item = canvas->rootObject()->findChild<QQuickItem*>("row");
+ QQuickItem *item = window->rootObject()->findChild<QQuickItem*>("row");
item->grabMouse();
QTRY_COMPARE(flickable->contentX(), 0.);
QTRY_VERIFY(!flickable->isMoving());
QTRY_VERIFY(!flickable->isDragging());
- QTest::mouseRelease(canvas, Qt::LeftButton, 0, QPoint(50, 10));
+ QTest::mouseRelease(window, Qt::LeftButton, 0, QPoint(50, 10));
}
+void tst_qquickflickable::clickAndDragWhenTransformed()
+{
+ QQuickView *view = new QQuickView;
+ view->setSource(testFileUrl("transformedFlickable.qml"));
+ view->show();
+ view->requestActivateWindow();
+ QTest::qWaitForWindowShown(view);
+ QVERIFY(view->rootObject() != 0);
+
+ QQuickFlickable *flickable = view->rootObject()->findChild<QQuickFlickable*>("flickable");
+ QVERIFY(flickable != 0);
+
+ // click outside child rect
+ QTest::mousePress(view, Qt::LeftButton, 0, QPoint(190, 190));
+ QTest::qWait(10);
+ QCOMPARE(flickable->property("itemPressed").toBool(), false);
+ QTest::mouseRelease(view, Qt::LeftButton, 0, QPoint(190, 190));
+
+ // click inside child rect
+ QTest::mousePress(view, Qt::LeftButton, 0, QPoint(200, 200));
+ QTest::qWait(10);
+ QCOMPARE(flickable->property("itemPressed").toBool(), true);
+ QTest::mouseRelease(view, Qt::LeftButton, 0, QPoint(200, 200));
+
+ const int threshold = qApp->styleHints()->startDragDistance();
+
+ // drag outside bounds
+ QTest::mousePress(view, Qt::LeftButton, 0, QPoint(160, 160));
+ QTest::qWait(10);
+ QTest::mouseMove(view, QPoint(160 + threshold * 2, 160));
+ QTest::mouseMove(view, QPoint(160 + threshold * 3, 160));
+ QCOMPARE(flickable->isDragging(), false);
+ QCOMPARE(flickable->property("itemPressed").toBool(), false);
+ QTest::mouseRelease(view, Qt::LeftButton, 0, QPoint(180, 160));
+
+ // drag inside bounds
+ QTest::mousePress(view, Qt::LeftButton, 0, QPoint(200, 140));
+ QTest::qWait(10);
+ QTest::mouseMove(view, QPoint(200 + threshold * 2, 140));
+ QTest::mouseMove(view, QPoint(200 + threshold * 3, 140));
+ QCOMPARE(flickable->isDragging(), true);
+ QCOMPARE(flickable->property("itemPressed").toBool(), false);
+ QTest::mouseRelease(view, Qt::LeftButton, 0, QPoint(220, 140));
+
+ delete view;
+}
QTEST_MAIN(tst_qquickflickable)