xref: /StarryEngine/starry_toolkit/src/layout/grid.rs (revision 8a41b76c5717dfb7ea5d2beaed20030c10ffce86)
1 use std::{
2     cell::{Cell, RefCell},
3     collections::BTreeMap,
4     sync::Arc,
5 };
6 
7 use starry_client::base::renderer::Renderer;
8 
9 use crate::{
10     base::{event::Event, rect::Rect, vector2::Vector2},
11     traits::{enter::Enter, focus::Focus},
12     widgets::{PivotType, Widget},
13 };
14 
15 /// 网格排列方式
16 #[derive(PartialEq, Copy, Clone)]
17 pub enum GridArrangeType {
18     /// 优先横向排列
19     Horizontal,
20     /// 优先纵向排列
21     Vertical,
22 }
23 
24 pub struct Grid {
25     pub rect: Cell<Rect>,
26     pivot: Cell<PivotType>,
27     pivot_offset: Cell<Vector2>,
28     children: RefCell<Vec<Arc<dyn Widget>>>,
29     parent: RefCell<Option<Arc<dyn Widget>>>,
30     /// x坐标间隔
31     space_x: Cell<i32>,
32     /// y坐标间隔
33     space_y: Cell<i32>,
34     /// 每行/列的最大元素数
35     upper_limit: Cell<usize>,
36     /// 当前行数
37     pub current_row: Cell<usize>,
38     /// 当前列数
39     pub current_column: Cell<usize>,
40     /// 当前最大行数
41     pub max_row: Cell<usize>,
42     /// 当前最大列数
43     pub max_column: Cell<usize>,
44     /// 元素字典
45     pub elements: RefCell<BTreeMap<(usize, usize), Arc<dyn Widget>>>,
46     /// 当前选中的元素id(行列号)
47     pub focused_id: Cell<Option<(usize, usize)>>,
48     /// 当前聚焦的widget
49     pub focused_widget: RefCell<Option<Arc<dyn Widget>>>,
50     /// 优先排列方式
51     arrange_type: Cell<GridArrangeType>,
52     /// 键盘输入回调
53     enter_callback: RefCell<Option<Arc<dyn Fn(&Self, char, &mut bool)>>>,
54 }
55 
56 impl Grid {
57     pub fn new() -> Arc<Self> {
58         Arc::new(Grid {
59             rect: Cell::new(Rect::default()),
60             pivot: Cell::new(PivotType::TopLeft),
61             pivot_offset: Cell::new(Vector2::new(0, 0)),
62             children: RefCell::new(vec![]),
63             parent: RefCell::new(None),
64             space_x: Cell::new(0),
65             space_y: Cell::new(0),
66             upper_limit: Cell::new(0),
67             current_row: Cell::new(0),
68             current_column: Cell::new(0),
69             max_row: Cell::new(0),
70             max_column: Cell::new(0),
71             elements: RefCell::new(BTreeMap::new()),
72             focused_id: Cell::new(None),
73             focused_widget: RefCell::new(None),
74             arrange_type: Cell::new(GridArrangeType::Vertical),
75             enter_callback: RefCell::new(None),
76         })
77     }
78 
79     /// 设置每行/列最大元素数量(取决于行/列优先排列)
80     pub fn set_upper_limit(&self, columns: usize) -> &Self {
81         self.upper_limit.set(columns);
82         self
83     }
84 
85     pub fn set_arrange_type(&self, arrange_type: GridArrangeType) -> &Self {
86         self.arrange_type.set(arrange_type);
87         self
88     }
89 
90     pub fn add<T: Widget>(&self, element: &Arc<T>) -> (usize, usize) {
91         self.find_next_slot();
92         self.elements.borrow_mut().insert(
93             (self.current_row.get(), self.current_column.get()),
94             element.clone(),
95         );
96         let res = (self.current_row.get(), self.current_column.get());
97         self.move_index();
98         self.arrange_elements(false);
99         return res;
100     }
101 
102     /// 找到下一个可放置元素的位置
103     fn find_next_slot(&self) {
104         let elements = self.elements.borrow();
105         while elements.contains_key(&(self.current_row.get(), self.current_column.get())) {
106             self.move_index();
107         }
108     }
109 
110     fn move_index(&self) {
111         match self.arrange_type.get() {
112             GridArrangeType::Horizontal => {
113                 self.current_column.set(self.current_column.get() + 1);
114 
115                 if self.current_column.get() == self.upper_limit.get() {
116                     self.current_row.set(self.current_row.get() + 1);
117                     self.current_column.set(0);
118                 }
119             }
120             GridArrangeType::Vertical => {
121                 self.current_row.set(self.current_row.get() + 1);
122 
123                 if self.current_row.get() == self.upper_limit.get() {
124                     self.current_column.set(self.current_column.get() + 1);
125                     self.current_row.set(0);
126                 }
127             }
128         }
129     }
130 
131     pub fn insert<T: Widget>(&self, column: usize, row: usize, element: &Arc<T>) {
132         self.elements
133             .borrow_mut()
134             .insert((row, column), element.clone());
135 
136         self.arrange_elements(false);
137     }
138 
139     pub fn remove(&self, column: usize, row: usize) {
140         self.elements.borrow_mut().remove(&(row, column));
141     }
142 
143     pub fn set_space(&self, x: i32, y: i32) -> &Self {
144         self.space_x.set(x);
145         self.space_y.set(y);
146         self
147     }
148 
149     // TODO 注释补充
150     pub fn arrange_elements(&self, resize_children: bool) {
151         if self.elements.borrow().is_empty() {
152             return;
153         }
154 
155         self.arrange_self();
156 
157         let mut cols = Vec::new();
158         let mut rows = Vec::new();
159         for (&(row, col), entry) in self.elements.borrow().iter() {
160             while col >= cols.len() {
161                 cols.push(Rect::default());
162             }
163             while row >= rows.len() {
164                 rows.push(Rect::default());
165             }
166             let rect = entry.rect().get();
167             if rect.width >= cols[col].width {
168                 cols[col as usize].width = rect.width;
169             }
170             if rect.width >= rows[row].width {
171                 rows[row as usize].width = rect.width;
172             }
173             if rect.height >= cols[col].height {
174                 cols[col as usize].height = rect.height;
175             }
176             if rect.height >= rows[row].height {
177                 rows[row as usize].height = rect.height;
178             }
179         }
180 
181         self.max_row.set(rows.len());
182         self.max_column.set(cols.len());
183 
184         let space_x = self.space_x.get();
185         let space_y = self.space_y.get();
186 
187         let mut x = 0;
188         for col in cols.iter_mut() {
189             col.x = x;
190             x += col.width as i32 + space_x;
191         }
192 
193         let mut y = 0;
194         for row in rows.iter_mut() {
195             row.y = y;
196             y += row.height as i32 + space_y;
197         }
198 
199         let grid_width = cols.len() as i32 * (cols[0].width as i32 + space_x) - space_x;
200         let grid_height = rows.len() as i32 * (rows[0].width as i32 + space_y) - space_y;
201         self.resize(grid_width as u32, grid_height as u32);
202 
203         for (&(row, col), child) in self.elements.borrow().iter() {
204             child.set_pivot_type(PivotType::TopLeft);
205             child.set_pivot_offset(Vector2::new(cols[col].x, rows[row].y));
206             if resize_children {
207                 child.resize(cols[col].width, rows[row].height);
208             }
209 
210             child.arrange_all();
211         }
212     }
213 
214     pub fn clear(&self) {
215         self.children.borrow_mut().clear();
216         self.elements.borrow_mut().clear();
217         self.current_column.set(0);
218         self.current_row.set(0);
219     }
220 }
221 
222 impl Widget for Grid {
223     fn name(&self) -> &str {
224         "Grid"
225     }
226 
227     fn rect(&self) -> &Cell<Rect> {
228         &self.rect
229     }
230 
231     fn pivot(&self) -> &Cell<PivotType> {
232         &self.pivot
233     }
234 
235     fn pivot_offset(&self) -> &Cell<Vector2> {
236         &self.pivot_offset
237     }
238 
239     fn parent(&self) -> &RefCell<Option<Arc<dyn Widget>>> {
240         &self.parent
241     }
242 
243     fn children(&self) -> &RefCell<Vec<Arc<dyn Widget>>> {
244         &self.children
245     }
246 
247     fn draw(&self, renderer: &mut dyn Renderer, _focused: bool) {
248         for (&(_row, _col), widget) in self.elements.borrow().iter() {
249             widget.update();
250             widget.draw(renderer, self.is_focused(widget));
251         }
252     }
253 
254     fn handle_event(
255         &self,
256         event: Event,
257         _focused: bool,
258         redraw: &mut bool,
259         caught: &mut bool,
260     ) -> bool {
261         match event {
262             Event::KeyPressed { character, .. } => {
263                 if let Some(character) = character {
264                     self.emit_enter(character, redraw);
265                 }
266 
267                 *caught = true;
268             }
269             // TODO
270             _ => {}
271         }
272         false
273     }
274 }
275 
276 impl Focus for Grid {
277     fn focused_widget(&self) -> RefCell<Option<Arc<dyn Widget>>> {
278         self.focused_widget.clone()
279     }
280 
281     fn focus(&self, widget: &Arc<dyn Widget>) {
282         (*self.focused_widget.borrow_mut()) = Some(widget.clone());
283     }
284 }
285 
286 impl Enter for Grid {
287     fn emit_enter(&self, char: char, redraw: &mut bool) {
288         if let Some(ref enter_callback) = *self.enter_callback.borrow() {
289             enter_callback(self, char, redraw);
290         }
291     }
292 
293     fn set_enter_callback<T: Fn(&Self, char, &mut bool) + 'static>(&self, func: T) {
294         (*self.enter_callback.borrow_mut()) = Some(Arc::new(func));
295     }
296 }
297