cascada 0.3.1

A general purpose UI layout engine
Documentation
use cascada::{
    BlockLayout, BoxSizing, EmptyLayout, HorizontalLayout, IntrinsicSize, Layout, Padding, Size,
    solve_layout,
};

#[test]
fn horizontal_layout() {
    let window = Size::new(800.0, 800.0);
    let child_1 = HorizontalLayout::new().intrinsic_size(IntrinsicSize::fixed(400.0, 200.0));
    let child_2 = HorizontalLayout::new().intrinsic_size(IntrinsicSize::fixed(500.0, 350.0));
    let mut root = HorizontalLayout::new()
        .add_child(child_1)
        .add_child(child_2);

    solve_layout(&mut root, window);

    assert_eq!(root.size(), Size::new(900.0, 350.0));

    assert_eq!(root.children()[0].size(), Size::new(400.0, 200.0));

    assert_eq!(root.children()[1].size(), Size::new(500.0, 350.0));
}

#[test]
fn horizontal_and_empty_layout() {
    let window = Size::new(1000.0, 1000.0);

    let child_1 = EmptyLayout::new().intrinsic_size(IntrinsicSize {
        width: BoxSizing::Fixed(250.0),
        height: BoxSizing::Flex(1),
    });

    let child_2 = EmptyLayout::new().intrinsic_size(IntrinsicSize {
        width: BoxSizing::Flex(1),
        height: BoxSizing::Fixed(20.0),
    });

    let child_3 = EmptyLayout::new().intrinsic_size(IntrinsicSize {
        height: BoxSizing::Fixed(250.0),
        ..Default::default()
    });

    let mut root = HorizontalLayout::new().add_children([child_1, child_2, child_3]);

    solve_layout(&mut root, window);

    assert_eq!(root.size(), Size::new(250.0, 250.0));
    assert_eq!(root.children()[0].size(), Size::new(250.0, 250.0));
    assert_eq!(root.children()[1].size(), Size::new(0.0, 20.0));
    assert_eq!(root.children()[2].size(), Size::new(0.0, 250.0));
}

#[test]
fn test_flex_sizing() {
    let window = Size::new(800.0, 800.0);
    let child = HorizontalLayout::new().intrinsic_size(IntrinsicSize::fill());
    let child_2 = HorizontalLayout::new().intrinsic_size(IntrinsicSize::fill());
    let mut root = HorizontalLayout::new()
        .intrinsic_size(IntrinsicSize::fill())
        .add_children([child, child_2]);

    solve_layout(&mut root, window);
    let child_size = Size::new(400.0, 800.0);
    assert_eq!(root.size(), window);
    assert_eq!(root.children()[0].size(), child_size);
    assert_eq!(root.children()[1].size(), child_size);
}

#[test]
fn flex_with_shrink() {
    let window = Size::new(800.0, 800.0);
    let padding = Padding::all(24.0);
    let spacing = 45;

    let inner_child = EmptyLayout::new().intrinsic_size(IntrinsicSize::fixed(250.0, 250.0));

    let block = BlockLayout::new(inner_child).padding(padding);

    let empty = EmptyLayout::new().intrinsic_size(IntrinsicSize::fill());

    let mut root = HorizontalLayout::new()
        .padding(padding)
        .spacing(spacing)
        .intrinsic_size(IntrinsicSize {
            width: BoxSizing::Flex(1),
            height: BoxSizing::Shrink,
        })
        .add_child(block)
        .add_child(empty);

    solve_layout(&mut root, window);

    let mut child_1_size = Size::new(250.0, 250.0);
    child_1_size.width += padding.horizontal_sum();
    child_1_size.height += padding.vertical_sum();

    let mut root_size = Size::new(window.width, child_1_size.height);
    root_size.height += padding.vertical_sum(); // Add the padding for child_1 and for the root

    let mut empty_size = Size::new(window.width, child_1_size.height);
    empty_size.width -= child_1_size.width;
    empty_size.width -= spacing as f32;
    empty_size.width -= padding.horizontal_sum();
    empty_size.height += padding.vertical_sum();

    let empty = &root.children()[1];
    assert_eq!(root.size(), root_size);
    assert_eq!(empty.size(), empty_size);
    assert_eq!(root.children()[0].size(), child_1_size);
}

#[test]
fn flex_with_fixed() {
    let window = Size::new(800.0, 800.0);
    let padding = Padding::all(24.0);
    let spacing = 45;

    let child_1 = EmptyLayout::new().intrinsic_size(IntrinsicSize::fixed(250.0, 250.0));

    let child_2 = EmptyLayout::new().intrinsic_size(IntrinsicSize {
        width: BoxSizing::Flex(1),
        height: BoxSizing::Flex(2),
    });

    let child_3 = EmptyLayout::new().intrinsic_size(IntrinsicSize::flex(4));

    let mut root = HorizontalLayout::new()
        .padding(padding)
        .spacing(spacing)
        .intrinsic_size(IntrinsicSize::fill())
        .add_children([child_1, child_2, child_3]);

    solve_layout(&mut root, window);

    let mut space = window;
    space.width -= spacing as f32 * 2.0;
    space.width -= padding.horizontal_sum();
    space.height -= padding.vertical_sum();
    space.width -= 250.0;

    assert_eq!(
        root.children()[1].size().height,
        window.height - padding.vertical_sum()
    );
    assert_eq!(root.children()[2].size().width, 4.0 / 5.0 * space.width);
    assert_eq!(root.children()[1].size().width, 1.0 / 5.0 * space.width);
}

#[test]
fn flex_factor() {
    let window = Size::new(800.0, 400.0);
    let child_node_1 = HorizontalLayout::new().intrinsic_size(IntrinsicSize::flex(1));
    let child_node_2 = HorizontalLayout::new().intrinsic_size(IntrinsicSize::flex(3));

    let mut node = HorizontalLayout::new()
        .intrinsic_size(IntrinsicSize::fill())
        .add_child(child_node_1)
        .add_child(child_node_2);

    solve_layout(&mut node, window);

    let flex_1_width = 1.0 / 4.0 * window.width;
    assert_eq!(node.children()[0].size().width, flex_1_width);
    assert_eq!(node.children()[0].size().height, 400.0);
    assert_eq!(
        node.children()[0].size().height,
        node.children()[1].size().height,
    );
    assert_eq!(
        node.children()[1].size().width,
        3.0 * node.children()[0].size().width
    );
    assert_ne!(
        node.children()[1].size().height,
        3.0 * node.children()[0].size().height
    );
}

#[test]
fn from_iter() {
    let layouts = [EmptyLayout::new(), EmptyLayout::new()];

    let layout = HorizontalLayout::from(layouts);
    assert_eq!(layout.children().len(), 2);
}