Skip to main content

multi_mono_font/
lib.rs

1#![no_std]
2
3mod char_size;
4mod draw_target;
5mod framebuf;
6mod generated;
7pub mod mapping;
8mod mono_image;
9mod multi_mono_text_style;
10mod static_text;
11mod sub_image;
12
13use core::fmt;
14
15pub use char_size::CharSize;
16pub use framebuf::{BulkFlushTarget, Framebuffer};
17pub use generated::*;
18use mapping::StrGlyphMapping;
19pub use mono_image::MonoImage;
20pub use multi_mono_text_style::{
21    MultiMonoLineHeight, MultiMonoTextStyle, MultiMonoTextStyleBuilder,
22};
23pub use static_text::StaticText;
24
25pub type MultiMonoFontList<'a> = &'a [&'a MultiMonoFont<'a>];
26
27use embedded_graphics::{
28    geometry::{OriginDimensions, Point},
29    image::ImageRaw,
30    pixelcolor::BinaryColor,
31    primitives::Rectangle,
32};
33use sub_image::SubImage;
34
35#[cfg(not(feature = "big-character-size"))]
36pub type ChSzTy = u8;
37#[cfg(feature = "big-character-size")]
38pub type ChSzTy = u16;
39
40/// A trait for objects that can be scaled.
41pub trait Scalable {
42    type T;
43    fn set_scale(&mut self, scale: Self::T);
44    fn get_scale(&self) -> Self::T;
45}
46
47/// Monospaced bitmap font.
48///
49/// See the [module documentation] for more information about using fonts.
50///
51/// [module documentation]: self
52#[derive(Clone, Copy)]
53pub struct MultiMonoFont<'a> {
54    /// Raw image data containing the font.
55    pub image: ImageRaw<'a, BinaryColor>,
56
57    /// Size of a single character in pixel.
58    pub character_size: CharSize,
59
60    /// Spacing between characters.
61    ///
62    /// The spacing defines how many empty pixels are added horizontally between adjacent characters
63    /// on a single line of text.
64    pub character_spacing: ChSzTy,
65
66    /// The baseline.
67    ///
68    /// Offset from the top of the glyph bounding box to the baseline.
69    pub baseline: ChSzTy,
70
71    /// Glyph mapping.
72    pub glyph_mapping: &'a StrGlyphMapping<'a>,
73}
74
75impl MultiMonoFont<'_> {
76    /// Returns a subimage for a glyph.
77    pub(crate) fn glyph(&self, c: char) -> SubImage<'_, ImageRaw<'_, BinaryColor>> {
78        if self.character_size.width == 0
79            || self.image.size().width < self.character_size.width as u32
80        {
81            return SubImage::new_unchecked(&self.image, Rectangle::zero());
82        }
83
84        let glyphs_per_row = self.image.size().width / self.character_size.width as u32;
85
86        // Char _code_ offset from first char, most often a space
87        // E.g. first char = ' ' (32), target char = '!' (33), offset = 33 - 32 = 1
88        let glyph_index = self.glyph_mapping.index(c) as u32;
89        let row = glyph_index / glyphs_per_row;
90
91        // Top left corner of character, in pixels
92        let char_x = (glyph_index - (row * glyphs_per_row)) * self.character_size.width as u32;
93        let char_y = row * self.character_size.height as u32;
94
95        SubImage::new_unchecked(
96            &self.image,
97            Rectangle::new(
98                Point::new(char_x as i32, char_y as i32),
99                self.character_size.size(),
100            ),
101        )
102    }
103}
104
105impl PartialEq for MultiMonoFont<'_> {
106    #[allow(trivial_casts)]
107    fn eq(&self, other: &Self) -> bool {
108        self.image == other.image
109            && self.character_size == other.character_size
110            && self.character_spacing == other.character_spacing
111            && self.baseline == other.baseline
112            && core::ptr::eq(self.glyph_mapping, other.glyph_mapping)
113    }
114}
115
116impl fmt::Debug for MultiMonoFont<'_> {
117    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
118        f.debug_struct("MultiMonoFont")
119            .field("image", &self.image)
120            .field("character_size", &self.character_size)
121            .field("character_spacing", &self.character_spacing)
122            .field("baseline", &self.baseline)
123            .field("glyph_mapping", &"?")
124            .finish_non_exhaustive()
125    }
126}
127
128#[cfg(feature = "defmt")]
129impl ::defmt::Format for MultiMonoFont<'_> {
130    fn format(&self, f: ::defmt::Formatter) {
131        ::defmt::write!(
132            f,
133            "MultiMonoFont {{ image: {}, character_size: {}, character_spacing: {}, baseline: {}, strikethrough: {}, underline: {}, .. }}",
134            &self.image,
135            &self.character_size,
136            &self.character_spacing,
137            &self.baseline,
138            &self.strikethrough,
139            &self.underline,
140
141        )
142    }
143}
144
145const NULL_FONT: MultiMonoFont = MultiMonoFont {
146    image: ImageRaw::new(&[], 1),
147    character_size: CharSize::zero(),
148    character_spacing: 0,
149    baseline: 0,
150    glyph_mapping: &StrGlyphMapping::new("", 0),
151};