mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-01-28 07:22:50 -05:00
plugins/desktop-widgets: create a new "desktop" widget plugin type
- Draggable per-monitor background layer widgets - Add basic dms version checks on plugins - Clock: built-in clock desktop plugin - dgop: built-in system monitor desktop plugin
This commit is contained in:
439
quickshell/Modules/BuiltinDesktopPlugins/DesktopClockWidget.qml
Normal file
439
quickshell/Modules/BuiltinDesktopPlugins/DesktopClockWidget.qml
Normal file
@@ -0,0 +1,439 @@
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
import qs.Common
|
||||
import qs.Widgets
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
property real widgetWidth: 280
|
||||
property real widgetHeight: 200
|
||||
|
||||
property string clockStyle: SettingsData.desktopClockStyle
|
||||
property bool forceSquare: clockStyle === "analog"
|
||||
|
||||
property real defaultWidth: {
|
||||
switch (clockStyle) {
|
||||
case "analog":
|
||||
return 200;
|
||||
case "stacked":
|
||||
return 160;
|
||||
default:
|
||||
return 280;
|
||||
}
|
||||
}
|
||||
property real defaultHeight: {
|
||||
switch (clockStyle) {
|
||||
case "analog":
|
||||
return 200;
|
||||
case "stacked":
|
||||
return 220;
|
||||
default:
|
||||
return 160;
|
||||
}
|
||||
}
|
||||
property real minWidth: {
|
||||
switch (clockStyle) {
|
||||
case "analog":
|
||||
return 120;
|
||||
case "stacked":
|
||||
return 100;
|
||||
default:
|
||||
return 140;
|
||||
}
|
||||
}
|
||||
property real minHeight: {
|
||||
switch (clockStyle) {
|
||||
case "analog":
|
||||
return 120;
|
||||
case "stacked":
|
||||
return 140;
|
||||
default:
|
||||
return 100;
|
||||
}
|
||||
}
|
||||
|
||||
property bool enabled: SettingsData.desktopClockEnabled
|
||||
property real transparency: SettingsData.desktopClockTransparency
|
||||
property string colorMode: SettingsData.desktopClockColorMode
|
||||
property color customColor: SettingsData.desktopClockCustomColor
|
||||
property bool showDate: SettingsData.desktopClockShowDate
|
||||
property bool showAnalogNumbers: 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)
|
||||
|
||||
SystemClock {
|
||||
id: systemClock
|
||||
precision: SystemClock.Seconds
|
||||
}
|
||||
|
||||
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
|
||||
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(Qt.locale(), SettingsData.clockDateFormat) ?? "";
|
||||
return systemClock.date?.toLocaleDateString(Qt.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 real baseSize: Math.max(28, height * 0.38)
|
||||
property real smallSize: Math.max(12, baseSize * 0.32)
|
||||
|
||||
Column {
|
||||
anchors.centerIn: parent
|
||||
spacing: 4
|
||||
|
||||
StyledText {
|
||||
visible: root.showDate
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
text: {
|
||||
if (SettingsData.clockDateFormat && SettingsData.clockDateFormat.length > 0)
|
||||
return systemClock.date?.toLocaleDateString(Qt.locale(), SettingsData.clockDateFormat) ?? "";
|
||||
return systemClock.date?.toLocaleDateString(Qt.locale(), "ddd, MMM d") ?? "";
|
||||
}
|
||||
font.pixelSize: digitalRoot.smallSize
|
||||
color: root.accentColor
|
||||
}
|
||||
|
||||
StyledText {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
text: {
|
||||
const hours = SettingsData.use24HourClock ? systemClock.date?.getHours() ?? 0 : ((systemClock.date?.getHours() ?? 0) % 12 || 12);
|
||||
const minutes = String(systemClock.date?.getMinutes() ?? 0).padStart(2, '0');
|
||||
return hours + ":" + minutes;
|
||||
}
|
||||
font.pixelSize: digitalRoot.baseSize
|
||||
font.weight: Font.Normal
|
||||
color: root.accentColor
|
||||
}
|
||||
|
||||
Row {
|
||||
visible: !SettingsData.use24HourClock || SettingsData.showSeconds
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
spacing: Theme.spacingS
|
||||
|
||||
Row {
|
||||
visible: SettingsData.showSeconds
|
||||
spacing: Theme.spacingXS
|
||||
|
||||
DankIcon {
|
||||
name: "timer"
|
||||
size: Math.max(10, digitalRoot.baseSize * 0.25)
|
||||
color: root.subtleTextColor
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: String(systemClock.date?.getSeconds() ?? 0).padStart(2, '0')
|
||||
font.pixelSize: digitalRoot.smallSize
|
||||
color: root.subtleTextColor
|
||||
}
|
||||
}
|
||||
|
||||
StyledText {
|
||||
visible: !SettingsData.use24HourClock
|
||||
text: (systemClock.date?.getHours() ?? 0) >= 12 ? "PM" : "AM"
|
||||
font.pixelSize: digitalRoot.smallSize
|
||||
font.weight: Font.Medium
|
||||
color: root.accentColor
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: stackedClock
|
||||
|
||||
Item {
|
||||
id: stackedRoot
|
||||
|
||||
property real baseSize: Math.max(32, height * 0.32)
|
||||
property real smallSize: Math.max(12, baseSize * 0.28)
|
||||
|
||||
Column {
|
||||
anchors.centerIn: parent
|
||||
spacing: -baseSize * 0.1
|
||||
|
||||
StyledText {
|
||||
visible: root.showDate
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
bottomPadding: Theme.spacingS
|
||||
text: {
|
||||
if (SettingsData.clockDateFormat && SettingsData.clockDateFormat.length > 0)
|
||||
return systemClock.date?.toLocaleDateString(Qt.locale(), SettingsData.clockDateFormat) ?? "";
|
||||
return systemClock.date?.toLocaleDateString(Qt.locale(), "ddd, MMM d") ?? "";
|
||||
}
|
||||
font.pixelSize: stackedRoot.smallSize
|
||||
color: root.accentColor
|
||||
}
|
||||
|
||||
StyledText {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
text: {
|
||||
const hours = SettingsData.use24HourClock ? systemClock.date?.getHours() ?? 0 : ((systemClock.date?.getHours() ?? 0) % 12 || 12);
|
||||
return String(hours).padStart(2, '0');
|
||||
}
|
||||
font.pixelSize: stackedRoot.baseSize
|
||||
font.weight: Font.Normal
|
||||
color: root.accentColor
|
||||
lineHeight: 0.85
|
||||
}
|
||||
|
||||
StyledText {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
text: String(systemClock.date?.getMinutes() ?? 0).padStart(2, '0')
|
||||
font.pixelSize: stackedRoot.baseSize
|
||||
font.weight: Font.Normal
|
||||
color: root.accentColor
|
||||
lineHeight: 0.85
|
||||
}
|
||||
|
||||
Row {
|
||||
visible: SettingsData.showSeconds || !SettingsData.use24HourClock
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
topPadding: Theme.spacingXS
|
||||
spacing: Theme.spacingS
|
||||
|
||||
Row {
|
||||
visible: SettingsData.showSeconds
|
||||
spacing: Theme.spacingXS
|
||||
|
||||
DankIcon {
|
||||
name: "timer"
|
||||
size: Math.max(10, stackedRoot.baseSize * 0.28)
|
||||
color: root.subtleTextColor
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: String(systemClock.date?.getSeconds() ?? 0).padStart(2, '0')
|
||||
font.pixelSize: stackedRoot.smallSize
|
||||
color: root.subtleTextColor
|
||||
}
|
||||
}
|
||||
|
||||
StyledText {
|
||||
visible: !SettingsData.use24HourClock
|
||||
text: (systemClock.date?.getHours() ?? 0) >= 12 ? "PM" : "AM"
|
||||
font.pixelSize: stackedRoot.smallSize
|
||||
font.weight: Font.Medium
|
||||
color: root.accentColor
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
736
quickshell/Modules/BuiltinDesktopPlugins/SystemMonitorWidget.qml
Normal file
736
quickshell/Modules/BuiltinDesktopPlugins/SystemMonitorWidget.qml
Normal file
@@ -0,0 +1,736 @@
|
||||
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 variantId: ""
|
||||
property var variantData: null
|
||||
|
||||
readonly property var cfg: variantData?.config ?? null
|
||||
readonly property bool isVariant: variantId !== "" && cfg !== null
|
||||
|
||||
property bool enabled: SettingsData.systemMonitorEnabled
|
||||
property bool showHeader: isVariant ? (cfg.showHeader ?? true) : SettingsData.systemMonitorShowHeader
|
||||
property real transparency: isVariant ? (cfg.transparency ?? 0.8) : SettingsData.systemMonitorTransparency
|
||||
property string colorMode: isVariant ? (cfg.colorMode ?? "primary") : SettingsData.systemMonitorColorMode
|
||||
property color customColor: isVariant ? (cfg.customColor ?? "#ffffff") : SettingsData.systemMonitorCustomColor
|
||||
property bool showCpu: isVariant ? (cfg.showCpu ?? true) : SettingsData.systemMonitorShowCpu
|
||||
property bool showCpuGraph: isVariant ? (cfg.showCpuGraph ?? true) : SettingsData.systemMonitorShowCpuGraph
|
||||
property bool showCpuTemp: isVariant ? (cfg.showCpuTemp ?? true) : SettingsData.systemMonitorShowCpuTemp
|
||||
property bool showGpuTemp: isVariant ? (cfg.showGpuTemp ?? false) : SettingsData.systemMonitorShowGpuTemp
|
||||
property string selectedGpuPciId: isVariant ? (cfg.gpuPciId ?? "") : SettingsData.systemMonitorGpuPciId
|
||||
property bool showMemory: isVariant ? (cfg.showMemory ?? true) : SettingsData.systemMonitorShowMemory
|
||||
property bool showMemoryGraph: isVariant ? (cfg.showMemoryGraph ?? true) : SettingsData.systemMonitorShowMemoryGraph
|
||||
property bool showNetwork: isVariant ? (cfg.showNetwork ?? true) : SettingsData.systemMonitorShowNetwork
|
||||
property bool showNetworkGraph: isVariant ? (cfg.showNetworkGraph ?? true) : SettingsData.systemMonitorShowNetworkGraph
|
||||
property bool showDisk: isVariant ? (cfg.showDisk ?? true) : SettingsData.systemMonitorShowDisk
|
||||
property bool showTopProcesses: isVariant ? (cfg.showTopProcesses ?? false) : SettingsData.systemMonitorShowTopProcesses
|
||||
property int topProcessCount: isVariant ? (cfg.topProcessCount ?? 3) : SettingsData.systemMonitorTopProcessCount
|
||||
property string topProcessSortBy: isVariant ? (cfg.topProcessSortBy ?? "cpu") : SettingsData.systemMonitorTopProcessSortBy
|
||||
property string layoutMode: isVariant ? (cfg.layoutMode ?? "auto") : SettingsData.systemMonitorLayoutMode
|
||||
property int graphInterval: isVariant ? (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 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");
|
||||
DgopService.addRef(modules);
|
||||
updateGpuRef();
|
||||
}
|
||||
|
||||
Component.onDestruction: {
|
||||
DgopService.removeRef();
|
||||
if (currentGpuPciIdRef)
|
||||
DgopService.removeGpuPciId(currentGpuPciIdRef);
|
||||
}
|
||||
|
||||
onShowGpuTempChanged: updateGpuRef()
|
||||
onSelectedGpuPciIdChanged: updateGpuRef()
|
||||
onShowTopProcessesChanged: {
|
||||
if (showTopProcesses)
|
||||
DgopService.addRef(["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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user