From dc07b802df10f22e4422486ad470fc85d17e28b7 Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Mon, 2 May 2016 15:36:17 +0200 Subject: add PointerHandlers autotests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Starting with touchEventDelivery and mouseEventDelivery, and reflecting the current state of the code: a handler cannot yet be the grabber, so we don't yet deliver properly to both the legacy event handler functions and to the handler objects. Change-Id: Ied73663b97907431668cb2621260d2551052d737 Reviewed-by: Jan Arve Sæther --- .../auto/quick/pointerhandlers/data/singleitem.qml | 22 + .../auto/quick/pointerhandlers/pointerhandlers.pro | 16 + .../quick/pointerhandlers/tst_pointerhandlers.cpp | 466 +++++++++++++++++++++ tests/auto/quick/quick.pro | 1 + 4 files changed, 505 insertions(+) create mode 100644 tests/auto/quick/pointerhandlers/data/singleitem.qml create mode 100644 tests/auto/quick/pointerhandlers/pointerhandlers.pro create mode 100644 tests/auto/quick/pointerhandlers/tst_pointerhandlers.cpp (limited to 'tests') diff --git a/tests/auto/quick/pointerhandlers/data/singleitem.qml b/tests/auto/quick/pointerhandlers/data/singleitem.qml new file mode 100644 index 0000000000..fe05a3f935 --- /dev/null +++ b/tests/auto/quick/pointerhandlers/data/singleitem.qml @@ -0,0 +1,22 @@ +import QtQuick 2.8 +import Qt.test 1.0 + +Rectangle { + id: root + width: 320 + height: 480 + color: "green" + + EventItem { + objectName: "eventItem1" + x: 5 + y: 5 + height: 30 + width: 30 + + EventHandler { + + } + } +} + diff --git a/tests/auto/quick/pointerhandlers/pointerhandlers.pro b/tests/auto/quick/pointerhandlers/pointerhandlers.pro new file mode 100644 index 0000000000..41e1196965 --- /dev/null +++ b/tests/auto/quick/pointerhandlers/pointerhandlers.pro @@ -0,0 +1,16 @@ +CONFIG += testcase + +TARGET = tst_pointerhandlers +QT += core-private gui-private qml-private quick-private testlib + +macos:CONFIG -= app_bundle + +SOURCES += tst_pointerhandlers.cpp + +include (../../shared/util.pri) +include (../shared/util.pri) + +TESTDATA = data/* + +# OTHER_FILES += data/foo.qml + diff --git a/tests/auto/quick/pointerhandlers/tst_pointerhandlers.cpp b/tests/auto/quick/pointerhandlers/tst_pointerhandlers.cpp new file mode 100644 index 0000000000..bed1721a52 --- /dev/null +++ b/tests/auto/quick/pointerhandlers/tst_pointerhandlers.cpp @@ -0,0 +1,466 @@ +/**************************************************************************** +** +** 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 + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include "../../shared/util.h" +#include "../shared/viewtestutil.h" + +Q_LOGGING_CATEGORY(lcPointerTests, "qt.quick.pointer.tests") + +struct Event +{ + Event(QEvent::Type t, QPointF item, QPointF scene) + :type(t), posWrtItem(item), posWrtScene(scene) + {} + + QEvent::Type type; + QPointF posWrtItem; + QPointF posWrtScene; + +}; + +#ifndef QT_NO_DEBUG_STREAM +QDebug operator<<(QDebug dbg, const struct Event &event) { + QDebugStateSaver saver(dbg); + dbg.nospace(); + dbg << "Event(" << event.type << " @" << event.posWrtScene << ")"; + return dbg; +} +#endif + +class EventItem : public QQuickItem +{ + Q_OBJECT +public: + EventItem(QQuickItem *parent = 0) + : QQuickItem(parent), acceptPointer(false), acceptMouse(false), acceptTouch(false), filterTouch(false) + {} + + void touchEvent(QTouchEvent *event) + { + qCDebug(lcPointerTests) << event << "will accept?" << acceptTouch; + for (const QTouchEvent::TouchPoint &tp : event->touchPoints()) + eventList.append(Event(event->type(), tp.pos(), tp.scenePos())); + event->setAccepted(acceptTouch); + } + void mousePressEvent(QMouseEvent *event) + { + qCDebug(lcPointerTests) << event; + eventList.append(Event(event->type(), event->pos(), event->windowPos())); + event->setAccepted(acceptMouse); + } + void mouseMoveEvent(QMouseEvent *event) + { + qCDebug(lcPointerTests) << event; + eventList.append(Event(event->type(), event->pos(), event->windowPos())); + event->setAccepted(acceptMouse); + } + void mouseReleaseEvent(QMouseEvent *event) + { + qCDebug(lcPointerTests) << event; + eventList.append(Event(event->type(), event->pos(), event->windowPos())); + event->setAccepted(acceptMouse); + } + void mouseDoubleClickEvent(QMouseEvent *event) + { + qCDebug(lcPointerTests) << event; + eventList.append(Event(event->type(), event->pos(), event->windowPos())); + event->setAccepted(acceptMouse); + } + + void mouseUngrabEvent() + { + qCDebug(lcPointerTests); + eventList.append(Event(QEvent::UngrabMouse, QPoint(0,0), QPoint(0,0))); + } + + bool event(QEvent *event) + { + qCDebug(lcPointerTests) << event; + return QQuickItem::event(event); + } + + QList eventList; + bool acceptPointer; + bool acceptMouse; + bool acceptTouch; + bool filterTouch; // when used as event filter + + bool eventFilter(QObject *o, QEvent *event) + { + qCDebug(lcPointerTests) << event << o; + if (event->type() == QEvent::TouchBegin || + event->type() == QEvent::TouchUpdate || + event->type() == QEvent::TouchCancel || + event->type() == QEvent::TouchEnd) { + QTouchEvent *touch = static_cast(event); + for (const QTouchEvent::TouchPoint &tp : touch->touchPoints()) + eventList.append(Event(event->type(), tp.pos(), tp.scenePos())); + if (filterTouch) + event->accept(); + return true; + } + return false; + } +}; + +class EventHandler : public QQuickPointerHandler +{ + void handlePointerEventImpl(QQuickPointerEvent *event) override + { + QQuickPointerHandler::handlePointerEventImpl(event); + if (!enabled()) + return; + EventItem *item = static_cast(target()); + qCDebug(lcPointerTests) << item->objectName() << event; + int c = event->pointCount(); + for (int i = 0; i < c; ++i) { + QQuickEventPoint *point = event->point(i); + point->setAccepted(item->acceptPointer); // has no effect: grabbing is up to us + if (item->acceptPointer) + setGrab(point, true); + qCDebug(lcPointerTests) << " " << i << ":" << point << "grabbed?" << item->acceptPointer; + item->eventList.append(Event(QEvent::Pointer, eventPos(point), point->scenePos())); + } + } +}; + +class tst_PointerHandlers : public QQmlDataTest +{ + Q_OBJECT +public: + tst_PointerHandlers() + :touchDevice(QTest::createTouchDevice()) + {} + +private slots: + void initTestCase(); + + void touchEventDelivery(); + void mouseEventDelivery(); + +protected: + bool eventFilter(QObject *, QEvent *event) + { + if (event->type() == QEvent::MouseButtonPress || + event->type() == QEvent::MouseMove || + event->type() == QEvent::MouseButtonRelease) { + QMouseEvent *me = static_cast(event); + filteredEventList.append(Event(me->type(), me->pos(), me->globalPos())); + } + return false; + } + +private: + QQuickView *createView(); + QTouchDevice *touchDevice; + QList filteredEventList; +}; + +QQuickView *tst_PointerHandlers::createView() +{ + QQuickView *window = new QQuickView(0); + window->setGeometry(0,0,240,320); + + return window; +} + +void tst_PointerHandlers::initTestCase() +{ + // This test assumes that we don't get synthesized mouse events from QGuiApplication + qApp->setAttribute(Qt::AA_SynthesizeMouseForUnhandledTouchEvents, false); + + QQmlDataTest::initTestCase(); + qmlRegisterType("Qt.test", 1, 0, "EventItem"); + qmlRegisterType("Qt.test", 1, 0, "EventHandler"); +} + +void tst_PointerHandlers::touchEventDelivery() +{ + QQuickView *window = createView(); + + window->setSource(testFileUrl("singleitem.qml")); + window->show(); + QVERIFY(QTest::qWaitForWindowExposed(window)); + window->requestActivate(); + QVERIFY(QTest::qWaitForWindowActive(window)); + QVERIFY(window->rootObject() != 0); + + EventItem *eventItem1 = window->rootObject()->findChild("eventItem1"); + QVERIFY(eventItem1); + + // Do not accept anything + QPoint p1 = QPoint(20, 20); + QTest::touchEvent(window, touchDevice).press(0, p1, window); + QQuickTouchUtils::flush(window); + QTRY_COMPARE(eventItem1->eventList.size(), 3); + QCOMPARE(eventItem1->eventList.at(0).type, QEvent::Pointer); + QCOMPARE(eventItem1->eventList.at(1).type, QEvent::TouchBegin); + QCOMPARE(eventItem1->eventList.at(2).type, QEvent::MouseButtonPress); + p1 += QPoint(10, 0); + QTest::touchEvent(window, touchDevice).move(0, p1, window); + QQuickTouchUtils::flush(window); + QCOMPARE(eventItem1->eventList.size(), 3); + QTest::touchEvent(window, touchDevice).release(0, p1, window); + QQuickTouchUtils::flush(window); + QCOMPARE(eventItem1->eventList.size(), 3); + eventItem1->eventList.clear(); + + // Accept touch + eventItem1->acceptTouch = true; + p1 = QPoint(20, 20); + QTest::touchEvent(window, touchDevice).press(0, p1, window); + QQuickTouchUtils::flush(window); + QCOMPARE(eventItem1->eventList.size(), 2); + QCOMPARE(eventItem1->eventList.at(0).type, QEvent::Pointer); + QCOMPARE(eventItem1->eventList.at(1).type, QEvent::TouchBegin); + auto pointerEvent = QQuickPointerDevice::touchDevices().at(0)->pointerEvent(); + QCOMPARE(pointerEvent->point(0)->grabber(), eventItem1); + p1 += QPoint(10, 0); + QTest::touchEvent(window, touchDevice).move(0, p1, window); + QQuickTouchUtils::flush(window); + QCOMPARE(eventItem1->eventList.size(), 4); + QCOMPARE(eventItem1->eventList.at(2).type, QEvent::Pointer); + QCOMPARE(eventItem1->eventList.at(3).type, QEvent::TouchUpdate); + QTest::touchEvent(window, touchDevice).release(0, p1, window); + QQuickTouchUtils::flush(window); + QCOMPARE(eventItem1->eventList.size(), 6); + QCOMPARE(eventItem1->eventList.at(4).type, QEvent::Pointer); + QCOMPARE(eventItem1->eventList.at(5).type, QEvent::TouchEnd); + 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, touchDevice).press(0, p1, window); + QQuickTouchUtils::flush(window); + QCOMPARE(eventItem1->eventList.size(), 3); + QCOMPARE(eventItem1->eventList.at(0).type, QEvent::Pointer); + QCOMPARE(eventItem1->eventList.at(1).type, QEvent::TouchBegin); + QCOMPARE(eventItem1->eventList.at(2).type, QEvent::MouseButtonPress); + QCOMPARE(window->mouseGrabberItem(), eventItem1); + + QPointF localPos = eventItem1->mapFromScene(p1); + QPointF scenePos = p1; // item is at 0,0 + QCOMPARE(eventItem1->eventList.at(1).posWrtItem, localPos); + QCOMPARE(eventItem1->eventList.at(1).posWrtScene, scenePos); + QCOMPARE(eventItem1->eventList.at(2).posWrtItem, localPos); + QCOMPARE(eventItem1->eventList.at(2).posWrtScene, scenePos); + + p1 += QPoint(10, 0); + QTest::touchEvent(window, touchDevice).move(0, p1, window); + QQuickTouchUtils::flush(window); + QCOMPARE(eventItem1->eventList.size(), 6); + QCOMPARE(eventItem1->eventList.at(3).type, QEvent::Pointer); + QCOMPARE(eventItem1->eventList.at(4).type, QEvent::TouchUpdate); + QCOMPARE(eventItem1->eventList.at(5).type, QEvent::MouseMove); + QTest::touchEvent(window, touchDevice).release(0, p1, window); + QQuickTouchUtils::flush(window); + QCOMPARE(eventItem1->eventList.size(), 10); + QCOMPARE(eventItem1->eventList.at(6).type, QEvent::Pointer); + QCOMPARE(eventItem1->eventList.at(7).type, QEvent::TouchEnd); + QCOMPARE(eventItem1->eventList.at(8).type, QEvent::MouseButtonRelease); + QCOMPARE(eventItem1->eventList.at(9).type, QEvent::UngrabMouse); + eventItem1->eventList.clear(); + + // wait to avoid getting a double click event + QTest::qWait(qApp->styleHints()->mouseDoubleClickInterval() + 10); + + // Accept mouse buttons but not the touch event + eventItem1->acceptTouch = false; + eventItem1->acceptMouse = false; + eventItem1->setAcceptedMouseButtons(Qt::LeftButton); + p1 = QPoint(20, 20); + QTest::touchEvent(window, touchDevice).press(0, p1, window); + QQuickTouchUtils::flush(window); + QCOMPARE(eventItem1->eventList.size(), 3); + QCOMPARE(eventItem1->eventList.at(0).type, QEvent::Pointer); + QCOMPARE(eventItem1->eventList.at(1).type, QEvent::TouchBegin); + QCOMPARE(eventItem1->eventList.at(2).type, QEvent::MouseButtonPress); + QCOMPARE(pointerEvent->point(0)->grabber(), nullptr); + p1 += QPoint(10, 0); + QTest::touchEvent(window, touchDevice).move(0, p1, window); + QQuickTouchUtils::flush(window); + QCOMPARE(eventItem1->eventList.size(), 3); + QTest::touchEvent(window, touchDevice).release(0, p1, window); + QQuickTouchUtils::flush(window); + QCOMPARE(eventItem1->eventList.size(), 3); + eventItem1->eventList.clear(); + + // wait to avoid getting a double click event + QTest::qWait(qApp->styleHints()->mouseDoubleClickInterval() + 10); + + // Accept touch + eventItem1->acceptTouch = true; + eventItem1->setAcceptedMouseButtons(Qt::LeftButton); + p1 = QPoint(20, 20); + QTest::touchEvent(window, touchDevice).press(0, p1, window); + QQuickTouchUtils::flush(window); + QCOMPARE(eventItem1->eventList.size(), 2); + QCOMPARE(eventItem1->eventList.at(0).type, QEvent::Pointer); + QCOMPARE(eventItem1->eventList.at(1).type, QEvent::TouchBegin); + p1 += QPoint(10, 0); + QTest::touchEvent(window, touchDevice).move(0, p1, window); + QQuickTouchUtils::flush(window); + QCOMPARE(eventItem1->eventList.size(), 4); + QCOMPARE(eventItem1->eventList.at(2).type, QEvent::Pointer); + QCOMPARE(eventItem1->eventList.at(3).type, QEvent::TouchUpdate); + QTest::touchEvent(window, touchDevice).release(0, p1, window); + QQuickTouchUtils::flush(window); + QCOMPARE(eventItem1->eventList.size(), 6); + QCOMPARE(eventItem1->eventList.at(4).type, QEvent::Pointer); + QCOMPARE(eventItem1->eventList.at(5).type, QEvent::TouchEnd); + eventItem1->eventList.clear(); + + // Accept pointer events + eventItem1->acceptPointer = true; + p1 = QPoint(20, 20); + QTest::touchEvent(window, touchDevice).press(0, p1, window); + QQuickTouchUtils::flush(window); + QCOMPARE(eventItem1->eventList.size(), 1); + QCOMPARE(eventItem1->eventList.at(0).type, QEvent::Pointer); + p1 += QPoint(10, 0); + QTest::touchEvent(window, touchDevice).move(0, p1, window); + QQuickTouchUtils::flush(window); + QCOMPARE(eventItem1->eventList.size(), 2); + QCOMPARE(eventItem1->eventList.at(1).type, QEvent::Pointer); + QTest::touchEvent(window, touchDevice).release(0, p1, window); + QQuickTouchUtils::flush(window); + QCOMPARE(eventItem1->eventList.size(), 3); + QCOMPARE(eventItem1->eventList.at(2).type, QEvent::Pointer); + eventItem1->eventList.clear(); + + delete window; +} + +void tst_PointerHandlers::mouseEventDelivery() +{ + QQuickView *window = createView(); + + window->setSource(testFileUrl("singleitem.qml")); + window->show(); + QVERIFY(QTest::qWaitForWindowExposed(window)); + window->requestActivate(); + QVERIFY(QTest::qWaitForWindowActive(window)); + QVERIFY(window->rootObject() != 0); + + EventItem *eventItem1 = window->rootObject()->findChild("eventItem1"); + QVERIFY(eventItem1); + + // Do not accept anything + QPoint p1 = QPoint(20, 20); + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, p1); + QCOMPARE(eventItem1->eventList.size(), 2); + p1 += QPoint(10, 0); + QTest::mouseMove(window, p1); + QCOMPARE(eventItem1->eventList.size(), 2); + QTest::mouseRelease(window, Qt::LeftButton); + QCOMPARE(eventItem1->eventList.size(), 2); + 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::mousePress(window, Qt::LeftButton, Qt::NoModifier, p1); + QCOMPARE(eventItem1->eventList.size(), 2); + QCOMPARE(eventItem1->eventList.at(0).type, QEvent::Pointer); + QCOMPARE(eventItem1->eventList.at(1).type, QEvent::MouseButtonPress); + QCOMPARE(window->mouseGrabberItem(), eventItem1); + + QPointF localPos = eventItem1->mapFromScene(p1); + QPointF scenePos = p1; // item is at 0,0 + QCOMPARE(eventItem1->eventList.at(0).posWrtItem, localPos); + QCOMPARE(eventItem1->eventList.at(0).posWrtScene, scenePos); + QCOMPARE(eventItem1->eventList.at(1).posWrtItem, localPos); + QCOMPARE(eventItem1->eventList.at(1).posWrtScene, scenePos); + + p1 += QPoint(10, 0); + QTest::mouseMove(window, p1); + QCOMPARE(eventItem1->eventList.size(), 4); + QCOMPARE(eventItem1->eventList.at(2).type, QEvent::Pointer); + QCOMPARE(eventItem1->eventList.at(3).type, QEvent::MouseMove); + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p1); + QCOMPARE(eventItem1->eventList.size(), 7); + QCOMPARE(eventItem1->eventList.at(4).type, QEvent::Pointer); + QCOMPARE(eventItem1->eventList.at(5).type, QEvent::MouseButtonRelease); + QCOMPARE(eventItem1->eventList.at(6).type, QEvent::UngrabMouse); + eventItem1->eventList.clear(); + + // wait to avoid getting a double click event + QTest::qWait(qApp->styleHints()->mouseDoubleClickInterval() + 10); + + // Accept pointer events + eventItem1->acceptPointer = true; + p1 = QPoint(20, 20); + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, p1); + QTRY_COMPARE(eventItem1->eventList.size(), 1); + QCOMPARE(eventItem1->eventList.at(0).type, QEvent::Pointer); + p1 += QPoint(10, 0); + QTest::mouseMove(window, p1); + QCOMPARE(eventItem1->eventList.size(), 2); + QCOMPARE(eventItem1->eventList.at(1).type, QEvent::Pointer); + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p1); + QCOMPARE(eventItem1->eventList.size(), 3); + QCOMPARE(eventItem1->eventList.at(2).type, QEvent::Pointer); + eventItem1->eventList.clear(); + + delete window; +} + +QTEST_MAIN(tst_PointerHandlers) + +#include "tst_pointerhandlers.moc" + diff --git a/tests/auto/quick/quick.pro b/tests/auto/quick/quick.pro index 70e5b8ef6a..8bf805e18d 100644 --- a/tests/auto/quick/quick.pro +++ b/tests/auto/quick/quick.pro @@ -46,6 +46,7 @@ PRIVATETESTS += \ !qtHaveModule(xmlpatterns): PRIVATETESTS -= qquickxmllistmodel QUICKTESTS = \ + pointerhandlers \ qquickaccessible \ qquickanchors \ qquickanimatedimage \ -- cgit v1.2.3 From 8a06075f48ad352acfc70111682e7decf8fedb33 Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Mon, 8 Aug 2016 17:09:15 +0200 Subject: QQuickEventPoint::grabber: allow grabbing either an item or a handler MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit QQuickPointerHandler and QQuickItem have only QObject in common. Change-Id: I8fb68cc1779f42049db1e0eb5ff60019a1c674d3 Reviewed-by: Jan Arve Sæther --- tests/auto/quick/pointerhandlers/tst_pointerhandlers.cpp | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'tests') diff --git a/tests/auto/quick/pointerhandlers/tst_pointerhandlers.cpp b/tests/auto/quick/pointerhandlers/tst_pointerhandlers.cpp index bed1721a52..7d2842d688 100644 --- a/tests/auto/quick/pointerhandlers/tst_pointerhandlers.cpp +++ b/tests/auto/quick/pointerhandlers/tst_pointerhandlers.cpp @@ -429,20 +429,19 @@ void tst_PointerHandlers::mouseEventDelivery() p1 += QPoint(10, 0); QTest::mouseMove(window, p1); - QCOMPARE(eventItem1->eventList.size(), 4); - QCOMPARE(eventItem1->eventList.at(2).type, QEvent::Pointer); - QCOMPARE(eventItem1->eventList.at(3).type, QEvent::MouseMove); + QCOMPARE(eventItem1->eventList.size(), 3); + QCOMPARE(eventItem1->eventList.at(2).type, QEvent::MouseMove); QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p1); - QCOMPARE(eventItem1->eventList.size(), 7); - QCOMPARE(eventItem1->eventList.at(4).type, QEvent::Pointer); - QCOMPARE(eventItem1->eventList.at(5).type, QEvent::MouseButtonRelease); - QCOMPARE(eventItem1->eventList.at(6).type, QEvent::UngrabMouse); + QCOMPARE(eventItem1->eventList.size(), 5); + QCOMPARE(eventItem1->eventList.at(3).type, QEvent::MouseButtonRelease); + QCOMPARE(eventItem1->eventList.at(4).type, QEvent::UngrabMouse); eventItem1->eventList.clear(); // wait to avoid getting a double click event QTest::qWait(qApp->styleHints()->mouseDoubleClickInterval() + 10); // Accept pointer events + eventItem1->acceptMouse = false; eventItem1->acceptPointer = true; p1 = QPoint(20, 20); QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, p1); -- cgit v1.2.3 From 524686cf13aa5647eae4ebb630d58396862027e5 Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Wed, 3 Aug 2016 15:44:19 +0200 Subject: add PointerHandler manual test project MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit QML manual tests will be added to test specific handlers later. Change-Id: I691cff23f97fc79020d1090448e70a78de3b4be9 Reviewed-by: Jan Arve Sæther --- tests/manual/pointer/main.cpp | 51 ++++++++++++++++++++++++++++++++++++ tests/manual/pointer/main.qml | 56 ++++++++++++++++++++++++++++++++++++++++ tests/manual/pointer/pointer.pro | 7 +++++ tests/manual/pointer/qml.qrc | 5 ++++ 4 files changed, 119 insertions(+) create mode 100644 tests/manual/pointer/main.cpp create mode 100644 tests/manual/pointer/main.qml create mode 100644 tests/manual/pointer/pointer.pro create mode 100644 tests/manual/pointer/qml.qrc (limited to 'tests') diff --git a/tests/manual/pointer/main.cpp b/tests/manual/pointer/main.cpp new file mode 100644 index 0000000000..a4e1060cf5 --- /dev/null +++ b/tests/manual/pointer/main.cpp @@ -0,0 +1,51 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the manual tests of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include +#include + +int main(int argc, char *argv[]) +{ + QGuiApplication app(argc, argv); + + QQmlApplicationEngine engine; + engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); + + return app.exec(); +} diff --git a/tests/manual/pointer/main.qml b/tests/manual/pointer/main.qml new file mode 100644 index 0000000000..aad848c8f0 --- /dev/null +++ b/tests/manual/pointer/main.qml @@ -0,0 +1,56 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the manual tests of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.8 +import QtQuick.Window 2.2 +import "qrc:/quick/shared/" as Examples + +Window { + width: 800 + height: 600 + visible: true + Examples.LauncherList { + id: ll + anchors.fill: parent + Component.onCompleted: { +// addExample("pointer", "PointerHandler: demonstrate the basics", Qt.resolvedUrl("pointerHandler.qml")) + } + } +} diff --git a/tests/manual/pointer/pointer.pro b/tests/manual/pointer/pointer.pro new file mode 100644 index 0000000000..3705d41df0 --- /dev/null +++ b/tests/manual/pointer/pointer.pro @@ -0,0 +1,7 @@ +TEMPLATE = app + +QT += qml quick + +SOURCES += main.cpp + +RESOURCES += qml.qrc ../../../examples/quick/shared/quick_shared.qrc diff --git a/tests/manual/pointer/qml.qrc b/tests/manual/pointer/qml.qrc new file mode 100644 index 0000000000..5f6483ac33 --- /dev/null +++ b/tests/manual/pointer/qml.qrc @@ -0,0 +1,5 @@ + + + main.qml + + -- cgit v1.2.3 From 124181973f586a67990c9a68e25a3642623b998a Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Mon, 18 Jul 2016 14:22:15 +0200 Subject: Introduce DragHandler MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A handler for dragging Items around by touch or mouse. Change-Id: Id83fea568095eb6374f3f1abc6f550d81f3731df Reviewed-by: Jan Arve Sæther --- .../qquickdraghandler/data/reparenting.qml | 60 +++++++++++ tests/manual/pointer/content/Slider.qml | 117 +++++++++++++++++++++ tests/manual/pointer/joystick.qml | 75 +++++++++++++ tests/manual/pointer/main.qml | 3 +- tests/manual/pointer/mixer.qml | 72 +++++++++++++ tests/manual/pointer/qml.qrc | 6 ++ tests/manual/pointer/resources/mixer-knob.png | Bin 0 -> 8555 bytes tests/manual/pointer/resources/redball.png | Bin 0 -> 10002 bytes 8 files changed, 332 insertions(+), 1 deletion(-) create mode 100644 tests/auto/quick/handlers/qquickdraghandler/data/reparenting.qml create mode 100644 tests/manual/pointer/content/Slider.qml create mode 100644 tests/manual/pointer/joystick.qml create mode 100644 tests/manual/pointer/mixer.qml create mode 100644 tests/manual/pointer/resources/mixer-knob.png create mode 100644 tests/manual/pointer/resources/redball.png (limited to 'tests') diff --git a/tests/auto/quick/handlers/qquickdraghandler/data/reparenting.qml b/tests/auto/quick/handlers/qquickdraghandler/data/reparenting.qml new file mode 100644 index 0000000000..3545badd86 --- /dev/null +++ b/tests/auto/quick/handlers/qquickdraghandler/data/reparenting.qml @@ -0,0 +1,60 @@ +import QtQuick 2.8 +import Qt.labs.handlers 1.0 + +Grid { + id: root + objectName: "root" + property bool reparentOnDrag: true + width: 200; height: 200 + columns: 3 + spacing: 10 + Repeater { + model: 9 + anchors.fill: parent + Item { + id: gridPlaceholder + objectName: "gridPlaceholder" + index + width: 60 + height: 60 + Rectangle { + id: icon + border.color: "black" + color: "beige" + radius: 3 + width: 60 + height: 60 + onParentChanged :console.log("parent " + parent) + anchors { + horizontalCenter: parent.horizontalCenter + verticalCenter: parent.verticalCenter + } + DragHandler { + id: dragArea + } + Text { + anchors.centerIn: parent + text: index + "@" + Math.round(icon.x) + "," + Math.round(icon.y) + font.pointSize: 8 + } + states: [ + State { + when: dragArea.dragging + AnchorChanges { + target: icon + anchors.horizontalCenter: undefined + anchors.verticalCenter: undefined + } + ParentChange { + target: root.reparentOnDrag ? icon : null + parent: root + } + PropertyChanges { + target: icon + color: "yellow" + } + } + ] + } + } + } +} diff --git a/tests/manual/pointer/content/Slider.qml b/tests/manual/pointer/content/Slider.qml new file mode 100644 index 0000000000..363f6911d4 --- /dev/null +++ b/tests/manual/pointer/content/Slider.qml @@ -0,0 +1,117 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the manual tests of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.8 +import Qt.labs.handlers 1.0 + +Item { + id: root + property int value: 50 + property int maximumValue: 99 + property alias label: label.text + + Rectangle { + id: slot + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.margins: 10 + anchors.topMargin: 30 + anchors.bottomMargin: 30 + anchors.horizontalCenter: parent.horizontalCenter + width: 10 + color: "black" + radius: width / 2 + smooth: true + } + + Rectangle { + // RectangularGlow is better, but that's a different module + id: glow + anchors.fill: knob + anchors.margins: -5 + anchors.leftMargin: -2 + anchors.horizontalCenterOffset: 1 + radius: 5 + color: "#4400FFFF" + visible: dragHandler.dragging + } + Image { + id: knob + source: "../resources/mixer-knob.png" + antialiasing: true + x: slot.x - width / 2 + slot.width / 2 + height: root.width / 2 + width: implicitWidth / implicitHeight * height + property bool programmatic: false + property real multiplier: root.maximumValue / (dragHandler.yAxis.maximum - dragHandler.yAxis.minimum) + onYChanged: if (!programmatic) root.value = root.maximumValue - (knob.y - dragHandler.yAxis.minimum) * multiplier + transformOrigin: Item.Center + function setValue(value) { knob.y = dragHandler.yAxis.maximum - value / knob.multiplier } + DragHandler { + id: dragHandler + xAxis.enabled: false + yAxis.minimum: slot.y + yAxis.maximum: slot.height + slot.y - knob.height + } + } + + Text { + font.pointSize: 16 + color: "red" + anchors.bottom: parent.bottom + anchors.horizontalCenter: parent.horizontalCenter + text: root.value + } + + Text { + id: label + font.pointSize: 12 + color: "red" + anchors.top: parent.top + anchors.topMargin: 5 + anchors.horizontalCenter: parent.horizontalCenter + } + + onHeightChanged: { + knob.programmatic = true + knob.setValue(root.value) + knob.programmatic = false + } +} diff --git a/tests/manual/pointer/joystick.qml b/tests/manual/pointer/joystick.qml new file mode 100644 index 0000000000..7959eaea42 --- /dev/null +++ b/tests/manual/pointer/joystick.qml @@ -0,0 +1,75 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the manual tests of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.8 +import Qt.labs.handlers 1.0 + +Rectangle { + width: 480 + height: 480 + color: "black" + + Image { + id: knob + source: "resources/redball.png" + anchors { + horizontalCenter: parent.horizontalCenter + verticalCenter: parent.verticalCenter + } + DragHandler { + id: dragHandler + } + states: [ + State { + when: dragHandler.dragging + AnchorChanges { + target: knob + anchors.horizontalCenter: undefined + anchors.verticalCenter: undefined + } + } + ] + transitions: [ + Transition { + AnchorAnimation { easing.type: Easing.OutElastic } + } + ] + } +} diff --git a/tests/manual/pointer/main.qml b/tests/manual/pointer/main.qml index aad848c8f0..efe603c57f 100644 --- a/tests/manual/pointer/main.qml +++ b/tests/manual/pointer/main.qml @@ -50,7 +50,8 @@ Window { id: ll anchors.fill: parent Component.onCompleted: { -// addExample("pointer", "PointerHandler: demonstrate the basics", Qt.resolvedUrl("pointerHandler.qml")) + addExample("joystick", "DragHandler: move one item inside another with any pointing device", Qt.resolvedUrl("joystick.qml")) + addExample("mixer", "mixing console", Qt.resolvedUrl("mixer.qml")) } } } diff --git a/tests/manual/pointer/mixer.qml b/tests/manual/pointer/mixer.qml new file mode 100644 index 0000000000..84ad975340 --- /dev/null +++ b/tests/manual/pointer/mixer.qml @@ -0,0 +1,72 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the manual tests of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.8 +import Qt.labs.handlers 1.0 +import "content" + +Rectangle { + id: root + width: 1280 + height: 960 + objectName: "root" + color: "#222222" + + ListView { + id: list + objectName: "listView" + anchors.fill: parent + anchors.margins: 10 + orientation: Qt.Horizontal + + model: 20 + + delegate: Item { + objectName: "delegateItem" + index + width: 154 + height: list.height + + Slider { + anchors.fill: parent + label: "Channel " + (index + 1) + } + } + } +} diff --git a/tests/manual/pointer/qml.qrc b/tests/manual/pointer/qml.qrc index 5f6483ac33..b802a73f08 100644 --- a/tests/manual/pointer/qml.qrc +++ b/tests/manual/pointer/qml.qrc @@ -1,5 +1,11 @@ main.qml + joystick.qml + main.qml + mixer.qml + content/Slider.qml + resources/mixer-knob.png + resources/redball.png diff --git a/tests/manual/pointer/resources/mixer-knob.png b/tests/manual/pointer/resources/mixer-knob.png new file mode 100644 index 0000000000..02cc9fc72b Binary files /dev/null and b/tests/manual/pointer/resources/mixer-knob.png differ diff --git a/tests/manual/pointer/resources/redball.png b/tests/manual/pointer/resources/redball.png new file mode 100644 index 0000000000..68d2e1d638 Binary files /dev/null and b/tests/manual/pointer/resources/redball.png differ -- cgit v1.2.3 From 678d3de4b53f22ead68a0874df2892137ad3b7f7 Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Tue, 11 Aug 2015 18:14:02 +0200 Subject: Introduce PinchHandler MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Similar to PinchArea but with improvements: - Allows rotating and scaling about an arbitrary point rather than the center - It's possible to require more than 2 fingers. E.g. maybe you use 3 fingers to manage a window, 2 fingers to manipulate content inside. This could be achieved with two independent PinchHandlers. Change-Id: Ifd40cfee115d7bc298378b26a58318bea40a8230 Reviewed-by: Jan Arve Sæther --- tests/manual/pointer/main.qml | 1 + tests/manual/pointer/pinchHandler.qml | 93 +++++++++++++++++++++++++++++++++++ tests/manual/pointer/qml.qrc | 2 +- 3 files changed, 95 insertions(+), 1 deletion(-) create mode 100644 tests/manual/pointer/pinchHandler.qml (limited to 'tests') diff --git a/tests/manual/pointer/main.qml b/tests/manual/pointer/main.qml index efe603c57f..45a339b302 100644 --- a/tests/manual/pointer/main.qml +++ b/tests/manual/pointer/main.qml @@ -52,6 +52,7 @@ Window { Component.onCompleted: { addExample("joystick", "DragHandler: move one item inside another with any pointing device", Qt.resolvedUrl("joystick.qml")) addExample("mixer", "mixing console", Qt.resolvedUrl("mixer.qml")) + addExample("pinch", "PinchHandler: scale, rotate and drag", Qt.resolvedUrl("pinchHandler.qml")) } } } diff --git a/tests/manual/pointer/pinchHandler.qml b/tests/manual/pointer/pinchHandler.qml new file mode 100644 index 0000000000..e4482a249d --- /dev/null +++ b/tests/manual/pointer/pinchHandler.qml @@ -0,0 +1,93 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the manual tests of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.8 +import Qt.labs.handlers 1.0 + +Rectangle { + id: root + width: 1024; height: 600 + color: "black" + + Rectangle { + width: 400 + height: 300 + color: "lightsteelblue" + antialiasing: true + + Text { + anchors.centerIn: parent + text: "Pinch with 2 fingers to scale & rotate\nDrag with 1 finger\ncurrent rotation " + pinch2.rotation.toFixed(1) + } + + DragHandler { objectName: "DragHandler" } + + PinchHandler { + id: pinch2 + objectName: "2-finger pinch" + minimumRotation: -45 + maximumRotation: 45 + minimumScale: 0.1 + maximumScale: 10 + pointDistanceThreshold: 150 + } + } + + Rectangle { + x: 512 + width: 400 + height: 300 + color: "wheat" + antialiasing: true + + Text { + anchors.centerIn: parent + text: "Pinch with 3 fingers to scale & rotate\ncurrent rotation " + pinch3.rotation.toFixed(1) + } + + PinchHandler { + id: pinch3 + objectName: "3-finger pinch" + requiredPointCount: 3 + minimumScale: 0.1 + maximumScale: 10 + } + } +} diff --git a/tests/manual/pointer/qml.qrc b/tests/manual/pointer/qml.qrc index b802a73f08..dac6b08b12 100644 --- a/tests/manual/pointer/qml.qrc +++ b/tests/manual/pointer/qml.qrc @@ -2,8 +2,8 @@ main.qml joystick.qml - main.qml mixer.qml + pinchHandler.qml content/Slider.qml resources/mixer-knob.png resources/redball.png -- cgit v1.2.3 From 65c3548c433bf5c9c5e2d962c8ec6af3b65f2bb8 Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Wed, 29 Jun 2016 11:37:19 +0200 Subject: add a map example as a manual test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The public-domain map is adapted from https://openclipart.org/detail/67039/ Change-Id: Ia3da049174a38a6cc9e9632eda4f4553ad16d3bf Reviewed-by: Jan Arve Sæther --- tests/manual/pointer/main.qml | 1 + tests/manual/pointer/map.qml | 74 ++++++++++++++++++++++++++++++++ tests/manual/pointer/qml.qrc | 2 + tests/manual/pointer/resources/map.svgz | Bin 0 -> 27956 bytes 4 files changed, 77 insertions(+) create mode 100644 tests/manual/pointer/map.qml create mode 100644 tests/manual/pointer/resources/map.svgz (limited to 'tests') diff --git a/tests/manual/pointer/main.qml b/tests/manual/pointer/main.qml index 45a339b302..7ba0d9a466 100644 --- a/tests/manual/pointer/main.qml +++ b/tests/manual/pointer/main.qml @@ -53,6 +53,7 @@ Window { addExample("joystick", "DragHandler: move one item inside another with any pointing device", Qt.resolvedUrl("joystick.qml")) addExample("mixer", "mixing console", Qt.resolvedUrl("mixer.qml")) addExample("pinch", "PinchHandler: scale, rotate and drag", Qt.resolvedUrl("pinchHandler.qml")) + addExample("map", "scale and pan", Qt.resolvedUrl("map.qml")) } } } diff --git a/tests/manual/pointer/map.qml b/tests/manual/pointer/map.qml new file mode 100644 index 0000000000..e1ca889064 --- /dev/null +++ b/tests/manual/pointer/map.qml @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the manual tests of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.8 +import Qt.labs.handlers 1.0 + +Item { + width: 640 + height: 480 + + Rectangle { + id: map + color: "aqua" + x: (parent.width - width) / 2 + y: (parent.height - height) / 2 + width: image.implicitWidth + height: image.implicitHeight + + Image { + id: image + anchors.centerIn: parent + fillMode: Image.PreserveAspectFit + source: "resources/map.svgz" + } + } + + PinchHandler { + id: pinch + target: map + minimumScale: 0.1 + maximumScale: 10 + } + + DragHandler { + target: map + } +} diff --git a/tests/manual/pointer/qml.qrc b/tests/manual/pointer/qml.qrc index dac6b08b12..3d7de4b728 100644 --- a/tests/manual/pointer/qml.qrc +++ b/tests/manual/pointer/qml.qrc @@ -2,9 +2,11 @@ main.qml joystick.qml + map.qml mixer.qml pinchHandler.qml content/Slider.qml + resources/map.svgz resources/mixer-knob.png resources/redball.png diff --git a/tests/manual/pointer/resources/map.svgz b/tests/manual/pointer/resources/map.svgz new file mode 100644 index 0000000000..64d509c106 Binary files /dev/null and b/tests/manual/pointer/resources/map.svgz differ -- cgit v1.2.3 From 4f26b351913c80c8d0a339b0361aea22e904ddf7 Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Sun, 28 Aug 2016 08:54:31 +0200 Subject: move qquickpointerhandler test to a subdirectory MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Tests will become too complex to do them all in one class, so let's have a subdirectory for each handler. Change-Id: I157f6c150f15ca53d77bc9eb716723c6105e393a Reviewed-by: Jan Arve Sæther --- .../auto/quick/pointerhandlers/data/singleitem.qml | 22 - .../auto/quick/pointerhandlers/pointerhandlers.pro | 19 +- .../qquickpointerhandler/data/singleitem.qml | 22 + .../qquickpointerhandler/qquickpointerhandler.pro | 16 + .../tst_qquickpointerhandler.cpp | 465 +++++++++++++++++++++ .../quick/pointerhandlers/tst_pointerhandlers.cpp | 465 --------------------- 6 files changed, 508 insertions(+), 501 deletions(-) delete mode 100644 tests/auto/quick/pointerhandlers/data/singleitem.qml create mode 100644 tests/auto/quick/pointerhandlers/qquickpointerhandler/data/singleitem.qml create mode 100644 tests/auto/quick/pointerhandlers/qquickpointerhandler/qquickpointerhandler.pro create mode 100644 tests/auto/quick/pointerhandlers/qquickpointerhandler/tst_qquickpointerhandler.cpp delete mode 100644 tests/auto/quick/pointerhandlers/tst_pointerhandlers.cpp (limited to 'tests') diff --git a/tests/auto/quick/pointerhandlers/data/singleitem.qml b/tests/auto/quick/pointerhandlers/data/singleitem.qml deleted file mode 100644 index fe05a3f935..0000000000 --- a/tests/auto/quick/pointerhandlers/data/singleitem.qml +++ /dev/null @@ -1,22 +0,0 @@ -import QtQuick 2.8 -import Qt.test 1.0 - -Rectangle { - id: root - width: 320 - height: 480 - color: "green" - - EventItem { - objectName: "eventItem1" - x: 5 - y: 5 - height: 30 - width: 30 - - EventHandler { - - } - } -} - diff --git a/tests/auto/quick/pointerhandlers/pointerhandlers.pro b/tests/auto/quick/pointerhandlers/pointerhandlers.pro index 41e1196965..4a3f99765e 100644 --- a/tests/auto/quick/pointerhandlers/pointerhandlers.pro +++ b/tests/auto/quick/pointerhandlers/pointerhandlers.pro @@ -1,16 +1,7 @@ -CONFIG += testcase +TEMPLATE = subdirs -TARGET = tst_pointerhandlers -QT += core-private gui-private qml-private quick-private testlib - -macos:CONFIG -= app_bundle - -SOURCES += tst_pointerhandlers.cpp - -include (../../shared/util.pri) -include (../shared/util.pri) - -TESTDATA = data/* - -# OTHER_FILES += data/foo.qml +qtConfig(private_tests) { + SUBDIRS += \ + qquickpointerhandler \ +} diff --git a/tests/auto/quick/pointerhandlers/qquickpointerhandler/data/singleitem.qml b/tests/auto/quick/pointerhandlers/qquickpointerhandler/data/singleitem.qml new file mode 100644 index 0000000000..fe05a3f935 --- /dev/null +++ b/tests/auto/quick/pointerhandlers/qquickpointerhandler/data/singleitem.qml @@ -0,0 +1,22 @@ +import QtQuick 2.8 +import Qt.test 1.0 + +Rectangle { + id: root + width: 320 + height: 480 + color: "green" + + EventItem { + objectName: "eventItem1" + x: 5 + y: 5 + height: 30 + width: 30 + + EventHandler { + + } + } +} + diff --git a/tests/auto/quick/pointerhandlers/qquickpointerhandler/qquickpointerhandler.pro b/tests/auto/quick/pointerhandlers/qquickpointerhandler/qquickpointerhandler.pro new file mode 100644 index 0000000000..c386969206 --- /dev/null +++ b/tests/auto/quick/pointerhandlers/qquickpointerhandler/qquickpointerhandler.pro @@ -0,0 +1,16 @@ +CONFIG += testcase + +TARGET = tst_qquickpointerhandler +QT += core-private gui-private qml-private quick-private testlib + +macos:CONFIG -= app_bundle + +SOURCES += tst_qquickpointerhandler.cpp + +include (../../../shared/util.pri) +include (../../shared/util.pri) + +TESTDATA = data/* + +# OTHER_FILES += data/foo.qml + diff --git a/tests/auto/quick/pointerhandlers/qquickpointerhandler/tst_qquickpointerhandler.cpp b/tests/auto/quick/pointerhandlers/qquickpointerhandler/tst_qquickpointerhandler.cpp new file mode 100644 index 0000000000..94bb44a12b --- /dev/null +++ b/tests/auto/quick/pointerhandlers/qquickpointerhandler/tst_qquickpointerhandler.cpp @@ -0,0 +1,465 @@ +/**************************************************************************** +** +** 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 + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include "../../../shared/util.h" +#include "../../shared/viewtestutil.h" + +Q_LOGGING_CATEGORY(lcPointerTests, "qt.quick.pointer.tests") + +struct Event +{ + Event(QEvent::Type t, QPointF item, QPointF scene) + :type(t), posWrtItem(item), posWrtScene(scene) + {} + + QEvent::Type type; + QPointF posWrtItem; + QPointF posWrtScene; + +}; + +#ifndef QT_NO_DEBUG_STREAM +QDebug operator<<(QDebug dbg, const struct Event &event) { + QDebugStateSaver saver(dbg); + dbg.nospace(); + dbg << "Event(" << event.type << " @" << event.posWrtScene << ")"; + return dbg; +} +#endif + +class EventItem : public QQuickItem +{ + Q_OBJECT +public: + EventItem(QQuickItem *parent = 0) + : QQuickItem(parent), acceptPointer(false), acceptMouse(false), acceptTouch(false), filterTouch(false) + {} + + void touchEvent(QTouchEvent *event) + { + qCDebug(lcPointerTests) << event << "will accept?" << acceptTouch; + for (const QTouchEvent::TouchPoint &tp : event->touchPoints()) + eventList.append(Event(event->type(), tp.pos(), tp.scenePos())); + event->setAccepted(acceptTouch); + } + void mousePressEvent(QMouseEvent *event) + { + qCDebug(lcPointerTests) << event; + eventList.append(Event(event->type(), event->pos(), event->windowPos())); + event->setAccepted(acceptMouse); + } + void mouseMoveEvent(QMouseEvent *event) + { + qCDebug(lcPointerTests) << event; + eventList.append(Event(event->type(), event->pos(), event->windowPos())); + event->setAccepted(acceptMouse); + } + void mouseReleaseEvent(QMouseEvent *event) + { + qCDebug(lcPointerTests) << event; + eventList.append(Event(event->type(), event->pos(), event->windowPos())); + event->setAccepted(acceptMouse); + } + void mouseDoubleClickEvent(QMouseEvent *event) + { + qCDebug(lcPointerTests) << event; + eventList.append(Event(event->type(), event->pos(), event->windowPos())); + event->setAccepted(acceptMouse); + } + + void mouseUngrabEvent() + { + qCDebug(lcPointerTests); + eventList.append(Event(QEvent::UngrabMouse, QPoint(0,0), QPoint(0,0))); + } + + bool event(QEvent *event) + { + qCDebug(lcPointerTests) << event; + return QQuickItem::event(event); + } + + QList eventList; + bool acceptPointer; + bool acceptMouse; + bool acceptTouch; + bool filterTouch; // when used as event filter + + bool eventFilter(QObject *o, QEvent *event) + { + qCDebug(lcPointerTests) << event << o; + if (event->type() == QEvent::TouchBegin || + event->type() == QEvent::TouchUpdate || + event->type() == QEvent::TouchCancel || + event->type() == QEvent::TouchEnd) { + QTouchEvent *touch = static_cast(event); + for (const QTouchEvent::TouchPoint &tp : touch->touchPoints()) + eventList.append(Event(event->type(), tp.pos(), tp.scenePos())); + if (filterTouch) + event->accept(); + return true; + } + return false; + } +}; + +class EventHandler : public QQuickPointerHandler +{ + void handlePointerEventImpl(QQuickPointerEvent *event) override + { + QQuickPointerHandler::handlePointerEventImpl(event); + if (!enabled()) + return; + EventItem *item = static_cast(target()); + qCDebug(lcPointerTests) << item->objectName() << event; + int c = event->pointCount(); + for (int i = 0; i < c; ++i) { + QQuickEventPoint *point = event->point(i); + point->setAccepted(item->acceptPointer); // has no effect: grabbing is up to us + if (item->acceptPointer) + setGrab(point, true); + qCDebug(lcPointerTests) << " " << i << ":" << point << "grabbed?" << item->acceptPointer; + item->eventList.append(Event(QEvent::Pointer, eventPos(point), point->scenePos())); + } + } +}; + +class tst_PointerHandlers : public QQmlDataTest +{ + Q_OBJECT +public: + tst_PointerHandlers() + :touchDevice(QTest::createTouchDevice()) + {} + +private slots: + void initTestCase(); + + void touchEventDelivery(); + void mouseEventDelivery(); + +protected: + bool eventFilter(QObject *, QEvent *event) + { + if (event->type() == QEvent::MouseButtonPress || + event->type() == QEvent::MouseMove || + event->type() == QEvent::MouseButtonRelease) { + QMouseEvent *me = static_cast(event); + filteredEventList.append(Event(me->type(), me->pos(), me->globalPos())); + } + return false; + } + +private: + QQuickView *createView(); + QTouchDevice *touchDevice; + QList filteredEventList; +}; + +QQuickView *tst_PointerHandlers::createView() +{ + QQuickView *window = new QQuickView(0); + window->setGeometry(0,0,240,320); + + return window; +} + +void tst_PointerHandlers::initTestCase() +{ + // This test assumes that we don't get synthesized mouse events from QGuiApplication + qApp->setAttribute(Qt::AA_SynthesizeMouseForUnhandledTouchEvents, false); + + QQmlDataTest::initTestCase(); + qmlRegisterType("Qt.test", 1, 0, "EventItem"); + qmlRegisterType("Qt.test", 1, 0, "EventHandler"); +} + +void tst_PointerHandlers::touchEventDelivery() +{ + QQuickView *window = createView(); + + window->setSource(testFileUrl("singleitem.qml")); + window->show(); + QVERIFY(QTest::qWaitForWindowExposed(window)); + window->requestActivate(); + QVERIFY(QTest::qWaitForWindowActive(window)); + QVERIFY(window->rootObject() != 0); + + EventItem *eventItem1 = window->rootObject()->findChild("eventItem1"); + QVERIFY(eventItem1); + + // Do not accept anything + QPoint p1 = QPoint(20, 20); + QTest::touchEvent(window, touchDevice).press(0, p1, window); + QQuickTouchUtils::flush(window); + QTRY_COMPARE(eventItem1->eventList.size(), 3); + QCOMPARE(eventItem1->eventList.at(0).type, QEvent::Pointer); + QCOMPARE(eventItem1->eventList.at(1).type, QEvent::TouchBegin); + QCOMPARE(eventItem1->eventList.at(2).type, QEvent::MouseButtonPress); + p1 += QPoint(10, 0); + QTest::touchEvent(window, touchDevice).move(0, p1, window); + QQuickTouchUtils::flush(window); + QCOMPARE(eventItem1->eventList.size(), 3); + QTest::touchEvent(window, touchDevice).release(0, p1, window); + QQuickTouchUtils::flush(window); + QCOMPARE(eventItem1->eventList.size(), 3); + eventItem1->eventList.clear(); + + // Accept touch + eventItem1->acceptTouch = true; + p1 = QPoint(20, 20); + QTest::touchEvent(window, touchDevice).press(0, p1, window); + QQuickTouchUtils::flush(window); + QCOMPARE(eventItem1->eventList.size(), 2); + QCOMPARE(eventItem1->eventList.at(0).type, QEvent::Pointer); + QCOMPARE(eventItem1->eventList.at(1).type, QEvent::TouchBegin); + auto pointerEvent = QQuickPointerDevice::touchDevices().at(0)->pointerEvent(); + QCOMPARE(pointerEvent->point(0)->grabber(), eventItem1); + p1 += QPoint(10, 0); + QTest::touchEvent(window, touchDevice).move(0, p1, window); + QQuickTouchUtils::flush(window); + QCOMPARE(eventItem1->eventList.size(), 4); + QCOMPARE(eventItem1->eventList.at(2).type, QEvent::Pointer); + QCOMPARE(eventItem1->eventList.at(3).type, QEvent::TouchUpdate); + QTest::touchEvent(window, touchDevice).release(0, p1, window); + QQuickTouchUtils::flush(window); + QCOMPARE(eventItem1->eventList.size(), 6); + QCOMPARE(eventItem1->eventList.at(4).type, QEvent::Pointer); + QCOMPARE(eventItem1->eventList.at(5).type, QEvent::TouchEnd); + 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, touchDevice).press(0, p1, window); + QQuickTouchUtils::flush(window); + QCOMPARE(eventItem1->eventList.size(), 3); + QCOMPARE(eventItem1->eventList.at(0).type, QEvent::Pointer); + QCOMPARE(eventItem1->eventList.at(1).type, QEvent::TouchBegin); + QCOMPARE(eventItem1->eventList.at(2).type, QEvent::MouseButtonPress); + QCOMPARE(window->mouseGrabberItem(), eventItem1); + + QPointF localPos = eventItem1->mapFromScene(p1); + QPointF scenePos = p1; // item is at 0,0 + QCOMPARE(eventItem1->eventList.at(1).posWrtItem, localPos); + QCOMPARE(eventItem1->eventList.at(1).posWrtScene, scenePos); + QCOMPARE(eventItem1->eventList.at(2).posWrtItem, localPos); + QCOMPARE(eventItem1->eventList.at(2).posWrtScene, scenePos); + + p1 += QPoint(10, 0); + QTest::touchEvent(window, touchDevice).move(0, p1, window); + QQuickTouchUtils::flush(window); + QCOMPARE(eventItem1->eventList.size(), 6); + QCOMPARE(eventItem1->eventList.at(3).type, QEvent::Pointer); + QCOMPARE(eventItem1->eventList.at(4).type, QEvent::TouchUpdate); + QCOMPARE(eventItem1->eventList.at(5).type, QEvent::MouseMove); + QTest::touchEvent(window, touchDevice).release(0, p1, window); + QQuickTouchUtils::flush(window); + QCOMPARE(eventItem1->eventList.size(), 10); + QCOMPARE(eventItem1->eventList.at(6).type, QEvent::Pointer); + QCOMPARE(eventItem1->eventList.at(7).type, QEvent::TouchEnd); + QCOMPARE(eventItem1->eventList.at(8).type, QEvent::MouseButtonRelease); + QCOMPARE(eventItem1->eventList.at(9).type, QEvent::UngrabMouse); + eventItem1->eventList.clear(); + + // wait to avoid getting a double click event + QTest::qWait(qApp->styleHints()->mouseDoubleClickInterval() + 10); + + // Accept mouse buttons but not the touch event + eventItem1->acceptTouch = false; + eventItem1->acceptMouse = false; + eventItem1->setAcceptedMouseButtons(Qt::LeftButton); + p1 = QPoint(20, 20); + QTest::touchEvent(window, touchDevice).press(0, p1, window); + QQuickTouchUtils::flush(window); + QCOMPARE(eventItem1->eventList.size(), 3); + QCOMPARE(eventItem1->eventList.at(0).type, QEvent::Pointer); + QCOMPARE(eventItem1->eventList.at(1).type, QEvent::TouchBegin); + QCOMPARE(eventItem1->eventList.at(2).type, QEvent::MouseButtonPress); + QCOMPARE(pointerEvent->point(0)->grabber(), nullptr); + p1 += QPoint(10, 0); + QTest::touchEvent(window, touchDevice).move(0, p1, window); + QQuickTouchUtils::flush(window); + QCOMPARE(eventItem1->eventList.size(), 3); + QTest::touchEvent(window, touchDevice).release(0, p1, window); + QQuickTouchUtils::flush(window); + QCOMPARE(eventItem1->eventList.size(), 3); + eventItem1->eventList.clear(); + + // wait to avoid getting a double click event + QTest::qWait(qApp->styleHints()->mouseDoubleClickInterval() + 10); + + // Accept touch + eventItem1->acceptTouch = true; + eventItem1->setAcceptedMouseButtons(Qt::LeftButton); + p1 = QPoint(20, 20); + QTest::touchEvent(window, touchDevice).press(0, p1, window); + QQuickTouchUtils::flush(window); + QCOMPARE(eventItem1->eventList.size(), 2); + QCOMPARE(eventItem1->eventList.at(0).type, QEvent::Pointer); + QCOMPARE(eventItem1->eventList.at(1).type, QEvent::TouchBegin); + p1 += QPoint(10, 0); + QTest::touchEvent(window, touchDevice).move(0, p1, window); + QQuickTouchUtils::flush(window); + QCOMPARE(eventItem1->eventList.size(), 4); + QCOMPARE(eventItem1->eventList.at(2).type, QEvent::Pointer); + QCOMPARE(eventItem1->eventList.at(3).type, QEvent::TouchUpdate); + QTest::touchEvent(window, touchDevice).release(0, p1, window); + QQuickTouchUtils::flush(window); + QCOMPARE(eventItem1->eventList.size(), 6); + QCOMPARE(eventItem1->eventList.at(4).type, QEvent::Pointer); + QCOMPARE(eventItem1->eventList.at(5).type, QEvent::TouchEnd); + eventItem1->eventList.clear(); + + // Accept pointer events + eventItem1->acceptPointer = true; + p1 = QPoint(20, 20); + QTest::touchEvent(window, touchDevice).press(0, p1, window); + QQuickTouchUtils::flush(window); + QCOMPARE(eventItem1->eventList.size(), 1); + QCOMPARE(eventItem1->eventList.at(0).type, QEvent::Pointer); + p1 += QPoint(10, 0); + QTest::touchEvent(window, touchDevice).move(0, p1, window); + QQuickTouchUtils::flush(window); + QCOMPARE(eventItem1->eventList.size(), 2); + QCOMPARE(eventItem1->eventList.at(1).type, QEvent::Pointer); + QTest::touchEvent(window, touchDevice).release(0, p1, window); + QQuickTouchUtils::flush(window); + QCOMPARE(eventItem1->eventList.size(), 3); + QCOMPARE(eventItem1->eventList.at(2).type, QEvent::Pointer); + eventItem1->eventList.clear(); + + delete window; +} + +void tst_PointerHandlers::mouseEventDelivery() +{ + QQuickView *window = createView(); + + window->setSource(testFileUrl("singleitem.qml")); + window->show(); + QVERIFY(QTest::qWaitForWindowExposed(window)); + window->requestActivate(); + QVERIFY(QTest::qWaitForWindowActive(window)); + QVERIFY(window->rootObject() != 0); + + EventItem *eventItem1 = window->rootObject()->findChild("eventItem1"); + QVERIFY(eventItem1); + + // Do not accept anything + QPoint p1 = QPoint(20, 20); + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, p1); + QCOMPARE(eventItem1->eventList.size(), 2); + p1 += QPoint(10, 0); + QTest::mouseMove(window, p1); + QCOMPARE(eventItem1->eventList.size(), 2); + QTest::mouseRelease(window, Qt::LeftButton); + QCOMPARE(eventItem1->eventList.size(), 2); + 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::mousePress(window, Qt::LeftButton, Qt::NoModifier, p1); + QCOMPARE(eventItem1->eventList.size(), 2); + QCOMPARE(eventItem1->eventList.at(0).type, QEvent::Pointer); + QCOMPARE(eventItem1->eventList.at(1).type, QEvent::MouseButtonPress); + QCOMPARE(window->mouseGrabberItem(), eventItem1); + + QPointF localPos = eventItem1->mapFromScene(p1); + QPointF scenePos = p1; // item is at 0,0 + QCOMPARE(eventItem1->eventList.at(0).posWrtItem, localPos); + QCOMPARE(eventItem1->eventList.at(0).posWrtScene, scenePos); + QCOMPARE(eventItem1->eventList.at(1).posWrtItem, localPos); + QCOMPARE(eventItem1->eventList.at(1).posWrtScene, scenePos); + + p1 += QPoint(10, 0); + QTest::mouseMove(window, p1); + QCOMPARE(eventItem1->eventList.size(), 3); + QCOMPARE(eventItem1->eventList.at(2).type, QEvent::MouseMove); + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p1); + QCOMPARE(eventItem1->eventList.size(), 5); + QCOMPARE(eventItem1->eventList.at(3).type, QEvent::MouseButtonRelease); + QCOMPARE(eventItem1->eventList.at(4).type, QEvent::UngrabMouse); + eventItem1->eventList.clear(); + + // wait to avoid getting a double click event + QTest::qWait(qApp->styleHints()->mouseDoubleClickInterval() + 10); + + // Accept pointer events + eventItem1->acceptMouse = false; + eventItem1->acceptPointer = true; + p1 = QPoint(20, 20); + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, p1); + QTRY_COMPARE(eventItem1->eventList.size(), 1); + QCOMPARE(eventItem1->eventList.at(0).type, QEvent::Pointer); + p1 += QPoint(10, 0); + QTest::mouseMove(window, p1); + QCOMPARE(eventItem1->eventList.size(), 2); + QCOMPARE(eventItem1->eventList.at(1).type, QEvent::Pointer); + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p1); + QCOMPARE(eventItem1->eventList.size(), 3); + QCOMPARE(eventItem1->eventList.at(2).type, QEvent::Pointer); + eventItem1->eventList.clear(); + + delete window; +} + +QTEST_MAIN(tst_PointerHandlers) + +#include "tst_qquickpointerhandler.moc" + diff --git a/tests/auto/quick/pointerhandlers/tst_pointerhandlers.cpp b/tests/auto/quick/pointerhandlers/tst_pointerhandlers.cpp deleted file mode 100644 index 7d2842d688..0000000000 --- a/tests/auto/quick/pointerhandlers/tst_pointerhandlers.cpp +++ /dev/null @@ -1,465 +0,0 @@ -/**************************************************************************** -** -** 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 - -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include - -#include "../../shared/util.h" -#include "../shared/viewtestutil.h" - -Q_LOGGING_CATEGORY(lcPointerTests, "qt.quick.pointer.tests") - -struct Event -{ - Event(QEvent::Type t, QPointF item, QPointF scene) - :type(t), posWrtItem(item), posWrtScene(scene) - {} - - QEvent::Type type; - QPointF posWrtItem; - QPointF posWrtScene; - -}; - -#ifndef QT_NO_DEBUG_STREAM -QDebug operator<<(QDebug dbg, const struct Event &event) { - QDebugStateSaver saver(dbg); - dbg.nospace(); - dbg << "Event(" << event.type << " @" << event.posWrtScene << ")"; - return dbg; -} -#endif - -class EventItem : public QQuickItem -{ - Q_OBJECT -public: - EventItem(QQuickItem *parent = 0) - : QQuickItem(parent), acceptPointer(false), acceptMouse(false), acceptTouch(false), filterTouch(false) - {} - - void touchEvent(QTouchEvent *event) - { - qCDebug(lcPointerTests) << event << "will accept?" << acceptTouch; - for (const QTouchEvent::TouchPoint &tp : event->touchPoints()) - eventList.append(Event(event->type(), tp.pos(), tp.scenePos())); - event->setAccepted(acceptTouch); - } - void mousePressEvent(QMouseEvent *event) - { - qCDebug(lcPointerTests) << event; - eventList.append(Event(event->type(), event->pos(), event->windowPos())); - event->setAccepted(acceptMouse); - } - void mouseMoveEvent(QMouseEvent *event) - { - qCDebug(lcPointerTests) << event; - eventList.append(Event(event->type(), event->pos(), event->windowPos())); - event->setAccepted(acceptMouse); - } - void mouseReleaseEvent(QMouseEvent *event) - { - qCDebug(lcPointerTests) << event; - eventList.append(Event(event->type(), event->pos(), event->windowPos())); - event->setAccepted(acceptMouse); - } - void mouseDoubleClickEvent(QMouseEvent *event) - { - qCDebug(lcPointerTests) << event; - eventList.append(Event(event->type(), event->pos(), event->windowPos())); - event->setAccepted(acceptMouse); - } - - void mouseUngrabEvent() - { - qCDebug(lcPointerTests); - eventList.append(Event(QEvent::UngrabMouse, QPoint(0,0), QPoint(0,0))); - } - - bool event(QEvent *event) - { - qCDebug(lcPointerTests) << event; - return QQuickItem::event(event); - } - - QList eventList; - bool acceptPointer; - bool acceptMouse; - bool acceptTouch; - bool filterTouch; // when used as event filter - - bool eventFilter(QObject *o, QEvent *event) - { - qCDebug(lcPointerTests) << event << o; - if (event->type() == QEvent::TouchBegin || - event->type() == QEvent::TouchUpdate || - event->type() == QEvent::TouchCancel || - event->type() == QEvent::TouchEnd) { - QTouchEvent *touch = static_cast(event); - for (const QTouchEvent::TouchPoint &tp : touch->touchPoints()) - eventList.append(Event(event->type(), tp.pos(), tp.scenePos())); - if (filterTouch) - event->accept(); - return true; - } - return false; - } -}; - -class EventHandler : public QQuickPointerHandler -{ - void handlePointerEventImpl(QQuickPointerEvent *event) override - { - QQuickPointerHandler::handlePointerEventImpl(event); - if (!enabled()) - return; - EventItem *item = static_cast(target()); - qCDebug(lcPointerTests) << item->objectName() << event; - int c = event->pointCount(); - for (int i = 0; i < c; ++i) { - QQuickEventPoint *point = event->point(i); - point->setAccepted(item->acceptPointer); // has no effect: grabbing is up to us - if (item->acceptPointer) - setGrab(point, true); - qCDebug(lcPointerTests) << " " << i << ":" << point << "grabbed?" << item->acceptPointer; - item->eventList.append(Event(QEvent::Pointer, eventPos(point), point->scenePos())); - } - } -}; - -class tst_PointerHandlers : public QQmlDataTest -{ - Q_OBJECT -public: - tst_PointerHandlers() - :touchDevice(QTest::createTouchDevice()) - {} - -private slots: - void initTestCase(); - - void touchEventDelivery(); - void mouseEventDelivery(); - -protected: - bool eventFilter(QObject *, QEvent *event) - { - if (event->type() == QEvent::MouseButtonPress || - event->type() == QEvent::MouseMove || - event->type() == QEvent::MouseButtonRelease) { - QMouseEvent *me = static_cast(event); - filteredEventList.append(Event(me->type(), me->pos(), me->globalPos())); - } - return false; - } - -private: - QQuickView *createView(); - QTouchDevice *touchDevice; - QList filteredEventList; -}; - -QQuickView *tst_PointerHandlers::createView() -{ - QQuickView *window = new QQuickView(0); - window->setGeometry(0,0,240,320); - - return window; -} - -void tst_PointerHandlers::initTestCase() -{ - // This test assumes that we don't get synthesized mouse events from QGuiApplication - qApp->setAttribute(Qt::AA_SynthesizeMouseForUnhandledTouchEvents, false); - - QQmlDataTest::initTestCase(); - qmlRegisterType("Qt.test", 1, 0, "EventItem"); - qmlRegisterType("Qt.test", 1, 0, "EventHandler"); -} - -void tst_PointerHandlers::touchEventDelivery() -{ - QQuickView *window = createView(); - - window->setSource(testFileUrl("singleitem.qml")); - window->show(); - QVERIFY(QTest::qWaitForWindowExposed(window)); - window->requestActivate(); - QVERIFY(QTest::qWaitForWindowActive(window)); - QVERIFY(window->rootObject() != 0); - - EventItem *eventItem1 = window->rootObject()->findChild("eventItem1"); - QVERIFY(eventItem1); - - // Do not accept anything - QPoint p1 = QPoint(20, 20); - QTest::touchEvent(window, touchDevice).press(0, p1, window); - QQuickTouchUtils::flush(window); - QTRY_COMPARE(eventItem1->eventList.size(), 3); - QCOMPARE(eventItem1->eventList.at(0).type, QEvent::Pointer); - QCOMPARE(eventItem1->eventList.at(1).type, QEvent::TouchBegin); - QCOMPARE(eventItem1->eventList.at(2).type, QEvent::MouseButtonPress); - p1 += QPoint(10, 0); - QTest::touchEvent(window, touchDevice).move(0, p1, window); - QQuickTouchUtils::flush(window); - QCOMPARE(eventItem1->eventList.size(), 3); - QTest::touchEvent(window, touchDevice).release(0, p1, window); - QQuickTouchUtils::flush(window); - QCOMPARE(eventItem1->eventList.size(), 3); - eventItem1->eventList.clear(); - - // Accept touch - eventItem1->acceptTouch = true; - p1 = QPoint(20, 20); - QTest::touchEvent(window, touchDevice).press(0, p1, window); - QQuickTouchUtils::flush(window); - QCOMPARE(eventItem1->eventList.size(), 2); - QCOMPARE(eventItem1->eventList.at(0).type, QEvent::Pointer); - QCOMPARE(eventItem1->eventList.at(1).type, QEvent::TouchBegin); - auto pointerEvent = QQuickPointerDevice::touchDevices().at(0)->pointerEvent(); - QCOMPARE(pointerEvent->point(0)->grabber(), eventItem1); - p1 += QPoint(10, 0); - QTest::touchEvent(window, touchDevice).move(0, p1, window); - QQuickTouchUtils::flush(window); - QCOMPARE(eventItem1->eventList.size(), 4); - QCOMPARE(eventItem1->eventList.at(2).type, QEvent::Pointer); - QCOMPARE(eventItem1->eventList.at(3).type, QEvent::TouchUpdate); - QTest::touchEvent(window, touchDevice).release(0, p1, window); - QQuickTouchUtils::flush(window); - QCOMPARE(eventItem1->eventList.size(), 6); - QCOMPARE(eventItem1->eventList.at(4).type, QEvent::Pointer); - QCOMPARE(eventItem1->eventList.at(5).type, QEvent::TouchEnd); - 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, touchDevice).press(0, p1, window); - QQuickTouchUtils::flush(window); - QCOMPARE(eventItem1->eventList.size(), 3); - QCOMPARE(eventItem1->eventList.at(0).type, QEvent::Pointer); - QCOMPARE(eventItem1->eventList.at(1).type, QEvent::TouchBegin); - QCOMPARE(eventItem1->eventList.at(2).type, QEvent::MouseButtonPress); - QCOMPARE(window->mouseGrabberItem(), eventItem1); - - QPointF localPos = eventItem1->mapFromScene(p1); - QPointF scenePos = p1; // item is at 0,0 - QCOMPARE(eventItem1->eventList.at(1).posWrtItem, localPos); - QCOMPARE(eventItem1->eventList.at(1).posWrtScene, scenePos); - QCOMPARE(eventItem1->eventList.at(2).posWrtItem, localPos); - QCOMPARE(eventItem1->eventList.at(2).posWrtScene, scenePos); - - p1 += QPoint(10, 0); - QTest::touchEvent(window, touchDevice).move(0, p1, window); - QQuickTouchUtils::flush(window); - QCOMPARE(eventItem1->eventList.size(), 6); - QCOMPARE(eventItem1->eventList.at(3).type, QEvent::Pointer); - QCOMPARE(eventItem1->eventList.at(4).type, QEvent::TouchUpdate); - QCOMPARE(eventItem1->eventList.at(5).type, QEvent::MouseMove); - QTest::touchEvent(window, touchDevice).release(0, p1, window); - QQuickTouchUtils::flush(window); - QCOMPARE(eventItem1->eventList.size(), 10); - QCOMPARE(eventItem1->eventList.at(6).type, QEvent::Pointer); - QCOMPARE(eventItem1->eventList.at(7).type, QEvent::TouchEnd); - QCOMPARE(eventItem1->eventList.at(8).type, QEvent::MouseButtonRelease); - QCOMPARE(eventItem1->eventList.at(9).type, QEvent::UngrabMouse); - eventItem1->eventList.clear(); - - // wait to avoid getting a double click event - QTest::qWait(qApp->styleHints()->mouseDoubleClickInterval() + 10); - - // Accept mouse buttons but not the touch event - eventItem1->acceptTouch = false; - eventItem1->acceptMouse = false; - eventItem1->setAcceptedMouseButtons(Qt::LeftButton); - p1 = QPoint(20, 20); - QTest::touchEvent(window, touchDevice).press(0, p1, window); - QQuickTouchUtils::flush(window); - QCOMPARE(eventItem1->eventList.size(), 3); - QCOMPARE(eventItem1->eventList.at(0).type, QEvent::Pointer); - QCOMPARE(eventItem1->eventList.at(1).type, QEvent::TouchBegin); - QCOMPARE(eventItem1->eventList.at(2).type, QEvent::MouseButtonPress); - QCOMPARE(pointerEvent->point(0)->grabber(), nullptr); - p1 += QPoint(10, 0); - QTest::touchEvent(window, touchDevice).move(0, p1, window); - QQuickTouchUtils::flush(window); - QCOMPARE(eventItem1->eventList.size(), 3); - QTest::touchEvent(window, touchDevice).release(0, p1, window); - QQuickTouchUtils::flush(window); - QCOMPARE(eventItem1->eventList.size(), 3); - eventItem1->eventList.clear(); - - // wait to avoid getting a double click event - QTest::qWait(qApp->styleHints()->mouseDoubleClickInterval() + 10); - - // Accept touch - eventItem1->acceptTouch = true; - eventItem1->setAcceptedMouseButtons(Qt::LeftButton); - p1 = QPoint(20, 20); - QTest::touchEvent(window, touchDevice).press(0, p1, window); - QQuickTouchUtils::flush(window); - QCOMPARE(eventItem1->eventList.size(), 2); - QCOMPARE(eventItem1->eventList.at(0).type, QEvent::Pointer); - QCOMPARE(eventItem1->eventList.at(1).type, QEvent::TouchBegin); - p1 += QPoint(10, 0); - QTest::touchEvent(window, touchDevice).move(0, p1, window); - QQuickTouchUtils::flush(window); - QCOMPARE(eventItem1->eventList.size(), 4); - QCOMPARE(eventItem1->eventList.at(2).type, QEvent::Pointer); - QCOMPARE(eventItem1->eventList.at(3).type, QEvent::TouchUpdate); - QTest::touchEvent(window, touchDevice).release(0, p1, window); - QQuickTouchUtils::flush(window); - QCOMPARE(eventItem1->eventList.size(), 6); - QCOMPARE(eventItem1->eventList.at(4).type, QEvent::Pointer); - QCOMPARE(eventItem1->eventList.at(5).type, QEvent::TouchEnd); - eventItem1->eventList.clear(); - - // Accept pointer events - eventItem1->acceptPointer = true; - p1 = QPoint(20, 20); - QTest::touchEvent(window, touchDevice).press(0, p1, window); - QQuickTouchUtils::flush(window); - QCOMPARE(eventItem1->eventList.size(), 1); - QCOMPARE(eventItem1->eventList.at(0).type, QEvent::Pointer); - p1 += QPoint(10, 0); - QTest::touchEvent(window, touchDevice).move(0, p1, window); - QQuickTouchUtils::flush(window); - QCOMPARE(eventItem1->eventList.size(), 2); - QCOMPARE(eventItem1->eventList.at(1).type, QEvent::Pointer); - QTest::touchEvent(window, touchDevice).release(0, p1, window); - QQuickTouchUtils::flush(window); - QCOMPARE(eventItem1->eventList.size(), 3); - QCOMPARE(eventItem1->eventList.at(2).type, QEvent::Pointer); - eventItem1->eventList.clear(); - - delete window; -} - -void tst_PointerHandlers::mouseEventDelivery() -{ - QQuickView *window = createView(); - - window->setSource(testFileUrl("singleitem.qml")); - window->show(); - QVERIFY(QTest::qWaitForWindowExposed(window)); - window->requestActivate(); - QVERIFY(QTest::qWaitForWindowActive(window)); - QVERIFY(window->rootObject() != 0); - - EventItem *eventItem1 = window->rootObject()->findChild("eventItem1"); - QVERIFY(eventItem1); - - // Do not accept anything - QPoint p1 = QPoint(20, 20); - QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, p1); - QCOMPARE(eventItem1->eventList.size(), 2); - p1 += QPoint(10, 0); - QTest::mouseMove(window, p1); - QCOMPARE(eventItem1->eventList.size(), 2); - QTest::mouseRelease(window, Qt::LeftButton); - QCOMPARE(eventItem1->eventList.size(), 2); - 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::mousePress(window, Qt::LeftButton, Qt::NoModifier, p1); - QCOMPARE(eventItem1->eventList.size(), 2); - QCOMPARE(eventItem1->eventList.at(0).type, QEvent::Pointer); - QCOMPARE(eventItem1->eventList.at(1).type, QEvent::MouseButtonPress); - QCOMPARE(window->mouseGrabberItem(), eventItem1); - - QPointF localPos = eventItem1->mapFromScene(p1); - QPointF scenePos = p1; // item is at 0,0 - QCOMPARE(eventItem1->eventList.at(0).posWrtItem, localPos); - QCOMPARE(eventItem1->eventList.at(0).posWrtScene, scenePos); - QCOMPARE(eventItem1->eventList.at(1).posWrtItem, localPos); - QCOMPARE(eventItem1->eventList.at(1).posWrtScene, scenePos); - - p1 += QPoint(10, 0); - QTest::mouseMove(window, p1); - QCOMPARE(eventItem1->eventList.size(), 3); - QCOMPARE(eventItem1->eventList.at(2).type, QEvent::MouseMove); - QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p1); - QCOMPARE(eventItem1->eventList.size(), 5); - QCOMPARE(eventItem1->eventList.at(3).type, QEvent::MouseButtonRelease); - QCOMPARE(eventItem1->eventList.at(4).type, QEvent::UngrabMouse); - eventItem1->eventList.clear(); - - // wait to avoid getting a double click event - QTest::qWait(qApp->styleHints()->mouseDoubleClickInterval() + 10); - - // Accept pointer events - eventItem1->acceptMouse = false; - eventItem1->acceptPointer = true; - p1 = QPoint(20, 20); - QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, p1); - QTRY_COMPARE(eventItem1->eventList.size(), 1); - QCOMPARE(eventItem1->eventList.at(0).type, QEvent::Pointer); - p1 += QPoint(10, 0); - QTest::mouseMove(window, p1); - QCOMPARE(eventItem1->eventList.size(), 2); - QCOMPARE(eventItem1->eventList.at(1).type, QEvent::Pointer); - QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p1); - QCOMPARE(eventItem1->eventList.size(), 3); - QCOMPARE(eventItem1->eventList.at(2).type, QEvent::Pointer); - eventItem1->eventList.clear(); - - delete window; -} - -QTEST_MAIN(tst_PointerHandlers) - -#include "tst_pointerhandlers.moc" - -- cgit v1.2.3 From b8106804c87f70c3be034dc3e191966293a8b877 Mon Sep 17 00:00:00 2001 From: Jan Arve Saether Date: Fri, 2 Sep 2016 12:58:43 +0200 Subject: Move device id to be in bits 24-31 of the point id This allows us for lossless conversion between QTouchEvent::TouchPoint id and QQuickEventPoint::pointId (both ways). Change-Id: I2087847a579dd8bc5b526515ad07b55c9ae8aa42 Reviewed-by: Shawn Rutledge --- tests/manual/touch/mpta-crosshairs.qml | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'tests') diff --git a/tests/manual/touch/mpta-crosshairs.qml b/tests/manual/touch/mpta-crosshairs.qml index 8b71e4fdc3..901b3e8bac 100644 --- a/tests/manual/touch/mpta-crosshairs.qml +++ b/tests/manual/touch/mpta-crosshairs.qml @@ -85,11 +85,22 @@ Rectangle { } Rectangle { color: touchPoint.color - width: 50 * touchPoint.pressure + width: Math.max(2, 50 * touchPoint.pressure) height: width radius: width / 2 x: touchPoint.x - width / 2 y: touchPoint.y - width / 2 + Rectangle { + y: -40 + anchors.horizontalCenter: parent.horizontalCenter + color: "#c0c0c0" + implicitWidth: label.implicitWidth + implicitHeight: label.implicitHeight + Text { + id: label + text: 'id: ' + touchPoint.pointId.toString(16) + '\npos: (' + touchPoint.x.toFixed(2) + ', ' + touchPoint.y.toFixed(2) + ')' + } + } } Rectangle { id: velocityVector -- cgit v1.2.3 From c364b935f06256ec7adfaf486ef35b3996152804 Mon Sep 17 00:00:00 2001 From: Jan Arve Saether Date: Fri, 2 Sep 2016 17:07:57 +0200 Subject: Fix rotation in PinchHandler If we want to allow rotation with more than 2 fingers, its not straightforward to calculate the rotation angle, because we cannot anymore calculate the angle between the two touchpoints. The approach chosen was to calculate the angle between the centroid and the touchpoints, and take the average between the angles. Then, for the next event we calculated the new average of the angles. However, this is not really reliable in some scenarios, suppose we have these three angles: 0 120 240, avg = 360/3 = 120 next, touch points rotate clockwise with 2 degrees, and we get these angles: 358 118 238, avg = 714/3 = 238 So, just by rotating all fingers by 2 degrees, we got a jump by 118 degrees "in average". Instead we need to track the angles of *all* touch points, and when the next touch event is received we calculate how much the angle has changed per touch point. We then take the average of those angles as the effective "rotation" of the PinchHandler Change-Id: I2bfdf80b886751177efe81bcc7b698af0d2938e3 Reviewed-by: Shawn Rutledge --- tests/manual/pointer/pinchHandler.qml | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) (limited to 'tests') diff --git a/tests/manual/pointer/pinchHandler.qml b/tests/manual/pointer/pinchHandler.qml index e4482a249d..d163343a3e 100644 --- a/tests/manual/pointer/pinchHandler.qml +++ b/tests/manual/pointer/pinchHandler.qml @@ -54,18 +54,21 @@ Rectangle { Text { anchors.centerIn: parent - text: "Pinch with 2 fingers to scale & rotate\nDrag with 1 finger\ncurrent rotation " + pinch2.rotation.toFixed(1) + text: "Pinch with 2 fingers to scale, rotate and translate" + + "\ncurrent rotation: " + pinch2.rotation.toFixed(1) + + "\nscale: " + pinch2.scale.toFixed(1) + + "\ntranslation: " + pinch2.translation } - DragHandler { objectName: "DragHandler" } - PinchHandler { id: pinch2 objectName: "2-finger pinch" minimumRotation: -45 maximumRotation: 45 - minimumScale: 0.1 - maximumScale: 10 + minimumScale: 0.5 + maximumScale: 3 + minimumX: 0 + maximumX: 600 pointDistanceThreshold: 150 } } @@ -79,8 +82,10 @@ Rectangle { Text { anchors.centerIn: parent - text: "Pinch with 3 fingers to scale & rotate\ncurrent rotation " + pinch3.rotation.toFixed(1) + text: "Pinch with 3 fingers to scale, rotate and translate\nDrag with 1 finger" + + "\ncurrent rotation " + pinch3.rotation.toFixed(1) } + DragHandler { objectName: "DragHandler" } PinchHandler { id: pinch3 @@ -90,4 +95,17 @@ Rectangle { maximumScale: 10 } } + + Rectangle { + id: centroidIndicator + property QtObject pincher: pinch2.active ? pinch2 : pinch3 + x: pincher.centroid.x + y: pincher.centroid.y + z: 1 + visible: pincher.active + radius: width / 2 + width: 10 + height: width + color: "red" + } } -- cgit v1.2.3 From 542eda976c2767ed6c1eecb4dbcbf838e0ca5a19 Mon Sep 17 00:00:00 2001 From: Jan Arve Saether Date: Tue, 18 Oct 2016 11:49:13 +0200 Subject: Fixed some problems with the centroid in PinchHandler The centroid was not always mapped to the correct coordinate system In addition, the return value of startingCentroid() was not always desirable, because its implementation calls sceneGrabPos(). We therefore had to get the starting centroid by querying touchPointCentroid() whenever the handler became active. Change-Id: I69de6b832b9bda208fda4eb90a8a95cc975405c2 Reviewed-by: Shawn Rutledge --- tests/manual/pointer/pinchHandler.qml | 96 +++++++++++++++++++---------------- 1 file changed, 52 insertions(+), 44 deletions(-) (limited to 'tests') diff --git a/tests/manual/pointer/pinchHandler.qml b/tests/manual/pointer/pinchHandler.qml index d163343a3e..3ab196a10a 100644 --- a/tests/manual/pointer/pinchHandler.qml +++ b/tests/manual/pointer/pinchHandler.qml @@ -42,60 +42,68 @@ import QtQuick 2.8 import Qt.labs.handlers 1.0 Rectangle { - id: root width: 1024; height: 600 - color: "black" - + color: "#eee" Rectangle { - width: 400 - height: 300 - color: "lightsteelblue" - antialiasing: true + id: root + color: "black" + width: 900 + height: 600 + x: 100 - Text { - anchors.centerIn: parent - text: "Pinch with 2 fingers to scale, rotate and translate" - + "\ncurrent rotation: " + pinch2.rotation.toFixed(1) - + "\nscale: " + pinch2.scale.toFixed(1) - + "\ntranslation: " + pinch2.translation - } + Rectangle { + width: 400 + height: 300 + color: "lightsteelblue" + antialiasing: true - PinchHandler { - id: pinch2 - objectName: "2-finger pinch" - minimumRotation: -45 - maximumRotation: 45 - minimumScale: 0.5 - maximumScale: 3 - minimumX: 0 - maximumX: 600 - pointDistanceThreshold: 150 + Text { + anchors.centerIn: parent + text: "Pinch with 2 fingers to scale, rotate and translate" + + "\ncurrent rotation: " + pinch2.rotation.toFixed(1) + + "\nscale: " + pinch2.scale.toFixed(1) + + "\ntranslation: " + pinch2.translation + } + + PinchHandler { + id: pinch2 + objectName: "2-finger pinch" + minimumRotation: -45 + maximumRotation: 45 + minimumScale: 0.5 + maximumScale: 3 + minimumX: 0 + maximumX: 600 + pointDistanceThreshold: 150 + } } - } - Rectangle { - x: 512 - width: 400 - height: 300 - color: "wheat" - antialiasing: true + Rectangle { + x: 500 + width: 400 + height: 300 + color: "wheat" + antialiasing: true - Text { - anchors.centerIn: parent - text: "Pinch with 3 fingers to scale, rotate and translate\nDrag with 1 finger" - + "\ncurrent rotation " + pinch3.rotation.toFixed(1) - } - DragHandler { objectName: "DragHandler" } + Text { + anchors.centerIn: parent + text: "Pinch with 3 fingers to scale, rotate and translate\nDrag with 1 finger" + + "\ncurrent rotation " + pinch3.rotation.toFixed(1) + + "\nscale: " + pinch3.scale.toFixed(1) + + "\ntranslation: " + pinch3.translation + } + DragHandler { objectName: "DragHandler" } - PinchHandler { - id: pinch3 - objectName: "3-finger pinch" - requiredPointCount: 3 - minimumScale: 0.1 - maximumScale: 10 + PinchHandler { + id: pinch3 + objectName: "3-finger pinch" + requiredPointCount: 3 + minimumScale: 0.1 + maximumScale: 10 + } } - } + } Rectangle { id: centroidIndicator property QtObject pincher: pinch2.active ? pinch2 : pinch3 -- cgit v1.2.3 From 3eeffae835b3474c8a3ca62125cb8ec24acdaa84 Mon Sep 17 00:00:00 2001 From: Jan Arve Saether Date: Tue, 13 Dec 2016 11:38:23 +0100 Subject: Let pinchhandler operate on QQuickItem properties This requires coordinate system mapping that varies with the transformOrigin. The properties exposed from PinchHandler (rotation, scale and translation) are currently relative to the point when the pinch became active. (Therefore, rotation, will reset back to 0 when a new pinch is activated). Its still unclear how the properties that limits the transform should influence. With this patch, they are like this: * {min,max}imumRotation applies to the actual rotation of the item. * {min,max}imumScale applies to the actual scale of the item. * {min,max}imum{X,Y} applies to the actual position of the item. (This has some unfortunate side-effects when the item is scaled or rotated, since the items actual position will change as it rotates) In addition, the behavior described above means that the limits won't have any effect if there is no target item. Change-Id: I279fb03667cd75324e8337039ae2594658265d13 Reviewed-by: Shawn Rutledge --- tests/manual/pointer/pinchHandler.qml | 41 ++++++++++++++++++++++------------- 1 file changed, 26 insertions(+), 15 deletions(-) (limited to 'tests') diff --git a/tests/manual/pointer/pinchHandler.qml b/tests/manual/pointer/pinchHandler.qml index 3ab196a10a..f317f361e2 100644 --- a/tests/manual/pointer/pinchHandler.qml +++ b/tests/manual/pointer/pinchHandler.qml @@ -44,25 +44,38 @@ import Qt.labs.handlers 1.0 Rectangle { width: 1024; height: 600 color: "#eee" + + function getTransformationDetails(item, pinchhandler) { + return "\n\npinch.scale:" + pinchhandler.scale.toFixed(2) + + "\npinch.rotation:" + pinchhandler.rotation.toFixed(2) + + "\npinch.translation:" + "(" + pinchhandler.translation.x.toFixed(2) + "," + pinchhandler.translation.y.toFixed(2) + ")" + + "\nrect.scale: " + item.scale.toFixed(2) + + "\nrect.rotation: " + item.rotation.toFixed(2) + + "\nrect.position: " + "(" + item.x.toFixed(2) + "," + item.y.toFixed(2) + ")" + } + Rectangle { - id: root - color: "black" - width: 900 - height: 600 - x: 100 + // Purpose of this item is just to make sure the rectangles are transformed into + // a coordinate system that is different from the scene coordinate system. + anchors.fill: parent + anchors.margins: 50 + color: "#ffe0e0e0" Rectangle { + id: rect2 width: 400 height: 300 color: "lightsteelblue" antialiasing: true + x: 100 + y: 200 + rotation: 30 + transformOrigin: Item.TopRight Text { anchors.centerIn: parent text: "Pinch with 2 fingers to scale, rotate and translate" - + "\ncurrent rotation: " + pinch2.rotation.toFixed(1) - + "\nscale: " + pinch2.scale.toFixed(1) - + "\ntranslation: " + pinch2.translation + + getTransformationDetails(rect2, pinch2) } PinchHandler { @@ -74,11 +87,12 @@ Rectangle { maximumScale: 3 minimumX: 0 maximumX: 600 - pointDistanceThreshold: 150 + pointDistanceThreshold: 0 } } Rectangle { + id: rect3 x: 500 width: 400 height: 300 @@ -88,9 +102,7 @@ Rectangle { Text { anchors.centerIn: parent text: "Pinch with 3 fingers to scale, rotate and translate\nDrag with 1 finger" - + "\ncurrent rotation " + pinch3.rotation.toFixed(1) - + "\nscale: " + pinch3.scale.toFixed(1) - + "\ntranslation: " + pinch3.translation + + getTransformationDetails(rect3, pinch3) } DragHandler { objectName: "DragHandler" } @@ -102,13 +114,12 @@ Rectangle { maximumScale: 10 } } - } Rectangle { id: centroidIndicator property QtObject pincher: pinch2.active ? pinch2 : pinch3 - x: pincher.centroid.x - y: pincher.centroid.y + x: pincher.centroid.x - radius + y: pincher.centroid.y - radius z: 1 visible: pincher.active radius: width / 2 -- cgit v1.2.3 From 871314ced803afe0ac31033cfbd79fa4c1b18e3d Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Thu, 8 Dec 2016 19:19:04 +0100 Subject: DragHandler active property replaces dragging; same as grabbing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If a QQuickPointerSingleHandler grabs a point, it's definitely in the active state: doing something with the point. (The converse is not always true though: e.g. TapHandler can sometimes detect a tap without ever grabbing.) In DragHandler, the "dragging" property means the same as "active": we always grab when dragging, to be sure to get the updates. So the "dragging" property is removed because it's redundant. In QQuickPointerHandler we don't say that "wanting" an event is the same as being active, because 1) it won't necessarily grab right away and 2) every handler which was active should "want" the release event, yet it needs to setActive(false) as soon as it's done processing it. Change-Id: Ie010db54714a7914109da6469e79865f9a0a18e4 Reviewed-by: Jan Arve Sæther --- tests/manual/pointer/content/Slider.qml | 2 +- tests/manual/pointer/joystick.qml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'tests') diff --git a/tests/manual/pointer/content/Slider.qml b/tests/manual/pointer/content/Slider.qml index 363f6911d4..cd52dfac80 100644 --- a/tests/manual/pointer/content/Slider.qml +++ b/tests/manual/pointer/content/Slider.qml @@ -70,7 +70,7 @@ Item { anchors.horizontalCenterOffset: 1 radius: 5 color: "#4400FFFF" - visible: dragHandler.dragging + opacity: dragHandler.active ? 1 : 0 } Image { id: knob diff --git a/tests/manual/pointer/joystick.qml b/tests/manual/pointer/joystick.qml index 7959eaea42..bcc4564471 100644 --- a/tests/manual/pointer/joystick.qml +++ b/tests/manual/pointer/joystick.qml @@ -58,7 +58,7 @@ Rectangle { } states: [ State { - when: dragHandler.dragging + when: dragHandler.active AnchorChanges { target: knob anchors.horizontalCenter: undefined -- cgit v1.2.3 From 9aa0e84d974d86cf9366714107e9c84dcde15490 Mon Sep 17 00:00:00 2001 From: Jan Arve Saether Date: Fri, 23 Dec 2016 15:35:43 +0100 Subject: Add a DragHandler::translation property This allows the application developer to get the translation of the dragged pointer, and apply it in a custom way. This should usually be combined with setting target to null. This will for instance be needed when we want to drag QtLocations map, where a map is dragged by specifying the geo location of the center of the map. The map2.qml example demonstrates this. Change-Id: I652d9fc92fa9b6dfd3796c7147832f25af0cc5bc Reviewed-by: Shawn Rutledge --- tests/manual/pointer/main.qml | 1 + tests/manual/pointer/map2.qml | 91 +++++++++++++++++++++++++++++++++++++++++++ tests/manual/pointer/qml.qrc | 1 + 3 files changed, 93 insertions(+) create mode 100644 tests/manual/pointer/map2.qml (limited to 'tests') diff --git a/tests/manual/pointer/main.qml b/tests/manual/pointer/main.qml index 7ba0d9a466..64b7148bd2 100644 --- a/tests/manual/pointer/main.qml +++ b/tests/manual/pointer/main.qml @@ -54,6 +54,7 @@ Window { addExample("mixer", "mixing console", Qt.resolvedUrl("mixer.qml")) addExample("pinch", "PinchHandler: scale, rotate and drag", Qt.resolvedUrl("pinchHandler.qml")) addExample("map", "scale and pan", Qt.resolvedUrl("map.qml")) + addExample("custom map", "scale and pan", Qt.resolvedUrl("map2.qml")) } } } diff --git a/tests/manual/pointer/map2.qml b/tests/manual/pointer/map2.qml new file mode 100644 index 0000000000..fcd144bd7f --- /dev/null +++ b/tests/manual/pointer/map2.qml @@ -0,0 +1,91 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the manual tests of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.8 +import Qt.labs.handlers 1.0 + +Item { + width: 640 + height: 480 + + Rectangle { + id: map + color: "aqua" + x: (parent.width - width) / 2 + y: (parent.height - height) / 2 + width: image.implicitWidth + height: image.implicitHeight + property point center : Qt.point(x + map.width/2, y + map.height/2) + + function setCenter(xx, yy) { + map.x = xx - map.width/2 + map.y = yy - map.height/2 + } + + + Image { + id: image + anchors.centerIn: parent + fillMode: Image.PreserveAspectFit + source: "resources/map.svgz" + } + } + + PinchHandler { + id: pinch + target: map + minimumScale: 0.1 + maximumScale: 10 + } + + DragHandler { + property point startDrag + target: null + onActiveChanged: { + if (active) + startDrag = map.center + } + + onTranslationChanged: { + if (!target) + map.setCenter(startDrag.x + translation.x, startDrag.y + translation.y) + } + } +} diff --git a/tests/manual/pointer/qml.qrc b/tests/manual/pointer/qml.qrc index 3d7de4b728..08488b020b 100644 --- a/tests/manual/pointer/qml.qrc +++ b/tests/manual/pointer/qml.qrc @@ -9,5 +9,6 @@ resources/map.svgz resources/mixer-knob.png resources/redball.png + map2.qml -- cgit v1.2.3 From 5c6245b7ff7a941c0a2425f32909c0dc0982e199 Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Fri, 25 Nov 2016 15:38:42 +0100 Subject: QQPSingleHandler: copy some values from QQuickEventPoint to properties MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We can't copy the eventpoint and we can't continue to refer to it after delivery, either. So we can't have an event property. Some QML use cases depend on being able to access last-known values between events. Change-Id: Ice8a1763015f2554275d0cb76824fd0366eaef56 Reviewed-by: Jan Arve Sæther --- tests/manual/pointer/main.qml | 1 + tests/manual/pointer/qml.qrc | 7 + tests/manual/pointer/resources/arrowhead.png | Bin 0 -> 883 bytes .../manual/pointer/resources/grabbing-location.svg | 1 + tests/manual/pointer/resources/mouse.png | Bin 0 -> 1919 bytes tests/manual/pointer/resources/mouse_left.png | Bin 0 -> 740 bytes tests/manual/pointer/resources/mouse_middle.png | Bin 0 -> 558 bytes tests/manual/pointer/resources/mouse_right.png | Bin 0 -> 906 bytes .../pointer/singlePointHandlerProperties.qml | 162 +++++++++++++++++++++ 9 files changed, 171 insertions(+) create mode 100644 tests/manual/pointer/resources/arrowhead.png create mode 100644 tests/manual/pointer/resources/grabbing-location.svg create mode 100644 tests/manual/pointer/resources/mouse.png create mode 100644 tests/manual/pointer/resources/mouse_left.png create mode 100644 tests/manual/pointer/resources/mouse_middle.png create mode 100644 tests/manual/pointer/resources/mouse_right.png create mode 100644 tests/manual/pointer/singlePointHandlerProperties.qml (limited to 'tests') diff --git a/tests/manual/pointer/main.qml b/tests/manual/pointer/main.qml index 64b7148bd2..62202c39b1 100644 --- a/tests/manual/pointer/main.qml +++ b/tests/manual/pointer/main.qml @@ -50,6 +50,7 @@ Window { id: ll anchors.fill: parent Component.onCompleted: { + addExample("single point handler", "QQuickPointerSingleHandler: test properties copied from events", Qt.resolvedUrl("singlePointHandlerProperties.qml")) addExample("joystick", "DragHandler: move one item inside another with any pointing device", Qt.resolvedUrl("joystick.qml")) addExample("mixer", "mixing console", Qt.resolvedUrl("mixer.qml")) addExample("pinch", "PinchHandler: scale, rotate and drag", Qt.resolvedUrl("pinchHandler.qml")) diff --git a/tests/manual/pointer/qml.qrc b/tests/manual/pointer/qml.qrc index 08488b020b..adf255ea1f 100644 --- a/tests/manual/pointer/qml.qrc +++ b/tests/manual/pointer/qml.qrc @@ -5,9 +5,16 @@ map.qml mixer.qml pinchHandler.qml + singlePointHandlerProperties.qml content/Slider.qml + resources/arrowhead.png + resources/grabbing-location.svg resources/map.svgz resources/mixer-knob.png + resources/mouse.png + resources/mouse_left.png + resources/mouse_middle.png + resources/mouse_right.png resources/redball.png map2.qml diff --git a/tests/manual/pointer/resources/arrowhead.png b/tests/manual/pointer/resources/arrowhead.png new file mode 100644 index 0000000000..7719bc6d6a Binary files /dev/null and b/tests/manual/pointer/resources/arrowhead.png differ diff --git a/tests/manual/pointer/resources/grabbing-location.svg b/tests/manual/pointer/resources/grabbing-location.svg new file mode 100644 index 0000000000..c26881e9ba --- /dev/null +++ b/tests/manual/pointer/resources/grabbing-location.svg @@ -0,0 +1 @@ + diff --git a/tests/manual/pointer/resources/mouse.png b/tests/manual/pointer/resources/mouse.png new file mode 100644 index 0000000000..268946df0a Binary files /dev/null and b/tests/manual/pointer/resources/mouse.png differ diff --git a/tests/manual/pointer/resources/mouse_left.png b/tests/manual/pointer/resources/mouse_left.png new file mode 100644 index 0000000000..9292301b47 Binary files /dev/null and b/tests/manual/pointer/resources/mouse_left.png differ diff --git a/tests/manual/pointer/resources/mouse_middle.png b/tests/manual/pointer/resources/mouse_middle.png new file mode 100644 index 0000000000..064e8b9c16 Binary files /dev/null and b/tests/manual/pointer/resources/mouse_middle.png differ diff --git a/tests/manual/pointer/resources/mouse_right.png b/tests/manual/pointer/resources/mouse_right.png new file mode 100644 index 0000000000..cab1a36ba6 Binary files /dev/null and b/tests/manual/pointer/resources/mouse_right.png differ diff --git a/tests/manual/pointer/singlePointHandlerProperties.qml b/tests/manual/pointer/singlePointHandlerProperties.qml new file mode 100644 index 0000000000..f5a938e401 --- /dev/null +++ b/tests/manual/pointer/singlePointHandlerProperties.qml @@ -0,0 +1,162 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the manual tests of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.9 +import Qt.labs.handlers 1.0 + +Rectangle { + id: root + width: 480 + height: 480 + color: "black" + + Item { + id: crosshairs + x: dragHandler.pos.x - width / 2 + y: dragHandler.pos.y - height / 2 + width: parent.width / 2; height: parent.height / 2 + visible: dragHandler.active + rotation: dragHandler.rotation + + Rectangle { + color: "goldenrod" + anchors.centerIn: parent + width: 2; height: parent.height + antialiasing: true + } + Rectangle { + color: "goldenrod" + anchors.centerIn: parent + width: parent.width; height: 2 + antialiasing: true + } + Rectangle { + color: "goldenrod" + width: Math.max(2, 50 * dragHandler.pressure) + height: width + radius: width / 2 + anchors.centerIn: parent + antialiasing: true + Rectangle { + y: -40 + anchors.horizontalCenter: parent.horizontalCenter + color: "lightsteelblue" + implicitWidth: label.implicitWidth + implicitHeight: label.implicitHeight + Text { + id: label + text: 'id: ' + dragHandler.pointId.toString(16) + " uid: " + dragHandler.uniquePointId.numericId + + '\npos: (' + dragHandler.pos.x.toFixed(2) + ', ' + dragHandler.pos.y.toFixed(2) + ')' + } + } + } + Rectangle { + color: "transparent" + border.color: "white" + antialiasing: true + width: dragHandler.ellipseDiameters.width + height: dragHandler.ellipseDiameters.height + radius: Math.min(width / 2, height / 2) + anchors.centerIn: parent + } + } + Rectangle { + id: velocityVector + visible: width > 0 + width: dragHandler.velocity.length() * 100 + height: 2 + x: dragHandler.pos.x + y: dragHandler.pos.y + rotation: Math.atan2(dragHandler.velocity.y, dragHandler.velocity.x) * 180 / Math.PI + transformOrigin: Item.BottomLeft + antialiasing: true + + Image { + source: "resources/arrowhead.png" + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + width: 16 + height: 12 + antialiasing: true + } + } + + Component { + id: grabbingLocationIndicator + Image { + source: "resources/grabbing-location.svg" + sourceSize.width: 32 + sourceSize.height: 32 + } + } + + Component { + id: mouseButtonIndicator + Image { + property int buttons + source: "resources/mouse.png" + Image { + source: "resources/mouse_left.png" + visible: buttons & Qt.LeftButton + } + Image { + source: "resources/mouse_middle.png" + visible: buttons & Qt.MidButton + } + Image { + source: "resources/mouse_right.png" + visible: buttons & Qt.RightButton + } + } + } + + DragHandler { + id: dragHandler + target: null + onGrabChanged: if (active) { + console.log("grabbed " + point.pointId + " @ " + sceneGrabPos) + grabbingLocationIndicator.createObject(root, {"x": sceneGrabPos.x, "y": sceneGrabPos.y - 16}) + } + onPressedButtonsChanged: { + if (pressedButtons) + mouseButtonIndicator.createObject(root, {"x": pressPos.x - 44, "y": pressPos.y - 64, "buttons": pressedButtons}) + } + } +} -- cgit v1.2.3 From 9d8fe2ac121162c15be6728495be2235b728325a Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Wed, 4 Jan 2017 08:31:07 +0100 Subject: tst_qquickwindow::mouseFiltering: verify that siblings don't filter MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A grandchild's parent's sibling (uncle) can be underneath the child in such a way that it will see the event during normal delivery, if neither the child nor its parent accepts the event, and yet this uncle will not get the opportunity to filter because it's not a parent. Also verify that after an item accepts a press event, subsequent mouse moves are filtered by the same parent and grandparent, even if the move has placed the cursor outside their bounds. Also rename mousePressId to mousePressCount, because the name was misleading: it's just a counter. Remove the comment about whether it's a bug that touch events are filtered: we are constrained by bincompat to use the same virtual function to filter both kinds of events, for now. Change-Id: If0fd62730883f3e4e29675580d975395c631e694 Reviewed-by: Jan Arve Sæther --- tests/auto/quick/qquickwindow/tst_qquickwindow.cpp | 88 +++++++++++++++++----- 1 file changed, 69 insertions(+), 19 deletions(-) (limited to 'tests') diff --git a/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp b/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp index 300ca392f9..3e78230d2e 100644 --- a/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp +++ b/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp @@ -46,6 +46,8 @@ #include #include +Q_LOGGING_CATEGORY(lcTests, "qt.quick.tests") + struct TouchEventData { QEvent::Type type; QWidget *widget; @@ -139,7 +141,7 @@ class TestTouchItem : public QQuickRectangle public: TestTouchItem(QQuickItem *parent = 0) : QQuickRectangle(parent), acceptTouchEvents(true), acceptMouseEvents(true), - mousePressId(0), + mousePressCount(0), mouseMoveCount(0), spinLoopWhenPressed(false), touchEventCount(0) { border()->setWidth(1); @@ -158,9 +160,10 @@ public: lastMousePos = QPointF(); lastMouseCapabilityFlags = 0; touchEventCount = 0; + mouseMoveCount = 0; } - static void clearMousePressCounter() + static void clearMouseEventCounters() { mousePressNum = mouseMoveNum = mouseReleaseNum = 0; } @@ -173,7 +176,8 @@ public: bool acceptTouchEvents; bool acceptMouseEvents; TouchEventData lastEvent; - int mousePressId; + int mousePressCount; + int mouseMoveCount; bool spinLoopWhenPressed; int touchEventCount; QVector2D lastVelocity; @@ -203,7 +207,7 @@ public: e->ignore(); return; } - mousePressId = ++mousePressNum; + mousePressCount = ++mousePressNum; lastMousePos = e->pos(); lastMouseCapabilityFlags = QGuiApplicationPrivate::mouseEventCaps(e); } @@ -213,7 +217,7 @@ public: e->ignore(); return; } - ++mouseMoveNum; + mouseMoveCount = ++mouseMoveNum; lastVelocityFromMouseMove = QGuiApplicationPrivate::mouseEventVelocity(e); lastMouseCapabilityFlags = QGuiApplicationPrivate::mouseEventCaps(e); lastMousePos = e->pos(); @@ -229,10 +233,19 @@ public: lastMouseCapabilityFlags = QGuiApplicationPrivate::mouseEventCaps(e); } - bool childMouseEventFilter(QQuickItem *, QEvent *event) { - // TODO Is it a bug if a QTouchEvent comes here? - if (event->type() == QEvent::MouseButtonPress) - mousePressId = ++mousePressNum; + bool childMouseEventFilter(QQuickItem *item, QEvent *e) { + qCDebug(lcTests) << objectName() << "filtering" << e << "ahead of delivery to" << item->metaObject()->className() << item->objectName(); + switch (e->type()) { + case QEvent::MouseButtonPress: + mousePressCount = ++mousePressNum; + break; + case QEvent::MouseMove: + mouseMoveCount = ++mouseMoveNum; + break; + default: + break; + } + return false; } @@ -500,7 +513,7 @@ void tst_qquickwindow::constantUpdatesOnWindow() void tst_qquickwindow::touchEvent_basic() { - TestTouchItem::clearMousePressCounter(); + TestTouchItem::clearMouseEventCounters(); QQuickWindow *window = new QQuickWindow; QScopedPointer cleanup(window); @@ -629,7 +642,7 @@ void tst_qquickwindow::touchEvent_basic() void tst_qquickwindow::touchEvent_propagation() { - TestTouchItem::clearMousePressCounter(); + TestTouchItem::clearMouseEventCounters(); QFETCH(bool, acceptTouchEvents); QFETCH(bool, acceptMouseEvents); @@ -776,7 +789,7 @@ void tst_qquickwindow::touchEvent_propagation_data() void tst_qquickwindow::touchEvent_cancel() { - TestTouchItem::clearMousePressCounter(); + TestTouchItem::clearMouseEventCounters(); QQuickWindow *window = new QQuickWindow; QScopedPointer cleanup(window); @@ -810,7 +823,7 @@ void tst_qquickwindow::touchEvent_cancel() void tst_qquickwindow::touchEvent_reentrant() { - TestTouchItem::clearMousePressCounter(); + TestTouchItem::clearMouseEventCounters(); QQuickWindow *window = new QQuickWindow; QScopedPointer cleanup(window); @@ -849,7 +862,7 @@ void tst_qquickwindow::touchEvent_reentrant() void tst_qquickwindow::touchEvent_velocity() { - TestTouchItem::clearMousePressCounter(); + TestTouchItem::clearMouseEventCounters(); QQuickWindow *window = new QQuickWindow; QScopedPointer cleanup(window); @@ -975,7 +988,7 @@ void tst_qquickwindow::mouseFromTouch_basic() // should result in sending mouse events generated from the touch // with the new event propagation system. - TestTouchItem::clearMousePressCounter(); + TestTouchItem::clearMouseEventCounters(); QQuickWindow *window = new QQuickWindow; QScopedPointer cleanup(window); window->resize(250, 250); @@ -1064,7 +1077,7 @@ void tst_qquickwindow::clearWindow() void tst_qquickwindow::mouseFiltering() { - TestTouchItem::clearMousePressCounter(); + TestTouchItem::clearMouseEventCounters(); QQuickWindow *window = new QQuickWindow; QScopedPointer cleanup(window); @@ -1078,6 +1091,11 @@ void tst_qquickwindow::mouseFiltering() bottomItem->setObjectName("Bottom Item"); bottomItem->setSize(QSizeF(150, 150)); + TestTouchItem *siblingItem = new TestTouchItem(bottomItem); + siblingItem->setObjectName("Sibling of Middle Item"); + siblingItem->setPosition(QPointF(90, 25)); + siblingItem->setSize(QSizeF(150, 150)); + TestTouchItem *middleItem = new TestTouchItem(bottomItem); middleItem->setObjectName("Middle Item"); middleItem->setPosition(QPointF(50, 50)); @@ -1097,9 +1115,41 @@ void tst_qquickwindow::mouseFiltering() // 1. middleItem filters event // 2. bottomItem filters event // 3. topItem receives event - QTRY_COMPARE(middleItem->mousePressId, 1); - QTRY_COMPARE(bottomItem->mousePressId, 2); - QTRY_COMPARE(topItem->mousePressId, 3); + QTRY_COMPARE(middleItem->mousePressCount, 1); + QTRY_COMPARE(bottomItem->mousePressCount, 2); + QTRY_COMPARE(topItem->mousePressCount, 3); + QCOMPARE(siblingItem->mousePressCount, 0); + + QTest::mouseRelease(window, Qt::LeftButton, 0, pos); + topItem->clearMouseEventCounters(); + middleItem->clearMouseEventCounters(); + bottomItem->clearMouseEventCounters(); + siblingItem->clearMouseEventCounters(); + + // Repeat, but this time have the top item accept the press + topItem->acceptMouseEvents = true; + + QTest::mousePress(window, Qt::LeftButton, 0, pos); + + // Mouse filtering propagates down the stack, so the + // correct order is + // 1. middleItem filters event + // 2. bottomItem filters event + // 3. topItem receives event + QTRY_COMPARE(middleItem->mousePressCount, 1); + QTRY_COMPARE(bottomItem->mousePressCount, 2); + QTRY_COMPARE(topItem->mousePressCount, 3); + QCOMPARE(siblingItem->mousePressCount, 0); + + pos += QPoint(50, 50); + QTest::mouseMove(window, pos); + + // The top item has grabbed, so the move goes there, but again + // all the ancestors can filter, even when the mouse is outside their bounds + QTRY_COMPARE(middleItem->mouseMoveCount, 1); + QTRY_COMPARE(bottomItem->mouseMoveCount, 2); + QTRY_COMPARE(topItem->mouseMoveCount, 3); + QCOMPARE(siblingItem->mouseMoveCount, 0); // clean up mouse press state for the next tests QTest::mouseRelease(window, Qt::LeftButton, 0, pos); -- cgit v1.2.3 From 9b5fc80af28580e9672792dd511d876a93947882 Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Wed, 28 Dec 2016 20:27:18 +0100 Subject: build a vector of child-filtering parents before delivery of pointer event MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Formerly during normal mouse or touch event delivery, sending it to the Item needed to be done via QQuickWindow::sendEvent, which would then call sendFilteredMouseEvent, which is a recursive function to visit all the item's parents, check whether filtersChildMouseEvents() returns true, if so then return early if childMouseEventFilter() returns true. This is the mechanism by which Flickable (for example) can monitor the movements of an eventpoint even while one of its children has an exclusive grab, and can steal the grab away. Now, we do this by building a vector of such parents first, then visiting them in order. It might be more efficient, it eliminates the recursion, and should eliminate the need for a QSet to ensure that we don't visit the same parent more than once. We can't change the behavior of QQuickWindow::sendEvent() because it's public API, but now we don't use it as much internally. Change-Id: I686fc5612c66eac09ec05c381a648ec65dec3923 Reviewed-by: Qt CI Bot Reviewed-by: Jan Arve Sæther --- tests/auto/qmltest/events/tst_touch.qml | 10 ++++++++++ tests/auto/quick/qquickflickable/data/nestedStopAtBounds.qml | 3 +++ 2 files changed, 13 insertions(+) (limited to 'tests') diff --git a/tests/auto/qmltest/events/tst_touch.qml b/tests/auto/qmltest/events/tst_touch.qml index 5b209a6d0b..fd603e5a71 100644 --- a/tests/auto/qmltest/events/tst_touch.qml +++ b/tests/auto/qmltest/events/tst_touch.qml @@ -35,6 +35,16 @@ MultiPointTouchArea { width: 100 height: 100 + // touchUpdatedSpy stores the QQuickTouchPoint, and in some cases + // MultiPointTouchArea can delete it out from under us. + // (test_simpleChain was failing because touchUpdatedSpy.signalArguments[0][0][0] + // ended up as an empty object somehow.) If we declare + // all the touchpoints that this test will use, that won't happen. + touchPoints: [ + TouchPoint { }, + TouchPoint { } + ] + SignalSpy { id: touchUpdatedSpy target: touchArea diff --git a/tests/auto/quick/qquickflickable/data/nestedStopAtBounds.qml b/tests/auto/quick/qquickflickable/data/nestedStopAtBounds.qml index 81187f3c2f..902920babc 100644 --- a/tests/auto/quick/qquickflickable/data/nestedStopAtBounds.qml +++ b/tests/auto/quick/qquickflickable/data/nestedStopAtBounds.qml @@ -18,6 +18,8 @@ Flickable { height: 300 color: "yellow" + objectName: "yellowRect" + Flickable { id: inner objectName: "innerFlickable" @@ -30,6 +32,7 @@ Flickable { Rectangle { anchors.fill: parent anchors.margins: 100 + objectName: "blueRect" color: "blue" } MouseArea { -- cgit v1.2.3 From 73e9dc0667935b7b403c10736775d24d6e22eb8c Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Thu, 2 Feb 2017 17:56:37 +0100 Subject: blacklist tst_TouchMouse::hoverEnabled This should be fixed somehow before merging to dev branch, but the test is blocking work, and maybe doesn't quite make sense yet anyway. Task-number: QTBUG-40856 Change-Id: Icffd3589313df1683550a19347a1d6c5282a619c Reviewed-by: Shawn Rutledge --- tests/auto/quick/touchmouse/BLACKLIST | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 tests/auto/quick/touchmouse/BLACKLIST (limited to 'tests') diff --git a/tests/auto/quick/touchmouse/BLACKLIST b/tests/auto/quick/touchmouse/BLACKLIST new file mode 100644 index 0000000000..ac0352d10b --- /dev/null +++ b/tests/auto/quick/touchmouse/BLACKLIST @@ -0,0 +1,3 @@ +# QTBUG-40856 hover regression on pointerhandler branch: TODO fix before merging to dev +[hoverEnabled] +* -- cgit v1.2.3 From e2fd141372335f917c2d216051abb00d8b15f87c Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Thu, 1 Sep 2016 06:16:18 +0200 Subject: QQuickWindow: deliver updates to handlers even if they don't grab MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The "weak grab" concept depends on this. First we deliver to grabbers, then we deliver to non-grabbing handlers (but not to non-grabbing items). Avoid re-delivering to grabbing handlers which already received the same event. Change-Id: If51e1cd9372e3bed1daea3758e9ef8e37c0ba5e3 Reviewed-by: Jan Arve Sæther --- .../tst_qquickpointerhandler.cpp | 57 +++++++++++++--------- 1 file changed, 33 insertions(+), 24 deletions(-) (limited to 'tests') diff --git a/tests/auto/quick/pointerhandlers/qquickpointerhandler/tst_qquickpointerhandler.cpp b/tests/auto/quick/pointerhandlers/qquickpointerhandler/tst_qquickpointerhandler.cpp index 94bb44a12b..8f65ec6d7f 100644 --- a/tests/auto/quick/pointerhandlers/qquickpointerhandler/tst_qquickpointerhandler.cpp +++ b/tests/auto/quick/pointerhandlers/qquickpointerhandler/tst_qquickpointerhandler.cpp @@ -76,7 +76,7 @@ class EventItem : public QQuickItem Q_OBJECT public: EventItem(QQuickItem *parent = 0) - : QQuickItem(parent), acceptPointer(false), acceptMouse(false), acceptTouch(false), filterTouch(false) + : QQuickItem(parent), acceptPointer(false), grabPointer(false), acceptMouse(false), acceptTouch(false), filterTouch(false) {} void touchEvent(QTouchEvent *event) @@ -125,6 +125,7 @@ public: QList eventList; bool acceptPointer; + bool grabPointer; bool acceptMouse; bool acceptTouch; bool filterTouch; // when used as event filter @@ -159,10 +160,11 @@ class EventHandler : public QQuickPointerHandler int c = event->pointCount(); for (int i = 0; i < c; ++i) { QQuickEventPoint *point = event->point(i); - point->setAccepted(item->acceptPointer); // has no effect: grabbing is up to us if (item->acceptPointer) - setGrab(point, true); - qCDebug(lcPointerTests) << " " << i << ":" << point << "grabbed?" << item->acceptPointer; + point->setAccepted(item->acceptPointer); // non-exclusive grab + if (item->grabPointer) + setGrab(point, true); // exclusive grab + qCDebug(lcPointerTests) << " " << i << ":" << point << "accepted?" << item->acceptPointer << "grabbed?" << (point->grabber() == this); item->eventList.append(Event(QEvent::Pointer, eventPos(point), point->scenePos())); } } @@ -236,17 +238,20 @@ void tst_PointerHandlers::touchEventDelivery() QPoint p1 = QPoint(20, 20); QTest::touchEvent(window, touchDevice).press(0, p1, window); QQuickTouchUtils::flush(window); - QTRY_COMPARE(eventItem1->eventList.size(), 3); + QTRY_COMPARE(eventItem1->eventList.size(), 4); QCOMPARE(eventItem1->eventList.at(0).type, QEvent::Pointer); QCOMPARE(eventItem1->eventList.at(1).type, QEvent::TouchBegin); QCOMPARE(eventItem1->eventList.at(2).type, QEvent::MouseButtonPress); + QCOMPARE(eventItem1->eventList.at(3).type, QEvent::Pointer); p1 += QPoint(10, 0); QTest::touchEvent(window, touchDevice).move(0, p1, window); QQuickTouchUtils::flush(window); - QCOMPARE(eventItem1->eventList.size(), 3); + QCOMPARE(eventItem1->eventList.size(), 5); + QCOMPARE(eventItem1->eventList.at(4).type, QEvent::Pointer); QTest::touchEvent(window, touchDevice).release(0, p1, window); QQuickTouchUtils::flush(window); - QCOMPARE(eventItem1->eventList.size(), 3); + QCOMPARE(eventItem1->eventList.size(), 6); + QCOMPARE(eventItem1->eventList.at(5).type, QEvent::Pointer); eventItem1->eventList.clear(); // Accept touch @@ -321,18 +326,19 @@ void tst_PointerHandlers::touchEventDelivery() p1 = QPoint(20, 20); QTest::touchEvent(window, touchDevice).press(0, p1, window); QQuickTouchUtils::flush(window); - QCOMPARE(eventItem1->eventList.size(), 3); + QCOMPARE(eventItem1->eventList.size(), 4); QCOMPARE(eventItem1->eventList.at(0).type, QEvent::Pointer); QCOMPARE(eventItem1->eventList.at(1).type, QEvent::TouchBegin); QCOMPARE(eventItem1->eventList.at(2).type, QEvent::MouseButtonPress); + QCOMPARE(eventItem1->eventList.at(3).type, QEvent::Pointer); QCOMPARE(pointerEvent->point(0)->grabber(), nullptr); p1 += QPoint(10, 0); QTest::touchEvent(window, touchDevice).move(0, p1, window); QQuickTouchUtils::flush(window); - QCOMPARE(eventItem1->eventList.size(), 3); + QCOMPARE(eventItem1->eventList.size(), 5); QTest::touchEvent(window, touchDevice).release(0, p1, window); QQuickTouchUtils::flush(window); - QCOMPARE(eventItem1->eventList.size(), 3); + QCOMPARE(eventItem1->eventList.size(), 6); eventItem1->eventList.clear(); // wait to avoid getting a double click event @@ -362,6 +368,7 @@ void tst_PointerHandlers::touchEventDelivery() // Accept pointer events eventItem1->acceptPointer = true; + eventItem1->grabPointer = true; p1 = QPoint(20, 20); QTest::touchEvent(window, touchDevice).press(0, p1, window); QQuickTouchUtils::flush(window); @@ -398,12 +405,12 @@ void tst_PointerHandlers::mouseEventDelivery() // Do not accept anything QPoint p1 = QPoint(20, 20); QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, p1); - QCOMPARE(eventItem1->eventList.size(), 2); + QCOMPARE(eventItem1->eventList.size(), 3); p1 += QPoint(10, 0); QTest::mouseMove(window, p1); - QCOMPARE(eventItem1->eventList.size(), 2); + QCOMPARE(eventItem1->eventList.size(), 4); QTest::mouseRelease(window, Qt::LeftButton); - QCOMPARE(eventItem1->eventList.size(), 2); + QCOMPARE(eventItem1->eventList.size(), 4); eventItem1->eventList.clear(); // wait to avoid getting a double click event @@ -415,9 +422,10 @@ void tst_PointerHandlers::mouseEventDelivery() eventItem1->setAcceptedMouseButtons(Qt::LeftButton); p1 = QPoint(20, 20); QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, p1); - QCOMPARE(eventItem1->eventList.size(), 2); + QCOMPARE(eventItem1->eventList.size(), 3); QCOMPARE(eventItem1->eventList.at(0).type, QEvent::Pointer); - QCOMPARE(eventItem1->eventList.at(1).type, QEvent::MouseButtonPress); + QCOMPARE(eventItem1->eventList.at(1).type, QEvent::Pointer); + QCOMPARE(eventItem1->eventList.at(2).type, QEvent::MouseButtonPress); QCOMPARE(window->mouseGrabberItem(), eventItem1); QPointF localPos = eventItem1->mapFromScene(p1); @@ -429,30 +437,31 @@ void tst_PointerHandlers::mouseEventDelivery() p1 += QPoint(10, 0); QTest::mouseMove(window, p1); - QCOMPARE(eventItem1->eventList.size(), 3); - QCOMPARE(eventItem1->eventList.at(2).type, QEvent::MouseMove); + QCOMPARE(eventItem1->eventList.size(), 4); + QCOMPARE(eventItem1->eventList.at(3).type, QEvent::MouseMove); QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p1); - QCOMPARE(eventItem1->eventList.size(), 5); - QCOMPARE(eventItem1->eventList.at(3).type, QEvent::MouseButtonRelease); - QCOMPARE(eventItem1->eventList.at(4).type, QEvent::UngrabMouse); + QCOMPARE(eventItem1->eventList.size(), 6); + QCOMPARE(eventItem1->eventList.at(4).type, QEvent::MouseButtonRelease); + QCOMPARE(eventItem1->eventList.at(5).type, QEvent::UngrabMouse); eventItem1->eventList.clear(); // wait to avoid getting a double click event QTest::qWait(qApp->styleHints()->mouseDoubleClickInterval() + 10); - // Accept pointer events + // Grab pointer events eventItem1->acceptMouse = false; eventItem1->acceptPointer = true; + eventItem1->grabPointer = true; p1 = QPoint(20, 20); QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, p1); - QTRY_COMPARE(eventItem1->eventList.size(), 1); + QTRY_COMPARE(eventItem1->eventList.size(), 2); QCOMPARE(eventItem1->eventList.at(0).type, QEvent::Pointer); p1 += QPoint(10, 0); QTest::mouseMove(window, p1); - QCOMPARE(eventItem1->eventList.size(), 2); + QCOMPARE(eventItem1->eventList.size(), 3); QCOMPARE(eventItem1->eventList.at(1).type, QEvent::Pointer); QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p1); - QCOMPARE(eventItem1->eventList.size(), 3); + QCOMPARE(eventItem1->eventList.size(), 4); QCOMPARE(eventItem1->eventList.at(2).type, QEvent::Pointer); eventItem1->eventList.clear(); -- cgit v1.2.3 From fb8058e5bfbd412e4503eb280721e4875fda0936 Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Wed, 18 Jan 2017 13:53:07 +0100 Subject: QQuickWindow: use QVector eventDeliveryTargets to avoid repeated delivery MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If no handler or item accepts a newly-pressed point, the event will be re-delivered in deliverTouchEvent(). It doesn't make sense to re-deliver to the same handlers though. A temporary QSet isn't cheap to create, whereas it seems we will need to keep track of handlers which have already been visited, in order to avoid visiting passively-grabbing handlers multiple times. Since both a QVector and a QSet are heap-allocated, and we expect to have a limited quantity of handlers grabbing at one time, a retained QVector (cleared between events) seems to be the cheapest data structure. Change-Id: I831e9a2576b2fcb9095e065795f2baff58115a49 Reviewed-by: Jan Arve Sæther --- .../qquickpointerhandler/tst_qquickpointerhandler.cpp | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) (limited to 'tests') diff --git a/tests/auto/quick/pointerhandlers/qquickpointerhandler/tst_qquickpointerhandler.cpp b/tests/auto/quick/pointerhandlers/qquickpointerhandler/tst_qquickpointerhandler.cpp index 8f65ec6d7f..a7237e7af3 100644 --- a/tests/auto/quick/pointerhandlers/qquickpointerhandler/tst_qquickpointerhandler.cpp +++ b/tests/auto/quick/pointerhandlers/qquickpointerhandler/tst_qquickpointerhandler.cpp @@ -238,20 +238,19 @@ void tst_PointerHandlers::touchEventDelivery() QPoint p1 = QPoint(20, 20); QTest::touchEvent(window, touchDevice).press(0, p1, window); QQuickTouchUtils::flush(window); - QTRY_COMPARE(eventItem1->eventList.size(), 4); + QTRY_COMPARE(eventItem1->eventList.size(), 3); QCOMPARE(eventItem1->eventList.at(0).type, QEvent::Pointer); QCOMPARE(eventItem1->eventList.at(1).type, QEvent::TouchBegin); QCOMPARE(eventItem1->eventList.at(2).type, QEvent::MouseButtonPress); - QCOMPARE(eventItem1->eventList.at(3).type, QEvent::Pointer); p1 += QPoint(10, 0); QTest::touchEvent(window, touchDevice).move(0, p1, window); QQuickTouchUtils::flush(window); - QCOMPARE(eventItem1->eventList.size(), 5); - QCOMPARE(eventItem1->eventList.at(4).type, QEvent::Pointer); + QCOMPARE(eventItem1->eventList.size(), 4); + QCOMPARE(eventItem1->eventList.at(3).type, QEvent::Pointer); QTest::touchEvent(window, touchDevice).release(0, p1, window); QQuickTouchUtils::flush(window); - QCOMPARE(eventItem1->eventList.size(), 6); - QCOMPARE(eventItem1->eventList.at(5).type, QEvent::Pointer); + QCOMPARE(eventItem1->eventList.size(), 5); + QCOMPARE(eventItem1->eventList.at(4).type, QEvent::Pointer); eventItem1->eventList.clear(); // Accept touch @@ -326,19 +325,18 @@ void tst_PointerHandlers::touchEventDelivery() p1 = QPoint(20, 20); QTest::touchEvent(window, touchDevice).press(0, p1, window); QQuickTouchUtils::flush(window); - QCOMPARE(eventItem1->eventList.size(), 4); + QCOMPARE(eventItem1->eventList.size(), 3); QCOMPARE(eventItem1->eventList.at(0).type, QEvent::Pointer); QCOMPARE(eventItem1->eventList.at(1).type, QEvent::TouchBegin); QCOMPARE(eventItem1->eventList.at(2).type, QEvent::MouseButtonPress); - QCOMPARE(eventItem1->eventList.at(3).type, QEvent::Pointer); QCOMPARE(pointerEvent->point(0)->grabber(), nullptr); p1 += QPoint(10, 0); QTest::touchEvent(window, touchDevice).move(0, p1, window); QQuickTouchUtils::flush(window); - QCOMPARE(eventItem1->eventList.size(), 5); + QCOMPARE(eventItem1->eventList.size(), 4); QTest::touchEvent(window, touchDevice).release(0, p1, window); QQuickTouchUtils::flush(window); - QCOMPARE(eventItem1->eventList.size(), 6); + QCOMPARE(eventItem1->eventList.size(), 5); eventItem1->eventList.clear(); // wait to avoid getting a double click event -- cgit v1.2.3 From f11c9a24e685178a0a1a2db453e0e43b7ca3a5f2 Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Fri, 24 Jul 2015 10:53:32 +0200 Subject: add MomentumAnimation as a manual test / experiment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It could be exposed as a new type of animation, but for now it's just an experiment. Change-Id: Ic900752a90ccae93270e27399f370f5d47495f74 Reviewed-by: Jan Arve Sæther --- tests/manual/pointer/content/MomentumAnimation.qml | 71 ++++++++++++++++++ tests/manual/pointer/flingAnimation.qml | 84 ++++++++++++++++++++++ tests/manual/pointer/main.qml | 1 + tests/manual/pointer/qml.qrc | 2 + 4 files changed, 158 insertions(+) create mode 100644 tests/manual/pointer/content/MomentumAnimation.qml create mode 100644 tests/manual/pointer/flingAnimation.qml (limited to 'tests') diff --git a/tests/manual/pointer/content/MomentumAnimation.qml b/tests/manual/pointer/content/MomentumAnimation.qml new file mode 100644 index 0000000000..abd9ac9269 --- /dev/null +++ b/tests/manual/pointer/content/MomentumAnimation.qml @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the manual tests of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.8 + +ParallelAnimation { + id: root + property Item target: null + property int duration: 500 + property vector2d velocity: Qt.vector2d(0,0) + + function restart(vel) { + stop() + velocity = vel + start() + } + + NumberAnimation { + id: xAnim + target: root.target + property: "x" + to: target.x + velocity.x / duration * 100000 + duration: root.duration + easing.type: Easing.OutQuad + } + NumberAnimation { + id: yAnim + target: root.target + property: "y" + to: target.y + velocity.y / duration * 100000 + duration: root.duration + easing.type: Easing.OutQuad + } +} diff --git a/tests/manual/pointer/flingAnimation.qml b/tests/manual/pointer/flingAnimation.qml new file mode 100644 index 0000000000..11b97dbb31 --- /dev/null +++ b/tests/manual/pointer/flingAnimation.qml @@ -0,0 +1,84 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the manual tests of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.8 +import Qt.labs.handlers 1.0 +import "content" + +Rectangle { + id: root + width: 640 + height: 480 + color: "black" + + Repeater { + model: 2 + + Image { + id: ball + objectName: "ball" + index + source: "resources/redball.png" + width: 80; height: 80; x: 200 + index * 200; y: 200 + + Text { + anchors.centerIn: parent + color: "white" + text: anim.velocity.x.toFixed(2) + "," + anim.velocity.y.toFixed(2) + } + + MomentumAnimation { id: anim; target: ball } + + DragHandler { + id: dragHandler + onActiveChanged: { + if (!active) + anim.restart(velocity) + } + } + Rectangle { + visible: dragHandler.active + anchors.fill: parent + anchors.margins: -5 + radius: width / 2 + opacity: 0.25 + } + } + } +} diff --git a/tests/manual/pointer/main.qml b/tests/manual/pointer/main.qml index 62202c39b1..3289df161c 100644 --- a/tests/manual/pointer/main.qml +++ b/tests/manual/pointer/main.qml @@ -56,6 +56,7 @@ Window { addExample("pinch", "PinchHandler: scale, rotate and drag", Qt.resolvedUrl("pinchHandler.qml")) addExample("map", "scale and pan", Qt.resolvedUrl("map.qml")) addExample("custom map", "scale and pan", Qt.resolvedUrl("map2.qml")) + addExample("fling animation", "DragHandler: after dragging, use an animation to simulate momentum", Qt.resolvedUrl("flingAnimation.qml")) } } } diff --git a/tests/manual/pointer/qml.qrc b/tests/manual/pointer/qml.qrc index adf255ea1f..9463ae4c84 100644 --- a/tests/manual/pointer/qml.qrc +++ b/tests/manual/pointer/qml.qrc @@ -1,11 +1,13 @@ + flingAnimation.qml main.qml joystick.qml map.qml mixer.qml pinchHandler.qml singlePointHandlerProperties.qml + content/MomentumAnimation.qml content/Slider.qml resources/arrowhead.png resources/grabbing-location.svg -- cgit v1.2.3 From 5d59327ebd0b19a8043f9d35c1c6cbf90681b5b2 Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Thu, 6 Aug 2015 15:43:34 +0200 Subject: add FakeFlickable manual test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Demonstrate that DragHandler, MomentumAnimation and a couple of Items are enough to implement most of Flickable's functionality. Change-Id: I59dae38dc66c16813385aa6c00e3a1a834520f31 Reviewed-by: Jan Arve Sæther --- tests/manual/pointer/content/FakeFlickable.qml | 89 ++++++++++++++++++++++++++ tests/manual/pointer/fakeFlickable.qml | 88 +++++++++++++++++++++++++ tests/manual/pointer/main.qml | 1 + tests/manual/pointer/qml.qrc | 2 + 4 files changed, 180 insertions(+) create mode 100644 tests/manual/pointer/content/FakeFlickable.qml create mode 100644 tests/manual/pointer/fakeFlickable.qml (limited to 'tests') diff --git a/tests/manual/pointer/content/FakeFlickable.qml b/tests/manual/pointer/content/FakeFlickable.qml new file mode 100644 index 0000000000..bfae653503 --- /dev/null +++ b/tests/manual/pointer/content/FakeFlickable.qml @@ -0,0 +1,89 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the manual tests of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.8 +import Qt.labs.handlers 1.0 + +Item { + id: root + default property alias data: __contentItem.data + property alias velocity: anim.velocity + property alias contentX: __contentItem.x // sign is reversed compared to Flickable.contentX + property alias contentY: __contentItem.y // sign is reversed compared to Flickable.contentY + property alias contentWidth: __contentItem.width + property alias contentHeight: __contentItem.height + signal flickStarted + signal flickEnded + + Item { + id: __contentItem + objectName: "__contentItem" + width: childrenRect.width + height: childrenRect.height + + property real xlimit: root.width - __contentItem.width + property real ylimit: root.height - __contentItem.height + + function returnToBounds() { + if (x > 0) + x = 0 + else if (x < xlimit) + x = xlimit + if (y > 0) + y = 0 + else if (y < ylimit) + y = ylimit + } + + DragHandler { + id: dragHandler + onActiveChanged: if (!active) anim.restart(velocity) + } + MomentumAnimation { + id: anim + target: __contentItem + onStarted: root.flickStarted() + onStopped: { + __contentItem.returnToBounds() + root.flickEnded() + } + } + } +} diff --git a/tests/manual/pointer/fakeFlickable.qml b/tests/manual/pointer/fakeFlickable.qml new file mode 100644 index 0000000000..31e3d9f74c --- /dev/null +++ b/tests/manual/pointer/fakeFlickable.qml @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the manual tests of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.8 +import Qt.labs.handlers 1.0 +import "content" + +Rectangle { + color: "#444" + width: 480 + height: 480 + + FakeFlickable { + anchors.fill: parent + Row { + Item { + width: 100 + height: 400 + Slider { + id: slider + label: "font size" + anchors.fill: parent + maximumValue: 36 + value: 14 + } + } + Text { + id: text + color: "beige" + font.family: "mono" + font.pointSize: slider.value + onTextChanged: console.log("text geom " + width + "x" + height + + ", parent " + parent + " geom " + parent.width + "x" + parent.height) + } + } + + + onFlickStarted: console.log("flick started with velocity " + velocity) + onFlickEnded: console.log("flick ended") + + Component.onCompleted: { + var request = new XMLHttpRequest() + request.open('GET', 'content/FakeFlickable.qml') + request.onreadystatechange = function(event) { + if (request.readyState === XMLHttpRequest.DONE) + text.text = request.responseText + } + request.send() + } + } +} diff --git a/tests/manual/pointer/main.qml b/tests/manual/pointer/main.qml index 3289df161c..e61d0ab576 100644 --- a/tests/manual/pointer/main.qml +++ b/tests/manual/pointer/main.qml @@ -57,6 +57,7 @@ Window { addExample("map", "scale and pan", Qt.resolvedUrl("map.qml")) addExample("custom map", "scale and pan", Qt.resolvedUrl("map2.qml")) addExample("fling animation", "DragHandler: after dragging, use an animation to simulate momentum", Qt.resolvedUrl("flingAnimation.qml")) + addExample("fake Flickable", "implementation of a simplified Flickable using only Items, DragHandler and MomentumAnimation", Qt.resolvedUrl("fakeFlickable.qml")) } } } diff --git a/tests/manual/pointer/qml.qrc b/tests/manual/pointer/qml.qrc index 9463ae4c84..50c0dc748d 100644 --- a/tests/manual/pointer/qml.qrc +++ b/tests/manual/pointer/qml.qrc @@ -2,11 +2,13 @@ flingAnimation.qml main.qml + fakeFlickable.qml joystick.qml map.qml mixer.qml pinchHandler.qml singlePointHandlerProperties.qml + content/FakeFlickable.qml content/MomentumAnimation.qml content/Slider.qml resources/arrowhead.png -- cgit v1.2.3 From f1f3fdd166c70da696981ff9070ebfa08df81d80 Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Fri, 7 Aug 2015 13:29:04 +0200 Subject: add modified photosurface as a manual test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is a version of examples/quick/demos/photosurface updated to use handlers instead of Areas. Change-Id: I80a6c46f2ea4821097f3654cd885553aa484d405 Reviewed-by: Jan Arve Sæther --- tests/manual/pointer/main.qml | 3 +- tests/manual/pointer/photosurface.qml | 175 ++++++++++++++++++++++++++++++++++ tests/manual/pointer/qml.qrc | 1 + 3 files changed, 178 insertions(+), 1 deletion(-) create mode 100644 tests/manual/pointer/photosurface.qml (limited to 'tests') diff --git a/tests/manual/pointer/main.qml b/tests/manual/pointer/main.qml index e61d0ab576..601065081d 100644 --- a/tests/manual/pointer/main.qml +++ b/tests/manual/pointer/main.qml @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the manual tests of the Qt Toolkit. @@ -58,6 +58,7 @@ Window { addExample("custom map", "scale and pan", Qt.resolvedUrl("map2.qml")) addExample("fling animation", "DragHandler: after dragging, use an animation to simulate momentum", Qt.resolvedUrl("flingAnimation.qml")) addExample("fake Flickable", "implementation of a simplified Flickable using only Items, DragHandler and MomentumAnimation", Qt.resolvedUrl("fakeFlickable.qml")) + addExample("photo surface", "re-implementation of the existing photo surface demo using Handlers", Qt.resolvedUrl("photosurface.qml")) } } } diff --git a/tests/manual/pointer/photosurface.qml b/tests/manual/pointer/photosurface.qml new file mode 100644 index 0000000000..6601909a37 --- /dev/null +++ b/tests/manual/pointer/photosurface.qml @@ -0,0 +1,175 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the manual tests of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.8 +import QtQuick.Dialogs 1.0 +import Qt.labs.folderlistmodel 1.0 +import Qt.labs.handlers 1.0 +import "content" + +Rectangle { + id: root + visible: true + width: 1024; height: 600 + color: "black" + property int highestZ: 0 + property real defaultSize: 200 + property real surfaceViewportRatio: 1.5 + + FileDialog { + id: fileDialog + title: "Choose a folder with some images" + selectFolder: true + onAccepted: folderModel.folder = fileUrl + "/" + } + Shortcut { + id: openShortcut + sequence: StandardKey.Open + onActivated: fileDialog.open() + } + + FakeFlickable { + id: flick + anchors.fill: parent + contentWidth: width * 2 + contentHeight: height * 2 + Repeater { + model: FolderListModel { + id: folderModel + folder: "resources/" + objectName: "folderModel" + showDirs: false + nameFilters: ["*.png", "*.jpg", "*.gif"] + } + Rectangle { + id: photoFrame + objectName: "frame-" + fileName + width: image.width * (1 + 0.10 * image.height / image.width) + height: image.height * 1.10 + scale: defaultSize / Math.max(image.sourceSize.width, image.sourceSize.height) + Behavior on scale { NumberAnimation { duration: 200 } } + Behavior on x { NumberAnimation { duration: 200 } } + Behavior on y { NumberAnimation { duration: 200 } } + border.color: pinchHandler.active || dragHandler.active ? "red" : "black" + border.width: 2 + smooth: true + antialiasing: true + Component.onCompleted: { + x = Math.random() * root.width - width / 2 + y = Math.random() * root.height - height / 2 + rotation = Math.random() * 13 - 6 + } + Image { + id: image + anchors.centerIn: parent + fillMode: Image.PreserveAspectFit + source: folderModel.folder + fileName + antialiasing: true + } + + MomentumAnimation { id: anim; target: photoFrame } + + DragHandler { + id: dragHandler + onActiveChanged: { + if (!active) + anim.restart(velocity) + } + } + + PinchHandler { + id: pinchHandler + minimumRotation: -360 + maximumRotation: 360 + minimumScale: 0.1 + maximumScale: 10 + property real zRestore: 0 + } + } + } + } + + Rectangle { + id: verticalScrollDecorator + anchors.right: parent.right + anchors.margins: 2 + color: "cyan" + border.color: "black" + border.width: 1 + width: 5 + radius: 2 + antialiasing: true + height: flick.height * (flick.height / flick.contentHeight) - (width - anchors.margins) * 2 + y: -flick.contentY * (flick.height / flick.contentHeight) + NumberAnimation on opacity { id: vfade; to: 0; duration: 500 } + onYChanged: { opacity = 1.0; fadeTimer.restart() } + } + + Rectangle { + id: horizontalScrollDecorator + anchors.bottom: parent.bottom + anchors.margins: 2 + color: "cyan" + border.color: "black" + border.width: 1 + height: 5 + radius: 2 + antialiasing: true + width: flick.width * (flick.width / flick.contentWidth) - (height - anchors.margins) * 2 + x: -flick.contentX * (flick.width / flick.contentWidth) + NumberAnimation on opacity { id: hfade; to: 0; duration: 500 } + onXChanged: { opacity = 1.0; fadeTimer.restart() } + } + + Timer { id: fadeTimer; interval: 1000; onTriggered: { hfade.start(); vfade.start() } } + + Text { + anchors.bottom: parent.bottom + anchors.left: parent.left + anchors.right: parent.right + anchors.margins: 10 + color: "darkgrey" + wrapMode: Text.WordWrap + font.pointSize: 8 + text: "Press " + openShortcut.nativeText + " to choose a different image folder\n" + + "On a touchscreen: use two fingers to zoom and rotate, one finger to drag\n" + + "With a mouse: drag normally" + } +} diff --git a/tests/manual/pointer/qml.qrc b/tests/manual/pointer/qml.qrc index 50c0dc748d..87fc021680 100644 --- a/tests/manual/pointer/qml.qrc +++ b/tests/manual/pointer/qml.qrc @@ -6,6 +6,7 @@ joystick.qml map.qml mixer.qml + photosurface.qml pinchHandler.qml singlePointHandlerProperties.qml content/FakeFlickable.qml -- cgit v1.2.3 From 2d61a39dedfb2718cdb6c26b370b7e4103db9c4a Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Tue, 28 Jul 2015 15:24:29 +0200 Subject: Introduce TapHandler MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Device-agnostic tap/click detection. Also detect whether the taps or clicks occur close enough together in both time and space to be considered part of a multi-tap gesture. Change-Id: I41a378feea3340b9f0409118273746a289641d6c Reviewed-by: Jan Arve Sæther --- tests/manual/pointer/main.qml | 1 + tests/manual/pointer/qml.qrc | 1 + tests/manual/pointer/tapHandler.qml | 136 ++++++++++++++++++++++++++++++++++++ 3 files changed, 138 insertions(+) create mode 100644 tests/manual/pointer/tapHandler.qml (limited to 'tests') diff --git a/tests/manual/pointer/main.qml b/tests/manual/pointer/main.qml index 601065081d..b06d3cf155 100644 --- a/tests/manual/pointer/main.qml +++ b/tests/manual/pointer/main.qml @@ -59,6 +59,7 @@ Window { addExample("fling animation", "DragHandler: after dragging, use an animation to simulate momentum", Qt.resolvedUrl("flingAnimation.qml")) addExample("fake Flickable", "implementation of a simplified Flickable using only Items, DragHandler and MomentumAnimation", Qt.resolvedUrl("fakeFlickable.qml")) addExample("photo surface", "re-implementation of the existing photo surface demo using Handlers", Qt.resolvedUrl("photosurface.qml")) + addExample("tap", "TapHandler: device-agnostic tap/click detection for buttons", Qt.resolvedUrl("tapHandler.qml")) } } } diff --git a/tests/manual/pointer/qml.qrc b/tests/manual/pointer/qml.qrc index 87fc021680..4535a26802 100644 --- a/tests/manual/pointer/qml.qrc +++ b/tests/manual/pointer/qml.qrc @@ -9,6 +9,7 @@ photosurface.qml pinchHandler.qml singlePointHandlerProperties.qml + tapHandler.qml content/FakeFlickable.qml content/MomentumAnimation.qml content/Slider.qml diff --git a/tests/manual/pointer/tapHandler.qml b/tests/manual/pointer/tapHandler.qml new file mode 100644 index 0000000000..d099fc7faf --- /dev/null +++ b/tests/manual/pointer/tapHandler.qml @@ -0,0 +1,136 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the manual tests of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.8 +import Qt.labs.handlers 1.0 +import "qrc:/quick/shared/" as Examples + +Item { + width: 480 + height: 320 + + Rectangle { + id: rect + anchors.fill: parent; anchors.margins: 40 + border.width: 3; border.color: "transparent" + color: handler.isPressed ? "lightsteelblue" : "darkgrey" + + TapHandler { + id: handler + acceptedButtons: (leftAllowedCB.checked ? Qt.LeftButton : Qt.NoButton) | + (middleAllowedCB.checked ? Qt.MiddleButton : Qt.NoButton) | + (rightAllowedCB.checked ? Qt.RightButton : Qt.NoButton) + onCanceled: { + console.log("canceled @ " + pos) + borderBlink.blinkColor = "red" + borderBlink.start() + } + onTapped: { + console.log("tapped @ " + point.pos + " button(s) " + point.event.button + " tapCount " + tapCount) + if (tapCount > 1) { + tapCountLabel.text = tapCount + flashAnimation.start() + } else { + switch (point.event.button) { + case Qt.LeftButton: borderBlink.blinkColor = "green"; break; + case Qt.MiddleButton: borderBlink.blinkColor = "orange"; break; + case Qt.RightButton: borderBlink.blinkColor = "magenta"; break; + } + borderBlink.start() + } + } + } + + Text { + id: tapCountLabel + anchors.centerIn: parent + font.pixelSize: 72 + font.weight: Font.Black + SequentialAnimation { + id: flashAnimation + PropertyAction { target: tapCountLabel; property: "visible"; value: true } + PropertyAction { target: tapCountLabel; property: "opacity"; value: 1.0 } + PropertyAction { target: tapCountLabel; property: "scale"; value: 1.0 } + ParallelAnimation { + NumberAnimation { + target: tapCountLabel + property: "opacity" + to: 0 + duration: 500 + } + NumberAnimation { + target: tapCountLabel + property: "scale" + to: 1.5 + duration: 500 + } + } + } + } + + SequentialAnimation { + id: borderBlink + property color blinkColor: "blue" + loops: 3 + ScriptAction { script: rect.border.color = borderBlink.blinkColor } + PauseAnimation { duration: 100 } + ScriptAction { script: rect.border.color = "transparent" } + PauseAnimation { duration: 100 } + } + } + + Row { + spacing: 6 + Text { text: "accepted mouse clicks:"; anchors.verticalCenter: leftAllowedCB.verticalCenter } + Examples.CheckBox { + id: leftAllowedCB + checked: true + text: "left click" + } + Examples.CheckBox { + id: middleAllowedCB + text: "middle click" + } + Examples.CheckBox { + id: rightAllowedCB + text: "right click" + } + } +} -- cgit v1.2.3 From 3e21962cea50433c8f043d2a8a0d61ef86339a22 Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Tue, 3 Jan 2017 08:57:02 +0100 Subject: add flickableWithHandlers manual test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit to verify that Flickable still works after the changes in event delivery logic, even when it contains a mix of various Areas and Handlers. Change-Id: Ibf68bc8b403718c87c7e647b17837f2a8e4e3f0e Reviewed-by: Jan Arve Sæther --- tests/manual/pointer/content/MouseAreaButton.qml | 86 ++++++++++++++++ tests/manual/pointer/content/MouseAreaSlider.qml | 119 ++++++++++++++++++++++ tests/manual/pointer/content/MptaButton.qml | 87 ++++++++++++++++ tests/manual/pointer/content/TapHandlerButton.qml | 84 +++++++++++++++ tests/manual/pointer/flickableWithHandlers.qml | 88 ++++++++++++++++ 5 files changed, 464 insertions(+) create mode 100644 tests/manual/pointer/content/MouseAreaButton.qml create mode 100644 tests/manual/pointer/content/MouseAreaSlider.qml create mode 100644 tests/manual/pointer/content/MptaButton.qml create mode 100644 tests/manual/pointer/content/TapHandlerButton.qml create mode 100644 tests/manual/pointer/flickableWithHandlers.qml (limited to 'tests') diff --git a/tests/manual/pointer/content/MouseAreaButton.qml b/tests/manual/pointer/content/MouseAreaButton.qml new file mode 100644 index 0000000000..de1d972386 --- /dev/null +++ b/tests/manual/pointer/content/MouseAreaButton.qml @@ -0,0 +1,86 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.1 +import QtQuick.Window 2.1 + +Item { + id: container + + property alias text: buttonLabel.text + property alias label: buttonLabel + signal clicked + property alias containsMouse: mouseArea.containsMouse + property alias pressed: mouseArea.pressed + implicitHeight: Math.max(Screen.pixelDensity * 7, buttonLabel.implicitHeight * 1.2) + implicitWidth: Math.max(Screen.pixelDensity * 11, buttonLabel.implicitWidth * 1.3) + height: implicitHeight + width: implicitWidth + + SystemPalette { id: palette } + + Rectangle { + id: frame + anchors.fill: parent + color: palette.button + gradient: Gradient { + GradientStop { position: 0.0; color: mouseArea.pressed ? Qt.darker(palette.button, 1.3) : palette.button } + GradientStop { position: 1.0; color: Qt.darker(palette.button, 1.3) } + } + antialiasing: true + radius: height / 6 + border.color: Qt.darker(palette.button, 1.5) + border.width: 1 + } + + MouseArea { + id: mouseArea + anchors.fill: parent + onClicked: container.clicked() + hoverEnabled: true + } + + Text { + id: buttonLabel + text: container.text + color: palette.buttonText + anchors.centerIn: parent + } +} diff --git a/tests/manual/pointer/content/MouseAreaSlider.qml b/tests/manual/pointer/content/MouseAreaSlider.qml new file mode 100644 index 0000000000..c34c528c7d --- /dev/null +++ b/tests/manual/pointer/content/MouseAreaSlider.qml @@ -0,0 +1,119 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the manual tests of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.7 + +Item { + id: root + property int value: 50 + property int maximumValue: 99 + property alias label: label.text + + Rectangle { + id: slot + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.margins: 10 + anchors.topMargin: 30 + anchors.bottomMargin: 30 + anchors.horizontalCenter: parent.horizontalCenter + width: 10 + color: "black" + radius: width / 2 + smooth: true + } + + Rectangle { + // RectangularGlow is better, but that's a different module + id: glow + anchors.fill: knob + anchors.margins: -5 + anchors.leftMargin: -2 + anchors.horizontalCenterOffset: 1 + radius: 5 + color: "#4400FFFF" + opacity: ma.pressed ? 1 : 0 + } + Image { + id: knob + source: "../resources/mixer-knob.png" + antialiasing: true + x: slot.x - width / 2 + slot.width / 2 + height: root.width / 2 + width: implicitWidth / implicitHeight * height + property bool programmatic: false + property real multiplier: root.maximumValue / (ma.drag.maximumY - ma.drag.minimumY) + onYChanged: if (!programmatic) root.value = root.maximumValue - (knob.y - ma.drag.minimumY) * multiplier + transformOrigin: Item.Center + function setValue(value) { knob.y = ma.drag.maximumY - value / knob.multiplier } + MouseArea { + id: ma + anchors.fill: parent + drag.target: parent + drag.minimumX: knob.x + drag.maximumX: knob.x + drag.minimumY: slot.y + drag.maximumY: slot.height + slot.y - knob.height + } + } + + Text { + font.pointSize: 16 + color: "red" + anchors.bottom: parent.bottom + anchors.horizontalCenter: parent.horizontalCenter + text: root.value + } + + Text { + id: label + font.pointSize: 12 + color: "red" + anchors.top: parent.top + anchors.topMargin: 5 + anchors.horizontalCenter: parent.horizontalCenter + } + + onHeightChanged: { + knob.programmatic = true + knob.setValue(root.value) + knob.programmatic = false + } +} diff --git a/tests/manual/pointer/content/MptaButton.qml b/tests/manual/pointer/content/MptaButton.qml new file mode 100644 index 0000000000..836744822b --- /dev/null +++ b/tests/manual/pointer/content/MptaButton.qml @@ -0,0 +1,87 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.7 +import QtQuick.Window 2.1 + +Item { + id: container + + property alias text: buttonLabel.text + property alias label: buttonLabel + signal clicked + property alias pressed: point.pressed + implicitHeight: Math.max(Screen.pixelDensity * 7, buttonLabel.implicitHeight * 1.2) + implicitWidth: Math.max(Screen.pixelDensity * 11, buttonLabel.implicitWidth * 1.3) + height: implicitHeight + width: implicitWidth + + SystemPalette { id: palette } + + Rectangle { + id: frame + anchors.fill: parent + color: palette.button + gradient: Gradient { + GradientStop { position: 0.0; color: container.pressed ? Qt.darker(palette.button, 1.3) : palette.button } + GradientStop { position: 1.0; color: Qt.darker(palette.button, 1.3) } + } + antialiasing: true + radius: height / 6 + border.color: Qt.darker(palette.button, 1.5) + border.width: 1 + } + + MultiPointTouchArea { + id: mpta + anchors.fill: parent + touchPoints: [ TouchPoint { + id: point + onPressedChanged: if (!pressed) container.clicked() + } ] + } + + Text { + id: buttonLabel + text: container.text + color: palette.buttonText + anchors.centerIn: parent + } +} diff --git a/tests/manual/pointer/content/TapHandlerButton.qml b/tests/manual/pointer/content/TapHandlerButton.qml new file mode 100644 index 0000000000..e40c539686 --- /dev/null +++ b/tests/manual/pointer/content/TapHandlerButton.qml @@ -0,0 +1,84 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.7 +import QtQuick.Window 2.1 +import Qt.labs.handlers 1.0 + +Item { + id: container + + property alias text: buttonLabel.text + property alias label: buttonLabel + signal clicked + property alias pressed: th.isPressed + implicitHeight: Math.max(Screen.pixelDensity * 7, buttonLabel.implicitHeight * 1.2) + implicitWidth: Math.max(Screen.pixelDensity * 11, buttonLabel.implicitWidth * 1.3) + height: implicitHeight + width: implicitWidth + + SystemPalette { id: palette } + + Rectangle { + id: frame + anchors.fill: parent + color: palette.button + gradient: Gradient { + GradientStop { position: 0.0; color: container.pressed ? Qt.darker(palette.button, 1.3) : palette.button } + GradientStop { position: 1.0; color: Qt.darker(palette.button, 1.3) } + } + antialiasing: true + radius: height / 6 + border.color: Qt.darker(palette.button, 1.5) + border.width: 1 + } + + TapHandler { + id: th + onTapped: container.clicked() + } + + Text { + id: buttonLabel + text: container.text + color: palette.buttonText + anchors.centerIn: parent + } +} diff --git a/tests/manual/pointer/flickableWithHandlers.qml b/tests/manual/pointer/flickableWithHandlers.qml new file mode 100644 index 0000000000..59e8661aac --- /dev/null +++ b/tests/manual/pointer/flickableWithHandlers.qml @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the manual tests of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.7 +import Qt.labs.handlers 1.0 +import "content" + +Rectangle { + id: root + width: 300 + height: 400 + objectName: "root" + color: "#222222" + + Flickable { + anchors.fill: parent + anchors.margins: 10 + contentHeight: 600 + contentWidth: 600 + + Row { + spacing: 6 + Slider { + label: "DragHandler" + width: 100; height: 500 + } + MouseAreaSlider { + label: "MouseArea" + width: 100; height: 500 + } + Column { + spacing: 6 + MouseAreaButton { + text: "MouseArea" + } + MptaButton { + text: "MultiPointTouchArea" + } + MptaButton { + text: "MultiPointTouchArea" + } + TapHandlerButton { + text: "TapHandler" + } + TapHandlerButton { + text: "TapHandler" + } + } + } + } +} -- cgit v1.2.3 From 5c639a07fd90916d39823e800d5d89f779d892e9 Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Fri, 18 Nov 2016 15:02:18 +0100 Subject: TapHandler: add long-press feature MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a longPressed signal, emitted when the point is held long enough. Add the longPressThreshold to control how long that is. Change-Id: I95a65f1e4c62eb41fb9ea02b14bdc3f16aa72ec2 Reviewed-by: Jan Arve Sæther --- tests/manual/pointer/tapHandler.qml | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) (limited to 'tests') diff --git a/tests/manual/pointer/tapHandler.qml b/tests/manual/pointer/tapHandler.qml index d099fc7faf..f2a454fb80 100644 --- a/tests/manual/pointer/tapHandler.qml +++ b/tests/manual/pointer/tapHandler.qml @@ -57,6 +57,11 @@ Item { acceptedButtons: (leftAllowedCB.checked ? Qt.LeftButton : Qt.NoButton) | (middleAllowedCB.checked ? Qt.MiddleButton : Qt.NoButton) | (rightAllowedCB.checked ? Qt.RightButton : Qt.NoButton) + onPressedButtonsChanged: switch (pressedButtons) { + case Qt.MiddleButton: borderBlink.blinkColor = "orange"; break; + case Qt.RightButton: borderBlink.blinkColor = "magenta"; break; + default: borderBlink.blinkColor = "green"; break; + } onCanceled: { console.log("canceled @ " + pos) borderBlink.blinkColor = "red" @@ -68,14 +73,13 @@ Item { tapCountLabel.text = tapCount flashAnimation.start() } else { - switch (point.event.button) { - case Qt.LeftButton: borderBlink.blinkColor = "green"; break; - case Qt.MiddleButton: borderBlink.blinkColor = "orange"; break; - case Qt.RightButton: borderBlink.blinkColor = "magenta"; break; - } borderBlink.start() } } + onLongPressed: longPressFeedback.createObject(rect, + {"x": pos.x, "y": pos.y, + "text": "long press", + "color": borderBlink.blinkColor}) } Text { @@ -105,6 +109,11 @@ Item { } } + Component { + id: longPressFeedback + Text { } + } + SequentialAnimation { id: borderBlink property color blinkColor: "blue" -- cgit v1.2.3 From cb78d5c91ed33543a8e7fe7717f74f95834e4cc3 Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Tue, 18 Oct 2016 18:45:49 +0200 Subject: TapHandler: add gesturePolicy MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Until now it behaved as if this was set to DragThreshold: give up on the tap as soon as you are clearly dragging rather than tapping. But that's not what is normally wanted when building a Button control, for example. So provide 3 options: give up past the drag threshold, when the pointer goes outside the bounds, or when it's released outside the bounds. The longPressThreshold also constrains all three cases: holding (or dragging) for too long will not result in an immediate cancellation, but it also will not be a tap gesture. Change-Id: I95aec978e783892b55371391a27642751d91d9ff Reviewed-by: Jan Arve Sæther --- tests/manual/pointer/content/FlashAnimation.qml | 57 ++++++++++++++ tests/manual/pointer/content/MultiButton.qml | 85 +++++++++++++++++++++ tests/manual/pointer/content/Slider.qml | 19 ++++- tests/manual/pointer/main.qml | 1 + tests/manual/pointer/multibuttons.qml | 95 ++++++++++++++++++++++++ tests/manual/pointer/qml.qrc | 6 ++ tests/manual/pointer/resources/balloon.png | Bin 0 -> 3759 bytes tests/manual/pointer/resources/fighter.png | Bin 0 -> 9669 bytes tests/manual/pointer/resources/missile.png | Bin 0 -> 2305 bytes tests/manual/pointer/resources/mixer-knob.png | Bin 8555 -> 7821 bytes tests/manual/pointer/tapHandler.qml | 29 ++++++++ 11 files changed, 290 insertions(+), 2 deletions(-) create mode 100644 tests/manual/pointer/content/FlashAnimation.qml create mode 100644 tests/manual/pointer/content/MultiButton.qml create mode 100644 tests/manual/pointer/multibuttons.qml create mode 100644 tests/manual/pointer/resources/balloon.png create mode 100644 tests/manual/pointer/resources/fighter.png create mode 100644 tests/manual/pointer/resources/missile.png (limited to 'tests') diff --git a/tests/manual/pointer/content/FlashAnimation.qml b/tests/manual/pointer/content/FlashAnimation.qml new file mode 100644 index 0000000000..b628255a3d --- /dev/null +++ b/tests/manual/pointer/content/FlashAnimation.qml @@ -0,0 +1,57 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the manual tests of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 + +SequentialAnimation { + id: tapFlash + running: false + PropertyAction { value: false } + PauseAnimation { duration: 100 } + PropertyAction { value: true } + PauseAnimation { duration: 100 } + PropertyAction { value: false } + PauseAnimation { duration: 100 } + PropertyAction { value: true } + PauseAnimation { duration: 100 } + PropertyAction { value: false } + PauseAnimation { duration: 100 } + PropertyAction { value: true } +} diff --git a/tests/manual/pointer/content/MultiButton.qml b/tests/manual/pointer/content/MultiButton.qml new file mode 100644 index 0000000000..5b31e9ebd0 --- /dev/null +++ b/tests/manual/pointer/content/MultiButton.qml @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the manual tests of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.8 +import Qt.labs.handlers 1.0 + +Rectangle { + id: root + property alias label: label.text + property alias pressed: tap.isPressed + property bool checked: false + property alias gesturePolicy: tap.gesturePolicy + signal tapped + + width: label.implicitWidth * 1.5; height: label.implicitHeight * 2.0 + border.color: "#9f9d9a"; border.width: 1; radius: height / 4; antialiasing: true + + gradient: Gradient { + GradientStop { position: 0.0; color: tap.isPressed ? "#b8b5b2" : "#efebe7" } + GradientStop { position: 1.0; color: "#b8b5b2" } + } + + TapHandler { + id: tap + objectName: label.text + onTapped: { + tapFlash.start() + root.tapped + } + } + + Text { + id: label + font.pointSize: 14 + text: "Button" + anchors.centerIn: parent + } + + Rectangle { + anchors.fill: parent + color: "transparent" + border.width: 2; radius: root.radius; antialiasing: true + opacity: tapFlash.running ? 1 : 0 + FlashAnimation on visible { + id: tapFlash + } + } +} diff --git a/tests/manual/pointer/content/Slider.qml b/tests/manual/pointer/content/Slider.qml index cd52dfac80..a1decf8c4b 100644 --- a/tests/manual/pointer/content/Slider.qml +++ b/tests/manual/pointer/content/Slider.qml @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the manual tests of the Qt Toolkit. @@ -46,6 +46,9 @@ Item { property int value: 50 property int maximumValue: 99 property alias label: label.text + property alias tapEnabled: tap.enabled + property alias pressed: tap.isPressed + signal tapped Rectangle { id: slot @@ -70,7 +73,10 @@ Item { anchors.horizontalCenterOffset: 1 radius: 5 color: "#4400FFFF" - opacity: dragHandler.active ? 1 : 0 + opacity: dragHandler.active || tapFlash.running ? 1 : 0 + FlashAnimation on visible { + id: tapFlash + } } Image { id: knob @@ -90,6 +96,15 @@ Item { yAxis.minimum: slot.y yAxis.maximum: slot.height + slot.y - knob.height } + TapHandler { + id: tap + objectName: label.text + gesturePolicy: TapHandler.DragThreshold + onTapped: { + tapFlash.start() + root.tapped + } + } } Text { diff --git a/tests/manual/pointer/main.qml b/tests/manual/pointer/main.qml index b06d3cf155..a71490d23b 100644 --- a/tests/manual/pointer/main.qml +++ b/tests/manual/pointer/main.qml @@ -60,6 +60,7 @@ Window { addExample("fake Flickable", "implementation of a simplified Flickable using only Items, DragHandler and MomentumAnimation", Qt.resolvedUrl("fakeFlickable.qml")) addExample("photo surface", "re-implementation of the existing photo surface demo using Handlers", Qt.resolvedUrl("photosurface.qml")) addExample("tap", "TapHandler: device-agnostic tap/click detection for buttons", Qt.resolvedUrl("tapHandler.qml")) + addExample("multibuttons", "TapHandler: gesturePolicy (99 red balloons)", Qt.resolvedUrl("multibuttons.qml")) } } } diff --git a/tests/manual/pointer/multibuttons.qml b/tests/manual/pointer/multibuttons.qml new file mode 100644 index 0000000000..16d2f191e7 --- /dev/null +++ b/tests/manual/pointer/multibuttons.qml @@ -0,0 +1,95 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the manual tests of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 +import QtQuick.Particles 2.0 +import QtQuick.Layouts 1.0 +import Qt.labs.handlers 1.0 +import "content" + +Item { + width: 800 + height: 800 + ColumnLayout { + anchors.right: parent.right + spacing: 20 + Text { text: "protagonist"; font.pointSize: 12 } + MultiButton { + id: balloonsButton + label: "Launch Balloons" + Layout.fillWidth: true + gesturePolicy: TapHandler.DragThreshold + } + Text { text: "the goons"; font.pointSize: 12 } + MultiButton { + id: missilesButton + label: "Launch Missiles" + Layout.fillWidth: true + gesturePolicy: TapHandler.WithinBounds + } + MultiButton { + id: fightersButton + label: "Launch Fighters" + Layout.fillWidth: true + gesturePolicy: TapHandler.ReleaseWithinBounds + } + } + ParticleSystem { + anchors.bottom: parent.bottom + anchors.left: parent.left + anchors.leftMargin: 150 + ImageParticle { source: "resources/balloon.png" } + Emitter { anchors.bottom: parent.bottom; enabled: balloonsButton.pressed; lifeSpan: 5000; size: 64 + maximumEmitted: 99 + emitRate: 50; velocity: PointDirection { x: 10; y: -150; yVariation: 30; xVariation: 50 } } } + ParticleSystem { + anchors.verticalCenter: parent.verticalCenter + anchors.right: parent.right + ImageParticle { source: "resources/fighter.png" } + Emitter { anchors.bottom: parent.bottom; enabled: fightersButton.pressed; lifeSpan: 15000; size: 204 + emitRate: 3; velocity: PointDirection { x: -1000; y: -250; yVariation: 150; xVariation: 50 } } } + ParticleSystem { + anchors.bottom: parent.bottom + anchors.right: parent.right + anchors.rightMargin: 100 + ImageParticle { source: "resources/missile.png"; autoRotation: true; rotation: 90 } + Emitter { anchors.bottom: parent.bottom; enabled: missilesButton.pressed; lifeSpan: 5000; size: 128 + emitRate: 10; velocity: PointDirection { x: -200; y: -350; yVariation: 200; xVariation: 100 } } } +} diff --git a/tests/manual/pointer/qml.qrc b/tests/manual/pointer/qml.qrc index 4535a26802..4113974d46 100644 --- a/tests/manual/pointer/qml.qrc +++ b/tests/manual/pointer/qml.qrc @@ -6,16 +6,22 @@ joystick.qml map.qml mixer.qml + multibuttons.qml photosurface.qml pinchHandler.qml singlePointHandlerProperties.qml tapHandler.qml content/FakeFlickable.qml + content/FlashAnimation.qml content/MomentumAnimation.qml + content/MultiButton.qml content/Slider.qml resources/arrowhead.png + resources/balloon.png + resources/fighter.png resources/grabbing-location.svg resources/map.svgz + resources/missile.png resources/mixer-knob.png resources/mouse.png resources/mouse_left.png diff --git a/tests/manual/pointer/resources/balloon.png b/tests/manual/pointer/resources/balloon.png new file mode 100644 index 0000000000..6476facc49 Binary files /dev/null and b/tests/manual/pointer/resources/balloon.png differ diff --git a/tests/manual/pointer/resources/fighter.png b/tests/manual/pointer/resources/fighter.png new file mode 100644 index 0000000000..2acee43cba Binary files /dev/null and b/tests/manual/pointer/resources/fighter.png differ diff --git a/tests/manual/pointer/resources/missile.png b/tests/manual/pointer/resources/missile.png new file mode 100644 index 0000000000..72c02d1fb9 Binary files /dev/null and b/tests/manual/pointer/resources/missile.png differ diff --git a/tests/manual/pointer/resources/mixer-knob.png b/tests/manual/pointer/resources/mixer-knob.png index 02cc9fc72b..b7d42ee3bd 100644 Binary files a/tests/manual/pointer/resources/mixer-knob.png and b/tests/manual/pointer/resources/mixer-knob.png differ diff --git a/tests/manual/pointer/tapHandler.qml b/tests/manual/pointer/tapHandler.qml index f2a454fb80..2e45b1c369 100644 --- a/tests/manual/pointer/tapHandler.qml +++ b/tests/manual/pointer/tapHandler.qml @@ -57,6 +57,9 @@ Item { acceptedButtons: (leftAllowedCB.checked ? Qt.LeftButton : Qt.NoButton) | (middleAllowedCB.checked ? Qt.MiddleButton : Qt.NoButton) | (rightAllowedCB.checked ? Qt.RightButton : Qt.NoButton) + gesturePolicy: (policyDragThresholdCB.checked ? TapHandler.DragThreshold : + policyWithinBoundsCB.checked ? TapHandler.WithinBounds : + TapHandler.ReleaseWithinBounds) onPressedButtonsChanged: switch (pressedButtons) { case Qt.MiddleButton: borderBlink.blinkColor = "orange"; break; case Qt.RightButton: borderBlink.blinkColor = "magenta"; break; @@ -141,5 +144,31 @@ Item { id: rightAllowedCB text: "right click" } + Text { text: " gesture policy:"; anchors.verticalCenter: leftAllowedCB.verticalCenter } + Examples.CheckBox { + id: policyDragThresholdCB + text: "drag threshold" + onCheckedChanged: if (checked) { + policyWithinBoundsCB.checked = false; + policyReleaseWithinBoundsCB.checked = false; + } + } + Examples.CheckBox { + id: policyWithinBoundsCB + text: "within bounds" + onCheckedChanged: if (checked) { + policyDragThresholdCB.checked = false; + policyReleaseWithinBoundsCB.checked = false; + } + } + Examples.CheckBox { + id: policyReleaseWithinBoundsCB + checked: true + text: "release within bounds" + onCheckedChanged: if (checked) { + policyDragThresholdCB.checked = false; + policyWithinBoundsCB.checked = false; + } + } } } -- cgit v1.2.3 From 12f3f20be7e160b4f8de4ee267909fec61673111 Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Wed, 5 Aug 2015 12:45:48 +0200 Subject: TapHandler: add timeHeld property MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It enables long-press gestures to have continuous feedback. Change-Id: Idd0838aff6213ebfc2fce66639bbc932e77208b4 Reviewed-by: Jan Arve Sæther --- tests/manual/pointer/tapHandler.qml | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) (limited to 'tests') diff --git a/tests/manual/pointer/tapHandler.qml b/tests/manual/pointer/tapHandler.qml index 2e45b1c369..06070a02ff 100644 --- a/tests/manual/pointer/tapHandler.qml +++ b/tests/manual/pointer/tapHandler.qml @@ -81,7 +81,7 @@ Item { } onLongPressed: longPressFeedback.createObject(rect, {"x": pos.x, "y": pos.y, - "text": "long press", + "text": Math.round(handler.timeHeld).toFixed(3) + " sec", "color": borderBlink.blinkColor}) } @@ -112,6 +112,20 @@ Item { } } + Rectangle { + id: expandingCircle + radius: handler.timeHeld * 100 + visible: radius > 0 && handler.isPressed + border.width: 3 + border.color: borderBlink.blinkColor + color: "transparent" + width: radius * 2 + height: radius * 2 + x: handler.pressPos.x - radius + y: handler.pressPos.y - radius + opacity: 0.25 + } + Component { id: longPressFeedback Text { } -- cgit v1.2.3 From 50aaca40fe09a3ab6c927f7a550b2e97cf332a9c Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Tue, 29 Nov 2016 14:50:05 +0100 Subject: start making explicit exclusive or passive grabs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I4a6e3c72d69e893fec2e39f4faab24af6d00c7e0 Reviewed-by: Jan Arve Sæther --- .../qquickpointerhandler/tst_qquickpointerhandler.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'tests') diff --git a/tests/auto/quick/pointerhandlers/qquickpointerhandler/tst_qquickpointerhandler.cpp b/tests/auto/quick/pointerhandlers/qquickpointerhandler/tst_qquickpointerhandler.cpp index a7237e7af3..5282fb8a6c 100644 --- a/tests/auto/quick/pointerhandlers/qquickpointerhandler/tst_qquickpointerhandler.cpp +++ b/tests/auto/quick/pointerhandlers/qquickpointerhandler/tst_qquickpointerhandler.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtQml module of the Qt Toolkit. @@ -161,9 +161,9 @@ class EventHandler : public QQuickPointerHandler for (int i = 0; i < c; ++i) { QQuickEventPoint *point = event->point(i); if (item->acceptPointer) - point->setAccepted(item->acceptPointer); // non-exclusive grab + point->setAccepted(item->acceptPointer); // does NOT imply a grab if (item->grabPointer) - setGrab(point, true); // exclusive grab + setExclusiveGrab(point, true); qCDebug(lcPointerTests) << " " << i << ":" << point << "accepted?" << item->acceptPointer << "grabbed?" << (point->grabber() == this); item->eventList.append(Event(QEvent::Pointer, eventPos(point), point->scenePos())); } -- cgit v1.2.3 From 4e7041c65216ada4f5fb604a9df840152ba60317 Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Wed, 8 Feb 2017 15:08:53 +0100 Subject: pointer handlers manual test: can give arg with qml to launch MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This makes it easier to repeatedly launch the same test: specify the qml file on the command line instead of having to click the list item each time. e.g. ./pointer tapHandler.qml Change-Id: I30b449b161107b1746418fc45518d202ba7d8381 Reviewed-by: Jan Arve Sæther --- tests/manual/pointer/main.cpp | 15 +++++++++++++++ tests/manual/pointer/main.qml | 1 + 2 files changed, 16 insertions(+) (limited to 'tests') diff --git a/tests/manual/pointer/main.cpp b/tests/manual/pointer/main.cpp index a4e1060cf5..7935b4072c 100644 --- a/tests/manual/pointer/main.cpp +++ b/tests/manual/pointer/main.cpp @@ -39,6 +39,8 @@ ****************************************************************************/ #include #include +#include +#include int main(int argc, char *argv[]) { @@ -46,6 +48,19 @@ int main(int argc, char *argv[]) QQmlApplicationEngine engine; engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); + if (!app.arguments().isEmpty()) { + QQuickWindow * win = static_cast(engine.rootObjects().first()); + auto lastArg = app.arguments().last(); + if (lastArg.endsWith(QLatin1String(".qml"))) { + auto root = win->findChild("LauncherList"); + int showExampleIdx = -1; + for (int i = root->metaObject()->methodCount(); showExampleIdx < 0 && i >= 0; --i) + if (root->metaObject()->method(i).name() == QByteArray("showExample")) + showExampleIdx = i; + QMetaMethod showExampleFn = root->metaObject()->method(showExampleIdx); + showExampleFn.invoke(root, Q_ARG(QVariant, QVariant(QLatin1String("../../") + lastArg))); + } + } return app.exec(); } diff --git a/tests/manual/pointer/main.qml b/tests/manual/pointer/main.qml index a71490d23b..e60edd06ce 100644 --- a/tests/manual/pointer/main.qml +++ b/tests/manual/pointer/main.qml @@ -48,6 +48,7 @@ Window { visible: true Examples.LauncherList { id: ll + objectName: "LauncherList" anchors.fill: parent Component.onCompleted: { addExample("single point handler", "QQuickPointerSingleHandler: test properties copied from events", Qt.resolvedUrl("singlePointHandlerProperties.qml")) -- cgit v1.2.3 From 7042cfd9cb1b552c5fd753b6912439ce604eb1a0 Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Fri, 20 Jan 2017 11:41:23 +0100 Subject: allow stealing grab from handlers; notify passive grabbers when stolen MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now if a Button with a TapHandler is pressed and has only a passive grab, Flickable can take the exclusive grab, and it notifies the TapHandler so that the button can go back to released state. This reverts parts of commit e2fd141372335f917c2d216051abb00d8b15f87c such that more of tst_PointerHandlers is working the same as it was before we started adding the passive grab concept. Change-Id: I88970716fcbbfb066a313fcefb233cf9263da944 Reviewed-by: Jan Arve Sæther --- .../tst_qquickpointerhandler.cpp | 27 +++++++++++----------- tests/manual/pointer/flickableWithHandlers.qml | 2 +- 2 files changed, 14 insertions(+), 15 deletions(-) (limited to 'tests') diff --git a/tests/auto/quick/pointerhandlers/qquickpointerhandler/tst_qquickpointerhandler.cpp b/tests/auto/quick/pointerhandlers/qquickpointerhandler/tst_qquickpointerhandler.cpp index 5282fb8a6c..736555c378 100644 --- a/tests/auto/quick/pointerhandlers/qquickpointerhandler/tst_qquickpointerhandler.cpp +++ b/tests/auto/quick/pointerhandlers/qquickpointerhandler/tst_qquickpointerhandler.cpp @@ -403,12 +403,12 @@ void tst_PointerHandlers::mouseEventDelivery() // Do not accept anything QPoint p1 = QPoint(20, 20); QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, p1); - QCOMPARE(eventItem1->eventList.size(), 3); + QCOMPARE(eventItem1->eventList.size(), 2); p1 += QPoint(10, 0); QTest::mouseMove(window, p1); - QCOMPARE(eventItem1->eventList.size(), 4); + QCOMPARE(eventItem1->eventList.size(), 3); QTest::mouseRelease(window, Qt::LeftButton); - QCOMPARE(eventItem1->eventList.size(), 4); + QCOMPARE(eventItem1->eventList.size(), 3); eventItem1->eventList.clear(); // wait to avoid getting a double click event @@ -420,10 +420,9 @@ void tst_PointerHandlers::mouseEventDelivery() eventItem1->setAcceptedMouseButtons(Qt::LeftButton); p1 = QPoint(20, 20); QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, p1); - QCOMPARE(eventItem1->eventList.size(), 3); + QCOMPARE(eventItem1->eventList.size(), 2); QCOMPARE(eventItem1->eventList.at(0).type, QEvent::Pointer); - QCOMPARE(eventItem1->eventList.at(1).type, QEvent::Pointer); - QCOMPARE(eventItem1->eventList.at(2).type, QEvent::MouseButtonPress); + QCOMPARE(eventItem1->eventList.at(1).type, QEvent::MouseButtonPress); QCOMPARE(window->mouseGrabberItem(), eventItem1); QPointF localPos = eventItem1->mapFromScene(p1); @@ -435,12 +434,12 @@ void tst_PointerHandlers::mouseEventDelivery() p1 += QPoint(10, 0); QTest::mouseMove(window, p1); - QCOMPARE(eventItem1->eventList.size(), 4); - QCOMPARE(eventItem1->eventList.at(3).type, QEvent::MouseMove); + QCOMPARE(eventItem1->eventList.size(), 3); + QCOMPARE(eventItem1->eventList.at(2).type, QEvent::MouseMove); QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p1); - QCOMPARE(eventItem1->eventList.size(), 6); - QCOMPARE(eventItem1->eventList.at(4).type, QEvent::MouseButtonRelease); - QCOMPARE(eventItem1->eventList.at(5).type, QEvent::UngrabMouse); + QCOMPARE(eventItem1->eventList.size(), 5); + QCOMPARE(eventItem1->eventList.at(3).type, QEvent::MouseButtonRelease); + QCOMPARE(eventItem1->eventList.at(4).type, QEvent::UngrabMouse); eventItem1->eventList.clear(); // wait to avoid getting a double click event @@ -452,14 +451,14 @@ void tst_PointerHandlers::mouseEventDelivery() eventItem1->grabPointer = true; p1 = QPoint(20, 20); QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, p1); - QTRY_COMPARE(eventItem1->eventList.size(), 2); + QTRY_COMPARE(eventItem1->eventList.size(), 1); QCOMPARE(eventItem1->eventList.at(0).type, QEvent::Pointer); p1 += QPoint(10, 0); QTest::mouseMove(window, p1); - QCOMPARE(eventItem1->eventList.size(), 3); + QCOMPARE(eventItem1->eventList.size(), 2); QCOMPARE(eventItem1->eventList.at(1).type, QEvent::Pointer); QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p1); - QCOMPARE(eventItem1->eventList.size(), 4); + QCOMPARE(eventItem1->eventList.size(), 3); QCOMPARE(eventItem1->eventList.at(2).type, QEvent::Pointer); eventItem1->eventList.clear(); diff --git a/tests/manual/pointer/flickableWithHandlers.qml b/tests/manual/pointer/flickableWithHandlers.qml index 59e8661aac..822ca7dc8a 100644 --- a/tests/manual/pointer/flickableWithHandlers.qml +++ b/tests/manual/pointer/flickableWithHandlers.qml @@ -44,7 +44,7 @@ import "content" Rectangle { id: root - width: 300 + width: 400 height: 400 objectName: "root" color: "#222222" -- cgit v1.2.3 From 8967a1b7b86306879a3113b290610b03727670ff Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Mon, 13 Feb 2017 15:18:43 +0100 Subject: clarify further exclusive vs. passive grabs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add documentation to the grab-related event and eventpoint methods. Rename "grabber" functions which relate only to the exclusive grab, in cases where it would otherwise be ambiguous. And a few other documentation changes. Change-Id: I1a203c8c06a19d4abdb000f08b387c38341ef476 Reviewed-by: Jan Arve Sæther --- .../qquickpointerhandler/tst_qquickpointerhandler.cpp | 6 +++--- tests/auto/quick/touchmouse/tst_touchmouse.cpp | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) (limited to 'tests') diff --git a/tests/auto/quick/pointerhandlers/qquickpointerhandler/tst_qquickpointerhandler.cpp b/tests/auto/quick/pointerhandlers/qquickpointerhandler/tst_qquickpointerhandler.cpp index 736555c378..d822330f21 100644 --- a/tests/auto/quick/pointerhandlers/qquickpointerhandler/tst_qquickpointerhandler.cpp +++ b/tests/auto/quick/pointerhandlers/qquickpointerhandler/tst_qquickpointerhandler.cpp @@ -164,7 +164,7 @@ class EventHandler : public QQuickPointerHandler point->setAccepted(item->acceptPointer); // does NOT imply a grab if (item->grabPointer) setExclusiveGrab(point, true); - qCDebug(lcPointerTests) << " " << i << ":" << point << "accepted?" << item->acceptPointer << "grabbed?" << (point->grabber() == this); + qCDebug(lcPointerTests) << " " << i << ":" << point << "accepted?" << item->acceptPointer << "grabbed?" << (point->exclusiveGrabber() == this); item->eventList.append(Event(QEvent::Pointer, eventPos(point), point->scenePos())); } } @@ -262,7 +262,7 @@ void tst_PointerHandlers::touchEventDelivery() QCOMPARE(eventItem1->eventList.at(0).type, QEvent::Pointer); QCOMPARE(eventItem1->eventList.at(1).type, QEvent::TouchBegin); auto pointerEvent = QQuickPointerDevice::touchDevices().at(0)->pointerEvent(); - QCOMPARE(pointerEvent->point(0)->grabber(), eventItem1); + QCOMPARE(pointerEvent->point(0)->exclusiveGrabber(), eventItem1); p1 += QPoint(10, 0); QTest::touchEvent(window, touchDevice).move(0, p1, window); QQuickTouchUtils::flush(window); @@ -329,7 +329,7 @@ void tst_PointerHandlers::touchEventDelivery() QCOMPARE(eventItem1->eventList.at(0).type, QEvent::Pointer); QCOMPARE(eventItem1->eventList.at(1).type, QEvent::TouchBegin); QCOMPARE(eventItem1->eventList.at(2).type, QEvent::MouseButtonPress); - QCOMPARE(pointerEvent->point(0)->grabber(), nullptr); + QCOMPARE(pointerEvent->point(0)->exclusiveGrabber(), nullptr); p1 += QPoint(10, 0); QTest::touchEvent(window, touchDevice).move(0, p1, window); QQuickTouchUtils::flush(window); diff --git a/tests/auto/quick/touchmouse/tst_touchmouse.cpp b/tests/auto/quick/touchmouse/tst_touchmouse.cpp index 4f4fac8fa5..bb251023c7 100644 --- a/tests/auto/quick/touchmouse/tst_touchmouse.cpp +++ b/tests/auto/quick/touchmouse/tst_touchmouse.cpp @@ -564,7 +564,7 @@ void tst_TouchMouse::buttonOnFlickable() QQuickWindowPrivate *windowPriv = QQuickWindowPrivate::get(window.data()); QVERIFY(windowPriv->touchMouseId != -1); auto pointerEvent = QQuickPointerDevice::touchDevices().at(0)->pointerEvent(); - QCOMPARE(pointerEvent->point(0)->grabber(), eventItem1); + QCOMPARE(pointerEvent->point(0)->exclusiveGrabber(), eventItem1); QCOMPARE(window->mouseGrabberItem(), eventItem1); p1 += QPoint(0, -10); @@ -585,7 +585,7 @@ void tst_TouchMouse::buttonOnFlickable() QCOMPARE(window->mouseGrabberItem(), flickable); QVERIFY(windowPriv->touchMouseId != -1); - QCOMPARE(pointerEvent->point(0)->grabber(), flickable); + QCOMPARE(pointerEvent->point(0)->exclusiveGrabber(), flickable); QVERIFY(flickable->isMovingVertically()); QTest::touchEvent(window.data(), device).release(0, p3, window.data()); @@ -690,7 +690,7 @@ void tst_TouchMouse::buttonOnDelayedPressFlickable() QCOMPARE(window->mouseGrabberItem(), flickable); QVERIFY(windowPriv->touchMouseId != -1); auto pointerEvent = QQuickPointerDevice::touchDevices().at(0)->pointerEvent(); - QCOMPARE(pointerEvent->point(0)->grabber(), flickable); + QCOMPARE(pointerEvent->point(0)->exclusiveGrabber(), flickable); QTest::touchEvent(window.data(), device).release(0, p3, window.data()); QQuickTouchUtils::flush(window.data()); -- cgit v1.2.3 From 55cb6574d41ff6e50d2956d7c6f1dd5ac1315741 Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Tue, 21 Feb 2017 15:32:36 +0100 Subject: flickableWithHandlers manual test improvements MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add it to main.qml and it and its dependencies to resources Add checkbox to control Flickable's pressDelay Change-Id: Ifaa4bbbaf61944231ab80cf356d7a3c44b24d73b Reviewed-by: Jan Arve Sæther --- tests/manual/pointer/flickableWithHandlers.qml | 62 +++++++++++++++++--------- tests/manual/pointer/main.qml | 1 + tests/manual/pointer/qml.qrc | 5 +++ 3 files changed, 47 insertions(+), 21 deletions(-) (limited to 'tests') diff --git a/tests/manual/pointer/flickableWithHandlers.qml b/tests/manual/pointer/flickableWithHandlers.qml index 822ca7dc8a..8225012591 100644 --- a/tests/manual/pointer/flickableWithHandlers.qml +++ b/tests/manual/pointer/flickableWithHandlers.qml @@ -40,6 +40,7 @@ import QtQuick 2.7 import Qt.labs.handlers 1.0 +import "qrc:/quick/shared/" as Examples import "content" Rectangle { @@ -52,35 +53,54 @@ Rectangle { Flickable { anchors.fill: parent anchors.margins: 10 + anchors.topMargin: 40 contentHeight: 600 contentWidth: 600 + pressDelay: pressDelayCB.checked ? 1000 : 0 - Row { + Column { spacing: 6 - Slider { - label: "DragHandler" - width: 100; height: 500 - } - MouseAreaSlider { - label: "MouseArea" - width: 100; height: 500 + Rectangle { + radius: 5 + width: parent.width - 12 + height: pressDelayCB.implicitHeight + 12 + x: 6 + color: "lightgray" + Examples.CheckBox { + x: 6; y: 6 + id: pressDelayCB + text: "press delay" + } } - Column { + + + Row { spacing: 6 - MouseAreaButton { - text: "MouseArea" - } - MptaButton { - text: "MultiPointTouchArea" - } - MptaButton { - text: "MultiPointTouchArea" + Slider { + label: "DragHandler" + value: 49; width: 100; height: 400 } - TapHandlerButton { - text: "TapHandler" + MouseAreaSlider { + label: "MouseArea" + value: 49; width: 100; height: 400 } - TapHandlerButton { - text: "TapHandler" + Column { + spacing: 6 + MouseAreaButton { + text: "MouseArea" + } + MptaButton { + text: "MultiPointTouchArea" + } + MptaButton { + text: "MultiPointTouchArea" + } + TapHandlerButton { + text: "TapHandler" + } + TapHandlerButton { + text: "TapHandler" + } } } } diff --git a/tests/manual/pointer/main.qml b/tests/manual/pointer/main.qml index e60edd06ce..df34c7d4a3 100644 --- a/tests/manual/pointer/main.qml +++ b/tests/manual/pointer/main.qml @@ -62,6 +62,7 @@ Window { addExample("photo surface", "re-implementation of the existing photo surface demo using Handlers", Qt.resolvedUrl("photosurface.qml")) addExample("tap", "TapHandler: device-agnostic tap/click detection for buttons", Qt.resolvedUrl("tapHandler.qml")) addExample("multibuttons", "TapHandler: gesturePolicy (99 red balloons)", Qt.resolvedUrl("multibuttons.qml")) + addExample("flickable with Handlers", "Flickable with buttons, sliders etc. implemented in various ways", Qt.resolvedUrl("flickableWithHandlers.qml")) } } } diff --git a/tests/manual/pointer/qml.qrc b/tests/manual/pointer/qml.qrc index 4113974d46..5bb79176c7 100644 --- a/tests/manual/pointer/qml.qrc +++ b/tests/manual/pointer/qml.qrc @@ -3,6 +3,7 @@ flingAnimation.qml main.qml fakeFlickable.qml + flickableWithHandlers.qml joystick.qml map.qml mixer.qml @@ -14,8 +15,12 @@ content/FakeFlickable.qml content/FlashAnimation.qml content/MomentumAnimation.qml + content/MouseAreaButton.qml + content/MouseAreaSlider.qml + content/MptaButton.qml content/MultiButton.qml content/Slider.qml + content/TapHandlerButton.qml resources/arrowhead.png resources/balloon.png resources/fighter.png -- cgit v1.2.3 From 95d1ff465c292445d36fa071b1f37a8cdaa2d7aa Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Tue, 18 Oct 2016 18:45:49 +0200 Subject: TapHandler manual test: demonstrate tapped signal MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Missiles are too expensive to launch in continuous sprays anyway. Also, it's too hard to keep holding down the "balloons" button if we use policy DragThreshold. This is better to have on the fighters button, since the usual use case is that ballons are launched first, and cheap enough to launch continuously. Change-Id: I3b52556b81afad9fb7ec1a4b1dec4dde3bab104c Reviewed-by: Jan Arve Sæther --- tests/manual/pointer/content/MultiButton.qml | 2 +- tests/manual/pointer/multibuttons.qml | 13 +++++++------ 2 files changed, 8 insertions(+), 7 deletions(-) (limited to 'tests') diff --git a/tests/manual/pointer/content/MultiButton.qml b/tests/manual/pointer/content/MultiButton.qml index 5b31e9ebd0..4a737dc9b0 100644 --- a/tests/manual/pointer/content/MultiButton.qml +++ b/tests/manual/pointer/content/MultiButton.qml @@ -62,7 +62,7 @@ Rectangle { objectName: label.text onTapped: { tapFlash.start() - root.tapped + root.tapped() } } diff --git a/tests/manual/pointer/multibuttons.qml b/tests/manual/pointer/multibuttons.qml index 16d2f191e7..748ec87c86 100644 --- a/tests/manual/pointer/multibuttons.qml +++ b/tests/manual/pointer/multibuttons.qml @@ -55,20 +55,21 @@ Item { id: balloonsButton label: "Launch Balloons" Layout.fillWidth: true - gesturePolicy: TapHandler.DragThreshold + gesturePolicy: TapHandler.WithinBounds } Text { text: "the goons"; font.pointSize: 12 } MultiButton { id: missilesButton - label: "Launch Missiles" + label: "Launch Missile" Layout.fillWidth: true - gesturePolicy: TapHandler.WithinBounds + gesturePolicy: TapHandler.ReleaseWithinBounds + onTapped: missileEmitter.burst(1) } MultiButton { id: fightersButton label: "Launch Fighters" Layout.fillWidth: true - gesturePolicy: TapHandler.ReleaseWithinBounds + gesturePolicy: TapHandler.DragThreshold } } ParticleSystem { @@ -90,6 +91,6 @@ Item { anchors.right: parent.right anchors.rightMargin: 100 ImageParticle { source: "resources/missile.png"; autoRotation: true; rotation: 90 } - Emitter { anchors.bottom: parent.bottom; enabled: missilesButton.pressed; lifeSpan: 5000; size: 128 - emitRate: 10; velocity: PointDirection { x: -200; y: -350; yVariation: 200; xVariation: 100 } } } + Emitter { id: missileEmitter; anchors.bottom: parent.bottom; lifeSpan: 5000; size: 128; + emitRate: 0; velocity: PointDirection { x: -200; y: -350; yVariation: 200; xVariation: 100 } } } } -- cgit v1.2.3 From 54bb88bc99a0ea3966b6bde2ba06e4ece237a32c Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Tue, 21 Feb 2017 17:02:08 +0100 Subject: add ScrollBar manual test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It demonstrates that DragHandler's grabs work well enough, so that you can grab the knob and drag it even while the cursor goes outside the window. Also the TapHandler for detecting clicks or taps within the "trough". And for completeness, the FakeFlickable example needed scrollbars, to prove that it's possible to build all the flicking and scrolling behaviors with only PointerHandlers. Change-Id: I9d9323b1f583a02e0157edb85b6bffbe1652711f Reviewed-by: Jan Arve Sæther --- tests/manual/pointer/content/ScrollBar.qml | 160 +++++++++++++++++++++++++++++ tests/manual/pointer/fakeFlickable.qml | 29 ++++++ tests/manual/pointer/qml.qrc | 1 + 3 files changed, 190 insertions(+) create mode 100644 tests/manual/pointer/content/ScrollBar.qml (limited to 'tests') diff --git a/tests/manual/pointer/content/ScrollBar.qml b/tests/manual/pointer/content/ScrollBar.qml new file mode 100644 index 0000000000..94d5ae47a7 --- /dev/null +++ b/tests/manual/pointer/content/ScrollBar.qml @@ -0,0 +1,160 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the manual tests of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.8 +import Qt.labs.handlers 1.0 + +Rectangle { + id: root + property real contentHeight: 100 + property FakeFlickable flick: null + property real position + + onPositionChanged: if (flick && (drag.active || tap.active)) { + if (knob.state === "horizontal") + flick.contentX = position * knob.scrollDistance + else if (knob.state === "vertical") + flick.contentY = position * knob.scrollDistance + } + + SystemPalette { id: palette } + + color: palette.button + border.color: Qt.darker(palette.button, 1.5) + gradient: Gradient { + GradientStop { position: 0; color: Qt.darker(palette.button, 1.3) } + GradientStop { position: 1; color: palette.button } + } + antialiasing: true + radius: Math.min(width, height) / 6 + width: 20 + height: 20 + + TapHandler { + id: tap + onTapped: { + if (knob.state === "horizontal") + knob.x = pos.x - knob.width / 2 + else if (knob.state === "vertical") + knob.y = pos.y - knob.height / 2 + } + } + + Rectangle { + id: knob + border.color: "black" + border.width: 1 + gradient: Gradient { + GradientStop { position: 0; color: palette.button } + GradientStop { position: 1; color: Qt.darker(palette.button, 1.3) } + } + radius: 2 + antialiasing: true + state: root.height > root.width ? "vertical" : root.height < root.width ? "horizontal" : "" + property real scrollDistance: 0 + property real scrolledX: 0 + property real scrolledY: 0 + property real max: 0 + + Binding on x { + value: knob.scrolledX + when: !drag.active + } + + Binding on y { + value: knob.scrolledY + when: !drag.active + } + + states: [ + // We will control the horizontal. We will control the vertical. + State { + name: "horizontal" + PropertyChanges { + target: knob + max: root.width - knob.width + scrolledX: Math.min(max, Math.max(0, max * flick.contentX / (flick.width - flick.contentWidth))) + scrolledY: 1 + scrollDistance: flick.width - flick.contentWidth + width: flick.width * (flick.width / flick.contentWidth) - (height - anchors.margins) * 2 + height: root.height - 2 + } + PropertyChanges { + target: drag + xAxis.minimum: 0 + xAxis.maximum: knob.max + yAxis.minimum: 1 + yAxis.maximum: 1 + } + PropertyChanges { + target: root + position: knob.x / drag.xAxis.maximum + } + }, + State { + name: "vertical" + PropertyChanges { + target: knob + max: root.height - knob.height + scrolledX: 1 + scrolledY: Math.min(max, Math.max(0, max * flick.contentY / (flick.height - flick.contentHeight))) + scrollDistance: flick.height - flick.contentHeight + width: root.width - 2 + height: root.width - 2 + } + PropertyChanges { + target: drag + xAxis.minimum: 1 + xAxis.maximum: 1 + yAxis.minimum: 0 + yAxis.maximum: knob.max + } + PropertyChanges { + target: root + position: knob.y / drag.yAxis.maximum + } + } + ] + + DragHandler { + id: drag + } + } +} diff --git a/tests/manual/pointer/fakeFlickable.qml b/tests/manual/pointer/fakeFlickable.qml index 31e3d9f74c..22b23a00c8 100644 --- a/tests/manual/pointer/fakeFlickable.qml +++ b/tests/manual/pointer/fakeFlickable.qml @@ -48,7 +48,9 @@ Rectangle { height: 480 FakeFlickable { + id: ff anchors.fill: parent + anchors.rightMargin: rightSB.width Row { Item { width: 100 @@ -85,4 +87,31 @@ Rectangle { request.send() } } + + ScrollBar { + id: rightSB + objectName: "rightSB" + flick: ff + height: parent.height - width + anchors.right: parent.right + } + + ScrollBar { + id: bottomSB + objectName: "bottomSB" + flick: ff + width: parent.width - height + anchors.bottom: parent.bottom + } + + Rectangle { + id: cornerCover + color: "lightgray" + width: rightSB.width + height: bottomSB.height + anchors { + right: parent.right + bottom: parent.bottom + } + } } diff --git a/tests/manual/pointer/qml.qrc b/tests/manual/pointer/qml.qrc index 5bb79176c7..68937a8c4a 100644 --- a/tests/manual/pointer/qml.qrc +++ b/tests/manual/pointer/qml.qrc @@ -19,6 +19,7 @@ content/MouseAreaSlider.qml content/MptaButton.qml content/MultiButton.qml + content/ScrollBar.qml content/Slider.qml content/TapHandlerButton.qml resources/arrowhead.png -- cgit v1.2.3 From 659317abee487c51837484208cc9e41061d3901f Mon Sep 17 00:00:00 2001 From: Jan Arve Saether Date: Thu, 9 Mar 2017 15:11:22 +0100 Subject: Red frame indicates that the item has an active handler Change-Id: I360063f3fe80eefb112b348d1b93f38d34416696 Reviewed-by: Shawn Rutledge --- tests/manual/pointer/pinchHandler.qml | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'tests') diff --git a/tests/manual/pointer/pinchHandler.qml b/tests/manual/pointer/pinchHandler.qml index f317f361e2..7f2f9bd70f 100644 --- a/tests/manual/pointer/pinchHandler.qml +++ b/tests/manual/pointer/pinchHandler.qml @@ -71,6 +71,8 @@ Rectangle { y: 200 rotation: 30 transformOrigin: Item.TopRight + border.width: pinch2.active ? 2 : 0 + border.color: pinch2.active ? "red" : "transparent" Text { anchors.centerIn: parent @@ -98,13 +100,18 @@ Rectangle { height: 300 color: "wheat" antialiasing: true + border.width: (dragHandler.active || pinch3.active) ? 2 : 0 + border.color: border.width > 0 ? "red" : "transparent" Text { anchors.centerIn: parent text: "Pinch with 3 fingers to scale, rotate and translate\nDrag with 1 finger" + getTransformationDetails(rect3, pinch3) } - DragHandler { objectName: "DragHandler" } + DragHandler { + id: dragHandler + objectName: "DragHandler" + } PinchHandler { id: pinch3 -- cgit v1.2.3 From 70513c7496dabf504132dd5c900cd85b367bd1b7 Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Mon, 10 Apr 2017 21:47:07 +0200 Subject: Blacklist ListView::test_listInteractiveCurrentIndexEnforce completely It has failed on Windows too. Change-Id: I539ffacaedcc62339e2017e2272297c9bc3846cf Reviewed-by: Shawn Rutledge --- tests/auto/qmltest/BLACKLIST | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'tests') diff --git a/tests/auto/qmltest/BLACKLIST b/tests/auto/qmltest/BLACKLIST index e0a4ce1743..bfe8e6d761 100644 --- a/tests/auto/qmltest/BLACKLIST +++ b/tests/auto/qmltest/BLACKLIST @@ -8,8 +8,7 @@ linux [tst_grabImage::test_equals] linux [ListView::test_listInteractiveCurrentIndexEnforce] -linux -macos-10.12 +* [TextEdit::test_textentry] macos-10.12 [TextEdit::test_textentry_char] -- cgit v1.2.3 From 1457df74f4c1d770e1e820de8cd082be1bd2489e Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Wed, 5 Apr 2017 11:21:29 +0200 Subject: Add QQuickItem acceptTouchEvents/setAcceptTouchEvents; require for touch It has been suboptimal to speculatively deliver touch events to Items which are not interested; even worse is when we must deliver to a parent item which is filtering events, when the child Item will not accept the touch event anyway. So now it is required that any QQuickItem subclass which wishes to accept touch events must call setAcceptTouchEvents(true) (typically in its constructor). If it does not do this, it will not get any touch events (and this saves us the trouble of looking for parents which filter touch events, too). It is consistent with needing to call setAcceptHoverEvents() to get hover events, and setAcceptedMouseButtons() to get mouse events. [ChangeLog][QtQuick][QQuickItem] When subclassing QQuickItem, it is now required to call setAcceptTouchEvents(true) if you need the item to receive touch events. Change-Id: Idc76c04f4e7f1d4a613087e756e96dac368f4f23 Reviewed-by: Shawn Rutledge --- tests/auto/quick/qquickflickable/tst_qquickflickable.cpp | 4 +++- tests/auto/quick/qquickitem/tst_qquickitem.cpp | 10 ++++++---- tests/auto/quick/touchmouse/tst_touchmouse.cpp | 1 + 3 files changed, 10 insertions(+), 5 deletions(-) (limited to 'tests') diff --git a/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp b/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp index ef6e444580..b37bb03305 100644 --- a/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp +++ b/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp @@ -63,7 +63,9 @@ public: , touchReleases(0) , ungrabs(0) , m_active(false) - { } + { + setAcceptTouchEvents(true); + } QPointF pos() const { return m_pos; } diff --git a/tests/auto/quick/qquickitem/tst_qquickitem.cpp b/tests/auto/quick/qquickitem/tst_qquickitem.cpp index 10a3a0bfa8..dbfe97d640 100644 --- a/tests/auto/quick/qquickitem/tst_qquickitem.cpp +++ b/tests/auto/quick/qquickitem/tst_qquickitem.cpp @@ -46,10 +46,12 @@ class TestItem : public QQuickItem Q_OBJECT public: TestItem(QQuickItem *parent = 0) - : QQuickItem(parent), focused(false), pressCount(0), releaseCount(0) - , wheelCount(0), acceptIncomingTouchEvents(true) - , touchEventReached(false), timestamp(0) - , lastWheelEventPos(0, 0), lastWheelEventGlobalPos(0, 0) {} + : QQuickItem(parent), focused(false), pressCount(0), releaseCount(0) + , wheelCount(0), acceptIncomingTouchEvents(true) + , touchEventReached(false), timestamp(0) + , lastWheelEventPos(0, 0), lastWheelEventGlobalPos(0, 0) { + setAcceptTouchEvents(true); + } bool focused; int pressCount; diff --git a/tests/auto/quick/touchmouse/tst_touchmouse.cpp b/tests/auto/quick/touchmouse/tst_touchmouse.cpp index 6e7fce6189..6f5c9a37d5 100644 --- a/tests/auto/quick/touchmouse/tst_touchmouse.cpp +++ b/tests/auto/quick/touchmouse/tst_touchmouse.cpp @@ -74,6 +74,7 @@ public: : QQuickItem(parent), touchUngrabCount(0), acceptMouse(false), acceptTouch(false), filterTouch(false), point0(-1) { setAcceptedMouseButtons(Qt::LeftButton); + setAcceptTouchEvents(true); } void touchEvent(QTouchEvent *event) -- cgit v1.2.3 From c2d6f267a74f7fdd9422af88e35ade280cf0a3d3 Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Fri, 31 Mar 2017 23:42:04 +0200 Subject: PinchHandler: add centroidVelocity Change-Id: I34cc9146155bded8311c1173e4b8d34d8b17b034 Reviewed-by: Shawn Rutledge --- tests/manual/pointer/pinchHandler.qml | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'tests') diff --git a/tests/manual/pointer/pinchHandler.qml b/tests/manual/pointer/pinchHandler.qml index 7f2f9bd70f..1d0a859564 100644 --- a/tests/manual/pointer/pinchHandler.qml +++ b/tests/manual/pointer/pinchHandler.qml @@ -40,6 +40,7 @@ import QtQuick 2.8 import Qt.labs.handlers 1.0 +import "content" Rectangle { width: 1024; height: 600 @@ -119,7 +120,13 @@ Rectangle { requiredPointCount: 3 minimumScale: 0.1 maximumScale: 10 + onActiveChanged: { + if (!active) + anim.restart(centroidVelocity) + } } + + MomentumAnimation { id: anim; target: rect3 } } } Rectangle { -- cgit v1.2.3 From 11034bd4ab4163797ae9e0dffd110217d2aafdaa Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Sat, 15 Apr 2017 10:22:34 +0200 Subject: PH manual tests: better object names for easier debugging Change-Id: Icd5b9dc5fa00c98cc40b03e9d72f6b28fc51a579 Reviewed-by: Shawn Rutledge --- tests/manual/pointer/content/Slider.qml | 3 ++- tests/manual/pointer/flingAnimation.qml | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'tests') diff --git a/tests/manual/pointer/content/Slider.qml b/tests/manual/pointer/content/Slider.qml index a1decf8c4b..44dea8e33b 100644 --- a/tests/manual/pointer/content/Slider.qml +++ b/tests/manual/pointer/content/Slider.qml @@ -92,13 +92,14 @@ Item { function setValue(value) { knob.y = dragHandler.yAxis.maximum - value / knob.multiplier } DragHandler { id: dragHandler + objectName: label.text + " DragHandler" xAxis.enabled: false yAxis.minimum: slot.y yAxis.maximum: slot.height + slot.y - knob.height } TapHandler { id: tap - objectName: label.text + objectName: label.text + " TapHandler" gesturePolicy: TapHandler.DragThreshold onTapped: { tapFlash.start() diff --git a/tests/manual/pointer/flingAnimation.qml b/tests/manual/pointer/flingAnimation.qml index 11b97dbb31..c8722fabb1 100644 --- a/tests/manual/pointer/flingAnimation.qml +++ b/tests/manual/pointer/flingAnimation.qml @@ -67,6 +67,7 @@ Rectangle { DragHandler { id: dragHandler + objectName: "dragHandler" + index onActiveChanged: { if (!active) anim.restart(velocity) -- cgit v1.2.3 From 1e87f4605bb9456ce642e9ff1797b96647a1ab1c Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Wed, 22 Mar 2017 09:54:57 +0100 Subject: add autotest for TapHandler MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: Idc516220365b3051e072506ede3f3159b0b736b2 Reviewed-by: Qt CI Bot Reviewed-by: Jan Arve Sæther --- .../auto/quick/pointerhandlers/pointerhandlers.pro | 1 + .../qquicktaphandler/data/Button.qml | 99 ++++ .../qquicktaphandler/data/FlashAnimation.qml | 57 ++ .../qquicktaphandler/data/buttons.qml | 65 +++ .../qquicktaphandler/qquicktaphandler.pro | 16 + .../qquicktaphandler/tst_qquicktaphandler.cpp | 591 +++++++++++++++++++++ 6 files changed, 829 insertions(+) create mode 100644 tests/auto/quick/pointerhandlers/qquicktaphandler/data/Button.qml create mode 100644 tests/auto/quick/pointerhandlers/qquicktaphandler/data/FlashAnimation.qml create mode 100644 tests/auto/quick/pointerhandlers/qquicktaphandler/data/buttons.qml create mode 100644 tests/auto/quick/pointerhandlers/qquicktaphandler/qquicktaphandler.pro create mode 100644 tests/auto/quick/pointerhandlers/qquicktaphandler/tst_qquicktaphandler.cpp (limited to 'tests') diff --git a/tests/auto/quick/pointerhandlers/pointerhandlers.pro b/tests/auto/quick/pointerhandlers/pointerhandlers.pro index 4a3f99765e..ba889d1399 100644 --- a/tests/auto/quick/pointerhandlers/pointerhandlers.pro +++ b/tests/auto/quick/pointerhandlers/pointerhandlers.pro @@ -3,5 +3,6 @@ TEMPLATE = subdirs qtConfig(private_tests) { SUBDIRS += \ qquickpointerhandler \ + qquicktaphandler \ } diff --git a/tests/auto/quick/pointerhandlers/qquicktaphandler/data/Button.qml b/tests/auto/quick/pointerhandlers/qquicktaphandler/data/Button.qml new file mode 100644 index 0000000000..ead86e142b --- /dev/null +++ b/tests/auto/quick/pointerhandlers/qquicktaphandler/data/Button.qml @@ -0,0 +1,99 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.8 +import Qt.labs.handlers 1.0 + +Rectangle { + id: root + property alias label: label.text + property alias pressed: tap.isPressed + property bool checked: false + property alias gesturePolicy: tap.gesturePolicy + signal tapped + + width: label.implicitWidth * 1.5; height: label.implicitHeight * 2.0 + border.color: "#9f9d9a"; border.width: 1; radius: height / 4; antialiasing: true + + gradient: Gradient { + GradientStop { position: 0.0; color: tap.isPressed ? "#b8b5b2" : "#efebe7" } + GradientStop { position: 1.0; color: "#b8b5b2" } + } + + TapHandler { + id: tap + objectName: label.text + longPressThreshold: 100 // CI can be insanely slow, so don't demand a timely release to generate onTapped + onTapped: { + tapFlash.start() + root.tapped() + } + } + + Text { + id: label + font.pointSize: 14 + text: "Button" + anchors.centerIn: parent + } + + Rectangle { + anchors.fill: parent + color: "transparent" + border.width: 2; radius: root.radius; antialiasing: true + opacity: tapFlash.running ? 1 : 0 + FlashAnimation on visible { id: tapFlash } + } + + Rectangle { + objectName: "expandingCircle" + radius: tap.timeHeld * 100 + visible: radius > 0 && tap.isPressed + border.width: 3 + border.color: "blue" + color: "transparent" + width: radius * 2 + height: radius * 2 + x: tap.scenePressPos.x - radius + y: tap.scenePressPos.y - radius + opacity: 0.25 + Component.onCompleted: parent = root.parent + } +} diff --git a/tests/auto/quick/pointerhandlers/qquicktaphandler/data/FlashAnimation.qml b/tests/auto/quick/pointerhandlers/qquicktaphandler/data/FlashAnimation.qml new file mode 100644 index 0000000000..2224276819 --- /dev/null +++ b/tests/auto/quick/pointerhandlers/qquicktaphandler/data/FlashAnimation.qml @@ -0,0 +1,57 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 + +SequentialAnimation { + id: tapFlash + running: false + PropertyAction { value: false } + PauseAnimation { duration: 100 } + PropertyAction { value: true } + PauseAnimation { duration: 100 } + PropertyAction { value: false } + PauseAnimation { duration: 100 } + PropertyAction { value: true } + PauseAnimation { duration: 100 } + PropertyAction { value: false } + PauseAnimation { duration: 100 } + PropertyAction { value: true } +} diff --git a/tests/auto/quick/pointerhandlers/qquicktaphandler/data/buttons.qml b/tests/auto/quick/pointerhandlers/qquicktaphandler/data/buttons.qml new file mode 100644 index 0000000000..ca1aba71fb --- /dev/null +++ b/tests/auto/quick/pointerhandlers/qquicktaphandler/data/buttons.qml @@ -0,0 +1,65 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 +import Qt.labs.handlers 1.0 + +Item { + width: 320 + height: 240 + Button { + objectName: "DragThreshold" + label: "DragThreshold" + x: 10; y: 10; width: parent.width - 20; height: 40 + gesturePolicy: TapHandler.DragThreshold + } + Button { + objectName: "WithinBounds" + label: "WithinBounds" + x: 10; y: 60; width: parent.width - 20; height: 40 + gesturePolicy: TapHandler.WithinBounds + } + Button { + objectName: "ReleaseWithinBounds" + label: "ReleaseWithinBounds" + x: 10; y: 110; width: parent.width - 20; height: 40 + gesturePolicy: TapHandler.ReleaseWithinBounds + } +} diff --git a/tests/auto/quick/pointerhandlers/qquicktaphandler/qquicktaphandler.pro b/tests/auto/quick/pointerhandlers/qquicktaphandler/qquicktaphandler.pro new file mode 100644 index 0000000000..b41a94b55e --- /dev/null +++ b/tests/auto/quick/pointerhandlers/qquicktaphandler/qquicktaphandler.pro @@ -0,0 +1,16 @@ +CONFIG += testcase + +TARGET = tst_qquicktaphandler +QT += core-private gui-private qml-private quick-private testlib + +macos:CONFIG -= app_bundle + +SOURCES += tst_qquicktaphandler.cpp + +include (../../../shared/util.pri) +include (../../shared/util.pri) + +TESTDATA = data/* + +# OTHER_FILES += data/foo.qml + diff --git a/tests/auto/quick/pointerhandlers/qquicktaphandler/tst_qquicktaphandler.cpp b/tests/auto/quick/pointerhandlers/qquicktaphandler/tst_qquicktaphandler.cpp new file mode 100644 index 0000000000..2c1926103f --- /dev/null +++ b/tests/auto/quick/pointerhandlers/qquicktaphandler/tst_qquicktaphandler.cpp @@ -0,0 +1,591 @@ +/**************************************************************************** +** +** Copyright (C) 2017 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 + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include "../../../shared/util.h" +#include "../../shared/viewtestutil.h" + +Q_LOGGING_CATEGORY(lcPointerTests, "qt.quick.pointer.tests") + +class tst_TapHandler : public QQmlDataTest +{ + Q_OBJECT +public: + tst_TapHandler() + :touchDevice(QTest::createTouchDevice()) + {} + +private slots: + void initTestCase(); + + void touchGesturePolicyDragThreshold(); + void mouseGesturePolicyDragThreshold(); + void touchGesturePolicyWithinBounds(); + void mouseGesturePolicyWithinBounds(); + void touchGesturePolicyReleaseWithinBounds(); + void mouseGesturePolicyReleaseWithinBounds(); + void touchMultiTap(); + void mouseMultiTap(); + void touchLongPress(); + void mouseLongPress(); + void buttonsMultiTouch(); + +private: + void createView(QScopedPointer &window, const char *fileName); + QTouchDevice *touchDevice; +}; + +void tst_TapHandler::createView(QScopedPointer &window, const char *fileName) +{ + window.reset(new QQuickView); + window->setSource(testFileUrl(fileName)); + QTRY_COMPARE(window->status(), QQuickView::Ready); + QQuickViewTestUtil::centerOnScreen(window.data()); + QQuickViewTestUtil::moveMouseAway(window.data()); + + window->show(); + QVERIFY(QTest::qWaitForWindowActive(window.data())); + QVERIFY(window->rootObject() != 0); +} + +void tst_TapHandler::initTestCase() +{ + // This test assumes that we don't get synthesized mouse events from QGuiApplication + qApp->setAttribute(Qt::AA_SynthesizeMouseForUnhandledTouchEvents, false); + + QQmlDataTest::initTestCase(); +} + +void tst_TapHandler::touchGesturePolicyDragThreshold() +{ + const int dragThreshold = QGuiApplication::styleHints()->startDragDistance(); + QScopedPointer windowPtr; + createView(windowPtr, "buttons.qml"); + QQuickView * window = windowPtr.data(); + + QQuickItem *buttonDragThreshold = window->rootObject()->findChild("DragThreshold"); + QVERIFY(buttonDragThreshold); + QSignalSpy dragThresholdTappedSpy(buttonDragThreshold, SIGNAL(tapped())); + + // DragThreshold button stays pressed while touchpoint stays within dragThreshold, emits tapped on release + QPoint p1 = buttonDragThreshold->mapToScene(QPointF(20, 20)).toPoint(); + QTest::touchEvent(window, touchDevice).press(1, p1, window); + QQuickTouchUtils::flush(window); + QTRY_VERIFY(buttonDragThreshold->property("pressed").toBool()); + p1 += QPoint(dragThreshold, 0); + QTest::touchEvent(window, touchDevice).move(1, p1, window); + QQuickTouchUtils::flush(window); + QVERIFY(buttonDragThreshold->property("pressed").toBool()); + QTest::touchEvent(window, touchDevice).release(1, p1, window); + QQuickTouchUtils::flush(window); + QTRY_VERIFY(!buttonDragThreshold->property("pressed").toBool()); + QCOMPARE(dragThresholdTappedSpy.count(), 1); + + // DragThreshold button is no longer pressed if touchpoint goes beyond dragThreshold + dragThresholdTappedSpy.clear(); + p1 = buttonDragThreshold->mapToScene(QPointF(20, 20)).toPoint(); + QTest::touchEvent(window, touchDevice).press(1, p1, window); + QQuickTouchUtils::flush(window); + QTRY_VERIFY(buttonDragThreshold->property("pressed").toBool()); + p1 += QPoint(dragThreshold, 0); + QTest::touchEvent(window, touchDevice).move(1, p1, window); + QQuickTouchUtils::flush(window); + QVERIFY(buttonDragThreshold->property("pressed").toBool()); + p1 += QPoint(1, 0); + QTest::touchEvent(window, touchDevice).move(1, p1, window); + QQuickTouchUtils::flush(window); + QTRY_VERIFY(!buttonDragThreshold->property("pressed").toBool()); + QTest::touchEvent(window, touchDevice).release(1, p1, window); + QQuickTouchUtils::flush(window); + QVERIFY(!buttonDragThreshold->property("pressed").toBool()); + QCOMPARE(dragThresholdTappedSpy.count(), 0); +} + +void tst_TapHandler::mouseGesturePolicyDragThreshold() +{ + const int dragThreshold = QGuiApplication::styleHints()->startDragDistance(); + QScopedPointer windowPtr; + createView(windowPtr, "buttons.qml"); + QQuickView * window = windowPtr.data(); + + QQuickItem *buttonDragThreshold = window->rootObject()->findChild("DragThreshold"); + QVERIFY(buttonDragThreshold); + QSignalSpy dragThresholdTappedSpy(buttonDragThreshold, SIGNAL(tapped())); + + // DragThreshold button stays pressed while mouse stays within dragThreshold, emits tapped on release + QPoint p1 = buttonDragThreshold->mapToScene(QPointF(20, 20)).toPoint(); + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, p1); + QTRY_VERIFY(buttonDragThreshold->property("pressed").toBool()); + p1 += QPoint(dragThreshold, 0); + QTest::mouseMove(window, p1); + QVERIFY(buttonDragThreshold->property("pressed").toBool()); + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p1); + QTRY_VERIFY(!buttonDragThreshold->property("pressed").toBool()); + QTRY_COMPARE(dragThresholdTappedSpy.count(), 1); + + // DragThreshold button is no longer pressed if mouse goes beyond dragThreshold + dragThresholdTappedSpy.clear(); + p1 = buttonDragThreshold->mapToScene(QPointF(20, 20)).toPoint(); + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, p1); + QTRY_VERIFY(buttonDragThreshold->property("pressed").toBool()); + p1 += QPoint(dragThreshold, 0); + QTest::mouseMove(window, p1); + QVERIFY(buttonDragThreshold->property("pressed").toBool()); + p1 += QPoint(1, 0); + QTest::mouseMove(window, p1); + QTRY_VERIFY(!buttonDragThreshold->property("pressed").toBool()); + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p1); + QVERIFY(!buttonDragThreshold->property("pressed").toBool()); + QCOMPARE(dragThresholdTappedSpy.count(), 0); +} + +void tst_TapHandler::touchGesturePolicyWithinBounds() +{ + QScopedPointer windowPtr; + createView(windowPtr, "buttons.qml"); + QQuickView * window = windowPtr.data(); + + QQuickItem *buttonWithinBounds = window->rootObject()->findChild("WithinBounds"); + QVERIFY(buttonWithinBounds); + QSignalSpy withinBoundsTappedSpy(buttonWithinBounds, SIGNAL(tapped())); + + // WithinBounds button stays pressed while touchpoint stays within bounds, emits tapped on release + QPoint p1 = buttonWithinBounds->mapToScene(QPointF(20, 20)).toPoint(); + QTest::touchEvent(window, touchDevice).press(1, p1, window); + QQuickTouchUtils::flush(window); + QTRY_VERIFY(buttonWithinBounds->property("pressed").toBool()); + p1 += QPoint(50, 0); + QTest::touchEvent(window, touchDevice).move(1, p1, window); + QQuickTouchUtils::flush(window); + QVERIFY(buttonWithinBounds->property("pressed").toBool()); + QTest::touchEvent(window, touchDevice).release(1, p1, window); + QQuickTouchUtils::flush(window); + QTRY_VERIFY(!buttonWithinBounds->property("pressed").toBool()); + QCOMPARE(withinBoundsTappedSpy.count(), 1); + + // WithinBounds button is no longer pressed if touchpoint leaves bounds + withinBoundsTappedSpy.clear(); + p1 = buttonWithinBounds->mapToScene(QPointF(20, 20)).toPoint(); + QTest::touchEvent(window, touchDevice).press(1, p1, window); + QQuickTouchUtils::flush(window); + QTRY_VERIFY(buttonWithinBounds->property("pressed").toBool()); + p1 += QPoint(0, 100); + QTest::touchEvent(window, touchDevice).move(1, p1, window); + QQuickTouchUtils::flush(window); + QTRY_VERIFY(!buttonWithinBounds->property("pressed").toBool()); + QTest::touchEvent(window, touchDevice).release(1, p1, window); + QQuickTouchUtils::flush(window); + QVERIFY(!buttonWithinBounds->property("pressed").toBool()); + QCOMPARE(withinBoundsTappedSpy.count(), 0); +} + +void tst_TapHandler::mouseGesturePolicyWithinBounds() +{ + QScopedPointer windowPtr; + createView(windowPtr, "buttons.qml"); + QQuickView * window = windowPtr.data(); + + QQuickItem *buttonWithinBounds = window->rootObject()->findChild("WithinBounds"); + QVERIFY(buttonWithinBounds); + QSignalSpy withinBoundsTappedSpy(buttonWithinBounds, SIGNAL(tapped())); + + // WithinBounds button stays pressed while touchpoint stays within bounds, emits tapped on release + QPoint p1 = buttonWithinBounds->mapToScene(QPointF(20, 20)).toPoint(); + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, p1); + QTRY_VERIFY(buttonWithinBounds->property("pressed").toBool()); + p1 += QPoint(50, 0); + QTest::mouseMove(window, p1); + QVERIFY(buttonWithinBounds->property("pressed").toBool()); + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p1); + QTRY_VERIFY(!buttonWithinBounds->property("pressed").toBool()); + QCOMPARE(withinBoundsTappedSpy.count(), 1); + + // WithinBounds button is no longer pressed if touchpoint leaves bounds + withinBoundsTappedSpy.clear(); + p1 = buttonWithinBounds->mapToScene(QPointF(20, 20)).toPoint(); + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, p1); + QTRY_VERIFY(buttonWithinBounds->property("pressed").toBool()); + p1 += QPoint(0, 100); + QTest::mouseMove(window, p1); + QTRY_VERIFY(!buttonWithinBounds->property("pressed").toBool()); + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p1); + QVERIFY(!buttonWithinBounds->property("pressed").toBool()); + QCOMPARE(withinBoundsTappedSpy.count(), 0); +} + +void tst_TapHandler::touchGesturePolicyReleaseWithinBounds() +{ + QScopedPointer windowPtr; + createView(windowPtr, "buttons.qml"); + QQuickView * window = windowPtr.data(); + + QQuickItem *buttonReleaseWithinBounds = window->rootObject()->findChild("ReleaseWithinBounds"); + QVERIFY(buttonReleaseWithinBounds); + QSignalSpy releaseWithinBoundsTappedSpy(buttonReleaseWithinBounds, SIGNAL(tapped())); + + // ReleaseWithinBounds button stays pressed while touchpoint wanders anywhere, + // then if it comes back within bounds, emits tapped on release + QPoint p1 = buttonReleaseWithinBounds->mapToScene(QPointF(20, 20)).toPoint(); + QTest::touchEvent(window, touchDevice).press(1, p1, window); + QQuickTouchUtils::flush(window); + QTRY_VERIFY(buttonReleaseWithinBounds->property("pressed").toBool()); + p1 += QPoint(50, 0); + QTest::touchEvent(window, touchDevice).move(1, p1, window); + QQuickTouchUtils::flush(window); + QVERIFY(buttonReleaseWithinBounds->property("pressed").toBool()); + p1 += QPoint(250, 100); + QTest::touchEvent(window, touchDevice).move(1, p1, window); + QQuickTouchUtils::flush(window); + QVERIFY(buttonReleaseWithinBounds->property("pressed").toBool()); + p1 = buttonReleaseWithinBounds->mapToScene(QPointF(25, 15)).toPoint(); + QTest::touchEvent(window, touchDevice).move(1, p1, window); + QQuickTouchUtils::flush(window); + QVERIFY(buttonReleaseWithinBounds->property("pressed").toBool()); + QTest::touchEvent(window, touchDevice).release(1, p1, window); + QQuickTouchUtils::flush(window); + QTRY_VERIFY(!buttonReleaseWithinBounds->property("pressed").toBool()); + QCOMPARE(releaseWithinBoundsTappedSpy.count(), 1); + + // ReleaseWithinBounds button does not emit tapped if released out of bounds + releaseWithinBoundsTappedSpy.clear(); + p1 = buttonReleaseWithinBounds->mapToScene(QPointF(20, 20)).toPoint(); + QTest::touchEvent(window, touchDevice).press(1, p1, window); + QQuickTouchUtils::flush(window); + QTRY_VERIFY(buttonReleaseWithinBounds->property("pressed").toBool()); + p1 += QPoint(0, 100); + QTest::touchEvent(window, touchDevice).move(1, p1, window); + QQuickTouchUtils::flush(window); + QVERIFY(buttonReleaseWithinBounds->property("pressed").toBool()); + QTest::touchEvent(window, touchDevice).release(1, p1, window); + QQuickTouchUtils::flush(window); + QTRY_VERIFY(!buttonReleaseWithinBounds->property("pressed").toBool()); + QCOMPARE(releaseWithinBoundsTappedSpy.count(), 0); +} + +void tst_TapHandler::mouseGesturePolicyReleaseWithinBounds() +{ + QScopedPointer windowPtr; + createView(windowPtr, "buttons.qml"); + QQuickView * window = windowPtr.data(); + + QQuickItem *buttonReleaseWithinBounds = window->rootObject()->findChild("ReleaseWithinBounds"); + QVERIFY(buttonReleaseWithinBounds); + QSignalSpy releaseWithinBoundsTappedSpy(buttonReleaseWithinBounds, SIGNAL(tapped())); + + // ReleaseWithinBounds button stays pressed while touchpoint wanders anywhere, + // then if it comes back within bounds, emits tapped on release + QPoint p1 = buttonReleaseWithinBounds->mapToScene(QPointF(20, 20)).toPoint(); + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, p1); + QTRY_VERIFY(buttonReleaseWithinBounds->property("pressed").toBool()); + p1 += QPoint(50, 0); + QTest::mouseMove(window, p1); + QVERIFY(buttonReleaseWithinBounds->property("pressed").toBool()); + p1 += QPoint(250, 100); + QTest::mouseMove(window, p1); + QVERIFY(buttonReleaseWithinBounds->property("pressed").toBool()); + p1 = buttonReleaseWithinBounds->mapToScene(QPointF(25, 15)).toPoint(); + QTest::mouseMove(window, p1); + QVERIFY(buttonReleaseWithinBounds->property("pressed").toBool()); + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p1); + QTRY_VERIFY(!buttonReleaseWithinBounds->property("pressed").toBool()); + QCOMPARE(releaseWithinBoundsTappedSpy.count(), 1); + + // ReleaseWithinBounds button does not emit tapped if released out of bounds + releaseWithinBoundsTappedSpy.clear(); + p1 = buttonReleaseWithinBounds->mapToScene(QPointF(20, 20)).toPoint(); + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, p1); + QTRY_VERIFY(buttonReleaseWithinBounds->property("pressed").toBool()); + p1 += QPoint(0, 100); + QTest::mouseMove(window, p1); + QVERIFY(buttonReleaseWithinBounds->property("pressed").toBool()); + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p1); + QTRY_VERIFY(!buttonReleaseWithinBounds->property("pressed").toBool()); + QCOMPARE(releaseWithinBoundsTappedSpy.count(), 0); +} + +void tst_TapHandler::touchMultiTap() +{ + const int dragThreshold = QGuiApplication::styleHints()->startDragDistance(); + QScopedPointer windowPtr; + createView(windowPtr, "buttons.qml"); + QQuickView * window = windowPtr.data(); + + QQuickItem *button = window->rootObject()->findChild("DragThreshold"); + QVERIFY(button); + QSignalSpy tappedSpy(button, SIGNAL(tapped())); + + // Tap once + QPoint p1 = button->mapToScene(QPointF(2, 2)).toPoint(); + QTest::touchEvent(window, touchDevice).press(1, p1, window); + QQuickTouchUtils::flush(window); + QTRY_VERIFY(button->property("pressed").toBool()); + QTest::touchEvent(window, touchDevice).release(1, p1, window); + QQuickTouchUtils::flush(window); + QTRY_VERIFY(!button->property("pressed").toBool()); + QCOMPARE(tappedSpy.count(), 1); + + // Tap again in exactly the same place (not likely with touch in the real world) + QTest::touchEvent(window, touchDevice).press(1, p1, window); + QQuickTouchUtils::flush(window); + QTRY_VERIFY(button->property("pressed").toBool()); + QTest::touchEvent(window, touchDevice).release(1, p1, window); + QQuickTouchUtils::flush(window); + QTRY_VERIFY(!button->property("pressed").toBool()); + QCOMPARE(tappedSpy.count(), 2); + + // Tap a third time, nearby + p1 += QPoint(dragThreshold, dragThreshold); + QTest::touchEvent(window, touchDevice).press(1, p1, window); + QQuickTouchUtils::flush(window); + QTRY_VERIFY(button->property("pressed").toBool()); + QTest::touchEvent(window, touchDevice).release(1, p1, window); + QQuickTouchUtils::flush(window); + QTRY_VERIFY(!button->property("pressed").toBool()); + QCOMPARE(tappedSpy.count(), 3); + + // Tap a fourth time, drifting farther away + p1 += QPoint(dragThreshold, dragThreshold); + QTest::touchEvent(window, touchDevice).press(1, p1, window); + QQuickTouchUtils::flush(window); + QTRY_VERIFY(button->property("pressed").toBool()); + QTest::touchEvent(window, touchDevice).release(1, p1, window); + QQuickTouchUtils::flush(window); + QTRY_VERIFY(!button->property("pressed").toBool()); + QCOMPARE(tappedSpy.count(), 4); +} + +void tst_TapHandler::mouseMultiTap() +{ + const int dragThreshold = QGuiApplication::styleHints()->startDragDistance(); + QScopedPointer windowPtr; + createView(windowPtr, "buttons.qml"); + QQuickView * window = windowPtr.data(); + + QQuickItem *button = window->rootObject()->findChild("DragThreshold"); + QVERIFY(button); + QSignalSpy tappedSpy(button, SIGNAL(tapped())); + + // Tap once + QPoint p1 = button->mapToScene(QPointF(2, 2)).toPoint(); + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, p1); + QTRY_VERIFY(button->property("pressed").toBool()); + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p1); + QTRY_VERIFY(!button->property("pressed").toBool()); + QCOMPARE(tappedSpy.count(), 1); + + // Tap again in exactly the same place (not likely with touch in the real world) + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, p1); + QTRY_VERIFY(button->property("pressed").toBool()); + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p1); + QTRY_VERIFY(!button->property("pressed").toBool()); + QCOMPARE(tappedSpy.count(), 2); + + // Tap a third time, nearby + p1 += QPoint(dragThreshold, dragThreshold); + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, p1); + QTRY_VERIFY(button->property("pressed").toBool()); + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p1); + QTRY_VERIFY(!button->property("pressed").toBool()); + QCOMPARE(tappedSpy.count(), 3); + + // Tap a fourth time, drifting farther away + p1 += QPoint(dragThreshold, dragThreshold); + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, p1); + QTRY_VERIFY(button->property("pressed").toBool()); + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p1); + QTRY_VERIFY(!button->property("pressed").toBool()); + QCOMPARE(tappedSpy.count(), 4); +} + +void tst_TapHandler::touchLongPress() +{ + QScopedPointer windowPtr; + createView(windowPtr, "buttons.qml"); + QQuickView * window = windowPtr.data(); + + QQuickItem *button = window->rootObject()->findChild("DragThreshold"); + QVERIFY(button); + QQuickTapHandler *tapHandler = button->findChild("DragThreshold"); + QVERIFY(tapHandler); + QSignalSpy tappedSpy(button, SIGNAL(tapped())); + QSignalSpy longPressThresholdChangedSpy(tapHandler, SIGNAL(longPressThresholdChanged())); + QSignalSpy timeHeldSpy(tapHandler, SIGNAL(timeHeldChanged())); + QSignalSpy longPressedSpy(tapHandler, SIGNAL(longPressed())); + + // Reduce the threshold so that we can get a long press quickly + tapHandler->setLongPressThreshold(0.5); + QCOMPARE(longPressThresholdChangedSpy.count(), 1); + + // Press and hold + QPoint p1 = button->mapToScene(button->clipRect().center()).toPoint(); + QTest::touchEvent(window, touchDevice).press(1, p1, window); + QQuickTouchUtils::flush(window); + QTRY_VERIFY(button->property("pressed").toBool()); + QTRY_COMPARE(longPressedSpy.count(), 1); + timeHeldSpy.wait(); // the longer we hold it, the more this will occur + qDebug() << "held" << tapHandler->timeHeld() << "secs; timeHeld updated" << timeHeldSpy.count() << "times"; + QVERIFY(timeHeldSpy.count() > 0); + QVERIFY(tapHandler->timeHeld() > 0.5); + + // Release and verify that tapped was not emitted + QTest::touchEvent(window, touchDevice).release(1, p1, window); + QQuickTouchUtils::flush(window); + QTRY_VERIFY(!button->property("pressed").toBool()); + QCOMPARE(tappedSpy.count(), 0); +} + +void tst_TapHandler::mouseLongPress() +{ + QScopedPointer windowPtr; + createView(windowPtr, "buttons.qml"); + QQuickView * window = windowPtr.data(); + + QQuickItem *button = window->rootObject()->findChild("DragThreshold"); + QVERIFY(button); + QQuickTapHandler *tapHandler = button->findChild("DragThreshold"); + QVERIFY(tapHandler); + QSignalSpy tappedSpy(button, SIGNAL(tapped())); + QSignalSpy longPressThresholdChangedSpy(tapHandler, SIGNAL(longPressThresholdChanged())); + QSignalSpy timeHeldSpy(tapHandler, SIGNAL(timeHeldChanged())); + QSignalSpy longPressedSpy(tapHandler, SIGNAL(longPressed())); + + // Reduce the threshold so that we can get a long press quickly + tapHandler->setLongPressThreshold(0.5); + QCOMPARE(longPressThresholdChangedSpy.count(), 1); + + // Press and hold + QPoint p1 = button->mapToScene(button->clipRect().center()).toPoint(); + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, p1); + QTRY_VERIFY(button->property("pressed").toBool()); + QTRY_COMPARE(longPressedSpy.count(), 1); + timeHeldSpy.wait(); // the longer we hold it, the more this will occur + qDebug() << "held" << tapHandler->timeHeld() << "secs; timeHeld updated" << timeHeldSpy.count() << "times"; + QVERIFY(timeHeldSpy.count() > 0); + QVERIFY(tapHandler->timeHeld() > 0.5); + + // Release and verify that tapped was not emitted + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p1, 500); + QTRY_VERIFY(!button->property("pressed").toBool()); + QCOMPARE(tappedSpy.count(), 0); +} + +void tst_TapHandler::buttonsMultiTouch() +{ + QScopedPointer windowPtr; + createView(windowPtr, "buttons.qml"); + QQuickView * window = windowPtr.data(); + + QQuickItem *buttonDragThreshold = window->rootObject()->findChild("DragThreshold"); + QVERIFY(buttonDragThreshold); + QSignalSpy dragThresholdTappedSpy(buttonDragThreshold, SIGNAL(tapped())); + + QQuickItem *buttonWithinBounds = window->rootObject()->findChild("WithinBounds"); + QVERIFY(buttonWithinBounds); + QSignalSpy withinBoundsTappedSpy(buttonWithinBounds, SIGNAL(tapped())); + + QQuickItem *buttonReleaseWithinBounds = window->rootObject()->findChild("ReleaseWithinBounds"); + QVERIFY(buttonReleaseWithinBounds); + QSignalSpy releaseWithinBoundsTappedSpy(buttonReleaseWithinBounds, SIGNAL(tapped())); + + // can press multiple buttons at the same time + QPoint p1 = buttonDragThreshold->mapToScene(QPointF(20, 20)).toPoint(); + QTest::touchEvent(window, touchDevice).press(1, p1, window); + QQuickTouchUtils::flush(window); + QTRY_VERIFY(buttonDragThreshold->property("pressed").toBool()); + QPoint p2 = buttonWithinBounds->mapToScene(QPointF(20, 20)).toPoint(); + QTest::touchEvent(window, touchDevice).stationary(1).press(2, p2, window); + QQuickTouchUtils::flush(window); + QTRY_VERIFY(buttonWithinBounds->property("pressed").toBool()); + QPoint p3 = buttonReleaseWithinBounds->mapToScene(QPointF(20, 20)).toPoint(); + QTest::touchEvent(window, touchDevice).stationary(1).stationary(2).press(3, p3, window); + QQuickTouchUtils::flush(window); + QTRY_VERIFY(buttonReleaseWithinBounds->property("pressed").toBool()); + + // can release top button and press again: others stay pressed the whole time + QTest::touchEvent(window, touchDevice).stationary(2).stationary(3).release(1, p1, window); + QQuickTouchUtils::flush(window); + QTRY_VERIFY(!buttonDragThreshold->property("pressed").toBool()); + QCOMPARE(dragThresholdTappedSpy.count(), 1); + QVERIFY(buttonWithinBounds->property("pressed").toBool()); + QCOMPARE(withinBoundsTappedSpy.count(), 0); + QVERIFY(buttonReleaseWithinBounds->property("pressed").toBool()); + QCOMPARE(releaseWithinBoundsTappedSpy.count(), 0); + QTest::touchEvent(window, touchDevice).stationary(2).stationary(3).press(1, p1, window); + QQuickTouchUtils::flush(window); + QTRY_VERIFY(buttonDragThreshold->property("pressed").toBool()); + QVERIFY(buttonWithinBounds->property("pressed").toBool()); + QVERIFY(buttonReleaseWithinBounds->property("pressed").toBool()); + + // can release middle button and press again: others stay pressed the whole time + QTest::touchEvent(window, touchDevice).stationary(1).stationary(3).release(2, p2, window); + QQuickTouchUtils::flush(window); + QTRY_VERIFY(!buttonWithinBounds->property("pressed").toBool()); + QCOMPARE(withinBoundsTappedSpy.count(), 1); + QVERIFY(buttonDragThreshold->property("pressed").toBool()); + QCOMPARE(dragThresholdTappedSpy.count(), 1); + QVERIFY(buttonReleaseWithinBounds->property("pressed").toBool()); + QCOMPARE(releaseWithinBoundsTappedSpy.count(), 0); + QTest::touchEvent(window, touchDevice).stationary(1).stationary(3).press(2, p2, window); + QQuickTouchUtils::flush(window); + QVERIFY(buttonDragThreshold->property("pressed").toBool()); + QVERIFY(buttonWithinBounds->property("pressed").toBool()); + QVERIFY(buttonReleaseWithinBounds->property("pressed").toBool()); + + // can release bottom button and press again: others stay pressed the whole time + QTest::touchEvent(window, touchDevice).stationary(1).stationary(2).release(3, p3, window); + QQuickTouchUtils::flush(window); + QCOMPARE(releaseWithinBoundsTappedSpy.count(), 1); + QVERIFY(buttonWithinBounds->property("pressed").toBool()); + QCOMPARE(withinBoundsTappedSpy.count(), 1); + QVERIFY(!buttonReleaseWithinBounds->property("pressed").toBool()); + QCOMPARE(dragThresholdTappedSpy.count(), 1); + QTest::touchEvent(window, touchDevice).stationary(1).stationary(2).press(3, p3, window); + QQuickTouchUtils::flush(window); + QTRY_VERIFY(buttonDragThreshold->property("pressed").toBool()); + QVERIFY(buttonWithinBounds->property("pressed").toBool()); + QVERIFY(buttonReleaseWithinBounds->property("pressed").toBool()); +} + +QTEST_MAIN(tst_TapHandler) + +#include "tst_qquicktaphandler.moc" + -- cgit v1.2.3 From 8576777f1c5e743ef9104ce939f1b5da6ede89d3 Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Mon, 24 Apr 2017 19:12:42 +0200 Subject: TapHandler longPress autotest: be less demanding about hold time It's hitting slightly less than the expected amount of time in CI. Change-Id: I51ab1ee385045dd948f52e0c27e72ce627952fd6 Reviewed-by: Shawn Rutledge --- .../quick/pointerhandlers/qquicktaphandler/tst_qquicktaphandler.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'tests') diff --git a/tests/auto/quick/pointerhandlers/qquicktaphandler/tst_qquicktaphandler.cpp b/tests/auto/quick/pointerhandlers/qquicktaphandler/tst_qquicktaphandler.cpp index 2c1926103f..d7eda5e19c 100644 --- a/tests/auto/quick/pointerhandlers/qquicktaphandler/tst_qquicktaphandler.cpp +++ b/tests/auto/quick/pointerhandlers/qquicktaphandler/tst_qquicktaphandler.cpp @@ -464,7 +464,7 @@ void tst_TapHandler::touchLongPress() timeHeldSpy.wait(); // the longer we hold it, the more this will occur qDebug() << "held" << tapHandler->timeHeld() << "secs; timeHeld updated" << timeHeldSpy.count() << "times"; QVERIFY(timeHeldSpy.count() > 0); - QVERIFY(tapHandler->timeHeld() > 0.5); + QVERIFY(tapHandler->timeHeld() > 0.4); // Should be > 0.5 but slow CI and timer granularity can interfere // Release and verify that tapped was not emitted QTest::touchEvent(window, touchDevice).release(1, p1, window); @@ -500,7 +500,7 @@ void tst_TapHandler::mouseLongPress() timeHeldSpy.wait(); // the longer we hold it, the more this will occur qDebug() << "held" << tapHandler->timeHeld() << "secs; timeHeld updated" << timeHeldSpy.count() << "times"; QVERIFY(timeHeldSpy.count() > 0); - QVERIFY(tapHandler->timeHeld() > 0.5); + QVERIFY(tapHandler->timeHeld() > 0.4); // Should be > 0.5 but slow CI and timer granularity can interfere // Release and verify that tapped was not emitted QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p1, 500); -- cgit v1.2.3 From f569af401aae651ea9bfa1f3a8ff68a58f8d71d1 Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Fri, 31 Mar 2017 18:36:53 +0200 Subject: QQuickPointerDeviceHandler: add acceptedModifiers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sometimes you want to require holding down a key in order to enable some interaction. As with the other "accepted" flags, it's better to do this with a property than with Javascript. Change-Id: Ie29880f5f9f496ddca1bee462e2c0e6dd30fa9f5 Reviewed-by: Jan Arve Sæther --- tests/manual/pointer/pinchHandler.qml | 1 + tests/manual/pointer/tapWithModifiers.qml | 58 +++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+) create mode 100644 tests/manual/pointer/tapWithModifiers.qml (limited to 'tests') diff --git a/tests/manual/pointer/pinchHandler.qml b/tests/manual/pointer/pinchHandler.qml index 1d0a859564..71cdd98e4f 100644 --- a/tests/manual/pointer/pinchHandler.qml +++ b/tests/manual/pointer/pinchHandler.qml @@ -91,6 +91,7 @@ Rectangle { minimumX: 0 maximumX: 600 pointDistanceThreshold: 0 + // acceptedModifiers: Qt.ControlModifier } } diff --git a/tests/manual/pointer/tapWithModifiers.qml b/tests/manual/pointer/tapWithModifiers.qml new file mode 100644 index 0000000000..9a6977da1c --- /dev/null +++ b/tests/manual/pointer/tapWithModifiers.qml @@ -0,0 +1,58 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the manual tests of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.8 +import Qt.labs.handlers 1.0 + +Item { + width: 200 + height: 200 + TapHandler { + acceptedModifiers: Qt.ControlModifier + onTapped: console.log("control-tapped") + } + TapHandler { + acceptedModifiers: Qt.NoModifier + onTapped: console.log("tapped with no modifiers") + } + TapHandler { + onTapped: console.log("tapped with modifiers " + point.event.modifiers) + } +} -- cgit v1.2.3 From 4ff6bb3edc18a251dd1395ff0cb6fd50a3d79abf Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Fri, 31 Mar 2017 10:36:57 +0200 Subject: add pinchDragFlingMPTA example MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is a prototype of what 3-finger pinch is intended for: manipulating a container exclusively with a 3-finger gesture while not interfering at all with other gestures that occur inside the container. And it's normal that existing Items (like MPTA) do implicit grabs of touchpoints just by accepting, so this is also a test of cooperation between PointerHandlers and legacy Areas. It also adds the ability to drag the MPTA only while the Meta key is held down. And there is momentum on release whether you are doing a 3-finger pinch or via the DragHandler. Change-Id: Icd0e84809ec32dc8f347dd9c8f875d10f52eba19 Reviewed-by: Jan Arve Sæther --- tests/manual/pointer/pinchDragFlingMPTA.qml | 97 +++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100644 tests/manual/pointer/pinchDragFlingMPTA.qml (limited to 'tests') diff --git a/tests/manual/pointer/pinchDragFlingMPTA.qml b/tests/manual/pointer/pinchDragFlingMPTA.qml new file mode 100644 index 0000000000..25be48bb42 --- /dev/null +++ b/tests/manual/pointer/pinchDragFlingMPTA.qml @@ -0,0 +1,97 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the manual tests of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.8 +import Qt.labs.handlers 1.0 +import "content" + +Rectangle { + width: 1024; height: 600 + color: "beige" + objectName: "beige root" + + function getTransformationDetails(item, pinchhandler) { + return "scale:" + pinchhandler.scale.toFixed(2) + + " rotation:" + pinchhandler.rotation.toFixed(2) + + " translation:" + "(" + pinchhandler.translation.x.toFixed(2) + "," + pinchhandler.translation.y.toFixed(2) + ")" + } + + Rectangle { + id: container + objectName: "container rect" + width: 600 + height: 500 + color: pinch3.active ? "red" : "black" + antialiasing: true + Loader { + source: "../touch/mpta-crosshairs.qml" + anchors.fill: parent + anchors.margins: 2 + } + Item { + anchors.fill: parent + // In order for PinchHandler to get a chance to take a passive grab, it has to get the touchpoints first. + // In order to get the touchpoints first, it has to be on top of the Z order: i.e. come last in paintOrderChildItems(). + // This is the opposite situation as with filtersChildMouseEvents: e.g. PinchArea would have wanted to be the parent, + // if it even knew that trick (which it doesn't). + PinchHandler { + id: pinch3 + objectName: "3-finger pinch" + target: container + requiredPointCount: 3 + minimumScale: 0.1 + maximumScale: 10 + onActiveChanged: if (!active) fling.restart(centroidVelocity) + } + DragHandler { + id: dragHandler + objectName: "DragHandler" + target: container + acceptedModifiers: Qt.MetaModifier + onActiveChanged: if (!active) fling.restart(velocity) + } + } + MomentumAnimation { id: fling; target: container } + } + Text { + anchors.bottom: parent.bottom + text: pinch3.active ? getTransformationDetails(container, pinch3) : "Pinch with 3 fingers to scale, rotate and translate" + } +} -- cgit v1.2.3 From b7f9f342480c669780a244c237642edaf5b57bc3 Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Thu, 27 Apr 2017 12:16:20 +0200 Subject: QQMultiPointerHandler: don't steal grab if keepMouseGrab/keepTouchGrab MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit An Item (such as MPTA with onGestureStarted: gesture.grab()) may set these flags, traditionally to prevent Flickable from stealing the grab. QQuickMultiPointerHandler (and thus PinchHandler) now respects these flags too. Change-Id: Iac3ab796c5aa410be45639d679ecf82b7c44a442 Reviewed-by: Jan Arve Sæther --- tests/manual/touch/mpta-crosshairs.qml | 1 + 1 file changed, 1 insertion(+) (limited to 'tests') diff --git a/tests/manual/touch/mpta-crosshairs.qml b/tests/manual/touch/mpta-crosshairs.qml index d1dbd0f188..efea16029b 100644 --- a/tests/manual/touch/mpta-crosshairs.qml +++ b/tests/manual/touch/mpta-crosshairs.qml @@ -50,6 +50,7 @@ Rectangle { MultiPointTouchArea { id: mpta anchors.fill: parent + //onGestureStarted: gesture.grab() // in case this is embedded in something that might steal touchPoints: [ TouchPoint { property color color: "red" }, TouchPoint { property color color: "orange" }, -- cgit v1.2.3 From 47479c0e969a3b3d220c77b8bb7cb8f2d58c07ae Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Mon, 24 Apr 2017 08:51:47 +0200 Subject: DragHandler: allow parent to be different from target The most obvious way to implement a Slider is to allow dragging the knob - as on a real-world physical sliding potentiometer. But to make it easier on a touchscreen, it should be possible to touch anywhere along the slider's travel, as on a QtQuick.Controls 2 Slider. For that purpose, we need to respond to events within the bounds of one Item while actually dragging a different Item (the knob). It's similar to the way that PinchHandler can handle pinch gestures within one Item while transforming another (which may be too small to get both fingers inside). Change-Id: Iac9a5f11a7a45e22d93fe52bf62d157c48d72d3d Reviewed-by: Shawn Rutledge --- tests/manual/pointer/content/Slider.qml | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) (limited to 'tests') diff --git a/tests/manual/pointer/content/Slider.qml b/tests/manual/pointer/content/Slider.qml index 44dea8e33b..ecf45c02f3 100644 --- a/tests/manual/pointer/content/Slider.qml +++ b/tests/manual/pointer/content/Slider.qml @@ -50,6 +50,15 @@ Item { property alias pressed: tap.isPressed signal tapped + DragHandler { + id: dragHandler + objectName: label.text + " DragHandler" + target: knob + xAxis.enabled: false + yAxis.minimum: slot.y + yAxis.maximum: slot.height + slot.y - knob.height + } + Rectangle { id: slot anchors.top: parent.top @@ -90,13 +99,6 @@ Item { onYChanged: if (!programmatic) root.value = root.maximumValue - (knob.y - dragHandler.yAxis.minimum) * multiplier transformOrigin: Item.Center function setValue(value) { knob.y = dragHandler.yAxis.maximum - value / knob.multiplier } - DragHandler { - id: dragHandler - objectName: label.text + " DragHandler" - xAxis.enabled: false - yAxis.minimum: slot.y - yAxis.maximum: slot.height + slot.y - knob.height - } TapHandler { id: tap objectName: label.text + " TapHandler" -- cgit v1.2.3 From 4c84de4a93b0cdc116d67173eb5d8e7926fe3311 Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Fri, 21 Apr 2017 15:18:27 +0200 Subject: Add tst_flickableinterop: verify drag and tap handlers inside Flickable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Flickable can steal the grab from a PointerHandler the same way it can steal from an Item: by filtering the children's events. But within the drag threshold, or if the DragHandler is dragging, the handlers behave normally. Change-Id: If1bc1f2e8d9aaebb590f3434a3018a9f1a1f1dac Reviewed-by: Jan Arve Sæther --- .../flickableinterop/data/FlashAnimation.qml | 57 +++ .../flickableinterop/data/Slider.qml | 133 +++++++ .../flickableinterop/data/TapHandlerButton.qml | 100 +++++ .../data/flickableWithHandlers.qml | 79 ++++ .../flickableinterop/flickableinterop.pro | 15 + .../flickableinterop/tst_flickableinterop.cpp | 431 +++++++++++++++++++++ .../auto/quick/pointerhandlers/pointerhandlers.pro | 1 + 7 files changed, 816 insertions(+) create mode 100644 tests/auto/quick/pointerhandlers/flickableinterop/data/FlashAnimation.qml create mode 100644 tests/auto/quick/pointerhandlers/flickableinterop/data/Slider.qml create mode 100644 tests/auto/quick/pointerhandlers/flickableinterop/data/TapHandlerButton.qml create mode 100644 tests/auto/quick/pointerhandlers/flickableinterop/data/flickableWithHandlers.qml create mode 100644 tests/auto/quick/pointerhandlers/flickableinterop/flickableinterop.pro create mode 100644 tests/auto/quick/pointerhandlers/flickableinterop/tst_flickableinterop.cpp (limited to 'tests') diff --git a/tests/auto/quick/pointerhandlers/flickableinterop/data/FlashAnimation.qml b/tests/auto/quick/pointerhandlers/flickableinterop/data/FlashAnimation.qml new file mode 100644 index 0000000000..b628255a3d --- /dev/null +++ b/tests/auto/quick/pointerhandlers/flickableinterop/data/FlashAnimation.qml @@ -0,0 +1,57 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the manual tests of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 + +SequentialAnimation { + id: tapFlash + running: false + PropertyAction { value: false } + PauseAnimation { duration: 100 } + PropertyAction { value: true } + PauseAnimation { duration: 100 } + PropertyAction { value: false } + PauseAnimation { duration: 100 } + PropertyAction { value: true } + PauseAnimation { duration: 100 } + PropertyAction { value: false } + PauseAnimation { duration: 100 } + PropertyAction { value: true } +} diff --git a/tests/auto/quick/pointerhandlers/flickableinterop/data/Slider.qml b/tests/auto/quick/pointerhandlers/flickableinterop/data/Slider.qml new file mode 100644 index 0000000000..35e7ee2177 --- /dev/null +++ b/tests/auto/quick/pointerhandlers/flickableinterop/data/Slider.qml @@ -0,0 +1,133 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.8 +import Qt.labs.handlers 1.0 + +Item { + id: root + property int value: 50 + property int maximumValue: 99 + property alias label: label.text + property alias tapEnabled: tap.enabled + property alias pressed: tap.isPressed + signal tapped + + Rectangle { + id: slot + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.margins: 10 + anchors.topMargin: 30 + anchors.bottomMargin: 30 + anchors.horizontalCenter: parent.horizontalCenter + width: 10 + color: "black" + radius: width / 2 + smooth: true + } + + Rectangle { + id: glow + anchors.fill: knob + anchors.margins: -5 + anchors.leftMargin: -2 + anchors.horizontalCenterOffset: 1 + radius: 5 + color: "#4400FFFF" + opacity: dragHandler.active || tapFlash.running ? 1 : 0 + FlashAnimation on visible { + id: tapFlash + } + } + Rectangle { + id: knob + objectName: "Slider Knob" + width: parent.width - 2 + height: 20 + radius: 5 + color: "darkgray" + border.color: "black" + property bool programmatic: false + property real multiplier: root.maximumValue / (dragHandler.yAxis.maximum - dragHandler.yAxis.minimum) + onYChanged: if (!programmatic) root.value = root.maximumValue - (knob.y - dragHandler.yAxis.minimum) * multiplier + transformOrigin: Item.Center + function setValue(value) { knob.y = dragHandler.yAxis.maximum - value / knob.multiplier } + DragHandler { + id: dragHandler + objectName: label.text + " DragHandler" + xAxis.enabled: false + yAxis.minimum: slot.y + yAxis.maximum: slot.height + slot.y - knob.height + } + TapHandler { + id: tap + objectName: label.text + " TapHandler" + gesturePolicy: TapHandler.DragThreshold + onTapped: { + tapFlash.start() + root.tapped + } + } + } + + Text { + font.pointSize: 16 + color: "red" + anchors.bottom: parent.bottom + anchors.horizontalCenter: parent.horizontalCenter + text: root.value + } + + Text { + id: label + font.pointSize: 12 + color: "red" + anchors.top: parent.top + anchors.topMargin: 5 + anchors.horizontalCenter: parent.horizontalCenter + } + + Component.onCompleted: { + knob.programmatic = true + knob.setValue(root.value) + knob.programmatic = false + } +} diff --git a/tests/auto/quick/pointerhandlers/flickableinterop/data/TapHandlerButton.qml b/tests/auto/quick/pointerhandlers/flickableinterop/data/TapHandlerButton.qml new file mode 100644 index 0000000000..af9b906861 --- /dev/null +++ b/tests/auto/quick/pointerhandlers/flickableinterop/data/TapHandlerButton.qml @@ -0,0 +1,100 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.8 +import Qt.labs.handlers 1.0 + +Rectangle { + id: root + property alias label: label.text + property alias pressed: tap.isPressed + property bool checked: false + property alias gesturePolicy: tap.gesturePolicy + property alias enabled: tap.enabled + signal tapped + + width: label.implicitWidth * 1.5; height: label.implicitHeight * 2.0 + border.color: "#9f9d9a"; border.width: 1; radius: height / 4; antialiasing: true + + gradient: Gradient { + GradientStop { position: 0.0; color: tap.isPressed ? "#b8b5b2" : "#efebe7" } + GradientStop { position: 1.0; color: "#b8b5b2" } + } + + TapHandler { + id: tap + objectName: label.text + longPressThreshold: 100 // CI can be insanely slow, so don't demand a timely release to generate onTapped + onTapped: { + tapFlash.start() + root.tapped() + } + } + + Text { + id: label + font.pointSize: 14 + text: "Button" + anchors.centerIn: parent + } + + Rectangle { + anchors.fill: parent; anchors.margins: -5 + color: "transparent"; border.color: "#4400FFFF" + border.width: 5; radius: root.radius; antialiasing: true + opacity: tapFlash.running ? 1 : 0 + FlashAnimation on visible { id: tapFlash } + } + + Rectangle { + objectName: "expandingCircle" + radius: tap.timeHeld * 100 + visible: radius > 0 && tap.isPressed + border.width: 3 + border.color: "cyan" + color: "transparent" + width: radius * 2 + height: radius * 2 + x: tap.scenePressPos.x - radius + y: tap.scenePressPos.y - radius + opacity: 0.25 + Component.onCompleted: parent = root.parent + } +} diff --git a/tests/auto/quick/pointerhandlers/flickableinterop/data/flickableWithHandlers.qml b/tests/auto/quick/pointerhandlers/flickableinterop/data/flickableWithHandlers.qml new file mode 100644 index 0000000000..7799dd0ec3 --- /dev/null +++ b/tests/auto/quick/pointerhandlers/flickableinterop/data/flickableWithHandlers.qml @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.8 +import Qt.labs.handlers 1.0 + +Rectangle { + id: root + width: 400 + height: 480 + objectName: "root" + color: "#222222" + + Flickable { + anchors.fill: parent + anchors.margins: 10 + anchors.topMargin: 40 + contentHeight: 600 + contentWidth: 600 +// pressDelay: TODO + + Row { + spacing: 6 + Slider { + label: "DragHandler" + objectName: "Slider" + value: 49; width: 100; height: 400 + } + Column { + spacing: 6 + TapHandlerButton { + label: "TapHandler" + objectName: "Button 1" + } + TapHandlerButton { + label: "TapHandler" + objectName: "Button 2" + } + } + } + } +} diff --git a/tests/auto/quick/pointerhandlers/flickableinterop/flickableinterop.pro b/tests/auto/quick/pointerhandlers/flickableinterop/flickableinterop.pro new file mode 100644 index 0000000000..9075044bd3 --- /dev/null +++ b/tests/auto/quick/pointerhandlers/flickableinterop/flickableinterop.pro @@ -0,0 +1,15 @@ +CONFIG += testcase + +TARGET = tst_flickableinterop +QT += core-private gui-private qml-private quick-private testlib + +macos:CONFIG -= app_bundle + +SOURCES += tst_flickableinterop.cpp + +include (../../../shared/util.pri) +include (../../shared/util.pri) + +TESTDATA = data/* + +OTHER_FILES += data/flickableWithHandlers.qml data/Slider.qml diff --git a/tests/auto/quick/pointerhandlers/flickableinterop/tst_flickableinterop.cpp b/tests/auto/quick/pointerhandlers/flickableinterop/tst_flickableinterop.cpp new file mode 100644 index 0000000000..93b6d27f21 --- /dev/null +++ b/tests/auto/quick/pointerhandlers/flickableinterop/tst_flickableinterop.cpp @@ -0,0 +1,431 @@ +/**************************************************************************** +** +** Copyright (C) 2017 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 + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include "../../../shared/util.h" +#include "../../shared/viewtestutil.h" + +Q_LOGGING_CATEGORY(lcPointerTests, "qt.quick.pointer.tests") + +class tst_FlickableInterop : public QQmlDataTest +{ + Q_OBJECT +public: + tst_FlickableInterop() + :touchDevice(QTest::createTouchDevice()) + {} + +private slots: + void initTestCase(); + + void touchTapButton(); + void touchDragFlickableBehindButton(); + void mouseClickButton(); + void mouseDragFlickableBehindButton(); + void touchDragSlider(); + void touchDragFlickableBehindSlider(); + void mouseDragSlider(); + void mouseDragFlickableBehindSlider(); + +private: + void createView(QScopedPointer &window, const char *fileName); + QTouchDevice *touchDevice; +}; + +void tst_FlickableInterop::createView(QScopedPointer &window, const char *fileName) +{ + window.reset(new QQuickView); + window->setSource(testFileUrl(fileName)); + QTRY_COMPARE(window->status(), QQuickView::Ready); + QQuickViewTestUtil::centerOnScreen(window.data()); + QQuickViewTestUtil::moveMouseAway(window.data()); + + window->show(); + QVERIFY(QTest::qWaitForWindowActive(window.data())); + QVERIFY(window->rootObject() != 0); +} + +void tst_FlickableInterop::initTestCase() +{ + // This test assumes that we don't get synthesized mouse events from QGuiApplication + qApp->setAttribute(Qt::AA_SynthesizeMouseForUnhandledTouchEvents, false); + + QQmlDataTest::initTestCase(); +} + +void tst_FlickableInterop::touchTapButton() +{ + const int dragThreshold = QGuiApplication::styleHints()->startDragDistance(); + QScopedPointer windowPtr; + createView(windowPtr, "flickableWithHandlers.qml"); + QQuickView * window = windowPtr.data(); + + QQuickItem *button = window->rootObject()->findChild("Button 1"); + QVERIFY(button); + QSignalSpy tappedSpy(button, SIGNAL(tapped())); + + // Button changes pressed state and emits tapped on release + QPoint p1 = button->mapToScene(QPointF(20, 20)).toPoint(); + QTest::touchEvent(window, touchDevice).press(1, p1, window); + QQuickTouchUtils::flush(window); + QTRY_VERIFY(button->property("pressed").toBool()); + QTest::touchEvent(window, touchDevice).release(1, p1, window); + QQuickTouchUtils::flush(window); + QTRY_VERIFY(!button->property("pressed").toBool()); + QCOMPARE(tappedSpy.count(), 1); + + // We can drag <= dragThreshold and the button still acts normal, Flickable doesn't grab + p1 = button->mapToScene(QPointF(20, 20)).toPoint(); + QTest::touchEvent(window, touchDevice).press(1, p1, window); + QQuickTouchUtils::flush(window); + QTRY_VERIFY(button->property("pressed").toBool()); + p1 += QPoint(dragThreshold, 0); + QTest::touchEvent(window, touchDevice).move(1, p1, window); + QQuickTouchUtils::flush(window); + QVERIFY(button->property("pressed").toBool()); + QTest::touchEvent(window, touchDevice).release(1, p1, window); + QQuickTouchUtils::flush(window); + QTRY_VERIFY(!button->property("pressed").toBool()); + QCOMPARE(tappedSpy.count(), 2); +} + +void tst_FlickableInterop::touchDragFlickableBehindButton() +{ + const int dragThreshold = QGuiApplication::styleHints()->startDragDistance(); + QScopedPointer windowPtr; + createView(windowPtr, "flickableWithHandlers.qml"); + QQuickView * window = windowPtr.data(); + + QQuickItem *button = window->rootObject()->findChild("Button 1"); + QVERIFY(button); + QQuickFlickable *flickable = window->rootObject()->findChild(); + QVERIFY(flickable); + QSignalSpy tappedSpy(button, SIGNAL(tapped())); + + // Button is no longer pressed if touchpoint goes beyond dragThreshold, + // because Flickable steals the grab + tappedSpy.clear(); + QPoint p1 = button->mapToScene(QPointF(20, 20)).toPoint(); + QTest::touchEvent(window, touchDevice).press(1, p1, window); + QQuickTouchUtils::flush(window); + QTRY_VERIFY(button->property("pressed").toBool()); + p1 += QPoint(dragThreshold, 0); + QTest::touchEvent(window, touchDevice).move(1, p1, window); + QQuickTouchUtils::flush(window); + QVERIFY(button->property("pressed").toBool()); + int i = 0; + for (; i < 100 && !flickable->isMoving(); ++i) { + p1 += QPoint(1, 0); + QTest::touchEvent(window, touchDevice).move(1, p1, window); + QQuickTouchUtils::flush(window); + } + QVERIFY(flickable->isMoving()); + qDebug() << "flickable started moving after" << i << "moves, when we got to" << p1; + QCOMPARE(i, 2); + QVERIFY(!button->property("pressed").toBool()); + QTest::touchEvent(window, touchDevice).release(1, p1, window); + QQuickTouchUtils::flush(window); + QVERIFY(!button->property("pressed").toBool()); + QCOMPARE(tappedSpy.count(), 0); +} + +void tst_FlickableInterop::mouseClickButton() +{ + const int dragThreshold = QGuiApplication::styleHints()->startDragDistance(); + QScopedPointer windowPtr; + createView(windowPtr, "flickableWithHandlers.qml"); + QQuickView * window = windowPtr.data(); + + QQuickItem *button = window->rootObject()->findChild("Button 1"); + QVERIFY(button); + QSignalSpy tappedSpy(button, SIGNAL(tapped())); + + // Button changes pressed state and emits tapped on release + QPoint p1 = button->mapToScene(QPointF(20, 20)).toPoint(); + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, p1); + QTRY_VERIFY(button->property("pressed").toBool()); + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p1); + QTRY_VERIFY(!button->property("pressed").toBool()); + QCOMPARE(tappedSpy.count(), 1); + + // We can drag <= dragThreshold and the button still acts normal, Flickable doesn't grab + p1 = button->mapToScene(QPointF(20, 20)).toPoint(); + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, p1); + QTRY_VERIFY(button->property("pressed").toBool()); + p1 += QPoint(dragThreshold, 0); + QTest::mouseMove(window, p1); + QVERIFY(button->property("pressed").toBool()); + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p1); + QTRY_VERIFY(!button->property("pressed").toBool()); + QCOMPARE(tappedSpy.count(), 2); +} + +void tst_FlickableInterop::mouseDragFlickableBehindButton() +{ + const int dragThreshold = QGuiApplication::styleHints()->startDragDistance(); + QScopedPointer windowPtr; + createView(windowPtr, "flickableWithHandlers.qml"); + QQuickView * window = windowPtr.data(); + + QQuickItem *button = window->rootObject()->findChild("Button 1"); + QVERIFY(button); + QQuickFlickable *flickable = window->rootObject()->findChild(); + QVERIFY(flickable); + QSignalSpy tappedSpy(button, SIGNAL(tapped())); + + // Button is no longer pressed if touchpoint goes beyond dragThreshold, + // because Flickable steals the grab + tappedSpy.clear(); + QPoint p1 = button->mapToScene(QPointF(20, 20)).toPoint(); + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, p1); + QTRY_VERIFY(button->property("pressed").toBool()); + p1 += QPoint(dragThreshold, 0); + QTest::touchEvent(window, touchDevice).move(1, p1, window); + QVERIFY(button->property("pressed").toBool()); + int i = 0; + for (; i < 100 && !flickable->isMoving(); ++i) { + p1 += QPoint(1, 0); + QTest::mouseMove(window, p1); + } + qDebug() << "flickable started moving after" << i << "moves, when we got to" << p1; + QVERIFY(flickable->isMoving()); + QCOMPARE(i, 2); + QVERIFY(!button->property("pressed").toBool()); + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p1); + QVERIFY(!button->property("pressed").toBool()); + QCOMPARE(tappedSpy.count(), 0); +} + +void tst_FlickableInterop::touchDragSlider() +{ + const int dragThreshold = QGuiApplication::styleHints()->startDragDistance(); + QScopedPointer windowPtr; + createView(windowPtr, "flickableWithHandlers.qml"); + QQuickView * window = windowPtr.data(); + + QQuickItem *slider = window->rootObject()->findChild("Slider"); + QVERIFY(slider); + QQuickDragHandler *drag = slider->findChild(); + QVERIFY(drag); + QQuickItem *knob = slider->findChild("Slider Knob"); + QVERIFY(knob); + QQuickFlickable *flickable = window->rootObject()->findChild(); + QVERIFY(flickable); + QSignalSpy tappedSpy(knob->parent(), SIGNAL(tapped())); + QSignalSpy translationChangedSpy(drag, SIGNAL(translationChanged())); + + // Drag the slider in the allowed (vertical) direction + tappedSpy.clear(); + QPoint p1 = knob->mapToScene(knob->clipRect().center()).toPoint(); + QTest::touchEvent(window, touchDevice).press(1, p1, window); + QQuickTouchUtils::flush(window); + QTRY_VERIFY(slider->property("pressed").toBool()); + p1 += QPoint(0, dragThreshold); + QTest::touchEvent(window, touchDevice).move(1, p1, window); + QQuickTouchUtils::flush(window); + QVERIFY(slider->property("pressed").toBool()); + QCOMPARE(slider->property("value").toInt(), 49); + p1 += QPoint(0, 1); + QTest::touchEvent(window, touchDevice).move(1, p1, window); + QQuickTouchUtils::flush(window); + p1 += QPoint(0, 10); + QTest::touchEvent(window, touchDevice).move(1, p1, window); + QQuickTouchUtils::flush(window); + QVERIFY(slider->property("value").toInt() < 49); + QVERIFY(!flickable->isMoving()); + QVERIFY(!slider->property("pressed").toBool()); + + // Now that the DragHandler is active, the Flickable will not steal the grab + // even if we move a large distance horizontally + p1 += QPoint(dragThreshold * 2, 0); + QTest::touchEvent(window, touchDevice).move(1, p1, window); + QQuickTouchUtils::flush(window); + QVERIFY(!flickable->isMoving()); + + // Release, and do not expect the tapped signal + QTest::touchEvent(window, touchDevice).release(1, p1, window); + QQuickTouchUtils::flush(window); + QCOMPARE(tappedSpy.count(), 0); + QCOMPARE(translationChangedSpy.count(), 1); +} + +void tst_FlickableInterop::mouseDragSlider() +{ + const int dragThreshold = QGuiApplication::styleHints()->startDragDistance(); + QScopedPointer windowPtr; + createView(windowPtr, "flickableWithHandlers.qml"); + QQuickView * window = windowPtr.data(); + + QQuickItem *slider = window->rootObject()->findChild("Slider"); + QVERIFY(slider); + QQuickDragHandler *drag = slider->findChild(); + QVERIFY(drag); + QQuickItem *knob = slider->findChild("Slider Knob"); + QVERIFY(knob); + QQuickFlickable *flickable = window->rootObject()->findChild(); + QVERIFY(flickable); + QSignalSpy tappedSpy(knob->parent(), SIGNAL(tapped())); + QSignalSpy translationChangedSpy(drag, SIGNAL(translationChanged())); + + // Drag the slider in the allowed (vertical) direction + tappedSpy.clear(); + QPoint p1 = knob->mapToScene(knob->clipRect().center()).toPoint(); + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, p1); + QTRY_VERIFY(slider->property("pressed").toBool()); + p1 += QPoint(0, dragThreshold); + QTest::mouseMove(window, p1); + QVERIFY(slider->property("pressed").toBool()); + QCOMPARE(slider->property("value").toInt(), 49); + p1 += QPoint(0, 1); + QTest::mouseMove(window, p1); + p1 += QPoint(0, 10); + QTest::mouseMove(window, p1); + QVERIFY(slider->property("value").toInt() < 49); + QVERIFY(!flickable->isMoving()); + QVERIFY(!slider->property("pressed").toBool()); + + // Now that the DragHandler is active, the Flickable will not steal the grab + // even if we move a large distance horizontally + p1 += QPoint(dragThreshold * 2, 0); + QTest::mouseMove(window, p1); + QVERIFY(!flickable->isMoving()); + + // Release, and do not expect the tapped signal + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p1); + QCOMPARE(tappedSpy.count(), 0); + QCOMPARE(translationChangedSpy.count(), 1); +} + +void tst_FlickableInterop::touchDragFlickableBehindSlider() +{ + const int dragThreshold = QGuiApplication::styleHints()->startDragDistance(); + QScopedPointer windowPtr; + createView(windowPtr, "flickableWithHandlers.qml"); + QQuickView * window = windowPtr.data(); + + QQuickItem *slider = window->rootObject()->findChild("Slider"); + QVERIFY(slider); + QQuickDragHandler *drag = slider->findChild(); + QVERIFY(drag); + QQuickItem *knob = slider->findChild("Slider Knob"); + QVERIFY(knob); + QQuickFlickable *flickable = window->rootObject()->findChild(); + QVERIFY(flickable); + QSignalSpy tappedSpy(knob->parent(), SIGNAL(tapped())); + QSignalSpy translationChangedSpy(drag, SIGNAL(translationChanged())); + + // Button is no longer pressed if touchpoint goes beyond dragThreshold, + // because Flickable steals the grab + tappedSpy.clear(); + QPoint p1 = knob->mapToScene(knob->clipRect().center()).toPoint(); + QTest::touchEvent(window, touchDevice).press(1, p1, window); + QQuickTouchUtils::flush(window); + QTRY_VERIFY(slider->property("pressed").toBool()); + p1 += QPoint(dragThreshold, 0); + QTest::touchEvent(window, touchDevice).move(1, p1, window); + QQuickTouchUtils::flush(window); + QVERIFY(slider->property("pressed").toBool()); + int i = 0; + for (; i < 100 && !flickable->isMoving(); ++i) { + p1 += QPoint(1, 0); + QTest::touchEvent(window, touchDevice).move(1, p1, window); + QQuickTouchUtils::flush(window); + } + qDebug() << "flickable started moving after" << i << "moves, when we got to" << p1; + QVERIFY(flickable->isMoving()); + QCOMPARE(i, 2); + QVERIFY(!slider->property("pressed").toBool()); + QTest::touchEvent(window, touchDevice).release(1, p1, window); + QQuickTouchUtils::flush(window); + QVERIFY(!slider->property("pressed").toBool()); + QCOMPARE(tappedSpy.count(), 0); + QCOMPARE(translationChangedSpy.count(), 0); +} + +void tst_FlickableInterop::mouseDragFlickableBehindSlider() +{ + const int dragThreshold = QGuiApplication::styleHints()->startDragDistance(); + QScopedPointer windowPtr; + createView(windowPtr, "flickableWithHandlers.qml"); + QQuickView * window = windowPtr.data(); + + QQuickItem *slider = window->rootObject()->findChild("Slider"); + QVERIFY(slider); + QQuickDragHandler *drag = slider->findChild(); + QVERIFY(drag); + QQuickItem *knob = slider->findChild("Slider Knob"); + QVERIFY(knob); + QQuickFlickable *flickable = window->rootObject()->findChild(); + QVERIFY(flickable); + QSignalSpy tappedSpy(knob->parent(), SIGNAL(tapped())); + QSignalSpy translationChangedSpy(drag, SIGNAL(translationChanged())); + + // Button is no longer pressed if touchpoint goes beyond dragThreshold, + // because Flickable steals the grab + tappedSpy.clear(); + QPoint p1 = knob->mapToScene(knob->clipRect().center()).toPoint(); + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, p1); + QTRY_VERIFY(slider->property("pressed").toBool()); + p1 += QPoint(dragThreshold, 0); + QTest::mouseMove(window, p1); + QQuickTouchUtils::flush(window); + QVERIFY(slider->property("pressed").toBool()); + int i = 0; + for (; i < 100 && !flickable->isMoving(); ++i) { + p1 += QPoint(1, 0); + QTest::mouseMove(window, p1); + } + qDebug() << "flickable started moving after" << i << "moves, when we got to" << p1; + QVERIFY(flickable->isMoving()); + QCOMPARE(i, 2); + QVERIFY(!slider->property("pressed").toBool()); + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p1); + QCOMPARE(tappedSpy.count(), 0); + QCOMPARE(translationChangedSpy.count(), 0); +} + +QTEST_MAIN(tst_FlickableInterop) + +#include "tst_flickableinterop.moc" + diff --git a/tests/auto/quick/pointerhandlers/pointerhandlers.pro b/tests/auto/quick/pointerhandlers/pointerhandlers.pro index ba889d1399..4aa66df2c4 100644 --- a/tests/auto/quick/pointerhandlers/pointerhandlers.pro +++ b/tests/auto/quick/pointerhandlers/pointerhandlers.pro @@ -2,6 +2,7 @@ TEMPLATE = subdirs qtConfig(private_tests) { SUBDIRS += \ + flickableinterop \ qquickpointerhandler \ qquicktaphandler \ } -- cgit v1.2.3 From ab91e7fa02a562d80fd0747f28a60e00c3b45a01 Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Tue, 2 May 2017 11:34:19 +0200 Subject: Default QQuickItem::acceptTouchEvents to true until Qt 6 This is a partial revert of 1457df74f4c1d770e1e820de8cd082be1bd2489e to avoid making a mandatory API change so soon. Change-Id: I05040579fa36d3dc5ef7616861f6d17adf500d2c Reviewed-by: Shawn Rutledge --- tests/auto/quick/qquickflickable/tst_qquickflickable.cpp | 4 ++++ tests/auto/quick/qquickitem/tst_qquickitem.cpp | 11 +++++++---- tests/auto/quick/touchmouse/tst_touchmouse.cpp | 2 ++ 3 files changed, 13 insertions(+), 4 deletions(-) (limited to 'tests') diff --git a/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp b/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp index b37bb03305..0bb913d104 100644 --- a/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp +++ b/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp @@ -64,7 +64,11 @@ public: , ungrabs(0) , m_active(false) { +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) setAcceptTouchEvents(true); +#else + setAcceptedMouseButtons(Qt::LeftButton); // not really, but we want touch events +#endif } QPointF pos() const { return m_pos; } diff --git a/tests/auto/quick/qquickitem/tst_qquickitem.cpp b/tests/auto/quick/qquickitem/tst_qquickitem.cpp index dbfe97d640..f4434d9d3f 100644 --- a/tests/auto/quick/qquickitem/tst_qquickitem.cpp +++ b/tests/auto/quick/qquickitem/tst_qquickitem.cpp @@ -46,11 +46,14 @@ class TestItem : public QQuickItem Q_OBJECT public: TestItem(QQuickItem *parent = 0) - : QQuickItem(parent), focused(false), pressCount(0), releaseCount(0) - , wheelCount(0), acceptIncomingTouchEvents(true) - , touchEventReached(false), timestamp(0) - , lastWheelEventPos(0, 0), lastWheelEventGlobalPos(0, 0) { + : QQuickItem(parent), focused(false), pressCount(0), releaseCount(0) + , wheelCount(0), acceptIncomingTouchEvents(true) + , touchEventReached(false), timestamp(0) + , lastWheelEventPos(0, 0), lastWheelEventGlobalPos(0, 0) + { +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) setAcceptTouchEvents(true); +#endif } bool focused; diff --git a/tests/auto/quick/touchmouse/tst_touchmouse.cpp b/tests/auto/quick/touchmouse/tst_touchmouse.cpp index 6f5c9a37d5..643d3dbb90 100644 --- a/tests/auto/quick/touchmouse/tst_touchmouse.cpp +++ b/tests/auto/quick/touchmouse/tst_touchmouse.cpp @@ -74,7 +74,9 @@ public: : QQuickItem(parent), touchUngrabCount(0), acceptMouse(false), acceptTouch(false), filterTouch(false), point0(-1) { setAcceptedMouseButtons(Qt::LeftButton); +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) setAcceptTouchEvents(true); +#endif } void touchEvent(QTouchEvent *event) -- cgit v1.2.3 From 15a1a4868fee2770debb4cb10ae64f701e63466b Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Thu, 11 May 2017 13:47:58 +0200 Subject: touchmouse autotest: add debug operator for the test-specific Event type It's nice to be able to do qDebug() << eventItem->eventList when troubleshooting behavior in case of test failure. Change-Id: I2b50d5b092a0c9eb4eab3105be66a36aedf871bb Reviewed-by: Shawn Rutledge --- tests/auto/quick/touchmouse/tst_touchmouse.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'tests') diff --git a/tests/auto/quick/touchmouse/tst_touchmouse.cpp b/tests/auto/quick/touchmouse/tst_touchmouse.cpp index 643d3dbb90..01aa5d1c8e 100644 --- a/tests/auto/quick/touchmouse/tst_touchmouse.cpp +++ b/tests/auto/quick/touchmouse/tst_touchmouse.cpp @@ -30,6 +30,7 @@ #include #include +#include #include #include @@ -62,6 +63,21 @@ struct Event QList 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 -- cgit v1.2.3 From c673220a3cdb03ba0aa2c0d09e14af9a2112f4a8 Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Wed, 26 Apr 2017 09:32:59 +0200 Subject: tst_qquickpointerhandler: use QScopedPointer; improvements It's now standard practice in autotests to use QScopedPointer to manage the window so that it doesn't need to be deleted (or would be left dangling if the test fails). It's nice to be able to see the bounds of the EventItem. Test not only the order of the event types received, but the EventPoint state, and where they were received. Of course PointerEvents go only to PointerHandlers in this test so far... but now we can distinguish filtered events from events which were received via the QQuickItem virtual function overrides. Change-Id: I4830a431bedb7101c8c980ab3260d23b5852b645 Reviewed-by: Shawn Rutledge --- .../qquickpointerhandler/data/singleitem.qml | 14 +- .../tst_qquickpointerhandler.cpp | 184 ++++++++++++--------- 2 files changed, 113 insertions(+), 85 deletions(-) (limited to 'tests') diff --git a/tests/auto/quick/pointerhandlers/qquickpointerhandler/data/singleitem.qml b/tests/auto/quick/pointerhandlers/qquickpointerhandler/data/singleitem.qml index fe05a3f935..126cf3ff2b 100644 --- a/tests/auto/quick/pointerhandlers/qquickpointerhandler/data/singleitem.qml +++ b/tests/auto/quick/pointerhandlers/qquickpointerhandler/data/singleitem.qml @@ -1,13 +1,20 @@ import QtQuick 2.8 import Qt.test 1.0 -Rectangle { +Item { id: root + objectName: "root Item" width: 320 height: 480 - color: "green" + + Rectangle { + objectName: "eventItem's bounds" + anchors.fill: eventItem + color: "lightsteelblue" + } EventItem { + id: eventItem objectName: "eventItem1" x: 5 y: 5 @@ -15,8 +22,7 @@ Rectangle { width: 30 EventHandler { - + objectName: "eventHandler" } } } - diff --git a/tests/auto/quick/pointerhandlers/qquickpointerhandler/tst_qquickpointerhandler.cpp b/tests/auto/quick/pointerhandlers/qquickpointerhandler/tst_qquickpointerhandler.cpp index d822330f21..f648fb33f6 100644 --- a/tests/auto/quick/pointerhandlers/qquickpointerhandler/tst_qquickpointerhandler.cpp +++ b/tests/auto/quick/pointerhandlers/qquickpointerhandler/tst_qquickpointerhandler.cpp @@ -52,11 +52,21 @@ Q_LOGGING_CATEGORY(lcPointerTests, "qt.quick.pointer.tests") struct Event { - Event(QEvent::Type t, QPointF item, QPointF scene) - :type(t), posWrtItem(item), posWrtScene(scene) + enum Destination { + FilterDestination, + MouseDestination, + TouchDestination, + HandlerDestination + }; + + Event(Destination d, QEvent::Type t, Qt::TouchPointState s, QPointF item, QPointF scene) + : destination(d), type(t), state(s), posWrtItem(item), posWrtScene(scene) {} + Destination destination; QEvent::Type type; + Qt::TouchPointState state; + QPointF posWrtItem; QPointF posWrtScene; @@ -83,38 +93,38 @@ public: { qCDebug(lcPointerTests) << event << "will accept?" << acceptTouch; for (const QTouchEvent::TouchPoint &tp : event->touchPoints()) - eventList.append(Event(event->type(), tp.pos(), tp.scenePos())); + eventList.append(Event(Event::TouchDestination, event->type(), tp.state(), tp.pos(), tp.scenePos())); event->setAccepted(acceptTouch); } void mousePressEvent(QMouseEvent *event) { qCDebug(lcPointerTests) << event; - eventList.append(Event(event->type(), event->pos(), event->windowPos())); + eventList.append(Event(Event::MouseDestination, event->type(), Qt::TouchPointPressed, event->pos(), event->windowPos())); event->setAccepted(acceptMouse); } void mouseMoveEvent(QMouseEvent *event) { qCDebug(lcPointerTests) << event; - eventList.append(Event(event->type(), event->pos(), event->windowPos())); + eventList.append(Event(Event::MouseDestination, event->type(), Qt::TouchPointMoved, event->pos(), event->windowPos())); event->setAccepted(acceptMouse); } void mouseReleaseEvent(QMouseEvent *event) { qCDebug(lcPointerTests) << event; - eventList.append(Event(event->type(), event->pos(), event->windowPos())); + eventList.append(Event(Event::MouseDestination, event->type(), Qt::TouchPointReleased, event->pos(), event->windowPos())); event->setAccepted(acceptMouse); } void mouseDoubleClickEvent(QMouseEvent *event) { qCDebug(lcPointerTests) << event; - eventList.append(Event(event->type(), event->pos(), event->windowPos())); + eventList.append(Event(Event::MouseDestination, event->type(), Qt::TouchPointPressed, event->pos(), event->windowPos())); event->setAccepted(acceptMouse); } void mouseUngrabEvent() { qCDebug(lcPointerTests); - eventList.append(Event(QEvent::UngrabMouse, QPoint(0,0), QPoint(0,0))); + eventList.append(Event(Event::MouseDestination, QEvent::UngrabMouse, Qt::TouchPointReleased, QPoint(0,0), QPoint(0,0))); } bool event(QEvent *event) @@ -139,7 +149,7 @@ public: event->type() == QEvent::TouchEnd) { QTouchEvent *touch = static_cast(event); for (const QTouchEvent::TouchPoint &tp : touch->touchPoints()) - eventList.append(Event(event->type(), tp.pos(), tp.scenePos())); + eventList.append(Event(Event::FilterDestination, event->type(), tp.state(), tp.pos(), tp.scenePos())); if (filterTouch) event->accept(); return true; @@ -148,6 +158,14 @@ public: } }; +#define QCOMPARE_EVENT(i, d, s, t) \ + {\ + const Event &event = eventItem1->eventList.at(i);\ + QCOMPARE(event.destination, d);\ + QCOMPARE(event.type, t);\ + QCOMPARE(event.state, s);\ + }\ + class EventHandler : public QQuickPointerHandler { void handlePointerEventImpl(QQuickPointerEvent *event) override @@ -165,7 +183,8 @@ class EventHandler : public QQuickPointerHandler if (item->grabPointer) setExclusiveGrab(point, true); qCDebug(lcPointerTests) << " " << i << ":" << point << "accepted?" << item->acceptPointer << "grabbed?" << (point->exclusiveGrabber() == this); - item->eventList.append(Event(QEvent::Pointer, eventPos(point), point->scenePos())); + item->eventList.append(Event(Event::HandlerDestination, QEvent::Pointer, + static_cast(point->state()), eventPos(point), point->scenePos())); } } }; @@ -187,27 +206,44 @@ private slots: protected: bool eventFilter(QObject *, QEvent *event) { - if (event->type() == QEvent::MouseButtonPress || - event->type() == QEvent::MouseMove || - event->type() == QEvent::MouseButtonRelease) { - QMouseEvent *me = static_cast(event); - filteredEventList.append(Event(me->type(), me->pos(), me->globalPos())); + Qt::TouchPointState tpState; + switch (event->type()) { + case QEvent::MouseButtonPress: + tpState = Qt::TouchPointPressed; + break; + case QEvent::MouseMove: + tpState = Qt::TouchPointMoved; + break; + case QEvent::MouseButtonRelease: + tpState = Qt::TouchPointReleased; + break; + default: + // So far we aren't recording filtered touch events here - they would be quite numerous in some cases + return false; } + QMouseEvent *me = static_cast(event); + filteredEventList.append(Event(Event::FilterDestination, event->type(), tpState, me->pos(), me->globalPos())); return false; } private: - QQuickView *createView(); + void createView(QScopedPointer &window, const char *fileName); QTouchDevice *touchDevice; QList filteredEventList; }; -QQuickView *tst_PointerHandlers::createView() +void tst_PointerHandlers::createView(QScopedPointer &window, const char *fileName) { - QQuickView *window = new QQuickView(0); - window->setGeometry(0,0,240,320); + window.reset(new QQuickView); +// window->setGeometry(0,0,240,320); + window->setSource(testFileUrl(fileName)); + QTRY_COMPARE(window->status(), QQuickView::Ready); + QQuickViewTestUtil::centerOnScreen(window.data()); + QQuickViewTestUtil::moveMouseAway(window.data()); - return window; + window->show(); + QVERIFY(QTest::qWaitForWindowActive(window.data())); + QVERIFY(window->rootObject() != 0); } void tst_PointerHandlers::initTestCase() @@ -222,14 +258,9 @@ void tst_PointerHandlers::initTestCase() void tst_PointerHandlers::touchEventDelivery() { - QQuickView *window = createView(); - - window->setSource(testFileUrl("singleitem.qml")); - window->show(); - QVERIFY(QTest::qWaitForWindowExposed(window)); - window->requestActivate(); - QVERIFY(QTest::qWaitForWindowActive(window)); - QVERIFY(window->rootObject() != 0); + QScopedPointer windowPtr; + createView(windowPtr, "singleitem.qml"); + QQuickView * window = windowPtr.data(); EventItem *eventItem1 = window->rootObject()->findChild("eventItem1"); QVERIFY(eventItem1); @@ -239,18 +270,18 @@ void tst_PointerHandlers::touchEventDelivery() QTest::touchEvent(window, touchDevice).press(0, p1, window); QQuickTouchUtils::flush(window); QTRY_COMPARE(eventItem1->eventList.size(), 3); - QCOMPARE(eventItem1->eventList.at(0).type, QEvent::Pointer); - QCOMPARE(eventItem1->eventList.at(1).type, QEvent::TouchBegin); - QCOMPARE(eventItem1->eventList.at(2).type, QEvent::MouseButtonPress); + QCOMPARE_EVENT(0, Event::HandlerDestination, Qt::TouchPointPressed, QEvent::Pointer); + QCOMPARE_EVENT(1, Event::TouchDestination, Qt::TouchPointPressed, QEvent::TouchBegin); + QCOMPARE_EVENT(2, Event::MouseDestination, Qt::TouchPointPressed, QEvent::MouseButtonPress); p1 += QPoint(10, 0); QTest::touchEvent(window, touchDevice).move(0, p1, window); QQuickTouchUtils::flush(window); QCOMPARE(eventItem1->eventList.size(), 4); - QCOMPARE(eventItem1->eventList.at(3).type, QEvent::Pointer); + QCOMPARE_EVENT(3, Event::HandlerDestination, Qt::TouchPointMoved, QEvent::Pointer); QTest::touchEvent(window, touchDevice).release(0, p1, window); QQuickTouchUtils::flush(window); QCOMPARE(eventItem1->eventList.size(), 5); - QCOMPARE(eventItem1->eventList.at(4).type, QEvent::Pointer); + QCOMPARE_EVENT(4, Event::HandlerDestination, Qt::TouchPointReleased, QEvent::Pointer); eventItem1->eventList.clear(); // Accept touch @@ -259,21 +290,21 @@ void tst_PointerHandlers::touchEventDelivery() QTest::touchEvent(window, touchDevice).press(0, p1, window); QQuickTouchUtils::flush(window); QCOMPARE(eventItem1->eventList.size(), 2); - QCOMPARE(eventItem1->eventList.at(0).type, QEvent::Pointer); - QCOMPARE(eventItem1->eventList.at(1).type, QEvent::TouchBegin); + QCOMPARE_EVENT(0, Event::HandlerDestination, Qt::TouchPointPressed, QEvent::Pointer); + QCOMPARE_EVENT(1, Event::TouchDestination, Qt::TouchPointPressed, QEvent::TouchBegin); auto pointerEvent = QQuickPointerDevice::touchDevices().at(0)->pointerEvent(); QCOMPARE(pointerEvent->point(0)->exclusiveGrabber(), eventItem1); p1 += QPoint(10, 0); QTest::touchEvent(window, touchDevice).move(0, p1, window); QQuickTouchUtils::flush(window); QCOMPARE(eventItem1->eventList.size(), 4); - QCOMPARE(eventItem1->eventList.at(2).type, QEvent::Pointer); - QCOMPARE(eventItem1->eventList.at(3).type, QEvent::TouchUpdate); + QCOMPARE_EVENT(2, Event::HandlerDestination, Qt::TouchPointMoved, QEvent::Pointer); + QCOMPARE_EVENT(3, Event::TouchDestination, Qt::TouchPointMoved, QEvent::TouchUpdate); QTest::touchEvent(window, touchDevice).release(0, p1, window); QQuickTouchUtils::flush(window); QCOMPARE(eventItem1->eventList.size(), 6); - QCOMPARE(eventItem1->eventList.at(4).type, QEvent::Pointer); - QCOMPARE(eventItem1->eventList.at(5).type, QEvent::TouchEnd); + QCOMPARE_EVENT(4, Event::HandlerDestination, Qt::TouchPointReleased, QEvent::Pointer); + QCOMPARE_EVENT(5, Event::TouchDestination, Qt::TouchPointReleased, QEvent::TouchEnd); eventItem1->eventList.clear(); // wait to avoid getting a double click event @@ -287,9 +318,9 @@ void tst_PointerHandlers::touchEventDelivery() QTest::touchEvent(window, touchDevice).press(0, p1, window); QQuickTouchUtils::flush(window); QCOMPARE(eventItem1->eventList.size(), 3); - QCOMPARE(eventItem1->eventList.at(0).type, QEvent::Pointer); - QCOMPARE(eventItem1->eventList.at(1).type, QEvent::TouchBegin); - QCOMPARE(eventItem1->eventList.at(2).type, QEvent::MouseButtonPress); + QCOMPARE_EVENT(0, Event::HandlerDestination, Qt::TouchPointPressed, QEvent::Pointer); + QCOMPARE_EVENT(1, Event::TouchDestination, Qt::TouchPointPressed, QEvent::TouchBegin); + QCOMPARE_EVENT(2, Event::MouseDestination, Qt::TouchPointPressed, QEvent::MouseButtonPress); QCOMPARE(window->mouseGrabberItem(), eventItem1); QPointF localPos = eventItem1->mapFromScene(p1); @@ -303,16 +334,16 @@ void tst_PointerHandlers::touchEventDelivery() QTest::touchEvent(window, touchDevice).move(0, p1, window); QQuickTouchUtils::flush(window); QCOMPARE(eventItem1->eventList.size(), 6); - QCOMPARE(eventItem1->eventList.at(3).type, QEvent::Pointer); - QCOMPARE(eventItem1->eventList.at(4).type, QEvent::TouchUpdate); - QCOMPARE(eventItem1->eventList.at(5).type, QEvent::MouseMove); + QCOMPARE_EVENT(3, Event::HandlerDestination, Qt::TouchPointMoved, QEvent::Pointer); + QCOMPARE_EVENT(4, Event::TouchDestination,Qt::TouchPointMoved, QEvent::TouchUpdate); + QCOMPARE_EVENT(5, Event::MouseDestination, Qt::TouchPointMoved, QEvent::MouseMove); QTest::touchEvent(window, touchDevice).release(0, p1, window); QQuickTouchUtils::flush(window); QCOMPARE(eventItem1->eventList.size(), 10); - QCOMPARE(eventItem1->eventList.at(6).type, QEvent::Pointer); - QCOMPARE(eventItem1->eventList.at(7).type, QEvent::TouchEnd); - QCOMPARE(eventItem1->eventList.at(8).type, QEvent::MouseButtonRelease); - QCOMPARE(eventItem1->eventList.at(9).type, QEvent::UngrabMouse); + QCOMPARE_EVENT(6, Event::HandlerDestination, Qt::TouchPointReleased, QEvent::Pointer); + QCOMPARE_EVENT(7, Event::TouchDestination, Qt::TouchPointReleased, QEvent::TouchEnd); + QCOMPARE_EVENT(8, Event::MouseDestination, Qt::TouchPointReleased, QEvent::MouseButtonRelease); + QCOMPARE_EVENT(9, Event::MouseDestination, Qt::TouchPointReleased, QEvent::UngrabMouse); eventItem1->eventList.clear(); // wait to avoid getting a double click event @@ -326,9 +357,9 @@ void tst_PointerHandlers::touchEventDelivery() QTest::touchEvent(window, touchDevice).press(0, p1, window); QQuickTouchUtils::flush(window); QCOMPARE(eventItem1->eventList.size(), 3); - QCOMPARE(eventItem1->eventList.at(0).type, QEvent::Pointer); - QCOMPARE(eventItem1->eventList.at(1).type, QEvent::TouchBegin); - QCOMPARE(eventItem1->eventList.at(2).type, QEvent::MouseButtonPress); + QCOMPARE_EVENT(0, Event::HandlerDestination, Qt::TouchPointPressed, QEvent::Pointer); + QCOMPARE_EVENT(1, Event::TouchDestination, Qt::TouchPointPressed, QEvent::TouchBegin); + QCOMPARE_EVENT(2, Event::MouseDestination, Qt::TouchPointPressed, QEvent::MouseButtonPress); QCOMPARE(pointerEvent->point(0)->exclusiveGrabber(), nullptr); p1 += QPoint(10, 0); QTest::touchEvent(window, touchDevice).move(0, p1, window); @@ -349,19 +380,19 @@ void tst_PointerHandlers::touchEventDelivery() QTest::touchEvent(window, touchDevice).press(0, p1, window); QQuickTouchUtils::flush(window); QCOMPARE(eventItem1->eventList.size(), 2); - QCOMPARE(eventItem1->eventList.at(0).type, QEvent::Pointer); - QCOMPARE(eventItem1->eventList.at(1).type, QEvent::TouchBegin); + QCOMPARE_EVENT(0, Event::HandlerDestination, Qt::TouchPointPressed, QEvent::Pointer); + QCOMPARE_EVENT(1, Event::TouchDestination, Qt::TouchPointPressed, QEvent::TouchBegin); p1 += QPoint(10, 0); QTest::touchEvent(window, touchDevice).move(0, p1, window); QQuickTouchUtils::flush(window); QCOMPARE(eventItem1->eventList.size(), 4); - QCOMPARE(eventItem1->eventList.at(2).type, QEvent::Pointer); - QCOMPARE(eventItem1->eventList.at(3).type, QEvent::TouchUpdate); + QCOMPARE_EVENT(2, Event::HandlerDestination, Qt::TouchPointMoved, QEvent::Pointer); + QCOMPARE_EVENT(3, Event::TouchDestination, Qt::TouchPointMoved, QEvent::TouchUpdate); QTest::touchEvent(window, touchDevice).release(0, p1, window); QQuickTouchUtils::flush(window); QCOMPARE(eventItem1->eventList.size(), 6); - QCOMPARE(eventItem1->eventList.at(4).type, QEvent::Pointer); - QCOMPARE(eventItem1->eventList.at(5).type, QEvent::TouchEnd); + QCOMPARE_EVENT(4, Event::HandlerDestination, Qt::TouchPointReleased, QEvent::Pointer); + QCOMPARE_EVENT(5, Event::TouchDestination, Qt::TouchPointReleased, QEvent::TouchEnd); eventItem1->eventList.clear(); // Accept pointer events @@ -371,31 +402,24 @@ void tst_PointerHandlers::touchEventDelivery() QTest::touchEvent(window, touchDevice).press(0, p1, window); QQuickTouchUtils::flush(window); QCOMPARE(eventItem1->eventList.size(), 1); - QCOMPARE(eventItem1->eventList.at(0).type, QEvent::Pointer); + QCOMPARE_EVENT(0, Event::HandlerDestination, Qt::TouchPointPressed, QEvent::Pointer); p1 += QPoint(10, 0); QTest::touchEvent(window, touchDevice).move(0, p1, window); QQuickTouchUtils::flush(window); QCOMPARE(eventItem1->eventList.size(), 2); - QCOMPARE(eventItem1->eventList.at(1).type, QEvent::Pointer); + QCOMPARE_EVENT(1, Event::HandlerDestination, Qt::TouchPointMoved, QEvent::Pointer); QTest::touchEvent(window, touchDevice).release(0, p1, window); QQuickTouchUtils::flush(window); QCOMPARE(eventItem1->eventList.size(), 3); - QCOMPARE(eventItem1->eventList.at(2).type, QEvent::Pointer); + QCOMPARE_EVENT(2, Event::HandlerDestination, Qt::TouchPointReleased, QEvent::Pointer); eventItem1->eventList.clear(); - - delete window; } void tst_PointerHandlers::mouseEventDelivery() { - QQuickView *window = createView(); - - window->setSource(testFileUrl("singleitem.qml")); - window->show(); - QVERIFY(QTest::qWaitForWindowExposed(window)); - window->requestActivate(); - QVERIFY(QTest::qWaitForWindowActive(window)); - QVERIFY(window->rootObject() != 0); + QScopedPointer windowPtr; + createView(windowPtr, "singleitem.qml"); + QQuickView * window = windowPtr.data(); EventItem *eventItem1 = window->rootObject()->findChild("eventItem1"); QVERIFY(eventItem1); @@ -421,8 +445,8 @@ void tst_PointerHandlers::mouseEventDelivery() p1 = QPoint(20, 20); QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, p1); QCOMPARE(eventItem1->eventList.size(), 2); - QCOMPARE(eventItem1->eventList.at(0).type, QEvent::Pointer); - QCOMPARE(eventItem1->eventList.at(1).type, QEvent::MouseButtonPress); + QCOMPARE_EVENT(0, Event::HandlerDestination, Qt::TouchPointPressed, QEvent::Pointer); + QCOMPARE_EVENT(1, Event::MouseDestination, Qt::TouchPointPressed, QEvent::MouseButtonPress); QCOMPARE(window->mouseGrabberItem(), eventItem1); QPointF localPos = eventItem1->mapFromScene(p1); @@ -435,11 +459,11 @@ void tst_PointerHandlers::mouseEventDelivery() p1 += QPoint(10, 0); QTest::mouseMove(window, p1); QCOMPARE(eventItem1->eventList.size(), 3); - QCOMPARE(eventItem1->eventList.at(2).type, QEvent::MouseMove); + QCOMPARE_EVENT(2, Event::MouseDestination, Qt::TouchPointMoved, QEvent::MouseMove); QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p1); QCOMPARE(eventItem1->eventList.size(), 5); - QCOMPARE(eventItem1->eventList.at(3).type, QEvent::MouseButtonRelease); - QCOMPARE(eventItem1->eventList.at(4).type, QEvent::UngrabMouse); + QCOMPARE_EVENT(3, Event::MouseDestination, Qt::TouchPointReleased, QEvent::MouseButtonRelease); + QCOMPARE_EVENT(4, Event::MouseDestination, Qt::TouchPointReleased, QEvent::UngrabMouse); eventItem1->eventList.clear(); // wait to avoid getting a double click event @@ -452,17 +476,15 @@ void tst_PointerHandlers::mouseEventDelivery() p1 = QPoint(20, 20); QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, p1); QTRY_COMPARE(eventItem1->eventList.size(), 1); - QCOMPARE(eventItem1->eventList.at(0).type, QEvent::Pointer); + QCOMPARE_EVENT(0, Event::HandlerDestination, Qt::TouchPointPressed, QEvent::Pointer); p1 += QPoint(10, 0); QTest::mouseMove(window, p1); QCOMPARE(eventItem1->eventList.size(), 2); - QCOMPARE(eventItem1->eventList.at(1).type, QEvent::Pointer); + QCOMPARE_EVENT(1, Event::HandlerDestination, Qt::TouchPointMoved, QEvent::Pointer); QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p1); QCOMPARE(eventItem1->eventList.size(), 3); - QCOMPARE(eventItem1->eventList.at(2).type, QEvent::Pointer); + QCOMPARE_EVENT(2, Event::HandlerDestination, Qt::TouchPointReleased, QEvent::Pointer); eventItem1->eventList.clear(); - - delete window; } QTEST_MAIN(tst_PointerHandlers) -- cgit v1.2.3 From 80e5e6976afe4425cc8fd22c010fcf039c5b4b91 Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Fri, 28 Apr 2017 10:38:52 +0200 Subject: tst_flickableinterop: test buttons with all gesturePolicy values MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: If3d9e10bb54fc75a7e72bc6367de3e083611a45f Reviewed-by: Jan Arve Sæther --- .../flickableinterop/data/Slider.qml | 2 +- .../flickableinterop/data/TapHandlerButton.qml | 8 +++- .../data/flickableWithHandlers.qml | 16 +++++-- .../flickableinterop/tst_flickableinterop.cpp | 56 +++++++++++++++++++--- tests/manual/pointer/content/Slider.qml | 2 +- 5 files changed, 71 insertions(+), 13 deletions(-) (limited to 'tests') diff --git a/tests/auto/quick/pointerhandlers/flickableinterop/data/Slider.qml b/tests/auto/quick/pointerhandlers/flickableinterop/data/Slider.qml index 35e7ee2177..d01bcf74ed 100644 --- a/tests/auto/quick/pointerhandlers/flickableinterop/data/Slider.qml +++ b/tests/auto/quick/pointerhandlers/flickableinterop/data/Slider.qml @@ -72,7 +72,7 @@ Item { anchors.horizontalCenterOffset: 1 radius: 5 color: "#4400FFFF" - opacity: dragHandler.active || tapFlash.running ? 1 : 0 + opacity: tap.isPressed || tapFlash.running ? 1 : 0 FlashAnimation on visible { id: tapFlash } diff --git a/tests/auto/quick/pointerhandlers/flickableinterop/data/TapHandlerButton.qml b/tests/auto/quick/pointerhandlers/flickableinterop/data/TapHandlerButton.qml index af9b906861..18a67eb094 100644 --- a/tests/auto/quick/pointerhandlers/flickableinterop/data/TapHandlerButton.qml +++ b/tests/auto/quick/pointerhandlers/flickableinterop/data/TapHandlerButton.qml @@ -95,6 +95,12 @@ Rectangle { x: tap.scenePressPos.x - radius y: tap.scenePressPos.y - radius opacity: 0.25 - Component.onCompleted: parent = root.parent + Component.onCompleted: { + // get on top of all the buttons + var par = root.parent; + while (par.parent) + par = par.parent; + parent = par; + } } } diff --git a/tests/auto/quick/pointerhandlers/flickableinterop/data/flickableWithHandlers.qml b/tests/auto/quick/pointerhandlers/flickableinterop/data/flickableWithHandlers.qml index 7799dd0ec3..833fef0a81 100644 --- a/tests/auto/quick/pointerhandlers/flickableinterop/data/flickableWithHandlers.qml +++ b/tests/auto/quick/pointerhandlers/flickableinterop/data/flickableWithHandlers.qml @@ -66,14 +66,22 @@ Rectangle { Column { spacing: 6 TapHandlerButton { - label: "TapHandler" - objectName: "Button 1" + objectName: "DragThreshold" + label: "DragThreshold" + gesturePolicy: TapHandler.DragThreshold } TapHandlerButton { - label: "TapHandler" - objectName: "Button 2" + objectName: "WithinBounds" + label: "WithinBounds" + gesturePolicy: TapHandler.WithinBounds + } + TapHandlerButton { + objectName: "ReleaseWithinBounds" + label: "ReleaseWithinBounds" + gesturePolicy: TapHandler.ReleaseWithinBounds // the default } } } } } + diff --git a/tests/auto/quick/pointerhandlers/flickableinterop/tst_flickableinterop.cpp b/tests/auto/quick/pointerhandlers/flickableinterop/tst_flickableinterop.cpp index 93b6d27f21..c8fe6052fb 100644 --- a/tests/auto/quick/pointerhandlers/flickableinterop/tst_flickableinterop.cpp +++ b/tests/auto/quick/pointerhandlers/flickableinterop/tst_flickableinterop.cpp @@ -59,9 +59,13 @@ public: private slots: void initTestCase(); + void touchTapButton_data(); void touchTapButton(); + void touchDragFlickableBehindButton_data(); void touchDragFlickableBehindButton(); + void mouseClickButton_data(); void mouseClickButton(); + void mouseDragFlickableBehindButton_data(); void mouseDragFlickableBehindButton(); void touchDragSlider(); void touchDragFlickableBehindSlider(); @@ -94,6 +98,14 @@ void tst_FlickableInterop::initTestCase() QQmlDataTest::initTestCase(); } +void tst_FlickableInterop::touchTapButton_data() +{ + QTest::addColumn("buttonName"); + QTest::newRow("DragThreshold") << QStringLiteral("DragThreshold"); + QTest::newRow("WithinBounds") << QStringLiteral("WithinBounds"); + QTest::newRow("ReleaseWithinBounds") << QStringLiteral("ReleaseWithinBounds"); +} + void tst_FlickableInterop::touchTapButton() { const int dragThreshold = QGuiApplication::styleHints()->startDragDistance(); @@ -101,7 +113,9 @@ void tst_FlickableInterop::touchTapButton() createView(windowPtr, "flickableWithHandlers.qml"); QQuickView * window = windowPtr.data(); - QQuickItem *button = window->rootObject()->findChild("Button 1"); + QFETCH(QString, buttonName); + + QQuickItem *button = window->rootObject()->findChild(buttonName); QVERIFY(button); QSignalSpy tappedSpy(button, SIGNAL(tapped())); @@ -130,6 +144,14 @@ void tst_FlickableInterop::touchTapButton() QCOMPARE(tappedSpy.count(), 2); } +void tst_FlickableInterop::touchDragFlickableBehindButton_data() +{ + QTest::addColumn("buttonName"); + QTest::newRow("DragThreshold") << QStringLiteral("DragThreshold"); + QTest::newRow("WithinBounds") << QStringLiteral("WithinBounds"); + QTest::newRow("ReleaseWithinBounds") << QStringLiteral("ReleaseWithinBounds"); +} + void tst_FlickableInterop::touchDragFlickableBehindButton() { const int dragThreshold = QGuiApplication::styleHints()->startDragDistance(); @@ -137,14 +159,14 @@ void tst_FlickableInterop::touchDragFlickableBehindButton() createView(windowPtr, "flickableWithHandlers.qml"); QQuickView * window = windowPtr.data(); - QQuickItem *button = window->rootObject()->findChild("Button 1"); + QFETCH(QString, buttonName); + + QQuickItem *button = window->rootObject()->findChild(buttonName); QVERIFY(button); QQuickFlickable *flickable = window->rootObject()->findChild(); QVERIFY(flickable); QSignalSpy tappedSpy(button, SIGNAL(tapped())); - // Button is no longer pressed if touchpoint goes beyond dragThreshold, - // because Flickable steals the grab tappedSpy.clear(); QPoint p1 = button->mapToScene(QPointF(20, 20)).toPoint(); QTest::touchEvent(window, touchDevice).press(1, p1, window); @@ -155,6 +177,8 @@ void tst_FlickableInterop::touchDragFlickableBehindButton() QQuickTouchUtils::flush(window); QVERIFY(button->property("pressed").toBool()); int i = 0; + // Start dragging; eventually when the touchpoint goes beyond dragThreshold, + // Button is no longer pressed because Flickable steals the grab for (; i < 100 && !flickable->isMoving(); ++i) { p1 += QPoint(1, 0); QTest::touchEvent(window, touchDevice).move(1, p1, window); @@ -170,6 +194,14 @@ void tst_FlickableInterop::touchDragFlickableBehindButton() QCOMPARE(tappedSpy.count(), 0); } +void tst_FlickableInterop::mouseClickButton_data() +{ + QTest::addColumn("buttonName"); + QTest::newRow("DragThreshold") << QStringLiteral("DragThreshold"); + QTest::newRow("WithinBounds") << QStringLiteral("WithinBounds"); + QTest::newRow("ReleaseWithinBounds") << QStringLiteral("ReleaseWithinBounds"); +} + void tst_FlickableInterop::mouseClickButton() { const int dragThreshold = QGuiApplication::styleHints()->startDragDistance(); @@ -177,7 +209,9 @@ void tst_FlickableInterop::mouseClickButton() createView(windowPtr, "flickableWithHandlers.qml"); QQuickView * window = windowPtr.data(); - QQuickItem *button = window->rootObject()->findChild("Button 1"); + QFETCH(QString, buttonName); + + QQuickItem *button = window->rootObject()->findChild(buttonName); QVERIFY(button); QSignalSpy tappedSpy(button, SIGNAL(tapped())); @@ -201,6 +235,14 @@ void tst_FlickableInterop::mouseClickButton() QCOMPARE(tappedSpy.count(), 2); } +void tst_FlickableInterop::mouseDragFlickableBehindButton_data() +{ + QTest::addColumn("buttonName"); + QTest::newRow("DragThreshold") << QStringLiteral("DragThreshold"); + QTest::newRow("WithinBounds") << QStringLiteral("WithinBounds"); + QTest::newRow("ReleaseWithinBounds") << QStringLiteral("ReleaseWithinBounds"); +} + void tst_FlickableInterop::mouseDragFlickableBehindButton() { const int dragThreshold = QGuiApplication::styleHints()->startDragDistance(); @@ -208,7 +250,9 @@ void tst_FlickableInterop::mouseDragFlickableBehindButton() createView(windowPtr, "flickableWithHandlers.qml"); QQuickView * window = windowPtr.data(); - QQuickItem *button = window->rootObject()->findChild("Button 1"); + QFETCH(QString, buttonName); + + QQuickItem *button = window->rootObject()->findChild(buttonName); QVERIFY(button); QQuickFlickable *flickable = window->rootObject()->findChild(); QVERIFY(flickable); diff --git a/tests/manual/pointer/content/Slider.qml b/tests/manual/pointer/content/Slider.qml index ecf45c02f3..809e4c5f1c 100644 --- a/tests/manual/pointer/content/Slider.qml +++ b/tests/manual/pointer/content/Slider.qml @@ -82,7 +82,7 @@ Item { anchors.horizontalCenterOffset: 1 radius: 5 color: "#4400FFFF" - opacity: dragHandler.active || tapFlash.running ? 1 : 0 + opacity: tap.isPressed || tapFlash.running ? 1 : 0 FlashAnimation on visible { id: tapFlash } -- cgit v1.2.3 From a09b2f6fcd087e849f4e766a03c1ab47ae49d0d7 Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Fri, 19 May 2017 08:23:31 +0200 Subject: tst_qquickpointerhandler: Remove unused includes; better debug output Change-Id: I1e0539fe24e19ca15641fa4007488b33c24ab8ba Reviewed-by: Frederik Gladhorn --- .../tst_qquickpointerhandler.cpp | 38 +++++++++++----------- 1 file changed, 19 insertions(+), 19 deletions(-) (limited to 'tests') diff --git a/tests/auto/quick/pointerhandlers/qquickpointerhandler/tst_qquickpointerhandler.cpp b/tests/auto/quick/pointerhandlers/qquickpointerhandler/tst_qquickpointerhandler.cpp index f648fb33f6..ebc5143073 100644 --- a/tests/auto/quick/pointerhandlers/qquickpointerhandler/tst_qquickpointerhandler.cpp +++ b/tests/auto/quick/pointerhandlers/qquickpointerhandler/tst_qquickpointerhandler.cpp @@ -26,38 +26,30 @@ ** ****************************************************************************/ - #include +#include #include - -#include -#include -#include -#include -#include -#include #include -#include - -#include - -#include -#include +#include +#include #include "../../../shared/util.h" #include "../../shared/viewtestutil.h" Q_LOGGING_CATEGORY(lcPointerTests, "qt.quick.pointer.tests") -struct Event +class Event { + Q_GADGET +public: enum Destination { FilterDestination, MouseDestination, TouchDestination, HandlerDestination }; + Q_ENUM(Destination) Event(Destination d, QEvent::Type t, Qt::TouchPointState s, QPointF item, QPointF scene) : destination(d), type(t), state(s), posWrtItem(item), posWrtScene(scene) @@ -66,17 +58,25 @@ struct Event Destination destination; QEvent::Type type; Qt::TouchPointState state; - QPointF posWrtItem; QPointF posWrtScene; - }; #ifndef QT_NO_DEBUG_STREAM -QDebug operator<<(QDebug dbg, const struct Event &event) { +QDebug operator<<(QDebug dbg, const class Event &event) { QDebugStateSaver saver(dbg); dbg.nospace(); - dbg << "Event(" << event.type << " @" << event.posWrtScene << ")"; + dbg << "Event("; + QtDebugUtils::formatQEnum(dbg, event.destination); + dbg << ' '; + QtDebugUtils::formatQEnum(dbg, event.type); + dbg << ' '; + QtDebugUtils::formatQEnum(dbg, event.state); + dbg << " @ "; + QtDebugUtils::formatQPoint(dbg, event.posWrtItem); + dbg << " S "; + QtDebugUtils::formatQPoint(dbg, event.posWrtScene); + dbg << ')'; return dbg; } #endif -- cgit v1.2.3 From 057fc4b5b037284ffe299a28725fcf59c7ac066f Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Thu, 27 Apr 2017 11:11:49 +0200 Subject: FakeFlickable: animate returnToBounds() when flicking is done It looks much nicer than just jerking back into position. We still don't have "resistance" to dragging past the bounds, though. Change-Id: I60f6f58fe87638fd17144ea6640bae673a3b633d Reviewed-by: Shawn Rutledge --- tests/manual/pointer/content/FakeFlickable.qml | 49 +++++++++++++++++++++----- 1 file changed, 41 insertions(+), 8 deletions(-) (limited to 'tests') diff --git a/tests/manual/pointer/content/FakeFlickable.qml b/tests/manual/pointer/content/FakeFlickable.qml index bfae653503..801b6b9f31 100644 --- a/tests/manual/pointer/content/FakeFlickable.qml +++ b/tests/manual/pointer/content/FakeFlickable.qml @@ -62,14 +62,23 @@ Item { property real ylimit: root.height - __contentItem.height function returnToBounds() { - if (x > 0) - x = 0 - else if (x < xlimit) - x = xlimit - if (y > 0) - y = 0 - else if (y < ylimit) - y = ylimit + var startAnim = false + if (x > 0) { + returnToBoundsAnim.x = 0 + startAnim = true + } else if (x < xlimit) { + returnToBoundsAnim.x = xlimit + startAnim = true + } + if (y > 0) { + returnToBoundsAnim.y = 0 + startAnim = true + } else if (y < ylimit) { + returnToBoundsAnim.y = ylimit + startAnim = true + } + if (startAnim) + returnToBoundsAnim.start() } DragHandler { @@ -85,5 +94,29 @@ Item { root.flickEnded() } } + ParallelAnimation { + id: returnToBoundsAnim + property Item target: __contentItem + property int duration: 200 + property real x: 0 + property real y: 0 + + NumberAnimation { + id: xAnim + target: returnToBoundsAnim.target + property: "x" + to: returnToBoundsAnim.x + duration: returnToBoundsAnim.duration + easing.type: Easing.OutQuad + } + NumberAnimation { + id: yAnim + target: returnToBoundsAnim.target + property: "y" + to: returnToBoundsAnim.y + duration: returnToBoundsAnim.duration + easing.type: Easing.OutQuad + } + } } } -- cgit v1.2.3 From 5d4f488bf30f5650051d6cc226a75dbd17cd9a70 Mon Sep 17 00:00:00 2001 From: Jan Arve Saether Date: Fri, 24 Feb 2017 16:42:47 +0100 Subject: Move properties into grouped "point" property Change-Id: I80000110a2e0ca69210322a0fcc587d86158358e Reviewed-by: Shawn Rutledge --- .../qquicktaphandler/data/Button.qml | 4 +-- tests/manual/pointer/content/FakeFlickable.qml | 2 +- tests/manual/pointer/content/ScrollBar.qml | 4 +-- tests/manual/pointer/fakeFlickable.qml | 2 +- tests/manual/pointer/flingAnimation.qml | 2 +- tests/manual/pointer/photosurface.qml | 2 +- tests/manual/pointer/pinchDragFlingMPTA.qml | 2 +- .../pointer/singlePointHandlerProperties.qml | 37 +++++++++++----------- tests/manual/pointer/tapHandler.qml | 24 +++++++------- 9 files changed, 41 insertions(+), 38 deletions(-) (limited to 'tests') diff --git a/tests/auto/quick/pointerhandlers/qquicktaphandler/data/Button.qml b/tests/auto/quick/pointerhandlers/qquicktaphandler/data/Button.qml index ead86e142b..6203a6769d 100644 --- a/tests/auto/quick/pointerhandlers/qquicktaphandler/data/Button.qml +++ b/tests/auto/quick/pointerhandlers/qquicktaphandler/data/Button.qml @@ -91,8 +91,8 @@ Rectangle { color: "transparent" width: radius * 2 height: radius * 2 - x: tap.scenePressPos.x - radius - y: tap.scenePressPos.y - radius + x: tap.point.scenePressPosition.x - radius + y: tap.point.scenePressPosition.y - radius opacity: 0.25 Component.onCompleted: parent = root.parent } diff --git a/tests/manual/pointer/content/FakeFlickable.qml b/tests/manual/pointer/content/FakeFlickable.qml index 801b6b9f31..55dafef82e 100644 --- a/tests/manual/pointer/content/FakeFlickable.qml +++ b/tests/manual/pointer/content/FakeFlickable.qml @@ -83,7 +83,7 @@ Item { DragHandler { id: dragHandler - onActiveChanged: if (!active) anim.restart(velocity) + onActiveChanged: if (!active) anim.restart(point.velocity) } MomentumAnimation { id: anim diff --git a/tests/manual/pointer/content/ScrollBar.qml b/tests/manual/pointer/content/ScrollBar.qml index 94d5ae47a7..ef18ceb98f 100644 --- a/tests/manual/pointer/content/ScrollBar.qml +++ b/tests/manual/pointer/content/ScrollBar.qml @@ -71,9 +71,9 @@ Rectangle { id: tap onTapped: { if (knob.state === "horizontal") - knob.x = pos.x - knob.width / 2 + knob.x = position.x - knob.width / 2 else if (knob.state === "vertical") - knob.y = pos.y - knob.height / 2 + knob.y = position.y - knob.height / 2 } } diff --git a/tests/manual/pointer/fakeFlickable.qml b/tests/manual/pointer/fakeFlickable.qml index 22b23a00c8..0c6dbe4558 100644 --- a/tests/manual/pointer/fakeFlickable.qml +++ b/tests/manual/pointer/fakeFlickable.qml @@ -75,7 +75,7 @@ Rectangle { onFlickStarted: console.log("flick started with velocity " + velocity) - onFlickEnded: console.log("flick ended") + onFlickEnded: console.log("flick ended with velocity " + velocity) Component.onCompleted: { var request = new XMLHttpRequest() diff --git a/tests/manual/pointer/flingAnimation.qml b/tests/manual/pointer/flingAnimation.qml index c8722fabb1..d868fcc498 100644 --- a/tests/manual/pointer/flingAnimation.qml +++ b/tests/manual/pointer/flingAnimation.qml @@ -70,7 +70,7 @@ Rectangle { objectName: "dragHandler" + index onActiveChanged: { if (!active) - anim.restart(velocity) + anim.restart(point.velocity) } } Rectangle { diff --git a/tests/manual/pointer/photosurface.qml b/tests/manual/pointer/photosurface.qml index 6601909a37..a2e8b2aede 100644 --- a/tests/manual/pointer/photosurface.qml +++ b/tests/manual/pointer/photosurface.qml @@ -110,7 +110,7 @@ Rectangle { id: dragHandler onActiveChanged: { if (!active) - anim.restart(velocity) + anim.restart(point.velocity) } } diff --git a/tests/manual/pointer/pinchDragFlingMPTA.qml b/tests/manual/pointer/pinchDragFlingMPTA.qml index 25be48bb42..6446a17873 100644 --- a/tests/manual/pointer/pinchDragFlingMPTA.qml +++ b/tests/manual/pointer/pinchDragFlingMPTA.qml @@ -85,7 +85,7 @@ Rectangle { objectName: "DragHandler" target: container acceptedModifiers: Qt.MetaModifier - onActiveChanged: if (!active) fling.restart(velocity) + onActiveChanged: if (!active) fling.restart(point.velocity) } } MomentumAnimation { id: fling; target: container } diff --git a/tests/manual/pointer/singlePointHandlerProperties.qml b/tests/manual/pointer/singlePointHandlerProperties.qml index f5a938e401..f91094ee9e 100644 --- a/tests/manual/pointer/singlePointHandlerProperties.qml +++ b/tests/manual/pointer/singlePointHandlerProperties.qml @@ -49,11 +49,11 @@ Rectangle { Item { id: crosshairs - x: dragHandler.pos.x - width / 2 - y: dragHandler.pos.y - height / 2 + x: dragHandler.point.position.x - width / 2 + y: dragHandler.point.position.y - height / 2 width: parent.width / 2; height: parent.height / 2 visible: dragHandler.active - rotation: dragHandler.rotation + rotation: dragHandler.point.rotation Rectangle { color: "goldenrod" @@ -69,7 +69,7 @@ Rectangle { } Rectangle { color: "goldenrod" - width: Math.max(2, 50 * dragHandler.pressure) + width: Math.max(2, 50 * dragHandler.point.pressure) height: width radius: width / 2 anchors.centerIn: parent @@ -82,8 +82,8 @@ Rectangle { implicitHeight: label.implicitHeight Text { id: label - text: 'id: ' + dragHandler.pointId.toString(16) + " uid: " + dragHandler.uniquePointId.numericId + - '\npos: (' + dragHandler.pos.x.toFixed(2) + ', ' + dragHandler.pos.y.toFixed(2) + ')' + text: 'id: ' + dragHandler.point.id.toString(16) + " uid: " + dragHandler.point.uniqueId.numericId + + '\npos: (' + dragHandler.point.position.x.toFixed(2) + ', ' + dragHandler.point.position.y.toFixed(2) + ')' } } } @@ -91,8 +91,8 @@ Rectangle { color: "transparent" border.color: "white" antialiasing: true - width: dragHandler.ellipseDiameters.width - height: dragHandler.ellipseDiameters.height + width: dragHandler.point.ellipseDiameters.width + height: dragHandler.point.ellipseDiameters.height radius: Math.min(width / 2, height / 2) anchors.centerIn: parent } @@ -100,11 +100,11 @@ Rectangle { Rectangle { id: velocityVector visible: width > 0 - width: dragHandler.velocity.length() * 100 + width: dragHandler.point.velocity.length() * 100 height: 2 - x: dragHandler.pos.x - y: dragHandler.pos.y - rotation: Math.atan2(dragHandler.velocity.y, dragHandler.velocity.x) * 180 / Math.PI + x: dragHandler.point.position.x + y: dragHandler.point.position.y + rotation: Math.atan2(dragHandler.point.velocity.y, dragHandler.point.velocity.x) * 180 / Math.PI transformOrigin: Item.BottomLeft antialiasing: true @@ -150,13 +150,14 @@ Rectangle { DragHandler { id: dragHandler target: null - onGrabChanged: if (active) { - console.log("grabbed " + point.pointId + " @ " + sceneGrabPos) - grabbingLocationIndicator.createObject(root, {"x": sceneGrabPos.x, "y": sceneGrabPos.y - 16}) + onGrabChanged: if (active) { // 'point' is an implicit parameter referencing to a QQuickEventPoint instance + console.log("grabbed " + point.pointId + " @ " + point.sceneGrabPos) + grabbingLocationIndicator.createObject(root, {"x": point.sceneGrabPos.x, "y": point.sceneGrabPos.y - 16}) } - onPressedButtonsChanged: { - if (pressedButtons) - mouseButtonIndicator.createObject(root, {"x": pressPos.x - 44, "y": pressPos.y - 64, "buttons": pressedButtons}) + onPointChanged: { + // Here, 'point' is referring to the property of the DragHandler + if (point.pressedButtons) + mouseButtonIndicator.createObject(root, {"x": point.pressPosition.x - 44, "y": point.pressPosition.y - 64, "buttons": point.pressedButtons}) } } } diff --git a/tests/manual/pointer/tapHandler.qml b/tests/manual/pointer/tapHandler.qml index 06070a02ff..5dac99a899 100644 --- a/tests/manual/pointer/tapHandler.qml +++ b/tests/manual/pointer/tapHandler.qml @@ -60,17 +60,13 @@ Item { gesturePolicy: (policyDragThresholdCB.checked ? TapHandler.DragThreshold : policyWithinBoundsCB.checked ? TapHandler.WithinBounds : TapHandler.ReleaseWithinBounds) - onPressedButtonsChanged: switch (pressedButtons) { - case Qt.MiddleButton: borderBlink.blinkColor = "orange"; break; - case Qt.RightButton: borderBlink.blinkColor = "magenta"; break; - default: borderBlink.blinkColor = "green"; break; - } + onCanceled: { - console.log("canceled @ " + pos) + console.log("canceled @ " + point.position) borderBlink.blinkColor = "red" borderBlink.start() } - onTapped: { + onTapped: { // 'point' is an implicit parameter referencing to a QQuickEventPoint instance console.log("tapped @ " + point.pos + " button(s) " + point.event.button + " tapCount " + tapCount) if (tapCount > 1) { tapCountLabel.text = tapCount @@ -80,7 +76,7 @@ Item { } } onLongPressed: longPressFeedback.createObject(rect, - {"x": pos.x, "y": pos.y, + {"x": point.position.x, "y": point.position.y, "text": Math.round(handler.timeHeld).toFixed(3) + " sec", "color": borderBlink.blinkColor}) } @@ -121,8 +117,8 @@ Item { color: "transparent" width: radius * 2 height: radius * 2 - x: handler.pressPos.x - radius - y: handler.pressPos.y - radius + x: handler.point.pressPosition.x - radius + y: handler.point.pressPosition.y - radius opacity: 0.25 } @@ -133,7 +129,13 @@ Item { SequentialAnimation { id: borderBlink - property color blinkColor: "blue" + property color blinkColor: (function(pbtns) { + switch (pbtns) { + case Qt.MiddleButton: return "orange"; + case Qt.RightButton: return "magenta"; + default: return "green"; + } + })(handler.point.pressedButtons) loops: 3 ScriptAction { script: rect.border.color = borderBlink.blinkColor } PauseAnimation { duration: 100 } -- cgit v1.2.3 From 69652f2945f0e8c74471f3486239c95506867510 Mon Sep 17 00:00:00 2001 From: Jan Arve Saether Date: Tue, 23 May 2017 14:22:54 +0200 Subject: Fix autotests to run with the new API 5d4f488bf30f5650051d6cc226a75dbd17cd9a70 changed some APIs, but it forgot to update all autotests. Change-Id: I2a0ca14dbc1a0dddcbad597389c00d5e6f6c8b79 Reviewed-by: Shawn Rutledge --- .../quick/pointerhandlers/flickableinterop/data/TapHandlerButton.qml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'tests') diff --git a/tests/auto/quick/pointerhandlers/flickableinterop/data/TapHandlerButton.qml b/tests/auto/quick/pointerhandlers/flickableinterop/data/TapHandlerButton.qml index 18a67eb094..4aac89402b 100644 --- a/tests/auto/quick/pointerhandlers/flickableinterop/data/TapHandlerButton.qml +++ b/tests/auto/quick/pointerhandlers/flickableinterop/data/TapHandlerButton.qml @@ -92,8 +92,8 @@ Rectangle { color: "transparent" width: radius * 2 height: radius * 2 - x: tap.scenePressPos.x - radius - y: tap.scenePressPos.y - radius + x: tap.point.scenePressPosition.x - radius + y: tap.point.scenePressPosition.y - radius opacity: 0.25 Component.onCompleted: { // get on top of all the buttons -- cgit v1.2.3 From b10e30705400a7967fd8c4215f201ce9586d9ecc Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Wed, 26 Apr 2017 13:45:36 +0200 Subject: tst_qquickpointerhandler: Test grab changes Now an Event could represent a QEvent, a PointerEvent, or a call to onGrabChanged, so we can test the sequence more thoroughly. Change-Id: Ib935cda8dfc87c37d917989423615688dc9c260c Reviewed-by: Shawn Rutledge --- .../tst_qquickpointerhandler.cpp | 151 ++++++++++++--------- 1 file changed, 90 insertions(+), 61 deletions(-) (limited to 'tests') diff --git a/tests/auto/quick/pointerhandlers/qquickpointerhandler/tst_qquickpointerhandler.cpp b/tests/auto/quick/pointerhandlers/qquickpointerhandler/tst_qquickpointerhandler.cpp index ebc5143073..1f3e67d5c0 100644 --- a/tests/auto/quick/pointerhandlers/qquickpointerhandler/tst_qquickpointerhandler.cpp +++ b/tests/auto/quick/pointerhandlers/qquickpointerhandler/tst_qquickpointerhandler.cpp @@ -51,13 +51,14 @@ public: }; Q_ENUM(Destination) - Event(Destination d, QEvent::Type t, Qt::TouchPointState s, QPointF item, QPointF scene) - : destination(d), type(t), state(s), posWrtItem(item), posWrtScene(scene) + Event(Destination d, QEvent::Type t, Qt::TouchPointState s, int grabState, QPointF item, QPointF scene) + : destination(d), type(t), state(s), grabState(grabState), posWrtItem(item), posWrtScene(scene) {} Destination destination; - QEvent::Type type; - Qt::TouchPointState state; + QEvent::Type type; // if this represents a QEvent that was received + Qt::TouchPointState state; // if this represents an event (pointer, touch or mouse) + int grabState; // if this represents an onGrabChanged() notification (QQuickEventPoint::GrabState) QPointF posWrtItem; QPointF posWrtScene; }; @@ -72,6 +73,10 @@ QDebug operator<<(QDebug dbg, const class Event &event) { QtDebugUtils::formatQEnum(dbg, event.type); dbg << ' '; QtDebugUtils::formatQEnum(dbg, event.state); + if (event.grabState) { + dbg << ' '; + QtDebugUtils::formatQEnum(dbg, QQuickEventPoint::GrabState(event.grabState)); + } dbg << " @ "; QtDebugUtils::formatQPoint(dbg, event.posWrtItem); dbg << " S "; @@ -81,6 +86,10 @@ QDebug operator<<(QDebug dbg, const class Event &event) { } #endif +enum { + NoGrab = 0, +}; + class EventItem : public QQuickItem { Q_OBJECT @@ -89,42 +98,46 @@ public: : QQuickItem(parent), acceptPointer(false), grabPointer(false), acceptMouse(false), acceptTouch(false), filterTouch(false) {} + inline int grabState(bool accept, Qt::TouchPointState state) { + return (accept && (state != Qt::TouchPointReleased)) ? (int)QQuickEventPoint::GrabExclusive : (int)NoGrab; + } + void touchEvent(QTouchEvent *event) { qCDebug(lcPointerTests) << event << "will accept?" << acceptTouch; for (const QTouchEvent::TouchPoint &tp : event->touchPoints()) - eventList.append(Event(Event::TouchDestination, event->type(), tp.state(), tp.pos(), tp.scenePos())); + eventList.append(Event(Event::TouchDestination, event->type(), tp.state(), grabState(acceptTouch, tp.state()), tp.pos(), tp.scenePos())); event->setAccepted(acceptTouch); } void mousePressEvent(QMouseEvent *event) { qCDebug(lcPointerTests) << event; - eventList.append(Event(Event::MouseDestination, event->type(), Qt::TouchPointPressed, event->pos(), event->windowPos())); + eventList.append(Event(Event::MouseDestination, event->type(), Qt::TouchPointPressed, grabState(acceptMouse, Qt::TouchPointPressed), event->pos(), event->windowPos())); event->setAccepted(acceptMouse); } void mouseMoveEvent(QMouseEvent *event) { qCDebug(lcPointerTests) << event; - eventList.append(Event(Event::MouseDestination, event->type(), Qt::TouchPointMoved, event->pos(), event->windowPos())); + eventList.append(Event(Event::MouseDestination, event->type(), Qt::TouchPointMoved, grabState(acceptMouse, Qt::TouchPointMoved), event->pos(), event->windowPos())); event->setAccepted(acceptMouse); } void mouseReleaseEvent(QMouseEvent *event) { qCDebug(lcPointerTests) << event; - eventList.append(Event(Event::MouseDestination, event->type(), Qt::TouchPointReleased, event->pos(), event->windowPos())); + eventList.append(Event(Event::MouseDestination, event->type(), Qt::TouchPointReleased, grabState(acceptMouse, Qt::TouchPointReleased), event->pos(), event->windowPos())); event->setAccepted(acceptMouse); } void mouseDoubleClickEvent(QMouseEvent *event) { qCDebug(lcPointerTests) << event; - eventList.append(Event(Event::MouseDestination, event->type(), Qt::TouchPointPressed, event->pos(), event->windowPos())); + eventList.append(Event(Event::MouseDestination, event->type(), Qt::TouchPointPressed, grabState(acceptMouse, Qt::TouchPointPressed), event->pos(), event->windowPos())); event->setAccepted(acceptMouse); } void mouseUngrabEvent() { qCDebug(lcPointerTests); - eventList.append(Event(Event::MouseDestination, QEvent::UngrabMouse, Qt::TouchPointReleased, QPoint(0,0), QPoint(0,0))); + eventList.append(Event(Event::MouseDestination, QEvent::UngrabMouse, Qt::TouchPointReleased, QQuickEventPoint::UngrabExclusive, QPoint(0,0), QPoint(0,0))); } bool event(QEvent *event) @@ -149,7 +162,7 @@ public: event->type() == QEvent::TouchEnd) { QTouchEvent *touch = static_cast(event); for (const QTouchEvent::TouchPoint &tp : touch->touchPoints()) - eventList.append(Event(Event::FilterDestination, event->type(), tp.state(), tp.pos(), tp.scenePos())); + eventList.append(Event(Event::FilterDestination, event->type(), tp.state(), QQuickEventPoint::GrabExclusive, tp.pos(), tp.scenePos())); if (filterTouch) event->accept(); return true; @@ -158,12 +171,13 @@ public: } }; -#define QCOMPARE_EVENT(i, d, s, t) \ +#define QCOMPARE_EVENT(i, d, t, s, g) \ {\ const Event &event = eventItem1->eventList.at(i);\ QCOMPARE(event.destination, d);\ QCOMPARE(event.type, t);\ QCOMPARE(event.state, s);\ + QCOMPARE(event.grabState, g);\ }\ class EventHandler : public QQuickPointerHandler @@ -184,9 +198,18 @@ class EventHandler : public QQuickPointerHandler setExclusiveGrab(point, true); qCDebug(lcPointerTests) << " " << i << ":" << point << "accepted?" << item->acceptPointer << "grabbed?" << (point->exclusiveGrabber() == this); item->eventList.append(Event(Event::HandlerDestination, QEvent::Pointer, - static_cast(point->state()), eventPos(point), point->scenePos())); + static_cast(point->state()), + item->grabPointer ? (int)QQuickEventPoint::GrabExclusive : (int)NoGrab, + eventPos(point), point->scenePos())); } } + + void onGrabChanged(QQuickPointerHandler *, QQuickEventPoint::GrabState stateChange, QQuickEventPoint *point) override + { + EventItem *item = static_cast(target()); + item->eventList.append(Event(Event::HandlerDestination, QEvent::None, + static_cast(point->state()), stateChange, eventPos(point), point->scenePos())); + } }; class tst_PointerHandlers : public QQmlDataTest @@ -222,7 +245,8 @@ protected: return false; } QMouseEvent *me = static_cast(event); - filteredEventList.append(Event(Event::FilterDestination, event->type(), tpState, me->pos(), me->globalPos())); + filteredEventList.append(Event(Event::FilterDestination, event->type(), tpState, + 0, me->pos(), me->globalPos())); return false; } @@ -270,18 +294,18 @@ void tst_PointerHandlers::touchEventDelivery() QTest::touchEvent(window, touchDevice).press(0, p1, window); QQuickTouchUtils::flush(window); QTRY_COMPARE(eventItem1->eventList.size(), 3); - QCOMPARE_EVENT(0, Event::HandlerDestination, Qt::TouchPointPressed, QEvent::Pointer); - QCOMPARE_EVENT(1, Event::TouchDestination, Qt::TouchPointPressed, QEvent::TouchBegin); - QCOMPARE_EVENT(2, Event::MouseDestination, Qt::TouchPointPressed, QEvent::MouseButtonPress); + QCOMPARE_EVENT(0, Event::HandlerDestination, QEvent::Pointer, Qt::TouchPointPressed, NoGrab); + QCOMPARE_EVENT(1, Event::TouchDestination, QEvent::TouchBegin, Qt::TouchPointPressed, NoGrab); + QCOMPARE_EVENT(2, Event::MouseDestination, QEvent::MouseButtonPress, Qt::TouchPointPressed, NoGrab); p1 += QPoint(10, 0); QTest::touchEvent(window, touchDevice).move(0, p1, window); QQuickTouchUtils::flush(window); QCOMPARE(eventItem1->eventList.size(), 4); - QCOMPARE_EVENT(3, Event::HandlerDestination, Qt::TouchPointMoved, QEvent::Pointer); + QCOMPARE_EVENT(3, Event::HandlerDestination, QEvent::Pointer, Qt::TouchPointMoved, NoGrab); QTest::touchEvent(window, touchDevice).release(0, p1, window); QQuickTouchUtils::flush(window); QCOMPARE(eventItem1->eventList.size(), 5); - QCOMPARE_EVENT(4, Event::HandlerDestination, Qt::TouchPointReleased, QEvent::Pointer); + QCOMPARE_EVENT(4, Event::HandlerDestination, QEvent::Pointer, Qt::TouchPointReleased, NoGrab); eventItem1->eventList.clear(); // Accept touch @@ -290,21 +314,21 @@ void tst_PointerHandlers::touchEventDelivery() QTest::touchEvent(window, touchDevice).press(0, p1, window); QQuickTouchUtils::flush(window); QCOMPARE(eventItem1->eventList.size(), 2); - QCOMPARE_EVENT(0, Event::HandlerDestination, Qt::TouchPointPressed, QEvent::Pointer); - QCOMPARE_EVENT(1, Event::TouchDestination, Qt::TouchPointPressed, QEvent::TouchBegin); + QCOMPARE_EVENT(0, Event::HandlerDestination, QEvent::Pointer, Qt::TouchPointPressed, NoGrab); + QCOMPARE_EVENT(1, Event::TouchDestination, QEvent::TouchBegin, Qt::TouchPointPressed, QQuickEventPoint::GrabExclusive); auto pointerEvent = QQuickPointerDevice::touchDevices().at(0)->pointerEvent(); QCOMPARE(pointerEvent->point(0)->exclusiveGrabber(), eventItem1); p1 += QPoint(10, 0); QTest::touchEvent(window, touchDevice).move(0, p1, window); QQuickTouchUtils::flush(window); QCOMPARE(eventItem1->eventList.size(), 4); - QCOMPARE_EVENT(2, Event::HandlerDestination, Qt::TouchPointMoved, QEvent::Pointer); - QCOMPARE_EVENT(3, Event::TouchDestination, Qt::TouchPointMoved, QEvent::TouchUpdate); + QCOMPARE_EVENT(2, Event::HandlerDestination, QEvent::Pointer, Qt::TouchPointMoved, NoGrab); + QCOMPARE_EVENT(3, Event::TouchDestination, QEvent::TouchUpdate, Qt::TouchPointMoved, QQuickEventPoint::GrabExclusive); QTest::touchEvent(window, touchDevice).release(0, p1, window); QQuickTouchUtils::flush(window); QCOMPARE(eventItem1->eventList.size(), 6); - QCOMPARE_EVENT(4, Event::HandlerDestination, Qt::TouchPointReleased, QEvent::Pointer); - QCOMPARE_EVENT(5, Event::TouchDestination, Qt::TouchPointReleased, QEvent::TouchEnd); + QCOMPARE_EVENT(4, Event::HandlerDestination, QEvent::Pointer, Qt::TouchPointReleased, NoGrab); + QCOMPARE_EVENT(5, Event::TouchDestination, QEvent::TouchEnd, Qt::TouchPointReleased, NoGrab); eventItem1->eventList.clear(); // wait to avoid getting a double click event @@ -318,9 +342,9 @@ void tst_PointerHandlers::touchEventDelivery() QTest::touchEvent(window, touchDevice).press(0, p1, window); QQuickTouchUtils::flush(window); QCOMPARE(eventItem1->eventList.size(), 3); - QCOMPARE_EVENT(0, Event::HandlerDestination, Qt::TouchPointPressed, QEvent::Pointer); - QCOMPARE_EVENT(1, Event::TouchDestination, Qt::TouchPointPressed, QEvent::TouchBegin); - QCOMPARE_EVENT(2, Event::MouseDestination, Qt::TouchPointPressed, QEvent::MouseButtonPress); + QCOMPARE_EVENT(0, Event::HandlerDestination, QEvent::Pointer, Qt::TouchPointPressed, NoGrab); + QCOMPARE_EVENT(1, Event::TouchDestination, QEvent::TouchBegin, Qt::TouchPointPressed, NoGrab); + QCOMPARE_EVENT(2, Event::MouseDestination, QEvent::MouseButtonPress, Qt::TouchPointPressed, QQuickEventPoint::GrabExclusive); QCOMPARE(window->mouseGrabberItem(), eventItem1); QPointF localPos = eventItem1->mapFromScene(p1); @@ -334,16 +358,16 @@ void tst_PointerHandlers::touchEventDelivery() QTest::touchEvent(window, touchDevice).move(0, p1, window); QQuickTouchUtils::flush(window); QCOMPARE(eventItem1->eventList.size(), 6); - QCOMPARE_EVENT(3, Event::HandlerDestination, Qt::TouchPointMoved, QEvent::Pointer); - QCOMPARE_EVENT(4, Event::TouchDestination,Qt::TouchPointMoved, QEvent::TouchUpdate); - QCOMPARE_EVENT(5, Event::MouseDestination, Qt::TouchPointMoved, QEvent::MouseMove); + QCOMPARE_EVENT(3, Event::HandlerDestination, QEvent::Pointer, Qt::TouchPointMoved, NoGrab); + QCOMPARE_EVENT(4, Event::TouchDestination, QEvent::TouchUpdate, Qt::TouchPointMoved, NoGrab); + QCOMPARE_EVENT(5, Event::MouseDestination, QEvent::MouseMove, Qt::TouchPointMoved, QQuickEventPoint::GrabExclusive); QTest::touchEvent(window, touchDevice).release(0, p1, window); QQuickTouchUtils::flush(window); QCOMPARE(eventItem1->eventList.size(), 10); - QCOMPARE_EVENT(6, Event::HandlerDestination, Qt::TouchPointReleased, QEvent::Pointer); - QCOMPARE_EVENT(7, Event::TouchDestination, Qt::TouchPointReleased, QEvent::TouchEnd); - QCOMPARE_EVENT(8, Event::MouseDestination, Qt::TouchPointReleased, QEvent::MouseButtonRelease); - QCOMPARE_EVENT(9, Event::MouseDestination, Qt::TouchPointReleased, QEvent::UngrabMouse); + QCOMPARE_EVENT(6, Event::HandlerDestination, QEvent::Pointer, Qt::TouchPointReleased, NoGrab); + QCOMPARE_EVENT(7, Event::TouchDestination, QEvent::TouchEnd, Qt::TouchPointReleased, NoGrab); + QCOMPARE_EVENT(8, Event::MouseDestination, QEvent::MouseButtonRelease, Qt::TouchPointReleased, NoGrab); + QCOMPARE_EVENT(9, Event::MouseDestination, QEvent::UngrabMouse, Qt::TouchPointReleased, QQuickEventPoint::UngrabExclusive); eventItem1->eventList.clear(); // wait to avoid getting a double click event @@ -357,9 +381,9 @@ void tst_PointerHandlers::touchEventDelivery() QTest::touchEvent(window, touchDevice).press(0, p1, window); QQuickTouchUtils::flush(window); QCOMPARE(eventItem1->eventList.size(), 3); - QCOMPARE_EVENT(0, Event::HandlerDestination, Qt::TouchPointPressed, QEvent::Pointer); - QCOMPARE_EVENT(1, Event::TouchDestination, Qt::TouchPointPressed, QEvent::TouchBegin); - QCOMPARE_EVENT(2, Event::MouseDestination, Qt::TouchPointPressed, QEvent::MouseButtonPress); + QCOMPARE_EVENT(0, Event::HandlerDestination, QEvent::Pointer, Qt::TouchPointPressed, NoGrab); + QCOMPARE_EVENT(1, Event::TouchDestination, QEvent::TouchBegin, Qt::TouchPointPressed, NoGrab); + QCOMPARE_EVENT(2, Event::MouseDestination, QEvent::MouseButtonPress, Qt::TouchPointPressed, NoGrab); QCOMPARE(pointerEvent->point(0)->exclusiveGrabber(), nullptr); p1 += QPoint(10, 0); QTest::touchEvent(window, touchDevice).move(0, p1, window); @@ -380,19 +404,19 @@ void tst_PointerHandlers::touchEventDelivery() QTest::touchEvent(window, touchDevice).press(0, p1, window); QQuickTouchUtils::flush(window); QCOMPARE(eventItem1->eventList.size(), 2); - QCOMPARE_EVENT(0, Event::HandlerDestination, Qt::TouchPointPressed, QEvent::Pointer); - QCOMPARE_EVENT(1, Event::TouchDestination, Qt::TouchPointPressed, QEvent::TouchBegin); + QCOMPARE_EVENT(0, Event::HandlerDestination, QEvent::Pointer, Qt::TouchPointPressed, NoGrab); + QCOMPARE_EVENT(1, Event::TouchDestination, QEvent::TouchBegin, Qt::TouchPointPressed, QQuickEventPoint::GrabExclusive); p1 += QPoint(10, 0); QTest::touchEvent(window, touchDevice).move(0, p1, window); QQuickTouchUtils::flush(window); QCOMPARE(eventItem1->eventList.size(), 4); - QCOMPARE_EVENT(2, Event::HandlerDestination, Qt::TouchPointMoved, QEvent::Pointer); - QCOMPARE_EVENT(3, Event::TouchDestination, Qt::TouchPointMoved, QEvent::TouchUpdate); + QCOMPARE_EVENT(2, Event::HandlerDestination, QEvent::Pointer, Qt::TouchPointMoved, NoGrab); + QCOMPARE_EVENT(3, Event::TouchDestination, QEvent::TouchUpdate, Qt::TouchPointMoved, QQuickEventPoint::GrabExclusive); QTest::touchEvent(window, touchDevice).release(0, p1, window); QQuickTouchUtils::flush(window); QCOMPARE(eventItem1->eventList.size(), 6); - QCOMPARE_EVENT(4, Event::HandlerDestination, Qt::TouchPointReleased, QEvent::Pointer); - QCOMPARE_EVENT(5, Event::TouchDestination, Qt::TouchPointReleased, QEvent::TouchEnd); + QCOMPARE_EVENT(4, Event::HandlerDestination, QEvent::Pointer, Qt::TouchPointReleased, NoGrab); + QCOMPARE_EVENT(5, Event::TouchDestination, QEvent::TouchEnd, Qt::TouchPointReleased, NoGrab); eventItem1->eventList.clear(); // Accept pointer events @@ -401,17 +425,20 @@ void tst_PointerHandlers::touchEventDelivery() p1 = QPoint(20, 20); QTest::touchEvent(window, touchDevice).press(0, p1, window); QQuickTouchUtils::flush(window); - QCOMPARE(eventItem1->eventList.size(), 1); - QCOMPARE_EVENT(0, Event::HandlerDestination, Qt::TouchPointPressed, QEvent::Pointer); + QCOMPARE(eventItem1->eventList.size(), 2); + QCOMPARE_EVENT(0, Event::HandlerDestination, QEvent::None, Qt::TouchPointPressed, QQuickEventPoint::GrabExclusive); + QCOMPARE_EVENT(1, Event::HandlerDestination, QEvent::Pointer, Qt::TouchPointPressed, QQuickEventPoint::GrabExclusive); p1 += QPoint(10, 0); QTest::touchEvent(window, touchDevice).move(0, p1, window); QQuickTouchUtils::flush(window); - QCOMPARE(eventItem1->eventList.size(), 2); - QCOMPARE_EVENT(1, Event::HandlerDestination, Qt::TouchPointMoved, QEvent::Pointer); + QCOMPARE(eventItem1->eventList.size(), 3); + QCOMPARE_EVENT(2, Event::HandlerDestination, QEvent::Pointer, Qt::TouchPointMoved, QQuickEventPoint::GrabExclusive); QTest::touchEvent(window, touchDevice).release(0, p1, window); QQuickTouchUtils::flush(window); - QCOMPARE(eventItem1->eventList.size(), 3); - QCOMPARE_EVENT(2, Event::HandlerDestination, Qt::TouchPointReleased, QEvent::Pointer); + QCOMPARE(eventItem1->eventList.size(), 5); + qCDebug(lcPointerTests) << eventItem1->eventList; + QCOMPARE_EVENT(3, Event::HandlerDestination, QEvent::Pointer, Qt::TouchPointReleased, QQuickEventPoint::GrabExclusive); + QCOMPARE_EVENT(4, Event::HandlerDestination, QEvent::None, Qt::TouchPointReleased, QQuickEventPoint::UngrabExclusive); eventItem1->eventList.clear(); } @@ -445,8 +472,8 @@ void tst_PointerHandlers::mouseEventDelivery() p1 = QPoint(20, 20); QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, p1); QCOMPARE(eventItem1->eventList.size(), 2); - QCOMPARE_EVENT(0, Event::HandlerDestination, Qt::TouchPointPressed, QEvent::Pointer); - QCOMPARE_EVENT(1, Event::MouseDestination, Qt::TouchPointPressed, QEvent::MouseButtonPress); + QCOMPARE_EVENT(0, Event::HandlerDestination, QEvent::Pointer, Qt::TouchPointPressed, NoGrab); + QCOMPARE_EVENT(1, Event::MouseDestination, QEvent::MouseButtonPress, Qt::TouchPointPressed, QQuickEventPoint::GrabExclusive); QCOMPARE(window->mouseGrabberItem(), eventItem1); QPointF localPos = eventItem1->mapFromScene(p1); @@ -459,11 +486,11 @@ void tst_PointerHandlers::mouseEventDelivery() p1 += QPoint(10, 0); QTest::mouseMove(window, p1); QCOMPARE(eventItem1->eventList.size(), 3); - QCOMPARE_EVENT(2, Event::MouseDestination, Qt::TouchPointMoved, QEvent::MouseMove); + QCOMPARE_EVENT(2, Event::MouseDestination, QEvent::MouseMove, Qt::TouchPointMoved, QQuickEventPoint::GrabExclusive); QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p1); QCOMPARE(eventItem1->eventList.size(), 5); - QCOMPARE_EVENT(3, Event::MouseDestination, Qt::TouchPointReleased, QEvent::MouseButtonRelease); - QCOMPARE_EVENT(4, Event::MouseDestination, Qt::TouchPointReleased, QEvent::UngrabMouse); + QCOMPARE_EVENT(3, Event::MouseDestination, QEvent::MouseButtonRelease, Qt::TouchPointReleased, NoGrab); + QCOMPARE_EVENT(4, Event::MouseDestination, QEvent::UngrabMouse, Qt::TouchPointReleased, QQuickEventPoint::UngrabExclusive); eventItem1->eventList.clear(); // wait to avoid getting a double click event @@ -475,15 +502,17 @@ void tst_PointerHandlers::mouseEventDelivery() eventItem1->grabPointer = true; p1 = QPoint(20, 20); QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, p1); - QTRY_COMPARE(eventItem1->eventList.size(), 1); - QCOMPARE_EVENT(0, Event::HandlerDestination, Qt::TouchPointPressed, QEvent::Pointer); + QTRY_COMPARE(eventItem1->eventList.size(), 2); + QCOMPARE_EVENT(0, Event::HandlerDestination, QEvent::None, Qt::TouchPointPressed, QQuickEventPoint::GrabExclusive); + QCOMPARE_EVENT(1, Event::HandlerDestination, QEvent::Pointer, Qt::TouchPointPressed, QQuickEventPoint::GrabExclusive); p1 += QPoint(10, 0); QTest::mouseMove(window, p1); - QCOMPARE(eventItem1->eventList.size(), 2); - QCOMPARE_EVENT(1, Event::HandlerDestination, Qt::TouchPointMoved, QEvent::Pointer); - QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p1); QCOMPARE(eventItem1->eventList.size(), 3); - QCOMPARE_EVENT(2, Event::HandlerDestination, Qt::TouchPointReleased, QEvent::Pointer); + QCOMPARE_EVENT(2, Event::HandlerDestination, QEvent::Pointer, Qt::TouchPointMoved, QQuickEventPoint::GrabExclusive); + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p1); + QCOMPARE(eventItem1->eventList.size(), 5); + QCOMPARE_EVENT(3, Event::HandlerDestination, QEvent::Pointer, Qt::TouchPointReleased, QQuickEventPoint::GrabExclusive); + QCOMPARE_EVENT(4, Event::HandlerDestination, QEvent::None, Qt::TouchPointReleased, QQuickEventPoint::UngrabExclusive); eventItem1->eventList.clear(); } -- cgit v1.2.3 From fac9f435b4c4e5457355d04b1d9219b60ae5ac3b Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Tue, 25 Apr 2017 14:03:05 +0200 Subject: Add tst_PointerHandlers::touchReleaseOutside MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit to verify when a point is pressed on a PointerHandler, dragged outside, and released, the handler gets a release event, or a cancel. Change-Id: Icdcb67c5549aca605bc6e7b425978760330ba270 Reviewed-by: Jan Arve Sæther --- .../tst_qquickpointerhandler.cpp | 57 ++++++++++++++++++++++ 1 file changed, 57 insertions(+) (limited to 'tests') diff --git a/tests/auto/quick/pointerhandlers/qquickpointerhandler/tst_qquickpointerhandler.cpp b/tests/auto/quick/pointerhandlers/qquickpointerhandler/tst_qquickpointerhandler.cpp index 1f3e67d5c0..18369abec7 100644 --- a/tests/auto/quick/pointerhandlers/qquickpointerhandler/tst_qquickpointerhandler.cpp +++ b/tests/auto/quick/pointerhandlers/qquickpointerhandler/tst_qquickpointerhandler.cpp @@ -225,6 +225,8 @@ private slots: void touchEventDelivery(); void mouseEventDelivery(); + void touchReleaseOutside_data(); + void touchReleaseOutside(); protected: bool eventFilter(QObject *, QEvent *event) @@ -516,6 +518,61 @@ void tst_PointerHandlers::mouseEventDelivery() eventItem1->eventList.clear(); } +void tst_PointerHandlers::touchReleaseOutside_data() +{ + QTest::addColumn("acceptPointer"); + QTest::addColumn("grabPointer"); + QTest::addColumn("eventCount"); + QTest::addColumn("endIndexToTest"); + QTest::addColumn("endDestination"); // Event::Destination + QTest::addColumn("endType"); // QEvent::Type + QTest::addColumn("endState"); // Qt::TouchPointState + QTest::addColumn("endGrabState"); // Qt::TouchPointState + + QTest::newRow("reject and ignore") << false << false << 6 << 5 << (int)Event::TouchDestination + << (int)QEvent::TouchEnd << (int)Qt::TouchPointReleased << (int)NoGrab; + QTest::newRow("reject and grab") << false << true << 5 << 4 << (int)Event::HandlerDestination + << (int)QEvent::None << (int)Qt::TouchPointReleased << (int)QQuickEventPoint::UngrabExclusive; + QTest::newRow("accept and ignore") << true << false << 1 << 0 << (int)Event::HandlerDestination + << (int)QEvent::Pointer << (int)Qt::TouchPointPressed << (int)NoGrab; + QTest::newRow("accept and grab") << true << true << 5 << 4 << (int)Event::HandlerDestination + << (int)QEvent::None << (int)Qt::TouchPointReleased << (int)QQuickEventPoint::UngrabExclusive; +} + +void tst_PointerHandlers::touchReleaseOutside() +{ + QScopedPointer windowPtr; + createView(windowPtr, "singleitem.qml"); + QQuickView * window = windowPtr.data(); + + QFETCH(bool, acceptPointer); + QFETCH(bool, grabPointer); + QFETCH(int, eventCount); + QFETCH(int, endIndexToTest); + QFETCH(int, endDestination); + QFETCH(int, endType); + QFETCH(int, endState); + QFETCH(int, endGrabState); + + EventItem *eventItem1 = window->rootObject()->findChild("eventItem1"); + QVERIFY(eventItem1); + + eventItem1->acceptTouch = true; + eventItem1->acceptPointer = acceptPointer; + eventItem1->grabPointer = grabPointer; + + QPoint p1 = QPoint(20, 20); + QTest::touchEvent(window, touchDevice).press(0, p1, window); + QQuickTouchUtils::flush(window); + p1.setX(eventItem1->mapToScene(eventItem1->clipRect().bottomRight()).x() + 10); + QTest::touchEvent(window, touchDevice).move(0, p1, window); + QTest::touchEvent(window, touchDevice).release(0, p1, window); + QQuickTouchUtils::flush(window); + qCDebug(lcPointerTests) << eventItem1->eventList; + QCOMPARE(eventItem1->eventList.size(), eventCount); + QCOMPARE_EVENT(endIndexToTest, endDestination, endType, endState, endGrabState); +} + QTEST_MAIN(tst_PointerHandlers) #include "tst_qquickpointerhandler.moc" -- cgit v1.2.3 From 08dc25c023af53f96a909bda5f822ea0905461ad Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Tue, 16 May 2017 10:21:01 +0200 Subject: Add tst_multipointtoucharea_interop autotest to test interoperability of PointerHandlers with conventional touch- handling Items (with MultiPointTouchArea being the prototypical instance) Change-Id: Id19f312b17b70df072d66cd91816d2b19250a500 Reviewed-by: Shawn Rutledge --- .../data/pinchDragMPTA.qml | 120 ++++++++++ .../multipointtoucharea_interop.pro | 15 ++ .../tst_multipointtoucharea_interop.cpp | 263 +++++++++++++++++++++ .../auto/quick/pointerhandlers/pointerhandlers.pro | 1 + 4 files changed, 399 insertions(+) create mode 100644 tests/auto/quick/pointerhandlers/multipointtoucharea_interop/data/pinchDragMPTA.qml create mode 100644 tests/auto/quick/pointerhandlers/multipointtoucharea_interop/multipointtoucharea_interop.pro create mode 100644 tests/auto/quick/pointerhandlers/multipointtoucharea_interop/tst_multipointtoucharea_interop.cpp (limited to 'tests') diff --git a/tests/auto/quick/pointerhandlers/multipointtoucharea_interop/data/pinchDragMPTA.qml b/tests/auto/quick/pointerhandlers/multipointtoucharea_interop/data/pinchDragMPTA.qml new file mode 100644 index 0000000000..d479882d38 --- /dev/null +++ b/tests/auto/quick/pointerhandlers/multipointtoucharea_interop/data/pinchDragMPTA.qml @@ -0,0 +1,120 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.8 +import Qt.labs.handlers 1.0 + +Rectangle { + width: 1024; height: 600 + color: "beige" + objectName: "beige root" + + Rectangle { + id: container + objectName: "container rect" + width: 600 + height: 500 + color: "black" + border.color: pinch3.active ? "red" : "black" + border.width: 3 + antialiasing: true + + MultiPointTouchArea { + id: mpta + anchors.fill: parent + //onGestureStarted: gesture.grab() // in case this is embedded in something that might steal + touchPoints: [ + TouchPoint { property color color: "red" }, + TouchPoint { property color color: "orange" }, + TouchPoint { property color color: "lightsteelblue" }, + TouchPoint { property color color: "green" } + ] } + + Repeater { + model: 4 + + Item { + id: crosshairs + property TouchPoint touchPoint + x: touchPoint.x - width / 2 + y: touchPoint.y - height / 2 + width: 300; height: 300 + visible: touchPoint.pressed + rotation: touchPoint.rotation + + Rectangle { + color: touchPoint.color + anchors.centerIn: parent + width: 2; height: parent.height + antialiasing: true + } + Rectangle { + color: touchPoint.color + anchors.centerIn: parent + width: parent.width; height: 2 + antialiasing: true + } + Component.onCompleted: touchPoint = mpta.touchPoints[index] + } + } + + Item { + objectName: "pinch and drag" + anchors.fill: parent + // In order for PinchHandler to get a chance to take a passive grab, it has to get the touchpoints first. + // In order to get the touchpoints first, it has to be on top of the Z order: i.e. come last in paintOrderChildItems(). + // This is the opposite situation as with filtersChildMouseEvents: e.g. PinchArea would have wanted to be the parent, + // if it even knew that trick (which it doesn't). + PinchHandler { + id: pinch3 + objectName: "3-finger pinch" + target: container + requiredPointCount: 3 + minimumScale: 0.1 + maximumScale: 10 + } + DragHandler { + id: dragHandler + objectName: "DragHandler" + target: container + } + } + } +} diff --git a/tests/auto/quick/pointerhandlers/multipointtoucharea_interop/multipointtoucharea_interop.pro b/tests/auto/quick/pointerhandlers/multipointtoucharea_interop/multipointtoucharea_interop.pro new file mode 100644 index 0000000000..10d0ff8018 --- /dev/null +++ b/tests/auto/quick/pointerhandlers/multipointtoucharea_interop/multipointtoucharea_interop.pro @@ -0,0 +1,15 @@ +CONFIG += testcase + +TARGET = tst_multipointtoucharea_interop +QT += core-private gui-private qml-private quick-private testlib + +macos:CONFIG -= app_bundle + +SOURCES += tst_multipointtoucharea_interop.cpp + +include (../../../shared/util.pri) +include (../../shared/util.pri) + +TESTDATA = data/* + +OTHER_FILES += data/pinchDragMPTA.qml diff --git a/tests/auto/quick/pointerhandlers/multipointtoucharea_interop/tst_multipointtoucharea_interop.cpp b/tests/auto/quick/pointerhandlers/multipointtoucharea_interop/tst_multipointtoucharea_interop.cpp new file mode 100644 index 0000000000..64ddf79255 --- /dev/null +++ b/tests/auto/quick/pointerhandlers/multipointtoucharea_interop/tst_multipointtoucharea_interop.cpp @@ -0,0 +1,263 @@ +/**************************************************************************** +** +** Copyright (C) 2017 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 + +#include +#include +#include +#include +#include +#include +#include + +#include "../../../shared/util.h" +#include "../../shared/viewtestutil.h" + +Q_LOGGING_CATEGORY(lcPointerTests, "qt.quick.pointer.tests") + +class tst_MptaInterop : public QQmlDataTest +{ + Q_OBJECT +public: + tst_MptaInterop() + : touchDevice(QTest::createTouchDevice()) + , touchPointerDevice(QQuickPointerDevice::touchDevice(touchDevice)) + {} + +private slots: + void initTestCase(); + + void touchDrag(); + void touchesThenPinch(); + +private: + void createView(QScopedPointer &window, const char *fileName); + QTouchDevice *touchDevice; + QQuickPointerDevice *touchPointerDevice; +}; + +void tst_MptaInterop::createView(QScopedPointer &window, const char *fileName) +{ + window.reset(new QQuickView); + window->setSource(testFileUrl(fileName)); + QTRY_COMPARE(window->status(), QQuickView::Ready); + QQuickViewTestUtil::centerOnScreen(window.data()); + QQuickViewTestUtil::moveMouseAway(window.data()); + + window->show(); + QVERIFY(QTest::qWaitForWindowActive(window.data())); + QVERIFY(window->rootObject() != 0); +} + +void tst_MptaInterop::initTestCase() +{ + // This test assumes that we don't get synthesized mouse events from QGuiApplication + qApp->setAttribute(Qt::AA_SynthesizeMouseForUnhandledTouchEvents, false); + + QQmlDataTest::initTestCase(); +} + +void tst_MptaInterop::touchDrag() +{ + const int dragThreshold = QGuiApplication::styleHints()->startDragDistance(); + QScopedPointer windowPtr; + createView(windowPtr, "pinchDragMPTA.qml"); + QQuickView * window = windowPtr.data(); + + QQuickMultiPointTouchArea *mpta = window->rootObject()->findChild(); + QVERIFY(mpta); + QQuickPinchHandler *pinch = window->rootObject()->findChild(); + QVERIFY(pinch); + QQuickDragHandler *drag = window->rootObject()->findChild(); + QVERIFY(drag); + QQmlListReference tp(mpta, "touchPoints"); + QVERIFY(tp.at(3)); // the QML declares four touchpoints + QSignalSpy mptaPressedSpy(mpta, SIGNAL(pressed(QList))); + QSignalSpy mptaReleasedSpy(mpta, SIGNAL(released(QList))); + QTest::QTouchEventSequence touch = QTest::touchEvent(window, touchDevice); + + // Press one touchpoint: + // DragHandler gets a passive grab + // PinchHandler declines, because it wants 3 touchpoints + // MPTA doesn't get a chance, because DragHandler accepted the single EventPoint + QPoint p1 = mpta->mapToScene(QPointF(20, 20)).toPoint(); + touch.press(1, p1).commit(); + QQuickTouchUtils::flush(window); + auto pointerEvent = touchPointerDevice->pointerEvent(); + QCOMPARE(tp.at(0)->property("pressed").toBool(), false); +// QCOMPARE(pointerEvent->point(0)->exclusiveGrabber(), mpta); + + // Start moving + // DragHandler gets keeps monitoring, due to its passive grab, + // and eventually steals the exclusive grab from MPTA + int dragStoleGrab = 0; + for (int i = 0; i < 4; ++i) { + p1 += QPoint(dragThreshold / 2, 0); + touch.move(1, p1).commit(); + QQuickTouchUtils::flush(window); + if (!dragStoleGrab && pointerEvent->point(0)->exclusiveGrabber() == drag) + dragStoleGrab = i; +// QCOMPARE(tp.at(0)->property("pressed").toBool(), !dragStoleGrab); + } + qCDebug(lcPointerTests, "DragHandler stole the grab after %d events", dragStoleGrab); + QVERIFY(dragStoleGrab > 1); + + touch.release(1, p1).commit(); + QQuickTouchUtils::flush(window); +} + +// TODO touchesThenPinch_data with press/release sequences somehow: vectors of touchpoint IDs? or a string representation? +void tst_MptaInterop::touchesThenPinch() +{ + const int dragThreshold = QGuiApplication::styleHints()->startDragDistance(); + QScopedPointer windowPtr; + createView(windowPtr, "pinchDragMPTA.qml"); + QQuickView * window = windowPtr.data(); + + QQuickMultiPointTouchArea *mpta = window->rootObject()->findChild(); + QVERIFY(mpta); + QQuickPinchHandler *pinch = window->rootObject()->findChild(); + QVERIFY(pinch); + QQuickDragHandler *drag = window->rootObject()->findChild(); + QVERIFY(drag); + QQmlListReference tp(mpta, "touchPoints"); + QVERIFY(tp.at(3)); // the QML declares four touchpoints + QSignalSpy mptaPressedSpy(mpta, SIGNAL(pressed(QList))); + QSignalSpy mptaReleasedSpy(mpta, SIGNAL(released(QList))); + QTest::QTouchEventSequence touch = QTest::touchEvent(window, touchDevice); + auto pointerEvent = touchPointerDevice->pointerEvent(); + // TODO after merge of e0c30279ec1fad88346ed3fb483bc3c672fdd01b +// auto pointerEvent = QQuickWindowPrivate::pointerEventInstance(touchPointerDevice); + + // Press one touchpoint: + // DragHandler gets a passive grab + // PinchHandler declines, because it wants 3 touchpoints + // MPTA doesn't get a chance, because DragHandler accepted the single EventPoint + QPoint p1 = mpta->mapToScene(QPointF(20, 20)).toPoint(); + touch.press(1, p1).commit(); + QQuickTouchUtils::flush(window); + QTRY_COMPARE(pointerEvent->point(0)->exclusiveGrabber(), nullptr); + QTRY_COMPARE(pointerEvent->point(0)->passiveGrabbers().first(), drag); +// QTRY_VERIFY(tp.at(0)->property("pressed").toBool()); + + // Press a second touchpoint: MPTA grabs it + QPoint p2 = mpta->mapToScene(QPointF(200, 30)).toPoint(); + touch.stationary(1).press(2, p2).commit(); + QQuickTouchUtils::flush(window); + QVERIFY(tp.at(0)->property("pressed").toBool()); + QTRY_VERIFY(tp.at(1)->property("pressed").toBool()); + QCOMPARE(mptaPressedSpy.count(), 1); + + // ATM it's required that when PinchHandler sees the third touchpoint, + // the pre-existing points must have moved far enough to exceed the drag threshold. + // If MPTA is allowed to grab that third point, then PinchHandler won't steal. + // TODO should we change that? make sure that if PH has a passive grab, it always gets updated even though MPTA has the grab? + for (int i = 0; i < 2; ++i) { + p1 += QPoint(dragThreshold, dragThreshold); + p2 += QPoint(dragThreshold, dragThreshold); + touch.move(1, p1).move(2, p2).commit(); + } + + // Press a third touchpoint: PinchHandler grabs, MPTA doesn't + QPoint p3 = mpta->mapToScene(QPointF(110, 200)).toPoint(); + touch.stationary(1).stationary(2).press(3, p3).commit(); + QQuickTouchUtils::flush(window); + QCOMPARE(tp.at(0)->property("pressed").toBool(), true); + QCOMPARE(tp.at(1)->property("pressed").toBool(), true); + QCOMPARE(tp.at(2)->property("pressed").toBool(), false); + QCOMPARE(mptaPressedSpy.count(), 1); + QTRY_COMPARE(pointerEvent->point(2)->exclusiveGrabber(), pinch); + QVERIFY(pinch->active()); + + // Move some more: PinchHandler reacts + for (int i = 0; i < 8; ++i) { + p1 += QPoint(4, 4); + p2 += QPoint(4, 4); + p3 += QPoint(-4, 4); + touch.move(1, p1).move(2, p2).move(3, p3).commit(); +// QTRY_COMPARE(tp.at(0)->property("pressed").toBool(), false); // TODO fails; MPTA doesn't know it lost its grabs +// QCOMPARE(tp.at(1)->property("pressed").toBool(), false); +// QCOMPARE(tp.at(2)->property("pressed").toBool(), false); + } + qCDebug(lcPointerTests) << "scale" << pinch->scale() << "rot" << pinch->rotation(); + QTRY_VERIFY(pinch->rotation() > 10); + QVERIFY(pinch->scale() > 1); + + // Press one more point (pinkie finger) + QPoint p4 = mpta->mapToScene(QPointF(300, 200)).toPoint(); + touch.stationary(1).stationary(2).stationary(3).press(4, p4).commit(); + // MPTA grabs p4 (which is at index 3) +// QTRY_COMPARE(pointerEvent->point(3)->exclusiveGrabber(), mpta); + // PinchHandler wantsPointerEvent declines, because it wants exactly 3 touchpoints, and there are now 4. + // Move some more... MPTA reacts, in spite of not grabbing all the points + for (int i = 0; i < 8; ++i) { + p1 += QPoint(4, 4); + p2 += QPoint(4, 4); + p3 += QPoint(-4, 4); + p4 += QPoint(-4, -4); + touch.move(1, p1).move(2, p2).move(3, p3).move(4, p4).commit(); +// QTRY_COMPARE(pointerEvent->point(0)->exclusiveGrabber(), nullptr); +// QCOMPARE(pointerEvent->point(1)->exclusiveGrabber(), nullptr); +// QCOMPARE(pointerEvent->point(2)->exclusiveGrabber(), nullptr); +// QCOMPARE(pointerEvent->point(3)->exclusiveGrabber(), mpta); + QCOMPARE(tp.at(0)->property("pressed").toBool(), true); + QCOMPARE(tp.at(1)->property("pressed").toBool(), true); +// QCOMPARE(tp.at(2)->property("pressed").toBool(), true); +// QCOMPARE(tp.at(3)->property("pressed").toBool(), true); + } + + // Release the pinkie + touch.stationary(1).stationary(2).stationary(3).release(4, p4).commit(); + // Move some more: PinchHander grabs again, and reacts + for (int i = 0; i < 8; ++i) { + p1 -= QPoint(4, 4); + p2 += QPoint(4, 4); + p3 -= QPoint(-4, 4); + touch.move(1, p1).move(2, p2).move(3, p3).commit(); + QTRY_COMPARE(pointerEvent->point(0)->exclusiveGrabber(), pinch); + } + + // Release the first finger + touch.stationary(2).stationary(3).release(1, p1).commit(); + // Move some more: PinchHander isn't interested in a mere 2 points, and MPTA should react... but it doesn't (TODO?) + for (int i = 0; i < 8; ++i) { + p1 -= QPoint(4, 4); + p2 += QPoint(4, 4); + touch.move(1, p1).move(2, p2).commit(); + QTest::qWait(100); + } + + touch.release(1, p1).release(2, p2).release(3, p3).commit(); + QQuickTouchUtils::flush(window); +// QTRY_COMPARE(mptaReleasedSpy.count(), 1); // all points at once +} + +QTEST_MAIN(tst_MptaInterop) + +#include "tst_multipointtoucharea_interop.moc" diff --git a/tests/auto/quick/pointerhandlers/pointerhandlers.pro b/tests/auto/quick/pointerhandlers/pointerhandlers.pro index 4aa66df2c4..13a4b81f4e 100644 --- a/tests/auto/quick/pointerhandlers/pointerhandlers.pro +++ b/tests/auto/quick/pointerhandlers/pointerhandlers.pro @@ -3,6 +3,7 @@ TEMPLATE = subdirs qtConfig(private_tests) { SUBDIRS += \ flickableinterop \ + multipointtoucharea_interop \ qquickpointerhandler \ qquicktaphandler \ } -- cgit v1.2.3 From 9ad61117048394ef97b99a7387f5f48b5a12d9d9 Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Fri, 21 Apr 2017 22:20:21 +0200 Subject: Add autotest for DragHandler MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I46f7e2c16b775723a08aa192845d490046231990 Reviewed-by: Jan Arve Sæther --- .../qquickdraghandler/data/reparenting.qml | 60 --- .../auto/quick/pointerhandlers/pointerhandlers.pro | 1 + .../qquickdraghandler/data/DragAnywhereSlider.qml | 138 +++++++ .../qquickdraghandler/data/FlashAnimation.qml | 57 +++ .../qquickdraghandler/data/Slider.qml | 137 +++++++ .../qquickdraghandler/data/draggables.qml | 72 ++++ .../qquickdraghandler/data/multipleSliders.qml | 79 ++++ .../qquickdraghandler/data/reparenting.qml | 60 +++ .../qquickdraghandler/qquickdraghandler.pro | 15 + .../qquickdraghandler/tst_qquickdraghandler.cpp | 405 +++++++++++++++++++++ 10 files changed, 964 insertions(+), 60 deletions(-) delete mode 100644 tests/auto/quick/handlers/qquickdraghandler/data/reparenting.qml create mode 100644 tests/auto/quick/pointerhandlers/qquickdraghandler/data/DragAnywhereSlider.qml create mode 100644 tests/auto/quick/pointerhandlers/qquickdraghandler/data/FlashAnimation.qml create mode 100644 tests/auto/quick/pointerhandlers/qquickdraghandler/data/Slider.qml create mode 100644 tests/auto/quick/pointerhandlers/qquickdraghandler/data/draggables.qml create mode 100644 tests/auto/quick/pointerhandlers/qquickdraghandler/data/multipleSliders.qml create mode 100644 tests/auto/quick/pointerhandlers/qquickdraghandler/data/reparenting.qml create mode 100644 tests/auto/quick/pointerhandlers/qquickdraghandler/qquickdraghandler.pro create mode 100644 tests/auto/quick/pointerhandlers/qquickdraghandler/tst_qquickdraghandler.cpp (limited to 'tests') diff --git a/tests/auto/quick/handlers/qquickdraghandler/data/reparenting.qml b/tests/auto/quick/handlers/qquickdraghandler/data/reparenting.qml deleted file mode 100644 index 3545badd86..0000000000 --- a/tests/auto/quick/handlers/qquickdraghandler/data/reparenting.qml +++ /dev/null @@ -1,60 +0,0 @@ -import QtQuick 2.8 -import Qt.labs.handlers 1.0 - -Grid { - id: root - objectName: "root" - property bool reparentOnDrag: true - width: 200; height: 200 - columns: 3 - spacing: 10 - Repeater { - model: 9 - anchors.fill: parent - Item { - id: gridPlaceholder - objectName: "gridPlaceholder" + index - width: 60 - height: 60 - Rectangle { - id: icon - border.color: "black" - color: "beige" - radius: 3 - width: 60 - height: 60 - onParentChanged :console.log("parent " + parent) - anchors { - horizontalCenter: parent.horizontalCenter - verticalCenter: parent.verticalCenter - } - DragHandler { - id: dragArea - } - Text { - anchors.centerIn: parent - text: index + "@" + Math.round(icon.x) + "," + Math.round(icon.y) - font.pointSize: 8 - } - states: [ - State { - when: dragArea.dragging - AnchorChanges { - target: icon - anchors.horizontalCenter: undefined - anchors.verticalCenter: undefined - } - ParentChange { - target: root.reparentOnDrag ? icon : null - parent: root - } - PropertyChanges { - target: icon - color: "yellow" - } - } - ] - } - } - } -} diff --git a/tests/auto/quick/pointerhandlers/pointerhandlers.pro b/tests/auto/quick/pointerhandlers/pointerhandlers.pro index 13a4b81f4e..2492924944 100644 --- a/tests/auto/quick/pointerhandlers/pointerhandlers.pro +++ b/tests/auto/quick/pointerhandlers/pointerhandlers.pro @@ -5,6 +5,7 @@ qtConfig(private_tests) { flickableinterop \ multipointtoucharea_interop \ qquickpointerhandler \ + qquickdraghandler \ qquicktaphandler \ } diff --git a/tests/auto/quick/pointerhandlers/qquickdraghandler/data/DragAnywhereSlider.qml b/tests/auto/quick/pointerhandlers/qquickdraghandler/data/DragAnywhereSlider.qml new file mode 100644 index 0000000000..9b0ef81635 --- /dev/null +++ b/tests/auto/quick/pointerhandlers/qquickdraghandler/data/DragAnywhereSlider.qml @@ -0,0 +1,138 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.8 +import Qt.labs.handlers 1.0 + +Item { + id: root + objectName: label + property int value: 50 + property int maximumValue: 99 + property alias label: label.text + property alias tapEnabled: tap.enabled + property alias pressed: tap.isPressed + signal tapped + width: 140 + height: 400 + + DragHandler { + id: dragHandler + objectName: label.text + " DragHandler" + target: knob + xAxis.enabled: false + yAxis.minimum: slot.y + yAxis.maximum: slot.height + slot.y - knob.height + } + + Rectangle { + id: slot + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.margins: 10 + anchors.topMargin: 30 + anchors.bottomMargin: 30 + anchors.horizontalCenter: parent.horizontalCenter + width: 10 + color: "black" + radius: width / 2 + smooth: true + } + + Rectangle { + id: glow + anchors.fill: knob + anchors.margins: -5 + anchors.leftMargin: -2 + anchors.horizontalCenterOffset: 1 + radius: 5 + color: "#4400FFFF" + opacity: tap.isPressed || tapFlash.running ? 1 : 0 + FlashAnimation on visible { + id: tapFlash + } + } + Rectangle { + id: knob + objectName: "Slider Knob" + width: parent.width - 2 + height: 30 + radius: 5 + color: "darkgray" + border.color: "black" + property bool programmatic: false + property real multiplier: root.maximumValue / (dragHandler.yAxis.maximum - dragHandler.yAxis.minimum) + onYChanged: if (!programmatic) root.value = root.maximumValue - (knob.y - dragHandler.yAxis.minimum) * multiplier + transformOrigin: Item.Center + function setValue(value) { knob.y = dragHandler.yAxis.maximum - value / knob.multiplier } + TapHandler { + id: tap + objectName: label.text + " TapHandler" + gesturePolicy: TapHandler.DragThreshold + onTapped: { + tapFlash.start() + root.tapped + } + } + } + + Text { + font.pointSize: 16 + color: "red" + anchors.bottom: parent.bottom + anchors.horizontalCenter: parent.horizontalCenter + text: root.value + } + + Text { + id: label + font.pointSize: 12 + color: "red" + anchors.top: parent.top + anchors.topMargin: 5 + anchors.horizontalCenter: parent.horizontalCenter + } + + Component.onCompleted: { + knob.programmatic = true + knob.setValue(root.value) + knob.programmatic = false + } +} diff --git a/tests/auto/quick/pointerhandlers/qquickdraghandler/data/FlashAnimation.qml b/tests/auto/quick/pointerhandlers/qquickdraghandler/data/FlashAnimation.qml new file mode 100644 index 0000000000..2224276819 --- /dev/null +++ b/tests/auto/quick/pointerhandlers/qquickdraghandler/data/FlashAnimation.qml @@ -0,0 +1,57 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 + +SequentialAnimation { + id: tapFlash + running: false + PropertyAction { value: false } + PauseAnimation { duration: 100 } + PropertyAction { value: true } + PauseAnimation { duration: 100 } + PropertyAction { value: false } + PauseAnimation { duration: 100 } + PropertyAction { value: true } + PauseAnimation { duration: 100 } + PropertyAction { value: false } + PauseAnimation { duration: 100 } + PropertyAction { value: true } +} diff --git a/tests/auto/quick/pointerhandlers/qquickdraghandler/data/Slider.qml b/tests/auto/quick/pointerhandlers/qquickdraghandler/data/Slider.qml new file mode 100644 index 0000000000..81c261fc7a --- /dev/null +++ b/tests/auto/quick/pointerhandlers/qquickdraghandler/data/Slider.qml @@ -0,0 +1,137 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.8 +import Qt.labs.handlers 1.0 + +Item { + id: root + objectName: label + property int value: 50 + property int maximumValue: 99 + property alias label: label.text + property alias tapEnabled: tap.enabled + property alias pressed: tap.isPressed + signal tapped + width: 140 + height: 400 + + Rectangle { + id: slot + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.margins: 10 + anchors.topMargin: 30 + anchors.bottomMargin: 30 + anchors.horizontalCenter: parent.horizontalCenter + width: 10 + color: "black" + radius: width / 2 + smooth: true + } + + Rectangle { + id: glow + anchors.fill: knob + anchors.margins: -5 + anchors.leftMargin: -2 + anchors.horizontalCenterOffset: 1 + radius: 5 + color: "#4400FFFF" + opacity: tap.isPressed || tapFlash.running ? 1 : 0 + FlashAnimation on visible { + id: tapFlash + } + } + Rectangle { + id: knob + objectName: root.label + " Knob" + width: parent.width - 2 + height: 30 + radius: 5 + color: "darkgray" + border.color: "black" + property bool programmatic: false + property real multiplier: root.maximumValue / (dragHandler.yAxis.maximum - dragHandler.yAxis.minimum) + onYChanged: if (!programmatic) root.value = root.maximumValue - (knob.y - dragHandler.yAxis.minimum) * multiplier + transformOrigin: Item.Center + function setValue(value) { knob.y = dragHandler.yAxis.maximum - value / knob.multiplier } + function flash() { tapFlash.start() } + DragHandler { + id: dragHandler + objectName: label.text + " DragHandler" + xAxis.enabled: false + yAxis.minimum: slot.y + yAxis.maximum: slot.height + slot.y - knob.height + } + TapHandler { + id: tap + objectName: label.text + " TapHandler" + gesturePolicy: TapHandler.DragThreshold + onTapped: { + tapFlash.start() + root.tapped + } + } + } + + Text { + font.pointSize: 16 + color: "red" + anchors.bottom: parent.bottom + anchors.horizontalCenter: parent.horizontalCenter + text: root.value + } + + Text { + id: label + font.pointSize: 12 + color: "red" + anchors.top: parent.top + anchors.topMargin: 5 + anchors.horizontalCenter: parent.horizontalCenter + } + + Component.onCompleted: { + knob.programmatic = true + knob.setValue(root.value) + knob.programmatic = false + } +} diff --git a/tests/auto/quick/pointerhandlers/qquickdraghandler/data/draggables.qml b/tests/auto/quick/pointerhandlers/qquickdraghandler/data/draggables.qml new file mode 100644 index 0000000000..cfacd69858 --- /dev/null +++ b/tests/auto/quick/pointerhandlers/qquickdraghandler/data/draggables.qml @@ -0,0 +1,72 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the manual tests of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.8 +import Qt.labs.handlers 1.0 + +Item { + id: root + objectName: "Draggables" + width: 640 + height: 480 + + Repeater { + model: 2 + + Rectangle { + id: ball + objectName: "Ball " + index + color: dragHandler.active ? "blue" : "lightsteelblue" + width: 80; height: 80; x: 200 + index * 200; y: 200; radius: width / 2 + onParentChanged: console.log(this + " parent " + parent) + + DragHandler { + id: dragHandler + objectName: "DragHandler " + index + } + + Text { + color: "white" + anchors.centerIn: parent + text: dragHandler.pos.x.toFixed(1) + "," + dragHandler.pos.y.toFixed(1) + } + } + } +} diff --git a/tests/auto/quick/pointerhandlers/qquickdraghandler/data/multipleSliders.qml b/tests/auto/quick/pointerhandlers/qquickdraghandler/data/multipleSliders.qml new file mode 100644 index 0000000000..bcb16f54cb --- /dev/null +++ b/tests/auto/quick/pointerhandlers/qquickdraghandler/data/multipleSliders.qml @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.8 +import Qt.labs.handlers 1.0 + +Rectangle { + id: root + width: 900 + height: 850 + objectName: "root" + color: "#222222" + + Grid { + objectName: "grid" + anchors.fill: parent + spacing: 10 + columns: 6 + Repeater { + id: top + objectName: "top" + model: 6 + + delegate: Slider { + objectName: label + label: "Drag Knob " + index + width: 140 + } + } + Repeater { + id: bottom + objectName: "bottom" + model: 6 + + delegate: DragAnywhereSlider { + objectName: label + label: "Drag Anywhere " + index + width: 140 + } + } + } +} diff --git a/tests/auto/quick/pointerhandlers/qquickdraghandler/data/reparenting.qml b/tests/auto/quick/pointerhandlers/qquickdraghandler/data/reparenting.qml new file mode 100644 index 0000000000..3545badd86 --- /dev/null +++ b/tests/auto/quick/pointerhandlers/qquickdraghandler/data/reparenting.qml @@ -0,0 +1,60 @@ +import QtQuick 2.8 +import Qt.labs.handlers 1.0 + +Grid { + id: root + objectName: "root" + property bool reparentOnDrag: true + width: 200; height: 200 + columns: 3 + spacing: 10 + Repeater { + model: 9 + anchors.fill: parent + Item { + id: gridPlaceholder + objectName: "gridPlaceholder" + index + width: 60 + height: 60 + Rectangle { + id: icon + border.color: "black" + color: "beige" + radius: 3 + width: 60 + height: 60 + onParentChanged :console.log("parent " + parent) + anchors { + horizontalCenter: parent.horizontalCenter + verticalCenter: parent.verticalCenter + } + DragHandler { + id: dragArea + } + Text { + anchors.centerIn: parent + text: index + "@" + Math.round(icon.x) + "," + Math.round(icon.y) + font.pointSize: 8 + } + states: [ + State { + when: dragArea.dragging + AnchorChanges { + target: icon + anchors.horizontalCenter: undefined + anchors.verticalCenter: undefined + } + ParentChange { + target: root.reparentOnDrag ? icon : null + parent: root + } + PropertyChanges { + target: icon + color: "yellow" + } + } + ] + } + } + } +} diff --git a/tests/auto/quick/pointerhandlers/qquickdraghandler/qquickdraghandler.pro b/tests/auto/quick/pointerhandlers/qquickdraghandler/qquickdraghandler.pro new file mode 100644 index 0000000000..b50fe5ca6f --- /dev/null +++ b/tests/auto/quick/pointerhandlers/qquickdraghandler/qquickdraghandler.pro @@ -0,0 +1,15 @@ +CONFIG += testcase + +TARGET = tst_qquickdraghandler +QT += core-private gui-private qml-private quick-private testlib + +macos:CONFIG -= app_bundle + +SOURCES += tst_qquickdraghandler.cpp + +include (../../../shared/util.pri) +include (../../shared/util.pri) + +TESTDATA = data/* + +# OTHER_FILES += data/foo.qml diff --git a/tests/auto/quick/pointerhandlers/qquickdraghandler/tst_qquickdraghandler.cpp b/tests/auto/quick/pointerhandlers/qquickdraghandler/tst_qquickdraghandler.cpp new file mode 100644 index 0000000000..5b59911965 --- /dev/null +++ b/tests/auto/quick/pointerhandlers/qquickdraghandler/tst_qquickdraghandler.cpp @@ -0,0 +1,405 @@ +/**************************************************************************** +** +** Copyright (C) 2017 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 + +#include +#include +#include +#include +#include +#include +#include + +#include "../../../shared/util.h" +#include "../../shared/viewtestutil.h" + +Q_LOGGING_CATEGORY(lcPointerTests, "qt.quick.pointer.tests") + +class tst_DragHandler : public QQmlDataTest +{ + Q_OBJECT +public: + tst_DragHandler() + :touchDevice(QTest::createTouchDevice()) + {} + +private slots: + void initTestCase(); + + void defaultPropertyValues(); + void touchDrag(); + void mouseDrag(); + void touchDragMulti(); + void touchDragMultiSliders_data(); + void touchDragMultiSliders(); + +private: + void createView(QScopedPointer &window, const char *fileName); + QTouchDevice *touchDevice; +}; + +void tst_DragHandler::createView(QScopedPointer &window, const char *fileName) +{ + window.reset(new QQuickView); + window->setSource(testFileUrl(fileName)); + QTRY_COMPARE(window->status(), QQuickView::Ready); + QQuickViewTestUtil::centerOnScreen(window.data()); + QQuickViewTestUtil::moveMouseAway(window.data()); + + window->show(); + QVERIFY(QTest::qWaitForWindowActive(window.data())); + QVERIFY(window->rootObject() != 0); +} + +void tst_DragHandler::initTestCase() +{ + // This test assumes that we don't get synthesized mouse events from QGuiApplication + qApp->setAttribute(Qt::AA_SynthesizeMouseForUnhandledTouchEvents, false); + + QQmlDataTest::initTestCase(); +} + +void tst_DragHandler::defaultPropertyValues() +{ + QScopedPointer windowPtr; + createView(windowPtr, "draggables.qml"); + QQuickView * window = windowPtr.data(); + + QQuickItem *ball = window->rootObject()->childItems().first(); + QVERIFY(ball); + QQuickDragHandler *dragHandler = ball->findChild(); + QVERIFY(dragHandler); + + QCOMPARE(dragHandler->acceptedButtons(), Qt::LeftButton); + QCOMPARE(dragHandler->translation(), QPointF()); + QCOMPARE(dragHandler->point().position(), QPointF()); + QCOMPARE(dragHandler->point().scenePosition(), QPointF()); + QCOMPARE(dragHandler->point().pressPosition(), QPointF()); + QCOMPARE(dragHandler->point().scenePressPosition(), QPointF()); + QCOMPARE(dragHandler->point().sceneGrabPosition(), QPointF()); +} + +void tst_DragHandler::touchDrag() +{ + const int dragThreshold = QGuiApplication::styleHints()->startDragDistance(); + QScopedPointer windowPtr; + createView(windowPtr, "draggables.qml"); + QQuickView * window = windowPtr.data(); + + QQuickItem *ball = window->rootObject()->childItems().first(); + QVERIFY(ball); + QQuickDragHandler *dragHandler = ball->findChild(); + QVERIFY(dragHandler); + + QSignalSpy translationChangedSpy(dragHandler, SIGNAL(translationChanged())); + + QPointF ballCenter = ball->clipRect().center(); + QPointF scenePressPos = ball->mapToScene(ballCenter); + QPoint p1 = scenePressPos.toPoint(); + QTest::touchEvent(window, touchDevice).press(1, p1, window); + QQuickTouchUtils::flush(window); + QVERIFY(!dragHandler->active()); + QCOMPARE(dragHandler->point().position(), ballCenter); + QCOMPARE(dragHandler->point().pressPosition(), ballCenter); + QCOMPARE(dragHandler->point().scenePosition(), scenePressPos); + QCOMPARE(dragHandler->point().scenePressPosition(), scenePressPos); + p1 += QPoint(dragThreshold, 0); + QTest::touchEvent(window, touchDevice).move(1, p1, window); + QQuickTouchUtils::flush(window); + QVERIFY(!dragHandler->active()); + p1 += QPoint(1, 0); + QTest::touchEvent(window, touchDevice).move(1, p1, window); + QQuickTouchUtils::flush(window); + QTRY_VERIFY(dragHandler->active()); + QCOMPARE(translationChangedSpy.count(), 0); + QCOMPARE(dragHandler->translation().x(), 0.0); + QPointF sceneGrabPos = p1; + QCOMPARE(dragHandler->point().sceneGrabPosition(), sceneGrabPos); + p1 += QPoint(19, 0); + QTest::touchEvent(window, touchDevice).move(1, p1, window); + QQuickTouchUtils::flush(window); + QTRY_VERIFY(dragHandler->active()); + QCOMPARE(dragHandler->point().position(), ballCenter); + QCOMPARE(dragHandler->point().pressPosition(), ballCenter); + QCOMPARE(dragHandler->point().scenePosition(), ball->mapToScene(ballCenter)); + QCOMPARE(dragHandler->point().scenePressPosition(), scenePressPos); + QCOMPARE(dragHandler->point().sceneGrabPosition(), sceneGrabPos); + QCOMPARE(dragHandler->translation().x(), dragThreshold + 20.0); + QCOMPARE(dragHandler->translation().y(), 0.0); + QTest::touchEvent(window, touchDevice).release(1, p1, window); + QQuickTouchUtils::flush(window); + QTRY_VERIFY(!dragHandler->active()); + QCOMPARE(dragHandler->point().pressedButtons(), Qt::NoButton); + QCOMPARE(ball->mapToScene(ballCenter).toPoint(), p1); + QCOMPARE(translationChangedSpy.count(), 1); +} + +void tst_DragHandler::mouseDrag() +{ + const int dragThreshold = QGuiApplication::styleHints()->startDragDistance(); + QScopedPointer windowPtr; + createView(windowPtr, "draggables.qml"); + QQuickView * window = windowPtr.data(); + + QQuickItem *ball = window->rootObject()->childItems().first(); + QVERIFY(ball); + QQuickDragHandler *dragHandler = ball->findChild(); + QVERIFY(dragHandler); + + QSignalSpy translationChangedSpy(dragHandler, SIGNAL(translationChanged())); + + QPointF ballCenter = ball->clipRect().center(); + QPointF scenePressPos = ball->mapToScene(ballCenter); + QPoint p1 = scenePressPos.toPoint(); + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, p1); + QVERIFY(!dragHandler->active()); + QCOMPARE(dragHandler->point().position(), ballCenter); + QCOMPARE(dragHandler->point().pressPosition(), ballCenter); + QCOMPARE(dragHandler->point().scenePosition(), scenePressPos); + QCOMPARE(dragHandler->point().scenePressPosition(), scenePressPos); + p1 += QPoint(dragThreshold, 0); + QTest::mouseMove(window, p1); + QVERIFY(!dragHandler->active()); + p1 += QPoint(1, 0); + QTest::mouseMove(window, p1); + QTRY_VERIFY(dragHandler->active()); + QCOMPARE(translationChangedSpy.count(), 0); + QCOMPARE(dragHandler->translation().x(), 0.0); + QPointF sceneGrabPos = p1; + QCOMPARE(dragHandler->point().sceneGrabPosition(), sceneGrabPos); + p1 += QPoint(19, 0); + QTest::mouseMove(window, p1); + QTRY_VERIFY(dragHandler->active()); + QCOMPARE(dragHandler->point().position(), ballCenter); + QCOMPARE(dragHandler->point().pressPosition(), ballCenter); + QCOMPARE(dragHandler->point().scenePosition(), ball->mapToScene(ballCenter)); + QCOMPARE(dragHandler->point().scenePressPosition(), scenePressPos); + QCOMPARE(dragHandler->point().sceneGrabPosition(), sceneGrabPos); + QCOMPARE(dragHandler->translation().x(), dragThreshold + 20.0); + QCOMPARE(dragHandler->translation().y(), 0.0); + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p1); + QTRY_VERIFY(!dragHandler->active()); + QCOMPARE(dragHandler->point().pressedButtons(), Qt::NoButton); + QCOMPARE(ball->mapToScene(ballCenter).toPoint(), p1); + QCOMPARE(translationChangedSpy.count(), 1); +} + +void tst_DragHandler::touchDragMulti() +{ + const int dragThreshold = QGuiApplication::styleHints()->startDragDistance(); + QScopedPointer windowPtr; + createView(windowPtr, "draggables.qml"); + QQuickView * window = windowPtr.data(); + + QQuickItem *ball1 = window->rootObject()->childItems().first(); + QVERIFY(ball1); + QQuickDragHandler *dragHandler1 = ball1->findChild(); + QVERIFY(dragHandler1); + QSignalSpy translationChangedSpy1(dragHandler1, SIGNAL(translationChanged())); + + QQuickItem *ball2 = window->rootObject()->childItems().at(1); + QVERIFY(ball2); + QQuickDragHandler *dragHandler2 = ball2->findChild(); + QVERIFY(dragHandler2); + QSignalSpy translationChangedSpy2(dragHandler2, SIGNAL(translationChanged())); + + QPointF ball1Center = ball1->clipRect().center(); + QPointF scenePressPos1 = ball1->mapToScene(ball1Center); + QPoint p1 = scenePressPos1.toPoint(); + QPointF ball2Center = ball2->clipRect().center(); + QPointF scenePressPos2 = ball2->mapToScene(ball2Center); + QPoint p2 = scenePressPos2.toPoint(); + + QTest::touchEvent(window, touchDevice).press(1, p1, window).press(2, p2, window); + QQuickTouchUtils::flush(window); + QVERIFY(!dragHandler1->active()); + QCOMPARE(dragHandler1->point().position(), ball1Center); + QCOMPARE(dragHandler1->point().pressPosition(), ball1Center); + QCOMPARE(dragHandler1->point().scenePosition(), scenePressPos1); + QCOMPARE(dragHandler1->point().scenePressPosition(), scenePressPos1); + QVERIFY(!dragHandler2->active()); + QCOMPARE(dragHandler2->point().position(), ball2Center); + QCOMPARE(dragHandler2->point().pressPosition(), ball2Center); + QCOMPARE(dragHandler2->point().scenePosition(), scenePressPos2); + QCOMPARE(dragHandler2->point().scenePressPosition(), scenePressPos2); + p1 += QPoint(dragThreshold, 0); + p2 += QPoint(0, dragThreshold); + QTest::touchEvent(window, touchDevice).move(1, p1, window).move(2, p2, window); + QQuickTouchUtils::flush(window); + QVERIFY(!dragHandler1->active()); + p1 += QPoint(1, 0); + p2 += QPoint(0, 1); + QTest::touchEvent(window, touchDevice).move(1, p1, window).move(2, p2, window); + QQuickTouchUtils::flush(window); + QTRY_VERIFY(dragHandler1->active()); + QVERIFY(dragHandler2->active()); + QCOMPARE(translationChangedSpy1.count(), 0); + QCOMPARE(dragHandler1->translation().x(), 0.0); + QPointF sceneGrabPos1 = p1; + QPointF sceneGrabPos2 = p2; + QCOMPARE(dragHandler1->point().sceneGrabPosition(), sceneGrabPos1); + QCOMPARE(dragHandler2->point().sceneGrabPosition(), sceneGrabPos2); + p1 += QPoint(19, 0); + p2 += QPoint(0, 19); + QVERIFY(dragHandler2->active()); + QCOMPARE(translationChangedSpy2.count(), 0); + QCOMPARE(dragHandler2->translation().x(), 0.0); + QCOMPARE(dragHandler2->point().sceneGrabPosition(), sceneGrabPos2); + QTest::touchEvent(window, touchDevice).move(1, p1, window).move(2, p2, window); + QQuickTouchUtils::flush(window); + QVERIFY(dragHandler1->active()); + QVERIFY(dragHandler2->active()); + QCOMPARE(dragHandler1->point().position(), ball1Center); + QCOMPARE(dragHandler1->point().pressPosition(), ball1Center); + QCOMPARE(dragHandler1->point().scenePosition(), ball1->mapToScene(ball1Center)); + QCOMPARE(dragHandler1->point().scenePressPosition(), scenePressPos1); + QCOMPARE(dragHandler1->point().sceneGrabPosition(), sceneGrabPos1); + QCOMPARE(dragHandler1->translation().x(), dragThreshold + 20.0); + QCOMPARE(dragHandler1->translation().y(), 0.0); + QCOMPARE(dragHandler2->point().position(), ball2Center); + QCOMPARE(dragHandler2->point().pressPosition(), ball2Center); + QCOMPARE(dragHandler2->point().scenePosition(), ball2->mapToScene(ball2Center)); + QCOMPARE(dragHandler2->point().scenePressPosition(), scenePressPos2); + QCOMPARE(dragHandler2->point().sceneGrabPosition(), sceneGrabPos2); + QCOMPARE(dragHandler2->translation().x(), 0.0); + QCOMPARE(dragHandler2->translation().y(), dragThreshold + 20.0); + QTest::touchEvent(window, touchDevice).release(1, p1, window).stationary(2); + QQuickTouchUtils::flush(window); + QTRY_VERIFY(!dragHandler1->active()); + QVERIFY(dragHandler2->active()); + QCOMPARE(dragHandler1->point().pressedButtons(), Qt::NoButton); + QCOMPARE(ball1->mapToScene(ball1Center).toPoint(), p1); + QCOMPARE(translationChangedSpy1.count(), 1); + QTest::touchEvent(window, touchDevice).release(2, p2, window); + QQuickTouchUtils::flush(window); + QTRY_VERIFY(!dragHandler2->active()); + QCOMPARE(ball2->mapToScene(ball2Center).toPoint(), p2); + QCOMPARE(translationChangedSpy2.count(), 1); +} + +void tst_DragHandler::touchDragMultiSliders_data() +{ + QTest::addColumn("sliderRow"); + QTest::addColumn >("whichSliders"); + QTest::addColumn >("startingCenterOffsets"); + QTest::addColumn >("movements"); + + QTest::newRow("Drag Knob: start on the knobs, drag down") << + 0 << QVector { 0, 1, 2 } << QVector { 0, 0, 0 } << QVector { {0, 60}, {0, 60}, {0, 60} }; + QTest::newRow("Drag Knob: start on the knobs, drag diagonally downward") << + 0 << QVector { 0, 1, 2 } << QVector { 0, 0, 0 } << QVector { {20, 40}, {20, 60}, {20, 80} }; + // TOOD these fail +// QTest::newRow("Drag Anywhere: start on the knobs, drag down") << +// 1 << QVector { 0, 1, 2 } << QVector { 0, 0, 0 } << QVector { {0, 60}, {0, 60}, {0, 60} }; +// QTest::newRow("Drag Anywhere: start on the knobs, drag diagonally downward") << +// 1 << QVector { 0, 1, 2 } << QVector { 0, 0, 0 } << QVector { {20, 40}, {20, 60}, {20, 80} }; + // TODO these next two fail because the DragHandler grabs when a finger + // drags across it from outside, but should rather start only if it is pressed inside +// QTest::newRow("Drag Knob: start above the knobs, drag down") << +// 0 << QVector { 0, 1, 2 } << QVector { -30, -30, -30 } << QVector { {0, 40}, {0, 60}, {0, 80} }; +// QTest::newRow("Drag Knob: start above the knobs, drag diagonally downward") << +// 0 << QVector { 0, 1, 2 } << QVector { -30, -30, -30 } << QVector { {20, 40}, {20, 60}, {20, 80} }; + QTest::newRow("Drag Anywhere: start above the knobs, drag down") << + 1 << QVector { 0, 1, 2 } << QVector { -20, -30, -40 } << QVector { {0, 60}, {0, 60}, {0, 60} }; + QTest::newRow("Drag Anywhere: start above the knobs, drag diagonally downward") << + 1 << QVector { 0, 1, 2 } << QVector { -20, -30, -40 } << QVector { {20, 40}, {20, 60}, {20, 80} }; +} + +void tst_DragHandler::touchDragMultiSliders() +{ + QFETCH(int, sliderRow); + QFETCH(QVector, whichSliders); + QFETCH(QVector, startingCenterOffsets); + QFETCH(QVector, movements); + const int moveCount = 8; + + QScopedPointer windowPtr; + createView(windowPtr, "multipleSliders.qml"); + QQuickView * window = windowPtr.data(); + QTest::QTouchEventSequence touch = QTest::touchEvent(window, touchDevice); + + QQuickRepeater *rowRepeater = window->rootObject()->findChildren()[sliderRow]; + QVector knobs; + QVector dragHandlers; + QVector tapHandlers; + QVector startPoints; + for (int sli : whichSliders) { + QQuickItem *slider = rowRepeater->itemAt(sli); + QVERIFY(slider); + dragHandlers << slider->findChild(); + QVERIFY(dragHandlers[sli]); + tapHandlers << slider->findChild(); + QVERIFY(tapHandlers[sli]); + knobs << tapHandlers[sli]->parentItem(); + QPointF startPoint = knobs[sli]->mapToScene(knobs[sli]->clipRect().center()); + startPoint.setY(startPoint.y() + startingCenterOffsets[sli]); + startPoints << startPoint; + qCDebug(lcPointerTests) << "row" << sliderRow << "slider" << sli << slider->objectName() << + "start" << startingCenterOffsets[sli] << startPoints[sli]; + } + QVector touchPoints = startPoints; + + // Press + for (int sli : whichSliders) + touch.press(sli, touchPoints[sli].toPoint()); + touch.commit(); + + // Moves + for (int m = 0; m < moveCount; ++m) { + for (int sli : whichSliders) { + QVector2D incr = movements[sli] / moveCount; + touchPoints[sli] += incr.toPointF(); + touch.move(sli, touchPoints[sli].toPoint()); + } + touch.commit(); + QQuickTouchUtils::flush(window); + } + + // Check that they moved to where they should: since the slider is constrained, + // only the y component should have an effect; knobs should not come out of their "grooves" + for (int sli : whichSliders) { + QPoint endPosition = knobs[sli]->mapToScene(knobs[sli]->clipRect().center()).toPoint(); + QPoint expectedEndPosition(startPoints[sli].x(), startPoints[sli].y() + movements[sli].y()); + if (sliderRow == 0 && qAbs(startingCenterOffsets[sli]) > knobs[sli]->height() / 2) + expectedEndPosition = startPoints[sli].toPoint(); + qCDebug(lcPointerTests) << "slider " << knobs[sli]->objectName() << "started @" << startPoints[sli] + << "tried to move by" << movements[sli] << "ended up @" << endPosition << "expected" << expectedEndPosition; + QTRY_COMPARE(endPosition, expectedEndPosition); + } + + // Release + for (int sli : whichSliders) + touch.release(sli, touchPoints[sli].toPoint()); + touch.commit(); +} + +QTEST_MAIN(tst_DragHandler) + +#include "tst_qquickdraghandler.moc" + -- cgit v1.2.3 From 3c778cfb8361f1afdd81feb4eaed91473ccc1f93 Mon Sep 17 00:00:00 2001 From: Jan Arve Saether Date: Tue, 30 May 2017 15:16:49 +0200 Subject: Update according to new "point" API of single handler Change-Id: Ia67dd04333a7879362819e1bb2a891c1f92b7069 Reviewed-by: Shawn Rutledge --- tests/auto/quick/pointerhandlers/qquickdraghandler/data/draggables.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tests') diff --git a/tests/auto/quick/pointerhandlers/qquickdraghandler/data/draggables.qml b/tests/auto/quick/pointerhandlers/qquickdraghandler/data/draggables.qml index cfacd69858..5ed9bd1523 100644 --- a/tests/auto/quick/pointerhandlers/qquickdraghandler/data/draggables.qml +++ b/tests/auto/quick/pointerhandlers/qquickdraghandler/data/draggables.qml @@ -65,7 +65,7 @@ Item { Text { color: "white" anchors.centerIn: parent - text: dragHandler.pos.x.toFixed(1) + "," + dragHandler.pos.y.toFixed(1) + text: dragHandler.point.position.x.toFixed(1) + "," + dragHandler.point.position.y.toFixed(1) } } } -- cgit v1.2.3 From 1b0c9b46ce13b0f9c533f18fb420ff10ad56e4f6 Mon Sep 17 00:00:00 2001 From: Jan Arve Saether Date: Thu, 27 Jul 2017 10:42:04 +0200 Subject: Fix some bugs related to child mouse filtering - Only abort event delivery early if event that got filtered was accepted (previously we aborted as soon as the event got filtered, even if the event was filtered, but explicitly *not* accepted) - If the event that got filtered was *not* accepted, we do not abort event delivery, but we need to remove the item from the list of target items that we will deliver to later - If childMouseEventFilter returns true it should not automatically mean that the event was accepted. Change-Id: I2f2415379061131af1d5102e03d01f010e1a8168 Reviewed-by: Frederik Gladhorn --- tests/auto/quick/qquickwindow/tst_qquickwindow.cpp | 80 ++++++++++++++++++++++ 1 file changed, 80 insertions(+) (limited to 'tests') diff --git a/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp b/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp index 0c341b2663..2133b4d2d3 100644 --- a/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp +++ b/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp @@ -37,6 +37,7 @@ #include #include #include +#include #include "../../shared/util.h" #include "../shared/visualtestutil.h" #include "../shared/viewtestutil.h" @@ -381,6 +382,7 @@ private slots: void testHoverChildMouseEventFilter(); void testHoverTimestamp(); + void test_circleMapItem(); void pointerEventTypeAndPointCount(); @@ -2553,6 +2555,84 @@ void tst_qquickwindow::testHoverTimestamp() QCOMPARE(hoverConsumer->hoverTimestamps.last(), 5UL); } +class CircleItem : public QQuickRectangle +{ +public: + CircleItem(QQuickItem *parent = 0) : QQuickRectangle(parent) { } + + void setRadius(qreal radius) { + const qreal diameter = radius*2; + setWidth(diameter); + setHeight(diameter); + } + + bool childMouseEventFilter(QQuickItem *item, QEvent *event) override + { + Q_UNUSED(item) + if (event->type() == QEvent::MouseButtonPress && !contains(static_cast(event)->pos())) { + // This is an evil hack: in case of items that are not rectangles, we never accept the event. + // Instead the events are now delivered to QDeclarativeGeoMapItemBase which doesn't to anything with them. + // The map below it still works since it filters events and steals the events at some point. + event->setAccepted(false); + return true; + } + return false; + } + + virtual bool contains(const QPointF &pos) const override { + // returns true if the point is inside the the embedded circle inside the (square) rect + const float radius = (float)width()/2; + const QVector2D center(radius, radius); + const QVector2D dx = QVector2D(pos) - center; + const bool ret = dx.lengthSquared() < radius*radius; + return ret; + } +}; + +void tst_qquickwindow::test_circleMapItem() +{ + QQuickWindow window; + + window.resize(250, 250); + window.setPosition(100, 100); + window.setTitle(QTest::currentTestFunction()); + + QQuickItem *root = window.contentItem(); + QQuickMouseArea *mab = new QQuickMouseArea(root); + mab->setObjectName("Bottom MouseArea"); + mab->setSize(QSizeF(100, 100)); + + CircleItem *topItem = new CircleItem(root); + topItem->setFiltersChildMouseEvents(true); + topItem->setColor(Qt::green); + topItem->setObjectName("Top Item"); + topItem->setPosition(QPointF(30, 30)); + topItem->setRadius(20); + QQuickMouseArea *mat = new QQuickMouseArea(topItem); + mat->setObjectName("Top Item/MouseArea"); + mat->setSize(QSizeF(40, 40)); + + QSignalSpy bottomSpy(mab, SIGNAL(clicked(QQuickMouseEvent *))); + QSignalSpy topSpy(mat, SIGNAL(clicked(QQuickMouseEvent *))); + + window.show(); + QTest::qWaitForWindowExposed(&window); + QTest::qWait(1000); + + QPoint pos(50, 50); + QTest::mouseClick(&window, Qt::LeftButton, Qt::KeyboardModifiers(), pos); + + QCOMPARE(topSpy.count(), 1); + QCOMPARE(bottomSpy.count(), 0); + + // Outside the "Circles" "input area", but on top of the bottomItem rectangle + pos = QPoint(66, 66); + QTest::mouseClick(&window, Qt::LeftButton, Qt::KeyboardModifiers(), pos); + + QCOMPARE(bottomSpy.count(), 1); + QCOMPARE(topSpy.count(), 1); +} + void tst_qquickwindow::pointerEventTypeAndPointCount() { QPointF localPosition(33, 66); -- cgit v1.2.3