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, Debug)]
49pub struct Margin {
50 pub top: f64,
51 pub right: f64,
52 pub bottom: f64,
53 pub left: f64,
54}
55
56impl Default for Margin {
57 fn default() -> Self {
58 Margin {
59 top: 10.0,
60 right: 10.0,
61 bottom: 10.0,
62 left: 10.0,
63 }
64 }
65}
66
67#[derive(Clone, Debug)]
69pub struct Theme {
70 pub text: ElementText,
72 pub title: ElementText,
73 pub axis_text_x: ElementText,
74 pub axis_text_y: ElementText,
75 pub axis_title_x: ElementText,
76 pub axis_title_y: ElementText,
77 pub axis_line: ElementLine,
78 pub axis_ticks: ElementLine,
79 pub panel_background: ElementRect,
80 pub panel_grid_major: ElementLine,
81 pub panel_grid_minor: ElementLine,
82 pub plot_background: ElementRect,
83 pub legend_position: LegendPosition,
84 pub plot_margin: Margin,
85
86 pub subtitle: ElementText,
88 pub caption: ElementText,
89 pub legend_title: ElementText,
90 pub legend_text: ElementText,
91 pub strip_text: ElementText,
92
93 pub axis_line_x: Option<ElementLine>,
95 pub axis_line_y: Option<ElementLine>,
96 pub axis_ticks_x: Option<ElementLine>,
97 pub axis_ticks_y: Option<ElementLine>,
98 pub panel_grid_major_x: Option<ElementLine>,
99 pub panel_grid_major_y: Option<ElementLine>,
100 pub panel_grid_minor_x: Option<ElementLine>,
101 pub panel_grid_minor_y: Option<ElementLine>,
102
103 pub panel_border: ElementLine,
105 pub legend_background: ElementRect,
106 pub legend_key: ElementRect,
107 pub strip_background: ElementRect,
108
109 pub axis_ticks_length: f64,
111 pub axis_text_x_dodge: usize,
114 pub legend_key_width: f64,
115 pub legend_key_height: f64,
116 pub legend_spacing: f64,
117 pub legend_margin: Margin,
118 pub panel_spacing: f64,
119 pub panel_spacing_x: Option<f64>,
120 pub panel_spacing_y: Option<f64>,
121
122 pub primary: Option<(u8, u8, u8)>,
127
128 pub aspect_ratio: Option<f64>,
131 pub panel_ontop: bool,
133 pub axis_minor_ticks: bool,
135 pub title_position: TitlePosition,
138 pub tag_position: TagPosition,
140 pub legend_direction: Option<LegendDirection>,
142 pub calendar_month_border: ElementLine,
144 pub legend_bar_border: Option<ElementLine>,
148 pub geom: ElementGeom,
151}
152
153impl Theme {
154 pub fn primary_or(&self, fallback: (u8, u8, u8)) -> (u8, u8, u8) {
157 self.primary.unwrap_or(fallback)
158 }
159
160 pub fn with_primary(mut self, color: (u8, u8, u8)) -> Self {
162 self.primary = Some(color);
163 self
164 }
165
166 pub fn set_geom(mut self, el: ElementGeom) -> Self {
168 self.geom = el;
169 self
170 }
171
172 pub fn with_ink_paper(mut self, ink: (u8, u8, u8), paper: (u8, u8, u8)) -> Self {
175 self.geom.ink = Some(ink);
176 self.geom.paper = Some(paper);
177 self
178 }
179
180 pub fn resolve_inheritance(&mut self) {
186 let root = self.text.clone();
187 let def = ElementText::default();
188 let children: [&mut ElementText; 10] = [
189 &mut self.title,
190 &mut self.subtitle,
191 &mut self.caption,
192 &mut self.axis_text_x,
193 &mut self.axis_text_y,
194 &mut self.axis_title_x,
195 &mut self.axis_title_y,
196 &mut self.legend_title,
197 &mut self.legend_text,
198 &mut self.strip_text,
199 ];
200 for el in children {
201 if el.family == def.family {
202 el.family = root.family.clone();
203 }
204 if el.color == def.color {
205 el.color = root.color;
206 }
207 }
208 }
209
210 pub fn get_axis_line_x(&self) -> &ElementLine {
213 self.axis_line_x.as_ref().unwrap_or(&self.axis_line)
214 }
215
216 pub fn get_axis_line_y(&self) -> &ElementLine {
217 self.axis_line_y.as_ref().unwrap_or(&self.axis_line)
218 }
219
220 pub fn get_axis_ticks_x(&self) -> &ElementLine {
221 self.axis_ticks_x.as_ref().unwrap_or(&self.axis_ticks)
222 }
223
224 pub fn get_axis_ticks_y(&self) -> &ElementLine {
225 self.axis_ticks_y.as_ref().unwrap_or(&self.axis_ticks)
226 }
227
228 pub fn get_panel_grid_major_x(&self) -> &ElementLine {
229 self.panel_grid_major_x
230 .as_ref()
231 .unwrap_or(&self.panel_grid_major)
232 }
233
234 pub fn get_panel_grid_major_y(&self) -> &ElementLine {
235 self.panel_grid_major_y
236 .as_ref()
237 .unwrap_or(&self.panel_grid_major)
238 }
239
240 pub fn get_panel_grid_minor_x(&self) -> &ElementLine {
241 self.panel_grid_minor_x
242 .as_ref()
243 .unwrap_or(&self.panel_grid_minor)
244 }
245
246 pub fn get_panel_grid_minor_y(&self) -> &ElementLine {
247 self.panel_grid_minor_y
248 .as_ref()
249 .unwrap_or(&self.panel_grid_minor)
250 }
251
252 pub fn get_panel_spacing_x(&self) -> f64 {
253 self.panel_spacing_x.unwrap_or(self.panel_spacing)
254 }
255
256 pub fn get_panel_spacing_y(&self) -> f64 {
257 self.panel_spacing_y.unwrap_or(self.panel_spacing)
258 }
259
260 pub fn set_axis_text_x(mut self, el: ElementText) -> Self {
263 self.axis_text_x = el;
264 self
265 }
266
267 pub fn set_axis_text_y(mut self, el: ElementText) -> Self {
268 self.axis_text_y = el;
269 self
270 }
271
272 pub fn set_axis_title_x(mut self, el: ElementText) -> Self {
273 self.axis_title_x = el;
274 self
275 }
276
277 pub fn set_axis_title_y(mut self, el: ElementText) -> Self {
278 self.axis_title_y = el;
279 self
280 }
281
282 pub fn set_axis_line(mut self, el: ElementLine) -> Self {
283 self.axis_line = el;
284 self
285 }
286
287 pub fn set_axis_ticks(mut self, el: ElementLine) -> Self {
288 self.axis_ticks = el;
289 self
290 }
291
292 pub fn set_panel_background(mut self, el: ElementRect) -> Self {
293 self.panel_background = el;
294 self
295 }
296
297 pub fn set_panel_grid_major(mut self, el: ElementLine) -> Self {
298 self.panel_grid_major = el;
299 self
300 }
301
302 pub fn set_panel_grid_minor(mut self, el: ElementLine) -> Self {
303 self.panel_grid_minor = el;
304 self
305 }
306
307 pub fn set_plot_background(mut self, el: ElementRect) -> Self {
308 self.plot_background = el;
309 self
310 }
311
312 pub fn set_legend_position(mut self, pos: LegendPosition) -> Self {
313 self.legend_position = pos;
314 self
315 }
316
317 pub fn set_plot_margin(mut self, margin: Margin) -> Self {
318 self.plot_margin = margin;
319 self
320 }
321
322 pub fn set_title(mut self, el: ElementText) -> Self {
323 self.title = el;
324 self
325 }
326
327 pub fn set_text(mut self, el: ElementText) -> Self {
328 self.text = el;
329 self
330 }
331
332 pub fn set_subtitle(mut self, el: ElementText) -> Self {
335 self.subtitle = el;
336 self
337 }
338
339 pub fn set_caption(mut self, el: ElementText) -> Self {
340 self.caption = el;
341 self
342 }
343
344 pub fn set_legend_title(mut self, el: ElementText) -> Self {
345 self.legend_title = el;
346 self
347 }
348
349 pub fn set_legend_text(mut self, el: ElementText) -> Self {
350 self.legend_text = el;
351 self
352 }
353
354 pub fn set_strip_text(mut self, el: ElementText) -> Self {
355 self.strip_text = el;
356 self
357 }
358
359 pub fn set_axis_line_x(mut self, el: Option<ElementLine>) -> Self {
360 self.axis_line_x = el;
361 self
362 }
363
364 pub fn set_axis_line_y(mut self, el: Option<ElementLine>) -> Self {
365 self.axis_line_y = el;
366 self
367 }
368
369 pub fn set_axis_ticks_x(mut self, el: Option<ElementLine>) -> Self {
370 self.axis_ticks_x = el;
371 self
372 }
373
374 pub fn set_axis_ticks_y(mut self, el: Option<ElementLine>) -> Self {
375 self.axis_ticks_y = el;
376 self
377 }
378
379 pub fn set_panel_grid_major_x(mut self, el: Option<ElementLine>) -> Self {
380 self.panel_grid_major_x = el;
381 self
382 }
383
384 pub fn set_panel_grid_major_y(mut self, el: Option<ElementLine>) -> Self {
385 self.panel_grid_major_y = el;
386 self
387 }
388
389 pub fn set_panel_grid_minor_x(mut self, el: Option<ElementLine>) -> Self {
390 self.panel_grid_minor_x = el;
391 self
392 }
393
394 pub fn set_panel_grid_minor_y(mut self, el: Option<ElementLine>) -> Self {
395 self.panel_grid_minor_y = el;
396 self
397 }
398
399 pub fn set_panel_border(mut self, el: ElementLine) -> Self {
400 self.panel_border = el;
401 self
402 }
403
404 pub fn legend_bar_border_line(&self) -> ElementLine {
407 self.legend_bar_border.clone().unwrap_or(ElementLine {
408 color: self.legend_key.color.unwrap_or((50, 50, 50)),
409 width: 0.5,
410 visible: true,
411 linetype: crate::render::backend::Linetype::Solid,
412 })
413 }
414
415 pub fn set_calendar_month_border(mut self, el: ElementLine) -> Self {
416 self.calendar_month_border = el;
417 self
418 }
419
420 pub fn set_legend_bar_border(mut self, el: Option<ElementLine>) -> Self {
421 self.legend_bar_border = el;
422 self
423 }
424
425 pub fn set_legend_background(mut self, el: ElementRect) -> Self {
426 self.legend_background = el;
427 self
428 }
429
430 pub fn set_legend_key(mut self, el: ElementRect) -> Self {
431 self.legend_key = el;
432 self
433 }
434
435 pub fn set_strip_background(mut self, el: ElementRect) -> Self {
436 self.strip_background = el;
437 self
438 }
439
440 pub fn set_axis_ticks_length(mut self, val: f64) -> Self {
441 self.axis_ticks_length = val;
442 self
443 }
444
445 pub fn set_legend_key_width(mut self, val: f64) -> Self {
446 self.legend_key_width = val;
447 self
448 }
449
450 pub fn set_legend_key_height(mut self, val: f64) -> Self {
451 self.legend_key_height = val;
452 self
453 }
454
455 pub fn set_legend_spacing(mut self, val: f64) -> Self {
456 self.legend_spacing = val;
457 self
458 }
459
460 pub fn set_legend_margin(mut self, margin: Margin) -> Self {
461 self.legend_margin = margin;
462 self
463 }
464
465 pub fn set_panel_spacing(mut self, val: f64) -> Self {
466 self.panel_spacing = val;
467 self
468 }
469
470 pub fn set_panel_spacing_x(mut self, val: Option<f64>) -> Self {
471 self.panel_spacing_x = val;
472 self
473 }
474
475 pub fn set_panel_spacing_y(mut self, val: Option<f64>) -> Self {
476 self.panel_spacing_y = val;
477 self
478 }
479
480 pub fn update(mut self, upd: ThemeUpdate) -> Self {
483 if let Some(v) = upd.text {
484 self.text = v;
485 }
486 if let Some(v) = upd.title {
487 self.title = v;
488 }
489 if let Some(v) = upd.subtitle {
490 self.subtitle = v;
491 }
492 if let Some(v) = upd.caption {
493 self.caption = v;
494 }
495 if let Some(v) = upd.axis_text_x {
496 self.axis_text_x = v;
497 }
498 if let Some(v) = upd.axis_text_y {
499 self.axis_text_y = v;
500 }
501 if let Some(v) = upd.axis_title_x {
502 self.axis_title_x = v;
503 }
504 if let Some(v) = upd.axis_title_y {
505 self.axis_title_y = v;
506 }
507 if let Some(v) = upd.axis_line {
508 self.axis_line = v;
509 }
510 if let Some(v) = upd.axis_ticks {
511 self.axis_ticks = v;
512 }
513 if let Some(v) = upd.panel_background {
514 self.panel_background = v;
515 }
516 if let Some(v) = upd.panel_grid_major {
517 self.panel_grid_major = v;
518 }
519 if let Some(v) = upd.panel_grid_minor {
520 self.panel_grid_minor = v;
521 }
522 if let Some(v) = upd.panel_border {
523 self.panel_border = v;
524 }
525 if let Some(v) = upd.calendar_month_border {
526 self.calendar_month_border = v;
527 }
528 if let Some(v) = upd.legend_bar_border {
529 self.legend_bar_border = Some(v);
530 }
531 if let Some(v) = upd.plot_background {
532 self.plot_background = v;
533 }
534 if let Some(v) = upd.legend_position {
535 self.legend_position = v;
536 }
537 if let Some(v) = upd.legend_title {
538 self.legend_title = v;
539 }
540 if let Some(v) = upd.legend_text {
541 self.legend_text = v;
542 }
543 if let Some(v) = upd.legend_background {
544 self.legend_background = v;
545 }
546 if let Some(v) = upd.strip_text {
547 self.strip_text = v;
548 }
549 if let Some(v) = upd.strip_background {
550 self.strip_background = v;
551 }
552 if let Some(v) = upd.plot_margin {
553 self.plot_margin = v;
554 }
555 if let Some(v) = upd.geom {
556 self.geom = v;
557 }
558 self
559 }
560}
561
562#[derive(Clone, Debug, Default)]
565pub struct ThemeUpdate {
566 pub text: Option<ElementText>,
567 pub title: Option<ElementText>,
568 pub subtitle: Option<ElementText>,
569 pub caption: Option<ElementText>,
570 pub axis_text_x: Option<ElementText>,
571 pub axis_text_y: Option<ElementText>,
572 pub axis_title_x: Option<ElementText>,
573 pub axis_title_y: Option<ElementText>,
574 pub axis_line: Option<ElementLine>,
575 pub axis_ticks: Option<ElementLine>,
576 pub panel_background: Option<ElementRect>,
577 pub panel_grid_major: Option<ElementLine>,
578 pub panel_grid_minor: Option<ElementLine>,
579 pub panel_border: Option<ElementLine>,
580 pub calendar_month_border: Option<ElementLine>,
581 pub legend_bar_border: Option<ElementLine>,
582 pub plot_background: Option<ElementRect>,
583 pub legend_position: Option<LegendPosition>,
584 pub legend_title: Option<ElementText>,
585 pub legend_text: Option<ElementText>,
586 pub legend_background: Option<ElementRect>,
587 pub strip_text: Option<ElementText>,
588 pub strip_background: Option<ElementRect>,
589 pub plot_margin: Option<Margin>,
590 pub geom: Option<ElementGeom>,
592}
593
594impl Default for Theme {
595 fn default() -> Self {
596 presets::theme_gray()
597 }
598}