From d8f7bac960e07504153c5d6123e4a50b4802343e Mon Sep 17 00:00:00 2001 From: 2 * r + 2 * t <61896496+soramanew@users.noreply.github.com> Date: Sat, 16 Aug 2025 00:10:48 +1000 Subject: bar/workspaces: refactor --- README.md | 5 +- config/BarConfig.qml | 5 +- modules/bar/Bar.qml | 1 - modules/bar/BarWrapper.qml | 1 - .../bar/components/workspaces/ActiveIndicator.qml | 43 ++++++------- modules/bar/components/workspaces/OccupiedBg.qml | 23 ++++--- modules/bar/components/workspaces/Workspace.qml | 41 ++++++------ modules/bar/components/workspaces/Workspaces.qml | 73 +++++++++------------- utils/Icons.qml | 15 +++++ 9 files changed, 97 insertions(+), 110 deletions(-) diff --git a/README.md b/README.md index ab3f306..816a627 100644 --- a/README.md +++ b/README.md @@ -254,13 +254,12 @@ All configuration options are in `~/.config/caelestia/shell.json`. }, "workspaces": { "activeIndicator": true, - "activeLabel": "󰮯 ", + "activeLabel": "󰮯", "activeTrail": false, "label": " ", "occupiedBg": false, - "occupiedLabel": "󰮯 ", + "occupiedLabel": "󰮯", "perMonitorWorkspaces": true, - "rounded": true, "showWindows": true, "shown": 5 } diff --git a/config/BarConfig.qml b/config/BarConfig.qml index bbe061b..4aaff8c 100644 --- a/config/BarConfig.qml +++ b/config/BarConfig.qml @@ -50,15 +50,14 @@ JsonObject { component Workspaces: JsonObject { property int shown: 5 - property bool rounded: true property bool activeIndicator: true property bool occupiedBg: false property bool showWindows: true property bool activeTrail: false property bool perMonitorWorkspaces: true property string label: " " - property string occupiedLabel: "󰮯 " - property string activeLabel: "󰮯 " + property string occupiedLabel: "󰮯" + property string activeLabel: "󰮯" } component Tray: JsonObject { diff --git a/modules/bar/Bar.qml b/modules/bar/Bar.qml index ec2cae9..58a30d1 100644 --- a/modules/bar/Bar.qml +++ b/modules/bar/Bar.qml @@ -177,6 +177,5 @@ ColumnLayout { visible: enabled active: enabled - asynchronous: true } } diff --git a/modules/bar/BarWrapper.qml b/modules/bar/BarWrapper.qml index 83ff1c3..c4ba52c 100644 --- a/modules/bar/BarWrapper.qml +++ b/modules/bar/BarWrapper.qml @@ -73,7 +73,6 @@ Item { anchors.right: parent.right active: root.shouldBeVisible || root.visible - asynchronous: true sourceComponent: Bar { width: root.contentWidth diff --git a/modules/bar/components/workspaces/ActiveIndicator.qml b/modules/bar/components/workspaces/ActiveIndicator.qml index 3167d6e..99d6275 100644 --- a/modules/bar/components/workspaces/ActiveIndicator.qml +++ b/modules/bar/components/workspaces/ActiveIndicator.qml @@ -8,45 +8,38 @@ StyledRect { id: root required property int activeWsId - required property list workspaces + required property Repeater workspaces required property Item mask - required property real maskWidth - required property real maskHeight - required property int groupOffset - - readonly property int currentWsIdx: activeWsId - 1 - groupOffset - property real leading: getWsY(currentWsIdx) - property real trailing: getWsY(currentWsIdx) - property real currentSize: workspaces[currentWsIdx]?.size ?? 0 + + readonly property int currentWsIdx: (activeWsId - 1) % Config.bar.workspaces.shown + + property real leading: workspaces.itemAt(currentWsIdx)?.y ?? 0 + property real trailing: workspaces.itemAt(currentWsIdx)?.y ?? 0 + property real currentSize: workspaces.itemAt(currentWsIdx)?.size ?? 0 property real offset: Math.min(leading, trailing) property real size: { const s = Math.abs(leading - trailing) + currentSize; - if (Config.bar.workspaces.activeTrail && lastWs > currentWsIdx) - return Math.min(getWsY(lastWs) + (workspaces[lastWs]?.size ?? 0) - offset, s); + if (Config.bar.workspaces.activeTrail && lastWs > currentWsIdx) { + const ws = workspaces.itemAt(lastWs); + // console.log(ws, lastWs); + return ws ? Math.min(ws.y + ws.size - offset, s) : 0; + } return s; } property int cWs property int lastWs - function getWsY(idx: int): real { - let y = 0; - for (let i = 0; i < idx; i++) - y += workspaces[i]?.size ?? 0; - return y; - } - onCurrentWsIdxChanged: { lastWs = cWs; cWs = currentWsIdx; } clip: true - x: 1 - y: offset + 1 - implicitWidth: Config.bar.sizes.innerHeight - 2 - implicitHeight: size - 2 - radius: Config.bar.workspaces.rounded ? Appearance.rounding.full : 0 + y: offset + mask.y + implicitWidth: Config.bar.sizes.innerWidth - Appearance.padding.small * 2 + implicitHeight: size + radius: Appearance.rounding.full color: Colours.palette.m3primary Colouriser { @@ -56,8 +49,8 @@ StyledRect { x: 0 y: -parent.offset - implicitWidth: root.maskWidth - implicitHeight: root.maskHeight + implicitWidth: root.mask.implicitWidth + implicitHeight: root.mask.implicitHeight anchors.horizontalCenter: parent.horizontalCenter } diff --git a/modules/bar/components/workspaces/OccupiedBg.qml b/modules/bar/components/workspaces/OccupiedBg.qml index bfdbbbd..37fe4c1 100644 --- a/modules/bar/components/workspaces/OccupiedBg.qml +++ b/modules/bar/components/workspaces/OccupiedBg.qml @@ -9,7 +9,7 @@ import QtQuick Item { id: root - required property list workspaces + required property Repeater workspaces required property var occupied required property int groupOffset @@ -48,18 +48,17 @@ Item { required property var modelData - readonly property Workspace start: root.workspaces[modelData.start - 1 - root.groupOffset] ?? null - readonly property Workspace end: root.workspaces[modelData.end - 1 - root.groupOffset] ?? null + readonly property Workspace start: root.workspaces.itemAt((modelData.start - 1) % Config.bar.workspaces.shown) ?? null + readonly property Workspace end: root.workspaces.itemAt((modelData.end - 1) % Config.bar.workspaces.shown) ?? null - color: Colours.tPalette.m3surfaceContainerHigh - radius: Config.bar.workspaces.rounded ? Appearance.rounding.full : 0 + anchors.horizontalCenter: root.horizontalCenter - x: start?.x ?? 0 - y: start?.y ?? 0 - implicitWidth: Config.bar.sizes.innerHeight - implicitHeight: end?.y + end?.height - start?.y + y: (start?.y ?? 0) - 1 + implicitWidth: Config.bar.sizes.innerWidth - Appearance.padding.small * 2 + 2 + implicitHeight: start && end ? end.y + end.size - start.y + 2 : 0 - anchors.horizontalCenter: parent.horizontalCenter + color: Colours.layer(Colours.palette.m3surfaceContainerHigh, 2) + radius: Appearance.rounding.full scale: 0 Component.onCompleted: scale = 1 @@ -70,11 +69,11 @@ Item { } } - Behavior on x { + Behavior on y { Anim {} } - Behavior on y { + Behavior on implicitHeight { Anim {} } } diff --git a/modules/bar/components/workspaces/Workspace.qml b/modules/bar/components/workspaces/Workspace.qml index acfb216..6bd230b 100644 --- a/modules/bar/components/workspaces/Workspace.qml +++ b/modules/bar/components/workspaces/Workspace.qml @@ -6,7 +6,7 @@ import Quickshell import QtQuick import QtQuick.Layouts -Item { +ColumnLayout { id: root required property int index @@ -16,41 +16,44 @@ Item { readonly property bool isWorkspace: true // Flag for finding workspace children // Unanimated prop for others to use as reference - readonly property real size: childrenRect.height + (hasWindows ? Appearance.padding.smaller : 0) + readonly property int size: implicitHeight + (hasWindows ? Appearance.padding.small : 0) readonly property int ws: groupOffset + index + 1 readonly property bool isOccupied: occupied[ws] ?? false readonly property bool hasWindows: isOccupied && Config.bar.workspaces.showWindows - Layout.preferredWidth: childrenRect.width + Layout.alignment: Qt.AlignHCenter Layout.preferredHeight: size + spacing: 0 + StyledText { id: indicator - readonly property string label: Config.bar.workspaces.label || root.ws - readonly property string occupiedLabel: Config.bar.workspaces.occupiedLabel || label - readonly property string activeLabel: Config.bar.workspaces.activeLabel || (root.isOccupied ? occupiedLabel : label) + Layout.alignment: Qt.AlignHCenter | Qt.AlignTop + Layout.preferredHeight: Config.bar.sizes.innerWidth - Appearance.padding.small * 2 animate: true - text: root.activeWsId === root.ws ? activeLabel : root.isOccupied ? occupiedLabel : label + text: { + const label = Config.bar.workspaces.label || root.ws; + const occupiedLabel = Config.bar.workspaces.occupiedLabel || label; + const activeLabel = Config.bar.workspaces.activeLabel || (root.isOccupied ? occupiedLabel : label); + return root.activeWsId === root.ws ? activeLabel : root.isOccupied ? occupiedLabel : label; + } color: Config.bar.workspaces.occupiedBg || root.isOccupied || root.activeWsId === root.ws ? Colours.palette.m3onSurface : Colours.layer(Colours.palette.m3outlineVariant, 2) - horizontalAlignment: StyledText.AlignHCenter - verticalAlignment: StyledText.AlignVCenter - - width: Config.bar.sizes.innerHeight - height: Config.bar.sizes.innerHeight + verticalAlignment: Qt.AlignVCenter } Loader { id: windows - active: Config.bar.workspaces.showWindows - asynchronous: true + Layout.alignment: Qt.AlignHCenter + Layout.fillHeight: true + Layout.topMargin: -Config.bar.sizes.innerWidth / 10 - anchors.horizontalCenter: indicator.horizontalCenter - anchors.top: indicator.bottom - anchors.topMargin: -Config.bar.sizes.innerHeight / 10 + visible: active + active: root.hasWindows + asynchronous: true sourceComponent: Column { spacing: 0 @@ -91,10 +94,6 @@ Item { } } - Behavior on Layout.preferredWidth { - Anim {} - } - Behavior on Layout.preferredHeight { Anim {} } diff --git a/modules/bar/components/workspaces/Workspaces.qml b/modules/bar/components/workspaces/Workspaces.qml index 68e9ac1..1acc111 100644 --- a/modules/bar/components/workspaces/Workspaces.qml +++ b/modules/bar/components/workspaces/Workspaces.qml @@ -13,76 +13,61 @@ StyledRect { required property ShellScreen screen readonly property int activeWsId: Config.bar.workspaces.perMonitorWorkspaces ? (Hyprland.monitorFor(screen).activeWorkspace?.id ?? 1) : Hyprland.activeWsId - readonly property list workspaces: layout.children.filter(c => c.isWorkspace).sort((w1, w2) => w1.ws - w2.ws) + readonly property var occupied: Hyprland.workspaces.values.reduce((acc, curr) => { acc[curr.id] = curr.lastIpcObject.windows > 0; return acc; }, {}) readonly property int groupOffset: Math.floor((activeWsId - 1) / Config.bar.workspaces.shown) * Config.bar.workspaces.shown - implicitWidth: layout.implicitWidth + Appearance.padding.small * 2 implicitHeight: layout.implicitHeight + Appearance.padding.small * 2 + implicitWidth: Config.bar.sizes.innerWidth + color: Colours.tPalette.m3surfaceContainer radius: Appearance.rounding.full - Item { - id: inner + Loader { + active: Config.bar.workspaces.occupiedBg + asynchronous: true anchors.fill: parent anchors.margins: Appearance.padding.small - ColumnLayout { - id: layout - - spacing: 0 - - Repeater { - model: Config.bar.workspaces.shown - - Workspace { - activeWsId: root.activeWsId - occupied: root.occupied - groupOffset: root.groupOffset - } - } + sourceComponent: OccupiedBg { + workspaces: workspaces + occupied: root.occupied + groupOffset: root.groupOffset } + } - Loader { - active: Config.bar.workspaces.occupiedBg - asynchronous: true + ColumnLayout { + id: layout - z: -1 - anchors.fill: parent + anchors.centerIn: parent + spacing: Math.floor(Appearance.spacing.small / 2) - sourceComponent: OccupiedBg { - workspaces: root.workspaces - occupied: root.occupied - groupOffset: root.groupOffset - } - } + Repeater { + id: workspaces - Loader { - active: Config.bar.workspaces.activeIndicator - asynchronous: true + model: Config.bar.workspaces.shown - sourceComponent: ActiveIndicator { + Workspace { activeWsId: root.activeWsId - workspaces: root.workspaces - mask: layout - maskWidth: inner.width - maskHeight: inner.height + occupied: root.occupied groupOffset: root.groupOffset } } + } - MouseArea { - anchors.fill: parent + Loader { + anchors.horizontalCenter: parent.horizontalCenter + active: Config.bar.workspaces.activeIndicator + asynchronous: true - onPressed: event => { - const ws = layout.childAt(event.x, event.y).index + root.groupOffset + 1; - if (Hyprland.activeWsId !== ws) - Hyprland.dispatch(`workspace ${ws}`); - } + sourceComponent: ActiveIndicator { + activeWsId: root.activeWsId + workspaces: workspaces + mask: layout } } } diff --git a/utils/Icons.qml b/utils/Icons.qml index 7551eac..3363e55 100644 --- a/utils/Icons.qml +++ b/utils/Icons.qml @@ -183,4 +183,19 @@ Singleton { return "volume_down"; return "volume_mute"; } + + function getSpecialWsIcon(name: string): string { + name = name.toLowerCase().slice("special:".length); + if (name === "special") + return "star"; + if (name === "communication") + return "forum"; + if (name === "music") + return "music_note"; + if (name === "todo") + return "checklist"; + if (name === "sysmon") + return "monitor_heart"; + return name[0].toUpperCase(); + } } -- cgit v1.2.3-freya