Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qquickgridview.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qquickgridview_p.h"
7
8#include <private/qqmlobjectmodel_p.h>
9#include <private/qquicksmoothedanimation_p_p.h>
10
11#include <QtGui/qevent.h>
12#include <QtCore/qmath.h>
13#include <QtCore/qcoreapplication.h>
14#include "qplatformdefs.h"
15
16#include <cmath>
17
19
20#ifndef QML_FLICK_SNAPONETHRESHOLD
21#define QML_FLICK_SNAPONETHRESHOLD 30
22#endif
23
24//----------------------------------------------------------------------------
25
27{
28public:
32
33 qreal position() const override {
34 return rowPos();
35 }
36
37 qreal endPosition() const override {
38 return endRowPos();
39 }
40
41 qreal size() const override {
43 }
44
45 qreal sectionSize() const override {
46 return 0.0;
47 }
48
55
56 qreal colPos() const {
59 qreal colSize = view->cellWidth();
60 int columns = view->width()/colSize;
61 return colSize * (columns-1) - itemX();
62 } else {
63 return itemX();
64 }
65 } else {
67 return -view->cellHeight() - itemY();
68 } else {
69 return itemY();
70 }
71 }
72 }
73 qreal endRowPos() const {
76 return -itemY();
77 else
78 return itemY() + view->cellHeight();
79 } else {
81 return -itemX();
82 else
83 return itemX() + view->cellWidth();
84 }
85 }
86 void setPosition(qreal col, qreal row, bool immediate = false) {
87 moveTo(pointForPosition(col, row), immediate);
88 }
89 bool contains(qreal x, qreal y) const override {
90 return (x >= itemX() && x < itemX() + view->cellWidth() &&
91 y >= itemY() && y < itemY() + view->cellHeight());
92 }
93
95
96private:
97 QPointF pointForPosition(qreal col, qreal row) const {
98 qreal x;
99 qreal y;
101 x = col;
102 y = row;
104 int columns = view->width()/view->cellWidth();
105 x = view->cellWidth() * (columns-1) - col;
106 }
107 } else {
108 x = row;
109 y = col;
111 x = -view->cellWidth() - row;
112 }
114 y = -view->cellHeight() - y;
115 return QPointF(x, y);
116 }
117};
118
119//----------------------------------------------------------------------------
120
122{
123 Q_DECLARE_PUBLIC(QQuickGridView)
124
125public:
126 Qt::Orientation layoutOrientation() const override;
127 bool isContentFlowReversed() const override;
128
129 qreal positionAt(int index) const override;
130 qreal endPositionAt(int index) const override;
131 qreal originPosition() const override;
132 qreal lastPosition() const override;
133
134 qreal rowSize() const;
135 qreal colSize() const;
136 qreal colPosAt(int modelIndex) const;
137 qreal rowPosAt(int modelIndex) const;
138 qreal snapPosAt(qreal pos) const;
140 int snapIndex() const;
143
144 void resetColumns();
145
146 bool addVisibleItems(qreal fillFrom, qreal fillTo, qreal bufferFrom, qreal bufferTo, bool doBuffer) override;
147 bool removeNonVisibleItems(qreal bufferFrom, qreal bufferTo) override;
148
150
151 FxViewItem *newViewItem(int index, QQuickItem *item) override;
152 void initializeViewItem(FxViewItem *item) override;
153 void repositionItemAt(FxViewItem *item, int index, qreal sizeBuffer) override;
154 void repositionPackageItemAt(QQuickItem *item, int index) override;
155 void resetFirstItemPosition(qreal pos = 0.0) override;
156 void adjustFirstItem(qreal forwards, qreal backwards, int changeBeforeVisible) override;
157
158 void createHighlight(bool onDestruction = false) override;
159 void updateHighlight() override;
160 void resetHighlightPosition() override;
161
162 void setPosition(qreal pos) override;
163 void layoutVisibleItems(int fromModelIndex = 0) override;
164 bool applyInsertionChange(const QQmlChangeSet::Change &insert, ChangeResult *changeResult, QList<FxViewItem *> *addedItems, QList<MovedItem> *movingIntoView) override;
165#if QT_CONFIG(quick_viewtransitions)
166 void translateAndTransitionItemsAfter(int afterModelIndex, const ChangeResult &insertionResult, const ChangeResult &removalResult) override;
167#endif
168 bool needsRefillForAddedOrRemovedIndex(int index) const override;
169
170 qreal headerSize() const override;
171 qreal footerSize() const override;
172 bool showHeaderForIndex(int index) const override;
173 bool showFooterForIndex(int index) const override;
174 void updateHeader() override;
175 void updateFooter() override;
176
177 void initializeComponentItem(QQuickItem *item) const override;
178
179 void changedVisibleIndex(int newIndex) override;
180 void initializeCurrentItem() override;
181
182 void updateViewport() override;
183 void fixupPosition() override;
184 void fixup(AxisData &data, qreal minExtent, qreal maxExtent) override;
186 QQuickTimeLineCallback::Callback fixupCallback, QEvent::Type eventType, qreal velocity) override;
187
193
196
204 {
205 delete highlightXAnimator;
206 delete highlightYAnimator;
207 }
208};
209
214
222
224{
225 visibleIndex = newIndex / columns * columns;
226}
227
229{
230 Q_Q(QQuickGridView);
231 q->QQuickFlickable::setContentX(contentXForPosition(pos));
232 q->QQuickFlickable::setContentY(contentYForPosition(pos));
233}
234
236{
237 qreal pos = 0;
238 if (!visibleItems.isEmpty())
239 pos = static_cast<FxGridItemSG*>(visibleItems.first())->rowPos() - visibleIndex / columns * rowSize();
240 return pos;
241}
242
244{
245 qreal pos = 0;
246 if (model && (model->count() || !visibleItems.isEmpty())) {
247 qreal lastRowPos = model->count() ? rowPosAt(model->count() - 1) : 0;
248 if (!visibleItems.isEmpty()) {
249 // If there are items in delayRemove state, they may be after any items linked to the model
250 lastRowPos = qMax(lastRowPos, static_cast<FxGridItemSG*>(visibleItems.last())->rowPos());
251 }
252 pos = lastRowPos + rowSize();
253 }
254 return pos;
255}
256
261
266
273
275{
276 if (FxViewItem *item = visibleItem(modelIndex))
277 return static_cast<FxGridItemSG*>(item)->colPos();
278 if (!visibleItems.isEmpty()) {
279 if (modelIndex == visibleIndex) {
280 FxGridItemSG *firstItem = static_cast<FxGridItemSG*>(visibleItems.first());
281 return firstItem->colPos();
282 } else if (modelIndex < visibleIndex) {
283 int count = (visibleIndex - modelIndex) % columns;
284 int col = static_cast<FxGridItemSG*>(visibleItems.first())->colPos() / colSize();
285 col = (columns - count + col) % columns;
286 return col * colSize();
287 } else {
288 FxGridItemSG *lastItem = static_cast<FxGridItemSG*>(visibleItems.last());
289 int count = modelIndex - lastItem->index;
290 int col = lastItem->colPos() / colSize();
291 col = (col + count) % columns;
292 return col * colSize();
293 }
294 }
295 return (modelIndex % columns) * colSize();
296}
297
299{
300 if (FxViewItem *item = visibleItem(modelIndex))
301 return static_cast<FxGridItemSG*>(item)->rowPos();
302 if (!visibleItems.isEmpty()) {
303 if (modelIndex == visibleIndex) {
304 FxGridItemSG *firstItem = static_cast<FxGridItemSG*>(visibleItems.first());
305 return firstItem->rowPos();
306 } else if (modelIndex < visibleIndex) {
307 FxGridItemSG *firstItem = static_cast<FxGridItemSG*>(visibleItems.first());
308 int firstCol = firstItem->colPos() / colSize();
309 int col = visibleIndex - modelIndex + (columns - firstCol - 1);
310 int rows = col / columns;
311 return firstItem->rowPos() - rows * rowSize();
312 } else {
313 FxGridItemSG *lastItem = static_cast<FxGridItemSG*>(visibleItems.last());
314 int count = modelIndex - lastItem->index;
315 int col = lastItem->colPos() + count * colSize();
316 int rows = col / (columns * colSize());
317 return lastItem->rowPos() + rows * rowSize();
318 }
319 }
320
321 qreal rowPos = ((modelIndex / columns) * rowSize());
322
324 // Add the effective startpos of row 0. Start by subtracting minExtent, which will contain the
325 // height of the rows outside the beginning of the content item. (Rows can end up outside if
326 // e.g flicking the viewport a long way down, changing cellSize, and then flick back).
327 // NOTE: It's not clearly understood why the flow == QQuickGridView::FlowLeftToRight guard is
328 // needed, since the flow shouldn't normally affect the y postition of an index. But without
329 // it, several auto tests start failing, so we keep it until this part is better understood.
330 rowPos -= minExtent;
331 // minExtent will also contain the size of the topMargin (vData.startMargin), the header, and
332 // the highlightRangeStart. Those should be added before the start of row 0. So we need to subtract
333 // them from the rowPos. But only the largest of topMargin and highlightRangeStart will need
334 // to be taken into account, since having a topMargin will also ensure that currentItem ends
335 // up within the requested highlight range when view is positioned at the beginning.
337 }
338
339 return rowPos;
340}
341
343{
344 Q_Q(const QQuickGridView);
345 qreal snapPos = 0;
346 if (!visibleItems.isEmpty()) {
347 qreal highlightStart = highlightRangeStart;
348 pos += highlightStart;
349 pos += rowSize()/2;
350 snapPos = static_cast<FxGridItemSG*>(visibleItems.first())->rowPos() - visibleIndex / columns * rowSize();
351 snapPos = pos - std::fmod(pos - snapPos, qreal(rowSize()));
352 snapPos -= highlightStart;
355 if (isContentFlowReversed()) {
356 maxExtent = q->minXExtent()-size();
357 minExtent = q->maxXExtent()-size();
358 } else {
359 maxExtent = flow == QQuickGridView::FlowLeftToRight ? -q->maxYExtent() : -q->maxXExtent();
360 minExtent = flow == QQuickGridView::FlowLeftToRight ? -q->minYExtent() : -q->minXExtent();
361 }
362 if (snapPos > maxExtent)
363 snapPos = maxExtent;
364 if (snapPos < minExtent)
365 snapPos = minExtent;
366 }
367 return snapPos;
368}
369
371{
372 for (FxViewItem *item : visibleItems) {
373 if (item->index == -1)
374 continue;
375 qreal itemTop = item->position();
376 if (itemTop+rowSize()/2 >= pos && itemTop - rowSize()/2 <= pos)
377 return item;
378 }
379 return nullptr;
380}
381
383{
384 int index = currentIndex;
385 for (FxViewItem *item : visibleItems) {
386 if (item->index == -1)
387 continue;
388 qreal itemTop = item->position();
389 FxGridItemSG *hItem = static_cast<FxGridItemSG*>(highlight.get());
390 if (itemTop >= hItem->rowPos()-rowSize()/2 && itemTop < hItem->rowPos()+rowSize()/2) {
391 FxGridItemSG *gridItem = static_cast<FxGridItemSG*>(item);
392 index = gridItem->index;
393 if (gridItem->colPos() >= hItem->colPos()-colSize()/2 && gridItem->colPos() < hItem->colPos()+colSize()/2)
394 return gridItem->index;
395 }
396 }
397 return index;
398}
399
401{
402 Q_Q(const QQuickGridView);
404 // vertical scroll
405 if (q->effectiveLayoutDirection() == Qt::LeftToRight) {
406 return -q->leftMargin();
407 } else {
409 int columns = (q->width() - q->leftMargin() - q->rightMargin()) / colSize;
410 return -q->width() + q->rightMargin() + (cellWidth * columns);
411 }
412 } else {
413 // horizontal scroll
414 if (q->effectiveLayoutDirection() == Qt::LeftToRight)
415 return pos;
416 else
417 return -pos - q->width();
418 }
419}
420
422{
423 Q_Q(const QQuickGridView);
425 // vertical scroll
427 return pos;
428 else
429 return -pos - q->height();
430 } else {
431 // horizontal scroll
433 return -q->topMargin();
434 else
435 return -q->height() + q->bottomMargin();
436 }
437}
438
440{
441 Q_Q(QQuickGridView);
443 ? q->width() - q->leftMargin() - q->rightMargin()
444 : q->height() - q->topMargin() - q->bottomMargin();
445 columns = qMax(1, qFloor(length / colSize()));
446}
447
449{
450 Q_Q(QQuickGridView);
451 Q_UNUSED(modelIndex);
452 return new FxGridItemSG(item, q, false);
453}
454
456{
458
459 // need to track current items that are animating
460 item->trackGeometry(true);
461}
462
463bool QQuickGridViewPrivate::addVisibleItems(qreal fillFrom, qreal fillTo, qreal bufferFrom, qreal bufferTo, bool doBuffer)
464{
465 qreal colPos = colPosAt(visibleIndex);
466 qreal rowPos = rowPosAt(visibleIndex);
467 if (visibleItems.size()) {
468 FxGridItemSG *lastItem = static_cast<FxGridItemSG*>(visibleItems.constLast());
469 rowPos = lastItem->rowPos();
470 int colNum = qFloor((lastItem->colPos()+colSize()/2) / colSize());
471 if (++colNum >= columns) {
472 colNum = 0;
473 rowPos += rowSize();
474 }
475 colPos = colNum * colSize();
476 }
477
478 int modelIndex = findLastVisibleIndex();
479 modelIndex = modelIndex < 0 ? visibleIndex : modelIndex + 1;
480
481 if (visibleItems.size() && (bufferFrom > rowPos + rowSize()*2
482 || bufferTo < rowPosAt(visibleIndex) - rowSize())) {
483 // We've jumped more than a page. Estimate which items are now
484 // visible and fill from there.
485 int count = (fillFrom - (rowPos + rowSize())) / (rowSize()) * columns;
487 modelIndex += count;
488 if (modelIndex >= model->count())
489 modelIndex = model->count() - 1;
490 else if (modelIndex < 0)
491 modelIndex = 0;
492 modelIndex = modelIndex / columns * columns;
493 visibleIndex = modelIndex;
494 colPos = colPosAt(visibleIndex);
495 rowPos = rowPosAt(visibleIndex);
496 }
497
498 int colNum = qFloor((colPos+colSize()/2) / colSize());
499 FxGridItemSG *item = nullptr;
500 bool changed = false;
501
503
504 while (modelIndex < model->count() && rowPos <= fillTo + rowSize()*(columns - colNum)/(columns+1)) {
505 qCDebug(lcItemViewDelegateLifecycle) << "refill: append item" << modelIndex << colPos << rowPos;
506 if (!(item = static_cast<FxGridItemSG*>(createItem(modelIndex, incubationMode))))
507 break;
508#if QT_CONFIG(quick_viewtransitions)
509 if (!transitioner || !transitioner->canTransition(QQuickItemViewTransitioner::PopulateTransition, true)) // pos will be set by layoutVisibleItems()
510 item->setPosition(colPos, rowPos, true);
511#endif
512 QQuickItemPrivate::get(item->item)->setCulled(doBuffer);
514 if (++colNum >= columns) {
515 colNum = 0;
516 rowPos += rowSize();
517 }
518 colPos = colNum * colSize();
519 ++modelIndex;
520 changed = true;
521 }
522
523 if (doBuffer && requestedIndex != -1) // already waiting for an item
524 return changed;
525
526 // Find first column
527 if (visibleItems.size()) {
528 FxGridItemSG *firstItem = static_cast<FxGridItemSG*>(visibleItems.constFirst());
529 rowPos = firstItem->rowPos();
530 colPos = firstItem->colPos();
531 }
532 colNum = qFloor((colPos+colSize()/2) / colSize());
533 if (--colNum < 0) {
534 colNum = columns - 1;
535 rowPos -= rowSize();
536 }
537
538 // Prepend
539 colPos = colNum * colSize();
540 while (visibleIndex > 0 && rowPos + rowSize() - 1 >= fillFrom - rowSize()*(colNum+1)/(columns+1)){
541 qCDebug(lcItemViewDelegateLifecycle) << "refill: prepend item" << visibleIndex-1 << "top pos" << rowPos << colPos;
542 if (!(item = static_cast<FxGridItemSG*>(createItem(visibleIndex-1, incubationMode))))
543 break;
544 --visibleIndex;
545#if QT_CONFIG(quick_viewtransitions)
546 if (!transitioner || !transitioner->canTransition(QQuickItemViewTransitioner::PopulateTransition, true)) // pos will be set by layoutVisibleItems()
547 item->setPosition(colPos, rowPos, true);
548#endif
549 QQuickItemPrivate::get(item->item)->setCulled(doBuffer);
551 if (--colNum < 0) {
552 colNum = columns-1;
553 rowPos -= rowSize();
554 }
555 colPos = colNum * colSize();
556 changed = true;
557 }
558
559 return changed;
560}
561
563{
564#if QT_CONFIG(quick_viewtransitions)
565 if (item->transitionScheduledOrRunning()) {
566 qCDebug(lcItemViewDelegateLifecycle) << "\tnot releasing animating item:" << item->index << item->item->objectName();
567 item->releaseAfterTransition = true;
568 releasePendingTransition.append(item);
569 } else
570#endif
571 {
573 }
574}
575
577{
578 FxGridItemSG *item = nullptr;
579 bool changed = false;
580
581 while (visibleItems.size() > 1
582 && (item = static_cast<FxGridItemSG*>(visibleItems.constFirst()))
583 && item->rowPos()+rowSize()-1 < bufferFrom - rowSize()*(item->colPos()/colSize()+1)/(columns+1)) {
584 if (item->attached->delayRemove())
585 break;
586 qCDebug(lcItemViewDelegateLifecycle) << "refill: remove first" << visibleIndex << "top end pos" << item->endRowPos();
587 if (item->index != -1)
588 visibleIndex++;
591 changed = true;
592 }
593 while (visibleItems.size() > 1
594 && (item = static_cast<FxGridItemSG*>(visibleItems.constLast()))
595 && item->rowPos() > bufferTo + rowSize()*(columns - item->colPos()/colSize())/(columns+1)) {
596 if (item->attached->delayRemove())
597 break;
598 qCDebug(lcItemViewDelegateLifecycle) << "refill: remove last" << visibleIndex+visibleItems.size()-1;
601 changed = true;
602 }
603
604 return changed;
605}
606
612
614{
615 if (visibleItems.size()) {
618
619 FxGridItemSG *firstItem = static_cast<FxGridItemSG*>(visibleItems.constFirst());
620 qreal rowPos = firstItem->rowPos();
621 qreal colPos = firstItem->colPos();
622 int col = visibleIndex % columns;
623 if (colPos != col * colSize()) {
624 colPos = col * colSize();
625 firstItem->setPosition(colPos, rowPos);
626 }
627 firstItem->setVisible(firstItem->rowPos() + rowSize() >= from && firstItem->rowPos() <= to);
628 for (int i = 1; i < visibleItems.size(); ++i) {
629 FxGridItemSG *item = static_cast<FxGridItemSG*>(visibleItems.at(i));
630 if (++col >= columns) {
631 col = 0;
632 rowPos += rowSize();
633 }
634 colPos = col * colSize();
635 if (item->index >= fromModelIndex) {
636 item->setPosition(colPos, rowPos);
637 item->setVisible(item->rowPos() + rowSize() >= from && item->rowPos() <= to);
638 }
639 }
640 }
641}
642
644{
645 int count = sizeBuffer / rowSize();
647}
648
650{
651 Q_Q(QQuickGridView);
652 qreal pos = position();
654 if (item->y() + item->height() > pos && item->y() < pos + q->height()) {
656 ? rowPosAt(index)
657 : -rowPosAt(index) - item->height();
658 item->setPosition(QPointF(colPosAt(index), y));
659 }
660 } else {
661 if (item->x() + item->width() > pos && item->x() < pos + q->width()) {
663 ? colPosAt(index)
664 : -colPosAt(index) - item->height();
665 if (flow == QQuickGridView::FlowTopToBottom && q->effectiveLayoutDirection() == Qt::RightToLeft)
666 item->setPosition(QPointF(-rowPosAt(index)-item->width(), y));
667 else
668 item->setPosition(QPointF(rowPosAt(index), y));
669 }
670 }
671}
672
678
679void QQuickGridViewPrivate::adjustFirstItem(qreal forwards, qreal backwards, int changeBeforeVisible)
680{
681 if (!visibleItems.size())
682 return;
683
684 int moveCount = (forwards - backwards) / rowSize();
685 if (moveCount == 0 && changeBeforeVisible != 0)
686 moveCount += (changeBeforeVisible % columns) - (columns - 1);
687
688 FxGridItemSG *gridItem = static_cast<FxGridItemSG*>(visibleItems.constFirst());
689 gridItem->setPosition(gridItem->colPos(), gridItem->rowPos() + ((moveCount / columns) * rowSize()));
690}
691
693{
694 bool changed = false;
695 if (highlight) {
696 if (trackedItem == highlight.get())
697 trackedItem = nullptr;
698 highlight.reset();
699
700 delete highlightXAnimator;
701 delete highlightYAnimator;
702 highlightXAnimator = nullptr;
703 highlightYAnimator = nullptr;
704
705 changed = true;
706 }
707
708 if (onDestruction)
709 return;
710
711 Q_Q(QQuickGridView);
712 if (currentItem) {
714 if (item) {
715 std::unique_ptr<FxGridItemSG> newHighlight
716 = std::make_unique<FxGridItemSG>(item, q, true);
717 newHighlight->trackGeometry(true);
718 if (autoHighlight)
726
727 highlight = std::move(newHighlight);
728 changed = true;
729 }
730 }
731 if (changed)
732 emit q->highlightItemChanged();
733}
734
736{
738
739 if ((!currentItem && highlight) || (currentItem && !highlight))
742 if (currentItem && autoHighlight && highlight && (!strictHighlight || !pressed)) {
743 // auto-update highlight
746 highlight->item->setSize(currentItem->item->size());
747
750 }
752}
753
755{
756 if (highlight && currentItem) {
757 FxGridItemSG *cItem = static_cast<FxGridItemSG*>(currentItem);
758 static_cast<FxGridItemSG *>(highlight.get())->setPosition(cItem->colPos(), cItem->rowPos());
759 }
760}
761
763{
764 if (!header)
765 return 0.0;
767}
768
770{
771 if (!footer)
772 return 0.0;
774}
775
777{
778 return index / columns == 0;
779}
780
782{
783 return index / columns == (model->count()-1) / columns;
784}
785
787{
788 Q_Q(QQuickGridView);
789 bool created = false;
790 if (!footer) {
792 if (!item)
793 return;
794 footer = new FxGridItemSG(item, q, true);
795 footer->trackGeometry(true);
796 created = true;
797 }
798
799 FxGridItemSG *gridItem = static_cast<FxGridItemSG*>(footer);
800 qreal colOffset = 0;
801 qreal rowOffset = 0;
802 if (q->effectiveLayoutDirection() == Qt::RightToLeft) {
804 rowOffset += gridItem->item->width() - cellWidth;
805 else
806 colOffset += gridItem->item->width() - cellWidth;
807 }
810 colOffset += gridItem->item->height() - cellHeight;
811 else
812 rowOffset += gridItem->item->height() - cellHeight;
813 }
814 if (visibleItems.size()) {
815 qreal endPos = lastPosition();
816 if (findLastVisibleIndex() == model->count()-1) {
817 gridItem->setPosition(colOffset, endPos + rowOffset);
818 } else {
819 qreal visiblePos = isContentFlowReversed() ? -position() : position() + size();
820 if (endPos <= visiblePos || gridItem->endPosition() <= endPos + rowOffset)
821 gridItem->setPosition(colOffset, endPos + rowOffset);
822 }
823 } else {
824 gridItem->setPosition(colOffset, rowOffset);
825 }
826
827 if (created)
828 emit q->footerItemChanged();
829}
830
832{
833 QQuickGridViewAttached *attached = static_cast<QQuickGridViewAttached *>(
834 qmlAttachedPropertiesObject<QQuickGridView>(item));
835 if (attached)
836 attached->setView(const_cast<QQuickGridView*>(q_func()));
837}
838
840{
841 Q_Q(QQuickGridView);
842 bool created = false;
843 if (!header) {
845 if (!item)
846 return;
847 header = new FxGridItemSG(item, q, true);
848 header->trackGeometry(true);
849 created = true;
850 }
851
852 FxGridItemSG *gridItem = static_cast<FxGridItemSG*>(header);
853 qreal colOffset = 0;
854 qreal rowOffset = -headerSize();
855 if (q->effectiveLayoutDirection() == Qt::RightToLeft) {
857 rowOffset += gridItem->item->width() - cellWidth;
858 else
859 colOffset += gridItem->item->width() - cellWidth;
860 }
863 colOffset += gridItem->item->height() - cellHeight;
864 else
865 rowOffset += gridItem->item->height() - cellHeight;
866 }
867 if (visibleItems.size()) {
868 qreal startPos = originPosition();
869 if (visibleIndex == 0) {
870 gridItem->setPosition(colOffset, startPos + rowOffset);
871 } else {
872 qreal tempPos = isContentFlowReversed() ? -position()-size() : position();
873 qreal headerPos = isContentFlowReversed() ? gridItem->rowPos() + cellWidth - headerSize() : gridItem->rowPos();
874 if (tempPos <= startPos || headerPos > startPos + rowOffset)
875 gridItem->setPosition(colOffset, startPos + rowOffset);
876 }
877 } else {
879 gridItem->setPosition(colOffset, rowOffset);
880 else
881 gridItem->setPosition(colOffset, -headerSize());
882 }
883
884 if (created)
885 emit q->headerItemChanged();
886}
887
889{
890 if (currentItem && currentIndex >= 0) {
891 FxGridItemSG *gridItem = static_cast<FxGridItemSG*>(currentItem);
892 FxViewItem *actualItem = visibleItem(currentIndex);
893
894 // don't reposition the item if it's about to be transitioned to another position
895 if ((!actualItem
896#if QT_CONFIG(quick_viewtransitions)
897 || !actualItem->transitionScheduledOrRunning()
898#endif
899 ))
900 gridItem->setPosition(colPosAt(currentIndex), rowPosAt(currentIndex));
901 }
902}
903
911
913{
916 return;
917
919
920 qreal viewPos = isContentFlowReversed() ? -position()-size() : position();
921
924 qreal tempPosition = isContentFlowReversed() ? -position()-size() : position();
926 // if we've been dragged < rowSize()/2 then bias towards the next row
927 qreal dist = data.move.value() - data.pressPos;
928 qreal bias = 0;
929 if (data.velocity > 0 && dist > QML_FLICK_SNAPONETHRESHOLD && dist < rowSize()/2)
930 bias = rowSize()/2;
931 else if (data.velocity < 0 && dist < -QML_FLICK_SNAPONETHRESHOLD && dist > -rowSize()/2)
932 bias = -rowSize()/2;
934 bias = -bias;
935 tempPosition -= bias;
936 }
937 FxViewItem *topItem = snapItemAt(tempPosition+highlightRangeStart);
938 if (strictHighlightRange && currentItem && (!topItem || (topItem->index != currentIndex && fixupMode == Immediate))) {
939 // StrictlyEnforceRange always keeps an item in range
941 topItem = currentItem;
942 }
943 FxViewItem *bottomItem = snapItemAt(tempPosition+highlightRangeEnd);
944 if (strictHighlightRange && currentItem && (!bottomItem || (bottomItem->index != currentIndex && fixupMode == Immediate))) {
945 // StrictlyEnforceRange always keeps an item in range
947 bottomItem = currentItem;
948 }
949 qreal pos;
950 bool isInBounds = -position() > maxExtent && -position() <= minExtent;
951 if (topItem && (isInBounds || strictHighlightRange)) {
952 qreal headerPos = header ? static_cast<FxGridItemSG*>(header)->rowPos() : 0;
953 if (topItem->index == 0 && header && tempPosition+highlightRangeStart < headerPos+headerSize()/2 && !strictHighlightRange) {
954 pos = isContentFlowReversed() ? - headerPos + highlightRangeStart - size() : headerPos - highlightRangeStart;
955 } else {
957 pos = qMax(qMin(-topItem->position() + highlightRangeStart - size(), -maxExtent), -minExtent);
958 else
959 pos = qMax(qMin(topItem->position() - highlightRangeStart, -maxExtent), -minExtent);
960 }
961 } else if (bottomItem && isInBounds) {
963 pos = qMax(qMin(-bottomItem->position() + highlightRangeEnd - size(), -maxExtent), -minExtent);
964 else
965 pos = qMax(qMin(bottomItem->position() - highlightRangeEnd, -maxExtent), -minExtent);
966 } else {
968 return;
969 }
970
971 qreal dist = qAbs(data.move + pos);
972 if (dist > 0) {
973 timeline.reset(data.move);
974 if (fixupMode != Immediate) {
976 data.fixingUp = true;
977 } else {
978 timeline.set(data.move, -pos);
979 }
980 vTime = timeline.time();
981 }
983 if (currentItem) {
985 qreal pos = static_cast<FxGridItemSG*>(currentItem)->rowPos();
986 if (viewPos < pos + rowSize() - highlightRangeEnd)
987 viewPos = pos + rowSize() - highlightRangeEnd;
988 if (viewPos > pos - highlightRangeStart)
989 viewPos = pos - highlightRangeStart;
991 viewPos = -viewPos-size();
992 timeline.reset(data.move);
993 if (viewPos != position()) {
994 if (fixupMode != Immediate) {
996 data.fixingUp = true;
997 } else {
998 timeline.set(data.move, -viewPos);
999 }
1000 }
1001 vTime = timeline.time();
1002 }
1003 } else {
1005 }
1006 data.inOvershoot = false;
1007 fixupMode = Normal;
1008}
1009
1010bool QQuickGridViewPrivate::flick(AxisData &data, qreal minExtent, qreal maxExtent, qreal vSize,
1011 QQuickTimeLineCallback::Callback fixupCallback, QEvent::Type eventType, qreal velocity)
1012{
1013 data.fixingUp = false;
1014 moveReason = Mouse;
1017 return QQuickItemViewPrivate::flick(data, minExtent, maxExtent, vSize, fixupCallback, eventType, velocity);
1018 }
1019 qreal maxDistance = 0;
1020 qreal dataValue = isContentFlowReversed() ? -data.move.value()+size() : data.move.value();
1021 // -ve velocity means list is moving up/left
1022 if (velocity > 0) {
1023 if (data.move.value() < minExtent) {
1025 // if we've been dragged < averageSize/2 then bias towards the next item
1026 qreal dist = data.move.value() - data.pressPos;
1027 qreal bias = dist < rowSize()/2 ? rowSize()/2 : 0;
1029 bias = -bias;
1030 data.flickTarget = -snapPosAt(-dataValue - bias);
1031 maxDistance = qAbs(data.flickTarget - data.move.value());
1032 velocity = maxVelocity;
1033 } else {
1034 maxDistance = qAbs(minExtent - data.move.value());
1035 }
1036 }
1038 data.flickTarget = minExtent;
1039 } else {
1040 if (data.move.value() > maxExtent) {
1042 // if we've been dragged < averageSize/2 then bias towards the next item
1043 qreal dist = data.move.value() - data.pressPos;
1044 qreal bias = -dist < rowSize()/2 ? rowSize()/2 : 0;
1046 bias = -bias;
1047 data.flickTarget = -snapPosAt(-dataValue + bias);
1048 maxDistance = qAbs(data.flickTarget - data.move.value());
1049 velocity = -maxVelocity;
1050 } else {
1051 maxDistance = qAbs(maxExtent - data.move.value());
1052 }
1053 }
1055 data.flickTarget = maxExtent;
1056 }
1058 if (maxDistance > 0 || overShoot) {
1059 // This mode requires the grid to stop exactly on a row boundary.
1060 qreal v = velocity;
1061 if (maxVelocity != -1 && maxVelocity < qAbs(v)) {
1062 if (v < 0)
1063 v = -maxVelocity;
1064 else
1065 v = maxVelocity;
1066 }
1067 qreal accel = eventType == QEvent::Wheel ? wheelDeceleration : deceleration;
1068 qreal v2 = v * v;
1069 qreal overshootDist = 0.0;
1070 if ((maxDistance > 0.0 && v2 / (2.0f * maxDistance) < accel) || snapMode == QQuickGridView::SnapOneRow) {
1071 // + rowSize()/4 to encourage moving at least one item in the flick direction
1072 qreal dist = v2 / (accel * 2.0) + rowSize()/4;
1073 dist = qMin(dist, maxDistance);
1074 if (v > 0)
1075 dist = -dist;
1077 qreal distTemp = isContentFlowReversed() ? -dist : dist;
1078 data.flickTarget = -snapPosAt(-dataValue + distTemp);
1079 }
1080 data.flickTarget = isContentFlowReversed() ? -data.flickTarget+size() : data.flickTarget;
1081 if (overShoot) {
1082 if (data.flickTarget >= minExtent) {
1083 overshootDist = overShootDistance(vSize);
1084 data.flickTarget += overshootDist;
1085 } else if (data.flickTarget <= maxExtent) {
1086 overshootDist = overShootDistance(vSize);
1087 data.flickTarget -= overshootDist;
1088 }
1089 }
1090 qreal adjDist = -data.flickTarget + data.move.value();
1091 if (qAbs(adjDist) > qAbs(dist)) {
1092 // Prevent painfully slow flicking - adjust velocity to suit flickDeceleration
1093 qreal adjv2 = accel * 2.0f * qAbs(adjDist);
1094 if (adjv2 > v2) {
1095 v2 = adjv2;
1096 v = qSqrt(v2);
1097 if (dist > 0)
1098 v = -v;
1099 }
1100 }
1101 dist = adjDist;
1102 accel = v2 / (2.0f * qAbs(dist));
1103 } else {
1104 data.flickTarget = velocity > 0 ? minExtent : maxExtent;
1105 overshootDist = overShoot ? overShootDistance(vSize) : 0;
1106 }
1107 timeline.reset(data.move);
1108 timeline.accel(data.move, v, accel, maxDistance + overshootDist);
1109 timeline.callback(QQuickTimeLineCallback(&data.move, fixupCallback, this));
1110 return true;
1111 } else {
1112 timeline.reset(data.move);
1114 return false;
1115 }
1116}
1117
1118
1119//----------------------------------------------------------------------------
1254
1256{
1257 Q_D(QQuickGridView);
1258 if (d->autoHighlight != autoHighlight) {
1259 if (!autoHighlight && d->highlightXAnimator) {
1260 d->highlightXAnimator->stop();
1261 d->highlightYAnimator->stop();
1262 }
1264 }
1265}
1266
1630{
1631 Q_D(QQuickGridView);
1632 if (d->highlightMoveDuration != duration) {
1633 if (d->highlightYAnimator) {
1634 d->highlightXAnimator->userDuration = duration;
1635 d->highlightYAnimator->userDuration = duration;
1636 }
1638 }
1639}
1640
1651{
1652 Q_D(const QQuickGridView);
1653 return d->flow;
1654}
1655
1657{
1658 Q_D(QQuickGridView);
1659 if (d->flow != flow) {
1660 d->flow = flow;
1661 if (d->flow == FlowLeftToRight) {
1662 setContentWidth(-1);
1664 } else {
1665 setContentHeight(-1);
1667 }
1668 setContentX(0);
1669 setContentY(0);
1670 d->regenerate(true);
1671 emit flowChanged();
1672 }
1673}
1674
1675
1685{
1686 Q_D(const QQuickGridView);
1687 return d->cellWidth;
1688}
1689
1691{
1692 Q_D(QQuickGridView);
1693 if (cellWidth != d->cellWidth && cellWidth > 0) {
1694 d->cellWidth = qMax(qreal(1), cellWidth);
1695 d->updateViewport();
1697 d->forceLayoutPolish();
1698 QQuickFlickable::setContentX(d->contentXForPosition(d->position()));
1699 }
1700}
1701
1703{
1704 Q_D(const QQuickGridView);
1705 return d->cellHeight;
1706}
1707
1709{
1710 Q_D(QQuickGridView);
1711 if (cellHeight != d->cellHeight && cellHeight > 0) {
1712 d->cellHeight = qMax(qreal(1), cellHeight);
1713 d->updateViewport();
1715 d->forceLayoutPolish();
1716 QQuickFlickable::setContentY(d->contentYForPosition(d->position()));
1717 }
1718}
1733{
1734 Q_D(const QQuickGridView);
1735 return d->snapMode;
1736}
1737
1739{
1740 Q_D(QQuickGridView);
1741 if (d->snapMode != mode) {
1742 d->snapMode = mode;
1744 }
1745}
1746
1747
2093void QQuickGridView::viewportMoved(Qt::Orientations orient)
2094{
2095 Q_D(QQuickGridView);
2097 if (!d->itemCount)
2098 return;
2099 if (d->inViewportMoved)
2100 return;
2101 d->inViewportMoved = true;
2102
2103 if (yflick()) {
2104 if (d->isContentFlowReversed())
2105 d->bufferMode = d->vData.smoothVelocity < 0 ? QQuickItemViewPrivate::BufferAfter : QQuickItemViewPrivate::BufferBefore;
2106 else
2107 d->bufferMode = d->vData.smoothVelocity < 0 ? QQuickItemViewPrivate::BufferBefore : QQuickItemViewPrivate::BufferAfter;
2108 } else {
2109 if (d->isContentFlowReversed())
2110 d->bufferMode = d->hData.smoothVelocity < 0 ? QQuickItemViewPrivate::BufferAfter : QQuickItemViewPrivate::BufferBefore;
2111 else
2112 d->bufferMode = d->hData.smoothVelocity < 0 ? QQuickItemViewPrivate::BufferBefore : QQuickItemViewPrivate::BufferAfter;
2113 }
2114
2115 d->refillOrLayout();
2116
2117 // Set visibility of items to eliminate cost of items outside the visible area.
2118 qreal from = d->isContentFlowReversed() ? -d->position()-d->displayMarginBeginning-d->size() : d->position()-d->displayMarginBeginning;
2119 qreal to = d->isContentFlowReversed() ? -d->position()+d->displayMarginEnd : d->position()+d->size()+d->displayMarginEnd;
2120 for (FxViewItem *item : std::as_const(d->visibleItems)) {
2121 FxGridItemSG *gridItem = static_cast<FxGridItemSG*>(item);
2122 QQuickItemPrivate::get(gridItem->item)->setCulled(gridItem->rowPos() + d->rowSize() < from || gridItem->rowPos() > to);
2123 }
2124 if (d->currentItem) {
2125 FxGridItemSG *item = static_cast<FxGridItemSG*>(d->currentItem);
2126 QQuickItemPrivate::get(item->item)->setCulled(item->rowPos() + d->rowSize() < from || item->rowPos() > to);
2127 }
2128
2129 if (d->hData.flicking || d->vData.flicking || d->hData.moving || d->vData.moving)
2130 d->moveReason = QQuickGridViewPrivate::Mouse;
2131 if (d->moveReason != QQuickGridViewPrivate::SetIndex) {
2132 if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange && d->highlight) {
2133 // reposition highlight
2134 qreal pos = d->highlight->position();
2135 qreal viewPos = d->isContentFlowReversed() ? -d->position()-d->size() : d->position();
2136 if (pos > viewPos + d->highlightRangeEnd - d->highlight->size())
2137 pos = viewPos + d->highlightRangeEnd - d->highlight->size();
2138 if (pos < viewPos + d->highlightRangeStart)
2139 pos = viewPos + d->highlightRangeStart;
2140
2141 if (pos != d->highlight->position()) {
2142 d->highlightXAnimator->stop();
2143 d->highlightYAnimator->stop();
2144 FxGridItemSG *sgHighlight = static_cast<FxGridItemSG *>(d->highlight.get());
2145 sgHighlight->setPosition(sgHighlight->colPos(), pos);
2146 } else {
2147 d->updateHighlight();
2148 }
2149
2150 // update current index
2151 int idx = d->snapIndex();
2152 if (idx >= 0 && idx != d->currentIndex) {
2153 d->updateCurrent(idx);
2154 if (d->currentItem
2155 && static_cast<FxGridItemSG*>(d->currentItem)->colPos()
2156 != static_cast<FxGridItemSG*>(d->highlight.get())->colPos()
2157 && d->autoHighlight) {
2158 if (d->flow == FlowLeftToRight)
2159 d->highlightXAnimator->to = d->currentItem->itemX();
2160 else
2161 d->highlightYAnimator->to = d->currentItem->itemY();
2162 }
2163 }
2164 }
2165 }
2166
2167 d->inViewportMoved = false;
2168}
2169
2171{
2172 Q_D(QQuickGridView);
2173 if (d->model && d->model->count() && ((d->interactive && !d->explicitKeyNavigationEnabled)
2174 || (d->explicitKeyNavigationEnabled && d->keyNavigationEnabled))) {
2175 d->moveReason = QQuickGridViewPrivate::SetIndex;
2176 int oldCurrent = currentIndex();
2177 switch (event->key()) {
2178 case Qt::Key_Up:
2180 break;
2181 case Qt::Key_Down:
2183 break;
2184 case Qt::Key_Left:
2186 break;
2187 case Qt::Key_Right:
2189 break;
2190 default:
2191 break;
2192 }
2193 if (oldCurrent != currentIndex() || d->wrap) {
2194 event->accept();
2195 return;
2196 }
2197 }
2198 event->ignore();
2200}
2201
2202void QQuickGridView::geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry)
2203{
2204 Q_D(QQuickGridView);
2205 d->resetColumns();
2206
2207 if (newGeometry.width() != oldGeometry.width()
2208 && newGeometry.height() != oldGeometry.height()) {
2209 d->setPosition(d->position());
2210 } else if (newGeometry.width() != oldGeometry.width()) {
2211 QQuickFlickable::setContentX(d->contentXForPosition(d->position()));
2212 } else if (newGeometry.height() != oldGeometry.height()) {
2213 QQuickFlickable::setContentY(d->contentYForPosition(d->position()));
2214 }
2215
2216 QQuickItemView::geometryChange(newGeometry, oldGeometry);
2217}
2218
2220{
2222
2223 // setting the view from the FxViewItem wrapper is too late if the delegate
2224 // needs access to the view in Component.onCompleted
2226 if (item) {
2227 QQuickGridViewAttached *attached = static_cast<QQuickGridViewAttached *>(
2228 qmlAttachedPropertiesObject<QQuickGridView>(item));
2229 if (attached)
2230 attached->setView(this);
2231 }
2232}
2233
2246{
2247 Q_D(QQuickGridView);
2248 const int count = d->model ? d->model->count() : 0;
2249 if (!count)
2250 return;
2251 if (d->verticalLayoutDirection == QQuickItemView::TopToBottom) {
2252 if (d->flow == QQuickGridView::FlowLeftToRight) {
2253 if (currentIndex() >= d->columns || d->wrap) {
2254 int index = currentIndex() - d->columns;
2255 setCurrentIndex((index >= 0 && index < count) ? index : count-1);
2256 }
2257 } else {
2258 if (currentIndex() > 0 || d->wrap) {
2259 int index = currentIndex() - 1;
2260 setCurrentIndex((index >= 0 && index < count) ? index : count-1);
2261 }
2262 }
2263 } else {
2264 if (d->flow == QQuickGridView::FlowLeftToRight) {
2265 if (currentIndex() < count - d->columns || d->wrap) {
2266 int index = currentIndex()+d->columns;
2267 setCurrentIndex((index >= 0 && index < count) ? index : 0);
2268 }
2269 } else {
2270 if (currentIndex() < count - 1 || d->wrap) {
2271 int index = currentIndex() + 1;
2272 setCurrentIndex((index >= 0 && index < count) ? index : 0);
2273 }
2274 }
2275 }
2276}
2277
2288{
2289 Q_D(QQuickGridView);
2290 const int count = d->model ? d->model->count() : 0;
2291 if (!count)
2292 return;
2293
2294 if (d->verticalLayoutDirection == QQuickItemView::TopToBottom) {
2295 if (d->flow == QQuickGridView::FlowLeftToRight) {
2296 if (currentIndex() < count - d->columns || d->wrap) {
2297 int index = currentIndex()+d->columns;
2298 setCurrentIndex((index >= 0 && index < count) ? index : 0);
2299 }
2300 } else {
2301 if (currentIndex() < count - 1 || d->wrap) {
2302 int index = currentIndex() + 1;
2303 setCurrentIndex((index >= 0 && index < count) ? index : 0);
2304 }
2305 }
2306 } else {
2307 if (d->flow == QQuickGridView::FlowLeftToRight) {
2308 if (currentIndex() >= d->columns || d->wrap) {
2309 int index = currentIndex() - d->columns;
2310 setCurrentIndex((index >= 0 && index < count) ? index : count-1);
2311 }
2312 } else {
2313 if (currentIndex() > 0 || d->wrap) {
2314 int index = currentIndex() - 1;
2315 setCurrentIndex((index >= 0 && index < count) ? index : count-1);
2316 }
2317 }
2318 }
2319}
2320
2331{
2332 Q_D(QQuickGridView);
2333 const int count = d->model ? d->model->count() : 0;
2334 if (!count)
2335 return;
2337 if (d->flow == QQuickGridView::FlowLeftToRight) {
2338 if (currentIndex() > 0 || d->wrap) {
2339 int index = currentIndex() - 1;
2340 setCurrentIndex((index >= 0 && index < count) ? index : count-1);
2341 }
2342 } else {
2343 if (currentIndex() >= d->columns || d->wrap) {
2344 int index = currentIndex() - d->columns;
2345 setCurrentIndex((index >= 0 && index < count) ? index : count-1);
2346 }
2347 }
2348 } else {
2349 if (d->flow == QQuickGridView::FlowLeftToRight) {
2350 if (currentIndex() < count - 1 || d->wrap) {
2351 int index = currentIndex() + 1;
2352 setCurrentIndex((index >= 0 && index < count) ? index : 0);
2353 }
2354 } else {
2355 if (currentIndex() < count - d->columns || d->wrap) {
2356 int index = currentIndex() + d->columns;
2357 setCurrentIndex((index >= 0 && index < count) ? index : 0);
2358 }
2359 }
2360 }
2361}
2362
2363
2374{
2375 Q_D(QQuickGridView);
2376 const int count = d->model ? d->model->count() : 0;
2377 if (!count)
2378 return;
2380 if (d->flow == QQuickGridView::FlowLeftToRight) {
2381 if (currentIndex() < count - 1 || d->wrap) {
2382 int index = currentIndex() + 1;
2383 setCurrentIndex((index >= 0 && index < count) ? index : 0);
2384 }
2385 } else {
2386 if (currentIndex() < count - d->columns || d->wrap) {
2387 int index = currentIndex()+d->columns;
2388 setCurrentIndex((index >= 0 && index < count) ? index : 0);
2389 }
2390 }
2391 } else {
2392 if (d->flow == QQuickGridView::FlowLeftToRight) {
2393 if (currentIndex() > 0 || d->wrap) {
2394 int index = currentIndex() - 1;
2395 setCurrentIndex((index >= 0 && index < count) ? index : count-1);
2396 }
2397 } else {
2398 if (currentIndex() >= d->columns || d->wrap) {
2399 int index = currentIndex() - d->columns;
2400 setCurrentIndex((index >= 0 && index < count) ? index : count-1);
2401 }
2402 }
2403 }
2404}
2405
2406bool QQuickGridViewPrivate::applyInsertionChange(const QQmlChangeSet::Change &change, ChangeResult *insertResult, QList<FxViewItem *> *addedItems, QList<MovedItem> *movingIntoView)
2407{
2408 Q_Q(QQuickGridView);
2409
2410 if (q->size().isEmpty())
2411 return false;
2412
2413 int modelIndex = change.index;
2414 int count = change.count;
2415
2416 int index = visibleItems.size() ? mapFromModel(modelIndex) : 0;
2417
2418 if (index < 0) {
2419 int i = visibleItems.size() - 1;
2420 while (i > 0 && visibleItems.at(i)->index == -1)
2421 --i;
2422 if (visibleItems.at(i)->index + 1 == modelIndex) {
2423 // Special case of appending an item to the model.
2425 } else {
2426 if (modelIndex <= visibleIndex) {
2427 // Insert before visible items
2429 for (FxViewItem *item : std::as_const(visibleItems)) {
2430 if (item->index != -1 && item->index >= modelIndex)
2431 item->index += count;
2432 }
2433 }
2434 return true;
2435 }
2436 }
2437
2438 qreal tempPos = isContentFlowReversed() ? -position()-size()+q->width()+1 : position();
2439 qreal colPos = 0;
2440 qreal rowPos = 0;
2441 int colNum = 0;
2442 if (visibleItems.size()) {
2443 if (index < visibleItems.size()) {
2444 FxGridItemSG *gridItem = static_cast<FxGridItemSG*>(visibleItems.at(index));
2445 colPos = gridItem->colPos();
2446 rowPos = gridItem->rowPos();
2447 colNum = qFloor((colPos+colSize()/2) / colSize());
2448 } else {
2449 // appending items to visible list
2450 FxGridItemSG *gridItem = static_cast<FxGridItemSG*>(visibleItems.at(index-1));
2451 rowPos = gridItem->rowPos();
2452 colNum = qFloor((gridItem->colPos()+colSize()/2) / colSize());
2453 if (++colNum >= columns) {
2454 colNum = 0;
2455 rowPos += rowSize();
2456 }
2457 colPos = colNum * colSize();
2458 }
2459 }
2460
2461#if QT_CONFIG(quick_viewtransitions)
2462 // Update the indexes of the following visible items.
2463 for (FxViewItem *item : std::as_const(visibleItems)) {
2464 if (item->index != -1 && item->index >= modelIndex) {
2465 item->index += count;
2466 if (change.isMove())
2467 item->transitionNextReposition(transitioner, QQuickItemViewTransitioner::MoveTransition, false);
2468 else
2469 item->transitionNextReposition(transitioner, QQuickItemViewTransitioner::AddTransition, false);
2470 }
2471 }
2472#endif
2473
2474 int prevVisibleCount = visibleItems.size();
2475 if (insertResult->visiblePos.isValid() && rowPos < insertResult->visiblePos) {
2476 // Insert items before the visible item.
2477 int insertionIdx = index;
2478 int i = count - 1;
2479 int from = tempPos - buffer - displayMarginBeginning;
2480
2481 if (rowPos > from && insertionIdx < visibleIndex) {
2482 // items won't be visible, just note the size for repositioning
2483 insertResult->countChangeBeforeVisible += count;
2484 insertResult->sizeChangesBeforeVisiblePos += ((count + columns - 1) / columns) * rowSize();
2485 } else {
2486 while (i >= 0) {
2487 // item is before first visible e.g. in cache buffer
2488 FxViewItem *item = nullptr;
2489 if (change.isMove() && (item = currentChanges.removedItems.take(change.moveKey(modelIndex + i))))
2490 item->index = modelIndex + i;
2491 if (!item)
2493 if (!item)
2494 return false;
2495
2496 QQuickItemPrivate::get(item->item)->setCulled(false);
2497 visibleItems.insert(insertionIdx, item);
2498 if (insertionIdx == 0)
2499 insertResult->changedFirstItem = true;
2500 if (!change.isMove()) {
2501 addedItems->append(item);
2502#if QT_CONFIG(quick_viewtransitions)
2503 if (transitioner)
2504 item->transitionNextReposition(transitioner, QQuickItemViewTransitioner::AddTransition, true);
2505 else
2506#endif
2507 item->moveTo(QPointF(colPos, rowPos), true);
2508 }
2509 insertResult->sizeChangesBeforeVisiblePos += rowSize();
2510
2511 if (--colNum < 0 ) {
2512 colNum = columns - 1;
2513 rowPos -= rowSize();
2514 }
2515 colPos = colNum * colSize();
2516 index++;
2517 i--;
2518 }
2519 }
2520
2521 // There may be gaps in the index sequence of visibleItems because
2522 // of the index shift/update done before the insertion just above.
2523 // Find if there is any...
2524 int firstOkIdx = -1;
2525 for (int i = 0; i <= insertionIdx && i < visibleItems.size() - 1; i++) {
2526 if (visibleItems.at(i)->index + 1 != visibleItems.at(i + 1)->index) {
2527 firstOkIdx = i + 1;
2528 break;
2529 }
2530 }
2531 // ... and remove all the items before that one
2532 for (int i = 0; i < firstOkIdx; i++) {
2533 FxViewItem *nvItem = visibleItems.takeFirst();
2534 addedItems->removeOne(nvItem);
2535 removeItem(nvItem);
2536 }
2537
2538 } else {
2539 int i = 0;
2540 int to = buffer+displayMarginEnd+tempPos+size()-1;
2541 while (i < count && rowPos <= to + rowSize()*(columns - colNum)/qreal(columns+1)) {
2542 FxViewItem *item = nullptr;
2543 if (change.isMove() && (item = currentChanges.removedItems.take(change.moveKey(modelIndex + i))))
2544 item->index = modelIndex + i;
2545 bool newItem = !item;
2546 if (!item)
2548 if (!item)
2549 return false;
2550
2551 QQuickItemPrivate::get(item->item)->setCulled(false);
2553 if (index == 0)
2554 insertResult->changedFirstItem = true;
2555 if (change.isMove()) {
2556 // we know this is a move target, since move displaced items that are
2557 // shuffled into view due to a move would be added in refill()
2558 if (newItem
2559#if QT_CONFIG(quick_viewtransitions)
2560 && transitioner && transitioner->canTransition(QQuickItemViewTransitioner::MoveTransition, true)
2561#endif
2562 )
2563 movingIntoView->append(MovedItem(item, change.moveKey(item->index)));
2564 } else {
2565 addedItems->append(item);
2566#if QT_CONFIG(quick_viewtransitions)
2567 if (transitioner)
2568 item->transitionNextReposition(transitioner, QQuickItemViewTransitioner::AddTransition, true);
2569 else
2570#endif
2571 item->moveTo(QPointF(colPos, rowPos), true);
2572 }
2573 insertResult->sizeChangesAfterVisiblePos += rowSize();
2574
2575 if (++colNum >= columns) {
2576 colNum = 0;
2577 rowPos += rowSize();
2578 }
2579 colPos = colNum * colSize();
2580 ++index;
2581 ++i;
2582 }
2583 }
2584
2586
2587 return visibleItems.size() > prevVisibleCount;
2588}
2589
2590#if QT_CONFIG(quick_viewtransitions)
2591void QQuickGridViewPrivate::translateAndTransitionItemsAfter(int afterModelIndex, const ChangeResult &insertionResult, const ChangeResult &removalResult)
2592{
2593 if (!transitioner)
2594 return;
2595
2596 int markerItemIndex = -1;
2597 for (int i=0; i<visibleItems.size(); i++) {
2598 if (visibleItems.at(i)->index == afterModelIndex) {
2599 markerItemIndex = i;
2600 break;
2601 }
2602 }
2603 if (markerItemIndex < 0)
2604 return;
2605
2606 const qreal viewEndPos = isContentFlowReversed() ? -position() : position() + size();
2607 int countItemsRemoved = -(removalResult.sizeChangesAfterVisiblePos / rowSize());
2608
2609 // account for whether first item has changed if < 1 row was removed before visible
2610 int changeBeforeVisible = insertionResult.countChangeBeforeVisible - removalResult.countChangeBeforeVisible;
2611 if (changeBeforeVisible != 0)
2612 countItemsRemoved += (changeBeforeVisible % columns) - (columns - 1);
2613
2614 countItemsRemoved -= removalResult.countChangeAfterVisibleItems;
2615
2616 for (int i=markerItemIndex+1; i<visibleItems.size(); i++) {
2617 FxGridItemSG *gridItem = static_cast<FxGridItemSG *>(visibleItems.at(i));
2618 if (gridItem->position() >= viewEndPos)
2619 break;
2620 if (!gridItem->transitionScheduledOrRunning()) {
2621 qreal origRowPos = gridItem->colPos();
2622 qreal origColPos = gridItem->rowPos();
2623 int indexDiff = gridItem->index - countItemsRemoved;
2624 gridItem->setPosition((indexDiff % columns) * colSize(), (indexDiff / columns) * rowSize());
2625 gridItem->transitionNextReposition(transitioner, QQuickItemViewTransitioner::RemoveTransition, false);
2626 gridItem->setPosition(origRowPos, origColPos);
2627 }
2628 }
2629}
2630#endif
2631
2633{
2634 // If we add or remove items before visible items, a layout may be
2635 // required to ensure item 0 is in the first column.
2636 return modelIndex < visibleIndex;
2637}
2638
2774
2776
2777#include "moc_qquickgridview_p.cpp"
bool contains(qreal x, qreal y) const override
qreal position() const override
qreal rowPos() const
QQuickGridView * view
void setPosition(qreal col, qreal row, bool immediate=false)
qreal endRowPos() const
qreal size() const override
qreal sectionSize() const override
qreal endPosition() const override
qreal colPos() const
FxGridItemSG(QQuickItem *i, QQuickGridView *v, bool own)
\inmodule QtCore
Type
This enum type defines the valid event types in Qt.
Definition qcoreevent.h:51
qreal y() const
This convenience function is equivalent to calling pos().y().
qreal x() const
This convenience function is equivalent to calling pos().x().
void setVisible(bool visible)
If visible is true, the item is made visible.
The QKeyEvent class describes a key event.
Definition qevent.h:424
qsizetype size() const noexcept
Definition qlist.h:397
void removeFirst() noexcept
Definition qlist.h:807
bool isEmpty() const noexcept
Definition qlist.h:401
T & first()
Definition qlist.h:645
T & last()
Definition qlist.h:648
const T & constLast() const noexcept
Definition qlist.h:650
iterator insert(qsizetype i, parameter_type t)
Definition qlist.h:488
const_reference at(qsizetype i) const noexcept
Definition qlist.h:446
value_type takeFirst()
Definition qlist.h:566
void prepend(rvalue_ref t)
Definition qlist.h:473
const T & constFirst() const noexcept
Definition qlist.h:647
void removeLast() noexcept
Definition qlist.h:815
void append(parameter_type t)
Definition qlist.h:458
T take(const Key &key)
Removes the item with the key from the hash and returns the value associated with it.
Definition qhash.h:1626
\inmodule QtCore
Definition qobject.h:103
\inmodule QtCore\reentrant
Definition qpoint.h:217
IncubationMode
Specifies the mode the incubator operates in.
The QQmlProperty class abstracts accessing properties on objects created from QML.
virtual bool flick(AxisData &data, qreal minExtent, qreal maxExtent, qreal vSize, QQuickTimeLineCallback::Callback fixupCallback, QEvent::Type eventType, qreal velocity)
qreal overShootDistance(qreal velocity) const
virtual void fixup(AxisData &data, qreal minExtent, qreal maxExtent)
QQuickFlickable::BoundsBehavior boundsBehavior
void setContentWidth(qreal)
virtual void setContentX(qreal pos)
virtual void viewportMoved(Qt::Orientations orient)
virtual void setContentY(qreal pos)
void setFlickableDirection(FlickableDirection)
void setContentHeight(qreal)
qreal footerSize() const override
bool addVisibleItems(qreal fillFrom, qreal fillTo, qreal bufferFrom, qreal bufferTo, bool doBuffer) override
qreal snapPosAt(qreal pos) const
void fixupPosition() override
void updateViewport() override
void updateHighlight() override
bool showFooterForIndex(int index) const override
bool isContentFlowReversed() const override
bool flick(QQuickItemViewPrivate::AxisData &data, qreal minExtent, qreal maxExtent, qreal vSize, QQuickTimeLineCallback::Callback fixupCallback, QEvent::Type eventType, qreal velocity) override
void repositionPackageItemAt(QQuickItem *item, int index) override
bool showHeaderForIndex(int index) const override
bool needsRefillForAddedOrRemovedIndex(int index) const override
QQuickGridView::Flow flow
void createHighlight(bool onDestruction=false) override
QQuickGridView::SnapMode snapMode
void initializeViewItem(FxViewItem *item) override
void removeItem(FxViewItem *item)
qreal positionAt(int index) const override
void updateFooter() override
Qt::Orientation layoutOrientation() const override
qreal endPositionAt(int index) const override
void setPosition(qreal pos) override
void resetFirstItemPosition(qreal pos=0.0) override
bool applyInsertionChange(const QQmlChangeSet::Change &insert, ChangeResult *changeResult, QList< FxViewItem * > *addedItems, QList< MovedItem > *movingIntoView) override
void initializeComponentItem(QQuickItem *item) const override
void adjustFirstItem(qreal forwards, qreal backwards, int changeBeforeVisible) override
QSmoothedAnimation * highlightYAnimator
qreal rowPosAt(int modelIndex) const
void repositionItemAt(FxViewItem *item, int index, qreal sizeBuffer) override
FxViewItem * snapItemAt(qreal pos) const
void fixup(AxisData &data, qreal minExtent, qreal maxExtent) override
void resetHighlightPosition() override
void changedVisibleIndex(int newIndex) override
void layoutVisibleItems(int fromModelIndex=0) override
qreal contentYForPosition(qreal pos) const
qreal lastPosition() const override
FxViewItem * newViewItem(int index, QQuickItem *item) override
QSmoothedAnimation * highlightXAnimator
qreal contentXForPosition(qreal pos) const
qreal headerSize() const override
qreal originPosition() const override
void updateHeader() override
bool removeNonVisibleItems(qreal bufferFrom, qreal bufferTo) override
qreal colPosAt(int modelIndex) const
void initializeCurrentItem() override
void geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry) override
void setHighlightFollowsCurrentItem(bool) override
void moveCurrentIndexRight()
\qmlmethod QtQuick::GridView::moveCurrentIndexRight()
static QQuickGridViewAttached * qmlAttachedProperties(QObject *)
\qmlmethod QtQuick::GridView::positionViewAtIndex(int index, PositionMode mode)
void flowChanged()
void moveCurrentIndexDown()
\qmlmethod QtQuick::GridView::moveCurrentIndexDown()
void moveCurrentIndexUp()
\qmlmethod QtQuick::GridView::moveCurrentIndexUp()
void cellWidthChanged()
void setCellWidth(qreal)
QQuickGridView(QQuickItem *parent=nullptr)
\qmltype GridView \instantiates QQuickGridView \inqmlmodule QtQuick
void snapModeChanged()
void moveCurrentIndexLeft()
\qmlmethod QtQuick::GridView::moveCurrentIndexLeft()
void initItem(int index, QObject *item) override
void setCellHeight(qreal)
void setHighlightMoveDuration(int) override
\qmlattachedproperty bool QtQuick::GridView::isCurrentItem \readonly
void setSnapMode(SnapMode mode)
void cellHeightChanged()
void viewportMoved(Qt::Orientations) override
\qmlproperty Component QtQuick::GridView::footer This property holds the component to use as the foot...
void keyPressEvent(QKeyEvent *) override
This event handler can be reimplemented in a subclass to receive key press events for an item.
static QQuickItemPrivate * get(QQuickItem *item)
void setView(QQuickItemView *view)
QMultiHash< QQmlChangeSet::MoveKey, FxViewItem * > removedItems
QPointer< QQuickItem > item
void setVisible(bool visible)
void moveTo(const QPointF &pos, bool immediate)
int findLastVisibleIndex(int defaultValue=-1) const
virtual void updateViewport()
FxViewItem * visibleItem(int modelIndex) const
QQuickItem * createHighlightItem() const
QPointer< QQmlInstanceModel > model
QList< FxViewItem * > visibleItems
virtual void initializeViewItem(FxViewItem *)
QQmlComponent * footerComponent
QQuickItemViewChangeSet currentChanges
QQuickItemView::VerticalLayoutDirection verticalLayoutDirection
int mapFromModel(int modelIndex) const
QQuickItem * createComponentItem(QQmlComponent *component, qreal zValue, bool createDefault=false) const
void releaseVisibleItems(QQmlInstanceModel::ReusableFlag reusableFlag)
FxViewItem * createItem(int modelIndex, QQmlIncubator::IncubationMode incubationMode=QQmlIncubator::AsynchronousIfNested)
QQmlComponent * headerComponent
virtual bool releaseItem(FxViewItem *item, QQmlInstanceModel::ReusableFlag reusableFlag)
QQmlInstanceModel::ReusableFlag reusableFlag
std::unique_ptr< FxViewItem > highlight
virtual void setHighlightFollowsCurrentItem(bool)
void setContentX(qreal pos) override
Qt::LayoutDirection effectiveLayoutDirection
void setContentY(qreal pos) override
virtual void initItem(int index, QObject *item)
virtual void setHighlightMoveDuration(int)
void setCurrentIndex(int idx)
VerticalLayoutDirection verticalLayoutDirection
void geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry) override
The QQuickItem class provides the most basic of all visual items in \l {Qt Quick}.
Definition qquickitem.h:63
virtual void keyPressEvent(QKeyEvent *event)
This event handler can be reimplemented in a subclass to receive key press events for an item.
QSizeF size() const
qreal width
This property holds the width of this item.
Definition qquickitem.h:75
qreal height
This property holds the height of this item.
Definition qquickitem.h:76
void reset(QQuickTimeLineValue &)
Cancel (but don't complete) all scheduled actions for timeLineValue.
int accel(QQuickTimeLineValue &, qreal velocity, qreal accel)
Decelerate timeLineValue from the starting velocity to zero at the given acceleration rate.
void callback(const QQuickTimeLineCallback &)
Execute the event.
void set(QQuickTimeLineValue &, qreal)
Set the value of timeLineValue.
void move(QQuickTimeLineValue &, qreal destination, int time=500)
Linearly change the timeLineValue from its current value to the given destination value over time mil...
\inmodule QtCore\reentrant
Definition qrect.h:484
constexpr qreal height() const noexcept
Returns the height of the rectangle.
Definition qrect.h:732
constexpr qreal width() const noexcept
Returns the width of the rectangle.
Definition qrect.h:729
cache insert(employee->id(), employee)
Combined button and popup list for selecting options.
@ LeftToRight
@ RightToLeft
Orientation
Definition qnamespace.h:98
@ Horizontal
Definition qnamespace.h:99
@ Vertical
Definition qnamespace.h:100
@ Key_Right
Definition qnamespace.h:679
@ Key_Left
Definition qnamespace.h:677
@ Key_Up
Definition qnamespace.h:678
@ Key_Down
Definition qnamespace.h:680
qfloat16 qSqrt(qfloat16 f)
Definition qfloat16.h:289
#define qCDebug(category,...)
int qFloor(T v)
Definition qmath.h:42
constexpr const T & qMin(const T &a, const T &b)
Definition qminmax.h:40
constexpr const T & qMax(const T &a, const T &b)
Definition qminmax.h:42
constexpr T qAbs(const T &t)
Definition qnumeric.h:328
n void setPosition(void) \n\
GLint GLfloat GLfloat GLfloat v2
GLsizei const GLfloat * v
[13]
GLint GLint GLint GLint GLint x
[0]
GLenum mode
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLuint index
[2]
GLenum GLuint GLenum GLsizei length
GLenum GLenum GLsizei count
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLenum GLuint buffer
GLint y
struct _cl_event * event
GLhandleARB obj
[2]
GLfloat bias
GLdouble GLdouble GLdouble GLdouble q
Definition qopenglext.h:259
GLenum GLenum GLsizei void * row
QObject * qmlAttachedPropertiesObject(QObject *object, QQmlAttachedPropertiesFunc func, bool create)
Definition qqml.cpp:114
QQuickItem * qmlobject_cast< QQuickItem * >(QObject *object)
#define QML_FLICK_SNAPONETHRESHOLD
QLatin1StringView QLatin1String
Definition qstringfwd.h:31
#define QT_CONFIG(feature)
#define emit
#define Q_UNUSED(x)
double qreal
Definition qtypes.h:187
std::uniform_real_distribution dist(1, 2.5)
[2]
QObject::connect nullptr
QGraphicsItem * item
MoveKey moveKey(int index) const