Align bar icons on a shared baseline

This commit is contained in:
David Heinemeier Hansson
2026-07-17 15:37:01 -07:00
parent 6e3b69b8da
commit 0c8c4ea26a
4 changed files with 33 additions and 24 deletions
+1
View File
@@ -343,6 +343,7 @@ QtObject {
readonly property int sizeVertical: root.barToken("size-vertical", 28)
readonly property int iconSlot: root.barToken("icon-slot", 27)
readonly property int iconCanvas: root.barToken("icon-canvas", 16)
readonly property int iconFont: root.barToken("icon-font", 13)
}
function refresh() {
+3 -2
View File
@@ -9,11 +9,12 @@ WidgetButton {
property real opticalSize: Style.bar.iconCanvas
property bool debugOpticalBounds: Quickshell.env("OMARCHY_DEBUG_BAR_ICONS") === "1"
readonly property real opticalCenterErrorX: glyph.visible ? glyph.paintedCenterX - opticalCanvas.width / 2 : 0
readonly property real opticalCenterErrorY: glyph.visible ? glyph.paintedCenterY - opticalCanvas.height / 2 : 0
readonly property real glyphBaselineY: glyph.visible ? glyph.baselineY : 0
readonly property int glyphFontSize: glyph.visible ? glyph.renderedFontSize : 0
labelVisible: false
hasVisualContent: text !== "" || iconComponent !== null
fontSize: Style.font.body
fontSize: Style.bar.iconFont
fixedWidth: vertical ? -1 : Style.bar.iconSlot
fixedHeight: vertical ? Style.bar.iconSlot : -1
+15 -18
View File
@@ -8,43 +8,31 @@ Item {
property string fontFamily: Style.font.family
property real fontSize: Style.font.body
property color color: Color.foreground
property real targetExtent: Math.min(width, height) * 0.82
property bool debugBounds: false
readonly property real baseTightWidth: Math.max(1, baseMetrics.tightBoundingRect.width)
readonly property real baseTightHeight: Math.max(1, baseMetrics.tightBoundingRect.height)
readonly property real normalizedScale: Math.min(1.5, targetExtent / Math.max(baseTightWidth, baseTightHeight))
readonly property int normalizedFontSize: Math.max(1, Math.round(fontSize * normalizedScale))
readonly property int renderedFontSize: Math.max(1, Math.round(fontSize))
readonly property real tightWidth: Math.max(1, glyphMetrics.tightBoundingRect.width)
readonly property real tightHeight: Math.max(1, glyphMetrics.tightBoundingRect.height)
readonly property real horizontalCorrection: glyph.implicitWidth / 2 - (glyphMetrics.tightBoundingRect.x + tightWidth / 2)
readonly property real verticalCorrection: glyph.implicitHeight / 2 - (glyph.baselineOffset + glyphMetrics.tightBoundingRect.y + tightHeight / 2)
readonly property real paintedCenterX: glyph.x + glyphMetrics.tightBoundingRect.x + tightWidth / 2
readonly property real paintedCenterY: glyph.y + glyph.baselineOffset + glyphMetrics.tightBoundingRect.y + tightHeight / 2
TextMetrics {
id: baseMetrics
font.family: root.fontFamily
font.pixelSize: root.fontSize
text: root.text
}
readonly property real baselineY: glyph.y + glyph.baselineOffset
TextMetrics {
id: glyphMetrics
font.family: root.fontFamily
font.pixelSize: root.normalizedFontSize
font.pixelSize: root.renderedFontSize
text: root.text
}
Text {
id: glyph
// Keep the shared line box and baseline intact. Correcting only the
// horizontal painted bounds avoids per-glyph vertical drift.
anchors.centerIn: parent
anchors.horizontalCenterOffset: root.horizontalCorrection
anchors.verticalCenterOffset: root.verticalCorrection
text: root.text
color: root.color
font.family: root.fontFamily
font.pixelSize: root.normalizedFontSize
font.pixelSize: root.renderedFontSize
renderType: Text.NativeRendering
}
@@ -55,4 +43,13 @@ Item {
border.width: 1
border.color: "#4488ff"
}
Rectangle {
visible: root.debugBounds
x: 0
y: Math.round(root.baselineY)
width: parent.width
height: 1
color: "#44ff88"
}
}
+14 -4
View File
@@ -38,8 +38,12 @@ ShellRoot {
fail(name + " optical canvas is " + icon.opticalSize)
return false
}
if (Math.abs(icon.opticalCenterErrorX) > 0.5 || Math.abs(icon.opticalCenterErrorY) > 0.5) {
fail(name + " painted bounds are over half a pixel off center by " + icon.opticalCenterErrorX + "," + icon.opticalCenterErrorY)
if (Math.abs(icon.opticalCenterErrorX) > 0.5) {
fail(name + " painted bounds are over half a pixel off center by " + icon.opticalCenterErrorX)
return false
}
if (icon.glyphFontSize !== Style.bar.iconFont) {
fail(name + " font size is " + icon.glyphFontSize)
return false
}
return true
@@ -51,6 +55,12 @@ ShellRoot {
if (!checkIcon(audio, "audio")) return
if (!checkIcon(monitor, "monitor")) return
if (!checkIcon(power, "power")) return
var baseline = bluetooth.glyphBaselineY
if (network.glyphBaselineY !== baseline || audio.glyphBaselineY !== baseline
|| monitor.glyphBaselineY !== baseline || power.glyphBaselineY !== baseline) {
fail("glyph baselines do not match")
return
}
if (vector.implicitWidth !== Style.bar.iconSlot || vector.opticalSize !== Style.bar.iconCanvas) {
fail("vector icon does not share glyph geometry")
return
@@ -96,7 +106,7 @@ output=$(timeout 15 env \
if ! grep -q 'RESULT pass' <<<"$output"; then
printf '%s\n' "$output" >&2
fail "bar icons share centered optical geometry"
fail "bar icons share slot and baseline geometry"
fi
pass "bar icons share centered optical geometry"
pass "bar icons share slot and baseline geometry"