1pub mod widgets;
2pub use widgets::button::Button;
3
4use egui::style::{Selection, WidgetVisuals, Widgets};
5use egui::{epaint, Color32, Context, Stroke, Style, Ui, Visuals};
6use material_colors::Argb;
7use std::str::FromStr;
8
9#[derive(Clone, Default, Debug)]
10pub struct MaterialColors {
11 pub dark: bool,
12 pub base_color: String,
13 pub zoom: f32,
14 pub primary: Color32,
15 pub on_primary: Color32,
16 pub primary_container: Color32,
17 pub on_primary_container: Color32,
18 pub inverse_primary: Color32,
19 pub primary_fixed: Color32,
20 pub primary_fixed_dim: Color32,
21 pub on_primary_fixed: Color32,
22 pub on_primary_fixed_variant: Color32,
23 pub secondary: Color32,
24 pub on_secondary: Color32,
25 pub secondary_container: Color32,
26 pub on_secondary_container: Color32,
27 pub secondary_fixed: Color32,
28 pub secondary_fixed_dim: Color32,
29 pub on_secondary_fixed: Color32,
30 pub on_secondary_fixed_variant: Color32,
31 pub tertiary: Color32,
32 pub on_tertiary: Color32,
33 pub tertiary_container: Color32,
34 pub on_tertiary_container: Color32,
35 pub tertiary_fixed: Color32,
36 pub tertiary_fixed_dim: Color32,
37 pub on_tertiary_fixed: Color32,
38 pub on_tertiary_fixed_variant: Color32,
39 pub error: Color32,
40 pub on_error: Color32,
41 pub error_container: Color32,
42 pub on_error_container: Color32,
43 pub surface_dim: Color32,
44 pub surface: Color32,
45 pub surface_bright: Color32,
46 pub surface_container_lowest: Color32,
47 pub surface_container_low: Color32,
48 pub surface_container: Color32,
49 pub surface_container_high: Color32,
50 pub surface_container_highest: Color32,
51 pub on_surface: Color32,
52 pub on_surface_variant: Color32,
53 pub outline: Color32,
54 pub outline_variant: Color32,
55 pub inverse_surface: Color32,
56 pub inverse_on_surface: Color32,
57 pub surface_variant: Color32,
58 pub background: Color32,
59 pub on_background: Color32,
60 pub shadow: Color32,
61 pub scrim: Color32,
62}
63
64fn c(i: Argb) -> Color32 {
65 Color32::from_rgba_premultiplied(i.red, i.green, i.blue, i.alpha)
66}
67
68impl MaterialColors {
69 pub fn rebuild(&mut self) -> Self {
70 *self = Self::new(self.base_color.clone(), self.dark, self.zoom).clone();
71 self.clone()
72 }
73 pub fn new(base_color: String, dark: bool, zoom: f32) -> Self {
74 let data = material_colors::theme_from_source_color(
75 Argb::from_str(&base_color).unwrap(),
76 Default::default(),
77 );
78
79 let scheme = match dark {
80 true => data.schemes.dark,
81 false => data.schemes.light,
82 };
83
84 Self {
85 base_color,
86 dark,
87 zoom,
88
89 primary: c(scheme.primary),
91 on_primary: c(scheme.on_primary),
92 primary_container: c(scheme.primary_container),
93 on_primary_container: c(scheme.on_primary_container),
94 inverse_primary: c(scheme.inverse_primary),
95 primary_fixed: c(scheme.primary_fixed),
96 primary_fixed_dim: c(scheme.primary_fixed_dim),
97 on_primary_fixed: c(scheme.on_primary_fixed),
98 on_primary_fixed_variant: c(scheme.on_primary_fixed_variant),
99 secondary: c(scheme.secondary),
101 on_secondary: c(scheme.on_secondary),
102 secondary_container: c(scheme.secondary_container),
103 on_secondary_container: c(scheme.on_secondary_container),
104 secondary_fixed: c(scheme.secondary_fixed),
105 secondary_fixed_dim: c(scheme.secondary_fixed_dim),
106 on_secondary_fixed: c(scheme.on_secondary_fixed),
107 on_secondary_fixed_variant: c(scheme.on_secondary_fixed_variant),
108 tertiary: c(scheme.tertiary),
110 on_tertiary: c(scheme.on_tertiary),
111 tertiary_container: c(scheme.tertiary_container),
112 on_tertiary_container: c(scheme.on_tertiary_container),
113 tertiary_fixed: c(scheme.tertiary_fixed),
114 tertiary_fixed_dim: c(scheme.tertiary_fixed_dim),
115 on_tertiary_fixed: c(scheme.on_tertiary_fixed),
116 on_tertiary_fixed_variant: c(scheme.on_tertiary_fixed_variant),
117 error: c(scheme.error),
119 on_error: c(scheme.on_error),
120 error_container: c(scheme.error_container),
121 on_error_container: c(scheme.on_error_container),
122 surface_dim: c(scheme.surface_dim),
124 surface: c(scheme.surface),
125 surface_bright: c(scheme.surface_bright),
126 surface_container_lowest: c(scheme.surface_container_lowest),
127 surface_container_low: c(scheme.surface_container_low),
128 surface_container: c(scheme.surface_container),
129 surface_container_high: c(scheme.surface_container_high),
130 surface_container_highest: c(scheme.surface_container_highest),
131 on_surface: c(scheme.on_surface),
132 on_surface_variant: c(scheme.on_surface_variant),
133 outline: c(scheme.outline),
135 outline_variant: c(scheme.outline_variant),
136 inverse_surface: c(scheme.inverse_surface),
138 inverse_on_surface: c(scheme.inverse_on_surface),
139 surface_variant: c(scheme.surface_variant),
140 background: c(scheme.background),
141 on_background: c(scheme.on_background),
142 shadow: c(scheme.shadow),
143 scrim: c(scheme.scrim),
144 }
145 }
146 pub fn export(&self) -> Style {
150 let p = self;
151
152 let visuals = Visuals {
153 collapsing_header_frame: true,
155 override_text_color: None,
156 hyperlink_color: p.on_primary,
157 faint_bg_color: p.surface_container,
159 extreme_bg_color: p.surface_variant,
160 code_bg_color: p.surface_dim,
161
162 window_fill: p.surface_container_highest,
163 panel_fill: p.surface,
164
165 warn_fg_color: p.error_container,
166 error_fg_color: p.error,
167
168 window_highlight_topmost: false,
174 widgets: widgets(p.clone()),
176 window_shadow: epaint::Shadow {
177 color: p.shadow,
178 ..Default::default()
179 },
180
181 popup_shadow: epaint::Shadow {
182 color: p.shadow,
183 ..Default::default()
184 },
185
186 selection: Selection {
189 bg_fill: p.secondary,
190 stroke: Stroke {
191 width: 1.5,
192 color: p.on_secondary,
193 },
194 },
195
196 ..Default::default()
197 };
198
199 Style {
200 visuals,
201
202 ..Default::default()
203 }
204 }
205 pub fn apply_zoom(&mut self, ctx: &Context, first_run: &mut bool) {
208 if *first_run {
209 ctx.set_zoom_factor(self.zoom);
210 *first_run = false;
211 }
212 ctx.set_style(self.export());
213 }
214
215 pub fn apply(&mut self, ctx: &Context) {
217 ctx.set_style(self.export());
218 }
219 pub fn apply_ui(&self, ui: &mut Ui) {
222 ui.set_style(self.export())
223 }
224
225 pub fn error_apply(&self, ui: &mut Ui) {
226 let widgets = &mut ui.style_mut().visuals.widgets;
227 let active = (self.error, self.on_error);
229 let rest = (self.error_container, self.on_error_container);
230 widget_maker_mut(&mut widgets.hovered, rest.0, rest.1);
232 widget_maker_mut(&mut widgets.inactive, rest.0, rest.1);
233 widget_maker_mut(&mut widgets.open, active.0, active.1);
234 widget_maker_mut(&mut widgets.active, active.0, active.1);
235 }
236}
237fn widgets(p: MaterialColors) -> Widgets {
238 let mut old = match p.dark {
239 true => Visuals::dark(),
240 false => Visuals::light(),
241 }
242 .widgets;
243
244 widget_maker_mut(&mut old.noninteractive, p.surface, p.on_surface);
246
247 old.noninteractive.bg_stroke.color = p.surface_variant;
248 old.noninteractive.bg_stroke.width = 4.;
249
250 widget_maker_mut(
251 &mut old.inactive,
252 p.primary_container,
253 p.on_primary_container,
254 );
255 widget_maker_mut(
256 &mut old.hovered,
257 p.tertiary_container,
258 p.on_tertiary_container,
259 );
260 widget_maker_mut(&mut old.active, p.tertiary, p.on_tertiary);
261 widget_maker_mut(&mut old.open, p.primary_container, p.on_primary_container);
262 old
263}
264fn widget_maker_mut(old: &mut WidgetVisuals, fill: Color32, text: Color32) {
265 old.bg_fill = fill;
266 old.weak_bg_fill = fill;
267 old.fg_stroke.color = text;
268 old.bg_stroke.color = fill;
269 old.expansion = 0.;
270}