feat: screen capture workflow - #349
Merged
Merged
Conversation
Refine the interactive region Review bar, selection badge, crosshair, and cursor feedback while keeping Copy, Save, Both, Board, and annotated-export controls.
`collapsible_match` fires on clippy 1.95 (the toolchain CI pins) but not on 1.97, so `-D warnings` failed there while passing locally. Clippy's own suggestion is a match guard, which would be wrong here: a guard that evaluates false stops matching and falls through to the permissive catch-all, turning a fail-closed argv gate into a no-op for exactly the arguments it exists to reject. Name the condition instead — the arm body is no longer a lone `if`, so the lint has nothing to collapse and the semantics are untouched.
Review could move and nudge a rectangle but never resize one, so a crop that was a few pixels short had to be drawn again. Four corners plus four edge midpoints now sit on the reviewed rectangle: a corner moves two edges, a midpoint moves one, and the opposite edges stay put. Reuses the vocabulary already in the tree — `SelectionHandle`'s eight variants and the resize cursors the canvas selection handles use — rather than inventing a second one. The frame drops its corner arms in Review so they cannot fight the corner grips for the same pixels. Three details worth stating: - A grip records the offset between the pointer and the edges it owns when it is grabbed. Grips are placed on the display rectangle, which rounds outward from the image rectangle, so without the offset a click with no motion would re-round that position and shift an edge by a pixel at a fractional scale. - Hit testing takes the nearest grip, not the first. On a rectangle small enough that every grab target covers all of it, first-match would leave only the top-left corner reachable — growable up and left but never down and right. - Grips claim at most a quarter of each side, so a small rectangle always keeps a draggable centre. Chip and grab target scale as one, so what is drawn stays what is grabbable. Pointer, touch and stylus all press through `begin_region_selection`, so the grip check sits in the shared event rather than in any one handler.
The Review toggle said "Include drawings in exports" and Board ignored it. The
original reasoning was that pasting a composited crop onto the board it came
from bakes a second copy of those annotations — true, but the toggle is the
control for exactly that, so turning it off is the answer rather than
overriding it per destination.
Board could not simply be let through: the composed path deliberately skips the
event-loop crop, so the Board arm's raw pixels would have been absent. Both
destinations now take their PNG from one `region_render_job`, so what Copy
writes and what Board pastes can only differ by the toggle — a construction
guarantee rather than a convention. `include_drawings_for_submit` is gone
instead of relaxed: once Board stopped being special it was an identity
function, a named place that no longer encoded a decision.
`RegionRenderSource::{Annotated, Raw}` replaces two independent Options, so the
impossible pairs are not representable and the mapping failure is a real arm
rather than a panic.
Board placement now maps the authoritative image rectangle instead of the
picker's outward-rounded display rectangle. Composition uses that same exact
world rectangle, so the pasted image lands where the annotations were drawn
rather than stretched by a quantization the chrome introduced; each edge rounds
once, to nearest, instead of compounding two outward roundings that could only
ever grow the crop. A rectangle whose edges collapse onto one integer still has
to be widened to a whole board pixel, which is the one documented exception to
the half-pixel bound.
A Board placement that cannot map now cancels with a toast instead of returning
silently, which would have left Review painted over a reservation nothing could
complete.
Searching the palette for "capture selection" turned up nothing, even though the action has a default chord and a help-overlay row. Palette membership is a curated list, and the capture entries had drifted out of step with the help overlay's: four actions were in help but not the palette, and `capture_full_screen` was on no surface at all — palette, help and toolbar all false — so a bound action was unreachable unless you already knew its chord. The rule applied here, and stated in the contract list: an action a user can bind must be runnable without knowing its shortcut. The help overlay is left alone; it is curated for density and is already long.
Interactive capture shipped unbound, so the feature was invisible unless a user went looking for it, while Ctrl+Shift+C ran the one-step region copy. Interactive is a strict superset of that: crop, then Ctrl+C in Review reaches the same clipboard result from the same chord, and Save, Both, Board, resize and nudge become reachable from a key people already press. `capture_region_interactive` now defaults to Ctrl+Shift+C and `capture_clipboard_selection` ships unbound. The cost is honest: a drag that used to copy on release now stops in Review and needs one more keystroke. BREAKING CHANGE: Ctrl+Shift+C opens the interactive region picker instead of copying the selection immediately. Configuration is sparse, so anyone who wrote `capture_clipboard_selection` explicitly keeps it — the new compiled-in default stands down with a skipped-default notice rather than taking away a shortcut they chose. Everyone on defaults moves. Bind `capture_clipboard_selection` to get the one-step copy back.
Rounding the near edge first and then pushing the far edge out anchors the forced pixel to an already-rounded position, so the two errors compound: `[10.5, 10.75]` placed at `[11, 12]`, 1.25 past its far edge, and the bound approaches 1.5 as the crop narrows. A collapsed axis now takes the unit cell centred on the crop, which holds every edge strictly inside one board pixel — the best achievable, since a one-pixel cell standing in for a sub-pixel crop has an edge up to a pixel away by construction. Two boundary cases failed outright before, each for its own reason: a crop straddling `i32::MAX` overflowed `checked_add(1)` and one at `i32::MIN` rounded its centre below the representable range, though `[MAX - 1, MAX]` and `[MIN, MIN + 1]` were available to both. The cell start is clamped into range instead. Clamping alone would license placing a crop that has run off the range entirely, so both edges are then checked against the bound and the placement is refused rather than misplaced. The exception was also described wrongly. Being under a board pixel across is necessary but not sufficient — position decides too, and `[0, 2/3]` rounds normally to `[0, 1]` — so the docs now say "when both rounded edges coincide". The sweep classified collapse by the placed width, which swept ordinary intervals that legitimately round to width one into the loose branch and left the tighter bound untested on the cases that must keep it. It now classifies from the rounded edges and holds collapsed placements strictly under one pixel.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
User-visible behavior
Spaceenters window-selection mode on supported Hyprland and Sway environments.Dtoggles annotations for the current reviewed export.