Manually apply SnapOneItem/Row changes from Qt 4.7
authorMartin Jones <martin.jones@nokia.com>
Mon, 26 Sep 2011 03:13:02 +0000 (13:13 +1000)
committerQt by Nokia <qt-info@nokia.com>
Tue, 27 Sep 2011 23:12:34 +0000 (01:12 +0200)
Apply following changes to Qt 5 for both QtQuick1 and QtQuick2 items:
cf23188de237009136fa1480ab8fd9e3ca364769
f85819fe083ae7c6804c884de68e906d153a6d11
09cd2f818208a83489fae034b80e6497b7cc83af

Task-number: QTBUG-20683
Change-Id: I974764e57e3004514bb4c9f46c5152ad07c136a7
Reviewed-on: http://codereview.qt-project.org/5484
Reviewed-by: Bea Lam <bea.lam@nokia.com>
src/declarative/items/qsgflickable.cpp
src/declarative/items/qsgflickable_p_p.h
src/declarative/items/qsggridview.cpp
src/declarative/items/qsglistview.cpp
src/qtquick1/graphicsitems/qdeclarativeflickable.cpp
src/qtquick1/graphicsitems/qdeclarativeflickable_p_p.h
src/qtquick1/graphicsitems/qdeclarativegridview.cpp
src/qtquick1/graphicsitems/qdeclarativelistview.cpp
tests/auto/qtquick1/qdeclarativegridview/tst_qdeclarativegridview.cpp

index 91a93b6..09bb8e3 100644 (file)
@@ -171,9 +171,7 @@ QSGFlickablePrivate::QSGFlickablePrivate()
   : contentItem(new QSGItem)
     , hData(this, &QSGFlickablePrivate::setViewportX)
     , vData(this, &QSGFlickablePrivate::setViewportY)
-    , flickingHorizontally(false), flickingVertically(false)
     , hMoved(false), vMoved(false)
-    , movingHorizontally(false), movingVertically(false)
     , stealMouse(false), pressed(false), interactive(true), calcVelocity(false)
     , pixelAligned(false)
     , deceleration(QML_FLICK_DEFAULTDECELERATION)
