Warning, /frameworks/kirigami/src/controls/NavigationTabBar.qml is written in an unsupported language. File is not indexed.
0001 /* 0002 * Copyright 2021 Devin Lin <espidev@gmail.com> 0003 * 0004 * SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 import QtQuick 2.15 0008 import QtQml 2.15 0009 import QtQuick.Layouts 1.15 0010 import QtGraphicalEffects 1.12 as GE 0011 import QtQuick.Templates 2.15 as T 0012 import org.kde.kirigami 2.19 as Kirigami 0013 0014 /** 0015 * @brief Page navigation tab-bar, used as an alternative to sidebars for 3-5 elements. 0016 * 0017 * Can be combined with secondary toolbars above (if in the footer) to provide page actions. 0018 * 0019 * Example usage: 0020 * @code{.qml} 0021 * import QtQuick 2.15 0022 * import QtQuick.Controls 2.15 0023 * import QtQuick.Layouts 1.15 0024 * import org.kde.kirigami 2.20 as Kirigami 0025 * 0026 * Kirigami.ApplicationWindow { 0027 * title: "Clock" 0028 * 0029 * pageStack.initialPage: worldPage 0030 * Kirigami.Page { 0031 * id: worldPage 0032 * title: "World" 0033 * visible: false 0034 * } 0035 * Kirigami.Page { 0036 * id: timersPage 0037 * title: "Timers" 0038 * visible: false 0039 * } 0040 * Kirigami.Page { 0041 * id: stopwatchPage 0042 * title: "Stopwatch" 0043 * visible: false 0044 * } 0045 * Kirigami.Page { 0046 * id: alarmsPage 0047 * title: "Alarms" 0048 * visible: false 0049 * } 0050 * 0051 * 0052 * footer: Kirigami.NavigationTabBar { 0053 * actions: [ 0054 * Kirigami.Action { 0055 * iconName: "globe" 0056 * text: "World" 0057 * checked: worldPage.visible 0058 * onTriggered: { 0059 * if (!worldPage.visible) { 0060 * while (pageStack.depth > 0) { 0061 * pageStack.pop(); 0062 * } 0063 * pageStack.push(worldPage); 0064 * } 0065 * } 0066 * }, 0067 * Kirigami.Action { 0068 * iconName: "player-time" 0069 * text: "Timers" 0070 * checked: timersPage.visible 0071 * onTriggered: { 0072 * if (!timersPage.visible) { 0073 * while (pageStack.depth > 0) { 0074 * pageStack.pop(); 0075 * } 0076 * pageStack.push(timersPage); 0077 * } 0078 * } 0079 * }, 0080 * Kirigami.Action { 0081 * iconName: "chronometer" 0082 * text: "Stopwatch" 0083 * checked: stopwatchPage.visible 0084 * onTriggered: { 0085 * if (!stopwatchPage.visible) { 0086 * while (pageStack.depth > 0) { 0087 * pageStack.pop(); 0088 * } 0089 * pageStack.push(stopwatchPage); 0090 * } 0091 * } 0092 * }, 0093 * Kirigami.Action { 0094 * iconName: "notifications" 0095 * text: "Alarms" 0096 * checked: alarmsPage.visible 0097 * onTriggered: { 0098 * if (!alarmsPage.visible) { 0099 * while (pageStack.depth > 0) { 0100 * pageStack.pop(); 0101 * } 0102 * pageStack.push(alarmsPage); 0103 * } 0104 * } 0105 * } 0106 * ] 0107 * } 0108 * } 0109 * @endcode 0110 * @see kirigami::NavigationTabButton 0111 * @see <a href="https://develop.kde.org/hig/components/navigation/navigationtabbar">Human Interface Guidelines on Navigation Tab Bars</a> 0112 * @since KDE Frameworks 5.87 0113 * @since org.kde.kirigami 2.19 0114 * @inherit QtQuick.Templates.Toolbar 0115 */ 0116 0117 T.ToolBar { 0118 id: root 0119 0120 //BEGIN properties 0121 /** 0122 * @brief This property holds the list of actions displayed in the toolbar. 0123 */ 0124 property list<Kirigami.Action> actions 0125 0126 /** 0127 * @brief The property holds the maximum width of the toolbar actions, before margins are added. 0128 */ 0129 property real maximumContentWidth: { 0130 const minDelegateWidth = Kirigami.Units.gridUnit * 5; 0131 // Always have at least the width of 5 items, so that small amounts of actions look natural. 0132 return minDelegateWidth * Math.max(actions.length, 5); 0133 } 0134 0135 /** 0136 * @brief This property holds the background color of the toolbar. 0137 * 0138 * default: @link Kirigami.PlatformTheme.highlightColor Kirigami.Theme.highlightColor @endlink 0139 */ 0140 property color backgroundColor: Kirigami.Theme.backgroundColor 0141 0142 /** 0143 * @brief This property holds the foreground color of the toolbar (text, icon). 0144 */ 0145 property color foregroundColor: Qt.rgba(Kirigami.Theme.textColor.r, Kirigami.Theme.textColor.g, Kirigami.Theme.textColor.b, 0.85) 0146 0147 /** 0148 * @brief This property holds the highlight foreground color (text, icon when action is checked). 0149 */ 0150 property color highlightForegroundColor: Qt.rgba(Kirigami.Theme.textColor.r, Kirigami.Theme.textColor.g, Kirigami.Theme.textColor.b, 0.85) 0151 0152 /** 0153 * @brief This property holds the color of the highlight bar when an action is checked. 0154 * 0155 * default: @link Kirigami.PlatformTheme.highlightColor Kirigami.Theme.highlightColor @endlink 0156 */ 0157 property color highlightBarColor: Kirigami.Theme.highlightColor 0158 0159 /** 0160 * @brief This property sets whether the toolbar should provide its own shadow. 0161 * 0162 * default: ``true`` 0163 */ 0164 property bool shadow: true 0165 0166 /** 0167 * @brief This property holds the index of currently checked tab. 0168 * 0169 * If the index set is out of bounds, or the triggered signal did not change any checked property of an action, the index 0170 * will remain the same. 0171 */ 0172 property int currentIndex: tabGroup.checkedButton && tabGroup.buttons.length > 0 ? tabGroup.checkedButton.tabIndex : -1 0173 0174 /** 0175 * @brief This property holds the number of tab buttons. 0176 */ 0177 readonly property int count: tabGroup.buttons.length 0178 0179 /** 0180 * @brief This property holds the ButtonGroup used to manage the tabs. 0181 */ 0182 readonly property T.ButtonGroup tabGroup: tabGroup 0183 0184 /** 0185 * @brief This property sets whether the icon colors should be masked with a single color. 0186 * 0187 * This only applies to buttons generated by the actions property. 0188 * 0189 * default: ``true`` 0190 * 0191 * @since KDE Frameworks 5.96 0192 */ 0193 property bool recolorIcons: true 0194 0195 /** 0196 * @brief This property holds the calculated width that buttons on the tab bar use. 0197 * 0198 * @since KDE Frameworks 5.102 0199 */ 0200 property real buttonWidth: { 0201 // Counting buttons because Repeaters can be counted among visibleChildren 0202 let visibleButtonCount = 0; 0203 const minWidth = contentItem.height * 0.75; 0204 for (let i = 0; i < contentItem.visibleChildren.length; ++i) { 0205 if (contentItem.width / visibleButtonCount >= minWidth && // make buttons go off the screen if there is physically no room for them 0206 contentItem.visibleChildren[i] instanceof T.AbstractButton) { // Checking for AbstractButtons because any AbstractButton can act as a tab 0207 ++visibleButtonCount; 0208 } 0209 } 0210 0211 return Math.round(contentItem.width / visibleButtonCount); 0212 } 0213 //END properties 0214 0215 onCurrentIndexChanged: { 0216 if (currentIndex === -1) { 0217 if (tabGroup.checkState !== Qt.Unchecked) { 0218 tabGroup.checkState = Qt.Unchecked; 0219 } 0220 return; 0221 } 0222 if (tabGroup.checkedButton.tabIndex !== currentIndex) { 0223 const buttonForCurrentIndex = tabGroup.buttons[currentIndex] 0224 if (buttonForCurrentIndex.action) { 0225 // trigger also toggles and causes clicked() to be emitted 0226 buttonForCurrentIndex.action.trigger(); 0227 } else { 0228 // toggle() does not trigger the action, 0229 // so don't use it if you want to use an action. 0230 // It also doesn't cause clicked() to be emitted. 0231 buttonForCurrentIndex.toggle(); 0232 } 0233 } 0234 } 0235 0236 // Using Math.round() on horizontalPadding can cause the contentItem to jitter left and right when resizing the window. 0237 horizontalPadding: Math.floor(Math.max(0, width - root.maximumContentWidth) / 2) 0238 contentWidth: Math.ceil(Math.min(root.availableWidth, root.maximumContentWidth)) 0239 implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset, contentWidth + leftPadding + rightPadding) 0240 implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset, contentHeight + topPadding + bottomPadding) 0241 0242 Kirigami.Theme.colorSet: Kirigami.Theme.Window 0243 0244 background: Rectangle { // color & shadow 0245 implicitHeight: Kirigami.Units.gridUnit * 3 + Kirigami.Units.smallSpacing * 2 0246 color: root.backgroundColor 0247 GE.RectangularGlow { 0248 anchors.fill: parent 0249 z: -1 0250 visible: root.shadow 0251 glowRadius: 5 0252 spread: 0.3 0253 color: Qt.rgba(0.0, 0.0, 0.0, 0.15) 0254 } 0255 } 0256 0257 // Using Row because setting just width is more convenient than having to set Layout.minimumWidth and Layout.maximumWidth 0258 contentItem: Row { 0259 id: rowLayout 0260 spacing: root.spacing 0261 } 0262 0263 // Used to manage which tab is checked and change the currentIndex 0264 T.ButtonGroup { 0265 id: tabGroup 0266 exclusive: true 0267 buttons: root.contentItem.children 0268 0269 onCheckedButtonChanged: { 0270 if (!checkedButton) { 0271 return 0272 } 0273 if (root.currentIndex !== checkedButton.tabIndex) { 0274 root.currentIndex = checkedButton.tabIndex; 0275 } 0276 } 0277 } 0278 0279 // Using a Repeater here because Instantiator was causing issues: 0280 // NavigationTabButtons that were supposed to be destroyed were still 0281 // registered as buttons in tabGroup. 0282 // NOTE: This will make Repeater show up as child through visibleChildren 0283 Repeater { 0284 id: instantiator 0285 model: root.actions 0286 delegate: NavigationTabButton { 0287 id: delegate 0288 parent: root.contentItem 0289 action: modelData 0290 visible: modelData.visible 0291 width: root.buttonWidth 0292 recolorIcon: root.recolorIcons 0293 T.ButtonGroup.group: tabGroup 0294 // Workaround setting the action when checkable is not explicitly set making tabs uncheckable 0295 onActionChanged: action.checkable = true 0296 0297 foregroundColor: root.foregroundColor 0298 highlightForegroundColor: root.highlightForegroundColor 0299 highlightBarColor: root.highlightBarColor 0300 } 0301 } 0302 }