Extract workspace switcher widget
This commit is contained in:
@@ -1,5 +1,4 @@
|
|||||||
import Quickshell
|
import Quickshell
|
||||||
import Quickshell.Hyprland
|
|
||||||
import Quickshell.Io
|
import Quickshell.Io
|
||||||
import Quickshell.Services.SystemTray
|
import Quickshell.Services.SystemTray
|
||||||
import Quickshell.Wayland
|
import Quickshell.Wayland
|
||||||
@@ -260,7 +259,6 @@ Item {
|
|||||||
function builtinModuleComponent(name) {
|
function builtinModuleComponent(name) {
|
||||||
switch (String(name)) {
|
switch (String(name)) {
|
||||||
case "omarchy": return omarchyModuleComponent
|
case "omarchy": return omarchyModuleComponent
|
||||||
case "workspaces": return workspacesModuleComponent
|
|
||||||
case "clock": return clockModuleComponent
|
case "clock": return clockModuleComponent
|
||||||
case "update": return updateModuleComponent
|
case "update": return updateModuleComponent
|
||||||
case "indicators": return indicatorsModuleComponent
|
case "indicators": return indicatorsModuleComponent
|
||||||
@@ -305,6 +303,7 @@ Item {
|
|||||||
// Each entry maps a module id to its display metadata; the QML source is
|
// Each entry maps a module id to its display metadata; the QML source is
|
||||||
// loaded asynchronously via Qt.createComponent.
|
// loaded asynchronously via Qt.createComponent.
|
||||||
readonly property var firstPartyWidgetMetadata: ({
|
readonly property var firstPartyWidgetMetadata: ({
|
||||||
|
"workspaces": { displayName: "Workspaces", description: "Workspace number indicators", category: "Compositor", allowMultiple: false },
|
||||||
"media": { displayName: "Media", description: "MPRIS now-playing with playback controls", category: "Media", allowMultiple: false },
|
"media": { displayName: "Media", description: "MPRIS now-playing with playback controls", category: "Media", allowMultiple: false },
|
||||||
"audioPanel": { displayName: "Audio", description: "Volume slider, output picker, per-app mixer", category: "Audio", allowMultiple: false, sourceDir: "../panels", sourceName: "Audio" },
|
"audioPanel": { displayName: "Audio", description: "Volume slider, output picker, per-app mixer", category: "Audio", allowMultiple: false, sourceDir: "../panels", sourceName: "Audio" },
|
||||||
"monitorPanel": { displayName: "Display", description: "Brightness slider and laptop display controls", category: "System", allowMultiple: false, sourceDir: "../panels", sourceName: "Monitor" },
|
"monitorPanel": { displayName: "Display", description: "Brightness slider and laptop display controls", category: "System", allowMultiple: false, sourceDir: "../panels", sourceName: "Monitor" },
|
||||||
@@ -441,30 +440,6 @@ Item {
|
|||||||
indicatorsRefreshRequested()
|
indicatorsRefreshRequested()
|
||||||
}
|
}
|
||||||
|
|
||||||
function workspaceById(id) {
|
|
||||||
var values = Hyprland.workspaces.values
|
|
||||||
for (var i = 0; i < values.length; i++) {
|
|
||||||
if (values[i].id === id)
|
|
||||||
return values[i]
|
|
||||||
}
|
|
||||||
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
function workspaceIds() {
|
|
||||||
var ids = [1, 2, 3, 4, 5]
|
|
||||||
var values = Hyprland.workspaces.values
|
|
||||||
|
|
||||||
for (var i = 0; i < values.length; i++) {
|
|
||||||
var id = values[i].id
|
|
||||||
if (id > 0 && id <= 10 && ids.indexOf(id) === -1)
|
|
||||||
ids.push(id)
|
|
||||||
}
|
|
||||||
|
|
||||||
ids.sort(function(left, right) { return left - right })
|
|
||||||
return ids
|
|
||||||
}
|
|
||||||
|
|
||||||
function trayIconSource(icon) {
|
function trayIconSource(icon) {
|
||||||
var value = String(icon || "")
|
var value = String(icon || "")
|
||||||
var marker = "?path="
|
var marker = "?path="
|
||||||
@@ -480,10 +455,6 @@ Item {
|
|||||||
return item.tooltipTitle || item.title || item.id || ""
|
return item.tooltipTitle || item.title || item.id || ""
|
||||||
}
|
}
|
||||||
|
|
||||||
function focusWorkspace(id) {
|
|
||||||
root.run("hyprctl dispatch " + Util.shellQuote("hl.dsp.focus({ workspace = \"" + id + "\" })"))
|
|
||||||
}
|
|
||||||
|
|
||||||
function clockEntry() {
|
function clockEntry() {
|
||||||
var serial = barConfigSerial
|
var serial = barConfigSerial
|
||||||
var sections = ["left", "center", "right"]
|
var sections = ["left", "center", "right"]
|
||||||
@@ -741,7 +712,6 @@ Item {
|
|||||||
|
|
||||||
Component { id: emptyModuleComponent; Item { implicitWidth: 0; implicitHeight: 0; visible: false } }
|
Component { id: emptyModuleComponent; Item { implicitWidth: 0; implicitHeight: 0; visible: false } }
|
||||||
Component { id: omarchyModuleComponent; OmarchyModule {} }
|
Component { id: omarchyModuleComponent; OmarchyModule {} }
|
||||||
Component { id: workspacesModuleComponent; WorkspacesModule {} }
|
|
||||||
Component { id: clockModuleComponent; ClockModule {} }
|
Component { id: clockModuleComponent; ClockModule {} }
|
||||||
Component { id: updateModuleComponent; UpdateModule {} }
|
Component { id: updateModuleComponent; UpdateModule {} }
|
||||||
Component { id: indicatorsModuleComponent; IndicatorsModule {} }
|
Component { id: indicatorsModuleComponent; IndicatorsModule {} }
|
||||||
@@ -1482,32 +1452,6 @@ Item {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
component WorkspacesModule: GridLayout {
|
|
||||||
columns: root.vertical ? 1 : root.workspaceIds().length
|
|
||||||
columnSpacing: root.vertical ? 0 : Style.space(2)
|
|
||||||
rowSpacing: root.vertical ? Style.space(2) : 0
|
|
||||||
|
|
||||||
Repeater {
|
|
||||||
model: root.workspaceIds()
|
|
||||||
|
|
||||||
ModuleButton {
|
|
||||||
required property int modelData
|
|
||||||
|
|
||||||
property var workspace: root.workspaceById(modelData)
|
|
||||||
property bool occupied: workspace !== null && workspace.toplevels.values.length > 0
|
|
||||||
property bool focused: Hyprland.focusedWorkspace !== null && Hyprland.focusedWorkspace.id === modelData
|
|
||||||
|
|
||||||
text: focused ? "" : (modelData === 10 ? "0" : String(modelData))
|
|
||||||
opacity: occupied || focused ? 1 : 0.5
|
|
||||||
horizontalMargin: 6
|
|
||||||
verticalPadding: 6
|
|
||||||
fixedWidth: root.vertical ? root.barSize : 22
|
|
||||||
fixedHeight: root.barSize
|
|
||||||
onPressed: function() { root.focusWorkspace(modelData) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
component ClockModule: ModuleButton {
|
component ClockModule: ModuleButton {
|
||||||
text: root.clockText()
|
text: root.clockText()
|
||||||
horizontalMargin: 8.75
|
horizontalMargin: 8.75
|
||||||
|
|||||||
@@ -54,6 +54,7 @@ Example `shell.json` (bar subtree only shown):
|
|||||||
|
|
||||||
| Name | What it does | Interactions |
|
| Name | What it does | Interactions |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
|
| `workspaces` | Hyprland workspace switcher | left = focus workspace |
|
||||||
| `media` | MPRIS now-playing — scrolling track + artist, cover-art popup | left = play/pause · middle = next · scroll = prev/next · right = popup |
|
| `media` | MPRIS now-playing — scrolling track + artist, cover-art popup | left = play/pause · middle = next · scroll = prev/next · right = popup |
|
||||||
| `daytime` | Day/time label with date tooltip | hover = date |
|
| `daytime` | Day/time label with date tooltip | hover = date |
|
||||||
| `notificationCenter` | Bell with badge + popup with recent notifications, DND toggle | left = popup · right = toggle DND |
|
| `notificationCenter` | Bell with badge + popup with recent notifications, DND toggle | left = popup · right = toggle DND |
|
||||||
@@ -73,7 +74,7 @@ Example `shell.json` (bar subtree only shown):
|
|||||||
|
|
||||||
### Built-in base modules (in `Bar.qml`)
|
### Built-in base modules (in `Bar.qml`)
|
||||||
|
|
||||||
`omarchy`, `workspaces`, `clock`, `update`, `indicators`, `tray`.
|
`omarchy`, `clock`, `update`, `indicators`, `tray`.
|
||||||
|
|
||||||
The `indicators` module loads individual bar indicators from `indicators/`, ordered by its `items` array in `shell.json`. Rich panels such as `powerPanel`, `networkPanel`, and `audioPanel` live in `../panels/` above.
|
The `indicators` module loads individual bar indicators from `indicators/`, ordered by its `items` array in `shell.json`. Rich panels such as `powerPanel`, `networkPanel`, and `audioPanel` live in `../panels/` above.
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,72 @@
|
|||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import Quickshell.Hyprland
|
||||||
|
import qs.Commons
|
||||||
|
import qs.Ui
|
||||||
|
|
||||||
|
BarWidget {
|
||||||
|
id: root
|
||||||
|
moduleName: "workspaces"
|
||||||
|
|
||||||
|
readonly property bool vertical: bar ? bar.vertical : false
|
||||||
|
readonly property int barSize: bar ? bar.barSize : Style.bar.sizeHorizontal
|
||||||
|
|
||||||
|
function workspaceById(id) {
|
||||||
|
var values = Hyprland.workspaces.values
|
||||||
|
for (var i = 0; i < values.length; i++) {
|
||||||
|
if (values[i].id === id) return values[i]
|
||||||
|
}
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
function workspaceIds() {
|
||||||
|
var ids = [1, 2, 3, 4, 5]
|
||||||
|
var values = Hyprland.workspaces.values
|
||||||
|
|
||||||
|
for (var i = 0; i < values.length; i++) {
|
||||||
|
var id = values[i].id
|
||||||
|
if (id > 0 && id <= 10 && ids.indexOf(id) === -1) ids.push(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
ids.sort(function(left, right) { return left - right })
|
||||||
|
return ids
|
||||||
|
}
|
||||||
|
|
||||||
|
function focusWorkspace(id) {
|
||||||
|
if (!root.bar) return
|
||||||
|
root.bar.run("hyprctl dispatch " + Util.shellQuote("hl.dsp.focus({ workspace = \"" + id + "\" })"))
|
||||||
|
}
|
||||||
|
|
||||||
|
implicitWidth: grid.implicitWidth
|
||||||
|
implicitHeight: grid.implicitHeight
|
||||||
|
|
||||||
|
GridLayout {
|
||||||
|
id: grid
|
||||||
|
anchors.fill: parent
|
||||||
|
columns: root.vertical ? 1 : root.workspaceIds().length
|
||||||
|
columnSpacing: root.vertical ? 0 : Style.space(2)
|
||||||
|
rowSpacing: root.vertical ? Style.space(2) : 0
|
||||||
|
|
||||||
|
Repeater {
|
||||||
|
model: root.workspaceIds()
|
||||||
|
|
||||||
|
WidgetButton {
|
||||||
|
required property int modelData
|
||||||
|
|
||||||
|
readonly property var workspace: root.workspaceById(modelData)
|
||||||
|
readonly property bool occupied: workspace !== null && workspace.toplevels.values.length > 0
|
||||||
|
readonly property bool focused: Hyprland.focusedWorkspace !== null && Hyprland.focusedWorkspace.id === modelData
|
||||||
|
|
||||||
|
bar: root.bar
|
||||||
|
text: focused ? "\uDB85\uDCFB" : (modelData === 10 ? "0" : String(modelData))
|
||||||
|
opacity: occupied || focused ? 1 : 0.5
|
||||||
|
horizontalMargin: 6
|
||||||
|
verticalPadding: 6
|
||||||
|
fixedWidth: root.vertical ? root.barSize : 22
|
||||||
|
fixedHeight: root.barSize
|
||||||
|
onPressed: function() { root.focusWorkspace(modelData) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -292,7 +292,6 @@ Item {
|
|||||||
// ---------------- widget catalog -----------------------------------------
|
// ---------------- widget catalog -----------------------------------------
|
||||||
readonly property var builtinWidgetMeta: ({
|
readonly property var builtinWidgetMeta: ({
|
||||||
"omarchy": { name: "Omarchy menu", description: "Launches the Omarchy menu", category: "Compositor" },
|
"omarchy": { name: "Omarchy menu", description: "Launches the Omarchy menu", category: "Compositor" },
|
||||||
"workspaces": { name: "Workspaces", description: "Workspace number indicators", category: "Compositor" },
|
|
||||||
"clock": { name: "Clock", description: "Date / time text", category: "Time" },
|
"clock": { name: "Clock", description: "Date / time text", category: "Time" },
|
||||||
"update": { name: "Updates", description: "Indicates available system updates", category: "System" },
|
"update": { name: "Updates", description: "Indicates available system updates", category: "System" },
|
||||||
"indicators": { name: "Indicators", description: "Manual state indicators", category: "Status" },
|
"indicators": { name: "Indicators", description: "Manual state indicators", category: "Status" },
|
||||||
|
|||||||
Reference in New Issue
Block a user