use crate::drawing::{Drawable, Plan};
use crate::layouts::{HasPlanner, Layout};
use skia_safe::{Canvas, Font, Paint, Point};
use std::cell::RefCell;
use std::rc::Rc;
pub struct TruncatedText {
text: RefCell<String>,
font: Font,
pub p: RefCell<Paint>,
dot_w: f32,
planner: RefCell<Option<Rc<dyn Layout>>>,
}
impl HasPlanner for TruncatedText {
fn planner(&self) -> &RefCell<Option<Rc<dyn Layout>>> {
&self.planner
}
fn set_planner(&self, p: Option<Rc<dyn Layout>>) {
*self.planner.borrow_mut() = p;
}
}
impl Drawable for TruncatedText {
fn draw(&self, canvas: &Canvas) -> anyhow::Result<()> {
let area = self.get_planned_drawing_area(canvas);
if area.is_empty() {
return Ok(());
}
let display_text = self.text.borrow();
let max_w = area.width();
let mut glyphs = vec![skia_safe::GlyphId::default(); display_text.len()];
let actual_glyph_count = self
.font
.text_to_glyphs(display_text.to_owned(), &mut glyphs);
glyphs.truncate(actual_glyph_count);
let mut widths = vec![0.0f32; glyphs.len()];
self.font.get_widths(&glyphs, &mut widths);
let total_text_w: f32 = widths.iter().sum();
let mut text_to_draw = display_text.clone();
if total_text_w > max_w {
let mut current_w = 0.0;
let mut char_count = 0;
let allowed_w = max_w - self.dot_w;
for &w in &widths {
if current_w + w > allowed_w {
break;
}
current_w += w;
char_count += 1;
}
if char_count > 0 {
text_to_draw = format!(
"{}...",
&display_text.chars().take(char_count).collect::<String>()
);
}
}
let (_, metrics) = self.font.metrics();
let center_y = area.top + area.height() / 2.0;
let baseline_y = center_y - (metrics.ascent + metrics.descent) / 2.0;
canvas.draw_str(
&text_to_draw,
Point::new(area.left, baseline_y),
&self.font,
&self.p.borrow(),
);
Ok(())
}
fn get_horizontal_plan(&self) -> Plan {
Plan::Fill
}
fn get_vertical_plan(&self) -> Plan {
Plan::Fill
}
}
impl TruncatedText {
pub fn new(text: &str, font: Font, paint: Paint, dot_w: f32) -> Rc<Self> {
Rc::new(Self {
text: RefCell::new(text.to_string()),
font,
p: RefCell::new(paint),
dot_w,
planner: RefCell::new(None),
})
}
}