Files
arthur-os/default/quickshell/bar/widgets/workspacesPro.qml
T
Ryan Hughes 55a9075415 Address reviewer follow-ups: powerProfile detect, slider live-value, glyphs
- powerProfile now hides on machines without power-profiles-daemon by
  checking against the published profile set rather than a never-undefined
  enum, and uses mdi-scale-balance for Balanced (not battery-charging).
- networkPanel renames the QML-keyword-shadowing 'signal' property to
  'signalStrength'; ethernet glyph corrected to mdi-ethernet (not the
  access-point icon).
- workspacesPro indicator color guards against null bar during construction.
- Common.Slider keeps an internal liveValue so external value bindings
  survive a drag; sliders fed from PipeWire/brightnessctl now follow
  external changes after the user interacts.
- audioPanel drops the redundant default-sink PwObjectTracker since the
  candidate-sinks tracker already covers it.
- networkPanel guards scan/connect commands against re-entry while the
  previous Process is running.
- notificationCenter only instantiates its NotificationServer when the
  module is opted in via settings.replaceMako (default off) so it does
  not collide with mako out of the box.
- PopupCard fully opaque while open (previously 0.98) — removes a
  visible ghost outline on first render.
- Drop dead code: calendar trailing MouseArea, weatherFlyout's unused
  parseForecast/forecast property, idleInhibitor's holdSeconds,
  media's scrollAnim.position; gate media's scroll animation off in
  vertical bar mode.
2026-05-14 02:21:47 -04:00

132 lines
4.0 KiB
QML

import QtQuick
import QtQuick.Layouts
import Quickshell
import Quickshell.Hyprland
Item {
id: root
property QtObject bar: null
property string moduleName: "workspacesPro"
property var settings: ({})
function setting(name, fallback) {
var value = settings ? settings[name] : undefined
return value === undefined || value === null ? fallback : value
}
readonly property var ids: bar ? bar.workspaceIds() : [1, 2, 3, 4, 5]
readonly property bool vertical: bar ? bar.vertical : false
readonly property int barSize: bar ? bar.barSize : 26
readonly property int slotSize: vertical ? barSize : 26
readonly property int spacing: vertical ? 4 : 4
readonly property int focusedIndex: {
if (!Hyprland.focusedWorkspace) return -1
var focused = Hyprland.focusedWorkspace.id
for (var i = 0; i < ids.length; i++) if (ids[i] === focused) return i
return -1
}
implicitWidth: vertical ? barSize : ids.length * slotSize + (ids.length - 1) * spacing + 6
implicitHeight: vertical ? ids.length * slotSize + (ids.length - 1) * spacing + 6 : barSize
Rectangle {
id: indicator
width: vertical ? root.slotSize - 8 : root.slotSize - 6
height: vertical ? root.slotSize - 6 : root.slotSize - 8
radius: 4
color: root.bar ? root.bar.foreground : "#cacccc"
opacity: root.focusedIndex >= 0 ? 0.25 : 0
x: vertical ? (root.width - width) / 2 : 3 + root.focusedIndex * (root.slotSize + root.spacing) + (root.slotSize - width) / 2
y: vertical ? 3 + root.focusedIndex * (root.slotSize + root.spacing) + (root.slotSize - height) / 2 : (root.height - height) / 2
Behavior on x { NumberAnimation { duration: 220; easing.type: Easing.OutCubic } }
Behavior on y { NumberAnimation { duration: 220; easing.type: Easing.OutCubic } }
Behavior on opacity { NumberAnimation { duration: 160 } }
}
Loader {
anchors.fill: parent
sourceComponent: root.vertical ? verticalLayout : horizontalLayout
}
Component {
id: horizontalLayout
Row {
anchors.centerIn: parent
spacing: root.spacing
Repeater {
model: root.ids
WorkspaceButton {
required property int modelData
workspaceId: modelData
}
}
}
}
Component {
id: verticalLayout
Column {
anchors.centerIn: parent
spacing: root.spacing
Repeater {
model: root.ids
WorkspaceButton {
required property int modelData
workspaceId: modelData
}
}
}
}
component WorkspaceButton: Item {
id: ws
property int workspaceId: 0
readonly property var workspace: root.bar ? root.bar.workspaceById(workspaceId) : null
readonly property bool occupied: workspace !== null && workspace.toplevels.values.length > 0
readonly property bool focused: Hyprland.focusedWorkspace !== null && Hyprland.focusedWorkspace.id === workspaceId
implicitWidth: root.slotSize
implicitHeight: root.slotSize
Text {
anchors.centerIn: parent
text: ws.focused ? "󱓻" : (ws.workspaceId === 10 ? "0" : String(ws.workspaceId))
color: root.bar ? root.bar.foreground : "#cacccc"
font.family: root.bar ? root.bar.fontFamily : "JetBrainsMono Nerd Font"
font.pixelSize: ws.focused ? 13 : 11
opacity: ws.focused ? 1 : (ws.occupied || ws.workspaceId <= 5 ? 0.8 : 0.4)
Behavior on opacity { NumberAnimation { duration: 160 } }
Behavior on font.pixelSize { NumberAnimation { duration: 160 } }
}
MouseArea {
anchors.fill: parent
hoverEnabled: true
acceptedButtons: Qt.LeftButton | Qt.RightButton
cursorShape: Qt.PointingHandCursor
onClicked: function(mouse) {
if (mouse.button === Qt.RightButton) {
Hyprland.dispatch("movetoworkspace " + ws.workspaceId)
} else {
root.bar.focusWorkspace(ws.workspaceId)
}
}
onWheel: function(wheel) {
if (wheel.angleDelta.y > 0) Hyprland.dispatch("workspace e-1")
else Hyprland.dispatch("workspace e+1")
}
}
}
}