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