1use super::layout::Bounds;
2use super::{CharmResult, Color};
3
4#[derive(Clone, Copy)]
5pub struct RenderCtx {
6 pub(crate) bounds: Bounds,
7}
8
9pub struct Renderer<'a> {
10 pub(crate) canvas: &'a mut sdl2::render::WindowCanvas,
11}
12
13impl<'a> Renderer<'a> {
14 pub fn fill_rect(
15 &mut self,
16 bounds: impl Into<Bounds>,
17 color: impl Into<Color>,
18 ) -> CharmResult<()> {
19 let bounds = bounds.into();
20 let color = color.into();
21
22 self.canvas.set_draw_color(color);
23 self.canvas
24 .fill_rect(sdl2::rect::Rect::new(
25 bounds.x as i32,
26 bounds.y as i32,
27 bounds.width as u32,
28 bounds.height as u32,
29 ))
30 .unwrap();
31
32 Ok(())
33 }
34}
35
36pub trait Component<Store> {
37 fn render<'a>(
38 &self,
39 ctx: RenderCtx,
40 renderer: &mut Renderer<'a>,
41 store: &Store,
42 ) -> CharmResult<Bounds>;
43}
44
45pub struct Parameter<T, Store> {
46 thunk: Box<dyn Fn(&Store) -> T>,
47}
48
49impl<T, Store> Parameter<T, Store> {
50 pub fn constant(constant: impl Into<T>) -> Self
51 where
52 T: 'static + Clone,
53 {
54 let constant = constant.into();
55 let thunk = move |_: &Store| constant.clone();
56
57 Self {
58 thunk: Box::new(thunk),
59 }
60 }
61
62 pub fn closure<O>(thunk: impl Fn(&Store) -> O + 'static) -> Self
63 where
64 O: Into<T>,
65 {
66 Self {
67 thunk: Box::new(move |store| thunk(store).into()),
68 }
69 }
70
71 pub(crate) fn resolve(&self, store: &Store) -> T {
72 (self.thunk)(store)
73 }
74}
75
76pub trait IntoParameter<P, Store> {
77 fn into_parameter(self) -> Parameter<P, Store>;
78}
79
80impl<P, Store> IntoParameter<P, Store> for P
81where
82 P: Clone + 'static,
83{
84 fn into_parameter(self) -> Parameter<P, Store> {
85 Parameter::constant(self)
86 }
87}
88
89impl<P, Store> IntoParameter<P, Store> for Parameter<P, Store> {
90 fn into_parameter(self) -> Parameter<P, Store> {
91 self
92 }
93}