aboutsummaryrefslogtreecommitdiffstats
path: root/src/quick/handlers
diff options
context:
space:
mode:
authorShawn Rutledge <shawn.rutledge@qt.io>2017-04-03 11:37:03 +0200
committerShawn Rutledge <shawn.rutledge@qt.io>2017-05-22 19:12:12 +0000
commit48011c2dfeb83b4fe717034d4b3c353714fead48 (patch)
tree836196ff3c97c7085b5c9e7a4be052ad02759b33 /src/quick/handlers
parenta09b2f6fcd087e849f4e766a03c1ab47ae49d0d7 (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.cpp36
-rw-r--r--src/quick/handlers/qquickmultipointerhandler_p.h2
-rw-r--r--src/quick/handlers/qquickpinchhandler.cpp6
-rw-r--r--src/quick/handlers/qquickpointerhandler.cpp1
-rw-r--r--src/quick/handlers/qquicktaphandler.cpp7
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)