summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--tests/auto/widgets/graphicsview/qgraphicsproxywidget/tst_qgraphicsproxywidget.cpp315
-rw-r--r--tests/auto/widgets/graphicsview/qgraphicsview/tst_qgraphicsview.cpp310
2 files changed, 315 insertions, 310 deletions
diff --git a/tests/auto/widgets/graphicsview/qgraphicsproxywidget/tst_qgraphicsproxywidget.cpp b/tests/auto/widgets/graphicsview/qgraphicsproxywidget/tst_qgraphicsproxywidget.cpp
index b5ed792c67..4bd0dd0a8c 100644
--- a/tests/auto/widgets/graphicsview/qgraphicsproxywidget/tst_qgraphicsproxywidget.cpp
+++ b/tests/auto/widgets/graphicsview/qgraphicsproxywidget/tst_qgraphicsproxywidget.cpp
@@ -157,7 +157,11 @@ private slots:
void mapToGlobal();
void mapToGlobalWithoutScene();
void QTBUG_43780_visibility();
+#if QT_CONFIG(wheelevent)
+ void wheelEventPropagation();
+#endif
void forwardTouchEvent();
+ void touchEventPropagation();
};
// Subclass that exposes the protected functions.
@@ -3632,6 +3636,149 @@ public:
}
};
+#if QT_CONFIG(wheelevent)
+/*!
+ QGraphicsProxyWidget receives wheel events from QGraphicsScene, and then
+ generates a new event that is sent spontaneously in order to enable event
+ propagation. This requires extra handling of the wheel grabbing we do for
+ high-precision wheel event streams.
+
+ Test that this doesn't trigger infinite recursion, while still resulting in
+ event propagation within the embedded widget hierarchy, and back to the
+ QGraphicsView if the event is not accepted.
+
+ See tst_QApplication::wheelEventPropagation for a similar test.
+*/
+void tst_QGraphicsProxyWidget::wheelEventPropagation()
+{
+ QGraphicsScene scene(0, 0, 600, 600);
+
+ QWidget *label = new QLabel("Direct");
+ label->setFixedSize(300, 30);
+ QGraphicsProxyWidget *labelProxy = scene.addWidget(label);
+ labelProxy->setPos(0, 50);
+ labelProxy->show();
+
+ class NestedWidget : public QWidget
+ {
+ public:
+ NestedWidget(const QString &text)
+ {
+ setObjectName("Nested Label");
+ QLabel *nested = new QLabel(text);
+ QHBoxLayout *hbox = new QHBoxLayout;
+ hbox->addWidget(nested);
+ setLayout(hbox);
+ }
+
+ int wheelEventCount = 0;
+ protected:
+ void wheelEvent(QWheelEvent *) override
+ {
+ ++wheelEventCount;
+ }
+ };
+ NestedWidget *nestedWidget = new NestedWidget("Nested");
+ nestedWidget->setFixedSize(300, 60);
+ QGraphicsProxyWidget *nestedProxy = scene.addWidget(nestedWidget);
+ nestedProxy->setPos(0, 120);
+ nestedProxy->show();
+
+ QGraphicsView view(&scene);
+ view.setFixedHeight(200);
+ view.show();
+
+ QVERIFY(QTest::qWaitForWindowActive(&view));
+ QVERIFY(view.verticalScrollBar()->isVisible());
+
+ view.verticalScrollBar()->setValue(0);
+ QSignalSpy scrollSpy(view.verticalScrollBar(), &QScrollBar::valueChanged);
+
+ const QPoint wheelPosition(50, 25);
+ auto wheelUp = [&view, wheelPosition](Qt::ScrollPhase phase) {
+ const QPoint global = view.mapToGlobal(wheelPosition);
+ const QPoint pixelDelta(0, -25);
+ const QPoint angleDelta(0, -120);
+ QWindowSystemInterface::handleWheelEvent(view.windowHandle(), wheelPosition, global,
+ pixelDelta, angleDelta, Qt::NoModifier,
+ phase);
+ QCoreApplication::processEvents();
+ };
+
+ int scrollCount = 0;
+ // test non-kinetic events; they are not grabbed, and should scroll the view unless
+ // accepted by the embedded widget
+ QCOMPARE(view.itemAt(wheelPosition), nullptr);
+ wheelUp(Qt::NoScrollPhase);
+ QCOMPARE(scrollSpy.count(), ++scrollCount);
+
+ // wheeling on the label, which ignores the event, should scroll the view
+ QCOMPARE(view.itemAt(wheelPosition), labelProxy);
+ wheelUp(Qt::NoScrollPhase);
+ QCOMPARE(scrollSpy.count(), ++scrollCount);
+ QCOMPARE(view.itemAt(wheelPosition), labelProxy);
+ wheelUp(Qt::NoScrollPhase);
+ QCOMPARE(scrollSpy.count(), ++scrollCount);
+
+ // left the widget
+ QCOMPARE(view.itemAt(wheelPosition), nullptr);
+ wheelUp(Qt::NoScrollPhase);
+ QCOMPARE(scrollSpy.count(), ++scrollCount);
+
+ // reached the nested widget, which accepts the wheel event, so no more scrolling
+ QCOMPARE(view.itemAt(wheelPosition), nestedProxy);
+ // remember this position for later
+ const int scrollBarValueOnNestedProxy = view.verticalScrollBar()->value();
+ wheelUp(Qt::NoScrollPhase);
+ QCOMPARE(scrollSpy.count(), scrollCount);
+ QCOMPARE(nestedWidget->wheelEventCount, 1);
+
+ // reset, try with kinetic events
+ view.verticalScrollBar()->setValue(0);
+ ++scrollCount;
+
+ // starting a scroll outside any widget and scrolling through the widgets should work,
+ // no matter if the widget accepts wheel events - the view has the grab
+ QCOMPARE(view.itemAt(wheelPosition), nullptr);
+ wheelUp(Qt::ScrollBegin);
+ QCOMPARE(scrollSpy.count(), ++scrollCount);
+ for (int i = 0; i < 5; ++i) {
+ wheelUp(Qt::ScrollUpdate);
+ QCOMPARE(scrollSpy.count(), ++scrollCount);
+ }
+ wheelUp(Qt::ScrollEnd);
+ QCOMPARE(scrollSpy.count(), ++scrollCount);
+
+ // reset
+ view.verticalScrollBar()->setValue(0);
+ scrollCount = scrollSpy.count();
+
+ // starting a scroll on a widget that doesn't accept wheel events
+ // should also scroll the view, which still gets the grab
+ wheelUp(Qt::NoScrollPhase);
+ scrollCount = scrollSpy.count();
+
+ QCOMPARE(view.itemAt(wheelPosition), labelProxy);
+ wheelUp(Qt::ScrollBegin);
+ QCOMPARE(scrollSpy.count(), ++scrollCount);
+ for (int i = 0; i < 5; ++i) {
+ wheelUp(Qt::ScrollUpdate);
+ QCOMPARE(scrollSpy.count(), ++scrollCount);
+ }
+ wheelUp(Qt::ScrollEnd);
+ QCOMPARE(scrollSpy.count(), ++scrollCount);
+
+ // starting a scroll on a widget that does accept wheel events
+ // should not scroll the view
+ view.verticalScrollBar()->setValue(scrollBarValueOnNestedProxy);
+ scrollCount = scrollSpy.count();
+
+ QCOMPARE(view.itemAt(wheelPosition), nestedProxy);
+ wheelUp(Qt::ScrollBegin);
+ QCOMPARE(scrollSpy.count(), scrollCount);
+}
+#endif // QT_CONFIG(wheelevent)
+
// QTBUG_45737
void tst_QGraphicsProxyWidget::forwardTouchEvent()
{
@@ -3670,5 +3817,173 @@ void tst_QGraphicsProxyWidget::forwardTouchEvent()
QCOMPARE(eventSpy.counts[QEvent::TouchEnd], 1);
}
+void tst_QGraphicsProxyWidget::touchEventPropagation()
+{
+ QGraphicsScene scene(0, 0, 300, 200);
+ QWidget *simpleWidget = new QWidget;
+ simpleWidget->setObjectName("simpleWidget");
+ simpleWidget->setAttribute(Qt::WA_AcceptTouchEvents, true);
+ QGraphicsProxyWidget *simpleProxy = scene.addWidget(simpleWidget);
+ simpleProxy->setAcceptTouchEvents(true);
+ simpleProxy->setGeometry(QRectF(0, 0, 30, 30));
+
+ QWidget *formWidget = new QWidget;
+ formWidget->setObjectName("formWidget");
+ formWidget->setAttribute(Qt::WA_AcceptTouchEvents, true);
+ QPushButton *pushButton1 = new QPushButton("One");
+ pushButton1->setObjectName("pushButton1");
+ pushButton1->setAttribute(Qt::WA_AcceptTouchEvents, true);
+ QPushButton *pushButton2 = new QPushButton("Two");
+ pushButton2->setObjectName("pushButton2");
+ pushButton2->setAttribute(Qt::WA_AcceptTouchEvents, true);
+ QVBoxLayout *vbox = new QVBoxLayout;
+ vbox->addWidget(pushButton1);
+ vbox->addWidget(pushButton2);
+ formWidget->setLayout(vbox);
+ QGraphicsProxyWidget *formProxy = scene.addWidget(formWidget);
+ formProxy->setAcceptTouchEvents(true);
+ formProxy->setGeometry(QRectF(50, 50, 200, 160));
+
+ QGraphicsView view(&scene);
+ view.setFixedSize(scene.width(), scene.height());
+ view.verticalScrollBar()->setValue(0);
+ view.horizontalScrollBar()->setValue(0);
+ view.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&view));
+
+ class TouchEventSpy : public QObject
+ {
+ public:
+ using QObject::QObject;
+
+ struct TouchRecord {
+ QObject *receiver;
+ QEvent::Type eventType;
+ QHash<int, QPointF> positions;
+ };
+ QList<TouchRecord> records;
+
+ int count() const { return records.count(); }
+ TouchRecord at(int i) const { return records.at(i); }
+ void clear() { records.clear(); }
+ protected:
+ bool eventFilter(QObject *receiver, QEvent *event) override
+ {
+ switch (event->type()) {
+ case QEvent::TouchBegin:
+ case QEvent::TouchUpdate:
+ case QEvent::TouchCancel:
+ case QEvent::TouchEnd: {
+ QTouchEvent *touchEvent = static_cast<QTouchEvent *>(event);
+ // instead of detaching each QEventPoint, just store the relative positions
+ QHash<int, QPointF> positions;
+ for (const auto &touchPoint : touchEvent->points())
+ positions[touchPoint.id()] = touchPoint.position();
+ records << TouchRecord{receiver, event->type(), positions};
+ break;
+ }
+ default:
+ break;
+ }
+ return QObject::eventFilter(receiver, event);
+ }
+ } eventSpy;
+ qApp->installEventFilter(&eventSpy);
+
+ auto touchDevice = QTest::createTouchDevice();
+ const QPointF simpleCenter = simpleProxy->geometry().center();
+
+ // On systems without double conversion we might get different rounding behavior.
+ // One pixel off in any direction is acceptable for this test.
+ constexpr auto closeEnough = [](QPointF exp, QPointF act) -> bool {
+ const QRectF expArea(exp - QPointF(1., 1.), exp + QPointF(1., 1.));
+ const bool contains = expArea.contains(act);
+ if (!contains)
+ qWarning() << act << "not in" << exp;
+ return contains;
+ };
+
+ // verify that the embedded widget gets the correctly translated event
+ {
+ auto sequence = QTest::touchEvent(view.viewport(), touchDevice);
+ sequence.press(0, simpleCenter.toPoint());
+ }
+ // window, viewport, scene, simpleProxy, simpleWidget
+ QCOMPARE(eventSpy.count(), 5);
+ auto record = eventSpy.at(eventSpy.count() - 1);
+ QCOMPARE(record.receiver, simpleWidget);
+ QCOMPARE(record.eventType, QEvent::TouchBegin);
+ QCOMPARE(record.positions.count(), 1);
+ QVERIFY(closeEnough(record.positions[0], simpleCenter));
+ eventSpy.clear();
+
+ // verify that the layout of formWidget is how we expect it to be
+ QCOMPARE(formWidget->childAt(QPoint(5, 5)), nullptr);
+ const QPoint pb1Center = pushButton1->rect().center();
+ QCOMPARE(formWidget->childAt(pushButton1->pos() + pb1Center), pushButton1);
+ const QPoint pb2Center = pushButton2->rect().center();
+ QCOMPARE(formWidget->childAt(pushButton2->pos() + pb2Center), pushButton2);
+
+ // Single touch point to nested widget not accepting event.
+ // Event should bubble up and translate correctly.
+ {
+ auto sequence = QTest::touchEvent(view.viewport(), touchDevice);
+ sequence.press(0, pushButton1->pos() + pb1Center + formProxy->pos().toPoint());
+ }
+ // ..., formProxy, pushButton1, formWidget
+ QCOMPARE(eventSpy.count(), 6);
+ record = eventSpy.at(eventSpy.count() - 2);
+ QCOMPARE(record.receiver, pushButton1);
+ QVERIFY(closeEnough(record.positions[0], pb1Center));
+ QCOMPARE(record.eventType, QEvent::TouchBegin);
+ // pushButton doesn't accept the point, so it propagates to parent
+ record = eventSpy.at(eventSpy.count() - 1);
+ QCOMPARE(record.receiver, formWidget);
+ QVERIFY(closeEnough(record.positions[0], pushButton1->pos() + pb1Center));
+ QCOMPARE(record.eventType, QEvent::TouchBegin);
+ eventSpy.clear();
+
+ // multi-touch to different widgets
+ {
+ auto sequence = QTest::touchEvent(view.viewport(), touchDevice);
+ sequence.press(0, pushButton1->pos() + pb1Center + formProxy->pos().toPoint());
+ sequence.press(1, pushButton2->pos() + pb2Center + formProxy->pos().toPoint());
+ }
+ // window, viewport, scene, formProxy, pushButton1, formWidget, pushButton2, formWidget
+ QCOMPARE(eventSpy.count(), 8);
+ record = eventSpy.at(4);
+ // the order in which the two presses are delivered is not defined
+ const bool pb1First = record.receiver == pushButton1;
+ if (pb1First) {
+ QCOMPARE(record.receiver, pushButton1);
+ QVERIFY(closeEnough(record.positions[0], pb1Center));
+ } else {
+ QCOMPARE(record.receiver, pushButton2);
+ QVERIFY(closeEnough(record.positions[1], pb2Center));
+ }
+ record = eventSpy.at(5);
+ QCOMPARE(record.receiver, formWidget);
+ if (pb1First) {
+ QVERIFY(closeEnough(record.positions[0], pushButton1->pos() + pb1Center));
+ } else {
+ QVERIFY(closeEnough(record.positions[1], pushButton2->pos() + pb2Center));
+ }
+ record = eventSpy.at(6);
+ if (pb1First) {
+ QCOMPARE(record.receiver, pushButton2);
+ QVERIFY(closeEnough(record.positions[1], pb2Center));
+ } else {
+ QCOMPARE(record.receiver, pushButton1);
+ QVERIFY(closeEnough(record.positions[0], pb1Center));
+ }
+ record = eventSpy.at(7);
+ QCOMPARE(record.receiver, formWidget);
+ if (pb1First) {
+ QVERIFY(closeEnough(record.positions[1], pushButton2->pos() + pb2Center));
+ } else {
+ QVERIFY(closeEnough(record.positions[0], pushButton1->pos() + pb1Center));
+ }
+}
+
QTEST_MAIN(tst_QGraphicsProxyWidget)
#include "tst_qgraphicsproxywidget.moc"
diff --git a/tests/auto/widgets/graphicsview/qgraphicsview/tst_qgraphicsview.cpp b/tests/auto/widgets/graphicsview/qgraphicsview/tst_qgraphicsview.cpp
index 8ce841e863..1f0f20a297 100644
--- a/tests/auto/widgets/graphicsview/qgraphicsview/tst_qgraphicsview.cpp
+++ b/tests/auto/widgets/graphicsview/qgraphicsview/tst_qgraphicsview.cpp
@@ -199,9 +199,7 @@ private slots:
void sendEvent();
#if QT_CONFIG(wheelevent)
void wheelEvent();
- void wheelEventPropagation();
#endif
- void touchEvent();
#ifndef QT_NO_CURSOR
void cursor();
void cursor2();
@@ -2247,316 +2245,8 @@ void tst_QGraphicsView::wheelEvent()
QCOMPARE(spy.count(), 2);
QVERIFY(widget->hasFocus());
}
-
-/*!
- QGraphicsProxyWidget receives wheel events from QGraphicsScene, and then
- generates a new event that is sent spontaneously in order to enable event
- propagation. This requires extra handling of the wheel grabbing we do for
- high-precision wheel event streams.
-
- Test that this doesn't trigger infinite recursion, while still resulting in
- event propagation within the embedded widget hierarchy, and back to the
- QGraphicsView if the event is not accepted.
-
- See tst_QApplication::wheelEventPropagation for a similar test.
-*/
-void tst_QGraphicsView::wheelEventPropagation()
-{
- QGraphicsScene scene(0, 0, 600, 600);
-
- QWidget *label = new QLabel("Direct");
- label->setFixedSize(300, 30);
- QGraphicsProxyWidget *labelProxy = scene.addWidget(label);
- labelProxy->setPos(0, 50);
- labelProxy->show();
-
- class NestedWidget : public QWidget
- {
- public:
- NestedWidget(const QString &text)
- {
- setObjectName("Nested Label");
- QLabel *nested = new QLabel(text);
- QHBoxLayout *hbox = new QHBoxLayout;
- hbox->addWidget(nested);
- setLayout(hbox);
- }
-
- int wheelEventCount = 0;
- protected:
- void wheelEvent(QWheelEvent *) override
- {
- ++wheelEventCount;
- }
- };
- NestedWidget *nestedWidget = new NestedWidget("Nested");
- nestedWidget->setFixedSize(300, 60);
- QGraphicsProxyWidget *nestedProxy = scene.addWidget(nestedWidget);
- nestedProxy->setPos(0, 120);
- nestedProxy->show();
-
- QGraphicsView view(&scene);
- view.setFixedHeight(200);
- view.show();
-
- QVERIFY(QTest::qWaitForWindowActive(&view));
- QVERIFY(view.verticalScrollBar()->isVisible());
-
- view.verticalScrollBar()->setValue(0);
- QSignalSpy scrollSpy(view.verticalScrollBar(), &QScrollBar::valueChanged);
-
- const QPoint wheelPosition(50, 25);
- auto wheelUp = [&view, wheelPosition](Qt::ScrollPhase phase) {
- const QPoint global = view.mapToGlobal(wheelPosition);
- const QPoint pixelDelta(0, -25);
- const QPoint angleDelta(0, -120);
- QWindowSystemInterface::handleWheelEvent(view.windowHandle(), wheelPosition, global,
- pixelDelta, angleDelta, Qt::NoModifier,
- phase);
- QCoreApplication::processEvents();
- };
-
- int scrollCount = 0;
- // test non-kinetic events; they are not grabbed, and should scroll the view unless
- // accepted by the embedded widget
- QCOMPARE(view.itemAt(wheelPosition), nullptr);
- wheelUp(Qt::NoScrollPhase);
- QCOMPARE(scrollSpy.count(), ++scrollCount);
-
- // wheeling on the label, which ignores the event, should scroll the view
- QCOMPARE(view.itemAt(wheelPosition), labelProxy);
- wheelUp(Qt::NoScrollPhase);
- QCOMPARE(scrollSpy.count(), ++scrollCount);
- QCOMPARE(view.itemAt(wheelPosition), labelProxy);
- wheelUp(Qt::NoScrollPhase);
- QCOMPARE(scrollSpy.count(), ++scrollCount);
-
- // left the widget
- QCOMPARE(view.itemAt(wheelPosition), nullptr);
- wheelUp(Qt::NoScrollPhase);
- QCOMPARE(scrollSpy.count(), ++scrollCount);
-
- // reached the nested widget, which accepts the wheel event, so no more scrolling
- QCOMPARE(view.itemAt(wheelPosition), nestedProxy);
- // remember this position for later
- const int scrollBarValueOnNestedProxy = view.verticalScrollBar()->value();
- wheelUp(Qt::NoScrollPhase);
- QCOMPARE(scrollSpy.count(), scrollCount);
- QCOMPARE(nestedWidget->wheelEventCount, 1);
-
- // reset, try with kinetic events
- view.verticalScrollBar()->setValue(0);
- ++scrollCount;
-
- // starting a scroll outside any widget and scrolling through the widgets should work,
- // no matter if the widget accepts wheel events - the view has the grab
- QCOMPARE(view.itemAt(wheelPosition), nullptr);
- wheelUp(Qt::ScrollBegin);
- QCOMPARE(scrollSpy.count(), ++scrollCount);
- for (int i = 0; i < 5; ++i) {
- wheelUp(Qt::ScrollUpdate);
- QCOMPARE(scrollSpy.count(), ++scrollCount);
- }
- wheelUp(Qt::ScrollEnd);
- QCOMPARE(scrollSpy.count(), ++scrollCount);
-
- // reset
- view.verticalScrollBar()->setValue(0);
- scrollCount = scrollSpy.count();
-
- // starting a scroll on a widget that doesn't accept wheel events
- // should also scroll the view, which still gets the grab
- wheelUp(Qt::NoScrollPhase);
- scrollCount = scrollSpy.count();
-
- QCOMPARE(view.itemAt(wheelPosition), labelProxy);
- wheelUp(Qt::ScrollBegin);
- QCOMPARE(scrollSpy.count(), ++scrollCount);
- for (int i = 0; i < 5; ++i) {
- wheelUp(Qt::ScrollUpdate);
- QCOMPARE(scrollSpy.count(), ++scrollCount);
- }
- wheelUp(Qt::ScrollEnd);
- QCOMPARE(scrollSpy.count(), ++scrollCount);
-
- // starting a scroll on a widget that does accept wheel events
- // should not scroll the view
- view.verticalScrollBar()->setValue(scrollBarValueOnNestedProxy);
- scrollCount = scrollSpy.count();
-
- QCOMPARE(view.itemAt(wheelPosition), nestedProxy);
- wheelUp(Qt::ScrollBegin);
- QCOMPARE(scrollSpy.count(), scrollCount);
-}
#endif // QT_CONFIG(wheelevent)
-void tst_QGraphicsView::touchEvent()
-{
- QGraphicsScene scene(0, 0, 300, 200);
- QWidget *simpleWidget = new QWidget;
- simpleWidget->setObjectName("simpleWidget");
- simpleWidget->setAttribute(Qt::WA_AcceptTouchEvents, true);
- QGraphicsProxyWidget *simpleProxy = scene.addWidget(simpleWidget);
- simpleProxy->setAcceptTouchEvents(true);
- simpleProxy->setGeometry(QRectF(0, 0, 30, 30));
-
- QWidget *formWidget = new QWidget;
- formWidget->setObjectName("formWidget");
- formWidget->setAttribute(Qt::WA_AcceptTouchEvents, true);
- QPushButton *pushButton1 = new QPushButton("One");
- pushButton1->setObjectName("pushButton1");
- pushButton1->setAttribute(Qt::WA_AcceptTouchEvents, true);
- QPushButton *pushButton2 = new QPushButton("Two");
- pushButton2->setObjectName("pushButton2");
- pushButton2->setAttribute(Qt::WA_AcceptTouchEvents, true);
- QVBoxLayout *vbox = new QVBoxLayout;
- vbox->addWidget(pushButton1);
- vbox->addWidget(pushButton2);
- formWidget->setLayout(vbox);
- QGraphicsProxyWidget *formProxy = scene.addWidget(formWidget);
- formProxy->setAcceptTouchEvents(true);
- formProxy->setGeometry(QRectF(50, 50, 200, 100));
-
- QGraphicsView view(&scene);
- view.setFixedSize(scene.width(), scene.height());
- view.verticalScrollBar()->setValue(0);
- view.horizontalScrollBar()->setValue(0);
- view.show();
- QVERIFY(QTest::qWaitForWindowExposed(&view));
-
- class TouchEventSpy : public QObject
- {
- public:
- using QObject::QObject;
-
- struct TouchRecord {
- QObject *receiver;
- QEvent::Type eventType;
- QHash<int, QPointF> positions;
- };
- QList<TouchRecord> records;
-
- int count() const { return records.count(); }
- TouchRecord at(int i) const { return records.at(i); }
- void clear() { records.clear(); }
- protected:
- bool eventFilter(QObject *receiver, QEvent *event) override
- {
- switch (event->type()) {
- case QEvent::TouchBegin:
- case QEvent::TouchUpdate:
- case QEvent::TouchCancel:
- case QEvent::TouchEnd: {
- QTouchEvent *touchEvent = static_cast<QTouchEvent *>(event);
- // instead of detaching each QEventPoint, just store the relative positions
- QHash<int, QPointF> positions;
- for (const auto &touchPoint : touchEvent->points())
- positions[touchPoint.id()] = touchPoint.position();
- records << TouchRecord{receiver, event->type(), positions};
- break;
- }
- default:
- break;
- }
- return QObject::eventFilter(receiver, event);
- }
- } eventSpy;
- qApp->installEventFilter(&eventSpy);
-
- auto touchDevice = QTest::createTouchDevice();
- const QPointF simpleCenter = simpleProxy->geometry().center();
-
- // On systems without double conversion we might get different rounding behavior.
- // One pixel off in any direction is acceptable for this test.
- constexpr auto closeEnough = [](QPointF exp, QPointF act) -> bool {
- const QRectF expArea(exp - QPointF(1., 1.), exp + QPointF(1., 1.));
- const bool contains = expArea.contains(act);
- if (!contains)
- qWarning() << act << "not in" << exp;
- return contains;
- };
-
- // verify that the embedded widget gets the correctly translated event
- {
- auto sequence = QTest::touchEvent(view.viewport(), touchDevice);
- sequence.press(0, simpleCenter.toPoint());
- }
- // window, viewport, scene, simpleProxy, simpleWidget
- QCOMPARE(eventSpy.count(), 5);
- auto record = eventSpy.at(eventSpy.count() - 1);
- QCOMPARE(record.receiver, simpleWidget);
- QCOMPARE(record.eventType, QEvent::TouchBegin);
- QCOMPARE(record.positions.count(), 1);
- QVERIFY(closeEnough(record.positions[0], simpleCenter));
- eventSpy.clear();
-
- // verify that the layout of formWidget is how we expect it to be
- QCOMPARE(formWidget->childAt(QPoint(5, 5)), nullptr);
- const QPoint pb1Center = pushButton1->rect().center();
- QCOMPARE(formWidget->childAt(pushButton1->pos() + pb1Center), pushButton1);
- const QPoint pb2Center = pushButton2->rect().center();
- QCOMPARE(formWidget->childAt(pushButton2->pos() + pb2Center), pushButton2);
-
- // single touch point to nested widget, event should bubble up and translate correctly
- {
- auto sequence = QTest::touchEvent(view.viewport(), touchDevice);
- sequence.press(0, pushButton1->pos() + pb1Center + formProxy->pos().toPoint());
- }
- // ..., formProxy, pushButton1, formWidget
- QCOMPARE(eventSpy.count(), 6);
- record = eventSpy.at(eventSpy.count() - 2);
- QCOMPARE(record.receiver, pushButton1);
- QVERIFY(closeEnough(record.positions[0], pb1Center));
- QCOMPARE(record.eventType, QEvent::TouchBegin);
- // pushButton doesn't accept the point, so it propagates to parent
- record = eventSpy.at(eventSpy.count() - 1);
- QCOMPARE(record.receiver, formWidget);
- QVERIFY(closeEnough(record.positions[0], pushButton1->pos() + pb1Center));
- QCOMPARE(record.eventType, QEvent::TouchBegin);
- eventSpy.clear();
-
- // multi-touch to different widgets
- {
- auto sequence = QTest::touchEvent(view.viewport(), touchDevice);
- sequence.press(0, pushButton1->pos() + pb1Center + formProxy->pos().toPoint());
- sequence.press(1, pushButton2->pos() + pb2Center + formProxy->pos().toPoint());
- }
- // window, viewport, scene, formProxy, pushButton1, formWidget, pushButton2, formWidget
- QCOMPARE(eventSpy.count(), 8);
- record = eventSpy.at(4);
- // the order in which the two presses are delivered is not defined
- const bool pb1First = record.receiver == pushButton1;
- if (pb1First) {
- QCOMPARE(record.receiver, pushButton1);
- QVERIFY(closeEnough(record.positions[0], pb1Center));
- } else {
- QCOMPARE(record.receiver, pushButton2);
- QVERIFY(closeEnough(record.positions[1], pb2Center));
- }
- record = eventSpy.at(5);
- QCOMPARE(record.receiver, formWidget);
- if (pb1First) {
- QVERIFY(closeEnough(record.positions[0], pushButton1->pos() + pb1Center));
- } else {
- QVERIFY(closeEnough(record.positions[1], pushButton2->pos() + pb2Center));
- }
- record = eventSpy.at(6);
- if (pb1First) {
- QCOMPARE(record.receiver, pushButton2);
- QVERIFY(closeEnough(record.positions[1], pb2Center));
- } else {
- QCOMPARE(record.receiver, pushButton1);
- QVERIFY(closeEnough(record.positions[0], pb1Center));
- }
- record = eventSpy.at(7);
- QCOMPARE(record.receiver, formWidget);
- if (pb1First) {
- QVERIFY(closeEnough(record.positions[1], pushButton2->pos() + pb2Center));
- } else {
- QVERIFY(closeEnough(record.positions[0], pushButton1->pos() + pb1Center));
- }
-}
-
#ifndef QT_NO_CURSOR
void tst_QGraphicsView::cursor()
{