zenthra_text/primitives/
shaped_buffer.rs1use crate::types::shaped_glyph::ShapedGlyph;
2use crate::types::line::LineInfo;
3
4#[derive(Debug, Clone, Default)]
7pub struct ShapedBuffer {
8 glyphs: Vec<ShapedGlyph>,
9 lines: Vec<LineInfo>,
10 width: f32,
11 height: f32,
12}
13
14impl ShapedBuffer {
15 pub fn new(glyphs: Vec<ShapedGlyph>, lines: Vec<LineInfo>, width: f32, height: f32) -> Self {
17 Self { glyphs, lines, width, height }
18 }
19
20 pub fn glyphs(&self) -> &[ShapedGlyph] {
22 &self.glyphs
23 }
24
25 pub fn lines(&self) -> &[LineInfo] {
27 &self.lines
28 }
29
30 pub fn len(&self) -> usize {
32 self.glyphs.len()
33 }
34
35 pub fn is_empty(&self) -> bool {
37 self.glyphs.is_empty()
38 }
39
40 pub fn content_size(&self) -> (f32, f32) {
42 (self.width, self.height)
43 }
44
45 pub fn outer_size(&self, padding: &crate::types::options::Padding) -> (f32, f32) {
47 (
48 self.width + padding.left + padding.right,
49 self.height + padding.top + padding.bottom,
50 )
51 }
52
53 pub fn size(&self) -> (f32, f32) {
56 self.content_size()
57 }
58
59 pub fn index_at(&self, x: f32, y: f32) -> usize {
61 if self.lines.is_empty() || self.glyphs.is_empty() {
62 return 0;
63 }
64
65 let mut best_line_idx = 0;
67 let mut min_dist_y = f32::MAX;
68
69 for (i, line) in self.lines.iter().enumerate() {
70 let dist = (y - line.y).abs();
71 if dist < min_dist_y {
72 min_dist_y = dist;
73 best_line_idx = i;
74 }
75 }
76
77 let best_line = &self.lines[best_line_idx];
78
79 let mut best_cluster = 0;
81 let mut min_dist_x = f32::MAX;
82
83 let mut found_glyph = false;
86 for glyph in &self.glyphs {
87 if (glyph.y - best_line.y).abs() < 1.0 {
88 let center_x = glyph.x + glyph.width / 2.0;
89 let dist = (x - center_x).abs();
90 if dist < min_dist_x {
91 min_dist_x = dist;
92 best_cluster = glyph.cluster;
93 found_glyph = true;
94 }
95 }
96 }
97
98 if !found_glyph {
99 return self.glyphs.first().map(|g| g.cluster).unwrap_or(0);
101 }
102
103 best_cluster
104 }
105
106 pub fn position_at(&self, index: usize) -> Option<(f32, f32)> {
108 self.glyphs.iter()
109 .find(|g| g.cluster == index)
110 .map(|g| (g.x, g.y))
111 }
112}
113
114
115