xref: /StarryEngine/starry_toolkit/src/layout/grid.rs (revision 49182ea7bc0263215864dd04cd265e345a4af8f5)
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::{point::Point, rect::Rect},
11     traits::{focus::Focus, transform::Transform},
12     widgets::{HorizontalPlacement, VerticalPlacement, Widget},
13 };
14 
15 pub struct Grid {
16     pub rect: Cell<Rect>,
17     local_position: Cell<Point>,
18     vertical_placement: Cell<VerticalPlacement>,
19     horizontal_placement: Cell<HorizontalPlacement>,
20     children: RefCell<Vec<Arc<dyn Widget>>>,
21     /// x坐标间隔
22     space_x: Cell<i32>,
23     /// y坐标间隔
24     space_y: Cell<i32>,
25     /// 每行的最大列数
26     max_columns: Cell<usize>,
27     /// 当前行数
28     current_row: Cell<usize>,
29     /// 当前列数
30     current_column: Cell<usize>,
31     /// 元素字典
32     pub elements: RefCell<BTreeMap<(usize, usize), Arc<dyn Widget>>>,
33     /// 当前选中的元素id(行列号)
34     pub focused_id: Cell<Option<(usize, usize)>>,
35     /// 当前聚焦的widget
36     pub focused_widget: RefCell<Option<Arc<dyn Widget>>>,
37 }
38 
39 impl Grid {
40     pub fn new() -> Arc<Self> {
41         Arc::new(Grid {
42             rect: Cell::new(Rect::default()),
43             local_position: Cell::new(Point::new(0, 0)),
44             vertical_placement: Cell::new(VerticalPlacement::Absolute),
45             horizontal_placement: Cell::new(HorizontalPlacement::Absolute),
46             children: RefCell::new(vec![]),
47             space_x: Cell::new(0),
48             space_y: Cell::new(0),
49             max_columns: Cell::new(0),
50             current_row: Cell::new(0),
51             current_column: Cell::new(0),
52             elements: RefCell::new(BTreeMap::new()),
53             focused_id: Cell::new(None),
54             focused_widget: RefCell::new(None),
55         })
56     }
57 
58     /// 设置最大列数
59     pub fn set_max_columns(&self, columns: usize) -> &Self {
60         self.max_columns.set(columns);
61         self
62     }
63 
64     pub fn add<T: Widget>(&self, element: &Arc<T>) {
65         if self.current_column.get() == self.max_columns.get() {
66             self.current_row.set(self.current_row.get() + 1);
67             self.current_column.set(0);
68         }
69 
70         self.elements.borrow_mut().insert(
71             (self.current_row.get(), self.current_column.get()),
72             element.clone(),
73         );
74         self.current_column.set(self.current_column.get() + 1);
75         self.arrange(false);
76     }
77 
78     pub fn insert<T: Widget>(&self, column: usize, row: usize, element: &Arc<T>) {
79         self.elements
80             .borrow_mut()
81             .insert((row, column), element.clone());
82 
83         self.arrange(false);
84     }
85 
86     pub fn clear(&self) {
87         self.elements.borrow_mut().clear();
88     }
89 
90     pub fn remove(&self, column: usize, row: usize) {
91         self.elements.borrow_mut().remove(&(row, column));
92     }
93 
94     pub fn set_space(&self, x: i32, y: i32) -> &Self {
95         self.space_x.set(x);
96         self.space_y.set(y);
97         self
98     }
99 
100     pub fn arrange(&self, resize_children: bool) {
101         let mut cols = Vec::new();
102         let mut rows = Vec::new();
103         for (&(col, row), entry) in self.elements.borrow().iter() {
104             while col >= cols.len() {
105                 cols.push(Rect::default());
106             }
107             while row >= rows.len() {
108                 rows.push(Rect::default());
109             }
110             let rect = entry.rect().get();
111             if rect.width >= cols[col].width {
112                 cols[col as usize].width = rect.width;
113             }
114             if rect.width >= rows[row].width {
115                 rows[row as usize].width = rect.width;
116             }
117             if rect.height >= cols[col].height {
118                 cols[col as usize].height = rect.height;
119             }
120             if rect.height >= rows[row].height {
121                 rows[row as usize].height = rect.height;
122             }
123         }
124 
125         let rect = self.rect.get();
126         let space_x = self.space_x.get();
127         let space_y = self.space_y.get();
128 
129         let mut x = rect.x;
130         for col in cols.iter_mut() {
131             col.x = x;
132             x += col.width as i32 + space_x;
133         }
134 
135         let mut y = rect.y;
136         for row in rows.iter_mut() {
137             row.y = y;
138             y += row.height as i32 + space_y;
139         }
140 
141         for (&(col, row), child) in self.elements.borrow().iter() {
142             let mut rect = child.rect().get();
143             rect.x = cols[col].x;
144             rect.y = rows[row].y;
145             if resize_children {
146                 rect.width = cols[col].width;
147                 rect.height = rows[row].height;
148             }
149             child.rect().set(rect);
150 
151             child.arrange();
152         }
153     }
154 }
155 
156 impl Widget for Grid {
157     fn name(&self) -> &str {
158         "Grid"
159     }
160 
161     fn rect(&self) -> &Cell<Rect> {
162         &self.rect
163     }
164 
165     fn local_position(&self) -> &Cell<Point> {
166         &self.local_position
167     }
168 
169     fn vertical_placement(&self) -> &Cell<VerticalPlacement> {
170         &self.vertical_placement
171     }
172 
173     fn horizontal_placement(&self) -> &Cell<HorizontalPlacement> {
174         &self.horizontal_placement
175     }
176 
177     fn children(&self) -> &RefCell<Vec<Arc<dyn Widget>>> {
178         &self.children
179     }
180 
181     fn draw(&self, renderer: &mut dyn Renderer, _focused: bool) {
182         fn draw_widget(widget: &Arc<dyn Widget>, renderer: &mut dyn Renderer, focused: bool) {
183             widget.update();
184             widget.draw(renderer, focused);
185 
186             for child in widget.children().borrow().iter() {
187                 draw_widget(child, renderer, focused);
188             }
189         }
190 
191         for (&(_col, _row), widget) in self.elements.borrow().iter() {
192             draw_widget(widget, renderer, self.is_focused(widget));
193         }
194     }
195 }
196 
197 impl Transform for Grid {
198     fn reposition(&self, x: i32, y: i32) -> &Self {
199         let mut rect = self.rect().get();
200         rect.x = x;
201         rect.y = y;
202         self.rect.set(rect);
203 
204         self.arrange(false);
205 
206         self
207     }
208 }
209 
210 impl Focus for Grid {
211     fn focused_widget(&self) -> RefCell<Option<Arc<dyn Widget>>> {
212         self.focused_widget.clone()
213     }
214 
215     fn focus(&self, widget: &Arc<dyn Widget>) {
216         (*self.focused_widget.borrow_mut()) = Some(widget.clone());
217     }
218 }
219