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