xref: /StarryEngine/starry_toolkit/src/widgets/mod.rs (revision 731cae0674923fcc85c6e683a2eee596eb642796) !
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