10#if QT_CONFIG(quick_draganddrop)
11#include "qquickdrag_p.h"
14#include <QtQuick/private/qquickpointerhandler_p.h>
15#include <QtQuick/private/qquicktransition_p.h>
16#include <private/qqmlglobal_p.h>
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 <QtGui/qaccessible.h>
25#include <QtCore/qmath.h>
26#include <qpa/qplatformtheme.h>
34Q_STATIC_LOGGING_CATEGORY(lcFilter,
"qt.quick.flickable.filter")
35Q_STATIC_LOGGING_CATEGORY(lcReplay,
"qt.quick.flickable.replay")
36Q_STATIC_LOGGING_CATEGORY(lcWheel,
"qt.quick.flickable.wheel")
37Q_STATIC_LOGGING_CATEGORY(lcVel,
"qt.quick.flickable.velocity")
41static const int RetainGrabVelocity = 100;
47QQuickFlickableVisibleArea::QQuickFlickableVisibleArea(QQuickFlickable *parent)
48 : QObject(parent), flickable(parent), m_xPosition(0.), m_widthRatio(0.)
49 , m_yPosition(0.), m_heightRatio(0.)
53qreal QQuickFlickableVisibleArea::widthRatio()
const
58qreal QQuickFlickableVisibleArea::xPosition()
const
63qreal QQuickFlickableVisibleArea::heightRatio()
const
68qreal QQuickFlickableVisibleArea::yPosition()
const
73void QQuickFlickableVisibleArea::updateVisible()
75 QQuickFlickablePrivate *p = QQuickFlickablePrivate::get(flickable);
79 bool changeWidth =
false;
80 bool changeHeight =
false;
83 const qreal viewheight = flickable->height();
84 const qreal maxyextent = -flickable->maxYExtent() + flickable->minYExtent();
85 const qreal maxYBounds = maxyextent + viewheight;
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;
94 if (pageSize != m_heightRatio) {
95 m_heightRatio = pageSize;
98 if (pagePos != m_yPosition) {
99 m_yPosition = pagePos;
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;
116 if (pageSize != m_widthRatio) {
117 m_widthRatio = pageSize;
120 if (pagePos != m_xPosition) {
121 m_xPosition = pagePos;
126 emit xPositionChanged(m_xPosition);
128 emit yPositionChanged(m_yPosition);
130 emit widthRatioChanged(m_widthRatio);
132 emit heightRatioChanged(m_heightRatio);
150 QQuickFlickablePrivate *fp = QQuickFlickablePrivate::get(flickable);
151 if (!fp->rebound || !fp->rebound->enabled())
155 axisData->transitionTo = toPos;
156 axisData->transitionToSet =
true;
159 actions << QQuickStateAction(fp->contentItem, propName, toPos);
160 QQuickTransitionManager::transition(actions, fp->rebound, fp->contentItem);
169 if (!flickable || !isRunning())
171 QQuickFlickablePrivate *fp = QQuickFlickablePrivate::get(flickable);
172 if (axisData == &fp->hData)
173 axisData->move.setValue(-flickable->contentX());
175 axisData->move.setValue(-flickable->contentY());
184 axisData->move.setValue(axisData->transitionTo);
185 QQuickFlickablePrivate *fp = QQuickFlickablePrivate::get(flickable);
188 if (!fp->hData.transitionToBounds->isActive()
189 && !fp->vData.transitionToBounds->isActive()) {
190 flickable->movementEnding();
195 QQuickStateOperation::ActionList actions;
196 QQuickFlickable *flickable;
197 QQuickFlickablePrivate::AxisData *axisData;
202QQuickFlickablePrivate::AxisData::~AxisData()
204 delete transitionToBounds;
212 auto *d = QQuickItemPrivate::get(
this);
217 d->eventHandlingChildrenWithinBounds =
false;
218 d->eventHandlingChildrenWithinBoundsSet =
true;
223
224
225
226
227
228
229
230
233 const QQuickItem *flickable = parentItem();
234 const QPointF posInFlickable = flickable->mapFromItem(
this, point);
235 return flickable->contains(posInFlickable);
239QQuickFlickablePrivate::QQuickFlickablePrivate()
240 : contentItem(
new QQuickFlickableContentItem)
241 , hData(
this, &QQuickFlickablePrivate::setViewportX)
242 , vData(
this, &QQuickFlickablePrivate::setViewportY)
243 , hMoved(
false), vMoved(
false)
244 , stealGrab(
false), pressed(
false)
245 , scrollingPhase(
false), interactive(
true), calcVelocity(
false)
246 , pixelAligned(
false)
248 , acceptedButtons(Qt::LeftButton)
251 , deceleration(QGuiApplicationPrivate::platformTheme()->themeHint(QPlatformTheme::FlickDeceleration).toReal())
252 , wheelDeceleration(15000)
253 , maxVelocity(QGuiApplicationPrivate::platformTheme()->themeHint(QPlatformTheme::FlickMaximumVelocity).toReal())
254 , delayedPressEvent(
nullptr), pressDelay(0), fixupDuration(400)
255 , flickBoost(1.0), initialWheelFlickDistance(qApp->styleHints()->wheelScrollLines() * 24)
256 , fixupMode(Normal), vTime(0), visibleArea(
nullptr)
257 , flickableDirection(QQuickFlickable::AutoFlickDirection)
258 , boundsBehavior(QQuickFlickable::DragAndOvershootBounds)
259 , boundsMovement(QQuickFlickable::FollowBoundsBehavior)
262 const int wheelDecelerationEnv = qEnvironmentVariableIntValue(
"QT_QUICK_FLICKABLE_WHEEL_DECELERATION");
263 if (wheelDecelerationEnv > 0)
264 wheelDeceleration = wheelDecelerationEnv;
267void QQuickFlickablePrivate::init()
269 Q_Q(QQuickFlickable);
270 QQml_setParent_noEvent(contentItem, q);
271 contentItem->setParentItem(q);
272 qmlobject_connect(&timeline, QQuickTimeLine, SIGNAL(completed()),
273 q, QQuickFlickable, SLOT(timelineCompleted()));
274 qmlobject_connect(&velocityTimeline, QQuickTimeLine, SIGNAL(completed()),
275 q, QQuickFlickable, SLOT(velocityTimelineCompleted()));
276 q->setAcceptedMouseButtons(acceptedButtons);
277 q->setAcceptTouchEvents(
true);
278 q->setFiltersChildMouseEvents(
true);
279 q->setFlag(QQuickItem::ItemIsViewport);
280 QQuickItemPrivate *viewportPrivate = QQuickItemPrivate::get(contentItem);
281 viewportPrivate->addItemChangeListener(
this, QQuickItemPrivate::Geometry);
282 setSizePolicy(QLayoutPolicy::Expanding, QLayoutPolicy::Expanding);
286
287
288
289
290qreal QQuickFlickablePrivate::overShootDistance(qreal velocity)
const
292 if (maxVelocity <= 0)
298void QQuickFlickablePrivate::AxisData::addVelocitySample(qreal v, qreal maxVelocity)
302 else if (v < -maxVelocity)
305 velocityBuffer[velocityWritePos] = v;
311void QQuickFlickablePrivate::AxisData::updateVelocity()
320 for (
int i = 0; i < count; ++i) {
328void QQuickFlickablePrivate::itemGeometryChanged(QQuickItem *item, QQuickGeometryChange change,
const QRectF &oldGeom)
330 Q_Q(QQuickFlickable);
331 if (item == contentItem) {
332 Qt::Orientations orient;
333 if (change.xChange())
334 orient |= Qt::Horizontal;
335 if (change.yChange())
336 orient |= Qt::Vertical;
338 q->viewportMoved(orient);
339 const QPointF deltaMoved = item->position() - oldGeom.topLeft();
340 if (hData.contentPositionChangedExternallyDuringDrag)
341 hData.pressPos += deltaMoved.x();
342 if (vData.contentPositionChangedExternallyDuringDrag)
343 vData.pressPos += deltaMoved.y();
345#if QT_CONFIG(accessibility)
346 bool updateAccessibility =
false;
348 if (orient & Qt::Horizontal) {
349 emit q->contentXChanged();
350#if QT_CONFIG(accessibility)
351 updateAccessibility =
true;
354 if (orient & Qt::Vertical) {
355 emit q->contentYChanged();
356#if QT_CONFIG(accessibility)
357 updateAccessibility =
true;
360#if QT_CONFIG(accessibility)
361 if (updateAccessibility && QAccessible::isActive()) {
362 if (!m_scrollEventTimer.isValid() || m_scrollEventTimer.elapsed() >= 250) {
363 m_scrollEventTimer.restart();
364 QAccessibleEvent ev(q, QAccessible::ScrollingPositionChanged);
365 QAccessible::updateAccessibility(&ev);
372bool QQuickFlickablePrivate::flickX(QEvent::Type eventType, qreal velocity)
374 Q_Q(QQuickFlickable);
375 return flick(hData, q->minXExtent(), q->maxXExtent(), q->width(), fixupX_callback, eventType, velocity);
378bool QQuickFlickablePrivate::flickY(QEvent::Type eventType, qreal velocity)
380 Q_Q(QQuickFlickable);
381 return flick(vData, q->minYExtent(), q->maxYExtent(), q->height(), fixupY_callback, eventType, velocity);
384bool QQuickFlickablePrivate::flick(AxisData &data, qreal minExtent, qreal maxExtent, qreal,
385 QQuickTimeLineCallback::Callback fixupCallback,
386 QEvent::Type eventType, qreal velocity)
388 Q_Q(QQuickFlickable);
389 qreal maxDistance = -1;
390 data.fixingUp =
false;
393 maxDistance = qAbs(minExtent - data.move.value());
394 data.flickTarget = minExtent;
396 maxDistance = qAbs(maxExtent - data.move.value());
397 data.flickTarget = maxExtent;
399 if (maxDistance > 0 || boundsBehavior & QQuickFlickable::OvershootBounds) {
401 if (maxVelocity != -1 && maxVelocity < qAbs(v)) {
408 qreal accel = eventType == QEvent::Wheel ? wheelDeceleration : deceleration;
409 qCDebug(lcFlickable) <<
"choosing deceleration" << accel <<
"for" << eventType;
412 qreal dist = v2 / (accel * 2.0);
415 qreal target = std::round(data.move.value() - dist);
416 dist = -target + data.move.value();
417 accel = v2 / (2.0f * qAbs(dist));
420 if (!data.inOvershoot) {
421 if (boundsBehavior & QQuickFlickable::OvershootBounds)
422 timeline.accel(data.move, v, accel);
424 timeline.accel(data.move, v, accel, maxDistance);
426 timeline.callback(QQuickTimeLineCallback(&data.move, fixupCallback,
this));
429 return !hData.flicking && q->xflick();
430 else if (&data == &vData)
431 return !vData.flicking && q->yflick();
435 fixup(data, minExtent, maxExtent);
440void QQuickFlickablePrivate::fixupY_callback(
void *data)
442 ((QQuickFlickablePrivate *)data)->fixupY();
445void QQuickFlickablePrivate::fixupX_callback(
void *data)
447 ((QQuickFlickablePrivate *)data)->fixupX();
450void QQuickFlickablePrivate::fixupX()
452 Q_Q(QQuickFlickable);
453 if (!q->isComponentComplete())
455 fixup(hData, q->minXExtent(), q->maxXExtent());
458void QQuickFlickablePrivate::fixupY()
460 Q_Q(QQuickFlickable);
461 if (!q->isComponentComplete())
463 fixup(vData, q->minYExtent(), q->maxYExtent());
467
468
469
470
471
472
473
474void QQuickFlickablePrivate::adjustContentPos(AxisData &data, qreal toPos)
476 Q_Q(QQuickFlickable);
479 timeline.set(data.move, toPos);
484 timeline.move(data.move, toPos, QEasingCurve(QEasingCurve::OutExpo), 3*fixupDuration/4);
485 data.fixingUp =
true;
488 if (data.transitionToBounds && data.transitionToBounds->startTransition(&data, toPos)) {
489 q->movementStarting();
490 data.fixingUp =
true;
492 qreal dist = toPos - data.move;
493 timeline.move(data.move, toPos - dist/2, QEasingCurve(QEasingCurve::InQuad), fixupDuration/4);
494 timeline.move(data.move, toPos, QEasingCurve(QEasingCurve::OutExpo), 3*fixupDuration/4);
495 data.fixingUp =
true;
501void QQuickFlickablePrivate::resetTimeline(AxisData &data)
503 timeline.reset(data.move);
504 if (data.transitionToBounds)
505 data.transitionToBounds->stopTransition();
508void QQuickFlickablePrivate::clearTimeline()
511 if (hData.transitionToBounds)
512 hData.transitionToBounds->stopTransition();
513 if (vData.transitionToBounds)
514 vData.transitionToBounds->stopTransition();
518
519
520
521
522
523
524
525
526
527void QQuickFlickablePrivate::fixup(AxisData &data, qreal minExtent, qreal maxExtent)
532 if (data.move.value() >= minExtent || maxExtent > minExtent) {
533 const bool wasActive = timeline.isActive();
535 if (data.move.value() != minExtent)
536 adjustContentPos(data, minExtent);
538 timeline.move(data.move, data.move.value(), QEasingCurve(QEasingCurve::Linear), 1);
539 }
else if (data.move.value() <= maxExtent) {
541 adjustContentPos(data, maxExtent);
542 }
else if (-std::round(-data.move.value()) != data.move.value()) {
545 qreal val = data.move.value();
546 if (std::abs(std::round(val) - val) < 0.25)
547 val = std::round(val);
548 else if (data.smoothVelocity.value() > 0)
549 val = std::ceil(val);
550 else if (data.smoothVelocity.value() < 0)
551 val = std::floor(val);
553 val = std::round(val);
554 timeline.set(data.move, val);
556 data.inOvershoot =
false;
558 data.vTime = timeline.time();
563 if (a == 0.0 || b == 0.0) {
568 return a <= b || qFuzzyCompare(a, b);
572
573
574
575
576
577
578
579
580void QQuickFlickablePrivate::updateBeginningEnd()
582 Q_Q(QQuickFlickable);
583 bool atXBeginningChange =
false, atXEndChange =
false;
584 bool atYBeginningChange =
false, atYEndChange =
false;
587 const qreal maxyextent = -q->maxYExtent();
588 const qreal minyextent = -q->minYExtent();
589 const qreal ypos = pixelAligned ? -std::round(vData.move.value()) : -vData.move.value();
590 bool atBeginning = fuzzyLessThanOrEqualTo(ypos, std::ceil(minyextent));
591 bool atEnd = fuzzyLessThanOrEqualTo(std::floor(maxyextent), ypos);
593 if (atBeginning != vData.atBeginning) {
594 vData.atBeginning = atBeginning;
595 atYBeginningChange =
true;
596 if (!vData.moving && atBeginning)
597 vData.smoothVelocity.setValue(0);
599 if (atEnd != vData.atEnd) {
602 if (!vData.moving && atEnd)
603 vData.smoothVelocity.setValue(0);
607 const qreal maxxextent = -q->maxXExtent();
608 const qreal minxextent = -q->minXExtent();
609 const qreal xpos = pixelAligned ? -std::round(hData.move.value()) : -hData.move.value();
610 atBeginning = fuzzyLessThanOrEqualTo(xpos, std::ceil(minxextent));
611 atEnd = fuzzyLessThanOrEqualTo(std::floor(maxxextent), xpos);
613 if (atBeginning != hData.atBeginning) {
614 hData.atBeginning = atBeginning;
615 atXBeginningChange =
true;
616 if (!hData.moving && atBeginning)
617 hData.smoothVelocity.setValue(0);
619 if (atEnd != hData.atEnd) {
622 if (!hData.moving && atEnd)
623 hData.smoothVelocity.setValue(0);
626 if (vData.extentsChanged) {
627 vData.extentsChanged =
false;
628 qreal originY = q->originY();
629 if (vData.origin != originY) {
630 vData.origin = originY;
631 emit q->originYChanged();
635 if (hData.extentsChanged) {
636 hData.extentsChanged =
false;
637 qreal originX = q->originX();
638 if (hData.origin != originX) {
639 hData.origin = originX;
640 emit q->originXChanged();
644 if (atXEndChange || atYEndChange || atXBeginningChange || atYBeginningChange)
645 emit q->isAtBoundaryChanged();
647 emit q->atXEndChanged();
648 if (atXBeginningChange)
649 emit q->atXBeginningChanged();
651 emit q->atYEndChanged();
652 if (atYBeginningChange)
653 emit q->atYBeginningChanged();
656 visibleArea->updateVisible();
660
661
662
663
664
667
668
669
670
671
672
673
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
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
760
761
762
763
764
767
768
769
770
771
772
773
774
777
778
779
780
781
782
785
786
787
788
789
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811QQuickFlickable::QQuickFlickable(QQuickItem *parent)
812 : QQuickItem(*(
new QQuickFlickablePrivate), parent)
814 Q_D(QQuickFlickable);
818QQuickFlickable::QQuickFlickable(QQuickFlickablePrivate &dd, QQuickItem *parent)
819 : QQuickItem(dd, parent)
821 Q_D(QQuickFlickable);
825QQuickFlickable::~QQuickFlickable()
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849qreal QQuickFlickable::contentX()
const
851 Q_D(
const QQuickFlickable);
852 return -d->contentItem->x();
855void QQuickFlickable::setContentX(qreal pos)
857 Q_D(QQuickFlickable);
858 d->hData.explicitValue =
true;
859 d->resetTimeline(d->hData);
860 d->hData.vTime = d->timeline.time();
861 if (isMoving() || isFlicking())
862 movementEnding(
true,
false);
863 if (!qFuzzyCompare(-pos, d->hData.move.value())) {
864 d->hData.contentPositionChangedExternallyDuringDrag = d->hData.dragging;
865 d->hData.move.setValue(-pos);
866 d->hData.contentPositionChangedExternallyDuringDrag =
false;
870qreal QQuickFlickable::contentY()
const
872 Q_D(
const QQuickFlickable);
873 return -d->contentItem->y();
876void QQuickFlickable::setContentY(qreal pos)
878 Q_D(QQuickFlickable);
879 d->vData.explicitValue =
true;
880 d->resetTimeline(d->vData);
881 d->vData.vTime = d->timeline.time();
882 if (isMoving() || isFlicking())
883 movementEnding(
false,
true);
884 if (!qFuzzyCompare(-pos, d->vData.move.value())) {
885 d->vData.contentPositionChangedExternallyDuringDrag = d->vData.dragging;
886 d->vData.move.setValue(-pos);
887 d->vData.contentPositionChangedExternallyDuringDrag =
false;
892
893
894
895
896
897
898
899
900
901
902
903
904bool QQuickFlickable::isInteractive()
const
906 Q_D(
const QQuickFlickable);
907 return d->interactive;
910void QQuickFlickable::setInteractive(
bool interactive)
912 Q_D(QQuickFlickable);
913 if (interactive != d->interactive) {
914 d->interactive = interactive;
916 d->cancelInteraction();
918 emit interactiveChanged();
923
924
925
926
927
928
929
930
931
932
933
934
935qreal QQuickFlickable::horizontalVelocity()
const
937 Q_D(
const QQuickFlickable);
938 return d->hData.smoothVelocity.value();
941qreal QQuickFlickable::verticalVelocity()
const
943 Q_D(
const QQuickFlickable);
944 return d->vData.smoothVelocity.value();
948
949
950
951
952
953
954
955
956bool QQuickFlickable::isAtXEnd()
const
958 Q_D(
const QQuickFlickable);
959 return d->hData.atEnd;
962bool QQuickFlickable::isAtXBeginning()
const
964 Q_D(
const QQuickFlickable);
965 return d->hData.atBeginning;
968bool QQuickFlickable::isAtYEnd()
const
970 Q_D(
const QQuickFlickable);
971 return d->vData.atEnd;
974bool QQuickFlickable::isAtYBeginning()
const
976 Q_D(
const QQuickFlickable);
977 return d->vData.atBeginning;
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998QQuickItem *QQuickFlickable::contentItem()
const
1000 Q_D(
const QQuickFlickable);
1001 return d->contentItem;
1004QQuickFlickableVisibleArea *QQuickFlickable::visibleArea()
1006 Q_D(QQuickFlickable);
1007 if (!d->visibleArea) {
1008 d->visibleArea =
new QQuickFlickableVisibleArea(
this);
1009 d->visibleArea->updateVisible();
1011 return d->visibleArea;
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033QQuickFlickable::FlickableDirection QQuickFlickable::flickableDirection()
const
1035 Q_D(
const QQuickFlickable);
1036 return d->flickableDirection;
1039void QQuickFlickable::setFlickableDirection(FlickableDirection direction)
1041 Q_D(QQuickFlickable);
1042 if (direction != d->flickableDirection) {
1043 d->flickableDirection = direction;
1044 emit flickableDirectionChanged();
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060bool QQuickFlickable::pixelAligned()
const
1062 Q_D(
const QQuickFlickable);
1063 return d->pixelAligned;
1066void QQuickFlickable::setPixelAligned(
bool align)
1068 Q_D(QQuickFlickable);
1069 if (align != d->pixelAligned) {
1070 d->pixelAligned = align;
1071 emit pixelAlignedChanged();
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087bool QQuickFlickable::synchronousDrag()
const
1089 Q_D(
const QQuickFlickable);
1093void QQuickFlickable::setSynchronousDrag(
bool v)
1095 Q_D(QQuickFlickable);
1096 if (v != d->syncDrag) {
1098 emit synchronousDragChanged();
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117Qt::MouseButtons QQuickFlickable::acceptedButtons()
const
1119 Q_D(
const QQuickFlickable);
1120 return d->acceptedButtons;
1123void QQuickFlickable::setAcceptedButtons(Qt::MouseButtons buttons)
1125 Q_D(QQuickFlickable);
1126 if (d->acceptedButtons == buttons)
1129 d->acceptedButtons = buttons;
1130 setAcceptedMouseButtons(buttons);
1131 emit acceptedButtonsChanged();
1135
1136
1137
1138QVector2D QQuickFlickablePrivate::firstPointLocalVelocity(QPointerEvent *event)
1140 QTransform transform = windowToItemTransform();
1142 return QVector2D(transform.map(event->point(0).velocity().toPointF()) - transform.map(QPointF()));
1145qint64 QQuickFlickablePrivate::computeCurrentTime(QInputEvent *event)
const
1147 if (0 != event->timestamp())
1148 return event->timestamp();
1149 if (!timer.isValid())
1151 return timer.elapsed();
1154void QQuickFlickablePrivate::handlePressEvent(QPointerEvent *event)
1156 Q_Q(QQuickFlickable);
1158 if (interactive && timeline.isActive()
1159 && ((qAbs(hData.smoothVelocity.value()) > RetainGrabVelocity && !hData.fixingUp && !hData.inOvershoot)
1160 || (qAbs(vData.smoothVelocity.value()) > RetainGrabVelocity && !vData.fixingUp && !vData.inOvershoot))) {
1164 int flickTime = timeline.time();
1165 if (flickTime > 600) {
1167 hData.continuousFlickVelocity = 0;
1168 vData.continuousFlickVelocity = 0;
1171 hData.continuousFlickVelocity = -hData.smoothVelocity.value();
1172 vData.continuousFlickVelocity = -vData.smoothVelocity.value();
1173 if (flickTime > 300)
1174 flickBoost = qMax(1.0, flickBoost - 0.5);
1178 hData.continuousFlickVelocity = 0;
1179 vData.continuousFlickVelocity = 0;
1182 if (event->isSinglePointEvent())
1183 q->setKeepMouseGrab(stealGrab);
1185 q->setKeepTouchGrab(stealGrab);
1187 maybeBeginDrag(computeCurrentTime(event), event->points().first().position(),
1188 event->isSinglePointEvent() ?
static_cast<QSinglePointEvent *>(event)->buttons()
1192void QQuickFlickablePrivate::maybeBeginDrag(qint64 currentTimestamp,
const QPointF &pressPosn, Qt::MouseButtons buttons)
1194 Q_Q(QQuickFlickable);
1195 clearDelayedPress();
1197 pressed = (buttons == Qt::NoButton) || (acceptedButtons != Qt::NoButton && (buttons & acceptedButtons) != 0);
1199 if (hData.transitionToBounds)
1200 hData.transitionToBounds->stopTransition();
1201 if (vData.transitionToBounds)
1202 vData.transitionToBounds->stopTransition();
1203 if (!hData.fixingUp)
1204 resetTimeline(hData);
1205 if (!vData.fixingUp)
1206 resetTimeline(vData);
1210 hData.dragMinBound = q->minXExtent() - hData.startMargin;
1211 vData.dragMinBound = q->minYExtent() - vData.startMargin;
1212 hData.dragMaxBound = q->maxXExtent() + hData.endMargin;
1213 vData.dragMaxBound = q->maxYExtent() + vData.endMargin;
1215 lastPos = QPointF();
1216 pressPos = pressPosn;
1217 hData.pressPos = hData.move.value();
1218 vData.pressPos = vData.move.value();
1219 const bool wasFlicking = hData.flicking || vData.flicking;
1220 hData.flickingWhenDragBegan = hData.flicking;
1221 vData.flickingWhenDragBegan = vData.flicking;
1222 if (hData.flicking) {
1223 hData.flicking =
false;
1224 emit q->flickingHorizontallyChanged();
1226 if (vData.flicking) {
1227 vData.flicking =
false;
1228 emit q->flickingVerticallyChanged();
1231 emit q->flickingChanged();
1232 lastPosTime = lastPressTime = currentTimestamp;
1233 vData.velocityTime.start();
1234 hData.velocityTime.start();
1237void QQuickFlickablePrivate::drag(qint64 currentTimestamp, QEvent::Type eventType,
const QPointF &localPos,
1238 const QVector2D &deltas,
bool overThreshold,
bool momentum,
1239 bool velocitySensitiveOverBounds,
const QVector2D &velocity)
1241 Q_Q(QQuickFlickable);
1242 bool rejectY =
false;
1243 bool rejectX =
false;
1245 bool keepY = q->yflick();
1246 bool keepX = q->xflick();
1248 bool stealY =
false;
1249 bool stealX =
false;
1250 bool isTouchEvent =
false;
1251 switch (eventType) {
1252 case QEvent::MouseMove:
1253 stealX = stealY = stealGrab;
1256 stealX = stealY = scrollingPhase;
1258 case QEvent::TouchUpdate:
1259 stealX = stealY = stealGrab;
1260 isTouchEvent =
true;
1266 bool prevHMoved = hMoved;
1267 bool prevVMoved = vMoved;
1269 qint64 elapsedSincePress = currentTimestamp - lastPressTime;
1270 qCDebug(lcFlickable).nospace() << currentTimestamp <<
' ' << eventType <<
" drag @ " << localPos.x() <<
',' << localPos.y()
1271 <<
" \u0394 " << deltas.x() <<
',' << deltas.y() <<
" vel " << velocity.x() <<
',' << velocity.y()
1272 <<
" thrsld? " << overThreshold <<
" momentum? " << momentum <<
" velSens? " << velocitySensitiveOverBounds
1273 <<
" sincePress " << elapsedSincePress;
1276 qreal dy = deltas.y();
1277 if (overThreshold || elapsedSincePress > 200) {
1278 if (!vMoved && !vData.dragging)
1279 vData.dragStartOffset = dy;
1280 qreal newY = dy + vData.pressPos - (syncDrag ? 0 : vData.dragStartOffset);
1284 const qreal minY = vData.dragMinBound + vData.startMargin;
1285 const qreal maxY = vData.dragMaxBound - vData.endMargin;
1286 if (!(boundsBehavior & QQuickFlickable::DragOverBounds)) {
1287 if (fuzzyLessThanOrEqualTo(newY, maxY)) {
1289 rejectY = vData.pressPos == maxY && vData.move.value() == maxY && dy < 0;
1291 if (fuzzyLessThanOrEqualTo(minY, newY)) {
1293 rejectY |= vData.pressPos == minY && vData.move.value() == minY && dy > 0;
1297 if (vel > 0. && vel > vData.velocity)
1299 else if (vel < 0. && vel < vData.velocity)
1303 if (momentum && vData.atBeginning) {
1304 if (!vData.inRebound) {
1305 vData.inRebound =
true;
1306 q->returnToBounds();
1310 if (velocitySensitiveOverBounds) {
1313 newY = minY + overshoot;
1315 newY = minY + (newY - minY) / 2;
1317 }
else if (newY < maxY && maxY - minY <= 0) {
1319 if (momentum && vData.atEnd) {
1320 if (!vData.inRebound) {
1321 vData.inRebound =
true;
1322 q->returnToBounds();
1326 if (velocitySensitiveOverBounds) {
1329 newY = maxY - overshoot;
1331 newY = maxY + (newY - maxY) / 2;
1335 if (!rejectY && stealGrab && dy != vData.previousDragDelta) {
1337 vData.move.setValue(newY);
1340 if (!rejectY && overThreshold)
1343 if ((newY >= minY && vData.pressPos == minY && vData.move.value() == minY && dy > 0)
1344 || (newY <= maxY && vData.pressPos == maxY && vData.move.value() == maxY && dy < 0)) {
1348 vData.previousDragDelta = dy;
1352 qreal dx = deltas.x();
1353 if (overThreshold || elapsedSincePress > 200) {
1354 if (!hMoved && !hData.dragging)
1355 hData.dragStartOffset = dx;
1356 qreal newX = dx + hData.pressPos - (syncDrag ? 0 : hData.dragStartOffset);
1357 const qreal minX = hData.dragMinBound + hData.startMargin;
1358 const qreal maxX = hData.dragMaxBound - hData.endMargin;
1359 if (!(boundsBehavior & QQuickFlickable::DragOverBounds)) {
1360 if (fuzzyLessThanOrEqualTo(newX, maxX)) {
1362 rejectX = hData.pressPos == maxX && hData.move.value() == maxX && dx < 0;
1364 if (fuzzyLessThanOrEqualTo(minX, newX)) {
1366 rejectX |= hData.pressPos == minX && hData.move.value() == minX && dx > 0;
1370 if (vel > 0. && vel > hData.velocity)
1372 else if (vel < 0. && vel < hData.velocity)
1376 if (momentum && hData.atBeginning) {
1377 if (!hData.inRebound) {
1378 hData.inRebound =
true;
1379 q->returnToBounds();
1383 if (velocitySensitiveOverBounds) {
1386 newX = minX + overshoot;
1388 newX = minX + (newX - minX) / 2;
1390 }
else if (newX < maxX && maxX - minX <= 0) {
1392 if (momentum && hData.atEnd) {
1393 if (!hData.inRebound) {
1394 hData.inRebound =
true;
1395 q->returnToBounds();
1399 if (velocitySensitiveOverBounds) {
1402 newX = maxX - overshoot;
1404 newX = maxX + (newX - maxX) / 2;
1408 if (!rejectX && stealGrab && dx != hData.previousDragDelta) {
1410 hData.move.setValue(newX);
1414 if (!rejectX && overThreshold)
1417 if ((newX >= minX && vData.pressPos == minX && vData.move.value() == minX && dx > 0)
1418 || (newX <= maxX && vData.pressPos == maxX && vData.move.value() == maxX && dx < 0)) {
1422 hData.previousDragDelta = dx;
1425 stealGrab = stealX || stealY;
1427 if ((stealX && keepX) || (stealY && keepY)) {
1429 q->setKeepTouchGrab(
true);
1431 q->setKeepMouseGrab(
true);
1433 clearDelayedPress();
1437 vData.velocitySamples = 0;
1438 vData.velocityWritePos = 0;
1442 hData.velocitySamples = 0;
1443 hData.velocityWritePos = 0;
1447 if (momentum && !hData.flicking && !vData.flicking)
1448 flickingStarted(hData.velocity != 0, vData.velocity != 0);
1451 if ((hMoved && !prevHMoved) || (vMoved && !prevVMoved))
1452 q->movementStarting();
1454 lastPosTime = currentTimestamp;
1455 if (q->yflick() && !rejectY)
1456 vData.addVelocitySample(velocity.y(), maxVelocity);
1457 if (q->xflick() && !rejectX)
1458 hData.addVelocitySample(velocity.x(), maxVelocity);
1462void QQuickFlickablePrivate::handleMoveEvent(QPointerEvent *event)
1464 Q_Q(QQuickFlickable);
1465 if (!interactive || lastPosTime == -1 ||
1466 (event->isSinglePointEvent() && !buttonsAccepted(
static_cast<QSinglePointEvent *>(event))))
1469 qint64 currentTimestamp = computeCurrentTime(event);
1470 const auto &firstPoint = event->points().first();
1471 const auto &pos = firstPoint.position();
1472 const QVector2D deltas = QVector2D(pos - q->mapFromGlobal(firstPoint.globalPressPosition()));
1473 const QVector2D velocity = firstPointLocalVelocity(event);
1474 bool overThreshold =
false;
1476 if (q->isMoving()) {
1478
1479
1480
1481
1482
1483
1484
1485 overThreshold =
true;
1486 }
else if (event->pointCount() == 1) {
1488 overThreshold |= QQuickDeliveryAgentPrivate::dragOverThreshold(deltas.y(), Qt::YAxis, firstPoint);
1490 overThreshold |= QQuickDeliveryAgentPrivate::dragOverThreshold(deltas.x(), Qt::XAxis, firstPoint);
1492 qCDebug(lcFilter) << q->objectName() <<
"ignoring multi-touch" << event;
1495 drag(currentTimestamp, event->type(), pos, deltas, overThreshold,
false,
false, velocity);
1498void QQuickFlickablePrivate::handleReleaseEvent(QPointerEvent *event)
1500 Q_Q(QQuickFlickable);
1502 q->setKeepMouseGrab(
false);
1503 q->setKeepTouchGrab(
false);
1507 qint64 elapsed = computeCurrentTime(event) - lastPosTime;
1509 vData.updateVelocity();
1510 hData.updateVelocity();
1514 if (lastPosTime == -1)
1517 hData.vTime = vData.vTime = timeline.time();
1519 bool canBoost =
false;
1520 const auto pos = event->points().first().position();
1521 const auto pressPos = q->mapFromGlobal(event->points().first().globalPressPosition());
1522 const QVector2D eventVelocity = firstPointLocalVelocity(event);
1523 qCDebug(lcVel) << event->deviceType() << event->type() <<
"velocity" << event->points().first().velocity() <<
"transformed to local" << eventVelocity;
1525 qreal vVelocity = 0;
1526 if (elapsed < 100 && vData.velocity != 0.) {
1527 vVelocity = (event->device()->capabilities().testFlag(QInputDevice::Capability::Velocity)
1528 ? eventVelocity.y() : vData.velocity);
1530 if ((vData.atBeginning && vVelocity > 0.) || (vData.atEnd && vVelocity < 0.)) {
1532 }
else if (vData.continuousFlickVelocity != 0.0
1534 && ((vVelocity > 0) == (vData.continuousFlickVelocity > 0))
1540 qreal hVelocity = 0;
1541 if (elapsed < 100 && hData.velocity != 0.) {
1542 hVelocity = (event->device()->capabilities().testFlag(QInputDevice::Capability::Velocity)
1543 ? eventVelocity.x() : hData.velocity);
1545 if ((hData.atBeginning && hVelocity > 0.) || (hData.atEnd && hVelocity < 0.)) {
1547 }
else if (hData.continuousFlickVelocity != 0.0
1549 && ((hVelocity > 0) == (hData.continuousFlickVelocity > 0))
1556 const int flickThreshold = QGuiApplicationPrivate::platformTheme()->themeHint(QPlatformTheme::FlickStartDistance).toInt();
1558 bool anyPointGrabbed = event->points().constEnd() !=
1559 std::find_if(event->points().constBegin(),event->points().constEnd(),
1560 [q, event](
const QEventPoint &point) {
return event->exclusiveGrabber(point) == q; });
1562 bool flickedVertically =
false;
1563 vVelocity *= flickBoost;
1564 const bool isVerticalFlickAllowed = anyPointGrabbed &&
1565 q->yflick() && qAbs(vVelocity) > _q_MinimumFlickVelocity &&
1566 qAbs(pos.y() - pressPos.y()) > flickThreshold;
1567 if (isVerticalFlickAllowed) {
1568 velocityTimeline.reset(vData.smoothVelocity);
1569 vData.smoothVelocity.setValue(-vVelocity);
1570 flickedVertically = flickY(event->type(), vVelocity);
1573 bool flickedHorizontally =
false;
1574 hVelocity *= flickBoost;
1575 const bool isHorizontalFlickAllowed = anyPointGrabbed &&
1576 q->xflick() && qAbs(hVelocity) > _q_MinimumFlickVelocity &&
1577 qAbs(pos.x() - pressPos.x()) > flickThreshold;
1578 if (isHorizontalFlickAllowed) {
1579 velocityTimeline.reset(hData.smoothVelocity);
1580 hData.smoothVelocity.setValue(-hVelocity);
1581 flickedHorizontally = flickX(event->type(), hVelocity);
1584 if (!isVerticalFlickAllowed)
1587 if (!isHorizontalFlickAllowed)
1590 flickingStarted(flickedHorizontally, flickedVertically);
1591 if (!isViewMoving()) {
1592 q->movementEnding();
1594 if (flickedVertically)
1596 if (flickedHorizontally)
1598 q->movementStarting();
1602bool QQuickFlickablePrivate::buttonsAccepted(
const QSinglePointEvent *event)
1604 return !((event->button() & acceptedButtons) == 0 && (event->buttons() & acceptedButtons) == 0);
1607void QQuickFlickable::mousePressEvent(QMouseEvent *event)
1609 Q_D(QQuickFlickable);
1610 if (d->interactive && !d->replayingPressEvent && d->buttonsAccepted(event) && d->wantsPointerEvent(event)) {
1612 d->handlePressEvent(event);
1615 QQuickItem::mousePressEvent(event);
1619void QQuickFlickable::mouseMoveEvent(QMouseEvent *event)
1621 Q_D(QQuickFlickable);
1622 if (d->interactive && d->buttonsAccepted(event) && d->wantsPointerEvent(event)) {
1623 d->handleMoveEvent(event);
1626 QQuickItem::mouseMoveEvent(event);
1630void QQuickFlickable::mouseReleaseEvent(QMouseEvent *event)
1632 Q_D(QQuickFlickable);
1633 if (d->interactive && d->buttonsAccepted(event) && d->wantsPointerEvent(event)) {
1634 if (d->delayedPressEvent) {
1635 d->replayDelayedPress();
1637 auto &firstPoint = event->point(0);
1638 if (
const auto *grabber = event->exclusiveGrabber(firstPoint); grabber && grabber->isQuickItemType()) {
1641 const auto oldPosition = firstPoint.position();
1642 QMutableEventPoint::setPosition(firstPoint, event->scenePosition());
1643 QCoreApplication::sendEvent(window(), event);
1644 QMutableEventPoint::setPosition(firstPoint, oldPosition);
1648 d->stealGrab =
false;
1653 d->handleReleaseEvent(event);
1656 QQuickItem::mouseReleaseEvent(event);
1660void QQuickFlickable::touchEvent(QTouchEvent *event)
1662 Q_D(QQuickFlickable);
1664 if (event->type() == QEvent::TouchCancel) {
1665 if (d->interactive && d->wantsPointerEvent(event))
1666 d->cancelInteraction();
1668 QQuickItem::touchEvent(event);
1672 bool unhandled =
false;
1673 const auto &firstPoint = event->points().first();
1674 switch (firstPoint.state()) {
1675 case QEventPoint::State::Pressed:
1676 if (d->interactive && !d->replayingPressEvent && d->wantsPointerEvent(event)) {
1678 d->handlePressEvent(event);
1684 case QEventPoint::State::Updated:
1685 if (d->interactive && d->wantsPointerEvent(event)) {
1686 d->handleMoveEvent(event);
1692 case QEventPoint::State::Released:
1693 if (d->interactive && d->wantsPointerEvent(event)) {
1694 if (d->delayedPressEvent) {
1695 d->replayDelayedPress();
1697 const auto &firstPoint = event->point(0);
1698 if (
const auto *grabber = event->exclusiveGrabber(firstPoint); grabber && grabber->isQuickItemType()) {
1700 QScopedPointer<QPointerEvent> localizedEvent(
1701 QQuickDeliveryAgentPrivate::clonePointerEvent(event, firstPoint.scenePosition()));
1702 QCoreApplication::sendEvent(window(), localizedEvent.data());
1706 d->stealGrab =
false;
1711 d->handleReleaseEvent(event);
1717 case QEventPoint::State::Stationary:
1718 case QEventPoint::State::Unknown:
1722 QQuickItem::touchEvent(event);
1725#if QT_CONFIG(wheelevent)
1726void QQuickFlickable::wheelEvent(QWheelEvent *event)
1728 Q_D(QQuickFlickable);
1729 if (!d->interactive || !d->wantsPointerEvent(event)) {
1730 QQuickItem::wheelEvent(event);
1733 qCDebug(lcWheel) << event->device() << event << event->source();
1734 event->setAccepted(
false);
1735 qint64 currentTimestamp = d->computeCurrentTime(event);
1736 switch (event->phase()) {
1737 case Qt::ScrollBegin:
1738 d->scrollingPhase =
true;
1739 d->accumulatedWheelPixelDelta = QVector2D();
1740 d->vData.velocity = 0;
1741 d->hData.velocity = 0;
1743 d->maybeBeginDrag(currentTimestamp, event->position());
1744 d->lastPosTime = -1;
1746 case Qt::NoScrollPhase:
1747 case Qt::ScrollUpdate:
1748 if (d->scrollingPhase)
1751 case Qt::ScrollMomentum:
1753 d->scrollingPhase =
false;
1754 d->draggingEnding();
1757 d->lastPosTime = -1;
1761 d->scrollingPhase =
false;
1762 d->draggingEnding();
1764 d->lastPosTime = -1;
1765 d->stealGrab =
false;
1766 if (!d->velocityTimeline.isActive() && !d->timeline.isActive())
1767 movementEnding(
true,
true);
1771 qreal elapsed = qreal(currentTimestamp - d->lastPosTime) / qreal(1000);
1773 d->lastPosTime = currentTimestamp;
1774 qCDebug(lcWheel) <<
"insufficient elapsed time: can't calculate velocity" << elapsed;
1778 if (event->source() == Qt::MouseEventNotSynthesized || event->pixelDelta().isNull() || event->phase() == Qt::NoScrollPhase) {
1780 int xDelta = event->angleDelta().x();
1781 int yDelta = event->angleDelta().y();
1783 if (d->wheelDeceleration > _q_MaximumWheelDeceleration) {
1784 const qreal wheelScroll = -qApp->styleHints()->wheelScrollLines() * 24;
1787 if (yflick() && yDelta != 0) {
1788 d->moveReason = QQuickFlickablePrivate::Mouse;
1790 qreal scrollPixel = (-yDelta / 120.0 * wheelScroll);
1791 bool acceptEvent =
true;
1792 if (scrollPixel > 0) {
1793 if (d->vData.move.value() >= minYExtent()) {
1795 acceptEvent =
false;
1798 if (d->vData.move.value() <= maxYExtent()) {
1800 acceptEvent =
false;
1804 if (d->boundsBehavior == QQuickFlickable::StopAtBounds) {
1805 const qreal estContentPos = scrollPixel + d->vData.move.value();
1806 if (scrollPixel > 0) {
1807 if (estContentPos > minYExtent()) {
1808 scrollPixel = minYExtent() - d->vData.move.value();
1809 acceptEvent =
false;
1812 if (estContentPos < maxYExtent()) {
1813 scrollPixel = maxYExtent() - d->vData.move.value();
1814 acceptEvent =
false;
1818 d->resetTimeline(d->vData);
1820 d->timeline.moveBy(d->vData.move, scrollPixel, QEasingCurve(QEasingCurve::OutExpo), 3*d->fixupDuration/4);
1821 d->vData.fixingUp =
true;
1822 d->timeline.callback(QQuickTimeLineCallback(&d->vData.move, QQuickFlickablePrivate::fixupY_callback, d));
1827 if (xflick() && xDelta != 0) {
1828 d->moveReason = QQuickFlickablePrivate::Mouse;
1830 qreal scrollPixel = (-xDelta / 120.0 * wheelScroll);
1831 bool acceptEvent =
true;
1832 if (scrollPixel > 0) {
1833 if (d->hData.move.value() >= minXExtent()) {
1835 acceptEvent =
false;
1838 if (d->hData.move.value() <= maxXExtent()) {
1840 acceptEvent =
false;
1844 if (d->boundsBehavior == QQuickFlickable::StopAtBounds) {
1845 const qreal estContentPos = scrollPixel + d->hData.move.value();
1846 if (scrollPixel > 0) {
1847 if (estContentPos > minXExtent()) {
1848 scrollPixel = minXExtent() - d->hData.move.value();
1849 acceptEvent =
false;
1852 if (estContentPos < maxXExtent()) {
1853 scrollPixel = maxXExtent() - d->hData.move.value();
1854 acceptEvent =
false;
1858 d->resetTimeline(d->hData);
1860 d->timeline.moveBy(d->hData.move, scrollPixel, QEasingCurve(QEasingCurve::OutExpo), 3*d->fixupDuration/4);
1861 d->hData.fixingUp =
true;
1862 d->timeline.callback(QQuickTimeLineCallback(&d->hData.move, QQuickFlickablePrivate::fixupX_callback, d));
1878 elapsed = 120 / qSqrt(d->wheelDeceleration * 2 * d->initialWheelFlickDistance);
1879 if (yflick() && yDelta != 0) {
1880 qreal instVelocity = yDelta / elapsed;
1882 if ((instVelocity < 0 && d->vData.velocity > 0) || (instVelocity > 0 && d->vData.velocity < 0)) {
1883 d->vData.velocitySamples = 0;
1884 d->vData.velocityWritePos = 0;
1886 d->vData.addVelocitySample(instVelocity, d->maxVelocity);
1887 d->vData.updateVelocity();
1888 if ((yDelta > 0 && contentY() > -minYExtent()) || (yDelta < 0 && contentY() < -maxYExtent())) {
1889 const bool newFlick = d->flickY(event->type(), d->vData.velocity);
1890 if (newFlick && (d->vData.atBeginning != (yDelta > 0) || d->vData.atEnd != (yDelta < 0))) {
1891 d->flickingStarted(
false,
true);
1898 if (xflick() && xDelta != 0) {
1899 qreal instVelocity = xDelta / elapsed;
1901 if ((instVelocity < 0 && d->hData.velocity > 0) || (instVelocity > 0 && d->hData.velocity < 0)) {
1902 d->hData.velocitySamples = 0;
1903 d->hData.velocityWritePos = 0;
1905 d->hData.addVelocitySample(instVelocity, d->maxVelocity);
1906 d->hData.updateVelocity();
1907 if ((xDelta > 0 && contentX() > -minXExtent()) || (xDelta < 0 && contentX() < -maxXExtent())) {
1908 const bool newFlick = d->flickX(event->type(), d->hData.velocity);
1909 if (newFlick && (d->hData.atBeginning != (xDelta > 0) || d->hData.atEnd != (xDelta < 0))) {
1910 d->flickingStarted(
true,
false);
1920 int xDelta = event->pixelDelta().x();
1921 int yDelta = event->pixelDelta().y();
1923 QVector2D velocity(xDelta / elapsed, yDelta / elapsed);
1924 d->accumulatedWheelPixelDelta += QVector2D(event->pixelDelta());
1930 if (isMoving() || isFlicking() || (yflick() && xflick())
1931 || (xflick() && qAbs(d->accumulatedWheelPixelDelta.x()) > qAbs(d->accumulatedWheelPixelDelta.y() * 2))
1932 || (yflick() && qAbs(d->accumulatedWheelPixelDelta.y()) > qAbs(d->accumulatedWheelPixelDelta.x() * 2))) {
1933 d->drag(currentTimestamp, event->type(), event->position(), d->accumulatedWheelPixelDelta,
1934 true, !d->scrollingPhase,
true, velocity);
1935 d->updateBeginningEnd();
1936 if ((xflick() && !isAtXBeginning() && !isAtXEnd()) || (yflick() && !isAtYBeginning() && !isAtYEnd()))
1939 qCDebug(lcWheel) <<
"not dragging: accumulated deltas" << d->accumulatedWheelPixelDelta <<
1940 "moving?" << isMoving() <<
"can flick horizontally?" << xflick() <<
"vertically?" << yflick();
1943 d->lastPosTime = currentTimestamp;
1945 if (!event->isAccepted())
1946 QQuickItem::wheelEvent(event);
1950bool QQuickFlickablePrivate::isInnermostPressDelay(QQuickItem *i)
const
1952 Q_Q(
const QQuickFlickable);
1953 QQuickItem *item = i;
1955 QQuickFlickable *flick = qobject_cast<QQuickFlickable*>(item);
1956 if (flick && flick->pressDelay() > 0 && flick->isInteractive()) {
1958 return (flick == q);
1960 item = item->parentItem();
1965void QQuickFlickablePrivate::captureDelayedPress(QQuickItem *item, QPointerEvent *event)
1967 Q_Q(QQuickFlickable);
1968 if (!q->window() || pressDelay <= 0)
1973 if (!isInnermostPressDelay(item))
1976 delayedPressEvent = QQuickDeliveryAgentPrivate::clonePointerEvent(event);
1977 delayedPressEvent->setAccepted(
false);
1978 delayedPressTimer.start(pressDelay, q);
1979 qCDebug(lcReplay) <<
"begin press delay" << pressDelay <<
"ms with" << delayedPressEvent;
1982void QQuickFlickablePrivate::clearDelayedPress()
1984 if (delayedPressEvent) {
1985 delayedPressTimer.stop();
1986 qCDebug(lcReplay) <<
"clear delayed press" << delayedPressEvent;
1987 delete delayedPressEvent;
1988 delayedPressEvent =
nullptr;
1992void QQuickFlickablePrivate::replayDelayedPress()
1994 Q_Q(QQuickFlickable);
1995 if (delayedPressEvent) {
1997 QScopedPointer<QPointerEvent> event(delayedPressEvent);
1998 delayedPressEvent =
nullptr;
1999 delayedPressTimer.stop();
2002 if (QQuickWindow *window = q->window()) {
2003 auto da = deliveryAgentPrivate();
2004 da->allowChildEventFiltering =
false;
2005 replayingPressEvent =
true;
2006 auto &firstPoint = event->point(0);
2012 if (event->exclusiveGrabber(firstPoint) == q)
2013 event->setExclusiveGrabber(firstPoint,
nullptr);
2015 qCDebug(lcReplay) <<
"replaying" << event.data();
2018 QMutableEventPoint::setPosition(firstPoint, firstPoint.scenePosition());
2022 QCoreApplication::sendEvent(window, event.data());
2023 qCDebug(lcReplay) <<
"replay done";
2026 replayingPressEvent =
false;
2027 da->allowChildEventFiltering =
true;
2035
2036
2037
2038
2039
2040
2041
2042void QQuickFlickablePrivate::setViewportX(qreal x)
2044 Q_Q(QQuickFlickable);
2045 qreal effectiveX = pixelAligned ? -std::round(-x) : x;
2047 const qreal maxX = q->maxXExtent();
2048 const qreal minX = q->minXExtent();
2050 if (boundsMovement ==
int(QQuickFlickable::StopAtBounds))
2051 effectiveX = qBound(maxX, effectiveX, minX);
2053 contentItem->setX(effectiveX);
2054 if (contentItem->x() != effectiveX)
2057 qreal overshoot = 0.0;
2059 overshoot = maxX - x;
2061 overshoot = minX - x;
2063 if (overshoot != hData.overshoot) {
2064 hData.overshoot = overshoot;
2065 emit q->horizontalOvershootChanged();
2070
2071
2072
2073
2074
2075
2076
2077void QQuickFlickablePrivate::setViewportY(qreal y)
2079 Q_Q(QQuickFlickable);
2080 qreal effectiveY = pixelAligned ? -std::round(-y) : y;
2082 const qreal maxY = q->maxYExtent();
2083 const qreal minY = q->minYExtent();
2085 if (boundsMovement ==
int(QQuickFlickable::StopAtBounds))
2086 effectiveY = qBound(maxY, effectiveY, minY);
2088 contentItem->setY(effectiveY);
2089 if (contentItem->y() != effectiveY)
2092 qreal overshoot = 0.0;
2094 overshoot = maxY - y;
2096 overshoot = minY - y;
2098 if (overshoot != vData.overshoot) {
2099 vData.overshoot = overshoot;
2100 emit q->verticalOvershootChanged();
2104void QQuickFlickable::timerEvent(QTimerEvent *event)
2106 Q_D(QQuickFlickable);
2107 if (event->timerId() == d->delayedPressTimer.timerId()) {
2108 d->delayedPressTimer.stop();
2109 if (d->delayedPressEvent) {
2110 d->replayDelayedPress();
2115qreal QQuickFlickable::minYExtent()
const
2117 Q_D(
const QQuickFlickable);
2118 return d->vData.startMargin;
2121qreal QQuickFlickable::minXExtent()
const
2123 Q_D(
const QQuickFlickable);
2124 return d->hData.startMargin;
2128qreal QQuickFlickable::maxXExtent()
const
2130 Q_D(
const QQuickFlickable);
2131 return qMin<qreal>(minXExtent(), width() - vWidth() - d->hData.endMargin);
2134qreal QQuickFlickable::maxYExtent()
const
2136 Q_D(
const QQuickFlickable);
2137 return qMin<qreal>(minYExtent(), height() - vHeight() - d->vData.endMargin);
2140void QQuickFlickable::componentComplete()
2142 Q_D(QQuickFlickable);
2143 QQuickItem::componentComplete();
2144 if (!d->hData.explicitValue && d->hData.startMargin != 0.)
2145 setContentX(-minXExtent());
2146 if (!d->vData.explicitValue && d->vData.startMargin != 0.)
2147 setContentY(-minYExtent());
2148 if (lcWheel().isDebugEnabled() || lcVel().isDebugEnabled()) {
2149 d->timeline.setObjectName(QLatin1String(
"timeline for Flickable ") + objectName());
2150 d->velocityTimeline.setObjectName(QLatin1String(
"velocity timeline for Flickable ") + objectName());
2154void QQuickFlickable::viewportMoved(Qt::Orientations orient)
2156 Q_D(QQuickFlickable);
2157 if (orient & Qt::Vertical)
2158 d->viewportAxisMoved(d->vData, minYExtent(), maxYExtent(), d->fixupY_callback);
2159 if (orient & Qt::Horizontal)
2160 d->viewportAxisMoved(d->hData, minXExtent(), maxXExtent(), d->fixupX_callback);
2161 d->updateBeginningEnd();
2164void QQuickFlickablePrivate::viewportAxisMoved(AxisData &data, qreal minExtent, qreal maxExtent,
2165 QQuickTimeLineCallback::Callback fixupCallback)
2167 if (!scrollingPhase && (pressed || calcVelocity)) {
2168 int elapsed = data.velocityTime.restart();
2170 qreal velocity = (data.lastPos - data.move.value()) * 1000 / elapsed;
2171 if (qAbs(velocity) > 0) {
2172 velocityTimeline.reset(data.smoothVelocity);
2173 velocityTimeline.set(data.smoothVelocity, velocity);
2174 qCDebug(lcVel) <<
"touchpad scroll phase: velocity" << velocity;
2178 if (timeline.time() > data.vTime) {
2179 velocityTimeline.reset(data.smoothVelocity);
2180 int dt = timeline.time() - data.vTime;
2182 qreal velocity = (data.lastPos - data.move.value()) * 1000 / dt;
2183 if (!qFuzzyCompare(data.smoothVelocity.value(), velocity))
2184 qCDebug(lcVel) <<
"velocity" << data.smoothVelocity.value() <<
"->" << velocity
2185 <<
"computed as (" << data.lastPos <<
"-" << data.move.value() <<
") * 1000 / ("
2186 << timeline.time() <<
"-" << data.vTime <<
")";
2187 data.smoothVelocity.setValue(velocity);
2192 if (!data.inOvershoot && !data.fixingUp && data.flicking
2193 && (data.move.value() > minExtent || data.move.value() < maxExtent)
2194 && qAbs(data.smoothVelocity.value()) > 10) {
2196 qreal overBound = data.move.value() > minExtent
2197 ? data.move.value() - minExtent
2198 : maxExtent - data.move.value();
2199 data.inOvershoot =
true;
2200 qreal maxDistance = overShootDistance(qAbs(data.smoothVelocity.value())) - overBound;
2201 resetTimeline(data);
2202 if (maxDistance > 0)
2204 timeline.callback(QQuickTimeLineCallback(&data.move, fixupCallback,
this));
2207 data.lastPos = data.move.value();
2208 data.vTime = timeline.time();
2211void QQuickFlickable::geometryChange(
const QRectF &newGeometry,
const QRectF &oldGeometry)
2213 Q_D(QQuickFlickable);
2214 QQuickItem::geometryChange(newGeometry, oldGeometry);
2216 bool changed =
false;
2217 if (newGeometry.width() != oldGeometry.width()) {
2219 if (d->hData.viewSize < 0)
2220 d->contentItem->setWidth(width() - d->hData.startMargin - d->hData.endMargin);
2222 if (!d->pressed && !d->hData.moving && !d->vData.moving) {
2223 d->fixupMode = QQuickFlickablePrivate::Immediate;
2227 if (newGeometry.height() != oldGeometry.height()) {
2229 if (d->vData.viewSize < 0)
2230 d->contentItem->setHeight(height() - d->vData.startMargin - d->vData.endMargin);
2232 if (!d->pressed && !d->hData.moving && !d->vData.moving) {
2233 d->fixupMode = QQuickFlickablePrivate::Immediate;
2239 d->updateBeginningEnd();
2243
2244
2245
2246
2247
2248
2249
2251void QQuickFlickable::flick(qreal xVelocity, qreal yVelocity)
2253 Q_D(QQuickFlickable);
2256 d->hData.velocity = xVelocity;
2257 d->vData.velocity = yVelocity;
2258 d->hData.vTime = d->vData.vTime = d->timeline.time();
2260 const bool flickedX = xflick() && !qFuzzyIsNull(xVelocity) && d->flickX(QEvent::TouchUpdate, xVelocity);
2261 const bool flickedY = yflick() && !qFuzzyIsNull(yVelocity) && d->flickY(QEvent::TouchUpdate, yVelocity);
2268 d->flickingStarted(flickedX, flickedY);
2271void QQuickFlickablePrivate::flickingStarted(
bool flickingH,
bool flickingV)
2273 Q_Q(QQuickFlickable);
2274 if (!flickingH && !flickingV)
2277 bool wasFlicking = hData.flicking || vData.flicking;
2278 if (flickingH && !hData.flicking) {
2279 hData.flicking =
true;
2280 emit q->flickingHorizontallyChanged();
2282 if (flickingV && !vData.flicking) {
2283 vData.flicking =
true;
2284 emit q->flickingVerticallyChanged();
2286 if (!wasFlicking && (hData.flicking || vData.flicking)) {
2287 emit q->flickingChanged();
2288 emit q->flickStarted();
2293
2294
2295
2296
2298void QQuickFlickable::cancelFlick()
2300 Q_D(QQuickFlickable);
2301 d->resetTimeline(d->hData);
2302 d->resetTimeline(d->vData);
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2339void QQuickFlickable::positionViewAtChild(QQuickItem *child, PositionMode mode,
const QPointF &offset)
2341 Q_D(QQuickFlickable);
2344 if (!d->contentItem->isAncestorOf(child))
2347 const QRectF itemRect =
2348 child->mapRectToItem(d->contentItem, QRectF(0, 0, child->width(), child->height()));
2350 QPointF currentPosition = QPointF(contentX(), contentY());
2351 QPointF newPosition = computePosition(currentPosition, itemRect, mode, offset);
2353 if (newPosition.x() != currentPosition.x()) {
2354 setContentX(newPosition.x());
2357 if (newPosition.y() != currentPosition.y()) {
2358 setContentY(newPosition.y());
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2395void QQuickFlickable::flickToChild(QQuickItem *child, PositionMode mode,
const QPointF &offset)
2397 Q_D(QQuickFlickable);
2400 if (!d->contentItem->isAncestorOf(child))
2403 const QRectF itemRect =
2404 child->mapRectToItem(d->contentItem, QRectF(0, 0, child->width(), child->height()));
2406 QPointF currentPosition = QPointF(contentX(), contentY());
2407 QPointF newPosition = computePosition(currentPosition, itemRect, mode, offset);
2409 flickTo(newPosition);
2413
2414
2415
2416
2417
2418
2419
2420
2422void QQuickFlickable::flickTo(
const QPointF &newPosition)
2424 Q_D(QQuickFlickable);
2426 QPointF currentPosition = QPointF(contentX(), contentY());
2428 qreal xVelocity = 0.0;
2429 qreal yVelocity = 0.0;
2431 const qreal deltaX = newPosition.x() - currentPosition.x();
2432 const qreal deltaY = newPosition.y() - currentPosition.y();
2437 if (xflick() && qAbs(deltaX) > 0.5) {
2438 const qreal decel = flickDeceleration();
2439 qreal velocity = qSqrt(2.0 * decel * qAbs(deltaX));
2440 if (qAbs(velocity) < _q_MinimumFlickVelocity)
2442 const qreal maxVel = maximumFlickVelocity();
2443 if (maxVel > 0 && velocity > maxVel)
2445 xVelocity = deltaX > 0 ? -velocity : velocity;
2448 if (yflick() && qAbs(deltaY) > 0.5) {
2449 const qreal decel = flickDeceleration();
2450 qreal velocity = qSqrt(2.0 * decel * qAbs(deltaY));
2451 if (qAbs(velocity) < _q_MinimumFlickVelocity)
2453 const qreal maxVel = maximumFlickVelocity();
2454 if (maxVel > 0 && velocity > maxVel)
2456 yVelocity = deltaY > 0 ? -velocity : velocity;
2459 if (qAbs(xVelocity) > 0.0 || qAbs(yVelocity) > 0.0) {
2460 flick(xVelocity, yVelocity);
2462 if (newPosition.x() != currentPosition.x()) {
2463 setContentX(newPosition.x());
2466 if (newPosition.y() != currentPosition.y()) {
2467 setContentY(newPosition.y());
2473void QQuickFlickablePrivate::data_append(QQmlListProperty<QObject> *prop, QObject *o)
2475 if (!prop || !prop->data)
2478 if (QQuickItem *i = qmlobject_cast<QQuickItem *>(o)) {
2479 i->setParentItem(
static_cast<QQuickFlickablePrivate*>(prop->data)->contentItem);
2480 }
else if (QQuickPointerHandler *pointerHandler = qmlobject_cast<QQuickPointerHandler *>(o)) {
2481 static_cast<QQuickFlickablePrivate*>(prop->data)->addPointerHandler(pointerHandler);
2483 o->setParent(prop->object);
2487qsizetype QQuickFlickablePrivate::data_count(QQmlListProperty<QObject> *)
2493QObject *QQuickFlickablePrivate::data_at(QQmlListProperty<QObject> *, qsizetype)
2499void QQuickFlickablePrivate::data_clear(QQmlListProperty<QObject> *)
2504QQmlListProperty<QObject> QQuickFlickable::flickableData()
2506 Q_D(QQuickFlickable);
2507 return QQmlListProperty<QObject>(
this, (
void *)d, QQuickFlickablePrivate::data_append,
2508 QQuickFlickablePrivate::data_count,
2509 QQuickFlickablePrivate::data_at,
2510 QQuickFlickablePrivate::data_clear);
2513QQmlListProperty<QQuickItem> QQuickFlickable::flickableChildren()
2515 Q_D(QQuickFlickable);
2516 return QQuickItemPrivate::get(d->contentItem)->children();
2520
2521
2522
2523
2524
2525
2526
2527
2528
2529
2530
2531
2532
2533
2534
2535
2536
2537
2538
2539
2540
2541
2542
2543
2544
2545QQuickFlickable::BoundsBehavior QQuickFlickable::boundsBehavior()
const
2547 Q_D(
const QQuickFlickable);
2548 return d->boundsBehavior;
2551void QQuickFlickable::setBoundsBehavior(BoundsBehavior b)
2553 Q_D(QQuickFlickable);
2554 if (b == d->boundsBehavior)
2556 d->boundsBehavior = b;
2557 emit boundsBehaviorChanged();
2561
2562
2563
2564
2565
2566
2567
2568
2569
2570
2571
2572
2573
2574
2575
2576
2577
2578
2579
2580
2581
2582
2583
2584
2585
2586
2587
2588
2589
2590
2591
2592
2593
2594
2595
2596
2597
2598
2599
2600
2601QQuickTransition *QQuickFlickable::rebound()
const
2603 Q_D(
const QQuickFlickable);
2607void QQuickFlickable::setRebound(QQuickTransition *transition)
2609 Q_D(QQuickFlickable);
2611 if (!d->hData.transitionToBounds)
2612 d->hData.transitionToBounds =
new QQuickFlickableReboundTransition(
this, QLatin1String(
"x"));
2613 if (!d->vData.transitionToBounds)
2614 d->vData.transitionToBounds =
new QQuickFlickableReboundTransition(
this, QLatin1String(
"y"));
2616 if (d->rebound != transition) {
2617 d->rebound = transition;
2618 emit reboundChanged();
2623
2624
2625
2626
2627
2628
2629
2630
2631
2632
2633
2634
2635
2636
2637
2638
2639
2640
2641
2642
2643
2644
2645
2646qreal QQuickFlickable::contentWidth()
const
2648 Q_D(
const QQuickFlickable);
2649 return d->hData.viewSize;
2652void QQuickFlickable::setContentWidth(qreal w)
2654 Q_D(QQuickFlickable);
2655 if (d->hData.viewSize == w)
2657 d->hData.viewSize = w;
2659 d->contentItem->setWidth(width() - d->hData.startMargin - d->hData.endMargin);
2661 d->contentItem->setWidth(w);
2662 d->hData.markExtentsDirty();
2664 if (!d->pressed && !d->hData.moving && !d->vData.moving) {
2665 d->fixupMode = QQuickFlickablePrivate::Immediate;
2667 }
else if (!d->pressed && d->hData.fixingUp) {
2668 d->fixupMode = QQuickFlickablePrivate::ExtentChanged;
2671 emit contentWidthChanged();
2672 d->updateBeginningEnd();
2675qreal QQuickFlickable::contentHeight()
const
2677 Q_D(
const QQuickFlickable);
2678 return d->vData.viewSize;
2681void QQuickFlickable::setContentHeight(qreal h)
2683 Q_D(QQuickFlickable);
2684 if (d->vData.viewSize == h)
2686 d->vData.viewSize = h;
2688 d->contentItem->setHeight(height() - d->vData.startMargin - d->vData.endMargin);
2690 d->contentItem->setHeight(h);
2691 d->vData.markExtentsDirty();
2693 if (!d->pressed && !d->hData.moving && !d->vData.moving) {
2694 d->fixupMode = QQuickFlickablePrivate::Immediate;
2696 }
else if (!d->pressed && d->vData.fixingUp) {
2697 d->fixupMode = QQuickFlickablePrivate::ExtentChanged;
2700 emit contentHeightChanged();
2701 d->updateBeginningEnd();
2705
2706
2707
2708
2709
2710
2711
2712
2715qreal QQuickFlickable::topMargin()
const
2717 Q_D(
const QQuickFlickable);
2718 return d->vData.startMargin;
2721void QQuickFlickable::setTopMargin(qreal m)
2723 Q_D(QQuickFlickable);
2724 if (d->vData.startMargin == m)
2726 d->vData.startMargin = m;
2727 d->vData.markExtentsDirty();
2728 if (!d->pressed && !d->hData.moving && !d->vData.moving) {
2730 d->fixupMode = QQuickFlickablePrivate::Immediate;
2733 emit topMarginChanged();
2734 d->updateBeginningEnd();
2737qreal QQuickFlickable::bottomMargin()
const
2739 Q_D(
const QQuickFlickable);
2740 return d->vData.endMargin;
2743void QQuickFlickable::setBottomMargin(qreal m)
2745 Q_D(QQuickFlickable);
2746 if (d->vData.endMargin == m)
2748 d->vData.endMargin = m;
2749 d->vData.markExtentsDirty();
2750 if (!d->pressed && !d->hData.moving && !d->vData.moving) {
2752 d->fixupMode = QQuickFlickablePrivate::Immediate;
2755 emit bottomMarginChanged();
2756 d->updateBeginningEnd();
2759qreal QQuickFlickable::leftMargin()
const
2761 Q_D(
const QQuickFlickable);
2762 return d->hData.startMargin;
2765void QQuickFlickable::setLeftMargin(qreal m)
2767 Q_D(QQuickFlickable);
2768 if (d->hData.startMargin == m)
2770 d->hData.startMargin = m;
2771 d->hData.markExtentsDirty();
2772 if (!d->pressed && !d->hData.moving && !d->vData.moving) {
2774 d->fixupMode = QQuickFlickablePrivate::Immediate;
2777 emit leftMarginChanged();
2778 d->updateBeginningEnd();
2781qreal QQuickFlickable::rightMargin()
const
2783 Q_D(
const QQuickFlickable);
2784 return d->hData.endMargin;
2787void QQuickFlickable::setRightMargin(qreal m)
2789 Q_D(QQuickFlickable);
2790 if (d->hData.endMargin == m)
2792 d->hData.endMargin = m;
2793 d->hData.markExtentsDirty();
2794 if (!d->pressed && !d->hData.moving && !d->vData.moving) {
2796 d->fixupMode = QQuickFlickablePrivate::Immediate;
2799 emit rightMarginChanged();
2800 d->updateBeginningEnd();
2804
2805
2806
2807
2808
2809
2810
2811
2812
2813
2814
2815
2817qreal QQuickFlickable::originY()
const
2819 Q_D(
const QQuickFlickable);
2820 return -minYExtent() + d->vData.startMargin;
2823qreal QQuickFlickable::originX()
const
2825 Q_D(
const QQuickFlickable);
2826 return -minXExtent() + d->hData.startMargin;
2831
2832
2833
2834
2835
2836
2837
2838
2839
2840
2841
2842void QQuickFlickable::resizeContent(qreal w, qreal h, QPointF center)
2844 Q_D(QQuickFlickable);
2845 const qreal oldHSize = d->hData.viewSize;
2846 const qreal oldVSize = d->vData.viewSize;
2847 const bool needToUpdateWidth = w != oldHSize;
2848 const bool needToUpdateHeight = h != oldVSize;
2849 d->hData.viewSize = w;
2850 d->vData.viewSize = h;
2851 d->contentItem->setSize(QSizeF(w, h));
2852 if (needToUpdateWidth)
2853 emit contentWidthChanged();
2854 if (needToUpdateHeight)
2855 emit contentHeightChanged();
2857 if (center.x() != 0) {
2858 qreal pos = center.x() * w / oldHSize;
2859 setContentX(contentX() + pos - center.x());
2861 if (center.y() != 0) {
2862 qreal pos = center.y() * h / oldVSize;
2863 setContentY(contentY() + pos - center.y());
2865 d->updateBeginningEnd();
2869
2870
2871
2872
2873
2874
2875
2876void QQuickFlickable::returnToBounds()
2878 Q_D(QQuickFlickable);
2883qreal QQuickFlickable::vWidth()
const
2885 Q_D(
const QQuickFlickable);
2886 if (d->hData.viewSize < 0)
2889 return d->hData.viewSize;
2892qreal QQuickFlickable::vHeight()
const
2894 Q_D(
const QQuickFlickable);
2895 if (d->vData.viewSize < 0)
2898 return d->vData.viewSize;
2902
2903
2904
2905
2906
2907
2908bool QQuickFlickable::xflick()
const
2910 Q_D(
const QQuickFlickable);
2911 const int contentWidthWithMargins = d->contentItem->width() + d->hData.startMargin + d->hData.endMargin;
2912 if ((d->flickableDirection & QQuickFlickable::AutoFlickIfNeeded) && (contentWidthWithMargins > width()))
2914 if (d->flickableDirection == QQuickFlickable::AutoFlickDirection)
2915 return std::floor(qAbs(contentWidthWithMargins - width()));
2916 return d->flickableDirection & QQuickFlickable::HorizontalFlick;
2920
2921
2922
2923
2924
2925
2926bool QQuickFlickable::yflick()
const
2928 Q_D(
const QQuickFlickable);
2929 const int contentHeightWithMargins = d->contentItem->height() + d->vData.startMargin + d->vData.endMargin;
2930 if ((d->flickableDirection & QQuickFlickable::AutoFlickIfNeeded) && (contentHeightWithMargins > height()))
2932 if (d->flickableDirection == QQuickFlickable::AutoFlickDirection)
2933 return std::floor(qAbs(contentHeightWithMargins - height()));
2934 return d->flickableDirection & QQuickFlickable::VerticalFlick;
2937QPointF QQuickFlickable::computePosition(QPointF currentPosition, QRectF itemRect, PositionMode mode,
const QPointF &offset)
const
2939 QPointF newPosition = currentPosition;
2942 const qreal viewWidth = width();
2944 if (mode & QQuickFlickable::AlignLeft)
2945 newPosition.setX(itemRect.left());
2946 if (mode & QQuickFlickable::AlignHCenter)
2947 newPosition.setX(itemRect.left() - (viewWidth - itemRect.width()) / 2);
2948 if (mode & QQuickFlickable::AlignRight)
2949 newPosition.setX(itemRect.right() - viewWidth);
2950 if (mode & QQuickFlickable::Visible) {
2951 if (itemRect.right() < currentPosition.x())
2952 newPosition.setX(itemRect.left());
2953 else if (itemRect.left() > currentPosition.x() + viewWidth)
2954 newPosition.setX(itemRect.right() - viewWidth);
2956 if (mode & QQuickFlickable::Contain) {
2957 if (itemRect.right() > currentPosition.x() + viewWidth)
2958 newPosition.setX(itemRect.right() - viewWidth);
2959 if (itemRect.left() < newPosition.x())
2960 newPosition.setX(itemRect.left());
2963 const qreal minX = -minXExtent();
2964 const qreal maxX = -maxXExtent();
2965 newPosition.setX(qMin(newPosition.x(), maxX));
2966 newPosition.setX(qMax(newPosition.x(), minX));
2970 const qreal viewHeight = height();
2972 if (mode & QQuickFlickable::AlignTop)
2973 newPosition.setY(itemRect.top());
2974 if (mode & QQuickFlickable::AlignVCenter)
2975 newPosition.setY(itemRect.top() - (viewHeight - itemRect.height()) / 2);
2976 if (mode & QQuickFlickable::AlignBottom)
2977 newPosition.setY(itemRect.bottom() - viewHeight);
2978 if (mode & QQuickFlickable::Visible) {
2979 if (itemRect.bottom() < currentPosition.y())
2980 newPosition.setY(itemRect.top());
2981 else if (itemRect.top() > currentPosition.y() + viewHeight)
2982 newPosition.setY(itemRect.bottom() - viewHeight);
2984 if (mode & QQuickFlickable::Contain) {
2985 if (itemRect.bottom() > currentPosition.y() + viewHeight)
2986 newPosition.setY(itemRect.bottom() - viewHeight);
2987 if (itemRect.top() < currentPosition.y())
2988 newPosition.setY(itemRect.top());
2991 const qreal minY = -minYExtent();
2992 const qreal maxY = -maxYExtent();
2993 newPosition.setY(qMin(newPosition.y(), maxY));
2994 newPosition.setY(qMax(newPosition.y(), minY));
2997 return newPosition + offset;
3000void QQuickFlickable::mouseUngrabEvent()
3002 Q_D(QQuickFlickable);
3005 if (!d->replayingPressEvent)
3006 d->cancelInteraction();
3009void QQuickFlickablePrivate::cancelInteraction()
3011 Q_Q(QQuickFlickable);
3013 clearDelayedPress();
3017 q->setKeepMouseGrab(
false);
3018 q->setKeepTouchGrab(
false);
3021 if (!isViewMoving())
3022 q->movementEnding();
3026void QQuickFlickablePrivate::addPointerHandler(QQuickPointerHandler *h)
3028 Q_Q(
const QQuickFlickable);
3029 qCDebug(lcHandlerParent) <<
"reparenting handler" << h <<
"to contentItem of" << q;
3030 h->setParent(contentItem);
3031 QQuickItemPrivate::get(contentItem)->addPointerHandler(h);
3035
3036
3037
3038
3039
3040
3041
3042bool QQuickFlickable::filterPointerEvent(QQuickItem *receiver, QPointerEvent *event)
3044 Q_D(QQuickFlickable);
3045 const bool isTouch = QQuickDeliveryAgentPrivate::isTouchEvent(event);
3046 const bool isMouse = QQuickDeliveryAgentPrivate::isMouseEvent(event);
3047 if (isMouse || QQuickDeliveryAgentPrivate::isTabletEvent(event)) {
3048 if (!d->buttonsAccepted(
static_cast<QSinglePointEvent *>(event)))
3049 return QQuickItem::childMouseEventFilter(receiver, event);
3050 }
else if (!isTouch) {
3053 Q_ASSERT_X(receiver !=
this,
"",
"Flickable received a filter event for itself");
3055 if (isTouch &&
static_cast<QTouchEvent *>(event)->touchPointStates().testFlag(QEventPoint::State::Pressed))
3056 d->stealGrab =
false;
3057 const auto &firstPoint = event->points().first();
3059 if (event->pointCount() == 1 && event->exclusiveGrabber(firstPoint) ==
this) {
3071 QPointF localPos = mapFromScene(firstPoint.scenePosition());
3072 bool receiverDisabled = receiver && !receiver->isEnabled();
3073 bool stealThisEvent = d->stealGrab;
3074 bool receiverKeepsGrab = receiver && (receiver->keepMouseGrab() || receiver->keepTouchGrab());
3075 bool receiverRelinquishGrab =
false;
3078 if (
auto *mouseArea = qmlobject_cast<QQuickMouseArea *>(receiver)) {
3079 bool preventStealing = mouseArea->preventStealing();
3080#if QT_CONFIG(quick_draganddrop)
3081 if (mouseArea->drag() && mouseArea->drag()->target())
3082 preventStealing =
true;
3084 if (!preventStealing && receiverKeepsGrab) {
3085 receiverRelinquishGrab = !receiverDisabled || (isMouse
3086 && firstPoint.state() == QEventPoint::State::Pressed
3087 && (receiver->acceptedMouseButtons() &
static_cast<QMouseEvent *>(event)->button()));
3088 if (receiverRelinquishGrab)
3089 receiverKeepsGrab =
false;
3093 if ((stealThisEvent || contains(localPos)) && (!receiver || !receiverKeepsGrab || receiverDisabled)) {
3094 QScopedPointer<QPointerEvent> localizedEvent(QQuickDeliveryAgentPrivate::clonePointerEvent(event, localPos));
3095 localizedEvent->setAccepted(
false);
3096 switch (firstPoint.state()) {
3097 case QEventPoint::State::Updated:
3098 d->handleMoveEvent(localizedEvent.data());
3100 case QEventPoint::State::Pressed:
3101 d->handlePressEvent(localizedEvent.data());
3102 d->captureDelayedPress(receiver, event);
3104 d->stealGrab =
false;
3105 stealThisEvent =
false;
3107 case QEventPoint::State::Released:
3108 d->handleReleaseEvent(localizedEvent.data());
3109 stealThisEvent = d->stealGrab;
3111 case QEventPoint::State::Stationary:
3112 case QEventPoint::State::Unknown:
3115 if ((receiver && stealThisEvent && !receiverKeepsGrab && receiver !=
this) || receiverDisabled) {
3116 d->clearDelayedPress();
3117 event->setExclusiveGrabber(firstPoint,
this);
3118 }
else if (d->delayedPressEvent) {
3119 event->setExclusiveGrabber(firstPoint,
this);
3122
3123
3124
3125
3126
3127
3128
3129
3130
3131
3132
3133 if (isMoving() || (!receiverRelinquishGrab && (stealThisEvent || d->delayedPressEvent || receiverDisabled))) {
3135 event->setAccepted(
true);
3141 }
else if (d->lastPosTime != -1) {
3142 d->lastPosTime = -1;
3145 if (firstPoint.state() == QEventPoint::State::Released || (receiverKeepsGrab && !receiverDisabled)) {
3147 d->lastPosTime = -1;
3148 d->clearDelayedPress();
3149 d->stealGrab =
false;
3156
3157
3158
3159bool QQuickFlickable::childMouseEventFilter(QQuickItem *i, QEvent *e)
3161 Q_D(QQuickFlickable);
3162 QPointerEvent *pointerEvent = e->isPointerEvent() ?
static_cast<QPointerEvent *>(e) :
nullptr;
3164 auto wantsPointerEvent_helper = [
this, d, i, pointerEvent]() {
3165 Q_ASSERT(pointerEvent);
3166 QQuickDeliveryAgentPrivate::localizePointerEvent(pointerEvent,
this);
3167 const bool wants = d->wantsPointerEvent(pointerEvent);
3169 QQuickDeliveryAgentPrivate::localizePointerEvent(pointerEvent, i);
3173 if (!isVisible() || !isEnabled() || !isInteractive() ||
3174 (pointerEvent && !wantsPointerEvent_helper())) {
3175 d->cancelInteraction();
3176 return QQuickItem::childMouseEventFilter(i, e);
3179 if (e->type() == QEvent::UngrabMouse) {
3180 Q_ASSERT(e->isSinglePointEvent());
3181 auto spe =
static_cast<QSinglePointEvent *>(e);
3182 const QObject *grabber = spe->exclusiveGrabber(spe->points().first());
3183 qCDebug(lcFilter) <<
"filtering UngrabMouse" << spe->points().first() <<
"for" << i <<
"grabber is" << grabber;
3184 if (grabber !=
this)
3186 }
else if (pointerEvent) {
3187 return filterPointerEvent(i, pointerEvent);
3190 return QQuickItem::childMouseEventFilter(i, e);
3194
3195
3196
3197
3198
3199qreal QQuickFlickable::maximumFlickVelocity()
const
3201 Q_D(
const QQuickFlickable);
3202 return d->maxVelocity;
3205void QQuickFlickable::setMaximumFlickVelocity(qreal v)
3207 Q_D(QQuickFlickable);
3208 if (v == d->maxVelocity)
3211 emit maximumFlickVelocityChanged();
3215
3216
3217
3218
3219
3220
3221
3222
3223qreal QQuickFlickable::flickDeceleration()
const
3225 Q_D(
const QQuickFlickable);
3226 return d->deceleration;
3229void QQuickFlickable::setFlickDeceleration(qreal deceleration)
3231 Q_D(QQuickFlickable);
3232 if (deceleration == d->deceleration)
3234 d->deceleration = qMax(0.001, deceleration);
3235 emit flickDecelerationChanged();
3238bool QQuickFlickable::isFlicking()
const
3240 Q_D(
const QQuickFlickable);
3241 return d->hData.flicking || d->vData.flicking;
3245
3246
3247
3248
3249
3250
3251
3252bool QQuickFlickable::isFlickingHorizontally()
const
3254 Q_D(
const QQuickFlickable);
3255 return d->hData.flicking;
3258bool QQuickFlickable::isFlickingVertically()
const
3260 Q_D(
const QQuickFlickable);
3261 return d->vData.flicking;
3265
3266
3267
3268
3269
3270
3271
3272bool QQuickFlickable::isDragging()
const
3274 Q_D(
const QQuickFlickable);
3275 return d->hData.dragging || d->vData.dragging;
3278bool QQuickFlickable::isDraggingHorizontally()
const
3280 Q_D(
const QQuickFlickable);
3281 return d->hData.dragging;
3284bool QQuickFlickable::isDraggingVertically()
const
3286 Q_D(
const QQuickFlickable);
3287 return d->vData.dragging;
3290void QQuickFlickablePrivate::draggingStarting()
3292 Q_Q(QQuickFlickable);
3293 bool wasDragging = hData.dragging || vData.dragging;
3294 if (hMoved && !hData.dragging) {
3295 hData.dragging =
true;
3296 emit q->draggingHorizontallyChanged();
3298 if (vMoved && !vData.dragging) {
3299 vData.dragging =
true;
3300 emit q->draggingVerticallyChanged();
3302 if (!wasDragging && (hData.dragging || vData.dragging)) {
3303 emit q->draggingChanged();
3304 emit q->dragStarted();
3308void QQuickFlickablePrivate::draggingEnding()
3310 Q_Q(QQuickFlickable);
3311 const bool wasDragging = hData.dragging || vData.dragging;
3312 if (hData.dragging) {
3313 hData.dragging =
false;
3314 emit q->draggingHorizontallyChanged();
3316 if (vData.dragging) {
3317 vData.dragging =
false;
3318 emit q->draggingVerticallyChanged();
3321 if (!hData.dragging && !vData.dragging) {
3322 emit q->draggingChanged();
3323 emit q->dragEnded();
3325 hData.inRebound =
false;
3326 vData.inRebound =
false;
3330bool QQuickFlickablePrivate::isViewMoving()
const
3332 if (timeline.isActive()
3333 || (hData.transitionToBounds && hData.transitionToBounds->isActive())
3334 || (vData.transitionToBounds && vData.transitionToBounds->isActive()) ) {
3341
3342
3343
3344
3345
3346
3347
3348
3349
3350
3351
3352
3353
3354
3355
3356
3357
3358int QQuickFlickable::pressDelay()
const
3360 Q_D(
const QQuickFlickable);
3361 return d->pressDelay;
3364void QQuickFlickable::setPressDelay(
int delay)
3366 Q_D(QQuickFlickable);
3367 if (d->pressDelay == delay)
3369 d->pressDelay = delay;
3370 emit pressDelayChanged();
3374
3375
3376
3377
3378
3379
3380
3381
3383bool QQuickFlickable::isMoving()
const
3385 Q_D(
const QQuickFlickable);
3386 return d->hData.moving || d->vData.moving;
3389bool QQuickFlickable::isMovingHorizontally()
const
3391 Q_D(
const QQuickFlickable);
3392 return d->hData.moving;
3395bool QQuickFlickable::isMovingVertically()
const
3397 Q_D(
const QQuickFlickable);
3398 return d->vData.moving;
3401void QQuickFlickable::velocityTimelineCompleted()
3403 Q_D(QQuickFlickable);
3404 if ( (d->hData.transitionToBounds && d->hData.transitionToBounds->isActive())
3405 || (d->vData.transitionToBounds && d->vData.transitionToBounds->isActive()) ) {
3412 if (d->vData.flicking)
3414 d->updateBeginningEnd();
3417void QQuickFlickable::timelineCompleted()
3419 Q_D(QQuickFlickable);
3420 if ( (d->hData.transitionToBounds && d->hData.transitionToBounds->isActive())
3421 || (d->vData.transitionToBounds && d->vData.transitionToBounds->isActive()) ) {
3425 d->updateBeginningEnd();
3428void QQuickFlickable::movementStarting()
3430 Q_D(QQuickFlickable);
3431 bool wasMoving = d->hData.moving || d->vData.moving;
3432 if (d->hMoved && !d->hData.moving) {
3433 d->hData.moving =
true;
3434 emit movingHorizontallyChanged();
3436 if (d->vMoved && !d->vData.moving) {
3437 d->vData.moving =
true;
3438 emit movingVerticallyChanged();
3441 if (!wasMoving && (d->hData.moving || d->vData.moving)) {
3442 emit movingChanged();
3443 emit movementStarted();
3444#if QT_CONFIG(accessibility)
3445 if (QAccessible::isActive()) {
3446 QAccessibleEvent ev(
this, QAccessible::ScrollingStart);
3447 QAccessible::updateAccessibility(&ev);
3453void QQuickFlickable::movementEnding()
3455 movementEnding(
true,
true);
3458void QQuickFlickable::movementEnding(
bool hMovementEnding,
bool vMovementEnding)
3460 Q_D(QQuickFlickable);
3463 const bool wasFlicking = d->hData.flicking || d->vData.flicking;
3464 if (hMovementEnding && d->hData.flicking) {
3465 d->hData.flicking =
false;
3466 emit flickingHorizontallyChanged();
3468 if (vMovementEnding && d->vData.flicking) {
3469 d->vData.flicking =
false;
3470 emit flickingVerticallyChanged();
3472 if (wasFlicking && (!d->hData.flicking || !d->vData.flicking)) {
3473 emit flickingChanged();
3475 }
else if (d->hData.flickingWhenDragBegan || d->vData.flickingWhenDragBegan) {
3476 d->hData.flickingWhenDragBegan = !hMovementEnding;
3477 d->vData.flickingWhenDragBegan = !vMovementEnding;
3482 bool wasMoving = isMoving();
3483 if (hMovementEnding && d->hData.moving
3484 && (!d->pressed && !d->stealGrab)) {
3485 d->hData.moving =
false;
3487 emit movingHorizontallyChanged();
3489 if (vMovementEnding && d->vData.moving
3490 && (!d->pressed && !d->stealGrab)) {
3491 d->vData.moving =
false;
3493 emit movingVerticallyChanged();
3495 if (wasMoving && !isMoving()) {
3496 emit movingChanged();
3497 emit movementEnded();
3498#if QT_CONFIG(accessibility)
3499 if (QAccessible::isActive()) {
3500 QAccessibleEvent ev(
this, QAccessible::ScrollingEnd);
3501 QAccessible::updateAccessibility(&ev);
3506 if (hMovementEnding) {
3507 d->hData.fixingUp =
false;
3508 d->hData.smoothVelocity.setValue(0);
3509 d->hData.previousDragDelta = 0.0;
3511 if (vMovementEnding) {
3512 d->vData.fixingUp =
false;
3513 d->vData.smoothVelocity.setValue(0);
3514 d->vData.previousDragDelta = 0.0;
3518void QQuickFlickablePrivate::updateVelocity()
3520 Q_Q(QQuickFlickable);
3521 emit q->horizontalVelocityChanged();
3522 emit q->verticalVelocityChanged();
3526
3527
3528
3529
3530
3531
3532
3533
3534
3535
3536
3537
3538
3539
3540qreal QQuickFlickable::horizontalOvershoot()
const
3542 Q_D(
const QQuickFlickable);
3543 return d->hData.overshoot;
3547
3548
3549
3550
3551
3552
3553
3554
3555
3556
3557
3558
3559
3560
3561qreal QQuickFlickable::verticalOvershoot()
const
3563 Q_D(
const QQuickFlickable);
3564 return d->vData.overshoot;
3568
3569
3570
3571
3572
3573
3574
3575
3576
3577
3578
3579
3580
3581
3582
3583
3584
3585
3586
3587
3588
3589
3590
3591
3592
3593
3594
3595
3596
3597
3598
3599
3600
3601
3602
3603
3604
3605
3606
3607
3608
3609
3610
3611
3612
3613QQuickFlickable::BoundsMovement QQuickFlickable::boundsMovement()
const
3615 Q_D(
const QQuickFlickable);
3616 return d->boundsMovement;
3619void QQuickFlickable::setBoundsMovement(BoundsMovement movement)
3621 Q_D(QQuickFlickable);
3622 if (d->boundsMovement == movement)
3625 d->boundsMovement = movement;
3626 emit boundsMovementChanged();
3631#include "moc_qquickflickable_p_p.cpp"
3633#include "moc_qquickflickable_p.cpp"
bool contains(const QPointF &point) const override
QQuickFlickableContentItem(QQuickItem *parent=nullptr)
~QQuickFlickableReboundTransition()
bool startTransition(QQuickFlickablePrivate::AxisData *data, qreal toPos)
QQuickFlickableReboundTransition(QQuickFlickable *f, const QString &name)
QT_BEGIN_NAMESPACE Q_STATIC_LOGGING_CATEGORY(lcSynthesizedIterableAccess, "qt.iterable.synthesized", QtWarningMsg)
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