Skip to content

Commit bdf017c

Browse files
authored
Merge pull request #16 from CrazyHPi/font-loader
add font loader
2 parents d860332 + 513a99d commit bdf017c

6 files changed

Lines changed: 224 additions & 2 deletions

File tree

Cargo.lock

Lines changed: 21 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,13 @@ tokio = { version = "1", features = ["macros", "net", "rt-multi-thread"] }
2727
webbrowser = { version = "1.0.4", optional = true }
2828
zip = { version = "7.2.0", features = ["deflate-flate2"], default-features = false }
2929

30+
[target.'cfg(target_os = "linux")'.dependencies]
31+
fontconfig = { version = "0.10.0", optional = true }
32+
3033
[features]
3134
default = ["gui"]
3235

33-
gui = ["dep:eframe", "dep:egui", "dep:rfd", "dep:webbrowser", "dep:rand", "dep:current_locale"]
36+
gui = ["dep:eframe", "dep:egui", "dep:rfd", "dep:webbrowser", "dep:rand", "dep:current_locale", "dep:fontconfig"]
3437

3538
[build-dependencies]
3639
embed-resource = "3.0.5"

res/font/fonts.json

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
{
2+
"windows": {
3+
"zh-CN": [
4+
"msyh.ttc",
5+
"msyhbd.ttc",
6+
"simsun.ttc",
7+
"simhei.ttf",
8+
"simkai.ttf",
9+
"simfang.ttf",
10+
"msjh.ttc",
11+
"msjhbd.ttc"
12+
],
13+
"ja": [
14+
"meiryo.ttc",
15+
"meiryob.ttc",
16+
"msgothic.ttc",
17+
"msmincho.ttc",
18+
"YuGothM.ttc",
19+
"YuGothB.ttc",
20+
"YuMincho.ttc"
21+
]
22+
},
23+
"linux": {
24+
"zh-CN": [
25+
"Noto Sans CJK SC",
26+
"WenQuanYi Micro Hei",
27+
"WenQuanYi Zen Hei",
28+
"AR PL UMing CN",
29+
"AR PL UKai CN"
30+
],
31+
"ja": [
32+
"Noto Sans CJK JP",
33+
"Noto Sans CJK SC",
34+
"Noto Sans CJK TC",
35+
"Noto Sans JP",
36+
"IPAGothic",
37+
"IPA Gothic",
38+
"VL Gothic"
39+
]
40+
},
41+
"macos": {
42+
"zh-CN": [
43+
"PingFang.ttc",
44+
"STHeiti Light.ttc",
45+
"STHeiti Medium.ttc",
46+
"Hiragino Sans GB.ttc",
47+
"Arial Unicode.ttf"
48+
],
49+
"ja": [
50+
"ヒラギノ角ゴシック W3.ttc",
51+
"ヒラギノ明朝 ProN.ttc",
52+
"ヒラギノ丸ゴ ProN W4.ttc",
53+
"Hiragino Sans GB.ttc"
54+
]
55+
}
56+
}

