use crate::types::shaped_glyph::ShapedGlyph;
use crate::types::line::LineInfo;
#[derive(Debug, Clone, Default)]
pub struct ShapedBuffer {
glyphs: Vec<ShapedGlyph>,
lines: Vec<LineInfo>,
width: f32,
height: f32,
}
impl ShapedBuffer {
pub fn new(glyphs: Vec<ShapedGlyph>, lines: Vec<LineInfo>, width: f32, height: f32) -> Self {
Self { glyphs, lines, width, height }
}
pub fn glyphs(&self) -> &[ShapedGlyph] {
&self.glyphs
}
pub fn lines(&self) -> &[LineInfo] {
&self.lines
}
pub fn len(&self) -> usize {
self.glyphs.len()
}
pub fn is_empty(&self) -> bool {
self.glyphs.is_empty()
}
pub fn content_size(&self) -> (f32, f32) {
(self.width, self.height)
}
pub fn outer_size(&self, padding: &crate::types::options::Padding) -> (f32, f32) {
(
self.width + padding.left + padding.right,
self.height + padding.top + padding.bottom,
)
}
pub fn size(&self) -> (f32, f32) {
self.content_size()
}
pub fn index_at(&self, x: f32, y: f32) -> usize {
if self.lines.is_empty() || self.glyphs.is_empty() {
return 0;
}
let mut best_line_idx = 0;
let mut min_dist_y = f32::MAX;
for (i, line) in self.lines.iter().enumerate() {
let dist = (y - line.y).abs();
if dist < min_dist_y {
min_dist_y = dist;
best_line_idx = i;
}
}
let best_line = &self.lines[best_line_idx];
let mut best_cluster = 0;
let mut min_dist_x = f32::MAX;
let mut found_glyph = false;
for glyph in &self.glyphs {
if (glyph.y - best_line.y).abs() < 1.0 {
let center_x = glyph.x + glyph.width / 2.0;
let dist = (x - center_x).abs();
if dist < min_dist_x {
min_dist_x = dist;
best_cluster = glyph.cluster;
found_glyph = true;
}
}
}
if !found_glyph {
return self.glyphs.first().map(|g| g.cluster).unwrap_or(0);
}
best_cluster
}
pub fn position_at(&self, index: usize) -> Option<(f32, f32)> {
self.glyphs.iter()
.find(|g| g.cluster == index)
.map(|g| (g.x, g.y))
}
}