Warning, /plasma/kdeplasma-addons/kwin/windowswitchers/flipswitch/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 // Make thumbnails slightly smaller the more there are, so it doesn't feel too crowded 0070 // The sizeFactor curve parameters have been calculated experimentally 0071 readonly property real boxScaleFactor: 0.35 + (0.5 / (visibleCount + 1)) 0072 readonly property int boxWidth: tabBox.screenGeometry.width * boxScaleFactor 0073 readonly property int boxHeight: tabBox.screenGeometry.height * boxScaleFactor 0074 0075 focus: true 0076 0077 anchors.fill: parent 0078 0079 preferredHighlightBegin: 1/(visibleCount + 1) 0080 preferredHighlightEnd: preferredHighlightBegin 0081 highlightRangeMode: PathView.StrictlyEnforceRange 0082 0083 // This property sets the animation duration between the current position to the next one, 0084 // without taking into account how much distance the thumbnails travel in that time. 0085 // To compensate the speed, we slowly reduce the duration with the number of thumbnails, 0086 // starting from `veryLongDuration` when there are 2 of them 0087 highlightMoveDuration: Kirigami.Units.veryLongDuration * (2 / Math.sqrt(visibleCount + 1)) 0088 0089 pathItemCount: 12 0090 0091 path: Path { 0092 // Nearest point of the path 0093 startX: Math.round(thumbnailView.width * 0.75) 0094 startY: Math.round(thumbnailView.height * 0.80) 0095 PathAttribute { name: "progress"; value: 1 } 0096 PathAttribute { name: "scale"; value: 1 } 0097 0098 // Back point of the path on top-left corner 0099 PathLine { 0100 x: Math.round(thumbnailView.width * 0.25) 0101 y: Math.round(thumbnailView.height * 0.20) 0102 } 0103 PathAttribute { name: "progress"; value: 0 } 0104 PathAttribute { name: "scale"; value: 0.6 } 0105 } 0106 0107 model: tabBox.model 0108 0109 delegate: Item { 0110 readonly property string caption: model.caption 0111 readonly property var icon: model.icon 0112 0113 readonly property real scaleFactor: { 0114 if (thumbnail.implicitWidth < thumbnailView.boxWidth && thumbnail.implicitHeight < thumbnailView.boxHeight) { 0115 // Do not scale up thumbnails smaller than the box frame 0116 return 1; 0117 } else if (thumbnail.ratio > thumbnailView.boxWidth / thumbnailView.boxHeight) { 0118 // Thumbnail is wider than the box 0119 return thumbnailView.boxWidth / thumbnail.implicitWidth; 0120 } else { 0121 // Thumbnail is taller than the box 0122 return thumbnailView.boxHeight / thumbnail.implicitHeight; 0123 } 0124 } 0125 0126 width: Math.round(thumbnail.implicitWidth * scaleFactor) 0127 height: Math.round(thumbnail.implicitHeight * scaleFactor) 0128 scale: PathView.onPath ? PathView.scale : 0 0129 z: PathView.onPath ? Math.floor(PathView.progress * thumbnailView.visibleCount) : -1 0130 0131 // Reduce opacity on the end so items dissapear more naturally 0132 opacity: Math.min(1, (1 - PathView.progress) / thumbnailView.preferredHighlightBegin); 0133 0134 KWin.WindowThumbnail { 0135 id: thumbnail 0136 readonly property double ratio: implicitWidth / implicitHeight 0137 0138 wId: windowId 0139 anchors.fill: parent 0140 } 0141 0142 Kirigami.ShadowedRectangle { 0143 anchors.fill: parent 0144 z: -1 0145 0146 color: "transparent" 0147 shadow.size: Kirigami.Units.gridUnit 0148 shadow.color: "black" 0149 opacity: 0.5 0150 shadow.yOffset: 1 0151 } 0152 0153 TapHandler { 0154 grabPermissions: PointerHandler.TakeOverForbidden 0155 gesturePolicy: TapHandler.WithinBounds 0156 onSingleTapped: { 0157 if (index === thumbnailView.currentIndex) { 0158 thumbnailView.model.activate(index); 0159 return; 0160 } 0161 thumbnailView.movementDirection = PathView.Positive 0162 thumbnailView.currentIndex = index 0163 } 0164 } 0165 } 0166 0167 transform: Rotation { 0168 origin { x: thumbnailView.width/2; y: thumbnailView.height/2 } 0169 axis { x: 0; y: 1; z: -0.15 } 0170 angle: 10 0171 } 0172 0173 highlight: KSvg.FrameSvgItem { 0174 imagePath: "widgets/viewitem" 0175 prefix: "hover" 0176 0177 readonly property Item target: thumbnailView.currentItem 0178 0179 visible: target !== null 0180 anchors.centerIn: target 0181 width: target ? target.width + 6 * Kirigami.Units.smallSpacing : 0 0182 height: target ? target.height + 6 * Kirigami.Units.smallSpacing : 0 0183 scale: target ? target.scale : 1 0184 z: target ? target.z - 0.5 : -0.5 0185 } 0186 0187 layer.enabled: true 0188 layer.smooth: true 0189 0190 onMovementStarted: movementDirection = PathView.Shortest 0191 0192 Keys.onUpPressed: decrementCurrentIndex() 0193 Keys.onLeftPressed: decrementCurrentIndex() 0194 Keys.onDownPressed: incrementCurrentIndex() 0195 Keys.onRightPressed: incrementCurrentIndex() 0196 } 0197 0198 RowLayout { 0199 id: infoBar 0200 0201 height: Kirigami.Units.iconSizes.large 0202 spacing: Kirigami.Units.gridUnit 0203 0204 anchors { 0205 horizontalCenter: parent.horizontalCenter 0206 bottom: parent.bottom 0207 margins: Kirigami.Units.gridUnit 0208 } 0209 0210 Kirigami.Icon { 0211 source: thumbnailView.currentItem ? thumbnailView.currentItem.icon : "" 0212 implicitWidth: Kirigami.Units.iconSizes.large 0213 implicitHeight: Kirigami.Units.iconSizes.large 0214 Layout.alignment: Qt.AlignCenter 0215 } 0216 0217 PC3.Label { 0218 font.bold: true 0219 font.pointSize: Math.round(Kirigami.Theme.defaultFont.pointSize * 1.6) 0220 text: thumbnailView.currentItem ? thumbnailView.currentItem.caption : "" 0221 textFormat: Text.PlainText 0222 maximumLineCount: 1 0223 elide: Text.ElideMiddle 0224 Layout.maximumWidth: tabBox.screenGeometry.width * 0.8 0225 Layout.alignment: Qt.AlignCenter 0226 } 0227 } 0228 } 0229 0230 onCurrentIndexChanged: { 0231 if (currentIndex === thumbnailView.currentIndex) { 0232 return 0233 } 0234 0235 // WindowSwitcher always changes currentIndex in increments of 1. 0236 // Detect the change direction and set the PathView movement accordingly, so fast changes 0237 // in the same direction don't result into a combination of forward and backward movements. 0238 if (thumbnailView.count === 2 || (currentIndex === 0 && thumbnailView.currentIndex === thumbnailView.count - 1)) { 0239 thumbnailView.movementDirection = PathView.Positive 0240 } else if (currentIndex === thumbnailView.count - 1 && thumbnailView.currentIndex === 0) { 0241 thumbnailView.movementDirection = PathView.Negative 0242 } else { 0243 thumbnailView.movementDirection = (currentIndex > thumbnailView.currentIndex) ? PathView.Positive : PathView.Negative 0244 } 0245 0246 thumbnailView.currentIndex = tabBox.currentIndex 0247 } 0248 0249 onVisibleChanged: { 0250 // Reset the PathView index when hiding to avoid unwanted animations on relaunch 0251 if (!visible) { 0252 thumbnailView.currentIndex = 0; 0253 } 0254 window.visible = visible; 0255 } 0256 }