aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/quick/items/qquickflickable.cpp163
-rw-r--r--src/quick/items/qquickflickable_p.h3
-rw-r--r--src/quick/items/qquickflickable_p_p.h7
-rw-r--r--src/quick/items/qquickgridview.cpp22
-rw-r--r--src/quick/items/qquicklistview.cpp28
-rw-r--r--tests/auto/quick/qquickflickable/data/flickable03.qml2
-rw-r--r--tests/auto/quick/qquickflickable/tst_qquickflickable.cpp434
7 files changed, 473 insertions, 186 deletions
diff --git a/src/quick/items/qquickflickable.cpp b/src/quick/items/qquickflickable.cpp
index a80f714fa7..c207c77458 100644
--- a/src/quick/items/qquickflickable.cpp
+++ b/src/quick/items/qquickflickable.cpp
@@ -267,19 +267,19 @@ void QQuickFlickablePrivate::itemGeometryChanged(QQuickItem *item, const QRectF
}
}
-void QQuickFlickablePrivate::flickX(qreal velocity)
+bool QQuickFlickablePrivate::flickX(qreal velocity)
{
Q_Q(QQuickFlickable);
- flick(hData, q->minXExtent(), q->maxXExtent(), q->width(), fixupX_callback, velocity);
+ return flick(hData, q->minXExtent(), q->maxXExtent(), q->width(), fixupX_callback, velocity);
}
-void QQuickFlickablePrivate::flickY(qreal velocity)
+bool QQuickFlickablePrivate::flickY(qreal velocity)
{
Q_Q(QQuickFlickable);
- flick(vData, q->minYExtent(), q->maxYExtent(), q->height(), fixupY_callback, velocity);
+ return flick(vData, q->minYExtent(), q->maxYExtent(), q->height(), fixupY_callback, velocity);
}
-void QQuickFlickablePrivate::flick(AxisData &data, qreal minExtent, qreal maxExtent, qreal,
+bool QQuickFlickablePrivate::flick(AxisData &data, qreal minExtent, qreal maxExtent, qreal,
QQuickTimeLineCallback::Callback fixupCallback, qreal velocity)
{
Q_Q(QQuickFlickable);
@@ -318,23 +318,16 @@ void QQuickFlickablePrivate::flick(AxisData &data, qreal minExtent, qreal maxExt
else
timeline.accel(data.move, v, accel, maxDistance);
timeline.callback(QQuickTimeLineCallback(&data.move, fixupCallback, this));
- if (!hData.flicking && q->xflick() && (&data == &hData)) {
- hData.flicking = true;
- emit q->flickingChanged();
- emit q->flickingHorizontallyChanged();
- if (!vData.flicking)
- emit q->flickStarted();
- }
- if (!vData.flicking && q->yflick() && (&data == &vData)) {
- vData.flicking = true;
- emit q->flickingChanged();
- emit q->flickingVerticallyChanged();
- if (!hData.flicking)
- emit q->flickStarted();
- }
+
+ if (&data == &hData)
+ return !hData.flicking && q->xflick();
+ else if (&data == &vData)
+ return !vData.flicking && q->yflick();
+ return false;
} else {
timeline.reset(data.move);
fixup(data, minExtent, maxExtent);
+ return false;
}
}
@@ -641,7 +634,7 @@ void QQuickFlickable::setContentX(qreal pos)
d->hData.explicitValue = true;
d->timeline.reset(d->hData.move);
d->vTime = d->timeline.time();
- movementXEnding();
+ movementEnding(true, false);
if (-pos != d->hData.move.value())
d->hData.move.setValue(-pos);
}
@@ -658,7 +651,7 @@ void QQuickFlickable::setContentY(qreal pos)
d->vData.explicitValue = true;
d->timeline.reset(d->vData.move);
d->vTime = d->timeline.time();
- movementYEnding();
+ movementEnding(false, true);
if (-pos != d->vData.move.value())
d->vData.move.setValue(-pos);
}
@@ -1083,24 +1076,27 @@ void QQuickFlickablePrivate::handleMouseReleaseEvent(QMouseEvent *event)
flickBoost = canBoost ? qBound(1.0, flickBoost+0.25, QML_FLICK_MULTIFLICK_MAXBOOST) : 1.0;
+ bool flickedV = false;
vVelocity *= flickBoost;
if (q->yflick() && qAbs(vVelocity) > MinimumFlickVelocity && qAbs(event->localPos().y() - pressPos.y()) > FlickThreshold) {
velocityTimeline.reset(vData.smoothVelocity);
vData.smoothVelocity.setValue(-vVelocity);
- flickY(vVelocity);
+ flickedV = flickY(vVelocity);
} else {
fixupY();
}
+ bool flickedH = false;
hVelocity *= flickBoost;
if (q->xflick() && qAbs(hVelocity) > MinimumFlickVelocity && qAbs(event->localPos().x() - pressPos.x()) > FlickThreshold) {
velocityTimeline.reset(hData.smoothVelocity);
hData.smoothVelocity.setValue(-hVelocity);
- flickX(hVelocity);
+ flickedH = flickX(hVelocity);
} else {
fixupX();
}
+ flickingStarted(flickedH, flickedV);
if (!timeline.isActive())
q->movementEnding();
}
@@ -1159,6 +1155,7 @@ void QQuickFlickable::wheelEvent(QWheelEvent *event)
if (valid) {
d->vData.flicking = false;
d->flickY(d->vData.velocity);
+ d->flickingStarted(false, true);
if (d->vData.flicking) {
d->vMoved = true;
movementStarting();
@@ -1177,6 +1174,7 @@ void QQuickFlickable::wheelEvent(QWheelEvent *event)
if (valid) {
d->hData.flicking = false;
d->flickX(d->hData.velocity);
+ d->flickingStarted(true, false);
if (d->hData.flicking) {
d->hMoved = true;
movementStarting();
@@ -1411,8 +1409,30 @@ void QQuickFlickable::geometryChanged(const QRectF &newGeometry,
void QQuickFlickable::flick(qreal xVelocity, qreal yVelocity)
{
Q_D(QQuickFlickable);
- d->flickX(xVelocity);
- d->flickY(yVelocity);
+ bool flickedX = d->flickX(xVelocity);
+ bool flickedY = d->flickY(yVelocity);
+ d->flickingStarted(flickedX, flickedY);
+}
+
+void QQuickFlickablePrivate::flickingStarted(bool flickingH, bool flickingV)
+{
+ Q_Q(QQuickFlickable);
+ if (!flickingH && !flickingV)
+ return;
+
+ bool wasFlicking = hData.flicking || vData.flicking;
+ if (flickingH && !hData.flicking) {
+ hData.flicking = true;
+ emit q->flickingHorizontallyChanged();
+ }
+ if (flickingV && !vData.flicking) {
+ vData.flicking = true;
+ emit q->flickingVerticallyChanged();
+ }
+ if (!wasFlicking && (hData.flicking || vData.flicking)) {
+ emit q->flickingChanged();
+ emit q->flickStarted();
+ }
}
/*!
@@ -2091,75 +2111,72 @@ bool QQuickFlickable::isMovingVertically() const
void QQuickFlickable::movementStarting()
{
Q_D(QQuickFlickable);
+ bool wasMoving = d->hData.moving || d->vData.moving;
if (d->hMoved && !d->hData.moving) {
d->hData.moving = true;
- emit movingChanged();
emit movingHorizontallyChanged();
- if (!d->vData.moving)
- emit movementStarted();
}
- else if (d->vMoved && !d->vData.moving) {
+ if (d->vMoved && !d->vData.moving) {
d->vData.moving = true;
- emit movingChanged();
emit movingVerticallyChanged();
- if (!d->hData.moving)
- emit movementStarted();
+ }
+ if (!wasMoving && (d->hData.moving || d->vData.moving)) {
+ emit movingChanged();
+ emit movementStarted();
}
}
void QQuickFlickable::movementEnding()
{
- Q_D(QQuickFlickable);
- movementXEnding();
- movementYEnding();
- d->hData.smoothVelocity.setValue(0);
- d->vData.smoothVelocity.setValue(0);
+ movementEnding(true, true);
}
-void QQuickFlickable::movementXEnding()
+void QQuickFlickable::movementEnding(bool hMovementEnding, bool vMovementEnding)
{
Q_D(QQuickFlickable);
- if (d->hData.flicking) {
+
+ // emit flicking signals
+ bool wasFlicking = d->hData.flicking || d->vData.flicking;
+ if (hMovementEnding && d->hData.flicking) {
d->hData.flicking = false;
- emit flickingChanged();
emit flickingHorizontallyChanged();
- if (!d->vData.flicking)
- emit flickEnded();
- }
- if (!d->pressed && !d->stealMouse) {
- if (d->hData.moving) {
- d->hData.moving = false;
- d->hMoved = false;
- emit movingChanged();
- emit movingHorizontallyChanged();
- if (!d->vData.moving)
- emit movementEnded();
- }
}
- d->hData.fixingUp = false;
-}
-
-void QQuickFlickable::movementYEnding()
-{
- Q_D(QQuickFlickable);
- if (d->vData.flicking) {
+ if (vMovementEnding && d->vData.flicking) {
d->vData.flicking = false;
- emit flickingChanged();
emit flickingVerticallyChanged();
- if (!d->hData.flicking)
- emit flickEnded();
- }
- if (!d->pressed && !d->stealMouse) {
- if (d->vData.moving) {
- d->vData.moving = false;
- d->vMoved = false;
- emit movingChanged();
- emit movingVerticallyChanged();
- if (!d->hData.moving)
- emit movementEnded();
- }
}
- d->vData.fixingUp = false;
+ if (wasFlicking && (!d->hData.flicking || !d->vData.flicking)) {
+ emit flickingChanged();
+ emit flickEnded();
+ }
+
+ // emit moving signals
+ bool wasMoving = d->hData.moving || d->vData.moving;
+ if (hMovementEnding && d->hData.moving
+ && (!d->pressed && !d->stealMouse)) {
+ d->hData.moving = false;
+ d->hMoved = false;
+ emit movingHorizontallyChanged();
+ }
+ if (vMovementEnding && d->vData.moving
+ && (!d->pressed && !d->stealMouse)) {
+ d->vData.moving = false;
+ d->vMoved = false;
+ emit movingVerticallyChanged();
+ }
+ if (wasMoving && (!d->hData.moving || !d->vData.moving)) {
+ emit movingChanged();
+ emit movementEnded();
+ }
+
+ if (hMovementEnding) {
+ d->hData.fixingUp = false;
+ d->hData.smoothVelocity.setValue(0);
+ }
+ if (vMovementEnding) {
+ d->vData.fixingUp = false;
+ d->vData.smoothVelocity.setValue(0);
+ }
}
void QQuickFlickablePrivate::updateVelocity()
diff --git a/src/quick/items/qquickflickable_p.h b/src/quick/items/qquickflickable_p.h
index 109bca2112..08aa487951 100644
--- a/src/quick/items/qquickflickable_p.h
+++ b/src/quick/items/qquickflickable_p.h
@@ -237,10 +237,9 @@ protected:
protected Q_SLOTS:
void movementStarting();
void movementEnding();
+ void movementEnding(bool hMovementEnding, bool vMovementEnding);
protected:
- void movementXEnding();
- void movementYEnding();
virtual qreal minXExtent() const;
virtual qreal minYExtent() const;
virtual qreal maxXExtent() const;
diff --git a/src/quick/items/qquickflickable_p_p.h b/src/quick/items/qquickflickable_p_p.h
index ac6f2fffed..ab3070e5b1 100644
--- a/src/quick/items/qquickflickable_p_p.h
+++ b/src/quick/items/qquickflickable_p_p.h
@@ -145,10 +145,11 @@ public:
mutable bool maxExtentDirty : 1;
};
- void flickX(qreal velocity);
- void flickY(qreal velocity);
- virtual void flick(AxisData &data, qreal minExtent, qreal maxExtent, qreal vSize,
+ bool flickX(qreal velocity);
+ bool flickY(qreal velocity);
+ virtual bool flick(AxisData &data, qreal minExtent, qreal maxExtent, qreal vSize,
QQuickTimeLineCallback::Callback fixupCallback, qreal velocity);
+ void flickingStarted(bool flickingH, bool flickingV);
void fixupX();
void fixupY();
diff --git a/src/quick/items/qquickgridview.cpp b/src/quick/items/qquickgridview.cpp
index 3315deaebf..235005b758 100644
--- a/src/quick/items/qquickgridview.cpp
+++ b/src/quick/items/qquickgridview.cpp
@@ -229,7 +229,7 @@ public:
virtual void updateViewport();
virtual void fixupPosition();
virtual void fixup(AxisData &data, qreal minExtent, qreal maxExtent);
- virtual void flick(QQuickItemViewPrivate::AxisData &data, qreal minExtent, qreal maxExtent, qreal vSize,
+ virtual bool flick(QQuickItemViewPrivate::AxisData &data, qreal minExtent, qreal maxExtent, qreal vSize,
QQuickTimeLineCallback::Callback fixupCallback, qreal velocity);
QQuickGridView::Flow flow;
@@ -1023,16 +1023,14 @@ void QQuickGridViewPrivate::fixup(AxisData &data, qreal minExtent, qreal maxExte
fixupMode = Normal;
}
-void QQuickGridViewPrivate::flick(AxisData &data, qreal minExtent, qreal maxExtent, qreal vSize,
+bool QQuickGridViewPrivate::flick(AxisData &data, qreal minExtent, qreal maxExtent, qreal vSize,
QQuickTimeLineCallback::Callback fixupCallback, qreal velocity)
{
- Q_Q(QQuickGridView);
data.fixingUp = false;
moveReason = Mouse;
if ((!haveHighlightRange || highlightRange != QQuickGridView::StrictlyEnforceRange)
&& snapMode == QQuickGridView::NoSnap) {
- QQuickItemViewPrivate::flick(data, minExtent, maxExtent, vSize, fixupCallback, velocity);
- return;
+ return QQuickItemViewPrivate::flick(data, minExtent, maxExtent, vSize, fixupCallback, velocity);
}
qreal maxDistance = 0;
qreal dataValue = isContentFlowReversed() ? -data.move.value()+size() : data.move.value();
@@ -1125,21 +1123,11 @@ void QQuickGridViewPrivate::flick(AxisData &data, qreal minExtent, qreal maxExte
timeline.reset(data.move);
timeline.accel(data.move, v, accel, maxDistance + overshootDist);
timeline.callback(QQuickTimeLineCallback(&data.move, fixupCallback, this));
- if (!hData.flicking && q->xflick()) {
- hData.flicking = true;
- emit q->flickingChanged();
- emit q->flickingHorizontallyChanged();
- emit q->flickStarted();
- }
- if (!vData.flicking && q->yflick()) {
- vData.flicking = true;
- emit q->flickingChanged();
- emit q->flickingVerticallyChanged();
- emit q->flickStarted();
- }
+ return true;
} else {
timeline.reset(data.move);
fixup(data, minExtent, maxExtent);
+ return false;
}
}
diff --git a/src/quick/items/qquicklistview.cpp b/src/quick/items/qquicklistview.cpp
index 48cdee8ea2..e2de19b498 100644
--- a/src/quick/items/qquicklistview.cpp
+++ b/src/quick/items/qquicklistview.cpp
@@ -132,7 +132,7 @@ public:
void itemGeometryChanged(QQuickItem *item, const QRectF &newGeometry, const QRectF &oldGeometry);
virtual void fixupPosition();
virtual void fixup(AxisData &data, qreal minExtent, qreal maxExtent);
- virtual void flick(QQuickItemViewPrivate::AxisData &data, qreal minExtent, qreal maxExtent, qreal vSize,
+ virtual bool flick(QQuickItemViewPrivate::AxisData &data, qreal minExtent, qreal maxExtent, qreal vSize,
QQuickTimeLineCallback::Callback fixupCallback, qreal velocity);
QQuickListView::Orientation orient;
@@ -1471,17 +1471,14 @@ void QQuickListViewPrivate::fixup(AxisData &data, qreal minExtent, qreal maxExte
fixupMode = Normal;
}
-void QQuickListViewPrivate::flick(AxisData &data, qreal minExtent, qreal maxExtent, qreal vSize,
+bool QQuickListViewPrivate::flick(AxisData &data, qreal minExtent, qreal maxExtent, qreal vSize,
QQuickTimeLineCallback::Callback fixupCallback, qreal velocity)
{
- Q_Q(QQuickListView);
-
data.fixingUp = false;
moveReason = Mouse;
if ((!haveHighlightRange || highlightRange != QQuickListView::StrictlyEnforceRange) && snapMode == QQuickListView::NoSnap) {
correctFlick = true;
- QQuickItemViewPrivate::flick(data, minExtent, maxExtent, vSize, fixupCallback, velocity);
- return;
+ return QQuickItemViewPrivate::flick(data, minExtent, maxExtent, vSize, fixupCallback, velocity);
}
qreal maxDistance = 0;
qreal dataValue = isContentFlowReversed() ? -data.move.value()+size() : data.move.value();
@@ -1587,19 +1584,8 @@ void QQuickListViewPrivate::flick(AxisData &data, qreal minExtent, qreal maxExte
timeline.reset(data.move);
timeline.accel(data.move, v, accel, maxDistance + overshootDist);
timeline.callback(QQuickTimeLineCallback(&data.move, fixupCallback, this));
- if (!hData.flicking && q->xflick()) {
- hData.flicking = true;
- emit q->flickingChanged();
- emit q->flickingHorizontallyChanged();
- emit q->flickStarted();
- }
- if (!vData.flicking && q->yflick()) {
- vData.flicking = true;
- emit q->flickingChanged();
- emit q->flickingVerticallyChanged();
- emit q->flickStarted();
- }
correctFlick = true;
+ return true;
} else {
// reevaluate the target boundary.
qreal newtarget = data.flickTarget;
@@ -1615,7 +1601,7 @@ void QQuickListViewPrivate::flick(AxisData &data, qreal minExtent, qreal maxExte
if (newtarget == data.flickTarget) { // boundary unchanged - nothing to do
if (qAbs(velocity) < MinimumFlickVelocity)
correctFlick = false;
- return;
+ return false;
}
data.flickTarget = newtarget;
qreal dist = -newtarget + data.move.value();
@@ -1623,16 +1609,18 @@ void QQuickListViewPrivate::flick(AxisData &data, qreal minExtent, qreal maxExte
correctFlick = false;
timeline.reset(data.move);
fixup(data, minExtent, maxExtent);
- return;
+ return false;
}
timeline.reset(data.move);
timeline.accelDistance(data.move, v, -dist);
timeline.callback(QQuickTimeLineCallback(&data.move, fixupCallback, this));
+ return false;
}
} else {
correctFlick = false;
timeline.reset(data.move);
fixup(data, minExtent, maxExtent);
+ return false;
}
}
diff --git a/tests/auto/quick/qquickflickable/data/flickable03.qml b/tests/auto/quick/qquickflickable/data/flickable03.qml
index 719c682ee6..a3e9d6fd59 100644
--- a/tests/auto/quick/qquickflickable/data/flickable03.qml
+++ b/tests/auto/quick/qquickflickable/data/flickable03.qml
@@ -8,7 +8,7 @@ Flickable {
id: column
Repeater {
model: 20
- Rectangle { width: 200; height: 300; color: "blue" }
+ Rectangle { width: 200; height: 300; border.width: 1; color: "yellow" }
}
}
}
diff --git a/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp b/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp
index 39d1075e53..7438320b9b 100644
--- a/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp
+++ b/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp
@@ -73,7 +73,12 @@ private slots:
void resizeContent();
void returnToBounds();
void wheel();
+ void movingAndFlicking();
+ void movingAndFlicking_data();
void movingAndDragging();
+ void movingAndDragging_data();
+ void flickOnRelease();
+ void pressWhileFlicking();
void disabled();
void flickVelocity();
void margins();
@@ -382,12 +387,206 @@ void tst_qquickflickable::wheel()
delete canvas;
}
+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 *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());
+ 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(canvas, 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(canvas, 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 canvas;
+}
+
+
+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()
{
#ifdef Q_OS_MAC
QSKIP("Producing flicks on Mac CI impossible due to timing problems");
#endif
+ QFETCH(bool, verticalEnabled);
+ QFETCH(bool, horizontalEnabled);
+ QFETCH(QPoint, moveByWithoutSnapBack);
+ QFETCH(QPoint, moveByWithSnapBack);
+
+ const QPoint moveFrom(50, 200); // centre
+
QQuickView *canvas = new QQuickView;
canvas->setSource(testFileUrl("flickable03.qml"));
canvas->show();
@@ -404,47 +603,170 @@ void tst_qquickflickable::movingAndDragging()
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));
+ // start the drag
+ QTest::mousePress(canvas, Qt::LeftButton, 0, moveFrom);
+ QTest::mouseMove(canvas, moveFrom + moveByWithoutSnapBack);
+ QTest::mouseMove(canvas, moveFrom + moveByWithoutSnapBack*2);
+ QTest::mouseMove(canvas, moveFrom + moveByWithoutSnapBack*3);
- QTest::mouseMove(canvas, QPoint(50, 80));
- QTest::mouseMove(canvas, QPoint(50, 70));
- QTest::mouseMove(canvas, QPoint(50, 60));
-
- 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);
- QTest::mouseRelease(canvas, Qt::LeftButton, 0, QPoint(50, 60));
+ QCOMPARE(moveStartSpy.count(), 1);
+ QCOMPARE(dragStartSpy.count(), 1);
+
+ QTest::mouseRelease(canvas, 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
- QCOMPARE(flickable->contentY(), (qreal)qRound(flickable->contentY()));
+ 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(canvas, Qt::LeftButton, 0, moveFrom);
+ QTest::mouseMove(canvas, moveFrom + moveByWithSnapBack);
+ QTest::mouseMove(canvas, moveFrom + moveByWithSnapBack*2);
+ QTest::mouseMove(canvas, 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(canvas, 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 canvas;
+}
+
+void tst_qquickflickable::flickOnRelease()
+{
+#ifdef Q_OS_MAC
+ 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();
+ QTest::qWaitForWindowShown(canvas);
+ QVERIFY(canvas->rootObject() != 0);
+
+ QQuickFlickable *flickable = qobject_cast<QQuickFlickable*>(canvas->rootObject());
+ QVERIFY(flickable != 0);
// Vertical with a quick press-move-release: should cause a flick in release.
QSignalSpy vFlickSpy(flickable, SIGNAL(flickingVerticallyChanged()));
@@ -465,58 +787,30 @@ void tst_qquickflickable::movingAndDragging()
// Stop on a full pixel after user interaction
QCOMPARE(flickable->contentY(), (qreal)qRound(flickable->contentY()));
- //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);
+ delete canvas;
+}
- QTest::mouseRelease(canvas, Qt::LeftButton, 0, QPoint(60, 50));
+void tst_qquickflickable::pressWhileFlicking()
+{
+#ifdef Q_OS_MAC
+ QSKIP("Producing flicks on Mac CI impossible due to timing problems");
+#endif
- 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
+ QQuickView *canvas = new QQuickView;
+ canvas->setSource(testFileUrl("flickable03.qml"));
+ canvas->show();
+ canvas->requestActivateWindow();
+ QTest::qWaitForWindowShown(canvas);
+ QVERIFY(canvas->rootObject() != 0);
- QTRY_VERIFY(!flickable->isMoving());
- // Stop on a full pixel after user interaction
- QCOMPARE(flickable->contentX(), (qreal)qRound(flickable->contentX()));
+ QQuickFlickable *flickable = qobject_cast<QQuickFlickable*>(canvas->rootObject());
+ QVERIFY(flickable != 0);
- vMoveSpy.clear();
- hMoveSpy.clear();
- moveSpy.clear();
- vFlickSpy.clear();
+ 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