Update Flickable velocity/overbound for each axis independently
authorMartin Jones <martin.jones@nokia.com>
Wed, 13 Jun 2012 01:17:44 +0000 (11:17 +1000)
committerQt by Nokia <qt-info@nokia.com>
Wed, 13 Jun 2012 07:07:03 +0000 (09:07 +0200)
We were attempting to update velocities/overbound correction for both
axes even if only one of them had changed, leading to inaccurate values
for one of the axes.  Also removes a bunch of code duplication.

Change-Id: I6a50b908992c976889373f541bdd1abad462e247
Reviewed-by: Bea Lam <bea.lam@nokia.com>
src/quick/items/qquickflickable.cpp
src/quick/items/qquickflickable_p.h
src/quick/items/qquickflickable_p_p.h
src/quick/items/qquickgridview.cpp
src/quick/items/qquickgridview_p.h
src/quick/items/qquicklistview.cpp
src/quick/items/qquicklistview_p.h

index 57fb712..9e65d96 100644 (file)
@@ -330,13 +330,16 @@ void QQuickFlickablePrivate::itemGeometryChanged(QQuickItem *item, const QRectF
 {
     Q_Q(QQuickFlickable);
     if (item == contentItem) {
-        bool xChanged = newGeom.x() != oldGeom.x();
-        bool yChanged = newGeom.y() != oldGeom.y();
-        if (xChanged || yChanged)
-            q->viewportMoved();
-        if (xChanged)
+        Qt::Orientations orient = 0;
+        if (newGeom.x() != oldGeom.x())
+            orient |= Qt::Horizontal;
+        if (newGeom.y() != oldGeom.y())
+            orient |= Qt::Vertical;
+        if (orient)
+            q->viewportMoved(orient);
+        if (orient & Qt::Horizontal)
             emit q->contentXChanged();
-        if (yChanged)
+        if (orient & Qt::Vertical)
             emit q->contentYChanged();
     }
 }
@@ -496,7 +499,7 @@ void QQuickFlickablePrivate::fixup(AxisData &data, qreal minExtent, qreal maxExt
     }
     data.inOvershoot = false;
     fixupMode = Normal;
-    vTime = timeline.time();
+    data.vTime = timeline.time();
 }
 
 void QQuickFlickablePrivate::updateBeginningEnd()
@@ -718,7 +721,7 @@ void QQuickFlickable::setContentX(qreal pos)
     Q_D(QQuickFlickable);
     d->hData.explicitValue = true;
     d->resetTimeline(d->hData);
-    d->vTime = d->timeline.time();
+    d->hData.vTime = d->timeline.time();
     movementEnding(true, false);
     if (-pos != d->hData.move.value())
         d->hData.move.setValue(-pos);
@@ -735,7 +738,7 @@ void QQuickFlickable::setContentY(qreal pos)
     Q_D(QQuickFlickable);
     d->vData.explicitValue = true;
     d->resetTimeline(d->vData);
-    d->vTime = d->timeline.time();
+    d->vData.vTime = d->timeline.time();
     movementEnding(false, true);
     if (-pos != d->vData.move.value())
         d->vData.move.setValue(-pos);
@@ -767,7 +770,7 @@ void QQuickFlickable::setInteractive(bool interactive)
         d->interactive = interactive;
         if (!interactive && (d->hData.flicking || d->vData.flicking)) {
             d->clearTimeline();
-            d->vTime = d->timeline.time();
+            d->hData.vTime = d->vData.vTime = d->timeline.time();
             d->hData.flicking = false;
             d->vData.flicking = false;
             emit flickingChanged();
@@ -982,7 +985,8 @@ void QQuickFlickablePrivate::handleMousePressEvent(QMouseEvent *event)
     if (wasFlicking)
         emit q->flickingChanged();
     lastPosTime = lastPressTime = computeCurrentTime(event);
-    QQuickItemPrivate::start(velocityTime);
+    QQuickItemPrivate::start(vData.velocityTime);
+    QQuickItemPrivate::start(hData.velocityTime);
 }
 
 void QQuickFlickablePrivate::handleMouseMoveEvent(QMouseEvent *event)
