diff --git a/quickshell/bar/Bar.qml b/quickshell/bar/Bar.qml index c35d6a2..1f0e063 100644 --- a/quickshell/bar/Bar.qml +++ b/quickshell/bar/Bar.qml @@ -52,6 +52,14 @@ PanelWindow { slash: true slashColor: Theme.accent slashWidth: 5 + + // No offset copy on the big slabs. The 3px black silhouette behind the + // fill is a print-misregistration trick, and at this scale it stops + // reading as one: on a 1900px bar you only ever see it at the chopped + // corners, where it turns the single clean cut into a staggered double + // edge that looks like a rendering fault. The black keyline still + // carries the heavy outer contour, which is what the corner needs. + drop: false } readonly property real edgeInset: Theme.barHeight * Theme.skew + Theme.padM diff --git a/quickshell/bar/Rail.qml b/quickshell/bar/Rail.qml index 02dd34c..c675215 100644 --- a/quickshell/bar/Rail.qml +++ b/quickshell/bar/Rail.qml @@ -56,6 +56,11 @@ PanelWindow { slash: true slashColor: Theme.accent slashWidth: 5 + + // Same as the bar — see the note there. The doubled corner is worse on + // the rail, because its chopped corners sit against the wallpaper's + // high-contrast stripes rather than against other chrome. + drop: false } readonly property real edgeInset: Theme.railWidth * Theme.skew + Theme.padM diff --git a/quickshell/components/MetricRow.qml b/quickshell/components/MetricRow.qml new file mode 100644 index 0000000..f4ceac1 --- /dev/null +++ b/quickshell/components/MetricRow.qml @@ -0,0 +1,91 @@ +import QtQuick +import "root:/config" +import "root:/components" + +// One metric in a popout: a label and its reading on a line, with a wide +// sheared segmented meter underneath. +// +// This replaces the radial Gauge. A 270° dial was the only curved thing in a +// shell whose whole geometry is sheared slabs and hard chamfers, so it read as +// though it had been imported from another design. The meter says the same +// thing in the language the bar and the OSD already speak, and it gets far more +// resolution across a popout's width than a 88px dial did. +Item { + id: root + + property string label: "" + property real value: 0 // 0..100 + property string readout: Math.round(root.value) + "%" + property string sub: "" + property color tone: Theme.heat(root.value) + + property int segments: 24 + property real segmentSpacing: 3 + + implicitHeight: head.height + Theme.padS + meter.height + + Item { + id: head + anchors.left: parent.left + anchors.right: parent.right + anchors.top: parent.top + height: Math.max(name.implicitHeight, figure.implicitHeight) + + Text { + id: name + anchors.left: parent.left + anchors.verticalCenter: parent.verticalCenter + text: root.label.toUpperCase() + color: Theme.subtext + font.family: Theme.fontMono + font.pixelSize: Theme.fsMicro + font.letterSpacing: 2 + renderType: Text.NativeRendering + } + + // The secondary figure — temperature, used-of-total. Sits next to the + // label rather than under the number so the right edge stays a single + // clean column of readings. + Text { + anchors.left: name.right + anchors.leftMargin: Theme.padM + anchors.right: figure.left + anchors.rightMargin: Theme.padM + anchors.verticalCenter: parent.verticalCenter + visible: root.sub !== "" + text: root.sub + color: Theme.muted + elide: Text.ElideRight + font.family: Theme.fontMono + font.pixelSize: Theme.fsMicro + renderType: Text.NativeRendering + } + + SplitText { + // Not `value` — an id by that name shadows the `value` property, and + // the defaults above then round a Text item instead of a number. + id: figure + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + text: root.readout + pixelSize: Theme.fsBody + color: Theme.text + split: 1 + splitOpacity: 0.5 + } + } + + MeterBar { + id: meter + anchors.left: parent.left + anchors.right: parent.right + anchors.bottom: parent.bottom + height: 12 + segments: root.segments + spacing: root.segmentSpacing + // Fill the row exactly rather than leaving a ragged tail on the right. + segmentWidth: (width - (root.segments - 1) * root.segmentSpacing) / root.segments + value: root.value + activeColor: root.tone + } +} diff --git a/quickshell/popouts/BatteryPopout.qml b/quickshell/popouts/BatteryPopout.qml index b15fa62..bf75bd4 100644 --- a/quickshell/popouts/BatteryPopout.qml +++ b/quickshell/popouts/BatteryPopout.qml @@ -9,7 +9,11 @@ Popout { id: root contentWidth: 310 - contentHeight: 296 + // Derived: the charge block is a different height from the dial it + // replaced, and the health line comes and goes. + contentHeight: header.height + Theme.padM + readout.height + Theme.padM + + bar.height + Theme.padM + detailText.implicitHeight + Theme.padL + + suspendButton.height + Theme.padM * 2 PopoutSurface { anchors.fill: parent @@ -26,27 +30,42 @@ Popout { subtitle: Battery.charging ? "CHARGING" : (Battery.onBattery ? "ON BATTERY" : "AC") } - Row { + // The dial that used to sit here duplicated the meter below it and was + // the only curve in the shell. The charge is now simply set large, and + // the MeterBar underneath is left to carry the level on its own. + Item { id: readout anchors.top: header.bottom anchors.topMargin: Theme.padM anchors.left: parent.left anchors.right: parent.right - spacing: Theme.padM + height: Math.max(charge.height, detail.height) - Gauge { - width: 92; height: 92 - value: Battery.percent - label: "CHARGE" - arcColor: Battery.tint - readout: Math.round(Battery.percent) + "%" + Column { + id: charge + anchors.left: parent.left + anchors.verticalCenter: parent.verticalCenter + // No "CHARGE" caption under the number. It landed directly on + // top of the meter, and between the header and a full-width + // charge bar there was nothing left for it to disambiguate. + SplitText { + text: Math.round(Battery.percent) + "%" + pixelSize: Theme.fsHuge + color: Battery.tint + split: 2.5 + splitOpacity: 0.7 + } } Column { + id: detail + anchors.right: parent.right anchors.verticalCenter: parent.verticalCenter spacing: Theme.padS SplitText { + anchors.right: parent.right + horizontalAlignment: Text.AlignRight text: Battery.timeLabel pixelSize: Theme.fsBody split: 1.1 @@ -57,6 +76,8 @@ Popout { text: Battery.changeRate > 0 ? Battery.changeRate.toFixed(1) + " W " + (Battery.charging ? "in" : "draw") : "idle" + anchors.right: parent.right + horizontalAlignment: Text.AlignRight color: Theme.subtext font.family: Theme.fontMono font.pixelSize: Theme.fsSmall @@ -66,6 +87,8 @@ Popout { Text { visible: Battery.health > 0 text: "Health " + Math.round(Battery.health) + "%" + anchors.right: parent.right + horizontalAlignment: Text.AlignRight color: Battery.health < 70 ? Theme.warn : Theme.muted font.family: Theme.fontMono font.pixelSize: Theme.fsMicro @@ -88,9 +111,26 @@ Popout { activeColor: Battery.tint } + Text { + id: detailText + anchors.top: bar.bottom + anchors.topMargin: Theme.padM + anchors.left: parent.left + anchors.right: parent.right + text: Battery.detail + wrapMode: Text.WordWrap + color: Theme.muted + font.family: Theme.fontMono + font.pixelSize: Theme.fsMicro + renderType: Text.NativeRendering + } + + // Follows the detail line rather than being pinned to the bottom of a + // fixed-height panel, which is what left a dead band above it. P5Button { id: suspendButton - anchors.bottom: parent.bottom + anchors.top: detailText.bottom + anchors.topMargin: Theme.padL anchors.left: parent.left text: "Suspend" icon: "󰤄" @@ -99,21 +139,5 @@ Popout { Actions.suspend(); } } - - Text { - anchors.top: bar.bottom - anchors.topMargin: Theme.padS - anchors.bottom: suspendButton.top - anchors.bottomMargin: Theme.padS - anchors.left: parent.left - anchors.right: parent.right - text: Battery.detail - wrapMode: Text.WordWrap - verticalAlignment: Text.AlignTop - color: Theme.muted - font.family: Theme.fontMono - font.pixelSize: Theme.fsMicro - renderType: Text.NativeRendering - } } } diff --git a/quickshell/popouts/SysPopout.qml b/quickshell/popouts/SysPopout.qml index 6b26d48..28157c3 100644 --- a/quickshell/popouts/SysPopout.qml +++ b/quickshell/popouts/SysPopout.qml @@ -9,7 +9,12 @@ Popout { id: root contentWidth: 420 - contentHeight: 268 + // Derived rather than a fixed number: the meters are taller than the dials + // they replaced, and the GPU block disappears entirely on machines without + // one. A hardcoded height would either clip or leave a hole. + contentHeight: header.height + Theme.padM + + gauges.implicitHeight + Theme.padL + + details.implicitHeight + Theme.padM * 2 PopoutSurface { anchors.fill: parent @@ -26,37 +31,38 @@ Popout { subtitle: "UP " + Sys.uptime + " · " + Sys.procs + " PROCS" } - Row { + Column { id: gauges anchors.top: header.bottom anchors.topMargin: Theme.padM - anchors.horizontalCenter: parent.horizontalCenter + anchors.left: parent.left + anchors.right: parent.right spacing: Theme.padM - Gauge { - width: 88; height: 88 + MetricRow { + width: parent.width value: Sys.cpuUsage label: "CPU" sub: Math.round(Sys.cpuTemp) + "°C" } - Gauge { - width: 88; height: 88 + MetricRow { + width: parent.width value: Sys.memPercent label: "MEM" - sub: Sys.gb(Sys.memUsed) + "/" + Sys.gb(Sys.memTotal) + sub: Sys.gb(Sys.memUsed) + " / " + Sys.gb(Sys.memTotal) } - Gauge { - width: 88; height: 88 + MetricRow { + width: parent.width visible: Sys.gpuAvailable value: Sys.gpuUsage label: "GPU" sub: Math.round(Sys.gpuTemp) + "°C" } - Gauge { - width: 88; height: 88 + MetricRow { + width: parent.width value: Sys.diskPercent label: "DISK" sub: Sys.diskFree + " free" @@ -64,8 +70,9 @@ Popout { } Column { + id: details anchors.top: gauges.bottom - anchors.topMargin: Theme.padM + anchors.topMargin: Theme.padL anchors.left: parent.left anchors.right: parent.right spacing: 3