2024-02-27 13:31:12 -06:00
|
|
|
//! text rendering, styling, measuring
|
|
|
|
|
2024-02-17 14:43:46 -06:00
|
|
|
use std::sync::Arc;
|
2024-03-01 11:21:02 -06:00
|
|
|
use fontdue::{Font, FontSettings};
|
|
|
|
use crate::draw::atlas::TextureAtlasManager;
|
2024-02-17 14:43:46 -06:00
|
|
|
|
|
|
|
mod font;
|
|
|
|
mod ftm;
|
2024-03-01 11:21:02 -06:00
|
|
|
mod stack;
|
2024-02-17 14:43:46 -06:00
|
|
|
|
2024-03-23 17:23:24 -05:00
|
|
|
/// Built-in font handle
|
2024-02-21 04:19:14 -06:00
|
|
|
#[cfg(feature="builtin_font")]
|
|
|
|
pub use font::BUILTIN_FONT;
|
2024-03-01 11:21:02 -06:00
|
|
|
pub use font::FontHandle;
|
|
|
|
|
|
|
|
use font::FontManager;
|
2024-02-17 14:43:46 -06:00
|
|
|
use ftm::FontTextureManager;
|
2024-02-27 11:23:55 -06:00
|
|
|
use ftm::GlyphCacheEntry;
|
2024-03-01 11:21:02 -06:00
|
|
|
use stack::FontStack;
|
2024-02-24 16:32:09 -06:00
|
|
|
|
2024-03-23 17:23:24 -05:00
|
|
|
pub(crate) struct TextRenderer {
|
2024-03-01 11:21:02 -06:00
|
|
|
manager: FontManager,
|
2024-02-17 14:43:46 -06:00
|
|
|
ftm: FontTextureManager,
|
2024-03-01 11:21:02 -06:00
|
|
|
stack: FontStack,
|
2024-02-17 14:43:46 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
impl TextRenderer {
|
|
|
|
pub fn new() -> Self {
|
|
|
|
Self {
|
2024-03-01 11:21:02 -06:00
|
|
|
manager: FontManager::new(),
|
2024-02-17 14:43:46 -06:00
|
|
|
ftm: FontTextureManager::default(),
|
2024-03-01 11:21:02 -06:00
|
|
|
stack: FontStack::new(),
|
2024-02-17 14:43:46 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn add_font_from_bytes(&mut self, font: &[u8]) -> FontHandle {
|
2024-03-01 11:21:02 -06:00
|
|
|
self.manager.add_font(Font::from_bytes(font, FontSettings::default()).unwrap())
|
2024-02-17 14:43:46 -06:00
|
|
|
}
|
|
|
|
|
2024-02-24 16:32:09 -06:00
|
|
|
pub fn glyph(&mut self, atlas: &mut TextureAtlasManager, font_handle: FontHandle, character: char, size: u8) -> Arc<GlyphCacheEntry> {
|
2024-03-01 11:21:02 -06:00
|
|
|
self.ftm.glyph(atlas, &self.manager, font_handle, character, size)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn push_font(&mut self, font: FontHandle) {
|
|
|
|
self.stack.push(font);
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn pop_font(&mut self) {
|
|
|
|
self.stack.pop();
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn current_font(&self) -> FontHandle {
|
|
|
|
self.stack.current_or_default()
|
2024-02-17 14:43:46 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) fn internal_font(&self, handle: FontHandle) -> &Font {
|
2024-03-01 11:21:02 -06:00
|
|
|
self.manager.get(handle).unwrap()
|
2024-02-17 14:43:46 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Default for TextRenderer {
|
|
|
|
fn default() -> Self {
|
|
|
|
Self::new()
|
|
|
|
}
|
|
|
|
}
|
2024-02-17 21:04:02 -06:00
|
|
|
|
2024-03-23 17:23:24 -05:00
|
|
|
/// Size of measured text
|
2024-02-17 21:04:02 -06:00
|
|
|
pub struct TextMeasureResponse {
|
|
|
|
pub max_width: f32,
|
|
|
|
pub height: f32,
|
|
|
|
}
|
|
|
|
|
2024-03-23 17:23:24 -05:00
|
|
|
/// Context for measuring text
|
2024-02-17 21:04:02 -06:00
|
|
|
#[derive(Clone, Copy)]
|
|
|
|
pub struct TextMeasure<'a>(&'a TextRenderer);
|
|
|
|
|
2024-12-11 13:36:14 -06:00
|
|
|
impl TextMeasure<'_> {
|
2024-03-23 17:23:24 -05:00
|
|
|
/// Measure the given string of text with the given font and size
|
2024-02-24 21:02:10 -06:00
|
|
|
pub fn measure(&self, font: FontHandle, size: u16, text: &str) -> TextMeasureResponse {
|
2024-02-17 21:04:02 -06:00
|
|
|
use fontdue::layout::{Layout, CoordinateSystem, TextStyle};
|
|
|
|
let mut layout = Layout::new(CoordinateSystem::PositiveYDown);
|
|
|
|
layout.append(
|
|
|
|
&[self.0.internal_font(font)],
|
|
|
|
&TextStyle::new(text, size as f32, 0)
|
|
|
|
);
|
|
|
|
TextMeasureResponse {
|
|
|
|
max_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.),
|
2024-02-18 10:22:31 -06:00
|
|
|
height: layout.height(),
|
2024-02-17 21:04:02 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl TextRenderer {
|
|
|
|
pub fn to_measure(&self) -> TextMeasure {
|
|
|
|
TextMeasure(self)
|
|
|
|
}
|
|
|
|
|
2024-02-24 21:02:10 -06:00
|
|
|
pub fn measure(&self, font: FontHandle, size: u16, text: &str) -> TextMeasureResponse {
|
2024-02-17 21:04:02 -06:00
|
|
|
TextMeasure(self).measure(font, size, text)
|
|
|
|
}
|
|
|
|
}
|