diff options
author | Volker Hilsheimer <volker.hilsheimer@qt.io> | 2023-01-13 16:14:51 +0100 |
---|---|---|
committer | Volker Hilsheimer <volker.hilsheimer@qt.io> | 2023-01-17 07:22:18 +0100 |
commit | 731cc2dbf6d6ebe041f232952dcc1af71e589b5a (patch) | |
tree | fd27ff12f083ed7713895e7549d7157154f8c75e /tests/auto | |
parent | 6137b73b9d39644f100a268e6d222939c98547d1 (diff) |
QQuickPopup: fix logic for modally blocking wheel events
After caca7d7d4fcb7281332904c01950a66385bad0b3, QQuickOverlay ate wheel
events to any item that was not a child of the top-most modal popup.
This broke event delivery to children of modless popups higher up in the
stack.
Fix that logic so that we don't eat events if we find a popup that the
item is a child of. Only eat the event if we don't find such a popup
before hitting the first modal popup.
Add a test with a relevant scenario, and as a drive-by, fix and simplify
the helper function sending wheel events. Since the event gets delivered
to the window, we have to use scene coordinates, not item coordinates.
This happened to work in the wheel test case as the test sliders cover
the entire window.
Fixes: QTBUG-110023
Pick-to: 6.5 6.4
Change-Id: Ibc53114cf09693e23b1e66f28a0c2056f3bd810e
Reviewed-by: Mitch Curtis <mitch.curtis@qt.io>
Diffstat (limited to 'tests/auto')
-rw-r--r-- | tests/auto/quickcontrols/qquickpopup/data/nested-wheel.qml | 44 | ||||
-rw-r--r-- | tests/auto/quickcontrols/qquickpopup/tst_qquickpopup.cpp | 50 |
2 files changed, 88 insertions, 6 deletions
diff --git a/tests/auto/quickcontrols/qquickpopup/data/nested-wheel.qml b/tests/auto/quickcontrols/qquickpopup/data/nested-wheel.qml new file mode 100644 index 0000000000..a0b319fd24 --- /dev/null +++ b/tests/auto/quickcontrols/qquickpopup/data/nested-wheel.qml @@ -0,0 +1,44 @@ +import QtQuick +import QtQuick.Controls + +ApplicationWindow { + width: 400 + height: 400 + + property alias modalPopup: popup + property alias comboBox: combobox + + Popup { + id: popup + objectName: "Modal Dialog" + width: 300 + height: 300 + anchors.centerIn: parent + visible: true + modal: true + + ComboBox { + id: combobox + anchors.centerIn: parent + width: 120 + model: 30 + + popup: Popup { + objectName: "Combobox Popup" + y: combobox.height + width: combobox.width + height: contentItem.implicitHeight + contentItem: ListView { + objectName: "Combobox ListView" + clip: true + implicitHeight: 150 + model: combobox.delegateModel + currentIndex: combobox.highlightedIndex + ScrollBar.vertical: ScrollBar { + objectName: "vbar" + } + } + } + } + } +} diff --git a/tests/auto/quickcontrols/qquickpopup/tst_qquickpopup.cpp b/tests/auto/quickcontrols/qquickpopup/tst_qquickpopup.cpp index ecd5479931..8343cc4f3a 100644 --- a/tests/auto/quickcontrols/qquickpopup/tst_qquickpopup.cpp +++ b/tests/auto/quickcontrols/qquickpopup/tst_qquickpopup.cpp @@ -65,6 +65,7 @@ private slots: void wheel(); void parentDestroyed(); void nested(); + void nestedWheel(); void modelessOnModalOnModeless(); void grabber(); void cursorShape(); @@ -1012,16 +1013,23 @@ void tst_QQuickPopup::wheel_data() QTest::newRow("ApplicationWindow:modeless") << "applicationwindow-wheel.qml" << false; } -static bool sendWheelEvent(QQuickItem *item, const QPoint &localPos, int degrees) +static bool sendWheelEvent(QQuickItem *item, const QPointF &localPos, int degrees) { QQuickWindow *window = item->window(); - QWheelEvent wheelEvent(localPos, item->window()->mapToGlobal(localPos), QPoint(0, 0), + const QPoint scenePos = item->mapToScene(localPos).toPoint(); + QWheelEvent wheelEvent(scenePos, window->mapToGlobal(scenePos), QPoint(0, 0), QPoint(0, 8 * degrees), Qt::NoButton, Qt::NoModifier, Qt::NoScrollPhase, false); QSpontaneKeyEvent::setSpontaneous(&wheelEvent); return qGuiApp->notify(window, &wheelEvent); } +static bool sendWheelEvent(QQuickItem *item, int degrees) +{ + const QPointF localPos = QPointF(item->width() / 2, item->height() / 2); + return sendWheelEvent(item, localPos, degrees); +} + void tst_QQuickPopup::wheel() { QFETCH(QString, source); @@ -1052,7 +1060,7 @@ void tst_QQuickPopup::wheel() qreal oldContentValue = contentSlider->value(); qreal oldPopupValue = popupSlider->value(); - QVERIFY(sendWheelEvent(contentSlider, QPoint(contentSlider->width() / 2, contentSlider->height() / 2), 15)); + QVERIFY(sendWheelEvent(contentSlider, 15)); QVERIFY(!qFuzzyCompare(contentSlider->value(), oldContentValue)); // must have moved QVERIFY(qFuzzyCompare(popupSlider->value(), oldPopupValue)); // must not have moved @@ -1068,7 +1076,7 @@ void tst_QQuickPopup::wheel() qreal oldContentValue = contentSlider->value(); qreal oldPopupValue = popupSlider->value(); - QVERIFY(sendWheelEvent(popupSlider, QPoint(popupSlider->width() / 2, popupSlider->height() / 2), 15)); + QVERIFY(sendWheelEvent(popupSlider, 15)); QVERIFY(qFuzzyCompare(contentSlider->value(), oldContentValue)); // must not have moved QVERIFY(!qFuzzyCompare(popupSlider->value(), oldPopupValue)); // must have moved @@ -1084,7 +1092,7 @@ void tst_QQuickPopup::wheel() qreal oldContentValue = contentSlider->value(); qreal oldPopupValue = popupSlider->value(); - QVERIFY(sendWheelEvent(popupSlider, QPoint(popupSlider->width() / 2, popupSlider->height() / 2), 15)); + QVERIFY(sendWheelEvent(popupSlider, 15)); QVERIFY(qFuzzyCompare(contentSlider->value(), oldContentValue)); // must not have moved QCOMPARE(qFuzzyCompare(popupSlider->value(), oldPopupValue), modal); // must not have moved unless modeless @@ -1095,7 +1103,7 @@ void tst_QQuickPopup::wheel() qreal oldContentValue = contentSlider->value(); qreal oldPopupValue = popupSlider->value(); - QVERIFY(sendWheelEvent(QQuickOverlay::overlay(window), QPoint(0, 0), 15)); + QVERIFY(sendWheelEvent(QQuickOverlay::overlay(window), QPointF(0, 0), 15)); if (modal) { // the content below a modal overlay must not move @@ -1145,6 +1153,36 @@ void tst_QQuickPopup::nested() QCOMPARE(modalPopup->isVisible(), true); } +void tst_QQuickPopup::nestedWheel() +{ + QQuickControlsApplicationHelper helper(this, QStringLiteral("nested-wheel.qml")); + QVERIFY2(helper.ready, helper.failureMessage()); + QQuickWindow *window = helper.window; + window->show(); + QVERIFY(QTest::qWaitForWindowExposed(window)); + + QQuickPopup *modalPopup = window->property("modalPopup").value<QQuickPopup *>(); + QVERIFY(modalPopup); + + QQuickComboBox *comboBox = window->property("comboBox").value<QQuickComboBox *>(); + QVERIFY(comboBox); + + const QPoint comboBoxCenter = comboBox->mapToScene( + QPointF(comboBox->width() / 2, comboBox->height() / 2)).toPoint(); + QTest::mouseClick(window, Qt::LeftButton, Qt::NoModifier, comboBoxCenter); + QTRY_VERIFY(comboBox->popup()->isOpened()); + + QQuickItem *listView = comboBox->popup()->contentItem(); + QVERIFY(listView); + QQuickItem *vbar = listView->findChild<QQuickItem *>("vbar"); + QVERIFY(vbar); + + const double startPosition = vbar->property("position").toDouble(); + // wheel over the list view, verify that it scrolls + sendWheelEvent(listView, -30); + QTRY_COMPARE_GT(vbar->property("position").toDouble(), startPosition); +} + void tst_QQuickPopup::modelessOnModalOnModeless() { QQuickControlsApplicationHelper helper(this, QStringLiteral("modelessOnModalOnModeless.qml")); |