diff options
author | Shawn Rutledge <shawn.rutledge@qt.io> | 2017-04-05 11:21:29 +0200 |
---|---|---|
committer | Shawn Rutledge <shawn.rutledge@qt.io> | 2017-04-14 08:47:53 +0000 |
commit | 1457df74f4c1d770e1e820de8cd082be1bd2489e (patch) | |
tree | 9a6a637ee9304607e0cab1163db9c4c9479f0352 /src/quick/items/qquickwindow.cpp | |
parent | 70513c7496dabf504132dd5c900cd85b367bd1b7 (diff) |
Add QQuickItem acceptTouchEvents/setAcceptTouchEvents; require for touch
It has been suboptimal to speculatively deliver touch events to Items
which are not interested; even worse is when we must deliver to a
parent item which is filtering events, when the child Item will not
accept the touch event anyway.
So now it is required that any QQuickItem subclass which wishes to
accept touch events must call setAcceptTouchEvents(true) (typically
in its constructor). If it does not do this, it will not get any
touch events (and this saves us the trouble of looking for parents
which filter touch events, too). It is consistent with needing to
call setAcceptHoverEvents() to get hover events, and
setAcceptedMouseButtons() to get mouse events.
[ChangeLog][QtQuick][QQuickItem] When subclassing QQuickItem, it is
now required to call setAcceptTouchEvents(true) if you need the item
to receive touch events.
Change-Id: Idc76c04f4e7f1d4a613087e756e96dac368f4f23
Reviewed-by: Shawn Rutledge <shawn.rutledge@qt.io>
Diffstat (limited to 'src/quick/items/qquickwindow.cpp')
-rw-r--r-- | src/quick/items/qquickwindow.cpp | 32 |
1 files changed, 21 insertions, 11 deletions
diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp index 888b0cde85..e6f77ea69a 100644 --- a/src/quick/items/qquickwindow.cpp +++ b/src/quick/items/qquickwindow.cpp @@ -1720,7 +1720,7 @@ void QQuickWindowPrivate::deliverMouseEvent(QQuickPointerMouseEvent *pointerEven } // If some points weren't grabbed, deliver to non-grabber PointerHandlers in reverse paint order if (!pointerEvent->allPointsGrabbed() && pointerEvent->buttons()) { - QVector<QQuickItem *> targetItems = pointerTargets(contentItem, point->scenePos(), false); + QVector<QQuickItem *> targetItems = pointerTargets(contentItem, point->scenePos(), false, false); for (QQuickItem *item : targetItems) { QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item); pointerEvent->localize(item); @@ -2206,7 +2206,10 @@ void QQuickWindowPrivate::deliverPointerEvent(QQuickPointerEvent *event) // check if item or any of its child items contain the point // FIXME: should this be iterative instead of recursive? -QVector<QQuickItem *> QQuickWindowPrivate::pointerTargets(QQuickItem *item, const QPointF &scenePos, bool checkMouseButtons) const +// If checkMouseButtons is true, it means we are finding targets for a mouse event, so no item for which acceptedMouseButtons() is NoButton will be added. +// If checkAcceptsTouch is true, it means we are finding targets for a touch event, so either acceptTouchEvents() must return true OR +// it must accept a synth. mouse event, thus if acceptTouchEvents() returns false but acceptedMouseButtons() is true, gets added; if not, it doesn't. +QVector<QQuickItem *> QQuickWindowPrivate::pointerTargets(QQuickItem *item, const QPointF &scenePos, bool checkMouseButtons, bool checkAcceptsTouch) const { QVector<QQuickItem *> targets; auto itemPrivate = QQuickItemPrivate::get(item); @@ -2224,13 +2227,16 @@ QVector<QQuickItem *> QQuickWindowPrivate::pointerTargets(QQuickItem *item, cons auto childPrivate = QQuickItemPrivate::get(child); if (!child->isVisible() || !child->isEnabled() || childPrivate->culled) continue; - targets << pointerTargets(child, scenePos, false); + targets << pointerTargets(child, scenePos, checkMouseButtons, checkAcceptsTouch); } - if (item->contains(itemPos) && (!checkMouseButtons || itemPrivate->acceptedMouseButtons())) { - // add this item last - children take precedence - targets << item; - } + bool relevant = item->contains(itemPos); + if (relevant && checkMouseButtons && item->acceptedMouseButtons() == Qt::NoButton) + relevant = false; + if (relevant && checkAcceptsTouch && !(item->acceptTouchEvents() || item->acceptedMouseButtons())) + relevant = false; + if (relevant) + targets << item; // add this item last: children take precedence return targets; } @@ -2337,7 +2343,7 @@ void QQuickWindowPrivate::deliverUpdatedTouchPoints(QQuickPointerTouchEvent *eve QQuickEventPoint *point = event->point(i); if (point->state() == QQuickEventPoint::Pressed) continue; // presses were delivered earlier; not the responsibility of deliverUpdatedTouchPoints - QVector<QQuickItem *> targetItemsForPoint = pointerTargets(contentItem, point->scenePos(), false); + QVector<QQuickItem *> targetItemsForPoint = pointerTargets(contentItem, point->scenePos(), false, false); if (targetItems.count()) { targetItems = mergePointerTargets(targetItems, targetItemsForPoint); } else { @@ -2363,8 +2369,9 @@ bool QQuickWindowPrivate::deliverPressEvent(QQuickPointerEvent *event) { const QVector<QPointF> points = event->unacceptedPressedPointScenePositions(); QVector<QQuickItem *> targetItems; + bool isTouchEvent = (event->asPointerTouchEvent() != nullptr); for (QPointF point: points) { - QVector<QQuickItem *> targetItemsForPoint = pointerTargets(contentItem, point, false); + QVector<QQuickItem *> targetItemsForPoint = pointerTargets(contentItem, point, !isTouchEvent, isTouchEvent); if (targetItems.count()) { targetItems = mergePointerTargets(targetItems, targetItemsForPoint); } else { @@ -2661,8 +2668,9 @@ void QQuickWindowPrivate::updateFilteringParentItems(const QVector<QQuickItem *> for (QQuickItem *item : targetItems) { QQuickItemPrivate *itemPriv = QQuickItemPrivate::get(item); // If the item neither handles events nor has handlers which do, then it will never be a receiver, so filtering is irrelevant - if (!item->acceptedMouseButtons() && !(itemPriv->extra.isAllocated() && !itemPriv->extra->pointerHandlers.isEmpty())) - continue; // TODO there's no acceptTouchEvents, so it's hard to avoid skipping any items which handle only touch + if (!item->acceptedMouseButtons() && !item->acceptTouchEvents() && + !(itemPriv->extra.isAllocated() && !itemPriv->extra->pointerHandlers.isEmpty())) + continue; QQuickItem *parent = item->parentItem(); while (parent) { if (parent->filtersChildMouseEvents()) { @@ -2700,6 +2708,8 @@ bool QQuickWindowPrivate::sendFilteredPointerEvent(QQuickPointerEvent *event, QQ QVarLengthArray<QPair<QQuickPointerHandler *, QQuickEventPoint *>, 32> passiveGrabsToCancel; for (QPair<QQuickItem *,QQuickItem *> itemAndParent : filteringParentItems) { QQuickItem *item = receiver ? receiver : itemAndParent.first; + if (!item->acceptTouchEvents() && !item->acceptedMouseButtons()) + continue; // if this item won't accept, parents don't need to filter the touch for it QQuickItem *filteringParent = itemAndParent.second; if (item == filteringParent) continue; // a filtering item never needs to filter for itself |