From f67ba78760602642bd947abed261e84dadb9cfdf Mon Sep 17 00:00:00 2001 From: Martin Jones Date: Fri, 20 Apr 2012 17:02:44 +1000 Subject: [PATCH] Stop flicking on a full pixel. When the user flicks/moves the view, stop on a full pixel. This ensures optimal presentation when static without affecting the smoothness of animation. Change-Id: I2d8ae084151f56d8e569fde35fb498866ad60f9c Reviewed-by: Michael Brasser --- src/quick/items/qquickflickable.cpp | 28 ++++++++++++++++++++-- .../quick/qquickflickable/tst_qquickflickable.cpp | 12 ++++++++-- 2 files changed, 36 insertions(+), 4 deletions(-) diff --git a/src/quick/items/qquickflickable.cpp b/src/quick/items/qquickflickable.cpp index 853535e..d82f08b 100644 --- a/src/quick/items/qquickflickable.cpp +++ b/src/quick/items/qquickflickable.cpp @@ -300,11 +300,22 @@ void QQuickFlickablePrivate::flick(AxisData &data, qreal minExtent, qreal maxExt else v = maxVelocity; } + + // adjust accel so that we hit a full pixel + qreal accel = deceleration; + qreal v2 = v * v; + qreal dist = v2 / (accel * 2.0); + if (v > 0) + dist = -dist; + qreal target = qRound(data.move.value() - dist); + dist = -target + data.move.value(); + accel = v2 / (2.0f * qAbs(dist)); + timeline.reset(data.move); if (boundsBehavior == QQuickFlickable::DragAndOvershootBounds) - timeline.accel(data.move, v, deceleration); + timeline.accel(data.move, v, accel); else - timeline.accel(data.move, v, deceleration, maxDistance); + timeline.accel(data.move, v, accel, maxDistance); timeline.callback(QQuickTimeLineCallback(&data.move, fixupCallback, this)); if (!hData.flicking && q->xflick() && (&data == &hData)) { hData.flicking = true; @@ -390,6 +401,19 @@ void QQuickFlickablePrivate::fixup(AxisData &data, qreal minExtent, qreal maxExt data.fixingUp = true; } } + } else if (qRound(data.move.value()) != data.move.value()) { + // We could animate, but since it is less than 0.5 pixel it's probably not worthwhile. + timeline.reset(data.move); + qreal val = data.move.value(); + if (qAbs(qRound(val) - val) < 0.25) // round small differences + val = qRound(val); + else if (data.smoothVelocity.value() > 0) // continue direction of motion for larger + val = qFloor(val); + else if (data.smoothVelocity.value() < 0) + val = qCeil(val); + else // otherwise round + val = qRound(val); + timeline.set(data.move, val); } data.inOvershoot = false; fixupMode = Normal; diff --git a/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp b/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp index f926dbe..f767940 100644 --- a/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp +++ b/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp @@ -410,8 +410,6 @@ void tst_qquickflickable::movingAndDragging() QTest::mouseMove(canvas, QPoint(50, 70)); QTest::mouseMove(canvas, QPoint(50, 60)); - QMouseEvent moveEvent(QEvent::MouseMove, QPoint(50, 80), Qt::LeftButton, Qt::LeftButton, 0); - QVERIFY(!flickable->isDraggingHorizontally()); QVERIFY(flickable->isDraggingVertically()); QVERIFY(flickable->isDragging()); @@ -441,6 +439,9 @@ void tst_qquickflickable::movingAndDragging() // wait for any motion to end QTRY_VERIFY(flickable->isMoving() == false); + // Stop on a full pixel after user interaction + QCOMPARE(flickable->contentY(), (qreal)qRound(flickable->contentY())); + // 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. @@ -457,6 +458,9 @@ void tst_qquickflickable::movingAndDragging() // wait for any motion to end QTRY_VERIFY(flickable->isMoving() == false); + // Stop on a full pixel after user interaction + QCOMPARE(flickable->contentY(), (qreal)qRound(flickable->contentY())); + //Horizontal vDragSpy.clear(); hDragSpy.clear(); @@ -505,6 +509,8 @@ void tst_qquickflickable::movingAndDragging() #endif QTRY_VERIFY(!flickable->isMoving()); + // Stop on a full pixel after user interaction + QCOMPARE(flickable->contentX(), (qreal)qRound(flickable->contentX())); vMoveSpy.clear(); hMoveSpy.clear(); @@ -541,6 +547,8 @@ void tst_qquickflickable::movingAndDragging() 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; } -- 2.7.4