qtdeclarative/tests/auto/quick/pointerhandlers/qquicktaphandler/tst_qquicktaphandler.cpp

592 lines
27 KiB
C++
Raw Normal View History

/****************************************************************************
**
** 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 <QtTest/QtTest>
#include <QtGui/qstylehints.h>
#include <QtQuick/qquickview.h>
#include <QtQuick/qquickitem.h>
#include <QtQuick/private/qquickpointerhandler_p.h>
#include <QtQuick/private/qquicktaphandler_p.h>
#include <qpa/qwindowsysteminterface.h>
#include <private/qquickwindow_p.h>
#include <QtQml/qqmlengine.h>
#include <QtQml/qqmlproperty.h>
#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<QQuickView> &window, const char *fileName);
QTouchDevice *touchDevice;
};
void tst_TapHandler::createView(QScopedPointer<QQuickView> &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<QQuickView> windowPtr;
createView(windowPtr, "buttons.qml");
QQuickView * window = windowPtr.data();
QQuickItem *buttonDragThreshold = window->rootObject()->findChild<QQuickItem*>("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<QQuickView> windowPtr;
createView(windowPtr, "buttons.qml");
QQuickView * window = windowPtr.data();
QQuickItem *buttonDragThreshold = window->rootObject()->findChild<QQuickItem*>("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<QQuickView> windowPtr;
createView(windowPtr, "buttons.qml");
QQuickView * window = windowPtr.data();
QQuickItem *buttonWithinBounds = window->rootObject()->findChild<QQuickItem*>("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<QQuickView> windowPtr;
createView(windowPtr, "buttons.qml");
QQuickView * window = windowPtr.data();
QQuickItem *buttonWithinBounds = window->rootObject()->findChild<QQuickItem*>("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<QQuickView> windowPtr;
createView(windowPtr, "buttons.qml");
QQuickView * window = windowPtr.data();
QQuickItem *buttonReleaseWithinBounds = window->rootObject()->findChild<QQuickItem*>("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<QQuickView> windowPtr;
createView(windowPtr, "buttons.qml");
QQuickView * window = windowPtr.data();
QQuickItem *buttonReleaseWithinBounds = window->rootObject()->findChild<QQuickItem*>("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<QQuickView> windowPtr;
createView(windowPtr, "buttons.qml");
QQuickView * window = windowPtr.data();
QQuickItem *button = window->rootObject()->findChild<QQuickItem*>("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<QQuickView> windowPtr;
createView(windowPtr, "buttons.qml");
QQuickView * window = windowPtr.data();
QQuickItem *button = window->rootObject()->findChild<QQuickItem*>("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<QQuickView> windowPtr;
createView(windowPtr, "buttons.qml");
QQuickView * window = windowPtr.data();
QQuickItem *button = window->rootObject()->findChild<QQuickItem*>("DragThreshold");
QVERIFY(button);
QQuickTapHandler *tapHandler = button->findChild<QQuickTapHandler*>("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<QQuickView> windowPtr;
createView(windowPtr, "buttons.qml");
QQuickView * window = windowPtr.data();
QQuickItem *button = window->rootObject()->findChild<QQuickItem*>("DragThreshold");
QVERIFY(button);
QQuickTapHandler *tapHandler = button->findChild<QQuickTapHandler*>("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<QQuickView> windowPtr;
createView(windowPtr, "buttons.qml");
QQuickView * window = windowPtr.data();
QQuickItem *buttonDragThreshold = window->rootObject()->findChild<QQuickItem*>("DragThreshold");
QVERIFY(buttonDragThreshold);
QSignalSpy dragThresholdTappedSpy(buttonDragThreshold, SIGNAL(tapped()));
QQuickItem *buttonWithinBounds = window->rootObject()->findChild<QQuickItem*>("WithinBounds");
QVERIFY(buttonWithinBounds);
QSignalSpy withinBoundsTappedSpy(buttonWithinBounds, SIGNAL(tapped()));
QQuickItem *buttonReleaseWithinBounds = window->rootObject()->findChild<QQuickItem*>("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"