1 use std::{ 2 any::Any, 3 cell::{Cell, RefCell}, 4 sync::Arc, 5 }; 6 7 use starry_client::base::renderer::Renderer; 8 use starry_server::core::{SCREEN_HEIGHT, SCREEN_WIDTH}; 9 10 use crate::{ 11 base::{event::Event, panel::Panel, rect::Rect, vector2::Vector2}, 12 util::{align_rect, widget_set_panel}, 13 }; 14 15 pub mod image; 16 pub mod label; 17 18 /// 控件对齐类型 19 #[derive(PartialEq, Copy, Clone, Debug)] 20 pub enum PivotType { 21 /// 不进行对齐 pivot_offset即为世界坐标 22 None, 23 /// 对齐左上角(默认对齐方式,这是由于矩形位置通过左上角顶点坐标来表示) 24 TopLeft, 25 /// 对齐正上方 26 Top, 27 /// 对齐右上角 28 TopRight, 29 /// 对齐正左方 30 Left, 31 /// 对齐中心 32 Center, 33 /// 对齐正右方 34 Right, 35 /// 对齐左下角 36 BottomLeft, 37 /// 对齐正下方 38 Bottom, 39 /// 对齐右下角 40 BottomRight, 41 } 42 43 /// UI组件需要实现的特性 44 pub trait Widget: Any { 45 /// 返回自身指针 self_ref(&self) -> Arc<dyn Widget>46 fn self_ref(&self) -> Arc<dyn Widget>; 47 48 /// 返回Any引用 as_any_ref(&self) -> &dyn Any49 fn as_any_ref(&self) -> &dyn Any; 50 51 /// 返回渲染的矩形区域 rect(&self) -> &Cell<Rect>52 fn rect(&self) -> &Cell<Rect>; 53 54 /// 对齐方式 pivot(&self) -> &Cell<PivotType>55 fn pivot(&self) -> &Cell<PivotType>; 56 57 /// 基于基准点的偏移量 pivot_offset(&self) -> &Cell<Vector2>58 fn pivot_offset(&self) -> &Cell<Vector2>; 59 60 /// 所属面板 panel(&self) -> &RefCell<Option<Arc<Panel>>>61 fn panel(&self) -> &RefCell<Option<Arc<Panel>>>; 62 63 /// 返回组件的名字 name(&self) -> &str64 fn name(&self) -> &str; 65 66 /// 返回子组件数组 children(&self) -> &RefCell<Vec<Arc<dyn Widget>>>67 fn children(&self) -> &RefCell<Vec<Arc<dyn Widget>>>; 68 69 /// 父物体 parent(&self) -> &RefCell<Option<Arc<dyn Widget>>>70 fn parent(&self) -> &RefCell<Option<Arc<dyn Widget>>>; 71 72 /// 添加子物体 add_child(&self, widget: Arc<dyn Widget>)73 fn add_child(&self, widget: Arc<dyn Widget>) { 74 self.children().borrow_mut().push(widget.clone()); 75 76 // 赋值父物体 77 (*widget.parent().borrow_mut()) = Some(self.self_ref()); 78 79 // 赋值所属的面板 80 if self.panel().borrow().is_some() { 81 widget_set_panel(&widget, &self.panel().borrow().clone().unwrap()); 82 } 83 } 84 85 /// 渲染组件 draw(&self, renderer: &mut dyn Renderer, focused: bool)86 fn draw(&self, renderer: &mut dyn Renderer, focused: bool); 87 88 /// 更新组件状态 update(&self)89 fn update(&self) {} 90 91 /// 处理输入事件 handle_event( &self, _event: Event, _focused: bool, _redraw: &Cell<bool>, _caught: &Cell<bool>, ) -> bool92 fn handle_event( 93 &self, 94 _event: Event, 95 _focused: bool, 96 _redraw: &Cell<bool>, 97 _caught: &Cell<bool>, 98 ) -> bool { 99 false 100 } 101 set_pivot_type(&self, pivot_type: PivotType)102 fn set_pivot_type(&self, pivot_type: PivotType) { 103 self.set_pivot_type_base(pivot_type); 104 } 105 106 /// 修改对齐方式的统一处理 方便覆写 set_pivot_type_base(&self, pivot_type: PivotType)107 fn set_pivot_type_base(&self, pivot_type: PivotType) { 108 self.pivot().set(pivot_type); 109 self.arrange_all(); 110 } 111 set_pivot_offset(&self, pivot_offset: Vector2)112 fn set_pivot_offset(&self, pivot_offset: Vector2) { 113 self.set_pivot_offset_base(pivot_offset); 114 } 115 116 /// 修改对齐偏移量的统一处理 方便覆写 set_pivot_offset_base(&self, pivot_offset: Vector2)117 fn set_pivot_offset_base(&self, pivot_offset: Vector2) { 118 self.pivot_offset().set(pivot_offset); 119 self.arrange_all(); 120 } 121 resize(&self, width: u32, height: u32)122 fn resize(&self, width: u32, height: u32) { 123 self.resize_base(width, height); 124 } 125 126 /// 修改大小时的统一处理 方便覆写 resize_base(&self, width: u32, height: u32)127 fn resize_base(&self, width: u32, height: u32) { 128 let mut rect = self.rect().get(); 129 rect.width = width; 130 rect.height = height; 131 self.rect().set(rect); 132 self.arrange_all(); 133 } 134 135 /// 重新排布自身和子对象的位置 arrange_all(&self)136 fn arrange_all(&self) { 137 self.arrange_self(); 138 139 for child in self.children().borrow_mut().iter() { 140 child.arrange_all(); 141 } 142 } 143 arrange_self(&self)144 fn arrange_self(&self) { 145 self.arrange_self_base(); 146 } 147 148 /// 根据参考的矩形和pivot值来调整自身位置(默认为父物体,也可以自定义为其他矩形) 149 /// 统一处理 方便覆写 arrange_self_base(&self)150 fn arrange_self_base(&self) { 151 let relative_rect: Rect = if self.parent().borrow().is_some() { 152 // 优先以父物体作为参考 153 self.parent().borrow().clone().unwrap().rect().get() 154 } else if self.panel().borrow().is_some() { 155 // 没有父物体 则以所属面板作为参考 156 self.panel().borrow().clone().unwrap().rect() 157 } else { 158 // 否则以整个屏幕作为参考 159 Rect::new(0, 0, SCREEN_WIDTH as u32, SCREEN_HEIGHT as u32) 160 }; 161 162 let target_rect = align_rect( 163 self.rect().get(), 164 relative_rect, 165 self.pivot().get(), 166 self.pivot_offset().get(), 167 ); 168 169 self.rect().set(target_rect); 170 } 171 } 172