1 use std::{ 2 any::Any, 3 cell::{Cell, RefCell}, 4 cmp::max, 5 sync::{Arc, Weak}, 6 }; 7 8 use starry_client::base::{color::Color, renderer::Renderer}; 9 10 use crate::{ 11 base::{panel::Panel, rect::Rect, vector2::Vector2}, 12 traits::text::Text, 13 util::{align_rect, get_local_rect}, 14 }; 15 16 use super::{PivotType, Widget}; 17 18 #[derive(PartialEq, Copy, Clone)] 19 pub enum LabelOverflowType { 20 /// 不适配 溢出部分不显示 21 None, 22 /// 根据字数调整大小 23 ShinkToFit, 24 /// 省略多余内容 25 Omit, 26 // TODO 支持"调整字体大小以适配"的选项 27 } 28 29 pub struct Label { 30 self_ref: RefCell<Weak<Label>>, 31 rect: Cell<Rect>, 32 pivot: Cell<PivotType>, 33 pivot_offset: Cell<Vector2>, 34 children: RefCell<Vec<Arc<dyn Widget>>>, 35 parent: RefCell<Option<Arc<dyn Widget>>>, 36 panel: RefCell<Option<Arc<Panel>>>, 37 /// 实际上的文本 38 real_text: RefCell<String>, 39 /// 用于显示的文本 40 show_text: RefCell<String>, 41 text_color: Cell<Color>, 42 adapt_type: Cell<LabelOverflowType>, 43 /// 渲染文本时的矩形区域 44 text_rect: Cell<Rect>, 45 /// 文本在矩形框内的对齐方式 46 text_pivot: Cell<PivotType>, 47 } 48 49 // TODO 暂时只支持渲染一行字体 50 impl Label { 51 pub fn new() -> Arc<Self> { 52 let label = Arc::new(Label { 53 rect: Cell::new(Rect::default()), 54 pivot: Cell::new(PivotType::TopLeft), 55 pivot_offset: Cell::new(Vector2::new(0, 0)), 56 children: RefCell::new(vec![]), 57 parent: RefCell::new(None), 58 panel: RefCell::new(None), 59 real_text: RefCell::new(String::new()), 60 show_text: RefCell::new(String::new()), 61 text_color: Cell::new(Color::rgb(0, 0, 0)), // 默认黑色字体 62 adapt_type: Cell::new(LabelOverflowType::None), 63 text_rect: Cell::new(Rect::default()), 64 text_pivot: Cell::new(PivotType::Center), 65 self_ref: RefCell::new(Weak::new()), 66 }); 67 68 (*label.self_ref.borrow_mut()) = Arc::downgrade(&label); 69 70 return label; 71 } 72 73 /// 处理文本溢出的情况 74 /// 在文本内容改变或大小改变时调用 75 fn handle_overflow(&self) { 76 let text = self.real_text.borrow(); 77 78 match self.adapt_type.get() { 79 LabelOverflowType::None => {} 80 LabelOverflowType::ShinkToFit => { 81 self.resize(text.len() as u32 * 8 as u32, 16); 82 } 83 LabelOverflowType::Omit => { 84 let rect = self.rect.get(); 85 86 if text.len() as u32 * 8 > rect.width { 87 let max_count = max(0, (rect.width as i32 - 3 * 8) / 8); 88 let mut omit_str = self.real_text.borrow().clone(); 89 let _ = omit_str.split_off(max_count as usize); 90 omit_str.push_str("..."); // 溢出字符用省略号取代 91 (*self.show_text.borrow_mut()) = omit_str; 92 } 93 } 94 } 95 96 self.text_rect.set(Rect::new( 97 0, 98 0, 99 self.show_text.borrow().len() as u32 * 8, 100 16, 101 )); 102 } 103 104 pub fn set_adapt_type(&self, adapt_type: LabelOverflowType) { 105 self.adapt_type.set(adapt_type); 106 } 107 } 108 109 impl Widget for Label { 110 fn self_ref(&self) -> Arc<dyn Widget> { 111 self.self_ref.borrow().upgrade().unwrap() as Arc<dyn Widget> 112 } 113 114 fn as_any_ref(&self) -> &dyn Any { 115 self 116 } 117 118 fn name(&self) -> &str { 119 "Label" 120 } 121 122 fn rect(&self) -> &Cell<Rect> { 123 &self.rect 124 } 125 126 fn pivot(&self) -> &Cell<PivotType> { 127 &self.pivot 128 } 129 130 fn pivot_offset(&self) -> &Cell<Vector2> { 131 &self.pivot_offset 132 } 133 134 fn parent(&self) -> &RefCell<Option<Arc<dyn Widget>>> { 135 &self.parent 136 } 137 138 fn children(&self) -> &RefCell<Vec<Arc<dyn Widget>>> { 139 &self.children 140 } 141 142 fn panel(&self) -> &RefCell<Option<Arc<crate::base::panel::Panel>>> { 143 &self.panel 144 } 145 146 fn draw(&self, renderer: &mut dyn Renderer, _focused: bool) { 147 let origin_rect = self.text_rect.get(); 148 let mut current_rect = self.text_rect.get(); // 当前字符渲染矩形 149 let origin_x = origin_rect.x; 150 let text = self.show_text.borrow().clone(); 151 152 // 矩形高度不满足 153 if origin_rect.height < 16 { 154 return; 155 } 156 157 for char in text.chars() { 158 if char == '\n' { 159 // 换行 退格到起始位置 160 current_rect.x = origin_x; 161 current_rect.y += 16; 162 } else { 163 // 避免超出矩形范围 164 if current_rect.x + 8 <= origin_rect.x + origin_rect.width as i32 165 && current_rect.y + 16 <= origin_rect.y + origin_rect.height as i32 166 { 167 if self.panel().borrow().is_some() { 168 let local_rect = get_local_rect( 169 current_rect, 170 self.panel().borrow().clone().unwrap().rect(), 171 ); 172 // TODO 应用主题(Theme)颜色 173 renderer.char(local_rect.x, local_rect.y, char, self.text_color.get()); 174 } else { 175 println!("[Error] Label do not belong to any panel!"); 176 } 177 } 178 current_rect.x += 8; 179 } 180 } 181 } 182 183 fn set_pivot_type(&self, pivot_type: PivotType) { 184 self.set_pivot_type_base(pivot_type); 185 186 self.text_rect.set(align_rect( 187 self.text_rect.get(), 188 self.rect.get(), 189 self.text_pivot.get(), 190 Vector2::new(0, 0), 191 )); 192 } 193 194 fn set_pivot_offset(&self, pivot_offset: Vector2) { 195 self.set_pivot_offset_base(pivot_offset); 196 197 self.text_rect.set(align_rect( 198 self.text_rect.get(), 199 self.rect.get(), 200 self.text_pivot.get(), 201 Vector2::new(0, 0), 202 )); 203 } 204 205 fn resize(&self, width: u32, height: u32) { 206 self.resize_base(width, height); 207 208 self.handle_overflow(); 209 self.text_rect.set(align_rect( 210 self.text_rect.get(), 211 self.rect.get(), 212 self.text_pivot.get(), 213 Vector2::new(0, 0), 214 )); 215 } 216 217 fn arrange_self(&self) { 218 self.arrange_self_base(); 219 220 self.text_rect.set(align_rect( 221 self.text_rect.get(), 222 self.rect.get(), 223 self.text_pivot.get(), 224 Vector2::new(0, 0), 225 )); 226 } 227 } 228 229 impl Text for Label { 230 fn set_text<S: Into<String>>(&self, text: S) -> &Self { 231 let text = text.into(); 232 (*self.real_text.borrow_mut()) = text.clone(); 233 (*self.show_text.borrow_mut()) = text; 234 self.handle_overflow(); 235 align_rect( 236 self.text_rect.get(), 237 self.rect.get(), 238 self.text_pivot.get(), 239 Vector2::new(0, 0), 240 ); 241 self 242 } 243 244 fn set_text_color(&self, color: Color) -> &Self { 245 self.text_color.set(color); 246 self 247 } 248 } 249