1 use std::{ 2 cell::{Cell, RefCell}, 3 sync::Arc, 4 }; 5 6 use starry_client::{ 7 base::{ 8 color::Color, 9 renderer::{RenderMode, Renderer}, 10 }, 11 window::Window, 12 }; 13 14 use crate::{traits::focus::Focus, widgets::Widget}; 15 16 use super::rect::Rect; 17 18 /// 面板渲染器 19 pub struct PanelRenderer<'a> { 20 /// 客户端窗口 21 window: &'a mut Window, 22 } 23 24 impl<'a> PanelRenderer<'a> { 25 pub fn new(window: &'a mut Window) -> Self { 26 PanelRenderer { window } 27 } 28 } 29 30 impl<'a> Renderer for PanelRenderer<'a> { 31 fn width(&self) -> u32 { 32 self.window.width() 33 } 34 35 fn height(&self) -> u32 { 36 self.window.height() 37 } 38 39 fn data(&self) -> &[Color] { 40 self.window.data() 41 } 42 43 fn data_mut(&mut self) -> &mut [Color] { 44 self.window.data_mut() 45 } 46 47 fn sync(&mut self) -> bool { 48 self.window.sync() 49 } 50 51 fn mode(&self) -> &Cell<RenderMode> { 52 &self.window.mode() 53 } 54 55 // TODO 56 // fn char(&mut self, x: i32, y: i32, c: char, color: Color) { 57 // } 58 } 59 60 impl<'a> Drop for PanelRenderer<'a> { 61 fn drop(&mut self) { 62 self.window.sync(); 63 } 64 } 65 66 /// UI面板类作为容器管理一组UI组件(UI-Widget) 67 /// 拥有一个窗口对象用于渲染和事件传递 68 pub struct Panel { 69 /// 客户端窗口对象 70 window: RefCell<Window>, 71 /// 子组件数组 72 pub widgets: RefCell<Vec<Arc<dyn Widget>>>, 73 /// 窗口是否打开 74 pub running: Cell<bool>, 75 /// 当前聚焦的窗口 76 pub focused_widget: RefCell<Option<Arc<dyn Widget>>>, 77 } 78 79 impl Panel { 80 pub fn new(rect: Rect, title: &str, color: Color) -> Self { 81 Panel::from_window(Window::new( 82 rect.x, 83 rect.y, 84 rect.width, 85 rect.height, 86 title, 87 color, 88 )) 89 } 90 91 pub fn from_window(window: Window) -> Self { 92 Panel { 93 window: RefCell::new(window), 94 widgets: RefCell::new(Vec::new()), 95 running: Cell::new(true), 96 focused_widget: RefCell::new(None), 97 } 98 } 99 100 /// 获得客户端窗口对象 101 pub fn into_window(self) -> Window { 102 self.window.into_inner() 103 } 104 105 /// 返回x坐标 106 pub fn x(&self) -> i32 { 107 let window = self.window.borrow(); 108 (*window).x() 109 } 110 111 /// 返回y坐标 112 pub fn y(&self) -> i32 { 113 let window = self.window.borrow(); 114 (*window).y() 115 } 116 117 /// 返回宽度值 118 pub fn width(&self) -> u32 { 119 let window = self.window.borrow(); 120 (*window).width() 121 } 122 123 /// 返回高度值 124 pub fn height(&self) -> u32 { 125 let window = self.window.borrow(); 126 (*window).height() 127 } 128 129 /// 窗口标题 130 pub fn title(&self) -> String { 131 let window = self.window.borrow(); 132 (*window).title() 133 } 134 135 /// 改变窗口位置 136 pub fn set_pos(&self, x: i32, y: i32) { 137 let mut window = self.window.borrow_mut(); 138 (*window).set_pos(x, y); 139 } 140 141 /// 改变窗口大小 142 pub fn set_size(&self, width: u32, height: u32) { 143 let mut window = self.window.borrow_mut(); 144 (*window).set_size(width, height); 145 } 146 147 /// 改变窗口标题 148 pub fn set_title(&self, title: &str) { 149 let mut window = self.window.borrow_mut(); 150 (*window).set_title(title); 151 } 152 153 /// 关闭窗口 154 pub fn close(&self) { 155 self.running.set(false); 156 } 157 158 /// 添加子组件,返回子组件id 159 pub fn add_child<T: Widget>(&self, widget: &Arc<T>) -> usize { 160 let mut widgets = self.widgets.borrow_mut(); 161 let id = widgets.len(); 162 widgets.push(widget.clone()); 163 164 return id; 165 } 166 167 /// 渲染面板(渲染子组件数组) 168 pub fn draw(&self) { 169 let mut window = self.window.borrow_mut(); 170 let mut renderer = PanelRenderer::new(&mut window); 171 172 for widget in self.widgets.borrow().iter() { 173 self.draw_widget(&mut renderer, widget); 174 } 175 176 renderer.sync(); 177 } 178 179 /// 渲染单个组件 180 pub fn draw_widget(&self, renderer: &mut dyn Renderer, widget: &Arc<dyn Widget>) { 181 widget.update(); 182 widget.draw(renderer, self.is_focused(widget)); 183 184 // 渲染子组件 185 for child in widget.children().borrow().iter() { 186 self.draw_widget(renderer, child); 187 } 188 } 189 } 190 191 impl Focus for Panel { 192 fn focused_widget(&self) -> RefCell<Option<Arc<dyn Widget>>> { 193 self.focused_widget.clone() 194 } 195 196 fn focus(&self, widget: &Arc<dyn Widget>) { 197 (*self.focused_widget.borrow_mut()) = Some(widget.clone()); 198 } 199 } 200