1 | // Copyright (C) 2016 The Qt Company Ltd. |
---|---|
2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only |
3 | |
4 | #ifndef QLISTVIEW_P_H |
5 | #define QLISTVIEW_P_H |
6 | |
7 | // |
8 | // W A R N I N G |
9 | // ------------- |
10 | // |
11 | // This file is not part of the Qt API. It exists for the convenience |
12 | // of other Qt classes. This header file may change from version to |
13 | // version without notice, or even be removed. |
14 | // |
15 | // We mean it. |
16 | // |
17 | |
18 | #include <QtWidgets/private/qtwidgetsglobal_p.h> |
19 | #include "qlistview.h" |
20 | #include "private/qabstractitemview_p.h" |
21 | #include "qbitarray.h" |
22 | #include "qbsptree_p.h" |
23 | #include <limits.h> |
24 | #include <qscrollbar.h> |
25 | |
26 | QT_REQUIRE_CONFIG(listview); |
27 | |
28 | QT_BEGIN_NAMESPACE |
29 | |
30 | class QListViewItem |
31 | { |
32 | friend class QListViewPrivate; |
33 | friend class QListModeViewBase; |
34 | friend class QIconModeViewBase; |
35 | public: |
36 | constexpr QListViewItem() |
37 | : x(-1), y(-1), w(0), h(0), indexHint(-1), visited(0xffff) {} |
38 | constexpr QListViewItem(QRect r, int i) |
39 | : x(r.x()), y(r.y()), w(qMin(a: r.width(), SHRT_MAX)), h(qMin(a: r.height(), SHRT_MAX)), |
40 | indexHint(i), visited(0xffff) {} |
41 | constexpr bool operator==(const QListViewItem &other) const { |
42 | return (x == other.x && y == other.y && w == other.w && h == other.h && |
43 | indexHint == other.indexHint); } |
44 | constexpr bool operator!=(const QListViewItem &other) const |
45 | { return !(*this == other); } |
46 | constexpr bool isValid() const |
47 | { return rect().isValid() && (indexHint > -1); } |
48 | constexpr void invalidate() |
49 | { x = -1; y = -1; w = 0; h = 0; } |
50 | constexpr void resize(QSize size) |
51 | { w = qMin(a: size.width(), SHRT_MAX); h = qMin(a: size.height(), SHRT_MAX); } |
52 | constexpr void move(QPoint position) |
53 | { x = position.x(); y = position.y(); } |
54 | constexpr int width() const { return w; } |
55 | constexpr int height() const { return h; } |
56 | private: |
57 | constexpr QRect rect() const |
58 | { return QRect(x, y, w, h); } |
59 | int x, y; |
60 | short w, h; |
61 | mutable int indexHint; |
62 | uint visited; |
63 | }; |
64 | Q_DECLARE_TYPEINFO(QListViewItem, Q_PRIMITIVE_TYPE); |
65 | |
66 | struct QListViewLayoutInfo |
67 | { |
68 | QRect bounds; |
69 | QSize grid; |
70 | int spacing; |
71 | int first; |
72 | int last; |
73 | bool wrap; |
74 | QListView::Flow flow; |
75 | int max; |
76 | }; |
77 | Q_DECLARE_TYPEINFO(QListViewLayoutInfo, Q_PRIMITIVE_TYPE); |
78 | |
79 | class QListView; |
80 | class QListViewPrivate; |
81 | |
82 | class QCommonListViewBase |
83 | { |
84 | public: |
85 | inline QCommonListViewBase(QListView *q, QListViewPrivate *d) : dd(d), qq(q), batchStartRow(0), batchSavedDeltaSeg(0) {} |
86 | virtual ~QCommonListViewBase() {} |
87 | |
88 | //common interface |
89 | virtual int itemIndex(const QListViewItem &item) const = 0; |
90 | virtual QListViewItem indexToListViewItem(const QModelIndex &index) const = 0; |
91 | virtual bool doBatchedItemLayout(const QListViewLayoutInfo &info, int max) = 0; |
92 | virtual void clear() = 0; |
93 | virtual void setRowCount(int) = 0; |
94 | virtual QList<QModelIndex> intersectingSet(const QRect &area) const = 0; |
95 | virtual void dataChanged(const QModelIndex &, const QModelIndex &) = 0; |
96 | |
97 | virtual int horizontalScrollToValue(int index, QListView::ScrollHint hint, |
98 | bool leftOf, bool rightOf, const QRect &area, const QRect &rect) const; |
99 | virtual int verticalScrollToValue(int index, QListView::ScrollHint hint, |
100 | bool above, bool below, const QRect &area, const QRect &rect) const; |
101 | virtual void scrollContentsBy(int dx, int dy, bool scrollElasticBand); |
102 | virtual QRect mapToViewport(const QRect &rect) const {return rect;} |
103 | virtual int horizontalOffset() const; |
104 | virtual int verticalOffset() const { return verticalScrollBar()->value(); } |
105 | virtual void updateHorizontalScrollBar(const QSize &step); |
106 | virtual void updateVerticalScrollBar(const QSize &step); |
107 | virtual void appendHiddenRow(int row); |
108 | virtual void removeHiddenRow(int row); |
109 | virtual void setPositionForIndex(const QPoint &, const QModelIndex &) { } |
110 | |
111 | #if QT_CONFIG(draganddrop) |
112 | virtual void paintDragDrop(QPainter *painter); |
113 | virtual bool filterDragMoveEvent(QDragMoveEvent *) { return false; } |
114 | virtual bool filterDragLeaveEvent(QDragLeaveEvent *) { return false; } |
115 | virtual bool filterDropEvent(QDropEvent *) { return false; } |
116 | virtual bool filterStartDrag(Qt::DropActions) { return false; } |
117 | #endif |
118 | |
119 | |
120 | //other inline members |
121 | inline int spacing() const; |
122 | inline bool isWrapping() const; |
123 | inline QSize gridSize() const; |
124 | inline QListView::Flow flow() const; |
125 | inline QListView::Movement movement() const; |
126 | |
127 | inline QPoint offset() const; |
128 | inline QPoint pressedPosition() const; |
129 | inline bool uniformItemSizes() const; |
130 | inline int column() const; |
131 | |
132 | inline QScrollBar *verticalScrollBar() const; |
133 | inline QScrollBar *horizontalScrollBar() const; |
134 | inline QListView::ScrollMode verticalScrollMode() const; |
135 | inline QListView::ScrollMode horizontalScrollMode() const; |
136 | |
137 | inline QModelIndex modelIndex(int row) const; |
138 | inline int rowCount() const; |
139 | |
140 | inline void initViewItemOption(QStyleOptionViewItem *option) const; |
141 | inline QWidget *viewport() const; |
142 | inline QRect clipRect() const; |
143 | |
144 | inline QSize cachedItemSize() const; |
145 | inline QRect viewItemRect(const QListViewItem &item) const; |
146 | inline QSize itemSize(const QStyleOptionViewItem &opt, const QModelIndex &idx) const; |
147 | inline QAbstractItemDelegate *delegate(const QModelIndex &idx) const; |
148 | |
149 | inline bool isHidden(int row) const; |
150 | inline int hiddenCount() const; |
151 | |
152 | inline bool isRightToLeft() const; |
153 | |
154 | QListViewPrivate *dd; |
155 | QListView *qq; |
156 | QSize contentsSize; |
157 | int batchStartRow; |
158 | int batchSavedDeltaSeg; |
159 | }; |
160 | |
161 | class QListModeViewBase : public QCommonListViewBase |
162 | { |
163 | public: |
164 | QListModeViewBase(QListView *q, QListViewPrivate *d); |
165 | |
166 | QList<int> flowPositions; |
167 | QList<int> segmentPositions; |
168 | QList<int> segmentStartRows; |
169 | QList<int> segmentExtents; |
170 | QList<int> scrollValueMap; |
171 | |
172 | // used when laying out in batches |
173 | int batchSavedPosition; |
174 | |
175 | //reimplementations |
176 | int itemIndex(const QListViewItem &item) const override { return item.indexHint; } |
177 | QListViewItem indexToListViewItem(const QModelIndex &index) const override; |
178 | bool doBatchedItemLayout(const QListViewLayoutInfo &info, int max) override; |
179 | void clear() override; |
180 | void setRowCount(int rowCount) override { flowPositions.resize(size: rowCount); } |
181 | QList<QModelIndex> intersectingSet(const QRect &area) const override; |
182 | void dataChanged(const QModelIndex &, const QModelIndex &) override; |
183 | |
184 | int horizontalScrollToValue(int index, QListView::ScrollHint hint, |
185 | bool leftOf, bool rightOf,const QRect &area, const QRect &rect) const override; |
186 | int verticalScrollToValue(int index, QListView::ScrollHint hint, |
187 | bool above, bool below, const QRect &area, const QRect &rect) const override; |
188 | void scrollContentsBy(int dx, int dy, bool scrollElasticBand) override; |
189 | QRect mapToViewport(const QRect &rect) const override; |
190 | int horizontalOffset() const override; |
191 | int verticalOffset() const override; |
192 | inline static QSize viewportSize(const QAbstractItemView *v); |
193 | void updateHorizontalScrollBar(const QSize &step) override; |
194 | void updateVerticalScrollBar(const QSize &step) override; |
195 | |
196 | #if QT_CONFIG(draganddrop) |
197 | // The next two methods are to be used on LefToRight flow only. |
198 | // WARNING: Plenty of duplicated code from QAbstractItemView{,Private}. |
199 | QAbstractItemView::DropIndicatorPosition position(const QPoint &pos, const QRect &rect, const QModelIndex &idx) const; |
200 | void dragMoveEvent(QDragMoveEvent *e); |
201 | bool dropOn(QDropEvent *event, int *row, int *col, QModelIndex *index); |
202 | #endif |
203 | |
204 | private: |
205 | QPoint initStaticLayout(const QListViewLayoutInfo &info); |
206 | void doStaticLayout(const QListViewLayoutInfo &info); |
207 | int perItemScrollToValue(int index, int value, int height, |
208 | QAbstractItemView::ScrollHint hint, |
209 | Qt::Orientation orientation, bool wrap, int extent) const; |
210 | int perItemScrollingPageSteps(int length, int bounds, bool wrap) const; |
211 | }; |
212 | |
213 | class QIconModeViewBase : public QCommonListViewBase |
214 | { |
215 | public: |
216 | QIconModeViewBase(QListView *q, QListViewPrivate *d) : QCommonListViewBase(q, d), interSectingVector(nullptr) {} |
217 | |
218 | QBspTree tree; |
219 | QList<QListViewItem> items; |
220 | QBitArray moved; |
221 | |
222 | QList<QModelIndex> draggedItems; // indices to the tree.itemVector |
223 | mutable QPoint draggedItemsPos; |
224 | |
225 | // used when laying out in batches |
226 | QList<QModelIndex> *interSectingVector; // used from within intersectingSet |
227 | |
228 | //reimplementations |
229 | int itemIndex(const QListViewItem &item) const override; |
230 | QListViewItem indexToListViewItem(const QModelIndex &index) const override; |
231 | bool doBatchedItemLayout(const QListViewLayoutInfo &info, int max) override; |
232 | void clear() override; |
233 | void setRowCount(int rowCount) override; |
234 | QList<QModelIndex> intersectingSet(const QRect &area) const override; |
235 | |
236 | void scrollContentsBy(int dx, int dy, bool scrollElasticBand) override; |
237 | void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight) override; |
238 | void appendHiddenRow(int row) override; |
239 | void removeHiddenRow(int row) override; |
240 | void setPositionForIndex(const QPoint &position, const QModelIndex &index) override; |
241 | |
242 | #if QT_CONFIG(draganddrop) |
243 | bool filterDragMoveEvent(QDragMoveEvent *) override; |
244 | bool filterDragLeaveEvent(QDragLeaveEvent *) override; |
245 | bool filterDropEvent(QDropEvent *e) override; |
246 | bool filterStartDrag(Qt::DropActions) override; |
247 | #endif |
248 | |
249 | private: |
250 | void initBspTree(const QSize &contents); |
251 | QPoint initDynamicLayout(const QListViewLayoutInfo &info); |
252 | void doDynamicLayout(const QListViewLayoutInfo &info); |
253 | static void addLeaf(QList<int> &leaf, const QRect &area, uint visited, QBspTree::Data data); |
254 | QRect itemsRect(const QList<QModelIndex> &indexes) const; |
255 | QRect draggedItemsRect() const; |
256 | QPoint snapToGrid(const QPoint &pos) const; |
257 | void updateContentsSize(); |
258 | QPoint draggedItemsDelta() const; |
259 | void drawItems(QPainter *painter, const QList<QModelIndex> &indexes) const; |
260 | void moveItem(int index, const QPoint &dest); |
261 | |
262 | }; |
263 | |
264 | class Q_AUTOTEST_EXPORT QListViewPrivate: public QAbstractItemViewPrivate |
265 | { |
266 | Q_DECLARE_PUBLIC(QListView) |
267 | public: |
268 | QListViewPrivate(); |
269 | ~QListViewPrivate(); |
270 | |
271 | void clear(); |
272 | void prepareItemsLayout(); |
273 | |
274 | bool doItemsLayout(int num); |
275 | |
276 | inline QList<QModelIndex> intersectingSet(const QRect &area, bool doLayout = true) const |
277 | { |
278 | if (doLayout) executePostedLayout(); |
279 | QRect a = (q_func()->isRightToLeft() ? flipX(r: area.normalized()) : area.normalized()); |
280 | return commonListView->intersectingSet(area: a); |
281 | } |
282 | |
283 | inline void resetBatchStartRow() { commonListView->batchStartRow = 0; } |
284 | inline int batchStartRow() const { return commonListView->batchStartRow; } |
285 | inline QSize contentsSize() const { return commonListView->contentsSize; } |
286 | inline void setContentsSize(int w, int h) { commonListView->contentsSize = QSize(w, h); } |
287 | |
288 | inline int flipX(int x) const |
289 | { return qMax(a: viewport->width(), b: contentsSize().width()) - x; } |
290 | inline QPoint flipX(const QPoint &p) const |
291 | { return QPoint(flipX(x: p.x()), p.y()); } |
292 | inline QRect flipX(const QRect &r) const |
293 | { return QRect(flipX(x: r.x()) - r.width(), r.y(), r.width(), r.height()); } |
294 | inline QRect viewItemRect(const QListViewItem &item) const |
295 | { if (q_func()->isRightToLeft()) return flipX(r: item.rect()); return item.rect(); } |
296 | |
297 | QListViewItem indexToListViewItem(const QModelIndex &index) const; |
298 | inline QModelIndex listViewItemToIndex(const QListViewItem &item) const |
299 | { return model->index(row: commonListView->itemIndex(item), column, parent: root); } |
300 | |
301 | inline bool hasRectForIndex(const QModelIndex &index) const |
302 | { |
303 | return isIndexValid(index) && index.parent() == root && index.column() == column && !isHidden(row: index.row()); |
304 | } |
305 | |
306 | QRect rectForIndex(const QModelIndex &index) const |
307 | { |
308 | if (!hasRectForIndex(index)) |
309 | return QRect(); |
310 | executePostedLayout(); |
311 | return viewItemRect(item: indexToListViewItem(index)); |
312 | } |
313 | |
314 | QRect cellRectForIndex(const QModelIndex &index) |
315 | { |
316 | if (!hasRectForIndex(index)) |
317 | return QRect(); |
318 | executePostedLayout(); |
319 | auto oldItemAlignment = itemAlignment; |
320 | itemAlignment = Qt::Alignment(); |
321 | const QRect rect = rectForIndex(index); |
322 | itemAlignment = oldItemAlignment; |
323 | return rect; |
324 | } |
325 | |
326 | void viewUpdateGeometries() { q_func()->updateGeometries(); } |
327 | |
328 | |
329 | QRect mapToViewport(const QRect &rect, bool extend = true) const; |
330 | |
331 | QModelIndex closestIndex(const QRect &target, const QList<QModelIndex> &candidates) const; |
332 | QSize itemSize(const QStyleOptionViewItem &option, const QModelIndex &index) const; |
333 | |
334 | bool selectionAllowed(const QModelIndex &index) const override |
335 | { if (viewMode == QListView::ListMode && !showElasticBand) return index.isValid(); return true; } |
336 | |
337 | int horizontalScrollToValue(const QModelIndex &index, const QRect &rect, QListView::ScrollHint hint) const; |
338 | int verticalScrollToValue(const QModelIndex &index, const QRect &rect, QListView::ScrollHint hint) const; |
339 | |
340 | QItemSelection selection(const QRect &rect) const; |
341 | void selectAll(QItemSelectionModel::SelectionFlags command) override; |
342 | |
343 | #if QT_CONFIG(draganddrop) |
344 | QAbstractItemView::DropIndicatorPosition position(const QPoint &pos, const QRect &rect, const QModelIndex &idx) const override; |
345 | bool dropOn(QDropEvent *event, int *row, int *col, QModelIndex *index) override; |
346 | #endif |
347 | |
348 | inline void setGridSize(const QSize &size) { grid = size; } |
349 | inline QSize gridSize() const { return grid; } |
350 | inline void setWrapping(bool b) { wrap = b; } |
351 | inline bool isWrapping() const { return wrap; } |
352 | inline void setSpacing(int s) { space = s; } |
353 | inline int spacing() const { return space; } |
354 | inline void setSelectionRectVisible(bool visible) { showElasticBand = visible; } |
355 | inline bool isSelectionRectVisible() const { return showElasticBand; } |
356 | |
357 | inline QModelIndex modelIndex(int row) const { return model->index(row, column, parent: root); } |
358 | inline bool isHidden(int row) const { |
359 | QModelIndex idx = model->index(row, column: 0, parent: root); |
360 | return isPersistent(index: idx) && hiddenRows.contains(value: idx); |
361 | } |
362 | // helper to avoid checking for isPersistent and creating persistent indexes as above in isHidden |
363 | QList<int> hiddenRowIds() const |
364 | { |
365 | QList<int> rowIds; |
366 | rowIds.reserve(asize: hiddenRows.size()); |
367 | for (const auto &idx : hiddenRows) |
368 | rowIds += idx.row(); |
369 | return rowIds; |
370 | } |
371 | inline bool isHiddenOrDisabled(int row) const { return isHidden(row) || !isIndexEnabled(index: modelIndex(row)); } |
372 | |
373 | void removeCurrentAndDisabled(QList<QModelIndex> *indexes, const QModelIndex ¤t) const; |
374 | |
375 | void scrollElasticBandBy(int dx, int dy); |
376 | |
377 | QItemViewPaintPairs draggablePaintPairs(const QModelIndexList &indexes, QRect *r) const override; |
378 | |
379 | void emitIndexesMoved(const QModelIndexList &indexes) { emit q_func()->indexesMoved(indexes); } |
380 | |
381 | |
382 | QCommonListViewBase *commonListView; |
383 | |
384 | // ### FIXME: see if we can move the members into the dynamic/static classes |
385 | |
386 | bool wrap; |
387 | int space; |
388 | QSize grid; |
389 | |
390 | QListView::Flow flow; |
391 | QListView::Movement movement; |
392 | QListView::ResizeMode resizeMode; |
393 | QListView::LayoutMode layoutMode; |
394 | QListView::ViewMode viewMode; |
395 | |
396 | // the properties controlling the |
397 | // icon- or list-view modes |
398 | enum ModeProperties { |
399 | Wrap = 1, |
400 | Spacing = 2, |
401 | GridSize = 4, |
402 | Flow = 8, |
403 | Movement = 16, |
404 | ResizeMode = 32, |
405 | SelectionRectVisible = 64 |
406 | }; |
407 | |
408 | uint modeProperties : 8; |
409 | |
410 | QRect layoutBounds; |
411 | |
412 | // timers |
413 | QBasicTimer batchLayoutTimer; |
414 | |
415 | // used for hidden items |
416 | QSet<QPersistentModelIndex> hiddenRows; |
417 | |
418 | int column; |
419 | bool uniformItemSizes; |
420 | mutable QSize cachedItemSize; |
421 | int batchSize; |
422 | |
423 | QRect elasticBand; |
424 | bool showElasticBand; |
425 | |
426 | Qt::Alignment itemAlignment; |
427 | }; |
428 | |
429 | // inline implementations |
430 | |
431 | inline int QCommonListViewBase::spacing() const { return dd->spacing(); } |
432 | inline bool QCommonListViewBase::isWrapping() const { return dd->isWrapping(); } |
433 | inline QSize QCommonListViewBase::gridSize() const { return dd->gridSize(); } |
434 | inline QListView::Flow QCommonListViewBase::flow() const { return dd->flow; } |
435 | inline QListView::Movement QCommonListViewBase::movement() const { return dd->movement; } |
436 | |
437 | inline QPoint QCommonListViewBase::offset() const { return dd->offset(); } |
438 | inline QPoint QCommonListViewBase::pressedPosition() const { return dd->pressedPosition; } |
439 | inline bool QCommonListViewBase::uniformItemSizes() const { return dd->uniformItemSizes; } |
440 | inline int QCommonListViewBase::column() const { return dd->column; } |
441 | |
442 | inline QScrollBar *QCommonListViewBase::verticalScrollBar() const { return qq->verticalScrollBar(); } |
443 | inline QScrollBar *QCommonListViewBase::horizontalScrollBar() const { return qq->horizontalScrollBar(); } |
444 | inline QListView::ScrollMode QCommonListViewBase::verticalScrollMode() const { return qq->verticalScrollMode(); } |
445 | inline QListView::ScrollMode QCommonListViewBase::horizontalScrollMode() const { return qq->horizontalScrollMode(); } |
446 | |
447 | inline QModelIndex QCommonListViewBase::modelIndex(int row) const |
448 | { return dd->model->index(row, column: dd->column, parent: dd->root); } |
449 | inline int QCommonListViewBase::rowCount() const { return dd->model->rowCount(parent: dd->root); } |
450 | |
451 | inline void QCommonListViewBase::initViewItemOption(QStyleOptionViewItem *option) const { qq->initViewItemOption(option); } |
452 | inline QWidget *QCommonListViewBase::viewport() const { return dd->viewport; } |
453 | inline QRect QCommonListViewBase::clipRect() const { return dd->clipRect(); } |
454 | |
455 | inline QSize QCommonListViewBase::cachedItemSize() const { return dd->cachedItemSize; } |
456 | inline QRect QCommonListViewBase::viewItemRect(const QListViewItem &item) const { return dd->viewItemRect(item); } |
457 | inline QSize QCommonListViewBase::itemSize(const QStyleOptionViewItem &opt, const QModelIndex &idx) const |
458 | { return dd->itemSize(option: opt, index: idx); } |
459 | |
460 | inline QAbstractItemDelegate *QCommonListViewBase::delegate(const QModelIndex &idx) const |
461 | { return qq->itemDelegateForIndex(index: idx); } |
462 | |
463 | inline bool QCommonListViewBase::isHidden(int row) const { return dd->isHidden(row); } |
464 | inline int QCommonListViewBase::hiddenCount() const { return dd->hiddenRows.size(); } |
465 | |
466 | inline bool QCommonListViewBase::isRightToLeft() const { return qq->isRightToLeft(); } |
467 | |
468 | QT_END_NAMESPACE |
469 | |
470 | #endif // QLISTVIEW_P_H |
471 |
Definitions
- QListViewItem
- QListViewItem
- QListViewItem
- operator==
- operator!=
- isValid
- invalidate
- resize
- move
- width
- height
- rect
- QListViewLayoutInfo
- QCommonListViewBase
- QCommonListViewBase
- ~QCommonListViewBase
- mapToViewport
- verticalOffset
- setPositionForIndex
- filterDragMoveEvent
- filterDragLeaveEvent
- filterDropEvent
- filterStartDrag
- QListModeViewBase
- itemIndex
- setRowCount
- QIconModeViewBase
- QIconModeViewBase
- QListViewPrivate
- intersectingSet
- resetBatchStartRow
- batchStartRow
- contentsSize
- setContentsSize
- flipX
- flipX
- flipX
- viewItemRect
- listViewItemToIndex
- hasRectForIndex
- rectForIndex
- cellRectForIndex
- viewUpdateGeometries
- selectionAllowed
- setGridSize
- gridSize
- setWrapping
- isWrapping
- setSpacing
- spacing
- setSelectionRectVisible
- isSelectionRectVisible
- modelIndex
- isHidden
- hiddenRowIds
- isHiddenOrDisabled
- emitIndexesMoved
- ModeProperties
- spacing
- isWrapping
- gridSize
- flow
- movement
- offset
- pressedPosition
- uniformItemSizes
- column
- verticalScrollBar
- horizontalScrollBar
- verticalScrollMode
- horizontalScrollMode
- modelIndex
- rowCount
- initViewItemOption
- viewport
- clipRect
- cachedItemSize
- viewItemRect
- itemSize
- delegate
- isHidden
- hiddenCount
Start learning QML with our Intro Training
Find out more