Commit Graph
1572 Commits
Author SHA1 Message Date
9ce6d89f46 i18n: interface translations from craft-i18n (#6055)
* build(i18n): embed the craft-i18n catalogs from a pinned checkout

- `craft-i18n.rev` pins storytold/craft-i18n at e45ddf7 (the PdfCraft cutover sync of
  pdfcraft@ecdd1e6); `.gitattributes` keeps it LF.
- The `craft-i18n` crate (craft-libs 787a7a0, PdfCraft's existing pin) is a direct dependency
  of the UI crate; it was already in the tree through craft-ui.
- `crates/ui-egui/build.rs` writes `CRAFT_I18N` from `CRAFT_I18N_DIR`: one (locale, common.tsv,
  pdfcraft.tsv) entry per locale with a `pdfcraft.tsv`, paths written with `{:?}` and never
  canonicalized. Unset it is empty (English only); `CRAFT_I18N_REQUIRED=1` makes a missing or
  invalid checkout an error.
- Both flatpak manifests name the craft-i18n commit and `CRAFT_I18N_DIR`; a test keeps both
  commits equal to the trimmed pin.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* feat(i18n): look strings up through craft-i18n behind a thin Lang wrapper

`i18n.rs` keeps PdfCraft's API (tr, tr_ctx, tr_id, trn, key_name, fmt,
Lang, LANGUAGES, detection) and hands lookups to the craft-i18n crate:
`get` for key names, `trn_plain` for plurals (no isolates, no digit
grouping), PdfCraft's own `fmt` (no FSI isolates). `@id` rows and the
"Undo {action}" template are read only where PdfCraft had them, so menus
and history labels read exactly as before.

Detection is unchanged (LC_ALL/LC_MESSAGES/LANG, macOS defaults,
sys_locale); the crate's match_tag would drop nb for no/nn, so PdfCraft's
own tag mapping stays, with one parity test per path.

Completeness tests become reports; tests that need catalogs skip with a
note when the build has none. Font coverage tests read the embedded
catalogs (shared and PdfCraft rows).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* chore(i18n): remove the in-repo catalogs; craft-i18n holds them

The 34 `crates/ui-egui/src/i18n/*.tsv` catalogs were migrated into
craft-i18n at pdfcraft@ecdd1e6 and are now embedded from the pinned
checkout. ATTRIBUTION.toml drops their 34 entries for one craft-i18n
`[[build_input]]` (craft-i18n's ATTRIBUTION.md credits the translators);
AGENTS.md and docs/localization.md describe the new system and how to
add a language.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* test(i18n): skip catalog tests without craft-i18n; drop the catalog hash exemption

Tests that switch to a non-English language skip with a note when the
build embeds no catalogs (CRAFT_I18N_DIR unset), so the English-only
build tests green. `skip_without_catalogs` moves to the integration
test support module.

With no catalogs left in the repository, `cargo xtask assets` no longer
exempts `crates/ui-egui/src/i18n/*.tsv` from hashing: every `[[asset]]`
carries a sha256 again, and a `.tsv` added back would need one.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* build(i18n): watch the locales directory before reading it

A CRAFT_I18N_DIR that doesn't exist yet now reruns the build script once it appears (review).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* build(i18n): pin craft-i18n dfbe955, the merge of storytold/craft-i18n#129

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(i18n): skip an @id row that changes the label's placeholders or ellipsis

craft-i18n checks placeholders and the trailing ellipsis on every row whose
source is English text, but not on @id rows, whose source is the command id.
The in-repo catalog test used to fail on such a row; since the cutover it only
prints it, while tr_id and menu_label still showed it. Both now use PdfCraft's
own @id row only when it keeps the label's shape (same_shape, the rule
craft-i18n applies elsewhere), and otherwise show the label's translation, as
bundled_catalogs_are_consistent says.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(i18n): reject an @id row with an open brace; list unused @id rows in the gaps report

same_shape skipped a `{` with no `}`, so an @id row such as "Öffnen {name…"
for "Open…" was still shown. It now counts as a changed shape.

bundled_catalogs_are_consistent printed the @id rows PdfCraft doesn't use, but
CI captures test output, so nobody saw them. translation_gaps_report, which
`cargo xtask i18n-report` runs with --nocapture, now lists them
(unused_id_rows).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(i18n): reject an @id row with a `}` that closes no placeholder

same_shape counted only the `}` that close a `{`, so "Öffnen name}…" for
"Open…" or "{name}} öffnen" for "Open {name}" still passed. A row whose `}`
count differs from its placeholders now counts as a changed shape.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(i18n): no braces in the assert messages of the brace test

assert! reads its message as a format string, so "a `}` without its `{`"
did not compile.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: FredApps <153173854+FredApps@users.noreply.github.com>
2026-11-04 00:47:17 +01:00
AdrianTM 0d3f57e120 M5: keep Fill & Sign editing on Enter and preserve line breaks (#5850) (#5954)
* M5: keep Fill & Sign editing on Enter and preserve line breaks (#5850)

* M5: preserve typewriter whitespace through readers and edits (#5850)

* M5: retain direct-subtype comment listing for Fill & Sign fix (#5850)
2026-11-03 10:24:45 -05:00
.CooCoo 15e45069cc Keep disabled scroll animations in Preferences (#5886) 2026-11-03 09:20:09 -05:00
ea353f7a59 fix(ui): do not open right-click context menu on image in crop mode (#5835) (#5900)
* fix(ui): do not open right-click context menu on image in crop mode (#5835)

* M7: preserve active crop context routing (#5835)

Prioritize active crops over overlapping images and share measured action-pill geometry with painting. Cover overlapping images, handle margins, page edges, and all view rotations with regression tests.

* fix(ui): test selected cropped image by quad in right-click loop (#5835)

* fix(ui): trim crop right-click routing to the crop box and handles (#5835)

The Done/Cancel/Remove Crop pills are widgets and already take their own
right-clicks, and the canvas context-menu guard already closes the image
menu, so drop the pill hit-test, the crop_pills layout extraction and the
extra secondary-click block. Move the session note to the Progress log.

---------

Co-authored-by: FredApps <FredApps@users.noreply.github.com>
Co-authored-by: FredApps <153173854+FredApps@users.noreply.github.com>
2026-11-03 14:00:16 +01:00
Harsh VermaandFredApps 01ba3ac9d1 Feat/unify hotbar quick tools (Fixes #5890) (#5909)
* feat(ui): unify quick bar and hotbar and refresh settings dialog (#5890)

* style(ui): compact hotbar tools customization menu

* fix(ui): keep hotbar settings visible when docked to sides and address review findings

- Add placed bool to Hotbar to distinguish explicitly placed [0.0, 0.0] from default floating margin offset
- Check !a.locked before applying quick bar color edits to annotations
- In non-full-side docked vertical layout, scroll tools within available height so settings button remains visible in compact windows
- Remove max_width(cell) on vertical full-side scroll area to avoid clipping wider controls
- Restore outer vertical scrolling with max_height on Hotbar tools picker window
- Add test verifying docked hotbar in compact windows keeps settings button visible, and assert controls do not overlap

* feat(ui): close hotbar settings menu when clicking outside or pressing Escape

- Detect pointer clicks outside the settings menu window bounds and dismiss the menu automatically
- Keep settings button click behavior to allow opening and keeping the menu open
- Support Escape key to dismiss the settings menu
- Add integration test verifying clicking outside on canvas or on another tool dismisses the menu

* style(ui): restore hotbar settings dialog design to match concept mockup

* fix(ui): cap hotbar tools picker width to viewport on narrow screens

* fix(ui): anchor hotbar tools picker to rendered bar edges to avoid overlap

* fix(ui): keep upgraded hotbars in the margin and label the settings controls (#5890)

Preferences written before this change have no `placed` key, so every
existing user's untouched floating, horizontal, top-centre hotbar would
have jumped out of the margin. Such a bar now takes the new default; any
spot the user chose, including the top-left corner, is kept.

The side picker reuses the Preferences segmented pill control, so its
options are themed, reachable as radio buttons by label and visible to the
translation scan. The layout switch now carries its label and enabled state.

---------

Co-authored-by: FredApps <153173854+FredApps@users.noreply.github.com>
2026-11-03 13:06:31 +01:00
Fatih KunakandClaude Opus 5.5 14ae839a28 i18n(tr): translate the 288 strings the gaps report lists (#5795)
* i18n(tr): translate the 288 strings the gaps report lists

The translation gaps report listed 288 English strings with no Turkish
translation, among them the Window menu ("Pencere"), the side-panel and
hotbar labels, the signature and timestamp validation messages, the
accessibility checker findings, the plurals and the calendar weekday heads.
The two English stand-ins at the top of the catalog are translated too.
`cargo xtask i18n-report` now lists 0 missing for tr.

Terms follow the existing catalog (annotation = açıklama, digital ID =
dijital kimlik, bookmark = yer işareti, redact = karart). Placeholders and
trailing ellipses match the English source. AI-assisted; not separately
reviewed line by line by a native speaker.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* i18n(tr): note the native review of the judgement calls

A native Turkish speaker reviewed the translations the PR flagged as
judgement calls ("of" as a slash, hotbar, navigation rail, the certificate
key-usage terms, the weekday heads) and kept them. The rest stay
AI-assisted, so full proofreading is still pending.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(i18n): state the Turkish coverage by the gaps report, not the dated union

The 2,798-key union in localization-parity.md was measured on 2026-10-25 and
predates keys added since, so "every current key" against it did not add up
(CodeRabbit). The Turkish row now says what was measured: 2,867 entries and
0 missing in `cargo xtask i18n-report` on 2026-11-03.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Revert the vendored Cargo.lock changes c700ce42 picked up by mistake

They came from running the vendored crates' tests locally and have nothing to
do with this PR.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-03 00:33:33 -05:00
Rahulandrahul05ranjan d9b735973b i18n(fr): translate the 16 strings the report listed as missing (#5736)
The French catalog lacked 16 interface strings: the crop-image and
mouse-wheel-speed labels, the signature-validation findings (RSA key
size, CMS content-type and message-digest rules, timestamp authority
certificate), the certificate recognition sentence, the changed-on-disk
reload warning, the password rule, the table-layout validations, and
the Appearance theme name.

Adds them in the catalog's TSV format. After this the report lists
nothing missing for fr.

Co-authored-by: rahul05ranjan <11793455+rahul05ranjan@users.noreply.github.com>
2026-11-03 00:33:26 -05:00
5cb65ff0ee feat(ui-egui): Preferences can invert the middle-button drag (#5790) (#5817)
Add a saved preference, invert_middle_drag (off by default), that
reverses the direction of the middle-button pan and of the latched
auto-scroll. It changes only the direction, not which of the two a
platform uses, so it composes with the Windows auto-scroll work.

Reachable as Preferences > Invert middle-button drag and headlessly
through ui.set invert_middle_drag. Parity "Automatic scrolling" notes
updated; status unchanged.

Tests: a unit test of both paths with the switch on and off (dead zone
kept), a settings round-trip test, and an end-to-end control-channel
drag. Each fails with its fix reverted.


Claude-Session: https://claude.ai/code/session_01SqmHYx8FiWM5PcsoiErgp9

Co-authored-by: KenM76 <KenM76>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-03 00:33:18 -05:00
Dylan M. Taylor 661ded72bb Merge pull request #5748 from Combiler01/fix/single-page-zoom-scroll-lock-5713
fix(ui): prevent wheel lockup at edge in non-continuous view (#5713)
2026-11-02 22:59:04 -05:00
FredApps 8f1441a3f2 fix(ui): keep pane resize edges right of the border, off the page scrollbar (#5730)
The centred 4 pt strip still covered the right 3 pt of the page's
scrollbar beside a right-docked pane. Register the host's resize edge
again from the border rightwards, on the host's own layer, and leave an
inert edge inert. The test now hovers and drags both scrollbars beside a
right-docked Tools pane (CodeRabbit) and checks the width is unchanged.
2026-11-02 16:59:26 +01:00
FredApps 1997b8ed94 Merge remote-tracking branch 'origin/main' into pr5740 2026-11-02 16:29:14 +01:00
FredApps 1303684851 Merge pull request #5639 from RiceDee/fix/rail-page-zoom-fields
fix(ui): the rail's page box fits, and the zoom field looks like a field (#5636)
2026-11-02 14:46:11 +01:00
FredApps 2d4e317a58 Merge pull request #5638 from RiceDee/fix/quick-bar-centred-in-margin
fix(ui): centre the quick-tools bar in the margin beside the page (#5635)
2026-11-02 14:45:58 +01:00
arnav-hiwarkarandClaude Opus 5.5 08af1dc39f fix(ui): end a notch's turn when the next notch only pans (#5713)
A wheel notch sets `turned`, and only a trackpad touch or a smooth burst
cleared it. With a wheel that macOS reports in points, a notch that
turned the page left `gesture_turned` set, so read_wheel swallowed every
later notch on that page. The same happened at the last page's bottom
edge.

A notch that cannot turn now clears `turned`. The new tests use Point
notches. The Line-unit test in b31b4035 passes without either fix,
because egui's own ScrollArea still applies line scrolling.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-02 18:33:38 +05:30
RiceDee ecd1822525 fix(ui): the size field shows "Mixed" whole in a tooltip (#5634)
A long translation scrolls in the capped field, so the tooltip gives the full status.
2026-11-02 23:37:29 +11:00
Combiler01 b31b40356d fix(ui): prevent wheel lockup at edge in non-continuous view (#5713) 2026-11-02 17:54:15 +05:30
RiceDee 89efc79ecd fix(ui): the size field stays within its room in the row in every language (#5634)
It reserves room for a translated "Mixed", and in Czech or French that pushed the alignment
button up to 54 pt past the Tools pane. The field is now no wider than SIZE_FIELD, and a longer
translation scrolls in it. The language test checks the size row too.
2026-11-02 23:23:20 +11:00
Harsh Verma ec2f59305b Merge branch 'storytold:main' into fix/panel-resize-scrollbar-5730 2026-11-02 12:23:11 +00:00
RiceDee 808ba71287 Merge main into fix/rail-page-zoom-fields
Conflict with main's rail docking, resolved by keeping both: the rail follows the side chosen
for it (main) at 49 pt with 1 pt padding, and main's dock button stays above the page display
button, while zoom out and in stay side by side under the zoom field.
2026-11-02 23:11:59 +11:00
RiceDee bcff9a3948 Merge main into fix/quick-bar-centred-in-margin
Conflict with main's hotbar, resolved by keeping both: the bar keeps main's offset past a hotbar
docked on the left or top, and centres in the margin that starts after it.
2026-11-02 22:58:09 +11:00
RiceDee f711b163c6 Merge main into fix/format-text-fields-fit-pane
Conflicts with main's font menu, size field and accessible names, resolved by keeping both:
the font list keeps main's searchable installed-fonts menu inside its outline; the line spacing
list and number fields keep their names. The size field now reserves room for "Mixed", so
MIN_ROW counts it (62 pt, measured for English), and the spacing columns take their width from
the font list so a longer translation of "Mixed" can't widen them.
2026-11-02 22:43:31 +11:00
Combiler01 8baae14c34 fix(ui): prevent panel resize handle collision with scrollbar (#5730) 2026-11-02 16:36:17 +05:30
FredApps 2f8a8fb625 Preferences: reconcile current main before final validation 2026-11-02 11:23:23 +01:00
NetterSilverandClaude Haiku 5.5 d7dd1de647 Reject '+' sign in page selection numbers (#5715)
Found while testing crates/ui-egui/src/panels/page_selection_ui.rs:24-27 (parse, `number` closure)

Co-authored-by: Claude Haiku 5.5 <noreply@anthropic.com>
2026-11-02 05:07:42 -05:00
Combiler01 d266527b98 ui: fold dotted and dotless i in preferences text search 2026-11-02 14:41:41 +05:30
Combiler01 b5e847d3b9 ui: scroll to matches in segmented pill options, toggle pills, and theme cards 2026-11-02 14:18:21 +05:30
Combiler01 7f42c375dd ui: translate search match-count text and remove unused toggle_pill 2026-11-02 12:45:46 +05:30
Combiler01 80ffea6df4 ui: remove misleading cancel button from preferences dialog 2026-11-02 12:28:19 +05:30
Combiler01 0c822af3b1 ui: implement browser-style in-situ text search and highlight in preferences 2026-11-02 12:00:53 +05:30
Harsh Verma fa818ccc08 Merge branch 'storytold:main' into feat/preferences-cards-refresh 2026-11-02 06:00:41 +00:00
Combiler01 6aa88171d3 ui: register theme card focus upfront and assert TwoUp continuous preservation 2026-11-02 11:24:53 +05:30
Combiler01 dac706f3b2 ui: fix vertical layout containment for theme preview cards 2026-11-02 11:02:02 +05:30
Combiler01 8867d15d18 ui: align navigation rail accessibility labels with existing integration test 2026-11-02 10:46:10 +05:30
Combiler01 ec533af1bb ui: fix two-page continuous scrolling and add keyboard focus indicators 2026-11-02 10:43:27 +05:30
f035218cb4 fix(ui): don't check recent files on the UI thread at startup (#5682) (#5692)
* fix(ui): don't check recent files on the UI thread at startup (#5682)

Restoring settings dropped recent files whose files no longer exist by
asking the file system about each one on the UI thread, before the first
frame. On a network mount that has stopped answering (davfs2 in the
report) that call blocks in the kernel, so the window never appears.

Settings now keep every recent entry when they load. Once the window is
up, a worker checks the restored paths and each frame drops the ones it
has found gone. An entry it hasn't reached, or can't tell about (the
mount answers with an error), stays listed. A worker stuck on a dead
mount stays stuck, but nothing waits for it. This follows the pinned
folders' worker.

Fixes #5682

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Recent files: a file opened while the check is pending stays listed

The worker's answer that a restored path is gone is out of date once the
user opens that path; keep the new entry (CodeRabbit on #5692).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-11-01 23:49:10 -05:00
Combiler01 5f07da4419 ui: modernize preferences dialog with card-based layout
- Replace cluttered settings list with clean, modular card containers
- Integrate interactive real-time search box flush with card boundary
- Combine page display and continuous scrolling into a unified segmented pill
- Enable smooth scrolling with dedicated animation duration
- Enhance vertical scrollbar spacing and layout geometry
- Update unit and integration tests across layout, appearance, and theme
- Credit @Combiler01 in contributors/people.toml
2026-11-02 09:58:24 +05:30
FredApps d35be6fdac fix(ui): use the shared rail viewport fix (#5677) 2026-11-01 22:40:04 +01:00
FredApps 8e035f2e34 fix(ui): reserve the navigation rail footer height (#5677) 2026-11-01 22:14:38 +01:00
archamon faebcfd264 fix(annot,ui): stabilize ink width bounds, search translated tool labels, and fix hotbar settings label 2026-11-01 20:58:16 +00:00
archamon 53c79ca9b0 feat(ui,annot): customizable hotbar strip, freehand highlight, and moveable navigation rail
- Add Freehand-Highlight tool with 100pt line width support, Lucide highlighter icon, and PDF Multiply blending.
- Add customizable floating and docked hotbar with command picker, size slider, full-side strip chrome integration, and settings gear icon anchored at the bar end.
- Add left/right docking options for the navigation rail with toggle button and preferences setting.
2026-11-01 20:23:12 +00:00
Livio OswaldandClaude eafe9e2c0b M8: typing the last page of a range keeps what is typed (#5574) (#5579)
* M8: typing the last page of a range keeps what is typed (#5574)

The page-range dialogs (Redact pages, Rotate pages, Duplicate field,
Number pages) raised the end to the start on every frame, so the
half-typed "1" of "12" became the start before the "2" arrived.
The end is now ordered only once its field is no longer being typed
into. Number pages no longer lowers the start to a half-typed end, and
its preview cannot underflow while the end is below the start.

* M8: a test types the last page of Rotate Pages' range (#5574)

Rotate Pages' From and to fields are labelled, and a test types "12" after a
first page of 5 (pages 5-12 are turned) and "3" left by clicking OK (page 5
alone), as croquete1 asked on #5579.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GbuSKAS2k5248LGFEapMUR

* M8: page ranges stay typed while the window is in the background, and OK orders them (#5574)

Review follow-up. The end field's typing check used Response::has_focus,
which is false while another window is in front, so switching apps
halfway through "12" still raised the typed "1" to the start. It now
asks egui's memory (widgets::typing_into). OK pressed while the end is
still focused (a screen reader's click) orders the range first in Rotate
pages, Duplicate field and Redact pages, and Number pages builds its edit
from the ordered end, so a reversed range never reaches the edit.

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-11-01 15:05:01 -05:00
Livio OswaldandClaude Opus 5.5 901050a31f M14: the comments panel lays out only the cards in view (#5488) (#5583)
* M14: the comments panel lays out only the cards in view (#5488)

With more than 100 comments, a card or page header out of view that
was measured at the current width only takes up its height instead of
being laid out every frame. The selected card is always drawn, so it
still scrolls itself into view. Shorter lists are laid out whole and
keep every card in the accessibility tree.

The 500-comment panel in tests/perf.rs drops from about 23 ms to 5 ms
per frame locally, well inside the 40 ms budget it overran on CI.

* M14: the comments panel measures a card again when it changes (#5488)

A card's kept height is now per document and per what the card shows (its
thread's text, author, date, status, colour and lock, and whether it is the
selected card), so another document at the same width, an edit, an undo or a
redo never lays the cards below it out at a stale height (CodeRabbit on #5583).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GbuSKAS2k5248LGFEapMUR

* M14: a comment card with an editor open is never skipped (#5488)

A card with an inline editor open on it or on one of its replies is laid out
wherever it is, and its kept height is apart from the one without the editor,
so the cards below make room for the editor (CodeRabbit on #5583).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GbuSKAS2k5248LGFEapMUR

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-11-01 15:04:57 -05:00
Livio OswaldandClaude Opus 5.5 2242eb322f M10: Create ▸ Blank page uses the system region's paper (#5644) (#5651)
* M10: Create ▸ Blank page uses the system region's paper (#5644)

A new blank document was always US Letter. It now takes the paper of the
system region: Windows' own Region paper size (iPaperSize) first, then the
system locale on macOS or LC_ALL/LC_PAPER/LANG, A4 everywhere outside CLDR's
US-Letter regions, and Letter when the region can't be told (web).
The region parsing is shared with the Units preference.

* M10: the first locale variable set decides the paper; extensions are not regions (#5644)

LC_ALL, LC_PAPER and LANG are read in POSIX order and the first one set
decides, so LC_ALL=C no longer falls through to LANG's region; and a locale
tag's region is read from its base tag only, so en-US-u-nu-latn is US, not
NU (CodeRabbit on #5651).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GbuSKAS2k5248LGFEapMUR

* M10: the blank page test covers A4 as well as Letter (#5644)

The app keeps the paper Create ▸ Blank page makes (blank_paper, the system
region's at start), so the test makes a blank page on A4 and on Letter
whatever the host's region (CodeRabbit on #5651).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GbuSKAS2k5248LGFEapMUR

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-11-01 15:04:52 -05:00
Livio Oswald a74e3d4715 M3: the wheel scrolls right after Alt+Tab back, before the mouse moves (#1518) (#5608)
After switching back to the window, the windowing layer sends no
pointer move until the mouse moves, so egui knew no pointer and the
wheel scrolled nothing. When a frame turns the wheel with no known
pointer and no move of its own, the raw-input hook now asks the system
where the pointer is (drag_pointer::in_window, already used for file
drags) and puts that move first.
2026-11-01 15:04:47 -05:00
VoiceLessQ 424ca0e972 M14: Preferences sets how many recent files to keep (#5572) (#5675)
The list was fixed at 12. Preferences ▸ Documents and view now takes a
number from 0 to 50, with 12 as the default. At 0 Home has no Recent
section and File ▸ Open Recent is disabled.

The list is cut when Preferences closes, so the number can pass through
0 on its way to another. Until then Home and saved settings already
leave out what is past it. A settings file can't ask for more than 50.

The control channel and launch options take it as recent-files. The two
new strings go in every catalog as English copies.
2026-11-01 13:52:47 -05:00
FredAppsandCodex GPT-6.1 6816d14e02 Fix context image placement and canvas selection ownership
Convert context-paste user coordinates into AddImage display coordinates and
identify the inserted image through its new owning stream and XObject. Keep
legacy added-image metadata aligned with the active image controller, route
Delete to the visible selection, and clear hidden image selections when leaving
the controller while preserving text selections and drafts.

Separate selection-dependent Copy from whole-page Snapshot and document Export
permissions. Add synthetic UI regressions covering transformed page placement,
identity collisions, shared image references, saved deletion results, tool
transitions, and permission controls.

Co-Authored-By: Codex GPT-6.1 <noreply@openai.com>
2026-11-01 17:54:15 +01:00
FredAppsandCodex GPT-6.1 fdb6a6f33e fix(ui): rotate cropped image previews around the committed pivot
Project the visible user-space bounds centre for the drag preview, matching the RotateBy engine operation. The full image centre differs for cropped artwork and caused the preview to jump on release.

The regression compares actual painted preview corners with saved/reopened image corners and verifies a requested 90-degree turn on cropped and uncropped controls, including page rotation. Linux scoped clippy, 106 tests, wasm, formatting, layering and assets pass.

Co-Authored-By: Codex GPT-6.1 <noreply@openai.com>
2026-11-01 17:34:13 +01:00
FredAppsandCodex GPT-6.1 c0a5a5cbf8 fix(ui): resize image frames relative to the captured press
Invert the actual affine basis instead of projecting onto assumed orthogonal axes. Capture the displayed crop frame for handles and apply its relative transform to the full artwork, preserving author clips on rotated pages. Exact out-and-back gestures preserve bytes and undo state, including off-centre presses.

Synthetic headless regressions verify sheared and rotated images, crop-frame anchors, press-offset independence and saved/reopened placement. Degenerate and nonfinite bases are refused; the inverse guard has a negative-control test.

Co-Authored-By: Codex GPT-6.1 <noreply@openai.com>
2026-11-01 17:34:13 +01:00
FredAppsandCodex GPT-6.1 393bd30701 fix(ui): leave source text untouched when script conversion is a no-op
Only request a script conversion from the panel; the caller decides whether conversion changed the text. Do not create a paragraph rewrite merely because the button was clicked. A hidden QQQ fixture checks both script buttons preserve document bytes, undo history and saved rendering, while supported conversions remain covered. Actual reverted-fix raster failure and scoped Linux native, wasm, clippy and repository checks passed.

Co-Authored-By: Codex GPT-6.1 <noreply@openai.com>
2026-11-01 17:19:21 +01:00
FredAppsandCodex GPT-6.1 27e34098d3 fix(ui): size the font field for the localized mixed label
Measure Mixed with the active body font and include the input margins and caret allowance. Keep that minimum stable while typing so the full label is visible without shifting the row on each keystroke.

A themed panel regression fails against the old 40-pixel input, verifies the text fits inside the field margins and keeps the alignment control inside a 272-pixel pane. Linux scoped clippy, format tests, wasm, formatting, layering and assets pass.

Co-Authored-By: Codex GPT-6.1 <noreply@openai.com>
2026-11-01 16:34:38 +01:00