aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorShawn Rutledge <shawn.rutledge@digia.com>2016-02-01 16:10:35 +0100
committerShawn Rutledge <shawn.rutledge@theqtcompany.com>2016-02-02 14:57:25 +0000
commit1929fee8e17e9ca66e7fe08faa9ed9fa7fdbb127 (patch)
treefdb68eb626a71bd0ab07a5f2a02b76b3cf34c3e0
parent666bc731a0ba930ca0cfda18daf836913fd91361 (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.cpp36
-rw-r--r--src/quick/items/qquickflickable_p.h1
-rw-r--r--src/quick/items/qquickflickable_p_p.h1
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;