import QtQuick import QtQuick.Controls import QtQuick.Layouts import Quickshell import Quickshell.Io import qs.Commons import qs.Modules.Bar.Extras import qs.Modules.Panels.Settings import qs.Services.System import qs.Services.UI import qs.Widgets Item { id: root property ShellScreen screen // Widget properties passed from Bar.qml for per-instance settings property string widgetId: "" property string section: "" property int sectionWidgetIndex: -1 property int sectionWidgetsCount: 0 property var widgetMetadata: BarWidgetRegistry.widgetMetadata[widgetId] // Explicit screenName property ensures reactive binding when screen changes readonly property string screenName: screen ? screen.name : "" property var widgetSettings: { if (section && sectionWidgetIndex >= 0 && screenName) { var widgets = Settings.getBarWidgetsForScreen(screenName)[section]; if (widgets && sectionWidgetIndex < widgets.length) { return widgets[sectionWidgetIndex]; } } return {}; } readonly property string barPosition: Settings.getBarPositionForScreen(screenName) readonly property bool isVertical: barPosition === "left" || barPosition === "right" readonly property real capsuleHeight: Style.getCapsuleHeightForScreen(screenName) readonly property real barFontSize: Style.getBarFontSizeForScreen(screenName) readonly property bool compactMode: widgetSettings.compactMode !== undefined ? widgetSettings.compactMode : widgetMetadata.compactMode readonly property string iconColorKey: widgetSettings.iconColor !== undefined ? widgetSettings.iconColor : widgetMetadata.iconColor readonly property string textColorKey: widgetSettings.textColor !== undefined ? widgetSettings.textColor : widgetMetadata.textColor readonly property bool useMonospaceFont: widgetSettings.useMonospaceFont !== undefined ? widgetSettings.useMonospaceFont : widgetMetadata.useMonospaceFont readonly property bool usePadding: !compactMode && !isVertical && useMonospaceFont && ((widgetSettings.usePadding !== undefined) ? widgetSettings.usePadding : widgetMetadata.usePadding) readonly property bool showCpuUsage: (widgetSettings.showCpuUsage !== undefined) ? widgetSettings.showCpuUsage : widgetMetadata.showCpuUsage readonly property bool showCpuCores: (widgetSettings.showCpuCores !== undefined) ? widgetSettings.showCpuCores : widgetMetadata.showCpuCores readonly property bool showCpuFreq: (widgetSettings.showCpuFreq !== undefined) ? widgetSettings.showCpuFreq : widgetMetadata.showCpuFreq readonly property bool showCpuTemp: (widgetSettings.showCpuTemp !== undefined) ? widgetSettings.showCpuTemp : widgetMetadata.showCpuTemp readonly property bool showGpuTemp: (widgetSettings.showGpuTemp !== undefined) ? widgetSettings.showGpuTemp : widgetMetadata.showGpuTemp readonly property bool showMemoryUsage: (widgetSettings.showMemoryUsage !== undefined) ? widgetSettings.showMemoryUsage : widgetMetadata.showMemoryUsage readonly property bool showMemoryAsPercent: (widgetSettings.showMemoryAsPercent !== undefined) ? widgetSettings.showMemoryAsPercent : widgetMetadata.showMemoryAsPercent readonly property bool showSwapUsage: (widgetSettings.showSwapUsage !== undefined) ? widgetSettings.showSwapUsage : widgetMetadata.showSwapUsage readonly property bool showNetworkStats: (widgetSettings.showNetworkStats !== undefined) ? widgetSettings.showNetworkStats : widgetMetadata.showNetworkStats readonly property bool showDiskUsage: (widgetSettings.showDiskUsage !== undefined) ? widgetSettings.showDiskUsage : widgetMetadata.showDiskUsage readonly property bool showDiskUsageAsPercent: (widgetSettings.showDiskUsageAsPercent !== undefined) ? widgetSettings.showDiskUsageAsPercent : widgetMetadata.showDiskUsageAsPercent readonly property bool showDiskAvailable: (widgetSettings.showDiskAvailable !== undefined) ? widgetSettings.showDiskAvailable : widgetMetadata.showDiskAvailable readonly property bool showLoadAverage: (widgetSettings.showLoadAverage !== undefined) ? widgetSettings.showLoadAverage : widgetMetadata.showLoadAverage readonly property string diskPath: (widgetSettings.diskPath !== undefined) ? widgetSettings.diskPath : widgetMetadata.diskPath readonly property string fontFamily: useMonospaceFont ? Settings.data.ui.fontFixed : Settings.data.ui.fontDefault readonly property int paddingPercent: usePadding ? String("100%").length : 0 readonly property int paddingTemp: usePadding ? String("999°").length : 0 readonly property int paddingCpuFreq: usePadding ? String("9.9").length : 0 readonly property int paddingSpeed: usePadding ? String("9999G").length : 0 readonly property real iconSize: Style.toOdd(capsuleHeight * 0.48) readonly property real miniGaugeWidth: Math.max(3, Style.toOdd(root.iconSize * 0.25)) // Content dimensions for implicit sizing readonly property real contentWidth: isVertical ? capsuleHeight : Math.round(mainGrid.implicitWidth + Style.margin2M) readonly property real contentHeight: isVertical ? Math.round(mainGrid.implicitHeight + Style.margin2M) : capsuleHeight readonly property color iconColor: Color.resolveColorKey(iconColorKey) readonly property color textColor: Color.resolveColorKey(textColorKey) // Size: use implicit width/height // BarWidgetLoader sets explicit width/height to extend click area implicitWidth: contentWidth implicitHeight: contentHeight Component.onCompleted: SystemStatService.registerComponent("bar-sysmon:" + (screen?.name || "unknown")) Component.onDestruction: SystemStatService.unregisterComponent("bar-sysmon:" + (screen?.name || "unknown")) function openExternalMonitor() { Quickshell.execDetached(["sh", "-c", Settings.data.systemMonitor.externalMonitor]); } // Build comprehensive tooltip text with all stats function buildTooltipContent() { let rows = []; // CPU rows.push([I18n.tr("system-monitor.cpu-usage"), `${Math.round(SystemStatService.cpuUsage)}% (${SystemStatService.cpuFreq.replace(/[^0-9.]/g, "")} GHz)`]); if (showCpuCores) { SystemStatService.coresUsage.forEach((usage, core) => rows.push([" " + I18n.tr("system-monitor.core-usage", { "id": core }), `${Math.round(usage)}%`])); } if (SystemStatService.cpuTemp > 0) { rows.push([I18n.tr("system-monitor.cpu-temp"), `${Math.round(SystemStatService.cpuTemp)}°C`]); } // GPU (if available) if (SystemStatService.gpuAvailable) { rows.push([I18n.tr("system-monitor.gpu-temp"), `${Math.round(SystemStatService.gpuTemp)}°C`]); } // Load Average if (SystemStatService.loadAvg1 >= 0) { rows.push([I18n.tr("system-monitor.load-average"), `${SystemStatService.loadAvg1.toFixed(2)} · ${SystemStatService.loadAvg5.toFixed(2)} · ${SystemStatService.loadAvg15.toFixed(2)}`]); } // Memory rows.push([I18n.tr("common.memory"), `${Math.round(SystemStatService.memPercent)}% (${(SystemStatService.memGb).toFixed(1)} GiB)`]); // Swap (if available) if (SystemStatService.swapTotalGb > 0) { rows.push([I18n.tr("bar.system-monitor.swap-usage-label"), `${Math.round(SystemStatService.swapPercent)}% (${(SystemStatService.swapGb).toFixed(1)} GiB)`]); } // Network rows.push([I18n.tr("system-monitor.download-speed"), `${SystemStatService.formatSpeed(SystemStatService.rxSpeed).replace(/([0-9.]+)([A-Za-z]+)/, "$1 $2")}` + "/s"]); rows.push([I18n.tr("system-monitor.upload-speed"), `${SystemStatService.formatSpeed(SystemStatService.txSpeed).replace(/([0-9.]+)([A-Za-z]+)/, "$1 $2")}` + "/s"]); // Disk const diskPercent = SystemStatService.diskPercents[diskPath]; if (diskPercent !== undefined) { const usedGb = SystemStatService.diskUsedGb[diskPath] || 0; const sizeGb = SystemStatService.diskSizeGb[diskPath] || 0; const availGb = SystemStatService.diskAvailableGb[diskPath] || 0; rows.push([I18n.tr("system-monitor.disk"), `${diskPercent}% (${usedGb.toFixed(1)} / ${sizeGb.toFixed(1)} GB)`]); rows.push([I18n.tr("common.available"), `${availGb.toFixed(1)} GB`]); } return rows; } // Visibility-aware warning/critical states (delegates to service) readonly property bool cpuWarning: showCpuUsage && SystemStatService.cpuWarning readonly property bool cpuCritical: showCpuUsage && SystemStatService.cpuCritical readonly property bool tempWarning: showCpuTemp && SystemStatService.tempWarning readonly property bool tempCritical: showCpuTemp && SystemStatService.tempCritical readonly property bool gpuWarning: showGpuTemp && SystemStatService.gpuWarning readonly property bool gpuCritical: showGpuTemp && SystemStatService.gpuCritical readonly property bool memWarning: showMemoryUsage && SystemStatService.memWarning readonly property bool memCritical: showMemoryUsage && SystemStatService.memCritical readonly property bool swapWarning: showSwapUsage && SystemStatService.swapWarning readonly property bool swapCritical: showSwapUsage && SystemStatService.swapCritical readonly property bool diskWarning: showDiskUsage && SystemStatService.isDiskWarning(diskPath) readonly property bool diskCritical: showDiskUsage && SystemStatService.isDiskCritical(diskPath) NPopupContextMenu { id: contextMenu model: [ { "label": I18n.tr("system-monitor.title"), "action": "sysmon-settings", "icon": "settings" }, { "label": I18n.tr("actions.widget-settings"), "action": "widget-settings", "icon": "settings" }, ] onTriggered: action => { contextMenu.close(); PanelService.closeContextMenu(screen); if (action === "sysmon-settings") { let monitorCmd = Settings.data.systemMonitor.externalMonitor; if (monitorCmd && monitorCmd.trim() !== "") { openExternalMonitor(); } else { SettingsPanelService.openToTab(SettingsPanel.Tab.System, 0, screen); } } else if (action === "widget-settings") { BarService.openWidgetSettings(screen, section, sectionWidgetIndex, widgetId, widgetSettings); } } } // Visual capsule centered in parent Rectangle { id: visualCapsule width: root.contentWidth height: root.contentHeight anchors.centerIn: parent radius: Style.radiusM color: Style.capsuleColor border.color: Style.capsuleBorderColor border.width: Style.capsuleBorderWidth // Mini gauge component for compact mode, vertical gauge that fills from bottom Component { id: miniGaugeComponent NLinearGauge { ratio: 0 orientation: Qt.Vertical fillColor: Color.mPrimary width: miniGaugeWidth height: iconSize } } GridLayout { id: mainGrid anchors.centerIn: parent flow: isVertical ? GridLayout.TopToBottom : GridLayout.LeftToRight rows: isVertical ? -1 : 1 columns: isVertical ? 1 : -1 rowSpacing: isVertical ? (compactMode ? Style.marginL : Style.marginXL) : 0 columnSpacing: isVertical ? 0 : Style.marginM // CPU Usage Component Item { id: cpuUsageContainer implicitWidth: cpuUsageContent.implicitWidth implicitHeight: cpuUsageContent.implicitHeight Layout.preferredWidth: isVertical ? root.width : implicitWidth Layout.preferredHeight: compactMode ? implicitHeight : capsuleHeight Layout.alignment: isVertical ? Qt.AlignHCenter : Qt.AlignVCenter visible: showCpuUsage GridLayout { id: cpuUsageContent anchors.centerIn: parent property bool verticalDisplay: isVertical && (!compactMode || showCpuCores) flow: verticalDisplay ? GridLayout.TopToBottom : GridLayout.LeftToRight rows: verticalDisplay ? -1 : 1 columns: verticalDisplay ? 1 : -1 rowSpacing: compactMode ? 3 : Style.marginXS columnSpacing: compactMode ? 3 : Style.marginXS Item { Layout.preferredWidth: iconSize Layout.preferredHeight: (compactMode || isVertical) ? iconSize : capsuleHeight Layout.alignment: Qt.AlignCenter Layout.row: (isVertical && !compactMode) ? 1 : 0 Layout.column: 0 NIcon { icon: "cpu-usage" pointSize: iconSize applyUiScale: false x: Style.pixelAlignCenter(parent.width, width) y: Style.pixelAlignCenter(parent.height, contentHeight) color: (cpuWarning || cpuCritical) ? SystemStatService.cpuColor : root.iconColor } } // Text mode NText { visible: !compactMode text: `${Math.round(SystemStatService.cpuUsage)}%`.padStart(paddingPercent, " ") family: fontFamily pointSize: barFontSize applyUiScale: false Layout.alignment: Qt.AlignCenter horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter color: (cpuWarning || cpuCritical) ? SystemStatService.cpuColor : root.textColor Layout.row: isVertical ? 0 : 0 Layout.column: isVertical ? 0 : 1 } // Compact mode general cpu Loader { active: compactMode && !showCpuCores visible: compactMode && !showCpuCores sourceComponent: miniGaugeComponent Layout.alignment: Qt.AlignCenter Layout.row: 0 Layout.column: 1 onLoaded: { item.ratio = Qt.binding(() => SystemStatService.cpuUsage / 100); item.fillColor = Qt.binding(() => SystemStatService.cpuColor); } } // Compact mode for cores Repeater { model: (compactMode && showCpuCores) ? SystemStatService.coresUsage : [] delegate: NLinearGauge { required property var modelData width: isVertical ? iconSize : miniGaugeWidth height: isVertical ? miniGaugeWidth : iconSize orientation: isVertical ? Qt.Horizontal : Qt.Vertical ratio: modelData / 100 fillColor: SystemStatService.getCoreUsageColor(modelData) } } } } // CPU Frequency Component Item { id: cpuFreqContainer implicitWidth: cpuFreqContent.implicitWidth implicitHeight: cpuFreqContent.implicitHeight Layout.preferredWidth: isVertical ? root.width : implicitWidth Layout.preferredHeight: compactMode ? implicitHeight : capsuleHeight Layout.alignment: isVertical ? Qt.AlignHCenter : Qt.AlignVCenter visible: showCpuFreq && (!isVertical || compactMode) GridLayout { id: cpuFreqContent anchors.centerIn: parent flow: (isVertical && !compactMode) ? GridLayout.TopToBottom : GridLayout.LeftToRight rows: (isVertical && !compactMode) ? 2 : 1 columns: (isVertical && !compactMode) ? 1 : 2 rowSpacing: Style.marginXXS columnSpacing: compactMode ? 3 : Style.marginXS Item { Layout.preferredWidth: iconSize Layout.preferredHeight: (compactMode || isVertical) ? iconSize : capsuleHeight Layout.alignment: Qt.AlignCenter Layout.row: (isVertical && !compactMode) ? 1 : 0 Layout.column: 0 NIcon { icon: "cpu-usage" pointSize: iconSize applyUiScale: false x: Style.pixelAlignCenter(parent.width, width) y: Style.pixelAlignCenter(parent.height, contentHeight) color: root.iconColor } } // Text mode NText { visible: !compactMode text: SystemStatService.cpuFreq.replace("Hz", "").replace(" ", "").padStart(paddingCpuFreq, " ") family: fontFamily pointSize: barFontSize applyUiScale: false Layout.alignment: Qt.AlignCenter horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter color: root.textColor Layout.row: isVertical ? 0 : 0 Layout.column: isVertical ? 0 : 1 } // Compact mode Loader { active: compactMode visible: compactMode sourceComponent: miniGaugeComponent Layout.alignment: Qt.AlignCenter Layout.row: 0 Layout.column: 1 onLoaded: { item.ratio = Qt.binding(() => SystemStatService.cpuFreqRatio); } } } } // CPU Temperature Component Item { id: cpuTempContainer implicitWidth: cpuTempContent.implicitWidth implicitHeight: cpuTempContent.implicitHeight Layout.preferredWidth: isVertical ? root.width : implicitWidth Layout.preferredHeight: compactMode ? implicitHeight : capsuleHeight Layout.alignment: isVertical ? Qt.AlignHCenter : Qt.AlignVCenter visible: showCpuTemp GridLayout { id: cpuTempContent anchors.centerIn: parent flow: (isVertical && !compactMode) ? GridLayout.TopToBottom : GridLayout.LeftToRight rows: (isVertical && !compactMode) ? 2 : 1 columns: (isVertical && !compactMode) ? 1 : 2 rowSpacing: Style.marginXXS columnSpacing: compactMode ? 3 : Style.marginXS Item { Layout.preferredWidth: iconSize Layout.preferredHeight: (compactMode || isVertical) ? iconSize : capsuleHeight Layout.alignment: Qt.AlignCenter Layout.row: (isVertical && !compactMode) ? 1 : 0 Layout.column: 0 NIcon { icon: "cpu-temperature" pointSize: iconSize applyUiScale: false x: Style.pixelAlignCenter(parent.width, width) y: Style.pixelAlignCenter(parent.height, contentHeight) color: (tempWarning || tempCritical) ? SystemStatService.tempColor : root.iconColor } } // Text mode NText { visible: !compactMode text: `${Math.round(SystemStatService.cpuTemp)}°`.padStart(paddingTemp, " ") family: fontFamily pointSize: barFontSize applyUiScale: false Layout.alignment: Qt.AlignCenter horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter color: (tempWarning || tempCritical) ? SystemStatService.tempColor : root.textColor Layout.row: isVertical ? 0 : 0 Layout.column: isVertical ? 0 : 1 } // Compact mode, mini gauge (to the right of icon) Loader { active: compactMode visible: compactMode sourceComponent: miniGaugeComponent Layout.alignment: Qt.AlignCenter Layout.row: 0 Layout.column: 1 onLoaded: { item.ratio = Qt.binding(() => SystemStatService.cpuTemp / 100); item.fillColor = Qt.binding(() => SystemStatService.tempColor); } } } } // GPU Temperature Component Item { id: gpuTempContainer implicitWidth: gpuTempContent.implicitWidth implicitHeight: gpuTempContent.implicitHeight Layout.preferredWidth: isVertical ? root.width : implicitWidth Layout.preferredHeight: compactMode ? implicitHeight : capsuleHeight Layout.alignment: isVertical ? Qt.AlignHCenter : Qt.AlignVCenter visible: showGpuTemp && SystemStatService.gpuAvailable GridLayout { id: gpuTempContent anchors.centerIn: parent flow: (isVertical && !compactMode) ? GridLayout.TopToBottom : GridLayout.LeftToRight rows: (isVertical && !compactMode) ? 2 : 1 columns: (isVertical && !compactMode) ? 1 : 2 rowSpacing: Style.marginXXS columnSpacing: compactMode ? 3 : Style.marginXS Item { Layout.preferredWidth: iconSize Layout.preferredHeight: (compactMode || isVertical) ? iconSize : capsuleHeight Layout.alignment: Qt.AlignCenter Layout.row: (isVertical && !compactMode) ? 1 : 0 Layout.column: 0 NIcon { icon: "gpu-temperature" pointSize: iconSize applyUiScale: false x: Style.pixelAlignCenter(parent.width, width) y: Style.pixelAlignCenter(parent.height, contentHeight) color: (gpuWarning || gpuCritical) ? SystemStatService.gpuColor : root.iconColor } } // Text mode NText { visible: !compactMode text: `${Math.round(SystemStatService.gpuTemp)}°`.padStart(paddingTemp, " ") family: fontFamily pointSize: barFontSize applyUiScale: false Layout.alignment: Qt.AlignCenter horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter color: (gpuWarning || gpuCritical) ? SystemStatService.gpuColor : root.textColor Layout.row: isVertical ? 0 : 0 Layout.column: isVertical ? 0 : 1 } // Compact mode Loader { active: compactMode visible: compactMode sourceComponent: miniGaugeComponent Layout.alignment: Qt.AlignCenter Layout.row: 0 Layout.column: 1 onLoaded: { item.ratio = Qt.binding(() => SystemStatService.gpuTemp / 100); item.fillColor = Qt.binding(() => SystemStatService.gpuColor); } } } } // Load Average Component Item { id: loadAvgContainer implicitWidth: loadAvgContent.implicitWidth implicitHeight: loadAvgContent.implicitHeight Layout.preferredWidth: isVertical ? root.width : implicitWidth Layout.preferredHeight: compactMode ? implicitHeight : capsuleHeight Layout.alignment: isVertical ? Qt.AlignHCenter : Qt.AlignVCenter visible: showLoadAverage && SystemStatService.nproc > 0 && SystemStatService.loadAvg1 > 0 GridLayout { id: loadAvgContent anchors.centerIn: parent flow: (isVertical && !compactMode) ? GridLayout.TopToBottom : GridLayout.LeftToRight rows: (isVertical && !compactMode) ? 2 : 1 columns: (isVertical && !compactMode) ? 1 : 2 rowSpacing: Style.marginXXS columnSpacing: compactMode ? 3 : Style.marginXS Item { Layout.preferredWidth: iconSize Layout.preferredHeight: (compactMode || isVertical) ? iconSize : capsuleHeight Layout.alignment: Qt.AlignCenter Layout.row: (isVertical && !compactMode) ? 1 : 0 Layout.column: 0 NIcon { icon: "weight" pointSize: iconSize applyUiScale: false x: Style.pixelAlignCenter(parent.width, width) y: Style.pixelAlignCenter(parent.height, contentHeight) color: root.iconColor } } // Text mode NText { visible: !compactMode text: `${SystemStatService.loadAvg1.toFixed(1)}`.padStart(usePadding ? `${SystemStatService.nproc.toFixed(1)}`.length : 0, " ") family: fontFamily pointSize: barFontSize applyUiScale: false Layout.alignment: Qt.AlignCenter horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter color: root.textColor Layout.row: isVertical ? 0 : 0 Layout.column: isVertical ? 0 : 1 } // Compact mode Loader { active: compactMode visible: compactMode sourceComponent: miniGaugeComponent Layout.alignment: Qt.AlignCenter Layout.row: 0 Layout.column: 1 onLoaded: { item.ratio = Qt.binding(() => Math.min(1, SystemStatService.loadAvg1 / SystemStatService.nproc)); } } } } // Memory Usage Component Item { id: memoryContainer implicitWidth: memoryContent.implicitWidth implicitHeight: memoryContent.implicitHeight Layout.preferredWidth: isVertical ? root.width : implicitWidth Layout.preferredHeight: compactMode ? implicitHeight : capsuleHeight Layout.alignment: isVertical ? Qt.AlignHCenter : Qt.AlignVCenter visible: showMemoryUsage GridLayout { id: memoryContent anchors.centerIn: parent flow: (isVertical && !compactMode) ? GridLayout.TopToBottom : GridLayout.LeftToRight rows: (isVertical && !compactMode) ? 2 : 1 columns: (isVertical && !compactMode) ? 1 : 2 rowSpacing: Style.marginXXS columnSpacing: compactMode ? 3 : Style.marginXS Item { Layout.preferredWidth: iconSize Layout.preferredHeight: (compactMode || isVertical) ? iconSize : capsuleHeight Layout.alignment: Qt.AlignCenter Layout.row: (isVertical && !compactMode) ? 1 : 0 Layout.column: 0 NIcon { icon: "memory" pointSize: iconSize applyUiScale: false x: Style.pixelAlignCenter(parent.width, width) y: Style.pixelAlignCenter(parent.height, contentHeight) color: (memWarning || memCritical) ? SystemStatService.memColor : root.iconColor } } // Text mode NText { visible: !compactMode text: SystemStatService.formatRamDisplay({ percent: showMemoryAsPercent, padding: usePadding }) family: fontFamily pointSize: barFontSize applyUiScale: false Layout.alignment: Qt.AlignCenter horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter color: (memWarning || memCritical) ? SystemStatService.memColor : root.textColor Layout.row: isVertical ? 0 : 0 Layout.column: isVertical ? 0 : 1 } // Compact mode Loader { active: compactMode visible: compactMode sourceComponent: miniGaugeComponent Layout.alignment: Qt.AlignCenter Layout.row: 0 Layout.column: 1 onLoaded: { item.ratio = Qt.binding(() => SystemStatService.memPercent / 100); item.fillColor = Qt.binding(() => SystemStatService.memColor); } } } } // Swap Usage Component Item { id: swapContainer implicitWidth: swapContent.implicitWidth implicitHeight: swapContent.implicitHeight Layout.preferredWidth: isVertical ? root.width : implicitWidth Layout.preferredHeight: compactMode ? implicitHeight : capsuleHeight Layout.alignment: isVertical ? Qt.AlignHCenter : Qt.AlignVCenter visible: showSwapUsage && SystemStatService.swapTotalGb > 0 GridLayout { id: swapContent anchors.centerIn: parent flow: (isVertical && !compactMode) ? GridLayout.TopToBottom : GridLayout.LeftToRight rows: (isVertical && !compactMode) ? 2 : 1 columns: (isVertical && !compactMode) ? 1 : 2 rowSpacing: Style.marginXXS columnSpacing: compactMode ? 3 : Style.marginXS Item { Layout.preferredWidth: iconSize Layout.preferredHeight: (compactMode || isVertical) ? iconSize : capsuleHeight Layout.alignment: Qt.AlignCenter Layout.row: (isVertical && !compactMode) ? 1 : 0 Layout.column: 0 NIcon { icon: "exchange" pointSize: iconSize applyUiScale: false x: Style.pixelAlignCenter(parent.width, width) y: Style.pixelAlignCenter(parent.height, contentHeight) color: (swapWarning || swapCritical) ? SystemStatService.swapColor : root.iconColor } } // Text mode NText { visible: !compactMode text: SystemStatService.formatRamDisplay({ swap: true, percent: true, padding: usePadding }) family: fontFamily pointSize: barFontSize applyUiScale: false Layout.alignment: Qt.AlignCenter horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter color: (swapWarning || swapCritical) ? SystemStatService.swapColor : root.textColor Layout.row: isVertical ? 0 : 0 Layout.column: isVertical ? 0 : 1 } // Compact mode Loader { active: compactMode visible: compactMode sourceComponent: miniGaugeComponent Layout.alignment: Qt.AlignCenter Layout.row: 0 Layout.column: 1 onLoaded: { item.ratio = Qt.binding(() => SystemStatService.swapPercent / 100); item.fillColor = Qt.binding(() => SystemStatService.swapColor); } } } } // Network Download Speed Component Item { implicitWidth: downloadContent.implicitWidth implicitHeight: downloadContent.implicitHeight Layout.preferredWidth: isVertical ? root.width : implicitWidth Layout.preferredHeight: compactMode ? implicitHeight : capsuleHeight Layout.alignment: isVertical ? Qt.AlignHCenter : Qt.AlignVCenter visible: showNetworkStats GridLayout { id: downloadContent anchors.centerIn: parent flow: (isVertical && !compactMode) ? GridLayout.TopToBottom : GridLayout.LeftToRight rows: (isVertical && !compactMode) ? 2 : 1 columns: (isVertical && !compactMode) ? 1 : 2 rowSpacing: Style.marginXXS columnSpacing: compactMode ? 3 : Style.marginXS Item { Layout.preferredWidth: iconSize Layout.preferredHeight: (compactMode || isVertical) ? iconSize : capsuleHeight Layout.alignment: Qt.AlignCenter Layout.row: (isVertical && !compactMode) ? 1 : 0 Layout.column: 0 NIcon { icon: "download-speed" pointSize: iconSize applyUiScale: false x: Style.pixelAlignCenter(parent.width, width) y: Style.pixelAlignCenter(parent.height, contentHeight) color: root.iconColor } } // Text mode NText { visible: !compactMode text: isVertical ? SystemStatService.formatCompactSpeed(SystemStatService.rxSpeed) : SystemStatService.formatSpeed(SystemStatService.rxSpeed).padStart(paddingSpeed, " ") family: fontFamily pointSize: barFontSize applyUiScale: false Layout.alignment: Qt.AlignCenter horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter color: root.textColor Layout.row: isVertical ? 0 : 0 Layout.column: isVertical ? 0 : 1 } // Compact mode Loader { active: compactMode visible: compactMode sourceComponent: miniGaugeComponent Layout.alignment: Qt.AlignCenter Layout.row: 0 Layout.column: 1 onLoaded: { item.ratio = Qt.binding(() => SystemStatService.rxRatio); } } } } // Network Upload Speed Component Item { implicitWidth: uploadContent.implicitWidth implicitHeight: uploadContent.implicitHeight Layout.preferredWidth: isVertical ? root.width : implicitWidth Layout.preferredHeight: compactMode ? implicitHeight : capsuleHeight Layout.alignment: isVertical ? Qt.AlignHCenter : Qt.AlignVCenter visible: showNetworkStats GridLayout { id: uploadContent anchors.centerIn: parent flow: (isVertical && !compactMode) ? GridLayout.TopToBottom : GridLayout.LeftToRight rows: (isVertical && !compactMode) ? 2 : 1 columns: (isVertical && !compactMode) ? 1 : 2 rowSpacing: Style.marginXXS columnSpacing: compactMode ? 3 : Style.marginXS Item { Layout.preferredWidth: iconSize Layout.preferredHeight: (compactMode || isVertical) ? iconSize : capsuleHeight Layout.alignment: Qt.AlignCenter Layout.row: (isVertical && !compactMode) ? 1 : 0 Layout.column: 0 NIcon { icon: "upload-speed" pointSize: iconSize applyUiScale: false x: Style.pixelAlignCenter(parent.width, width) y: Style.pixelAlignCenter(parent.height, contentHeight) color: root.iconColor } } // Text mode NText { visible: !compactMode text: isVertical ? SystemStatService.formatCompactSpeed(SystemStatService.txSpeed) : SystemStatService.formatSpeed(SystemStatService.txSpeed).padStart(paddingSpeed, " ") family: fontFamily pointSize: barFontSize applyUiScale: false Layout.alignment: Qt.AlignCenter horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter color: root.textColor Layout.row: isVertical ? 0 : 0 Layout.column: isVertical ? 0 : 1 } // Compact mode Loader { active: compactMode visible: compactMode sourceComponent: miniGaugeComponent Layout.alignment: Qt.AlignCenter Layout.row: 0 Layout.column: 1 onLoaded: { item.ratio = Qt.binding(() => SystemStatService.txRatio); } } } } // Disk Usage Component (primary drive) Item { id: diskContainer implicitWidth: diskContent.implicitWidth implicitHeight: diskContent.implicitHeight Layout.preferredWidth: isVertical ? root.width : implicitWidth Layout.preferredHeight: compactMode ? implicitHeight : capsuleHeight Layout.alignment: isVertical ? Qt.AlignHCenter : Qt.AlignVCenter visible: showDiskUsage GridLayout { id: diskContent anchors.centerIn: parent flow: (isVertical && !compactMode) ? GridLayout.TopToBottom : GridLayout.LeftToRight rows: (isVertical && !compactMode) ? 2 : 1 columns: (isVertical && !compactMode) ? 1 : 2 rowSpacing: Style.marginXXS columnSpacing: compactMode ? 3 : Style.marginXS Item { Layout.preferredWidth: iconSize Layout.preferredHeight: (compactMode || isVertical) ? iconSize : capsuleHeight Layout.alignment: Qt.AlignCenter Layout.row: (isVertical && !compactMode) ? 1 : 0 Layout.column: 0 NIcon { icon: "storage" pointSize: iconSize applyUiScale: false x: Style.pixelAlignCenter(parent.width, width) y: Style.pixelAlignCenter(parent.height, contentHeight) color: (diskWarning || diskCritical) ? SystemStatService.getDiskColor(diskPath) : root.iconColor } } // Text mode NText { visible: !compactMode text: SystemStatService.formatDiskDisplay(diskPath, { percent: showDiskUsageAsPercent, available: showDiskAvailable, padding: usePadding }) family: fontFamily pointSize: barFontSize applyUiScale: false Layout.alignment: Qt.AlignCenter horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter color: (diskWarning || diskCritical) ? SystemStatService.getDiskColor(diskPath) : root.textColor Layout.row: isVertical ? 0 : 0 Layout.column: isVertical ? 0 : 1 } // Compact mode Loader { active: compactMode visible: compactMode sourceComponent: miniGaugeComponent Layout.alignment: Qt.AlignCenter Layout.row: 0 Layout.column: 1 onLoaded: { item.ratio = Qt.binding(() => (showDiskAvailable ? SystemStatService.diskAvailPercents[diskPath] : SystemStatService.diskPercents[diskPath] ?? 0) / 100); item.fillColor = Qt.binding(() => SystemStatService.getDiskColor(diskPath, showDiskAvailable)); } } } } } } // MouseArea at root level for extended click area MouseArea { id: tooltipArea anchors.fill: parent cursorShape: Qt.PointingHandCursor acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton hoverEnabled: true onClicked: mouse => { if (mouse.button === Qt.LeftButton) { PanelService.getPanel("systemStatsPanel", screen)?.toggle(root); TooltipService.hide(); } else if (mouse.button === Qt.RightButton) { TooltipService.hide(); PanelService.showContextMenu(contextMenu, root, screen); } else if (mouse.button === Qt.MiddleButton) { TooltipService.hide(); openExternalMonitor(); } } onEntered: { if (!PanelService.getPanel("systemStatsPanel", screen).isPanelOpen) { TooltipService.show(root, buildTooltipContent(), BarService.getTooltipDirection(root.screen?.name)); tooltipRefreshTimer.start(); } } onExited: { tooltipRefreshTimer.stop(); TooltipService.hide(); } } Timer { id: tooltipRefreshTimer interval: 1000 repeat: true onTriggered: { if (tooltipArea.containsMouse) { TooltipService.updateText(buildTooltipContent()); } } } }