Qt 6.x
The Qt SDK
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:
30 {
31 }
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
49 qreal rowPos() const {
52 else
54 }
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
198 : flow(QQuickGridView::FlowLeftToRight)
199 , cellWidth(100), cellHeight(100), columns(1)
200 , snapMode(QQuickGridView::NoSnap)
202 {}
204 {
205 delete highlightXAnimator;
206 delete highlightYAnimator;
207 }
208};
209
211{
213}
214
216{
217 Q_Q(const QQuickGridView);
218
220 || (flow == QQuickGridView::FlowTopToBottom && q->effectiveLayoutDirection() == Qt::RightToLeft);
221}
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
258{
259 return rowPosAt(index);
260}
261
263{
264 return rowPosAt(index) + rowSize();
265}
266
269}
272}
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
608{
609 resetColumns();
611}
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
674{
676 item->setPosition(0, pos);
677}
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 ))
901 }
902}
903
905{
907 fixupY();
908 else
909 fixupX();
910}
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 {
958 else
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//----------------------------------------------------------------------------
1252{
1253}
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
1586{
1587 Q_D(QQuickGridView);
1588 if (d->highlightMoveDuration != duration) {
1589 if (d->highlightYAnimator) {
1590 d->highlightXAnimator->userDuration = duration;
1591 d->highlightYAnimator->userDuration = duration;
1592 }
1594 }
1595}
1596
1607{
1608 Q_D(const QQuickGridView);
1609 return d->flow;
1610}
1611
1613{
1614 Q_D(QQuickGridView);
1615 if (d->flow != flow) {
1616 d->flow = flow;
1617 if (d->flow == FlowLeftToRight) {
1618 setContentWidth(-1);
1620 } else {
1621 setContentHeight(-1);
1623 }
1624 setContentX(0);
1625 setContentY(0);
1626 d->regenerate(true);
1627 emit flowChanged();
1628 }
1629}
1630
1631
1641{
1642 Q_D(const QQuickGridView);
1643 return d->cellWidth;
1644}
1645
1647{
1648 Q_D(QQuickGridView);
1649 if (cellWidth != d->cellWidth && cellWidth > 0) {
1650 d->cellWidth = qMax(qreal(1), cellWidth);
1651 d->updateViewport();
1653 d->forceLayoutPolish();
1654 QQuickFlickable::setContentX(d->contentXForPosition(d->position()));
1655 }
1656}
1657
1659{
1660 Q_D(const QQuickGridView);
1661 return d->cellHeight;
1662}
1663
1665{
1666 Q_D(QQuickGridView);
1667 if (cellHeight != d->cellHeight && cellHeight > 0) {
1668 d->cellHeight = qMax(qreal(1), cellHeight);
1669 d->updateViewport();
1671 d->forceLayoutPolish();
1672 QQuickFlickable::setContentY(d->contentYForPosition(d->position()));
1673 }
1674}
1689{
1690 Q_D(const QQuickGridView);
1691 return d->snapMode;
1692}
1693
1695{
1696 Q_D(QQuickGridView);
1697 if (d->snapMode != mode) {
1698 d->snapMode = mode;
1700 }
1701}
1702
1703
2049void QQuickGridView::viewportMoved(Qt::Orientations orient)
2050{
2051 Q_D(QQuickGridView);
2053 if (!d->itemCount)
2054 return;
2055 if (d->inViewportMoved)
2056 return;
2057 d->inViewportMoved = true;
2058
2059 if (yflick()) {
2060 if (d->isContentFlowReversed())
2061 d->bufferMode = d->vData.smoothVelocity < 0 ? QQuickItemViewPrivate::BufferAfter : QQuickItemViewPrivate::BufferBefore;
2062 else
2063 d->bufferMode = d->vData.smoothVelocity < 0 ? QQuickItemViewPrivate::BufferBefore : QQuickItemViewPrivate::BufferAfter;
2064 } else {
2065 if (d->isContentFlowReversed())
2066 d->bufferMode = d->hData.smoothVelocity < 0 ? QQuickItemViewPrivate::BufferAfter : QQuickItemViewPrivate::BufferBefore;
2067 else
2068 d->bufferMode = d->hData.smoothVelocity < 0 ? QQuickItemViewPrivate::BufferBefore : QQuickItemViewPrivate::BufferAfter;
2069 }
2070
2071 d->refillOrLayout();
2072
2073 // Set visibility of items to eliminate cost of items outside the visible area.
2074 qreal from = d->isContentFlowReversed() ? -d->position()-d->displayMarginBeginning-d->size() : d->position()-d->displayMarginBeginning;
2075 qreal to = d->isContentFlowReversed() ? -d->position()+d->displayMarginEnd : d->position()+d->size()+d->displayMarginEnd;
2076 for (FxViewItem *item : std::as_const(d->visibleItems)) {
2077 FxGridItemSG *gridItem = static_cast<FxGridItemSG*>(item);
2078 QQuickItemPrivate::get(gridItem->item)->setCulled(gridItem->rowPos() + d->rowSize() < from || gridItem->rowPos() > to);
2079 }
2080 if (d->currentItem) {
2081 FxGridItemSG *item = static_cast<FxGridItemSG*>(d->currentItem);
2082 QQuickItemPrivate::get(item->item)->setCulled(item->rowPos() + d->rowSize() < from || item->rowPos() > to);
2083 }
2084
2085 if (d->hData.flicking || d->vData.flicking || d->hData.moving || d->vData.moving)
2086 d->moveReason = QQuickGridViewPrivate::Mouse;
2087 if (d->moveReason != QQuickGridViewPrivate::SetIndex) {
2088 if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange && d->highlight) {
2089 // reposition highlight
2090 qreal pos = d->highlight->position();
2091 qreal viewPos = d->isContentFlowReversed() ? -d->position()-d->size() : d->position();
2092 if (pos > viewPos + d->highlightRangeEnd - d->highlight->size())
2093 pos = viewPos + d->highlightRangeEnd - d->highlight->size();
2094 if (pos < viewPos + d->highlightRangeStart)
2095 pos = viewPos + d->highlightRangeStart;
2096
2097 if (pos != d->highlight->position()) {
2098 d->highlightXAnimator->stop();
2099 d->highlightYAnimator->stop();
2100 FxGridItemSG *sgHighlight = static_cast<FxGridItemSG *>(d->highlight.get());
2101 sgHighlight->setPosition(sgHighlight->colPos(), pos);
2102 } else {
2103 d->updateHighlight();
2104 }
2105
2106 // update current index
2107 int idx = d->snapIndex();
2108 if (idx >= 0 && idx != d->currentIndex) {
2109 d->updateCurrent(idx);
2110 if (d->currentItem
2111 && static_cast<FxGridItemSG*>(d->currentItem)->colPos()
2112 != static_cast<FxGridItemSG*>(d->highlight.get())->colPos()
2113 && d->autoHighlight) {
2114 if (d->flow == FlowLeftToRight)
2115 d->highlightXAnimator->to = d->currentItem->itemX();
2116 else
2117 d->highlightYAnimator->to = d->currentItem->itemY();
2118 }
2119 }
2120 }
2121 }
2122
2123 d->inViewportMoved = false;
2124}
2125
2127{
2128 Q_D(QQuickGridView);
2129 if (d->model && d->model->count() && ((d->interactive && !d->explicitKeyNavigationEnabled)
2130 || (d->explicitKeyNavigationEnabled && d->keyNavigationEnabled))) {
2131 d->moveReason = QQuickGridViewPrivate::SetIndex;
2132 int oldCurrent = currentIndex();
2133 switch (event->key()) {
2134 case Qt::Key_Up:
2136 break;
2137 case Qt::Key_Down:
2139 break;
2140 case Qt::Key_Left:
2142 break;
2143 case Qt::Key_Right:
2145 break;
2146 default:
2147 break;
2148 }
2149 if (oldCurrent != currentIndex() || d->wrap) {
2150 event->accept();
2151 return;
2152 }
2153 }
2154 event->ignore();
2156}
2157
2158void QQuickGridView::geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry)
2159{
2160 Q_D(QQuickGridView);
2161 d->resetColumns();
2162
2163 if (newGeometry.width() != oldGeometry.width()
2164 && newGeometry.height() != oldGeometry.height()) {
2165 d->setPosition(d->position());
2166 } else if (newGeometry.width() != oldGeometry.width()) {
2167 QQuickFlickable::setContentX(d->contentXForPosition(d->position()));
2168 } else if (newGeometry.height() != oldGeometry.height()) {
2169 QQuickFlickable::setContentY(d->contentYForPosition(d->position()));
2170 }
2171
2172 QQuickItemView::geometryChange(newGeometry, oldGeometry);
2173}
2174
2176{
2178
2179 // setting the view from the FxViewItem wrapper is too late if the delegate
2180 // needs access to the view in Component.onCompleted
2182 if (item) {
2183 QQuickGridViewAttached *attached = static_cast<QQuickGridViewAttached *>(
2184 qmlAttachedPropertiesObject<QQuickGridView>(item));
2185 if (attached)
2186 attached->setView(this);
2187 }
2188}
2189
2202{
2203 Q_D(QQuickGridView);
2204 const int count = d->model ? d->model->count() : 0;
2205 if (!count)
2206 return;
2207 if (d->verticalLayoutDirection == QQuickItemView::TopToBottom) {
2208 if (d->flow == QQuickGridView::FlowLeftToRight) {
2209 if (currentIndex() >= d->columns || d->wrap) {
2210 int index = currentIndex() - d->columns;
2211 setCurrentIndex((index >= 0 && index < count) ? index : count-1);
2212 }
2213 } else {
2214 if (currentIndex() > 0 || d->wrap) {
2215 int index = currentIndex() - 1;
2216 setCurrentIndex((index >= 0 && index < count) ? index : count-1);
2217 }
2218 }
2219 } else {
2220 if (d->flow == QQuickGridView::FlowLeftToRight) {
2221 if (currentIndex() < count - d->columns || d->wrap) {
2222 int index = currentIndex()+d->columns;
2223 setCurrentIndex((index >= 0 && index < count) ? index : 0);
2224 }
2225 } else {
2226 if (currentIndex() < count - 1 || d->wrap) {
2227 int index = currentIndex() + 1;
2228 setCurrentIndex((index >= 0 && index < count) ? index : 0);
2229 }
2230 }
2231 }
2232}
2233
2244{
2245 Q_D(QQuickGridView);
2246 const int count = d->model ? d->model->count() : 0;
2247 if (!count)
2248 return;
2249
2250 if (d->verticalLayoutDirection == QQuickItemView::TopToBottom) {
2251 if (d->flow == QQuickGridView::FlowLeftToRight) {
2252 if (currentIndex() < count - d->columns || d->wrap) {
2253 int index = currentIndex()+d->columns;
2254 setCurrentIndex((index >= 0 && index < count) ? index : 0);
2255 }
2256 } else {
2257 if (currentIndex() < count - 1 || d->wrap) {
2258 int index = currentIndex() + 1;
2259 setCurrentIndex((index >= 0 && index < count) ? index : 0);
2260 }
2261 }
2262 } else {
2263 if (d->flow == QQuickGridView::FlowLeftToRight) {
2264 if (currentIndex() >= d->columns || d->wrap) {
2265 int index = currentIndex() - d->columns;
2266 setCurrentIndex((index >= 0 && index < count) ? index : count-1);
2267 }
2268 } else {
2269 if (currentIndex() > 0 || d->wrap) {
2270 int index = currentIndex() - 1;
2271 setCurrentIndex((index >= 0 && index < count) ? index : count-1);
2272 }
2273 }
2274 }
2275}
2276
2287{
2288 Q_D(QQuickGridView);
2289 const int count = d->model ? d->model->count() : 0;
2290 if (!count)
2291 return;
2293 if (d->flow == QQuickGridView::FlowLeftToRight) {
2294 if (currentIndex() > 0 || d->wrap) {
2295 int index = currentIndex() - 1;
2296 setCurrentIndex((index >= 0 && index < count) ? index : count-1);
2297 }
2298 } else {
2299 if (currentIndex() >= d->columns || d->wrap) {
2300 int index = currentIndex() - d->columns;
2301 setCurrentIndex((index >= 0 && index < count) ? index : count-1);
2302 }
2303 }
2304 } else {
2305 if (d->flow == QQuickGridView::FlowLeftToRight) {
2306 if (currentIndex() < count - 1 || d->wrap) {
2307 int index = currentIndex() + 1;
2308 setCurrentIndex((index >= 0 && index < count) ? index : 0);
2309 }
2310 } else {
2311 if (currentIndex() < count - d->columns || d->wrap) {
2312 int index = currentIndex() + d->columns;
2313 setCurrentIndex((index >= 0 && index < count) ? index : 0);
2314 }
2315 }
2316 }
2317}
2318
2319
2330{
2331 Q_D(QQuickGridView);
2332 const int count = d->model ? d->model->count() : 0;
2333 if (!count)
2334 return;
2336 if (d->flow == QQuickGridView::FlowLeftToRight) {
2337 if (currentIndex() < count - 1 || d->wrap) {
2338 int index = currentIndex() + 1;
2339 setCurrentIndex((index >= 0 && index < count) ? index : 0);
2340 }
2341 } else {
2342 if (currentIndex() < count - d->columns || d->wrap) {
2343 int index = currentIndex()+d->columns;
2344 setCurrentIndex((index >= 0 && index < count) ? index : 0);
2345 }
2346 }
2347 } else {
2348 if (d->flow == QQuickGridView::FlowLeftToRight) {
2349 if (currentIndex() > 0 || d->wrap) {
2350 int index = currentIndex() - 1;
2351 setCurrentIndex((index >= 0 && index < count) ? index : count-1);
2352 }
2353 } else {
2354 if (currentIndex() >= d->columns || d->wrap) {
2355 int index = currentIndex() - d->columns;
2356 setCurrentIndex((index >= 0 && index < count) ? index : count-1);
2357 }
2358 }
2359 }
2360}
2361
2363{
2364 Q_Q(QQuickGridView);
2365
2366 if (q->size().isEmpty())
2367 return false;
2368
2369 int modelIndex = change.index;
2370 int count = change.count;
2371
2372 int index = visibleItems.size() ? mapFromModel(modelIndex) : 0;
2373
2374 if (index < 0) {
2375 int i = visibleItems.size() - 1;
2376 while (i > 0 && visibleItems.at(i)->index == -1)
2377 --i;
2378 if (visibleItems.at(i)->index + 1 == modelIndex) {
2379 // Special case of appending an item to the model.
2381 } else {
2382 if (modelIndex <= visibleIndex) {
2383 // Insert before visible items
2385 for (FxViewItem *item : std::as_const(visibleItems)) {
2386 if (item->index != -1 && item->index >= modelIndex)
2387 item->index += count;
2388 }
2389 }
2390 return true;
2391 }
2392 }
2393
2394 qreal tempPos = isContentFlowReversed() ? -position()-size()+q->width()+1 : position();
2395 qreal colPos = 0;
2396 qreal rowPos = 0;
2397 int colNum = 0;
2398 if (visibleItems.size()) {
2399 if (index < visibleItems.size()) {
2400 FxGridItemSG *gridItem = static_cast<FxGridItemSG*>(visibleItems.at(index));
2401 colPos = gridItem->colPos();
2402 rowPos = gridItem->rowPos();
2403 colNum = qFloor((colPos+colSize()/2) / colSize());
2404 } else {
2405 // appending items to visible list
2406 FxGridItemSG *gridItem = static_cast<FxGridItemSG*>(visibleItems.at(index-1));
2407 rowPos = gridItem->rowPos();
2408 colNum = qFloor((gridItem->colPos()+colSize()/2) / colSize());
2409 if (++colNum >= columns) {
2410 colNum = 0;
2411 rowPos += rowSize();
2412 }
2413 colPos = colNum * colSize();
2414 }
2415 }
2416
2417#if QT_CONFIG(quick_viewtransitions)
2418 // Update the indexes of the following visible items.
2419 for (FxViewItem *item : std::as_const(visibleItems)) {
2420 if (item->index != -1 && item->index >= modelIndex) {
2421 item->index += count;
2422 if (change.isMove())
2423 item->transitionNextReposition(transitioner, QQuickItemViewTransitioner::MoveTransition, false);
2424 else
2425 item->transitionNextReposition(transitioner, QQuickItemViewTransitioner::AddTransition, false);
2426 }
2427 }
2428#endif
2429
2430 int prevVisibleCount = visibleItems.size();
2431 if (insertResult->visiblePos.isValid() && rowPos < insertResult->visiblePos) {
2432 // Insert items before the visible item.
2433 int insertionIdx = index;
2434 int i = count - 1;
2435 int from = tempPos - buffer - displayMarginBeginning;
2436
2437 if (rowPos > from && insertionIdx < visibleIndex) {
2438 // items won't be visible, just note the size for repositioning
2439 insertResult->countChangeBeforeVisible += count;
2440 insertResult->sizeChangesBeforeVisiblePos += ((count + columns - 1) / columns) * rowSize();
2441 } else {
2442 while (i >= 0) {
2443 // item is before first visible e.g. in cache buffer
2444 FxViewItem *item = nullptr;
2445 if (change.isMove() && (item = currentChanges.removedItems.take(change.moveKey(modelIndex + i))))
2446 item->index = modelIndex + i;
2447 if (!item)
2449 if (!item)
2450 return false;
2451
2452 QQuickItemPrivate::get(item->item)->setCulled(false);
2453 visibleItems.insert(insertionIdx, item);
2454 if (insertionIdx == 0)
2455 insertResult->changedFirstItem = true;
2456 if (!change.isMove()) {
2457 addedItems->append(item);
2458#if QT_CONFIG(quick_viewtransitions)
2459 if (transitioner)
2460 item->transitionNextReposition(transitioner, QQuickItemViewTransitioner::AddTransition, true);
2461 else
2462#endif
2463 item->moveTo(QPointF(colPos, rowPos), true);
2464 }
2465 insertResult->sizeChangesBeforeVisiblePos += rowSize();
2466
2467 if (--colNum < 0 ) {
2468 colNum = columns - 1;
2469 rowPos -= rowSize();
2470 }
2471 colPos = colNum * colSize();
2472 index++;
2473 i--;
2474 }
2475 }
2476
2477 // There may be gaps in the index sequence of visibleItems because
2478 // of the index shift/update done before the insertion just above.
2479 // Find if there is any...
2480 int firstOkIdx = -1;
2481 for (int i = 0; i <= insertionIdx && i < visibleItems.size() - 1; i++) {
2482 if (visibleItems.at(i)->index + 1 != visibleItems.at(i + 1)->index) {
2483 firstOkIdx = i + 1;
2484 break;
2485 }
2486 }
2487 // ... and remove all the items before that one
2488 for (int i = 0; i < firstOkIdx; i++) {
2489 FxViewItem *nvItem = visibleItems.takeFirst();
2490 addedItems->removeOne(nvItem);
2491 removeItem(nvItem);
2492 }
2493
2494 } else {
2495 int i = 0;
2496 int to = buffer+displayMarginEnd+tempPos+size()-1;
2497 while (i < count && rowPos <= to + rowSize()*(columns - colNum)/qreal(columns+1)) {
2498 FxViewItem *item = nullptr;
2499 if (change.isMove() && (item = currentChanges.removedItems.take(change.moveKey(modelIndex + i))))
2500 item->index = modelIndex + i;
2501 bool newItem = !item;
2502 if (!item)
2504 if (!item)
2505 return false;
2506
2507 QQuickItemPrivate::get(item->item)->setCulled(false);
2509 if (index == 0)
2510 insertResult->changedFirstItem = true;
2511 if (change.isMove()) {
2512 // we know this is a move target, since move displaced items that are
2513 // shuffled into view due to a move would be added in refill()
2514 if (newItem
2515#if QT_CONFIG(quick_viewtransitions)
2516 && transitioner && transitioner->canTransition(QQuickItemViewTransitioner::MoveTransition, true)
2517#endif
2518 )
2519 movingIntoView->append(MovedItem(item, change.moveKey(item->index)));
2520 } else {
2521 addedItems->append(item);
2522#if QT_CONFIG(quick_viewtransitions)
2523 if (transitioner)
2524 item->transitionNextReposition(transitioner, QQuickItemViewTransitioner::AddTransition, true);
2525 else
2526#endif
2527 item->moveTo(QPointF(colPos, rowPos), true);
2528 }
2529 insertResult->sizeChangesAfterVisiblePos += rowSize();
2530
2531 if (++colNum >= columns) {
2532 colNum = 0;
2533 rowPos += rowSize();
2534 }
2535 colPos = colNum * colSize();
2536 ++index;
2537 ++i;
2538 }
2539 }
2540
2542
2543 return visibleItems.size() > prevVisibleCount;
2544}
2545
2546#if QT_CONFIG(quick_viewtransitions)
2547void QQuickGridViewPrivate::translateAndTransitionItemsAfter(int afterModelIndex, const ChangeResult &insertionResult, const ChangeResult &removalResult)
2548{
2549 if (!transitioner)
2550 return;
2551
2552 int markerItemIndex = -1;
2553 for (int i=0; i<visibleItems.size(); i++) {
2554 if (visibleItems.at(i)->index == afterModelIndex) {
2555 markerItemIndex = i;
2556 break;
2557 }
2558 }
2559 if (markerItemIndex < 0)
2560 return;
2561
2562 const qreal viewEndPos = isContentFlowReversed() ? -position() : position() + size();
2563 int countItemsRemoved = -(removalResult.sizeChangesAfterVisiblePos / rowSize());
2564
2565 // account for whether first item has changed if < 1 row was removed before visible
2566 int changeBeforeVisible = insertionResult.countChangeBeforeVisible - removalResult.countChangeBeforeVisible;
2567 if (changeBeforeVisible != 0)
2568 countItemsRemoved += (changeBeforeVisible % columns) - (columns - 1);
2569
2570 countItemsRemoved -= removalResult.countChangeAfterVisibleItems;
2571
2572 for (int i=markerItemIndex+1; i<visibleItems.size(); i++) {
2573 FxGridItemSG *gridItem = static_cast<FxGridItemSG *>(visibleItems.at(i));
2574 if (gridItem->position() >= viewEndPos)
2575 break;
2576 if (!gridItem->transitionScheduledOrRunning()) {
2577 qreal origRowPos = gridItem->colPos();
2578 qreal origColPos = gridItem->rowPos();
2579 int indexDiff = gridItem->index - countItemsRemoved;
2580 gridItem->setPosition((indexDiff % columns) * colSize(), (indexDiff / columns) * rowSize());
2581 gridItem->transitionNextReposition(transitioner, QQuickItemViewTransitioner::RemoveTransition, false);
2582 gridItem->setPosition(origRowPos, origColPos);
2583 }
2584 }
2585}
2586#endif
2587
2589{
2590 // If we add or remove items before visible items, a layout may be
2591 // required to ensure item 0 is in the first column.
2592 return modelIndex < visibleIndex;
2593}
2594
2727{
2728 return new QQuickGridViewAttached(obj);
2729}
2730
2732
2733#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:423
Definition qlist.h:74
qsizetype size() const noexcept
Definition qlist.h:386
void removeFirst() noexcept
Definition qlist.h:800
bool isEmpty() const noexcept
Definition qlist.h:390
T & first()
Definition qlist.h:628
T & last()
Definition qlist.h:631
const T & constLast() const noexcept
Definition qlist.h:633
iterator insert(qsizetype i, parameter_type t)
Definition qlist.h:471
bool removeOne(const AT &t)
Definition qlist.h:581
const_reference at(qsizetype i) const noexcept
Definition qlist.h:429
value_type takeFirst()
Definition qlist.h:549
void prepend(rvalue_ref t)
Definition qlist.h:456
const T & constFirst() const noexcept
Definition qlist.h:630
void removeLast() noexcept
Definition qlist.h:808
void append(parameter_type t)
Definition qlist.h:441
T take(const Key &key)
Removes the item with the key from the hash and returns the value associated with it.
Definition qhash.h:1541
\inmodule QtCore
Definition qobject.h:90
\inmodule QtCore\reentrant
Definition qpoint.h:214
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 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
virtual qreal position() const =0
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:64
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:76
qreal height
This property holds the height of this item.
Definition qquickitem.h:77
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:483
constexpr qreal height() const noexcept
Returns the height of the rectangle.
Definition qrect.h:718
constexpr qreal width() const noexcept
Returns the width of the rectangle.
Definition qrect.h:715
cache insert(employee->id(), employee)
Combined button and popup list for selecting options.
@ LeftToRight
@ RightToLeft
Orientation
Definition qnamespace.h:97
@ Horizontal
Definition qnamespace.h:98
@ Vertical
Definition qnamespace.h:99
@ Key_Right
Definition qnamespace.h:674
@ Key_Left
Definition qnamespace.h:672
@ Key_Up
Definition qnamespace.h:673
@ Key_Down
Definition qnamespace.h:675
qfloat16 qSqrt(qfloat16 f)
Definition qfloat16.h:243
#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
GLenum GLuint buffer
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
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:110
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:92
std::uniform_real_distribution dist(1, 2.5)
[2]
QObject::connect nullptr
QGraphicsItem * item
MoveKey moveKey(int index) const
QQmlNullableValue< qreal > visiblePos
IUIAutomationTreeWalker __RPC__deref_out_opt IUIAutomationElement ** parent