diff options
5 files changed, 108 insertions, 45 deletions
diff --git a/src/declarative/graphicsitems/qdeclarativeflickable.cpp b/src/declarative/graphicsitems/qdeclarativeflickable.cpp index 364d76f..d64c347 100644 --- a/src/declarative/graphicsitems/qdeclarativeflickable.cpp +++ b/src/declarative/graphicsitems/qdeclarativeflickable.cpp @@ -143,7 +143,7 @@ QDeclarativeFlickablePrivate::QDeclarativeFlickablePrivate() , stealMouse(false), pressed(false), interactive(true), calcVelocity(false) , deceleration(500), maxVelocity(2000), reportedVelocitySmoothing(100) , delayedPressEvent(0), delayedPressTarget(0), pressDelay(0), fixupDuration(600) - , vTime(0), visibleArea(0) + , fixupMode(Normal), vTime(0), visibleArea(0) , flickableDirection(QDeclarativeFlickable::AutoFlickDirection) , boundsBehavior(QDeclarativeFlickable::DragAndOvershootBounds) { @@ -219,6 +219,7 @@ void QDeclarativeFlickablePrivate::flick(AxisData &data, qreal minExtent, qreal { Q_Q(QDeclarativeFlickable); qreal maxDistance = -1; + data.fixingUp = false; bool overShoot = boundsBehavior == QDeclarativeFlickable::DragAndOvershootBounds; // -ve velocity means list is moving up if (velocity > 0) { @@ -288,24 +289,45 @@ void QDeclarativeFlickablePrivate::fixup(AxisData &data, qreal minExtent, qreal if (data.move.value() > minExtent || maxExtent > minExtent) { timeline.reset(data.move); if (data.move.value() != minExtent) { - if (fixupDuration) { - qreal dist = minExtent - data.move; - timeline.move(data.move, minExtent - dist/2, QEasingCurve(QEasingCurve::InQuad), fixupDuration/4); - timeline.move(data.move, minExtent, QEasingCurve(QEasingCurve::OutExpo), 3*fixupDuration/4); - } else { + switch (fixupMode) { + case Immediate: timeline.set(data.move, minExtent); + break; + case ExtentChanged: + // The target has changed. Don't start from the beginning; just complete the + // second half of the animation using the new extent. + timeline.move(data.move, minExtent, QEasingCurve(QEasingCurve::OutExpo), 3*fixupDuration/4); + data.fixingUp = true; + break; + default: { + qreal dist = minExtent - data.move; + timeline.move(data.move, minExtent - dist/2, QEasingCurve(QEasingCurve::InQuad), fixupDuration/4); + timeline.move(data.move, minExtent, QEasingCurve(QEasingCurve::OutExpo), 3*fixupDuration/4); + data.fixingUp = true; + } } } } else if (data.move.value() < maxExtent) { timeline.reset(data.move); - if (fixupDuration) { - qreal dist = maxExtent - data.move; - timeline.move(data.move, maxExtent - dist/2, QEasingCurve(QEasingCurve::InQuad), fixupDuration/4); - timeline.move(data.move, maxExtent, QEasingCurve(QEasingCurve::OutExpo), 3*fixupDuration/4); - } else { + switch (fixupMode) { + case Immediate: timeline.set(data.move, maxExtent); + break; + case ExtentChanged: + // The target has changed. Don't start from the beginning; just complete the + // second half of the animation using the new extent. + timeline.move(data.move, maxExtent, QEasingCurve(QEasingCurve::OutExpo), 3*fixupDuration/4); + data.fixingUp = true; + break; + default: { + qreal dist = maxExtent - data.move; + timeline.move(data.move, maxExtent - dist/2, QEasingCurve(QEasingCurve::InQuad), fixupDuration/4); + timeline.move(data.move, maxExtent, QEasingCurve(QEasingCurve::OutExpo), 3*fixupDuration/4); + data.fixingUp = true; + } } } + fixupMode = Normal; vTime = timeline.time(); } @@ -688,6 +710,12 @@ void QDeclarativeFlickablePrivate::handleMousePressEvent(QGraphicsSceneMouseEven vData.velocity = 0; hData.dragStartOffset = 0; vData.dragStartOffset = 0; + hData.dragMinBound = q->minXExtent(); + vData.dragMinBound = q->minYExtent(); + hData.dragMaxBound = q->maxXExtent(); + vData.dragMaxBound = q->maxYExtent(); + hData.fixingUp = false; + vData.fixingUp = false; lastPos = QPoint(); QDeclarativeItemPrivate::start(lastPosTime); pressPos = event->pos(); @@ -716,8 +744,8 @@ void QDeclarativeFlickablePrivate::handleMouseMoveEvent(QGraphicsSceneMouseEvent if (!vMoved) vData.dragStartOffset = dy; qreal newY = dy + vData.pressPos - vData.dragStartOffset; - const qreal minY = q->minYExtent(); - const qreal maxY = q->maxYExtent(); + const qreal minY = vData.dragMinBound; + const qreal maxY = vData.dragMaxBound; if (newY > minY) newY = minY + (newY - minY) / 2; if (newY < maxY && maxY - minY <= 0) @@ -748,8 +776,8 @@ void QDeclarativeFlickablePrivate::handleMouseMoveEvent(QGraphicsSceneMouseEvent if (!hMoved) hData.dragStartOffset = dx; qreal newX = dx + hData.pressPos - hData.dragStartOffset; - const qreal minX = q->minXExtent(); - const qreal maxX = q->maxXExtent(); + const qreal minX = hData.dragMinBound; + const qreal maxX = hData.dragMaxBound; if (newX > minX) newX = minX + (newX - minX) / 2; if (newX < maxX && maxX - minX <= 0) @@ -1065,10 +1093,8 @@ void QDeclarativeFlickable::geometryChanged(const QRectF &newGeometry, } // Make sure that we're entirely in view. if (!d->pressed && !d->movingHorizontally && !d->movingVertically) { - int oldDuration = d->fixupDuration; - d->fixupDuration = 0; + d->fixupMode = QDeclarativeFlickablePrivate::Immediate; d->fixupX(); - d->fixupDuration = oldDuration; } } if (newGeometry.height() != oldGeometry.height()) { @@ -1080,10 +1106,8 @@ void QDeclarativeFlickable::geometryChanged(const QRectF &newGeometry, } // Make sure that we're entirely in view. if (!d->pressed && !d->movingHorizontally && !d->movingVertically) { - int oldDuration = d->fixupDuration; - d->fixupDuration = 0; + d->fixupMode = QDeclarativeFlickablePrivate::Immediate; d->fixupY(); - d->fixupDuration = oldDuration; } } @@ -1258,10 +1282,11 @@ void QDeclarativeFlickable::setContentWidth(qreal w) d->contentItem->setWidth(w); // Make sure that we're entirely in view. if (!d->pressed && !d->movingHorizontally && !d->movingVertically) { - int oldDuration = d->fixupDuration; - d->fixupDuration = 0; + d->fixupMode = QDeclarativeFlickablePrivate::Immediate; + d->fixupX(); + } else if (!d->pressed && d->hData.fixingUp) { + d->fixupMode = QDeclarativeFlickablePrivate::ExtentChanged; d->fixupX(); - d->fixupDuration = oldDuration; } emit contentWidthChanged(); d->updateBeginningEnd(); @@ -1285,10 +1310,11 @@ void QDeclarativeFlickable::setContentHeight(qreal h) d->contentItem->setHeight(h); // Make sure that we're entirely in view. if (!d->pressed && !d->movingHorizontally && !d->movingVertically) { - int oldDuration = d->fixupDuration; - d->fixupDuration = 0; + d->fixupMode = QDeclarativeFlickablePrivate::Immediate; + d->fixupY(); + } else if (!d->pressed && d->vData.fixingUp) { + d->fixupMode = QDeclarativeFlickablePrivate::ExtentChanged; d->fixupY(); - d->fixupDuration = oldDuration; } emit contentHeightChanged(); d->updateBeginningEnd(); @@ -1660,6 +1686,7 @@ void QDeclarativeFlickable::movementXEnding() emit movementEnded(); } } + d->hData.fixingUp = false; } void QDeclarativeFlickable::movementYEnding() @@ -1682,6 +1709,7 @@ void QDeclarativeFlickable::movementYEnding() emit movementEnded(); } } + d->vData.fixingUp = false; } void QDeclarativeFlickablePrivate::updateVelocity() diff --git a/src/declarative/graphicsitems/qdeclarativeflickable_p_p.h b/src/declarative/graphicsitems/qdeclarativeflickable_p_p.h index 1b6081c..38a5eb3 100644 --- a/src/declarative/graphicsitems/qdeclarativeflickable_p_p.h +++ b/src/declarative/graphicsitems/qdeclarativeflickable_p_p.h @@ -94,17 +94,21 @@ public: struct AxisData { AxisData(QDeclarativeFlickablePrivate *fp, void (QDeclarativeFlickablePrivate::*func)(qreal)) : move(fp, func), viewSize(-1), smoothVelocity(fp), atEnd(false), atBeginning(true) + , fixingUp(false) {} QDeclarativeTimeLineValueProxy<QDeclarativeFlickablePrivate> move; qreal viewSize; qreal pressPos; qreal dragStartOffset; + qreal dragMinBound; + qreal dragMaxBound; qreal velocity; qreal flickTarget; QDeclarativeFlickablePrivate::Velocity smoothVelocity; bool atEnd : 1; bool atBeginning : 1; + bool fixingUp : 1; }; void flickX(qreal velocity); @@ -161,6 +165,9 @@ public: int pressDelay; int fixupDuration; + enum FixupMode { Normal, Immediate, ExtentChanged }; + FixupMode fixupMode; + static void fixupY_callback(void *); static void fixupX_callback(void *); diff --git a/src/declarative/graphicsitems/qdeclarativegridview.cpp b/src/declarative/graphicsitems/qdeclarativegridview.cpp index 00e5b3f..1d2ad1c 100644 --- a/src/declarative/graphicsitems/qdeclarativegridview.cpp +++ b/src/declarative/graphicsitems/qdeclarativegridview.cpp @@ -912,8 +912,7 @@ void QDeclarativeGridViewPrivate::fixup(AxisData &data, qreal minExtent, qreal m || (flow == QDeclarativeGridView::LeftToRight && &data == &hData)) return; - int oldDuration = fixupDuration; - fixupDuration = moveReason == Mouse ? fixupDuration : 0; + fixupMode = moveReason == Mouse ? fixupMode : Immediate; if (snapMode != QDeclarativeGridView::NoSnap) { FxGridItem *topItem = snapItemAt(position()+highlightRangeStart); @@ -932,7 +931,6 @@ void QDeclarativeGridViewPrivate::fixup(AxisData &data, qreal minExtent, qreal m pos = qMax(qMin(bottomItem->rowPos() - highlightRangeStart, -maxExtent), -minExtent); } else { QDeclarativeFlickablePrivate::fixup(data, minExtent, maxExtent); - fixupDuration = oldDuration; return; } if (currentItem && haveHighlightRange && highlightRange == QDeclarativeGridView::StrictlyEnforceRange) { @@ -947,10 +945,12 @@ void QDeclarativeGridViewPrivate::fixup(AxisData &data, qreal minExtent, qreal m qreal dist = qAbs(data.move + pos); if (dist > 0) { timeline.reset(data.move); - if (fixupDuration) + if (fixupMode != Immediate) { timeline.move(data.move, -pos, QEasingCurve(QEasingCurve::InOutQuad), fixupDuration/2); - else + data.fixingUp = true; + } else { timeline.set(data.move, -pos); + } vTime = timeline.time(); } } else if (haveHighlightRange && highlightRange == QDeclarativeGridView::StrictlyEnforceRange) { @@ -965,23 +965,26 @@ void QDeclarativeGridViewPrivate::fixup(AxisData &data, qreal minExtent, qreal m timeline.reset(data.move); if (viewPos != position()) { - if (fixupDuration) + if (fixupMode != Immediate) { timeline.move(data.move, -viewPos, QEasingCurve(QEasingCurve::InOutQuad), fixupDuration/2); - else + data.fixingUp = true; + } else { timeline.set(data.move, -viewPos); + } } vTime = timeline.time(); } } else { QDeclarativeFlickablePrivate::fixup(data, minExtent, maxExtent); } - fixupDuration = oldDuration; + fixupMode = Normal; } void QDeclarativeGridViewPrivate::flick(AxisData &data, qreal minExtent, qreal maxExtent, qreal vSize, QDeclarativeTimeLineCallback::Callback fixupCallback, qreal velocity) { Q_Q(QDeclarativeGridView); + data.fixingUp = false; moveReason = Mouse; if ((!haveHighlightRange || highlightRange != QDeclarativeGridView::StrictlyEnforceRange) && snapMode == QDeclarativeGridView::NoSnap) { diff --git a/src/declarative/graphicsitems/qdeclarativelistview.cpp b/src/declarative/graphicsitems/qdeclarativelistview.cpp index e8bc1bf..e369ba6 100644 --- a/src/declarative/graphicsitems/qdeclarativelistview.cpp +++ b/src/declarative/graphicsitems/qdeclarativelistview.cpp @@ -1198,8 +1198,7 @@ void QDeclarativeListViewPrivate::fixup(AxisData &data, qreal minExtent, qreal m return; correctFlick = false; - int oldDuration = fixupDuration; - fixupDuration = moveReason == Mouse ? fixupDuration : 0; + fixupMode = moveReason == Mouse ? fixupMode : Immediate; if (currentItem && haveHighlightRange && highlightRange == QDeclarativeListView::StrictlyEnforceRange) { updateHighlight(); @@ -1212,10 +1211,12 @@ void QDeclarativeListViewPrivate::fixup(AxisData &data, qreal minExtent, qreal m timeline.reset(data.move); if (viewPos != position()) { - if (fixupDuration) + if (fixupMode != Immediate) { timeline.move(data.move, -viewPos, QEasingCurve(QEasingCurve::InOutQuad), fixupDuration/2); - else + data.fixingUp = true; + } else { timeline.set(data.move, -viewPos); + } } vTime = timeline.time(); } else if (snapMode != QDeclarativeListView::NoSnap) { @@ -1231,23 +1232,24 @@ void QDeclarativeListViewPrivate::fixup(AxisData &data, qreal minExtent, qreal m pos = qMax(qMin(bottomItem->position() - highlightRangeStart, -maxExtent), -minExtent); } else { QDeclarativeFlickablePrivate::fixup(data, minExtent, maxExtent); - fixupDuration = oldDuration; return; } qreal dist = qAbs(data.move + pos); if (dist > 0) { timeline.reset(data.move); - if (fixupDuration) + if (fixupMode != Immediate) { timeline.move(data.move, -pos, QEasingCurve(QEasingCurve::InOutQuad), fixupDuration/2); - else + data.fixingUp = true; + } else { timeline.set(data.move, -pos); + } vTime = timeline.time(); } } else { QDeclarativeFlickablePrivate::fixup(data, minExtent, maxExtent); } - fixupDuration = oldDuration; + fixupMode = Normal; } void QDeclarativeListViewPrivate::flick(AxisData &data, qreal minExtent, qreal maxExtent, qreal vSize, @@ -1255,6 +1257,7 @@ void QDeclarativeListViewPrivate::flick(AxisData &data, qreal minExtent, qreal m { Q_Q(QDeclarativeListView); + data.fixingUp = false; moveReason = Mouse; if ((!haveHighlightRange || highlightRange != QDeclarativeListView::StrictlyEnforceRange) && snapMode == QDeclarativeListView::NoSnap) { correctFlick = true; diff --git a/tests/auto/declarative/qdeclarativelistview/tst_qdeclarativelistview.cpp b/tests/auto/declarative/qdeclarativelistview/tst_qdeclarativelistview.cpp index cceeb63..e326136 100644 --- a/tests/auto/declarative/qdeclarativelistview/tst_qdeclarativelistview.cpp +++ b/tests/auto/declarative/qdeclarativelistview/tst_qdeclarativelistview.cpp @@ -1104,7 +1104,7 @@ void tst_QDeclarativeListView::sectionsDelegate() model.modifyItem(9, "Two", "aaa"); model.modifyItem(10, "Two", "aaa"); model.modifyItem(11, "Two", "aaa"); - QTest::qWait(100); + QTRY_COMPARE(findItems<QDeclarativeItem>(contentItem, "sect_aaa").count(), 1); canvas->rootObject()->setProperty("sectionProperty", "name"); // ensure view has settled. QTRY_COMPARE(findItems<QDeclarativeItem>(contentItem, "sect_Four").count(), 1); @@ -1115,6 +1115,28 @@ void tst_QDeclarativeListView::sectionsDelegate() QTRY_COMPARE(item->y(), qreal(i*20*4)); } + // QTBUG-17769 + model.removeItems(10, 20); + // ensure view has settled. + QTRY_COMPARE(findItems<QDeclarativeItem>(contentItem, "wrapper").count(), 10); + // Drag view up beyond bounds + QTest::mousePress(canvas->viewport(), Qt::LeftButton, 0, canvas->mapFromScene(QPoint(20,20))); + { + QMouseEvent mv(QEvent::MouseMove, canvas->mapFromScene(QPoint(20,0)), Qt::LeftButton, Qt::LeftButton,Qt::NoModifier); + QApplication::sendEvent(canvas->viewport(), &mv); + } + { + QMouseEvent mv(QEvent::MouseMove, canvas->mapFromScene(QPoint(20,-50)), Qt::LeftButton, Qt::LeftButton,Qt::NoModifier); + QApplication::sendEvent(canvas->viewport(), &mv); + } + { + QMouseEvent mv(QEvent::MouseMove, canvas->mapFromScene(QPoint(20,-200)), Qt::LeftButton, Qt::LeftButton,Qt::NoModifier); + QApplication::sendEvent(canvas->viewport(), &mv); + } + QTest::mouseRelease(canvas->viewport(), Qt::LeftButton, 0, canvas->mapFromScene(QPoint(20,-200))); + // view should settle back at 0 + QTRY_COMPARE(listview->contentY(), 0.0); + delete canvas; } @@ -2445,7 +2467,7 @@ QList<T*> tst_QDeclarativeListView::findItems(QGraphicsObject *parent, const QSt //qDebug() << parent->childItems().count() << "children"; for (int i = 0; i < parent->childItems().count(); ++i) { QDeclarativeItem *item = qobject_cast<QDeclarativeItem*>(parent->childItems().at(i)); - if(!item) + if(!item || !item->isVisible()) continue; //qDebug() << "try" << item; if (mo.cast(item) && (objectName.isEmpty() || item->objectName() == objectName)) |