1#[cfg(feature = "default")]
10pub mod themes;
11
12pub trait Aesthetix {
23 fn name(&self) -> &str;
25
26 fn primary_accent_color_visuals(&self) -> egui::Color32;
28
29 fn secondary_accent_color_visuals(&self) -> egui::Color32;
31
32 fn bg_primary_color_visuals(&self) -> egui::Color32;
36
37 fn bg_secondary_color_visuals(&self) -> egui::Color32;
41
42 fn bg_triage_color_visuals(&self) -> egui::Color32;
47
48 fn bg_auxiliary_color_visuals(&self) -> egui::Color32;
53
54 fn bg_contrast_color_visuals(&self) -> egui::Color32;
56
57 fn fg_primary_text_color_visuals(&self) -> Option<egui::Color32>;
62
63 fn fg_success_text_color_visuals(&self) -> egui::Color32;
65
66 fn fg_warn_text_color_visuals(&self) -> egui::Color32;
68
69 fn fg_error_text_color_visuals(&self) -> egui::Color32;
71
72 fn dark_mode_visuals(&self) -> bool;
75
76 fn margin_style(&self) -> f32;
82
83 fn button_padding(&self) -> egui::Vec2;
87
88 fn item_spacing_style(&self) -> f32;
94
95 fn scroll_bar_width_style(&self) -> f32;
99
100 fn rounding_visuals(&self) -> f32;
104
105 fn spacing_style(&self) -> egui::style::Spacing {
113 egui::style::Spacing {
114 item_spacing: egui::Vec2 {
115 x: self.item_spacing_style(),
116 y: self.item_spacing_style(),
117 },
118 window_margin: egui::Margin {
119 left: self.margin_style(),
120 right: self.margin_style(),
121 top: self.margin_style(),
122 bottom: self.margin_style(),
123 },
124 button_padding: self.button_padding(),
125 menu_margin: egui::Margin {
126 left: self.margin_style(),
127 right: self.margin_style(),
128 top: self.margin_style(),
129 bottom: self.margin_style(),
130 },
131 indent: 18.0,
132 interact_size: egui::Vec2 { x: 40.0, y: 20.0 },
133 slider_width: 100.0,
134 combo_width: 100.0,
135 text_edit_width: 280.0,
136 icon_width: 14.0,
137 icon_width_inner: 8.0,
138 icon_spacing: 6.0,
139 tooltip_width: 600.0,
140 indent_ends_with_horizontal_line: false,
141 combo_height: 200.0,
142 scroll: egui::style::ScrollStyle {
143 bar_width: self.scroll_bar_width_style(),
144 handle_min_length: 12.0,
145 bar_inner_margin: 4.0,
146 bar_outer_margin: 0.0,
147 ..Default::default()
148 },
149 ..Default::default()
150 }
151 }
152
153 fn interaction_style(&self) -> egui::style::Interaction {
155 egui::style::Interaction {
156 resize_grab_radius_side: 5.0,
157 resize_grab_radius_corner: 10.0,
158 show_tooltips_only_when_still: true,
159 ..Default::default()
160 }
161 }
162
163 fn custom_noninteractive_widget_visuals(&self) -> egui::style::WidgetVisuals {
169 egui::style::WidgetVisuals {
170 bg_fill: self.bg_auxiliary_color_visuals(),
171 weak_bg_fill: self.bg_auxiliary_color_visuals(),
172 bg_stroke: egui::Stroke {
173 width: 1.0,
174 color: self.bg_auxiliary_color_visuals(),
175 },
176 rounding: egui::Rounding {
177 nw: self.rounding_visuals(),
178 ne: self.rounding_visuals(),
179 sw: self.rounding_visuals(),
180 se: self.rounding_visuals(),
181 },
182 fg_stroke: egui::Stroke {
183 width: 1.0,
184 color: self.fg_primary_text_color_visuals().unwrap_or_default(),
185 },
186 expansion: 0.0,
187 }
188 }
189
190 fn widget_inactive_visual(&self) -> egui::style::WidgetVisuals {
192 egui::style::WidgetVisuals {
193 bg_fill: self.bg_auxiliary_color_visuals(),
194 weak_bg_fill: self.bg_auxiliary_color_visuals(),
195 bg_stroke: egui::Stroke {
196 width: 0.0,
197 color: egui::Color32::from_rgba_premultiplied(0, 0, 0, 0),
198 },
199 rounding: egui::Rounding {
200 nw: self.rounding_visuals(),
201 ne: self.rounding_visuals(),
202 sw: self.rounding_visuals(),
203 se: self.rounding_visuals(),
204 },
205 fg_stroke: egui::Stroke {
206 width: 1.0,
207 color: self.fg_primary_text_color_visuals().unwrap_or_default(),
208 },
209 expansion: 0.0,
210 }
211 }
212
213 fn widget_hovered_visual(&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_triage_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.5,
230 color: self.fg_primary_text_color_visuals().unwrap_or_default(),
231 },
232 expansion: 2.0,
233 }
234 }
235
236 fn custom_active_widget_visual(&self) -> egui::style::WidgetVisuals {
238 egui::style::WidgetVisuals {
239 bg_fill: self.bg_primary_color_visuals(),
240 weak_bg_fill: self.primary_accent_color_visuals(),
241 bg_stroke: egui::Stroke {
242 width: 1.0,
243 color: self.bg_primary_color_visuals(),
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: 2.0,
253 color: self.fg_primary_text_color_visuals().unwrap_or_default(),
254 },
255 expansion: 1.0,
256 }
257 }
258
259 fn custom_open_widget_visual(&self) -> egui::style::WidgetVisuals {
261 egui::style::WidgetVisuals {
262 bg_fill: self.bg_secondary_color_visuals(),
263 weak_bg_fill: self.bg_secondary_color_visuals(),
264 bg_stroke: egui::Stroke {
265 width: 1.0,
266 color: self.bg_triage_color_visuals(),
267 },
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.0,
276 color: self.bg_contrast_color_visuals(),
277 },
278 expansion: 0.0,
279 }
280 }
281
282 fn custom_selection_visual(&self) -> egui::style::Selection {
284 egui::style::Selection {
285 bg_fill: self.primary_accent_color_visuals(),
286 stroke: egui::Stroke {
287 width: 1.0,
288 color: self.bg_primary_color_visuals(),
289 },
290 }
291 }
292
293 fn custom_text_styles(&self) -> std::collections::BTreeMap<egui::TextStyle, egui::FontId> {
296 use egui::FontFamily::{Monospace, Proportional};
297 [
298 (
299 egui::TextStyle::Small,
300 egui::FontId::new(10.0, Proportional),
301 ),
302 (egui::TextStyle::Body, egui::FontId::new(14.0, Proportional)),
303 (
304 egui::TextStyle::Button,
305 egui::FontId::new(14.00, Proportional),
306 ),
307 (
308 egui::TextStyle::Heading,
309 egui::FontId::new(18.0, Proportional),
310 ),
311 (
312 egui::TextStyle::Monospace,
313 egui::FontId::new(12.0, Monospace),
314 ),
315 ]
316 .into()
317 }
318
319 fn custom_style(&self) -> egui::Style {
324 egui::style::Style {
325 override_text_style: None,
327
328 override_font_id: None,
330
331 text_styles: self.custom_text_styles(),
333
334 spacing: self.spacing_style(),
336 interaction: self.interaction_style(),
337
338 visuals: egui::Visuals {
339 dark_mode: self.dark_mode_visuals(),
340 override_text_color: self.fg_primary_text_color_visuals(),
341 widgets: egui::style::Widgets {
342 noninteractive: self.custom_noninteractive_widget_visuals(),
343 inactive: self.widget_inactive_visual(),
344 hovered: self.widget_hovered_visual(),
345 active: self.custom_active_widget_visual(),
346 open: self.custom_open_widget_visual(),
347 },
348 selection: self.custom_selection_visual(),
349 hyperlink_color: self.bg_contrast_color_visuals(),
350 panel_fill: self.bg_primary_color_visuals(),
351 faint_bg_color: self.bg_secondary_color_visuals(),
352 extreme_bg_color: self.bg_triage_color_visuals(),
353 code_bg_color: self.bg_auxiliary_color_visuals(),
354 warn_fg_color: self.fg_warn_text_color_visuals(),
355 error_fg_color: self.fg_error_text_color_visuals(),
356 window_rounding: egui::Rounding {
357 nw: self.rounding_visuals(),
358 ne: self.rounding_visuals(),
359 sw: self.rounding_visuals(),
360 se: self.rounding_visuals(),
361 },
362 window_shadow: egui::epaint::Shadow {
363 spread: 32.0,
364 color: egui::Color32::from_rgba_premultiplied(0, 0, 0, 96),
365 ..Default::default()
366 },
367 window_fill: self.bg_primary_color_visuals(),
368 window_stroke: egui::Stroke {
369 width: 1.0,
370 color: self.bg_contrast_color_visuals(),
371 },
372 menu_rounding: egui::Rounding {
373 nw: self.rounding_visuals(),
374 ne: self.rounding_visuals(),
375 sw: self.rounding_visuals(),
376 se: self.rounding_visuals(),
377 },
378 popup_shadow: egui::epaint::Shadow {
379 spread: 16.0,
380 color: egui::Color32::from_rgba_premultiplied(19, 18, 18, 96),
381 ..Default::default()
382 },
383 resize_corner_size: 12.0,
384 clip_rect_margin: 3.0,
385 button_frame: true,
386 collapsing_header_frame: true,
387 indent_has_left_vline: true,
388 striped: true,
389 slider_trailing_fill: true,
390 ..Default::default()
391 },
392 animation_time: 0.083_333_336,
393 explanation_tooltips: true,
394 ..Default::default()
395 }
396 }
397}
398
399impl std::fmt::Debug for dyn Aesthetix {
400 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
401 write!(f, "{}", self.name())
402 }
403}
404
405impl PartialEq for dyn Aesthetix {
406 fn eq(&self, other: &Self) -> bool {
407 self.name() == other.name()
408 }
409}