use super::{ColorsLinear, Theme, ThemeDst, Window};
use crate::config::{Config, WindowConfig};
use crate::draw::{DrawIface, DrawSharedImpl, color};
use crate::event::EventState;
use crate::theme::ThemeDraw;
use std::cell::RefCell;
use std::collections::HashMap;
type DynTheme<DS> = Box<dyn ThemeDst<DS>>;
pub struct MultiTheme<DS> {
names: HashMap<String, usize>,
themes: Vec<DynTheme<DS>>,
active: usize,
}
impl<DS> MultiTheme<DS> {
#[allow(clippy::new_without_default)]
pub fn new() -> MultiTheme<DS> {
MultiTheme {
names: HashMap::new(),
themes: vec![],
active: 0,
}
}
pub fn add<S: ToString, T>(&mut self, name: S, theme: T) -> usize
where
DS: DrawSharedImpl,
T: ThemeDst<DS> + 'static,
{
let index = self.themes.len();
self.names.insert(name.to_string(), index);
self.themes.push(Box::new(theme));
index
}
pub fn set_active(&mut self, index: usize) {
self.active = index;
}
}
impl<DS: DrawSharedImpl> Theme<DS> for MultiTheme<DS> {
type Window = Box<dyn Window>;
type Draw<'a> = Box<dyn ThemeDraw + 'a>;
fn init(&mut self, config: &RefCell<Config>) {
if self.active >= self.themes.len() {
panic!(
"MultiTheme: invalid index {} in list of {} themes added",
self.active,
self.themes.len()
);
}
if config.borrow().theme.active_theme.is_empty() {
for (name, index) in &self.names {
if *index == self.active {
let _ = config.borrow_mut().theme.set_active_theme(name.to_string());
break;
}
}
}
for theme in &mut self.themes {
theme.init(config);
}
}
fn new_window(&mut self, config: &WindowConfig) -> Self::Window {
let theme = &config.theme().active_theme;
if let Some(index) = self.names.get(theme).cloned()
&& index != self.active
{
self.active = index;
}
self.themes[self.active].new_window(config)
}
fn update_window(&mut self, window: &mut Self::Window, config: &WindowConfig) -> bool {
self.themes[self.active].update_window(window, config)
}
fn draw<'a>(
&'a self,
draw: DrawIface<'a, DS>,
ev: &'a mut EventState,
window: &'a mut Self::Window,
) -> Box<dyn ThemeDraw + 'a> {
self.themes[self.active].draw(draw, ev, window)
}
fn draw_upcast<'a>(
_draw: DrawIface<'a, DS>,
_ev: &'a mut EventState,
_w: &'a mut Self::Window,
_cols: &'a ColorsLinear,
) -> Self::Draw<'a> {
unimplemented!()
}
fn clear_color(&self) -> color::Rgba {
self.themes[self.active].clear_color()
}
}