1/*
2 * SPDX-FileCopyrightText: 2020 Arjen Hiemstra <ahiemstra@heimr.nl>
3 *
4 * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
5 */
6
7#ifndef TOOLBARLAYOUT_H
8#define TOOLBARLAYOUT_H
9
10#include <QQuickItem>
11#include <memory>
12
13class ToolBarLayoutPrivate;
14
15class ToolBarLayoutAttached : public QObject
16{
17 Q_OBJECT
18 Q_PROPERTY(QObject *action READ action CONSTANT FINAL)
19public:
20 ToolBarLayoutAttached(QObject *parent = nullptr);
21
22 QObject *action() const;
23 void setAction(QObject *action);
24
25private:
26 QObject *m_action = nullptr;
27};
28
29/*!
30 * \qmltype ToolBarLayout
31 * \inqmlmodule org.kde.kirigami.layouts
32 * \inherits Item
33 *
34 * \brief An item that creates delegates for actions and lays them out in a row.
35 *
36 * This effectively combines RowLayout and Repeater in a single item, with the
37 * addition of some extra performance enhancing tweaks. It will create instances
38 * of fullDelegate and itemDelegate for each action in actions. These are
39 * then positioned horizontally. Any action that ends up being placed outside
40 * the width of the item is hidden and will be part of hiddenActions.
41 *
42 * The items created as delegates are always created asynchronously, to avoid
43 * creation lag spikes. Each delegate has access to the action it was created
44 * for through the action attached property.
45 */
46class ToolBarLayout : public QQuickItem
47{
48 Q_OBJECT
49 QML_ELEMENT
50 QML_ATTACHED(ToolBarLayoutAttached)
51 /*!
52 * \qmlproperty list<QtObject> ToolBarLayout::actions
53 *
54 * The actions this layout should create delegates for.
55 */
56 Q_PROPERTY(QQmlListProperty<QObject> actions READ actionsProperty NOTIFY actionsChanged FINAL)
57 /*!
58 * \qmlproperty list<QtObject> ToolBarLayout::hiddenActions
59 *
60 * A list of actions that do not fit in the current view and are thus hidden.
61 */
62 Q_PROPERTY(QList<QObject *> hiddenActions READ hiddenActions NOTIFY hiddenActionsChanged FINAL)
63 /*!
64 * \qmlproperty Component ToolBarLayout::fullDelegate
65 *
66 * A component that is used to create full-size delegates from.
67 *
68 * Each delegate has three states, it can be full-size, icon-only or hidden.
69 * By default, the full-size delegate is used. When the action has the
70 * DisplayHint.IconOnly hint set, it will always use the iconDelegate. When
71 * it has the DisplayHint.KeepVisible hint set, it will use the full-size
72 * delegate when it fits. If not, it will use the iconDelegate, unless even
73 * that does not fit, in which case it will still be hidden.
74 */
75 Q_PROPERTY(QQmlComponent *fullDelegate READ fullDelegate WRITE setFullDelegate NOTIFY fullDelegateChanged FINAL)
76 /*!
77 * \qmlproperty Component ToolBarLayout::iconDelegate
78 *
79 * A component that is used to create icon-only delegates from.
80 *
81 * \sa fullDelegate
82 */
83 Q_PROPERTY(QQmlComponent *iconDelegate READ iconDelegate WRITE setIconDelegate NOTIFY iconDelegateChanged FINAL)
84 /*!
85 * \qmlproperty Component ToolBarLayout::separatorDelegate
86 *
87 * A component that is used to create separator delegates from.
88 *
89 * \since 6.7
90 *
91 * \sa fullDelegate
92 */
93 Q_PROPERTY(QQmlComponent *separatorDelegate READ separatorDelegate WRITE setSeparatorDelegate NOTIFY separatorDelegateChanged FINAL)
94 /*!
95 * \qmlproperty Component ToolBarLayout::moreButton
96 *
97 * A component that is used to create the "more button" item from.
98 *
99 * The more button is shown when there are actions that do not fit the
100 * current view. It is intended to have functionality to show these hidden
101 * actions, like popup a menu with them showing.
102 */
103 Q_PROPERTY(QQmlComponent *moreButton READ moreButton WRITE setMoreButton NOTIFY moreButtonChanged FINAL)
104 /*!
105 * \qmlproperty real ToolBarLayout::spacing
106 *
107 * The amount of spacing between individual delegates.
108 */
109 Q_PROPERTY(qreal spacing READ spacing WRITE setSpacing NOTIFY spacingChanged FINAL)
110 /*!
111 * \qmlproperty Qt.Alignment ToolBarLayout::alignment
112 *
113 * How to align the delegates within this layout.
114 *
115 * When there is more space available than required by the visible delegates,
116 * we need to determine how to place the delegates. This property determines
117 * how to do that. Note that the moreButton, if visible, will always be
118 * placed at the end of the layout.
119 */
120 Q_PROPERTY(Qt::Alignment alignment READ alignment WRITE setAlignment NOTIFY alignmentChanged FINAL)
121 /*!
122 * \qmlproperty real ToolBarLayout::visibleWidth
123 *
124 * The combined width of visible delegates in this layout.
125 */
126 Q_PROPERTY(qreal visibleWidth READ visibleWidth NOTIFY visibleWidthChanged FINAL)
127 /*!
128 * \qmlproperty real ToolBarLayout::minimumWidth
129 *
130 * The minimum width this layout can have.
131 *
132 * This is equal to the width of the moreButton.
133 */
134 Q_PROPERTY(qreal minimumWidth READ minimumWidth NOTIFY minimumWidthChanged FINAL)
135 /*!
136 * \qmlproperty Qt.LayoutDirection ToolBarLayout::layoutDirection
137 *
138 * Which direction to layout in.
139 *
140 * This is primarily intended to support right-to-left layouts. When set to
141 * LeftToRight, delegates will be layout with the first item on the left and
142 * following items to the right of that. The more button will be placed at
143 * the rightmost position. Alignment flags work normally.
144 *
145 * When set to RightToLeft, delegates will be layout with the first item on
146 * the right and following items to the left of that. The more button will
147 * be placed at the leftmost position. Alignment flags are inverted, so
148 * AlignLeft will align items to the right, and vice-versa.
149 */
150 Q_PROPERTY(Qt::LayoutDirection layoutDirection READ layoutDirection WRITE setLayoutDirection NOTIFY layoutDirectionChanged FINAL)
151 /*!
152 * \qmlproperty enumeration ToolBarLayout::heightMode
153 * How to handle items that do not match the toolbar's height.
154 *
155 * When toolbar items do not match the height of the toolbar, there are
156 * several ways we can deal with this. This property sets the preferred way.
157 *
158 * Available are:
159 * \list
160 * \li AlwaysCenter Always center items, allowing them to go outside the bounds of the layout if they are larger
161 * \li AlwaysFill Always match the height of the layout. Larger items will be reduced in height, smaller items will be increased
162 * \li ConstrainIfLarger If the item is larger than the toolbar, reduce its height. Otherwise center it in the toolbar
163 * \endlist
164 *
165 * The default is HeightMode::ConstrainIfLarger .
166 */
167 Q_PROPERTY(HeightMode heightMode READ heightMode WRITE setHeightMode NOTIFY heightModeChanged FINAL)
168
169 /*!
170 * \qmlattachedproperty QtObject ToolBarLayout::action
171 *
172 * The action this delegate was created for.
173 */
174
175public:
176 using ActionsProperty = QQmlListProperty<QObject>;
177
178 enum HeightMode {
179 AlwaysCenter,
180 AlwaysFill,
181 ConstrainIfLarger,
182 };
183 Q_ENUM(HeightMode)
184
185 ToolBarLayout(QQuickItem *parent = nullptr);
186 ~ToolBarLayout() override;
187
188 ActionsProperty actionsProperty() const;
189
190 void addAction(QObject *action);
191
192 void removeAction(QObject *action);
193
194 void clearActions();
195 Q_SIGNAL void actionsChanged();
196
197 QList<QObject *> hiddenActions() const;
198 Q_SIGNAL void hiddenActionsChanged();
199
200 QQmlComponent *fullDelegate() const;
201 void setFullDelegate(QQmlComponent *newFullDelegate);
202 Q_SIGNAL void fullDelegateChanged();
203
204 QQmlComponent *iconDelegate() const;
205 void setIconDelegate(QQmlComponent *newIconDelegate);
206 Q_SIGNAL void iconDelegateChanged();
207
208 QQmlComponent *separatorDelegate() const;
209 void setSeparatorDelegate(QQmlComponent *newSeparatorDelegate);
210 Q_SIGNAL void separatorDelegateChanged();
211
212 QQmlComponent *moreButton() const;
213 void setMoreButton(QQmlComponent *newMoreButton);
214 Q_SIGNAL void moreButtonChanged();
215
216 qreal spacing() const;
217 void setSpacing(qreal newSpacing);
218 Q_SIGNAL void spacingChanged();
219
220 Qt::Alignment alignment() const;
221 void setAlignment(Qt::Alignment newAlignment);
222 Q_SIGNAL void alignmentChanged();
223
224 qreal visibleWidth() const;
225 Q_SIGNAL void visibleWidthChanged();
226
227 qreal minimumWidth() const;
228 Q_SIGNAL void minimumWidthChanged();
229
230 Qt::LayoutDirection layoutDirection() const;
231 void setLayoutDirection(Qt::LayoutDirection &newLayoutDirection);
232 Q_SIGNAL void layoutDirectionChanged();
233
234 HeightMode heightMode() const;
235 void setHeightMode(HeightMode newHeightMode);
236 Q_SIGNAL void heightModeChanged();
237
238 /*!
239 * \qmlmethod void ToolBarLayout::relayout()
240 * Queue a relayout of this layout.
241 *
242 * \note The layouting happens during the next scene graph polishing phase.
243 */
244 Q_SLOT void relayout();
245
246 static ToolBarLayoutAttached *qmlAttachedProperties(QObject *object)
247 {
248 return new ToolBarLayoutAttached(object);
249 }
250
251protected:
252 void componentComplete() override;
253 void geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry) override;
254 void itemChange(QQuickItem::ItemChange change, const QQuickItem::ItemChangeData &data) override;
255 void updatePolish() override;
256
257private:
258 friend class ToolBarLayoutPrivate;
259 const std::unique_ptr<ToolBarLayoutPrivate> d;
260};
261
262QML_DECLARE_TYPEINFO(ToolBarLayout, QML_HAS_ATTACHED_PROPERTIES)
263
264#endif // TOOLBARLAYOUT_H
265

source code of kirigami/src/layouts/toolbarlayout.h