10#include <QtQml/qqmlcomponent.h>
11#include <QtQuick/private/qquickstate_p.h>
12#include <private/qqmlglobal_p.h>
13#include <private/qqmlopenmetaobject_p.h>
14#include <private/qqmlchangeset_p.h>
15#include <qpa/qplatformtheme.h>
17#include <QtQml/qqmlinfo.h>
19#include <QtGui/private/qeventpoint_p.h>
20#include <QtGui/qevent.h>
21#include <QtGui/qguiapplication.h>
22#include <QtGui/private/qguiapplication_p.h>
23#include <QtGui/qstylehints.h>
24#include <QtCore/qmath.h>
28#if QT_CONFIG(quick_itemview)
29#include <private/qquickitemview_p.h>
34#if !QT_CONFIG(quick_itemview)
42: QObject(parent), m_percent(-1), m_view(
nullptr), m_onPath(
false), m_isCurrent(
false)
45 m_metaobject =
new QQmlOpenMetaObject(
this, qPathViewAttachedType);
46 m_metaobject->setCached(
true);
48 m_metaobject =
new QQmlOpenMetaObject(
this);
58 return m_metaobject->value(name);
62 m_metaobject->setValue(name, val);
66 : path(
nullptr),
currentIndex(0), currentItemOffset(0), startPc(0)
67 , offset(0), offsetAdj(0), mappedRange(1), mappedCache(0)
72 , dragMargin(0), deceleration(100)
73 , maximumFlickVelocity(QGuiApplicationPrivate::platformTheme()->themeHint(QPlatformTheme::FlickMaximumVelocity).toReal())
74 , moveOffset(
this, &QQuickPathViewPrivate::setAdjustedOffset),
flickDuration(0)
76 ,
moveReason(
Other), movementDirection(QQuickPathView::Shortest), moveDirection(QQuickPathView::Shortest)
78 , moveHighlight(
this, &QQuickPathViewPrivate::setHighlightPosition)
79 , highlightPosition(0)
80 , highlightRangeStart(0), highlightRangeEnd(0)
81 , highlightRangeMode(QQuickPathView::StrictlyEnforceRange)
84 setSizePolicy(QLayoutPolicy::Preferred, QLayoutPolicy::Preferred);
91 q->setAcceptedMouseButtons(Qt::LeftButton);
92 q->setFlag(QQuickItem::ItemIsFocusScope);
93 q->setFiltersChildMouseEvents(
true);
94 qmlobject_connect(&tl, QQuickTimeLine, SIGNAL(updated()),
95 q, QQuickPathView, SLOT(ticked()));
97 qmlobject_connect(&tl, QQuickTimeLine, SIGNAL(completed()),
98 q, QQuickPathView, SLOT(movementEnding()));
107 QObject *object = model->object(modelIndex, async ? QQmlIncubator::Asynchronous : QQmlIncubator::AsynchronousIfNested);
108 QQuickItem *item = qmlobject_cast<QQuickItem*>(object);
111 model->release(object);
114 QObject* delegate = q->delegate();
115 qmlWarning(delegate ? delegate : q) << QQuickPathView::tr(
"Delegate must be of Item type");
119 item->setParentItem(q);
121 QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
122 itemPrivate->addItemChangeListener(
123 this, QQuickItemPrivate::Geometry | QQuickItemPrivate::Destroyed);
129void QQuickPathView::createdItem(
int index, QObject *object)
132 QQuickItem *item = qmlobject_cast<QQuickItem*>(object);
133 if (d->requestedIndex != index) {
134 qPathViewAttachedType = d->attachedType();
135 QQuickPathViewAttached *att =
static_cast<QQuickPathViewAttached *>(qmlAttachedPropertiesObject<QQuickPathView>(item));
136 qPathViewAttachedType =
nullptr;
139 att->setOnPath(
false);
141 item->setParentItem(
this);
142 d->updateItem(item, 1);
144 d->requestedIndex = -1;
150void QQuickPathView::initItem(
int index, QObject *object)
153 QQuickItem *item = qmlobject_cast<QQuickItem*>(object);
154 if (item && d->requestedIndex == index) {
155 QQuickItemPrivate::get(item)->setCulled(
true);
156 item->setParentItem(
this);
157 qPathViewAttachedType = d->attachedType();
158 QQuickPathViewAttached *att =
static_cast<QQuickPathViewAttached *>(qmlAttachedPropertiesObject<QQuickPathView>(item));
159 qPathViewAttachedType =
nullptr;
162 qreal percent = d->positionOfIndex(index);
163 if (percent < 1 && d->path) {
164 const auto attributes = d->path->attributes();
165 for (
const QString &attr : attributes)
166 att->setValue(attr.toUtf8(), d->path->attributeAt(attr, percent));
167 item->setZ(d->requestedZ);
169 att->setOnPath(percent < 1);
178 qCDebug(lcItemViewDelegateLifecycle) <<
"release" << item;
179 QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
180 itemPrivate->removeItemChangeListener(
181 this, QQuickItemPrivate::Geometry | QQuickItemPrivate::Destroyed);
184 QQmlInstanceModel::ReleaseFlags flags = model->release(item);
189 }
else if (flags & QQmlInstanceModel::Destroyed) {
191 item->setParentItem(
nullptr);
197 return static_cast<QQuickPathViewAttached *>(qmlAttachedPropertiesObject<QQuickPathView>(item,
false));
204 attType =
new QQmlOpenMetaObjectType(&QQuickPathViewAttached::staticMetaObject);
206 const auto attributes = path->attributes();
207 for (
const QString &attr : attributes)
208 attType->createProperty(attr.toUtf8());
219 for (QQuickItem *p : std::as_const(items))
222 for (QQuickItem *p : std::as_const(itemCache))
227 model->cancel(requestedIndex);
242 if (model && pathItems != -1 && pathItems < modelCount) {
243 mappedRange = qreal(modelCount)/pathItems;
244 mappedCache = qreal(cacheSize)/pathItems/2;
255 if (model && index >= 0 && index < modelCount) {
257 if (haveHighlightRange && (highlightRangeMode != QQuickPathView::NoHighlightRange
258 || snapMode != QQuickPathView::NoSnap))
259 start = highlightRangeStart;
260 qreal globalPos = index + offset;
261 globalPos = std::fmod(globalPos, qreal(modelCount)) / modelCount;
263 globalPos += start / mappedRange;
264 globalPos = std::fmod(globalPos, qreal(1));
265 pos = globalPos * mappedRange;
267 pos = std::fmod(globalPos + start, qreal(1));
277 qreal upper,
bool emptyRangeCheck)
const
279 if (emptyRangeCheck && qFuzzyCompare(lower, upper))
282 if (position > upper && position > lower)
283 position -= mappedRange;
284 lower -= mappedRange;
286 return position >= lower && position < upper;
292 if (!q->isComponentComplete())
295 bool changed =
false;
303 QQuickItem *item =
nullptr;
306 QQmlContext *highlightContext =
new QQmlContext(
307 creationContext ? creationContext : qmlContext(q));
310 QQml_setParent_noEvent(highlightContext, nobj);
311 item = qobject_cast<QQuickItem *>(nobj);
315 delete highlightContext;
318 item =
new QQuickItem;
321 QQml_setParent_noEvent(item, q);
322 item->setParentItem(q);
327 emit q->highlightItemChanged();
333 if (!q->isComponentComplete() || !isValid())
336 if (haveHighlightRange && highlightRangeMode == QQuickPathView::StrictlyEnforceRange) {
337 updateItem(highlightItem, highlightRangeStart);
339 qreal target = currentIndex;
342 tl.reset(moveHighlight);
343 moveHighlight.setValue(highlightPosition);
347 if (target - highlightPosition > modelCount/2) {
349 qreal distance = modelCount - target + highlightPosition;
350 tl.move(moveHighlight, 0, QEasingCurve(QEasingCurve::InQuad),
int(duration * highlightPosition / distance));
351 tl.set(moveHighlight, modelCount-0.01);
352 tl.move(moveHighlight, target, QEasingCurve(QEasingCurve::OutQuad),
int(duration * (modelCount-target) / distance));
353 }
else if (target - highlightPosition <= -modelCount/2) {
355 qreal distance = modelCount - highlightPosition + target;
356 tl.move(moveHighlight, modelCount-0.01, QEasingCurve(QEasingCurve::InQuad),
int(duration * (modelCount-highlightPosition) / distance));
357 tl.set(moveHighlight, 0);
358 tl.move(moveHighlight, target, QEasingCurve(QEasingCurve::OutQuad),
int(duration * target / distance));
360 highlightUp = highlightPosition - target < 0;
361 tl.move(moveHighlight, target, QEasingCurve(QEasingCurve::InOutQuad), duration);
369 if (!(qFuzzyCompare(pos, highlightPosition))) {
372 if (haveHighlightRange && highlightRangeMode != QQuickPathView::NoHighlightRange) {
373 start = highlightRangeStart;
374 end = highlightRangeEnd;
377 qreal range = qreal(modelCount);
379 qreal relativeHighlight = std::fmod(pos + offset, range) / range;
381 if (!highlightUp && relativeHighlight > end / mappedRange) {
382 qreal diff = 1 - relativeHighlight;
383 setOffset(offset + diff * range);
384 }
else if (highlightUp && relativeHighlight >= (end - start) / mappedRange) {
385 qreal diff = relativeHighlight - (end - start) / mappedRange;
386 setOffset(offset - diff * range - 0.00001);
389 highlightPosition = pos;
390 qreal pathPos = positionOfIndex(pos);
391 updateItem(highlightItem, pathPos);
392 if (QQuickPathViewAttached *att = attached(highlightItem))
393 att->setOnPath(pathPos < 1);
397void QQuickPathView::pathUpdated()
400 for (QQuickItem *item : std::as_const(d->items)) {
401 if (QQuickPathViewAttached *att = d->attached(item))
412 if (qFuzzyCompare(att->m_percent, percent))
414 att->m_percent = percent;
415 const auto attributes = path->attributes();
416 for (
const QString &attr : attributes)
417 att->setValue(attr.toUtf8(), path->attributeAt(attr, percent));
420 QQuickItemPrivate::get(item)->setCulled(percent >= 1);
421 QPointF pf = path->pointAtPercent(qMin(percent, qreal(1)));
422 item->setX(pf.x() - item->width()/2);
423 item->setY(pf.y() - item->height()/2);
429 if (!q->isComponentComplete())
449 emit q->dragStarted();
453 emit q->draggingChanged();
457
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
523QQuickPathView::QQuickPathView(QQuickItem *parent)
524 : QQuickItem(*(
new QQuickPathViewPrivate), parent)
530QQuickPathView::~QQuickPathView()
535 d->attType->release();
541
542
543
544
545
546
547
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
572
573
574
575
576
577
578
579
580
581
582
585
586
587
588
589
590
591
592
593
594
595
596QVariant QQuickPathView::model()
const
598 Q_D(
const QQuickPathView);
599 return d->modelVariant;
602void QQuickPathView::setModel(
const QVariant &m)
606 if (model.userType() == qMetaTypeId<QJSValue>())
607 model = model.value<QJSValue>().toVariant();
609 if (d->modelVariant == model)
613 qmlobject_disconnect(d->model, QQmlInstanceModel, SIGNAL(modelUpdated(QQmlChangeSet,
bool)),
614 this, QQuickPathView, SLOT(modelUpdated(QQmlChangeSet,
bool)));
615 qmlobject_disconnect(d->model, QQmlInstanceModel, SIGNAL(createdItem(
int,QObject*)),
616 this, QQuickPathView, SLOT(createdItem(
int,QObject*)));
617 qmlobject_disconnect(d->model, QQmlInstanceModel, SIGNAL(initItem(
int,QObject*)),
618 this, QQuickPathView, SLOT(initItem(
int,QObject*)));
622 d->modelVariant = model;
623 QObject *object = qvariant_cast<QObject*>(model);
624 QQmlInstanceModel *vim =
nullptr;
625 if (object && (vim = qobject_cast<QQmlInstanceModel *>(object))) {
633 d->model =
new QQmlDelegateModel(qmlContext(
this));
635 if (isComponentComplete())
636 static_cast<QQmlDelegateModel *>(d->model.data())->componentComplete();
638 if (QQmlDelegateModel *dataModel = qobject_cast<QQmlDelegateModel*>(d->model))
639 dataModel->setModel(model);
641 int oldModelCount = d->modelCount;
644 qmlobject_connect(d->model, QQmlInstanceModel, SIGNAL(modelUpdated(QQmlChangeSet,
bool)),
645 this, QQuickPathView, SLOT(modelUpdated(QQmlChangeSet,
bool)));
646 qmlobject_connect(d->model, QQmlInstanceModel, SIGNAL(createdItem(
int,QObject*)),
647 this, QQuickPathView, SLOT(createdItem(
int,QObject*)));
648 qmlobject_connect(d->model, QQmlInstanceModel, SIGNAL(initItem(
int,QObject*)),
649 this, QQuickPathView, SLOT(initItem(
int,QObject*)));
650 d->modelCount = d->model->count();
652 if (isComponentComplete()) {
653 if (d->currentIndex != 0) {
655 emit currentIndexChanged();
657 if (!(qFuzzyIsNull(d->offset))) {
659 emit offsetChanged();
663 if (d->modelCount != oldModelCount)
669
670
671
672int QQuickPathView::count()
const
674 Q_D(
const QQuickPathView);
675 return d->model ? d->modelCount : 0;
679
680
681
682
683QQuickPath *QQuickPathView::path()
const
685 Q_D(
const QQuickPathView);
689void QQuickPathView::setPath(QQuickPath *path)
695 qmlobject_disconnect(d->path, QQuickPath, SIGNAL(changed()),
696 this, QQuickPathView, SLOT(pathUpdated()));
700 qmlobject_connect(d->path, QQuickPath, SIGNAL(changed()),
701 this, QQuickPathView, SLOT(pathUpdated()));
704 if (isComponentComplete()) {
708 d->attType->release();
709 d->attType =
nullptr;
719
720
721
722int QQuickPathView::currentIndex()
const
724 Q_D(
const QQuickPathView);
725 return d->currentIndex;
728void QQuickPathView::setCurrentIndex(
int idx)
731 if (!isComponentComplete()) {
732 if (idx != d->currentIndex) {
733 d->currentIndex = idx;
734 emit currentIndexChanged();
740 ? ((idx % d->modelCount) + d->modelCount) % d->modelCount
742 if (d->model && (idx != d->currentIndex || !d->currentItem)) {
743 const bool hadCurrentItem = d->currentItem !=
nullptr;
744 const int oldCurrentIdx = d->currentIndex;
745 if (hadCurrentItem) {
746 if (QQuickPathViewAttached *att = d->attached(d->currentItem))
747 att->setIsCurrentItem(
false);
748 d->releaseCurrentItem();
750 d->moveReason = QQuickPathViewPrivate::SetIndex;
751 d->currentIndex = idx;
753 d->createCurrentItem();
754 if (d->haveHighlightRange && d->highlightRangeMode == QQuickPathView::StrictlyEnforceRange)
755 d->snapToIndex(d->currentIndex, QQuickPathViewPrivate::SetIndex);
756 d->currentItemOffset = d->positionOfIndex(d->currentIndex);
757 d->updateHighlight();
759 if (oldCurrentIdx != d->currentIndex)
760 emit currentIndexChanged();
762 emit currentItemChanged();
767
768
769
770QQuickItem *QQuickPathView::currentItem()
const
772 Q_D(
const QQuickPathView);
773 return d->currentItem;
777
778
779
780
781
782
783void QQuickPathView::incrementCurrentIndex()
786 d->moveDirection = QQuickPathView::Positive;
787 setCurrentIndex(currentIndex()+1);
791
792
793
794
795
796
797void QQuickPathView::decrementCurrentIndex()
800 d->moveDirection = QQuickPathView::Negative;
801 setCurrentIndex(currentIndex()-1);
805
806
807
808
809
810qreal QQuickPathView::offset()
const
812 Q_D(
const QQuickPathView);
816void QQuickPathView::setOffset(qreal offset)
819 d->moveReason = QQuickPathViewPrivate::Other;
820 d->setOffset(offset);
827 if (!qFuzzyCompare(offset, o)) {
828 if (isValid() && q->isComponentComplete()) {
829 qreal oldOffset = offset;
830 offset = std::fmod(o, qreal(modelCount));
832 offset += qreal(modelCount);
833 qCDebug(lcItemViewDelegateLifecycle) << o <<
"was" << oldOffset <<
"now" << offset;
838 emit q->offsetChanged();
844 setOffset(o+offsetAdj);
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870QQmlComponent *QQuickPathView::highlight()
const
872 Q_D(
const QQuickPathView);
873 return d->highlightComponent;
876void QQuickPathView::setHighlight(QQmlComponent *highlight)
879 if (highlight != d->highlightComponent) {
880 d->highlightComponent = highlight;
881 d->createHighlight();
882 d->updateHighlight();
883 emit highlightChanged();
888
889
890
891
892
893
894
895QQuickItem *QQuickPathView::highlightItem()
const
897 Q_D(
const QQuickPathView);
898 return d->highlightItem;
902
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
937qreal QQuickPathView::preferredHighlightBegin()
const
939 Q_D(
const QQuickPathView);
940 return d->highlightRangeStart;
943void QQuickPathView::setPreferredHighlightBegin(qreal start)
946 if (qFuzzyCompare(d->highlightRangeStart, start) || start < 0 || start > 1)
948 d->highlightRangeStart = start;
949 d->haveHighlightRange = d->highlightRangeStart <= d->highlightRangeEnd;
951 emit preferredHighlightBeginChanged();
954qreal QQuickPathView::preferredHighlightEnd()
const
956 Q_D(
const QQuickPathView);
957 return d->highlightRangeEnd;
960void QQuickPathView::setPreferredHighlightEnd(qreal end)
963 if (qFuzzyCompare(d->highlightRangeEnd, end) || end < 0 || end > 1)
965 d->highlightRangeEnd = end;
966 d->haveHighlightRange = d->highlightRangeStart <= d->highlightRangeEnd;
968 emit preferredHighlightEndChanged();
971QQuickPathView::HighlightRangeMode QQuickPathView::highlightRangeMode()
const
973 Q_D(
const QQuickPathView);
974 return d->highlightRangeMode;
977void QQuickPathView::setHighlightRangeMode(HighlightRangeMode mode)
980 if (d->highlightRangeMode == mode)
982 d->highlightRangeMode = mode;
983 d->haveHighlightRange = d->highlightRangeStart <= d->highlightRangeEnd;
984 if (d->haveHighlightRange) {
986 int index = d->highlightRangeMode != NoHighlightRange ? d->currentIndex : d->calcCurrentIndex();
988 d->snapToIndex(index, QQuickPathViewPrivate::Other);
990 emit highlightRangeModeChanged();
994
995
996
997
998
999
1000
1001
1002int QQuickPathView::highlightMoveDuration()
const
1004 Q_D(
const QQuickPathView);
1005 return d->highlightMoveDuration;
1008void QQuickPathView::setHighlightMoveDuration(
int duration)
1010 Q_D(QQuickPathView);
1011 if (d->highlightMoveDuration == duration)
1013 d->highlightMoveDuration = duration;
1014 emit highlightMoveDurationChanged();
1018
1019
1020
1021
1022
1023
1024
1025qreal QQuickPathView::dragMargin()
const
1027 Q_D(
const QQuickPathView);
1028 return d->dragMargin;
1031void QQuickPathView::setDragMargin(qreal dragMargin)
1033 Q_D(QQuickPathView);
1034 if (qFuzzyCompare(d->dragMargin, dragMargin))
1036 d->dragMargin = dragMargin;
1037 emit dragMarginChanged();
1041
1042
1043
1044
1045
1046qreal QQuickPathView::flickDeceleration()
const
1048 Q_D(
const QQuickPathView);
1049 return d->deceleration;
1052void QQuickPathView::setFlickDeceleration(qreal dec)
1054 Q_D(QQuickPathView);
1055 if (qFuzzyCompare(d->deceleration, dec))
1057 d->deceleration = dec;
1058 emit flickDecelerationChanged();
1062
1063
1064
1065
1066
1067qreal QQuickPathView::maximumFlickVelocity()
const
1069 Q_D(
const QQuickPathView);
1070 return d->maximumFlickVelocity;
1073void QQuickPathView::setMaximumFlickVelocity(qreal vel)
1075 Q_D(QQuickPathView);
1076 if (qFuzzyCompare(vel, d->maximumFlickVelocity))
1078 d->maximumFlickVelocity = vel;
1079 emit maximumFlickVelocityChanged();
1084
1085
1086
1087
1088
1089
1090
1091bool QQuickPathView::isInteractive()
const
1093 Q_D(
const QQuickPathView);
1094 return d->interactive;
1097void QQuickPathView::setInteractive(
bool interactive)
1099 Q_D(QQuickPathView);
1100 if (interactive != d->interactive) {
1101 d->interactive = interactive;
1104 emit interactiveChanged();
1109
1110
1111
1112
1113
1114bool QQuickPathView::isMoving()
const
1116 Q_D(
const QQuickPathView);
1121
1122
1123
1124
1125
1126bool QQuickPathView::isFlicking()
const
1128 Q_D(
const QQuickPathView);
1133
1134
1135
1136
1137
1138bool QQuickPathView::isDragging()
const
1140 Q_D(
const QQuickPathView);
1145
1146
1147
1148
1149
1152
1153
1154
1155
1156
1157
1158
1159
1162
1163
1164
1165
1166
1167
1170
1171
1172
1173
1176
1177
1178
1179
1180
1183
1184
1185
1186
1187
1188
1189
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209QQmlComponent *QQuickPathView::delegate()
const
1211 Q_D(
const QQuickPathView);
1213 if (QQmlDelegateModel *dataModel = qobject_cast<QQmlDelegateModel*>(d->model))
1214 return dataModel->delegate();
1220void QQuickPathView::setDelegate(QQmlComponent *delegate)
1222 Q_D(QQuickPathView);
1223 if (delegate ==
this->delegate())
1226 d->model =
new QQmlDelegateModel(qmlContext(
this));
1228 if (isComponentComplete())
1229 static_cast<QQmlDelegateModel *>(d->model.data())->componentComplete();
1231 if (QQmlDelegateModel *dataModel = qobject_cast<QQmlDelegateModel*>(d->model)) {
1232 int oldCount = dataModel->count();
1233 dataModel->setDelegate(delegate);
1234 d->modelCount = dataModel->count();
1236 if (oldCount != dataModel->count())
1237 emit countChanged();
1238 emit delegateChanged();
1239 d->delegateValidated =
false;
1244
1245
1246
1247
1248
1249int QQuickPathView::pathItemCount()
const
1251 Q_D(
const QQuickPathView);
1252 return d->pathItems;
1255void QQuickPathView::setPathItemCount(
int i)
1257 Q_D(QQuickPathView);
1258 if (i == d->pathItems)
1263 d->updateMappedRange();
1264 if (d->isValid() && isComponentComplete()) {
1267 emit pathItemCountChanged();
1270void QQuickPathView::resetPathItemCount()
1272 Q_D(QQuickPathView);
1273 if (-1 == d->pathItems)
1276 d->updateMappedRange();
1277 if (d->isValid() && isComponentComplete())
1279 emit pathItemCountChanged();
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303int QQuickPathView::cacheItemCount()
const
1305 Q_D(
const QQuickPathView);
1306 return d->requestedCacheSize;
1309void QQuickPathView::setCacheItemCount(
int i)
1311 Q_D(QQuickPathView);
1312 if (i == d->requestedCacheSize || i < 0)
1315 d->requestedCacheSize = i;
1316 d->updateMappedRange();
1318 emit cacheItemCountChanged();
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339QQuickPathView::SnapMode QQuickPathView::snapMode()
const
1341 Q_D(
const QQuickPathView);
1345void QQuickPathView::setSnapMode(SnapMode mode)
1347 Q_D(QQuickPathView);
1348 if (mode == d->snapMode)
1351 emit snapModeChanged();
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377QQuickPathView::MovementDirection QQuickPathView::movementDirection()
const
1379 Q_D(
const QQuickPathView);
1380 return d->movementDirection;
1383void QQuickPathView::setMovementDirection(QQuickPathView::MovementDirection dir)
1385 Q_D(QQuickPathView);
1386 if (dir == d->movementDirection)
1388 d->movementDirection = dir;
1389 if (!d->tl.isActive())
1390 d->moveDirection = d->movementDirection;
1391 emit movementDirectionChanged();
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416void QQuickPathView::positionViewAtIndex(
int index,
int mode)
1418 Q_D(QQuickPathView);
1421 if (mode < QQuickPathView::Beginning || mode > QQuickPathView::SnapPosition || mode == 3)
1424 if (mode == QQuickPathView::Contain && (d->pathItems < 0 || d->modelCount <= d->pathItems))
1427 int count = d->pathItems == -1 ? d->modelCount : qMin(d->pathItems, d->modelCount);
1428 int idx = (index+d->modelCount) % d->modelCount;
1429 bool snap = d->haveHighlightRange && (d->highlightRangeMode != QQuickPathView::NoHighlightRange
1430 || d->snapMode != QQuickPathView::NoSnap);
1435 beginOffset = d->modelCount - idx - qFloor(count * d->highlightRangeStart);
1436 endOffset = beginOffset + count - 1;
1438 beginOffset = d->modelCount - idx;
1441 qreal adj =
sizeof(qreal) ==
sizeof(
float) ? 0.00001f : 0.000000000001;
1442 endOffset = std::fmod(beginOffset + count, qreal(d->modelCount)) - adj;
1444 qreal offset = d->offset;
1447 offset = beginOffset;
1453 if (beginOffset < endOffset)
1454 offset = (beginOffset + endOffset)/2;
1456 offset = (beginOffset + (endOffset + d->modelCount))/2;
1458 offset = qRound(offset);
1461 if ((beginOffset < endOffset && (d->offset < beginOffset || d->offset > endOffset))
1462 || (d->offset < beginOffset && d->offset > endOffset)) {
1463 qreal diff1 = std::fmod(beginOffset - d->offset + d->modelCount, qreal(d->modelCount));
1464 qreal diff2 = std::fmod(d->offset - endOffset + d->modelCount, qreal(d->modelCount));
1466 offset = beginOffset;
1472 offset = d->modelCount - idx;
1481
1482
1483
1484
1485
1486
1487
1488int QQuickPathView::indexAt(qreal x, qreal y)
const
1490 Q_D(
const QQuickPathView);
1491 QQuickItem *item = itemAt(x, y);
1492 return item ? d->model->indexOf(item,
nullptr) : -1;
1496
1497
1498
1499
1500
1501
1502
1503QQuickItem *QQuickPathView::itemAt(qreal x, qreal y)
const
1505 Q_D(
const QQuickPathView);
1509 for (QQuickItem *item : d->items) {
1510 QPointF p = item->mapFromItem(
this, QPointF(x, y));
1511 if (item->contains(p))
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531QQuickItem *QQuickPathView::itemAtIndex(
int index)
const
1533 Q_D(
const QQuickPathView);
1537 for (QQuickItem *item : d->items) {
1538 if (index == d->model->indexOf(item,
nullptr))
1546
1547
1548
1549
1550
1551
1552
1555 const auto pathLength = path->path().length();
1556 qreal samples = qMin(pathLength / 5, qreal(500));
1557 qreal res = pathLength / samples;
1559 qreal mindist = 1e10;
1560 QPointF nearPoint = path->pointAtPercent(0);
1564 for (qreal i=1; i < samples; i++) {
1565 QPointF pt = path->pointAtPercent(i/samples);
1566 QPointF diff = pt - point;
1567 qreal dist = diff.x()*diff.x() + diff.y()*diff.y();
1568 if (dist < mindist) {
1576 qreal approxPc = nearPc;
1577 for (qreal i = approxPc-1; i < approxPc+1; i += 1/(2*res)) {
1578 QPointF pt = path->pointAtPercent(i/samples);
1579 QPointF diff = pt - point;
1580 qreal dist = diff.x()*diff.x() + diff.y()*diff.y();
1581 if (dist < mindist) {
1589 *nearPercent = nearPc / samples;
1596 velocityBuffer.append(v);
1598 velocityBuffer.remove(0);
1599 qCDebug(lcPathView) <<
"instantaneous velocity" << v;
1607 for (
int i = 0; i < count; ++i) {
1608 qreal v = velocityBuffer.at(i);
1612 qCDebug(lcPathView) <<
"average velocity" << velocity <<
"based on" << count <<
"samples";
1619 if (0 != event->timestamp())
1620 return qint64(event->timestamp());
1621 return timer.elapsed();
1624void QQuickPathView::mousePressEvent(QMouseEvent *event)
1626 Q_D(QQuickPathView);
1627 if (d->interactive) {
1628 d->handleMousePressEvent(event);
1631 QQuickItem::mousePressEvent(event);
1637 Q_Q(QQuickPathView);
1638 if (!interactive || !items.size() || !model || !modelCount)
1640 velocityBuffer.clear();
1642 for (; idx < items.size(); ++idx) {
1643 QQuickItem *item = items.at(idx);
1644 if (item->contains(item->mapFromScene(event->scenePosition())))
1647 if (idx == items.size() && qFuzzyIsNull(dragMargin))
1650 startPoint = pointNear(event->position(), &startPc);
1651 startPos = event->position();
1652 if (idx == items.size()) {
1653 qreal distance = qAbs(event->position().x() - startPoint.x()) + qAbs(event->position().y() - startPoint.y());
1654 if (distance > dragMargin)
1658 if (tl.isActive() && flicking && flickDuration && qreal(tl.time()) / flickDuration < 0.8) {
1664 q->setKeepMouseGrab(stealMouse);
1667 lastPosTime = computeCurrentTime(event);
1671void QQuickPathView::mouseMoveEvent(QMouseEvent *event)
1673 Q_D(QQuickPathView);
1674 if (d->interactive) {
1675 d->handleMouseMoveEvent(event);
1678 QQuickItem::mouseMoveEvent(event);
1684 Q_Q(QQuickPathView);
1685 if (!interactive || !timer.isValid() || !model || !modelCount)
1688 qint64 currentTimestamp = computeCurrentTime(event);
1690 QPointF pathPoint = pointNear(event->position(), &newPc);
1692 QPointF posDelta = event->position() - startPos;
1693 if (QQuickDeliveryAgentPrivate::dragOverThreshold(posDelta.y(), Qt::YAxis, event) ||
1694 QQuickDeliveryAgentPrivate::dragOverThreshold(posDelta.x(), Qt::XAxis, event)) {
1698 QPointF pathDelta = pathPoint - startPoint;
1699 const int startDragDistance = QGuiApplication::styleHints()->startDragDistance();
1700 if (qAbs(pathDelta.x()) > startDragDistance * 0.8
1701 || qAbs(pathDelta.y()) > startDragDistance * 0.8) {
1703 q->setKeepMouseGrab(
true);
1709 qreal diff = (newPc - startPc)*count;
1710 if (!qFuzzyIsNull(diff)) {
1711 q->setOffset(offset + diff);
1713 if (diff > modelCount/2)
1715 else if (diff < -modelCount/2)
1718 qint64 elapsed = currentTimestamp - lastPosTime;
1720 addVelocitySample(diff / (qreal(elapsed) / 1000));
1724 emit q->movingChanged();
1725 emit q->movementStarted();
1730 lastPosTime = currentTimestamp;
1733void QQuickPathView::mouseReleaseEvent(QMouseEvent *event)
1735 Q_D(QQuickPathView);
1736 if (d->interactive) {
1737 d->handleMouseReleaseEvent(event);
1741 QQuickItem::mouseReleaseEvent(event);
1747 Q_Q(QQuickPathView);
1749 q->setKeepMouseGrab(
false);
1751 if (!interactive || !timer.isValid() || !model || !modelCount) {
1754 q->movementEnding();
1758 qreal velocity = calcVelocity();
1759 qint64 elapsed = computeCurrentTime(event) - lastPosTime;
1764 qCDebug(lcPathView) <<
"after elapsed time" << elapsed <<
"velocity decayed to" << velocity;
1765 qreal count = pathItems == -1 ? modelCount : qMin(pathItems, modelCount);
1766 const auto averageItemLength = path->path().length() / count;
1767 qreal pixelVelocity = averageItemLength * velocity;
1768 if (qAbs(pixelVelocity) > _q_MinimumFlickVelocity) {
1769 if (qAbs(pixelVelocity) > maximumFlickVelocity || snapMode == QQuickPathView::SnapOneItem) {
1771 qreal maxVel = velocity < 0 ? -maximumFlickVelocity : maximumFlickVelocity;
1772 velocity = maxVel / averageItemLength;
1775 qreal v2 = velocity*velocity;
1776 qreal accel = deceleration/10;
1778 if (haveHighlightRange && (highlightRangeMode == QQuickPathView::StrictlyEnforceRange
1779 || snapMode != QQuickPathView::NoSnap)) {
1780 if (snapMode == QQuickPathView::SnapOneItem) {
1783 dist = qRound(0.5 + offset) - offset;
1785 dist = qRound(0.5 - offset) + offset;
1788 dist = qMin(qreal(modelCount-1), qreal(v2 / (accel * 2) + 0.25));
1792 dist = qRound(dist + offset) - offset;
1794 dist = qRound(dist - offset) + offset;
1801 accel = v2 / (2 * qAbs(dist));
1804 dist = qMin(qreal(modelCount-1), qreal(v2 / (accel * 2)));
1806 flickDuration =
int(1000 * qAbs(velocity) / accel);
1808 moveOffset.setValue(offset);
1809 tl.accel(moveOffset, velocity, accel, dist);
1810 tl.callback(QQuickTimeLineCallback(&moveOffset, fixOffsetCallback,
this));
1813 emit q->flickingChanged();
1814 emit q->flickStarted();
1822 q->movementEnding();
1825bool QQuickPathView::childMouseEventFilter(QQuickItem *i, QEvent *e)
1827 Q_D(QQuickPathView);
1828 if (!isVisible() || !d->interactive || !e->isPointerEvent())
1829 return QQuickItem::childMouseEventFilter(i, e);
1831 QPointerEvent *pe =
static_cast<QPointerEvent *>(e);
1832 if (QQuickDeliveryAgentPrivate::isMouseEvent(pe)) {
1835 const auto &point = pe->points().first();
1836 QPointF localPos = mapFromScene(point.scenePosition());
1837 QQuickItem *grabber = qmlobject_cast<QQuickItem *>(pe->exclusiveGrabber(point));
1838 if (grabber ==
this && d->stealMouse) {
1843 bool grabberDisabled = grabber && !grabber->isEnabled();
1844 bool stealThisEvent = d->stealMouse;
1845 if ((stealThisEvent || contains(localPos)) && (!grabber || !grabber->keepMouseGrab() || grabberDisabled)) {
1847 QMutableSinglePointEvent localizedEvent(*
static_cast<QMouseEvent *>(pe));
1848 QMutableEventPoint::setPosition(localizedEvent.point(0), localPos);
1849 localizedEvent.setAccepted(
false);
1851 switch (localizedEvent.type()) {
1852 case QEvent::MouseMove:
1853 d->handleMouseMoveEvent(
static_cast<QMouseEvent *>(
static_cast<QSinglePointEvent *>(&localizedEvent)));
1855 case QEvent::MouseButtonPress:
1856 d->handleMousePressEvent(
static_cast<QMouseEvent *>(
static_cast<QSinglePointEvent *>(&localizedEvent)));
1857 stealThisEvent = d->stealMouse;
1859 case QEvent::MouseButtonRelease:
1860 d->handleMouseReleaseEvent(
static_cast<QMouseEvent *>(
static_cast<QSinglePointEvent *>(&localizedEvent)));
1866 grabber = qmlobject_cast<QQuickItem *>(localizedEvent.exclusiveGrabber(localizedEvent.points().first()));
1867 if ((grabber && stealThisEvent && !grabber->keepMouseGrab() && grabber !=
this) || grabberDisabled)
1868 pe->setExclusiveGrabber(point,
this);
1870 const bool filtered = stealThisEvent || grabberDisabled;
1872 pe->setAccepted(stealThisEvent && grabber ==
this && grabber->isEnabled());
1875 }
else if (d->timer.isValid()) {
1876 d->timer.invalidate();
1879 if (pe->type() == QEvent::MouseButtonRelease || (grabber && grabber->keepMouseGrab() && !grabberDisabled))
1880 d->stealMouse =
false;
1884 return QQuickItem::childMouseEventFilter(i, e);
1887void QQuickPathView::mouseUngrabEvent()
1889 Q_D(QQuickPathView);
1890 if (d->stealMouse ||
1891 (!d->flicking && d->snapMode != NoSnap && !qFuzzyCompare(qRound(d->offset), d->offset))) {
1894 d->stealMouse =
false;
1895 setKeepMouseGrab(
false);
1896 d->timer.invalidate();
1898 d->setDragging(
false);
1899 if (!d->tl.isActive())
1904void QQuickPathView::updatePolish()
1906 QQuickItem::updatePolish();
1912 if (currentIndex < 0)
1913 return modelCount + currentIndex % modelCount;
1915 return currentIndex % modelCount;
1918void QQuickPathView::componentComplete()
1920 Q_D(QQuickPathView);
1921 if (d->model && d->ownModel)
1922 static_cast<QQmlDelegateModel *>(d->model.data())->componentComplete();
1924 QQuickItem::componentComplete();
1927 d->modelCount = d->model->count();
1928 if (d->modelCount && d->currentIndex != 0)
1929 d->offset = std::fmod(qreal(d->modelCount - currentIndexRemainder(d->currentIndex, d->modelCount)), qreal(d->modelCount));
1932 d->createHighlight();
1934 d->updateHighlight();
1938 emit countChanged();
1941void QQuickPathView::refill()
1943 Q_D(QQuickPathView);
1946 d->scheduleLayout();
1950 d->layoutScheduled =
false;
1952 if (!d->isValid() || !isComponentComplete())
1957 bool currentVisible =
false;
1958 int count = d->pathItems == -1 ? d->modelCount : qMin(d->pathItems, d->modelCount);
1961 qCDebug(lcItemViewDelegateLifecycle) <<
"currentIndex" << d->currentIndex <<
"offset" << d->offset;
1962 QList<QQuickItem*>::iterator it = d->items.begin();
1963 while (it != d->items.end()) {
1964 QQuickItem *item = *it;
1965 int idx = d->model->indexOf(item,
nullptr);
1966 qreal pos = d->positionOfIndex(idx);
1967 if (lcItemViewDelegateLifecycle().isDebugEnabled()) {
1968 QQuickText *text = qmlobject_cast<QQuickText*>(item);
1970 qCDebug(lcItemViewDelegateLifecycle) <<
"idx" << idx <<
"@" << pos <<
": QQuickText" << text->objectName() << QStringView{text->text()}.left(40);
1972 qCDebug(lcItemViewDelegateLifecycle) <<
"idx" << idx <<
"@" << pos <<
":" << item;
1975 d->updateItem(item, pos);
1976 if (idx == d->currentIndex) {
1977 currentVisible =
true;
1978 d->currentItemOffset = pos;
1982 d->updateItem(item, pos);
1983 if (QQuickPathViewAttached *att = d->attached(item))
1984 att->setOnPath(pos < 1);
1985 if (!d->isInBound(pos, d->mappedRange - d->mappedCache, 1 + d->mappedCache)) {
1986 qCDebug(lcItemViewDelegateLifecycle) <<
"release" << idx <<
"@" << pos <<
", !isInBound: lower" << (d->mappedRange - d->mappedCache) <<
"upper" << (1 + d->mappedCache);
1987 d->releaseItem(item);
1988 it = d->items.erase(it);
1995 bool waiting =
false;
1996 if (d->modelCount) {
1998 if (d->items.size() < count+d->cacheSize) {
2003 const bool wasEmpty = d->items.isEmpty();
2009 for (QQuickItem * item : std::as_const(d->items)) {
2010 int idx = d->model->indexOf(item,
nullptr);
2011 qreal curPos = d->positionOfIndex(idx);
2012 if (curPos > endPos) {
2017 if (curPos < startPos) {
2023 if (d->haveHighlightRange
2024 && (d->highlightRangeMode != QQuickPathView::NoHighlightRange
2025 || d->snapMode != QQuickPathView::NoSnap))
2026 startPos = d->highlightRangeStart;
2028 endIdx = (qRound(d->modelCount - d->offset) - 1) % d->modelCount;
2029 endIdx = qMax(-1, endIdx);
2030 endPos = d->positionOfIndex(endIdx);
2033 int idx = endIdx + 1;
2034 if (idx >= d->modelCount)
2036 qreal nextPos = d->positionOfIndex(idx);
2037 while ((d->isInBound(nextPos, endPos, 1 + d->mappedCache,
false) || !d->items.size())
2038 && d->items.size() < count + d->cacheSize) {
2039 qCDebug(lcItemViewDelegateLifecycle) <<
"append" << idx <<
"@" << nextPos << (d->currentIndex == idx ?
"current" :
"") <<
"items count was" << d->items.size();
2040 QQuickItem *item = d->getItem(idx, idx+1, nextPos >= 1);
2045 if (d->items.contains(item)) {
2046 d->releaseItem(item);
2049 if (d->currentIndex == idx) {
2050 currentVisible =
true;
2051 d->currentItemOffset = nextPos;
2053 d->items.append(item);
2054 d->updateItem(item, nextPos);
2058 if (idx >= d->modelCount)
2060 nextPos = d->positionOfIndex(idx);
2064 idx = (wasEmpty ? d->calcCurrentIndex() : startIdx) - 1;
2067 idx = d->modelCount - 1;
2068 nextPos = d->positionOfIndex(idx);
2069 while (!waiting && d->isInBound(nextPos, d->mappedRange - d->mappedCache, startPos)
2070 && d->items.size() < count+d->cacheSize) {
2071 qCDebug(lcItemViewDelegateLifecycle) <<
"prepend" << idx <<
"@" << nextPos << (d->currentIndex == idx ?
"current" :
"") <<
"items count was" << d->items.size();
2072 QQuickItem *item = d->getItem(idx, idx+1, nextPos >= 1);
2077 if (d->items.contains(item)) {
2078 d->releaseItem(item);
2081 if (d->currentIndex == idx) {
2082 currentVisible =
true;
2083 d->currentItemOffset = nextPos;
2085 d->items.prepend(item);
2086 d->updateItem(item, nextPos);
2091 idx = d->modelCount - 1;
2092 nextPos = d->positionOfIndex(idx);
2099 if (!waiting && d->items.size() < count+d->cacheSize) {
2100 qCDebug(lcItemViewDelegateLifecycle) <<
"Checking for pathview middle inserts, items count was" << d->items.size();
2102 QQuickItem *lastItem = d->items.at(0);
2103 while (idx != endIdx) {
2104 nextPos = d->positionOfIndex(idx);
2105 if (d->isInBound(nextPos, d->mappedRange - d->mappedCache, 1 + d->mappedCache)) {
2107 QQuickItem *item = d->getItem(idx, idx+1, nextPos >= 1);
2113 if (!d->items.contains(item)) {
2114 qCDebug(lcItemViewDelegateLifecycle) <<
"middle insert" << idx <<
"@" << nextPos
2115 << (d->currentIndex == idx ?
"current" :
"")
2116 <<
"items count was" << d->items.size();
2117 if (d->currentIndex == idx) {
2118 currentVisible =
true;
2119 d->currentItemOffset = nextPos;
2121 int lastListIdx = d->items.indexOf(lastItem);
2122 d->items.insert(lastListIdx + 1, item);
2123 d->updateItem(item, nextPos);
2125 d->releaseItem(item);
2132 if (idx >= d->modelCount)
2139 bool currentChanged =
false;
2140 if (!currentVisible) {
2141 d->currentItemOffset = 1;
2142 if (d->currentItem) {
2143 d->updateItem(d->currentItem, 1);
2144 }
else if (!waiting && d->currentIndex >= 0 && d->currentIndex < d->modelCount) {
2145 if ((d->currentItem = d->getItem(d->currentIndex, d->currentIndex))) {
2146 currentChanged =
true;
2147 d->updateItem(d->currentItem, 1);
2148 if (QQuickPathViewAttached *att = d->attached(d->currentItem))
2149 att->setIsCurrentItem(
true);
2152 }
else if (!waiting && !d->currentItem) {
2153 if ((d->currentItem = d->getItem(d->currentIndex, d->currentIndex))) {
2154 currentChanged =
true;
2155 d->currentItem->setFocus(
true);
2156 if (QQuickPathViewAttached *att = d->attached(d->currentItem))
2157 att->setIsCurrentItem(
true);
2161 if (d->highlightItem && d->haveHighlightRange && d->highlightRangeMode == QQuickPathView::StrictlyEnforceRange) {
2162 d->updateItem(d->highlightItem, d->highlightRangeStart);
2163 if (QQuickPathViewAttached *att = d->attached(d->highlightItem))
2164 att->setOnPath(
true);
2165 }
else if (d->highlightItem && d->moveReason != QQuickPathViewPrivate::SetIndex) {
2166 d->updateItem(d->highlightItem, d->currentItemOffset);
2167 if (QQuickPathViewAttached *att = d->attached(d->highlightItem))
2168 att->setOnPath(currentVisible);
2170 for (QQuickItem *item : std::as_const(d->itemCache))
2171 d->releaseItem(item);
2172 d->itemCache.clear();
2174 d->inRefill =
false;
2176 emit currentItemChanged();
2179void QQuickPathView::modelUpdated(
const QQmlChangeSet &changeSet,
bool reset)
2181 Q_D(QQuickPathView);
2182 if (!d->model || !d->model->isValid() || !d->path || !isComponentComplete())
2186 d->modelCount = d->model->count();
2188 emit countChanged();
2192 if (changeSet.removes().isEmpty() && changeSet.inserts().isEmpty())
2195 const int modelCount = d->modelCount;
2198 bool currentChanged =
false;
2199 bool changedOffset =
false;
2200 for (
const QQmlChangeSet::Change &r : changeSet.removes()) {
2201 if (moveId == -1 && d->currentIndex >= r.index + r.count) {
2202 d->currentIndex -= r.count;
2203 currentChanged =
true;
2204 }
else if (moveId == -1 && d->currentIndex >= r.index && d->currentIndex < r.index + r.count) {
2208 moveOffset = d->currentIndex - r.index;
2209 }
else if (d->currentItem) {
2210 if (QQuickPathViewAttached *att = d->attached(d->currentItem))
2211 att->setIsCurrentItem(
true);
2212 d->releaseCurrentItem();
2214 d->currentIndex = qMin(r.index, d->modelCount - r.count - 1);
2215 currentChanged =
true;
2218 if (r.index > d->currentIndex) {
2219 changedOffset =
true;
2220 d->offset -= r.count;
2221 d->offsetAdj -= r.count;
2223 d->modelCount -= r.count;
2225 for (
const QQmlChangeSet::Change &i : changeSet.inserts()) {
2226 if (d->modelCount) {
2227 if (moveId == -1 && i.index <= d->currentIndex) {
2228 d->currentIndex += i.count;
2229 currentChanged =
true;
2231 if (moveId != -1 && moveId == i.moveId) {
2232 d->currentIndex = i.index + moveOffset;
2233 currentChanged =
true;
2235 if (i.index > d->currentIndex) {
2236 d->offset += i.count;
2237 d->offsetAdj += i.count;
2238 changedOffset =
true;
2242 d->modelCount += i.count;
2245 d->offset = std::fmod(d->offset, qreal(d->modelCount));
2247 d->offset += d->modelCount;
2248 if (d->currentIndex == -1)
2249 d->currentIndex = d->calcCurrentIndex();
2251 d->itemCache += d->items;
2254 if (!d->modelCount) {
2255 for (QQuickItem * item : std::as_const(d->itemCache))
2256 d->releaseItem(item);
2257 d->itemCache.clear();
2259 changedOffset =
true;
2260 d->tl.reset(d->moveOffset);
2262 if (!d->flicking && !d->moving && d->haveHighlightRange && d->highlightRangeMode == QQuickPathView::StrictlyEnforceRange) {
2263 d->offset = std::fmod(qreal(d->modelCount - d->currentIndex), qreal(d->modelCount));
2264 changedOffset =
true;
2266 d->updateMappedRange();
2267 d->scheduleLayout();
2270 emit offsetChanged();
2272 emit currentIndexChanged();
2273 if (d->modelCount != modelCount)
2274 emit countChanged();
2277void QQuickPathView::destroyingItem(QObject *item)
2282void QQuickPathView::ticked()
2284 Q_D(QQuickPathView);
2288void QQuickPathView::movementEnding()
2290 Q_D(QQuickPathView);
2292 d->flicking =
false;
2293 emit flickingChanged();
2296 if (d->moving && !d->stealMouse) {
2298 emit movingChanged();
2299 emit movementEnded();
2301 d->moveDirection = d->movementDirection;
2308 if (modelCount && model && items.size()) {
2309 offset = std::fmod(offset, qreal(modelCount));
2311 offset += modelCount;
2312 current = qRound(qAbs(std::fmod(modelCount - offset, qreal(modelCount))));
2324 bool inItems =
false;
2325 for (QQuickItem *item : std::as_const(items)) {
2326 if (model->indexOf(item,
nullptr) == currentIndex) {
2333 if ((currentItem = getItem(currentIndex, currentIndex))) {
2334 currentItem->setFocus(
true);
2339 if ((currentItem = getItem(currentIndex, currentIndex))) {
2340 updateItem(currentItem, 1);
2349 Q_Q(QQuickPathView);
2352 if (!modelCount || !haveHighlightRange || highlightRangeMode != QQuickPathView::StrictlyEnforceRange)
2356 if (model && (idx != currentIndex || !currentItem)) {
2364 currentItem =
nullptr;
2367 emit q->currentIndexChanged();
2368 emit q->currentItemChanged();
2379 Q_Q(QQuickPathView);
2380 if (model && items.size()) {
2381 if (haveHighlightRange && (highlightRangeMode == QQuickPathView::StrictlyEnforceRange
2382 || snapMode != QQuickPathView::NoSnap)) {
2384 if (curr != currentIndex && highlightRangeMode == QQuickPathView::StrictlyEnforceRange)
2385 q->setCurrentIndex(curr);
2394 if (!model || modelCount <= 0)
2397 qreal targetOffset = std::fmod(qreal(modelCount - index), qreal(modelCount));
2400 tl.reset(moveOffset);
2401 moveOffset.setValue(offset);
2406 const qreal averageItemLength = path->path().length() / count;
2407 const qreal threshold = 0.5 / averageItemLength;
2409 if (!duration || qAbs(offset - targetOffset) < threshold || (qFuzzyIsNull(targetOffset) && qAbs(modelCount - offset) < threshold)) {
2410 tl.set(moveOffset, targetOffset);
2411 }
else if (moveDirection == QQuickPathView::Positive || (moveDirection == QQuickPathView::Shortest && targetOffset - offset > modelCount/2)) {
2412 qreal distance = modelCount - targetOffset + offset;
2413 if (targetOffset > moveOffset) {
2414 tl.move(moveOffset, 0, QEasingCurve(QEasingCurve::InQuad),
int(duration * offset / distance));
2415 tl.set(moveOffset, modelCount);
2416 tl.move(moveOffset, targetOffset, QEasingCurve(qFuzzyIsNull(offset) ? QEasingCurve::InOutQuad : QEasingCurve::OutQuad),
int(duration * (modelCount-targetOffset) / distance));
2418 tl.move(moveOffset, targetOffset, QEasingCurve(QEasingCurve::InOutQuad), duration);
2420 }
else if (moveDirection == QQuickPathView::Negative || targetOffset - offset <= -modelCount/2) {
2421 qreal distance = modelCount - offset + targetOffset;
2422 if (targetOffset < moveOffset) {
2423 tl.move(moveOffset, modelCount, QEasingCurve(qFuzzyIsNull(targetOffset) ? QEasingCurve::InOutQuad : QEasingCurve::InQuad),
int(duration * (modelCount-offset) / distance));
2424 tl.set(moveOffset, 0);
2425 tl.move(moveOffset, targetOffset, QEasingCurve(QEasingCurve::OutQuad),
int(duration * targetOffset / distance));
2427 tl.move(moveOffset, targetOffset, QEasingCurve(QEasingCurve::InOutQuad), duration);
2430 tl.move(moveOffset, targetOffset, QEasingCurve(QEasingCurve::InOutQuad), duration);
2434QQuickPathViewAttached *QQuickPathView::qmlAttachedProperties(QObject *obj)
2436 return new QQuickPathViewAttached(obj);
2441#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
Q_STATIC_LOGGING_CATEGORY(lcAccessibilityCore, "qt.accessibility.core")
#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