1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2016 The Qt Company Ltd. |
4 | ** Contact: https://www.qt.io/licensing/ |
5 | ** |
6 | ** This file is part of the $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 | #include <QtGui> |
30 | #include <QtWidgets> |
31 | #include <QtTest> |
32 | #include <qpa/qwindowsysteminterface.h> |
33 | |
34 | // #include <QDebug> |
35 | |
36 | class tst_QScrollerWidget : public QWidget |
37 | { |
38 | public: |
39 | tst_QScrollerWidget() |
40 | : QWidget() |
41 | { |
42 | reset(); |
43 | } |
44 | |
45 | void reset() |
46 | { |
47 | receivedPrepare = false; |
48 | receivedScroll = false; |
49 | receivedFirst = false; |
50 | receivedLast = false; |
51 | receivedOvershoot = false; |
52 | } |
53 | |
54 | bool event(QEvent *e) |
55 | { |
56 | switch (e->type()) { |
57 | case QEvent::Gesture: |
58 | e->setAccepted(false); // better reject the event or QGestureManager will make trouble |
59 | return false; |
60 | |
61 | case QEvent::ScrollPrepare: |
62 | { |
63 | receivedPrepare = true; |
64 | QScrollPrepareEvent *se = static_cast<QScrollPrepareEvent *>(e); |
65 | se->setViewportSize(QSizeF(100,100)); |
66 | se->setContentPosRange(scrollArea); |
67 | se->setContentPos(scrollPosition); |
68 | se->accept(); |
69 | return true; |
70 | } |
71 | |
72 | case QEvent::Scroll: |
73 | { |
74 | receivedScroll = true; |
75 | QScrollEvent *se = static_cast<QScrollEvent *>(e); |
76 | // qDebug() << "Scroll for"<<this<<"pos"<<se->scrollPos()<<"ov"<<se->overshoot()<<"first"<<se->isFirst()<<"last"<<se->isLast(); |
77 | |
78 | if (se->scrollState() == QScrollEvent::ScrollStarted) |
79 | receivedFirst = true; |
80 | if (se->scrollState() == QScrollEvent::ScrollFinished) |
81 | receivedLast = true; |
82 | |
83 | currentPos = se->contentPos(); |
84 | overshoot = se->overshootDistance(); |
85 | if (!qFuzzyCompare(p1: overshoot.x() + 1.0, p2: 1.0) || |
86 | !qFuzzyCompare(p1: overshoot.y() + 1.0, p2: 1.0)) |
87 | receivedOvershoot = true; |
88 | return true; |
89 | } |
90 | |
91 | default: |
92 | return QObject::event(event: e); |
93 | } |
94 | } |
95 | |
96 | |
97 | QRectF scrollArea; |
98 | QPointF scrollPosition; |
99 | |
100 | bool receivedPrepare; |
101 | bool receivedScroll; |
102 | bool receivedFirst; |
103 | bool receivedLast; |
104 | bool receivedOvershoot; |
105 | |
106 | QPointF currentPos; |
107 | QPointF overshoot; |
108 | }; |
109 | |
110 | |
111 | class tst_QScroller : public QObject |
112 | { |
113 | Q_OBJECT |
114 | public: |
115 | tst_QScroller() { } |
116 | ~tst_QScroller() { } |
117 | |
118 | private: |
119 | void kineticScroll(tst_QScrollerWidget *sw, QPointF from, QPoint touchStart, QPoint touchUpdate, QPoint touchEnd); |
120 | void kineticScrollNoTest(tst_QScrollerWidget *sw, QPointF from, QPoint touchStart, QPoint touchUpdate, QPoint touchEnd); |
121 | |
122 | private slots: |
123 | void staticScrollers(); |
124 | void scrollerProperties(); |
125 | void scrollTo(); |
126 | void scroll(); |
127 | void overshoot(); |
128 | void multipleWindows(); |
129 | |
130 | private: |
131 | QTouchDevice *m_touchScreen = QTest::createTouchDevice(); |
132 | }; |
133 | |
134 | /*! \internal |
135 | Generates touchBegin, touchUpdate and touchEnd events to trigger scrolling. |
136 | Tests some in between states but does not wait until scrolling is finished. |
137 | */ |
138 | void tst_QScroller::kineticScroll(tst_QScrollerWidget *sw, QPointF from, QPoint touchStart, QPoint touchUpdate, QPoint touchEnd) |
139 | { |
140 | sw->scrollPosition = from; |
141 | sw->currentPos= from; |
142 | |
143 | QScroller *s1 = QScroller::scroller(target: sw); |
144 | QCOMPARE(s1->state(), QScroller::Inactive); |
145 | |
146 | QScrollerProperties sp1 = QScroller::scroller(target: sw)->scrollerProperties(); |
147 | |
148 | QTouchEvent::TouchPoint rawTouchPoint; |
149 | rawTouchPoint.setId(0); |
150 | |
151 | // send the touch begin event |
152 | QTouchEvent::TouchPoint touchPoint(0); |
153 | touchPoint.setState(Qt::TouchPointPressed); |
154 | touchPoint.setPos(touchStart); |
155 | touchPoint.setScenePos(touchStart); |
156 | touchPoint.setScreenPos(touchStart); |
157 | QTouchEvent touchEvent1(QEvent::TouchBegin, |
158 | m_touchScreen, |
159 | Qt::NoModifier, |
160 | Qt::TouchPointPressed, |
161 | (QList<QTouchEvent::TouchPoint>() << touchPoint)); |
162 | QApplication::sendEvent(receiver: sw, event: &touchEvent1); |
163 | |
164 | QCOMPARE(s1->state(), QScroller::Pressed); |
165 | |
166 | // send the touch update far enough to trigger a scroll |
167 | QTest::qWait(ms: 200); // we need to wait a little or else the speed would be infinite. now we have around 500 pixel per second. |
168 | touchPoint.setPos(touchUpdate); |
169 | touchPoint.setScenePos(touchUpdate); |
170 | touchPoint.setScreenPos(touchUpdate); |
171 | QTouchEvent touchEvent2(QEvent::TouchUpdate, |
172 | m_touchScreen, |
173 | Qt::NoModifier, |
174 | Qt::TouchPointMoved, |
175 | (QList<QTouchEvent::TouchPoint>() << touchPoint)); |
176 | QApplication::sendEvent(receiver: sw, event: &touchEvent2); |
177 | |
178 | QCOMPARE(s1->state(), QScroller::Dragging); |
179 | QCOMPARE(sw->receivedPrepare, true); |
180 | |
181 | |
182 | QTRY_COMPARE(sw->receivedFirst, true); |
183 | QCOMPARE(sw->receivedScroll, true); |
184 | QCOMPARE(sw->receivedOvershoot, false); |
185 | |
186 | // note that the scrolling goes in a different direction than the mouse move |
187 | QPoint calculatedPos = from.toPoint() - touchUpdate - touchStart; |
188 | QVERIFY(qAbs(sw->currentPos.x() - calculatedPos.x()) < 1.0); |
189 | QVERIFY(qAbs(sw->currentPos.y() - calculatedPos.y()) < 1.0); |
190 | |
191 | // send the touch end |
192 | touchPoint.setPos(touchEnd); |
193 | touchPoint.setScenePos(touchEnd); |
194 | touchPoint.setScreenPos(touchEnd); |
195 | QTouchEvent touchEvent5(QEvent::TouchEnd, |
196 | m_touchScreen, |
197 | Qt::NoModifier, |
198 | Qt::TouchPointReleased, |
199 | (QList<QTouchEvent::TouchPoint>() << touchPoint)); |
200 | QApplication::sendEvent(receiver: sw, event: &touchEvent5); |
201 | } |
202 | |
203 | /*! \internal |
204 | Generates touchBegin, touchUpdate and touchEnd events to trigger scrolling. |
205 | This function does not have any in between tests, it does not expect the scroller to actually scroll. |
206 | */ |
207 | void tst_QScroller::kineticScrollNoTest(tst_QScrollerWidget *sw, QPointF from, QPoint touchStart, QPoint touchUpdate, QPoint touchEnd) |
208 | { |
209 | sw->scrollPosition = from; |
210 | sw->currentPos = from; |
211 | |
212 | QScroller *s1 = QScroller::scroller(target: sw); |
213 | QCOMPARE(s1->state(), QScroller::Inactive); |
214 | |
215 | QScrollerProperties sp1 = s1->scrollerProperties(); |
216 | int fps = 60; |
217 | |
218 | QTouchEvent::TouchPoint rawTouchPoint; |
219 | rawTouchPoint.setId(0); |
220 | |
221 | // send the touch begin event |
222 | QTouchEvent::TouchPoint touchPoint(0); |
223 | touchPoint.setState(Qt::TouchPointPressed); |
224 | touchPoint.setPos(touchStart); |
225 | touchPoint.setScenePos(touchStart); |
226 | touchPoint.setScreenPos(touchStart); |
227 | QTouchEvent touchEvent1(QEvent::TouchBegin, |
228 | m_touchScreen, |
229 | Qt::NoModifier, |
230 | Qt::TouchPointPressed, |
231 | (QList<QTouchEvent::TouchPoint>() << touchPoint)); |
232 | QApplication::sendEvent(receiver: sw, event: &touchEvent1); |
233 | |
234 | // send the touch update far enough to trigger a scroll |
235 | QTest::qWait(ms: 200); // we need to wait a little or else the speed would be infinite. now we have around 500 pixel per second. |
236 | touchPoint.setPos(touchUpdate); |
237 | touchPoint.setScenePos(touchUpdate); |
238 | touchPoint.setScreenPos(touchUpdate); |
239 | QTouchEvent touchEvent2(QEvent::TouchUpdate, |
240 | m_touchScreen, |
241 | Qt::NoModifier, |
242 | Qt::TouchPointMoved, |
243 | (QList<QTouchEvent::TouchPoint>() << touchPoint)); |
244 | QApplication::sendEvent(receiver: sw, event: &touchEvent2); |
245 | |
246 | QTest::qWait(ms: 1000 / fps * 2); // wait until the first scroll move |
247 | |
248 | // send the touch end |
249 | touchPoint.setPos(touchEnd); |
250 | touchPoint.setScenePos(touchEnd); |
251 | touchPoint.setScreenPos(touchEnd); |
252 | QTouchEvent touchEvent5(QEvent::TouchEnd, |
253 | m_touchScreen, |
254 | Qt::NoModifier, |
255 | Qt::TouchPointReleased, |
256 | (QList<QTouchEvent::TouchPoint>() << touchPoint)); |
257 | QApplication::sendEvent(receiver: sw, event: &touchEvent5); |
258 | } |
259 | |
260 | |
261 | void tst_QScroller::staticScrollers() |
262 | { |
263 | // scrollers |
264 | { |
265 | QObject *o1 = new QObject(this); |
266 | QObject *o2 = new QObject(this); |
267 | |
268 | // get scroller for object |
269 | QScroller *s1 = QScroller::scroller(target: o1); |
270 | QScroller *s2 = QScroller::scroller(target: o2); |
271 | |
272 | QVERIFY(s1); |
273 | QVERIFY(s2); |
274 | QVERIFY(s1 != s2); |
275 | |
276 | QVERIFY(!QScroller::scroller(static_cast<const QObject*>(0))); |
277 | QCOMPARE(QScroller::scroller(o1), s1); |
278 | |
279 | delete o1; |
280 | delete o2; |
281 | } |
282 | |
283 | // the same for properties |
284 | { |
285 | QObject *o1 = new QObject(this); |
286 | QObject *o2 = new QObject(this); |
287 | |
288 | // get scroller for object |
289 | QScrollerProperties sp1 = QScroller::scroller(target: o1)->scrollerProperties(); |
290 | QScrollerProperties sp2 = QScroller::scroller(target: o2)->scrollerProperties(); |
291 | |
292 | // default properties should be the same |
293 | QCOMPARE(sp1, sp2); |
294 | |
295 | QCOMPARE(QScroller::scroller(o1)->scrollerProperties(), sp1); |
296 | |
297 | delete o1; |
298 | delete o2; |
299 | } |
300 | } |
301 | |
302 | void tst_QScroller::scrollerProperties() |
303 | { |
304 | QObject *o1 = new QObject(this); |
305 | QScrollerProperties sp1 = QScroller::scroller(target: o1)->scrollerProperties(); |
306 | |
307 | QScrollerProperties::ScrollMetric metrics[] = |
308 | { |
309 | QScrollerProperties::MousePressEventDelay, // qreal [s] |
310 | QScrollerProperties::DragStartDistance, // qreal [m] |
311 | QScrollerProperties::DragVelocitySmoothingFactor, // qreal [0..1/s] (complex calculation involving time) v = v_new* DASF + v_old * (1-DASF) |
312 | QScrollerProperties::AxisLockThreshold, // qreal [0..1] atan(|min(dx,dy)|/|max(dx,dy)|) |
313 | |
314 | QScrollerProperties::DecelerationFactor, // slope of the curve |
315 | |
316 | QScrollerProperties::MinimumVelocity, // qreal [m/s] |
317 | QScrollerProperties::MaximumVelocity, // qreal [m/s] |
318 | QScrollerProperties::MaximumClickThroughVelocity, // qreal [m/s] |
319 | |
320 | QScrollerProperties::AcceleratingFlickMaximumTime, // qreal [s] |
321 | QScrollerProperties::AcceleratingFlickSpeedupFactor, // qreal [1..] |
322 | |
323 | QScrollerProperties::SnapPositionRatio, // qreal [0..1] |
324 | QScrollerProperties::SnapTime, // qreal [s] |
325 | |
326 | QScrollerProperties::OvershootDragResistanceFactor, // qreal [0..1] |
327 | QScrollerProperties::OvershootDragDistanceFactor, // qreal [0..1] |
328 | QScrollerProperties::OvershootScrollDistanceFactor, // qreal [0..1] |
329 | QScrollerProperties::OvershootScrollTime, // qreal [s] |
330 | }; |
331 | |
332 | for (unsigned int i = 0; i < sizeof(metrics) / sizeof(metrics[0]); i++) { |
333 | sp1.setScrollMetric(metric: metrics[i], value: 0.9); |
334 | QCOMPARE(sp1.scrollMetric(metrics[i]).toDouble(), 0.9); |
335 | } |
336 | sp1.setScrollMetric(metric: QScrollerProperties::ScrollingCurve, value: QEasingCurve(QEasingCurve::OutQuart)); |
337 | QCOMPARE(sp1.scrollMetric(QScrollerProperties::ScrollingCurve).toEasingCurve().type(), QEasingCurve::OutQuart); |
338 | |
339 | sp1.setScrollMetric(metric: QScrollerProperties::HorizontalOvershootPolicy, value: QVariant::fromValue(value: QScrollerProperties::OvershootAlwaysOff)); |
340 | QCOMPARE(sp1.scrollMetric(QScrollerProperties::HorizontalOvershootPolicy).value<QScrollerProperties::OvershootPolicy>(), QScrollerProperties::OvershootAlwaysOff); |
341 | |
342 | sp1.setScrollMetric(metric: QScrollerProperties::VerticalOvershootPolicy, value: QVariant::fromValue(value: QScrollerProperties::OvershootAlwaysOn)); |
343 | QCOMPARE(sp1.scrollMetric(QScrollerProperties::VerticalOvershootPolicy).value<QScrollerProperties::OvershootPolicy>(), QScrollerProperties::OvershootAlwaysOn); |
344 | |
345 | sp1.setScrollMetric(metric: QScrollerProperties::FrameRate, value: QVariant::fromValue(value: QScrollerProperties::Fps20)); |
346 | QCOMPARE(sp1.scrollMetric(QScrollerProperties::FrameRate).value<QScrollerProperties::FrameRates>(), QScrollerProperties::Fps20); |
347 | } |
348 | |
349 | void tst_QScroller::scrollTo() |
350 | { |
351 | QScopedPointer<tst_QScrollerWidget> sw(new tst_QScrollerWidget); |
352 | sw->show(); |
353 | QApplication::setActiveWindow(sw.data()); |
354 | if (!QTest::qWaitForWindowExposed(widget: sw.data()) || !QTest::qWaitForWindowActive(widget: sw.data())) |
355 | QSKIP("Failed to show and activate window" ); |
356 | |
357 | sw->scrollArea = QRectF(0, 0, 1000, 1000); |
358 | sw->scrollPosition = QPointF(500, 500); |
359 | |
360 | QScroller *s1 = QScroller::scroller(target: sw.data()); |
361 | QCOMPARE(s1->state(), QScroller::Inactive); |
362 | |
363 | // a normal scroll |
364 | s1->scrollTo(pos: QPointF(100,100), scrollTime: 100); |
365 | QTest::qWait(ms: 200); |
366 | |
367 | QTRY_COMPARE(sw->receivedPrepare, true); |
368 | QCOMPARE(sw->receivedScroll, true); |
369 | QCOMPARE(sw->receivedFirst, true); |
370 | QCOMPARE(sw->receivedLast, true); |
371 | QCOMPARE(sw->receivedOvershoot, false); |
372 | QTRY_VERIFY(qFuzzyCompare(sw->currentPos.x(), 100)); |
373 | QVERIFY(qFuzzyCompare(sw->currentPos.y(), 100)); |
374 | } |
375 | |
376 | void tst_QScroller::scroll() |
377 | { |
378 | #if QT_CONFIG(gestures) && QT_CONFIG(scroller) |
379 | // -- good case. normal scroll |
380 | QScopedPointer<tst_QScrollerWidget> sw(new tst_QScrollerWidget()); |
381 | sw->scrollArea = QRectF(0, 0, 1000, 1000); |
382 | QScroller::grabGesture(target: sw.data(), gestureType: QScroller::TouchGesture); |
383 | sw->setGeometry(ax: 100, ay: 100, aw: 400, ah: 300); |
384 | sw->show(); |
385 | QApplication::setActiveWindow(sw.data()); |
386 | if (!QTest::qWaitForWindowExposed(widget: sw.data()) || !QTest::qWaitForWindowActive(widget: sw.data())) |
387 | QSKIP("Failed to show and activate window" ); |
388 | |
389 | QScroller *s1 = QScroller::scroller(target: sw.data()); |
390 | kineticScroll(sw: sw.data(), from: QPointF(500, 500), touchStart: QPoint(0, 0), touchUpdate: QPoint(100, 100), touchEnd: QPoint(200, 200)); |
391 | // now we should be scrolling |
392 | QTRY_COMPARE(s1->state(), QScroller::Scrolling); |
393 | |
394 | // wait until finished, check that no further first scroll is sent |
395 | sw->receivedFirst = false; |
396 | sw->receivedScroll = false; |
397 | QTRY_VERIFY(s1->state() != QScroller::Scrolling); |
398 | |
399 | QCOMPARE(sw->receivedFirst, false); |
400 | QCOMPARE(sw->receivedScroll, true); |
401 | QCOMPARE(sw->receivedLast, true); |
402 | QVERIFY(sw->currentPos.x() < 400); |
403 | QVERIFY(sw->currentPos.y() < 400); |
404 | |
405 | // -- try to scroll when nothing to scroll |
406 | |
407 | sw->reset(); |
408 | sw->scrollArea = QRectF(0, 0, 0, 1000); |
409 | kineticScrollNoTest(sw: sw.data(), from: QPointF(0, 500), touchStart: QPoint(0, 0), touchUpdate: QPoint(100, 0), touchEnd: QPoint(200, 0)); |
410 | |
411 | QTRY_COMPARE(s1->state(), QScroller::Inactive); |
412 | |
413 | QCOMPARE(sw->currentPos.x(), 0.0); |
414 | QCOMPARE(sw->currentPos.y(), 500.0); |
415 | #endif |
416 | } |
417 | |
418 | void tst_QScroller::overshoot() |
419 | { |
420 | #if QT_CONFIG(gestures) && QT_CONFIG(scroller) |
421 | QScopedPointer<tst_QScrollerWidget> sw(new tst_QScrollerWidget); |
422 | sw->scrollArea = QRectF(0, 0, 1000, 1000); |
423 | QScroller::grabGesture(target: sw.data(), gestureType: QScroller::TouchGesture); |
424 | sw->setGeometry(ax: 100, ay: 100, aw: 400, ah: 300); |
425 | sw->show(); |
426 | QApplication::setActiveWindow(sw.data()); |
427 | if (!QTest::qWaitForWindowExposed(widget: sw.data()) || !QTest::qWaitForWindowActive(widget: sw.data())) |
428 | QSKIP("Failed to show and activate window" ); |
429 | |
430 | QScroller *s1 = QScroller::scroller(target: sw.data()); |
431 | QScrollerProperties sp1 = s1->scrollerProperties(); |
432 | |
433 | sp1.setScrollMetric(metric: QScrollerProperties::OvershootDragResistanceFactor, value: 0.5); |
434 | sp1.setScrollMetric(metric: QScrollerProperties::OvershootDragDistanceFactor, value: 0.2); |
435 | sp1.setScrollMetric(metric: QScrollerProperties::OvershootScrollDistanceFactor, value: 0.2); |
436 | |
437 | // -- try to scroll with overshoot (when scrollable good case) |
438 | |
439 | sp1.setScrollMetric(metric: QScrollerProperties::HorizontalOvershootPolicy, value: QVariant::fromValue(value: QScrollerProperties::OvershootWhenScrollable)); |
440 | s1->setScrollerProperties(sp1); |
441 | kineticScrollNoTest(sw: sw.data(), from: QPointF(500, 500), touchStart: QPoint(0, 0), touchUpdate: QPoint(400, 0), touchEnd: QPoint(490, 0)); |
442 | |
443 | QTRY_COMPARE(s1->state(), QScroller::Inactive); |
444 | |
445 | //qDebug() << "Overshoot fuzzy: "<<sw->currentPos; |
446 | QVERIFY(qFuzzyCompare(sw->currentPos.x(), 0)); |
447 | QVERIFY(qFuzzyCompare(sw->currentPos.y(), 500)); |
448 | QCOMPARE(sw->receivedOvershoot, true); |
449 | |
450 | // -- try to scroll with overshoot (when scrollable bad case) |
451 | sw->reset(); |
452 | sw->scrollArea = QRectF(0, 0, 0, 1000); |
453 | |
454 | sp1.setScrollMetric(metric: QScrollerProperties::HorizontalOvershootPolicy, value: QVariant::fromValue(value: QScrollerProperties::OvershootWhenScrollable)); |
455 | s1->setScrollerProperties(sp1); |
456 | kineticScrollNoTest(sw: sw.data(), from: QPointF(0, 500), touchStart: QPoint(0, 0), touchUpdate: QPoint(400, 0), touchEnd: QPoint(490, 0)); |
457 | |
458 | QTRY_COMPARE(s1->state(), QScroller::Inactive); |
459 | |
460 | //qDebug() << "Overshoot fuzzy: "<<sw->currentPos; |
461 | QVERIFY(qFuzzyCompare(sw->currentPos.x(), 0)); |
462 | QVERIFY(qFuzzyCompare(sw->currentPos.y(), 500)); |
463 | QCOMPARE(sw->receivedOvershoot, false); |
464 | |
465 | // -- try to scroll with overshoot (always on) |
466 | sw->reset(); |
467 | sw->scrollArea = QRectF(0, 0, 0, 1000); |
468 | |
469 | sp1.setScrollMetric(metric: QScrollerProperties::HorizontalOvershootPolicy, value: QVariant::fromValue(value: QScrollerProperties::OvershootAlwaysOn)); |
470 | s1->setScrollerProperties(sp1); |
471 | kineticScrollNoTest(sw: sw.data(), from: QPointF(0, 500), touchStart: QPoint(0, 0), touchUpdate: QPoint(400, 0), touchEnd: QPoint(490, 0)); |
472 | |
473 | QTRY_COMPARE(s1->state(), QScroller::Inactive); |
474 | |
475 | //qDebug() << "Overshoot fuzzy: "<<sw->currentPos; |
476 | |
477 | QVERIFY(qFuzzyCompare(sw->currentPos.x(), 0)); |
478 | QVERIFY(qFuzzyCompare(sw->currentPos.y(), 500)); |
479 | QCOMPARE(sw->receivedOvershoot, true); |
480 | |
481 | // -- try to scroll with overshoot (always off) |
482 | sw->reset(); |
483 | sw->scrollArea = QRectF(0, 0, 1000, 1000); |
484 | |
485 | sp1.setScrollMetric(metric: QScrollerProperties::HorizontalOvershootPolicy, value: QVariant::fromValue(value: QScrollerProperties::OvershootAlwaysOff)); |
486 | s1->setScrollerProperties(sp1); |
487 | kineticScrollNoTest(sw: sw.data(), from: QPointF(500, 500), touchStart: QPoint(0, 0), touchUpdate: QPoint(400, 0), touchEnd: QPoint(490, 0)); |
488 | |
489 | QTRY_COMPARE(s1->state(), QScroller::Inactive); |
490 | |
491 | QVERIFY(qFuzzyCompare(sw->currentPos.x(), 0)); |
492 | QVERIFY(qFuzzyCompare(sw->currentPos.y(), 500)); |
493 | QCOMPARE(sw->receivedOvershoot, false); |
494 | |
495 | // -- try to scroll with overshoot (always on but max overshoot = 0) |
496 | sp1.setScrollMetric(metric: QScrollerProperties::OvershootDragDistanceFactor, value: 0.0); |
497 | sp1.setScrollMetric(metric: QScrollerProperties::OvershootScrollDistanceFactor, value: 0.0); |
498 | sw->reset(); |
499 | sw->scrollArea = QRectF(0, 0, 1000, 1000); |
500 | |
501 | sp1.setScrollMetric(metric: QScrollerProperties::HorizontalOvershootPolicy, value: QVariant::fromValue(value: QScrollerProperties::OvershootAlwaysOn)); |
502 | s1->setScrollerProperties(sp1); |
503 | kineticScrollNoTest(sw: sw.data(), from: QPointF(500, 500), touchStart: QPoint(0, 0), touchUpdate: QPoint(400, 0), touchEnd: QPoint(490, 0)); |
504 | |
505 | QTRY_COMPARE(s1->state(), QScroller::Inactive); |
506 | |
507 | QVERIFY(qFuzzyCompare(sw->currentPos.x(), 0)); |
508 | QVERIFY(qFuzzyCompare(sw->currentPos.y(), 500)); |
509 | QCOMPARE(sw->receivedOvershoot, false); |
510 | #endif |
511 | } |
512 | |
513 | void tst_QScroller::multipleWindows() |
514 | { |
515 | #if QT_CONFIG(gestures) && QT_CONFIG(scroller) |
516 | QScopedPointer<tst_QScrollerWidget> sw1(new tst_QScrollerWidget); |
517 | sw1->scrollArea = QRectF(0, 0, 1000, 1000); |
518 | QScroller::grabGesture(target: sw1.data(), gestureType: QScroller::TouchGesture); |
519 | sw1->setGeometry(ax: 100, ay: 100, aw: 400, ah: 300); |
520 | |
521 | QScroller *s1 = QScroller::scroller(target: sw1.data()); |
522 | kineticScroll(sw: sw1.data(), from: QPointF(500, 500), touchStart: QPoint(0, 0), touchUpdate: QPoint(100, 100), touchEnd: QPoint(200, 200)); |
523 | // now we should be scrolling |
524 | QTRY_COMPARE(s1->state(), QScroller::Scrolling); |
525 | |
526 | // That was fun! Do it again! |
527 | QScopedPointer<tst_QScrollerWidget> sw2(new tst_QScrollerWidget()); |
528 | sw2->scrollArea = QRectF(0, 0, 1000, 1000); |
529 | QScroller::grabGesture(target: sw2.data(), gestureType: QScroller::TouchGesture); |
530 | sw2->setGeometry(ax: 100, ay: 100, aw: 400, ah: 300); |
531 | |
532 | QScroller *s2 = QScroller::scroller(target: sw2.data()); |
533 | kineticScroll(sw: sw2.data(), from: QPointF(500, 500), touchStart: QPoint(0, 0), touchUpdate: QPoint(100, 100), touchEnd: QPoint(200, 200)); |
534 | // now we should be scrolling |
535 | QTRY_COMPARE(s2->state(), QScroller::Scrolling); |
536 | |
537 | // wait for both to stop |
538 | QTRY_VERIFY(s1->state() != QScroller::Scrolling); |
539 | QTRY_VERIFY(s2->state() != QScroller::Scrolling); |
540 | |
541 | sw1.reset(); // destroy one window |
542 | sw2->reset(); // reset the other scroller's internal state |
543 | // make sure we can still scroll the remaining one without crashing (QTBUG-71232) |
544 | kineticScroll(sw: sw2.data(), from: QPointF(500, 500), touchStart: QPoint(0, 0), touchUpdate: QPoint(100, 100), touchEnd: QPoint(200, 200)); |
545 | #endif |
546 | } |
547 | |
548 | QTEST_MAIN(tst_QScroller) |
549 | |
550 | #include "tst_qscroller.moc" |
551 | |