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