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