Files
ming-wm/ming-wm-lib/src/fonts.rs
stjet 40f6795163 v1.2.2: text measuring improvements, minor code clean
fixed some clippy warnings, ignored many that I do not care about. also, added demo video and updated koxinga image
2025-09-28 04:39:41 +00:00

127 lines
3.4 KiB
Rust

use std::fs::File;
use std::io::Read;
use std::collections::HashMap;
use crate::dirs;
#[derive(Clone)]
pub struct FontCharInfo {
pub c: char,
pub data: Vec<Vec<u8>>,
pub top_offset: u8,
pub height: usize,
pub width: usize,
}
fn get_font_char(dir: &str, c: char) -> Option<FontCharInfo> {
let c = if c == '/' { '𐘋' } else if c == '\\' { '𐚆' } else if c == '.' { '𐘅' } else { c };
if let Ok(mut file) = File::open(dir.to_string() + "/" + &c.to_string() + ".alpha") {
let mut ch: Vec<Vec<u8>> = Vec::new();
let mut contents = String::new();
file.read_to_string(&mut contents).unwrap();
let lines: Vec<&str> = contents.split("\n").collect();
for ln in lines.iter().skip(1) {
//.unwrap_or(0) is important because zeroes are just empty
ch.push(ln.replace(":", ",,,,").replace(";", ",,,").replace(".", ",,").split(",").map(|n| n.parse().unwrap_or(0)).collect());
}
return Some(FontCharInfo {
c,
top_offset: lines[0].parse().unwrap(),
height: lines.len() - 1,
width: ch[0].len(),
data: ch,
});
}
None
}
pub fn get_font_char_from_fonts(fonts: &[String], c: char) -> FontCharInfo {
for font in fonts {
let p = dirs::exe_dir(Some(&("ming_bmps/".to_string() + &font))).to_string_lossy().to_string();
if let Some(font_char) = get_font_char(&p, c) {
return font_char;
}
}
let p = dirs::exe_dir(Some(&("ming_bmps/".to_string() + &fonts[0]))).to_string_lossy().to_string();
//so a ? char should be in every font. otherwise will just return blank
get_font_char(&p, '?').unwrap_or(FontCharInfo {
c: '?',
data: vec![vec![0]],
top_offset: 0,
height: 1,
width: 1,
})
}
pub struct MeasureInfo {
pub height: usize,
pub width: usize,
}
pub fn measure_text(fonts: &[String], text: &str, horiz_spacing: Option<usize>) -> MeasureInfo {
let mut height = 0;
let mut width = 0;
for c in text.chars() {
let i = get_font_char_from_fonts(fonts, c);
let c_height = i.top_offset as usize + i.height;
if c_height > height {
height = c_height;
}
width += i.width + horiz_spacing.unwrap_or(1);
}
width -= horiz_spacing.unwrap_or(1);
MeasureInfo {
height,
width,
}
}
pub fn measure_text_with_cache(fc_getter: &mut CachedFontCharGetter, fonts: &[String], text: &str, horiz_spacing: Option<usize>) -> MeasureInfo {
let mut height = 0;
let mut width = 0;
for c in text.chars() {
let i = fc_getter.get(fonts, c);
let c_height = i.top_offset as usize + i.height;
if c_height > height {
height = c_height;
}
width += i.width + horiz_spacing.unwrap_or(1);
}
width -= horiz_spacing.unwrap_or(1);
MeasureInfo {
height,
width,
}
}
#[derive(Default)]
pub struct CachedFontCharGetter {
cache: HashMap<char, FontCharInfo>,
cache_size: usize, //# of items cached
pub max_cache_size: usize,
}
impl CachedFontCharGetter {
pub fn new(max_cache_size: usize) -> Self {
Self {
max_cache_size,
..Default::default()
}
}
pub fn get(&mut self, fonts: &[String], c: char) -> FontCharInfo {
if let Some(cached) = self.cache.get(&c) {
cached.clone()
} else {
let got = get_font_char_from_fonts(fonts, c);
if self.cache_size == self.max_cache_size {
self.cache_size = 0;
self.cache = HashMap::new();
}
self.cache.insert(c, got.clone());
self.cache_size += 1;
got
}
}
}