diff options
-rw-r--r-- | src/quicktemplates2/qquickoverlay.cpp | 76 | ||||
-rw-r--r-- | src/quicktemplates2/qquickoverlay_p.h | 1 | ||||
-rw-r--r-- | tests/auto/popup/tst_popup.cpp | 56 |
3 files changed, 111 insertions, 22 deletions
diff --git a/src/quicktemplates2/qquickoverlay.cpp b/src/quicktemplates2/qquickoverlay.cpp index 308eda86..60f2a36f 100644 --- a/src/quicktemplates2/qquickoverlay.cpp +++ b/src/quicktemplates2/qquickoverlay.cpp @@ -200,9 +200,6 @@ bool QQuickOverlayPrivate::startDrag(QEvent *event) bool QQuickOverlayPrivate::handlePress(QQuickItem *source, QEvent *event, QQuickPopup *target) { - Q_Q(QQuickOverlay); - emit q->pressed(); - if (target) { if (target->overlayEvent(source, event)) { setMouseGrabberPopup(target); @@ -234,9 +231,6 @@ bool QQuickOverlayPrivate::handleMove(QQuickItem *source, QEvent *event, QQuickP bool QQuickOverlayPrivate::handleRelease(QQuickItem *source, QEvent *event, QQuickPopup *target) { - Q_Q(QQuickOverlay); - emit q->released(); - if (target) { setMouseGrabberPopup(nullptr); if (target->overlayEvent(source, event)) { @@ -350,6 +344,10 @@ QQuickOverlay::QQuickOverlay(QQuickItem *parent) if (parent) { setSize(QSizeF(parent->width(), parent->height())); QQuickItemPrivate::get(parent)->addItemChangeListener(d, QQuickItemPrivate::Geometry); + parent->setAcceptedMouseButtons(Qt::AllButtons); + parent->installEventFilter(this); + if (QQuickWindow *window = parent->window()) + window->installEventFilter(this); } } @@ -535,4 +533,70 @@ bool QQuickOverlay::childMouseEventFilter(QQuickItem *item, QEvent *event) return false; } +bool QQuickOverlay::eventFilter(QObject *object, QEvent *event) +{ + Q_D(QQuickOverlay); + if (!isVisible() || !d->window) + return false; + + if (object == d->window) { + switch (event->type()) { + case QEvent::TouchBegin: + case QEvent::TouchUpdate: + case QEvent::TouchEnd: + if (static_cast<QTouchEvent *>(event)->touchPointStates() & Qt::TouchPointPressed) + emit pressed(); + if (static_cast<QTouchEvent *>(event)->touchPointStates() & Qt::TouchPointReleased) + emit released(); + + // allow non-modal popups to close on touch release outside + if (!d->mouseGrabberPopup) { + for (const QTouchEvent::TouchPoint &point : static_cast<QTouchEvent *>(event)->touchPoints()) { + if (point.state() == Qt::TouchPointReleased) { + if (d->handleRelease(d->window->contentItem(), event, nullptr)) + break; + } + } + } + break; + + case QEvent::MouseButtonPress: + // do not emit pressed() twice when mouse events have been synthesized from touch events + if (static_cast<QMouseEvent *>(event)->source() == Qt::MouseEventNotSynthesized) + emit pressed(); + break; + + case QEvent::MouseButtonRelease: + // do not emit released() twice when mouse events have been synthesized from touch events + if (static_cast<QMouseEvent *>(event)->source() == Qt::MouseEventNotSynthesized) + emit released(); + + // allow non-modal popups to close on mouse release outside + if (!d->mouseGrabberPopup) + d->handleRelease(d->window->contentItem(), event, nullptr); + break; + + default: + break; + } + } else if (object == d->window->contentItem()) { + // A touch or mouse press has reached the content item of the window, + // meaning that nothing at the press point was interested in touch or + // mouse events. Make sure to accept the press in order to receive the + // consequent move and release events to be able to close non-modal + // popups on release outside. + switch (event->type()) { + case QEvent::TouchBegin: + case QEvent::TouchUpdate: + case QEvent::MouseButtonPress: + event->accept(); + break; + default: + break; + } + } + + return false; +} + QT_END_NAMESPACE diff --git a/src/quicktemplates2/qquickoverlay_p.h b/src/quicktemplates2/qquickoverlay_p.h index 3a535b93..7d1ff143 100644 --- a/src/quicktemplates2/qquickoverlay_p.h +++ b/src/quicktemplates2/qquickoverlay_p.h @@ -92,6 +92,7 @@ protected: void wheelEvent(QWheelEvent *event) override; #endif bool childMouseEventFilter(QQuickItem *item, QEvent *event) override; + bool eventFilter(QObject *object, QEvent *event) override; private: Q_DISABLE_COPY(QQuickOverlay) diff --git a/tests/auto/popup/tst_popup.cpp b/tests/auto/popup/tst_popup.cpp index 0e9b55f7..686a5923 100644 --- a/tests/auto/popup/tst_popup.cpp +++ b/tests/auto/popup/tst_popup.cpp @@ -39,6 +39,7 @@ #include "../shared/util.h" #include "../shared/visualtestutil.h" +#include <QtGui/qpa/qwindowsysteminterface.h> #include <QtQuickTemplates2/private/qquickapplicationwindow_p.h> #include <QtQuickTemplates2/private/qquickoverlay_p.h> #include <QtQuickTemplates2/private/qquickpopup_p.h> @@ -207,17 +208,20 @@ void tst_popup::overlay() QQuickButton *button = window->property("button").value<QQuickButton*>(); QVERIFY(button); + int overlayPressCount = 0; + int overlayReleaseCount = 0; + popup->open(); QVERIFY(popup->isVisible()); QVERIFY(overlay->isVisible()); QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, QPoint(1, 1)); - QCOMPARE(overlayPressedSignal.count(), 1); - QCOMPARE(overlayReleasedSignal.count(), 0); + QCOMPARE(overlayPressedSignal.count(), ++overlayPressCount); + QCOMPARE(overlayReleasedSignal.count(), overlayReleaseCount); QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, QPoint(1, 1)); - QCOMPARE(overlayPressedSignal.count(), 1); - QCOMPARE(overlayReleasedSignal.count(), 0); // no modal-popups open + QCOMPARE(overlayPressedSignal.count(), overlayPressCount); + QCOMPARE(overlayReleasedSignal.count(), overlayReleaseCount); // no modal-popups open popup->close(); QVERIFY(!popup->isVisible()); @@ -227,28 +231,48 @@ void tst_popup::overlay() popup->setModal(modal); popup->setClosePolicy(QQuickPopup::CloseOnReleaseOutside); + // mouse popup->open(); QVERIFY(popup->isVisible()); QVERIFY(overlay->isVisible()); QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, QPoint(1, 1)); - QCOMPARE(overlayPressedSignal.count(), 2); - QCOMPARE(overlayReleasedSignal.count(), 0); + QCOMPARE(overlayPressedSignal.count(), ++overlayPressCount); + QCOMPARE(overlayReleasedSignal.count(), overlayReleaseCount); QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, QPoint(1, 1)); - QCOMPARE(overlayPressedSignal.count(), 2); + QCOMPARE(overlayPressedSignal.count(), overlayPressCount); + QCOMPARE(overlayReleasedSignal.count(), ++overlayReleaseCount); + + QVERIFY(!popup->isVisible()); + QCOMPARE(overlay->isVisible(), popup->isVisible()); + + // touch + popup->open(); + QVERIFY(popup->isVisible()); + QVERIFY(overlay->isVisible()); + + struct TouchDeviceDeleter + { + static inline void cleanup(QTouchDevice *device) + { + QWindowSystemInterface::unregisterTouchDevice(device); + delete device; + } + }; + + QScopedPointer<QTouchDevice, TouchDeviceDeleter> device(new QTouchDevice); + device->setType(QTouchDevice::TouchScreen); + QWindowSystemInterface::registerTouchDevice(device.data()); - #define comment "Non-modal popups do not yet support CloseOnReleaseXxx" - #define QEXPECT_NON_MODAL_POPUP_FAILS() \ - QEXPECT_FAIL("Window", comment, Continue); \ - QEXPECT_FAIL("Window,dim", comment, Continue); \ - QEXPECT_FAIL("ApplicationWindow", comment, Continue); \ - QEXPECT_FAIL("ApplicationWindow,dim", comment, Continue); + QTest::touchEvent(window, device.data()).press(0, QPoint(1, 1)); + QCOMPARE(overlayPressedSignal.count(), ++overlayPressCount); + QCOMPARE(overlayReleasedSignal.count(), overlayReleaseCount); - QEXPECT_NON_MODAL_POPUP_FAILS() - QCOMPARE(overlayReleasedSignal.count(), 1); + QTest::touchEvent(window, device.data()).release(0, QPoint(1, 1)); + QCOMPARE(overlayPressedSignal.count(), overlayPressCount); + QCOMPARE(overlayReleasedSignal.count(), ++overlayReleaseCount); - QEXPECT_NON_MODAL_POPUP_FAILS() QVERIFY(!popup->isVisible()); QCOMPARE(overlay->isVisible(), popup->isVisible()); } |