1#[cfg(feature = "default")]
10pub mod themes;
11
12use egui::style::ScrollStyle;
13
14pub trait Aesthetix {
25 fn name(&self) -> &str;
27
28 fn primary_accent_color_visuals(&self) -> egui::Color32;
30
31 fn secondary_accent_color_visuals(&self) -> egui::Color32;
33
34 fn bg_primary_color_visuals(&self) -> egui::Color32;
38
39 fn bg_secondary_color_visuals(&self) -> egui::Color32;
43
44 fn bg_triage_color_visuals(&self) -> egui::Color32;
49
50 fn bg_auxiliary_color_visuals(&self) -> egui::Color32;
55
56 fn bg_contrast_color_visuals(&self) -> egui::Color32;
58
59 fn fg_primary_text_color_visuals(&self) -> Option<egui::Color32>;
64
65 fn fg_success_text_color_visuals(&self) -> egui::Color32;
67
68 fn fg_warn_text_color_visuals(&self) -> egui::Color32;
70
71 fn fg_error_text_color_visuals(&self) -> egui::Color32;
73
74 fn dark_mode_visuals(&self) -> bool;
77
78 fn window_shadow(&self) -> egui::epaint::Shadow {
79 egui::epaint::Shadow {
80 spread: 2.0,
81 blur: 16.0,
82 color: egui::Color32::from_rgba_premultiplied(19, 18, 18, 96),
84 ..Default::default()
85 }
86 }
87
88 fn popup_shadow(&self) -> egui::epaint::Shadow {
89 egui::epaint::Shadow {
90 spread: 2.0,
91 blur: 16.0,
92 color: egui::Color32::from_rgba_premultiplied(19, 18, 18, 96),
93 ..Default::default()
94 }
95 }
96
97 fn text_cursor(&self) -> egui::style::TextCursorStyle {
98 egui::style::TextCursorStyle {
99 stroke: egui::Stroke::new(
100 2.0,
101 self.fg_primary_text_color_visuals().unwrap_or_default(),
102 ),
103 ..Default::default()
104 }
105 }
106
107 fn resize_corner_size(&self) -> f32 {
108 12.0
109 }
110
111 fn margin_style(&self) -> f32 {
117 6.0
118 }
119
120 fn button_padding(&self) -> egui::Vec2 {
125 egui::Vec2 { x: 6.0, y: 4.0 }
126 }
127
128 fn item_spacing_style(&self) -> f32 {
134 4.0
135 }
136
137 fn scroll_bar_width_style(&self) -> f32 {
141 6.0
142 }
143
144 fn rounding_visuals(&self) -> f32 {
148 4.0
149 }
150
151 fn spacing_style(&self) -> egui::style::Spacing {
159 egui::style::Spacing {
160 item_spacing: egui::Vec2 {
161 x: self.item_spacing_style(),
162 y: self.item_spacing_style(),
163 },
164 window_margin: egui::Margin {
165 left: self.margin_style(),
166 right: self.margin_style(),
167 top: self.margin_style(),
168 bottom: self.margin_style(),
169 },
170 button_padding: self.button_padding(),
171 menu_margin: egui::Margin {
172 left: self.margin_style(),
173 right: self.margin_style(),
174 top: self.margin_style(),
175 bottom: self.margin_style(),
176 },
177 indent: 18.0,
178 interact_size: egui::Vec2 { x: 40.0, y: 20.0 },
179 slider_width: 100.0,
180 combo_width: 100.0,
181 text_edit_width: 280.0,
182 icon_width: 14.0,
183 icon_width_inner: 8.0,
184 icon_spacing: 6.0,
185 tooltip_width: 600.0,
186 indent_ends_with_horizontal_line: false,
187 combo_height: 200.0,
188 scroll: ScrollStyle {
189 bar_width: self.scroll_bar_width_style(),
190 handle_min_length: 12.0,
191 bar_inner_margin: 4.0,
192 bar_outer_margin: 0.0,
193 ..Default::default()
194 },
195 ..Default::default()
196 }
197 }
198
199 fn interaction_style(&self) -> egui::style::Interaction {
201 egui::style::Interaction {
202 resize_grab_radius_side: 5.0,
203 resize_grab_radius_corner: 10.0,
204 show_tooltips_only_when_still: true,
205 ..Default::default()
206 }
207 }
208
209 fn custom_noninteractive_widget_visuals(&self) -> egui::style::WidgetVisuals {
215 egui::style::WidgetVisuals {
216 bg_fill: self.bg_auxiliary_color_visuals(),
217 weak_bg_fill: self.bg_auxiliary_color_visuals(),
218 bg_stroke: egui::Stroke {
219 width: 1.0,
220 color: self.bg_auxiliary_color_visuals(),
221 },
222 rounding: egui::Rounding {
223 nw: self.rounding_visuals(),
224 ne: self.rounding_visuals(),
225 sw: self.rounding_visuals(),
226 se: self.rounding_visuals(),
227 },
228 fg_stroke: egui::Stroke {
229 width: 1.0,
230 color: self.fg_primary_text_color_visuals().unwrap_or_default(),
231 },
232 expansion: 0.0,
233 }
234 }
235
236 fn widget_inactive_visual(&self) -> egui::style::WidgetVisuals {
238 egui::style::WidgetVisuals {
239 bg_fill: self.bg_auxiliary_color_visuals(),
240 weak_bg_fill: self.bg_auxiliary_color_visuals(),
241 bg_stroke: egui::Stroke {
242 width: 0.0,
243 color: egui::Color32::from_rgba_premultiplied(0, 0, 0, 0),
244 },
245 rounding: egui::Rounding {
246 nw: self.rounding_visuals(),
247 ne: self.rounding_visuals(),
248 sw: self.rounding_visuals(),
249 se: self.rounding_visuals(),
250 },
251 fg_stroke: egui::Stroke {
252 width: 1.0,
253 color: self.fg_primary_text_color_visuals().unwrap_or_default(),
254 },
255 expansion: 0.0,
256 }
257 }
258
259 fn widget_hovered_visual(&self) -> egui::style::WidgetVisuals {
261 egui::style::WidgetVisuals {
262 bg_fill: self.bg_auxiliary_color_visuals(),
263 weak_bg_fill: self.bg_auxiliary_color_visuals(),
264 bg_stroke: egui::Stroke {
265 width: 1.0,
266 color: self.fg_primary_text_color_visuals().unwrap_or_default(), },
268 rounding: egui::Rounding {
269 nw: self.rounding_visuals(),
270 ne: self.rounding_visuals(),
271 sw: self.rounding_visuals(),
272 se: self.rounding_visuals(),
273 },
274 fg_stroke: egui::Stroke {
275 width: 1.5,
276 color: self.fg_primary_text_color_visuals().unwrap_or_default(),
277 },
278 expansion: 2.0,
279 }
280 }
281
282 fn custom_active_widget_visual(&self) -> egui::style::WidgetVisuals {
284 egui::style::WidgetVisuals {
285 bg_fill: self.bg_primary_color_visuals(),
286 weak_bg_fill: self.primary_accent_color_visuals(),
287 bg_stroke: egui::Stroke {
288 width: 1.0,
289 color: self.bg_primary_color_visuals(),
290 },
291 rounding: egui::Rounding {
292 nw: self.rounding_visuals(),
293 ne: self.rounding_visuals(),
294 sw: self.rounding_visuals(),
295 se: self.rounding_visuals(),
296 },
297 fg_stroke: egui::Stroke {
298 width: 2.0,
299 color: self.fg_primary_text_color_visuals().unwrap_or_default(),
300 },
301 expansion: 1.0,
302 }
303 }
304
305 fn custom_open_widget_visual(&self) -> egui::style::WidgetVisuals {
307 egui::style::WidgetVisuals {
308 bg_fill: self.bg_secondary_color_visuals(),
309 weak_bg_fill: self.bg_secondary_color_visuals(),
310 bg_stroke: egui::Stroke {
311 width: 1.0,
312 color: self.bg_triage_color_visuals(),
313 },
314 rounding: egui::Rounding {
315 nw: self.rounding_visuals(),
316 ne: self.rounding_visuals(),
317 sw: self.rounding_visuals(),
318 se: self.rounding_visuals(),
319 },
320 fg_stroke: egui::Stroke {
321 width: 1.0,
322 color: self.bg_contrast_color_visuals(),
323 },
324 expansion: 0.0,
325 }
326 }
327
328 fn custom_selection_visual(&self) -> egui::style::Selection {
330 egui::style::Selection {
331 bg_fill: self.primary_accent_color_visuals(),
332 stroke: egui::Stroke {
333 width: 1.0,
334 color: self.fg_primary_text_color_visuals().unwrap_or_default(),
335 },
336 }
337 }
338
339 fn custom_text_styles(&self) -> std::collections::BTreeMap<egui::TextStyle, egui::FontId> {
342 use egui::FontFamily::{Monospace, Proportional};
343 [
344 (
345 egui::TextStyle::Small,
346 egui::FontId::new(10.0, Proportional),
347 ),
348 (egui::TextStyle::Body, egui::FontId::new(14.0, Proportional)),
349 (
350 egui::TextStyle::Button,
351 egui::FontId::new(14.00, Proportional),
352 ),
353 (
354 egui::TextStyle::Heading,
355 egui::FontId::new(18.0, Proportional),
356 ),
357 (
358 egui::TextStyle::Monospace,
359 egui::FontId::new(12.0, Monospace),
360 ),
361 ]
362 .into()
363 }
364
365 fn custom_style(&self) -> egui::Style {
370 egui::style::Style {
371 override_text_style: None,
373
374 override_font_id: None,
376
377 text_styles: self.custom_text_styles(),
379
380 spacing: self.spacing_style(),
383 interaction: self.interaction_style(),
384
385 visuals: egui::Visuals {
386 dark_mode: self.dark_mode_visuals(),
387 widgets: egui::style::Widgets {
389 noninteractive: self.custom_noninteractive_widget_visuals(),
390 inactive: self.widget_inactive_visual(),
391 hovered: self.widget_hovered_visual(),
392 active: self.custom_active_widget_visual(),
393 open: self.custom_open_widget_visual(),
394 },
395 selection: self.custom_selection_visual(),
396 hyperlink_color: self.bg_contrast_color_visuals(),
397 panel_fill: self.bg_primary_color_visuals(),
398 faint_bg_color: self.bg_secondary_color_visuals(),
399 extreme_bg_color: self.bg_triage_color_visuals(),
400 code_bg_color: self.bg_auxiliary_color_visuals(),
401 warn_fg_color: self.fg_warn_text_color_visuals(),
402 error_fg_color: self.fg_error_text_color_visuals(),
403 window_rounding: egui::Rounding {
404 nw: self.rounding_visuals(),
405 ne: self.rounding_visuals(),
406 sw: self.rounding_visuals(),
407 se: self.rounding_visuals(),
408 },
409 window_shadow: self.window_shadow(),
410 window_fill: self.bg_primary_color_visuals(),
411 window_stroke: egui::Stroke {
412 width: 1.0,
413 color: self.bg_contrast_color_visuals(),
414 },
415 menu_rounding: egui::Rounding {
416 nw: self.rounding_visuals(),
417 ne: self.rounding_visuals(),
418 sw: self.rounding_visuals(),
419 se: self.rounding_visuals(),
420 },
421 popup_shadow: self.popup_shadow(),
422 resize_corner_size: self.resize_corner_size(),
423 text_cursor: self.text_cursor(),
424 clip_rect_margin: 3.0,
425 button_frame: true,
426 collapsing_header_frame: true,
427 indent_has_left_vline: true,
428 striped: true,
429 slider_trailing_fill: true,
430 ..Default::default()
431 },
432 animation_time: 0.083_333_336,
433 explanation_tooltips: true,
434 ..Default::default()
435 }
436 }
437}
438
439impl std::fmt::Debug for dyn Aesthetix {
440 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
441 write!(f, "{}", self.name())
442 }
443}
444
445impl PartialEq for dyn Aesthetix {
446 fn eq(&self, other: &Self) -> bool {
447 self.name() == other.name()
448 }
449}