Use capitalized camel for all classes
This commit is contained in:
@@ -0,0 +1,290 @@
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
import qs.Ui
|
||||
import qs.Commons
|
||||
|
||||
BarWidget {
|
||||
id: root
|
||||
moduleName: "SystemStats"
|
||||
|
||||
|
||||
property real cpuPercent: 0
|
||||
property real memPercent: 0
|
||||
property var cpuHistory: []
|
||||
property var memHistory: []
|
||||
property real loadAvg: 0
|
||||
|
||||
property var prevCpu: ({ idle: 0, total: 0 })
|
||||
|
||||
property bool popupOpen: false
|
||||
|
||||
function close() { popupOpen = false }
|
||||
|
||||
readonly property int historyLimit: 30
|
||||
|
||||
function refresh() {
|
||||
if (!cpuProc.running) cpuProc.running = true
|
||||
if (!memProc.running) memProc.running = true
|
||||
if (!loadProc.running) loadProc.running = true
|
||||
}
|
||||
|
||||
function pushHistory(arr, value) {
|
||||
var next = arr.slice()
|
||||
next.push(value)
|
||||
if (next.length > historyLimit) next.shift()
|
||||
return next
|
||||
}
|
||||
|
||||
function updateCpu(raw) {
|
||||
var fields = String(raw || "").trim().split(/\s+/)
|
||||
if (fields.length < 8) return
|
||||
var user = parseInt(fields[1], 10) || 0
|
||||
var nice = parseInt(fields[2], 10) || 0
|
||||
var sys = parseInt(fields[3], 10) || 0
|
||||
var idle = parseInt(fields[4], 10) || 0
|
||||
var iowait = parseInt(fields[5], 10) || 0
|
||||
var irq = parseInt(fields[6], 10) || 0
|
||||
var softirq = parseInt(fields[7], 10) || 0
|
||||
|
||||
var total = user + nice + sys + idle + iowait + irq + softirq
|
||||
var totalDiff = total - prevCpu.total
|
||||
var idleDiff = idle - prevCpu.idle
|
||||
|
||||
if (prevCpu.total > 0 && totalDiff > 0) {
|
||||
var usage = (1 - idleDiff / totalDiff) * 100
|
||||
cpuPercent = Math.max(0, Math.min(100, usage))
|
||||
cpuHistory = pushHistory(cpuHistory, cpuPercent)
|
||||
}
|
||||
|
||||
prevCpu = { idle: idle, total: total }
|
||||
}
|
||||
|
||||
function updateMem(raw) {
|
||||
var lines = String(raw || "").split("\n")
|
||||
var total = 0
|
||||
var available = 0
|
||||
for (var i = 0; i < lines.length; i++) {
|
||||
var line = lines[i]
|
||||
if (line.indexOf("MemTotal:") === 0) total = parseInt(line.replace(/[^0-9]/g, ""), 10) || 0
|
||||
else if (line.indexOf("MemAvailable:") === 0) available = parseInt(line.replace(/[^0-9]/g, ""), 10) || 0
|
||||
}
|
||||
if (total > 0) {
|
||||
memPercent = ((total - available) / total) * 100
|
||||
memHistory = pushHistory(memHistory, memPercent)
|
||||
}
|
||||
}
|
||||
|
||||
function updateLoad(raw) {
|
||||
var n = parseFloat(String(raw || "").trim().split(/\s+/)[0])
|
||||
if (!isNaN(n)) loadAvg = n
|
||||
}
|
||||
|
||||
Component.onCompleted: refresh()
|
||||
|
||||
Process {
|
||||
id: cpuProc
|
||||
command: ["bash", "-lc", "head -n1 /proc/stat"]
|
||||
stdout: StdioCollector {
|
||||
waitForEnd: true
|
||||
onStreamFinished: root.updateCpu(text)
|
||||
}
|
||||
}
|
||||
|
||||
Process {
|
||||
id: memProc
|
||||
command: ["bash", "-lc", "head -n3 /proc/meminfo"]
|
||||
stdout: StdioCollector {
|
||||
waitForEnd: true
|
||||
onStreamFinished: root.updateMem(text)
|
||||
}
|
||||
}
|
||||
|
||||
Process {
|
||||
id: loadProc
|
||||
command: ["bash", "-lc", "cat /proc/loadavg"]
|
||||
stdout: StdioCollector {
|
||||
waitForEnd: true
|
||||
onStreamFinished: root.updateLoad(text)
|
||||
}
|
||||
}
|
||||
|
||||
Timer {
|
||||
interval: 2000
|
||||
running: true
|
||||
repeat: true
|
||||
onTriggered: root.refresh()
|
||||
}
|
||||
|
||||
readonly property color statColor: bar ? bar.foreground : Color.foreground
|
||||
|
||||
implicitWidth: button.implicitWidth
|
||||
implicitHeight: button.implicitHeight
|
||||
|
||||
// Hover state across the trigger button and the popup.
|
||||
property bool buttonHovered: false
|
||||
property bool popupHovered: popup.containsMouse
|
||||
|
||||
function showPopup() {
|
||||
hideTimer.stop()
|
||||
popupOpen = true
|
||||
}
|
||||
|
||||
function scheduleHide() {
|
||||
hideTimer.restart()
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: hideTimer
|
||||
interval: 220
|
||||
onTriggered: {
|
||||
if (!root.buttonHovered && !root.popupHovered) root.popupOpen = false
|
||||
}
|
||||
}
|
||||
|
||||
onButtonHoveredChanged: buttonHovered ? showPopup() : scheduleHide()
|
||||
onPopupHoveredChanged: popupHovered ? hideTimer.stop() : scheduleHide()
|
||||
|
||||
WidgetButton {
|
||||
id: button
|
||||
anchors.fill: parent
|
||||
bar: root.bar
|
||||
text: ""
|
||||
horizontalMargin: 7.5
|
||||
tooltipText: ""
|
||||
|
||||
onPressed: function(b) {
|
||||
if (b === Qt.LeftButton) {
|
||||
root.popupOpen = false
|
||||
root.bar.run("omarchy-launch-or-focus-tui btop")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HoverHandler {
|
||||
id: hoverHandler
|
||||
target: button
|
||||
onHoveredChanged: root.buttonHovered = hovered
|
||||
}
|
||||
|
||||
PopupCard {
|
||||
id: popup
|
||||
anchorItem: button
|
||||
owner: root
|
||||
bar: root.bar
|
||||
open: root.popupOpen
|
||||
triggerMode: "hover"
|
||||
contentWidth: popup.fittedContentWidth(Style.space(320))
|
||||
contentHeight: popup.fittedContentHeight(detailColumn.implicitHeight)
|
||||
|
||||
Column {
|
||||
id: detailColumn
|
||||
anchors.fill: parent
|
||||
spacing: Style.space(10)
|
||||
|
||||
Text {
|
||||
text: "System"
|
||||
color: root.bar.foreground
|
||||
font.family: root.bar.fontFamily
|
||||
font.pixelSize: Style.font.body
|
||||
font.bold: true
|
||||
}
|
||||
|
||||
DetailStat {
|
||||
title: "CPU"
|
||||
value: Math.round(root.cpuPercent) + "%"
|
||||
history: root.cpuHistory
|
||||
barFg: root.statColor
|
||||
fontFamily: root.bar.fontFamily
|
||||
width: parent.width
|
||||
}
|
||||
|
||||
DetailStat {
|
||||
title: "Memory"
|
||||
value: Math.round(root.memPercent) + "%"
|
||||
history: root.memHistory
|
||||
barFg: root.statColor
|
||||
fontFamily: root.bar.fontFamily
|
||||
width: parent.width
|
||||
}
|
||||
|
||||
Row {
|
||||
width: parent.width
|
||||
spacing: Style.space(6)
|
||||
Text {
|
||||
text: "Load"
|
||||
color: Qt.darker(root.bar.foreground, 1.5)
|
||||
font.family: root.bar.fontFamily
|
||||
font.pixelSize: Style.font.bodySmall
|
||||
}
|
||||
Text {
|
||||
text: root.loadAvg.toFixed(2)
|
||||
color: root.bar.foreground
|
||||
font.family: root.bar.fontFamily
|
||||
font.pixelSize: Style.font.bodySmall
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
component DetailStat: Column {
|
||||
id: detail
|
||||
|
||||
property string title: ""
|
||||
property string value: ""
|
||||
property var history: []
|
||||
property color barFg: Color.foreground
|
||||
property string fontFamily: Style.font.family
|
||||
|
||||
spacing: Style.space(4)
|
||||
|
||||
Row {
|
||||
width: parent.width
|
||||
Text {
|
||||
text: detail.title
|
||||
color: Qt.darker(detail.barFg, 1.4)
|
||||
font.family: detail.fontFamily
|
||||
font.pixelSize: Style.font.bodySmall
|
||||
}
|
||||
Item { width: detail.width - parent.children[0].implicitWidth - parent.children[2].implicitWidth; height: 1 }
|
||||
Text {
|
||||
text: detail.value
|
||||
color: detail.barFg
|
||||
font.family: detail.fontFamily
|
||||
font.pixelSize: Style.font.bodySmall
|
||||
}
|
||||
}
|
||||
|
||||
Canvas {
|
||||
id: detailCanvas
|
||||
width: parent.width
|
||||
height: Style.space(40)
|
||||
property var history: detail.history
|
||||
onHistoryChanged: requestPaint()
|
||||
|
||||
onPaint: {
|
||||
var ctx = getContext("2d")
|
||||
ctx.clearRect(0, 0, width, height)
|
||||
if (!detail.history || detail.history.length === 0) return
|
||||
|
||||
ctx.strokeStyle = detail.barFg
|
||||
ctx.fillStyle = Qt.rgba(detail.barFg.r, detail.barFg.g, detail.barFg.b, 0.25)
|
||||
ctx.lineWidth = 1.5
|
||||
|
||||
ctx.beginPath()
|
||||
var step = width / Math.max(1, detail.history.length - 1)
|
||||
for (var i = 0; i < detail.history.length; i++) {
|
||||
var x = i * step
|
||||
var y = height - (detail.history[i] / 100) * (height - 2) - 1
|
||||
if (i === 0) ctx.moveTo(x, y)
|
||||
else ctx.lineTo(x, y)
|
||||
}
|
||||
ctx.stroke()
|
||||
ctx.lineTo(width, height)
|
||||
ctx.lineTo(0, height)
|
||||
ctx.closePath()
|
||||
ctx.fill()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user