Fix #683: Preferences > Type > Additional Fonts Folder

VectorCraft found fonts only in the system's font folders (and, on Windows,
those font services activate). A new preference names one more folder, read
with its subfolders after the platform's: its fonts are listed in the font
menus and used as if installed, without installing them.

- vectorcraft_text::set_user_font_dirs / user_font_dirs: folders
  system_font_dirs adds to every scan (none on wasm).
- prefs fontsFolder (Type > Options > Additional Fonts Folder), trimmed; when
  it changes after the first scan, the fonts are scanned again at once, so the
  folder's fonts appear (or go) and type in them lays out again.
- The label is translated where Additional Plug-ins Folder is.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
bflatastic
2026-10-09 12:05:16 +07:00
co-authored by Claude Opus 5.5
parent b61089e5c6
commit e92bbdbdac
14 changed files with 69 additions and 4 deletions
+16 -1
View File
@@ -247,7 +247,7 @@ fn font_list(_: &mut Session, p: &Value) -> Result<Value> {
}
}
fn rescan(s: &mut Session, _: &Value) -> Result<Value> {
pub(crate) fn rescan(s: &mut Session, _: &Value) -> Result<Value> {
let db = vectorcraft_text::FontDb::global();
#[cfg(not(target_arch = "wasm32"))]
let faces = db.load_system_fonts();
@@ -283,6 +283,21 @@ fn rescan(s: &mut Session, _: &Value) -> Result<Value> {
mod tests {
use super::*;
/// Type › Options › Additional Fonts Folder (#683) adds its folder to the system font scan,
/// trimmed; clearing it takes the folder out again.
#[test]
fn the_additional_fonts_folder_joins_the_font_scan() {
let mut s = Session::new();
let dir = std::env::temp_dir().join("vectorcraft-fonts-folder-pref");
s.execute("prefs.set", &json!({"key": "fontsFolder", "value": format!(" {} ", dir.display())})).unwrap();
assert_eq!(vectorcraft_text::user_font_dirs(), std::slice::from_ref(&dir));
if !cfg!(target_arch = "wasm32") {
assert!(vectorcraft_text::system_font_dirs().contains(&dir));
}
s.execute("prefs.set", &json!({"key": "fontsFolder", "value": ""})).unwrap();
assert!(vectorcraft_text::user_font_dirs().is_empty() && !vectorcraft_text::system_font_dirs().contains(&dir));
}
#[test]
fn list_flag_missing_replace_and_select() {
let mut s = Session::new();
+12
View File
@@ -187,6 +187,7 @@ pub const PREF_SPECS: &[PrefSpec] = &[
p!("missingGlyphProtection", "Type", "Options", "Enable Missing Glyph Protection", bool),
p!("highlightAlternateGlyphs", "Type", "Options", "Highlight Alternate Glyphs", bool),
p!("placeholderText", "Type", "Options", "Fill New Type Objects With Placeholder Text", bool),
p!("fontsFolder", "Type", "Options", "Additional Fonts Folder", text),
// Units
p!("unitsGeneral", "Units", "", "General", choice(UNITS)),
p!("unitsStroke", "Units", "", "Stroke", choice(UNITS)),
@@ -460,7 +461,18 @@ impl Session {
let grid_changed = p.gridline_every != self.prefs.gridline_every || p.grid_subdivisions != self.prefs.grid_subdivisions;
let history_changed = p.history_states != self.prefs.history_states;
let tile_edge_changed = p.pattern_tile_edge_color != self.prefs.pattern_tile_edge_color;
let fonts_folder_changed = p.fonts_folder != self.prefs.fonts_folder;
self.prefs = p;
if fonts_folder_changed {
let folder = self.prefs.fonts_folder.trim();
vectorcraft_text::set_user_font_dirs(if folder.is_empty() { vec![] } else { vec![folder.into()] });
// Once the fonts were scanned, scan again now: the folder's fonts appear (or go) in the
// font menus, and type in them lays out again. The first scan reads it anyway.
if vectorcraft_text::FontDb::global().installed_fonts_changed() {
// Its result only counts the faces cataloged.
let _ = super::fonts::rescan(self, &serde_json::Value::Null);
}
}
vectorcraft_render::set_default_threads(u16::try_from(self.prefs.render_threads).ok());
for st in &mut self.docs {
if history_changed {