11#if QT_CONFIG(quick_draganddrop)
12#include "qquickdrag_p.h"
15#include <QtQuick/private/qquickpointerhandler_p.h>
16#include <QtQuick/private/qquicktransition_p.h>
17#include <private/qqmlglobal_p.h>
19#include <QtQml/qqmlinfo.h>
20#include <QtGui/qevent.h>
21#include <QtGui/qguiapplication.h>
22#include <QtGui/private/qguiapplication_p.h>
23#include <QtGui/private/qeventpoint_p.h>
24#include <QtGui/qstylehints.h>
25#include <QtGui/qaccessible.h>
26#include <QtCore/qmath.h>
27#include <qpa/qplatformtheme.h>
35Q_STATIC_LOGGING_CATEGORY(lcFilter,
"qt.quick.flickable.filter")
36Q_STATIC_LOGGING_CATEGORY(lcReplay,
"qt.quick.flickable.replay")
37Q_STATIC_LOGGING_CATEGORY(lcWheel,
"qt.quick.flickable.wheel")
38Q_STATIC_LOGGING_CATEGORY(lcVel,
"qt.quick.flickable.velocity")
42static const int RetainGrabVelocity = 100;
48QQuickFlickableVisibleArea::QQuickFlickableVisibleArea(QQuickFlickable *parent)
49 : QObject(parent), flickable(parent), m_xPosition(0.), m_widthRatio(0.)
50 , m_yPosition(0.), m_heightRatio(0.)
54qreal QQuickFlickableVisibleArea::widthRatio()
const
59qreal QQuickFlickableVisibleArea::xPosition()
const
64qreal QQuickFlickableVisibleArea::heightRatio()
const
69qreal QQuickFlickableVisibleArea::yPosition()
const
74void QQuickFlickableVisibleArea::updateVisible()
76 QQuickFlickablePrivate *p = QQuickFlickablePrivate::get(flickable);
80 bool changeWidth =
false;
81 bool changeHeight =
false;
84 const qreal viewheight = flickable->height();
85 const qreal maxyextent = -flickable->maxYExtent() + flickable->minYExtent();
86 const qreal maxYBounds = maxyextent + viewheight;
89 if (!qFuzzyIsNull(maxYBounds)) {
90 qreal y = p->pixelAligned ? std::round(p->vData.move.value()) : p->vData.move.value();
91 pagePos = (-y + flickable->minYExtent()) / maxYBounds;
92 pageSize = viewheight / maxYBounds;
95 if (pageSize != m_heightRatio) {
96 m_heightRatio = pageSize;
99 if (pagePos != m_yPosition) {
100 m_yPosition = pagePos;
105 const qreal viewwidth = flickable->width();
106 const qreal maxxextent = -flickable->maxXExtent() + flickable->minXExtent();
107 const qreal maxXBounds = maxxextent + viewwidth;
108 if (!qFuzzyIsNull(maxXBounds)) {
109 qreal x = p->pixelAligned ? std::round(p->hData.move.value()) : p->hData.move.value();
110 pagePos = (-x + flickable->minXExtent()) / maxXBounds;
111 pageSize = viewwidth / maxXBounds;
117 if (pageSize != m_widthRatio) {
118 m_widthRatio = pageSize;
121 if (pagePos != m_xPosition) {
122 m_xPosition = pagePos;
127 emit xPositionChanged(m_xPosition);
129 emit yPositionChanged(m_yPosition);
131 emit widthRatioChanged(m_widthRatio);
133 emit heightRatioChanged(m_heightRatio);
151 QQuickFlickablePrivate *fp = QQuickFlickablePrivate::get(flickable);
152 if (!fp->rebound || !fp->rebound->enabled())
156 axisData->transitionTo = toPos;
157 axisData->transitionToSet =
true;
160 actions << QQuickStateAction(fp->contentItem, propName, toPos);
161 QQuickTransitionManager::transition(actions, fp->rebound, fp->contentItem);
170 if (!flickable || !isRunning())
172 QQuickFlickablePrivate *fp = QQuickFlickablePrivate::get(flickable);
173 if (axisData == &fp->hData)
174 axisData->move.setValue(-flickable->contentX());
176 axisData->move.setValue(-flickable->contentY());
185 axisData->move.setValue(axisData->transitionTo);
186 QQuickFlickablePrivate *fp = QQuickFlickablePrivate::get(flickable);
189 if (!fp->hData.transitionToBounds->isActive()
190 && !fp->vData.transitionToBounds->isActive()) {
191 flickable->movementEnding();
196 QQuickStateOperation::ActionList actions;
197 QQuickFlickable *flickable;
198 QQuickFlickablePrivate::AxisData *axisData;
203QQuickFlickablePrivate::AxisData::~AxisData()
205 delete transitionToBounds;
211
212
213
214
215
216
217
218
221 const QQuickItem *flickable = parentItem();
222 const QPointF posInFlickable = flickable->mapFromItem(
this, point);
223 return flickable->contains(posInFlickable);
227QQuickFlickablePrivate::QQuickFlickablePrivate()
228 : contentItem(
new QQuickFlickableContentItem)
229 , hData(
this, &QQuickFlickablePrivate::setViewportX)
230 , vData(
this, &QQuickFlickablePrivate::setViewportY)
231 , hMoved(
false), vMoved(
false)
232 , stealMouse(
false), pressed(
false)
233 , scrollingPhase(
false), interactive(
true), calcVelocity(
false)
234 , pixelAligned(
false)
236 , acceptedButtons(Qt::LeftButton)
239 , deceleration(QGuiApplicationPrivate::platformTheme()->themeHint(QPlatformTheme::FlickDeceleration).toReal())
240 , wheelDeceleration(15000)
241 , maxVelocity(QGuiApplicationPrivate::platformTheme()->themeHint(QPlatformTheme::FlickMaximumVelocity).toReal())
242 , delayedPressEvent(
nullptr), pressDelay(0), fixupDuration(400)
243 , flickBoost(1.0), initialWheelFlickDistance(qApp->styleHints()->wheelScrollLines() * 24)
244 , fixupMode(Normal), vTime(0), visibleArea(
nullptr)
245 , flickableDirection(QQuickFlickable::AutoFlickDirection)
246 , boundsBehavior(QQuickFlickable::DragAndOvershootBounds)
247 , boundsMovement(QQuickFlickable::FollowBoundsBehavior)
250 const int wheelDecelerationEnv = qEnvironmentVariableIntValue(
"QT_QUICK_FLICKABLE_WHEEL_DECELERATION");
251 if (wheelDecelerationEnv > 0)
252 wheelDeceleration = wheelDecelerationEnv;
255void QQuickFlickablePrivate::init()
257 Q_Q(QQuickFlickable);
258 QQml_setParent_noEvent(contentItem, q);
259 contentItem->setParentItem(q);
260 qmlobject_connect(&timeline, QQuickTimeLine, SIGNAL(completed()),
261 q, QQuickFlickable, SLOT(timelineCompleted()));
262 qmlobject_connect(&velocityTimeline, QQuickTimeLine, SIGNAL(completed()),
263 q, QQuickFlickable, SLOT(velocityTimelineCompleted()));
264 q->setAcceptedMouseButtons(acceptedButtons);
265 q->setAcceptTouchEvents(
true);
266 q->setFiltersChildMouseEvents(
true);
267 q->setFlag(QQuickItem::ItemIsViewport);
268 QQuickItemPrivate *viewportPrivate = QQuickItemPrivate::get(contentItem);
269 viewportPrivate->addItemChangeListener(
this, QQuickItemPrivate::Geometry);
270 setSizePolicy(QLayoutPolicy::Expanding, QLayoutPolicy::Expanding);
274
275
276
277
278qreal QQuickFlickablePrivate::overShootDistance(qreal velocity)
const
280 if (maxVelocity <= 0)
286void QQuickFlickablePrivate::AxisData::addVelocitySample(qreal v, qreal maxVelocity)
290 else if (v < -maxVelocity)
292 velocityBuffer.append(v);
294 velocityBuffer.remove(0);
297void QQuickFlickablePrivate::AxisData::updateVelocity()
302 for (
int i = 0; i < count; ++i) {
303 qreal v = velocityBuffer.at(i);
310void QQuickFlickablePrivate::itemGeometryChanged(QQuickItem *item, QQuickGeometryChange change,
const QRectF &oldGeom)
312 Q_Q(QQuickFlickable);
313 if (item == contentItem) {
314 Qt::Orientations orient;
315 if (change.xChange())
316 orient |= Qt::Horizontal;
317 if (change.yChange())
318 orient |= Qt::Vertical;
320 q->viewportMoved(orient);
321 const QPointF deltaMoved = item->position() - oldGeom.topLeft();
322 if (hData.contentPositionChangedExternallyDuringDrag)
323 hData.pressPos += deltaMoved.x();
324 if (vData.contentPositionChangedExternallyDuringDrag)
325 vData.pressPos += deltaMoved.y();
327 if (orient & Qt::Horizontal)
328 emit q->contentXChanged();
329 if (orient & Qt::Vertical)
330 emit q->contentYChanged();
334bool QQuickFlickablePrivate::flickX(QEvent::Type eventType, qreal velocity)
336 Q_Q(QQuickFlickable);
337 return flick(hData, q->minXExtent(), q->maxXExtent(), q->width(), fixupX_callback, eventType, velocity);
340bool QQuickFlickablePrivate::flickY(QEvent::Type eventType, qreal velocity)
342 Q_Q(QQuickFlickable);
343 return flick(vData, q->minYExtent(), q->maxYExtent(), q->height(), fixupY_callback, eventType, velocity);
346bool QQuickFlickablePrivate::flick(AxisData &data, qreal minExtent, qreal maxExtent, qreal,
347 QQuickTimeLineCallback::Callback fixupCallback,
348 QEvent::Type eventType, qreal velocity)
350 Q_Q(QQuickFlickable);
351 qreal maxDistance = -1;
352 data.fixingUp =
false;
355 maxDistance = qAbs(minExtent - data.move.value());
356 data.flickTarget = minExtent;
358 maxDistance = qAbs(maxExtent - data.move.value());
359 data.flickTarget = maxExtent;
361 if (maxDistance > 0 || boundsBehavior & QQuickFlickable::OvershootBounds) {
363 if (maxVelocity != -1 && maxVelocity < qAbs(v)) {
370 qreal accel = eventType == QEvent::Wheel ? wheelDeceleration : deceleration;
371 qCDebug(lcFlickable) <<
"choosing deceleration" << accel <<
"for" << eventType;
374 qreal dist = v2 / (accel * 2.0);
377 qreal target = std::round(data.move.value() - dist);
378 dist = -target + data.move.value();
379 accel = v2 / (2.0f * qAbs(dist));
382 if (!data.inOvershoot) {
383 if (boundsBehavior & QQuickFlickable::OvershootBounds)
384 timeline.accel(data.move, v, accel);
386 timeline.accel(data.move, v, accel, maxDistance);
388 timeline.callback(QQuickTimeLineCallback(&data.move, fixupCallback,
this));
391 return !hData.flicking && q->xflick();
392 else if (&data == &vData)
393 return !vData.flicking && q->yflick();
397 fixup(data, minExtent, maxExtent);
402void QQuickFlickablePrivate::fixupY_callback(
void *data)
404 ((QQuickFlickablePrivate *)data)->fixupY();
407void QQuickFlickablePrivate::fixupX_callback(
void *data)
409 ((QQuickFlickablePrivate *)data)->fixupX();
412void QQuickFlickablePrivate::fixupX()
414 Q_Q(QQuickFlickable);
415 if (!q->isComponentComplete())
417 fixup(hData, q->minXExtent(), q->maxXExtent());
420void QQuickFlickablePrivate::fixupY()
422 Q_Q(QQuickFlickable);
423 if (!q->isComponentComplete())
425 fixup(vData, q->minYExtent(), q->maxYExtent());
429
430
431
432
433
434
435
436void QQuickFlickablePrivate::adjustContentPos(AxisData &data, qreal toPos)
438 Q_Q(QQuickFlickable);
441 timeline.set(data.move, toPos);
446 timeline.move(data.move, toPos, QEasingCurve(QEasingCurve::OutExpo), 3*fixupDuration/4);
447 data.fixingUp =
true;
450 if (data.transitionToBounds && data.transitionToBounds->startTransition(&data, toPos)) {
451 q->movementStarting();
452 data.fixingUp =
true;
454 qreal dist = toPos - data.move;
455 timeline.move(data.move, toPos - dist/2, QEasingCurve(QEasingCurve::InQuad), fixupDuration/4);
456 timeline.move(data.move, toPos, QEasingCurve(QEasingCurve::OutExpo), 3*fixupDuration/4);
457 data.fixingUp =
true;
463void QQuickFlickablePrivate::resetTimeline(AxisData &data)
465 timeline.reset(data.move);
466 if (data.transitionToBounds)
467 data.transitionToBounds->stopTransition();
470void QQuickFlickablePrivate::clearTimeline()
473 if (hData.transitionToBounds)
474 hData.transitionToBounds->stopTransition();
475 if (vData.transitionToBounds)
476 vData.transitionToBounds->stopTransition();
480
481
482
483
484
485
486
487
488
489void QQuickFlickablePrivate::fixup(AxisData &data, qreal minExtent, qreal maxExtent)
491 if (data.move.value() >= minExtent || maxExtent > minExtent) {
493 if (data.move.value() != minExtent) {
494 adjustContentPos(data, minExtent);
496 }
else if (data.move.value() <= maxExtent) {
498 adjustContentPos(data, maxExtent);
499 }
else if (-std::round(-data.move.value()) != data.move.value()) {
502 qreal val = data.move.value();
503 if (std::abs(std::round(val) - val) < 0.25)
504 val = std::round(val);
505 else if (data.smoothVelocity.value() > 0)
506 val = std::ceil(val);
507 else if (data.smoothVelocity.value() < 0)
508 val = std::floor(val);
510 val = std::round(val);
511 timeline.set(data.move, val);
513 data.inOvershoot =
false;
515 data.vTime = timeline.time();
520 if (a == 0.0 || b == 0.0) {
525 return a <= b || qFuzzyCompare(a, b);
529
530
531
532
533
534
535
536
537void QQuickFlickablePrivate::updateBeginningEnd()
539 Q_Q(QQuickFlickable);
540 bool atXBeginningChange =
false, atXEndChange =
false;
541 bool atYBeginningChange =
false, atYEndChange =
false;
544 const qreal maxyextent = -q->maxYExtent();
545 const qreal minyextent = -q->minYExtent();
546 const qreal ypos = pixelAligned ? -std::round(vData.move.value()) : -vData.move.value();
547 bool atBeginning = fuzzyLessThanOrEqualTo(ypos, std::ceil(minyextent));
548 bool atEnd = fuzzyLessThanOrEqualTo(std::floor(maxyextent), ypos);
550 if (atBeginning != vData.atBeginning) {
551 vData.atBeginning = atBeginning;
552 atYBeginningChange =
true;
553 if (!vData.moving && atBeginning)
554 vData.smoothVelocity.setValue(0);
556 if (atEnd != vData.atEnd) {
559 if (!vData.moving && atEnd)
560 vData.smoothVelocity.setValue(0);
564 const qreal maxxextent = -q->maxXExtent();
565 const qreal minxextent = -q->minXExtent();
566 const qreal xpos = pixelAligned ? -std::round(hData.move.value()) : -hData.move.value();
567 atBeginning = fuzzyLessThanOrEqualTo(xpos, std::ceil(minxextent));
568 atEnd = fuzzyLessThanOrEqualTo(std::floor(maxxextent), xpos);
570 if (atBeginning != hData.atBeginning) {
571 hData.atBeginning = atBeginning;
572 atXBeginningChange =
true;
573 if (!hData.moving && atBeginning)
574 hData.smoothVelocity.setValue(0);
576 if (atEnd != hData.atEnd) {
579 if (!hData.moving && atEnd)
580 hData.smoothVelocity.setValue(0);
583 if (vData.extentsChanged) {
584 vData.extentsChanged =
false;
585 qreal originY = q->originY();
586 if (vData.origin != originY) {
587 vData.origin = originY;
588 emit q->originYChanged();
592 if (hData.extentsChanged) {
593 hData.extentsChanged =
false;
594 qreal originX = q->originX();
595 if (hData.origin != originX) {
596 hData.origin = originX;
597 emit q->originXChanged();
601 if (atXEndChange || atYEndChange || atXBeginningChange || atYBeginningChange)
602 emit q->isAtBoundaryChanged();
604 emit q->atXEndChanged();
605 if (atXBeginningChange)
606 emit q->atXBeginningChanged();
608 emit q->atYEndChanged();
609 if (atYBeginningChange)
610 emit q->atYBeginningChanged();
613 visibleArea->updateVisible();
617
618
619
620
621
624
625
626
627
628
629
630
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
711
712
713
714
715
718
719
720
721
722
723
724
725
728
729
730
731
732
733
736
737
738
739
740
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762QQuickFlickable::QQuickFlickable(QQuickItem *parent)
763 : QQuickItem(*(
new QQuickFlickablePrivate), parent)
765 Q_D(QQuickFlickable);
769QQuickFlickable::QQuickFlickable(QQuickFlickablePrivate &dd, QQuickItem *parent)
770 : QQuickItem(dd, parent)
772 Q_D(QQuickFlickable);
776QQuickFlickable::~QQuickFlickable()
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800qreal QQuickFlickable::contentX()
const
802 Q_D(
const QQuickFlickable);
803 return -d->contentItem->x();
806void QQuickFlickable::setContentX(qreal pos)
808 Q_D(QQuickFlickable);
809 d->hData.explicitValue =
true;
810 d->resetTimeline(d->hData);
811 d->hData.vTime = d->timeline.time();
812 if (isMoving() || isFlicking())
813 movementEnding(
true,
false);
814 if (!qFuzzyCompare(-pos, d->hData.move.value())) {
815 d->hData.contentPositionChangedExternallyDuringDrag = d->hData.dragging;
816 d->hData.move.setValue(-pos);
817 d->hData.contentPositionChangedExternallyDuringDrag =
false;
821qreal QQuickFlickable::contentY()
const
823 Q_D(
const QQuickFlickable);
824 return -d->contentItem->y();
827void QQuickFlickable::setContentY(qreal pos)
829 Q_D(QQuickFlickable);
830 d->vData.explicitValue =
true;
831 d->resetTimeline(d->vData);
832 d->vData.vTime = d->timeline.time();
833 if (isMoving() || isFlicking())
834 movementEnding(
false,
true);
835 if (!qFuzzyCompare(-pos, d->vData.move.value())) {
836 d->vData.contentPositionChangedExternallyDuringDrag = d->vData.dragging;
837 d->vData.move.setValue(-pos);
838 d->vData.contentPositionChangedExternallyDuringDrag =
false;
843
844
845
846
847
848
849
850
851
852
853
854
855bool QQuickFlickable::isInteractive()
const
857 Q_D(
const QQuickFlickable);
858 return d->interactive;
861void QQuickFlickable::setInteractive(
bool interactive)
863 Q_D(QQuickFlickable);
864 if (interactive != d->interactive) {
865 d->interactive = interactive;
867 d->cancelInteraction();
869 emit interactiveChanged();
874
875
876
877
878
879
880
881
882
883
884
885
886qreal QQuickFlickable::horizontalVelocity()
const
888 Q_D(
const QQuickFlickable);
889 return d->hData.smoothVelocity.value();
892qreal QQuickFlickable::verticalVelocity()
const
894 Q_D(
const QQuickFlickable);
895 return d->vData.smoothVelocity.value();
899
900
901
902
903
904
905
906
907bool QQuickFlickable::isAtXEnd()
const
909 Q_D(
const QQuickFlickable);
910 return d->hData.atEnd;
913bool QQuickFlickable::isAtXBeginning()
const
915 Q_D(
const QQuickFlickable);
916 return d->hData.atBeginning;
919bool QQuickFlickable::isAtYEnd()
const
921 Q_D(
const QQuickFlickable);
922 return d->vData.atEnd;
925bool QQuickFlickable::isAtYBeginning()
const
927 Q_D(
const QQuickFlickable);
928 return d->vData.atBeginning;
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949QQuickItem *QQuickFlickable::contentItem()
const
951 Q_D(
const QQuickFlickable);
952 return d->contentItem;
955QQuickFlickableVisibleArea *QQuickFlickable::visibleArea()
957 Q_D(QQuickFlickable);
958 if (!d->visibleArea) {
959 d->visibleArea =
new QQuickFlickableVisibleArea(
this);
960 d->visibleArea->updateVisible();
962 return d->visibleArea;
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984QQuickFlickable::FlickableDirection QQuickFlickable::flickableDirection()
const
986 Q_D(
const QQuickFlickable);
987 return d->flickableDirection;
990void QQuickFlickable::setFlickableDirection(FlickableDirection direction)
992 Q_D(QQuickFlickable);
993 if (direction != d->flickableDirection) {
994 d->flickableDirection = direction;
995 emit flickableDirectionChanged();
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011bool QQuickFlickable::pixelAligned()
const
1013 Q_D(
const QQuickFlickable);
1014 return d->pixelAligned;
1017void QQuickFlickable::setPixelAligned(
bool align)
1019 Q_D(QQuickFlickable);
1020 if (align != d->pixelAligned) {
1021 d->pixelAligned = align;
1022 emit pixelAlignedChanged();
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038bool QQuickFlickable::synchronousDrag()
const
1040 Q_D(
const QQuickFlickable);
1044void QQuickFlickable::setSynchronousDrag(
bool v)
1046 Q_D(QQuickFlickable);
1047 if (v != d->syncDrag) {
1049 emit synchronousDragChanged();
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068Qt::MouseButtons QQuickFlickable::acceptedButtons()
const
1070 Q_D(
const QQuickFlickable);
1071 return d->acceptedButtons;
1074void QQuickFlickable::setAcceptedButtons(Qt::MouseButtons buttons)
1076 Q_D(QQuickFlickable);
1077 if (d->acceptedButtons == buttons)
1080 d->acceptedButtons = buttons;
1081 setAcceptedMouseButtons(buttons);
1082 emit acceptedButtonsChanged();
1086
1087
1088
1089QVector2D QQuickFlickablePrivate::firstPointLocalVelocity(QPointerEvent *event)
1091 QTransform transform = windowToItemTransform();
1093 return QVector2D(transform.map(event->point(0).velocity().toPointF()) - transform.map(QPointF()));
1096qint64 QQuickFlickablePrivate::computeCurrentTime(QInputEvent *event)
const
1098 if (0 != event->timestamp())
1099 return event->timestamp();
1100 if (!timer.isValid())
1102 return timer.elapsed();
1105void QQuickFlickablePrivate::handlePressEvent(QPointerEvent *event)
1107 Q_Q(QQuickFlickable);
1109 if (interactive && timeline.isActive()
1110 && ((qAbs(hData.smoothVelocity.value()) > RetainGrabVelocity && !hData.fixingUp && !hData.inOvershoot)
1111 || (qAbs(vData.smoothVelocity.value()) > RetainGrabVelocity && !vData.fixingUp && !vData.inOvershoot))) {
1113 int flickTime = timeline.time();
1114 if (flickTime > 600) {
1116 hData.continuousFlickVelocity = 0;
1117 vData.continuousFlickVelocity = 0;
1120 hData.continuousFlickVelocity = -hData.smoothVelocity.value();
1121 vData.continuousFlickVelocity = -vData.smoothVelocity.value();
1122 if (flickTime > 300)
1123 flickBoost = qMax(1.0, flickBoost - 0.5);
1127 hData.continuousFlickVelocity = 0;
1128 vData.continuousFlickVelocity = 0;
1131 q->setKeepMouseGrab(stealMouse);
1133 maybeBeginDrag(computeCurrentTime(event), event->points().first().position(),
1134 event->isSinglePointEvent() ?
static_cast<QSinglePointEvent *>(event)->buttons()
1138void QQuickFlickablePrivate::maybeBeginDrag(qint64 currentTimestamp,
const QPointF &pressPosn, Qt::MouseButtons buttons)
1140 Q_Q(QQuickFlickable);
1141 clearDelayedPress();
1143 pressed = (buttons == Qt::NoButton) || (acceptedButtons != Qt::NoButton && (buttons & acceptedButtons) != 0);
1145 if (hData.transitionToBounds)
1146 hData.transitionToBounds->stopTransition();
1147 if (vData.transitionToBounds)
1148 vData.transitionToBounds->stopTransition();
1149 if (!hData.fixingUp)
1150 resetTimeline(hData);
1151 if (!vData.fixingUp)
1152 resetTimeline(vData);
1156 hData.dragMinBound = q->minXExtent() - hData.startMargin;
1157 vData.dragMinBound = q->minYExtent() - vData.startMargin;
1158 hData.dragMaxBound = q->maxXExtent() + hData.endMargin;
1159 vData.dragMaxBound = q->maxYExtent() + vData.endMargin;
1161 lastPos = QPointF();
1162 pressPos = pressPosn;
1163 hData.pressPos = hData.move.value();
1164 vData.pressPos = vData.move.value();
1165 const bool wasFlicking = hData.flicking || vData.flicking;
1166 hData.flickingWhenDragBegan = hData.flicking;
1167 vData.flickingWhenDragBegan = vData.flicking;
1168 if (hData.flicking) {
1169 hData.flicking =
false;
1170 emit q->flickingHorizontallyChanged();
1172 if (vData.flicking) {
1173 vData.flicking =
false;
1174 emit q->flickingVerticallyChanged();
1177 emit q->flickingChanged();
1178 lastPosTime = lastPressTime = currentTimestamp;
1179 vData.velocityTime.start();
1180 hData.velocityTime.start();
1183void QQuickFlickablePrivate::drag(qint64 currentTimestamp, QEvent::Type eventType,
const QPointF &localPos,
1184 const QVector2D &deltas,
bool overThreshold,
bool momentum,
1185 bool velocitySensitiveOverBounds,
const QVector2D &velocity)
1187 Q_Q(QQuickFlickable);
1188 bool rejectY =
false;
1189 bool rejectX =
false;
1191 bool keepY = q->yflick();
1192 bool keepX = q->xflick();
1194 bool stealY =
false;
1195 bool stealX =
false;
1196 if (eventType == QEvent::MouseMove) {
1197 stealX = stealY = stealMouse;
1198 }
else if (eventType == QEvent::Wheel) {
1199 stealX = stealY = scrollingPhase;
1202 bool prevHMoved = hMoved;
1203 bool prevVMoved = vMoved;
1205 qint64 elapsedSincePress = currentTimestamp - lastPressTime;
1206 qCDebug(lcFlickable).nospace() << currentTimestamp <<
' ' << eventType <<
" drag @ " << localPos.x() <<
',' << localPos.y()
1207 <<
" \u0394 " << deltas.x() <<
',' << deltas.y() <<
" vel " << velocity.x() <<
',' << velocity.y()
1208 <<
" thrsld? " << overThreshold <<
" momentum? " << momentum <<
" velSens? " << velocitySensitiveOverBounds
1209 <<
" sincePress " << elapsedSincePress;
1212 qreal dy = deltas.y();
1213 if (overThreshold || elapsedSincePress > 200) {
1214 if (!vMoved && !vData.dragging)
1215 vData.dragStartOffset = dy;
1216 qreal newY = dy + vData.pressPos - (syncDrag ? 0 : vData.dragStartOffset);
1220 const qreal minY = vData.dragMinBound + vData.startMargin;
1221 const qreal maxY = vData.dragMaxBound - vData.endMargin;
1222 if (!(boundsBehavior & QQuickFlickable::DragOverBounds)) {
1223 if (fuzzyLessThanOrEqualTo(newY, maxY)) {
1225 rejectY = vData.pressPos == maxY && vData.move.value() == maxY && dy < 0;
1227 if (fuzzyLessThanOrEqualTo(minY, newY)) {
1229 rejectY |= vData.pressPos == minY && vData.move.value() == minY && dy > 0;
1233 if (vel > 0. && vel > vData.velocity)
1235 else if (vel < 0. && vel < vData.velocity)
1239 if (momentum && vData.atBeginning) {
1240 if (!vData.inRebound) {
1241 vData.inRebound =
true;
1242 q->returnToBounds();
1246 if (velocitySensitiveOverBounds) {
1249 newY = minY + overshoot;
1251 newY = minY + (newY - minY) / 2;
1253 }
else if (newY < maxY && maxY - minY <= 0) {
1255 if (momentum && vData.atEnd) {
1256 if (!vData.inRebound) {
1257 vData.inRebound =
true;
1258 q->returnToBounds();
1262 if (velocitySensitiveOverBounds) {
1265 newY = maxY - overshoot;
1267 newY = maxY + (newY - maxY) / 2;
1271 if (!rejectY && stealMouse && dy != vData.previousDragDelta) {
1273 vData.move.setValue(newY);
1276 if (!rejectY && overThreshold)
1279 if ((newY >= minY && vData.pressPos == minY && vData.move.value() == minY && dy > 0)
1280 || (newY <= maxY && vData.pressPos == maxY && vData.move.value() == maxY && dy < 0)) {
1284 vData.previousDragDelta = dy;
1288 qreal dx = deltas.x();
1289 if (overThreshold || elapsedSincePress > 200) {
1290 if (!hMoved && !hData.dragging)
1291 hData.dragStartOffset = dx;
1292 qreal newX = dx + hData.pressPos - (syncDrag ? 0 : hData.dragStartOffset);
1293 const qreal minX = hData.dragMinBound + hData.startMargin;
1294 const qreal maxX = hData.dragMaxBound - hData.endMargin;
1295 if (!(boundsBehavior & QQuickFlickable::DragOverBounds)) {
1296 if (fuzzyLessThanOrEqualTo(newX, maxX)) {
1298 rejectX = hData.pressPos == maxX && hData.move.value() == maxX && dx < 0;
1300 if (fuzzyLessThanOrEqualTo(minX, newX)) {
1302 rejectX |= hData.pressPos == minX && hData.move.value() == minX && dx > 0;
1306 if (vel > 0. && vel > hData.velocity)
1308 else if (vel < 0. && vel < hData.velocity)
1312 if (momentum && hData.atBeginning) {
1313 if (!hData.inRebound) {
1314 hData.inRebound =
true;
1315 q->returnToBounds();
1319 if (velocitySensitiveOverBounds) {
1322 newX = minX + overshoot;
1324 newX = minX + (newX - minX) / 2;
1326 }
else if (newX < maxX && maxX - minX <= 0) {
1328 if (momentum && hData.atEnd) {
1329 if (!hData.inRebound) {
1330 hData.inRebound =
true;
1331 q->returnToBounds();
1335 if (velocitySensitiveOverBounds) {
1338 newX = maxX - overshoot;
1340 newX = maxX + (newX - maxX) / 2;
1344 if (!rejectX && stealMouse && dx != hData.previousDragDelta) {
1346 hData.move.setValue(newX);
1350 if (!rejectX && overThreshold)
1353 if ((newX >= minX && vData.pressPos == minX && vData.move.value() == minX && dx > 0)
1354 || (newX <= maxX && vData.pressPos == maxX && vData.move.value() == maxX && dx < 0)) {
1358 hData.previousDragDelta = dx;
1361 stealMouse = stealX || stealY;
1363 if ((stealX && keepX) || (stealY && keepY))
1364 q->setKeepMouseGrab(
true);
1365 clearDelayedPress();
1369 vData.velocityBuffer.clear();
1373 hData.velocityBuffer.clear();
1377 if (momentum && !hData.flicking && !vData.flicking)
1378 flickingStarted(hData.velocity != 0, vData.velocity != 0);
1381 if ((hMoved && !prevHMoved) || (vMoved && !prevVMoved))
1382 q->movementStarting();
1384 lastPosTime = currentTimestamp;
1385 if (q->yflick() && !rejectY)
1386 vData.addVelocitySample(velocity.y(), maxVelocity);
1387 if (q->xflick() && !rejectX)
1388 hData.addVelocitySample(velocity.x(), maxVelocity);
1392void QQuickFlickablePrivate::handleMoveEvent(QPointerEvent *event)
1394 Q_Q(QQuickFlickable);
1395 if (!interactive || lastPosTime == -1 ||
1396 (event->isSinglePointEvent() && !buttonsAccepted(
static_cast<QSinglePointEvent *>(event))))
1399 qint64 currentTimestamp = computeCurrentTime(event);
1400 const auto &firstPoint = event->points().first();
1401 const auto &pos = firstPoint.position();
1402 const QVector2D deltas = QVector2D(pos - q->mapFromGlobal(firstPoint.globalPressPosition()));
1403 const QVector2D velocity = firstPointLocalVelocity(event);
1404 bool overThreshold =
false;
1406 if (q->isMoving()) {
1408
1409
1410
1411
1412
1413
1414
1415 overThreshold =
true;
1416 }
else if (event->pointCount() == 1) {
1418 overThreshold |= QQuickDeliveryAgentPrivate::dragOverThreshold(deltas.y(), Qt::YAxis, firstPoint);
1420 overThreshold |= QQuickDeliveryAgentPrivate::dragOverThreshold(deltas.x(), Qt::XAxis, firstPoint);
1422 qCDebug(lcFilter) << q->objectName() <<
"ignoring multi-touch" << event;
1425 drag(currentTimestamp, event->type(), pos, deltas, overThreshold,
false,
false, velocity);
1428void QQuickFlickablePrivate::handleReleaseEvent(QPointerEvent *event)
1430 Q_Q(QQuickFlickable);
1432 q->setKeepMouseGrab(
false);
1436 qint64 elapsed = computeCurrentTime(event) - lastPosTime;
1438 vData.updateVelocity();
1439 hData.updateVelocity();
1443 if (lastPosTime == -1)
1446 hData.vTime = vData.vTime = timeline.time();
1448 bool canBoost =
false;
1449 const auto pos = event->points().first().position();
1450 const auto pressPos = q->mapFromGlobal(event->points().first().globalPressPosition());
1451 const QVector2D eventVelocity = firstPointLocalVelocity(event);
1452 qCDebug(lcVel) << event->deviceType() << event->type() <<
"velocity" << event->points().first().velocity() <<
"transformed to local" << eventVelocity;
1454 qreal vVelocity = 0;
1455 if (elapsed < 100 && vData.velocity != 0.) {
1456 vVelocity = (event->device()->capabilities().testFlag(QInputDevice::Capability::Velocity)
1457 ? eventVelocity.y() : vData.velocity);
1459 if ((vData.atBeginning && vVelocity > 0.) || (vData.atEnd && vVelocity < 0.)) {
1461 }
else if (vData.continuousFlickVelocity != 0.0
1463 && ((vVelocity > 0) == (vData.continuousFlickVelocity > 0))
1469 qreal hVelocity = 0;
1470 if (elapsed < 100 && hData.velocity != 0.) {
1471 hVelocity = (event->device()->capabilities().testFlag(QInputDevice::Capability::Velocity)
1472 ? eventVelocity.x() : hData.velocity);
1474 if ((hData.atBeginning && hVelocity > 0.) || (hData.atEnd && hVelocity < 0.)) {
1476 }
else if (hData.continuousFlickVelocity != 0.0
1478 && ((hVelocity > 0) == (hData.continuousFlickVelocity > 0))
1485 const int flickThreshold = QGuiApplicationPrivate::platformTheme()->themeHint(QPlatformTheme::FlickStartDistance).toInt();
1487 bool anyPointGrabbed = event->points().constEnd() !=
1488 std::find_if(event->points().constBegin(),event->points().constEnd(),
1489 [q, event](
const QEventPoint &point) {
return event->exclusiveGrabber(point) == q; });
1491 bool flickedVertically =
false;
1492 vVelocity *= flickBoost;
1493 const bool isVerticalFlickAllowed = anyPointGrabbed &&
1494 q->yflick() && qAbs(vVelocity) > _q_MinimumFlickVelocity &&
1495 qAbs(pos.y() - pressPos.y()) > flickThreshold;
1496 if (isVerticalFlickAllowed) {
1497 velocityTimeline.reset(vData.smoothVelocity);
1498 vData.smoothVelocity.setValue(-vVelocity);
1499 flickedVertically = flickY(event->type(), vVelocity);
1502 bool flickedHorizontally =
false;
1503 hVelocity *= flickBoost;
1504 const bool isHorizontalFlickAllowed = anyPointGrabbed &&
1505 q->xflick() && qAbs(hVelocity) > _q_MinimumFlickVelocity &&
1506 qAbs(pos.x() - pressPos.x()) > flickThreshold;
1507 if (isHorizontalFlickAllowed) {
1508 velocityTimeline.reset(hData.smoothVelocity);
1509 hData.smoothVelocity.setValue(-hVelocity);
1510 flickedHorizontally = flickX(event->type(), hVelocity);
1513 if (!isVerticalFlickAllowed)
1516 if (!isHorizontalFlickAllowed)
1519 flickingStarted(flickedHorizontally, flickedVertically);
1520 if (!isViewMoving()) {
1521 q->movementEnding();
1523 if (flickedVertically)
1525 if (flickedHorizontally)
1527 q->movementStarting();
1531bool QQuickFlickablePrivate::buttonsAccepted(
const QSinglePointEvent *event)
1533 return !((event->button() & acceptedButtons) == 0 && (event->buttons() & acceptedButtons) == 0);
1536void QQuickFlickable::mousePressEvent(QMouseEvent *event)
1538 Q_D(QQuickFlickable);
1539 if (d->interactive && !d->replayingPressEvent && d->buttonsAccepted(event) && d->wantsPointerEvent(event)) {
1541 d->handlePressEvent(event);
1544 QQuickItem::mousePressEvent(event);
1548void QQuickFlickable::mouseMoveEvent(QMouseEvent *event)
1550 Q_D(QQuickFlickable);
1551 if (d->interactive && d->buttonsAccepted(event) && d->wantsPointerEvent(event)) {
1552 d->handleMoveEvent(event);
1555 QQuickItem::mouseMoveEvent(event);
1559void QQuickFlickable::mouseReleaseEvent(QMouseEvent *event)
1561 Q_D(QQuickFlickable);
1562 if (d->interactive && d->buttonsAccepted(event) && d->wantsPointerEvent(event)) {
1563 if (d->delayedPressEvent) {
1564 d->replayDelayedPress();
1566 auto &firstPoint = event->point(0);
1567 if (
const auto *grabber = event->exclusiveGrabber(firstPoint); grabber && grabber->isQuickItemType()) {
1570 const auto oldPosition = firstPoint.position();
1571 QMutableEventPoint::setPosition(firstPoint, event->scenePosition());
1572 QCoreApplication::sendEvent(window(), event);
1573 QMutableEventPoint::setPosition(firstPoint, oldPosition);
1577 d->stealMouse =
false;
1582 d->handleReleaseEvent(event);
1585 QQuickItem::mouseReleaseEvent(event);
1589void QQuickFlickable::touchEvent(QTouchEvent *event)
1591 Q_D(QQuickFlickable);
1593 if (event->type() == QEvent::TouchCancel) {
1594 if (d->interactive && d->wantsPointerEvent(event))
1595 d->cancelInteraction();
1597 QQuickItem::touchEvent(event);
1601 bool unhandled =
false;
1602 const auto &firstPoint = event->points().first();
1603 switch (firstPoint.state()) {
1604 case QEventPoint::State::Pressed:
1605 if (d->interactive && !d->replayingPressEvent && d->wantsPointerEvent(event)) {
1607 d->handlePressEvent(event);
1613 case QEventPoint::State::Updated:
1614 if (d->interactive && d->wantsPointerEvent(event)) {
1615 d->handleMoveEvent(event);
1621 case QEventPoint::State::Released:
1622 if (d->interactive && d->wantsPointerEvent(event)) {
1623 if (d->delayedPressEvent) {
1624 d->replayDelayedPress();
1626 const auto &firstPoint = event->point(0);
1627 if (
const auto *grabber = event->exclusiveGrabber(firstPoint); grabber && grabber->isQuickItemType()) {
1629 QScopedPointer<QPointerEvent> localizedEvent(
1630 QQuickDeliveryAgentPrivate::clonePointerEvent(event, firstPoint.scenePosition()));
1631 QCoreApplication::sendEvent(window(), localizedEvent.data());
1635 d->stealMouse =
false;
1640 d->handleReleaseEvent(event);
1646 case QEventPoint::State::Stationary:
1647 case QEventPoint::State::Unknown:
1651 QQuickItem::touchEvent(event);
1654#if QT_CONFIG(wheelevent)
1655void QQuickFlickable::wheelEvent(QWheelEvent *event)
1657 Q_D(QQuickFlickable);
1658 if (!d->interactive || !d->wantsPointerEvent(event)) {
1659 QQuickItem::wheelEvent(event);
1662 qCDebug(lcWheel) << event->device() << event << event->source();
1663 event->setAccepted(
false);
1664 qint64 currentTimestamp = d->computeCurrentTime(event);
1665 switch (event->phase()) {
1666 case Qt::ScrollBegin:
1667 d->scrollingPhase =
true;
1668 d->accumulatedWheelPixelDelta = QVector2D();
1669 d->vData.velocity = 0;
1670 d->hData.velocity = 0;
1672 d->maybeBeginDrag(currentTimestamp, event->position());
1673 d->lastPosTime = -1;
1675 case Qt::NoScrollPhase:
1676 case Qt::ScrollUpdate:
1677 if (d->scrollingPhase)
1680 case Qt::ScrollMomentum:
1682 d->scrollingPhase =
false;
1683 d->draggingEnding();
1686 d->lastPosTime = -1;
1690 d->scrollingPhase =
false;
1691 d->draggingEnding();
1693 d->lastPosTime = -1;
1694 d->stealMouse =
false;
1695 if (!d->velocityTimeline.isActive() && !d->timeline.isActive())
1696 movementEnding(
true,
true);
1700 qreal elapsed = qreal(currentTimestamp - d->lastPosTime) / qreal(1000);
1702 d->lastPosTime = currentTimestamp;
1703 qCDebug(lcWheel) <<
"insufficient elapsed time: can't calculate velocity" << elapsed;
1707 if (event->source() == Qt::MouseEventNotSynthesized || event->pixelDelta().isNull() || event->phase() == Qt::NoScrollPhase) {
1709 int xDelta = event->angleDelta().x();
1710 int yDelta = event->angleDelta().y();
1712 if (d->wheelDeceleration > _q_MaximumWheelDeceleration) {
1713 const qreal wheelScroll = -qApp->styleHints()->wheelScrollLines() * 24;
1716 if (yflick() && yDelta != 0) {
1717 d->moveReason = QQuickFlickablePrivate::Mouse;
1719 qreal scrollPixel = (-yDelta / 120.0 * wheelScroll);
1720 bool acceptEvent =
true;
1721 if (scrollPixel > 0) {
1722 if (d->vData.move.value() >= minYExtent()) {
1724 acceptEvent =
false;
1727 if (d->vData.move.value() <= maxYExtent()) {
1729 acceptEvent =
false;
1733 if (d->boundsBehavior == QQuickFlickable::StopAtBounds) {
1734 const qreal estContentPos = scrollPixel + d->vData.move.value();
1735 if (scrollPixel > 0) {
1736 if (estContentPos > minYExtent()) {
1737 scrollPixel = minYExtent() - d->vData.move.value();
1738 acceptEvent =
false;
1741 if (estContentPos < maxYExtent()) {
1742 scrollPixel = maxYExtent() - d->vData.move.value();
1743 acceptEvent =
false;
1747 d->resetTimeline(d->vData);
1749 d->timeline.moveBy(d->vData.move, scrollPixel, QEasingCurve(QEasingCurve::OutExpo), 3*d->fixupDuration/4);
1750 d->vData.fixingUp =
true;
1751 d->timeline.callback(QQuickTimeLineCallback(&d->vData.move, QQuickFlickablePrivate::fixupY_callback, d));
1756 if (xflick() && xDelta != 0) {
1757 d->moveReason = QQuickFlickablePrivate::Mouse;
1759 qreal scrollPixel = (-xDelta / 120.0 * wheelScroll);
1760 bool acceptEvent =
true;
1761 if (scrollPixel > 0) {
1762 if (d->hData.move.value() >= minXExtent()) {
1764 acceptEvent =
false;
1767 if (d->hData.move.value() <= maxXExtent()) {
1769 acceptEvent =
false;
1773 if (d->boundsBehavior == QQuickFlickable::StopAtBounds) {
1774 const qreal estContentPos = scrollPixel + d->hData.move.value();
1775 if (scrollPixel > 0) {
1776 if (estContentPos > minXExtent()) {
1777 scrollPixel = minXExtent() - d->hData.move.value();
1778 acceptEvent =
false;
1781 if (estContentPos < maxXExtent()) {
1782 scrollPixel = maxXExtent() - d->hData.move.value();
1783 acceptEvent =
false;
1787 d->resetTimeline(d->hData);
1789 d->timeline.moveBy(d->hData.move, scrollPixel, QEasingCurve(QEasingCurve::OutExpo), 3*d->fixupDuration/4);
1790 d->hData.fixingUp =
true;
1791 d->timeline.callback(QQuickTimeLineCallback(&d->hData.move, QQuickFlickablePrivate::fixupX_callback, d));
1807 elapsed = 120 / qSqrt(d->wheelDeceleration * 2 * d->initialWheelFlickDistance);
1808 if (yflick() && yDelta != 0) {
1809 qreal instVelocity = yDelta / elapsed;
1811 if ((instVelocity < 0 && d->vData.velocity > 0) || (instVelocity > 0 && d->vData.velocity < 0))
1812 d->vData.velocityBuffer.clear();
1813 d->vData.addVelocitySample(instVelocity, d->maxVelocity);
1814 d->vData.updateVelocity();
1815 if ((yDelta > 0 && contentY() > -minYExtent()) || (yDelta < 0 && contentY() < -maxYExtent())) {
1816 const bool newFlick = d->flickY(event->type(), d->vData.velocity);
1817 if (newFlick && (d->vData.atBeginning != (yDelta > 0) || d->vData.atEnd != (yDelta < 0))) {
1818 d->flickingStarted(
false,
true);
1825 if (xflick() && xDelta != 0) {
1826 qreal instVelocity = xDelta / elapsed;
1828 if ((instVelocity < 0 && d->hData.velocity > 0) || (instVelocity > 0 && d->hData.velocity < 0))
1829 d->hData.velocityBuffer.clear();
1830 d->hData.addVelocitySample(instVelocity, d->maxVelocity);
1831 d->hData.updateVelocity();
1832 if ((xDelta > 0 && contentX() > -minXExtent()) || (xDelta < 0 && contentX() < -maxXExtent())) {
1833 const bool newFlick = d->flickX(event->type(), d->hData.velocity);
1834 if (newFlick && (d->hData.atBeginning != (xDelta > 0) || d->hData.atEnd != (xDelta < 0))) {
1835 d->flickingStarted(
true,
false);
1845 int xDelta = event->pixelDelta().x();
1846 int yDelta = event->pixelDelta().y();
1848 QVector2D velocity(xDelta / elapsed, yDelta / elapsed);
1849 d->accumulatedWheelPixelDelta += QVector2D(event->pixelDelta());
1855 if (isMoving() || isFlicking() || (yflick() && xflick())
1856 || (xflick() && qAbs(d->accumulatedWheelPixelDelta.x()) > qAbs(d->accumulatedWheelPixelDelta.y() * 2))
1857 || (yflick() && qAbs(d->accumulatedWheelPixelDelta.y()) > qAbs(d->accumulatedWheelPixelDelta.x() * 2))) {
1858 d->drag(currentTimestamp, event->type(), event->position(), d->accumulatedWheelPixelDelta,
1859 true, !d->scrollingPhase,
true, velocity);
1860 d->updateBeginningEnd();
1861 if ((xflick() && !isAtXBeginning() && !isAtXEnd()) || (yflick() && !isAtYBeginning() && !isAtYEnd()))
1864 qCDebug(lcWheel) <<
"not dragging: accumulated deltas" << d->accumulatedWheelPixelDelta <<
1865 "moving?" << isMoving() <<
"can flick horizontally?" << xflick() <<
"vertically?" << yflick();
1868 d->lastPosTime = currentTimestamp;
1870 if (!event->isAccepted())
1871 QQuickItem::wheelEvent(event);
1875bool QQuickFlickablePrivate::isInnermostPressDelay(QQuickItem *i)
const
1877 Q_Q(
const QQuickFlickable);
1878 QQuickItem *item = i;
1880 QQuickFlickable *flick = qobject_cast<QQuickFlickable*>(item);
1881 if (flick && flick->pressDelay() > 0 && flick->isInteractive()) {
1883 return (flick == q);
1885 item = item->parentItem();
1890void QQuickFlickablePrivate::captureDelayedPress(QQuickItem *item, QPointerEvent *event)
1892 Q_Q(QQuickFlickable);
1893 if (!q->window() || pressDelay <= 0)
1898 if (!isInnermostPressDelay(item))
1901 delayedPressEvent = QQuickDeliveryAgentPrivate::clonePointerEvent(event);
1902 delayedPressEvent->setAccepted(
false);
1903 delayedPressTimer.start(pressDelay, q);
1904 qCDebug(lcReplay) <<
"begin press delay" << pressDelay <<
"ms with" << delayedPressEvent;
1907void QQuickFlickablePrivate::clearDelayedPress()
1909 if (delayedPressEvent) {
1910 delayedPressTimer.stop();
1911 qCDebug(lcReplay) <<
"clear delayed press" << delayedPressEvent;
1912 delete delayedPressEvent;
1913 delayedPressEvent =
nullptr;
1917void QQuickFlickablePrivate::replayDelayedPress()
1919 Q_Q(QQuickFlickable);
1920 if (delayedPressEvent) {
1922 QScopedPointer<QPointerEvent> event(delayedPressEvent);
1923 delayedPressEvent =
nullptr;
1924 delayedPressTimer.stop();
1927 if (QQuickWindow *window = q->window()) {
1928 auto da = deliveryAgentPrivate();
1929 da->allowChildEventFiltering =
false;
1930 replayingPressEvent =
true;
1931 auto &firstPoint = event->point(0);
1937 if (event->exclusiveGrabber(firstPoint) == q)
1938 event->setExclusiveGrabber(firstPoint,
nullptr);
1940 qCDebug(lcReplay) <<
"replaying" << event.data();
1943 QMutableEventPoint::setPosition(firstPoint, firstPoint.scenePosition());
1947 QCoreApplication::sendEvent(window, event.data());
1948 qCDebug(lcReplay) <<
"replay done";
1951 replayingPressEvent =
false;
1952 da->allowChildEventFiltering =
true;
1960
1961
1962
1963
1964
1965
1966
1967void QQuickFlickablePrivate::setViewportX(qreal x)
1969 Q_Q(QQuickFlickable);
1970 qreal effectiveX = pixelAligned ? -std::round(-x) : x;
1972 const qreal maxX = q->maxXExtent();
1973 const qreal minX = q->minXExtent();
1975 if (boundsMovement ==
int(QQuickFlickable::StopAtBounds))
1976 effectiveX = qBound(maxX, effectiveX, minX);
1978 contentItem->setX(effectiveX);
1979 if (contentItem->x() != effectiveX)
1982 qreal overshoot = 0.0;
1984 overshoot = maxX - x;
1986 overshoot = minX - x;
1988 if (overshoot != hData.overshoot) {
1989 hData.overshoot = overshoot;
1990 emit q->horizontalOvershootChanged();
1995
1996
1997
1998
1999
2000
2001
2002void QQuickFlickablePrivate::setViewportY(qreal y)
2004 Q_Q(QQuickFlickable);
2005 qreal effectiveY = pixelAligned ? -std::round(-y) : y;
2007 const qreal maxY = q->maxYExtent();
2008 const qreal minY = q->minYExtent();
2010 if (boundsMovement ==
int(QQuickFlickable::StopAtBounds))
2011 effectiveY = qBound(maxY, effectiveY, minY);
2013 contentItem->setY(effectiveY);
2014 if (contentItem->y() != effectiveY)
2017 qreal overshoot = 0.0;
2019 overshoot = maxY - y;
2021 overshoot = minY - y;
2023 if (overshoot != vData.overshoot) {
2024 vData.overshoot = overshoot;
2025 emit q->verticalOvershootChanged();
2029void QQuickFlickable::timerEvent(QTimerEvent *event)
2031 Q_D(QQuickFlickable);
2032 if (event->timerId() == d->delayedPressTimer.timerId()) {
2033 d->delayedPressTimer.stop();
2034 if (d->delayedPressEvent) {
2035 d->replayDelayedPress();
2040qreal QQuickFlickable::minYExtent()
const
2042 Q_D(
const QQuickFlickable);
2043 return d->vData.startMargin;
2046qreal QQuickFlickable::minXExtent()
const
2048 Q_D(
const QQuickFlickable);
2049 return d->hData.startMargin;
2053qreal QQuickFlickable::maxXExtent()
const
2055 Q_D(
const QQuickFlickable);
2056 return qMin<qreal>(minXExtent(), width() - vWidth() - d->hData.endMargin);
2059qreal QQuickFlickable::maxYExtent()
const
2061 Q_D(
const QQuickFlickable);
2062 return qMin<qreal>(minYExtent(), height() - vHeight() - d->vData.endMargin);
2065void QQuickFlickable::componentComplete()
2067 Q_D(QQuickFlickable);
2068 QQuickItem::componentComplete();
2069 if (!d->hData.explicitValue && d->hData.startMargin != 0.)
2070 setContentX(-minXExtent());
2071 if (!d->vData.explicitValue && d->vData.startMargin != 0.)
2072 setContentY(-minYExtent());
2073 if (lcWheel().isDebugEnabled() || lcVel().isDebugEnabled()) {
2074 d->timeline.setObjectName(QLatin1String(
"timeline for Flickable ") + objectName());
2075 d->velocityTimeline.setObjectName(QLatin1String(
"velocity timeline for Flickable ") + objectName());
2079void QQuickFlickable::viewportMoved(Qt::Orientations orient)
2081 Q_D(QQuickFlickable);
2082 if (orient & Qt::Vertical)
2083 d->viewportAxisMoved(d->vData, minYExtent(), maxYExtent(), d->fixupY_callback);
2084 if (orient & Qt::Horizontal)
2085 d->viewportAxisMoved(d->hData, minXExtent(), maxXExtent(), d->fixupX_callback);
2086 d->updateBeginningEnd();
2089void QQuickFlickablePrivate::viewportAxisMoved(AxisData &data, qreal minExtent, qreal maxExtent,
2090 QQuickTimeLineCallback::Callback fixupCallback)
2092 if (!scrollingPhase && (pressed || calcVelocity)) {
2093 int elapsed = data.velocityTime.restart();
2095 qreal velocity = (data.lastPos - data.move.value()) * 1000 / elapsed;
2096 if (qAbs(velocity) > 0) {
2097 velocityTimeline.reset(data.smoothVelocity);
2098 velocityTimeline.set(data.smoothVelocity, velocity);
2099 qCDebug(lcVel) <<
"touchpad scroll phase: velocity" << velocity;
2103 if (timeline.time() > data.vTime) {
2104 velocityTimeline.reset(data.smoothVelocity);
2105 int dt = timeline.time() - data.vTime;
2107 qreal velocity = (data.lastPos - data.move.value()) * 1000 / dt;
2108 if (!qFuzzyCompare(data.smoothVelocity.value(), velocity))
2109 qCDebug(lcVel) <<
"velocity" << data.smoothVelocity.value() <<
"->" << velocity
2110 <<
"computed as (" << data.lastPos <<
"-" << data.move.value() <<
") * 1000 / ("
2111 << timeline.time() <<
"-" << data.vTime <<
")";
2112 data.smoothVelocity.setValue(velocity);
2117 if (!data.inOvershoot && !data.fixingUp && data.flicking
2118 && (data.move.value() > minExtent || data.move.value() < maxExtent)
2119 && qAbs(data.smoothVelocity.value()) > 10) {
2121 qreal overBound = data.move.value() > minExtent
2122 ? data.move.value() - minExtent
2123 : maxExtent - data.move.value();
2124 data.inOvershoot =
true;
2125 qreal maxDistance = overShootDistance(qAbs(data.smoothVelocity.value())) - overBound;
2126 resetTimeline(data);
2127 if (maxDistance > 0)
2129 timeline.callback(QQuickTimeLineCallback(&data.move, fixupCallback,
this));
2132 data.lastPos = data.move.value();
2133 data.vTime = timeline.time();
2136void QQuickFlickable::geometryChange(
const QRectF &newGeometry,
const QRectF &oldGeometry)
2138 Q_D(QQuickFlickable);
2139 QQuickItem::geometryChange(newGeometry, oldGeometry);
2141 bool changed =
false;
2142 if (newGeometry.width() != oldGeometry.width()) {
2144 if (d->hData.viewSize < 0)
2145 d->contentItem->setWidth(width() - d->hData.startMargin - d->hData.endMargin);
2147 if (!d->pressed && !d->hData.moving && !d->vData.moving) {
2148 d->fixupMode = QQuickFlickablePrivate::Immediate;
2152 if (newGeometry.height() != oldGeometry.height()) {
2154 if (d->vData.viewSize < 0)
2155 d->contentItem->setHeight(height() - d->vData.startMargin - d->vData.endMargin);
2157 if (!d->pressed && !d->hData.moving && !d->vData.moving) {
2158 d->fixupMode = QQuickFlickablePrivate::Immediate;
2164 d->updateBeginningEnd();
2168
2169
2170
2171
2172
2173
2174
2176void QQuickFlickable::flick(qreal xVelocity, qreal yVelocity)
2178 Q_D(QQuickFlickable);
2181 d->hData.velocity = xVelocity;
2182 d->vData.velocity = yVelocity;
2183 d->hData.vTime = d->vData.vTime = d->timeline.time();
2185 const bool flickedX = xflick() && !qFuzzyIsNull(xVelocity) && d->flickX(QEvent::TouchUpdate, xVelocity);
2186 const bool flickedY = yflick() && !qFuzzyIsNull(yVelocity) && d->flickY(QEvent::TouchUpdate, yVelocity);
2193 d->flickingStarted(flickedX, flickedY);
2196void QQuickFlickablePrivate::flickingStarted(
bool flickingH,
bool flickingV)
2198 Q_Q(QQuickFlickable);
2199 if (!flickingH && !flickingV)
2202 bool wasFlicking = hData.flicking || vData.flicking;
2203 if (flickingH && !hData.flicking) {
2204 hData.flicking =
true;
2205 emit q->flickingHorizontallyChanged();
2207 if (flickingV && !vData.flicking) {
2208 vData.flicking =
true;
2209 emit q->flickingVerticallyChanged();
2211 if (!wasFlicking && (hData.flicking || vData.flicking)) {
2212 emit q->flickingChanged();
2213 emit q->flickStarted();
2218
2219
2220
2221
2223void QQuickFlickable::cancelFlick()
2225 Q_D(QQuickFlickable);
2226 d->resetTimeline(d->hData);
2227 d->resetTimeline(d->vData);
2231void QQuickFlickablePrivate::data_append(QQmlListProperty<QObject> *prop, QObject *o)
2233 if (!prop || !prop->data)
2236 if (QQuickItem *i = qmlobject_cast<QQuickItem *>(o)) {
2237 i->setParentItem(
static_cast<QQuickFlickablePrivate*>(prop->data)->contentItem);
2238 }
else if (QQuickPointerHandler *pointerHandler = qmlobject_cast<QQuickPointerHandler *>(o)) {
2239 static_cast<QQuickFlickablePrivate*>(prop->data)->addPointerHandler(pointerHandler);
2241 o->setParent(prop->object);
2245qsizetype QQuickFlickablePrivate::data_count(QQmlListProperty<QObject> *)
2251QObject *QQuickFlickablePrivate::data_at(QQmlListProperty<QObject> *, qsizetype)
2257void QQuickFlickablePrivate::data_clear(QQmlListProperty<QObject> *)
2262QQmlListProperty<QObject> QQuickFlickable::flickableData()
2264 Q_D(QQuickFlickable);
2265 return QQmlListProperty<QObject>(
this, (
void *)d, QQuickFlickablePrivate::data_append,
2266 QQuickFlickablePrivate::data_count,
2267 QQuickFlickablePrivate::data_at,
2268 QQuickFlickablePrivate::data_clear);
2271QQmlListProperty<QQuickItem> QQuickFlickable::flickableChildren()
2273 Q_D(QQuickFlickable);
2274 return QQuickItemPrivate::get(d->contentItem)->children();
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303QQuickFlickable::BoundsBehavior QQuickFlickable::boundsBehavior()
const
2305 Q_D(
const QQuickFlickable);
2306 return d->boundsBehavior;
2309void QQuickFlickable::setBoundsBehavior(BoundsBehavior b)
2311 Q_D(QQuickFlickable);
2312 if (b == d->boundsBehavior)
2314 d->boundsBehavior = b;
2315 emit boundsBehaviorChanged();
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358QQuickTransition *QQuickFlickable::rebound()
const
2360 Q_D(
const QQuickFlickable);
2364void QQuickFlickable::setRebound(QQuickTransition *transition)
2366 Q_D(QQuickFlickable);
2368 if (!d->hData.transitionToBounds)
2369 d->hData.transitionToBounds =
new QQuickFlickableReboundTransition(
this, QLatin1String(
"x"));
2370 if (!d->vData.transitionToBounds)
2371 d->vData.transitionToBounds =
new QQuickFlickableReboundTransition(
this, QLatin1String(
"y"));
2373 if (d->rebound != transition) {
2374 d->rebound = transition;
2375 emit reboundChanged();
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403qreal QQuickFlickable::contentWidth()
const
2405 Q_D(
const QQuickFlickable);
2406 return d->hData.viewSize;
2409void QQuickFlickable::setContentWidth(qreal w)
2411 Q_D(QQuickFlickable);
2412 if (d->hData.viewSize == w)
2414 d->hData.viewSize = w;
2416 d->contentItem->setWidth(width() - d->hData.startMargin - d->hData.endMargin);
2418 d->contentItem->setWidth(w);
2419 d->hData.markExtentsDirty();
2421 if (!d->pressed && !d->hData.moving && !d->vData.moving) {
2422 d->fixupMode = QQuickFlickablePrivate::Immediate;
2424 }
else if (!d->pressed && d->hData.fixingUp) {
2425 d->fixupMode = QQuickFlickablePrivate::ExtentChanged;
2428 emit contentWidthChanged();
2429 d->updateBeginningEnd();
2432qreal QQuickFlickable::contentHeight()
const
2434 Q_D(
const QQuickFlickable);
2435 return d->vData.viewSize;
2438void QQuickFlickable::setContentHeight(qreal h)
2440 Q_D(QQuickFlickable);
2441 if (d->vData.viewSize == h)
2443 d->vData.viewSize = h;
2445 d->contentItem->setHeight(height() - d->vData.startMargin - d->vData.endMargin);
2447 d->contentItem->setHeight(h);
2448 d->vData.markExtentsDirty();
2450 if (!d->pressed && !d->hData.moving && !d->vData.moving) {
2451 d->fixupMode = QQuickFlickablePrivate::Immediate;
2453 }
else if (!d->pressed && d->vData.fixingUp) {
2454 d->fixupMode = QQuickFlickablePrivate::ExtentChanged;
2457 emit contentHeightChanged();
2458 d->updateBeginningEnd();
2462
2463
2464
2465
2466
2467
2468
2469
2472qreal QQuickFlickable::topMargin()
const
2474 Q_D(
const QQuickFlickable);
2475 return d->vData.startMargin;
2478void QQuickFlickable::setTopMargin(qreal m)
2480 Q_D(QQuickFlickable);
2481 if (d->vData.startMargin == m)
2483 d->vData.startMargin = m;
2484 d->vData.markExtentsDirty();
2485 if (!d->pressed && !d->hData.moving && !d->vData.moving) {
2487 d->fixupMode = QQuickFlickablePrivate::Immediate;
2490 emit topMarginChanged();
2491 d->updateBeginningEnd();
2494qreal QQuickFlickable::bottomMargin()
const
2496 Q_D(
const QQuickFlickable);
2497 return d->vData.endMargin;
2500void QQuickFlickable::setBottomMargin(qreal m)
2502 Q_D(QQuickFlickable);
2503 if (d->vData.endMargin == m)
2505 d->vData.endMargin = m;
2506 d->vData.markExtentsDirty();
2507 if (!d->pressed && !d->hData.moving && !d->vData.moving) {
2509 d->fixupMode = QQuickFlickablePrivate::Immediate;
2512 emit bottomMarginChanged();
2513 d->updateBeginningEnd();
2516qreal QQuickFlickable::leftMargin()
const
2518 Q_D(
const QQuickFlickable);
2519 return d->hData.startMargin;
2522void QQuickFlickable::setLeftMargin(qreal m)
2524 Q_D(QQuickFlickable);
2525 if (d->hData.startMargin == m)
2527 d->hData.startMargin = m;
2528 d->hData.markExtentsDirty();
2529 if (!d->pressed && !d->hData.moving && !d->vData.moving) {
2531 d->fixupMode = QQuickFlickablePrivate::Immediate;
2534 emit leftMarginChanged();
2535 d->updateBeginningEnd();
2538qreal QQuickFlickable::rightMargin()
const
2540 Q_D(
const QQuickFlickable);
2541 return d->hData.endMargin;
2544void QQuickFlickable::setRightMargin(qreal m)
2546 Q_D(QQuickFlickable);
2547 if (d->hData.endMargin == m)
2549 d->hData.endMargin = m;
2550 d->hData.markExtentsDirty();
2551 if (!d->pressed && !d->hData.moving && !d->vData.moving) {
2553 d->fixupMode = QQuickFlickablePrivate::Immediate;
2556 emit rightMarginChanged();
2557 d->updateBeginningEnd();
2561
2562
2563
2564
2565
2566
2567
2568
2569
2570
2571
2572
2574qreal QQuickFlickable::originY()
const
2576 Q_D(
const QQuickFlickable);
2577 return -minYExtent() + d->vData.startMargin;
2580qreal QQuickFlickable::originX()
const
2582 Q_D(
const QQuickFlickable);
2583 return -minXExtent() + d->hData.startMargin;
2588
2589
2590
2591
2592
2593
2594
2595
2596
2597
2598
2599void QQuickFlickable::resizeContent(qreal w, qreal h, QPointF center)
2601 Q_D(QQuickFlickable);
2602 const qreal oldHSize = d->hData.viewSize;
2603 const qreal oldVSize = d->vData.viewSize;
2604 const bool needToUpdateWidth = w != oldHSize;
2605 const bool needToUpdateHeight = h != oldVSize;
2606 d->hData.viewSize = w;
2607 d->vData.viewSize = h;
2608 d->contentItem->setSize(QSizeF(w, h));
2609 if (needToUpdateWidth)
2610 emit contentWidthChanged();
2611 if (needToUpdateHeight)
2612 emit contentHeightChanged();
2614 if (center.x() != 0) {
2615 qreal pos = center.x() * w / oldHSize;
2616 setContentX(contentX() + pos - center.x());
2618 if (center.y() != 0) {
2619 qreal pos = center.y() * h / oldVSize;
2620 setContentY(contentY() + pos - center.y());
2622 d->updateBeginningEnd();
2626
2627
2628
2629
2630
2631
2632
2633void QQuickFlickable::returnToBounds()
2635 Q_D(QQuickFlickable);
2640qreal QQuickFlickable::vWidth()
const
2642 Q_D(
const QQuickFlickable);
2643 if (d->hData.viewSize < 0)
2646 return d->hData.viewSize;
2649qreal QQuickFlickable::vHeight()
const
2651 Q_D(
const QQuickFlickable);
2652 if (d->vData.viewSize < 0)
2655 return d->vData.viewSize;
2659
2660
2661
2662
2663
2664
2665bool QQuickFlickable::xflick()
const
2667 Q_D(
const QQuickFlickable);
2668 const int contentWidthWithMargins = d->contentItem->width() + d->hData.startMargin + d->hData.endMargin;
2669 if ((d->flickableDirection & QQuickFlickable::AutoFlickIfNeeded) && (contentWidthWithMargins > width()))
2671 if (d->flickableDirection == QQuickFlickable::AutoFlickDirection)
2672 return std::floor(qAbs(contentWidthWithMargins - width()));
2673 return d->flickableDirection & QQuickFlickable::HorizontalFlick;
2677
2678
2679
2680
2681
2682
2683bool QQuickFlickable::yflick()
const
2685 Q_D(
const QQuickFlickable);
2686 const int contentHeightWithMargins = d->contentItem->height() + d->vData.startMargin + d->vData.endMargin;
2687 if ((d->flickableDirection & QQuickFlickable::AutoFlickIfNeeded) && (contentHeightWithMargins > height()))
2689 if (d->flickableDirection == QQuickFlickable::AutoFlickDirection)
2690 return std::floor(qAbs(contentHeightWithMargins - height()));
2691 return d->flickableDirection & QQuickFlickable::VerticalFlick;
2694void QQuickFlickable::mouseUngrabEvent()
2696 Q_D(QQuickFlickable);
2699 if (!d->replayingPressEvent)
2700 d->cancelInteraction();
2703void QQuickFlickablePrivate::cancelInteraction()
2705 Q_Q(QQuickFlickable);
2707 clearDelayedPress();
2711 q->setKeepMouseGrab(
false);
2714 if (!isViewMoving())
2715 q->movementEnding();
2719void QQuickFlickablePrivate::addPointerHandler(QQuickPointerHandler *h)
2721 Q_Q(
const QQuickFlickable);
2722 qCDebug(lcHandlerParent) <<
"reparenting handler" << h <<
"to contentItem of" << q;
2723 h->setParent(contentItem);
2724 QQuickItemPrivate::get(contentItem)->addPointerHandler(h);
2728
2729
2730
2731
2732
2733
2734
2735bool QQuickFlickable::filterPointerEvent(QQuickItem *receiver, QPointerEvent *event)
2737 Q_D(QQuickFlickable);
2738 const bool isTouch = QQuickDeliveryAgentPrivate::isTouchEvent(event);
2739 const bool isMouse = QQuickDeliveryAgentPrivate::isMouseEvent(event);
2740 if (isMouse || QQuickDeliveryAgentPrivate::isTabletEvent(event)) {
2741 if (!d->buttonsAccepted(
static_cast<QSinglePointEvent *>(event)))
2742 return QQuickItem::childMouseEventFilter(receiver, event);
2743 }
else if (!isTouch) {
2746 Q_ASSERT_X(receiver !=
this,
"",
"Flickable received a filter event for itself");
2748 if (isTouch &&
static_cast<QTouchEvent *>(event)->touchPointStates().testFlag(QEventPoint::State::Pressed))
2749 d->stealMouse =
false;
2751 if (event->pointCount() > 1) {
2752 qCDebug(lcFilter) << objectName() <<
"ignoring multi-touch" << event <<
"for" << receiver;
2753 d->stealMouse =
false;
2756 qCDebug(lcFilter) << objectName() <<
"filtering" << event <<
"for" << receiver;
2759 const auto &firstPoint = event->points().first();
2761 if (event->pointCount() == 1 && event->exclusiveGrabber(firstPoint) ==
this) {
2768 event->setAccepted(
true);
2772 QPointF localPos = mapFromScene(firstPoint.scenePosition());
2773 bool receiverDisabled = receiver && !receiver->isEnabled();
2774 bool stealThisEvent = d->stealMouse;
2775 bool receiverKeepsGrab = receiver && (receiver->keepMouseGrab() || receiver->keepTouchGrab());
2776 bool receiverRelinquishGrab =
false;
2779 if (
auto *mouseArea = qmlobject_cast<QQuickMouseArea *>(receiver)) {
2780 bool preventStealing = mouseArea->preventStealing();
2781#if QT_CONFIG(quick_draganddrop)
2782 if (mouseArea->drag() && mouseArea->drag()->target())
2783 preventStealing =
true;
2785 if (!preventStealing && receiverKeepsGrab) {
2786 receiverRelinquishGrab = !receiverDisabled || (isMouse
2787 && firstPoint.state() == QEventPoint::State::Pressed
2788 && (receiver->acceptedMouseButtons() &
static_cast<QMouseEvent *>(event)->button()));
2789 if (receiverRelinquishGrab)
2790 receiverKeepsGrab =
false;
2794 if ((stealThisEvent || contains(localPos)) && (!receiver || !receiverKeepsGrab || receiverDisabled)) {
2795 QScopedPointer<QPointerEvent> localizedEvent(QQuickDeliveryAgentPrivate::clonePointerEvent(event, localPos));
2796 localizedEvent->setAccepted(
false);
2797 switch (firstPoint.state()) {
2798 case QEventPoint::State::Updated:
2799 d->handleMoveEvent(localizedEvent.data());
2801 case QEventPoint::State::Pressed:
2802 d->handlePressEvent(localizedEvent.data());
2803 d->captureDelayedPress(receiver, event);
2805 d->stealMouse =
false;
2806 stealThisEvent =
false;
2808 case QEventPoint::State::Released:
2809 d->handleReleaseEvent(localizedEvent.data());
2810 stealThisEvent = d->stealMouse;
2812 case QEventPoint::State::Stationary:
2813 case QEventPoint::State::Unknown:
2816 if ((receiver && stealThisEvent && !receiverKeepsGrab && receiver !=
this) || receiverDisabled) {
2817 d->clearDelayedPress();
2818 event->setExclusiveGrabber(firstPoint,
this);
2819 }
else if (d->delayedPressEvent) {
2820 event->setExclusiveGrabber(firstPoint,
this);
2823
2824
2825
2826
2827
2828
2829
2830
2831
2832
2833
2834 if (isMoving() || (!receiverRelinquishGrab && (stealThisEvent || d->delayedPressEvent || receiverDisabled))) {
2836 event->setAccepted(
true);
2842 }
else if (d->lastPosTime != -1) {
2843 d->lastPosTime = -1;
2846 if (firstPoint.state() == QEventPoint::State::Released || (receiverKeepsGrab && !receiverDisabled)) {
2848 d->lastPosTime = -1;
2849 d->clearDelayedPress();
2850 d->stealMouse =
false;
2857
2858
2859
2860bool QQuickFlickable::childMouseEventFilter(QQuickItem *i, QEvent *e)
2862 Q_D(QQuickFlickable);
2863 QPointerEvent *pointerEvent = e->isPointerEvent() ?
static_cast<QPointerEvent *>(e) :
nullptr;
2865 auto wantsPointerEvent_helper = [
this, d, i, pointerEvent]() {
2866 Q_ASSERT(pointerEvent);
2867 QQuickDeliveryAgentPrivate::localizePointerEvent(pointerEvent,
this);
2868 const bool wants = d->wantsPointerEvent(pointerEvent);
2870 QQuickDeliveryAgentPrivate::localizePointerEvent(pointerEvent, i);
2874 if (!isVisible() || !isEnabled() || !isInteractive() ||
2875 (pointerEvent && !wantsPointerEvent_helper())) {
2876 d->cancelInteraction();
2877 return QQuickItem::childMouseEventFilter(i, e);
2880 if (e->type() == QEvent::UngrabMouse) {
2881 Q_ASSERT(e->isSinglePointEvent());
2882 auto spe =
static_cast<QSinglePointEvent *>(e);
2883 const QObject *grabber = spe->exclusiveGrabber(spe->points().first());
2884 qCDebug(lcFilter) <<
"filtering UngrabMouse" << spe->points().first() <<
"for" << i <<
"grabber is" << grabber;
2885 if (grabber !=
this)
2887 }
else if (pointerEvent) {
2888 return filterPointerEvent(i, pointerEvent);
2891 return QQuickItem::childMouseEventFilter(i, e);
2895
2896
2897
2898
2899
2900qreal QQuickFlickable::maximumFlickVelocity()
const
2902 Q_D(
const QQuickFlickable);
2903 return d->maxVelocity;
2906void QQuickFlickable::setMaximumFlickVelocity(qreal v)
2908 Q_D(QQuickFlickable);
2909 if (v == d->maxVelocity)
2912 emit maximumFlickVelocityChanged();
2916
2917
2918
2919
2920
2921
2922
2923
2924qreal QQuickFlickable::flickDeceleration()
const
2926 Q_D(
const QQuickFlickable);
2927 return d->deceleration;
2930void QQuickFlickable::setFlickDeceleration(qreal deceleration)
2932 Q_D(QQuickFlickable);
2933 if (deceleration == d->deceleration)
2935 d->deceleration = qMax(0.001, deceleration);
2936 emit flickDecelerationChanged();
2939bool QQuickFlickable::isFlicking()
const
2941 Q_D(
const QQuickFlickable);
2942 return d->hData.flicking || d->vData.flicking;
2946
2947
2948
2949
2950
2951
2952
2953bool QQuickFlickable::isFlickingHorizontally()
const
2955 Q_D(
const QQuickFlickable);
2956 return d->hData.flicking;
2959bool QQuickFlickable::isFlickingVertically()
const
2961 Q_D(
const QQuickFlickable);
2962 return d->vData.flicking;
2966
2967
2968
2969
2970
2971
2972
2973bool QQuickFlickable::isDragging()
const
2975 Q_D(
const QQuickFlickable);
2976 return d->hData.dragging || d->vData.dragging;
2979bool QQuickFlickable::isDraggingHorizontally()
const
2981 Q_D(
const QQuickFlickable);
2982 return d->hData.dragging;
2985bool QQuickFlickable::isDraggingVertically()
const
2987 Q_D(
const QQuickFlickable);
2988 return d->vData.dragging;
2991void QQuickFlickablePrivate::draggingStarting()
2993 Q_Q(QQuickFlickable);
2994 bool wasDragging = hData.dragging || vData.dragging;
2995 if (hMoved && !hData.dragging) {
2996 hData.dragging =
true;
2997 emit q->draggingHorizontallyChanged();
2999 if (vMoved && !vData.dragging) {
3000 vData.dragging =
true;
3001 emit q->draggingVerticallyChanged();
3003 if (!wasDragging && (hData.dragging || vData.dragging)) {
3004 emit q->draggingChanged();
3005 emit q->dragStarted();
3009void QQuickFlickablePrivate::draggingEnding()
3011 Q_Q(QQuickFlickable);
3012 const bool wasDragging = hData.dragging || vData.dragging;
3013 if (hData.dragging) {
3014 hData.dragging =
false;
3015 emit q->draggingHorizontallyChanged();
3017 if (vData.dragging) {
3018 vData.dragging =
false;
3019 emit q->draggingVerticallyChanged();
3022 if (!hData.dragging && !vData.dragging) {
3023 emit q->draggingChanged();
3024 emit q->dragEnded();
3026 hData.inRebound =
false;
3027 vData.inRebound =
false;
3031bool QQuickFlickablePrivate::isViewMoving()
const
3033 if (timeline.isActive()
3034 || (hData.transitionToBounds && hData.transitionToBounds->isActive())
3035 || (vData.transitionToBounds && vData.transitionToBounds->isActive()) ) {
3042
3043
3044
3045
3046
3047
3048
3049
3050
3051
3052
3053
3054
3055
3056
3057
3058
3059int QQuickFlickable::pressDelay()
const
3061 Q_D(
const QQuickFlickable);
3062 return d->pressDelay;
3065void QQuickFlickable::setPressDelay(
int delay)
3067 Q_D(QQuickFlickable);
3068 if (d->pressDelay == delay)
3070 d->pressDelay = delay;
3071 emit pressDelayChanged();
3075
3076
3077
3078
3079
3080
3081
3082
3084bool QQuickFlickable::isMoving()
const
3086 Q_D(
const QQuickFlickable);
3087 return d->hData.moving || d->vData.moving;
3090bool QQuickFlickable::isMovingHorizontally()
const
3092 Q_D(
const QQuickFlickable);
3093 return d->hData.moving;
3096bool QQuickFlickable::isMovingVertically()
const
3098 Q_D(
const QQuickFlickable);
3099 return d->vData.moving;
3102void QQuickFlickable::velocityTimelineCompleted()
3104 Q_D(QQuickFlickable);
3105 if ( (d->hData.transitionToBounds && d->hData.transitionToBounds->isActive())
3106 || (d->vData.transitionToBounds && d->vData.transitionToBounds->isActive()) ) {
3113 if (d->vData.flicking)
3115 d->updateBeginningEnd();
3118void QQuickFlickable::timelineCompleted()
3120 Q_D(QQuickFlickable);
3121 if ( (d->hData.transitionToBounds && d->hData.transitionToBounds->isActive())
3122 || (d->vData.transitionToBounds && d->vData.transitionToBounds->isActive()) ) {
3126 d->updateBeginningEnd();
3129void QQuickFlickable::movementStarting()
3131 Q_D(QQuickFlickable);
3132 bool wasMoving = d->hData.moving || d->vData.moving;
3133 if (d->hMoved && !d->hData.moving) {
3134 d->hData.moving =
true;
3135 emit movingHorizontallyChanged();
3137 if (d->vMoved && !d->vData.moving) {
3138 d->vData.moving =
true;
3139 emit movingVerticallyChanged();
3142 if (!wasMoving && (d->hData.moving || d->vData.moving)) {
3143 emit movingChanged();
3144 emit movementStarted();
3145#if QT_CONFIG(accessibility)
3146 if (QAccessible::isActive()) {
3147 QAccessibleEvent ev(
this, QAccessible::ScrollingStart);
3148 QAccessible::updateAccessibility(&ev);
3154void QQuickFlickable::movementEnding()
3156 movementEnding(
true,
true);
3159void QQuickFlickable::movementEnding(
bool hMovementEnding,
bool vMovementEnding)
3161 Q_D(QQuickFlickable);
3164 const bool wasFlicking = d->hData.flicking || d->vData.flicking;
3165 if (hMovementEnding && d->hData.flicking) {
3166 d->hData.flicking =
false;
3167 emit flickingHorizontallyChanged();
3169 if (vMovementEnding && d->vData.flicking) {
3170 d->vData.flicking =
false;
3171 emit flickingVerticallyChanged();
3173 if (wasFlicking && (!d->hData.flicking || !d->vData.flicking)) {
3174 emit flickingChanged();
3176 }
else if (d->hData.flickingWhenDragBegan || d->vData.flickingWhenDragBegan) {
3177 d->hData.flickingWhenDragBegan = !hMovementEnding;
3178 d->vData.flickingWhenDragBegan = !vMovementEnding;
3183 bool wasMoving = isMoving();
3184 if (hMovementEnding && d->hData.moving
3185 && (!d->pressed && !d->stealMouse)) {
3186 d->hData.moving =
false;
3188 emit movingHorizontallyChanged();
3190 if (vMovementEnding && d->vData.moving
3191 && (!d->pressed && !d->stealMouse)) {
3192 d->vData.moving =
false;
3194 emit movingVerticallyChanged();
3196 if (wasMoving && !isMoving()) {
3197 emit movingChanged();
3198 emit movementEnded();
3199#if QT_CONFIG(accessibility)
3200 if (QAccessible::isActive()) {
3201 QAccessibleEvent ev(
this, QAccessible::ScrollingEnd);
3202 QAccessible::updateAccessibility(&ev);
3207 if (hMovementEnding) {
3208 d->hData.fixingUp =
false;
3209 d->hData.smoothVelocity.setValue(0);
3210 d->hData.previousDragDelta = 0.0;
3212 if (vMovementEnding) {
3213 d->vData.fixingUp =
false;
3214 d->vData.smoothVelocity.setValue(0);
3215 d->vData.previousDragDelta = 0.0;
3219void QQuickFlickablePrivate::updateVelocity()
3221 Q_Q(QQuickFlickable);
3222 emit q->horizontalVelocityChanged();
3223 emit q->verticalVelocityChanged();
3227
3228
3229
3230
3231
3232
3233
3234
3235
3236
3237
3238
3239
3240
3241qreal QQuickFlickable::horizontalOvershoot()
const
3243 Q_D(
const QQuickFlickable);
3244 return d->hData.overshoot;
3248
3249
3250
3251
3252
3253
3254
3255
3256
3257
3258
3259
3260
3261
3262qreal QQuickFlickable::verticalOvershoot()
const
3264 Q_D(
const QQuickFlickable);
3265 return d->vData.overshoot;
3269
3270
3271
3272
3273
3274
3275
3276
3277
3278
3279
3280
3281
3282
3283
3284
3285
3286
3287
3288
3289
3290
3291
3292
3293
3294
3295
3296
3297
3298
3299
3300
3301
3302
3303
3304
3305
3306
3307
3308
3309
3310
3311
3312
3313
3314QQuickFlickable::BoundsMovement QQuickFlickable::boundsMovement()
const
3316 Q_D(
const QQuickFlickable);
3317 return d->boundsMovement;
3320void QQuickFlickable::setBoundsMovement(BoundsMovement movement)
3322 Q_D(QQuickFlickable);
3323 if (d->boundsMovement == movement)
3326 d->boundsMovement = movement;
3327 emit boundsMovementChanged();
3332#include "moc_qquickflickable_p_p.cpp"
3334#include "moc_qquickflickable_p.cpp"
bool contains(const QPointF &point) const override
~QQuickFlickableReboundTransition()
bool startTransition(QQuickFlickablePrivate::AxisData *data, qreal toPos)
QQuickFlickableReboundTransition(QQuickFlickable *f, const QString &name)
Q_STATIC_LOGGING_CATEGORY(lcAccessibilityCore, "qt.accessibility.core")
static bool fuzzyLessThanOrEqualTo(qreal a, qreal b)
static qreal EaseOvershoot(qreal t)
#define QML_FLICK_SAMPLEBUFFER
#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