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