use crate::{
elements::rich_text::{RichText, Span},
fonts::Font,
*,
};
pub use elements::rich_text::TextAlign;
pub struct Text<'a, F: Font> {
pub text: &'a str,
pub font: &'a F,
pub size: f32,
pub color: u32,
pub underline: bool,
pub extra_character_spacing: f32,
pub extra_word_spacing: f32,
pub extra_line_height: f32,
pub align: TextAlign,
pub link: Option<LinkTarget<'a>>,
}
impl<'a, F: Font> Text<'a, F> {
pub fn new(text: &'a str, font: &'a F, size: f32) -> Self {
Text {
text,
font,
size,
color: 0x00_00_00_FF,
underline: false,
extra_character_spacing: 0.,
extra_word_spacing: 0.,
extra_line_height: 0.,
align: TextAlign::Left,
link: None,
}
}
fn as_rich_text(&self) -> RichText<std::iter::Once<Span<'a, F>>> {
RichText {
spans: std::iter::once(Span {
text: self.text,
font: self.font,
size: self.size,
color: self.color,
underline: self.underline,
extra_character_spacing: self.extra_character_spacing,
extra_word_spacing: self.extra_word_spacing,
extra_line_height: self.extra_line_height, link: self.link,
}),
align: self.align,
}
}
}
impl<'a, F: Font + 'a> Element for Text<'a, F> {
fn first_location_usage(&self, ctx: FirstLocationUsageCtx) -> FirstLocationUsage {
self.as_rich_text().first_location_usage(ctx)
}
fn measure(&self, ctx: MeasureCtx) -> ElementSize {
self.as_rich_text().measure(ctx)
}
fn draw(&self, ctx: DrawCtx) -> ElementSize {
self.as_rich_text().draw(ctx)
}
}
#[cfg(test)]
mod tests {
use elements::column::Column;
use fonts::truetype::TruetypeFont;
use insta::*;
use crate::fonts::builtin::BuiltinFont;
use crate::test_utils::binary_snapshots::*;
use super::*;
const FONT: &[u8] = include_bytes!("../../assets/fonts/Kenney Bold.ttf");
#[test]
fn test_multi_page() {
let bytes = test_element_bytes(TestElementParams::breakable(), |mut callback| {
let font = BuiltinFont::courier(callback.pdf());
let content = Text::new(LOREM_IPSUM, &font, 32.);
let content = content.debug(0);
callback.call(&content);
});
assert_binary_snapshot!(".pdf", bytes);
}
#[test]
fn test_truetype() {
let bytes = test_element_bytes(TestElementParams::breakable(), |mut callback| {
let font = TruetypeFont::new(callback.pdf(), FONT);
let content = Text::new(LOREM_IPSUM, &font, 32.);
let content = content.debug(0);
callback.call(&content);
});
assert_binary_snapshot!(".pdf", bytes);
}
#[test]
fn test_truetype_trailing_whitespace() {
let mut params = TestElementParams::breakable();
params.width.expand = false;
let bytes = test_element_bytes(params, |mut callback| {
let font = TruetypeFont::new(callback.pdf(), FONT);
let content = Text::new("Whitespace ", &font, 32.);
let content = content.debug(0);
callback.call(&content);
});
assert_binary_snapshot!(".pdf", bytes);
}
#[test]
fn test_truetype_extra_spacing() {
let mut params = TestElementParams::breakable();
params.width.expand = false;
let bytes = test_element_bytes(params, |mut callback| {
let font = TruetypeFont::new(callback.pdf(), FONT);
callback.call(&Column {
gap: 12.,
collapse: false,
content: |content| {
let normal = Text::new("Hello, World", &font, 32.);
let character_spacing = Text {
extra_character_spacing: 16.,
..Text::new("Hello, World", &font, 32.)
};
let word_spacing = Text {
extra_word_spacing: 16.,
..Text::new("Hello, World", &font, 32.)
};
let both = Text {
extra_character_spacing: 16.,
extra_word_spacing: 16.,
..Text::new("Hello, World", &font, 32.)
};
content
.add(&normal.debug(0).show_max_width())?
.add(&character_spacing.debug(1).show_max_width())?
.add(&word_spacing.debug(2).show_max_width())?
.add(&both.debug(3).show_max_width())?;
None
},
});
});
assert_binary_snapshot!(".pdf", bytes);
}
#[test]
fn test_truetype_soft_hyphen() {
let mut params = TestElementParams::breakable();
params.width.expand = false;
let bytes = test_element_bytes(params, |mut callback| {
let font = TruetypeFont::new(callback.pdf(), FONT);
callback.call(&Column {
gap: 12.,
collapse: false,
content: |content| {
let a = Text::new("Hello\u{00AD}Wrld", &font, 32.);
let b = Text::new("A Hello\u{00AD}Wrld", &font, 32.);
let c = Text::new("A\u{00A0}Hello\u{00AD}Wrld", &font, 32.);
let d = Text::new("Hello\u{00AD}Wrld\u{00AD}", &font, 32.);
content
.add(&Padding::right(100., a.debug(0).show_max_width()))?
.add(&Padding::right(120., b.debug(0).show_max_width()))?
.add(&Padding::right(120., c.debug(0).show_max_width()))?
.add(&Padding::right(20., d.debug(0).show_max_width()))?;
None
},
});
});
assert_binary_snapshot!(".pdf", bytes);
}
}