Stop flicking on a full pixel.
authorMartin Jones <martin.jones@nokia.com>
Fri, 20 Apr 2012 07:02:44 +0000 (17:02 +1000)
committerQt by Nokia <qt-info@nokia.com>
Tue, 8 May 2012 22:56:16 +0000 (00:56 +0200)
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 <michael.brasser@nokia.com>
src/quick/items/qquickflickable.cpp
tests/auto/quick/qquickflickable/tst_qquickflickable.cpp

index 853535e..d82f08b 100644 (file)
@@ -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;
index f926dbe..f767940 100644 (file)
@@ -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;
 }