aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/quick/items/qquickwindow.cpp49
-rw-r--r--src/quick/items/qquickwindow_p.h1
-rw-r--r--tests/auto/quick/pointerhandlers/flickableinterop/data/flickableWithHandlers.qml78
-rw-r--r--tests/auto/quick/pointerhandlers/flickableinterop/tst_flickableinterop.cpp77
4 files changed, 188 insertions, 17 deletions
diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp
index 65d69a3bcf..45c14f10a1 100644
--- a/src/quick/items/qquickwindow.cpp
+++ b/src/quick/items/qquickwindow.cpp
@@ -1669,6 +1669,36 @@ QMouseEvent *QQuickWindowPrivate::cloneMouseEvent(QMouseEvent *event, QPointF *t
return me;
}
+void QQuickWindowPrivate::deliverToPassiveGrabbers(const QVector<QPointer <QQuickPointerHandler> > &passiveGrabbers,
+ QQuickPointerEvent *pointerEvent)
+{
+ const QVector<QQuickPointerHandler *> &eventDeliveryTargets = pointerEvent->device()->eventDeliveryTargets();
+ QVarLengthArray<QPair<QQuickItem *, bool>, 4> sendFilteredPointerEventResult;
+ for (auto handler : passiveGrabbers) {
+ // a null pointer in passiveGrabbers is unlikely, unless the grabbing handler was deleted dynamically
+ if (Q_LIKELY(handler) && !eventDeliveryTargets.contains(handler)) {
+ bool alreadyFiltered = false;
+ QQuickItem *par = handler->parentItem();
+
+ // see if we already have sent a filter event to the parent
+ auto it = std::find_if(sendFilteredPointerEventResult.begin(), sendFilteredPointerEventResult.end(),
+ [par](const QPair<QQuickItem *, bool> &pair) { return pair.first == par; });
+ if (it != sendFilteredPointerEventResult.end()) {
+ // Yes, the event was already filtered to that parent, do not call it again but use
+ // the result of the previous call to determine if we should call the handler.
+ alreadyFiltered = it->second;
+ } else {
+ alreadyFiltered = sendFilteredPointerEvent(pointerEvent, par);
+ sendFilteredPointerEventResult << qMakePair<QQuickItem*, bool>(par, alreadyFiltered);
+ }
+ if (!alreadyFiltered)
+ handler->handlePointerEvent(pointerEvent);
+ }
+ }
+}
+
+
+
void QQuickWindowPrivate::deliverMouseEvent(QQuickPointerMouseEvent *pointerEvent)
{
auto point = pointerEvent->point(0);
@@ -1717,14 +1747,8 @@ void QQuickWindowPrivate::deliverMouseEvent(QQuickPointerMouseEvent *pointerEven
// if this is an update or release from an actual mouse,
// and the point wasn't grabbed, deliver only to PointerHandlers:
// passive grabbers first, then the rest
- const QVector<QQuickPointerHandler *> &eventDeliveryTargets = pointerEvent->device()->eventDeliveryTargets();
- for (auto handler : point->passiveGrabbers()) {
- // a null pointer in passiveGrabbers is unlikely, unless the grabbing handler was deleted dynamically
- if (Q_LIKELY(handler) && !eventDeliveryTargets.contains(handler)) {
- if (!sendFilteredPointerEvent(pointerEvent, handler->parentItem()))
- handler->handlePointerEvent(pointerEvent);
- }
- }
+ deliverToPassiveGrabbers(point->passiveGrabbers(), pointerEvent);
+
// 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->scenePosition(), false, false);
@@ -2398,16 +2422,9 @@ void QQuickWindowPrivate::deliverUpdatedTouchPoints(QQuickPointerTouchEvent *eve
int pointCount = event->pointCount();
// Deliver to each eventpoint's passive grabbers (but don't visit any handler more than once)
- const QVector<QQuickPointerHandler *> &eventDeliveryTargets = event->device()->eventDeliveryTargets();
for (int i = 0; i < pointCount; ++i) {
QQuickEventPoint *point = event->point(i);
- for (auto handler : point->passiveGrabbers()) {
- if (Q_LIKELY(handler) && !eventDeliveryTargets.contains(handler)) {
- if (sendFilteredPointerEvent(event, handler->parentItem()))
- return;
- handler->handlePointerEvent(event);
- }
- }
+ deliverToPassiveGrabbers(point->passiveGrabbers(), event);
}
// If some points weren't grabbed, deliver to non-grabber PointerHandlers in reverse paint order
diff --git a/src/quick/items/qquickwindow_p.h b/src/quick/items/qquickwindow_p.h
index ae49d5e304..2d7b81cec8 100644
--- a/src/quick/items/qquickwindow_p.h
+++ b/src/quick/items/qquickwindow_p.h
@@ -146,6 +146,7 @@ public:
void grabTouchPoints(QObject *grabber, const QVector<int> &ids);
void removeGrabber(QQuickItem *grabber, bool mouse = true, bool touch = true);
static QMouseEvent *cloneMouseEvent(QMouseEvent *event, QPointF *transformedLocalPos = 0);
+ void deliverToPassiveGrabbers(const QVector<QPointer <QQuickPointerHandler> > &passiveGrabbers, QQuickPointerEvent *pointerEvent);
void deliverMouseEvent(QQuickPointerMouseEvent *pointerEvent);
bool sendFilteredMouseEvent(QEvent *event, QQuickItem *receiver, QQuickItem *filteringParent);
bool sendFilteredPointerEvent(QQuickPointerEvent *event, QQuickItem *receiver, QQuickItem *filteringParent = nullptr);
diff --git a/tests/auto/quick/pointerhandlers/flickableinterop/data/flickableWithHandlers.qml b/tests/auto/quick/pointerhandlers/flickableinterop/data/flickableWithHandlers.qml
index 833fef0a81..651f290570 100644
--- a/tests/auto/quick/pointerhandlers/flickableinterop/data/flickableWithHandlers.qml
+++ b/tests/auto/quick/pointerhandlers/flickableinterop/data/flickableWithHandlers.qml
@@ -43,7 +43,7 @@ import Qt.labs.handlers 1.0
Rectangle {
id: root
- width: 400
+ width: 500
height: 480
objectName: "root"
color: "#222222"
@@ -81,6 +81,82 @@ Rectangle {
gesturePolicy: TapHandler.ReleaseWithinBounds // the default
}
}
+ Column {
+ spacing: 6
+ Rectangle {
+ width: 50
+ height: 50
+ color: "aqua"
+ border.color: drag1.active ? "darkgreen" : "transparent"
+ border.width: 3
+ objectName: "drag"
+ DragHandler {
+ id: drag1
+ }
+ Text {
+ anchors.centerIn: parent
+ enabled: false
+ text: "drag"
+ }
+ }
+ Rectangle {
+ width: 50
+ height: 50
+ color: "aqua"
+ objectName: "tap"
+ border.color: tap1.isPressed ? "red" : "transparent"
+ border.width: 3
+ TapHandler {
+ id: tap1
+ gesturePolicy: TapHandler.DragThreshold
+ }
+ Text {
+ anchors.centerIn: parent
+ enabled: false
+ text: "tap"
+ }
+ }
+ Rectangle {
+ width: 50
+ height: 50
+ color: "aqua"
+ border.color: tap2.isPressed ? "red" : drag2.active ? "darkgreen" : "transparent"
+ border.width: 3
+ objectName: "dragAndTap"
+ DragHandler {
+ id: drag2
+ }
+ TapHandler {
+ id: tap2
+ gesturePolicy: TapHandler.DragThreshold
+ }
+ Text {
+ anchors.centerIn: parent
+ enabled: false
+ text: "drag\nand\ntap"
+ }
+ }
+ Rectangle {
+ width: 50
+ height: 50
+ color: "aqua"
+ border.color: tap3.isPressed ? "red" : drag3.active ? "darkgreen" : "transparent"
+ border.width: 3
+ objectName: "tapAndDrag"
+ TapHandler {
+ id: tap3
+ gesturePolicy: TapHandler.DragThreshold
+ }
+ DragHandler {
+ id: drag3
+ }
+ Text {
+ anchors.centerIn: parent
+ enabled: false
+ text: "tap\nand\ndrag"
+ }
+ }
+ }
}
}
}
diff --git a/tests/auto/quick/pointerhandlers/flickableinterop/tst_flickableinterop.cpp b/tests/auto/quick/pointerhandlers/flickableinterop/tst_flickableinterop.cpp
index c8fe6052fb..7862d72db8 100644
--- a/tests/auto/quick/pointerhandlers/flickableinterop/tst_flickableinterop.cpp
+++ b/tests/auto/quick/pointerhandlers/flickableinterop/tst_flickableinterop.cpp
@@ -71,6 +71,10 @@ private slots:
void touchDragFlickableBehindSlider();
void mouseDragSlider();
void mouseDragFlickableBehindSlider();
+ void touchDragFlickableBehindItemWithHandlers_data();
+ void touchDragFlickableBehindItemWithHandlers();
+ void mouseDragFlickableBehindItemWithHandlers_data();
+ void mouseDragFlickableBehindItemWithHandlers();
private:
void createView(QScopedPointer<QQuickView> &window, const char *fileName);
@@ -469,6 +473,79 @@ void tst_FlickableInterop::mouseDragFlickableBehindSlider()
QCOMPARE(translationChangedSpy.count(), 0);
}
+void tst_FlickableInterop::touchDragFlickableBehindItemWithHandlers_data()
+{
+ QTest::addColumn<QByteArray>("nameOfRectangleToDrag");
+ QTest::addColumn<bool>("expectedFlickableMoving");
+ QTest::newRow("drag") << QByteArray("drag") << false;
+ QTest::newRow("tap") << QByteArray("tap") << true;
+ QTest::newRow("dragAndTap") << QByteArray("dragAndTap") << false;
+ QTest::newRow("tapAndDrag") << QByteArray("tapAndDrag") << false;
+}
+
+void tst_FlickableInterop::touchDragFlickableBehindItemWithHandlers()
+{
+ QFETCH(bool, expectedFlickableMoving);
+ QFETCH(QByteArray, nameOfRectangleToDrag);
+ const int dragThreshold = QGuiApplication::styleHints()->startDragDistance();
+ QScopedPointer<QQuickView> windowPtr;
+ createView(windowPtr, "flickableWithHandlers.qml");
+ QQuickView * window = windowPtr.data();
+ QQuickItem *rect = window->rootObject()->findChild<QQuickItem*>(nameOfRectangleToDrag);
+ QVERIFY(rect);
+ QQuickFlickable *flickable = window->rootObject()->findChild<QQuickFlickable*>();
+ QVERIFY(flickable);
+ QPoint p1 = rect->mapToScene(rect->clipRect().center()).toPoint();
+ QPoint originP1 = p1;
+
+ QTest::touchEvent(window, touchDevice).press(1, p1, window);
+ QQuickTouchUtils::flush(window);
+ for (int i = 0; i < dragThreshold * 3; ++i) {
+ p1 = originP1;
+ p1.rx() += i;
+ QTest::touchEvent(window, touchDevice).move(1, p1, window);
+ QQuickTouchUtils::flush(window);
+ }
+ QCOMPARE(flickable->isMoving(), expectedFlickableMoving);
+ if (!expectedFlickableMoving) {
+ QVERIFY(rect->mapToScene(rect->clipRect().center()).toPoint().x() > originP1.x());
+ }
+ QTest::touchEvent(window, touchDevice).release(1, p1, window);
+ QQuickTouchUtils::flush(window);
+}
+
+void tst_FlickableInterop::mouseDragFlickableBehindItemWithHandlers_data()
+{
+ touchDragFlickableBehindItemWithHandlers_data();
+}
+
+void tst_FlickableInterop::mouseDragFlickableBehindItemWithHandlers()
+{
+ QFETCH(bool, expectedFlickableMoving);
+ QFETCH(QByteArray, nameOfRectangleToDrag);
+ const int dragThreshold = QGuiApplication::styleHints()->startDragDistance();
+ QScopedPointer<QQuickView> windowPtr;
+ createView(windowPtr, "flickableWithHandlers.qml");
+ QQuickView * window = windowPtr.data();
+ QQuickItem *rect = window->rootObject()->findChild<QQuickItem*>(nameOfRectangleToDrag);
+ QVERIFY(rect);
+ QQuickFlickable *flickable = window->rootObject()->findChild<QQuickFlickable*>();
+ QVERIFY(flickable);
+ QPoint p1 = rect->mapToScene(rect->clipRect().center()).toPoint();
+ QPoint originP1 = p1;
+ QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, p1);
+ for (int i = 0; i < 3; ++i) {
+ p1 += QPoint(dragThreshold, 0);
+ QTest::mouseMove(window, p1);
+ QQuickTouchUtils::flush(window);
+ }
+ QCOMPARE(flickable->isMoving(), expectedFlickableMoving);
+ if (!expectedFlickableMoving) {
+ QCOMPARE(originP1 + QPoint(3*dragThreshold, 0), p1);
+ }
+ QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p1);
+}
+
QTEST_MAIN(tst_FlickableInterop)
#include "tst_flickableinterop.moc"