Kirigami2

NavigationTabBar.qml
1/*
2 * Copyright 2021 Devin Lin <espidev@gmail.com>
3 *
4 * SPDX-License-Identifier: LGPL-2.0-or-later
5 */
6
7pragma ComponentBehavior: Bound
8
9import QtQuick
10import QtQml
11import QtQuick.Controls as QQC2
12import QtQuick.Templates as T
13import org.kde.kirigami as Kirigami
14
15/**
16 * @brief Page navigation tab-bar, used as an alternative to sidebars for 3-5 elements.
17 *
18 * Can be combined with secondary toolbars above (if in the footer) to provide page actions.
19 *
20 * Example usage:
21 * @code{.qml}
22 * import QtQuick 2.15
23 * import QtQuick.Controls 2.15
24 * import QtQuick.Layouts 1.15
25 * import org.kde.kirigami 2.20 as Kirigami
26 *
27 * Kirigami.ApplicationWindow {
28 * title: "Clock"
29 *
30 * pageStack.initialPage: worldPage
31 *
32 * Kirigami.Page {
33 * id: worldPage
34 * title: "World"
35 * visible: false
36 * }
37 * Kirigami.Page {
38 * id: timersPage
39 * title: "Timers"
40 * visible: false
41 * }
42 * Kirigami.Page {
43 * id: stopwatchPage
44 * title: "Stopwatch"
45 * visible: false
46 * }
47 * Kirigami.Page {
48 * id: alarmsPage
49 * title: "Alarms"
50 * visible: false
51 * }
52 *
53 * footer: Kirigami.NavigationTabBar {
54 * actions: [
55 * Kirigami.Action {
56 * icon.name: "globe"
57 * text: "World"
58 * checked: worldPage.visible
59 * onTriggered: {
60 * if (!worldPage.visible) {
61 * while (pageStack.depth > 0) {
62 * pageStack.pop();
63 * }
64 * pageStack.push(worldPage);
65 * }
66 * }
67 * },
68 * Kirigami.Action {
69 * icon.name: "player-time"
70 * text: "Timers"
71 * checked: timersPage.visible
72 * onTriggered: {
73 * if (!timersPage.visible) {
74 * while (pageStack.depth > 0) {
75 * pageStack.pop();
76 * }
77 * pageStack.push(timersPage);
78 * }
79 * }
80 * },
81 * Kirigami.Action {
82 * icon.name: "chronometer"
83 * text: "Stopwatch"
84 * checked: stopwatchPage.visible
85 * onTriggered: {
86 * if (!stopwatchPage.visible) {
87 * while (pageStack.depth > 0) {
88 * pageStack.pop();
89 * }
90 * pageStack.push(stopwatchPage);
91 * }
92 * }
93 * },
94 * Kirigami.Action {
95 * icon.name: "notifications"
96 * text: "Alarms"
97 * checked: alarmsPage.visible
98 * onTriggered: {
99 * if (!alarmsPage.visible) {
100 * while (pageStack.depth > 0) {
101 * pageStack.pop();
102 * }
103 * pageStack.push(alarmsPage);
104 * }
105 * }
106 * }
107 * ]
108 * }
109 * }
110 * @endcode
111 *
112 * @see NavigationTabButton
113 * @since 5.87
114 * @since org.kde.kirigami 2.19
115 * @inherit QtQuick.Templates.Toolbar
116 */
117
118QQC2.ToolBar {
119 id: root
120
121//BEGIN properties
122 /**
123 * @brief This property holds the list of actions to be displayed in the toolbar.
124 */
125 property list<T.Action> actions
126
127 /**
128 * @brief This property holds a subset of visible actions of the list of actions.
129 *
130 * An action is considered visible if it is either a Kirigami.Action with
131 * ``visible`` property set to true, or it is a plain QQC2.Action.
132 */
133 readonly property list<T.Action> visibleActions: actions
134 // Note: instanceof check implies `!== null`
135 .filter(action => action instanceof Kirigami.Action
136 ? action.visible
137 : action !== null
138 )
140 /**
141 * @brief The property holds the maximum width of the toolbar actions, before margins are added.
142 */
143 property real maximumContentWidth: {
144 const minDelegateWidth = Kirigami.Units.gridUnit * 5;
145 // Always have at least the width of 5 items, so that small amounts of actions look natural.
146 return minDelegateWidth * Math.max(visibleActions.length, 5);
147 }
148
149 /**
150 * @brief This property holds the index of currently checked tab.
151 *
152 * If the index set is out of bounds, or the triggered signal did not change any checked property of an action, the index
153 * will remain the same.
154 */
155 property int currentIndex: tabGroup.checkedButton && tabGroup.buttons.length > 0 ? tabGroup.checkedButton.tabIndex : -1
156
157 /**
158 * @brief This property holds the number of tab buttons.
159 */
160 readonly property int count: tabGroup.buttons.length
161
162 /**
163 * @brief This property holds the ButtonGroup used to manage the tabs.
164 */
165 readonly property T.ButtonGroup tabGroup: tabGroup
166
167 /**
168 * @brief This property holds the calculated width that buttons on the tab bar use.
169 *
170 * @since 5.102
171 */
172 property real buttonWidth: {
173 // Counting buttons because Repeaters can be counted among visibleChildren
174 let visibleButtonCount = 0;
175 const minWidth = contentItem.height * 0.75;
176 for (const visibleChild of contentItem.visibleChildren) {
177 if (contentItem.width / visibleButtonCount >= minWidth && // make buttons go off the screen if there is physically no room for them
178 visibleChild instanceof T.AbstractButton) { // Checking for AbstractButtons because any AbstractButton can act as a tab
179 ++visibleButtonCount;
180 }
181 }
182
183 return Math.round(contentItem.width / visibleButtonCount);
184 }
185//END properties
186
187 onCurrentIndexChanged: {
188 if (currentIndex === -1) {
189 if (tabGroup.checkState !== Qt.Unchecked) {
190 tabGroup.checkState = Qt.Unchecked;
191 }
192 return;
193 }
194 if (!tabGroup.checkedButton || tabGroup.checkedButton.tabIndex !== currentIndex) {
195 const buttonForCurrentIndex = tabGroup.buttons[currentIndex]
196 if (buttonForCurrentIndex.action) {
197 // trigger also toggles and causes clicked() to be emitted
198 buttonForCurrentIndex.action.trigger();
199 } else {
200 // toggle() does not trigger the action,
201 // so don't use it if you want to use an action.
202 // It also doesn't cause clicked() to be emitted.
203 buttonForCurrentIndex.toggle();
204 }
205 }
206 }
207
208 // ensure that by default, we do not have unintended padding and spacing from the style
209 spacing: 0
210 padding: 0
211 topPadding: undefined
212 leftPadding: undefined
213 rightPadding: undefined
214 bottomPadding: undefined
215 verticalPadding: undefined
216 // Using Math.round() on horizontalPadding can cause the contentItem to jitter left and right when resizing the window.
217 horizontalPadding: Math.floor(Math.max(0, width - root.maximumContentWidth) / 2)
218
219 contentWidth: Math.ceil(Math.min(root.availableWidth, root.maximumContentWidth))
220 implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset, contentWidth + leftPadding + rightPadding)
221 implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset, contentHeight + topPadding + bottomPadding)
222 position: {
223 if (QQC2.ApplicationWindow.window?.footer === root) {
224 return QQC2.ToolBar.Footer
225 } else if (parent?.footer === root) {
226 return QQC2.ToolBar.Footer
227 } else if (parent?.parent?.footer === parent) {
228 return QQC2.ToolBar.Footer
229 } else {
230 return QQC2.ToolBar.Header
231 }
232 }
233
234 // Using Row because setting just width is more convenient than having to set Layout.minimumWidth and Layout.maximumWidth
235 contentItem: Row {
236 id: rowLayout
237 spacing: root.spacing
238 }
239
240 // Used to manage which tab is checked and change the currentIndex
241 T.ButtonGroup {
242 id: tabGroup
243 exclusive: true
244 buttons: root.contentItem.children
245
246 onCheckedButtonChanged: {
247 if (!checkedButton) {
248 return
249 }
250 if (root.currentIndex !== checkedButton.tabIndex) {
251 root.currentIndex = checkedButton.tabIndex;
252 }
253 }
254 }
255
256 // Using a Repeater here because Instantiator was causing issues:
257 // NavigationTabButtons that were supposed to be destroyed were still
258 // registered as buttons in tabGroup.
259 // NOTE: This will make Repeater show up as child through visibleChildren
260 Repeater {
261 id: instantiator
262 model: root.visibleActions
263 delegate: NavigationTabButton {
264 id: delegate
265
266 required property T.Action modelData
267
268 parent: root.contentItem
269 action: modelData
270 width: root.buttonWidth
271 // Workaround setting the action when checkable is not explicitly set making tabs uncheckable
272 onActionChanged: action.checkable = true
273
274 Kirigami.Theme.textColor: root.Kirigami.Theme.textColor
275 Kirigami.Theme.backgroundColor: root.Kirigami.Theme.backgroundColor
276 Kirigami.Theme.highlightColor: root.Kirigami.Theme.highlightColor
277 }
278 }
279}
Navigation buttons to be used for the NavigationTabBar component.
qsizetype length() const const
QStringList filter(QStringView str, Qt::CaseSensitivity cs) const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Fri May 17 2024 11:49:07 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.