106 , cellWidth(100), cellHeight(100), columns(1), requestedIndex(-1), itemCount(0) |
106 , cellWidth(100), cellHeight(100), columns(1), requestedIndex(-1), itemCount(0) |
107 , highlightRangeStart(0), highlightRangeEnd(0), highlightRange(QDeclarativeGridView::NoHighlightRange) |
107 , highlightRangeStart(0), highlightRangeEnd(0), highlightRange(QDeclarativeGridView::NoHighlightRange) |
108 , highlightComponent(0), highlight(0), trackedItem(0) |
108 , highlightComponent(0), highlight(0), trackedItem(0) |
109 , moveReason(Other), buffer(0), highlightXAnimator(0), highlightYAnimator(0) |
109 , moveReason(Other), buffer(0), highlightXAnimator(0), highlightYAnimator(0) |
110 , highlightMoveDuration(150) |
110 , highlightMoveDuration(150) |
|
111 , footerComponent(0), footer(0), headerComponent(0), header(0) |
111 , bufferMode(BufferBefore | BufferAfter), snapMode(QDeclarativeGridView::NoSnap) |
112 , bufferMode(BufferBefore | BufferAfter), snapMode(QDeclarativeGridView::NoSnap) |
112 , ownModel(false), wrap(false), autoHighlight(true) |
113 , ownModel(false), wrap(false), autoHighlight(true) |
113 , fixCurrentVisibility(false), lazyRelease(false), layoutScheduled(false) |
114 , fixCurrentVisibility(false), lazyRelease(false), layoutScheduled(false) |
114 , deferredRelease(false), haveHighlightRange(false) {} |
115 , deferredRelease(false), haveHighlightRange(false) {} |
115 |
116 |
126 void updateUnrequestedPositions(); |
127 void updateUnrequestedPositions(); |
127 void updateTrackedItem(); |
128 void updateTrackedItem(); |
128 void createHighlight(); |
129 void createHighlight(); |
129 void updateHighlight(); |
130 void updateHighlight(); |
130 void updateCurrent(int modelIndex); |
131 void updateCurrent(int modelIndex); |
|
132 void updateHeader(); |
|
133 void updateFooter(); |
131 void fixupPosition(); |
134 void fixupPosition(); |
132 |
135 |
133 FxGridItem *visibleItem(int modelIndex) const { |
136 FxGridItem *visibleItem(int modelIndex) const { |
134 if (modelIndex >= visibleIndex && modelIndex < visibleIndex + visibleItems.count()) { |
137 if (modelIndex >= visibleIndex && modelIndex < visibleIndex + visibleItems.count()) { |
135 for (int i = modelIndex - visibleIndex; i < visibleItems.count(); ++i) { |
138 for (int i = modelIndex - visibleIndex; i < visibleItems.count(); ++i) { |
146 return flow == QDeclarativeGridView::LeftToRight ? q->contentY() : q->contentX(); |
149 return flow == QDeclarativeGridView::LeftToRight ? q->contentY() : q->contentX(); |
147 } |
150 } |
148 void setPosition(qreal pos) { |
151 void setPosition(qreal pos) { |
149 Q_Q(QDeclarativeGridView); |
152 Q_Q(QDeclarativeGridView); |
150 if (flow == QDeclarativeGridView::LeftToRight) |
153 if (flow == QDeclarativeGridView::LeftToRight) |
151 q->setContentY(pos); |
154 q->QDeclarativeFlickable::setContentY(pos); |
152 else |
155 else |
153 q->setContentX(pos); |
156 q->QDeclarativeFlickable::setContentX(pos); |
154 } |
157 } |
155 int size() const { |
158 int size() const { |
156 Q_Q(const QDeclarativeGridView); |
159 Q_Q(const QDeclarativeGridView); |
157 return flow == QDeclarativeGridView::LeftToRight ? q->height() : q->width(); |
160 return flow == QDeclarativeGridView::LeftToRight ? q->height() : q->width(); |
158 } |
161 } |
228 return item; |
231 return item; |
229 } |
232 } |
230 return visibleItems.count() ? visibleItems.first() : 0; |
233 return visibleItems.count() ? visibleItems.first() : 0; |
231 } |
234 } |
232 |
235 |
|
236 int lastVisibleIndex() const { |
|
237 int lastIndex = -1; |
|
238 for (int i = visibleItems.count()-1; i >= 0; --i) { |
|
239 FxGridItem *gridItem = visibleItems.at(i); |
|
240 if (gridItem->index != -1) { |
|
241 lastIndex = gridItem->index; |
|
242 break; |
|
243 } |
|
244 } |
|
245 return lastIndex; |
|
246 } |
|
247 |
233 // Map a model index to visibleItems list index. |
248 // Map a model index to visibleItems list index. |
234 // These may differ if removed items are still present in the visible list, |
249 // These may differ if removed items are still present in the visible list, |
235 // e.g. doing a removal animation |
250 // e.g. doing a removal animation |
236 int mapFromModel(int modelIndex) const { |
251 int mapFromModel(int modelIndex) const { |
237 if (modelIndex < visibleIndex || modelIndex >= visibleIndex + visibleItems.count()) |
252 if (modelIndex < visibleIndex || modelIndex >= visibleIndex + visibleItems.count()) |
244 return -1; |
259 return -1; |
245 } |
260 } |
246 return -1; // Not in visibleList |
261 return -1; // Not in visibleList |
247 } |
262 } |
248 |
263 |
249 qreal snapPosAt(qreal pos) { |
264 qreal snapPosAt(qreal pos) const { |
|
265 Q_Q(const QDeclarativeGridView); |
250 qreal snapPos = 0; |
266 qreal snapPos = 0; |
251 if (!visibleItems.isEmpty()) { |
267 if (!visibleItems.isEmpty()) { |
252 pos += rowSize()/2; |
268 pos += rowSize()/2; |
253 snapPos = visibleItems.first()->rowPos() - visibleIndex / columns * rowSize(); |
269 snapPos = visibleItems.first()->rowPos() - visibleIndex / columns * rowSize(); |
254 snapPos = pos - fmodf(pos - snapPos, qreal(rowSize())); |
270 snapPos = pos - fmodf(pos - snapPos, qreal(rowSize())); |
|
271 qreal maxExtent = flow == QDeclarativeGridView::LeftToRight ? -q->maxYExtent() : -q->maxXExtent(); |
|
272 qreal minExtent = flow == QDeclarativeGridView::LeftToRight ? -q->minYExtent() : -q->minXExtent(); |
|
273 if (snapPos > maxExtent) |
|
274 snapPos = maxExtent; |
|
275 if (snapPos < minExtent) |
|
276 snapPos = minExtent; |
255 } |
277 } |
256 return snapPos; |
278 return snapPos; |
|
279 } |
|
280 |
|
281 FxGridItem *snapItemAt(qreal pos) { |
|
282 for (int i = 0; i < visibleItems.count(); ++i) { |
|
283 FxGridItem *item = visibleItems[i]; |
|
284 if (item->index == -1) |
|
285 continue; |
|
286 qreal itemTop = item->rowPos(); |
|
287 if (item->index == model->count()-1 || (itemTop+rowSize()/2 >= pos)) |
|
288 return item; |
|
289 } |
|
290 if (visibleItems.count() && visibleItems.first()->rowPos() <= pos) |
|
291 return visibleItems.first(); |
|
292 return 0; |
257 } |
293 } |
258 |
294 |
259 int snapIndex() { |
295 int snapIndex() { |
260 int index = currentIndex; |
296 int index = currentIndex; |
261 for (int i = 0; i < visibleItems.count(); ++i) { |
297 for (int i = 0; i < visibleItems.count(); ++i) { |
328 MovementReason moveReason; |
367 MovementReason moveReason; |
329 int buffer; |
368 int buffer; |
330 QSmoothedAnimation *highlightXAnimator; |
369 QSmoothedAnimation *highlightXAnimator; |
331 QSmoothedAnimation *highlightYAnimator; |
370 QSmoothedAnimation *highlightYAnimator; |
332 int highlightMoveDuration; |
371 int highlightMoveDuration; |
|
372 QDeclarativeComponent *footerComponent; |
|
373 FxGridItem *footer; |
|
374 QDeclarativeComponent *headerComponent; |
|
375 FxGridItem *header; |
333 enum BufferMode { NoBuffer = 0x00, BufferBefore = 0x01, BufferAfter = 0x02 }; |
376 enum BufferMode { NoBuffer = 0x00, BufferBefore = 0x01, BufferAfter = 0x02 }; |
334 int bufferMode; |
377 int bufferMode; |
335 QDeclarativeGridView::SnapMode snapMode; |
378 QDeclarativeGridView::SnapMode snapMode; |
336 |
379 |
337 bool ownModel : 1; |
380 bool ownModel : 1; |
376 listItem = new FxGridItem(item, q); |
419 listItem = new FxGridItem(item, q); |
377 listItem->index = modelIndex; |
420 listItem->index = modelIndex; |
378 if (model->completePending()) { |
421 if (model->completePending()) { |
379 // complete |
422 // complete |
380 listItem->item->setZValue(1); |
423 listItem->item->setZValue(1); |
381 listItem->item->setParentItem(q->viewport()); |
424 listItem->item->setParentItem(q->contentItem()); |
382 model->completeItem(); |
425 model->completeItem(); |
383 } else { |
426 } else { |
384 listItem->item->setParentItem(q->viewport()); |
427 listItem->item->setParentItem(q->contentItem()); |
385 } |
428 } |
386 unrequestedItems.remove(listItem->item); |
429 unrequestedItems.remove(listItem->item); |
387 } |
430 } |
388 requestedIndex = -1; |
431 requestedIndex = -1; |
389 return listItem; |
432 return listItem; |
410 void QDeclarativeGridViewPrivate::refill(qreal from, qreal to, bool doBuffer) |
453 void QDeclarativeGridViewPrivate::refill(qreal from, qreal to, bool doBuffer) |
411 { |
454 { |
412 Q_Q(QDeclarativeGridView); |
455 Q_Q(QDeclarativeGridView); |
413 if (!isValid() || !q->isComponentComplete()) |
456 if (!isValid() || !q->isComponentComplete()) |
414 return; |
457 return; |
415 |
|
416 itemCount = model->count(); |
458 itemCount = model->count(); |
417 qreal bufferFrom = from - buffer; |
459 qreal bufferFrom = from - buffer; |
418 qreal bufferTo = to + buffer; |
460 qreal bufferTo = to + buffer; |
419 qreal fillFrom = from; |
461 qreal fillFrom = from; |
420 qreal fillTo = to; |
462 qreal fillTo = to; |
664 } else { |
714 } else { |
665 delete highlightContext; |
715 delete highlightContext; |
666 } |
716 } |
667 } else { |
717 } else { |
668 item = new QDeclarativeItem; |
718 item = new QDeclarativeItem; |
669 QDeclarative_setParent_noEvent(item, q->viewport()); |
719 QDeclarative_setParent_noEvent(item, q->contentItem()); |
670 item->setParentItem(q->viewport()); |
720 item->setParentItem(q->contentItem()); |
671 } |
721 } |
672 if (item) { |
722 if (item) { |
673 QDeclarative_setParent_noEvent(item, q->viewport()); |
723 QDeclarative_setParent_noEvent(item, q->contentItem()); |
674 item->setParentItem(q->viewport()); |
724 item->setParentItem(q->contentItem()); |
675 highlight = new FxGridItem(item, q); |
725 highlight = new FxGridItem(item, q); |
676 highlightXAnimator = new QSmoothedAnimation(q); |
726 highlightXAnimator = new QSmoothedAnimation(q); |
677 highlightXAnimator->target = QDeclarativeProperty(highlight->item, QLatin1String("x")); |
727 highlightXAnimator->target = QDeclarativeProperty(highlight->item, QLatin1String("x")); |
678 highlightXAnimator->userDuration = highlightMoveDuration; |
728 highlightXAnimator->userDuration = highlightMoveDuration; |
679 highlightYAnimator = new QSmoothedAnimation(q); |
729 highlightYAnimator = new QSmoothedAnimation(q); |
740 updateHighlight(); |
790 updateHighlight(); |
741 emit q->currentIndexChanged(); |
791 emit q->currentIndexChanged(); |
742 releaseItem(oldCurrentItem); |
792 releaseItem(oldCurrentItem); |
743 } |
793 } |
744 |
794 |
|
795 void QDeclarativeGridViewPrivate::updateFooter() |
|
796 { |
|
797 Q_Q(QDeclarativeGridView); |
|
798 if (!footer && footerComponent) { |
|
799 QDeclarativeItem *item = 0; |
|
800 QDeclarativeContext *context = new QDeclarativeContext(qmlContext(q)); |
|
801 QObject *nobj = footerComponent->create(context); |
|
802 if (nobj) { |
|
803 QDeclarative_setParent_noEvent(context, nobj); |
|
804 item = qobject_cast<QDeclarativeItem *>(nobj); |
|
805 if (!item) |
|
806 delete nobj; |
|
807 } else { |
|
808 delete context; |
|
809 } |
|
810 if (item) { |
|
811 QDeclarative_setParent_noEvent(item, q->contentItem()); |
|
812 item->setParentItem(q->contentItem()); |
|
813 item->setZValue(1); |
|
814 QDeclarativeItemPrivate *itemPrivate = static_cast<QDeclarativeItemPrivate*>(QGraphicsItemPrivate::get(item)); |
|
815 itemPrivate->addItemChangeListener(this, QDeclarativeItemPrivate::Geometry); |
|
816 footer = new FxGridItem(item, q); |
|
817 } |
|
818 } |
|
819 if (footer) { |
|
820 if (visibleItems.count()) { |
|
821 qreal endPos = endPosition(); |
|
822 if (lastVisibleIndex() == model->count()-1) { |
|
823 footer->setPosition(0, endPos); |
|
824 } else { |
|
825 qreal visiblePos = position() + q->height(); |
|
826 if (endPos <= visiblePos || footer->endRowPos() < endPos) |
|
827 footer->setPosition(0, endPos); |
|
828 } |
|
829 } else { |
|
830 qreal endPos = 0; |
|
831 if (header) { |
|
832 endPos += flow == QDeclarativeGridView::LeftToRight |
|
833 ? header->item->height() |
|
834 : header->item->width(); |
|
835 } |
|
836 footer->setPosition(0, endPos); |
|
837 } |
|
838 } |
|
839 } |
|
840 |
|
841 void QDeclarativeGridViewPrivate::updateHeader() |
|
842 { |
|
843 Q_Q(QDeclarativeGridView); |
|
844 if (!header && headerComponent) { |
|
845 QDeclarativeItem *item = 0; |
|
846 QDeclarativeContext *context = new QDeclarativeContext(qmlContext(q)); |
|
847 QObject *nobj = headerComponent->create(context); |
|
848 if (nobj) { |
|
849 QDeclarative_setParent_noEvent(context, nobj); |
|
850 item = qobject_cast<QDeclarativeItem *>(nobj); |
|
851 if (!item) |
|
852 delete nobj; |
|
853 } else { |
|
854 delete context; |
|
855 } |
|
856 if (item) { |
|
857 QDeclarative_setParent_noEvent(item, q->contentItem()); |
|
858 item->setParentItem(q->contentItem()); |
|
859 item->setZValue(1); |
|
860 QDeclarativeItemPrivate *itemPrivate = static_cast<QDeclarativeItemPrivate*>(QGraphicsItemPrivate::get(item)); |
|
861 itemPrivate->addItemChangeListener(this, QDeclarativeItemPrivate::Geometry); |
|
862 header = new FxGridItem(item, q); |
|
863 } |
|
864 } |
|
865 if (header) { |
|
866 if (visibleItems.count()) { |
|
867 qreal startPos = startPosition(); |
|
868 qreal headerSize = flow == QDeclarativeGridView::LeftToRight |
|
869 ? header->item->height() |
|
870 : header->item->width(); |
|
871 if (visibleIndex == 0) { |
|
872 header->setPosition(0, startPos - headerSize); |
|
873 } else { |
|
874 if (position() <= startPos || header->rowPos() > startPos - headerSize) |
|
875 header->setPosition(0, startPos - headerSize); |
|
876 } |
|
877 } else { |
|
878 header->setPosition(0, 0); |
|
879 } |
|
880 } |
|
881 } |
|
882 |
745 void QDeclarativeGridViewPrivate::fixupPosition() |
883 void QDeclarativeGridViewPrivate::fixupPosition() |
746 { |
884 { |
747 moveReason = Other; |
885 moveReason = Other; |
748 if (flow == QDeclarativeGridView::LeftToRight) |
886 if (flow == QDeclarativeGridView::LeftToRight) |
749 fixupY(); |
887 fixupY(); |
751 fixupX(); |
889 fixupX(); |
752 } |
890 } |
753 |
891 |
754 void QDeclarativeGridViewPrivate::fixup(AxisData &data, qreal minExtent, qreal maxExtent) |
892 void QDeclarativeGridViewPrivate::fixup(AxisData &data, qreal minExtent, qreal maxExtent) |
755 { |
893 { |
756 Q_Q(QDeclarativeGridView); |
|
757 if ((flow == QDeclarativeGridView::TopToBottom && &data == &vData) |
894 if ((flow == QDeclarativeGridView::TopToBottom && &data == &vData) |
758 || (flow == QDeclarativeGridView::LeftToRight && &data == &hData)) |
895 || (flow == QDeclarativeGridView::LeftToRight && &data == &hData)) |
759 return; |
896 return; |
760 |
897 |
761 int oldDuration = fixupDuration; |
898 int oldDuration = fixupDuration; |
762 fixupDuration = moveReason == Mouse ? fixupDuration : 0; |
899 fixupDuration = moveReason == Mouse ? fixupDuration : 0; |
763 |
900 |
764 if (haveHighlightRange && highlightRange == QDeclarativeGridView::StrictlyEnforceRange) { |
901 if (snapMode != QDeclarativeGridView::NoSnap) { |
|
902 FxGridItem *topItem = snapItemAt(position()+highlightRangeStart); |
|
903 FxGridItem *bottomItem = snapItemAt(position()+highlightRangeEnd); |
|
904 qreal pos; |
|
905 if (topItem && bottomItem && haveHighlightRange && highlightRange == QDeclarativeGridView::StrictlyEnforceRange) { |
|
906 qreal topPos = qMin(topItem->rowPos() - highlightRangeStart, -maxExtent); |
|
907 qreal bottomPos = qMax(bottomItem->rowPos() - highlightRangeEnd, -minExtent); |
|
908 pos = qAbs(data.move + topPos) < qAbs(data.move + bottomPos) ? topPos : bottomPos; |
|
909 } else if (topItem) { |
|
910 pos = qMax(qMin(topItem->rowPos() - highlightRangeStart, -maxExtent), -minExtent); |
|
911 } else if (bottomItem) { |
|
912 pos = qMax(qMin(bottomItem->rowPos() - highlightRangeStart, -maxExtent), -minExtent); |
|
913 } else { |
|
914 fixupDuration = oldDuration; |
|
915 return; |
|
916 } |
|
917 if (currentItem && haveHighlightRange && highlightRange == QDeclarativeGridView::StrictlyEnforceRange) { |
|
918 updateHighlight(); |
|
919 qreal currPos = currentItem->rowPos(); |
|
920 if (pos < currPos + rowSize() - highlightRangeEnd) |
|
921 pos = currPos + rowSize() - highlightRangeEnd; |
|
922 if (pos > currPos - highlightRangeStart) |
|
923 pos = currPos - highlightRangeStart; |
|
924 } |
|
925 |
|
926 qreal dist = qAbs(data.move + pos); |
|
927 if (dist > 0) { |
|
928 timeline.reset(data.move); |
|
929 if (fixupDuration) |
|
930 timeline.move(data.move, -pos, QEasingCurve(QEasingCurve::InOutQuad), fixupDuration/2); |
|
931 else |
|
932 timeline.set(data.move, -pos); |
|
933 vTime = timeline.time(); |
|
934 } |
|
935 } else if (haveHighlightRange && highlightRange == QDeclarativeGridView::StrictlyEnforceRange) { |
765 if (currentItem) { |
936 if (currentItem) { |
766 updateHighlight(); |
937 updateHighlight(); |
767 qreal pos = currentItem->rowPos(); |
938 qreal pos = currentItem->rowPos(); |
768 qreal viewPos = position(); |
939 qreal viewPos = position(); |
769 if (viewPos < pos + rowSize() - highlightRangeEnd) |
940 if (viewPos < pos + rowSize() - highlightRangeEnd) |
771 if (viewPos > pos - highlightRangeStart) |
942 if (viewPos > pos - highlightRangeStart) |
772 viewPos = pos - highlightRangeStart; |
943 viewPos = pos - highlightRangeStart; |
773 |
944 |
774 timeline.reset(data.move); |
945 timeline.reset(data.move); |
775 if (viewPos != position()) { |
946 if (viewPos != position()) { |
776 if (fixupDuration) { |
947 if (fixupDuration) |
777 timeline.move(data.move, -viewPos, QEasingCurve(QEasingCurve::InOutQuad), fixupDuration/2); |
948 timeline.move(data.move, -viewPos, QEasingCurve(QEasingCurve::InOutQuad), fixupDuration/2); |
778 } else { |
949 else |
779 data.move.setValue(-viewPos); |
950 timeline.set(data.move, -viewPos); |
780 q->viewportMoved(); |
|
781 } |
|
782 } |
|
783 vTime = timeline.time(); |
|
784 } |
|
785 } else if (snapMode != QDeclarativeGridView::NoSnap) { |
|
786 qreal pos = -snapPosAt(-(data.move.value() - highlightRangeStart)) + highlightRangeStart; |
|
787 pos = qMin(qMax(pos, maxExtent), minExtent); |
|
788 qreal dist = qAbs(data.move.value() - pos); |
|
789 if (dist > 0) { |
|
790 timeline.reset(data.move); |
|
791 if (fixupDuration) { |
|
792 timeline.move(data.move, pos, QEasingCurve(QEasingCurve::InOutQuad), fixupDuration/2); |
|
793 } else { |
|
794 data.move.setValue(pos); |
|
795 q->viewportMoved(); |
|
796 } |
951 } |
797 vTime = timeline.time(); |
952 vTime = timeline.time(); |
798 } |
953 } |
799 } else { |
954 } else { |
800 QDeclarativeFlickablePrivate::fixup(data, minExtent, maxExtent); |
955 QDeclarativeFlickablePrivate::fixup(data, minExtent, maxExtent); |
804 |
959 |
805 void QDeclarativeGridViewPrivate::flick(AxisData &data, qreal minExtent, qreal maxExtent, qreal vSize, |
960 void QDeclarativeGridViewPrivate::flick(AxisData &data, qreal minExtent, qreal maxExtent, qreal vSize, |
806 QDeclarativeTimeLineCallback::Callback fixupCallback, qreal velocity) |
961 QDeclarativeTimeLineCallback::Callback fixupCallback, qreal velocity) |
807 { |
962 { |
808 Q_Q(QDeclarativeGridView); |
963 Q_Q(QDeclarativeGridView); |
809 |
|
810 moveReason = Mouse; |
964 moveReason = Mouse; |
811 if ((!haveHighlightRange || highlightRange != QDeclarativeGridView::StrictlyEnforceRange) |
965 if ((!haveHighlightRange || highlightRange != QDeclarativeGridView::StrictlyEnforceRange) |
812 && snapMode == QDeclarativeGridView::NoSnap) { |
966 && snapMode == QDeclarativeGridView::NoSnap) { |
813 QDeclarativeFlickablePrivate::flick(data, minExtent, maxExtent, vSize, fixupCallback, velocity); |
967 QDeclarativeFlickablePrivate::flick(data, minExtent, maxExtent, vSize, fixupCallback, velocity); |
814 return; |
968 return; |
849 v = maxVelocity; |
1003 v = maxVelocity; |
850 } |
1004 } |
851 qreal accel = deceleration; |
1005 qreal accel = deceleration; |
852 qreal v2 = v * v; |
1006 qreal v2 = v * v; |
853 qreal overshootDist = 0.0; |
1007 qreal overshootDist = 0.0; |
854 if (maxDistance > 0.0 && v2 / (2.0f * maxDistance) < accel) { |
1008 if ((maxDistance > 0.0 && v2 / (2.0f * maxDistance) < accel) || snapMode == QDeclarativeGridView::SnapOneRow) { |
855 // + rowSize()/4 to encourage moving at least one item in the flick direction |
1009 // + rowSize()/4 to encourage moving at least one item in the flick direction |
856 qreal dist = v2 / (accel * 2.0) + rowSize()/4; |
1010 qreal dist = v2 / (accel * 2.0) + rowSize()/4; |
|
1011 dist = qMin(dist, maxDistance); |
857 if (v > 0) |
1012 if (v > 0) |
858 dist = -dist; |
1013 dist = -dist; |
859 data.flickTarget = -snapPosAt(-(data.move.value() - highlightRangeStart) + dist) + highlightRangeStart; |
1014 data.flickTarget = -snapPosAt(-(data.move.value() - highlightRangeStart) + dist) + highlightRangeStart; |
860 qreal adjDist = -data.flickTarget + data.move.value(); |
1015 qreal adjDist = -data.flickTarget + data.move.value(); |
861 if (qAbs(adjDist) > qAbs(dist)) { |
1016 if (qAbs(adjDist) > qAbs(dist)) { |
902 \qmlclass GridView QDeclarativeGridView |
1057 \qmlclass GridView QDeclarativeGridView |
903 \since 4.7 |
1058 \since 4.7 |
904 \inherits Flickable |
1059 \inherits Flickable |
905 \brief The GridView item provides a grid view of items provided by a model. |
1060 \brief The GridView item provides a grid view of items provided by a model. |
906 |
1061 |
907 The model is typically provided by a QAbstractListModel "C++ model object", |
1062 A GridView displays data from models created from built-in QML elements like ListModel |
908 but can also be created directly in QML. |
1063 and XmlListModel, or custom model classes defined in C++ that inherit from |
909 |
1064 QAbstractListModel. |
910 The items are laid out top to bottom (vertically) or left to right (horizontally) |
1065 |
911 and may be flicked to scroll. |
1066 A GridView has a \l model, which defines the data to be displayed, and |
912 |
1067 a \l delegate, which defines how the data should be displayed. Items in a |
913 The below example creates a very simple grid, using a QML model. |
1068 GridView are laid out horizontally or vertically. Grid views are inherently flickable |
914 |
1069 as GridView inherits from \l Flickable. |
915 \image gridview.png |
1070 |
916 |
1071 For example, if there is a simple list model defined in a file \c ContactModel.qml like this: |
917 \snippet doc/src/snippets/declarative/gridview/gridview.qml 3 |
1072 |
918 |
1073 \snippet doc/src/snippets/declarative/gridview/ContactModel.qml 0 |
919 The model is defined as a ListModel using QML: |
1074 |
920 \quotefile doc/src/snippets/declarative/gridview/dummydata/ContactModel.qml |
1075 Another component can display this model data in a GridView, like this: |
921 |
1076 |
922 In this case ListModel is a handy way for us to test our UI. In practice |
1077 \snippet doc/src/snippets/declarative/gridview/gridview.qml import |
923 the model would be implemented in C++, or perhaps via a SQL data source. |
1078 \codeline |
|
1079 \snippet doc/src/snippets/declarative/gridview/gridview.qml classdocs simple |
|
1080 \image gridview-simple.png |
|
1081 |
|
1082 Here, the GridView creates a \c ContactModel component for its model, and a \l Column element |
|
1083 (containing \l Image and \ Text elements) for its delegate. The view will create a new delegate |
|
1084 for each item in the model. Notice the delegate is able to access the model's \c name and |
|
1085 \c portrait data directly. |
|
1086 |
|
1087 An improved grid view is shown below. The delegate is visually improved and is moved |
|
1088 into a separate \c contactDelegate component. Also, the currently selected item is highlighted |
|
1089 with a blue \l Rectangle using the \l highlight property, and \c focus is set to \c true |
|
1090 to enable keyboard navigation for the grid view. |
|
1091 |
|
1092 \snippet doc/src/snippets/declarative/gridview/gridview.qml classdocs advanced |
|
1093 \image gridview-highlight.png |
924 |
1094 |
925 Delegates are instantiated as needed and may be destroyed at any time. |
1095 Delegates are instantiated as needed and may be destroyed at any time. |
926 State should \e never be stored in a delegate. |
1096 State should \e never be stored in a delegate. |
927 |
1097 |
928 \bold Note that views do not enable \e clip automatically. If the view |
1098 \note Views do not enable \e clip automatically. If the view |
929 is not clipped by another item or the screen, it will be necessary |
1099 is not clipped by another item or the screen, it will be necessary |
930 to set \e {clip: true} in order to have the out of view items clipped |
1100 to set \e {clip: true} in order to have the out of view items clipped |
931 nicely. |
1101 nicely. |
|
1102 |
|
1103 \sa {declarative/modelviews/gridview}{GridView example} |
932 */ |
1104 */ |
933 QDeclarativeGridView::QDeclarativeGridView(QDeclarativeItem *parent) |
1105 QDeclarativeGridView::QDeclarativeGridView(QDeclarativeItem *parent) |
934 : QDeclarativeFlickable(*(new QDeclarativeGridViewPrivate), parent) |
1106 : QDeclarativeFlickable(*(new QDeclarativeGridViewPrivate), parent) |
935 { |
1107 { |
936 Q_D(QDeclarativeGridView); |
1108 Q_D(QDeclarativeGridView); |
969 until an animation completes. |
1143 until an animation completes. |
970 |
1144 |
971 The example below ensures that the animation completes before |
1145 The example below ensures that the animation completes before |
972 the item is removed from the grid. |
1146 the item is removed from the grid. |
973 |
1147 |
974 \code |
1148 \snippet doc/src/snippets/declarative/gridview/gridview.qml delayRemove |
975 Component { |
|
976 id: myDelegate |
|
977 Item { |
|
978 id: wrapper |
|
979 GridView.onRemove: SequentialAnimation { |
|
980 PropertyAction { target: wrapper; property: "GridView.delayRemove"; value: true } |
|
981 NumberAnimation { target: wrapper; property: "scale"; to: 0; duration: 250; easing.type: Easing.InOutQuad } |
|
982 PropertyAction { target: wrapper; property: "GridView.delayRemove"; value: false } |
|
983 } |
|
984 } |
|
985 } |
|
986 \endcode |
|
987 */ |
1149 */ |
988 |
1150 |
989 /*! |
1151 /*! |
990 \qmlattachedsignal GridView::onAdd() |
1152 \qmlattachedsignal GridView::onAdd() |
991 This attached handler is called immediately after an item is added to the view. |
1153 This attached handler is called immediately after an item is added to the view. |
999 |
1161 |
1000 /*! |
1162 /*! |
1001 \qmlproperty model GridView::model |
1163 \qmlproperty model GridView::model |
1002 This property holds the model providing data for the grid. |
1164 This property holds the model providing data for the grid. |
1003 |
1165 |
1004 The model provides a set of data that is used to create the items |
1166 The model provides the set of data that is used to create the items |
1005 for the view. For large or dynamic datasets the model is usually |
1167 in the view. Models can be created directly in QML using \l ListModel, \l XmlListModel |
1006 provided by a C++ model object. The C++ model object must be a \l |
1168 or \l VisualItemModel, or provided by C++ model classes. If a C++ model class is |
1007 {QAbstractItemModel} subclass, a VisualModel, or a simple list. |
1169 used, it must be a subclass of \l QAbstractItemModel or a simple list. |
1008 |
1170 |
1009 \sa {qmlmodels}{Data Models} |
1171 \sa {qmlmodels}{Data Models} |
1010 */ |
1172 */ |
1011 QVariant QDeclarativeGridView::model() const |
1173 QVariant QDeclarativeGridView::model() const |
1012 { |
1174 { |
1052 if (d->currentIndex >= d->model->count() || d->currentIndex < 0) { |
1214 if (d->currentIndex >= d->model->count() || d->currentIndex < 0) { |
1053 setCurrentIndex(0); |
1215 setCurrentIndex(0); |
1054 } else { |
1216 } else { |
1055 d->moveReason = QDeclarativeGridViewPrivate::SetIndex; |
1217 d->moveReason = QDeclarativeGridViewPrivate::SetIndex; |
1056 d->updateCurrent(d->currentIndex); |
1218 d->updateCurrent(d->currentIndex); |
|
1219 if (d->highlight && d->currentItem) { |
|
1220 d->highlight->setPosition(d->currentItem->colPos(), d->currentItem->rowPos()); |
|
1221 d->updateTrackedItem(); |
|
1222 } |
|
1223 d->moveReason = QDeclarativeGridViewPrivate::Other; |
1057 } |
1224 } |
1058 } |
1225 } |
1059 connect(d->model, SIGNAL(itemsInserted(int,int)), this, SLOT(itemsInserted(int,int))); |
1226 connect(d->model, SIGNAL(itemsInserted(int,int)), this, SLOT(itemsInserted(int,int))); |
1060 connect(d->model, SIGNAL(itemsRemoved(int,int)), this, SLOT(itemsRemoved(int,int))); |
1227 connect(d->model, SIGNAL(itemsRemoved(int,int)), this, SLOT(itemsRemoved(int,int))); |
1061 connect(d->model, SIGNAL(itemsMoved(int,int,int)), this, SLOT(itemsMoved(int,int,int))); |
1228 connect(d->model, SIGNAL(itemsMoved(int,int,int)), this, SLOT(itemsMoved(int,int,int))); |
1077 The number of elements in the delegate has a direct effect on the |
1244 The number of elements in the delegate has a direct effect on the |
1078 flicking performance of the view. If at all possible, place functionality |
1245 flicking performance of the view. If at all possible, place functionality |
1079 that is not needed for the normal display of the delegate in a \l Loader which |
1246 that is not needed for the normal display of the delegate in a \l Loader which |
1080 can load additional elements when needed. |
1247 can load additional elements when needed. |
1081 |
1248 |
1082 Note that the GridView will layout the items based on the size of the root item |
1249 The GridView will layout the items based on the size of the root item |
1083 in the delegate. |
1250 in the delegate. |
1084 |
1251 |
1085 Here is an example delegate: |
1252 \note Delegates are instantiated as needed and may be destroyed at any time. |
1086 \snippet doc/src/snippets/declarative/gridview/gridview.qml 0 |
1253 State should \e never be stored in a delegate. |
1087 */ |
1254 */ |
1088 QDeclarativeComponent *QDeclarativeGridView::delegate() const |
1255 QDeclarativeComponent *QDeclarativeGridView::delegate() const |
1089 { |
1256 { |
1090 Q_D(const QDeclarativeGridView); |
1257 Q_D(const QDeclarativeGridView); |
1091 if (d->model) { |
1258 if (d->model) { |
1110 dataModel->setDelegate(delegate); |
1277 dataModel->setDelegate(delegate); |
1111 if (isComponentComplete()) { |
1278 if (isComponentComplete()) { |
1112 refill(); |
1279 refill(); |
1113 d->moveReason = QDeclarativeGridViewPrivate::SetIndex; |
1280 d->moveReason = QDeclarativeGridViewPrivate::SetIndex; |
1114 d->updateCurrent(d->currentIndex); |
1281 d->updateCurrent(d->currentIndex); |
|
1282 if (d->highlight && d->currentItem) { |
|
1283 d->highlight->setPosition(d->currentItem->colPos(), d->currentItem->rowPos()); |
|
1284 d->updateTrackedItem(); |
|
1285 } |
|
1286 d->moveReason = QDeclarativeGridViewPrivate::Other; |
1115 } |
1287 } |
1116 emit delegateChanged(); |
1288 emit delegateChanged(); |
1117 } |
1289 } |
1118 } |
1290 } |
1119 |
1291 |
1120 /*! |
1292 /*! |
1121 \qmlproperty int GridView::currentIndex |
1293 \qmlproperty int GridView::currentIndex |
1122 \qmlproperty Item GridView::currentItem |
1294 \qmlproperty Item GridView::currentItem |
1123 |
1295 |
1124 \c currentIndex holds the index of the current item. |
1296 The \c currentIndex property holds the index of the current item, and |
1125 \c currentItem is the current item. Note that the position of the current item |
1297 \c currentItem holds the current item. |
1126 may only be approximate until it becomes visible in the view. |
1298 |
|
1299 If highlightFollowsCurrentItem is \c true, setting either of these |
|
1300 properties will smoothly scroll the GridView so that the current |
|
1301 item becomes visible. |
|
1302 |
|
1303 Note that the position of the current item |
|
1304 may only be approximate until it becomes visible in the view. |
1127 */ |
1305 */ |
1128 int QDeclarativeGridView::currentIndex() const |
1306 int QDeclarativeGridView::currentIndex() const |
1129 { |
1307 { |
1130 Q_D(const QDeclarativeGridView); |
1308 Q_D(const QDeclarativeGridView); |
1131 return d->currentIndex; |
1309 return d->currentIndex; |
1136 Q_D(QDeclarativeGridView); |
1314 Q_D(QDeclarativeGridView); |
1137 if (d->requestedIndex >= 0) // currently creating item |
1315 if (d->requestedIndex >= 0) // currently creating item |
1138 return; |
1316 return; |
1139 if (isComponentComplete() && d->isValid() && index != d->currentIndex && index < d->model->count() && index >= 0) { |
1317 if (isComponentComplete() && d->isValid() && index != d->currentIndex && index < d->model->count() && index >= 0) { |
1140 d->moveReason = QDeclarativeGridViewPrivate::SetIndex; |
1318 d->moveReason = QDeclarativeGridViewPrivate::SetIndex; |
1141 cancelFlick(); |
|
1142 d->updateCurrent(index); |
1319 d->updateCurrent(index); |
1143 } else if (index != d->currentIndex) { |
1320 } else if (index != d->currentIndex) { |
1144 d->currentIndex = index; |
1321 d->currentIndex = index; |
1145 emit currentIndexChanged(); |
1322 emit currentIndexChanged(); |
1146 } |
1323 } |
1187 |
1363 |
1188 /*! |
1364 /*! |
1189 \qmlproperty Component GridView::highlight |
1365 \qmlproperty Component GridView::highlight |
1190 This property holds the component to use as the highlight. |
1366 This property holds the component to use as the highlight. |
1191 |
1367 |
1192 An instance of the highlight component will be created for each view. |
1368 An instance of the highlight component is created for each view. |
1193 The geometry of the resultant component instance will be managed by the view |
1369 The geometry of the resulting component instance will be managed by the view |
1194 so as to stay with the current item, unless the highlightFollowsCurrentItem property is false. |
1370 so as to stay with the current item, unless the highlightFollowsCurrentItem property is false. |
1195 |
|
1196 The below example demonstrates how to make a simple highlight: |
|
1197 \snippet doc/src/snippets/declarative/gridview/gridview.qml 1 |
|
1198 |
1371 |
1199 \sa highlightItem, highlightFollowsCurrentItem |
1372 \sa highlightItem, highlightFollowsCurrentItem |
1200 */ |
1373 */ |
1201 QDeclarativeComponent *QDeclarativeGridView::highlight() const |
1374 QDeclarativeComponent *QDeclarativeGridView::highlight() const |
1202 { |
1375 { |
1216 |
1389 |
1217 /*! |
1390 /*! |
1218 \qmlproperty bool GridView::highlightFollowsCurrentItem |
1391 \qmlproperty bool GridView::highlightFollowsCurrentItem |
1219 This property sets whether the highlight is managed by the view. |
1392 This property sets whether the highlight is managed by the view. |
1220 |
1393 |
1221 If highlightFollowsCurrentItem is true, the highlight will be moved smoothly |
1394 If this property is true (the default value), the highlight is moved smoothly |
1222 to follow the current item. If highlightFollowsCurrentItem is false, the |
1395 to follow the current item. Otherwise, the |
1223 highlight will not be moved by the view, and must be implemented |
1396 highlight is not moved by the view, and any movement must be implemented |
1224 by the highlight component, for example: |
1397 by the highlight. |
1225 |
1398 |
1226 \code |
1399 Here is a highlight with its motion defined by a \l {SpringAnimation} item: |
1227 Component { |
1400 |
1228 id: myHighlight |
1401 \snippet doc/src/snippets/declarative/gridview/gridview.qml highlightFollowsCurrentItem |
1229 Rectangle { |
|
1230 id: wrapper; color: "lightsteelblue"; radius: 4; width: 320; height: 60 |
|
1231 SpringFollow on y { source: wrapper.GridView.view.currentItem.y; spring: 3; damping: 0.2 } |
|
1232 SpringFollow on x { source: wrapper.GridView.view.currentItem.x; spring: 3; damping: 0.2 } |
|
1233 } |
|
1234 } |
|
1235 \endcode |
|
1236 */ |
1402 */ |
1237 bool QDeclarativeGridView::highlightFollowsCurrentItem() const |
1403 bool QDeclarativeGridView::highlightFollowsCurrentItem() const |
1238 { |
1404 { |
1239 Q_D(const QDeclarativeGridView); |
1405 Q_D(const QDeclarativeGridView); |
1240 return d->autoHighlight; |
1406 return d->autoHighlight; |
1288 /*! |
1454 /*! |
1289 \qmlproperty real GridView::preferredHighlightBegin |
1455 \qmlproperty real GridView::preferredHighlightBegin |
1290 \qmlproperty real GridView::preferredHighlightEnd |
1456 \qmlproperty real GridView::preferredHighlightEnd |
1291 \qmlproperty enumeration GridView::highlightRangeMode |
1457 \qmlproperty enumeration GridView::highlightRangeMode |
1292 |
1458 |
1293 These properties set the preferred range of the highlight (current item) |
1459 These properties define the preferred range of the highlight (for the current item) |
1294 within the view. |
1460 within the view. The \c preferredHighlightBegin value must be less than the |
1295 |
1461 \c preferredHighlightEnd value. |
1296 Note that this is the correct way to influence where the |
1462 |
1297 current item ends up when the view scrolls. For example, if you want the |
1463 These properties affect the position of the current item when the view is scrolled. |
1298 currently selected item to be in the middle of the list, then set the |
1464 For example, if the currently selected item should stay in the middle of the |
1299 highlight range to be where the middle item would go. Then, when the view scrolls, |
1465 view when it is scrolled, set the \c preferredHighlightBegin and |
1300 the currently selected item will be the item at that spot. This also applies to |
1466 \c preferredHighlightEnd values to the top and bottom coordinates of where the middle |
1301 when the currently selected item changes - it will scroll to within the preferred |
1467 item would be. If the \c currentItem is changed programmatically, the view will |
1302 highlight range. Furthermore, the behaviour of the current item index will occur |
1468 automatically scroll so that the current item is in the middle of the view. |
1303 whether or not a highlight exists. |
1469 Furthermore, the behavior of the current item index will occur whether or not a |
1304 |
1470 highlight exists. |
1305 If highlightRangeMode is set to \e GridView.ApplyRange the view will |
1471 |
1306 attempt to maintain the highlight within the range, however |
1472 Valid values for \c highlightRangeMode are: |
1307 the highlight can move outside of the range at the ends of the list |
1473 |
1308 or due to a mouse interaction. |
1474 \list |
1309 |
1475 \o GridView.ApplyRange - the view attempts to maintain the highlight within the range. |
1310 If highlightRangeMode is set to \e GridView.StrictlyEnforceRange the highlight will never |
1476 However, the highlight can move outside of the range at the ends of the view or due |
1311 move outside of the range. This means that the current item will change |
1477 to mouse interaction. |
1312 if a keyboard or mouse action would cause the highlight to move |
1478 \o GridView.StrictlyEnforceRange - the highlight never moves outside of the range. |
1313 outside of the range. |
1479 The current item changes if a keyboard or mouse action would cause the highlight to move |
1314 |
1480 outside of the range. |
1315 The default value is \e GridView.NoHighlightRange. |
1481 \o GridView.NoHighlightRange - this is the default value. |
1316 |
1482 \endlist |
1317 Note that a valid range requires preferredHighlightEnd to be greater |
|
1318 than or equal to preferredHighlightBegin. |
|
1319 */ |
1483 */ |
1320 qreal QDeclarativeGridView::preferredHighlightBegin() const |
1484 qreal QDeclarativeGridView::preferredHighlightBegin() const |
1321 { |
1485 { |
1322 Q_D(const QDeclarativeGridView); |
1486 Q_D(const QDeclarativeGridView); |
1323 return d->highlightRangeStart; |
1487 return d->highlightRangeStart; |
1368 |
1532 |
1369 /*! |
1533 /*! |
1370 \qmlproperty enumeration GridView::flow |
1534 \qmlproperty enumeration GridView::flow |
1371 This property holds the flow of the grid. |
1535 This property holds the flow of the grid. |
1372 |
1536 |
1373 Possible values are \c GridView.LeftToRight (default) and \c GridView.TopToBottom. |
1537 Possible values: |
1374 |
1538 |
1375 If \a flow is \c GridView.LeftToRight, the view will scroll vertically. |
1539 \list |
1376 If \a flow is \c GridView.TopToBottom, the view will scroll horizontally. |
1540 \o GridView.LeftToRight (default) - Items are laid out from left to right, and the view scrolls vertically |
|
1541 \o GridView.TopToBottom - Items are laid out from top to bottom, and the view scrolls horizontally |
|
1542 \endlist |
1377 */ |
1543 */ |
1378 QDeclarativeGridView::Flow QDeclarativeGridView::flow() const |
1544 QDeclarativeGridView::Flow QDeclarativeGridView::flow() const |
1379 { |
1545 { |
1380 Q_D(const QDeclarativeGridView); |
1546 Q_D(const QDeclarativeGridView); |
1381 return d->flow; |
1547 return d->flow; |
1403 |
1569 |
1404 /*! |
1570 /*! |
1405 \qmlproperty bool GridView::keyNavigationWraps |
1571 \qmlproperty bool GridView::keyNavigationWraps |
1406 This property holds whether the grid wraps key navigation |
1572 This property holds whether the grid wraps key navigation |
1407 |
1573 |
1408 If this property is true then key presses to move off of one end of the grid will cause the |
1574 If this is true, key navigation that would move the current item selection |
1409 selection to jump to the other side. |
1575 past one end of the view instead wraps around and moves the selection to |
|
1576 the other end of the view. |
|
1577 |
|
1578 By default, key navigation is not wrapped. |
1410 */ |
1579 */ |
1411 bool QDeclarativeGridView::isWrapEnabled() const |
1580 bool QDeclarativeGridView::isWrapEnabled() const |
1412 { |
1581 { |
1413 Q_D(const QDeclarativeGridView); |
1582 Q_D(const QDeclarativeGridView); |
1414 return d->wrap; |
1583 return d->wrap; |
1501 } |
1670 } |
1502 } |
1671 } |
1503 /*! |
1672 /*! |
1504 \qmlproperty enumeration GridView::snapMode |
1673 \qmlproperty enumeration GridView::snapMode |
1505 |
1674 |
1506 This property determines where the view will settle following a drag or flick. |
1675 This property determines how the view scrolling will settle following a drag or flick. |
1507 The allowed values are: |
1676 The possible values are: |
1508 |
1677 |
1509 \list |
1678 \list |
1510 \o GridView.NoSnap (default) - the view will stop anywhere within the visible area. |
1679 \o GridView.NoSnap (default) - the view stops anywhere within the visible area. |
1511 \o GridView.SnapToRow - the view will settle with a row (or column for TopToBottom flow) |
1680 \o GridView.SnapToRow - the view settles with a row (or column for \c GridView.TopToBottom flow) |
1512 aligned with the start of the view. |
1681 aligned with the start of the view. |
1513 \o GridView.SnapOneRow - the view will settle no more than one row (or column for TopToBottom flow) |
1682 \o GridView.SnapOneRow - the view will settle no more than one row (or column for \c GridView.TopToBottom flow) |
1514 away from the first visible row at the time the mouse button is released. |
1683 away from the first visible row at the time the mouse button is released. |
1515 This mode is particularly useful for moving one page at a time. |
1684 This mode is particularly useful for moving one page at a time. |
1516 \endlist |
1685 \endlist |
1517 |
1686 |
1518 */ |
1687 */ |
1527 Q_D(QDeclarativeGridView); |
1696 Q_D(QDeclarativeGridView); |
1528 if (d->snapMode != mode) { |
1697 if (d->snapMode != mode) { |
1529 d->snapMode = mode; |
1698 d->snapMode = mode; |
1530 emit snapModeChanged(); |
1699 emit snapModeChanged(); |
1531 } |
1700 } |
|
1701 } |
|
1702 |
|
1703 /*! |
|
1704 \qmlproperty Component GridView::footer |
|
1705 This property holds the component to use as the footer. |
|
1706 |
|
1707 An instance of the footer component is created for each view. The |
|
1708 footer is positioned at the end of the view, after any items. |
|
1709 |
|
1710 \sa header |
|
1711 */ |
|
1712 QDeclarativeComponent *QDeclarativeGridView::footer() const |
|
1713 { |
|
1714 Q_D(const QDeclarativeGridView); |
|
1715 return d->footerComponent; |
|
1716 } |
|
1717 |
|
1718 void QDeclarativeGridView::setFooter(QDeclarativeComponent *footer) |
|
1719 { |
|
1720 Q_D(QDeclarativeGridView); |
|
1721 if (d->footerComponent != footer) { |
|
1722 if (d->footer) { |
|
1723 delete d->footer; |
|
1724 d->footer = 0; |
|
1725 } |
|
1726 d->footerComponent = footer; |
|
1727 d->updateFooter(); |
|
1728 d->updateGrid(); |
|
1729 emit footerChanged(); |
|
1730 } |
|
1731 } |
|
1732 |
|
1733 /*! |
|
1734 \qmlproperty Component GridView::header |
|
1735 This property holds the component to use as the header. |
|
1736 |
|
1737 An instance of the header component is created for each view. The |
|
1738 header is positioned at the beginning of the view, before any items. |
|
1739 |
|
1740 \sa footer |
|
1741 */ |
|
1742 QDeclarativeComponent *QDeclarativeGridView::header() const |
|
1743 { |
|
1744 Q_D(const QDeclarativeGridView); |
|
1745 return d->headerComponent; |
|
1746 } |
|
1747 |
|
1748 void QDeclarativeGridView::setHeader(QDeclarativeComponent *header) |
|
1749 { |
|
1750 Q_D(QDeclarativeGridView); |
|
1751 if (d->headerComponent != header) { |
|
1752 if (d->header) { |
|
1753 delete d->header; |
|
1754 d->header = 0; |
|
1755 } |
|
1756 d->headerComponent = header; |
|
1757 d->updateHeader(); |
|
1758 d->updateFooter(); |
|
1759 d->updateGrid(); |
|
1760 emit headerChanged(); |
|
1761 } |
|
1762 } |
|
1763 |
|
1764 void QDeclarativeGridView::setContentX(qreal pos) |
|
1765 { |
|
1766 Q_D(QDeclarativeGridView); |
|
1767 // Positioning the view manually should override any current movement state |
|
1768 d->moveReason = QDeclarativeGridViewPrivate::Other; |
|
1769 QDeclarativeFlickable::setContentX(pos); |
|
1770 } |
|
1771 |
|
1772 void QDeclarativeGridView::setContentY(qreal pos) |
|
1773 { |
|
1774 Q_D(QDeclarativeGridView); |
|
1775 // Positioning the view manually should override any current movement state |
|
1776 d->moveReason = QDeclarativeGridViewPrivate::Other; |
|
1777 QDeclarativeFlickable::setContentY(pos); |
1532 } |
1778 } |
1533 |
1779 |
1534 bool QDeclarativeGridView::event(QEvent *event) |
1780 bool QDeclarativeGridView::event(QEvent *event) |
1535 { |
1781 { |
1536 Q_D(QDeclarativeGridView); |
1782 Q_D(QDeclarativeGridView); |
1595 { |
1841 { |
1596 Q_D(const QDeclarativeGridView); |
1842 Q_D(const QDeclarativeGridView); |
1597 if (d->flow == QDeclarativeGridView::TopToBottom) |
1843 if (d->flow == QDeclarativeGridView::TopToBottom) |
1598 return QDeclarativeFlickable::minYExtent(); |
1844 return QDeclarativeFlickable::minYExtent(); |
1599 qreal extent = -d->startPosition(); |
1845 qreal extent = -d->startPosition(); |
|
1846 if (d->header && d->visibleItems.count()) |
|
1847 extent += d->header->item->height(); |
1600 if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange) { |
1848 if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange) { |
1601 extent += d->highlightRangeStart; |
1849 extent += d->highlightRangeStart; |
1602 extent = qMax(extent, -(d->rowPosAt(0) + d->rowSize() - d->highlightRangeEnd)); |
1850 extent = qMax(extent, -(d->rowPosAt(0) + d->rowSize() - d->highlightRangeEnd)); |
1603 } |
1851 } |
1604 return extent; |
1852 return extent; |
1608 { |
1856 { |
1609 Q_D(const QDeclarativeGridView); |
1857 Q_D(const QDeclarativeGridView); |
1610 if (d->flow == QDeclarativeGridView::TopToBottom) |
1858 if (d->flow == QDeclarativeGridView::TopToBottom) |
1611 return QDeclarativeFlickable::maxYExtent(); |
1859 return QDeclarativeFlickable::maxYExtent(); |
1612 qreal extent; |
1860 qreal extent; |
1613 if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange) { |
1861 if (!d->model || !d->model->count()) { |
|
1862 extent = 0; |
|
1863 } else if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange) { |
1614 extent = -(d->rowPosAt(d->model->count()-1) - d->highlightRangeStart); |
1864 extent = -(d->rowPosAt(d->model->count()-1) - d->highlightRangeStart); |
1615 if (d->highlightRangeEnd != d->highlightRangeStart) |
1865 if (d->highlightRangeEnd != d->highlightRangeStart) |
1616 extent = qMin(extent, -(d->endPosition() - d->highlightRangeEnd + 1)); |
1866 extent = qMin(extent, -(d->endPosition() - d->highlightRangeEnd + 1)); |
1617 } else { |
1867 } else { |
1618 extent = -(d->endPosition() - height()); |
1868 extent = -(d->endPosition() - height()); |
1619 } |
1869 } |
|
1870 if (d->footer) |
|
1871 extent -= d->footer->item->height(); |
1620 const qreal minY = minYExtent(); |
1872 const qreal minY = minYExtent(); |
1621 if (extent > minY) |
1873 if (extent > minY) |
1622 extent = minY; |
1874 extent = minY; |
1623 return extent; |
1875 return extent; |
1624 } |
1876 } |
1627 { |
1879 { |
1628 Q_D(const QDeclarativeGridView); |
1880 Q_D(const QDeclarativeGridView); |
1629 if (d->flow == QDeclarativeGridView::LeftToRight) |
1881 if (d->flow == QDeclarativeGridView::LeftToRight) |
1630 return QDeclarativeFlickable::minXExtent(); |
1882 return QDeclarativeFlickable::minXExtent(); |
1631 qreal extent = -d->startPosition(); |
1883 qreal extent = -d->startPosition(); |
|
1884 if (d->header && d->visibleItems.count()) |
|
1885 extent += d->header->item->width(); |
1632 if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange) { |
1886 if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange) { |
1633 extent += d->highlightRangeStart; |
1887 extent += d->highlightRangeStart; |
1634 extent = qMax(extent, -(d->rowPosAt(0) + d->rowSize() - d->highlightRangeEnd)); |
1888 extent = qMax(extent, -(d->rowPosAt(0) + d->rowSize() - d->highlightRangeEnd)); |
1635 } |
1889 } |
1636 return extent; |
1890 return extent; |
1640 { |
1894 { |
1641 Q_D(const QDeclarativeGridView); |
1895 Q_D(const QDeclarativeGridView); |
1642 if (d->flow == QDeclarativeGridView::LeftToRight) |
1896 if (d->flow == QDeclarativeGridView::LeftToRight) |
1643 return QDeclarativeFlickable::maxXExtent(); |
1897 return QDeclarativeFlickable::maxXExtent(); |
1644 qreal extent; |
1898 qreal extent; |
1645 if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange) { |
1899 if (!d->model || !d->model->count()) { |
|
1900 extent = 0; |
|
1901 } if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange) { |
1646 extent = -(d->rowPosAt(d->model->count()-1) - d->highlightRangeStart); |
1902 extent = -(d->rowPosAt(d->model->count()-1) - d->highlightRangeStart); |
1647 if (d->highlightRangeEnd != d->highlightRangeStart) |
1903 if (d->highlightRangeEnd != d->highlightRangeStart) |
1648 extent = qMin(extent, -(d->endPosition() - d->highlightRangeEnd + 1)); |
1904 extent = qMin(extent, -(d->endPosition() - d->highlightRangeEnd + 1)); |
1649 } else { |
1905 } else { |
1650 extent = -(d->endPosition() - height()); |
1906 extent = -(d->endPosition() - width()); |
1651 } |
1907 } |
|
1908 if (d->footer) |
|
1909 extent -= d->footer->item->width(); |
1652 const qreal minX = minXExtent(); |
1910 const qreal minX = minXExtent(); |
1653 if (extent > minX) |
1911 if (extent > minX) |
1654 extent = minX; |
1912 extent = minX; |
1655 return extent; |
1913 return extent; |
1656 } |
1914 } |
1694 \qmlmethod GridView::moveCurrentIndexUp() |
1952 \qmlmethod GridView::moveCurrentIndexUp() |
1695 |
1953 |
1696 Move the currentIndex up one item in the view. |
1954 Move the currentIndex up one item in the view. |
1697 The current index will wrap if keyNavigationWraps is true and it |
1955 The current index will wrap if keyNavigationWraps is true and it |
1698 is currently at the end. |
1956 is currently at the end. |
|
1957 |
|
1958 \bold Note: methods should only be called after the Component has completed. |
1699 */ |
1959 */ |
1700 void QDeclarativeGridView::moveCurrentIndexUp() |
1960 void QDeclarativeGridView::moveCurrentIndexUp() |
1701 { |
1961 { |
1702 Q_D(QDeclarativeGridView); |
1962 Q_D(QDeclarativeGridView); |
1703 if (d->flow == QDeclarativeGridView::LeftToRight) { |
1963 if (d->flow == QDeclarativeGridView::LeftToRight) { |
1717 \qmlmethod GridView::moveCurrentIndexDown() |
1977 \qmlmethod GridView::moveCurrentIndexDown() |
1718 |
1978 |
1719 Move the currentIndex down one item in the view. |
1979 Move the currentIndex down one item in the view. |
1720 The current index will wrap if keyNavigationWraps is true and it |
1980 The current index will wrap if keyNavigationWraps is true and it |
1721 is currently at the end. |
1981 is currently at the end. |
|
1982 |
|
1983 \bold Note: methods should only be called after the Component has completed. |
1722 */ |
1984 */ |
1723 void QDeclarativeGridView::moveCurrentIndexDown() |
1985 void QDeclarativeGridView::moveCurrentIndexDown() |
1724 { |
1986 { |
1725 Q_D(QDeclarativeGridView); |
1987 Q_D(QDeclarativeGridView); |
1726 if (d->flow == QDeclarativeGridView::LeftToRight) { |
1988 if (d->flow == QDeclarativeGridView::LeftToRight) { |
1740 \qmlmethod GridView::moveCurrentIndexLeft() |
2002 \qmlmethod GridView::moveCurrentIndexLeft() |
1741 |
2003 |
1742 Move the currentIndex left one item in the view. |
2004 Move the currentIndex left one item in the view. |
1743 The current index will wrap if keyNavigationWraps is true and it |
2005 The current index will wrap if keyNavigationWraps is true and it |
1744 is currently at the end. |
2006 is currently at the end. |
|
2007 |
|
2008 \bold Note: methods should only be called after the Component has completed. |
1745 */ |
2009 */ |
1746 void QDeclarativeGridView::moveCurrentIndexLeft() |
2010 void QDeclarativeGridView::moveCurrentIndexLeft() |
1747 { |
2011 { |
1748 Q_D(QDeclarativeGridView); |
2012 Q_D(QDeclarativeGridView); |
1749 if (d->flow == QDeclarativeGridView::LeftToRight) { |
2013 if (d->flow == QDeclarativeGridView::LeftToRight) { |
1763 \qmlmethod GridView::moveCurrentIndexRight() |
2027 \qmlmethod GridView::moveCurrentIndexRight() |
1764 |
2028 |
1765 Move the currentIndex right one item in the view. |
2029 Move the currentIndex right one item in the view. |
1766 The current index will wrap if keyNavigationWraps is true and it |
2030 The current index will wrap if keyNavigationWraps is true and it |
1767 is currently at the end. |
2031 is currently at the end. |
|
2032 |
|
2033 \bold Note: methods should only be called after the Component has completed. |
1768 */ |
2034 */ |
1769 void QDeclarativeGridView::moveCurrentIndexRight() |
2035 void QDeclarativeGridView::moveCurrentIndexRight() |
1770 { |
2036 { |
1771 Q_D(QDeclarativeGridView); |
2037 Q_D(QDeclarativeGridView); |
1772 if (d->flow == QDeclarativeGridView::LeftToRight) { |
2038 if (d->flow == QDeclarativeGridView::LeftToRight) { |
1787 |
2053 |
1788 Positions the view such that the \a index is at the position specified by |
2054 Positions the view such that the \a index is at the position specified by |
1789 \a mode: |
2055 \a mode: |
1790 |
2056 |
1791 \list |
2057 \list |
1792 \o Beginning - position item at the top (or left for TopToBottom flow) of the view. |
2058 \o GridView.Beginning - position item at the top (or left for \c GridView.TopToBottom flow) of the view. |
1793 \o Center- position item in the center of the view. |
2059 \o GridView.Center - position item in the center of the view. |
1794 \o End - position item at bottom (or right for horizontal orientation) of the view. |
2060 \o GridView.End - position item at bottom (or right for horizontal orientation) of the view. |
1795 \o Visible - if any part of the item is visible then take no action, otherwise |
2061 \o GridView.Visible - if any part of the item is visible then take no action, otherwise |
1796 bring the item into view. |
2062 bring the item into view. |
1797 \o Contain - ensure the entire item is visible. If the item is larger than |
2063 \o GridView.Contain - ensure the entire item is visible. If the item is larger than |
1798 the view the item is positioned at the top (or left for TopToBottom flow) of the view. |
2064 the view the item is positioned at the top (or left for \c GridView.TopToBottom flow) of the view. |
1799 \endlist |
2065 \endlist |
1800 |
2066 |
1801 If positioning the view at the index would cause empty space to be displayed at |
2067 If positioning the view at the index would cause empty space to be displayed at |
1802 the beginning or end of the view, the view will be positioned at the boundary. |
2068 the beginning or end of the view, the view will be positioned at the boundary. |
1803 |
2069 |
1804 It is not recommended to use contentX or contentY to position the view |
2070 It is not recommended to use \l {Flickable::}{contentX} or \l {Flickable::}{contentY} to position the view |
1805 at a particular index. This is unreliable since removing items from the start |
2071 at a particular index. This is unreliable since removing items from the start |
1806 of the view does not cause all other items to be repositioned. |
2072 of the view does not cause all other items to be repositioned. |
1807 The correct way to bring an item into view is with positionViewAtIndex. |
2073 The correct way to bring an item into view is with \c positionViewAtIndex. |
|
2074 |
|
2075 \bold Note: methods should only be called after the Component has completed. To position |
|
2076 the view at startup, this method should be called by Component.onCompleted. For |
|
2077 example, to position the view at the end: |
|
2078 |
|
2079 \code |
|
2080 Component.onCompleted: positionViewAtIndex(count - 1, GridView.Beginning) |
|
2081 \endcode |
1808 */ |
2082 */ |
1809 void QDeclarativeGridView::positionViewAtIndex(int index, int mode) |
2083 void QDeclarativeGridView::positionViewAtIndex(int index, int mode) |
1810 { |
2084 { |
1811 Q_D(QDeclarativeGridView); |
2085 Q_D(QDeclarativeGridView); |
1812 if (!d->isValid() || index < 0 || index >= d->model->count()) |
2086 if (!d->isValid() || index < 0 || index >= d->model->count()) |
1813 return; |
2087 return; |
1814 if (mode < Beginning || mode > Contain) |
2088 if (mode < Beginning || mode > Contain) |
1815 return; |
2089 return; |
1816 |
2090 |
|
2091 if (d->layoutScheduled) |
|
2092 d->layout(); |
1817 qreal pos = d->position(); |
2093 qreal pos = d->position(); |
1818 FxGridItem *item = d->visibleItem(index); |
2094 FxGridItem *item = d->visibleItem(index); |
1819 if (!item) { |
2095 if (!item) { |
1820 int itemPos = d->rowPosAt(index); |
2096 int itemPos = d->rowPosAt(index); |
1821 // save the currently visible items in case any of them end up visible again |
2097 // save the currently visible items in case any of them end up visible again |
1868 coordinates. If there is no item at the point specified, or the item is |
2146 coordinates. If there is no item at the point specified, or the item is |
1869 not visible -1 is returned. |
2147 not visible -1 is returned. |
1870 |
2148 |
1871 If the item is outside the visible area, -1 is returned, regardless of |
2149 If the item is outside the visible area, -1 is returned, regardless of |
1872 whether an item will exist at that point when scrolled into view. |
2150 whether an item will exist at that point when scrolled into view. |
|
2151 |
|
2152 \bold Note: methods should only be called after the Component has completed. |
1873 */ |
2153 */ |
1874 int QDeclarativeGridView::indexAt(int x, int y) const |
2154 int QDeclarativeGridView::indexAt(int x, int y) const |
1875 { |
2155 { |
1876 Q_D(const QDeclarativeGridView); |
2156 Q_D(const QDeclarativeGridView); |
1877 for (int i = 0; i < d->visibleItems.count(); ++i) { |
2157 for (int i = 0; i < d->visibleItems.count(); ++i) { |
1888 Q_D(QDeclarativeGridView); |
2168 Q_D(QDeclarativeGridView); |
1889 QDeclarativeFlickable::componentComplete(); |
2169 QDeclarativeFlickable::componentComplete(); |
1890 d->updateGrid(); |
2170 d->updateGrid(); |
1891 if (d->isValid()) { |
2171 if (d->isValid()) { |
1892 refill(); |
2172 refill(); |
|
2173 d->moveReason = QDeclarativeGridViewPrivate::SetIndex; |
1893 if (d->currentIndex < 0) |
2174 if (d->currentIndex < 0) |
1894 d->updateCurrent(0); |
2175 d->updateCurrent(0); |
1895 else |
2176 else |
1896 d->updateCurrent(d->currentIndex); |
2177 d->updateCurrent(d->currentIndex); |
|
2178 if (d->highlight && d->currentItem) { |
|
2179 d->highlight->setPosition(d->currentItem->colPos(), d->currentItem->rowPos()); |
|
2180 d->updateTrackedItem(); |
|
2181 } |
|
2182 d->moveReason = QDeclarativeGridViewPrivate::Other; |
1897 d->fixupPosition(); |
2183 d->fixupPosition(); |
1898 } |
2184 } |
1899 } |
2185 } |
1900 |
2186 |
1901 void QDeclarativeGridView::trackedPositionChanged() |
2187 void QDeclarativeGridView::trackedPositionChanged() |
1902 { |
2188 { |
1903 Q_D(QDeclarativeGridView); |
2189 Q_D(QDeclarativeGridView); |
1904 if (!d->trackedItem || !d->currentItem) |
2190 if (!d->trackedItem || !d->currentItem) |
1905 return; |
2191 return; |
1906 if (!d->flickingHorizontally && !d->flickingVertically && !d->movingHorizontally && !d->movingVertically |
2192 if (d->moveReason == QDeclarativeGridViewPrivate::SetIndex) { |
1907 && d->moveReason == QDeclarativeGridViewPrivate::SetIndex) { |
|
1908 const qreal trackedPos = d->trackedItem->rowPos(); |
2193 const qreal trackedPos = d->trackedItem->rowPos(); |
1909 const qreal viewPos = d->position(); |
2194 const qreal viewPos = d->position(); |
|
2195 qreal pos = viewPos; |
1910 if (d->haveHighlightRange) { |
2196 if (d->haveHighlightRange) { |
1911 if (d->highlightRange == StrictlyEnforceRange) { |
2197 if (d->highlightRange == StrictlyEnforceRange) { |
1912 qreal pos = viewPos; |
|
1913 if (trackedPos > pos + d->highlightRangeEnd - d->rowSize()) |
2198 if (trackedPos > pos + d->highlightRangeEnd - d->rowSize()) |
1914 pos = trackedPos - d->highlightRangeEnd + d->rowSize(); |
2199 pos = trackedPos - d->highlightRangeEnd + d->rowSize(); |
1915 if (trackedPos < pos + d->highlightRangeStart) |
2200 if (trackedPos < pos + d->highlightRangeStart) |
1916 pos = trackedPos - d->highlightRangeStart; |
2201 pos = trackedPos - d->highlightRangeStart; |
1917 d->setPosition(pos); |
|
1918 } else { |
2202 } else { |
1919 qreal pos = viewPos; |
|
1920 if (trackedPos < d->startPosition() + d->highlightRangeStart) { |
2203 if (trackedPos < d->startPosition() + d->highlightRangeStart) { |
1921 pos = d->startPosition(); |
2204 pos = d->startPosition(); |
1922 } else if (d->trackedItem->endRowPos() > d->endPosition() - d->size() + d->highlightRangeEnd) { |
2205 } else if (d->trackedItem->endRowPos() > d->endPosition() - d->size() + d->highlightRangeEnd) { |
1923 pos = d->endPosition() - d->size(); |
2206 pos = d->endPosition() - d->size(); |
1924 if (pos < d->startPosition()) |
2207 if (pos < d->startPosition()) |
1928 pos = trackedPos - d->highlightRangeStart; |
2211 pos = trackedPos - d->highlightRangeStart; |
1929 } else if (trackedPos > viewPos + d->highlightRangeEnd - d->rowSize()) { |
2212 } else if (trackedPos > viewPos + d->highlightRangeEnd - d->rowSize()) { |
1930 pos = trackedPos - d->highlightRangeEnd + d->rowSize(); |
2213 pos = trackedPos - d->highlightRangeEnd + d->rowSize(); |
1931 } |
2214 } |
1932 } |
2215 } |
1933 d->setPosition(pos); |
|
1934 } |
2216 } |
1935 } else { |
2217 } else { |
1936 if (trackedPos < viewPos && d->currentItem->rowPos() < viewPos) { |
2218 if (trackedPos < viewPos && d->currentItem->rowPos() < viewPos) { |
1937 d->setPosition(d->currentItem->rowPos() < trackedPos ? trackedPos : d->currentItem->rowPos()); |
2219 pos = d->currentItem->rowPos() < trackedPos ? trackedPos : d->currentItem->rowPos(); |
1938 } else if (d->trackedItem->endRowPos() > viewPos + d->size() |
2220 } else if (d->trackedItem->endRowPos() > viewPos + d->size() |
1939 && d->currentItem->endRowPos() > viewPos + d->size()) { |
2221 && d->currentItem->endRowPos() > viewPos + d->size()) { |
1940 qreal pos; |
|
1941 if (d->trackedItem->endRowPos() < d->currentItem->endRowPos()) { |
2222 if (d->trackedItem->endRowPos() < d->currentItem->endRowPos()) { |
1942 pos = d->trackedItem->endRowPos() - d->size(); |
2223 pos = d->trackedItem->endRowPos() - d->size(); |
1943 if (d->rowSize() > d->size()) |
2224 if (d->rowSize() > d->size()) |
1944 pos = trackedPos; |
2225 pos = trackedPos; |
1945 } else { |
2226 } else { |
1946 pos = d->currentItem->endRowPos() - d->size(); |
2227 pos = d->currentItem->endRowPos() - d->size(); |
1947 if (d->rowSize() > d->size()) |
2228 if (d->rowSize() > d->size()) |
1948 pos = d->currentItem->rowPos(); |
2229 pos = d->currentItem->rowPos(); |
1949 } |
2230 } |
1950 d->setPosition(pos); |
2231 } |
1951 } |
2232 } |
|
2233 if (viewPos != pos) { |
|
2234 cancelFlick(); |
|
2235 d->setPosition(pos); |
1952 } |
2236 } |
1953 } |
2237 } |
1954 } |
2238 } |
1955 |
2239 |
1956 void QDeclarativeGridView::itemsInserted(int modelIndex, int count) |
2240 void QDeclarativeGridView::itemsInserted(int modelIndex, int count) |
2292 Q_D(QDeclarativeGridView); |
2579 Q_D(QDeclarativeGridView); |
2293 d->clear(); |
2580 d->clear(); |
2294 refill(); |
2581 refill(); |
2295 d->moveReason = QDeclarativeGridViewPrivate::SetIndex; |
2582 d->moveReason = QDeclarativeGridViewPrivate::SetIndex; |
2296 d->updateCurrent(d->currentIndex); |
2583 d->updateCurrent(d->currentIndex); |
|
2584 if (d->highlight && d->currentItem) { |
|
2585 d->highlight->setPosition(d->currentItem->colPos(), d->currentItem->rowPos()); |
|
2586 d->updateTrackedItem(); |
|
2587 } |
|
2588 d->moveReason = QDeclarativeGridViewPrivate::Other; |
|
2589 |
2297 emit countChanged(); |
2590 emit countChanged(); |
2298 } |
2591 } |
2299 |
2592 |
2300 void QDeclarativeGridView::createdItem(int index, QDeclarativeItem *item) |
2593 void QDeclarativeGridView::createdItem(int index, QDeclarativeItem *item) |
2301 { |
2594 { |