mix 0.2.1

mix - a rust ui library cooked up in half a day! (expect extra salt)
use crate::platform::math::Vec2;
use crate::draw::layout::{Layout, LayoutDirection, LayoutAlign};
use crate::draw::rect::Rect;

#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Walk {
    Size(Vec2),
    Compute,
}

impl Walk {
    pub fn size(&self) -> Option<Vec2> {
        match self {
            Walk::Size(size) => Some(*size),
            Walk::Compute => None,
        }
    }

    pub fn width(&self) -> Option<f32> {
        self.size().map(|s| s.x)
    }

    pub fn height(&self) -> Option<f32> {
        self.size().map(|s| s.y)
    }
}

#[derive(Clone, Debug)]
pub struct Turtle {
    pub rect: Rect,
    pub layout: Layout,
    pub items: Vec<TurtleItem>,
}

#[derive(Clone, Debug)]
pub struct TurtleItem {
    pub rect: Rect,
    pub align_self: Option<LayoutAlign>,
}

impl Turtle {
    pub fn new(rect: Rect, layout: Layout) -> Self {
        Self {
            rect,
            layout,
            items: Vec::new(),
        }
    }

    pub fn add_item(&mut self, size: Vec2, align_self: Option<LayoutAlign>) -> Rect {
        let rect: Rect;

        match self.layout.direction {
            LayoutDirection::Horizontal => {
                let x = if self.items.is_empty() {
                    self.rect.pos.x + self.layout.padding.x
                } else {
                    let last_item = self.items.last().unwrap();
                    last_item.rect.right() + self.layout.spacing
                };

                let align = align_self.unwrap_or(self.layout.align_items);
                let y = self.rect.pos.y + self.layout.padding.y + align.resolve(
                    self.rect.height() - self.layout.padding.y * 2.0,
                    size.y
                );

                rect = Rect::new(x, y, size.x, size.y);
            },
            LayoutDirection::Vertical => {
                let y = if self.items.is_empty() {
                    self.rect.pos.y + self.layout.padding.y
                } else {
                    let last_item = self.items.last().unwrap();
                    last_item.rect.bottom() + self.layout.spacing
                };

                let align = align_self.unwrap_or(self.layout.align_items);
                let x = self.rect.pos.x + self.layout.padding.x + align.resolve(
                    self.rect.width() - self.layout.padding.x * 2.0,
                    size.x
                );

                rect = Rect::new(x, y, size.x, size.y);
            },
        }

        self.items.push(TurtleItem {
            rect,
            align_self,
        });

        rect
    }

    pub fn compute_content_size(&self) -> Vec2 {
        if self.items.is_empty() {
            return Vec2::zero();
        }

        match self.layout.direction {
            LayoutDirection::Horizontal => {
                let mut width: f32 = 0.0;
                let mut height: f32 = 0.0;

                for (i, item) in self.items.iter().enumerate() {
                    width += item.rect.width();
                    if i < self.items.len() - 1 {
                        width += self.layout.spacing;
                    }
                    height = height.max(item.rect.height());
                }

                Vec2::new(
                    width + self.layout.padding.x * 2.0,
                    height + self.layout.padding.y * 2.0,
                )
            },
            LayoutDirection::Vertical => {
                let mut width: f32 = 0.0;
                let mut height: f32 = 0.0;

                for (i, item) in self.items.iter().enumerate() {
                    height += item.rect.height();
                    if i < self.items.len() - 1 {
                        height += self.layout.spacing;
                    }
                    width = width.max(item.rect.width());
                }

                Vec2::new(
                    width + self.layout.padding.x * 2.0,
                    height + self.layout.padding.y * 2.0,
                )
            },
        }
    }
}