hefty: bar: resources popup: show mem & cpu

This commit is contained in:
end-4
2026-03-12 11:23:48 +01:00
parent 522bb5dc0a
commit e4ad01c20f
4 changed files with 303 additions and 15 deletions
@@ -0,0 +1,62 @@
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Controls
Control {
id: root
property list<real> valueWeights: [1]
property list<real> values: [0.5]
property list<color> valueHighlights: ["white"]
property list<color> valueTroughs: []
readonly property list<real> normalizedValueWeights: {
const totalWeight = valueWeights.reduce((sum, weight) => sum + weight, 0)
return valueWeights.map(weight => weight / totalWeight)
}
readonly property list<real> visualEnds: {
let cumsum = 0;
let positions = [];
for (let i = 0; i < normalizedValueWeights.length; i++) {
cumsum += normalizedValueWeights[i];
positions.push(cumsum);
}
return positions;
}
readonly property list<real> visualPositions: {
let positions = [];
let lastEnd = 0;
for(let i = 0; i < visualEnds.length; i++) {
const thisEnd = visualEnds[i];
const width = thisEnd - lastEnd;
const thisPos = lastEnd + width * values[i];
positions.push(thisPos);
lastEnd = visualEnds[i];
}
return positions;
}
readonly property list<var> visualSegments: {
let segs = [];
let lastEnd = 0;
for(let i = 0; i < visualEnds.length; i++) {
const thisEnd = visualEnds[i];
const thisPos = visualPositions[i];
segs.push([lastEnd, thisPos]);
segs.push([thisPos, thisEnd]);
lastEnd = visualEnds[i];
}
return segs;
}
readonly property list<color> segmentColors: {
var cols = [];
for(let i = 0; i < valueHighlights.length; i++) {
cols.push(valueHighlights[i]);
cols.push(valueTroughs[i]);
}
return cols;
}
}
@@ -0,0 +1,72 @@
pragma ComponentBehavior: Bound
import QtQuick
import qs.modules.common
AbstractCombinedProgressBar {
id: root
property real valueBarWidth: 120
property real valueBarHeight: 4
property real valueBarGap: 4
property real valueBarInnerRadius: Appearance.rounding.unsharpen
valueHighlights: [Appearance.colors.colPrimary, Appearance.colors.colTertiary]
valueTroughs: [Appearance.colors.colSecondaryContainer, Appearance.colors.colTertiaryContainer]
background: Item {
implicitWidth: root.valueBarWidth
implicitHeight: root.valueBarHeight
}
// "negligible" = too small that it'd look weird when shown
function isNegligibleSegment(seg: var): bool {
const wdth = seg[1] - seg[0];
const visualWidth = availableWidth * wdth;
return (visualWidth <= valueBarGap + valueBarHeight)
}
contentItem: Item {
Repeater {
model: root.visualSegments
delegate: Rectangle {
required property int index
required property var modelData
visible: !root.isNegligibleSegment(modelData)
anchors {
top: parent.top
bottom: parent.bottom
}
property bool atStart: index == 0
property bool atEnd: index == root.visualSegments.length - 1
property real displaySegStart: { // swallow previous segments if they're "negligible"
var i = index;
while ((i > 0 && root.isNegligibleSegment(root.visualSegments[i-1])))
i--;
return root.visualSegments[i][0]
}
x: {
var result = root.availableWidth * displaySegStart;
if (!atStart) result += root.valueBarGap / 2;
return result;
}
width: {
var result = root.availableWidth * (modelData[1] - displaySegStart)
if (atStart || atEnd) result -= root.valueBarGap / 2;
else result -= root.valueBarGap;
return result;
}
color: root.segmentColors[index % root.segmentColors.length]
property real startRadius: atStart ? height / 2 : root.valueBarInnerRadius
property real endRadius: atEnd ? height / 2 : root.valueBarInnerRadius
topLeftRadius: startRadius
bottomLeftRadius: startRadius
topRightRadius: endRadius
bottomRightRadius: endRadius
}
}
}
}
@@ -162,6 +162,102 @@ HBarWidgetWithPopout {
W.FlyFadeEnterChoreographable {
Layout.fillWidth: true
Column {
anchors {
left: parent.left
right: parent.right
}
spacing: 2
Item {
anchors {
left: parent.left
right: parent.right
}
implicitHeight: memUsed.implicitHeight
BigSmallTextPair {
id: memUsed
materialSymbol: "memory"
bigText: S.ResourceUsage.kbToGbString(S.ResourceUsage.memoryUsed, false)
smallText: {
const total = S.ResourceUsage.kbToGbString(S.ResourceUsage.memoryTotal, false);
return S.Translation.tr("%1").arg(`/ ${total}`)
}
W.StyledText {
Layout.alignment: Qt.AlignBaseline
text: S.Translation.tr("Memory")
color: C.Appearance.colors.colOutline
}
}
BigSmallTextPair {
id: swapUsed
TextMetrics {
id: plusTextMetric
font: swapUsed.bigFont
text: "+"
}
property real halfWidthOfAPlus: plusTextMetric.width / 2
x: Math.min(memProg.availableWidth * memProg.visualEnds[0] - halfWidthOfAPlus, parent.width - width)
bigText: "+ " + S.ResourceUsage.kbToGbString(S.ResourceUsage.swapUsed, false)
smallText: {
const total = S.ResourceUsage.kbToGbString(S.ResourceUsage.swapTotal, false);
return `/ ${total} GB`
}
}
}
W.StyledCombinedProgressBar {
id: memProg
anchors {
left: parent.left
right: parent.right
}
valueWeights: [S.ResourceUsage.memoryTotal, S.ResourceUsage.swapTotal]
values: [S.ResourceUsage.memoryUsedPercentage, S.ResourceUsage.swapUsedPercentage]
}
}
}
W.FlyFadeEnterChoreographable {
Layout.fillWidth: true
Column {
anchors {
left: parent.left
right: parent.right
}
spacing: 2
BigSmallTextPair {
spacing: 0
materialSymbol: "developer_board"
bigText: Math.round(S.ResourceUsage.cpuUsage * 100)
smallText: "%"
W.StyledText {
Layout.alignment: Qt.AlignBaseline
text: " " + S.Translation.tr("CPU")
color: C.Appearance.colors.colOutline
}
}
W.StyledCombinedProgressBar {
anchors {
left: parent.left
right: parent.right
}
property bool useSingleAggregate: S.ResourceUsage.cpuCoreUsages.length > 8
valueWeights: useSingleAggregate ? [1] : S.ResourceUsage.cpuCoreFreqCaps
values: useSingleAggregate ? [S.ResourceUsage.cpuUsage] : S.ResourceUsage.cpuCoreUsages
}
}
}
W.FlyFadeEnterChoreographable {
Layout.topMargin: 8
Layout.fillWidth: true
RowLayout {
spacing: 10
width: parent.width
@@ -258,6 +354,36 @@ HBarWidgetWithPopout {
}
}
component BigSmallTextPair: RowLayout {
id: txtPair
property string materialSymbol: ""
property string bigText: ""
property string smallText: ""
property alias bigFont: bigTxt.font
property alias smallFont: smallTxt.font
spacing: 6
W.MaterialSymbol {
Layout.rightMargin: 6 - spacing
visible: text.length > 0
Layout.alignment: Qt.AlignVCenter
text: txtPair.materialSymbol
fill: 1
iconSize: 24
}
W.StyledText {
id: bigTxt
Layout.alignment: Qt.AlignBaseline
font.pixelSize: C.Appearance.font.pixelSize.title
text: txtPair.bigText
}
W.StyledText {
id: smallTxt
Layout.alignment: Qt.AlignBaseline
text: txtPair.smallText
}
}
component StatWithIcon: Item {
id: statItem
required property string icon