summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJan Arve Saether <jan-arve.saether@qt.io>2017-07-27 10:42:04 +0200
committerShawn Rutledge <shawn.rutledge@qt.io>2017-08-08 10:50:29 +0000
commit1b0c9b46ce13b0f9c533f18fb420ff10ad56e4f6 (patch)
treec7c48d968cbaac7450a84a18bc472679d451c6dc
parent2329a3145e59c16b5bbc37cedad7e67e16f14fb8 (diff)
Fix some bugs related to child mouse filteringwip/pointerhandler
- Only abort event delivery early if event that got filtered was accepted (previously we aborted as soon as the event got filtered, even if the event was filtered, but explicitly *not* accepted) - If the event that got filtered was *not* accepted, we do not abort event delivery, but we need to remove the item from the list of target items that we will deliver to later - If childMouseEventFilter returns true it should not automatically mean that the event was accepted. Change-Id: I2f2415379061131af1d5102e03d01f010e1a8168 Reviewed-by: Frederik Gladhorn <frederik.gladhorn@qt.io>
-rw-r--r--src/quick/items/qquickwindow.cpp12
-rw-r--r--src/quick/items/qquickwindow_p.h2
-rw-r--r--tests/auto/quick/qquickwindow/tst_qquickwindow.cpp80
3 files changed, 89 insertions, 5 deletions
diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp
index e2dcff7770..7b331251f0 100644
--- a/src/quick/items/qquickwindow.cpp
+++ b/src/quick/items/qquickwindow.cpp
@@ -2421,8 +2421,12 @@ bool QQuickWindowPrivate::deliverPressOrReleaseEvent(QQuickPointerEvent *event,
if (allowChildEventFiltering && !handlersOnly) {
updateFilteringParentItems(targetItems);
- if (sendFilteredPointerEvent(event, nullptr))
- return true;
+ QQuickItem *filteredItem;
+ if (sendFilteredPointerEvent(event, nullptr, &filteredItem)) {
+ if (event->isAccepted())
+ return true;
+ targetItems.removeAll(filteredItem);
+ }
}
for (QQuickItem *item: targetItems) {
@@ -2745,7 +2749,7 @@ void QQuickWindowPrivate::updateFilteringParentItems(const QVector<QQuickItem *>
}
}
-bool QQuickWindowPrivate::sendFilteredPointerEvent(QQuickPointerEvent *event, QQuickItem *receiver)
+bool QQuickWindowPrivate::sendFilteredPointerEvent(QQuickPointerEvent *event, QQuickItem *receiver, QQuickItem **itemThatFiltered)
{
if (!allowChildEventFiltering)
return false;
@@ -2759,7 +2763,7 @@ bool QQuickWindowPrivate::sendFilteredPointerEvent(QQuickPointerEvent *event, QQ
QPointF localPos = item->mapFromScene(pme->point(0)->scenePos());
QMouseEvent *me = pme->asMouseEvent(localPos);
if (filteringParent->childMouseEventFilter(item, me)) {
- event->setAccepted(true);
+ if (itemThatFiltered) *itemThatFiltered = item;
ret = true;
}
}
diff --git a/src/quick/items/qquickwindow_p.h b/src/quick/items/qquickwindow_p.h
index c2d2a7a8a4..14564a7f55 100644
--- a/src/quick/items/qquickwindow_p.h
+++ b/src/quick/items/qquickwindow_p.h
@@ -148,7 +148,7 @@ public:
static QMouseEvent *cloneMouseEvent(QMouseEvent *event, QPointF *transformedLocalPos = 0);
void deliverMouseEvent(QQuickPointerMouseEvent *pointerEvent);
bool sendFilteredMouseEvent(QQuickItem *, QQuickItem *, QEvent *, QSet<QQuickItem *> *);
- bool sendFilteredPointerEvent(QQuickPointerEvent *event, QQuickItem *receiver);
+ bool sendFilteredPointerEvent(QQuickPointerEvent *event, QQuickItem *receiver, QQuickItem **itemThatFiltered = 0);
#if QT_CONFIG(wheelevent)
bool deliverWheelEvent(QQuickItem *, QWheelEvent *);
#endif
diff --git a/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp b/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp
index 0c341b2663..2133b4d2d3 100644
--- a/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp
+++ b/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp
@@ -37,6 +37,7 @@
#include <QtQml/QQmlComponent>
#include <QtQuick/private/qquickrectangle_p.h>
#include <QtQuick/private/qquickloader_p.h>
+#include <QtQuick/private/qquickmousearea_p.h>
#include "../../shared/util.h"
#include "../shared/visualtestutil.h"
#include "../shared/viewtestutil.h"
@@ -381,6 +382,7 @@ private slots:
void testHoverChildMouseEventFilter();
void testHoverTimestamp();
+ void test_circleMapItem();
void pointerEventTypeAndPointCount();
@@ -2553,6 +2555,84 @@ void tst_qquickwindow::testHoverTimestamp()
QCOMPARE(hoverConsumer->hoverTimestamps.last(), 5UL);
}
+class CircleItem : public QQuickRectangle
+{
+public:
+ CircleItem(QQuickItem *parent = 0) : QQuickRectangle(parent) { }
+
+ void setRadius(qreal radius) {
+ const qreal diameter = radius*2;
+ setWidth(diameter);
+ setHeight(diameter);
+ }
+
+ bool childMouseEventFilter(QQuickItem *item, QEvent *event) override
+ {
+ Q_UNUSED(item)
+ if (event->type() == QEvent::MouseButtonPress && !contains(static_cast<QMouseEvent*>(event)->pos())) {
+ // This is an evil hack: in case of items that are not rectangles, we never accept the event.
+ // Instead the events are now delivered to QDeclarativeGeoMapItemBase which doesn't to anything with them.
+ // The map below it still works since it filters events and steals the events at some point.
+ event->setAccepted(false);
+ return true;
+ }
+ return false;
+ }
+
+ virtual bool contains(const QPointF &pos) const override {
+ // returns true if the point is inside the the embedded circle inside the (square) rect
+ const float radius = (float)width()/2;
+ const QVector2D center(radius, radius);
+ const QVector2D dx = QVector2D(pos) - center;
+ const bool ret = dx.lengthSquared() < radius*radius;
+ return ret;
+ }
+};
+
+void tst_qquickwindow::test_circleMapItem()
+{
+ QQuickWindow window;
+
+ window.resize(250, 250);
+ window.setPosition(100, 100);
+ window.setTitle(QTest::currentTestFunction());
+
+ QQuickItem *root = window.contentItem();
+ QQuickMouseArea *mab = new QQuickMouseArea(root);
+ mab->setObjectName("Bottom MouseArea");
+ mab->setSize(QSizeF(100, 100));
+
+ CircleItem *topItem = new CircleItem(root);
+ topItem->setFiltersChildMouseEvents(true);
+ topItem->setColor(Qt::green);
+ topItem->setObjectName("Top Item");
+ topItem->setPosition(QPointF(30, 30));
+ topItem->setRadius(20);
+ QQuickMouseArea *mat = new QQuickMouseArea(topItem);
+ mat->setObjectName("Top Item/MouseArea");
+ mat->setSize(QSizeF(40, 40));
+
+ QSignalSpy bottomSpy(mab, SIGNAL(clicked(QQuickMouseEvent *)));
+ QSignalSpy topSpy(mat, SIGNAL(clicked(QQuickMouseEvent *)));
+
+ window.show();
+ QTest::qWaitForWindowExposed(&window);
+ QTest::qWait(1000);
+
+ QPoint pos(50, 50);
+ QTest::mouseClick(&window, Qt::LeftButton, Qt::KeyboardModifiers(), pos);
+
+ QCOMPARE(topSpy.count(), 1);
+ QCOMPARE(bottomSpy.count(), 0);
+
+ // Outside the "Circles" "input area", but on top of the bottomItem rectangle
+ pos = QPoint(66, 66);
+ QTest::mouseClick(&window, Qt::LeftButton, Qt::KeyboardModifiers(), pos);
+
+ QCOMPARE(bottomSpy.count(), 1);
+ QCOMPARE(topSpy.count(), 1);
+}
+
void tst_qquickwindow::pointerEventTypeAndPointCount()
{
QPointF localPosition(33, 66);