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 }