summaryrefslogtreecommitdiff
path: root/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Modules/BuiltinDesktopPlugins
diff options
context:
space:
mode:
authorAlexanderCurl <alexc@alexc.hu>2026-04-18 17:46:06 +0100
committerAlexanderCurl <alexc@alexc.hu>2026-04-18 17:46:06 +0100
commit70ca3fef77ee8bdc6e3ac28589a6fa08c024cc69 (patch)
treeab1123d4067c1b086dd6faa7ee4ea643236b565a /raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Modules/BuiltinDesktopPlugins
parent5d94c0a7d44a2255b81815a52a7056a94a39842d (diff)
downloadRaveOS-PKGBUILD-70ca3fef77ee8bdc6e3ac28589a6fa08c024cc69.tar.gz
RaveOS-PKGBUILD-70ca3fef77ee8bdc6e3ac28589a6fa08c024cc69.zip
Replaced file structures for themes in the correct format
Diffstat (limited to 'raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Modules/BuiltinDesktopPlugins')
-rw-r--r--raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Modules/BuiltinDesktopPlugins/DesktopClockWidget.qml547
-rw-r--r--raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Modules/BuiltinDesktopPlugins/OrganicBlobHourBulges.qml137
-rw-r--r--raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Modules/BuiltinDesktopPlugins/SystemMonitorWidget.qml743
3 files changed, 1427 insertions, 0 deletions
diff --git a/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Modules/BuiltinDesktopPlugins/DesktopClockWidget.qml b/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Modules/BuiltinDesktopPlugins/DesktopClockWidget.qml
new file mode 100644
index 0000000..dc2ea24
--- /dev/null
+++ b/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Modules/BuiltinDesktopPlugins/DesktopClockWidget.qml
@@ -0,0 +1,547 @@
+import QtQuick
+import Quickshell
+import qs.Common
+import qs.Widgets
+
+Item {
+ id: root
+
+ property real widgetWidth: 280
+ property real widgetHeight: 200
+
+ property string instanceId: ""
+ property var instanceData: null
+ readonly property var cfg: instanceData?.config ?? null
+ readonly property bool isInstance: instanceId !== "" && cfg !== null
+
+ property string clockStyle: isInstance ? (cfg.style ?? "analog") : SettingsData.desktopClockStyle
+ property bool forceSquare: clockStyle === "analog"
+
+ property real defaultWidth: {
+ switch (clockStyle) {
+ case "analog":
+ return 200;
+ case "stacked":
+ return 100;
+ default:
+ return 160;
+ }
+ }
+ property real defaultHeight: {
+ switch (clockStyle) {
+ case "analog":
+ return 200;
+ case "stacked":
+ return 160;
+ default:
+ return 70;
+ }
+ }
+ property real minWidth: {
+ switch (clockStyle) {
+ case "analog":
+ return 120;
+ case "stacked":
+ return 70;
+ default:
+ return 100;
+ }
+ }
+ property real minHeight: {
+ switch (clockStyle) {
+ case "analog":
+ return 120;
+ case "stacked":
+ return 100;
+ default:
+ return 45;
+ }
+ }
+
+ property bool enabled: isInstance ? (instanceData?.enabled ?? true) : SettingsData.desktopClockEnabled
+ property real transparency: isInstance ? (cfg.transparency ?? 0.8) : SettingsData.desktopClockTransparency
+ property string colorMode: isInstance ? (cfg.colorMode ?? "primary") : SettingsData.desktopClockColorMode
+ property color customColor: isInstance ? (cfg.customColor ?? "#ffffff") : SettingsData.desktopClockCustomColor
+ property bool showDate: isInstance ? (cfg.showDate ?? true) : SettingsData.desktopClockShowDate
+ property bool showAnalogNumbers: isInstance ? (cfg.showAnalogNumbers ?? false) : SettingsData.desktopClockShowAnalogNumbers
+
+ readonly property real scaleFactor: Math.min(width, height) / 200
+
+ readonly property color accentColor: {
+ if (colorMode === "primary")
+ return Theme.primary;
+ if (colorMode === "secondary")
+ return Theme.secondary;
+ if (colorMode === "custom")
+ return customColor;
+ return Theme.primary;
+ }
+
+ readonly property color handColor: accentColor
+ readonly property color handColorDim: Theme.withAlpha(accentColor, 0.65)
+ readonly property color textColor: Theme.onSurface
+ readonly property color subtleTextColor: Theme.onSurfaceVariant
+ readonly property color backgroundColor: Theme.withAlpha(Theme.surface, root.transparency)
+
+ readonly property bool showAnalogSeconds: isInstance ? (cfg.showAnalogSeconds ?? true) : SettingsData.desktopClockShowAnalogSeconds
+ readonly property bool showDigitalSeconds: isInstance ? (cfg.showDigitalSeconds ?? false) : false
+ readonly property bool needsSeconds: clockStyle === "analog" ? showAnalogSeconds : showDigitalSeconds
+
+ SystemClock {
+ id: systemClock
+ precision: root.needsSeconds ? SystemClock.Seconds : SystemClock.Minutes
+ }
+
+ Rectangle {
+ anchors.fill: parent
+ radius: Theme.cornerRadius
+ color: root.backgroundColor
+ visible: root.clockStyle !== "analog"
+ }
+
+ OrganicBlobHourBulges {
+ anchors.fill: parent
+ fillColor: root.backgroundColor
+ visible: root.clockStyle === "analog"
+ lobes: 12
+ rotationDeg: -90
+ lobeAmount: 0.075
+ hillPower: 0.92
+ roundness: 0.22
+ paddingFrac: 0.02
+ segments: 144
+ }
+
+ Loader {
+ anchors.fill: parent
+ anchors.margins: Theme.spacingM
+ sourceComponent: {
+ if (root.clockStyle === "analog")
+ return analogClock;
+ if (root.clockStyle === "stacked")
+ return stackedClock;
+ return digitalClock;
+ }
+ }
+
+ Component {
+ id: analogClock
+
+ Item {
+ id: analogRoot
+
+ property real clockSize: Math.min(width, height)
+ property real centerX: width / 2
+ property real centerY: height / 2
+ property real faceRadius: clockSize / 2 - 12
+
+ property int hours: systemClock.date?.getHours() % 12 ?? 0
+ property int minutes: systemClock.date?.getMinutes() ?? 0
+ property int seconds: systemClock.date?.getSeconds() ?? 0
+
+ Repeater {
+ model: root.showAnalogNumbers ? 12 : 0
+
+ StyledText {
+ required property int index
+ property real angle: (index + 1) * 30 * Math.PI / 180
+ property real numRadius: analogRoot.faceRadius + 10
+
+ x: analogRoot.centerX + numRadius * Math.sin(angle) - width / 2
+ y: analogRoot.centerY - numRadius * Math.cos(angle) - height / 2
+ text: index + 1
+ font.pixelSize: Theme.fontSizeSmall
+ font.weight: Font.Medium
+ color: root.accentColor
+ }
+ }
+
+ Rectangle {
+ id: hourHand
+ property real angle: (analogRoot.hours + analogRoot.minutes / 60) * 30
+ property real handWidth: Math.max(8, 12 * root.scaleFactor)
+ property real mainLength: analogRoot.faceRadius * 0.55
+ property real tailLength: handWidth * 0.5
+
+ x: analogRoot.centerX - width / 2
+ y: analogRoot.centerY - mainLength
+ width: handWidth
+ height: mainLength + tailLength
+ radius: width / 2
+ color: root.handColor
+ antialiasing: true
+
+ transform: Rotation {
+ origin.x: hourHand.width / 2
+ origin.y: hourHand.mainLength
+ angle: hourHand.angle
+ }
+ }
+
+ Rectangle {
+ id: minuteHand
+ property real angle: (analogRoot.minutes + analogRoot.seconds / 60) * 6
+ property real mainLength: analogRoot.faceRadius * 0.75
+ property real tailLength: hourHand.handWidth * 0.5
+
+ x: analogRoot.centerX - width / 2
+ y: analogRoot.centerY - mainLength
+ width: hourHand.handWidth
+ height: mainLength + tailLength
+ radius: width / 2
+ color: root.handColorDim
+ antialiasing: true
+
+ transform: Rotation {
+ origin.x: minuteHand.width / 2
+ origin.y: minuteHand.mainLength
+ angle: minuteHand.angle
+ }
+ }
+
+ Rectangle {
+ id: secondDot
+ visible: root.showAnalogSeconds
+
+ property real angle: analogRoot.seconds * 6 * Math.PI / 180
+ property real orbitRadius: analogRoot.faceRadius * 0.92
+
+ x: analogRoot.centerX + orbitRadius * Math.sin(angle) - width / 2
+ y: analogRoot.centerY - orbitRadius * Math.cos(angle) - height / 2
+ width: Math.max(10, analogRoot.clockSize * 0.07)
+ height: width
+ radius: width / 2
+ color: root.accentColor
+
+ Behavior on x {
+ NumberAnimation {
+ duration: Theme.shortDuration
+ easing.type: Theme.standardEasing
+ }
+ }
+ Behavior on y {
+ NumberAnimation {
+ duration: Theme.shortDuration
+ easing.type: Theme.standardEasing
+ }
+ }
+ }
+
+ StyledText {
+ id: dateText
+ visible: root.showDate
+
+ property real hourAngle: (analogRoot.hours + analogRoot.minutes / 60) * 30
+ property real minuteAngle: analogRoot.minutes * 6
+
+ property string bestPosition: {
+ const hRad = hourAngle * Math.PI / 180;
+ const mRad = minuteAngle * Math.PI / 180;
+
+ const topWeight = Math.max(0, Math.cos(hRad)) + Math.max(0, Math.cos(mRad));
+ const bottomWeight = Math.max(0, -Math.cos(hRad)) + Math.max(0, -Math.cos(mRad));
+ const rightWeight = Math.max(0, Math.sin(hRad)) + Math.max(0, Math.sin(mRad));
+ const leftWeight = Math.max(0, -Math.sin(hRad)) + Math.max(0, -Math.sin(mRad));
+
+ const minWeight = Math.min(topWeight, bottomWeight, leftWeight, rightWeight);
+
+ if (minWeight === bottomWeight)
+ return "bottom";
+ if (minWeight === topWeight)
+ return "top";
+ if (minWeight === rightWeight)
+ return "right";
+ return "left";
+ }
+
+ x: {
+ if (bestPosition === "left")
+ return analogRoot.centerX - analogRoot.faceRadius * 0.5 - width / 2;
+ if (bestPosition === "right")
+ return analogRoot.centerX + analogRoot.faceRadius * 0.5 - width / 2;
+ return analogRoot.centerX - width / 2;
+ }
+ y: {
+ if (bestPosition === "top")
+ return analogRoot.centerY - analogRoot.faceRadius * 0.5 - height / 2;
+ if (bestPosition === "bottom")
+ return analogRoot.centerY + analogRoot.faceRadius * 0.5 - height / 2;
+ return analogRoot.centerY - height / 2;
+ }
+
+ text: {
+ if (SettingsData.clockDateFormat && SettingsData.clockDateFormat.length > 0)
+ return systemClock.date?.toLocaleDateString(I18n.locale(), SettingsData.clockDateFormat) ?? "";
+ return systemClock.date?.toLocaleDateString(I18n.locale(), "ddd, MMM d") ?? "";
+ }
+ font.pixelSize: Theme.fontSizeSmall
+ color: root.accentColor
+
+ Behavior on x {
+ NumberAnimation {
+ duration: Theme.mediumDuration
+ easing.type: Theme.emphasizedEasing
+ }
+ }
+ Behavior on y {
+ NumberAnimation {
+ duration: Theme.mediumDuration
+ easing.type: Theme.emphasizedEasing
+ }
+ }
+ }
+ }
+ }
+
+ Component {
+ id: digitalClock
+
+ Item {
+ id: digitalRoot
+
+ property bool hasDate: root.showDate
+ property bool hasAmPm: !SettingsData.use24HourClock
+ property real verticalScale: hasDate && hasAmPm ? 0.55 : (hasDate || hasAmPm ? 0.65 : 0.8)
+ property real baseSize: Math.min(height * verticalScale, width * 0.22)
+ property real digitWidth: baseSize * 0.62
+ property real smallSize: baseSize * 0.35
+
+ property string hoursStr: {
+ const hours = SettingsData.use24HourClock ? systemClock.date?.getHours() ?? 0 : ((systemClock.date?.getHours() ?? 0) % 12 || 12);
+ if (SettingsData.use24HourClock || SettingsData.padHours12Hour)
+ return String(hours).padStart(2, '0');
+ return String(hours);
+ }
+ property string minutesStr: String(systemClock.date?.getMinutes() ?? 0).padStart(2, '0')
+ property string secondsStr: String(systemClock.date?.getSeconds() ?? 0).padStart(2, '0')
+
+ Column {
+ anchors.centerIn: parent
+ spacing: 0
+
+ StyledText {
+ visible: root.showDate
+ anchors.horizontalCenter: parent.horizontalCenter
+ text: {
+ if (SettingsData.clockDateFormat && SettingsData.clockDateFormat.length > 0)
+ return systemClock.date?.toLocaleDateString(I18n.locale(), SettingsData.clockDateFormat) ?? "";
+ return systemClock.date?.toLocaleDateString(I18n.locale(), "ddd, MMM d") ?? "";
+ }
+ font.pixelSize: digitalRoot.smallSize
+ color: Theme.withAlpha(root.accentColor, 0.7)
+ }
+
+ Row {
+ anchors.horizontalCenter: parent.horizontalCenter
+ spacing: 0
+
+ StyledText {
+ visible: digitalRoot.hoursStr.length > 1
+ width: digitalRoot.digitWidth
+ text: digitalRoot.hoursStr.charAt(0)
+ font.pixelSize: digitalRoot.baseSize
+ font.weight: Font.Medium
+ color: root.accentColor
+ horizontalAlignment: Text.AlignHCenter
+ }
+ StyledText {
+ width: digitalRoot.digitWidth
+ text: digitalRoot.hoursStr.length > 1 ? digitalRoot.hoursStr.charAt(1) : digitalRoot.hoursStr.charAt(0)
+ font.pixelSize: digitalRoot.baseSize
+ font.weight: Font.Medium
+ color: root.accentColor
+ horizontalAlignment: Text.AlignHCenter
+ }
+ StyledText {
+ text: ":"
+ font.pixelSize: digitalRoot.baseSize
+ font.weight: Font.Medium
+ color: root.accentColor
+ }
+ StyledText {
+ width: digitalRoot.digitWidth
+ text: digitalRoot.minutesStr.charAt(0)
+ font.pixelSize: digitalRoot.baseSize
+ font.weight: Font.Medium
+ color: root.accentColor
+ horizontalAlignment: Text.AlignHCenter
+ }
+ StyledText {
+ width: digitalRoot.digitWidth
+ text: digitalRoot.minutesStr.charAt(1)
+ font.pixelSize: digitalRoot.baseSize
+ font.weight: Font.Medium
+ color: root.accentColor
+ horizontalAlignment: Text.AlignHCenter
+ }
+ StyledText {
+ visible: root.showDigitalSeconds
+ text: ":"
+ font.pixelSize: digitalRoot.baseSize
+ font.weight: Font.Medium
+ color: Theme.withAlpha(root.accentColor, 0.7)
+ }
+ StyledText {
+ visible: root.showDigitalSeconds
+ width: digitalRoot.digitWidth
+ text: digitalRoot.secondsStr.charAt(0)
+ font.pixelSize: digitalRoot.baseSize
+ font.weight: Font.Medium
+ color: Theme.withAlpha(root.accentColor, 0.7)
+ horizontalAlignment: Text.AlignHCenter
+ }
+ StyledText {
+ visible: root.showDigitalSeconds
+ width: digitalRoot.digitWidth
+ text: digitalRoot.secondsStr.charAt(1)
+ font.pixelSize: digitalRoot.baseSize
+ font.weight: Font.Medium
+ color: Theme.withAlpha(root.accentColor, 0.7)
+ horizontalAlignment: Text.AlignHCenter
+ }
+ }
+
+ StyledText {
+ visible: !SettingsData.use24HourClock
+ anchors.horizontalCenter: parent.horizontalCenter
+ text: (systemClock.date?.getHours() ?? 0) >= 12 ? "PM" : "AM"
+ font.pixelSize: digitalRoot.smallSize
+ font.weight: Font.Medium
+ color: Theme.withAlpha(root.accentColor, 0.7)
+ }
+ }
+ }
+ }
+
+ Component {
+ id: stackedClock
+
+ Item {
+ id: stackedRoot
+
+ property bool hasSeconds: root.showDigitalSeconds
+ property bool hasDate: root.showDate
+ property bool hasAmPm: !SettingsData.use24HourClock
+ property real extraContent: (hasSeconds ? 0.12 : 0) + (hasDate ? 0.08 : 0) + (hasAmPm ? 0.08 : 0)
+ property real baseSize: height * (0.42 - extraContent * 0.5)
+ property real digitWidth: baseSize * 0.58
+ property real smallSize: baseSize * 0.5
+ property real rowSpacing: -baseSize * 0.17
+
+ Column {
+ anchors.centerIn: parent
+ spacing: 0
+
+ Column {
+ spacing: stackedRoot.rowSpacing
+ anchors.horizontalCenter: parent.horizontalCenter
+
+ Row {
+ spacing: 0
+ anchors.horizontalCenter: parent.horizontalCenter
+
+ StyledText {
+ text: {
+ if (SettingsData.use24HourClock)
+ return String(systemClock.date?.getHours() ?? 0).padStart(2, '0').charAt(0);
+ const hours = systemClock.date?.getHours() ?? 0;
+ const display = hours === 0 ? 12 : hours > 12 ? hours - 12 : hours;
+ return String(display).padStart(2, '0').charAt(0);
+ }
+ font.pixelSize: stackedRoot.baseSize
+ font.weight: Font.Medium
+ color: root.accentColor
+ width: stackedRoot.digitWidth
+ horizontalAlignment: Text.AlignHCenter
+ }
+
+ StyledText {
+ text: {
+ if (SettingsData.use24HourClock)
+ return String(systemClock.date?.getHours() ?? 0).padStart(2, '0').charAt(1);
+ const hours = systemClock.date?.getHours() ?? 0;
+ const display = hours === 0 ? 12 : hours > 12 ? hours - 12 : hours;
+ return String(display).padStart(2, '0').charAt(1);
+ }
+ font.pixelSize: stackedRoot.baseSize
+ font.weight: Font.Medium
+ color: root.accentColor
+ width: stackedRoot.digitWidth
+ horizontalAlignment: Text.AlignHCenter
+ }
+ }
+
+ Row {
+ spacing: 0
+ anchors.horizontalCenter: parent.horizontalCenter
+
+ StyledText {
+ text: String(systemClock.date?.getMinutes() ?? 0).padStart(2, '0').charAt(0)
+ font.pixelSize: stackedRoot.baseSize
+ font.weight: Font.Medium
+ color: root.accentColor
+ width: stackedRoot.digitWidth
+ horizontalAlignment: Text.AlignHCenter
+ }
+
+ StyledText {
+ text: String(systemClock.date?.getMinutes() ?? 0).padStart(2, '0').charAt(1)
+ font.pixelSize: stackedRoot.baseSize
+ font.weight: Font.Medium
+ color: root.accentColor
+ width: stackedRoot.digitWidth
+ horizontalAlignment: Text.AlignHCenter
+ }
+ }
+ }
+
+ Row {
+ visible: stackedRoot.hasSeconds
+ spacing: 0
+ anchors.horizontalCenter: parent.horizontalCenter
+
+ StyledText {
+ text: String(systemClock.date?.getSeconds() ?? 0).padStart(2, '0').charAt(0)
+ font.pixelSize: stackedRoot.smallSize
+ font.weight: Font.Medium
+ color: Theme.withAlpha(root.accentColor, 0.7)
+ width: stackedRoot.smallSize * 0.58
+ horizontalAlignment: Text.AlignHCenter
+ }
+
+ StyledText {
+ text: String(systemClock.date?.getSeconds() ?? 0).padStart(2, '0').charAt(1)
+ font.pixelSize: stackedRoot.smallSize
+ font.weight: Font.Medium
+ color: Theme.withAlpha(root.accentColor, 0.7)
+ width: stackedRoot.smallSize * 0.58
+ horizontalAlignment: Text.AlignHCenter
+ }
+ }
+
+ Item {
+ width: 1
+ height: stackedRoot.baseSize * 0.1
+ visible: stackedRoot.hasDate
+ }
+
+ StyledText {
+ visible: stackedRoot.hasDate
+ anchors.horizontalCenter: parent.horizontalCenter
+ text: systemClock.date?.toLocaleDateString(I18n.locale(), "MMM dd") ?? ""
+ font.pixelSize: stackedRoot.smallSize * 0.7
+ color: Theme.withAlpha(root.accentColor, 0.7)
+ }
+
+ StyledText {
+ visible: stackedRoot.hasAmPm
+ anchors.horizontalCenter: parent.horizontalCenter
+ text: (systemClock.date?.getHours() ?? 0) >= 12 ? "PM" : "AM"
+ font.pixelSize: stackedRoot.smallSize * 0.7
+ font.weight: Font.Medium
+ color: Theme.withAlpha(root.accentColor, 0.7)
+ }
+ }
+ }
+ }
+}
diff --git a/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Modules/BuiltinDesktopPlugins/OrganicBlobHourBulges.qml b/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Modules/BuiltinDesktopPlugins/OrganicBlobHourBulges.qml
new file mode 100644
index 0000000..cced1a4
--- /dev/null
+++ b/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Modules/BuiltinDesktopPlugins/OrganicBlobHourBulges.qml
@@ -0,0 +1,137 @@
+import QtQuick
+import QtQuick.Shapes
+
+Item {
+ id: root
+
+ property color fillColor: "transparent"
+
+ property int lobes: 12
+ property real lobeAmount: 0.070
+ property real roundness: 0.22
+ property real hillPower: 0.78
+ property real paddingFrac: 0.020
+ property real inset: 0
+ property int segments: 120
+ property real rotationDeg: -90
+
+ layer.enabled: true
+ layer.samples: 4
+
+ function sgn(v) {
+ return v < 0 ? -1 : 1;
+ }
+ function clamp(v, a, b) {
+ return Math.max(a, Math.min(b, v));
+ }
+
+ function squircleMap(u, v, p) {
+ const ax = sgn(u) * Math.pow(Math.abs(u), p);
+ const ay = sgn(v) * Math.pow(Math.abs(v), p);
+ return {
+ x: ax,
+ y: ay
+ };
+ }
+
+ function buildPathD(w, h) {
+ const x0 = inset, y0 = inset;
+ const x1 = w - inset, y1 = h - inset;
+ const iw = Math.max(2, x1 - x0);
+ const ih = Math.max(2, y1 - y0);
+
+ const cx = x0 + iw * 0.5;
+ const cy = y0 + ih * 0.5;
+
+ const rx = iw * 0.5;
+ const ry = ih * 0.5;
+ const rMin = Math.min(rx, ry);
+
+ const amp = clamp(lobeAmount, 0.0, 0.14) * rMin;
+ const extraPad = paddingFrac * rMin + 1.5;
+ const pad = amp + extraPad;
+
+ const rxBase = Math.max(2, rx - pad);
+ const ryBase = Math.max(2, ry - pad);
+
+ const blend = clamp(roundness, 0.0, 0.45);
+ const squirclePow = 1.0 + blend * 2.8;
+
+ const N = Math.max(48, segments);
+ const rot = rotationDeg * Math.PI / 180.0;
+ const dt = (Math.PI * 2.0) / N;
+
+ function hillWave(a) {
+ const t = (Math.cos(lobes * a) + 1.0) * 0.5;
+ return Math.pow(t, hillPower);
+ }
+
+ function P(t) {
+ const a = t + rot;
+ const u = Math.cos(a);
+ const v = Math.sin(a);
+
+ const m = 1.0 + (amp / rMin) * hillWave(a);
+
+ const ex = u * rxBase * m;
+ const ey = v * ryBase * m;
+
+ const sm = squircleMap(u, v, 1.0 / squirclePow);
+ const sx = sm.x * rxBase * m;
+ const sy = sm.y * ryBase * m;
+
+ const x = ex * (1.0 - blend) + sx * blend;
+ const y = ey * (1.0 - blend) + sy * blend;
+ return {
+ x: cx + x,
+ y: cy + y
+ };
+ }
+
+ function dP(t) {
+ const eps = dt * 0.25;
+ const p1 = P(t - eps);
+ const p2 = P(t + eps);
+ return {
+ x: (p2.x - p1.x) / (2 * eps),
+ y: (p2.y - p1.y) / (2 * eps)
+ };
+ }
+
+ const p0 = P(0.0);
+ let d = `M ${p0.x.toFixed(2)} ${p0.y.toFixed(2)} `;
+
+ for (let i = 0; i < N; i++) {
+ const tA = i * dt;
+ const tB = (i + 1) * dt;
+
+ const A = P(tA);
+ const B = P(tB);
+ const dA = dP(tA);
+ const dB = dP(tB);
+
+ const c1x = A.x + (dt / 3.0) * dA.x;
+ const c1y = A.y + (dt / 3.0) * dA.y;
+ const c2x = B.x - (dt / 3.0) * dB.x;
+ const c2y = B.y - (dt / 3.0) * dB.y;
+
+ d += `C ${c1x.toFixed(2)} ${c1y.toFixed(2)}, ${c2x.toFixed(2)} ${c2y.toFixed(2)}, ${B.x.toFixed(2)} ${B.y.toFixed(2)} `;
+ }
+
+ d += "Z";
+ return d;
+ }
+
+ Shape {
+ anchors.fill: parent
+
+ ShapePath {
+ fillColor: root.fillColor
+ strokeColor: "transparent"
+
+ PathSvg {
+ path: root.buildPathD(root.width, root.height)
+ }
+ }
+ }
+}
diff --git a/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Modules/BuiltinDesktopPlugins/SystemMonitorWidget.qml b/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Modules/BuiltinDesktopPlugins/SystemMonitorWidget.qml
new file mode 100644
index 0000000..515e74e
--- /dev/null
+++ b/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Modules/BuiltinDesktopPlugins/SystemMonitorWidget.qml
@@ -0,0 +1,743 @@
+import QtQuick
+import QtQuick.Layouts
+import Quickshell
+import qs.Common
+import qs.Services
+import qs.Widgets
+
+Item {
+ id: root
+
+ property real widgetWidth: 320
+ property real widgetHeight: 480
+ property real defaultWidth: 320
+ property real defaultHeight: 480
+ property real minWidth: {
+ const tileCount = enabledTiles.length;
+ if (tileCount === 0)
+ return 80;
+ if (tileCount === 1)
+ return 100;
+ return 160;
+ }
+ property real minHeight: {
+ const tileCount = enabledTiles.length;
+ if (tileCount === 0)
+ return 60;
+ if (tileCount === 1)
+ return 80;
+ if (tileCount <= 2)
+ return 120;
+ return 180;
+ }
+
+ property string instanceId: ""
+ property var instanceData: null
+
+ readonly property var cfg: instanceData?.config ?? null
+ readonly property bool isInstance: instanceId !== "" && cfg !== null
+
+ property bool enabled: isInstance ? (instanceData?.enabled ?? true) : SettingsData.systemMonitorEnabled
+ property bool showHeader: isInstance ? (cfg.showHeader ?? true) : SettingsData.systemMonitorShowHeader
+ property real transparency: isInstance ? (cfg.transparency ?? 0.8) : SettingsData.systemMonitorTransparency
+ property string colorMode: isInstance ? (cfg.colorMode ?? "primary") : SettingsData.systemMonitorColorMode
+ property color customColor: isInstance ? (cfg.customColor ?? "#ffffff") : SettingsData.systemMonitorCustomColor
+ property bool showCpu: isInstance ? (cfg.showCpu ?? true) : SettingsData.systemMonitorShowCpu
+ property bool showCpuGraph: isInstance ? (cfg.showCpuGraph ?? true) : SettingsData.systemMonitorShowCpuGraph
+ property bool showCpuTemp: isInstance ? (cfg.showCpuTemp ?? true) : SettingsData.systemMonitorShowCpuTemp
+ property bool showGpuTemp: isInstance ? (cfg.showGpuTemp ?? false) : SettingsData.systemMonitorShowGpuTemp
+ property string selectedGpuPciId: isInstance ? (cfg.gpuPciId ?? "") : SettingsData.systemMonitorGpuPciId
+ property bool showMemory: isInstance ? (cfg.showMemory ?? true) : SettingsData.systemMonitorShowMemory
+ property bool showMemoryGraph: isInstance ? (cfg.showMemoryGraph ?? true) : SettingsData.systemMonitorShowMemoryGraph
+ property bool showNetwork: isInstance ? (cfg.showNetwork ?? true) : SettingsData.systemMonitorShowNetwork
+ property bool showNetworkGraph: isInstance ? (cfg.showNetworkGraph ?? true) : SettingsData.systemMonitorShowNetworkGraph
+ property bool showDisk: isInstance ? (cfg.showDisk ?? true) : SettingsData.systemMonitorShowDisk
+ property bool showTopProcesses: isInstance ? (cfg.showTopProcesses ?? false) : SettingsData.systemMonitorShowTopProcesses
+ property int topProcessCount: isInstance ? (cfg.topProcessCount ?? 3) : SettingsData.systemMonitorTopProcessCount
+ property string topProcessSortBy: isInstance ? (cfg.topProcessSortBy ?? "cpu") : SettingsData.systemMonitorTopProcessSortBy
+ property string layoutMode: isInstance ? (cfg.layoutMode ?? "auto") : SettingsData.systemMonitorLayoutMode
+ property int graphInterval: isInstance ? (cfg.graphInterval ?? 60) : SettingsData.systemMonitorGraphInterval
+
+ readonly property color accentColor: {
+ switch (colorMode) {
+ case "secondary":
+ return Theme.secondary;
+ case "custom":
+ return customColor;
+ default:
+ return Theme.primary;
+ }
+ }
+
+ readonly property color bgColor: Theme.withAlpha(Theme.surface, root.transparency)
+ readonly property color tileBg: Theme.withAlpha(Theme.surfaceContainerHigh, root.transparency)
+ readonly property color textColor: Theme.surfaceText
+ readonly property color dimColor: Theme.surfaceVariantText
+
+ property string currentGpuPciIdRef: ""
+ property var activeModuleRefs: []
+
+ property var cpuHistory: []
+ property var memHistory: []
+ property var netRxHistory: []
+ property var netTxHistory: []
+ property var diskReadHistory: []
+ property var diskWriteHistory: []
+ readonly property int historySize: 60
+
+ readonly property int sampleInterval: {
+ switch (graphInterval) {
+ case 60:
+ return 1000;
+ case 300:
+ return 5000;
+ case 600:
+ return 10000;
+ case 900:
+ return 15000;
+ case 1800:
+ return 30000;
+ default:
+ return 1000;
+ }
+ }
+
+ readonly property var enabledTiles: {
+ var tiles = [];
+ if (showCpu)
+ tiles.push("cpu");
+ if (showMemory)
+ tiles.push("mem");
+ if (showNetwork)
+ tiles.push("net");
+ if (showDisk)
+ tiles.push("disk");
+ if (showGpuTemp && selectedGpuPciId)
+ tiles.push("gpu");
+ return tiles;
+ }
+
+ readonly property var sortedProcesses: {
+ if (!showTopProcesses || !DgopService.processes)
+ return [];
+ var procs = DgopService.processes.slice();
+ if (topProcessSortBy === "memory") {
+ procs.sort((a, b) => (b.memoryKB || 0) - (a.memoryKB || 0));
+ } else {
+ procs.sort((a, b) => (b.cpu || 0) - (a.cpu || 0));
+ }
+ return procs.slice(0, topProcessCount);
+ }
+
+ Component.onCompleted: {
+ var modules = ["system"];
+ if (showCpu || showCpuTemp || showCpuGraph)
+ modules.push("cpu");
+ if (showMemory || showMemoryGraph)
+ modules.push("memory");
+ if (showNetwork || showNetworkGraph)
+ modules.push("network");
+ if (showDisk)
+ modules.push("disk", "diskmounts");
+ if (showTopProcesses)
+ modules.push("processes");
+ activeModuleRefs = modules;
+ DgopService.addRef(modules);
+ updateGpuRef();
+ }
+
+ Component.onDestruction: {
+ DgopService.removeRef(activeModuleRefs);
+ if (currentGpuPciIdRef)
+ DgopService.removeGpuPciId(currentGpuPciIdRef);
+ }
+
+ onShowGpuTempChanged: updateGpuRef()
+ onSelectedGpuPciIdChanged: updateGpuRef()
+ onShowTopProcessesChanged: {
+ if (showTopProcesses) {
+ activeModuleRefs = activeModuleRefs.concat(["processes"]);
+ DgopService.addRef(["processes"]);
+ } else {
+ DgopService.removeRef(["processes"]);
+ activeModuleRefs = activeModuleRefs.filter(m => m !== "processes");
+ }
+ }
+
+ function updateGpuRef() {
+ if (currentGpuPciIdRef && currentGpuPciIdRef !== selectedGpuPciId) {
+ DgopService.removeGpuPciId(currentGpuPciIdRef);
+ currentGpuPciIdRef = "";
+ }
+ if (!showGpuTemp || !selectedGpuPciId) {
+ if (currentGpuPciIdRef) {
+ DgopService.removeGpuPciId(currentGpuPciIdRef);
+ currentGpuPciIdRef = "";
+ }
+ return;
+ }
+ if (selectedGpuPciId && !currentGpuPciIdRef) {
+ DgopService.addGpuPciId(selectedGpuPciId);
+ currentGpuPciIdRef = selectedGpuPciId;
+ }
+ }
+
+ function getGpuInfo() {
+ if (!selectedGpuPciId || !DgopService.availableGpus)
+ return null;
+ return DgopService.availableGpus.find(g => g.pciId === selectedGpuPciId);
+ }
+
+ function formatBytes(bytes) {
+ if (bytes < 1024)
+ return bytes.toFixed(0) + "B";
+ if (bytes < 1024 * 1024)
+ return (bytes / 1024).toFixed(0) + "K";
+ if (bytes < 1024 * 1024 * 1024)
+ return (bytes / (1024 * 1024)).toFixed(1) + "M";
+ return (bytes / (1024 * 1024 * 1024)).toFixed(1) + "G";
+ }
+
+ function formatMemKB(kb) {
+ if (kb < 1024)
+ return kb.toFixed(0) + "K";
+ if (kb < 1024 * 1024)
+ return (kb / 1024).toFixed(0) + "M";
+ return (kb / (1024 * 1024)).toFixed(1) + "G";
+ }
+
+ function addToHistory(arr, val) {
+ var newArr = arr.slice();
+ newArr.push(val);
+ if (newArr.length > historySize)
+ newArr.shift();
+ return newArr;
+ }
+
+ function sampleData() {
+ if (showCpuGraph)
+ cpuHistory = addToHistory(cpuHistory, DgopService.cpuUsage);
+ if (showMemoryGraph)
+ memHistory = addToHistory(memHistory, DgopService.memoryUsage);
+ if (showNetworkGraph) {
+ netRxHistory = addToHistory(netRxHistory, DgopService.networkRxRate);
+ netTxHistory = addToHistory(netTxHistory, DgopService.networkTxRate);
+ }
+ if (showDisk) {
+ diskReadHistory = addToHistory(diskReadHistory, DgopService.diskReadRate);
+ diskWriteHistory = addToHistory(diskWriteHistory, DgopService.diskWriteRate);
+ }
+ }
+
+ readonly property int sampleSeconds: sampleInterval / 1000
+
+ SystemClock {
+ id: sampleClock
+ precision: SystemClock.Seconds
+ onDateChanged: {
+ var sec = date.getSeconds();
+ if (sec % root.sampleSeconds === 0)
+ root.sampleData();
+ }
+ }
+
+ Rectangle {
+ anchors.fill: parent
+ radius: Theme.cornerRadius
+ color: root.bgColor
+ border.width: 0
+
+ ColumnLayout {
+ anchors.fill: parent
+ anchors.margins: (root.enabledTiles.length === 1 && !root.showHeader) ? 0 : Theme.spacingS
+ spacing: Theme.spacingS
+
+ RowLayout {
+ Layout.fillWidth: true
+ spacing: Theme.spacingS
+ visible: root.showHeader
+
+ ColumnLayout {
+ spacing: 0
+
+ StyledText {
+ text: DgopService.cpuModel || DgopService.hostname || "System"
+ isMonospace: true
+ font.pixelSize: Theme.fontSizeSmall
+ color: root.textColor
+ elide: Text.ElideRight
+ Layout.maximumWidth: root.width - Theme.spacingM * 2
+ }
+
+ StyledText {
+ visible: DgopService.shortUptime && DgopService.shortUptime.length > 0
+ text: DgopService.shortUptime
+ isMonospace: true
+ font.pixelSize: Theme.fontSizeSmall
+ color: root.dimColor
+ }
+ }
+ }
+
+ GridLayout {
+ id: tileGrid
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ columns: {
+ if (root.layoutMode === "list")
+ return 1;
+ if (root.layoutMode === "grid")
+ return 2;
+ // auto
+ if (root.width < 280)
+ return 1;
+ if (root.width < 500)
+ return 2;
+ return 3;
+ }
+ rowSpacing: Theme.spacingXS
+ columnSpacing: Theme.spacingXS
+
+ Repeater {
+ model: root.enabledTiles
+
+ Rectangle {
+ id: tile
+ readonly property int span: Layout.columnSpan
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ Layout.columnSpan: {
+ if (root.layoutMode === "list")
+ return 1;
+
+ var cols = tileGrid.columns;
+ if (cols <= 1)
+ return 1;
+
+ var count = root.enabledTiles.length;
+ var idx = index;
+
+ if (idx !== count - 1)
+ return 1;
+
+ var remainder = count % cols;
+ if (remainder === 0)
+ return 1;
+
+ if (!tile.hasGraph)
+ return 1;
+
+ return cols - remainder + 1;
+ }
+ Layout.minimumHeight: 60
+ radius: Theme.cornerRadius - 2
+ color: root.tileBg
+ border.width: 0
+ clip: true
+
+ readonly property string tileType: modelData
+ readonly property bool hasGraph: {
+ switch (tileType) {
+ case "cpu":
+ return root.showCpuGraph;
+ case "mem":
+ return root.showMemoryGraph;
+ case "net":
+ return root.showNetworkGraph;
+ case "disk":
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ Canvas {
+ id: tileGraph
+ anchors.fill: parent
+ visible: tile.hasGraph
+ renderStrategy: Canvas.Cooperative
+
+ property var hist: {
+ switch (tile.tileType) {
+ case "cpu":
+ return root.cpuHistory;
+ case "mem":
+ return root.memHistory;
+ case "net":
+ return root.netRxHistory;
+ case "disk":
+ return root.diskReadHistory;
+ default:
+ return [];
+ }
+ }
+ property var hist2: {
+ switch (tile.tileType) {
+ case "net":
+ return root.netTxHistory;
+ case "disk":
+ return root.diskWriteHistory;
+ default:
+ return null;
+ }
+ }
+
+ onHistChanged: requestPaint()
+ onHist2Changed: requestPaint()
+ onWidthChanged: requestPaint()
+ onHeightChanged: requestPaint()
+
+ onPaint: {
+ var ctx = getContext("2d");
+ ctx.reset();
+ ctx.clearRect(0, 0, width, height);
+ if (!hist || hist.length < 2)
+ return;
+ var maxVal = 100;
+ if (tile.tileType === "net" || tile.tileType === "disk") {
+ maxVal = 1;
+ for (var k = 0; k < hist.length; k++)
+ maxVal = Math.max(maxVal, hist[k]);
+ if (hist2)
+ for (var l = 0; l < hist2.length; l++)
+ maxVal = Math.max(maxVal, hist2[l]);
+ }
+
+ var c = root.accentColor;
+ var grad = ctx.createLinearGradient(0, 0, 0, height);
+ grad.addColorStop(0, Qt.rgba(c.r, c.g, c.b, 0.3));
+ grad.addColorStop(1, Qt.rgba(c.r, c.g, c.b, 0.05));
+
+ ctx.fillStyle = grad;
+ ctx.beginPath();
+ ctx.moveTo(0, height);
+ for (var i = 0; i < hist.length; i++) {
+ var x = (width / (root.historySize - 1)) * i;
+ var y = height - (hist[i] / maxVal) * height * 0.85;
+ ctx.lineTo(x, y);
+ }
+ ctx.lineTo((width / (root.historySize - 1)) * (hist.length - 1), height);
+ ctx.closePath();
+ ctx.fill();
+
+ ctx.strokeStyle = Qt.rgba(c.r, c.g, c.b, 0.6);
+ ctx.lineWidth = 1.5;
+ ctx.beginPath();
+ for (var j = 0; j < hist.length; j++) {
+ var px = (width / (root.historySize - 1)) * j;
+ var py = height - (hist[j] / maxVal) * height * 0.85;
+ j === 0 ? ctx.moveTo(px, py) : ctx.lineTo(px, py);
+ }
+ ctx.stroke();
+
+ if (hist2 && hist2.length >= 2) {
+ ctx.strokeStyle = Qt.rgba(c.r, c.g, c.b, 0.3);
+ ctx.lineWidth = 1;
+ ctx.beginPath();
+ for (var m = 0; m < hist2.length; m++) {
+ var sx = (width / (root.historySize - 1)) * m;
+ var sy = height - (hist2[m] / maxVal) * height * 0.85;
+ m === 0 ? ctx.moveTo(sx, sy) : ctx.lineTo(sx, sy);
+ }
+ ctx.stroke();
+ }
+ }
+ }
+
+ ColumnLayout {
+ anchors.fill: parent
+ anchors.margins: Theme.spacingS
+ spacing: 2
+
+ RowLayout {
+ Layout.fillWidth: true
+ spacing: Theme.spacingXS
+
+ StyledText {
+ text: tile.tileType.toUpperCase()
+ isMonospace: true
+ font.pixelSize: Theme.fontSizeSmall
+ font.weight: Font.Bold
+ color: root.accentColor
+ }
+
+ Item {
+ Layout.fillWidth: true
+ }
+
+ StyledText {
+ visible: tile.tileType === "cpu" && root.showCpuTemp && DgopService.cpuTemperature > 0
+ text: DgopService.cpuTemperature.toFixed(0) + "°"
+ isMonospace: true
+ font.pixelSize: Theme.fontSizeSmall
+ color: DgopService.cpuTemperature > 80 ? Theme.error : (DgopService.cpuTemperature > 60 ? Theme.warning : root.dimColor)
+ }
+
+ StyledText {
+ visible: tile.tileType === "mem"
+ text: DgopService.formatSystemMemory(DgopService.usedMemoryKB)
+ isMonospace: true
+ font.pixelSize: Theme.fontSizeSmall
+ color: root.dimColor
+ }
+ }
+
+ Item {
+ Layout.fillHeight: true
+ }
+
+ StyledText {
+ visible: tile.tileType === "cpu"
+ text: DgopService.cpuUsage.toFixed(0) + "%"
+ isMonospace: true
+ font.pixelSize: Theme.fontSizeXLarge
+ font.weight: Font.Medium
+ color: root.textColor
+ }
+
+ StyledText {
+ visible: tile.tileType === "mem"
+ text: DgopService.memoryUsage.toFixed(0) + "%"
+ isMonospace: true
+ font.pixelSize: Theme.fontSizeXLarge
+ font.weight: Font.Medium
+ color: root.textColor
+ }
+
+ RowLayout {
+ visible: tile.tileType === "net"
+ spacing: Theme.spacingM
+ ColumnLayout {
+ spacing: 0
+ StyledText {
+ text: "↓"
+ font.pixelSize: Theme.fontSizeSmall
+ color: root.accentColor
+ }
+ StyledText {
+ text: root.formatBytes(DgopService.networkRxRate) + "/s"
+ isMonospace: true
+ font.pixelSize: Theme.fontSizeMedium
+ color: root.textColor
+ }
+ }
+ ColumnLayout {
+ spacing: 0
+ StyledText {
+ text: "↑"
+ font.pixelSize: Theme.fontSizeSmall
+ color: root.dimColor
+ }
+ StyledText {
+ text: root.formatBytes(DgopService.networkTxRate) + "/s"
+ isMonospace: true
+ font.pixelSize: Theme.fontSizeMedium
+ color: root.textColor
+ }
+ }
+ }
+
+ RowLayout {
+ visible: tile.tileType === "disk"
+ spacing: Theme.spacingM
+ ColumnLayout {
+ spacing: 0
+ StyledText {
+ text: "R"
+ font.pixelSize: Theme.fontSizeSmall
+ color: root.accentColor
+ }
+ StyledText {
+ text: root.formatBytes(DgopService.diskReadRate) + "/s"
+ isMonospace: true
+ font.pixelSize: Theme.fontSizeMedium
+ color: root.textColor
+ }
+ }
+ ColumnLayout {
+ spacing: 0
+ StyledText {
+ text: "W"
+ font.pixelSize: Theme.fontSizeSmall
+ color: root.dimColor
+ }
+ StyledText {
+ text: root.formatBytes(DgopService.diskWriteRate) + "/s"
+ isMonospace: true
+ font.pixelSize: Theme.fontSizeMedium
+ color: root.textColor
+ }
+ }
+ }
+
+ ColumnLayout {
+ visible: tile.tileType === "gpu"
+ spacing: 0
+ property var gpu: root.getGpuInfo()
+ Layout.alignment: tile.span > 1 ? Qt.AlignHCenter : Qt.AlignLeft
+
+ StyledText {
+ property real temp: parent.gpu?.temperature ?? 0
+ text: temp > 0 ? temp.toFixed(0) + "°C" : "--"
+ isMonospace: true
+ font.pixelSize: Theme.fontSizeXLarge
+ font.weight: Font.Medium
+ color: root.textColor
+ Layout.alignment: tile.span > 1 ? Qt.AlignHCenter : Qt.AlignLeft
+ }
+ StyledText {
+ text: parent.gpu?.displayName ?? ""
+ isMonospace: true
+ font.pixelSize: Theme.fontSizeSmall
+ color: root.dimColor
+ Layout.fillWidth: true
+ horizontalAlignment: tile.span > 1 ? Text.AlignHCenter : Text.AlignLeft
+ elide: Text.ElideRight
+ }
+ }
+
+ Rectangle {
+ visible: tile.tileType === "cpu" || tile.tileType === "mem"
+ Layout.fillWidth: true
+ height: 4
+ radius: 2
+ color: Theme.withAlpha(Theme.outline, 0.2)
+
+ Rectangle {
+ property real pct: tile.tileType === "cpu" ? DgopService.cpuUsage / 100 : DgopService.memoryUsage / 100
+ width: parent.width * Math.min(1, pct)
+ height: parent.height
+ radius: 2
+ color: pct > 0.8 ? Theme.error : (pct > 0.6 ? Theme.warning : root.accentColor)
+ Behavior on width {
+ NumberAnimation {
+ duration: 150
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ ColumnLayout {
+ Layout.fillWidth: true
+ spacing: Theme.spacingXS
+ visible: root.showTopProcesses && root.sortedProcesses.length > 0
+
+ Rectangle {
+ Layout.fillWidth: true
+ height: 1
+ color: Theme.withAlpha(Theme.outline, 0.15)
+ }
+
+ RowLayout {
+ Layout.fillWidth: true
+ spacing: Theme.spacingXS
+
+ StyledText {
+ text: "TOP BY " + root.topProcessSortBy.toUpperCase()
+ isMonospace: true
+ font.pixelSize: Theme.fontSizeSmall
+ font.weight: Font.Bold
+ color: root.accentColor
+ }
+
+ Item {
+ Layout.fillWidth: true
+ }
+
+ StyledText {
+ text: root.topProcessSortBy === "cpu" ? "CPU" : "MEM"
+ isMonospace: true
+ font.pixelSize: Theme.fontSizeSmall
+ color: root.dimColor
+ Layout.preferredWidth: 48
+ horizontalAlignment: Text.AlignRight
+ }
+ }
+
+ Repeater {
+ model: root.sortedProcesses
+
+ RowLayout {
+ Layout.fillWidth: true
+ spacing: Theme.spacingXS
+
+ StyledText {
+ text: modelData.command || "unknown"
+ isMonospace: true
+ font.pixelSize: Theme.fontSizeSmall
+ color: root.textColor
+ Layout.fillWidth: true
+ elide: Text.ElideRight
+ }
+
+ StyledText {
+ text: root.topProcessSortBy === "cpu" ? (modelData.cpu || 0).toFixed(1) + "%" : root.formatMemKB(modelData.memoryKB || 0)
+ isMonospace: true
+ font.pixelSize: Theme.fontSizeSmall
+ color: root.dimColor
+ Layout.preferredWidth: 48
+ horizontalAlignment: Text.AlignRight
+ }
+ }
+ }
+ }
+
+ ColumnLayout {
+ Layout.fillWidth: true
+ spacing: Theme.spacingXS
+ visible: root.showDisk && DgopService.diskMounts.length > 0
+
+ Rectangle {
+ Layout.fillWidth: true
+ height: 1
+ color: Theme.withAlpha(Theme.outline, 0.15)
+ }
+
+ Repeater {
+ model: DgopService.diskMounts.filter(m => m.mountpoint === "/" || m.mountpoint === "/home")
+
+ RowLayout {
+ Layout.fillWidth: true
+ spacing: Theme.spacingXS
+
+ StyledText {
+ text: modelData.mountpoint
+ isMonospace: true
+ font.pixelSize: Theme.fontSizeSmall
+ color: root.dimColor
+ Layout.preferredWidth: 48
+ }
+
+ Rectangle {
+ Layout.fillWidth: true
+ height: 4
+ radius: 2
+ color: Theme.withAlpha(Theme.outline, 0.2)
+
+ Rectangle {
+ property real pct: (modelData.used || 0) / Math.max(1, modelData.total || 1)
+ width: parent.width * pct
+ height: parent.height
+ radius: 2
+ color: pct > 0.9 ? Theme.error : (pct > 0.75 ? Theme.warning : root.accentColor)
+ }
+ }
+
+ StyledText {
+ text: ((modelData.used || 0) / (modelData.total || 1) * 100).toFixed(0) + "%"
+ isMonospace: true
+ font.pixelSize: Theme.fontSizeSmall
+ color: root.textColor
+ Layout.preferredWidth: 32
+ horizontalAlignment: Text.AlignRight
+ }
+ }
+ }
+ }
+ }
+ }
+}