From 042271637469d46b65e8d7ded6bdad4b44f951a1 Mon Sep 17 00:00:00 2001 From: Ryan Hughes Date: Tue, 19 May 2026 18:06:08 -0400 Subject: [PATCH] More cleanup --- default/themed/shell.toml.tpl | 43 ++++- shell/Commons/Color.qml | 69 +++----- shell/Commons/Style.qml | 193 +++++++-------------- shell/plugins/background/Background.qml | 11 +- shell/plugins/image-picker/ImagePicker.qml | 10 +- shell/plugins/notifications/Service.qml | 8 +- shell/shell.qml | 9 +- 7 files changed, 146 insertions(+), 197 deletions(-) diff --git a/default/themed/shell.toml.tpl b/default/themed/shell.toml.tpl index e1ffb521..bdbc4998 100644 --- a/default/themed/shell.toml.tpl +++ b/default/themed/shell.toml.tpl @@ -49,8 +49,36 @@ pressed-fill-alpha = 0.22 selection-fill-alpha = 0.35 [spacing] -# Multiplies shared margins, gaps, and padding. See docs/omarchy-shell.md#spacing. +# `scale` multiplies shared margins, gaps, and padding; components keep +# their proportions. Per-token overrides (in px) below pin individual +# values without affecting the rest of the scale. Uncomment any to tune +# a specific surface. scale = 1.0 +# xxs = 2 +# xs = 3 +# sm = 4 +# md = 6 +# lg = 8 +# xl = 10 +# xxl = 12 +# xxxl = 14 +# huge = 18 +# control-gap = 8 +# control-padding-x = 10 +# control-padding-y = 6 +# input-padding-y = 7 +# control-height = 28 +# popup-row-height = 28 +# row-gap = 8 +# row-padding-x = 12 +# label-gap = 4 +# panel-gap = 14 +# panel-padding = 18 +# popup-padding = 14 +# dropdown-width = 240 +# searchable-dropdown-width = 260 +# number-field-width = 120 +# searchable-popup-min-height = 220 [font] # base-size is the rem root for the type scale. Every Style.font. @@ -138,7 +166,8 @@ selected-border-alpha = 0.25 # Polkit authentication prompt (sudo/password dialogs). scrim is the # darkening layer behind the card; background is the card itself. # text-error tints the lock icon, password text, and placeholder when -# authentication fails. +# authentication fails. border-alpha applies to both border and +# border-error (the two states are mutually exclusive in time). background = "{{ background }}" background-alpha = 1.0 text = "{{ foreground }}" @@ -155,6 +184,8 @@ accent = "{{ accent }}" # Lock screen password input. background/background-alpha control the # centered input field card; border/border-active/border-error cycle # through idle, typing/authenticating, and wrong-password states. +# border-alpha applies to all three border states (they are mutually +# exclusive in time). background = "{{ background }}" background-alpha = 0.8 text = "{{ foreground }}" @@ -168,12 +199,10 @@ selection = "{{ accent }}" selection-alpha = 0.45 [image-picker] -# Carousel-style picker. The picker has no separate card surface, so -# `scrim` is the full-screen wash. `background` is the underlying color -# used for per-slice dim overlays and text outlines on top of the scrim. +# Carousel-style picker. The picker has no card surface, so `scrim` is +# the full-screen wash. Per-slice dim overlays and text outlines on top +# of the scrim track the foundational background color directly. # unselected-border-alpha softens carousel slices that aren't selected. -background = "{{ background }}" -background-alpha = 1.0 scrim = "{{ background }}" scrim-alpha = 0.5 text = "{{ foreground }}" diff --git a/shell/Commons/Color.qml b/shell/Commons/Color.qml index a3b904fb..9170e4e4 100644 --- a/shell/Commons/Color.qml +++ b/shell/Commons/Color.qml @@ -3,25 +3,20 @@ import QtQuick import Quickshell import Quickshell.Io -// Single source of truth for shell color surfaces. Top-level tokens -// (foreground/background/accent/urgent) come from the theme's colors.toml. -// Per-surface roles (Color.bar.*, Color.popups.*, Color.tooltip.*, -// Color.notifications.*, Color.menu.*, Color.appLauncher.*, -// Color.imagePicker.*, Color.polkit.*, Color.lock.*) come from shell.toml, -// which is generated -// per theme from default/themed/shell.toml.tpl (or shipped directly by a -// theme to override). Surfaces that don't appear in shell.toml fall back to -// the foundational palette, so themes can ship partial overrides. +// Color surfaces for the shell. Foundational palette (foreground, background, +// accent, urgent) comes from theme/colors.toml. Per-surface roles come from +// theme/shell.toml — generated per theme from default/themed/shell.toml.tpl, +// or shipped directly by a theme to override individual keys. Surfaces that +// don't appear in shell.toml fall back to the foundational palette. QtObject { id: root - // Foundational palette. Live updated from theme/colors.toml. property color foreground: "#cacccc" property color background: "#101315" property color accent: "#cacccc" property color urgent: "#a55555" - // Flat dictionary of "section.key" -> "#rrggbb" parsed from shell.toml. + // Flat dictionary of "section.key" -> raw string from shell.toml. // Reassigning this whole property is what makes surface bindings below // re-evaluate when the theme swaps; mutating it in place would not. property var shellValues: ({}) @@ -41,24 +36,15 @@ QtObject { function alpha(c, opacity) { if (!c) return Qt.rgba(0, 0, 0, opacity) - // pick() returns raw strings from shell.toml; convert to a color object - // so .r/.g/.b are defined. Color objects pass through unchanged. if (typeof c === "string") c = Qt.color(c) return Qt.rgba(c.r, c.g, c.b, opacity) } - // Compose a color from a base-color key and its `-alpha` companion, - // applying the alpha to the resolved color. Used by every surface that - // exposes an alpha companion so consumers can read a single ready-to-use - // value rather than composing themselves. + // Compose a color from a base-color key and its `-alpha` companion. function composed(colorKey, alphaKey, colorFallback, alphaFallback) { return alpha(pick(colorKey, colorFallback), pickAlpha(alphaKey, alphaFallback)) } - // Surface roles. Each property reads its shell.toml override if set, - // otherwise falls back to a foundational palette token. Color values are - // pre-composed with their `-alpha` companion where one exists, so - // consumers can drop them straight into a Rectangle.color binding. readonly property QtObject bar: QtObject { property color background: root.composed("bar.background", "bar.background-alpha", root.background, 1.0) property color text: root.pick("bar.text", root.foreground) @@ -67,12 +53,10 @@ QtObject { readonly property QtObject popups: QtObject { property color background: root.composed("popups.background", "popups.background-alpha", root.background, 1.0) property color text: root.pick("popups.text", root.foreground) - property color border: root.composed("popups.border", "popups.border-alpha", root.pick("notifications.border", root.accent), 1.0) + property color border: root.composed("popups.border", "popups.border-alpha", root.accent, 1.0) } readonly property QtObject tooltip: QtObject { - // Default background-alpha 0.97 matches the legacy tooltip opacity so - // existing themes look identical until they override it. - property color background: root.composed("tooltip.background", "tooltip.background-alpha", root.background, 0.97) + property color background: root.composed("tooltip.background", "tooltip.background-alpha", root.background, 1.0) property color text: root.pick("tooltip.text", root.foreground) property color border: root.composed("tooltip.border", "tooltip.border-alpha", root.foreground, 1.0) } @@ -83,7 +67,7 @@ QtObject { property color countdown: root.pick("notifications.countdown", root.accent) } readonly property QtObject appLauncher: QtObject { - property color background: root.composed("app-launcher.background", "app-launcher.background-alpha", root.background, 0.95) + property color background: root.composed("app-launcher.background", "app-launcher.background-alpha", root.background, 1.0) property color text: root.pick("app-launcher.text", root.foreground) property color border: root.composed("app-launcher.border", "app-launcher.border-alpha", root.foreground, 1.0) property color scrim: root.composed("app-launcher.scrim", "app-launcher.scrim-alpha", root.background, 0.5) @@ -92,17 +76,17 @@ QtObject { property color selectedBorder: root.composed("app-launcher.selected-border", "app-launcher.selected-border-alpha", root.foreground, 0.0) } readonly property QtObject menu: QtObject { - // Defaults mirror the panel cursor: a subtle foreground-tint fill, - // no visible border, accent text. Themes override any of these - // (including the alpha companions) per surface. property color background: root.composed("menu.background", "menu.background-alpha", root.background, 1.0) property color text: root.pick("menu.text", root.foreground) property color border: root.composed("menu.border", "menu.border-alpha", root.foreground, 1.0) property color scrim: root.composed("menu.scrim", "menu.scrim-alpha", root.background, 0.5) - property color selectedBackground: root.composed("menu.selected-background", "menu.selected-background-alpha", root.pick("menu.selected", root.foreground), 0.08) + property color selectedBackground: root.composed("menu.selected-background", "menu.selected-background-alpha", root.foreground, 0.08) property color selectedText: root.pick("menu.selected-text", root.accent) property color selectedBorder: root.composed("menu.selected-border", "menu.selected-border-alpha", root.foreground, 0.0) } + // polkit + lock share a single border-alpha across border / border-active / + // border-error: the three states are mutually exclusive in time, so one + // companion is enough. readonly property QtObject polkit: QtObject { property color background: root.composed("polkit.background", "polkit.background-alpha", root.background, 1.0) property color text: root.pick("polkit.text", root.foreground) @@ -121,11 +105,10 @@ QtObject { property color borderError: root.composed("lock.border-error", "lock.border-alpha", root.urgent, 1.0) property color selection: root.composed("lock.selection", "lock.selection-alpha", root.accent, 0.45) } + // The image picker has no card surface; `scrim` is the full-screen dim + // wash, and per-slice dim overlays / text outlines use the foundational + // `background` color directly. readonly property QtObject imagePicker: QtObject { - // The picker has no separate card; `scrim` is the full-screen dim - // wash, `background` is the palette color used for per-slice dim - // overlays and text outlines on top of the scrim. - property color background: root.composed("image-picker.background", "image-picker.background-alpha", root.background, 1.0) property color scrim: root.composed("image-picker.scrim", "image-picker.scrim-alpha", root.background, 0.5) property color text: root.pick("image-picker.text", root.foreground) property color selectedBorder: root.composed("image-picker.selected-border", "image-picker.selected-border-alpha", root.accent, 1.0) @@ -142,9 +125,8 @@ QtObject { if (match[1] === "foreground") foreground = match[2] else if (match[1] === "background") background = match[2] // Prefer the explicit `accent` key; only fall back to color4 when the - // theme doesn't define a separate accent. Aether/oodle/etc define both, - // and color4 appears later in the file so the old single-property - // approach was clobbering accent with color4 (#8274fd purple). + // theme doesn't define a separate accent. color4 appears later in the + // file so the old single-property approach clobbered accent with it. else if (match[1] === "accent") { accent = match[2]; foundAccent = true } else if (match[1] === "color4") color4Value = match[2] else if (match[1] === "red" || match[1] === "color1") urgent = match[2] @@ -152,11 +134,10 @@ QtObject { if (!foundAccent && color4Value.length > 0) accent = color4Value } - // Walk shell.toml line-by-line. The file is small, so no proper TOML - // parser. Accepts double- or single-quoted strings for colors and bare - // numeric values (e.g. alpha companions like `selected-background-alpha - // = 0.08`), and tolerates trailing inline comments. Numbers are kept as - // strings here; pickAlpha() coerces and clamps when read. + // Single TOML walker for shell.toml. Both Color (surface roles) and Style + // (typography, spacing, bar, control states) consume the resulting dict. + // Accepts quoted strings and bare numeric values; tolerates inline comments. + // Numbers are kept as strings here — readers coerce when they pull a value. function loadShell(raw) { var parsed = {} var text = String(raw || "") @@ -170,12 +151,14 @@ QtObject { if (sectionMatch) { section = sectionMatch[1]; continue } var stringKv = line.match(/^([A-Za-z0-9_-]+)\s*=\s*["']([^"']+)["']\s*(#.*)?$/) var numKv = line.match(/^([A-Za-z0-9_-]+)\s*=\s*(-?\d+(?:\.\d+)?)\s*(#.*)?$/) - var kv = stringKv || numKv + var bareKv = line.match(/^([A-Za-z0-9_-]+)\s*=\s*([A-Za-z][A-Za-z0-9_-]*)\s*(#.*)?$/) + var kv = stringKv || numKv || bareKv if (!kv || !section) continue parsed[section + "." + kv[1]] = kv[2] } } shellValues = parsed + Style.applyShellValues(parsed) } // Startup load only. Runtime theme switches push the payload explicitly diff --git a/shell/Commons/Style.qml b/shell/Commons/Style.qml index 2d37a8db..8a881f01 100644 --- a/shell/Commons/Style.qml +++ b/shell/Commons/Style.qml @@ -5,15 +5,15 @@ import Quickshell.Io // Shared structural style tokens for the shell. Color is the palette // singleton; Style holds everything else themes can influence — corner -// rounding, state affordances, spacing, typography scale, and bar -// dimensions — so panels and qs.Ui components have a single source of -// truth. +// rounding, gap to screen edges, state affordances, spacing, typography +// scale, and bar dimensions. // -// `cornerRadius` mirrors Hyprland's `decoration:rounding`. Themes and user -// Hyprland config own that value; the shell picks it up by re-running -// `hyprctl getoption` on startup and after theme IPC applies a theme. +// `cornerRadius` mirrors Hyprland's `decoration:rounding`, and `gapsOut` +// mirrors `general:gaps_out`. Themes and user Hyprland config own those +// values; the shell picks them up by re-running `hyprctl getoption` on +// startup and after theme IPC applies a theme. // -// Typography, spacing, and bar size come from `theme/shell.toml`. +// Typography, spacing, and bar size come from theme/shell.toml. // `[font] base-size` is the rem root; every `Style.font.` derives // from it via the scale multipliers below unless the theme pins that // specific token. `[spacing] scale` multiplies shared margins, gaps, and @@ -29,41 +29,25 @@ QtObject { // ---------------------------------------------------------- state tokens // // Shared interactive-state tokens for every reusable surface in the kit. - // The vocabulary is intentionally small: + // The vocabulary: // normal — idle control chrome // hover-cursor — mouse hover OR panel keyboard cursor (`hasCursor`) // selected — persistent chosen/current state // focus — actual Qt activeFocus, defaulting to hover-cursor // - // Each state has a color token plus fill/border alphas. Color tokens may - // be palette roles (`foreground`, `accent`, `urgent`, `background`) or - // hex colors. Border widths are the on/off switch themes can use: set a - // state width to 0 to remove that state border everywhere. Legacy - // `border-width`, `idle-border-alpha`, `hover-*`, and `hot-fill-alpha` - // remain supported aliases for existing theme shell.toml files. + // Each state has a color token plus fill/border alphas. Color tokens + // may be palette roles (`foreground`, `accent`, `urgent`, `background`) + // or hex colors. Set a state's border width to 0 to drop that border. property var styleOverrides: ({}) - function keyList(keys) { - return (typeof keys === "string") ? [keys] : keys - } - function styleRawNum(key) { var v = styleOverrides[key] var n = Number(v) return isFinite(n) ? n : null } - function styleRawNumAny(keys) { - var list = keyList(keys) - for (var i = 0; i < list.length; i++) { - var n = styleRawNum(list[i]) - if (n !== null) return n - } - return null - } - - function styleNum(keys, fallback) { - var n = styleRawNumAny(keys) + function styleNum(key, fallback) { + var n = styleRawNum(key) return n === null ? fallback : n } @@ -73,54 +57,40 @@ QtObject { return Math.max(0, Math.min(1, n)) } - function styleAlpha(keys, fallback) { - return clampAlpha(styleNum(keys, fallback)) + function styleAlpha(key, fallback) { + return clampAlpha(styleNum(key, fallback)) } - function styleString(keys, fallback) { - var list = keyList(keys) - for (var i = 0; i < list.length; i++) { - var v = styleOverrides[list[i]] - if (typeof v !== "string") continue - v = v.replace(/^\s+|\s+$/g, "") - if (v.length > 0) return v - } - return fallback + function styleString(key, fallback) { + var v = styleOverrides[key] + if (typeof v !== "string") return fallback + v = v.replace(/^\s+|\s+$/g, "") + return v.length > 0 ? v : fallback } readonly property string normalColorToken: styleString("normal-color", "foreground") - readonly property string hoverColorToken: styleString(["hover-cursor-color", "hover-color"], "foreground") + readonly property string hoverColorToken: styleString("hover-cursor-color", "foreground") readonly property string selectedColorToken: styleString("selected-color", "foreground") readonly property string pressedColorToken: styleString("pressed-color", hoverColorToken) readonly property string focusColorToken: styleString("focus-color", hoverColorToken) readonly property string selectionColorToken: styleString("selection-color", "foreground") - readonly property int normalBorderWidth: Math.max(0, Math.round(styleNum(["normal-border-width", "border-width"], 1))) - readonly property int hoverBorderWidth: Math.max(0, Math.round(styleNum(["hover-cursor-border-width", "hover-border-width"], normalBorderWidth))) + readonly property int normalBorderWidth: Math.max(0, Math.round(styleNum("normal-border-width", 1))) + readonly property int hoverBorderWidth: Math.max(0, Math.round(styleNum("hover-cursor-border-width", normalBorderWidth))) readonly property int selectedBorderWidth: Math.max(0, Math.round(styleNum("selected-border-width", 0))) readonly property int focusBorderWidth: Math.max(0, Math.round(styleNum("focus-border-width", hoverBorderWidth))) - // Back-compat names used by older components / third-party plugins. - readonly property int borderWidth: normalBorderWidth - readonly property int hoverCursorBorderWidth: hoverBorderWidth + readonly property real normalFillAlpha: styleAlpha("normal-fill-alpha", 0.04) + readonly property real hoverFillAlpha: styleAlpha("hover-cursor-fill-alpha", 0.08) + readonly property real selectedFillAlpha: styleAlpha("selected-fill-alpha", 0.18) + readonly property real pressedFillAlpha: styleAlpha("pressed-fill-alpha", 0.22) + readonly property real focusFillAlpha: styleAlpha("focus-fill-alpha", hoverFillAlpha) + readonly property real selectionFillAlpha: styleAlpha("selection-fill-alpha", 0.35) - readonly property real normalFillAlpha: styleAlpha("normal-fill-alpha", 0.04) - readonly property real hoverFillAlpha: styleAlpha(["hover-cursor-fill-alpha", "hover-fill-alpha", "hot-fill-alpha"], 0.08) - readonly property real selectedFillAlpha: styleAlpha("selected-fill-alpha", 0.18) - readonly property real pressedFillAlpha: styleAlpha("pressed-fill-alpha", 0.22) - readonly property real focusFillAlpha: styleAlpha("focus-fill-alpha", hoverFillAlpha) - readonly property real selectionFillAlpha: styleAlpha("selection-fill-alpha", 0.35) - - readonly property real normalBorderAlpha: styleAlpha(["normal-border-alpha", "idle-border-alpha"], 0.4) - readonly property real hoverBorderAlpha: styleAlpha(["hover-cursor-border-alpha", "hover-border-alpha"], 0.25) - readonly property real selectedBorderAlpha: styleAlpha("selected-border-alpha", 1.0) - readonly property real focusBorderAlpha: styleAlpha("focus-border-alpha", hoverBorderAlpha) - - // Back-compat names used by older components / third-party plugins. - readonly property real idleBorderAlpha: normalBorderAlpha - readonly property real hotFillAlpha: hoverFillAlpha - readonly property real hoverCursorFillAlpha: hoverFillAlpha - readonly property real hoverCursorBorderAlpha: hoverBorderAlpha + readonly property real normalBorderAlpha: styleAlpha("normal-border-alpha", 0.4) + readonly property real hoverBorderAlpha: styleAlpha("hover-cursor-border-alpha", 0.25) + readonly property real selectedBorderAlpha: styleAlpha("selected-border-alpha", 1.0) + readonly property real focusBorderAlpha: styleAlpha("focus-border-alpha", hoverBorderAlpha) function alpha(c, opacity) { var a = clampAlpha(opacity) @@ -200,16 +170,13 @@ QtObject { function selectedBorderFor(foreground, accent, urgent) { return alpha(selectedStateColor(foreground, accent, urgent), selectedBorderAlpha) } function focusBorderFor(foreground, accent, urgent) { return alpha(focusStateColor(foreground, accent, urgent), focusBorderAlpha) } - // Convenience colors used by panel rows and pills. `hot*` remains as a - // compatibility alias for the hover/cursor state. + // Convenience colors resolved against the foundational palette. readonly property color normalFill: normalFillFor(Color.foreground, Color.accent, Color.urgent) readonly property color hoverFill: hoverFillFor(Color.foreground, Color.accent, Color.urgent) - readonly property color hotFill: hoverFill readonly property color selectedFill: selectedFillFor(Color.foreground, Color.accent, Color.urgent) readonly property color pressedFill: pressedFillFor(Color.foreground, Color.accent, Color.urgent) readonly property color focusFillColor: focusFillFor(Color.foreground, Color.accent, Color.urgent) readonly property color normalBorderColor: normalBorderFor(Color.foreground, Color.accent, Color.urgent) - readonly property color idleBorderColor: normalBorderColor readonly property color hoverBorderColor: hoverBorderFor(Color.foreground, Color.accent, Color.urgent) readonly property color selectedBorderColor: selectedBorderFor(Color.foreground, Color.accent, Color.urgent) readonly property color focusBorderColor: focusBorderFor(Color.foreground, Color.accent, Color.urgent) @@ -221,8 +188,8 @@ QtObject { // The spacing scale is the shell equivalent of rem for margins, gaps, // and padding. Components keep their existing proportions by asking for // the old pixel value through `Style.space(px)` (or `spaceReal(px)` for - // fractional geometry); themes can make the shell denser or roomier with - // a single `[spacing] scale` value. + // fractional geometry); themes can make the shell denser or roomier + // with `[spacing] scale`, or pin individual tokens. property real spacingScale: 1.0 property var spacingOverrides: ({}) @@ -290,13 +257,10 @@ QtObject { // read `resolvedFontFamily` when you want to *display* what's drawing. property string resolvedFontFamily: "monospace" - // Clamped 11..13 by loadShell — some row heights remain fixed, so - // unbounded type growth can still clip even with scalable spacing. + // Clamped 11..13 by applyShellValues — some row heights remain fixed, + // so unbounded type growth can still clip even with scalable spacing. property int fontBaseSize: 12 - // Parsed maps populated by loadShell. Keep them as plain dicts so - // reassigning the whole property fires reactive bindings. styleOverrides - // and spacingOverrides are declared near the helpers that consume them. property var fontOverrides: ({}) property var barOverrides: ({}) @@ -371,53 +335,39 @@ QtObject { } } - // Parse [font] base-size + per-token overrides, [bar] size-* keys, - // [controls] state colors / alphas / border widths, and [spacing] scale + - // token overrides out of shell.toml. Color.qml owns the quoted-string - // side of the surface color sections; Style owns quoted strings only - // inside [controls]. - function loadShell(raw) { + // Pull typography, bar dimensions, state tokens, and spacing out of the + // shell.toml dict that Color already parsed. Called by Color.loadShell so + // a single parse pass feeds both singletons. + function applyShellValues(values) { var fontOut = {} var barOut = {} var styleOut = {} var spacingOut = {} var nextBase = 12 var nextSpacingScale = 1.0 - var text = String(raw || "") - if (text) { - var lines = text.split("\n") - var section = "" - for (var i = 0; i < lines.length; i++) { - var line = lines[i].replace(/^\s+|\s+$/g, "") - if (!line || line.charAt(0) === "#") continue - var sectionMatch = line.match(/^\[([A-Za-z0-9_-]+)\]\s*(#.*)?$/) - if (sectionMatch) { section = sectionMatch[1]; continue } - // Accept ints/floats for numeric tokens and quoted/bare words for - // [controls] color roles / inheritance sentinels (e.g. "foreground", - // "accent", "hover-cursor", "#c0caf5"). - var numKv = line.match(/^([A-Za-z0-9_-]+)\s*=\s*(-?\d+(?:\.\d+)?)\s*(#.*)?$/) - var stringKv = line.match(/^([A-Za-z0-9_-]+)\s*=\s*["']([^"']+)["']\s*(#.*)?$/) - var bareKv = line.match(/^([A-Za-z0-9_-]+)\s*=\s*([A-Za-z][A-Za-z0-9_-]*)\s*(#.*)?$/) - var kv = numKv || stringKv || bareKv - if (!kv) continue - var key = kv[1] - var rawValue = kv[2] - if (section === "font" && numKv) { - var ival = parseInt(rawValue, 10) - if (key === "base-size") nextBase = ival - else fontOut[key] = ival - } else if (section === "bar" && numKv && (key === "size-horizontal" || key === "size-vertical")) { - barOut[key] = parseInt(rawValue, 10) - } else if (section === "spacing" && numKv) { - var fval = parseFloat(rawValue) - if (key === "scale") nextSpacingScale = fval - else spacingOut[key] = fval - } else if (section === "controls" || section === "style") { - // `[controls]` is the canonical section name; `[style]` is kept - // as a legacy alias so hand-written theme shell.toml files that - // predate the rename still apply. - styleOut[key] = numKv ? parseFloat(rawValue) : rawValue - } + var v = values || {} + for (var fullKey in v) { + var dot = fullKey.indexOf(".") + if (dot < 0) continue + var section = fullKey.substr(0, dot) + var key = fullKey.substr(dot + 1) + var raw = v[fullKey] + if (section === "font") { + var ival = parseInt(raw, 10) + 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 === "spacing") { + 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 @@ -491,8 +441,8 @@ QtObject { } // `omarchy toggle window-gaps` creates/removes this flag file. Hyprland - // reloads its config when sourced files change, then hyprctl reflects the - // new effective value. + // reloads its config when sourced files change, then hyprctl reflects + // the new effective value. property FileView windowNoGapsToggle: FileView { path: Quickshell.env("HOME") + "/.local/state/omarchy/toggles/hypr/window-no-gaps.lua" watchChanges: true @@ -502,15 +452,6 @@ QtObject { onLoadFailed: refreshTimer.restart() } - property FileView shellTomlFile: FileView { - id: shellTomlFile - path: Quickshell.env("HOME") + "/.config/omarchy/current/theme/shell.toml" - watchChanges: false - printErrors: false - onLoaded: root.loadShell(text()) - onLoadFailed: root.loadShell("") - } - Component.onCompleted: { refresh() resolveFontFamily() diff --git a/shell/plugins/background/Background.qml b/shell/plugins/background/Background.qml index 05f29ae6..c10f748f 100644 --- a/shell/plugins/background/Background.qml +++ b/shell/plugins/background/Background.qml @@ -4,7 +4,7 @@ import Quickshell.Wayland import QtQuick import QtQuick.Effects import QtQuick.Shapes -import qs.Commons as NoctaliaCommons +import qs.Commons Item { id: root @@ -74,12 +74,11 @@ Item { function applyPendingTheme() { if (pendingThemeVersion !== backgroundVersion) return - NoctaliaCommons.Color.loadColors(pendingColorsRaw) - NoctaliaCommons.Color.loadShell(pendingShellRaw) - // Push style tokens synchronously so the type scale flips with the + Color.loadColors(pendingColorsRaw) + // Color.loadShell also refreshes Style so the type scale flips with the // background reveal instead of waiting for a separate reload path. - NoctaliaCommons.Style.loadShell(pendingShellRaw) - NoctaliaCommons.Style.scheduleRefresh() + Color.loadShell(pendingShellRaw) + Style.scheduleRefresh() pendingThemeVersion = -1 pendingColorsRaw = "" pendingShellRaw = "" diff --git a/shell/plugins/image-picker/ImagePicker.qml b/shell/plugins/image-picker/ImagePicker.qml index 5f4f232d..81a5255b 100644 --- a/shell/plugins/image-picker/ImagePicker.qml +++ b/shell/plugins/image-picker/ImagePicker.qml @@ -29,7 +29,9 @@ Item { property string filterText: "" property var doneFilesToRelease: [] // Bound to the central [image-picker] section in shell.toml via Color.qml. - property color background: Color.imagePicker.background + // `dimColor` tints unselected slices and text outlines on top of the scrim; + // it intentionally tracks the foundational background, not a surface role. + property color dimColor: Color.background property color foreground: Color.imagePicker.text property color scrim: Color.imagePicker.scrim property color selectedBorder: Color.imagePicker.selectedBorder @@ -583,7 +585,7 @@ Item { Rectangle { anchors.fill: parent - color: root.withAlpha(root.background, item.selected ? 0 : 0.42) + color: root.withAlpha(root.dimColor, item.selected ? 0 : 0.42) } } @@ -622,7 +624,7 @@ Item { text: root.currentLabel() color: root.foreground style: Text.Outline - styleColor: root.withAlpha(root.background, 0.7) + styleColor: root.withAlpha(root.dimColor, 0.7) font.pixelSize: Style.font.display font.weight: Font.DemiBold horizontalAlignment: Text.AlignHCenter @@ -639,7 +641,7 @@ Item { color: root.foreground opacity: 0.85 style: Text.Outline - styleColor: root.withAlpha(root.background, 0.7) + styleColor: root.withAlpha(root.dimColor, 0.7) font.pixelSize: Style.font.title horizontalAlignment: Text.AlignHCenter elide: Text.ElideRight diff --git a/shell/plugins/notifications/Service.qml b/shell/plugins/notifications/Service.qml index 96dcaec4..7b823299 100644 --- a/shell/plugins/notifications/Service.qml +++ b/shell/plugins/notifications/Service.qml @@ -1,7 +1,4 @@ -// Notification service. Adapted from noctalia-shell (MIT) and -// DankMaterialShell (MIT). Original implementations: -// https://github.com/noctalia-dev/noctalia-shell -// https://github.com/AvengeMedia/DankMaterialShell +// Notification service for the omarchy shell. import QtQuick import QtQuick.Layouts @@ -200,8 +197,7 @@ Item { } // Qt.callLater avoids "QV4::Object::insertMember" crashes when a - // Repeater is mid-incubation while we mutate its model — see noctalia - // NotificationService.qml ~L307. + // Repeater is mid-incubation while we mutate its model. Qt.callLater(function() { removeByOriginalId(popupModel, snapshot.originalId) popupModel.insert(0, snapshot) diff --git a/shell/shell.qml b/shell/shell.qml index be9c0d97..d5cdbd59 100644 --- a/shell/shell.qml +++ b/shell/shell.qml @@ -3,7 +3,7 @@ import QtQml.Models import Quickshell import Quickshell.Io -import qs.Commons as NoctaliaCommons +import qs.Commons import "plugins/bar" import "services" @@ -582,10 +582,9 @@ ShellRoot { var shellRaw = "" try { colorsRaw = Qt.atob(String(colorsB64 || "")) } catch (e) { colorsRaw = "" } try { shellRaw = Qt.atob(String(shellB64 || "")) } catch (e2) { shellRaw = "" } - NoctaliaCommons.Color.loadColors(colorsRaw) - NoctaliaCommons.Color.loadShell(shellRaw) - NoctaliaCommons.Style.loadShell(shellRaw) - NoctaliaCommons.Style.scheduleRefresh() + Color.loadColors(colorsRaw) + Color.loadShell(shellRaw) + Style.scheduleRefresh() return "ok" }