|
@@ -0,0 +1,217 @@
|
|
|
|
+use std::{
|
|
|
|
+ cell::{Cell, RefCell},
|
|
|
|
+ collections::BTreeMap,
|
|
|
|
+ sync::Arc,
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+use starry_client::base::renderer::Renderer;
|
|
|
|
+
|
|
|
|
+use crate::{
|
|
|
|
+ base::{point::Point, rect::Rect},
|
|
|
|
+ traits::{focus::Focus, transform::Transform},
|
|
|
|
+ widgets::{HorizontalPlacement, VerticalPlacement, Widget},
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+pub struct Grid {
|
|
|
|
+ pub rect: Cell<Rect>,
|
|
|
|
+ local_position: Cell<Point>,
|
|
|
|
+ vertical_placement: Cell<VerticalPlacement>,
|
|
|
|
+ horizontal_placement: Cell<HorizontalPlacement>,
|
|
|
|
+ children: RefCell<Vec<Arc<dyn Widget>>>,
|
|
|
|
+ /// x坐标间隔
|
|
|
|
+ space_x: Cell<i32>,
|
|
|
|
+ /// y坐标间隔
|
|
|
|
+ space_y: Cell<i32>,
|
|
|
|
+ /// 每行的最大列数
|
|
|
|
+ max_columns: Cell<usize>,
|
|
|
|
+ /// 当前行数
|
|
|
|
+ current_row: Cell<usize>,
|
|
|
|
+ /// 当前列数
|
|
|
|
+ current_column: Cell<usize>,
|
|
|
|
+ /// 元素字典
|
|
|
|
+ elements: RefCell<BTreeMap<(usize, usize), Arc<dyn Widget>>>,
|
|
|
|
+ /// 当前选中的元素id(行列号)
|
|
|
|
+ focused_id: Cell<Option<(usize, usize)>>,
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+impl Grid {
|
|
|
|
+ pub fn new() -> Arc<Self> {
|
|
|
|
+ Arc::new(Grid {
|
|
|
|
+ rect: Cell::new(Rect::default()),
|
|
|
|
+ local_position: Cell::new(Point::new(0, 0)),
|
|
|
|
+ vertical_placement: Cell::new(VerticalPlacement::Absolute),
|
|
|
|
+ horizontal_placement: Cell::new(HorizontalPlacement::Absolute),
|
|
|
|
+ children: RefCell::new(vec![]),
|
|
|
|
+ space_x: Cell::new(0),
|
|
|
|
+ space_y: Cell::new(0),
|
|
|
|
+ max_columns: Cell::new(0),
|
|
|
|
+ current_row: Cell::new(0),
|
|
|
|
+ current_column: Cell::new(0),
|
|
|
|
+ elements: RefCell::new(BTreeMap::new()),
|
|
|
|
+ focused_id: Cell::new(None),
|
|
|
|
+ })
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /// 设置最大列数
|
|
|
|
+ pub fn set_max_columns(&self, columns: usize) -> &Self {
|
|
|
|
+ self.max_columns.set(columns);
|
|
|
|
+ self
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ pub fn add<T: Widget>(&self, element: &Arc<T>) {
|
|
|
|
+ if self.current_column.get() == self.max_columns.get() {
|
|
|
|
+ self.current_row.set(self.current_row.get() + 1);
|
|
|
|
+ self.current_column.set(0);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ self.elements.borrow_mut().insert(
|
|
|
|
+ (self.current_row.get(), self.current_column.get()),
|
|
|
|
+ element.clone(),
|
|
|
|
+ );
|
|
|
|
+ self.current_column.set(self.current_column.get() + 1);
|
|
|
|
+ self.arrange(false);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ pub fn insert<T: Widget>(&self, column: usize, row: usize, element: &Arc<T>) {
|
|
|
|
+ self.elements
|
|
|
|
+ .borrow_mut()
|
|
|
|
+ .insert((row, column), element.clone());
|
|
|
|
+
|
|
|
|
+ self.arrange(false);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ pub fn clear(&self) {
|
|
|
|
+ self.elements.borrow_mut().clear();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ pub fn remove(&self, column: usize, row: usize) {
|
|
|
|
+ self.elements.borrow_mut().remove(&(row, column));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ pub fn set_space(&self, x: i32, y: i32) -> &Self {
|
|
|
|
+ self.space_x.set(x);
|
|
|
|
+ self.space_y.set(y);
|
|
|
|
+ self
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ pub fn arrange(&self, resize_children: bool) {
|
|
|
|
+ let mut cols = Vec::new();
|
|
|
|
+ let mut rows = Vec::new();
|
|
|
|
+ for (&(col, row), entry) in self.elements.borrow().iter() {
|
|
|
|
+ while col >= cols.len() {
|
|
|
|
+ cols.push(Rect::default());
|
|
|
|
+ }
|
|
|
|
+ while row >= rows.len() {
|
|
|
|
+ rows.push(Rect::default());
|
|
|
|
+ }
|
|
|
|
+ let rect = entry.rect().get();
|
|
|
|
+ if rect.width >= cols[col].width {
|
|
|
|
+ cols[col as usize].width = rect.width;
|
|
|
|
+ }
|
|
|
|
+ if rect.width >= rows[row].width {
|
|
|
|
+ rows[row as usize].width = rect.width;
|
|
|
|
+ }
|
|
|
|
+ if rect.height >= cols[col].height {
|
|
|
|
+ cols[col as usize].height = rect.height;
|
|
|
|
+ }
|
|
|
|
+ if rect.height >= rows[row].height {
|
|
|
|
+ rows[row as usize].height = rect.height;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ let rect = self.rect.get();
|
|
|
|
+ let space_x = self.space_x.get();
|
|
|
|
+ let space_y = self.space_y.get();
|
|
|
|
+
|
|
|
|
+ let mut x = rect.x;
|
|
|
|
+ for col in cols.iter_mut() {
|
|
|
|
+ col.x = x;
|
|
|
|
+ x += col.width as i32 + space_x;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ let mut y = rect.y;
|
|
|
|
+ for row in rows.iter_mut() {
|
|
|
|
+ row.y = y;
|
|
|
|
+ y += row.height as i32 + space_y;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ for (&(col, row), child) in self.elements.borrow().iter() {
|
|
|
|
+ let mut rect = child.rect().get();
|
|
|
|
+ rect.x = cols[col].x;
|
|
|
|
+ rect.y = rows[row].y;
|
|
|
|
+ if resize_children {
|
|
|
|
+ rect.width = cols[col].width;
|
|
|
|
+ rect.height = rows[row].height;
|
|
|
|
+ }
|
|
|
|
+ child.rect().set(rect);
|
|
|
|
+
|
|
|
|
+ child.arrange();
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+impl Widget for Grid {
|
|
|
|
+ fn name(&self) -> &str {
|
|
|
|
+ "Grid"
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ fn rect(&self) -> &Cell<Rect> {
|
|
|
|
+ &self.rect
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ fn local_position(&self) -> &Cell<Point> {
|
|
|
|
+ &self.local_position
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ fn vertical_placement(&self) -> &Cell<VerticalPlacement> {
|
|
|
|
+ &self.vertical_placement
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ fn horizontal_placement(&self) -> &Cell<HorizontalPlacement> {
|
|
|
|
+ &self.horizontal_placement
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ fn children(&self) -> &RefCell<Vec<Arc<dyn Widget>>> {
|
|
|
|
+ &self.children
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ fn draw(&self, renderer: &mut dyn Renderer, _focused: bool) {
|
|
|
|
+ fn draw_widget(widget: &Arc<dyn Widget>, renderer: &mut dyn Renderer, focused: bool) {
|
|
|
|
+ widget.update();
|
|
|
|
+ widget.draw(renderer, focused);
|
|
|
|
+
|
|
|
|
+ for child in widget.children().borrow().iter() {
|
|
|
|
+ draw_widget(child, renderer, focused);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ for (&(_col, _row), widget) in self.elements.borrow().iter() {
|
|
|
|
+ draw_widget(widget, renderer, self.is_focused(widget));
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+impl Transform for Grid {
|
|
|
|
+ fn reposition(&self, x: i32, y: i32) -> &Self {
|
|
|
|
+ let mut rect = self.rect().get();
|
|
|
|
+ rect.x = x;
|
|
|
|
+ rect.y = y;
|
|
|
|
+ self.rect.set(rect);
|
|
|
|
+
|
|
|
|
+ self.arrange(false);
|
|
|
|
+
|
|
|
|
+ self
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+impl Focus for Grid {
|
|
|
|
+ fn focused_widget(&self) -> RefCell<Option<Arc<dyn Widget>>> {
|
|
|
|
+ if let Some((row, column)) = self.focused_id.get() {
|
|
|
|
+ if let Some(widget) = self.elements.borrow().get(&(row, column)) {
|
|
|
|
+ return RefCell::new(Some((*widget).clone()));
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return RefCell::new(None);
|
|
|
|
+ }
|
|
|
|
+}
|