Unify shell corner radius and speed up Settings page switching
This commit is contained in:
1 parent
ef912daeba
commit
e5e2b74a25
10 files changed
+164
-91
No files matched your search
@@ -76,7 +76,7 @@ impl Default for ShellTheme {
|
||||
bar_margin_top: 0,
|
||||
bar_window_gap: 0,
|
||||
bar_margin_horizontal: 0,
|
||||
bar_radius: 0.0,
|
||||
bar_radius: 14.0,
|
||||
material_radius: 14.0,
|
||||
panel_padding: 12.0,
|
||||
control_gap: 12.0,
|
||||
@@ -253,8 +253,10 @@ struct ThemeGeometryConfig {
|
||||
top_bar_window_gap: i32,
|
||||
#[serde(default = "default_bar_margin_horizontal")]
|
||||
top_bar_margin_horizontal: i32,
|
||||
#[serde(default = "default_bar_radius")]
|
||||
top_bar_radius: f32,
|
||||
#[serde(default)]
|
||||
shell_radius: Option<f32>,
|
||||
#[serde(default)]
|
||||
top_bar_radius: Option<f32>,
|
||||
#[serde(default = "default_panel_padding")]
|
||||
panel_padding: f32,
|
||||
#[serde(default = "default_control_gap")]
|
||||
@@ -268,7 +270,8 @@ impl Default for ThemeGeometryConfig {
|
||||
top_bar_margin_top: default_bar_margin_top(),
|
||||
top_bar_window_gap: default_bar_window_gap(),
|
||||
top_bar_margin_horizontal: default_bar_margin_horizontal(),
|
||||
top_bar_radius: default_bar_radius(),
|
||||
shell_radius: None,
|
||||
top_bar_radius: None,
|
||||
panel_padding: default_panel_padding(),
|
||||
control_gap: default_control_gap(),
|
||||
}
|
||||
@@ -330,8 +333,17 @@ pub(crate) fn parse_source(source: &str) -> Result<ShellConfig, ferese_config::E
|
||||
.validate()
|
||||
.map_err(ferese_config::Error::from)?;
|
||||
let mut theme = shell_theme(&config.theme);
|
||||
theme.material_radius =
|
||||
nonnegative_or(config.appearance.corner_radius.unwrap_or(14.0), 14.0);
|
||||
theme.material_radius = nonnegative_or(
|
||||
config
|
||||
.theme
|
||||
.geometry
|
||||
.shell_radius
|
||||
.or(config.appearance.corner_radius)
|
||||
.or(config.theme.geometry.top_bar_radius)
|
||||
.unwrap_or(14.0),
|
||||
14.0,
|
||||
);
|
||||
theme.bar_radius = theme.material_radius;
|
||||
|
||||
Ok(ShellConfig {
|
||||
notifications: config.notifications,
|
||||
@@ -388,7 +400,14 @@ fn shell_theme(theme: &ThemeConfig) -> ShellTheme {
|
||||
bar_margin_top: theme.geometry.top_bar_margin_top.max(0),
|
||||
bar_window_gap: theme.geometry.top_bar_window_gap.max(0),
|
||||
bar_margin_horizontal: theme.geometry.top_bar_margin_horizontal.max(0),
|
||||
bar_radius: nonnegative_or(theme.geometry.top_bar_radius, defaults.bar_radius),
|
||||
bar_radius: nonnegative_or(
|
||||
theme
|
||||
.geometry
|
||||
.shell_radius
|
||||
.or(theme.geometry.top_bar_radius)
|
||||
.unwrap_or(14.0),
|
||||
defaults.bar_radius,
|
||||
),
|
||||
panel_padding: nonnegative_or(theme.geometry.panel_padding, defaults.panel_padding),
|
||||
control_gap: nonnegative_or(theme.geometry.control_gap, defaults.control_gap),
|
||||
shadow_offset_y: finite_or(theme.shadow.soft.offset_y, defaults.shadow_offset_y),
|
||||
@@ -476,10 +495,6 @@ const fn default_bar_margin_horizontal() -> i32 {
|
||||
0
|
||||
}
|
||||
|
||||
const fn default_bar_radius() -> f32 {
|
||||
0.0
|
||||
}
|
||||
|
||||
const fn default_panel_padding() -> f32 {
|
||||
12.0
|
||||
}
|
||||
@@ -572,6 +587,21 @@ theme {
|
||||
assert_eq!(config.theme.background.mode, WallpaperMode::Fit);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn shell_radius_unifies_surfaces_and_preserves_legacy_fallbacks() {
|
||||
for radius in [0.0, 18.0] {
|
||||
let config = parse_source(&format!("appearance {{\n corner-radius 9\n}}\ntheme {{\n geometry {{\n shell-radius {radius}\n top-bar-radius 5\n window-radius 23\n }}\n}}")).unwrap();
|
||||
assert_eq!(config.theme.material_radius, radius);
|
||||
assert_eq!(config.theme.bar_radius, radius);
|
||||
}
|
||||
let legacy = parse_source("theme {\n geometry {\n top-bar-radius 7\n }\n}").unwrap();
|
||||
assert_eq!(legacy.theme.material_radius, 7.0);
|
||||
assert_eq!(legacy.theme.bar_radius, 7.0);
|
||||
let legacy = parse_source("appearance {\n corner-radius 6\n}").unwrap();
|
||||
assert_eq!(legacy.theme.material_radius, 6.0);
|
||||
assert_eq!(legacy.theme.bar_radius, 6.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn defaults_to_the_ferese_visual_profile() {
|
||||
let config: FereseConfig = ferese_config::from_str("").unwrap();
|
||||
@@ -586,7 +616,7 @@ theme {
|
||||
assert_eq!(theme.bar_margin_top, 0);
|
||||
assert_eq!(theme.bar_height, 28.0);
|
||||
assert_eq!(theme.bar_margin_horizontal, 0);
|
||||
assert_eq!(theme.bar_radius, 0.0);
|
||||
assert_eq!(theme.bar_radius, 14.0);
|
||||
assert_eq!(theme.bar_background, ShellTheme::default().bar_background);
|
||||
assert_eq!(theme.for_bar().text_primary, theme.bar_text_primary);
|
||||
assert_ne!(theme.for_bar().text_primary, theme.text_primary);
|
||||
|
||||
@@ -154,7 +154,7 @@ fn main() -> cosmic::iced::Result {
|
||||
"../../../assets/fonts/Cantarell-ExtraBold.otf"
|
||||
)));
|
||||
let mut config = config::load();
|
||||
motion::configure(config.animations);
|
||||
motion::configure(config.animations, config.theme.material_radius);
|
||||
let compositor_wallpaper = std::env::var_os("FERESE_COMPOSITOR_WALLPAPER").is_some();
|
||||
if compositor_wallpaper {
|
||||
// The compositor owns one GPU image, shared across output renderers;
|
||||
@@ -771,7 +771,7 @@ impl FereseShell {
|
||||
.write()
|
||||
.unwrap() = configured_font(config.font_family.as_deref());
|
||||
}
|
||||
motion::configure(config.animations);
|
||||
motion::configure(config.animations, config.theme.material_radius);
|
||||
if self.config.animations != config.animations
|
||||
&& let Some(menu) = &mut self.menu
|
||||
{
|
||||
@@ -1365,15 +1365,20 @@ impl FereseShell {
|
||||
.note_editor
|
||||
.as_ref()
|
||||
.is_some_and(|editor| editor.id == id);
|
||||
body = body.push(row([]).push(header).push(
|
||||
button::text(if editing { "Done" } else { "Edit" }).on_press(cosmic::Action::App(
|
||||
if editing {
|
||||
Message::FinishNoteEdit
|
||||
} else {
|
||||
Message::BeginNoteEdit(id.to_owned())
|
||||
},
|
||||
body = body.push(
|
||||
row([]).push(header).push(motion::button(
|
||||
button::custom(text(if editing { "Done" } else { "Edit" }))
|
||||
.padding([4, 8])
|
||||
.on_press(cosmic::Action::App(if editing {
|
||||
Message::FinishNoteEdit
|
||||
} else {
|
||||
Message::BeginNoteEdit(id.to_owned())
|
||||
})),
|
||||
foreground,
|
||||
false,
|
||||
1.0,
|
||||
)),
|
||||
));
|
||||
);
|
||||
} else if !note.title.is_empty() {
|
||||
body = body.push(
|
||||
cosmic::widget::text(note.title.clone())
|
||||
@@ -1393,6 +1398,12 @@ impl FereseShell {
|
||||
let id = id.to_owned();
|
||||
body = body.push(
|
||||
cosmic::widget::TextEditor::new(&editor.content)
|
||||
.style(|theme, status| {
|
||||
use cosmic::iced::widget::text_editor::Catalog;
|
||||
let mut style = theme.style(&<cosmic::Theme as Catalog>::default(), status);
|
||||
style.border.radius = motion::radius(f32::MAX).into();
|
||||
style
|
||||
})
|
||||
.height(Length::Fill)
|
||||
.font(font)
|
||||
.size(note.text_size)
|
||||
@@ -1417,7 +1428,7 @@ impl FereseShell {
|
||||
.class(theme::Text::Color(foreground)),
|
||||
);
|
||||
}
|
||||
let radius = note.radius;
|
||||
let radius = self.config.theme.material_radius;
|
||||
container(body)
|
||||
.padding(note.padding)
|
||||
.width(Length::Fill)
|
||||
@@ -1646,7 +1657,7 @@ impl FereseShell {
|
||||
tint.a *= clock.opacity;
|
||||
Background::Color(tint)
|
||||
});
|
||||
let radius = clock.radius;
|
||||
let radius = self.config.theme.material_radius;
|
||||
container(labels)
|
||||
.padding(clock.padding)
|
||||
.width(Length::Fill)
|
||||
@@ -2249,7 +2260,7 @@ fn workspace_selector_style(
|
||||
border: Border {
|
||||
color: color_with_opacity(shell_theme.accent, 0.55),
|
||||
width: if active_elsewhere { 1.0 } else { 0.0 },
|
||||
radius: 6.0.into(),
|
||||
radius: shell_theme.material_radius.min(14.0).into(),
|
||||
},
|
||||
..Default::default()
|
||||
}
|
||||
@@ -2440,7 +2451,7 @@ fn bar_group_style(theme: ShellTheme) -> container::Style {
|
||||
border: Border {
|
||||
color: color_with_opacity(theme.text_muted, 0.12),
|
||||
width: 1.0,
|
||||
radius: 7.0.into(),
|
||||
radius: theme.material_radius.min(16.0).into(),
|
||||
},
|
||||
..Default::default()
|
||||
}
|
||||
|
||||
@@ -42,7 +42,16 @@ impl Settings {
|
||||
}
|
||||
}
|
||||
static SETTINGS: std::sync::OnceLock<std::sync::RwLock<Settings>> = std::sync::OnceLock::new();
|
||||
pub(crate) fn configure(settings: Settings) {
|
||||
static SHELL_RADIUS: std::sync::atomic::AtomicU32 =
|
||||
std::sync::atomic::AtomicU32::new(14.0_f32.to_bits());
|
||||
|
||||
/// All shell shapes share one radius, capped to fit smaller controls.
|
||||
pub(crate) fn radius(limit: f32) -> f32 {
|
||||
f32::from_bits(SHELL_RADIUS.load(std::sync::atomic::Ordering::Relaxed)).min(limit)
|
||||
}
|
||||
|
||||
pub(crate) fn configure(settings: Settings, radius: f32) {
|
||||
SHELL_RADIUS.store(radius.to_bits(), std::sync::atomic::Ordering::Relaxed);
|
||||
*SETTINGS
|
||||
.get_or_init(|| std::sync::RwLock::new(Settings::default()))
|
||||
.write()
|
||||
@@ -138,7 +147,7 @@ pub(crate) fn button<'a, M: Clone + 'a>(
|
||||
let paint = move |progress: f32, pressed: bool| cosmic::widget::button::Style {
|
||||
text_color: Some(foreground),
|
||||
icon_color: Some(foreground),
|
||||
border_radius: 6.0.into(),
|
||||
border_radius: radius(14.0).into(),
|
||||
background: Some(cosmic::iced::Background::Color(cosmic::iced::Color {
|
||||
a: if pressed {
|
||||
0.20 * opacity
|
||||
|
||||
@@ -98,7 +98,7 @@ fn card_button<'a>(
|
||||
text_color: Some(foreground),
|
||||
icon_color: Some(foreground),
|
||||
background: (active || round).then_some(Background::Color(hover)),
|
||||
border_radius: (if round { 9.0 } else { 0.0 }).into(),
|
||||
border_radius: (if round { motion::radius(11.0) } else { 0.0 }).into(),
|
||||
..Default::default()
|
||||
};
|
||||
button::custom(content)
|
||||
@@ -141,7 +141,7 @@ fn icon_control<'a>(
|
||||
.class(theme::Container::custom(move |_| container::Style {
|
||||
background: Some(Background::Color(background)),
|
||||
border: Border {
|
||||
radius: 6.0.into(),
|
||||
radius: motion::radius(12.0).into(),
|
||||
..Default::default()
|
||||
},
|
||||
text_color: Some(foreground),
|
||||
@@ -380,7 +380,7 @@ impl FereseShell {
|
||||
.class(theme::Container::custom(move |_| container::Style {
|
||||
background: Some(Background::Color(well)),
|
||||
border: Border {
|
||||
radius: 8.0.into(),
|
||||
radius: motion::radius(15.0).into(),
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
@@ -397,7 +397,7 @@ impl FereseShell {
|
||||
.class(theme::Container::custom(move |_| container::Style {
|
||||
background: Some(Background::Color(accent)),
|
||||
border: Border {
|
||||
radius: 8.0.into(),
|
||||
radius: motion::radius(8.0).into(),
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
@@ -747,7 +747,7 @@ impl FereseShell {
|
||||
.class(theme::Container::custom(move |_| container::Style {
|
||||
background: Some(Background::Color(well)),
|
||||
border: Border {
|
||||
radius: 28.0.into(),
|
||||
radius: motion::radius(28.0).into(),
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
|
||||
@@ -277,7 +277,7 @@ impl FereseShell {
|
||||
theme::Container::custom(move |_| container::Style {
|
||||
background: Some(Background::Color(foreground)),
|
||||
border: Border {
|
||||
radius: 2.0.into(),
|
||||
radius: motion::radius(2.0).into(),
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
@@ -345,7 +345,7 @@ impl FereseShell {
|
||||
0.12 * p,
|
||||
))),
|
||||
border: Border {
|
||||
radius: 10.0.into(),
|
||||
radius: motion::radius(20.0).into(),
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
@@ -772,7 +772,7 @@ fn status_summary<'a>(
|
||||
..badge_color
|
||||
})),
|
||||
border: Border {
|
||||
radius: 9.0.into(),
|
||||
radius: motion::radius(16.0).into(),
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
@@ -823,7 +823,7 @@ fn level_meter(
|
||||
}
|
||||
})),
|
||||
border: Border {
|
||||
radius: 2.5.into(),
|
||||
radius: motion::radius(2.5).into(),
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
@@ -854,7 +854,7 @@ fn control_card<'a>(
|
||||
..foreground
|
||||
})),
|
||||
border: Border {
|
||||
radius: 11.0.into(),
|
||||
radius: motion::radius(22.0).into(),
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
@@ -890,7 +890,7 @@ fn connection_control<'a>(
|
||||
opacity,
|
||||
)),
|
||||
border: Border {
|
||||
radius: 10.0.into(),
|
||||
radius: motion::radius(20.0).into(),
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
@@ -1006,12 +1006,16 @@ fn slider_row(
|
||||
),
|
||||
width: 4.0,
|
||||
border: Border {
|
||||
radius: 2.0.into(),
|
||||
radius: motion::radius(2.0).into(),
|
||||
..Default::default()
|
||||
},
|
||||
},
|
||||
handle: Handle {
|
||||
shape: HandleShape::Circle { radius: 5.0 },
|
||||
shape: HandleShape::Rectangle {
|
||||
width: 10,
|
||||
height: 10,
|
||||
border_radius: motion::radius(5.0).into(),
|
||||
},
|
||||
background: foreground.into(),
|
||||
border_width: 0.0,
|
||||
border_color: Color::TRANSPARENT,
|
||||
|
||||
Reference in new issue
Block a user