mirror of
https://github.com/storytold/effectcraft.git
synced 2026-10-31 05:27:08 -06:00
Merge #2453: Font menu: a name the interface fonts cannot draw shows in English
This commit is contained in:
@@ -702,10 +702,11 @@ pub(super) fn font_picker(app: &mut EffectcraftApp, ui: &mut egui::Ui, id: egui:
|
||||
let resp = ui.add_sized([row_width, 24.0], egui::Button::selectable(index == state.selected, ""));
|
||||
resp.widget_info(|| egui::WidgetInfo::selected(egui::Role::Button, ui.is_enabled(), index == state.selected, &r.display));
|
||||
let label_rect = Rect::from_min_size(resp.rect.min + vec2(5.0, 0.0), vec2(label_width - 5.0, resp.rect.height()));
|
||||
let name = drawn_font_name(ui.ctx(), r);
|
||||
ui.painter().with_clip_rect(label_rect.intersect(ui.clip_rect())).text(
|
||||
label_rect.left_center(),
|
||||
Align2::LEFT_CENTER,
|
||||
&r.display,
|
||||
name,
|
||||
Tokens::ui(12.0),
|
||||
t.text,
|
||||
);
|
||||
@@ -739,7 +740,7 @@ pub(super) fn font_picker(app: &mut EffectcraftApp, ui: &mut egui::Ui, id: egui:
|
||||
if resp.clicked() {
|
||||
chosen = Some(r.family.clone());
|
||||
}
|
||||
resp.on_hover_text(&r.display);
|
||||
resp.on_hover_text(name);
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -886,6 +887,13 @@ fn align_glyph(p: &egui::Painter, r: Rect, op: &str, distribute: bool, t: &Token
|
||||
}
|
||||
}
|
||||
|
||||
/// The name a font menu row draws: the font's own-language name when the interface fonts have a
|
||||
/// glyph for each of its characters, else its English family name. A Simplified Chinese name
|
||||
/// such as 微软雅黑 can have characters that the Han face of an English interface lacks.
|
||||
fn drawn_font_name<'a>(ctx: &egui::Context, row: &'a effectcraft_engine::FontRow) -> &'a str {
|
||||
if ctx.fonts_mut(|f| f.has_glyphs(&Tokens::ui(12.0), &row.display)) { &row.display } else { &row.family }
|
||||
}
|
||||
|
||||
/// Where a font's "Sample" outlines (`lines`, baseline at y = 0) go in `room`: `(scale, origin)`,
|
||||
/// a point `p` landing at `origin + p * scale`. At their natural size on `baseline` when they fit;
|
||||
/// fonts with large or odd metrics are scaled down (never up) and moved inside, so no preview
|
||||
@@ -944,4 +952,17 @@ mod tests {
|
||||
assert!(fit_preview(&[], room, baseline).is_none());
|
||||
assert!(fit_preview(&[vec![[f32::NAN, 1.0]]], room, baseline).is_none());
|
||||
}
|
||||
|
||||
/// A font menu row draws the font's own-language name when the interface fonts have its
|
||||
/// glyphs, and the English family name when they do not.
|
||||
#[test]
|
||||
fn font_menu_rows_draw_a_name_the_interface_fonts_have() {
|
||||
let ctx = egui::Context::default();
|
||||
crate::theme::install(&ctx, &Tokens::for_kind(Default::default()), "en");
|
||||
ctx.run_ui(Default::default(), |_| {}).textures_delta.clear();
|
||||
let row = |display: &str| effectcraft_engine::FontRow { family: "Menu Name Test".into(), display: display.into(), recent: false, variable: false };
|
||||
// U+F1234 is in a private use plane that no interface font maps.
|
||||
assert_eq!(drawn_font_name(&ctx, &row("Menu \u{F1234}")), "Menu Name Test");
|
||||
assert_eq!(drawn_font_name(&ctx, &row("Nom du menu")), "Nom du menu");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,6 +106,52 @@ fn font_search_preserves_edited_text_and_applies_only_to_selected_characters() {
|
||||
assert_eq!(doc.style_at(8).font, "Inter");
|
||||
}
|
||||
|
||||
/// A font file of just `name`: the family and Regular in English, and the family again in
|
||||
/// Simplified Chinese (language 0x804).
|
||||
fn font_with_native_name(family: &str, native: &str) -> Vec<u8> {
|
||||
let u16s = |v: &[u16]| -> Vec<u8> { v.iter().flat_map(|x| x.to_be_bytes()).collect() };
|
||||
let records = [(0x409, 1, family), (0x409, 2, "Regular"), (0x804, 1, native)];
|
||||
let strings: Vec<Vec<u8>> = records.iter().map(|(_, _, s)| s.encode_utf16().flat_map(|u| u.to_be_bytes()).collect()).collect();
|
||||
let mut name = u16s(&[0, records.len() as u16, 6 + 12 * records.len() as u16]);
|
||||
let mut off = 0;
|
||||
for ((lang, id, _), st) in records.iter().zip(&strings) {
|
||||
name.extend(u16s(&[3, 1, *lang, *id, st.len() as u16, off]));
|
||||
off += st.len() as u16;
|
||||
}
|
||||
strings.iter().for_each(|st| name.extend(st));
|
||||
let mut out = u16s(&[1, 0, 1, 0, 0, 0]);
|
||||
out.extend(b"name");
|
||||
out.extend([0u8; 4]);
|
||||
out.extend(28u32.to_be_bytes());
|
||||
out.extend((name.len() as u32).to_be_bytes());
|
||||
out.extend(name);
|
||||
out
|
||||
}
|
||||
|
||||
/// A family whose own-language name has a character no interface font has is listed under its
|
||||
/// English name: the harness fails on a missing glyph, and the app would draw boxes. Picking the
|
||||
/// row still applies the family.
|
||||
#[test]
|
||||
fn font_menu_lists_a_name_the_interface_fonts_lack_in_english() {
|
||||
const FAMILY: &str = "Native Name Menu Test";
|
||||
// U+F1234 is in a private use plane that no interface font maps.
|
||||
const NATIVE: &str = "中文\u{F1234}字体";
|
||||
assert_eq!(effectcraft_engine::text::fonts::add_font_data(font_with_native_name(FAMILY, NATIVE)).len(), 1);
|
||||
assert_eq!(effectcraft_engine::text::fonts::native_families().get(FAMILY).map(String::as_str), Some(NATIVE));
|
||||
let mut s = Session::default();
|
||||
s.execute("comp.new", json!({"width": 320, "height": 180})).unwrap();
|
||||
let lid = s.execute("layer.newText", json!({"text": "Native", "font": "Inter"})).unwrap()["layer"].as_u64().unwrap();
|
||||
let mut h = Harness::builder().with_size(egui::vec2(1600.0, 1000.0)).build_eframe(move |_| EffectcraftApp::new(s));
|
||||
h.state_mut().show_panel(PanelKind::Character);
|
||||
h.run_steps(3);
|
||||
click(&mut h, "character.font");
|
||||
type_text(&mut h, "native name menu");
|
||||
let shown: Vec<String> = h.state().auto.query("character.font.option.").iter().map(|e| e.id.clone()).collect();
|
||||
assert_eq!(shown, vec![format!("character.font.option.{FAMILY}")]);
|
||||
click(&mut h, &format!("character.font.option.{FAMILY}"));
|
||||
assert_eq!(layer_doc(&h.state().session, LayerId(lid)).unwrap().font, FAMILY);
|
||||
}
|
||||
|
||||
/// A font file of just `name` (the family, Regular) and an `fvar` table with one axis pinned at
|
||||
/// 400: a variable font as far as the font menu's filter is concerned.
|
||||
fn pinned_variable_font(family: &str) -> Vec<u8> {
|
||||
|
||||
Reference in New Issue
Block a user