use std::{borrow::Cow, hash::{Hash, Hasher}}; use fontdue::layout::{CoordinateSystem, Layout}; use glam::{vec2, Vec2}; use hui_shared::rect::Rect; use crate::{ paint::{ buffer::PaintBuffer, command::PaintCommand, }, text::FontHandle, PainterInstance }; // TODO align, multichunk etc pub struct TextChunk { pub text: Cow<'static, str>, pub font: FontHandle, pub size: f32, } pub struct PaintText { // TODO multiple text chunks pub text: TextChunk, } impl PaintText { pub fn new(text: impl Into<Cow<'static, str>>, font: FontHandle, size: f32) -> Self { Self { text: TextChunk { text: text.into(), font, size, } } } fn build_font_array<'a>(&self, ctx: &'a PainterInstance) -> Vec<&'a fontdue::Font> { let font = ctx.fonts.get_fontdue_font(self.text.font) .expect("FontHandle is invalid"); vec![&font] } fn build_layout(&self, font_array: &[&fontdue::Font]) -> Layout { let mut layout = Layout::new(CoordinateSystem::PositiveYDown); layout.append( font_array, &fontdue::layout::TextStyle::new( &self.text.text, self.text.size, 0 ) ); layout } } impl PaintCommand for PaintText { fn pre_paint(&self, ctx: &mut PainterInstance) { let font_array = self.build_font_array(ctx); let layout = self.build_layout(&font_array); for glyph in layout.glyphs() { ctx.fonts.render_glyph(&mut ctx.atlas, self.text.font, glyph.key); } } fn paint(&self, ctx: &mut PainterInstance, into: &mut PaintBuffer) { // let font_array = self.build_font_array(ctx); // let layout = self.build_layout(&font_array); // for glyph in layout.glyphs() { // let config = GlyphRasterConfig { // glyph_index: glyph.font_index // }; // let glyph_raster = ctx.fonts().render_glyph(atlas, font, config); // } // todo!() // TODO_IMPORTANT text rendering } fn bounds(&self, ctx: &PainterInstance) -> Rect { let font_array = self.build_font_array(ctx); let layout = self.build_layout(&font_array); let width = layout.lines().map(|lines| { lines.iter().fold(0.0_f32, |acc, x| { let glyph = layout.glyphs().get(x.glyph_end).unwrap(); acc.max(glyph.x + glyph.width as f32) }) }).unwrap_or(0.); let height = layout.height(); Rect { position: vec2(0., 0.), size: vec2(width, height), } } fn cache_hash(&self) -> u64 { let mut hasher = rustc_hash::FxHasher::default(); self.text.font.hash(&mut hasher); hasher.write_u32(self.text.size.to_bits()); hasher.write(self.text.text.as_bytes()); hasher.finish() } }