1use super::{ColorsLinear, Theme, ThemeDst, Window};
9use crate::config::{Config, WindowConfig};
10use crate::draw::{DrawIface, DrawSharedImpl, color};
11use crate::event::EventState;
12use crate::theme::ThemeDraw;
13use std::cell::RefCell;
14use std::collections::HashMap;
15
16type DynTheme<DS> = Box<dyn ThemeDst<DS>>;
17
18pub struct MultiTheme<DS> {
20 names: HashMap<String, usize>,
21 themes: Vec<DynTheme<DS>>,
22 active: usize,
23}
24
25pub struct MultiThemeBuilder<DS> {
29 names: HashMap<String, usize>,
30 themes: Vec<DynTheme<DS>>,
31}
32
33impl<DS> MultiTheme<DS> {
34 pub fn builder() -> MultiThemeBuilder<DS> {
36 MultiThemeBuilder {
37 names: HashMap::new(),
38 themes: vec![],
39 }
40 }
41}
42
43impl<DS> MultiThemeBuilder<DS> {
44 #[must_use]
46 pub fn add<S: ToString, T>(mut self, name: S, theme: T) -> Self
47 where
48 DS: DrawSharedImpl,
49 T: ThemeDst<DS> + 'static,
50 {
51 let index = self.themes.len();
52 self.names.insert(name.to_string(), index);
53 self.themes.push(Box::new(theme));
54 self
55 }
56
57 pub fn try_build(self) -> Option<MultiTheme<DS>> {
61 if self.themes.is_empty() {
62 return None;
63 }
64 Some(MultiTheme {
65 names: self.names,
66 themes: self.themes,
67 active: 0,
68 })
69 }
70
71 pub fn build(self) -> MultiTheme<DS> {
75 self.try_build()
76 .unwrap_or_else(|| panic!("MultiThemeBuilder: no themes added"))
77 }
78}
79
80impl<DS: DrawSharedImpl> Theme<DS> for MultiTheme<DS> {
81 type Window = Box<dyn Window>;
82 type Draw<'a> = Box<dyn ThemeDraw + 'a>;
83
84 fn init(&mut self, config: &RefCell<Config>) {
85 if config.borrow().theme.active_theme.is_empty() {
86 for (name, index) in &self.names {
87 if *index == self.active {
88 let _ = config.borrow_mut().theme.set_active_theme(name.to_string());
89 break;
90 }
91 }
92 }
93
94 for theme in &mut self.themes {
95 theme.init(config);
96 }
97 }
98
99 fn new_window(&mut self, config: &WindowConfig) -> Self::Window {
100 let theme = &config.theme().active_theme;
102 if let Some(index) = self.names.get(theme).cloned()
103 && index != self.active
104 {
105 self.active = index;
106 }
107
108 self.themes[self.active].new_window(config)
109 }
110
111 fn update_window(&mut self, window: &mut Self::Window, config: &WindowConfig) {
112 self.themes[self.active].update_window(window, config);
113 }
114
115 fn draw<'a>(
116 &'a self,
117 draw: DrawIface<'a, DS>,
118 ev: &'a mut EventState,
119 window: &'a mut Self::Window,
120 ) -> Box<dyn ThemeDraw + 'a> {
121 self.themes[self.active].draw(draw, ev, window)
122 }
123
124 fn draw_upcast<'a>(
125 _draw: DrawIface<'a, DS>,
126 _ev: &'a mut EventState,
127 _w: &'a mut Self::Window,
128 _cols: &'a ColorsLinear,
129 ) -> Self::Draw<'a> {
130 unimplemented!()
131 }
132
133 fn clear_color(&self) -> color::Rgba {
134 self.themes[self.active].clear_color()
135 }
136}