cranpose_ui/layout/
coordinator.rs1use cranpose_core::NodeId;
12use cranpose_foundation::ModifierNodeContext;
13use cranpose_ui_layout::{Constraints, Measurable, Placeable};
14use std::cell::{Cell, RefCell};
15use std::rc::Rc;
16
17use crate::layout::{LayoutNodeContext, MeasurePolicy, MeasureResult};
18use crate::modifier::{Point, Size};
19
20pub trait NodeCoordinator: Measurable {
25 fn total_content_offset(&self) -> Point;
28}
29
30pub struct LayoutModifierCoordinator<'a> {
35 node: Rc<RefCell<Box<dyn cranpose_foundation::ModifierNode>>>,
39 wrapped: Box<dyn NodeCoordinator + 'a>,
41 measured_size: Cell<Size>,
43 accumulated_offset: Cell<Point>,
46 context: Rc<RefCell<LayoutNodeContext>>,
48}
49
50impl<'a> LayoutModifierCoordinator<'a> {
51 #[allow(private_interfaces)]
53 pub fn new(
54 node: Rc<RefCell<Box<dyn cranpose_foundation::ModifierNode>>>,
55 wrapped: Box<dyn NodeCoordinator + 'a>,
56 context: Rc<RefCell<LayoutNodeContext>>,
57 ) -> Self {
58 Self {
59 node,
60 wrapped,
61 measured_size: Cell::new(Size::default()),
62 accumulated_offset: Cell::new(Point::default()),
63 context,
64 }
65 }
66}
67
68impl<'a> NodeCoordinator for LayoutModifierCoordinator<'a> {
69 fn total_content_offset(&self) -> Point {
70 self.accumulated_offset.get()
72 }
73}
74
75impl<'a> Measurable for LayoutModifierCoordinator<'a> {
76 fn measure(&self, constraints: Constraints) -> Placeable {
78 let node_borrow = self.node.borrow();
79
80 let result = {
81 if let Some(layout_node) = node_borrow.as_layout_node() {
82 match self.context.try_borrow_mut() {
83 Ok(mut context) => {
84 layout_node.measure(&mut *context, self.wrapped.as_ref(), constraints)
85 }
86 Err(_) => {
87 let mut temp = LayoutNodeContext::new();
89 let result =
90 layout_node.measure(&mut temp, self.wrapped.as_ref(), constraints);
91
92 if let Ok(mut shared) = self.context.try_borrow_mut() {
94 for kind in temp.take_invalidations() {
95 shared.invalidate(kind);
96 }
97 }
98
99 result
100 }
101 }
102 } else {
103 let placeable = self.wrapped.measure(constraints);
105 let child_accumulated = self.wrapped.total_content_offset();
107 self.accumulated_offset.set(child_accumulated);
108 return Placeable::value_with_offset(
109 placeable.width(),
110 placeable.height(),
111 NodeId::default(),
112 (child_accumulated.x, child_accumulated.y),
113 );
114 }
115 };
116
117 self.measured_size.set(result.size);
119
120 let local_offset = Point {
122 x: result.placement_offset_x,
123 y: result.placement_offset_y,
124 };
125
126 let child_accumulated = self.wrapped.total_content_offset();
129
130 let accumulated = Point {
132 x: local_offset.x + child_accumulated.x,
133 y: local_offset.y + child_accumulated.y,
134 };
135 self.accumulated_offset.set(accumulated);
136
137 Placeable::value_with_offset(
138 result.size.width,
139 result.size.height,
140 NodeId::default(),
141 (accumulated.x, accumulated.y),
142 )
143 }
144
145 fn min_intrinsic_width(&self, height: f32) -> f32 {
146 let node_borrow = self.node.borrow();
147 if let Some(layout_node) = node_borrow.as_layout_node() {
148 layout_node.min_intrinsic_width(self.wrapped.as_ref(), height)
149 } else {
150 self.wrapped.min_intrinsic_width(height)
151 }
152 }
153
154 fn max_intrinsic_width(&self, height: f32) -> f32 {
155 let node_borrow = self.node.borrow();
156 if let Some(layout_node) = node_borrow.as_layout_node() {
157 layout_node.max_intrinsic_width(self.wrapped.as_ref(), height)
158 } else {
159 self.wrapped.max_intrinsic_width(height)
160 }
161 }
162
163 fn min_intrinsic_height(&self, width: f32) -> f32 {
164 let node_borrow = self.node.borrow();
165 if let Some(layout_node) = node_borrow.as_layout_node() {
166 layout_node.min_intrinsic_height(self.wrapped.as_ref(), width)
167 } else {
168 self.wrapped.min_intrinsic_height(width)
169 }
170 }
171
172 fn max_intrinsic_height(&self, width: f32) -> f32 {
173 let node_borrow = self.node.borrow();
174 if let Some(layout_node) = node_borrow.as_layout_node() {
175 layout_node.max_intrinsic_height(self.wrapped.as_ref(), width)
176 } else {
177 self.wrapped.max_intrinsic_height(width)
178 }
179 }
180}
181
182pub struct InnerCoordinator<'a> {
186 measure_policy: Rc<dyn MeasurePolicy>,
188 measurables: &'a [Box<dyn Measurable>],
190 measured_size: Cell<Size>,
192 result_holder: Rc<RefCell<Option<MeasureResult>>>,
195}
196
197impl<'a> InnerCoordinator<'a> {
198 pub fn new(
200 measure_policy: Rc<dyn MeasurePolicy>,
201 measurables: &'a [Box<dyn Measurable>],
202 result_holder: Rc<RefCell<Option<MeasureResult>>>,
203 ) -> Self {
204 Self {
205 measure_policy,
206 measurables,
207 measured_size: Cell::new(Size::ZERO),
208 result_holder,
209 }
210 }
211}
212
213impl<'a> NodeCoordinator for InnerCoordinator<'a> {
214 fn total_content_offset(&self) -> Point {
215 Point::default()
216 }
217}
218
219impl<'a> Measurable for InnerCoordinator<'a> {
220 fn measure(&self, constraints: Constraints) -> Placeable {
221 let result = self.measure_policy.measure(self.measurables, constraints);
223
224 let size = result.size;
226 self.measured_size.set(size);
227
228 *self.result_holder.borrow_mut() = Some(result);
230
231 Placeable::value(size.width, size.height, NodeId::default())
233 }
234
235 fn min_intrinsic_width(&self, height: f32) -> f32 {
236 self.measure_policy
237 .min_intrinsic_width(self.measurables, height)
238 }
239
240 fn max_intrinsic_width(&self, height: f32) -> f32 {
241 self.measure_policy
242 .max_intrinsic_width(self.measurables, height)
243 }
244
245 fn min_intrinsic_height(&self, width: f32) -> f32 {
246 self.measure_policy
247 .min_intrinsic_height(self.measurables, width)
248 }
249
250 fn max_intrinsic_height(&self, width: f32) -> f32 {
251 self.measure_policy
252 .max_intrinsic_height(self.measurables, width)
253 }
254}