1use std::fs::File;
2use std::io::Read;
3use std::collections::HashMap;
4
5use crate::dirs;
6
7#[derive(Clone)]
8pub struct FontCharInfo {
9 pub c: char,
10 pub data: Vec<Vec<u8>>,
11 pub top_offset: u8,
12 pub height: usize,
13 pub width: usize,
14}
15
16fn get_font_char(dir: &str, c: char) -> Option<FontCharInfo> {
17 let c = if c == '/' { '𐘋' } else if c == '\\' { '𐚆' } else if c == '.' { '𐘅' } else { c };
18 if let Ok(mut file) = File::open(dir.to_string() + "/" + &c.to_string() + ".alpha") {
19 let mut ch: Vec<Vec<u8>> = Vec::new();
20 let mut contents = String::new();
21 file.read_to_string(&mut contents).unwrap();
22 let lines: Vec<&str> = contents.split("\n").collect();
23 for ln in lines.iter().skip(1) {
24 ch.push(ln.replace(":", ",,,,").replace(";", ",,,").replace(".", ",,").split(",").map(|n| n.parse().unwrap_or(0)).collect());
26 }
27 return Some(FontCharInfo {
28 c,
29 top_offset: lines[0].parse().unwrap(),
30 height: lines.len() - 1,
31 width: ch[0].len(),
32 data: ch,
33 });
34 }
35 None
36}
37
38pub fn get_font_char_from_fonts(fonts: &[String], c: char) -> FontCharInfo {
39 for font in fonts {
40 let p = dirs::exe_dir(Some(&("ming_bmps/".to_string() + &font))).to_string_lossy().to_string();
41 if let Some(font_char) = get_font_char(&p, c) {
42 return font_char;
43 }
44 }
45 let p = dirs::exe_dir(Some(&("ming_bmps/".to_string() + &fonts[0]))).to_string_lossy().to_string();
46 get_font_char(&p, '?').unwrap_or(FontCharInfo {
48 c: '?',
49 data: vec![vec![0]],
50 top_offset: 0,
51 height: 1,
52 width: 1,
53 })
54}
55
56pub struct MeasureInfo {
57 pub height: usize,
58 pub width: usize,
59}
60
61pub fn measure_text(fonts: &[String], text: &str, horiz_spacing: Option<usize>) -> MeasureInfo {
62 let mut height = 0;
63 let mut width = 0;
64 for c in text.chars() {
65 let i = get_font_char_from_fonts(fonts, c);
66 let c_height = i.top_offset as usize + i.height;
67 if c_height > height {
68 height = c_height;
69 }
70 width += i.width + horiz_spacing.unwrap_or(1);
71 }
72 width -= horiz_spacing.unwrap_or(1);
73 MeasureInfo {
74 height,
75 width,
76 }
77}
78
79pub fn measure_text_with_cache(fc_getter: &mut CachedFontCharGetter, fonts: &[String], text: &str, horiz_spacing: Option<usize>) -> MeasureInfo {
80 let mut height = 0;
81 let mut width = 0;
82 for c in text.chars() {
83 let i = fc_getter.get(fonts, c);
84 let c_height = i.top_offset as usize + i.height;
85 if c_height > height {
86 height = c_height;
87 }
88 width += i.width + horiz_spacing.unwrap_or(1);
89 }
90 width -= horiz_spacing.unwrap_or(1);
91 MeasureInfo {
92 height,
93 width,
94 }
95}
96
97#[derive(Default)]
98pub struct CachedFontCharGetter {
99 cache: HashMap<char, FontCharInfo>,
100 cache_size: usize, pub max_cache_size: usize,
102}
103
104impl CachedFontCharGetter {
105 pub fn new(max_cache_size: usize) -> Self {
106 Self {
107 max_cache_size,
108 ..Default::default()
109 }
110 }
111
112 pub fn get(&mut self, fonts: &[String], c: char) -> FontCharInfo {
113 if let Some(cached) = self.cache.get(&c) {
114 cached.clone()
115 } else {
116 let got = get_font_char_from_fonts(fonts, c);
117 if self.cache_size == self.max_cache_size {
118 self.cache_size = 0;
119 self.cache = HashMap::new();
120 }
121 self.cache.insert(c, got.clone());
122 self.cache_size += 1;
123 got
124 }
125 }
126}