diff --git a/quickshell/Modules/DankBar/Widgets/WorkspaceSwitcher.qml b/quickshell/Modules/DankBar/Widgets/WorkspaceSwitcher.qml index 2e2a538a..3721e350 100644 --- a/quickshell/Modules/DankBar/Widgets/WorkspaceSwitcher.qml +++ b/quickshell/Modules/DankBar/Widgets/WorkspaceSwitcher.qml @@ -20,6 +20,46 @@ Item { property var blurBarWindow: null property var hyprlandOverviewLoader: null property var parentScreen: null + + readonly property real _leftMargin: { + if (isVertical) + return 0; + root.x; + if (!root.parent) + return 0; + const gap = root.mapToItem(null, 0, 0).x; + return (gap > 0 && gap < 30) ? gap + 5 : 0; + } + readonly property real _rightMargin: { + if (isVertical) + return 0; + root.x; + root.width; + if (!root.parent || !blurBarWindow) + return 0; + const gap = blurBarWindow.width - root.mapToItem(null, root.width, 0).x; + return (gap > 0 && gap < 30) ? gap + 5 : 0; + } + readonly property real _topMargin: { + if (!isVertical) + return 0; + root.y; + if (!root.parent) + return 0; + const gap = root.mapToItem(null, 0, 0).y; + return (gap > 0 && gap < 30) ? gap + 5 : 0; + } + readonly property real _bottomMargin: { + if (!isVertical) + return 0; + root.y; + root.height; + if (!root.parent || !blurBarWindow) + return 0; + const gap = blurBarWindow.height - root.mapToItem(null, 0, root.height).y; + return (gap > 0 && gap < 30) ? gap + 5 : 0; + } + property int _desktopEntriesUpdateTrigger: 0 readonly property var sortedToplevels: { return CompositorService.filterCurrentWorkspace(CompositorService.sortedToplevels, screenName); @@ -539,6 +579,60 @@ Item { }); } + function switchToWorkspaceByModelData(data) { + if (!data) + return; + + if (root.useExtWorkspace && (data.id || data.name)) { + ExtWorkspaceService.activateWorkspace(data.id || data.name, data.groupID || ""); + return; + } + + switch (CompositorService.compositor) { + case "niri": + if (data.idx !== undefined) + NiriService.switchToWorkspace(data.idx); + break; + case "hyprland": + if (data.id) + Hyprland.dispatch(`workspace ${data.id}`); + break; + case "dwl": + if (data.tag !== undefined) + DwlService.switchToTag(root.screenName, data.tag); + break; + case "sway": + case "scroll": + case "miracle": + if (data.num) + try { + I3.dispatch(`workspace number ${data.num}`); + } catch (_) {} + break; + } + } + + function findClosestWorkspaceIndex(localX, localY) { + if (workspaceRepeater.count === 0) + return -1; + + let closestIdx = -1; + let closestDist = Infinity; + + for (let i = 0; i < workspaceRepeater.count; i++) { + const item = workspaceRepeater.itemAt(i); + if (!item) + continue; + const center = item.mapToItem(root, item.width / 2, item.height / 2); + const dist = isVertical ? Math.abs(localY - center.y) : Math.abs(localX - center.x); + if (dist < closestDist) { + closestDist = dist; + closestIdx = i; + } + } + return closestIdx; + } + function switchWorkspace(direction) { if (useExtWorkspace) { const realWorkspaces = getRealWorkspaces(); @@ -752,8 +846,15 @@ Item { } MouseArea { - anchors.fill: parent - acceptedButtons: Qt.RightButton + id: edgeMouseArea + z: -1 + x: -root._leftMargin + y: -root._topMargin + width: root.width + root._leftMargin + root._rightMargin + height: root.height + root._topMargin + root._bottomMargin + acceptedButtons: Qt.LeftButton | Qt.RightButton + hoverEnabled: true + cursorShape: Qt.PointingHandCursor property real touchpadAccumulator: 0 property real mouseAccumulator: 0 @@ -766,12 +867,20 @@ Item { } onClicked: mouse => { - if (mouse.button === Qt.RightButton) { + const rootPos = edgeMouseArea.mapToItem(root, mouse.x, mouse.y); + switch (mouse.button) { + case Qt.RightButton: if (CompositorService.isNiri) { NiriService.toggleOverview(); } else if (CompositorService.isHyprland && root.hyprlandOverviewLoader?.item) { root.hyprlandOverviewLoader.item.overviewOpen = !root.hyprlandOverviewLoader.item.overviewOpen; } + break; + case Qt.LeftButton: + const idx = root.findClosestWorkspaceIndex(rootPos.x, rootPos.y); + if (idx >= 0) + root.switchToWorkspaceByModelData(root.workspaceList[idx]); + break; } } diff --git a/quickshell/Modules/Settings/WidgetsTabSection.qml b/quickshell/Modules/Settings/WidgetsTabSection.qml index 2023ae9e..599c1f1a 100644 --- a/quickshell/Modules/Settings/WidgetsTabSection.qml +++ b/quickshell/Modules/Settings/WidgetsTabSection.qml @@ -1,6 +1,5 @@ import QtQuick import QtQuick.Controls -import QtQuick.Layouts import qs.Common import qs.Widgets import qs.Services @@ -52,15 +51,14 @@ Column { height: implicitHeight spacing: Theme.spacingM - RowLayout { - width: parent.width + Row { spacing: Theme.spacingM DankIcon { name: root.titleIcon size: Theme.iconSize color: Theme.primary - Layout.alignment: Qt.AlignVCenter + anchors.verticalCenter: parent.verticalCenter } StyledText { @@ -68,7 +66,7 @@ Column { font.pixelSize: Theme.fontSizeLarge font.weight: Font.Medium color: Theme.surfaceText - Layout.alignment: Qt.AlignVCenter + anchors.verticalCenter: parent.verticalCenter } } @@ -981,10 +979,26 @@ Column { Repeater { model: [ - { label: I18n.tr("Percentage"), mode: 0, icon: "percent" }, - { label: I18n.tr("Total"), mode: 1, icon: "storage" }, - { label: I18n.tr("Remaining"), mode: 2, icon: "hourglass_empty" }, - { label: I18n.tr("Remaining / Total"), mode: 3, icon: "pie_chart" } + { + label: I18n.tr("Percentage"), + mode: 0, + icon: "percent" + }, + { + label: I18n.tr("Total"), + mode: 1, + icon: "storage" + }, + { + label: I18n.tr("Remaining"), + mode: 2, + icon: "hourglass_empty" + }, + { + label: I18n.tr("Remaining / Total"), + mode: 3, + icon: "pie_chart" + } ] delegate: Rectangle { @@ -1316,20 +1330,7 @@ Column { id: longestControlCenterLabelMetrics font.pixelSize: Theme.fontSizeSmall text: { - const labels = [ - I18n.tr("Network"), - I18n.tr("VPN"), - I18n.tr("Bluetooth"), - I18n.tr("Audio"), - I18n.tr("Volume"), - I18n.tr("Microphone"), - I18n.tr("Microphone Volume"), - I18n.tr("Brightness"), - I18n.tr("Brightness Value"), - I18n.tr("Battery"), - I18n.tr("Printer"), - I18n.tr("Screen Sharing") - ]; + const labels = [I18n.tr("Network"), I18n.tr("VPN"), I18n.tr("Bluetooth"), I18n.tr("Audio"), I18n.tr("Volume"), I18n.tr("Microphone"), I18n.tr("Microphone Volume"), I18n.tr("Brightness"), I18n.tr("Brightness Value"), I18n.tr("Battery"), I18n.tr("Printer"), I18n.tr("Screen Sharing")]; let longest = ""; for (let i = 0; i < labels.length; i++) { if (labels[i].length > longest.length) @@ -1340,6 +1341,7 @@ Column { } Repeater { + id: groupRepeater model: controlCenterContextMenu.controlCenterGroups delegate: Item { @@ -1569,8 +1571,6 @@ Column { } } } - - id: groupRepeater } } }