1use std::any::{Any, TypeId};
8use std::collections::HashMap;
9use std::fmt::{self, Debug};
10use std::rc::Rc;
11
12use inset_embedder::{Offset, Size};
13use inset_foundation::{App, Handle, Key, Listenable, Listener};
14
15use crate::box_::{
16 AnyRenderBox, BoxConstraints, BoxHitTestResult, BoxParentData, ContainerBoxParentData,
17 RenderBox, RenderBoxContainerDefaultsMixin, RenderBoxData,
18};
19use crate::object::{
20 AnyRenderObject, Constraints, ContainerParentData, ContainerParentDataMixin,
21 ContainerRenderObjectData, ContainerRenderObjectMixin, ParentData, RenderHandle, RenderObject,
22 RenderObjectData,
23};
24use crate::painting_context::PaintingContext;
25use crate::pipeline_owner::PipelineOwner;
26
27pub type ChildLayoutId = Rc<dyn Key>;
31
32#[derive(Debug)]
34pub struct MultiChildLayoutParentData {
35 box_parent_data: BoxParentData,
36 container_parent_data: ContainerParentData<AnyRenderBox>,
37
38 pub id: Option<ChildLayoutId>,
40}
41
42impl MultiChildLayoutParentData {
43 pub const fn new() -> MultiChildLayoutParentData {
45 MultiChildLayoutParentData {
46 box_parent_data: BoxParentData::new(),
47 container_parent_data: ContainerParentData::new(),
48 id: None,
49 }
50 }
51}
52
53impl Default for MultiChildLayoutParentData {
54 fn default() -> MultiChildLayoutParentData {
55 MultiChildLayoutParentData::new()
56 }
57}
58
59impl ParentData for MultiChildLayoutParentData {
60 fn detach(&mut self) {
61 ContainerParentDataMixin::detach(self);
62 }
63
64 fn provide(&self, id: TypeId) -> Option<&dyn Any> {
65 if id == TypeId::of::<MultiChildLayoutParentData>() {
66 return Some(self);
67 }
68 self.box_parent_data.provide(id)
69 }
70
71 fn provide_mut(&mut self, id: TypeId) -> Option<&mut dyn Any> {
72 if id == TypeId::of::<MultiChildLayoutParentData>() {
73 return Some(self);
74 }
75 self.box_parent_data.provide_mut(id)
76 }
77}
78
79impl ContainerParentDataMixin for MultiChildLayoutParentData {
80 type ChildType = AnyRenderBox;
81
82 fn container_parent_data(&self) -> &ContainerParentData<AnyRenderBox> {
83 &self.container_parent_data
84 }
85
86 fn container_parent_data_mut(&mut self) -> &mut ContainerParentData<AnyRenderBox> {
87 &mut self.container_parent_data
88 }
89}
90
91impl ContainerBoxParentData for MultiChildLayoutParentData {
92 fn box_parent_data(&self) -> &BoxParentData {
93 &self.box_parent_data
94 }
95
96 fn box_parent_data_mut(&mut self) -> &mut BoxParentData {
97 &mut self.box_parent_data
98 }
99}
100
101impl fmt::Display for MultiChildLayoutParentData {
102 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
103 write!(f, "{}; id={:?}", self.box_parent_data, self.id)
104 }
105}
106
107pub struct MultiChildLayoutChildren {
114 id_to_child: HashMap<ChildLayoutId, AnyRenderBox>,
115 #[cfg(debug_assertions)]
116 children_needing_layout: std::collections::HashSet<AnyRenderBox>,
117}
118
119impl MultiChildLayoutChildren {
120 pub fn has_child(&self, child_id: &ChildLayoutId) -> bool {
128 self.id_to_child.contains_key(child_id)
129 }
130
131 pub fn layout_child(
143 &mut self,
144 app: &mut App,
145 child_id: &ChildLayoutId,
146 constraints: BoxConstraints,
147 ) -> Size {
148 let child = *self.id_to_child.get(child_id).unwrap_or_else(|| {
149 panic!(
150 "The custom multichild layout delegate tried to lay out a non-existent child. \
151 There is no child with the id {child_id:?}."
152 )
153 });
154 #[cfg(debug_assertions)]
155 assert!(
156 self.children_needing_layout.remove(&child),
157 "The custom multichild layout delegate tried to lay out the child with id \
158 {child_id:?} more than once. Each child must be laid out exactly once."
159 );
160 debug_assert!(
161 constraints.debug_assert_is_valid(true),
162 "The custom multichild layout delegate provided invalid box constraints for the \
163 child with id {child_id:?}. The minimum width and height must be greater than or \
164 equal to zero. The maximum width must be greater than or equal to the minimum \
165 width. The maximum height must be greater than or equal to the minimum height."
166 );
167 child.layout(app, constraints, true);
168 child.size(app)
169 }
170
171 pub fn position_child(&self, app: &mut App, child_id: &ChildLayoutId, offset: Offset) {
182 let child = *self.id_to_child.get(child_id).unwrap_or_else(|| {
183 panic!(
184 "The custom multichild layout delegate tried to position out a non-existent \
185 child: there is no child with the id {child_id:?}."
186 )
187 });
188 child
189 .parent_data_of_mut::<MultiChildLayoutParentData>(app)
190 .set_offset(offset);
191 }
192}
193
194pub trait MultiChildLayoutDelegate: Debug + 'static {
226 fn relayout(&self) -> Option<&Rc<dyn Listenable>> {
230 None
231 }
232
233 fn get_size(&self, constraints: BoxConstraints) -> Size {
241 constraints.biggest()
242 }
243
244 fn perform_layout(&self, app: &mut App, children: &mut MultiChildLayoutChildren, size: Size);
250
251 fn should_relayout(&self, old_delegate: &dyn MultiChildLayoutDelegate) -> bool;
258
259 fn as_any(&self) -> &dyn Any;
262}
263
264pub struct RenderCustomMultiChildLayoutBox {
270 render_object: RenderObjectData,
271 render_box: RenderBoxData,
272 container: ContainerRenderObjectData<AnyRenderBox>,
273 delegate: Rc<dyn MultiChildLayoutDelegate>,
274}
275
276impl RenderCustomMultiChildLayoutBox {
277 pub fn new(
282 app: &mut App,
283 delegate: Rc<dyn MultiChildLayoutDelegate>,
284 ) -> RenderHandle<RenderCustomMultiChildLayoutBox> {
285 RenderHandle::new_box(
286 app,
287 RenderCustomMultiChildLayoutBox {
288 render_object: RenderObjectData::new(),
289 render_box: RenderBoxData::new(),
290 container: ContainerRenderObjectData::new(),
291 delegate,
292 },
293 )
294 }
295
296 pub fn delegate(self: RenderHandle<Self>, app: &App) -> Rc<dyn MultiChildLayoutDelegate> {
298 Rc::clone(&self.get(app).delegate)
299 }
300
301 pub fn set_delegate(
303 self: RenderHandle<Self>,
304 app: &mut App,
305 new_delegate: Rc<dyn MultiChildLayoutDelegate>,
306 ) {
307 let old_delegate = Rc::clone(&self.get(app).delegate);
308 if Rc::ptr_eq(&old_delegate, &new_delegate) {
309 return;
310 }
311 if new_delegate.as_any().type_id() != old_delegate.as_any().type_id()
312 || new_delegate.should_relayout(&*old_delegate)
313 {
314 self.mark_needs_layout(app);
315 }
316 self.get_mut(app).delegate = Rc::clone(&new_delegate);
317 if self.attached(app) {
318 if let Some(relayout) = old_delegate.relayout() {
319 relayout.remove_listener(app, &self.relayout_listener());
320 }
321 if let Some(relayout) = new_delegate.relayout() {
322 relayout.add_listener(app, self.relayout_listener());
323 }
324 }
325 }
326
327 fn relayout_listener(self: RenderHandle<Self>) -> Listener {
329 Listener::handle_method(self.handle(), mark_needs_layout)
330 }
331
332 fn get_size(self: RenderHandle<Self>, app: &App, constraints: BoxConstraints) -> Size {
334 debug_assert!(constraints.debug_assert_is_valid(false));
335 constraints.constrain(self.get(app).delegate.get_size(constraints))
336 }
337
338 fn call_perform_layout(self: RenderHandle<Self>, app: &mut App, size: Size) {
344 let mut children = MultiChildLayoutChildren {
345 id_to_child: HashMap::new(),
346 #[cfg(debug_assertions)]
347 children_needing_layout: std::collections::HashSet::new(),
348 };
349 let mut child = self.first_child(app);
350 while let Some(current) = child {
351 let child_parent_data = current
352 .as_object()
353 .parent_data_of::<MultiChildLayoutParentData>(app);
354 let (id, next_sibling) = (
355 child_parent_data.id.clone(),
356 child_parent_data.next_sibling(),
357 );
358 let id = id.unwrap_or_else(|| {
359 panic!(
360 "Every child of a RenderCustomMultiChildLayoutBox must have an ID in its \
361 parent data. The following child has no ID: {current:?}"
362 )
363 });
364 children.id_to_child.insert(id, current);
365 #[cfg(debug_assertions)]
366 children.children_needing_layout.insert(current);
367 child = next_sibling;
368 }
369
370 let delegate = Rc::clone(&self.get(app).delegate);
371 delegate.perform_layout(app, &mut children, size);
372
373 #[cfg(debug_assertions)]
374 assert!(
375 children.children_needing_layout.is_empty(),
376 "Each child must be laid out exactly once. The custom multichild layout delegate \
377 forgot to lay out {:?}",
378 children.children_needing_layout
379 );
380 }
381}
382
383fn mark_needs_layout(this: Handle<RenderCustomMultiChildLayoutBox>, app: &mut App) {
384 RenderHandle::from_handle(this).mark_needs_layout(app);
385}
386
387impl ContainerRenderObjectMixin for RenderCustomMultiChildLayoutBox {
388 type ChildType = AnyRenderBox;
389 type ParentDataType = MultiChildLayoutParentData;
390
391 fn container_data(
392 self: RenderHandle<Self>,
393 app: &App,
394 ) -> &ContainerRenderObjectData<AnyRenderBox> {
395 &self.get(app).container
396 }
397
398 fn container_data_mut(
399 self: RenderHandle<Self>,
400 app: &mut App,
401 ) -> &mut ContainerRenderObjectData<AnyRenderBox> {
402 &mut self.get_mut(app).container
403 }
404}
405
406impl RenderBoxContainerDefaultsMixin for RenderCustomMultiChildLayoutBox {}
407
408impl RenderObject for RenderCustomMultiChildLayoutBox {
409 crate::render_object_accessors!();
410
411 fn perform_layout(self: RenderHandle<Self>, app: &mut App) {
412 let constraints = self.constraints(app);
413 let size = self.get_size(app, constraints);
414 self.set_size(app, size);
415 self.call_perform_layout(app, size);
416 }
417
418 fn visit_children(
419 self: RenderHandle<Self>,
420 app: &App,
421 visitor: &mut dyn FnMut(AnyRenderObject),
422 ) {
423 ContainerRenderObjectMixin::visit_children(self, app, visitor)
424 }
425
426 fn did_attach(self: RenderHandle<Self>, app: &mut App, owner: Handle<PipelineOwner>) {
427 ContainerRenderObjectMixin::did_attach(self, app, owner);
428 if let Some(relayout) = self.delegate(app).relayout() {
429 relayout.add_listener(app, self.relayout_listener());
430 }
431 }
432
433 fn did_detach(self: RenderHandle<Self>, app: &mut App) {
434 if let Some(relayout) = self.delegate(app).relayout() {
435 relayout.remove_listener(app, &self.relayout_listener());
436 }
437 ContainerRenderObjectMixin::did_detach(self, app)
438 }
439
440 fn redepth_children(self: RenderHandle<Self>, app: &mut App) {
441 ContainerRenderObjectMixin::redepth_children(self, app)
442 }
443
444 fn paint(
445 self: RenderHandle<Self>,
446 app: &mut App,
447 context: &mut PaintingContext,
448 offset: Offset,
449 ) {
450 self.default_paint(app, context, offset);
451 }
452}
453
454impl RenderBox for RenderCustomMultiChildLayoutBox {
455 crate::render_box_accessors!();
456
457 fn setup_parent_data(self: RenderHandle<Self>, app: &mut App, child: AnyRenderObject) {
458 if !child.parent_data_is::<MultiChildLayoutParentData>(app) {
459 child.set_parent_data(app, MultiChildLayoutParentData::new());
460 }
461 }
462
463 fn compute_min_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
467 let width = self
468 .get_size(app, BoxConstraints::tight_for_finite(f64::INFINITY, height))
469 .width();
470 if width.is_finite() { width } else { 0.0 }
471 }
472
473 fn compute_max_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
474 let width = self
475 .get_size(app, BoxConstraints::tight_for_finite(f64::INFINITY, height))
476 .width();
477 if width.is_finite() { width } else { 0.0 }
478 }
479
480 fn compute_min_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
481 let height = self
482 .get_size(app, BoxConstraints::tight_for_finite(width, f64::INFINITY))
483 .height();
484 if height.is_finite() { height } else { 0.0 }
485 }
486
487 fn compute_max_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
488 let height = self
489 .get_size(app, BoxConstraints::tight_for_finite(width, f64::INFINITY))
490 .height();
491 if height.is_finite() { height } else { 0.0 }
492 }
493
494 fn compute_dry_layout(
495 self: RenderHandle<Self>,
496 app: &mut App,
497 constraints: BoxConstraints,
498 ) -> Size {
499 self.get_size(app, constraints)
500 }
501
502 fn hit_test_children(
503 self: RenderHandle<Self>,
504 app: &mut App,
505 result: &mut BoxHitTestResult<'_>,
506 position: Offset,
507 ) -> bool {
508 self.default_hit_test_children(app, result, position)
509 }
510}