1#[cfg(feature = "serde")]
2pub mod config;
3pub mod elements;
4pub mod presets;
5
6pub use elements::{ElementGeom, ElementLine, ElementRect, ElementText};
7
8#[derive(Clone, Debug)]
10pub enum LegendPosition {
11 Right,
12 Left,
13 Top,
14 Bottom,
15 None,
16 Inside(f64, f64),
19}
20
21#[derive(Clone, Copy, Debug, Default, PartialEq)]
24pub enum TitlePosition {
25 #[default]
26 Panel,
27 Plot,
28}
29
30#[derive(Clone, Copy, Debug, Default, PartialEq)]
32pub enum TagPosition {
33 #[default]
34 TopLeft,
35 TopRight,
36 BottomLeft,
37 BottomRight,
38}
39
40#[derive(Clone, Copy, Debug, PartialEq)]
42pub enum LegendDirection {
43 Vertical,
44 Horizontal,
45}
46
47#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
51pub enum AxisLabelFit {
52 Clip,
55 Shift,
60 #[default]
66 Reserve,
67}
68
69#[derive(Clone, Debug)]
71pub struct Margin {
72 pub top: f64,
73 pub right: f64,
74 pub bottom: f64,
75 pub left: f64,
76}
77
78impl Default for Margin {
79 fn default() -> Self {
80 Margin {
81 top: 10.0,
82 right: 10.0,
83 bottom: 10.0,
84 left: 10.0,
85 }
86 }
87}
88
89#[derive(Clone, Debug)]
91pub struct Theme {
92 pub text: ElementText,
94 pub title: ElementText,
95 pub axis_text_x: ElementText,
96 pub axis_text_y: ElementText,
97 pub axis_title_x: ElementText,
98 pub axis_title_y: ElementText,
99 pub axis_line: ElementLine,
100 pub axis_ticks: ElementLine,
101 pub panel_background: ElementRect,
102 pub panel_grid_major: ElementLine,
103 pub panel_grid_minor: ElementLine,
104 pub plot_background: ElementRect,
105 pub legend_position: LegendPosition,
106 pub plot_margin: Margin,
107
108 pub subtitle: ElementText,
110 pub caption: ElementText,
111 pub legend_title: ElementText,
112 pub legend_text: ElementText,
113 pub strip_text: ElementText,
114
115 pub axis_line_x: Option<ElementLine>,
117 pub axis_line_y: Option<ElementLine>,
118 pub axis_ticks_x: Option<ElementLine>,
119 pub axis_ticks_y: Option<ElementLine>,
120 pub panel_grid_major_x: Option<ElementLine>,
121 pub panel_grid_major_y: Option<ElementLine>,
122 pub panel_grid_minor_x: Option<ElementLine>,
123 pub panel_grid_minor_y: Option<ElementLine>,
124
125 pub panel_border: ElementLine,
127 pub legend_background: ElementRect,
128 pub legend_key: ElementRect,
129 pub strip_background: ElementRect,
130
131 pub axis_ticks_length: f64,
133 pub axis_text_x_dodge: usize,
136 pub legend_key_width: f64,
137 pub legend_key_height: f64,
138 pub legend_spacing: f64,
139 pub legend_margin: Margin,
140 pub panel_spacing: f64,
141 pub panel_spacing_x: Option<f64>,
142 pub panel_spacing_y: Option<f64>,
143
144 pub primary: Option<(u8, u8, u8)>,
149
150 pub aspect_ratio: Option<f64>,
153 pub panel_ontop: bool,
155 pub axis_minor_ticks: bool,
157 pub title_position: TitlePosition,
160 pub tag_position: TagPosition,
162 pub legend_direction: Option<LegendDirection>,
164 pub calendar_month_border: ElementLine,
166 pub legend_bar_border: Option<ElementLine>,
170 pub geom: ElementGeom,
173
174 pub axis_text_x_fit: AxisLabelFit,
177 pub axis_text_x_check_overlap: bool,
180}
181
182impl Theme {
183 pub fn primary_or(&self, fallback: (u8, u8, u8)) -> (u8, u8, u8) {
186 self.primary.unwrap_or(fallback)
187 }
188
189 pub fn with_primary(mut self, color: (u8, u8, u8)) -> Self {
191 self.primary = Some(color);
192 self
193 }
194
195 pub fn set_geom(mut self, el: ElementGeom) -> Self {
197 self.geom = el;
198 self
199 }
200
201 pub fn with_ink_paper(mut self, ink: (u8, u8, u8), paper: (u8, u8, u8)) -> Self {
204 self.geom.ink = Some(ink);
205 self.geom.paper = Some(paper);
206 self
207 }
208
209 pub fn resolve_inheritance(&mut self) {
215 let root = self.text.clone();
216 let def = ElementText::default();
217 let children: [&mut ElementText; 10] = [
218 &mut self.title,
219 &mut self.subtitle,
220 &mut self.caption,
221 &mut self.axis_text_x,
222 &mut self.axis_text_y,
223 &mut self.axis_title_x,
224 &mut self.axis_title_y,
225 &mut self.legend_title,
226 &mut self.legend_text,
227 &mut self.strip_text,
228 ];
229 for el in children {
230 if el.family == def.family {
231 el.family = root.family.clone();
232 }
233 if el.color == def.color {
234 el.color = root.color;
235 }
236 }
237 }
238
239 pub fn get_axis_line_x(&self) -> &ElementLine {
242 self.axis_line_x.as_ref().unwrap_or(&self.axis_line)
243 }
244
245 pub fn get_axis_line_y(&self) -> &ElementLine {
246 self.axis_line_y.as_ref().unwrap_or(&self.axis_line)
247 }
248
249 pub fn get_axis_ticks_x(&self) -> &ElementLine {
250 self.axis_ticks_x.as_ref().unwrap_or(&self.axis_ticks)
251 }
252
253 pub fn get_axis_ticks_y(&self) -> &ElementLine {
254 self.axis_ticks_y.as_ref().unwrap_or(&self.axis_ticks)
255 }
256
257 pub fn get_panel_grid_major_x(&self) -> &ElementLine {
258 self.panel_grid_major_x
259 .as_ref()
260 .unwrap_or(&self.panel_grid_major)
261 }
262
263 pub fn get_panel_grid_major_y(&self) -> &ElementLine {
264 self.panel_grid_major_y
265 .as_ref()
266 .unwrap_or(&self.panel_grid_major)
267 }
268
269 pub fn get_panel_grid_minor_x(&self) -> &ElementLine {
270 self.panel_grid_minor_x
271 .as_ref()
272 .unwrap_or(&self.panel_grid_minor)
273 }
274
275 pub fn get_panel_grid_minor_y(&self) -> &ElementLine {
276 self.panel_grid_minor_y
277 .as_ref()
278 .unwrap_or(&self.panel_grid_minor)
279 }
280
281 pub fn get_panel_spacing_x(&self) -> f64 {
282 self.panel_spacing_x.unwrap_or(self.panel_spacing)
283 }
284
285 pub fn get_panel_spacing_y(&self) -> f64 {
286 self.panel_spacing_y.unwrap_or(self.panel_spacing)
287 }
288
289 pub fn set_axis_text_x(mut self, el: ElementText) -> Self {
292 self.axis_text_x = el;
293 self
294 }
295
296 pub fn set_axis_text_y(mut self, el: ElementText) -> Self {
297 self.axis_text_y = el;
298 self
299 }
300
301 pub fn set_axis_title_x(mut self, el: ElementText) -> Self {
302 self.axis_title_x = el;
303 self
304 }
305
306 pub fn set_axis_title_y(mut self, el: ElementText) -> Self {
307 self.axis_title_y = el;
308 self
309 }
310
311 pub fn set_axis_line(mut self, el: ElementLine) -> Self {
312 self.axis_line = el;
313 self
314 }
315
316 pub fn set_axis_ticks(mut self, el: ElementLine) -> Self {
317 self.axis_ticks = el;
318 self
319 }
320
321 pub fn set_panel_background(mut self, el: ElementRect) -> Self {
322 self.panel_background = el;
323 self
324 }
325
326 pub fn set_panel_grid_major(mut self, el: ElementLine) -> Self {
327 self.panel_grid_major = el;
328 self
329 }
330
331 pub fn set_panel_grid_minor(mut self, el: ElementLine) -> Self {
332 self.panel_grid_minor = el;
333 self
334 }
335
336 pub fn set_plot_background(mut self, el: ElementRect) -> Self {
337 self.plot_background = el;
338 self
339 }
340
341 pub fn set_legend_position(mut self, pos: LegendPosition) -> Self {
342 self.legend_position = pos;
343 self
344 }
345
346 pub fn set_plot_margin(mut self, margin: Margin) -> Self {
347 self.plot_margin = margin;
348 self
349 }
350
351 pub fn set_title(mut self, el: ElementText) -> Self {
352 self.title = el;
353 self
354 }
355
356 pub fn set_text(mut self, el: ElementText) -> Self {
357 self.text = el;
358 self
359 }
360
361 pub fn set_subtitle(mut self, el: ElementText) -> Self {
364 self.subtitle = el;
365 self
366 }
367
368 pub fn set_caption(mut self, el: ElementText) -> Self {
369 self.caption = el;
370 self
371 }
372
373 pub fn set_legend_title(mut self, el: ElementText) -> Self {
374 self.legend_title = el;
375 self
376 }
377
378 pub fn set_legend_text(mut self, el: ElementText) -> Self {
379 self.legend_text = el;
380 self
381 }
382
383 pub fn set_strip_text(mut self, el: ElementText) -> Self {
384 self.strip_text = el;
385 self
386 }
387
388 pub fn set_axis_line_x(mut self, el: Option<ElementLine>) -> Self {
389 self.axis_line_x = el;
390 self
391 }
392
393 pub fn set_axis_line_y(mut self, el: Option<ElementLine>) -> Self {
394 self.axis_line_y = el;
395 self
396 }
397
398 pub fn set_axis_ticks_x(mut self, el: Option<ElementLine>) -> Self {
399 self.axis_ticks_x = el;
400 self
401 }
402
403 pub fn set_axis_ticks_y(mut self, el: Option<ElementLine>) -> Self {
404 self.axis_ticks_y = el;
405 self
406 }
407
408 pub fn set_panel_grid_major_x(mut self, el: Option<ElementLine>) -> Self {
409 self.panel_grid_major_x = el;
410 self
411 }
412
413 pub fn set_panel_grid_major_y(mut self, el: Option<ElementLine>) -> Self {
414 self.panel_grid_major_y = el;
415 self
416 }
417
418 pub fn set_panel_grid_minor_x(mut self, el: Option<ElementLine>) -> Self {
419 self.panel_grid_minor_x = el;
420 self
421 }
422
423 pub fn set_panel_grid_minor_y(mut self, el: Option<ElementLine>) -> Self {
424 self.panel_grid_minor_y = el;
425 self
426 }
427
428 pub fn set_panel_border(mut self, el: ElementLine) -> Self {
429 self.panel_border = el;
430 self
431 }
432
433 pub fn legend_bar_border_line(&self) -> ElementLine {
436 self.legend_bar_border.clone().unwrap_or(ElementLine {
437 color: self.legend_key.color.unwrap_or((50, 50, 50)),
438 width: 0.5,
439 visible: true,
440 linetype: crate::render::backend::Linetype::Solid,
441 })
442 }
443
444 pub fn set_calendar_month_border(mut self, el: ElementLine) -> Self {
445 self.calendar_month_border = el;
446 self
447 }
448
449 pub fn set_legend_bar_border(mut self, el: Option<ElementLine>) -> Self {
450 self.legend_bar_border = el;
451 self
452 }
453
454 pub fn set_legend_background(mut self, el: ElementRect) -> Self {
455 self.legend_background = el;
456 self
457 }
458
459 pub fn set_legend_key(mut self, el: ElementRect) -> Self {
460 self.legend_key = el;
461 self
462 }
463
464 pub fn set_strip_background(mut self, el: ElementRect) -> Self {
465 self.strip_background = el;
466 self
467 }
468
469 pub fn set_axis_ticks_length(mut self, val: f64) -> Self {
470 self.axis_ticks_length = val;
471 self
472 }
473
474 pub fn set_legend_key_width(mut self, val: f64) -> Self {
475 self.legend_key_width = val;
476 self
477 }
478
479 pub fn set_legend_key_height(mut self, val: f64) -> Self {
480 self.legend_key_height = val;
481 self
482 }
483
484 pub fn set_legend_spacing(mut self, val: f64) -> Self {
485 self.legend_spacing = val;
486 self
487 }
488
489 pub fn set_legend_margin(mut self, margin: Margin) -> Self {
490 self.legend_margin = margin;
491 self
492 }
493
494 pub fn set_panel_spacing(mut self, val: f64) -> Self {
495 self.panel_spacing = val;
496 self
497 }
498
499 pub fn set_panel_spacing_x(mut self, val: Option<f64>) -> Self {
500 self.panel_spacing_x = val;
501 self
502 }
503
504 pub fn set_panel_spacing_y(mut self, val: Option<f64>) -> Self {
505 self.panel_spacing_y = val;
506 self
507 }
508
509 pub fn update(mut self, upd: ThemeUpdate) -> Self {
512 if let Some(v) = upd.text {
513 self.text = v;
514 }
515 if let Some(v) = upd.title {
516 self.title = v;
517 }
518 if let Some(v) = upd.subtitle {
519 self.subtitle = v;
520 }
521 if let Some(v) = upd.caption {
522 self.caption = v;
523 }
524 if let Some(v) = upd.axis_text_x {
525 self.axis_text_x = v;
526 }
527 if let Some(v) = upd.axis_text_y {
528 self.axis_text_y = v;
529 }
530 if let Some(v) = upd.axis_title_x {
531 self.axis_title_x = v;
532 }
533 if let Some(v) = upd.axis_title_y {
534 self.axis_title_y = v;
535 }
536 if let Some(v) = upd.axis_line {
537 self.axis_line = v;
538 }
539 if let Some(v) = upd.axis_ticks {
540 self.axis_ticks = v;
541 }
542 if let Some(v) = upd.panel_background {
543 self.panel_background = v;
544 }
545 if let Some(v) = upd.panel_grid_major {
546 self.panel_grid_major = v;
547 }
548 if let Some(v) = upd.panel_grid_minor {
549 self.panel_grid_minor = v;
550 }
551 if let Some(v) = upd.panel_border {
552 self.panel_border = v;
553 }
554 if let Some(v) = upd.calendar_month_border {
555 self.calendar_month_border = v;
556 }
557 if let Some(v) = upd.legend_bar_border {
558 self.legend_bar_border = Some(v);
559 }
560 if let Some(v) = upd.plot_background {
561 self.plot_background = v;
562 }
563 if let Some(v) = upd.legend_position {
564 self.legend_position = v;
565 }
566 if let Some(v) = upd.legend_title {
567 self.legend_title = v;
568 }
569 if let Some(v) = upd.legend_text {
570 self.legend_text = v;
571 }
572 if let Some(v) = upd.legend_background {
573 self.legend_background = v;
574 }
575 if let Some(v) = upd.strip_text {
576 self.strip_text = v;
577 }
578 if let Some(v) = upd.strip_background {
579 self.strip_background = v;
580 }
581 if let Some(v) = upd.plot_margin {
582 self.plot_margin = v;
583 }
584 if let Some(v) = upd.geom {
585 self.geom = v;
586 }
587 self
588 }
589}
590
591#[derive(Clone, Debug, Default)]
594pub struct ThemeUpdate {
595 pub text: Option<ElementText>,
596 pub title: Option<ElementText>,
597 pub subtitle: Option<ElementText>,
598 pub caption: Option<ElementText>,
599 pub axis_text_x: Option<ElementText>,
600 pub axis_text_y: Option<ElementText>,
601 pub axis_title_x: Option<ElementText>,
602 pub axis_title_y: Option<ElementText>,
603 pub axis_line: Option<ElementLine>,
604 pub axis_ticks: Option<ElementLine>,
605 pub panel_background: Option<ElementRect>,
606 pub panel_grid_major: Option<ElementLine>,
607 pub panel_grid_minor: Option<ElementLine>,
608 pub panel_border: Option<ElementLine>,
609 pub calendar_month_border: Option<ElementLine>,
610 pub legend_bar_border: Option<ElementLine>,
611 pub plot_background: Option<ElementRect>,
612 pub legend_position: Option<LegendPosition>,
613 pub legend_title: Option<ElementText>,
614 pub legend_text: Option<ElementText>,
615 pub legend_background: Option<ElementRect>,
616 pub strip_text: Option<ElementText>,
617 pub strip_background: Option<ElementRect>,
618 pub plot_margin: Option<Margin>,
619 pub geom: Option<ElementGeom>,
621}
622
623impl Default for Theme {
624 fn default() -> Self {
625 presets::theme_gray()
626 }
627}