Re-implement better scaling with new icon spacing

This commit is contained in:
Ryan Hughes
2026-05-22 13:30:53 -04:00
parent 20cfa2f84e
commit e8fc2ef08f
8 changed files with 110 additions and 64 deletions
+47 -19
View File
@@ -19,10 +19,12 @@ import Quickshell.Io
// Typography, spacing, and bar size come from theme/shell.toml.
// `[font] base-size` is the rem root; every `Style.font.<token>` derives
// from it via the scale multipliers below unless the theme pins that
// specific token. `[spacing] scale` multiplies shared margins, gaps, and
// padding while preserving each component's proportions. `[bar]
// specific token. `[spacing] scale` multiplies shared margins, gaps,
// padding, controls, and panel dimensions while preserving each component's
// proportions; by default it also tracks `base-size`. `[bar]
// size-horizontal` / `size-vertical` set the cross-axis dimension for
// top/bottom and left/right bars respectively.
// top/bottom and left/right bars at the default 12px font size; by default
// those dimensions scale with `base-size` so larger fonts don't clip.
QtObject {
id: root
@@ -204,12 +206,14 @@ QtObject {
// fractional geometry); themes can make the shell denser or roomier
// with `[spacing] scale`, or pin individual tokens.
property real spacingScale: 1.0
property bool spacingScaleWithFont: true
property var spacingOverrides: ({})
readonly property real effectiveSpacingScale: spacingScale * (spacingScaleWithFont ? fontScale : 1)
function spaceReal(px) {
var n = Number(px)
if (!isFinite(n) || n <= 0) return 0
return n * spacingScale
return n * effectiveSpacingScale
}
function space(px) {
@@ -225,7 +229,7 @@ QtObject {
}
readonly property QtObject spacing: QtObject {
readonly property real scale: root.spacingScale
readonly property real scale: root.effectiveSpacingScale
readonly property int hairline: root.space(1)
readonly property int xxs: root.spacingToken("xxs", 2)
@@ -270,12 +274,14 @@ QtObject {
// read `resolvedFontFamily` when you want to *display* what's drawing.
property string resolvedFontFamily: "monospace"
// Clamped 11..13 by applyShellValues — some row heights remain fixed,
// so unbounded type growth can still clip even with scalable spacing.
// The only sanity floor is 1px. Themes and users can make this as large
// as they like; if the shell gets ridiculous, that's their call.
property int fontBaseSize: 12
property var fontOverrides: ({})
property var barOverrides: ({})
property bool barScaleWithFont: true
readonly property real fontScale: Math.max(1 / 12, fontBaseSize / 12)
function fontPx(mult) {
return Math.max(1, Math.round(fontBaseSize * mult))
@@ -290,7 +296,17 @@ QtObject {
function barToken(key, fallback) {
var v = barOverrides[key]
var n = Number(v)
return (isFinite(n) && n > 0) ? Math.round(n) : fallback
var base = (isFinite(n) && n > 0) ? n : fallback
if (barScaleWithFont) base *= fontScale
return Math.max(1, Math.round(base))
}
function boolToken(value, fallback) {
if (value === undefined || value === null) return fallback
var s = String(value).replace(/^\s+|\s+$/g, "").toLowerCase()
if (s === "true" || s === "1" || s === "yes" || s === "on") return true
if (s === "false" || s === "0" || s === "no" || s === "off") return false
return fallback
}
// The launcher, menu, polkit, emojis, and clipboard surfaces honor an
@@ -368,6 +384,8 @@ QtObject {
var spacingOut = {}
var nextBase = 12
var nextSpacingScale = 1.0
var nextSpacingScaleWithFont = true
var nextBarScaleWithFont = true
var v = values || {}
for (var fullKey in v) {
var dot = fullKey.indexOf(".")
@@ -380,28 +398,38 @@ QtObject {
if (!isFinite(ival)) continue
if (key === "base-size") nextBase = ival
else fontOut[key] = ival
} else if (section === "bar" && (key === "size-horizontal" || key === "size-vertical")) {
var b = parseInt(raw, 10)
if (isFinite(b)) barOut[key] = b
} else if (section === "bar") {
if (key === "scale-with-font") {
nextBarScaleWithFont = boolToken(raw, nextBarScaleWithFont)
} else if (key === "size-horizontal" || key === "size-vertical") {
var b = parseInt(raw, 10)
if (isFinite(b)) barOut[key] = b
}
} else if (section === "spacing") {
var fval = parseFloat(raw)
if (!isFinite(fval)) continue
if (key === "scale") nextSpacingScale = fval
else spacingOut[key] = fval
if (key === "scale-with-font") {
nextSpacingScaleWithFont = boolToken(raw, nextSpacingScaleWithFont)
} else {
var fval = parseFloat(raw)
if (!isFinite(fval)) continue
if (key === "scale") nextSpacingScale = fval
else spacingOut[key] = fval
}
} else if (section === "controls") {
// Strings are passed through; styleRawNum/styleString coerce on read.
styleOut[key] = raw
}
}
// Clamp the rem root. Per-token overrides aren't clamped — a theme
// that wants display-large = 64 should be allowed to ship it.
if (nextBase < 11) nextBase = 11
if (nextBase > 13) nextBase = 13
// Keep only a 1px sanity floor. Per-token overrides aren't clamped
// either — a theme that wants display-large = 64 should be allowed to
// ship it.
if (!isFinite(nextBase) || nextBase < 1) nextBase = 1
if (!isFinite(nextSpacingScale) || nextSpacingScale < 0) nextSpacingScale = 1.0
spacingScale = nextSpacingScale
spacingScaleWithFont = nextSpacingScaleWithFont
fontBaseSize = nextBase
fontOverrides = fontOut
barOverrides = barOut
barScaleWithFont = nextBarScaleWithFont
spacingOverrides = spacingOut
styleOverrides = styleOut
}
+2 -2
View File
@@ -40,8 +40,8 @@ PanelWindow {
property var owner: null
property int margin: Style.gapsOut
property int padding: Style.spacing.popupPadding
property int contentWidth: 280
property int contentHeight: 200
property int contentWidth: Style.space(280)
property int contentHeight: Style.space(200)
property bool open: false
property int gap: Style.gapsOut // distance between bar edge and panel
property bool popoutSwitching: false
+2 -2
View File
@@ -11,8 +11,8 @@ PopupWindow {
property var owner: null
property int margin: Style.gapsOut
property int padding: Style.spacing.popupPadding
property int contentWidth: 280
property int contentHeight: 200
property int contentWidth: Style.space(280)
property int contentHeight: Style.space(200)
property color borderColor: Color.popups.border
property bool open: false
property bool centerOnBar: false
+15 -12
View File
@@ -18,7 +18,10 @@ BarWidget {
readonly property var drawerItems: bucket("drawer")
readonly property var allItems: bucket("all")
readonly property int drawerCount: drawerItems.length
readonly property int drawerExtent: drawerCount > 0 ? drawerCount * 16 + (drawerCount - 1) * 17 : 0
readonly property int trayItemExtent: Style.space(16)
readonly property int trayItemGap: Style.space(17)
readonly property int trayJoinGap: Style.space(6)
readonly property int drawerExtent: drawerCount > 0 ? drawerCount * trayItemExtent + (drawerCount - 1) * trayItemGap : 0
// Match Waybar's group/tray-expander drawer transition-duration.
readonly property int animationDuration: 600
property real revealProgress: expanded ? 1 : 0
@@ -173,7 +176,7 @@ BarWidget {
id: trayIcons
x: root.drawerExtent - root.revealExtent
anchors.verticalCenter: parent.verticalCenter
spacing: Style.space(17)
spacing: root.trayItemGap
layer.enabled: true
Repeater {
@@ -188,8 +191,8 @@ BarWidget {
id: pinnedRow
x: drawerArea.x + horizontalTrayRoot.drawerBlockWidth
anchors.verticalCenter: parent.verticalCenter
spacing: Style.space(17)
leftPadding: root.pinnedItems.length > 0 && root.allItems.length > 0 ? Style.space(6) : 0
spacing: root.trayItemGap
leftPadding: root.pinnedItems.length > 0 && root.allItems.length > 0 ? root.trayJoinGap : 0
Repeater {
model: root.pinnedItems
TrayItem {}
@@ -258,7 +261,7 @@ BarWidget {
id: trayIcons
y: root.drawerExtent - root.revealExtent
anchors.horizontalCenter: parent.horizontalCenter
spacing: Style.space(17)
spacing: root.trayItemGap
layer.enabled: true
Repeater {
@@ -273,8 +276,8 @@ BarWidget {
id: pinnedCol
y: drawerArea.y + verticalTrayRoot.drawerBlockHeight
anchors.horizontalCenter: parent.horizontalCenter
spacing: Style.space(17)
topPadding: root.pinnedItems.length > 0 && root.allItems.length > 0 ? Style.space(6) : 0
spacing: root.trayItemGap
topPadding: root.pinnedItems.length > 0 && root.allItems.length > 0 ? root.trayJoinGap : 0
Repeater {
model: root.pinnedItems
TrayItem {}
@@ -407,14 +410,14 @@ BarWidget {
required property var modelData
visible: modelData.status !== Status.Passive
implicitWidth: visible ? 16 : 0
implicitHeight: visible ? 16 : 0
implicitWidth: visible ? root.trayItemExtent : 0
implicitHeight: visible ? root.trayItemExtent : 0
IconImage {
anchors.centerIn: parent
implicitSize: 12
width: 12
height: 12
implicitSize: Style.space(12)
width: Style.space(12)
height: Style.space(12)
source: root.trayIconSource(trayItemRoot.modelData.icon)
}
+1 -1
View File
@@ -60,7 +60,7 @@ BarWidget {
opacity: occupied || focused ? 1 : 0.5
horizontalMargin: 6
verticalPadding: 6
fixedWidth: root.vertical ? root.barSize : 22
fixedWidth: root.vertical ? root.barSize : Style.space(22)
fixedHeight: root.barSize
onPressed: function() { root.focusWorkspace(modelData) }
}
+6 -5
View File
@@ -445,11 +445,12 @@ Item {
}
Text {
text: "Style.font.* is the shell-wide type scale. Themes ship a single "
+ "[font] base-size in shell.toml (clamped 11..13); every token derives from "
+ "it via a fixed multiplier, so changing base-size rescales the whole shell "
+ "proportionally. Themes can also pin individual tokens (caption, heading, "
+ "display, etc.) for stylistic emphasis. The family follows the fontconfig "
+ "monospace alias \u2014 set it with `omarchy font set <name>`."
+ "[font] base-size in shell.toml; every token derives from it via a "
+ "fixed multiplier, so changing base-size rescales the whole shell "
+ "proportionally. There is no upper clamp. Themes can also pin "
+ "individual tokens (caption, heading, display, etc.) for stylistic "
+ "emphasis. The family follows the fontconfig monospace alias \u2014 "
+ "set it with `omarchy font set <name>`."
color: Qt.darker(root.foreground, 1.5)
font.family: root.fontFamily
font.pixelSize: Style.font.bodySmall