charm-ui 0.1.0

an immediate-mode gui library with a friendly API
Documentation
use super::layout::Bounds;
use super::{CharmResult, Color};

#[derive(Clone, Copy)]
pub struct RenderCtx {
    pub(crate) bounds: Bounds,
}

pub struct Renderer<'a> {
    pub(crate) canvas: &'a mut sdl2::render::WindowCanvas,
}

impl<'a> Renderer<'a> {
    pub fn fill_rect(
        &mut self,
        bounds: impl Into<Bounds>,
        color: impl Into<Color>,
    ) -> CharmResult<()> {
        let bounds = bounds.into();
        let color = color.into();

        self.canvas.set_draw_color(color);
        self.canvas
            .fill_rect(sdl2::rect::Rect::new(
                bounds.x as i32,
                bounds.y as i32,
                bounds.width as u32,
                bounds.height as u32,
            ))
            .unwrap();

        Ok(())
    }
}

pub trait Component<Store> {
    fn render<'a>(
        &self,
        ctx: RenderCtx,
        renderer: &mut Renderer<'a>,
        store: &Store,
    ) -> CharmResult<Bounds>;
}

pub struct Parameter<T, Store> {
    thunk: Box<dyn Fn(&Store) -> T>,
}

impl<T, Store> Parameter<T, Store> {
    pub fn constant(constant: impl Into<T>) -> Self
    where
        T: 'static + Clone,
    {
        let constant = constant.into();
        let thunk = move |_: &Store| constant.clone();

        Self {
            thunk: Box::new(thunk),
        }
    }

    pub fn closure<O>(thunk: impl Fn(&Store) -> O + 'static) -> Self
    where
        O: Into<T>,
    {
        Self {
            thunk: Box::new(move |store| thunk(store).into()),
        }
    }

    pub(crate) fn resolve(&self, store: &Store) -> T {
        (self.thunk)(store)
    }
}

pub trait IntoParameter<P, Store> {
    fn into_parameter(self) -> Parameter<P, Store>;
}

impl<P, Store> IntoParameter<P, Store> for P
where
    P: Clone + 'static,
{
    fn into_parameter(self) -> Parameter<P, Store> {
        Parameter::constant(self)
    }
}

impl<P, Store> IntoParameter<P, Store> for Parameter<P, Store> {
    fn into_parameter(self) -> Parameter<P, Store> {
        self
    }
}