diff options
author | Shawn Rutledge <shawn.rutledge@qt.io> | 2017-04-03 11:37:03 +0200 |
---|---|---|
committer | Shawn Rutledge <shawn.rutledge@qt.io> | 2017-05-22 19:12:12 +0000 |
commit | 48011c2dfeb83b4fe717034d4b3c353714fead48 (patch) | |
tree | 836196ff3c97c7085b5c9e7a4be052ad02759b33 /src/quick/handlers | |
parent | a09b2f6fcd087e849f4e766a03c1ab47ae49d0d7 (diff) |
Start over with event delivery when touchpoint releases occur
The new rule is that when the number of touchpoints changes, we start
over with event delivery as if the touch had just begun, to give more
opportunities to hand off processing from one item or handler to
another. And MultiPointTouchArea can now handle the handoff:
for example in tests/manual/pointer/pinchDragFlingMPTA.qml when the
user is pressing three fingers, the PinchHandler is active; when the
user then lifts one finger, the MPTA can resume handling the two
remaining touchpoints as if they were just pressed.
The change in QQuickMultiPointerHandler::wantsPointerEvent is both
a behavior change and an optimization: released points aren't eligible;
but if some points are released, then pressed, updated and stationary
points are all eligible. And, figure this out without looping over the
points twice.
Change-Id: I26b7593de8e72b471adfec4a4482dd87a8288442
Reviewed-by: Jan Arve Sæther <jan-arve.saether@qt.io>
Diffstat (limited to 'src/quick/handlers')
-rw-r--r-- | src/quick/handlers/qquickmultipointerhandler.cpp | 36 | ||||
-rw-r--r-- | src/quick/handlers/qquickmultipointerhandler_p.h | 2 | ||||
-rw-r--r-- | src/quick/handlers/qquickpinchhandler.cpp | 6 | ||||
-rw-r--r-- | src/quick/handlers/qquickpointerhandler.cpp | 1 | ||||
-rw-r--r-- | src/quick/handlers/qquicktaphandler.cpp | 7 |
5 files changed, 24 insertions, 28 deletions
diff --git a/src/quick/handlers/qquickmultipointerhandler.cpp b/src/quick/handlers/qquickmultipointerhandler.cpp index 016210beff..a605b3f12e 100644 --- a/src/quick/handlers/qquickmultipointerhandler.cpp +++ b/src/quick/handlers/qquickmultipointerhandler.cpp @@ -66,44 +66,34 @@ bool QQuickMultiPointerHandler::wantsPointerEvent(QQuickPointerEvent *event) if (!QQuickPointerDeviceHandler::wantsPointerEvent(event)) return false; - const int pCount = event->pointCount(); - int pointCandidateCount = 0; - - // If one or more points are newly pressed, all points are candidates for this handler. - // In other cases however, do not steal the grab: that is, if a point has a grabber, - // it's not a candidate for this handler. - if (event->isPressEvent()) { - pointCandidateCount = pCount; - } else { - for (int i = 0; i < pCount; ++i) { - QQuickEventPoint *pt = event->point(i); - QObject *exclusiveGrabber = pt->exclusiveGrabber(); - if (!exclusiveGrabber || exclusiveGrabber == this) - ++pointCandidateCount; - } - } - - if (pointCandidateCount < m_requiredPointCount) - return false; if (sameAsCurrentPoints(event)) return true; - const QVector<QQuickEventPoint *> candidatePoints = pointsInsideOrNearTarget(event); + const QVector<QQuickEventPoint *> candidatePoints = eligiblePoints(event); const bool ret = (candidatePoints.size() == m_requiredPointCount); if (ret) m_currentPoints = candidatePoints; return ret; } -QVector<QQuickEventPoint *> QQuickMultiPointerHandler::pointsInsideOrNearTarget(QQuickPointerEvent *event) +QVector<QQuickEventPoint *> QQuickMultiPointerHandler::eligiblePoints(QQuickPointerEvent *event) { QVector<QQuickEventPoint *> ret; int c = event->pointCount(); QRectF targetBounds = target()->mapRectToScene(target()->boundingRect()) .marginsAdded(QMarginsF(m_pointDistanceThreshold, m_pointDistanceThreshold, m_pointDistanceThreshold, m_pointDistanceThreshold)); + // If one or more points are newly pressed or released, all non-released points are candidates for this handler. + // In other cases however, do not steal the grab: that is, if a point has a grabber, + // it's not a candidate for this handler. + bool stealingAllowed = event->isPressEvent() || event->isReleaseEvent(); for (int i = 0; i < c; ++i) { QQuickEventPoint *p = event->point(i); - if (targetBounds.contains(p->scenePos())) + if (!stealingAllowed) { + QObject *exclusiveGrabber = p->exclusiveGrabber(); + if (exclusiveGrabber && exclusiveGrabber != this) + continue; + } + if (p->state() != QQuickEventPoint::Released && targetBounds.contains(p->scenePos())) ret << p; } return ret; @@ -136,6 +126,8 @@ bool QQuickMultiPointerHandler::sameAsCurrentPoints(QQuickPointerEvent *event) // TODO optimize: either ensure the points are sorted, // or use std::equal with a predicate for (int i = 0; ret && i < c; ++i) { + if (event->point(i)->state() == QQuickEventPoint::Released) + return false; bool found = false; int pointId = event->point(i)->pointId(); for (QQuickEventPoint *o : qAsConst(m_currentPoints)) diff --git a/src/quick/handlers/qquickmultipointerhandler_p.h b/src/quick/handlers/qquickmultipointerhandler_p.h index ce014d658c..1f2d213e56 100644 --- a/src/quick/handlers/qquickmultipointerhandler_p.h +++ b/src/quick/handlers/qquickmultipointerhandler_p.h @@ -88,7 +88,7 @@ protected: bool wantsPointerEvent(QQuickPointerEvent *event) override; bool sameAsCurrentPoints(QQuickPointerEvent *event); - QVector<QQuickEventPoint *> pointsInsideOrNearTarget(QQuickPointerEvent *event); + QVector<QQuickEventPoint *> eligiblePoints(QQuickPointerEvent *event); QPointF touchPointCentroid(); QVector2D touchPointCentroidVelocity(); qreal averageTouchPointDistance(const QPointF &ref); diff --git a/src/quick/handlers/qquickpinchhandler.cpp b/src/quick/handlers/qquickpinchhandler.cpp index 3af77593e2..465a49a6fd 100644 --- a/src/quick/handlers/qquickpinchhandler.cpp +++ b/src/quick/handlers/qquickpinchhandler.cpp @@ -228,7 +228,8 @@ void QQuickPinchHandler::handlePointerEventImpl(QQuickPointerEvent *event) qCDebug(lcPinchHandler) << point->state() << point->sceneGrabPos() << "->" << point->scenePos(); } - if (!active()) { + bool containsReleasedPoints = event->isReleaseEvent(); + if (!active() && !containsReleasedPoints) { // Verify that least one of the points have moved beyond threshold needed to activate the handler for (QQuickEventPoint *point : qAsConst(m_currentPoints)) { if (QQuickWindowPrivate::dragOverThreshold(point)) { @@ -302,7 +303,8 @@ void QQuickPinchHandler::handlePointerEventImpl(QQuickPointerEvent *event) << ", rotation" << rotation; } - acceptPoints(m_currentPoints); + if (!containsReleasedPoints) + acceptPoints(m_currentPoints); emit updated(); } diff --git a/src/quick/handlers/qquickpointerhandler.cpp b/src/quick/handlers/qquickpointerhandler.cpp index 3774c2d24c..1ed80c0a5b 100644 --- a/src/quick/handlers/qquickpointerhandler.cpp +++ b/src/quick/handlers/qquickpointerhandler.cpp @@ -216,6 +216,7 @@ void QQuickPointerHandler::handlePointerEvent(QQuickPointerEvent *event) pt->cancelExclusiveGrab(); } } + event->device()->eventDeliveryTargets().append(this); } bool QQuickPointerHandler::wantsPointerEvent(QQuickPointerEvent *event) diff --git a/src/quick/handlers/qquicktaphandler.cpp b/src/quick/handlers/qquicktaphandler.cpp index f79dbb266a..d73e9fd100 100644 --- a/src/quick/handlers/qquicktaphandler.cpp +++ b/src/quick/handlers/qquicktaphandler.cpp @@ -270,7 +270,7 @@ void QQuickTapHandler::setPressed(bool press, bool cancel, QQuickEventPoint *poi else setExclusiveGrab(point, press); } - if (!cancel && !press) { + if (!cancel && !press && parentContains(point)) { if (point->timeHeld() < longPressThreshold()) { // Assuming here that pointerEvent()->timestamp() is in ms. qreal ts = point->pointerEvent()->timestamp() / 1000.0; @@ -301,8 +301,9 @@ void QQuickTapHandler::setPressed(bool press, bool cancel, QQuickEventPoint *poi void QQuickTapHandler::onGrabChanged(QQuickPointerHandler *grabber, QQuickEventPoint::GrabState stateChange, QQuickEventPoint *point) { QQuickPointerSingleHandler::onGrabChanged(grabber, stateChange, point); - if (grabber == this && (stateChange == QQuickEventPoint::CancelGrabExclusive || stateChange == QQuickEventPoint::CancelGrabPassive)) - setPressed(false, true, point); + bool isCanceled = stateChange == QQuickEventPoint::CancelGrabExclusive || stateChange == QQuickEventPoint::CancelGrabPassive; + if (grabber == this && (isCanceled || point->state() == QQuickEventPoint::Released)) + setPressed(false, isCanceled, point); } void QQuickTapHandler::connectPreRenderSignal(bool conn) |