#![allow(clippy::unwrap_used, clippy::panic)]
use panes::resolver::BoundaryAxis;
use panes::runtime::LayoutRuntime;
use panes::{Layout, Overlay};
#[test]
fn panel_at_point_center_of_panel() {
let layout = Layout::row(["a", "b", "c"]).unwrap();
let resolved = layout.resolve(300.0, 100.0).unwrap();
let b_rect = resolved.by_kind("b")[0];
let b_resolved = resolved.get(b_rect).unwrap();
let (cx, cy) = b_resolved.center();
let hit = resolved.panel_at_point(cx, cy);
assert_eq!(hit, Some(b_rect));
}
#[test]
fn panel_at_point_outside_all_panels() {
let layout = Layout::row(["a", "b", "c"]).unwrap();
let resolved = layout.resolve(300.0, 100.0).unwrap();
assert_eq!(resolved.panel_at_point(-10.0, -10.0), None);
}
#[test]
fn panel_at_point_on_edge_returns_panel() {
let layout = Layout::row(["a", "b"]).unwrap();
let resolved = layout.resolve(200.0, 100.0).unwrap();
let a_id = resolved.by_kind("a")[0];
let a_rect = resolved.get(a_id).unwrap();
let hit = resolved.panel_at_point(a_rect.x, a_rect.y);
assert_eq!(hit, Some(a_id));
}
#[test]
fn panel_at_point_overlay_wins_over_panel() {
let mut rt = Layout::master_stack(["editor", "chat", "status"])
.master_ratio(0.6)
.gap(1.0)
.into_runtime()
.unwrap();
rt.add_overlay("palette", Overlay::center().fixed(200.0, 100.0))
.unwrap();
let frame = rt.resolve(800.0, 600.0).unwrap();
let resolved = frame.layout();
let overlay_hit = resolved.overlay_at_point(400.0, 300.0);
assert!(overlay_hit.is_some(), "overlay should be hit at center");
let panel_hit = resolved.panel_at_point(400.0, 300.0);
assert!(
panel_hit.is_some(),
"panel should still be found beneath overlay"
);
}
#[test]
fn panel_at_point_ignores_retired_panel_holes() {
let layout = Layout::row(["a", "tmp1", "b", "tmp2", "c"]).unwrap();
let mut rt = LayoutRuntime::new(layout.into());
let initial = rt.resolve(500.0, 100.0).unwrap();
let tmp1 = initial.layout().by_kind("tmp1")[0];
let tmp2 = initial.layout().by_kind("tmp2")[0];
rt.tree_mut().remove_panel(tmp1).unwrap();
rt.tree_mut().remove_panel(tmp2).unwrap();
let frame = rt.resolve(300.0, 100.0).unwrap();
let resolved = frame.layout();
let b_id = resolved.by_kind("b")[0];
let b_rect = resolved.get(b_id).unwrap();
let (cx, cy) = b_rect.center();
assert_eq!(resolved.panel_at_point(cx, cy), Some(b_id));
}
#[test]
fn panel_at_point_returns_topmost_on_overlapping_rects() {
let layout = Layout::row(["a", "b"]).unwrap();
let mut resolved = layout.resolve(200.0, 100.0).unwrap();
let a_id = resolved.by_kind("a")[0];
let b_id = resolved.by_kind("b")[0];
let a_rect = *resolved.get(a_id).unwrap();
let b_rect = *resolved.get(b_id).unwrap();
let (a_cx, a_cy) = a_rect.center();
let (b_cx, b_cy) = b_rect.center();
assert_eq!(resolved.panel_at_point(a_cx, a_cy), Some(a_id));
assert_eq!(resolved.panel_at_point(b_cx, b_cy), Some(b_id));
resolved.shift_x(-b_rect.x);
let overlap_y = a_rect.h / 2.0;
let hit = resolved.panel_at_point(1.0, overlap_y);
assert!(
b_id.raw() > a_id.raw(),
"b should have higher raw id than a"
);
assert_eq!(hit, Some(b_id));
}
#[test]
fn panel_at_point_returns_none_for_empty_space() {
let mut rt = Layout::master_stack(["editor", "chat", "status"])
.master_ratio(0.6)
.gap(10.0)
.into_runtime()
.unwrap();
let frame = rt.resolve(800.0, 600.0).unwrap();
let resolved = frame.layout();
let gap_x = 485.0;
let gap_y = 300.0;
let hit = resolved.panel_at_point(gap_x, gap_y);
assert_eq!(hit, None, "gap area should not hit any panel");
}
#[test]
fn boundary_at_point_between_siblings() {
let layout = Layout::row(["a", "b"]).unwrap();
let resolved = layout.resolve(200.0, 100.0).unwrap();
let hit = resolved.boundary_at_point(100.0, 50.0, 5.0);
assert!(hit.is_some(), "should find boundary between a and b");
let hit = hit.unwrap();
assert_eq!(hit.axis, BoundaryAxis::Vertical);
}
#[test]
fn boundary_at_point_no_boundary_in_tolerance() {
let layout = Layout::row(["a", "b"]).unwrap();
let resolved = layout.resolve(200.0, 100.0).unwrap();
let hit = resolved.boundary_at_point(50.0, 50.0, 5.0);
assert!(hit.is_none(), "no boundary near center of panel");
}
#[test]
fn boundary_at_point_col_returns_horizontal() {
let layout = Layout::col(["a", "b"]).unwrap();
let resolved = layout.resolve(100.0, 200.0).unwrap();
let hit = resolved.boundary_at_point(50.0, 100.0, 5.0);
assert!(hit.is_some(), "should find boundary between a and b");
let hit = hit.unwrap();
assert_eq!(hit.axis, BoundaryAxis::Horizontal);
}
#[test]
fn boundary_at_point_nested_containers() {
let mut rt = Layout::master_stack(["editor", "chat", "status"])
.master_ratio(0.6)
.gap(0.0)
.into_runtime()
.unwrap();
let frame = rt.resolve(800.0, 600.0).unwrap();
let resolved = frame.layout();
let hit = resolved.boundary_at_point(480.0, 300.0, 5.0);
assert!(
hit.is_some(),
"should find boundary between master and stack"
);
let hit = hit.unwrap();
assert_eq!(hit.axis, BoundaryAxis::Vertical);
}
#[test]
fn boundary_hit_testing_uses_same_observable_results_under_indexed_query_model() {
let layout = Layout::build_row(|row| {
row.col(|col| {
col.panel("a");
col.panel("b");
});
row.col(|col| {
col.panel("c");
col.panel("d");
});
row.col(|col| {
col.panel("e");
col.panel("f");
});
})
.unwrap();
let resolved = layout.resolve(600.0, 200.0).unwrap();
let hit = resolved.boundary_at_point(200.0, 50.0, 5.0);
assert!(hit.is_some(), "vertical boundary at x≈200");
assert_eq!(hit.unwrap().axis, BoundaryAxis::Vertical);
let hit = resolved.boundary_at_point(400.0, 150.0, 5.0);
assert!(hit.is_some(), "vertical boundary at x≈400");
assert_eq!(hit.unwrap().axis, BoundaryAxis::Vertical);
let hit = resolved.boundary_at_point(100.0, 100.0, 5.0);
assert!(hit.is_some(), "horizontal boundary at y≈100 in first col");
assert_eq!(hit.unwrap().axis, BoundaryAxis::Horizontal);
let hit = resolved.boundary_at_point(500.0, 100.0, 5.0);
assert!(hit.is_some(), "horizontal boundary at y≈100 in third col");
assert_eq!(hit.unwrap().axis, BoundaryAxis::Horizontal);
let hit = resolved.boundary_at_point(100.0, 50.0, 2.0);
assert!(hit.is_none(), "no boundary at center of panel a");
let hit = resolved.boundary_at_point(-10.0, 50.0, 5.0);
assert!(hit.is_none(), "no boundary outside layout");
let hit = resolved.boundary_at_point(201.0, 50.0, 3.0);
assert!(hit.is_some(), "should find vertical boundary near x=200");
assert_eq!(hit.unwrap().axis, BoundaryAxis::Vertical);
let hit1 = resolved.boundary_at_point(200.0, 80.0, 5.0);
let hit2 = resolved.boundary_at_point(200.0, 80.0, 5.0);
assert_eq!(hit1.unwrap().axis, hit2.unwrap().axis);
assert_eq!(hit1.unwrap().position, hit2.unwrap().position);
}