anathema-default-widgets 0.2.2

Default widget implementations for Anathema
Documentation
use std::ops::ControlFlow;

use anathema_geometry::Size;
use anathema_value_resolver::AttributeStorage;
use anathema_widgets::error::Result;
use anathema_widgets::layout::{Constraints, LayoutCtx, PositionCtx};
use anathema_widgets::paint::{PaintCtx, SizePos};
use anathema_widgets::{LayoutForEach, PaintChildren, PositionChildren, Widget, WidgetId};

use super::Stack;
use crate::layout::Axis;

pub struct VStack(Stack);

impl Default for VStack {
    fn default() -> Self {
        VStack(Stack(Axis::Vertical))
    }
}

impl Widget for VStack {
    fn layout<'bp>(
        &mut self,
        children: LayoutForEach<'_, 'bp>,
        constraints: Constraints,
        id: WidgetId,
        ctx: &mut LayoutCtx<'_, 'bp>,
    ) -> Result<Size> {
        self.0.layout(children, constraints, id, ctx)
    }

    fn position<'bp>(
        &mut self,
        children: PositionChildren<'_, 'bp>,
        attributes: WidgetId,
        attribute_storage: &AttributeStorage<'bp>,
        ctx: PositionCtx,
    ) {
        self.0.position(children, attributes, attribute_storage, ctx)
    }

    fn paint<'bp>(
        &mut self,
        mut children: PaintChildren<'_, 'bp>,
        _id: WidgetId,
        attribute_storage: &AttributeStorage<'bp>,
        mut ctx: PaintCtx<'_, SizePos>,
    ) {
        _ = children.each(|child, children| {
            let ctx = ctx.to_unsized();
            child.paint(children, ctx, attribute_storage);
            ControlFlow::Continue(())
        });
    }
}

#[cfg(test)]
mod test {

    use crate::testing::TestRunner;

    #[test]
    fn vstack() {
        let tpl = "
            vstack
                border
                    text state.value
                for i in [2]
                    border
                        text i
        ";

        let expected_first = "
            ╔═══╗
            ║┌─┐║
            ║│0│║
            ║└─┘║
            ║┌─┐║
            ║│2│║
            ║└─┘║
            ╚═══╝
        ";

        let expected_second = "
            ╔═══╗
            ║┌─┐║
            ║│7│║
            ║└─┘║
            ║┌─┐║
            ║│2│║
            ║└─┘║
            ╚═══╝
        ";

        TestRunner::new(tpl, (3, 6))
            .instance()
            .render_assert(expected_first)
            .with_state(|state| *state.value.to_mut() = 7)
            .render_assert(expected_second);
    }

    #[test]
    fn fixed_height() {
        let tpl = "
            vstack [height: 2]
                for i in [0, 1]
                    border
                        text i
        ";

        let expected = "
            ╔══╗
            ║┌┐║
            ║└┘║
            ╚══╝
        ";

        TestRunner::new(tpl, (2, 2)).instance().render_assert(expected);
    }

    #[test]
    fn fixed_width() {
        let tpl = "
            vstack [width: 7, height: 3]
                border
                    expand
                        text 'a'
        ";

        let expected = "
            ╔═══════╗
            ║┌─────┐║
            ║│a    │║
            ║└─────┘║
            ╚═══════╝
        ";

        TestRunner::new(tpl, (7, 3)).instance().render_assert(expected);
    }

    #[test]
    fn bottom_up_vstack() {
        let tpl = "
            vstack [direction: 'back']
                text 'b'
                border
                    text 'a'
        ";

        let expected = "
            ╔══════╗
            ║      ║
            ║┌─┐   ║
            ║│a│   ║
            ║└─┘   ║
            ║b     ║
            ╚══════╝
        ";

        TestRunner::new(tpl, (6, 5)).instance().render_assert(expected);
    }

    #[test]
    fn vstack_overflow() {
        let tpl = "
            vstack
                text 'a'
                text 'b'
                text 'c'
                text 'd'
        ";

        let expected = "
            ╔══════╗
            ║a     ║
            ║b     ║
            ╚══════╝
        ";

        let mut runner = TestRunner::new(tpl, (6, 2));
        let mut runner = runner.instance();
        runner.render_assert(expected);
    }
}