1
/****************************************************************************
3
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
4
** Contact: http://www.qt-project.org/legal
6
** This file is part of the QtQuick module of the Qt Toolkit.
8
** $QT_BEGIN_LICENSE:LGPL$
9
** Commercial License Usage
10
** Licensees holding valid commercial Qt licenses may use this file in
11
** accordance with the commercial license agreement provided with the
12
** Software or, alternatively, in accordance with the terms contained in
13
** a written agreement between you and Digia. For licensing terms and
14
** conditions see http://qt.digia.com/licensing. For further information
15
** use the contact form at http://qt.digia.com/contact-us.
17
** GNU Lesser General Public License Usage
18
** Alternatively, this file may be used under the terms of the GNU Lesser
19
** General Public License version 2.1 as published by the Free Software
20
** Foundation and appearing in the file LICENSE.LGPL included in the
21
** packaging of this file. Please review the following information to
22
** ensure the GNU Lesser General Public License version 2.1 requirements
23
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25
** In addition, as a special exception, Digia gives you certain additional
26
** rights. These rights are described in the Digia Qt LGPL Exception
27
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29
** GNU General Public License Usage
30
** Alternatively, this file may be used under the terms of the GNU
31
** General Public License version 3.0 as published by the Free Software
32
** Foundation and appearing in the file LICENSE.GPL included in the
33
** packaging of this file. Please review the following information to
34
** ensure the GNU General Public License version 3.0 requirements will be
35
** met: http://www.gnu.org/copyleft/gpl.html.
40
****************************************************************************/
42
#include "qquickgridview_p.h"
43
#include "qquickflickable_p_p.h"
44
#include "qquickitemview_p_p.h"
46
#include <private/qqmlobjectmodel_p.h>
47
#include <private/qquicksmoothedanimation_p_p.h>
49
#include <QtGui/qevent.h>
50
#include <QtCore/qmath.h>
51
#include <QtCore/qcoreapplication.h>
53
#include "qplatformdefs.h"
57
#ifndef QML_FLICK_SNAPONETHRESHOLD
58
#define QML_FLICK_SNAPONETHRESHOLD 30
61
//#define DEBUG_DELEGATE_LIFECYCLE
63
//----------------------------------------------------------------------------
65
class FxGridItemSG : public FxViewItem
68
FxGridItemSG(QQuickItem *i, QQuickGridView *v, bool own) : FxViewItem(i, v, own, static_cast<QQuickItemViewAttached*>(qmlAttachedPropertiesObject<QQuickGridView>(i))), view(v)
72
qreal position() const {
76
qreal endPosition() const {
81
return view->flow() == QQuickGridView::FlowLeftToRight ? view->cellHeight() : view->cellWidth();
84
qreal sectionSize() const {
88
qreal rowPos() const {
89
if (view->flow() == QQuickGridView::FlowLeftToRight)
90
return (view->verticalLayoutDirection() == QQuickItemView::BottomToTop ? -view->cellHeight()-itemY() : itemY());
92
return (view->effectiveLayoutDirection() == Qt::RightToLeft ? -view->cellWidth()-itemX() : itemX());
95
qreal colPos() const {
96
if (view->flow() == QQuickGridView::FlowLeftToRight) {
97
if (view->effectiveLayoutDirection() == Qt::RightToLeft) {
98
qreal colSize = view->cellWidth();
99
int columns = view->width()/colSize;
100
return colSize * (columns-1) - itemX();
105
if (view->verticalLayoutDirection() == QQuickItemView::BottomToTop) {
106
return -view->cellHeight() - itemY();
112
qreal endRowPos() const {
113
if (view->flow() == QQuickGridView::FlowLeftToRight) {
114
if (view->verticalLayoutDirection() == QQuickItemView::BottomToTop)
117
return itemY() + view->cellHeight();
119
if (view->effectiveLayoutDirection() == Qt::RightToLeft)
122
return itemX() + view->cellWidth();
125
void setPosition(qreal col, qreal row, bool immediate = false) {
126
moveTo(pointForPosition(col, row), immediate);
128
bool contains(qreal x, qreal y) const {
129
return (x >= itemX() && x < itemX() + view->cellWidth() &&
130
y >= itemY() && y < itemY() + view->cellHeight());
133
QQuickGridView *view;
136
QPointF pointForPosition(qreal col, qreal row) const {
139
if (view->flow() == QQuickGridView::FlowLeftToRight) {
142
if (view->effectiveLayoutDirection() == Qt::RightToLeft) {
143
int columns = view->width()/view->cellWidth();
144
x = view->cellWidth() * (columns-1) - col;
149
if (view->effectiveLayoutDirection() == Qt::RightToLeft)
150
x = -view->cellWidth() - row;
152
if (view->verticalLayoutDirection() == QQuickItemView::BottomToTop)
153
y = -view->cellHeight() - y;
154
return QPointF(x, y);
158
//----------------------------------------------------------------------------
160
class QQuickGridViewPrivate : public QQuickItemViewPrivate
162
Q_DECLARE_PUBLIC(QQuickGridView)
165
virtual Qt::Orientation layoutOrientation() const;
166
virtual bool isContentFlowReversed() const;
168
virtual qreal positionAt(int index) const;
169
virtual qreal endPositionAt(int index) const;
170
virtual qreal originPosition() const;
171
virtual qreal lastPosition() const;
173
qreal rowSize() const;
174
qreal colSize() const;
175
qreal colPosAt(int modelIndex) const;
176
qreal rowPosAt(int modelIndex) const;
177
qreal snapPosAt(qreal pos) const;
178
FxViewItem *snapItemAt(qreal pos) const;
179
int snapIndex() const;
180
qreal contentXForPosition(qreal pos) const;
181
qreal contentYForPosition(qreal pos) const;
185
virtual bool addVisibleItems(qreal fillFrom, qreal fillTo, qreal bufferFrom, qreal bufferTo, bool doBuffer);
186
virtual bool removeNonVisibleItems(qreal bufferFrom, qreal bufferTo);
188
virtual FxViewItem *newViewItem(int index, QQuickItem *item);
189
virtual void initializeViewItem(FxViewItem *item);
190
virtual void repositionItemAt(FxViewItem *item, int index, qreal sizeBuffer);
191
virtual void repositionPackageItemAt(QQuickItem *item, int index);
192
virtual void resetFirstItemPosition(qreal pos = 0.0);
193
virtual void adjustFirstItem(qreal forwards, qreal backwards, int changeBeforeVisible);
195
virtual void createHighlight();
196
virtual void updateHighlight();
197
virtual void resetHighlightPosition();
199
virtual void setPosition(qreal pos);
200
virtual void layoutVisibleItems(int fromModelIndex = 0);
201
virtual bool applyInsertionChange(const QQmlChangeSet::Insert &insert, ChangeResult *changeResult, QList<FxViewItem *> *addedItems, QList<MovedItem> *movingIntoView);
202
virtual void translateAndTransitionItemsAfter(int afterModelIndex, const ChangeResult &insertionResult, const ChangeResult &removalResult);
203
virtual bool needsRefillForAddedOrRemovedIndex(int index) const;
205
virtual qreal headerSize() const;
206
virtual qreal footerSize() const;
207
virtual bool showHeaderForIndex(int index) const;
208
virtual bool showFooterForIndex(int index) const;
209
virtual void updateHeader();
210
virtual void updateFooter();
212
virtual void changedVisibleIndex(int newIndex);
213
virtual void initializeCurrentItem();
215
virtual void updateViewport();
216
virtual void fixupPosition();
217
virtual void fixup(AxisData &data, qreal minExtent, qreal maxExtent);
218
virtual bool flick(QQuickItemViewPrivate::AxisData &data, qreal minExtent, qreal maxExtent, qreal vSize,
219
QQuickTimeLineCallback::Callback fixupCallback, qreal velocity);
221
QQuickGridView::Flow flow;
225
QQuickGridView::SnapMode snapMode;
227
QSmoothedAnimation *highlightXAnimator;
228
QSmoothedAnimation *highlightYAnimator;
230
QQuickGridViewPrivate()
231
: flow(QQuickGridView::FlowLeftToRight)
232
, cellWidth(100), cellHeight(100), columns(1)
233
, snapMode(QQuickGridView::NoSnap)
234
, highlightXAnimator(0), highlightYAnimator(0)
236
~QQuickGridViewPrivate()
238
delete highlightXAnimator;
239
delete highlightYAnimator;
243
Qt::Orientation QQuickGridViewPrivate::layoutOrientation() const
245
return flow == QQuickGridView::FlowLeftToRight ? Qt::Vertical : Qt::Horizontal;
248
bool QQuickGridViewPrivate::isContentFlowReversed() const
250
Q_Q(const QQuickGridView);
252
return (flow == QQuickGridView::FlowLeftToRight && verticalLayoutDirection == QQuickItemView::BottomToTop)
253
|| (flow == QQuickGridView::FlowTopToBottom && q->effectiveLayoutDirection() == Qt::RightToLeft);
256
void QQuickGridViewPrivate::changedVisibleIndex(int newIndex)
258
visibleIndex = newIndex / columns * columns;
261
void QQuickGridViewPrivate::setPosition(qreal pos)
264
q->QQuickFlickable::setContentX(contentXForPosition(pos));
265
q->QQuickFlickable::setContentY(contentYForPosition(pos));
268
qreal QQuickGridViewPrivate::originPosition() const
271
if (!visibleItems.isEmpty())
272
pos = static_cast<FxGridItemSG*>(visibleItems.first())->rowPos() - visibleIndex / columns * rowSize();
276
qreal QQuickGridViewPrivate::lastPosition() const
279
if (model && model->count()) {
280
// get end position of last item
281
pos = (rowPosAt(model->count() - 1) + rowSize());
286
qreal QQuickGridViewPrivate::positionAt(int index) const
288
return rowPosAt(index);
291
qreal QQuickGridViewPrivate::endPositionAt(int index) const
293
return rowPosAt(index) + rowSize();
296
qreal QQuickGridViewPrivate::rowSize() const {
297
return flow == QQuickGridView::FlowLeftToRight ? cellHeight : cellWidth;
299
qreal QQuickGridViewPrivate::colSize() const {
300
return flow == QQuickGridView::FlowLeftToRight ? cellWidth : cellHeight;
303
qreal QQuickGridViewPrivate::colPosAt(int modelIndex) const
305
if (FxViewItem *item = visibleItem(modelIndex))
306
return static_cast<FxGridItemSG*>(item)->colPos();
307
if (!visibleItems.isEmpty()) {
308
if (modelIndex == visibleIndex) {
309
FxGridItemSG *firstItem = static_cast<FxGridItemSG*>(visibleItems.first());
310
return firstItem->colPos();
311
} else if (modelIndex < visibleIndex) {
312
int count = (visibleIndex - modelIndex) % columns;
313
int col = static_cast<FxGridItemSG*>(visibleItems.first())->colPos() / colSize();
314
col = (columns - count + col) % columns;
315
return col * colSize();
317
FxGridItemSG *lastItem = static_cast<FxGridItemSG*>(visibleItems.last());
318
int count = modelIndex - lastItem->index;
319
int col = lastItem->colPos() / colSize();
320
col = (col + count) % columns;
321
return col * colSize();
324
return (modelIndex % columns) * colSize();
327
qreal QQuickGridViewPrivate::rowPosAt(int modelIndex) const
329
if (FxViewItem *item = visibleItem(modelIndex))
330
return static_cast<FxGridItemSG*>(item)->rowPos();
331
if (!visibleItems.isEmpty()) {
332
if (modelIndex == visibleIndex) {
333
FxGridItemSG *firstItem = static_cast<FxGridItemSG*>(visibleItems.first());
334
return firstItem->rowPos();
335
} else if (modelIndex < visibleIndex) {
336
FxGridItemSG *firstItem = static_cast<FxGridItemSG*>(visibleItems.first());
337
int firstCol = firstItem->colPos() / colSize();
338
int col = visibleIndex - modelIndex + (columns - firstCol - 1);
339
int rows = col / columns;
340
return firstItem->rowPos() - rows * rowSize();
342
FxGridItemSG *lastItem = static_cast<FxGridItemSG*>(visibleItems.last());
343
int count = modelIndex - lastItem->index;
344
int col = lastItem->colPos() + count * colSize();
345
int rows = col / (columns * colSize());
346
return lastItem->rowPos() + rows * rowSize();
349
return (modelIndex / columns) * rowSize();
353
qreal QQuickGridViewPrivate::snapPosAt(qreal pos) const
355
Q_Q(const QQuickGridView);
357
if (!visibleItems.isEmpty()) {
358
qreal highlightStart = highlightRangeStart;
359
pos += highlightStart;
361
snapPos = static_cast<FxGridItemSG*>(visibleItems.first())->rowPos() - visibleIndex / columns * rowSize();
362
snapPos = pos - fmodf(pos - snapPos, qreal(rowSize()));
363
snapPos -= highlightStart;
366
if (isContentFlowReversed()) {
367
maxExtent = q->minXExtent()-size();
368
minExtent = q->maxXExtent()-size();
370
maxExtent = flow == QQuickGridView::FlowLeftToRight ? -q->maxYExtent() : -q->maxXExtent();
371
minExtent = flow == QQuickGridView::FlowLeftToRight ? -q->minYExtent() : -q->minXExtent();
373
if (snapPos > maxExtent)
375
if (snapPos < minExtent)
381
FxViewItem *QQuickGridViewPrivate::snapItemAt(qreal pos) const
383
for (int i = 0; i < visibleItems.count(); ++i) {
384
FxViewItem *item = visibleItems.at(i);
385
if (item->index == -1)
387
qreal itemTop = item->position();
388
if (itemTop+rowSize()/2 >= pos && itemTop - rowSize()/2 <= pos)
394
int QQuickGridViewPrivate::snapIndex() const
396
int index = currentIndex;
397
for (int i = 0; i < visibleItems.count(); ++i) {
398
FxGridItemSG *item = static_cast<FxGridItemSG*>(visibleItems.at(i));
399
if (item->index == -1)
401
qreal itemTop = item->position();
402
FxGridItemSG *hItem = static_cast<FxGridItemSG*>(highlight);
403
if (itemTop >= hItem->rowPos()-rowSize()/2 && itemTop < hItem->rowPos()+rowSize()/2) {
405
if (item->colPos() >= hItem->colPos()-colSize()/2 && item->colPos() < hItem->colPos()+colSize()/2)
412
qreal QQuickGridViewPrivate::contentXForPosition(qreal pos) const
414
Q_Q(const QQuickGridView);
415
if (flow == QQuickGridView::FlowLeftToRight) {
417
if (q->effectiveLayoutDirection() == Qt::LeftToRight) {
420
qreal colSize = cellWidth;
421
int columns = q->width()/colSize;
422
return -q->width() + (cellWidth * columns);
426
if (q->effectiveLayoutDirection() == Qt::LeftToRight)
429
return -pos - q->width();
433
qreal QQuickGridViewPrivate::contentYForPosition(qreal pos) const
435
Q_Q(const QQuickGridView);
436
if (flow == QQuickGridView::FlowLeftToRight) {
438
if (verticalLayoutDirection == QQuickItemView::TopToBottom)
441
return -pos - q->height();
444
if (verticalLayoutDirection == QQuickItemView::TopToBottom)
451
void QQuickGridViewPrivate::resetColumns()
454
qreal length = flow == QQuickGridView::FlowLeftToRight ? q->width() : q->height();
455
columns = qMax(1, qFloor(length / colSize()));
458
FxViewItem *QQuickGridViewPrivate::newViewItem(int modelIndex, QQuickItem *item)
461
Q_UNUSED(modelIndex);
462
return new FxGridItemSG(item, q, false);
465
void QQuickGridViewPrivate::initializeViewItem(FxViewItem *item)
467
QQuickItemViewPrivate::initializeViewItem(item);
469
// need to track current items that are animating
470
item->trackGeometry(true);
473
bool QQuickGridViewPrivate::addVisibleItems(qreal fillFrom, qreal fillTo, qreal bufferFrom, qreal bufferTo, bool doBuffer)
475
qreal colPos = colPosAt(visibleIndex);
476
qreal rowPos = rowPosAt(visibleIndex);
477
if (visibleItems.count()) {
478
FxGridItemSG *lastItem = static_cast<FxGridItemSG*>(visibleItems.last());
479
rowPos = lastItem->rowPos();
480
int colNum = qFloor((lastItem->colPos()+colSize()/2) / colSize());
481
if (++colNum >= columns) {
485
colPos = colNum * colSize();
488
int modelIndex = findLastVisibleIndex();
489
modelIndex = modelIndex < 0 ? visibleIndex : modelIndex + 1;
491
if (visibleItems.count() && (bufferFrom > rowPos + rowSize()*2
492
|| bufferTo < rowPosAt(visibleIndex) - rowSize())) {
493
// We've jumped more than a page. Estimate which items are now
494
// visible and fill from there.
495
int count = (fillFrom - (rowPos + rowSize())) / (rowSize()) * columns;
496
for (int i = 0; i < visibleItems.count(); ++i)
497
releaseItem(visibleItems.at(i));
498
visibleItems.clear();
500
if (modelIndex >= model->count())
501
modelIndex = model->count() - 1;
502
else if (modelIndex < 0)
504
modelIndex = modelIndex / columns * columns;
505
visibleIndex = modelIndex;
506
colPos = colPosAt(visibleIndex);
507
rowPos = rowPosAt(visibleIndex);
510
int colNum = qFloor((colPos+colSize()/2) / colSize());
511
FxGridItemSG *item = 0;
512
bool changed = false;
514
while (modelIndex < model->count() && rowPos <= fillTo + rowSize()*(columns - colNum)/(columns+1)) {
515
#ifdef DEBUG_DELEGATE_LIFECYCLE
516
qDebug() << "refill: append item" << modelIndex << colPos << rowPos;
518
if (!(item = static_cast<FxGridItemSG*>(createItem(modelIndex, doBuffer))))
520
if (!transitioner || !transitioner->canTransition(QQuickItemViewTransitioner::PopulateTransition, true)) // pos will be set by layoutVisibleItems()
521
item->setPosition(colPos, rowPos, true);
522
QQuickItemPrivate::get(item->item)->setCulled(doBuffer);
523
visibleItems.append(item);
524
if (++colNum >= columns) {
528
colPos = colNum * colSize();
533
if (doBuffer && requestedIndex != -1) // already waiting for an item
537
if (visibleItems.count()) {
538
FxGridItemSG *firstItem = static_cast<FxGridItemSG*>(visibleItems.first());
539
rowPos = firstItem->rowPos();
540
colNum = qFloor((firstItem->colPos()+colSize()/2) / colSize());
542
colNum = columns - 1;
546
colNum = qFloor((colPos+colSize()/2) / colSize());
550
colPos = colNum * colSize();
551
while (visibleIndex > 0 && rowPos + rowSize() - 1 >= fillFrom - rowSize()*(colNum+1)/(columns+1)){
552
#ifdef DEBUG_DELEGATE_LIFECYCLE
553
qDebug() << "refill: prepend item" << visibleIndex-1 << "top pos" << rowPos << colPos;
555
if (!(item = static_cast<FxGridItemSG*>(createItem(visibleIndex-1, doBuffer))))
558
if (!transitioner || !transitioner->canTransition(QQuickItemViewTransitioner::PopulateTransition, true)) // pos will be set by layoutVisibleItems()
559
item->setPosition(colPos, rowPos, true);
560
QQuickItemPrivate::get(item->item)->setCulled(doBuffer);
561
visibleItems.prepend(item);
566
colPos = colNum * colSize();
573
bool QQuickGridViewPrivate::removeNonVisibleItems(qreal bufferFrom, qreal bufferTo)
575
FxGridItemSG *item = 0;
576
bool changed = false;
578
while (visibleItems.count() > 1
579
&& (item = static_cast<FxGridItemSG*>(visibleItems.first()))
580
&& item->rowPos()+rowSize()-1 < bufferFrom - rowSize()*(item->colPos()/colSize()+1)/(columns+1)) {
581
if (item->attached->delayRemove())
583
#ifdef DEBUG_DELEGATE_LIFECYCLE
584
qDebug() << "refill: remove first" << visibleIndex << "top end pos" << item->endRowPos();
586
if (item->index != -1)
588
visibleItems.removeFirst();
589
if (item->transitionScheduledOrRunning()) {
590
#ifdef DEBUG_DELEGATE_LIFECYCLE
591
qDebug() << "\tnot releasing animating item:" << item->index << item->item->objectName();
593
item->releaseAfterTransition = true;
594
releasePendingTransition.append(item);
600
while (visibleItems.count() > 1
601
&& (item = static_cast<FxGridItemSG*>(visibleItems.last()))
602
&& item->rowPos() > bufferTo + rowSize()*(columns - item->colPos()/colSize())/(columns+1)) {
603
if (item->attached->delayRemove())
605
#ifdef DEBUG_DELEGATE_LIFECYCLE
606
qDebug() << "refill: remove last" << visibleIndex+visibleItems.count()-1;
608
visibleItems.removeLast();
609
if (item->transitionScheduledOrRunning()) {
610
#ifdef DEBUG_DELEGATE_LIFECYCLE
611
qDebug() << "\tnot releasing animating item:" << item->index << item->item->objectName();
613
item->releaseAfterTransition = true;
614
releasePendingTransition.append(item);
624
void QQuickGridViewPrivate::updateViewport()
627
QQuickItemViewPrivate::updateViewport();
630
void QQuickGridViewPrivate::layoutVisibleItems(int fromModelIndex)
632
if (visibleItems.count()) {
633
const qreal from = isContentFlowReversed() ? -position()-displayMarginBeginning-size() : position()-displayMarginBeginning;
634
const qreal to = isContentFlowReversed() ? -position()+displayMarginEnd : position()+size()+displayMarginEnd;
636
FxGridItemSG *firstItem = static_cast<FxGridItemSG*>(visibleItems.first());
637
qreal rowPos = firstItem->rowPos();
638
qreal colPos = firstItem->colPos();
639
int col = visibleIndex % columns;
640
if (colPos != col * colSize()) {
641
colPos = col * colSize();
642
firstItem->setPosition(colPos, rowPos);
643
firstItem->setVisible(firstItem->rowPos() + rowSize() >= from && firstItem->rowPos() <= to);
645
for (int i = 1; i < visibleItems.count(); ++i) {
646
FxGridItemSG *item = static_cast<FxGridItemSG*>(visibleItems.at(i));
647
if (++col >= columns) {
651
colPos = col * colSize();
652
if (item->index >= fromModelIndex) {
653
item->setPosition(colPos, rowPos);
654
item->setVisible(item->rowPos() + rowSize() >= from && item->rowPos() <= to);
660
void QQuickGridViewPrivate::repositionItemAt(FxViewItem *item, int index, qreal sizeBuffer)
662
int count = sizeBuffer / rowSize();
663
static_cast<FxGridItemSG *>(item)->setPosition(colPosAt(index + count), rowPosAt(index + count));
666
void QQuickGridViewPrivate::repositionPackageItemAt(QQuickItem *item, int index)
669
qreal pos = position();
670
if (flow == QQuickGridView::FlowLeftToRight) {
671
if (item->y() + item->height() > pos && item->y() < pos + q->height()) {
672
qreal y = (verticalLayoutDirection == QQuickItemView::TopToBottom)
674
: -rowPosAt(index) - item->height();
675
item->setPosition(QPointF(colPosAt(index), y));
678
if (item->x() + item->width() > pos && item->x() < pos + q->width()) {
679
qreal y = (verticalLayoutDirection == QQuickItemView::TopToBottom)
681
: -colPosAt(index) - item->height();
682
if (flow == QQuickGridView::FlowTopToBottom && q->effectiveLayoutDirection() == Qt::RightToLeft)
683
item->setPosition(QPointF(-rowPosAt(index)-item->width(), y));
685
item->setPosition(QPointF(rowPosAt(index), y));
690
void QQuickGridViewPrivate::resetFirstItemPosition(qreal pos)
692
FxGridItemSG *item = static_cast<FxGridItemSG*>(visibleItems.first());
693
item->setPosition(0, pos);
696
void QQuickGridViewPrivate::adjustFirstItem(qreal forwards, qreal backwards, int changeBeforeVisible)
698
if (!visibleItems.count())
701
int moveCount = (forwards - backwards) / rowSize();
702
if (moveCount == 0 && changeBeforeVisible != 0)
703
moveCount += (changeBeforeVisible % columns) - (columns - 1);
705
FxGridItemSG *gridItem = static_cast<FxGridItemSG*>(visibleItems.first());
706
gridItem->setPosition(gridItem->colPos(), gridItem->rowPos() + ((moveCount / columns) * rowSize()));
709
void QQuickGridViewPrivate::createHighlight()
712
bool changed = false;
714
if (trackedItem == highlight)
719
delete highlightXAnimator;
720
delete highlightYAnimator;
721
highlightXAnimator = 0;
722
highlightYAnimator = 0;
728
QQuickItem *item = createHighlightItem();
730
FxGridItemSG *newHighlight = new FxGridItemSG(item, q, true);
731
newHighlight->trackGeometry(true);
733
resetHighlightPosition();
734
highlightXAnimator = new QSmoothedAnimation;
735
highlightXAnimator->target = QQmlProperty(item, QLatin1String("x"));
736
highlightXAnimator->userDuration = highlightMoveDuration;
737
highlightYAnimator = new QSmoothedAnimation;
738
highlightYAnimator->target = QQmlProperty(item, QLatin1String("y"));
739
highlightYAnimator->userDuration = highlightMoveDuration;
741
highlight = newHighlight;
746
emit q->highlightItemChanged();
749
void QQuickGridViewPrivate::updateHighlight()
751
applyPendingChanges();
753
if ((!currentItem && highlight) || (currentItem && !highlight))
755
bool strictHighlight = haveHighlightRange && highlightRange == QQuickGridView::StrictlyEnforceRange;
756
if (currentItem && autoHighlight && highlight && (!strictHighlight || !pressed)) {
757
// auto-update highlight
758
highlightXAnimator->to = currentItem->itemX();
759
highlightYAnimator->to = currentItem->itemY();
760
highlight->item->setWidth(currentItem->item->width());
761
highlight->item->setHeight(currentItem->item->height());
763
highlightXAnimator->restart();
764
highlightYAnimator->restart();
769
void QQuickGridViewPrivate::resetHighlightPosition()
771
if (highlight && currentItem) {
772
FxGridItemSG *cItem = static_cast<FxGridItemSG*>(currentItem);
773
static_cast<FxGridItemSG*>(highlight)->setPosition(cItem->colPos(), cItem->rowPos());
777
qreal QQuickGridViewPrivate::headerSize() const
781
return flow == QQuickGridView::FlowLeftToRight ? header->item->height() : header->item->width();
784
qreal QQuickGridViewPrivate::footerSize() const
788
return flow == QQuickGridView::FlowLeftToRight? footer->item->height() : footer->item->width();
791
bool QQuickGridViewPrivate::showHeaderForIndex(int index) const
793
return index / columns == 0;
796
bool QQuickGridViewPrivate::showFooterForIndex(int index) const
798
return index / columns == (model->count()-1) / columns;
801
void QQuickGridViewPrivate::updateFooter()
804
bool created = false;
806
QQuickItem *item = createComponentItem(footerComponent, 1.0);
809
footer = new FxGridItemSG(item, q, true);
810
footer->trackGeometry(true);
814
FxGridItemSG *gridItem = static_cast<FxGridItemSG*>(footer);
817
if (q->effectiveLayoutDirection() == Qt::RightToLeft) {
818
if (flow == QQuickGridView::FlowTopToBottom)
819
rowOffset += gridItem->item->width() - cellWidth;
821
colOffset += gridItem->item->width() - cellWidth;
823
if (verticalLayoutDirection == QQuickItemView::BottomToTop) {
824
if (flow == QQuickGridView::FlowTopToBottom)
825
colOffset += gridItem->item->height() - cellHeight;
827
rowOffset += gridItem->item->height() - cellHeight;
829
if (visibleItems.count()) {
830
qreal endPos = lastPosition();
831
if (findLastVisibleIndex() == model->count()-1) {
832
gridItem->setPosition(colOffset, endPos + rowOffset);
834
qreal visiblePos = isContentFlowReversed() ? -position() : position() + size();
835
if (endPos <= visiblePos || gridItem->endPosition() <= endPos + rowOffset)
836
gridItem->setPosition(colOffset, endPos + rowOffset);
839
gridItem->setPosition(colOffset, rowOffset);
843
emit q->footerItemChanged();
846
void QQuickGridViewPrivate::updateHeader()
849
bool created = false;
851
QQuickItem *item = createComponentItem(headerComponent, 1.0);
854
header = new FxGridItemSG(item, q, true);
855
header->trackGeometry(true);
859
FxGridItemSG *gridItem = static_cast<FxGridItemSG*>(header);
861
qreal rowOffset = -headerSize();
862
if (q->effectiveLayoutDirection() == Qt::RightToLeft) {
863
if (flow == QQuickGridView::FlowTopToBottom)
864
rowOffset += gridItem->item->width() - cellWidth;
866
colOffset += gridItem->item->width() - cellWidth;
868
if (verticalLayoutDirection == QQuickItemView::BottomToTop) {
869
if (flow == QQuickGridView::FlowTopToBottom)
870
colOffset += gridItem->item->height() - cellHeight;
872
rowOffset += gridItem->item->height() - cellHeight;
874
if (visibleItems.count()) {
875
qreal startPos = originPosition();
876
if (visibleIndex == 0) {
877
gridItem->setPosition(colOffset, startPos + rowOffset);
879
qreal tempPos = isContentFlowReversed() ? -position()-size() : position();
880
qreal headerPos = isContentFlowReversed() ? gridItem->rowPos() + cellWidth - headerSize() : gridItem->rowPos();
881
if (tempPos <= startPos || headerPos > startPos + rowOffset)
882
gridItem->setPosition(colOffset, startPos + rowOffset);
885
if (isContentFlowReversed())
886
gridItem->setPosition(colOffset, rowOffset);
888
gridItem->setPosition(colOffset, -headerSize());
892
emit q->headerItemChanged();
895
void QQuickGridViewPrivate::initializeCurrentItem()
897
if (currentItem && currentIndex >= 0) {
898
FxGridItemSG *gridItem = static_cast<FxGridItemSG*>(currentItem);
899
FxViewItem *actualItem = visibleItem(currentIndex);
901
// don't reposition the item if it's about to be transitioned to another position
902
if ((!actualItem || !actualItem->transitionScheduledOrRunning()))
903
gridItem->setPosition(colPosAt(currentIndex), rowPosAt(currentIndex));
907
void QQuickGridViewPrivate::fixupPosition()
910
if (flow == QQuickGridView::FlowLeftToRight)
916
void QQuickGridViewPrivate::fixup(AxisData &data, qreal minExtent, qreal maxExtent)
918
if ((flow == QQuickGridView::FlowTopToBottom && &data == &vData)
919
|| (flow == QQuickGridView::FlowLeftToRight && &data == &hData))
922
fixupMode = moveReason == Mouse ? fixupMode : Immediate;
924
qreal viewPos = isContentFlowReversed() ? -position()-size() : position();
926
bool strictHighlightRange = haveHighlightRange && highlightRange == QQuickGridView::StrictlyEnforceRange;
927
if (snapMode != QQuickGridView::NoSnap) {
928
qreal tempPosition = isContentFlowReversed() ? -position()-size() : position();
929
if (snapMode == QQuickGridView::SnapOneRow && moveReason == Mouse) {
930
// if we've been dragged < rowSize()/2 then bias towards the next row
931
qreal dist = data.move.value() - (data.pressPos - data.dragStartOffset);
933
if (data.velocity > 0 && dist > QML_FLICK_SNAPONETHRESHOLD && dist < rowSize()/2)
935
else if (data.velocity < 0 && dist < -QML_FLICK_SNAPONETHRESHOLD && dist > -rowSize()/2)
937
if (isContentFlowReversed())
939
tempPosition -= bias;
941
FxViewItem *topItem = snapItemAt(tempPosition+highlightRangeStart);
942
if (!topItem && strictHighlightRange && currentItem) {
943
// StrictlyEnforceRange always keeps an item in range
945
topItem = currentItem;
947
FxViewItem *bottomItem = snapItemAt(tempPosition+highlightRangeEnd);
948
if (!bottomItem && strictHighlightRange && currentItem) {
949
// StrictlyEnforceRange always keeps an item in range
951
bottomItem = currentItem;
954
bool isInBounds = -position() > maxExtent && -position() <= minExtent;
955
if (topItem && (isInBounds || strictHighlightRange)) {
956
qreal headerPos = header ? static_cast<FxGridItemSG*>(header)->rowPos() : 0;
957
if (topItem->index == 0 && header && tempPosition+highlightRangeStart < headerPos+headerSize()/2 && !strictHighlightRange) {
958
pos = isContentFlowReversed() ? - headerPos + highlightRangeStart - size() : headerPos - highlightRangeStart;
960
if (isContentFlowReversed())
961
pos = qMax(qMin(-topItem->position() + highlightRangeStart - size(), -maxExtent), -minExtent);
963
pos = qMax(qMin(topItem->position() - highlightRangeStart, -maxExtent), -minExtent);
965
} else if (bottomItem && isInBounds) {
966
if (isContentFlowReversed())
967
pos = qMax(qMin(-bottomItem->position() + highlightRangeEnd - size(), -maxExtent), -minExtent);
969
pos = qMax(qMin(bottomItem->position() - highlightRangeEnd, -maxExtent), -minExtent);
971
QQuickItemViewPrivate::fixup(data, minExtent, maxExtent);
975
qreal dist = qAbs(data.move + pos);
977
timeline.reset(data.move);
978
if (fixupMode != Immediate) {
979
timeline.move(data.move, -pos, QEasingCurve(QEasingCurve::InOutQuad), fixupDuration/2);
980
data.fixingUp = true;
982
timeline.set(data.move, -pos);
984
vTime = timeline.time();
986
} else if (haveHighlightRange && highlightRange == QQuickGridView::StrictlyEnforceRange) {
989
qreal pos = static_cast<FxGridItemSG*>(currentItem)->rowPos();
990
if (viewPos < pos + rowSize() - highlightRangeEnd)
991
viewPos = pos + rowSize() - highlightRangeEnd;
992
if (viewPos > pos - highlightRangeStart)
993
viewPos = pos - highlightRangeStart;
994
if (isContentFlowReversed())
995
viewPos = -viewPos-size();
996
timeline.reset(data.move);
997
if (viewPos != position()) {
998
if (fixupMode != Immediate) {
999
timeline.move(data.move, -viewPos, QEasingCurve(QEasingCurve::InOutQuad), fixupDuration/2);
1000
data.fixingUp = true;
1002
timeline.set(data.move, -viewPos);
1005
vTime = timeline.time();
1008
QQuickItemViewPrivate::fixup(data, minExtent, maxExtent);
1010
data.inOvershoot = false;
1014
bool QQuickGridViewPrivate::flick(AxisData &data, qreal minExtent, qreal maxExtent, qreal vSize,
1015
QQuickTimeLineCallback::Callback fixupCallback, qreal velocity)
1017
data.fixingUp = false;
1019
if ((!haveHighlightRange || highlightRange != QQuickGridView::StrictlyEnforceRange)
1020
&& snapMode == QQuickGridView::NoSnap) {
1021
return QQuickItemViewPrivate::flick(data, minExtent, maxExtent, vSize, fixupCallback, velocity);
1023
qreal maxDistance = 0;
1024
qreal dataValue = isContentFlowReversed() ? -data.move.value()+size() : data.move.value();
1025
// -ve velocity means list is moving up/left
1027
if (data.move.value() < minExtent) {
1028
if (snapMode == QQuickGridView::SnapOneRow) {
1029
// if we've been dragged < averageSize/2 then bias towards the next item
1030
qreal dist = data.move.value() - (data.pressPos - data.dragStartOffset);
1031
qreal bias = dist < rowSize()/2 ? rowSize()/2 : 0;
1032
if (isContentFlowReversed())
1034
data.flickTarget = -snapPosAt(-dataValue - bias);
1035
maxDistance = qAbs(data.flickTarget - data.move.value());
1036
velocity = maxVelocity;
1038
maxDistance = qAbs(minExtent - data.move.value());
1041
if (snapMode == QQuickGridView::NoSnap && highlightRange != QQuickGridView::StrictlyEnforceRange)
1042
data.flickTarget = minExtent;
1044
if (data.move.value() > maxExtent) {
1045
if (snapMode == QQuickGridView::SnapOneRow) {
1046
// if we've been dragged < averageSize/2 then bias towards the next item
1047
qreal dist = data.move.value() - (data.pressPos - data.dragStartOffset);
1048
qreal bias = -dist < rowSize()/2 ? rowSize()/2 : 0;
1049
if (isContentFlowReversed())
1051
data.flickTarget = -snapPosAt(-dataValue + bias);
1052
maxDistance = qAbs(data.flickTarget - data.move.value());
1053
velocity = -maxVelocity;
1055
maxDistance = qAbs(maxExtent - data.move.value());
1058
if (snapMode == QQuickGridView::NoSnap && highlightRange != QQuickGridView::StrictlyEnforceRange)
1059
data.flickTarget = maxExtent;
1061
bool overShoot = boundsBehavior == QQuickFlickable::DragAndOvershootBounds;
1062
if (maxDistance > 0 || overShoot) {
1063
// This mode requires the grid to stop exactly on a row boundary.
1065
if (maxVelocity != -1 && maxVelocity < qAbs(v)) {
1071
qreal accel = deceleration;
1073
qreal overshootDist = 0.0;
1074
if ((maxDistance > 0.0 && v2 / (2.0f * maxDistance) < accel) || snapMode == QQuickGridView::SnapOneRow) {
1075
// + rowSize()/4 to encourage moving at least one item in the flick direction
1076
qreal dist = v2 / (accel * 2.0) + rowSize()/4;
1077
dist = qMin(dist, maxDistance);
1080
if (snapMode != QQuickGridView::SnapOneRow) {
1081
qreal distTemp = isContentFlowReversed() ? -dist : dist;
1082
data.flickTarget = -snapPosAt(-dataValue + distTemp);
1084
data.flickTarget = isContentFlowReversed() ? -data.flickTarget+size() : data.flickTarget;
1086
if (data.flickTarget >= minExtent) {
1087
overshootDist = overShootDistance(vSize);
1088
data.flickTarget += overshootDist;
1089
} else if (data.flickTarget <= maxExtent) {
1090
overshootDist = overShootDistance(vSize);
1091
data.flickTarget -= overshootDist;
1094
qreal adjDist = -data.flickTarget + data.move.value();
1095
if (qAbs(adjDist) > qAbs(dist)) {
1096
// Prevent painfully slow flicking - adjust velocity to suit flickDeceleration
1097
qreal adjv2 = accel * 2.0f * qAbs(adjDist);
1106
accel = v2 / (2.0f * qAbs(dist));
1108
data.flickTarget = velocity > 0 ? minExtent : maxExtent;
1109
overshootDist = overShoot ? overShootDistance(vSize) : 0;
1111
timeline.reset(data.move);
1112
timeline.accel(data.move, v, accel, maxDistance + overshootDist);
1113
timeline.callback(QQuickTimeLineCallback(&data.move, fixupCallback, this));
1116
timeline.reset(data.move);
1117
fixup(data, minExtent, maxExtent);
1123
//----------------------------------------------------------------------------
1126
\instantiates QQuickGridView
1127
\inqmlmodule QtQuick
1128
\ingroup qtquick-views
1131
\brief For specifying a grid view of items provided by a model
1133
A GridView displays data from models created from built-in QML types like ListModel
1134
and XmlListModel, or custom model classes defined in C++ that inherit from
1137
A GridView has a \l model, which defines the data to be displayed, and
1138
a \l delegate, which defines how the data should be displayed. Items in a
1139
GridView are laid out horizontally or vertically. Grid views are inherently flickable
1140
as GridView inherits from \l Flickable.
1142
\section1 Example Usage
1144
The following example shows the definition of a simple list model defined
1145
in a file called \c ContactModel.qml:
1147
\snippet qml/gridview/ContactModel.qml 0
1149
\div {class="float-right"}
1150
\inlineimage gridview-simple.png
1153
This model can be referenced as \c ContactModel in other QML files. See \l{QML Modules}
1154
for more information about creating reusable components like this.
1156
Another component can display this model data in a GridView, as in the following
1157
example, which creates a \c ContactModel component for its model, and a \l Column
1158
(containing \l Image and \l Text items) for its delegate.
1161
\snippet qml/gridview/gridview.qml import
1163
\snippet qml/gridview/gridview.qml classdocs simple
1165
\div {class="float-right"}
1166
\inlineimage gridview-highlight.png
1169
The view will create a new delegate for each item in the model. Note that the delegate
1170
is able to access the model's \c name and \c portrait data directly.
1172
An improved grid view is shown below. The delegate is visually improved and is moved
1173
into a separate \c contactDelegate component.
1176
\snippet qml/gridview/gridview.qml classdocs advanced
1178
The currently selected item is highlighted with a blue \l Rectangle using the \l highlight property,
1179
and \c focus is set to \c true to enable keyboard navigation for the grid view.
1180
The grid view itself is a focus scope (see \l{Keyboard Focus in Qt Quick} for more details).
1182
Delegates are instantiated as needed and may be destroyed at any time.
1183
State should \e never be stored in a delegate.
1185
GridView attaches a number of properties to the root item of the delegate, for example
1186
\c {GridView.isCurrentItem}. In the following example, the root delegate item can access
1187
this attached property directly as \c GridView.isCurrentItem, while the child
1188
\c contactInfo object must refer to this property as \c wrapper.GridView.isCurrentItem.
1190
\snippet qml/gridview/gridview.qml isCurrentItem
1192
\note Views do not set the \l{Item::}{clip} property automatically.
1193
If the view is not clipped by another item or the screen, it will be necessary
1194
to set this property to true in order to clip the items that are partially or
1195
fully outside the view.
1198
\section1 GridView layouts
1200
The layout of the items in a GridView can be controlled by these properties:
1203
\li \l flow - controls whether items flow from left to right (as a series of rows)
1204
or from top to bottom (as a series of columns). This value can be either
1205
GridView.FlowLeftToRight or GridView.FlowTopToBottom.
1206
\li \l layoutDirection - controls the horizontal layout direction: that is, whether items
1207
are laid out from the left side of the view to the right, or vice-versa. This value can
1208
be either Qt.LeftToRight or Qt.RightToLeft.
1209
\li \l verticalLayoutDirection - controls the vertical layout direction: that is, whether items
1210
are laid out from the top of the view down towards the bottom of the view, or vice-versa.
1211
This value can be either GridView.TopToBottom or GridView.BottomToTop.
1214
By default, a GridView flows from left to right, and items are laid out from left to right
1215
horizontally, and from top to bottom vertically.
1217
These properties can be combined to produce a variety of layouts, as shown in the table below.
1218
The GridViews in the first row all have a \l flow value of GridView.FlowLeftToRight, but use
1219
different combinations of horizontal and vertical layout directions (specified by \l layoutDirection
1220
and \l verticalLayoutDirection respectively). Similarly, the GridViews in the second row below
1221
all have a \l flow value of GridView.FlowTopToBottom, but use different combinations of horizontal and
1222
vertical layout directions to lay out their items in different ways.
1227
\b GridViews with GridView.FlowLeftToRight flow
1229
\li \b (H) Left to right \b (V) Top to bottom
1230
\image gridview-layout-lefttoright-ltr-ttb.png
1231
\li \b (H) Right to left \b (V) Top to bottom
1232
\image gridview-layout-lefttoright-rtl-ttb.png
1233
\li \b (H) Left to right \b (V) Bottom to top
1234
\image gridview-layout-lefttoright-ltr-btt.png
1235
\li \b (H) Right to left \b (V) Bottom to top
1236
\image gridview-layout-lefttoright-rtl-btt.png
1239
\b GridViews with GridView.FlowTopToBottom flow
1241
\li \b (H) Left to right \b (V) Top to bottom
1242
\image gridview-layout-toptobottom-ltr-ttb.png
1243
\li \b (H) Right to left \b (V) Top to bottom
1244
\image gridview-layout-toptobottom-rtl-ttb.png
1245
\li \b (H) Left to right \b (V) Bottom to top
1246
\image gridview-layout-toptobottom-ltr-btt.png
1247
\li \b (H) Right to left \b (V) Bottom to top
1248
\image gridview-layout-toptobottom-rtl-btt.png
1251
\sa {QML Data Models}, ListView, PathView, {Qt Quick Examples - Views}
1254
QQuickGridView::QQuickGridView(QQuickItem *parent)
1255
: QQuickItemView(*(new QQuickGridViewPrivate), parent)
1259
QQuickGridView::~QQuickGridView()
1263
void QQuickGridView::setHighlightFollowsCurrentItem(bool autoHighlight)
1265
Q_D(QQuickGridView);
1266
if (d->autoHighlight != autoHighlight) {
1267
if (!autoHighlight && d->highlightXAnimator) {
1268
d->highlightXAnimator->stop();
1269
d->highlightYAnimator->stop();
1271
QQuickItemView::setHighlightFollowsCurrentItem(autoHighlight);
1276
\qmlattachedproperty bool QtQuick::GridView::isCurrentItem
1277
This attached property is true if this delegate is the current item; otherwise false.
1279
It is attached to each instance of the delegate.
1283
\qmlattachedproperty GridView QtQuick::GridView::view
1284
This attached property holds the view that manages this delegate instance.
1286
It is attached to each instance of the delegate and also to the header, the footer
1287
and the highlight delegates.
1289
\snippet qml/gridview/gridview.qml isCurrentItem
1293
\qmlattachedproperty bool QtQuick::GridView::delayRemove
1294
This attached property holds whether the delegate may be destroyed. It
1295
is attached to each instance of the delegate. The default value is false.
1297
It is sometimes necessary to delay the destruction of an item
1298
until an animation completes. The example delegate below ensures that the
1299
animation completes before the item is removed from the list.
1301
\snippet qml/gridview/gridview.qml delayRemove
1303
If a \l remove transition has been specified, it will not be applied until
1304
delayRemove is returned to \c false.
1308
\qmlattachedsignal QtQuick::GridView::add()
1309
This attached signal is emitted immediately after an item is added to the view.
1311
The corresponding handler is \c onAdd.
1315
\qmlattachedsignal QtQuick::GridView::remove()
1316
This attached signal is emitted immediately before an item is removed from the view.
1318
If a \l remove transition has been specified, it is applied after
1319
this signal is handled, providing that \l delayRemove is false.
1321
The corresponding handler is \c onRemove.
1326
\qmlproperty model QtQuick::GridView::model
1327
This property holds the model providing data for the grid.
1329
The model provides the set of data that is used to create the items
1330
in the view. Models can be created directly in QML using \l ListModel, \l XmlListModel
1331
or \l VisualItemModel, or provided by C++ model classes. If a C++ model class is
1332
used, it must be a subclass of \l QAbstractItemModel or a simple list.
1334
\sa {qml-data-models}{Data Models}
1338
\qmlproperty Component QtQuick::GridView::delegate
1340
The delegate provides a template defining each item instantiated by the view.
1341
The index is exposed as an accessible \c index property. Properties of the
1342
model are also available depending upon the type of \l {qml-data-models}{Data Model}.
1344
The number of objects and bindings in the delegate has a direct effect on the
1345
flicking performance of the view. If at all possible, place functionality
1346
that is not needed for the normal display of the delegate in a \l Loader which
1347
can load additional components when needed.
1349
The item size of the GridView is determined by cellHeight and cellWidth. It will not resize the items
1350
based on the size of the root item in the delegate.
1352
The default \l {QQuickItem::z}{stacking order} of delegate instances is \c 1.
1354
\note Delegates are instantiated as needed and may be destroyed at any time.
1355
State should \e never be stored in a delegate.
1359
\qmlproperty int QtQuick::GridView::currentIndex
1360
\qmlproperty Item QtQuick::GridView::currentItem
1362
The \c currentIndex property holds the index of the current item, and
1363
\c currentItem holds the current item. Setting the currentIndex to -1
1364
will clear the highlight and set currentItem to null.
1366
If highlightFollowsCurrentItem is \c true, setting either of these
1367
properties will smoothly scroll the GridView so that the current
1368
item becomes visible.
1370
Note that the position of the current item
1371
may only be approximate until it becomes visible in the view.
1376
\qmlproperty Item QtQuick::GridView::highlightItem
1378
This holds the highlight item created from the \l highlight component.
1380
The highlightItem is managed by the view unless
1381
\l highlightFollowsCurrentItem is set to false.
1382
The default \l {QQuickItem::z}{stacking order}
1383
of the highlight item is \c 0.
1385
\sa highlight, highlightFollowsCurrentItem
1390
\qmlproperty int QtQuick::GridView::count
1391
This property holds the number of items in the view.
1396
\qmlproperty Component QtQuick::GridView::highlight
1397
This property holds the component to use as the highlight.
1399
An instance of the highlight component is created for each view.
1400
The geometry of the resulting component instance will be managed by the view
1401
so as to stay with the current item, unless the highlightFollowsCurrentItem property is false.
1402
The default \l {QQuickItem::z}{stacking order} of the highlight item is \c 0.
1404
\sa highlightItem, highlightFollowsCurrentItem
1408
\qmlproperty bool QtQuick::GridView::highlightFollowsCurrentItem
1409
This property sets whether the highlight is managed by the view.
1411
If this property is true (the default value), the highlight is moved smoothly
1412
to follow the current item. Otherwise, the
1413
highlight is not moved by the view, and any movement must be implemented
1416
Here is a highlight with its motion defined by a \l {SpringAnimation} item:
1418
\snippet qml/gridview/gridview.qml highlightFollowsCurrentItem
1423
\qmlproperty int QtQuick::GridView::highlightMoveDuration
1424
This property holds the move animation duration of the highlight delegate.
1426
highlightFollowsCurrentItem must be true for this property
1429
The default value for the duration is 150ms.
1431
\sa highlightFollowsCurrentItem
1435
\qmlproperty real QtQuick::GridView::preferredHighlightBegin
1436
\qmlproperty real QtQuick::GridView::preferredHighlightEnd
1437
\qmlproperty enumeration QtQuick::GridView::highlightRangeMode
1439
These properties define the preferred range of the highlight (for the current item)
1440
within the view. The \c preferredHighlightBegin value must be less than the
1441
\c preferredHighlightEnd value.
1443
These properties affect the position of the current item when the view is scrolled.
1444
For example, if the currently selected item should stay in the middle of the
1445
view when it is scrolled, set the \c preferredHighlightBegin and
1446
\c preferredHighlightEnd values to the top and bottom coordinates of where the middle
1447
item would be. If the \c currentItem is changed programmatically, the view will
1448
automatically scroll so that the current item is in the middle of the view.
1449
Furthermore, the behavior of the current item index will occur whether or not a
1452
Valid values for \c highlightRangeMode are:
1455
\li GridView.ApplyRange - the view attempts to maintain the highlight within the range.
1456
However, the highlight can move outside of the range at the ends of the view or due
1457
to mouse interaction.
1458
\li GridView.StrictlyEnforceRange - the highlight never moves outside of the range.
1459
The current item changes if a keyboard or mouse action would cause the highlight to move
1460
outside of the range.
1461
\li GridView.NoHighlightRange - this is the default value.
1467
\qmlproperty enumeration QtQuick::GridView::layoutDirection
1468
This property holds the layout direction of the grid.
1473
\li Qt.LeftToRight (default) - Items will be laid out starting in the top, left corner. The flow is
1474
dependent on the \l GridView::flow property.
1475
\li Qt.RightToLeft - Items will be laid out starting in the top, right corner. The flow is dependent
1476
on the \l GridView::flow property.
1479
\b Note: If GridView::flow is set to GridView.FlowLeftToRight, this is not to be confused if
1480
GridView::layoutDirection is set to Qt.RightToLeft. The GridView.FlowLeftToRight flow value simply
1481
indicates that the flow is horizontal.
1483
\sa GridView::effectiveLayoutDirection, GridView::verticalLayoutDirection
1488
\qmlproperty enumeration QtQuick::GridView::effectiveLayoutDirection
1489
This property holds the effective layout direction of the grid.
1491
When using the attached property \l {LayoutMirroring::enabled}{LayoutMirroring::enabled} for locale layouts,
1492
the visual layout direction of the grid will be mirrored. However, the
1493
property \l {GridView::layoutDirection}{layoutDirection} will remain unchanged.
1495
\sa GridView::layoutDirection, {LayoutMirroring}{LayoutMirroring}
1499
\qmlproperty enumeration QtQuick::GridView::verticalLayoutDirection
1500
This property holds the vertical layout direction of the grid.
1505
\li GridView.TopToBottom (default) - Items are laid out from the top of the view down to the bottom of the view.
1506
\li GridView.BottomToTop - Items are laid out from the bottom of the view up to the top of the view.
1509
\sa GridView::layoutDirection
1513
\qmlproperty bool QtQuick::GridView::keyNavigationWraps
1514
This property holds whether the grid wraps key navigation
1516
If this is true, key navigation that would move the current item selection
1517
past one end of the view instead wraps around and moves the selection to
1518
the other end of the view.
1520
By default, key navigation is not wrapped.
1523
\qmlproperty int QtQuick::GridView::cacheBuffer
1524
This property determines whether delegates are retained outside the
1525
visible area of the view.
1527
If non-zero the view may keep as many delegates
1528
instantiated as will fit within the buffer specified. For example,
1529
if in a vertical view the delegate is 20 pixels high, there are 3
1530
columns and \c cacheBuffer is
1531
set to 40, then up to 6 delegates above and 6 delegates below the visible
1532
area may be created/retained. The buffered delegates are created asynchronously,
1533
allowing creation to occur across multiple frames and reducing the
1534
likelihood of skipping frames. In order to improve painting performance
1535
delegates outside the visible area are not painted.
1537
The default value of this property is platform dependent, but will usually
1538
be a non-zero value.
1540
Note that cacheBuffer is not a pixel buffer - it only maintains additional
1541
instantiated delegates.
1543
Setting this value can make scrolling the list smoother at the expense
1544
of additional memory usage. It is not a substitute for creating efficient
1545
delegates; the fewer objects and bindings in a delegate, the faster a view may be
1548
The cacheBuffer operates outside of any display margins specified by
1549
displayMarginBeginning or displayMarginEnd.
1553
\qmlproperty int QtQuick::GridView::displayMarginBeginning
1554
\qmlproperty int QtQuick::GridView::displayMarginEnd
1557
This property allows delegates to be displayed outside of the view geometry.
1559
If this value is non-zero, the view will create extra delegates before the
1560
start of the view, or after the end. The view will create as many delegates
1561
as it can fit into the pixel size specified.
1563
For example, if in a vertical view the delegate is 20 pixels high,
1564
there are 3 columns, and
1565
\c displayMarginBeginning and \c displayMarginEnd are both set to 40,
1566
then 6 delegates above and 6 delegates below will be created and shown.
1568
The default value is 0.
1570
This property is meant for allowing certain UI configurations,
1571
and not as a performance optimization. If you wish to create delegates
1572
outside of the view geometry for performance reasons, you probably
1573
want to use the cacheBuffer property instead.
1576
void QQuickGridView::setHighlightMoveDuration(int duration)
1578
Q_D(QQuickGridView);
1579
if (d->highlightMoveDuration != duration) {
1580
if (d->highlightYAnimator) {
1581
d->highlightXAnimator->userDuration = duration;
1582
d->highlightYAnimator->userDuration = duration;
1584
QQuickItemView::setHighlightMoveDuration(duration);
1589
\qmlproperty enumeration QtQuick::GridView::flow
1590
This property holds the flow of the grid.
1595
\li GridView.FlowLeftToRight (default) - Items are laid out from left to right, and the view scrolls vertically
1596
\li GridView.FlowTopToBottom - Items are laid out from top to bottom, and the view scrolls horizontally
1599
QQuickGridView::Flow QQuickGridView::flow() const
1601
Q_D(const QQuickGridView);
1605
void QQuickGridView::setFlow(Flow flow)
1607
Q_D(QQuickGridView);
1608
if (d->flow != flow) {
1610
if (d->flow == FlowLeftToRight) {
1611
setContentWidth(-1);
1612
setFlickableDirection(VerticalFlick);
1614
setContentHeight(-1);
1615
setFlickableDirection(HorizontalFlick);
1626
\qmlproperty real QtQuick::GridView::cellWidth
1627
\qmlproperty real QtQuick::GridView::cellHeight
1629
These properties holds the width and height of each cell in the grid.
1631
The default cell size is 100x100.
1633
qreal QQuickGridView::cellWidth() const
1635
Q_D(const QQuickGridView);
1636
return d->cellWidth;
1639
void QQuickGridView::setCellWidth(qreal cellWidth)
1641
Q_D(QQuickGridView);
1642
if (cellWidth != d->cellWidth && cellWidth > 0) {
1643
d->cellWidth = qMax(qreal(1), cellWidth);
1644
d->updateViewport();
1645
emit cellWidthChanged();
1646
d->forceLayoutPolish();
1650
qreal QQuickGridView::cellHeight() const
1652
Q_D(const QQuickGridView);
1653
return d->cellHeight;
1656
void QQuickGridView::setCellHeight(qreal cellHeight)
1658
Q_D(QQuickGridView);
1659
if (cellHeight != d->cellHeight && cellHeight > 0) {
1660
d->cellHeight = qMax(qreal(1), cellHeight);
1661
d->updateViewport();
1662
emit cellHeightChanged();
1663
d->forceLayoutPolish();
1667
\qmlproperty enumeration QtQuick::GridView::snapMode
1669
This property determines how the view scrolling will settle following a drag or flick.
1670
The possible values are:
1673
\li GridView.NoSnap (default) - the view stops anywhere within the visible area.
1674
\li GridView.SnapToRow - the view settles with a row (or column for \c GridView.FlowTopToBottom flow)
1675
aligned with the start of the view.
1676
\li GridView.SnapOneRow - the view will settle no more than one row (or column for \c GridView.FlowTopToBottom flow)
1677
away from the first visible row at the time the mouse button is released.
1678
This mode is particularly useful for moving one page at a time.
1682
QQuickGridView::SnapMode QQuickGridView::snapMode() const
1684
Q_D(const QQuickGridView);
1688
void QQuickGridView::setSnapMode(SnapMode mode)
1690
Q_D(QQuickGridView);
1691
if (d->snapMode != mode) {
1693
emit snapModeChanged();
1699
\qmlproperty Component QtQuick::GridView::footer
1700
This property holds the component to use as the footer.
1702
An instance of the footer component is created for each view. The
1703
footer is positioned at the end of the view, after any items. The
1704
default \l {QQuickItem::z}{stacking order} of the footer is \c 1.
1706
\sa header, footerItem
1709
\qmlproperty Component QtQuick::GridView::header
1710
This property holds the component to use as the header.
1712
An instance of the header component is created for each view. The
1713
header is positioned at the beginning of the view, before any items.
1714
The default \l {QQuickItem::z}{stacking order} of the header is \c 1.
1716
\sa footer, headerItem
1720
\qmlproperty Item QtQuick::GridView::headerItem
1721
This holds the header item created from the \l header component.
1723
An instance of the header component is created for each view. The
1724
header is positioned at the beginning of the view, before any items.
1725
The default \l {QQuickItem::z}{stacking order} of the header is \c 1.
1727
\sa header, footerItem
1731
\qmlproperty Item QtQuick::GridView::footerItem
1732
This holds the footer item created from the \l footer component.
1734
An instance of the footer component is created for each view. The
1735
footer is positioned at the end of the view, after any items. The
1736
default \l {QQuickItem::z}{stacking order} of the footer is \c 1.
1738
\sa footer, headerItem
1742
\qmlproperty Transition QtQuick::GridView::populate
1744
This property holds the transition to apply to the items that are initially created
1747
It is applied to all items that are created when:
1750
\li The view is first created
1751
\li The view's \l model changes
1752
\li The view's \l model is \l {QAbstractItemModel::reset()}{reset}, if the model is a QAbstractItemModel subclass
1755
For example, here is a view that specifies such a transition:
1760
populate: Transition {
1761
NumberAnimation { properties: "x,y"; duration: 1000 }
1766
When the view is initialized, the view will create all the necessary items for the view,
1767
then animate them to their correct positions within the view over one second.
1769
For more details and examples on how to use view transitions, see the ViewTransition
1772
\sa add, ViewTransition
1776
\qmlproperty Transition QtQuick::GridView::add
1778
This property holds the transition to apply to items that are added to the view.
1780
For example, here is a view that specifies such a transition:
1786
NumberAnimation { properties: "x,y"; from: 100; duration: 1000 }
1791
Whenever an item is added to the above view, the item will be animated from the position (100,100)
1792
to its final x,y position within the view, over one second. The transition only applies to
1793
the new items that are added to the view; it does not apply to the items below that are
1794
displaced by the addition of the new items. To animate the displaced items, set the \l displaced
1795
or \l addDisplaced properties.
1797
For more details and examples on how to use view transitions, see the ViewTransition
1800
\note This transition is not applied to the items that are created when the view is initially
1801
populated, or when the view's \l model changes. (In those cases, the \l populate transition is
1802
applied instead.) Additionally, this transition should \e not animate the height of the new item;
1803
doing so will cause any items beneath the new item to be laid out at the wrong position. Instead,
1804
the height can be animated within the \l {add}{onAdd} handler in the delegate.
1806
\sa addDisplaced, populate, ViewTransition
1810
\qmlproperty Transition QtQuick::GridView::addDisplaced
1812
This property holds the transition to apply to items within the view that are displaced by
1813
the addition of other items to the view.
1815
For example, here is a view that specifies such a transition:
1820
addDisplaced: Transition {
1821
NumberAnimation { properties: "x,y"; duration: 1000 }
1826
Whenever an item is added to the above view, all items beneath the new item are displaced, causing
1827
them to move down (or sideways, if horizontally orientated) within the view. As this
1828
displacement occurs, the items' movement to their new x,y positions within the view will be
1829
animated by a NumberAnimation over one second, as specified. This transition is not applied to
1830
the new item that has been added to the view; to animate the added items, set the \l add
1833
If an item is displaced by multiple types of operations at the same time, it is not defined as to
1834
whether the addDisplaced, moveDisplaced or removeDisplaced transition will be applied. Additionally,
1835
if it is not necessary to specify different transitions depending on whether an item is displaced
1836
by an add, move or remove operation, consider setting the \l displaced property instead.
1838
For more details and examples on how to use view transitions, see the ViewTransition
1841
\note This transition is not applied to the items that are created when the view is initially
1842
populated, or when the view's \l model changes. In those cases, the \l populate transition is
1845
\sa displaced, add, populate, ViewTransition
1848
\qmlproperty Transition QtQuick::GridView::move
1850
This property holds the transition to apply to items in the view that are being moved due
1851
to a move operation in the view's \l model.
1853
For example, here is a view that specifies such a transition:
1859
NumberAnimation { properties: "x,y"; duration: 1000 }
1864
Whenever the \l model performs a move operation to move a particular set of indexes, the
1865
respective items in the view will be animated to their new positions in the view over one
1866
second. The transition only applies to the items that are the subject of the move operation
1867
in the model; it does not apply to items below them that are displaced by the move operation.
1868
To animate the displaced items, set the \l displaced or \l moveDisplaced properties.
1870
For more details and examples on how to use view transitions, see the ViewTransition
1873
\sa moveDisplaced, ViewTransition
1877
\qmlproperty Transition QtQuick::GridView::moveDisplaced
1879
This property holds the transition to apply to items that are displaced by a move operation in
1880
the view's \l model.
1882
For example, here is a view that specifies such a transition:
1887
moveDisplaced: Transition {
1888
NumberAnimation { properties: "x,y"; duration: 1000 }
1893
Whenever the \l model performs a move operation to move a particular set of indexes, the items
1894
between the source and destination indexes of the move operation are displaced, causing them
1895
to move upwards or downwards (or sideways, if horizontally orientated) within the view. As this
1896
displacement occurs, the items' movement to their new x,y positions within the view will be
1897
animated by a NumberAnimation over one second, as specified. This transition is not applied to
1898
the items that are the actual subjects of the move operation; to animate the moved items, set
1899
the \l move property.
1901
If an item is displaced by multiple types of operations at the same time, it is not defined as to
1902
whether the addDisplaced, moveDisplaced or removeDisplaced transition will be applied. Additionally,
1903
if it is not necessary to specify different transitions depending on whether an item is displaced
1904
by an add, move or remove operation, consider setting the \l displaced property instead.
1906
For more details and examples on how to use view transitions, see the ViewTransition
1909
\sa displaced, move, ViewTransition
1913
\qmlproperty Transition QtQuick::GridView::remove
1915
This property holds the transition to apply to items that are removed from the view.
1917
For example, here is a view that specifies such a transition:
1922
remove: Transition {
1924
NumberAnimation { property: "opacity"; to: 0; duration: 1000 }
1925
NumberAnimation { properties: "x,y"; to: 100; duration: 1000 }
1931
Whenever an item is removed from the above view, the item will be animated to the position (100,100)
1932
over one second, and in parallel will also change its opacity to 0. The transition
1933
only applies to the items that are removed from the view; it does not apply to the items below
1934
them that are displaced by the removal of the items. To animate the displaced items, set the
1935
\l displaced or \l removeDisplaced properties.
1937
Note that by the time the transition is applied, the item has already been removed from the
1938
model; any references to the model data for the removed index will not be valid.
1940
Additionally, if the \l delayRemove attached property has been set for a delegate item, the
1941
remove transition will not be applied until \l delayRemove becomes false again.
1943
For more details and examples on how to use view transitions, see the ViewTransition
1946
\sa removeDisplaced, ViewTransition
1950
\qmlproperty Transition QtQuick::GridView::removeDisplaced
1952
This property holds the transition to apply to items in the view that are displaced by the
1953
removal of other items in the view.
1955
For example, here is a view that specifies such a transition:
1960
removeDisplaced: Transition {
1961
NumberAnimation { properties: "x,y"; duration: 1000 }
1966
Whenever an item is removed from the above view, all items beneath it are displaced, causing
1967
them to move upwards (or sideways, if horizontally orientated) within the view. As this
1968
displacement occurs, the items' movement to their new x,y positions within the view will be
1969
animated by a NumberAnimation over one second, as specified. This transition is not applied to
1970
the item that has actually been removed from the view; to animate the removed items, set the
1973
If an item is displaced by multiple types of operations at the same time, it is not defined as to
1974
whether the addDisplaced, moveDisplaced or removeDisplaced transition will be applied. Additionally,
1975
if it is not necessary to specify different transitions depending on whether an item is displaced
1976
by an add, move or remove operation, consider setting the \l displaced property instead.
1978
For more details and examples on how to use view transitions, see the ViewTransition
1981
\sa displaced, remove, ViewTransition
1985
\qmlproperty Transition QtQuick::GridView::displaced
1986
This property holds the generic transition to apply to items that have been displaced by
1987
any model operation that affects the view.
1989
This is a convenience for specifying a generic transition for items that are displaced
1990
by add, move or remove operations, without having to specify the individual addDisplaced,
1991
moveDisplaced and removeDisplaced properties. For example, here is a view that specifies
1992
a displaced transition:
1997
displaced: Transition {
1998
NumberAnimation { properties: "x,y"; duration: 1000 }
2003
When any item is added, moved or removed within the above view, the items below it are
2004
displaced, causing them to move down (or sideways, if horizontally orientated) within the
2005
view. As this displacement occurs, the items' movement to their new x,y positions within
2006
the view will be animated by a NumberAnimation over one second, as specified.
2008
If a view specifies this generic displaced transition as well as a specific addDisplaced,
2009
moveDisplaced or removeDisplaced transition, the more specific transition will be used
2010
instead of the generic displaced transition when the relevant operation occurs, providing that
2011
the more specific transition has not been disabled (by setting \l {Transition::enabled}{enabled}
2012
to false). If it has indeed been disabled, the generic displaced transition is applied instead.
2014
For more details and examples on how to use view transitions, see the ViewTransition
2017
\sa addDisplaced, moveDisplaced, removeDisplaced, ViewTransition
2020
void QQuickGridView::viewportMoved(Qt::Orientations orient)
2022
Q_D(QQuickGridView);
2023
QQuickItemView::viewportMoved(orient);
2026
if (d->inViewportMoved)
2028
d->inViewportMoved = true;
2031
if (d->isContentFlowReversed())
2032
d->bufferMode = d->vData.smoothVelocity < 0 ? QQuickItemViewPrivate::BufferAfter : QQuickItemViewPrivate::BufferBefore;
2034
d->bufferMode = d->vData.smoothVelocity < 0 ? QQuickItemViewPrivate::BufferBefore : QQuickItemViewPrivate::BufferAfter;
2036
if (d->isContentFlowReversed())
2037
d->bufferMode = d->hData.smoothVelocity < 0 ? QQuickItemViewPrivate::BufferAfter : QQuickItemViewPrivate::BufferBefore;
2039
d->bufferMode = d->hData.smoothVelocity < 0 ? QQuickItemViewPrivate::BufferBefore : QQuickItemViewPrivate::BufferAfter;
2042
d->refillOrLayout();
2044
// Set visibility of items to eliminate cost of items outside the visible area.
2045
qreal from = d->isContentFlowReversed() ? -d->position()-d->displayMarginBeginning-d->size() : d->position()-d->displayMarginBeginning;
2046
qreal to = d->isContentFlowReversed() ? -d->position()+d->displayMarginEnd : d->position()+d->size()+d->displayMarginEnd;
2047
for (int i = 0; i < d->visibleItems.count(); ++i) {
2048
FxGridItemSG *item = static_cast<FxGridItemSG*>(d->visibleItems.at(i));
2049
QQuickItemPrivate::get(item->item)->setCulled(item->rowPos() + d->rowSize() < from || item->rowPos() > to);
2051
if (d->currentItem) {
2052
FxGridItemSG *item = static_cast<FxGridItemSG*>(d->currentItem);
2053
QQuickItemPrivate::get(item->item)->setCulled(item->rowPos() + d->rowSize() < from || item->rowPos() > to);
2056
if (d->hData.flicking || d->vData.flicking || d->hData.moving || d->vData.moving)
2057
d->moveReason = QQuickGridViewPrivate::Mouse;
2058
if (d->moveReason != QQuickGridViewPrivate::SetIndex) {
2059
if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange && d->highlight) {
2060
// reposition highlight
2061
qreal pos = d->highlight->position();
2062
qreal viewPos = d->isContentFlowReversed() ? -d->position()-d->size() : d->position();
2063
if (pos > viewPos + d->highlightRangeEnd - d->highlight->size())
2064
pos = viewPos + d->highlightRangeEnd - d->highlight->size();
2065
if (pos < viewPos + d->highlightRangeStart)
2066
pos = viewPos + d->highlightRangeStart;
2068
if (pos != d->highlight->position()) {
2069
d->highlightXAnimator->stop();
2070
d->highlightYAnimator->stop();
2071
static_cast<FxGridItemSG*>(d->highlight)->setPosition(static_cast<FxGridItemSG*>(d->highlight)->colPos(), pos);
2073
d->updateHighlight();
2076
// update current index
2077
int idx = d->snapIndex();
2078
if (idx >= 0 && idx != d->currentIndex) {
2079
d->updateCurrent(idx);
2080
if (d->currentItem && static_cast<FxGridItemSG*>(d->currentItem)->colPos() != static_cast<FxGridItemSG*>(d->highlight)->colPos() && d->autoHighlight) {
2081
if (d->flow == FlowLeftToRight)
2082
d->highlightXAnimator->to = d->currentItem->itemX();
2084
d->highlightYAnimator->to = d->currentItem->itemY();
2090
d->inViewportMoved = false;
2093
void QQuickGridView::keyPressEvent(QKeyEvent *event)
2095
Q_D(QQuickGridView);
2096
if (d->model && d->model->count() && d->interactive) {
2097
d->moveReason = QQuickGridViewPrivate::SetIndex;
2098
int oldCurrent = currentIndex();
2099
switch (event->key()) {
2101
moveCurrentIndexUp();
2104
moveCurrentIndexDown();
2107
moveCurrentIndexLeft();
2110
moveCurrentIndexRight();
2115
if (oldCurrent != currentIndex() || d->wrap) {
2121
QQuickItemView::keyPressEvent(event);
2124
void QQuickGridView::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
2126
Q_D(QQuickGridView);
2129
if (newGeometry.width() != oldGeometry.width()
2130
&& newGeometry.height() != oldGeometry.height()) {
2131
d->setPosition(d->position());
2132
} else if (newGeometry.width() != oldGeometry.width()) {
2133
QQuickFlickable::setContentX(d->contentXForPosition(d->position()));
2134
} else if (newGeometry.height() != oldGeometry.height()) {
2135
QQuickFlickable::setContentY(d->contentYForPosition(d->position()));
2138
QQuickItemView::geometryChanged(newGeometry, oldGeometry);
2141
void QQuickGridView::initItem(int index, QObject *obj)
2143
QQuickItemView::initItem(index, obj);
2145
// setting the view from the FxViewItem wrapper is too late if the delegate
2146
// needs access to the view in Component.onCompleted
2147
QQuickItem *item = qmlobject_cast<QQuickItem*>(obj);
2149
QQuickGridViewAttached *attached = static_cast<QQuickGridViewAttached *>(
2150
qmlAttachedPropertiesObject<QQuickGridView>(item));
2152
attached->setView(this);
2157
\qmlmethod QtQuick::GridView::moveCurrentIndexUp()
2159
Move the currentIndex up one item in the view.
2160
The current index will wrap if keyNavigationWraps is true and it
2161
is currently at the end. This method has no effect if the \l count is zero.
2163
\b Note: methods should only be called after the Component has completed.
2167
void QQuickGridView::moveCurrentIndexUp()
2169
Q_D(QQuickGridView);
2170
const int count = d->model ? d->model->count() : 0;
2173
if (d->verticalLayoutDirection == QQuickItemView::TopToBottom) {
2174
if (d->flow == QQuickGridView::FlowLeftToRight) {
2175
if (currentIndex() >= d->columns || d->wrap) {
2176
int index = currentIndex() - d->columns;
2177
setCurrentIndex((index >= 0 && index < count) ? index : count-1);
2180
if (currentIndex() > 0 || d->wrap) {
2181
int index = currentIndex() - 1;
2182
setCurrentIndex((index >= 0 && index < count) ? index : count-1);
2186
if (d->flow == QQuickGridView::FlowLeftToRight) {
2187
if (currentIndex() < count - d->columns || d->wrap) {
2188
int index = currentIndex()+d->columns;
2189
setCurrentIndex((index >= 0 && index < count) ? index : 0);
2192
if (currentIndex() < count - 1 || d->wrap) {
2193
int index = currentIndex() + 1;
2194
setCurrentIndex((index >= 0 && index < count) ? index : 0);
2201
\qmlmethod QtQuick::GridView::moveCurrentIndexDown()
2203
Move the currentIndex down one item in the view.
2204
The current index will wrap if keyNavigationWraps is true and it
2205
is currently at the end. This method has no effect if the \l count is zero.
2207
\b Note: methods should only be called after the Component has completed.
2209
void QQuickGridView::moveCurrentIndexDown()
2211
Q_D(QQuickGridView);
2212
const int count = d->model ? d->model->count() : 0;
2216
if (d->verticalLayoutDirection == QQuickItemView::TopToBottom) {
2217
if (d->flow == QQuickGridView::FlowLeftToRight) {
2218
if (currentIndex() < count - d->columns || d->wrap) {
2219
int index = currentIndex()+d->columns;
2220
setCurrentIndex((index >= 0 && index < count) ? index : 0);
2223
if (currentIndex() < count - 1 || d->wrap) {
2224
int index = currentIndex() + 1;
2225
setCurrentIndex((index >= 0 && index < count) ? index : 0);
2229
if (d->flow == QQuickGridView::FlowLeftToRight) {
2230
if (currentIndex() >= d->columns || d->wrap) {
2231
int index = currentIndex() - d->columns;
2232
setCurrentIndex((index >= 0 && index < count) ? index : count-1);
2235
if (currentIndex() > 0 || d->wrap) {
2236
int index = currentIndex() - 1;
2237
setCurrentIndex((index >= 0 && index < count) ? index : count-1);
2244
\qmlmethod QtQuick::GridView::moveCurrentIndexLeft()
2246
Move the currentIndex left one item in the view.
2247
The current index will wrap if keyNavigationWraps is true and it
2248
is currently at the end. This method has no effect if the \l count is zero.
2250
\b Note: methods should only be called after the Component has completed.
2252
void QQuickGridView::moveCurrentIndexLeft()
2254
Q_D(QQuickGridView);
2255
const int count = d->model ? d->model->count() : 0;
2258
if (effectiveLayoutDirection() == Qt::LeftToRight) {
2259
if (d->flow == QQuickGridView::FlowLeftToRight) {
2260
if (currentIndex() > 0 || d->wrap) {
2261
int index = currentIndex() - 1;
2262
setCurrentIndex((index >= 0 && index < count) ? index : count-1);
2265
if (currentIndex() >= d->columns || d->wrap) {
2266
int index = currentIndex() - d->columns;
2267
setCurrentIndex((index >= 0 && index < count) ? index : count-1);
2271
if (d->flow == QQuickGridView::FlowLeftToRight) {
2272
if (currentIndex() < count - 1 || d->wrap) {
2273
int index = currentIndex() + 1;
2274
setCurrentIndex((index >= 0 && index < count) ? index : 0);
2277
if (currentIndex() < count - d->columns || d->wrap) {
2278
int index = currentIndex() + d->columns;
2279
setCurrentIndex((index >= 0 && index < count) ? index : 0);
2287
\qmlmethod QtQuick::GridView::moveCurrentIndexRight()
2289
Move the currentIndex right one item in the view.
2290
The current index will wrap if keyNavigationWraps is true and it
2291
is currently at the end. This method has no effect if the \l count is zero.
2293
\b Note: methods should only be called after the Component has completed.
2295
void QQuickGridView::moveCurrentIndexRight()
2297
Q_D(QQuickGridView);
2298
const int count = d->model ? d->model->count() : 0;
2301
if (effectiveLayoutDirection() == Qt::LeftToRight) {
2302
if (d->flow == QQuickGridView::FlowLeftToRight) {
2303
if (currentIndex() < count - 1 || d->wrap) {
2304
int index = currentIndex() + 1;
2305
setCurrentIndex((index >= 0 && index < count) ? index : 0);
2308
if (currentIndex() < count - d->columns || d->wrap) {
2309
int index = currentIndex()+d->columns;
2310
setCurrentIndex((index >= 0 && index < count) ? index : 0);
2314
if (d->flow == QQuickGridView::FlowLeftToRight) {
2315
if (currentIndex() > 0 || d->wrap) {
2316
int index = currentIndex() - 1;
2317
setCurrentIndex((index >= 0 && index < count) ? index : count-1);
2320
if (currentIndex() >= d->columns || d->wrap) {
2321
int index = currentIndex() - d->columns;
2322
setCurrentIndex((index >= 0 && index < count) ? index : count-1);
2328
bool QQuickGridViewPrivate::applyInsertionChange(const QQmlChangeSet::Insert &change, ChangeResult *insertResult, QList<FxViewItem *> *addedItems, QList<MovedItem> *movingIntoView)
2330
Q_Q(QQuickGridView);
2332
int modelIndex = change.index;
2333
int count = change.count;
2335
int index = visibleItems.count() ? mapFromModel(modelIndex) : 0;
2338
int i = visibleItems.count() - 1;
2339
while (i > 0 && visibleItems.at(i)->index == -1)
2341
if (visibleItems.at(i)->index + 1 == modelIndex) {
2342
// Special case of appending an item to the model.
2343
index = visibleItems.count();
2345
if (modelIndex <= visibleIndex) {
2346
// Insert before visible items
2347
visibleIndex += count;
2348
for (int i = 0; i < visibleItems.count(); ++i) {
2349
FxViewItem *item = visibleItems.at(i);
2350
if (item->index != -1 && item->index >= modelIndex)
2351
item->index += count;
2358
qreal tempPos = isContentFlowReversed() ? -position()-size()+q->width()+1 : position();
2362
if (visibleItems.count()) {
2363
if (index < visibleItems.count()) {
2364
FxGridItemSG *gridItem = static_cast<FxGridItemSG*>(visibleItems.at(index));
2365
colPos = gridItem->colPos();
2366
rowPos = gridItem->rowPos();
2367
colNum = qFloor((colPos+colSize()/2) / colSize());
2369
// appending items to visible list
2370
FxGridItemSG *gridItem = static_cast<FxGridItemSG*>(visibleItems.at(index-1));
2371
rowPos = gridItem->rowPos();
2372
colNum = qFloor((gridItem->colPos()+colSize()/2) / colSize());
2373
if (++colNum >= columns) {
2375
rowPos += rowSize();
2377
colPos = colNum * colSize();
2381
// Update the indexes of the following visible items.
2382
for (int i = 0; i < visibleItems.count(); ++i) {
2383
FxViewItem *item = visibleItems.at(i);
2384
if (item->index != -1 && item->index >= modelIndex) {
2385
item->index += count;
2386
if (change.isMove())
2387
item->transitionNextReposition(transitioner, QQuickItemViewTransitioner::MoveTransition, false);
2389
item->transitionNextReposition(transitioner, QQuickItemViewTransitioner::AddTransition, false);
2393
int prevVisibleCount = visibleItems.count();
2394
if (insertResult->visiblePos.isValid() && rowPos < insertResult->visiblePos) {
2395
// Insert items before the visible item.
2396
int insertionIdx = index;
2398
int from = tempPos - buffer - displayMarginBeginning;
2401
if (rowPos > from && insertionIdx < visibleIndex) {
2402
// item won't be visible, just note the size for repositioning
2403
insertResult->countChangeBeforeVisible++;
2405
// item is before first visible e.g. in cache buffer
2406
FxViewItem *item = 0;
2407
if (change.isMove() && (item = currentChanges.removedItems.take(change.moveKey(modelIndex + i))))
2408
item->index = modelIndex + i;
2410
item = createItem(modelIndex + i);
2414
QQuickItemPrivate::get(item->item)->setCulled(false);
2415
visibleItems.insert(insertionIdx, item);
2416
if (insertionIdx == 0)
2417
insertResult->changedFirstItem = true;
2418
if (!change.isMove()) {
2419
addedItems->append(item);
2420
item->transitionNextReposition(transitioner, QQuickItemViewTransitioner::AddTransition, true);
2422
insertResult->sizeChangesBeforeVisiblePos += rowSize();
2425
if (--colNum < 0 ) {
2426
colNum = columns - 1;
2427
rowPos -= rowSize();
2429
colPos = colNum * colSize();
2435
int to = buffer+displayMarginEnd+tempPos+size()-1;
2436
while (i < count && rowPos <= to + rowSize()*(columns - colNum)/qreal(columns+1)) {
2437
FxViewItem *item = 0;
2438
if (change.isMove() && (item = currentChanges.removedItems.take(change.moveKey(modelIndex + i))))
2439
item->index = modelIndex + i;
2440
bool newItem = !item;
2442
item = createItem(modelIndex + i);
2446
QQuickItemPrivate::get(item->item)->setCulled(false);
2447
visibleItems.insert(index, item);
2449
insertResult->changedFirstItem = true;
2450
if (change.isMove()) {
2451
// we know this is a move target, since move displaced items that are
2452
// shuffled into view due to a move would be added in refill()
2453
if (newItem && transitioner && transitioner->canTransition(QQuickItemViewTransitioner::MoveTransition, true))
2454
movingIntoView->append(MovedItem(item, change.moveKey(item->index)));
2456
addedItems->append(item);
2457
item->transitionNextReposition(transitioner, QQuickItemViewTransitioner::AddTransition, true);
2459
insertResult->sizeChangesAfterVisiblePos += rowSize();
2461
if (++colNum >= columns) {
2463
rowPos += rowSize();
2465
colPos = colNum * colSize();
2471
updateVisibleIndex();
2473
return visibleItems.count() > prevVisibleCount;
2476
void QQuickGridViewPrivate::translateAndTransitionItemsAfter(int afterModelIndex, const ChangeResult &insertionResult, const ChangeResult &removalResult)
2481
int markerItemIndex = -1;
2482
for (int i=0; i<visibleItems.count(); i++) {
2483
if (visibleItems[i]->index == afterModelIndex) {
2484
markerItemIndex = i;
2488
if (markerItemIndex < 0)
2491
const qreal viewEndPos = isContentFlowReversed() ? -position() : position() + size();
2492
int countItemsRemoved = -(removalResult.sizeChangesAfterVisiblePos / rowSize());
2494
// account for whether first item has changed if < 1 row was removed before visible
2495
int changeBeforeVisible = insertionResult.countChangeBeforeVisible - removalResult.countChangeBeforeVisible;
2496
if (changeBeforeVisible != 0)
2497
countItemsRemoved += (changeBeforeVisible % columns) - (columns - 1);
2499
countItemsRemoved -= removalResult.countChangeAfterVisibleItems;
2501
for (int i=markerItemIndex+1; i<visibleItems.count() && visibleItems.at(i)->position() < viewEndPos; i++) {
2502
FxGridItemSG *gridItem = static_cast<FxGridItemSG *>(visibleItems[i]);
2503
if (!gridItem->transitionScheduledOrRunning()) {
2504
qreal origRowPos = gridItem->colPos();
2505
qreal origColPos = gridItem->rowPos();
2506
int indexDiff = gridItem->index - countItemsRemoved;
2507
gridItem->setPosition((indexDiff % columns) * colSize(), (indexDiff / columns) * rowSize());
2508
gridItem->transitionNextReposition(transitioner, QQuickItemViewTransitioner::RemoveTransition, false);
2509
gridItem->setPosition(origRowPos, origColPos);
2514
bool QQuickGridViewPrivate::needsRefillForAddedOrRemovedIndex(int modelIndex) const
2516
// If we add or remove items before visible items, a layout may be
2517
// required to ensure item 0 is in the first column.
2518
return modelIndex < visibleIndex;
2522
\qmlmethod QtQuick::GridView::positionViewAtIndex(int index, PositionMode mode)
2524
Positions the view such that the \a index is at the position specified by
2528
\li GridView.Beginning - position item at the top (or left for \c GridView.FlowTopToBottom flow) of the view.
2529
\li GridView.Center - position item in the center of the view.
2530
\li GridView.End - position item at bottom (or right for horizontal orientation) of the view.
2531
\li GridView.Visible - if any part of the item is visible then take no action, otherwise
2532
bring the item into view.
2533
\li GridView.Contain - ensure the entire item is visible. If the item is larger than
2534
the view the item is positioned at the top (or left for \c GridView.FlowTopToBottom flow) of the view.
2535
\li GridView.SnapPosition - position the item at \l preferredHighlightBegin. This mode
2536
is only valid if \l highlightRangeMode is StrictlyEnforceRange or snapping is enabled
2540
If positioning the view at the index would cause empty space to be displayed at
2541
the beginning or end of the view, the view will be positioned at the boundary.
2543
It is not recommended to use \l {Flickable::}{contentX} or \l {Flickable::}{contentY} to position the view
2544
at a particular index. This is unreliable since removing items from the start
2545
of the view does not cause all other items to be repositioned.
2546
The correct way to bring an item into view is with \c positionViewAtIndex.
2548
\b Note: methods should only be called after the Component has completed. To position
2549
the view at startup, this method should be called by Component.onCompleted. For
2550
example, to position the view at the end:
2553
Component.onCompleted: positionViewAtIndex(count - 1, GridView.Beginning)
2558
\qmlmethod QtQuick::GridView::positionViewAtBeginning()
2559
\qmlmethod QtQuick::GridView::positionViewAtEnd()
2561
Positions the view at the beginning or end, taking into account any header or footer.
2563
It is not recommended to use \l {Flickable::}{contentX} or \l {Flickable::}{contentY} to position the view
2564
at a particular index. This is unreliable since removing items from the start
2565
of the list does not cause all other items to be repositioned, and because
2566
the actual start of the view can vary based on the size of the delegates.
2568
\b Note: methods should only be called after the Component has completed. To position
2569
the view at startup, this method should be called by Component.onCompleted. For
2570
example, to position the view at the end on startup:
2573
Component.onCompleted: positionViewAtEnd()
2578
\qmlmethod int QtQuick::GridView::indexAt(int x, int y)
2580
Returns the index of the visible item containing the point \a x, \a y in content
2581
coordinates. If there is no item at the point specified, or the item is
2582
not visible -1 is returned.
2584
If the item is outside the visible area, -1 is returned, regardless of
2585
whether an item will exist at that point when scrolled into view.
2587
\b Note: methods should only be called after the Component has completed.
2591
\qmlmethod Item QtQuick::GridView::itemAt(int x, int y)
2593
Returns the visible item containing the point \a x, \a y in content
2594
coordinates. If there is no item at the point specified, or the item is
2595
not visible null is returned.
2597
If the item is outside the visible area, null is returned, regardless of
2598
whether an item will exist at that point when scrolled into view.
2600
\b Note: methods should only be called after the Component has completed.
2605
\qmlmethod QtQuick::GridView::forceLayout()
2607
Responding to changes in the model is usually batched to happen only once
2608
per frame. This means that inside script blocks it is possible for the
2609
underlying model to have changed, but the GridView has not caught up yet.
2611
This method forces the GridView to immediately respond to any outstanding
2612
changes in the model.
2616
\b Note: methods should only be called after the Component has completed.
2619
QQuickGridViewAttached *QQuickGridView::qmlAttachedProperties(QObject *obj)
2621
return new QQuickGridViewAttached(obj);