diff options
author | Shawn Rutledge <shawn.rutledge@digia.com> | 2016-02-01 16:10:35 +0100 |
---|---|---|
committer | Shawn Rutledge <shawn.rutledge@theqtcompany.com> | 2016-02-02 14:57:25 +0000 |
commit | 1929fee8e17e9ca66e7fe08faa9ed9fa7fdbb127 (patch) | |
tree | fdb68eb626a71bd0ab07a5f2a02b76b3cf34c3e0 | |
parent | 666bc731a0ba930ca0cfda18daf836913fd91361 (diff) |
Flickable: ensure movementEnded after wheel/trackpad flick
In qtdeclarative/tests/manual/touch/flicktext.qml it was already clear
that the moving/movingVertically/Horizontally properties did not revert
to false after a trackpad flick on OS X. It turns out that the failure
to emit the movementEnded signal also caused a scrolling bug in ListView.
QQuickFlickable::wheelEvent() looks at event->phase(), but ScrollEnd is not
absolute: on OS X with a bluetooth trackpad, it happens once when the user's
fingers are lifted, then the "momentum" events occur with ScrollUpdate, and
then ScrollEnd happens again at the end of the momentum phase. But if the
user's fingers come to rest before being lifted, to stop the momentum, then
the ScrollEnd phase happens only once, and that's actually the end of
scrolling, flicking and movement, all at once. The events don't seem to
provide enough information to disambiguate these two cases; but if ScrollEnd
phase occurs, and then we don't receive any more events within some short
time interval, we can be pretty sure the scrolling really ended. So, use
a timer to check whether any more events have been received, a little later
after the ScrollEnd phase.
The movementEnded signal can now be emitted for several reasons: the
regular timeline ended movement, the velocityTimeline ended movement,
or the movementEndingTimer sent an event.
Also, when flicking with a physical mouse wheel, flickStarted was emitted
multiple times; now it will be emitted only once.
Task-number: QTBUG-47151
Change-Id: I534e99befbd9bf6af24c4ebdca73dd21964f1063
Reviewed-by: Robin Burchell <robin.burchell@viroteck.net>
-rw-r--r-- | src/quick/items/qquickflickable.cpp | 36 | ||||
-rw-r--r-- | src/quick/items/qquickflickable_p.h | 1 | ||||
-rw-r--r-- | src/quick/items/qquickflickable_p_p.h | 1 |
3 files changed, 36 insertions, 2 deletions
diff --git a/src/quick/items/qquickflickable.cpp b/src/quick/items/qquickflickable.cpp index 43405db40d..b568db1d26 100644 --- a/src/quick/items/qquickflickable.cpp +++ b/src/quick/items/qquickflickable.cpp @@ -59,6 +59,8 @@ static const int FlickThreshold = 15; // will ensure the Flickable retains the grab on consecutive flicks. static const int RetainGrabVelocity = 100; +static const int MovementEndingTimerInterval = 100; + static qreal EaseOvershoot(qreal t) { return qAtan(t); } @@ -238,6 +240,8 @@ void QQuickFlickablePrivate::init() contentItem->setParentItem(q); qmlobject_connect(&timeline, QQuickTimeLine, SIGNAL(completed()), q, QQuickFlickable, SLOT(timelineCompleted())) + qmlobject_connect(&velocityTimeline, QQuickTimeLine, SIGNAL(completed()), + q, QQuickFlickable, SLOT(velocityTimelineCompleted())) q->setAcceptedMouseButtons(Qt::LeftButton); q->setFiltersChildMouseEvents(true); QQuickItemPrivate *viewportPrivate = QQuickItemPrivate::get(contentItem); @@ -1196,6 +1200,8 @@ void QQuickFlickablePrivate::drag(qint64 currentTimestamp, QEvent::Type eventTyp hData.velocity = 0; } + if (momentum && !hData.flicking && !vData.flicking) + flickingStarted(hData.velocity != 0, vData.velocity != 0); draggingStarting(); if ((hMoved && !prevHMoved) || (vMoved && !prevVMoved)) @@ -1385,9 +1391,15 @@ void QQuickFlickable::wheelEvent(QWheelEvent *event) d->maybeBeginDrag(currentTimestamp, event->posF()); break; case Qt::ScrollUpdate: + if (d->scrollingPhase) { + d->pressed = true; + d->movementEndingTimer.start(MovementEndingTimerInterval, this); + } break; case Qt::ScrollEnd: + d->pressed = false; d->scrollingPhase = false; + d->movementEndingTimer.start(MovementEndingTimerInterval, this); d->draggingEnding(); event->accept(); returnToBounds(); @@ -1409,7 +1421,6 @@ void QQuickFlickable::wheelEvent(QWheelEvent *event) valid = true; } if (valid) { - d->vData.flicking = false; d->flickY(d->vData.velocity); d->flickingStarted(false, true); if (d->vData.flicking) { @@ -1429,7 +1440,6 @@ void QQuickFlickable::wheelEvent(QWheelEvent *event) valid = true; } if (valid) { - d->hData.flicking = false; d->flickX(d->hData.velocity); d->flickingStarted(true, false); if (d->hData.flicking) { @@ -1542,6 +1552,12 @@ void QQuickFlickable::timerEvent(QTimerEvent *event) if (d->delayedPressEvent) { d->replayDelayedPress(); } + } else if (event->timerId() == d->movementEndingTimer.timerId()) { + d->movementEndingTimer.stop(); + d->pressed = false; + d->stealMouse = false; + if (!d->velocityTimeline.isActive()) + movementEnding(true, true); } } @@ -2469,6 +2485,22 @@ bool QQuickFlickable::isMovingVertically() const return d->vData.moving; } +void QQuickFlickable::velocityTimelineCompleted() +{ + Q_D(QQuickFlickable); + if ( (d->hData.transitionToBounds && d->hData.transitionToBounds->isActive()) + || (d->vData.transitionToBounds && d->vData.transitionToBounds->isActive()) ) { + return; + } + // With subclasses such as GridView, velocityTimeline.completed is emitted repeatedly: + // for example setting currentIndex results in a visual "flick" which the user + // didn't initiate directly. We don't want to end movement repeatedly, and in + // that case movementEnding will happen after the sequence of movements ends. + if (d->vData.flicking) + movementEnding(); + d->updateBeginningEnd(); +} + void QQuickFlickable::timelineCompleted() { Q_D(QQuickFlickable); diff --git a/src/quick/items/qquickflickable_p.h b/src/quick/items/qquickflickable_p.h index ac072f0e50..f1299ee4f2 100644 --- a/src/quick/items/qquickflickable_p.h +++ b/src/quick/items/qquickflickable_p.h @@ -253,6 +253,7 @@ protected Q_SLOTS: void movementStarting(); void movementEnding(); void movementEnding(bool hMovementEnding, bool vMovementEnding); + void velocityTimelineCompleted(); void timelineCompleted(); protected: diff --git a/src/quick/items/qquickflickable_p_p.h b/src/quick/items/qquickflickable_p_p.h index 9d75533c8a..ea46720cb6 100644 --- a/src/quick/items/qquickflickable_p_p.h +++ b/src/quick/items/qquickflickable_p_p.h @@ -212,6 +212,7 @@ public: bool calcVelocity : 1; bool pixelAligned : 1; QElapsedTimer timer; + QBasicTimer movementEndingTimer; qint64 lastPosTime; qint64 lastPressTime; QPointF lastPos; |