xref: /StarryEngine/starry_toolkit/src/base/panel.rs (revision 282ef85ca13266353a8fb594bdc60918a2715518)
1 use starry_client::{
2     base::{
3         color::Color,
4         renderer::{RenderMode, Renderer},
5     },
6     window::Window,
7 };
8 use std::{
9     cell::{Cell, RefCell},
10     fs::File,
11     io::Read,
12     sync::{Arc, Weak},
13     thread,
14     time::Duration,
15 };
16 
17 use crate::{traits::focus::Focus, util::widget_set_panel, widgets::Widget};
18 
19 use super::{event::Event, rect::Rect};
20 
21 const TTY_DEVICE_PATH: &str = "/dev/char/tty0";
22 
23 const DURATION_TIME: Duration = Duration::from_millis(25);
24 
25 /// 面板渲染器
26 pub struct PanelRenderer<'a> {
27     /// 客户端窗口
28     window: &'a mut Window,
29 }
30 
31 impl<'a> PanelRenderer<'a> {
32     pub fn new(window: &'a mut Window) -> Self {
33         PanelRenderer { window }
34     }
35 }
36 
37 impl<'a> Renderer for PanelRenderer<'a> {
38     fn width(&self) -> u32 {
39         self.window.width()
40     }
41 
42     fn height(&self) -> u32 {
43         self.window.height()
44     }
45 
46     fn data(&self) -> &[Color] {
47         self.window.data()
48     }
49 
50     fn data_mut(&mut self) -> &mut [Color] {
51         self.window.data_mut()
52     }
53 
54     fn sync(&mut self) -> bool {
55         self.window.sync()
56     }
57 
58     fn mode(&self) -> &Cell<RenderMode> {
59         &self.window.mode()
60     }
61 
62     // TODO
63     // fn char(&mut self, x: i32, y: i32, c: char, color: Color) {
64     // }
65 }
66 
67 /// UI面板类作为容器管理一组UI组件(UI-Widget)
68 /// 拥有一个窗口对象用于渲染和事件传递
69 pub struct Panel {
70     /// 指向自身的弱引用
71     self_ref: RefCell<Weak<Panel>>,
72     /// 客户端窗口对象
73     window: RefCell<Window>,
74     /// 面板矩形
75     rect: Cell<Rect>,
76     /// 子组件数组
77     widgets: RefCell<Vec<Arc<dyn Widget>>>,
78     /// 窗口是否打开
79     running: Cell<bool>,
80     /// 当前聚焦的窗口
81     focused_widget: RefCell<Option<Arc<dyn Widget>>>,
82     /// 事件数组
83     events: RefCell<Vec<Event>>,
84     /// 需要重绘画面
85     redraw: Cell<bool>,
86     /// tty文件
87     tty_file: RefCell<File>,
88 }
89 
90 impl Panel {
91     pub fn new(rect: Rect, title: &str, color: Color) -> Arc<Panel> {
92         Panel::from_window(
93             Window::new(rect.x, rect.y, rect.width, rect.height, title, color),
94             rect,
95         )
96     }
97 
98     pub fn from_window(window: Window, rect: Rect) -> Arc<Panel> {
99         let panel = Arc::new(Panel {
100             self_ref: RefCell::new(Weak::default()),
101             window: RefCell::new(window),
102             rect: Cell::new(rect),
103             widgets: RefCell::new(Vec::new()),
104             running: Cell::new(true),
105             focused_widget: RefCell::new(None),
106             events: RefCell::new(Vec::new()),
107             redraw: Cell::new(false),
108             tty_file: RefCell::new(
109                 File::open(TTY_DEVICE_PATH).expect("[Error] Panel failed to open tty file"),
110             ),
111         });
112 
113         (*panel.self_ref.borrow_mut()) = Arc::downgrade(&panel);
114 
115         return panel;
116     }
117 
118     /// 获得客户端窗口对象
119     pub fn into_window(self) -> Window {
120         self.window.into_inner()
121     }
122 
123     /// 返回x坐标
124     pub fn x(&self) -> i32 {
125         let window = self.window.borrow();
126         (*window).x()
127     }
128 
129     /// 返回y坐标
130     pub fn y(&self) -> i32 {
131         let window = self.window.borrow();
132         (*window).y()
133     }
134 
135     /// 返回宽度值
136     pub fn width(&self) -> u32 {
137         let window = self.window.borrow();
138         (*window).width()
139     }
140 
141     /// 返回高度值
142     pub fn height(&self) -> u32 {
143         let window = self.window.borrow();
144         (*window).height()
145     }
146 
147     /// 返回面板矩形
148     pub fn rect(&self) -> Rect {
149         self.rect.get()
150     }
151 
152     /// 窗口标题
153     pub fn title(&self) -> String {
154         let window = self.window.borrow();
155         (*window).title()
156     }
157 
158     /// 改变窗口位置
159     pub fn set_pos(&self, x: i32, y: i32) {
160         let mut window = self.window.borrow_mut();
161         (*window).set_pos(x, y);
162     }
163 
164     /// 改变窗口大小
165     pub fn set_size(&self, width: u32, height: u32) {
166         let mut window = self.window.borrow_mut();
167         (*window).set_size(width, height);
168     }
169 
170     /// 改变窗口标题
171     pub fn set_title(&self, title: &str) {
172         let mut window = self.window.borrow_mut();
173         (*window).set_title(title);
174     }
175 
176     /// 关闭窗口
177     pub fn close(&self) {
178         self.running.set(false);
179     }
180 
181     /// 添加子组件,返回子组件id
182     pub fn add_child<T: Widget>(&self, widget: &Arc<T>) -> usize {
183         widget_set_panel(
184             &widget.self_ref(),
185             &self.self_ref.borrow().upgrade().unwrap(),
186         );
187 
188         let mut widgets = self.widgets.borrow_mut();
189         let id = widgets.len();
190         widgets.push(widget.clone());
191         widget.arrange_all();
192         return id;
193     }
194 
195     /// 渲染面板(渲染子组件数组)
196     pub fn draw(&self) {
197         let mut window = self.window.borrow_mut();
198         let mut renderer = PanelRenderer::new(&mut window);
199 
200         for widget in self.widgets.borrow().iter() {
201             self.draw_widget(&mut renderer, widget);
202         }
203 
204         renderer.sync();
205     }
206 
207     /// 渲染单个组件
208     pub fn draw_widget(&self, renderer: &mut dyn Renderer, widget: &Arc<dyn Widget>) {
209         widget.update();
210         widget.draw(renderer, self.is_focused(widget));
211 
212         // 渲染子组件
213         for child in widget.children().borrow().iter() {
214             self.draw_widget(renderer, child);
215         }
216     }
217 
218     pub fn tick(&self) {
219         // TODO 通过服务器,先从Window对象接收事件,再进行处理
220         self.handle_events();
221     }
222 
223     /// 将事件传递给Widget对象
224     fn handle_events(&self) {
225         while let Some(event) = self.events.borrow_mut().pop() {
226             // 事件是否已被处理
227             let caught = Cell::new(false);
228 
229             for widget in self.widgets.borrow().iter().rev() {
230                 // TODO 处理返回值
231                 widget.handle_event(event, self.is_focused(widget), &self.redraw, &caught);
232 
233                 if caught.get() {
234                     break;
235                 }
236             }
237         }
238     }
239 
240     // TODO 临时函数 用于客户端直接处理用户输入
241     pub fn push_event(&self, event: Event) {
242         self.events.borrow_mut().push(event);
243     }
244 
245     pub fn exec(&self) {
246         while self.running.get() {
247             self.polling_tty();
248             self.tick();
249             self.draw_if_needed();
250 
251             thread::sleep(DURATION_TIME);
252         }
253     }
254 
255     /// 必要时重绘
256     fn draw_if_needed(&self) {
257         if self.redraw.get() {
258             self.draw();
259             self.redraw.set(false);
260         }
261     }
262 
263     // TODO 临时在客户端做输入读取  后续改为由服务器实现
264     fn polling_tty(&self) {
265         let mut bufffer: [u8; 128] = [0; 128];
266         let count = self
267             .tty_file
268             .borrow_mut()
269             .read(&mut bufffer)
270             .expect("[Error] Panel failed to read tty file");
271         for i in 0..count {
272             self.push_event(Event::KeyPressed {
273                 character: Some(bufffer[i] as char),
274             });
275         }
276     }
277 }
278 
279 impl Focus for Panel {
280     fn focused_widget(&self) -> RefCell<Option<Arc<dyn Widget>>> {
281         self.focused_widget.clone()
282     }
283 
284     fn focus(&self, widget: &Arc<dyn Widget>) {
285         (*self.focused_widget.borrow_mut()) = Some(widget.clone());
286     }
287 }
288