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