use std::collections::HashMap;
#[cfg(feature = "unsize")]
use std::marker::Unsize;
use crate::{StackDst, Theme, ThemeDst, WindowDst};
use kas::draw::{Colour, DrawHandle, DrawShared};
use kas::geom::Rect;
use kas::{string::CowString, ThemeAction, ThemeApi};
#[cfg(feature = "unsize")]
type DynTheme<Draw> = StackDst<dyn ThemeDst<Draw>>;
#[cfg(not(feature = "unsize"))]
type DynTheme<Draw> = Box<dyn ThemeDst<Draw>>;
pub struct MultiTheme<Draw> {
names: HashMap<CowString, usize>,
themes: Vec<DynTheme<Draw>>,
active: usize,
}
pub struct MultiThemeBuilder<Draw> {
names: HashMap<CowString, usize>,
themes: Vec<DynTheme<Draw>>,
}
impl<Draw> MultiTheme<Draw> {
pub fn builder() -> MultiThemeBuilder<Draw> {
MultiThemeBuilder {
names: HashMap::new(),
themes: vec![],
}
}
}
impl<Draw> MultiThemeBuilder<Draw> {
#[cfg(feature = "unsize")]
pub fn add<S: Into<CowString>, U>(mut self, name: S, theme: U) -> Self
where
U: Unsize<dyn ThemeDst<Draw>>,
Box<U>: Unsize<dyn ThemeDst<Draw>>,
{
let index = self.themes.len();
self.names.insert(name.into(), index);
self.themes.push(StackDst::new_or_boxed(theme));
self
}
#[cfg(not(feature = "unsize"))]
pub fn add<S: Into<CowString>, T>(mut self, name: S, theme: T) -> Self
where
Draw: DrawShared,
T: ThemeDst<Draw> + 'static,
{
let index = self.themes.len();
self.names.insert(name.into(), index);
self.themes.push(Box::new(theme));
self
}
pub fn try_build(self) -> Result<MultiTheme<Draw>, ()> {
if self.themes.len() == 0 {
return Err(());
}
Ok(MultiTheme {
names: self.names,
themes: self.themes,
active: 0,
})
}
pub fn build(self) -> MultiTheme<Draw> {
self.try_build()
.unwrap_or_else(|_| panic!("MultiThemeBuilder: no themes added"))
}
}
impl<D: DrawShared + 'static> Theme<D> for MultiTheme<D> {
type Window = StackDst<dyn WindowDst<D::Draw>>;
#[cfg(not(feature = "gat"))]
type DrawHandle = StackDst<dyn DrawHandle>;
#[cfg(feature = "gat")]
type DrawHandle<'a> = StackDst<dyn DrawHandle + 'a>;
fn init(&mut self, draw: &mut D) {
for theme in &mut self.themes {
theme.init(draw);
}
}
fn new_window(&self, draw: &mut D::Draw, dpi_factor: f32) -> Self::Window {
self.themes[self.active].new_window(draw, dpi_factor)
}
fn update_window(&self, window: &mut Self::Window, dpi_factor: f32) {
self.themes[self.active].update_window(window, dpi_factor);
}
#[cfg(not(feature = "gat"))]
unsafe fn draw_handle<'a>(
&'a self,
draw: &'a mut D::Draw,
window: &'a mut Self::Window,
rect: Rect,
) -> StackDst<dyn DrawHandle> {
self.themes[self.active].draw_handle(draw, window, rect)
}
#[cfg(feature = "gat")]
fn draw_handle<'a>(
&'a self,
draw: &'a mut D::Draw,
window: &'a mut Self::Window,
rect: Rect,
) -> StackDst<dyn DrawHandle + 'a> {
self.themes[self.active].draw_handle(draw, window, rect)
}
fn clear_colour(&self) -> Colour {
self.themes[self.active].clear_colour()
}
}
impl<Draw> ThemeApi for MultiTheme<Draw> {
fn set_font_size(&mut self, size: f32) -> ThemeAction {
let mut action = ThemeAction::None;
for theme in &mut self.themes {
action = action.max(theme.set_font_size(size));
}
action
}
fn set_colours(&mut self, scheme: &str) -> ThemeAction {
let mut action = ThemeAction::None;
for theme in &mut self.themes {
action = action.max(theme.set_colours(scheme));
}
action
}
fn set_theme(&mut self, theme: &str) -> ThemeAction {
if let Some(index) = self.names.get(theme).cloned() {
if index != self.active {
self.active = index;
return ThemeAction::ThemeResize;
}
}
ThemeAction::None
}
}