Warning, /plasma/plasma-desktop/applets/kickoff/package/contents/ui/Footer.qml is written in an unsupported language. File is not indexed.

0001 /*
0002  *    SPDX-FileCopyrightText: 2021 Mikel Johnson <mikel5764@gmail.com>
0003  *    SPDX-FileCopyrightText: 2021 Noah Davis <noahadvs@gmail.com>
0004  *
0005  *    SPDX-License-Identifier: GPL-2.0-or-later
0006  */
0007 
0008 import QtQuick 2.15
0009 import QtQml 2.15
0010 import org.kde.ksvg 1.0 as KSvg
0011 import org.kde.plasma.components 3.0 as PC3
0012 import org.kde.plasma.extras 2.0 as PlasmaExtras
0013 import org.kde.kirigami 2.20 as Kirigami
0014 
0015 PlasmaExtras.PlasmoidHeading {
0016     id: root
0017 
0018     readonly property alias tabBar: tabBar
0019     property real preferredTabBarWidth: 0
0020     readonly property alias leaveButtons: leaveButtons
0021 
0022     contentWidth: tabBar.implicitWidth + root.spacing
0023     contentHeight: leaveButtons.implicitHeight
0024 
0025     // We use an increased vertical padding to improve touch usability
0026     leftPadding: kickoff.backgroundMetrics.leftPadding
0027     rightPadding: kickoff.backgroundMetrics.rightPadding
0028     topPadding: Kirigami.Units.smallSpacing * 2
0029     bottomPadding: Kirigami.Units.smallSpacing * 2
0030 
0031     leftInset: 0
0032     rightInset: 0
0033     topInset: 0
0034     bottomInset: 0
0035 
0036     spacing: kickoff.backgroundMetrics.spacing
0037     position: PC3.ToolBar.Footer
0038 
0039     PC3.TabBar {
0040         id: tabBar
0041         property real tabWidth: Math.max(applicationsTab.implicitWidth, placesTab.implicitWidth)
0042         focus: true
0043         width: root.preferredTabBarWidth > 0 ? root.preferredTabBarWidth : implicitWidth
0044         implicitWidth: contentWidth + leftPadding + rightPadding
0045         implicitHeight: contentHeight + topPadding + bottomPadding
0046 
0047         // This is needed to keep the sparators horizontally aligned
0048         leftPadding: mirrored ? root.spacing : 0
0049         rightPadding: !mirrored ? root.spacing : 0
0050 
0051         anchors {
0052             left: parent.left
0053             top: parent.top
0054             bottom:parent.bottom
0055         }
0056 
0057         position: PC3.TabBar.Footer
0058 
0059         contentItem: ListView {
0060             id: tabBarListView
0061             focus: true
0062             model: tabBar.contentModel
0063             currentIndex: tabBar.currentIndex
0064 
0065             spacing: tabBar.spacing
0066             orientation: ListView.Horizontal
0067             boundsBehavior: Flickable.StopAtBounds
0068             flickableDirection: Flickable.AutoFlickIfNeeded
0069             snapMode: ListView.SnapToItem
0070 
0071             highlightMoveDuration: Kirigami.Units.longDuration
0072             highlightRangeMode: ListView.ApplyRange
0073             preferredHighlightBegin: tabBar.tabWidth
0074             preferredHighlightEnd: width - tabBar.tabWidth
0075             highlight: KSvg.FrameSvgItem {
0076                 anchors.top: tabBarListView.contentItem.top
0077                 anchors.bottom: tabBarListView.contentItem.bottom
0078                 anchors.topMargin: -root.topPadding
0079                 anchors.bottomMargin: -root.bottomPadding
0080                 imagePath: "widgets/tabbar"
0081                 prefix: tabBar.position === PC3.TabBar.Header ? "north-active-tab" : "south-active-tab"
0082             }
0083             keyNavigationEnabled: false
0084         }
0085 
0086         PC3.TabButton {
0087             id: applicationsTab
0088             focus: true
0089             width: tabBar.tabWidth
0090             anchors.top: tabBarListView.contentItem.top
0091             anchors.bottom: tabBarListView.contentItem.bottom
0092             anchors.topMargin: -root.topPadding
0093             anchors.bottomMargin: -root.bottomPadding
0094             icon.width: Kirigami.Units.iconSizes.smallMedium
0095             icon.height: Kirigami.Units.iconSizes.smallMedium
0096             icon.name: "applications-all-symbolic"
0097             text: i18n("Applications")
0098             Keys.onBacktabPressed: event => {
0099                 (kickoff.lastCentralPane || nextItemInFocusChain(false))
0100                     .forceActiveFocus(Qt.BacktabFocusReason)
0101             }
0102         }
0103         PC3.TabButton {
0104             id: placesTab
0105             width: tabBar.tabWidth
0106             anchors.top: tabBarListView.contentItem.top
0107             anchors.bottom: tabBarListView.contentItem.bottom
0108             anchors.topMargin: -root.topPadding
0109             anchors.bottomMargin: -root.bottomPadding
0110             icon.width: Kirigami.Units.iconSizes.smallMedium
0111             icon.height: Kirigami.Units.iconSizes.smallMedium
0112             icon.name: "compass"
0113             text: i18n("Places") //Explore?
0114         }
0115 
0116         Connections {
0117             target: kickoff
0118             function onExpandedChanged() {
0119                 if (kickoff.expanded) {
0120                     tabBar.currentIndex = 0
0121                 }
0122             }
0123         }
0124 
0125         Keys.onPressed: event => {
0126             const Key_Next = Qt.application.layoutDirection === Qt.RightToLeft ? Qt.Key_Left : Qt.Key_Right
0127             const Key_Prev = Qt.application.layoutDirection === Qt.RightToLeft ? Qt.Key_Right : Qt.Key_Left
0128             if (event.key === Key_Next) {
0129                 if (currentIndex === count - 1) {
0130                     leaveButtons.nextItemInFocusChain().forceActiveFocus(Qt.TabFocusReason)
0131                 } else {
0132                     incrementCurrentIndex()
0133                     currentItem.forceActiveFocus(Qt.TabFocusReason)
0134                 }
0135                 event.accepted = true
0136             } else if (event.key === Key_Prev && currentIndex > 0) {
0137                 decrementCurrentIndex()
0138                 currentItem.forceActiveFocus(Qt.BacktabFocusReason)
0139                 event.accepted = true
0140             }
0141         }
0142         Keys.onUpPressed: event => {
0143             kickoff.firstCentralPane.forceActiveFocus(Qt.BacktabFocusReason);
0144         }
0145     }
0146 
0147     LeaveButtons {
0148         id: leaveButtons
0149         anchors {
0150             right: parent.right
0151             top: parent.top
0152             bottom: parent.bottom
0153             leftMargin: root.spacing
0154         }
0155         shouldCollapseButtons: root.contentWidth + root.spacing + buttonImplicitWidth > root.width
0156         Keys.onUpPressed: event => {
0157             kickoff.lastCentralPane.forceActiveFocus(Qt.BacktabFocusReason);
0158         }
0159     }
0160 
0161     Behavior on height {
0162         enabled: kickoff.expanded
0163         NumberAnimation {
0164             duration: Kirigami.Units.longDuration
0165             easing.type: Easing.InQuad
0166         }
0167     }
0168 
0169     // Using item containing WheelHandler instead of MouseArea because
0170     // MouseArea doesn't keep track to the total amount of rotation.
0171     // Keeping track of the total amount of rotation makes it work
0172     // better for touch pads.
0173     Item {
0174         id: mouseItem
0175         parent: root
0176         anchors.left: parent.left
0177         height: root.height
0178         width: tabBar.width
0179         z: 1 // Has to be above contentItem to receive mouse wheel events
0180         WheelHandler {
0181             id: tabScrollHandler
0182             acceptedDevices: PointerDevice.Mouse | PointerDevice.TouchPad
0183             onWheel: {
0184                 let shouldDec = rotation >= 15
0185                 let shouldInc = rotation <= -15
0186                 let shouldReset = (rotation > 0 && tabBar.currentIndex === 0) || (rotation < 0 && tabBar.currentIndex === tabBar.count - 1)
0187                 if (shouldDec) {
0188                     tabBar.decrementCurrentIndex();
0189                     rotation = 0
0190                 } else if (shouldInc) {
0191                     tabBar.incrementCurrentIndex();
0192                     rotation = 0
0193                 } else if (shouldReset) {
0194                     rotation = 0
0195                 }
0196             }
0197         }
0198     }
0199 
0200     Shortcut {
0201         sequences: ["Ctrl+Tab", "Ctrl+Shift+Tab", StandardKey.NextChild, StandardKey.PreviousChild]
0202         onActivated: {
0203             tabBar.currentIndex = (tabBar.currentIndex === 0) ? 1 : 0;
0204         }
0205     }
0206 }