Commit Graph
4844 Commits
Author SHA1 Message Date
vangel76andClaude Sonnet 5.5 a371b24f2a test(sign): tighten the NeedAppearances tests (#5939)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-05 01:25:41 +01:00
vangel76andClaude Sonnet 5.5 a62633e902 fix(sign): the first signature drops /NeedAppearances so Acrobat recognises it (#5939)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-05 01:16:17 +01:00
vangel76andClaude Sonnet 5.5 c4dd5fe245 Format
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-05 00:07:26 +01:00
vangel76andClaude Sonnet 5.5 d604dc3c30 Merge upstream/main into perf/write-full-retain-parsed-objects
Upstream now counts the parsed tree and keys in held_bytes and tracks the cache total itself,
which replaces this branch's copy of the cache accounting and its owned_bytes. write_full's
retention budget uses held_bytes; the separate node budget is dropped since held_bytes counts nodes.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-05 00:06:23 +01:00
Dylan M. Taylor d22641a875 Pass the Linux signing key to the release workflow (#6200) 2026-11-04 17:44:52 -05:00
oracola91 a427cd2de5 Word takes the script a language tag names
pa-Arab-PK is Punjabi in Arabic script, which Word keeps as right-to-left
text, but word_lang looked only at the language and wrote w:val. A script
subtag (Arab, Hebr, Syrc, Thaa; Hans, Hant, Hani, Jpan, Kore, Hang, Hira,
Kana; Latn, Cyrl, Grek) now decides over the language. It is read only in
its own place, after the language and any extended languages, so private
use such as en-x-arab names no script.
2026-11-04 23:00:11 +02:00
oracola91 561cc0d707 A language tag can't end in a singleton
A singleton (one letter or digit) starts an extension, or with x private
use, and BCP 47 needs a subtag after it. en-x and en-a were written as the
document's language. They and a singleton straight after another are now
left out; one-character subtags inside private use stay allowed.
2026-11-04 23:00:11 +02:00
oracola91 0cae1c518b A language tag longer than 35 characters is still a tag
BCP 47 sets no maximum length; 35 characters is only the least a protocol
must hold. A well formed tag such as en-US-u-ca-gregory-nu-latn-co-phonebk
was left out of both exports. The bound is now 255, kept only so a PDF's
/Lang can't put an unbounded string in the file.
2026-11-04 23:00:11 +02:00
oracola91 a699e13305 Word and HTML exports name the document's language
Word export named no language, so Word checked the spelling of every
export as English and underlined a whole document in any other
language. The PDF already says its language in the catalog's /Lang.
When that is a well formed language tag, Word gets it as the default
language of the text (w:docDefaults), in the attribute Word keeps for
its script: w:eastAsia for Chinese, Japanese and Korean, w:bidi for
Arabic, Hebrew, Persian and Urdu, w:val for the rest. Both HTML
exports, with and without CSS, get <html lang>. Without /Lang, or with a
malformed one, the files are exactly as before.

docx_with_language, html_with_language and html_simple_with_language
take the language; docx, html and html_simple stay as they are and call
them with none. The engine reads /Lang through the existing initial
view.

The new export and engine tests fail without the change.
2026-11-04 23:00:11 +02:00
KenM76andClaude Opus 5.5 ecb5cae460 Merge origin/main (083b3aca) into feat/rich-copy
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SqmHYx8FiWM5PcsoiErgp9
2026-11-04 15:54:54 -05:00
KenM76andClaude Opus 5.5 29ea66cd4e M3: the clip text-cap test is bounded, so it fails without the cap
The test pushed until the builder refused; with the cap removed it never
stopped. It now pushes at most two chunks past the cap and checks the cap
stopped it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SqmHYx8FiWM5PcsoiErgp9
2026-11-04 15:54:28 -05:00
KenM76andClaude Opus 5.5 a955373428 M3: copy with formatting keeps one clipboard open and is tested through a stand-in
Review fixes for Copy with formatting.

- ui-egui: the HTML copy goes through one arboard Clipboard, created on
  first use and kept in the app (os_clipboard::with_kept, under the same
  process-wide lock), instead of a fresh one per copy. On X11 the copied
  data is served only while its Clipboard lives, so a fresh one dropped
  at once could leave nothing to paste without a clipboard manager. A
  failed create or set falls back to egui's plain-text copy.
- ui-egui: html_clipboard_override stands in for the system clipboard in
  tests. With the system clipboard on, Copy sets HTML and plain text in
  one set and emits no CopyText; when the set is refused it emits
  CopyText with the plain text. The HTML is built only when a clipboard
  will take it (system clipboard on, not the web build). The
  last_copied_html field is gone.
- export: clipboard HTML text is escaped in one pass and also drops C1
  controls, a bare carriage return and the bidirectional overrides and
  isolates. Font sizes are written within 1 to 1000 pt.
- engine: the glyph-to-block step budget is a parameter, tested; the copy
  says styles_incomplete only when matching actually ran out of steps.
- automation: text_extract format "html" has one 32 MiB HTML budget
  across all pages; a page past it gets none, and the result carries
  html_truncated. The tool description says so.
- parity: the new tests are evidence.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SqmHYx8FiWM5PcsoiErgp9
2026-11-04 15:51:57 -05:00
FredApps 083b3aca44 Merge pull request #6087 from KenM76/feat/model3d-render
M12: model_render, a page's 3D model drawn to a PNG (stacked on #6069)
2026-11-04 20:19:35 +01:00
FredApps 52d68d7844 annot: share threed's MAX_MODEL_BYTES with model3d
main's 3D-embed change (#5808) added crates/annot/src/threed.rs with its own
pub MAX_MODEL_BYTES (same 256 MiB value), so both were re-exported from the
crate root and pdfcraft-annot no longer compiled after merging main. model3d
now uses threed's constant.
2026-11-04 19:52:51 +01:00
FredApps 697a02e2ef Merge storytold/main into feat/model3d-render
# Conflicts:
#	crates/automation/src/lib.rs
#	crates/automation/tests/it/main.rs
2026-11-04 19:52:51 +01:00
FredApps ef8c71ac9c Merge pull request #6069 from KenM76/feat/prc-render
M12: headless renderer for PRC models (`pdfcraft-prc-render`), stacked on #5786
2026-11-04 19:42:33 +01:00
FredApps 8f8842e3ab Merge pull request #5396 from KenM76/fix/ocr-edit-under-scan
fix(edit): an edited OCR phrase under its scan image is drawn on top (#3973)
2026-11-04 19:42:25 +01:00
alehelandClaude Opus 5.5 723667f29d test(ui): pin the behaviour changes no test covered
Found in review: the PR lists these and nothing pinned them.

- With Prepare open, a drag from a highlight draws the selection rectangle.
- A double-click on a paragraph selected with others opens it.
- In crop mode, a right-click on the next page goes to what lies there,
  though a clipped artwork's whole frame reaches over it.
- A crop grip takes a press within its reach, 9 px off.
- A comment's menu opens over a picture and over a paragraph.
- A right-click with the button held opens the selected comment's menu.

Each seen failing against a planted violation.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-04 19:37:47 +01:00
alehelandClaude Opus 5.5 a21f098049 test(ui): true docs and no dead code after the review of the routing
Found in review. No change in behaviour.

- The guard's `PAGE_HIT_CALLS` refused nothing once `main`'s press-handler
  check went; it only failed when it was stale, so it goes.
- The guard's notes said `canvas/image_pick.rs` uses none of the marks (it
  takes `PagePointer` now), that page modules read only
  `PagePointer::drag_started` (some ask for the primary button themselves),
  and left out the point tests that tell a tool a press began on its page.
- `content_ui`'s and the comments' notes said added text is its own with
  every tool, and that added content decides for itself.
- `object_ui`'s `!double_clicked()` can't fail (the page view re-routes
  that press), and Fill & Sign's preview recomputed `hovered`.
- `Capture` is private, and `top` is `canvas`'s.
- Test notes gave as history bugs that only this branch ever had.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-04 19:37:47 +01:00
alehelandClaude Opus 5.5 8102109d19 fix(ui): a right-button drag leaves a text selection alone
Found in review. `fix(ui): a right-button drag on the pages starts nothing
a left one does` covered drag starts. A right-button drag still moved the
end of a selection already made, as `update_dragged_selection` tested a
drag by any button (`main` replaced the selection instead). And its end
finished a selection whichever button it was, so with a markup tool, Replace
Text or Redact a selection left from another tool became a comment. Both
read the primary button now.

Tests, each seen failing with its fix reverted (Redact's on its own):
`a_right_button_drag_leaves_a_text_selection_alone`,
`a_right_button_drag_makes_no_mark_of_a_text_selection`.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-04 19:37:47 +01:00
alehelandClaude Opus 5.5 9262213589 fix(ui): Add text's held draft and a locked document keep their limits
Found in review, each against `main`:

- With Add text holding text it can't draw, a drag from a paragraph moved
  the paragraph; only its click was refused. Neither acts now (#125's
  draft stays where it is being typed).
- A right-click reached a Prepare field whatever the field tool and while
  a table is set up (a review ruling), but also on a document that can't
  be changed, where Prepare stays open after a tab switch: it selected the
  field and opened a menu of entries the engine would refuse. It selects
  nothing there.

Tests, each seen failing with its fix reverted:
`add_text_moves_no_paragraph_while_it_holds_a_draft_it_cant_draw`,
`with_prepare_on_a_locked_document_a_right_click_on_a_field_selects_nothing`.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-04 19:37:47 +01:00
alehelandClaude Opus 5.5 dd9ec46efc fix(ui): a picture's grip and knob take their drag from the press
Found in review. On `main` the selected picture's grips and rotate knob
were drag-only widgets of their own, so their drag began at the press.
Their widgets went, and the page's response is click-and-drag, which calls
it a drag only past egui's click distance: a move of a few pixels resized
nothing. They take their drag from the press again. A click that doesn't
move edits nothing, as before; a drag of the picture itself still waits,
since a click selects.

Tests: `a_short_drag_from_a_picture_grip_resizes_it` (seen failing with
the fix reverted), `a_click_on_a_picture_grip_changes_nothing` (a pin,
seen failing with the release planted to edit always).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-04 19:37:47 +01:00
alehelandClaude Opus 5.5 fd091beaab fix(ui): a drag from the selected picture moves it under another picture
Found in review. The selected picture's frame is its own on `main`: a
drag from it moves it, though another picture lies over it there. The
routed press was the top picture's, and the drag only started for the
selected one's, so nothing moved. `PicturePart::OverSelected` says so: a
click there selects the picture on top, as before, and a drag moves the
selected one.

Test, seen failing with the part planted away:
`a_drag_from_the_selected_picture_under_another_moves_the_selected_one`.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-04 19:37:47 +01:00
alehelandClaude Opus 5.5 1ee332ae55 fix(ui): a picture's keys act only while its page is drawn
Found in review. Delete, Backspace and crop's Enter and Escape moved to
the app's keys, which run before anything is drawn and don't look at what
is on screen. So with Edit text and a picture selected:
- Delete in the page grid removed the hidden picture and kept the pages;
- Delete with the pointer on the Pages panel did the same;
- with the picture's page scrolled away or in single-page view on another
  page, Delete removed a picture the reader couldn't see, and Enter
  applied its crop.

`main` read these keys in the picture's own page pass, which none of
those cases reach. `picture_keys` runs there again, from
`page_tool_input`, under Edit text's gate (so no dialog gets them), and
before the group acts. Delete still works wherever on the pages the
pointer is.

Tests, each seen failing with the fix reverted:
`delete_in_the_page_grid_deletes_the_page_and_not_the_hidden_picture`,
`a_selected_pictures_keys_wait_for_its_page_to_be_on_screen`,
`delete_with_the_pointer_on_the_pages_panel_deletes_a_page`.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-04 19:37:47 +01:00
alehelandClaude Opus 5.5 79205fe4ac fix(ui): with Edit text, what has no menu gives way to a picture under it
Found in review. With Edit text, a right-click on added text or on an
open paragraph's frame went to that, which has no menu: the picture under
it was unselected and the page's menu opened. `main` opens the picture's.
Those give way to a picture under them, as paragraphs do, and to nothing
else: a comment under added text stays unselected, as before.

A comment in `draw_pages` said a selected Prepare field keeps its menu
off the pages. Since the page menu follows the right-click, it stays
selected and the menu is the page's.

Tests, each seen failing with the fix reverted:
`a_right_click_on_added_text_over_a_picture_selects_the_picture`,
`a_right_click_on_an_open_paragraphs_frame_over_a_picture_selects_the_picture`.
`a_right_click_with_edit_text_on_added_text_over_a_comment_selects_no_comment`
is a pin, seen failing with added text dropped from the hits outright.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-04 19:37:47 +01:00
alehelandClaude Opus 5.5 a5ed8c68bf test(ui): the page guard sees router aliases and scoped names; true docs
Found in review:

- Rule (f) missed `pub(in …)` functions, the visibility the guard's commit brought
  in (`declares` strips any `pub(…)`), and flagged names that merely
  end in its words (`dropdowns`): it now matches whole words of the name.
- Inside `canvas` the narrowed visibility doesn't hold, and a router
  taken whole (`let r = &view.router;`) got past the checks by method
  name; such a use now counts as the router's (`takes_the_router`).
- Docs: the router's module doc and `PagePress::Free` say a declined
  drag is nobody's once it starts; Prepare's note says a highlight's drag
  is Prepare's; Add text's paragraph note names `ParagraphCx::adding`;
  a test's doc claimed crop-mode keys it doesn't press.
- One source each for the objects' menu test (`object_ui::menu_open`)
  and Edit text's gesture cancel (`cancel_pointer_gestures` calls
  `cancel_edit_text_gestures`); the page-menu test asserts an entry
  only the page's menu has.

Each guard addition seen failing against a violation planted in
`#[cfg(any())]` code in `canvas/area.rs`.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-04 19:37:47 +01:00
alehelandClaude Opus 5.5 d10a89fdd1 fix(ui): Edit text's presses that 4b's routing dropped reach their owners
Found in review, each against `main`'s behaviour:

- A double-click on one of the objects selected together only left the
  group: the second press was the group's. It is the object's under it,
  so added text opens for typing and a picture is selected, as before;
  a paragraph opens too (the user's ruling).
- On a page whose objects can't be selected together, a click on the
  empty page left the picture selected: no area selection starts there
  to drop it, and the picture's own test that did is gone. A click nobody
  holds on the page unselects it.
- Crop mode's grips stopped at the page's edge, so those of a picture
  filling its page could be taken from their inner half only. They reach
  past it, cursor, press and right-click: no page took a right-click
  there, which left crop mode and opened the page menu (#5900 keeps crop
  mode there). The box and the picture stop at the page's edge, as a
  clipped artwork's whole frame can reach over the next pages.
- A press past a page's edge was the page's whenever it had any hit
  there: the objects selected together, or the open paragraph's frame,
  took presses on the next page and did nothing with them. Past the edge
  only the selected picture's knob and grips (crop mode's too) take a
  press, and the objects' hit stays on its page.
- A drag from a hole in the selected picture (a clip with a hole) fell
  through, started an area selection and unselected it. The selected
  picture's frame is its own, as before.
- Image pick: a drag or double-click from a link let the picked picture
  go before ruling 5, and does again; the link's click still picks none.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-04 19:37:47 +01:00
alehelandClaude Opus 5.5 caf364670f fix(ui): Delete on a selected added picture deletes it alone
`refactor(ui): crop mode is a hit of its picture` moved the picture's Delete to the app's key handling, which
runs before the page view, so its edit applied before added content read
the keys. Added content's selection mirrors the picture's when the
picture is added content (`sync_image_selection`), and once the picture
was gone that index named the next added item on the page: added
content's own Delete, seeing the same key press, deleted it too.

The picture's Delete consumes the key, and drops the mirrored selection
with the picture's.

Found in review.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-04 19:37:47 +01:00
alehelandClaude Opus 5.5 f592fe332a fix(ui): a right-click goes to what its tool reaches, and the menu follows it
Found in review of the right-clicks 4b routes:

- With Edit text, a right-click on a picture under a link went to the
  link, which Edit text doesn't follow: the page menu opened and the
  picture was unselected. A right-click counts links only for the tools
  that reach them (Select; the Link tool).
- Edit text's paragraphs have no menu, and give way to the picture
  under them (the user's ruling): text over a picture, an OCR'd scan's
  among it, no longer hides the picture's menu.
- With a Prepare field tool, or while a table is set up, Prepare's hit
  leaves fields out, so a right-click on the selected field opened the
  page menu. A right-click reaches fields whatever the field tool.
- In crop mode, a right-click off the crop went to crop mode's whole-page
  hit and unselected every picture. Only one on the picture being
  cropped, its box or its grips is the crop's (#5900's area), which
  opens no menu; elsewhere it goes to what lies there, as without crop
  mode: another picture is selected for its menu.
- Under a held press, the menu was the page's on anything but a link. It
  is the routed owner's when that owner is the one selected (the held
  press leaves the selections alone), the page's otherwise.

`DocView.menu_for` is `pub(in crate::canvas)`.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-04 19:37:47 +01:00
alehelandClaude Opus 5.5 c10f87f673 fix(ui): a comment's gesture whose release the pages missed applies nothing
`fix(ui): a comment's move, resize or reshape ends` ended a comment's move, resize or reshape once the button was
up, and applied it where the pointer then was: when the pages missed
the release (the page scrolled out of range, a tab switch, a tool
switched mid-drag), the comment jumped to wherever the pointer next
showed up over its page, and while the pointer stayed off the pages the
gesture waited for it.

Only a drag that stops on the page applies its gesture now; one that
ends with the button up and no drag stopped there ends with nothing
applied, whether the pointer is on the page or not. The test hovers away
from the move's start, where the jump shows.

Found in review.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-04 19:37:47 +01:00
alehelandClaude Opus 5.5 58fa110d2d fix(ui): a right-button drag on the pages starts nothing a left one does
The pages' presses are the primary button's (`PagePointer.edges`, the
router's `began`), so a right-button drag was a press nobody held, and
every tool that started on egui's `drag_started()`, which counts every
button, started on it: the Rectangle tool drew a rectangle, Prepare's
selection rectangle selected the fields in it, the Link tool opened Link
Properties for a new link, the camera moved its quadrilateral to the page,
and the Select tool selected text. On `main` too.

`PagePointer.drag_started` is a primary drag of a press the pages hold,
started this frame. The page modules read it instead of egui's (comments'
shapes, callout and text box, Prepare, the Link tool, the camera, the text
layer, image pick, and the Edit text group, whose owned presses were
primary already); zoom, crop, Sign area and Redact already asked for the
primary button. The guard refuses a bare `.drag_started()` in a page
module (`NOT_PAGE_DRAGS` lists the widgets of their own: Organize's
thumbnails, the signature pad, the Scan tab), and the router's
`drag_started` is `drag_began`, so the rule reads cleanly.

Tests, one per family, each seen failing with the fix reverted:
`a_right_button_drag_draws_no_rectangle`, `…_selects_no_field`,
`…_draws_no_link`, `…_leaves_the_camera_quadrilateral`,
`…_selects_no_text`; the guard rule against a planted `#[cfg(any())]`
call.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-04 19:37:47 +01:00
alehelandClaude Opus 5.5 3c0ac1f77c test(ui): wait_for_cursor waits with step_until
It hovered fifty times with a 10 ms sleep between, so a busy runner
could run out of tries before the page's text or paragraph boxes
arrived from their worker threads. It now steps frames with
`support::step_until`, as the other waits for background work do,
until the cursor is the one wanted or 30 seconds pass.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-04 19:37:47 +01:00
alehelandClaude Opus 5.5 0378eee687 test(ui): page modules never read the router; the compiler holds it
With the Edit text group, the text layer and link following told what
the press is to their page, only the page view reads the router.

- The router's methods and `DocView.router` are `pub(in crate::canvas)`:
  outside `canvas` the compiler refuses a read or a write, aliases
  included, which the guard's text match could miss. `ROUTER_READERS`
  keeps only the page view's dispatcher (`page_tool_input`).
- Rule (f): no function in a page module is named with "grabs" or
  "owns", which decide for themselves whether a press is theirs.
- CLAUDE.md's "Page presses" rule says so: modules never read the
  router; they are told.

Each rule seen failing against a violation planted in `#[cfg(any())]`
code (a `router.keeps_drag()` read in `content_ui`, a `fn fill_grabs` in
`fill_sign`), and a real router read from `content_ui` no longer
compiles.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-04 19:37:46 +01:00
alehelandClaude Opus 5.5 b3509dc629 fix(ui): a comment's move, resize or reshape ends once its button is up
A comment's gesture ended only on egui's `drag_stopped()`. When the pages
missed its release (the button let go where they didn't see it), the
gesture stayed live: it kept the page's frames from Fill & Sign and the
shape tools, and the next drag that stopped on the page committed it,
taking the comment there.

It now ends, as the other page gestures do, on `drag_stopped()` or once
the primary button is up, where the pointer is.

Two tests planted a live move with the button up to check that a live
move keeps its page's presses (`main`'s
`active_comment_gesture_keeps_highlighted_link_click` and 4a's
`a_fill_and_sign_click_places_nothing_while_a_mark_is_moved`). That
state now ends at once, so both hold the press through the planted move
instead: the intent stands, and each still fails with the live-move
guard taken out.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-04 19:37:46 +01:00
alehelandClaude Opus 5.5 85fbcc436b refactor(ui): the text layer, image pick and link following are told the press
The text layer asked the router whether the press's owner kept its drag,
link following asked it which link held the press, and the Link tool
started a new link from a press any link held, since the router kept a
declined drag's capture.

- `PageRouter::drag_started`: a drag the owner declines (text markup;
  with the Link tool, a link) is nobody's once it starts, on the page it
  began on. The Link tool draws a new link only from a drag nobody
  holds.
- `PageInput` carries the press (`PagePress`) and whether its drag is the
  page's text's (`text_drag`): the text layer and link following read
  them, and `PageRouter::owner` goes. Only the page view reads the
  router now.
- Image pick acts on a press nobody holds: a link's click follows the
  link only, and picks no picture under it (the user's ruling).
- The I-beam drops over a link only where a press would go to it, the
  top hit under the pointer (the user's ruling): the tools that select a
  link's text show it there.
- `PageText::glyph_at` is the one test for the text under a point, for
  the text layer and Redact's boxes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-04 19:37:46 +01:00
alehelandClaude Opus 5.5 a9f592fd64 fix(ui): Edit text's drags end when its input is blocked
Edit text ignores input while a dialog, the palette, another window or
another tab has it. Only a drag of the objects selected together ended
then; a paragraph's move or rewrap, a picture's move, resize, turn or
crop and added content's move waited, and once the input came back with
the button up they landed wherever the pointer was.

While Edit text's input is blocked, `DocView::cancel_edit_text_gestures`
abandons them all, as the objects' already was.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-04 19:37:46 +01:00
alehelandClaude Opus 5.5 607635c157 fix(ui): the page menu is the menu of what the right-click went to
The page's menu chose its entries from the selections, in a fixed order:
a selected Prepare field's menu, then a link's, then the picture's, then
a comment's. A selection left from before outranked what was just
right-clicked, so with a field selected, a right-click on the empty page
(or on a comment) opened the field's menu.

The right-click remembers what it went to (`DocView.menu_for`, from the
routed hits), and the menu shows that owner's entries when it has a
menu, or else the page's (the user's ruling). Add text's right-click is
the page's, as before; while a press is held only a link takes its menu.
The picture menu's flag and its geometric test go with it.

#5900's menu check (no image menu over the picture being cropped, #5835)
is the routed owner's too: a right-click that went to the crop (its
picture, box or grips) opens no menu, and `crop_contains_point` and
`crop_controls_contain`, its second point test, go.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-04 19:37:46 +01:00
alehelandClaude Opus 5.5 cbcf79acc7 refactor(ui): tell Edit text, Add text, pictures and added content whether the press is theirs
The Edit text group still asked the router for itself and passed answers
from one module to the next: `others_own_pointer`, `text_used`,
`over_source`, `source_blocked` and the pictures' `allow_interaction`
decided who acted, so what the pointer happened to be over at the release,
or an earlier module's answer, could take a click from the module its
press was on.

- Paragraphs (`ParagraphCx`), pictures (`ImageCx`) and added content
  (`ContentCx`) are told the press (`PagePress`) and Edit text's gate (its
  input blocked by a dialog, the palette, another window or tab, as
  before), and act on their own presses; the paragraph outline comes from
  the top hit under the pointer (`hovered`), hidden while the objects
  selected together or added content being moved hold the page. The flags
  go, and the three modules no longer read the router.
- Add text acts on the paragraph its press was on, or the one under the
  pointer; its click on a paragraph refuses a blocked draft and finishes
  the one being typed in the paragraph's own act.
- Clicks act where they were pressed (the user's ruling): a paragraph
  opens though the button came up just past its box, added text is
  selected, and opened for typing, by the item its press was on, and Add
  text's new box starts where it was pressed (a press beside a paragraph
  released inside it starts a box; it placed nothing).
- The picture's grips and rotate knob lose their egui widgets: a drag
  takes what the press was on. A press past a page's edge is the page's
  that has something under it there (the knob of a picture filling its
  page), so the knob still turns the picture there.
- Edit text's right-click goes to what lies on top under it, as every
  tool's does (ruling C): a picture is selected for its menu through
  `edit_text_ui::picture_context`, and a comment over a paragraph or a
  picture gets its own menu. The page view's own picture scan goes.
- #5900's part of that scan (a right-click on the picture being cropped,
  its box or its grips keeps crop mode, over a picture on top of it too)
  is the crop hit's: `CropPart::Cut`, the picture outside the box kept,
  shown or cut away, joins the grips and the box, so a right-click there
  keeps crop mode. Its menu check stays for now (the menu commit takes
  it). Test: `a_right_click_on_the_part_a_crop_cuts_away_keeps_crop_mode`,
  seen failing without `Cut`.
