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 QtQml 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 "qquickvisualitemmodel_p.h"
44
#include "qquickflickable_p_p.h"
45
#include "qquickitemview_p_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, bool trackGeometry) : FxViewItem(i, own, trackGeometry), view(v) {
69
attached = static_cast<QQuickGridViewAttached*>(qmlAttachedPropertiesObject<QQuickGridView>(item));
71
QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
72
itemPrivate->addItemChangeListener(QQuickItemViewPrivate::get(view), QQuickItemPrivate::Geometry);
78
QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
79
itemPrivate->removeItemChangeListener(QQuickItemViewPrivate::get(view), QQuickItemPrivate::Geometry);
83
qreal position() const {
87
qreal endPosition() const {
92
return view->flow() == QQuickGridView::FlowLeftToRight ? view->cellHeight() : view->cellWidth();
95
qreal sectionSize() const {
99
qreal rowPos() const {
100
if (view->flow() == QQuickGridView::FlowLeftToRight)
101
return (view->verticalLayoutDirection() == QQuickItemView::BottomToTop ? -view->cellHeight()-itemY() : itemY());
103
return (view->effectiveLayoutDirection() == Qt::RightToLeft ? -view->cellWidth()-itemX() : itemX());
106
qreal colPos() const {
107
if (view->flow() == QQuickGridView::FlowLeftToRight) {
108
if (view->effectiveLayoutDirection() == Qt::RightToLeft) {
109
qreal colSize = view->cellWidth();
110
int columns = view->width()/colSize;
111
return colSize * (columns-1) - itemX();
116
if (view->verticalLayoutDirection() == QQuickItemView::BottomToTop) {
117
return -view->cellHeight() - itemY();
123
qreal endRowPos() const {
124
if (view->flow() == QQuickGridView::FlowLeftToRight) {
125
if (view->verticalLayoutDirection() == QQuickItemView::BottomToTop)
128
return itemY() + view->cellHeight();
130
if (view->effectiveLayoutDirection() == Qt::RightToLeft)
133
return itemX() + view->cellWidth();
136
void setPosition(qreal col, qreal row, bool immediate = false) {
137
moveTo(pointForPosition(col, row), immediate);
139
bool contains(qreal x, qreal y) const {
140
return (x >= itemX() && x < itemX() + view->cellWidth() &&
141
y >= itemY() && y < itemY() + view->cellHeight());
144
QQuickGridView *view;
147
QPointF pointForPosition(qreal col, qreal row) const {
150
if (view->flow() == QQuickGridView::FlowLeftToRight) {
153
if (view->effectiveLayoutDirection() == Qt::RightToLeft) {
154
int columns = view->width()/view->cellWidth();
155
x = view->cellWidth() * (columns-1) - col;
160
if (view->effectiveLayoutDirection() == Qt::RightToLeft)
161
x = -view->cellWidth() - row;
163
if (view->verticalLayoutDirection() == QQuickItemView::BottomToTop)
164
y = -view->cellHeight() - y;
165
return QPointF(x, y);
169
//----------------------------------------------------------------------------
171
class QQuickGridViewPrivate : public QQuickItemViewPrivate
173
Q_DECLARE_PUBLIC(QQuickGridView)
176
virtual Qt::Orientation layoutOrientation() const;
177
virtual bool isContentFlowReversed() const;
179
virtual qreal positionAt(int index) const;
180
virtual qreal endPositionAt(int index) const;
181
virtual qreal originPosition() const;
182
virtual qreal lastPosition() const;
184
qreal rowSize() const;
185
qreal colSize() const;
186
qreal colPosAt(int modelIndex) const;
187
qreal rowPosAt(int modelIndex) const;
188
qreal snapPosAt(qreal pos) const;
189
FxViewItem *snapItemAt(qreal pos) const;
190
int snapIndex() const;
191
qreal contentXForPosition(qreal pos) const;
192
qreal contentYForPosition(qreal pos) const;
196
virtual bool addVisibleItems(qreal fillFrom, qreal fillTo, qreal bufferFrom, qreal bufferTo, bool doBuffer);
197
virtual bool removeNonVisibleItems(qreal bufferFrom, qreal bufferTo);
199
virtual FxViewItem *newViewItem(int index, QQuickItem *item);
200
virtual void initializeViewItem(FxViewItem *item);
201
virtual void repositionItemAt(FxViewItem *item, int index, qreal sizeBuffer);
202
virtual void repositionPackageItemAt(QQuickItem *item, int index);
203
virtual void resetFirstItemPosition(qreal pos = 0.0);
204
virtual void adjustFirstItem(qreal forwards, qreal backwards, int changeBeforeVisible);
206
virtual void createHighlight();
207
virtual void updateHighlight();
208
virtual void resetHighlightPosition();
210
virtual void setPosition(qreal pos);
211
virtual void layoutVisibleItems(int fromModelIndex = 0);
212
virtual bool applyInsertionChange(const QQuickChangeSet::Insert &insert, ChangeResult *changeResult, QList<FxViewItem *> *addedItems, QList<MovedItem> *movingIntoView);
213
virtual void translateAndTransitionItemsAfter(int afterModelIndex, const ChangeResult &insertionResult, const ChangeResult &removalResult);
214
virtual bool needsRefillForAddedOrRemovedIndex(int index) const;
216
virtual qreal headerSize() const;
217
virtual qreal footerSize() const;
218
virtual bool showHeaderForIndex(int index) const;
219
virtual bool showFooterForIndex(int index) const;
220
virtual void updateHeader();
221
virtual void updateFooter();
223
virtual void changedVisibleIndex(int newIndex);
224
virtual void initializeCurrentItem();
226
virtual void updateViewport();
227
virtual void fixupPosition();
228
virtual void fixup(AxisData &data, qreal minExtent, qreal maxExtent);
229
virtual bool flick(QQuickItemViewPrivate::AxisData &data, qreal minExtent, qreal maxExtent, qreal vSize,
230
QQuickTimeLineCallback::Callback fixupCallback, qreal velocity);
232
QQuickGridView::Flow flow;
236
QQuickGridView::SnapMode snapMode;
238
QSmoothedAnimation *highlightXAnimator;
239
QSmoothedAnimation *highlightYAnimator;
241
QQuickGridViewPrivate()
242
: flow(QQuickGridView::FlowLeftToRight)
243
, cellWidth(100), cellHeight(100), columns(1)
244
, snapMode(QQuickGridView::NoSnap)
245
, highlightXAnimator(0), highlightYAnimator(0)
247
~QQuickGridViewPrivate()
249
delete highlightXAnimator;
250
delete highlightYAnimator;
254
Qt::Orientation QQuickGridViewPrivate::layoutOrientation() const
256
return flow == QQuickGridView::FlowLeftToRight ? Qt::Vertical : Qt::Horizontal;
259
bool QQuickGridViewPrivate::isContentFlowReversed() const
261
Q_Q(const QQuickGridView);
263
return (flow == QQuickGridView::FlowLeftToRight && verticalLayoutDirection == QQuickItemView::BottomToTop)
264
|| (flow == QQuickGridView::FlowTopToBottom && q->effectiveLayoutDirection() == Qt::RightToLeft);
267
void QQuickGridViewPrivate::changedVisibleIndex(int newIndex)
269
visibleIndex = newIndex / columns * columns;
272
void QQuickGridViewPrivate::setPosition(qreal pos)
275
q->QQuickFlickable::setContentX(contentXForPosition(pos));
276
q->QQuickFlickable::setContentY(contentYForPosition(pos));
279
qreal QQuickGridViewPrivate::originPosition() const
282
if (!visibleItems.isEmpty())
283
pos = static_cast<FxGridItemSG*>(visibleItems.first())->rowPos() - visibleIndex / columns * rowSize();
287
qreal QQuickGridViewPrivate::lastPosition() const
290
if (model && model->count()) {
291
// get end position of last item
292
pos = (rowPosAt(model->count() - 1) + rowSize());
297
qreal QQuickGridViewPrivate::positionAt(int index) const
299
return rowPosAt(index);
302
qreal QQuickGridViewPrivate::endPositionAt(int index) const
304
return rowPosAt(index) + rowSize();
307
qreal QQuickGridViewPrivate::rowSize() const {
308
return flow == QQuickGridView::FlowLeftToRight ? cellHeight : cellWidth;
310
qreal QQuickGridViewPrivate::colSize() const {
311
return flow == QQuickGridView::FlowLeftToRight ? cellWidth : cellHeight;
314
qreal QQuickGridViewPrivate::colPosAt(int modelIndex) const
316
if (FxViewItem *item = visibleItem(modelIndex))
317
return static_cast<FxGridItemSG*>(item)->colPos();
318
if (!visibleItems.isEmpty()) {
319
if (modelIndex == visibleIndex) {
320
FxGridItemSG *firstItem = static_cast<FxGridItemSG*>(visibleItems.first());
321
return firstItem->colPos();
322
} else if (modelIndex < visibleIndex) {
323
int count = (visibleIndex - modelIndex) % columns;
324
int col = static_cast<FxGridItemSG*>(visibleItems.first())->colPos() / colSize();
325
col = (columns - count + col) % columns;
326
return col * colSize();
328
FxGridItemSG *lastItem = static_cast<FxGridItemSG*>(visibleItems.last());
329
int count = modelIndex - lastItem->index;
330
int col = lastItem->colPos() / colSize();
331
col = (col + count) % columns;
332
return col * colSize();
335
return (modelIndex % columns) * colSize();
338
qreal QQuickGridViewPrivate::rowPosAt(int modelIndex) const
340
if (FxViewItem *item = visibleItem(modelIndex))
341
return static_cast<FxGridItemSG*>(item)->rowPos();
342
if (!visibleItems.isEmpty()) {
343
if (modelIndex == visibleIndex) {
344
FxGridItemSG *firstItem = static_cast<FxGridItemSG*>(visibleItems.first());
345
return firstItem->rowPos();
346
} else if (modelIndex < visibleIndex) {
347
FxGridItemSG *firstItem = static_cast<FxGridItemSG*>(visibleItems.first());
348
int firstCol = firstItem->colPos() / colSize();
349
int col = visibleIndex - modelIndex + (columns - firstCol - 1);
350
int rows = col / columns;
351
return firstItem->rowPos() - rows * rowSize();
353
FxGridItemSG *lastItem = static_cast<FxGridItemSG*>(visibleItems.last());
354
int count = modelIndex - lastItem->index;
355
int col = lastItem->colPos() + count * colSize();
356
int rows = col / (columns * colSize());
357
return lastItem->rowPos() + rows * rowSize();
360
return (modelIndex / columns) * rowSize();
364
qreal QQuickGridViewPrivate::snapPosAt(qreal pos) const
366
Q_Q(const QQuickGridView);
368
if (!visibleItems.isEmpty()) {
369
qreal highlightStart = highlightRangeStart;
370
pos += highlightStart;
372
snapPos = static_cast<FxGridItemSG*>(visibleItems.first())->rowPos() - visibleIndex / columns * rowSize();
373
snapPos = pos - fmodf(pos - snapPos, qreal(rowSize()));
374
snapPos -= highlightStart;
377
if (isContentFlowReversed()) {
378
maxExtent = q->minXExtent()-size();
379
minExtent = q->maxXExtent()-size();
381
maxExtent = flow == QQuickGridView::FlowLeftToRight ? -q->maxYExtent() : -q->maxXExtent();
382
minExtent = flow == QQuickGridView::FlowLeftToRight ? -q->minYExtent() : -q->minXExtent();
384
if (snapPos > maxExtent)
386
if (snapPos < minExtent)
392
FxViewItem *QQuickGridViewPrivate::snapItemAt(qreal pos) const
394
for (int i = 0; i < visibleItems.count(); ++i) {
395
FxViewItem *item = visibleItems.at(i);
396
if (item->index == -1)
398
qreal itemTop = item->position();
399
if (itemTop+rowSize()/2 >= pos && itemTop - rowSize()/2 <= pos)
405
int QQuickGridViewPrivate::snapIndex() const
407
int index = currentIndex;
408
for (int i = 0; i < visibleItems.count(); ++i) {
409
FxGridItemSG *item = static_cast<FxGridItemSG*>(visibleItems.at(i));
410
if (item->index == -1)
412
qreal itemTop = item->position();
413
FxGridItemSG *hItem = static_cast<FxGridItemSG*>(highlight);
414
if (itemTop >= hItem->rowPos()-rowSize()/2 && itemTop < hItem->rowPos()+rowSize()/2) {
416
if (item->colPos() >= hItem->colPos()-colSize()/2 && item->colPos() < hItem->colPos()+colSize()/2)
423
qreal QQuickGridViewPrivate::contentXForPosition(qreal pos) const
425
Q_Q(const QQuickGridView);
426
if (flow == QQuickGridView::FlowLeftToRight) {
428
if (q->effectiveLayoutDirection() == Qt::LeftToRight) {
431
qreal colSize = cellWidth;
432
int columns = q->width()/colSize;
433
return -q->width() + (cellWidth * columns);
437
if (q->effectiveLayoutDirection() == Qt::LeftToRight)
440
return -pos - q->width();
444
qreal QQuickGridViewPrivate::contentYForPosition(qreal pos) const
446
Q_Q(const QQuickGridView);
447
if (flow == QQuickGridView::FlowLeftToRight) {
449
if (verticalLayoutDirection == QQuickItemView::TopToBottom)
452
return -pos - q->height();
455
if (verticalLayoutDirection == QQuickItemView::TopToBottom)
462
void QQuickGridViewPrivate::resetColumns()
465
qreal length = flow == QQuickGridView::FlowLeftToRight ? q->width() : q->height();
466
columns = (int)qMax((length + colSize()/2) / colSize(), qreal(1.));
469
FxViewItem *QQuickGridViewPrivate::newViewItem(int modelIndex, QQuickItem *item)
472
Q_UNUSED(modelIndex);
473
return new FxGridItemSG(item, q, false, false);
476
void QQuickGridViewPrivate::initializeViewItem(FxViewItem *item)
478
QQuickItemViewPrivate::initializeViewItem(item);
480
// need to track current items that are animating
481
QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item->item);
482
itemPrivate->addItemChangeListener(this, QQuickItemPrivate::Geometry);
485
bool QQuickGridViewPrivate::addVisibleItems(qreal fillFrom, qreal fillTo, qreal bufferFrom, qreal bufferTo, bool doBuffer)
487
qreal colPos = colPosAt(visibleIndex);
488
qreal rowPos = rowPosAt(visibleIndex);
489
if (visibleItems.count()) {
490
FxGridItemSG *lastItem = static_cast<FxGridItemSG*>(visibleItems.last());
491
rowPos = lastItem->rowPos();
492
int colNum = qFloor((lastItem->colPos()+colSize()/2) / colSize());
493
if (++colNum >= columns) {
497
colPos = colNum * colSize();
500
int modelIndex = findLastVisibleIndex();
501
modelIndex = modelIndex < 0 ? visibleIndex : modelIndex + 1;
503
if (visibleItems.count() && (bufferFrom > rowPos + rowSize()*2
504
|| bufferTo < rowPosAt(visibleIndex) - rowSize())) {
505
// We've jumped more than a page. Estimate which items are now
506
// visible and fill from there.
507
int count = (fillFrom - (rowPos + rowSize())) / (rowSize()) * columns;
508
for (int i = 0; i < visibleItems.count(); ++i)
509
releaseItem(visibleItems.at(i));
510
visibleItems.clear();
512
if (modelIndex >= model->count())
513
modelIndex = model->count() - 1;
514
else if (modelIndex < 0)
516
modelIndex = modelIndex / columns * columns;
517
visibleIndex = modelIndex;
518
colPos = colPosAt(visibleIndex);
519
rowPos = rowPosAt(visibleIndex);
522
int colNum = qFloor((colPos+colSize()/2) / colSize());
523
FxGridItemSG *item = 0;
524
bool changed = false;
526
while (modelIndex < model->count() && rowPos <= fillTo + rowSize()*(columns - colNum)/(columns+1)) {
527
#ifdef DEBUG_DELEGATE_LIFECYCLE
528
qDebug() << "refill: append item" << modelIndex << colPos << rowPos;
530
if (!(item = static_cast<FxGridItemSG*>(createItem(modelIndex, doBuffer))))
532
if (!transitioner || !transitioner->canTransition(QQuickItemViewTransitioner::PopulateTransition, true)) // pos will be set by layoutVisibleItems()
533
item->setPosition(colPos, rowPos, true);
534
QQuickItemPrivate::get(item->item)->setCulled(doBuffer);
535
visibleItems.append(item);
536
if (++colNum >= columns) {
540
colPos = colNum * colSize();
545
if (doBuffer && requestedIndex != -1) // already waiting for an item
549
if (visibleItems.count()) {
550
FxGridItemSG *firstItem = static_cast<FxGridItemSG*>(visibleItems.first());
551
rowPos = firstItem->rowPos();
552
colNum = qFloor((firstItem->colPos()+colSize()/2) / colSize());
554
colNum = columns - 1;
558
colNum = qFloor((colPos+colSize()/2) / colSize());
562
colPos = colNum * colSize();
563
while (visibleIndex > 0 && rowPos + rowSize() - 1 >= fillFrom - rowSize()*(colNum+1)/(columns+1)){
564
#ifdef DEBUG_DELEGATE_LIFECYCLE
565
qDebug() << "refill: prepend item" << visibleIndex-1 << "top pos" << rowPos << colPos;
567
if (!(item = static_cast<FxGridItemSG*>(createItem(visibleIndex-1, doBuffer))))
570
if (!transitioner || !transitioner->canTransition(QQuickItemViewTransitioner::PopulateTransition, true)) // pos will be set by layoutVisibleItems()
571
item->setPosition(colPos, rowPos, true);
572
QQuickItemPrivate::get(item->item)->setCulled(doBuffer);
573
visibleItems.prepend(item);
578
colPos = colNum * colSize();
585
bool QQuickGridViewPrivate::removeNonVisibleItems(qreal bufferFrom, qreal bufferTo)
587
FxGridItemSG *item = 0;
588
bool changed = false;
590
while (visibleItems.count() > 1
591
&& (item = static_cast<FxGridItemSG*>(visibleItems.first()))
592
&& item->rowPos()+rowSize()-1 < bufferFrom - rowSize()*(item->colPos()/colSize()+1)/(columns+1)) {
593
if (item->attached->delayRemove())
595
#ifdef DEBUG_DELEGATE_LIFECYCLE
596
qDebug() << "refill: remove first" << visibleIndex << "top end pos" << item->endRowPos();
598
if (item->index != -1)
600
visibleItems.removeFirst();
601
if (item->transitionScheduledOrRunning()) {
602
#ifdef DEBUG_DELEGATE_LIFECYCLE
603
qDebug() << "\tnot releasing animating item:" << item->index << item->item->objectName();
605
item->releaseAfterTransition = true;
606
releasePendingTransition.append(item);
612
while (visibleItems.count() > 1
613
&& (item = static_cast<FxGridItemSG*>(visibleItems.last()))
614
&& item->rowPos() > bufferTo + rowSize()*(columns - item->colPos()/colSize())/(columns+1)) {
615
if (item->attached->delayRemove())
617
#ifdef DEBUG_DELEGATE_LIFECYCLE
618
qDebug() << "refill: remove last" << visibleIndex+visibleItems.count()-1;
620
visibleItems.removeLast();
621
if (item->transitionScheduledOrRunning()) {
622
#ifdef DEBUG_DELEGATE_LIFECYCLE
623
qDebug() << "\tnot releasing animating item:" << item->index << item->item->objectName();
625
item->releaseAfterTransition = true;
626
releasePendingTransition.append(item);
636
void QQuickGridViewPrivate::updateViewport()
639
QQuickItemViewPrivate::updateViewport();
642
void QQuickGridViewPrivate::layoutVisibleItems(int fromModelIndex)
644
if (visibleItems.count()) {
645
const qreal from = isContentFlowReversed() ? -position() - size() : position();
646
const qreal to = isContentFlowReversed() ? -position() : position() + size();
648
FxGridItemSG *firstItem = static_cast<FxGridItemSG*>(visibleItems.first());
649
qreal rowPos = firstItem->rowPos();
650
qreal colPos = firstItem->colPos();
651
int col = visibleIndex % columns;
652
if (colPos != col * colSize()) {
653
colPos = col * colSize();
654
firstItem->setPosition(colPos, rowPos);
655
firstItem->setVisible(firstItem->rowPos() + rowSize() >= from && firstItem->rowPos() <= to);
657
for (int i = 1; i < visibleItems.count(); ++i) {
658
FxGridItemSG *item = static_cast<FxGridItemSG*>(visibleItems.at(i));
659
if (++col >= columns) {
663
colPos = col * colSize();
664
if (item->index >= fromModelIndex) {
665
item->setPosition(colPos, rowPos);
666
item->setVisible(item->rowPos() + rowSize() >= from && item->rowPos() <= to);
672
void QQuickGridViewPrivate::repositionItemAt(FxViewItem *item, int index, qreal sizeBuffer)
674
int count = sizeBuffer / rowSize();
675
static_cast<FxGridItemSG *>(item)->setPosition(colPosAt(index + count), rowPosAt(index + count));
678
void QQuickGridViewPrivate::repositionPackageItemAt(QQuickItem *item, int index)
681
qreal pos = position();
682
if (flow == QQuickGridView::FlowLeftToRight) {
683
if (item->y() + item->height() > pos && item->y() < pos + q->height()) {
684
qreal y = (verticalLayoutDirection == QQuickItemView::TopToBottom)
686
: -rowPosAt(index) - item->height();
687
item->setPosition(QPointF(colPosAt(index), y));
690
if (item->x() + item->width() > pos && item->x() < pos + q->width()) {
691
qreal y = (verticalLayoutDirection == QQuickItemView::TopToBottom)
693
: -colPosAt(index) - item->height();
694
if (flow == QQuickGridView::FlowTopToBottom && q->effectiveLayoutDirection() == Qt::RightToLeft)
695
item->setPosition(QPointF(-rowPosAt(index)-item->width(), y));
697
item->setPosition(QPointF(rowPosAt(index), y));
702
void QQuickGridViewPrivate::resetFirstItemPosition(qreal pos)
704
FxGridItemSG *item = static_cast<FxGridItemSG*>(visibleItems.first());
705
item->setPosition(0, pos);
708
void QQuickGridViewPrivate::adjustFirstItem(qreal forwards, qreal backwards, int changeBeforeVisible)
710
if (!visibleItems.count())
713
int moveCount = (forwards - backwards) / rowSize();
714
if (moveCount == 0 && changeBeforeVisible != 0)
715
moveCount += (changeBeforeVisible % columns) - (columns - 1);
717
FxGridItemSG *gridItem = static_cast<FxGridItemSG*>(visibleItems.first());
718
gridItem->setPosition(gridItem->colPos(), gridItem->rowPos() + ((moveCount / columns) * rowSize()));
721
void QQuickGridViewPrivate::createHighlight()
724
bool changed = false;
726
if (trackedItem == highlight)
731
delete highlightXAnimator;
732
delete highlightYAnimator;
733
highlightXAnimator = 0;
734
highlightYAnimator = 0;
740
QQuickItem *item = createHighlightItem();
742
FxGridItemSG *newHighlight = new FxGridItemSG(item, q, true, true);
744
resetHighlightPosition();
745
highlightXAnimator = new QSmoothedAnimation;
746
highlightXAnimator->target = QQmlProperty(item, QLatin1String("x"));
747
highlightXAnimator->userDuration = highlightMoveDuration;
748
highlightYAnimator = new QSmoothedAnimation;
749
highlightYAnimator->target = QQmlProperty(item, QLatin1String("y"));
750
highlightYAnimator->userDuration = highlightMoveDuration;
752
highlight = newHighlight;
757
emit q->highlightItemChanged();
760
void QQuickGridViewPrivate::updateHighlight()
762
applyPendingChanges();
764
if ((!currentItem && highlight) || (currentItem && !highlight))
766
bool strictHighlight = haveHighlightRange && highlightRange == QQuickGridView::StrictlyEnforceRange;
767
if (currentItem && autoHighlight && highlight && (!strictHighlight || !pressed)) {
768
// auto-update highlight
769
highlightXAnimator->to = currentItem->itemX();
770
highlightYAnimator->to = currentItem->itemY();
771
highlight->item->setWidth(currentItem->item->width());
772
highlight->item->setHeight(currentItem->item->height());
774
highlightXAnimator->restart();
775
highlightYAnimator->restart();
780
void QQuickGridViewPrivate::resetHighlightPosition()
782
if (highlight && currentItem) {
783
FxGridItemSG *cItem = static_cast<FxGridItemSG*>(currentItem);
784
static_cast<FxGridItemSG*>(highlight)->setPosition(cItem->colPos(), cItem->rowPos());
788
qreal QQuickGridViewPrivate::headerSize() const
792
return flow == QQuickGridView::FlowLeftToRight ? header->item->height() : header->item->width();
795
qreal QQuickGridViewPrivate::footerSize() const
799
return flow == QQuickGridView::FlowLeftToRight? footer->item->height() : footer->item->width();
802
bool QQuickGridViewPrivate::showHeaderForIndex(int index) const
804
return index / columns == 0;
807
bool QQuickGridViewPrivate::showFooterForIndex(int index) const
809
return index / columns == (model->count()-1) / columns;
812
void QQuickGridViewPrivate::updateFooter()
815
bool created = false;
817
QQuickItem *item = createComponentItem(footerComponent, 1.0);
820
footer = new FxGridItemSG(item, q, true, true);
824
FxGridItemSG *gridItem = static_cast<FxGridItemSG*>(footer);
827
if (q->effectiveLayoutDirection() == Qt::RightToLeft) {
828
if (flow == QQuickGridView::FlowTopToBottom)
829
rowOffset += gridItem->item->width() - cellWidth;
831
colOffset += gridItem->item->width() - cellWidth;
833
if (verticalLayoutDirection == QQuickItemView::BottomToTop) {
834
if (flow == QQuickGridView::FlowTopToBottom)
835
colOffset += gridItem->item->height() - cellHeight;
837
rowOffset += gridItem->item->height() - cellHeight;
839
if (visibleItems.count()) {
840
qreal endPos = lastPosition();
841
if (findLastVisibleIndex() == model->count()-1) {
842
gridItem->setPosition(colOffset, endPos + rowOffset);
844
qreal visiblePos = isContentFlowReversed() ? -position() : position() + size();
845
if (endPos <= visiblePos || gridItem->endPosition() <= endPos + rowOffset)
846
gridItem->setPosition(colOffset, endPos + rowOffset);
849
gridItem->setPosition(colOffset, rowOffset);
853
emit q->footerItemChanged();
856
void QQuickGridViewPrivate::updateHeader()
859
bool created = false;
861
QQuickItem *item = createComponentItem(headerComponent, 1.0);
864
header = new FxGridItemSG(item, q, true, true);
868
FxGridItemSG *gridItem = static_cast<FxGridItemSG*>(header);
870
qreal rowOffset = -headerSize();
871
if (q->effectiveLayoutDirection() == Qt::RightToLeft) {
872
if (flow == QQuickGridView::FlowTopToBottom)
873
rowOffset += gridItem->item->width() - cellWidth;
875
colOffset += gridItem->item->width() - cellWidth;
877
if (verticalLayoutDirection == QQuickItemView::BottomToTop) {
878
if (flow == QQuickGridView::FlowTopToBottom)
879
colOffset += gridItem->item->height() - cellHeight;
881
rowOffset += gridItem->item->height() - cellHeight;
883
if (visibleItems.count()) {
884
qreal startPos = originPosition();
885
if (visibleIndex == 0) {
886
gridItem->setPosition(colOffset, startPos + rowOffset);
888
qreal tempPos = isContentFlowReversed() ? -position()-size() : position();
889
qreal headerPos = isContentFlowReversed() ? gridItem->rowPos() + cellWidth - headerSize() : gridItem->rowPos();
890
if (tempPos <= startPos || headerPos > startPos + rowOffset)
891
gridItem->setPosition(colOffset, startPos + rowOffset);
894
if (isContentFlowReversed())
895
gridItem->setPosition(colOffset, rowOffset);
897
gridItem->setPosition(colOffset, -headerSize());
901
emit q->headerItemChanged();
904
void QQuickGridViewPrivate::initializeCurrentItem()
906
if (currentItem && currentIndex >= 0) {
907
FxGridItemSG *gridItem = static_cast<FxGridItemSG*>(currentItem);
908
FxViewItem *actualItem = visibleItem(currentIndex);
910
// don't reposition the item if it's about to be transitioned to another position
911
if ((!actualItem || !actualItem->transitionScheduledOrRunning()))
912
gridItem->setPosition(colPosAt(currentIndex), rowPosAt(currentIndex));
916
void QQuickGridViewPrivate::fixupPosition()
919
if (flow == QQuickGridView::FlowLeftToRight)
925
void QQuickGridViewPrivate::fixup(AxisData &data, qreal minExtent, qreal maxExtent)
927
if ((flow == QQuickGridView::FlowTopToBottom && &data == &vData)
928
|| (flow == QQuickGridView::FlowLeftToRight && &data == &hData))
931
fixupMode = moveReason == Mouse ? fixupMode : Immediate;
933
qreal viewPos = isContentFlowReversed() ? -position()-size() : position();
935
bool strictHighlightRange = haveHighlightRange && highlightRange == QQuickGridView::StrictlyEnforceRange;
936
if (snapMode != QQuickGridView::NoSnap) {
937
qreal tempPosition = isContentFlowReversed() ? -position()-size() : position();
938
if (snapMode == QQuickGridView::SnapOneRow && moveReason == Mouse) {
939
// if we've been dragged < rowSize()/2 then bias towards the next row
940
qreal dist = data.move.value() - (data.pressPos - data.dragStartOffset);
942
if (data.velocity > 0 && dist > QML_FLICK_SNAPONETHRESHOLD && dist < rowSize()/2)
944
else if (data.velocity < 0 && dist < -QML_FLICK_SNAPONETHRESHOLD && dist > -rowSize()/2)
946
if (isContentFlowReversed())
948
tempPosition -= bias;
950
FxViewItem *topItem = snapItemAt(tempPosition+highlightRangeStart);
951
if (!topItem && strictHighlightRange && currentItem) {
952
// StrictlyEnforceRange always keeps an item in range
954
topItem = currentItem;
956
FxViewItem *bottomItem = snapItemAt(tempPosition+highlightRangeEnd);
957
if (!bottomItem && strictHighlightRange && currentItem) {
958
// StrictlyEnforceRange always keeps an item in range
960
bottomItem = currentItem;
963
bool isInBounds = -position() > maxExtent && -position() <= minExtent;
964
if (topItem && (isInBounds || strictHighlightRange)) {
965
qreal headerPos = header ? static_cast<FxGridItemSG*>(header)->rowPos() : 0;
966
if (topItem->index == 0 && header && tempPosition+highlightRangeStart < headerPos+headerSize()/2 && !strictHighlightRange) {
967
pos = isContentFlowReversed() ? - headerPos + highlightRangeStart - size() : headerPos - highlightRangeStart;
969
if (isContentFlowReversed())
970
pos = qMax(qMin(-topItem->position() + highlightRangeStart - size(), -maxExtent), -minExtent);
972
pos = qMax(qMin(topItem->position() - highlightRangeStart, -maxExtent), -minExtent);
974
} else if (bottomItem && isInBounds) {
975
if (isContentFlowReversed())
976
pos = qMax(qMin(-bottomItem->position() + highlightRangeEnd - size(), -maxExtent), -minExtent);
978
pos = qMax(qMin(bottomItem->position() - highlightRangeEnd, -maxExtent), -minExtent);
980
QQuickItemViewPrivate::fixup(data, minExtent, maxExtent);
984
qreal dist = qAbs(data.move + pos);
986
timeline.reset(data.move);
987
if (fixupMode != Immediate) {
988
timeline.move(data.move, -pos, QEasingCurve(QEasingCurve::InOutQuad), fixupDuration/2);
989
data.fixingUp = true;
991
timeline.set(data.move, -pos);
993
vTime = timeline.time();
995
} else if (haveHighlightRange && highlightRange == QQuickGridView::StrictlyEnforceRange) {
998
qreal pos = static_cast<FxGridItemSG*>(currentItem)->rowPos();
999
if (viewPos < pos + rowSize() - highlightRangeEnd)
1000
viewPos = pos + rowSize() - highlightRangeEnd;
1001
if (viewPos > pos - highlightRangeStart)
1002
viewPos = pos - highlightRangeStart;
1003
if (isContentFlowReversed())
1004
viewPos = -viewPos-size();
1005
timeline.reset(data.move);
1006
if (viewPos != position()) {
1007
if (fixupMode != Immediate) {
1008
timeline.move(data.move, -viewPos, QEasingCurve(QEasingCurve::InOutQuad), fixupDuration/2);
1009
data.fixingUp = true;
1011
timeline.set(data.move, -viewPos);
1014
vTime = timeline.time();
1017
QQuickItemViewPrivate::fixup(data, minExtent, maxExtent);
1019
data.inOvershoot = false;
1023
bool QQuickGridViewPrivate::flick(AxisData &data, qreal minExtent, qreal maxExtent, qreal vSize,
1024
QQuickTimeLineCallback::Callback fixupCallback, qreal velocity)
1026
data.fixingUp = false;
1028
if ((!haveHighlightRange || highlightRange != QQuickGridView::StrictlyEnforceRange)
1029
&& snapMode == QQuickGridView::NoSnap) {
1030
return QQuickItemViewPrivate::flick(data, minExtent, maxExtent, vSize, fixupCallback, velocity);
1032
qreal maxDistance = 0;
1033
qreal dataValue = isContentFlowReversed() ? -data.move.value()+size() : data.move.value();
1034
// -ve velocity means list is moving up/left
1036
if (data.move.value() < minExtent) {
1037
if (snapMode == QQuickGridView::SnapOneRow) {
1038
// if we've been dragged < averageSize/2 then bias towards the next item
1039
qreal dist = data.move.value() - (data.pressPos - data.dragStartOffset);
1040
qreal bias = dist < rowSize()/2 ? rowSize()/2 : 0;
1041
if (isContentFlowReversed())
1043
data.flickTarget = -snapPosAt(-dataValue - bias);
1044
maxDistance = qAbs(data.flickTarget - data.move.value());
1045
velocity = maxVelocity;
1047
maxDistance = qAbs(minExtent - data.move.value());
1050
if (snapMode == QQuickGridView::NoSnap && highlightRange != QQuickGridView::StrictlyEnforceRange)
1051
data.flickTarget = minExtent;
1053
if (data.move.value() > maxExtent) {
1054
if (snapMode == QQuickGridView::SnapOneRow) {
1055
// if we've been dragged < averageSize/2 then bias towards the next item
1056
qreal dist = data.move.value() - (data.pressPos - data.dragStartOffset);
1057
qreal bias = -dist < rowSize()/2 ? rowSize()/2 : 0;
1058
if (isContentFlowReversed())
1060
data.flickTarget = -snapPosAt(-dataValue + bias);
1061
maxDistance = qAbs(data.flickTarget - data.move.value());
1062
velocity = -maxVelocity;
1064
maxDistance = qAbs(maxExtent - data.move.value());
1067
if (snapMode == QQuickGridView::NoSnap && highlightRange != QQuickGridView::StrictlyEnforceRange)
1068
data.flickTarget = maxExtent;
1070
bool overShoot = boundsBehavior == QQuickFlickable::DragAndOvershootBounds;
1071
if (maxDistance > 0 || overShoot) {
1072
// This mode requires the grid to stop exactly on a row boundary.
1074
if (maxVelocity != -1 && maxVelocity < qAbs(v)) {
1080
qreal accel = deceleration;
1082
qreal overshootDist = 0.0;
1083
if ((maxDistance > 0.0 && v2 / (2.0f * maxDistance) < accel) || snapMode == QQuickGridView::SnapOneRow) {
1084
// + rowSize()/4 to encourage moving at least one item in the flick direction
1085
qreal dist = v2 / (accel * 2.0) + rowSize()/4;
1086
dist = qMin(dist, maxDistance);
1089
if (snapMode != QQuickGridView::SnapOneRow) {
1090
qreal distTemp = isContentFlowReversed() ? -dist : dist;
1091
data.flickTarget = -snapPosAt(-dataValue + distTemp);
1093
data.flickTarget = isContentFlowReversed() ? -data.flickTarget+size() : data.flickTarget;
1095
if (data.flickTarget >= minExtent) {
1096
overshootDist = overShootDistance(vSize);
1097
data.flickTarget += overshootDist;
1098
} else if (data.flickTarget <= maxExtent) {
1099
overshootDist = overShootDistance(vSize);
1100
data.flickTarget -= overshootDist;
1103
qreal adjDist = -data.flickTarget + data.move.value();
1104
if (qAbs(adjDist) > qAbs(dist)) {
1105
// Prevent painfully slow flicking - adjust velocity to suit flickDeceleration
1106
qreal adjv2 = accel * 2.0f * qAbs(adjDist);
1115
accel = v2 / (2.0f * qAbs(dist));
1117
data.flickTarget = velocity > 0 ? minExtent : maxExtent;
1118
overshootDist = overShoot ? overShootDistance(vSize) : 0;
1120
timeline.reset(data.move);
1121
timeline.accel(data.move, v, accel, maxDistance + overshootDist);
1122
timeline.callback(QQuickTimeLineCallback(&data.move, fixupCallback, this));
1125
timeline.reset(data.move);
1126
fixup(data, minExtent, maxExtent);
1132
//----------------------------------------------------------------------------
1135
\instantiates QQuickGridView
1136
\inqmlmodule QtQuick 2
1137
\ingroup qtquick-views
1140
\brief For specifying a grid view of items provided by a model
1142
A GridView displays data from models created from built-in QML types like ListModel
1143
and XmlListModel, or custom model classes defined in C++ that inherit from
1146
A GridView has a \l model, which defines the data to be displayed, and
1147
a \l delegate, which defines how the data should be displayed. Items in a
1148
GridView are laid out horizontally or vertically. Grid views are inherently flickable
1149
as GridView inherits from \l Flickable.
1151
\section1 Example Usage
1153
The following example shows the definition of a simple list model defined
1154
in a file called \c ContactModel.qml:
1156
\snippet qml/gridview/ContactModel.qml 0
1158
\div {class="float-right"}
1159
\inlineimage gridview-simple.png
1162
This model can be referenced as \c ContactModel in other QML files. See \l{QML Modules}
1163
for more information about creating reusable components like this.
1165
Another component can display this model data in a GridView, as in the following
1166
example, which creates a \c ContactModel component for its model, and a \l Column
1167
(containing \l Image and \l Text items) for its delegate.
1170
\snippet qml/gridview/gridview.qml import
1172
\snippet qml/gridview/gridview.qml classdocs simple
1174
\div {class="float-right"}
1175
\inlineimage gridview-highlight.png
1178
The view will create a new delegate for each item in the model. Note that the delegate
1179
is able to access the model's \c name and \c portrait data directly.
1181
An improved grid view is shown below. The delegate is visually improved and is moved
1182
into a separate \c contactDelegate component.
1185
\snippet qml/gridview/gridview.qml classdocs advanced
1187
The currently selected item is highlighted with a blue \l Rectangle using the \l highlight property,
1188
and \c focus is set to \c true to enable keyboard navigation for the grid view.
1189
The grid view itself is a focus scope (see \l{Keyboard Focus in Qt Quick} for more details).
1191
Delegates are instantiated as needed and may be destroyed at any time.
1192
State should \e never be stored in a delegate.
1194
GridView attaches a number of properties to the root item of the delegate, for example
1195
\c {GridView.isCurrentItem}. In the following example, the root delegate item can access
1196
this attached property directly as \c GridView.isCurrentItem, while the child
1197
\c contactInfo object must refer to this property as \c wrapper.GridView.isCurrentItem.
1199
\snippet qml/gridview/gridview.qml isCurrentItem
1201
\note Views do not set the \l{Item::}{clip} property automatically.
1202
If the view is not clipped by another item or the screen, it will be necessary
1203
to set this property to true in order to clip the items that are partially or
1204
fully outside the view.
1207
\section1 GridView layouts
1209
The layout of the items in a GridView can be controlled by these properties:
1212
\li \l flow - controls whether items flow from left to right (as a series of rows)
1213
or from top to bottom (as a series of columns). This value can be either
1214
GridView.LeftToRight or GridView.TopToBottom.
1215
\li \l layoutDirection - controls the horizontal layout direction: that is, whether items
1216
are laid out from the left side of the view to the right, or vice-versa. This value can
1217
be either Qt.LeftToRight or Qt.RightToLeft.
1218
\li \l verticalLayoutDirection - controls the vertical layout direction: that is, whether items
1219
are laid out from the top of the view down towards the bottom of the view, or vice-versa.
1220
This value can be either GridView.TopToBottom or GridView.BottomToTop.
1223
By default, a GridView flows from left to right, and items are laid out from left to right
1224
horizontally, and from top to bottom vertically.
1226
These properties can be combined to produce a variety of layouts, as shown in the table below.
1227
The GridViews in the first row all have a \l flow value of GridView.LeftToRight, but use
1228
different combinations of horizontal and vertical layout directions (specified by \l layoutDirection
1229
and \l verticalLayoutDirection respectively). Similarly, the GridViews in the second row below
1230
all have a \l flow value of GridView.TopToBottom, but use different combinations of horizontal and
1231
vertical layout directions to lay out their items in different ways.
1236
\b GridViews with GridView.LeftToRight flow
1238
\li \b (H) Left to right \b (V) Top to bottom
1239
\image gridview-layout-lefttoright-ltr-ttb.png
1240
\li \b (H) Right to left \b (V) Top to bottom
1241
\image gridview-layout-lefttoright-rtl-ttb.png
1242
\li \b (H) Left to right \b (V) Bottom to top
1243
\image gridview-layout-lefttoright-ltr-btt.png
1244
\li \b (H) Right to left \b (V) Bottom to top
1245
\image gridview-layout-lefttoright-rtl-btt.png
1248
\b GridViews with GridView.TopToBottom flow
1250
\li \b (H) Left to right \b (V) Top to bottom
1251
\image gridview-layout-toptobottom-ltr-ttb.png
1252
\li \b (H) Right to left \b (V) Top to bottom
1253
\image gridview-layout-toptobottom-rtl-ttb.png
1254
\li \b (H) Left to right \b (V) Bottom to top
1255
\image gridview-layout-toptobottom-ltr-btt.png
1256
\li \b (H) Right to left \b (V) Bottom to top
1257
\image gridview-layout-toptobottom-rtl-btt.png
1260
\sa {quick/modelviews/gridview}{GridView example}
1263
QQuickGridView::QQuickGridView(QQuickItem *parent)
1264
: QQuickItemView(*(new QQuickGridViewPrivate), parent)
1268
QQuickGridView::~QQuickGridView()
1272
void QQuickGridView::setHighlightFollowsCurrentItem(bool autoHighlight)
1274
Q_D(QQuickGridView);
1275
if (d->autoHighlight != autoHighlight) {
1276
if (!autoHighlight && d->highlightXAnimator) {
1277
d->highlightXAnimator->stop();
1278
d->highlightYAnimator->stop();
1280
QQuickItemView::setHighlightFollowsCurrentItem(autoHighlight);
1285
\qmlattachedproperty bool QtQuick2::GridView::isCurrentItem
1286
This attached property is true if this delegate is the current item; otherwise false.
1288
It is attached to each instance of the delegate.
1292
\qmlattachedproperty GridView QtQuick2::GridView::view
1293
This attached property holds the view that manages this delegate instance.
1295
It is attached to each instance of the delegate.
1297
\snippet qml/gridview/gridview.qml isCurrentItem
1301
\qmlattachedproperty bool QtQuick2::GridView::delayRemove
1302
This attached property holds whether the delegate may be destroyed. It
1303
is attached to each instance of the delegate. The default value is false.
1305
It is sometimes necessary to delay the destruction of an item
1306
until an animation completes. The example delegate below ensures that the
1307
animation completes before the item is removed from the list.
1309
\snippet qml/gridview/gridview.qml delayRemove
1311
If a \l remove transition has been specified, it will not be applied until
1312
delayRemove is returned to \c false.
1316
\qmlattachedsignal QtQuick2::GridView::onAdd()
1317
This attached handler is called immediately after an item is added to the view.
1321
\qmlattachedsignal QtQuick2::GridView::onRemove()
1322
This attached handler is called immediately before an item is removed from the view.
1324
If a \l remove transition has been specified, it is applied after
1325
this signal handler is called, providing that delayRemove is false.
1330
\qmlproperty model QtQuick2::GridView::model
1331
This property holds the model providing data for the grid.
1333
The model provides the set of data that is used to create the items
1334
in the view. Models can be created directly in QML using \l ListModel, \l XmlListModel
1335
or \l VisualItemModel, or provided by C++ model classes. If a C++ model class is
1336
used, it must be a subclass of \l QAbstractItemModel or a simple list.
1338
\sa {qml-data-models}{Data Models}
1342
\qmlproperty Component QtQuick2::GridView::delegate
1344
The delegate provides a template defining each item instantiated by the view.
1345
The index is exposed as an accessible \c index property. Properties of the
1346
model are also available depending upon the type of \l {qml-data-models}{Data Model}.
1348
The number of objects and bindings in the delegate has a direct effect on the
1349
flicking performance of the view. If at all possible, place functionality
1350
that is not needed for the normal display of the delegate in a \l Loader which
1351
can load additional components when needed.
1353
The item size of the GridView is determined by cellHeight and cellWidth. It will not resize the items
1354
based on the size of the root item in the delegate.
1356
\note Delegates are instantiated as needed and may be destroyed at any time.
1357
State should \e never be stored in a delegate.
1361
\qmlproperty int QtQuick2::GridView::currentIndex
1362
\qmlproperty Item QtQuick2::GridView::currentItem
1364
The \c currentIndex property holds the index of the current item, and
1365
\c currentItem holds the current item. Setting the currentIndex to -1
1366
will clear the highlight and set currentItem to null.
1368
If highlightFollowsCurrentItem is \c true, setting either of these
1369
properties will smoothly scroll the GridView so that the current
1370
item becomes visible.
1372
Note that the position of the current item
1373
may only be approximate until it becomes visible in the view.
1378
\qmlproperty Item QtQuick2::GridView::highlightItem
1380
This holds the highlight item created from the \l highlight component.
1382
The highlightItem is managed by the view unless
1383
\l highlightFollowsCurrentItem is set to false.
1385
\sa highlight, highlightFollowsCurrentItem
1390
\qmlproperty int QtQuick2::GridView::count
1391
This property holds the number of items in the view.
1396
\qmlproperty Component QtQuick2::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.
1403
\sa highlightItem, highlightFollowsCurrentItem
1407
\qmlproperty bool QtQuick2::GridView::highlightFollowsCurrentItem
1408
This property sets whether the highlight is managed by the view.
1410
If this property is true (the default value), the highlight is moved smoothly
1411
to follow the current item. Otherwise, the
1412
highlight is not moved by the view, and any movement must be implemented
1415
Here is a highlight with its motion defined by a \l {SpringAnimation} item:
1417
\snippet qml/gridview/gridview.qml highlightFollowsCurrentItem
1422
\qmlproperty int QtQuick2::GridView::highlightMoveDuration
1423
This property holds the move animation duration of the highlight delegate.
1425
highlightFollowsCurrentItem must be true for this property
1428
The default value for the duration is 150ms.
1430
\sa highlightFollowsCurrentItem
1434
\qmlproperty real QtQuick2::GridView::preferredHighlightBegin
1435
\qmlproperty real QtQuick2::GridView::preferredHighlightEnd
1436
\qmlproperty enumeration QtQuick2::GridView::highlightRangeMode
1438
These properties define the preferred range of the highlight (for the current item)
1439
within the view. The \c preferredHighlightBegin value must be less than the
1440
\c preferredHighlightEnd value.
1442
These properties affect the position of the current item when the view is scrolled.
1443
For example, if the currently selected item should stay in the middle of the
1444
view when it is scrolled, set the \c preferredHighlightBegin and
1445
\c preferredHighlightEnd values to the top and bottom coordinates of where the middle
1446
item would be. If the \c currentItem is changed programmatically, the view will
1447
automatically scroll so that the current item is in the middle of the view.
1448
Furthermore, the behavior of the current item index will occur whether or not a
1451
Valid values for \c highlightRangeMode are:
1454
\li GridView.ApplyRange - the view attempts to maintain the highlight within the range.
1455
However, the highlight can move outside of the range at the ends of the view or due
1456
to mouse interaction.
1457
\li GridView.StrictlyEnforceRange - the highlight never moves outside of the range.
1458
The current item changes if a keyboard or mouse action would cause the highlight to move
1459
outside of the range.
1460
\li GridView.NoHighlightRange - this is the default value.
1466
\qmlproperty enumeration QtQuick2::GridView::layoutDirection
1467
This property holds the layout direction of the grid.
1472
\li Qt.LeftToRight (default) - Items will be laid out starting in the top, left corner. The flow is
1473
dependent on the \l GridView::flow property.
1474
\li Qt.RightToLeft - Items will be laid out starting in the top, right corner. The flow is dependent
1475
on the \l GridView::flow property.
1478
\b Note: If GridView::flow is set to GridView.LeftToRight, this is not to be confused if
1479
GridView::layoutDirection is set to Qt.RightToLeft. The GridView.LeftToRight flow value simply
1480
indicates that the flow is horizontal.
1482
\sa GridView::effectiveLayoutDirection, GridView::verticalLayoutDirection
1487
\qmlproperty enumeration QtQuick2::GridView::effectiveLayoutDirection
1488
This property holds the effective layout direction of the grid.
1490
When using the attached property \l {LayoutMirroring::enabled}{LayoutMirroring::enabled} for locale layouts,
1491
the visual layout direction of the grid will be mirrored. However, the
1492
property \l {GridView::layoutDirection}{layoutDirection} will remain unchanged.
1494
\sa GridView::layoutDirection, {LayoutMirroring}{LayoutMirroring}
1498
\qmlproperty enumeration QtQuick2::GridView::verticalLayoutDirection
1499
This property holds the vertical layout direction of the grid.
1504
\li GridView.TopToBottom (default) - Items are laid out from the top of the view down to the bottom of the view.
1505
\li GridView.BottomToTop - Items are laid out from the bottom of the view up to the top of the view.
1508
\sa GridView::layoutDirection
1512
\qmlproperty bool QtQuick2::GridView::keyNavigationWraps
1513
This property holds whether the grid wraps key navigation
1515
If this is true, key navigation that would move the current item selection
1516
past one end of the view instead wraps around and moves the selection to
1517
the other end of the view.
1519
By default, key navigation is not wrapped.
1522
\qmlproperty int QtQuick2::GridView::cacheBuffer
1523
This property determines whether delegates are retained outside the
1524
visible area of the view.
1526
If non-zero the view may keep as many delegates
1527
instantiated as will fit within the buffer specified. For example,
1528
if in a vertical view the delegate is 20 pixels high, there are 3
1529
columns and \c cacheBuffer is
1530
set to 40, then up to 6 delegates above and 6 delegates below the visible
1531
area may be created/retained. The buffered delegates are created asynchronously,
1532
allowing creation to occur across multiple frames and reducing the
1533
likelihood of skipping frames. In order to improve painting performance
1534
delegates outside the visible area are not painted.
1536
The default value of this property is platform dependent, but will usually
1537
be a non-zero value.
1539
Note that cacheBuffer is not a pixel buffer - it only maintains additional
1540
instantiated delegates.
1542
Setting this value can make scrolling the list smoother at the expense
1543
of additional memory usage. It is not a substitute for creating efficient
1544
delegates; the fewer objects and bindings in a delegate, the faster a view may be
1547
void QQuickGridView::setHighlightMoveDuration(int duration)
1549
Q_D(QQuickGridView);
1550
if (d->highlightMoveDuration != duration) {
1551
if (d->highlightYAnimator) {
1552
d->highlightXAnimator->userDuration = duration;
1553
d->highlightYAnimator->userDuration = duration;
1555
QQuickItemView::setHighlightMoveDuration(duration);
1560
\qmlproperty enumeration QtQuick2::GridView::flow
1561
This property holds the flow of the grid.
1566
\li GridView.LeftToRight (default) - Items are laid out from left to right, and the view scrolls vertically
1567
\li GridView.TopToBottom - Items are laid out from top to bottom, and the view scrolls horizontally
1570
QQuickGridView::Flow QQuickGridView::flow() const
1572
Q_D(const QQuickGridView);
1576
void QQuickGridView::setFlow(Flow flow)
1578
Q_D(QQuickGridView);
1579
if (d->flow != flow) {
1581
if (d->flow == FlowLeftToRight) {
1582
setContentWidth(-1);
1583
setFlickableDirection(VerticalFlick);
1585
setContentHeight(-1);
1586
setFlickableDirection(HorizontalFlick);
1597
\qmlproperty real QtQuick2::GridView::cellWidth
1598
\qmlproperty real QtQuick2::GridView::cellHeight
1600
These properties holds the width and height of each cell in the grid.
1602
The default cell size is 100x100.
1604
qreal QQuickGridView::cellWidth() const
1606
Q_D(const QQuickGridView);
1607
return d->cellWidth;
1610
void QQuickGridView::setCellWidth(qreal cellWidth)
1612
Q_D(QQuickGridView);
1613
if (cellWidth != d->cellWidth && cellWidth > 0) {
1614
d->cellWidth = qMax(qreal(1), cellWidth);
1615
d->updateViewport();
1616
emit cellWidthChanged();
1617
d->forceLayoutPolish();
1621
qreal QQuickGridView::cellHeight() const
1623
Q_D(const QQuickGridView);
1624
return d->cellHeight;
1627
void QQuickGridView::setCellHeight(qreal cellHeight)
1629
Q_D(QQuickGridView);
1630
if (cellHeight != d->cellHeight && cellHeight > 0) {
1631
d->cellHeight = qMax(qreal(1), cellHeight);
1632
d->updateViewport();
1633
emit cellHeightChanged();
1634
d->forceLayoutPolish();
1638
\qmlproperty enumeration QtQuick2::GridView::snapMode
1640
This property determines how the view scrolling will settle following a drag or flick.
1641
The possible values are:
1644
\li GridView.NoSnap (default) - the view stops anywhere within the visible area.
1645
\li GridView.SnapToRow - the view settles with a row (or column for \c GridView.TopToBottom flow)
1646
aligned with the start of the view.
1647
\li GridView.SnapOneRow - the view will settle no more than one row (or column for \c GridView.TopToBottom flow)
1648
away from the first visible row at the time the mouse button is released.
1649
This mode is particularly useful for moving one page at a time.
1653
QQuickGridView::SnapMode QQuickGridView::snapMode() const
1655
Q_D(const QQuickGridView);
1659
void QQuickGridView::setSnapMode(SnapMode mode)
1661
Q_D(QQuickGridView);
1662
if (d->snapMode != mode) {
1664
emit snapModeChanged();
1670
\qmlproperty Component QtQuick2::GridView::footer
1671
This property holds the component to use as the footer.
1673
An instance of the footer component is created for each view. The
1674
footer is positioned at the end of the view, after any items.
1676
\sa header, footerItem
1679
\qmlproperty Component QtQuick2::GridView::header
1680
This property holds the component to use as the header.
1682
An instance of the header component is created for each view. The
1683
header is positioned at the beginning of the view, before any items.
1685
\sa footer, headerItem
1689
\qmlproperty Item QtQuick2::GridView::headerItem
1690
This holds the header item created from the \l header component.
1692
An instance of the header component is created for each view. The
1693
header is positioned at the beginning of the view, before any items.
1695
\sa header, footerItem
1699
\qmlproperty Item QtQuick2::GridView::footerItem
1700
This holds the footer item created from the \l footer component.
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.
1705
\sa footer, headerItem
1709
\qmlproperty Transition QtQuick2::GridView::populate
1711
This property holds the transition to apply to the items that are initially created
1714
It is applied to all items that are created when:
1717
\li The view is first created
1718
\li The view's \l model changes
1719
\li The view's \l model is \l {QAbstractItemModel::reset()}{reset}, if the model is a QAbstractItemModel subclass
1722
For example, here is a view that specifies such a transition:
1727
populate: Transition {
1728
NumberAnimation { properties: "x,y"; duration: 1000 }
1733
When the view is initialized, the view will create all the necessary items for the view,
1734
then animate them to their correct positions within the view over one second.
1736
For more details and examples on how to use view transitions, see the ViewTransition
1739
\sa add, ViewTransition
1743
\qmlproperty Transition QtQuick2::GridView::add
1745
This property holds the transition to apply to items that are added to the view.
1747
For example, here is a view that specifies such a transition:
1753
NumberAnimation { properties: "x,y"; from: 100; duration: 1000 }
1758
Whenever an item is added to the above view, the item will be animated from the position (100,100)
1759
to its final x,y position within the view, over one second. The transition only applies to
1760
the new items that are added to the view; it does not apply to the items below that are
1761
displaced by the addition of the new items. To animate the displaced items, set the \l displaced
1762
or \l addDisplaced properties.
1764
For more details and examples on how to use view transitions, see the ViewTransition
1767
\note This transition is not applied to the items that are created when the view is initially
1768
populated, or when the view's \l model changes. (In those cases, the \l populate transition is
1769
applied instead.) Additionally, this transition should \e not animate the height of the new item;
1770
doing so will cause any items beneath the new item to be laid out at the wrong position. Instead,
1771
the height can be animated within a \l {ListView::onAdd()}{ListView.onAdd} in the delegate.
1773
\sa addDisplaced, populate, ViewTransition
1777
\qmlproperty Transition QtQuick2::GridView::addDisplaced
1779
This property holds the transition to apply to items within the view that are displaced by
1780
the addition of other items to the view.
1782
For example, here is a view that specifies such a transition:
1787
addDisplaced: Transition {
1788
NumberAnimation { properties: "x,y"; duration: 1000 }
1793
Whenever an item is added to the above view, all items beneath the new item are displaced, causing
1794
them to move down (or sideways, if horizontally orientated) within the view. As this
1795
displacement occurs, the items' movement to their new x,y positions within the view will be
1796
animated by a NumberAnimation over one second, as specified. This transition is not applied to
1797
the new item that has been added to the view; to animate the added items, set the \l add
1800
If an item is displaced by multiple types of operations at the same time, it is not defined as to
1801
whether the addDisplaced, moveDisplaced or removeDisplaced transition will be applied. Additionally,
1802
if it is not necessary to specify different transitions depending on whether an item is displaced
1803
by an add, move or remove operation, consider setting the \l displaced property instead.
1805
For more details and examples on how to use view transitions, see the ViewTransition
1808
\note This transition is not applied to the items that are created when the view is initially
1809
populated, or when the view's \l model changes. In those cases, the \l populate transition is
1812
\sa displaced, add, populate, ViewTransition
1815
\qmlproperty Transition QtQuick2::GridView::move
1817
This property holds the transition to apply to items in the view that are being moved due
1818
to a move operation in the view's \l model.
1820
For example, here is a view that specifies such a transition:
1826
NumberAnimation { properties: "x,y"; duration: 1000 }
1831
Whenever the \l model performs a move operation to move a particular set of indexes, the
1832
respective items in the view will be animated to their new positions in the view over one
1833
second. The transition only applies to the items that are the subject of the move operation
1834
in the model; it does not apply to items below them that are displaced by the move operation.
1835
To animate the displaced items, set the \l displaced or \l moveDisplaced properties.
1837
For more details and examples on how to use view transitions, see the ViewTransition
1840
\sa moveDisplaced, ViewTransition
1844
\qmlproperty Transition QtQuick2::GridView::moveDisplaced
1846
This property holds the transition to apply to items that are displaced by a move operation in
1847
the view's \l model.
1849
For example, here is a view that specifies such a transition:
1854
moveDisplaced: Transition {
1855
NumberAnimation { properties: "x,y"; duration: 1000 }
1860
Whenever the \l model performs a move operation to move a particular set of indexes, the items
1861
between the source and destination indexes of the move operation are displaced, causing them
1862
to move upwards or downwards (or sideways, if horizontally orientated) within the view. As this
1863
displacement occurs, the items' movement to their new x,y positions within the view will be
1864
animated by a NumberAnimation over one second, as specified. This transition is not applied to
1865
the items that are the actual subjects of the move operation; to animate the moved items, set
1866
the \l move property.
1868
If an item is displaced by multiple types of operations at the same time, it is not defined as to
1869
whether the addDisplaced, moveDisplaced or removeDisplaced transition will be applied. Additionally,
1870
if it is not necessary to specify different transitions depending on whether an item is displaced
1871
by an add, move or remove operation, consider setting the \l displaced property instead.
1873
For more details and examples on how to use view transitions, see the ViewTransition
1876
\sa displaced, move, ViewTransition
1880
\qmlproperty Transition QtQuick2::GridView::remove
1882
This property holds the transition to apply to items that are removed from the view.
1884
For example, here is a view that specifies such a transition:
1889
remove: Transition {
1891
NumberAnimation { property: "opacity"; to: 0; duration: 1000 }
1892
NumberAnimation { properties: "x,y"; to: 100; duration: 1000 }
1898
Whenever an item is removed from the above view, the item will be animated to the position (100,100)
1899
over one second, and in parallel will also change its opacity to 0. The transition
1900
only applies to the items that are removed from the view; it does not apply to the items below
1901
them that are displaced by the removal of the items. To animate the displaced items, set the
1902
\l displaced or \l removeDisplaced properties.
1904
Note that by the time the transition is applied, the item has already been removed from the
1905
model; any references to the model data for the removed index will not be valid.
1907
Additionally, if the \l delayRemove attached property has been set for a delegate item, the
1908
remove transition will not be applied until \l delayRemove becomes false again.
1910
For more details and examples on how to use view transitions, see the ViewTransition
1913
\sa removeDisplaced, ViewTransition
1917
\qmlproperty Transition QtQuick2::GridView::removeDisplaced
1919
This property holds the transition to apply to items in the view that are displaced by the
1920
removal of other items in the view.
1922
For example, here is a view that specifies such a transition:
1927
removeDisplaced: Transition {
1928
NumberAnimation { properties: "x,y"; duration: 1000 }
1933
Whenever an item is removed from the above view, all items beneath it are displaced, causing
1934
them to move upwards (or sideways, if horizontally orientated) within the view. As this
1935
displacement occurs, the items' movement to their new x,y positions within the view will be
1936
animated by a NumberAnimation over one second, as specified. This transition is not applied to
1937
the item that has actually been removed from the view; to animate the removed items, set the
1940
If an item is displaced by multiple types of operations at the same time, it is not defined as to
1941
whether the addDisplaced, moveDisplaced or removeDisplaced transition will be applied. Additionally,
1942
if it is not necessary to specify different transitions depending on whether an item is displaced
1943
by an add, move or remove operation, consider setting the \l displaced property instead.
1945
For more details and examples on how to use view transitions, see the ViewTransition
1948
\sa displaced, remove, ViewTransition
1952
\qmlproperty Transition QtQuick2::GridView::displaced
1953
This property holds the generic transition to apply to items that have been displaced by
1954
any model operation that affects the view.
1956
This is a convenience for specifying a generic transition for items that are displaced
1957
by add, move or remove operations, without having to specify the individual addDisplaced,
1958
moveDisplaced and removeDisplaced properties. For example, here is a view that specifies
1959
a displaced transition:
1964
displaced: Transition {
1965
NumberAnimation { properties: "x,y"; duration: 1000 }
1970
When any item is added, moved or removed within the above view, the items below it are
1971
displaced, causing them to move down (or sideways, if horizontally orientated) within the
1972
view. As this displacement occurs, the items' movement to their new x,y positions within
1973
the view will be animated by a NumberAnimation over one second, as specified.
1975
If a view specifies this generic displaced transition as well as a specific addDisplaced,
1976
moveDisplaced or removeDisplaced transition, the more specific transition will be used
1977
instead of the generic displaced transition when the relevant operation occurs, providing that
1978
the more specific transition has not been disabled (by setting \l {Transition::enabled}{enabled}
1979
to false). If it has indeed been disabled, the generic displaced transition is applied instead.
1981
For more details and examples on how to use view transitions, see the ViewTransition
1984
\sa addDisplaced, moveDisplaced, removeDisplaced, ViewTransition
1987
void QQuickGridView::viewportMoved(Qt::Orientations orient)
1989
Q_D(QQuickGridView);
1990
QQuickItemView::viewportMoved(orient);
1993
if (d->inViewportMoved)
1995
d->inViewportMoved = true;
1998
if (d->isContentFlowReversed())
1999
d->bufferMode = d->vData.smoothVelocity < 0 ? QQuickItemViewPrivate::BufferAfter : QQuickItemViewPrivate::BufferBefore;
2001
d->bufferMode = d->vData.smoothVelocity < 0 ? QQuickItemViewPrivate::BufferBefore : QQuickItemViewPrivate::BufferAfter;
2003
if (d->isContentFlowReversed())
2004
d->bufferMode = d->hData.smoothVelocity < 0 ? QQuickItemViewPrivate::BufferAfter : QQuickItemViewPrivate::BufferBefore;
2006
d->bufferMode = d->hData.smoothVelocity < 0 ? QQuickItemViewPrivate::BufferBefore : QQuickItemViewPrivate::BufferAfter;
2009
d->refillOrLayout();
2011
// Set visibility of items to eliminate cost of items outside the visible area.
2012
qreal from = d->isContentFlowReversed() ? -d->position()-d->size() : d->position();
2013
qreal to = d->isContentFlowReversed() ? -d->position() : d->position()+d->size();
2014
for (int i = 0; i < d->visibleItems.count(); ++i) {
2015
FxGridItemSG *item = static_cast<FxGridItemSG*>(d->visibleItems.at(i));
2016
QQuickItemPrivate::get(item->item)->setCulled(item->rowPos() + d->rowSize() < from || item->rowPos() > to);
2018
if (d->currentItem) {
2019
FxGridItemSG *item = static_cast<FxGridItemSG*>(d->currentItem);
2020
QQuickItemPrivate::get(item->item)->setCulled(item->rowPos() + d->rowSize() < from || item->rowPos() > to);
2023
if (d->hData.flicking || d->vData.flicking || d->hData.moving || d->vData.moving)
2024
d->moveReason = QQuickGridViewPrivate::Mouse;
2025
if (d->moveReason != QQuickGridViewPrivate::SetIndex) {
2026
if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange && d->highlight) {
2027
// reposition highlight
2028
qreal pos = d->highlight->position();
2029
qreal viewPos = d->isContentFlowReversed() ? -d->position()-d->size() : d->position();
2030
if (pos > viewPos + d->highlightRangeEnd - d->highlight->size())
2031
pos = viewPos + d->highlightRangeEnd - d->highlight->size();
2032
if (pos < viewPos + d->highlightRangeStart)
2033
pos = viewPos + d->highlightRangeStart;
2035
if (pos != d->highlight->position()) {
2036
d->highlightXAnimator->stop();
2037
d->highlightYAnimator->stop();
2038
static_cast<FxGridItemSG*>(d->highlight)->setPosition(static_cast<FxGridItemSG*>(d->highlight)->colPos(), pos);
2040
d->updateHighlight();
2043
// update current index
2044
int idx = d->snapIndex();
2045
if (idx >= 0 && idx != d->currentIndex) {
2046
d->updateCurrent(idx);
2047
if (d->currentItem && static_cast<FxGridItemSG*>(d->currentItem)->colPos() != static_cast<FxGridItemSG*>(d->highlight)->colPos() && d->autoHighlight) {
2048
if (d->flow == FlowLeftToRight)
2049
d->highlightXAnimator->to = d->currentItem->itemX();
2051
d->highlightYAnimator->to = d->currentItem->itemY();
2057
d->inViewportMoved = false;
2060
void QQuickGridView::keyPressEvent(QKeyEvent *event)
2062
Q_D(QQuickGridView);
2063
if (d->model && d->model->count() && d->interactive) {
2064
d->moveReason = QQuickGridViewPrivate::SetIndex;
2065
int oldCurrent = currentIndex();
2066
switch (event->key()) {
2068
moveCurrentIndexUp();
2071
moveCurrentIndexDown();
2074
moveCurrentIndexLeft();
2077
moveCurrentIndexRight();
2082
if (oldCurrent != currentIndex() || d->wrap) {
2088
QQuickItemView::keyPressEvent(event);
2091
void QQuickGridView::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
2093
Q_D(QQuickGridView);
2096
if (newGeometry.width() != oldGeometry.width()
2097
&& newGeometry.height() != oldGeometry.height()) {
2098
d->setPosition(d->position());
2099
} else if (newGeometry.width() != oldGeometry.width()) {
2100
QQuickFlickable::setContentX(d->contentXForPosition(d->position()));
2101
} else if (newGeometry.height() != oldGeometry.height()) {
2102
QQuickFlickable::setContentY(d->contentYForPosition(d->position()));
2105
QQuickItemView::geometryChanged(newGeometry, oldGeometry);
2108
void QQuickGridView::initItem(int index, QQuickItem *item)
2110
QQuickItemView::initItem(index, item);
2111
QQuickGridViewAttached *attached = static_cast<QQuickGridViewAttached *>(
2112
qmlAttachedPropertiesObject<QQuickGridView>(item));
2114
attached->setView(this);
2118
\qmlmethod QtQuick2::GridView::moveCurrentIndexUp()
2120
Move the currentIndex up one item in the view.
2121
The current index will wrap if keyNavigationWraps is true and it
2122
is currently at the end. This method has no effect if the \l count is zero.
2124
\b Note: methods should only be called after the Component has completed.
2128
void QQuickGridView::moveCurrentIndexUp()
2130
Q_D(QQuickGridView);
2131
const int count = d->model ? d->model->count() : 0;
2134
if (d->verticalLayoutDirection == QQuickItemView::TopToBottom) {
2135
if (d->flow == QQuickGridView::FlowLeftToRight) {
2136
if (currentIndex() >= d->columns || d->wrap) {
2137
int index = currentIndex() - d->columns;
2138
setCurrentIndex((index >= 0 && index < count) ? index : count-1);
2141
if (currentIndex() > 0 || d->wrap) {
2142
int index = currentIndex() - 1;
2143
setCurrentIndex((index >= 0 && index < count) ? index : count-1);
2147
if (d->flow == QQuickGridView::FlowLeftToRight) {
2148
if (currentIndex() < count - d->columns || d->wrap) {
2149
int index = currentIndex()+d->columns;
2150
setCurrentIndex((index >= 0 && index < count) ? index : 0);
2153
if (currentIndex() < count - 1 || d->wrap) {
2154
int index = currentIndex() + 1;
2155
setCurrentIndex((index >= 0 && index < count) ? index : 0);
2162
\qmlmethod QtQuick2::GridView::moveCurrentIndexDown()
2164
Move the currentIndex down one item in the view.
2165
The current index will wrap if keyNavigationWraps is true and it
2166
is currently at the end. This method has no effect if the \l count is zero.
2168
\b Note: methods should only be called after the Component has completed.
2170
void QQuickGridView::moveCurrentIndexDown()
2172
Q_D(QQuickGridView);
2173
const int count = d->model ? d->model->count() : 0;
2177
if (d->verticalLayoutDirection == QQuickItemView::TopToBottom) {
2178
if (d->flow == QQuickGridView::FlowLeftToRight) {
2179
if (currentIndex() < count - d->columns || d->wrap) {
2180
int index = currentIndex()+d->columns;
2181
setCurrentIndex((index >= 0 && index < count) ? index : 0);
2184
if (currentIndex() < count - 1 || d->wrap) {
2185
int index = currentIndex() + 1;
2186
setCurrentIndex((index >= 0 && index < count) ? index : 0);
2190
if (d->flow == QQuickGridView::FlowLeftToRight) {
2191
if (currentIndex() >= d->columns || d->wrap) {
2192
int index = currentIndex() - d->columns;
2193
setCurrentIndex((index >= 0 && index < count) ? index : count-1);
2196
if (currentIndex() > 0 || d->wrap) {
2197
int index = currentIndex() - 1;
2198
setCurrentIndex((index >= 0 && index < count) ? index : count-1);
2205
\qmlmethod QtQuick2::GridView::moveCurrentIndexLeft()
2207
Move the currentIndex left one item in the view.
2208
The current index will wrap if keyNavigationWraps is true and it
2209
is currently at the end. This method has no effect if the \l count is zero.
2211
\b Note: methods should only be called after the Component has completed.
2213
void QQuickGridView::moveCurrentIndexLeft()
2215
Q_D(QQuickGridView);
2216
const int count = d->model ? d->model->count() : 0;
2219
if (effectiveLayoutDirection() == Qt::LeftToRight) {
2220
if (d->flow == QQuickGridView::FlowLeftToRight) {
2221
if (currentIndex() > 0 || d->wrap) {
2222
int index = currentIndex() - 1;
2223
setCurrentIndex((index >= 0 && index < count) ? index : count-1);
2226
if (currentIndex() >= d->columns || d->wrap) {
2227
int index = currentIndex() - d->columns;
2228
setCurrentIndex((index >= 0 && index < count) ? index : count-1);
2232
if (d->flow == QQuickGridView::FlowLeftToRight) {
2233
if (currentIndex() < count - 1 || d->wrap) {
2234
int index = currentIndex() + 1;
2235
setCurrentIndex((index >= 0 && index < count) ? index : 0);
2238
if (currentIndex() < count - d->columns || d->wrap) {
2239
int index = currentIndex() + d->columns;
2240
setCurrentIndex((index >= 0 && index < count) ? index : 0);
2248
\qmlmethod QtQuick2::GridView::moveCurrentIndexRight()
2250
Move the currentIndex right one item in the view.
2251
The current index will wrap if keyNavigationWraps is true and it
2252
is currently at the end. This method has no effect if the \l count is zero.
2254
\b Note: methods should only be called after the Component has completed.
2256
void QQuickGridView::moveCurrentIndexRight()
2258
Q_D(QQuickGridView);
2259
const int count = d->model ? d->model->count() : 0;
2262
if (effectiveLayoutDirection() == Qt::LeftToRight) {
2263
if (d->flow == QQuickGridView::FlowLeftToRight) {
2264
if (currentIndex() < count - 1 || d->wrap) {
2265
int index = currentIndex() + 1;
2266
setCurrentIndex((index >= 0 && index < count) ? index : 0);
2269
if (currentIndex() < count - d->columns || d->wrap) {
2270
int index = currentIndex()+d->columns;
2271
setCurrentIndex((index >= 0 && index < count) ? index : 0);
2275
if (d->flow == QQuickGridView::FlowLeftToRight) {
2276
if (currentIndex() > 0 || d->wrap) {
2277
int index = currentIndex() - 1;
2278
setCurrentIndex((index >= 0 && index < count) ? index : count-1);
2281
if (currentIndex() >= d->columns || d->wrap) {
2282
int index = currentIndex() - d->columns;
2283
setCurrentIndex((index >= 0 && index < count) ? index : count-1);
2289
bool QQuickGridViewPrivate::applyInsertionChange(const QQuickChangeSet::Insert &change, ChangeResult *insertResult, QList<FxViewItem *> *addedItems, QList<MovedItem> *movingIntoView)
2291
Q_Q(QQuickGridView);
2293
int modelIndex = change.index;
2294
int count = change.count;
2296
int index = visibleItems.count() ? mapFromModel(modelIndex) : 0;
2299
int i = visibleItems.count() - 1;
2300
while (i > 0 && visibleItems.at(i)->index == -1)
2302
if (visibleItems.at(i)->index + 1 == modelIndex) {
2303
// Special case of appending an item to the model.
2304
index = visibleItems.count();
2306
if (modelIndex <= visibleIndex) {
2307
// Insert before visible items
2308
visibleIndex += count;
2309
for (int i = 0; i < visibleItems.count(); ++i) {
2310
FxViewItem *item = visibleItems.at(i);
2311
if (item->index != -1 && item->index >= modelIndex)
2312
item->index += count;
2319
qreal tempPos = isContentFlowReversed() ? -position()-size()+q->width()+1 : position();
2323
if (visibleItems.count()) {
2324
if (index < visibleItems.count()) {
2325
FxGridItemSG *gridItem = static_cast<FxGridItemSG*>(visibleItems.at(index));
2326
colPos = gridItem->colPos();
2327
rowPos = gridItem->rowPos();
2328
colNum = qFloor((colPos+colSize()/2) / colSize());
2330
// appending items to visible list
2331
FxGridItemSG *gridItem = static_cast<FxGridItemSG*>(visibleItems.at(index-1));
2332
rowPos = gridItem->rowPos();
2333
colNum = qFloor((gridItem->colPos()+colSize()/2) / colSize());
2334
if (++colNum >= columns) {
2336
rowPos += rowSize();
2338
colPos = colNum * colSize();
2342
// Update the indexes of the following visible items.
2343
for (int i = 0; i < visibleItems.count(); ++i) {
2344
FxViewItem *item = visibleItems.at(i);
2345
if (item->index != -1 && item->index >= modelIndex) {
2346
item->index += count;
2347
if (change.isMove())
2348
item->transitionNextReposition(transitioner, QQuickItemViewTransitioner::MoveTransition, false);
2350
item->transitionNextReposition(transitioner, QQuickItemViewTransitioner::AddTransition, false);
2354
int prevVisibleCount = visibleItems.count();
2355
if (insertResult->visiblePos.isValid() && rowPos < insertResult->visiblePos) {
2356
// Insert items before the visible item.
2357
int insertionIdx = index;
2359
int from = tempPos - buffer;
2362
if (rowPos > from && insertionIdx < visibleIndex) {
2363
// item won't be visible, just note the size for repositioning
2364
insertResult->countChangeBeforeVisible++;
2366
// item is before first visible e.g. in cache buffer
2367
FxViewItem *item = 0;
2368
if (change.isMove() && (item = currentChanges.removedItems.take(change.moveKey(modelIndex + i))))
2369
item->index = modelIndex + i;
2371
item = createItem(modelIndex + i);
2375
QQuickItemPrivate::get(item->item)->setCulled(false);
2376
visibleItems.insert(insertionIdx, item);
2377
if (insertionIdx == 0)
2378
insertResult->changedFirstItem = true;
2379
if (!change.isMove()) {
2380
addedItems->append(item);
2381
item->transitionNextReposition(transitioner, QQuickItemViewTransitioner::AddTransition, true);
2383
insertResult->sizeChangesBeforeVisiblePos += rowSize();
2386
if (--colNum < 0 ) {
2387
colNum = columns - 1;
2388
rowPos -= rowSize();
2390
colPos = colNum * colSize();
2396
int to = buffer+tempPos+size()-1;
2397
while (i < count && rowPos <= to + rowSize()*(columns - colNum)/qreal(columns+1)) {
2398
FxViewItem *item = 0;
2399
if (change.isMove() && (item = currentChanges.removedItems.take(change.moveKey(modelIndex + i))))
2400
item->index = modelIndex + i;
2401
bool newItem = !item;
2403
item = createItem(modelIndex + i);
2407
QQuickItemPrivate::get(item->item)->setCulled(false);
2408
visibleItems.insert(index, item);
2410
insertResult->changedFirstItem = true;
2411
if (change.isMove()) {
2412
// we know this is a move target, since move displaced items that are
2413
// shuffled into view due to a move would be added in refill()
2414
if (newItem && transitioner && transitioner->canTransition(QQuickItemViewTransitioner::MoveTransition, true))
2415
movingIntoView->append(MovedItem(item, change.moveKey(item->index)));
2417
addedItems->append(item);
2418
item->transitionNextReposition(transitioner, QQuickItemViewTransitioner::AddTransition, true);
2420
insertResult->sizeChangesAfterVisiblePos += rowSize();
2422
if (++colNum >= columns) {
2424
rowPos += rowSize();
2426
colPos = colNum * colSize();
2432
updateVisibleIndex();
2434
return visibleItems.count() > prevVisibleCount;
2437
void QQuickGridViewPrivate::translateAndTransitionItemsAfter(int afterModelIndex, const ChangeResult &insertionResult, const ChangeResult &removalResult)
2442
int markerItemIndex = -1;
2443
for (int i=0; i<visibleItems.count(); i++) {
2444
if (visibleItems[i]->index == afterModelIndex) {
2445
markerItemIndex = i;
2449
if (markerItemIndex < 0)
2452
const qreal viewEndPos = isContentFlowReversed() ? -position() : position() + size();
2453
int countItemsRemoved = -(removalResult.sizeChangesAfterVisiblePos / rowSize());
2455
// account for whether first item has changed if < 1 row was removed before visible
2456
int changeBeforeVisible = insertionResult.countChangeBeforeVisible - removalResult.countChangeBeforeVisible;
2457
if (changeBeforeVisible != 0)
2458
countItemsRemoved += (changeBeforeVisible % columns) - (columns - 1);
2460
countItemsRemoved -= removalResult.countChangeAfterVisibleItems;
2462
for (int i=markerItemIndex+1; i<visibleItems.count() && visibleItems.at(i)->position() < viewEndPos; i++) {
2463
FxGridItemSG *gridItem = static_cast<FxGridItemSG *>(visibleItems[i]);
2464
if (!gridItem->transitionScheduledOrRunning()) {
2465
qreal origRowPos = gridItem->colPos();
2466
qreal origColPos = gridItem->rowPos();
2467
int indexDiff = gridItem->index - countItemsRemoved;
2468
gridItem->setPosition((indexDiff % columns) * colSize(), (indexDiff / columns) * rowSize());
2469
gridItem->transitionNextReposition(transitioner, QQuickItemViewTransitioner::RemoveTransition, false);
2470
gridItem->setPosition(origRowPos, origColPos);
2475
bool QQuickGridViewPrivate::needsRefillForAddedOrRemovedIndex(int modelIndex) const
2477
// If we add or remove items before visible items, a layout may be
2478
// required to ensure item 0 is in the first column.
2479
return modelIndex < visibleIndex;
2483
\qmlmethod QtQuick2::GridView::positionViewAtIndex(int index, PositionMode mode)
2485
Positions the view such that the \a index is at the position specified by
2489
\li GridView.Beginning - position item at the top (or left for \c GridView.TopToBottom flow) of the view.
2490
\li GridView.Center - position item in the center of the view.
2491
\li GridView.End - position item at bottom (or right for horizontal orientation) of the view.
2492
\li GridView.Visible - if any part of the item is visible then take no action, otherwise
2493
bring the item into view.
2494
\li GridView.Contain - ensure the entire item is visible. If the item is larger than
2495
the view the item is positioned at the top (or left for \c GridView.TopToBottom flow) of the view.
2496
\li GridView.SnapPosition - position the item at \l preferredHighlightBegin. This mode
2497
is only valid if \l highlightRangeMode is StrictlyEnforceRange or snapping is enabled
2501
If positioning the view at the index would cause empty space to be displayed at
2502
the beginning or end of the view, the view will be positioned at the boundary.
2504
It is not recommended to use \l {Flickable::}{contentX} or \l {Flickable::}{contentY} to position the view
2505
at a particular index. This is unreliable since removing items from the start
2506
of the view does not cause all other items to be repositioned.
2507
The correct way to bring an item into view is with \c positionViewAtIndex.
2509
\b Note: methods should only be called after the Component has completed. To position
2510
the view at startup, this method should be called by Component.onCompleted. For
2511
example, to position the view at the end:
2514
Component.onCompleted: positionViewAtIndex(count - 1, GridView.Beginning)
2519
\qmlmethod QtQuick2::GridView::positionViewAtBeginning()
2520
\qmlmethod QtQuick2::GridView::positionViewAtEnd()
2522
Positions the view at the beginning or end, taking into account any header or footer.
2524
It is not recommended to use \l {Flickable::}{contentX} or \l {Flickable::}{contentY} to position the view
2525
at a particular index. This is unreliable since removing items from the start
2526
of the list does not cause all other items to be repositioned, and because
2527
the actual start of the view can vary based on the size of the delegates.
2529
\b Note: methods should only be called after the Component has completed. To position
2530
the view at startup, this method should be called by Component.onCompleted. For
2531
example, to position the view at the end on startup:
2534
Component.onCompleted: positionViewAtEnd()
2539
\qmlmethod int QtQuick2::GridView::indexAt(int x, int y)
2541
Returns the index of the visible item containing the point \a x, \a y in content
2542
coordinates. If there is no item at the point specified, or the item is
2543
not visible -1 is returned.
2545
If the item is outside the visible area, -1 is returned, regardless of
2546
whether an item will exist at that point when scrolled into view.
2548
\b Note: methods should only be called after the Component has completed.
2552
\qmlmethod Item QtQuick2::GridView::itemAt(int x, int y)
2554
Returns the visible item containing the point \a x, \a y in content
2555
coordinates. If there is no item at the point specified, or the item is
2556
not visible null is returned.
2558
If the item is outside the visible area, null is returned, regardless of
2559
whether an item will exist at that point when scrolled into view.
2561
\b Note: methods should only be called after the Component has completed.
2566
\qmlmethod QtQuick2::GridView::forceLayout()
2568
Responding to changes in the model is usually batched to happen only once
2569
per frame. This means that inside script blocks it is possible for the
2570
underlying model to have changed, but the GridView has not caught up yet.
2572
This method forces the GridView to immediately respond to any outstanding
2573
changes in the model.
2577
\b Note: methods should only be called after the Component has completed.
2580
QQuickGridViewAttached *QQuickGridView::qmlAttachedProperties(QObject *obj)
2582
return new QQuickGridViewAttached(obj);