1use crate::Widget;
2use expanse::geometry::Size;
3use expanse::number::Number;
4use expanse::Stretch;
5use mt_dom::attr;
6
7pub(crate) fn compute_node_layout<MSG>(
10 widget_node: &mut dyn Widget<MSG>,
11 parent_size: Size<Number>,
12) {
13 let mut stretch = Stretch::new();
14 let stretch_node = build_stretch_node_recursive(&mut stretch, widget_node)
15 .expect("must have built a style node");
16 stretch
17 .compute_layout(stretch_node, parent_size)
18 .expect("must compute the layout");
19 set_node_layout_from_stretch_node(
20 widget_node,
21 stretch_node,
22 &stretch,
23 (0.0, 0.0),
24 (0.0, 0.0),
25 )
26}
27
28pub(crate) fn node_hit_at<MSG>(
29 node: &dyn Widget<MSG>,
30 x: f32,
31 y: f32,
32 cur_node_idx: &mut usize,
33) -> Vec<usize> {
34 let layout = node.layout().expect("must have a layout");
35 let loc = layout.location;
36 let width = layout.size.width;
37 let height = layout.size.height;
38
39 let mut hits = vec![];
40
41 if x >= loc.x && x < loc.x + width && y >= loc.y && y < loc.y + height {
42 hits.push(*cur_node_idx);
43 }
44 if let Some(children) = node.children() {
45 for child in children.iter() {
46 *cur_node_idx += 1;
47 hits.extend(node_hit_at(child.as_ref(), x, y, cur_node_idx));
48 }
49 }
50
51 hits
52}
53
54fn build_stretch_node_recursive<MSG>(
55 stretch: &mut Stretch,
56 widget_node: &dyn Widget<MSG>,
57) -> Option<expanse::node::Node> {
58 let children_styles = if let Some(children) = widget_node.children() {
59 children
60 .iter()
61 .filter_map(|c| build_stretch_node_recursive(stretch, c.as_ref()))
62 .collect()
63 } else {
64 vec![]
65 };
66 let node_style = widget_node.style();
67 stretch.new_node(node_style, &children_styles).ok()
68}
69
70fn set_node_layout_from_stretch_node<MSG>(
71 widget_node: &mut dyn Widget<MSG>,
72 stretch_node: expanse::node::Node,
73 stretch: &Stretch,
74 parent_loc: (f32, f32),
75 parent_offset: (f32, f32),
76) {
77 let mut layout = *stretch.layout(stretch_node).expect("must have layout");
78
79 let (parent_loc_x, parent_loc_y) = parent_loc;
80 let (parent_offset_x, parent_offset_y) = parent_offset;
81 let (child_offset_x, child_offset_y) = widget_node.get_offset();
82
83 layout.location.x += parent_loc_x + parent_offset_x;
84 layout.location.y += parent_loc_y + parent_offset_y;
85
86 layout.size.width -= parent_offset_x;
87 layout.size.height -= parent_offset_y;
88
89 let stretch_node_children: Vec<expanse::node::Node> =
90 stretch.children(stretch_node).expect("must get children");
91
92 let widget_children = widget_node.children_mut().unwrap_or(&mut []);
93
94 stretch_node_children
95 .into_iter()
96 .zip(widget_children.iter_mut())
97 .for_each(|(stretch_node_child, widget_child)| {
98 set_node_layout_from_stretch_node(
99 widget_child.as_mut(),
100 stretch_node_child,
101 stretch,
102 (layout.location.x, layout.location.y),
103 (child_offset_x, child_offset_y),
104 )
105 });
106
107 widget_node.set_layout(layout);
108}