From 6cdb8915512f80cf9f5281296d0ffe7c032778d0 Mon Sep 17 00:00:00 2001 From: purian23 Date: Thu, 2 Jul 2026 22:45:55 -0400 Subject: [PATCH] feat(matugen): add color preview pallette & outline border option theme settings - Closes #1738 --- core/cmd/dms/commands_matugen.go | 23 +++ core/internal/matugen/matugen.go | 44 ++++ .../Modals/Clipboard/ClipboardContextMenu.qml | 4 +- .../DankLauncherV2/LauncherContextMenu.qml | 4 +- .../FileBrowserItemContextMenu.qml | 4 +- .../DankBar/Widgets/AppsDockContextMenu.qml | 4 +- .../DankBar/Widgets/ClipboardButton.qml | 4 +- .../Modules/DankBar/Widgets/NotepadButton.qml | 4 +- .../Modules/DankBar/Widgets/RunningApps.qml | 4 +- .../Modules/Dock/DockContextMenuBase.qml | 4 +- .../Notifications/Center/DndDurationMenu.qml | 4 +- .../Notifications/NotificationContextMenu.qml | 4 +- .../ProcessList/ProcessContextMenu.qml | 4 +- .../Modules/Settings/ColorDropdownRow.qml | 6 +- .../Modules/Settings/ThemeColorsTab.qml | 188 ++++++++++++------ quickshell/Services/BlurService.qml | 5 +- quickshell/Widgets/DankOSD.qml | 4 +- quickshell/Widgets/DankPopoutConnected.qml | 2 +- quickshell/Widgets/DankPopoutStandalone.qml | 2 +- quickshell/Widgets/DankSlideout.qml | 2 +- quickshell/Widgets/DankTooltip.qml | 4 +- quickshell/Widgets/DankTooltipV2.qml | 2 +- .../translations/settings_search_index.json | 109 +++++----- quickshell/translations/template.json | 10 +- 24 files changed, 298 insertions(+), 147 deletions(-) diff --git a/core/cmd/dms/commands_matugen.go b/core/cmd/dms/commands_matugen.go index 566f3600f..31a9cb327 100644 --- a/core/cmd/dms/commands_matugen.go +++ b/core/cmd/dms/commands_matugen.go @@ -38,10 +38,17 @@ var matugenCheckCmd = &cobra.Command{ Run: runMatugenCheck, } +var matugenPreviewCmd = &cobra.Command{ + Use: "preview", + Short: "Preview Matugen scheme colors without applying them", + Run: runMatugenPreview, +} + func init() { matugenCmd.AddCommand(matugenGenerateCmd) matugenCmd.AddCommand(matugenQueueCmd) matugenCmd.AddCommand(matugenCheckCmd) + matugenCmd.AddCommand(matugenPreviewCmd) for _, cmd := range []*cobra.Command{matugenGenerateCmd, matugenQueueCmd} { cmd.Flags().String("state-dir", "", "State directory for cache files") @@ -62,6 +69,8 @@ func init() { matugenQueueCmd.Flags().Bool("wait", true, "Wait for completion") matugenQueueCmd.Flags().Duration("timeout", 90*time.Second, "Timeout for waiting") + matugenPreviewCmd.Flags().String("source-color", "", "Source color used to generate previews") + matugenPreviewCmd.Flags().Float64("contrast", 0, "Contrast value from -1 to 1 (0 = standard)") } func buildMatugenOptions(cmd *cobra.Command) matugen.Options { @@ -200,3 +209,17 @@ func runMatugenCheck(cmd *cobra.Command, args []string) { } fmt.Println(string(data)) } + +func runMatugenPreview(cmd *cobra.Command, args []string) { + sourceColor, _ := cmd.Flags().GetString("source-color") + contrast, _ := cmd.Flags().GetFloat64("contrast") + previews, err := matugen.PreviewSchemes(sourceColor, contrast) + if err != nil { + log.Fatalf("Failed to generate Matugen previews: %v", err) + } + data, err := json.Marshal(previews) + if err != nil { + log.Fatalf("Failed to marshal Matugen previews: %v", err) + } + fmt.Println(string(data)) +} diff --git a/core/internal/matugen/matugen.go b/core/internal/matugen/matugen.go index d03041778..063275126 100644 --- a/core/internal/matugen/matugen.go +++ b/core/internal/matugen/matugen.go @@ -118,6 +118,50 @@ type ColorsOutput struct { } `json:"colors"` } +type SchemePreview struct { + Dark string `json:"dark"` + Light string `json:"light"` +} + +var previewSchemeTypes = []string{ + "scheme-tonal-spot", + "scheme-vibrant", + "scheme-content", + "scheme-expressive", + "scheme-fidelity", + "scheme-fruit-salad", + "scheme-monochrome", + "scheme-neutral", + "scheme-rainbow", +} + +func PreviewSchemes(sourceColor string, contrast float64) (map[string]SchemePreview, error) { + if sourceColor == "" { + return nil, fmt.Errorf("source color is required") + } + + previews := make(map[string]SchemePreview, len(previewSchemeTypes)) + for _, schemeType := range previewSchemeTypes { + output, err := runMatugenDryRun(&Options{ + Kind: "hex", + Value: sourceColor, + MatugenType: schemeType, + Contrast: contrast, + }) + if err != nil { + return nil, fmt.Errorf("preview %s: %w", schemeType, err) + } + + dark := extractMatugenColor(output, "primary", "dark") + light := extractMatugenColor(output, "primary", "light") + if dark == "" || light == "" { + return nil, fmt.Errorf("preview %s: primary colors missing from matugen output", schemeType) + } + previews[schemeType] = SchemePreview{Dark: dark, Light: light} + } + return previews, nil +} + func (o *Options) ColorsOutput() string { return filepath.Join(o.StateDir, "dms-colors.json") } diff --git a/quickshell/Modals/Clipboard/ClipboardContextMenu.qml b/quickshell/Modals/Clipboard/ClipboardContextMenu.qml index a67adb669..6ab1e626a 100644 --- a/quickshell/Modals/Clipboard/ClipboardContextMenu.qml +++ b/quickshell/Modals/Clipboard/ClipboardContextMenu.qml @@ -258,8 +258,8 @@ Item { height: root.effectiveMenuHeight color: Theme.withAlpha(Theme.surfaceContainer, Theme.popupTransparency) radius: Theme.cornerRadius - border.color: BlurService.enabled ? BlurService.borderColor : Theme.outlineMedium - border.width: BlurService.enabled ? BlurService.borderWidth : 1 + border.color: BlurService.borderColor + border.width: BlurService.borderWidth opacity: root.openState ? 1 : 0 Behavior on opacity { diff --git a/quickshell/Modals/DankLauncherV2/LauncherContextMenu.qml b/quickshell/Modals/DankLauncherV2/LauncherContextMenu.qml index 8ee197bc1..5ce4aecca 100644 --- a/quickshell/Modals/DankLauncherV2/LauncherContextMenu.qml +++ b/quickshell/Modals/DankLauncherV2/LauncherContextMenu.qml @@ -518,8 +518,8 @@ Item { height: root.effectiveMenuHeight color: Theme.withAlpha(Theme.surfaceContainer, Theme.popupTransparency) radius: Theme.cornerRadius - border.color: BlurService.enabled ? BlurService.borderColor : Theme.outlineMedium - border.width: BlurService.enabled ? BlurService.borderWidth : 1 + border.color: BlurService.borderColor + border.width: BlurService.borderWidth opacity: root.openState ? 1 : 0 Behavior on opacity { diff --git a/quickshell/Modals/FileBrowser/FileBrowserItemContextMenu.qml b/quickshell/Modals/FileBrowser/FileBrowserItemContextMenu.qml index 2f84aa886..708391c6b 100644 --- a/quickshell/Modals/FileBrowser/FileBrowserItemContextMenu.qml +++ b/quickshell/Modals/FileBrowser/FileBrowserItemContextMenu.qml @@ -89,8 +89,8 @@ Popup { contentItem: Rectangle { color: Theme.floatingSurface radius: Theme.cornerRadius - border.color: BlurService.enabled ? BlurService.borderColor : Theme.outlineMedium - border.width: BlurService.enabled ? BlurService.borderWidth : 1 + border.color: BlurService.borderColor + border.width: BlurService.borderWidth Column { id: menuColumn diff --git a/quickshell/Modules/DankBar/Widgets/AppsDockContextMenu.qml b/quickshell/Modules/DankBar/Widgets/AppsDockContextMenu.qml index 9f3ed931d..bda80c16c 100644 --- a/quickshell/Modules/DankBar/Widgets/AppsDockContextMenu.qml +++ b/quickshell/Modules/DankBar/Widgets/AppsDockContextMenu.qml @@ -121,8 +121,8 @@ PanelWindow { height: Math.max(60, menuColumn.implicitHeight + Theme.spacingS * 2) color: Theme.floatingSurface radius: Theme.cornerRadius - border.color: BlurService.enabled ? BlurService.borderColor : Theme.outlineMedium - border.width: BlurService.enabled ? BlurService.borderWidth : 1 + border.color: BlurService.borderColor + border.width: BlurService.borderWidth opacity: root.visible ? 1 : 0 visible: opacity > 0 diff --git a/quickshell/Modules/DankBar/Widgets/ClipboardButton.qml b/quickshell/Modules/DankBar/Widgets/ClipboardButton.qml index 1ed21fd6f..0e535a90d 100644 --- a/quickshell/Modules/DankBar/Widgets/ClipboardButton.qml +++ b/quickshell/Modules/DankBar/Widgets/ClipboardButton.qml @@ -197,8 +197,8 @@ BasePill { height: Math.max(64, menuColumn.implicitHeight + Theme.spacingS * 2) color: Theme.withAlpha(Theme.surfaceContainer, Theme.popupTransparency) radius: Theme.cornerRadius - border.color: BlurService.enabled ? BlurService.borderColor : Theme.outlineMedium - border.width: BlurService.enabled ? BlurService.borderWidth : 1 + border.color: BlurService.borderColor + border.width: BlurService.borderWidth opacity: contextMenuWindow.visible ? 1 : 0 visible: opacity > 0 diff --git a/quickshell/Modules/DankBar/Widgets/NotepadButton.qml b/quickshell/Modules/DankBar/Widgets/NotepadButton.qml index cfac2d759..b5b30eeb5 100644 --- a/quickshell/Modules/DankBar/Widgets/NotepadButton.qml +++ b/quickshell/Modules/DankBar/Widgets/NotepadButton.qml @@ -271,8 +271,8 @@ BasePill { height: Math.max(60, menuColumn.implicitHeight + Theme.spacingS * 2) color: Theme.withAlpha(Theme.surfaceContainer, Theme.popupTransparency) radius: Theme.cornerRadius - border.color: BlurService.enabled ? BlurService.borderColor : Theme.outlineMedium - border.width: BlurService.enabled ? BlurService.borderWidth : 1 + border.color: BlurService.borderColor + border.width: BlurService.borderWidth opacity: contextMenuWindow.visible ? 1 : 0 visible: opacity > 0 diff --git a/quickshell/Modules/DankBar/Widgets/RunningApps.qml b/quickshell/Modules/DankBar/Widgets/RunningApps.qml index cb0c1706e..789d4d514 100644 --- a/quickshell/Modules/DankBar/Widgets/RunningApps.qml +++ b/quickshell/Modules/DankBar/Widgets/RunningApps.qml @@ -860,8 +860,8 @@ BasePill { height: 32 color: Theme.withAlpha(Theme.surfaceContainer, Theme.popupTransparency) radius: Theme.cornerRadius - border.width: BlurService.enabled ? BlurService.borderWidth : 1 - border.color: BlurService.enabled ? BlurService.borderColor : Theme.outlineStrong + border.width: BlurService.borderWidth + border.color: BlurService.borderColor Rectangle { anchors.fill: parent diff --git a/quickshell/Modules/Dock/DockContextMenuBase.qml b/quickshell/Modules/Dock/DockContextMenuBase.qml index 1fec294ea..f9109608f 100644 --- a/quickshell/Modules/Dock/DockContextMenuBase.qml +++ b/quickshell/Modules/Dock/DockContextMenuBase.qml @@ -157,8 +157,8 @@ PanelWindow { height: menuColumn.implicitHeight + Theme.spacingS * 2 color: Theme.withAlpha(Theme.surfaceContainer, Theme.popupTransparency) radius: Theme.cornerRadius - border.color: BlurService.enabled ? BlurService.borderColor : Theme.outlineMedium - border.width: BlurService.enabled ? BlurService.borderWidth : 1 + border.color: BlurService.borderColor + border.width: BlurService.borderWidth opacity: root.visible ? 1 : 0 visible: opacity > 0 diff --git a/quickshell/Modules/Notifications/Center/DndDurationMenu.qml b/quickshell/Modules/Notifications/Center/DndDurationMenu.qml index ffd7598b0..df8478de2 100644 --- a/quickshell/Modules/Notifications/Center/DndDurationMenu.qml +++ b/quickshell/Modules/Notifications/Center/DndDurationMenu.qml @@ -109,8 +109,8 @@ Rectangle { implicitHeight: menuColumn.implicitHeight + Theme.spacingM * 2 color: Theme.floatingSurface radius: Theme.cornerRadius - border.color: BlurService.enabled ? BlurService.borderColor : Theme.outlineStrong - border.width: BlurService.enabled ? BlurService.borderWidth : 1 + border.color: BlurService.borderColor + border.width: BlurService.borderWidth Column { id: menuColumn diff --git a/quickshell/Modules/Notifications/NotificationContextMenu.qml b/quickshell/Modules/Notifications/NotificationContextMenu.qml index ab64f206d..d28863b8a 100644 --- a/quickshell/Modules/Notifications/NotificationContextMenu.qml +++ b/quickshell/Modules/Notifications/NotificationContextMenu.qml @@ -95,8 +95,8 @@ PanelWindow { height: menuColumn.implicitHeight + Theme.spacingS * 2 radius: Theme.cornerRadius color: Theme.withAlpha(Theme.surfaceContainer, Theme.popupTransparency) - border.color: BlurService.enabled ? BlurService.borderColor : Theme.outlineMedium - border.width: BlurService.enabled ? BlurService.borderWidth : 1 + border.color: BlurService.borderColor + border.width: BlurService.borderWidth Column { id: menuColumn diff --git a/quickshell/Modules/ProcessList/ProcessContextMenu.qml b/quickshell/Modules/ProcessList/ProcessContextMenu.qml index 78986fc26..97091343b 100644 --- a/quickshell/Modules/ProcessList/ProcessContextMenu.qml +++ b/quickshell/Modules/ProcessList/ProcessContextMenu.qml @@ -187,8 +187,8 @@ Popup { contentItem: Rectangle { color: Theme.floatingSurface radius: Theme.cornerRadius - border.color: BlurService.enabled ? BlurService.borderColor : Theme.outlineMedium - border.width: BlurService.enabled ? BlurService.borderWidth : 1 + border.color: BlurService.borderColor + border.width: BlurService.borderWidth Item { id: keyboardHandler diff --git a/quickshell/Modules/Settings/ColorDropdownRow.qml b/quickshell/Modules/Settings/ColorDropdownRow.qml index 7b3bce55c..78f8c85fe 100644 --- a/quickshell/Modules/Settings/ColorDropdownRow.qml +++ b/quickshell/Modules/Settings/ColorDropdownRow.qml @@ -23,8 +23,10 @@ Column { readonly property var optionColorMap: { var map = {}; - for (var i = 0; i < options.length; i++) - map[options[i].label] = root.colorForValue(options[i].value); + for (var i = 0; i < options.length; i++) { + const option = options[i]; + map[option.label] = option.previewColor ?? root.colorForValue(option.value); + } return map; } diff --git a/quickshell/Modules/Settings/ThemeColorsTab.qml b/quickshell/Modules/Settings/ThemeColorsTab.qml index 9e1afd4bc..ac35d0fc8 100644 --- a/quickshell/Modules/Settings/ThemeColorsTab.qml +++ b/quickshell/Modules/Settings/ThemeColorsTab.qml @@ -18,11 +18,27 @@ Item { property var cachedIconThemes: SettingsData.availableIconThemes property var cachedCursorThemes: SettingsData.availableCursorThemes property var cachedMatugenSchemes: Theme.availableMatugenSchemes.map(option => option.label) + property var matugenSchemePreviews: ({}) + property string matugenPreviewSource: "" + property real matugenPreviewContrast: 0 + property string matugenPreviewRequestKey: "" property var installedRegistryThemes: [] property var templateDetection: [] + readonly property var matugenSchemeColorMap: { + const map = {}; + const mode = SessionData.isLightMode ? "light" : "dark"; + for (var i = 0; i < Theme.availableMatugenSchemes.length; i++) { + const option = Theme.availableMatugenSchemes[i]; + const preview = matugenSchemePreviews[option.value]; + if (preview?.[mode]) + map[option.label] = preview[mode]; + } + return map; + } readonly property var widgetBackgroundOptions: [({ "value": "sth", - "label": I18n.tr("Subtle Overlay", "widget background color option") + "label": I18n.tr("Overlay", "widget background color option"), + "previewColor": Theme.blend(Theme.surfaceContainerHigh, Theme.surfaceText, 0.24) }), ({ "value": "s", "label": I18n.tr("Surface", "widget background color option") @@ -173,9 +189,9 @@ Item { return Theme.warning; } - function openBlurBorderColorPicker() { + function openSurfaceBorderColorPicker() { PopoutService.colorPickerModal.selectedColor = SettingsData.blurBorderCustomColor ?? "#ffffff"; - PopoutService.colorPickerModal.pickerTitle = I18n.tr("Blur Border Color"); + PopoutService.colorPickerModal.pickerTitle = I18n.tr("Surface Border Color"); PopoutService.colorPickerModal.onColorSelectedCallback = function (color) { SettingsData.set("blurBorderCustomColor", color.toString()); }; @@ -210,6 +226,35 @@ Item { } } + function refreshMatugenSchemePreviews() { + if (!Theme.matugenAvailable) + return; + const sourceColor = Theme.getMatugenColor("source_color", Theme.primary).toString(); + const contrast = SettingsData.matugenContrast ?? 0; + const requestKey = sourceColor + "|" + contrast; + if (sourceColor === matugenPreviewSource && contrast === matugenPreviewContrast && Object.keys(matugenSchemePreviews).length > 0) + return; + if (requestKey === matugenPreviewRequestKey) + return; + matugenPreviewRequestKey = requestKey; + + Proc.runCommand("", ["dms", "matugen", "preview", "--source-color", sourceColor, "--contrast", contrast.toString()], (output, exitCode) => { + if (requestKey !== themeColorsTab.matugenPreviewRequestKey) + return; + if (exitCode !== 0) { + themeColorsTab.matugenPreviewRequestKey = ""; + return; + } + try { + themeColorsTab.matugenSchemePreviews = JSON.parse(output.trim()); + themeColorsTab.matugenPreviewSource = sourceColor; + themeColorsTab.matugenPreviewContrast = contrast; + } catch (e) { + themeColorsTab.matugenPreviewRequestKey = ""; + } + }); + } + Component.onCompleted: { SettingsData.detectAvailableIconThemes(); SettingsData.detectAvailableCursorThemes(); @@ -226,6 +271,7 @@ Item { }); if (CompositorService.isNiri || CompositorService.isHyprland || CompositorService.isMango) checkCursorIncludeStatus(); + refreshMatugenSchemePreviews(); } Connections { @@ -243,6 +289,23 @@ Item { } } + Connections { + target: Theme + function onMatugenColorsChanged() { + themeColorsTab.refreshMatugenSchemePreviews(); + } + function onMatugenAvailableChanged() { + themeColorsTab.refreshMatugenSchemePreviews(); + } + } + + Connections { + target: SettingsData + function onMatugenContrastChanged() { + themeColorsTab.refreshMatugenSchemePreviews(); + } + } + DankFlickable { anchors.fill: parent clip: true @@ -558,6 +621,7 @@ Item { text: I18n.tr("Matugen Palette") description: I18n.tr("Select the palette algorithm used for wallpaper-based colors") options: cachedMatugenSchemes + optionColorMap: matugenSchemeColorMap currentValue: Theme.getMatugenScheme(SettingsData.matugenScheme).label enabled: Theme.matugenAvailable opacity: enabled ? 1 : 0.4 @@ -1706,6 +1770,64 @@ Item { onSliderValueChanged: newValue => SettingsData.set("popupTransparency", newValue / 100) } + SettingsDropdownRow { + tab: "theme" + tags: ["surface", "popup", "modal", "border", "outline", "edge"] + settingKey: "blurBorderColor" + text: I18n.tr("Surface Border Color") + description: I18n.tr("Border color around popouts, modals, and other shell surfaces") + options: [I18n.tr("Outline", "surface border color"), I18n.tr("Primary", "surface border color"), I18n.tr("Secondary", "surface border color"), I18n.tr("Text Color", "surface border color"), I18n.tr("Custom", "surface border color")] + optionColorMap: ({ + [I18n.tr("Outline", "surface border color")]: Theme.outline, + [I18n.tr("Primary", "surface border color")]: Theme.primary, + [I18n.tr("Secondary", "surface border color")]: Theme.secondary, + [I18n.tr("Text Color", "surface border color")]: Theme.surfaceText, + [I18n.tr("Custom", "surface border color")]: SettingsData.blurBorderCustomColor ?? "#ffffff" + }) + currentValue: { + switch (SettingsData.blurBorderColor) { + case "primary": + return I18n.tr("Primary", "surface border color"); + case "secondary": + return I18n.tr("Secondary", "surface border color"); + case "surfaceText": + return I18n.tr("Text Color", "surface border color"); + case "custom": + return I18n.tr("Custom", "surface border color"); + default: + return I18n.tr("Outline", "surface border color"); + } + } + onValueChanged: value => { + if (value === I18n.tr("Primary", "surface border color")) { + SettingsData.set("blurBorderColor", "primary"); + } else if (value === I18n.tr("Secondary", "surface border color")) { + SettingsData.set("blurBorderColor", "secondary"); + } else if (value === I18n.tr("Text Color", "surface border color")) { + SettingsData.set("blurBorderColor", "surfaceText"); + } else if (value === I18n.tr("Custom", "surface border color")) { + SettingsData.set("blurBorderColor", "custom"); + openSurfaceBorderColorPicker(); + } else { + SettingsData.set("blurBorderColor", "outline"); + } + } + } + + SettingsSliderRow { + tab: "theme" + tags: ["surface", "popup", "modal", "border", "opacity"] + settingKey: "blurBorderOpacity" + text: I18n.tr("Surface Border Opacity") + description: I18n.tr("Controls the outline of popouts, modals, and other shell surfaces") + value: Math.round((SettingsData.blurBorderOpacity ?? 0.35) * 100) + minimum: 0 + maximum: 100 + unit: "%" + defaultValue: 35 + onSliderValueChanged: newValue => SettingsData.set("blurBorderOpacity", newValue / 100) + } + SettingsSliderRow { tab: "theme" tags: ["foreground", "layers", "outline", "border", "cards", "widgets", "notifications", "control center"] @@ -1760,59 +1882,6 @@ Item { onToggled: checked => SettingsData.set("blurEnabled", checked) } - SettingsDropdownRow { - tab: "theme" - tags: ["blur", "border", "outline", "edge"] - settingKey: "blurBorderColor" - text: I18n.tr("Blur Border Color") - description: I18n.tr("Border color around blurred surfaces") - visible: SettingsData.blurEnabled - options: [I18n.tr("Outline", "blur border color"), I18n.tr("Primary", "blur border color"), I18n.tr("Secondary", "blur border color"), I18n.tr("Text Color", "blur border color"), I18n.tr("Custom", "blur border color")] - currentValue: { - switch (SettingsData.blurBorderColor) { - case "primary": - return I18n.tr("Primary", "blur border color"); - case "secondary": - return I18n.tr("Secondary", "blur border color"); - case "surfaceText": - return I18n.tr("Text Color", "blur border color"); - case "custom": - return I18n.tr("Custom", "blur border color"); - default: - return I18n.tr("Outline", "blur border color"); - } - } - onValueChanged: value => { - if (value === I18n.tr("Primary", "blur border color")) { - SettingsData.set("blurBorderColor", "primary"); - } else if (value === I18n.tr("Secondary", "blur border color")) { - SettingsData.set("blurBorderColor", "secondary"); - } else if (value === I18n.tr("Text Color", "blur border color")) { - SettingsData.set("blurBorderColor", "surfaceText"); - } else if (value === I18n.tr("Custom", "blur border color")) { - SettingsData.set("blurBorderColor", "custom"); - openBlurBorderColorPicker(); - } else { - SettingsData.set("blurBorderColor", "outline"); - } - } - } - - SettingsSliderRow { - tab: "theme" - tags: ["blur", "border", "opacity"] - settingKey: "blurBorderOpacity" - text: I18n.tr("Blur Border Opacity") - description: I18n.tr("Controls the outer edge of protocol-blurred windows") - visible: SettingsData.blurEnabled - value: Math.round((SettingsData.blurBorderOpacity ?? 0.35) * 100) - minimum: 0 - maximum: 100 - unit: "%" - defaultValue: 35 - onSliderValueChanged: newValue => SettingsData.set("blurBorderOpacity", newValue / 100) - } - Item { width: parent.width height: xrayHintRow.implicitHeight @@ -1902,6 +1971,13 @@ Item { text: I18n.tr("Shadow Color") description: I18n.tr("Base color for shadows (opacity is applied automatically)") options: [I18n.tr("Default (Black)", "shadow color option"), I18n.tr("Text Color", "shadow color option"), I18n.tr("Primary", "shadow color option"), I18n.tr("Surface Variant", "shadow color option"), I18n.tr("Custom", "shadow color option")] + optionColorMap: ({ + [I18n.tr("Default (Black)", "shadow color option")]: "#000000", + [I18n.tr("Text Color", "shadow color option")]: Theme.surfaceText, + [I18n.tr("Primary", "shadow color option")]: Theme.primary, + [I18n.tr("Surface Variant", "shadow color option")]: Theme.surfaceVariant, + [I18n.tr("Custom", "shadow color option")]: SettingsData.m3ElevationCustomColor ?? "#000000" + }) currentValue: { switch (SettingsData.m3ElevationColorMode) { case "text": diff --git a/quickshell/Services/BlurService.qml b/quickshell/Services/BlurService.qml index cb7f3bb93..77fffcc98 100644 --- a/quickshell/Services/BlurService.qml +++ b/quickshell/Services/BlurService.qml @@ -15,9 +15,8 @@ Singleton { readonly property bool available: compositorSupported readonly property bool enabled: available && (SettingsData.blurEnabled ?? false) + // These settings predate non-blurred surface borders, so keep their keys for compatibility. readonly property color borderColor: { - if (!enabled) - return "transparent"; const opacity = SettingsData.blurBorderOpacity ?? 0.35; switch (SettingsData.blurBorderColor ?? "outline") { case "primary": @@ -32,7 +31,7 @@ Singleton { return Theme.withAlpha(Theme.outline, opacity); } } - readonly property int borderWidth: enabled ? 1 : 0 + readonly property int borderWidth: 1 function hoverColor(baseColor, hoverAlpha) { if (!enabled) diff --git a/quickshell/Widgets/DankOSD.qml b/quickshell/Widgets/DankOSD.qml index 481af5591..969384188 100644 --- a/quickshell/Widgets/DankOSD.qml +++ b/quickshell/Widgets/DankOSD.qml @@ -273,8 +273,8 @@ PanelWindow { anchors.fill: parent radius: Theme.cornerRadius color: "transparent" - border.color: BlurService.enabled ? BlurService.borderColor : Theme.outlineMedium - border.width: BlurService.enabled ? BlurService.borderWidth : 1 + border.color: BlurService.borderColor + border.width: BlurService.borderWidth z: -1 } diff --git a/quickshell/Widgets/DankPopoutConnected.qml b/quickshell/Widgets/DankPopoutConnected.qml index 0552f2cb8..f314f2dec 100644 --- a/quickshell/Widgets/DankPopoutConnected.qml +++ b/quickshell/Widgets/DankPopoutConnected.qml @@ -1040,7 +1040,7 @@ Item { readonly property string connectedBarSide: barTop ? "top" : (barBottom ? "bottom" : (barLeft ? "left" : "right")) readonly property real surfaceRadius: root.usesConnectedSurfaceChrome ? Theme.connectedSurfaceRadius : Theme.cornerRadius readonly property color surfaceColor: root.usesConnectedSurfaceChrome ? Theme.connectedSurfaceColor : Theme.withAlpha(Theme.surfaceContainer, Theme.popupTransparency) - readonly property color surfaceBorderColor: root.usesConnectedSurfaceChrome ? Theme.withAlpha(Theme.outlineMedium, 0) : (BlurService.enabled ? BlurService.borderColor : Theme.outlineMedium) + readonly property color surfaceBorderColor: root.usesConnectedSurfaceChrome ? Theme.withAlpha(BlurService.borderColor, 0) : BlurService.borderColor readonly property real surfaceBorderWidth: root.usesConnectedSurfaceChrome ? 0 : BlurService.borderWidth readonly property real surfaceTopLeftRadius: root.usesConnectedSurfaceChrome && (barTop || barLeft) ? 0 : surfaceRadius readonly property real surfaceTopRightRadius: root.usesConnectedSurfaceChrome && (barTop || barRight) ? 0 : surfaceRadius diff --git a/quickshell/Widgets/DankPopoutStandalone.qml b/quickshell/Widgets/DankPopoutStandalone.qml index b3cd4dc9e..35083ed8f 100644 --- a/quickshell/Widgets/DankPopoutStandalone.qml +++ b/quickshell/Widgets/DankPopoutStandalone.qml @@ -909,7 +909,7 @@ Item { visible: contentWrapper.visible radius: Theme.cornerRadius color: "transparent" - border.color: BlurService.enabled ? BlurService.borderColor : Theme.outlineMedium + border.color: BlurService.borderColor border.width: BlurService.borderWidth z: 100 } diff --git a/quickshell/Widgets/DankSlideout.qml b/quickshell/Widgets/DankSlideout.qml index 6c5c9eb1b..8dc4ffcb4 100644 --- a/quickshell/Widgets/DankSlideout.qml +++ b/quickshell/Widgets/DankSlideout.qml @@ -187,7 +187,7 @@ PanelWindow { anchors.fill: parent color: contentRect.slideoutSurfaceColor radius: Theme.connectedSurfaceRadius - border.color: Theme.isConnectedEffect ? Theme.withAlpha(Theme.outlineMedium, 0) : (BlurService.enabled ? BlurService.borderColor : Theme.outlineMedium) + border.color: Theme.isConnectedEffect ? Theme.withAlpha(BlurService.borderColor, 0) : BlurService.borderColor border.width: Theme.isConnectedEffect ? 0 : BlurService.borderWidth } diff --git a/quickshell/Widgets/DankTooltip.qml b/quickshell/Widgets/DankTooltip.qml index bb9f3d0f1..931691ee6 100644 --- a/quickshell/Widgets/DankTooltip.qml +++ b/quickshell/Widgets/DankTooltip.qml @@ -78,8 +78,8 @@ PanelWindow { anchors.fill: parent color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) radius: Theme.cornerRadius - border.width: BlurService.enabled ? BlurService.borderWidth : 1 - border.color: BlurService.enabled ? BlurService.borderColor : Theme.outlineMedium + border.width: BlurService.borderWidth + border.color: BlurService.borderColor StyledText { id: textContent diff --git a/quickshell/Widgets/DankTooltipV2.qml b/quickshell/Widgets/DankTooltipV2.qml index 6cd53c8d9..d9c530870 100644 --- a/quickshell/Widgets/DankTooltipV2.qml +++ b/quickshell/Widgets/DankTooltipV2.qml @@ -111,7 +111,7 @@ Item { dim: false background: Rectangle { - color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) + color: Theme.surfaceContainerHigh radius: Theme.cornerRadius border.width: 1 border.color: Theme.outlineMedium diff --git a/quickshell/translations/settings_search_index.json b/quickshell/translations/settings_search_index.json index ebda7a0d7..ae2f189dd 100644 --- a/quickshell/translations/settings_search_index.json +++ b/quickshell/translations/settings_search_index.json @@ -3058,7 +3058,8 @@ "transparency" ], "icon": "blur_on", - "description": "Your compositor does not support background blur (ext-background-effect-v1)" + "description": "Your compositor does not support background blur (ext-background-effect-v1)", + "conditionKey": "isNiri" }, { "section": "barElevationEnabled", @@ -3087,56 +3088,6 @@ ], "description": "Shadow elevation on bars and panels" }, - { - "section": "blurBorderColor", - "label": "Blur Border Color", - "tabIndex": 10, - "category": "Theme & Colors", - "keywords": [ - "appearance", - "around", - "blur", - "blurred", - "border", - "color", - "colors", - "colour", - "edge", - "hue", - "look", - "outline", - "scheme", - "style", - "surfaces", - "theme", - "tint" - ], - "description": "Border color around blurred surfaces" - }, - { - "section": "blurBorderOpacity", - "label": "Blur Border Opacity", - "tabIndex": 10, - "category": "Theme & Colors", - "keywords": [ - "appearance", - "blur", - "blurred", - "border", - "colors", - "controls", - "edge", - "look", - "opacity", - "outer", - "protocol", - "scheme", - "style", - "theme", - "windows" - ], - "description": "Controls the outer edge of protocol-blurred windows" - }, { "section": "buttonColorMode", "label": "Button Color", @@ -4057,6 +4008,62 @@ "icon": "layers", "description": "Material inspired shadows and elevation on modals, popouts, and dialogs" }, + { + "section": "blurBorderColor", + "label": "Surface Border Color", + "tabIndex": 10, + "category": "Theme & Colors", + "keywords": [ + "appearance", + "around", + "border", + "color", + "colors", + "colour", + "edge", + "hue", + "look", + "modal", + "modals", + "outline", + "popouts", + "popup", + "scheme", + "shell", + "style", + "surface", + "surfaces", + "theme", + "tint" + ], + "description": "Border color around popouts, modals, and other shell surfaces" + }, + { + "section": "blurBorderOpacity", + "label": "Surface Border Opacity", + "tabIndex": 10, + "category": "Theme & Colors", + "keywords": [ + "appearance", + "border", + "colors", + "controls", + "look", + "modal", + "modals", + "opacity", + "outline", + "popouts", + "popup", + "scheme", + "shell", + "style", + "surface", + "surfaces", + "theme" + ], + "description": "Controls the outline of popouts, modals, and other shell surfaces" + }, { "section": "popupTransparency", "label": "Surface Opacity", diff --git a/quickshell/translations/template.json b/quickshell/translations/template.json index d6c3c175f..7c4d68885 100644 --- a/quickshell/translations/template.json +++ b/quickshell/translations/template.json @@ -2632,14 +2632,14 @@ "comment": "" }, { - "term": "Blur Border Color", + "term": "Surface Border Color", "translation": "", "context": "", "reference": "", "comment": "" }, { - "term": "Blur Border Opacity", + "term": "Surface Border Opacity", "translation": "", "context": "", "reference": "", @@ -2758,7 +2758,7 @@ "comment": "" }, { - "term": "Border color around blurred surfaces", + "term": "Border color around popouts, modals, and other shell surfaces", "translation": "", "context": "", "reference": "", @@ -4340,7 +4340,7 @@ "comment": "" }, { - "term": "Controls the outer edge of protocol-blurred windows", + "term": "Controls the outer edge of popouts, modals, and other shell surfaces", "translation": "", "context": "", "reference": "", @@ -17696,7 +17696,7 @@ "comment": "" }, { - "term": "Subtle Overlay", + "term": "Overlay", "translation": "", "context": "widget background color option", "reference": "",