endbasic_std/gfx/lcd/fonts/
mod.rs1use crate::console::{CharsXY, SizeInPixels};
20use crate::gfx::lcd::LcdSize;
21use std::collections::HashMap;
22use std::io;
23
24mod font_5x8;
25pub use font_5x8::FONT_5X8;
26
27mod font_16x16;
28pub use font_16x16::FONT_16X16;
29
30mod font_vga8x16;
31pub use font_vga8x16::FONT_VGA8X16;
32
33pub struct Font {
35 pub name: &'static str,
37
38 pub glyph_size: LcdSize,
40
41 pub stride: usize,
43
44 pub data: &'static [u8],
46}
47
48impl Font {
49 pub(crate) fn glyph(&self, mut ch: char) -> &'static [u8] {
54 if !(' '..='~').contains(&ch) {
55 ch = '?';
58 }
59 let height = self.glyph_size.height * self.stride;
60 let offset = ((ch as usize) - (' ' as usize)) * height;
61 debug_assert!(offset < (self.data.len() + height));
62 &self.data[offset..offset + height]
63 }
64
65 pub fn chars_in_area(&self, area: SizeInPixels) -> CharsXY {
67 CharsXY::new(
68 area.width
69 .checked_div(u16::try_from(self.glyph_size.width).expect("Must fit"))
70 .expect("Glyph size tested for non-zero during init"),
71 area.height
72 .checked_div(u16::try_from(self.glyph_size.height).expect("Must fit"))
73 .expect("Glyph size tested for non-zero during init"),
74 )
75 }
76}
77
78pub struct Fonts(HashMap<&'static str, &'static Font>);
80
81impl Fonts {
82 pub fn all() -> Self {
84 let mut fonts = HashMap::default();
85 fonts.insert(FONT_5X8.name, &FONT_5X8);
86 fonts.insert(FONT_16X16.name, &FONT_16X16);
87 fonts.insert(FONT_VGA8X16.name, &FONT_VGA8X16);
88 Self(fonts)
89 }
90
91 pub fn get(&self, name: &str) -> io::Result<&'static Font> {
93 match self.0.get(name) {
94 Some(font) => Ok(*font),
95 None => {
96 let mut valid = self.0.keys().copied().collect::<Vec<&'static str>>();
97 valid.sort();
98 Err(io::Error::new(
99 io::ErrorKind::InvalidInput,
100 format!("Unknown font: {}; valid names are: {}", name, valid.join(", ")),
101 ))
102 }
103 }
104 }
105}
106
107#[cfg(test)]
108mod tests {
109 use super::*;
110
111 #[test]
112 fn test_font_glyph_printable() {
113 let font = &FONT_5X8;
114
115 let offset = (usize::from(b'a') - usize::from(b' ')) * 8;
116 let expected = &font.data[offset..offset + 8];
117
118 let data = font.glyph('a');
119 assert_eq!(expected, data);
120 }
121
122 #[test]
123 fn test_font_glyph_non_printable() {
124 let font = &FONT_5X8;
125
126 let offset = (usize::from(b'?') - usize::from(b' ')) * 8;
127 let expected = &font.data[offset..offset + 8];
128
129 let data = font.glyph(char::from(30));
130 assert_eq!(expected, data);
131 }
132}