Skip to content

fix(input): allow unconstrained selection translation on pannable boards and sync drag anchor - #425

Merged
devmobasa merged 2 commits into
devmobasa:mainfrom
gsmith-alvarez:fix/unconstrained-panned-selection-move
Oct 26, 2026
Merged

devmobasa merged 2 commits into
devmobasa:mainfrom
gsmith-alvarez:fix/unconstrained-panned-selection-move

Conversation

@gsmith-alvarez

Copy link
Copy Markdown
Contributor

Follow-up to #423.

PR #423 addressed the coordinate unit mismatch by clamping against visible_canvas_rect. However, on solid boards where panning is enabled, the canvas is unbounded. Constraining selection translation to the visible viewport created an artificial "invisible wall" around the monitor edges. Furthermore, when motion was clamped to zero delta, last_x/last_y stopped advancing, causing a stale reference anchor that made selections jump when the pointer moved in an unblocked direction.

This change:

  1. Skips viewport clamping on boards where panning is enabled (pan_enabled && !board_is_transparent), allowing free selection movement across the canvas.
  2. Retains screen bounds clamping on the fixed transparent overlay.
  3. Always advances last_x/last_y on pointer motion so the drag anchor never becomes stale or jumps.

Validation:

  • Added regression tests in src/input/state/tests/transform.rs:
    • moving_a_selection_on_a_panned_board_follows_the_pointer
    • moving_a_selection_on_a_panned_board_can_move_freely_across_canvas
    • moving_a_selection_on_transparent_board_clamps_to_screen
  • Verified unit tests: cargo test --lib moving_a_selection (3 passed, 0 failed).
  • Code formatting: cargo fmt --check clean.
  • Whitespace check: git diff --check clean.

(Note: Prepared with AI assistance.)

@gsmith-alvarez
gsmith-alvarez marked this pull request as draft October 25, 2026 15:48
@gsmith-alvarez

Copy link
Copy Markdown
Contributor Author

Give it more time since issues keep arrive. Will keep running for longer to confirm stability

…rds and sync drag anchor

- Pannable boards (solid boards) have unbounded canvases; do not clamp selection
  translation against the viewport rectangle.
- Retain clamping on transparent overlay boards where the canvas is bound to the output.
- Always advance MovingSelection last_x/last_y on pointer motion so dragging against
  a boundary does not leave a stale reference anchor that causes jumping.
@gsmith-alvarez
gsmith-alvarez force-pushed the fix/unconstrained-panned-selection-move branch from c7b9d17 to f9b8622 Compare October 25, 2026 16:00
@devmobasa
devmobasa marked this pull request as ready for review October 25, 2026 16:45
Keep the press as the drag anchor until the pointer leaves the click
radius, so the first drag motion is not lost. After that the anchor
follows the pointer on every motion, including blocked ones, so
reversing at an edge moves the selection at once.

Apply coordinate limits on every board. Pannable boards still move
freely, but each translated coordinate and the painted bounds now stay
in the i32 range. Before, a nudge near i32::MAX wrapped in release
builds: the line jumped to span the whole coordinate range and was
saved that way. Debug builds panicked instead.

On a fixed canvas (the transparent overlay, or a board with panning
disabled), a selection that already crosses an edge, or lies outside
the canvas, can no longer move further out, and it is never pulled
back. Before, any nudge snapped it inside, up to thousands of pixels.

Align the move-to-edge actions with the visible canvas, including pan
and zoom, instead of the screen origin. A target further away than
i32::MAX is reached in several steps that record one undo entry.

Combine selection bounds in i64. Shape bounds are clamped to the i32
range, so a shape at the coordinate limit is measured on a copy moved
toward the origin; the limits and edge actions then see its full
stroke padding. A selection whose painted bounds end past i32::MAX
gets no selection Rect, because handle hit-testing and other selection
code compute x + width in i32. Its chrome then marks full damage, so
the halos of its other members are still repainted. The Properties
panel uses the same bounds, the text resize handle is omitted when it
would end past i32::MAX, and handle hit-testing compares pointer
distances in i64.

Test changes:
- nudge_selection_clamps_right_and_bottom_edges starts at (87, 87).
  At (90, 90) the stroke padding already crossed the canvas edge, and
  the test passed only because the old clamp pulled the shape back.
- moving_a_selection_on_transparent_board_clamps_to_screen checks the
  exact landing edge. It also passed when nothing moved.

The coordinate guard and the view-relative edge targets are adapted
from devmobasa#424.
@devmobasa

Copy link
Copy Markdown
Owner

Thanks for the fix and the clear report. I pushed one commit on top of yours (da68d15) rather than asking you for another round.

What it adds:

  • A drag now catches up once it passes the click threshold, so the first few pixels of a drag aren't lost.
  • Coordinate limits on every board. Pannable boards still move freely, but a move near the end of the coordinate range can no longer wrap a shape's coordinates.
  • On the transparent overlay, or a board with panning disabled, a selection that already sticks out past the screen edge is no longer snapped back. Reversing at an edge moves it at once.
  • Home, End, Ctrl+Home and Ctrl+End line up with the visible area after panning and zooming.

Could you try it on your niri setup before we merge? From this branch:

On a panned (and zoomed) blackboard:

  1. Draw a few strokes, select them and drag. They should follow the pointer from the start, with no jump.
  2. Nudge them with the arrow keys.
  3. Press Home, End, Ctrl+Home and Ctrl+End. The selection should line up with the edges of what you see.
  4. Undo after a drag. One undo should reverse the whole drag.

On the transparent overlay, drag a shape against a screen edge, keep pushing, then drag back. It should stop at the edge and come back as soon as you reverse.

If anything looks off, a short clip like the one in #422 helps a lot.

@gsmith-alvarez

Copy link
Copy Markdown
Contributor Author

Yeah I'll test it now.

@gsmith-alvarez

Copy link
Copy Markdown
Contributor Author

Works just fine to me

@devmobasa
devmobasa merged commit abb03bb into devmobasa:main Oct 26, 2026
3 checks passed
@gsmith-alvarez
gsmith-alvarez deleted the fix/unconstrained-panned-selection-move branch October 26, 2026 08:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants