diff --git a/crates/egui/src/context.rs b/crates/egui/src/context.rs index cbd0381de..77ee51a87 100644 --- a/crates/egui/src/context.rs +++ b/crates/egui/src/context.rs @@ -2061,9 +2061,8 @@ impl Context { &self, classes: &Classes, state: WidgetState, - base: &Style, ) -> Option { - self.write(move |ctx| ctx.themes.get::(classes, state, base)) + self.write(move |ctx| ctx.themes.get::(classes, state)) } } diff --git a/crates/egui/src/theme_plugin.rs b/crates/egui/src/theme_plugin.rs index 7d56ed63b..672dbf401 100644 --- a/crates/egui/src/theme_plugin.rs +++ b/crates/egui/src/theme_plugin.rs @@ -3,7 +3,7 @@ use std::sync::Arc; use epaint::mutex::Mutex; use crate::{ - Id, Style, Ui, + Id, Ui, util::IdTypeMap, widget_style::{Classes, StyleStruct, WidgetState}, }; @@ -40,7 +40,7 @@ impl ThemeCache { /// A Theme plugin that implement a style computation for a defined `StyleStruct` pub trait ThemeStyle { /// The style according to the classes and state of the widget - fn style(&mut self, classes: &Classes, state: WidgetState, base: &Style) -> S; + fn style(&mut self, classes: &Classes, state: WidgetState) -> S; } impl Ui { @@ -53,9 +53,6 @@ impl Ui { id: crate::Id, classes: &Classes, ) -> S { - // If the requested `StyleStruct` is cached, return it without computing. - // Otherwise proceed to compute the style from the widget information. - // Fetch the current state of the widget let state = self .ctx() @@ -63,10 +60,10 @@ impl Ui { .map(|r| r.widget_state()) .unwrap_or_default(); - if let Some(style) = self.get_style::(classes, state, self.style()) { + if let Some(style) = self.get_style::(classes, state) { style } else { - S::default_style(classes, state, self.style()) + S::default_style(classes, state) } } } @@ -103,11 +100,10 @@ impl Themes { &self, classes: &Classes, state: WidgetState, - base: &Style, ) -> Option { let v = self .themes .get_temp:: + Send + Sync>>>>(Id::NULL); - v.map(|engine| engine.lock().style(classes, state, base)) + v.map(|engine| engine.lock().style(classes, state)) } } diff --git a/crates/egui/src/widget_style.rs b/crates/egui/src/widget_style.rs index 1953034e6..5f8378510 100644 --- a/crates/egui/src/widget_style.rs +++ b/crates/egui/src/widget_style.rs @@ -8,13 +8,14 @@ use epaint::{Color32, FontId, Shadow, Stroke, text::TextWrapMode}; use smallvec::SmallVec; use crate::{ - Frame, Response, Style, TextBuffer as _, TextStyle, + Frame, Response, Spacing, Style, TextBuffer as _, TextStyle, Visuals, style::{WidgetVisuals, Widgets}, }; /// Each dedicated style must implement this trait to be used in the theme plugin system pub trait StyleStruct: Debug + Clone + Send + Sync + std::any::Any + 'static { - fn default_style(classes: &Classes, state: WidgetState, base: &Style) -> Self + /// The default style for this struct based on classes and state of the widget. + fn default_style(classes: &Classes, state: WidgetState) -> Self where Self: Sized; } @@ -44,24 +45,29 @@ pub struct WidgetStyle { } impl StyleStruct for WidgetStyle { - fn default_style(_classes: &Classes, state: WidgetState, base: &Style) -> Self { - let visuals = base.visuals.widgets.state(state); - let font_id = base.override_font_id.clone(); + fn default_style(_classes: &Classes, state: WidgetState) -> Self { + let visuals = Widgets::dark(); + let spacing = Spacing::default(); + + let visuals = match state { + WidgetState::Noninteractive => visuals.noninteractive, + WidgetState::Inactive => visuals.inactive, + WidgetState::Hovered => visuals.hovered, + WidgetState::Active => visuals.active, + }; + Self { frame: Frame { fill: visuals.bg_fill, stroke: visuals.bg_stroke, corner_radius: visuals.corner_radius, - inner_margin: base.spacing.button_padding.into(), + inner_margin: spacing.button_padding.into(), ..Default::default() }, stroke: visuals.fg_stroke, text: TextVisuals { - color: base - .visuals - .override_text_color - .unwrap_or_else(|| visuals.text_color()), - font_id: font_id.unwrap_or_else(|| TextStyle::Body.resolve(base)), + color: visuals.text_color(), + font_id: TextStyle::Button.resolve(&Style::default()), strikethrough: Stroke::NONE, underline: Stroke::NONE, }, @@ -77,25 +83,35 @@ pub struct ButtonStyle { } impl StyleStruct for ButtonStyle { - fn default_style(classes: &Classes, state: WidgetState, base: &Style) -> Self { - let mut visuals = *base.visuals.widgets.state(state); - let mut ws = WidgetStyle::default_style(classes, state, base); + fn default_style(classes: &Classes, state: WidgetState) -> Self { + let widget_visuals = Widgets::dark(); + let spacing = Spacing::default(); + + let mut widget_visuals = match state { + WidgetState::Noninteractive => widget_visuals.noninteractive, + WidgetState::Inactive => widget_visuals.inactive, + WidgetState::Hovered => widget_visuals.hovered, + WidgetState::Active => widget_visuals.active, + }; + + let mut ws = WidgetStyle::default_style(classes, state); if classes.has(SELECTED_CLASS) { - visuals.weak_bg_fill = base.visuals.selection.bg_fill; - visuals.bg_fill = base.visuals.selection.bg_fill; - visuals.fg_stroke = base.visuals.selection.stroke; - ws.text.color = base.visuals.selection.stroke.color; + let visuals = Visuals::default(); + widget_visuals.weak_bg_fill = visuals.selection.bg_fill; + widget_visuals.bg_fill = visuals.selection.bg_fill; + widget_visuals.fg_stroke = visuals.selection.stroke; + ws.text.color = visuals.selection.stroke.color; } Self { frame: Frame { - fill: visuals.weak_bg_fill, - stroke: visuals.bg_stroke, - corner_radius: visuals.corner_radius, - outer_margin: (-Vec2::splat(visuals.expansion)).into(), - inner_margin: (base.spacing.button_padding + Vec2::splat(visuals.expansion) - - Vec2::splat(visuals.bg_stroke.width)) + fill: widget_visuals.weak_bg_fill, + stroke: widget_visuals.bg_stroke, + corner_radius: widget_visuals.corner_radius, + outer_margin: (-Vec2::splat(widget_visuals.expansion)).into(), + inner_margin: (spacing.button_padding + Vec2::splat(widget_visuals.expansion) + - Vec2::splat(widget_visuals.bg_stroke.width)) .into(), ..Default::default() }, @@ -127,17 +143,27 @@ pub struct CheckboxStyle { } impl StyleStruct for CheckboxStyle { - fn default_style(classes: &Classes, state: WidgetState, base: &Style) -> Self { - let visuals = base.visuals.widgets.state(state); - let ws = WidgetStyle::default_style(classes, state, base); + fn default_style(classes: &Classes, state: WidgetState) -> Self { + let widget_visuals = Widgets::dark(); + let spacing = Spacing::default(); + + let widget_visuals = match state { + WidgetState::Noninteractive => widget_visuals.noninteractive, + WidgetState::Inactive => widget_visuals.inactive, + WidgetState::Hovered => widget_visuals.hovered, + WidgetState::Active => widget_visuals.active, + }; + + let ws = WidgetStyle::default_style(classes, state); + Self { frame: Frame::new(), - checkbox_size: base.spacing.icon_width, - check_size: base.spacing.icon_width_inner, + checkbox_size: spacing.icon_width, + check_size: spacing.icon_width_inner, checkbox_frame: Frame { - fill: visuals.bg_fill, - corner_radius: visuals.corner_radius, - stroke: visuals.bg_stroke, + fill: widget_visuals.bg_fill, + corner_radius: widget_visuals.corner_radius, + stroke: widget_visuals.bg_stroke, ..Default::default() }, text_style: ws.text, diff --git a/examples/styling_engine/src/custom_engine.rs b/examples/styling_engine/src/custom_engine.rs index 9f5a7facb..630a620f1 100644 --- a/examples/styling_engine/src/custom_engine.rs +++ b/examples/styling_engine/src/custom_engine.rs @@ -1,7 +1,7 @@ use std::collections::HashMap; use eframe::egui::{ - Color32, Style, + Color32, theme_plugin::{ThemeCache, ThemeStyle}, widget_style::{ ButtonStyle, Classes, HasClasses as _, StyleStruct as _, WidgetState, WidgetStyle, @@ -78,17 +78,19 @@ impl ESSEngine { } } +/// This implementation basically do nothing. This is only the minimum requirement with caching. impl ThemeStyle for ESSEngine { - fn style(&mut self, classes: &Classes, state: WidgetState, base: &Style) -> WidgetStyle { - self.cache - .get(classes, state, || base.widget_style(classes, state)) + fn style(&mut self, classes: &Classes, state: WidgetState) -> WidgetStyle { + self.cache.get(classes, state, || { + WidgetStyle::default_style(classes, state) + }) } } impl ThemeStyle for ESSEngine { - fn style(&mut self, classes: &Classes, state: WidgetState, base: &Style) -> ButtonStyle { + fn style(&mut self, classes: &Classes, state: WidgetState) -> ButtonStyle { self.cache.get(classes, state, || { - let mut default = ButtonStyle::default_style(classes, state, base); + let mut default = ButtonStyle::default_style(classes, state); for classe in classes.list() { if let Some(properties) = self.info.get(&classe.to_string()) { for (property, value) in properties { diff --git a/examples/styling_engine/src/main.rs b/examples/styling_engine/src/main.rs index 322d1af86..7af3b131d 100644 --- a/examples/styling_engine/src/main.rs +++ b/examples/styling_engine/src/main.rs @@ -53,12 +53,10 @@ fn main() -> eframe::Result { if ui.text_edit_multiline(&mut style_code).changed() && let Ok(engine) = ESSEngine::try_parse(&style_code) { + // Overwrite the current theme with the new one.clear ui.replace_theme::(engine.clone()); ui.replace_theme::(engine); } - - // Should find a way to detect if a change is made on a plugin - // Maybe by saving the plugin in the system instead and invalidating the cache when it's pulled as mut ? }); });