hefty: bar: resources indicator: add more stats

This commit is contained in:
end-4
2026-03-15 13:17:40 +01:00
parent 05eb696ead
commit 6e433e4a39
7 changed files with 283 additions and 15 deletions
@@ -4,11 +4,18 @@ import Quickshell.Io
JsonObject {
property JsonObject bar: JsonObject {
property list<var> leftWidgets: ["HWindowInfo"]
property list<var> leftWidgets: ["HLeftSidebarButton"]
property list<var> centerLeftWidgets: ["HTime"]
property list<var> centerWidgets: ["HWorkspaces"]
property list<var> centerRightWidgets: ["HResources"]
property list<var> rightWidgets: []
property list<var> rightWidgets: ["HSystemIndicators"]
property bool m3ExpressiveGrouping: true
property JsonObject resources: JsonObject {
property bool showMemory: false
property bool showRam: false
property bool showSwap: false
property bool showCpu: false
}
}
}
@@ -0,0 +1,75 @@
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Shapes
import qs.modules.common
AbstractCombinedProgressBar {
id: root
property int implicitSize: 30
property int lineWidth: 2
property real gapAngle: 360 / 18
valueHighlights: [Appearance.colors.colPrimary, Appearance.colors.colTertiary]
valueTroughs: [Appearance.colors.colSecondaryContainer, Appearance.colors.colTertiaryContainer]
property bool enableAnimation: true
property int animationDuration: 800
property var easingType: Easing.OutCubic
implicitWidth: implicitSize
implicitHeight: implicitSize
readonly property real centerX: root.width / 2
readonly property real centerY: root.height / 2
readonly property real arcRadius: root.implicitSize / 2 - root.lineWidth
readonly property real startAngle: -90
background: Item {
implicitWidth: root.implicitSize
implicitHeight: root.implicitSize
}
function isNegligibleSegment(seg: var): bool {
const range = seg[1] - seg[0];
return range < 1 / 360; // TODO make this less arbitrary
}
Repeater {
model: root.visualSegments
delegate: Shape {
id: segShape
required property int index
required property var modelData
property bool negligible: root.isNegligibleSegment(modelData)
property bool atStart: index == 0
property bool atEnd: index == root.visualSegments.length - 1
property real displaySegStart: {
var i = index;
while ((i > 0 && root.isNegligibleSegment(root.visualSegments[i - 1])))
i--;
return root.visualSegments[i][0];
}
anchors.fill: parent
layer.enabled: true
layer.smooth: true
preferredRendererType: Shape.CurveRenderer
ShapePath {
strokeColor: segShape.negligible ? "transparent" : root.segmentColors[segShape.index % root.segmentColors.length]
strokeWidth: segShape.negligible ? 0 : root.lineWidth
capStyle: ShapePath.RoundCap
fillColor: "transparent"
PathAngleArc {
centerX: root.centerX
centerY: root.centerY
radiusX: root.arcRadius
radiusY: root.arcRadius
startAngle: root.startAngle + 360 * segShape.displaySegStart + root.gapAngle / 2
sweepAngle: 360 * (segShape.modelData[1] - segShape.displaySegStart) - root.gapAngle
}
}
}
}
}
@@ -33,6 +33,7 @@ RippleButton {
}
StyledSwitch {
id: switchWidget
focusPolicy: Qt.NoFocus
down: root.down
Layout.fillWidth: false
checked: root.checked
@@ -22,6 +22,13 @@ Button {
hoverEnabled: true
opacity: root.enabled ? 1 : 0.5
Behavior on colBackground {
animation: Appearance.animation.elementMoveFast.colorAnimation.createObject(this)
}
Behavior on colForeground {
animation: Appearance.animation.elementMoveFast.colorAnimation.createObject(this)
}
HoverHandler {
cursorShape: root.enabled ? Qt.PointingHandCursor : Qt.ArrowCursor
}
@@ -33,10 +33,6 @@ AbstractCombinedProgressBar {
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"
@@ -46,6 +42,11 @@ AbstractCombinedProgressBar {
return root.visualSegments[i][0]
}
anchors {
top: parent.top
bottom: parent.bottom
}
x: {
var result = root.availableWidth * displaySegStart;
if (!atStart) result += root.valueBarGap / 2;
@@ -56,7 +56,13 @@ Item {
property Item contentItem: GridLayout {
id: layout
columns: C.Config.options.bar.vertical ? 1 : -1
anchors.centerIn: parent
anchors {
fill: parent
leftMargin: root.vertical ? 0 : root.padding
rightMargin: root.vertical ? 0 : root.padding
topMargin: root.vertical ? root.padding : 0
bottomMargin: root.vertical ? root.padding : 0
}
property real spacing: 4
columnSpacing: spacing
rowSpacing: spacing
@@ -54,19 +54,92 @@ HBarWidgetWithPopout {
W.BoxLayout {
id: contentGrid
vertical: root.vertical
anchors.fill: parent
property int visibleChildren: children.filter(child => child.shown).length
property bool hasResourceIndicators: visibleChildren > 1 || (visibleChildren > 0 && !S.Battery.available)
anchors {
fill: parent
leftMargin: !root.vertical ? (hasResourceIndicators ? 1 : 4) : 0
topMargin: root.vertical ? 2 : 0
rightMargin: !root.vertical ? (root.endSide ? 1 : (battLoader.visible ? 0 : -3)) : 0
bottomMargin: root.vertical ? (root.endSide ? 4 : 2) : 0
}
spacing: 4
Battery {
Layout.leftMargin: !root.vertical ? (root.startSide ? 8 : 6) : 0
Layout.rightMargin: !root.vertical ? (root.endSide ? 0 : -3) : 0
Layout.bottomMargin: root.vertical ? (root.endSide ? 4 : 2) : 0
Layout.topMargin: root.vertical ? 2 : 0
AlignedFadeLoader {
shown: C.Config.options.hefty.bar.resources.showMemory || (
!battLoader.visible
&& !C.Config.options.hefty.bar.resources.showRam
&& !C.Config.options.hefty.bar.resources.showSwap
&& !C.Config.options.hefty.bar.resources.showCpu
)
sourceComponent: Memory {}
}
AlignedFadeLoader {
shown: C.Config.options.hefty.bar.resources.showRam
sourceComponent: RamOnly {}
}
AlignedFadeLoader {
shown: C.Config.options.hefty.bar.resources.showSwap
sourceComponent: SwapOnly {}
}
AlignedFadeLoader {
shown: C.Config.options.hefty.bar.resources.showCpu
sourceComponent: Cpu {}
}
AlignedFadeLoader {
id: battLoader
shown: S.Battery.available
Layout.fillWidth: root.vertical
Layout.fillHeight: !root.vertical
sourceComponent: Battery {}
}
}
}
component AlignedFadeLoader: W.FadeLoader {
Layout.alignment: root.vertical ? Qt.AlignHCenter : Qt.AlignVCenter
}
component Memory: SysResourceProgress {
valueWeights: [S.ResourceUsage.memoryTotal, S.ResourceUsage.swapTotal]
values: [S.ResourceUsage.memoryUsedPercentage, S.ResourceUsage.swapUsedPercentage]
centerChar: S.Translation.tr("Memory")[0]
}
component RamOnly: SysResourceProgress {
values: [S.ResourceUsage.memoryUsedPercentage]
centerChar: S.Translation.tr("RAM")[0]
}
component SwapOnly: SysResourceProgress {
values: [S.ResourceUsage.swapUsedPercentage]
centerChar: S.Translation.tr("Swap")[0]
}
component Cpu: SysResourceProgress {
values: [S.ResourceUsage.cpuUsage]
centerChar: S.Translation.tr("CPU")[0]
}
component SysResourceProgress: W.CombinedCircularProgress {
id: sysResProg
implicitSize: 22
valueHighlights: [C.Appearance.colors.colPrimary]
valueTroughs: [C.Appearance.colors.colSecondaryContainer]
property string centerChar: ""
W.StyledText {
renderType: Text.QtRendering
anchors.centerIn: parent
text: sysResProg.centerChar
font.pixelSize: 9
}
}
component Battery: Item {
implicitWidth: !root.vertical ? battShape.implicitWidth : battShape.implicitHeight
implicitHeight: !root.vertical ? battShape.implicitHeight : battShape.implicitWidth
@@ -105,7 +178,7 @@ HBarWidgetWithPopout {
bottomMargin: (parent.height - height) / 2
}
rotation: 180 * root.vertical
spacing: 0
spacing: 4
W.MaterialSymbol {
id: boltIcon
@@ -125,6 +198,7 @@ HBarWidgetWithPopout {
return "";
}
iconSize: C.Appearance.font.pixelSize.small
renderType: Text.QtRendering // Better than Native for small sizes
font.weight: Font.DemiBold
visible: text != ""
}
@@ -149,9 +223,12 @@ HBarWidgetWithPopout {
}
component SysInfoPopupContent: W.ChoreographerLoader {
id: sysInfoPopupContent
property bool showSettings: false
sourceComponent: W.ChoreographerGridLayout {
id: popupRoot
rowSpacing: 8
rowSpacing: 10
onShownChanged: {
if (shown) {
@@ -159,6 +236,51 @@ HBarWidgetWithPopout {
}
}
W.FlyFadeEnterChoreographable {
z: 1
Layout.fillWidth: true
Item {
anchors {
left: parent.left
right: parent.right
}
implicitHeight: popupHeaderLayout.implicitHeight
ColumnLayout {
anchors {
top: parent.top
left: parent.left
right: parent.right
}
spacing: 10
RowLayout {
id: popupHeaderLayout
Layout.fillWidth: true
W.StyledText {
Layout.fillWidth: true
text: S.Translation.tr("Resources")
elide: Text.ElideRight
font.pixelSize: C.Appearance.font.pixelSize.title
}
W.StyledIconButton {
implicitSize: C.Appearance.rounding.normal * 2
text: "settings"
iconSize: 20
onClicked: sysInfoPopupContent.showSettings = !sysInfoPopupContent.showSettings;
checked: sysInfoPopupContent.showSettings
}
}
W.FadeLoader {
shown: sysInfoPopupContent.showSettings
Layout.fillWidth: true
sourceComponent: SysInfoPopupConfig {}
}
}
}
}
W.FlyFadeEnterChoreographable {
Layout.fillWidth: true
@@ -354,6 +476,55 @@ HBarWidgetWithPopout {
}
}
component SysInfoPopupConfig: Rectangle {
implicitWidth: sysConfLayout.implicitWidth
implicitHeight: sysConfLayout.implicitHeight
radius: C.Appearance.rounding.normal
color: C.Appearance.colors.colLayer4Base
W.StyledRectangularShadow {
target: parent
z: -1
}
ColumnLayout {
id: sysConfLayout
anchors.fill: parent
W.ConfigSwitch {
buttonIcon: "pie_chart"
text: S.Translation.tr("Show memory usage")
checked: C.Config.options.hefty.bar.resources.showMemory
onCheckedChanged: {
C.Config.options.hefty.bar.resources.showMemory = checked;
}
}
W.ConfigSwitch {
buttonIcon: "memory"
text: S.Translation.tr("Show physical memory usage")
checked: C.Config.options.hefty.bar.resources.showRam
onCheckedChanged: {
C.Config.options.hefty.bar.resources.showRam = checked;
}
}
W.ConfigSwitch {
buttonIcon: "swap_horiz"
text: S.Translation.tr("Show swap")
checked: C.Config.options.hefty.bar.resources.showSwap
onCheckedChanged: {
C.Config.options.hefty.bar.resources.showSwap = checked;
}
}
W.ConfigSwitch {
buttonIcon: "planner_review"
text: S.Translation.tr("Show CPU usage")
checked: C.Config.options.hefty.bar.resources.showCpu
onCheckedChanged: {
C.Config.options.hefty.bar.resources.showCpu = checked;
}
}
}
}
component BigSmallTextPair: RowLayout {
id: txtPair
property string materialSymbol: ""