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