Skip to content

Commit

Permalink
Use dark-light on Mac and Windows
Browse files Browse the repository at this point in the history
dark-light has a nasty problem on Linux: frewsxcv/rust-dark-light#17

So we made dark-light opt-in in #1437

This PR makes dark-light a default dependency again,
but only use it on Max and Windows.

This is controlled with the new NativeOptions::follow_system_theme.
If this isn't enabled, then NativeOptions::default_theme is used.
  • Loading branch information
emilk committed Jun 9, 2022
1 parent 4525cad commit 9cbe0a0
Show file tree
Hide file tree
Showing 5 changed files with 84 additions and 38 deletions.
4 changes: 3 additions & 1 deletion eframe/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,11 @@ all-features = true


[features]
default = ["default_fonts", "glow"]
default = ["dark-light", "default_fonts", "glow"]

## Detect dark mode system preference using [`dark-light`](https://docs.rs/dark-light).
##
## See also [`NativeOptions::follow_system_theme`] and [`NativeOptions::default_theme`].
dark-light = ["dep:dark-light"]

## If set, egui will use `include_bytes!` to bundle some fonts.
Expand Down
65 changes: 63 additions & 2 deletions eframe/src/epi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,23 @@ pub struct NativeOptions {

/// What rendering backend to use.
pub renderer: Renderer,

/// If the `dark-light` feature is enabled:
///
/// Try to detect and follow the system preferred setting for dark vs light mode.
///
/// By default, this is `true` on Mac and Windows, but `false` on Linux
/// due to <https://github.com/frewsxcv/rust-dark-light/issues/17>.
///
/// See also [`Self::default_theme`].
pub follow_system_theme: bool,

/// Use the dark mode theme if:
/// * the `dark-light` feature is disabled
/// * OR [`Self::follow_system_theme`] is `false`.
///
/// Default: `Theme::Dark` (default to dark theme).
pub default_theme: Theme,
}

impl Default for NativeOptions {
Expand All @@ -265,6 +282,49 @@ impl Default for NativeOptions {
stencil_buffer: 0,
hardware_acceleration: HardwareAcceleration::Preferred,
renderer: Renderer::default(),
follow_system_theme: cfg!(target_os = "macos") || cfg!(target_os = "windows"),
default_theme: Theme::Dark,
}
}
}

impl NativeOptions {
/// The theme used by the system.
#[cfg(feature = "dark-light")]
pub fn system_theme(&self) -> Option<Theme> {
if self.follow_system_theme {
crate::profile_scope!("dark_light::detect");
match dark_light::detect() {
dark_light::Mode::Dark => Some(Theme::Dark),
dark_light::Mode::Light => Some(Theme::Light),
}
} else {
None
}
}

/// The theme used by the system.
#[cfg(not(feature = "dark-light"))]
pub fn system_theme(&self) -> Option<Theme> {
None
}
}

/// Dark or Light theme.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
pub enum Theme {
/// Dark mode: light text on a dark background.
Dark,
/// Light mode: dark text on a light background.
Light,
}

