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 | |
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')
-rw-r--r-- | src/quick/items/qquickitem.cpp | 27 | ||||
-rw-r--r-- | src/quick/items/qquickitem.h | 2 | ||||
-rw-r--r-- | src/quick/items/qquickitem_p.h | 1 | ||||
-rw-r--r-- | src/quick/items/qquickmultipointtoucharea.cpp | 1 | ||||
-rw-r--r-- | src/quick/items/qquickpincharea.cpp | 1 | ||||
-rw-r--r-- | src/quick/items/qquickwindow.cpp | 32 | ||||
-rw-r--r-- | src/quick/items/qquickwindow_p.h | 2 |
7 files changed, 54 insertions, 12 deletions
diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp index bfc4a59851..ef22af965a 100644 --- a/src/quick/items/qquickitem.cpp +++ b/src/quick/items/qquickitem.cpp @@ -3172,6 +3172,7 @@ QQuickItemPrivate::QQuickItemPrivate() , antialiasingValid(false) , isTabFence(false) , replayingPressEvent(false) + , touchEnabled(false) , dirtyAttributes(0) , nextDirtyItem(0) , prevDirtyItem(0) @@ -7190,6 +7191,32 @@ void QQuickItem::setAcceptHoverEvents(bool enabled) d->setHasHoverInChild(enabled); } +/*! + Returns whether touch events are accepted by this item. + + The default value is false. + + If this is false, then the item will not receive any touch events through + the touchEvent() function. +*/ +bool QQuickItem::acceptTouchEvents() const +{ + Q_D(const QQuickItem); + return d->touchEnabled; +} + +/*! + If \a enabled is true, this sets the item to accept touch events; + otherwise, touch events are not accepted by this item. + + \sa acceptTouchEvents() +*/ +void QQuickItem::setAcceptTouchEvents(bool accept) +{ + Q_D(QQuickItem); + d->touchEnabled = accept; +} + void QQuickItemPrivate::setHasCursorInChild(bool hasCursor) { #if QT_CONFIG(cursor) diff --git a/src/quick/items/qquickitem.h b/src/quick/items/qquickitem.h index 1d174ca979..b7a25581a7 100644 --- a/src/quick/items/qquickitem.h +++ b/src/quick/items/qquickitem.h @@ -292,6 +292,8 @@ public: void setAcceptedMouseButtons(Qt::MouseButtons buttons); bool acceptHoverEvents() const; void setAcceptHoverEvents(bool enabled); + bool acceptTouchEvents() const; + void setAcceptTouchEvents(bool accept); #if QT_CONFIG(cursor) QCursor cursor() const; diff --git a/src/quick/items/qquickitem_p.h b/src/quick/items/qquickitem_p.h index 263cb19d20..6b010fc24d 100644 --- a/src/quick/items/qquickitem_p.h +++ b/src/quick/items/qquickitem_p.h @@ -442,6 +442,7 @@ public: // focus chain and prevents tabbing outside. bool isTabFence:1; bool replayingPressEvent:1; + bool touchEnabled:1; enum DirtyType { TransformOrigin = 0x00000001, diff --git a/src/quick/items/qquickmultipointtoucharea.cpp b/src/quick/items/qquickmultipointtoucharea.cpp index 62119effb2..9b2b4daa58 100644 --- a/src/quick/items/qquickmultipointtoucharea.cpp +++ b/src/quick/items/qquickmultipointtoucharea.cpp @@ -420,6 +420,7 @@ QQuickMultiPointTouchArea::QQuickMultiPointTouchArea(QQuickItem *parent) if (qmlVisualTouchDebugging()) { setFlag(QQuickItem::ItemHasContents); } + setAcceptTouchEvents(true); #ifdef Q_OS_OSX setAcceptHoverEvents(true); // needed to enable touch events on mouse hover. #endif diff --git a/src/quick/items/qquickpincharea.cpp b/src/quick/items/qquickpincharea.cpp index 6295aa1932..171b98cd31 100644 --- a/src/quick/items/qquickpincharea.cpp +++ b/src/quick/items/qquickpincharea.cpp @@ -288,6 +288,7 @@ QQuickPinchArea::QQuickPinchArea(QQuickItem *parent) { Q_D(QQuickPinchArea); d->init(); + setAcceptTouchEvents(true); #ifdef Q_OS_OSX setAcceptHoverEvents(true); // needed to enable touch events on mouse hover. #endif 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 diff --git a/src/quick/items/qquickwindow_p.h b/src/quick/items/qquickwindow_p.h index b8131a056f..f66809cc8a 100644 --- a/src/quick/items/qquickwindow_p.h +++ b/src/quick/items/qquickwindow_p.h @@ -172,7 +172,7 @@ public: void deliverUpdatedTouchPoints(QQuickPointerTouchEvent *event); void deliverMatchingPointsToItem(QQuickItem *item, QQuickPointerEvent *pointerEvent); - QVector<QQuickItem *> pointerTargets(QQuickItem *, const QPointF &, bool checkMouseButtons) const; + QVector<QQuickItem *> pointerTargets(QQuickItem *, const QPointF &, bool checkMouseButtons, bool checkAcceptsTouch) const; QVector<QQuickItem *> mergePointerTargets(const QVector<QQuickItem *> &list1, const QVector<QQuickItem *> &list2) const; void updateFilteringParentItems(const QVector<QQuickItem *> &targetItems); |