10#include <QtQml/qqmlcomponent.h>
11#include <QtQuick/private/qquickpointerhandler_p.h>
12#include <QtQuick/private/qquickstate_p.h>
13#include <private/qqmlglobal_p.h>
14#include <private/qqmlopenmetaobject_p.h>
15#include <private/qqmlchangeset_p.h>
16#include <qpa/qplatformtheme.h>
18#include <QtQml/qqmlinfo.h>
20#include <QtGui/private/qeventpoint_p.h>
21#include <QtGui/qevent.h>
22#include <QtGui/qguiapplication.h>
23#include <QtGui/private/qguiapplication_p.h>
24#include <QtGui/qstylehints.h>
25#include <QtCore/qmath.h>
29#if QT_CONFIG(quick_itemview)
30#include <private/qquickitemview_p.h>
35#if !QT_CONFIG(quick_itemview)
43: QObject(parent), m_percent(-1), m_view(
nullptr), m_onPath(
false), m_isCurrent(
false)
46 m_metaobject =
new QQmlOpenMetaObject(
this, qPathViewAttachedType);
47 m_metaobject->setCached(
true);
49 m_metaobject =
new QQmlOpenMetaObject(
this);
59 return m_metaobject->value(name);
63 m_metaobject->setValue(name, val);
67 : path(
nullptr),
currentIndex(0), currentItemOffset(0), startPc(0)
68 , offset(0), offsetAdj(0), mappedRange(1), mappedCache(0)
73 , dragMargin(0), deceleration(100)
74 , maximumFlickVelocity(QGuiApplicationPrivate::platformTheme()->themeHint(QPlatformTheme::FlickMaximumVelocity).toReal())
75 , moveOffset(
this, &QQuickPathViewPrivate::setAdjustedOffset),
flickDuration(0)
77 ,
moveReason(
Other), movementDirection(QQuickPathView::Shortest), moveDirection(QQuickPathView::Shortest)
79 , moveHighlight(
this, &QQuickPathViewPrivate::setHighlightPosition)
80 , highlightPosition(0)
81 , highlightRangeStart(0), highlightRangeEnd(0)
82 , highlightRangeMode(QQuickPathView::StrictlyEnforceRange)
86 setSizePolicy(QLayoutPolicy::Preferred, QLayoutPolicy::Preferred);
93 q->setAcceptedMouseButtons(Qt::LeftButton);
94 q->setFlag(QQuickItem::ItemIsFocusScope);
95 q->setFiltersChildMouseEvents(
true);
96 qmlobject_connect(&tl, QQuickTimeLine, SIGNAL(updated()),
97 q, QQuickPathView, SLOT(ticked()));
99 qmlobject_connect(&tl, QQuickTimeLine, SIGNAL(completed()),
100 q, QQuickPathView, SLOT(movementEnding()));
109 QObject *object = model->object(modelIndex, async ? QQmlIncubator::Asynchronous : QQmlIncubator::AsynchronousIfNested);
110 QQuickItem *item = qmlobject_cast<QQuickItem*>(object);
113 model->release(object);
116 QObject* delegate = q->delegate();
117 qmlWarning(delegate ? delegate : q) << QQuickPathView::tr(
"Delegate must be of Item type");
121 item->setParentItem(q);
123 QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
124 itemPrivate->addItemChangeListener(
125 this, QQuickItemPrivate::Geometry | QQuickItemPrivate::Destroyed);
131void QQuickPathView::createdItem(
int index, QObject *object)
134 QQuickItem *item = qmlobject_cast<QQuickItem*>(object);
135 if (d->requestedIndex != index) {
136 qPathViewAttachedType = d->attachedType();
137 QQuickPathViewAttached *att =
static_cast<QQuickPathViewAttached *>(qmlAttachedPropertiesObject<QQuickPathView>(item));
138 qPathViewAttachedType =
nullptr;
141 att->setOnPath(
false);
143 item->setParentItem(
this);
144 d->updateItem(item, 1);
146 d->requestedIndex = -1;
152void QQuickPathView::initItem(
int index, QObject *object)
155 QQuickItem *item = qmlobject_cast<QQuickItem*>(object);
156 if (item && d->requestedIndex == index) {
157 QQuickItemPrivate::get(item)->setCulled(
true);
158 item->setParentItem(
this);
159 qPathViewAttachedType = d->attachedType();
160 QQuickPathViewAttached *att =
static_cast<QQuickPathViewAttached *>(qmlAttachedPropertiesObject<QQuickPathView>(item));
161 qPathViewAttachedType =
nullptr;
164 qreal percent = d->positionOfIndex(index);
165 if (percent < 1 && d->path) {
166 const auto attributes = d->path->attributes();
167 for (
const QString &attr : attributes)
168 att->setValue(attr.toUtf8(), d->path->attributeAt(attr, percent));
169 item->setZ(d->requestedZ);
171 att->setOnPath(percent < 1);
180 qCDebug(lcItemViewDelegateLifecycle) <<
"release" << item;
181 QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
182 itemPrivate->removeItemChangeListener(
183 this, QQuickItemPrivate::Geometry | QQuickItemPrivate::Destroyed);
186 QQmlInstanceModel::ReleaseFlags flags = model->release(item);
191 }
else if (flags & QQmlInstanceModel::Destroyed) {
193 item->setParentItem(
nullptr);
199 return static_cast<QQuickPathViewAttached *>(qmlAttachedPropertiesObject<QQuickPathView>(item,
false));
206 attType =
new QQmlOpenMetaObjectType(&QQuickPathViewAttached::staticMetaObject);
208 const auto attributes = path->attributes();
209 for (
const QString &attr : attributes)
210 attType->createProperty(attr.toUtf8());
221 for (QQuickItem *p : std::as_const(items))
224 for (QQuickItem *p : std::as_const(itemCache))
229 model->cancel(requestedIndex);
244 if (model && pathItems != -1 && pathItems < modelCount) {
245 mappedRange = qreal(modelCount)/pathItems;
246 mappedCache = qreal(cacheSize)/pathItems/2;
257 if (model && index >= 0 && index < modelCount) {
259 if (haveHighlightRange && (highlightRangeMode != QQuickPathView::NoHighlightRange
260 || snapMode != QQuickPathView::NoSnap))
261 start = highlightRangeStart;
262 qreal globalPos = index + offset;
263 globalPos = std::fmod(globalPos, qreal(modelCount)) / modelCount;
265 globalPos += start / mappedRange;
266 globalPos = std::fmod(globalPos, qreal(1));
267 pos = globalPos * mappedRange;
269 pos = std::fmod(globalPos + start, qreal(1));
279 qreal upper,
bool emptyRangeCheck)
const
281 if (emptyRangeCheck && qFuzzyCompare(lower, upper))
284 if (position > upper && position > lower)
285 position -= mappedRange;
286 lower -= mappedRange;
288 return position >= lower && position < upper;
294 if (!q->isComponentComplete())
297 bool changed =
false;
305 QQuickItem *item =
nullptr;
308 QQmlContext *highlightContext =
new QQmlContext(
309 creationContext ? creationContext : qmlContext(q));
312 QQml_setParent_noEvent(highlightContext, nobj);
313 item = qobject_cast<QQuickItem *>(nobj);
317 delete highlightContext;
320 item =
new QQuickItem;
323 QQml_setParent_noEvent(item, q);
324 item->setParentItem(q);
329 emit q->highlightItemChanged();
335 if (!q->isComponentComplete() || !isValid())
338 if (haveHighlightRange && highlightRangeMode == QQuickPathView::StrictlyEnforceRange) {
339 updateItem(highlightItem, highlightRangeStart);
341 qreal target = currentIndex;
344 tl.reset(moveHighlight);
345 moveHighlight.setValue(highlightPosition);
349 if (target - highlightPosition > modelCount/2) {
351 qreal distance = modelCount - target + highlightPosition;
352 tl.move(moveHighlight, 0, QEasingCurve(QEasingCurve::InQuad),
int(duration * highlightPosition / distance));
353 tl.set(moveHighlight, modelCount-0.01);
354 tl.move(moveHighlight, target, QEasingCurve(QEasingCurve::OutQuad),
int(duration * (modelCount-target) / distance));
355 }
else if (target - highlightPosition <= -modelCount/2) {
357 qreal distance = modelCount - highlightPosition + target;
358 tl.move(moveHighlight, modelCount-0.01, QEasingCurve(QEasingCurve::InQuad),
int(duration * (modelCount-highlightPosition) / distance));
359 tl.set(moveHighlight, 0);
360 tl.move(moveHighlight, target, QEasingCurve(QEasingCurve::OutQuad),
int(duration * target / distance));
362 highlightUp = highlightPosition - target < 0;
363 tl.move(moveHighlight, target, QEasingCurve(QEasingCurve::InOutQuad), duration);
371 if (!(qFuzzyCompare(pos, highlightPosition))) {
374 if (haveHighlightRange && highlightRangeMode != QQuickPathView::NoHighlightRange) {
375 start = highlightRangeStart;
376 end = highlightRangeEnd;
379 qreal range = qreal(modelCount);
381 qreal relativeHighlight = std::fmod(pos + offset, range) / range;
383 if (!highlightUp && relativeHighlight > end / mappedRange) {
384 qreal diff = 1 - relativeHighlight;
385 setOffset(offset + diff * range);
386 }
else if (highlightUp && relativeHighlight >= (end - start) / mappedRange) {
387 qreal diff = relativeHighlight - (end - start) / mappedRange;
388 setOffset(offset - diff * range - 0.00001);
391 highlightPosition = pos;
392 qreal pathPos = positionOfIndex(pos);
393 updateItem(highlightItem, pathPos);
399void QQuickPathView::pathUpdated()
402 for (QQuickItem *item : std::as_const(d->items)) {
403 if (QQuickPathViewAttached *att = d->attached(item))
414 if (qFuzzyCompare(att->m_percent, percent))
416 att->m_percent = percent;
417 const auto attributes = path->attributes();
418 for (
const QString &attr : attributes)
419 att->setValue(attr.toUtf8(), path->attributeAt(attr, percent));
422 QQuickItemPrivate::get(item)->setCulled(percent >= 1);
423 QPointF pf = path->pointAtPercent(qMin(percent, qreal(1)));
424 item->setX(pf.x() - item->width()/2);
425 item->setY(pf.y() - item->height()/2);
431 if (!q->isComponentComplete())
451 emit q->dragStarted();
455 emit q->draggingChanged();
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
525QQuickPathView::QQuickPathView(QQuickItem *parent)
526 : QQuickItem(*(
new QQuickPathViewPrivate), parent)
532QQuickPathView::~QQuickPathView()
537 d->attType->release();
543
544
545
546
547
548
549
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
574
575
576
577
578
579
580
581
582
583
584
587
588
589
590
591
592
593
594
595
596
597
598QVariant QQuickPathView::model()
const
600 Q_D(
const QQuickPathView);
601 return d->modelVariant;
604void QQuickPathView::setModel(
const QVariant &m)
608 if (model.userType() == qMetaTypeId<QJSValue>())
609 model = model.value<QJSValue>().toVariant();
611 if (d->modelVariant == model)
615 qmlobject_disconnect(d->model, QQmlInstanceModel, SIGNAL(modelUpdated(QQmlChangeSet,
bool)),
616 this, QQuickPathView, SLOT(modelUpdated(QQmlChangeSet,
bool)));
617 qmlobject_disconnect(d->model, QQmlInstanceModel, SIGNAL(createdItem(
int,QObject*)),
618 this, QQuickPathView, SLOT(createdItem(
int,QObject*)));
619 qmlobject_disconnect(d->model, QQmlInstanceModel, SIGNAL(initItem(
int,QObject*)),
620 this, QQuickPathView, SLOT(initItem(
int,QObject*)));
624 d->modelVariant = model;
625 QObject *object = qvariant_cast<QObject*>(model);
626 QQmlInstanceModel *vim =
nullptr;
627 if (object && (vim = qobject_cast<QQmlInstanceModel *>(object))) {
635 d->model =
new QQmlDelegateModel(qmlContext(
this));
637 if (isComponentComplete())
638 static_cast<QQmlDelegateModel *>(d->model.data())->componentComplete();
640 if (QQmlDelegateModel *dataModel = qobject_cast<QQmlDelegateModel*>(d->model))
641 dataModel->setModel(model);
643 int oldModelCount = d->modelCount;
646 qmlobject_connect(d->model, QQmlInstanceModel, SIGNAL(modelUpdated(QQmlChangeSet,
bool)),
647 this, QQuickPathView, SLOT(modelUpdated(QQmlChangeSet,
bool)));
648 qmlobject_connect(d->model, QQmlInstanceModel, SIGNAL(createdItem(
int,QObject*)),
649 this, QQuickPathView, SLOT(createdItem(
int,QObject*)));
650 qmlobject_connect(d->model, QQmlInstanceModel, SIGNAL(initItem(
int,QObject*)),
651 this, QQuickPathView, SLOT(initItem(
int,QObject*)));
652 d->modelCount = d->model->count();
654 if (isComponentComplete()) {
655 if (d->currentIndex != 0) {
657 emit currentIndexChanged();
659 if (!(qFuzzyIsNull(d->offset))) {
661 emit offsetChanged();
665 if (d->modelCount != oldModelCount)
671
672
673
674int QQuickPathView::count()
const
676 Q_D(
const QQuickPathView);
677 return d->model ? d->modelCount : 0;
681
682
683
684
685QQuickPath *QQuickPathView::path()
const
687 Q_D(
const QQuickPathView);
691void QQuickPathView::setPath(QQuickPath *path)
697 qmlobject_disconnect(d->path, QQuickPath, SIGNAL(changed()),
698 this, QQuickPathView, SLOT(pathUpdated()));
702 qmlobject_connect(d->path, QQuickPath, SIGNAL(changed()),
703 this, QQuickPathView, SLOT(pathUpdated()));
706 if (isComponentComplete()) {
710 d->attType->release();
711 d->attType =
nullptr;
721
722
723
724int QQuickPathView::currentIndex()
const
726 Q_D(
const QQuickPathView);
727 return d->currentIndex;
730void QQuickPathView::setCurrentIndex(
int idx)
733 if (!isComponentComplete()) {
734 if (idx != d->currentIndex) {
735 d->currentIndex = idx;
736 emit currentIndexChanged();
742 ? ((idx % d->modelCount) + d->modelCount) % d->modelCount
744 if (d->model && (idx != d->currentIndex || !d->currentItem)) {
745 const bool hadCurrentItem = d->currentItem !=
nullptr;
746 const int oldCurrentIdx = d->currentIndex;
747 if (hadCurrentItem) {
748 if (QQuickPathViewAttached *att = d->attached(d->currentItem))
749 att->setIsCurrentItem(
false);
750 d->releaseCurrentItem();
752 d->moveReason = QQuickPathViewPrivate::SetIndex;
753 d->currentIndex = idx;
755 d->createCurrentItem();
756 if (d->haveHighlightRange && d->highlightRangeMode == QQuickPathView::StrictlyEnforceRange)
757 d->snapToIndex(d->currentIndex, QQuickPathViewPrivate::SetIndex);
758 d->currentItemOffset = d->positionOfIndex(d->currentIndex);
759 d->updateHighlight();
761 if (oldCurrentIdx != d->currentIndex)
762 emit currentIndexChanged();
764 emit currentItemChanged();
769
770
771
772QQuickItem *QQuickPathView::currentItem()
const
774 Q_D(
const QQuickPathView);
775 return d->currentItem;
779
780
781
782
783
784
785void QQuickPathView::incrementCurrentIndex()
788 d->moveDirection = QQuickPathView::Positive;
789 setCurrentIndex(currentIndex()+1);
793
794
795
796
797
798
799void QQuickPathView::decrementCurrentIndex()
802 d->moveDirection = QQuickPathView::Negative;
803 setCurrentIndex(currentIndex()-1);
807
808
809
810
811
812qreal QQuickPathView::offset()
const
814 Q_D(
const QQuickPathView);
818void QQuickPathView::setOffset(qreal offset)
821 d->moveReason = QQuickPathViewPrivate::Other;
822 d->setOffset(offset);
829 if (!qFuzzyCompare(offset, o)) {
830 if (isValid() && q->isComponentComplete()) {
831 qreal oldOffset = offset;
832 offset = std::fmod(o, qreal(modelCount));
834 offset += qreal(modelCount);
835 qCDebug(lcItemViewDelegateLifecycle) << o <<
"was" << oldOffset <<
"now" << offset;
840 emit q->offsetChanged();
846 setOffset(o+offsetAdj);
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872QQmlComponent *QQuickPathView::highlight()
const
874 Q_D(
const QQuickPathView);
875 return d->highlightComponent;
878void QQuickPathView::setHighlight(QQmlComponent *highlight)
881 if (highlight != d->highlightComponent) {
882 d->highlightComponent = highlight;
883 d->createHighlight();
884 d->updateHighlight();
885 emit highlightChanged();
890
891
892
893
894
895
896
897QQuickItem *QQuickPathView::highlightItem()
const
899 Q_D(
const QQuickPathView);
900 return d->highlightItem;
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939qreal QQuickPathView::preferredHighlightBegin()
const
941 Q_D(
const QQuickPathView);
942 return d->highlightRangeStart;
945void QQuickPathView::setPreferredHighlightBegin(qreal start)
948 if (qFuzzyCompare(d->highlightRangeStart, start) || start < 0 || start > 1)
950 d->highlightRangeStart = start;
951 d->haveHighlightRange = d->highlightRangeStart <= d->highlightRangeEnd;
953 emit preferredHighlightBeginChanged();
956qreal QQuickPathView::preferredHighlightEnd()
const
958 Q_D(
const QQuickPathView);
959 return d->highlightRangeEnd;
962void QQuickPathView::setPreferredHighlightEnd(qreal end)
965 if (qFuzzyCompare(d->highlightRangeEnd, end) || end < 0 || end > 1)
967 d->highlightRangeEnd = end;
968 d->haveHighlightRange = d->highlightRangeStart <= d->highlightRangeEnd;
970 emit preferredHighlightEndChanged();
973QQuickPathView::HighlightRangeMode QQuickPathView::highlightRangeMode()
const
975 Q_D(
const QQuickPathView);
976 return d->highlightRangeMode;
979void QQuickPathView::setHighlightRangeMode(HighlightRangeMode mode)
982 if (d->highlightRangeMode == mode)
984 d->highlightRangeMode = mode;
985 d->haveHighlightRange = d->highlightRangeStart <= d->highlightRangeEnd;
986 if (d->haveHighlightRange) {
988 int index = d->highlightRangeMode != NoHighlightRange ? d->currentIndex : d->calcCurrentIndex();
990 d->snapToIndex(index, QQuickPathViewPrivate::Other);
992 emit highlightRangeModeChanged();
996
997
998
999
1000
1001
1002
1003
1004int QQuickPathView::highlightMoveDuration()
const
1006 Q_D(
const QQuickPathView);
1007 return d->highlightMoveDuration;
1010void QQuickPathView::setHighlightMoveDuration(
int duration)
1012 Q_D(QQuickPathView);
1013 if (d->highlightMoveDuration == duration)
1015 d->highlightMoveDuration = duration;
1016 emit highlightMoveDurationChanged();
1020
1021
1022
1023
1024
1025
1026
1027qreal QQuickPathView::dragMargin()
const
1029 Q_D(
const QQuickPathView);
1030 return d->dragMargin;
1033void QQuickPathView::setDragMargin(qreal dragMargin)
1035 Q_D(QQuickPathView);
1036 if (qFuzzyCompare(d->dragMargin, dragMargin))
1038 d->dragMargin = dragMargin;
1039 emit dragMarginChanged();
1043
1044
1045
1046
1047
1048qreal QQuickPathView::flickDeceleration()
const
1050 Q_D(
const QQuickPathView);
1051 return d->deceleration;
1054void QQuickPathView::setFlickDeceleration(qreal dec)
1056 Q_D(QQuickPathView);
1057 if (qFuzzyCompare(d->deceleration, dec))
1059 d->deceleration = dec;
1060 emit flickDecelerationChanged();
1064
1065
1066
1067
1068
1069qreal QQuickPathView::maximumFlickVelocity()
const
1071 Q_D(
const QQuickPathView);
1072 return d->maximumFlickVelocity;
1075void QQuickPathView::setMaximumFlickVelocity(qreal vel)
1077 Q_D(QQuickPathView);
1078 if (qFuzzyCompare(vel, d->maximumFlickVelocity))
1080 d->maximumFlickVelocity = vel;
1081 emit maximumFlickVelocityChanged();
1086
1087
1088
1089
1090
1091
1092
1093bool QQuickPathView::isInteractive()
const
1095 Q_D(
const QQuickPathView);
1096 return d->interactive;
1099void QQuickPathView::setInteractive(
bool interactive)
1101 Q_D(QQuickPathView);
1102 if (interactive != d->interactive) {
1103 d->interactive = interactive;
1106 emit interactiveChanged();
1111
1112
1113
1114
1115
1116bool QQuickPathView::isMoving()
const
1118 Q_D(
const QQuickPathView);
1123
1124
1125
1126
1127
1128bool QQuickPathView::isFlicking()
const
1130 Q_D(
const QQuickPathView);
1135
1136
1137
1138
1139
1140bool QQuickPathView::isDragging()
const
1142 Q_D(
const QQuickPathView);
1147
1148
1149
1150
1151
1154
1155
1156
1157
1158
1159
1160
1161
1164
1165
1166
1167
1168
1169
1172
1173
1174
1175
1178
1179
1180
1181
1182
1185
1186
1187
1188
1189
1190
1191
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211QQmlComponent *QQuickPathView::delegate()
const
1213 Q_D(
const QQuickPathView);
1215 if (QQmlDelegateModel *dataModel = qobject_cast<QQmlDelegateModel*>(d->model))
1216 return dataModel->delegate();
1222void QQuickPathView::setDelegate(QQmlComponent *delegate)
1224 Q_D(QQuickPathView);
1225 if (delegate ==
this->delegate())
1228 d->model =
new QQmlDelegateModel(qmlContext(
this));
1230 if (isComponentComplete())
1231 static_cast<QQmlDelegateModel *>(d->model.data())->componentComplete();
1233 if (QQmlDelegateModel *dataModel = qobject_cast<QQmlDelegateModel*>(d->model)) {
1234 int oldCount = dataModel->count();
1235 dataModel->setDelegate(delegate);
1236 d->modelCount = dataModel->count();
1238 if (oldCount != dataModel->count())
1239 emit countChanged();
1240 emit delegateChanged();
1241 d->delegateValidated =
false;
1246
1247
1248
1249
1250
1251int QQuickPathView::pathItemCount()
const
1253 Q_D(
const QQuickPathView);
1254 return d->pathItems;
1257void QQuickPathView::setPathItemCount(
int i)
1259 Q_D(QQuickPathView);
1260 if (i == d->pathItems)
1265 d->updateMappedRange();
1266 if (d->isValid() && isComponentComplete()) {
1269 emit pathItemCountChanged();
1272void QQuickPathView::resetPathItemCount()
1274 Q_D(QQuickPathView);
1275 if (-1 == d->pathItems)
1278 d->updateMappedRange();
1279 if (d->isValid() && isComponentComplete())
1281 emit pathItemCountChanged();
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305int QQuickPathView::cacheItemCount()
const
1307 Q_D(
const QQuickPathView);
1308 return d->requestedCacheSize;
1311void QQuickPathView::setCacheItemCount(
int i)
1313 Q_D(QQuickPathView);
1314 if (i == d->requestedCacheSize || i < 0)
1317 d->requestedCacheSize = i;
1318 d->updateMappedRange();
1320 emit cacheItemCountChanged();
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341QQuickPathView::SnapMode QQuickPathView::snapMode()
const
1343 Q_D(
const QQuickPathView);
1347void QQuickPathView::setSnapMode(SnapMode mode)
1349 Q_D(QQuickPathView);
1350 if (mode == d->snapMode)
1353 emit snapModeChanged();
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379QQuickPathView::MovementDirection QQuickPathView::movementDirection()
const
1381 Q_D(
const QQuickPathView);
1382 return d->movementDirection;
1385void QQuickPathView::setMovementDirection(QQuickPathView::MovementDirection dir)
1387 Q_D(QQuickPathView);
1388 if (dir == d->movementDirection)
1390 d->movementDirection = dir;
1391 if (!d->tl.isActive())
1392 d->moveDirection = d->movementDirection;
1393 emit movementDirectionChanged();
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418void QQuickPathView::positionViewAtIndex(
int index,
int mode)
1420 Q_D(QQuickPathView);
1423 if (mode < QQuickPathView::Beginning || mode > QQuickPathView::SnapPosition || mode == 3)
1426 if (mode == QQuickPathView::Contain && (d->pathItems < 0 || d->modelCount <= d->pathItems))
1429 int count = d->pathItems == -1 ? d->modelCount : qMin(d->pathItems, d->modelCount);
1430 int idx = (index+d->modelCount) % d->modelCount;
1431 bool snap = d->haveHighlightRange && (d->highlightRangeMode != QQuickPathView::NoHighlightRange
1432 || d->snapMode != QQuickPathView::NoSnap);
1437 beginOffset = d->modelCount - idx - qFloor(count * d->highlightRangeStart);
1438 endOffset = beginOffset + count - 1;
1440 beginOffset = d->modelCount - idx;
1443 qreal adj =
sizeof(qreal) ==
sizeof(
float) ? 0.00001f : 0.000000000001;
1444 endOffset = std::fmod(beginOffset + count, qreal(d->modelCount)) - adj;
1446 qreal offset = d->offset;
1449 offset = beginOffset;
1455 if (beginOffset < endOffset)
1456 offset = (beginOffset + endOffset)/2;
1458 offset = (beginOffset + (endOffset + d->modelCount))/2;
1460 offset = qRound(offset);
1463 if ((beginOffset < endOffset && (d->offset < beginOffset || d->offset > endOffset))
1464 || (d->offset < beginOffset && d->offset > endOffset)) {
1465 qreal diff1 = std::fmod(beginOffset - d->offset + d->modelCount, qreal(d->modelCount));
1466 qreal diff2 = std::fmod(d->offset - endOffset + d->modelCount, qreal(d->modelCount));
1468 offset = beginOffset;
1474 offset = d->modelCount - idx;
1483
1484
1485
1486
1487
1488
1489
1490int QQuickPathView::indexAt(qreal x, qreal y)
const
1492 Q_D(
const QQuickPathView);
1493 QQuickItem *item = itemAt(x, y);
1494 return item ? d->model->indexOf(item,
nullptr) : -1;
1498
1499
1500
1501
1502
1503
1504
1505QQuickItem *QQuickPathView::itemAt(qreal x, qreal y)
const
1507 Q_D(
const QQuickPathView);
1511 for (QQuickItem *item : d->items) {
1512 QPointF p = item->mapFromItem(
this, QPointF(x, y));
1513 if (item->contains(p))
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533QQuickItem *QQuickPathView::itemAtIndex(
int index)
const
1535 Q_D(
const QQuickPathView);
1539 for (QQuickItem *item : d->items) {
1540 if (index == d->model->indexOf(item,
nullptr))
1548
1549
1550
1551
1552
1553
1554
1557 const auto pathLength = path->path().length();
1558 qreal samples = qMin(pathLength / 5, qreal(500));
1559 qreal res = pathLength / samples;
1561 qreal mindist = 1e10;
1562 QPointF nearPoint = path->pointAtPercent(0);
1566 for (qreal i=1; i < samples; i++) {
1567 QPointF pt = path->pointAtPercent(i/samples);
1568 QPointF diff = pt - point;
1569 qreal dist = diff.x()*diff.x() + diff.y()*diff.y();
1570 if (dist < mindist) {
1578 qreal approxPc = nearPc;
1579 for (qreal i = approxPc-1; i < approxPc+1; i += 1/(2*res)) {
1580 QPointF pt = path->pointAtPercent(i/samples);
1581 QPointF diff = pt - point;
1582 qreal dist = diff.x()*diff.x() + diff.y()*diff.y();
1583 if (dist < mindist) {
1591 *nearPercent = nearPc / samples;
1598 velocityBuffer[velocityWritePos] = v;
1602 qCDebug(lcPathView) <<
"instantaneous velocity" << v;
1614 for (
int i = 0; i < count; ++i) {
1619 qCDebug(lcPathView) <<
"average velocity" << velocity <<
"based on" << count <<
"samples";
1626 if (0 != event->timestamp())
1627 return qint64(event->timestamp());
1628 return timer.elapsed();
1631void QQuickPathView::mousePressEvent(QMouseEvent *event)
1633 Q_D(QQuickPathView);
1634 if (d->interactive) {
1635 d->handleMousePressEvent(event);
1638 QQuickItem::mousePressEvent(event);
1644 Q_Q(QQuickPathView);
1645 if (!interactive || !items.size() || !model || !modelCount)
1650 for (; idx < items.size(); ++idx) {
1651 QQuickItem *item = items.at(idx);
1652 if (item->contains(item->mapFromScene(event->scenePosition())))
1655 if (idx == items.size() && qFuzzyIsNull(dragMargin))
1658 startPoint = pointNear(event->position(), &startPc);
1659 startPos = event->position();
1660 if (idx == items.size()) {
1661 qreal distance = qAbs(event->position().x() - startPoint.x()) + qAbs(event->position().y() - startPoint.y());
1662 if (distance > dragMargin)
1666 if (tl.isActive() && flicking && flickDuration && qreal(tl.time()) / flickDuration < 0.8) {
1672 q->setKeepMouseGrab(stealMouse);
1675 lastPosTime = computeCurrentTime(event);
1679void QQuickPathView::mouseMoveEvent(QMouseEvent *event)
1681 Q_D(QQuickPathView);
1682 if (d->interactive) {
1683 d->handleMouseMoveEvent(event);
1686 QQuickItem::mouseMoveEvent(event);
1692 Q_Q(QQuickPathView);
1693 if (!interactive || !timer.isValid() || !model || !modelCount)
1696 qint64 currentTimestamp = computeCurrentTime(event);
1698 QPointF pathPoint = pointNear(event->position(), &newPc);
1700 QPointF posDelta = event->position() - startPos;
1701 if (QQuickDeliveryAgentPrivate::dragOverThreshold(posDelta.y(), Qt::YAxis, event) ||
1702 QQuickDeliveryAgentPrivate::dragOverThreshold(posDelta.x(), Qt::XAxis, event)) {
1706 QPointF pathDelta = pathPoint - startPoint;
1707 const int startDragDistance = QGuiApplication::styleHints()->startDragDistance();
1708 if (qAbs(pathDelta.x()) > startDragDistance * 0.8
1709 || qAbs(pathDelta.y()) > startDragDistance * 0.8) {
1711 q->setKeepMouseGrab(
true);
1717 qreal diff = (newPc - startPc)*count;
1718 if (!qFuzzyIsNull(diff)) {
1719 q->setOffset(offset + diff);
1721 if (diff > modelCount/2)
1723 else if (diff < -modelCount/2)
1726 qint64 elapsed = currentTimestamp - lastPosTime;
1728 addVelocitySample(diff / (qreal(elapsed) / 1000));
1732 emit q->movingChanged();
1733 emit q->movementStarted();
1738 lastPosTime = currentTimestamp;
1741void QQuickPathView::mouseReleaseEvent(QMouseEvent *event)
1743 Q_D(QQuickPathView);
1744 if (d->interactive) {
1745 d->handleMouseReleaseEvent(event);
1749 QQuickItem::mouseReleaseEvent(event);
1755 Q_Q(QQuickPathView);
1757 q->setKeepMouseGrab(
false);
1759 if (!interactive || !timer.isValid() || !model || !modelCount) {
1762 q->movementEnding();
1766 qreal velocity = calcVelocity();
1767 qint64 elapsed = computeCurrentTime(event) - lastPosTime;
1772 qCDebug(lcPathView) <<
"after elapsed time" << elapsed <<
"velocity decayed to" << velocity;
1773 qreal count = pathItems == -1 ? modelCount : qMin(pathItems, modelCount);
1774 const auto averageItemLength = path->path().length() / count;
1775 qreal pixelVelocity = averageItemLength * velocity;
1776 if (qAbs(pixelVelocity) > _q_MinimumFlickVelocity) {
1777 if (qAbs(pixelVelocity) > maximumFlickVelocity || snapMode == QQuickPathView::SnapOneItem) {
1779 qreal maxVel = velocity < 0 ? -maximumFlickVelocity : maximumFlickVelocity;
1780 velocity = maxVel / averageItemLength;
1783 qreal v2 = velocity*velocity;
1784 qreal accel = deceleration/10;
1786 if (haveHighlightRange && (highlightRangeMode == QQuickPathView::StrictlyEnforceRange
1787 || snapMode != QQuickPathView::NoSnap)) {
1788 if (snapMode == QQuickPathView::SnapOneItem) {
1791 dist = qRound(0.5 + offset) - offset;
1793 dist = qRound(0.5 - offset) + offset;
1796 dist = qMin(qreal(modelCount-1), qreal(v2 / (accel * 2) + 0.25));
1800 dist = qRound(dist + offset) - offset;
1802 dist = qRound(dist - offset) + offset;
1809 accel = v2 / (2 * qAbs(dist));
1812 dist = qMin(qreal(modelCount-1), qreal(v2 / (accel * 2)));
1814 flickDuration =
int(1000 * qAbs(velocity) / accel);
1816 moveOffset.setValue(offset);
1817 tl.accel(moveOffset, velocity, accel, dist);
1818 tl.callback(QQuickTimeLineCallback(&moveOffset, fixOffsetCallback,
this));
1821 emit q->flickingChanged();
1822 emit q->flickStarted();
1830 q->movementEnding();
1833bool QQuickPathView::childMouseEventFilter(QQuickItem *i, QEvent *e)
1835 Q_D(QQuickPathView);
1836 if (!isVisible() || !d->interactive || !e->isPointerEvent())
1837 return QQuickItem::childMouseEventFilter(i, e);
1839 QPointerEvent *pe =
static_cast<QPointerEvent *>(e);
1840 if (QQuickDeliveryAgentPrivate::isMouseEvent(pe)) {
1843 const auto &point = pe->points().first();
1844 QPointF localPos = mapFromScene(point.scenePosition());
1845 QObject *grabber = pe->exclusiveGrabber(point);
1846 QQuickPointerHandler *grabberHandler = qmlobject_cast<QQuickPointerHandler *>(grabber);
1847 QQuickItem *grabberItem = grabberHandler ? grabberHandler->parentItem() : qmlobject_cast<QQuickItem *>(grabber);
1848 if (grabberItem ==
this && d->stealMouse) {
1853 bool grabberDisabled = (grabberItem && !grabberItem->isEnabled()) || (grabberHandler && !grabberHandler->enabled());
1854 bool stealThisEvent = d->stealMouse;
1855 const bool mouseFromTouch = pe->pointingDevice()->type() == QPointingDevice::DeviceType::TouchScreen;
1856 if ((stealThisEvent || contains(localPos)) && (!grabberItem ||
1857 (!grabberItem->keepMouseGrab() && (!mouseFromTouch || !grabberItem->keepTouchGrab())) || grabberDisabled)) {
1859 QMutableSinglePointEvent localizedEvent(*
static_cast<QMouseEvent *>(pe));
1860 QMutableEventPoint::setPosition(localizedEvent.point(0), localPos);
1861 localizedEvent.setAccepted(
false);
1863 switch (localizedEvent.type()) {
1864 case QEvent::MouseMove:
1865 d->handleMouseMoveEvent(
static_cast<QMouseEvent *>(
static_cast<QSinglePointEvent *>(&localizedEvent)));
1867 case QEvent::MouseButtonPress:
1868 d->handleMousePressEvent(
static_cast<QMouseEvent *>(
static_cast<QSinglePointEvent *>(&localizedEvent)));
1869 stealThisEvent = d->stealMouse;
1871 case QEvent::MouseButtonRelease:
1872 d->handleMouseReleaseEvent(
static_cast<QMouseEvent *>(
static_cast<QSinglePointEvent *>(&localizedEvent)));
1878 grabber = localizedEvent.exclusiveGrabber(localizedEvent.points().first());
1879 grabberHandler = qmlobject_cast<QQuickPointerHandler *>(grabber);
1880 grabberItem = grabberHandler ? grabberHandler->parentItem() : qmlobject_cast<QQuickItem *>(grabber);
1881 grabberDisabled = (grabberItem && !grabberItem->isEnabled()) || (grabberHandler && !grabberHandler->enabled());
1882 if ((grabberItem && stealThisEvent && !grabberItem->keepMouseGrab() && grabber !=
this) || grabberDisabled)
1883 pe->setExclusiveGrabber(point,
this);
1885 const bool filtered = stealThisEvent || grabberDisabled;
1887 pe->setAccepted(stealThisEvent && grabberItem ==
this && !grabberDisabled);
1890 }
else if (d->timer.isValid()) {
1891 d->timer.invalidate();
1894 if (pe->type() == QEvent::MouseButtonRelease || (grabberItem && grabberItem->keepMouseGrab() && !grabberDisabled))
1895 d->stealMouse =
false;
1899 return QQuickItem::childMouseEventFilter(i, e);
1902void QQuickPathView::mouseUngrabEvent()
1904 Q_D(QQuickPathView);
1905 if (d->stealMouse ||
1906 (!d->flicking && d->snapMode != NoSnap && !qFuzzyCompare(qRound(d->offset), d->offset))) {
1909 d->stealMouse =
false;
1910 setKeepMouseGrab(
false);
1911 d->timer.invalidate();
1913 d->setDragging(
false);
1914 if (!d->tl.isActive())
1919void QQuickPathView::updatePolish()
1921 QQuickItem::updatePolish();
1927 if (currentIndex < 0)
1928 return modelCount + currentIndex % modelCount;
1930 return currentIndex % modelCount;
1933void QQuickPathView::componentComplete()
1935 Q_D(QQuickPathView);
1936 if (d->model && d->ownModel)
1937 static_cast<QQmlDelegateModel *>(d->model.data())->componentComplete();
1939 QQuickItem::componentComplete();
1942 d->modelCount = d->model->count();
1943 if (d->modelCount && d->currentIndex != 0)
1944 d->offset = std::fmod(qreal(d->modelCount - currentIndexRemainder(d->currentIndex, d->modelCount)), qreal(d->modelCount));
1947 d->createHighlight();
1949 d->updateHighlight();
1953 emit countChanged();
1956void QQuickPathView::refill()
1958 Q_D(QQuickPathView);
1961 d->scheduleLayout();
1965 d->layoutScheduled =
false;
1967 if (!d->isValid() || !isComponentComplete())
1972 bool currentVisible =
false;
1973 int count = d->pathItems == -1 ? d->modelCount : qMin(d->pathItems, d->modelCount);
1976 qCDebug(lcItemViewDelegateLifecycle) <<
"currentIndex" << d->currentIndex <<
"offset" << d->offset;
1977 QList<QQuickItem*>::iterator it = d->items.begin();
1978 while (it != d->items.end()) {
1979 QQuickItem *item = *it;
1980 int idx = d->model->indexOf(item,
nullptr);
1981 qreal pos = d->positionOfIndex(idx);
1982 if (lcItemViewDelegateLifecycle().isDebugEnabled()) {
1983 QQuickText *text = qmlobject_cast<QQuickText*>(item);
1985 qCDebug(lcItemViewDelegateLifecycle) <<
"idx" << idx <<
"@" << pos <<
": QQuickText" << text->objectName() << QStringView{text->text()}.left(40);
1987 qCDebug(lcItemViewDelegateLifecycle) <<
"idx" << idx <<
"@" << pos <<
":" << item;
1990 d->updateItem(item, pos);
1991 if (idx == d->currentIndex) {
1992 currentVisible =
true;
1993 d->currentItemOffset = pos;
1997 d->updateItem(item, pos);
1998 if (QQuickPathViewAttached *att = d->attached(item))
1999 att->setOnPath(pos < 1);
2000 if (!d->isInBound(pos, d->mappedRange - d->mappedCache, 1 + d->mappedCache)) {
2001 qCDebug(lcItemViewDelegateLifecycle) <<
"release" << idx <<
"@" << pos <<
", !isInBound: lower" << (d->mappedRange - d->mappedCache) <<
"upper" << (1 + d->mappedCache);
2002 d->releaseItem(item);
2003 it = d->items.erase(it);
2010 bool waiting =
false;
2011 if (d->modelCount) {
2013 if (d->items.size() < count+d->cacheSize) {
2018 const bool wasEmpty = d->items.isEmpty();
2024 for (QQuickItem * item : std::as_const(d->items)) {
2025 int idx = d->model->indexOf(item,
nullptr);
2026 qreal curPos = d->positionOfIndex(idx);
2027 if (curPos > endPos) {
2032 if (curPos < startPos) {
2038 if (d->haveHighlightRange
2039 && (d->highlightRangeMode != QQuickPathView::NoHighlightRange
2040 || d->snapMode != QQuickPathView::NoSnap))
2041 startPos = d->highlightRangeStart;
2043 endIdx = (qRound(d->modelCount - d->offset) - 1) % d->modelCount;
2044 endIdx = qMax(-1, endIdx);
2045 endPos = d->positionOfIndex(endIdx);
2048 int idx = endIdx + 1;
2049 if (idx >= d->modelCount)
2051 qreal nextPos = d->positionOfIndex(idx);
2052 while ((d->isInBound(nextPos, endPos, 1 + d->mappedCache,
false) || !d->items.size())
2053 && d->items.size() < count + d->cacheSize) {
2054 qCDebug(lcItemViewDelegateLifecycle) <<
"append" << idx <<
"@" << nextPos << (d->currentIndex == idx ?
"current" :
"") <<
"items count was" << d->items.size();
2055 QQuickItem *item = d->getItem(idx, idx+1, nextPos >= 1);
2060 if (d->items.contains(item)) {
2061 d->releaseItem(item);
2064 if (d->currentIndex == idx) {
2065 currentVisible =
true;
2066 d->currentItemOffset = nextPos;
2068 d->items.append(item);
2069 d->updateItem(item, nextPos);
2073 if (idx >= d->modelCount)
2075 nextPos = d->positionOfIndex(idx);
2079 idx = (wasEmpty ? d->calcCurrentIndex() : startIdx) - 1;
2082 idx = d->modelCount - 1;
2083 nextPos = d->positionOfIndex(idx);
2084 while (!waiting && d->isInBound(nextPos, d->mappedRange - d->mappedCache, startPos)
2085 && d->items.size() < count+d->cacheSize) {
2086 qCDebug(lcItemViewDelegateLifecycle) <<
"prepend" << idx <<
"@" << nextPos << (d->currentIndex == idx ?
"current" :
"") <<
"items count was" << d->items.size();
2087 QQuickItem *item = d->getItem(idx, idx+1, nextPos >= 1);
2092 if (d->items.contains(item)) {
2093 d->releaseItem(item);
2096 if (d->currentIndex == idx) {
2097 currentVisible =
true;
2098 d->currentItemOffset = nextPos;
2100 d->items.prepend(item);
2101 d->updateItem(item, nextPos);
2106 idx = d->modelCount - 1;
2107 nextPos = d->positionOfIndex(idx);
2114 if (!waiting && d->items.size() < count+d->cacheSize) {
2115 qCDebug(lcItemViewDelegateLifecycle) <<
"Checking for pathview middle inserts, items count was" << d->items.size();
2117 QQuickItem *lastItem = d->items.at(0);
2118 while (idx != endIdx) {
2119 nextPos = d->positionOfIndex(idx);
2120 if (d->isInBound(nextPos, d->mappedRange - d->mappedCache, 1 + d->mappedCache)) {
2122 QQuickItem *item = d->getItem(idx, idx+1, nextPos >= 1);
2128 if (!d->items.contains(item)) {
2129 qCDebug(lcItemViewDelegateLifecycle) <<
"middle insert" << idx <<
"@" << nextPos
2130 << (d->currentIndex == idx ?
"current" :
"")
2131 <<
"items count was" << d->items.size();
2132 if (d->currentIndex == idx) {
2133 currentVisible =
true;
2134 d->currentItemOffset = nextPos;
2136 int lastListIdx = d->items.indexOf(lastItem);
2137 d->items.insert(lastListIdx + 1, item);
2138 d->updateItem(item, nextPos);
2140 d->releaseItem(item);
2147 if (idx >= d->modelCount)
2154 bool currentChanged =
false;
2155 if (!currentVisible) {
2156 d->currentItemOffset = 1;
2157 if (d->currentItem) {
2158 d->updateItem(d->currentItem, 1);
2159 }
else if (!waiting && d->currentIndex >= 0 && d->currentIndex < d->modelCount) {
2160 if ((d->currentItem = d->getItem(d->currentIndex, d->currentIndex))) {
2161 currentChanged =
true;
2162 d->updateItem(d->currentItem, 1);
2163 if (QQuickPathViewAttached *att = d->attached(d->currentItem))
2164 att->setIsCurrentItem(
true);
2167 }
else if (!waiting && !d->currentItem) {
2168 if ((d->currentItem = d->getItem(d->currentIndex, d->currentIndex))) {
2169 currentChanged =
true;
2170 d->currentItem->setFocus(
true);
2171 if (QQuickPathViewAttached *att = d->attached(d->currentItem))
2172 att->setIsCurrentItem(
true);
2176 if (d->highlightItem && d->haveHighlightRange && d->highlightRangeMode == QQuickPathView::StrictlyEnforceRange) {
2177 d->updateItem(d->highlightItem, d->highlightRangeStart);
2178 if (QQuickPathViewAttached *att = d->attached(d->highlightItem))
2179 att->setOnPath(
true);
2180 }
else if (d->highlightItem && d->moveReason != QQuickPathViewPrivate::SetIndex) {
2181 d->updateItem(d->highlightItem, d->currentItemOffset);
2182 if (QQuickPathViewAttached *att = d->attached(d->highlightItem))
2183 att->setOnPath(currentVisible);
2185 for (QQuickItem *item : std::as_const(d->itemCache))
2186 d->releaseItem(item);
2187 d->itemCache.clear();
2189 d->inRefill =
false;
2191 emit currentItemChanged();
2194void QQuickPathView::modelUpdated(
const QQmlChangeSet &changeSet,
bool reset)
2196 Q_D(QQuickPathView);
2197 if (!d->model || !d->model->isValid() || !d->path || !isComponentComplete())
2201 d->modelCount = d->model->count();
2203 emit countChanged();
2207 if (changeSet.removes().isEmpty() && changeSet.inserts().isEmpty())
2210 const int modelCount = d->modelCount;
2213 bool currentChanged =
false;
2214 bool changedOffset =
false;
2215 for (
const QQmlChangeSet::Change &r : changeSet.removes()) {
2216 if (moveId == -1 && d->currentIndex >= r.index + r.count) {
2217 d->currentIndex -= r.count;
2218 currentChanged =
true;
2219 }
else if (moveId == -1 && d->currentIndex >= r.index && d->currentIndex < r.index + r.count) {
2223 moveOffset = d->currentIndex - r.index;
2224 }
else if (d->currentItem) {
2225 if (QQuickPathViewAttached *att = d->attached(d->currentItem))
2226 att->setIsCurrentItem(
true);
2227 d->releaseCurrentItem();
2229 d->currentIndex = qMin(r.index, d->modelCount - r.count - 1);
2230 currentChanged =
true;
2233 if (r.index > d->currentIndex) {
2234 changedOffset =
true;
2235 d->offset -= r.count;
2236 d->offsetAdj -= r.count;
2238 d->modelCount -= r.count;
2240 for (
const QQmlChangeSet::Change &i : changeSet.inserts()) {
2241 if (d->modelCount) {
2242 if (moveId == -1 && i.index <= d->currentIndex) {
2243 d->currentIndex += i.count;
2244 currentChanged =
true;
2246 if (moveId != -1 && moveId == i.moveId) {
2247 d->currentIndex = i.index + moveOffset;
2248 currentChanged =
true;
2250 if (i.index > d->currentIndex) {
2251 d->offset += i.count;
2252 d->offsetAdj += i.count;
2253 changedOffset =
true;
2257 d->modelCount += i.count;
2260 d->offset = std::fmod(d->offset, qreal(d->modelCount));
2262 d->offset += d->modelCount;
2263 if (d->currentIndex == -1)
2264 d->currentIndex = d->calcCurrentIndex();
2266 d->itemCache += d->items;
2269 if (!d->modelCount) {
2270 for (QQuickItem * item : std::as_const(d->itemCache))
2271 d->releaseItem(item);
2272 d->itemCache.clear();
2274 changedOffset =
true;
2275 d->tl.reset(d->moveOffset);
2277 if (!d->flicking && !d->moving && d->haveHighlightRange && d->highlightRangeMode == QQuickPathView::StrictlyEnforceRange) {
2278 d->offset = std::fmod(qreal(d->modelCount - d->currentIndex), qreal(d->modelCount));
2279 changedOffset =
true;
2281 d->updateMappedRange();
2282 d->scheduleLayout();
2285 emit offsetChanged();
2287 emit currentIndexChanged();
2288 if (d->modelCount != modelCount)
2289 emit countChanged();
2292void QQuickPathView::destroyingItem(QObject *item)
2297void QQuickPathView::ticked()
2299 Q_D(QQuickPathView);
2303void QQuickPathView::movementEnding()
2305 Q_D(QQuickPathView);
2307 d->flicking =
false;
2308 emit flickingChanged();
2311 if (d->moving && !d->stealMouse) {
2313 emit movingChanged();
2314 emit movementEnded();
2316 d->moveDirection = d->movementDirection;
2323 if (modelCount && model && items.size()) {
2324 offset = std::fmod(offset, qreal(modelCount));
2326 offset += modelCount;
2327 current = qRound(qAbs(
std::fmod(modelCount - offset, qreal(
modelCount))));
2339 bool inItems =
false;
2340 for (QQuickItem *item : std::as_const(items)) {
2341 if (model->indexOf(item,
nullptr) == currentIndex) {
2348 if ((currentItem = getItem(currentIndex, currentIndex))) {
2349 currentItem->setFocus(
true);
2354 if ((currentItem = getItem(currentIndex, currentIndex))) {
2355 updateItem(currentItem, 1);
2364 Q_Q(QQuickPathView);
2367 if (!modelCount || !haveHighlightRange || highlightRangeMode != QQuickPathView::StrictlyEnforceRange)
2371 if (model && (idx != currentIndex || !currentItem)) {
2379 currentItem =
nullptr;
2382 emit q->currentIndexChanged();
2383 emit q->currentItemChanged();
2394 Q_Q(QQuickPathView);
2395 if (model && items.size()) {
2396 if (haveHighlightRange && (highlightRangeMode == QQuickPathView::StrictlyEnforceRange
2397 || snapMode != QQuickPathView::NoSnap)) {
2399 if (curr != currentIndex && highlightRangeMode == QQuickPathView::StrictlyEnforceRange)
2400 q->setCurrentIndex(curr);
2409 if (!model || modelCount <= 0)
2412 qreal targetOffset = std::fmod(qreal(modelCount - index), qreal(modelCount));
2415 tl.reset(moveOffset);
2416 moveOffset.setValue(offset);
2421 const qreal averageItemLength = path->path().length() / count;
2422 const qreal threshold = 0.5 / averageItemLength;
2424 if (!duration || qAbs(offset - targetOffset) < threshold || (qFuzzyIsNull(targetOffset) && qAbs(modelCount - offset) < threshold)) {
2425 tl.set(moveOffset, targetOffset);
2426 }
else if (moveDirection == QQuickPathView::Positive || (moveDirection == QQuickPathView::Shortest && targetOffset - offset > modelCount/2)) {
2427 qreal distance = modelCount - targetOffset + offset;
2428 if (targetOffset > moveOffset) {
2429 tl.move(moveOffset, 0, QEasingCurve(QEasingCurve::InQuad),
int(duration * offset / distance));
2430 tl.set(moveOffset, modelCount);
2431 tl.move(moveOffset, targetOffset, QEasingCurve(qFuzzyIsNull(offset) ? QEasingCurve::InOutQuad : QEasingCurve::OutQuad),
int(duration * (modelCount-targetOffset) / distance));
2433 tl.move(moveOffset, targetOffset, QEasingCurve(QEasingCurve::InOutQuad), duration);
2435 }
else if (moveDirection == QQuickPathView::Negative || targetOffset - offset <= -modelCount/2) {
2436 qreal distance = modelCount - offset + targetOffset;
2437 if (targetOffset < moveOffset) {
2438 tl.move(moveOffset, modelCount, QEasingCurve(qFuzzyIsNull(targetOffset) ? QEasingCurve::InOutQuad : QEasingCurve::InQuad),
int(duration * (modelCount-offset) / distance));
2439 tl.set(moveOffset, 0);
2440 tl.move(moveOffset, targetOffset, QEasingCurve(QEasingCurve::OutQuad),
int(duration * targetOffset / distance));
2442 tl.move(moveOffset, targetOffset, QEasingCurve(QEasingCurve::InOutQuad), duration);
2445 tl.move(moveOffset, targetOffset, QEasingCurve(QEasingCurve::InOutQuad), duration);
2449QQuickPathViewAttached *QQuickPathView::qmlAttachedProperties(QObject *obj)
2451 return new QQuickPathViewAttached(obj);
2456#include "moc_qquickpathview_p.cpp"
void setIsCurrentItem(bool c)
void setValue(const QByteArray &name, const QVariant &val)
QVariant value(const QByteArray &name) const
~QQuickPathViewAttached()
void releaseItem(QQuickItem *item)
qint64 computeCurrentTime(QInputEvent *event) const
void updateItem(QQuickItem *, qreal)
void snapToIndex(int index, MovementReason reason)
void handleMousePressEvent(QMouseEvent *event)
QQmlOpenMetaObjectType * attType
QQuickItem * highlightItem
void handleMouseReleaseEvent(QMouseEvent *)
void releaseCurrentItem()
QQmlComponent * highlightComponent
void setAdjustedOffset(qreal offset)
int highlightMoveDuration
void setHighlightPosition(qreal pos)
void handleMouseMoveEvent(QMouseEvent *event)
QPointF pointNear(const QPointF &point, qreal *nearPercent=0) const
void setOffset(qreal offset)
QQmlOpenMetaObjectType * attachedType()
qreal positionOfIndex(qreal index) const
QQuickItem * getItem(int modelIndex, qreal z=0, bool async=false)
void addVelocitySample(qreal v)
qreal calcVelocity() const
QQuickPathViewAttached * attached(QQuickItem *item)
bool isInBound(qreal position, qreal lower, qreal upper, bool emptyRangeCheck=true) const
static void fixOffsetCallback(void *)
MovementReason moveReason
QT_BEGIN_NAMESPACE Q_STATIC_LOGGING_CATEGORY(lcSynthesizedIterableAccess, "qt.iterable.synthesized", QtWarningMsg)
#define QML_FLICK_SAMPLEBUFFER
#define QML_FLICK_DISCARDSAMPLES
#define QML_FLICK_VELOCITY_DECAY_TIME
static QT_BEGIN_NAMESPACE QQmlOpenMetaObjectType * qPathViewAttachedType
static int currentIndexRemainder(int currentIndex, int modelCount) noexcept