kas_theme/
theme_dst.rs

1// Licensed under the Apache License, Version 2.0 (the "License");
2// you may not use this file except in compliance with the License.
3// You may obtain a copy of the License in the LICENSE-APACHE file or at:
4//     https://www.apache.org/licenses/LICENSE-2.0
5
6//! Stack-DST versions of theme traits
7
8use std::any::Any;
9use std::borrow::Cow;
10use std::ops::{Deref, DerefMut};
11
12use super::{Theme, Window};
13use kas::draw::{color, DrawIface, DrawSharedImpl, SharedState};
14use kas::event::EventState;
15use kas::theme::{ThemeControl, ThemeDraw, ThemeSize};
16use kas::TkAction;
17
18/// An optionally-owning (boxed) reference
19///
20/// This is related but not identical to [`Cow`].
21pub enum MaybeBoxed<'a, B: 'a + ?Sized> {
22    Borrowed(&'a B),
23    Boxed(Box<B>),
24}
25
26impl<T: ?Sized> AsRef<T> for MaybeBoxed<'_, T> {
27    fn as_ref(&self) -> &T {
28        match self {
29            MaybeBoxed::Borrowed(r) => r,
30            MaybeBoxed::Boxed(b) => b.as_ref(),
31        }
32    }
33}
34
35/// As [`Theme`], but without associated types
36///
37/// This trait is implemented automatically for all implementations of
38/// [`Theme`]. It is intended only for use where a less parameterised
39/// trait is required.
40pub trait ThemeDst<DS: DrawSharedImpl>: ThemeControl {
41    /// Get current configuration
42    fn config(&self) -> MaybeBoxed<dyn Any>;
43
44    /// Apply/set the passed config
45    fn apply_config(&mut self, config: &dyn Any) -> TkAction;
46
47    /// Theme initialisation
48    ///
49    /// See also [`Theme::init`].
50    fn init(&mut self, shared: &mut SharedState<DS>);
51
52    /// Construct per-window storage
53    ///
54    /// See also [`Theme::new_window`].
55    fn new_window(&self, dpi_factor: f32) -> Box<dyn Window>;
56
57    /// Update a window created by [`Theme::new_window`]
58    ///
59    /// See also [`Theme::update_window`].
60    fn update_window(&self, window: &mut dyn Window, dpi_factor: f32);
61
62    fn draw<'a>(
63        &'a self,
64        draw: DrawIface<'a, DS>,
65        ev: &'a mut EventState,
66        window: &'a mut dyn Window,
67    ) -> Box<dyn ThemeDraw + 'a>;
68
69    /// Background colour
70    ///
71    /// See also [`Theme::clear_color`].
72    fn clear_color(&self) -> color::Rgba;
73}
74
75impl<DS: DrawSharedImpl, T: Theme<DS>> ThemeDst<DS> for T {
76    fn config(&self) -> MaybeBoxed<dyn Any> {
77        match self.config() {
78            Cow::Borrowed(config) => MaybeBoxed::Borrowed(config),
79            Cow::Owned(config) => MaybeBoxed::Boxed(Box::new(config)),
80        }
81    }
82
83    fn apply_config(&mut self, config: &dyn Any) -> TkAction {
84        self.apply_config(config.downcast_ref().unwrap())
85    }
86
87    fn init(&mut self, shared: &mut SharedState<DS>) {
88        self.init(shared);
89    }
90
91    fn new_window(&self, dpi_factor: f32) -> Box<dyn Window> {
92        let window = <T as Theme<DS>>::new_window(self, dpi_factor);
93        Box::new(window)
94    }
95
96    fn update_window(&self, window: &mut dyn Window, dpi_factor: f32) {
97        let window = window.as_any_mut().downcast_mut().unwrap();
98        self.update_window(window, dpi_factor);
99    }
100
101    fn draw<'b>(
102        &'b self,
103        draw: DrawIface<'b, DS>,
104        ev: &'b mut EventState,
105        window: &'b mut dyn Window,
106    ) -> Box<dyn ThemeDraw + 'b> {
107        let window = window.as_any_mut().downcast_mut().unwrap();
108        Box::new(<T as Theme<DS>>::draw(self, draw, ev, window))
109    }
110
111    fn clear_color(&self) -> color::Rgba {
112        self.clear_color()
113    }
114}
115
116impl Window for Box<dyn Window> {
117    fn size(&self) -> &dyn ThemeSize {
118        self.deref().size()
119    }
120
121    fn as_any_mut(&mut self) -> &mut dyn Any {
122        self.deref_mut().as_any_mut()
123    }
124}