1/*
2 * SPDX-FileCopyrightText: 2019 Marco Martin <mart@kde.org>
3 *
4 * SPDX-License-Identifier: LGPL-2.0-or-later
5 */
6
7#pragma once
8
9#include <QPointer>
10#include <QQuickItem>
11#include <QVariant>
12
13class ContentItem;
14class ColumnView;
15
16class ScrollIntentionEvent : public QObject
17{
18 Q_OBJECT
19 Q_PROPERTY(QPointF delta MEMBER delta CONSTANT FINAL)
20 Q_PROPERTY(bool accepted MEMBER accepted FINAL)
21public:
22 ScrollIntentionEvent()
23 {
24 }
25 ~ScrollIntentionEvent() override
26 {
27 }
28
29 QPointF delta;
30 bool accepted = false;
31};
32
33/**
34 * This is an attached property to every item that is inserted in the ColumnView,
35 * used to access the view and page information such as the position and information for layouting, such as fillWidth
36 * @since 2.7
37 */
38class ColumnViewAttached : public QObject
39{
40 Q_OBJECT
41
42 /**
43 * The index position of the column in the view, starting from 0
44 */
45 Q_PROPERTY(int index READ index WRITE setIndex NOTIFY indexChanged FINAL)
46
47 /**
48 * If true, the column will expand to take the whole viewport space minus reservedSpace
49 */
50 Q_PROPERTY(bool fillWidth READ fillWidth WRITE setFillWidth NOTIFY fillWidthChanged FINAL)
51
52 /**
53 * When a column is fillWidth, it will keep reservedSpace amount of pixels from going to fill the full viewport width
54 */
55 Q_PROPERTY(qreal reservedSpace READ reservedSpace WRITE setReservedSpace NOTIFY reservedSpaceChanged FINAL)
56
57 /**
58 * Like the same property of MouseArea, when this is true, the column view won't
59 * try to manage events by itself when filtering from a child, not
60 * disturbing user interaction
61 */
62 Q_PROPERTY(bool preventStealing READ preventStealing WRITE setPreventStealing NOTIFY preventStealingChanged FINAL)
63
64 /**
65 * If true the page will never go out of view, but will stay either
66 * at the right or left side of the ColumnView
67 */
68 Q_PROPERTY(bool pinned READ isPinned WRITE setPinned NOTIFY pinnedChanged FINAL)
69
70 /**
71 * The view this column belongs to
72 */
73 Q_PROPERTY(ColumnView *view READ view NOTIFY viewChanged FINAL)
74
75 /**
76 * True if this column is at least partly visible in the ColumnView's viewport.
77 * @since 5.77
78 */
79 Q_PROPERTY(bool inViewport READ inViewport NOTIFY inViewportChanged FINAL)
80
81 Q_PROPERTY(QQuickItem *globalHeader READ globalHeader WRITE setGlobalHeader NOTIFY globalHeaderChanged FINAL)
82 Q_PROPERTY(QQuickItem *globalFooter READ globalFooter WRITE setGlobalFooter NOTIFY globalFooterChanged FINAL)
83
84public:
85 ColumnViewAttached(QObject *parent = nullptr);
86 ~ColumnViewAttached() override;
87
88 void setIndex(int index);
89 int index() const;
90
91 void setFillWidth(bool fill);
92 bool fillWidth() const;
93
94 qreal reservedSpace() const;
95 void setReservedSpace(qreal space);
96
97 ColumnView *view();
98 void setView(ColumnView *view);
99
100 // Private API, not for QML use
101 QQuickItem *originalParent() const;
102 void setOriginalParent(QQuickItem *parent);
103
104 bool shouldDeleteOnRemove() const;
105 void setShouldDeleteOnRemove(bool del);
106
107 bool preventStealing() const;
108 void setPreventStealing(bool prevent);
109
110 bool isPinned() const;
111 void setPinned(bool pinned);
112
113 bool inViewport() const;
114 void setInViewport(bool inViewport);
115
116 QQuickItem *globalHeader() const;
117 void setGlobalHeader(QQuickItem *header);
118
119 QQuickItem *globalFooter() const;
120 void setGlobalFooter(QQuickItem *footer);
121
122Q_SIGNALS:
123 void indexChanged();
124 void fillWidthChanged();
125 void reservedSpaceChanged();
126 void viewChanged();
127 void preventStealingChanged();
128 void pinnedChanged();
129 void scrollIntention(ScrollIntentionEvent *event);
130 void inViewportChanged();
131 void globalHeaderChanged(QQuickItem *oldHeader, QQuickItem *newHeader);
132 void globalFooterChanged(QQuickItem *oldFooter, QQuickItem *newFooter);
133
134private:
135 int m_index = -1;
136 bool m_fillWidth = false;
137 qreal m_reservedSpace = 0;
138 QPointer<ColumnView> m_view;
139 QPointer<QQuickItem> m_originalParent;
140 bool m_customFillWidth = false;
141 bool m_customReservedSpace = false;
142 bool m_shouldDeleteOnRemove = true;
143 bool m_preventStealing = false;
144 bool m_pinned = false;
145 bool m_inViewport = false;
146 QPointer<QQuickItem> m_globalHeader;
147 QPointer<QQuickItem> m_globalFooter;
148};
149
150/**
151 * ColumnView is a container that lays out items horizontally in a row,
152 * when not all items fit in the ColumnView, it will behave like a Flickable and will be a scrollable view which shows only a determined number of columns.
153 * The columns can either all have the same fixed size (recommended),
154 * size themselves with implicitWidth, or automatically expand to take all the available width: by default the last column will always be the expanding one.
155 * Items inside the ColumnView can access info of the view and set layouting hints via the ColumnView attached property.
156 *
157 * This is the base for the implementation of PageRow
158 * @since 2.7
159 */
160class ColumnView : public QQuickItem
161{
162 Q_OBJECT
163 QML_ELEMENT
164 QML_ATTACHED(ColumnViewAttached)
165
166 /**
167 * The strategy to follow while automatically resizing the columns,
168 * the enum can have the following values:
169 * * FixedColumns: every column is fixed at the same width of the columnWidth property
170 * * DynamicColumns: columns take their width from their implicitWidth
171 * * SingleColumn: only one column at a time is shown, as wide as the viewport, eventual reservedSpace on the column's attached property is ignored
172 */
173 Q_PROPERTY(ColumnResizeMode columnResizeMode READ columnResizeMode WRITE setColumnResizeMode NOTIFY columnResizeModeChanged FINAL)
174
175 /**
176 * The width of all columns when columnResizeMode is FixedColumns
177 */
178 Q_PROPERTY(qreal columnWidth READ columnWidth WRITE setColumnWidth NOTIFY columnWidthChanged FINAL)
179
180 /**
181 * How many columns this view containsItem*/
182 Q_PROPERTY(int count READ count NOTIFY countChanged FINAL)
183
184 /**
185 * The position of the currently active column. The current column will also have keyboard focus
186 */
187 Q_PROPERTY(int currentIndex READ currentIndex WRITE setCurrentIndex NOTIFY currentIndexChanged FINAL)
188
189 /**
190 * The currently active column. The current column will also have keyboard focus
191 */
192 Q_PROPERTY(QQuickItem *currentItem READ currentItem NOTIFY currentItemChanged FINAL)
193
194 /**
195 * The main content item of this view: it's the parent of the column items
196 */
197 Q_PROPERTY(QQuickItem *contentItem READ contentItem CONSTANT FINAL)
198
199 /**
200 * The value of the horizontal scroll of the view, in pixels
201 */
202 Q_PROPERTY(qreal contentX READ contentX WRITE setContentX NOTIFY contentXChanged FINAL)
203
204 /**
205 * The compound width of all columns in the view
206 */
207 Q_PROPERTY(qreal contentWidth READ contentWidth NOTIFY contentWidthChanged FINAL)
208
209 /**
210 * The padding this will have at the top
211 */
212 Q_PROPERTY(qreal topPadding READ topPadding WRITE setTopPadding NOTIFY topPaddingChanged FINAL)
213
214 /**
215 * The padding this will have at the bottom
216 */
217 Q_PROPERTY(qreal bottomPadding READ bottomPadding WRITE setBottomPadding NOTIFY bottomPaddingChanged FINAL)
218
219 /**
220 * The duration for scrolling animations
221 */
222 Q_PROPERTY(int scrollDuration READ scrollDuration WRITE setScrollDuration NOTIFY scrollDurationChanged FINAL)
223
224 /**
225 * True if columns should be visually separated by a separator line
226 */
227 Q_PROPERTY(bool separatorVisible READ separatorVisible WRITE setSeparatorVisible NOTIFY separatorVisibleChanged FINAL)
228
229 /**
230 * The list of all visible column items that are at least partially in the viewport at any given moment
231 */
232 Q_PROPERTY(QList<QObject *> visibleItems READ visibleItems NOTIFY visibleItemsChanged FINAL)
233
234 /**
235 * The first of visibleItems provided from convenience
236 */
237 Q_PROPERTY(QQuickItem *leadingVisibleItem READ leadingVisibleItem NOTIFY leadingVisibleItemChanged FINAL)
238
239 /**
240 * The last of visibleItems provided from convenience
241 */
242 Q_PROPERTY(QQuickItem *trailingVisibleItem READ trailingVisibleItem NOTIFY trailingVisibleItemChanged FINAL)
243
244 // Properties to make it similar to Flickable
245 /**
246 * True when the user is dragging around with touch gestures the view contents
247 */
248 Q_PROPERTY(bool dragging READ dragging NOTIFY draggingChanged FINAL)
249
250 /**
251 * True both when the user is dragging around with touch gestures the view contents or the view is animating
252 */
253 Q_PROPERTY(bool moving READ moving NOTIFY movingChanged FINAL)
254
255 /**
256 * True if it supports moving the contents by dragging
257 */
258 Q_PROPERTY(bool interactive READ interactive WRITE setInteractive NOTIFY interactiveChanged FINAL)
259
260 /**
261 * True if the contents can be dragged also with mouse besides touch
262 */
263 Q_PROPERTY(bool acceptsMouse READ acceptsMouse WRITE setAcceptsMouse NOTIFY acceptsMouseChanged FINAL)
264
265 // Default properties
266 /**
267 * Every column item the view contains
268 */
269 Q_PROPERTY(QQmlListProperty<QQuickItem> contentChildren READ contentChildren NOTIFY contentChildrenChanged FINAL)
270 /**
271 * every item declared inside the view, both visual and non-visual items
272 */
273 Q_PROPERTY(QQmlListProperty<QObject> contentData READ contentData FINAL)
274 Q_CLASSINFO("DefaultProperty", "contentData")
275
276public:
277 enum ColumnResizeMode {
278 FixedColumns = 0,
279 DynamicColumns,
280 SingleColumn,
281 };
282 Q_ENUM(ColumnResizeMode)
283
284 ColumnView(QQuickItem *parent = nullptr);
285 ~ColumnView() override;
286
287 // QML property accessors
288 ColumnResizeMode columnResizeMode() const;
289 void setColumnResizeMode(ColumnResizeMode mode);
290
291 qreal columnWidth() const;
292 void setColumnWidth(qreal width);
293
294 int currentIndex() const;
295 void setCurrentIndex(int index);
296
297 int scrollDuration() const;
298 void setScrollDuration(int duration);
299
300 bool separatorVisible() const;
301 void setSeparatorVisible(bool visible);
302
303 int count() const;
304
305 qreal topPadding() const;
306 void setTopPadding(qreal padding);
307
308 qreal bottomPadding() const;
309 void setBottomPadding(qreal padding);
310
311 QQuickItem *currentItem();
312
313 // NOTE: It's a QList<QObject *> as QML can't correctly build an Array out of QList<QQuickItem*>
314 QList<QObject *> visibleItems() const;
315 QQuickItem *leadingVisibleItem() const;
316 QQuickItem *trailingVisibleItem() const;
317
318 QQuickItem *contentItem() const;
319
320 QQmlListProperty<QQuickItem> contentChildren();
321 QQmlListProperty<QObject> contentData();
322
323 bool dragging() const;
324 bool moving() const;
325 qreal contentWidth() const;
326
327 qreal contentX() const;
328 void setContentX(qreal x) const;
329
330 bool interactive() const;
331 void setInteractive(bool interactive);
332
333 bool acceptsMouse() const;
334 void setAcceptsMouse(bool accepts);
335
336 /**
337 * @brief This method removes all the items after the specified item or
338 * index from the view and returns the last item that was removed.
339 *
340 * Note that if the passed value is neither of the values said below, it
341 * will return a nullptr.
342 *
343 * @param item the item to remove. It can be an item, index or not defined
344 * in which case it will pop the last item.
345 */
346 Q_INVOKABLE QQuickItem *pop(const QVariant &item);
347
348 /**
349 * @brief This method removes all the items after the specified item from
350 * the view and returns the last item that was removed.
351 *
352 * @see ::removeItem()
353 *
354 * @param the item where the iteration should stop at
355 * @returns the last item that has been removed
356 */
357 QQuickItem *pop(QQuickItem *item);
358
359 /**
360 * @brief This method removes all the items after the specified position
361 * from the view and returns the last item that was removed.
362 *
363 * It starts iterating from the last item to the first item calling
364 * removeItem() for each of them until it reaches the specified position.
365 *
366 * @see ::removeItem()
367 *
368 * @param the position where the iteration should stop at
369 * @returns the last item that has been removed
370 */
371 QQuickItem *pop(int index);
372
373 /**
374 * @brief This method removes the last item from the view and returns it.
375 *
376 * This method calls removeItem() on the last item.
377 *
378 * @see ::removeItem()
379 *
380 * @return the removed item
381 */
382 Q_INVOKABLE QQuickItem *pop();
383
384 /**
385 * @brief This method removes the specified item from the view.
386 *
387 * Items will be reparented to their old parent. If they have JavaScript
388 * ownership and they didn't have an old parent, they will be destroyed.
389 * CurrentIndex may be changed in order to keep the same currentItem
390 *
391 * @param item pointer to the item to remove
392 * @returns the removed item
393 */
394 QQuickItem *removeItem(QQuickItem *item);
395
396 /**
397 * @brief This method removes an item at a given index from the view.
398 *
399 * This method calls removeItem(QQuickItem *item) to remove the item at
400 * the specified index.
401 *
402 * @see ::removeItem(QQuickItem *item)
403 *
404 * @param index the index of the item which should be removed
405 * @return the removed item
406 */
407 QQuickItem *removeItem(int index);
408
409 // QML attached property
410 static ColumnViewAttached *qmlAttachedProperties(QObject *object);
411
412public Q_SLOTS:
413 /**
414 * Pushes a new item at the end of the view
415 * @param item the new item which will be reparented and managed
416 */
417 void addItem(QQuickItem *item);
418
419 /**
420 * @brief This method removes an item from the view.
421 *
422 * If the argument is a number, this method dispatches to removeItem(int index)
423 * to remove an item by its index. Otherwise the argument should be the item
424 * itself to be removed itself, and this method will dispatch to removeItem(QQuickItem *item).
425 *
426 * @see ::removeItem(QQuickItem *item)
427 *
428 * @param index the index of the item which should be removed, or the item itself
429 * @return the removed item
430 */
431 Q_INVOKABLE QQuickItem *removeItem(const QVariant &item);
432
433 /**
434 * Inserts a new item in the view at a given position.
435 * The current Item will not be changed, currentIndex will be adjusted
436 * accordingly if needed to keep the same current item.
437 * @param pos the position we want the new item to be inserted in
438 * @param item the new item which will be reparented and managed
439 */
440 void insertItem(int pos, QQuickItem *item);
441
442 /**
443 * Replaces an item in the view at a given position with a new item.
444 * The current Item and currentIndex will not be changed.
445 * @param pos the position we want the new item to be placed in
446 * @param item the new item which will be reparented and managed
447 */
448 void replaceItem(int pos, QQuickItem *item);
449
450 /**
451 * Move an item inside the view.
452 * The currentIndex property may be changed in order to keep currentItem the same.
453 * @param from the old position
454 * @param to the new position
455 */
456 void moveItem(int from, int to);
457
458 /**
459 * Removes every item in the view.
460 * Items will be reparented to their old parent.
461 * If they have JavaScript ownership and they didn't have an old parent, they will be destroyed
462 */
463 void clear();
464
465 /**
466 * @returns true if the view contains the given item
467 */
468 bool containsItem(QQuickItem *item);
469
470 /**
471 * Returns the visible item containing the point x, y in content coordinates.
472 * If there is no item at the point specified, or the item is not visible null is returned.
473 */
474 QQuickItem *itemAt(qreal x, qreal y);
475
476protected:
477 void classBegin() override;
478 void componentComplete() override;
479 void updatePolish() override;
480 void itemChange(QQuickItem::ItemChange change, const QQuickItem::ItemChangeData &value) override;
481 void geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry) override;
482 bool childMouseEventFilter(QQuickItem *item, QEvent *event) override;
483 void mousePressEvent(QMouseEvent *event) override;
484 void mouseMoveEvent(QMouseEvent *event) override;
485 void mouseReleaseEvent(QMouseEvent *event) override;
486 void mouseUngrabEvent() override;
487
488Q_SIGNALS:
489 /**
490 * A new item has been inserted
491 * @param position where the page has been inserted
492 * @param item a pointer to the new item
493 */
494 void itemInserted(int position, QQuickItem *item);
495
496 /**
497 * An item has just been removed from the view
498 * @param item a pointer to the item that has just been removed
499 */
500 void itemRemoved(QQuickItem *item);
501
502 // Property notifiers
503 void contentChildrenChanged();
504 void columnResizeModeChanged();
505 void columnWidthChanged();
506 void currentIndexChanged();
507 void currentItemChanged();
508 void visibleItemsChanged();
509 void countChanged();
510 void draggingChanged();
511 void movingChanged();
512 void contentXChanged();
513 void contentWidthChanged();
514 void interactiveChanged();
515 void acceptsMouseChanged();
516 void scrollDurationChanged();
517 void separatorVisibleChanged();
518 void leadingVisibleItemChanged();
519 void trailingVisibleItemChanged();
520 void topPaddingChanged();
521 void bottomPaddingChanged();
522
523private:
524 static void contentChildren_append(QQmlListProperty<QQuickItem> *prop, QQuickItem *object);
525 static qsizetype contentChildren_count(QQmlListProperty<QQuickItem> *prop);
526 static QQuickItem *contentChildren_at(QQmlListProperty<QQuickItem> *prop, qsizetype index);
527 static void contentChildren_clear(QQmlListProperty<QQuickItem> *prop);
528
529 static void contentData_append(QQmlListProperty<QObject> *prop, QObject *object);
530 static qsizetype contentData_count(QQmlListProperty<QObject> *prop);
531 static QObject *contentData_at(QQmlListProperty<QObject> *prop, qsizetype index);
532 static void contentData_clear(QQmlListProperty<QObject> *prop);
533
534 QList<QObject *> m_contentData;
535
536 ContentItem *m_contentItem;
537 QPointer<QQuickItem> m_currentItem;
538
539 qreal m_oldMouseX = -1.0;
540 qreal m_startMouseX = -1.0;
541 qreal m_oldMouseY = -1.0;
542 qreal m_startMouseY = -1.0;
543 int m_currentIndex = -1;
544 qreal m_topPadding = 0;
545 qreal m_bottomPadding = 0;
546
547 bool m_mouseDown = false;
548 bool m_interactive = true;
549 bool m_dragging = false;
550 bool m_moving = false;
551 bool m_separatorVisible = true;
552 bool m_complete = false;
553 bool m_acceptsMouse = false;
554};
555
556QML_DECLARE_TYPEINFO(ColumnView, QML_HAS_ATTACHED_PROPERTIES)
557

source code of kirigami/src/columnview.h