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}