Skip to main content

fui/node/
grid.rs

1use super::core::*;
2use super::*;
3
4#[derive(Clone)]
5pub struct Grid {
6    base: FlexBox,
7    props: Rc<RefCell<GridProps>>,
8    placements: Rc<RefCell<Vec<(NodeRef, GridPlacement)>>>,
9}
10
11#[derive(Clone, Copy, Debug, PartialEq)]
12pub struct GridTrack {
13    pub value: f32,
14    pub unit: GridUnit,
15}
16
17impl GridTrack {
18    pub const fn px(value: f32) -> Self {
19        Self {
20            value,
21            unit: GridUnit::Pixel,
22        }
23    }
24
25    pub const fn star(value: f32) -> Self {
26        Self {
27            value,
28            unit: GridUnit::Star,
29        }
30    }
31
32    pub const fn auto() -> Self {
33        Self {
34            value: 0.0,
35            unit: GridUnit::Auto,
36        }
37    }
38}
39
40impl Default for Grid {
41    fn default() -> Self {
42        let base = FlexBox::default();
43        base.core.borrow_mut().kind = NodeKind::Grid;
44        Self {
45            base,
46            props: Rc::new(RefCell::new(GridProps::default())),
47            placements: Rc::new(RefCell::new(Vec::new())),
48        }
49    }
50}
51
52impl Node for Grid {
53    fn retained_node_ref(&self) -> NodeRef {
54        NodeRef::from_node(self.base.core.clone(), self.clone())
55    }
56
57    fn build_self(&self) {
58        self.base.build_self();
59        apply_grid_props(self.handle(), &self.props.borrow());
60    }
61
62    fn build_children(&self) {
63        self.base.build_children();
64        self.apply_grid_placements();
65    }
66}
67
68impl Grid {
69    pub fn shared_size_scope<T: Node>(target: &T, enabled: bool) {
70        let node = target.retained_node_ref();
71        node.set_shared_size_scope(enabled);
72        if target.has_built_handle() {
73            target.notify_retained_layout_mutation();
74        }
75    }
76
77    pub(crate) fn downgrade(&self) -> WeakFlexBox {
78        self.base.downgrade()
79    }
80
81    fn apply_grid_placements(&self) {
82        for (child, placement) in self.placements.borrow().iter() {
83            let handle = child.handle();
84            if handle != NodeHandle::INVALID {
85                ui::set_grid_placement(
86                    handle.raw(),
87                    placement.row,
88                    placement.col,
89                    placement.row_span,
90                    placement.col_span,
91                );
92            }
93        }
94    }
95
96    pub fn columns<I>(&self, tracks: I) -> &Self
97    where
98        I: IntoIterator<Item = GridTrack>,
99    {
100        let tracks: Vec<GridTrack> = tracks.into_iter().collect();
101        let mut props = self.props.borrow_mut();
102        props.columns = tracks.iter().map(|track| track.value).collect();
103        props.column_types = tracks.iter().map(|track| track.unit).collect();
104        drop(props);
105        if self.has_built_handle() {
106            self.build_self();
107            self.notify_retained_layout_mutation();
108        }
109        self
110    }
111
112    pub fn rows<I>(&self, tracks: I) -> &Self
113    where
114        I: IntoIterator<Item = GridTrack>,
115    {
116        let tracks: Vec<GridTrack> = tracks.into_iter().collect();
117        let mut props = self.props.borrow_mut();
118        props.rows = tracks.iter().map(|track| track.value).collect();
119        props.row_types = tracks.iter().map(|track| track.unit).collect();
120        drop(props);
121        if self.has_built_handle() {
122            self.build_self();
123            self.notify_retained_layout_mutation();
124        }
125        self
126    }
127
128    pub fn column_shared_size_group(&self, index: u32, group: impl Into<String>) -> &Self {
129        let group = group.into();
130        let mut props = self.props.borrow_mut();
131        if let Some((_, existing)) = props
132            .column_shared_size_groups
133            .iter_mut()
134            .find(|(existing_index, _)| *existing_index == index)
135        {
136            *existing = group;
137        } else {
138            props.column_shared_size_groups.push((index, group));
139        }
140        drop(props);
141        if self.has_built_handle() {
142            self.build_self();
143            self.notify_retained_layout_mutation();
144        }
145        self
146    }
147
148    pub fn clear_column_shared_size_group(&self, index: u32) -> &Self {
149        self.column_shared_size_group(index, "")
150    }
151
152    pub fn row_shared_size_group(&self, index: u32, group: impl Into<String>) -> &Self {
153        let group = group.into();
154        let mut props = self.props.borrow_mut();
155        if let Some((_, existing)) = props
156            .row_shared_size_groups
157            .iter_mut()
158            .find(|(existing_index, _)| *existing_index == index)
159        {
160            *existing = group;
161        } else {
162            props.row_shared_size_groups.push((index, group));
163        }
164        drop(props);
165        if self.has_built_handle() {
166            self.build_self();
167            self.notify_retained_layout_mutation();
168        }
169        self
170    }
171
172    pub fn clear_row_shared_size_group(&self, index: u32) -> &Self {
173        self.row_shared_size_group(index, "")
174    }
175
176    pub fn place_child<T: Node>(
177        &self,
178        child: &T,
179        row: u32,
180        col: u32,
181        row_span: u32,
182        col_span: u32,
183    ) -> &Self {
184        self.append_child(child);
185        self.placements.borrow_mut().push((
186            child.node_ref(),
187            GridPlacement {
188                row,
189                col,
190                row_span,
191                col_span,
192            },
193        ));
194        if self.has_built_handle() {
195            self.apply_grid_placements();
196        }
197        self
198    }
199}
200
201impl HasFlexBoxRoot for Grid {
202    fn flex_box_root(&self) -> &FlexBox {
203        &self.base
204    }
205}
206
207impl ThemeBindable for Grid {
208    fn theme_binding_node(&self) -> NodeRef {
209        self.retained_node_ref()
210    }
211
212    fn weak_theme_target(&self) -> Box<dyn Fn() -> Option<Self>> {
213        let base = self.base.downgrade();
214        let props = Rc::downgrade(&self.props);
215        let placements = Rc::downgrade(&self.placements);
216        Box::new(move || {
217            Some(Self {
218                base: base.upgrade()?,
219                props: props.upgrade()?,
220                placements: placements.upgrade()?,
221            })
222        })
223    }
224}