Keep egui on the System theme preference so the OS appearance is followed live (#301) (#363)

This commit is contained in:
MarekSpodBiedry 2026-10-11 00:08:41 +02:00 committed by GitHub
parent 35a8617855
commit 6d8af2e5a4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 29 additions and 5 deletions

View File

@ -166,6 +166,8 @@ pub struct CadApp {
styled: bool,
/// The theme last installed into egui (`None` until the first frame).
shown_theme: Option<egui::Theme>,
/// Whether the last applied theme was handed to egui as the System preference.
shown_follows_system: bool,
pub frame_ms: f64,
pub quit_requested: bool,
/// The app may close although drawings have unsaved changes (they were dealt with, or the
@ -195,6 +197,7 @@ impl CadApp {
frame_cap: None,
styled: false,
shown_theme: None,
shown_follows_system: false,
frame_ms: 0.0,
quit_requested: false,
quit_confirmed: false,
@ -359,9 +362,11 @@ impl CadApp {
// browser report changes as input); the saved choice itself never changes here.
let shown = self.ui.theme.resolve(ctx.system_theme());
theme::set_active(shown);
if self.shown_theme != Some(shown) {
theme::apply(ctx, shown);
let follows_system = self.ui.theme == theme::ThemePref::System;
if self.shown_theme != Some(shown) || self.shown_follows_system != follows_system {
theme::apply(ctx, shown, follows_system);
self.shown_theme = Some(shown);
self.shown_follows_system = follows_system;
}
self.drain_control(ctx);
if !self.synthetic.is_empty() {
@ -582,6 +587,22 @@ mod tests {
assert_eq!(a.prefs_json(), r#"{"interfaceLanguage":"auto","saveFormat":"dxf","theme":"system"}"#);
}
#[test]
fn system_theme_keeps_egui_on_the_system_preference() {
let mut a = app();
a.start("ui.theme.system");
let ctx = egui::Context::default();
frame(&mut a, &ctx, Some(egui::Theme::Light));
// A concrete Light would pin the native window appearance and hide later OS changes.
assert_eq!(ctx.options(|o| o.theme_preference), egui::ThemePreference::System);
a.start("ui.theme.dark");
frame(&mut a, &ctx, Some(egui::Theme::Light));
assert_eq!(ctx.options(|o| o.theme_preference), egui::ThemePreference::Dark);
a.start("ui.theme.system");
frame(&mut a, &ctx, Some(egui::Theme::Light));
assert_eq!(ctx.options(|o| o.theme_preference), egui::ThemePreference::System);
}
#[test]
fn default_save_format_persists_and_names_new_drawings() {
let mut a = app();

View File

@ -284,12 +284,15 @@ fn visuals(theme: Theme) -> Visuals {
}
/// Install the styles of both themes and show `theme` (egui's own widgets, popups and menus
/// follow it; our own painting follows [`Tokens::get`]).
pub fn apply(ctx: &egui::Context, theme: Theme) {
/// follow it; our own painting follows [`Tokens::get`]). `follow_system` is true for the
/// [`ThemePref::System`] choice, whose `theme` was resolved from the OS report.
pub fn apply(ctx: &egui::Context, theme: Theme, follow_system: bool) {
set_active(theme);
ctx.set_visuals_of(Theme::Dark, visuals(Theme::Dark));
ctx.set_visuals_of(Theme::Light, visuals(Theme::Light));
ctx.set_theme(theme);
// A System choice keeps egui's own System preference: a concrete Light/Dark would pin the native
// window appearance (winit then stops reporting OS changes) and the app would never follow again.
ctx.set_theme(if follow_system { egui::ThemePreference::System } else { egui::ThemePreference::from(theme) });
ctx.all_styles_mut(|s| {
s.spacing.item_spacing = egui::vec2(6.0, 4.0);
s.spacing.button_padding = egui::vec2(6.0, 3.0);