summaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
authorVolker Hilsheimer <volker.hilsheimer@qt.io>2021-08-29 10:52:14 +0200
committerVolker Hilsheimer <volker.hilsheimer@qt.io>2021-08-30 18:20:08 +0200
commit5c7c2f84bcc1d934315ed86757791b0810be9c1e (patch)
tree7769c29dd43d5d6db4379f7863c4f76ee6eb175b /tests
parenta49ba9265f90a5561351de2b47c6082b267f43b0 (diff)
Move QGraphicsProxyWidget test into correct test case
The test case was previously disabled, so tests were added to the QGraphicsView test instead. With the QGraphicsProxyWidget test active again, move the test cases where they belong. Amends 1ecf2212fae176b78c9951a37df9e33eb24d4f2d, 01aeb5f7e4fd977e9698fffdc7650897664ecb82, and 06235d36ae9d00366215e748d80ff0faed3c2124 Pick-to: 6.2 Change-Id: I208b8a418653cf0640c2e7c9f716fa69538ad7e9 Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: Shawn Rutledge <shawn.rutledge@qt.io>
Diffstat (limited to 'tests')
-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()
{