124 lines
3.8 KiB
Rust
124 lines
3.8 KiB
Rust
use super::*;
|
|
|
|
fn rect(x: u16, y: u16, width: u16, height: u16) -> PaneRect {
|
|
PaneRect {
|
|
x,
|
|
y,
|
|
width,
|
|
height,
|
|
}
|
|
}
|
|
|
|
fn leaves(tree: &PaneTree, bounds: PaneRect) -> Vec<(usize, PaneRect)> {
|
|
let mut leaves = Vec::new();
|
|
tree.visit_rects(bounds, |id, rect| leaves.push((id, rect)));
|
|
leaves
|
|
}
|
|
|
|
#[test]
|
|
fn nested_layout_partitions_bounds_and_preserves_ids() {
|
|
let bounds = rect(3, 5, 11, 9);
|
|
let mut tree = PaneTree::new(10);
|
|
assert!(tree.split(10, 20, SplitAxis::Vertical));
|
|
assert!(tree.split(20, 30, SplitAxis::Horizontal));
|
|
assert!(!tree.split(99, 40, SplitAxis::Horizontal));
|
|
assert!(!tree.split(10, 30, SplitAxis::Horizontal));
|
|
assert!(!tree.split(10, 10, SplitAxis::Horizontal));
|
|
assert_eq!(tree.len(), 3);
|
|
let panes = leaves(&tree, bounds);
|
|
assert_eq!(
|
|
panes,
|
|
vec![
|
|
(10, rect(3, 5, 5, 9)),
|
|
(20, rect(8, 5, 6, 4)),
|
|
(30, rect(8, 9, 6, 5))
|
|
]
|
|
);
|
|
let mut cells = std::collections::HashSet::new();
|
|
for (_, pane) in panes {
|
|
for y in pane.y..pane.y + pane.height {
|
|
for x in pane.x..pane.x + pane.width {
|
|
assert!(cells.insert((x, y)), "overlapping pane cell");
|
|
}
|
|
}
|
|
}
|
|
assert_eq!(
|
|
cells.len(),
|
|
usize::from(bounds.width) * usize::from(bounds.height)
|
|
);
|
|
assert!(leaves(&tree, rect(0, 0, 0, 10)).is_empty());
|
|
assert!(leaves(&tree, rect(0, 0, 10, 0)).is_empty());
|
|
}
|
|
|
|
#[test]
|
|
fn closing_expands_nested_sibling_and_refuses_last() {
|
|
let bounds = rect(0, 0, 20, 12);
|
|
let mut tree = PaneTree::new(1);
|
|
tree.split(1, 2, SplitAxis::Vertical);
|
|
tree.split(2, 3, SplitAxis::Horizontal);
|
|
assert_eq!(tree.close(1), Some(2));
|
|
assert_eq!(
|
|
leaves(&tree, bounds),
|
|
vec![(2, rect(0, 0, 20, 6)), (3, rect(0, 6, 20, 6))]
|
|
);
|
|
assert_eq!(tree.close(99), None);
|
|
assert_eq!(tree.close(2), Some(3));
|
|
assert_eq!(leaves(&tree, bounds), vec![(3, bounds)]);
|
|
assert_eq!(tree.close(3), None);
|
|
assert_eq!(tree.len(), 1);
|
|
assert!(!tree.contains(1));
|
|
assert!(tree.contains(3));
|
|
}
|
|
|
|
#[test]
|
|
fn directional_focus_handles_unequal_nested_regions() {
|
|
let bounds = rect(0, 0, 20, 12);
|
|
let mut tree = PaneTree::new(1);
|
|
tree.split(1, 2, SplitAxis::Vertical);
|
|
tree.split(2, 3, SplitAxis::Horizontal);
|
|
tree.split(3, 4, SplitAxis::Horizontal);
|
|
assert_eq!(tree.neighbor(1, PaneDirection::Right, bounds), Some(3));
|
|
assert_eq!(tree.neighbor(2, PaneDirection::Down, bounds), Some(3));
|
|
assert_eq!(tree.neighbor(3, PaneDirection::Down, bounds), Some(4));
|
|
assert_eq!(tree.neighbor(4, PaneDirection::Up, bounds), Some(3));
|
|
assert_eq!(tree.neighbor(4, PaneDirection::Left, bounds), Some(1));
|
|
assert_eq!(tree.neighbor(1, PaneDirection::Left, bounds), None);
|
|
assert_eq!(tree.neighbor(99, PaneDirection::Right, bounds), None);
|
|
assert_eq!(
|
|
tree.neighbor(1, PaneDirection::Right, rect(0, 0, 0, 0)),
|
|
None
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn navigation_prefers_overlap_then_edge_and_breaks_ties_by_id() {
|
|
let current = rect(10, 10, 10, 10);
|
|
let candidates = [
|
|
(1, rect(20, 0, 5, 5)),
|
|
(2, rect(25, 10, 5, 10)),
|
|
(4, rect(22, 10, 5, 10)),
|
|
(3, rect(22, 10, 5, 10)),
|
|
(0, rect(20, 10, 0, 10)),
|
|
];
|
|
assert_eq!(
|
|
directional_neighbor(current, PaneDirection::Right, candidates.into_iter()),
|
|
Some(3)
|
|
);
|
|
assert_eq!(
|
|
directional_neighbor(current, PaneDirection::Right, candidates.into_iter().rev()),
|
|
Some(3)
|
|
);
|
|
assert_eq!(
|
|
directional_neighbor(
|
|
current,
|
|
PaneDirection::Up,
|
|
[(7, rect(10, 0, 10, 5))].into_iter()
|
|
),
|
|
Some(7)
|
|
);
|
|
assert_eq!(
|
|
directional_neighbor(current, PaneDirection::Left, candidates.into_iter()),
|
|
None
|
|
);
|
|
}
|