Match shell squircle outlines with compositor masks

Use shared corner geometry for shell controls, window clipping, materials and blur masks. Preserve circular pills and controls where appropriate, track contour changes in damage, and use tagged ferese-shape and libcosmic dependencies.
This commit is contained in:
Samuel Onoja authored and GitHub committed 2026-10-04 07:39:54 +01:00
1 parent 03a265b97f
commit d75c93db85
31 files changed
+453 -80

No files matched your search

+1 -1
View File
@@ -10,7 +10,7 @@ jiff.workspace = true
ferese-theme-model = { path = "../ferese-theme-model" }
libcosmic = { workspace = true, features = ["a11y"] }
iced_accessibility = { git = "https://github.com/pop-os/libcosmic", rev = "03d7dcb832bc6d15bc1bb07327a1aa426b2d5bc0" }
iced_accessibility = { git = "https://github.com/ferese-wm/libcosmic", tag = "ferese-v0.1.0" }
[dev-dependencies]
ferese-config = { path = "../ferese-config" }
+3
View File
@@ -1,3 +1,4 @@
use cosmic::iced::border::Shape as BorderShape;
use cosmic::iced::{Background, Color};
use cosmic::theme;
use cosmic::widget::button;
@@ -27,6 +28,8 @@ pub(crate) fn accent_button_style(theme: &cosmic::Theme, state: State, focused:
let background = composite(fill, native.primary(false).base.into());
let foreground = foreground(background, component.on.into());
button::Style {
shape: Some(BorderShape::Continuous),
outline: None,
background: Some(Background::Color(background)),
text_color: Some(foreground),
icon_color: Some(foreground),
+2
View File
@@ -1,4 +1,5 @@
//! Date/time labels and a calendar grid; callers own navigation and popup behavior.
use cosmic::iced::border::Shape as BorderShape;
use cosmic::iced::{Alignment, Background, Border, Length};
use cosmic::widget::{column, container, row};
use cosmic::{Element, theme};
@@ -124,6 +125,7 @@ pub fn grid<'a, M: Clone + 'a>(
.class(theme::Container::custom(move |_| container::Style {
background: is_today.then_some(Background::Color(palette.accent.scale_alpha(0.2 * opacity))),
border: Border {
shape: BorderShape::Continuous,
radius: palette.radius.min(12.).into(),
..Default::default()
},
+22
View File
@@ -1,3 +1,4 @@
use cosmic::iced::border::Shape as BorderShape;
use cosmic::iced::{Background, Border, Color, Vector};
use cosmic::widget::{button, container};
use cosmic::{theme, widget};
@@ -66,6 +67,8 @@ pub fn text_button<'a, M: Clone + 'a>(
pub fn switch<'a, M: Clone + 'a>(enabled: bool, palette: Palette) -> button::Button<'a, M> {
let paint = move |focused| button::Style {
shape: Some(BorderShape::Continuous),
outline: None,
background: None,
text_color: Some(palette.text),
icon_color: Some(palette.text),
@@ -100,6 +103,8 @@ pub fn navigation_style(p: Palette, selected: bool) -> theme::Button {
pub fn settings_input(p: Palette) -> theme::TextInput {
let appearance = move |focused: bool, hovered: bool| cosmic::widget::text_input::Appearance {
shape: Some(BorderShape::Continuous),
outline: None,
background: mix(p.card, p.text, if hovered { 0.06 } else { 0.035 }).into(),
border_radius: p.radius.min(7.).into(),
border_width: 1.,
@@ -133,9 +138,11 @@ pub fn select<'a, M: 'a>(
widget::container(content).class(theme::Container::custom(move |_| container::Style {
background: Some(mix(p.card, p.text, 0.035).into()),
border: Border {
shape: BorderShape::Continuous,
width: 1.,
color: mix(p.card, p.text, 0.18),
radius: p.radius.min(7.).into(),
..Default::default()
},
..Default::default()
}))
@@ -170,6 +177,8 @@ fn styled_button(p: Palette, selected: bool, navigation: bool, opacity: f32, foc
};
button::Style {
shape: Some(BorderShape::Continuous),
outline: None,
background: Some(Background::Color(background)),
text_color: Some(on),
icon_color: Some(on),
@@ -208,6 +217,8 @@ pub fn authentication_button(palette: Palette) -> theme::Button {
(crate::composite(palette.card, palette.background), palette.muted)
};
button::Style {
shape: Some(BorderShape::Continuous),
outline: None,
background: Some(Background::Color(fill)),
text_color: Some(foreground),
icon_color: Some(foreground),
@@ -231,6 +242,8 @@ pub fn authentication_input(palette: Palette) -> theme::TextInput {
let accent = palette.accent;
let radius = palette.radius.min(10.);
let appearance = move |focused: bool| widget::text_input::Appearance {
shape: Some(BorderShape::Continuous),
outline: None,
background: Color::from_rgba(text.r, text.g, text.b, 0.045).into(),
border_radius: radius.into(),
border_width: 1.,
@@ -258,6 +271,8 @@ pub fn authentication_input(palette: Palette) -> theme::TextInput {
pub fn lock_input(radius: f32, accent: cosmic::iced::Color, surface: cosmic::iced::Color) -> theme::TextInput {
let appearance = move |focused: bool| widget::text_input::Appearance {
shape: Some(BorderShape::Continuous),
outline: None,
background: cosmic::iced::Color::from_rgba(
(surface.r + 1.) * 0.5,
(surface.g + 1.) * 0.5,
@@ -299,6 +314,8 @@ pub fn shell_button(
pressed: bool,
) -> button::Style {
button::Style {
shape: Some(BorderShape::Continuous),
outline: None,
text_color: Some(foreground),
icon_color: Some(foreground),
border_radius: radius.into(),
@@ -318,6 +335,7 @@ pub fn surface_appearance(background: Color, radius: f32) -> container::Style {
container::Style {
background: Some(Background::Color(background)),
border: Border {
shape: BorderShape::Continuous,
radius: radius.into(),
..Default::default()
},
@@ -327,6 +345,8 @@ pub fn surface_appearance(background: Color, radius: f32) -> container::Style {
pub fn notification_button(foreground: Color, hover: Color, radius: f32, filled: bool) -> theme::Button {
let style = move |active: bool| button::Style {
shape: Some(BorderShape::Continuous),
outline: None,
text_color: Some(foreground),
icon_color: Some(foreground),
background: (active || filled).then_some(Background::Color(hover)),
@@ -343,6 +363,8 @@ pub fn notification_button(foreground: Color, hover: Color, radius: f32, filled:
pub fn filled_button(fill: Color, foreground: Color, radius: f32, opacity: f32) -> theme::Button {
let paint = move |outline| button::Style {
shape: Some(BorderShape::Continuous),
outline: None,
background: Some(Color { a: opacity, ..fill }.into()),
text_color: Some(foreground),
icon_color: Some(foreground),
+5
View File
@@ -1,5 +1,6 @@
use cosmic::iced::advanced::widget::{Id, Operation, Tree, tree};
use cosmic::iced::advanced::{Clipboard, Layout, Shell, Widget, layout, mouse, renderer};
use cosmic::iced::border::Shape as BorderShape;
use cosmic::iced::{Event, Length, Rectangle, Size, keyboard};
use cosmic::{Element, Renderer, Theme};
use ferese_theme_model::Appearance;
@@ -65,6 +66,8 @@ pub fn tile<M: Clone + 'static>(
fn tile_style(palette: crate::Palette, selected: bool) -> cosmic::theme::Button {
let style = move |focused: bool, hovered: bool| cosmic::widget::button::Style {
shape: Some(BorderShape::Continuous),
outline: None,
background: Some(if hovered { palette.sidebar } else { palette.card }.into()),
border_width: if selected { 2. } else { 0. },
border_color: palette.accent,
@@ -395,9 +398,11 @@ impl<M: Clone> Widget<M, Theme, Renderer> for Radio<'_, M> {
renderer::Quad {
bounds: layout.bounds(),
border: cosmic::iced::Border {
shape: BorderShape::Continuous,
color: style.text_color,
width: 2.,
radius: 10.into(),
..Default::default()
},
..Default::default()
},
+1 -1
View File
@@ -1,4 +1,4 @@
/// Radius of a concentric inset, in the same units as the outer radius.
/// Radius of a circular inset. Squircle insets retain an `Outline` and its distance offset.
pub fn inner_radius(outer: f32, padding: f32) -> f32 {
(outer - padding).max(0.0)
}
+3
View File
@@ -1,5 +1,6 @@
//! Shared menu layouts and paint; callers own actions and animation timing.
use cosmic::Element;
use cosmic::iced::border::Shape as BorderShape;
use cosmic::iced::{Alignment, Color, Length};
use cosmic::widget::{button, container, row as iced_row};
@@ -115,11 +116,13 @@ pub fn slider(foreground: Color, opacity: f32) -> cosmic::theme::iced::Slider {
),
width: 4.,
border: cosmic::iced::Border {
shape: BorderShape::Continuous,
radius: 2.into(),
..Default::default()
},
},
handle: Handle {
corner_shape: BorderShape::Circular,
shape: HandleShape::Circle { radius: 6. },
background: foreground.into(),
border_width: 0.,
+6 -2
View File
@@ -1,4 +1,5 @@
use cosmic::iced::Color;
use cosmic::iced::border::Shape as BorderShape;
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Palette {
@@ -68,8 +69,9 @@ impl Palette {
.text_tint(rgba(self.text).color)
.accent(rgba(self.accent).color)
.build();
crate::apply(&mut native, self.on_accent);
cosmic::Theme::custom(std::sync::Arc::new(native))
cosmic::Theme::custom(std::sync::Arc::new(native)).corner_shape(BorderShape::Continuous)
}
pub fn application_style(self, background: Color) -> cosmic::iced::theme::Style {
@@ -135,7 +137,9 @@ mod tests {
resolved.accessibility.increase_contrast = high_contrast;
let palette = Palette::from_resolved(&resolved);
assert_eq!(palette.high_contrast, high_contrast);
assert_eq!(palette.native_theme().cosmic().is_high_contrast, high_contrast);
let native = palette.native_theme();
assert_eq!(native.cosmic().is_high_contrast, high_contrast);
assert_eq!(native.corner_shape, BorderShape::Continuous);
}
}
}