mirror of
https://github.com/emilk/egui.git
synced 2026-08-29 04:40:03 -04:00
Sync window theme with egui theme (#8299)
Adds a new option to sync the window theme with the egui theme, enabled by default. Works across viewports. https://github.com/user-attachments/assets/513c2318-cd6e-4e2b-805d-04002c375a10 --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -243,6 +243,12 @@ pub struct ViewportState {
|
|||||||
// ----------------------
|
// ----------------------
|
||||||
// Cross-frame statistics:
|
// Cross-frame statistics:
|
||||||
pub num_multipass_in_row: usize,
|
pub num_multipass_in_row: usize,
|
||||||
|
|
||||||
|
/// The last theme we sent to the native window via [`ViewportCommand::SetTheme`],
|
||||||
|
/// used to avoid sending redundant commands.
|
||||||
|
///
|
||||||
|
/// See [`crate::Options::sync_window_theme`].
|
||||||
|
pub(crate) last_sent_window_theme: Option<crate::SystemTheme>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// What called [`Context::request_repaint`] or [`Context::request_discard`]?
|
/// What called [`Context::request_repaint`] or [`Context::request_discard`]?
|
||||||
@@ -2393,6 +2399,8 @@ impl Context {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.sync_window_theme();
|
||||||
|
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
self.debug_painting();
|
self.debug_painting();
|
||||||
|
|
||||||
@@ -2404,6 +2412,38 @@ impl Context {
|
|||||||
output
|
output
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Keep the native window theme in sync with the egui [`crate::ThemePreference`],
|
||||||
|
/// if [`crate::Options::sync_window_theme`] is enabled.
|
||||||
|
///
|
||||||
|
/// Sends a [`ViewportCommand::SetTheme`] to the current viewport whenever the
|
||||||
|
/// derived theme changes, so the native window decorations match the egui theme.
|
||||||
|
fn sync_window_theme(&self) {
|
||||||
|
if !self.options(|o| o.sync_window_theme) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
use crate::{SystemTheme, ThemePreference};
|
||||||
|
let window_theme = match self.options(|o| o.theme_preference) {
|
||||||
|
ThemePreference::System => SystemTheme::SystemDefault,
|
||||||
|
ThemePreference::Dark => SystemTheme::Dark,
|
||||||
|
ThemePreference::Light => SystemTheme::Light,
|
||||||
|
};
|
||||||
|
|
||||||
|
let changed = self.write(|ctx| {
|
||||||
|
let viewport = ctx.viewport();
|
||||||
|
if viewport.last_sent_window_theme == Some(window_theme) {
|
||||||
|
false
|
||||||
|
} else {
|
||||||
|
viewport.last_sent_window_theme = Some(window_theme);
|
||||||
|
true
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if changed {
|
||||||
|
self.send_viewport_cmd(ViewportCommand::SetTheme(window_theme));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Called at the end of the pass.
|
/// Called at the end of the pass.
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
fn debug_painting(&self) {
|
fn debug_painting(&self) {
|
||||||
|
|||||||
@@ -216,6 +216,18 @@ pub struct Options {
|
|||||||
#[cfg_attr(feature = "serde", serde(skip))]
|
#[cfg_attr(feature = "serde", serde(skip))]
|
||||||
pub(crate) system_theme: Option<Theme>,
|
pub(crate) system_theme: Option<Theme>,
|
||||||
|
|
||||||
|
/// If `true`, egui will keep the native window theme in sync with
|
||||||
|
/// [`Self::theme_preference`] by sending a [`crate::ViewportCommand::SetTheme`]
|
||||||
|
/// to the root viewport whenever the preference changes.
|
||||||
|
///
|
||||||
|
/// This makes the native window decorations (title bar, borders, …) match the
|
||||||
|
/// theme selected inside egui.
|
||||||
|
///
|
||||||
|
/// Set this to `false` if you want to manage the native window theme yourself.
|
||||||
|
///
|
||||||
|
/// This is `true` by default.
|
||||||
|
pub sync_window_theme: bool,
|
||||||
|
|
||||||
/// Global zoom factor of the UI.
|
/// Global zoom factor of the UI.
|
||||||
///
|
///
|
||||||
/// This is used to calculate the `pixels_per_point`
|
/// This is used to calculate the `pixels_per_point`
|
||||||
@@ -318,6 +330,7 @@ impl Default for Options {
|
|||||||
theme_preference: Default::default(),
|
theme_preference: Default::default(),
|
||||||
fallback_theme: Theme::Dark,
|
fallback_theme: Theme::Dark,
|
||||||
system_theme: None,
|
system_theme: None,
|
||||||
|
sync_window_theme: true,
|
||||||
zoom_factor: 1.0,
|
zoom_factor: 1.0,
|
||||||
zoom_with_keyboard: true,
|
zoom_with_keyboard: true,
|
||||||
quit_shortcuts: vec![crate::KeyboardShortcut::new(
|
quit_shortcuts: vec![crate::KeyboardShortcut::new(
|
||||||
@@ -381,6 +394,7 @@ impl Options {
|
|||||||
theme_preference,
|
theme_preference,
|
||||||
fallback_theme: _,
|
fallback_theme: _,
|
||||||
system_theme: _,
|
system_theme: _,
|
||||||
|
sync_window_theme,
|
||||||
zoom_factor,
|
zoom_factor,
|
||||||
zoom_with_keyboard,
|
zoom_with_keyboard,
|
||||||
quit_shortcuts: _, // not shown in ui
|
quit_shortcuts: _, // not shown in ui
|
||||||
@@ -429,6 +443,8 @@ impl Options {
|
|||||||
.show(ui, |ui| {
|
.show(ui, |ui| {
|
||||||
theme_preference.radio_buttons(ui);
|
theme_preference.radio_buttons(ui);
|
||||||
|
|
||||||
|
ui.checkbox(sync_window_theme, "Sync window theme with egui theme");
|
||||||
|
|
||||||
let style = std::sync::Arc::make_mut(match theme {
|
let style = std::sync::Arc::make_mut(match theme {
|
||||||
Theme::Dark => dark_style,
|
Theme::Dark => dark_style,
|
||||||
Theme::Light => light_style,
|
Theme::Light => light_style,
|
||||||
|
|||||||
Reference in New Issue
Block a user