Add font selection to the text tool with a default in Settings - #186
Open
wangtuchuan wants to merge 1 commit into
Open
wangtuchuan wants to merge 1 commit into
wangtuchuan wants to merge 1 commit into
Conversation
Text annotations were locked to the bold system font. Add a font picker to the text sub-toolbar and a "default text font" row in Settings. - `TextAnnotation` gains an optional `fontName` (font family). nil keeps the existing bold system font, so old behaviour is unchanged. All drawing, measuring and editing paths resolve through one entry point, `TextAnnotation.font(named:size:)`: bold variant of the family when it has one, regular otherwise, system bold when the family is missing. - `withFontName` anchors the cap line the same way `withFontSize` does, so switching fonts does not make the text jump. Changing the font of a selected annotation goes through the atomic mutation path and is undoable; an active text field re-fonts live. - The sub-toolbar gets a `HUDPopupButton` ahead of the size slider. It uses `AdaptiveChrome.subtleFill` / `selectedFill` / `border` directly, like the other HUD buttons: those colours carry their own alpha, and `withAlphaComponent` replaces rather than scales it. - `FontCatalog` is the single source of the family list for both the editor menu (titles previewed in their own font) and the Settings popup (plain titles, matching neighbouring popups). Lists are cached. - `Defaults.textFontName` is one stored value: Settings edits it and the editor writes it too, matching the existing remember-last-used text options. A family that is no longer installed reads back as nil. - Localized strings added to all eight languages. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Text annotations are locked to the bold system font. There is no way to pick a typeface for a label, and no way to set one as the default.
What this adds
Editor — a font button at the front of the text sub-toolbar, followed by a separator, then the existing size slider / swatches / checkboxes unchanged. It opens a menu with "System default" on top and every installed font family below, each title previewed in its own typeface, current choice checked.
Settings — a "default text font" row in the capture pane, right after the beautify defaults (the pane that already owns editor-side defaults). Same title / hint / small
NSPopUpButtonrow geometry as its neighbours, plain titles so the closed popup matches the adjacent ones, refreshed on language change.Model
TextAnnotationgainsfontName: String?holding a font family.nilmeans the existing bold system font, so every existing call site and the Agent CLI behave exactly as before.All drawing, measuring, editing and re-editing paths now resolve through a single entry point,
TextAnnotation.font(named:size:): the family's bold variant when it has one, its regular face otherwise, and bold system font when the family is missing. No hard-codedNSFont.systemFont(..., weight: .bold)remains on the text path.withFontName(_:)anchors the cap line the same waywithFontSizedoes, so switching fonts does not make the text jump vertically.annotationsEqualEnoughcomparesfontName, so undo snapshots do not miss a font change.Persistence
One stored value,
Defaults.textFontName. Settings edits it; the editor writes it too, consistent with the existing remember-last-used text options (lastTextFontSize,lastTextStroke, …). A family that is no longer installed reads back asnil, so an uninstalled font can never wedge the tool.FontCatalogis the single provider of the family list for both surfaces (hidden.-prefixed families filtered, sorted by localized name, lists and preview titles cached).A note on
HUDPopupButtoncoloursThe button fills with
AdaptiveChrome.subtleFill(hover/pressed:selectedFill) and strokes withAdaptiveChrome.border, withoutwithAlphaComponent— the same wayMoreOptionsButtonandToolButtondo it.This matters: those adaptive colours carry their own alpha (
subtleFillis black @0.08 in light mode), andwithAlphaComponentreplaces alpha rather than scaling it. An early revision wrotesubtleFill.withAlphaComponent(0.72)and got a near-opaque black button with dark label text in light mode. A comment at the draw site records this.HUDCheckboxButtonuses that same formula today — its unchecked box renders as a dark grey block in light mode. That is existing behaviour and is left alone here to keep this PR scoped; happy to send a follow-up.Verification
bash scripts/compile-check.shclean,git diff --checkcleanswift test: 219 tests, 0 failures. NewTextAnnotationFontTests(11 cases): nil / empty / unknown family fall back to bold system font; an installed family resolves to itself at the right size;withFontNamepreserves other fields and round-trips;withFontSizepreservesfontName;Defaultsnormalizes an uninstalled family to nil;FontCatalogfilters hidden families..aquaand.darkAquawith a long CJK family name to check contrast, truncation and chevron direction in both appearances, then checked on device.Localizable.strings, none ending in punctuation.🤖 Generated with Claude Code