Kirigami2

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

KDE's Doxygen guidelines are available online.