Files
ltk/tests/layout_stack_spacer.rs

278 lines
8.8 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// Integration coverage for `Stack` alignment / margin / translation and for
// the way `Spacer` distributes leftover space inside a `Column`.
use ltk::core::Canvas;
use ltk::{ stack, spacer, HAlign, VAlign, Rect };
fn make_canvas() -> Canvas
{
Canvas::new( 800, 600 )
}
fn rect( x: f32, y: f32, w: f32, h: f32 ) -> Rect
{
Rect { x, y, width: w, height: h }
}
// ── Stack: alignment ──────────────────────────────────────────────────────────
#[ test ]
fn stack_fill_child_takes_full_rect()
{
let canvas = make_canvas();
let s = stack::<()>().push( spacer().width( 100.0 ).height( 100.0 ) );
let layout = s.layout( rect( 0.0, 0.0, 400.0, 300.0 ), &canvas );
assert_eq!( layout.len(), 1 );
let ( child_rect, _ ) = layout[ 0 ];
// Fill ignores the spacer's preferred size and stretches across the
// entire stack rect.
assert_eq!( child_rect, rect( 0.0, 0.0, 400.0, 300.0 ) );
}
#[ test ]
fn stack_center_centers_child_inside_rect()
{
let canvas = make_canvas();
let child = spacer().width( 100.0 ).height( 50.0 );
let s = stack::<()>().push_aligned( child, HAlign::Center, VAlign::Center );
let layout = s.layout( rect( 0.0, 0.0, 400.0, 300.0 ), &canvas );
let ( child_rect, _ ) = layout[ 0 ];
assert_eq!( child_rect.x, 150.0 );
assert_eq!( child_rect.y, 125.0 );
assert_eq!( child_rect.width, 100.0 );
assert_eq!( child_rect.height, 50.0 );
}
#[ test ]
fn stack_end_bottom_anchors_to_bottom_right()
{
let canvas = make_canvas();
let child = spacer().width( 80.0 ).height( 40.0 );
let s = stack::<()>().push_aligned( child, HAlign::End, VAlign::Bottom );
let layout = s.layout( rect( 0.0, 0.0, 400.0, 300.0 ), &canvas );
let ( child_rect, _ ) = layout[ 0 ];
assert_eq!( child_rect.x, 320.0 );
assert_eq!( child_rect.y, 260.0 );
}
#[ test ]
fn stack_start_top_anchors_to_top_left()
{
let canvas = make_canvas();
let child = spacer().width( 40.0 ).height( 30.0 );
let s = stack::<()>().push_aligned( child, HAlign::Start, VAlign::Top );
let layout = s.layout( rect( 100.0, 50.0, 400.0, 300.0 ), &canvas );
let ( child_rect, _ ) = layout[ 0 ];
assert_eq!( child_rect.x, 100.0 );
assert_eq!( child_rect.y, 50.0 );
}
// ── Stack: margin ─────────────────────────────────────────────────────────────
#[ test ]
fn stack_margin_insets_fill_child_on_all_sides()
{
let canvas = make_canvas();
let child = spacer().width( 50.0 ).height( 50.0 );
let s = stack::<()>()
.push_aligned_margin( child, HAlign::Fill, VAlign::Fill, 12.0 );
let layout = s.layout( rect( 0.0, 0.0, 400.0, 300.0 ), &canvas );
let ( child_rect, _ ) = layout[ 0 ];
// Fill + margin = original rect inset on every side.
assert_eq!( child_rect, rect( 12.0, 12.0, 376.0, 276.0 ) );
}
#[ test ]
fn stack_margin_pushes_end_anchored_child_inward()
{
let canvas = make_canvas();
let child = spacer().width( 50.0 ).height( 50.0 );
let s = stack::<()>()
.push_aligned_margin( child, HAlign::End, VAlign::Top, 8.0 );
let layout = s.layout( rect( 0.0, 0.0, 400.0, 300.0 ), &canvas );
let ( child_rect, _ ) = layout[ 0 ];
// 400 - 50 - 8 = 342 from left edge; y starts at 8.
assert_eq!( child_rect.x, 342.0 );
assert_eq!( child_rect.y, 8.0 );
}
#[ test ]
fn stack_margin_larger_than_half_rect_clamps_inner_to_zero()
{
let canvas = make_canvas();
let child = spacer().width( 10.0 ).height( 10.0 );
let s = stack::<()>()
.push_aligned_margin( child, HAlign::Fill, VAlign::Fill, 200.0 );
// Stack rect is 100×100; margin 200 → inner is clamped to (0, 0).
let layout = s.layout( rect( 0.0, 0.0, 100.0, 100.0 ), &canvas );
let ( child_rect, _ ) = layout[ 0 ];
assert_eq!( child_rect.width, 0.0 );
assert_eq!( child_rect.height, 0.0 );
}
// ── Stack: translation ────────────────────────────────────────────────────────
#[ test ]
fn stack_translation_offsets_child_after_alignment()
{
let canvas = make_canvas();
let child = spacer().width( 40.0 ).height( 30.0 );
let s = stack::<()>()
.push_translated( child, HAlign::Start, VAlign::Top, 5.0, 7.0 );
let layout = s.layout( rect( 0.0, 0.0, 400.0, 300.0 ), &canvas );
let ( child_rect, _ ) = layout[ 0 ];
assert_eq!( child_rect.x, 5.0 );
assert_eq!( child_rect.y, 7.0 );
}
// ── Stack: order ─────────────────────────────────────────────────────────────
#[ test ]
fn stack_layout_preserves_child_order()
{
let canvas = make_canvas();
let s = stack::<()>()
.push( spacer().width( 10.0 ).height( 10.0 ) )
.push( spacer().width( 20.0 ).height( 20.0 ) )
.push( spacer().width( 30.0 ).height( 30.0 ) );
let layout = s.layout( rect( 0.0, 0.0, 400.0, 300.0 ), &canvas );
assert_eq!( layout.len(), 3 );
assert_eq!( layout[ 0 ].1, 0 );
assert_eq!( layout[ 1 ].1, 1 );
assert_eq!( layout[ 2 ].1, 2 );
}
// ── Stack: preferred_size ─────────────────────────────────────────────────────
#[ test ]
fn stack_preferred_size_returns_max_child_height()
{
let canvas = make_canvas();
let s = stack::<()>()
.push( spacer().width( 40.0 ).height( 30.0 ) )
.push( spacer().width( 60.0 ).height( 80.0 ) );
let ( w, h ) = s.preferred_size( 400.0, &canvas );
// Stack always reports `max_width` for width, and the tallest child for
// height — Stack is meant for overlaying, not flow.
assert_eq!( w, 400.0 );
assert_eq!( h, 80.0 );
}
#[ test ]
fn stack_empty_preferred_size_height_is_zero()
{
let canvas = make_canvas();
let s: ltk::Stack<()> = stack();
let ( _, h ) = s.preferred_size( 400.0, &canvas );
assert_eq!( h, 0.0 );
}
// ── Spacer: builder semantics ─────────────────────────────────────────────────
#[ test ]
fn spacer_default_has_weight_one_and_no_fixed_size()
{
let s = spacer();
assert_eq!( s.weight, 1 );
assert!( s.fixed_height.is_none() );
assert!( s.fixed_width.is_none() );
assert_eq!( s.preferred_size(), ( 0.0, 0.0 ) );
}
#[ test ]
fn spacer_height_pins_vertical_axis_only()
{
let s = spacer().height( 24.0 );
assert_eq!( s.fixed_height, Some( 24.0 ) );
assert!( s.fixed_width.is_none() );
assert_eq!( s.preferred_size(), ( 0.0, 24.0 ) );
}
#[ test ]
fn spacer_width_pins_horizontal_axis_only()
{
let s = spacer().width( 12.0 );
assert_eq!( s.fixed_width, Some( 12.0 ) );
assert!( s.fixed_height.is_none() );
assert_eq!( s.preferred_size(), ( 12.0, 0.0 ) );
}
#[ test ]
fn spacer_weight_replaces_default()
{
let s = spacer().weight( 5 );
assert_eq!( s.weight, 5 );
}
// ── Spacer in Column: leftover distribution ───────────────────────────────────
// These use `column().layout(...)` directly (Column re-exports its `layout()`
// method as `pub`). Fixed-height children consume known space; flexible spacers
// must absorb the rest.
#[ test ]
fn flexible_spacer_in_column_consumes_leftover_height()
{
use ltk::column;
let canvas = make_canvas();
let col = column::<()>()
.padding( 0.0 )
.spacing( 0.0 )
.push( spacer().width( 50.0 ).height( 100.0 ) )
.push( spacer() ) // flexible
.push( spacer().width( 50.0 ).height( 100.0 ) );
let layout = col.layout( rect( 0.0, 0.0, 200.0, 500.0 ), &canvas );
assert_eq!( layout.len(), 3 );
// Two fixed children of 100 each + one spacer absorbing the leftover 300.
assert!( ( layout[ 0 ].0.height - 100.0 ).abs() < 1e-3 );
assert!( ( layout[ 1 ].0.height - 300.0 ).abs() < 1e-3 );
assert!( ( layout[ 2 ].0.height - 100.0 ).abs() < 1e-3 );
}
#[ test ]
fn weighted_spacers_split_leftover_proportionally()
{
use ltk::column;
let canvas = make_canvas();
let col = column::<()>()
.padding( 0.0 )
.spacing( 0.0 )
.push( spacer().weight( 1 ) )
.push( spacer().weight( 3 ) );
let layout = col.layout( rect( 0.0, 0.0, 200.0, 400.0 ), &canvas );
// Total weight 4; leftover 400; weight 1 → 100, weight 3 → 300.
assert!( ( layout[ 0 ].0.height - 100.0 ).abs() < 1e-3 );
assert!( ( layout[ 1 ].0.height - 300.0 ).abs() < 1e-3 );
}
#[ test ]
fn fixed_height_spacer_does_not_consume_leftover()
{
use ltk::column;
let canvas = make_canvas();
let col = column::<()>()
.padding( 0.0 )
.spacing( 0.0 )
.push( spacer().height( 50.0 ) ) // fixed — keeps its 50 px
.push( spacer() ); // flexible — absorbs the rest
let layout = col.layout( rect( 0.0, 0.0, 200.0, 500.0 ), &canvas );
assert!( ( layout[ 0 ].0.height - 50.0 ).abs() < 1e-3 );
assert!( ( layout[ 1 ].0.height - 450.0 ).abs() < 1e-3 );
}