From 6bd87bccc60d8d7e033b9c5b476bc52f7337f63e Mon Sep 17 00:00:00 2001 From: Filip Strajnar Date: Wed, 14 Oct 2026 21:12:39 +0200 Subject: [PATCH] M7: the Small caps sample in Type settings draws without a box MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Small caps button in Type settings labelled itself "Aɢ", but the small-capital G (U+0262) is missing from egui's default fonts, which the UI uses whenever Inter isn't built in, so the button showed "A" and a box. The sample is now a capital followed by smaller capitals laid out from ordinary letters every UI font has. A test checks the UI fonts draw every letter of the sample. --- crates/ui-egui/src/typography.rs | 56 +++++++++++++++++++++++++++++++- docs/roadmap.md | 1 + docs/ui-parity.md | 3 +- 3 files changed, 58 insertions(+), 2 deletions(-) diff --git a/crates/ui-egui/src/typography.rs b/crates/ui-egui/src/typography.rs index 873ac0f0..56854f27 100644 --- a/crates/ui-egui/src/typography.rs +++ b/crates/ui-egui/src/typography.rs @@ -825,7 +825,11 @@ fn text_seg(ui: &mut Ui, salt: &str, items: &[(&str, &str)], active: Option Arc { + let mut job = egui::text::LayoutJob::default(); + let mut chars = label.chars(); + let first: String = chars.next().into_iter().collect(); + let rest: String = chars.map(small_capital_to_capital).collect::().to_uppercase(); + job.append(&first, 0.0, egui::TextFormat { font_id: regular(11.5), color: col, valign: egui::Align::BOTTOM, ..Default::default() }); + job.append(&rest, 0.0, egui::TextFormat { font_id: regular(8.5), color: col, valign: egui::Align::BOTTOM, ..Default::default() }); + ui.painter().layout_job(job) +} + +/// The capital a small-capital letter stands for (the ones a sample uses), else the letter. +fn small_capital_to_capital(c: char) -> char { + match c { + 'ɢ' => 'G', + 'ʜ' => 'H', + 'ɪ' => 'I', + 'ʟ' => 'L', + 'ɴ' => 'N', + 'ʀ' => 'R', + 'ʏ' => 'Y', + c => c, + } +} + /// One OpenType feature toggle; `on` None = mixed. Returns true when clicked. fn feature_row(ui: &mut Ui, tag: &str, label: &str, on: Option, supported: bool) -> bool { let t = Tokens::get(ui.ctx()); @@ -1136,6 +1167,29 @@ pub(crate) fn font_picker(ui: &mut Ui, current: Option<&str>, just_opened: bool) mod tests { use super::*; + #[test] + fn small_caps_sample_draws_only_letters_the_ui_font_has() { + let ctx = egui::Context::default(); + crate::theme::install_fonts(&ctx, false, 0); + let mut shown = None; + let input = egui::RawInput { screen_rect: Some(Rect::from_min_size(pos2(0.0, 0.0), vec2(400.0, 300.0))), ..Default::default() }; + let mut out = ctx.run_ui(input, |ui| { + shown = Some(small_caps_sample(ui, "Aɢ", Color32::WHITE)); + }); + out.textures_delta.clear(); + let g = shown.expect("drawn"); + assert_eq!(g.job.text, "AG"); + let [a, rest] = g.job.sections.as_slice() else { panic!("two sections: {:?}", g.job.sections) }; + assert!(rest.format.font_id.size < a.format.font_id.size, "the other letters are smaller capitals"); + ctx.fonts_mut(|f| { + for sec in &g.job.sections { + assert!(f.has_glyphs(&sec.format.font_id, &g.job.text), "UI font draws {:?}", g.job.text); + } + }); + assert_eq!(small_capital_to_capital('ʀ'), 'R'); + assert_eq!(small_capital_to_capital('x'), 'x'); + } + #[test] fn parses_line_height_and_letter_spacing() { assert_eq!(parse_line_height("Auto", None), Some(json!("auto"))); diff --git a/docs/roadmap.md b/docs/roadmap.md index 8e2780d6..12f2a5fb 100644 --- a/docs/roadmap.md +++ b/docs/roadmap.md @@ -73,6 +73,7 @@ blockers. | Date | Change | Summary | |---|---|---| +| 2026-10-14 | minor | M7: the Small caps button in Type settings showed a box where the UI font has no small-capital `ɢ` (builds without Inter use egui's fonts); its sample is now a capital and a smaller capital, drawn from ordinary letters every UI font has. Numbers unchanged | | 2026-10-14 | minor | M7: Home screen recent files as cards: each card shows the picture its file carries on its first page's colour, the file's icon, name and "Edited ... ago"; sort by name, creation or last change either way; a table view; a click selects, a double-click or Enter opens, arrow keys move; Open, Show in folder and Remove from recents on right-click. Numbers unchanged. | | 2026-10-14 | minor | Lost images reported on loading (#207): a `.figcraft` file whose image member is damaged, too large or missing no longer loads in silence; each lost image (up to 20, then a count) is listed in `repairs` on `file.open` with its hash and the reason, and the app shows it as a toast. Saving still writes the file without the lost images. Numbers unchanged | | 2026-10-14 | minor | SVG import budgets (#190): gzipped SVG is unpacked by FigCraft within 64 MiB before parsing (it was unpacked without a limit), so the nesting check sees the real document; SVG documents embedded in `` data URIs share one 32 MiB budget and at most 4 levels, and one past a budget is left out. Linked files stay unread. Numbers unchanged | diff --git a/docs/ui-parity.md b/docs/ui-parity.md index 6de538e7..84269b4b 100644 --- a/docs/ui-parity.md +++ b/docs/ui-parity.md @@ -1,6 +1,6 @@ # UI and interaction parity -> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-14 · **Change:** minor (recent files as cards; vector edit mode: hovering, hatching, selecting and dragging filled regions; home screen: Templates tab, first-run templates and Getting started tips; number fields: scrub rates, arrow steps, arithmetic with brackets, relative edits of mixed values; outline mode's hidden layers and object bounds; Hide when publishing; cursors per tool and modifier; panel widths; dark pages for files made in the dark theme; drag threshold and double-clicks into text in groups; rotation origin on Alt+R and placing with Enter: no documented shortcut missing; keyboard shortcut parity suite and bindings; cursor chat and spotlight in live sessions; layers and assets panels behaviour suite and fixes; vector multi-edit and the vector edit tail; canvas navigation, guides and grids behaviour suite and fixes; shapes and vector behaviour suite and fixes; paint and effects behaviour suite and fixes; frames, groups, sections and masks behaviour suite and fixes; layers panel keyboard: F2 rename, Shift+F10 context menu, F8 box selection; selection and transform behaviour suite and fixes; Display P3: gamut warning and soft-proof (true P3 blocked upstream); several windows; boolean hit testing on the result, group drags, frame outlines and slices; outlines for the selection, mask outlines; arc fields, live boolean editing, shape builder on strokes, one-sided widths) · **Target:** Figma Design UI3 (desktop app 126.10.7) +> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-14 · **Change:** minor (the Small caps sample in Type settings drawn from capitals; recent files as cards; vector edit mode: hovering, hatching, selecting and dragging filled regions; home screen: Templates tab, first-run templates and Getting started tips; number fields: scrub rates, arrow steps, arithmetic with brackets, relative edits of mixed values; outline mode's hidden layers and object bounds; Hide when publishing; cursors per tool and modifier; panel widths; dark pages for files made in the dark theme; drag threshold and double-clicks into text in groups; rotation origin on Alt+R and placing with Enter: no documented shortcut missing; keyboard shortcut parity suite and bindings; cursor chat and spotlight in live sessions; layers and assets panels behaviour suite and fixes; vector multi-edit and the vector edit tail; canvas navigation, guides and grids behaviour suite and fixes; shapes and vector behaviour suite and fixes; paint and effects behaviour suite and fixes; frames, groups, sections and masks behaviour suite and fixes; layers panel keyboard: F2 rename, Shift+F10 context menu, F8 box selection; selection and transform behaviour suite and fixes; Display P3: gamut warning and soft-proof (true P3 blocked upstream); several windows; boolean hit testing on the result, group drags, frame outlines and slices; outlines for the selection, mask outlines; arc fields, live boolean editing, shape builder on strokes, one-sided widths) · **Target:** Figma Design UI3 (desktop app 126.10.7) Fine canvas control is what Figma users feel first: handles, snapping, nudging, modifier keys, drag behaviour, numeric precision. This checklist covers the tools, gestures and panels. Status: @@ -164,6 +164,7 @@ in the table. `crates/ui-egui/src/shortcut_keys_tests.rs` drives the keys a look | Date | Change | Summary | |---|---|---| +| 2026-10-14 | minor | Type settings: the Small caps button draws its sample as a capital and a smaller capital, no longer as a box where the UI font lacks the small-capital letter (egui's default fonts) | | 2026-10-14 | minor | Home screen recent files as cards with thumbnails on their page colour, a sortable table view, selection, keyboard and a context menu | | 2026-10-13 | minor | Vector edit mode regions: with the Move tool the filled area under the pointer is hatched with "/" lines in the selection colour (about 1.4 px), clipped by the area's own fill rule so holes stay clear, and the hatch goes when the pointer is 3.5 px from a point or 2 px from a segment (screen pixels at any zoom); the spacing follows octave folding, fitted to measurements at several zoom levels (8 px at every power-of-two zoom, the gap growing with the zoom and stepping back at √2 · 2ⁿ), anchored to the vector so it doesn't slide when panning, one continuous pattern across selected areas; a click selects an area with its points (they move with it but keep the unselected look), Shift adds an area or takes a selected one out, a press on a selected area drags everything selected, drags show no hover hatch, a click on an empty spot (such as a hole) clears the areas and stays in edit mode, the last area listed wins where areas overlap, only filled vectors have areas; `vector.edit.select {regions}` and `vector.edit.state` report them (`regions_tests`, `vector_regions_tests`) | | 2026-10-13 | minor | Home screen: a Templates tab (eight starter templates as cards with thumbnails, search and a kind filter; click or Enter opens a new document) replaces the Community placeholder, the Drafts placeholder is removed, Recents offers four templates while there are no recent files and shows a Getting started card (closable; Help ▸ Getting started brings it back), File ▸ New from template…, and a first run opens on the home screen |