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