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) -> Box<dyn 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 Box::new(CoordinatorPlaceable {
109 size: Size {
110 width: placeable.width(),
111 height: placeable.height(),
112 },
113 content_offset: child_accumulated,
114 });
115 }
116 };
117
118 self.measured_size.set(result.size);
120
121 let local_offset = Point {
123 x: result.placement_offset_x,
124 y: result.placement_offset_y,
125 };
126
127 let child_accumulated = self.wrapped.total_content_offset();
130
131 let accumulated = Point {
133 x: local_offset.x + child_accumulated.x,
134 y: local_offset.y + child_accumulated.y,
135 };
136 self.accumulated_offset.set(accumulated);
137
138 Box::new(CoordinatorPlaceable {
139 size: result.size,
140 content_offset: accumulated,
141 })
142 }
143
144 fn min_intrinsic_width(&self, height: f32) -> f32 {
145 let node_borrow = self.node.borrow();
146 if let Some(layout_node) = node_borrow.as_layout_node() {
147 layout_node.min_intrinsic_width(self.wrapped.as_ref(), height)
148 } else {
149 self.wrapped.min_intrinsic_width(height)
150 }
151 }
152
153 fn max_intrinsic_width(&self, height: f32) -> f32 {
154 let node_borrow = self.node.borrow();
155 if let Some(layout_node) = node_borrow.as_layout_node() {
156 layout_node.max_intrinsic_width(self.wrapped.as_ref(), height)
157 } else {
158 self.wrapped.max_intrinsic_width(height)
159 }
160 }
161
162 fn min_intrinsic_height(&self, width: f32) -> f32 {
163 let node_borrow = self.node.borrow();
164 if let Some(layout_node) = node_borrow.as_layout_node() {
165 layout_node.min_intrinsic_height(self.wrapped.as_ref(), width)
166 } else {
167 self.wrapped.min_intrinsic_height(width)
168 }
169 }
170
171 fn max_intrinsic_height(&self, width: f32) -> f32 {
172 let node_borrow = self.node.borrow();
173 if let Some(layout_node) = node_borrow.as_layout_node() {
174 layout_node.max_intrinsic_height(self.wrapped.as_ref(), width)
175 } else {
176 self.wrapped.max_intrinsic_height(width)
177 }
178 }
179}
180
181pub struct InnerCoordinator<'a> {
185 measure_policy: Rc<dyn MeasurePolicy>,
187 measurables: &'a [Box<dyn Measurable>],
189 measured_size: Cell<Size>,
191 result_holder: Rc<RefCell<Option<MeasureResult>>>,
194}
195
196impl<'a> InnerCoordinator<'a> {
197 pub fn new(
199 measure_policy: Rc<dyn MeasurePolicy>,
200 measurables: &'a [Box<dyn Measurable>],
201 result_holder: Rc<RefCell<Option<MeasureResult>>>,
202 ) -> Self {
203 Self {
204 measure_policy,
205 measurables,
206 measured_size: Cell::new(Size::ZERO),
207 result_holder,
208 }
209 }
210}
211
212impl<'a> NodeCoordinator for InnerCoordinator<'a> {
213 fn total_content_offset(&self) -> Point {
214 Point::default()
215 }
216}
217
218impl<'a> Measurable for InnerCoordinator<'a> {
219 fn measure(&self, constraints: Constraints) -> Box<dyn Placeable> {
220 let result = self.measure_policy.measure(self.measurables, constraints);
222
223 let size = result.size;
225 self.measured_size.set(size);
226
227 *self.result_holder.borrow_mut() = Some(result);
229
230 Box::new(CoordinatorPlaceable {
232 size,
233 content_offset: Point::default(),
234 })
235 }
236
237 fn min_intrinsic_width(&self, height: f32) -> f32 {
238 self.measure_policy
239 .min_intrinsic_width(self.measurables, height)
240 }
241
242 fn max_intrinsic_width(&self, height: f32) -> f32 {
243 self.measure_policy
244 .max_intrinsic_width(self.measurables, height)
245 }
246
247 fn min_intrinsic_height(&self, width: f32) -> f32 {
248 self.measure_policy
249 .min_intrinsic_height(self.measurables, width)
250 }
251
252 fn max_intrinsic_height(&self, width: f32) -> f32 {
253 self.measure_policy
254 .max_intrinsic_height(self.measurables, width)
255 }
256}
257
258struct CoordinatorPlaceable {
261 size: Size,
262 content_offset: Point,
264}
265
266impl Placeable for CoordinatorPlaceable {
267 fn width(&self) -> f32 {
268 self.size.width
269 }
270
271 fn height(&self) -> f32 {
272 self.size.height
273 }
274
275 fn place(&self, _x: f32, _y: f32) {
276 }
278
279 fn node_id(&self) -> NodeId {
280 NodeId::default()
281 }
282
283 fn content_offset(&self) -> (f32, f32) {
284 (self.content_offset.x, self.content_offset.y)
285 }
286}