use crate::bitfield; use crate::common::Rect; use crate::engine_constants::EngineConstants; use crate::framework::context::Context; use crate::framework::error::GameResult; use crate::graphics::texture_set::TextureSet; bitfield! { #[derive(Clone, Copy)] #[repr(C)] pub struct TextBuilderFlag(u8); pub shadow, set_shadow: 0; pub centered, set_centered: 1; } #[derive(Copy, Clone)] pub struct Symbols<'a> { pub symbols: &'a [(char, Rect)], pub texture: &'a str, } pub static EMPTY_SYMBOLS: Symbols = Symbols { symbols: &[], texture: "" }; pub trait Font { fn builder(&self) -> TextBuilder where Self: Sized, { TextBuilder::new(self) } fn line_height(&self) -> f32; fn compute_width(&self, text: &mut dyn Iterator, symbols: Option<&Symbols>) -> f32; fn draw( &self, text: &mut dyn Iterator, x: f32, y: f32, scale: f32, box_width: f32, shadow_color: (u8, u8, u8, u8), color: (u8, u8, u8, u8), flags: TextBuilderFlag, constants: &EngineConstants, texture_set: &mut TextureSet, symbols: Option, ctx: &mut Context, ) -> GameResult; } pub struct TextBuilder<'a, 'b> { font: &'a dyn Font, x: f32, y: f32, scale: f32, shadow_color: (u8, u8, u8, u8), color: (u8, u8, u8, u8), flags: TextBuilderFlag, box_width: f32, symbols: Option>, } #[allow(dead_code)] impl<'a, 'b> TextBuilder<'a, 'b> { #[inline] pub fn new(font: &'a dyn Font) -> Self { Self { font, x: 0.0, y: 0.0, scale: 1.0, shadow_color: (0, 0, 0, 150), color: (255, 255, 255, 255), flags: TextBuilderFlag(0), box_width: 0.0, symbols: None, } } #[inline] pub fn position(mut self, x: f32, y: f32) -> Self { self.x = x; self.y = y; self } #[inline] pub fn x(mut self, x: f32) -> Self { self.x = x; self } #[inline] pub fn y(mut self, y: f32) -> Self { self.y = y; self } #[inline] pub fn get_position(&self) -> (f32, f32) { (self.x, self.y) } #[inline] pub const fn color(mut self, color: (u8, u8, u8, u8)) -> Self { self.color = color; self } #[inline] pub const fn get_color(&self) -> (u8, u8, u8, u8) { self.color } #[inline] pub const fn shadow_color(mut self, color: (u8, u8, u8, u8)) -> Self { self.shadow_color = color; self } #[inline] pub const fn get_shadow_color(&self) -> (u8, u8, u8, u8) { self.shadow_color } #[inline] pub const fn scale(mut self, scale: f32) -> Self { self.scale = scale; self } #[inline] pub const fn get_scale(&self) -> f32 { self.scale } #[inline] pub fn shadow(mut self, shadow: bool) -> Self { self.flags.set_shadow(shadow); self } #[inline] pub fn get_shadow(&self) -> bool { self.flags.shadow() } #[inline] pub fn with_symbols(mut self, symbols: Option>) -> Self { self.symbols = symbols; self } #[inline] pub fn center(mut self, box_width: f32) -> Self { self.box_width = box_width; self.flags.set_centered(true); self } #[inline] pub fn compute_width(&self, text: &str) -> f32 { self.compute_width_iter(text.chars()) } #[inline] pub fn compute_width_iter(&self, mut text: impl Iterator) -> f32 { self.font.compute_width(&mut text, self.symbols.as_ref()) } #[inline] pub fn draw( self, text: &str, ctx: &mut Context, constants: &EngineConstants, texture_set: &mut TextureSet, ) -> GameResult { self.draw_iter(text.chars(), ctx, constants, texture_set) } pub fn draw_iter( self, mut text: impl Iterator, ctx: &mut Context, constants: &EngineConstants, texture_set: &mut TextureSet, ) -> GameResult { self.font.draw( &mut text, self.x, self.y, self.scale, self.box_width, self.shadow_color, self.color, self.flags, constants, texture_set, self.symbols, ctx, ) } }