1 /****************************************************************************
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the QtDeclarative module of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include "qsggridview_p.h"
43 #include "qsgvisualitemmodel_p.h"
44 #include "qsgflickable_p_p.h"
45 #include "qsgitemview_p_p.h"
47 #include <private/qdeclarativesmoothedanimation_p_p.h>
48 #include <private/qlistmodelinterface_p.h>
50 #include <QtGui/qevent.h>
51 #include <QtCore/qmath.h>
52 #include <QtCore/qcoreapplication.h>
57 //----------------------------------------------------------------------------
59 class FxGridItemSG : public FxViewItem
62 FxGridItemSG(QSGItem *i, QSGGridView *v, bool own) : FxViewItem(i, own), view(v) {
63 attached = static_cast<QSGGridViewAttached*>(qmlAttachedPropertiesObject<QSGGridView>(item));
65 static_cast<QSGGridViewAttached*>(attached)->setView(view);
70 qreal position() const {
74 qreal endPosition() const {
79 return view->flow() == QSGGridView::LeftToRight ? view->cellHeight() : view->cellWidth();
82 qreal sectionSize() const {
86 qreal rowPos() const {
87 if (view->flow() == QSGGridView::LeftToRight)
90 return (view->effectiveLayoutDirection() == Qt::RightToLeft ? -view->cellWidth()-item->x() : item->x());
93 qreal colPos() const {
94 if (view->flow() == QSGGridView::LeftToRight) {
95 if (view->effectiveLayoutDirection() == Qt::RightToLeft) {
96 int colSize = view->cellWidth();
97 int columns = view->width()/colSize;
98 return colSize * (columns-1) - item->x();
106 qreal endRowPos() const {
107 if (view->flow() == QSGGridView::LeftToRight) {
108 return item->y() + view->cellHeight();
110 if (view->effectiveLayoutDirection() == Qt::RightToLeft)
113 return item->x() + view->cellWidth();
116 void setPosition(qreal col, qreal row) {
117 if (view->effectiveLayoutDirection() == Qt::RightToLeft) {
118 if (view->flow() == QSGGridView::LeftToRight) {
119 int columns = view->width()/view->cellWidth();
120 item->setPos(QPointF((view->cellWidth() * (columns-1) - col), row));
122 item->setPos(QPointF(-view->cellWidth()-row, col));
125 if (view->flow() == QSGGridView::LeftToRight)
126 item->setPos(QPointF(col, row));
128 item->setPos(QPointF(row, col));
131 bool contains(qreal x, qreal y) const {
132 return (x >= item->x() && x < item->x() + view->cellWidth() &&
133 y >= item->y() && y < item->y() + view->cellHeight());
139 //----------------------------------------------------------------------------
141 class QSGGridViewPrivate : public QSGItemViewPrivate
143 Q_DECLARE_PUBLIC(QSGGridView)
146 virtual Qt::Orientation layoutOrientation() const;
147 virtual bool isContentFlowReversed() const;
148 bool isRightToLeftTopToBottom() const;
150 virtual qreal positionAt(int index) const;
151 virtual qreal endPositionAt(int index) const;
152 virtual qreal originPosition() const;
153 virtual qreal lastPosition() const;
157 qreal colPosAt(int modelIndex) const;
158 qreal rowPosAt(int modelIndex) const;
159 qreal snapPosAt(qreal pos) const;
160 FxViewItem *snapItemAt(qreal pos) const;
161 int snapIndex() const;
163 virtual bool addVisibleItems(int fillFrom, int fillTo, bool doBuffer);
164 virtual bool removeNonVisibleItems(int bufferFrom, int bufferTo);
165 virtual void visibleItemsChanged();
167 virtual FxViewItem *newViewItem(int index, QSGItem *item);
168 virtual void repositionPackageItemAt(QSGItem *item, int index);
170 virtual void createHighlight();
171 virtual void updateHighlight();
172 virtual void resetHighlightPosition();
174 virtual void setPosition(qreal pos);
175 virtual void layoutVisibleItems();
177 virtual qreal headerSize() const;
178 virtual qreal footerSize() const;
179 virtual void updateHeader();
180 virtual void updateFooter();
182 virtual void changedVisibleIndex(int newIndex);
183 virtual void initializeCurrentItem();
185 virtual void updateViewport();
186 virtual void itemGeometryChanged(QSGItem *item, const QRectF &newGeometry, const QRectF &oldGeometry);
187 virtual void fixupPosition();
188 virtual void fixup(AxisData &data, qreal minExtent, qreal maxExtent);
189 virtual void flick(QSGItemViewPrivate::AxisData &data, qreal minExtent, qreal maxExtent, qreal vSize,
190 QDeclarativeTimeLineCallback::Callback fixupCallback, qreal velocity);
192 QSGGridView::Flow flow;
196 QSGGridView::SnapMode snapMode;
198 QSmoothedAnimation *highlightXAnimator;
199 QSmoothedAnimation *highlightYAnimator;
202 : flow(QSGGridView::LeftToRight)
203 , cellWidth(100), cellHeight(100), columns(1)
204 , snapMode(QSGGridView::NoSnap)
205 , highlightXAnimator(0), highlightYAnimator(0)
209 Qt::Orientation QSGGridViewPrivate::layoutOrientation() const
211 return flow == QSGGridView::LeftToRight ? Qt::Vertical : Qt::Horizontal;
214 bool QSGGridViewPrivate::isContentFlowReversed() const
216 return isRightToLeftTopToBottom();
219 bool QSGGridViewPrivate::isRightToLeftTopToBottom() const
221 Q_Q(const QSGGridView);
222 return flow == QSGGridView::TopToBottom && q->effectiveLayoutDirection() == Qt::RightToLeft;
225 void QSGGridViewPrivate::changedVisibleIndex(int newIndex)
227 visibleIndex = newIndex / columns * columns;
230 void QSGGridViewPrivate::setPosition(qreal pos)
233 if (flow == QSGGridView::LeftToRight) {
234 q->QSGFlickable::setContentY(pos);
235 q->QSGFlickable::setContentX(0);
237 if (q->effectiveLayoutDirection() == Qt::LeftToRight)
238 q->QSGFlickable::setContentX(pos);
240 q->QSGFlickable::setContentX(-pos-size());
241 q->QSGFlickable::setContentY(0);
245 qreal QSGGridViewPrivate::originPosition() const
248 if (!visibleItems.isEmpty())
249 pos = static_cast<FxGridItemSG*>(visibleItems.first())->rowPos() - visibleIndex / columns * rowSize();
253 qreal QSGGridViewPrivate::lastPosition() const
256 if (model && model->count()) {
257 // get end position of last item
258 pos = (rowPosAt(model->count() - 1) + rowSize());
263 qreal QSGGridViewPrivate::positionAt(int index) const
265 return rowPosAt(index);
268 qreal QSGGridViewPrivate::endPositionAt(int index) const
270 return rowPosAt(index) + rowSize();
273 int QSGGridViewPrivate::rowSize() const {
274 return flow == QSGGridView::LeftToRight ? cellHeight : cellWidth;
276 int QSGGridViewPrivate::colSize() const {
277 return flow == QSGGridView::LeftToRight ? cellWidth : cellHeight;
280 qreal QSGGridViewPrivate::colPosAt(int modelIndex) const
282 if (FxViewItem *item = visibleItem(modelIndex))
283 return static_cast<FxGridItemSG*>(item)->colPos();
284 if (!visibleItems.isEmpty()) {
285 if (modelIndex < visibleIndex) {
286 int count = (visibleIndex - modelIndex) % columns;
287 int col = static_cast<FxGridItemSG*>(visibleItems.first())->colPos() / colSize();
288 col = (columns - count + col) % columns;
289 return col * colSize();
291 int count = columns - 1 - (modelIndex - visibleItems.last()->index - 1) % columns;
292 return static_cast<FxGridItemSG*>(visibleItems.last())->colPos() - count * colSize();
295 return (modelIndex % columns) * colSize();
298 qreal QSGGridViewPrivate::rowPosAt(int modelIndex) const
300 if (FxViewItem *item = visibleItem(modelIndex))
301 return static_cast<FxGridItemSG*>(item)->rowPos();
302 if (!visibleItems.isEmpty()) {
303 if (modelIndex < visibleIndex) {
304 FxGridItemSG *firstItem = static_cast<FxGridItemSG*>(visibleItems.first());
305 int firstCol = firstItem->colPos() / colSize();
306 int col = visibleIndex - modelIndex + (columns - firstCol - 1);
307 int rows = col / columns;
308 return firstItem->rowPos() - rows * rowSize();
310 FxGridItemSG *lastItem = static_cast<FxGridItemSG*>(visibleItems.last());
311 int count = modelIndex - lastItem->index;
312 int col = lastItem->colPos() + count * colSize();
313 int rows = col / (columns * colSize());
314 return lastItem->rowPos() + rows * rowSize();
317 return (modelIndex / columns) * rowSize();
321 qreal QSGGridViewPrivate::snapPosAt(qreal pos) const
323 Q_Q(const QSGGridView);
325 if (!visibleItems.isEmpty()) {
327 snapPos = static_cast<FxGridItemSG*>(visibleItems.first())->rowPos() - visibleIndex / columns * rowSize();
328 snapPos = pos - fmodf(pos - snapPos, qreal(rowSize()));
331 if (isRightToLeftTopToBottom()) {
332 maxExtent = q->minXExtent();
333 minExtent = q->maxXExtent();
335 maxExtent = flow == QSGGridView::LeftToRight ? -q->maxYExtent() : -q->maxXExtent();
336 minExtent = flow == QSGGridView::LeftToRight ? -q->minYExtent() : -q->minXExtent();
338 if (snapPos > maxExtent)
340 if (snapPos < minExtent)
346 FxViewItem *QSGGridViewPrivate::snapItemAt(qreal pos) const
348 for (int i = 0; i < visibleItems.count(); ++i) {
349 FxViewItem *item = visibleItems.at(i);
350 if (item->index == -1)
352 qreal itemTop = item->position();
353 if (itemTop+rowSize()/2 >= pos && itemTop - rowSize()/2 <= pos)
359 int QSGGridViewPrivate::snapIndex() const
361 int index = currentIndex;
362 for (int i = 0; i < visibleItems.count(); ++i) {
363 FxGridItemSG *item = static_cast<FxGridItemSG*>(visibleItems.at(i));
364 if (item->index == -1)
366 qreal itemTop = item->position();
367 FxGridItemSG *hItem = static_cast<FxGridItemSG*>(highlight);
368 if (itemTop >= hItem->rowPos()-rowSize()/2 && itemTop < hItem->rowPos()+rowSize()/2) {
370 if (item->colPos() >= hItem->colPos()-colSize()/2 && item->colPos() < hItem->colPos()+colSize()/2)
377 FxViewItem *QSGGridViewPrivate::newViewItem(int modelIndex, QSGItem *item)
380 Q_UNUSED(modelIndex);
381 return new FxGridItemSG(item, q, false);
384 bool QSGGridViewPrivate::addVisibleItems(int fillFrom, int fillTo, bool doBuffer)
386 int colPos = colPosAt(visibleIndex);
387 int rowPos = rowPosAt(visibleIndex);
388 if (visibleItems.count()) {
389 FxGridItemSG *lastItem = static_cast<FxGridItemSG*>(visibleItems.last());
390 rowPos = lastItem->rowPos();
391 colPos = lastItem->colPos() + colSize();
392 if (colPos > colSize() * (columns-1)) {
398 int modelIndex = findLastVisibleIndex();
399 modelIndex = modelIndex < 0 ? visibleIndex : modelIndex + 1;
401 if (visibleItems.count() && (fillFrom > rowPos + rowSize()*2
402 || fillTo < rowPosAt(visibleIndex) - rowSize())) {
403 // We've jumped more than a page. Estimate which items are now
404 // visible and fill from there.
405 int count = (fillFrom - (rowPos + rowSize())) / (rowSize()) * columns;
406 for (int i = 0; i < visibleItems.count(); ++i)
407 releaseItem(visibleItems.at(i));
408 visibleItems.clear();
410 if (modelIndex >= model->count())
411 modelIndex = model->count() - 1;
412 else if (modelIndex < 0)
414 modelIndex = modelIndex / columns * columns;
415 visibleIndex = modelIndex;
416 colPos = colPosAt(visibleIndex);
417 rowPos = rowPosAt(visibleIndex);
420 int colNum = colPos / colSize();
421 FxGridItemSG *item = 0;
422 bool changed = false;
424 while (modelIndex < model->count() && rowPos <= fillTo + rowSize()*(columns - colNum)/(columns+1)) {
425 // qDebug() << "refill: append item" << modelIndex;
426 if (!(item = static_cast<FxGridItemSG*>(createItem(modelIndex))))
428 item->setPosition(colPos, rowPos);
429 visibleItems.append(item);
432 if (colPos > colSize() * (columns-1)) {
439 if (doBuffer) // never buffer more than one item per frame
443 if (visibleItems.count()) {
444 FxGridItemSG *firstItem = static_cast<FxGridItemSG*>(visibleItems.first());
445 rowPos = firstItem->rowPos();
446 colPos = firstItem->colPos() - colSize();
448 colPos = colSize() * (columns - 1);
453 colNum = colPos / colSize();
454 while (visibleIndex > 0 && rowPos + rowSize() - 1 >= fillFrom - rowSize()*(colNum+1)/(columns+1)){
455 // qDebug() << "refill: prepend item" << visibleIndex-1 << "top pos" << rowPos << colPos;
456 if (!(item = static_cast<FxGridItemSG*>(createItem(visibleIndex-1))))
459 item->setPosition(colPos, rowPos);
460 visibleItems.prepend(item);
464 colPos = colSize() * (columns - 1);
469 if (doBuffer) // never buffer more than one item per frame
476 bool QSGGridViewPrivate::removeNonVisibleItems(int bufferFrom, int bufferTo)
478 FxGridItemSG *item = 0;
479 bool changed = false;
481 while (visibleItems.count() > 1
482 && (item = static_cast<FxGridItemSG*>(visibleItems.first()))
483 && item->rowPos()+rowSize()-1 < bufferFrom - rowSize()*(item->colPos()/colSize()+1)/(columns+1)) {
484 if (item->attached->delayRemove())
486 // qDebug() << "refill: remove first" << visibleIndex << "top end pos" << item->endRowPos();
487 if (item->index != -1)
489 visibleItems.removeFirst();
493 while (visibleItems.count() > 1
494 && (item = static_cast<FxGridItemSG*>(visibleItems.last()))
495 && item->rowPos() > bufferTo + rowSize()*(columns - item->colPos()/colSize())/(columns+1)) {
496 if (item->attached->delayRemove())
498 // qDebug() << "refill: remove last" << visibleIndex+visibleItems.count()-1;
499 visibleItems.removeLast();
507 void QSGGridViewPrivate::visibleItemsChanged()
514 void QSGGridViewPrivate::updateViewport()
517 columns = (int)qMax((flow == QSGGridView::LeftToRight ? q->width() : q->height()) / colSize(), qreal(1.));
518 QSGItemViewPrivate::updateViewport();
521 void QSGGridViewPrivate::layoutVisibleItems()
523 if (visibleItems.count()) {
524 FxGridItemSG *firstItem = static_cast<FxGridItemSG*>(visibleItems.first());
525 qreal rowPos = firstItem->rowPos();
526 qreal colPos = firstItem->colPos();
527 int col = visibleIndex % columns;
528 if (colPos != col * colSize()) {
529 colPos = col * colSize();
530 firstItem->setPosition(colPos, rowPos);
532 for (int i = 1; i < visibleItems.count(); ++i) {
533 FxGridItemSG *item = static_cast<FxGridItemSG*>(visibleItems.at(i));
535 if (colPos > colSize() * (columns-1)) {
539 item->setPosition(colPos, rowPos);
544 void QSGGridViewPrivate::repositionPackageItemAt(QSGItem *item, int index)
547 qreal pos = position();
548 if (flow == QSGGridView::LeftToRight) {
549 if (item->y() + item->height() > pos && item->y() < pos + q->height())
550 item->setPos(QPointF(colPosAt(index), rowPosAt(index)));
552 if (item->x() + item->width() > pos && item->x() < pos + q->width()) {
553 if (isRightToLeftTopToBottom())
554 item->setPos(QPointF(-rowPosAt(index)-item->width(), colPosAt(index)));
556 item->setPos(QPointF(rowPosAt(index), colPosAt(index)));
562 void QSGGridViewPrivate::createHighlight()
565 bool changed = false;
567 if (trackedItem == highlight)
572 delete highlightXAnimator;
573 delete highlightYAnimator;
574 highlightXAnimator = 0;
575 highlightYAnimator = 0;
581 QSGItem *item = createHighlightItem();
583 FxGridItemSG *newHighlight = new FxGridItemSG(item, q, true);
585 resetHighlightPosition();
586 highlightXAnimator = new QSmoothedAnimation(q);
587 highlightXAnimator->target = QDeclarativeProperty(item, QLatin1String("x"));
588 highlightXAnimator->userDuration = highlightMoveDuration;
589 highlightYAnimator = new QSmoothedAnimation(q);
590 highlightYAnimator->target = QDeclarativeProperty(item, QLatin1String("y"));
591 highlightYAnimator->userDuration = highlightMoveDuration;
593 highlight = newHighlight;
598 emit q->highlightItemChanged();
601 void QSGGridViewPrivate::updateHighlight()
603 if ((!currentItem && highlight) || (currentItem && !highlight))
605 bool strictHighlight = haveHighlightRange && highlightRange == QSGGridView::StrictlyEnforceRange;
606 if (currentItem && autoHighlight && highlight && (!strictHighlight || !pressed)) {
607 // auto-update highlight
608 highlightXAnimator->to = currentItem->item->x();
609 highlightYAnimator->to = currentItem->item->y();
610 highlight->item->setWidth(currentItem->item->width());
611 highlight->item->setHeight(currentItem->item->height());
613 highlightXAnimator->restart();
614 highlightYAnimator->restart();
619 void QSGGridViewPrivate::resetHighlightPosition()
621 if (highlight && currentItem) {
622 FxGridItemSG *cItem = static_cast<FxGridItemSG*>(currentItem);
623 static_cast<FxGridItemSG*>(highlight)->setPosition(cItem->colPos(), cItem->rowPos());
627 qreal QSGGridViewPrivate::headerSize() const
631 return flow == QSGGridView::LeftToRight ? header->item->height() : header->item->width();
634 qreal QSGGridViewPrivate::footerSize() const
638 return flow == QSGGridView::LeftToRight? footer->item->height() : footer->item->width();
641 void QSGGridViewPrivate::updateFooter()
644 bool created = false;
646 QSGItem *item = createComponentItem(footerComponent, true);
650 footer = new FxGridItemSG(item, q, true);
654 FxGridItemSG *gridItem = static_cast<FxGridItemSG*>(footer);
657 if (q->effectiveLayoutDirection() == Qt::RightToLeft) {
658 if (flow == QSGGridView::TopToBottom)
659 rowOffset = gridItem->item->width() - cellWidth;
661 colOffset = gridItem->item->width() - cellWidth;
663 if (visibleItems.count()) {
664 qreal endPos = lastPosition();
665 if (findLastVisibleIndex() == model->count()-1) {
666 gridItem->setPosition(colOffset, endPos + rowOffset);
668 qreal visiblePos = isRightToLeftTopToBottom() ? -position() : position() + size();
669 if (endPos <= visiblePos || gridItem->endPosition() <= endPos + rowOffset)
670 gridItem->setPosition(colOffset, endPos + rowOffset);
673 gridItem->setPosition(colOffset, rowOffset);
677 emit q->footerItemChanged();
680 void QSGGridViewPrivate::updateHeader()
683 bool created = false;
685 QSGItem *item = createComponentItem(headerComponent, true);
689 header = new FxGridItemSG(item, q, true);
693 FxGridItemSG *gridItem = static_cast<FxGridItemSG*>(header);
695 qreal rowOffset = -headerSize();
696 if (q->effectiveLayoutDirection() == Qt::RightToLeft) {
697 if (flow == QSGGridView::TopToBottom)
698 rowOffset += gridItem->item->width()-cellWidth;
700 colOffset = gridItem->item->width()-cellWidth;
702 if (visibleItems.count()) {
703 qreal startPos = originPosition();
704 if (visibleIndex == 0) {
705 gridItem->setPosition(colOffset, startPos + rowOffset);
707 qreal tempPos = isRightToLeftTopToBottom() ? -position()-size() : position();
708 qreal headerPos = isRightToLeftTopToBottom() ? gridItem->rowPos() + cellWidth - headerSize() : gridItem->rowPos();
709 if (tempPos <= startPos || headerPos > startPos + rowOffset)
710 gridItem->setPosition(colOffset, startPos + rowOffset);
713 if (isRightToLeftTopToBottom())
714 gridItem->setPosition(colOffset, rowOffset);
716 gridItem->setPosition(colOffset, -headerSize());
720 emit q->headerItemChanged();
723 void QSGGridViewPrivate::initializeCurrentItem()
725 if (currentItem && currentIndex >= 0) {
726 FxGridItemSG *gridItem = static_cast<FxGridItemSG*>(currentItem);
728 gridItem->setPosition(colPosAt(currentIndex), rowPosAt(currentIndex));
732 void QSGGridViewPrivate::itemGeometryChanged(QSGItem *item, const QRectF &newGeometry, const QRectF &oldGeometry)
735 QSGItemViewPrivate::itemGeometryChanged(item, newGeometry, oldGeometry);
736 if (!q->isComponentComplete())
739 if (newGeometry.height() != oldGeometry.height() || newGeometry.width() != oldGeometry.width()) {
746 void QSGGridViewPrivate::fixupPosition()
749 if (flow == QSGGridView::LeftToRight)
755 void QSGGridViewPrivate::fixup(AxisData &data, qreal minExtent, qreal maxExtent)
757 if ((flow == QSGGridView::TopToBottom && &data == &vData)
758 || (flow == QSGGridView::LeftToRight && &data == &hData))
761 fixupMode = moveReason == Mouse ? fixupMode : Immediate;
763 qreal highlightStart;
766 if (isRightToLeftTopToBottom()) {
767 // Handle Right-To-Left exceptions
768 viewPos = -position()-size();
769 highlightStart = highlightRangeStartValid ? size()-highlightRangeEnd : highlightRangeStart;
770 highlightEnd = highlightRangeEndValid ? size()-highlightRangeStart : highlightRangeEnd;
772 viewPos = position();
773 highlightStart = highlightRangeStart;
774 highlightEnd = highlightRangeEnd;
777 if (snapMode != QSGGridView::NoSnap) {
778 qreal tempPosition = isRightToLeftTopToBottom() ? -position()-size() : position();
779 FxViewItem *topItem = snapItemAt(tempPosition+highlightStart);
780 FxViewItem *bottomItem = snapItemAt(tempPosition+highlightEnd);
782 if (topItem && bottomItem && haveHighlightRange && highlightRange == QSGGridView::StrictlyEnforceRange) {
783 qreal topPos = qMin(topItem->position() - highlightStart, -maxExtent);
784 qreal bottomPos = qMax(bottomItem->position() - highlightEnd, -minExtent);
785 pos = qAbs(data.move + topPos) < qAbs(data.move + bottomPos) ? topPos : bottomPos;
786 } else if (topItem) {
789 headerPos = isRightToLeftTopToBottom() ? static_cast<FxGridItemSG*>(header)->rowPos() + cellWidth - headerSize() : static_cast<FxGridItemSG*>(header)->rowPos();
790 if (topItem->index == 0 && header && tempPosition+highlightStart < headerPos+headerSize()/2) {
791 pos = isRightToLeftTopToBottom() ? - headerPos + highlightStart - size() : headerPos - highlightStart;
793 if (isRightToLeftTopToBottom())
794 pos = qMax(qMin(-topItem->position() + highlightStart - size(), -maxExtent), -minExtent);
796 pos = qMax(qMin(topItem->position() - highlightStart, -maxExtent), -minExtent);
798 } else if (bottomItem) {
799 if (isRightToLeftTopToBottom())
800 pos = qMax(qMin(-bottomItem->position() + highlightStart - size(), -maxExtent), -minExtent);
802 pos = qMax(qMin(bottomItem->position() - highlightStart, -maxExtent), -minExtent);
804 QSGItemViewPrivate::fixup(data, minExtent, maxExtent);
807 if (currentItem && haveHighlightRange && highlightRange == QSGGridView::StrictlyEnforceRange) {
809 qreal currPos = static_cast<FxGridItemSG*>(currentItem)->rowPos();
810 if (isRightToLeftTopToBottom())
811 pos = -pos-size(); // Transform Pos if required
812 if (pos < currPos + rowSize() - highlightEnd)
813 pos = currPos + rowSize() - highlightEnd;
814 if (pos > currPos - highlightStart)
815 pos = currPos - highlightStart;
816 if (isRightToLeftTopToBottom())
817 pos = -pos-size(); // Untransform
820 qreal dist = qAbs(data.move + pos);
822 timeline.reset(data.move);
823 if (fixupMode != Immediate) {
824 timeline.move(data.move, -pos, QEasingCurve(QEasingCurve::InOutQuad), fixupDuration/2);
825 data.fixingUp = true;
827 timeline.set(data.move, -pos);
829 vTime = timeline.time();
831 } else if (haveHighlightRange && highlightRange == QSGGridView::StrictlyEnforceRange) {
834 qreal pos = static_cast<FxGridItemSG*>(currentItem)->rowPos();
835 if (viewPos < pos + rowSize() - highlightEnd)
836 viewPos = pos + rowSize() - highlightEnd;
837 if (viewPos > pos - highlightStart)
838 viewPos = pos - highlightStart;
839 if (isRightToLeftTopToBottom())
840 viewPos = -viewPos-size();
841 timeline.reset(data.move);
842 if (viewPos != position()) {
843 if (fixupMode != Immediate) {
844 timeline.move(data.move, -viewPos, QEasingCurve(QEasingCurve::InOutQuad), fixupDuration/2);
845 data.fixingUp = true;
847 timeline.set(data.move, -viewPos);
850 vTime = timeline.time();
853 QSGItemViewPrivate::fixup(data, minExtent, maxExtent);
855 data.inOvershoot = false;
859 void QSGGridViewPrivate::flick(AxisData &data, qreal minExtent, qreal maxExtent, qreal vSize,
860 QDeclarativeTimeLineCallback::Callback fixupCallback, qreal velocity)
863 data.fixingUp = false;
865 if ((!haveHighlightRange || highlightRange != QSGGridView::StrictlyEnforceRange)
866 && snapMode == QSGGridView::NoSnap) {
867 QSGItemViewPrivate::flick(data, minExtent, maxExtent, vSize, fixupCallback, velocity);
870 qreal maxDistance = 0;
871 qreal dataValue = isRightToLeftTopToBottom() ? -data.move.value()+size() : data.move.value();
872 // -ve velocity means list is moving up/left
874 if (data.move.value() < minExtent) {
875 if (snapMode == QSGGridView::SnapOneRow) {
876 if (FxViewItem *item = firstVisibleItem())
877 maxDistance = qAbs(item->position() + dataValue);
879 maxDistance = qAbs(minExtent - data.move.value());
882 if (snapMode == QSGGridView::NoSnap && highlightRange != QSGGridView::StrictlyEnforceRange)
883 data.flickTarget = minExtent;
885 if (data.move.value() > maxExtent) {
886 if (snapMode == QSGGridView::SnapOneRow) {
887 qreal pos = snapPosAt(-dataValue) + (isRightToLeftTopToBottom() ? 0 : rowSize());
888 maxDistance = qAbs(pos + dataValue);
890 maxDistance = qAbs(maxExtent - data.move.value());
893 if (snapMode == QSGGridView::NoSnap && highlightRange != QSGGridView::StrictlyEnforceRange)
894 data.flickTarget = maxExtent;
896 bool overShoot = boundsBehavior == QSGFlickable::DragAndOvershootBounds;
897 qreal highlightStart = isRightToLeftTopToBottom() && highlightRangeStartValid ? size()-highlightRangeEnd : highlightRangeStart;
898 if (maxDistance > 0 || overShoot) {
899 // This mode requires the grid to stop exactly on a row boundary.
901 if (maxVelocity != -1 && maxVelocity < qAbs(v)) {
907 qreal accel = deceleration;
909 qreal overshootDist = 0.0;
910 if ((maxDistance > 0.0 && v2 / (2.0f * maxDistance) < accel) || snapMode == QSGGridView::SnapOneRow) {
911 // + rowSize()/4 to encourage moving at least one item in the flick direction
912 qreal dist = v2 / (accel * 2.0) + rowSize()/4;
913 dist = qMin(dist, maxDistance);
916 qreal distTemp = isRightToLeftTopToBottom() ? -dist : dist;
917 data.flickTarget = -snapPosAt(-(dataValue - highlightStart) + distTemp) + highlightStart;
918 data.flickTarget = isRightToLeftTopToBottom() ? -data.flickTarget+size() : data.flickTarget;
919 qreal adjDist = -data.flickTarget + data.move.value();
920 if (qAbs(adjDist) > qAbs(dist)) {
921 // Prevent painfully slow flicking - adjust velocity to suit flickDeceleration
922 qreal adjv2 = accel * 2.0f * qAbs(adjDist);
931 accel = v2 / (2.0f * qAbs(dist));
933 data.flickTarget = velocity > 0 ? minExtent : maxExtent;
934 overshootDist = overShoot ? overShootDistance(vSize) : 0;
936 timeline.reset(data.move);
937 timeline.accel(data.move, v, accel, maxDistance + overshootDist);
938 timeline.callback(QDeclarativeTimeLineCallback(&data.move, fixupCallback, this));
939 if (!flickingHorizontally && q->xflick()) {
940 flickingHorizontally = true;
941 emit q->flickingChanged();
942 emit q->flickingHorizontallyChanged();
943 emit q->flickStarted();
945 if (!flickingVertically && q->yflick()) {
946 flickingVertically = true;
947 emit q->flickingChanged();
948 emit q->flickingVerticallyChanged();
949 emit q->flickStarted();
952 timeline.reset(data.move);
953 fixup(data, minExtent, maxExtent);
958 //----------------------------------------------------------------------------
960 QSGGridView::QSGGridView(QSGItem *parent)
961 : QSGItemView(*(new QSGGridViewPrivate), parent)
965 QSGGridView::~QSGGridView()
969 void QSGGridView::setHighlightFollowsCurrentItem(bool autoHighlight)
972 if (d->autoHighlight != autoHighlight) {
973 if (!autoHighlight && d->highlightXAnimator) {
974 d->highlightXAnimator->stop();
975 d->highlightYAnimator->stop();
977 QSGItemView::setHighlightFollowsCurrentItem(autoHighlight);
981 void QSGGridView::setHighlightMoveDuration(int duration)
984 if (d->highlightMoveDuration != duration) {
985 if (d->highlightYAnimator) {
986 d->highlightXAnimator->userDuration = duration;
987 d->highlightYAnimator->userDuration = duration;
989 QSGItemView::setHighlightMoveDuration(duration);
993 QSGGridView::Flow QSGGridView::flow() const
995 Q_D(const QSGGridView);
999 void QSGGridView::setFlow(Flow flow)
1002 if (d->flow != flow) {
1004 if (d->flow == LeftToRight) {
1005 setContentWidth(-1);
1006 setFlickableDirection(VerticalFlick);
1008 setContentHeight(-1);
1009 setFlickableDirection(HorizontalFlick);
1019 int QSGGridView::cellWidth() const
1021 Q_D(const QSGGridView);
1022 return d->cellWidth;
1025 void QSGGridView::setCellWidth(int cellWidth)
1028 if (cellWidth != d->cellWidth && cellWidth > 0) {
1029 d->cellWidth = qMax(1, cellWidth);
1030 d->updateViewport();
1031 emit cellWidthChanged();
1036 int QSGGridView::cellHeight() const
1038 Q_D(const QSGGridView);
1039 return d->cellHeight;
1042 void QSGGridView::setCellHeight(int cellHeight)
1045 if (cellHeight != d->cellHeight && cellHeight > 0) {
1046 d->cellHeight = qMax(1, cellHeight);
1047 d->updateViewport();
1048 emit cellHeightChanged();
1053 QSGGridView::SnapMode QSGGridView::snapMode() const
1055 Q_D(const QSGGridView);
1059 void QSGGridView::setSnapMode(SnapMode mode)
1062 if (d->snapMode != mode) {
1064 emit snapModeChanged();
1069 void QSGGridView::viewportMoved()
1072 QSGItemView::viewportMoved();
1075 if (d->inViewportMoved)
1077 d->inViewportMoved = true;
1079 d->lazyRelease = true;
1080 if (d->flickingHorizontally || d->flickingVertically) {
1082 if (d->vData.velocity > 0)
1083 d->bufferMode = QSGGridViewPrivate::BufferBefore;
1084 else if (d->vData.velocity < 0)
1085 d->bufferMode = QSGGridViewPrivate::BufferAfter;
1089 if (d->hData.velocity > 0)
1090 d->bufferMode = QSGGridViewPrivate::BufferBefore;
1091 else if (d->hData.velocity < 0)
1092 d->bufferMode = QSGGridViewPrivate::BufferAfter;
1096 if (d->flickingHorizontally || d->flickingVertically || d->movingHorizontally || d->movingVertically)
1097 d->moveReason = QSGGridViewPrivate::Mouse;
1098 if (d->moveReason != QSGGridViewPrivate::SetIndex) {
1099 if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange && d->highlight) {
1100 // reposition highlight
1101 qreal pos = d->highlight->position();
1103 qreal highlightStart;
1105 if (d->isRightToLeftTopToBottom()) {
1106 viewPos = -d->position()-d->size();
1107 highlightStart = d->highlightRangeStartValid ? d->size()-d->highlightRangeEnd : d->highlightRangeStart;
1108 highlightEnd = d->highlightRangeEndValid ? d->size()-d->highlightRangeStart : d->highlightRangeEnd;
1110 viewPos = d->position();
1111 highlightStart = d->highlightRangeStart;
1112 highlightEnd = d->highlightRangeEnd;
1114 if (pos > viewPos + highlightEnd - d->highlight->size())
1115 pos = viewPos + highlightEnd - d->highlight->size();
1116 if (pos < viewPos + highlightStart)
1117 pos = viewPos + highlightStart;
1119 if (pos != d->highlight->position()) {
1120 d->highlightXAnimator->stop();
1121 d->highlightYAnimator->stop();
1122 static_cast<FxGridItemSG*>(d->highlight)->setPosition(static_cast<FxGridItemSG*>(d->highlight)->colPos(), pos);
1124 d->updateHighlight();
1127 // update current index
1128 int idx = d->snapIndex();
1129 if (idx >= 0 && idx != d->currentIndex) {
1130 d->updateCurrent(idx);
1131 if (d->currentItem && static_cast<FxGridItemSG*>(d->currentItem)->colPos() != static_cast<FxGridItemSG*>(d->highlight)->colPos() && d->autoHighlight) {
1132 if (d->flow == LeftToRight)
1133 d->highlightXAnimator->to = d->currentItem->item->x();
1135 d->highlightYAnimator->to = d->currentItem->item->y();
1141 d->inViewportMoved = false;
1144 void QSGGridView::keyPressEvent(QKeyEvent *event)
1147 if (d->model && d->model->count() && d->interactive) {
1148 d->moveReason = QSGGridViewPrivate::SetIndex;
1149 int oldCurrent = currentIndex();
1150 switch (event->key()) {
1152 moveCurrentIndexUp();
1155 moveCurrentIndexDown();
1158 moveCurrentIndexLeft();
1161 moveCurrentIndexRight();
1166 if (oldCurrent != currentIndex()) {
1172 QSGItemView::keyPressEvent(event);
1175 void QSGGridView::moveCurrentIndexUp()
1178 const int count = d->model ? d->model->count() : 0;
1181 if (d->flow == QSGGridView::LeftToRight) {
1182 if (currentIndex() >= d->columns || d->wrap) {
1183 int index = currentIndex() - d->columns;
1184 setCurrentIndex((index >= 0 && index < count) ? index : count-1);
1187 if (currentIndex() > 0 || d->wrap) {
1188 int index = currentIndex() - 1;
1189 setCurrentIndex((index >= 0 && index < count) ? index : count-1);
1194 void QSGGridView::moveCurrentIndexDown()
1197 const int count = d->model ? d->model->count() : 0;
1200 if (d->flow == QSGGridView::LeftToRight) {
1201 if (currentIndex() < count - d->columns || d->wrap) {
1202 int index = currentIndex()+d->columns;
1203 setCurrentIndex((index >= 0 && index < count) ? index : 0);
1206 if (currentIndex() < count - 1 || d->wrap) {
1207 int index = currentIndex() + 1;
1208 setCurrentIndex((index >= 0 && index < count) ? index : 0);
1213 void QSGGridView::moveCurrentIndexLeft()
1216 const int count = d->model ? d->model->count() : 0;
1219 if (effectiveLayoutDirection() == Qt::LeftToRight) {
1220 if (d->flow == QSGGridView::LeftToRight) {
1221 if (currentIndex() > 0 || d->wrap) {
1222 int index = currentIndex() - 1;
1223 setCurrentIndex((index >= 0 && index < count) ? index : count-1);
1226 if (currentIndex() >= d->columns || d->wrap) {
1227 int index = currentIndex() - d->columns;
1228 setCurrentIndex((index >= 0 && index < count) ? index : count-1);
1232 if (d->flow == QSGGridView::LeftToRight) {
1233 if (currentIndex() < count - 1 || d->wrap) {
1234 int index = currentIndex() + 1;
1235 setCurrentIndex((index >= 0 && index < count) ? index : 0);
1238 if (currentIndex() < count - d->columns || d->wrap) {
1239 int index = currentIndex() + d->columns;
1240 setCurrentIndex((index >= 0 && index < count) ? index : 0);
1246 void QSGGridView::moveCurrentIndexRight()
1249 const int count = d->model ? d->model->count() : 0;
1252 if (effectiveLayoutDirection() == Qt::LeftToRight) {
1253 if (d->flow == QSGGridView::LeftToRight) {
1254 if (currentIndex() < count - 1 || d->wrap) {
1255 int index = currentIndex() + 1;
1256 setCurrentIndex((index >= 0 && index < count) ? index : 0);
1259 if (currentIndex() < count - d->columns || d->wrap) {
1260 int index = currentIndex()+d->columns;
1261 setCurrentIndex((index >= 0 && index < count) ? index : 0);
1265 if (d->flow == QSGGridView::LeftToRight) {
1266 if (currentIndex() > 0 || d->wrap) {
1267 int index = currentIndex() - 1;
1268 setCurrentIndex((index >= 0 && index < count) ? index : count-1);
1271 if (currentIndex() >= d->columns || d->wrap) {
1272 int index = currentIndex() - d->columns;
1273 setCurrentIndex((index >= 0 && index < count) ? index : count-1);
1280 void QSGGridView::itemsInserted(int modelIndex, int count)
1283 if (!isComponentComplete() || !d->model || !d->model->isValid())
1286 int index = d->visibleItems.count() ? d->mapFromModel(modelIndex) : 0;
1288 int i = d->visibleItems.count() - 1;
1289 while (i > 0 && d->visibleItems.at(i)->index == -1)
1291 if (d->visibleItems.at(i)->index + 1 == modelIndex) {
1292 // Special case of appending an item to the model.
1293 index = d->visibleIndex + d->visibleItems.count();
1295 if (modelIndex <= d->visibleIndex) {
1296 // Insert before visible items
1297 d->visibleIndex += count;
1298 for (int i = 0; i < d->visibleItems.count(); ++i) {
1299 FxViewItem *item = d->visibleItems.at(i);
1300 if (item->index != -1 && item->index >= modelIndex)
1301 item->index += count;
1304 if (d->currentIndex >= modelIndex) {
1305 // adjust current item index
1306 d->currentIndex += count;
1308 d->currentItem->index = d->currentIndex;
1309 emit currentIndexChanged();
1311 d->scheduleLayout();
1312 d->itemCount += count;
1313 emit countChanged();
1318 int insertCount = count;
1319 if (index < d->visibleIndex && d->visibleItems.count()) {
1320 insertCount -= d->visibleIndex - index;
1321 index = d->visibleIndex;
1322 modelIndex = d->visibleIndex;
1325 qreal tempPos = d->isRightToLeftTopToBottom() ? -d->position()-d->size()+width()+1 : d->position();
1326 int to = d->buffer+tempPos+d->size()-1;
1329 if (d->visibleItems.count()) {
1330 index -= d->visibleIndex;
1331 if (index < d->visibleItems.count()) {
1332 FxGridItemSG *gridItem = static_cast<FxGridItemSG*>(d->visibleItems.at(index));
1333 colPos = gridItem->colPos();
1334 rowPos = gridItem->rowPos();
1336 // appending items to visible list
1337 FxGridItemSG *gridItem = static_cast<FxGridItemSG*>(d->visibleItems.at(index-1));
1338 colPos = gridItem->colPos() + d->colSize();
1339 rowPos = gridItem->rowPos();
1340 if (colPos > d->colSize() * (d->columns-1)) {
1342 rowPos += d->rowSize();
1347 // Update the indexes of the following visible items.
1348 for (int i = 0; i < d->visibleItems.count(); ++i) {
1349 FxViewItem *item = d->visibleItems.at(i);
1350 if (item->index != -1 && item->index >= modelIndex)
1351 item->index += count;
1354 bool addedVisible = false;
1355 QList<FxGridItemSG*> added;
1357 while (i < insertCount && rowPos <= to + d->rowSize()*(d->columns - (colPos/d->colSize()))/qreal(d->columns)) {
1358 if (!addedVisible) {
1359 d->scheduleLayout();
1360 addedVisible = true;
1362 FxGridItemSG *item = static_cast<FxGridItemSG*>(d->createItem(modelIndex + i));
1363 d->visibleItems.insert(index, item);
1364 item->setPosition(colPos, rowPos);
1366 colPos += d->colSize();
1367 if (colPos > d->colSize() * (d->columns-1)) {
1369 rowPos += d->rowSize();
1374 if (i < insertCount) {
1375 // We didn't insert all our new items, which means anything
1376 // beyond the current index is not visible - remove it.
1377 while (d->visibleItems.count() > index) {
1378 d->releaseItem(d->visibleItems.takeLast());
1382 // update visibleIndex
1383 d->visibleIndex = 0;
1384 for (QList<FxViewItem*>::Iterator it = d->visibleItems.begin(); it != d->visibleItems.end(); ++it) {
1385 if ((*it)->index != -1) {
1386 d->visibleIndex = (*it)->index;
1391 if (d->itemCount && d->currentIndex >= modelIndex) {
1392 // adjust current item index
1393 d->currentIndex += count;
1394 if (d->currentItem) {
1395 d->currentItem->index = d->currentIndex;
1396 static_cast<FxGridItemSG*>(d->currentItem)->setPosition(d->colPosAt(d->currentIndex), d->rowPosAt(d->currentIndex));
1398 emit currentIndexChanged();
1399 } else if (d->itemCount == 0 && (!d->currentIndex || (d->currentIndex < 0 && !d->currentIndexCleared))) {
1403 // everything is in order now - emit add() signal
1404 for (int j = 0; j < added.count(); ++j)
1405 added.at(j)->attached->emitAdd();
1407 d->itemCount += count;
1408 emit countChanged();
1411 void QSGGridView::itemsRemoved(int modelIndex, int count)
1414 if (!isComponentComplete() || !d->model || !d->model->isValid())
1417 d->itemCount -= count;
1418 bool currentRemoved = d->currentIndex >= modelIndex && d->currentIndex < modelIndex + count;
1419 bool removedVisible = false;
1421 // Remove the items from the visible list, skipping anything already marked for removal
1422 QList<FxViewItem*>::Iterator it = d->visibleItems.begin();
1423 while (it != d->visibleItems.end()) {
1424 FxViewItem *item = *it;
1425 if (item->index == -1 || item->index < modelIndex) {
1426 // already removed, or before removed items
1427 if (item->index < modelIndex && !removedVisible) {
1428 d->scheduleLayout();
1429 removedVisible = true;
1432 } else if (item->index >= modelIndex + count) {
1433 // after removed items
1434 item->index -= count;
1438 if (!removedVisible) {
1439 d->scheduleLayout();
1440 removedVisible = true;
1442 item->attached->emitRemove();
1443 if (item->attached->delayRemove()) {
1445 connect(item->attached, SIGNAL(delayRemoveChanged()), this, SLOT(destroyRemoved()), Qt::QueuedConnection);
1448 it = d->visibleItems.erase(it);
1449 d->releaseItem(item);
1454 // update visibleIndex
1455 d->visibleIndex = 0;
1456 for (it = d->visibleItems.begin(); it != d->visibleItems.end(); ++it) {
1457 if ((*it)->index != -1) {
1458 d->visibleIndex = (*it)->index;
1464 if (d->currentIndex >= modelIndex + count) {
1465 d->currentIndex -= count;
1467 d->currentItem->index -= count;
1468 emit currentIndexChanged();
1469 } else if (currentRemoved) {
1470 // current item has been removed.
1471 d->releaseItem(d->currentItem);
1473 d->currentIndex = -1;
1475 d->updateCurrent(qMin(modelIndex, d->itemCount-1));
1477 emit currentIndexChanged();
1480 if (removedVisible && d->visibleItems.isEmpty()) {
1481 d->timeline.clear();
1482 if (d->itemCount == 0) {
1483 d->setPosition(d->contentStartPosition());
1489 emit countChanged();
1493 void QSGGridView::itemsMoved(int from, int to, int count)
1496 if (!isComponentComplete() || !d->isValid())
1498 d->updateUnrequestedIndexes();
1500 if (d->visibleItems.isEmpty()) {
1505 d->moveReason = QSGGridViewPrivate::Other;
1507 bool movingBackwards = from > to;
1508 d->adjustMoveParameters(&from, &to, &count);
1510 QHash<int,FxGridItemSG*> moved;
1511 int moveByCount = 0;
1512 FxGridItemSG *firstVisible = static_cast<FxGridItemSG*>(d->firstVisibleItem());
1513 int firstItemIndex = firstVisible ? firstVisible->index : -1;
1515 // if visibleItems.first() is above the content start pos, and the items
1516 // beneath it are moved, ensure this first item is later repositioned correctly
1517 // (to above the next visible item) so that subsequent layout() is correct
1518 bool repositionFirstItem = firstVisible
1519 && d->visibleItems.first()->position() < firstVisible->position()
1520 && from > d->visibleItems.first()->index;
1522 QList<FxViewItem*>::Iterator it = d->visibleItems.begin();
1523 while (it != d->visibleItems.end()) {
1524 FxViewItem *item = *it;
1525 if (item->index >= from && item->index < from + count) {
1526 // take the items that are moving
1527 item->index += (to-from);
1528 moved.insert(item->index, static_cast<FxGridItemSG*>(item));
1529 if (repositionFirstItem)
1531 it = d->visibleItems.erase(it);
1533 if (item->index > from && item->index != -1) {
1534 // move everything after the moved items.
1535 item->index -= count;
1536 if (item->index < d->visibleIndex)
1537 d->visibleIndex = item->index;
1544 int endIndex = d->visibleIndex;
1545 it = d->visibleItems.begin();
1546 while (it != d->visibleItems.end()) {
1547 FxViewItem *item = *it;
1548 if (movedCount < count && item->index >= to && item->index < to + count) {
1549 // place items in the target position, reusing any existing items
1550 int targetIndex = item->index + movedCount;
1551 FxGridItemSG *movedItem = moved.take(targetIndex);
1553 movedItem = static_cast<FxGridItemSG*>(d->createItem(targetIndex));
1554 it = d->visibleItems.insert(it, movedItem);
1558 if (item->index != -1) {
1559 if (item->index >= to) {
1560 // update everything after the moved items.
1561 item->index += count;
1563 endIndex = item->index;
1569 // If we have moved items to the end of the visible items
1570 // then add any existing moved items that we have
1571 while (FxGridItemSG *item = moved.take(endIndex+1)) {
1572 d->visibleItems.append(item);
1576 // update visibleIndex
1577 for (it = d->visibleItems.begin(); it != d->visibleItems.end(); ++it) {
1578 if ((*it)->index != -1) {
1579 d->visibleIndex = (*it)->index;
1584 // if first visible item is moving but another item is moving up to replace it,
1585 // do this positioning now to avoid shifting all content forwards
1586 if (movingBackwards && firstItemIndex >= 0) {
1587 for (it = d->visibleItems.begin(); it != d->visibleItems.end(); ++it) {
1588 if ((*it)->index == firstItemIndex) {
1589 static_cast<FxGridItemSG*>(*it)->setPosition(firstVisible->colPos(),
1590 firstVisible->rowPos());
1596 // Fix current index
1597 if (d->currentIndex >= 0 && d->currentItem) {
1598 int oldCurrent = d->currentIndex;
1599 d->currentIndex = d->model->indexOf(d->currentItem->item, this);
1600 if (oldCurrent != d->currentIndex) {
1601 d->currentItem->index = d->currentIndex;
1602 emit currentIndexChanged();
1606 // Whatever moved items remain are no longer visible items.
1607 while (moved.count()) {
1608 int idx = moved.begin().key();
1609 FxGridItemSG *item = moved.take(idx);
1610 if (d->currentItem && item->item == d->currentItem->item)
1611 item->setPosition(d->colPosAt(idx), d->rowPosAt(idx));
1612 d->releaseItem(item);
1615 // Ensure we don't cause an ugly list scroll.
1616 if (d->visibleItems.count() && moveByCount > 0) {
1617 FxGridItemSG *first = static_cast<FxGridItemSG*>(d->visibleItems.first());
1618 first->setPosition(first->colPos(), first->rowPos() + ((moveByCount / d->columns) * d->rowSize()));
1625 QSGGridViewAttached *QSGGridView::qmlAttachedProperties(QObject *obj)
1627 return new QSGGridViewAttached(obj);