src/ui/font_loader.rs

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
use egui::FontData;
2+
use egui::FontFamily::{Monospace, Proportional};
3+
use egui::epaint::text::FontPriority::Lowest;
4+
use egui::epaint::text::{FontInsert, InsertFontFamily};
5+
use serde::Deserialize;
6+
use std::collections::HashMap;
7+
use log::warn;
8+
9+
const FONT_LIST: &str = include_str!("../../res/font/fonts.json");
10+
11+
#[cfg(target_os = "windows")]
12+
const WINDOWS_FONT_PATH: &str = r"C:\Windows\Fonts\";
13+
#[cfg(target_os = "macos")]
14+
const MACOS_FONT_PATH: &str = "/System/Library/Fonts/";
15+
#[cfg(target_os = "macos")]
16+
const MACOS_FONT_PATH_SHARED: &str = "/Library/Fonts/";
17+
18+
#[derive(Deserialize)]
19+
struct SystemFontList {
20+
#[cfg(target_os = "windows")]
21+
windows: PlatformFonts,
22+
#[cfg(target_os = "linux")]
23+
linux: PlatformFonts,
24+
#[cfg(target_os = "macos")]
25+
macos: PlatformFonts,
26+
}
27+
28+
type PlatformFonts = HashMap<String, Vec<String>>;
29+
30+
pub fn load_system_font_to_egui(ctx: &egui::Context) {
31+
let system_font = find_system_font();
32+
33+
if system_font.is_empty() {
34+
warn!("No system font found, some languages may not display properly.");
35+
return;
36+
}
37+
38+
for font in system_font {
39+
let font_insert = FontInsert::new(
40+
&font.0,
41+
font.1,
42+
vec![
43+
InsertFontFamily {
44+
family: Proportional,
45+
priority: Lowest, // low priority to not override existing fonts
46+
},
47+
InsertFontFamily {
48+
family: Monospace,
49+
priority: Lowest,
50+
},
51+
],
52+
);
53+
54+
ctx.add_font(font_insert);
55+
}
56+
}
57+
58+
fn find_system_font() -> HashMap<String, FontData> {
59+
let sys_font_list: SystemFontList =
60+
serde_json::from_str(FONT_LIST).expect("failed to parse font list");
61+
62+
let mut result: HashMap<String, FontData> = HashMap::new();
63+
64+
#[cfg(target_os = "windows")]
65+
{
66+
load_fonts_from_paths(&sys_font_list.windows, &[WINDOWS_FONT_PATH], &mut result);
67+
}
68+
69+
#[cfg(target_os = "macos")]
70+
{
71+
load_fonts_from_paths(
72+
&sys_font_list.macos,
73+
&[MACOS_FONT_PATH, MACOS_FONT_PATH_SHARED],
74+
&mut result,
75+
);
76+
}
77+
78+
#[cfg(target_os = "linux")]
79+
{
80+
// use fontconfig for linux fo find fonts
81+
load_fonts_from_fontconfig(&sys_font_list.linux, &mut result);
82+
}
83+
84+
result
85+
}
86+
87+
#[cfg(any(target_os = "windows", target_os = "macos"))]
88+
fn load_fonts_from_paths(
89+
platform_fonts: &PlatformFonts,
90+
search_paths: &[&str],
91+
result: &mut HashMap<String, FontData>,
92+
) {
93+
for (language, font_files) in platform_fonts {
94+
let mut loaded = false;
95+
for font_file in font_files {
96+
for search_path in search_paths {
97+
let font_path = format!("{}{}", search_path, font_file);
98+
if let Ok(font_data) = std::fs::read(&font_path) {
99+
result.insert(language.to_string(), FontData::from_owned(font_data));
100+
loaded = true;
101+
break;
102+
}
103+
}
104+
if loaded {
105+
break;
106+
}
107+
}
108+
}
109+
}
110+
111+
#[cfg(all(target_os = "linux", feature = "gui"))]
112+
fn load_fonts_from_fontconfig(
113+
platform_fonts: &PlatformFonts,
114+
result: &mut HashMap<String, FontData>,
115+
) {
116+
use fontconfig::Fontconfig;
117+
118+
if let Some(fc) = Fontconfig::new() {
119+
platform_fonts.iter().for_each(|(language, font_names)| {
120+
for font_name in font_names {
121+
if let Some(font) = fc.find(font_name, None) {
122+
if let Ok(data) = std::fs::read(font.path) {
123+
result.insert(language.to_string(), FontData::from_owned(data));
124+
break;
125+
}
126+
}
127+
}
128+
})
129+
} else {
130+
warn!("Failed to init Fontconfig")
131+
}
132+
}

src/ui/gui.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ use egui::{
3131
};
3232
use std::hash::Hash;
3333

34+
use crate::ui::font_loader::load_system_font_to_egui;
35+
3436
#[derive(PartialEq, Clone, Copy, Debug)]
3537
enum Mode {
3638
Client,
@@ -80,7 +82,12 @@ async fn create_window() -> Result<(), InstallerError> {
8082
eframe::run_native(
8183
&("Ornithe Installer ".to_owned() + crate::VERSION),
8284
options,
83-
Box::new(|_cc| Ok(Box::new(app))),
85+
Box::new(|_cc| {
86+
// load needed system fonts
87+
load_system_font_to_egui(&_cc.egui_ctx);
88+
89+
Ok(Box::new(app))
90+
}),
8491
)?;
8592
Ok(())
8693
}

src/ui/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ pub mod cli;
55
#[cfg(feature = "gui")]
66
pub mod gui;
77

8+
#[cfg(feature = "gui")]
9+
mod font_loader;
10+
811
fn home_dir() -> Option<PathBuf> {
912
#[allow(deprecated)]
1013
std::env::home_dir()

0 commit comments

Comments
 (0)