1pub mod elements;
2pub mod presets;
3
4pub use elements::{ElementLine, ElementRect, ElementText};
5
6#[derive(Clone, Debug)]
8pub enum LegendPosition {
9 Right,
10 Left,
11 Top,
12 Bottom,
13 None,
14 Inside(f64, f64),
17}
18
19#[derive(Clone, Copy, Debug, Default, PartialEq)]
22pub enum TitlePosition {
23 #[default]
24 Panel,
25 Plot,
26}
27
28#[derive(Clone, Copy, Debug, Default, PartialEq)]
30pub enum TagPosition {
31 #[default]
32 TopLeft,
33 TopRight,
34 BottomLeft,
35 BottomRight,
36}
37
38#[derive(Clone, Copy, Debug, PartialEq)]
40pub enum LegendDirection {
41 Vertical,
42 Horizontal,
43}
44
45#[derive(Clone, Debug)]
47pub struct Margin {
48 pub top: f64,
49 pub right: f64,
50 pub bottom: f64,
51 pub left: f64,
52}
53
54impl Default for Margin {
55 fn default() -> Self {
56 Margin {
57 top: 10.0,
58 right: 10.0,
59 bottom: 10.0,
60 left: 10.0,
61 }
62 }
63}
64
65#[derive(Clone, Debug)]
67pub struct Theme {
68 pub text: ElementText,
70 pub title: ElementText,
71 pub axis_text_x: ElementText,
72 pub axis_text_y: ElementText,
73 pub axis_title_x: ElementText,
74 pub axis_title_y: ElementText,
75 pub axis_line: ElementLine,
76 pub axis_ticks: ElementLine,
77 pub panel_background: ElementRect,
78 pub panel_grid_major: ElementLine,
79 pub panel_grid_minor: ElementLine,
80 pub plot_background: ElementRect,
81 pub legend_position: LegendPosition,
82 pub plot_margin: Margin,
83
84 pub subtitle: ElementText,
86 pub caption: ElementText,
87 pub legend_title: ElementText,
88 pub legend_text: ElementText,
89 pub strip_text: ElementText,
90
91 pub axis_line_x: Option<ElementLine>,
93 pub axis_line_y: Option<ElementLine>,
94 pub axis_ticks_x: Option<ElementLine>,
95 pub axis_ticks_y: Option<ElementLine>,
96 pub panel_grid_major_x: Option<ElementLine>,
97 pub panel_grid_major_y: Option<ElementLine>,
98 pub panel_grid_minor_x: Option<ElementLine>,
99 pub panel_grid_minor_y: Option<ElementLine>,
100
101 pub panel_border: ElementLine,
103 pub legend_background: ElementRect,
104 pub legend_key: ElementRect,
105 pub strip_background: ElementRect,
106
107 pub axis_ticks_length: f64,
109 pub axis_text_x_dodge: usize,
112 pub legend_key_width: f64,
113 pub legend_key_height: f64,
114 pub legend_spacing: f64,
115 pub legend_margin: Margin,
116 pub panel_spacing: f64,
117 pub panel_spacing_x: Option<f64>,
118 pub panel_spacing_y: Option<f64>,
119
120 pub primary: Option<(u8, u8, u8)>,
125
126 pub aspect_ratio: Option<f64>,
129 pub panel_ontop: bool,
131 pub axis_minor_ticks: bool,
133 pub title_position: TitlePosition,
136 pub tag_position: TagPosition,
138 pub legend_direction: Option<LegendDirection>,
140}
141
142impl Theme {
143 pub fn primary_or(&self, fallback: (u8, u8, u8)) -> (u8, u8, u8) {
146 self.primary.unwrap_or(fallback)
147 }
148
149 pub fn with_primary(mut self, color: (u8, u8, u8)) -> Self {
151 self.primary = Some(color);
152 self
153 }
154
155 pub fn resolve_inheritance(&mut self) {
161 let root = self.text.clone();
162 let def = ElementText::default();
163 let children: [&mut ElementText; 10] = [
164 &mut self.title,
165 &mut self.subtitle,
166 &mut self.caption,
167 &mut self.axis_text_x,
168 &mut self.axis_text_y,
169 &mut self.axis_title_x,
170 &mut self.axis_title_y,
171 &mut self.legend_title,
172 &mut self.legend_text,
173 &mut self.strip_text,
174 ];
175 for el in children {
176 if el.family == def.family {
177 el.family = root.family.clone();
178 }
179 if el.color == def.color {
180 el.color = root.color;
181 }
182 }
183 }
184
185 pub fn get_axis_line_x(&self) -> &ElementLine {
188 self.axis_line_x.as_ref().unwrap_or(&self.axis_line)
189 }
190
191 pub fn get_axis_line_y(&self) -> &ElementLine {
192 self.axis_line_y.as_ref().unwrap_or(&self.axis_line)
193 }
194
195 pub fn get_axis_ticks_x(&self) -> &ElementLine {
196 self.axis_ticks_x.as_ref().unwrap_or(&self.axis_ticks)
197 }
198
199 pub fn get_axis_ticks_y(&self) -> &ElementLine {
200 self.axis_ticks_y.as_ref().unwrap_or(&self.axis_ticks)
201 }
202
203 pub fn get_panel_grid_major_x(&self) -> &ElementLine {
204 self.panel_grid_major_x
205 .as_ref()
206 .unwrap_or(&self.panel_grid_major)
207 }
208
209 pub fn get_panel_grid_major_y(&self) -> &ElementLine {
210 self.panel_grid_major_y
211 .as_ref()
212 .unwrap_or(&self.panel_grid_major)
213 }
214
215 pub fn get_panel_grid_minor_x(&self) -> &ElementLine {
216 self.panel_grid_minor_x
217 .as_ref()
218 .unwrap_or(&self.panel_grid_minor)
219 }
220
221 pub fn get_panel_grid_minor_y(&self) -> &ElementLine {
222 self.panel_grid_minor_y
223 .as_ref()
224 .unwrap_or(&self.panel_grid_minor)
225 }
226
227 pub fn get_panel_spacing_x(&self) -> f64 {
228 self.panel_spacing_x.unwrap_or(self.panel_spacing)
229 }
230
231 pub fn get_panel_spacing_y(&self) -> f64 {
232 self.panel_spacing_y.unwrap_or(self.panel_spacing)
233 }
234
235 pub fn set_axis_text_x(mut self, el: ElementText) -> Self {
238 self.axis_text_x = el;
239 self
240 }
241
242 pub fn set_axis_text_y(mut self, el: ElementText) -> Self {
243 self.axis_text_y = el;
244 self
245 }
246
247 pub fn set_axis_title_x(mut self, el: ElementText) -> Self {
248 self.axis_title_x = el;
249 self
250 }
251
252 pub fn set_axis_title_y(mut self, el: ElementText) -> Self {
253 self.axis_title_y = el;
254 self
255 }
256
257 pub fn set_axis_line(mut self, el: ElementLine) -> Self {
258 self.axis_line = el;
259 self
260 }
261
262 pub fn set_axis_ticks(mut self, el: ElementLine) -> Self {
263 self.axis_ticks = el;
264 self
265 }
266
267 pub fn set_panel_background(mut self, el: ElementRect) -> Self {
268 self.panel_background = el;
269 self
270 }
271
272 pub fn set_panel_grid_major(mut self, el: ElementLine) -> Self {
273 self.panel_grid_major = el;
274 self
275 }
276
277 pub fn set_panel_grid_minor(mut self, el: ElementLine) -> Self {
278 self.panel_grid_minor = el;
279 self
280 }
281
282 pub fn set_plot_background(mut self, el: ElementRect) -> Self {
283 self.plot_background = el;
284 self
285 }
286
287 pub fn set_legend_position(mut self, pos: LegendPosition) -> Self {
288 self.legend_position = pos;
289 self
290 }
291
292 pub fn set_plot_margin(mut self, margin: Margin) -> Self {
293 self.plot_margin = margin;
294 self
295 }
296
297 pub fn set_title(mut self, el: ElementText) -> Self {
298 self.title = el;
299 self
300 }
301
302 pub fn set_text(mut self, el: ElementText) -> Self {
303 self.text = el;
304 self
305 }
306
307 pub fn set_subtitle(mut self, el: ElementText) -> Self {
310 self.subtitle = el;
311 self
312 }
313
314 pub fn set_caption(mut self, el: ElementText) -> Self {
315 self.caption = el;
316 self
317 }
318
319 pub fn set_legend_title(mut self, el: ElementText) -> Self {
320 self.legend_title = el;
321 self
322 }
323
324 pub fn set_legend_text(mut self, el: ElementText) -> Self {
325 self.legend_text = el;
326 self
327 }
328
329 pub fn set_strip_text(mut self, el: ElementText) -> Self {
330 self.strip_text = el;
331 self
332 }
333
334 pub fn set_axis_line_x(mut self, el: Option<ElementLine>) -> Self {
335 self.axis_line_x = el;
336 self
337 }
338
339 pub fn set_axis_line_y(mut self, el: Option<ElementLine>) -> Self {
340 self.axis_line_y = el;
341 self
342 }
343
344 pub fn set_axis_ticks_x(mut self, el: Option<ElementLine>) -> Self {
345 self.axis_ticks_x = el;
346 self
347 }
348
349 pub fn set_axis_ticks_y(mut self, el: Option<ElementLine>) -> Self {
350 self.axis_ticks_y = el;
351 self
352 }
353
354 pub fn set_panel_grid_major_x(mut self, el: Option<ElementLine>) -> Self {
355 self.panel_grid_major_x = el;
356 self
357 }
358
359 pub fn set_panel_grid_major_y(mut self, el: Option<ElementLine>) -> Self {
360 self.panel_grid_major_y = el;
361 self
362 }
363
364 pub fn set_panel_grid_minor_x(mut self, el: Option<ElementLine>) -> Self {
365 self.panel_grid_minor_x = el;
366 self
367 }
368
369 pub fn set_panel_grid_minor_y(mut self, el: Option<ElementLine>) -> Self {
370 self.panel_grid_minor_y = el;
371 self
372 }
373
374 pub fn set_panel_border(mut self, el: ElementLine) -> Self {
375 self.panel_border = el;
376 self
377 }
378
379 pub fn set_legend_background(mut self, el: ElementRect) -> Self {
380 self.legend_background = el;
381 self
382 }
383
384 pub fn set_legend_key(mut self, el: ElementRect) -> Self {
385 self.legend_key = el;
386 self
387 }
388
389 pub fn set_strip_background(mut self, el: ElementRect) -> Self {
390 self.strip_background = el;
391 self
392 }
393
394 pub fn set_axis_ticks_length(mut self, val: f64) -> Self {
395 self.axis_ticks_length = val;
396 self
397 }
398
399 pub fn set_legend_key_width(mut self, val: f64) -> Self {
400 self.legend_key_width = val;
401 self
402 }
403
404 pub fn set_legend_key_height(mut self, val: f64) -> Self {
405 self.legend_key_height = val;
406 self
407 }
408
409 pub fn set_legend_spacing(mut self, val: f64) -> Self {
410 self.legend_spacing = val;
411 self
412 }
413
414 pub fn set_legend_margin(mut self, margin: Margin) -> Self {
415 self.legend_margin = margin;
416 self
417 }
418
419 pub fn set_panel_spacing(mut self, val: f64) -> Self {
420 self.panel_spacing = val;
421 self
422 }
423
424 pub fn set_panel_spacing_x(mut self, val: Option<f64>) -> Self {
425 self.panel_spacing_x = val;
426 self
427 }
428
429 pub fn set_panel_spacing_y(mut self, val: Option<f64>) -> Self {
430 self.panel_spacing_y = val;
431 self
432 }
433
434 pub fn update(mut self, upd: ThemeUpdate) -> Self {
437 if let Some(v) = upd.text {
438 self.text = v;
439 }
440 if let Some(v) = upd.title {
441 self.title = v;
442 }
443 if let Some(v) = upd.subtitle {
444 self.subtitle = v;
445 }
446 if let Some(v) = upd.caption {
447 self.caption = v;
448 }
449 if let Some(v) = upd.axis_text_x {
450 self.axis_text_x = v;
451 }
452 if let Some(v) = upd.axis_text_y {
453 self.axis_text_y = v;
454 }
455 if let Some(v) = upd.axis_title_x {
456 self.axis_title_x = v;
457 }
458 if let Some(v) = upd.axis_title_y {
459 self.axis_title_y = v;
460 }
461 if let Some(v) = upd.axis_line {
462 self.axis_line = v;
463 }
464 if let Some(v) = upd.axis_ticks {
465 self.axis_ticks = v;
466 }
467 if let Some(v) = upd.panel_background {
468 self.panel_background = v;
469 }
470 if let Some(v) = upd.panel_grid_major {
471 self.panel_grid_major = v;
472 }
473 if let Some(v) = upd.panel_grid_minor {
474 self.panel_grid_minor = v;
475 }
476 if let Some(v) = upd.panel_border {
477 self.panel_border = v;
478 }
479 if let Some(v) = upd.plot_background {
480 self.plot_background = v;
481 }
482 if let Some(v) = upd.legend_position {
483 self.legend_position = v;
484 }
485 if let Some(v) = upd.legend_title {
486 self.legend_title = v;
487 }
488 if let Some(v) = upd.legend_text {
489 self.legend_text = v;
490 }
491 if let Some(v) = upd.legend_background {
492 self.legend_background = v;
493 }
494 if let Some(v) = upd.strip_text {
495 self.strip_text = v;
496 }
497 if let Some(v) = upd.strip_background {
498 self.strip_background = v;
499 }
500 if let Some(v) = upd.plot_margin {
501 self.plot_margin = v;
502 }
503 self
504 }
505}
506
507#[derive(Clone, Debug, Default)]
510pub struct ThemeUpdate {
511 pub text: Option<ElementText>,
512 pub title: Option<ElementText>,
513 pub subtitle: Option<ElementText>,
514 pub caption: Option<ElementText>,
515 pub axis_text_x: Option<ElementText>,
516 pub axis_text_y: Option<ElementText>,
517 pub axis_title_x: Option<ElementText>,
518 pub axis_title_y: Option<ElementText>,
519 pub axis_line: Option<ElementLine>,
520 pub axis_ticks: Option<ElementLine>,
521 pub panel_background: Option<ElementRect>,
522 pub panel_grid_major: Option<ElementLine>,
523 pub panel_grid_minor: Option<ElementLine>,
524 pub panel_border: Option<ElementLine>,
525 pub plot_background: Option<ElementRect>,
526 pub legend_position: Option<LegendPosition>,
527 pub legend_title: Option<ElementText>,
528 pub legend_text: Option<ElementText>,
529 pub legend_background: Option<ElementRect>,
530 pub strip_text: Option<ElementText>,
531 pub strip_background: Option<ElementRect>,
532 pub plot_margin: Option<Margin>,
533}
534
535impl Default for Theme {
536 fn default() -> Self {
537 presets::theme_gray()
538 }
539}