- With the Edit panel open, the tools that don't pick added content up
  still select added text by its own test at the pointer, as before: a
  press-time hit would take the press from the stamps and the other tools
  that place on any press.
- `main`'s press-handler check guards nothing now, and goes; rule (e)
  (`ROUTER_READERS`) keeps the modules from reading the router again.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-04 19:37:46 +01:00
alehelandClaude Opus 5.5 6789b25956 refactor(ui): a press with Shift or ⌘ in Edit text is the objects', by their hit
`object_ui` took a Shift- or ⌘-press before anyone else, whoever owned it,
through its own inventory test at the press point, and declined a plain
press where that test found an object the router didn't (just outside a
picture's edge), so such a press started nothing at all.

- The page view reads the press's modifiers from `PagePointer`
  (`modifiers`: those held at the frame's first primary press). With
  Edit text, a press that adds (Shift, Ctrl or ⌘) is the objects' whole:
  `object_ui::modified_hit` gives `Objects { Toggle(target) }` for the
  object under it, or none (an area selection that adds), `Held` while
  text being typed is open, and `Refused` on a page whose objects can't
  be selected together. Only the press asks: hover and cursors are as
  before.
- `object_ui` is told what the press is to its page (`PagePress`) and acts
  on its own parts; a press nobody holds starts the area selection. The
  inventory test and its decline go, and so does `blocked_page`: the held
  press keeps the editor open until the button is up through its capture.
- A plain press beside a picture, within the 2 px the objects are found
  in but outside the picture, now starts an area selection.
- The guard: `object_ui::input` no longer reads the router.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-04 19:37:46 +01:00
alehelandClaude Opus 5.5 97094a1c86 refactor(ui): crop mode is a hit of its picture, and the picture's keys are the app's
Crop mode held every press on its page through a hit with no point test,
so its claim won the cursor on every visible page (its Default arrow over
the next page's paragraphs), and its own grip test at the drag's start and
its cursor test used different reaches (10 and 8 px).

- `edit_text_ui::crop_hit` says what of the picture being cropped lies
  under a point: a grip of the box kept, the box itself, or the rest of
  its page (`PicturePart::Crop`, on `Layer::Editor`), and the hand over
  its Done, Cancel and Remove Crop controls, past the page's edge too.
  A drag takes what its press was on (`ImageCx.press`), and the cursor is
  the hit's: one reach for both.
- Delete and Backspace on a selected picture, and crop mode's Enter and
  Escape, move to the app's key handling (`edit_text_ui::picture_keys`),
  which no key reaches under a dialog. Delete works wherever the pointer
  is (the user's ruling: before, it did nothing over a paragraph).
  Escape while a button is down is still the press's: it cancels a crop
  drag, and crop mode stays.

- #5900's `crop_controls_contain` (the right-click check for #5835)
  measures with `crop_frames` and the grips' reach, so the crop's frame
  and reach have one source; its `crop_bounds` was `crop_frames`' frame.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-04 19:37:46 +01:00
FredApps 60894af44d Merge pull request #6125 from KenM76/feat/bookmark-clipboard
feat(ui): cut, copy and paste bookmark subtrees (#3994)
2026-11-04 19:33:28 +01:00
Andrew 2afd62082b Merge remote-tracking branch 'origin/main' into fix/fill-sign-quick-bar-controls 2026-11-04 11:22:09 -07:00
FredApps 9070431ed3 Merge pull request #5250 from KenM76/fix/cleared-max-len-stays-cleared
fix(forms): clearing a field's length limit leaves it with none, not its parent field's
2026-11-04 19:08:06 +01:00
KenM76andClaude Opus 5.5 34426ebd9e Merge origin/main (3788af11) into feat/unreadable-object-report
Keeps both new cos document tests side by side.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SqmHYx8FiWM5PcsoiErgp9
2026-11-04 13:05:10 -05:00
FredApps 3788af11d3 Merge pull request #5808 from KenM76/feat/3d-embed
M12: add a 3D model (U3D or PRC) to a page with a poster (#1297)
2026-11-04 18:53:39 +01:00
FredApps 83cbf8f89f Merge pull request #5476 from KenM76/fix/xfa-check-button-width
M12: an XFA check box without a width is as wide as its box and caption
2026-11-04 18:53:31 +01:00
FredApps 5bf6b63910 Merge pull request #5487 from KenM76/fix/file-dialog-extension-case
fix(ui): list X.PDF in file pickers on Linux and the BSDs (#5481)
2026-11-04 18:53:24 +01:00
FredApps 0429b23ea9 Merge storytold/main into feat/prc-render 2026-11-04 18:51:49 +01:00
FredApps 8d7eb74ff7 Merge remote-tracking branch 'upstream/main' into pk-6125m 2026-11-04 18:50:24 +01:00
FredApps 7d17aea92c Merge pull request #5786 from KenM76/feat/prc-reader
M12: PRC reader crate (`pdfcraft-prc`) (#1297)
2026-11-04 18:50:09 +01:00