diff options
author | Michal Policht <michpolicht@gmail.com> | 2017-09-01 19:56:39 +0200 |
---|---|---|
committer | J-P Nurmi <jpnurmi@qt.io> | 2017-09-06 06:47:19 +0000 |
commit | 3512d1b617fb66f13a01e8763e395fcf69b0b5b7 (patch) | |
tree | 53f8988c11d36e391859212466e0c24d96f8ac2e | |
parent | 60eaf0f9432697416abdc758e003c9ac44962324 (diff) |
Fix non-modal drawer drag/swipe open and close
Function QQuickPopupPrivate::blockInput() has been overridden in
QQuickDrawerPrivate to accept events that occur while mouse/touch is
grabbed and events within drag area.
Task-number: QTBUG-59652
Change-Id: Icf4129e702a351b266ea9c4544830185c315fc37
Reviewed-by: J-P Nurmi <jpnurmi@qt.io>
-rw-r--r-- | src/quicktemplates2/qquickdrawer.cpp | 26 | ||||
-rw-r--r-- | src/quicktemplates2/qquickdrawer_p_p.h | 1 | ||||
-rw-r--r-- | tests/auto/drawer/tst_drawer.cpp | 83 |
3 files changed, 109 insertions, 1 deletions
diff --git a/src/quicktemplates2/qquickdrawer.cpp b/src/quicktemplates2/qquickdrawer.cpp index c63d40d1..6ccac70c 100644 --- a/src/quicktemplates2/qquickdrawer.cpp +++ b/src/quicktemplates2/qquickdrawer.cpp @@ -246,7 +246,7 @@ void QQuickDrawerPrivate::resizeOverlay() dimmer->setSize(geometry.size()); } -static bool isWithinDragMargin(QQuickDrawer *drawer, const QPointF &pos) +static bool isWithinDragMargin(const QQuickDrawer *drawer, const QPointF &pos) { switch (drawer->edge()) { case Qt::LeftEdge: @@ -393,6 +393,30 @@ bool QQuickDrawerPrivate::grabTouch(QQuickItem *item, QTouchEvent *event) static const qreal openCloseVelocityThreshold = 300; +bool QQuickDrawerPrivate::blockInput(QQuickItem *item, const QPointF &point) const +{ + Q_Q(const QQuickDrawer); + + // We want all events, if mouse/touch is already grabbed. + if (popupItem->keepMouseGrab() || popupItem->keepTouchGrab()) + return true; + + // Don't block input to drawer's children/content. + if (popupItem->isAncestorOf(item)) + return false; + + // Don't block outside a drawer's background dimming + if (dimmer && !dimmer->contains(dimmer->mapFromScene(point))) + return false; + + // Accept all events within drag area. + if (isWithinDragMargin(q, point)) + return true; + + // Accept all other events if drawer is modal. + return modal; +} + bool QQuickDrawerPrivate::handlePress(QQuickItem *item, const QPointF &point, ulong timestamp) { offset = 0; diff --git a/src/quicktemplates2/qquickdrawer_p_p.h b/src/quicktemplates2/qquickdrawer_p_p.h index 6ed62cf5..aff6e81e 100644 --- a/src/quicktemplates2/qquickdrawer_p_p.h +++ b/src/quicktemplates2/qquickdrawer_p_p.h @@ -77,6 +77,7 @@ public: #if QT_CONFIG(quicktemplates2_multitouch) bool grabTouch(QQuickItem *item, QTouchEvent *event); #endif + bool blockInput(QQuickItem *item, const QPointF &point) const override; bool handlePress(QQuickItem* item, const QPointF &point, ulong timestamp) override; bool handleMove(QQuickItem* item, const QPointF &point, ulong timestamp) override; diff --git a/tests/auto/drawer/tst_drawer.cpp b/tests/auto/drawer/tst_drawer.cpp index d316e08f..0bfb3fc9 100644 --- a/tests/auto/drawer/tst_drawer.cpp +++ b/tests/auto/drawer/tst_drawer.cpp @@ -99,6 +99,9 @@ private slots: void dragOverModalShadow_data(); void dragOverModalShadow(); + void nonModal_data(); + void nonModal(); + private: struct TouchDeviceDeleter { @@ -1136,6 +1139,86 @@ void tst_Drawer::dragOverModalShadow() QVERIFY(!drawer->isVisible()); } +void tst_Drawer::nonModal_data() +{ + QTest::addColumn<bool>("mouse"); + QTest::newRow("mouse") << true; + QTest::newRow("touch") << false; +} + +// QTBUG-59652 +void tst_Drawer::nonModal() +{ + QFETCH(bool, mouse); + + QQuickApplicationHelper helper(this, QStringLiteral("window.qml")); + QQuickWindow *window = helper.window; + window->show(); + QVERIFY(QTest::qWaitForWindowActive(window)); + + QQuickDrawer *drawer = window->property("drawer").value<QQuickDrawer *>(); + QVERIFY(drawer); + drawer->setModal(false); + + const QPoint from(1, 1); + const QPoint to(150, 1); + + // drag to open + QSignalSpy openedSpy(drawer, SIGNAL(opened())); + QVERIFY(openedSpy.isValid()); + + if (mouse) + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, from); + else + QTest::touchEvent(window, touchDevice.data()).press(0, from); + + static const int steps = 10; + for (int i = 0; i < steps; ++i) { + int x = i * qAbs(from.x() - to.x()) / steps; + int y = i * qAbs(from.y() - to.y()) / steps; + + if (mouse) + QTest::mouseMove(window, QPoint(x, y)); + else + QTest::touchEvent(window, touchDevice.data()).move(0, QPoint(x, y)); + QTest::qWait(1); // avoid infinite velocity + } + QVERIFY(drawer->isVisible()); + + if (mouse) + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, to); + else + QTest::touchEvent(window, touchDevice.data()).release(0, to); + QVERIFY(openedSpy.wait()); + + // drag to close + QSignalSpy closedSpy(drawer, SIGNAL(closed())); + QVERIFY(closedSpy.isValid()); + + if (mouse) + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, to); + else + QTest::touchEvent(window, touchDevice.data()).press(0, to); + + for (int i = steps - 1; i >= 0; --i) { + int x = i * qAbs(from.x() - to.x()) / steps; + int y = i * qAbs(from.y() - to.y()) / steps; + + if (mouse) + QTest::mouseMove(window, QPoint(x, y)); + else + QTest::touchEvent(window, touchDevice.data()).move(0, QPoint(x, y)); + QTest::qWait(1); // avoid infinite velocity + } + QVERIFY(drawer->isVisible()); + + if (mouse) + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, from); + else + QTest::touchEvent(window, touchDevice.data()).release(0, from); + QVERIFY(closedSpy.wait()); +} + QTEST_MAIN(tst_Drawer) #include "tst_drawer.moc" |