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
754
755
756
757
758
761
762
763
764
765
766
767
768
771
772
773
774
775
776
779
780
781
782
783
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805QQuickFlickable::QQuickFlickable(QQuickItem *parent)
806 : QQuickItem(*(
new QQuickFlickablePrivate), parent)
808 Q_D(QQuickFlickable);
812QQuickFlickable::QQuickFlickable(QQuickFlickablePrivate &dd, QQuickItem *parent)
813 : QQuickItem(dd, parent)
815 Q_D(QQuickFlickable);
819QQuickFlickable::~QQuickFlickable()
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843qreal QQuickFlickable::contentX()
const
845 Q_D(
const QQuickFlickable);
846 return -d->contentItem->x();
849void QQuickFlickable::setContentX(qreal pos)
851 Q_D(QQuickFlickable);
852 d->hData.explicitValue =
true;
853 d->resetTimeline(d->hData);
854 d->hData.vTime = d->timeline.time();
855 if (isMoving() || isFlicking())
856 movementEnding(
true,
false);
857 if (!qFuzzyCompare(-pos, d->hData.move.value())) {
858 d->hData.contentPositionChangedExternallyDuringDrag = d->hData.dragging;
859 d->hData.move.setValue(-pos);
860 d->hData.contentPositionChangedExternallyDuringDrag =
false;
864qreal QQuickFlickable::contentY()
const
866 Q_D(
const QQuickFlickable);
867 return -d->contentItem->y();
870void QQuickFlickable::setContentY(qreal pos)
872 Q_D(QQuickFlickable);
873 d->vData.explicitValue =
true;
874 d->resetTimeline(d->vData);
875 d->vData.vTime = d->timeline.time();
876 if (isMoving() || isFlicking())
877 movementEnding(
false,
true);
878 if (!qFuzzyCompare(-pos, d->vData.move.value())) {
879 d->vData.contentPositionChangedExternallyDuringDrag = d->vData.dragging;
880 d->vData.move.setValue(-pos);
881 d->vData.contentPositionChangedExternallyDuringDrag =
false;
886
887
888
889
890
891
892
893
894
895
896
897
898bool QQuickFlickable::isInteractive()
const
900 Q_D(
const QQuickFlickable);
901 return d->interactive;
904void QQuickFlickable::setInteractive(
bool interactive)
906 Q_D(QQuickFlickable);
907 if (interactive != d->interactive) {
908 d->interactive = interactive;
910 d->cancelInteraction();
912 emit interactiveChanged();
917
918
919
920
921
922
923
924
925
926
927
928
929qreal QQuickFlickable::horizontalVelocity()
const
931 Q_D(
const QQuickFlickable);
932 return d->hData.smoothVelocity.value();
935qreal QQuickFlickable::verticalVelocity()
const
937 Q_D(
const QQuickFlickable);
938 return d->vData.smoothVelocity.value();
942
943
944
945
946
947
948
949
950bool QQuickFlickable::isAtXEnd()
const
952 Q_D(
const QQuickFlickable);
953 return d->hData.atEnd;
956bool QQuickFlickable::isAtXBeginning()
const
958 Q_D(
const QQuickFlickable);
959 return d->hData.atBeginning;
962bool QQuickFlickable::isAtYEnd()
const
964 Q_D(
const QQuickFlickable);
965 return d->vData.atEnd;
968bool QQuickFlickable::isAtYBeginning()
const
970 Q_D(
const QQuickFlickable);
971 return d->vData.atBeginning;
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992QQuickItem *QQuickFlickable::contentItem()
const
994 Q_D(
const QQuickFlickable);
995 return d->contentItem;
998QQuickFlickableVisibleArea *QQuickFlickable::visibleArea()
1000 Q_D(QQuickFlickable);
1001 if (!d->visibleArea) {
1002 d->visibleArea =
new QQuickFlickableVisibleArea(
this);
1003 d->visibleArea->updateVisible();
1005 return d->visibleArea;
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027QQuickFlickable::FlickableDirection QQuickFlickable::flickableDirection()
const
1029 Q_D(
const QQuickFlickable);
1030 return d->flickableDirection;
1033void QQuickFlickable::setFlickableDirection(FlickableDirection direction)
1035 Q_D(QQuickFlickable);
1036 if (direction != d->flickableDirection) {
1037 d->flickableDirection = direction;
1038 emit flickableDirectionChanged();
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054bool QQuickFlickable::pixelAligned()
const
1056 Q_D(
const QQuickFlickable);
1057 return d->pixelAligned;
1060void QQuickFlickable::setPixelAligned(
bool align)
1062 Q_D(QQuickFlickable);
1063 if (align != d->pixelAligned) {
1064 d->pixelAligned = align;
1065 emit pixelAlignedChanged();
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081bool QQuickFlickable::synchronousDrag()
const
1083 Q_D(
const QQuickFlickable);
1087void QQuickFlickable::setSynchronousDrag(
bool v)
1089 Q_D(QQuickFlickable);
1090 if (v != d->syncDrag) {
1092 emit synchronousDragChanged();
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111Qt::MouseButtons QQuickFlickable::acceptedButtons()
const
1113 Q_D(
const QQuickFlickable);
1114 return d->acceptedButtons;
1117void QQuickFlickable::setAcceptedButtons(Qt::MouseButtons buttons)
1119 Q_D(QQuickFlickable);
1120 if (d->acceptedButtons == buttons)
1123 d->acceptedButtons = buttons;
1124 setAcceptedMouseButtons(buttons);
1125 emit acceptedButtonsChanged();
1129
1130
1131
1132QVector2D QQuickFlickablePrivate::firstPointLocalVelocity(QPointerEvent *event)
1134 QTransform transform = windowToItemTransform();
1136 return QVector2D(transform.map(event->point(0).velocity().toPointF()) - transform.map(QPointF()));
1139qint64 QQuickFlickablePrivate::computeCurrentTime(QInputEvent *event)
const
1141 if (0 != event->timestamp())
1142 return event->timestamp();
1143 if (!timer.isValid())
1145 return timer.elapsed();
1148void QQuickFlickablePrivate::handlePressEvent(QPointerEvent *event)
1150 Q_Q(QQuickFlickable);
1152 if (interactive && timeline.isActive()
1153 && ((qAbs(hData.smoothVelocity.value()) > RetainGrabVelocity && !hData.fixingUp && !hData.inOvershoot)
1154 || (qAbs(vData.smoothVelocity.value()) > RetainGrabVelocity && !vData.fixingUp && !vData.inOvershoot))) {
1158 int flickTime = timeline.time();
1159 if (flickTime > 600) {
1161 hData.continuousFlickVelocity = 0;
1162 vData.continuousFlickVelocity = 0;
1165 hData.continuousFlickVelocity = -hData.smoothVelocity.value();
1166 vData.continuousFlickVelocity = -vData.smoothVelocity.value();
1167 if (flickTime > 300)
1168 flickBoost = qMax(1.0, flickBoost - 0.5);
1172 hData.continuousFlickVelocity = 0;
1173 vData.continuousFlickVelocity = 0;
1176 if (event->isSinglePointEvent())
1177 q->setKeepMouseGrab(stealGrab);
1179 q->setKeepTouchGrab(stealGrab);
1181 maybeBeginDrag(computeCurrentTime(event), event->points().first().position(),
1182 event->isSinglePointEvent() ?
static_cast<QSinglePointEvent *>(event)->buttons()
1186void QQuickFlickablePrivate::maybeBeginDrag(qint64 currentTimestamp,
const QPointF &pressPosn, Qt::MouseButtons buttons)
1188 Q_Q(QQuickFlickable);
1189 clearDelayedPress();
1191 pressed = (buttons == Qt::NoButton) || (acceptedButtons != Qt::NoButton && (buttons & acceptedButtons) != 0);
1193 if (hData.transitionToBounds)
1194 hData.transitionToBounds->stopTransition();
1195 if (vData.transitionToBounds)
1196 vData.transitionToBounds->stopTransition();
1197 if (!hData.fixingUp)
1198 resetTimeline(hData);
1199 if (!vData.fixingUp)
1200 resetTimeline(vData);
1204 hData.dragMinBound = q->minXExtent() - hData.startMargin;
1205 vData.dragMinBound = q->minYExtent() - vData.startMargin;
1206 hData.dragMaxBound = q->maxXExtent() + hData.endMargin;
1207 vData.dragMaxBound = q->maxYExtent() + vData.endMargin;
1209 lastPos = QPointF();
1210 pressPos = pressPosn;
1211 hData.pressPos = hData.move.value();
1212 vData.pressPos = vData.move.value();
1213 const bool wasFlicking = hData.flicking || vData.flicking;
1214 hData.flickingWhenDragBegan = hData.flicking;
1215 vData.flickingWhenDragBegan = vData.flicking;
1216 if (hData.flicking) {
1217 hData.flicking =
false;
1218 emit q->flickingHorizontallyChanged();
1220 if (vData.flicking) {
1221 vData.flicking =
false;
1222 emit q->flickingVerticallyChanged();
1225 emit q->flickingChanged();
1226 lastPosTime = lastPressTime = currentTimestamp;
1227 vData.velocityTime.start();
1228 hData.velocityTime.start();
1231void QQuickFlickablePrivate::drag(qint64 currentTimestamp, QEvent::Type eventType,
const QPointF &localPos,
1232 const QVector2D &deltas,
bool overThreshold,
bool momentum,
1233 bool velocitySensitiveOverBounds,
const QVector2D &velocity)
1235 Q_Q(QQuickFlickable);
1236 bool rejectY =
false;
1237 bool rejectX =
false;
1239 bool keepY = q->yflick();
1240 bool keepX = q->xflick();
1242 bool stealY =
false;
1243 bool stealX =
false;
1244 bool isTouchEvent =
false;
1245 switch (eventType) {
1246 case QEvent::MouseMove:
1247 stealX = stealY = stealGrab;
1250 stealX = stealY = scrollingPhase;
1252 case QEvent::TouchUpdate:
1253 stealX = stealY = stealGrab;
1254 isTouchEvent =
true;
1260 bool prevHMoved = hMoved;
1261 bool prevVMoved = vMoved;
1263 qint64 elapsedSincePress = currentTimestamp - lastPressTime;
1264 qCDebug(lcFlickable).nospace() << currentTimestamp <<
' ' << eventType <<
" drag @ " << localPos.x() <<
',' << localPos.y()
1265 <<
" \u0394 " << deltas.x() <<
',' << deltas.y() <<
" vel " << velocity.x() <<
',' << velocity.y()
1266 <<
" thrsld? " << overThreshold <<
" momentum? " << momentum <<
" velSens? " << velocitySensitiveOverBounds
1267 <<
" sincePress " << elapsedSincePress;
1270 qreal dy = deltas.y();
1271 if (overThreshold || elapsedSincePress > 200) {
1272 if (!vMoved && !vData.dragging)
1273 vData.dragStartOffset = dy;
1274 qreal newY = dy + vData.pressPos - (syncDrag ? 0 : vData.dragStartOffset);
1278 const qreal minY = vData.dragMinBound + vData.startMargin;
1279 const qreal maxY = vData.dragMaxBound - vData.endMargin;
1280 if (!(boundsBehavior & QQuickFlickable::DragOverBounds)) {
1281 if (fuzzyLessThanOrEqualTo(newY, maxY)) {
1283 rejectY = vData.pressPos == maxY && vData.move.value() == maxY && dy < 0;
1285 if (fuzzyLessThanOrEqualTo(minY, newY)) {
1287 rejectY |= vData.pressPos == minY && vData.move.value() == minY && dy > 0;
1291 if (vel > 0. && vel > vData.velocity)
1293 else if (vel < 0. && vel < vData.velocity)
1297 if (momentum && vData.atBeginning) {
1298 if (!vData.inRebound) {
1299 vData.inRebound =
true;
1300 q->returnToBounds();
1304 if (velocitySensitiveOverBounds) {
1307 newY = minY + overshoot;
1309 newY = minY + (newY - minY) / 2;
1311 }
else if (newY < maxY && maxY - minY <= 0) {
1313 if (momentum && vData.atEnd) {
1314 if (!vData.inRebound) {
1315 vData.inRebound =
true;
1316 q->returnToBounds();
1320 if (velocitySensitiveOverBounds) {
1323 newY = maxY - overshoot;
1325 newY = maxY + (newY - maxY) / 2;
1329 if (!rejectY && stealGrab && dy != vData.previousDragDelta) {
1331 vData.move.setValue(newY);
1334 if (!rejectY && overThreshold)
1337 if ((newY >= minY && vData.pressPos == minY && vData.move.value() == minY && dy > 0)
1338 || (newY <= maxY && vData.pressPos == maxY && vData.move.value() == maxY && dy < 0)) {
1342 vData.previousDragDelta = dy;
1346 qreal dx = deltas.x();
1347 if (overThreshold || elapsedSincePress > 200) {
1348 if (!hMoved && !hData.dragging)
1349 hData.dragStartOffset = dx;
1350 qreal newX = dx + hData.pressPos - (syncDrag ? 0 : hData.dragStartOffset);
1351 const qreal minX = hData.dragMinBound + hData.startMargin;
1352 const qreal maxX = hData.dragMaxBound - hData.endMargin;
1353 if (!(boundsBehavior & QQuickFlickable::DragOverBounds)) {
1354 if (fuzzyLessThanOrEqualTo(newX, maxX)) {
1356 rejectX = hData.pressPos == maxX && hData.move.value() == maxX && dx < 0;
1358 if (fuzzyLessThanOrEqualTo(minX, newX)) {
1360 rejectX |= hData.pressPos == minX && hData.move.value() == minX && dx > 0;
1364 if (vel > 0. && vel > hData.velocity)
1366 else if (vel < 0. && vel < hData.velocity)
1370 if (momentum && hData.atBeginning) {
1371 if (!hData.inRebound) {
1372 hData.inRebound =
true;
1373 q->returnToBounds();
1377 if (velocitySensitiveOverBounds) {
1380 newX = minX + overshoot;
1382 newX = minX + (newX - minX) / 2;
1384 }
else if (newX < maxX && maxX - minX <= 0) {
1386 if (momentum && hData.atEnd) {
1387 if (!hData.inRebound) {
1388 hData.inRebound =
true;
1389 q->returnToBounds();
1393 if (velocitySensitiveOverBounds) {
1396 newX = maxX - overshoot;
1398 newX = maxX + (newX - maxX) / 2;
1402 if (!rejectX && stealGrab && dx != hData.previousDragDelta) {
1404 hData.move.setValue(newX);
1408 if (!rejectX && overThreshold)
1411 if ((newX >= minX && vData.pressPos == minX && vData.move.value() == minX && dx > 0)
1412 || (newX <= maxX && vData.pressPos == maxX && vData.move.value() == maxX && dx < 0)) {
1416 hData.previousDragDelta = dx;
1419 stealGrab = stealX || stealY;
1421 if ((stealX && keepX) || (stealY && keepY)) {
1423 q->setKeepTouchGrab(
true);
1425 q->setKeepMouseGrab(
true);
1427 clearDelayedPress();
1431 vData.velocitySamples = 0;
1432 vData.velocityWritePos = 0;
1436 hData.velocitySamples = 0;
1437 hData.velocityWritePos = 0;
1441 if (momentum && !hData.flicking && !vData.flicking)
1442 flickingStarted(hData.velocity != 0, vData.velocity != 0);
1445 if ((hMoved && !prevHMoved) || (vMoved && !prevVMoved))
1446 q->movementStarting();
1448 lastPosTime = currentTimestamp;
1449 if (q->yflick() && !rejectY)
1450 vData.addVelocitySample(velocity.y(), maxVelocity);
1451 if (q->xflick() && !rejectX)
1452 hData.addVelocitySample(velocity.x(), maxVelocity);
1456void QQuickFlickablePrivate::handleMoveEvent(QPointerEvent *event)
1458 Q_Q(QQuickFlickable);
1459 if (!interactive || lastPosTime == -1 ||
1460 (event->isSinglePointEvent() && !buttonsAccepted(
static_cast<QSinglePointEvent *>(event))))
1463 qint64 currentTimestamp = computeCurrentTime(event);
1464 const auto &firstPoint = event->points().first();
1465 const auto &pos = firstPoint.position();
1466 const QVector2D deltas = QVector2D(pos - q->mapFromGlobal(firstPoint.globalPressPosition()));
1467 const QVector2D velocity = firstPointLocalVelocity(event);
1468 bool overThreshold =
false;
1470 if (q->isMoving()) {
1472
1473
1474
1475
1476
1477
1478
1479 overThreshold =
true;
1480 }
else if (event->pointCount() == 1) {
1482 overThreshold |= QQuickDeliveryAgentPrivate::dragOverThreshold(deltas.y(), Qt::YAxis, firstPoint);
1484 overThreshold |= QQuickDeliveryAgentPrivate::dragOverThreshold(deltas.x(), Qt::XAxis, firstPoint);
1486 qCDebug(lcFilter) << q->objectName() <<
"ignoring multi-touch" << event;
1489 drag(currentTimestamp, event->type(), pos, deltas, overThreshold,
false,
false, velocity);
1492void QQuickFlickablePrivate::handleReleaseEvent(QPointerEvent *event)
1494 Q_Q(QQuickFlickable);
1496 q->setKeepMouseGrab(
false);
1497 q->setKeepTouchGrab(
false);
1501 qint64 elapsed = computeCurrentTime(event) - lastPosTime;
1503 vData.updateVelocity();
1504 hData.updateVelocity();
1508 if (lastPosTime == -1)
1511 hData.vTime = vData.vTime = timeline.time();
1513 bool canBoost =
false;
1514 const auto pos = event->points().first().position();
1515 const auto pressPos = q->mapFromGlobal(event->points().first().globalPressPosition());
1516 const QVector2D eventVelocity = firstPointLocalVelocity(event);
1517 qCDebug(lcVel) << event->deviceType() << event->type() <<
"velocity" << event->points().first().velocity() <<
"transformed to local" << eventVelocity;
1519 qreal vVelocity = 0;
1520 if (elapsed < 100 && vData.velocity != 0.) {
1521 vVelocity = (event->device()->capabilities().testFlag(QInputDevice::Capability::Velocity)
1522 ? eventVelocity.y() : vData.velocity);
1524 if ((vData.atBeginning && vVelocity > 0.) || (vData.atEnd && vVelocity < 0.)) {
1526 }
else if (vData.continuousFlickVelocity != 0.0
1528 && ((vVelocity > 0) == (vData.continuousFlickVelocity > 0))
1534 qreal hVelocity = 0;
1535 if (elapsed < 100 && hData.velocity != 0.) {
1536 hVelocity = (event->device()->capabilities().testFlag(QInputDevice::Capability::Velocity)
1537 ? eventVelocity.x() : hData.velocity);
1539 if ((hData.atBeginning && hVelocity > 0.) || (hData.atEnd && hVelocity < 0.)) {
1541 }
else if (hData.continuousFlickVelocity != 0.0
1543 && ((hVelocity > 0) == (hData.continuousFlickVelocity > 0))
1550 const int flickThreshold = QGuiApplicationPrivate::platformTheme()->themeHint(QPlatformTheme::FlickStartDistance).toInt();
1552 bool anyPointGrabbed = event->points().constEnd() !=
1553 std::find_if(event->points().constBegin(),event->points().constEnd(),
1554 [q, event](
const QEventPoint &point) {
return event->exclusiveGrabber(point) == q; });
1556 bool flickedVertically =
false;
1557 vVelocity *= flickBoost;
1558 const bool isVerticalFlickAllowed = anyPointGrabbed &&
1559 q->yflick() && qAbs(vVelocity) > _q_MinimumFlickVelocity &&
1560 qAbs(pos.y() - pressPos.y()) > flickThreshold;
1561 if (isVerticalFlickAllowed) {
1562 velocityTimeline.reset(vData.smoothVelocity);
1563 vData.smoothVelocity.setValue(-vVelocity);
1564 flickedVertically = flickY(event->type(), vVelocity);
1567 bool flickedHorizontally =
false;
1568 hVelocity *= flickBoost;
1569 const bool isHorizontalFlickAllowed = anyPointGrabbed &&
1570 q->xflick() && qAbs(hVelocity) > _q_MinimumFlickVelocity &&
1571 qAbs(pos.x() - pressPos.x()) > flickThreshold;
1572 if (isHorizontalFlickAllowed) {
1573 velocityTimeline.reset(hData.smoothVelocity);
1574 hData.smoothVelocity.setValue(-hVelocity);
1575 flickedHorizontally = flickX(event->type(), hVelocity);
1578 if (!isVerticalFlickAllowed)
1581 if (!isHorizontalFlickAllowed)
1584 flickingStarted(flickedHorizontally, flickedVertically);
1585 if (!isViewMoving()) {
1586 q->movementEnding();
1588 if (flickedVertically)
1590 if (flickedHorizontally)
1592 q->movementStarting();
1596bool QQuickFlickablePrivate::buttonsAccepted(
const QSinglePointEvent *event)
1598 return !((event->button() & acceptedButtons) == 0 && (event->buttons() & acceptedButtons) == 0);
1601void QQuickFlickable::mousePressEvent(QMouseEvent *event)
1603 Q_D(QQuickFlickable);
1604 if (d->interactive && !d->replayingPressEvent && d->buttonsAccepted(event) && d->wantsPointerEvent(event)) {
1606 d->handlePressEvent(event);
1609 QQuickItem::mousePressEvent(event);
1613void QQuickFlickable::mouseMoveEvent(QMouseEvent *event)
1615 Q_D(QQuickFlickable);
1616 if (d->interactive && d->buttonsAccepted(event) && d->wantsPointerEvent(event)) {
1617 d->handleMoveEvent(event);
1620 QQuickItem::mouseMoveEvent(event);
1624void QQuickFlickable::mouseReleaseEvent(QMouseEvent *event)
1626 Q_D(QQuickFlickable);
1627 if (d->interactive && d->buttonsAccepted(event) && d->wantsPointerEvent(event)) {
1628 if (d->delayedPressEvent) {
1629 d->replayDelayedPress();
1631 auto &firstPoint = event->point(0);
1632 if (
const auto *grabber = event->exclusiveGrabber(firstPoint); grabber && grabber->isQuickItemType()) {
1635 const auto oldPosition = firstPoint.position();
1636 QMutableEventPoint::setPosition(firstPoint, event->scenePosition());
1637 QCoreApplication::sendEvent(window(), event);
1638 QMutableEventPoint::setPosition(firstPoint, oldPosition);
1642 d->stealGrab =
false;
1647 d->handleReleaseEvent(event);
1650 QQuickItem::mouseReleaseEvent(event);
1654void QQuickFlickable::touchEvent(QTouchEvent *event)
1656 Q_D(QQuickFlickable);
1658 if (event->type() == QEvent::TouchCancel) {
1659 if (d->interactive && d->wantsPointerEvent(event))
1660 d->cancelInteraction();
1662 QQuickItem::touchEvent(event);
1666 bool unhandled =
false;
1667 const auto &firstPoint = event->points().first();
1668 switch (firstPoint.state()) {
1669 case QEventPoint::State::Pressed:
1670 if (d->interactive && !d->replayingPressEvent && d->wantsPointerEvent(event)) {
1672 d->handlePressEvent(event);
1678 case QEventPoint::State::Updated:
1679 if (d->interactive && d->wantsPointerEvent(event)) {
1680 d->handleMoveEvent(event);
1686 case QEventPoint::State::Released:
1687 if (d->interactive && d->wantsPointerEvent(event)) {
1688 if (d->delayedPressEvent) {
1689 d->replayDelayedPress();
1691 const auto &firstPoint = event->point(0);
1692 if (
const auto *grabber = event->exclusiveGrabber(firstPoint); grabber && grabber->isQuickItemType()) {
1694 QScopedPointer<QPointerEvent> localizedEvent(
1695 QQuickDeliveryAgentPrivate::clonePointerEvent(event, firstPoint.scenePosition()));
1696 QCoreApplication::sendEvent(window(), localizedEvent.data());
1700 d->stealGrab =
false;
1705 d->handleReleaseEvent(event);
1711 case QEventPoint::State::Stationary:
1712 case QEventPoint::State::Unknown:
1716 QQuickItem::touchEvent(event);
1719#if QT_CONFIG(wheelevent)
1720void QQuickFlickable::wheelEvent(QWheelEvent *event)
1722 Q_D(QQuickFlickable);
1723 if (!d->interactive || !d->wantsPointerEvent(event)) {
1724 QQuickItem::wheelEvent(event);
1727 qCDebug(lcWheel) << event->device() << event << event->source();
1728 event->setAccepted(
false);
1729 qint64 currentTimestamp = d->computeCurrentTime(event);
1730 switch (event->phase()) {
1731 case Qt::ScrollBegin:
1732 d->scrollingPhase =
true;
1733 d->accumulatedWheelPixelDelta = QVector2D();
1734 d->vData.velocity = 0;
1735 d->hData.velocity = 0;
1737 d->maybeBeginDrag(currentTimestamp, event->position());
1738 d->lastPosTime = -1;
1740 case Qt::NoScrollPhase:
1741 case Qt::ScrollUpdate:
1742 if (d->scrollingPhase)
1745 case Qt::ScrollMomentum:
1747 d->scrollingPhase =
false;
1748 d->draggingEnding();
1751 d->lastPosTime = -1;
1755 d->scrollingPhase =
false;
1756 d->draggingEnding();
1758 d->lastPosTime = -1;
1759 d->stealGrab =
false;
1760 if (!d->velocityTimeline.isActive() && !d->timeline.isActive())
1761 movementEnding(
true,
true);
1765 qreal elapsed = qreal(currentTimestamp - d->lastPosTime) / qreal(1000);
1767 d->lastPosTime = currentTimestamp;
1768 qCDebug(lcWheel) <<
"insufficient elapsed time: can't calculate velocity" << elapsed;
1772 if (event->source() == Qt::MouseEventNotSynthesized || event->pixelDelta().isNull() || event->phase() == Qt::NoScrollPhase) {
1774 int xDelta = event->angleDelta().x();
1775 int yDelta = event->angleDelta().y();
1777 if (d->wheelDeceleration > _q_MaximumWheelDeceleration) {
1778 const qreal wheelScroll = -qApp->styleHints()->wheelScrollLines() * 24;
1781 if (yflick() && yDelta != 0) {
1782 d->moveReason = QQuickFlickablePrivate::Mouse;
1784 qreal scrollPixel = (-yDelta / 120.0 * wheelScroll);
1785 bool acceptEvent =
true;
1786 if (scrollPixel > 0) {
1787 if (d->vData.move.value() >= minYExtent()) {
1789 acceptEvent =
false;
1792 if (d->vData.move.value() <= maxYExtent()) {
1794 acceptEvent =
false;
1798 if (d->boundsBehavior == QQuickFlickable::StopAtBounds) {
1799 const qreal estContentPos = scrollPixel + d->vData.move.value();
1800 if (scrollPixel > 0) {
1801 if (estContentPos > minYExtent()) {
1802 scrollPixel = minYExtent() - d->vData.move.value();
1803 acceptEvent =
false;
1806 if (estContentPos < maxYExtent()) {
1807 scrollPixel = maxYExtent() - d->vData.move.value();
1808 acceptEvent =
false;
1812 d->resetTimeline(d->vData);
1814 d->timeline.moveBy(d->vData.move, scrollPixel, QEasingCurve(QEasingCurve::OutExpo), 3*d->fixupDuration/4);
1815 d->vData.fixingUp =
true;
1816 d->timeline.callback(QQuickTimeLineCallback(&d->vData.move, QQuickFlickablePrivate::fixupY_callback, d));
1821 if (xflick() && xDelta != 0) {
1822 d->moveReason = QQuickFlickablePrivate::Mouse;
1824 qreal scrollPixel = (-xDelta / 120.0 * wheelScroll);
1825 bool acceptEvent =
true;
1826 if (scrollPixel > 0) {
1827 if (d->hData.move.value() >= minXExtent()) {
1829 acceptEvent =
false;
1832 if (d->hData.move.value() <= maxXExtent()) {
1834 acceptEvent =
false;
1838 if (d->boundsBehavior == QQuickFlickable::StopAtBounds) {
1839 const qreal estContentPos = scrollPixel + d->hData.move.value();
1840 if (scrollPixel > 0) {
1841 if (estContentPos > minXExtent()) {
1842 scrollPixel = minXExtent() - d->hData.move.value();
1843 acceptEvent =
false;
1846 if (estContentPos < maxXExtent()) {
1847 scrollPixel = maxXExtent() - d->hData.move.value();
1848 acceptEvent =
false;
1852 d->resetTimeline(d->hData);
1854 d->timeline.moveBy(d->hData.move, scrollPixel, QEasingCurve(QEasingCurve::OutExpo), 3*d->fixupDuration/4);
1855 d->hData.fixingUp =
true;
1856 d->timeline.callback(QQuickTimeLineCallback(&d->hData.move, QQuickFlickablePrivate::fixupX_callback, d));
1872 elapsed = 120 / qSqrt(d->wheelDeceleration * 2 * d->initialWheelFlickDistance);
1873 if (yflick() && yDelta != 0) {
1874 qreal instVelocity = yDelta / elapsed;
1876 if ((instVelocity < 0 && d->vData.velocity > 0) || (instVelocity > 0 && d->vData.velocity < 0)) {
1877 d->vData.velocitySamples = 0;
1878 d->vData.velocityWritePos = 0;
1880 d->vData.addVelocitySample(instVelocity, d->maxVelocity);
1881 d->vData.updateVelocity();
1882 if ((yDelta > 0 && contentY() > -minYExtent()) || (yDelta < 0 && contentY() < -maxYExtent())) {
1883 const bool newFlick = d->flickY(event->type(), d->vData.velocity);
1884 if (newFlick && (d->vData.atBeginning != (yDelta > 0) || d->vData.atEnd != (yDelta < 0))) {
1885 d->flickingStarted(
false,
true);
1892 if (xflick() && xDelta != 0) {
1893 qreal instVelocity = xDelta / elapsed;
1895 if ((instVelocity < 0 && d->hData.velocity > 0) || (instVelocity > 0 && d->hData.velocity < 0)) {
1896 d->hData.velocitySamples = 0;
1897 d->hData.velocityWritePos = 0;
1899 d->hData.addVelocitySample(instVelocity, d->maxVelocity);
1900 d->hData.updateVelocity();
1901 if ((xDelta > 0 && contentX() > -minXExtent()) || (xDelta < 0 && contentX() < -maxXExtent())) {
1902 const bool newFlick = d->flickX(event->type(), d->hData.velocity);
1903 if (newFlick && (d->hData.atBeginning != (xDelta > 0) || d->hData.atEnd != (xDelta < 0))) {
1904 d->flickingStarted(
true,
false);
1914 int xDelta = event->pixelDelta().x();
1915 int yDelta = event->pixelDelta().y();
1917 QVector2D velocity(xDelta / elapsed, yDelta / elapsed);
1918 d->accumulatedWheelPixelDelta += QVector2D(event->pixelDelta());
1924 if (isMoving() || isFlicking() || (yflick() && xflick())
1925 || (xflick() && qAbs(d->accumulatedWheelPixelDelta.x()) > qAbs(d->accumulatedWheelPixelDelta.y() * 2))
1926 || (yflick() && qAbs(d->accumulatedWheelPixelDelta.y()) > qAbs(d->accumulatedWheelPixelDelta.x() * 2))) {
1927 d->drag(currentTimestamp, event->type(), event->position(), d->accumulatedWheelPixelDelta,
1928 true, !d->scrollingPhase,
true, velocity);
1929 d->updateBeginningEnd();
1930 if ((xflick() && !isAtXBeginning() && !isAtXEnd()) || (yflick() && !isAtYBeginning() && !isAtYEnd()))
1933 qCDebug(lcWheel) <<
"not dragging: accumulated deltas" << d->accumulatedWheelPixelDelta <<
1934 "moving?" << isMoving() <<
"can flick horizontally?" << xflick() <<
"vertically?" << yflick();
1937 d->lastPosTime = currentTimestamp;
1939 if (!event->isAccepted())
1940 QQuickItem::wheelEvent(event);
1944bool QQuickFlickablePrivate::isInnermostPressDelay(QQuickItem *i)
const
1946 Q_Q(
const QQuickFlickable);
1947 QQuickItem *item = i;
1949 QQuickFlickable *flick = qobject_cast<QQuickFlickable*>(item);
1950 if (flick && flick->pressDelay() > 0 && flick->isInteractive()) {
1952 return (flick == q);
1954 item = item->parentItem();
1959void QQuickFlickablePrivate::captureDelayedPress(QQuickItem *item, QPointerEvent *event)
1961 Q_Q(QQuickFlickable);
1962 if (!q->window() || pressDelay <= 0)
1967 if (!isInnermostPressDelay(item))
1970 delayedPressEvent = QQuickDeliveryAgentPrivate::clonePointerEvent(event);
1971 delayedPressEvent->setAccepted(
false);
1972 delayedPressTimer.start(pressDelay, q);
1973 qCDebug(lcReplay) <<
"begin press delay" << pressDelay <<
"ms with" << delayedPressEvent;
1976void QQuickFlickablePrivate::clearDelayedPress()
1978 if (delayedPressEvent) {
1979 delayedPressTimer.stop();
1980 qCDebug(lcReplay) <<
"clear delayed press" << delayedPressEvent;
1981 delete delayedPressEvent;
1982 delayedPressEvent =
nullptr;
1986void QQuickFlickablePrivate::replayDelayedPress()
1988 Q_Q(QQuickFlickable);
1989 if (delayedPressEvent) {
1991 QScopedPointer<QPointerEvent> event(delayedPressEvent);
1992 delayedPressEvent =
nullptr;
1993 delayedPressTimer.stop();
1996 if (QQuickWindow *window = q->window()) {
1997 auto da = deliveryAgentPrivate();
1998 da->allowChildEventFiltering =
false;
1999 replayingPressEvent =
true;
2000 auto &firstPoint = event->point(0);
2006 if (event->exclusiveGrabber(firstPoint) == q)
2007 event->setExclusiveGrabber(firstPoint,
nullptr);
2009 qCDebug(lcReplay) <<
"replaying" << event.data();
2012 QMutableEventPoint::setPosition(firstPoint, firstPoint.scenePosition());
2016 QCoreApplication::sendEvent(window, event.data());
2017 qCDebug(lcReplay) <<
"replay done";
2020 replayingPressEvent =
false;
2021 da->allowChildEventFiltering =
true;
2029
2030
2031
2032
2033
2034
2035
2036void QQuickFlickablePrivate::setViewportX(qreal x)
2038 Q_Q(QQuickFlickable);
2039 qreal effectiveX = pixelAligned ? -std::round(-x) : x;
2041 const qreal maxX = q->maxXExtent();
2042 const qreal minX = q->minXExtent();
2044 if (boundsMovement ==
int(QQuickFlickable::StopAtBounds))
2045 effectiveX = qBound(maxX, effectiveX, minX);
2047 contentItem->setX(effectiveX);
2048 if (contentItem->x() != effectiveX)
2051 qreal overshoot = 0.0;
2053 overshoot = maxX - x;
2055 overshoot = minX - x;
2057 if (overshoot != hData.overshoot) {
2058 hData.overshoot = overshoot;
2059 emit q->horizontalOvershootChanged();
2064
2065
2066
2067
2068
2069
2070
2071void QQuickFlickablePrivate::setViewportY(qreal y)
2073 Q_Q(QQuickFlickable);
2074 qreal effectiveY = pixelAligned ? -std::round(-y) : y;
2076 const qreal maxY = q->maxYExtent();
2077 const qreal minY = q->minYExtent();
2079 if (boundsMovement ==
int(QQuickFlickable::StopAtBounds))
2080 effectiveY = qBound(maxY, effectiveY, minY);
2082 contentItem->setY(effectiveY);
2083 if (contentItem->y() != effectiveY)
2086 qreal overshoot = 0.0;
2088 overshoot = maxY - y;
2090 overshoot = minY - y;
2092 if (overshoot != vData.overshoot) {
2093 vData.overshoot = overshoot;
2094 emit q->verticalOvershootChanged();
2098void QQuickFlickable::timerEvent(QTimerEvent *event)
2100 Q_D(QQuickFlickable);
2101 if (event->timerId() == d->delayedPressTimer.timerId()) {
2102 d->delayedPressTimer.stop();
2103 if (d->delayedPressEvent) {
2104 d->replayDelayedPress();
2109qreal QQuickFlickable::minYExtent()
const
2111 Q_D(
const QQuickFlickable);
2112 return d->vData.startMargin;
2115qreal QQuickFlickable::minXExtent()
const
2117 Q_D(
const QQuickFlickable);
2118 return d->hData.startMargin;
2122qreal QQuickFlickable::maxXExtent()
const
2124 Q_D(
const QQuickFlickable);
2125 return qMin<qreal>(minXExtent(), width() - vWidth() - d->hData.endMargin);
2128qreal QQuickFlickable::maxYExtent()
const
2130 Q_D(
const QQuickFlickable);
2131 return qMin<qreal>(minYExtent(), height() - vHeight() - d->vData.endMargin);
2134void QQuickFlickable::componentComplete()
2136 Q_D(QQuickFlickable);
2137 QQuickItem::componentComplete();
2138 if (!d->hData.explicitValue && d->hData.startMargin != 0.)
2139 setContentX(-minXExtent());
2140 if (!d->vData.explicitValue && d->vData.startMargin != 0.)
2141 setContentY(-minYExtent());
2142 if (lcWheel().isDebugEnabled() || lcVel().isDebugEnabled()) {
2143 d->timeline.setObjectName(QLatin1String(
"timeline for Flickable ") + objectName());
2144 d->velocityTimeline.setObjectName(QLatin1String(
"velocity timeline for Flickable ") + objectName());
2148void QQuickFlickable::viewportMoved(Qt::Orientations orient)
2150 Q_D(QQuickFlickable);
2151 if (orient & Qt::Vertical)
2152 d->viewportAxisMoved(d->vData, minYExtent(), maxYExtent(), d->fixupY_callback);
2153 if (orient & Qt::Horizontal)
2154 d->viewportAxisMoved(d->hData, minXExtent(), maxXExtent(), d->fixupX_callback);
2155 d->updateBeginningEnd();
2158void QQuickFlickablePrivate::viewportAxisMoved(AxisData &data, qreal minExtent, qreal maxExtent,
2159 QQuickTimeLineCallback::Callback fixupCallback)
2161 if (!scrollingPhase && (pressed || calcVelocity)) {
2162 int elapsed = data.velocityTime.restart();
2164 qreal velocity = (data.lastPos - data.move.value()) * 1000 / elapsed;
2165 if (qAbs(velocity) > 0) {
2166 velocityTimeline.reset(data.smoothVelocity);
2167 velocityTimeline.set(data.smoothVelocity, velocity);
2168 qCDebug(lcVel) <<
"touchpad scroll phase: velocity" << velocity;
2172 if (timeline.time() > data.vTime) {
2173 velocityTimeline.reset(data.smoothVelocity);
2174 int dt = timeline.time() - data.vTime;
2176 qreal velocity = (data.lastPos - data.move.value()) * 1000 / dt;
2177 if (!qFuzzyCompare(data.smoothVelocity.value(), velocity))
2178 qCDebug(lcVel) <<
"velocity" << data.smoothVelocity.value() <<
"->" << velocity
2179 <<
"computed as (" << data.lastPos <<
"-" << data.move.value() <<
") * 1000 / ("
2180 << timeline.time() <<
"-" << data.vTime <<
")";
2181 data.smoothVelocity.setValue(velocity);
2186 if (!data.inOvershoot && !data.fixingUp && data.flicking
2187 && (data.move.value() > minExtent || data.move.value() < maxExtent)
2188 && qAbs(data.smoothVelocity.value()) > 10) {
2190 qreal overBound = data.move.value() > minExtent
2191 ? data.move.value() - minExtent
2192 : maxExtent - data.move.value();
2193 data.inOvershoot =
true;
2194 qreal maxDistance = overShootDistance(qAbs(data.smoothVelocity.value())) - overBound;
2195 resetTimeline(data);
2196 if (maxDistance > 0)
2198 timeline.callback(QQuickTimeLineCallback(&data.move, fixupCallback,
this));
2201 data.lastPos = data.move.value();
2202 data.vTime = timeline.time();
2205void QQuickFlickable::geometryChange(
const QRectF &newGeometry,
const QRectF &oldGeometry)
2207 Q_D(QQuickFlickable);
2208 QQuickItem::geometryChange(newGeometry, oldGeometry);
2210 bool changed =
false;
2211 if (newGeometry.width() != oldGeometry.width()) {
2213 if (d->hData.viewSize < 0)
2214 d->contentItem->setWidth(width() - d->hData.startMargin - d->hData.endMargin);
2216 if (!d->pressed && !d->hData.moving && !d->vData.moving) {
2217 d->fixupMode = QQuickFlickablePrivate::Immediate;
2221 if (newGeometry.height() != oldGeometry.height()) {
2223 if (d->vData.viewSize < 0)
2224 d->contentItem->setHeight(height() - d->vData.startMargin - d->vData.endMargin);
2226 if (!d->pressed && !d->hData.moving && !d->vData.moving) {
2227 d->fixupMode = QQuickFlickablePrivate::Immediate;
2233 d->updateBeginningEnd();
2237
2238
2239
2240
2241
2242
2243
2245void QQuickFlickable::flick(qreal xVelocity, qreal yVelocity)
2247 Q_D(QQuickFlickable);
2250 d->hData.velocity = xVelocity;
2251 d->vData.velocity = yVelocity;
2252 d->hData.vTime = d->vData.vTime = d->timeline.time();
2254 const bool flickedX = xflick() && !qFuzzyIsNull(xVelocity) && d->flickX(QEvent::TouchUpdate, xVelocity);
2255 const bool flickedY = yflick() && !qFuzzyIsNull(yVelocity) && d->flickY(QEvent::TouchUpdate, yVelocity);
2262 d->flickingStarted(flickedX, flickedY);
2265void QQuickFlickablePrivate::flickingStarted(
bool flickingH,
bool flickingV)
2267 Q_Q(QQuickFlickable);
2268 if (!flickingH && !flickingV)
2271 bool wasFlicking = hData.flicking || vData.flicking;
2272 if (flickingH && !hData.flicking) {
2273 hData.flicking =
true;
2274 emit q->flickingHorizontallyChanged();
2276 if (flickingV && !vData.flicking) {
2277 vData.flicking =
true;
2278 emit q->flickingVerticallyChanged();
2280 if (!wasFlicking && (hData.flicking || vData.flicking)) {
2281 emit q->flickingChanged();
2282 emit q->flickStarted();
2287
2288
2289
2290
2292void QQuickFlickable::cancelFlick()
2294 Q_D(QQuickFlickable);
2295 d->resetTimeline(d->hData);
2296 d->resetTimeline(d->vData);
2301
2302
2303
2304
2305
2306
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
2333void QQuickFlickable::positionViewAtChild(QQuickItem *child, PositionMode mode,
const QPointF &offset)
2335 Q_D(QQuickFlickable);
2338 if (!d->contentItem->isAncestorOf(child))
2341 const QRectF itemRect =
2342 child->mapRectToItem(d->contentItem, QRectF(0, 0, child->width(), child->height()));
2344 QPointF currentPosition = QPointF(contentX(), contentY());
2345 QPointF newPosition = computePosition(currentPosition, itemRect, mode, offset);
2347 if (newPosition.x() != currentPosition.x()) {
2348 setContentX(newPosition.x());
2351 if (newPosition.y() != currentPosition.y()) {
2352 setContentY(newPosition.y());
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2389void QQuickFlickable::flickToChild(QQuickItem *child, PositionMode mode,
const QPointF &offset)
2391 Q_D(QQuickFlickable);
2394 if (!d->contentItem->isAncestorOf(child))
2397 const QRectF itemRect =
2398 child->mapRectToItem(d->contentItem, QRectF(0, 0, child->width(), child->height()));
2400 QPointF currentPosition = QPointF(contentX(), contentY());
2401 QPointF newPosition = computePosition(currentPosition, itemRect, mode, offset);
2403 flickTo(newPosition);
2407
2408
2409
2410
2411
2412
2413
2414
2416void QQuickFlickable::flickTo(
const QPointF &newPosition)
2418 Q_D(QQuickFlickable);
2420 QPointF currentPosition = QPointF(contentX(), contentY());
2422 qreal xVelocity = 0.0;
2423 qreal yVelocity = 0.0;
2425 const qreal deltaX = newPosition.x() - currentPosition.x();
2426 const qreal deltaY = newPosition.y() - currentPosition.y();
2431 if (xflick() && qAbs(deltaX) > 0.5) {
2432 const qreal decel = flickDeceleration();
2433 qreal velocity = qSqrt(2.0 * decel * qAbs(deltaX));
2434 if (qAbs(velocity) < _q_MinimumFlickVelocity)
2436 const qreal maxVel = maximumFlickVelocity();
2437 if (maxVel > 0 && velocity > maxVel)
2439 xVelocity = deltaX > 0 ? -velocity : velocity;
2442 if (yflick() && qAbs(deltaY) > 0.5) {
2443 const qreal decel = flickDeceleration();
2444 qreal velocity = qSqrt(2.0 * decel * qAbs(deltaY));
2445 if (qAbs(velocity) < _q_MinimumFlickVelocity)
2447 const qreal maxVel = maximumFlickVelocity();
2448 if (maxVel > 0 && velocity > maxVel)
2450 yVelocity = deltaY > 0 ? -velocity : velocity;
2453 if (qAbs(xVelocity) > 0.0 || qAbs(yVelocity) > 0.0) {
2454 flick(xVelocity, yVelocity);
2456 if (newPosition.x() != currentPosition.x()) {
2457 setContentX(newPosition.x());
2460 if (newPosition.y() != currentPosition.y()) {
2461 setContentY(newPosition.y());
2467void QQuickFlickablePrivate::data_append(QQmlListProperty<QObject> *prop, QObject *o)
2469 if (!prop || !prop->data)
2472 if (QQuickItem *i = qmlobject_cast<QQuickItem *>(o)) {
2473 i->setParentItem(
static_cast<QQuickFlickablePrivate*>(prop->data)->contentItem);
2474 }
else if (QQuickPointerHandler *pointerHandler = qmlobject_cast<QQuickPointerHandler *>(o)) {
2475 static_cast<QQuickFlickablePrivate*>(prop->data)->addPointerHandler(pointerHandler);
2477 o->setParent(prop->object);
2481qsizetype QQuickFlickablePrivate::data_count(QQmlListProperty<QObject> *)
2487QObject *QQuickFlickablePrivate::data_at(QQmlListProperty<QObject> *, qsizetype)
2493void QQuickFlickablePrivate::data_clear(QQmlListProperty<QObject> *)
2498QQmlListProperty<QObject> QQuickFlickable::flickableData()
2500 Q_D(QQuickFlickable);
2501 return QQmlListProperty<QObject>(
this, (
void *)d, QQuickFlickablePrivate::data_append,
2502 QQuickFlickablePrivate::data_count,
2503 QQuickFlickablePrivate::data_at,
2504 QQuickFlickablePrivate::data_clear);
2507QQmlListProperty<QQuickItem> QQuickFlickable::flickableChildren()
2509 Q_D(QQuickFlickable);
2510 return QQuickItemPrivate::get(d->contentItem)->children();
2514
2515
2516
2517
2518
2519
2520
2521
2522
2523
2524
2525
2526
2527
2528
2529
2530
2531
2532
2533
2534
2535
2536
2537
2538
2539QQuickFlickable::BoundsBehavior QQuickFlickable::boundsBehavior()
const
2541 Q_D(
const QQuickFlickable);
2542 return d->boundsBehavior;
2545void QQuickFlickable::setBoundsBehavior(BoundsBehavior b)
2547 Q_D(QQuickFlickable);
2548 if (b == d->boundsBehavior)
2550 d->boundsBehavior = b;
2551 emit boundsBehaviorChanged();
2555
2556
2557
2558
2559
2560
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
2594QQuickTransition *QQuickFlickable::rebound()
const
2596 Q_D(
const QQuickFlickable);
2600void QQuickFlickable::setRebound(QQuickTransition *transition)
2602 Q_D(QQuickFlickable);
2604 if (!d->hData.transitionToBounds)
2605 d->hData.transitionToBounds =
new QQuickFlickableReboundTransition(
this, QLatin1String(
"x"));
2606 if (!d->vData.transitionToBounds)
2607 d->vData.transitionToBounds =
new QQuickFlickableReboundTransition(
this, QLatin1String(
"y"));
2609 if (d->rebound != transition) {
2610 d->rebound = transition;
2611 emit reboundChanged();
2616
2617
2618
2619
2620
2621
2622
2623
2624
2625
2626
2627
2628
2629
2630
2631
2632
2633
2634
2635
2636
2637
2638
2639qreal QQuickFlickable::contentWidth()
const
2641 Q_D(
const QQuickFlickable);
2642 return d->hData.viewSize;
2645void QQuickFlickable::setContentWidth(qreal w)
2647 Q_D(QQuickFlickable);
2648 if (d->hData.viewSize == w)
2650 d->hData.viewSize = w;
2652 d->contentItem->setWidth(width() - d->hData.startMargin - d->hData.endMargin);
2654 d->contentItem->setWidth(w);
2655 d->hData.markExtentsDirty();
2657 if (!d->pressed && !d->hData.moving && !d->vData.moving) {
2658 d->fixupMode = QQuickFlickablePrivate::Immediate;
2660 }
else if (!d->pressed && d->hData.fixingUp) {
2661 d->fixupMode = QQuickFlickablePrivate::ExtentChanged;
2664 emit contentWidthChanged();
2665 d->updateBeginningEnd();
2668qreal QQuickFlickable::contentHeight()
const
2670 Q_D(
const QQuickFlickable);
2671 return d->vData.viewSize;
2674void QQuickFlickable::setContentHeight(qreal h)
2676 Q_D(QQuickFlickable);
2677 if (d->vData.viewSize == h)
2679 d->vData.viewSize = h;
2681 d->contentItem->setHeight(height() - d->vData.startMargin - d->vData.endMargin);
2683 d->contentItem->setHeight(h);
2684 d->vData.markExtentsDirty();
2686 if (!d->pressed && !d->hData.moving && !d->vData.moving) {
2687 d->fixupMode = QQuickFlickablePrivate::Immediate;
2689 }
else if (!d->pressed && d->vData.fixingUp) {
2690 d->fixupMode = QQuickFlickablePrivate::ExtentChanged;
2693 emit contentHeightChanged();
2694 d->updateBeginningEnd();
2698
2699
2700
2701
2702
2703
2704
2705
2708qreal QQuickFlickable::topMargin()
const
2710 Q_D(
const QQuickFlickable);
2711 return d->vData.startMargin;
2714void QQuickFlickable::setTopMargin(qreal m)
2716 Q_D(QQuickFlickable);
2717 if (d->vData.startMargin == m)
2719 d->vData.startMargin = m;
2720 d->vData.markExtentsDirty();
2721 if (!d->pressed && !d->hData.moving && !d->vData.moving) {
2723 d->fixupMode = QQuickFlickablePrivate::Immediate;
2726 emit topMarginChanged();
2727 d->updateBeginningEnd();
2730qreal QQuickFlickable::bottomMargin()
const
2732 Q_D(
const QQuickFlickable);
2733 return d->vData.endMargin;
2736void QQuickFlickable::setBottomMargin(qreal m)
2738 Q_D(QQuickFlickable);
2739 if (d->vData.endMargin == m)
2741 d->vData.endMargin = m;
2742 d->vData.markExtentsDirty();
2743 if (!d->pressed && !d->hData.moving && !d->vData.moving) {
2745 d->fixupMode = QQuickFlickablePrivate::Immediate;
2748 emit bottomMarginChanged();
2749 d->updateBeginningEnd();
2752qreal QQuickFlickable::leftMargin()
const
2754 Q_D(
const QQuickFlickable);
2755 return d->hData.startMargin;
2758void QQuickFlickable::setLeftMargin(qreal m)
2760 Q_D(QQuickFlickable);
2761 if (d->hData.startMargin == m)
2763 d->hData.startMargin = m;
2764 d->hData.markExtentsDirty();
2765 if (!d->pressed && !d->hData.moving && !d->vData.moving) {
2767 d->fixupMode = QQuickFlickablePrivate::Immediate;
2770 emit leftMarginChanged();
2771 d->updateBeginningEnd();
2774qreal QQuickFlickable::rightMargin()
const
2776 Q_D(
const QQuickFlickable);
2777 return d->hData.endMargin;
2780void QQuickFlickable::setRightMargin(qreal m)
2782 Q_D(QQuickFlickable);
2783 if (d->hData.endMargin == m)
2785 d->hData.endMargin = m;
2786 d->hData.markExtentsDirty();
2787 if (!d->pressed && !d->hData.moving && !d->vData.moving) {
2789 d->fixupMode = QQuickFlickablePrivate::Immediate;
2792 emit rightMarginChanged();
2793 d->updateBeginningEnd();
2797
2798
2799
2800
2801
2802
2803
2804
2805
2806
2807
2808
2810qreal QQuickFlickable::originY()
const
2812 Q_D(
const QQuickFlickable);
2813 return -minYExtent() + d->vData.startMargin;
2816qreal QQuickFlickable::originX()
const
2818 Q_D(
const QQuickFlickable);
2819 return -minXExtent() + d->hData.startMargin;
2824
2825
2826
2827
2828
2829
2830
2831
2832
2833
2834
2835void QQuickFlickable::resizeContent(qreal w, qreal h, QPointF center)
2837 Q_D(QQuickFlickable);
2838 const qreal oldHSize = d->hData.viewSize;
2839 const qreal oldVSize = d->vData.viewSize;
2840 const bool needToUpdateWidth = w != oldHSize;
2841 const bool needToUpdateHeight = h != oldVSize;
2842 d->hData.viewSize = w;
2843 d->vData.viewSize = h;
2844 d->contentItem->setSize(QSizeF(w, h));
2845 if (needToUpdateWidth)
2846 emit contentWidthChanged();
2847 if (needToUpdateHeight)
2848 emit contentHeightChanged();
2850 if (center.x() != 0) {
2851 qreal pos = center.x() * w / oldHSize;
2852 setContentX(contentX() + pos - center.x());
2854 if (center.y() != 0) {
2855 qreal pos = center.y() * h / oldVSize;
2856 setContentY(contentY() + pos - center.y());
2858 d->updateBeginningEnd();
2862
2863
2864
2865
2866
2867
2868
2869void QQuickFlickable::returnToBounds()
2871 Q_D(QQuickFlickable);
2876qreal QQuickFlickable::vWidth()
const
2878 Q_D(
const QQuickFlickable);
2879 if (d->hData.viewSize < 0)
2882 return d->hData.viewSize;
2885qreal QQuickFlickable::vHeight()
const
2887 Q_D(
const QQuickFlickable);
2888 if (d->vData.viewSize < 0)
2891 return d->vData.viewSize;
2895
2896
2897
2898
2899
2900
2901bool QQuickFlickable::xflick()
const
2903 Q_D(
const QQuickFlickable);
2904 const int contentWidthWithMargins = d->contentItem->width() + d->hData.startMargin + d->hData.endMargin;
2905 if ((d->flickableDirection & QQuickFlickable::AutoFlickIfNeeded) && (contentWidthWithMargins > width()))
2907 if (d->flickableDirection == QQuickFlickable::AutoFlickDirection)
2908 return std::floor(qAbs(contentWidthWithMargins - width()));
2909 return d->flickableDirection & QQuickFlickable::HorizontalFlick;
2913
2914
2915
2916
2917
2918
2919bool QQuickFlickable::yflick()
const
2921 Q_D(
const QQuickFlickable);
2922 const int contentHeightWithMargins = d->contentItem->height() + d->vData.startMargin + d->vData.endMargin;
2923 if ((d->flickableDirection & QQuickFlickable::AutoFlickIfNeeded) && (contentHeightWithMargins > height()))
2925 if (d->flickableDirection == QQuickFlickable::AutoFlickDirection)
2926 return std::floor(qAbs(contentHeightWithMargins - height()));
2927 return d->flickableDirection & QQuickFlickable::VerticalFlick;
2930QPointF QQuickFlickable::computePosition(QPointF currentPosition, QRectF itemRect, PositionMode mode,
const QPointF &offset)
const
2932 QPointF newPosition = currentPosition;
2935 const qreal viewWidth = width();
2937 if (mode & QQuickFlickable::AlignLeft)
2938 newPosition.setX(itemRect.left());
2939 if (mode & QQuickFlickable::AlignHCenter)
2940 newPosition.setX(itemRect.left() - (viewWidth - itemRect.width()) / 2);
2941 if (mode & QQuickFlickable::AlignRight)
2942 newPosition.setX(itemRect.right() - viewWidth);
2943 if (mode & QQuickFlickable::Visible) {
2944 if (itemRect.right() < currentPosition.x())
2945 newPosition.setX(itemRect.left());
2946 else if (itemRect.left() > currentPosition.x() + viewWidth)
2947 newPosition.setX(itemRect.right() - viewWidth);
2949 if (mode & QQuickFlickable::Contain) {
2950 if (itemRect.right() > currentPosition.x() + viewWidth)
2951 newPosition.setX(itemRect.right() - viewWidth);
2952 if (itemRect.left() < newPosition.x())
2953 newPosition.setX(itemRect.left());
2956 const qreal minX = -minXExtent();
2957 const qreal maxX = -maxXExtent();
2958 newPosition.setX(qMin(newPosition.x(), maxX));
2959 newPosition.setX(qMax(newPosition.x(), minX));
2963 const qreal viewHeight = height();
2965 if (mode & QQuickFlickable::AlignTop)
2966 newPosition.setY(itemRect.top());
2967 if (mode & QQuickFlickable::AlignVCenter)
2968 newPosition.setY(itemRect.top() - (viewHeight - itemRect.height()) / 2);
2969 if (mode & QQuickFlickable::AlignBottom)
2970 newPosition.setY(itemRect.bottom() - viewHeight);
2971 if (mode & QQuickFlickable::Visible) {
2972 if (itemRect.bottom() < currentPosition.y())
2973 newPosition.setY(itemRect.top());
2974 else if (itemRect.top() > currentPosition.y() + viewHeight)
2975 newPosition.setY(itemRect.bottom() - viewHeight);
2977 if (mode & QQuickFlickable::Contain) {
2978 if (itemRect.bottom() > currentPosition.y() + viewHeight)
2979 newPosition.setY(itemRect.bottom() - viewHeight);
2980 if (itemRect.top() < currentPosition.y())
2981 newPosition.setY(itemRect.top());
2984 const qreal minY = -minYExtent();
2985 const qreal maxY = -maxYExtent();
2986 newPosition.setY(qMin(newPosition.y(), maxY));
2987 newPosition.setY(qMax(newPosition.y(), minY));
2990 return newPosition + offset;
2993void QQuickFlickable::mouseUngrabEvent()
2995 Q_D(QQuickFlickable);
2998 if (!d->replayingPressEvent)
2999 d->cancelInteraction();
3002void QQuickFlickablePrivate::cancelInteraction()
3004 Q_Q(QQuickFlickable);
3006 clearDelayedPress();
3010 q->setKeepMouseGrab(
false);
3011 q->setKeepTouchGrab(
false);
3014 if (!isViewMoving())
3015 q->movementEnding();
3019void QQuickFlickablePrivate::addPointerHandler(QQuickPointerHandler *h)
3021 Q_Q(
const QQuickFlickable);
3022 qCDebug(lcHandlerParent) <<
"reparenting handler" << h <<
"to contentItem of" << q;
3023 h->setParent(contentItem);
3024 QQuickItemPrivate::get(contentItem)->addPointerHandler(h);
3028
3029
3030
3031
3032
3033
3034
3035bool QQuickFlickable::filterPointerEvent(QQuickItem *receiver, QPointerEvent *event)
3037 Q_D(QQuickFlickable);
3038 const bool isTouch = QQuickDeliveryAgentPrivate::isTouchEvent(event);
3039 const bool isMouse = QQuickDeliveryAgentPrivate::isMouseEvent(event);
3040 if (isMouse || QQuickDeliveryAgentPrivate::isTabletEvent(event)) {
3041 if (!d->buttonsAccepted(
static_cast<QSinglePointEvent *>(event)))
3042 return QQuickItem::childMouseEventFilter(receiver, event);
3043 }
else if (!isTouch) {
3046 Q_ASSERT_X(receiver !=
this,
"",
"Flickable received a filter event for itself");
3048 if (isTouch &&
static_cast<QTouchEvent *>(event)->touchPointStates().testFlag(QEventPoint::State::Pressed))
3049 d->stealGrab =
false;
3050 const auto &firstPoint = event->points().first();
3052 if (event->pointCount() == 1 && event->exclusiveGrabber(firstPoint) ==
this) {
3064 QPointF localPos = mapFromScene(firstPoint.scenePosition());
3065 bool receiverDisabled = receiver && !receiver->isEnabled();
3066 bool stealThisEvent = d->stealGrab;
3067 bool receiverKeepsGrab = receiver && (receiver->keepMouseGrab() || receiver->keepTouchGrab());
3068 bool receiverRelinquishGrab =
false;
3071 if (
auto *mouseArea = qmlobject_cast<QQuickMouseArea *>(receiver)) {
3072 bool preventStealing = mouseArea->preventStealing();
3073#if QT_CONFIG(quick_draganddrop)
3074 if (mouseArea->drag() && mouseArea->drag()->target())
3075 preventStealing =
true;
3077 if (!preventStealing && receiverKeepsGrab) {
3078 receiverRelinquishGrab = !receiverDisabled || (isMouse
3079 && firstPoint.state() == QEventPoint::State::Pressed
3080 && (receiver->acceptedMouseButtons() &
static_cast<QMouseEvent *>(event)->button()));
3081 if (receiverRelinquishGrab)
3082 receiverKeepsGrab =
false;
3086 if ((stealThisEvent || contains(localPos)) && (!receiver || !receiverKeepsGrab || receiverDisabled)) {
3087 QScopedPointer<QPointerEvent> localizedEvent(QQuickDeliveryAgentPrivate::clonePointerEvent(event, localPos));
3088 localizedEvent->setAccepted(
false);
3089 switch (firstPoint.state()) {
3090 case QEventPoint::State::Updated:
3091 d->handleMoveEvent(localizedEvent.data());
3093 case QEventPoint::State::Pressed:
3094 d->handlePressEvent(localizedEvent.data());
3095 d->captureDelayedPress(receiver, event);
3097 d->stealGrab =
false;
3098 stealThisEvent =
false;
3100 case QEventPoint::State::Released:
3101 d->handleReleaseEvent(localizedEvent.data());
3102 stealThisEvent = d->stealGrab;
3104 case QEventPoint::State::Stationary:
3105 case QEventPoint::State::Unknown:
3108 if ((receiver && stealThisEvent && !receiverKeepsGrab && receiver !=
this) || receiverDisabled) {
3109 d->clearDelayedPress();
3110 event->setExclusiveGrabber(firstPoint,
this);
3111 }
else if (d->delayedPressEvent) {
3112 event->setExclusiveGrabber(firstPoint,
this);
3115
3116
3117
3118
3119
3120
3121
3122
3123
3124
3125
3126 if (isMoving() || (!receiverRelinquishGrab && (stealThisEvent || d->delayedPressEvent || receiverDisabled))) {
3128 event->setAccepted(
true);
3134 }
else if (d->lastPosTime != -1) {
3135 d->lastPosTime = -1;
3138 if (firstPoint.state() == QEventPoint::State::Released || (receiverKeepsGrab && !receiverDisabled)) {
3140 d->lastPosTime = -1;
3141 d->clearDelayedPress();
3142 d->stealGrab =
false;
3149
3150
3151
3152bool QQuickFlickable::childMouseEventFilter(QQuickItem *i, QEvent *e)
3154 Q_D(QQuickFlickable);
3155 QPointerEvent *pointerEvent = e->isPointerEvent() ?
static_cast<QPointerEvent *>(e) :
nullptr;
3157 auto wantsPointerEvent_helper = [
this, d, i, pointerEvent]() {
3158 Q_ASSERT(pointerEvent);
3159 QQuickDeliveryAgentPrivate::localizePointerEvent(pointerEvent,
this);
3160 const bool wants = d->wantsPointerEvent(pointerEvent);
3162 QQuickDeliveryAgentPrivate::localizePointerEvent(pointerEvent, i);
3166 if (!isVisible() || !isEnabled() || !isInteractive() ||
3167 (pointerEvent && !wantsPointerEvent_helper())) {
3168 d->cancelInteraction();
3169 return QQuickItem::childMouseEventFilter(i, e);
3172 if (e->type() == QEvent::UngrabMouse) {
3173 Q_ASSERT(e->isSinglePointEvent());
3174 auto spe =
static_cast<QSinglePointEvent *>(e);
3175 const QObject *grabber = spe->exclusiveGrabber(spe->points().first());
3176 qCDebug(lcFilter) <<
"filtering UngrabMouse" << spe->points().first() <<
"for" << i <<
"grabber is" << grabber;
3177 if (grabber !=
this)
3179 }
else if (pointerEvent) {
3180 return filterPointerEvent(i, pointerEvent);
3183 return QQuickItem::childMouseEventFilter(i, e);
3187
3188
3189
3190
3191
3192qreal QQuickFlickable::maximumFlickVelocity()
const
3194 Q_D(
const QQuickFlickable);
3195 return d->maxVelocity;
3198void QQuickFlickable::setMaximumFlickVelocity(qreal v)
3200 Q_D(QQuickFlickable);
3201 if (v == d->maxVelocity)
3204 emit maximumFlickVelocityChanged();
3208
3209
3210
3211
3212
3213
3214
3215
3216qreal QQuickFlickable::flickDeceleration()
const
3218 Q_D(
const QQuickFlickable);
3219 return d->deceleration;
3222void QQuickFlickable::setFlickDeceleration(qreal deceleration)
3224 Q_D(QQuickFlickable);
3225 if (deceleration == d->deceleration)
3227 d->deceleration = qMax(0.001, deceleration);
3228 emit flickDecelerationChanged();
3231bool QQuickFlickable::isFlicking()
const
3233 Q_D(
const QQuickFlickable);
3234 return d->hData.flicking || d->vData.flicking;
3238
3239
3240
3241
3242
3243
3244
3245bool QQuickFlickable::isFlickingHorizontally()
const
3247 Q_D(
const QQuickFlickable);
3248 return d->hData.flicking;
3251bool QQuickFlickable::isFlickingVertically()
const
3253 Q_D(
const QQuickFlickable);
3254 return d->vData.flicking;
3258
3259
3260
3261
3262
3263
3264
3265bool QQuickFlickable::isDragging()
const
3267 Q_D(
const QQuickFlickable);
3268 return d->hData.dragging || d->vData.dragging;
3271bool QQuickFlickable::isDraggingHorizontally()
const
3273 Q_D(
const QQuickFlickable);
3274 return d->hData.dragging;
3277bool QQuickFlickable::isDraggingVertically()
const
3279 Q_D(
const QQuickFlickable);
3280 return d->vData.dragging;
3283void QQuickFlickablePrivate::draggingStarting()
3285 Q_Q(QQuickFlickable);
3286 bool wasDragging = hData.dragging || vData.dragging;
3287 if (hMoved && !hData.dragging) {
3288 hData.dragging =
true;
3289 emit q->draggingHorizontallyChanged();
3291 if (vMoved && !vData.dragging) {
3292 vData.dragging =
true;
3293 emit q->draggingVerticallyChanged();
3295 if (!wasDragging && (hData.dragging || vData.dragging)) {
3296 emit q->draggingChanged();
3297 emit q->dragStarted();
3301void QQuickFlickablePrivate::draggingEnding()
3303 Q_Q(QQuickFlickable);
3304 const bool wasDragging = hData.dragging || vData.dragging;
3305 if (hData.dragging) {
3306 hData.dragging =
false;
3307 emit q->draggingHorizontallyChanged();
3309 if (vData.dragging) {
3310 vData.dragging =
false;
3311 emit q->draggingVerticallyChanged();
3314 if (!hData.dragging && !vData.dragging) {
3315 emit q->draggingChanged();
3316 emit q->dragEnded();
3318 hData.inRebound =
false;
3319 vData.inRebound =
false;
3323bool QQuickFlickablePrivate::isViewMoving()
const
3325 if (timeline.isActive()
3326 || (hData.transitionToBounds && hData.transitionToBounds->isActive())
3327 || (vData.transitionToBounds && vData.transitionToBounds->isActive()) ) {
3334
3335
3336
3337
3338
3339
3340
3341
3342
3343
3344
3345
3346
3347
3348
3349
3350
3351int QQuickFlickable::pressDelay()
const
3353 Q_D(
const QQuickFlickable);
3354 return d->pressDelay;
3357void QQuickFlickable::setPressDelay(
int delay)
3359 Q_D(QQuickFlickable);
3360 if (d->pressDelay == delay)
3362 d->pressDelay = delay;
3363 emit pressDelayChanged();
3367
3368
3369
3370
3371
3372
3373
3374
3376bool QQuickFlickable::isMoving()
const
3378 Q_D(
const QQuickFlickable);
3379 return d->hData.moving || d->vData.moving;
3382bool QQuickFlickable::isMovingHorizontally()
const
3384 Q_D(
const QQuickFlickable);
3385 return d->hData.moving;
3388bool QQuickFlickable::isMovingVertically()
const
3390 Q_D(
const QQuickFlickable);
3391 return d->vData.moving;
3394void QQuickFlickable::velocityTimelineCompleted()
3396 Q_D(QQuickFlickable);
3397 if ( (d->hData.transitionToBounds && d->hData.transitionToBounds->isActive())
3398 || (d->vData.transitionToBounds && d->vData.transitionToBounds->isActive()) ) {
3405 if (d->vData.flicking)
3407 d->updateBeginningEnd();
3410void QQuickFlickable::timelineCompleted()
3412 Q_D(QQuickFlickable);
3413 if ( (d->hData.transitionToBounds && d->hData.transitionToBounds->isActive())
3414 || (d->vData.transitionToBounds && d->vData.transitionToBounds->isActive()) ) {
3418 d->updateBeginningEnd();
3421void QQuickFlickable::movementStarting()
3423 Q_D(QQuickFlickable);
3424 bool wasMoving = d->hData.moving || d->vData.moving;
3425 if (d->hMoved && !d->hData.moving) {
3426 d->hData.moving =
true;
3427 emit movingHorizontallyChanged();
3429 if (d->vMoved && !d->vData.moving) {
3430 d->vData.moving =
true;
3431 emit movingVerticallyChanged();
3434 if (!wasMoving && (d->hData.moving || d->vData.moving)) {
3435 emit movingChanged();
3436 emit movementStarted();
3437#if QT_CONFIG(accessibility)
3438 if (QAccessible::isActive()) {
3439 QAccessibleEvent ev(
this, QAccessible::ScrollingStart);
3440 QAccessible::updateAccessibility(&ev);
3446void QQuickFlickable::movementEnding()
3448 movementEnding(
true,
true);
3451void QQuickFlickable::movementEnding(
bool hMovementEnding,
bool vMovementEnding)
3453 Q_D(QQuickFlickable);
3456 const bool wasFlicking = d->hData.flicking || d->vData.flicking;
3457 if (hMovementEnding && d->hData.flicking) {
3458 d->hData.flicking =
false;
3459 emit flickingHorizontallyChanged();
3461 if (vMovementEnding && d->vData.flicking) {
3462 d->vData.flicking =
false;
3463 emit flickingVerticallyChanged();
3465 if (wasFlicking && (!d->hData.flicking || !d->vData.flicking)) {
3466 emit flickingChanged();
3468 }
else if (d->hData.flickingWhenDragBegan || d->vData.flickingWhenDragBegan) {
3469 d->hData.flickingWhenDragBegan = !hMovementEnding;
3470 d->vData.flickingWhenDragBegan = !vMovementEnding;
3475 bool wasMoving = isMoving();
3476 if (hMovementEnding && d->hData.moving
3477 && (!d->pressed && !d->stealGrab)) {
3478 d->hData.moving =
false;
3480 emit movingHorizontallyChanged();
3482 if (vMovementEnding && d->vData.moving
3483 && (!d->pressed && !d->stealGrab)) {
3484 d->vData.moving =
false;
3486 emit movingVerticallyChanged();
3488 if (wasMoving && !isMoving()) {
3489 emit movingChanged();
3490 emit movementEnded();
3491#if QT_CONFIG(accessibility)
3492 if (QAccessible::isActive()) {
3493 QAccessibleEvent ev(
this, QAccessible::ScrollingEnd);
3494 QAccessible::updateAccessibility(&ev);
3499 if (hMovementEnding) {
3500 d->hData.fixingUp =
false;
3501 d->hData.smoothVelocity.setValue(0);
3502 d->hData.previousDragDelta = 0.0;
3504 if (vMovementEnding) {
3505 d->vData.fixingUp =
false;
3506 d->vData.smoothVelocity.setValue(0);
3507 d->vData.previousDragDelta = 0.0;
3511void QQuickFlickablePrivate::updateVelocity()
3513 Q_Q(QQuickFlickable);
3514 emit q->horizontalVelocityChanged();
3515 emit q->verticalVelocityChanged();
3519
3520
3521
3522
3523
3524
3525
3526
3527
3528
3529
3530
3531
3532
3533qreal QQuickFlickable::horizontalOvershoot()
const
3535 Q_D(
const QQuickFlickable);
3536 return d->hData.overshoot;
3540
3541
3542
3543
3544
3545
3546
3547
3548
3549
3550
3551
3552
3553
3554qreal QQuickFlickable::verticalOvershoot()
const
3556 Q_D(
const QQuickFlickable);
3557 return d->vData.overshoot;
3561
3562
3563
3564
3565
3566
3567
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
3606QQuickFlickable::BoundsMovement QQuickFlickable::boundsMovement()
const
3608 Q_D(
const QQuickFlickable);
3609 return d->boundsMovement;
3612void QQuickFlickable::setBoundsMovement(BoundsMovement movement)
3614 Q_D(QQuickFlickable);
3615 if (d->boundsMovement == movement)
3618 d->boundsMovement = movement;
3619 emit boundsMovementChanged();
3624#include "moc_qquickflickable_p_p.cpp"
3626#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