Files
dotfiles/.config/quickshell/own/modules/WorkspacesWidget.qml
T

108 lines
3.6 KiB
QML

// WorkspacesWidget.qml - shows workspaces and allows switching between them
import QtQuick
import QtQuick.Layouts
import Quickshell.Hyprland
import ".."
Rectangle {
id: root
required property var screen
property var sortedWorkspaces: Array.from(Hyprland.workspaces.values).sort((a, b) => a.id - b.id)
property int activeIndex: {
var fid = Hyprland.focusedWorkspace?.id ?? -1
for (var i = 0; i < sortedWorkspaces.length; i++)
if (sortedWorkspaces[i].id === fid) return i
return -1
}
// Get the active workspace for this monitor
property var monitorActiveWorkspace: {
var activeWs = Hyprland.focusedWorkspace
// Check if focused workspace is on this monitor
if (activeWs && activeWs.monitor?.id === root.screen.id) {
return activeWs
}
// Otherwise find the first workspace on this monitor
for (var i = 0; i < sortedWorkspaces.length; i++) {
if (sortedWorkspaces[i].monitor?.id === root.screen.id) {
return sortedWorkspaces[i]
}
}
return null
}
function isWorkspaceOnThisMonitor(workspace) {
// Find the monitor in Hyprland.monitors that matches this screen's name
for (const monitor of Hyprland.monitors.values) {
if (monitor.name === root.screen.name && monitor.id === workspace.monitor.id) {
return true
}
}
return false
}
readonly property int btnWidth: 32
color: Theme.pill
radius: Theme.radius
clip: true
implicitWidth: wsRow.implicitWidth
implicitHeight: Theme.barHeight
Behavior on implicitWidth {
NumberAnimation { duration: Theme.workspaceSlideTime; easing.type: Easing.InOutCubic }
}
// Sliding active indicator - single Rectangle that travels between buttons
Rectangle {
visible: root.activeIndex >= 0
x: root.activeIndex * root.btnWidth
width: root.btnWidth
height: parent.height
color: Theme.wsActive
Behavior on x {
NumberAnimation { duration: Theme.workspaceSlideTime; easing.type: Easing.InOutCubic }
}
}
RowLayout {
id: wsRow
anchors.fill: parent
spacing: 0
Repeater {
model: root.sortedWorkspaces
delegate: Rectangle {
required property var modelData
Layout.fillHeight: true
implicitWidth: root.btnWidth
color: wsBtn.containsMouse ? Theme.pillHover : "transparent"
// Reduce opacity for workspaces not on this monitor
opacity: root.isWorkspaceOnThisMonitor(modelData) ? 1.0 : 0.4
Behavior on opacity { NumberAnimation { duration: 150 } }
Behavior on color { ColorAnimation { duration: 150 } }
Text {
anchors.centerIn: parent
text: modelData.id
font { family: Theme.fontSans; pixelSize: Theme.fontSizeSecondary }
color: Theme.pillText
}
MouseArea {
id: wsBtn
anchors.fill: parent
hoverEnabled: true
onClicked: Hyprland.dispatch("hl.dsp.focus({ workspace = '" + modelData.id + "' })")
onWheel: (w) => Hyprland.dispatch(
"hl.dsp.focus({ workspace = \"" + (w.angleDelta.y > 0 ? "e+1" : "e-1") + "\" })"
)
}
}
}
}
}