nosignal-shell/modules/bar/components/workspaces/Workspace.qml
2026-04-11 22:17:24 +10:00

116 lines
3.8 KiB
QML

pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Layouts
import Quickshell
import Caelestia.Config
import qs.components
import qs.services
import qs.utils
ColumnLayout {
id: root
required property int index
required property int activeWsId
required property var occupied
required property int groupOffset
readonly property bool isWorkspace: true // Flag for finding workspace children
// Unanimated prop for others to use as reference
readonly property int size: implicitHeight + (hasWindows ? Tokens.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.alignment: Qt.AlignHCenter
Layout.preferredHeight: size
spacing: 0
StyledText {
id: indicator
Layout.alignment: Qt.AlignHCenter | Qt.AlignTop
Layout.preferredHeight: Tokens.sizes.bar.innerWidth - Tokens.padding.small * 2
animate: true
text: {
const ws = Hypr.workspaces.values.find(w => w.id === root.ws);
const wsName = !ws || ws.name == root.ws ? root.ws : ws.name[0];
let displayName = wsName.toString();
if (Config.bar.workspaces.capitalisation.toLowerCase() === "upper") {
displayName = displayName.toUpperCase();
} else if (Config.bar.workspaces.capitalisation.toLowerCase() === "lower") {
displayName = displayName.toLowerCase();
}
const label = Config.bar.workspaces.label || displayName;
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)
verticalAlignment: Qt.AlignVCenter
}
Loader {
id: windows
asynchronous: true
Layout.alignment: Qt.AlignHCenter
Layout.fillHeight: true
Layout.topMargin: -Tokens.sizes.bar.innerWidth / 10
visible: active
active: root.hasWindows
sourceComponent: Column {
spacing: 0
add: Transition {
Anim {
properties: "scale"
from: 0
to: 1
easing: Tokens.anim.standardDecel
}
}
move: Transition {
Anim {
properties: "scale"
to: 1
easing: Tokens.anim.standardDecel
}
Anim {
properties: "x,y"
}
}
Repeater {
model: ScriptModel {
values: {
const ws = root.ws;
const windows = Hypr.toplevels.values.filter(c => c.workspace?.id === ws);
const maxIcons = Config.bar.workspaces.maxWindowIcons;
return maxIcons > 0 ? windows.slice(0, maxIcons) : windows;
}
}
MaterialIcon {
required property var modelData
grade: 0
text: Icons.getAppCategoryIcon(modelData.lastIpcObject.class, "terminal")
color: Colours.palette.m3onSurfaceVariant
}
}
}
}
Behavior on Layout.preferredHeight {
Anim {}
}
}