1use egui::{Context, FontData, FontDefinitions, FontFamily};
18
19#[derive(Debug)]
21pub enum FontError {
22 NotFound(String),
24 ReadError(std::io::Error),
26 UnsupportedPlatform,
28}
29
30impl std::fmt::Display for FontError {
31 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
32 match self {
33 FontError::NotFound(path) => write!(f, "Font file not found: {}", path),
34 FontError::ReadError(err) => write!(f, "Failed to read font file: {}", err),
35 FontError::UnsupportedPlatform => write!(f, "Platform not supported"),
36 }
37 }
38}
39
40impl std::error::Error for FontError {}
41
42pub fn setup_chinese_fonts(ctx: &Context) -> Result<(), FontError> {
54 let mut fonts = FontDefinitions::default();
55
56 let chinese_font_data = load_chinese_font()?;
58
59 fonts.font_data.insert(
61 "chinese".to_owned(),
62 chinese_font_data,
63 );
64
65 fonts.families.entry(FontFamily::Proportional).or_default()
67 .insert(0, "chinese".to_owned());
68 fonts.families.entry(FontFamily::Monospace).or_default()
69 .insert(0, "chinese".to_owned());
70
71 ctx.set_fonts(fonts);
73
74 Ok(())
75}
76
77fn load_chinese_font() -> Result<FontData, FontError> {
79 #[cfg(target_os = "windows")]
80 {
81 load_windows_chinese_font()
82 }
83
84 #[cfg(target_os = "macos")]
85 {
86 load_macos_chinese_font()
87 }
88
89 #[cfg(target_os = "linux")]
90 {
91 load_linux_chinese_font()
92 }
93
94 #[cfg(not(any(target_os = "windows", target_os = "macos", target_os = "linux")))]
95 {
96 Err(FontError::UnsupportedPlatform)
97 }
98}
99
100#[cfg(target_os = "windows")]
101fn load_windows_chinese_font() -> Result<FontData, FontError> {
102 let font_paths = [
104 r"C:\Windows\Fonts\msyh.ttc", r"C:\Windows\Fonts\msyhbd.ttc", r"C:\Windows\Fonts\simsun.ttc", r"C:\Windows\Fonts\simhei.ttf", r"C:\Windows\Fonts\simkai.ttf", r"C:\Windows\Fonts\simfang.ttf", r"C:\Windows\Fonts\msjh.ttc", r"C:\Windows\Fonts\msjhbd.ttc", r"C:\Windows\Fonts\kaiu.ttf", r"C:\Windows\Fonts\mingliu.ttc", ];
115
116 for font_path in &font_paths {
117 if let Ok(font_data) = std::fs::read(font_path) {
118 return Ok(FontData::from_owned(font_data));
119 }
120 }
121
122 Err(FontError::NotFound("No Chinese font found on Windows".to_string()))
123}
124
125#[cfg(target_os = "macos")]
126fn load_macos_chinese_font() -> Result<FontData, FontError> {
127 let font_paths = [
128 "/System/Library/Fonts/PingFang.ttc", "/System/Library/Fonts/STHeiti Light.ttc", "/System/Library/Fonts/STHeiti Medium.ttc",
131 "/System/Library/Fonts/Hiragino Sans GB.ttc", "/Library/Fonts/Arial Unicode.ttf", "/System/Library/Fonts/Apple LiGothic Medium.ttf", ];
135
136 for font_path in &font_paths {
137 if let Ok(font_data) = std::fs::read(font_path) {
138 return Ok(FontData::from_owned(font_data));
139 }
140 }
141
142 Err(FontError::NotFound("No Chinese font found on macOS".to_string()))
143}
144
145#[cfg(target_os = "linux")]
146fn load_linux_chinese_font() -> Result<FontData, FontError> {
147 let font_paths = [
149 "/usr/share/fonts/truetype/droid/DroidSansFallbackFull.ttf",
150 "/usr/share/fonts/truetype/arphic/uming.ttc",
151 "/usr/share/fonts/truetype/arphic/ukai.ttc",
152 "/usr/share/fonts/truetype/wqy/wqy-microhei.ttc",
153 "/usr/share/fonts/truetype/wqy/wqy-zenhei.ttc",
154 "/usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc",
155 "/usr/share/fonts/truetype/liberation/LiberationSans-Regular.ttf",
156 "/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf",
158 "/usr/share/fonts/google-droid/DroidSansFallbackFull.ttf",
160 "/usr/share/fonts/noto-cjk/NotoSansCJK-Regular.ttc",
162 ];
163
164 for font_path in &font_paths {
165 if let Ok(font_data) = std::fs::read(font_path) {
166 return Ok(FontData::from_owned(font_data));
167 }
168 }
169
170 Err(FontError::NotFound("No Chinese font found on Linux".to_string()))
171}
172
173pub fn setup_custom_chinese_font(
183 ctx: &Context,
184 font_data: Vec<u8>,
185 font_name: Option<&str>
186) {
187 let mut fonts = FontDefinitions::default();
188 let name = font_name.unwrap_or("chinese");
189
190 fonts.font_data.insert(
191 name.to_owned(),
192 FontData::from_owned(font_data),
193 );
194
195 fonts.families.entry(FontFamily::Proportional).or_default()
196 .insert(0, name.to_owned());
197 fonts.families.entry(FontFamily::Monospace).or_default()
198 .insert(0, name.to_owned());
199
200 ctx.set_fonts(fonts);
201}
202
203pub fn get_chinese_font_paths() -> Vec<String> {
208 #[cfg(target_os = "windows")]
209 {
210 vec![
211 r"C:\Windows\Fonts\msyh.ttc".to_string(),
212 r"C:\Windows\Fonts\msyhbd.ttc".to_string(),
213 r"C:\Windows\Fonts\simsun.ttc".to_string(),
214 r"C:\Windows\Fonts\simhei.ttf".to_string(),
215 r"C:\Windows\Fonts\simkai.ttf".to_string(),
216 r"C:\Windows\Fonts\simfang.ttf".to_string(),
217 r"C:\Windows\Fonts\msjh.ttc".to_string(),
218 r"C:\Windows\Fonts\msjhbd.ttc".to_string(),
219 ]
220 }
221
222 #[cfg(target_os = "macos")]
223 {
224 vec![
225 "/System/Library/Fonts/PingFang.ttc".to_string(),
226 "/System/Library/Fonts/STHeiti Light.ttc".to_string(),
227 "/System/Library/Fonts/STHeiti Medium.ttc".to_string(),
228 "/System/Library/Fonts/Hiragino Sans GB.ttc".to_string(),
229 "/Library/Fonts/Arial Unicode.ttf".to_string(),
230 ]
231 }
232
233 #[cfg(target_os = "linux")]
234 {
235 vec![
236 "/usr/share/fonts/truetype/droid/DroidSansFallbackFull.ttf".to_string(),
237 "/usr/share/fonts/truetype/arphic/uming.ttc".to_string(),
238 "/usr/share/fonts/truetype/wqy/wqy-microhei.ttc".to_string(),
239 "/usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc".to_string(),
240 ]
241 }
242
243 #[cfg(not(any(target_os = "windows", target_os = "macos", target_os = "linux")))]
244 {
245 vec![]
246 }
247}