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

0001 /*
0002  * SPDX-FileCopyrightText: 2020 Arjen Hiemstra <ahiemstra@heimr.nl>
0003  *
0004  * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0005  */
0006 
0007 #ifndef TOOLBARLAYOUT_H
0008 #define TOOLBARLAYOUT_H
0009 
0010 #include <QQuickItem>
0011 #include <memory>
0012 
0013 /**
0014  * @brief Attached property for ToolBarLayout delegates.
0015  */
0016 class ToolBarLayoutAttached : public QObject
0017 {
0018     Q_OBJECT
0019     /**
0020      * @brief This property holds the action that this delegate was created for.
0021      */
0022     Q_PROPERTY(QObject *action READ action CONSTANT)
0023 public:
0024     ToolBarLayoutAttached(QObject *parent = nullptr);
0025 
0026     QObject *action() const;
0027     void setAction(QObject *action);
0028 
0029 private:
0030     QObject *m_action = nullptr;
0031 };
0032 
0033 /**
0034  * @brief This is a layout that creates delegates for actions and lays them out in a row.
0035  *
0036  * This effectively combines QtQuick.Layouts.RowLayout and QtQuick.Repeater in a single item,
0037  * with the addition of some extra performance enhancing tweaks. It will create instances
0038  * of ::fullDelegate and ::iconDelegate for each action in ::actions. These are
0039  * then positioned horizontally. Any action that ends up being placed outside
0040  * the width of the item is hidden and will be part of ::hiddenActions which are
0041  * shown in a overflow menu.
0042  *
0043  * The items created as delegates are always created asynchronously, to avoid
0044  * creation lag spikes. Each delegate has access to the action it was created
0045  * for through the ToolBarLayoutAttached attached property.
0046  */
0047 class ToolBarLayout : public QQuickItem
0048 {
0049     Q_OBJECT
0050     /**
0051      * @brief This property holds a list of visible actions this layout should create delegates for.
0052      */
0053     Q_PROPERTY(QQmlListProperty<QObject> actions READ actionsProperty NOTIFY actionsChanged)
0054     /**
0055      * @brief This property holds a list of hidden actions that do not fit in the current view,
0056      * and are thus hidden.
0057      */
0058     Q_PROPERTY(QList<QObject *> hiddenActions READ hiddenActions NOTIFY hiddenActionsChanged)
0059     /**
0060      * @brief This property holds a component that is used to create full-size delegates.
0061      *
0062      * Each delegate has three states, it can be full-size, icon-only or hidden.
0063      * By default, the full-size delegate is used.
0064      *
0065      * The full-size delegate is used when the action has its display hint set to
0066      * @link DisplayHint.KeepVisible KeepVisible @endlink. If there is not enough
0067      * space, it will either use iconDelegate or the delegate will be shown in the
0068      * overflow menu.
0069      *
0070      * @see org::kde::kirigami::Action::displayComponent
0071      */
0072     Q_PROPERTY(QQmlComponent *fullDelegate READ fullDelegate WRITE setFullDelegate NOTIFY fullDelegateChanged)
0073     /**
0074      * @brief This property holds a component that is used to create icon-only delegates.
0075      *
0076      * This is used when display hint is set to @link DisplayHint.IconOnly IconOnly @endlink,
0077      * unless there is not enough space, in which case it will show the delegate in the
0078      * overflow menu.
0079      *
0080      * @see ::fullDelegate
0081      */
0082     Q_PROPERTY(QQmlComponent *iconDelegate READ iconDelegate WRITE setIconDelegate NOTIFY iconDelegateChanged)
0083     /**
0084      * @brief This property holds a component that is used to create the "more button" item from.
0085      *
0086      * The more button is shown when there are actions that do not fit the
0087      * current view. It is intended to have functionality to show these hidden
0088      * actions, like popup a menu with them showing.
0089      */
0090     Q_PROPERTY(QQmlComponent *moreButton READ moreButton WRITE setMoreButton NOTIFY moreButtonChanged)
0091     /**
0092      * @brief This property holds the amount of spacing between individual delegates.
0093      */
0094     Q_PROPERTY(qreal spacing READ spacing WRITE setSpacing NOTIFY spacingChanged)
0095     /**
0096      * @brief This property sets how to align the delegates within this layout.
0097      *
0098      * When there is more space available than required by the visible delegates,
0099      * we need to determine how to place the delegates. This property determines
0100      * how to do that.
0101      *
0102      * @note The ::moreButton, if visible, will always be placed at the end of the layout.
0103      * @see Qt::Alignment
0104      */
0105     Q_PROPERTY(Qt::Alignment alignment READ alignment WRITE setAlignment NOTIFY alignmentChanged)
0106     /**
0107      * @brief This property holds the combined width of visible delegates in this layout.
0108      */
0109     Q_PROPERTY(qreal visibleWidth READ visibleWidth NOTIFY visibleWidthChanged)
0110     /**
0111      * @brief This property holds the minimum width this layout can have.
0112      *
0113      * This is equal to the width of the ::moreButton.
0114      */
0115     Q_PROPERTY(qreal minimumWidth READ minimumWidth NOTIFY minimumWidthChanged)
0116     /**
0117      * @brief This property sets the layout direction of the toolbar layout.
0118      *
0119      * This is primarily intended to support right-to-left layouts. When set to
0120      * LeftToRight, delegates will be layout with the first item on the left and
0121      * following items to the right of that. The more button will be placed at
0122      * the rightmost position. Alignment flags work normally.
0123      *
0124      * When set to RightToLeft, delegates will be layout with the first item on
0125      * the right and following items to the left of that. The more button will
0126      * be placed at the leftmost position. Alignment flags are inverted, so
0127      * AlignLeft will align items to the right, and vice-versa.
0128      */
0129     Q_PROPERTY(Qt::LayoutDirection layoutDirection READ layoutDirection WRITE setLayoutDirection NOTIFY layoutDirectionChanged)
0130     /**
0131      * @brief This property sets how to handle items that do not match the toolbar's height.
0132      *
0133      * When toolbar items do not match the height of the toolbar, there are
0134      * several ways we can deal with this. This property sets the preferred way.
0135      *
0136      * default: ``ToolBarLayout.HeightMode.ConstrainIfLarger``
0137      *
0138      * @see ::HeightMode
0139      */
0140     Q_PROPERTY(HeightMode heightMode READ heightMode WRITE setHeightMode NOTIFY heightModeChanged)
0141 
0142 public:
0143     using ActionsProperty = QQmlListProperty<QObject>;
0144 
0145     /**
0146      * @brief This enum describes several modes that can be used to deal with items with
0147      * height that does not match the toolbar's height.
0148      */
0149     enum HeightMode {
0150         /**
0151          * @brief Always center items, allowing them to go outside the bounds of the layout if they are larger.
0152          */
0153         AlwaysCenter,
0154 
0155         /**
0156          * @brief Always match the height of the layout. Larger items will be reduced in height, smaller items will be increased.
0157          */
0158         AlwaysFill,
0159 
0160         /**
0161          * @brief If the item is larger than the toolbar, reduce its height. Otherwise center it in the toolbar.
0162          */
0163         ConstrainIfLarger,
0164     };
0165     Q_ENUM(HeightMode)
0166 
0167     ToolBarLayout(QQuickItem *parent = nullptr);
0168     ~ToolBarLayout() override;
0169 
0170     ActionsProperty actionsProperty() const;
0171     /**
0172      * @brief This method adds an action to the list of actions.
0173      *
0174      * @param action The action to add.
0175      */
0176     void addAction(QObject *action);
0177     /**
0178      * This method  removes an action from the list of actions.
0179      *
0180      * @param action The action to remove.
0181      */
0182     void removeAction(QObject *action);
0183     /**
0184      * @brief This method clears the list of actions.
0185      */
0186     void clearActions();
0187     Q_SIGNAL void actionsChanged();
0188 
0189     QList<QObject *> hiddenActions() const;
0190     Q_SIGNAL void hiddenActionsChanged();
0191 
0192     QQmlComponent *fullDelegate() const;
0193     void setFullDelegate(QQmlComponent *newFullDelegate);
0194     Q_SIGNAL void fullDelegateChanged();
0195 
0196     QQmlComponent *iconDelegate() const;
0197     void setIconDelegate(QQmlComponent *newIconDelegate);
0198     Q_SIGNAL void iconDelegateChanged();
0199 
0200     QQmlComponent *moreButton() const;
0201     void setMoreButton(QQmlComponent *newMoreButton);
0202     Q_SIGNAL void moreButtonChanged();
0203 
0204     qreal spacing() const;
0205     void setSpacing(qreal newSpacing);
0206     Q_SIGNAL void spacingChanged();
0207 
0208     Qt::Alignment alignment() const;
0209     void setAlignment(Qt::Alignment newAlignment);
0210     Q_SIGNAL void alignmentChanged();
0211 
0212     qreal visibleWidth() const;
0213     Q_SIGNAL void visibleWidthChanged();
0214 
0215     qreal minimumWidth() const;
0216     Q_SIGNAL void minimumWidthChanged();
0217 
0218     Qt::LayoutDirection layoutDirection() const;
0219     void setLayoutDirection(Qt::LayoutDirection &newLayoutDirection);
0220     Q_SIGNAL void layoutDirectionChanged();
0221 
0222     HeightMode heightMode() const;
0223     void setHeightMode(HeightMode newHeightMode);
0224     Q_SIGNAL void heightModeChanged();
0225 
0226     /**
0227      * @brief This slot queues a relayout of this ToolBarLayout.
0228      *
0229      * @note The layouting happens during the next scene graph polishing phase.
0230      */
0231     Q_SLOT void relayout();
0232 
0233     static ToolBarLayoutAttached *qmlAttachedProperties(QObject *object)
0234     {
0235         return new ToolBarLayoutAttached(object);
0236     }
0237 
0238 protected:
0239     void componentComplete() override;
0240 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
0241     void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) override;
0242 #else
0243     void geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry) override;
0244 #endif
0245     void itemChange(QQuickItem::ItemChange change, const QQuickItem::ItemChangeData &data) override;
0246     void updatePolish() override;
0247 
0248 private:
0249     class Private;
0250     const std::unique_ptr<Private> d;
0251 };
0252 
0253 QML_DECLARE_TYPEINFO(ToolBarLayout, QML_HAS_ATTACHED_PROPERTIES)
0254 
0255 #endif // TOOLBARLAYOUT_H