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

KDE's Doxygen guidelines are available online.