@@ -286,18 +284,18 @@ void QSGFlickablePrivate::flick(AxisData &data, qreal minExtent, qreal maxExtent
         else
             timeline.accel(data.move, v, deceleration, maxDistance);
         timeline.callback(QDeclarativeTimeLineCallback(&data.move, fixupCallback, this));
-        if (!flickingHorizontally && q->xflick()) {
-            flickingHorizontally = true;
+        if (!hData.flicking && q->xflick()) {
+            hData.flicking = true;
             emit q->flickingChanged();
             emit q->flickingHorizontallyChanged();
-            if (!flickingVertically)
+            if (!vData.flicking)
                 emit q->flickStarted();
         }
-        if (!flickingVertically && q->yflick()) {
-            flickingVertically = true;
+        if (!vData.flicking && q->yflick()) {
+            vData.flicking = true;
             emit q->flickingChanged();
             emit q->flickingVerticallyChanged();
-            if (!flickingHorizontally)
+            if (!hData.flicking)
                 emit q->flickStarted();
         }
     } else {
@@ -645,11 +643,11 @@ void QSGFlickable::setInteractive(bool interactive)
     Q_D(QSGFlickable);
     if (interactive != d->interactive) {
         d->interactive = interactive;
-        if (!interactive && (d->flickingHorizontally || d->flickingVertically)) {
+        if (!interactive && (d->hData.flicking || d->vData.flicking)) {
             d->timeline.clear();
             d->vTime = d->timeline.time();
-            d->flickingHorizontally = false;
-            d->flickingVertically = false;
+            d->hData.flicking = false;
+            d->vData.flicking = false;
             emit flickingChanged();
             emit flickingHorizontallyChanged();
             emit flickingVerticallyChanged();
@@ -819,8 +817,8 @@ void QSGFlickablePrivate::handleMousePressEvent(QMouseEvent *event)
     pressPos = event->localPos();
     hData.pressPos = hData.move.value();
     vData.pressPos = vData.move.value();
-    flickingHorizontally = false;
-    flickingVertically = false;
+    hData.flicking = false;
+    vData.flicking = false;
     QSGItemPrivate::start(pressTime);
     QSGItemPrivate::start(velocityTime);
 }
@@ -944,13 +942,10 @@ void QSGFlickablePrivate::handleMouseReleaseEvent(QMouseEvent *event)
     pressed = false;
 
     // if we drag then pause before release we should not cause a flick.
-    if (QSGItemPrivate::elapsed(lastPosTime) < 100) {
-        vData.updateVelocity();
-        hData.updateVelocity();
-    } else {
-        hData.velocity = 0.0;
-        vData.velocity = 0.0;
-    }
+    qint64 elapsed = QSGItemPrivate::elapsed(lastPosTime);
+     
+    vData.updateVelocity();
+    hData.updateVelocity();
 
     draggingEnding();
 
@@ -959,7 +954,7 @@ void QSGFlickablePrivate::handleMouseReleaseEvent(QMouseEvent *event)
 
     vTime = timeline.time();
 
-    qreal velocity = vData.velocity;
+    qreal velocity = elapsed < 100 ? vData.velocity : 0;
     if (vData.atBeginning || vData.atEnd)
         velocity /= 2;
     if (q->yflick() && qAbs(velocity) > MinimumFlickVelocity && qAbs(event->localPos().y() - pressPos.y()) > FlickThreshold) {
@@ -970,7 +965,7 @@ void QSGFlickablePrivate::handleMouseReleaseEvent(QMouseEvent *event)
         fixupY();
     }
 
-    velocity = hData.velocity;
+    velocity = elapsed < 100 ? hData.velocity : 0;
     if (hData.atBeginning || hData.atEnd)
         velocity /= 2;
     if (q->xflick() && qAbs(velocity) > MinimumFlickVelocity && qAbs(event->localPos().x() - pressPos.x()) > FlickThreshold) {
@@ -1036,9 +1031,9 @@ void QSGFlickable::wheelEvent(QWheelEvent *event)
             valid = true;
         }
         if (valid) {
-            d->flickingVertically = false;
+            d->vData.flicking = false;
             d->flickY(d->vData.velocity);
-            if (d->flickingVertically) {
+            if (d->vData.flicking) {
                 d->vMoved = true;
                 movementStarting();
             }
@@ -1054,9 +1049,9 @@ void QSGFlickable::wheelEvent(QWheelEvent *event)
             valid = true;
         }
         if (valid) {
-            d->flickingHorizontally = false;
+            d->hData.flicking = false;
             d->flickX(d->hData.velocity);
-            if (d->flickingHorizontally) {
+            if (d->hData.flicking) {
                 d->hMoved = true;
                 movementStarting();
             }
@@ -1202,7 +1197,7 @@ void QSGFlickable::viewportMoved()
         }
     }
 
-    if (!d->vData.inOvershoot && !d->vData.fixingUp && d->flickingVertically
+    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()) > 100) {
         // Increase deceleration if we've passed a bound
@@ -1212,7 +1207,7 @@ void QSGFlickable::viewportMoved()
         d->timeline.accel(d->vData.move, -d->vData.smoothVelocity.value(), d->deceleration*QML_FLICK_OVERSHOOTFRICTION, maxDistance);
         d->timeline.callback(QDeclarativeTimeLineCallback(&d->vData.move, d->fixupY_callback, d));
     }
-    if (!d->hData.inOvershoot && !d->hData.fixingUp && d->flickingHorizontally
+    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()) > 100) {
         // Increase deceleration if we've passed a bound
@@ -1244,7 +1239,7 @@ void QSGFlickable::geometryChanged(const QRectF &newGeometry,
             emit contentWidthChanged();
         }
         // Make sure that we're entirely in view.
-        if (!d->pressed && !d->movingHorizontally && !d->movingVertically) {
+        if (!d->pressed && !d->hData.moving && !d->vData.moving) {
             d->fixupMode = QSGFlickablePrivate::Immediate;
             d->fixupX();
         }
@@ -1257,7 +1252,7 @@ void QSGFlickable::geometryChanged(const QRectF &newGeometry,
             emit contentHeightChanged();
         }
         // Make sure that we're entirely in view.
-        if (!d->pressed && !d->movingHorizontally && !d->movingVertically) {
+        if (!d->pressed && !d->hData.moving && !d->vData.moving) {
             d->fixupMode = QSGFlickablePrivate::Immediate;
             d->fixupY();
         }
@@ -1388,7 +1383,7 @@ void QSGFlickable::setContentWidth(qreal w)
         d->contentItem->setWidth(w);
     d->hData.markExtentsDirty();
     // Make sure that we're entirely in view.
-    if (!d->pressed && !d->movingHorizontally && !d->movingVertically) {
+    if (!d->pressed && !d->hData.moving && !d->vData.moving) {
         d->fixupMode = QSGFlickablePrivate::Immediate;
         d->fixupX();
     } else if (!d->pressed && d->hData.fixingUp) {
@@ -1417,7 +1412,7 @@ void QSGFlickable::setContentHeight(qreal h)
         d->contentItem->setHeight(h);
     d->vData.markExtentsDirty();
     // Make sure that we're entirely in view.
-    if (!d->pressed && !d->movingHorizontally && !d->movingVertically) {
+    if (!d->pressed && !d->hData.moving && !d->vData.moving) {
         d->fixupMode = QSGFlickablePrivate::Immediate;
         d->fixupY();
     } else if (!d->pressed && d->vData.fixingUp) {
@@ -1452,7 +1447,7 @@ void QSGFlickable::setTopMargin(qreal m)
         return;
     d->vData.startMargin = m;
     d->vData.markExtentsDirty();
-    if (!d->pressed && !d->movingHorizontally && !d->movingVertically) {
+    if (!d->pressed && !d->hData.moving && !d->vData.moving) {
         d->fixupMode = QSGFlickablePrivate::Immediate;
         d->fixupY();
     }
@@ -1473,7 +1468,7 @@ void QSGFlickable::setBottomMargin(qreal m)
         return;
     d->vData.endMargin = m;
     d->vData.markExtentsDirty();
-    if (!d->pressed && !d->movingHorizontally && !d->movingVertically) {
+    if (!d->pressed && !d->hData.moving && !d->vData.moving) {
         d->fixupMode = QSGFlickablePrivate::Immediate;
         d->fixupY();
     }
@@ -1494,7 +1489,7 @@ void QSGFlickable::setLeftMargin(qreal m)
         return;
     d->hData.startMargin = m;
     d->hData.markExtentsDirty();
-    if (!d->pressed && !d->movingHorizontally && !d->movingVertically) {
+    if (!d->pressed && !d->hData.moving && !d->vData.moving) {
         d->fixupMode = QSGFlickablePrivate::Immediate;
         d->fixupX();
     }
@@ -1515,7 +1510,7 @@ void QSGFlickable::setRightMargin(qreal m)
         return;
     d->hData.endMargin = m;
     d->hData.markExtentsDirty();
-    if (!d->pressed && !d->movingHorizontally && !d->movingVertically) {
+    if (!d->pressed && !d->hData.moving && !d->vData.moving) {
         d->fixupMode = QSGFlickablePrivate::Immediate;
         d->fixupX();
     }
@@ -1776,7 +1771,7 @@ void QSGFlickable::setFlickDeceleration(qreal deceleration)
 bool QSGFlickable::isFlicking() const
 {
     Q_D(const QSGFlickable);
-    return d->flickingHorizontally ||  d->flickingVertically;
+    return d->hData.flicking ||  d->vData.flicking;
 }
 
 /*!
@@ -1790,13 +1785,13 @@ bool QSGFlickable::isFlicking() const
 bool QSGFlickable::isFlickingHorizontally() const
 {
     Q_D(const QSGFlickable);
-    return d->flickingHorizontally;
+    return d->hData.flicking;
 }
 
 bool QSGFlickable::isFlickingVertically() const
 {
     Q_D(const QSGFlickable);
-    return d->flickingVertically;
+    return d->vData.flicking;
 }
 
 /*!
@@ -1903,36 +1898,36 @@ void QSGFlickable::setPressDelay(int delay)
 bool QSGFlickable::isMoving() const
 {
     Q_D(const QSGFlickable);
-    return d->movingHorizontally || d->movingVertically;
+    return d->hData.moving || d->vData.moving;
 }
 
 bool QSGFlickable::isMovingHorizontally() const
 {
     Q_D(const QSGFlickable);
-    return d->movingHorizontally;
+    return d->hData.moving;
 }
 
 bool QSGFlickable::isMovingVertically() const
 {
     Q_D(const QSGFlickable);
-    return d->movingVertically;
+    return d->vData.moving;
 }
 
 void QSGFlickable::movementStarting()
 {
     Q_D(QSGFlickable);
-    if (d->hMoved && !d->movingHorizontally) {
-        d->movingHorizontally = true;
+    if (d->hMoved && !d->hData.moving) {
+        d->hData.moving = true;
         emit movingChanged();
         emit movingHorizontallyChanged();
-        if (!d->movingVertically)
+        if (!d->vData.moving)
             emit movementStarted();
     }
-    else if (d->vMoved && !d->movingVertically) {
-        d->movingVertically = true;
+    else if (d->vMoved && !d->vData.moving) {
+        d->vData.moving = true;
         emit movingChanged();
         emit movingVerticallyChanged();
-        if (!d->movingHorizontally)
+        if (!d->hData.moving)
             emit movementStarted();
     }
 }
@@ -1949,20 +1944,20 @@ void QSGFlickable::movementEnding()
 void QSGFlickable::movementXEnding()
 {
     Q_D(QSGFlickable);
-    if (d->flickingHorizontally) {
-        d->flickingHorizontally = false;
+    if (d->hData.flicking) {
+        d->hData.flicking = false;
         emit flickingChanged();
         emit flickingHorizontallyChanged();
-        if (!d->flickingVertically)
+        if (!d->vData.flicking)
            emit flickEnded();
     }
     if (!d->pressed && !d->stealMouse) {
-        if (d->movingHorizontally) {
-            d->movingHorizontally = false;
+        if (d->hData.moving) {
+            d->hData.moving = false;
             d->hMoved = false;
             emit movingChanged();
             emit movingHorizontallyChanged();
-            if (!d->movingVertically)
+            if (!d->vData.moving)
                 emit movementEnded();
         }
     }
@@ -1972,20 +1967,20 @@ void QSGFlickable::movementXEnding()
 void QSGFlickable::movementYEnding()
 {
     Q_D(QSGFlickable);
-    if (d->flickingVertically) {
-        d->flickingVertically = false;
+    if (d->vData.flicking) {
+        d->vData.flicking = false;
         emit flickingChanged();
         emit flickingVerticallyChanged();
-        if (!d->flickingHorizontally)
+        if (!d->hData.flicking)
            emit flickEnded();
     }
     if (!d->pressed && !d->stealMouse) {
-        if (d->movingVertically) {
-            d->movingVertically = false;
+        if (d->vData.moving) {
+            d->vData.moving = false;
             d->vMoved = false;
             emit movingChanged();
             emit movingVerticallyChanged();
-            if (!d->movingHorizontally)
+            if (!d->hData.moving)
                 emit movementEnded();
         }
     }
index b3690b4..b7a91a0 100644 (file)
@@ -60,6 +60,7 @@
 
 #include <QtDeclarative/qdeclarative.h>
 #include <QtCore/qdatetime.h>
+#include "qplatformdefs.h"
 
 #include <private/qdeclarativetimeline_p_p.h>
 #include <private/qdeclarativeanimation_p_p.h>
@@ -97,7 +98,8 @@ public:
         AxisData(QSGFlickablePrivate *fp, void (QSGFlickablePrivate::*func)(qreal))
             : move(fp, func), viewSize(-1), startMargin(0), endMargin(0)
             , smoothVelocity(fp), atEnd(false), atBeginning(true)
-            , fixingUp(false), inOvershoot(false), dragging(false), extentsChanged(false)
+            , fixingUp(false), inOvershoot(false), moving(false), flicking(false)
+            , dragging(false), extentsChanged(false)
             , explicitValue(false), minExtentDirty(true), maxExtentDirty(true)
         {}
 
@@ -133,6 +135,8 @@ public:
         bool atBeginning : 1;
         bool fixingUp : 1;
         bool inOvershoot : 1;
+        bool moving : 1;
+        bool flicking : 1;
         bool dragging : 1;
         bool extentsChanged : 1;
         bool explicitValue : 1;
@@ -172,12 +176,8 @@ public:
     AxisData vData;
 
     QDeclarativeTimeLine timeline;
-    bool flickingHorizontally : 1;
-    bool flickingVertically : 1;
     bool hMoved : 1;
     bool vMoved : 1;
-    bool movingHorizontally : 1;
-    bool movingVertically : 1;
     bool stealMouse : 1;
     bool pressed : 1;
     bool interactive : 1;
index 4d794aa..dfcd1b2 100644 (file)
 #include <QtCore/qmath.h>
 #include <QtCore/qcoreapplication.h>
 #include <math.h>
+#include "qplatformdefs.h"
 
 QT_BEGIN_NAMESPACE
 
+#ifndef QML_FLICK_SNAPONETHRESHOLD
+#define QML_FLICK_SNAPONETHRESHOLD 30
+#endif
+
 //----------------------------------------------------------------------------
 
 class FxGridItemSG : public FxViewItem
@@ -329,9 +334,12 @@ qreal QSGGridViewPrivate::snapPosAt(qreal pos) const
     Q_Q(const QSGGridView);
     qreal snapPos = 0;
     if (!visibleItems.isEmpty()) {
+        qreal highlightStart = isRightToLeftTopToBottom() && highlightRangeStartValid ? size()-highlightRangeEnd : highlightRangeStart;
+        pos += highlightStart;
         pos += rowSize()/2;
         snapPos = static_cast<FxGridItemSG*>(visibleItems.first())->rowPos() - visibleIndex / columns * rowSize();
         snapPos = pos - fmodf(pos - snapPos, qreal(rowSize()));
+        snapPos -= highlightStart;
         qreal maxExtent;
         qreal minExtent;
         if (isRightToLeftTopToBottom()) {
@@ -810,12 +818,35 @@ void QSGGridViewPrivate::fixup(AxisData &data, qreal minExtent, qreal maxExtent)
         highlightEnd = highlightRangeEnd;
     }
 
+    bool strictHighlightRange = haveHighlightRange && highlightRange == QSGGridView::StrictlyEnforceRange;
     if (snapMode != QSGGridView::NoSnap) {
         qreal tempPosition = isRightToLeftTopToBottom() ? -position()-size() : position();
+        if (snapMode == QSGGridView::SnapOneRow && moveReason == Mouse) {
+            // if we've been dragged < rowSize()/2 then bias towards the next row
+            qreal dist = data.move.value() - (data.pressPos - data.dragStartOffset);
+            qreal bias = 0;
+            if (data.velocity > 0 && dist > QML_FLICK_SNAPONETHRESHOLD && dist < rowSize()/2)
+                bias = rowSize()/2;
+            else if (data.velocity < 0 && dist < -QML_FLICK_SNAPONETHRESHOLD && dist > -rowSize()/2)
+                bias = -rowSize()/2;
+            if (isRightToLeftTopToBottom())
+                bias = -bias;
+            tempPosition -= bias;
+        }
         FxViewItem *topItem = snapItemAt(tempPosition+highlightStart);
+        if (!topItem && strictHighlightRange && currentItem) {
+            // StrictlyEnforceRange always keeps an item in range
+            updateHighlight();
+            topItem = currentItem;
+        }
         FxViewItem *bottomItem = snapItemAt(tempPosition+highlightEnd);
+        if (!bottomItem && strictHighlightRange && currentItem) {
+            // StrictlyEnforceRange always keeps an item in range
+            updateHighlight();
+            bottomItem = currentItem;
+        }
         qreal pos;
-        if (topItem && bottomItem && haveHighlightRange && highlightRange == QSGGridView::StrictlyEnforceRange) {
+        if (topItem && bottomItem && strictHighlightRange) {
             qreal topPos = qMin(topItem->position() - highlightStart, -maxExtent);
             qreal bottomPos = qMax(bottomItem->position() - highlightEnd, -minExtent);
             pos = qAbs(data.move + topPos) < qAbs(data.move + bottomPos) ? topPos : bottomPos;
@@ -823,7 +854,7 @@ void QSGGridViewPrivate::fixup(AxisData &data, qreal minExtent, qreal maxExtent)
             qreal headerPos = 0;
             if (header)
                 headerPos = isRightToLeftTopToBottom() ? static_cast<FxGridItemSG*>(header)->rowPos() + cellWidth - headerSize() : static_cast<FxGridItemSG*>(header)->rowPos();
-            if (topItem->index == 0 && header && tempPosition+highlightStart < headerPos+headerSize()/2) {
+            if (topItem->index == 0 && header && tempPosition+highlightStart < headerPos+headerSize()/2 && !strictHighlightRange) {
                 pos = isRightToLeftTopToBottom() ? - headerPos + highlightStart - size() : headerPos - highlightStart;
             } else {
                 if (isRightToLeftTopToBottom())
@@ -833,25 +864,13 @@ void QSGGridViewPrivate::fixup(AxisData &data, qreal minExtent, qreal maxExtent)
             }
         } else if (bottomItem) {
             if (isRightToLeftTopToBottom())
-                pos = qMax(qMin(-bottomItem->position() + highlightStart - size(), -maxExtent), -minExtent);
+                pos = qMax(qMin(-bottomItem->position() + highlightEnd - size(), -maxExtent), -minExtent);
             else
-                pos = qMax(qMin(bottomItem->position() - highlightStart, -maxExtent), -minExtent);
+                pos = qMax(qMin(bottomItem->position() - highlightEnd, -maxExtent), -minExtent);
         } else {
             QSGItemViewPrivate::fixup(data, minExtent, maxExtent);
             return;
         }
-        if (currentItem && haveHighlightRange && highlightRange == QSGGridView::StrictlyEnforceRange) {
-            updateHighlight();
-            qreal currPos = static_cast<FxGridItemSG*>(currentItem)->rowPos();
-            if (isRightToLeftTopToBottom())
-                pos = -pos-size(); // Transform Pos if required
-            if (pos < currPos + rowSize() - highlightEnd)
-                pos = currPos + rowSize() - highlightEnd;
-            if (pos > currPos - highlightStart)
-                pos = currPos - highlightStart;
-            if (isRightToLeftTopToBottom())
-                pos = -pos-size(); // Untransform
-        }
 
         qreal dist = qAbs(data.move + pos);
         if (dist > 0) {
@@ -909,8 +928,14 @@ void QSGGridViewPrivate::flick(AxisData &data, qreal minExtent, qreal maxExtent,
     if (velocity > 0) {
         if (data.move.value() < minExtent) {
             if (snapMode == QSGGridView::SnapOneRow) {
-                if (FxViewItem *item = firstVisibleItem())
-                    maxDistance = qAbs(item->position() + dataValue);
+                // if we've been dragged < averageSize/2 then bias towards the next item
+                qreal dist = data.move.value() - (data.pressPos - data.dragStartOffset);
+                qreal bias = dist < rowSize()/2 ? rowSize()/2 : 0;
+                if (isRightToLeftTopToBottom())
+                    bias = -bias;
+                data.flickTarget = -snapPosAt(-dataValue - bias);
+                maxDistance = qAbs(data.flickTarget - data.move.value());
+                velocity = maxVelocity;
             } else {
                 maxDistance = qAbs(minExtent - data.move.value());
             }
@@ -920,8 +945,14 @@ void QSGGridViewPrivate::flick(AxisData &data, qreal minExtent, qreal maxExtent,
     } else {
         if (data.move.value() > maxExtent) {
             if (snapMode == QSGGridView::SnapOneRow) {
-                qreal pos = snapPosAt(-dataValue) + (isRightToLeftTopToBottom() ? 0 : rowSize());
-                maxDistance = qAbs(pos + dataValue);
+                // if we've been dragged < averageSize/2 then bias towards the next item
+                qreal dist = data.move.value() - (data.pressPos - data.dragStartOffset);
+                qreal bias = -dist < rowSize()/2 ? rowSize()/2 : 0;
+                if (isRightToLeftTopToBottom())
+                    bias = -bias;
+                data.flickTarget = -snapPosAt(-dataValue + bias);
+                maxDistance = qAbs(data.flickTarget - data.move.value());
+                velocity = -maxVelocity;
             } else {
                 maxDistance = qAbs(maxExtent - data.move.value());
             }
@@ -930,7 +961,6 @@ void QSGGridViewPrivate::flick(AxisData &data, qreal minExtent, qreal maxExtent,
             data.flickTarget = maxExtent;
     }
     bool overShoot = boundsBehavior == QSGFlickable::DragAndOvershootBounds;
-    qreal highlightStart = isRightToLeftTopToBottom() && highlightRangeStartValid ? size()-highlightRangeEnd : highlightRangeStart;
     if (maxDistance > 0 || overShoot) {
         // This mode requires the grid to stop exactly on a row boundary.
         qreal v = velocity;
@@ -949,9 +979,20 @@ void QSGGridViewPrivate::flick(AxisData &data, qreal minExtent, qreal maxExtent,
             dist = qMin(dist, maxDistance);
             if (v > 0)
                 dist = -dist;
-            qreal distTemp = isRightToLeftTopToBottom() ? -dist : dist;
-            data.flickTarget = -snapPosAt(-(dataValue - highlightStart) + distTemp) + highlightStart;
+            if (snapMode != QSGGridView::SnapOneRow) {
+                qreal distTemp = isRightToLeftTopToBottom() ? -dist : dist;
+                data.flickTarget = -snapPosAt(-dataValue + distTemp);
+            }
             data.flickTarget = isRightToLeftTopToBottom() ? -data.flickTarget+size() : data.flickTarget;
+            if (overShoot) {
+                if (data.flickTarget >= minExtent) {
+                    overshootDist = overShootDistance(vSize);
+                    data.flickTarget += overshootDist;
+                } else if (data.flickTarget <= maxExtent) {
+                    overshootDist = overShootDistance(vSize);
+                    data.flickTarget -= overshootDist;
+                }
+            }
             qreal adjDist = -data.flickTarget + data.move.value();
             if (qAbs(adjDist) > qAbs(dist)) {
                 // Prevent painfully slow flicking - adjust velocity to suit flickDeceleration
@@ -972,14 +1013,14 @@ void QSGGridViewPrivate::flick(AxisData &data, qreal minExtent, qreal maxExtent,
         timeline.reset(data.move);
         timeline.accel(data.move, v, accel, maxDistance + overshootDist);
         timeline.callback(QDeclarativeTimeLineCallback(&data.move, fixupCallback, this));
-        if (!flickingHorizontally && q->xflick()) {
-            flickingHorizontally = true;
+        if (!hData.flicking && q->xflick()) {
+            hData.flicking = true;
             emit q->flickingChanged();
             emit q->flickingHorizontallyChanged();
             emit q->flickStarted();
         }
-        if (!flickingVertically && q->yflick()) {
-            flickingVertically = true;
+        if (!vData.flicking && q->yflick()) {
+            vData.flicking = true;
             emit q->flickingChanged();
             emit q->flickingVerticallyChanged();
             emit q->flickStarted();
@@ -1477,7 +1518,7 @@ void QSGGridView::viewportMoved()
     d->inViewportMoved = true;
 
     d->lazyRelease = true;
-    if (d->flickingHorizontally || d->flickingVertically) {
+    if (d->hData.flicking || d->vData.flicking) {
         if (yflick()) {
             if (d->vData.velocity > 0)
                 d->bufferMode = QSGGridViewPrivate::BufferBefore;
@@ -1493,7 +1534,7 @@ void QSGGridView::viewportMoved()
         }
     }
     d->refill();
-    if (d->flickingHorizontally || d->flickingVertically || d->movingHorizontally || d->movingVertically)
+    if (d->hData.flicking || d->vData.flicking || d->hData.moving || d->vData.moving)
         d->moveReason = QSGGridViewPrivate::Mouse;
     if (d->moveReason != QSGGridViewPrivate::SetIndex) {
         if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange && d->highlight) {
index f4d1392..b38c682 100644 (file)
 
 #include <private/qdeclarativesmoothedanimation_p_p.h>
 #include <private/qlistmodelinterface_p.h>
+#include "qplatformdefs.h"
 
 QT_BEGIN_NAMESPACE
 
+#ifndef QML_FLICK_SNAPONETHRESHOLD
+#define QML_FLICK_SNAPONETHRESHOLD 30
+#endif
+
 class FxListItemSG;
 
 class QSGListViewPrivate : public QSGItemViewPrivate
@@ -72,7 +77,6 @@ public:
     virtual qreal originPosition() const;
     virtual qreal lastPosition() const;
 
-    FxViewItem *nextVisibleItem() const;
     FxViewItem *itemBefore(int modelIndex) const;
     QString sectionAt(int modelIndex);
     qreal snapPosAt(qreal pos);
@@ -327,22 +331,6 @@ bool QSGListViewPrivate::isRightToLeft() const
     return orient == QSGListView::Horizontal && q->effectiveLayoutDirection() == Qt::RightToLeft;
 }
 
-FxViewItem *QSGListViewPrivate::nextVisibleItem() const
-{
-    const qreal pos = isRightToLeft() ? -position()-size() : position();
-    bool foundFirst = false;
-    for (int i = 0; i < visibleItems.count(); ++i) {
-        FxViewItem *item = visibleItems.at(i);
-        if (item->index != -1) {
-            if (foundFirst)
-                return item;
-            else if (item->position() < pos && item->endPosition() >= pos)
-                foundFirst = true;
-        }
-    }
-    return 0;
-}
-
 // Returns the item before modelIndex, if created.
 // May return an item marked for removal.
 FxViewItem *QSGListViewPrivate::itemBefore(int modelIndex) const
@@ -1261,6 +1249,7 @@ void QSGListViewPrivate::fixup(AxisData &data, qreal minExtent, qreal maxExtent)
 
     correctFlick = false;
     fixupMode = moveReason == Mouse ? fixupMode : Immediate;
+    bool strictHighlightRange = haveHighlightRange && highlightRange == QSGListView::StrictlyEnforceRange;
 
     qreal highlightStart;
     qreal highlightEnd;
@@ -1276,35 +1265,36 @@ void QSGListViewPrivate::fixup(AxisData &data, qreal minExtent, qreal maxExtent)
         highlightEnd = highlightRangeEnd;
     }
 
-    if (currentItem && haveHighlightRange && highlightRange == QSGListView::StrictlyEnforceRange
-            && moveReason != QSGListViewPrivate::SetIndex) {
-        updateHighlight();
-        qreal pos = static_cast<FxListItemSG*>(currentItem)->itemPosition();
-        if (viewPos < pos + static_cast<FxListItemSG*>(currentItem)->itemSize() - highlightEnd)
-            viewPos = pos + static_cast<FxListItemSG*>(currentItem)->itemSize() - highlightEnd;
-        if (viewPos > pos - highlightStart)
-            viewPos = pos - highlightStart;
-        if (isRightToLeft())
-            viewPos = -viewPos-size();
-
-        timeline.reset(data.move);
-        if (viewPos != position()) {
-            if (fixupMode != Immediate) {
-                timeline.move(data.move, -viewPos, QEasingCurve(QEasingCurve::InOutQuad), fixupDuration/2);
-                data.fixingUp = true;
-            } else {
-                timeline.set(data.move, -viewPos);
-            }
-        }
-        vTime = timeline.time();
-    } else if (snapMode != QSGListView::NoSnap && moveReason != QSGListViewPrivate::SetIndex) {
+    if (snapMode != QSGListView::NoSnap && moveReason != QSGListViewPrivate::SetIndex) {
         qreal tempPosition = isRightToLeft() ? -position()-size() : position();
+        if (snapMode == QSGListView::SnapOneItem && moveReason == Mouse) {
+            // if we've been dragged < averageSize/2 then bias towards the next item
+            qreal dist = data.move.value() - (data.pressPos - data.dragStartOffset);
+            qreal bias = 0;
+            if (data.velocity > 0 && dist > QML_FLICK_SNAPONETHRESHOLD && dist < averageSize/2)
+                bias = averageSize/2;
+            else if (data.velocity < 0 && dist < -QML_FLICK_SNAPONETHRESHOLD && dist > -averageSize/2)
+                bias = -averageSize/2;
+            if (isRightToLeft())
+                bias = -bias;
+            tempPosition -= bias;
+        }
         FxViewItem *topItem = snapItemAt(tempPosition+highlightStart);
+        if (!topItem && strictHighlightRange && currentItem) {
+            // StrictlyEnforceRange always keeps an item in range
+            updateHighlight();
+            topItem = currentItem;
+        }
         FxViewItem *bottomItem = snapItemAt(tempPosition+highlightEnd);
+        if (!bottomItem && strictHighlightRange && currentItem) {
+            // StrictlyEnforceRange always keeps an item in range
+            updateHighlight();
+            bottomItem = currentItem;
+        }
         qreal pos;
-        bool isInBounds = -position() > maxExtent && -position() < minExtent;
-        if (topItem && isInBounds) {
-            if (topItem->index == 0 && header && tempPosition+highlightStart < header->position()+headerSize()/2) {
+        bool isInBounds = -position() > maxExtent && -position() <= minExtent;
+        if (topItem && (isInBounds || strictHighlightRange)) {
+            if (topItem->index == 0 && header && tempPosition+highlightStart < header->position()+header->size()/2 && !strictHighlightRange) {
                 pos = isRightToLeft() ? - header->position() + highlightStart - size() : header->position() - highlightStart;
             } else {
                 if (isRightToLeft())
@@ -1314,9 +1304,9 @@ void QSGListViewPrivate::fixup(AxisData &data, qreal minExtent, qreal maxExtent)
             }
         } else if (bottomItem && isInBounds) {
             if (isRightToLeft())
-                pos = qMax(qMin(-bottomItem->position() + highlightStart - size(), -maxExtent), -minExtent);
+                pos = qMax(qMin(-bottomItem->position() + highlightEnd - size(), -maxExtent), -minExtent);
             else
-                pos = qMax(qMin(bottomItem->position() - highlightStart, -maxExtent), -minExtent);
+                pos = qMax(qMin(bottomItem->position() - highlightEnd, -maxExtent), -minExtent);
         } else {
             QSGItemViewPrivate::fixup(data, minExtent, maxExtent);
             return;
@@ -1333,6 +1323,26 @@ void QSGListViewPrivate::fixup(AxisData &data, qreal minExtent, qreal maxExtent)
             }
             vTime = timeline.time();
         }
+    } else if (currentItem && strictHighlightRange && moveReason != QSGListViewPrivate::SetIndex) {
+        updateHighlight();
+        qreal pos = static_cast<FxListItemSG*>(currentItem)->itemPosition();
+        if (viewPos < pos + static_cast<FxListItemSG*>(currentItem)->itemSize() - highlightEnd)
+            viewPos = pos + static_cast<FxListItemSG*>(currentItem)->itemSize() - highlightEnd;
+        if (viewPos > pos - highlightStart)
+            viewPos = pos - highlightStart;
+        if (isRightToLeft())
+            viewPos = -viewPos-size();
+
+        timeline.reset(data.move);
+        if (viewPos != position()) {
+            if (fixupMode != Immediate) {
+                timeline.move(data.move, -viewPos, QEasingCurve(QEasingCurve::InOutQuad), fixupDuration/2);
+                data.fixingUp = true;
+            } else {
+                timeline.set(data.move, -viewPos);
+            }
+        }
+        vTime = timeline.time();
     } else {
         QSGItemViewPrivate::fixup(data, minExtent, maxExtent);
     }
@@ -1354,12 +1364,19 @@ void QSGListViewPrivate::flick(AxisData &data, qreal minExtent, qreal maxExtent,
     }
     qreal maxDistance = 0;
     qreal dataValue = isRightToLeft() ? -data.move.value()+size() : data.move.value();
+    qreal highlightStart = isRightToLeft() && highlightRangeStartValid ? size()-highlightRangeEnd : highlightRangeStart;
     // -ve velocity means list is moving up/left
     if (velocity > 0) {
         if (data.move.value() < minExtent) {
-            if (snapMode == QSGListView::SnapOneItem) {
-                if (FxViewItem *item = isRightToLeft() ? nextVisibleItem() : firstVisibleItem())
-                    maxDistance = qAbs(item->position() + dataValue);
+            if (snapMode == QSGListView::SnapOneItem && !hData.flicking && !vData.flicking) {
+                // if we've been dragged < averageSize/2 then bias towards the next item
+                qreal dist = data.move.value() - (data.pressPos - data.dragStartOffset);
+                qreal bias = dist < averageSize/2 ? averageSize/2 : 0;
+                if (isRightToLeft())
+                    bias = -bias;
+                data.flickTarget = -snapPosAt(-(dataValue - highlightStart) - bias) + highlightStart;
+                maxDistance = qAbs(data.flickTarget - data.move.value());
+                velocity = maxVelocity;
             } else {
                 maxDistance = qAbs(minExtent - data.move.value());
             }
@@ -1368,9 +1385,15 @@ void QSGListViewPrivate::flick(AxisData &data, qreal minExtent, qreal maxExtent,
             data.flickTarget = minExtent;
     } else {
         if (data.move.value() > maxExtent) {
-            if (snapMode == QSGListView::SnapOneItem) {
-                if (FxViewItem *item = isRightToLeft() ? firstVisibleItem() : nextVisibleItem())
-                    maxDistance = qAbs(item->position() + dataValue);
+            if (snapMode == QSGListView::SnapOneItem && !hData.flicking && !vData.flicking) {
+                // if we've been dragged < averageSize/2 then bias towards the next item
+                qreal dist = data.move.value() - (data.pressPos - data.dragStartOffset);
+                qreal bias = -dist < averageSize/2 ? averageSize/2 : 0;
+                if (isRightToLeft())
+                    bias = -bias;
+                data.flickTarget = -snapPosAt(-(dataValue - highlightStart) + bias) + highlightStart;
+                maxDistance = qAbs(data.flickTarget - data.move.value());
+                velocity = -maxVelocity;
             } else {
                 maxDistance = qAbs(maxExtent - data.move.value());
             }
@@ -1379,7 +1402,6 @@ void QSGListViewPrivate::flick(AxisData &data, qreal minExtent, qreal maxExtent,
             data.flickTarget = maxExtent;
     }
     bool overShoot = boundsBehavior == QSGFlickable::DragAndOvershootBounds;
-    qreal highlightStart = isRightToLeft() && highlightRangeStartValid ? size()-highlightRangeEnd : highlightRangeStart;
     if (maxDistance > 0 || overShoot) {
         // These modes require the list to stop exactly on an item boundary.
         // The initial flick will estimate the boundary to stop on.
@@ -1392,7 +1414,7 @@ void QSGListViewPrivate::flick(AxisData &data, qreal minExtent, qreal maxExtent,
             else
                 v = maxVelocity;
         }
-        if (!flickingHorizontally && !flickingVertically) {
+        if (!hData.flicking && !vData.flicking) {
             // the initial flick - estimate boundary
             qreal accel = deceleration;
             qreal v2 = v * v;
@@ -1404,8 +1426,10 @@ void QSGListViewPrivate::flick(AxisData &data, qreal minExtent, qreal maxExtent,
             if (v > 0)
                 dist = -dist;
             if ((maxDistance > 0.0 && v2 / (2.0f * maxDistance) < accel) || snapMode == QSGListView::SnapOneItem) {
-                qreal distTemp = isRightToLeft() ? -dist : dist;
-                data.flickTarget = -snapPosAt(-(dataValue - highlightStart) + distTemp) + highlightStart;
+                if (snapMode != QSGListView::SnapOneItem) {
+                    qreal distTemp = isRightToLeft() ? -dist : dist;
+                    data.flickTarget = -snapPosAt(-(dataValue - highlightStart) + distTemp) + highlightStart;
+                }
                 data.flickTarget = isRightToLeft() ? -data.flickTarget+size() : data.flickTarget;
                 if (overShoot) {
                     if (data.flickTarget >= minExtent) {
@@ -1442,14 +1466,14 @@ void QSGListViewPrivate::flick(AxisData &data, qreal minExtent, qreal maxExtent,
             timeline.reset(data.move);
             timeline.accel(data.move, v, accel, maxDistance + overshootDist);
             timeline.callback(QDeclarativeTimeLineCallback(&data.move, fixupCallback, this));
-            if (!flickingHorizontally && q->xflick()) {
-                flickingHorizontally = true;
+            if (!hData.flicking && q->xflick()) {
+                hData.flicking = true;
                 emit q->flickingChanged();
                 emit q->flickingHorizontallyChanged();
                 emit q->flickStarted();
             }
-            if (!flickingVertically && q->yflick()) {
-                flickingVertically = true;
+            if (!vData.flicking && q->yflick()) {
+                vData.flicking = true;
                 emit q->flickingChanged();
                 emit q->flickingVerticallyChanged();
                 emit q->flickStarted();
@@ -2137,7 +2161,7 @@ void QSGListView::viewportMoved()
     d->inViewportMoved = true;
     d->lazyRelease = true;
     d->refill();
-    if (d->flickingHorizontally || d->flickingVertically || d->movingHorizontally || d->movingVertically)
+    if (d->hData.flicking || d->vData.flicking || d->hData.moving || d->vData.moving)
         d->moveReason = QSGListViewPrivate::Mouse;
     if (d->moveReason != QSGListViewPrivate::SetIndex) {
         if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange && d->highlight) {
@@ -2175,7 +2199,7 @@ void QSGListView::viewportMoved()
         }
     }
 
-    if ((d->flickingHorizontally || d->flickingVertically) && d->correctFlick && !d->inFlickCorrection) {
+    if ((d->hData.flicking || d->vData.flicking) && d->correctFlick && !d->inFlickCorrection) {
         d->inFlickCorrection = true;
         // Near an end and it seems that the extent has changed?
         // Recalculate the flick so that we don't end up in an odd position.
index 6fa92b3..6a7f6ae 100644 (file)
@@ -170,9 +170,7 @@ QDeclarative1FlickablePrivate::QDeclarative1FlickablePrivate()
   : contentItem(new QDeclarativeItem)
     , hData(this, &QDeclarative1FlickablePrivate::setRoundedViewportX)
     , vData(this, &QDeclarative1FlickablePrivate::setRoundedViewportY)
-    , flickingHorizontally(false), flickingVertically(false)
     , hMoved(false), vMoved(false)
-    , movingHorizontally(false), movingVertically(false)
     , stealMouse(false), pressed(false), interactive(true), calcVelocity(false)
     , deceleration(QML_FLICK_DEFAULTDECELERATION)
     , maxVelocity(QML_FLICK_DEFAULTMAXVELOCITY), reportedVelocitySmoothing(100)
@@ -296,18 +294,18 @@ void QDeclarative1FlickablePrivate::flick(AxisData &data, qreal minExtent, qreal
         else
             timeline.accel(data.move, v, deceleration, maxDistance);
         timeline.callback(QDeclarative1TimeLineCallback(&data.move, fixupCallback, this));
-        if (!flickingHorizontally && q->xflick()) {
-            flickingHorizontally = true;
+        if (!hData.flicking && q->xflick()) {
+            hData.flicking = true;
             emit q->flickingChanged();
             emit q->flickingHorizontallyChanged();
-            if (!flickingVertically)
+            if (!vData.flicking)
                 emit q->flickStarted();
         }
-        if (!flickingVertically && q->yflick()) {
-            flickingVertically = true;
+        if (!vData.flicking && q->yflick()) {
+            vData.flicking = true;
             emit q->flickingChanged();
             emit q->flickingVerticallyChanged();
-            if (!flickingHorizontally)
+            if (!hData.flicking)
                 emit q->flickStarted();
         }
     } else {
@@ -617,11 +615,11 @@ void QDeclarative1Flickable::setInteractive(bool interactive)
     Q_D(QDeclarative1Flickable);
     if (interactive != d->interactive) {
         d->interactive = interactive;
-        if (!interactive && (d->flickingHorizontally || d->flickingVertically)) {
+        if (!interactive && (d->hData.flicking || d->vData.flicking)) {
             d->timeline.clear();
             d->vTime = d->timeline.time();
-            d->flickingHorizontally = false;
-            d->flickingVertically = false;
+            d->hData.flicking = false;
+            d->vData.flicking = false;
             emit flickingChanged();
             emit flickingHorizontallyChanged();
             emit flickingVerticallyChanged();
@@ -774,8 +772,8 @@ void QDeclarative1FlickablePrivate::handleMousePressEvent(QGraphicsSceneMouseEve
     pressPos = event->pos();
     hData.pressPos = hData.move.value();
     vData.pressPos = vData.move.value();
-    flickingHorizontally = false;
-    flickingVertically = false;
+    hData.flicking = false;
+    vData.flicking = false;
     QDeclarativeItemPrivate::start(pressTime);
     QDeclarativeItemPrivate::start(velocityTime);
 }
@@ -900,17 +898,14 @@ void QDeclarative1FlickablePrivate::handleMouseReleaseEvent(QGraphicsSceneMouseE
         return;
 
     // if we drag then pause before release we should not cause a flick.
-    if (QDeclarativeItemPrivate::elapsed(lastPosTime) < 100) {
-        vData.updateVelocity();
-        hData.updateVelocity();
-    } else {
-        hData.velocity = 0.0;
-        vData.velocity = 0.0;
-    }
+    qint64 elapsed = QDeclarativeItemPrivate::elapsed(lastPosTime);
+     
+    vData.updateVelocity();
+    hData.updateVelocity();
 
     vTime = timeline.time();
 
-    qreal velocity = vData.velocity;
+    qreal velocity = elapsed < 100 ? vData.velocity : 0;
     if (vData.atBeginning || vData.atEnd)
         velocity /= 2;
     if (q->yflick() && qAbs(velocity) > MinimumFlickVelocity && qAbs(event->pos().y() - pressPos.y()) > FlickThreshold) {
@@ -921,7 +916,7 @@ void QDeclarative1FlickablePrivate::handleMouseReleaseEvent(QGraphicsSceneMouseE
         fixupY();
     }
 
-    velocity = hData.velocity;
+    velocity = elapsed < 100 ? hData.velocity : 0;
     if (hData.atBeginning || hData.atEnd)
         velocity /= 2;
     if (q->xflick() && qAbs(velocity) > MinimumFlickVelocity && qAbs(event->pos().x() - pressPos.x()) > FlickThreshold) {
@@ -987,9 +982,9 @@ void QDeclarative1Flickable::wheelEvent(QGraphicsSceneWheelEvent *event)
             valid = true;
         }
         if (valid) {
-            d->flickingVertically = false;
+            d->vData.flicking = false;
             d->flickY(d->vData.velocity);
-            if (d->flickingVertically) {
+            if (d->vData.flicking) {
                 d->vMoved = true;
                 movementStarting();
             }
@@ -1005,9 +1000,9 @@ void QDeclarative1Flickable::wheelEvent(QGraphicsSceneWheelEvent *event)
             valid = true;
         }
         if (valid) {
-            d->flickingHorizontally = false;
+            d->hData.flicking = false;
             d->flickX(d->hData.velocity);
-            if (d->flickingHorizontally) {
+            if (d->hData.flicking) {
                 d->hMoved = true;
                 movementStarting();
             }
@@ -1156,7 +1151,7 @@ void QDeclarative1Flickable::viewportMoved()
         }
     }
 
-    if (!d->vData.inOvershoot && !d->vData.fixingUp && d->flickingVertically
+    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()) > 100) {
         // Increase deceleration if we've passed a bound
@@ -1166,7 +1161,7 @@ void QDeclarative1Flickable::viewportMoved()
         d->timeline.accel(d->vData.move, -d->vData.smoothVelocity.value(), d->deceleration*QML_FLICK_OVERSHOOTFRICTION, maxDistance);
         d->timeline.callback(QDeclarative1TimeLineCallback(&d->vData.move, d->fixupY_callback, d));
     }
-    if (!d->hData.inOvershoot && !d->hData.fixingUp && d->flickingHorizontally
+    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()) > 100) {
         // Increase deceleration if we've passed a bound
@@ -1198,7 +1193,7 @@ void QDeclarative1Flickable::geometryChanged(const QRectF &newGeometry,
             emit contentWidthChanged();
         }
         // Make sure that we're entirely in view.
-        if (!d->pressed && !d->movingHorizontally && !d->movingVertically) {
+        if (!d->pressed && !d->hData.moving && !d->vData.moving) {
             d->fixupMode = QDeclarative1FlickablePrivate::Immediate;
             d->fixupX();
         }
@@ -1211,7 +1206,7 @@ void QDeclarative1Flickable::geometryChanged(const QRectF &newGeometry,
             emit contentHeightChanged();
         }
         // Make sure that we're entirely in view.
-        if (!d->pressed && !d->movingHorizontally && !d->movingVertically) {
+        if (!d->pressed && !d->hData.moving && !d->vData.moving) {
             d->fixupMode = QDeclarative1FlickablePrivate::Immediate;
             d->fixupY();
         }
@@ -1366,7 +1361,7 @@ void QDeclarative1Flickable::setContentWidth(qreal w)
     else
         d->contentItem->setWidth(w);
     // Make sure that we're entirely in view.
-    if (!d->pressed && !d->movingHorizontally && !d->movingVertically) {
+    if (!d->pressed && !d->hData.moving && !d->vData.moving) {
         d->fixupMode = QDeclarative1FlickablePrivate::Immediate;
         d->fixupX();
     } else if (!d->pressed && d->hData.fixingUp) {
@@ -1394,7 +1389,7 @@ void QDeclarative1Flickable::setContentHeight(qreal h)
     else
         d->contentItem->setHeight(h);
     // Make sure that we're entirely in view.
-    if (!d->pressed && !d->movingHorizontally && !d->movingVertically) {
+    if (!d->pressed && !d->hData.moving && !d->vData.moving) {
         d->fixupMode = QDeclarative1FlickablePrivate::Immediate;
         d->fixupY();
     } else if (!d->pressed && d->vData.fixingUp) {
@@ -1651,7 +1646,7 @@ void QDeclarative1Flickable::setFlickDeceleration(qreal deceleration)
 bool QDeclarative1Flickable::isFlicking() const
 {
     Q_D(const QDeclarative1Flickable);
-    return d->flickingHorizontally ||  d->flickingVertically;
+    return d->hData.flicking ||  d->vData.flicking;
 }
 
 /*!
@@ -1665,13 +1660,13 @@ bool QDeclarative1Flickable::isFlicking() const
 bool QDeclarative1Flickable::isFlickingHorizontally() const
 {
     Q_D(const QDeclarative1Flickable);
-    return d->flickingHorizontally;
+    return d->hData.flicking;
 }
 
 bool QDeclarative1Flickable::isFlickingVertically() const
 {
     Q_D(const QDeclarative1Flickable);
-    return d->flickingVertically;
+    return d->vData.flicking;
 }
 
 /*!
@@ -1707,7 +1702,7 @@ void QDeclarative1Flickable::setPressDelay(int delay)
 bool QDeclarative1Flickable::isMoving() const
 {
     Q_D(const QDeclarative1Flickable);
-    return d->movingHorizontally || d->movingVertically;
+    return d->hData.moving || d->vData.moving;
 }
 
 /*!
@@ -1722,30 +1717,30 @@ bool QDeclarative1Flickable::isMoving() const
 bool QDeclarative1Flickable::isMovingHorizontally() const
 {
     Q_D(const QDeclarative1Flickable);
-    return d->movingHorizontally;
+    return d->hData.moving;
 }
 
 bool QDeclarative1Flickable::isMovingVertically() const
 {
     Q_D(const QDeclarative1Flickable);
-    return d->movingVertically;
+    return d->vData.moving;
 }
 
 void QDeclarative1Flickable::movementStarting()
 {
     Q_D(QDeclarative1Flickable);
-    if (d->hMoved && !d->movingHorizontally) {
-        d->movingHorizontally = true;
+    if (d->hMoved && !d->hData.moving) {
+        d->hData.moving = true;
         emit movingChanged();
         emit movingHorizontallyChanged();
-        if (!d->movingVertically)
+        if (!d->vData.moving)
             emit movementStarted();
     }
-    else if (d->vMoved && !d->movingVertically) {
-        d->movingVertically = true;
+    else if (d->vMoved && !d->vData.moving) {
+        d->vData.moving = true;
         emit movingChanged();
         emit movingVerticallyChanged();
-        if (!d->movingHorizontally)
+        if (!d->hData.moving)
             emit movementStarted();
     }
 }
@@ -1762,20 +1757,20 @@ void QDeclarative1Flickable::movementEnding()
 void QDeclarative1Flickable::movementXEnding()
 {
     Q_D(QDeclarative1Flickable);
-    if (d->flickingHorizontally) {
-        d->flickingHorizontally = false;
+    if (d->hData.flicking) {
+        d->hData.flicking = false;
         emit flickingChanged();
         emit flickingHorizontallyChanged();
-        if (!d->flickingVertically)
+        if (!d->vData.flicking)
            emit flickEnded();
     }
     if (!d->pressed && !d->stealMouse) {
-        if (d->movingHorizontally) {
-            d->movingHorizontally = false;
+        if (d->hData.moving) {
+            d->hData.moving = false;
             d->hMoved = false;
             emit movingChanged();
             emit movingHorizontallyChanged();
-            if (!d->movingVertically)
+            if (!d->vData.moving)
                 emit movementEnded();
         }
     }
@@ -1785,20 +1780,20 @@ void QDeclarative1Flickable::movementXEnding()
 void QDeclarative1Flickable::movementYEnding()
 {
     Q_D(QDeclarative1Flickable);
-    if (d->flickingVertically) {
-        d->flickingVertically = false;
+    if (d->vData.flicking) {
+        d->vData.flicking = false;
         emit flickingChanged();
         emit flickingVerticallyChanged();
-        if (!d->flickingHorizontally)
+        if (!d->hData.flicking)
            emit flickEnded();
     }
     if (!d->pressed && !d->stealMouse) {
-        if (d->movingVertically) {
-            d->movingVertically = false;
+        if (d->vData.moving) {
+            d->vData.moving = false;
             d->vMoved = false;
             emit movingChanged();
             emit movingVerticallyChanged();
-            if (!d->movingHorizontally)
+            if (!d->hData.moving)
                 emit movementEnded();
         }
     }
index 5bbeb27..c76da83 100644 (file)
@@ -94,7 +94,7 @@ public:
     struct AxisData {
         AxisData(QDeclarative1FlickablePrivate *fp, void (QDeclarative1FlickablePrivate::*func)(qreal))
             : move(fp, func), viewSize(-1), smoothVelocity(fp), atEnd(false), atBeginning(true)
-            , fixingUp(false), inOvershoot(false)
+            , fixingUp(false), inOvershoot(false), moving(false), flicking(false)
         {}
 
         void reset() {
@@ -121,6 +121,8 @@ public:
         bool atBeginning : 1;
         bool fixingUp : 1;
         bool inOvershoot : 1;
+        bool moving : 1;
+        bool flicking : 1;
     };
 
     void flickX(qreal velocity);
@@ -152,12 +154,8 @@ public:
     AxisData vData;
 
     QDeclarative1TimeLine timeline;
-    bool flickingHorizontally : 1;
-    bool flickingVertically : 1;
     bool hMoved : 1;
     bool vMoved : 1;
-    bool movingHorizontally : 1;
-    bool movingVertically : 1;
     bool stealMouse : 1;
     bool pressed : 1;
     bool interactive : 1;
index f2511a1..feabbf0 100644 (file)
 
 #include <qmath.h>
 #include <math.h>
+#include "qplatformdefs.h"
 
 QT_BEGIN_NAMESPACE
 
-
-
+#ifndef QML_FLICK_SNAPONETHRESHOLD
+#define QML_FLICK_SNAPONETHRESHOLD 30
+#endif
 
 //----------------------------------------------------------------------------
 
@@ -346,9 +348,12 @@ public:
         Q_Q(const QDeclarative1GridView);
         qreal snapPos = 0;
         if (!visibleItems.isEmpty()) {
+            qreal highlightStart = isRightToLeftTopToBottom() && highlightRangeStartValid ? size()-highlightRangeEnd : highlightRangeStart;
+            pos += highlightStart;
             pos += rowSize()/2;
             snapPos = visibleItems.first()->rowPos() - visibleIndex / columns * rowSize();
             snapPos = pos - fmodf(pos - snapPos, qreal(rowSize()));
+            snapPos -= highlightStart;
             qreal maxExtent;
             qreal minExtent;
             if (isRightToLeftTopToBottom()) {
@@ -876,7 +881,7 @@ void QDeclarative1GridViewPrivate::updateHighlight()
 {
     if ((!currentItem && highlight) || (currentItem && !highlight))
         createHighlight();
-    if (currentItem && autoHighlight && highlight && !movingHorizontally && !movingVertically) {
+    if (currentItem && autoHighlight && highlight && !hData.moving && !vData.moving) {
         // auto-update highlight
         highlightXAnimator->to = currentItem->item->x();
         highlightYAnimator->to = currentItem->item->y();
@@ -1061,12 +1066,36 @@ void QDeclarative1GridViewPrivate::fixup(AxisData &data, qreal minExtent, qreal
         highlightEnd = highlightRangeEnd;
     }
 
+    bool strictHighlightRange = haveHighlightRange && highlightRange == QDeclarative1GridView::StrictlyEnforceRange;
+
     if (snapMode != QDeclarative1GridView::NoSnap) {
         qreal tempPosition = isRightToLeftTopToBottom() ? -position()-size() : position();
+        if (snapMode == QDeclarative1GridView::SnapOneRow && moveReason == Mouse) {
+            // if we've been dragged < rowSize()/2 then bias towards the next row
+            qreal dist = data.move.value() - (data.pressPos - data.dragStartOffset);
+            qreal bias = 0;
+            if (data.velocity > 0 && dist > QML_FLICK_SNAPONETHRESHOLD && dist < rowSize()/2)
+                bias = rowSize()/2;
+            else if (data.velocity < 0 && dist < -QML_FLICK_SNAPONETHRESHOLD && dist > -rowSize()/2)
+                bias = -rowSize()/2;
+            if (isRightToLeftTopToBottom())
+                bias = -bias;
+            tempPosition -= bias;
+        }
         FxGridItem1 *topItem = snapItemAt(tempPosition+highlightStart);
+        if (!topItem && strictHighlightRange && currentItem) {
+            // StrictlyEnforceRange always keeps an item in range
+            updateHighlight();
+            topItem = currentItem;
+        }
         FxGridItem1 *bottomItem = snapItemAt(tempPosition+highlightEnd);
+        if (!bottomItem && strictHighlightRange && currentItem) {
+            // StrictlyEnforceRange always keeps an item in range
+            updateHighlight();
+            bottomItem = currentItem;
+        }
         qreal pos;
-        if (topItem && bottomItem && haveHighlightRange && highlightRange == QDeclarative1GridView::StrictlyEnforceRange) {
+        if (topItem && bottomItem && strictHighlightRange) {
             qreal topPos = qMin(topItem->rowPos() - highlightStart, -maxExtent);
             qreal bottomPos = qMax(bottomItem->rowPos() - highlightEnd, -minExtent);
             pos = qAbs(data.move + topPos) < qAbs(data.move + bottomPos) ? topPos : bottomPos;
@@ -1074,7 +1103,7 @@ void QDeclarative1GridViewPrivate::fixup(AxisData &data, qreal minExtent, qreal
             qreal headerPos = 0;
             if (header)
                 headerPos = isRightToLeftTopToBottom() ? header->rowPos() + cellWidth - headerSize() : header->rowPos();
-            if (topItem->index == 0 && header && tempPosition+highlightStart < headerPos+headerSize()/2) {
+            if (topItem->index == 0 && header && tempPosition+highlightStart < headerPos+headerSize()/2 && !strictHighlightRange) {
                 pos = isRightToLeftTopToBottom() ? - headerPos + highlightStart - size() : headerPos - highlightStart;
             } else {
                 if (isRightToLeftTopToBottom())
@@ -1084,25 +1113,13 @@ void QDeclarative1GridViewPrivate::fixup(AxisData &data, qreal minExtent, qreal
             }
         } else if (bottomItem) {
             if (isRightToLeftTopToBottom())
-                pos = qMax(qMin(-bottomItem->rowPos() + highlightStart - size(), -maxExtent), -minExtent);
+                pos = qMax(qMin(-bottomItem->rowPos() + highlightEnd - size(), -maxExtent), -minExtent);
             else
-                pos = qMax(qMin(bottomItem->rowPos() - highlightStart, -maxExtent), -minExtent);
+                pos = qMax(qMin(bottomItem->rowPos() - highlightEnd, -maxExtent), -minExtent);
         } else {
             QDeclarative1FlickablePrivate::fixup(data, minExtent, maxExtent);
             return;
         }
-        if (currentItem && haveHighlightRange && highlightRange == QDeclarative1GridView::StrictlyEnforceRange) {
-            updateHighlight();
-            qreal currPos = currentItem->rowPos();
-            if (isRightToLeftTopToBottom())
-                pos = -pos-size(); // Transform Pos if required
-            if (pos < currPos + rowSize() - highlightEnd)
-                pos = currPos + rowSize() - highlightEnd;
-            if (pos > currPos - highlightStart)
-                pos = currPos - highlightStart;
-            if (isRightToLeftTopToBottom())
-                pos = -pos-size(); // Untransform
-        }
         qreal dist = qAbs(data.move + pos);
         if (dist > 0) {
             timeline.reset(data.move);
@@ -1159,9 +1176,14 @@ void QDeclarative1GridViewPrivate::flick(AxisData &data, qreal minExtent, qreal
     if (velocity > 0) {
         if (data.move.value() < minExtent) {
             if (snapMode == QDeclarative1GridView::SnapOneRow) {
-                if (FxGridItem1 *item = firstVisibleItem()) {
-                    maxDistance = qAbs(item->rowPos() + dataValue);
-                }
+                // if we've been dragged < averageSize/2 then bias towards the next item
+                qreal dist = data.move.value() - (data.pressPos - data.dragStartOffset);
+                qreal bias = dist < rowSize()/2 ? rowSize()/2 : 0;
+                if (isRightToLeftTopToBottom())
+                    bias = -bias;
+                data.flickTarget = -snapPosAt(-dataValue - bias);
+                maxDistance = qAbs(data.flickTarget - data.move.value());
+                velocity = maxVelocity;
             } else {
                 maxDistance = qAbs(minExtent - data.move.value());
             }
@@ -1171,8 +1193,14 @@ void QDeclarative1GridViewPrivate::flick(AxisData &data, qreal minExtent, qreal
     } else {
         if (data.move.value() > maxExtent) {
             if (snapMode == QDeclarative1GridView::SnapOneRow) {
-                qreal pos = snapPosAt(-dataValue) + (isRightToLeftTopToBottom() ? 0 : rowSize());
-                maxDistance = qAbs(pos + dataValue);
+                // if we've been dragged < averageSize/2 then bias towards the next item
+                qreal dist = data.move.value() - (data.pressPos - data.dragStartOffset);
+                qreal bias = -dist < rowSize()/2 ? rowSize()/2 : 0;
+                if (isRightToLeftTopToBottom())
+                    bias = -bias;
+                data.flickTarget = -snapPosAt(-dataValue + bias);
+                maxDistance = qAbs(data.flickTarget - data.move.value());
+                velocity = -maxVelocity;
             } else {
                 maxDistance = qAbs(maxExtent - data.move.value());
             }
@@ -1182,7 +1210,6 @@ void QDeclarative1GridViewPrivate::flick(AxisData &data, qreal minExtent, qreal
     }
 
     bool overShoot = boundsBehavior == QDeclarative1Flickable::DragAndOvershootBounds;
-    qreal highlightStart = isRightToLeftTopToBottom() && highlightRangeStartValid ? size()-highlightRangeEnd : highlightRangeStart;
 
     if (maxDistance > 0 || overShoot) {
         // This mode requires the grid to stop exactly on a row boundary.
@@ -1202,9 +1229,20 @@ void QDeclarative1GridViewPrivate::flick(AxisData &data, qreal minExtent, qreal
             dist = qMin(dist, maxDistance);
             if (v > 0)
                 dist = -dist;
-            qreal distTemp = isRightToLeftTopToBottom() ? -dist : dist;
-            data.flickTarget = -snapPosAt(-(dataValue - highlightStart) + distTemp) + highlightStart;
+            if (snapMode != QDeclarative1GridView::SnapOneRow) {
+                qreal distTemp = isRightToLeftTopToBottom() ? -dist : dist;
+                data.flickTarget = -snapPosAt(-dataValue + distTemp);
+            }
             data.flickTarget = isRightToLeftTopToBottom() ? -data.flickTarget+size() : data.flickTarget;
+            if (overShoot) {
+                if (data.flickTarget >= minExtent) {
+                    overshootDist = overShootDistance(vSize);
+                    data.flickTarget += overshootDist;
+                } else if (data.flickTarget <= maxExtent) {
+                    overshootDist = overShootDistance(vSize);
+                    data.flickTarget -= overshootDist;
+                }
+            }
             qreal adjDist = -data.flickTarget + data.move.value();
             if (qAbs(adjDist) > qAbs(dist)) {
                 // Prevent painfully slow flicking - adjust velocity to suit flickDeceleration
@@ -1225,14 +1263,14 @@ void QDeclarative1GridViewPrivate::flick(AxisData &data, qreal minExtent, qreal
         timeline.reset(data.move);
         timeline.accel(data.move, v, accel, maxDistance + overshootDist);
         timeline.callback(QDeclarative1TimeLineCallback(&data.move, fixupCallback, this));
-        if (!flickingHorizontally && q->xflick()) {
-            flickingHorizontally = true;
+        if (!hData.flicking && q->xflick()) {
+            hData.flicking = true;
             emit q->flickingChanged();
             emit q->flickingHorizontallyChanged();
             emit q->flickStarted();
         }
-        if (!flickingVertically && q->yflick()) {
-            flickingVertically = true;
+        if (!vData.flicking && q->yflick()) {
+            vData.flicking = true;
             emit q->flickingChanged();
             emit q->flickingVerticallyChanged();
             emit q->flickStarted();
@@ -1557,6 +1595,8 @@ void QDeclarative1GridView::setCurrentIndex(int index)
     if (index == d->currentIndex)
         return;
     if (isComponentComplete() && d->isValid()) {
+        if (d->layoutScheduled)
+            d->layout();
         d->moveReason = QDeclarative1GridViewPrivate::SetIndex;
         d->updateCurrent(index);
     } else {
@@ -2110,7 +2150,8 @@ bool QDeclarative1GridView::event(QEvent *event)
 {
     Q_D(QDeclarative1GridView);
     if (event->type() == QEvent::User) {
-        d->layout();
+        if (d->layoutScheduled)
+            d->layout();
         return true;
     }
 
@@ -2124,7 +2165,7 @@ void QDeclarative1GridView::viewportMoved()
     if (!d->itemCount)
         return;
     d->lazyRelease = true;
-    if (d->flickingHorizontally || d->flickingVertically) {
+    if (d->hData.flicking || d->vData.flicking) {
         if (yflick()) {
             if (d->vData.velocity > 0)
                 d->bufferMode = QDeclarative1GridViewPrivate::BufferBefore;
@@ -2140,7 +2181,7 @@ void QDeclarative1GridView::viewportMoved()
         }
     }
     refill();
-    if (d->flickingHorizontally || d->flickingVertically || d->movingHorizontally || d->movingVertically)
+    if (d->hData.flicking || d->vData.flicking || d->hData.moving || d->vData.moving)
         d->moveReason = QDeclarative1GridViewPrivate::Mouse;
     if (d->moveReason != QDeclarative1GridViewPrivate::SetIndex) {
         if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange && d->highlight) {
@@ -2928,6 +2969,11 @@ void QDeclarative1GridView::itemsRemoved(int modelIndex, int count)
         }
     }
 
+    // If we removed items before visible items a layout may be
+    // required to ensure item 0 is in the first column.
+    if (!removedVisible && modelIndex < d->visibleIndex)
+        d->scheduleLayout();
+
     // fix current
     if (d->currentIndex >= modelIndex + count) {
         d->currentIndex -= count;
index 5119c0e..7b9cb12 100644 (file)
 
 #include <qmath.h>
 #include <QKeyEvent>
+#include "qplatformdefs.h"
 
 QT_BEGIN_NAMESPACE
 
-
+#ifndef QML_FLICK_SNAPONETHRESHOLD
+#define QML_FLICK_SNAPONETHRESHOLD 30
+#endif
 
 void QDeclarative1ViewSection::setProperty(const QString &property)
 {
@@ -235,21 +238,6 @@ public:
         return visibleItems.count() ? visibleItems.first() : 0;
     }
 
-    FxListItem1 *nextVisibleItem() const {
-        const qreal pos = isRightToLeft() ? -position()-size() : position();
-        bool foundFirst = false;
-        for (int i = 0; i < visibleItems.count(); ++i) {
-            FxListItem1 *item = visibleItems.at(i);
-            if (item->index != -1) {
-                if (foundFirst)
-                    return item;
-                else if (item->position() < pos && item->endPosition() > pos)
-                    foundFirst = true;
-            }
-        }
-        return 0;
-    }
-
     // Returns the item before modelIndex, if created.
     // May return an item marked for removal.
     FxListItem1 *itemBefore(int modelIndex) const {
@@ -1013,7 +1001,7 @@ void QDeclarative1ListViewPrivate::updateHighlight()
 {
     if ((!currentItem && highlight) || (currentItem && !highlight))
         createHighlight();
-    if (currentItem && autoHighlight && highlight && !movingHorizontally && !movingVertically) {
+    if (currentItem && autoHighlight && highlight && !hData.moving && !vData.moving) {
         // auto-update highlight
         highlightPosAnimator->to = isRightToLeft()
                 ? -currentItem->itemPosition()-currentItem->itemSize()
@@ -1308,6 +1296,7 @@ void QDeclarative1ListViewPrivate::fixup(AxisData &data, qreal minExtent, qreal
 
     correctFlick = false;
     fixupMode = moveReason == Mouse ? fixupMode : Immediate;
+    bool strictHighlightRange = haveHighlightRange && highlightRange == QDeclarative1ListView::StrictlyEnforceRange;
 
     qreal highlightStart;
     qreal highlightEnd;
@@ -1323,35 +1312,36 @@ void QDeclarative1ListViewPrivate::fixup(AxisData &data, qreal minExtent, qreal
         highlightEnd = highlightRangeEnd;
     }
 
-    if (currentItem && haveHighlightRange && highlightRange == QDeclarative1ListView::StrictlyEnforceRange
-            && moveReason != QDeclarative1ListViewPrivate::SetIndex) {
-        updateHighlight();
-        qreal pos = currentItem->itemPosition();
-        if (viewPos < pos + currentItem->itemSize() - highlightEnd)
-            viewPos = pos + currentItem->itemSize() - highlightEnd;
-        if (viewPos > pos - highlightStart)
-            viewPos = pos - highlightStart;
-        if (isRightToLeft())
-            viewPos = -viewPos-size();
-
-        timeline.reset(data.move);
-        if (viewPos != position()) {
-            if (fixupMode != Immediate) {
-                timeline.move(data.move, -viewPos, QEasingCurve(QEasingCurve::InOutQuad), fixupDuration/2);
-                data.fixingUp = true;
-            } else {
-                timeline.set(data.move, -viewPos);
-            }
-        }
-        vTime = timeline.time();
-    } else if (snapMode != QDeclarative1ListView::NoSnap && moveReason != QDeclarative1ListViewPrivate::SetIndex) {
+    if (snapMode != QDeclarative1ListView::NoSnap && moveReason != QDeclarative1ListViewPrivate::SetIndex) {
         qreal tempPosition = isRightToLeft() ? -position()-size() : position();
+        if (snapMode == QDeclarative1ListView::SnapOneItem && moveReason == Mouse) {
+            // if we've been dragged < averageSize/2 then bias towards the next item
+            qreal dist = data.move.value() - (data.pressPos - data.dragStartOffset);
+            qreal bias = 0;
+            if (data.velocity > 0 && dist > QML_FLICK_SNAPONETHRESHOLD && dist < averageSize/2)
+                bias = averageSize/2;
+            else if (data.velocity < 0 && dist < -QML_FLICK_SNAPONETHRESHOLD && dist > -averageSize/2)
+                bias = -averageSize/2;
+            if (isRightToLeft())
+                bias = -bias;
+            tempPosition -= bias;
+        }
         FxListItem1 *topItem = snapItemAt(tempPosition+highlightStart);
+        if (!topItem && strictHighlightRange && currentItem) {
+            // StrictlyEnforceRange always keeps an item in range
+            updateHighlight();
+            topItem = currentItem;
+        }
         FxListItem1 *bottomItem = snapItemAt(tempPosition+highlightEnd);
+        if (!bottomItem && strictHighlightRange && currentItem) {
+            // StrictlyEnforceRange always keeps an item in range
+            updateHighlight();
+            bottomItem = currentItem;
+        }
         qreal pos;
-        bool isInBounds = -position() > maxExtent && -position() < minExtent;
-        if (topItem && isInBounds) {
-            if (topItem->index == 0 && header && tempPosition+highlightStart < header->position()+header->size()/2) {
+        bool isInBounds = -position() > maxExtent && -position() <= minExtent;
+        if (topItem && (isInBounds || strictHighlightRange)) {
+            if (topItem->index == 0 && header && tempPosition+highlightStart < header->position()+header->size()/2 && !strictHighlightRange) {
                 pos = isRightToLeft() ? - header->position() + highlightStart - size() : header->position() - highlightStart;
             } else {
                 if (isRightToLeft())
@@ -1361,9 +1351,9 @@ void QDeclarative1ListViewPrivate::fixup(AxisData &data, qreal minExtent, qreal
             }
         } else if (bottomItem && isInBounds) {
             if (isRightToLeft())
-                pos = qMax(qMin(-bottomItem->position() + highlightStart - size(), -maxExtent), -minExtent);
+                pos = qMax(qMin(-bottomItem->position() + highlightEnd - size(), -maxExtent), -minExtent);
             else
-                pos = qMax(qMin(bottomItem->position() - highlightStart, -maxExtent), -minExtent);
+                pos = qMax(qMin(bottomItem->position() - highlightEnd, -maxExtent), -minExtent);
         } else {
             QDeclarative1FlickablePrivate::fixup(data, minExtent, maxExtent);
             return;
@@ -1380,6 +1370,27 @@ void QDeclarative1ListViewPrivate::fixup(AxisData &data, qreal minExtent, qreal
             }
             vTime = timeline.time();
         }
+    } else if (currentItem && strictHighlightRange
+                && moveReason != QDeclarative1ListViewPrivate::SetIndex) {
+        updateHighlight();
+        qreal pos = currentItem->itemPosition();
+        if (viewPos < pos + currentItem->itemSize() - highlightEnd)
+            viewPos = pos + currentItem->itemSize() - highlightEnd;
+        if (viewPos > pos - highlightStart)
+            viewPos = pos - highlightStart;
+        if (isRightToLeft())
+            viewPos = -viewPos-size();
+
+        timeline.reset(data.move);
+        if (viewPos != position()) {
+            if (fixupMode != Immediate) {
+                timeline.move(data.move, -viewPos, QEasingCurve(QEasingCurve::InOutQuad), fixupDuration/2);
+                data.fixingUp = true;
+            } else {
+                timeline.set(data.move, -viewPos);
+            }
+        }
+        vTime = timeline.time();
     } else {
         QDeclarative1FlickablePrivate::fixup(data, minExtent, maxExtent);
     }
@@ -1401,12 +1412,19 @@ void QDeclarative1ListViewPrivate::flick(AxisData &data, qreal minExtent, qreal
     }
     qreal maxDistance = 0;
     qreal dataValue = isRightToLeft() ? -data.move.value()+size() : data.move.value();
+    qreal highlightStart = isRightToLeft() && highlightRangeStartValid ? size()-highlightRangeEnd : highlightRangeStart;
     // -ve velocity means list is moving up/left
     if (velocity > 0) {
         if (data.move.value() < minExtent) {
-            if (snapMode == QDeclarative1ListView::SnapOneItem) {
-                if (FxListItem1 *item = isRightToLeft() ? nextVisibleItem() : firstVisibleItem())
-                    maxDistance = qAbs(item->position() + dataValue);
+            if (snapMode == QDeclarative1ListView::SnapOneItem && !hData.flicking && !vData.flicking) {
+                // if we've been dragged < averageSize/2 then bias towards the next item
+                qreal dist = data.move.value() - (data.pressPos - data.dragStartOffset);
+                qreal bias = dist < averageSize/2 ? averageSize/2 : 0;
+                if (isRightToLeft())
+                    bias = -bias;
+                data.flickTarget = -snapPosAt(-(dataValue - highlightStart) - bias) + highlightStart;
+                maxDistance = qAbs(data.flickTarget - data.move.value());
+                velocity = maxVelocity;
             } else {
                 maxDistance = qAbs(minExtent - data.move.value());
             }
@@ -1415,9 +1433,15 @@ void QDeclarative1ListViewPrivate::flick(AxisData &data, qreal minExtent, qreal
             data.flickTarget = minExtent;
     } else {
         if (data.move.value() > maxExtent) {
-            if (snapMode == QDeclarative1ListView::SnapOneItem) {
-                if (FxListItem1 *item = isRightToLeft() ? firstVisibleItem() : nextVisibleItem())
-                    maxDistance = qAbs(item->position() + dataValue);
+            if (snapMode == QDeclarative1ListView::SnapOneItem && !hData.flicking && !vData.flicking) {
+                // if we've been dragged < averageSize/2 then bias towards the next item
+                qreal dist = data.move.value() - (data.pressPos - data.dragStartOffset);
+                qreal bias = -dist < averageSize/2 ? averageSize/2 : 0;
+                if (isRightToLeft())
+                    bias = -bias;
+                data.flickTarget = -snapPosAt(-(dataValue - highlightStart) + bias) + highlightStart;
+                maxDistance = qAbs(data.flickTarget - data.move.value());
+                velocity = -maxVelocity;
             } else {
                 maxDistance = qAbs(maxExtent - data.move.value());
             }
@@ -1427,7 +1451,6 @@ void QDeclarative1ListViewPrivate::flick(AxisData &data, qreal minExtent, qreal
     }
 
     bool overShoot = boundsBehavior == QDeclarative1Flickable::DragAndOvershootBounds;
-    qreal highlightStart = isRightToLeft() && highlightRangeStartValid ? size()-highlightRangeEnd : highlightRangeStart;
 
     if (maxDistance > 0 || overShoot) {
         // These modes require the list to stop exactly on an item boundary.
@@ -1441,7 +1464,7 @@ void QDeclarative1ListViewPrivate::flick(AxisData &data, qreal minExtent, qreal
             else
                 v = maxVelocity;
         }
-        if (!flickingHorizontally && !flickingVertically) {
+        if (!hData.flicking && !vData.flicking) {
             // the initial flick - estimate boundary
             qreal accel = deceleration;
             qreal v2 = v * v;
@@ -1453,8 +1476,10 @@ void QDeclarative1ListViewPrivate::flick(AxisData &data, qreal minExtent, qreal
             if (v > 0)
                 dist = -dist;
             if ((maxDistance > 0.0 && v2 / (2.0f * maxDistance) < accel) || snapMode == QDeclarative1ListView::SnapOneItem) {
-                qreal distTemp = isRightToLeft() ? -dist : dist;
-                data.flickTarget = -snapPosAt(-(dataValue - highlightStart) + distTemp) + highlightStart;
+                if (snapMode != QDeclarative1ListView::SnapOneItem) {
+                    qreal distTemp = isRightToLeft() ? -dist : dist;
+                    data.flickTarget = -snapPosAt(-(dataValue - highlightStart) + distTemp) + highlightStart;
+                }
                 data.flickTarget = isRightToLeft() ? -data.flickTarget+size() : data.flickTarget;
                 if (overShoot) {
                     if (data.flickTarget >= minExtent) {
@@ -1492,14 +1517,14 @@ void QDeclarative1ListViewPrivate::flick(AxisData &data, qreal minExtent, qreal
             timeline.reset(data.move);
             timeline.accel(data.move, v, accel, maxDistance + overshootDist);
             timeline.callback(QDeclarative1TimeLineCallback(&data.move, fixupCallback, this));
-            if (!flickingHorizontally && q->xflick()) {
-                flickingHorizontally = true;
+            if (!hData.flicking && q->xflick()) {
+                hData.flicking = true;
                 emit q->flickingChanged();
                 emit q->flickingHorizontallyChanged();
                 emit q->flickStarted();
             }
-            if (!flickingVertically && q->yflick()) {
-                flickingVertically = true;
+            if (!vData.flicking && q->yflick()) {
+                vData.flicking = true;
                 emit q->flickingChanged();
                 emit q->flickingVerticallyChanged();
                 emit q->flickStarted();
@@ -1876,6 +1901,8 @@ void QDeclarative1ListView::setCurrentIndex(int index)
     if (index == d->currentIndex)
         return;
     if (isComponentComplete() && d->isValid()) {
+        if (d->layoutScheduled)
+            d->layout();
         d->moveReason = QDeclarative1ListViewPrivate::SetIndex;
         d->updateCurrent(index);
     } else if (d->currentIndex != index) {
@@ -2568,7 +2595,8 @@ bool QDeclarative1ListView::event(QEvent *event)
 {
     Q_D(QDeclarative1ListView);
     if (event->type() == QEvent::User) {
-        d->layout();
+        if (d->layoutScheduled)
+            d->layout();
         return true;
     }
 
@@ -2587,7 +2615,7 @@ void QDeclarative1ListView::viewportMoved()
     d->inViewportMoved = true;
     d->lazyRelease = true;
     refill();
-    if (d->flickingHorizontally || d->flickingVertically || d->movingHorizontally || d->movingVertically)
+    if (d->hData.flicking || d->vData.flicking || d->hData.moving || d->vData.moving)
         d->moveReason = QDeclarative1ListViewPrivate::Mouse;
     if (d->moveReason != QDeclarative1ListViewPrivate::SetIndex) {
         if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange && d->highlight) {
@@ -2621,7 +2649,7 @@ void QDeclarative1ListView::viewportMoved()
         }
     }
 
-    if ((d->flickingHorizontally || d->flickingVertically) && d->correctFlick && !d->inFlickCorrection) {
+    if ((d->hData.flicking || d->vData.flicking) && d->correctFlick && !d->inFlickCorrection) {
         d->inFlickCorrection = true;
         // Near an end and it seems that the extent has changed?
         // Recalculate the flick so that we don't end up in an odd position.
index e96af51..c370a01 100644 (file)
@@ -448,12 +448,12 @@ void tst_QDeclarative1GridView::removed()
     model.removeItem(1);
 
     // Confirm items positioned correctly
-    for (int i = 6; i < 18; ++i) {
+    for (int i = 3; i < 15; ++i) {
         QDeclarativeItem *item = findItem<QDeclarativeItem>(contentItem, "wrapper", i);
         if (!item) qWarning() << "Item" << i << "not found";
         QTRY_VERIFY(item);
-        QTRY_VERIFY(item->x() == (i%3)*80);
-        QTRY_VERIFY(item->y() == (i/3)*60);
+        QTRY_COMPARE(item->x(), (i%3)*80.0);
+        QTRY_COMPARE(item->y(), 60+(i/3)*60.0);
     }
 
     // Remove currentIndex
@@ -474,7 +474,7 @@ void tst_QDeclarative1GridView::removed()
         if (!item) qWarning() << "Item" << i << "not found";
         QTRY_VERIFY(item);
         QTRY_VERIFY(item->x() == (i%3)*80);
-        QTRY_VERIFY(item->y() == (i/3)*60);
+        QTRY_VERIFY(item->y() == 60+(i/3)*60);
     }
 
     // remove item outside current view.