CodeRabbit's findings on #6243, each checked against the code:
- A double-click on the objects selected together took its target from
the hits at the release, so a release just off the paragraph pressed
opened nothing. The router keeps what lay on top at the press with the
objects aside (`under_objects`), as every owner acts where its press was.
- A drag first seen on another page left the picked picture picked: that
page is told `Elsewhere`, and the picture's test no longer ran there.
- Delete with a button held removed the item, and the press held then named
the next one. Delete waits for the button to come up, for pictures and
added content.
- A page just off the screen is still run for what lies near it, so a
picture's keys acted there unseen. They ask whether the page is on screen.
- Add text's drags end while its input is blocked, as Edit text's do.
- With the page gaps hidden, a Shift-click on the row two pages share
selected on the first page and the second cleared it. A press another
page holds leaves the selection alone.
Tests, each seen failing with its fix reverted:
`a_double_click_on_a_grouped_paragraph_released_just_off_it_opens_it`,
`a_drag_first_seen_on_the_next_page_lets_the_picked_picture_go`,
`delete_waits_for_the_button_to_come_up` (each half),
`a_selected_pictures_keys_wait_for_its_page_to_be_on_screen` (its
continuous case), `a_paragraph_drag_ends_when_the_window_loses_focus` (Add
text), `a_shift_click_where_two_pages_touch_keeps_what_it_selected`,
`a_press_counts_the_modifiers_of_its_own_event`.
`add_text_keeps_a_changed_paragraph_and_a_draft_when_it_moves_on` pins that a
click on the page applies the open paragraph before a new box starts, so
neither edit can take the other's place; seen failing with the draft's edit
dropped.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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>
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>
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>
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>
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>
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>
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>
`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>
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>
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>
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>
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>
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>
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>
Two of CodeRabbit's findings on #5803. A right-click off the pages
cleared only the menu's anchor and kept the selected comment, so the
menu that opened was that comment's, not the current page's. A
right-click on a page's empty part deselects it, so one that no page
takes (`PageFrame.right_clicked`) now does the same. A selected Prepare
field keeps its menu off the pages, as it does on a page's empty part;
the comment there says so.
Where pages touch, the first page takes a right-click on the row they
share and anchors the menu there, but a picture on the second page under
it still opens its menu. Paste from that menu centred the image on page
1's point, which on page 2 is at its foot. The image menu now uses the
anchor only on the picture's own page, and otherwise pastes as Ctrl+V
does.
Tests, each seen failing with its fix reverted:
`a_right_click_between_the_pages_opens_the_page_menu_not_the_selected_comments`,
`paste_from_a_picture_menu_where_two_pages_touch_keeps_off_the_first_pages_point`.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Found in review (CodeRabbit): the last fix located a camera click by the pointer, which can have
moved on by the end of the release's frame. A click pressed on page 2 and released on page 1,
with the pointer back on page 2 by then, moved the quadrilateral to page 2. `PagePointer` keeps
each release's position, so `PagePointer::released` gives where the click came up, and the click
is located there.
Test: `a_camera_click_released_off_its_page_moves_nothing`, seen failing without the fix.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Found in review (CodeRabbit): with the camera tool, a press nobody holds on a page without the
quadrilateral moves it there, but a click was located by its press's origin, which egui has
cleared by the release frame. So only a drag moved it, and a click did nothing. This was so on
`main` too. A click is now located where it came up; `PagePress::Free` already says its press
began on this page.
Test: `a_camera_click_on_another_page_moves_the_quadrilateral_there`, seen failing without the
fix.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Found in review:
- **A right-click off the pages.** Between the pages or beside one, no page took the
right-click, but the page menu still opened over the page view, on the last anchor: Delete
page, Paste and Copy Image acted on a page right-clicked long before. This was so on `main`
too. The anchor is now cleared on every right-click before the pages set it, so off the pages
the menu acts on the current page.
- **The guard** took a file as a page module only by marks a router read doesn't need. A file
that reads `.router.` is one too, so its router reads are checked.
- **Docs.** egui ends a press's drag when any button is released, not when a second goes down.
`link_ui::hit` takes the tip from the link it found rather than looking it up again.
Tests: a right-click between the pages clears the anchor, seen failing without the fix. A
planted router read in an unlisted file fails the guard.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Found in review:
- **Fill & Sign during a mark's move.** `main` placed no Fill & Sign mark while a comment's move,
resize or reshape was live on the page, whoever held the press. That guard was lost: with a
move left over (its release never seen), the next click placed a new mark. A live gesture on
the page now counts as over a mark again (`comments::moving_on`, which the comments' own
dispatch uses too).
- **The guard** missed the router's and the page view's hits called by path
(`PageRouter::owner(&view.router, i)`), and its doc said the `.at(` it matches was confined to
`page_input.rs`.
- `measure_ui::Clicks` derived traits nothing uses.
Tests: a Fill & Sign click while a mark's move is live places nothing, seen failing without the
fix. A planted router read by path fails the guard.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Found in review:
- **A right-click where two pages touch.** With the page gaps hidden, a right-click on the row
two pages share ran on both: the first page selected its comment, the second unselected it,
and the second page's anchor for the menu stood. A right-click is now the first page's, as a
press has been since the last fix. This was so on `main` too.
- **The guard** matched one line at a time, so a call rustfmt splits across lines
(`view` / `.router` / `.owner(i)`) got past it. A continued line is now read with the one it
continues. It also refuses a hit test imported under a name that isn't a hit test's
(`use …::hit as under`), which the checks by name would miss.
- **Docs.** Links still take a right-click while the primary button is held, as before, and when
Escape comes in a press's own frame every page is `Elsewhere`, not `Free`.
Tests: a stamp clicked where two pages touch lands on the first, a click pressed on one page and
released on the next places nothing, a right-click where two pages touch is the first page's,
Prepare keeps its selection on a click that began off the page, and the Note tool starts no note
on added text with the Edit panel open. Each was seen failing with its fix, or the rule it pins,
reverted. A planted split router read and a planted aliased hit test fail the guard.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Found in review:
- **A double-click another tool took finished a polygon.** Round 5 kept commenting tools off a
press another tool had taken, but a polygon, polyline or cloud finishes on a double-click or
Enter whoever has the press. With Prepare open, a double-click on a field opened its properties
and committed the polygon being clicked out. Added text opened for editing did the same with
the Edit panel open. The commenting tools now skip such a frame entirely, as `main`'s consumed
chain did. The comments' own presses and a click's unselecting still run.
- **The menu's anchor after Escape.** While a press Escape cancelled is held, the page's tools
are skipped, and a right-click left the page menu on the page right-clicked before. It now
anchors where it is, as every other right-click does.
- **The guard.** It now lists who asks the page view's hits at a point (`PageHits::at` and
`context_at`), so a new place in `page_input.rs` can't test a point again. It takes a file
that uses the comments' page context (`PageCx`) for a page module. Its doc of the point tests
it doesn't list is now true.
- **Docs and visibility.** True docs for `PagePress::Free`, where a press is off the pages, and
the camera's hit. `link_ui::screen_rect` is private.
Tests: a polygon left unfinished by a double-click on a Prepare field, and a right-click after
Escape anchoring the menu. Each was seen failing without its fix. A planted ask of the page
view's hits, and a planted unlisted file using `PageCx`, each fail the guard.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Found in review:
- **Comments acted on presses another tool had taken.** Comments run every frame now, and a
commenting tool acted on any press nobody held, so with Prepare open a Rectangle drag drew a
rectangle as well as Prepare's selection rectangle. Added content, with the Edit panel open,
could likewise open a note composer under the Note tool. `main` skipped comments when another
module took the frame. They are now told (`taken`), and their drawing and placing tools leave
such a press alone. A click there still unselects.
- **The page menu's anchor went stale.** A right-click while the primary button was held skipped
the call that also anchors the page menu, so Delete page, Paste and Copy Image acted on the page
right-clicked before. Every right-click on a page now anchors the menu there, whoever takes it,
and only the selections wait for the release. That includes the right-clicks Add text, Edit
text, the Link tool and a field tool take, which used to keep the previous anchor.
- **Edit text's right-clicks.** Edit text took right-clicks on added content too. It now takes
those on its paragraphs, pictures and the objects selected together, and comments see a
right-click on added text, as before.
- **Camera corners.** A camera corner at the page's edge showed its grab cursor past the edge,
where a press is no page's. Its hit now stops at the page, as a link's does.
- One source for a comment's layer, dead code in Add text's right-click, and true docs for
`PagePress::Elsewhere` and the "Page presses" rule.
Tests: a shape-tool drag with Prepare open, a right-click with the button held on another page,
a right-click on added text with Edit text, the menu anchored by an Edit text right-click, and a
camera corner at the page's edge. Each was seen failing with its fix reverted.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Found in review:
- **Right-clicks during a press.** A comment being moved kept its selection only while its
gesture state was live, so a gesture left over (a release the pages never saw) blocked every
later right-click. Comments and Prepare now leave their selection alone while the primary
button is held. egui ends the press's own interaction (and its drag) when another button goes
down, so the button is what tells. A touch's long press, which egui reports as a right-click
with the finger still down, still opens its menu.
- **A click that began beside the page** unselected the selected comment, though the Link tool and
Prepare now leave theirs alone for such a click. Comments do the same.
- **The guard** took a file as a page module only if it named `PagePointer`; a file using
`PageToolContext`, `PagePress` or the router's hits or owners is one too. Its message about
tooltips and release checks now points at the page view's own hits, and its doc of the router's
readers names link following.
Tests: a right-click with a gesture left over, a click that began beside the page, and a long
press on a comment. Each was seen failing with its fix
reverted. A planted page-router name in a module the guard didn't list fails the guard.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Found in review:
- **The Link tool's click** acted on any press: with Prepare open, a click on a field also
unselected the selected link, and a click that began off the page did too. It now acts only on
a press on a link, or one nobody holds.
- **A right-click while a comment is moved** selected the comment under it mid-drag, though the
release still moved the first. Comments now keep their selection during a move, resize or
reshape, as Prepare does.
- The hits under the pointer before the tools act are taken only on the pointer's page, and the
Link tool's right-click reuses them.
- The router has one source for the press's page (`Capture` no longer carries its own).
- The guard lists which functions may ask which comment lies under a point (`comment_at`); the
guard finds hit tests by name, and its docs say so.
- Docs made true: what `PagePress::Mine` promises, what `tool_input` gates, and that a dialog does
not cancel the pages' press (only Escape and automation's cancel do).
Tests: the two fixes, and ruling 1 for added text (a click on it unselects the comment), each seen
failing with its fix reverted; the drawing-tool right-click test now checks the comment's menu.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Routing right-clicks changed a few more cases beyond the rulings, found in review:
- **The Link tool.** A right-click on a link also unselected the selected comment and moved the
page menu's anchor; the Link tool used to take it whole. On a document it can't change, its
right-click on a note over a link opened the plain page menu instead of the note's. Now the Link
tool's right-click is what its press there would take, on a document it can change, and on a
link it leaves comments alone.
- **The camera.** A corner, on the handle layer, took right-clicks from a comment under it,
though it has no menu. Corners are no longer right-click targets.
- **The Link tool's hand** showed in the 2 px margin past the page's edge, where a press is no
page's. `link_ui::hit` now finds nothing off the page.
Docs made true: what a comment's press is (`comments::page_input`), what reaches the free-press
gate (`page_tool_input`), and when every page is `PagePress::Free`.
Tests: those three, and two that pin right-clicks kept as before: Edit text's on a paragraph
under a comment, and a Prepare field tool's. Each seen failing with its fix reverted.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
egui reports a drag once the pointer has moved a few points from the press. A press near a page's
bottom edge, flicked onto the next page in one frame, is seen as a drag only with the pointer on
the next page. Redact (and the area Highlight), the Link tool and Prepare returned before their
drag start unless the pointer was on their own page, and the next page is `Elsewhere`, so the
press drew nothing anywhere. (On main the next page took it, with the box's start on the page
before.)
They now start the gesture from where the press began on their own page, as zoom, snapshot, crop
and Sign area already did, so the box, link rectangle, marquee, field drawn or field moved belongs
to the page the press began on. Tests: one per tool, each seen failing with the fix reverted.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The page's hover (the top hit under the pointer) was only worked out when nothing was drawn over
the pages, so with the palette open a field beside it lost its tooltip and its hover outline,
and comments their outline. The palette keeps the page's cursor and tips away, which is what
that gate is for; hover now ignores it, as the outlines and the field tooltip did before.
The hits under the pointer were also asked up to four times a page each frame, each pass running
every module's hit test: for a click's release, for Fill & Sign's preview, for a right-click, and
for the cursor. A click's release, Fill & Sign's preview and a right-click's tool checks now share
one pass, taken before the tools act and only on frames that need it. A right-click's own pass
(comments by `context_hit`) stays, and the cursor and hover keep theirs, after the tools act.
A unit test pins that cancelling the pages' gestures lets go of a camera corner. The kittest for
Escape mid corner drag passes on `main` too, because Escape leaves the camera tool first.
Tests: `a_fields_tooltip_shows_beside_the_open_palette`,
`cancelling_pointer_gestures_lets_go_of_a_camera_corner`; each seen failing with its fix reverted.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Routing right-clicks by what lies on top under the pointer changed three cases beyond the
rulings:
- **Prepare.** A right-click while a field was dragged selected the field under the pointer, and
the release then moved that one. Prepare used to ignore right-clicks during a drag; it does
again (`prepare::context` returns while a grab is held).
- **The Link tool.** A note over a link took the right-click, though the Link tool's press there
is the link's. The Link tool's right-click on a link is the link's again, whatever lies over it.
- **Add text.** Comments took right-clicks away from paragraphs and added items. Add text used to
take every right-click on a page it can change; it does again.
Tests: those three, and two that pin ruling 6's right-click half with the Select tool: no link
menu on a link with no action, and none on a form field over a link. Each was seen failing with
its fix reverted.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Forms and Prepare read the router themselves, and forms tested the pointer twice more: for a
field's tooltip, and for whether a click came up over the widget it was pressed on. Following a
link tested the pointer again too.
Both are now told the page's `PagePress`. Prepare's Select tool draws a selection rectangle, or
unselects, only on a press nobody holds, and a field tool draws only on such a press. Whether a
click came up over what its press began on is answered once, from the hits under the pointer
(`released_over`), for fields and for following links. The field tooltip (`forms_ui::tooltip`)
and the field hover outline come from the page's hover, the top hit under the pointer.
`PageHits::hits` is now the only function that calls a hit test, and the press-handler check no
longer lists forms or Prepare.
Behaviour changes: a field's tooltip shows only where a press would take the field, not under
a comment drawn over it (the user's ruling, 2026-10-31); a field's hover outline follows the
same rule, so it shows only with the Select tool, which fills fields.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The tools that act wherever on the page each decided for themselves whether a press was
theirs: Sign area, zoom and snapshot, crop, redact and the stamps asked the router, and Measure,
Fill & Sign, the camera and the Link tool's rectangle acted on any press. Stamp placement lived
inline in the page view.
`tool_input` is now the one gate. Measure, the Stamp tool and custom stamps, Fill & Sign, Sign
area, zoom and snapshot, the camera and crop are each told whether the press is the tool's (it
began on their page and no hit won it), and act only then; their cursors and gestures run as
before. Redact's boxes and the Link tool's rectangle are told the same where they are called.
Stamp placement moves to `stamps_ui::place` and `place_custom`, beside custom stamps. Measure
is told its clicks (`measure_ui::Clicks`), Sign area takes a `PageToolContext`.
The camera's corners are hits (`camera_ui::hit`, `Owner::CameraCorner` on the handle layer), so
a corner's drag is an owned press like any other: it starts on the corner's own press, ends on
`drag_stopped() || !primary_down`, and `cancel_pointer_gestures` drops it. Until now only the
order of two key handlers kept Escape mid-drag from leaving a corner following the pointer:
Escape leaves the camera tool before the pages see it. The kittest for Escape mid-drag can't
fail with that order; a unit test of the cancel comes later in this series.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Comments ran last in the page view's chain of `||`, so only when no earlier module had taken the
frame, and asked the router themselves (`grabs`, `fill_grabs`, `draw_grabs`), with a hit test of
their own for hover. A link, a field or added text taking the frame first hid a comment's
gesture end, its Escape and the click that unselects it.
Comments now run on every frame and are told the page's `PagePress`:
- a press on a comment (its body, a handle or a point) goes to `select_input` with the part,
with the Select tool, a shape tool (the selected shape's handles) or Fill & Sign (its marks);
- the drawing tools act only on a press nobody holds (`Gestures::free`);
- a click on anything but a comment leaves comments unselected.
`grabs`, `fill_grabs`, `draw_grabs` and `cancelled_drag` (with the raw button read in `keys` it
needed) are gone; `grabs_points` is `reaches_points`. Fill & Sign leaves the press to a mark
when the press is someone's, or, with no button down, when a mark is the top hit under the
pointer. The page's hover is that top hit (`PageInput.hover`), and the comments' hover outline
follows it, so it no longer shows under a field or added text that would take a press.
Behaviour change (the user's ruling, 2026-10-31): a click on a form field, or on added text,
leaves the selected comment unselected, as a click on a link or the page already did.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Each right-click handler tested the pointer itself, and the chain's order decided which ran:
comments only when no earlier module took the frame, Prepare by its own widget scan.
A right-click now goes to what lies on top under the pointer (`PageHits::context_at`), by the
layer ranking a press uses, with two differences. Comments count with every tool, as a
comment's menu opens whatever tool is active (`comments::context_hit`). A highlight over a link
is the highlight's: a left click there follows the link, a right-click opens the highlight's
menu. On every right-click the page's menu is anchored at the pointer, and the comment it is
on is selected, or none (`comments::context`); a Prepare field is selected (`prepare::context`);
links take theirs from the same answer. Edit text's own paragraphs and pictures, and a Prepare
field tool, keep their right-clicks as before.
Behaviour change (the user's ruling, 2026-10-31): a right-click on a highlight over a link opens
the highlight's menu, not the link's.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Three link tests disagreed. The Select tool's hand and click (`link_hit`) took the topmost link
the renderer lists, with no margin, by its place in that list. The Link tool's selection and
Select's right-click took the bottom one of every link the engine lists, 2 px around each, by
`/Annots` index. Comments had a fourth (`on_link`).
Now `link_ui::hit` is the one test, and `Owner::Link` carries the `/Annots` index:
- the Link tool finds every link the engine lists, 2 px around each, and takes the topmost; a
drag from a link still draws a new one (the hit declines the drag);
- every other tool finds the links the renderer can follow, with no margin (so Select shows no
hand over a link with no action, as before), and takes the topmost;
- following a link looks its target up by that index;
- `comments::hit` is told whether a link is under the point.
The Link tool is told the link its press is on, and the one a right-click is on, instead of
testing the pointer itself. A right-click goes to the top hit under the pointer, so with the
Select tool a right-click on a note over a link selects the note and opens its menu, and one
just beside a link no longer opens the link's.
Behaviour changes (the user's rulings, 2026-10-31): the Link tool takes the topmost of stacked
links; Select's right-click has no margin; a right-click on a note over a link is the note's.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A click acted on what its press was on wherever the button came up: a press on a link, a push
button, a signature field or a list box that slipped off it before the release (still a click to
egui, within 6 px) followed the link, ran the button's action, opened signing or picked a list
box's option. On main a click went to what lay under its release. Now it needs both: the
link's or the fields' hit test at the release point must give what the press was on, as a button
pressed and released off itself does nothing. Check boxes and radio buttons already did so, by
their overlay's click-outside test.
New tests a_press_on_a_link_released_off_it_follows_nothing and
a_press_on_a_button_released_off_it_runs_nothing, seen failing with this commit's source
reverted; the check box test shares their slipping_click helper. From CodeRabbit's second review
of #5300.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
From a review of this branch:
- Escape mid-drag with a text markup tool (Highlight, Underline, Strikeout, Squiggly, Replace
Text) or Redact over text left the half-made selection on the page: the cancel took the Escape
that would have cleared it. It is dropped now. The marks made from a selection at its end
(after the page tools, which the release blocking did not reach) also wait for a cancelled
press's button; egui ends its own drag on Escape without a drag stop, so they were not made
in practice, but nothing but egui stopped them.
- The open paragraph's frame took the press above and below the text only: its sides still gave
edge grips (a closed paragraph's rewrap handles) on the Editor layer, over the frame. Edges now
belong to closed paragraphs only.
- A press in the frame right after a release kept the last press's owner until a page claimed
it, so a drag from the margin beside a page could move the comment just clicked. A new press
now drops the last owner before the pages give it theirs.
- A release and a new press in one frame no longer leave the new press cancelled.
- Added content is picked up with the tools that act on it (Select, Add text, Edit text), not with
every tool while Edit a PDF is open.
- The layer docs in page_cursor.rs say what lies on each layer now.
New tests an_open_paragraphs_frame_takes_the_box_beside_its_text and
a_drag_from_beside_the_page_right_after_a_click_leaves_the_comment_alone (the release and the
next press in one frame) fail on the previous commit. escape_cancels_a_highlight_being_dragged_over_text
(with a control: the drag highlights without Escape) passes there too, for the reason above, and
stays as a guard.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Edit text's paragraph edges were tested twice: by edit_text_ui for the cursor, on the page's
paragraphs, and by object_ui for the press, on its own object inventory (grabs_edge). Where the
two inventories disagree, the resize arrow shows and a press starts an invisible area selection
instead (#2276, the review's step-3 probe). The open paragraph's frame showed the Move cursor
4 px out and took the press 6 px out.
Each of these parts now has one hit test, in the page router's table, and acts only on the
press it was captured on:
- edit_text_ui::hit: a paragraph's edges (Handle), its body (Text; Editor for the open one).
- edit_text_ui::picture_hit and picture_handle_hit: a picture's body on the Text layer, asked
before the paragraphs, so text on top of artwork takes the press; the selected picture's
corners and rotate knob on Handle, asked after them, so they win over text.
- object_ui::hit: the objects selected together (Placed) and the open paragraph's frame
(Handle), with one reach (FRAME_REACH, 6 px) for the cursor and the press. An area selection
starts only where nobody's hit claims the press.
- content_ui::hit: added text and pictures (Placed; the selected one's corners on Handle), over
form fields; Add text starts a new box only where nobody's hit claims the press.
image_owns_pointer and content_ui::select_grabs go, with the edge test object_ui kept a copy of
(grabs_edge). The page's hits move into canvas::PageHits.
Un-ignores a_paragraph_edge_resizes_wherever_it_shows_the_resize_cursor: it passes on main
already (the inventories agree for its paragraph since the probe was written), so it stays as a
guard rather than as proof. New test an_open_paragraphs_frame_shows_move_wherever_a_press_takes_the_box
fails on the previous commit (the cursor is Default there).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Forms: forms_ui::hit is the fields' only hit test (cursor and press). The press opens a text
field (#2213) and its click acts on the field the press was on, from the page router, instead
of the field under the release point: a press on one check box released over the one beside it
ticked the second. Now it ticks neither, as a button pressed and released off itself does
nothing. Forms no longer wait on comments::select_grabs: a comment that moves (a note, a shape,
a signature, a Fill & Sign mark) hits on the Placed layer, over form fields, so it still takes a
press over a field (a signature can be dragged off the field it covers), and text markup stays
on the Comment layer, under them, so a click on a box under a highlight ticks the box.
select_grabs goes.
Prepare Form: prepare::hit (the selected field's corner handles, then a field, on Placed so a
field being moved stays over the comments as before) gives the cursor, and the drag, click and
double click act on what the press was on; a press held by something else is not Prepare's.
New tests: a_press_on_one_check_box_released_over_another_ticks_neither (fails without this
commit: the second box is ticked) and a_check_box_under_a_highlight_takes_the_click (fails with
markup on the Placed layer).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Sign area, marquee zoom and snapshot, crop and redaction boxes, and the stamps, act where
nothing drawn over the page holds the press (the page router has no owner for it), rather than
wherever the press lands on the page. Fill & Sign already asks the router (fill_grabs).
Their drags start on the primary button and end with its release, however egui reported it:
its drag stop, or the button found up. They started on any button, so a right-drag drew a
signature rectangle and opened the signing dialog (and drew a crop or a marquee), and the end
waited for a pointer position, so a drag whose release came without one never ended.
New test a_right_drag_draws_no_signature_rectangle, seen failing with the drag started on any
button.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The page router (canvas/page_router.rs): a page module answers "what of mine is under this
point?" in one hit test, which gives a Hit (an owner, a layer, a cursor, a tip). On the frame of
a press, the hits at the press point decide who it belongs to, by PR 2's table (the highest
layer the tool reaches), and the router holds that capture until the button is up and its
release has been seen; automation's cancel and Escape drop it. The pointer's hits claim the
cursor and the tip, after the tools that are not converted yet, as before.
Comments: comments::hit is the module's only hit test, with each tool's filter (Select: point
handles, resize handles, then the comment; Fill & Sign: the same over its marks only; shape
tools: the selected comment's handles only). The Select tool's drag, click and double click act
on the comment and part the press was captured on, instead of testing the press origin and the
release point again; fill_grabs and select_grabs ask the router while the button is down. The
topmost comment is the one drawn last (/Annots order), not the last in inspection's top-edge
order: over stacked comments the tip named the top one while a click selected the one
underneath. Text markup declines the drag, so a click on a highlight selects it and a drag
across it still selects the text.
Links: the link hover is a hit (hand and target), and a click follows the link its press was
on. Text selection starts unless the press is held by something that keeps its drag (a link, a
comment that moves); it tested for a link under the pointer at the moment egui called the press
a drag, so a drag from text onto a link selected nothing.
Un-ignores a_click_on_stacked_comments_selects_the_one_drawn_on_top; new test
a_drag_from_text_onto_a_link_selects_the_text. Both fail with their fix reverted (inspection
order for the topmost comment; the link test at the pointer).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Escape cancelled a comment gesture, Prepare's marquee, measuring and the camera tool, each in its
own module; with the Sign area, crop, marquee zoom, a redaction box, the Link tool's rectangle,
a paragraph or picture drag, added content, an object move or a text selection it did nothing,
and the release then drew, placed or opened what the drag had begun (the step-4 probe: Escape
mid-rectangle still opened the signing dialog).
document_area now handles Escape once, before the pages: while the pages hold a press, it drops
every pointer gesture (DocView::cancel_pointer_gestures, as automation's cancel does) and marks
the press cancelled. Until the button is up the page tools take no input from it, so its
release neither clicks (a stamp, a Fill & Sign mark) nor ends a drag. Escape without a press
keeps its meanings (close the editor, clear the selection, back to the Select tool).
Un-ignores escape_cancels_a_signature_rectangle. Two new tests: Escape mid-press keeps the
release from placing a stamp, and Escape mid-drag abandons a crop rectangle. All three fail
with the cancel taken out; the stamp test also fails with the cancel kept and the release let
through.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Every page module set egui's cursor itself and the last write of a frame won, so the
order of document_area's per-page chain decided the cursor, not what a press there does.
The link hover loop ran last and showed the hand over any link for every tool but Fill &
Sign, though only the Select tool follows links: a click with the stamp tool placed a
stamp, a drag with the rectangle tool drew, and in Edit text a drag from linked words
moved the paragraph, all under the hand. The text layer ran after the comments and showed
the I-beam over a movable comment lying on text, which a drag there moves.
Page modules now claim the cursor instead (src/page_cursor.rs): a layer, an icon and
optionally a tip. The layers are the review's priority table, Editor > Handle > Placed >
Field > Comment > Link > Text > tool area, with Drag on top for a drag in progress, whose
owner names the cursor until the release. document_area resolves the claims once per
frame, after the pages, and calls set_cursor_icon once: the claim on the highest layer
the active tool reaches wins. Links count only for the Select tool (follow) and the Link
tool (edit), comments only for the Select tool; the other layers are claimed only by the
modules of the tools that act on them. The claims go into a per-frame collector on
DocView, which every page module already takes, so the calls in the dispatch block keep
their arguments (camera, content and redact lose a `ui` they took only for the cursor).
A link's tip goes with its claim, so it shows only where the link wins: no longer with a
stamp, drawing or other tool that does not follow links. A comment's tip is a description
instead (comments::describe), shown with any tool beside that tool's cursor unless the
winning claim has a tip of its own: Acrobat shows a comment's tooltip with every tool
(observed with Select, Hand, Add comment, Highlight, Rectangle and Stamp). It keeps the old
exceptions (Fill & Sign, freehand drawing for #429, a comment gesture in progress) and
comments. A signed field's validation badge (#1895) says its verdict the same way, with any
tool, ranked below a comment's description as it was below the comment's tip; the topmost
of overlapping badges still speaks.
FieldPointer::Over existed only to keep the text layer from overwriting a field's cursor
(#2099); the Field layer above Text does that now, so forms_ui::page_input returns whether
a field owns the press. Who acts on a press is unchanged (step 3 of the router).
The picture's rotate knob claims too: Grab as a handle, Grabbing as a drag while it turns,
which dragging_the_rotate_knob_turns_a_page_image now checks.
The contains_pointer checks #2755 put before the cursor in content_ui, edit_text_ui,
forms_ui and the text layer go: the pages' pointer has no position where the mode bar or a
side panel covers a page, so nothing is claimed there, and #2755's tests pass unchanged.
During a press the pages hold, those four now keep their cursor over the chrome too, as
the other page modules and a text selection being dragged already did.
Un-ignores the four step-2 probes in tests/it/pointer.rs, each seen failing on the
previous commit at its cursor assertion, after its press assertions passed. A new test,
also seen failing there: a link's tip shows only with its hand. Another pins a comment's
tip with every tool beside its cursor, and its exceptions; it was seen failing with comment
tips tied to the cursor's winner instead, which shows them with the Select tool only. In
tests/it/signing.rs, a signed field's badge says its verdict with the Select tool and with a
stamp; it fails when the badge is left out of the resolver, as resolving after the page
loop would otherwise do. A new ignored probe pins a step-3 bug: over stacked comments the
tip names the one drawn on top, but a click selects the one underneath, because
PageCx::hit takes the last in inspection's top-edge order.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Record successful PdfCraft web application check
* E21: bound startup requests and validate font and license inputs
* E21: separate pending control completion and gesture regression phases
* M-egui037: enforce control admission and per-family font notices
* M-egui037: qualify capture fixes and document migration behavior
* egui-037: identify current and historical qualification results
* refactor(ui): side panels on craft-ui task panes and the shared rail
The Tools pane and the open side panel are docked craft-ui task panes
(craft_ui::panes::PaneHost, Columns policy, no title bars, not movable),
and the rail is craft_ui::panes::Rail with the page navigation cluster
as its foot. On the right, outermost first: the rail, Tools when
Preferences > Tools panel side is Right, the side panel, the page.
Read mode uses the same panes without Tools; All tools full view still
covers them. Floating, tab groups and drag-in are gone with docking.rs.
- Widths are resizable within the old limits and saved under a new
side_panels preference (version 1) with the Tools side and open state.
The old docking value is read once as plain JSON and dropped on save.
- ui.dock becomes ui.panel {panel: tools|side, open, width};
ui.dock.reset resets the side panels ("Reset side panels").
- F4 shows or hides the side panel (reopening the last one) and
Shift+F4 the Tools panel, as View menu commands.
- craft-ui pinned to e9630ae7 (craft-libs#309).
* fix(ui): side panels clippy lint and the dragged-width test's grab offset
* chore(deps): pin craft-ui at 7c42807, whose pane resize edges work over the page
* chore(deps): pin craft-ui at craft-libs main ea4c823, with panes::Rail
The page pointer has the pointer only where egui has the pages on top, and egui knows what
is drawn over them from the layers it met in the frame before. Dialogs are drawn after the
pages, so on the frame one opens egui has not met its layer yet. For that frame the pages
kept the pointer, and a press that landed then was theirs: a link's tip showed over the
dialog, and a click placed a stamp or followed a link under it. main's page_covered had
kept the link's tip and click off the page while a dialog was open, from a hand-kept list.
PagePointer::read now also takes whether a dialog is open: PdfCraftApp::modal_open, the
list the page press and the edge scroll already check, the Unlock prompt included. With one
open the pages see no pointer and no press, except a drag they already have, which goes on
to its release. The palette is not a dialog and the page beside it keeps its tools, so it
is left to egui's layers, from the frame after it opens.
Tests: tests/it/pointer.rs hovers a link and opens the Unlock prompt (no tip in that
frame), and clicks with the Stamp tool in the frame the prompt opens (no stamp). A
page_pointer unit test hides the pointer and a click under a dialog, and keeps a drag the
pages have until its release. With the fix reverted, all three fail.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A click on a check box or radio button focuses it, so Tab, Space and the arrows reach it
(#2223). The page hands the click to the field, and the field overlay toggles the box in
the same frame unless the click landed elsewhere. That check read hover_pos, which is None
on the frame egui reports a tap: egui-winit sends PointerGone with every touch release,
and winit reports Windows pen input as touch. So a finger or pen tap counted as a click
away. The focus closed and the toggle was dropped: a tap left a check box unticked and
unfocused, and a tap on a radio button selected nothing. The check now uses the overlay's
clicked_outside, which reads interact_pos, as the other field editors do.
Tests: touch_tap_ticks_a_check_box runs again. tests/it/editor_taps.rs taps a focused
check box and the other button of a focused radio group, each with a mouse click as the
control. Each checks that the focus stays and the tap toggles, and for the radio group that
the arrows still move within it. With the fix reverted, the three tap tests fail and the
controls pass.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The page view had no single reading of the pointer. About twenty page modules each
read egui's raw state (hover_pos, latest_pos, interact_pos, press_origin) and tested it
against an unclipped page rectangle. That state knows nothing of what is drawn over the
pages, and hover_pos is None on the frame a finger or a Windows pen lifts: egui-winit
sends PointerGone with every touch release, and winit reports Windows pen input as
touch. So a tap placed no stamp, followed no link and ticked no check box. A touch drag
of a comment never committed, and the next drag anywhere on the page moved the comment.
The Stamp crosshair showed on the command palette, on the quick bar and on the chrome
over a page scrolled under it, a link's tip floated over the Unlock prompt, and a
double-click on a dialog's backdrop selected the word under it.
canvas::document_area now reads one PagePointer per frame from the pages' content
widget (step 1 of the page pointer router in the cursor-handling review):
- pos: interact_pos, which keeps the position through a touch release, only while egui
has the pages under the pointer with nothing over them (contains_pointer, and the top
layer there is the pages', as the closed#2626 did) or while the pages hold a press.
- origin: where the held press began, also on the frame that brings both the press and
its release. This replaces the text layer's raw-event fallback (#2100).
- edges: the frame's primary presses and releases on the pages, in order.
It reaches the page modules through comments::PageCx and as an argument: the stamp
blocks, text layer, page press and link and comment hover in canvas.rs; comments and the
signature drag preview; forms and Prepare a form; Fill & Sign and the Sign area; crop,
marquee zoom, snapshot, camera and measure; redact and the Link tool; added content,
Edit text, images and objects. page_covered, a hand-kept list of what covers the pages
that missed the Unlock prompt, is gone. The pages' hover tip is click-through, as a
tooltip is, so a quick move onto it does not take the pointer off the link under it.
Tests: tests/it/support/input.rs sends pointer input in the frames the platform delivers
it in (a touch tap and drag, a click in one frame, a double-click). kittest otherwise
runs one frame per event, so the suite never saw a touch release. tests/it/pointer.rs
holds the review's probes and #2626's layer tests. With the fix reverted, the
tap (stamp, link, check box), touch drag, palette, quick bar, chrome, Unlock tip and
dialog double-click tests fail, and the mouse-click and one-frame-click controls pass.
The tip test fails with the tip interactable, and each page_pointer unit test fails
under a mutation of the part it pins. The probes for later steps stay ignored: the
link hand and the I-beam over other tools' targets (step 2), paragraph edges (step 3)
and Escape mid-drag (step 4). touch_tap_ticks_a_check_box is ignored until the
check box focus fix that follows: since #2223 a tap on a check box counts as a click away
from its focus.
tests/it/comments.rs: the multiline markup hover test (#3541) hovered a point below the
window on a page rotated 270 degrees, and its tip showed only because the hover was
tested against the page's whole rectangle. Its harness now zooms to 100 %, so every
rotation shows the whole page, and the hover helper asserts the point is on screen.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>