git.lucas.co / cce-ui
GPU-accelerated UI toolkit (Vulkan)
git clone https://git.lucas.co/cce-ui.git

src/widget/display/text_label.rs (2.7K)

 1 
 2 #[derive(Debug, Clone)]
 3 pub struct TextLabel {
 4     pub text: String,
 5     pub x: f32,
 6     pub y: f32,
 7     pub font_size: f32,
 8     pub color: [u8; 3],
 9 }
10 
11 impl TextLabel {
12     pub fn estimate_width(text: &str, font_size: f32) -> f32 {
13         let mut weight_sum = 0.0;
14         for c in text.chars() {
15             weight_sum += match c {
16                 'i' | 'l' | 't' | 'j' | 'I' | ' ' | '.' | ',' | '!' | ';' | ':' | '\'' | '1' | '-' | '(' | ')' | '[' | ']' => 0.26,
17                 'f' | 'r' | 's' | 'J' => 0.35,
18                 'w' | 'm' | 'M' | 'W' => 0.72,
19                 'A' | 'B' | 'C' | 'D' | 'E' | 'G' | 'H' | 'K' | 'N' | 'O' | 'P' | 'Q' | 'R' | 'S' | 'T' | 'U' | 'V' | 'X' | 'Y' | 'Z' => 0.65,
20                 _ => 0.52,
21             };
22         }
23         (weight_sum * font_size * 1.30).ceil()
24     }
25 
26     pub fn curved_layout(
27         text: &str,
28         cx: f32,
29         cy: f32,
30         r: f32,
31         start_angle: f32,
32         end_angle: f32,
33         font_size: f32,
34         color: [u8; 3],
35     ) -> Vec<TextLabel> {
36         let mut labels = Vec::new();
37         let font_fam = crate::layout::menubar_font_parsed().0;
38         let char_widths: Vec<f32> = text.chars().map(|c| {
39             crate::widget::display::measure_text_width(&c.to_string(), &font_fam, font_size)
40         }).collect();
41         let total_width: f32 = char_widths.iter().sum();
42         
43         let mid_angle = (start_angle + end_angle) / 2.0;
44         let angular_width = total_width / r;
45         let text_start_angle = mid_angle - angular_width / 2.0;
46         
47         let mut current_angle = text_start_angle;
48         for (i, c) in text.chars().enumerate() {
49             let cw = char_widths[i];
50             let dtheta = cw / r;
51             let char_center_angle = current_angle + dtheta / 2.0;
52             
53             let x = cx + r * char_center_angle.cos() - cw / 2.0;
54             let y = cy + r * char_center_angle.sin() - font_size / 2.0;
55             
56             labels.push(TextLabel {
57                 text: c.to_string(),
58                 x,
59                 y,
60                 font_size,
61                 color,
62             });
63             
64             current_angle += dtheta;
65         }
66         labels
67     }
68  
69     pub fn is_covered_by(&self, px: f32, py: f32, pw: f32, ph: f32) -> bool {
70         let text_w = crate::widget::display::measure_text(&self.text, self.font_size);
71         let x_overlap = self.x <= px + pw && (self.x + text_w) >= px;
72         let y_overlap = self.y <= py + ph && (self.y + self.font_size) >= py;
73         x_overlap && y_overlap
74     }
75 }
76 
77 pub(crate) fn make_widget_text_buffer(fs: &mut cosmic_text::FontSystem, text: &str, size: f32, font_family: &str) -> cosmic_text::Buffer {
78     crate::backend::window_runner::get_text_buffer(fs, text, size, Some(font_family))
79 }