buoyant 0.5.0

SwiftUI-like UIs in Rust for embedded devices
Documentation
use crate::primitives::{Interpolate as _, Point};

use super::{AnimatedJoin, AnimationDomain};

#[non_exhaustive]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct Image<'a, T> {
    pub origin: Point,
    pub image: &'a T,
}

impl<'a, T> Image<'a, T> {
    pub const fn new(origin: Point, image: &'a T) -> Self {
        Self { origin, image }
    }
}

impl<T> AnimatedJoin for Image<'_, T> {
    fn join(source: Self, target: Self, domain: &AnimationDomain) -> Self {
        Self {
            origin: Point::interpolate(source.origin, target.origin, domain.factor),
            image: source.image,
        }
    }
}

// This is an implementation that uses the more generic brush
//
// use crate::primitives::geometry::Rectangle;
// use crate::render_target::{Brush, ImageBrush, RenderTarget};
// impl<C: From<<I as Brush>::ColorFormat>, I: ImageBrush> Render<C> for Image<'_, I> {
//     fn render(
//         &self,
//         render_target: &mut impl RenderTarget<ColorFormat = C>,
//         _style: &C,
//         offset: crate::primitives::Point,
//     ) {
//         let origin = self.origin + offset;
//         let rectangle = Rectangle::new(Point::new(0, 0), self.image.size());
//         render_target.fill(origin, self.image, None, &rectangle);
//     }
//
//     fn render_animated(
//         render_target: &mut impl RenderTarget<ColorFormat = C>,
//         source: &Self,
//         target: &Self,
//         _style: &C,
//         offset: crate::primitives::Point,
//         domain: &super::AnimationDomain,
//     ) {
//         let origin = offset + Point::interpolate(source.origin, target.origin, domain.factor);
//         let rectangle = Rectangle::new(Point::new(0, 0), target.image.size());
//         render_target.fill(origin, target.image, None, &rectangle);
//     }
// }

#[cfg(feature = "embedded-graphics")]
mod embedded_graphics {
    use embedded_graphics::{draw_target::DrawTargetExt, image::ImageDrawable};

    use crate::{
        primitives::{Interpolate as _, Point},
        render::Render,
        render_target::RenderTarget,
        surface::AsDrawTarget,
    };

    use super::Image;
    impl<I: ImageDrawable> Render<I::Color> for Image<'_, I> {
        fn render(
            &self,
            render_target: &mut impl RenderTarget<ColorFormat = I::Color>,
            _style: &I::Color,
            offset: crate::primitives::Point,
        ) {
            // TODO: Only render a sub-image if the image is clipped?
            let origin = self.origin + offset;
            _ = self.image.draw(
                &mut render_target
                    .raw_surface()
                    .draw_target()
                    .translated(origin.into()),
            );
        }

        fn render_animated(
            render_target: &mut impl RenderTarget<ColorFormat = I::Color>,
            source: &Self,
            target: &Self,
            style: &I::Color,
            offset: crate::primitives::Point,
            domain: &super::AnimationDomain,
        ) {
            let origin = offset + Point::interpolate(source.origin, target.origin, domain.factor);
            if domain.factor == 0 {
                source.render(render_target, style, origin);
            } else {
                target.render(render_target, style, origin);
            }
        }
    }
}