From cbb531ec06baed49d0b4c901fa15a687a7f49440 Mon Sep 17 00:00:00 2001 From: adrien <221212@umons.ac.be> Date: Fri, 2 Jan 2026 20:31:35 +0100 Subject: [PATCH] modifiers and classes --- crates/egui/src/widget_style.rs | 116 +++++++++++++++++++++++++++++++- 1 file changed, 115 insertions(+), 1 deletion(-) diff --git a/crates/egui/src/widget_style.rs b/crates/egui/src/widget_style.rs index 424eea460..793b43ed6 100644 --- a/crates/egui/src/widget_style.rs +++ b/crates/egui/src/widget_style.rs @@ -2,7 +2,7 @@ use emath::Vec2; use epaint::{Color32, FontId, Shadow, Stroke, text::TextWrapMode}; use crate::{ - Frame, Response, Style, TextStyle, + Frame, Id, Response, Style, TextStyle, Theme, Ui, style::{WidgetVisuals, Widgets}, }; @@ -199,3 +199,117 @@ impl Style { } } } + +#[derive(PartialEq, Eq, Clone)] +pub enum StyleModifier { + /// Widget type should be a modifier or a separate information ? + /// Could have the trait [`HasClasses`] force to implement a method "name" + /// or "`widget_type`" + Button, + Label, + Separator, + Checkbox, + /// Classes and Id are string + Class(String), + Id(String), + /// Theme can be useful + Theme(Theme), +} + +/// Text modifiers affect only the text of the widgets +pub enum TextModifier { + Header, + Small, + Weak, + Strong, + Code, +} + +impl From<&str> for StyleModifier { + fn from(class: &str) -> Self { + match class { + "dark" => Self::Theme(Theme::Dark), + "light" => Self::Theme(Theme::Light), + "button" => Self::Button, + "label" => Self::Label, + "separator" => Self::Separator, + "checkbox" => Self::Checkbox, + // Maybe add a prefix for class and ID ? + _ => Self::Class(class.to_owned()), + } + } +} + +pub(crate) const CLASSES_SMALL_VEC_SIZE: usize = 5; + +/// Small vec for performance +#[derive(Default)] +pub struct Modifiers { + pub modifiers: Vec, + text: Option, + parent: Option, +} + +impl Modifiers { + pub fn with_classes(mut self, classes: &[StyleModifier]) -> Self { + // debug_assert!( + // classes.len() <= CLASSES_SMALL_VEC_SIZE - self.modifiers.len(), + // "Too many modifiers !" + // ); + self.modifiers.append(&mut classes.to_vec()); + self + } + + pub fn with_class(mut self, class: impl Into) -> Self { + self.modifiers.push(class.into()); + self + } + + pub fn with_parent(mut self, parent: &Ui) -> Self { + self.parent = Some(parent.id()); + self + } + + /// Add a class to the list + pub fn add_if(&mut self, class: impl Into, condition: bool) { + if condition { + self.modifiers.push(class.into()); + } + } + /// Add a class to the list and return the list, for method chaining + pub fn with_if(mut self, class: impl Into, condition: bool) -> Self { + self.add_if(class.into(), condition); + self + } + pub fn has(&self, class: impl Into) -> bool { + self.modifiers.contains(&class.into()) + } +} + +/// Any widgets supporting classes must implement this trait +pub trait HasModifier { + fn classes(&self) -> &Modifiers; + + fn classes_mut(&mut self) -> &mut Modifiers; + + fn add_class(&mut self, class: impl Into) -> &Self { + self.classes_mut().add_if(class.into(), true); + self + } + + fn with_class(mut self, class: impl Into) -> Self + where + Self: Sized, + { + self.classes_mut().add_if(class.into(), true); + self + } + + fn with_class_if(mut self, class: impl Into, condition: bool) -> Self + where + Self: Sized, + { + self.classes_mut().add_if(class.into(), condition); + self + } +}