aboutsummaryrefslogtreecommitdiffstats
path: root/src/quick/items/qquickwindow.cpp
diff options
context:
space:
mode:
authorShawn Rutledge <shawn.rutledge@qt.io>2017-04-05 11:21:29 +0200
committerShawn Rutledge <shawn.rutledge@qt.io>2017-04-14 08:47:53 +0000
commit1457df74f4c1d770e1e820de8cd082be1bd2489e (patch)
tree9a6a637ee9304607e0cab1163db9c4c9479f0352 /src/quick/items/qquickwindow.cpp
parent70513c7496dabf504132dd5c900cd85b367bd1b7 (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.cpp32
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