1#[cfg(feature = "serde")]
2pub mod config;
3pub mod elements;
4pub mod presets;
5
6pub use elements::{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}
143
144impl Theme {
145 pub fn primary_or(&self, fallback: (u8, u8, u8)) -> (u8, u8, u8) {
148 self.primary.unwrap_or(fallback)
149 }
150
151 pub fn with_primary(mut self, color: (u8, u8, u8)) -> Self {
153 self.primary = Some(color);
154 self
155 }
156
157 pub fn resolve_inheritance(&mut self) {
163 let root = self.text.clone();
164 let def = ElementText::default();
165 let children: [&mut ElementText; 10] = [
166 &mut self.title,
167 &mut self.subtitle,
168 &mut self.caption,
169 &mut self.axis_text_x,
170 &mut self.axis_text_y,
171 &mut self.axis_title_x,
172 &mut self.axis_title_y,
173 &mut self.legend_title,
174 &mut self.legend_text,
175 &mut self.strip_text,
176 ];
177 for el in children {
178 if el.family == def.family {
179 el.family = root.family.clone();
180 }
181 if el.color == def.color {
182 el.color = root.color;
183 }
184 }
185 }
186
187 pub fn get_axis_line_x(&self) -> &ElementLine {
190 self.axis_line_x.as_ref().unwrap_or(&self.axis_line)
191 }
192
193 pub fn get_axis_line_y(&self) -> &ElementLine {
194 self.axis_line_y.as_ref().unwrap_or(&self.axis_line)
195 }
196
197 pub fn get_axis_ticks_x(&self) -> &ElementLine {
198 self.axis_ticks_x.as_ref().unwrap_or(&self.axis_ticks)
199 }
200
201 pub fn get_axis_ticks_y(&self) -> &ElementLine {
202 self.axis_ticks_y.as_ref().unwrap_or(&self.axis_ticks)
203 }
204
205 pub fn get_panel_grid_major_x(&self) -> &ElementLine {
206 self.panel_grid_major_x
207 .as_ref()
208 .unwrap_or(&self.panel_grid_major)
209 }
210
211 pub fn get_panel_grid_major_y(&self) -> &ElementLine {
212 self.panel_grid_major_y
213 .as_ref()
214 .unwrap_or(&self.panel_grid_major)
215 }
216
217 pub fn get_panel_grid_minor_x(&self) -> &ElementLine {
218 self.panel_grid_minor_x
219 .as_ref()
220 .unwrap_or(&self.panel_grid_minor)
221 }
222
223 pub fn get_panel_grid_minor_y(&self) -> &ElementLine {
224 self.panel_grid_minor_y
225 .as_ref()
226 .unwrap_or(&self.panel_grid_minor)
227 }
228
229 pub fn get_panel_spacing_x(&self) -> f64 {
230 self.panel_spacing_x.unwrap_or(self.panel_spacing)
231 }
232
233 pub fn get_panel_spacing_y(&self) -> f64 {
234 self.panel_spacing_y.unwrap_or(self.panel_spacing)
235 }
236
237 pub fn set_axis_text_x(mut self, el: ElementText) -> Self {
240 self.axis_text_x = el;
241 self
242 }
243
244 pub fn set_axis_text_y(mut self, el: ElementText) -> Self {
245 self.axis_text_y = el;
246 self
247 }
248
249 pub fn set_axis_title_x(mut self, el: ElementText) -> Self {
250 self.axis_title_x = el;
251 self
252 }
253
254 pub fn set_axis_title_y(mut self, el: ElementText) -> Self {
255 self.axis_title_y = el;
256 self
257 }
258
259 pub fn set_axis_line(mut self, el: ElementLine) -> Self {
260 self.axis_line = el;
261 self
262 }
263
264 pub fn set_axis_ticks(mut self, el: ElementLine) -> Self {
265 self.axis_ticks = el;
266 self
267 }
268
269 pub fn set_panel_background(mut self, el: ElementRect) -> Self {
270 self.panel_background = el;
271 self
272 }
273
274 pub fn set_panel_grid_major(mut self, el: ElementLine) -> Self {
275 self.panel_grid_major = el;
276 self
277 }
278
279 pub fn set_panel_grid_minor(mut self, el: ElementLine) -> Self {
280 self.panel_grid_minor = el;
281 self
282 }
283
284 pub fn set_plot_background(mut self, el: ElementRect) -> Self {
285 self.plot_background = el;
286 self
287 }
288
289 pub fn set_legend_position(mut self, pos: LegendPosition) -> Self {
290 self.legend_position = pos;
291 self
292 }
293
294 pub fn set_plot_margin(mut self, margin: Margin) -> Self {
295 self.plot_margin = margin;
296 self
297 }
298
299 pub fn set_title(mut self, el: ElementText) -> Self {
300 self.title = el;
301 self
302 }
303
304 pub fn set_text(mut self, el: ElementText) -> Self {
305 self.text = el;
306 self
307 }
308
309 pub fn set_subtitle(mut self, el: ElementText) -> Self {
312 self.subtitle = el;
313 self
314 }
315
316 pub fn set_caption(mut self, el: ElementText) -> Self {
317 self.caption = el;
318 self
319 }
320
321 pub fn set_legend_title(mut self, el: ElementText) -> Self {
322 self.legend_title = el;
323 self
324 }
325
326 pub fn set_legend_text(mut self, el: ElementText) -> Self {
327 self.legend_text = el;
328 self
329 }
330
331 pub fn set_strip_text(mut self, el: ElementText) -> Self {
332 self.strip_text = el;
333 self
334 }
335
336 pub fn set_axis_line_x(mut self, el: Option<ElementLine>) -> Self {
337 self.axis_line_x = el;
338 self
339 }
340
341 pub fn set_axis_line_y(mut self, el: Option<ElementLine>) -> Self {
342 self.axis_line_y = el;
343 self
344 }
345
346 pub fn set_axis_ticks_x(mut self, el: Option<ElementLine>) -> Self {
347 self.axis_ticks_x = el;
348 self
349 }
350
351 pub fn set_axis_ticks_y(mut self, el: Option<ElementLine>) -> Self {
352 self.axis_ticks_y = el;
353 self
354 }
355
356 pub fn set_panel_grid_major_x(mut self, el: Option<ElementLine>) -> Self {
357 self.panel_grid_major_x = el;
358 self
359 }
360
361 pub fn set_panel_grid_major_y(mut self, el: Option<ElementLine>) -> Self {
362 self.panel_grid_major_y = el;
363 self
364 }
365
366 pub fn set_panel_grid_minor_x(mut self, el: Option<ElementLine>) -> Self {
367 self.panel_grid_minor_x = el;
368 self
369 }
370
371 pub fn set_panel_grid_minor_y(mut self, el: Option<ElementLine>) -> Self {
372 self.panel_grid_minor_y = el;
373 self
374 }
375
376 pub fn set_panel_border(mut self, el: ElementLine) -> Self {
377 self.panel_border = el;
378 self
379 }
380
381 pub fn set_legend_background(mut self, el: ElementRect) -> Self {
382 self.legend_background = el;
383 self
384 }
385
386 pub fn set_legend_key(mut self, el: ElementRect) -> Self {
387 self.legend_key = el;
388 self
389 }
390
391 pub fn set_strip_background(mut self, el: ElementRect) -> Self {
392 self.strip_background = el;
393 self
394 }
395
396 pub fn set_axis_ticks_length(mut self, val: f64) -> Self {
397 self.axis_ticks_length = val;
398 self
399 }
400
401 pub fn set_legend_key_width(mut self, val: f64) -> Self {
402 self.legend_key_width = val;
403 self
404 }
405
406 pub fn set_legend_key_height(mut self, val: f64) -> Self {
407 self.legend_key_height = val;
408 self
409 }
410
411 pub fn set_legend_spacing(mut self, val: f64) -> Self {
412 self.legend_spacing = val;
413 self
414 }
415
416 pub fn set_legend_margin(mut self, margin: Margin) -> Self {
417 self.legend_margin = margin;
418 self
419 }
420
421 pub fn set_panel_spacing(mut self, val: f64) -> Self {
422 self.panel_spacing = val;
423 self
424 }
425
426 pub fn set_panel_spacing_x(mut self, val: Option<f64>) -> Self {
427 self.panel_spacing_x = val;
428 self
429 }
430
431 pub fn set_panel_spacing_y(mut self, val: Option<f64>) -> Self {
432 self.panel_spacing_y = val;
433 self
434 }
435
436 pub fn update(mut self, upd: ThemeUpdate) -> Self {
439 if let Some(v) = upd.text {
440 self.text = v;
441 }
442 if let Some(v) = upd.title {
443 self.title = v;
444 }
445 if let Some(v) = upd.subtitle {
446 self.subtitle = v;
447 }
448 if let Some(v) = upd.caption {
449 self.caption = v;
450 }
451 if let Some(v) = upd.axis_text_x {
452 self.axis_text_x = v;
453 }
454 if let Some(v) = upd.axis_text_y {
455 self.axis_text_y = v;
456 }
457 if let Some(v) = upd.axis_title_x {
458 self.axis_title_x = v;
459 }
460 if let Some(v) = upd.axis_title_y {
461 self.axis_title_y = v;
462 }
463 if let Some(v) = upd.axis_line {
464 self.axis_line = v;
465 }
466 if let Some(v) = upd.axis_ticks {
467 self.axis_ticks = v;
468 }
469 if let Some(v) = upd.panel_background {
470 self.panel_background = v;
471 }
472 if let Some(v) = upd.panel_grid_major {
473 self.panel_grid_major = v;
474 }
475 if let Some(v) = upd.panel_grid_minor {
476 self.panel_grid_minor = v;
477 }
478 if let Some(v) = upd.panel_border {
479 self.panel_border = v;
480 }
481 if let Some(v) = upd.plot_background {
482 self.plot_background = v;
483 }
484 if let Some(v) = upd.legend_position {
485 self.legend_position = v;
486 }
487 if let Some(v) = upd.legend_title {
488 self.legend_title = v;
489 }
490 if let Some(v) = upd.legend_text {
491 self.legend_text = v;
492 }
493 if let Some(v) = upd.legend_background {
494 self.legend_background = v;
495 }
496 if let Some(v) = upd.strip_text {
497 self.strip_text = v;
498 }
499 if let Some(v) = upd.strip_background {
500 self.strip_background = v;
501 }
502 if let Some(v) = upd.plot_margin {
503 self.plot_margin = v;
504 }
505 self
506 }
507}
508
509#[derive(Clone, Debug, Default)]
512pub struct ThemeUpdate {
513 pub text: Option<ElementText>,
514 pub title: Option<ElementText>,
515 pub subtitle: Option<ElementText>,
516 pub caption: Option<ElementText>,
517 pub axis_text_x: Option<ElementText>,
518 pub axis_text_y: Option<ElementText>,
519 pub axis_title_x: Option<ElementText>,
520 pub axis_title_y: Option<ElementText>,
521 pub axis_line: Option<ElementLine>,
522 pub axis_ticks: Option<ElementLine>,
523 pub panel_background: Option<ElementRect>,
524 pub panel_grid_major: Option<ElementLine>,
525 pub panel_grid_minor: Option<ElementLine>,
526 pub panel_border: Option<ElementLine>,
527 pub plot_background: Option<ElementRect>,
528 pub legend_position: Option<LegendPosition>,
529 pub legend_title: Option<ElementText>,
530 pub legend_text: Option<ElementText>,
531 pub legend_background: Option<ElementRect>,
532 pub strip_text: Option<ElementText>,
533 pub strip_background: Option<ElementRect>,
534 pub plot_margin: Option<Margin>,
535}
536
537impl Default for Theme {
538 fn default() -> Self {
539 presets::theme_gray()
540 }
541}