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)
85 setSizePolicy(QLayoutPolicy::Preferred, QLayoutPolicy::Preferred);
92 q->setAcceptedMouseButtons(Qt::LeftButton);
93 q->setFlag(QQuickItem::ItemIsFocusScope);
94 q->setFiltersChildMouseEvents(
true);
95 qmlobject_connect(&tl, QQuickTimeLine, SIGNAL(updated()),
96 q, QQuickPathView, SLOT(ticked()));
98 qmlobject_connect(&tl, QQuickTimeLine, SIGNAL(completed()),
99 q, QQuickPathView, SLOT(movementEnding()));
108 QObject *object = model->object(modelIndex, async ? QQmlIncubator::Asynchronous : QQmlIncubator::AsynchronousIfNested);
109 QQuickItem *item = qmlobject_cast<QQuickItem*>(object);
112 model->release(object);
115 QObject* delegate = q->delegate();
116 qmlWarning(delegate ? delegate : q) << QQuickPathView::tr(
"Delegate must be of Item type");
120 item->setParentItem(q);
122 QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
123 itemPrivate->addItemChangeListener(
124 this, QQuickItemPrivate::Geometry | QQuickItemPrivate::Destroyed);
130void QQuickPathView::createdItem(
int index, QObject *object)
133 QQuickItem *item = qmlobject_cast<QQuickItem*>(object);
134 if (d->requestedIndex != index) {
135 qPathViewAttachedType = d->attachedType();
136 QQuickPathViewAttached *att =
static_cast<QQuickPathViewAttached *>(qmlAttachedPropertiesObject<QQuickPathView>(item));
137 qPathViewAttachedType =
nullptr;
140 att->setOnPath(
false);
142 item->setParentItem(
this);
143 d->updateItem(item, 1);
145 d->requestedIndex = -1;
151void QQuickPathView::initItem(
int index, QObject *object)
154 QQuickItem *item = qmlobject_cast<QQuickItem*>(object);
155 if (item && d->requestedIndex == index) {
156 QQuickItemPrivate::get(item)->setCulled(
true);
157 item->setParentItem(
this);
158 qPathViewAttachedType = d->attachedType();
159 QQuickPathViewAttached *att =
static_cast<QQuickPathViewAttached *>(qmlAttachedPropertiesObject<QQuickPathView>(item));
160 qPathViewAttachedType =
nullptr;
163 qreal percent = d->positionOfIndex(index);
164 if (percent < 1 && d->path) {
165 const auto attributes = d->path->attributes();
166 for (
const QString &attr : attributes)
167 att->setValue(attr.toUtf8(), d->path->attributeAt(attr, percent));
168 item->setZ(d->requestedZ);
170 att->setOnPath(percent < 1);
179 qCDebug(lcItemViewDelegateLifecycle) <<
"release" << item;
180 QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
181 itemPrivate->removeItemChangeListener(
182 this, QQuickItemPrivate::Geometry | QQuickItemPrivate::Destroyed);
185 QQmlInstanceModel::ReleaseFlags flags = model->release(item);
190 }
else if (flags & QQmlInstanceModel::Destroyed) {
192 item->setParentItem(
nullptr);
198 return static_cast<QQuickPathViewAttached *>(qmlAttachedPropertiesObject<QQuickPathView>(item,
false));
205 attType =
new QQmlOpenMetaObjectType(&QQuickPathViewAttached::staticMetaObject);
207 const auto attributes = path->attributes();
208 for (
const QString &attr : attributes)
209 attType->createProperty(attr.toUtf8());
220 for (QQuickItem *p : std::as_const(items))
223 for (QQuickItem *p : std::as_const(itemCache))
228 model->cancel(requestedIndex);
243 if (model && pathItems != -1 && pathItems < modelCount) {
244 mappedRange = qreal(modelCount)/pathItems;
245 mappedCache = qreal(cacheSize)/pathItems/2;
256 if (model && index >= 0 && index < modelCount) {
258 if (haveHighlightRange && (highlightRangeMode != QQuickPathView::NoHighlightRange
259 || snapMode != QQuickPathView::NoSnap))
260 start = highlightRangeStart;
261 qreal globalPos = index + offset;
262 globalPos = std::fmod(globalPos, qreal(modelCount)) / modelCount;
264 globalPos += start / mappedRange;
265 globalPos = std::fmod(globalPos, qreal(1));
266 pos = globalPos * mappedRange;
268 pos = std::fmod(globalPos + start, qreal(1));
278 qreal upper,
bool emptyRangeCheck)
const
280 if (emptyRangeCheck && qFuzzyCompare(lower, upper))
283 if (position > upper && position > lower)
284 position -= mappedRange;
285 lower -= mappedRange;
287 return position >= lower && position < upper;
293 if (!q->isComponentComplete())
296 bool changed =
false;
304 QQuickItem *item =
nullptr;
307 QQmlContext *highlightContext =
new QQmlContext(
308 creationContext ? creationContext : qmlContext(q));
311 QQml_setParent_noEvent(highlightContext, nobj);
312 item = qobject_cast<QQuickItem *>(nobj);
316 delete highlightContext;
319 item =
new QQuickItem;
322 QQml_setParent_noEvent(item, q);
323 item->setParentItem(q);
328 emit q->highlightItemChanged();
334 if (!q->isComponentComplete() || !isValid())
337 if (haveHighlightRange && highlightRangeMode == QQuickPathView::StrictlyEnforceRange) {
338 updateItem(highlightItem, highlightRangeStart);
340 qreal target = currentIndex;
343 tl.reset(moveHighlight);
344 moveHighlight.setValue(highlightPosition);
348 if (target - highlightPosition > modelCount/2) {
350 qreal distance = modelCount - target + highlightPosition;
351 tl.move(moveHighlight, 0, QEasingCurve(QEasingCurve::InQuad),
int(duration * highlightPosition / distance));
352 tl.set(moveHighlight, modelCount-0.01);
353 tl.move(moveHighlight, target, QEasingCurve(QEasingCurve::OutQuad),
int(duration * (modelCount-target) / distance));
354 }
else if (target - highlightPosition <= -modelCount/2) {
356 qreal distance = modelCount - highlightPosition + target;
357 tl.move(moveHighlight, modelCount-0.01, QEasingCurve(QEasingCurve::InQuad),
int(duration * (modelCount-highlightPosition) / distance));
358 tl.set(moveHighlight, 0);
359 tl.move(moveHighlight, target, QEasingCurve(QEasingCurve::OutQuad),
int(duration * target / distance));
361 highlightUp = highlightPosition - target < 0;
362 tl.move(moveHighlight, target, QEasingCurve(QEasingCurve::InOutQuad), duration);
370 if (!(qFuzzyCompare(pos, highlightPosition))) {
373 if (haveHighlightRange && highlightRangeMode != QQuickPathView::NoHighlightRange) {
374 start = highlightRangeStart;
375 end = highlightRangeEnd;
378 qreal range = qreal(modelCount);
380 qreal relativeHighlight = std::fmod(pos + offset, range) / range;
382 if (!highlightUp && relativeHighlight > end / mappedRange) {
383 qreal diff = 1 - relativeHighlight;
384 setOffset(offset + diff * range);
385 }
else if (highlightUp && relativeHighlight >= (end - start) / mappedRange) {
386 qreal diff = relativeHighlight - (end - start) / mappedRange;
387 setOffset(offset - diff * range - 0.00001);
390 highlightPosition = pos;
391 qreal pathPos = positionOfIndex(pos);
392 updateItem(highlightItem, pathPos);
398void QQuickPathView::pathUpdated()
401 for (QQuickItem *item : std::as_const(d->items)) {
402 if (QQuickPathViewAttached *att = d->attached(item))
413 if (qFuzzyCompare(att->m_percent, percent))
415 att->m_percent = percent;
416 const auto attributes = path->attributes();
417 for (
const QString &attr : attributes)
418 att->setValue(attr.toUtf8(), path->attributeAt(attr, percent));
421 QQuickItemPrivate::get(item)->setCulled(percent >= 1);
422 QPointF pf = path->pointAtPercent(qMin(percent, qreal(1)));
423 item->setX(pf.x() - item->width()/2);
424 item->setY(pf.y() - item->height()/2);
430 if (!q->isComponentComplete())
450 emit q->dragStarted();
454 emit q->draggingChanged();
458
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
524QQuickPathView::QQuickPathView(QQuickItem *parent)
525 : QQuickItem(*(
new QQuickPathViewPrivate), parent)
531QQuickPathView::~QQuickPathView()
536 d->attType->release();
542
543
544
545
546
547
548
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
573
574
575
576
577
578
579
580
581
582
583
586
587
588
589
590
591
592
593
594
595
596
597QVariant QQuickPathView::model()
const
599 Q_D(
const QQuickPathView);
600 return d->modelVariant;
603void QQuickPathView::setModel(
const QVariant &m)
607 if (model.userType() == qMetaTypeId<QJSValue>())
608 model = model.value<QJSValue>().toVariant();
610 if (d->modelVariant == model)
614 qmlobject_disconnect(d->model, QQmlInstanceModel, SIGNAL(modelUpdated(QQmlChangeSet,
bool)),
615 this, QQuickPathView, SLOT(modelUpdated(QQmlChangeSet,
bool)));
616 qmlobject_disconnect(d->model, QQmlInstanceModel, SIGNAL(createdItem(
int,QObject*)),
617 this, QQuickPathView, SLOT(createdItem(
int,QObject*)));
618 qmlobject_disconnect(d->model, QQmlInstanceModel, SIGNAL(initItem(
int,QObject*)),
619 this, QQuickPathView, SLOT(initItem(
int,QObject*)));
623 d->modelVariant = model;
624 QObject *object = qvariant_cast<QObject*>(model);
625 QQmlInstanceModel *vim =
nullptr;
626 if (object && (vim = qobject_cast<QQmlInstanceModel *>(object))) {
634 d->model =
new QQmlDelegateModel(qmlContext(
this));
636 if (isComponentComplete())
637 static_cast<QQmlDelegateModel *>(d->model.data())->componentComplete();
639 if (QQmlDelegateModel *dataModel = qobject_cast<QQmlDelegateModel*>(d->model))
640 dataModel->setModel(model);
642 int oldModelCount = d->modelCount;
645 qmlobject_connect(d->model, QQmlInstanceModel, SIGNAL(modelUpdated(QQmlChangeSet,
bool)),
646 this, QQuickPathView, SLOT(modelUpdated(QQmlChangeSet,
bool)));
647 qmlobject_connect(d->model, QQmlInstanceModel, SIGNAL(createdItem(
int,QObject*)),
648 this, QQuickPathView, SLOT(createdItem(
int,QObject*)));
649 qmlobject_connect(d->model, QQmlInstanceModel, SIGNAL(initItem(
int,QObject*)),
650 this, QQuickPathView, SLOT(initItem(
int,QObject*)));
651 d->modelCount = d->model->count();
653 if (isComponentComplete()) {
654 if (d->currentIndex != 0) {
656 emit currentIndexChanged();
658 if (!(qFuzzyIsNull(d->offset))) {
660 emit offsetChanged();
664 if (d->modelCount != oldModelCount)
670
671
672
673int QQuickPathView::count()
const
675 Q_D(
const QQuickPathView);
676 return d->model ? d->modelCount : 0;
680
681
682
683
684QQuickPath *QQuickPathView::path()
const
686 Q_D(
const QQuickPathView);
690void QQuickPathView::setPath(QQuickPath *path)
696 qmlobject_disconnect(d->path, QQuickPath, SIGNAL(changed()),
697 this, QQuickPathView, SLOT(pathUpdated()));
701 qmlobject_connect(d->path, QQuickPath, SIGNAL(changed()),
702 this, QQuickPathView, SLOT(pathUpdated()));
705 if (isComponentComplete()) {
709 d->attType->release();
710 d->attType =
nullptr;
720
721
722
723int QQuickPathView::currentIndex()
const
725 Q_D(
const QQuickPathView);
726 return d->currentIndex;
729void QQuickPathView::setCurrentIndex(
int idx)
732 if (!isComponentComplete()) {
733 if (idx != d->currentIndex) {
734 d->currentIndex = idx;
735 emit currentIndexChanged();
741 ? ((idx % d->modelCount) + d->modelCount) % d->modelCount
743 if (d->model && (idx != d->currentIndex || !d->currentItem)) {
744 const bool hadCurrentItem = d->currentItem !=
nullptr;
745 const int oldCurrentIdx = d->currentIndex;
746 if (hadCurrentItem) {
747 if (QQuickPathViewAttached *att = d->attached(d->currentItem))
748 att->setIsCurrentItem(
false);
749 d->releaseCurrentItem();
751 d->moveReason = QQuickPathViewPrivate::SetIndex;
752 d->currentIndex = idx;
754 d->createCurrentItem();
755 if (d->haveHighlightRange && d->highlightRangeMode == QQuickPathView::StrictlyEnforceRange)
756 d->snapToIndex(d->currentIndex, QQuickPathViewPrivate::SetIndex);
757 d->currentItemOffset = d->positionOfIndex(d->currentIndex);
758 d->updateHighlight();
760 if (oldCurrentIdx != d->currentIndex)
761 emit currentIndexChanged();
763 emit currentItemChanged();
768
769
770
771QQuickItem *QQuickPathView::currentItem()
const
773 Q_D(
const QQuickPathView);
774 return d->currentItem;
778
779
780
781
782
783
784void QQuickPathView::incrementCurrentIndex()
787 d->moveDirection = QQuickPathView::Positive;
788 setCurrentIndex(currentIndex()+1);
792
793
794
795
796
797
798void QQuickPathView::decrementCurrentIndex()
801 d->moveDirection = QQuickPathView::Negative;
802 setCurrentIndex(currentIndex()-1);
806
807
808
809
810
811qreal QQuickPathView::offset()
const
813 Q_D(
const QQuickPathView);
817void QQuickPathView::setOffset(qreal offset)
820 d->moveReason = QQuickPathViewPrivate::Other;
821 d->setOffset(offset);
828 if (!qFuzzyCompare(offset, o)) {
829 if (isValid() && q->isComponentComplete()) {
830 qreal oldOffset = offset;
831 offset = std::fmod(o, qreal(modelCount));
833 offset += qreal(modelCount);
834 qCDebug(lcItemViewDelegateLifecycle) << o <<
"was" << oldOffset <<
"now" << offset;
839 emit q->offsetChanged();
845 setOffset(o+offsetAdj);
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871QQmlComponent *QQuickPathView::highlight()
const
873 Q_D(
const QQuickPathView);
874 return d->highlightComponent;
877void QQuickPathView::setHighlight(QQmlComponent *highlight)
880 if (highlight != d->highlightComponent) {
881 d->highlightComponent = highlight;
882 d->createHighlight();
883 d->updateHighlight();
884 emit highlightChanged();
889
890
891
892
893
894
895
896QQuickItem *QQuickPathView::highlightItem()
const
898 Q_D(
const QQuickPathView);
899 return d->highlightItem;
903
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
938qreal QQuickPathView::preferredHighlightBegin()
const
940 Q_D(
const QQuickPathView);
941 return d->highlightRangeStart;
944void QQuickPathView::setPreferredHighlightBegin(qreal start)
947 if (qFuzzyCompare(d->highlightRangeStart, start) || start < 0 || start > 1)
949 d->highlightRangeStart = start;
950 d->haveHighlightRange = d->highlightRangeStart <= d->highlightRangeEnd;
952 emit preferredHighlightBeginChanged();
955qreal QQuickPathView::preferredHighlightEnd()
const
957 Q_D(
const QQuickPathView);
958 return d->highlightRangeEnd;
961void QQuickPathView::setPreferredHighlightEnd(qreal end)
964 if (qFuzzyCompare(d->highlightRangeEnd, end) || end < 0 || end > 1)
966 d->highlightRangeEnd = end;
967 d->haveHighlightRange = d->highlightRangeStart <= d->highlightRangeEnd;
969 emit preferredHighlightEndChanged();
972QQuickPathView::HighlightRangeMode QQuickPathView::highlightRangeMode()
const
974 Q_D(
const QQuickPathView);
975 return d->highlightRangeMode;
978void QQuickPathView::setHighlightRangeMode(HighlightRangeMode mode)
981 if (d->highlightRangeMode == mode)
983 d->highlightRangeMode = mode;
984 d->haveHighlightRange = d->highlightRangeStart <= d->highlightRangeEnd;
985 if (d->haveHighlightRange) {
987 int index = d->highlightRangeMode != NoHighlightRange ? d->currentIndex : d->calcCurrentIndex();
989 d->snapToIndex(index, QQuickPathViewPrivate::Other);
991 emit highlightRangeModeChanged();
995
996
997
998
999
1000
1001
1002
1003int QQuickPathView::highlightMoveDuration()
const
1005 Q_D(
const QQuickPathView);
1006 return d->highlightMoveDuration;
1009void QQuickPathView::setHighlightMoveDuration(
int duration)
1011 Q_D(QQuickPathView);
1012 if (d->highlightMoveDuration == duration)
1014 d->highlightMoveDuration = duration;
1015 emit highlightMoveDurationChanged();
1019
1020
1021
1022
1023
1024
1025
1026qreal QQuickPathView::dragMargin()
const
1028 Q_D(
const QQuickPathView);
1029 return d->dragMargin;
1032void QQuickPathView::setDragMargin(qreal dragMargin)
1034 Q_D(QQuickPathView);
1035 if (qFuzzyCompare(d->dragMargin, dragMargin))
1037 d->dragMargin = dragMargin;
1038 emit dragMarginChanged();
1042
1043
1044
1045
1046
1047qreal QQuickPathView::flickDeceleration()
const
1049 Q_D(
const QQuickPathView);
1050 return d->deceleration;
1053void QQuickPathView::setFlickDeceleration(qreal dec)
1055 Q_D(QQuickPathView);
1056 if (qFuzzyCompare(d->deceleration, dec))
1058 d->deceleration = dec;
1059 emit flickDecelerationChanged();
1063
1064
1065
1066
1067
1068qreal QQuickPathView::maximumFlickVelocity()
const
1070 Q_D(
const QQuickPathView);
1071 return d->maximumFlickVelocity;
1074void QQuickPathView::setMaximumFlickVelocity(qreal vel)
1076 Q_D(QQuickPathView);
1077 if (qFuzzyCompare(vel, d->maximumFlickVelocity))
1079 d->maximumFlickVelocity = vel;
1080 emit maximumFlickVelocityChanged();
1085
1086
1087
1088
1089
1090
1091
1092bool QQuickPathView::isInteractive()
const
1094 Q_D(
const QQuickPathView);
1095 return d->interactive;
1098void QQuickPathView::setInteractive(
bool interactive)
1100 Q_D(QQuickPathView);
1101 if (interactive != d->interactive) {
1102 d->interactive = interactive;
1105 emit interactiveChanged();
1110
1111
1112
1113
1114
1115bool QQuickPathView::isMoving()
const
1117 Q_D(
const QQuickPathView);
1122
1123
1124
1125
1126
1127bool QQuickPathView::isFlicking()
const
1129 Q_D(
const QQuickPathView);
1134
1135
1136
1137
1138
1139bool QQuickPathView::isDragging()
const
1141 Q_D(
const QQuickPathView);
1146
1147
1148
1149
1150
1153
1154
1155
1156
1157
1158
1159
1160
1163
1164
1165
1166
1167
1168
1171
1172
1173
1174
1177
1178
1179
1180
1181
1184
1185
1186
1187
1188
1189
1190
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210QQmlComponent *QQuickPathView::delegate()
const
1212 Q_D(
const QQuickPathView);
1214 if (QQmlDelegateModel *dataModel = qobject_cast<QQmlDelegateModel*>(d->model))
1215 return dataModel->delegate();
1221void QQuickPathView::setDelegate(QQmlComponent *delegate)
1223 Q_D(QQuickPathView);
1224 if (delegate ==
this->delegate())
1227 d->model =
new QQmlDelegateModel(qmlContext(
this));
1229 if (isComponentComplete())
1230 static_cast<QQmlDelegateModel *>(d->model.data())->componentComplete();
1232 if (QQmlDelegateModel *dataModel = qobject_cast<QQmlDelegateModel*>(d->model)) {
1233 int oldCount = dataModel->count();
1234 dataModel->setDelegate(delegate);
1235 d->modelCount = dataModel->count();
1237 if (oldCount != dataModel->count())
1238 emit countChanged();
1239 emit delegateChanged();
1240 d->delegateValidated =
false;
1245
1246
1247
1248
1249
1250int QQuickPathView::pathItemCount()
const
1252 Q_D(
const QQuickPathView);
1253 return d->pathItems;
1256void QQuickPathView::setPathItemCount(
int i)
1258 Q_D(QQuickPathView);
1259 if (i == d->pathItems)
1264 d->updateMappedRange();
1265 if (d->isValid() && isComponentComplete()) {
1268 emit pathItemCountChanged();
1271void QQuickPathView::resetPathItemCount()
1273 Q_D(QQuickPathView);
1274 if (-1 == d->pathItems)
1277 d->updateMappedRange();
1278 if (d->isValid() && isComponentComplete())
1280 emit pathItemCountChanged();
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304int QQuickPathView::cacheItemCount()
const
1306 Q_D(
const QQuickPathView);
1307 return d->requestedCacheSize;
1310void QQuickPathView::setCacheItemCount(
int i)
1312 Q_D(QQuickPathView);
1313 if (i == d->requestedCacheSize || i < 0)
1316 d->requestedCacheSize = i;
1317 d->updateMappedRange();
1319 emit cacheItemCountChanged();
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340QQuickPathView::SnapMode QQuickPathView::snapMode()
const
1342 Q_D(
const QQuickPathView);
1346void QQuickPathView::setSnapMode(SnapMode mode)
1348 Q_D(QQuickPathView);
1349 if (mode == d->snapMode)
1352 emit snapModeChanged();
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378QQuickPathView::MovementDirection QQuickPathView::movementDirection()
const
1380 Q_D(
const QQuickPathView);
1381 return d->movementDirection;
1384void QQuickPathView::setMovementDirection(QQuickPathView::MovementDirection dir)
1386 Q_D(QQuickPathView);
1387 if (dir == d->movementDirection)
1389 d->movementDirection = dir;
1390 if (!d->tl.isActive())
1391 d->moveDirection = d->movementDirection;
1392 emit movementDirectionChanged();
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417void QQuickPathView::positionViewAtIndex(
int index,
int mode)
1419 Q_D(QQuickPathView);
1422 if (mode < QQuickPathView::Beginning || mode > QQuickPathView::SnapPosition || mode == 3)
1425 if (mode == QQuickPathView::Contain && (d->pathItems < 0 || d->modelCount <= d->pathItems))
1428 int count = d->pathItems == -1 ? d->modelCount : qMin(d->pathItems, d->modelCount);
1429 int idx = (index+d->modelCount) % d->modelCount;
1430 bool snap = d->haveHighlightRange && (d->highlightRangeMode != QQuickPathView::NoHighlightRange
1431 || d->snapMode != QQuickPathView::NoSnap);
1436 beginOffset = d->modelCount - idx - qFloor(count * d->highlightRangeStart);
1437 endOffset = beginOffset + count - 1;
1439 beginOffset = d->modelCount - idx;
1442 qreal adj =
sizeof(qreal) ==
sizeof(
float) ? 0.00001f : 0.000000000001;
1443 endOffset = std::fmod(beginOffset + count, qreal(d->modelCount)) - adj;
1445 qreal offset = d->offset;
1448 offset = beginOffset;
1454 if (beginOffset < endOffset)
1455 offset = (beginOffset + endOffset)/2;
1457 offset = (beginOffset + (endOffset + d->modelCount))/2;
1459 offset = qRound(offset);
1462 if ((beginOffset < endOffset && (d->offset < beginOffset || d->offset > endOffset))
1463 || (d->offset < beginOffset && d->offset > endOffset)) {
1464 qreal diff1 = std::fmod(beginOffset - d->offset + d->modelCount, qreal(d->modelCount));
1465 qreal diff2 = std::fmod(d->offset - endOffset + d->modelCount, qreal(d->modelCount));
1467 offset = beginOffset;
1473 offset = d->modelCount - idx;
1482
1483
1484
1485
1486
1487
1488
1489int QQuickPathView::indexAt(qreal x, qreal y)
const
1491 Q_D(
const QQuickPathView);
1492 QQuickItem *item = itemAt(x, y);
1493 return item ? d->model->indexOf(item,
nullptr) : -1;
1497
1498
1499
1500
1501
1502
1503
1504QQuickItem *QQuickPathView::itemAt(qreal x, qreal y)
const
1506 Q_D(
const QQuickPathView);
1510 for (QQuickItem *item : d->items) {
1511 QPointF p = item->mapFromItem(
this, QPointF(x, y));
1512 if (item->contains(p))
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532QQuickItem *QQuickPathView::itemAtIndex(
int index)
const
1534 Q_D(
const QQuickPathView);
1538 for (QQuickItem *item : d->items) {
1539 if (index == d->model->indexOf(item,
nullptr))
1547
1548
1549
1550
1551
1552
1553
1556 const auto pathLength = path->path().length();
1557 qreal samples = qMin(pathLength / 5, qreal(500));
1558 qreal res = pathLength / samples;
1560 qreal mindist = 1e10;
1561 QPointF nearPoint = path->pointAtPercent(0);
1565 for (qreal i=1; i < samples; i++) {
1566 QPointF pt = path->pointAtPercent(i/samples);
1567 QPointF diff = pt - point;
1568 qreal dist = diff.x()*diff.x() + diff.y()*diff.y();
1569 if (dist < mindist) {
1577 qreal approxPc = nearPc;
1578 for (qreal i = approxPc-1; i < approxPc+1; i += 1/(2*res)) {
1579 QPointF pt = path->pointAtPercent(i/samples);
1580 QPointF diff = pt - point;
1581 qreal dist = diff.x()*diff.x() + diff.y()*diff.y();
1582 if (dist < mindist) {
1590 *nearPercent = nearPc / samples;
1597 velocityBuffer.append(v);
1599 velocityBuffer.remove(0);
1600 qCDebug(lcPathView) <<
"instantaneous velocity" << v;
1608 for (
int i = 0; i < count; ++i) {
1609 qreal v = velocityBuffer.at(i);
1613 qCDebug(lcPathView) <<
"average velocity" << velocity <<
"based on" << count <<
"samples";
1620 if (0 != event->timestamp())
1621 return qint64(event->timestamp());
1622 return timer.elapsed();
1625void QQuickPathView::mousePressEvent(QMouseEvent *event)
1627 Q_D(QQuickPathView);
1628 if (d->interactive) {
1629 d->handleMousePressEvent(event);
1632 QQuickItem::mousePressEvent(event);
1638 Q_Q(QQuickPathView);
1639 if (!interactive || !items.size() || !model || !modelCount)
1641 velocityBuffer.clear();
1643 for (; idx < items.size(); ++idx) {
1644 QQuickItem *item = items.at(idx);
1645 if (item->contains(item->mapFromScene(event->scenePosition())))
1648 if (idx == items.size() && qFuzzyIsNull(dragMargin))
1651 startPoint = pointNear(event->position(), &startPc);
1652 startPos = event->position();
1653 if (idx == items.size()) {
1654 qreal distance = qAbs(event->position().x() - startPoint.x()) + qAbs(event->position().y() - startPoint.y());
1655 if (distance > dragMargin)
1659 if (tl.isActive() && flicking && flickDuration && qreal(tl.time()) / flickDuration < 0.8) {
1665 q->setKeepMouseGrab(stealMouse);
1668 lastPosTime = computeCurrentTime(event);
1672void QQuickPathView::mouseMoveEvent(QMouseEvent *event)
1674 Q_D(QQuickPathView);
1675 if (d->interactive) {
1676 d->handleMouseMoveEvent(event);
1679 QQuickItem::mouseMoveEvent(event);
1685 Q_Q(QQuickPathView);
1686 if (!interactive || !timer.isValid() || !model || !modelCount)
1689 qint64 currentTimestamp = computeCurrentTime(event);
1691 QPointF pathPoint = pointNear(event->position(), &newPc);
1693 QPointF posDelta = event->position() - startPos;
1694 if (QQuickDeliveryAgentPrivate::dragOverThreshold(posDelta.y(), Qt::YAxis, event) ||
1695 QQuickDeliveryAgentPrivate::dragOverThreshold(posDelta.x(), Qt::XAxis, event)) {
1699 QPointF pathDelta = pathPoint - startPoint;
1700 const int startDragDistance = QGuiApplication::styleHints()->startDragDistance();
1701 if (qAbs(pathDelta.x()) > startDragDistance * 0.8
1702 || qAbs(pathDelta.y()) > startDragDistance * 0.8) {
1704 q->setKeepMouseGrab(
true);
1710 qreal diff = (newPc - startPc)*count;
1711 if (!qFuzzyIsNull(diff)) {
1712 q->setOffset(offset + diff);
1714 if (diff > modelCount/2)
1716 else if (diff < -modelCount/2)
1719 qint64 elapsed = currentTimestamp - lastPosTime;
1721 addVelocitySample(diff / (qreal(elapsed) / 1000));
1725 emit q->movingChanged();
1726 emit q->movementStarted();
1731 lastPosTime = currentTimestamp;
1734void QQuickPathView::mouseReleaseEvent(QMouseEvent *event)
1736 Q_D(QQuickPathView);
1737 if (d->interactive) {
1738 d->handleMouseReleaseEvent(event);
1742 QQuickItem::mouseReleaseEvent(event);
1748 Q_Q(QQuickPathView);
1750 q->setKeepMouseGrab(
false);
1752 if (!interactive || !timer.isValid() || !model || !modelCount) {
1755 q->movementEnding();
1759 qreal velocity = calcVelocity();
1760 qint64 elapsed = computeCurrentTime(event) - lastPosTime;
1765 qCDebug(lcPathView) <<
"after elapsed time" << elapsed <<
"velocity decayed to" << velocity;
1766 qreal count = pathItems == -1 ? modelCount : qMin(pathItems, modelCount);
1767 const auto averageItemLength = path->path().length() / count;
1768 qreal pixelVelocity = averageItemLength * velocity;
1769 if (qAbs(pixelVelocity) > _q_MinimumFlickVelocity) {
1770 if (qAbs(pixelVelocity) > maximumFlickVelocity || snapMode == QQuickPathView::SnapOneItem) {
1772 qreal maxVel = velocity < 0 ? -maximumFlickVelocity : maximumFlickVelocity;
1773 velocity = maxVel / averageItemLength;
1776 qreal v2 = velocity*velocity;
1777 qreal accel = deceleration/10;
1779 if (haveHighlightRange && (highlightRangeMode == QQuickPathView::StrictlyEnforceRange
1780 || snapMode != QQuickPathView::NoSnap)) {
1781 if (snapMode == QQuickPathView::SnapOneItem) {
1784 dist = qRound(0.5 + offset) - offset;
1786 dist = qRound(0.5 - offset) + offset;
1789 dist = qMin(qreal(modelCount-1), qreal(v2 / (accel * 2) + 0.25));
1793 dist = qRound(dist + offset) - offset;
1795 dist = qRound(dist - offset) + offset;
1802 accel = v2 / (2 * qAbs(dist));
1805 dist = qMin(qreal(modelCount-1), qreal(v2 / (accel * 2)));
1807 flickDuration =
int(1000 * qAbs(velocity) / accel);
1809 moveOffset.setValue(offset);
1810 tl.accel(moveOffset, velocity, accel, dist);
1811 tl.callback(QQuickTimeLineCallback(&moveOffset, fixOffsetCallback,
this));
1814 emit q->flickingChanged();
1815 emit q->flickStarted();
1823 q->movementEnding();
1826bool QQuickPathView::childMouseEventFilter(QQuickItem *i, QEvent *e)
1828 Q_D(QQuickPathView);
1829 if (!isVisible() || !d->interactive || !e->isPointerEvent())
1830 return QQuickItem::childMouseEventFilter(i, e);
1832 QPointerEvent *pe =
static_cast<QPointerEvent *>(e);
1833 if (QQuickDeliveryAgentPrivate::isMouseEvent(pe)) {
1836 const auto &point = pe->points().first();
1837 QPointF localPos = mapFromScene(point.scenePosition());
1838 QObject *grabber = pe->exclusiveGrabber(point);
1839 QQuickPointerHandler *grabberHandler = qmlobject_cast<QQuickPointerHandler *>(grabber);
1840 QQuickItem *grabberItem = grabberHandler ? grabberHandler->parentItem() : qmlobject_cast<QQuickItem *>(grabber);
1841 if (grabberItem ==
this && d->stealMouse) {
1846 bool grabberDisabled = (grabberItem && !grabberItem->isEnabled()) || (grabberHandler && !grabberHandler->enabled());
1847 bool stealThisEvent = d->stealMouse;
1848 const bool mouseFromTouch = pe->pointingDevice()->type() == QPointingDevice::DeviceType::TouchScreen;
1849 if ((stealThisEvent || contains(localPos)) && (!grabberItem ||
1850 (!grabberItem->keepMouseGrab() && (!mouseFromTouch || !grabberItem->keepTouchGrab())) || grabberDisabled)) {
1852 QMutableSinglePointEvent localizedEvent(*
static_cast<QMouseEvent *>(pe));
1853 QMutableEventPoint::setPosition(localizedEvent.point(0), localPos);
1854 localizedEvent.setAccepted(
false);
1856 switch (localizedEvent.type()) {
1857 case QEvent::MouseMove:
1858 d->handleMouseMoveEvent(
static_cast<QMouseEvent *>(
static_cast<QSinglePointEvent *>(&localizedEvent)));
1860 case QEvent::MouseButtonPress:
1861 d->handleMousePressEvent(
static_cast<QMouseEvent *>(
static_cast<QSinglePointEvent *>(&localizedEvent)));
1862 stealThisEvent = d->stealMouse;
1864 case QEvent::MouseButtonRelease:
1865 d->handleMouseReleaseEvent(
static_cast<QMouseEvent *>(
static_cast<QSinglePointEvent *>(&localizedEvent)));
1871 grabber = localizedEvent.exclusiveGrabber(localizedEvent.points().first());
1872 grabberHandler = qmlobject_cast<QQuickPointerHandler *>(grabber);
1873 grabberItem = grabberHandler ? grabberHandler->parentItem() : qmlobject_cast<QQuickItem *>(grabber);
1874 grabberDisabled = (grabberItem && !grabberItem->isEnabled()) || (grabberHandler && !grabberHandler->enabled());
1875 if ((grabberItem && stealThisEvent && !grabberItem->keepMouseGrab() && grabber !=
this) || grabberDisabled)
1876 pe->setExclusiveGrabber(point,
this);
1878 const bool filtered = stealThisEvent || grabberDisabled;
1880 pe->setAccepted(stealThisEvent && grabberItem ==
this && !grabberDisabled);
1883 }
else if (d->timer.isValid()) {
1884 d->timer.invalidate();
1887 if (pe->type() == QEvent::MouseButtonRelease || (grabberItem && grabberItem->keepMouseGrab() && !grabberDisabled))
1888 d->stealMouse =
false;
1892 return QQuickItem::childMouseEventFilter(i, e);
1895void QQuickPathView::mouseUngrabEvent()
1897 Q_D(QQuickPathView);
1898 if (d->stealMouse ||
1899 (!d->flicking && d->snapMode != NoSnap && !qFuzzyCompare(qRound(d->offset), d->offset))) {
1902 d->stealMouse =
false;
1903 setKeepMouseGrab(
false);
1904 d->timer.invalidate();
1906 d->setDragging(
false);
1907 if (!d->tl.isActive())
1912void QQuickPathView::updatePolish()
1914 QQuickItem::updatePolish();
1920 if (currentIndex < 0)
1921 return modelCount + currentIndex % modelCount;
1923 return currentIndex % modelCount;
1926void QQuickPathView::componentComplete()
1928 Q_D(QQuickPathView);
1929 if (d->model && d->ownModel)
1930 static_cast<QQmlDelegateModel *>(d->model.data())->componentComplete();
1932 QQuickItem::componentComplete();
1935 d->modelCount = d->model->count();
1936 if (d->modelCount && d->currentIndex != 0)
1937 d->offset = std::fmod(qreal(d->modelCount - currentIndexRemainder(d->currentIndex, d->modelCount)), qreal(d->modelCount));
1940 d->createHighlight();
1942 d->updateHighlight();
1946 emit countChanged();
1949void QQuickPathView::refill()
1951 Q_D(QQuickPathView);
1954 d->scheduleLayout();
1958 d->layoutScheduled =
false;
1960 if (!d->isValid() || !isComponentComplete())
1965 bool currentVisible =
false;
1966 int count = d->pathItems == -1 ? d->modelCount : qMin(d->pathItems, d->modelCount);
1969 qCDebug(lcItemViewDelegateLifecycle) <<
"currentIndex" << d->currentIndex <<
"offset" << d->offset;
1970 QList<QQuickItem*>::iterator it = d->items.begin();
1971 while (it != d->items.end()) {
1972 QQuickItem *item = *it;
1973 int idx = d->model->indexOf(item,
nullptr);
1974 qreal pos = d->positionOfIndex(idx);
1975 if (lcItemViewDelegateLifecycle().isDebugEnabled()) {
1976 QQuickText *text = qmlobject_cast<QQuickText*>(item);
1978 qCDebug(lcItemViewDelegateLifecycle) <<
"idx" << idx <<
"@" << pos <<
": QQuickText" << text->objectName() << QStringView{text->text()}.left(40);
1980 qCDebug(lcItemViewDelegateLifecycle) <<
"idx" << idx <<
"@" << pos <<
":" << item;
1983 d->updateItem(item, pos);
1984 if (idx == d->currentIndex) {
1985 currentVisible =
true;
1986 d->currentItemOffset = pos;
1990 d->updateItem(item, pos);
1991 if (QQuickPathViewAttached *att = d->attached(item))
1992 att->setOnPath(pos < 1);
1993 if (!d->isInBound(pos, d->mappedRange - d->mappedCache, 1 + d->mappedCache)) {
1994 qCDebug(lcItemViewDelegateLifecycle) <<
"release" << idx <<
"@" << pos <<
", !isInBound: lower" << (d->mappedRange - d->mappedCache) <<
"upper" << (1 + d->mappedCache);
1995 d->releaseItem(item);
1996 it = d->items.erase(it);
2003 bool waiting =
false;
2004 if (d->modelCount) {
2006 if (d->items.size() < count+d->cacheSize) {
2011 const bool wasEmpty = d->items.isEmpty();
2017 for (QQuickItem * item : std::as_const(d->items)) {
2018 int idx = d->model->indexOf(item,
nullptr);
2019 qreal curPos = d->positionOfIndex(idx);
2020 if (curPos > endPos) {
2025 if (curPos < startPos) {
2031 if (d->haveHighlightRange
2032 && (d->highlightRangeMode != QQuickPathView::NoHighlightRange
2033 || d->snapMode != QQuickPathView::NoSnap))
2034 startPos = d->highlightRangeStart;
2036 endIdx = (qRound(d->modelCount - d->offset) - 1) % d->modelCount;
2037 endIdx = qMax(-1, endIdx);
2038 endPos = d->positionOfIndex(endIdx);
2041 int idx = endIdx + 1;
2042 if (idx >= d->modelCount)
2044 qreal nextPos = d->positionOfIndex(idx);
2045 while ((d->isInBound(nextPos, endPos, 1 + d->mappedCache,
false) || !d->items.size())
2046 && d->items.size() < count + d->cacheSize) {
2047 qCDebug(lcItemViewDelegateLifecycle) <<
"append" << idx <<
"@" << nextPos << (d->currentIndex == idx ?
"current" :
"") <<
"items count was" << d->items.size();
2048 QQuickItem *item = d->getItem(idx, idx+1, nextPos >= 1);
2053 if (d->items.contains(item)) {
2054 d->releaseItem(item);
2057 if (d->currentIndex == idx) {
2058 currentVisible =
true;
2059 d->currentItemOffset = nextPos;
2061 d->items.append(item);
2062 d->updateItem(item, nextPos);
2066 if (idx >= d->modelCount)
2068 nextPos = d->positionOfIndex(idx);
2072 idx = (wasEmpty ? d->calcCurrentIndex() : startIdx) - 1;
2075 idx = d->modelCount - 1;
2076 nextPos = d->positionOfIndex(idx);
2077 while (!waiting && d->isInBound(nextPos, d->mappedRange - d->mappedCache, startPos)
2078 && d->items.size() < count+d->cacheSize) {
2079 qCDebug(lcItemViewDelegateLifecycle) <<
"prepend" << idx <<
"@" << nextPos << (d->currentIndex == idx ?
"current" :
"") <<
"items count was" << d->items.size();
2080 QQuickItem *item = d->getItem(idx, idx+1, nextPos >= 1);
2085 if (d->items.contains(item)) {
2086 d->releaseItem(item);
2089 if (d->currentIndex == idx) {
2090 currentVisible =
true;
2091 d->currentItemOffset = nextPos;
2093 d->items.prepend(item);
2094 d->updateItem(item, nextPos);
2099 idx = d->modelCount - 1;
2100 nextPos = d->positionOfIndex(idx);
2107 if (!waiting && d->items.size() < count+d->cacheSize) {
2108 qCDebug(lcItemViewDelegateLifecycle) <<
"Checking for pathview middle inserts, items count was" << d->items.size();
2110 QQuickItem *lastItem = d->items.at(0);
2111 while (idx != endIdx) {
2112 nextPos = d->positionOfIndex(idx);
2113 if (d->isInBound(nextPos, d->mappedRange - d->mappedCache, 1 + d->mappedCache)) {
2115 QQuickItem *item = d->getItem(idx, idx+1, nextPos >= 1);
2121 if (!d->items.contains(item)) {
2122 qCDebug(lcItemViewDelegateLifecycle) <<
"middle insert" << idx <<
"@" << nextPos
2123 << (d->currentIndex == idx ?
"current" :
"")
2124 <<
"items count was" << d->items.size();
2125 if (d->currentIndex == idx) {
2126 currentVisible =
true;
2127 d->currentItemOffset = nextPos;
2129 int lastListIdx = d->items.indexOf(lastItem);
2130 d->items.insert(lastListIdx + 1, item);
2131 d->updateItem(item, nextPos);
2133 d->releaseItem(item);
2140 if (idx >= d->modelCount)
2147 bool currentChanged =
false;
2148 if (!currentVisible) {
2149 d->currentItemOffset = 1;
2150 if (d->currentItem) {
2151 d->updateItem(d->currentItem, 1);
2152 }
else if (!waiting && d->currentIndex >= 0 && d->currentIndex < d->modelCount) {
2153 if ((d->currentItem = d->getItem(d->currentIndex, d->currentIndex))) {
2154 currentChanged =
true;
2155 d->updateItem(d->currentItem, 1);
2156 if (QQuickPathViewAttached *att = d->attached(d->currentItem))
2157 att->setIsCurrentItem(
true);
2160 }
else if (!waiting && !d->currentItem) {
2161 if ((d->currentItem = d->getItem(d->currentIndex, d->currentIndex))) {
2162 currentChanged =
true;
2163 d->currentItem->setFocus(
true);
2164 if (QQuickPathViewAttached *att = d->attached(d->currentItem))
2165 att->setIsCurrentItem(
true);
2169 if (d->highlightItem && d->haveHighlightRange && d->highlightRangeMode == QQuickPathView::StrictlyEnforceRange) {
2170 d->updateItem(d->highlightItem, d->highlightRangeStart);
2171 if (QQuickPathViewAttached *att = d->attached(d->highlightItem))
2172 att->setOnPath(
true);
2173 }
else if (d->highlightItem && d->moveReason != QQuickPathViewPrivate::SetIndex) {
2174 d->updateItem(d->highlightItem, d->currentItemOffset);
2175 if (QQuickPathViewAttached *att = d->attached(d->highlightItem))
2176 att->setOnPath(currentVisible);
2178 for (QQuickItem *item : std::as_const(d->itemCache))
2179 d->releaseItem(item);
2180 d->itemCache.clear();
2182 d->inRefill =
false;
2184 emit currentItemChanged();
2187void QQuickPathView::modelUpdated(
const QQmlChangeSet &changeSet,
bool reset)
2189 Q_D(QQuickPathView);
2190 if (!d->model || !d->model->isValid() || !d->path || !isComponentComplete())
2194 d->modelCount = d->model->count();
2196 emit countChanged();
2200 if (changeSet.removes().isEmpty() && changeSet.inserts().isEmpty())
2203 const int modelCount = d->modelCount;
2206 bool currentChanged =
false;
2207 bool changedOffset =
false;
2208 for (
const QQmlChangeSet::Change &r : changeSet.removes()) {
2209 if (moveId == -1 && d->currentIndex >= r.index + r.count) {
2210 d->currentIndex -= r.count;
2211 currentChanged =
true;
2212 }
else if (moveId == -1 && d->currentIndex >= r.index && d->currentIndex < r.index + r.count) {
2216 moveOffset = d->currentIndex - r.index;
2217 }
else if (d->currentItem) {
2218 if (QQuickPathViewAttached *att = d->attached(d->currentItem))
2219 att->setIsCurrentItem(
true);
2220 d->releaseCurrentItem();
2222 d->currentIndex = qMin(r.index, d->modelCount - r.count - 1);
2223 currentChanged =
true;
2226 if (r.index > d->currentIndex) {
2227 changedOffset =
true;
2228 d->offset -= r.count;
2229 d->offsetAdj -= r.count;
2231 d->modelCount -= r.count;
2233 for (
const QQmlChangeSet::Change &i : changeSet.inserts()) {
2234 if (d->modelCount) {
2235 if (moveId == -1 && i.index <= d->currentIndex) {
2236 d->currentIndex += i.count;
2237 currentChanged =
true;
2239 if (moveId != -1 && moveId == i.moveId) {
2240 d->currentIndex = i.index + moveOffset;
2241 currentChanged =
true;
2243 if (i.index > d->currentIndex) {
2244 d->offset += i.count;
2245 d->offsetAdj += i.count;
2246 changedOffset =
true;
2250 d->modelCount += i.count;
2253 d->offset = std::fmod(d->offset, qreal(d->modelCount));
2255 d->offset += d->modelCount;
2256 if (d->currentIndex == -1)
2257 d->currentIndex = d->calcCurrentIndex();
2259 d->itemCache += d->items;
2262 if (!d->modelCount) {
2263 for (QQuickItem * item : std::as_const(d->itemCache))
2264 d->releaseItem(item);
2265 d->itemCache.clear();
2267 changedOffset =
true;
2268 d->tl.reset(d->moveOffset);
2270 if (!d->flicking && !d->moving && d->haveHighlightRange && d->highlightRangeMode == QQuickPathView::StrictlyEnforceRange) {
2271 d->offset = std::fmod(qreal(d->modelCount - d->currentIndex), qreal(d->modelCount));
2272 changedOffset =
true;
2274 d->updateMappedRange();
2275 d->scheduleLayout();
2278 emit offsetChanged();
2280 emit currentIndexChanged();
2281 if (d->modelCount != modelCount)
2282 emit countChanged();
2285void QQuickPathView::destroyingItem(QObject *item)
2290void QQuickPathView::ticked()
2292 Q_D(QQuickPathView);
2296void QQuickPathView::movementEnding()
2298 Q_D(QQuickPathView);
2300 d->flicking =
false;
2301 emit flickingChanged();
2304 if (d->moving && !d->stealMouse) {
2306 emit movingChanged();
2307 emit movementEnded();
2309 d->moveDirection = d->movementDirection;
2316 if (modelCount && model && items.size()) {
2317 offset = std::fmod(offset, qreal(modelCount));
2319 offset += modelCount;
2320 current = qRound(qAbs(
std::fmod(modelCount - offset, qreal(
modelCount))));
2332 bool inItems =
false;
2333 for (QQuickItem *item : std::as_const(items)) {
2334 if (model->indexOf(item,
nullptr) == currentIndex) {
2341 if ((currentItem = getItem(currentIndex, currentIndex))) {
2342 currentItem->setFocus(
true);
2347 if ((currentItem = getItem(currentIndex, currentIndex))) {
2348 updateItem(currentItem, 1);
2357 Q_Q(QQuickPathView);
2360 if (!modelCount || !haveHighlightRange || highlightRangeMode != QQuickPathView::StrictlyEnforceRange)
2364 if (model && (idx != currentIndex || !currentItem)) {
2372 currentItem =
nullptr;
2375 emit q->currentIndexChanged();
2376 emit q->currentItemChanged();
2387 Q_Q(QQuickPathView);
2388 if (model && items.size()) {
2389 if (haveHighlightRange && (highlightRangeMode == QQuickPathView::StrictlyEnforceRange
2390 || snapMode != QQuickPathView::NoSnap)) {
2392 if (curr != currentIndex && highlightRangeMode == QQuickPathView::StrictlyEnforceRange)
2393 q->setCurrentIndex(curr);
2402 if (!model || modelCount <= 0)
2405 qreal targetOffset = std::fmod(qreal(modelCount - index), qreal(modelCount));
2408 tl.reset(moveOffset);
2409 moveOffset.setValue(offset);
2414 const qreal averageItemLength = path->path().length() / count;
2415 const qreal threshold = 0.5 / averageItemLength;
2417 if (!duration || qAbs(offset - targetOffset) < threshold || (qFuzzyIsNull(targetOffset) && qAbs(modelCount - offset) < threshold)) {
2418 tl.set(moveOffset, targetOffset);
2419 }
else if (moveDirection == QQuickPathView::Positive || (moveDirection == QQuickPathView::Shortest && targetOffset - offset > modelCount/2)) {
2420 qreal distance = modelCount - targetOffset + offset;
2421 if (targetOffset > moveOffset) {
2422 tl.move(moveOffset, 0, QEasingCurve(QEasingCurve::InQuad),
int(duration * offset / distance));
2423 tl.set(moveOffset, modelCount);
2424 tl.move(moveOffset, targetOffset, QEasingCurve(qFuzzyIsNull(offset) ? QEasingCurve::InOutQuad : QEasingCurve::OutQuad),
int(duration * (modelCount-targetOffset) / distance));
2426 tl.move(moveOffset, targetOffset, QEasingCurve(QEasingCurve::InOutQuad), duration);
2428 }
else if (moveDirection == QQuickPathView::Negative || targetOffset - offset <= -modelCount/2) {
2429 qreal distance = modelCount - offset + targetOffset;
2430 if (targetOffset < moveOffset) {
2431 tl.move(moveOffset, modelCount, QEasingCurve(qFuzzyIsNull(targetOffset) ? QEasingCurve::InOutQuad : QEasingCurve::InQuad),
int(duration * (modelCount-offset) / distance));
2432 tl.set(moveOffset, 0);
2433 tl.move(moveOffset, targetOffset, QEasingCurve(QEasingCurve::OutQuad),
int(duration * targetOffset / distance));
2435 tl.move(moveOffset, targetOffset, QEasingCurve(QEasingCurve::InOutQuad), duration);
2438 tl.move(moveOffset, targetOffset, QEasingCurve(QEasingCurve::InOutQuad), duration);
2442QQuickPathViewAttached *QQuickPathView::qmlAttachedProperties(QObject *obj)
2444 return new QQuickPathViewAttached(obj);
2449#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