1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2018 The Qt Company Ltd. |
4 | ** Contact: https://www.qt.io/licensing/ |
5 | ** |
6 | ** This file is part of the QtQml module of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ |
9 | ** Commercial License Usage |
10 | ** Licensees holding valid commercial Qt licenses may use this file in |
11 | ** accordance with the commercial license agreement provided with the |
12 | ** Software or, alternatively, in accordance with the terms contained in |
13 | ** a written agreement between you and The Qt Company. For licensing terms |
14 | ** and conditions see https://www.qt.io/terms-conditions. For further |
15 | ** information use the contact form at https://www.qt.io/contact-us. |
16 | ** |
17 | ** GNU General Public License Usage |
18 | ** Alternatively, this file may be used under the terms of the GNU |
19 | ** General Public License version 3 as published by the Free Software |
20 | ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT |
21 | ** included in the packaging of this file. Please review the following |
22 | ** information to ensure the GNU General Public License requirements will |
23 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html. |
24 | ** |
25 | ** $QT_END_LICENSE$ |
26 | ** |
27 | ****************************************************************************/ |
28 | |
29 | |
30 | #include <QtTest/QtTest> |
31 | |
32 | #include <QtGui/qstylehints.h> |
33 | #include <QtQuick/qquickview.h> |
34 | #include <QtQuick/qquickitem.h> |
35 | #include <QtQuick/private/qquickflickable_p.h> |
36 | #include <QtQuick/private/qquickitemview_p.h> |
37 | #include <QtQuick/private/qquickpointerhandler_p.h> |
38 | #include <QtQuick/private/qquickdraghandler_p.h> |
39 | #include <QtQuick/private/qquicktaphandler_p.h> |
40 | #include <QtQuick/private/qquicktableview_p.h> |
41 | #include <qpa/qwindowsysteminterface.h> |
42 | |
43 | #include <private/qquickwindow_p.h> |
44 | |
45 | #include <QtQml/qqmlengine.h> |
46 | #include <QtQml/qqmlproperty.h> |
47 | |
48 | #include "../../../shared/util.h" |
49 | #include "../../shared/viewtestutil.h" |
50 | |
51 | Q_LOGGING_CATEGORY(lcPointerTests, "qt.quick.pointer.tests" ) |
52 | |
53 | class tst_FlickableInterop : public QQmlDataTest |
54 | { |
55 | Q_OBJECT |
56 | public: |
57 | tst_FlickableInterop() |
58 | :touchDevice(QTest::createTouchDevice()) |
59 | {} |
60 | |
61 | private slots: |
62 | void touchTapButton_data(); |
63 | void touchTapButton(); |
64 | void touchDragFlickableBehindButton_data(); |
65 | void touchDragFlickableBehindButton(); |
66 | void mouseClickButton_data(); |
67 | void mouseClickButton(); |
68 | void mouseDragFlickableBehindButton_data(); |
69 | void mouseDragFlickableBehindButton(); |
70 | void touchDragSlider(); |
71 | void touchDragFlickableBehindSlider(); |
72 | void mouseDragSlider_data(); |
73 | void mouseDragSlider(); |
74 | void mouseDragFlickableBehindSlider(); |
75 | void touchDragFlickableBehindItemWithHandlers_data(); |
76 | void touchDragFlickableBehindItemWithHandlers(); |
77 | void mouseDragFlickableBehindItemWithHandlers_data(); |
78 | void mouseDragFlickableBehindItemWithHandlers(); |
79 | void touchDragSliderAndFlickable(); |
80 | void touchAndDragHandlerOnFlickable_data(); |
81 | void touchAndDragHandlerOnFlickable(); |
82 | |
83 | private: |
84 | void createView(QScopedPointer<QQuickView> &window, const char *fileName); |
85 | QTouchDevice *touchDevice; |
86 | }; |
87 | |
88 | void tst_FlickableInterop::createView(QScopedPointer<QQuickView> &window, const char *fileName) |
89 | { |
90 | window.reset(other: new QQuickView); |
91 | window->setSource(testFileUrl(fileName)); |
92 | QTRY_COMPARE(window->status(), QQuickView::Ready); |
93 | QQuickViewTestUtil::centerOnScreen(window: window.data()); |
94 | QQuickViewTestUtil::moveMouseAway(window: window.data()); |
95 | |
96 | window->show(); |
97 | QVERIFY(QTest::qWaitForWindowActive(window.data())); |
98 | QVERIFY(window->rootObject() != nullptr); |
99 | } |
100 | |
101 | void tst_FlickableInterop::touchTapButton_data() |
102 | { |
103 | QTest::addColumn<QString>(name: "buttonName" ); |
104 | QTest::newRow(dataTag: "DragThreshold" ) << QStringLiteral("DragThreshold" ); |
105 | QTest::newRow(dataTag: "WithinBounds" ) << QStringLiteral("WithinBounds" ); |
106 | QTest::newRow(dataTag: "ReleaseWithinBounds" ) << QStringLiteral("ReleaseWithinBounds" ); |
107 | } |
108 | |
109 | void tst_FlickableInterop::touchTapButton() |
110 | { |
111 | const int dragThreshold = QGuiApplication::styleHints()->startDragDistance(); |
112 | QScopedPointer<QQuickView> windowPtr; |
113 | createView(window&: windowPtr, fileName: "flickableWithHandlers.qml" ); |
114 | QQuickView * window = windowPtr.data(); |
115 | |
116 | QFETCH(QString, buttonName); |
117 | |
118 | QQuickItem *button = window->rootObject()->findChild<QQuickItem*>(aName: buttonName); |
119 | QVERIFY(button); |
120 | QSignalSpy tappedSpy(button, SIGNAL(tapped())); |
121 | |
122 | // Button changes pressed state and emits tapped on release |
123 | QPoint p1 = button->mapToScene(point: QPointF(20, 20)).toPoint(); |
124 | QTest::touchEvent(window, device: touchDevice).press(touchId: 1, pt: p1, window); |
125 | QQuickTouchUtils::flush(window); |
126 | QTRY_VERIFY(button->property("pressed" ).toBool()); |
127 | QTest::touchEvent(window, device: touchDevice).release(touchId: 1, pt: p1, window); |
128 | QQuickTouchUtils::flush(window); |
129 | QTRY_VERIFY(!button->property("pressed" ).toBool()); |
130 | QCOMPARE(tappedSpy.count(), 1); |
131 | |
132 | // We can drag <= dragThreshold and the button still acts normal, Flickable doesn't grab |
133 | p1 = button->mapToScene(point: QPointF(20, 20)).toPoint(); |
134 | QTest::touchEvent(window, device: touchDevice).press(touchId: 1, pt: p1, window); |
135 | QQuickTouchUtils::flush(window); |
136 | QTRY_VERIFY(button->property("pressed" ).toBool()); |
137 | p1 += QPoint(dragThreshold, 0); |
138 | QTest::touchEvent(window, device: touchDevice).move(touchId: 1, pt: p1, window); |
139 | QQuickTouchUtils::flush(window); |
140 | QVERIFY(button->property("pressed" ).toBool()); |
141 | QTest::touchEvent(window, device: touchDevice).release(touchId: 1, pt: p1, window); |
142 | QQuickTouchUtils::flush(window); |
143 | QTRY_VERIFY(!button->property("pressed" ).toBool()); |
144 | QCOMPARE(tappedSpy.count(), 2); |
145 | } |
146 | |
147 | void tst_FlickableInterop::touchDragFlickableBehindButton_data() |
148 | { |
149 | QTest::addColumn<QString>(name: "buttonName" ); |
150 | QTest::newRow(dataTag: "DragThreshold" ) << QStringLiteral("DragThreshold" ); |
151 | QTest::newRow(dataTag: "WithinBounds" ) << QStringLiteral("WithinBounds" ); |
152 | QTest::newRow(dataTag: "ReleaseWithinBounds" ) << QStringLiteral("ReleaseWithinBounds" ); |
153 | } |
154 | |
155 | void tst_FlickableInterop::touchDragFlickableBehindButton() |
156 | { |
157 | const int dragThreshold = QGuiApplication::styleHints()->startDragDistance(); |
158 | QScopedPointer<QQuickView> windowPtr; |
159 | createView(window&: windowPtr, fileName: "flickableWithHandlers.qml" ); |
160 | QQuickView * window = windowPtr.data(); |
161 | |
162 | QFETCH(QString, buttonName); |
163 | |
164 | QQuickItem *button = window->rootObject()->findChild<QQuickItem*>(aName: buttonName); |
165 | QVERIFY(button); |
166 | QQuickFlickable *flickable = window->rootObject()->findChild<QQuickFlickable*>(); |
167 | QVERIFY(flickable); |
168 | QSignalSpy tappedSpy(button, SIGNAL(tapped())); |
169 | |
170 | tappedSpy.clear(); |
171 | QPoint p1 = button->mapToScene(point: QPointF(20, 20)).toPoint(); |
172 | QTest::touchEvent(window, device: touchDevice).press(touchId: 1, pt: p1, window); |
173 | QQuickTouchUtils::flush(window); |
174 | QTRY_VERIFY(button->property("pressed" ).toBool()); |
175 | p1 += QPoint(dragThreshold, 0); |
176 | QTest::touchEvent(window, device: touchDevice).move(touchId: 1, pt: p1, window); |
177 | QQuickTouchUtils::flush(window); |
178 | QVERIFY(button->property("pressed" ).toBool()); |
179 | int i = 0; |
180 | // Start dragging; eventually when the touchpoint goes beyond dragThreshold, |
181 | // Button is no longer pressed because Flickable steals the grab |
182 | for (; i < 100 && !flickable->isMoving(); ++i) { |
183 | p1 += QPoint(1, 0); |
184 | QTest::touchEvent(window, device: touchDevice).move(touchId: 1, pt: p1, window); |
185 | QQuickTouchUtils::flush(window); |
186 | } |
187 | qCDebug(lcPointerTests) << "flickable started moving after" << i << "moves, when we got to" << p1; |
188 | QVERIFY(flickable->isMoving()); |
189 | QCOMPARE(i, 2); |
190 | QVERIFY(!button->property("pressed" ).toBool()); |
191 | QTest::touchEvent(window, device: touchDevice).release(touchId: 1, pt: p1, window); |
192 | QQuickTouchUtils::flush(window); |
193 | QVERIFY(!button->property("pressed" ).toBool()); |
194 | QCOMPARE(tappedSpy.count(), 0); |
195 | } |
196 | |
197 | void tst_FlickableInterop::mouseClickButton_data() |
198 | { |
199 | QTest::addColumn<QString>(name: "buttonName" ); |
200 | QTest::newRow(dataTag: "DragThreshold" ) << QStringLiteral("DragThreshold" ); |
201 | QTest::newRow(dataTag: "WithinBounds" ) << QStringLiteral("WithinBounds" ); |
202 | QTest::newRow(dataTag: "ReleaseWithinBounds" ) << QStringLiteral("ReleaseWithinBounds" ); |
203 | } |
204 | |
205 | void tst_FlickableInterop::mouseClickButton() |
206 | { |
207 | const int dragThreshold = QGuiApplication::styleHints()->startDragDistance(); |
208 | QScopedPointer<QQuickView> windowPtr; |
209 | createView(window&: windowPtr, fileName: "flickableWithHandlers.qml" ); |
210 | QQuickView * window = windowPtr.data(); |
211 | |
212 | QFETCH(QString, buttonName); |
213 | |
214 | QQuickItem *button = window->rootObject()->findChild<QQuickItem*>(aName: buttonName); |
215 | QVERIFY(button); |
216 | QSignalSpy tappedSpy(button, SIGNAL(tapped())); |
217 | |
218 | // Button changes pressed state and emits tapped on release |
219 | QPoint p1 = button->mapToScene(point: QPointF(20, 20)).toPoint(); |
220 | QTest::mousePress(window, button: Qt::LeftButton, stateKey: Qt::NoModifier, pos: p1); |
221 | QTRY_VERIFY(button->property("pressed" ).toBool()); |
222 | QTest::mouseRelease(window, button: Qt::LeftButton, stateKey: Qt::NoModifier, pos: p1); |
223 | QTRY_VERIFY(!button->property("pressed" ).toBool()); |
224 | QCOMPARE(tappedSpy.count(), 1); |
225 | |
226 | // We can drag <= dragThreshold and the button still acts normal, Flickable doesn't grab |
227 | p1 = button->mapToScene(point: QPointF(20, 20)).toPoint(); |
228 | QTest::mousePress(window, button: Qt::LeftButton, stateKey: Qt::NoModifier, pos: p1, qApp->styleHints()->mouseDoubleClickInterval() + 10); |
229 | QTRY_VERIFY(button->property("pressed" ).toBool()); |
230 | p1 += QPoint(dragThreshold, 0); |
231 | QTest::mouseMove(window, pos: p1); |
232 | QVERIFY(button->property("pressed" ).toBool()); |
233 | QTest::mouseRelease(window, button: Qt::LeftButton, stateKey: Qt::NoModifier, pos: p1); |
234 | QTRY_VERIFY(!button->property("pressed" ).toBool()); |
235 | QCOMPARE(tappedSpy.count(), 2); |
236 | } |
237 | |
238 | void tst_FlickableInterop::mouseDragFlickableBehindButton_data() |
239 | { |
240 | QTest::addColumn<QString>(name: "buttonName" ); |
241 | QTest::newRow(dataTag: "DragThreshold" ) << QStringLiteral("DragThreshold" ); |
242 | QTest::newRow(dataTag: "WithinBounds" ) << QStringLiteral("WithinBounds" ); |
243 | QTest::newRow(dataTag: "ReleaseWithinBounds" ) << QStringLiteral("ReleaseWithinBounds" ); |
244 | } |
245 | |
246 | void tst_FlickableInterop::mouseDragFlickableBehindButton() |
247 | { |
248 | const int dragThreshold = QGuiApplication::styleHints()->startDragDistance(); |
249 | QScopedPointer<QQuickView> windowPtr; |
250 | createView(window&: windowPtr, fileName: "flickableWithHandlers.qml" ); |
251 | QQuickView * window = windowPtr.data(); |
252 | |
253 | QFETCH(QString, buttonName); |
254 | |
255 | QQuickItem *button = window->rootObject()->findChild<QQuickItem*>(aName: buttonName); |
256 | QVERIFY(button); |
257 | QQuickFlickable *flickable = window->rootObject()->findChild<QQuickFlickable*>(); |
258 | QVERIFY(flickable); |
259 | QSignalSpy tappedSpy(button, SIGNAL(tapped())); |
260 | |
261 | // Button is no longer pressed if touchpoint goes beyond dragThreshold, |
262 | // because Flickable steals the grab |
263 | tappedSpy.clear(); |
264 | QPoint p1 = button->mapToScene(point: QPointF(20, 20)).toPoint(); |
265 | QTest::mousePress(window, button: Qt::LeftButton, stateKey: Qt::NoModifier, pos: p1); |
266 | QTRY_VERIFY(button->property("pressed" ).toBool()); |
267 | p1 += QPoint(dragThreshold, 0); |
268 | QTest::touchEvent(window, device: touchDevice).move(touchId: 1, pt: p1, window); |
269 | QVERIFY(button->property("pressed" ).toBool()); |
270 | int i = 0; |
271 | for (; i < 100 && !flickable->isMoving(); ++i) { |
272 | p1 += QPoint(1, 0); |
273 | QTest::mouseMove(window, pos: p1); |
274 | } |
275 | qCDebug(lcPointerTests) << "flickable started moving after" << i << "moves, when we got to" << p1; |
276 | QVERIFY(flickable->isMoving()); |
277 | QCOMPARE(i, 2); |
278 | QVERIFY(!button->property("pressed" ).toBool()); |
279 | QTest::mouseRelease(window, button: Qt::LeftButton, stateKey: Qt::NoModifier, pos: p1); |
280 | QVERIFY(!button->property("pressed" ).toBool()); |
281 | QCOMPARE(tappedSpy.count(), 0); |
282 | } |
283 | |
284 | void tst_FlickableInterop::touchDragSlider() |
285 | { |
286 | const int dragThreshold = QGuiApplication::styleHints()->startDragDistance(); |
287 | QScopedPointer<QQuickView> windowPtr; |
288 | createView(window&: windowPtr, fileName: "flickableWithHandlers.qml" ); |
289 | QQuickView * window = windowPtr.data(); |
290 | |
291 | QQuickItem *slider = window->rootObject()->findChild<QQuickItem*>(aName: "knobSlider" ); |
292 | QVERIFY(slider); |
293 | QQuickDragHandler *drag = slider->findChild<QQuickDragHandler*>(); |
294 | QVERIFY(drag); |
295 | QQuickItem *knob = slider->findChild<QQuickItem*>(aName: "Slider Knob" ); |
296 | QVERIFY(knob); |
297 | QQuickFlickable *flickable = window->rootObject()->findChild<QQuickFlickable*>(); |
298 | QVERIFY(flickable); |
299 | QSignalSpy tappedSpy(knob->parent(), SIGNAL(tapped())); |
300 | QSignalSpy translationChangedSpy(drag, SIGNAL(translationChanged())); |
301 | |
302 | // Drag the slider in the allowed (vertical) direction |
303 | tappedSpy.clear(); |
304 | QPoint p1 = knob->mapToScene(point: knob->clipRect().center()).toPoint() - QPoint(0, 8); |
305 | QTest::touchEvent(window, device: touchDevice).press(touchId: 1, pt: p1, window); |
306 | QQuickTouchUtils::flush(window); |
307 | QTRY_VERIFY(slider->property("pressed" ).toBool()); |
308 | p1 += QPoint(0, dragThreshold); |
309 | QTest::touchEvent(window, device: touchDevice).move(touchId: 1, pt: p1, window); |
310 | QQuickTouchUtils::flush(window); |
311 | QVERIFY(slider->property("pressed" ).toBool()); |
312 | QCOMPARE(slider->property("value" ).toInt(), 49); |
313 | p1 += QPoint(0, 1); |
314 | QTest::touchEvent(window, device: touchDevice).move(touchId: 1, pt: p1, window); |
315 | QQuickTouchUtils::flush(window); |
316 | p1 += QPoint(0, 10); |
317 | QTest::touchEvent(window, device: touchDevice).move(touchId: 1, pt: p1, window); |
318 | QQuickTouchUtils::flush(window); |
319 | QVERIFY(slider->property("value" ).toInt() < 49); |
320 | QVERIFY(!flickable->isMoving()); |
321 | QVERIFY(!slider->property("pressed" ).toBool()); |
322 | |
323 | // Now that the DragHandler is active, the Flickable will not steal the grab |
324 | // even if we move a large distance horizontally |
325 | p1 += QPoint(dragThreshold * 2, 0); |
326 | QTest::touchEvent(window, device: touchDevice).move(touchId: 1, pt: p1, window); |
327 | QQuickTouchUtils::flush(window); |
328 | QVERIFY(!flickable->isMoving()); |
329 | |
330 | // Release, and do not expect the tapped signal |
331 | QTest::touchEvent(window, device: touchDevice).release(touchId: 1, pt: p1, window); |
332 | QQuickTouchUtils::flush(window); |
333 | QCOMPARE(tappedSpy.count(), 0); |
334 | QCOMPARE(translationChangedSpy.count(), 1); |
335 | } |
336 | |
337 | void tst_FlickableInterop::mouseDragSlider_data() |
338 | { |
339 | QTest::addColumn<QString>(name: "nameOfSliderToDrag" ); |
340 | QTest::addColumn<QPoint>(name: "pressPositionRelativeToKnob" ); |
341 | QTest::addColumn<QPoint>(name: "dragDirection" ); // a unit vector |
342 | QTest::addColumn<bool>(name: "expectedTapHandlerPressed" ); |
343 | QTest::addColumn<bool>(name: "expectedDragHandlerActive" ); |
344 | QTest::addColumn<bool>(name: "expectedFlickableMoving" ); |
345 | |
346 | QTest::newRow(dataTag: "drag down on knob of knobSlider" ) << "knobSlider" << QPoint(0, -8) << QPoint(0, 1) << true << true << false; |
347 | QTest::newRow(dataTag: "drag sideways on knob of knobSlider" ) << "knobSlider" << QPoint(0, 0) << QPoint(1, 0) << true << false << true; |
348 | QTest::newRow(dataTag: "drag down on groove of knobSlider" ) << "knobSlider" << QPoint(0, 20) << QPoint(0, 1) << false << false << true; |
349 | QTest::newRow(dataTag: "drag sideways on groove of knobSlider" ) << "knobSlider" << QPoint(0, 20) << QPoint(1, 0) << false << false << true; |
350 | |
351 | QTest::newRow(dataTag: "drag down on knob of grooveSlider" ) << "grooveSlider" << QPoint(0, -8) << QPoint(0, 1) << true << true << false; |
352 | QTest::newRow(dataTag: "drag sideways on knob of grooveSlider" ) << "grooveSlider" << QPoint(0, 0) << QPoint(1, 0) << true << false << true; |
353 | QTest::newRow(dataTag: "drag down on groove of grooveSlider" ) << "grooveSlider" << QPoint(0, 20) << QPoint(0, 1) << false << true << false; |
354 | QTest::newRow(dataTag: "drag sideways on groove of grooveSlider" ) << "grooveSlider" << QPoint(0, 20) << QPoint(1, 0) << false << false << true; |
355 | } |
356 | |
357 | void tst_FlickableInterop::mouseDragSlider() |
358 | { |
359 | const int dragThreshold = QGuiApplication::styleHints()->startDragDistance(); |
360 | QScopedPointer<QQuickView> windowPtr; |
361 | createView(window&: windowPtr, fileName: "flickableWithHandlers.qml" ); |
362 | QQuickView * window = windowPtr.data(); |
363 | |
364 | QFETCH(QString, nameOfSliderToDrag); |
365 | QFETCH(QPoint, pressPositionRelativeToKnob); |
366 | QFETCH(QPoint, dragDirection); // a unit vector |
367 | QFETCH(bool, expectedTapHandlerPressed); |
368 | QFETCH(bool, expectedDragHandlerActive); |
369 | QFETCH(bool, expectedFlickableMoving); |
370 | |
371 | QQuickItem *slider = window->rootObject()->findChild<QQuickItem*>(aName: nameOfSliderToDrag); |
372 | QVERIFY(slider); |
373 | QQuickDragHandler *drag = slider->findChild<QQuickDragHandler*>(); |
374 | QVERIFY(drag); |
375 | QQuickItem *knob = slider->findChild<QQuickItem*>(aName: "Slider Knob" ); |
376 | QVERIFY(knob); |
377 | QQuickFlickable *flickable = window->rootObject()->findChild<QQuickFlickable*>(); |
378 | QVERIFY(flickable); |
379 | QSignalSpy tappedSpy(knob->parent(), SIGNAL(tapped())); |
380 | QSignalSpy translationChangedSpy(drag, SIGNAL(translationChanged())); |
381 | |
382 | // Drag the slider |
383 | tappedSpy.clear(); |
384 | QPoint p1 = knob->mapToScene(point: knob->clipRect().center()).toPoint() + pressPositionRelativeToKnob; |
385 | QTest::mousePress(window, button: Qt::LeftButton, stateKey: Qt::NoModifier, pos: p1); |
386 | QTRY_COMPARE(slider->property("pressed" ).toBool(), expectedTapHandlerPressed); |
387 | p1 += QPoint(dragThreshold * dragDirection.x(), dragThreshold * dragDirection.y()); |
388 | QTest::mouseMove(window, pos: p1); |
389 | QCOMPARE(drag->active(), false); |
390 | QCOMPARE(slider->property("pressed" ).toBool(), expectedTapHandlerPressed); |
391 | QCOMPARE(slider->property("value" ).toInt(), 49); |
392 | p1 += dragDirection; // one more pixel |
393 | QTest::mouseMove(window, pos: p1); |
394 | // After moving by the drag threshold, the point should still be inside the knob. |
395 | // However, QQuickTapHandler::wantsEventPoint() returns false because the drag threshold is exceeded. |
396 | // Therefore QQuickTapHandler::setPressed(false, true, point) is called: the active state is canceled. |
397 | QCOMPARE(slider->property("pressed" ).toBool(), false); |
398 | QCOMPARE(drag->active(), expectedDragHandlerActive); |
399 | // drag farther, to make sure the knob gets adjusted significantly |
400 | p1 += QPoint(10 * dragDirection.x(), 10 * dragDirection.y()); |
401 | QTest::mouseMove(window, pos: p1); |
402 | if (expectedDragHandlerActive && dragDirection.y() > 0) |
403 | QVERIFY(slider->property("value" ).toInt() < 49); |
404 | // by now, Flickable will have stolen the grab, if it decided that it wanted to during filtering of the last event |
405 | QCOMPARE(flickable->isMoving(), expectedFlickableMoving); |
406 | QCOMPARE(slider->property("pressed" ).toBool(), false); |
407 | |
408 | // If the DragHandler is active, the Flickable will not steal the grab |
409 | // even if we move a large distance horizontally |
410 | if (expectedDragHandlerActive) { |
411 | p1 += QPoint(dragThreshold * 2, 0); |
412 | QTest::mouseMove(window, pos: p1); |
413 | QCOMPARE(flickable->isMoving(), false); |
414 | } |
415 | |
416 | // Release, and do not expect the tapped signal |
417 | QTest::mouseRelease(window, button: Qt::LeftButton, stateKey: Qt::NoModifier, pos: p1); |
418 | QCOMPARE(tappedSpy.count(), 0); |
419 | QCOMPARE(translationChangedSpy.count(), expectedDragHandlerActive ? 1 : 0); |
420 | } |
421 | |
422 | void tst_FlickableInterop::touchDragFlickableBehindSlider() |
423 | { |
424 | const int dragThreshold = QGuiApplication::styleHints()->startDragDistance(); |
425 | QScopedPointer<QQuickView> windowPtr; |
426 | createView(window&: windowPtr, fileName: "flickableWithHandlers.qml" ); |
427 | QQuickView * window = windowPtr.data(); |
428 | |
429 | QQuickItem *slider = window->rootObject()->findChild<QQuickItem*>(aName: "knobSlider" ); |
430 | QVERIFY(slider); |
431 | QQuickDragHandler *drag = slider->findChild<QQuickDragHandler*>(); |
432 | QVERIFY(drag); |
433 | QQuickItem *knob = slider->findChild<QQuickItem*>(aName: "Slider Knob" ); |
434 | QVERIFY(knob); |
435 | QQuickFlickable *flickable = window->rootObject()->findChild<QQuickFlickable*>(); |
436 | QVERIFY(flickable); |
437 | QSignalSpy tappedSpy(knob->parent(), SIGNAL(tapped())); |
438 | QSignalSpy translationChangedSpy(drag, SIGNAL(translationChanged())); |
439 | |
440 | // Button is no longer pressed if touchpoint goes beyond dragThreshold, |
441 | // because Flickable steals the grab |
442 | tappedSpy.clear(); |
443 | QPoint p1 = knob->mapToScene(point: knob->clipRect().center()).toPoint(); |
444 | QTest::touchEvent(window, device: touchDevice).press(touchId: 1, pt: p1, window); |
445 | QQuickTouchUtils::flush(window); |
446 | QTRY_VERIFY(slider->property("pressed" ).toBool()); |
447 | p1 += QPoint(dragThreshold, 0); |
448 | QTest::touchEvent(window, device: touchDevice).move(touchId: 1, pt: p1, window); |
449 | QQuickTouchUtils::flush(window); |
450 | QVERIFY(slider->property("pressed" ).toBool()); |
451 | int i = 0; |
452 | for (; i < 100 && !flickable->isMoving(); ++i) { |
453 | p1 += QPoint(1, 0); |
454 | QTest::touchEvent(window, device: touchDevice).move(touchId: 1, pt: p1, window); |
455 | QQuickTouchUtils::flush(window); |
456 | } |
457 | qCDebug(lcPointerTests) << "flickable started moving after" << i << "moves, when we got to" << p1; |
458 | QVERIFY(flickable->isMoving()); |
459 | QCOMPARE(i, 2); |
460 | QVERIFY(!slider->property("pressed" ).toBool()); |
461 | QTest::touchEvent(window, device: touchDevice).release(touchId: 1, pt: p1, window); |
462 | QQuickTouchUtils::flush(window); |
463 | QVERIFY(!slider->property("pressed" ).toBool()); |
464 | QCOMPARE(tappedSpy.count(), 0); |
465 | QCOMPARE(translationChangedSpy.count(), 0); |
466 | } |
467 | |
468 | void tst_FlickableInterop::mouseDragFlickableBehindSlider() |
469 | { |
470 | const int dragThreshold = QGuiApplication::styleHints()->startDragDistance(); |
471 | QScopedPointer<QQuickView> windowPtr; |
472 | createView(window&: windowPtr, fileName: "flickableWithHandlers.qml" ); |
473 | QQuickView * window = windowPtr.data(); |
474 | |
475 | QQuickItem *slider = window->rootObject()->findChild<QQuickItem*>(aName: "knobSlider" ); |
476 | QVERIFY(slider); |
477 | QQuickDragHandler *drag = slider->findChild<QQuickDragHandler*>(); |
478 | QVERIFY(drag); |
479 | QQuickItem *knob = slider->findChild<QQuickItem*>(aName: "Slider Knob" ); |
480 | QVERIFY(knob); |
481 | QQuickFlickable *flickable = window->rootObject()->findChild<QQuickFlickable*>(); |
482 | QVERIFY(flickable); |
483 | QSignalSpy tappedSpy(knob->parent(), SIGNAL(tapped())); |
484 | QSignalSpy translationChangedSpy(drag, SIGNAL(translationChanged())); |
485 | |
486 | // Button is no longer pressed if touchpoint goes beyond dragThreshold, |
487 | // because Flickable steals the grab |
488 | tappedSpy.clear(); |
489 | QPoint p1 = knob->mapToScene(point: knob->clipRect().center()).toPoint(); |
490 | QTest::mousePress(window, button: Qt::LeftButton, stateKey: Qt::NoModifier, pos: p1); |
491 | QTRY_VERIFY(slider->property("pressed" ).toBool()); |
492 | p1 += QPoint(dragThreshold, 0); |
493 | QTest::mouseMove(window, pos: p1); |
494 | QQuickTouchUtils::flush(window); |
495 | QVERIFY(slider->property("pressed" ).toBool()); |
496 | int i = 0; |
497 | for (; i < 100 && !flickable->isMoving(); ++i) { |
498 | p1 += QPoint(1, 0); |
499 | QTest::mouseMove(window, pos: p1); |
500 | } |
501 | qCDebug(lcPointerTests) << "flickable started moving after" << i << "moves, when we got to" << p1; |
502 | QVERIFY(flickable->isMoving()); |
503 | QCOMPARE(i, 2); |
504 | QVERIFY(!slider->property("pressed" ).toBool()); |
505 | QTest::mouseRelease(window, button: Qt::LeftButton, stateKey: Qt::NoModifier, pos: p1); |
506 | QCOMPARE(tappedSpy.count(), 0); |
507 | QCOMPARE(translationChangedSpy.count(), 0); |
508 | } |
509 | |
510 | void tst_FlickableInterop::touchDragFlickableBehindItemWithHandlers_data() |
511 | { |
512 | QTest::addColumn<QByteArray>(name: "nameOfRectangleToDrag" ); |
513 | QTest::addColumn<bool>(name: "expectedFlickableMoving" ); |
514 | QTest::newRow(dataTag: "drag" ) << QByteArray("drag" ) << false; |
515 | QTest::newRow(dataTag: "tap" ) << QByteArray("tap" ) << true; |
516 | QTest::newRow(dataTag: "dragAndTap" ) << QByteArray("dragAndTap" ) << false; |
517 | QTest::newRow(dataTag: "tapAndDrag" ) << QByteArray("tapAndDrag" ) << false; |
518 | } |
519 | |
520 | void tst_FlickableInterop::touchDragFlickableBehindItemWithHandlers() |
521 | { |
522 | QFETCH(bool, expectedFlickableMoving); |
523 | QFETCH(QByteArray, nameOfRectangleToDrag); |
524 | const int dragThreshold = QGuiApplication::styleHints()->startDragDistance(); |
525 | QScopedPointer<QQuickView> windowPtr; |
526 | createView(window&: windowPtr, fileName: "flickableWithHandlers.qml" ); |
527 | QQuickView * window = windowPtr.data(); |
528 | QQuickItem *rect = window->rootObject()->findChild<QQuickItem*>(aName: nameOfRectangleToDrag); |
529 | QVERIFY(rect); |
530 | QQuickFlickable *flickable = window->rootObject()->findChild<QQuickFlickable*>(); |
531 | QVERIFY(flickable); |
532 | QPoint p1 = rect->mapToScene(point: rect->clipRect().center()).toPoint(); |
533 | QPoint originP1 = p1; |
534 | |
535 | QTest::touchEvent(window, device: touchDevice).press(touchId: 1, pt: p1, window); |
536 | QQuickTouchUtils::flush(window); |
537 | for (int i = 0; i < dragThreshold * 3; ++i) { |
538 | p1 = originP1; |
539 | p1.rx() += i; |
540 | QTest::touchEvent(window, device: touchDevice).move(touchId: 1, pt: p1, window); |
541 | QQuickTouchUtils::flush(window); |
542 | } |
543 | QCOMPARE(flickable->isMoving(), expectedFlickableMoving); |
544 | if (!expectedFlickableMoving) { |
545 | QVERIFY(rect->mapToScene(rect->clipRect().center()).toPoint().x() > originP1.x()); |
546 | } |
547 | QTest::touchEvent(window, device: touchDevice).release(touchId: 1, pt: p1, window); |
548 | QQuickTouchUtils::flush(window); |
549 | } |
550 | |
551 | void tst_FlickableInterop::mouseDragFlickableBehindItemWithHandlers_data() |
552 | { |
553 | touchDragFlickableBehindItemWithHandlers_data(); |
554 | } |
555 | |
556 | void tst_FlickableInterop::mouseDragFlickableBehindItemWithHandlers() |
557 | { |
558 | QFETCH(bool, expectedFlickableMoving); |
559 | QFETCH(QByteArray, nameOfRectangleToDrag); |
560 | const int dragThreshold = QGuiApplication::styleHints()->startDragDistance(); |
561 | QScopedPointer<QQuickView> windowPtr; |
562 | createView(window&: windowPtr, fileName: "flickableWithHandlers.qml" ); |
563 | QQuickView * window = windowPtr.data(); |
564 | QQuickItem *rect = window->rootObject()->findChild<QQuickItem*>(aName: nameOfRectangleToDrag); |
565 | QVERIFY(rect); |
566 | QQuickFlickable *flickable = window->rootObject()->findChild<QQuickFlickable*>(); |
567 | QVERIFY(flickable); |
568 | QPoint p1 = rect->mapToScene(point: rect->clipRect().center()).toPoint(); |
569 | QPoint originP1 = p1; |
570 | QTest::mousePress(window, button: Qt::LeftButton, stateKey: Qt::NoModifier, pos: p1); |
571 | for (int i = 0; i < 3; ++i) { |
572 | p1 += QPoint(dragThreshold, 0); |
573 | QTest::mouseMove(window, pos: p1); |
574 | QQuickTouchUtils::flush(window); |
575 | } |
576 | QCOMPARE(flickable->isMoving(), expectedFlickableMoving); |
577 | if (!expectedFlickableMoving) { |
578 | QCOMPARE(originP1 + QPoint(3*dragThreshold, 0), p1); |
579 | } |
580 | QTest::mouseRelease(window, button: Qt::LeftButton, stateKey: Qt::NoModifier, pos: p1); |
581 | // wait until flickable stops |
582 | QTRY_COMPARE(flickable->isMoving(), false); |
583 | |
584 | // After the mouse button has been released, move the mouse and ensure that nothing is moving |
585 | // because of that (this tests if all grabs are released when the mouse button is released). |
586 | p1 = rect->mapToScene(point: rect->clipRect().center()).toPoint(); |
587 | originP1 = p1; |
588 | for (int i = 0; i < 3; ++i) { |
589 | p1 += QPoint(dragThreshold, 0); |
590 | QTest::mouseMove(window, pos: p1); |
591 | QQuickTouchUtils::flush(window); |
592 | } |
593 | QCOMPARE(flickable->isMoving(), false); |
594 | QCOMPARE(originP1, rect->mapToScene(rect->clipRect().center()).toPoint()); |
595 | } |
596 | |
597 | void tst_FlickableInterop::touchDragSliderAndFlickable() |
598 | { |
599 | const int dragThreshold = QGuiApplication::styleHints()->startDragDistance(); |
600 | QScopedPointer<QQuickView> windowPtr; |
601 | createView(window&: windowPtr, fileName: "flickableWithHandlers.qml" ); |
602 | QQuickView * window = windowPtr.data(); |
603 | |
604 | QQuickItem *slider = window->rootObject()->findChild<QQuickItem*>(aName: "knobSlider" ); |
605 | QVERIFY(slider); |
606 | QQuickDragHandler *drag = slider->findChild<QQuickDragHandler*>(); |
607 | QVERIFY(drag); |
608 | QQuickItem *knob = slider->findChild<QQuickItem*>(aName: "Slider Knob" ); |
609 | QVERIFY(knob); |
610 | QQuickFlickable *flickable = window->rootObject()->findChild<QQuickFlickable*>(); |
611 | QVERIFY(flickable); |
612 | QTest::QTouchEventSequence touchSeq = QTest::touchEvent(window, device: touchDevice, autoCommit: false); |
613 | |
614 | // The knob is initially centered over the slider's "groove" |
615 | qreal initialXOffset = qAbs(t: knob->mapToScene(point: knob->clipRect().center()).x() - slider->mapToScene |
616 | (point: slider->clipRect().center()).x()); |
617 | QVERIFY(initialXOffset <= 1); |
618 | |
619 | // Drag the slider in the allowed (vertical) direction with one finger |
620 | QPoint p1 = knob->mapToScene(point: knob->clipRect().center()).toPoint(); |
621 | touchSeq.press(touchId: 1, pt: p1, window).commit(); |
622 | QQuickTouchUtils::flush(window); |
623 | p1 += QPoint(0, dragThreshold); |
624 | touchSeq.move(touchId: 1, pt: p1, window).commit(); |
625 | QQuickTouchUtils::flush(window); |
626 | p1 += QPoint(0, dragThreshold); |
627 | touchSeq.move(touchId: 1, pt: p1, window).commit(); |
628 | QQuickTouchUtils::flush(window); |
629 | p1 += QPoint(0, dragThreshold); |
630 | touchSeq.move(touchId: 1, pt: p1, window).commit(); |
631 | QQuickTouchUtils::flush(window); |
632 | QTRY_VERIFY(slider->property("value" ).toInt() < 49); |
633 | QVERIFY(!flickable->isMoving()); |
634 | |
635 | // Drag the Flickable with a second finger |
636 | QPoint p2(300,300); |
637 | touchSeq.stationary(touchId: 1).press(touchId: 2, pt: p2, window).commit(); |
638 | QQuickTouchUtils::flush(window); |
639 | for (int i = 0; i < 4; ++i) { |
640 | p1 += QPoint(-10, -10); |
641 | p2 += QPoint(dragThreshold, 0); |
642 | touchSeq.move(touchId: 1, pt: p1, window).stationary(touchId: 2).commit(); |
643 | QQuickTouchUtils::flush(window); |
644 | p1 += QPoint(-10, -10); |
645 | p2 += QPoint(dragThreshold, 0); |
646 | touchSeq.stationary(touchId: 1).move(touchId: 2, pt: p2, window).commit(); |
647 | QQuickTouchUtils::flush(window); |
648 | qCDebug(lcPointerTests) << "step" << i << ": fingers @" << p1 << p2 << "is Flickable moving yet?" << flickable->isMoving(); |
649 | } |
650 | QVERIFY(flickable->isMoving()); |
651 | qreal knobSliderXOffset = qAbs(t: knob->mapToScene(point: knob->clipRect().center()).toPoint().x() - |
652 | slider->mapToScene(point: slider->clipRect().center()).toPoint().x()) - initialXOffset; |
653 | if (knobSliderXOffset > 1) |
654 | qCDebug(lcPointerTests) << "knob has slipped out of groove by" << knobSliderXOffset << "pixels" ; |
655 | // See if the knob is still centered over the slider's "groove" |
656 | QVERIFY(qAbs(knobSliderXOffset) <= 1); |
657 | |
658 | // Release |
659 | touchSeq.release(touchId: 1, pt: p1, window).release(touchId: 2, pt: p2, window).commit(); |
660 | } |
661 | |
662 | void tst_FlickableInterop::touchAndDragHandlerOnFlickable_data() |
663 | { |
664 | QTest::addColumn<QByteArray>(name: "qmlFile" ); |
665 | QTest::addColumn<bool>(name: "pressDelay" ); |
666 | QTest::addColumn<bool>(name: "targetNull" ); |
667 | QTest::newRow(dataTag: "tapOnFlickable" ) << QByteArray("tapOnFlickable.qml" ) << false << false; |
668 | QTest::newRow(dataTag: "tapOnList" ) << QByteArray("tapOnList.qml" ) << false << false; |
669 | QTest::newRow(dataTag: "tapOnTable" ) << QByteArray("tapOnTable.qml" ) << false << false; |
670 | QTest::newRow(dataTag: "dragOnFlickable" ) << QByteArray("dragOnFlickable.qml" ) << false << false; |
671 | QTest::newRow(dataTag: "dragOnList" ) << QByteArray("dragOnList.qml" ) << false << false; |
672 | QTest::newRow(dataTag: "dragOnTable" ) << QByteArray("dragOnTable.qml" ) << false << false; |
673 | QTest::newRow(dataTag: "tapDelayOnFlickable" ) << QByteArray("tapOnFlickable.qml" ) << true << false; |
674 | QTest::newRow(dataTag: "tapDelayOnList" ) << QByteArray("tapOnList.qml" ) << true << false; |
675 | QTest::newRow(dataTag: "tapDelayOnTable" ) << QByteArray("tapOnTable.qml" ) << true << false; |
676 | QTest::newRow(dataTag: "dragDelayOnFlickable" ) << QByteArray("dragOnFlickable.qml" ) << true << false; |
677 | QTest::newRow(dataTag: "dragDelayOnList" ) << QByteArray("dragOnList.qml" ) << true << false; |
678 | QTest::newRow(dataTag: "dragDelayOnTable" ) << QByteArray("dragOnTable.qml" ) << true << false; |
679 | QTest::newRow(dataTag: "tapOnFlickableWithNullTargets" ) << QByteArray("tapOnFlickable.qml" ) << false << true; |
680 | QTest::newRow(dataTag: "tapOnListWithNullTargets" ) << QByteArray("tapOnList.qml" ) << false << true; |
681 | QTest::newRow(dataTag: "tapOnTableWithNullTargets" ) << QByteArray("tapOnTable.qml" ) << false << true; |
682 | QTest::newRow(dataTag: "dragOnFlickableWithNullTargets" ) << QByteArray("dragOnFlickable.qml" ) << false << true; |
683 | QTest::newRow(dataTag: "dragOnListWithNullTargets" ) << QByteArray("dragOnList.qml" ) << false << true; |
684 | QTest::newRow(dataTag: "dragOnTableWithNullTargets" ) << QByteArray("dragOnTable.qml" ) << false << true; |
685 | QTest::newRow(dataTag: "tapDelayOnFlickableWithNullTargets" ) << QByteArray("tapOnFlickable.qml" ) << true << true; |
686 | QTest::newRow(dataTag: "tapDelayOnListWithNullTargets" ) << QByteArray("tapOnList.qml" ) << true << true; |
687 | QTest::newRow(dataTag: "tapDelayOnTableWithNullTargets" ) << QByteArray("tapOnTable.qml" ) << true << true; |
688 | QTest::newRow(dataTag: "dragDelayOnFlickableWithNullTargets" ) << QByteArray("dragOnFlickable.qml" ) << true << true; |
689 | QTest::newRow(dataTag: "dragDelayOnListWithNullTargets" ) << QByteArray("dragOnList.qml" ) << true << true; |
690 | QTest::newRow(dataTag: "dragDelayOnTableWithNullTargets" ) << QByteArray("dragOnTable.qml" ) << true << true; |
691 | } |
692 | |
693 | void tst_FlickableInterop::touchAndDragHandlerOnFlickable() |
694 | { |
695 | QFETCH(QByteArray, qmlFile); |
696 | QFETCH(bool, pressDelay); |
697 | QFETCH(bool, targetNull); |
698 | |
699 | const int dragThreshold = QGuiApplication::styleHints()->startDragDistance(); |
700 | QScopedPointer<QQuickView> windowPtr; |
701 | createView(window&: windowPtr, fileName: qmlFile.constData()); |
702 | QQuickView * window = windowPtr.data(); |
703 | QQuickFlickable *flickable = qmlobject_cast<QQuickFlickable*>(object: window->rootObject()); |
704 | QVERIFY(flickable); |
705 | flickable->setPressDelay(pressDelay ? 5000 : 0); |
706 | QQuickItem *delegate = nullptr; |
707 | if (QQuickItemView *itemView = qmlobject_cast<QQuickItemView *>(object: flickable)) |
708 | delegate = itemView->currentItem(); |
709 | if (!delegate) |
710 | delegate = flickable->property(name: "delegateUnderTest" ).value<QQuickItem*>(); |
711 | QQuickItem *button = delegate ? delegate->findChild<QQuickItem*>(aName: "button" ) |
712 | : flickable->findChild<QQuickItem*>(aName: "button" ); |
713 | if (!button) |
714 | button = flickable->property(name: "buttonUnderTest" ).value<QQuickItem*>(); |
715 | QVERIFY(button); |
716 | QQuickPointerHandler *buttonHandler = button->findChild<QQuickPointerHandler*>(); |
717 | QVERIFY(buttonHandler); |
718 | QQuickTapHandler *buttonTapHandler = qmlobject_cast<QQuickTapHandler *>(object: buttonHandler); |
719 | QQuickDragHandler *buttonDragHandler = qmlobject_cast<QQuickDragHandler *>(object: buttonHandler); |
720 | QQuickPointerHandler *delegateHandler = delegate ? delegate->findChild<QQuickPointerHandler*>() : nullptr; |
721 | QQuickPointerHandler *contentItemHandler = flickable->findChild<QQuickPointerHandler*>(); |
722 | QVERIFY(contentItemHandler); |
723 | // a handler declared directly in a Flickable (or item view) must actually be a child of the contentItem, |
724 | // just as Items declared inside are (QTBUG-71918 and QTBUG-73035) |
725 | QCOMPARE(contentItemHandler->parentItem(), flickable->contentItem()); |
726 | if (targetNull) { |
727 | buttonHandler->setTarget(nullptr); |
728 | if (delegateHandler) |
729 | delegateHandler->setTarget(nullptr); |
730 | contentItemHandler->setTarget(nullptr); |
731 | } |
732 | |
733 | // Drag one finger on the Flickable and make sure it flicks |
734 | QTest::QTouchEventSequence touchSeq = QTest::touchEvent(window, device: touchDevice, autoCommit: false); |
735 | QPoint p1(780, 460); |
736 | touchSeq.press(touchId: 1, pt: p1, window).commit(); |
737 | QQuickTouchUtils::flush(window); |
738 | for (int i = 0; i < 4; ++i) { |
739 | p1 -= QPoint(dragThreshold, dragThreshold); |
740 | touchSeq.move(touchId: 1, pt: p1, window).commit(); |
741 | QQuickTouchUtils::flush(window); |
742 | } |
743 | if (!(buttonDragHandler && !pressDelay)) |
744 | QTRY_VERIFY(flickable->contentY() >= dragThreshold); |
745 | if (buttonTapHandler) |
746 | QCOMPARE(buttonTapHandler->isPressed(), false); |
747 | touchSeq.release(touchId: 1, pt: p1, window).commit(); |
748 | QQuickTouchUtils::flush(window); |
749 | |
750 | // Drag one finger on the delegate and make sure Flickable flicks |
751 | if (delegate) { |
752 | flickable->setContentY(0); |
753 | QTRY_COMPARE(flickable->isMoving(), false); |
754 | QVERIFY(delegateHandler); |
755 | QQuickTapHandler *delegateTapHandler = qmlobject_cast<QQuickTapHandler *>(object: delegateHandler); |
756 | p1 = button->mapToScene(point: button->clipRect().bottomRight()).toPoint() + QPoint(10, 0); |
757 | touchSeq.press(touchId: 1, pt: p1, window).commit(); |
758 | QQuickTouchUtils::flush(window); |
759 | if (delegateTapHandler && !pressDelay) |
760 | QCOMPARE(delegateTapHandler->isPressed(), true); |
761 | for (int i = 0; i < 4; ++i) { |
762 | p1 -= QPoint(dragThreshold, dragThreshold); |
763 | touchSeq.move(touchId: 1, pt: p1, window).commit(); |
764 | QQuickTouchUtils::flush(window); |
765 | if (i > 1) |
766 | QTRY_VERIFY(delegateHandler->active() || flickable->isMoving()); |
767 | } |
768 | if (!(buttonDragHandler && !pressDelay)) |
769 | QVERIFY(flickable->contentY() > 0); |
770 | if (delegateTapHandler) |
771 | QCOMPARE(delegateTapHandler->isPressed(), false); |
772 | touchSeq.release(touchId: 1, pt: p1, window).commit(); |
773 | QQuickTouchUtils::flush(window); |
774 | } |
775 | |
776 | // Drag one finger on the button and make sure Flickable flicks |
777 | flickable->setContentY(0); |
778 | QTRY_COMPARE(flickable->isMoving(), false); |
779 | p1 = button->mapToScene(point: button->clipRect().center()).toPoint(); |
780 | touchSeq.press(touchId: 1, pt: p1, window).commit(); |
781 | QQuickTouchUtils::flush(window); |
782 | if (buttonTapHandler && !pressDelay) |
783 | QTRY_COMPARE(buttonTapHandler->isPressed(), true); |
784 | for (int i = 0; i < 4; ++i) { |
785 | p1 -= QPoint(dragThreshold, dragThreshold); |
786 | touchSeq.move(touchId: 1, pt: p1, window).commit(); |
787 | QQuickTouchUtils::flush(window); |
788 | } |
789 | if (!(buttonDragHandler && !pressDelay)) |
790 | QVERIFY(flickable->contentY() > 0); |
791 | if (buttonTapHandler) |
792 | QCOMPARE(buttonTapHandler->isPressed(), false); |
793 | touchSeq.release(touchId: 1, pt: p1, window).commit(); |
794 | } |
795 | |
796 | QTEST_MAIN(tst_FlickableInterop) |
797 | |
798 | #include "tst_flickableinterop.moc" |
799 | |
800 | |