Compare commits

...

4 commits

Author SHA1 Message Date
Damocles
186c9a3aa2 move stuff into components 2026-04-12 01:00:05 +02:00
Damocles
14292e6683 move stuff into components 2026-04-12 00:56:17 +02:00
Damocles
6370732e4e add tooltips 2026-04-12 00:49:58 +02:00
Damocles
7ca7e1e952 add scrool or click actions 2026-04-12 00:46:38 +02:00
20 changed files with 147 additions and 49 deletions

View file

@ -2,13 +2,26 @@ import QtQuick
import Quickshell.Io import Quickshell.Io
import "." as M import "." as M
Row { M.BarSection {
id: root id: root
spacing: 4 spacing: 4
visible: percent > 0 visible: percent > 0
tooltip: "Brightness: " + root.percent + "%"
property int percent: 0 property int percent: 0
Process {
id: adjProc
property string cmd: ""
command: ["sh", "-c", cmd]
onRunningChanged: if (!running && cmd !== "") current.reload()
}
function adjust(delta) {
adjProc.cmd = delta > 0 ? "light -A 5" : "light -U 5";
adjProc.running = true;
}
FileView { FileView {
id: current id: current
path: "/sys/class/backlight/intel_backlight/brightness" path: "/sys/class/backlight/intel_backlight/brightness"
@ -36,4 +49,8 @@ Row {
font.family: M.Theme.fontFamily font.family: M.Theme.fontFamily
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
} }
WheelHandler {
onWheel: event => root.adjust(event.angleDelta.y)
}
} }

View file

@ -1,12 +1,20 @@
import QtQuick import QtQuick
import QtQuick.Controls
import "." as M import "." as M
Text { Text {
property string icon: "" property string icon: ""
property string tooltip: ""
text: icon text: icon
color: M.Theme.base05 color: M.Theme.base05
font.pixelSize: M.Theme.fontSize + 1 font.pixelSize: M.Theme.fontSize + 1
font.family: M.Theme.iconFontFamily font.family: M.Theme.iconFontFamily
verticalAlignment: Text.AlignVCenter verticalAlignment: Text.AlignVCenter
HoverHandler { id: _hover }
ToolTip {
visible: _hover.hovered && parent.tooltip !== ""
text: parent.tooltip
}
} }

View file

@ -1,12 +1,20 @@
import QtQuick import QtQuick
import QtQuick.Controls
import "." as M import "." as M
Text { Text {
property string label: "" property string label: ""
property string tooltip: ""
text: label text: label
color: M.Theme.base05 color: M.Theme.base05
font.pixelSize: M.Theme.fontSize font.pixelSize: M.Theme.fontSize
font.family: M.Theme.fontFamily font.family: M.Theme.fontFamily
verticalAlignment: Text.AlignVCenter verticalAlignment: Text.AlignVCenter
HoverHandler { id: _hover }
ToolTip {
visible: _hover.hovered && parent.tooltip !== ""
text: parent.tooltip
}
} }

12
modules/BarSection.qml Normal file
View file

@ -0,0 +1,12 @@
import QtQuick
import QtQuick.Controls
Row {
property string tooltip: ""
HoverHandler { id: _hover }
ToolTip {
visible: _hover.hovered && parent.tooltip !== ""
text: parent.tooltip
}
}

View file

@ -2,10 +2,17 @@ import QtQuick
import Quickshell.Services.UPower import Quickshell.Services.UPower
import "." as M import "." as M
Row { M.BarSection {
id: root id: root
spacing: 4 spacing: 4
visible: UPower.displayDevice?.isLaptopBattery ?? false visible: UPower.displayDevice?.isLaptopBattery ?? false
tooltip: {
const state = root.charging ? "Charging" : "Discharging";
const t = root.charging ? root.dev?.timeToFull : root.dev?.timeToEmpty;
const mins = t ? Math.round(t / 60) : 0;
const timeStr = mins > 0 ? "\n" + Math.floor(mins / 60) + "h " + (mins % 60) + "m " + (root.charging ? "until full" : "remaining") : "";
return state + " \u2014 " + Math.round(root.pct) + "%" + timeStr;
}
readonly property var dev: UPower.displayDevice readonly property var dev: UPower.displayDevice
readonly property real pct: (dev?.percentage ?? 0) * 100 readonly property real pct: (dev?.percentage ?? 0) * 100

View file

@ -2,9 +2,10 @@ import QtQuick
import Quickshell.Io import Quickshell.Io
import "." as M import "." as M
Row { M.BarSection {
id: root id: root
spacing: 4 spacing: 4
tooltip: root.status === "connected" ? "Bluetooth: " + root.device : "Bluetooth: on"
property string status: "off" property string status: "off"
property string device: "" property string device: ""

View file

@ -2,15 +2,13 @@ import QtQuick
import Quickshell import Quickshell
import "." as M import "." as M
Text { M.BarLabel {
SystemClock { SystemClock {
id: clock id: clock
precision: SystemClock.Minutes precision: SystemClock.Seconds
} }
text: Qt.formatDateTime(clock.date, "ddd, dd. MMM HH:mm")
color: M.Theme.base05
font.pixelSize: M.Theme.fontSize + 1 font.pixelSize: M.Theme.fontSize + 1
font.family: M.Theme.fontFamily label: Qt.formatDateTime(clock.date, "ddd, dd. MMM HH:mm")
verticalAlignment: Text.AlignVCenter tooltip: Qt.formatDateTime(clock.date, "dddd, dd. MMMM yyyy\nHH:mm:ss")
} }

View file

@ -2,13 +2,13 @@ import QtQuick
import Quickshell.Io import Quickshell.Io
import "." as M import "." as M
Row { M.BarSection {
id: root id: root
spacing: 2 spacing: 2
tooltip: "CPU: " + root.usage + "%\n" + root.freqGhz.toFixed(2) + " GHz"
property int usage: 0 property int usage: 0
property real freqGhz: 0 property real freqGhz: 0
property var _prev: null property var _prev: null
FileView { FileView {
@ -25,10 +25,7 @@ Row {
if (dTotal > 0) if (dTotal > 0)
root.usage = Math.round((1 - dIdle / dTotal) * 100); root.usage = Math.round((1 - dIdle / dTotal) * 100);
} }
root._prev = { root._prev = { idle, total };
idle,
total
};
} }
} }
FileView { FileView {
@ -36,8 +33,7 @@ Row {
path: "/proc/cpuinfo" path: "/proc/cpuinfo"
onLoaded: { onLoaded: {
const lines = text().split("\n").filter(l => l.startsWith("cpu MHz")); const lines = text().split("\n").filter(l => l.startsWith("cpu MHz"));
if (lines.length === 0) if (lines.length === 0) return;
return;
const sum = lines.reduce((a, l) => a + parseFloat(l.split(":")[1]), 0); const sum = lines.reduce((a, l) => a + parseFloat(l.split(":")[1]), 0);
root.freqGhz = sum / lines.length / 1000; root.freqGhz = sum / lines.length / 1000;
} }
@ -46,10 +42,7 @@ Row {
interval: 1000 interval: 1000
running: true running: true
repeat: true repeat: true
onTriggered: { onTriggered: { stat.reload(); cpuinfo.reload(); }
stat.reload();
cpuinfo.reload();
}
} }
M.BarIcon { M.BarIcon {

View file

@ -2,9 +2,10 @@ import QtQuick
import Quickshell.Io import Quickshell.Io
import "." as M import "." as M
Row { M.BarSection {
id: root id: root
spacing: 2 spacing: 2
tooltip: root.freePct + "% free of " + root.totalTb.toFixed(1) + " TB"
property int freePct: 0 property int freePct: 0
property real totalTb: 0 property real totalTb: 0

View file

@ -4,6 +4,7 @@ import "." as M
M.BarIcon { M.BarIcon {
id: root id: root
tooltip: "Idle inhibition: " + (root.active ? "active" : "inactive")
property bool active: false property bool active: false

View file

@ -2,9 +2,10 @@ import QtQuick
import Quickshell.Io import Quickshell.Io
import "." as M import "." as M
Row { M.BarSection {
id: root id: root
spacing: 2 spacing: 2
tooltip: "Memory: " + root.percent + "% used"
property int percent: 0 property int percent: 0
@ -15,8 +16,7 @@ Row {
const m = {}; const m = {};
text().split("\n").forEach(l => { text().split("\n").forEach(l => {
const [k, v] = l.split(":"); const [k, v] = l.split(":");
if (v) if (v) m[k.trim()] = parseInt(v.trim());
m[k.trim()] = parseInt(v.trim());
}); });
const total = m.MemTotal; const total = m.MemTotal;
const avail = m.MemAvailable; const avail = m.MemAvailable;

View file

@ -2,10 +2,19 @@ import QtQuick
import Quickshell.Services.Mpris import Quickshell.Services.Mpris
import "." as M import "." as M
Row { M.BarSection {
id: root id: root
spacing: 4 spacing: 4
visible: player !== null visible: player !== null
tooltip: {
const p = root.player;
if (!p) return "";
const parts = [];
if (p.trackTitle) parts.push(p.trackTitle);
if (p.trackArtists?.length) parts.push(p.trackArtists.join(", "));
if (p.trackAlbum) parts.push(p.trackAlbum);
return parts.join("\n") || p.identity;
}
readonly property MprisPlayer player: Mpris.players.values[0] ?? null readonly property MprisPlayer player: Mpris.players.values[0] ?? null
readonly property bool playing: player?.playbackState === MprisPlaybackState.Playing readonly property bool playing: player?.playbackState === MprisPlaybackState.Playing

View file

@ -2,9 +2,15 @@ import QtQuick
import Quickshell.Io import Quickshell.Io
import "." as M import "." as M
Row { M.BarSection {
id: root id: root
spacing: 4 spacing: 4
tooltip: {
if (root.state === "wifi") return "WiFi: " + root.essid + (root.ifname ? "\nInterface: " + root.ifname : "");
if (root.state === "eth") return "Ethernet: " + root.ifname;
if (root.state === "linked") return "Linked: " + root.ifname;
return "Disconnected";
}
property string ifname: "" property string ifname: ""
property string essid: "" property string essid: ""
@ -44,12 +50,9 @@ Row {
M.BarIcon { M.BarIcon {
icon: { icon: {
if (root.state === "wifi") if (root.state === "wifi") return "\uF1EB";
return "\uF1EB"; if (root.state === "eth") return "\uDB80\uDE00";
if (root.state === "eth") if (root.state === "linked") return "\uDB85\uDE16";
return "\uDB80\uDE00";
if (root.state === "linked")
return "\uDB85\uDE16";
return "\uDB82\uDCFD"; return "\uDB82\uDCFD";
} }
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter

View file

@ -2,9 +2,15 @@ import QtQuick
import Quickshell.Io import Quickshell.Io
import "." as M import "." as M
Row { M.BarSection {
id: root id: root
spacing: 4 spacing: 4
tooltip: {
const parts = [root.count + " notification" + (root.count !== 1 ? "s" : "")];
if (root.dnd) parts.push("Do not disturb");
if (root.inhibited) parts.push("Inhibited");
return parts.join("\n");
}
property int count: 0 property int count: 0
property bool dnd: false property bool dnd: false
@ -55,7 +61,5 @@ Row {
clicker.running = true; clicker.running = true;
} }
} }
Process { Process { id: clicker }
id: clicker
}
} }

View file

@ -4,6 +4,7 @@ import "." as M
M.BarIcon { M.BarIcon {
id: root id: root
tooltip: "Power profile: " + (root.profile || "unknown")
property string profile: "" property string profile: ""
@ -28,4 +29,20 @@ M.BarIcon {
repeat: true repeat: true
onTriggered: proc.running = true onTriggered: proc.running = true
} }
Process {
id: setter
property string next: ""
command: ["powerprofilesctl", "set", next]
onRunningChanged: if (!running && next !== "") proc.running = true
}
TapHandler {
onTapped: {
const cycle = ["performance", "balanced", "power-saver"];
const idx = cycle.indexOf(root.profile);
setter.next = cycle[(idx + 1) % cycle.length];
setter.running = true;
}
}
} }

View file

@ -2,9 +2,10 @@ import QtQuick
import Quickshell.Io import Quickshell.Io
import "." as M import "." as M
Row { M.BarSection {
id: root id: root
spacing: 2 spacing: 2
tooltip: "Temperature: " + root.celsius + "\u00B0C"
property int celsius: 0 property int celsius: 0
@ -26,7 +27,7 @@ Row {
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
} }
Text { Text {
text: root.celsius + "°C" text: root.celsius + "\u00B0C"
color: root.celsius > 80 ? M.Theme.base08 : M.Theme.base05 color: root.celsius > 80 ? M.Theme.base08 : M.Theme.base05
font.pixelSize: M.Theme.fontSize font.pixelSize: M.Theme.fontSize
font.family: M.Theme.fontFamily font.family: M.Theme.fontFamily

View file

@ -2,9 +2,12 @@ import QtQuick
import Quickshell.Services.Pipewire import Quickshell.Services.Pipewire
import "." as M import "." as M
Row { M.BarSection {
id: root id: root
spacing: 4 spacing: 4
tooltip: (root.sink?.description ?? root.sink?.name ?? "Unknown sink") +
"\nVolume: " + Math.round(root.volume * 100) + "%" +
(root.muted ? "\nMuted" : "")
PwObjectTracker { PwObjectTracker {
objects: [Pipewire.defaultAudioSink] objects: [Pipewire.defaultAudioSink]
@ -26,4 +29,11 @@ Row {
TapHandler { TapHandler {
onTapped: if (root.sink?.audio) root.sink.audio.muted = !root.sink.audio.muted onTapped: if (root.sink?.audio) root.sink.audio.muted = !root.sink.audio.muted
} }
WheelHandler {
onWheel: event => {
if (!root.sink?.audio) return;
root.sink.audio.volume = Math.max(0, root.sink.audio.volume + (event.angleDelta.y > 0 ? 0.05 : -0.05));
}
}
} }

View file

@ -2,10 +2,12 @@ import QtQuick
import Quickshell.Io import Quickshell.Io
import "." as M import "." as M
Text { M.BarSection {
id: root id: root
spacing: 4
tooltip: root.weatherTooltip
property string label: "" property string weatherTooltip: ""
Process { Process {
id: proc id: proc
@ -15,9 +17,11 @@ Text {
onStreamFinished: { onStreamFinished: {
try { try {
const data = JSON.parse(text); const data = JSON.parse(text);
root.label = data.text ?? ""; label.text = data.text ?? "";
root.weatherTooltip = data.tooltip ?? "";
} catch (e) { } catch (e) {
root.label = ""; label.text = "";
root.weatherTooltip = "";
} }
} }
} }
@ -29,9 +33,11 @@ Text {
onTriggered: proc.running = true onTriggered: proc.running = true
} }
text: root.label Text {
id: label
color: M.Theme.base05 color: M.Theme.base05
font.pixelSize: M.Theme.fontSize font.pixelSize: M.Theme.fontSize
font.family: M.Theme.iconFontFamily font.family: M.Theme.iconFontFamily
verticalAlignment: Text.AlignVCenter anchors.verticalCenter: parent.verticalCenter
}
} }

View file

@ -4,6 +4,7 @@ import "." as M
M.BarIcon { M.BarIcon {
icon: "\uF011" icon: "\uF011"
tooltip: "Open logout menu"
Process { Process {
id: proc id: proc

View file

@ -1,6 +1,7 @@
module modules module modules
singleton Theme 1.0 Theme.qml singleton Theme 1.0 Theme.qml
Bar 1.0 Bar.qml Bar 1.0 Bar.qml
BarSection 1.0 BarSection.qml
Workspaces 1.0 Workspaces.qml Workspaces 1.0 Workspaces.qml
WindowTitle 1.0 WindowTitle.qml WindowTitle 1.0 WindowTitle.qml
Clock 1.0 Clock.qml Clock 1.0 Clock.qml