ming_wm_lib/
fonts.rs

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      //.unwrap_or(0) is important because zeroes are just empty
25      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  //so a ? char should be in every font. otherwise will just return blank
47  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, //# of items cached
101  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}