| /**************************************************************************** |
| ** |
| ** Copyright (C) 2016 The Qt Company Ltd. |
| ** Contact: https://www.qt.io/licensing/ |
| ** |
| ** This file is part of the QtQml module of the Qt Toolkit. |
| ** |
| ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ |
| ** Commercial License Usage |
| ** Licensees holding valid commercial Qt licenses may use this file in |
| ** accordance with the commercial license agreement provided with the |
| ** Software or, alternatively, in accordance with the terms contained in |
| ** a written agreement between you and The Qt Company. For licensing terms |
| ** and conditions see https://www.qt.io/terms-conditions. For further |
| ** information use the contact form at https://www.qt.io/contact-us. |
| ** |
| ** GNU General Public License Usage |
| ** Alternatively, this file may be used under the terms of the GNU |
| ** General Public License version 3 as published by the Free Software |
| ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT |
| ** included in the packaging of this file. Please review the following |
| ** information to ensure the GNU General Public License requirements will |
| ** be met: https://www.gnu.org/licenses/gpl-3.0.html. |
| ** |
| ** $QT_END_LICENSE$ |
| ** |
| ****************************************************************************/ |
| |
| |
| #include <QtTest/QtTest> |
| #include <QDebug> |
| |
| #include <QtGui/qstylehints.h> |
| #include <private/qdebug_p.h> |
| |
| #include <QtQuick/qquickview.h> |
| #include <QtQuick/qquickitem.h> |
| #include <QtQuick/private/qquickevents_p_p.h> |
| #include <QtQuick/private/qquickmousearea_p.h> |
| #include <QtQuick/private/qquickmultipointtoucharea_p.h> |
| #include <QtQuick/private/qquickpincharea_p.h> |
| #include <QtQuick/private/qquickflickable_p.h> |
| #include <QtQuick/private/qquickwindow_p.h> |
| |
| #include <QtQml/qqmlengine.h> |
| #include <QtQml/qqmlproperty.h> |
| |
| #include "../../shared/util.h" |
| #include "../shared/viewtestutil.h" |
| |
| Q_LOGGING_CATEGORY(lcTests, "qt.quick.tests") |
| |
| struct Event |
| { |
| Event(QEvent::Type t, QPoint mouse, QPoint global) |
| :type(t), mousePos(mouse), mousePosGlobal(global) |
| {} |
| |
| Event(QEvent::Type t, QList<QTouchEvent::TouchPoint> touch) |
| :type(t), points(touch) |
| {} |
| |
| QEvent::Type type; |
| QPoint mousePos; |
| QPoint mousePosGlobal; |
| QList<QTouchEvent::TouchPoint> points; |
| }; |
| |
| #ifndef QT_NO_DEBUG_STREAM |
| QDebug operator<<(QDebug dbg, const struct Event &event) { |
| QDebugStateSaver saver(dbg); |
| dbg.nospace(); |
| dbg << "Event("; |
| QtDebugUtils::formatQEnum(dbg, event.type); |
| if (event.points.isEmpty()) |
| dbg << " @ " << event.mousePos << " global " << event.mousePosGlobal; |
| else |
| dbg << ", " << event.points.count() << " touchpoints: " << event.points; |
| dbg << ')'; |
| return dbg; |
| } |
| #endif |
| |
| class EventItem : public QQuickItem |
| { |
| Q_OBJECT |
| |
| Q_SIGNALS: |
| void onTouchEvent(QQuickItem *receiver); |
| |
| public: |
| EventItem(QQuickItem *parent = nullptr) |
| : QQuickItem(parent) |
| { |
| setAcceptedMouseButtons(Qt::LeftButton); |
| #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) |
| setAcceptTouchEvents(true); |
| #endif |
| } |
| |
| void touchEvent(QTouchEvent *event) |
| { |
| eventList.append(Event(event->type(), event->touchPoints())); |
| QList<QTouchEvent::TouchPoint> tps = event->touchPoints(); |
| Q_ASSERT(!tps.isEmpty()); |
| point0 = tps.first().id(); |
| event->setAccepted(acceptTouch); |
| emit onTouchEvent(this); |
| } |
| void mousePressEvent(QMouseEvent *event) |
| { |
| eventList.append(Event(event->type(), event->pos(), event->globalPos())); |
| event->setAccepted(acceptMouse); |
| } |
| void mouseMoveEvent(QMouseEvent *event) |
| { |
| eventList.append(Event(event->type(), event->pos(), event->globalPos())); |
| event->setAccepted(acceptMouse); |
| } |
| void mouseReleaseEvent(QMouseEvent *event) |
| { |
| eventList.append(Event(event->type(), event->pos(), event->globalPos())); |
| event->setAccepted(acceptMouse); |
| } |
| void mouseDoubleClickEvent(QMouseEvent *event) |
| { |
| eventList.append(Event(event->type(), event->pos(), event->globalPos())); |
| event->setAccepted(acceptMouse); |
| } |
| |
| void mouseUngrabEvent() |
| { |
| eventList.append(Event(QEvent::UngrabMouse, QPoint(0,0), QPoint(0,0))); |
| } |
| |
| void touchUngrabEvent() |
| { |
| ++touchUngrabCount; |
| } |
| |
| bool event(QEvent *event) { |
| return QQuickItem::event(event); |
| } |
| |
| QList<Event> eventList; |
| int touchUngrabCount = 0; |
| bool acceptMouse = false; |
| bool acceptTouch = false; |
| bool filterTouch = false; // when used as event filter |
| |
| bool eventFilter(QObject *, QEvent *event) |
| { |
| if (event->type() == QEvent::TouchBegin || |
| event->type() == QEvent::TouchUpdate || |
| event->type() == QEvent::TouchCancel || |
| event->type() == QEvent::TouchEnd) { |
| QTouchEvent *touch = static_cast<QTouchEvent*>(event); |
| eventList.append(Event(event->type(), touch->touchPoints())); |
| QList<QTouchEvent::TouchPoint> tps = touch->touchPoints(); |
| Q_ASSERT(!tps.isEmpty()); |
| point0 = tps.first().id(); |
| if (filterTouch) |
| event->accept(); |
| return true; |
| } |
| return false; |
| } |
| int point0 = -1; |
| }; |
| |
| class tst_TouchMouse : public QQmlDataTest |
| { |
| Q_OBJECT |
| public: |
| tst_TouchMouse() |
| :device(QTest::createTouchDevice()) |
| {} |
| |
| private slots: |
| void initTestCase(); |
| |
| void simpleTouchEvent_data(); |
| void simpleTouchEvent(); |
| void testEventFilter(); |
| void mouse(); |
| void touchOverMouse(); |
| void mouseOverTouch(); |
| |
| void buttonOnFlickable(); |
| void touchButtonOnFlickable(); |
| void buttonOnDelayedPressFlickable_data(); |
| void buttonOnDelayedPressFlickable(); |
| void buttonOnTouch(); |
| |
| void pinchOnFlickable(); |
| void flickableOnPinch(); |
| void mouseOnFlickableOnPinch(); |
| |
| void tapOnDismissiveTopMouseAreaClicksBottomOne(); |
| |
| void touchGrabCausesMouseUngrab(); |
| void touchPointDeliveryOrder(); |
| |
| void hoverEnabled(); |
| void implicitUngrab(); |
| |
| protected: |
| bool eventFilter(QObject *, QEvent *event) |
| { |
| if (event->type() == QEvent::MouseButtonPress || |
| event->type() == QEvent::MouseMove || |
| event->type() == QEvent::MouseButtonRelease) { |
| QMouseEvent *me = static_cast<QMouseEvent*>(event); |
| filteredEventList.append(Event(me->type(), me->pos(), me->globalPos())); |
| } |
| return false; |
| } |
| |
| private: |
| QQuickView *createView(); |
| QTouchDevice *device; |
| QList<Event> filteredEventList; |
| }; |
| |
| QQuickView *tst_TouchMouse::createView() |
| { |
| QQuickView *window = new QQuickView(nullptr); |
| return window; |
| } |
| |
| void tst_TouchMouse::initTestCase() |
| { |
| QQmlDataTest::initTestCase(); |
| qmlRegisterType<EventItem>("Qt.test", 1, 0, "EventItem"); |
| } |
| |
| void tst_TouchMouse::simpleTouchEvent_data() |
| { |
| QTest::addColumn<bool>("synthMouse"); // AA_SynthesizeMouseForUnhandledTouchEvents |
| QTest::newRow("no synth") << false; |
| QTest::newRow("synth") << true; |
| } |
| |
| void tst_TouchMouse::simpleTouchEvent() |
| { |
| QFETCH(bool, synthMouse); |
| qApp->setAttribute(Qt::AA_SynthesizeMouseForUnhandledTouchEvents, synthMouse); |
| |
| QScopedPointer<QQuickView> window(createView()); |
| window->setSource(testFileUrl("singleitem.qml")); |
| window->show(); |
| QQuickViewTestUtil::centerOnScreen(window.data()); |
| QVERIFY(QTest::qWaitForWindowActive(window.data())); |
| QVERIFY(window->rootObject() != nullptr); |
| |
| EventItem *eventItem1 = window->rootObject()->findChild<EventItem*>("eventItem1"); |
| QVERIFY(eventItem1); |
| |
| // Do not accept touch or mouse |
| QPoint p1; |
| p1 = QPoint(20, 20); |
| QTest::touchEvent(window.data(), device).press(0, p1, window.data()); |
| QQuickTouchUtils::flush(window.data()); |
| // Get a touch and then mouse event offered |
| QCOMPARE(eventItem1->eventList.size(), synthMouse ? 2 : 1); |
| QCOMPARE(eventItem1->eventList.at(0).type, QEvent::TouchBegin); |
| p1 += QPoint(10, 0); |
| QTest::touchEvent(window.data(), device).move(0, p1, window.data()); |
| QQuickTouchUtils::flush(window.data()); |
| // Not accepted, no updates |
| QCOMPARE(eventItem1->eventList.size(), synthMouse ? 2 : 1); |
| QTest::touchEvent(window.data(), device).release(0, p1, window.data()); |
| QQuickTouchUtils::flush(window.data()); |
| QCOMPARE(eventItem1->eventList.size(), synthMouse ? 2 : 1); |
| eventItem1->eventList.clear(); |
| |
| // Accept touch |
| eventItem1->acceptTouch = true; |
| p1 = QPoint(20, 20); |
| QTest::touchEvent(window.data(), device).press(0, p1, window.data()); |
| QQuickTouchUtils::flush(window.data()); |
| QCOMPARE(eventItem1->eventList.size(), 1); |
| p1 += QPoint(10, 0); |
| QTest::touchEvent(window.data(), device).move(0, p1, window.data()); |
| QQuickTouchUtils::flush(window.data()); |
| QCOMPARE(eventItem1->eventList.size(), 2); |
| QTest::touchEvent(window.data(), device).release(0, p1, window.data()); |
| QQuickTouchUtils::flush(window.data()); |
| QCOMPARE(eventItem1->eventList.size(), 3); |
| eventItem1->eventList.clear(); |
| |
| // wait to avoid getting a double click event |
| QTest::qWait(qApp->styleHints()->mouseDoubleClickInterval() + 10); |
| |
| // Accept mouse |
| eventItem1->acceptTouch = false; |
| eventItem1->acceptMouse = true; |
| eventItem1->setAcceptedMouseButtons(Qt::LeftButton); |
| p1 = QPoint(20, 20); |
| QTest::touchEvent(window.data(), device).press(0, p1, window.data()); |
| QQuickTouchUtils::flush(window.data()); |
| QCOMPARE(eventItem1->eventList.size(), synthMouse ? 2 : 1); |
| QCOMPARE(eventItem1->eventList.at(0).type, QEvent::TouchBegin); |
| if (synthMouse) |
| QCOMPARE(eventItem1->eventList.at(1).type, QEvent::MouseButtonPress); |
| QCOMPARE(window->mouseGrabberItem(), synthMouse ? eventItem1 : nullptr); |
| |
| QPoint localPos = eventItem1->mapFromScene(p1).toPoint(); |
| QPoint globalPos = window->mapToGlobal(p1); |
| QPoint scenePos = p1; // item is at 0,0 |
| QCOMPARE(eventItem1->eventList.at(0).points.at(0).pos().toPoint(), localPos); |
| QCOMPARE(eventItem1->eventList.at(0).points.at(0).scenePos().toPoint(), scenePos); |
| QCOMPARE(eventItem1->eventList.at(0).points.at(0).screenPos().toPoint(), globalPos); |
| if (synthMouse) { |
| QCOMPARE(eventItem1->eventList.at(1).mousePos, localPos); |
| QCOMPARE(eventItem1->eventList.at(1).mousePosGlobal, globalPos); |
| } |
| |
| p1 += QPoint(10, 0); |
| QTest::touchEvent(window.data(), device).move(0, p1, window.data()); |
| QQuickTouchUtils::flush(window.data()); |
| QCOMPARE(eventItem1->eventList.size(), synthMouse ? 4 : 1); |
| if (synthMouse) { |
| QCOMPARE(eventItem1->eventList.at(2).type, QEvent::TouchUpdate); |
| QCOMPARE(eventItem1->eventList.at(3).type, QEvent::MouseMove); |
| } |
| // else, if there was no synth-mouse and we didn't accept the touch, |
| // TouchUpdate was not sent to eventItem1 either. |
| QTest::touchEvent(window.data(), device).release(0, p1, window.data()); |
| QQuickTouchUtils::flush(window.data()); |
| QCOMPARE(eventItem1->eventList.size(), synthMouse ? 7 : 1); |
| if (synthMouse) { |
| QCOMPARE(eventItem1->eventList.at(4).type, QEvent::TouchEnd); |
| QCOMPARE(eventItem1->eventList.at(5).type, QEvent::MouseButtonRelease); |
| QCOMPARE(eventItem1->eventList.at(6).type, QEvent::UngrabMouse); |
| } |
| // else, if there was no synth-mouse and we didn't accept the touch, |
| // TouchEnd was not sent to eventItem1 either. |
| eventItem1->eventList.clear(); |
| |
| // wait to avoid getting a double click event |
| QTest::qWait(qApp->styleHints()->mouseDoubleClickInterval() + 10); |
| |
| // Accept mouse buttons but not the event |
| eventItem1->acceptTouch = false; |
| eventItem1->acceptMouse = false; |
| eventItem1->setAcceptedMouseButtons(Qt::LeftButton); |
| p1 = QPoint(20, 20); |
| QTest::touchEvent(window.data(), device).press(0, p1, window.data()); |
| QQuickTouchUtils::flush(window.data()); |
| QCOMPARE(eventItem1->eventList.size(), synthMouse ? 2 : 1); |
| QCOMPARE(eventItem1->eventList.at(0).type, QEvent::TouchBegin); |
| if (synthMouse) |
| QCOMPARE(eventItem1->eventList.at(1).type, QEvent::MouseButtonPress); |
| p1 += QPoint(10, 0); |
| QTest::touchEvent(window.data(), device).move(0, p1, window.data()); |
| QQuickTouchUtils::flush(window.data()); |
| QCOMPARE(eventItem1->eventList.size(), synthMouse ? 2 : 1); |
| QTest::touchEvent(window.data(), device).release(0, p1, window.data()); |
| QQuickTouchUtils::flush(window.data()); |
| QCOMPARE(eventItem1->eventList.size(), synthMouse ? 2 : 1); |
| eventItem1->eventList.clear(); |
| |
| // wait to avoid getting a double click event |
| QTest::qWait(qApp->styleHints()->mouseDoubleClickInterval() + 10); |
| |
| // Accept touch and mouse |
| eventItem1->acceptTouch = true; |
| eventItem1->setAcceptedMouseButtons(Qt::LeftButton); |
| p1 = QPoint(20, 20); |
| QTest::touchEvent(window.data(), device).press(0, p1, window.data()); |
| QQuickTouchUtils::flush(window.data()); |
| QCOMPARE(eventItem1->eventList.size(), 1); |
| QCOMPARE(eventItem1->eventList.at(0).type, QEvent::TouchBegin); |
| p1 += QPoint(10, 0); |
| QTest::touchEvent(window.data(), device).move(0, p1, window.data()); |
| QQuickTouchUtils::flush(window.data()); |
| QCOMPARE(eventItem1->eventList.size(), 2); |
| QCOMPARE(eventItem1->eventList.at(1).type, QEvent::TouchUpdate); |
| QTest::touchEvent(window.data(), device).release(0, p1, window.data()); |
| QQuickTouchUtils::flush(window.data()); |
| QCOMPARE(eventItem1->eventList.size(), 3); |
| QCOMPARE(eventItem1->eventList.at(2).type, QEvent::TouchEnd); |
| eventItem1->eventList.clear(); |
| } |
| |
| void tst_TouchMouse::testEventFilter() |
| { |
| // // install event filter on item and see that it can grab events |
| // QScopedPointer<QQuickView> window(createView()); |
| // window->setSource(testFileUrl("singleitem.qml")); |
| // window->show(); |
| // QQuickViewTestUtil::centerOnScreen(window.data()); |
| // QVERIFY(QTest::qWaitForWindowActive(window.data())); |
| // QVERIFY(window->rootObject() != 0); |
| |
| // EventItem *eventItem1 = window->rootObject()->findChild<EventItem*>("eventItem1"); |
| // QVERIFY(eventItem1); |
| // eventItem1->acceptTouch = true; |
| |
| // EventItem *filter = new EventItem; |
| // filter->filterTouch = true; |
| // eventItem1->installEventFilter(filter); |
| |
| // QPoint p1 = QPoint(20, 20); |
| // QTest::touchEvent(window.data(), device).press(0, p1, window.data()); |
| // // QEXPECT_FAIL("", "We do not implement event filters correctly", Abort); |
| // QCOMPARE(eventItem1->eventList.size(), 0); |
| // QCOMPARE(filter->eventList.size(), 1); |
| // QTest::touchEvent(window.data(), device).release(0, p1, window.data()); |
| // QCOMPARE(eventItem1->eventList.size(), 0); |
| // QCOMPARE(filter->eventList.size(), 2); |
| |
| // delete filter; |
| } |
| |
| void tst_TouchMouse::mouse() |
| { |
| // eventItem1 |
| // - eventItem2 |
| |
| QTest::qWait(qApp->styleHints()->mouseDoubleClickInterval() + 10); |
| QScopedPointer<QQuickView> window(createView()); |
| window->setSource(testFileUrl("twoitems.qml")); |
| window->show(); |
| QQuickViewTestUtil::centerOnScreen(window.data()); |
| QVERIFY(QTest::qWaitForWindowActive(window.data())); |
| QVERIFY(window->rootObject() != nullptr); |
| |
| EventItem *eventItem1 = window->rootObject()->findChild<EventItem*>("eventItem1"); |
| QVERIFY(eventItem1); |
| EventItem *eventItem2 = window->rootObject()->findChild<EventItem*>("eventItem2"); |
| QVERIFY(eventItem2); |
| |
| // bottom item likes mouse, top likes touch |
| eventItem1->setAcceptedMouseButtons(Qt::LeftButton); |
| eventItem1->acceptMouse = true; |
| // item 2 doesn't accept anything, thus it sees a touch pass by |
| QPoint p1 = QPoint(30, 30); |
| QTest::touchEvent(window.data(), device).press(0, p1, window.data()); |
| QQuickTouchUtils::flush(window.data()); |
| |
| QCOMPARE(eventItem1->eventList.size(), 2); |
| QCOMPARE(eventItem1->eventList.at(0).type, QEvent::TouchBegin); |
| QCOMPARE(eventItem1->eventList.at(1).type, QEvent::MouseButtonPress); |
| } |
| |
| void tst_TouchMouse::touchOverMouse() |
| { |
| // eventItem1 |
| // - eventItem2 |
| |
| QScopedPointer<QQuickView> window(createView()); |
| window->setSource(testFileUrl("twoitems.qml")); |
| window->show(); |
| QQuickViewTestUtil::centerOnScreen(window.data()); |
| QVERIFY(QTest::qWaitForWindowActive(window.data())); |
| QVERIFY(window->rootObject() != nullptr); |
| |
| EventItem *eventItem1 = window->rootObject()->findChild<EventItem*>("eventItem1"); |
| QVERIFY(eventItem1); |
| EventItem *eventItem2 = window->rootObject()->findChild<EventItem*>("eventItem2"); |
| QVERIFY(eventItem2); |
| |
| // bottom item likes mouse, top likes touch |
| eventItem1->setAcceptedMouseButtons(Qt::LeftButton); |
| eventItem2->acceptTouch = true; |
| |
| QCOMPARE(eventItem1->eventList.size(), 0); |
| QPoint p1 = QPoint(20, 20); |
| QTest::touchEvent(window.data(), device).press(0, p1, window.data()); |
| QQuickTouchUtils::flush(window.data()); |
| QCOMPARE(eventItem1->eventList.size(), 0); |
| QCOMPARE(eventItem2->eventList.size(), 1); |
| QCOMPARE(eventItem2->eventList.at(0).type, QEvent::TouchBegin); |
| p1 += QPoint(10, 0); |
| QTest::touchEvent(window.data(), device).move(0, p1, window.data()); |
| QQuickTouchUtils::flush(window.data()); |
| QCOMPARE(eventItem2->eventList.size(), 2); |
| QCOMPARE(eventItem2->eventList.at(1).type, QEvent::TouchUpdate); |
| QTest::touchEvent(window.data(), device).release(0, p1, window.data()); |
| QQuickTouchUtils::flush(window.data()); |
| QCOMPARE(eventItem2->eventList.size(), 3); |
| QCOMPARE(eventItem2->eventList.at(2).type, QEvent::TouchEnd); |
| eventItem2->eventList.clear(); |
| } |
| |
| void tst_TouchMouse::mouseOverTouch() |
| { |
| // eventItem1 |
| // - eventItem2 |
| |
| QScopedPointer<QQuickView> window(createView()); |
| window->setSource(testFileUrl("twoitems.qml")); |
| window->show(); |
| QQuickViewTestUtil::centerOnScreen(window.data()); |
| QVERIFY(QTest::qWaitForWindowActive(window.data())); |
| QVERIFY(window->rootObject() != nullptr); |
| |
| EventItem *eventItem1 = window->rootObject()->findChild<EventItem*>("eventItem1"); |
| QVERIFY(eventItem1); |
| EventItem *eventItem2 = window->rootObject()->findChild<EventItem*>("eventItem2"); |
| QVERIFY(eventItem2); |
| |
| // bottom item likes mouse, top likes touch |
| eventItem1->acceptTouch = true; |
| eventItem2->setAcceptedMouseButtons(Qt::LeftButton); |
| eventItem2->acceptMouse = true; |
| |
| QPoint p1 = QPoint(20, 20); |
| QTest::qWait(qApp->styleHints()->mouseDoubleClickInterval() + 10); |
| QTest::touchEvent(window.data(), device).press(0, p1, window.data()); |
| QQuickTouchUtils::flush(window.data()); |
| QCOMPARE(eventItem1->eventList.size(), 0); |
| QCOMPARE(eventItem2->eventList.size(), 2); |
| QCOMPARE(eventItem2->eventList.at(0).type, QEvent::TouchBegin); |
| QCOMPARE(eventItem2->eventList.at(1).type, QEvent::MouseButtonPress); |
| |
| |
| // p1 += QPoint(10, 0); |
| // QTest::touchEvent(window.data(), device).move(0, p1, window.data()); |
| // QCOMPARE(eventItem2->eventList.size(), 1); |
| // QTest::touchEvent(window.data(), device).release(0, p1, window.data()); |
| // QCOMPARE(eventItem2->eventList.size(), 1); |
| // eventItem2->eventList.clear(); |
| } |
| |
| void tst_TouchMouse::buttonOnFlickable() |
| { |
| // flickable - height 500 / 1000 |
| // - eventItem1 y: 100, height 100 |
| // - eventItem2 y: 300, height 100 |
| |
| QScopedPointer<QQuickView> window(createView()); |
| window->setSource(testFileUrl("buttononflickable.qml")); |
| window->show(); |
| QQuickViewTestUtil::centerOnScreen(window.data()); |
| QVERIFY(QTest::qWaitForWindowActive(window.data())); |
| QVERIFY(window->rootObject() != nullptr); |
| |
| QQuickFlickable *flickable = window->rootObject()->findChild<QQuickFlickable*>("flickable"); |
| QVERIFY(flickable); |
| |
| // should a mouse area button be clickable on top of flickable? yes :) |
| EventItem *eventItem1 = window->rootObject()->findChild<EventItem*>("eventItem1"); |
| QVERIFY(eventItem1); |
| eventItem1->setAcceptedMouseButtons(Qt::LeftButton); |
| eventItem1->acceptMouse = true; |
| |
| // should a touch button be touchable on top of flickable? yes :) |
| EventItem *eventItem2 = window->rootObject()->findChild<EventItem*>("eventItem2"); |
| QVERIFY(eventItem2); |
| QCOMPARE(eventItem2->eventList.size(), 0); |
| eventItem2->acceptTouch = true; |
| |
| // wait to avoid getting a double click event |
| QTest::qWait(qApp->styleHints()->mouseDoubleClickInterval() + 10); |
| |
| // check that buttons are clickable |
| // mouse button |
| QCOMPARE(eventItem1->eventList.size(), 0); |
| QPoint p1 = QPoint(20, 130); |
| QTest::touchEvent(window.data(), device).press(0, p1, window.data()); |
| QQuickTouchUtils::flush(window.data()); |
| QTRY_COMPARE(eventItem1->eventList.size(), 2); |
| QCOMPARE(eventItem1->eventList.at(0).type, QEvent::TouchBegin); |
| QCOMPARE(eventItem1->eventList.at(1).type, QEvent::MouseButtonPress); |
| QTest::touchEvent(window.data(), device).release(0, p1, window.data()); |
| QQuickTouchUtils::flush(window.data()); |
| QCOMPARE(eventItem1->eventList.size(), 5); |
| QCOMPARE(eventItem1->eventList.at(2).type, QEvent::TouchEnd); |
| QCOMPARE(eventItem1->eventList.at(3).type, QEvent::MouseButtonRelease); |
| QCOMPARE(eventItem1->eventList.at(4).type, QEvent::UngrabMouse); |
| eventItem1->eventList.clear(); |
| |
| // touch button |
| p1 = QPoint(10, 310); |
| QTest::touchEvent(window.data(), device).press(0, p1, window.data()); |
| QQuickTouchUtils::flush(window.data()); |
| QCOMPARE(eventItem2->eventList.size(), 1); |
| QCOMPARE(eventItem2->eventList.at(0).type, QEvent::TouchBegin); |
| QTest::touchEvent(window.data(), device).release(0, p1, window.data()); |
| QQuickTouchUtils::flush(window.data()); |
| QCOMPARE(eventItem2->eventList.size(), 2); |
| QCOMPARE(eventItem2->eventList.at(1).type, QEvent::TouchEnd); |
| QCOMPARE(eventItem1->eventList.size(), 0); |
| eventItem2->eventList.clear(); |
| |
| // wait to avoid getting a double click event |
| QTest::qWait(qApp->styleHints()->mouseDoubleClickInterval() + 10); |
| |
| // click above button, no events please |
| p1 = QPoint(10, 90); |
| QTest::touchEvent(window.data(), device).press(0, p1, window.data()); |
| QQuickTouchUtils::flush(window.data()); |
| QCOMPARE(eventItem1->eventList.size(), 0); |
| QTest::touchEvent(window.data(), device).release(0, p1, window.data()); |
| QQuickTouchUtils::flush(window.data()); |
| QCOMPARE(eventItem1->eventList.size(), 0); |
| eventItem1->eventList.clear(); |
| |
| // wait to avoid getting a double click event |
| QTest::qWait(qApp->styleHints()->mouseDoubleClickInterval() + 10); |
| |
| // check that flickable moves - mouse button |
| QCOMPARE(eventItem1->eventList.size(), 0); |
| p1 = QPoint(10, 110); |
| QTest::touchEvent(window.data(), device).press(0, p1, window.data()); |
| QQuickTouchUtils::flush(window.data()); |
| QCOMPARE(eventItem1->eventList.size(), 2); |
| QCOMPARE(eventItem1->eventList.at(0).type, QEvent::TouchBegin); |
| QCOMPARE(eventItem1->eventList.at(1).type, QEvent::MouseButtonPress); |
| |
| QQuickWindowPrivate *windowPriv = QQuickWindowPrivate::get(window.data()); |
| QVERIFY(windowPriv->touchMouseId != -1); |
| auto pointerEvent = windowPriv->pointerEventInstance(QQuickPointerDevice::touchDevices().at(0)); |
| QCOMPARE(pointerEvent->point(0)->exclusiveGrabber(), eventItem1); |
| QCOMPARE(window->mouseGrabberItem(), eventItem1); |
| |
| int dragDelta = -qApp->styleHints()->startDragDistance(); |
| p1 += QPoint(0, dragDelta); |
| QPoint p2 = p1 + QPoint(0, dragDelta); |
| QPoint p3 = p2 + QPoint(0, dragDelta); |
| QQuickTouchUtils::flush(window.data()); |
| QTest::touchEvent(window.data(), device).move(0, p1, window.data()); |
| QQuickTouchUtils::flush(window.data()); |
| QTest::touchEvent(window.data(), device).move(0, p2, window.data()); |
| QQuickTouchUtils::flush(window.data()); |
| QTest::touchEvent(window.data(), device).move(0, p3, window.data()); |
| QQuickTouchUtils::flush(window.data()); |
| |
| // we cannot really know when the events get grabbed away |
| QVERIFY(eventItem1->eventList.size() >= 4); |
| QCOMPARE(eventItem1->eventList.at(2).type, QEvent::TouchUpdate); |
| QCOMPARE(eventItem1->eventList.at(3).type, QEvent::MouseMove); |
| |
| QCOMPARE(window->mouseGrabberItem(), flickable); |
| QVERIFY(windowPriv->touchMouseId != -1); |
| QCOMPARE(pointerEvent->point(0)->exclusiveGrabber(), flickable); |
| QVERIFY(flickable->isMovingVertically()); |
| |
| QTest::touchEvent(window.data(), device).release(0, p3, window.data()); |
| QQuickTouchUtils::flush(window.data()); |
| } |
| |
| void tst_TouchMouse::touchButtonOnFlickable() |
| { |
| // flickable - height 500 / 1000 |
| // - eventItem1 y: 100, height 100 |
| // - eventItem2 y: 300, height 100 |
| |
| QScopedPointer<QQuickView> window(createView()); |
| window->setSource(testFileUrl("buttononflickable.qml")); |
| window->show(); |
| QQuickViewTestUtil::centerOnScreen(window.data()); |
| QVERIFY(QTest::qWaitForWindowActive(window.data())); |
| QVERIFY(window->rootObject() != nullptr); |
| |
| QQuickFlickable *flickable = window->rootObject()->findChild<QQuickFlickable*>("flickable"); |
| QVERIFY(flickable); |
| |
| EventItem *eventItem2 = window->rootObject()->findChild<EventItem*>("eventItem2"); |
| QVERIFY(eventItem2); |
| QCOMPARE(eventItem2->eventList.size(), 0); |
| eventItem2->acceptTouch = true; |
| |
| // press via touch, then drag: check that flickable moves and that the button gets ungrabbed |
| QCOMPARE(eventItem2->eventList.size(), 0); |
| QPoint p1 = QPoint(10, 310); |
| QTest::touchEvent(window.data(), device).press(0, p1, window.data()); |
| QQuickTouchUtils::flush(window.data()); |
| QCOMPARE(eventItem2->eventList.size(), 1); |
| QCOMPARE(eventItem2->eventList.at(0).type, QEvent::TouchBegin); |
| |
| QQuickWindowPrivate *windowPriv = QQuickWindowPrivate::get(window.data()); |
| QVERIFY(windowPriv->touchMouseId == -1); |
| auto pointerEvent = windowPriv->pointerEventInstance(QQuickPointerDevice::touchDevices().at(0)); |
| QCOMPARE(pointerEvent->point(0)->grabberItem(), eventItem2); |
| QCOMPARE(window->mouseGrabberItem(), nullptr); |
| |
| int dragDelta = qApp->styleHints()->startDragDistance() * -0.7; |
| p1 += QPoint(0, dragDelta); |
| QPoint p2 = p1 + QPoint(0, dragDelta); |
| QPoint p3 = p2 + QPoint(0, dragDelta); |
| |
| QQuickTouchUtils::flush(window.data()); |
| QTest::touchEvent(window.data(), device).move(0, p1, window.data()); |
| QQuickTouchUtils::flush(window.data()); |
| QTest::touchEvent(window.data(), device).move(0, p2, window.data()); |
| QQuickTouchUtils::flush(window.data()); |
| QTest::touchEvent(window.data(), device).move(0, p3, window.data()); |
| QQuickTouchUtils::flush(window.data()); |
| |
| QTRY_COMPARE(eventItem2->touchUngrabCount, 1); |
| QVERIFY(eventItem2->eventList.size() > 2); |
| QCOMPARE(eventItem2->eventList.at(1).type, QEvent::TouchUpdate); |
| QCOMPARE(window->mouseGrabberItem(), flickable); |
| QVERIFY(windowPriv->touchMouseId != -1); |
| QCOMPARE(pointerEvent->point(0)->grabberItem(), flickable); |
| QVERIFY(flickable->isMovingVertically()); |
| |
| QTest::touchEvent(window.data(), device).release(0, p3, window.data()); |
| QQuickTouchUtils::flush(window.data()); |
| } |
| |
| void tst_TouchMouse::buttonOnDelayedPressFlickable_data() |
| { |
| QTest::addColumn<bool>("scrollBeforeDelayIsOver"); |
| QTest::addColumn<bool>("releaseBeforeDelayIsOver"); |
| |
| // the item should never see the event, |
| // due to the pressDelay which never delivers if we start moving |
| QTest::newRow("scroll before press delay is over") << true << false; |
| |
| // after release, the item should see the press and release via event replay (QTBUG-61144) |
| QTest::newRow("release before press delay is over") << false << true; |
| |
| // wait until the "button" sees the press but then |
| // start moving: the button gets a press and cancel event |
| QTest::newRow("scroll after press delay is over") << false << false; |
| } |
| |
| void tst_TouchMouse::buttonOnDelayedPressFlickable() |
| { |
| // flickable - height 500 / 1000 |
| // - eventItem1 y: 100, height 100 |
| // - eventItem2 y: 300, height 100 |
| QFETCH(bool, scrollBeforeDelayIsOver); |
| QFETCH(bool, releaseBeforeDelayIsOver); |
| |
| qApp->setAttribute(Qt::AA_SynthesizeMouseForUnhandledTouchEvents, true); |
| filteredEventList.clear(); |
| |
| QScopedPointer<QQuickView> window(createView()); |
| window->setSource(testFileUrl("buttononflickable.qml")); |
| window->show(); |
| QQuickViewTestUtil::centerOnScreen(window.data()); |
| QVERIFY(QTest::qWaitForWindowActive(window.data())); |
| QVERIFY(window->rootObject() != nullptr); |
| |
| QQuickFlickable *flickable = window->rootObject()->findChild<QQuickFlickable*>("flickable"); |
| QVERIFY(flickable); |
| |
| window->installEventFilter(this); |
| |
| // wait 600 ms before letting the child see the press event |
| flickable->setPressDelay(600); |
| |
| // should a mouse area button be clickable on top of flickable? yes :) |
| EventItem *eventItem1 = window->rootObject()->findChild<EventItem*>("eventItem1"); |
| QVERIFY(eventItem1); |
| eventItem1->setAcceptedMouseButtons(Qt::LeftButton); |
| eventItem1->acceptMouse = true; |
| |
| // should a touch button be touchable on top of flickable? yes :) |
| EventItem *eventItem2 = window->rootObject()->findChild<EventItem*>("eventItem2"); |
| QVERIFY(eventItem2); |
| QCOMPARE(eventItem2->eventList.size(), 0); |
| eventItem2->acceptTouch = true; |
| |
| // wait to avoid getting a double click event |
| QTest::qWait(qApp->styleHints()->mouseDoubleClickInterval() + 10); |
| QQuickWindowPrivate *windowPriv = QQuickWindowPrivate::get(window.data()); |
| QCOMPARE(windowPriv->touchMouseId, -1); // no grabber |
| |
| // touch press |
| QPoint p1 = QPoint(10, 110); |
| QPoint pEnd = p1; |
| QTest::touchEvent(window.data(), device).press(0, p1, window.data()); |
| QQuickTouchUtils::flush(window.data()); |
| |
| if (scrollBeforeDelayIsOver || releaseBeforeDelayIsOver) { |
| // no events yet: press is delayed |
| QCOMPARE(eventItem1->eventList.size(), 0); |
| } else { |
| // wait until the button sees the press |
| QTRY_COMPARE(eventItem1->eventList.size(), 1); |
| QCOMPARE(eventItem1->eventList.at(0).type, QEvent::MouseButtonPress); |
| QCOMPARE(filteredEventList.count(), 1); |
| } |
| |
| if (!releaseBeforeDelayIsOver) { |
| // move the touchpoint: try to flick |
| p1 += QPoint(0, -10); |
| QPoint p2 = p1 + QPoint(0, -10); |
| pEnd = p2 + QPoint(0, -10); |
| QQuickTouchUtils::flush(window.data()); |
| QTest::touchEvent(window.data(), device).move(0, p1, window.data()); |
| QQuickTouchUtils::flush(window.data()); |
| QTest::touchEvent(window.data(), device).move(0, p2, window.data()); |
| QQuickTouchUtils::flush(window.data()); |
| QTest::touchEvent(window.data(), device).move(0, pEnd, window.data()); |
| QQuickTouchUtils::flush(window.data()); |
| QTRY_VERIFY(flickable->isMovingVertically()); |
| |
| if (scrollBeforeDelayIsOver) { |
| QCOMPARE(eventItem1->eventList.size(), 0); |
| QCOMPARE(filteredEventList.count(), 0); |
| } else { |
| // see at least press, move and ungrab |
| QTRY_VERIFY(eventItem1->eventList.size() > 2); |
| QCOMPARE(eventItem1->eventList.at(0).type, QEvent::MouseButtonPress); |
| QCOMPARE(eventItem1->eventList.last().type, QEvent::UngrabMouse); |
| QCOMPARE(filteredEventList.count(), 1); |
| } |
| |
| // flickable should have the mouse grab, and have moved the itemForTouchPointId |
| // for the touchMouseId to the new grabber. |
| QCOMPARE(window->mouseGrabberItem(), flickable); |
| QVERIFY(windowPriv->touchMouseId != -1); |
| auto pointerEvent = windowPriv->pointerEventInstance(QQuickPointerDevice::touchDevices().at(0)); |
| QCOMPARE(pointerEvent->point(0)->grabberItem(), flickable); |
| } |
| |
| QTest::touchEvent(window.data(), device).release(0, pEnd, window.data()); |
| QQuickTouchUtils::flush(window.data()); |
| |
| if (releaseBeforeDelayIsOver) { |
| // when the touchpoint was released, the child saw the delayed press and the release in sequence |
| qCDebug(lcTests) << "expected delivered events: press, release, ungrab" << eventItem1->eventList; |
| qCDebug(lcTests) << "expected filtered events: delayed press, release" << filteredEventList; |
| QTRY_COMPARE(eventItem1->eventList.size(), 3); |
| QCOMPARE(eventItem1->eventList.at(0).type, QEvent::MouseButtonPress); |
| QCOMPARE(eventItem1->eventList.at(1).type, QEvent::MouseButtonRelease); |
| QCOMPARE(eventItem1->eventList.last().type, QEvent::UngrabMouse); |
| // QQuickWindow filters the delayed press and release |
| QCOMPARE(filteredEventList.count(), 2); |
| QCOMPARE(filteredEventList.at(0).type, QEvent::MouseButtonPress); |
| QCOMPARE(filteredEventList.at(1).type, QEvent::MouseButtonRelease); |
| } else { |
| // QQuickWindow filters the delayed press if there was one; otherwise nothing |
| if (scrollBeforeDelayIsOver) { |
| QCOMPARE(filteredEventList.count(), 0); |
| } else { |
| qCDebug(lcTests) << "expected filtered event: delayed press" << filteredEventList; |
| QCOMPARE(filteredEventList.count(), 1); |
| QCOMPARE(filteredEventList.at(0).type, QEvent::MouseButtonPress); |
| } |
| } |
| } |
| |
| void tst_TouchMouse::buttonOnTouch() |
| { |
| // 400x800 |
| // PinchArea - height 400 |
| // - eventItem1 y: 100, height 100 |
| // - eventItem2 y: 300, height 100 |
| // MultiPointTouchArea - height 400 |
| // - eventItem1 y: 100, height 100 |
| // - eventItem2 y: 300, height 100 |
| |
| QScopedPointer<QQuickView> window(createView()); |
| window->setSource(testFileUrl("buttonontouch.qml")); |
| window->show(); |
| QQuickViewTestUtil::centerOnScreen(window.data()); |
| QVERIFY(QTest::qWaitForWindowActive(window.data())); |
| QVERIFY(window->rootObject() != nullptr); |
| |
| QQuickPinchArea *pinchArea = window->rootObject()->findChild<QQuickPinchArea*>("pincharea"); |
| QVERIFY(pinchArea); |
| QQuickItem *button1 = window->rootObject()->findChild<QQuickItem*>("button1"); |
| QVERIFY(button1); |
| EventItem *eventItem1 = window->rootObject()->findChild<EventItem*>("eventItem1"); |
| QVERIFY(eventItem1); |
| EventItem *eventItem2 = window->rootObject()->findChild<EventItem*>("eventItem2"); |
| QVERIFY(eventItem2); |
| |
| QQuickMultiPointTouchArea *touchArea = window->rootObject()->findChild<QQuickMultiPointTouchArea*>("toucharea"); |
| QVERIFY(touchArea); |
| EventItem *eventItem3 = window->rootObject()->findChild<EventItem*>("eventItem3"); |
| QVERIFY(eventItem3); |
| EventItem *eventItem4 = window->rootObject()->findChild<EventItem*>("eventItem4"); |
| QVERIFY(eventItem4); |
| |
| QTest::QTouchEventSequence touchSeq = QTest::touchEvent(window.data(), device, false); |
| |
| // Test the common case of a mouse area on top of pinch |
| eventItem1->setAcceptedMouseButtons(Qt::LeftButton); |
| eventItem1->acceptMouse = true; |
| |
| |
| // wait to avoid getting a double click event |
| QTest::qWait(qApp->styleHints()->mouseDoubleClickInterval() + 10); |
| |
| // Normal touch click |
| QPoint p1 = QPoint(10, 110); |
| touchSeq.press(0, p1, window.data()).commit(); |
| QQuickTouchUtils::flush(window.data()); |
| touchSeq.release(0, p1, window.data()).commit(); |
| QQuickTouchUtils::flush(window.data()); |
| QCOMPARE(eventItem1->eventList.size(), 5); |
| QCOMPARE(eventItem1->eventList.at(0).type, QEvent::TouchBegin); |
| QCOMPARE(eventItem1->eventList.at(1).type, QEvent::MouseButtonPress); |
| QCOMPARE(eventItem1->eventList.at(2).type, QEvent::TouchEnd); |
| QCOMPARE(eventItem1->eventList.at(3).type, QEvent::MouseButtonRelease); |
| QCOMPARE(eventItem1->eventList.at(4).type, QEvent::UngrabMouse); |
| eventItem1->eventList.clear(); |
| |
| // Normal mouse click |
| QTest::mouseClick(window.data(), Qt::LeftButton, Qt::NoModifier, p1); |
| QCOMPARE(eventItem1->eventList.size(), 3); |
| QCOMPARE(eventItem1->eventList.at(0).type, QEvent::MouseButtonPress); |
| QCOMPARE(eventItem1->eventList.at(1).type, QEvent::MouseButtonRelease); |
| QCOMPARE(eventItem1->eventList.at(2).type, QEvent::UngrabMouse); |
| eventItem1->eventList.clear(); |
| |
| // Pinch starting on the PinchArea should work |
| p1 = QPoint(40, 10); |
| QPoint p2 = QPoint(60, 10); |
| |
| // Start the events after each other |
| touchSeq.press(0, p1, window.data()).commit(); |
| QQuickTouchUtils::flush(window.data()); |
| touchSeq.stationary(0).press(1, p2, window.data()).commit(); |
| QQuickTouchUtils::flush(window.data()); |
| |
| QCOMPARE(button1->scale(), 1.0); |
| |
| // This event seems to be discarded, let's ignore it for now until someone digs into pincharea |
| p1 -= QPoint(10, 0); |
| p2 += QPoint(10, 0); |
| touchSeq.move(0, p1, window.data()).move(1, p2, window.data()).commit(); |
| QQuickTouchUtils::flush(window.data()); |
| |
| p1 -= QPoint(10, 0); |
| p2 += QPoint(10, 0); |
| touchSeq.move(0, p1, window.data()).move(1, p2, window.data()).commit(); |
| QQuickTouchUtils::flush(window.data()); |
| // QCOMPARE(button1->scale(), 1.5); |
| qDebug() << "Button scale: " << button1->scale(); |
| |
| p1 -= QPoint(10, 0); |
| p2 += QPoint(10, 0); |
| touchSeq.move(0, p1, window.data()).move(1, p2, window.data()).commit(); |
| QQuickTouchUtils::flush(window.data()); |
| // QCOMPARE(button1->scale(), 2.0); |
| qDebug() << "Button scale: " << button1->scale(); |
| |
| touchSeq.release(0, p1, window.data()).release(1, p2, window.data()).commit(); |
| QQuickTouchUtils::flush(window.data()); |
| // QVERIFY(eventItem1->eventList.isEmpty()); |
| // QCOMPARE(button1->scale(), 2.0); |
| qDebug() << "Button scale: " << button1->scale(); |
| |
| |
| // wait to avoid getting a double click event |
| QTest::qWait(qApp->styleHints()->mouseDoubleClickInterval() + 10); |
| |
| // Start pinching while on the button |
| button1->setScale(1.0); |
| p1 = QPoint(40, 110); |
| p2 = QPoint(60, 110); |
| touchSeq.press(0, p1, window.data()).press(1, p2, window.data()).commit(); |
| QQuickTouchUtils::flush(window.data()); |
| QCOMPARE(button1->scale(), 1.0); |
| QCOMPARE(eventItem1->eventList.count(), 2); |
| QCOMPARE(eventItem1->eventList.at(0).type, QEvent::TouchBegin); |
| QCOMPARE(eventItem1->eventList.at(1).type, QEvent::MouseButtonPress); |
| |
| // This event seems to be discarded, let's ignore it for now until someone digs into pincharea |
| p1 -= QPoint(10, 0); |
| p2 += QPoint(10, 0); |
| touchSeq.move(0, p1, window.data()).move(1, p2, window.data()).commit(); |
| QQuickTouchUtils::flush(window.data()); |
| |
| p1 -= QPoint(10, 0); |
| p2 += QPoint(10, 0); |
| touchSeq.move(0, p1, window.data()).move(1, p2, window.data()).commit(); |
| QQuickTouchUtils::flush(window.data()); |
| //QCOMPARE(button1->scale(), 1.5); |
| qDebug() << button1->scale(); |
| |
| p1 -= QPoint(10, 0); |
| p2 += QPoint(10, 0); |
| touchSeq.move(0, p1, window.data()).move(1, p2, window.data()).commit(); |
| QQuickTouchUtils::flush(window.data()); |
| qDebug() << button1->scale(); |
| //QCOMPARE(button1->scale(), 2.0); |
| |
| touchSeq.release(0, p1, window.data()).release(1, p2, window.data()).commit(); |
| QQuickTouchUtils::flush(window.data()); |
| // QCOMPARE(eventItem1->eventList.size(), 99); |
| qDebug() << button1->scale(); |
| //QCOMPARE(button1->scale(), 2.0); |
| } |
| |
| void tst_TouchMouse::pinchOnFlickable() |
| { |
| QScopedPointer<QQuickView> window(createView()); |
| window->setSource(testFileUrl("pinchonflickable.qml")); |
| window->show(); |
| QQuickViewTestUtil::centerOnScreen(window.data()); |
| QVERIFY(QTest::qWaitForWindowActive(window.data())); |
| QVERIFY(window->rootObject() != nullptr); |
| |
| QQuickPinchArea *pinchArea = window->rootObject()->findChild<QQuickPinchArea*>("pincharea"); |
| QVERIFY(pinchArea); |
| QQuickFlickable *flickable = window->rootObject()->findChild<QQuickFlickable*>("flickable"); |
| QVERIFY(flickable); |
| QQuickItem *rect = window->rootObject()->findChild<QQuickItem*>("rect"); |
| QVERIFY(rect); |
| |
| // flickable - single touch point |
| QCOMPARE(flickable->contentX(), 0.0); |
| QPoint p = QPoint(100, 100); |
| QTest::touchEvent(window.data(), device).press(0, p, window.data()); |
| QQuickTouchUtils::flush(window.data()); |
| QCOMPARE(rect->position(), QPointF(200.0, 200.0)); |
| p -= QPoint(10, 0); |
| QTest::touchEvent(window.data(), device).move(0, p, window.data()); |
| QQuickTouchUtils::flush(window.data()); |
| p -= QPoint(10, 0); |
| QTest::touchEvent(window.data(), device).move(0, p, window.data()); |
| QQuickTouchUtils::flush(window.data()); |
| p -= QPoint(10, 0); |
| QTest::touchEvent(window.data(), device).move(0, p, window.data()); |
| QQuickTouchUtils::flush(window.data()); |
| p -= QPoint(10, 0); |
| QTest::touchEvent(window.data(), device).move(0, p, window.data()); |
| QQuickTouchUtils::flush(window.data()); |
| QTest::touchEvent(window.data(), device).release(0, p, window.data()); |
| QQuickTouchUtils::flush(window.data()); |
| |
| QGuiApplication::processEvents(); |
| QTest::qWait(10); |
| QVERIFY(!flickable->isAtXBeginning()); |
| // wait until flicking is done |
| QTRY_VERIFY(!flickable->isFlicking()); |
| |
| // pinch |
| QPoint p1 = QPoint(40, 20); |
| QPoint p2 = QPoint(60, 20); |
| |
| QTest::QTouchEventSequence pinchSequence = QTest::touchEvent(window.data(), device); |
| QQuickTouchUtils::flush(window.data()); |
| pinchSequence.press(0, p1, window.data()).commit(); |
| QQuickTouchUtils::flush(window.data()); |
| // In order for the stationary point to remember its previous position, |
| // we have to reuse the same pinchSequence object. Otherwise if we let it |
| // be destroyed and then start a new sequence, point 0 will default to being |
| // stationary at 0, 0, and PinchArea will filter out that touchpoint because |
| // it is outside its bounds. |
| pinchSequence.stationary(0).press(1, p2, window.data()).commit(); |
| QQuickTouchUtils::flush(window.data()); |
| p1 -= QPoint(10,10); |
| p2 += QPoint(10,10); |
| pinchSequence.move(0, p1, window.data()).move(1, p2, window.data()).commit(); |
| QQuickTouchUtils::flush(window.data()); |
| QCOMPARE(rect->scale(), 1.0); |
| p1 -= QPoint(10, 0); |
| p2 += QPoint(10, 0); |
| pinchSequence.move(0, p1, window.data()).move(1, p2, window.data()).commit(); |
| QQuickTouchUtils::flush(window.data()); |
| p1 -= QPoint(10, 0); |
| p2 += QPoint(10, 0); |
| pinchSequence.move(0, p1, window.data()).move(1, p2, window.data()).commit(); |
| QQuickTouchUtils::flush(window.data()); |
| p1 -= QPoint(10, 0); |
| p2 += QPoint(10, 0); |
| pinchSequence.move(0, p1, window.data()).move(1, p2, window.data()).commit(); |
| QVERIFY(!flickable->isDragging()); |
| QQuickTouchUtils::flush(window.data()); |
| pinchSequence.release(0, p1, window.data()).release(1, p2, window.data()).commit(); |
| QQuickTouchUtils::flush(window.data()); |
| QVERIFY(rect->scale() > 1.0); |
| } |
| |
| void tst_TouchMouse::flickableOnPinch() |
| { |
| QScopedPointer<QQuickView> window(createView()); |
| window->setSource(testFileUrl("flickableonpinch.qml")); |
| window->show(); |
| QQuickViewTestUtil::centerOnScreen(window.data()); |
| QVERIFY(QTest::qWaitForWindowActive(window.data())); |
| QVERIFY(window->rootObject() != nullptr); |
| |
| QQuickPinchArea *pinchArea = window->rootObject()->findChild<QQuickPinchArea*>("pincharea"); |
| QVERIFY(pinchArea); |
| QQuickFlickable *flickable = window->rootObject()->findChild<QQuickFlickable*>("flickable"); |
| QVERIFY(flickable); |
| QQuickItem *rect = window->rootObject()->findChild<QQuickItem*>("rect"); |
| QVERIFY(rect); |
| |
| // flickable - single touch point |
| QCOMPARE(flickable->contentX(), 0.0); |
| QPoint p = QPoint(100, 100); |
| QTest::touchEvent(window.data(), device).press(0, p, window.data()); |
| QQuickTouchUtils::flush(window.data()); |
| QCOMPARE(rect->position(), QPointF(200.0, 200.0)); |
| p -= QPoint(10, 0); |
| QTest::touchEvent(window.data(), device).move(0, p, window.data()); |
| QQuickTouchUtils::flush(window.data()); |
| p -= QPoint(10, 0); |
| QTest::touchEvent(window.data(), device).move(0, p, window.data()); |
| QQuickTouchUtils::flush(window.data()); |
| |
| QTest::qWait(1000); |
| |
| p -= QPoint(10, 0); |
| QTest::touchEvent(window.data(), device).move(0, p, window.data()); |
| QQuickTouchUtils::flush(window.data()); |
| QTest::touchEvent(window.data(), device).release(0, p, window.data()); |
| QQuickTouchUtils::flush(window.data()); |
| |
| QTest::qWait(1000); |
| |
| //QVERIFY(flickable->isMovingHorizontally()); |
| qDebug() << "Pos: " << rect->position(); |
| // wait until flicking is done |
| QTRY_VERIFY(!flickable->isFlicking()); |
| |
| // pinch |
| QPoint p1 = QPoint(40, 20); |
| QPoint p2 = QPoint(60, 20); |
| QTest::QTouchEventSequence pinchSequence = QTest::touchEvent(window.data(), device); |
| pinchSequence.press(0, p1, window.data()).commit(); |
| QQuickTouchUtils::flush(window.data()); |
| // In order for the stationary point to remember its previous position, |
| // we have to reuse the same pinchSequence object. Otherwise if we let it |
| // be destroyed and then start a new sequence, point 0 will default to being |
| // stationary at 0, 0, and PinchArea will filter out that touchpoint because |
| // it is outside its bounds. |
| pinchSequence.stationary(0).press(1, p2, window.data()).commit(); |
| QQuickTouchUtils::flush(window.data()); |
| p1 -= QPoint(10,10); |
| p2 += QPoint(10,10); |
| pinchSequence.move(0, p1, window.data()).move(1, p2, window.data()).commit(); |
| QQuickTouchUtils::flush(window.data()); |
| QCOMPARE(rect->scale(), 1.0); |
| p1 -= QPoint(10, 0); |
| p2 += QPoint(10, 0); |
| pinchSequence.move(0, p1, window.data()).move(1, p2, window.data()).commit(); |
| QQuickTouchUtils::flush(window.data()); |
| p1 -= QPoint(10, 0); |
| p2 += QPoint(10, 0); |
| pinchSequence.move(0, p1, window.data()).move(1, p2, window.data()).commit(); |
| QQuickTouchUtils::flush(window.data()); |
| p1 -= QPoint(10, 0); |
| p2 += QPoint(10, 0); |
| pinchSequence.move(0, p1, window.data()).move(1, p2, window.data()).commit(); |
| QQuickTouchUtils::flush(window.data()); |
| pinchSequence.release(0, p1, window.data()).release(1, p2, window.data()).commit(); |
| QQuickTouchUtils::flush(window.data()); |
| QVERIFY(rect->scale() > 1.0); |
| } |
| |
| void tst_TouchMouse::mouseOnFlickableOnPinch() |
| { |
| QScopedPointer<QQuickView> window(createView()); |
| window->setSource(testFileUrl("mouseonflickableonpinch.qml")); |
| window->show(); |
| QQuickViewTestUtil::centerOnScreen(window.data()); |
| QVERIFY(QTest::qWaitForWindowActive(window.data())); |
| QVERIFY(window->rootObject() != nullptr); |
| |
| QRect windowRect = QRect(window->position(), window->size()); |
| QCursor::setPos(windowRect.center()); |
| |
| QQuickPinchArea *pinchArea = window->rootObject()->findChild<QQuickPinchArea*>("pincharea"); |
| QVERIFY(pinchArea); |
| QQuickFlickable *flickable = window->rootObject()->findChild<QQuickFlickable*>("flickable"); |
| QVERIFY(flickable); |
| QQuickItem *rect = window->rootObject()->findChild<QQuickItem*>("rect"); |
| QVERIFY(rect); |
| |
| // flickable - single touch point |
| QCOMPARE(flickable->contentX(), 0.0); |
| QPoint p = QPoint(100, 100); |
| QTest::touchEvent(window.data(), device).press(0, p, window.data()); |
| QQuickTouchUtils::flush(window.data()); |
| QCOMPARE(rect->position(), QPointF(200.0, 200.0)); |
| p -= QPoint(10, 0); |
| QTest::touchEvent(window.data(), device).move(0, p, window.data()); |
| QQuickTouchUtils::flush(window.data()); |
| p -= QPoint(10, 0); |
| QTest::touchEvent(window.data(), device).move(0, p, window.data()); |
| QQuickTouchUtils::flush(window.data()); |
| p -= QPoint(10, 0); |
| QTest::touchEvent(window.data(), device).move(0, p, window.data()); |
| QQuickTouchUtils::flush(window.data()); |
| QTest::touchEvent(window.data(), device).release(0, p, window.data()); |
| QQuickTouchUtils::flush(window.data()); |
| |
| //QVERIFY(flickable->isMovingHorizontally()); |
| |
| // Wait for flick to end |
| QTRY_VERIFY(!flickable->isMoving()); |
| qDebug() << "Pos: " << rect->position(); |
| |
| // pinch |
| QPoint p1 = QPoint(40, 20); |
| QPoint p2 = QPoint(60, 20); |
| QTest::QTouchEventSequence pinchSequence = QTest::touchEvent(window.data(), device); |
| pinchSequence.press(0, p1, window.data()).commit(); |
| QQuickTouchUtils::flush(window.data()); |
| // In order for the stationary point to remember its previous position, |
| // we have to reuse the same pinchSequence object. Otherwise if we let it |
| // be destroyed and then start a new sequence, point 0 will default to being |
| // stationary at 0, 0, and PinchArea will filter out that touchpoint because |
| // it is outside its bounds. |
| pinchSequence.stationary(0).press(1, p2, window.data()).commit(); |
| QQuickTouchUtils::flush(window.data()); |
| p1 -= QPoint(10,10); |
| p2 += QPoint(10,10); |
| pinchSequence.move(0, p1, window.data()).move(1, p2, window.data()).commit(); |
| QQuickTouchUtils::flush(window.data()); |
| QCOMPARE(rect->scale(), 1.0); |
| p1 -= QPoint(10, 0); |
| p2 += QPoint(10, 0); |
| pinchSequence.move(0, p1, window.data()).move(1, p2, window.data()).commit(); |
| QQuickTouchUtils::flush(window.data()); |
| p1 -= QPoint(10, 0); |
| p2 += QPoint(10, 0); |
| pinchSequence.move(0, p1, window.data()).move(1, p2, window.data()).commit(); |
| QQuickTouchUtils::flush(window.data()); |
| p1 -= QPoint(10, 0); |
| p2 += QPoint(10, 0); |
| pinchSequence.move(0, p1, window.data()).move(1, p2, window.data()).commit(); |
| QQuickTouchUtils::flush(window.data()); |
| pinchSequence.release(0, p1, window.data()).release(1, p2, window.data()).commit(); |
| QQuickTouchUtils::flush(window.data()); |
| QVERIFY(rect->scale() > 1.0); |
| |
| // PinchArea should steal the event after flicking started |
| rect->setScale(1.0); |
| flickable->setContentX(0.0); |
| p = QPoint(100, 100); |
| pinchSequence.press(0, p, window.data()).commit(); |
| QQuickTouchUtils::flush(window.data()); |
| QCOMPARE(rect->position(), QPointF(200.0, 200.0)); |
| p -= QPoint(10, 0); |
| pinchSequence.move(0, p, window.data()).commit(); |
| QQuickTouchUtils::flush(window.data()); |
| p -= QPoint(10, 0); |
| pinchSequence.move(0, p, window.data()).commit(); |
| QQuickTouchUtils::flush(window.data()); |
| QGuiApplication::processEvents(); |
| p -= QPoint(10, 0); |
| pinchSequence.move(0, p, window.data()).commit(); |
| QQuickTouchUtils::flush(window.data()); |
| |
| QCOMPARE(window->mouseGrabberItem(), flickable); |
| |
| // Add a second finger, this should lead to stealing |
| p1 = QPoint(40, 100); |
| p2 = QPoint(60, 100); |
| pinchSequence.stationary(0).press(1, p2, window.data()).commit(); |
| QQuickTouchUtils::flush(window.data()); |
| QCOMPARE(rect->scale(), 1.0); |
| |
| p1 -= QPoint(5, 0); |
| p2 += QPoint(5, 0); |
| pinchSequence.move(0, p1, window.data()).move(1, p2, window.data()).commit(); |
| QQuickTouchUtils::flush(window.data()); |
| p1 -= QPoint(5, 0); |
| p2 += QPoint(5, 0); |
| pinchSequence.move(0, p1, window.data()).move(1, p2, window.data()).commit(); |
| QQuickTouchUtils::flush(window.data()); |
| p1 -= QPoint(5, 0); |
| p2 += QPoint(5, 0); |
| pinchSequence.move(0, p1, window.data()).move(1, p2, window.data()).commit(); |
| QQuickTouchUtils::flush(window.data()); |
| pinchSequence.release(0, p1, window.data()).release(1, p2, window.data()).commit(); |
| QQuickTouchUtils::flush(window.data()); |
| QVERIFY(rect->scale() > 1.0); |
| pinchSequence.release(0, p, window.data()).commit(); |
| QQuickTouchUtils::flush(window.data()); |
| } |
| |
| /* |
| Regression test for the following use case: |
| You have two mouse areas, on on top of the other. |
| 1 - You tap the top one. |
| 2 - That top mouse area receives a mouse press event but doesn't accept it |
| Expected outcome: |
| 3 - the bottom mouse area gets clicked (besides press and release mouse events) |
| Bogus outcome: |
| 3 - the bottom mouse area gets double clicked. |
| */ |
| void tst_TouchMouse::tapOnDismissiveTopMouseAreaClicksBottomOne() |
| { |
| QScopedPointer<QQuickView> window(createView()); |
| window->setSource(testFileUrl("twoMouseAreas.qml")); |
| window->show(); |
| QQuickViewTestUtil::centerOnScreen(window.data()); |
| QVERIFY(QTest::qWaitForWindowActive(window.data())); |
| QVERIFY(window->rootObject() != nullptr); |
| |
| QQuickMouseArea *bottomMouseArea = |
| window->rootObject()->findChild<QQuickMouseArea*>("rear mouseArea"); |
| |
| QSignalSpy bottomClickedSpy(bottomMouseArea, SIGNAL(clicked(QQuickMouseEvent*))); |
| QSignalSpy bottomDoubleClickedSpy(bottomMouseArea, |
| SIGNAL(doubleClicked(QQuickMouseEvent*))); |
| |
| // tap the front mouse area (see qml file) |
| QPoint p1(20, 20); |
| QTest::touchEvent(window.data(), device).press(0, p1, window.data()); |
| QQuickTouchUtils::flush(window.data()); |
| QTest::touchEvent(window.data(), device).release(0, p1, window.data()); |
| QQuickTouchUtils::flush(window.data()); |
| |
| QCOMPARE(bottomClickedSpy.count(), 1); |
| QCOMPARE(bottomDoubleClickedSpy.count(), 0); |
| |
| QTest::touchEvent(window.data(), device).press(0, p1, window.data()); |
| QQuickTouchUtils::flush(window.data()); |
| QTest::touchEvent(window.data(), device).release(0, p1, window.data()); |
| QQuickTouchUtils::flush(window.data()); |
| |
| QCOMPARE(bottomClickedSpy.count(), 1); |
| QCOMPARE(bottomDoubleClickedSpy.count(), 1); |
| } |
| |
| /* |
| If an item grabs a touch that is currently being used for mouse pointer emulation, |
| the current mouse grabber should lose the mouse as mouse events will no longer |
| be generated from that touch point. |
| */ |
| void tst_TouchMouse::touchGrabCausesMouseUngrab() |
| { |
| QScopedPointer<QQuickView> window(createView()); |
| window->setSource(testFileUrl("twosiblingitems.qml")); |
| window->show(); |
| QQuickViewTestUtil::centerOnScreen(window.data()); |
| QVERIFY(QTest::qWaitForWindowActive(window.data())); |
| QVERIFY(window->rootObject() != nullptr); |
| |
| EventItem *leftItem = window->rootObject()->findChild<EventItem*>("leftItem"); |
| QVERIFY(leftItem); |
| |
| EventItem *rightItem = window->rootObject()->findChild<EventItem*>("rightItem"); |
| QVERIFY(leftItem); |
| |
| // Send a touch to the leftItem. But leftItem accepts only mouse events, thus |
| // a mouse event will be synthesized out of this touch and will get accepted by |
| // leftItem. |
| leftItem->acceptMouse = true; |
| leftItem->setAcceptedMouseButtons(Qt::LeftButton); |
| QPoint p1; |
| p1 = QPoint(leftItem->width() / 2, leftItem->height() / 2); |
| QTest::touchEvent(window.data(), device).press(0, p1, window.data()); |
| QQuickTouchUtils::flush(window.data()); |
| QCOMPARE(leftItem->eventList.size(), 2); |
| QCOMPARE(leftItem->eventList.at(0).type, QEvent::TouchBegin); |
| QCOMPARE(leftItem->eventList.at(1).type, QEvent::MouseButtonPress); |
| QCOMPARE(window->mouseGrabberItem(), leftItem); |
| leftItem->eventList.clear(); |
| |
| rightItem->acceptTouch = true; |
| { |
| QVector<int> ids; |
| ids.append(leftItem->point0); |
| rightItem->grabTouchPoints(ids); |
| } |
| |
| // leftItem should have lost the mouse as the touch point that was being used to emulate it |
| // has been grabbed by another item. |
| QCOMPARE(leftItem->eventList.size(), 1); |
| QCOMPARE(leftItem->eventList.at(0).type, QEvent::UngrabMouse); |
| QCOMPARE(window->mouseGrabberItem(), (QQuickItem*)nullptr); |
| } |
| |
| void tst_TouchMouse::touchPointDeliveryOrder() |
| { |
| // Touch points should be first delivered to the item under the primary finger |
| QScopedPointer<QQuickView> window(createView()); |
| window->setSource(testFileUrl("touchpointdeliveryorder.qml")); |
| window->show(); |
| QQuickViewTestUtil::centerOnScreen(window.data()); |
| QVERIFY(QTest::qWaitForWindowActive(window.data())); |
| |
| /* |
| The items are positioned from left to right: |
| | background | |
| | left | |
| | | right | |
| | middle | |
| 0 150 300 450 600 |
| */ |
| QPoint pLeft = QPoint(100, 100); |
| QPoint pRight = QPoint(500, 100); |
| QPoint pLeftMiddle = QPoint(200, 100); |
| QPoint pRightMiddle = QPoint(350, 100); |
| |
| QTest::QTouchEventSequence touchSeq = QTest::touchEvent(window.data(), device, false); |
| |
| QVector<QQuickItem*> events; |
| EventItem *background = window->rootObject()->findChild<EventItem*>("background"); |
| EventItem *left = window->rootObject()->findChild<EventItem*>("left"); |
| EventItem *middle = window->rootObject()->findChild<EventItem*>("middle"); |
| EventItem *right = window->rootObject()->findChild<EventItem*>("right"); |
| QVERIFY(background); |
| QVERIFY(left); |
| QVERIFY(middle); |
| QVERIFY(right); |
| connect(background, &EventItem::onTouchEvent, [&events](QQuickItem* receiver){ events.append(receiver); }); |
| connect(left, &EventItem::onTouchEvent, [&events](QQuickItem* receiver){ events.append(receiver); }); |
| connect(middle, &EventItem::onTouchEvent, [&events](QQuickItem* receiver){ events.append(receiver); }); |
| connect(right, &EventItem::onTouchEvent, [&events](QQuickItem* receiver){ events.append(receiver); }); |
| |
| touchSeq.press(0, pLeft, window.data()).commit(); |
| QQuickTouchUtils::flush(window.data()); |
| |
| // Touch on left, then background |
| QCOMPARE(events.size(), 2); |
| QCOMPARE(events.at(0), left); |
| QCOMPARE(events.at(1), background); |
| events.clear(); |
| |
| // New press events are deliverd first, the stationary point was not accepted, thus it doesn't get delivered |
| touchSeq.stationary(0).press(1, pRightMiddle, window.data()).commit(); |
| QQuickTouchUtils::flush(window.data()); |
| QCOMPARE(events.size(), 3); |
| QCOMPARE(events.at(0), middle); |
| QCOMPARE(events.at(1), right); |
| QCOMPARE(events.at(2), background); |
| events.clear(); |
| |
| touchSeq.release(0, pLeft, window.data()).release(1, pRightMiddle, window.data()).commit(); |
| QQuickTouchUtils::flush(window.data()); |
| QCOMPARE(events.size(), 0); // no accepted events |
| |
| // Two presses, the first point should come first |
| touchSeq.press(0, pLeft, window.data()).press(1, pRight, window.data()).commit(); |
| QQuickTouchUtils::flush(window.data()); |
| QCOMPARE(events.size(), 3); |
| QCOMPARE(events.at(0), left); |
| QCOMPARE(events.at(1), right); |
| QCOMPARE(events.at(2), background); |
| touchSeq.release(0, pLeft, window.data()).release(1, pRight, window.data()).commit(); |
| events.clear(); |
| |
| // Again, pressing right first |
| touchSeq.press(0, pRight, window.data()).press(1, pLeft, window.data()).commit(); |
| QQuickTouchUtils::flush(window.data()); |
| QCOMPARE(events.size(), 3); |
| QCOMPARE(events.at(0), right); |
| QCOMPARE(events.at(1), left); |
| QCOMPARE(events.at(2), background); |
| touchSeq.release(0, pRight, window.data()).release(1, pLeft, window.data()).commit(); |
| events.clear(); |
| |
| // Two presses, both hitting the middle item on top, then branching left and right, then bottom |
| // Each target should be offered the events exactly once, middle first, left must come before right (id 0) |
| touchSeq.press(0, pLeftMiddle, window.data()).press(1, pRightMiddle, window.data()).commit(); |
| QCOMPARE(events.size(), 4); |
| QCOMPARE(events.at(0), middle); |
| QCOMPARE(events.at(1), left); |
| QCOMPARE(events.at(2), right); |
| QCOMPARE(events.at(3), background); |
| touchSeq.release(0, pLeftMiddle, window.data()).release(1, pRightMiddle, window.data()).commit(); |
| events.clear(); |
| |
| touchSeq.press(0, pRightMiddle, window.data()).press(1, pLeftMiddle, window.data()).commit(); |
| qDebug() << events; |
| QCOMPARE(events.size(), 4); |
| QCOMPARE(events.at(0), middle); |
| QCOMPARE(events.at(1), right); |
| QCOMPARE(events.at(2), left); |
| QCOMPARE(events.at(3), background); |
| touchSeq.release(0, pRightMiddle, window.data()).release(1, pLeftMiddle, window.data()).commit(); |
| } |
| |
| void tst_TouchMouse::hoverEnabled() |
| { |
| // QTouchDevice *device = new QTouchDevice; |
| // device->setType(QTouchDevice::TouchScreen); |
| // QWindowSystemInterface::registerTouchDevice(device); |
| |
| QScopedPointer<QQuickView> window(createView()); |
| window->setSource(testFileUrl("hoverMouseAreas.qml")); |
| QQuickViewTestUtil::centerOnScreen(window.data()); |
| QQuickViewTestUtil::moveMouseAway(window.data()); |
| window->show(); |
| QVERIFY(QTest::qWaitForWindowActive(window.data())); |
| QQuickItem *root = window->rootObject(); |
| QVERIFY(root != nullptr); |
| |
| QQuickMouseArea *mouseArea1 = root->findChild<QQuickMouseArea*>("mouseArea1"); |
| QVERIFY(mouseArea1 != nullptr); |
| |
| QQuickMouseArea *mouseArea2 = root->findChild<QQuickMouseArea*>("mouseArea2"); |
| QVERIFY(mouseArea2 != nullptr); |
| |
| QSignalSpy enterSpy1(mouseArea1, SIGNAL(entered())); |
| QSignalSpy exitSpy1(mouseArea1, SIGNAL(exited())); |
| QSignalSpy clickSpy1(mouseArea1, SIGNAL(clicked(QQuickMouseEvent *))); |
| |
| QSignalSpy enterSpy2(mouseArea2, SIGNAL(entered())); |
| QSignalSpy exitSpy2(mouseArea2, SIGNAL(exited())); |
| QSignalSpy clickSpy2(mouseArea2, SIGNAL(clicked(QQuickMouseEvent *))); |
| |
| QPoint p1(150, 150); |
| QPoint p2(150, 250); |
| |
| // ------------------------- Mouse move to mouseArea1 |
| QTest::mouseMove(window.data(), p1); |
| |
| QVERIFY(enterSpy1.count() == 1); |
| QVERIFY(mouseArea1->hovered()); |
| QVERIFY(!mouseArea2->hovered()); |
| |
| // ------------------------- Touch click on mouseArea1 |
| QTest::touchEvent(window.data(), device).press(0, p1, window.data()); |
| |
| QCOMPARE(enterSpy1.count(), 1); |
| QCOMPARE(enterSpy2.count(), 0); |
| QVERIFY(mouseArea1->pressed()); |
| QVERIFY(mouseArea1->hovered()); |
| QVERIFY(!mouseArea2->hovered()); |
| |
| QTest::touchEvent(window.data(), device).release(0, p1, window.data()); |
| QVERIFY(clickSpy1.count() == 1); |
| QVERIFY(mouseArea1->hovered()); |
| QVERIFY(!mouseArea2->hovered()); |
| |
| // ------------------------- Touch click on mouseArea2 |
| QTest::touchEvent(window.data(), device).press(0, p2, window.data()); |
| |
| QVERIFY(mouseArea1->hovered()); |
| QVERIFY(mouseArea2->hovered()); |
| QVERIFY(mouseArea2->pressed()); |
| QCOMPARE(enterSpy1.count(), 1); |
| QCOMPARE(enterSpy2.count(), 1); |
| |
| QTest::touchEvent(window.data(), device).release(0, p2, window.data()); |
| |
| QVERIFY(clickSpy2.count() == 1); |
| QVERIFY(mouseArea1->hovered()); |
| QVERIFY(!mouseArea2->hovered()); |
| QCOMPARE(exitSpy1.count(), 0); |
| QCOMPARE(exitSpy2.count(), 1); |
| |
| // ------------------------- Another touch click on mouseArea1 |
| QTest::touchEvent(window.data(), device).press(0, p1, window.data()); |
| |
| QCOMPARE(enterSpy1.count(), 1); |
| QCOMPARE(enterSpy2.count(), 1); |
| QVERIFY(mouseArea1->pressed()); |
| QVERIFY(mouseArea1->hovered()); |
| QVERIFY(!mouseArea2->hovered()); |
| |
| QTest::touchEvent(window.data(), device).release(0, p1, window.data()); |
| QCOMPARE(clickSpy1.count(), 2); |
| QVERIFY(mouseArea1->hovered()); |
| QVERIFY(!mouseArea1->pressed()); |
| QVERIFY(!mouseArea2->hovered()); |
| } |
| |
| void tst_TouchMouse::implicitUngrab() |
| { |
| QScopedPointer<QQuickView> window(createView()); |
| window->setSource(testFileUrl("singleitem.qml")); |
| window->show(); |
| QQuickViewTestUtil::centerOnScreen(window.data()); |
| QQuickViewTestUtil::moveMouseAway(window.data()); |
| QVERIFY(QTest::qWaitForWindowActive(window.data())); |
| |
| QQuickItem *root = window->rootObject(); |
| QVERIFY(root != nullptr); |
| EventItem *eventItem = root->findChild<EventItem*>("eventItem1"); |
| eventItem->acceptMouse = true; |
| QPoint p1(20, 20); |
| QTest::touchEvent(window.data(), device).press(0, p1); |
| |
| QCOMPARE(window->mouseGrabberItem(), eventItem); |
| eventItem->eventList.clear(); |
| eventItem->setEnabled(false); |
| QVERIFY(!eventItem->eventList.isEmpty()); |
| QCOMPARE(eventItem->eventList.at(0).type, QEvent::UngrabMouse); |
| QTest::touchEvent(window.data(), device).release(0, p1); // clean up potential state |
| |
| eventItem->setEnabled(true); |
| QTest::touchEvent(window.data(), device).press(0, p1); |
| eventItem->eventList.clear(); |
| eventItem->setVisible(false); |
| QVERIFY(!eventItem->eventList.isEmpty()); |
| QCOMPARE(eventItem->eventList.at(0).type, QEvent::UngrabMouse); |
| QTest::touchEvent(window.data(), device).release(0, p1); // clean up potential state |
| } |
| QTEST_MAIN(tst_TouchMouse) |
| |
| #include "tst_touchmouse.moc" |
| |