/* * SPDX-FileCopyrightText: 2021-2024 Devin Lin * * SPDX-License-Identifier: LGPL-2.0-or-later */ import QtQuick 2.15 import org.kde.plasma.private.mobileshell.shellsettingsplugin as ShellSettings import org.kde.plasma.private.mobileshell as MobileShell /** * Component that triggers the opening and closing of an ActionDrawer when dragged on with touch or mouse. */ MobileShell.SwipeArea { id: root mode: MobileShell.SwipeArea.VerticalOnly required property ActionDrawer actionDrawer property var virtualDesktopInfo: null readonly property real touchpadDirectionLockThreshold: 12 readonly property real touchpadWorkspaceSwitchThreshold: 80 readonly property real touchpadAxisDominance: 1.25 property point touchpadStartPoint: Qt.point(0, 0) property string touchpadGestureMode: "" property bool touchpadWorkspaceSwitched: false function startSwipe() { if (actionDrawer.intendedToBeVisible) { // ensure the action drawer state is consistent actionDrawer.closeImmediately(); } actionDrawer.cancelAnimations(); actionDrawer.dragging = true; actionDrawer.opened = false; // must be after properties other are set, we cannot have actionDrawer.updateState() be called actionDrawer.offset = 0; actionDrawer.oldOffset = 0; actionDrawer.intendedToBeVisible = true; } function startSwipeWithPoint(point) { if (ShellSettings.Settings.convergenceModeEnabled) { actionDrawer.openToPinnedMode = false; } else if (point.x < root.width / 2) { actionDrawer.openToPinnedMode = ShellSettings.Settings.actionDrawerTopLeftMode == ShellSettings.Settings.Pinned; } else { actionDrawer.openToPinnedMode = ShellSettings.Settings.actionDrawerTopRightMode == ShellSettings.Settings.Pinned; } startSwipe(); } function endSwipe() { actionDrawer.dragging = false; actionDrawer.updateState(); } function updateOffset(offsetY) { actionDrawer.offset += offsetY; } function workspaceScrollAvailable() { return ShellSettings.Settings.convergenceModeEnabled && virtualDesktopInfo !== null && virtualDesktopInfo.numberOfDesktops > 1; } function desktopIndexForId(desktopId) { if (virtualDesktopInfo === null || !virtualDesktopInfo.desktopIds) { return -1; } for (let i = 0; i < virtualDesktopInfo.desktopIds.length; ++i) { if (String(virtualDesktopInfo.desktopIds[i]) === String(desktopId)) { return i; } } return -1; } function activateAdjacentWorkspace(direction) { if (!workspaceScrollAvailable()) { return; } const currentIndex = desktopIndexForId(virtualDesktopInfo.currentDesktop); if (currentIndex < 0) { return; } const targetIndex = Math.max(0, Math.min(virtualDesktopInfo.desktopIds.length - 1, currentIndex + direction)); if (targetIndex !== currentIndex) { virtualDesktopInfo.requestActivate(virtualDesktopInfo.desktopIds[targetIndex]); } } function startTouchpadScroll(point) { touchpadStartPoint = point; touchpadGestureMode = ""; touchpadWorkspaceSwitched = false; if (!ShellSettings.Settings.convergenceModeEnabled) { touchpadGestureMode = "drawer"; startSwipeWithPoint(point); } } function moveTouchpadScroll(totalDeltaX, totalDeltaY, deltaX, deltaY) { if (touchpadGestureMode === "") { const absX = Math.abs(totalDeltaX); const absY = Math.abs(totalDeltaY); if (absY >= touchpadDirectionLockThreshold && absY > absX * touchpadAxisDominance) { touchpadGestureMode = "drawer"; startSwipeWithPoint(touchpadStartPoint); updateOffset(totalDeltaY); return; } else if (workspaceScrollAvailable() && absX >= touchpadDirectionLockThreshold && absX > absY * touchpadAxisDominance) { touchpadGestureMode = "workspace"; } else { return; } } if (touchpadGestureMode === "drawer") { updateOffset(deltaY); return; } if (!touchpadWorkspaceSwitched && Math.abs(totalDeltaX) >= touchpadWorkspaceSwitchThreshold) { touchpadWorkspaceSwitched = true; activateAdjacentWorkspace(totalDeltaX < 0 ? 1 : -1); } } function endTouchpadScroll() { if (touchpadGestureMode === "drawer") { endSwipe(); } touchpadGestureMode = ""; touchpadWorkspaceSwitched = false; } anchors.fill: parent MouseArea { anchors.fill: parent acceptedButtons: Qt.NoButton hoverEnabled: true scrollGestureEnabled: false cursorShape: ShellSettings.Settings.convergenceModeEnabled ? Qt.PointingHandCursor : Qt.ArrowCursor } onSwipeStarted: (point) => startSwipeWithPoint(point) onSwipeEnded: endSwipe() onSwipeMove: (totalDeltaX, totalDeltaY, deltaX, deltaY) => updateOffset(deltaY); onTouchpadScrollStarted: (point) => startTouchpadScroll(point) onTouchpadScrollEnded: endTouchpadScroll() onTouchpadScrollMove: (totalDeltaX, totalDeltaY, deltaX, deltaY) => moveTouchpadScroll(totalDeltaX, totalDeltaY, deltaX, deltaY); // In convergence mode, allow click to toggle the action drawer (mouse-friendly) onClicked: { if (ShellSettings.Settings.convergenceModeEnabled) { if (actionDrawer.intendedToBeVisible) { actionDrawer.close(); } else { actionDrawer.openToPinnedMode = false; actionDrawer.intendedToBeVisible = true; actionDrawer.open(); } } } }