144 lines
4.1 KiB
Rust
144 lines
4.1 KiB
Rust
use cosmic_text::{Attrs, Family, FontSystem, Metrics, Shaping};
|
|
|
|
use crate::{prelude::*, util::MutDetect};
|
|
|
|
pub struct Text {
|
|
pub content: MutDetect<String>,
|
|
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<String>) -> 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<String>) -> 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
|
|
}
|
|
}
|