mod build; mod edit; pub use build::*; pub use edit::*; use crate::{prelude::*, util::MutDetect}; use cosmic_text::{Attrs, Metrics, Shaping}; use std::ops::{Deref, DerefMut}; pub const SHAPING: Shaping = Shaping::Advanced; pub struct Text { pub content: MutDetect, view: TextView, } pub struct TextView { pub attrs: MutDetect, pub buf: MutDetect, // cache tex: Option, width: Option, } impl TextView { pub fn new(buf: TextBuffer, attrs: TextAttrs) -> Self { Self { attrs: attrs.into(), buf: buf.into(), tex: None, width: None, } } pub fn draw(&mut self, ctx: &mut SizeCtx) -> TextTexture { let width = if self.attrs.wrap { Some(ctx.px_size().x) } else { None }; if width == self.width && let Some(tex) = &self.tex && !self.attrs.changed && !self.buf.changed { return tex.clone(); } self.width = width; let font_system = &mut ctx.text.font_system; self.attrs.apply(font_system, &mut self.buf, width); self.buf.shape_until_scroll(font_system, false); let tex = ctx.draw_text(&mut self.buf, &self.attrs); self.tex = Some(tex.clone()); self.attrs.changed = false; self.buf.changed = false; tex } pub fn tex(&self) -> Option<&TextTexture> { self.tex.as_ref() } } impl Text { pub fn new(content: impl Into) -> Self { let attrs = TextAttrs::default(); let buf = TextBuffer::new_empty(Metrics::new(attrs.font_size, attrs.line_height)); Self { content: content.into().into(), view: TextView::new(buf, attrs), } } fn update_buf(&mut self, ctx: &mut SizeCtx) -> TextTexture { if self.content.changed { self.content.changed = false; self.view.buf.set_text( &mut ctx.text.font_system, &self.content, &Attrs::new().family(self.view.attrs.family), SHAPING, None, ); } self.view.draw(ctx) } } impl Widget for Text { fn draw(&mut self, painter: &mut Painter) { let tex = self.update_buf(&mut painter.size_ctx()); let region = text_region(&tex, self.align); painter.texture_within(&tex.handle, region); } fn desired_size(&mut self, ctx: &mut SizeCtx) -> Size { Size::abs(self.update_buf(ctx).size()) } } pub fn text_region(tex: &TextTexture, align: Align) -> UiRegion { let tex_dims = tex.handle.size(); let mut region = UiRegion::from_size_align(tex.size(), align); region.top_left.abs += tex.top_left; region.bot_right.abs = region.top_left.abs + tex_dims; region } impl Deref for Text { type Target = TextAttrs; fn deref(&self) -> &Self::Target { &self.view } } impl DerefMut for Text { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.view } } impl Deref for TextView { type Target = TextAttrs; fn deref(&self) -> &Self::Target { &self.attrs } } impl DerefMut for TextView { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.attrs } }