Qt 6.x
The Qt SDK
Loading...
Searching...
No Matches
qquickflickable.cpp
Go to the documentation of this file.
1// Copyright (C) 2020 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qquickflickable_p.h"
7#include "qquickwindow.h"
8#include "qquickwindow_p.h"
9#include "qquickmousearea_p.h"
10#if QT_CONFIG(quick_draganddrop)
11#include "qquickdrag_p.h"
12#endif
13
14#include <QtQuick/private/qquickpointerhandler_p.h>
15#include <QtQuick/private/qquicktransition_p.h>
16#include <private/qqmlglobal_p.h>
17
18#include <QtQml/qqmlinfo.h>
19#include <QtGui/qevent.h>
20#include <QtGui/qguiapplication.h>
21#include <QtGui/private/qguiapplication_p.h>
22#include <QtGui/private/qeventpoint_p.h>
23#include <QtGui/qstylehints.h>
24#include <QtCore/qmath.h>
25#include <qpa/qplatformintegration.h>
26
27#include <math.h>
28#include <cmath>
29
31
32Q_DECLARE_LOGGING_CATEGORY(lcHandlerParent)
33Q_LOGGING_CATEGORY(lcFlickable, "qt.quick.flickable")
34Q_LOGGING_CATEGORY(lcFilter, "qt.quick.flickable.filter")
35Q_LOGGING_CATEGORY(lcReplay, "qt.quick.flickable.replay")
36Q_LOGGING_CATEGORY(lcWheel, "qt.quick.flickable.wheel")
37Q_LOGGING_CATEGORY(lcVel, "qt.quick.flickable.velocity")
38
39// RetainGrabVelocity is the maxmimum instantaneous velocity that
40// will ensure the Flickable retains the grab on consecutive flicks.
41static const int RetainGrabVelocity = 100;
42
44 return qAtan(t);
45}
46
48 : QObject(parent), flickable(parent), m_xPosition(0.), m_widthRatio(0.)
49 , m_yPosition(0.), m_heightRatio(0.)
50{
51}
52
54{
55 return m_widthRatio;
56}
57
59{
60 return m_xPosition;
61}
62
64{
65 return m_heightRatio;
66}
67
69{
70 return m_yPosition;
71}
72
74{
76
77 bool changeX = false;
78 bool changeY = false;
79 bool changeWidth = false;
80 bool changeHeight = false;
81
82 // Vertical
83 const qreal viewheight = flickable->height();
84 const qreal maxyextent = -flickable->maxYExtent() + flickable->minYExtent();
85 const qreal maxYBounds = maxyextent + viewheight;
86 qreal pagePos = 0;
87 qreal pageSize = 0;
88 if (!qFuzzyIsNull(maxYBounds)) {
89 qreal y = p->pixelAligned ? std::round(p->vData.move.value()) : p->vData.move.value();
90 pagePos = (-y + flickable->minYExtent()) / maxYBounds;
91 pageSize = viewheight / maxYBounds;
92 }
93
94 if (pageSize != m_heightRatio) {
95 m_heightRatio = pageSize;
96 changeHeight = true;
97 }
98 if (pagePos != m_yPosition) {
99 m_yPosition = pagePos;
100 changeY = true;
101 }
102
103 // Horizontal
104 const qreal viewwidth = flickable->width();
105 const qreal maxxextent = -flickable->maxXExtent() + flickable->minXExtent();
106 const qreal maxXBounds = maxxextent + viewwidth;
107 if (!qFuzzyIsNull(maxXBounds)) {
108 qreal x = p->pixelAligned ? std::round(p->hData.move.value()) : p->hData.move.value();
109 pagePos = (-x + flickable->minXExtent()) / maxXBounds;
110 pageSize = viewwidth / maxXBounds;
111 } else {
112 pagePos = 0;
113 pageSize = 0;
114 }
115
116 if (pageSize != m_widthRatio) {
117 m_widthRatio = pageSize;
118 changeWidth = true;
119 }
120 if (pagePos != m_xPosition) {
121 m_xPosition = pagePos;
122 changeX = true;
123 }
124
125 if (changeX)
126 emit xPositionChanged(m_xPosition);
127 if (changeY)
128 emit yPositionChanged(m_yPosition);
129 if (changeWidth)
130 emit widthRatioChanged(m_widthRatio);
131 if (changeHeight)
132 emit heightRatioChanged(m_heightRatio);
133}
134
135
137{
138public:
140 : flickable(f), axisData(nullptr), propName(name), active(false)
141 {
142 }
143
145 {
146 flickable = nullptr;
147 }
148
151 if (!fp->rebound || !fp->rebound->enabled())
152 return false;
153 active = true;
154 axisData = data;
155 axisData->transitionTo = toPos;
156 axisData->transitionToSet = true;
157
158 actions.clear();
159 actions << QQuickStateAction(fp->contentItem, propName, toPos);
160 QQuickTransitionManager::transition(actions, fp->rebound, fp->contentItem);
161 return true;
162 }
163
164 bool isActive() const {
165 return active;
166 }
167
169 if (!flickable || !isRunning())
170 return;
172 if (axisData == &fp->hData)
173 axisData->move.setValue(-flickable->contentX());
174 else
175 axisData->move.setValue(-flickable->contentY());
176 active = false;
177 cancel();
178 }
179
180protected:
181 void finished() override {
182 if (!flickable)
183 return;
184 axisData->move.setValue(axisData->transitionTo);
186 active = false;
187
188 if (!fp->hData.transitionToBounds->isActive()
189 && !fp->vData.transitionToBounds->isActive()) {
190 flickable->movementEnding();
191 }
192 }
193
194private:
196 QQuickFlickable *flickable;
198 QString propName;
199 bool active;
200};
201
203{
204 delete transitionToBounds;
205}
206
208{
218 bool contains(const QPointF &point) const override
219 {
220 const QQuickItem *flickable = parentItem();
221 const QPointF posInFlickable = flickable->mapFromItem(this, point);
222 return flickable->contains(posInFlickable);
223 }
224};
225
234 , syncDrag(false)
235 , lastPosTime(-1)
236 , lastPressTime(0)
237 , deceleration(QGuiApplicationPrivate::platformIntegration()->styleHint(QPlatformIntegration::FlickDeceleration).toReal())
238 , wheelDeceleration(15000)
239 , maxVelocity(QGuiApplicationPrivate::platformIntegration()->styleHint(QPlatformIntegration::FlickMaximumVelocity).toReal())
241 , flickBoost(1.0), initialWheelFlickDistance(qApp->styleHints()->wheelScrollLines() * 24)
243 , flickableDirection(QQuickFlickable::AutoFlickDirection)
244 , boundsBehavior(QQuickFlickable::DragAndOvershootBounds)
245 , boundsMovement(QQuickFlickable::FollowBoundsBehavior)
247{
248 const int wheelDecelerationEnv = qEnvironmentVariableIntValue("QT_QUICK_FLICKABLE_WHEEL_DECELERATION");
249 if (wheelDecelerationEnv > 0)
250 wheelDeceleration = wheelDecelerationEnv;
251}
252
254{
255 Q_Q(QQuickFlickable);
259 q, QQuickFlickable, SLOT(timelineCompleted()));
261 q, QQuickFlickable, SLOT(velocityTimelineCompleted()));
262 q->setAcceptedMouseButtons(Qt::LeftButton);
263 q->setAcceptTouchEvents(true);
264 q->setFiltersChildMouseEvents(true);
268}
269
276{
277 if (maxVelocity <= 0)
278 return 0;
279
280 return qMin(qreal(QML_FLICK_OVERSHOOT), velocity / 3);
281}
282
284{
285 if (v > maxVelocity)
286 v = maxVelocity;
287 else if (v < -maxVelocity)
288 v = -maxVelocity;
292}
293
295{
296 velocity = 0;
297 if (velocityBuffer.count() > QML_FLICK_DISCARDSAMPLES) {
298 int count = velocityBuffer.count()-QML_FLICK_DISCARDSAMPLES;
299 for (int i = 0; i < count; ++i) {
300 qreal v = velocityBuffer.at(i);
301 velocity += v;
302 }
303 velocity /= count;
304 }
305}
306
308{
309 Q_Q(QQuickFlickable);
310 if (item == contentItem) {
311 Qt::Orientations orient;
312 if (change.xChange())
313 orient |= Qt::Horizontal;
314 if (change.yChange())
315 orient |= Qt::Vertical;
316 if (orient) {
317 q->viewportMoved(orient);
318 const QPointF deltaMoved = item->position() - oldGeom.topLeft();
320 hData.pressPos += deltaMoved.x();
322 vData.pressPos += deltaMoved.y();
323 }
324 if (orient & Qt::Horizontal)
325 emit q->contentXChanged();
326 if (orient & Qt::Vertical)
327 emit q->contentYChanged();
328 }
329}
330
332{
333 Q_Q(QQuickFlickable);
334 return flick(hData, q->minXExtent(), q->maxXExtent(), q->width(), fixupX_callback, eventType, velocity);
335}
336
338{
339 Q_Q(QQuickFlickable);
340 return flick(vData, q->minYExtent(), q->maxYExtent(), q->height(), fixupY_callback, eventType, velocity);
341}
342
345 QEvent::Type eventType, qreal velocity)
346{
347 Q_Q(QQuickFlickable);
348 qreal maxDistance = -1;
349 data.fixingUp = false;
350 // -ve velocity means list is moving up
351 if (velocity > 0) {
352 maxDistance = qAbs(minExtent - data.move.value());
353 data.flickTarget = minExtent;
354 } else {
355 maxDistance = qAbs(maxExtent - data.move.value());
356 data.flickTarget = maxExtent;
357 }
358 if (maxDistance > 0 || boundsBehavior & QQuickFlickable::OvershootBounds) {
359 qreal v = velocity;
360 if (maxVelocity != -1 && maxVelocity < qAbs(v)) {
361 if (v < 0)
362 v = -maxVelocity;
363 else
364 v = maxVelocity;
365 }
366
367 qreal accel = eventType == QEvent::Wheel ? wheelDeceleration : deceleration;
368 qCDebug(lcFlickable) << "choosing deceleration" << accel << "for" << eventType;
369 // adjust accel so that we hit a full pixel
370 qreal v2 = v * v;
371 qreal dist = v2 / (accel * 2.0);
372 if (v > 0)
373 dist = -dist;
374 qreal target = -std::round(-(data.move.value() - dist));
375 dist = -target + data.move.value();
376 accel = v2 / (2.0f * qAbs(dist));
377
379 if (!data.inOvershoot) {
381 timeline.accel(data.move, v, accel);
382 else
383 timeline.accel(data.move, v, accel, maxDistance);
384 }
385 timeline.callback(QQuickTimeLineCallback(&data.move, fixupCallback, this));
386
387 if (&data == &hData)
388 return !hData.flicking && q->xflick();
389 else if (&data == &vData)
390 return !vData.flicking && q->yflick();
391 return false;
392 } else {
394 fixup(data, minExtent, maxExtent);
395 return false;
396 }
397}
398
400{
401 ((QQuickFlickablePrivate *)data)->fixupY();
402}
403
405{
406 ((QQuickFlickablePrivate *)data)->fixupX();
407}
408
410{
411 Q_Q(QQuickFlickable);
412 if (!q->isComponentComplete())
413 return; //Do not fixup from initialization values
414 fixup(hData, q->minXExtent(), q->maxXExtent());
415}
416
418{
419 Q_Q(QQuickFlickable);
420 if (!q->isComponentComplete())
421 return; //Do not fixup from initialization values
422 fixup(vData, q->minYExtent(), q->maxYExtent());
423}
424
434{
435 Q_Q(QQuickFlickable);
436 switch (fixupMode) {
437 case Immediate:
438 timeline.set(data.move, toPos);
439 break;
440 case ExtentChanged:
441 // The target has changed. Don't start from the beginning; just complete the
442 // second half of the animation using the new extent.
444 data.fixingUp = true;
445 break;
446 default: {
447 if (data.transitionToBounds && data.transitionToBounds->startTransition(&data, toPos)) {
448 q->movementStarting();
449 data.fixingUp = true;
450 } else {
451 qreal dist = toPos - data.move;
454 data.fixingUp = true;
455 }
456 }
457 }
458}
459
461{
462 timeline.reset(data.move);
463 if (data.transitionToBounds)
464 data.transitionToBounds->stopTransition();
465}
466
468{
469 timeline.clear();
474}
475
487{
488 if (data.move.value() >= minExtent || maxExtent > minExtent) {
490 if (data.move.value() != minExtent) {
491 adjustContentPos(data, minExtent);
492 }
493 } else if (data.move.value() <= maxExtent) {
495 adjustContentPos(data, maxExtent);
496 } else if (-std::round(-data.move.value()) != data.move.value()) {
497 // We could animate, but since it is less than 0.5 pixel it's probably not worthwhile.
499 qreal val = data.move.value();
500 if (qAbs(-std::round(-val) - val) < 0.25) // round small differences
501 val = -std::round(-val);
502 else if (data.smoothVelocity.value() > 0) // continue direction of motion for larger
503 val = -qFloor(-val);
504 else if (data.smoothVelocity.value() < 0)
505 val = -qCeil(-val);
506 else // otherwise round
507 val = -std::round(-val);
508 timeline.set(data.move, val);
509 }
510 data.inOvershoot = false;
512 data.vTime = timeline.time();
513}
514
516{
517 if (a == 0.0 || b == 0.0) {
518 // qFuzzyCompare is broken
519 a += 1.0;
520 b += 1.0;
521 }
522 return a <= b || qFuzzyCompare(a, b);
523}
524
535{
536 Q_Q(QQuickFlickable);
537 bool atXBeginningChange = false, atXEndChange = false;
538 bool atYBeginningChange = false, atYEndChange = false;
539
540 // Vertical
541 const qreal maxyextent = -q->maxYExtent();
542 const qreal minyextent = -q->minYExtent();
543 const qreal ypos = -vData.move.value();
544 bool atBeginning = fuzzyLessThanOrEqualTo(ypos, std::ceil(minyextent));
545 bool atEnd = fuzzyLessThanOrEqualTo(std::floor(maxyextent), ypos);
546
547 if (atBeginning != vData.atBeginning) {
548 vData.atBeginning = atBeginning;
549 atYBeginningChange = true;
550 if (!vData.moving && atBeginning)
552 }
553 if (atEnd != vData.atEnd) {
554 vData.atEnd = atEnd;
555 atYEndChange = true;
556 if (!vData.moving && atEnd)
558 }
559
560 // Horizontal
561 const qreal maxxextent = -q->maxXExtent();
562 const qreal minxextent = -q->minXExtent();
563 const qreal xpos = -hData.move.value();
564 atBeginning = fuzzyLessThanOrEqualTo(xpos, std::ceil(minxextent));
565 atEnd = fuzzyLessThanOrEqualTo(std::floor(maxxextent), xpos);
566
567 if (atBeginning != hData.atBeginning) {
568 hData.atBeginning = atBeginning;
569 atXBeginningChange = true;
570 if (!hData.moving && atBeginning)
572 }
573 if (atEnd != hData.atEnd) {
574 hData.atEnd = atEnd;
575 atXEndChange = true;
576 if (!hData.moving && atEnd)
578 }
579
580 if (vData.extentsChanged) {
581 vData.extentsChanged = false;
582 qreal originY = q->originY();
583 if (vData.origin != originY) {
584 vData.origin = originY;
585 emit q->originYChanged();
586 }
587 }
588
589 if (hData.extentsChanged) {
590 hData.extentsChanged = false;
591 qreal originX = q->originX();
592 if (hData.origin != originX) {
593 hData.origin = originX;
594 emit q->originXChanged();
595 }
596 }
597
598 if (atXEndChange || atYEndChange || atXBeginningChange || atYBeginningChange)
599 emit q->isAtBoundaryChanged();
600 if (atXEndChange)
601 emit q->atXEndChanged();
602 if (atXBeginningChange)
603 emit q->atXBeginningChanged();
604 if (atYEndChange)
605 emit q->atYEndChanged();
606 if (atYBeginningChange)
607 emit q->atYBeginningChanged();
608
609 if (visibleArea)
611}
612
761{
762 Q_D(QQuickFlickable);
763 d->init();
764}
765
767 : QQuickItem(dd, parent)
768{
769 Q_D(QQuickFlickable);
770 d->init();
771}
772
774{
775}
776
798{
799 Q_D(const QQuickFlickable);
800 return -d->contentItem->x();
801}
802
804{
805 Q_D(QQuickFlickable);
806 d->hData.explicitValue = true;
807 d->resetTimeline(d->hData);
808 d->hData.vTime = d->timeline.time();
809 if (isMoving() || isFlicking())
810 movementEnding(true, false);
811 if (!qFuzzyCompare(-pos, d->hData.move.value())) {
812 d->hData.contentPositionChangedExternallyDuringDrag = d->hData.dragging;
813 d->hData.move.setValue(-pos);
814 d->hData.contentPositionChangedExternallyDuringDrag = false;
815 }
816}
817
819{
820 Q_D(const QQuickFlickable);
821 return -d->contentItem->y();
822}
823
825{
826 Q_D(QQuickFlickable);
827 d->vData.explicitValue = true;
828 d->resetTimeline(d->vData);
829 d->vData.vTime = d->timeline.time();
830 if (isMoving() || isFlicking())
831 movementEnding(false, true);
832 if (!qFuzzyCompare(-pos, d->vData.move.value())) {
833 d->vData.contentPositionChangedExternallyDuringDrag = d->vData.dragging;
834 d->vData.move.setValue(-pos);
835 d->vData.contentPositionChangedExternallyDuringDrag = false;
836 }
837}
838
853{
854 Q_D(const QQuickFlickable);
855 return d->interactive;
856}
857
859{
860 Q_D(QQuickFlickable);
861 if (interactive != d->interactive) {
862 d->interactive = interactive;
863 if (!interactive) {
864 d->cancelInteraction();
865 }
867 }
868}
869
884{
885 Q_D(const QQuickFlickable);
886 return d->hData.smoothVelocity.value();
887}
888
890{
891 Q_D(const QQuickFlickable);
892 return d->vData.smoothVelocity.value();
893}
894
905{
906 Q_D(const QQuickFlickable);
907 return d->hData.atEnd;
908}
909
911{
912 Q_D(const QQuickFlickable);
913 return d->hData.atBeginning;
914}
915
917{
918 Q_D(const QQuickFlickable);
919 return d->vData.atEnd;
920}
921
923{
924 Q_D(const QQuickFlickable);
925 return d->vData.atBeginning;
926}
927
947{
948 Q_D(const QQuickFlickable);
949 return d->contentItem;
950}
951
953{
954 Q_D(QQuickFlickable);
955 if (!d->visibleArea) {
956 d->visibleArea = new QQuickFlickableVisibleArea(this);
957 d->visibleArea->updateVisible(); // calculate initial ratios
958 }
959 return d->visibleArea;
960}
961
982{
983 Q_D(const QQuickFlickable);
984 return d->flickableDirection;
985}
986
988{
989 Q_D(QQuickFlickable);
990 if (direction != d->flickableDirection) {
991 d->flickableDirection = direction;
993 }
994}
995
1009{
1010 Q_D(const QQuickFlickable);
1011 return d->pixelAligned;
1012}
1013
1015{
1016 Q_D(QQuickFlickable);
1017 if (align != d->pixelAligned) {
1018 d->pixelAligned = align;
1020 }
1021}
1022
1036{
1037 Q_D(const QQuickFlickable);
1038 return d->syncDrag;
1039}
1040
1042{
1043 Q_D(QQuickFlickable);
1044 if (v != d->syncDrag) {
1045 d->syncDrag = v;
1046 emit synchronousDragChanged();
1047 }
1048}
1049
1055{
1057 // rotate and scale the velocity vector from scene to local
1058 return QVector2D(transform.map(event->point(0).velocity().toPointF()) - transform.map(QPointF()));
1059}
1060
1062{
1063 if (0 != event->timestamp())
1064 return event->timestamp();
1065 if (!timer.isValid())
1066 return 0LL;
1067 return timer.elapsed();
1068}
1069
1071{
1072 return (window ? window->effectiveDevicePixelRatio() : qApp->devicePixelRatio());
1073}
1074
1076{
1077 Q_Q(QQuickFlickable);
1078 timer.start();
1082 stealMouse = true; // If we've been flicked then steal the click.
1083 int flickTime = timeline.time();
1084 if (flickTime > 600) {
1085 // too long between flicks - cancel boost
1088 flickBoost = 1.0;
1089 } else {
1092 if (flickTime > 300) // slower flicking - reduce boost
1093 flickBoost = qMax(1.0, flickBoost - 0.5);
1094 }
1095 } else {
1096 stealMouse = false;
1099 flickBoost = 1.0;
1100 }
1101 q->setKeepMouseGrab(stealMouse);
1102
1103 maybeBeginDrag(computeCurrentTime(event), event->points().first().position());
1104}
1105
1106void QQuickFlickablePrivate::maybeBeginDrag(qint64 currentTimestamp, const QPointF &pressPosn)
1107{
1108 Q_Q(QQuickFlickable);
1110 pressed = true;
1111
1116 if (!hData.fixingUp)
1118 if (!vData.fixingUp)
1120
1121 hData.reset();
1122 vData.reset();
1123 hData.dragMinBound = q->minXExtent() - hData.startMargin;
1124 vData.dragMinBound = q->minYExtent() - vData.startMargin;
1125 hData.dragMaxBound = q->maxXExtent() + hData.endMargin;
1126 vData.dragMaxBound = q->maxYExtent() + vData.endMargin;
1127 fixupMode = Normal;
1128 lastPos = QPointF();
1129 pressPos = pressPosn;
1132 const bool wasFlicking = hData.flicking || vData.flicking;
1135 if (hData.flicking) {
1136 hData.flicking = false;
1137 emit q->flickingHorizontallyChanged();
1138 }
1139 if (vData.flicking) {
1140 vData.flicking = false;
1141 emit q->flickingVerticallyChanged();
1142 }
1143 if (wasFlicking)
1144 emit q->flickingChanged();
1145 lastPosTime = lastPressTime = currentTimestamp;
1148}
1149
1150void QQuickFlickablePrivate::drag(qint64 currentTimestamp, QEvent::Type eventType, const QPointF &localPos,
1151 const QVector2D &deltas, bool overThreshold, bool momentum,
1152 bool velocitySensitiveOverBounds, const QVector2D &velocity)
1153{
1154 Q_Q(QQuickFlickable);
1155 bool rejectY = false;
1156 bool rejectX = false;
1157
1158 bool keepY = q->yflick();
1159 bool keepX = q->xflick();
1160
1161 bool stealY = false;
1162 bool stealX = false;
1163 if (eventType == QEvent::MouseMove) {
1164 stealX = stealY = stealMouse;
1165 } else if (eventType == QEvent::Wheel) {
1166 stealX = stealY = scrollingPhase;
1167 }
1168
1169 bool prevHMoved = hMoved;
1170 bool prevVMoved = vMoved;
1171
1172 qint64 elapsedSincePress = currentTimestamp - lastPressTime;
1173 qCDebug(lcFlickable).nospace() << currentTimestamp << ' ' << eventType << " drag @ " << localPos.x() << ',' << localPos.y()
1174 << " \u0394 " << deltas.x() << ',' << deltas.y() << " vel " << velocity.x() << ',' << velocity.y()
1175 << " thrsld? " << overThreshold << " momentum? " << momentum << " velSens? " << velocitySensitiveOverBounds
1176 << " sincePress " << elapsedSincePress;
1177
1178 if (q->yflick()) {
1179 qreal dy = deltas.y();
1180 if (overThreshold || elapsedSincePress > 200) {
1181 if (!vMoved)
1183 qreal newY = dy + vData.pressPos - (syncDrag ? 0 : vData.dragStartOffset);
1184 // Recalculate bounds in case margins have changed, but use the content
1185 // size estimate taken at the start of the drag in case the drag causes
1186 // the estimate to be altered
1190 if (fuzzyLessThanOrEqualTo(newY, maxY)) {
1191 newY = maxY;
1192 rejectY = vData.pressPos == maxY && vData.move.value() == maxY && dy < 0;
1193 }
1194 if (fuzzyLessThanOrEqualTo(minY, newY)) {
1195 newY = minY;
1196 rejectY |= vData.pressPos == minY && vData.move.value() == minY && dy > 0;
1197 }
1198 } else {
1199 qreal vel = velocity.y() / QML_FLICK_OVERSHOOTFRICTION;
1200 if (vel > 0. && vel > vData.velocity)
1202 else if (vel < 0. && vel < vData.velocity)
1204 if (newY > minY) {
1205 // Overshoot beyond the top. But don't wait for momentum phase to end before returning to bounds.
1206 if (momentum && vData.atBeginning) {
1207 if (!vData.inRebound) {
1208 vData.inRebound = true;
1209 q->returnToBounds();
1210 }
1211 return;
1212 }
1213 if (velocitySensitiveOverBounds) {
1216 newY = minY + overshoot;
1217 } else {
1218 newY = minY + (newY - minY) / 2;
1219 }
1220 } else if (newY < maxY && maxY - minY <= 0) {
1221 // Overshoot beyond the bottom. But don't wait for momentum phase to end before returning to bounds.
1222 if (momentum && vData.atEnd) {
1223 if (!vData.inRebound) {
1224 vData.inRebound = true;
1225 q->returnToBounds();
1226 }
1227 return;
1228 }
1229 if (velocitySensitiveOverBounds) {
1232 newY = maxY - overshoot;
1233 } else {
1234 newY = maxY + (newY - maxY) / 2;
1235 }
1236 }
1237 }
1238 if (!rejectY && stealMouse && dy != 0.0 && dy != vData.previousDragDelta) {
1239 clearTimeline();
1240 vData.move.setValue(newY);
1241 vMoved = true;
1242 }
1243 if (!rejectY && overThreshold)
1244 stealY = true;
1245
1246 if ((newY >= minY && vData.pressPos == minY && vData.move.value() == minY && dy > 0)
1247 || (newY <= maxY && vData.pressPos == maxY && vData.move.value() == maxY && dy < 0)) {
1248 keepY = false;
1249 }
1250 }
1252 }
1253
1254 if (q->xflick()) {
1255 qreal dx = deltas.x();
1256 if (overThreshold || elapsedSincePress > 200) {
1257 if (!hMoved)
1259 qreal newX = dx + hData.pressPos - (syncDrag ? 0 : hData.dragStartOffset);
1260 const qreal minX = hData.dragMinBound + hData.startMargin;
1263 if (fuzzyLessThanOrEqualTo(newX, maxX)) {
1264 newX = maxX;
1265 rejectX = hData.pressPos == maxX && hData.move.value() == maxX && dx < 0;
1266 }
1267 if (fuzzyLessThanOrEqualTo(minX, newX)) {
1268 newX = minX;
1269 rejectX |= hData.pressPos == minX && hData.move.value() == minX && dx > 0;
1270 }
1271 } else {
1272 qreal vel = velocity.x() / QML_FLICK_OVERSHOOTFRICTION;
1273 if (vel > 0. && vel > hData.velocity)
1275 else if (vel < 0. && vel < hData.velocity)
1277 if (newX > minX) {
1278 // Overshoot beyond the left. But don't wait for momentum phase to end before returning to bounds.
1279 if (momentum && hData.atBeginning) {
1280 if (!hData.inRebound) {
1281 hData.inRebound = true;
1282 q->returnToBounds();
1283 }
1284 return;
1285 }
1286 if (velocitySensitiveOverBounds) {
1287 qreal overshoot = (newX - minX) * hData.velocity / maxVelocity / QML_FLICK_OVERSHOOTFRICTION;
1289 newX = minX + overshoot;
1290 } else {
1291 newX = minX + (newX - minX) / 2;
1292 }
1293 } else if (newX < maxX && maxX - minX <= 0) {
1294 // Overshoot beyond the right. But don't wait for momentum phase to end before returning to bounds.
1295 if (momentum && hData.atEnd) {
1296 if (!hData.inRebound) {
1297 hData.inRebound = true;
1298 q->returnToBounds();
1299 }
1300 return;
1301 }
1302 if (velocitySensitiveOverBounds) {
1305 newX = maxX - overshoot;
1306 } else {
1307 newX = maxX + (newX - maxX) / 2;
1308 }
1309 }
1310 }
1311
1312 if (!rejectX && stealMouse && dx != 0.0 && dx != hData.previousDragDelta) {
1313 clearTimeline();
1314 hData.move.setValue(newX);
1315 hMoved = true;
1316 }
1317
1318 if (!rejectX && overThreshold)
1319 stealX = true;
1320
1321 if ((newX >= minX && vData.pressPos == minX && vData.move.value() == minX && dx > 0)
1322 || (newX <= maxX && vData.pressPos == maxX && vData.move.value() == maxX && dx < 0)) {
1323 keepX = false;
1324 }
1325 }
1327 }
1328
1329 stealMouse = stealX || stealY;
1330 if (stealMouse) {
1331 if ((stealX && keepX) || (stealY && keepY))
1332 q->setKeepMouseGrab(true);
1334 }
1335
1336 if (rejectY) {
1338 vData.velocity = 0;
1339 }
1340 if (rejectX) {
1342 hData.velocity = 0;
1343 }
1344
1345 if (momentum && !hData.flicking && !vData.flicking)
1348
1349 if ((hMoved && !prevHMoved) || (vMoved && !prevVMoved))
1350 q->movementStarting();
1351
1352 lastPosTime = currentTimestamp;
1353 if (q->yflick() && !rejectY)
1354 vData.addVelocitySample(velocity.y(), maxVelocity);
1355 if (q->xflick() && !rejectX)
1356 hData.addVelocitySample(velocity.x(), maxVelocity);
1357 lastPos = localPos;
1358}
1359
1361{
1362 Q_Q(QQuickFlickable);
1363 if (!interactive || lastPosTime == -1 ||
1364 (event->isSinglePointEvent() && !static_cast<QSinglePointEvent *>(event)->buttons().testFlag(Qt::LeftButton)))
1365 return;
1366
1367 qint64 currentTimestamp = computeCurrentTime(event);
1368 const auto &firstPoint = event->points().first();
1369 const auto &pos = firstPoint.position();
1370 const QVector2D deltas = QVector2D(pos - q->mapFromGlobal(firstPoint.globalPressPosition()));
1371 const QVector2D velocity = firstPointLocalVelocity(event);
1372 bool overThreshold = false;
1373
1374 if (event->pointCount() == 1) {
1375 if (q->yflick())
1376 overThreshold |= QQuickDeliveryAgentPrivate::dragOverThreshold(deltas.y(), Qt::YAxis, firstPoint);
1377 if (q->xflick())
1378 overThreshold |= QQuickDeliveryAgentPrivate::dragOverThreshold(deltas.x(), Qt::XAxis, firstPoint);
1379 } else {
1380 qCDebug(lcFilter) << q->objectName() << "ignoring multi-touch" << event;
1381 }
1382
1383 drag(currentTimestamp, event->type(), pos, deltas, overThreshold, false, false, velocity);
1384}
1385
1387{
1388 Q_Q(QQuickFlickable);
1389 stealMouse = false;
1390 q->setKeepMouseGrab(false);
1391 pressed = false;
1392
1393 // if we drag then pause before release we should not cause a flick.
1395
1398
1400
1401 if (lastPosTime == -1)
1402 return;
1403
1405
1406 bool canBoost = false;
1407 const auto pos = event->points().first().position();
1408 const auto pressPos = q->mapFromGlobal(event->points().first().globalPressPosition());
1409 const QVector2D eventVelocity = firstPointLocalVelocity(event);
1410 qCDebug(lcVel) << event->deviceType() << event->type() << "velocity" << event->points().first().velocity() << "transformed to local" << eventVelocity;
1411
1412 qreal vVelocity = 0;
1413 if (elapsed < 100 && vData.velocity != 0.) {
1414 vVelocity = (event->device()->capabilities().testFlag(QInputDevice::Capability::Velocity)
1415 ? eventVelocity.y() : vData.velocity);
1416 }
1417 if ((vData.atBeginning && vVelocity > 0.) || (vData.atEnd && vVelocity < 0.)) {
1418 vVelocity /= 2;
1419 } else if (vData.continuousFlickVelocity != 0.0
1421 && ((vVelocity > 0) == (vData.continuousFlickVelocity > 0))
1422 && qAbs(vVelocity) > QML_FLICK_MULTIFLICK_THRESHOLD) {
1423 // accelerate flick for large view flicked quickly
1424 canBoost = true;
1425 }
1426
1427 qreal hVelocity = 0;
1428 if (elapsed < 100 && hData.velocity != 0.) {
1429 hVelocity = (event->device()->capabilities().testFlag(QInputDevice::Capability::Velocity)
1430 ? eventVelocity.x() : hData.velocity);
1431 }
1432 if ((hData.atBeginning && hVelocity > 0.) || (hData.atEnd && hVelocity < 0.)) {
1433 hVelocity /= 2;
1434 } else if (hData.continuousFlickVelocity != 0.0
1436 && ((hVelocity > 0) == (hData.continuousFlickVelocity > 0))
1437 && qAbs(hVelocity) > QML_FLICK_MULTIFLICK_THRESHOLD) {
1438 // accelerate flick for large view flicked quickly
1439 canBoost = true;
1440 }
1441
1442 flickBoost = canBoost ? qBound(1.0, flickBoost+0.25, QML_FLICK_MULTIFLICK_MAXBOOST) : 1.0;
1444
1445 bool flickedVertically = false;
1446 vVelocity *= flickBoost;
1447 bool isVerticalFlickAllowed = q->yflick() && qAbs(vVelocity) > _q_MinimumFlickVelocity && qAbs(pos.y() - pressPos.y()) > flickThreshold;
1448 if (isVerticalFlickAllowed) {
1450 vData.smoothVelocity.setValue(-vVelocity);
1451 flickedVertically = flickY(event->type(), vVelocity);
1452 }
1453
1454 bool flickedHorizontally = false;
1455 hVelocity *= flickBoost;
1456 bool isHorizontalFlickAllowed = q->xflick() && qAbs(hVelocity) > _q_MinimumFlickVelocity && qAbs(pos.x() - pressPos.x()) > flickThreshold;
1457 if (isHorizontalFlickAllowed) {
1459 hData.smoothVelocity.setValue(-hVelocity);
1460 flickedHorizontally = flickX(event->type(), hVelocity);
1461 }
1462
1463 if (!isVerticalFlickAllowed)
1464 fixupY();
1465
1466 if (!isHorizontalFlickAllowed)
1467 fixupX();
1468
1469 flickingStarted(flickedHorizontally, flickedVertically);
1470 if (!isViewMoving()) {
1471 q->movementEnding();
1472 } else {
1473 if (flickedVertically)
1474 vMoved = true;
1475 if (flickedHorizontally)
1476 hMoved = true;
1477 q->movementStarting();
1478 }
1479}
1480
1482{
1483 Q_D(QQuickFlickable);
1484 if (d->interactive && !d->replayingPressEvent && d->wantsPointerEvent(event)) {
1485 if (!d->pressed)
1486 d->handlePressEvent(event);
1487 event->accept();
1488 } else {
1490 }
1491}
1492
1494{
1495 Q_D(QQuickFlickable);
1496 if (d->interactive && d->wantsPointerEvent(event)) {
1497 d->handleMoveEvent(event);
1498 event->accept();
1499 } else {
1501 }
1502}
1503
1505{
1506 Q_D(QQuickFlickable);
1507 if (d->interactive && d->wantsPointerEvent(event)) {
1508 if (d->delayedPressEvent) {
1509 d->replayDelayedPress();
1510
1511 // Now send the release
1512 if (auto grabber = qmlobject_cast<QQuickItem *>(event->exclusiveGrabber(event->point(0)))) {
1513 // not copying or detaching anything, so make sure we return the original event unchanged
1514 const auto oldPosition = event->point(0).position();
1515 QMutableEventPoint::setPosition(event->point(0), grabber->mapFromScene(event->scenePosition()));
1517 QMutableEventPoint::setPosition(event->point(0), oldPosition);
1518 }
1519
1520 // And the event has been consumed
1521 d->stealMouse = false;
1522 d->pressed = false;
1523 return;
1524 }
1525
1526 d->handleReleaseEvent(event);
1527 event->accept();
1528 } else {
1530 }
1531}
1532
1534{
1535 Q_D(QQuickFlickable);
1536 bool unhandled = false;
1537 const auto &firstPoint = event->points().first();
1538 switch (firstPoint.state()) {
1540 if (d->interactive && !d->replayingPressEvent && d->wantsPointerEvent(event)) {
1541 if (!d->pressed)
1542 d->handlePressEvent(event);
1543 event->accept();
1544 } else {
1545 unhandled = true;
1546 }
1547 break;
1549 if (d->interactive && d->wantsPointerEvent(event)) {
1550 d->handleMoveEvent(event);
1551 event->accept();
1552 } else {
1553 unhandled = true;
1554 }
1555 break;
1557 if (d->interactive && d->wantsPointerEvent(event)) {
1558 if (d->delayedPressEvent) {
1559 d->replayDelayedPress();
1560
1561 // Now send the release
1562 auto &firstPoint = event->point(0);
1563 if (auto grabber = qmlobject_cast<QQuickItem *>(event->exclusiveGrabber(firstPoint))) {
1564 const auto localPos = grabber->mapFromScene(firstPoint.scenePosition());
1566 QCoreApplication::sendEvent(window(), localizedEvent.data());
1567 }
1568
1569 // And the event has been consumed
1570 d->stealMouse = false;
1571 d->pressed = false;
1572 return;
1573 }
1574
1575 d->handleReleaseEvent(event);
1576 event->accept();
1577 } else {
1578 unhandled = true;
1579 }
1580 break;
1583 break;
1584 }
1585 if (unhandled)
1587}
1588
1589#if QT_CONFIG(wheelevent)
1590void QQuickFlickable::wheelEvent(QWheelEvent *event)
1591{
1592 Q_D(QQuickFlickable);
1593 if (!d->interactive || !d->wantsPointerEvent(event)) {
1594 QQuickItem::wheelEvent(event);
1595 return;
1596 }
1597 qCDebug(lcWheel) << event->device() << event << event->source();
1598 event->setAccepted(false);
1599 qint64 currentTimestamp = d->computeCurrentTime(event);
1600 switch (event->phase()) {
1601 case Qt::ScrollBegin:
1602 d->scrollingPhase = true;
1603 d->accumulatedWheelPixelDelta = QVector2D();
1604 d->vData.velocity = 0;
1605 d->hData.velocity = 0;
1606 d->timer.start();
1607 d->maybeBeginDrag(currentTimestamp, event->position());
1608 d->lastPosTime = -1;
1609 break;
1610 case Qt::NoScrollPhase: // default phase with an ordinary wheel mouse
1611 case Qt::ScrollUpdate:
1612 if (d->scrollingPhase)
1613 d->pressed = true;
1614 break;
1615 case Qt::ScrollMomentum:
1616 d->pressed = false;
1617 d->scrollingPhase = false;
1618 d->draggingEnding();
1619 if (isMoving())
1620 event->accept();
1621 d->lastPosTime = -1;
1622 break;
1623 case Qt::ScrollEnd:
1624 d->pressed = false;
1625 d->scrollingPhase = false;
1626 d->draggingEnding();
1627 event->accept();
1629 d->lastPosTime = -1;
1630 d->stealMouse = false;
1631 if (!d->velocityTimeline.isActive() && !d->timeline.isActive())
1632 movementEnding(true, true);
1633 return;
1634 }
1635
1636 qreal elapsed = qreal(currentTimestamp - d->lastPosTime) / qreal(1000);
1637 if (elapsed <= 0) {
1638 d->lastPosTime = currentTimestamp;
1639 qCDebug(lcWheel) << "insufficient elapsed time: can't calculate velocity" << elapsed;
1640 return;
1641 }
1642
1643 if (event->source() == Qt::MouseEventNotSynthesized || event->pixelDelta().isNull() || event->phase() == Qt::NoScrollPhase) {
1644 // no pixel delta (physical mouse wheel, or "dumb" touchpad), so use angleDelta
1645 int xDelta = event->angleDelta().x();
1646 int yDelta = event->angleDelta().y();
1647
1648 if (d->wheelDeceleration > _q_MaximumWheelDeceleration) {
1649 const qreal wheelScroll = -qApp->styleHints()->wheelScrollLines() * 24;
1650 // If wheelDeceleration is very large, i.e. the user or the platform does not want to have any mouse wheel
1651 // acceleration behavior, we want to move a distance proportional to QStyleHints::wheelScrollLines()
1652 if (yflick() && yDelta != 0) {
1653 d->moveReason = QQuickFlickablePrivate::Mouse; // ItemViews will set fixupMode to Immediate in fixup() without this.
1654 d->vMoved = true;
1655 qreal scrollPixel = (-yDelta / 120.0 * wheelScroll);
1656 if (d->boundsBehavior == QQuickFlickable::StopAtBounds) {
1657 const qreal estContentPos = scrollPixel + d->vData.move.value();
1658 if (scrollPixel > 0) { // Forward direction (away from user)
1659 if (d->vData.move.value() >= minYExtent())
1660 d->vMoved = false;
1661 else if (estContentPos > minYExtent())
1662 scrollPixel = minYExtent() - d->vData.move.value();
1663 } else { // Backward direction (towards user)
1664 if (d->vData.move.value() <= maxYExtent())
1665 d->vMoved = false;
1666 else if (estContentPos < maxYExtent())
1667 scrollPixel = maxYExtent() - d->vData.move.value();
1668 }
1669 }
1670 if (d->vMoved) {
1671 d->resetTimeline(d->vData);
1673 d->timeline.moveBy(d->vData.move, scrollPixel, QEasingCurve(QEasingCurve::OutExpo), 3*d->fixupDuration/4);
1674 d->vData.fixingUp = true;
1675 d->timeline.callback(QQuickTimeLineCallback(&d->vData.move, QQuickFlickablePrivate::fixupY_callback, d));
1676 }
1677 event->accept();
1678 }
1679 if (xflick() && xDelta != 0) {
1680 d->moveReason = QQuickFlickablePrivate::Mouse; // ItemViews will set fixupMode to Immediate in fixup() without this.
1681 d->hMoved = true;
1682 qreal scrollPixel = (-xDelta / 120.0 * wheelScroll);
1683 if (d->boundsBehavior == QQuickFlickable::StopAtBounds) {
1684 const qreal estContentPos = scrollPixel + d->hData.move.value();
1685 if (scrollPixel > 0) { // Forward direction (away from user)
1686 if (d->hData.move.value() >= minXExtent())
1687 d->hMoved = false;
1688 else if (estContentPos > minXExtent())
1689 scrollPixel = minXExtent() - d->hData.move.value();
1690 } else { // Backward direction (towards user)
1691 if (d->hData.move.value() <= maxXExtent())
1692 d->hMoved = false;
1693 else if (estContentPos < maxXExtent())
1694 scrollPixel = maxXExtent() - d->hData.move.value();
1695 }
1696 }
1697 if (d->hMoved) {
1698 d->resetTimeline(d->hData);
1700 d->timeline.moveBy(d->hData.move, scrollPixel, QEasingCurve(QEasingCurve::OutExpo), 3*d->fixupDuration/4);
1701 d->hData.fixingUp = true;
1702 d->timeline.callback(QQuickTimeLineCallback(&d->hData.move, QQuickFlickablePrivate::fixupX_callback, d));
1703 }
1704 event->accept();
1705 }
1706 } else {
1707 // wheelDeceleration is set to some reasonable value: the user or the platform wants to have
1708 // the classic Qt Quick mouse wheel acceleration behavior.
1709 // For a single "clicky" wheel event (angleDelta +/- 120),
1710 // we want flick() to end up moving a distance proportional to QStyleHints::wheelScrollLines().
1711 // The decel algo from there is
1712 // qreal dist = v2 / (accel * 2.0);
1713 // i.e. initialWheelFlickDistance = (120 / dt)^2 / (deceleration * 2)
1714 // now solve for dt:
1715 // dt = 120 / sqrt(deceleration * 2 * initialWheelFlickDistance)
1716 if (!isMoving())
1717 elapsed = 120 / qSqrt(d->wheelDeceleration * 2 * d->initialWheelFlickDistance);
1718 if (yflick() && yDelta != 0) {
1719 qreal instVelocity = yDelta / elapsed;
1720 // if the direction has changed, start over with filtering, to allow instant movement in the opposite direction
1721 if ((instVelocity < 0 && d->vData.velocity > 0) || (instVelocity > 0 && d->vData.velocity < 0))
1722 d->vData.velocityBuffer.clear();
1723 d->vData.addVelocitySample(instVelocity, d->maxVelocity);
1724 d->vData.updateVelocity();
1725 if ((yDelta > 0 && contentY() > -minYExtent()) || (yDelta < 0 && contentY() < -maxYExtent())) {
1726 const bool newFlick = d->flickY(event->type(), d->vData.velocity);
1727 if (newFlick && (d->vData.atBeginning != (yDelta > 0) || d->vData.atEnd != (yDelta < 0))) {
1728 d->flickingStarted(false, true);
1729 d->vMoved = true;
1731 }
1732 event->accept();
1733 }
1734 }
1735 if (xflick() && xDelta != 0) {
1736 qreal instVelocity = xDelta / elapsed;
1737 // if the direction has changed, start over with filtering, to allow instant movement in the opposite direction
1738 if ((instVelocity < 0 && d->hData.velocity > 0) || (instVelocity > 0 && d->hData.velocity < 0))
1739 d->hData.velocityBuffer.clear();
1740 d->hData.addVelocitySample(instVelocity, d->maxVelocity);
1741 d->hData.updateVelocity();
1742 if ((xDelta > 0 && contentX() > -minXExtent()) || (xDelta < 0 && contentX() < -maxXExtent())) {
1743 const bool newFlick = d->flickX(event->type(), d->hData.velocity);
1744 if (newFlick && (d->hData.atBeginning != (xDelta > 0) || d->hData.atEnd != (xDelta < 0))) {
1745 d->flickingStarted(true, false);
1746 d->hMoved = true;
1748 }
1749 event->accept();
1750 }
1751 }
1752 }
1753 } else {
1754 // use pixelDelta (probably from a trackpad): this is where we want to be on most platforms eventually
1755 int xDelta = event->pixelDelta().x();
1756 int yDelta = event->pixelDelta().y();
1757
1758 QVector2D velocity(xDelta / elapsed, yDelta / elapsed);
1759 d->accumulatedWheelPixelDelta += QVector2D(event->pixelDelta());
1760 // Try to drag if 1) we already are dragging or flicking, or
1761 // 2) the flickable is free to flick both directions, or
1762 // 3) the movement so far has been mostly horizontal AND it's free to flick horizontally, or
1763 // 4) the movement so far has been mostly vertical AND it's free to flick vertically.
1764 // Otherwise, wait until the next event. Wheel events with pixel deltas tend to come frequently.
1765 if (isMoving() || isFlicking() || (yflick() && xflick())
1766 || (xflick() && qAbs(d->accumulatedWheelPixelDelta.x()) > qAbs(d->accumulatedWheelPixelDelta.y() * 2))
1767 || (yflick() && qAbs(d->accumulatedWheelPixelDelta.y()) > qAbs(d->accumulatedWheelPixelDelta.x() * 2))) {
1768 d->drag(currentTimestamp, event->type(), event->position(), d->accumulatedWheelPixelDelta,
1769 true, !d->scrollingPhase, true, velocity);
1770 event->accept();
1771 } else {
1772 qCDebug(lcWheel) << "not dragging: accumulated deltas" << d->accumulatedWheelPixelDelta <<
1773 "moving?" << isMoving() << "can flick horizontally?" << xflick() << "vertically?" << yflick();
1774 }
1775 }
1776 d->lastPosTime = currentTimestamp;
1777
1778 if (!event->isAccepted())
1779 QQuickItem::wheelEvent(event);
1780}
1781#endif
1782
1784{
1785 Q_Q(const QQuickFlickable);
1786 QQuickItem *item = i;
1787 while (item) {
1788 QQuickFlickable *flick = qobject_cast<QQuickFlickable*>(item);
1789 if (flick && flick->pressDelay() > 0 && flick->isInteractive()) {
1790 // Found the innermost flickable with press delay - is it me?
1791 return (flick == q);
1792 }
1793 item = item->parentItem();
1794 }
1795 return false;
1796}
1797
1799{
1800 Q_Q(QQuickFlickable);
1801 if (!q->window() || pressDelay <= 0)
1802 return;
1803
1804 // Only the innermost flickable should handle the delayed press; this allows
1805 // flickables up the parent chain to all see the events in their filter functions
1807 return;
1808
1812 qCDebug(lcReplay) << "begin press delay" << pressDelay << "ms with" << delayedPressEvent;
1813}
1814
1816{
1817 if (delayedPressEvent) {
1819 qCDebug(lcReplay) << "clear delayed press" << delayedPressEvent;
1820 delete delayedPressEvent;
1821 delayedPressEvent = nullptr;
1822 }
1823}
1824
1826{
1827 Q_Q(QQuickFlickable);
1828 if (delayedPressEvent) {
1829 // Losing the grab will clear the delayed press event; take control of it here
1831 delayedPressEvent = nullptr;
1833
1834 // If we have the grab, release before delivering the event
1835 if (QQuickWindow *window = q->window()) {
1836 auto da = deliveryAgentPrivate();
1837 da->allowChildEventFiltering = false; // don't allow re-filtering during replay
1838 replayingPressEvent = true;
1839 auto &firstPoint = event->point(0);
1840 // At first glance, it's weird for delayedPressEvent to already have a grabber;
1841 // but on press, filterMouseEvent() took the exclusive grab, and that's stored
1842 // in the device-specific EventPointData instance in QPointingDevicePrivate::activePoints,
1843 // not in the event itself. If this Flickable is still the grabber of that point on that device,
1844 // that's the reason; but now it doesn't need that grab anymore.
1845 if (event->exclusiveGrabber(firstPoint) == q)
1846 event->setExclusiveGrabber(firstPoint, nullptr);
1847
1848 qCDebug(lcReplay) << "replaying" << event.data();
1849 // Put scenePosition into position, for the sake of QQuickWindowPrivate::translateTouchEvent()
1850 // TODO remove this if we remove QQuickWindowPrivate::translateTouchEvent()
1851 QMutableEventPoint::setPosition(firstPoint, firstPoint.scenePosition());
1852 // Send it through like a fresh press event, and let QQuickWindow
1853 // (more specifically, QQuickWindowPrivate::deliverPressOrReleaseEvent)
1854 // find the item or handler that should receive it, as usual.
1856 qCDebug(lcReplay) << "replay done";
1857
1858 // We're done with replay, go back to normal delivery behavior
1859 replayingPressEvent = false;
1860 da->allowChildEventFiltering = true;
1861 }
1862 }
1863}
1864
1865//XXX pixelAligned ignores the global position of the Flickable, i.e. assumes Flickable itself is pixel aligned.
1866
1876{
1877 Q_Q(QQuickFlickable);
1878 qreal effectiveX = pixelAligned ? -std::round(-x) : x;
1879
1880 const qreal maxX = q->maxXExtent();
1881 const qreal minX = q->minXExtent();
1882
1884 effectiveX = qBound(maxX, effectiveX, minX);
1885
1886 contentItem->setX(effectiveX);
1887 if (contentItem->x() != effectiveX)
1888 return; // reentered
1889
1890 qreal overshoot = 0.0;
1891 if (x <= maxX)
1892 overshoot = maxX - x;
1893 else if (x >= minX)
1894 overshoot = minX - x;
1895
1896 if (overshoot != hData.overshoot) {
1897 hData.overshoot = overshoot;
1898 emit q->horizontalOvershootChanged();
1899 }
1900}
1901
1911{
1912 Q_Q(QQuickFlickable);
1913 qreal effectiveY = pixelAligned ? -std::round(-y) : y;
1914
1915 const qreal maxY = q->maxYExtent();
1916 const qreal minY = q->minYExtent();
1917
1919 effectiveY = qBound(maxY, effectiveY, minY);
1920
1921 contentItem->setY(effectiveY);
1922 if (contentItem->y() != effectiveY)
1923 return; // reentered
1924
1925 qreal overshoot = 0.0;
1926 if (y <= maxY)
1927 overshoot = maxY - y;
1928 else if (y >= minY)
1929 overshoot = minY - y;
1930
1931 if (overshoot != vData.overshoot) {
1932 vData.overshoot = overshoot;
1933 emit q->verticalOvershootChanged();
1934 }
1935}
1936
1938{
1939 Q_D(QQuickFlickable);
1940 if (event->timerId() == d->delayedPressTimer.timerId()) {
1941 d->delayedPressTimer.stop();
1942 if (d->delayedPressEvent) {
1943 d->replayDelayedPress();
1944 }
1945 }
1946}
1947
1949{
1950 Q_D(const QQuickFlickable);
1951 return d->vData.startMargin;
1952}
1953
1955{
1956 Q_D(const QQuickFlickable);
1957 return d->hData.startMargin;
1958}
1959
1960/* returns -ve */
1962{
1963 Q_D(const QQuickFlickable);
1964 return qMin<qreal>(minXExtent(), width() - vWidth() - d->hData.endMargin);
1965}
1966/* returns -ve */
1968{
1969 Q_D(const QQuickFlickable);
1970 return qMin<qreal>(minYExtent(), height() - vHeight() - d->vData.endMargin);
1971}
1972
1974{
1975 Q_D(QQuickFlickable);
1977 if (!d->hData.explicitValue && d->hData.startMargin != 0.)
1979 if (!d->vData.explicitValue && d->vData.startMargin != 0.)
1981 if (lcWheel().isDebugEnabled() || lcVel().isDebugEnabled()) {
1982 d->timeline.setObjectName(QLatin1String("timeline for Flickable ") + objectName());
1983 d->velocityTimeline.setObjectName(QLatin1String("velocity timeline for Flickable ") + objectName());
1984 }
1985}
1986
1987void QQuickFlickable::viewportMoved(Qt::Orientations orient)
1988{
1989 Q_D(QQuickFlickable);
1990 if (orient & Qt::Vertical)
1991 d->viewportAxisMoved(d->vData, minYExtent(), maxYExtent(), d->fixupY_callback);
1992 if (orient & Qt::Horizontal)
1993 d->viewportAxisMoved(d->hData, minXExtent(), maxXExtent(), d->fixupX_callback);
1994 d->updateBeginningEnd();
1995}
1996
1999{
2000 if (!scrollingPhase && (pressed || calcVelocity)) {
2001 int elapsed = data.velocityTime.restart();
2002 if (elapsed > 0) {
2003 qreal velocity = (data.lastPos - data.move.value()) * 1000 / elapsed;
2004 if (qAbs(velocity) > 0) {
2005 velocityTimeline.reset(data.smoothVelocity);
2006 velocityTimeline.set(data.smoothVelocity, velocity);
2007 qCDebug(lcVel) << "touchpad scroll phase: velocity" << velocity;
2008 }
2009 }
2010 } else {
2011 if (timeline.time() > data.vTime) {
2012 velocityTimeline.reset(data.smoothVelocity);
2013 int dt = timeline.time() - data.vTime;
2014 if (dt > 2) {
2015 qreal velocity = (data.lastPos - data.move.value()) * 1000 / dt;
2016 if (!qFuzzyCompare(data.smoothVelocity.value(), velocity))
2017 qCDebug(lcVel) << "velocity" << data.smoothVelocity.value() << "->" << velocity
2018 << "computed as (" << data.lastPos << "-" << data.move.value() << ") * 1000 / ("
2019 << timeline.time() << "-" << data.vTime << ")";
2020 data.smoothVelocity.setValue(velocity);
2021 }
2022 }
2023 }
2024
2025 if (!data.inOvershoot && !data.fixingUp && data.flicking
2026 && (data.move.value() > minExtent || data.move.value() < maxExtent)
2027 && qAbs(data.smoothVelocity.value()) > 10) {
2028 // Increase deceleration if we've passed a bound
2029 qreal overBound = data.move.value() > minExtent
2030 ? data.move.value() - minExtent
2031 : maxExtent - data.move.value();
2032 data.inOvershoot = true;
2033 qreal maxDistance = overShootDistance(qAbs(data.smoothVelocity.value())) - overBound;
2035 if (maxDistance > 0)
2036 timeline.accel(data.move, -data.smoothVelocity.value(), deceleration*QML_FLICK_OVERSHOOTFRICTION, maxDistance);
2037 timeline.callback(QQuickTimeLineCallback(&data.move, fixupCallback, this));
2038 }
2039
2040 data.lastPos = data.move.value();
2041 data.vTime = timeline.time();
2042}
2043
2044void QQuickFlickable::geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry)
2045{
2046 Q_D(QQuickFlickable);
2047 QQuickItem::geometryChange(newGeometry, oldGeometry);
2048
2049 bool changed = false;
2050 if (newGeometry.width() != oldGeometry.width()) {
2051 changed = true; // we must update visualArea.widthRatio
2052 if (d->hData.viewSize < 0)
2053 d->contentItem->setWidth(width() - d->hData.startMargin - d->hData.endMargin);
2054 // Make sure that we're entirely in view.
2055 if (!d->pressed && !d->hData.moving && !d->vData.moving) {
2057 d->fixupX();
2058 }
2059 }
2060 if (newGeometry.height() != oldGeometry.height()) {
2061 changed = true; // we must update visualArea.heightRatio
2062 if (d->vData.viewSize < 0)
2063 d->contentItem->setHeight(height() - d->vData.startMargin - d->vData.endMargin);
2064 // Make sure that we're entirely in view.
2065 if (!d->pressed && !d->hData.moving && !d->vData.moving) {
2067 d->fixupY();
2068 }
2069 }
2070
2071 if (changed)
2072 d->updateBeginningEnd();
2073}
2074
2084void QQuickFlickable::flick(qreal xVelocity, qreal yVelocity)
2085{
2086 Q_D(QQuickFlickable);
2087 d->hData.reset();
2088 d->vData.reset();
2089 d->hData.velocity = xVelocity;
2090 d->vData.velocity = yVelocity;
2091 d->hData.vTime = d->vData.vTime = d->timeline.time();
2092
2093 const bool flickedX = xflick() && !qFuzzyIsNull(xVelocity) && d->flickX(QEvent::TouchUpdate, xVelocity);
2094 const bool flickedY = yflick() && !qFuzzyIsNull(yVelocity) && d->flickY(QEvent::TouchUpdate, yVelocity);
2095
2096 if (flickedX)
2097 d->hMoved = true;
2098 if (flickedY)
2099 d->vMoved = true;
2101 d->flickingStarted(flickedX, flickedY);
2102}
2103
2104void QQuickFlickablePrivate::flickingStarted(bool flickingH, bool flickingV)
2105{
2106 Q_Q(QQuickFlickable);
2107 if (!flickingH && !flickingV)
2108 return;
2109
2110 bool wasFlicking = hData.flicking || vData.flicking;
2111 if (flickingH && !hData.flicking) {
2112 hData.flicking = true;
2113 emit q->flickingHorizontallyChanged();
2114 }
2115 if (flickingV && !vData.flicking) {
2116 vData.flicking = true;
2117 emit q->flickingVerticallyChanged();
2118 }
2119 if (!wasFlicking && (hData.flicking || vData.flicking)) {
2120 emit q->flickingChanged();
2121 emit q->flickStarted();
2122 }
2123}
2124
2132{
2133 Q_D(QQuickFlickable);
2134 d->resetTimeline(d->hData);
2135 d->resetTimeline(d->vData);
2137}
2138
2140{
2141 if (!prop || !prop->data)
2142 return;
2143
2145 i->setParentItem(static_cast<QQuickFlickablePrivate*>(prop->data)->contentItem);
2146 } else if (QQuickPointerHandler *pointerHandler = qmlobject_cast<QQuickPointerHandler *>(o)) {
2147 static_cast<QQuickFlickablePrivate*>(prop->data)->addPointerHandler(pointerHandler);
2148 } else {
2149 o->setParent(prop->object); // XXX todo - do we want this?
2150 }
2151}
2152
2154{
2155 // XXX todo
2156 return 0;
2157}
2158
2160{
2161 // XXX todo
2162 return nullptr;
2163}
2164
2166{
2167 // XXX todo
2168}
2169
2171{
2172 Q_D(QQuickFlickable);
2177}
2178
2180{
2181 Q_D(QQuickFlickable);
2182 return QQuickItemPrivate::get(d->contentItem)->children();
2183}
2184
2211QQuickFlickable::BoundsBehavior QQuickFlickable::boundsBehavior() const
2212{
2213 Q_D(const QQuickFlickable);
2214 return d->boundsBehavior;
2215}
2216
2218{
2219 Q_D(QQuickFlickable);
2220 if (b == d->boundsBehavior)
2221 return;
2222 d->boundsBehavior = b;
2224}
2225
2267{
2268 Q_D(const QQuickFlickable);
2269 return d->rebound;
2270}
2271
2273{
2274 Q_D(QQuickFlickable);
2275 if (transition) {
2276 if (!d->hData.transitionToBounds)
2277 d->hData.transitionToBounds = new QQuickFlickableReboundTransition(this, QLatin1String("x"));
2278 if (!d->vData.transitionToBounds)
2279 d->vData.transitionToBounds = new QQuickFlickableReboundTransition(this, QLatin1String("y"));
2280 }
2281 if (d->rebound != transition) {
2282 d->rebound = transition;
2284 }
2285}
2286
2312{
2313 Q_D(const QQuickFlickable);
2314 return d->hData.viewSize;
2315}
2316
2318{
2319 Q_D(QQuickFlickable);
2320 if (d->hData.viewSize == w)
2321 return;
2322 d->hData.viewSize = w;
2323 if (w < 0)
2324 d->contentItem->setWidth(width() - d->hData.startMargin - d->hData.endMargin);
2325 else
2326 d->contentItem->setWidth(w);
2327 d->hData.markExtentsDirty();
2328 // Make sure that we're entirely in view.
2329 if (!d->pressed && !d->hData.moving && !d->vData.moving) {
2331 d->fixupX();
2332 } else if (!d->pressed && d->hData.fixingUp) {
2334 d->fixupX();
2335 }
2337 d->updateBeginningEnd();
2338}
2339
2341{
2342 Q_D(const QQuickFlickable);
2343 return d->vData.viewSize;
2344}
2345
2347{
2348 Q_D(QQuickFlickable);
2349 if (d->vData.viewSize == h)
2350 return;
2351 d->vData.viewSize = h;
2352 if (h < 0)
2353 d->contentItem->setHeight(height() - d->vData.startMargin - d->vData.endMargin);
2354 else
2355 d->contentItem->setHeight(h);
2356 d->vData.markExtentsDirty();
2357 // Make sure that we're entirely in view.
2358 if (!d->pressed && !d->hData.moving && !d->vData.moving) {
2360 d->fixupY();
2361 } else if (!d->pressed && d->vData.fixingUp) {
2363 d->fixupY();
2364 }
2366 d->updateBeginningEnd();
2367}
2368
2381{
2382 Q_D(const QQuickFlickable);
2383 return d->vData.startMargin;
2384}
2385
2387{
2388 Q_D(QQuickFlickable);
2389 if (d->vData.startMargin == m)
2390 return;
2391 d->vData.startMargin = m;
2392 d->vData.markExtentsDirty();
2393 if (!d->pressed && !d->hData.moving && !d->vData.moving) {
2395 d->fixupY();
2396 }
2398 d->updateBeginningEnd();
2399}
2400
2402{
2403 Q_D(const QQuickFlickable);
2404 return d->vData.endMargin;
2405}
2406
2408{
2409 Q_D(QQuickFlickable);
2410 if (d->vData.endMargin == m)
2411 return;
2412 d->vData.endMargin = m;
2413 d->vData.markExtentsDirty();
2414 if (!d->pressed && !d->hData.moving && !d->vData.moving) {
2416 d->fixupY();
2417 }
2419 d->updateBeginningEnd();
2420}
2421
2423{
2424 Q_D(const QQuickFlickable);
2425 return d->hData.startMargin;
2426}
2427
2429{
2430 Q_D(QQuickFlickable);
2431 if (d->hData.startMargin == m)
2432 return;
2433 d->hData.startMargin = m;
2434 d->hData.markExtentsDirty();
2435 if (!d->pressed && !d->hData.moving && !d->vData.moving) {
2437 d->fixupX();
2438 }
2440 d->updateBeginningEnd();
2441}
2442
2444{
2445 Q_D(const QQuickFlickable);
2446 return d->hData.endMargin;
2447}
2448
2450{
2451 Q_D(QQuickFlickable);
2452 if (d->hData.endMargin == m)
2453 return;
2454 d->hData.endMargin = m;
2455 d->hData.markExtentsDirty();
2456 if (!d->pressed && !d->hData.moving && !d->vData.moving) {
2458 d->fixupX();
2459 }
2461 d->updateBeginningEnd();
2462}
2463
2479{
2480 Q_D(const QQuickFlickable);
2481 return -minYExtent() + d->vData.startMargin;
2482}
2483
2485{
2486 Q_D(const QQuickFlickable);
2487 return -minXExtent() + d->hData.startMargin;
2488}
2489
2490
2504{
2505 Q_D(QQuickFlickable);
2506 const qreal oldHSize = d->hData.viewSize;
2507 const qreal oldVSize = d->vData.viewSize;
2508 const bool needToUpdateWidth = w != oldHSize;
2509 const bool needToUpdateHeight = h != oldVSize;
2510 d->hData.viewSize = w;
2511 d->vData.viewSize = h;
2512 d->contentItem->setSize(QSizeF(w, h));
2513 if (needToUpdateWidth)
2515 if (needToUpdateHeight)
2517
2518 if (center.x() != 0) {
2519 qreal pos = center.x() * w / oldHSize;
2520 setContentX(contentX() + pos - center.x());
2521 }
2522 if (center.y() != 0) {
2523 qreal pos = center.y() * h / oldVSize;
2524 setContentY(contentY() + pos - center.y());
2525 }
2526 d->updateBeginningEnd();
2527}
2528
2538{
2539 Q_D(QQuickFlickable);
2540 d->fixupX();
2541 d->fixupY();
2542}
2543
2545{
2546 Q_D(const QQuickFlickable);
2547 if (d->hData.viewSize < 0)
2548 return width();
2549 else
2550 return d->hData.viewSize;
2551}
2552
2554{
2555 Q_D(const QQuickFlickable);
2556 if (d->vData.viewSize < 0)
2557 return height();
2558 else
2559 return d->vData.viewSize;
2560}
2561
2570{
2571 Q_D(const QQuickFlickable);
2572 const int contentWidthWithMargins = d->contentItem->width() + d->hData.startMargin + d->hData.endMargin;
2573 if ((d->flickableDirection & QQuickFlickable::AutoFlickIfNeeded) && (contentWidthWithMargins > width()))
2574 return true;
2575 if (d->flickableDirection == QQuickFlickable::AutoFlickDirection)
2576 return std::floor(qAbs(contentWidthWithMargins - width()));
2577 return d->flickableDirection & QQuickFlickable::HorizontalFlick;
2578}
2579
2588{
2589 Q_D(const QQuickFlickable);
2590 const int contentHeightWithMargins = d->contentItem->height() + d->vData.startMargin + d->vData.endMargin;
2591 if ((d->flickableDirection & QQuickFlickable::AutoFlickIfNeeded) && (contentHeightWithMargins > height()))
2592 return true;
2593 if (d->flickableDirection == QQuickFlickable::AutoFlickDirection)
2594 return std::floor(qAbs(contentHeightWithMargins - height()));
2595 return d->flickableDirection & QQuickFlickable::VerticalFlick;
2596}
2597
2599{
2600 Q_D(QQuickFlickable);
2601 // if our mouse grab has been removed (probably by another Flickable),
2602 // fix our state
2603 if (!d->replayingPressEvent)
2604 d->cancelInteraction();
2605}
2606
2608{
2609 Q_Q(QQuickFlickable);
2610 if (pressed) {
2612 pressed = false;
2614 stealMouse = false;
2615 q->setKeepMouseGrab(false);
2616 fixupX();
2617 fixupY();
2618 if (!isViewMoving())
2619 q->movementEnding();
2620 }
2621}
2622
2624{
2625 Q_Q(const QQuickFlickable);
2626 qCDebug(lcHandlerParent) << "reparenting handler" << h << "to contentItem of" << q;
2627 h->setParent(contentItem);
2629}
2630
2640{
2641 const bool isTouch = QQuickDeliveryAgentPrivate::isTouchEvent(event);
2644 return false; // don't filter hover events or wheel events, for example
2645 Q_ASSERT_X(receiver != this, "", "Flickable received a filter event for itself");
2646 Q_D(QQuickFlickable);
2647 // If a touch event contains a new press point, don't steal right away: watch the movements for a while
2648 if (isTouch && static_cast<QTouchEvent *>(event)->touchPointStates().testFlag(QEventPoint::State::Pressed))
2649 d->stealMouse = false;
2650 // If multiple touchpoints are within bounds, don't grab: it's probably meant for multi-touch interaction in some child
2651 if (event->pointCount() > 1) {
2652 qCDebug(lcFilter) << objectName() << "ignoring multi-touch" << event << "for" << receiver;
2653 d->stealMouse = false;
2654 } else {
2655 qCDebug(lcFilter) << objectName() << "filtering" << event << "for" << receiver;
2656 }
2657
2658 const auto &firstPoint = event->points().first();
2659
2660 if (event->pointCount() == 1 && event->exclusiveGrabber(firstPoint) == this) {
2661 // We have an exclusive grab (since we're e.g dragging), but at the same time, we have
2662 // a child with a passive grab (which is why this filter is being called). And because
2663 // of that, we end up getting the same pointer events twice; First in our own event
2664 // handlers (because of the grab), then once more in here, since we filter the child.
2665 // To avoid processing the event twice (e.g avoid calling handleReleaseEvent once more
2666 // from below), we mark the event as filtered, and simply return.
2667 event->setAccepted(true);
2668 return true;
2669 }
2670
2671 QPointF localPos = mapFromScene(firstPoint.scenePosition());
2672 bool receiverDisabled = receiver && !receiver->isEnabled();
2673 bool stealThisEvent = d->stealMouse;
2674 bool receiverKeepsGrab = receiver && (receiver->keepMouseGrab() || receiver->keepTouchGrab());
2675 bool receiverRelinquishGrab = false;
2676
2677 // Special case for MouseArea, try to guess what it does with the event
2678 if (auto *mouseArea = qmlobject_cast<QQuickMouseArea *>(receiver)) {
2679 bool preventStealing = mouseArea->preventStealing();
2680#if QT_CONFIG(quick_draganddrop)
2681 if (mouseArea->drag() && mouseArea->drag()->target())
2682 preventStealing = true;
2683#endif
2684 if (!preventStealing && receiverKeepsGrab) {
2685 receiverRelinquishGrab = !receiverDisabled
2687 && firstPoint.state() == QEventPoint::State::Pressed
2688 && (receiver->acceptedMouseButtons() & static_cast<QMouseEvent *>(event)->button()));
2689 if (receiverRelinquishGrab)
2690 receiverKeepsGrab = false;
2691 }
2692 }
2693
2694 if ((stealThisEvent || contains(localPos)) && (!receiver || !receiverKeepsGrab || receiverDisabled)) {
2696 localizedEvent->setAccepted(false);
2697 switch (firstPoint.state()) {
2699 d->handleMoveEvent(localizedEvent.data());
2700 break;
2702 d->handlePressEvent(localizedEvent.data());
2703 d->captureDelayedPress(receiver, event);
2704 // never grab the pointing device on press during filtering: do it later, during a move
2705 d->stealMouse = false;
2706 stealThisEvent = false;
2707 break;
2709 d->handleReleaseEvent(localizedEvent.data());
2710 stealThisEvent = d->stealMouse;
2711 break;
2714 break;
2715 }
2716 if ((receiver && stealThisEvent && !receiverKeepsGrab && receiver != this) || receiverDisabled) {
2717 d->clearDelayedPress();
2718 event->setExclusiveGrabber(firstPoint, this);
2719 } else if (d->delayedPressEvent) {
2720 event->setExclusiveGrabber(firstPoint, this);
2721 }
2722
2723 const bool filtered = !receiverRelinquishGrab && (stealThisEvent || d->delayedPressEvent || receiverDisabled);
2724 if (filtered) {
2725 event->setAccepted(true);
2726 }
2727 return filtered;
2728 } else if (d->lastPosTime != -1) {
2729 d->lastPosTime = -1;
2731 }
2732 if (firstPoint.state() == QEventPoint::State::Released || (receiverKeepsGrab && !receiverDisabled)) {
2733 // mouse released, or another item has claimed the grab
2734 d->lastPosTime = -1;
2735 d->clearDelayedPress();
2736 d->stealMouse = false;
2737 d->pressed = false;
2738 }
2739 return false;
2740}
2741
2747{
2748 Q_D(QQuickFlickable);
2749 QPointerEvent *pointerEvent = e->isPointerEvent() ? static_cast<QPointerEvent *>(e) : nullptr;
2750
2751 auto wantsPointerEvent_helper = [this, d, i, pointerEvent]() {
2752 Q_ASSERT(pointerEvent);
2754 const bool wants = d->wantsPointerEvent(pointerEvent);
2755 // re-localize event back to \a i before returning
2757 return wants;
2758 };
2759
2760 if (!isVisible() || !isEnabled() || !isInteractive() ||
2761 (pointerEvent && !wantsPointerEvent_helper())) {
2762 d->cancelInteraction();
2764 }
2765
2766 if (e->type() == QEvent::UngrabMouse) {
2767 Q_ASSERT(e->isSinglePointEvent());
2768 auto spe = static_cast<QSinglePointEvent *>(e);
2769 const QObject *grabber = spe->exclusiveGrabber(spe->points().first());
2770 qCDebug(lcFilter) << "filtering UngrabMouse" << spe->points().first() << "for" << i << "grabber is" << grabber;
2771 if (grabber != this)
2772 mouseUngrabEvent(); // A child has been ungrabbed
2773 } else if (pointerEvent) {
2774 return filterPointerEvent(i, pointerEvent);
2775 }
2776
2778}
2779
2787{
2788 Q_D(const QQuickFlickable);
2789 return d->maxVelocity;
2790}
2791
2793{
2794 Q_D(QQuickFlickable);
2795 if (v == d->maxVelocity)
2796 return;
2797 d->maxVelocity = v;
2799}
2800
2811{
2812 Q_D(const QQuickFlickable);
2813 return d->deceleration;
2814}
2815
2817{
2818 Q_D(QQuickFlickable);
2819 if (deceleration == d->deceleration)
2820 return;
2821 d->deceleration = qMax(0.001, deceleration);
2823}
2824
2826{
2827 Q_D(const QQuickFlickable);
2828 return d->hData.flicking || d->vData.flicking;
2829}
2830
2840{
2841 Q_D(const QQuickFlickable);
2842 return d->hData.flicking;
2843}
2844
2846{
2847 Q_D(const QQuickFlickable);
2848 return d->vData.flicking;
2849}
2850
2860{
2861 Q_D(const QQuickFlickable);
2862 return d->hData.dragging || d->vData.dragging;
2863}
2864
2866{
2867 Q_D(const QQuickFlickable);
2868 return d->hData.dragging;
2869}
2870
2872{
2873 Q_D(const QQuickFlickable);
2874 return d->vData.dragging;
2875}
2876
2878{
2879 Q_Q(QQuickFlickable);
2880 bool wasDragging = hData.dragging || vData.dragging;
2881 if (hMoved && !hData.dragging) {
2882 hData.dragging = true;
2883 emit q->draggingHorizontallyChanged();
2884 }
2885 if (vMoved && !vData.dragging) {
2886 vData.dragging = true;
2887 emit q->draggingVerticallyChanged();
2888 }
2889 if (!wasDragging && (hData.dragging || vData.dragging)) {
2890 emit q->draggingChanged();
2891 emit q->dragStarted();
2892 }
2893}
2894
2896{
2897 Q_Q(QQuickFlickable);
2898 const bool wasDragging = hData.dragging || vData.dragging;
2899 if (hData.dragging) {
2900 hData.dragging = false;
2901 emit q->draggingHorizontallyChanged();
2902 }
2903 if (vData.dragging) {
2904 vData.dragging = false;
2905 emit q->draggingVerticallyChanged();
2906 }
2907 if (wasDragging) {
2908 if (!hData.dragging && !vData.dragging) {
2909 emit q->draggingChanged();
2910 emit q->dragEnded();
2911 }
2912 hData.inRebound = false;
2913 vData.inRebound = false;
2914 }
2915}
2916
2918{
2919 if (timeline.isActive()
2922 return true;
2923 }
2924 return false;
2925}
2926
2946{
2947 Q_D(const QQuickFlickable);
2948 return d->pressDelay;
2949}
2950
2952{
2953 Q_D(QQuickFlickable);
2954 if (d->pressDelay == delay)
2955 return;
2956 d->pressDelay = delay;
2958}
2959
2971{
2972 Q_D(const QQuickFlickable);
2973 return d->hData.moving || d->vData.moving;
2974}
2975
2977{
2978 Q_D(const QQuickFlickable);
2979 return d->hData.moving;
2980}
2981
2983{
2984 Q_D(const QQuickFlickable);
2985 return d->vData.moving;
2986}
2987
2989{
2990 Q_D(QQuickFlickable);
2991 if ( (d->hData.transitionToBounds && d->hData.transitionToBounds->isActive())
2992 || (d->vData.transitionToBounds && d->vData.transitionToBounds->isActive()) ) {
2993 return;
2994 }
2995 // With subclasses such as GridView, velocityTimeline.completed is emitted repeatedly:
2996 // for example setting currentIndex results in a visual "flick" which the user
2997 // didn't initiate directly. We don't want to end movement repeatedly, and in
2998 // that case movementEnding will happen after the sequence of movements ends.
2999 if (d->vData.flicking)
3001 d->updateBeginningEnd();
3002}
3003
3005{
3006 Q_D(QQuickFlickable);
3007 if ( (d->hData.transitionToBounds && d->hData.transitionToBounds->isActive())
3008 || (d->vData.transitionToBounds && d->vData.transitionToBounds->isActive()) ) {
3009 return;
3010 }
3012 d->updateBeginningEnd();
3013}
3014
3016{
3017 Q_D(QQuickFlickable);
3018 bool wasMoving = d->hData.moving || d->vData.moving;
3019 if (d->hMoved && !d->hData.moving) {
3020 d->hData.moving = true;
3022 }
3023 if (d->vMoved && !d->vData.moving) {
3024 d->vData.moving = true;
3026 }
3027
3028 if (!wasMoving && (d->hData.moving || d->vData.moving)) {
3031#if QT_CONFIG(accessibility)
3032 if (QAccessible::isActive()) {
3033 QAccessibleEvent ev(this, QAccessible::ScrollingStart);
3034 QAccessible::updateAccessibility(&ev);
3035 }
3036#endif
3037 }
3038}
3039
3041{
3042 movementEnding(true, true);
3043}
3044
3045void QQuickFlickable::movementEnding(bool hMovementEnding, bool vMovementEnding)
3046{
3047 Q_D(QQuickFlickable);
3048
3049 // emit flicking signals
3050 const bool wasFlicking = d->hData.flicking || d->vData.flicking;
3051 if (hMovementEnding && d->hData.flicking) {
3052 d->hData.flicking = false;
3054 }
3055 if (vMovementEnding && d->vData.flicking) {
3056 d->vData.flicking = false;
3058 }
3059 if (wasFlicking && (!d->hData.flicking || !d->vData.flicking)) {
3061 emit flickEnded();
3062 } else if (d->hData.flickingWhenDragBegan || d->vData.flickingWhenDragBegan) {
3063 d->hData.flickingWhenDragBegan = !hMovementEnding;
3064 d->vData.flickingWhenDragBegan = !vMovementEnding;
3065 emit flickEnded();
3066 }
3067
3068 // emit moving signals
3069 bool wasMoving = isMoving();
3070 if (hMovementEnding && d->hData.moving
3071 && (!d->pressed && !d->stealMouse)) {
3072 d->hData.moving = false;
3073 d->hMoved = false;
3075 }
3076 if (vMovementEnding && d->vData.moving
3077 && (!d->pressed && !d->stealMouse)) {
3078 d->vData.moving = false;
3079 d->vMoved = false;
3081 }
3082 if (wasMoving && !isMoving()) {
3085#if QT_CONFIG(accessibility)
3086 if (QAccessible::isActive()) {
3087 QAccessibleEvent ev(this, QAccessible::ScrollingEnd);
3088 QAccessible::updateAccessibility(&ev);
3089 }
3090#endif
3091 }
3092
3093 if (hMovementEnding) {
3094 d->hData.fixingUp = false;
3095 d->hData.smoothVelocity.setValue(0);
3096 d->hData.previousDragDelta = 0.0;
3097 }
3098 if (vMovementEnding) {
3099 d->vData.fixingUp = false;
3100 d->vData.smoothVelocity.setValue(0);
3101 d->vData.previousDragDelta = 0.0;
3102 }
3103}
3104
3106{
3107 Q_Q(QQuickFlickable);
3108 emit q->horizontalVelocityChanged();
3109 emit q->verticalVelocityChanged();
3110}
3111
3128{
3129 Q_D(const QQuickFlickable);
3130 return d->hData.overshoot;
3131}
3132
3149{
3150 Q_D(const QQuickFlickable);
3151 return d->vData.overshoot;
3152}
3153
3201{
3202 Q_D(const QQuickFlickable);
3203 return d->boundsMovement;
3204}
3205
3207{
3208 Q_D(QQuickFlickable);
3209 if (d->boundsMovement == movement)
3210 return;
3211
3212 d->boundsMovement = movement;
3213 emit boundsMovementChanged();
3214}
3215
3217
3218#include "moc_qquickflickable_p_p.cpp"
3219
3220#include "moc_qquickflickable_p.cpp"
void start(int msec, QObject *obj)
\obsolete Use chrono overload instead.
void stop()
Stops the timer.
static bool sendEvent(QObject *receiver, QEvent *event)
Sends event event directly to receiver receiver, using the notify() function.
\inmodule QtCore
qint64 elapsed() const noexcept
Returns the number of milliseconds since this QElapsedTimer was last started.
void start() noexcept
Starts this timer.
bool isValid() const noexcept
Returns false if the timer has never been started or invalidated by a call to invalidate().
\inmodule QtCore
Definition qcoreevent.h:45
Type
This enum type defines the valid event types in Qt.
Definition qcoreevent.h:51
@ UngrabMouse
Definition qcoreevent.h:234
@ MouseMove
Definition qcoreevent.h:63
@ TouchUpdate
Definition qcoreevent.h:242
QGraphicsItem * parentItem() const
Returns a pointer to this item's parent item.
static QPlatformIntegration * platformIntegration()
\inmodule QtGui
Definition qevent.h:49
void clear()
Definition qlist.h:417
\inmodule QtGui
Definition qevent.h:195
QObject * parent
Definition qobject.h:61
\inmodule QtCore
Definition qobject.h:90
QString objectName
the name of this object
Definition qobject.h:94
void clear()
void remove(int idx, int count=1)
void append(const T &v)
int count() const
The QPlatformIntegration class is the entry for WindowSystem specific functionality.
virtual QVariant styleHint(StyleHint hint) const
\inmodule QtCore\reentrant
Definition qpoint.h:214
constexpr qreal x() const noexcept
Returns the x coordinate of this point.
Definition qpoint.h:333
constexpr qreal y() const noexcept
Returns the y coordinate of this point.
Definition qpoint.h:338
A base class for pointer events.
Definition qevent.h:73
virtual void setAccepted(bool accepted) override
\reimp
Definition qevent.cpp:315
The QQmlListProperty class allows applications to expose list-like properties of QObject-derived clas...
Definition qqmllist.h:24
QObject * object
Definition qqmllist.h:81
static bool isTabletEvent(const QPointerEvent *ev)
static bool isTouchEvent(const QPointerEvent *ev)
static bool isMouseEvent(const QPointerEvent *ev)
static QPointerEvent * clonePointerEvent(QPointerEvent *event, std::optional< QPointF > transformedLocalPos=std::nullopt)
static bool dragOverThreshold(qreal d, Qt::Axis axis, QMouseEvent *event, int startDragThreshold=-1)
static void localizePointerEvent(QPointerEvent *ev, const QQuickItem *dest)
bool contains(const QPointF &point) const override
void resetTimeline(AxisData &data)
static void fixupX_callback(void *)
virtual bool flick(AxisData &data, qreal minExtent, qreal maxExtent, qreal vSize, QQuickTimeLineCallback::Callback fixupCallback, QEvent::Type eventType, qreal velocity)
static qsizetype data_count(QQmlListProperty< QObject > *)
void flickingStarted(bool flickingH, bool flickingV)
void captureDelayedPress(QQuickItem *item, QPointerEvent *event)
qint64 computeCurrentTime(QInputEvent *event) const
qreal overShootDistance(qreal velocity) const
bool flickY(QEvent::Type eventType, qreal velocity)
void handleMoveEvent(QPointerEvent *)
bool isInnermostPressDelay(QQuickItem *item) const
QQuickFlickable::BoundsMovement boundsMovement
void adjustContentPos(AxisData &data, qreal toPos)
void drag(qint64 currentTimestamp, QEvent::Type eventType, const QPointF &localPos, const QVector2D &deltas, bool overThreshold, bool momentum, bool velocitySensitiveOverBounds, const QVector2D &velocity)
void addPointerHandler(QQuickPointerHandler *h) override
virtual void fixup(AxisData &data, qreal minExtent, qreal maxExtent)
static QQuickFlickablePrivate * get(QQuickFlickable *o)
QQuickFlickable::FlickableDirection flickableDirection
static void fixupY_callback(void *)
static void data_clear(QQmlListProperty< QObject > *)
void itemGeometryChanged(QQuickItem *, QQuickGeometryChange, const QRectF &) override
static void data_append(QQmlListProperty< QObject > *, QObject *)
QPointerEvent * delayedPressEvent
QQuickFlickableVisibleArea * visibleArea
void handleReleaseEvent(QPointerEvent *)
void viewportAxisMoved(AxisData &data, qreal minExtent, qreal maxExtent, QQuickTimeLineCallback::Callback fixupCallback)
void handlePressEvent(QPointerEvent *)
QQuickFlickable::BoundsBehavior boundsBehavior
static QObject * data_at(QQmlListProperty< QObject > *, qsizetype)
QVector2D firstPointLocalVelocity(QPointerEvent *event)
bool flickX(QEvent::Type eventType, qreal velocity)
void maybeBeginDrag(qint64 currentTimestamp, const QPointF &pressPosn)
bool startTransition(QQuickFlickablePrivate::AxisData *data, qreal toPos)
QQuickFlickableReboundTransition(QQuickFlickable *f, const QString &name)
void yPositionChanged(qreal yPosition)
void heightRatioChanged(qreal heightRatio)
void widthRatioChanged(qreal widthRatio)
void xPositionChanged(qreal xPosition)
QQuickFlickableVisibleArea(QQuickFlickable *parent=nullptr)
void flickDecelerationChanged()
void setMaximumFlickVelocity(qreal)
void geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry) override
friend class QQuickFlickableReboundTransition
void movementEnded()
void touchEvent(QTouchEvent *event) override
This event handler can be reimplemented in a subclass to receive touch events for an item.
void mouseUngrabEvent() override
This event handler can be reimplemented in a subclass to be notified when a mouse ungrab event has oc...
void setBottomMargin(qreal m)
Q_INVOKABLE void flick(qreal xVelocity, qreal yVelocity)
\qmlmethod QtQuick::Flickable::flick(qreal xVelocity, qreal yVelocity)
void setPixelAligned(bool align)
void flickingChanged()
void maximumFlickVelocityChanged()
bool isAtXEnd() const
\qmlproperty bool QtQuick::Flickable::atXBeginning \qmlproperty bool QtQuick::Flickable::atXEnd \qmlp...
virtual qreal minYExtent() const
void movementStarted()
QQuickFlickable(QQuickItem *parent=nullptr)
\qmlsignal QtQuick::Flickable::dragStarted()
void boundsBehaviorChanged()
Q_INVOKABLE void returnToBounds()
\qmlmethod QtQuick::Flickable::returnToBounds()
void setPressDelay(int delay)
bool isMovingHorizontally() const
FINALQQmlListProperty< QObject > flickableData
bool isInteractive() const
\qmlproperty bool QtQuick::Flickable::interactive
void timerEvent(QTimerEvent *event) override
This event handler can be reimplemented in a subclass to receive timer events for the object.
~QQuickFlickable() override
void componentComplete() override
Invoked after the root component that caused this instantiation has completed construction.
void setContentWidth(qreal)
void setLeftMargin(qreal m)
bool isFlickingVertically() const
void movingChanged()
BoundsBehavior boundsBehavior
FINALQQuickTransition * rebound
FINALqreal verticalOvershoot
virtual void setContentX(qreal pos)
void mousePressEvent(QMouseEvent *event) override
This event handler can be reimplemented in a subclass to receive mouse press events for an item.
Q_INVOKABLE void resizeContent(qreal w, qreal h, QPointF center)
\qmlmethod QtQuick::Flickable::resizeContent(real width, real height, QPointF center)
void leftMarginChanged()
FlickableDirection flickableDirection
void topMarginChanged()
void setRightMargin(qreal m)
void setTopMargin(qreal m)
bool filterPointerEvent(QQuickItem *receiver, QPointerEvent *event)
void interactiveChanged()
virtual void viewportMoved(Qt::Orientations orient)
bool isDraggingHorizontally() const
void flickableDirectionChanged()
FINALqreal horizontalOvershoot
void pixelAlignedChanged()
bool isDragging() const
\qmlproperty bool QtQuick::Flickable::dragging \qmlproperty bool QtQuick::Flickable::draggingHorizont...
bool isAtYEnd() const
void setRebound(QQuickTransition *transition)
void bottomMarginChanged()
void movingHorizontallyChanged()
Q_INVOKABLE void cancelFlick()
\qmlmethod QtQuick::Flickable::cancelFlick()
bool childMouseEventFilter(QQuickItem *, QEvent *) override
void flickingVerticallyChanged()
bool isAtYBeginning() const
bool isFlickingHorizontally() const
\qmlproperty bool QtQuick::Flickable::flicking \qmlproperty bool QtQuick::Flickable::flickingHorizont...
void setFlickDeceleration(qreal)
qreal vHeight() const
void setInteractive(bool)
bool isMoving() const
\qmlproperty bool QtQuick::Flickable::moving \qmlproperty bool QtQuick::Flickable::movingHorizontally...
bool isAtXBeginning() const
void mouseReleaseEvent(QMouseEvent *event) override
This event handler can be reimplemented in a subclass to receive mouse release events for an item.
void contentWidthChanged()
friend class QQuickFlickableVisibleArea
virtual void setContentY(qreal pos)
void movingVerticallyChanged()
void pressDelayChanged()
void rightMarginChanged()
void mouseMoveEvent(QMouseEvent *event) override
This event handler can be reimplemented in a subclass to receive mouse move events for an item.
QQuickFlickableVisibleArea * visibleArea
void setFlickableDirection(FlickableDirection)
virtual qreal maxXExtent() const
void flickingHorizontallyChanged()
virtual qreal maxYExtent() const
BoundsMovement boundsMovement
void contentHeightChanged()
void setSynchronousDrag(bool v)
bool isDraggingVertically() const
QQuickItem * contentItem
virtual qreal minXExtent() const
QQmlListProperty< QQuickItem > flickableChildren
void setContentHeight(qreal)
void reboundChanged()
void setBoundsMovement(BoundsMovement movement)
bool isMovingVertically() const
void setBoundsBehavior(BoundsBehavior)
bool isFlicking() const
QTransform windowToItemTransform() const
Returns a transform that maps points from window space into item space.
quint32 replayingPressEvent
void addItemChangeListener(QQuickItemChangeListener *listener, ChangeTypes types)
QQuickWindow * window
QQuickDeliveryAgentPrivate * deliveryAgentPrivate()
virtual void addPointerHandler(QQuickPointerHandler *h)
QQmlListProperty< QQuickItem > children()
static QQuickItemPrivate * get(QQuickItem *item)
The QQuickItem class provides the most basic of all visual items in \l {Qt Quick}.
Definition qquickitem.h:64
virtual void mouseReleaseEvent(QMouseEvent *event)
This event handler can be reimplemented in a subclass to receive mouse release events for an item.
Q_INVOKABLE QPointF mapFromItem(const QQuickItem *item, const QPointF &point) const
Maps the given point in item's coordinate system to the equivalent point within this item's coordinat...
Qt::MouseButtons acceptedMouseButtons() const
Returns the mouse buttons accepted by this item.
virtual void geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry)
qreal x
\qmlproperty real QtQuick::Item::x \qmlproperty real QtQuick::Item::y \qmlproperty real QtQuick::Item...
Definition qquickitem.h:73
void setParentItem(QQuickItem *parent)
void componentComplete() override
\reimp Derived classes should call the base class method before adding their own actions to perform a...
QPointF mapFromScene(const QPointF &point) const
Maps the given point in the scene's coordinate system to the equivalent point within this item's coor...
qreal y
Defines the item's y position relative to its parent.
Definition qquickitem.h:74
bool isVisible() const
virtual Q_INVOKABLE bool contains(const QPointF &point) const
\qmlmethod bool QtQuick::Item::contains(point point)
bool keepTouchGrab() const
Returns whether the touch points grabbed by this item should exclusively remain with this item.
QQuickWindow * window() const
Returns the window in which this item is rendered.
virtual void mousePressEvent(QMouseEvent *event)
This event handler can be reimplemented in a subclass to receive mouse press events for an item.
qreal width
This property holds the width of this item.
Definition qquickitem.h:76
bool keepMouseGrab() const
Returns whether mouse input should exclusively remain with this item.
bool isEnabled() const
virtual void touchEvent(QTouchEvent *event)
This event handler can be reimplemented in a subclass to receive touch events for an item.
qreal height
This property holds the height of this item.
Definition qquickitem.h:77
virtual bool childMouseEventFilter(QQuickItem *, QEvent *)
Reimplement this method to filter the pointer events that are received by this item's children.
void setX(qreal)
void setY(qreal)
virtual void mouseMoveEvent(QMouseEvent *event)
This event handler can be reimplemented in a subclass to receive mouse move events for an item.
void setValue(qreal v) override
Set the current value.
virtual qreal value() const
Return the current value.
The QQuickTimeLine class provides a timeline for controlling animations.
void reset(QQuickTimeLineValue &)
Cancel (but don't complete) all scheduled actions for timeLineValue.
int accel(QQuickTimeLineValue &, qreal velocity, qreal accel)
Decelerate timeLineValue from the starting velocity to zero at the given acceleration rate.
void callback(const QQuickTimeLineCallback &)
Execute the event.
bool isActive() const
Returns true if the timeline is active.
void clear()
Resets the timeline.
void set(QQuickTimeLineValue &, qreal)
Set the value of timeLineValue.
void move(QQuickTimeLineValue &, qreal destination, int time=500)
Linearly change the timeLineValue from its current value to the given destination value over time mil...
void transition(const QList< QQuickStateAction > &, QQuickTransition *transition, QObject *defaultTarget=nullptr)
\qmltype Window \instantiates QQuickWindow \inqmlmodule QtQuick
\inmodule QtCore\reentrant
Definition qrect.h:483
constexpr qreal height() const noexcept
Returns the height of the rectangle.
Definition qrect.h:718
constexpr qreal width() const noexcept
Returns the width of the rectangle.
Definition qrect.h:715
constexpr QPointF topLeft() const noexcept
Returns the position of the rectangle's top-left corner.
Definition qrect.h:510
\inmodule QtCore
T * data() const noexcept
Returns the value of the pointer referenced by this object.
A base class for pointer events containing a single point, such as mouse events.
Definition qevent.h:108
Qt::MouseButtons buttons() const
Returns the button state when the event was generated.
Definition qevent.h:116
\inmodule QtCore
Definition qsize.h:207
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:127
\inmodule QtCore
Definition qcoreevent.h:359
The QTouchEvent class contains parameters that describe a touch event.
Definition qevent.h:916
The QTransform class specifies 2D transformations of a coordinate system.
Definition qtransform.h:20
int toInt(bool *ok=nullptr) const
Returns the variant as an int if the variant has userType() \l QMetaType::Int, \l QMetaType::Bool,...
The QVector2D class represents a vector or vertex in 2D space.
Definition qvectornd.h:31
constexpr float y() const noexcept
Returns the y coordinate of this point.
Definition qvectornd.h:502
constexpr float x() const noexcept
Returns the x coordinate of this point.
Definition qvectornd.h:501
#define this
Definition dialogs.cpp:9
QPushButton * button
[2]
double e
direction
Combined button and popup list for selecting options.
@ LeftButton
Definition qnamespace.h:57
@ Horizontal
Definition qnamespace.h:98
@ Vertical
Definition qnamespace.h:99
@ MouseEventNotSynthesized
@ ScrollBegin
@ ScrollUpdate
@ ScrollMomentum
@ NoScrollPhase
@ ScrollEnd
@ XAxis
@ YAxis
#define qApp
bool qFuzzyCompare(qfloat16 p1, qfloat16 p2) noexcept
Definition qfloat16.h:287
bool qFuzzyIsNull(qfloat16 f) noexcept
Definition qfloat16.h:303
qfloat16 qSqrt(qfloat16 f)
Definition qfloat16.h:243
#define Q_LOGGING_CATEGORY(name,...)
#define qCDebug(category,...)
#define Q_DECLARE_LOGGING_CATEGORY(name)
int qFloor(T v)
Definition qmath.h:42
int qCeil(T v)
Definition qmath.h:36
auto qAtan(T v)
Definition qmath.h:84
constexpr const T & qMin(const T &a, const T &b)
Definition qminmax.h:40
constexpr const T & qBound(const T &min, const T &val, const T &max)
Definition qminmax.h:44
constexpr const T & qMax(const T &a, const T &b)
Definition qminmax.h:42
constexpr T qAbs(const T &t)
Definition qnumeric.h:328
#define SLOT(a)
Definition qobjectdefs.h:51
#define SIGNAL(a)
Definition qobjectdefs.h:52
GLint GLfloat GLfloat GLfloat v2
GLboolean GLboolean GLboolean b
GLsizei const GLfloat * v
[13]
GLint GLint GLint GLint GLint x
[0]
const GLfloat * m
GLfloat GLfloat GLfloat w
[0]
GLint GLsizei GLsizei height
GLfloat GLfloat GLfloat GLfloat GLfloat maxY
GLboolean GLboolean GLboolean GLboolean a
[7]
GLenum GLenum GLsizei count
GLfloat minY
GLfloat GLfloat f
GLint GLsizei width
GLenum target
GLint GLint GLint GLint GLint GLint GLint GLbitfield GLenum filter
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLuint name
GLint y
GLfloat GLfloat GLfloat GLfloat maxX
GLfloat GLfloat GLfloat GLfloat h
struct _cl_event * event
GLuint GLenum GLenum transform
GLuint GLfloat * val
GLdouble GLdouble t
Definition qopenglext.h:243
GLdouble GLdouble GLdouble GLdouble q
Definition qopenglext.h:259
GLfloat GLfloat p
[1]
#define qmlobject_connect(Sender, SenderType, Signal, Receiver, ReceiverType, Method)
Connect Signal of Sender to Method of Receiver.
void QQml_setParent_noEvent(QObject *object, QObject *parent)
Makes the object a child of parent.
QQuickItem * qmlobject_cast< QQuickItem * >(QObject *object)
static bool fuzzyLessThanOrEqualTo(qreal a, qreal b)
static qreal EaseOvershoot(qreal t)
static QT_BEGIN_NAMESPACE const int RetainGrabVelocity
const qreal _q_MaximumWheelDeceleration
#define QML_FLICK_SAMPLEBUFFER
const qreal _q_MinimumFlickVelocity
#define QML_FLICK_OVERSHOOT
#define QML_FLICK_MULTIFLICK_MAXBOOST
#define QML_FLICK_MULTIFLICK_THRESHOLD
#define QML_FLICK_OVERSHOOTFRICTION
#define QML_FLICK_DISCARDSAMPLES
#define QML_FLICK_MULTIFLICK_RATIO
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define Q_ASSERT_X(cond, x, msg)
Definition qrandom.cpp:48
QLatin1StringView QLatin1String
Definition qstringfwd.h:31
#define fp
static double elapsed(qint64 after, qint64 before)
Q_CORE_EXPORT int qEnvironmentVariableIntValue(const char *varName, bool *ok=nullptr) noexcept
#define emit
ptrdiff_t qsizetype
Definition qtypes.h:70
long long qint64
Definition qtypes.h:55
double qreal
Definition qtypes.h:92
bool testFlag(MaskType mask, FlagType flag)
std::uniform_real_distribution dist(1, 2.5)
[2]
QObject::connect nullptr
QPoint oldPosition
[6]
QGraphicsItem * item
void addVelocitySample(qreal v, qreal maxVelocity)
QQuickFlickableReboundTransition * transitionToBounds
QPODVector< qreal, 10 > velocityBuffer
QQuickFlickablePrivate::Velocity smoothVelocity
QQuickTimeLineValueProxy< QQuickFlickablePrivate > move
void setValue(qreal v) override
Set the current value.
IUIAutomationTreeWalker __RPC__deref_out_opt IUIAutomationElement ** parent