From ba201c73edb4ff452bfb13fa5afd6af6a02c4af0 Mon Sep 17 00:00:00 2001 From: Frederik Gladhorn Date: Tue, 26 Jul 2016 20:56:56 +0200 Subject: Touch handling: remove acceptedNewPoints We keep track of the state inside the individual points, simplify the code. Change-Id: I6716f3ad9bc21ab066888a3b373719c5e4f30af2 Reviewed-by: Frederik Gladhorn --- src/quick/items/qquickevents.cpp | 30 ++++++++++++++++------- src/quick/items/qquickevents_p_p.h | 2 +- src/quick/items/qquickwindow.cpp | 49 +++++++++----------------------------- src/quick/items/qquickwindow_p.h | 2 +- 4 files changed, 35 insertions(+), 48 deletions(-) diff --git a/src/quick/items/qquickevents.cpp b/src/quick/items/qquickevents.cpp index 4a531b09ba..393d8345ec 100644 --- a/src/quick/items/qquickevents.cpp +++ b/src/quick/items/qquickevents.cpp @@ -764,29 +764,43 @@ const QTouchEvent::TouchPoint *QQuickPointerTouchEvent::touchPointById(int point /*! \internal Make a new QTouchEvent, giving it a subset of the original touch points. + + Returns a nullptr if all points are stationary or there are no points inside the item. */ -QTouchEvent *QQuickPointerTouchEvent::touchEventForItem(const QList &newPoints, QQuickItem *relativeTo) const +QTouchEvent *QQuickPointerTouchEvent::touchEventForItem(QQuickItem *item) const { QList touchPoints; Qt::TouchPointStates eventStates; // TODO maybe add QQuickItem::mapVector2DFromScene(QVector2D) to avoid needing QQuickItemPrivate here // Or else just document that velocity is always scene-relative and is not scaled and rotated with the item // but that would require changing tst_qquickwindow::touchEvent_velocity(): it expects transformed velocity - QMatrix4x4 transformMatrix(QQuickItemPrivate::get(relativeTo)->windowToItemTransform()); - for (const QQuickEventPoint * p : newPoints) { + + QMatrix4x4 transformMatrix(QQuickItemPrivate::get(item)->windowToItemTransform()); + for (int i = 0; i < m_pointCount; ++i) { + auto p = m_touchPoints.at(i); + if (p->isAccepted()) + continue; + bool isGrabber = p->grabber() == item; + bool isPressInside = p->state() == Qt::TouchPointPressed && item->contains(item->mapFromScene(p->scenePos())); + if (!(isGrabber || isPressInside)) + continue; + const QTouchEvent::TouchPoint *tp = touchPointById(p->pointId()); if (tp) { eventStates |= tp->state(); QTouchEvent::TouchPoint tpCopy = *tp; - tpCopy.setPos(relativeTo->mapFromScene(tpCopy.scenePos())); - tpCopy.setLastPos(relativeTo->mapFromScene(tpCopy.lastScenePos())); - tpCopy.setStartPos(relativeTo->mapFromScene(tpCopy.startScenePos())); - tpCopy.setRect(relativeTo->mapRectFromScene(tpCopy.sceneRect())); + tpCopy.setPos(item->mapFromScene(tpCopy.scenePos())); + tpCopy.setLastPos(item->mapFromScene(tpCopy.lastScenePos())); + tpCopy.setStartPos(item->mapFromScene(tpCopy.startScenePos())); + tpCopy.setRect(item->mapRectFromScene(tpCopy.sceneRect())); tpCopy.setVelocity(transformMatrix.mapVector(tpCopy.velocity()).toVector2D()); touchPoints << tpCopy; } } + if (eventStates == Qt::TouchPointStationary || touchPoints.isEmpty()) + return nullptr; + // if all points have the same state, set the event type accordingly const QTouchEvent &event = *asTouchEvent(); QEvent::Type eventType = event.type(); @@ -804,7 +818,7 @@ QTouchEvent *QQuickPointerTouchEvent::touchEventForItem(const QListsetWindow(event.window()); - touchEvent->setTarget(relativeTo); + touchEvent->setTarget(item); touchEvent->setDevice(event.device()); touchEvent->setModifiers(event.modifiers()); touchEvent->setTouchPoints(touchPoints); diff --git a/src/quick/items/qquickevents_p_p.h b/src/quick/items/qquickevents_p_p.h index 82f58efb7a..2375ae797b 100644 --- a/src/quick/items/qquickevents_p_p.h +++ b/src/quick/items/qquickevents_p_p.h @@ -423,7 +423,7 @@ public: void clearGrabbers() const override; QMouseEvent *syntheticMouseEvent(int pointID, QQuickItem *relativeTo) const; - QTouchEvent *touchEventForItem(const QList &newPoints, QQuickItem *relativeTo) const; + QTouchEvent *touchEventForItem(QQuickItem *item) const; QTouchEvent *asTouchEvent() const; diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp index baf0e196dd..805011ca41 100644 --- a/src/quick/items/qquickwindow.cpp +++ b/src/quick/items/qquickwindow.cpp @@ -2285,44 +2285,22 @@ bool QQuickWindowPrivate::deliverPoints(QQuickItem *item, QQuickPointerTouchEven // set of IDs of "interesting" new points QSet matchingNewPoints; - // set of points which this item has previously accepted, for starters - QList matchingPoints = (*updatedPoints)[item]; // now add the new points which are inside this item's bounds if (newPoints.count() > 0 && acceptedNewPoints->count() < newPoints.count()) { for (int i = 0; i < newPoints.count(); i++) { const QQuickEventPoint * point = newPoints[i]; - if (acceptedNewPoints->contains(point->pointId())) + if (acceptedNewPoints->contains(point->pointId())) { + Q_ASSERT(point->isAccepted()); continue; + } QPointF p = item->mapFromScene(point->scenePos()); - if (item->contains(p)) { + if (item->contains(p)) matchingNewPoints.insert(point->pointId()); - matchingPoints << point; - } - } - } - // If there are no matching new points, and the existing points are all stationary, - // there's no need to send an event to this item. This is required by a test in - // tst_qquickwindow::touchEvent_basic: - // a single stationary press on an item shouldn't cause an event - if (matchingNewPoints.isEmpty()) { - bool stationaryOnly = true; - - for (const QQuickEventPoint *tp : matchingPoints) { - if (tp->state() != Qt::TouchPointStationary) { - stationaryOnly = false; - break; - } } - - if (stationaryOnly) - matchingPoints.clear(); } - if (!matchingPoints.isEmpty()) { - // Now we know this item might be interested in the event. Copy and send it, but - // with only the subset of TouchPoints which are relevant to that item: that's matchingPoints. - deliverMatchingPointsToItem(item, event, acceptedNewPoints, matchingNewPoints, matchingPoints, hasFiltered); - } + // This item might be interested in the event. + deliverMatchingPointsToItem(item, event, acceptedNewPoints, matchingNewPoints, hasFiltered); // record the fact that this item has been visited already updatedPoints->remove(item); @@ -2336,15 +2314,15 @@ bool QQuickWindowPrivate::deliverPoints(QQuickItem *item, QQuickPointerTouchEven // matchingPoints to already be that set of interesting points. // They are all pre-transformed, too. bool QQuickWindowPrivate::deliverMatchingPointsToItem(QQuickItem *item, const QQuickPointerTouchEvent *event, QSet *acceptedNewPoints, - const QSet &matchingNewPoints, const QList &matchingPoints, + const QSet &matchingNewPoints, QSet *hasFiltered) { - QScopedPointer touchEvent(event->touchEventForItem(matchingPoints, item)); - if (touchEvent.data()->touchPoints().isEmpty()) + QScopedPointer touchEvent(event->touchEventForItem(item)); + if (!touchEvent) return false; - bool touchEventAccepted = false; qCDebug(DBG_TOUCH) << " - considering delivering " << touchEvent.data() << " to " << item; + bool touchEventAccepted = false; // First check whether the parent wants to be a filter, // and if the parent accepts the event we are done. @@ -2359,12 +2337,6 @@ bool QQuickWindowPrivate::deliverMatchingPointsToItem(QQuickItem *item, const QQ return true; } - // Since it can change in sendEvent, update itemForTouchPointId now - foreach (int id, matchingNewPoints) { - qCDebug(DBG_TOUCH_TARGET) << "TP" << id << "->" << item; - event->pointById(id)->setGrabber(item); - } - // Deliver the touch event to the given item qCDebug(DBG_TOUCH) << " - actually delivering " << touchEvent.data() << " to " << item; QCoreApplication::sendEvent(item, touchEvent.data()); @@ -2383,6 +2355,7 @@ bool QQuickWindowPrivate::deliverMatchingPointsToItem(QQuickItem *item, const QQ // update acceptedNewPoints. foreach (int id, matchingNewPoints) { event->pointById(id)->setAccepted(); + event->pointById(id)->setGrabber(item); acceptedNewPoints->insert(id); } } else { diff --git a/src/quick/items/qquickwindow_p.h b/src/quick/items/qquickwindow_p.h index 3f4fc50e31..36414f5b6f 100644 --- a/src/quick/items/qquickwindow_p.h +++ b/src/quick/items/qquickwindow_p.h @@ -168,7 +168,7 @@ public: bool deliverTouchCancelEvent(QTouchEvent *); bool deliverPoints(QQuickItem *, QQuickPointerTouchEvent *, const QList &, QSet *, QHash > *, QSet *); - bool deliverMatchingPointsToItem(QQuickItem *item, const QQuickPointerTouchEvent *event, QSet *acceptedNewPoints, const QSet &matchingNewPoints, const QList &matchingPoints, QSet *filtered); + bool deliverMatchingPointsToItem(QQuickItem *item, const QQuickPointerTouchEvent *event, QSet *acceptedNewPoints, const QSet &matchingNewPoints, QSet *filtered); static QTouchEvent *touchEventForItem(QQuickItem *target, const QTouchEvent &originalEvent, bool alwaysCheckBounds = false); static QTouchEvent *touchEventWithPoints(const QTouchEvent &event, const QList &newPoints); bool sendFilteredTouchEvent(QQuickItem *target, QQuickItem *item, QTouchEvent *event, QSet *filtered); -- cgit v1.2.3