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
25impl<DS> MultiTheme<DS> {
26 #[allow(clippy::new_without_default)]
30 pub fn new() -> MultiTheme<DS> {
31 MultiTheme {
32 names: HashMap::new(),
33 themes: vec![],
34 active: 0,
35 }
36 }
37
38 pub fn add<S: ToString, T>(&mut self, name: S, theme: T) -> usize
42 where
43 DS: DrawSharedImpl,
44 T: ThemeDst<DS> + 'static,
45 {
46 let index = self.themes.len();
47 self.names.insert(name.to_string(), index);
48 self.themes.push(Box::new(theme));
49 index
50 }
51
52 pub fn set_active(&mut self, index: usize) {
58 self.active = index;
59 }
60}
61
62impl<DS: DrawSharedImpl> Theme<DS> for MultiTheme<DS> {
63 type Window = Box<dyn Window>;
64 type Draw<'a> = Box<dyn ThemeDraw + 'a>;
65
66 fn init(&mut self, config: &RefCell<Config>) {
67 if self.active >= self.themes.len() {
68 panic!(
69 "MultiTheme: invalid index {} in list of {} themes added",
70 self.active,
71 self.themes.len()
72 );
73 }
74
75 if config.borrow().theme.active_theme.is_empty() {
76 for (name, index) in &self.names {
77 if *index == self.active {
78 let _ = config.borrow_mut().theme.set_active_theme(name.to_string());
79 break;
80 }
81 }
82 }
83
84 for theme in &mut self.themes {
85 theme.init(config);
86 }
87 }
88
89 fn new_window(&mut self, config: &WindowConfig) -> Self::Window {
90 let theme = &config.theme().active_theme;
92 if let Some(index) = self.names.get(theme).cloned()
93 && index != self.active
94 {
95 self.active = index;
96 }
97
98 self.themes[self.active].new_window(config)
99 }
100
101 fn update_window(&mut self, window: &mut Self::Window, config: &WindowConfig) -> bool {
102 self.themes[self.active].update_window(window, config)
103 }
104
105 fn draw<'a>(
106 &'a self,
107 draw: DrawIface<'a, DS>,
108 ev: &'a mut EventState,
109 window: &'a mut Self::Window,
110 ) -> Box<dyn ThemeDraw + 'a> {
111 self.themes[self.active].draw(draw, ev, window)
112 }
113
114 fn draw_upcast<'a>(
115 _draw: DrawIface<'a, DS>,
116 _ev: &'a mut EventState,
117 _w: &'a mut Self::Window,
118 _cols: &'a ColorsLinear,
119 ) -> Self::Draw<'a> {
120 unimplemented!()
121 }
122
123 fn clear_color(&self) -> color::Rgba {
124 self.themes[self.active].clear_color()
125 }
126}