File indexing completed on 2024-04-21 03:55:58

0001 /*
0002  *  SPDX-FileCopyrightText: 2019 Marco Martin <mart@kde.org>
0003  *
0004  *  SPDX-License-Identifier: LGPL-2.0-or-later
0005  */
0006 
0007 #pragma once
0008 
0009 #include <QPointer>
0010 #include <QQuickItem>
0011 #include <QVariant>
0012 
0013 class ContentItem;
0014 class ColumnView;
0015 
0016 class ScrollIntentionEvent : public QObject
0017 {
0018     Q_OBJECT
0019     Q_PROPERTY(QPointF delta MEMBER delta CONSTANT FINAL)
0020     Q_PROPERTY(bool accepted MEMBER accepted FINAL)
0021 public:
0022     ScrollIntentionEvent()
0023     {
0024     }
0025     ~ScrollIntentionEvent() override
0026     {
0027     }
0028 
0029     QPointF delta;
0030     bool accepted = false;
0031 };
0032 
0033 /**
0034  * This is an attached property to every item that is inserted in the ColumnView,
0035  * used to access the view and page information such as the position and information for layouting, such as fillWidth
0036  * @since 2.7
0037  */
0038 class ColumnViewAttached : public QObject
0039 {
0040     Q_OBJECT
0041 
0042     /**
0043      * The index position of the column in the view, starting from 0
0044      */
0045     Q_PROPERTY(int index READ index WRITE setIndex NOTIFY indexChanged FINAL)
0046 
0047     /**
0048      * If true, the column will expand to take the whole viewport space minus reservedSpace
0049      */
0050     Q_PROPERTY(bool fillWidth READ fillWidth WRITE setFillWidth NOTIFY fillWidthChanged FINAL)
0051 
0052     /**
0053      * When a column is fillWidth, it will keep reservedSpace amount of pixels from going to fill the full viewport width
0054      */
0055     Q_PROPERTY(qreal reservedSpace READ reservedSpace WRITE setReservedSpace NOTIFY reservedSpaceChanged FINAL)
0056 
0057     /**
0058      * Like the same property of MouseArea, when this is true, the column view won't
0059      * try to manage events by itself when filtering from a child, not
0060      * disturbing user interaction
0061      */
0062     Q_PROPERTY(bool preventStealing READ preventStealing WRITE setPreventStealing NOTIFY preventStealingChanged FINAL)
0063 
0064     /**
0065      * If true the page will never go out of view, but will stay either
0066      * at the right or left side of the ColumnView
0067      */
0068     Q_PROPERTY(bool pinned READ isPinned WRITE setPinned NOTIFY pinnedChanged FINAL)
0069 
0070     /**
0071      * The view this column belongs to
0072      */
0073     Q_PROPERTY(ColumnView *view READ view NOTIFY viewChanged FINAL)
0074 
0075     /**
0076      * True if this column is at least partly visible in the ColumnView's viewport.
0077      * @since 5.77
0078      */
0079     Q_PROPERTY(bool inViewport READ inViewport NOTIFY inViewportChanged FINAL)
0080 
0081     Q_PROPERTY(QQuickItem *globalHeader READ globalHeader WRITE setGlobalHeader NOTIFY globalHeaderChanged FINAL)
0082     Q_PROPERTY(QQuickItem *globalFooter READ globalFooter WRITE setGlobalFooter NOTIFY globalFooterChanged FINAL)
0083 
0084 public:
0085     ColumnViewAttached(QObject *parent = nullptr);
0086     ~ColumnViewAttached() override;
0087 
0088     void setIndex(int index);
0089     int index() const;
0090 
0091     void setFillWidth(bool fill);
0092     bool fillWidth() const;
0093 
0094     qreal reservedSpace() const;
0095     void setReservedSpace(qreal space);
0096 
0097     ColumnView *view();
0098     void setView(ColumnView *view);
0099 
0100     // Private API, not for QML use
0101     QQuickItem *originalParent() const;
0102     void setOriginalParent(QQuickItem *parent);
0103 
0104     bool shouldDeleteOnRemove() const;
0105     void setShouldDeleteOnRemove(bool del);
0106 
0107     bool preventStealing() const;
0108     void setPreventStealing(bool prevent);
0109 
0110     bool isPinned() const;
0111     void setPinned(bool pinned);
0112 
0113     bool inViewport() const;
0114     void setInViewport(bool inViewport);
0115 
0116     QQuickItem *globalHeader() const;
0117     void setGlobalHeader(QQuickItem *header);
0118 
0119     QQuickItem *globalFooter() const;
0120     void setGlobalFooter(QQuickItem *footer);
0121 
0122 Q_SIGNALS:
0123     void indexChanged();
0124     void fillWidthChanged();
0125     void reservedSpaceChanged();
0126     void viewChanged();
0127     void preventStealingChanged();
0128     void pinnedChanged();
0129     void scrollIntention(ScrollIntentionEvent *event);
0130     void inViewportChanged();
0131     void globalHeaderChanged(QQuickItem *oldHeader, QQuickItem *newHeader);
0132     void globalFooterChanged(QQuickItem *oldFooter, QQuickItem *newFooter);
0133 
0134 private:
0135     int m_index = -1;
0136     bool m_fillWidth = false;
0137     qreal m_reservedSpace = 0;
0138     QPointer<ColumnView> m_view;
0139     QPointer<QQuickItem> m_originalParent;
0140     bool m_customFillWidth = false;
0141     bool m_customReservedSpace = false;
0142     bool m_shouldDeleteOnRemove = true;
0143     bool m_preventStealing = false;
0144     bool m_pinned = false;
0145     bool m_inViewport = false;
0146     QPointer<QQuickItem> m_globalHeader;
0147     QPointer<QQuickItem> m_globalFooter;
0148 };
0149 
0150 /**
0151  * ColumnView is a container that lays out items horizontally in a row,
0152  * 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.
0153  * The columns can either all have the same fixed size (recommended),
0154  * size themselves with implicitWidth, or automatically expand to take all the available width: by default the last column will always be the expanding one.
0155  * Items inside the ColumnView can access info of the view and set layouting hints via the ColumnView attached property.
0156  *
0157  * This is the base for the implementation of PageRow
0158  * @since 2.7
0159  */
0160 class ColumnView : public QQuickItem
0161 {
0162     Q_OBJECT
0163     QML_ELEMENT
0164     QML_ATTACHED(ColumnViewAttached)
0165 
0166     /**
0167      * The strategy to follow while automatically resizing the columns,
0168      * the enum can have the following values:
0169      * * FixedColumns: every column is fixed at the same width of the columnWidth property
0170      * * DynamicColumns: columns take their width from their implicitWidth
0171      * * SingleColumn: only one column at a time is shown, as wide as the viewport, eventual reservedSpace on the column's attached property is ignored
0172      */
0173     Q_PROPERTY(ColumnResizeMode columnResizeMode READ columnResizeMode WRITE setColumnResizeMode NOTIFY columnResizeModeChanged FINAL)
0174 
0175     /**
0176      * The width of all columns when columnResizeMode is FixedColumns
0177      */
0178     Q_PROPERTY(qreal columnWidth READ columnWidth WRITE setColumnWidth NOTIFY columnWidthChanged FINAL)
0179 
0180     /**
0181      * How many columns this view containsItem*/
0182     Q_PROPERTY(int count READ count NOTIFY countChanged FINAL)
0183 
0184     /**
0185      * The position of the currently active column. The current column will also have keyboard focus
0186      */
0187     Q_PROPERTY(int currentIndex READ currentIndex WRITE setCurrentIndex NOTIFY currentIndexChanged FINAL)
0188 
0189     /**
0190      * The currently active column. The current column will also have keyboard focus
0191      */
0192     Q_PROPERTY(QQuickItem *currentItem READ currentItem NOTIFY currentItemChanged FINAL)
0193 
0194     /**
0195      * The main content item of this view: it's the parent of the column items
0196      */
0197     Q_PROPERTY(QQuickItem *contentItem READ contentItem CONSTANT FINAL)
0198 
0199     /**
0200      * The value of the horizontal scroll of the view, in pixels
0201      */
0202     Q_PROPERTY(qreal contentX READ contentX WRITE setContentX NOTIFY contentXChanged FINAL)
0203 
0204     /**
0205      * The compound width of all columns in the view
0206      */
0207     Q_PROPERTY(qreal contentWidth READ contentWidth NOTIFY contentWidthChanged FINAL)
0208 
0209     /**
0210      * The padding this will have at the top
0211      */
0212     Q_PROPERTY(qreal topPadding READ topPadding WRITE setTopPadding NOTIFY topPaddingChanged FINAL)
0213 
0214     /**
0215      * The padding this will have at the bottom
0216      */
0217     Q_PROPERTY(qreal bottomPadding READ bottomPadding WRITE setBottomPadding NOTIFY bottomPaddingChanged FINAL)
0218 
0219     /**
0220      * The duration for scrolling animations
0221      */
0222     Q_PROPERTY(int scrollDuration READ scrollDuration WRITE setScrollDuration NOTIFY scrollDurationChanged FINAL)
0223 
0224     /**
0225      * True if columns should be visually separated by a separator line
0226      */
0227     Q_PROPERTY(bool separatorVisible READ separatorVisible WRITE setSeparatorVisible NOTIFY separatorVisibleChanged FINAL)
0228 
0229     /**
0230      * The list of all visible column items that are at least partially in the viewport at any given moment
0231      */
0232     Q_PROPERTY(QList<QObject *> visibleItems READ visibleItems NOTIFY visibleItemsChanged FINAL)
0233 
0234     /**
0235      * The first of visibleItems provided from convenience
0236      */
0237     Q_PROPERTY(QQuickItem *leadingVisibleItem READ leadingVisibleItem NOTIFY leadingVisibleItemChanged FINAL)
0238 
0239     /**
0240      * The last of visibleItems provided from convenience
0241      */
0242     Q_PROPERTY(QQuickItem *trailingVisibleItem READ trailingVisibleItem NOTIFY trailingVisibleItemChanged FINAL)
0243 
0244     // Properties to make it similar to Flickable
0245     /**
0246      * True when the user is dragging around with touch gestures the view contents
0247      */
0248     Q_PROPERTY(bool dragging READ dragging NOTIFY draggingChanged FINAL)
0249 
0250     /**
0251      * True both when the user is dragging around with touch gestures the view contents or the view is animating
0252      */
0253     Q_PROPERTY(bool moving READ moving NOTIFY movingChanged FINAL)
0254 
0255     /**
0256      * True if it supports moving the contents by dragging
0257      */
0258     Q_PROPERTY(bool interactive READ interactive WRITE setInteractive NOTIFY interactiveChanged FINAL)
0259 
0260     /**
0261      * True if the contents can be dragged also with mouse besides touch
0262      */
0263     Q_PROPERTY(bool acceptsMouse READ acceptsMouse WRITE setAcceptsMouse NOTIFY acceptsMouseChanged FINAL)
0264 
0265     // Default properties
0266     /**
0267      * Every column item the view contains
0268      */
0269     Q_PROPERTY(QQmlListProperty<QQuickItem> contentChildren READ contentChildren NOTIFY contentChildrenChanged FINAL)
0270     /**
0271      * every item declared inside the view, both visual and non-visual items
0272      */
0273     Q_PROPERTY(QQmlListProperty<QObject> contentData READ contentData FINAL)
0274     Q_CLASSINFO("DefaultProperty", "contentData")
0275 
0276 public:
0277     enum ColumnResizeMode {
0278         FixedColumns = 0,
0279         DynamicColumns,
0280         SingleColumn,
0281     };
0282     Q_ENUM(ColumnResizeMode)
0283 
0284     ColumnView(QQuickItem *parent = nullptr);
0285     ~ColumnView() override;
0286 
0287     // QML property accessors
0288     ColumnResizeMode columnResizeMode() const;
0289     void setColumnResizeMode(ColumnResizeMode mode);
0290 
0291     qreal columnWidth() const;
0292     void setColumnWidth(qreal width);
0293 
0294     int currentIndex() const;
0295     void setCurrentIndex(int index);
0296 
0297     int scrollDuration() const;
0298     void setScrollDuration(int duration);
0299 
0300     bool separatorVisible() const;
0301     void setSeparatorVisible(bool visible);
0302 
0303     int count() const;
0304 
0305     qreal topPadding() const;
0306     void setTopPadding(qreal padding);
0307 
0308     qreal bottomPadding() const;
0309     void setBottomPadding(qreal padding);
0310 
0311     QQuickItem *currentItem();
0312 
0313     // NOTE: It's a QList<QObject *> as QML can't correctly build an Array out of QList<QQuickItem*>
0314     QList<QObject *> visibleItems() const;
0315     QQuickItem *leadingVisibleItem() const;
0316     QQuickItem *trailingVisibleItem() const;
0317 
0318     QQuickItem *contentItem() const;
0319 
0320     QQmlListProperty<QQuickItem> contentChildren();
0321     QQmlListProperty<QObject> contentData();
0322 
0323     bool dragging() const;
0324     bool moving() const;
0325     qreal contentWidth() const;
0326 
0327     qreal contentX() const;
0328     void setContentX(qreal x) const;
0329 
0330     bool interactive() const;
0331     void setInteractive(bool interactive);
0332 
0333     bool acceptsMouse() const;
0334     void setAcceptsMouse(bool accepts);
0335 
0336     /**
0337      * @brief This method removes all the items after the specified item or
0338      * index from the view and returns the last item that was removed.
0339      *
0340      * Note that if the passed value is neither of the values said below, it
0341      * will return a nullptr.
0342      *
0343      * @param item the item to remove. It can be an item, index or not defined
0344      * in which case it will pop the last item.
0345      */
0346     Q_INVOKABLE QQuickItem *pop(const QVariant &item);
0347 
0348     /**
0349      * @brief This method removes all the items after the specified item from
0350      * the view and returns the last item that was removed.
0351      *
0352      * @see ::removeItem()
0353      *
0354      * @param the item where the iteration should stop at
0355      * @returns the last item that has been removed
0356      */
0357     QQuickItem *pop(QQuickItem *item);
0358 
0359     /**
0360      * @brief This method removes all the items after the specified position
0361      * from the view and returns the last item that was removed.
0362      *
0363      * It starts iterating from the last item to the first item calling
0364      * removeItem() for each of them until it reaches the specified position.
0365      *
0366      * @see ::removeItem()
0367      *
0368      * @param the position where the iteration should stop at
0369      * @returns the last item that has been removed
0370      */
0371     QQuickItem *pop(int index);
0372 
0373     /**
0374      * @brief This method removes the last item from the view and returns it.
0375      *
0376      * This method calls removeItem() on the last item.
0377      *
0378      * @see ::removeItem()
0379      *
0380      * @return the removed item
0381      */
0382     Q_INVOKABLE QQuickItem *pop();
0383 
0384     /**
0385      * @brief This method removes the specified item from the view.
0386      *
0387      * Items will be reparented to their old parent. If they have JavaScript
0388      * ownership and they didn't have an old parent, they will be destroyed.
0389      * CurrentIndex may be changed in order to keep the same currentItem
0390      *
0391      * @param item pointer to the item to remove
0392      * @returns the removed item
0393      */
0394     QQuickItem *removeItem(QQuickItem *item);
0395 
0396     /**
0397      * @brief This method removes an item at a given index from the view.
0398      *
0399      * This method calls removeItem(QQuickItem *item) to remove the item at
0400      * the specified index.
0401      *
0402      * @see ::removeItem(QQuickItem *item)
0403      *
0404      * @param index the index of the item which should be removed
0405      * @return the removed item
0406      */
0407     QQuickItem *removeItem(int index);
0408 
0409     // QML attached property
0410     static ColumnViewAttached *qmlAttachedProperties(QObject *object);
0411 
0412 public Q_SLOTS:
0413     /**
0414      * Pushes a new item at the end of the view
0415      * @param item the new item which will be reparented and managed
0416      */
0417     void addItem(QQuickItem *item);
0418 
0419     /**
0420      * @brief This method removes an item from the view.
0421      *
0422      * If the argument is a number, this method dispatches to removeItem(int index)
0423      * to remove an item by its index. Otherwise the argument should be the item
0424      * itself to be removed itself, and this method will dispatch to removeItem(QQuickItem *item).
0425      *
0426      * @see ::removeItem(QQuickItem *item)
0427      *
0428      * @param index the index of the item which should be removed, or the item itself
0429      * @return the removed item
0430      */
0431     Q_INVOKABLE QQuickItem *removeItem(const QVariant &item);
0432 
0433     /**
0434      * Inserts a new item in the view at a given position.
0435      * The current Item will not be changed, currentIndex will be adjusted
0436      * accordingly if needed to keep the same current item.
0437      * @param pos the position we want the new item to be inserted in
0438      * @param item the new item which will be reparented and managed
0439      */
0440     void insertItem(int pos, QQuickItem *item);
0441 
0442     /**
0443      * Replaces an item in the view at a given position with a new item.
0444      * The current Item and currentIndex will not be changed.
0445      * @param pos the position we want the new item to be placed in
0446      * @param item the new item which will be reparented and managed
0447      */
0448     void replaceItem(int pos, QQuickItem *item);
0449 
0450     /**
0451      * Move an item inside the view.
0452      * The currentIndex property may be changed in order to keep currentItem the same.
0453      * @param from the old position
0454      * @param to the new position
0455      */
0456     void moveItem(int from, int to);
0457 
0458     /**
0459      * Removes every item in the view.
0460      * Items will be reparented to their old parent.
0461      * If they have JavaScript ownership and they didn't have an old parent, they will be destroyed
0462      */
0463     void clear();
0464 
0465     /**
0466      * @returns true if the view contains the given item
0467      */
0468     bool containsItem(QQuickItem *item);
0469 
0470     /**
0471      * Returns the visible item containing the point x, y in content coordinates.
0472      * If there is no item at the point specified, or the item is not visible null is returned.
0473      */
0474     QQuickItem *itemAt(qreal x, qreal y);
0475 
0476 protected:
0477     void classBegin() override;
0478     void componentComplete() override;
0479     void updatePolish() override;
0480     void itemChange(QQuickItem::ItemChange change, const QQuickItem::ItemChangeData &value) override;
0481     void geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry) override;
0482     bool childMouseEventFilter(QQuickItem *item, QEvent *event) override;
0483     void mousePressEvent(QMouseEvent *event) override;
0484     void mouseMoveEvent(QMouseEvent *event) override;
0485     void mouseReleaseEvent(QMouseEvent *event) override;
0486     void mouseUngrabEvent() override;
0487 
0488 Q_SIGNALS:
0489     /**
0490      * A new item has been inserted
0491      * @param position where the page has been inserted
0492      * @param item a pointer to the new item
0493      */
0494     void itemInserted(int position, QQuickItem *item);
0495 
0496     /**
0497      * An item has just been removed from the view
0498      * @param item a pointer to the item that has just been removed
0499      */
0500     void itemRemoved(QQuickItem *item);
0501 
0502     // Property notifiers
0503     void contentChildrenChanged();
0504     void columnResizeModeChanged();
0505     void columnWidthChanged();
0506     void currentIndexChanged();
0507     void currentItemChanged();
0508     void visibleItemsChanged();
0509     void countChanged();
0510     void draggingChanged();
0511     void movingChanged();
0512     void contentXChanged();
0513     void contentWidthChanged();
0514     void interactiveChanged();
0515     void acceptsMouseChanged();
0516     void scrollDurationChanged();
0517     void separatorVisibleChanged();
0518     void leadingVisibleItemChanged();
0519     void trailingVisibleItemChanged();
0520     void topPaddingChanged();
0521     void bottomPaddingChanged();
0522 
0523 private:
0524     static void contentChildren_append(QQmlListProperty<QQuickItem> *prop, QQuickItem *object);
0525     static qsizetype contentChildren_count(QQmlListProperty<QQuickItem> *prop);
0526     static QQuickItem *contentChildren_at(QQmlListProperty<QQuickItem> *prop, qsizetype index);
0527     static void contentChildren_clear(QQmlListProperty<QQuickItem> *prop);
0528 
0529     static void contentData_append(QQmlListProperty<QObject> *prop, QObject *object);
0530     static qsizetype contentData_count(QQmlListProperty<QObject> *prop);
0531     static QObject *contentData_at(QQmlListProperty<QObject> *prop, qsizetype index);
0532     static void contentData_clear(QQmlListProperty<QObject> *prop);
0533 
0534     QList<QObject *> m_contentData;
0535 
0536     ContentItem *m_contentItem;
0537     QPointer<QQuickItem> m_currentItem;
0538 
0539     qreal m_oldMouseX = -1.0;
0540     qreal m_startMouseX = -1.0;
0541     qreal m_oldMouseY = -1.0;
0542     qreal m_startMouseY = -1.0;
0543     int m_currentIndex = -1;
0544     qreal m_topPadding = 0;
0545     qreal m_bottomPadding = 0;
0546 
0547     bool m_mouseDown = false;
0548     bool m_interactive = true;
0549     bool m_dragging = false;
0550     bool m_moving = false;
0551     bool m_separatorVisible = true;
0552     bool m_complete = false;
0553     bool m_acceptsMouse = false;
0554 };
0555 
0556 QML_DECLARE_TYPEINFO(ColumnView, QML_HAS_ATTACHED_PROPERTIES)