aboutsummaryrefslogtreecommitdiffstats
path: root/tests/auto/quick/pointerhandlers/flickableinterop/tst_flickableinterop.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tests/auto/quick/pointerhandlers/flickableinterop/tst_flickableinterop.cpp')
-rw-r--r--tests/auto/quick/pointerhandlers/flickableinterop/tst_flickableinterop.cpp319
1 files changed, 242 insertions, 77 deletions
diff --git a/tests/auto/quick/pointerhandlers/flickableinterop/tst_flickableinterop.cpp b/tests/auto/quick/pointerhandlers/flickableinterop/tst_flickableinterop.cpp
index 869ba80658..790c7c771e 100644
--- a/tests/auto/quick/pointerhandlers/flickableinterop/tst_flickableinterop.cpp
+++ b/tests/auto/quick/pointerhandlers/flickableinterop/tst_flickableinterop.cpp
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 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$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtTest/QtTest>
@@ -36,6 +11,7 @@
#include <QtQuick/private/qquickitemview_p.h>
#include <QtQuick/private/qquickpointerhandler_p.h>
#include <QtQuick/private/qquickdraghandler_p.h>
+#include <QtQuick/private/qquickpinchhandler_p.h>
#include <QtQuick/private/qquicktaphandler_p.h>
#include <QtQuick/private/qquicktableview_p.h>
#include <qpa/qwindowsysteminterface.h>
@@ -45,8 +21,8 @@
#include <QtQml/qqmlengine.h>
#include <QtQml/qqmlproperty.h>
-#include "../../../shared/util.h"
-#include "../../shared/viewtestutil.h"
+#include <QtQuickTestUtils/private/qmlutils_p.h>
+#include <QtQuickTestUtils/private/viewtestutils_p.h>
Q_LOGGING_CATEGORY(lcPointerTests, "qt.quick.pointer.tests")
@@ -55,7 +31,7 @@ class tst_FlickableInterop : public QQmlDataTest
Q_OBJECT
public:
tst_FlickableInterop()
- :touchDevice(QTest::createTouchDevice())
+ : QQmlDataTest(QT_QMLTEST_DATADIR)
{}
private slots:
@@ -79,10 +55,15 @@ private slots:
void touchDragSliderAndFlickable();
void touchAndDragHandlerOnFlickable_data();
void touchAndDragHandlerOnFlickable();
+ void pinchHandlerOnFlickable();
+ void nativeGesturePinchOnFlickableWithParentTapHandler_data();
+ void nativeGesturePinchOnFlickableWithParentTapHandler();
private:
void createView(QScopedPointer<QQuickView> &window, const char *fileName);
- QPointingDevice *touchDevice;
+ QScopedPointer<QPointingDevice> touchDevice = QScopedPointer<QPointingDevice>(QTest::createTouchDevice());
+ QScopedPointer<QPointingDevice> touchpad = QScopedPointer<QPointingDevice>(
+ QTest::createTouchDevice(QInputDevice::DeviceType::TouchPad));
};
void tst_FlickableInterop::createView(QScopedPointer<QQuickView> &window, const char *fileName)
@@ -90,8 +71,8 @@ void tst_FlickableInterop::createView(QScopedPointer<QQuickView> &window, const
window.reset(new QQuickView);
window->setSource(testFileUrl(fileName));
QTRY_COMPARE(window->status(), QQuickView::Ready);
- QQuickViewTestUtil::centerOnScreen(window.data());
- QQuickViewTestUtil::moveMouseAway(window.data());
+ QQuickViewTestUtils::centerOnScreen(window.data());
+ QQuickViewTestUtils::moveMouseAway(window.data());
window->show();
QVERIFY(QTest::qWaitForWindowActive(window.data()));
@@ -121,27 +102,27 @@ void tst_FlickableInterop::touchTapButton()
// 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);
+ QTest::touchEvent(window, touchDevice.get()).press(1, p1, window);
QQuickTouchUtils::flush(window);
QTRY_VERIFY(button->property("pressed").toBool());
- QTest::touchEvent(window, touchDevice).release(1, p1, window);
+ QTest::touchEvent(window, touchDevice.get()).release(1, p1, window);
QQuickTouchUtils::flush(window);
QTRY_VERIFY(!button->property("pressed").toBool());
- QCOMPARE(tappedSpy.count(), 1);
+ QCOMPARE(tappedSpy.size(), 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);
+ QTest::touchEvent(window, touchDevice.get()).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);
+ QTest::touchEvent(window, touchDevice.get()).move(1, p1, window);
QQuickTouchUtils::flush(window);
QVERIFY(button->property("pressed").toBool());
- QTest::touchEvent(window, touchDevice).release(1, p1, window);
+ QTest::touchEvent(window, touchDevice.get()).release(1, p1, window);
QQuickTouchUtils::flush(window);
QTRY_VERIFY(!button->property("pressed").toBool());
- QCOMPARE(tappedSpy.count(), 2);
+ QCOMPARE(tappedSpy.size(), 2);
}
void tst_FlickableInterop::touchDragFlickableBehindButton_data()
@@ -169,11 +150,11 @@ void tst_FlickableInterop::touchDragFlickableBehindButton()
tappedSpy.clear();
QPoint p1 = button->mapToScene(QPointF(20, 20)).toPoint();
- QTest::touchEvent(window, touchDevice).press(1, p1, window);
+ QTest::touchEvent(window, touchDevice.get()).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);
+ QTest::touchEvent(window, touchDevice.get()).move(1, p1, window);
QQuickTouchUtils::flush(window);
QVERIFY(button->property("pressed").toBool());
int i = 0;
@@ -181,17 +162,17 @@ void tst_FlickableInterop::touchDragFlickableBehindButton()
// 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);
+ QTest::touchEvent(window, touchDevice.get()).move(1, p1, window);
QQuickTouchUtils::flush(window);
}
qCDebug(lcPointerTests) << "flickable started moving after" << i << "moves, when we got to" << p1;
QVERIFY(flickable->isMoving());
QCOMPARE(i, 2);
QVERIFY(!button->property("pressed").toBool());
- QTest::touchEvent(window, touchDevice).release(1, p1, window);
+ QTest::touchEvent(window, touchDevice.get()).release(1, p1, window);
QQuickTouchUtils::flush(window);
QVERIFY(!button->property("pressed").toBool());
- QCOMPARE(tappedSpy.count(), 0);
+ QCOMPARE(tappedSpy.size(), 0);
}
void tst_FlickableInterop::mouseClickButton_data()
@@ -221,7 +202,7 @@ void tst_FlickableInterop::mouseClickButton()
QTRY_VERIFY(button->property("pressed").toBool());
QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p1);
QTRY_VERIFY(!button->property("pressed").toBool());
- QCOMPARE(tappedSpy.count(), 1);
+ QCOMPARE(tappedSpy.size(), 1);
// We can drag <= dragThreshold and the button still acts normal, Flickable doesn't grab
p1 = button->mapToScene(QPointF(20, 20)).toPoint();
@@ -232,7 +213,7 @@ void tst_FlickableInterop::mouseClickButton()
QVERIFY(button->property("pressed").toBool());
QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p1);
QTRY_VERIFY(!button->property("pressed").toBool());
- QCOMPARE(tappedSpy.count(), 2);
+ QCOMPARE(tappedSpy.size(), 2);
}
void tst_FlickableInterop::mouseDragFlickableBehindButton_data()
@@ -265,7 +246,7 @@ void tst_FlickableInterop::mouseDragFlickableBehindButton()
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);
+ QTest::touchEvent(window, touchDevice.get()).move(1, p1, window);
QVERIFY(button->property("pressed").toBool());
int i = 0;
for (; i < 100 && !flickable->isMoving(); ++i) {
@@ -278,7 +259,7 @@ void tst_FlickableInterop::mouseDragFlickableBehindButton()
QVERIFY(!button->property("pressed").toBool());
QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p1);
QVERIFY(!button->property("pressed").toBool());
- QCOMPARE(tappedSpy.count(), 0);
+ QCOMPARE(tappedSpy.size(), 0);
}
void tst_FlickableInterop::touchDragSlider()
@@ -297,24 +278,24 @@ void tst_FlickableInterop::touchDragSlider()
QQuickFlickable *flickable = window->rootObject()->findChild<QQuickFlickable*>();
QVERIFY(flickable);
QSignalSpy tappedSpy(knob->parent(), SIGNAL(tapped()));
- QSignalSpy translationChangedSpy(drag, SIGNAL(translationChanged()));
+ QSignalSpy translationChangedSpy(drag, &QQuickDragHandler::translationChanged);
// Drag the slider in the allowed (vertical) direction
tappedSpy.clear();
QPoint p1 = knob->mapToScene(knob->clipRect().center()).toPoint() - QPoint(0, 8);
- QTest::touchEvent(window, touchDevice).press(1, p1, window);
+ QTest::touchEvent(window, touchDevice.get()).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);
+ QTest::touchEvent(window, touchDevice.get()).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);
+ QTest::touchEvent(window, touchDevice.get()).move(1, p1, window);
QQuickTouchUtils::flush(window);
p1 += QPoint(0, 10);
- QTest::touchEvent(window, touchDevice).move(1, p1, window);
+ QTest::touchEvent(window, touchDevice.get()).move(1, p1, window);
QQuickTouchUtils::flush(window);
QVERIFY(slider->property("value").toInt() < 49);
QVERIFY(!flickable->isMoving());
@@ -323,15 +304,15 @@ void tst_FlickableInterop::touchDragSlider()
// 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);
+ QTest::touchEvent(window, touchDevice.get()).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);
+ QTest::touchEvent(window, touchDevice.get()).release(1, p1, window);
QQuickTouchUtils::flush(window);
- QCOMPARE(tappedSpy.count(), 0);
- QCOMPARE(translationChangedSpy.count(), 1);
+ QCOMPARE(tappedSpy.size(), 0);
+ QCOMPARE(translationChangedSpy.size(), 1);
}
void tst_FlickableInterop::mouseDragSlider_data()
@@ -377,7 +358,7 @@ void tst_FlickableInterop::mouseDragSlider()
QQuickFlickable *flickable = window->rootObject()->findChild<QQuickFlickable*>();
QVERIFY(flickable);
QSignalSpy tappedSpy(knob->parent(), SIGNAL(tapped()));
- QSignalSpy translationChangedSpy(drag, SIGNAL(translationChanged()));
+ QSignalSpy translationChangedSpy(drag, &QQuickDragHandler::translationChanged);
// Drag the slider
tappedSpy.clear();
@@ -415,8 +396,8 @@ void tst_FlickableInterop::mouseDragSlider()
// Release, and do not expect the tapped signal
QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p1);
- QCOMPARE(tappedSpy.count(), 0);
- QCOMPARE(translationChangedSpy.count(), expectedDragHandlerActive ? 1 : 0);
+ QCOMPARE(tappedSpy.size(), 0);
+ QCOMPARE(translationChangedSpy.size(), expectedDragHandlerActive ? 1 : 0);
}
void tst_FlickableInterop::touchDragFlickableBehindSlider()
@@ -435,34 +416,34 @@ void tst_FlickableInterop::touchDragFlickableBehindSlider()
QQuickFlickable *flickable = window->rootObject()->findChild<QQuickFlickable*>();
QVERIFY(flickable);
QSignalSpy tappedSpy(knob->parent(), SIGNAL(tapped()));
- QSignalSpy translationChangedSpy(drag, SIGNAL(translationChanged()));
+ QSignalSpy translationChangedSpy(drag, &QQuickDragHandler::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);
+ QTest::touchEvent(window, touchDevice.get()).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);
+ QTest::touchEvent(window, touchDevice.get()).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);
+ QTest::touchEvent(window, touchDevice.get()).move(1, p1, window);
QQuickTouchUtils::flush(window);
}
qCDebug(lcPointerTests) << "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);
+ QTest::touchEvent(window, touchDevice.get()).release(1, p1, window);
QQuickTouchUtils::flush(window);
QVERIFY(!slider->property("pressed").toBool());
- QCOMPARE(tappedSpy.count(), 0);
- QCOMPARE(translationChangedSpy.count(), 0);
+ QCOMPARE(tappedSpy.size(), 0);
+ QCOMPARE(translationChangedSpy.size(), 0);
}
void tst_FlickableInterop::mouseDragFlickableBehindSlider()
@@ -481,7 +462,7 @@ void tst_FlickableInterop::mouseDragFlickableBehindSlider()
QQuickFlickable *flickable = window->rootObject()->findChild<QQuickFlickable*>();
QVERIFY(flickable);
QSignalSpy tappedSpy(knob->parent(), SIGNAL(tapped()));
- QSignalSpy translationChangedSpy(drag, SIGNAL(translationChanged()));
+ QSignalSpy translationChangedSpy(drag, &QQuickDragHandler::translationChanged);
// Button is no longer pressed if touchpoint goes beyond dragThreshold,
// because Flickable steals the grab
@@ -503,8 +484,8 @@ void tst_FlickableInterop::mouseDragFlickableBehindSlider()
QCOMPARE(i, 2);
QVERIFY(!slider->property("pressed").toBool());
QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p1);
- QCOMPARE(tappedSpy.count(), 0);
- QCOMPARE(translationChangedSpy.count(), 0);
+ QCOMPARE(tappedSpy.size(), 0);
+ QCOMPARE(translationChangedSpy.size(), 0);
}
void tst_FlickableInterop::touchDragFlickableBehindItemWithHandlers_data()
@@ -532,19 +513,19 @@ void tst_FlickableInterop::touchDragFlickableBehindItemWithHandlers()
QPoint p1 = rect->mapToScene(rect->clipRect().center()).toPoint();
QPoint originP1 = p1;
- QTest::touchEvent(window, touchDevice).press(1, p1, window);
+ QTest::touchEvent(window, touchDevice.get()).press(1, p1, window);
QQuickTouchUtils::flush(window);
for (int i = 0; i < dragThreshold * 3; ++i) {
p1 = originP1;
p1.rx() += i;
- QTest::touchEvent(window, touchDevice).move(1, p1, window);
+ QTest::touchEvent(window, touchDevice.get()).move(1, p1, window);
QQuickTouchUtils::flush(window);
}
QCOMPARE(flickable->isMoving(), expectedFlickableMoving);
if (!expectedFlickableMoving) {
QVERIFY(rect->mapToScene(rect->clipRect().center()).toPoint().x() > originP1.x());
}
- QTest::touchEvent(window, touchDevice).release(1, p1, window);
+ QTest::touchEvent(window, touchDevice.get()).release(1, p1, window);
QQuickTouchUtils::flush(window);
}
@@ -609,7 +590,7 @@ void tst_FlickableInterop::touchDragSliderAndFlickable()
QVERIFY(knob);
QQuickFlickable *flickable = window->rootObject()->findChild<QQuickFlickable*>();
QVERIFY(flickable);
- QTest::QTouchEventSequence touchSeq = QTest::touchEvent(window, touchDevice, false);
+ QTest::QTouchEventSequence touchSeq = QTest::touchEvent(window, touchDevice.get(), false);
// The knob is initially centered over the slider's "groove"
qreal initialXOffset = qAbs(knob->mapToScene(knob->clipRect().center()).x() - slider->mapToScene
@@ -647,7 +628,10 @@ void tst_FlickableInterop::touchDragSliderAndFlickable()
QQuickTouchUtils::flush(window);
qCDebug(lcPointerTests) << "step" << i << ": fingers @" << p1 << p2 << "is Flickable moving yet?" << flickable->isMoving();
}
- QVERIFY(flickable->isMoving());
+ // In Qt 6, Flickable doesn't see the second touchpoint, so it doesn't move.
+ // One way to see this is that Flickable is more immune to stray touches than it otherwise would be.
+ // But time will tell if we are missing out on something useful, which was possible in Qt 5 (QTBUG-123490).
+ QCOMPARE(flickable->isMoving(), false);
qreal knobSliderXOffset = qAbs(knob->mapToScene(knob->clipRect().center()).toPoint().x() -
slider->mapToScene(slider->clipRect().center()).toPoint().x()) - initialXOffset;
if (knobSliderXOffset > 1)
@@ -739,7 +723,7 @@ void tst_FlickableInterop::touchAndDragHandlerOnFlickable()
}
// Drag one finger on the Flickable (between delegates) and make sure it flicks
- QTest::QTouchEventSequence touchSeq = QTest::touchEvent(window, touchDevice, false);
+ QTest::QTouchEventSequence touchSeq = QTest::touchEvent(window, touchDevice.get(), false);
QPoint p1(780, 460);
if (delegate)
p1 = delegate->mapToScene(delegate->clipRect().bottomRight()).toPoint() + QPoint(-1, 1);
@@ -806,6 +790,187 @@ void tst_FlickableInterop::touchAndDragHandlerOnFlickable()
touchSeq.release(1, p1, window).commit();
}
+void tst_FlickableInterop::pinchHandlerOnFlickable()
+{
+ const int dragThreshold = QGuiApplication::styleHints()->startDragDistance();
+ QQuickView window;
+ QVERIFY(QQuickTest::showView(window, testFileUrl("pinchOnFlickable.qml")));
+ QQuickFlickable *flickable = qmlobject_cast<QQuickFlickable*>(window.rootObject());
+ QVERIFY(flickable);
+ QQuickPointerHandler *pinchHandler = flickable->findChild<QQuickPointerHandler*>();
+ QVERIFY(pinchHandler);
+ QQuickItem *pinchable = pinchHandler->target();
+ QVERIFY(pinchable);
+
+ QSignalSpy flickMoveSpy(flickable, &QQuickFlickable::movementStarted);
+ QSignalSpy grabChangedSpy(touchDevice.get(), &QPointingDevice::grabChanged);
+
+ QObject *grabber = nullptr;
+ connect(touchDevice.get(), &QPointingDevice::grabChanged,
+ [&grabber](QObject *g, QPointingDevice::GrabTransition transition, const QPointerEvent *, const QEventPoint &) {
+ if (transition == QPointingDevice::GrabTransition::GrabExclusive)
+ grabber = g;
+ });
+
+ QPoint p0 = pinchable->mapToScene({50, 100}).toPoint();
+ QPoint p1 = pinchable->mapToScene({150, 100}).toPoint();
+ QTest::QTouchEventSequence touch = QTest::touchEvent(&window, touchDevice.get());
+
+ touch.press(0, p0, &window).press(1, p1, &window).commit();
+ QQuickTouchUtils::flush(&window);
+ int activeStep = -1;
+ int grabTransitionCount = 0;
+ // drag two fingers down: PinchHandler moves the item; Flickable doesn't grab, because there are 2 points
+ for (int i = 0; i < 4; ++i) {
+ p0 += QPoint(0, dragThreshold);
+ p1 += QPoint(0, dragThreshold);
+ touch.move(0, p0, &window).move(1, p1, &window).commit();
+ QQuickTouchUtils::flush(&window);
+ if (pinchHandler->active() && activeStep < 0) {
+ qCDebug(lcPointerTests) << "pinch began at step" << i;
+ activeStep = i;
+ QCOMPARE(grabber, pinchHandler);
+ grabTransitionCount = grabChangedSpy.count();
+ }
+ }
+ QVERIFY(pinchHandler->active());
+ QCOMPARE(grabChangedSpy.count(), grabTransitionCount);
+ QCOMPARE(grabber, pinchHandler);
+ qreal scale = pinchable->scale();
+ QCOMPARE(scale, 1);
+ qreal rot = pinchable->rotation();
+ QCOMPARE(rot, 0);
+ // start expanding and rotating
+ for (int i = 0; i < 4; ++i) {
+ p0 += QPoint(-5, 10);
+ p1 += QPoint(5, -10);
+ touch.move(0, p0, &window).move(1, p1, &window).commit();
+ QQuickTouchUtils::flush(&window);
+ QVERIFY(pinchHandler->active());
+ // PinchHandler keeps grab: no more transitions
+ QCOMPARE(grabChangedSpy.count(), grabTransitionCount);
+ QCOMPARE(grabber, pinchHandler);
+ QTRY_COMPARE_GT(pinchable->scale(), scale);
+ scale = pinchable->scale();
+ QCOMPARE_LT(pinchable->rotation(), rot);
+ rot = pinchable->rotation();
+ }
+ touch.release(0, p0, &window).release(1, p1, &window).commit();
+ QQuickTouchUtils::flush(&window);
+ QTRY_COMPARE(pinchHandler->active(), false);
+ QCOMPARE(flickMoveSpy.count(), 0); // Flickable never moved
+}
+
+void tst_FlickableInterop::nativeGesturePinchOnFlickableWithParentTapHandler_data()
+{
+ QTest::addColumn<const QPointingDevice*>("device");
+ QTest::addColumn<Qt::MouseButton>("button");
+ QTest::addColumn<Qt::NativeGestureType>("gesture");
+ QTest::addColumn<qreal>("value");
+ QTest::addColumn<qreal>("expectedPropertyValue");
+
+ const QPointingDevice *constTouchPad = touchpad.data();
+
+ QTest::newRow("touchpad: left and rotate") << constTouchPad << Qt::LeftButton << Qt::RotateNativeGesture << 5.0 << 10.0;
+ QTest::newRow("touchpad: right and rotate") << constTouchPad << Qt::RightButton << Qt::RotateNativeGesture << 5.0 << 10.0;
+ QTest::newRow("touchpad: left and scale") << constTouchPad << Qt::LeftButton << Qt::ZoomNativeGesture << 0.1 << 1.21;
+ QTest::newRow("touchpad: right and scale") << constTouchPad << Qt::RightButton << Qt::ZoomNativeGesture << 0.1 << 1.21;
+
+ const auto *mouse = QPointingDevice::primaryPointingDevice();
+ if (mouse->type() == QInputDevice::DeviceType::Mouse) {
+ QTest::newRow("mouse: left and rotate") << mouse << Qt::LeftButton << Qt::RotateNativeGesture << 5.0 << 10.0;
+ QTest::newRow("mouse: right and rotate") << mouse << Qt::RightButton << Qt::RotateNativeGesture << 5.0 << 10.0;
+ QTest::newRow("mouse: left and scale") << mouse << Qt::LeftButton << Qt::ZoomNativeGesture << 0.1 << 1.21;
+ QTest::newRow("mouse: right and scale") << mouse << Qt::RightButton << Qt::ZoomNativeGesture << 0.1 << 1.21;
+ } else {
+ qCWarning(lcPointerTests) << "skipping mouse tests: primary device is not a mouse" << mouse;
+ }
+}
+
+void tst_FlickableInterop::nativeGesturePinchOnFlickableWithParentTapHandler()
+{
+ QFETCH(const QPointingDevice*, device);
+ QFETCH(Qt::MouseButton, button);
+ QFETCH(Qt::NativeGestureType, gesture);
+ QFETCH(qreal, value);
+ QFETCH(qreal, expectedPropertyValue);
+
+ QQuickView window;
+ QVERIFY(QQuickTest::showView(window, testFileUrl("pinchOnFlickableWithParentTapHandler.qml")));
+ QQuickFlickable *flickable = window.rootObject()->findChild<QQuickFlickable*>();
+ QVERIFY(flickable);
+ QQuickPointerHandler *pinchHandler = flickable->findChild<QQuickPinchHandler*>();
+ QVERIFY(pinchHandler);
+ QQuickItem *pinchable = pinchHandler->target();
+ QVERIFY(pinchable);
+ QQuickTapHandler *tapHandler = window.rootObject()->findChild<QQuickTapHandler*>();
+ QVERIFY(tapHandler);
+ const bool expectTap = button & tapHandler->acceptedButtons();
+
+ QSignalSpy flickMoveSpy(flickable, &QQuickFlickable::movementStarted);
+ QSignalSpy grabChangedSpy(touchDevice.get(), &QPointingDevice::grabChanged);
+ QSignalSpy tapActiveSpy(tapHandler, &QQuickTapHandler::activeChanged);
+ QSignalSpy tapSpy(tapHandler, &QQuickTapHandler::tapped);
+
+ QObject *grabber = nullptr;
+ connect(device, &QPointingDevice::grabChanged,
+ [&grabber](QObject *g, QPointingDevice::GrabTransition transition, const QPointerEvent *, const QEventPoint &) {
+ if (transition == QPointingDevice::GrabTransition::GrabExclusive)
+ grabber = g;
+ });
+
+ const QPoint pinchPos(75, 75);
+ const QPoint outsidePos(200, 200);
+
+ // move to position
+ QTest::mouseMove(&window, pinchPos);
+
+ // pinch via native gesture
+ ulong ts = 502; // after the mouse move, which is at time 501 in practice
+ QWindowSystemInterface::handleGestureEvent(&window, ts++, touchpad.get(),
+ Qt::BeginNativeGesture, pinchPos, pinchPos);
+ if (lcPointerTests().isDebugEnabled()) QTest::qWait(500);
+ for (int i = 0; i < 2; ++i) {
+ QWindowSystemInterface::handleGestureEventWithRealValue(&window, ts++, touchpad.get(),
+ gesture, value, pinchPos, pinchPos);
+ }
+ if (gesture == Qt::RotateNativeGesture)
+ QTRY_COMPARE(pinchHandler->parentItem()->rotation(), expectedPropertyValue);
+ else if (gesture == Qt::ZoomNativeGesture)
+ QTRY_COMPARE(pinchHandler->parentItem()->scale(), expectedPropertyValue);
+ QVERIFY(pinchHandler->active());
+ QCOMPARE(grabChangedSpy.count(), 0);
+ QCOMPARE(grabber, nullptr);
+ if (lcPointerTests().isDebugEnabled()) QTest::qWait(500);
+ QWindowSystemInterface::handleGestureEvent(&window, ts++, touchpad.get(),
+ Qt::EndNativeGesture, pinchPos, pinchPos);
+
+ // tap in square: TapHandler detects tap iff acceptedButtons permits
+ // TODO delay; unfortunately this also begins at timestamp 502 because we don't have testlib
+ // functions to send gesture events, and QQuickTest::pointerPress() doesn't take a delay value
+ QQuickTest::pointerPress(device, &window, 0, pinchPos, button);
+ QCOMPARE(tapHandler->point().id(), expectTap ? 0 : -1);
+ QQuickTest::pointerRelease(device, &window, 0, pinchPos, button);
+ if (lcPointerTests().isDebugEnabled()) QTest::qWait(500);
+ QCOMPARE(tapSpy.size() != 0, expectTap);
+ QCOMPARE(tapActiveSpy.size(), 0);
+ QCOMPARE(tapHandler->point().id(), -1); // does not keep tracking after release
+
+ // move outside: nothing should happen;
+ // but QTBUG-108896 happened because TapHandler was setting pointInfo to track this moving point
+ QQuickTest::pointerMove(device, &window, 0, outsidePos);
+ QCOMPARE(tapHandler->point().id(), -1); // does not track after mouse move
+
+ // tap outside: nothing happens
+ tapSpy.clear();
+ tapActiveSpy.clear();
+ QQuickTest::pointerPress(device, &window, 0, outsidePos, button);
+ QQuickTest::pointerRelease(device, &window, 0, outsidePos, button);
+ if (lcPointerTests().isDebugEnabled()) QTest::qWait(500);
+ QCOMPARE(tapSpy.size(), 0);
+ QCOMPARE(tapActiveSpy.size(), 0);
+}
+
QTEST_MAIN(tst_FlickableInterop)
#include "tst_flickableinterop.moc"