Warning, /frameworks/kirigami/src/controls/GlobalDrawer.qml is written in an unsupported language. File is not indexed.
0001 /* 0002 * SPDX-FileCopyrightText: 2015 Marco Martin <mart@kde.org> 0003 * 0004 * SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 pragma ComponentBehavior: Bound 0008 0009 import QtQuick 0010 import QtQuick.Templates as T 0011 import QtQuick.Controls as QQC2 0012 import QtQuick.Layouts 0013 import org.kde.kirigami as Kirigami 0014 import "private" as KP 0015 0016 /** 0017 * A specialized form of the Drawer intended for showing an application's 0018 * always-available global actions. Think of it like a mobile version of 0019 * a desktop application's menubar. 0020 * 0021 * Example usage: 0022 * @code 0023 * import org.kde.kirigami 2.4 as Kirigami 0024 * 0025 * Kirigami.ApplicationWindow { 0026 * [...] 0027 * globalDrawer: Kirigami.GlobalDrawer { 0028 * actions: [ 0029 * Kirigami.Action { 0030 * text: "View" 0031 * icon.name: "view-list-icons" 0032 * Kirigami.Action { 0033 * text: "action 1" 0034 * } 0035 * Kirigami.Action { 0036 * text: "action 2" 0037 * } 0038 * Kirigami.Action { 0039 * text: "action 3" 0040 * } 0041 * }, 0042 * Kirigami.Action { 0043 * text: "Sync" 0044 * icon.name: "folder-sync" 0045 * } 0046 * ] 0047 * } 0048 * [...] 0049 * } 0050 * @endcode 0051 * 0052 */ 0053 Kirigami.OverlayDrawer { 0054 id: root 0055 0056 edge: Qt.application.layoutDirection === Qt.RightToLeft ? Qt.RightEdge : Qt.LeftEdge 0057 0058 handleClosedIcon.source: null 0059 handleOpenIcon.source: null 0060 0061 handleVisible: { 0062 // When drawer is inline with content and opened, there is no point is showing handle. 0063 if (!modal && drawerOpen) { 0064 return false; 0065 } 0066 0067 // GlobalDrawer can be hidden by controlsVisible... 0068 if (typeof applicationWindow === "function") { 0069 const w = applicationWindow(); 0070 if (w && !w.controlsVisible) { 0071 return false; 0072 } 0073 } 0074 0075 // ...but it still performs additional checks. 0076 return !isMenu || Kirigami.Settings.isMobile; 0077 } 0078 0079 enabled: !isMenu || Kirigami.Settings.isMobile 0080 0081 //BEGIN properties 0082 /** 0083 * @brief This property holds the title displayed at the top of the drawer. 0084 * @see org::kde::kirigami::private::BannerImage::title 0085 * @property string title 0086 */ 0087 property string title 0088 0089 /** 0090 * @brief This property holds an icon to be displayed alongside the title. 0091 * @see org::kde::kirigami::private::BannerImage::titleIcon 0092 * @see org::kde::kirigami::Icon::source 0093 * @property var titleIcon 0094 */ 0095 property var titleIcon 0096 0097 /** 0098 * @brief This property holds the actions displayed in the drawer. 0099 * 0100 * The list of actions can be nested having a tree structure. 0101 * A tree depth bigger than 2 is discouraged. 0102 * 0103 * Example usage: 0104 * 0105 * @code 0106 * import org.kde.kirigami as Kirigami 0107 * 0108 * Kirigami.ApplicationWindow { 0109 * globalDrawer: Kirigami.GlobalDrawer { 0110 * actions: [ 0111 * Kirigami.Action { 0112 * text: "View" 0113 * icon.name: "view-list-icons" 0114 * Kirigami.Action { 0115 * text: "action 1" 0116 * } 0117 * Kirigami.Action { 0118 * text: "action 2" 0119 * } 0120 * Kirigami.Action { 0121 * text: "action 3" 0122 * } 0123 * }, 0124 * Kirigami.Action { 0125 * text: "Sync" 0126 * icon.name: "folder-sync" 0127 * } 0128 * ] 0129 * } 0130 * } 0131 * @endcode 0132 * @property list<T.Action> actions 0133 */ 0134 property list<T.Action> actions 0135 0136 /** 0137 * @brief This property holds an item that will always be displayed at the top of the drawer. 0138 * 0139 * If the drawer contents can be scrolled, this item will stay still and won't scroll. 0140 * 0141 * @note This property is mainly intended for toolbars. 0142 * @since 2.12 0143 */ 0144 property alias header: mainLayout.header 0145 0146 /** 0147 * @brief This property holds an item that will always be displayed at the bottom of the drawer. 0148 * 0149 * If the drawer contents can be scrolled, this item will stay still and won't scroll. 0150 * 0151 * @note This property is mainly intended for toolbars. 0152 * @since 6.0 0153 */ 0154 property alias footer: mainLayout.footer 0155 0156 /** 0157 * @brief This property holds items that are displayed above the actions. 0158 * 0159 * Example usage: 0160 * @code 0161 * import org.kde.kirigami 2.4 as Kirigami 0162 * 0163 * Kirigami.ApplicationWindow { 0164 * [...] 0165 * globalDrawer: Kirigami.GlobalDrawer { 0166 * actions: [...] 0167 * topContent: [Button { 0168 * text: "Button" 0169 * onClicked: //do stuff 0170 * }] 0171 * } 0172 * [...] 0173 * } 0174 * @endcode 0175 * @property list<QtObject> topContent 0176 */ 0177 property alias topContent: topContent.data 0178 0179 /** 0180 * @brief This property holds items that are displayed under the actions. 0181 * 0182 * Example usage: 0183 * @code 0184 * import org.kde.kirigami 2.4 as Kirigami 0185 * 0186 * Kirigami.ApplicationWindow { 0187 * [...] 0188 * globalDrawer: Kirigami.GlobalDrawer { 0189 * actions: [...] 0190 * Button { 0191 * text: "Button" 0192 * onClicked: //do stuff 0193 * } 0194 * } 0195 * [...] 0196 * } 0197 * @endcode 0198 * @note This is a `default` property. 0199 * @property list<QtObject> content 0200 */ 0201 default property alias content: mainContent.data 0202 0203 /** 0204 * @brief This property sets whether content items at the top should be shown. 0205 * when the drawer is collapsed as a sidebar. 0206 * 0207 * If you want to keep some items visible and some invisible, set this to 0208 * false and control the visibility/opacity of individual items, 0209 * binded to the collapsed property 0210 * 0211 * default: ``false`` 0212 * 0213 * @since 2.5 0214 */ 0215 property bool showTopContentWhenCollapsed: false 0216 0217 /** 0218 * @brief This property sets whether content items at the bottom should be shown. 0219 * when the drawer is collapsed as a sidebar. 0220 * 0221 * If you want to keep some items visible and some invisible, set this to 0222 * false and control the visibility/opacity of individual items, 0223 * binded to the collapsed property 0224 * 0225 * default: ``false`` 0226 * 0227 * @see content 0228 * @since 2.5 0229 */ 0230 property bool showContentWhenCollapsed: false 0231 0232 // TODO 0233 property bool showHeaderWhenCollapsed: false 0234 0235 /** 0236 * @brief This property sets whether activating a leaf action resets the 0237 * menu to show leaf's parent actions. 0238 * 0239 * A leaf action is an action without any child actions. 0240 * 0241 * default: ``true`` 0242 */ 0243 property bool resetMenuOnTriggered: true 0244 0245 /** 0246 * @brief This property points to the action acting as a submenu 0247 */ 0248 readonly property T.Action currentSubMenu: stackView.currentItem?.current ?? null 0249 0250 /** 0251 * @brief This property sets whether the drawer becomes a menu on the desktop. 0252 * 0253 * default: ``false`` 0254 * 0255 * @since 2.11 0256 */ 0257 property bool isMenu: false 0258 0259 /** 0260 * @brief This property sets the visibility of the collapse button 0261 * when the drawer collapsible. 0262 * 0263 * default: ``true`` 0264 * 0265 * @since 2.12 0266 */ 0267 property bool collapseButtonVisible: true 0268 //END properties 0269 0270 /** 0271 * @brief This function reverts the menu back to its initial state 0272 */ 0273 function resetMenu() { 0274 stackView.pop(stackView.get(0, T.StackView.DontLoad)); 0275 if (root.modal) { 0276 root.drawerOpen = false; 0277 } 0278 } 0279 0280 // rightPadding: !Kirigami.Settings.isMobile && mainFlickable.contentHeight > mainFlickable.height ? Kirigami.Units.gridUnit : Kirigami.Units.smallSpacing 0281 0282 Kirigami.Theme.colorSet: modal ? Kirigami.Theme.Window : Kirigami.Theme.View 0283 0284 onIsMenuChanged: drawerOpen = false 0285 0286 Component { 0287 id: menuComponent 0288 0289 Column { 0290 property alias model: actionsRepeater.model 0291 property T.Action current 0292 property int level: 0 0293 0294 spacing: 0 0295 Layout.maximumHeight: Layout.minimumHeight 0296 0297 QQC2.ItemDelegate { 0298 id: backItem 0299 0300 visible: level > 0 0301 width: parent.width 0302 icon.name: mirrored ? "go-previous-symbolic-rtl" : "go-previous-symbolic" 0303 0304 text: Kirigami.MnemonicData.richTextLabel 0305 0306 Kirigami.MnemonicData.enabled: enabled && visible 0307 Kirigami.MnemonicData.controlType: Kirigami.MnemonicData.MenuItem 0308 Kirigami.MnemonicData.label: qsTr("Back") 0309 0310 onClicked: stackView.pop() 0311 0312 Keys.onEnterPressed: stackView.pop() 0313 Keys.onReturnPressed: stackView.pop() 0314 0315 Keys.onDownPressed: nextItemInFocusChain().focus = true 0316 Keys.onUpPressed: nextItemInFocusChain(false).focus = true 0317 } 0318 0319 Shortcut { 0320 sequence: backItem.Kirigami.MnemonicData.sequence 0321 onActivated: backItem.clicked() 0322 } 0323 0324 Repeater { 0325 id: actionsRepeater 0326 0327 readonly property bool withSections: { 0328 for (const action of root.actions) { 0329 if (action.hasOwnProperty("expandible") && action.expandible) { 0330 return true; 0331 } 0332 } 0333 return false; 0334 } 0335 0336 model: root.actions 0337 0338 delegate: ActionDelegate { 0339 required property T.Action modelData 0340 0341 tAction: modelData 0342 withSections: actionsRepeater.withSections 0343 } 0344 } 0345 } 0346 } 0347 0348 component ActionDelegate : Column { 0349 id: delegate 0350 0351 required property int index 0352 required property T.Action tAction 0353 required property bool withSections 0354 0355 // `as` case operator is still buggy 0356 readonly property Kirigami.Action kAction: tAction instanceof Kirigami.Action ? tAction : null 0357 0358 readonly property bool isExpanded: { 0359 return !root.collapsed 0360 && kAction 0361 && kAction.expandible 0362 && kAction.children.length > 0; 0363 } 0364 0365 visible: kAction?.visible ?? true 0366 0367 width: parent.width 0368 0369 KP.GlobalDrawerActionItem { 0370 Kirigami.Theme.colorSet: !root.modal && !root.collapsed && delegate.withSections 0371 ? Kirigami.Theme.Window : parent.Kirigami.Theme.colorSet 0372 0373 visible: !delegate.isExpanded 0374 width: parent.width 0375 0376 tAction: delegate.tAction 0377 0378 onCheckedChanged: { 0379 // move every checked item into view 0380 if (checked && topContent.height + backItem.height + (delegate.index + 1) * height - mainFlickable.contentY > mainFlickable.height) { 0381 mainFlickable.contentY += height 0382 } 0383 } 0384 } 0385 0386 Item { 0387 id: headerItem 0388 0389 visible: delegate.isExpanded 0390 height: sectionHeader.implicitHeight 0391 width: parent.width 0392 0393 Kirigami.ListSectionHeader { 0394 id: sectionHeader 0395 0396 anchors.fill: parent 0397 Kirigami.Theme.colorSet: root.modal ? Kirigami.Theme.View : Kirigami.Theme.Window 0398 0399 contentItem: RowLayout { 0400 spacing: sectionHeader.spacing 0401 0402 Kirigami.Icon { 0403 property int size: Kirigami.Units.iconSizes.smallMedium 0404 Layout.minimumHeight: size 0405 Layout.maximumHeight: size 0406 Layout.minimumWidth: size 0407 Layout.maximumWidth: size 0408 source: delegate.tAction.icon.name || delegate.tAction.icon.source 0409 } 0410 0411 Kirigami.Heading { 0412 level: 4 0413 text: delegate.tAction.text 0414 elide: Text.ElideRight 0415 Layout.fillWidth: true 0416 } 0417 } 0418 } 0419 } 0420 0421 Repeater { 0422 model: delegate.isExpanded ? (delegate.kAction?.children ?? null) : null 0423 0424 NestedActionDelegate { 0425 required property T.Action modelData 0426 0427 tAction: modelData 0428 withSections: delegate.withSections 0429 } 0430 } 0431 } 0432 0433 component NestedActionDelegate : KP.GlobalDrawerActionItem { 0434 required property bool withSections 0435 0436 width: parent.width 0437 opacity: !root.collapsed 0438 leftPadding: withSections && !root.collapsed && !root.modal ? padding * 2 : padding * 4 0439 } 0440 0441 contentItem: Kirigami.HeaderFooterLayout { 0442 id: mainLayout 0443 0444 anchors { 0445 fill: parent 0446 topMargin: root.collapsed && !showHeaderWhenCollapsed ? -contentItem.y : 0 0447 } 0448 0449 Behavior on anchors.topMargin { 0450 NumberAnimation { 0451 duration: Kirigami.Units.longDuration 0452 easing.type: Easing.InOutQuad 0453 } 0454 } 0455 0456 header: RowLayout { 0457 visible: root.title.length > 0 || Boolean(root.titleIcon) 0458 0459 Kirigami.Icon { 0460 source: root.titleIcon 0461 } 0462 0463 Kirigami.Heading { 0464 text: root.title 0465 elide: Text.ElideRight 0466 visible: !root.collapsed 0467 Layout.fillWidth: true 0468 } 0469 } 0470 0471 contentItem: QQC2.ScrollView { 0472 id: scrollView 0473 0474 //ensure the attached property exists 0475 Kirigami.Theme.inherit: true 0476 0477 // HACK: workaround for https://bugreports.qt.io/browse/QTBUG-83890 0478 QQC2.ScrollBar.horizontal.policy: QQC2.ScrollBar.AlwaysOff 0479 0480 implicitWidth: Math.min(Kirigami.Units.gridUnit * 20, root.parent.width * 0.8) 0481 0482 Flickable { 0483 id: mainFlickable 0484 0485 contentWidth: width 0486 contentHeight: mainColumn.Layout.minimumHeight 0487 0488 clip: root.footer !== null 0489 0490 ColumnLayout { 0491 id: mainColumn 0492 width: mainFlickable.width 0493 spacing: 0 0494 height: Math.max(scrollView.height, Layout.minimumHeight) 0495 0496 ColumnLayout { 0497 id: topContent 0498 0499 spacing: 0 0500 0501 Layout.alignment: Qt.AlignHCenter 0502 Layout.leftMargin: root.leftPadding 0503 Layout.rightMargin: root.rightPadding 0504 Layout.bottomMargin: Kirigami.Units.smallSpacing 0505 Layout.topMargin: root.topPadding 0506 Layout.fillWidth: true 0507 Layout.fillHeight: true 0508 Layout.preferredHeight: implicitHeight * opacity 0509 // NOTE: why this? just Layout.fillWidth: true doesn't seem sufficient 0510 // as items are added only after this column creation 0511 Layout.minimumWidth: parent.width - root.leftPadding - root.rightPadding 0512 0513 visible: children.length > 0 && childrenRect.height > 0 && opacity > 0 0514 opacity: !root.collapsed || showTopContentWhenCollapsed 0515 0516 Behavior on opacity { 0517 // not an animator as is binded 0518 NumberAnimation { 0519 duration: Kirigami.Units.longDuration 0520 easing.type: Easing.InOutQuad 0521 } 0522 } 0523 } 0524 0525 T.StackView { 0526 id: stackView 0527 0528 property KP.ActionsMenu openSubMenu 0529 0530 clip: true 0531 Layout.fillWidth: true 0532 Layout.minimumHeight: currentItem ? currentItem.implicitHeight : 0 0533 Layout.maximumHeight: Layout.minimumHeight 0534 0535 initialItem: menuComponent 0536 0537 // NOTE: it's important those are NumberAnimation and not XAnimators 0538 // as while the animation is running the drawer may close, and 0539 // the animator would stop when not drawing see BUG 381576 0540 popEnter: Transition { 0541 NumberAnimation { property: "x"; from: (stackView.mirrored ? -1 : 1) * -stackView.width; to: 0; duration: Kirigami.Units.veryLongDuration; easing.type: Easing.OutCubic } 0542 } 0543 0544 popExit: Transition { 0545 NumberAnimation { property: "x"; from: 0; to: (stackView.mirrored ? -1 : 1) * stackView.width; duration: Kirigami.Units.veryLongDuration; easing.type: Easing.OutCubic } 0546 } 0547 0548 pushEnter: Transition { 0549 NumberAnimation { property: "x"; from: (stackView.mirrored ? -1 : 1) * stackView.width; to: 0; duration: Kirigami.Units.veryLongDuration; easing.type: Easing.OutCubic } 0550 } 0551 0552 pushExit: Transition { 0553 NumberAnimation { property: "x"; from: 0; to: (stackView.mirrored ? -1 : 1) * -stackView.width; duration: Kirigami.Units.veryLongDuration; easing.type: Easing.OutCubic } 0554 } 0555 0556 replaceEnter: Transition { 0557 NumberAnimation { property: "x"; from: (stackView.mirrored ? -1 : 1) * stackView.width; to: 0; duration: Kirigami.Units.veryLongDuration; easing.type: Easing.OutCubic } 0558 } 0559 0560 replaceExit: Transition { 0561 NumberAnimation { property: "x"; from: 0; to: (stackView.mirrored ? -1 : 1) * -stackView.width; duration: Kirigami.Units.veryLongDuration; easing.type: Easing.OutCubic } 0562 } 0563 } 0564 0565 Item { 0566 Layout.fillWidth: true 0567 Layout.fillHeight: root.actions.length > 0 0568 Layout.minimumHeight: Kirigami.Units.smallSpacing 0569 } 0570 0571 ColumnLayout { 0572 id: mainContent 0573 Layout.alignment: Qt.AlignHCenter 0574 Layout.leftMargin: root.leftPadding 0575 Layout.rightMargin: root.rightPadding 0576 Layout.fillWidth: true 0577 Layout.fillHeight: true 0578 // NOTE: why this? just Layout.fillWidth: true doesn't seem sufficient 0579 // as items are added only after this column creation 0580 Layout.minimumWidth: parent.width - root.leftPadding - root.rightPadding 0581 visible: children.length > 0 && (opacity > 0 || mainContentAnimator.running) 0582 opacity: !root.collapsed || showContentWhenCollapsed 0583 Behavior on opacity { 0584 OpacityAnimator { 0585 id: mainContentAnimator 0586 duration: Kirigami.Units.longDuration 0587 easing.type: Easing.InOutQuad 0588 } 0589 } 0590 } 0591 0592 Item { 0593 Layout.minimumWidth: Kirigami.Units.smallSpacing 0594 Layout.minimumHeight: root.bottomPadding 0595 } 0596 0597 QQC2.ToolButton { 0598 Layout.fillWidth: true 0599 0600 icon.name: { 0601 if (root.collapsible && root.collapseButtonVisible) { 0602 // Check for edge regardless of RTL/locale/mirrored status, 0603 // because edge can be set externally. 0604 const mirrored = root.edge === Qt.RightEdge; 0605 0606 if (root.collapsed) { 0607 return mirrored ? "sidebar-expand-right" : "sidebar-expand-left"; 0608 } else { 0609 return mirrored ? "sidebar-collapse-right" : "sidebar-collapse-left"; 0610 } 0611 } 0612 return ""; 0613 } 0614 0615 visible: root.collapsible && root.collapseButtonVisible 0616 text: root.collapsed ? "" : qsTr("Close Sidebar") 0617 0618 onClicked: root.collapsed = !root.collapsed 0619 0620 QQC2.ToolTip.visible: root.collapsed && (Kirigami.Settings.tabletMode ? pressed : hovered) 0621 QQC2.ToolTip.text: qsTr("Open Sidebar") 0622 QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay 0623 } 0624 } 0625 } 0626 } 0627 } 0628 }