use std::{ any::Any, cell::{Cell, RefCell}, collections::BTreeMap, sync::{Arc, Weak}, }; use starry_client::base::renderer::Renderer; use crate::{ base::{panel::Panel, rect::Rect, vector2::Vector2}, traits::focus::Focus, widgets::{PivotType, Widget}, }; #[derive(PartialEq, Copy, Clone)] pub enum ListArrangeType { /// 横向排列 Horizontal, /// 纵向排列 Vertical, } #[derive(PartialEq, Copy, Clone)] pub enum ListElementPivotType { LeftOrTop, Center, RightOrBottom, } pub struct List { self_ref: RefCell>, rect: Cell, pivot: Cell, pivot_offset: Cell, children: RefCell>>, parent: RefCell>>, panel: RefCell>>, space: Cell, current_index: Cell, elements: RefCell>>, focused_id: Cell>, focused_widget: RefCell>>, arrange_type: Cell, element_pivot_type: Cell, } impl List { pub fn new() -> Arc { let list = Arc::new(List { self_ref: RefCell::new(Weak::default()), rect: Cell::new(Rect::default()), pivot: Cell::new(PivotType::TopLeft), pivot_offset: Cell::new(Vector2::new(0, 0)), children: RefCell::new(vec![]), parent: RefCell::new(None), panel: RefCell::new(None), space: Cell::new(0), current_index: Cell::new(0), elements: RefCell::new(BTreeMap::new()), focused_id: Cell::new(None), focused_widget: RefCell::new(None), arrange_type: Cell::new(ListArrangeType::Vertical), element_pivot_type: Cell::new(ListElementPivotType::Center), }); (*list.self_ref.borrow_mut()) = Arc::downgrade(&list); return list; } pub fn set_arrange_type(&self, arrange_type: ListArrangeType) -> &Self { self.arrange_type.set(arrange_type); self } pub fn set_space(&self, space: u32) -> &Self { self.space.set(space); self } pub fn add_element(&self, element: &Arc) -> usize { self.add_child(element.self_ref()); self.elements .borrow_mut() .insert(self.current_index.get(), element.clone()); let res = self.current_index.get(); self.current_index.set(res + 1); self.arrange_elements(); return res; } pub fn arrange_elements(&self) { if self.elements.borrow().is_empty() { return; } self.arrange_self(); // 遍历找到最大的长或宽值 let mut max_size: u32 = 0; for (&_index, element) in self.elements.borrow().iter() { match self.arrange_type.get() { ListArrangeType::Horizontal => { max_size = u32::max(max_size, element.rect().get().height); } ListArrangeType::Vertical => { max_size = u32::max(max_size, element.rect().get().width); } } } let mut x_offset: u32 = 0; let mut y_offset: u32 = 0; for (&_index, element) in self.elements.borrow().iter() { let align_vector: Vector2; match self.arrange_type.get() { ListArrangeType::Horizontal => { align_vector = match self.element_pivot_type.get() { ListElementPivotType::LeftOrTop => { Vector2::new(x_offset as i32, y_offset as i32) } ListElementPivotType::Center => Vector2::new( x_offset as i32, y_offset as i32 + (max_size - element.rect().get().height) as i32 / 2, ), ListElementPivotType::RightOrBottom => Vector2::new( x_offset as i32, y_offset as i32 + (max_size - element.rect().get().height) as i32, ), }; } ListArrangeType::Vertical => { align_vector = match self.element_pivot_type.get() { ListElementPivotType::LeftOrTop => { Vector2::new(x_offset as i32, y_offset as i32) } ListElementPivotType::Center => Vector2::new( x_offset as i32 + (max_size - element.rect().get().width) as i32 / 2, y_offset as i32, ), ListElementPivotType::RightOrBottom => Vector2::new( x_offset as i32 + (max_size - element.rect().get().width) as i32, y_offset as i32, ), } } } element.set_pivot_type(PivotType::TopLeft); element.set_pivot_offset(align_vector); element.arrange_all(); match self.arrange_type.get() { ListArrangeType::Horizontal => { x_offset += element.rect().get().width + self.space.get(); } ListArrangeType::Vertical => { y_offset += element.rect().get().height + self.space.get(); } } } } } impl Widget for List { fn self_ref(&self) -> Arc { self.self_ref.borrow().upgrade().unwrap() } fn as_any_ref(&self) -> &dyn Any { self } fn name(&self) -> &str { "List" } fn rect(&self) -> &Cell { &self.rect } fn pivot(&self) -> &Cell { &self.pivot } fn pivot_offset(&self) -> &Cell { &self.pivot_offset } fn parent(&self) -> &RefCell>> { &self.parent } fn children(&self) -> &RefCell>> { &self.children } fn panel(&self) -> &RefCell>> { &self.panel } fn draw(&self, renderer: &mut dyn Renderer, _focused: bool) { for (&_index, widget) in self.elements.borrow().iter() { widget.update(); widget.draw(renderer, self.is_focused(widget)); } } fn handle_event( &self, _event: crate::base::event::Event, _focused: bool, _redraw: &Cell, _caught: &Cell, ) -> bool { false } } impl Focus for List { fn focused_widget(&self) -> RefCell>> { self.focused_widget.clone() } fn focus(&self, focused_widget: &Arc) { // 同时更新focused_id for (&index, widget) in self.elements.borrow().iter() { if Arc::ptr_eq(widget, focused_widget) { self.focused_id.set(Some(index)); (*self.focused_widget.borrow_mut()) = Some(focused_widget.clone()); } } } }