titik/
layout.rs

1use crate::Widget;
2use expanse::geometry::Size;
3use expanse::number::Number;
4use expanse::Stretch;
5use mt_dom::attr;
6
7/// calculate the layout of the nodes utilizing the styles set on each of the widget
8/// and its children widget styles
9pub(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}