xref: /StarryEngine/starry_toolkit/src/widgets/label.rs (revision 48d97639c61db7d12182c250896dd116973d24c5)
1 use std::{
2     cell::{Cell, RefCell},
3     sync::Arc,
4 };
5 
6 use starry_client::base::{color::Color, renderer::Renderer};
7 
8 use crate::{base::{point::Point, rect::Rect}, traits::{place::Place, text::Text}};
9 
10 use super::{HorizontalPlacement, VerticalPlacement, Widget};
11 
12 pub struct Label {
13     pub rect: Cell<Rect>,
14     local_position: Cell<Point>,
15     vertical_placement: Cell<VerticalPlacement>,
16     horizontal_placement: Cell<HorizontalPlacement>,
17     children: RefCell<Vec<Arc<dyn Widget>>>,
18     pub text: RefCell<String>,
19     pub text_offset: Cell<Point>,
20 }
21 
22 impl Label {
23         pub fn new() -> Arc<Self> {
24         Arc::new(Label {
25             rect: Cell::new(Rect::default()),
26             local_position: Cell::new(Point::new(0, 0)),
27             vertical_placement: Cell::new(VerticalPlacement::Absolute),
28             horizontal_placement: Cell::new(HorizontalPlacement::Absolute),
29             children: RefCell::new(vec![]),
30             text: RefCell::new(String::new()),
31             text_offset: Cell::new(Point::default()),
32         })
33     }
34 
35     fn adjust_size(&self) {
36         let text = self.text.borrow();
37         self.size(
38             text.len() as u32 * 8 + 2 * self.text_offset.get().x as u32,
39             16 + 2 * self.text_offset.get().y as u32,
40         );
41     }
42 }
43 
44 impl Place for Label {}
45 
46 impl Widget for Label {
47     fn name(&self) -> &str {
48         "Label"
49     }
50 
51     fn rect(&self) -> &Cell<Rect> {
52         &self.rect
53     }
54 
55     fn local_position(&self) -> &Cell<Point> {
56         &self.local_position
57     }
58 
59     fn vertical_placement(&self) -> &Cell<VerticalPlacement> {
60         &self.vertical_placement
61     }
62 
63     fn horizontal_placement(&self) -> &Cell<HorizontalPlacement> {
64         &self.horizontal_placement
65     }
66 
67     fn children(&self) -> &RefCell<Vec<Arc<dyn Widget>>> {
68         &self.children
69     }
70 
71     fn draw(&self, renderer: &mut dyn Renderer) {
72         let origin_rect = self.rect().get();
73         let mut current_rect = self.rect().get(); // 当前字符渲染矩形
74         let origin_x = origin_rect.x;
75         let text = self.text.borrow().clone();
76 
77         for char in text.chars() {
78             if char == '\n' {
79                 // 换行 退格到起始位置
80                 current_rect.x = origin_x;
81                 current_rect.y += 16;
82             } else {
83                 // 避免超出矩形范围
84                 if current_rect.x + 8 <= origin_rect.x + origin_rect.width as i32
85                     && current_rect.y + 16 <= origin_rect.y + origin_rect.height as i32
86                 {
87                     // 默认渲染白色字体
88                     // TODO 应用主题(Theme)颜色
89                     renderer.char(current_rect.x, current_rect.y, char, Color::rgb(255, 255, 255));
90                 }
91                 current_rect.x += 8;
92             }
93         }
94     }
95 }
96 
97 impl Text for Label {
98     fn text<S: Into<String>>(&self, target_text: S) -> &Self {
99         {
100             let mut text = self.text.borrow_mut();
101             *text = target_text.into();
102         }
103         self.adjust_size();
104         self
105     }
106 
107     fn text_offset(&self, x: i32, y: i32) -> &Self {
108         self.text_offset.set(Point::new(x, y));
109         self.adjust_size();
110         self
111     }
112 }