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 bool showHeaderForIndex(int index) const;
180 virtual bool showFooterForIndex(int index) const;
181 virtual void updateHeader();
182 virtual void updateFooter();
184 virtual void changedVisibleIndex(int newIndex);
185 virtual void initializeCurrentItem();
187 virtual void updateViewport();
188 virtual void itemGeometryChanged(QSGItem *item, const QRectF &newGeometry, const QRectF &oldGeometry);
189 virtual void fixupPosition();
190 virtual void fixup(AxisData &data, qreal minExtent, qreal maxExtent);
191 virtual void flick(QSGItemViewPrivate::AxisData &data, qreal minExtent, qreal maxExtent, qreal vSize,
192 QDeclarativeTimeLineCallback::Callback fixupCallback, qreal velocity);
194 QSGGridView::Flow flow;
198 QSGGridView::SnapMode snapMode;
200 QSmoothedAnimation *highlightXAnimator;
201 QSmoothedAnimation *highlightYAnimator;
204 : flow(QSGGridView::LeftToRight)
205 , cellWidth(100), cellHeight(100), columns(1)
206 , snapMode(QSGGridView::NoSnap)
207 , highlightXAnimator(0), highlightYAnimator(0)
211 Qt::Orientation QSGGridViewPrivate::layoutOrientation() const
213 return flow == QSGGridView::LeftToRight ? Qt::Vertical : Qt::Horizontal;
216 bool QSGGridViewPrivate::isContentFlowReversed() const
218 return isRightToLeftTopToBottom();
221 bool QSGGridViewPrivate::isRightToLeftTopToBottom() const
223 Q_Q(const QSGGridView);
224 return flow == QSGGridView::TopToBottom && q->effectiveLayoutDirection() == Qt::RightToLeft;
227 void QSGGridViewPrivate::changedVisibleIndex(int newIndex)
229 visibleIndex = newIndex / columns * columns;
232 void QSGGridViewPrivate::setPosition(qreal pos)
235 if (flow == QSGGridView::LeftToRight) {
236 q->QSGFlickable::setContentY(pos);
237 q->QSGFlickable::setContentX(0);
239 if (q->effectiveLayoutDirection() == Qt::LeftToRight)
240 q->QSGFlickable::setContentX(pos);
242 q->QSGFlickable::setContentX(-pos-size());
243 q->QSGFlickable::setContentY(0);
247 qreal QSGGridViewPrivate::originPosition() const
250 if (!visibleItems.isEmpty())
251 pos = static_cast<FxGridItemSG*>(visibleItems.first())->rowPos() - visibleIndex / columns * rowSize();
255 qreal QSGGridViewPrivate::lastPosition() const
258 if (model && model->count()) {
259 // get end position of last item
260 pos = (rowPosAt(model->count() - 1) + rowSize());
265 qreal QSGGridViewPrivate::positionAt(int index) const
267 return rowPosAt(index);
270 qreal QSGGridViewPrivate::endPositionAt(int index) const
272 return rowPosAt(index) + rowSize();
275 int QSGGridViewPrivate::rowSize() const {
276 return flow == QSGGridView::LeftToRight ? cellHeight : cellWidth;
278 int QSGGridViewPrivate::colSize() const {
279 return flow == QSGGridView::LeftToRight ? cellWidth : cellHeight;
282 qreal QSGGridViewPrivate::colPosAt(int modelIndex) const
284 if (FxViewItem *item = visibleItem(modelIndex))
285 return static_cast<FxGridItemSG*>(item)->colPos();
286 if (!visibleItems.isEmpty()) {
287 if (modelIndex < visibleIndex) {
288 int count = (visibleIndex - modelIndex) % columns;
289 int col = static_cast<FxGridItemSG*>(visibleItems.first())->colPos() / colSize();
290 col = (columns - count + col) % columns;
291 return col * colSize();
293 int count = columns - 1 - (modelIndex - visibleItems.last()->index - 1) % columns;
294 return static_cast<FxGridItemSG*>(visibleItems.last())->colPos() - count * colSize();
297 return (modelIndex % columns) * colSize();
300 qreal QSGGridViewPrivate::rowPosAt(int modelIndex) const
302 if (FxViewItem *item = visibleItem(modelIndex))
303 return static_cast<FxGridItemSG*>(item)->rowPos();
304 if (!visibleItems.isEmpty()) {
305 if (modelIndex < visibleIndex) {
306 FxGridItemSG *firstItem = static_cast<FxGridItemSG*>(visibleItems.first());
307 int firstCol = firstItem->colPos() / colSize();
308 int col = visibleIndex - modelIndex + (columns - firstCol - 1);
309 int rows = col / columns;
310 return firstItem->rowPos() - rows * rowSize();
312 FxGridItemSG *lastItem = static_cast<FxGridItemSG*>(visibleItems.last());
313 int count = modelIndex - lastItem->index;
314 int col = lastItem->colPos() + count * colSize();
315 int rows = col / (columns * colSize());
316 return lastItem->rowPos() + rows * rowSize();
319 return (modelIndex / columns) * rowSize();
323 qreal QSGGridViewPrivate::snapPosAt(qreal pos) const
325 Q_Q(const QSGGridView);
327 if (!visibleItems.isEmpty()) {
329 snapPos = static_cast<FxGridItemSG*>(visibleItems.first())->rowPos() - visibleIndex / columns * rowSize();
330 snapPos = pos - fmodf(pos - snapPos, qreal(rowSize()));
333 if (isRightToLeftTopToBottom()) {
334 maxExtent = q->minXExtent();
335 minExtent = q->maxXExtent();
337 maxExtent = flow == QSGGridView::LeftToRight ? -q->maxYExtent() : -q->maxXExtent();
338 minExtent = flow == QSGGridView::LeftToRight ? -q->minYExtent() : -q->minXExtent();
340 if (snapPos > maxExtent)
342 if (snapPos < minExtent)
348 FxViewItem *QSGGridViewPrivate::snapItemAt(qreal pos) const
350 for (int i = 0; i < visibleItems.count(); ++i) {
351 FxViewItem *item = visibleItems.at(i);
352 if (item->index == -1)
354 qreal itemTop = item->position();
355 if (itemTop+rowSize()/2 >= pos && itemTop - rowSize()/2 <= pos)
361 int QSGGridViewPrivate::snapIndex() const
363 int index = currentIndex;
364 for (int i = 0; i < visibleItems.count(); ++i) {
365 FxGridItemSG *item = static_cast<FxGridItemSG*>(visibleItems.at(i));
366 if (item->index == -1)
368 qreal itemTop = item->position();
369 FxGridItemSG *hItem = static_cast<FxGridItemSG*>(highlight);
370 if (itemTop >= hItem->rowPos()-rowSize()/2 && itemTop < hItem->rowPos()+rowSize()/2) {
372 if (item->colPos() >= hItem->colPos()-colSize()/2 && item->colPos() < hItem->colPos()+colSize()/2)
379 FxViewItem *QSGGridViewPrivate::newViewItem(int modelIndex, QSGItem *item)
382 Q_UNUSED(modelIndex);
383 return new FxGridItemSG(item, q, false);
386 bool QSGGridViewPrivate::addVisibleItems(int fillFrom, int fillTo, bool doBuffer)
388 int colPos = colPosAt(visibleIndex);
389 int rowPos = rowPosAt(visibleIndex);
390 if (visibleItems.count()) {
391 FxGridItemSG *lastItem = static_cast<FxGridItemSG*>(visibleItems.last());
392 rowPos = lastItem->rowPos();
393 colPos = lastItem->colPos() + colSize();
394 if (colPos > colSize() * (columns-1)) {
400 int modelIndex = findLastVisibleIndex();
401 modelIndex = modelIndex < 0 ? visibleIndex : modelIndex + 1;
403 if (visibleItems.count() && (fillFrom > rowPos + rowSize()*2
404 || fillTo < rowPosAt(visibleIndex) - rowSize())) {
405 // We've jumped more than a page. Estimate which items are now
406 // visible and fill from there.
407 int count = (fillFrom - (rowPos + rowSize())) / (rowSize()) * columns;
408 for (int i = 0; i < visibleItems.count(); ++i)
409 releaseItem(visibleItems.at(i));
410 visibleItems.clear();
412 if (modelIndex >= model->count())
413 modelIndex = model->count() - 1;
414 else if (modelIndex < 0)
416 modelIndex = modelIndex / columns * columns;
417 visibleIndex = modelIndex;
418 colPos = colPosAt(visibleIndex);
419 rowPos = rowPosAt(visibleIndex);
422 int colNum = colPos / colSize();
423 FxGridItemSG *item = 0;
424 bool changed = false;
426 while (modelIndex < model->count() && rowPos <= fillTo + rowSize()*(columns - colNum)/(columns+1)) {
427 // qDebug() << "refill: append item" << modelIndex;
428 if (!(item = static_cast<FxGridItemSG*>(createItem(modelIndex))))
430 item->setPosition(colPos, rowPos);
431 visibleItems.append(item);
434 if (colPos > colSize() * (columns-1)) {
441 if (doBuffer) // never buffer more than one item per frame
445 if (visibleItems.count()) {
446 FxGridItemSG *firstItem = static_cast<FxGridItemSG*>(visibleItems.first());
447 rowPos = firstItem->rowPos();
448 colPos = firstItem->colPos() - colSize();
450 colPos = colSize() * (columns - 1);
455 colNum = colPos / colSize();
456 while (visibleIndex > 0 && rowPos + rowSize() - 1 >= fillFrom - rowSize()*(colNum+1)/(columns+1)){
457 // qDebug() << "refill: prepend item" << visibleIndex-1 << "top pos" << rowPos << colPos;
458 if (!(item = static_cast<FxGridItemSG*>(createItem(visibleIndex-1))))
461 item->setPosition(colPos, rowPos);
462 visibleItems.prepend(item);
466 colPos = colSize() * (columns - 1);
471 if (doBuffer) // never buffer more than one item per frame
478 bool QSGGridViewPrivate::removeNonVisibleItems(int bufferFrom, int bufferTo)
480 FxGridItemSG *item = 0;
481 bool changed = false;
483 while (visibleItems.count() > 1
484 && (item = static_cast<FxGridItemSG*>(visibleItems.first()))
485 && item->rowPos()+rowSize()-1 < bufferFrom - rowSize()*(item->colPos()/colSize()+1)/(columns+1)) {
486 if (item->attached->delayRemove())
488 // qDebug() << "refill: remove first" << visibleIndex << "top end pos" << item->endRowPos();
489 if (item->index != -1)
491 visibleItems.removeFirst();
495 while (visibleItems.count() > 1
496 && (item = static_cast<FxGridItemSG*>(visibleItems.last()))
497 && item->rowPos() > bufferTo + rowSize()*(columns - item->colPos()/colSize())/(columns+1)) {
498 if (item->attached->delayRemove())
500 // qDebug() << "refill: remove last" << visibleIndex+visibleItems.count()-1;
501 visibleItems.removeLast();
509 void QSGGridViewPrivate::visibleItemsChanged()
516 void QSGGridViewPrivate::updateViewport()
519 columns = (int)qMax((flow == QSGGridView::LeftToRight ? q->width() : q->height()) / colSize(), qreal(1.));
520 QSGItemViewPrivate::updateViewport();
523 void QSGGridViewPrivate::layoutVisibleItems()
525 if (visibleItems.count()) {
526 FxGridItemSG *firstItem = static_cast<FxGridItemSG*>(visibleItems.first());
527 qreal rowPos = firstItem->rowPos();
528 qreal colPos = firstItem->colPos();
529 int col = visibleIndex % columns;
530 if (colPos != col * colSize()) {
531 colPos = col * colSize();
532 firstItem->setPosition(colPos, rowPos);
534 for (int i = 1; i < visibleItems.count(); ++i) {
535 FxGridItemSG *item = static_cast<FxGridItemSG*>(visibleItems.at(i));
537 if (colPos > colSize() * (columns-1)) {
541 item->setPosition(colPos, rowPos);
546 void QSGGridViewPrivate::repositionPackageItemAt(QSGItem *item, int index)
549 qreal pos = position();
550 if (flow == QSGGridView::LeftToRight) {
551 if (item->y() + item->height() > pos && item->y() < pos + q->height())
552 item->setPos(QPointF(colPosAt(index), rowPosAt(index)));
554 if (item->x() + item->width() > pos && item->x() < pos + q->width()) {
555 if (isRightToLeftTopToBottom())
556 item->setPos(QPointF(-rowPosAt(index)-item->width(), colPosAt(index)));
558 item->setPos(QPointF(rowPosAt(index), colPosAt(index)));
564 void QSGGridViewPrivate::createHighlight()
567 bool changed = false;
569 if (trackedItem == highlight)
574 delete highlightXAnimator;
575 delete highlightYAnimator;
576 highlightXAnimator = 0;
577 highlightYAnimator = 0;
583 QSGItem *item = createHighlightItem();
585 FxGridItemSG *newHighlight = new FxGridItemSG(item, q, true);
587 resetHighlightPosition();
588 highlightXAnimator = new QSmoothedAnimation(q);
589 highlightXAnimator->target = QDeclarativeProperty(item, QLatin1String("x"));
590 highlightXAnimator->userDuration = highlightMoveDuration;
591 highlightYAnimator = new QSmoothedAnimation(q);
592 highlightYAnimator->target = QDeclarativeProperty(item, QLatin1String("y"));
593 highlightYAnimator->userDuration = highlightMoveDuration;
595 highlight = newHighlight;
600 emit q->highlightItemChanged();
603 void QSGGridViewPrivate::updateHighlight()
605 if ((!currentItem && highlight) || (currentItem && !highlight))
607 bool strictHighlight = haveHighlightRange && highlightRange == QSGGridView::StrictlyEnforceRange;
608 if (currentItem && autoHighlight && highlight && (!strictHighlight || !pressed)) {
609 // auto-update highlight
610 highlightXAnimator->to = currentItem->item->x();
611 highlightYAnimator->to = currentItem->item->y();
612 highlight->item->setWidth(currentItem->item->width());
613 highlight->item->setHeight(currentItem->item->height());
615 highlightXAnimator->restart();
616 highlightYAnimator->restart();
621 void QSGGridViewPrivate::resetHighlightPosition()
623 if (highlight && currentItem) {
624 FxGridItemSG *cItem = static_cast<FxGridItemSG*>(currentItem);
625 static_cast<FxGridItemSG*>(highlight)->setPosition(cItem->colPos(), cItem->rowPos());
629 qreal QSGGridViewPrivate::headerSize() const
633 return flow == QSGGridView::LeftToRight ? header->item->height() : header->item->width();
636 qreal QSGGridViewPrivate::footerSize() const
640 return flow == QSGGridView::LeftToRight? footer->item->height() : footer->item->width();
643 bool QSGGridViewPrivate::showHeaderForIndex(int index) const
645 return index / columns == 0;
648 bool QSGGridViewPrivate::showFooterForIndex(int index) const
650 return index / columns == (model->count()-1) / columns;
653 void QSGGridViewPrivate::updateFooter()
656 bool created = false;
658 QSGItem *item = createComponentItem(footerComponent, true);
662 footer = new FxGridItemSG(item, q, true);
666 FxGridItemSG *gridItem = static_cast<FxGridItemSG*>(footer);
669 if (q->effectiveLayoutDirection() == Qt::RightToLeft) {
670 if (flow == QSGGridView::TopToBottom)
671 rowOffset = gridItem->item->width() - cellWidth;
673 colOffset = gridItem->item->width() - cellWidth;
675 if (visibleItems.count()) {
676 qreal endPos = lastPosition();
677 if (findLastVisibleIndex() == model->count()-1) {
678 gridItem->setPosition(colOffset, endPos + rowOffset);
680 qreal visiblePos = isRightToLeftTopToBottom() ? -position() : position() + size();
681 if (endPos <= visiblePos || gridItem->endPosition() <= endPos + rowOffset)
682 gridItem->setPosition(colOffset, endPos + rowOffset);
685 gridItem->setPosition(colOffset, rowOffset);
689 emit q->footerItemChanged();
692 void QSGGridViewPrivate::updateHeader()
695 bool created = false;
697 QSGItem *item = createComponentItem(headerComponent, true);
701 header = new FxGridItemSG(item, q, true);
705 FxGridItemSG *gridItem = static_cast<FxGridItemSG*>(header);
707 qreal rowOffset = -headerSize();
708 if (q->effectiveLayoutDirection() == Qt::RightToLeft) {
709 if (flow == QSGGridView::TopToBottom)
710 rowOffset += gridItem->item->width()-cellWidth;
712 colOffset = gridItem->item->width()-cellWidth;
714 if (visibleItems.count()) {
715 qreal startPos = originPosition();
716 if (visibleIndex == 0) {
717 gridItem->setPosition(colOffset, startPos + rowOffset);
719 qreal tempPos = isRightToLeftTopToBottom() ? -position()-size() : position();
720 qreal headerPos = isRightToLeftTopToBottom() ? gridItem->rowPos() + cellWidth - headerSize() : gridItem->rowPos();
721 if (tempPos <= startPos || headerPos > startPos + rowOffset)
722 gridItem->setPosition(colOffset, startPos + rowOffset);
725 if (isRightToLeftTopToBottom())
726 gridItem->setPosition(colOffset, rowOffset);
728 gridItem->setPosition(colOffset, -headerSize());
732 emit q->headerItemChanged();
735 void QSGGridViewPrivate::initializeCurrentItem()
737 if (currentItem && currentIndex >= 0) {
738 FxGridItemSG *gridItem = static_cast<FxGridItemSG*>(currentItem);
740 gridItem->setPosition(colPosAt(currentIndex), rowPosAt(currentIndex));
744 void QSGGridViewPrivate::itemGeometryChanged(QSGItem *item, const QRectF &newGeometry, const QRectF &oldGeometry)
747 QSGItemViewPrivate::itemGeometryChanged(item, newGeometry, oldGeometry);
748 if (!q->isComponentComplete())
751 if (newGeometry.height() != oldGeometry.height() || newGeometry.width() != oldGeometry.width()) {
758 void QSGGridViewPrivate::fixupPosition()
761 if (flow == QSGGridView::LeftToRight)
767 void QSGGridViewPrivate::fixup(AxisData &data, qreal minExtent, qreal maxExtent)
769 if ((flow == QSGGridView::TopToBottom && &data == &vData)
770 || (flow == QSGGridView::LeftToRight && &data == &hData))
773 fixupMode = moveReason == Mouse ? fixupMode : Immediate;
775 qreal highlightStart;
778 if (isRightToLeftTopToBottom()) {
779 // Handle Right-To-Left exceptions
780 viewPos = -position()-size();
781 highlightStart = highlightRangeStartValid ? size()-highlightRangeEnd : highlightRangeStart;
782 highlightEnd = highlightRangeEndValid ? size()-highlightRangeStart : highlightRangeEnd;
784 viewPos = position();
785 highlightStart = highlightRangeStart;
786 highlightEnd = highlightRangeEnd;
789 if (snapMode != QSGGridView::NoSnap) {
790 qreal tempPosition = isRightToLeftTopToBottom() ? -position()-size() : position();
791 FxViewItem *topItem = snapItemAt(tempPosition+highlightStart);
792 FxViewItem *bottomItem = snapItemAt(tempPosition+highlightEnd);
794 if (topItem && bottomItem && haveHighlightRange && highlightRange == QSGGridView::StrictlyEnforceRange) {
795 qreal topPos = qMin(topItem->position() - highlightStart, -maxExtent);
796 qreal bottomPos = qMax(bottomItem->position() - highlightEnd, -minExtent);
797 pos = qAbs(data.move + topPos) < qAbs(data.move + bottomPos) ? topPos : bottomPos;
798 } else if (topItem) {
801 headerPos = isRightToLeftTopToBottom() ? static_cast<FxGridItemSG*>(header)->rowPos() + cellWidth - headerSize() : static_cast<FxGridItemSG*>(header)->rowPos();
802 if (topItem->index == 0 && header && tempPosition+highlightStart < headerPos+headerSize()/2) {
803 pos = isRightToLeftTopToBottom() ? - headerPos + highlightStart - size() : headerPos - highlightStart;
805 if (isRightToLeftTopToBottom())
806 pos = qMax(qMin(-topItem->position() + highlightStart - size(), -maxExtent), -minExtent);
808 pos = qMax(qMin(topItem->position() - highlightStart, -maxExtent), -minExtent);
810 } else if (bottomItem) {
811 if (isRightToLeftTopToBottom())
812 pos = qMax(qMin(-bottomItem->position() + highlightStart - size(), -maxExtent), -minExtent);
814 pos = qMax(qMin(bottomItem->position() - highlightStart, -maxExtent), -minExtent);
816 QSGItemViewPrivate::fixup(data, minExtent, maxExtent);
819 if (currentItem && haveHighlightRange && highlightRange == QSGGridView::StrictlyEnforceRange) {
821 qreal currPos = static_cast<FxGridItemSG*>(currentItem)->rowPos();
822 if (isRightToLeftTopToBottom())
823 pos = -pos-size(); // Transform Pos if required
824 if (pos < currPos + rowSize() - highlightEnd)
825 pos = currPos + rowSize() - highlightEnd;
826 if (pos > currPos - highlightStart)
827 pos = currPos - highlightStart;
828 if (isRightToLeftTopToBottom())
829 pos = -pos-size(); // Untransform
832 qreal dist = qAbs(data.move + pos);
834 timeline.reset(data.move);
835 if (fixupMode != Immediate) {
836 timeline.move(data.move, -pos, QEasingCurve(QEasingCurve::InOutQuad), fixupDuration/2);
837 data.fixingUp = true;
839 timeline.set(data.move, -pos);
841 vTime = timeline.time();
843 } else if (haveHighlightRange && highlightRange == QSGGridView::StrictlyEnforceRange) {
846 qreal pos = static_cast<FxGridItemSG*>(currentItem)->rowPos();
847 if (viewPos < pos + rowSize() - highlightEnd)
848 viewPos = pos + rowSize() - highlightEnd;
849 if (viewPos > pos - highlightStart)
850 viewPos = pos - highlightStart;
851 if (isRightToLeftTopToBottom())
852 viewPos = -viewPos-size();
853 timeline.reset(data.move);
854 if (viewPos != position()) {
855 if (fixupMode != Immediate) {
856 timeline.move(data.move, -viewPos, QEasingCurve(QEasingCurve::InOutQuad), fixupDuration/2);
857 data.fixingUp = true;
859 timeline.set(data.move, -viewPos);
862 vTime = timeline.time();
865 QSGItemViewPrivate::fixup(data, minExtent, maxExtent);
867 data.inOvershoot = false;
871 void QSGGridViewPrivate::flick(AxisData &data, qreal minExtent, qreal maxExtent, qreal vSize,
872 QDeclarativeTimeLineCallback::Callback fixupCallback, qreal velocity)
875 data.fixingUp = false;
877 if ((!haveHighlightRange || highlightRange != QSGGridView::StrictlyEnforceRange)
878 && snapMode == QSGGridView::NoSnap) {
879 QSGItemViewPrivate::flick(data, minExtent, maxExtent, vSize, fixupCallback, velocity);
882 qreal maxDistance = 0;
883 qreal dataValue = isRightToLeftTopToBottom() ? -data.move.value()+size() : data.move.value();
884 // -ve velocity means list is moving up/left
886 if (data.move.value() < minExtent) {
887 if (snapMode == QSGGridView::SnapOneRow) {
888 if (FxViewItem *item = firstVisibleItem())
889 maxDistance = qAbs(item->position() + dataValue);
891 maxDistance = qAbs(minExtent - data.move.value());
894 if (snapMode == QSGGridView::NoSnap && highlightRange != QSGGridView::StrictlyEnforceRange)
895 data.flickTarget = minExtent;
897 if (data.move.value() > maxExtent) {
898 if (snapMode == QSGGridView::SnapOneRow) {
899 qreal pos = snapPosAt(-dataValue) + (isRightToLeftTopToBottom() ? 0 : rowSize());
900 maxDistance = qAbs(pos + dataValue);
902 maxDistance = qAbs(maxExtent - data.move.value());
905 if (snapMode == QSGGridView::NoSnap && highlightRange != QSGGridView::StrictlyEnforceRange)
906 data.flickTarget = maxExtent;
908 bool overShoot = boundsBehavior == QSGFlickable::DragAndOvershootBounds;
909 qreal highlightStart = isRightToLeftTopToBottom() && highlightRangeStartValid ? size()-highlightRangeEnd : highlightRangeStart;
910 if (maxDistance > 0 || overShoot) {
911 // This mode requires the grid to stop exactly on a row boundary.
913 if (maxVelocity != -1 && maxVelocity < qAbs(v)) {
919 qreal accel = deceleration;
921 qreal overshootDist = 0.0;
922 if ((maxDistance > 0.0 && v2 / (2.0f * maxDistance) < accel) || snapMode == QSGGridView::SnapOneRow) {
923 // + rowSize()/4 to encourage moving at least one item in the flick direction
924 qreal dist = v2 / (accel * 2.0) + rowSize()/4;
925 dist = qMin(dist, maxDistance);
928 qreal distTemp = isRightToLeftTopToBottom() ? -dist : dist;
929 data.flickTarget = -snapPosAt(-(dataValue - highlightStart) + distTemp) + highlightStart;
930 data.flickTarget = isRightToLeftTopToBottom() ? -data.flickTarget+size() : data.flickTarget;
931 qreal adjDist = -data.flickTarget + data.move.value();
932 if (qAbs(adjDist) > qAbs(dist)) {
933 // Prevent painfully slow flicking - adjust velocity to suit flickDeceleration
934 qreal adjv2 = accel * 2.0f * qAbs(adjDist);
943 accel = v2 / (2.0f * qAbs(dist));
945 data.flickTarget = velocity > 0 ? minExtent : maxExtent;
946 overshootDist = overShoot ? overShootDistance(vSize) : 0;
948 timeline.reset(data.move);
949 timeline.accel(data.move, v, accel, maxDistance + overshootDist);
950 timeline.callback(QDeclarativeTimeLineCallback(&data.move, fixupCallback, this));
951 if (!flickingHorizontally && q->xflick()) {
952 flickingHorizontally = true;
953 emit q->flickingChanged();
954 emit q->flickingHorizontallyChanged();
955 emit q->flickStarted();
957 if (!flickingVertically && q->yflick()) {
958 flickingVertically = true;
959 emit q->flickingChanged();
960 emit q->flickingVerticallyChanged();
961 emit q->flickStarted();
964 timeline.reset(data.move);
965 fixup(data, minExtent, maxExtent);
970 //----------------------------------------------------------------------------
972 QSGGridView::QSGGridView(QSGItem *parent)
973 : QSGItemView(*(new QSGGridViewPrivate), parent)
977 QSGGridView::~QSGGridView()
981 void QSGGridView::setHighlightFollowsCurrentItem(bool autoHighlight)
984 if (d->autoHighlight != autoHighlight) {
985 if (!autoHighlight && d->highlightXAnimator) {
986 d->highlightXAnimator->stop();
987 d->highlightYAnimator->stop();
989 QSGItemView::setHighlightFollowsCurrentItem(autoHighlight);
993 void QSGGridView::setHighlightMoveDuration(int duration)
996 if (d->highlightMoveDuration != duration) {
997 if (d->highlightYAnimator) {
998 d->highlightXAnimator->userDuration = duration;
999 d->highlightYAnimator->userDuration = duration;
1001 QSGItemView::setHighlightMoveDuration(duration);
1005 QSGGridView::Flow QSGGridView::flow() const
1007 Q_D(const QSGGridView);
1011 void QSGGridView::setFlow(Flow flow)
1014 if (d->flow != flow) {
1016 if (d->flow == LeftToRight) {
1017 setContentWidth(-1);
1018 setFlickableDirection(VerticalFlick);
1020 setContentHeight(-1);
1021 setFlickableDirection(HorizontalFlick);
1031 int QSGGridView::cellWidth() const
1033 Q_D(const QSGGridView);
1034 return d->cellWidth;
1037 void QSGGridView::setCellWidth(int cellWidth)
1040 if (cellWidth != d->cellWidth && cellWidth > 0) {
1041 d->cellWidth = qMax(1, cellWidth);
1042 d->updateViewport();
1043 emit cellWidthChanged();
1048 int QSGGridView::cellHeight() const
1050 Q_D(const QSGGridView);
1051 return d->cellHeight;
1054 void QSGGridView::setCellHeight(int cellHeight)
1057 if (cellHeight != d->cellHeight && cellHeight > 0) {
1058 d->cellHeight = qMax(1, cellHeight);
1059 d->updateViewport();
1060 emit cellHeightChanged();
1065 QSGGridView::SnapMode QSGGridView::snapMode() const
1067 Q_D(const QSGGridView);
1071 void QSGGridView::setSnapMode(SnapMode mode)
1074 if (d->snapMode != mode) {
1076 emit snapModeChanged();
1081 void QSGGridView::viewportMoved()
1084 QSGItemView::viewportMoved();
1087 if (d->inViewportMoved)
1089 d->inViewportMoved = true;
1091 d->lazyRelease = true;
1092 if (d->flickingHorizontally || d->flickingVertically) {
1094 if (d->vData.velocity > 0)
1095 d->bufferMode = QSGGridViewPrivate::BufferBefore;
1096 else if (d->vData.velocity < 0)
1097 d->bufferMode = QSGGridViewPrivate::BufferAfter;
1101 if (d->hData.velocity > 0)
1102 d->bufferMode = QSGGridViewPrivate::BufferBefore;
1103 else if (d->hData.velocity < 0)
1104 d->bufferMode = QSGGridViewPrivate::BufferAfter;
1108 if (d->flickingHorizontally || d->flickingVertically || d->movingHorizontally || d->movingVertically)
1109 d->moveReason = QSGGridViewPrivate::Mouse;
1110 if (d->moveReason != QSGGridViewPrivate::SetIndex) {
1111 if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange && d->highlight) {
1112 // reposition highlight
1113 qreal pos = d->highlight->position();
1115 qreal highlightStart;
1117 if (d->isRightToLeftTopToBottom()) {
1118 viewPos = -d->position()-d->size();
1119 highlightStart = d->highlightRangeStartValid ? d->size()-d->highlightRangeEnd : d->highlightRangeStart;
1120 highlightEnd = d->highlightRangeEndValid ? d->size()-d->highlightRangeStart : d->highlightRangeEnd;
1122 viewPos = d->position();
1123 highlightStart = d->highlightRangeStart;
1124 highlightEnd = d->highlightRangeEnd;
1126 if (pos > viewPos + highlightEnd - d->highlight->size())
1127 pos = viewPos + highlightEnd - d->highlight->size();
1128 if (pos < viewPos + highlightStart)
1129 pos = viewPos + highlightStart;
1131 if (pos != d->highlight->position()) {
1132 d->highlightXAnimator->stop();
1133 d->highlightYAnimator->stop();
1134 static_cast<FxGridItemSG*>(d->highlight)->setPosition(static_cast<FxGridItemSG*>(d->highlight)->colPos(), pos);
1136 d->updateHighlight();
1139 // update current index
1140 int idx = d->snapIndex();
1141 if (idx >= 0 && idx != d->currentIndex) {
1142 d->updateCurrent(idx);
1143 if (d->currentItem && static_cast<FxGridItemSG*>(d->currentItem)->colPos() != static_cast<FxGridItemSG*>(d->highlight)->colPos() && d->autoHighlight) {
1144 if (d->flow == LeftToRight)
1145 d->highlightXAnimator->to = d->currentItem->item->x();
1147 d->highlightYAnimator->to = d->currentItem->item->y();
1153 d->inViewportMoved = false;
1156 void QSGGridView::keyPressEvent(QKeyEvent *event)
1159 if (d->model && d->model->count() && d->interactive) {
1160 d->moveReason = QSGGridViewPrivate::SetIndex;
1161 int oldCurrent = currentIndex();
1162 switch (event->key()) {
1164 moveCurrentIndexUp();
1167 moveCurrentIndexDown();
1170 moveCurrentIndexLeft();
1173 moveCurrentIndexRight();
1178 if (oldCurrent != currentIndex()) {
1184 QSGItemView::keyPressEvent(event);
1187 void QSGGridView::moveCurrentIndexUp()
1190 const int count = d->model ? d->model->count() : 0;
1193 if (d->flow == QSGGridView::LeftToRight) {
1194 if (currentIndex() >= d->columns || d->wrap) {
1195 int index = currentIndex() - d->columns;
1196 setCurrentIndex((index >= 0 && index < count) ? index : count-1);
1199 if (currentIndex() > 0 || d->wrap) {
1200 int index = currentIndex() - 1;
1201 setCurrentIndex((index >= 0 && index < count) ? index : count-1);
1206 void QSGGridView::moveCurrentIndexDown()
1209 const int count = d->model ? d->model->count() : 0;
1212 if (d->flow == QSGGridView::LeftToRight) {
1213 if (currentIndex() < count - d->columns || d->wrap) {
1214 int index = currentIndex()+d->columns;
1215 setCurrentIndex((index >= 0 && index < count) ? index : 0);
1218 if (currentIndex() < count - 1 || d->wrap) {
1219 int index = currentIndex() + 1;
1220 setCurrentIndex((index >= 0 && index < count) ? index : 0);
1225 void QSGGridView::moveCurrentIndexLeft()
1228 const int count = d->model ? d->model->count() : 0;
1231 if (effectiveLayoutDirection() == Qt::LeftToRight) {
1232 if (d->flow == QSGGridView::LeftToRight) {
1233 if (currentIndex() > 0 || d->wrap) {
1234 int index = currentIndex() - 1;
1235 setCurrentIndex((index >= 0 && index < count) ? index : count-1);
1238 if (currentIndex() >= d->columns || d->wrap) {
1239 int index = currentIndex() - d->columns;
1240 setCurrentIndex((index >= 0 && index < count) ? index : count-1);
1244 if (d->flow == QSGGridView::LeftToRight) {
1245 if (currentIndex() < count - 1 || d->wrap) {
1246 int index = currentIndex() + 1;
1247 setCurrentIndex((index >= 0 && index < count) ? index : 0);
1250 if (currentIndex() < count - d->columns || d->wrap) {
1251 int index = currentIndex() + d->columns;
1252 setCurrentIndex((index >= 0 && index < count) ? index : 0);
1258 void QSGGridView::moveCurrentIndexRight()
1261 const int count = d->model ? d->model->count() : 0;
1264 if (effectiveLayoutDirection() == Qt::LeftToRight) {
1265 if (d->flow == QSGGridView::LeftToRight) {
1266 if (currentIndex() < count - 1 || d->wrap) {
1267 int index = currentIndex() + 1;
1268 setCurrentIndex((index >= 0 && index < count) ? index : 0);
1271 if (currentIndex() < count - d->columns || d->wrap) {
1272 int index = currentIndex()+d->columns;
1273 setCurrentIndex((index >= 0 && index < count) ? index : 0);
1277 if (d->flow == QSGGridView::LeftToRight) {
1278 if (currentIndex() > 0 || d->wrap) {
1279 int index = currentIndex() - 1;
1280 setCurrentIndex((index >= 0 && index < count) ? index : count-1);
1283 if (currentIndex() >= d->columns || d->wrap) {
1284 int index = currentIndex() - d->columns;
1285 setCurrentIndex((index >= 0 && index < count) ? index : count-1);
1292 void QSGGridView::itemsInserted(int modelIndex, int count)
1295 if (!isComponentComplete() || !d->model || !d->model->isValid())
1298 int index = d->visibleItems.count() ? d->mapFromModel(modelIndex) : 0;
1300 int i = d->visibleItems.count() - 1;
1301 while (i > 0 && d->visibleItems.at(i)->index == -1)
1303 if (d->visibleItems.at(i)->index + 1 == modelIndex) {
1304 // Special case of appending an item to the model.
1305 index = d->visibleIndex + d->visibleItems.count();
1307 if (modelIndex <= d->visibleIndex) {
1308 // Insert before visible items
1309 d->visibleIndex += count;
1310 for (int i = 0; i < d->visibleItems.count(); ++i) {
1311 FxViewItem *item = d->visibleItems.at(i);
1312 if (item->index != -1 && item->index >= modelIndex)
1313 item->index += count;
1316 if (d->currentIndex >= modelIndex) {
1317 // adjust current item index
1318 d->currentIndex += count;
1320 d->currentItem->index = d->currentIndex;
1321 emit currentIndexChanged();
1323 d->scheduleLayout();
1324 d->itemCount += count;
1325 emit countChanged();
1330 int insertCount = count;
1331 if (index < d->visibleIndex && d->visibleItems.count()) {
1332 insertCount -= d->visibleIndex - index;
1333 index = d->visibleIndex;
1334 modelIndex = d->visibleIndex;
1337 qreal tempPos = d->isRightToLeftTopToBottom() ? -d->position()-d->size()+width()+1 : d->position();
1338 int to = d->buffer+tempPos+d->size()-1;
1341 if (d->visibleItems.count()) {
1342 index -= d->visibleIndex;
1343 if (index < d->visibleItems.count()) {
1344 FxGridItemSG *gridItem = static_cast<FxGridItemSG*>(d->visibleItems.at(index));
1345 colPos = gridItem->colPos();
1346 rowPos = gridItem->rowPos();
1348 // appending items to visible list
1349 FxGridItemSG *gridItem = static_cast<FxGridItemSG*>(d->visibleItems.at(index-1));
1350 colPos = gridItem->colPos() + d->colSize();
1351 rowPos = gridItem->rowPos();
1352 if (colPos > d->colSize() * (d->columns-1)) {
1354 rowPos += d->rowSize();
1359 // Update the indexes of the following visible items.
1360 for (int i = 0; i < d->visibleItems.count(); ++i) {
1361 FxViewItem *item = d->visibleItems.at(i);
1362 if (item->index != -1 && item->index >= modelIndex)
1363 item->index += count;
1366 bool addedVisible = false;
1367 QList<FxGridItemSG*> added;
1369 while (i < insertCount && rowPos <= to + d->rowSize()*(d->columns - (colPos/d->colSize()))/qreal(d->columns)) {
1370 if (!addedVisible) {
1371 d->scheduleLayout();
1372 addedVisible = true;
1374 FxGridItemSG *item = static_cast<FxGridItemSG*>(d->createItem(modelIndex + i));
1375 d->visibleItems.insert(index, item);
1376 item->setPosition(colPos, rowPos);
1378 colPos += d->colSize();
1379 if (colPos > d->colSize() * (d->columns-1)) {
1381 rowPos += d->rowSize();
1386 if (i < insertCount) {
1387 // We didn't insert all our new items, which means anything
1388 // beyond the current index is not visible - remove it.
1389 while (d->visibleItems.count() > index) {
1390 d->releaseItem(d->visibleItems.takeLast());
1394 // update visibleIndex
1395 d->visibleIndex = 0;
1396 for (QList<FxViewItem*>::Iterator it = d->visibleItems.begin(); it != d->visibleItems.end(); ++it) {
1397 if ((*it)->index != -1) {
1398 d->visibleIndex = (*it)->index;
1403 if (d->itemCount && d->currentIndex >= modelIndex) {
1404 // adjust current item index
1405 d->currentIndex += count;
1406 if (d->currentItem) {
1407 d->currentItem->index = d->currentIndex;
1408 static_cast<FxGridItemSG*>(d->currentItem)->setPosition(d->colPosAt(d->currentIndex), d->rowPosAt(d->currentIndex));
1410 emit currentIndexChanged();
1411 } else if (d->itemCount == 0 && (!d->currentIndex || (d->currentIndex < 0 && !d->currentIndexCleared))) {
1415 // everything is in order now - emit add() signal
1416 for (int j = 0; j < added.count(); ++j)
1417 added.at(j)->attached->emitAdd();
1419 d->itemCount += count;
1420 emit countChanged();
1423 void QSGGridView::itemsRemoved(int modelIndex, int count)
1426 if (!isComponentComplete() || !d->model || !d->model->isValid())
1429 d->itemCount -= count;
1430 bool currentRemoved = d->currentIndex >= modelIndex && d->currentIndex < modelIndex + count;
1431 bool removedVisible = false;
1433 // Remove the items from the visible list, skipping anything already marked for removal
1434 QList<FxViewItem*>::Iterator it = d->visibleItems.begin();
1435 while (it != d->visibleItems.end()) {
1436 FxViewItem *item = *it;
1437 if (item->index == -1 || item->index < modelIndex) {
1438 // already removed, or before removed items
1439 if (item->index < modelIndex && !removedVisible) {
1440 d->scheduleLayout();
1441 removedVisible = true;
1444 } else if (item->index >= modelIndex + count) {
1445 // after removed items
1446 item->index -= count;
1450 if (!removedVisible) {
1451 d->scheduleLayout();
1452 removedVisible = true;
1454 item->attached->emitRemove();
1455 if (item->attached->delayRemove()) {
1457 connect(item->attached, SIGNAL(delayRemoveChanged()), this, SLOT(destroyRemoved()), Qt::QueuedConnection);
1460 it = d->visibleItems.erase(it);
1461 d->releaseItem(item);
1466 // update visibleIndex
1467 d->visibleIndex = 0;
1468 for (it = d->visibleItems.begin(); it != d->visibleItems.end(); ++it) {
1469 if ((*it)->index != -1) {
1470 d->visibleIndex = (*it)->index;
1476 if (d->currentIndex >= modelIndex + count) {
1477 d->currentIndex -= count;
1479 d->currentItem->index -= count;
1480 emit currentIndexChanged();
1481 } else if (currentRemoved) {
1482 // current item has been removed.
1483 d->releaseItem(d->currentItem);
1485 d->currentIndex = -1;
1487 d->updateCurrent(qMin(modelIndex, d->itemCount-1));
1489 emit currentIndexChanged();
1492 if (removedVisible && d->visibleItems.isEmpty()) {
1493 d->timeline.clear();
1494 if (d->itemCount == 0) {
1495 d->setPosition(d->contentStartPosition());
1501 emit countChanged();
1505 void QSGGridView::itemsMoved(int from, int to, int count)
1508 if (!isComponentComplete() || !d->isValid())
1510 d->updateUnrequestedIndexes();
1512 if (d->visibleItems.isEmpty()) {
1517 d->moveReason = QSGGridViewPrivate::Other;
1519 bool movingBackwards = from > to;
1520 d->adjustMoveParameters(&from, &to, &count);
1522 QHash<int,FxGridItemSG*> moved;
1523 int moveByCount = 0;
1524 FxGridItemSG *firstVisible = static_cast<FxGridItemSG*>(d->firstVisibleItem());
1525 int firstItemIndex = firstVisible ? firstVisible->index : -1;
1527 // if visibleItems.first() is above the content start pos, and the items
1528 // beneath it are moved, ensure this first item is later repositioned correctly
1529 // (to above the next visible item) so that subsequent layout() is correct
1530 bool repositionFirstItem = firstVisible
1531 && d->visibleItems.first()->position() < firstVisible->position()
1532 && from > d->visibleItems.first()->index;
1534 QList<FxViewItem*>::Iterator it = d->visibleItems.begin();
1535 while (it != d->visibleItems.end()) {
1536 FxViewItem *item = *it;
1537 if (item->index >= from && item->index < from + count) {
1538 // take the items that are moving
1539 item->index += (to-from);
1540 moved.insert(item->index, static_cast<FxGridItemSG*>(item));
1541 if (repositionFirstItem)
1543 it = d->visibleItems.erase(it);
1545 if (item->index > from && item->index != -1) {
1546 // move everything after the moved items.
1547 item->index -= count;
1548 if (item->index < d->visibleIndex)
1549 d->visibleIndex = item->index;
1556 int endIndex = d->visibleIndex;
1557 it = d->visibleItems.begin();
1558 while (it != d->visibleItems.end()) {
1559 FxViewItem *item = *it;
1560 if (movedCount < count && item->index >= to && item->index < to + count) {
1561 // place items in the target position, reusing any existing items
1562 int targetIndex = item->index + movedCount;
1563 FxGridItemSG *movedItem = moved.take(targetIndex);
1565 movedItem = static_cast<FxGridItemSG*>(d->createItem(targetIndex));
1566 it = d->visibleItems.insert(it, movedItem);
1570 if (item->index != -1) {
1571 if (item->index >= to) {
1572 // update everything after the moved items.
1573 item->index += count;
1575 endIndex = item->index;
1581 // If we have moved items to the end of the visible items
1582 // then add any existing moved items that we have
1583 while (FxGridItemSG *item = moved.take(endIndex+1)) {
1584 d->visibleItems.append(item);
1588 // update visibleIndex
1589 for (it = d->visibleItems.begin(); it != d->visibleItems.end(); ++it) {
1590 if ((*it)->index != -1) {
1591 d->visibleIndex = (*it)->index;
1596 // if first visible item is moving but another item is moving up to replace it,
1597 // do this positioning now to avoid shifting all content forwards
1598 if (movingBackwards && firstItemIndex >= 0) {
1599 for (it = d->visibleItems.begin(); it != d->visibleItems.end(); ++it) {
1600 if ((*it)->index == firstItemIndex) {
1601 static_cast<FxGridItemSG*>(*it)->setPosition(firstVisible->colPos(),
1602 firstVisible->rowPos());
1608 // Fix current index
1609 if (d->currentIndex >= 0 && d->currentItem) {
1610 int oldCurrent = d->currentIndex;
1611 d->currentIndex = d->model->indexOf(d->currentItem->item, this);
1612 if (oldCurrent != d->currentIndex) {
1613 d->currentItem->index = d->currentIndex;
1614 emit currentIndexChanged();
1618 // Whatever moved items remain are no longer visible items.
1619 while (moved.count()) {
1620 int idx = moved.begin().key();
1621 FxGridItemSG *item = moved.take(idx);
1622 if (d->currentItem && item->item == d->currentItem->item)
1623 item->setPosition(d->colPosAt(idx), d->rowPosAt(idx));
1624 d->releaseItem(item);
1627 // Ensure we don't cause an ugly list scroll.
1628 if (d->visibleItems.count() && moveByCount > 0) {
1629 FxGridItemSG *first = static_cast<FxGridItemSG*>(d->visibleItems.first());
1630 first->setPosition(first->colPos(), first->rowPos() + ((moveByCount / d->columns) * d->rowSize()));
1637 QSGGridViewAttached *QSGGridView::qmlAttachedProperties(QObject *obj)
1639 return new QSGGridViewAttached(obj);