use presentar_core::widget::{AccessibleRole, LayoutResult};
use presentar_core::{
Brick, BrickAssertion, BrickBudget, BrickVerification, Canvas, Constraints, Event, Rect, Size,
TypeId, Widget,
};
use presentar_layout::LayoutEngine;
use std::any::Any;
use std::time::Duration;
struct Box {
min_size: Size,
children: Vec<std::boxed::Box<dyn Widget>>,
}
impl Box {
fn new(width: f32, height: f32) -> Self {
Self {
min_size: Size::new(width, height),
children: Vec::new(),
}
}
fn with_child(mut self, child: impl Widget + 'static) -> Self {
self.children.push(std::boxed::Box::new(child));
self
}
}
impl Brick for Box {
fn brick_name(&self) -> &'static str {
"Box"
}
fn assertions(&self) -> &[BrickAssertion] {
&[]
}
fn budget(&self) -> BrickBudget {
BrickBudget::uniform(16)
}
fn verify(&self) -> BrickVerification {
BrickVerification {
passed: vec![],
failed: vec![],
verification_time: Duration::from_micros(1),
}
}
fn to_html(&self) -> String {
String::new()
}
fn to_css(&self) -> String {
String::new()
}
}
impl Widget for Box {
fn type_id(&self) -> TypeId {
TypeId::of::<Self>()
}
fn measure(&self, constraints: Constraints) -> Size {
constraints.constrain(self.min_size)
}
fn layout(&mut self, bounds: Rect) -> LayoutResult {
LayoutResult {
size: bounds.size(),
}
}
fn paint(&self, _canvas: &mut dyn Canvas) {}
fn event(&mut self, _event: &Event) -> Option<std::boxed::Box<dyn Any + Send>> {
None
}
fn children(&self) -> &[std::boxed::Box<dyn Widget>] {
&self.children
}
fn children_mut(&mut self) -> &mut [std::boxed::Box<dyn Widget>] {
&mut self.children
}
fn accessible_role(&self) -> AccessibleRole {
AccessibleRole::Generic
}
}
#[allow(dead_code)]
struct Flexible {
flex: f32,
children: Vec<std::boxed::Box<dyn Widget>>,
}
impl Flexible {
fn new(flex: f32) -> Self {
Self {
flex,
children: Vec::new(),
}
}
}
impl Brick for Flexible {
fn brick_name(&self) -> &'static str {
"Flexible"
}
fn assertions(&self) -> &[BrickAssertion] {
&[]
}
fn budget(&self) -> BrickBudget {
BrickBudget::uniform(16)
}
fn verify(&self) -> BrickVerification {
BrickVerification {
passed: vec![],
failed: vec![],
verification_time: Duration::from_micros(1),
}
}
fn to_html(&self) -> String {
String::new()
}
fn to_css(&self) -> String {
String::new()
}
}
impl Widget for Flexible {
fn type_id(&self) -> TypeId {
TypeId::of::<Self>()
}
fn measure(&self, constraints: Constraints) -> Size {
constraints.biggest()
}
fn layout(&mut self, bounds: Rect) -> LayoutResult {
LayoutResult {
size: bounds.size(),
}
}
fn paint(&self, _canvas: &mut dyn Canvas) {}
fn event(&mut self, _event: &Event) -> Option<std::boxed::Box<dyn Any + Send>> {
None
}
fn children(&self) -> &[std::boxed::Box<dyn Widget>] {
&self.children
}
fn children_mut(&mut self) -> &mut [std::boxed::Box<dyn Widget>] {
&mut self.children
}
fn accessible_role(&self) -> AccessibleRole {
AccessibleRole::Generic
}
}
#[test]
fn test_layout_single_widget() {
let mut engine = LayoutEngine::new();
let mut widget = Box::new(100.0, 50.0);
let viewport = Size::new(800.0, 600.0);
let tree = engine.compute(&mut widget, viewport);
assert_eq!(tree.widget_count(), 1);
let size = tree.get_size(0).expect("should have size");
assert_eq!(size.width, 100.0);
assert_eq!(size.height, 50.0);
}
#[test]
fn test_layout_widget_tree() {
let mut engine = LayoutEngine::new();
let mut widget = Box::new(400.0, 300.0)
.with_child(Box::new(100.0, 100.0))
.with_child(Box::new(100.0, 100.0))
.with_child(Box::new(100.0, 100.0));
let viewport = Size::new(800.0, 600.0);
let tree = engine.compute(&mut widget, viewport);
assert_eq!(tree.widget_count(), 4);
}
#[test]
fn test_layout_nested_widgets() {
let mut engine = LayoutEngine::new();
let mut widget = Box::new(500.0, 400.0).with_child(
Box::new(300.0, 200.0)
.with_child(Box::new(100.0, 100.0))
.with_child(Box::new(100.0, 100.0)),
);
let viewport = Size::new(800.0, 600.0);
let tree = engine.compute(&mut widget, viewport);
assert_eq!(tree.widget_count(), 4);
}
#[test]
fn test_layout_constrained_by_viewport() {
let mut engine = LayoutEngine::new();
let mut widget = Box::new(1000.0, 800.0);
let viewport = Size::new(400.0, 300.0);
let tree = engine.compute(&mut widget, viewport);
let size = tree.get_size(0).expect("should have size");
assert!(size.width <= viewport.width);
assert!(size.height <= viewport.height);
}
#[test]
fn test_layout_readonly_mode() {
let mut engine = LayoutEngine::new();
let widget = Box::new(200.0, 150.0);
let viewport = Size::new(800.0, 600.0);
let tree = engine.compute_readonly(&widget, viewport);
assert_eq!(tree.widget_count(), 1);
let size = tree.get_size(0).expect("should have size");
assert_eq!(size.width, 200.0);
assert_eq!(size.height, 150.0);
}
#[test]
fn test_layout_cache_clear() {
let mut engine = LayoutEngine::new();
let mut widget = Box::new(100.0, 100.0);
let viewport = Size::new(800.0, 600.0);
engine.compute(&mut widget, viewport);
let (hits1, _misses1) = engine.cache_stats();
engine.clear_cache();
engine.compute(&mut widget, viewport);
let (hits2, _misses2) = engine.cache_stats();
assert_eq!(hits1, 0);
assert_eq!(hits2, 0);
}
#[test]
fn test_layout_positions_at_origin() {
let mut engine = LayoutEngine::new();
let mut widget = Box::new(100.0, 100.0);
let viewport = Size::new(800.0, 600.0);
let tree = engine.compute(&mut widget, viewport);
let pos = tree.get_position(0).expect("should have position");
assert_eq!(pos.x, 0.0);
assert_eq!(pos.y, 0.0);
}
#[test]
fn test_layout_deep_nesting() {
let mut engine = LayoutEngine::new();
let mut widget = Box::new(500.0, 500.0).with_child(
Box::new(400.0, 400.0).with_child(
Box::new(300.0, 300.0)
.with_child(Box::new(200.0, 200.0).with_child(Box::new(100.0, 100.0))),
),
);
let viewport = Size::new(800.0, 600.0);
let tree = engine.compute(&mut widget, viewport);
assert_eq!(tree.widget_count(), 5);
}
#[test]
fn test_layout_wide_tree() {
let mut engine = LayoutEngine::new();
let mut widget = Box::new(800.0, 600.0);
for _ in 0..20 {
widget = widget.with_child(Box::new(50.0, 50.0));
}
let viewport = Size::new(800.0, 600.0);
let tree = engine.compute(&mut widget, viewport);
assert_eq!(tree.widget_count(), 21);
}
#[test]
fn test_layout_empty_widget() {
let mut engine = LayoutEngine::new();
let mut widget = Box::new(0.0, 0.0);
let viewport = Size::new(800.0, 600.0);
let tree = engine.compute(&mut widget, viewport);
let size = tree.get_size(0).expect("should have size");
assert_eq!(size.width, 0.0);
assert_eq!(size.height, 0.0);
}
#[test]
fn test_layout_flexible_widget() {
let mut engine = LayoutEngine::new();
let mut widget = Flexible::new(1.0);
let viewport = Size::new(400.0, 300.0);
let tree = engine.compute(&mut widget, viewport);
let size = tree.get_size(0).expect("should have size");
assert_eq!(size.width, 400.0);
assert_eq!(size.height, 300.0);
}
#[test]
fn test_layout_zero_viewport() {
let mut engine = LayoutEngine::new();
let mut widget = Box::new(100.0, 100.0);
let viewport = Size::new(0.0, 0.0);
let tree = engine.compute(&mut widget, viewport);
let size = tree.get_size(0).expect("should have size");
assert_eq!(size.width, 0.0);
assert_eq!(size.height, 0.0);
}
#[test]
fn test_layout_very_large_viewport() {
let mut engine = LayoutEngine::new();
let mut widget = Box::new(100.0, 100.0);
let viewport = Size::new(10000.0, 10000.0);
let tree = engine.compute(&mut widget, viewport);
let size = tree.get_size(0).expect("should have size");
assert_eq!(size.width, 100.0);
assert_eq!(size.height, 100.0);
}