faststep 0.1.0

UIKit-inspired embedded UI framework built on embedded-graphics
Documentation
use embedded_graphics::{
    draw_target::{DrawTarget, DrawTargetExt},
    pixelcolor::Rgb565,
    prelude::Point,
    primitives::Rectangle,
};

use crate::Layer;

use super::{StackMotion, UiApp, ViewDelegate};

impl<'a, ViewId, Delegate, const STACK_DEPTH: usize> UiApp<'a, ViewId, Delegate, STACK_DEPTH>
where
    ViewId: Copy,
    Delegate: ViewDelegate<'a, ViewId>,
{
    /// Draws the full compatibility UI.
    pub fn draw<D>(&self, display: &mut D, bounds: Rectangle)
    where
        D: DrawTarget<Color = Rgb565>,
    {
        let nav = self.nav_view(bounds);
        nav.draw_chrome(display, &self.theme, &self.i18n, &self.nav_touch);
        self.draw_layer(display, nav.layers.base);
        if let Some(overlay) = nav.layers.overlay {
            self.draw_layer(display, overlay);
        }
    }

    /// Draws only interactive chrome and the active view.
    pub fn draw_interactive<D>(&self, display: &mut D, bounds: Rectangle)
    where
        D: DrawTarget<Color = Rgb565>,
    {
        let nav = self.nav_view(bounds);
        nav.draw_chrome(display, &self.theme, &self.i18n, &self.nav_touch);
        self.delegate
            .draw_view(self.stack.top(), display, nav.body, &self.theme, &self.i18n);
    }

    /// Draws only the active view body.
    pub fn draw_active_view<D>(&self, display: &mut D, bounds: Rectangle)
    where
        D: DrawTarget<Color = Rgb565>,
    {
        let nav = self.nav_view(bounds);
        self.delegate
            .draw_view(self.stack.top(), display, nav.body, &self.theme, &self.i18n);
    }

    /// Returns geometry for a stack transition, if one is active.
    pub fn stack_motion(&self, bounds: Rectangle) -> Option<StackMotion> {
        let nav = self.nav_view(bounds);
        nav.layers.overlay.map(|overlay| StackMotion {
            header: nav.header,
            body: nav.body,
            overlay: overlay.translated_frame(),
        })
    }

    /// Draws only the stack-motion header region.
    pub fn draw_stack_motion_header<D>(&self, display: &mut D, bounds: Rectangle)
    where
        D: DrawTarget<Color = Rgb565>,
    {
        self.nav_view(bounds)
            .draw_chrome(display, &self.theme, &self.i18n, &self.nav_touch);
    }

    /// Draws the base layer for a stack transition.
    pub fn draw_stack_motion_base<D>(&self, display: &mut D, bounds: Rectangle)
    where
        D: DrawTarget<Color = Rgb565>,
    {
        self.draw_layer(display, self.nav_view(bounds).layers.base);
    }

    /// Draws the overlay layer for a stack transition.
    pub fn draw_stack_motion_overlay<D>(&self, display: &mut D, bounds: Rectangle)
    where
        D: DrawTarget<Color = Rgb565>,
    {
        if let Some(overlay) = self.nav_view(bounds).layers.overlay {
            self.draw_layer(display, overlay);
        }
    }

    pub(super) fn nav_view(&self, bounds: Rectangle) -> crate::NavView<'a, ViewId> {
        self.stack
            .nav_view(bounds, |view| self.delegate.title(view))
    }

    pub(super) fn draw_layer<D>(&self, display: &mut D, layer: Layer<ViewId>)
    where
        D: DrawTarget<Color = Rgb565>,
    {
        if layer.offset == Point::zero() {
            self.delegate.draw_layer(
                layer.key,
                display,
                layer.frame,
                false,
                &self.theme,
                &self.i18n,
            );
            return;
        }

        let mut translated = display.translated(layer.offset);
        let mut clipped = translated.clipped(&layer.frame);
        self.delegate.draw_layer(
            layer.key,
            &mut clipped,
            layer.frame,
            true,
            &self.theme,
            &self.i18n,
        );
    }
}