File indexing completed on 2024-04-28 15:27:41

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