epaint panics in set_fonts on a face skrifa can't open. Every system font
file is now checked with the same skrifa call (plus a readable cmap)
before it reaches FontDefinitions; a bad candidate is skipped with a
warning and the next one is tried, and a final pass drops any remaining
unparseable face from the definitions and every family.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
winit reports no system theme on Linux — `ActiveEventLoop::system_theme()` is
`None` there on every desktop — so `System` in the appearance setting never saw
the desktop's choice and fell back to light. A new `desktop_theme` module asks
the XDG Desktop Portal's Settings interface for
`org.gnome.desktop.interface color-scheme` on a thread of its own, so no
D-Bus call is ever made from the frame loop, and the app follows the answer,
including a change made while it runs.
egui resolves `ThemePreference::System` from what winit reports and offers no
way to set that itself, so where a desktop answered, the app hands egui the
concrete theme instead. What is drawn is unchanged on macOS and Windows, where
winit answers and the same resolution happens a step earlier; the saved
preference is still `system`, so a file keeps meaning the same thing.
The colour scheme is asked for under its GNOME schema name first, which GNOME's
portal and XFCE's both answer, then under the older freedesktop one, which KDE
answers. A desktop that answers neither leaves the user's own choice alone.
Add an interface-language preference. It defaults to the system's
language on first run (sys-locale, native only) and is switched by hand
from the View tab, next to Dark Mode, or with app.language.english /
app.language.japanese over the control channel. It is saved in ui.json.
Follows the filmcraft house convention: a Language enum and a
table of English-to-Japanese strings with English fallback, so coverage
can grow incrementally. Japanese chrome renders without any bundled
font: the CJK fallback faces already appended to every family cover
kana and kanji.
The ribbon chrome all flows through the small_button/big_button/
toggle_button/split_button/icon_button helpers and menu_items, so
translating there localises the whole ribbon in one place; the language
of the frame is read from egui context data (i18n::current). Command
ids, file names and document text are never translated.
The font dropdown showed a hardcoded 17-name list and cells always
rendered in the built-in Calibri/role font, so a font installed on the
machine could not be listed or chosen. Both trace to one constraint:
egui panics when asked for a FontFamily::Name that was never bound to
font data, so only the 8 built-in roles were ever bound.
Scan the platform font folders for installed families (a bounded read of
each file's name table via skrifa, already compiled transitively through
epaint), bind the faces a workbook actually uses into egui as
fnt:{family}:{b|n}{i|n} roles chained to the defaults, and offer the
installed families in the font combos after the standard set. cell_family
returns the installed role when it is bound, else the previous bucketing,
so it never names an unbound family. The scan runs in the background and
the first frame that rebinds skips painting, like the existing startup
gate. Native only; wasm keeps the standard list.
Incidental: newer local clippy flagged pre-existing lints in untouched
crates (no toolchain is pinned); fixed behavior-preservingly so the gate
passes.
* About: contributors compiled in from contributors.json (grab bag + table, sortable, name toggle)
Adds an About GridCraft dialog (tabs About · Contributors · Models) following the craftrules
standard (standards/contributors.md): contributors/contributors.json is generated by
craftrules/scripts/contributors.py and baked into the binary by crates/ui-egui/build.rs as
static tables. Each contributor line: @username, opt-in display/real name, PRs, commits,
lines +/−/Δ, binary assets +/−, first/last commit. Sortable by every column; alphabetical
ignores case and the leading @.
Reachable from the macOS app menu (About GridCraft, previously a web link), Help ▸
Contributors…, and Automate ▸ About GridCraft in the ribbon (all platforms and the web).
Dialog hyperlinks open through the host's open_url service. The snapshot example gains
--dialog 'name={json}' for offscreen renders of dialogs.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Contributors: self-submitted names in contributors/people.toml; AGENTS.md credit-yourself section
build.rs reads contributors/people.toml next to the generated contributors.json and shows a name only
for entries the generator verified as written by that person (craftrules standards/contributors.md).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Contributors: regenerate (verified people.toml entries)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
- ui-egui: title bar with QAT, full ribbon (Home/Insert/Draw/Page Layout/Formulas/Data/
Review/View/Automate + Table/Chart Design), formula bar with Name Box, virtualised grid
(frozen panes, overflow, borders, CF data bars/scales/icons, tables, sparklines, filter
buttons, charts/pictures/shapes), in-cell editor with point mode, reference colouring,
autocomplete and argument hints, sheet tabs, status bar, dialogs, control channel
- apps/sheetcraft: desktop app (control server, file dialogs, prefs, drag & drop)
- chart: toolkit-free chart layout/rendering for 25 chart kinds + sparklines + rasteriser
- mcp + sheetcraft-cli: MCP server (headless or bridged) and CLI (info/convert/eval/cat/run/mcp)
- xtask (ci/layers/assets/wasm/version/parity), release workflows, packaging, placeholder icon
- automatic row heights
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>