Skip to content

Commit

Permalink
Make dark and light style configurable in Options
Browse files Browse the repository at this point in the history
  • Loading branch information
bash committed Jul 3, 2024
1 parent beb1264 commit 61cca8b
Show file tree
Hide file tree
Showing 3 changed files with 106 additions and 14 deletions.
35 changes: 27 additions & 8 deletions crates/egui/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -411,6 +411,8 @@ impl ContextImpl {
let is_outermost_viewport = self.viewport_stack.is_empty(); // not necessarily root, just outermost immediate viewport
self.viewport_stack.push(ids);

self.update_theme_mut(&new_raw_input);

self.begin_frame_repaint_logic(viewport_id);

let viewport = self.viewports.entry(viewport_id).or_default();
Expand Down Expand Up @@ -469,7 +471,13 @@ impl ContextImpl {
});

viewport.hits = if let Some(pos) = viewport.input.pointer.interact_pos() {
let interact_radius = self.memory.options.style.interaction.interact_radius;
let interact_radius = self
.memory
.options
.style
.active()
.interaction
.interact_radius;

crate::hit_test::hit_test(
&viewport.widgets_prev_frame,
Expand Down Expand Up @@ -565,12 +573,16 @@ impl ContextImpl {
crate::profile_scope!("preload_font_glyphs");
// Preload the most common characters for the most common fonts.
// This is not very important to do, but may save a few GPU operations.
for font_id in self.memory.options.style.text_styles.values() {
for font_id in self.memory.options.style.active().text_styles.values() {
fonts.lock().fonts.font(font_id).preload_common_characters();
}
}
}

fn update_theme_mut(&mut self, new_raw_input: &RawInput) {
self.memory.options.style.update(new_raw_input.system_theme);
}

#[cfg(feature = "accesskit")]
fn accesskit_node_builder(&mut self, id: Id) -> &mut accesskit::NodeBuilder {
let state = self
Expand Down Expand Up @@ -1215,7 +1227,14 @@ impl Context {
pub fn register_widget_info(&self, id: Id, make_info: impl Fn() -> crate::WidgetInfo) {
#[cfg(debug_assertions)]
self.write(|ctx| {
if ctx.memory.options.style.debug.show_interactive_widgets {
if ctx
.memory
.options
.style
.active()
.debug
.show_interactive_widgets
{
ctx.viewport().widgets_this_frame.set_info(id, make_info());
}
});
Expand Down Expand Up @@ -1574,7 +1593,7 @@ impl Context {

/// The [`Style`] used by all subsequent windows, panels etc.
pub fn style(&self) -> Arc<Style> {
self.options(|opt| opt.style.clone())
self.options(|opt| opt.style.active().clone())
}

/// Mutate the [`Style`] used by all subsequent windows, panels etc.
Expand All @@ -1587,7 +1606,7 @@ impl Context {
/// });
/// ```
pub fn style_mut(&self, mutate_style: impl FnOnce(&mut Style)) {
self.options_mut(|opt| mutate_style(std::sync::Arc::make_mut(&mut opt.style)));
self.options_mut(|opt| mutate_style(opt.style.active_mut()));
}

/// The [`Style`] used by all new windows, panels etc.
Expand All @@ -1596,7 +1615,7 @@ impl Context {
///
/// You can use [`Ui::style_mut`] to change the style of a single [`Ui`].
pub fn set_style(&self, style: impl Into<Arc<Style>>) {
self.options_mut(|opt| opt.style = style.into());
self.options_mut(|opt| opt.style.set_active(style.into()));
}

/// The [`Visuals`] used by all subsequent windows, panels etc.
Expand All @@ -1609,7 +1628,7 @@ impl Context {
/// ctx.set_visuals(egui::Visuals::light()); // Switch to light mode
/// ```
pub fn set_visuals(&self, visuals: crate::Visuals) {
self.options_mut(|opt| std::sync::Arc::make_mut(&mut opt.style).visuals = visuals);
self.options_mut(|opt| opt.style.active_mut().visuals = visuals);
}

/// The number of physical pixels for each logical point.
Expand Down Expand Up @@ -2431,7 +2450,7 @@ impl Context {
/// Whether or not to debug widget layout on hover.
#[cfg(debug_assertions)]
pub fn debug_on_hover(&self) -> bool {
self.options(|opt| opt.style.debug.debug_on_hover)
self.options(|opt| opt.style.active().debug.debug_on_hover)
}

/// Turn on/off whether or not to debug widget layout on hover.
Expand Down
75 changes: 70 additions & 5 deletions crates/egui/src/memory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ use ahash::{HashMap, HashSet};
use epaint::emath::TSTransform;

use crate::{
area, vec2, EventFilter, Id, IdMap, LayerId, Order, Pos2, Rangef, RawInput, Rect, Style, Vec2,
ViewportId, ViewportIdMap, ViewportIdSet,
area, vec2, EventFilter, Id, IdMap, LayerId, Order, Pos2, Rangef, RawInput, Rect, Style, Theme,
Vec2, ViewportId, ViewportIdMap, ViewportIdSet,
};

// ----------------------------------------------------------------------------
Expand Down Expand Up @@ -166,8 +166,7 @@ impl FocusDirection {
#[cfg_attr(feature = "serde", serde(default))]
pub struct Options {
/// The default style for new [`Ui`](crate::Ui):s.
#[cfg_attr(feature = "serde", serde(skip))]
pub(crate) style: std::sync::Arc<Style>,
pub(crate) style: StyleSet,

/// Global zoom factor of the UI.
///
Expand Down Expand Up @@ -250,6 +249,72 @@ pub struct Options {
pub reduce_texture_memory: bool,
}

#[derive(Clone, Debug, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
#[cfg_attr(feature = "serde", serde(default))]
pub struct StyleSet {
/// The default style for new [`Ui`](crate::Ui):s in dark mode.
#[cfg_attr(feature = "serde", serde(skip))]
pub(crate) dark: std::sync::Arc<Style>,

/// The default style for new [`Ui`](crate::Ui):s in light mode.
#[cfg_attr(feature = "serde", serde(skip))]
pub(crate) light: std::sync::Arc<Style>,

/// Dark or light style? Default is [`Theme::Dark`].
pub theme: Theme,

/// Change [`Self::theme`] based on [`RawInput::system_theme`]?
pub follow_system_theme: bool,
}

impl Default for StyleSet {
fn default() -> Self {
Self {
dark: Default::default(),
light: std::sync::Arc::new(Style::light()),
theme: Default::default(),
follow_system_theme: true,
}
}
}

impl StyleSet {
pub(crate) fn update(&mut self, system_theme: Option<Theme>) {
log::info!(
"updating style set with theme: {system_theme:?}, follow={}",
self.follow_system_theme
);
if self.follow_system_theme {
if let Some(system_theme) = system_theme {
self.theme = system_theme;
}
}
}

pub(crate) fn active(&self) -> &std::sync::Arc<Style> {
match self.theme {
Theme::Dark => &self.dark,
Theme::Light => &self.light,
}
}

pub(crate) fn active_mut(&mut self) -> &mut Style {
use std::sync::Arc;
match self.theme {
Theme::Dark => Arc::make_mut(&mut self.dark),
Theme::Light => Arc::make_mut(&mut self.light),
}
}

pub(crate) fn set_active(&mut self, style: std::sync::Arc<Style>) {
match self.theme {
Theme::Dark => self.dark = style,
Theme::Light => self.light = style,
}
}
}

impl Default for Options {
fn default() -> Self {
// TODO(emilk): figure out why these constants need to be different on web and on native (winit).
Expand Down Expand Up @@ -320,7 +385,7 @@ impl Options {
CollapsingHeader::new("🎑 Style")
.default_open(true)
.show(ui, |ui| {
std::sync::Arc::make_mut(style).ui(ui);
style.active_mut().ui(ui);
});

CollapsingHeader::new("✒ Painting")
Expand Down
10 changes: 9 additions & 1 deletion crates/egui/src/style.rs
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,13 @@ fn style_impl_send_sync() {
}

impl Style {
pub(crate) fn light() -> Self {
Self {
visuals: Visuals::light(),
..Default::default()
}
}

// TODO(emilk): rename style.interact() to maybe… `style.interactive` ?
/// Use this style for interactive things.
/// Note that you must already have a response,
Expand Down Expand Up @@ -930,10 +937,11 @@ impl Visuals {
}

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

/// Light mode: dark text on a light background.
Expand Down

0 comments on commit 61cca8b

Please sign in to comment.