@@ -1131,7 +1135,7 @@ void QQuickFlickablePrivate::handleMouseReleaseEvent(QMouseEvent *event)
     if (lastPosTime == -1)
         return;
 
-    vTime = timeline.time();
+    hData.vTime = vData.vTime = timeline.time();
 
     bool canBoost = false;
 
@@ -1382,77 +1386,57 @@ void QQuickFlickable::componentComplete()
         setContentY(-minYExtent());
 }
 
-void QQuickFlickable::viewportMoved()
+void QQuickFlickable::viewportMoved(Qt::Orientations orient)
 {
     Q_D(QQuickFlickable);
+    if (orient & Qt::Vertical)
+        d->viewportAxisMoved(d->vData, minYExtent(), maxYExtent(), height(), d->fixupY_callback);
+    if (orient & Qt::Horizontal)
+        d->viewportAxisMoved(d->hData, minXExtent(), maxXExtent(), width(), d->fixupX_callback);
+    d->updateBeginningEnd();
+}
 
-    qreal prevX = d->lastFlickablePosition.x();
-    qreal prevY = d->lastFlickablePosition.y();
-    if (d->pressed || d->calcVelocity) {
-        int elapsed = QQuickItemPrivate::restart(d->velocityTime);
+void QQuickFlickablePrivate::viewportAxisMoved(AxisData &data, qreal minExtent, qreal maxExtent, qreal vSize,
+                                           QQuickTimeLineCallback::Callback fixupCallback)
+{
+    if (pressed || calcVelocity) {
+        int elapsed = QQuickItemPrivate::restart(data.velocityTime);
         if (elapsed > 0) {
-            qreal horizontalVelocity = (prevX - d->hData.move.value()) * 1000 / elapsed;
-            if (qAbs(horizontalVelocity) > 0) {
-                d->velocityTimeline.reset(d->hData.smoothVelocity);
-                if (d->calcVelocity)
-                    d->velocityTimeline.set(d->hData.smoothVelocity, horizontalVelocity);
+            qreal velocity = (data.lastPos - data.move.value()) * 1000 / elapsed;
+            if (qAbs(velocity) > 0) {
+                velocityTimeline.reset(data.smoothVelocity);
+                if (calcVelocity)
+                    velocityTimeline.set(data.smoothVelocity, velocity);
                 else
-                    d->velocityTimeline.move(d->hData.smoothVelocity, horizontalVelocity, d->reportedVelocitySmoothing);
-                d->velocityTimeline.move(d->hData.smoothVelocity, 0, d->reportedVelocitySmoothing);
-            }
-            qreal verticalVelocity = (prevY - d->vData.move.value()) * 1000 / elapsed;
-            if (qAbs(verticalVelocity) > 0) {
-                d->velocityTimeline.reset(d->vData.smoothVelocity);
-                if (d->calcVelocity)
-                    d->velocityTimeline.set(d->vData.smoothVelocity, verticalVelocity);
-                else
-                    d->velocityTimeline.move(d->vData.smoothVelocity, verticalVelocity, d->reportedVelocitySmoothing);
-                d->velocityTimeline.move(d->vData.smoothVelocity, 0, d->reportedVelocitySmoothing);
+                    velocityTimeline.move(data.smoothVelocity, velocity, reportedVelocitySmoothing);
+                velocityTimeline.move(data.smoothVelocity, 0, reportedVelocitySmoothing);
             }
         }
     } else {
-        if (d->timeline.time() > d->vTime) {
-            d->velocityTimeline.clear();
-            qreal horizontalVelocity = (prevX - d->hData.move.value()) * 1000 / (d->timeline.time() - d->vTime);
-            qreal verticalVelocity = (prevY - d->vData.move.value()) * 1000 / (d->timeline.time() - d->vTime);
-            d->hData.smoothVelocity.setValue(horizontalVelocity);
-            d->vData.smoothVelocity.setValue(verticalVelocity);
+        if (timeline.time() > data.vTime) {
+            velocityTimeline.reset(data.smoothVelocity);
+            qreal velocity = (data.lastPos - data.move.value()) * 1000 / (timeline.time() - data.vTime);
+            data.smoothVelocity.setValue(velocity);
         }
     }
 
-    if (!d->vData.inOvershoot && !d->vData.fixingUp && d->vData.flicking
-            && (d->vData.move.value() > minYExtent() || d->vData.move.value() < maxYExtent())
-            && qAbs(d->vData.smoothVelocity.value()) > 10) {
-        // Increase deceleration if we've passed a bound
-        qreal overBound = d->vData.move.value() > minYExtent()
-                ? d->vData.move.value() - minYExtent()
-                : maxYExtent() - d->vData.move.value();
-        d->vData.inOvershoot = true;
-        qreal maxDistance = d->overShootDistance(height()) - overBound;
-        d->resetTimeline(d->vData);
-        if (maxDistance > 0)
-            d->timeline.accel(d->vData.move, -d->vData.smoothVelocity.value(), d->deceleration*QML_FLICK_OVERSHOOTFRICTION, maxDistance);
-        d->timeline.callback(QQuickTimeLineCallback(&d->vData.move, d->fixupY_callback, d));
-    }
-    if (!d->hData.inOvershoot && !d->hData.fixingUp && d->hData.flicking
-            && (d->hData.move.value() > minXExtent() || d->hData.move.value() < maxXExtent())
-            && qAbs(d->hData.smoothVelocity.value()) > 10) {
+    if (!data.inOvershoot && !data.fixingUp && data.flicking
+            && (data.move.value() > minExtent || data.move.value() < maxExtent)
+            && qAbs(data.smoothVelocity.value()) > 10) {
         // Increase deceleration if we've passed a bound
-        qreal overBound = d->hData.move.value() > minXExtent()
-                ? d->hData.move.value() - minXExtent()
-                : maxXExtent() - d->hData.move.value();
-        d->hData.inOvershoot = true;
-        qreal maxDistance = d->overShootDistance(width()) - overBound;
-        d->resetTimeline(d->hData);
+        qreal overBound = data.move.value() > minExtent
+                ? data.move.value() - minExtent
+                : maxExtent - data.move.value();
+        data.inOvershoot = true;
+        qreal maxDistance = overShootDistance(vSize) - overBound;
+        resetTimeline(data);
         if (maxDistance > 0)
-            d->timeline.accel(d->hData.move, -d->hData.smoothVelocity.value(), d->deceleration*QML_FLICK_OVERSHOOTFRICTION, maxDistance);
-        d->timeline.callback(QQuickTimeLineCallback(&d->hData.move, d->fixupX_callback, d));
+            timeline.accel(data.move, -data.smoothVelocity.value(), deceleration*QML_FLICK_OVERSHOOTFRICTION, maxDistance);
+        timeline.callback(QQuickTimeLineCallback(&data.move, fixupCallback, this));
     }
 
-    d->lastFlickablePosition = QPointF(d->hData.move.value(), d->vData.move.value());
-
-    d->vTime = d->timeline.time();
-    d->updateBeginningEnd();
+    data.lastPos = data.move.value();
+    data.vTime = timeline.time();
 }
 
 void QQuickFlickable::geometryChanged(const QRectF &newGeometry,
index 81135c2..68e6cae 100644 (file)
@@ -253,7 +253,7 @@ protected:
     qreal vWidth() const;
     qreal vHeight() const;
     virtual void componentComplete();
-    virtual void viewportMoved();
+    virtual void viewportMoved(Qt::Orientations orient);
     virtual void geometryChanged(const QRectF &newGeometry,
                                  const QRectF &oldGeometry);
     void mouseUngrabEvent();
index 64335c8..e0fa526 100644 (file)
@@ -103,7 +103,7 @@ public:
             , transitionToBounds(0)
             , viewSize(-1), startMargin(0), endMargin(0)
             , transitionTo(0)
-            , continuousFlickVelocity(0)
+            , continuousFlickVelocity(0), vTime(0)
             , smoothVelocity(fp), atEnd(false), atBeginning(true)
             , transitionToSet(false)
             , fixingUp(false), inOvershoot(false), moving(false), flicking(false)
@@ -138,6 +138,7 @@ public:
         QQuickFlickableReboundTransition *transitionToBounds;
         qreal viewSize;
         qreal pressPos;
+        qreal lastPos;
         qreal dragStartOffset;
         qreal dragMinBound;
         qreal dragMaxBound;
@@ -147,6 +148,8 @@ public:
         qreal endMargin;
         qreal transitionTo;
         qreal continuousFlickVelocity;
+        QElapsedTimer velocityTime;
+        int vTime;
         QQuickFlickablePrivate::Velocity smoothVelocity;
         QPODVector<qreal,10> velocityBuffer;
         bool atEnd : 1;
@@ -215,8 +218,6 @@ public:
     QPointF pressPos;
     qreal deceleration;
     qreal maxVelocity;
-    QElapsedTimer velocityTime;
-    QPointF lastFlickablePosition;
     qreal reportedVelocitySmoothing;
     QMouseEvent *delayedPressEvent;
     QQuickItem *delayedPressTarget;
@@ -239,6 +240,9 @@ public:
     QQuickFlickable::BoundsBehavior boundsBehavior;
     QQuickTransition *rebound;
 
+    void viewportAxisMoved(AxisData &data, qreal minExtent, qreal maxExtent, qreal vSize,
+                       QQuickTimeLineCallback::Callback fixupCallback);
+
     void handleMousePressEvent(QMouseEvent *);
     void handleMouseMoveEvent(QMouseEvent *);
     void handleMouseReleaseEvent(QMouseEvent *);
index fa1e96c..65ca1ae 100644 (file)
@@ -1986,10 +1986,10 @@ void QQuickGridView::setSnapMode(SnapMode mode)
     \sa addDisplaced, moveDisplaced, removeDisplaced, ViewTransition
 */
 
-void QQuickGridView::viewportMoved()
+void QQuickGridView::viewportMoved(Qt::Orientations orient)
 {
     Q_D(QQuickGridView);
-    QQuickItemView::viewportMoved();
+    QQuickItemView::viewportMoved(orient);
     if (!d->itemCount)
         return;
     if (d->inViewportMoved)
index 789c641..aa4e56e 100644 (file)
@@ -109,7 +109,7 @@ Q_SIGNALS:
     void snapModeChanged();
 
 protected:
-    virtual void viewportMoved();
+    virtual void viewportMoved(Qt::Orientations);
     virtual void keyPressEvent(QKeyEvent *);
     virtual void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry);
 };
index 5401abc..17851cd 100644 (file)
@@ -2631,10 +2631,10 @@ void QQuickListView::setSnapMode(SnapMode mode)
     \sa addDisplaced, moveDisplaced, removeDisplaced, ViewTransition
 */
 
-void QQuickListView::viewportMoved()
+void QQuickListView::viewportMoved(Qt::Orientations orient)
 {
     Q_D(QQuickListView);
-    QQuickItemView::viewportMoved();
+    QQuickItemView::viewportMoved(orient);
     if (!d->itemCount)
         return;
     // Recursion can occur due to refill changing the content size.
index ef989ba..be8da90 100644 (file)
@@ -167,7 +167,7 @@ Q_SIGNALS:
     void snapModeChanged();
 
 protected:
-    virtual void viewportMoved();
+    virtual void viewportMoved(Qt::Orientations orient);
     virtual void keyPressEvent(QKeyEvent *);
     virtual void geometryChanged(const QRectF &newGeometry,const QRectF &oldGeometry);