1use std::sync::Arc;
2
3pub use euclid::Rect;
4
5use crate::{
6 geometry::Area,
7 node::Node,
8 prelude::{
9 AreaModel,
10 Gaps,
11 SendAnyMap,
12 },
13};
14
15#[derive(Debug, Default, Clone)]
17pub struct LayoutNode {
18 pub area: Area,
20
21 pub inner_area: Area,
23
24 pub margin: Gaps,
26
27 pub data: Option<Arc<SendAnyMap>>,
29}
30
31impl PartialEq for LayoutNode {
32 fn eq(&self, other: &Self) -> bool {
33 self.area == other.area
34 && self.inner_area == other.inner_area
35 && self.margin == other.margin
36 }
37}
38
39impl LayoutNode {
40 pub fn visible_area(&self) -> Area {
42 self.area.without_gaps(&self.margin)
43 }
44}
45
46pub trait NodeKey: Clone + PartialEq + Eq + std::hash::Hash + Copy + std::fmt::Debug {}
47
48impl NodeKey for usize {}
49
50#[cfg(feature = "dioxus")]
51impl NodeKey for freya_native_core::NodeId {}
52
53pub trait DOMAdapter<Key: NodeKey> {
54 fn root_id(&self) -> Key;
55
56 fn get_node(&self, node_id: &Key) -> Option<Node>;
58
59 fn height(&self, node_id: &Key) -> Option<u16>;
61
62 fn parent_of(&self, node_id: &Key) -> Option<Key>;
64
65 fn children_of(&mut self, node_id: &Key) -> Vec<Key>;
67
68 fn is_node_valid(&mut self, node_id: &Key) -> bool;
70
71 fn closest_common_parent(&self, node_a: &Key, node_b: &Key) -> Option<Key> {
73 let height_a = self.height(node_a)?;
74 let height_b = self.height(node_b)?;
75
76 let (node_a, node_b) = match height_a.cmp(&height_b) {
77 std::cmp::Ordering::Less => (
78 *node_a,
79 balance_heights(self, *node_b, *node_a).unwrap_or(*node_b),
80 ),
81 std::cmp::Ordering::Equal => (*node_a, *node_b),
82 std::cmp::Ordering::Greater => (
83 balance_heights(self, *node_a, *node_b).unwrap_or(*node_a),
84 *node_b,
85 ),
86 };
87
88 let mut currents = (node_a, node_b);
89
90 loop {
91 if currents.0 == currents.1 {
93 return Some(currents.0);
94 }
95
96 let parent_a = self.parent_of(¤ts.0);
97 if let Some(parent_a) = parent_a {
98 currents.0 = parent_a;
99 } else if self.root_id() != currents.0 {
100 break;
102 }
103
104 let parent_b = self.parent_of(¤ts.1);
105 if let Some(parent_b) = parent_b {
106 currents.1 = parent_b;
107 } else if self.root_id() != currents.1 {
108 break;
110 }
111 }
112
113 None
114 }
115}
116
117fn balance_heights<Key: NodeKey>(
119 dom_adapter: &(impl DOMAdapter<Key> + ?Sized),
120 base: Key,
121 target: Key,
122) -> Option<Key> {
123 let target_height = dom_adapter.height(&target)?;
124 let mut current = base;
125 loop {
126 if dom_adapter.height(¤t)? == target_height {
127 break;
128 }
129
130 let parent_current = dom_adapter.parent_of(¤t);
131 if let Some(parent_current) = parent_current {
132 current = parent_current;
133 }
134 }
135 Some(current)
136}