11#if QT_CONFIG(quick_draganddrop)
12#include "qquickdrag_p.h"
15#include <QtQuick/private/qquickpointerhandler_p.h>
16#include <QtQuick/private/qquicktransition_p.h>
17#include <private/qqmlglobal_p.h>
19#include <QtQml/qqmlinfo.h>
20#include <QtGui/qevent.h>
21#include <QtGui/qguiapplication.h>
22#include <QtGui/private/qguiapplication_p.h>
23#include <QtGui/private/qeventpoint_p.h>
24#include <QtGui/qstylehints.h>
25#include <QtGui/qaccessible.h>
26#include <QtCore/qmath.h>
27#include <qpa/qplatformtheme.h>
35Q_STATIC_LOGGING_CATEGORY(lcFilter,
"qt.quick.flickable.filter")
36Q_STATIC_LOGGING_CATEGORY(lcReplay,
"qt.quick.flickable.replay")
37Q_STATIC_LOGGING_CATEGORY(lcWheel,
"qt.quick.flickable.wheel")
38Q_STATIC_LOGGING_CATEGORY(lcVel,
"qt.quick.flickable.velocity")
42static const int RetainGrabVelocity = 100;
48QQuickFlickableVisibleArea::QQuickFlickableVisibleArea(QQuickFlickable *parent)
49 : QObject(parent), flickable(parent), m_xPosition(0.), m_widthRatio(0.)
50 , m_yPosition(0.), m_heightRatio(0.)
54qreal QQuickFlickableVisibleArea::widthRatio()
const
59qreal QQuickFlickableVisibleArea::xPosition()
const
64qreal QQuickFlickableVisibleArea::heightRatio()
const
69qreal QQuickFlickableVisibleArea::yPosition()
const
74void QQuickFlickableVisibleArea::updateVisible()
76 QQuickFlickablePrivate *p = QQuickFlickablePrivate::get(flickable);
80 bool changeWidth =
false;
81 bool changeHeight =
false;
84 const qreal viewheight = flickable->height();
85 const qreal maxyextent = -flickable->maxYExtent() + flickable->minYExtent();
86 const qreal maxYBounds = maxyextent + viewheight;
89 if (!qFuzzyIsNull(maxYBounds)) {
90 qreal y = p->pixelAligned ? std::round(p->vData.move.value()) : p->vData.move.value();
91 pagePos = (-y + flickable->minYExtent()) / maxYBounds;
92 pageSize = viewheight / maxYBounds;
95 if (pageSize != m_heightRatio) {
96 m_heightRatio = pageSize;
99 if (pagePos != m_yPosition) {
100 m_yPosition = pagePos;
105 const qreal viewwidth = flickable->width();
106 const qreal maxxextent = -flickable->maxXExtent() + flickable->minXExtent();
107 const qreal maxXBounds = maxxextent + viewwidth;
108 if (!qFuzzyIsNull(maxXBounds)) {
109 qreal x = p->pixelAligned ? std::round(p->hData.move.value()) : p->hData.move.value();
110 pagePos = (-x + flickable->minXExtent()) / maxXBounds;
111 pageSize = viewwidth / maxXBounds;
117 if (pageSize != m_widthRatio) {
118 m_widthRatio = pageSize;
121 if (pagePos != m_xPosition) {
122 m_xPosition = pagePos;
127 emit xPositionChanged(m_xPosition);
129 emit yPositionChanged(m_yPosition);
131 emit widthRatioChanged(m_widthRatio);
133 emit heightRatioChanged(m_heightRatio);
151 QQuickFlickablePrivate *fp = QQuickFlickablePrivate::get(flickable);
152 if (!fp->rebound || !fp->rebound->enabled())
156 axisData->transitionTo = toPos;
157 axisData->transitionToSet =
true;
160 actions << QQuickStateAction(fp->contentItem, propName, toPos);
161 QQuickTransitionManager::transition(actions, fp->rebound, fp->contentItem);
170 if (!flickable || !isRunning())
172 QQuickFlickablePrivate *fp = QQuickFlickablePrivate::get(flickable);
173 if (axisData == &fp->hData)
174 axisData->move.setValue(-flickable->contentX());
176 axisData->move.setValue(-flickable->contentY());
185 axisData->move.setValue(axisData->transitionTo);
186 QQuickFlickablePrivate *fp = QQuickFlickablePrivate::get(flickable);
189 if (!fp->hData.transitionToBounds->isActive()
190 && !fp->vData.transitionToBounds->isActive()) {
191 flickable->movementEnding();
196 QQuickStateOperation::ActionList actions;
197 QQuickFlickable *flickable;
198 QQuickFlickablePrivate::AxisData *axisData;
203QQuickFlickablePrivate::AxisData::~AxisData()
205 delete transitionToBounds;
213 auto *d = QQuickItemPrivate::get(
this);
218 d->eventHandlingChildrenWithinBounds =
false;
219 d->eventHandlingChildrenWithinBoundsSet =
true;
224
225
226
227
228
229
230
231
234 const QQuickItem *flickable = parentItem();
235 const QPointF posInFlickable = flickable->mapFromItem(
this, point);
236 return flickable->contains(posInFlickable);
240QQuickFlickablePrivate::QQuickFlickablePrivate()
241 : contentItem(
new QQuickFlickableContentItem)
242 , hData(
this, &QQuickFlickablePrivate::setViewportX)
243 , vData(
this, &QQuickFlickablePrivate::setViewportY)
244 , hMoved(
false), vMoved(
false)
245 , stealMouse(
false), pressed(
false)
246 , scrollingPhase(
false), interactive(
true), calcVelocity(
false)
247 , pixelAligned(
false)
249 , acceptedButtons(Qt::LeftButton)
252 , deceleration(QGuiApplicationPrivate::platformTheme()->themeHint(QPlatformTheme::FlickDeceleration).toReal())
253 , wheelDeceleration(15000)
254 , maxVelocity(QGuiApplicationPrivate::platformTheme()->themeHint(QPlatformTheme::FlickMaximumVelocity).toReal())
255 , delayedPressEvent(
nullptr), pressDelay(0), fixupDuration(400)
256 , flickBoost(1.0), initialWheelFlickDistance(qApp->styleHints()->wheelScrollLines() * 24)
257 , fixupMode(Normal), vTime(0), visibleArea(
nullptr)
258 , flickableDirection(QQuickFlickable::AutoFlickDirection)
259 , boundsBehavior(QQuickFlickable::DragAndOvershootBounds)
260 , boundsMovement(QQuickFlickable::FollowBoundsBehavior)
263 const int wheelDecelerationEnv = qEnvironmentVariableIntValue(
"QT_QUICK_FLICKABLE_WHEEL_DECELERATION");
264 if (wheelDecelerationEnv > 0)
265 wheelDeceleration = wheelDecelerationEnv;
268void QQuickFlickablePrivate::init()
270 Q_Q(QQuickFlickable);
271 QQml_setParent_noEvent(contentItem, q);
272 contentItem->setParentItem(q);
273 qmlobject_connect(&timeline, QQuickTimeLine, SIGNAL(completed()),
274 q, QQuickFlickable, SLOT(timelineCompleted()));
275 qmlobject_connect(&velocityTimeline, QQuickTimeLine, SIGNAL(completed()),
276 q, QQuickFlickable, SLOT(velocityTimelineCompleted()));
277 q->setAcceptedMouseButtons(acceptedButtons);
278 q->setAcceptTouchEvents(
true);
279 q->setFiltersChildMouseEvents(
true);
280 q->setFlag(QQuickItem::ItemIsViewport);
281 QQuickItemPrivate *viewportPrivate = QQuickItemPrivate::get(contentItem);
282 viewportPrivate->addItemChangeListener(
this, QQuickItemPrivate::Geometry);
283 setSizePolicy(QLayoutPolicy::Expanding, QLayoutPolicy::Expanding);
287
288
289
290
291qreal QQuickFlickablePrivate::overShootDistance(qreal velocity)
const
293 if (maxVelocity <= 0)
299void QQuickFlickablePrivate::AxisData::addVelocitySample(qreal v, qreal maxVelocity)
303 else if (v < -maxVelocity)
305 velocityBuffer.append(v);
307 velocityBuffer.remove(0);
310void QQuickFlickablePrivate::AxisData::updateVelocity()
315 for (
int i = 0; i < count; ++i) {
316 qreal v = velocityBuffer.at(i);
323void QQuickFlickablePrivate::itemGeometryChanged(QQuickItem *item, QQuickGeometryChange change,
const QRectF &oldGeom)
325 Q_Q(QQuickFlickable);
326 if (item == contentItem) {
327 Qt::Orientations orient;
328 if (change.xChange())
329 orient |= Qt::Horizontal;
330 if (change.yChange())
331 orient |= Qt::Vertical;
333 q->viewportMoved(orient);
334 const QPointF deltaMoved = item->position() - oldGeom.topLeft();
335 if (hData.contentPositionChangedExternallyDuringDrag)
336 hData.pressPos += deltaMoved.x();
337 if (vData.contentPositionChangedExternallyDuringDrag)
338 vData.pressPos += deltaMoved.y();
340 if (orient & Qt::Horizontal)
341 emit q->contentXChanged();
342 if (orient & Qt::Vertical)
343 emit q->contentYChanged();
347bool QQuickFlickablePrivate::flickX(QEvent::Type eventType, qreal velocity)
349 Q_Q(QQuickFlickable);
350 return flick(hData, q->minXExtent(), q->maxXExtent(), q->width(), fixupX_callback, eventType, velocity);
353bool QQuickFlickablePrivate::flickY(QEvent::Type eventType, qreal velocity)
355 Q_Q(QQuickFlickable);
356 return flick(vData, q->minYExtent(), q->maxYExtent(), q->height(), fixupY_callback, eventType, velocity);
359bool QQuickFlickablePrivate::flick(AxisData &data, qreal minExtent, qreal maxExtent, qreal,
360 QQuickTimeLineCallback::Callback fixupCallback,
361 QEvent::Type eventType, qreal velocity)
363 Q_Q(QQuickFlickable);
364 qreal maxDistance = -1;
365 data.fixingUp =
false;
368 maxDistance = qAbs(minExtent - data.move.value());
369 data.flickTarget = minExtent;
371 maxDistance = qAbs(maxExtent - data.move.value());
372 data.flickTarget = maxExtent;
374 if (maxDistance > 0 || boundsBehavior & QQuickFlickable::OvershootBounds) {
376 if (maxVelocity != -1 && maxVelocity < qAbs(v)) {
383 qreal accel = eventType == QEvent::Wheel ? wheelDeceleration : deceleration;
384 qCDebug(lcFlickable) <<
"choosing deceleration" << accel <<
"for" << eventType;
387 qreal dist = v2 / (accel * 2.0);
390 qreal target = std::round(data.move.value() - dist);
391 dist = -target + data.move.value();
392 accel = v2 / (2.0f * qAbs(dist));
395 if (!data.inOvershoot) {
396 if (boundsBehavior & QQuickFlickable::OvershootBounds)
397 timeline.accel(data.move, v, accel);
399 timeline.accel(data.move, v, accel, maxDistance);
401 timeline.callback(QQuickTimeLineCallback(&data.move, fixupCallback,
this));
404 return !hData.flicking && q->xflick();
405 else if (&data == &vData)
406 return !vData.flicking && q->yflick();
410 fixup(data, minExtent, maxExtent);
415void QQuickFlickablePrivate::fixupY_callback(
void *data)
417 ((QQuickFlickablePrivate *)data)->fixupY();
420void QQuickFlickablePrivate::fixupX_callback(
void *data)
422 ((QQuickFlickablePrivate *)data)->fixupX();
425void QQuickFlickablePrivate::fixupX()
427 Q_Q(QQuickFlickable);
428 if (!q->isComponentComplete())
430 fixup(hData, q->minXExtent(), q->maxXExtent());
433void QQuickFlickablePrivate::fixupY()
435 Q_Q(QQuickFlickable);
436 if (!q->isComponentComplete())
438 fixup(vData, q->minYExtent(), q->maxYExtent());
442
443
444
445
446
447
448
449void QQuickFlickablePrivate::adjustContentPos(AxisData &data, qreal toPos)
451 Q_Q(QQuickFlickable);
454 timeline.set(data.move, toPos);
459 timeline.move(data.move, toPos, QEasingCurve(QEasingCurve::OutExpo), 3*fixupDuration/4);
460 data.fixingUp =
true;
463 if (data.transitionToBounds && data.transitionToBounds->startTransition(&data, toPos)) {
464 q->movementStarting();
465 data.fixingUp =
true;
467 qreal dist = toPos - data.move;
468 timeline.move(data.move, toPos - dist/2, QEasingCurve(QEasingCurve::InQuad), fixupDuration/4);
469 timeline.move(data.move, toPos, QEasingCurve(QEasingCurve::OutExpo), 3*fixupDuration/4);
470 data.fixingUp =
true;
476void QQuickFlickablePrivate::resetTimeline(AxisData &data)
478 timeline.reset(data.move);
479 if (data.transitionToBounds)
480 data.transitionToBounds->stopTransition();
483void QQuickFlickablePrivate::clearTimeline()
486 if (hData.transitionToBounds)
487 hData.transitionToBounds->stopTransition();
488 if (vData.transitionToBounds)
489 vData.transitionToBounds->stopTransition();
493
494
495
496
497
498
499
500
501
502void QQuickFlickablePrivate::fixup(AxisData &data, qreal minExtent, qreal maxExtent)
507 if (data.move.value() >= minExtent || maxExtent > minExtent) {
508 const bool wasActive = timeline.isActive();
510 if (data.move.value() != minExtent)
511 adjustContentPos(data, minExtent);
513 timeline.move(data.move, data.move.value(), QEasingCurve(QEasingCurve::Linear), 1);
514 }
else if (data.move.value() <= maxExtent) {
516 adjustContentPos(data, maxExtent);
517 }
else if (-std::round(-data.move.value()) != data.move.value()) {
520 qreal val = data.move.value();
521 if (std::abs(std::round(val) - val) < 0.25)
522 val = std::round(val);
523 else if (data.smoothVelocity.value() > 0)
524 val = std::ceil(val);
525 else if (data.smoothVelocity.value() < 0)
526 val = std::floor(val);
528 val = std::round(val);
529 timeline.set(data.move, val);
531 data.inOvershoot =
false;
533 data.vTime = timeline.time();
538 if (a == 0.0 || b == 0.0) {
543 return a <= b || qFuzzyCompare(a, b);
547
548
549
550
551
552
553
554
555void QQuickFlickablePrivate::updateBeginningEnd()
557 Q_Q(QQuickFlickable);
558 bool atXBeginningChange =
false, atXEndChange =
false;
559 bool atYBeginningChange =
false, atYEndChange =
false;
562 const qreal maxyextent = -q->maxYExtent();
563 const qreal minyextent = -q->minYExtent();
564 const qreal ypos = pixelAligned ? -std::round(vData.move.value()) : -vData.move.value();
565 bool atBeginning = fuzzyLessThanOrEqualTo(ypos, std::ceil(minyextent));
566 bool atEnd = fuzzyLessThanOrEqualTo(std::floor(maxyextent), ypos);
568 if (atBeginning != vData.atBeginning) {
569 vData.atBeginning = atBeginning;
570 atYBeginningChange =
true;
571 if (!vData.moving && atBeginning)
572 vData.smoothVelocity.setValue(0);
574 if (atEnd != vData.atEnd) {
577 if (!vData.moving && atEnd)
578 vData.smoothVelocity.setValue(0);
582 const qreal maxxextent = -q->maxXExtent();
583 const qreal minxextent = -q->minXExtent();
584 const qreal xpos = pixelAligned ? -std::round(hData.move.value()) : -hData.move.value();
585 atBeginning = fuzzyLessThanOrEqualTo(xpos, std::ceil(minxextent));
586 atEnd = fuzzyLessThanOrEqualTo(std::floor(maxxextent), xpos);
588 if (atBeginning != hData.atBeginning) {
589 hData.atBeginning = atBeginning;
590 atXBeginningChange =
true;
591 if (!hData.moving && atBeginning)
592 hData.smoothVelocity.setValue(0);
594 if (atEnd != hData.atEnd) {
597 if (!hData.moving && atEnd)
598 hData.smoothVelocity.setValue(0);
601 if (vData.extentsChanged) {
602 vData.extentsChanged =
false;
603 qreal originY = q->originY();
604 if (vData.origin != originY) {
605 vData.origin = originY;
606 emit q->originYChanged();
610 if (hData.extentsChanged) {
611 hData.extentsChanged =
false;
612 qreal originX = q->originX();
613 if (hData.origin != originX) {
614 hData.origin = originX;
615 emit q->originXChanged();
619 if (atXEndChange || atYEndChange || atXBeginningChange || atYBeginningChange)
620 emit q->isAtBoundaryChanged();
622 emit q->atXEndChanged();
623 if (atXBeginningChange)
624 emit q->atXBeginningChanged();
626 emit q->atYEndChanged();
627 if (atYBeginningChange)
628 emit q->atYBeginningChanged();
631 visibleArea->updateVisible();
635
636
637
638
639
642
643
644
645
646
647
648
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
729
730
731
732
733
736
737
738
739
740
741
742
743
746
747
748
749
750
751
754
755
756
757
758
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780QQuickFlickable::QQuickFlickable(QQuickItem *parent)
781 : QQuickItem(*(
new QQuickFlickablePrivate), parent)
783 Q_D(QQuickFlickable);
787QQuickFlickable::QQuickFlickable(QQuickFlickablePrivate &dd, QQuickItem *parent)
788 : QQuickItem(dd, parent)
790 Q_D(QQuickFlickable);
794QQuickFlickable::~QQuickFlickable()
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818qreal QQuickFlickable::contentX()
const
820 Q_D(
const QQuickFlickable);
821 return -d->contentItem->x();
824void QQuickFlickable::setContentX(qreal pos)
826 Q_D(QQuickFlickable);
827 d->hData.explicitValue =
true;
828 d->resetTimeline(d->hData);
829 d->hData.vTime = d->timeline.time();
830 if (isMoving() || isFlicking())
831 movementEnding(
true,
false);
832 if (!qFuzzyCompare(-pos, d->hData.move.value())) {
833 d->hData.contentPositionChangedExternallyDuringDrag = d->hData.dragging;
834 d->hData.move.setValue(-pos);
835 d->hData.contentPositionChangedExternallyDuringDrag =
false;
839qreal QQuickFlickable::contentY()
const
841 Q_D(
const QQuickFlickable);
842 return -d->contentItem->y();
845void QQuickFlickable::setContentY(qreal pos)
847 Q_D(QQuickFlickable);
848 d->vData.explicitValue =
true;
849 d->resetTimeline(d->vData);
850 d->vData.vTime = d->timeline.time();
851 if (isMoving() || isFlicking())
852 movementEnding(
false,
true);
853 if (!qFuzzyCompare(-pos, d->vData.move.value())) {
854 d->vData.contentPositionChangedExternallyDuringDrag = d->vData.dragging;
855 d->vData.move.setValue(-pos);
856 d->vData.contentPositionChangedExternallyDuringDrag =
false;
861
862
863
864
865
866
867
868
869
870
871
872
873bool QQuickFlickable::isInteractive()
const
875 Q_D(
const QQuickFlickable);
876 return d->interactive;
879void QQuickFlickable::setInteractive(
bool interactive)
881 Q_D(QQuickFlickable);
882 if (interactive != d->interactive) {
883 d->interactive = interactive;
885 d->cancelInteraction();
887 emit interactiveChanged();
892
893
894
895
896
897
898
899
900
901
902
903
904qreal QQuickFlickable::horizontalVelocity()
const
906 Q_D(
const QQuickFlickable);
907 return d->hData.smoothVelocity.value();
910qreal QQuickFlickable::verticalVelocity()
const
912 Q_D(
const QQuickFlickable);
913 return d->vData.smoothVelocity.value();
917
918
919
920
921
922
923
924
925bool QQuickFlickable::isAtXEnd()
const
927 Q_D(
const QQuickFlickable);
928 return d->hData.atEnd;
931bool QQuickFlickable::isAtXBeginning()
const
933 Q_D(
const QQuickFlickable);
934 return d->hData.atBeginning;
937bool QQuickFlickable::isAtYEnd()
const
939 Q_D(
const QQuickFlickable);
940 return d->vData.atEnd;
943bool QQuickFlickable::isAtYBeginning()
const
945 Q_D(
const QQuickFlickable);
946 return d->vData.atBeginning;
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967QQuickItem *QQuickFlickable::contentItem()
const
969 Q_D(
const QQuickFlickable);
970 return d->contentItem;
973QQuickFlickableVisibleArea *QQuickFlickable::visibleArea()
975 Q_D(QQuickFlickable);
976 if (!d->visibleArea) {
977 d->visibleArea =
new QQuickFlickableVisibleArea(
this);
978 d->visibleArea->updateVisible();
980 return d->visibleArea;
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002QQuickFlickable::FlickableDirection QQuickFlickable::flickableDirection()
const
1004 Q_D(
const QQuickFlickable);
1005 return d->flickableDirection;
1008void QQuickFlickable::setFlickableDirection(FlickableDirection direction)
1010 Q_D(QQuickFlickable);
1011 if (direction != d->flickableDirection) {
1012 d->flickableDirection = direction;
1013 emit flickableDirectionChanged();
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029bool QQuickFlickable::pixelAligned()
const
1031 Q_D(
const QQuickFlickable);
1032 return d->pixelAligned;
1035void QQuickFlickable::setPixelAligned(
bool align)
1037 Q_D(QQuickFlickable);
1038 if (align != d->pixelAligned) {
1039 d->pixelAligned = align;
1040 emit pixelAlignedChanged();
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056bool QQuickFlickable::synchronousDrag()
const
1058 Q_D(
const QQuickFlickable);
1062void QQuickFlickable::setSynchronousDrag(
bool v)
1064 Q_D(QQuickFlickable);
1065 if (v != d->syncDrag) {
1067 emit synchronousDragChanged();
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086Qt::MouseButtons QQuickFlickable::acceptedButtons()
const
1088 Q_D(
const QQuickFlickable);
1089 return d->acceptedButtons;
1092void QQuickFlickable::setAcceptedButtons(Qt::MouseButtons buttons)
1094 Q_D(QQuickFlickable);
1095 if (d->acceptedButtons == buttons)
1098 d->acceptedButtons = buttons;
1099 setAcceptedMouseButtons(buttons);
1100 emit acceptedButtonsChanged();
1104
1105
1106
1107QVector2D QQuickFlickablePrivate::firstPointLocalVelocity(QPointerEvent *event)
1109 QTransform transform = windowToItemTransform();
1111 return QVector2D(transform.map(event->point(0).velocity().toPointF()) - transform.map(QPointF()));
1114qint64 QQuickFlickablePrivate::computeCurrentTime(QInputEvent *event)
const
1116 if (0 != event->timestamp())
1117 return event->timestamp();
1118 if (!timer.isValid())
1120 return timer.elapsed();
1123void QQuickFlickablePrivate::handlePressEvent(QPointerEvent *event)
1125 Q_Q(QQuickFlickable);
1127 if (interactive && timeline.isActive()
1128 && ((qAbs(hData.smoothVelocity.value()) > RetainGrabVelocity && !hData.fixingUp && !hData.inOvershoot)
1129 || (qAbs(vData.smoothVelocity.value()) > RetainGrabVelocity && !vData.fixingUp && !vData.inOvershoot))) {
1131 int flickTime = timeline.time();
1132 if (flickTime > 600) {
1134 hData.continuousFlickVelocity = 0;
1135 vData.continuousFlickVelocity = 0;
1138 hData.continuousFlickVelocity = -hData.smoothVelocity.value();
1139 vData.continuousFlickVelocity = -vData.smoothVelocity.value();
1140 if (flickTime > 300)
1141 flickBoost = qMax(1.0, flickBoost - 0.5);
1145 hData.continuousFlickVelocity = 0;
1146 vData.continuousFlickVelocity = 0;
1149 q->setKeepMouseGrab(stealMouse);
1151 maybeBeginDrag(computeCurrentTime(event), event->points().first().position(),
1152 event->isSinglePointEvent() ?
static_cast<QSinglePointEvent *>(event)->buttons()
1156void QQuickFlickablePrivate::maybeBeginDrag(qint64 currentTimestamp,
const QPointF &pressPosn, Qt::MouseButtons buttons)
1158 Q_Q(QQuickFlickable);
1159 clearDelayedPress();
1161 pressed = (buttons == Qt::NoButton) || (acceptedButtons != Qt::NoButton && (buttons & acceptedButtons) != 0);
1163 if (hData.transitionToBounds)
1164 hData.transitionToBounds->stopTransition();
1165 if (vData.transitionToBounds)
1166 vData.transitionToBounds->stopTransition();
1167 if (!hData.fixingUp)
1168 resetTimeline(hData);
1169 if (!vData.fixingUp)
1170 resetTimeline(vData);
1174 hData.dragMinBound = q->minXExtent() - hData.startMargin;
1175 vData.dragMinBound = q->minYExtent() - vData.startMargin;
1176 hData.dragMaxBound = q->maxXExtent() + hData.endMargin;
1177 vData.dragMaxBound = q->maxYExtent() + vData.endMargin;
1179 lastPos = QPointF();
1180 pressPos = pressPosn;
1181 hData.pressPos = hData.move.value();
1182 vData.pressPos = vData.move.value();
1183 const bool wasFlicking = hData.flicking || vData.flicking;
1184 hData.flickingWhenDragBegan = hData.flicking;
1185 vData.flickingWhenDragBegan = vData.flicking;
1186 if (hData.flicking) {
1187 hData.flicking =
false;
1188 emit q->flickingHorizontallyChanged();
1190 if (vData.flicking) {
1191 vData.flicking =
false;
1192 emit q->flickingVerticallyChanged();
1195 emit q->flickingChanged();
1196 lastPosTime = lastPressTime = currentTimestamp;
1197 vData.velocityTime.start();
1198 hData.velocityTime.start();
1201void QQuickFlickablePrivate::drag(qint64 currentTimestamp, QEvent::Type eventType,
const QPointF &localPos,
1202 const QVector2D &deltas,
bool overThreshold,
bool momentum,
1203 bool velocitySensitiveOverBounds,
const QVector2D &velocity)
1205 Q_Q(QQuickFlickable);
1206 bool rejectY =
false;
1207 bool rejectX =
false;
1209 bool keepY = q->yflick();
1210 bool keepX = q->xflick();
1212 bool stealY =
false;
1213 bool stealX =
false;
1214 if (eventType == QEvent::MouseMove) {
1215 stealX = stealY = stealMouse;
1216 }
else if (eventType == QEvent::Wheel) {
1217 stealX = stealY = scrollingPhase;
1220 bool prevHMoved = hMoved;
1221 bool prevVMoved = vMoved;
1223 qint64 elapsedSincePress = currentTimestamp - lastPressTime;
1224 qCDebug(lcFlickable).nospace() << currentTimestamp <<
' ' << eventType <<
" drag @ " << localPos.x() <<
',' << localPos.y()
1225 <<
" \u0394 " << deltas.x() <<
',' << deltas.y() <<
" vel " << velocity.x() <<
',' << velocity.y()
1226 <<
" thrsld? " << overThreshold <<
" momentum? " << momentum <<
" velSens? " << velocitySensitiveOverBounds
1227 <<
" sincePress " << elapsedSincePress;
1230 qreal dy = deltas.y();
1231 if (overThreshold || elapsedSincePress > 200) {
1232 if (!vMoved && !vData.dragging)
1233 vData.dragStartOffset = dy;
1234 qreal newY = dy + vData.pressPos - (syncDrag ? 0 : vData.dragStartOffset);
1238 const qreal minY = vData.dragMinBound + vData.startMargin;
1239 const qreal maxY = vData.dragMaxBound - vData.endMargin;
1240 if (!(boundsBehavior & QQuickFlickable::DragOverBounds)) {
1241 if (fuzzyLessThanOrEqualTo(newY, maxY)) {
1243 rejectY = vData.pressPos == maxY && vData.move.value() == maxY && dy < 0;
1245 if (fuzzyLessThanOrEqualTo(minY, newY)) {
1247 rejectY |= vData.pressPos == minY && vData.move.value() == minY && dy > 0;
1251 if (vel > 0. && vel > vData.velocity)
1253 else if (vel < 0. && vel < vData.velocity)
1257 if (momentum && vData.atBeginning) {
1258 if (!vData.inRebound) {
1259 vData.inRebound =
true;
1260 q->returnToBounds();
1264 if (velocitySensitiveOverBounds) {
1267 newY = minY + overshoot;
1269 newY = minY + (newY - minY) / 2;
1271 }
else if (newY < maxY && maxY - minY <= 0) {
1273 if (momentum && vData.atEnd) {
1274 if (!vData.inRebound) {
1275 vData.inRebound =
true;
1276 q->returnToBounds();
1280 if (velocitySensitiveOverBounds) {
1283 newY = maxY - overshoot;
1285 newY = maxY + (newY - maxY) / 2;
1289 if (!rejectY && stealMouse && dy != vData.previousDragDelta) {
1291 vData.move.setValue(newY);
1294 if (!rejectY && overThreshold)
1297 if ((newY >= minY && vData.pressPos == minY && vData.move.value() == minY && dy > 0)
1298 || (newY <= maxY && vData.pressPos == maxY && vData.move.value() == maxY && dy < 0)) {
1302 vData.previousDragDelta = dy;
1306 qreal dx = deltas.x();
1307 if (overThreshold || elapsedSincePress > 200) {
1308 if (!hMoved && !hData.dragging)
1309 hData.dragStartOffset = dx;
1310 qreal newX = dx + hData.pressPos - (syncDrag ? 0 : hData.dragStartOffset);
1311 const qreal minX = hData.dragMinBound + hData.startMargin;
1312 const qreal maxX = hData.dragMaxBound - hData.endMargin;
1313 if (!(boundsBehavior & QQuickFlickable::DragOverBounds)) {
1314 if (fuzzyLessThanOrEqualTo(newX, maxX)) {
1316 rejectX = hData.pressPos == maxX && hData.move.value() == maxX && dx < 0;
1318 if (fuzzyLessThanOrEqualTo(minX, newX)) {
1320 rejectX |= hData.pressPos == minX && hData.move.value() == minX && dx > 0;
1324 if (vel > 0. && vel > hData.velocity)
1326 else if (vel < 0. && vel < hData.velocity)
1330 if (momentum && hData.atBeginning) {
1331 if (!hData.inRebound) {
1332 hData.inRebound =
true;
1333 q->returnToBounds();
1337 if (velocitySensitiveOverBounds) {
1340 newX = minX + overshoot;
1342 newX = minX + (newX - minX) / 2;
1344 }
else if (newX < maxX && maxX - minX <= 0) {
1346 if (momentum && hData.atEnd) {
1347 if (!hData.inRebound) {
1348 hData.inRebound =
true;
1349 q->returnToBounds();
1353 if (velocitySensitiveOverBounds) {
1356 newX = maxX - overshoot;
1358 newX = maxX + (newX - maxX) / 2;
1362 if (!rejectX && stealMouse && dx != hData.previousDragDelta) {
1364 hData.move.setValue(newX);
1368 if (!rejectX && overThreshold)
1371 if ((newX >= minX && vData.pressPos == minX && vData.move.value() == minX && dx > 0)
1372 || (newX <= maxX && vData.pressPos == maxX && vData.move.value() == maxX && dx < 0)) {
1376 hData.previousDragDelta = dx;
1379 stealMouse = stealX || stealY;
1381 if ((stealX && keepX) || (stealY && keepY))
1382 q->setKeepMouseGrab(
true);
1383 clearDelayedPress();
1387 vData.velocityBuffer.clear();
1391 hData.velocityBuffer.clear();
1395 if (momentum && !hData.flicking && !vData.flicking)
1396 flickingStarted(hData.velocity != 0, vData.velocity != 0);
1399 if ((hMoved && !prevHMoved) || (vMoved && !prevVMoved))
1400 q->movementStarting();
1402 lastPosTime = currentTimestamp;
1403 if (q->yflick() && !rejectY)
1404 vData.addVelocitySample(velocity.y(), maxVelocity);
1405 if (q->xflick() && !rejectX)
1406 hData.addVelocitySample(velocity.x(), maxVelocity);
1410void QQuickFlickablePrivate::handleMoveEvent(QPointerEvent *event)
1412 Q_Q(QQuickFlickable);
1413 if (!interactive || lastPosTime == -1 ||
1414 (event->isSinglePointEvent() && !buttonsAccepted(
static_cast<QSinglePointEvent *>(event))))
1417 qint64 currentTimestamp = computeCurrentTime(event);
1418 const auto &firstPoint = event->points().first();
1419 const auto &pos = firstPoint.position();
1420 const QVector2D deltas = QVector2D(pos - q->mapFromGlobal(firstPoint.globalPressPosition()));
1421 const QVector2D velocity = firstPointLocalVelocity(event);
1422 bool overThreshold =
false;
1424 if (q->isMoving()) {
1426
1427
1428
1429
1430
1431
1432
1433 overThreshold =
true;
1434 }
else if (event->pointCount() == 1) {
1436 overThreshold |= QQuickDeliveryAgentPrivate::dragOverThreshold(deltas.y(), Qt::YAxis, firstPoint);
1438 overThreshold |= QQuickDeliveryAgentPrivate::dragOverThreshold(deltas.x(), Qt::XAxis, firstPoint);
1440 qCDebug(lcFilter) << q->objectName() <<
"ignoring multi-touch" << event;
1443 drag(currentTimestamp, event->type(), pos, deltas, overThreshold,
false,
false, velocity);
1446void QQuickFlickablePrivate::handleReleaseEvent(QPointerEvent *event)
1448 Q_Q(QQuickFlickable);
1450 q->setKeepMouseGrab(
false);
1454 qint64 elapsed = computeCurrentTime(event) - lastPosTime;
1456 vData.updateVelocity();
1457 hData.updateVelocity();
1461 if (lastPosTime == -1)
1464 hData.vTime = vData.vTime = timeline.time();
1466 bool canBoost =
false;
1467 const auto pos = event->points().first().position();
1468 const auto pressPos = q->mapFromGlobal(event->points().first().globalPressPosition());
1469 const QVector2D eventVelocity = firstPointLocalVelocity(event);
1470 qCDebug(lcVel) << event->deviceType() << event->type() <<
"velocity" << event->points().first().velocity() <<
"transformed to local" << eventVelocity;
1472 qreal vVelocity = 0;
1473 if (elapsed < 100 && vData.velocity != 0.) {
1474 vVelocity = (event->device()->capabilities().testFlag(QInputDevice::Capability::Velocity)
1475 ? eventVelocity.y() : vData.velocity);
1477 if ((vData.atBeginning && vVelocity > 0.) || (vData.atEnd && vVelocity < 0.)) {
1479 }
else if (vData.continuousFlickVelocity != 0.0
1481 && ((vVelocity > 0) == (vData.continuousFlickVelocity > 0))
1487 qreal hVelocity = 0;
1488 if (elapsed < 100 && hData.velocity != 0.) {
1489 hVelocity = (event->device()->capabilities().testFlag(QInputDevice::Capability::Velocity)
1490 ? eventVelocity.x() : hData.velocity);
1492 if ((hData.atBeginning && hVelocity > 0.) || (hData.atEnd && hVelocity < 0.)) {
1494 }
else if (hData.continuousFlickVelocity != 0.0
1496 && ((hVelocity > 0) == (hData.continuousFlickVelocity > 0))
1503 const int flickThreshold = QGuiApplicationPrivate::platformTheme()->themeHint(QPlatformTheme::FlickStartDistance).toInt();
1505 bool anyPointGrabbed = event->points().constEnd() !=
1506 std::find_if(event->points().constBegin(),event->points().constEnd(),
1507 [q, event](
const QEventPoint &point) {
return event->exclusiveGrabber(point) == q; });
1509 bool flickedVertically =
false;
1510 vVelocity *= flickBoost;
1511 const bool isVerticalFlickAllowed = anyPointGrabbed &&
1512 q->yflick() && qAbs(vVelocity) > _q_MinimumFlickVelocity &&
1513 qAbs(pos.y() - pressPos.y()) > flickThreshold;
1514 if (isVerticalFlickAllowed) {
1515 velocityTimeline.reset(vData.smoothVelocity);
1516 vData.smoothVelocity.setValue(-vVelocity);
1517 flickedVertically = flickY(event->type(), vVelocity);
1520 bool flickedHorizontally =
false;
1521 hVelocity *= flickBoost;
1522 const bool isHorizontalFlickAllowed = anyPointGrabbed &&
1523 q->xflick() && qAbs(hVelocity) > _q_MinimumFlickVelocity &&
1524 qAbs(pos.x() - pressPos.x()) > flickThreshold;
1525 if (isHorizontalFlickAllowed) {
1526 velocityTimeline.reset(hData.smoothVelocity);
1527 hData.smoothVelocity.setValue(-hVelocity);
1528 flickedHorizontally = flickX(event->type(), hVelocity);
1531 if (!isVerticalFlickAllowed)
1534 if (!isHorizontalFlickAllowed)
1537 flickingStarted(flickedHorizontally, flickedVertically);
1538 if (!isViewMoving()) {
1539 q->movementEnding();
1541 if (flickedVertically)
1543 if (flickedHorizontally)
1545 q->movementStarting();
1549bool QQuickFlickablePrivate::buttonsAccepted(
const QSinglePointEvent *event)
1551 return !((event->button() & acceptedButtons) == 0 && (event->buttons() & acceptedButtons) == 0);
1554void QQuickFlickable::mousePressEvent(QMouseEvent *event)
1556 Q_D(QQuickFlickable);
1557 if (d->interactive && !d->replayingPressEvent && d->buttonsAccepted(event) && d->wantsPointerEvent(event)) {
1559 d->handlePressEvent(event);
1562 QQuickItem::mousePressEvent(event);
1566void QQuickFlickable::mouseMoveEvent(QMouseEvent *event)
1568 Q_D(QQuickFlickable);
1569 if (d->interactive && d->buttonsAccepted(event) && d->wantsPointerEvent(event)) {
1570 d->handleMoveEvent(event);
1573 QQuickItem::mouseMoveEvent(event);
1577void QQuickFlickable::mouseReleaseEvent(QMouseEvent *event)
1579 Q_D(QQuickFlickable);
1580 if (d->interactive && d->buttonsAccepted(event) && d->wantsPointerEvent(event)) {
1581 if (d->delayedPressEvent) {
1582 d->replayDelayedPress();
1584 auto &firstPoint = event->point(0);
1585 if (
const auto *grabber = event->exclusiveGrabber(firstPoint); grabber && grabber->isQuickItemType()) {
1588 const auto oldPosition = firstPoint.position();
1589 QMutableEventPoint::setPosition(firstPoint, event->scenePosition());
1590 QCoreApplication::sendEvent(window(), event);
1591 QMutableEventPoint::setPosition(firstPoint, oldPosition);
1595 d->stealMouse =
false;
1600 d->handleReleaseEvent(event);
1603 QQuickItem::mouseReleaseEvent(event);
1607void QQuickFlickable::touchEvent(QTouchEvent *event)
1609 Q_D(QQuickFlickable);
1611 if (event->type() == QEvent::TouchCancel) {
1612 if (d->interactive && d->wantsPointerEvent(event))
1613 d->cancelInteraction();
1615 QQuickItem::touchEvent(event);
1619 bool unhandled =
false;
1620 const auto &firstPoint = event->points().first();
1621 switch (firstPoint.state()) {
1622 case QEventPoint::State::Pressed:
1623 if (d->interactive && !d->replayingPressEvent && d->wantsPointerEvent(event)) {
1625 d->handlePressEvent(event);
1631 case QEventPoint::State::Updated:
1632 if (d->interactive && d->wantsPointerEvent(event)) {
1633 d->handleMoveEvent(event);
1639 case QEventPoint::State::Released:
1640 if (d->interactive && d->wantsPointerEvent(event)) {
1641 if (d->delayedPressEvent) {
1642 d->replayDelayedPress();
1644 const auto &firstPoint = event->point(0);
1645 if (
const auto *grabber = event->exclusiveGrabber(firstPoint); grabber && grabber->isQuickItemType()) {
1647 QScopedPointer<QPointerEvent> localizedEvent(
1648 QQuickDeliveryAgentPrivate::clonePointerEvent(event, firstPoint.scenePosition()));
1649 QCoreApplication::sendEvent(window(), localizedEvent.data());
1653 d->stealMouse =
false;
1658 d->handleReleaseEvent(event);
1664 case QEventPoint::State::Stationary:
1665 case QEventPoint::State::Unknown:
1669 QQuickItem::touchEvent(event);
1672#if QT_CONFIG(wheelevent)
1673void QQuickFlickable::wheelEvent(QWheelEvent *event)
1675 Q_D(QQuickFlickable);
1676 if (!d->interactive || !d->wantsPointerEvent(event)) {
1677 QQuickItem::wheelEvent(event);
1680 qCDebug(lcWheel) << event->device() << event << event->source();
1681 event->setAccepted(
false);
1682 qint64 currentTimestamp = d->computeCurrentTime(event);
1683 switch (event->phase()) {
1684 case Qt::ScrollBegin:
1685 d->scrollingPhase =
true;
1686 d->accumulatedWheelPixelDelta = QVector2D();
1687 d->vData.velocity = 0;
1688 d->hData.velocity = 0;
1690 d->maybeBeginDrag(currentTimestamp, event->position());
1691 d->lastPosTime = -1;
1693 case Qt::NoScrollPhase:
1694 case Qt::ScrollUpdate:
1695 if (d->scrollingPhase)
1698 case Qt::ScrollMomentum:
1700 d->scrollingPhase =
false;
1701 d->draggingEnding();
1704 d->lastPosTime = -1;
1708 d->scrollingPhase =
false;
1709 d->draggingEnding();
1711 d->lastPosTime = -1;
1712 d->stealMouse =
false;
1713 if (!d->velocityTimeline.isActive() && !d->timeline.isActive())
1714 movementEnding(
true,
true);
1718 qreal elapsed = qreal(currentTimestamp - d->lastPosTime) / qreal(1000);
1720 d->lastPosTime = currentTimestamp;
1721 qCDebug(lcWheel) <<
"insufficient elapsed time: can't calculate velocity" << elapsed;
1725 if (event->source() == Qt::MouseEventNotSynthesized || event->pixelDelta().isNull() || event->phase() == Qt::NoScrollPhase) {
1727 int xDelta = event->angleDelta().x();
1728 int yDelta = event->angleDelta().y();
1730 if (d->wheelDeceleration > _q_MaximumWheelDeceleration) {
1731 const qreal wheelScroll = -qApp->styleHints()->wheelScrollLines() * 24;
1734 if (yflick() && yDelta != 0) {
1735 d->moveReason = QQuickFlickablePrivate::Mouse;
1737 qreal scrollPixel = (-yDelta / 120.0 * wheelScroll);
1738 bool acceptEvent =
true;
1739 if (scrollPixel > 0) {
1740 if (d->vData.move.value() >= minYExtent()) {
1742 acceptEvent =
false;
1745 if (d->vData.move.value() <= maxYExtent()) {
1747 acceptEvent =
false;
1751 if (d->boundsBehavior == QQuickFlickable::StopAtBounds) {
1752 const qreal estContentPos = scrollPixel + d->vData.move.value();
1753 if (scrollPixel > 0) {
1754 if (estContentPos > minYExtent()) {
1755 scrollPixel = minYExtent() - d->vData.move.value();
1756 acceptEvent =
false;
1759 if (estContentPos < maxYExtent()) {
1760 scrollPixel = maxYExtent() - d->vData.move.value();
1761 acceptEvent =
false;
1765 d->resetTimeline(d->vData);
1767 d->timeline.moveBy(d->vData.move, scrollPixel, QEasingCurve(QEasingCurve::OutExpo), 3*d->fixupDuration/4);
1768 d->vData.fixingUp =
true;
1769 d->timeline.callback(QQuickTimeLineCallback(&d->vData.move, QQuickFlickablePrivate::fixupY_callback, d));
1774 if (xflick() && xDelta != 0) {
1775 d->moveReason = QQuickFlickablePrivate::Mouse;
1777 qreal scrollPixel = (-xDelta / 120.0 * wheelScroll);
1778 bool acceptEvent =
true;
1779 if (scrollPixel > 0) {
1780 if (d->hData.move.value() >= minXExtent()) {
1782 acceptEvent =
false;
1785 if (d->hData.move.value() <= maxXExtent()) {
1787 acceptEvent =
false;
1791 if (d->boundsBehavior == QQuickFlickable::StopAtBounds) {
1792 const qreal estContentPos = scrollPixel + d->hData.move.value();
1793 if (scrollPixel > 0) {
1794 if (estContentPos > minXExtent()) {
1795 scrollPixel = minXExtent() - d->hData.move.value();
1796 acceptEvent =
false;
1799 if (estContentPos < maxXExtent()) {
1800 scrollPixel = maxXExtent() - d->hData.move.value();
1801 acceptEvent =
false;
1805 d->resetTimeline(d->hData);
1807 d->timeline.moveBy(d->hData.move, scrollPixel, QEasingCurve(QEasingCurve::OutExpo), 3*d->fixupDuration/4);
1808 d->hData.fixingUp =
true;
1809 d->timeline.callback(QQuickTimeLineCallback(&d->hData.move, QQuickFlickablePrivate::fixupX_callback, d));
1825 elapsed = 120 / qSqrt(d->wheelDeceleration * 2 * d->initialWheelFlickDistance);
1826 if (yflick() && yDelta != 0) {
1827 qreal instVelocity = yDelta / elapsed;
1829 if ((instVelocity < 0 && d->vData.velocity > 0) || (instVelocity > 0 && d->vData.velocity < 0))
1830 d->vData.velocityBuffer.clear();
1831 d->vData.addVelocitySample(instVelocity, d->maxVelocity);
1832 d->vData.updateVelocity();
1833 if ((yDelta > 0 && contentY() > -minYExtent()) || (yDelta < 0 && contentY() < -maxYExtent())) {
1834 const bool newFlick = d->flickY(event->type(), d->vData.velocity);
1835 if (newFlick && (d->vData.atBeginning != (yDelta > 0) || d->vData.atEnd != (yDelta < 0))) {
1836 d->flickingStarted(
false,
true);
1843 if (xflick() && xDelta != 0) {
1844 qreal instVelocity = xDelta / elapsed;
1846 if ((instVelocity < 0 && d->hData.velocity > 0) || (instVelocity > 0 && d->hData.velocity < 0))
1847 d->hData.velocityBuffer.clear();
1848 d->hData.addVelocitySample(instVelocity, d->maxVelocity);
1849 d->hData.updateVelocity();
1850 if ((xDelta > 0 && contentX() > -minXExtent()) || (xDelta < 0 && contentX() < -maxXExtent())) {
1851 const bool newFlick = d->flickX(event->type(), d->hData.velocity);
1852 if (newFlick && (d->hData.atBeginning != (xDelta > 0) || d->hData.atEnd != (xDelta < 0))) {
1853 d->flickingStarted(
true,
false);
1863 int xDelta = event->pixelDelta().x();
1864 int yDelta = event->pixelDelta().y();
1866 QVector2D velocity(xDelta / elapsed, yDelta / elapsed);
1867 d->accumulatedWheelPixelDelta += QVector2D(event->pixelDelta());
1873 if (isMoving() || isFlicking() || (yflick() && xflick())
1874 || (xflick() && qAbs(d->accumulatedWheelPixelDelta.x()) > qAbs(d->accumulatedWheelPixelDelta.y() * 2))
1875 || (yflick() && qAbs(d->accumulatedWheelPixelDelta.y()) > qAbs(d->accumulatedWheelPixelDelta.x() * 2))) {
1876 d->drag(currentTimestamp, event->type(), event->position(), d->accumulatedWheelPixelDelta,
1877 true, !d->scrollingPhase,
true, velocity);
1878 d->updateBeginningEnd();
1879 if ((xflick() && !isAtXBeginning() && !isAtXEnd()) || (yflick() && !isAtYBeginning() && !isAtYEnd()))
1882 qCDebug(lcWheel) <<
"not dragging: accumulated deltas" << d->accumulatedWheelPixelDelta <<
1883 "moving?" << isMoving() <<
"can flick horizontally?" << xflick() <<
"vertically?" << yflick();
1886 d->lastPosTime = currentTimestamp;
1888 if (!event->isAccepted())
1889 QQuickItem::wheelEvent(event);
1893bool QQuickFlickablePrivate::isInnermostPressDelay(QQuickItem *i)
const
1895 Q_Q(
const QQuickFlickable);
1896 QQuickItem *item = i;
1898 QQuickFlickable *flick = qobject_cast<QQuickFlickable*>(item);
1899 if (flick && flick->pressDelay() > 0 && flick->isInteractive()) {
1901 return (flick == q);
1903 item = item->parentItem();
1908void QQuickFlickablePrivate::captureDelayedPress(QQuickItem *item, QPointerEvent *event)
1910 Q_Q(QQuickFlickable);
1911 if (!q->window() || pressDelay <= 0)
1916 if (!isInnermostPressDelay(item))
1919 delayedPressEvent = QQuickDeliveryAgentPrivate::clonePointerEvent(event);
1920 delayedPressEvent->setAccepted(
false);
1921 delayedPressTimer.start(pressDelay, q);
1922 qCDebug(lcReplay) <<
"begin press delay" << pressDelay <<
"ms with" << delayedPressEvent;
1925void QQuickFlickablePrivate::clearDelayedPress()
1927 if (delayedPressEvent) {
1928 delayedPressTimer.stop();
1929 qCDebug(lcReplay) <<
"clear delayed press" << delayedPressEvent;
1930 delete delayedPressEvent;
1931 delayedPressEvent =
nullptr;
1935void QQuickFlickablePrivate::replayDelayedPress()
1937 Q_Q(QQuickFlickable);
1938 if (delayedPressEvent) {
1940 QScopedPointer<QPointerEvent> event(delayedPressEvent);
1941 delayedPressEvent =
nullptr;
1942 delayedPressTimer.stop();
1945 if (QQuickWindow *window = q->window()) {
1946 auto da = deliveryAgentPrivate();
1947 da->allowChildEventFiltering =
false;
1948 replayingPressEvent =
true;
1949 auto &firstPoint = event->point(0);
1955 if (event->exclusiveGrabber(firstPoint) == q)
1956 event->setExclusiveGrabber(firstPoint,
nullptr);
1958 qCDebug(lcReplay) <<
"replaying" << event.data();
1961 QMutableEventPoint::setPosition(firstPoint, firstPoint.scenePosition());
1965 QCoreApplication::sendEvent(window, event.data());
1966 qCDebug(lcReplay) <<
"replay done";
1969 replayingPressEvent =
false;
1970 da->allowChildEventFiltering =
true;
1978
1979
1980
1981
1982
1983
1984
1985void QQuickFlickablePrivate::setViewportX(qreal x)
1987 Q_Q(QQuickFlickable);
1988 qreal effectiveX = pixelAligned ? -std::round(-x) : x;
1990 const qreal maxX = q->maxXExtent();
1991 const qreal minX = q->minXExtent();
1993 if (boundsMovement ==
int(QQuickFlickable::StopAtBounds))
1994 effectiveX = qBound(maxX, effectiveX, minX);
1996 contentItem->setX(effectiveX);
1997 if (contentItem->x() != effectiveX)
2000 qreal overshoot = 0.0;
2002 overshoot = maxX - x;
2004 overshoot = minX - x;
2006 if (overshoot != hData.overshoot) {
2007 hData.overshoot = overshoot;
2008 emit q->horizontalOvershootChanged();
2013
2014
2015
2016
2017
2018
2019
2020void QQuickFlickablePrivate::setViewportY(qreal y)
2022 Q_Q(QQuickFlickable);
2023 qreal effectiveY = pixelAligned ? -std::round(-y) : y;
2025 const qreal maxY = q->maxYExtent();
2026 const qreal minY = q->minYExtent();
2028 if (boundsMovement ==
int(QQuickFlickable::StopAtBounds))
2029 effectiveY = qBound(maxY, effectiveY, minY);
2031 contentItem->setY(effectiveY);
2032 if (contentItem->y() != effectiveY)
2035 qreal overshoot = 0.0;
2037 overshoot = maxY - y;
2039 overshoot = minY - y;
2041 if (overshoot != vData.overshoot) {
2042 vData.overshoot = overshoot;
2043 emit q->verticalOvershootChanged();
2047void QQuickFlickable::timerEvent(QTimerEvent *event)
2049 Q_D(QQuickFlickable);
2050 if (event->timerId() == d->delayedPressTimer.timerId()) {
2051 d->delayedPressTimer.stop();
2052 if (d->delayedPressEvent) {
2053 d->replayDelayedPress();
2058qreal QQuickFlickable::minYExtent()
const
2060 Q_D(
const QQuickFlickable);
2061 return d->vData.startMargin;
2064qreal QQuickFlickable::minXExtent()
const
2066 Q_D(
const QQuickFlickable);
2067 return d->hData.startMargin;
2071qreal QQuickFlickable::maxXExtent()
const
2073 Q_D(
const QQuickFlickable);
2074 return qMin<qreal>(minXExtent(), width() - vWidth() - d->hData.endMargin);
2077qreal QQuickFlickable::maxYExtent()
const
2079 Q_D(
const QQuickFlickable);
2080 return qMin<qreal>(minYExtent(), height() - vHeight() - d->vData.endMargin);
2083void QQuickFlickable::componentComplete()
2085 Q_D(QQuickFlickable);
2086 QQuickItem::componentComplete();
2087 if (!d->hData.explicitValue && d->hData.startMargin != 0.)
2088 setContentX(-minXExtent());
2089 if (!d->vData.explicitValue && d->vData.startMargin != 0.)
2090 setContentY(-minYExtent());
2091 if (lcWheel().isDebugEnabled() || lcVel().isDebugEnabled()) {
2092 d->timeline.setObjectName(QLatin1String(
"timeline for Flickable ") + objectName());
2093 d->velocityTimeline.setObjectName(QLatin1String(
"velocity timeline for Flickable ") + objectName());
2097void QQuickFlickable::viewportMoved(Qt::Orientations orient)
2099 Q_D(QQuickFlickable);
2100 if (orient & Qt::Vertical)
2101 d->viewportAxisMoved(d->vData, minYExtent(), maxYExtent(), d->fixupY_callback);
2102 if (orient & Qt::Horizontal)
2103 d->viewportAxisMoved(d->hData, minXExtent(), maxXExtent(), d->fixupX_callback);
2104 d->updateBeginningEnd();
2107void QQuickFlickablePrivate::viewportAxisMoved(AxisData &data, qreal minExtent, qreal maxExtent,
2108 QQuickTimeLineCallback::Callback fixupCallback)
2110 if (!scrollingPhase && (pressed || calcVelocity)) {
2111 int elapsed = data.velocityTime.restart();
2113 qreal velocity = (data.lastPos - data.move.value()) * 1000 / elapsed;
2114 if (qAbs(velocity) > 0) {
2115 velocityTimeline.reset(data.smoothVelocity);
2116 velocityTimeline.set(data.smoothVelocity, velocity);
2117 qCDebug(lcVel) <<
"touchpad scroll phase: velocity" << velocity;
2121 if (timeline.time() > data.vTime) {
2122 velocityTimeline.reset(data.smoothVelocity);
2123 int dt = timeline.time() - data.vTime;
2125 qreal velocity = (data.lastPos - data.move.value()) * 1000 / dt;
2126 if (!qFuzzyCompare(data.smoothVelocity.value(), velocity))
2127 qCDebug(lcVel) <<
"velocity" << data.smoothVelocity.value() <<
"->" << velocity
2128 <<
"computed as (" << data.lastPos <<
"-" << data.move.value() <<
") * 1000 / ("
2129 << timeline.time() <<
"-" << data.vTime <<
")";
2130 data.smoothVelocity.setValue(velocity);
2135 if (!data.inOvershoot && !data.fixingUp && data.flicking
2136 && (data.move.value() > minExtent || data.move.value() < maxExtent)
2137 && qAbs(data.smoothVelocity.value()) > 10) {
2139 qreal overBound = data.move.value() > minExtent
2140 ? data.move.value() - minExtent
2141 : maxExtent - data.move.value();
2142 data.inOvershoot =
true;
2143 qreal maxDistance = overShootDistance(qAbs(data.smoothVelocity.value())) - overBound;
2144 resetTimeline(data);
2145 if (maxDistance > 0)
2147 timeline.callback(QQuickTimeLineCallback(&data.move, fixupCallback,
this));
2150 data.lastPos = data.move.value();
2151 data.vTime = timeline.time();
2154void QQuickFlickable::geometryChange(
const QRectF &newGeometry,
const QRectF &oldGeometry)
2156 Q_D(QQuickFlickable);
2157 QQuickItem::geometryChange(newGeometry, oldGeometry);
2159 bool changed =
false;
2160 if (newGeometry.width() != oldGeometry.width()) {
2162 if (d->hData.viewSize < 0)
2163 d->contentItem->setWidth(width() - d->hData.startMargin - d->hData.endMargin);
2165 if (!d->pressed && !d->hData.moving && !d->vData.moving) {
2166 d->fixupMode = QQuickFlickablePrivate::Immediate;
2170 if (newGeometry.height() != oldGeometry.height()) {
2172 if (d->vData.viewSize < 0)
2173 d->contentItem->setHeight(height() - d->vData.startMargin - d->vData.endMargin);
2175 if (!d->pressed && !d->hData.moving && !d->vData.moving) {
2176 d->fixupMode = QQuickFlickablePrivate::Immediate;
2182 d->updateBeginningEnd();
2186
2187
2188
2189
2190
2191
2192
2194void QQuickFlickable::flick(qreal xVelocity, qreal yVelocity)
2196 Q_D(QQuickFlickable);
2199 d->hData.velocity = xVelocity;
2200 d->vData.velocity = yVelocity;
2201 d->hData.vTime = d->vData.vTime = d->timeline.time();
2203 const bool flickedX = xflick() && !qFuzzyIsNull(xVelocity) && d->flickX(QEvent::TouchUpdate, xVelocity);
2204 const bool flickedY = yflick() && !qFuzzyIsNull(yVelocity) && d->flickY(QEvent::TouchUpdate, yVelocity);
2211 d->flickingStarted(flickedX, flickedY);
2214void QQuickFlickablePrivate::flickingStarted(
bool flickingH,
bool flickingV)
2216 Q_Q(QQuickFlickable);
2217 if (!flickingH && !flickingV)
2220 bool wasFlicking = hData.flicking || vData.flicking;
2221 if (flickingH && !hData.flicking) {
2222 hData.flicking =
true;
2223 emit q->flickingHorizontallyChanged();
2225 if (flickingV && !vData.flicking) {
2226 vData.flicking =
true;
2227 emit q->flickingVerticallyChanged();
2229 if (!wasFlicking && (hData.flicking || vData.flicking)) {
2230 emit q->flickingChanged();
2231 emit q->flickStarted();
2236
2237
2238
2239
2241void QQuickFlickable::cancelFlick()
2243 Q_D(QQuickFlickable);
2244 d->resetTimeline(d->hData);
2245 d->resetTimeline(d->vData);
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2282void QQuickFlickable::positionViewAtChild(QQuickItem *child, PositionMode mode,
const QPointF &offset)
2284 Q_D(QQuickFlickable);
2287 if (!d->contentItem->isAncestorOf(child))
2290 const QRectF itemRect =
2291 child->mapRectToItem(d->contentItem, QRectF(0, 0, child->width(), child->height()));
2293 QPointF currentPosition = QPointF(contentX(), contentY());
2294 QPointF newPosition = computePosition(currentPosition, itemRect, mode, offset);
2296 if (newPosition.x() != currentPosition.x()) {
2297 setContentX(newPosition.x());
2300 if (newPosition.y() != currentPosition.y()) {
2301 setContentY(newPosition.y());
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
2338void QQuickFlickable::flickToChild(QQuickItem *child, PositionMode mode,
const QPointF &offset)
2340 Q_D(QQuickFlickable);
2343 if (!d->contentItem->isAncestorOf(child))
2346 const QRectF itemRect =
2347 child->mapRectToItem(d->contentItem, QRectF(0, 0, child->width(), child->height()));
2349 QPointF currentPosition = QPointF(contentX(), contentY());
2350 QPointF newPosition = computePosition(currentPosition, itemRect, mode, offset);
2352 flickTo(newPosition);
2356
2357
2358
2359
2360
2361
2362
2363
2365void QQuickFlickable::flickTo(
const QPointF &newPosition)
2367 Q_D(QQuickFlickable);
2369 QPointF currentPosition = QPointF(contentX(), contentY());
2371 qreal xVelocity = 0.0;
2372 qreal yVelocity = 0.0;
2374 const qreal deltaX = newPosition.x() - currentPosition.x();
2375 const qreal deltaY = newPosition.y() - currentPosition.y();
2380 if (xflick() && qAbs(deltaX) > 0.5) {
2381 const qreal decel = flickDeceleration();
2382 qreal velocity = qSqrt(2.0 * decel * qAbs(deltaX));
2383 if (qAbs(velocity) < _q_MinimumFlickVelocity)
2385 const qreal maxVel = maximumFlickVelocity();
2386 if (maxVel > 0 && velocity > maxVel)
2388 xVelocity = deltaX > 0 ? -velocity : velocity;
2391 if (yflick() && qAbs(deltaY) > 0.5) {
2392 const qreal decel = flickDeceleration();
2393 qreal velocity = qSqrt(2.0 * decel * qAbs(deltaY));
2394 if (qAbs(velocity) < _q_MinimumFlickVelocity)
2396 const qreal maxVel = maximumFlickVelocity();
2397 if (maxVel > 0 && velocity > maxVel)
2399 yVelocity = deltaY > 0 ? -velocity : velocity;
2402 if (qAbs(xVelocity) > 0.0 || qAbs(yVelocity) > 0.0) {
2403 flick(xVelocity, yVelocity);
2405 if (newPosition.x() != currentPosition.x()) {
2406 setContentX(newPosition.x());
2409 if (newPosition.y() != currentPosition.y()) {
2410 setContentY(newPosition.y());
2416void QQuickFlickablePrivate::data_append(QQmlListProperty<QObject> *prop, QObject *o)
2418 if (!prop || !prop->data)
2421 if (QQuickItem *i = qmlobject_cast<QQuickItem *>(o)) {
2422 i->setParentItem(
static_cast<QQuickFlickablePrivate*>(prop->data)->contentItem);
2423 }
else if (QQuickPointerHandler *pointerHandler = qmlobject_cast<QQuickPointerHandler *>(o)) {
2424 static_cast<QQuickFlickablePrivate*>(prop->data)->addPointerHandler(pointerHandler);
2426 o->setParent(prop->object);
2430qsizetype QQuickFlickablePrivate::data_count(QQmlListProperty<QObject> *)
2436QObject *QQuickFlickablePrivate::data_at(QQmlListProperty<QObject> *, qsizetype)
2442void QQuickFlickablePrivate::data_clear(QQmlListProperty<QObject> *)
2447QQmlListProperty<QObject> QQuickFlickable::flickableData()
2449 Q_D(QQuickFlickable);
2450 return QQmlListProperty<QObject>(
this, (
void *)d, QQuickFlickablePrivate::data_append,
2451 QQuickFlickablePrivate::data_count,
2452 QQuickFlickablePrivate::data_at,
2453 QQuickFlickablePrivate::data_clear);
2456QQmlListProperty<QQuickItem> QQuickFlickable::flickableChildren()
2458 Q_D(QQuickFlickable);
2459 return QQuickItemPrivate::get(d->contentItem)->children();
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
2487
2488QQuickFlickable::BoundsBehavior QQuickFlickable::boundsBehavior()
const
2490 Q_D(
const QQuickFlickable);
2491 return d->boundsBehavior;
2494void QQuickFlickable::setBoundsBehavior(BoundsBehavior b)
2496 Q_D(QQuickFlickable);
2497 if (b == d->boundsBehavior)
2499 d->boundsBehavior = b;
2500 emit boundsBehaviorChanged();
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
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
2539
2540
2541
2542
2543QQuickTransition *QQuickFlickable::rebound()
const
2545 Q_D(
const QQuickFlickable);
2549void QQuickFlickable::setRebound(QQuickTransition *transition)
2551 Q_D(QQuickFlickable);
2553 if (!d->hData.transitionToBounds)
2554 d->hData.transitionToBounds =
new QQuickFlickableReboundTransition(
this, QLatin1String(
"x"));
2555 if (!d->vData.transitionToBounds)
2556 d->vData.transitionToBounds =
new QQuickFlickableReboundTransition(
this, QLatin1String(
"y"));
2558 if (d->rebound != transition) {
2559 d->rebound = transition;
2560 emit reboundChanged();
2565
2566
2567
2568
2569
2570
2571
2572
2573
2574
2575
2576
2577
2578
2579
2580
2581
2582
2583
2584
2585
2586
2587
2588qreal QQuickFlickable::contentWidth()
const
2590 Q_D(
const QQuickFlickable);
2591 return d->hData.viewSize;
2594void QQuickFlickable::setContentWidth(qreal w)
2596 Q_D(QQuickFlickable);
2597 if (d->hData.viewSize == w)
2599 d->hData.viewSize = w;
2601 d->contentItem->setWidth(width() - d->hData.startMargin - d->hData.endMargin);
2603 d->contentItem->setWidth(w);
2604 d->hData.markExtentsDirty();
2606 if (!d->pressed && !d->hData.moving && !d->vData.moving) {
2607 d->fixupMode = QQuickFlickablePrivate::Immediate;
2609 }
else if (!d->pressed && d->hData.fixingUp) {
2610 d->fixupMode = QQuickFlickablePrivate::ExtentChanged;
2613 emit contentWidthChanged();
2614 d->updateBeginningEnd();
2617qreal QQuickFlickable::contentHeight()
const
2619 Q_D(
const QQuickFlickable);
2620 return d->vData.viewSize;
2623void QQuickFlickable::setContentHeight(qreal h)
2625 Q_D(QQuickFlickable);
2626 if (d->vData.viewSize == h)
2628 d->vData.viewSize = h;
2630 d->contentItem->setHeight(height() - d->vData.startMargin - d->vData.endMargin);
2632 d->contentItem->setHeight(h);
2633 d->vData.markExtentsDirty();
2635 if (!d->pressed && !d->hData.moving && !d->vData.moving) {
2636 d->fixupMode = QQuickFlickablePrivate::Immediate;
2638 }
else if (!d->pressed && d->vData.fixingUp) {
2639 d->fixupMode = QQuickFlickablePrivate::ExtentChanged;
2642 emit contentHeightChanged();
2643 d->updateBeginningEnd();
2647
2648
2649
2650
2651
2652
2653
2654
2657qreal QQuickFlickable::topMargin()
const
2659 Q_D(
const QQuickFlickable);
2660 return d->vData.startMargin;
2663void QQuickFlickable::setTopMargin(qreal m)
2665 Q_D(QQuickFlickable);
2666 if (d->vData.startMargin == m)
2668 d->vData.startMargin = m;
2669 d->vData.markExtentsDirty();
2670 if (!d->pressed && !d->hData.moving && !d->vData.moving) {
2672 d->fixupMode = QQuickFlickablePrivate::Immediate;
2675 emit topMarginChanged();
2676 d->updateBeginningEnd();
2679qreal QQuickFlickable::bottomMargin()
const
2681 Q_D(
const QQuickFlickable);
2682 return d->vData.endMargin;
2685void QQuickFlickable::setBottomMargin(qreal m)
2687 Q_D(QQuickFlickable);
2688 if (d->vData.endMargin == m)
2690 d->vData.endMargin = m;
2691 d->vData.markExtentsDirty();
2692 if (!d->pressed && !d->hData.moving && !d->vData.moving) {
2694 d->fixupMode = QQuickFlickablePrivate::Immediate;
2697 emit bottomMarginChanged();
2698 d->updateBeginningEnd();
2701qreal QQuickFlickable::leftMargin()
const
2703 Q_D(
const QQuickFlickable);
2704 return d->hData.startMargin;
2707void QQuickFlickable::setLeftMargin(qreal m)
2709 Q_D(QQuickFlickable);
2710 if (d->hData.startMargin == m)
2712 d->hData.startMargin = m;
2713 d->hData.markExtentsDirty();
2714 if (!d->pressed && !d->hData.moving && !d->vData.moving) {
2716 d->fixupMode = QQuickFlickablePrivate::Immediate;
2719 emit leftMarginChanged();
2720 d->updateBeginningEnd();
2723qreal QQuickFlickable::rightMargin()
const
2725 Q_D(
const QQuickFlickable);
2726 return d->hData.endMargin;
2729void QQuickFlickable::setRightMargin(qreal m)
2731 Q_D(QQuickFlickable);
2732 if (d->hData.endMargin == m)
2734 d->hData.endMargin = m;
2735 d->hData.markExtentsDirty();
2736 if (!d->pressed && !d->hData.moving && !d->vData.moving) {
2738 d->fixupMode = QQuickFlickablePrivate::Immediate;
2741 emit rightMarginChanged();
2742 d->updateBeginningEnd();
2746
2747
2748
2749
2750
2751
2752
2753
2754
2755
2756
2757
2759qreal QQuickFlickable::originY()
const
2761 Q_D(
const QQuickFlickable);
2762 return -minYExtent() + d->vData.startMargin;
2765qreal QQuickFlickable::originX()
const
2767 Q_D(
const QQuickFlickable);
2768 return -minXExtent() + d->hData.startMargin;
2773
2774
2775
2776
2777
2778
2779
2780
2781
2782
2783
2784void QQuickFlickable::resizeContent(qreal w, qreal h, QPointF center)
2786 Q_D(QQuickFlickable);
2787 const qreal oldHSize = d->hData.viewSize;
2788 const qreal oldVSize = d->vData.viewSize;
2789 const bool needToUpdateWidth = w != oldHSize;
2790 const bool needToUpdateHeight = h != oldVSize;
2791 d->hData.viewSize = w;
2792 d->vData.viewSize = h;
2793 d->contentItem->setSize(QSizeF(w, h));
2794 if (needToUpdateWidth)
2795 emit contentWidthChanged();
2796 if (needToUpdateHeight)
2797 emit contentHeightChanged();
2799 if (center.x() != 0) {
2800 qreal pos = center.x() * w / oldHSize;
2801 setContentX(contentX() + pos - center.x());
2803 if (center.y() != 0) {
2804 qreal pos = center.y() * h / oldVSize;
2805 setContentY(contentY() + pos - center.y());
2807 d->updateBeginningEnd();
2811
2812
2813
2814
2815
2816
2817
2818void QQuickFlickable::returnToBounds()
2820 Q_D(QQuickFlickable);
2825qreal QQuickFlickable::vWidth()
const
2827 Q_D(
const QQuickFlickable);
2828 if (d->hData.viewSize < 0)
2831 return d->hData.viewSize;
2834qreal QQuickFlickable::vHeight()
const
2836 Q_D(
const QQuickFlickable);
2837 if (d->vData.viewSize < 0)
2840 return d->vData.viewSize;
2844
2845
2846
2847
2848
2849
2850bool QQuickFlickable::xflick()
const
2852 Q_D(
const QQuickFlickable);
2853 const int contentWidthWithMargins = d->contentItem->width() + d->hData.startMargin + d->hData.endMargin;
2854 if ((d->flickableDirection & QQuickFlickable::AutoFlickIfNeeded) && (contentWidthWithMargins > width()))
2856 if (d->flickableDirection == QQuickFlickable::AutoFlickDirection)
2857 return std::floor(qAbs(contentWidthWithMargins - width()));
2858 return d->flickableDirection & QQuickFlickable::HorizontalFlick;
2862
2863
2864
2865
2866
2867
2868bool QQuickFlickable::yflick()
const
2870 Q_D(
const QQuickFlickable);
2871 const int contentHeightWithMargins = d->contentItem->height() + d->vData.startMargin + d->vData.endMargin;
2872 if ((d->flickableDirection & QQuickFlickable::AutoFlickIfNeeded) && (contentHeightWithMargins > height()))
2874 if (d->flickableDirection == QQuickFlickable::AutoFlickDirection)
2875 return std::floor(qAbs(contentHeightWithMargins - height()));
2876 return d->flickableDirection & QQuickFlickable::VerticalFlick;
2879QPointF QQuickFlickable::computePosition(QPointF currentPosition, QRectF itemRect, PositionMode mode,
const QPointF &offset)
const
2881 QPointF newPosition = currentPosition;
2884 const qreal viewWidth = width();
2886 if (mode & QQuickFlickable::AlignLeft)
2887 newPosition.setX(itemRect.left());
2888 if (mode & QQuickFlickable::AlignHCenter)
2889 newPosition.setX(itemRect.left() - (viewWidth - itemRect.width()) / 2);
2890 if (mode & QQuickFlickable::AlignRight)
2891 newPosition.setX(itemRect.right() - viewWidth);
2892 if (mode & QQuickFlickable::Visible) {
2893 if (itemRect.right() < currentPosition.x())
2894 newPosition.setX(itemRect.left());
2895 else if (itemRect.left() > currentPosition.x() + viewWidth)
2896 newPosition.setX(itemRect.right() - viewWidth);
2898 if (mode & QQuickFlickable::Contain) {
2899 if (itemRect.right() > currentPosition.x() + viewWidth)
2900 newPosition.setX(itemRect.right() - viewWidth);
2901 if (itemRect.left() < newPosition.x())
2902 newPosition.setX(itemRect.left());
2905 const qreal minX = -minXExtent();
2906 const qreal maxX = -maxXExtent();
2907 newPosition.setX(qMin(newPosition.x(), maxX));
2908 newPosition.setX(qMax(newPosition.x(), minX));
2912 const qreal viewHeight = height();
2914 if (mode & QQuickFlickable::AlignTop)
2915 newPosition.setY(itemRect.top());
2916 if (mode & QQuickFlickable::AlignVCenter)
2917 newPosition.setY(itemRect.top() - (viewHeight - itemRect.height()) / 2);
2918 if (mode & QQuickFlickable::AlignBottom)
2919 newPosition.setY(itemRect.bottom() - viewHeight);
2920 if (mode & QQuickFlickable::Visible) {
2921 if (itemRect.bottom() < currentPosition.y())
2922 newPosition.setY(itemRect.top());
2923 else if (itemRect.top() > currentPosition.y() + viewHeight)
2924 newPosition.setY(itemRect.bottom() - viewHeight);
2926 if (mode & QQuickFlickable::Contain) {
2927 if (itemRect.bottom() > currentPosition.y() + viewHeight)
2928 newPosition.setY(itemRect.bottom() - viewHeight);
2929 if (itemRect.top() < currentPosition.y())
2930 newPosition.setY(itemRect.top());
2933 const qreal minY = -minYExtent();
2934 const qreal maxY = -maxYExtent();
2935 newPosition.setY(qMin(newPosition.y(), maxY));
2936 newPosition.setY(qMax(newPosition.y(), minY));
2939 return newPosition + offset;
2942void QQuickFlickable::mouseUngrabEvent()
2944 Q_D(QQuickFlickable);
2947 if (!d->replayingPressEvent)
2948 d->cancelInteraction();
2951void QQuickFlickablePrivate::cancelInteraction()
2953 Q_Q(QQuickFlickable);
2955 clearDelayedPress();
2959 q->setKeepMouseGrab(
false);
2962 if (!isViewMoving())
2963 q->movementEnding();
2967void QQuickFlickablePrivate::addPointerHandler(QQuickPointerHandler *h)
2969 Q_Q(
const QQuickFlickable);
2970 qCDebug(lcHandlerParent) <<
"reparenting handler" << h <<
"to contentItem of" << q;
2971 h->setParent(contentItem);
2972 QQuickItemPrivate::get(contentItem)->addPointerHandler(h);
2976
2977
2978
2979
2980
2981
2982
2983bool QQuickFlickable::filterPointerEvent(QQuickItem *receiver, QPointerEvent *event)
2985 Q_D(QQuickFlickable);
2986 const bool isTouch = QQuickDeliveryAgentPrivate::isTouchEvent(event);
2987 const bool isMouse = QQuickDeliveryAgentPrivate::isMouseEvent(event);
2988 if (isMouse || QQuickDeliveryAgentPrivate::isTabletEvent(event)) {
2989 if (!d->buttonsAccepted(
static_cast<QSinglePointEvent *>(event)))
2990 return QQuickItem::childMouseEventFilter(receiver, event);
2991 }
else if (!isTouch) {
2994 Q_ASSERT_X(receiver !=
this,
"",
"Flickable received a filter event for itself");
2996 if (isTouch &&
static_cast<QTouchEvent *>(event)->touchPointStates().testFlag(QEventPoint::State::Pressed))
2997 d->stealMouse =
false;
2999 if (event->pointCount() > 1) {
3000 qCDebug(lcFilter) << objectName() <<
"ignoring multi-touch" << event <<
"for" << receiver;
3001 d->stealMouse =
false;
3004 qCDebug(lcFilter) << objectName() <<
"filtering" << event <<
"for" << receiver;
3007 const auto &firstPoint = event->points().first();
3009 if (event->pointCount() == 1 && event->exclusiveGrabber(firstPoint) ==
this) {
3016 event->setAccepted(
true);
3020 QPointF localPos = mapFromScene(firstPoint.scenePosition());
3021 bool receiverDisabled = receiver && !receiver->isEnabled();
3022 bool stealThisEvent = d->stealMouse;
3023 bool receiverKeepsGrab = receiver && (receiver->keepMouseGrab() || receiver->keepTouchGrab());
3024 bool receiverRelinquishGrab =
false;
3027 if (
auto *mouseArea = qmlobject_cast<QQuickMouseArea *>(receiver)) {
3028 bool preventStealing = mouseArea->preventStealing();
3029#if QT_CONFIG(quick_draganddrop)
3030 if (mouseArea->drag() && mouseArea->drag()->target())
3031 preventStealing =
true;
3033 if (!preventStealing && receiverKeepsGrab) {
3034 receiverRelinquishGrab = !receiverDisabled || (isMouse
3035 && firstPoint.state() == QEventPoint::State::Pressed
3036 && (receiver->acceptedMouseButtons() &
static_cast<QMouseEvent *>(event)->button()));
3037 if (receiverRelinquishGrab)
3038 receiverKeepsGrab =
false;
3042 if ((stealThisEvent || contains(localPos)) && (!receiver || !receiverKeepsGrab || receiverDisabled)) {
3043 QScopedPointer<QPointerEvent> localizedEvent(QQuickDeliveryAgentPrivate::clonePointerEvent(event, localPos));
3044 localizedEvent->setAccepted(
false);
3045 switch (firstPoint.state()) {
3046 case QEventPoint::State::Updated:
3047 d->handleMoveEvent(localizedEvent.data());
3049 case QEventPoint::State::Pressed:
3050 d->handlePressEvent(localizedEvent.data());
3051 d->captureDelayedPress(receiver, event);
3053 d->stealMouse =
false;
3054 stealThisEvent =
false;
3056 case QEventPoint::State::Released:
3057 d->handleReleaseEvent(localizedEvent.data());
3058 stealThisEvent = d->stealMouse;
3060 case QEventPoint::State::Stationary:
3061 case QEventPoint::State::Unknown:
3064 if ((receiver && stealThisEvent && !receiverKeepsGrab && receiver !=
this) || receiverDisabled) {
3065 d->clearDelayedPress();
3066 event->setExclusiveGrabber(firstPoint,
this);
3067 }
else if (d->delayedPressEvent) {
3068 event->setExclusiveGrabber(firstPoint,
this);
3071
3072
3073
3074
3075
3076
3077
3078
3079
3080
3081
3082 if (isMoving() || (!receiverRelinquishGrab && (stealThisEvent || d->delayedPressEvent || receiverDisabled))) {
3084 event->setAccepted(
true);
3090 }
else if (d->lastPosTime != -1) {
3091 d->lastPosTime = -1;
3094 if (firstPoint.state() == QEventPoint::State::Released || (receiverKeepsGrab && !receiverDisabled)) {
3096 d->lastPosTime = -1;
3097 d->clearDelayedPress();
3098 d->stealMouse =
false;
3105
3106
3107
3108bool QQuickFlickable::childMouseEventFilter(QQuickItem *i, QEvent *e)
3110 Q_D(QQuickFlickable);
3111 QPointerEvent *pointerEvent = e->isPointerEvent() ?
static_cast<QPointerEvent *>(e) :
nullptr;
3113 auto wantsPointerEvent_helper = [
this, d, i, pointerEvent]() {
3114 Q_ASSERT(pointerEvent);
3115 QQuickDeliveryAgentPrivate::localizePointerEvent(pointerEvent,
this);
3116 const bool wants = d->wantsPointerEvent(pointerEvent);
3118 QQuickDeliveryAgentPrivate::localizePointerEvent(pointerEvent, i);
3122 if (!isVisible() || !isEnabled() || !isInteractive() ||
3123 (pointerEvent && !wantsPointerEvent_helper())) {
3124 d->cancelInteraction();
3125 return QQuickItem::childMouseEventFilter(i, e);
3128 if (e->type() == QEvent::UngrabMouse) {
3129 Q_ASSERT(e->isSinglePointEvent());
3130 auto spe =
static_cast<QSinglePointEvent *>(e);
3131 const QObject *grabber = spe->exclusiveGrabber(spe->points().first());
3132 qCDebug(lcFilter) <<
"filtering UngrabMouse" << spe->points().first() <<
"for" << i <<
"grabber is" << grabber;
3133 if (grabber !=
this)
3135 }
else if (pointerEvent) {
3136 return filterPointerEvent(i, pointerEvent);
3139 return QQuickItem::childMouseEventFilter(i, e);
3143
3144
3145
3146
3147
3148qreal QQuickFlickable::maximumFlickVelocity()
const
3150 Q_D(
const QQuickFlickable);
3151 return d->maxVelocity;
3154void QQuickFlickable::setMaximumFlickVelocity(qreal v)
3156 Q_D(QQuickFlickable);
3157 if (v == d->maxVelocity)
3160 emit maximumFlickVelocityChanged();
3164
3165
3166
3167
3168
3169
3170
3171
3172qreal QQuickFlickable::flickDeceleration()
const
3174 Q_D(
const QQuickFlickable);
3175 return d->deceleration;
3178void QQuickFlickable::setFlickDeceleration(qreal deceleration)
3180 Q_D(QQuickFlickable);
3181 if (deceleration == d->deceleration)
3183 d->deceleration = qMax(0.001, deceleration);
3184 emit flickDecelerationChanged();
3187bool QQuickFlickable::isFlicking()
const
3189 Q_D(
const QQuickFlickable);
3190 return d->hData.flicking || d->vData.flicking;
3194
3195
3196
3197
3198
3199
3200
3201bool QQuickFlickable::isFlickingHorizontally()
const
3203 Q_D(
const QQuickFlickable);
3204 return d->hData.flicking;
3207bool QQuickFlickable::isFlickingVertically()
const
3209 Q_D(
const QQuickFlickable);
3210 return d->vData.flicking;
3214
3215
3216
3217
3218
3219
3220
3221bool QQuickFlickable::isDragging()
const
3223 Q_D(
const QQuickFlickable);
3224 return d->hData.dragging || d->vData.dragging;
3227bool QQuickFlickable::isDraggingHorizontally()
const
3229 Q_D(
const QQuickFlickable);
3230 return d->hData.dragging;
3233bool QQuickFlickable::isDraggingVertically()
const
3235 Q_D(
const QQuickFlickable);
3236 return d->vData.dragging;
3239void QQuickFlickablePrivate::draggingStarting()
3241 Q_Q(QQuickFlickable);
3242 bool wasDragging = hData.dragging || vData.dragging;
3243 if (hMoved && !hData.dragging) {
3244 hData.dragging =
true;
3245 emit q->draggingHorizontallyChanged();
3247 if (vMoved && !vData.dragging) {
3248 vData.dragging =
true;
3249 emit q->draggingVerticallyChanged();
3251 if (!wasDragging && (hData.dragging || vData.dragging)) {
3252 emit q->draggingChanged();
3253 emit q->dragStarted();
3257void QQuickFlickablePrivate::draggingEnding()
3259 Q_Q(QQuickFlickable);
3260 const bool wasDragging = hData.dragging || vData.dragging;
3261 if (hData.dragging) {
3262 hData.dragging =
false;
3263 emit q->draggingHorizontallyChanged();
3265 if (vData.dragging) {
3266 vData.dragging =
false;
3267 emit q->draggingVerticallyChanged();
3270 if (!hData.dragging && !vData.dragging) {
3271 emit q->draggingChanged();
3272 emit q->dragEnded();
3274 hData.inRebound =
false;
3275 vData.inRebound =
false;
3279bool QQuickFlickablePrivate::isViewMoving()
const
3281 if (timeline.isActive()
3282 || (hData.transitionToBounds && hData.transitionToBounds->isActive())
3283 || (vData.transitionToBounds && vData.transitionToBounds->isActive()) ) {
3290
3291
3292
3293
3294
3295
3296
3297
3298
3299
3300
3301
3302
3303
3304
3305
3306
3307int QQuickFlickable::pressDelay()
const
3309 Q_D(
const QQuickFlickable);
3310 return d->pressDelay;
3313void QQuickFlickable::setPressDelay(
int delay)
3315 Q_D(QQuickFlickable);
3316 if (d->pressDelay == delay)
3318 d->pressDelay = delay;
3319 emit pressDelayChanged();
3323
3324
3325
3326
3327
3328
3329
3330
3332bool QQuickFlickable::isMoving()
const
3334 Q_D(
const QQuickFlickable);
3335 return d->hData.moving || d->vData.moving;
3338bool QQuickFlickable::isMovingHorizontally()
const
3340 Q_D(
const QQuickFlickable);
3341 return d->hData.moving;
3344bool QQuickFlickable::isMovingVertically()
const
3346 Q_D(
const QQuickFlickable);
3347 return d->vData.moving;
3350void QQuickFlickable::velocityTimelineCompleted()
3352 Q_D(QQuickFlickable);
3353 if ( (d->hData.transitionToBounds && d->hData.transitionToBounds->isActive())
3354 || (d->vData.transitionToBounds && d->vData.transitionToBounds->isActive()) ) {
3361 if (d->vData.flicking)
3363 d->updateBeginningEnd();
3366void QQuickFlickable::timelineCompleted()
3368 Q_D(QQuickFlickable);
3369 if ( (d->hData.transitionToBounds && d->hData.transitionToBounds->isActive())
3370 || (d->vData.transitionToBounds && d->vData.transitionToBounds->isActive()) ) {
3374 d->updateBeginningEnd();
3377void QQuickFlickable::movementStarting()
3379 Q_D(QQuickFlickable);
3380 bool wasMoving = d->hData.moving || d->vData.moving;
3381 if (d->hMoved && !d->hData.moving) {
3382 d->hData.moving =
true;
3383 emit movingHorizontallyChanged();
3385 if (d->vMoved && !d->vData.moving) {
3386 d->vData.moving =
true;
3387 emit movingVerticallyChanged();
3390 if (!wasMoving && (d->hData.moving || d->vData.moving)) {
3391 emit movingChanged();
3392 emit movementStarted();
3393#if QT_CONFIG(accessibility)
3394 if (QAccessible::isActive()) {
3395 QAccessibleEvent ev(
this, QAccessible::ScrollingStart);
3396 QAccessible::updateAccessibility(&ev);
3402void QQuickFlickable::movementEnding()
3404 movementEnding(
true,
true);
3407void QQuickFlickable::movementEnding(
bool hMovementEnding,
bool vMovementEnding)
3409 Q_D(QQuickFlickable);
3412 const bool wasFlicking = d->hData.flicking || d->vData.flicking;
3413 if (hMovementEnding && d->hData.flicking) {
3414 d->hData.flicking =
false;
3415 emit flickingHorizontallyChanged();
3417 if (vMovementEnding && d->vData.flicking) {
3418 d->vData.flicking =
false;
3419 emit flickingVerticallyChanged();
3421 if (wasFlicking && (!d->hData.flicking || !d->vData.flicking)) {
3422 emit flickingChanged();
3424 }
else if (d->hData.flickingWhenDragBegan || d->vData.flickingWhenDragBegan) {
3425 d->hData.flickingWhenDragBegan = !hMovementEnding;
3426 d->vData.flickingWhenDragBegan = !vMovementEnding;
3431 bool wasMoving = isMoving();
3432 if (hMovementEnding && d->hData.moving
3433 && (!d->pressed && !d->stealMouse)) {
3434 d->hData.moving =
false;
3436 emit movingHorizontallyChanged();
3438 if (vMovementEnding && d->vData.moving
3439 && (!d->pressed && !d->stealMouse)) {
3440 d->vData.moving =
false;
3442 emit movingVerticallyChanged();
3444 if (wasMoving && !isMoving()) {
3445 emit movingChanged();
3446 emit movementEnded();
3447#if QT_CONFIG(accessibility)
3448 if (QAccessible::isActive()) {
3449 QAccessibleEvent ev(
this, QAccessible::ScrollingEnd);
3450 QAccessible::updateAccessibility(&ev);
3455 if (hMovementEnding) {
3456 d->hData.fixingUp =
false;
3457 d->hData.smoothVelocity.setValue(0);
3458 d->hData.previousDragDelta = 0.0;
3460 if (vMovementEnding) {
3461 d->vData.fixingUp =
false;
3462 d->vData.smoothVelocity.setValue(0);
3463 d->vData.previousDragDelta = 0.0;
3467void QQuickFlickablePrivate::updateVelocity()
3469 Q_Q(QQuickFlickable);
3470 emit q->horizontalVelocityChanged();
3471 emit q->verticalVelocityChanged();
3475
3476
3477
3478
3479
3480
3481
3482
3483
3484
3485
3486
3487
3488
3489qreal QQuickFlickable::horizontalOvershoot()
const
3491 Q_D(
const QQuickFlickable);
3492 return d->hData.overshoot;
3496
3497
3498
3499
3500
3501
3502
3503
3504
3505
3506
3507
3508
3509
3510qreal QQuickFlickable::verticalOvershoot()
const
3512 Q_D(
const QQuickFlickable);
3513 return d->vData.overshoot;
3517
3518
3519
3520
3521
3522
3523
3524
3525
3526
3527
3528
3529
3530
3531
3532
3533
3534
3535
3536
3537
3538
3539
3540
3541
3542
3543
3544
3545
3546
3547
3548
3549
3550
3551
3552
3553
3554
3555
3556
3557
3558
3559
3560
3561
3562QQuickFlickable::BoundsMovement QQuickFlickable::boundsMovement()
const
3564 Q_D(
const QQuickFlickable);
3565 return d->boundsMovement;
3568void QQuickFlickable::setBoundsMovement(BoundsMovement movement)
3570 Q_D(QQuickFlickable);
3571 if (d->boundsMovement == movement)
3574 d->boundsMovement = movement;
3575 emit boundsMovementChanged();
3580#include "moc_qquickflickable_p_p.cpp"
3582#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