108 lines
3.6 KiB
QML
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") + "\" })"
|
|
)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|