impl Theme {
pub(crate) fn egui_visuals(self) -> egui::Visuals {
match self {
Self::Dark => egui::Visuals::dark(),
Self::Light => egui::Visuals::light(),
}
}
}
Expand Down Expand Up @@ -531,9 +591,10 @@ pub struct IntegrationInfo {
/// If the app is running in a Web context, this returns information about the environment.
pub web_info: Option<WebInfo>,

/// Does the system prefer dark mode (over light mode)?
/// Does the OS use dark or light mode?
///
/// `None` means "don't know".
pub prefer_dark_mode: Option<bool>,
pub system_theme: Option<Theme>,

/// Seconds of cpu usage (in seconds) of UI code on the previous frame.
/// `None` if this is the first frame.
Expand Down
33 changes: 4 additions & 29 deletions eframe/src/native/epi_integration.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::{epi, WindowInfo};
use crate::{epi, Theme, WindowInfo};
use egui_winit::{native_pixels_per_point, WindowSettings};
use winit::event_loop::EventLoopWindowTarget;

Expand Down Expand Up @@ -47,12 +47,7 @@ pub fn window_builder(
max_window_size,
resizable,
transparent,
vsync: _, // used in `fn create_display`
multisampling: _, // used in `fn create_display`
depth_buffer: _, // used in `fn create_display`
stencil_buffer: _, // used in `fn create_display`
hardware_acceleration: _, // used in `fn create_display`
renderer: _, // used in `fn run_native`
..
} = native_options;

let window_icon = icon_data.clone().and_then(load_icon);
Expand Down Expand Up @@ -187,6 +182,7 @@ impl EpiIntegration {
event_loop: &EventLoopWindowTarget<E>,
max_texture_side: usize,
window: &winit::window::Window,
system_theme: Option<Theme>,
storage: Option<Box<dyn epi::Storage>>,
#[cfg(feature = "glow")] gl: Option<std::sync::Arc<glow::Context>>,
#[cfg(feature = "wgpu")] render_state: Option<egui_wgpu::RenderState>,
Expand All @@ -195,12 +191,10 @@ impl EpiIntegration {

*egui_ctx.memory() = load_egui_memory(storage.as_deref()).unwrap_or_default();

let prefer_dark_mode = prefer_dark_mode();

let frame = epi::Frame {
info: epi::IntegrationInfo {
web_info: None,
prefer_dark_mode,
system_theme,
cpu_usage: None,
native_pixels_per_point: Some(native_pixels_per_point(window)),
window_info: read_window_info(window, egui_ctx.pixels_per_point()),
Expand All @@ -213,12 +207,6 @@ impl EpiIntegration {
render_state,
};

if prefer_dark_mode == Some(true) {
egui_ctx.set_visuals(egui::Visuals::dark());
} else {
egui_ctx.set_visuals(egui::Visuals::light());
}

let mut egui_winit = egui_winit::State::new(event_loop);
egui_winit.set_max_texture_side(max_texture_side);
let pixels_per_point = window.scale_factor() as f32;
Expand Down Expand Up @@ -376,16 +364,3 @@ pub fn load_egui_memory(_storage: Option<&dyn epi::Storage>) -> Option<egui::Mem
#[cfg(not(feature = "persistence"))]
None
}

#[cfg(feature = "dark-light")]
fn prefer_dark_mode() -> Option<bool> {
match dark_light::detect() {
dark_light::Mode::Dark => Some(true),
dark_light::Mode::Light => Some(false),
}
}

#[cfg(not(feature = "dark-light"))]
fn prefer_dark_mode() -> Option<bool> {
None
}
14 changes: 14 additions & 0 deletions eframe/src/native/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,15 +66,22 @@ pub fn run_glow(
let mut painter = egui_glow::Painter::new(gl.clone(), None, "")
.unwrap_or_else(|error| panic!("some OpenGL error occurred {}\n", error));

let system_theme = native_options.system_theme();
let mut integration = epi_integration::EpiIntegration::new(
&event_loop,
painter.max_texture_side(),
gl_window.window(),
system_theme,
storage,
Some(gl.clone()),
#[cfg(feature = "wgpu")]
None,
);
integration.egui_ctx.set_visuals(
system_theme
.unwrap_or(native_options.default_theme)
.egui_visuals(),
);

{
let event_loop_proxy = egui::mutex::Mutex::new(event_loop.create_proxy());
Expand Down Expand Up @@ -248,15 +255,22 @@ pub fn run_wgpu(

let render_state = painter.get_render_state().expect("Uninitialized");

let system_theme = native_options.system_theme();
let mut integration = epi_integration::EpiIntegration::new(
&event_loop,
painter.max_texture_side().unwrap_or(2048),
&window,
system_theme,
storage,
#[cfg(feature = "glow")]
None,
Some(render_state.clone()),
);
integration.egui_ctx.set_visuals(
system_theme
.unwrap_or(native_options.default_theme)
.egui_visuals(),
);

{
let event_loop_proxy = egui::mutex::Mutex::new(event_loop.create_proxy());
Expand Down
6 changes: 0 additions & 6 deletions egui_demo_app/src/wrap_app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,12 +112,6 @@ impl WrapApp {
}
}

if cc.integration_info.prefer_dark_mode == Some(false) {
cc.egui_ctx.set_visuals(egui::Visuals::light()); // use light mode if explicitly asked for
} else {
cc.egui_ctx.set_visuals(egui::Visuals::dark()); // use dark mode if there is no preference, or the preference is dark mode
}

slf
}

Expand Down

0 comments on commit 9cbe0a0

Please sign in to comment.