Files
quickdots/bar/modules/Stats.qml
2026-04-24 02:14:35 +00:00

182 lines
4.9 KiB
QML

import QtQuick
import QtQuick.Layouts
import Quickshell
import Quickshell.Io
import "../../config" as Cfg
Rectangle {
id: root
property real panelRadius: Cfg.Config.radius / 2
property int borderWidth: Cfg.Config.panelBorderWidth
property int barHeight: Cfg.Config.barHeight
property int barMargin: Cfg.Config.margin
readonly property var t: Cfg.Config.theme
width: statsLayout.implicitWidth + 20
height: Cfg.Config.moduleHeight
color: t.statsBg
radius: panelRadius
border.color: t.statsBorder
border.width: borderWidth
Behavior on width {
NumberAnimation { duration: 250; easing.type: Easing.OutCubic }
}
HoverHandler { cursorShape: Qt.PointingHandCursor }
property real cpuVal: 0
property real memVal: 0
property real diskVal: 0
Timer {
interval: 2000
running: true
repeat: true
triggeredOnStart: true
onTriggered: {
cpuProc.running = true
memProc.running = true
diskProc.running = true
}
}
Process {
id: cpuProc
command: ["sh", "-c", "top -bn1 | awk '/^%Cpu/ {print 100-$8}'"]
stdout: SplitParser {
onRead: data => {
let val = parseFloat(data.trim())
root.cpuVal = isNaN(val) ? 0 : val
}
}
}
Process {
id: memProc
command: ["sh", "-c", "free | awk '/Mem:/ {print ($2-$7)/$2 * 100}'"]
stdout: SplitParser {
onRead: data => {
let val = parseFloat(data.trim())
root.memVal = isNaN(val) ? 0 : val
}
}
}
Process {
id: diskProc
command: ["sh", "-c", "df / --output=pcent | tail -1 | tr -dc '0-9'"]
stdout: SplitParser {
onRead: data => {
let val = parseFloat(data.trim())
root.diskVal = isNaN(val) ? 0 : val
}
}
}
component StatRing: Item {
id: ring
property real value: 0.0
property string label: ""
property color ringColor: Cfg.Config.theme.accent
property color trackColor: Cfg.Config.theme.statsTrackColor
property color labelColor: Cfg.Config.theme.textMain
Behavior on value {
NumberAnimation {
duration: 800
easing.type: Easing.OutCubic
}
}
readonly property real fraction: Math.max(0, Math.min(value, 100)) / 100
width: Cfg.Config.statsRingSize
height: Cfg.Config.statsRingSize
onFractionChanged: arc.requestPaint()
onRingColorChanged: arc.requestPaint()
Canvas {
id: arc
anchors.fill: parent
antialiasing: true
onPaint: {
var ctx = getContext("2d")
ctx.reset()
ctx.clearRect(0, 0, width, height)
var cx = width / 2
var cy = height / 2
var lw = 2.8
var r = Math.min(cx, cy) - lw / 2 - 0.5
ctx.beginPath()
ctx.arc(cx, cy, r, 0, Math.PI * 2)
ctx.strokeStyle = ring.trackColor
ctx.lineWidth = lw
ctx.stroke()
if (ring.fraction > 0) {
var start = -Math.PI / 2
var end = start + (ring.fraction * Math.PI * 2)
ctx.beginPath()
ctx.arc(cx, cy, r, start, end)
ctx.strokeStyle = ring.ringColor
ctx.lineWidth = lw
ctx.lineCap = "round"
ctx.stroke()
}
}
}
HoverHandler { id: hov }
Text {
anchors.centerIn: parent
text: Cfg.Config.statsShowPercentByDefault
? (hov.hovered ? ring.label : Math.round(ring.value) + "%")
: (hov.hovered ? Math.round(ring.value) + "%" : ring.label)
color: ring.labelColor
font.pixelSize: Cfg.Config.statsRingFontSize
font.bold: true
font.family: "monospace"
}
}
RowLayout {
id: statsLayout
anchors.centerIn: parent
spacing: 10
StatRing {
value: root.cpuVal
label: "cpu"
ringColor: root.t.statsCpuColor
trackColor: root.t.statsTrackColor
labelColor: root.t.statsText
}
StatRing {
value: root.memVal
label: "ram"
ringColor: root.t.statsMemColor
trackColor: root.t.statsTrackColor
labelColor: root.t.statsText
}
StatRing {
value: root.diskVal
label: "disk"
ringColor: root.t.statsDiskColor
trackColor: root.t.statsTrackColor
labelColor: root.t.statsText
}
}
}