From 5b7dafe13627ca4374954b57b74da79c49029ea9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danielle=20For=C3=A9?= Date: Fri, 28 Aug 2026 14:23:11 -0700 Subject: [PATCH 1/2] Styles: revamp OSD with backdrop blur --- demo/GraniteDemo.vala | 4 +-- demo/Views/OverlayBarView.vala | 33 ------------------ demo/Views/OverlayView.vala | 56 ++++++++++++++++++++++++++++++ demo/Views/ToastView.vala | 42 ---------------------- demo/meson.build | 3 +- lib/Constants.vala | 7 ++++ lib/Styles/Granite/OverlayBar.scss | 6 +--- lib/Styles/Granite/Toast.scss | 2 +- lib/Styles/Gtk/Tooltip.scss | 3 +- lib/Styles/Gtk/Video.scss | 14 ++------ lib/Styles/_osd.scss | 50 ++++++++++++++++++++++---- 11 files changed, 116 insertions(+), 104 deletions(-) delete mode 100644 demo/Views/OverlayBarView.vala create mode 100644 demo/Views/OverlayView.vala delete mode 100644 demo/Views/ToastView.vala diff --git a/demo/GraniteDemo.vala b/demo/GraniteDemo.vala index f1d95ad73..125e50a55 100644 --- a/demo/GraniteDemo.vala +++ b/demo/GraniteDemo.vala @@ -27,7 +27,6 @@ public class Granite.Demo : Gtk.Application { var controls_view = new ControlsView (); var maps_view = new MapsView (); var overlaybar_view = new OverlayBarView (); - var toast_view = new ToastView (); var settings_uris_view = new SettingsUrisView (); var utils_view = new UtilsView (); var video_view = new VideoView (); @@ -49,9 +48,8 @@ public class Granite.Demo : Gtk.Application { main_stack.add_titled (controls_view, "controls", "Controls"); main_stack.add_titled (maps_view, "maps", "Maps"); main_stack.add_titled (video_view, "video", video_view.title); - main_stack.add_titled (overlaybar_view, "overlaybar", "OverlayBar"); + main_stack.add_titled (overlaybar_view, "overlaybar", "Overlays"); main_stack.add_titled (settings_uris_view, "settings_uris", "Settings URIs"); - main_stack.add_titled (toast_view, "toasts", "Toast"); main_stack.add_titled (utils_view, "utils", "Utils"); main_stack.add_titled (dialogs_view, "dialogs", "Dialogs"); main_stack.add_titled (application_view, "application", "Application"); diff --git a/demo/Views/OverlayBarView.vala b/demo/Views/OverlayBarView.vala deleted file mode 100644 index aa0f56037..000000000 --- a/demo/Views/OverlayBarView.vala +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2017-2021 elementary, Inc. (https://elementary.io) - * SPDX-License-Identifier: LGPL-3.0-or-later - */ - -public class OverlayBarView : DemoPage { - construct { - var button = new Gtk.ToggleButton.with_label ("Show Spinner"); - - /* This is necessary to workaround an issue in the stylesheet with buttons packed directly into overlays */ - var box = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 6) { - halign = Gtk.Align.CENTER, - valign = Gtk.Align.CENTER - }; - - box.append (button); - - var overlay = new Gtk.Overlay () { - child = box, - hexpand = true - }; - - var overlaybar = new Granite.OverlayBar (overlay) { - label = "Hover the OverlayBar to change its position" - }; - - child = overlay; - - button.toggled.connect (() => { - overlaybar.active = button.active; - }); - } -} diff --git a/demo/Views/OverlayView.vala b/demo/Views/OverlayView.vala new file mode 100644 index 000000000..0f6a3f782 --- /dev/null +++ b/demo/Views/OverlayView.vala @@ -0,0 +1,56 @@ +/* + * Copyright 2017-2021 elementary, Inc. (https://elementary.io) + * SPDX-License-Identifier: LGPL-3.0-or-later + */ + +public class OverlayBarView : DemoPage { + construct { + var picture = new Gtk.Picture.for_filename ("/usr/share/backgrounds/elementaryos-default") { + content_fit = COVER, + margin_top = 12, + margin_end = 12, + margin_bottom = 12, + margin_start = 12 + }; + picture.add_css_class (Granite.CssClass.CARD); + + var toast = new Granite.Toast (_("Button was pressed!")); + toast.set_default_action (_("Do Things")); + + var toast_button = new Gtk.Button.with_label (_("Send Toast")); + toast_button.add_css_class (Granite.CssClass.OSD); + + var spinner_button = new Gtk.ToggleButton.with_label ("Show Spinner"); + spinner_button.add_css_class (Granite.CssClass.OSD); + + var box = new Granite.Box (VERTICAL) { + halign = CENTER, + valign = CENTER + }; + box.append (toast_button); + box.append (spinner_button); + + var overlay = new Gtk.Overlay () { + child = picture, + hexpand = true + }; + overlay.add_overlay (box); + overlay.add_overlay (toast); + overlay.set_measure_overlay (toast, true); + + var overlaybar = new Granite.OverlayBar (overlay) { + label = "Hover the OverlayBar to change its position" + }; + + child = overlay; + + toast_button.clicked.connect (toast.send_notification); + + toast.default_action.connect (() => { + toast.title = _("Already did the thing"); + toast.set_default_action (null); + }); + + spinner_button.bind_property ("active", overlaybar, "active"); + } +} diff --git a/demo/Views/ToastView.vala b/demo/Views/ToastView.vala deleted file mode 100644 index eeaff783a..000000000 --- a/demo/Views/ToastView.vala +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 2011-2021 elementary, Inc. (https://elementary.io) - * SPDX-License-Identifier: LGPL-3.0-or-later - */ - -public class ToastView : DemoPage { - construct { - var overlay = new Gtk.Overlay (); - - var toast = new Granite.Toast (_("Button was pressed!")); - toast.set_default_action (_("Do Things")); - - var button = new Gtk.Button.with_label (_("Press Me")); - - var box = new Gtk.Box (Gtk.Orientation.VERTICAL, 6) { - margin_start = 24, - margin_end = 24, - margin_top = 24, - margin_bottom = 24, - halign = Gtk.Align.CENTER, - valign = Gtk.Align.CENTER - }; - box.append (button); - - overlay.add_overlay (box); - overlay.add_overlay (toast); - overlay.set_measure_overlay (toast, true); - - button.clicked.connect (() => { - toast.send_notification (); - }); - - toast.default_action.connect (() => { - var label = new Gtk.Label (_("Did The Thing")); - toast.title = _("Already did the thing"); - toast.set_default_action (null); - box.append (label); - }); - - child = overlay; - } -} diff --git a/demo/meson.build b/demo/meson.build index f39e416f7..fcbdde21b 100644 --- a/demo/meson.build +++ b/demo/meson.build @@ -19,9 +19,8 @@ executable( 'Views/HyperTextViewGrid.vala', 'Views/ListsView.vala', 'Views/MapsView.vala', - 'Views/OverlayBarView.vala', + 'Views/OverlayView.vala', 'Views/SettingsUrisView.vala', - 'Views/ToastView.vala', 'Views/UtilsView.vala', 'Views/VideoView.vala', 'Views/WelcomeView.vala', diff --git a/lib/Constants.vala b/lib/Constants.vala index 86702c0e3..d78c38249 100644 --- a/lib/Constants.vala +++ b/lib/Constants.vala @@ -101,6 +101,7 @@ namespace Granite { /** * Style class for "on-screen display" widgets such as {@link Granite.Toast} and {@link Granite.OverlayBar} */ + [Version (deprecated = true, deprecated_since = "9.0.0", replacement = "Granite.CssClass.OSD")] public const string STYLE_CLASS_OSD = "osd"; /** * Style class for rounded corners, i.e. on a {@link Gtk.Window} or {@link Granite.STYLE_CLASS_CARD} @@ -232,6 +233,12 @@ namespace Granite { [Version (since = "7.7.0")] public const string CARD = "card"; + /** + * Style class for "on-screen display" widgets such as {@link Granite.Toast} and {@link Granite.OverlayBar} + */ + [Version (since = "9.0.0")] + public const string OSD = "osd"; + /** * Style class for checkered backgrounds to represent transparency in images */ diff --git a/lib/Styles/Granite/OverlayBar.scss b/lib/Styles/Granite/OverlayBar.scss index b1f72f128..f9da0fe7d 100644 --- a/lib/Styles/Granite/OverlayBar.scss +++ b/lib/Styles/Granite/OverlayBar.scss @@ -1,10 +1,6 @@ overlaybar .osd { + border-radius: rem($window_radius / 2); padding: rem(6px) rem(12px); - text-shadow: 0 rem(1px) rem(2px) rgba($fg_color, 0.6); - - spinner { - -gtk-icon-shadow: 0 rem(1px) rem(2px) rgba($fg_color, 0.6); - } revealer:dir(ltr) > spinner { margin-left: $button-spacing; diff --git a/lib/Styles/Granite/Toast.scss b/lib/Styles/Granite/Toast.scss index 7fb15d38d..b8341572e 100644 --- a/lib/Styles/Granite/Toast.scss +++ b/lib/Styles/Granite/Toast.scss @@ -1,4 +1,4 @@ toast .osd > label { margin: 0 rem(12px); - text-shadow: 0 1px 2px #{'alpha(@theme_fg_color, 0.6)'}; + // text-shadow: 0 1px 2px #{'alpha(@theme_fg_color, 0.6)'}; } diff --git a/lib/Styles/Gtk/Tooltip.scss b/lib/Styles/Gtk/Tooltip.scss index 17a78ad26..4cc1641b2 100644 --- a/lib/Styles/Gtk/Tooltip.scss +++ b/lib/Styles/Gtk/Tooltip.scss @@ -1,6 +1,7 @@ tooltip { + background-color: scale-color(bg-color(2), $alpha: -5%); @extend .osd; margin: rem(3px); - text-shadow: 0 rem(1px) rem(2px) rgba($fg_color, 0.6); + // text-shadow: 0 rem(1px) rem(2px) rgba($fg_color, 0.6); } diff --git a/lib/Styles/Gtk/Video.scss b/lib/Styles/Gtk/Video.scss index 703ff72ee..3c96e5cb0 100644 --- a/lib/Styles/Gtk/Video.scss +++ b/lib/Styles/Gtk/Video.scss @@ -6,23 +6,15 @@ video { // Play/Repeat indicator image.circular.large-icons.osd { - background: - rgba($SILVER_300, 0.65); - -gtk-icon-shadow: - 0 1px 2px rgba(black, 0.2), - 0 0.3rem 1rem rgba(black, 0.3); + -gtk-icon-shadow: + 0 1px 2px rgba(black, 0.2), + 0 0.3rem 1rem rgba(black, 0.3); color: white; padding: 1rem; } controls.osd { - background: linear-gradient( - to bottom, - transparent, - rgba(black, 0.1) 1.5rem - ); color: white; - margin: 0; padding: 1em; > box { diff --git a/lib/Styles/_osd.scss b/lib/Styles/_osd.scss index 33d3c1f92..30e35740a 100644 --- a/lib/Styles/_osd.scss +++ b/lib/Styles/_osd.scss @@ -1,8 +1,46 @@ .osd { - background-color: rgba($fg-color, 0.95); - border-radius: rem($window_radius / 2); - box-shadow: shadow(1); - color: bg-color(1); - margin: rem(6px); - padding: rem(6px); + backdrop-filter: blur(6px); + background-color: scale-color(bg-color(2), $alpha: -50%); + background-clip: padding-box; + background-image: + linear-gradient( + to top, + scale-color($highlight_color, $alpha: -97%), + transparent calc(100% - 0.5rem), + ); + border: 1px solid $border-color; + border-radius: rem($window_radius); + box-shadow: + inset 0 1px 0 0 scale-color($highlight_color, $alpha: -80%), + inset 1px 0 0 0 scale-color($highlight_color, $alpha: -93%), + inset -1px 0 0 0 scale-color($highlight_color, $alpha: -93%), + inset 0 -1px 0 0 scale-color($highlight_color, $alpha: -70%), + 0 2px 4px rgba(black, 0.1), + 0 1px 2px rgba(black, 0.1); + margin: 0.5rem; + padding: 0.5rem; + text-shadow: 0 1px 1px scale-color(bg_color(3), $alpha: -80%); + -gtk-icon-shadow: 0 1px 1px scale-color(bg_color(3), $alpha: -80%); + + &.circular { + background-image: + linear-gradient( + to top, + scale-color($highlight_color, $alpha: -97%), + transparent calc(100% - 0.5rem), + ), + radial-gradient( + ellipse 65% 50%, + transparent calc(100% - 0.5rem), + scale-color($highlight_color, $alpha: -75%), + ); + border-radius: 100%; + + } } + +@media (#{'prefers-contrast: more'}) { + .osd { + background-color: bg-color(2); + } +}; From 89eafeafd8f02de16a4626c2cc37974841c9fcfb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danielle=20For=C3=A9?= Date: Fri, 28 Aug 2026 14:50:23 -0700 Subject: [PATCH 2/2] Lots more --- demo/Views/OverlayView.vala | 9 +++++--- lib/Styles/Granite/Button.scss | 39 ++++++++++++++++++++-------------- lib/Styles/Gtk/Button.scss | 6 +++--- lib/Styles/_osd.scss | 3 +-- 4 files changed, 33 insertions(+), 24 deletions(-) diff --git a/demo/Views/OverlayView.vala b/demo/Views/OverlayView.vala index 0f6a3f782..719a815a4 100644 --- a/demo/Views/OverlayView.vala +++ b/demo/Views/OverlayView.vala @@ -17,18 +17,21 @@ public class OverlayBarView : DemoPage { var toast = new Granite.Toast (_("Button was pressed!")); toast.set_default_action (_("Do Things")); - var toast_button = new Gtk.Button.with_label (_("Send Toast")); + var toast_button = new Gtk.Button.from_icon_name ("list-add-symbolic") { + halign = CENTER, + tooltip_text = "Send Toast" + }; toast_button.add_css_class (Granite.CssClass.OSD); var spinner_button = new Gtk.ToggleButton.with_label ("Show Spinner"); spinner_button.add_css_class (Granite.CssClass.OSD); - var box = new Granite.Box (VERTICAL) { + var box = new Granite.Box (HORIZONTAL) { halign = CENTER, valign = CENTER }; - box.append (toast_button); box.append (spinner_button); + box.append (toast_button); var overlay = new Gtk.Overlay () { child = picture, diff --git a/lib/Styles/Granite/Button.scss b/lib/Styles/Granite/Button.scss index 4fdde5258..2ee33c77f 100644 --- a/lib/Styles/Granite/Button.scss +++ b/lib/Styles/Granite/Button.scss @@ -44,35 +44,42 @@ button { } &.osd { - @include control; - @include border-interactive-roundrect; - // This stacks with the other shadows, // so reduce it's alpha by the sum of other shadows $shadow-border-color: scale-color($border-color, $alpha: -50%); - @if $color-scheme == "dark" { - $shadow-border-color: transparent - } - background-image: none; - border: none; - box-shadow: - highlight(), - // Intentionally not in ems since it's used as a stroke - 0 0 0 1px $shadow-border-color, - shadow(2); - color: $fg-color; margin: 0; padding: $button-spacing; + &.text-button { + @include control; + @include border-interactive-roundrect; + @if $color-scheme == "dark" { + $shadow-border-color: transparent + } + + background-image: none; + border: none; + box-shadow: + highlight(), + // Intentionally not in ems since it's used as a stroke + 0 0 0 1px $shadow-border-color, + shadow(2); + color: $fg-color; + } + transition: background duration("expand") easing(), transform duration("expand") easing("ease-out-back"); &:active { transition: - background duration("collapse") easing(), - transform duration("collapse") easing(); + background duration("collapse") easing(), + transform duration("collapse") easing(); + + &.image-button { + background-color: scale-color(bg-color(2), $alpha: -40%); + } } &:disabled { diff --git a/lib/Styles/Gtk/Button.scss b/lib/Styles/Gtk/Button.scss index c015f69ac..9b065979e 100644 --- a/lib/Styles/Gtk/Button.scss +++ b/lib/Styles/Gtk/Button.scss @@ -8,7 +8,7 @@ button { &.image-button { @extend .circular; - padding: rem(4px); + padding: $button-spacing; min-height: 16px; min-width: 16px; transition: @@ -16,7 +16,7 @@ button { transform duration("expand") easing("ease-out-back"); &:active { - background: rgba($fg-color, 0.15); + background-color: rgba($fg-color, 0.15); transform: scale(0.8); transition: background duration("collapse") easing(), @@ -43,7 +43,7 @@ button { &.text-button { @extend %raised; - padding: rem(2px) rem(4px); + padding: $button-spacing $button-spacing * 2; } // Almost certainly a button with text and image diff --git a/lib/Styles/_osd.scss b/lib/Styles/_osd.scss index 30e35740a..e6ba01588 100644 --- a/lib/Styles/_osd.scss +++ b/lib/Styles/_osd.scss @@ -22,6 +22,7 @@ text-shadow: 0 1px 1px scale-color(bg_color(3), $alpha: -80%); -gtk-icon-shadow: 0 1px 1px scale-color(bg_color(3), $alpha: -80%); + &.image-button:not(.toggle), &.circular { background-image: linear-gradient( @@ -34,8 +35,6 @@ transparent calc(100% - 0.5rem), scale-color($highlight_color, $alpha: -75%), ); - border-radius: 100%; - } }