MauiKit Controls

ToolActions.qml
1import QtQuick
2import QtQuick.Controls
3import QtQuick.Layouts
4import QtQml
5
6import org.mauikit.controls as Maui
7import "private" as Private
8
9/**
10 * @inherit QtQuick.Controls.Control
11 * @brief A set of grouped action visually joined together.
12 *
13 * <a href="https://doc.qt.io/qt-6/qml-qtquick-controls-control.html">This control inherits from QQC2 Control, to checkout its inherited properties refer to the Qt Docs.</a>
14 *
15 * The set actions can be checkable and auto-exclusive or not.
16 *
17 * @image html Misc/toolactions.png "[1] Non-checkable. [2] Checkable non-auto-exclusive. [3] Checkable and autoexclusive"
18 *
19 * @section features Features
20 * This control supports checkable and non-checkable actions. Also auto-exclusive and non-auto-exclusive actions.
21 *
22 * When enabling the `autoExclusive` property, then only one action in the group can be marked as checked at the time.
23 *
24 * There is also the option to collapse the actions into a single button with a popup menu where the actions are listed, this is useful when the available space changes and the control needs to be made more compact to save space.
25 *
26 * @image html Misc/toolactions2.png "The collapsed actions into a menu"
27 *
28 * If only two actions are added and marked as auto-exclusive, then this control has the option to enable a `cyclic` behavior, which means that toggling one button will activate the next action in line and cyclic around.
29 * @see canCyclic
30 * @see cyclic
31 *
32 * Heres a example of how to achieve such behavior:
33 * @code
34 * Maui.ToolActions
35 * {
36 * id: _actions
37 * checkable: true
38 * autoExclusive: true
39 * cyclic: true //enable the cyclic behavior
40 * expanded: false //the cyclic behavior needs to be in the collapsed mode
41 *
42 * property int currentAction: 0 //here we keep the state for the current action checked
43 *
44 * Action
45 * {
46 * id: _action1
47 * icon.name: "view-list-details"
48 * checked: _actions.currentAction === 0
49 * onTriggered:
50 * {
51 * _actions.currentAction = 0
52 * }
53 * }
54 *
55 * Action
56 * {
57 * id: _action2
58 * icon.name: "view-list-icons"
59 * checked: _actions.currentAction === 1
60 * onTriggered:
61 * {
62 * _actions.currentAction = 1
63 * }
64 * }
65 * }
66 * @endcode
67 *
68 * @code
69 * Maui.ToolActions
70 * {
71 * checkable: true
72 * autoExclusive: true
73 *
74 * Action
75 * {
76 * text: "Pick"
77 * }
78 *
79 * Action
80 * {
81 * text: "Only"
82 * }
83 *
84 * Action
85 * {
86 * text: "One"
87 * }
88 * }
89 * @endcode
90 *
91 * <a href="https://invent.kde.org/maui/mauikit/-/blob/qt6-2/examples/ToolActions.qml">You can find a more complete example at this link.</a>
92 */
93Control
94{
95 id: control
96
97 implicitWidth: _loader.implicitWidth + leftPadding + rightPadding
98 implicitHeight: _loader.implicitHeight + topPadding + bottomPadding
99
100 opacity: enabled ? 1 : 0.5
101
102 spacing: 2
103 padding: 0
105 font.pointSize: Maui.Style.fontSizes.small
106
107 Maui.Theme.colorSet: Maui.Theme.Button
108 Maui.Theme.inherit: false
110 /**
111 * @brief The list of QQC2 Action to be listed. These can be declared a children elements of this control.
112 */
113 default property list<Action> actions
115 /**
116 * @brief Whether this control should only allow one action to be checked at the time.
117 * By default this is set to `true`
118 */
119 property bool autoExclusive: true
120
121 /**
122 * @brief Whether the action button can be checked. If enabled, then the state will be styled accordingly.
123 * @By default this is set to `true`.
124 */
125 property bool checkable: true
126
127 /**
128 * @brief Options on how to display the button text and icon.
129 * Available options are:
130 * - ToolButton.IconOnly
131 * - ToolButton.TextBesideIcon
132 * - ToolButton.TextOnly
133 * - ToolButton.TextUnderIcon
134 * By default this is set to `ToolButton.TextBesideIcon`
135 */
136 property int display: ToolButton.TextBesideIcon
137
138 /**
139 * @brief Whether two actions can be triggered in a cyclic manner. So one press will activate the next action and then cycle around to the first one again.
140 * @note For this to work only two actions can be added
141 * @see canCyclic
142 * By default this is set to `false`
143 */
144 property bool cyclic: false
146 /**
147 * @brief Whether the `cyclic` behavior can be activated.
148 * For it to be possible, the conditions are: only two actions and those must be auto-exclusive.
149 * @see cyclic
150 * @see autoExclusive
151 * @see count
152 */
153 readonly property bool canCyclic : control.cyclic && control.count === 2 && control.autoExclusive
154
155 /**
156 * @brief Whether the style of this control should be styled as flat.
157 * By default this is set to `false`.
158 */
159 property bool flat : false
161 /**
162 * @brief The total amount of actions declared.
163 */
164 readonly property int count : actions.length
166
167 /**
168 * @brief Whether the control should display all the actions as buttons in a row, or to collapse them into a popup menu.
169 * By default this is set to `true`.
170 */
171 property bool expanded : true
172
173 /**
174 * @brief The icon name to be used in the button that opens the menu popup, when the view is collapsed.
175 * By default this is set to `application-menu`.
176 */
177 property string defaultIconName: "application-menu"
178
179 /**
180 * @brief Forces to uncheck all the actions except the one action sent as the argument.
181 * @param except the action that should not be unchecked.
182 */
183 function uncheck(except)
184 {
185 for(var i in control.actions)
186 {
187 if(control.actions[i] === except)
188 {
189 continue
190 }
191
192 control.actions[i].checked = false
193 }
194 }
195
196 Behavior on implicitWidth
197 {
198 NumberAnimation
199 {
200 duration: Maui.Style.units.shortDuration
201 easing.type: Easing.InQuad
202 }
203 }
204
205 contentItem: Loader
206 {
207 id: _loader
208 asynchronous: true
209 sourceComponent: control.expanded ? _rowComponent : (control.canCyclic ? _buttonComponent : _toolButtonMenuComponent)
210 }
211
212 background: null
213
214 Component
215 {
216 id: _rowComponent
217
218 Row
219 {
220 id: _row
221 property int biggerHeight : 0
222 spacing: control.spacing
223
224 Behavior on width
225 {
226 enabled: Maui.Style.enableEffects
227
228 NumberAnimation
229 {
230 duration: Maui.Style.units.shortDuration
231 easing.type: Easing.InOutQuad
232 }
233 }
234
235 function calculateBiggerHeight()
236 {
237 var value = 0
238 for(var i in _row.children)
239 {
240 const height = _row.children[i].implicitHeight
241 if(height > value)
242 {
243 value = height
244 }
245 }
246
247 return value
248 }
249
250 Repeater
251 {
252 id: _repeater
253 model: control.actions
254
255 ToolButton
256 {
257 id: _actionButton
258 action : modelData
259 Maui.Controls.status: control.Maui.Controls.status
260
261 checkable: control.checkable || action.checkable
262
263 height: Math.max(implicitHeight, _row.biggerHeight)
264
265 onImplicitHeightChanged: _row.biggerHeight = _row.calculateBiggerHeight()
266
267 autoExclusive: control.autoExclusive
268 enabled: action.enabled
269
270 display: control.display
271 font: control.font
272
273 background: Maui.ShadowedRectangle
274 {
275 color: (checked || down ? Maui.Theme.highlightColor : ( hovered ? Maui.Theme.hoverColor : Maui.Theme.backgroundColor))
276 corners
277 {
278 topLeftRadius: index === 0 ? Maui.Style.radiusV : 0
279 topRightRadius: index === _repeater.count - 1 ? Maui.Style.radiusV : 0
280 bottomLeftRadius: index === 0 ? Maui.Style.radiusV : 0
281 bottomRightRadius: index === _repeater.count - 1 ? Maui.Style.radiusV : 0
282 }
283
284 Behavior on color
285 {
286 Maui.ColorTransition{}
287 }
288
289 Behavior on border.color
290 {
291 Maui.ColorTransition{}
292 }
293
294 border.color: statusColor(_actionButton)
295
296 function statusColor(control)
297 {
298 if(control.Maui.Controls.status)
299 {
300 switch(control.Maui.Controls.status)
301 {
302 case Maui.Controls.Positive: return control.Maui.Theme.positiveBackgroundColor
303 case Maui.Controls.Negative: return control.Maui.Theme.negativeBackgroundColor
304 case Maui.Controls.Neutral: return control.Maui.Theme.neutralBackgroundColor
305 case Maui.Controls.Normal:
306 default:
307 return "red"
308 }
309 }
310
311 return "red"
312 }
313 }
314 }
315 }
316 }
317 }
318
319 Component
320 {
321 id: _toolButtonMenuComponent
322
323 Maui.ToolButtonMenu
324 {
325 Maui.Controls.status: control.Maui.Controls.status
326 flat: false
327 property Action m_action
328 hoverEnabled: true
329 display: control.display
330 icon.name: m_action ? m_action.icon.name : control.defaultIconName
331 text: m_action ? m_action.text: ""
332
333 Component.onCompleted:
334 {
335 m_action = buttonAction()
336 }
337
338 Repeater
339 {
340 model: control.autoExclusive && control.canCyclic ? undefined : control.actions
341
342 delegate: MenuItem
343 {
344 action: modelData
345 enabled: modelData.enabled
346 autoExclusive: control.autoExclusive
347 checkable: control.checkable || action.checkable
348 }
349 }
350
351 Row
352 {
353 visible: false
354 Repeater
355 {
356 model: control.actions
357 delegate: Item
358 {
359 property bool checked : modelData.checked
360 onCheckedChanged: m_action = buttonAction()
361 }
362 }
363 }
364
365 function buttonAction()
366 {
367 if(control.autoExclusive)
368 {
369 var currentAction
370 var actionIndex = -1
371 for(var i in control.actions)
372 {
373 console.log("Checking current action", i)
374 if(control.actions[i].checked)
375 {
376 actionIndex = i
377 currentAction = control.actions[actionIndex]
378 console.log("Found current action", i, actionIndex)
379 return currentAction
380 }
381 }
382 }
383
384 return null
385 }
386 }
387 }
388
389 Component
390 {
391 id: _buttonComponent
392
393 Button
394 {
395 id: _defaultButtonIcon
396 Maui.Controls.status: control.Maui.Controls.status
397
398 property Action m_action
399
400 function buttonAction()
401 {
402 if(control.autoExclusive)
403 {
404 var currentAction
405 var actionIndex = -1
406 for(var i in control.actions)
407 {
408 console.log("Checking current action", i)
409 if(control.actions[i].checked)
410 {
411 actionIndex = i
412 currentAction = control.actions[actionIndex]
413 console.log("Found current action", i, actionIndex)
414 }
415 }
416
417 if(control.canCyclic)
418 {
419 actionIndex++
420
421 let m_index = actionIndex >= control.actions.length ? 0 : actionIndex
422 //
423 console.log("Setting current action at", m_index)
424 if(control.actions[m_index].enabled)
425 {
426 return control.actions[m_index];
427 }
428 }
429
430 return currentAction
431 }
432
433 return null
434 }
435
436 Row
437 {
438 visible: false
439 Repeater
440 {
441 model: control.actions
442 delegate: Item
443 {
444 property bool checked : modelData.checked
445 onCheckedChanged: _defaultButtonIcon.m_action = _defaultButtonIcon.buttonAction()
446 }
447 }
448 }
449
450 onClicked:
451 {
452 if(_defaultButtonIcon.m_action && control.canCyclic)
453 {
454 console.log("Trigger next cyclic action", _defaultButtonIcon.m_action.icon.name)
455 // var previousAction = _defaultButtonIcon.action
456 _defaultButtonIcon.m_action.triggered()
457 _defaultButtonIcon.m_action = _defaultButtonIcon.buttonAction()
458 }
459 }
460
461 icon.color: m_action ? (m_action.icon.color && m_action.icon.color.length ? m_action.icon.color : (pressed || checked ? control.Maui.Theme.highlightedTextColor : control.Maui.Theme.textColor)) : control.Maui.Theme.textColor
462
463 icon.name: m_action ? m_action.icon.name : control.defaultIconName
464 text: m_action ? m_action.text: ""
465
466 enabled: m_action ? m_action.enabled : true
467
468 Component.onCompleted:
469 {
470 _defaultButtonIcon.m_action = _defaultButtonIcon.buttonAction()
471 }
472
473 display: control.display
474
475 checkable: control.checkable && (action ? action.checkable : false)
476 }
477 }
478}
list< Action > actions
The list of QQC2 Action to be listed.
bool canCyclic
Whether the cyclic behavior can be activated.
void uncheck(except)
Forces to uncheck all the actions except the one action sent as the argument.
int display
Options on how to display the button text and icon.
bool flat
Whether the style of this control should be styled as flat.
bool checkable
Whether the action button can be checked.
bool autoExclusive
Whether this control should only allow one action to be checked at the time.
bool cyclic
Whether two actions can be triggered in a cyclic manner.
bool expanded
Whether the control should display all the actions as buttons in a row, or to collapse them into a po...
int count
The total amount of actions declared.
string defaultIconName
The icon name to be used in the button that opens the menu popup, when the view is collapsed.
QString name(StandardAction id)
This file is part of the KDE documentation.
Documentation copyright © 1996-2025 The KDE developers.
Generated on Fri May 2 2025 11:57:11 by doxygen 1.13.2 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.