import QtQuick import "../services" as S Column { id: root required property color accentColor property bool active: true function _fmt(gb) { return gb >= 10 ? gb.toFixed(1) + "G" : gb.toFixed(2) + "G"; } // Header - vendor + usage% Item { width: parent.width height: 28 Text { anchors.left: parent.left anchors.leftMargin: 12 anchors.verticalCenter: parent.verticalCenter text: S.SystemStats.gpuVendor.toUpperCase() color: S.Theme.base03 font.pixelSize: S.Theme.fontSize - 3 font.family: S.Theme.fontFamily font.letterSpacing: 1 } Text { anchors.right: parent.right anchors.rightMargin: 12 anchors.verticalCenter: parent.verticalCenter text: S.SystemStats.gpuUsage + "%" color: S.Theme.loadColor(S.SystemStats.gpuUsage) font.pixelSize: S.Theme.fontSize font.family: S.Theme.fontFamily font.bold: true } } // Usage bar Item { width: parent.width height: 14 Item { anchors.left: parent.left anchors.leftMargin: 12 anchors.right: parent.right anchors.rightMargin: 12 anchors.verticalCenter: parent.verticalCenter height: 6 Rectangle { anchors.fill: parent color: S.Theme.base02 radius: 3 } Rectangle { width: parent.width * Math.min(1, S.SystemStats.gpuUsage / 100) height: parent.height color: S.Theme.loadColor(S.SystemStats.gpuUsage) radius: 3 Behavior on width { enabled: root.active NumberAnimation { duration: 200 easing.type: Easing.OutCubic } } } } } // Usage history sparkline Canvas { id: _sparkline anchors.left: parent.left anchors.leftMargin: 12 anchors.right: parent.right anchors.rightMargin: 12 height: 36 property var _hist: S.SystemStats.gpuHistory on_HistChanged: if (root.active) requestPaint() onVisibleChanged: if (visible) requestPaint() onPaint: { const ctx = getContext("2d"); if (!ctx) return; ctx.clearRect(0, 0, width, height); const d = _hist; if (!d.length) return; const maxSamples = 60; const bw = width / maxSamples; const offset = maxSamples - d.length; for (let i = 0; i < d.length; i++) { const barH = Math.max(1, height * d[i] / 100); const col = S.Theme.loadColor(d[i]); ctx.fillStyle = col.toString(); ctx.fillRect((offset + i) * bw, height - barH, Math.max(1, bw - 0.5), barH); } } } // VRAM section Rectangle { width: parent.width - 16 height: 1 anchors.horizontalCenter: parent.horizontalCenter color: S.Theme.base03 } Item { width: parent.width height: 22 Text { anchors.left: parent.left anchors.leftMargin: 12 anchors.verticalCenter: parent.verticalCenter text: "VRAM" color: S.Theme.base03 font.pixelSize: S.Theme.fontSize - 3 font.family: S.Theme.fontFamily font.letterSpacing: 1 } Text { anchors.right: parent.right anchors.rightMargin: 12 anchors.verticalCenter: parent.verticalCenter text: root._fmt(S.SystemStats.gpuVramUsedGb) + " / " + root._fmt(S.SystemStats.gpuVramTotalGb) color: root.accentColor font.pixelSize: S.Theme.fontSize - 1 font.family: S.Theme.fontFamily font.bold: true } } Item { width: parent.width height: 12 Item { anchors.left: parent.left anchors.leftMargin: 12 anchors.right: parent.right anchors.rightMargin: 12 anchors.verticalCenter: parent.verticalCenter height: 5 Rectangle { anchors.fill: parent color: S.Theme.base02 radius: 2 } Rectangle { width: S.SystemStats.gpuVramTotalGb > 0 ? parent.width * Math.min(1, S.SystemStats.gpuVramUsedGb / S.SystemStats.gpuVramTotalGb) : 0 height: parent.height color: root.accentColor radius: 2 Behavior on width { enabled: root.active NumberAnimation { duration: 200 easing.type: Easing.OutCubic } } } } } // Temperature row Item { width: parent.width height: 22 visible: S.SystemStats.gpuTempC > 0 Text { anchors.left: parent.left anchors.leftMargin: 12 anchors.verticalCenter: parent.verticalCenter text: "Temp" color: S.Theme.base04 font.pixelSize: S.Theme.fontSize - 2 font.family: S.Theme.fontFamily } Text { anchors.right: parent.right anchors.rightMargin: 12 anchors.verticalCenter: parent.verticalCenter text: S.SystemStats.gpuTempC + "\u00B0C" color: S.SystemStats.gpuTempC > 85 ? S.Theme.base08 : S.SystemStats.gpuTempC > 70 ? S.Theme.base0A : S.Theme.base05 font.pixelSize: S.Theme.fontSize - 2 font.family: S.Theme.fontFamily } } Item { width: 1 height: 4 } }