xref: /StarryEngine/starry_toolkit/src/base/panel.rs (revision 731cae0674923fcc85c6e683a2eee596eb642796)
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 #[derive(PartialEq, Copy, Clone, Debug)]
26 pub enum PanelRendererMode {
27     /// 标准模式
28     Normal,
29     /// 绘制线框
30     WithWireframe,
31     /// 仅线框
32     OnlyWireframe,
33 }
34 
35 /// 面板渲染器
36 pub struct PanelRenderer<'a> {
37     /// 客户端窗口
38     window: &'a mut Window,
39 }
40 
41 impl<'a> PanelRenderer<'a> {
new(window: &'a mut Window) -> Self42     pub fn new(window: &'a mut Window) -> Self {
43         PanelRenderer { window: window }
44     }
45 }
46 
47 impl<'a> Renderer for PanelRenderer<'a> {
width(&self) -> u3248     fn width(&self) -> u32 {
49         self.window.width()
50     }
51 
height(&self) -> u3252     fn height(&self) -> u32 {
53         self.window.height()
54     }
55 
data(&self) -> &[Color]56     fn data(&self) -> &[Color] {
57         self.window.data()
58     }
59 
data_mut(&mut self) -> &mut [Color]60     fn data_mut(&mut self) -> &mut [Color] {
61         self.window.data_mut()
62     }
63 
sync(&mut self) -> bool64     fn sync(&mut self) -> bool {
65         self.window.sync()
66     }
67 
mode(&self) -> &Cell<RenderMode>68     fn mode(&self) -> &Cell<RenderMode> {
69         &self.window.mode()
70     }
71 
72     // TODO
73     // fn char(&mut self, x: i32, y: i32, c: char, color: Color) {
74     // }
75 }
76 
77 /// UI面板类作为容器管理一组UI组件(UI-Widget)
78 /// 拥有一个窗口对象用于渲染和事件传递
79 pub struct Panel {
80     /// 指向自身的弱引用
81     self_ref: RefCell<Weak<Panel>>,
82     /// 客户端窗口对象
83     window: RefCell<Window>,
84     /// 面板矩形
85     rect: Cell<Rect>,
86     /// 管理的控件对象数组
87     widgets: RefCell<Vec<Arc<dyn Widget>>>,
88     /// 窗口是否打开
89     running: Cell<bool>,
90     /// 当前聚焦的窗口
91     focused_widget: RefCell<Option<Arc<dyn Widget>>>,
92     /// 事件数组
93     events: RefCell<Vec<Event>>,
94     /// 需要重绘画面
95     redraw: Cell<bool>,
96     /// tty文件
97     tty_file: RefCell<File>,
98     /// 渲染模式
99     renderer_mode: Cell<PanelRendererMode>,
100 }
101 
102 impl Panel {
new(rect: Rect, title: &str, color: Color) -> Arc<Panel>103     pub fn new(rect: Rect, title: &str, color: Color) -> Arc<Panel> {
104         Panel::from_window(
105             Window::new(rect.x, rect.y, rect.width, rect.height, title, color),
106             rect,
107         )
108     }
109 
from_window(window: Window, rect: Rect) -> Arc<Panel>110     pub fn from_window(window: Window, rect: Rect) -> Arc<Panel> {
111         let panel = Arc::new(Panel {
112             self_ref: RefCell::new(Weak::default()),
113             window: RefCell::new(window),
114             rect: Cell::new(rect),
115             widgets: RefCell::new(Vec::new()),
116             running: Cell::new(true),
117             focused_widget: RefCell::new(None),
118             events: RefCell::new(Vec::new()),
119             redraw: Cell::new(false),
120             tty_file: RefCell::new(
121                 File::open(TTY_DEVICE_PATH).expect("[Error] Panel failed to open tty file"),
122             ),
123             renderer_mode: Cell::new(PanelRendererMode::Normal),
124         });
125 
126         (*panel.self_ref.borrow_mut()) = Arc::downgrade(&panel);
127 
128         return panel;
129     }
130 
131     /// 获得客户端窗口对象
into_window(self) -> Window132     pub fn into_window(self) -> Window {
133         self.window.into_inner()
134     }
135 
136     /// 返回x坐标
x(&self) -> i32137     pub fn x(&self) -> i32 {
138         let window = self.window.borrow();
139         (*window).x()
140     }
141 
142     /// 返回y坐标
y(&self) -> i32143     pub fn y(&self) -> i32 {
144         let window = self.window.borrow();
145         (*window).y()
146     }
147 
148     /// 返回宽度值
width(&self) -> u32149     pub fn width(&self) -> u32 {
150         let window = self.window.borrow();
151         (*window).width()
152     }
153 
154     /// 返回高度值
height(&self) -> u32155     pub fn height(&self) -> u32 {
156         let window = self.window.borrow();
157         (*window).height()
158     }
159 
160     /// 返回面板矩形
rect(&self) -> Rect161     pub fn rect(&self) -> Rect {
162         self.rect.get()
163     }
164 
165     /// 窗口标题
title(&self) -> String166     pub fn title(&self) -> String {
167         let window = self.window.borrow();
168         (*window).title()
169     }
170 
171     /// 改变窗口位置
set_pos(&self, x: i32, y: i32)172     pub fn set_pos(&self, x: i32, y: i32) {
173         let mut window = self.window.borrow_mut();
174         (*window).set_pos(x, y);
175     }
176 
177     /// 改变窗口大小
set_size(&self, width: u32, height: u32)178     pub fn set_size(&self, width: u32, height: u32) {
179         let mut window = self.window.borrow_mut();
180         (*window).set_size(width, height);
181     }
182 
183     /// 改变窗口标题
set_title(&self, title: &str)184     pub fn set_title(&self, title: &str) {
185         let mut window = self.window.borrow_mut();
186         (*window).set_title(title);
187     }
188 
189     /// 设置是否绘制线框
set_renderer_mode(&self, renderer_mode: PanelRendererMode)190     pub fn set_renderer_mode(&self, renderer_mode: PanelRendererMode) {
191         self.renderer_mode.set(renderer_mode);
192     }
193 
194     /// 关闭窗口
close(&self)195     pub fn close(&self) {
196         self.running.set(false);
197     }
198 
199     /// 添加子组件,返回子组件id
add_child<T: Widget>(&self, widget: &Arc<T>) -> usize200     pub fn add_child<T: Widget>(&self, widget: &Arc<T>) -> usize {
201         widget_set_panel(
202             &widget.self_ref(),
203             &self.self_ref.borrow().upgrade().unwrap(),
204         );
205 
206         let mut widgets = self.widgets.borrow_mut();
207         let id = widgets.len();
208         widgets.push(widget.clone());
209         widget.arrange_all();
210         return id;
211     }
212 
213     /// 渲染面板(渲染子组件数组)
draw(&self)214     pub fn draw(&self) {
215         let mut window = self.window.borrow_mut();
216         let mut renderer = PanelRenderer::new(&mut window);
217 
218         for widget in self.widgets.borrow().iter() {
219             self.draw_widget(&mut renderer, widget);
220         }
221 
222         renderer.sync();
223     }
224 
225     /// 渲染单个组件
draw_widget(&self, renderer: &mut dyn Renderer, widget: &Arc<dyn Widget>)226     pub fn draw_widget(&self, renderer: &mut dyn Renderer, widget: &Arc<dyn Widget>) {
227         widget.update();
228 
229         if self.renderer_mode.get() == PanelRendererMode::Normal
230             || self.renderer_mode.get() == PanelRendererMode::WithWireframe
231         {
232             widget.draw(renderer, self.is_focused(widget));
233         }
234 
235         if self.renderer_mode.get() == PanelRendererMode::WithWireframe
236             || self.renderer_mode.get() == PanelRendererMode::OnlyWireframe
237         {
238             Self::draw_rect_wireframe(renderer, widget.rect().get(), Color::rgb(0, 0, 0));
239         }
240 
241         // 渲染子组件
242         for child in widget.children().borrow().iter() {
243             if self.renderer_mode.get() == PanelRendererMode::Normal
244                 || self.renderer_mode.get() == PanelRendererMode::WithWireframe
245             {
246                 self.draw_widget(renderer, child);
247             }
248 
249             if self.renderer_mode.get() == PanelRendererMode::WithWireframe
250                 || self.renderer_mode.get() == PanelRendererMode::OnlyWireframe
251             {
252                 Self::draw_rect_wireframe(renderer, child.rect().get(), Color::rgb(0, 0, 0));
253             }
254         }
255     }
256 
257     /// 绘制矩形线框
draw_rect_wireframe(renderer: &mut dyn Renderer, rect: Rect, color: Color)258     fn draw_rect_wireframe(renderer: &mut dyn Renderer, rect: Rect, color: Color) {
259         renderer.lines(
260             &[
261                 [rect.top_left_pos().x, rect.top_left_pos().y],
262                 [rect.top_right_pos().x, rect.top_right_pos().y],
263                 [rect.bottom_right_pos().x, rect.bottom_right_pos().y],
264                 [rect.bottom_left_pos().x, rect.bottom_left_pos().y],
265                 [rect.top_left_pos().x, rect.top_left_pos().y],
266             ],
267             color,
268         );
269     }
270 
tick(&self)271     pub fn tick(&self) {
272         // TODO 通过服务器,先从Window对象接收事件,再进行处理
273         self.handle_events();
274     }
275 
276     /// 将事件传递给Widget对象
handle_events(&self)277     fn handle_events(&self) {
278         while let Some(event) = self.events.borrow_mut().pop() {
279             // 事件是否已被处理
280             let caught = Cell::new(false);
281 
282             for widget in self.widgets.borrow().iter().rev() {
283                 // TODO 处理返回值
284                 widget.handle_event(event, self.is_focused(widget), &self.redraw, &caught);
285 
286                 if caught.get() {
287                     break;
288                 }
289             }
290         }
291     }
292 
293     // TODO 临时函数 用于客户端直接处理用户输入
push_event(&self, event: Event)294     pub fn push_event(&self, event: Event) {
295         self.events.borrow_mut().push(event);
296     }
297 
exec(&self)298     pub fn exec(&self) {
299         while self.running.get() {
300             self.polling_tty();
301             self.tick();
302             self.draw_if_needed();
303 
304             thread::sleep(DURATION_TIME);
305         }
306     }
307 
308     /// 必要时重绘
draw_if_needed(&self)309     fn draw_if_needed(&self) {
310         if self.redraw.get() {
311             self.draw();
312             self.redraw.set(false);
313         }
314     }
315 
316     // TODO 临时在客户端做输入读取  后续改为由服务器实现
polling_tty(&self)317     fn polling_tty(&self) {
318         let mut bufffer: [u8; 128] = [0; 128];
319         let count = self
320             .tty_file
321             .borrow_mut()
322             .read(&mut bufffer)
323             .expect("[Error] Panel failed to read tty file");
324         for i in 0..count {
325             self.push_event(Event::KeyPressed {
326                 character: Some(bufffer[i] as char),
327             });
328         }
329     }
330 }
331 
332 impl Focus for Panel {
focused_widget(&self) -> RefCell<Option<Arc<dyn Widget>>>333     fn focused_widget(&self) -> RefCell<Option<Arc<dyn Widget>>> {
334         self.focused_widget.clone()
335     }
336 
focus(&self, widget: &Arc<dyn Widget>)337     fn focus(&self, widget: &Arc<dyn Widget>) {
338         (*self.focused_widget.borrow_mut()) = Some(widget.clone());
339     }
340 }
341