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::base::{event::Event, rect::Rect, vector2::Vector2}; 11 12 pub mod image; 13 pub mod label; 14 15 pub fn widget_add_child(parent: Arc<dyn Widget>, child: Arc<dyn Widget>) { 16 parent.children().borrow_mut().push(child.clone()); 17 (*child.parent().borrow_mut()) = Some(parent.clone()); 18 parent.arrange_all(); 19 } 20 21 /// # 函数功能 22 /// 工具类 根据pivot和offset来进行矩形位置的对齐 23 /// 24 /// ## 参数 25 /// - origin_rect: 待对齐的矩形 26 /// - relative_rect: 作为对齐参考的矩形 27 /// - pivot: 对齐方式 28 /// - pivot_offset: 偏移量 29 /// 30 /// ## 返回值 31 /// 对齐后的矩形 32 pub fn align_rect( 33 origin_rect: Rect, 34 relative_rect: Rect, 35 pivot: PivotType, 36 pivot_offset: Vector2, 37 ) -> Rect { 38 let relative_pos = match pivot { 39 PivotType::None => Vector2::new(0, 0), 40 PivotType::Bottom => relative_rect.bottom_pos(), 41 PivotType::BottomLeft => relative_rect.bottom_left_pos(), 42 PivotType::BottomRight => relative_rect.bottom_right_pos(), 43 PivotType::Center => relative_rect.center_pos(), 44 PivotType::Top => relative_rect.top_pos(), 45 PivotType::TopLeft => relative_rect.top_left_pos(), 46 PivotType::TopRight => relative_rect.top_right_pos(), 47 PivotType::Left => relative_rect.left_pos(), 48 PivotType::Right => relative_rect.right_pos(), 49 }; 50 51 let mut target_pos = relative_pos + pivot_offset; 52 53 let negative_width = -(origin_rect.width as i32); 54 let negative_height = -(origin_rect.height as i32); 55 let offset_vec = match pivot { 56 PivotType::None => Vector2::new(0, 0), 57 PivotType::Bottom => Vector2::new(negative_width / 2, negative_height), 58 PivotType::BottomLeft => Vector2::new(0, negative_height), 59 PivotType::BottomRight => Vector2::new(negative_width, negative_height), 60 PivotType::Center => Vector2::new(negative_width / 2, negative_height / 2), 61 PivotType::Top => Vector2::new(negative_width / 2, 0), 62 PivotType::TopLeft => Vector2::new(0, 0), 63 PivotType::TopRight => Vector2::new(negative_width, 0), 64 PivotType::Left => Vector2::new(0, negative_height / 2), 65 PivotType::Right => Vector2::new(negative_width, negative_height / 2), 66 }; 67 68 target_pos = target_pos + offset_vec; 69 Rect::new( 70 target_pos.x, 71 target_pos.y, 72 origin_rect.width, 73 origin_rect.height, 74 ) 75 } 76 77 #[derive(PartialEq, Copy, Clone)] 78 pub enum PivotType { 79 /// 不进行对齐 pivot_offset即为世界坐标 80 None, 81 /// 对齐左上角(默认对齐方式,这是由于矩形位置通过左上角顶点坐标来表示) 82 TopLeft, 83 /// 对齐正上方 84 Top, 85 /// 对齐右上角 86 TopRight, 87 /// 对齐正左方 88 Left, 89 /// 对齐中心 90 Center, 91 /// 对齐正右方 92 Right, 93 /// 对齐左下角 94 BottomLeft, 95 /// 对齐正下方 96 Bottom, 97 /// 对齐右下角 98 BottomRight, 99 } 100 101 /// UI组件需要实现的特性 102 pub trait Widget: Any { 103 /// 返回渲染的矩形区域 104 fn rect(&self) -> &Cell<Rect>; 105 106 /// 对齐方式 107 fn pivot(&self) -> &Cell<PivotType>; 108 109 /// 基于基准点的偏移量 110 fn pivot_offset(&self) -> &Cell<Vector2>; 111 112 /// 返回组件的名字 113 fn name(&self) -> &str; 114 115 /// 返回父物体 116 fn parent(&self) -> &RefCell<Option<Arc<dyn Widget>>>; 117 118 /// 返回子组件数组 119 fn children(&self) -> &RefCell<Vec<Arc<dyn Widget>>>; 120 121 /// 渲染组件 122 fn draw(&self, renderer: &mut dyn Renderer, focused: bool); 123 124 /// 更新组件状态 125 fn update(&self) {} 126 127 /// 处理输入事件 128 fn handle_event( 129 &self, 130 _event: Event, 131 _focused: bool, 132 _redraw: &mut bool, 133 _caught: &mut bool, 134 ) -> bool { 135 false 136 } 137 138 fn set_pivot_type(&self, pivot_type: PivotType) { 139 self.set_pivot_type_base(pivot_type); 140 } 141 142 /// 修改对齐方式的统一处理 方便覆写 143 fn set_pivot_type_base(&self, pivot_type: PivotType) { 144 self.pivot().set(pivot_type); 145 self.arrange_all(); 146 } 147 148 fn set_pivot_offset(&self, pivot_offset: Vector2) { 149 self.set_pivot_offset_base(pivot_offset); 150 } 151 152 /// 修改对齐偏移量的统一处理 方便覆写 153 fn set_pivot_offset_base(&self, pivot_offset: Vector2) { 154 self.pivot_offset().set(pivot_offset); 155 self.arrange_all(); 156 } 157 158 fn resize(&self, width: u32, height: u32) { 159 self.resize_base(width, height); 160 } 161 162 /// 修改大小时的统一处理 方便覆写 163 fn resize_base(&self, width: u32, height: u32) { 164 let mut rect = self.rect().get(); 165 rect.width = width; 166 rect.height = height; 167 self.rect().set(rect); 168 self.arrange_all(); 169 } 170 171 /// 重新排布自身和子对象的位置 172 fn arrange_all(&self) { 173 self.arrange_self(); 174 175 for child in self.children().borrow_mut().iter() { 176 child.arrange_all(); 177 } 178 } 179 180 fn arrange_self(&self) { 181 self.arrange_self_base(); 182 } 183 184 /// 根据父物体和pivot值来调整自身位置 统一处理 方便覆写 185 fn arrange_self_base(&self) { 186 let relative_rect: Rect = if self.parent().borrow().is_some() { 187 self.parent().borrow().as_ref().unwrap().rect().get() 188 } else { 189 // 没有父物体 则以整个屏幕作为参考 190 Rect::new(0, 0, SCREEN_WIDTH as u32, SCREEN_HEIGHT as u32) 191 }; 192 193 let target_rect = align_rect( 194 self.rect().get(), 195 relative_rect, 196 self.pivot().get(), 197 self.pivot_offset().get(), 198 ); 199 200 self.rect().set(target_rect); 201 } 202 } 203