From 6f72604f2cd33284100810f6d8669b9d8a61570c Mon Sep 17 00:00:00 2001 From: Ryan Hughes Date: Tue, 19 May 2026 15:53:58 -0400 Subject: [PATCH] Add missing alpha tokens --- default/themed/shell.toml.tpl | 60 +++++++++++------- shell/Commons/Color.qml | 74 +++++++++++++--------- shell/Ui/Button.qml | 1 - shell/Ui/PanelToolTip.qml | 1 - shell/plugins/app-launcher/AppLauncher.qml | 13 ++-- shell/plugins/bar/Bar.qml | 1 - shell/plugins/image-picker/ImagePicker.qml | 4 +- shell/plugins/menu/Menu.qml | 13 ++-- 8 files changed, 97 insertions(+), 70 deletions(-) diff --git a/default/themed/shell.toml.tpl b/default/themed/shell.toml.tpl index 01674ad5..f1335a1e 100644 --- a/default/themed/shell.toml.tpl +++ b/default/themed/shell.toml.tpl @@ -3,14 +3,16 @@ # themes//shell.toml to override any individual key. [bar] -background = "{{ background }}" -text = "{{ foreground }}" +# Alpha companions (where present) range from 0 (invisible) to 1 (opaque). +background = "{{ background }}" +background-alpha = 1.0 +text = "{{ foreground }}" # Modules calling attention to themselves (recording, voxtype, alerts, updates) -active = "{{ color1 }}" +active = "{{ color1 }}" # Cross-axis size in px. size-horizontal is the height of top/bottom bars; # size-vertical is the width of left/right bars. -size-horizontal = 26 -size-vertical = 28 +size-horizontal = 26 +size-vertical = 28 [style] # Shared control state tokens. See docs/omarchy-shell.md#interactive-states. @@ -72,28 +74,37 @@ base-size = 12 [popups] # Shared by every bar flyout. Body text inside flyouts is not separately # themable — it follows [bar].text. -background = "{{ background }}" -border = "{{ accent }}" +background = "{{ background }}" +background-alpha = 1.0 +border = "{{ accent }}" +border-alpha = 1.0 [tooltip] -# Hover tooltips across the bar, panels, and buttons. -background = "{{ background }}" -text = "{{ foreground }}" -border = "{{ foreground }}" +# Hover tooltips across the bar, panels, and buttons. background-alpha of +# 0.97 mirrors the legacy hard-coded tooltip opacity. +background = "{{ background }}" +background-alpha = 0.97 +text = "{{ foreground }}" +border = "{{ foreground }}" +border-alpha = 1.0 [notifications] -background = "{{ background }}" -text = "{{ foreground }}" +background = "{{ background }}" +background-alpha = 1.0 +text = "{{ foreground }}" # Conventionally matches the Hyprland active-window border -border = "{{ accent }}" -countdown = "{{ accent }}" +border = "{{ accent }}" +border-alpha = 1.0 +countdown = "{{ accent }}" [app-launcher] # Same six tokens as [menu], applied to the app launcher overlay. Alpha # companions go from 0 (invisible) to 1 (opaque). Defaults mirror [menu]: # subtle foreground-tinted fill on the selected row, no visible border, -# accent-colored text. +# accent-colored text. background-alpha of 0.95 mirrors the legacy +# hard-coded card translucency. background = "{{ background }}" +background-alpha = 0.95 text = "{{ foreground }}" border = "{{ foreground }}" border-alpha = 1.0 @@ -109,6 +120,7 @@ selected-border-alpha = 0.25 # cursor: a subtle foreground-tinted fill on the selected row, no visible # border, accent-colored text. Override any of these per-theme. background = "{{ background }}" +background-alpha = 1.0 text = "{{ foreground }}" border = "{{ foreground }}" border-alpha = 1.0 @@ -119,9 +131,13 @@ selected-border = "{{ foreground }}" selected-border-alpha = 0.25 [image-picker] -# Drawn at ~70% alpha as a scrim -background = "{{ background }}" -text = "{{ foreground }}" -selected-border = "{{ accent }}" -# Drawn at ~28% alpha -unselected-border = "{{ foreground }}" +# Carousel-style picker. background-alpha sets the scrim opacity behind +# the picker; unselected-border-alpha softens carousel slices that aren't +# the current selection. Defaults preserve the legacy hard-coded behavior. +background = "{{ background }}" +background-alpha = 0.5 +text = "{{ foreground }}" +selected-border = "{{ accent }}" +selected-border-alpha = 1.0 +unselected-border = "{{ foreground }}" +unselected-border-alpha = 0.28 diff --git a/shell/Commons/Color.qml b/shell/Commons/Color.qml index bce74a55..11de502a 100644 --- a/shell/Commons/Color.qml +++ b/shell/Commons/Color.qml @@ -38,63 +38,75 @@ QtObject { return Math.max(0, Math.min(1, n)) } + 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. + 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. + // 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.pick("bar.background", root.background) + property color background: root.composed("bar.background", "bar.background-alpha", root.background, 1.0) property color text: root.pick("bar.text", root.foreground) property color active: root.pick("bar.active", root.urgent) } readonly property QtObject popups: QtObject { - property color background: root.pick("popups.background", root.background) - property color border: root.pick("popups.border", root.pick("notifications.border", root.accent)) + property color background: root.composed("popups.background", "popups.background-alpha", root.background, 1.0) + property color border: root.composed("popups.border", "popups.border-alpha", root.pick("notifications.border", root.accent), 1.0) } readonly property QtObject tooltip: QtObject { - property color background: root.pick("tooltip.background", root.background) + // 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 text: root.pick("tooltip.text", root.foreground) - property color border: root.pick("tooltip.border", root.foreground) + property color border: root.composed("tooltip.border", "tooltip.border-alpha", root.foreground, 1.0) } readonly property QtObject notifications: QtObject { - property color background: root.pick("notifications.background", root.background) + property color background: root.composed("notifications.background", "notifications.background-alpha", root.background, 1.0) property color text: root.pick("notifications.text", root.foreground) - property color border: root.pick("notifications.border", root.accent) + property color border: root.composed("notifications.border", "notifications.border-alpha", root.accent, 1.0) property color countdown: root.pick("notifications.countdown", root.accent) } readonly property QtObject appLauncher: QtObject { - property color background: root.pick("app-launcher.background", root.background) + property color background: root.composed("app-launcher.background", "app-launcher.background-alpha", root.background, 0.95) property color text: root.pick("app-launcher.text", root.foreground) - property color border: root.pick("app-launcher.border", root.foreground) - property real borderAlpha: root.pickAlpha("app-launcher.border-alpha", 1.0) - property color selectedBackground: root.pick("app-launcher.selected-background", root.foreground) - property real selectedBackgroundAlpha: root.pickAlpha("app-launcher.selected-background-alpha", 0.08) + property color border: root.composed("app-launcher.border", "app-launcher.border-alpha", root.foreground, 1.0) + property color selectedBackground: root.composed("app-launcher.selected-background", "app-launcher.selected-background-alpha", root.foreground, 0.08) property color selectedText: root.pick("app-launcher.selected-text", root.accent) - property color selectedBorder: root.pick("app-launcher.selected-border", root.foreground) - property real selectedBorderAlpha: root.pickAlpha("app-launcher.selected-border-alpha", 0.0) + property color selectedBorder: root.composed("app-launcher.selected-border", "app-launcher.selected-border-alpha", root.foreground, 0.0) } readonly property QtObject menu: QtObject { - property color background: root.pick("menu.background", root.background) - property color text: root.pick("menu.text", root.foreground) - property color border: root.pick("menu.border", root.foreground) - property real borderAlpha: root.pickAlpha("menu.border-alpha", 1.0) // 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 selectedBackground: root.pick("menu.selected-background", root.pick("menu.selected", root.foreground)) - property real selectedBackgroundAlpha: root.pickAlpha("menu.selected-background-alpha", 0.08) + 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 selectedBackground: root.composed("menu.selected-background", "menu.selected-background-alpha", root.pick("menu.selected", root.foreground), 0.08) property color selectedText: root.pick("menu.selected-text", root.accent) - property color selectedBorder: root.pick("menu.selected-border", root.foreground) - property real selectedBorderAlpha: root.pickAlpha("menu.selected-border-alpha", 0.0) + property color selectedBorder: root.composed("menu.selected-border", "menu.selected-border-alpha", root.foreground, 0.0) } readonly property QtObject imagePicker: QtObject { - property color background: root.pick("image-picker.background", root.background) + // Defaults reflect what the picker hard-coded before alphas were + // themable: scrim background at 0.5, unselected carousel borders at + // 0.28, selected border fully opaque. + property color background: root.composed("image-picker.background", "image-picker.background-alpha", root.background, 0.5) property color text: root.pick("image-picker.text", root.foreground) - property color selectedBorder: root.pick("image-picker.selected-border", root.accent) - property color unselectedBorder: root.pick("image-picker.unselected-border", root.foreground) - } - - function alpha(c, opacity) { - if (!c) return Qt.rgba(0, 0, 0, opacity) - return Qt.rgba(c.r, c.g, c.b, opacity) + property color selectedBorder: root.composed("image-picker.selected-border", "image-picker.selected-border-alpha", root.accent, 1.0) + property color unselectedBorder: root.composed("image-picker.unselected-border", "image-picker.unselected-border-alpha", root.foreground, 0.28) } function loadColors(raw) { diff --git a/shell/Ui/Button.qml b/shell/Ui/Button.qml index 415d1671..1ad6df84 100644 --- a/shell/Ui/Button.qml +++ b/shell/Ui/Button.qml @@ -108,7 +108,6 @@ Rectangle { border.color: root.tooltipBorder border.width: Math.max(1, Style.normalBorderWidth) radius: 0 - opacity: 0.97 } contentItem: Text { text: root.tooltipText diff --git a/shell/Ui/PanelToolTip.qml b/shell/Ui/PanelToolTip.qml index 84d7312b..97c7da08 100644 --- a/shell/Ui/PanelToolTip.qml +++ b/shell/Ui/PanelToolTip.qml @@ -32,7 +32,6 @@ ToolTip { border.color: root.panelBorder border.width: Style.normalBorderWidth radius: Style.cornerRadius - opacity: 0.97 } contentItem: Text { diff --git a/shell/plugins/app-launcher/AppLauncher.qml b/shell/plugins/app-launcher/AppLauncher.qml index b83de13e..d2a096e0 100644 --- a/shell/plugins/app-launcher/AppLauncher.qml +++ b/shell/plugins/app-launcher/AppLauncher.qml @@ -20,13 +20,14 @@ Item { property var filteredEntries: [] // Bound to the central [app-launcher] section in shell.toml via Color.qml. - // Each surface color composes with its alpha companion at render time. + // Each color already includes its alpha companion (composed in the + // singleton), so consumers can drop them straight into a Rectangle. property color background: Color.appLauncher.background property color foreground: Color.appLauncher.text - property color border: Color.alpha(Color.appLauncher.border, Color.appLauncher.borderAlpha) - property color selectedBackground: Color.alpha(Color.appLauncher.selectedBackground, Color.appLauncher.selectedBackgroundAlpha) + property color border: Color.appLauncher.border + property color selectedBackground: Color.appLauncher.selectedBackground property color selectedText: Color.appLauncher.selectedText - property color selectedBorder: Color.alpha(Color.appLauncher.selectedBorder, Color.appLauncher.selectedBorderAlpha) + property color selectedBorder: Color.appLauncher.selectedBorder property string fontFamily: Quickshell.env("OMARCHY_MENU_FONT") || "monospace" property int cardWidth: 644 @@ -248,7 +249,7 @@ Item { height: Math.min(root.cardHeight, panel.height - Style.gapsOut * 2) radius: Style.cornerRadius anchors.centerIn: parent - color: root.withAlpha(root.background, 0.95) + color: root.background border.color: root.border border.width: 2 clip: true @@ -357,7 +358,7 @@ Item { radius: 0 color: row.hasCursor ? root.selectedBackground : "transparent" border.color: row.hasCursor ? root.selectedBorder : "transparent" - border.width: (row.hasCursor && Color.appLauncher.selectedBorderAlpha > 0) ? Math.max(1, Style.normalBorderWidth) : 0 + border.width: (row.hasCursor && root.selectedBorder.a > 0) ? Math.max(1, Style.normalBorderWidth) : 0 Item { id: iconSlot diff --git a/shell/plugins/bar/Bar.qml b/shell/plugins/bar/Bar.qml index f9032240..1436263a 100644 --- a/shell/plugins/bar/Bar.qml +++ b/shell/plugins/bar/Bar.qml @@ -687,7 +687,6 @@ Item { border.color: Color.tooltip.border border.width: 1 radius: Style.cornerRadius - opacity: 0.97 Text { id: tooltipLabel diff --git a/shell/plugins/image-picker/ImagePicker.qml b/shell/plugins/image-picker/ImagePicker.qml index 45708be1..37f9a49d 100644 --- a/shell/plugins/image-picker/ImagePicker.qml +++ b/shell/plugins/image-picker/ImagePicker.qml @@ -440,7 +440,7 @@ Item { Rectangle { anchors.fill: parent visible: root.opened && root.imagesLoaded - color: root.withAlpha(root.background, 0.5) + color: root.background } MouseArea { @@ -592,7 +592,7 @@ Item { preferredRendererType: Shape.CurveRenderer ShapePath { fillColor: "transparent" - strokeColor: item.selected ? root.selectedBorder : root.withAlpha(root.unselectedBorder, 0.28) + strokeColor: item.selected ? root.selectedBorder : root.unselectedBorder strokeWidth: item.selected ? 3 : 1 startX: item.topLeft; startY: 0 PathLine { x: item.topRight; y: 0 } diff --git a/shell/plugins/menu/Menu.qml b/shell/plugins/menu/Menu.qml index 7d15edd9..012e511f 100644 --- a/shell/plugins/menu/Menu.qml +++ b/shell/plugins/menu/Menu.qml @@ -62,14 +62,15 @@ Item { property var navStack: [] property var providersLoaded: ({}) property var providerQueue: [] - // Bound to the central [menu] section in shell.toml via Color.qml. Each - // surface color composes with its alpha companion at render time. + // Bound to the central [menu] section in shell.toml via Color.qml. + // Each color already includes its alpha companion (composed in the + // singleton), so consumers can drop them straight into a Rectangle. property color background: Color.menu.background property color foreground: Color.menu.text - property color border: Color.alpha(Color.menu.border, Color.menu.borderAlpha) - property color selectedBackground: Color.alpha(Color.menu.selectedBackground, Color.menu.selectedBackgroundAlpha) + property color border: Color.menu.border + property color selectedBackground: Color.menu.selectedBackground property color selectedText: Color.menu.selectedText - property color selectedBorder: Color.alpha(Color.menu.selectedBorder, Color.menu.selectedBorderAlpha) + property color selectedBorder: Color.menu.selectedBorder readonly property int cornerRadius: Style.cornerRadius property int contentMargin: Style.spacing.panelPadding property int headerHeight: Math.max(Style.space(34), Style.font.title + Style.spacing.controlPaddingY * 2) @@ -1083,7 +1084,7 @@ Item { radius: root.cornerRadius color: row.hasCursor ? root.selectedBackground : "transparent" border.color: row.hasCursor ? root.selectedBorder : "transparent" - border.width: (row.hasCursor && Color.menu.selectedBorderAlpha > 0) ? Style.hoverBorderWidth : 0 + border.width: (row.hasCursor && root.selectedBorder.a > 0) ? Style.hoverBorderWidth : 0 Rectangle { visible: false