xref: /StarryEngine/starry_toolkit/src/base/panel.rs (revision 6f3c183754d5940a0fbae5cb2a8bc423f3ed1beb)
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) -> Self {
81         Panel::from_window(Window::new(rect.x, rect.y, rect.width, rect.height, title))
82     }
83 
84     pub fn from_window(window: Window) -> Self {
85         Panel {
86             window: RefCell::new(window),
87             widgets: RefCell::new(Vec::new()),
88             running: Cell::new(true),
89             focused_widget: RefCell::new(None),
90         }
91     }
92 
93     /// 获得客户端窗口对象
94     pub fn into_window(self) -> Window {
95         self.window.into_inner()
96     }
97 
98     /// 返回x坐标
99     pub fn x(&self) -> i32 {
100         let window = self.window.borrow();
101         (*window).x()
102     }
103 
104     /// 返回y坐标
105     pub fn y(&self) -> i32 {
106         let window = self.window.borrow();
107         (*window).y()
108     }
109 
110     /// 返回宽度值
111     pub fn width(&self) -> u32 {
112         let window = self.window.borrow();
113         (*window).width()
114     }
115 
116     /// 返回高度值
117     pub fn height(&self) -> u32 {
118         let window = self.window.borrow();
119         (*window).height()
120     }
121 
122     /// 窗口标题
123     pub fn title(&self) -> String {
124         let window = self.window.borrow();
125         (*window).title()
126     }
127 
128     /// 改变窗口位置
129     pub fn set_pos(&self, x: i32, y: i32) {
130         let mut window = self.window.borrow_mut();
131         (*window).set_pos(x, y);
132     }
133 
134     /// 改变窗口大小
135     pub fn set_size(&self, width: u32, height: u32) {
136         let mut window = self.window.borrow_mut();
137         (*window).set_size(width, height);
138     }
139 
140     /// 改变窗口标题
141     pub fn set_title(&self, title: &str) {
142         let mut window = self.window.borrow_mut();
143         (*window).set_title(title);
144     }
145 
146     /// 关闭窗口
147     pub fn close(&self) {
148         self.running.set(false);
149     }
150 
151     /// 添加子组件,返回子组件id
152     pub fn add_child<T: Widget>(&self, widget: &Arc<T>) -> usize {
153         let mut widgets = self.widgets.borrow_mut();
154         let id = widgets.len();
155         widgets.push(widget.clone());
156 
157         return id;
158     }
159 
160     /// 渲染面板(渲染子组件数组)
161     pub fn draw(&self) {
162         let mut window = self.window.borrow_mut();
163         let mut renderer = PanelRenderer::new(&mut window);
164 
165         for widget in self.widgets.borrow().iter() {
166             self.draw_widget(&mut renderer, widget);
167         }
168 
169         renderer.sync();
170     }
171 
172     /// 渲染单个组件
173     pub fn draw_widget(&self, renderer: &mut dyn Renderer, widget: &Arc<dyn Widget>) {
174         widget.update();
175         widget.draw(renderer, self.is_focused(widget));
176 
177         // 渲染子组件
178         for child in widget.children().borrow().iter() {
179             self.draw_widget(renderer, child);
180         }
181     }
182 }
183 
184 impl Focus for Panel {
185     fn focused_widget(&self) -> RefCell<Option<Arc<dyn Widget>>> {
186         self.focused_widget.clone()
187     }
188 }
189