1use std::{
2 any::Any,
3 rc::Rc,
4};
5
6pub use euclid::Rect;
7
8use crate::{
9 geometry::Area,
10 node::Node,
11 prelude::{
12 AreaModel,
13 Gaps,
14 Length,
15 },
16};
17
18#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
19#[derive(Debug, Default, Clone)]
21pub struct LayoutNode {
22 pub area: Area,
24
25 pub inner_area: Area,
27
28 pub margin: Gaps,
30
31 pub offset_x: Length,
33 pub offset_y: Length,
34
35 #[cfg_attr(feature = "serde", serde(skip_deserializing, skip_serializing))]
37 pub data: Option<Rc<dyn Any>>,
38}
39
40impl PartialEq for LayoutNode {
41 fn eq(&self, other: &Self) -> bool {
42 self.area == other.area
43 && self.inner_area == other.inner_area
44 && self.margin == other.margin
45 && self.offset_x == other.offset_x
46 && self.offset_y == other.offset_y
47 }
48}
49
50impl LayoutNode {
51 pub fn visible_area(&self) -> Area {
53 self.area.without_gaps(&self.margin)
54 }
55}
56
57pub trait NodeKey: Clone + PartialEq + Eq + std::hash::Hash + Copy + std::fmt::Debug {}
58
59impl NodeKey for usize {}
60
61pub trait TreeAdapter<Key: NodeKey> {
62 fn root_id(&self) -> Key;
63
64 fn get_node(&self, node_id: &Key) -> Option<Node>;
66
67 fn height(&self, node_id: &Key) -> Option<u16>;
69
70 fn parent_of(&self, node_id: &Key) -> Option<Key>;
72
73 fn children_of(&mut self, node_id: &Key) -> Vec<Key>;
75
76 fn closest_common_parent(
78 &self,
79 node_a: &Key,
80 node_b: &Key,
81 walker: impl FnMut(Key),
82 ) -> Option<Key> {
83 let height_a = self.height(node_a)?;
84 let height_b = self.height(node_b)?;
85
86 let (node_a, node_b) = match height_a.cmp(&height_b) {
87 std::cmp::Ordering::Less => (
88 *node_a,
89 balance_heights(self, *node_b, *node_a, None::<fn(_)>).unwrap_or(*node_b),
91 ),
92 std::cmp::Ordering::Equal => (*node_a, *node_b),
93 std::cmp::Ordering::Greater => (
94 balance_heights(self, *node_a, *node_b, Some(walker)).unwrap_or(*node_a),
95 *node_b,
96 ),
97 };
98
99 let mut currents = (node_a, node_b);
100
101 loop {
102 if currents.0 == currents.1 {
104 return Some(currents.0);
105 }
106
107 let parent_a = self.parent_of(¤ts.0);
108 if let Some(parent_a) = parent_a {
109 currents.0 = parent_a;
110 } else if self.root_id() != currents.0 {
111 break;
113 }
114
115 let parent_b = self.parent_of(¤ts.1);
116 if let Some(parent_b) = parent_b {
117 currents.1 = parent_b;
118 } else if self.root_id() != currents.1 {
119 break;
121 }
122 }
123
124 None
125 }
126}
127
128fn balance_heights<Key: NodeKey>(
130 dom_adapter: &(impl TreeAdapter<Key> + ?Sized),
131 base: Key,
132 target: Key,
133 mut walker: Option<impl FnMut(Key)>,
134) -> Option<Key> {
135 let target_height = dom_adapter.height(&target)?;
136 let mut current = base;
137 loop {
138 if let Some(walker) = &mut walker {
139 (walker)(current);
140 }
141 if dom_adapter.height(¤t)? == target_height {
142 break;
143 }
144
145 let parent_current = dom_adapter.parent_of(¤t);
146 if let Some(parent_current) = parent_current {
147 current = parent_current;
148 }
149 }
150 Some(current)
151}