aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichal Policht <michpolicht@gmail.com>2017-09-01 19:56:39 +0200
committerJ-P Nurmi <jpnurmi@qt.io>2017-09-06 06:47:19 +0000
commit3512d1b617fb66f13a01e8763e395fcf69b0b5b7 (patch)
tree53f8988c11d36e391859212466e0c24d96f8ac2e
parent60eaf0f9432697416abdc758e003c9ac44962324 (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.cpp26
-rw-r--r--src/quicktemplates2/qquickdrawer_p_p.h1
-rw-r--r--tests/auto/drawer/tst_drawer.cpp83
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"