feat(regionSelector): Crop implies Rect - auto-swap Freehand on entry

Entering Crop while Freehand is active swaps selection to Rect; the R
key and the Rect/Freehand tabs are inert while Crop is on. Leaving Crop
keeps Rect (no restore); already-Rect swaps are no-ops.
This commit is contained in:
DJ committed 2026-07-04 23:56:46 -04:00
1 parent 0ac5c4fca8
commit 3bbfdbb6bf
4 files changed
+18 -12

No files matched your search

+1 -1
View File
@@ -9,7 +9,7 @@ and this project adheres to [Conventional Commits](https://www.conventionalcommi
### Added
- **Crop Mode** - Press `C` (or the new Instant/Crop toolbar tabs) to switch the region selector into Crop mode: releasing a selection opens an adjustable editor (8 resize handles + interior move, min-size and screen clamping, live size label) instead of capturing immediately; **Enter**/**Space** or the confirm button captures, **Escape** returns to drawing. Works with both selection modes (a circle loop seeds the editor with its bounding box). Works for screenshots and recording alike; configurable via `regionSelector.crop.minSize`/`handleSize`
- **Crop Mode** - Press `C` (or the new Instant/Crop toolbar tabs) to switch the region selector into Crop mode: releasing a selection opens an adjustable editor (8 resize handles + interior move, min-size and screen clamping, live size label) instead of capturing immediately; **Enter**/**Space** or the confirm button captures, **Escape** returns to drawing. Crop implies rectangles: entering it from Freehand auto-swaps to Rect (Freehand is unselectable while Crop is active). Works for screenshots and recording alike; configurable via `regionSelector.crop.minSize`/`handleSize`
- **`R` Hotkey** - Toggles Rect/Freehand selection mode inside the overlay (the "Circle" tab is now labeled **Freehand**; config keys keep their `circle` names)
- **Freehand True-Shape Capture** - Freehand selections now capture only the pixels inside the drawn loop (transparent outside, via an ImageMagick polygon mask). OCR flattens onto white; recording and the crop editor remain rectangular (true-shape applies to Instant-mode freehand only)
- **`regionSelector.dragThreshold` Config Key** - Pixel dead-zone (default `6`) for the region selector's click/drag discriminator; `0` disables it, restoring the previous per-pixel sensitivity (circle mode always uses `0` — every circle gesture is the drawn shape)
+2 -2
View File
@@ -27,7 +27,7 @@ Click and drag to select a rectangular region. Features:
### Freehand Selection
Freehand captures the true drawn shape: the output is cropped to the loop's bounding box and everything outside the loop is transparent. OCR flattens the mask onto white (tesseract dislikes alpha); recording always captures the bounding rectangle (wf-recorder is rectangle-only). In Crop mode the mask is discarded — the crop editor is a rectangle tool, so a freehand seed adjusted there captures the adjusted rect.
Freehand captures the true drawn shape: the output is cropped to the loop's bounding box and everything outside the loop is transparent. OCR flattens the mask onto white (tesseract dislikes alpha); recording always captures the bounding rectangle (wf-recorder is rectangle-only). Freehand is Instant-mode only — entering Crop swaps to rectangle selection.
Used for image search by default. Draw a freeform circle around content:
@@ -55,7 +55,7 @@ By default captures happen instantly when you release the mouse. Press `C` (or u
- `Enter` or `Space` (or the confirm button) captures the adjusted region; `Escape` goes back to drawing
- Works for all actions, including recording; right-click selections still open the editor and route to Edit on confirm
Crop mode is per monitor and always starts off (the overlay opens in Instant mode). Freehand selection works in Crop too — the drawn loop's bounding box seeds the editor. Toggle Rect/Freehand with `R`. Minimum size and handle size are configurable via `regionSelector.crop` in the config.
Crop mode is per monitor and always starts off (the overlay opens in Instant mode). Crop implies rectangle selection: entering Crop while Freehand is active swaps to Rect, and Freehand cannot be selected while Crop is on (toggle Rect/Freehand with `R` in Instant mode). Minimum size and handle size are configurable via `regionSelector.crop` in the config.
## Screenshot Actions
@@ -75,12 +75,11 @@ Toolbar {
}
}
// Selection mode tabs (Rect/Circle) - usable in Crop too (a circle loop seeds the
// editor via its bounding box); inert only while the crop editor is open, same as
// the capture tabs
// Selection mode tabs (Rect/Freehand) - inert while Crop is active (Crop implies
// rectangles; entering Crop from Freehand auto-swaps to Rect)
ToolbarTabBar {
id: tabBar
enabled: !root.cropEditing
enabled: !root.cropActive
opacity: enabled ? 1 : 0.4
tabButtonList: [
{"icon": "activity_zone", "name": Translation.tr("Rect")},
@@ -46,13 +46,17 @@ PanelWindow {
property bool isCropMode: (root.captureMode === RegionSelection.CaptureMode.Crop)
// Swapping capture modes resets the editor and any in-progress drag — never the
// frame or the selection mode. Circle works in Crop too: the drawn loop's bounding
// box seeds the editor. Lives here so both the C key and the toolbar tabs get the
// same behavior.
// frame. Crop implies rectangles: entering Crop from Freehand auto-swaps to Rect
// (and Freehand stays unselectable while Crop is active — R key and tab are inert).
// Leaving Crop does NOT restore Freehand; already-Rect swaps are no-ops. Lives here
// so both the C key and the toolbar tabs get the same behavior.
onCaptureModeChanged: {
root.cropEditing = false;
root.pendingSnipPoints = [];
dragState.reset();
if (root.isCropMode && root.selectionMode === RegionSelection.SelectionMode.Circle) {
root.selectionMode = RegionSelection.SelectionMode.RectCorners;
}
}
// Restore session defaults when a capture shortcut re-triggers while the overlay is
@@ -374,9 +378,10 @@ PanelWindow {
root.captureMode = root.isCropMode
? RegionSelection.CaptureMode.Instant
: RegionSelection.CaptureMode.Crop;
} else if (event.key === Qt.Key_R && event.modifiers === Qt.NoModifier && !dragState.dragging && !root.cropEditing) {
} else if (event.key === Qt.Key_R && event.modifiers === Qt.NoModifier && !dragState.dragging && !root.isCropMode) {
// Rect/Freehand toggle — same guards as C (no mid-drag swaps), plus
// inert while the editor is open, matching the toolbar tab gating
// inert while Crop is active (Crop implies rectangles), matching the
// toolbar tab gating
root.selectionMode = root.selectionMode === RegionSelection.SelectionMode.RectCorners
? RegionSelection.SelectionMode.Circle
: RegionSelection.SelectionMode.RectCorners;
@@ -600,6 +605,8 @@ PanelWindow {
selectionMode: root.selectionMode
captureMode: root.captureMode
onSelectionModeSelected: (mode) => {
// Crop implies rectangles (tab is disabled then too — belt and braces)
if (root.isCropMode && mode === RegionSelection.SelectionMode.Circle) return;
if (root.selectionMode !== mode) root.selectionMode = mode;
}
onCaptureModeSelected: (mode) => {