Skip to main content

term_wm_layout_engine/
layout.rs

1use crate::node::BspNode;
2use crate::node::NaryNode;
3use crate::rect::{LayoutError, LayoutRect, Orientation, SizeConstraints};
4use crate::snap::InsertPosition;
5
6/// Common interface for tree-based layout engines (BSP and N-ary).
7///
8/// All mutation methods accept `SizeConstraints` to enforce minimum
9/// dimensions and return `Result<(), LayoutError>` on violation.
10pub trait LayoutEngine<Id: Copy + Eq + Ord> {
11    fn layout(&self, area: LayoutRect) -> Vec<(Id, LayoutRect)>;
12    fn insert_leaf(
13        &mut self,
14        target: Id,
15        insert: Id,
16        position: InsertPosition,
17        area: LayoutRect,
18        constraints: &SizeConstraints,
19    ) -> Result<(), LayoutError>;
20    fn remove_leaf(&mut self, id: Id) -> Result<(), LayoutError>;
21    fn all_leaf_ids(&self) -> Vec<Id>;
22    fn subtree_any(&self, predicate: &mut impl FnMut(Id) -> bool) -> bool;
23    fn apply_drag(
24        &mut self,
25        area: LayoutRect,
26        path: &[usize],
27        index: usize,
28        orientation: Orientation,
29        delta: i16,
30        constraints: &SizeConstraints,
31    ) -> bool;
32}
33
34impl<Id: Copy + Eq + Ord> LayoutEngine<Id> for BspNode<Id> {
35    fn layout(&self, area: LayoutRect) -> Vec<(Id, LayoutRect)> {
36        self.layout(area)
37    }
38
39    fn insert_leaf(
40        &mut self,
41        target: Id,
42        insert: Id,
43        position: InsertPosition,
44        area: LayoutRect,
45        constraints: &SizeConstraints,
46    ) -> Result<(), LayoutError> {
47        self.insert_leaf(target, insert, position, area, constraints)
48    }
49
50    fn remove_leaf(&mut self, id: Id) -> Result<(), LayoutError> {
51        self.remove_leaf(id)
52    }
53
54    fn all_leaf_ids(&self) -> Vec<Id> {
55        self.all_leaf_ids()
56    }
57
58    fn subtree_any(&self, predicate: &mut impl FnMut(Id) -> bool) -> bool {
59        self.subtree_any(predicate)
60    }
61
62    fn apply_drag(
63        &mut self,
64        area: LayoutRect,
65        path: &[usize],
66        _index: usize,
67        orientation: Orientation,
68        delta: i16,
69        constraints: &SizeConstraints,
70    ) -> bool {
71        let bool_path: Vec<bool> = path.iter().map(|&i| i != 0).collect();
72        self.apply_drag(area, &bool_path, orientation, delta, constraints)
73    }
74}
75
76impl<Id: Copy + Eq + Ord> LayoutEngine<Id> for NaryNode<Id> {
77    fn layout(&self, area: LayoutRect) -> Vec<(Id, LayoutRect)> {
78        self.layout(area)
79    }
80
81    fn insert_leaf(
82        &mut self,
83        target: Id,
84        insert: Id,
85        position: InsertPosition,
86        area: LayoutRect,
87        constraints: &SizeConstraints,
88    ) -> Result<(), LayoutError> {
89        self.insert_leaf(target, insert, position, area, constraints)
90    }
91
92    fn remove_leaf(&mut self, id: Id) -> Result<(), LayoutError> {
93        self.remove_leaf(id)
94    }
95
96    fn all_leaf_ids(&self) -> Vec<Id> {
97        self.all_leaf_ids()
98    }
99
100    fn subtree_any(&self, predicate: &mut impl FnMut(Id) -> bool) -> bool {
101        self.subtree_any(predicate)
102    }
103
104    fn apply_drag(
105        &mut self,
106        area: LayoutRect,
107        path: &[usize],
108        index: usize,
109        orientation: Orientation,
110        delta: i16,
111        constraints: &SizeConstraints,
112    ) -> bool {
113        self.apply_drag(area, path, index, orientation, delta, constraints)
114    }
115}
116
117#[cfg(test)]
118mod tests {
119    use super::*;
120    use crate::node::BspNode;
121    use crate::node::NaryNode;
122
123    #[test]
124    fn layout_engine_trait_works_with_bsp_node() {
125        let mut node: BspNode<u8> = BspNode::leaf(1);
126        let constraints = SizeConstraints {
127            min_width: 2,
128            min_height: 2,
129        };
130        let area = LayoutRect {
131            x: 0,
132            y: 0,
133            width: 80,
134            height: 24,
135        };
136
137        assert!(
138            LayoutEngine::insert_leaf(&mut node, 1, 2, InsertPosition::Right, area, &constraints)
139                .is_ok()
140        );
141
142        let regions = LayoutEngine::layout(&node, area);
143        assert_eq!(regions.len(), 2);
144    }
145
146    #[test]
147    fn layout_engine_trait_works_with_nary_node() {
148        let mut node: NaryNode<u8> = NaryNode::leaf(1);
149        let constraints = SizeConstraints {
150            min_width: 2,
151            min_height: 2,
152        };
153        let area = LayoutRect {
154            x: 0,
155            y: 0,
156            width: 80,
157            height: 24,
158        };
159
160        assert!(
161            LayoutEngine::insert_leaf(&mut node, 1, 2, InsertPosition::Right, area, &constraints)
162                .is_ok()
163        );
164
165        let regions = LayoutEngine::layout(&node, area);
166        assert_eq!(regions.len(), 2);
167    }
168}