use cosmic_text::{Attrs, Family, FontSystem, Metrics, Shaping}; use crate::{prelude::*, util::MutDetect}; pub struct Text { pub content: MutDetect, pub attrs: TextAttrs, /// inner alignment of text region (within where its drawn) pub align: Align, pub(super) buf: TextBuffer, size: Vec2, } impl Text { pub fn size(mut self, size: impl UiNum) -> Self { self.attrs.font_size = size.to_f32(); self.attrs.line_height = self.attrs.font_size * 1.1; self } pub fn color(mut self, color: UiColor) -> Self { self.attrs.color = color; self } pub fn family(mut self, family: Family<'static>) -> Self { self.attrs.family = family; self } pub fn line_height(mut self, height: f32) -> Self { self.attrs.line_height = height; self } pub fn new(content: impl Into) -> Self { let attrs = TextAttrs::default(); Self { content: content.into().into(), buf: TextBuffer::new_empty(Metrics::new(attrs.font_size, attrs.line_height)), attrs, align: Align::Center, size: Vec2::ZERO, } } pub fn region(&self) -> UiRegion { UiRegion::from_size_align(self.size, self.align) } fn update_buf(&mut self, font_system: &mut FontSystem) { self.buf.set_metrics( font_system, Metrics::new(self.attrs.font_size, self.attrs.line_height), ); if self.content.changed { self.content.changed = false; self.buf.set_text( font_system, &self.content, &Attrs::new().family(self.attrs.family), Shaping::Advanced, ); } } } impl Widget for Text { fn draw(&mut self, painter: &mut Painter) { let font_system = &mut painter.text_data().font_system; self.update_buf(font_system); let (handle, offset) = painter.render_text(&mut self.buf, &self.attrs); let dims = handle.size(); self.size = offset.size(&handle); let mut region = self.region(); region.top_left.abs += offset.top_left; region.bot_right.abs = region.top_left.abs + dims; painter.texture_within(&handle, region); } fn desired_size(&mut self, ctx: &mut SizeCtx) -> UiVec2 { self.update_buf(&mut ctx.text.font_system); let (handle, offset) = ctx.draw_text(&mut self.buf, &self.attrs); UiVec2::abs(offset.size(&handle)) } } pub fn text(content: impl Into) -> TextBuilder { TextBuilder { content: content.into(), align: Align::Center, attrs: TextAttrs::default(), } } pub struct TextBuilder { pub content: String, pub attrs: TextAttrs, /// inner alignment of text region (within where its drawn) pub align: Align, } impl TextBuilder { pub fn size(mut self, size: impl UiNum) -> Self { self.attrs.font_size = size.to_f32(); self.attrs.line_height = self.attrs.font_size * 1.1; self } pub fn color(mut self, color: UiColor) -> Self { self.attrs.color = color; self } pub fn family(mut self, family: Family<'static>) -> Self { self.attrs.family = family; self } pub fn line_height(mut self, height: f32) -> Self { self.attrs.line_height = height; self } } impl FnOnce<(&mut Ui,)> for TextBuilder { type Output = Text; extern "rust-call" fn call_once(self, args: (&mut Ui,)) -> Self::Output { let mut buf = TextBuffer::new_empty(Metrics::new(self.attrs.font_size, self.attrs.line_height)); buf.set_text( &mut args.0.text.font_system, &self.content, &Attrs::new(), Shaping::Advanced, ); let mut text = Text { content: self.content.into(), buf, attrs: self.attrs, align: self.align, size: Vec2::ZERO, }; text.content.changed = false; self.attrs .apply(&mut args.0.text.font_system, &mut text.buf); text } }