16 Commits
Author SHA1 Message Date
mahmatias 206d73e898 test(keymap): the aspect-lock test reads the tool's own lock
The integration brought #1864: a fresh crop keeps the raw develop
aspect untouched, and the first toggle only records "free" for the
tool (lib.rs interceptor), so reading develop.crop.aspect never
changes on an untouched photo. The lock the row controls is the
effective one - crop_tool_aspect(), which now starts engaged on
"original" - and that is what the test asserts, like main's own
crop_keys. The feature behavior was already right; only the test's
observation point was stale.

1139/1139 ui-egui lib; fmt clean.
2026-10-22 10:05:28 -03:00
mahmatias acbf7c70f2 fix(shortcuts): exempt contextual pairs in the ui-conflicts test 2026-10-22 10:05:28 -03:00
mahmatias d1ccdc4775 docs(parity): LR-CROP-ASPECT notes crop.lockAspect as its own A row 2026-10-22 10:05:28 -03:00
mahmatias 0d60d824a0 feat(shortcuts): Lock Aspect Ratio becomes a row on A
crop.lockAspect is declared like any other command (label Lock Aspect Ratio, default A, both keymap profiles) and lists in Help - Keyboard Shortcuts, editable like the rest. The hidden remapping that turned view.visualizeSpots into crop.aspect while the Crop panel was open is gone: the two now share A as a contextual pair - Visualize Spots fires everywhere except under the Crop panel, where the aspect lock takes the key - so A no longer steals the Remove panel from Crop or runs both commands at once (the old remap plus a direct binding would double-toggle). tests_keymap 28/28.
2026-10-22 10:01:47 -03:00
mahmatias 77b0204331 fix(guided): the press position survives press+release in one frame
egui clears `press_origin` on the release, so a slow frame that swallows
press, move and release into one batch reports `primary_pressed` with no
origin: the gesture fell back to the release position and a real drag
wrote nothing (its length check saw a zero-length stub). The gate now
reads the primary press back from the frame's own events before that
fallback — the press decides what it means, wherever the batch ended.
2026-10-21 14:13:18 -03:00
mahmatias c19265dee0 fix(guided): the press point, not the current pointer, owns the gesture
`contains_pointer` reads where the pointer is NOW; a slow frame can
deliver the press on a menu and the move off it in the same pass, and
the gate would then pass with the saved press origin under the menu.
`layer_id_at(press_origin) == resp.layer_id` asks which layer owns the
press itself: the menu's area (or any modal) wins there and the guide
under it stays untouched. The navigator check stays for its own widget.
2026-10-21 14:13:18 -03:00
mahmatias f2e97d39fe fix(guided): the loupe's press is layer-aware, not just inside its rect
`primary_pressed` plus `resp.rect.contains` reads the raw pointer, so
anything floating above the photo — the context menu, a dropdown, a
dialog — also started a guide gesture under it. The gate now asks
`resp.contains_pointer()`, which the hit test keeps honest about
covering widgets; the navigator check stays. Two tests press on a menu
over a line and over an endpoint: nothing is selected, moved or drawn.
2026-10-21 14:13:18 -03:00
mahmatias b1c607d7ac fix(guided): the primary button and the canvas only; the press point is the gesture's own
- a secondary/middle press or one on the navigator panned the photo but
  also selected or drew a guide: the gestures take the primary button and
  skip the navigator's rect
- egui forgets the press origin by the release, so the endpoint drag
  compared against the guide's old position: a press that landed within
  the grab radius and never moved wrote a no-op guide; the gesture now
  carries the press point itself
- a selection left behind by a Delete past the last guide clears with the
  photo/tool check in crop_overlay
2026-10-21 14:13:17 -03:00
mahmatias ca26c4046a fix(guided): a stale selected index does not fire an empty guides edit; docs: un-mojibake the dashes 2026-10-21 14:13:17 -03:00
mahmatias 331e0d2103 style: fmt (blank line before point_segment_dist) 2026-10-21 14:13:17 -03:00
mahmatias aa0f9b92a7 docs(parity): LR-GUIDED-SELECT/DELETE rows land as done (press semantics) 2026-10-21 14:13:17 -03:00
mahmatias a22c496d03 feat(guided): guides start on the press and their endpoints can be dragged
A press starts what it means right away from the pointer's press point: on an endpoint (within 7 px) it drags that endpoint, committing one geometry.guides edit on release (the guide must stay at least 0.02 long; a press without a real move only selects, so a click never leaves a no-op undo entry); on a line (within 6 px) it selects the guide (a press on the selected one deselects); anywhere else it starts a new guide from the press point itself instead of where egui's drag threshold was crossed, leaving nothing selected. The endpoint being dragged is drawn bright while the pointer moves. tests_guided_guides 8/8.
2026-10-21 14:11:08 -03:00
mahmatias 7635b38c36 feat(guided): select and delete one Guided Upright guide
A click near a guide selects it (white, thicker, larger endpoints); drawing a new guide or clicking away clears the selection, and so does leaving the photo or the tool. Delete / Backspace with the tool open removes only the selected guide (geometry.guides minus its index, one undo step); with none selected it removes nothing — the photo itself is never deleted while Guided Upright is open. selected_guide is UI-only (serde skip). Coverage: tests_guided_guides 5/5.
2026-10-21 14:11:08 -03:00
mahmatias 4c4f4ca215 Contributors: add mahmatias 2026-10-19 14:02:35 -03:00
mahmatias 54c6505191 test(slideshow): drop the template cache after the hand-written bad files
The folder's mtime may not move from the save's listing to the list that follows (same clock tick on a fast machine), so the stale cache hid the bad files and problems came back empty - deterministic on a warm build. The test drops the cache as its own wild.json case already did (and as templates_changed documents).
2026-10-19 14:02:35 -03:00
mahmatias e3d2654bd2 fix(tests): make Windows path spellings match folder-tree widget ids
The folder tree writes FolderNode.path with forward slashes on every platform, but tests_folder_drop built its widget ids from to_string_lossy, which gives backslashes on Windows: the 8 tests never found their rows there. row_path() normalizes the way tests_sync already does. Same class of fix in tests_export (path comparison) and an unused-import guard in catalog's staging tests (the module's only test is unix-only).
2026-10-19 14:02:29 -03:00