Warning, /plasma/kdeplasma-addons/kwin/windowswitchers/coverswitch/contents/ui/main.qml is written in an unsupported language. File is not indexed.
0001 /* 0002 SPDX-FileCopyrightText: 2021 Ismael Asensio <isma.af@gmail.com> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 import QtQuick 2.15 0008 import QtQuick.Controls 2.15 as QQC2 0009 import Qt5Compat.GraphicalEffects 0010 import QtQuick.Layouts 1.15 0011 import QtQuick.Window 2.15 0012 0013 import org.kde.kirigami 2.20 as Kirigami 0014 import org.kde.ksvg 1.0 as KSvg 0015 import org.kde.plasma.components 3.0 as PC3 0016 0017 import org.kde.kwin 3.0 as KWin 0018 import org.kde.kwin.private.effects 1.0 0019 0020 0021 KWin.TabBoxSwitcher { 0022 id: tabBox 0023 currentIndex: thumbnailView ? thumbnailView.currentIndex : -1 0024 0025 // TODO: Make it user configurable ? 0026 property bool enableBlur: true 0027 0028 Window { 0029 id: window 0030 0031 x: tabBox.screenGeometry.x 0032 y: tabBox.screenGeometry.y 0033 width: tabBox.screenGeometry.width 0034 height: tabBox.screenGeometry.height 0035 flags: Qt.BypassWindowManagerHint | Qt.FramelessWindowHint 0036 visibility: Window.FullScreen 0037 // Workaround QTBUG-35244. Do not directly assign here to avoid warning 0038 visible: true 0039 0040 color: "transparent" 0041 0042 KWin.DesktopBackground { 0043 activity: KWin.Workspace.currentActivity 0044 desktop: KWin.Workspace.currentVirtualDesktop 0045 outputName: window.screen.name 0046 0047 layer.enabled: true 0048 layer.effect: FastBlur { 0049 radius: enableBlur ? 64 : 0 0050 } 0051 } 0052 0053 Rectangle { 0054 anchors { 0055 top: enableBlur ? parent.top : infoBar.top 0056 topMargin: enableBlur ? 0 : -infoBar.anchors.bottomMargin 0057 left: parent.left 0058 right: parent.right 0059 bottom: parent.bottom 0060 } 0061 color: Kirigami.Theme.backgroundColor 0062 opacity: enableBlur ? 0.5 : 0.75 0063 } 0064 0065 PathView { 0066 id: thumbnailView 0067 0068 readonly property int visibleCount: Math.min(count, pathItemCount) 0069 readonly property real boxScaleFactor: 0.5 0070 readonly property int boxWidth: tabBox.screenGeometry.width * boxScaleFactor 0071 readonly property int boxHeight: tabBox.screenGeometry.height * boxScaleFactor 0072 0073 focus: true 0074 0075 anchors.fill: parent 0076 0077 preferredHighlightBegin: 0.49 0078 preferredHighlightEnd: preferredHighlightBegin 0079 highlightRangeMode: PathView.StrictlyEnforceRange 0080 0081 // This property sets the animation duration between the current position to the next one, 0082 // without taking into account how much distance the thumbnails travel in that time. 0083 // To compensate the speed, we slowly reduce the duration with the number of thumbnails, 0084 // starting from `veryLongDuration` when there are 2 of them 0085 highlightMoveDuration: Kirigami.Units.veryLongDuration * (2 / Math.sqrt(visibleCount + 1)) 0086 0087 pathItemCount: 13 0088 0089 path: Path { 0090 // Left stack 0091 startX: thumbnailView.width * 0.1; startY: thumbnailView.height * 0.5 0092 PathAttribute { name: "progress"; value: 0 } 0093 PathAttribute { name: "scale"; value: 0.7 } 0094 PathAttribute { name: "rotation"; value: 70 } 0095 PathPercent { value: 0 } 0096 0097 PathLine { x: thumbnailView.width * 0.25 ; y: thumbnailView.height * 0.5 } 0098 PathAttribute { name: "progress"; value: 0.8 } 0099 PathAttribute { name: "scale"; value: 0.7 } 0100 PathAttribute { name: "rotation"; value: 70 } 0101 PathPercent { value: 0.4 } 0102 0103 // Center Item 0104 PathQuad { 0105 x: thumbnailView.width * 0.5 ; y: thumbnailView.height * 0.6 0106 controlX: thumbnailView.width * 0.45; controlY: thumbnailView.height * 0.55 0107 } 0108 PathAttribute { name: "progress"; value: 1 } 0109 PathAttribute { name: "scale"; value: 1 } 0110 PathAttribute { name: "rotation"; value: 0 } 0111 PathPercent { value: 0.49 } // A bit less than 50% so items preferrably stack on the right side 0112 0113 // Right stack 0114 PathQuad { 0115 x: thumbnailView.width * 0.75 ; y: thumbnailView.height * 0.5 0116 controlX: thumbnailView.width * 0.55; controlY: thumbnailView.height * 0.55 0117 } 0118 PathAttribute { name: "progress"; value: 0.8 } 0119 PathAttribute { name: "scale"; value: 0.7 } 0120 PathAttribute { name: "rotation"; value: -70 } 0121 PathPercent { value: 0.6 } 0122 0123 PathLine { x: thumbnailView.width * 0.9 ; y: thumbnailView.height * 0.5 } 0124 PathAttribute { name: "progress"; value: 0 } 0125 PathAttribute { name: "scale"; value: 0.7 } 0126 PathAttribute { name: "rotation"; value: -70 } 0127 PathPercent { value: 1 } 0128 } 0129 0130 model: tabBox.model 0131 0132 delegate: Item { 0133 id: delegateItem 0134 0135 readonly property string caption: model.caption 0136 readonly property var icon: model.icon 0137 0138 readonly property real scaleFactor: { 0139 if (thumbnail.implicitWidth < thumbnailView.boxWidth && thumbnail.implicitHeight < thumbnailView.boxHeight) { 0140 // Do not scale up thumbnails smaller than the box frame 0141 return 1; 0142 } else if (thumbnail.ratio > thumbnailView.boxWidth / thumbnailView.boxHeight) { 0143 // Thumbnail is wider than the box 0144 return thumbnailView.boxWidth / thumbnail.implicitWidth; 0145 } else { 0146 // Thumbnail is taller than the box 0147 return thumbnailView.boxHeight / thumbnail.implicitHeight; 0148 } 0149 } 0150 0151 width: Math.round(thumbnail.implicitWidth * scaleFactor) 0152 height: Math.round(thumbnail.implicitHeight * scaleFactor) 0153 scale: PathView.onPath ? PathView.scale : 0 0154 z: PathView.onPath ? Math.floor(PathView.progress * thumbnailView.visibleCount) : -1 0155 0156 KWin.WindowThumbnail { 0157 id: thumbnail 0158 readonly property double ratio: implicitWidth / implicitHeight 0159 0160 wId: windowId 0161 anchors.fill: parent 0162 } 0163 0164 Kirigami.ShadowedRectangle { 0165 anchors.fill: parent 0166 z: -1 0167 0168 color: "transparent" 0169 shadow.size: Kirigami.Units.gridUnit 0170 shadow.color: "black" 0171 opacity: 0.5 0172 } 0173 0174 transform: Rotation { 0175 origin { x: delegateItem.width/2; y: delegateItem.height/2 } 0176 axis { x: 0; y: 1; z: 0 } 0177 angle: delegateItem.PathView.rotation 0178 } 0179 0180 TapHandler { 0181 grabPermissions: PointerHandler.TakeOverForbidden 0182 gesturePolicy: TapHandler.WithinBounds 0183 onSingleTapped: { 0184 if (index === thumbnailView.currentIndex) { 0185 thumbnailView.model.activate(index); 0186 return; 0187 } 0188 thumbnailView.movementDirection = (delegateItem.PathView.rotation < 0) ? PathView.Positive : PathView.Negative 0189 thumbnailView.currentIndex = index 0190 } 0191 } 0192 } 0193 0194 highlight: KSvg.FrameSvgItem { 0195 id: highlightItem 0196 imagePath: "widgets/viewitem" 0197 prefix: "hover" 0198 0199 readonly property Item target: thumbnailView.currentItem 0200 0201 visible: target !== null 0202 // Make sure the highlight is pixel perfect aligned on both sides even if the target is not 0203 anchors.centerIn: target 0204 anchors.horizontalCenterOffset: target ? Math.round(target.x) - target.x : 0 0205 anchors.verticalCenterOffset: target ? Math.round(target.y) - target.y : 0 0206 width: target ? Math.round(target.width/2 + 3 * Kirigami.Units.smallSpacing) * 2 : 0 0207 height: target ? Math.round(target.height/2 + 3 * Kirigami.Units.smallSpacing) * 2 : 0 0208 scale: target ? target.scale : 1 0209 z: target ? target.z - 0.5 : -0.5 0210 // The transform cannot be directly assigned as the transform origin is different 0211 transform: Rotation { 0212 origin { x: highlightItem.width/2; y: highlightItem.height/2 } 0213 axis { x: 0; y: 1; z: 0 } 0214 angle: target ? target.PathView.rotation : 0 0215 } 0216 } 0217 0218 layer.enabled: true 0219 layer.smooth: true 0220 0221 onMovementStarted: movementDirection = PathView.Shortest 0222 0223 Keys.onUpPressed: decrementCurrentIndex() 0224 Keys.onLeftPressed: decrementCurrentIndex() 0225 Keys.onDownPressed: incrementCurrentIndex() 0226 Keys.onRightPressed: incrementCurrentIndex() 0227 } 0228 0229 RowLayout { 0230 id: infoBar 0231 0232 height: Kirigami.Units.iconSizes.large 0233 spacing: Kirigami.Units.gridUnit 0234 0235 anchors { 0236 horizontalCenter: parent.horizontalCenter 0237 bottom: parent.bottom 0238 margins: Kirigami.Units.gridUnit 0239 } 0240 0241 Kirigami.Icon { 0242 source: thumbnailView.currentItem ? thumbnailView.currentItem.icon : "" 0243 implicitWidth: Kirigami.Units.iconSizes.large 0244 implicitHeight: Kirigami.Units.iconSizes.large 0245 Layout.alignment: Qt.AlignCenter 0246 } 0247 0248 PC3.Label { 0249 font.bold: true 0250 font.pointSize: Math.round(Kirigami.Theme.defaultFont.pointSize * 1.6) 0251 text: thumbnailView.currentItem ? thumbnailView.currentItem.caption : "" 0252 textFormat: Text.PlainText 0253 maximumLineCount: 1 0254 elide: Text.ElideMiddle 0255 Layout.maximumWidth: tabBox.screenGeometry.width * 0.8 0256 Layout.alignment: Qt.AlignCenter 0257 } 0258 } 0259 } 0260 0261 onCurrentIndexChanged: { 0262 if (currentIndex === thumbnailView.currentIndex) { 0263 return 0264 } 0265 0266 // WindowSwitcher always changes currentIndex in increments of 1. 0267 // Detect the change direction and set the PathView movement accordingly, so fast changes 0268 // in the same direction don't result into a combination of forward and backward movements. 0269 if (thumbnailView.count === 2 || (currentIndex === 0 && thumbnailView.currentIndex === thumbnailView.count - 1)) { 0270 thumbnailView.movementDirection = PathView.Positive 0271 } else if (currentIndex === thumbnailView.count - 1 && thumbnailView.currentIndex === 0) { 0272 thumbnailView.movementDirection = PathView.Negative 0273 } else { 0274 thumbnailView.movementDirection = (currentIndex > thumbnailView.currentIndex) ? PathView.Positive : PathView.Negative 0275 } 0276 0277 thumbnailView.currentIndex = tabBox.currentIndex 0278 } 0279 0280 onVisibleChanged: { 0281 // Reset the PathView index when hiding to avoid unwanted animations on relaunch 0282 if (!visible) { 0283 thumbnailView.currentIndex = 0; 0284 } 0285 window.visible = visible; 0286 } 0287 }