mirror of
https://invent.kde.org/marcoa/shift-shell.git
synced 2026-06-11 16:57:43 +00:00
Improve touchpad scroll handling for convergence workflows while avoiding gesture conflicts. - make SwipeArea handle angleDelta-based touchpad wheel streams and phase-less sequences safely - wire topbar ActionDrawerOpenSurface to virtual desktop info and horizontal workspace switching logic - add dock pager wheel switching in FavouritesBar for the vertical wheel axis environments deliver - prevent wallpaper/home surface touchpad scroll from opening app drawer in convergence - extend convergence invariant checks for the new gesture paths
179 lines
5.9 KiB
QML
179 lines
5.9 KiB
QML
/*
|
|
* SPDX-FileCopyrightText: 2021-2024 Devin Lin <devin@kde.org>
|
|
*
|
|
* 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();
|
|
}
|
|
}
|
|
}
|
|
}
|