use densa_core::{Color, Point, Size};
use densa_draw::Canvas;
use densa_paragraph::{Paragraph, ParagraphStyle};
use densa_ui::{Available, Constraints, LayoutCx};
#[derive(Debug)]
pub(crate) struct Text {
content: String,
size: Option<f32>,
wrap: bool,
paragraph: Option<Paragraph>,
shaped: Option<(f32, Color)>,
}
impl Text {
pub(crate) fn new(content: impl Into<String>) -> Self {
Self {
content: content.into(),
size: None,
wrap: false,
paragraph: None,
shaped: None,
}
}
pub(crate) fn as_str(&self) -> &str {
&self.content
}
pub(crate) fn set(&mut self, content: impl Into<String>) {
self.content = content.into();
self.paragraph = None;
}
pub(crate) fn set_size(&mut self, logical: f32) {
self.size = Some(logical);
self.paragraph = None;
}
pub(crate) fn set_wrap(&mut self, wrap: bool) {
self.wrap = wrap;
}
pub(crate) fn shape(&mut self, cx: &mut LayoutCx<'_>, color: Color) -> Option<&mut Paragraph> {
let px = cx.px(self.size.unwrap_or(cx.theme().font_size));
if self.paragraph.is_none() || self.shaped != Some((px, color)) {
let style = ParagraphStyle::new(px).with_color(color);
self.paragraph = cx.text_system().paragraph(&self.content, &style, &[]).ok();
self.shaped = Some((px, color));
}
self.paragraph.as_mut()
}
pub(crate) fn measure(
&mut self,
cx: &mut LayoutCx<'_>,
constraints: Constraints,
color: Color,
) -> Size {
let wrap = self.wrap;
let Some(paragraph) = self.shape(cx, color) else {
return Size::ZERO;
};
let width = constraints.width.or(match constraints.available_width {
Available::Definite(room) => Some(room),
Available::MinContent => Some(0.0),
_ => None,
});
let _ = paragraph.reflow(width.filter(|_| wrap));
Size::new(paragraph.width().ceil(), paragraph.height().ceil())
}
pub(crate) fn fit(&mut self, cx: &mut LayoutCx<'_>, width: f32, color: Color) {
let wrap = self.wrap;
if let Some(paragraph) = self.shape(cx, color) {
let _ = paragraph.reflow(wrap.then_some(width.max(0.0)));
}
}
pub(crate) fn size(&self) -> Size {
self.paragraph
.as_ref()
.map_or(Size::ZERO, |p| Size::new(p.width(), p.height()))
}
pub(crate) fn paint(&self, canvas: &mut Canvas<'_>, origin: Point) {
if let Some(paragraph) = &self.paragraph {
for run in paragraph.runs() {
canvas.draw_run(run, origin);
}
}
}
}