Skip to content

Improve canvas and gizmos - #64

Merged
TheJoeFin merged 5 commits into
devfrom
issue-35-handle-precision
Aug 2, 2026
Merged

Improve canvas and gizmos#64
TheJoeFin merged 5 commits into
devfrom
issue-35-handle-precision

Conversation

@TheJoeFin

Copy link
Copy Markdown
Owner

PR Classification

Design and usability enhancement for canvas interaction, handle manipulation, and persistent user preferences.

PR Summary

Improves canvas panning and transform handle precision, adds keyboard nudging, and introduces persistent canvas settings. Refines UI feedback and pixel zoom for better user experience.

  • Added CursorHelper for a custom "grabbing" cursor during canvas panning.
  • Enhanced transform handle visuals and interaction, including crosshair overlays, keyboard nudging, and zoom-invariant sizing.
  • Improved PixelPrecisionZoom to magnify handle centers with dynamic detail and crisp rendering.
  • Introduced AppSettingsService and updated MainWindow to persist and apply canvas preferences in JSON.
  • Updated MainWindowViewModel to show context-specific busy messages and refactored handle movement logic.

TheJoeFin and others added 5 commits August 1, 2026 23:17
Issue #35 asks for accurate placement of the perspective bounding box.
Two things got in the way:

The loupe magnified the cursor rather than the handle. Since a handle can
be grabbed anywhere within its bounds, an off-centre grab pointed the
crosshair a few pixels away from where the corner would actually land,
and it kept moving after the handle had been clamped to the image edge.
It now tracks the constrained handle centre while still parking itself
next to the cursor.

The handle itself is an opaque dot sitting on the exact pixel being
aimed at. While dragging, it now becomes a hollow ring with a crosshair
that leaves the centre clear; idle handles keep the filled look. Both
stay a constant size on screen at any zoom.

Also make the loupe magnification adaptive instead of a fixed 6x, which
could be *less* magnified than the canvas on a small image at high zoom,
and render it with NearestNeighbor so magnified pixels stay crisp.

Arrow keys now nudge the last-grabbed handle (1px, Shift 10px,
Ctrl 0.25px) for placement finer than the mouse can manage.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The perspective transform handles already counter-scale against the
canvas zoom, but the crop and local-adjustment rectangles live on the
same canvas and still grew and shrank with it — the complaint issue #35
raises about the transform box applies equally here.

Re-centre each grab handle on the edge or corner it controls (the
margins were off by a pixel), which is what makes counter-scaling about
the handle centre leave it pinned in place at any zoom, then scale the
handles and the outline inversely from UpdateTransformVisualScale.

Resize math is unaffected: ResizableRectangle computes its drag deltas
in canvas coordinates, so only the hit-test area changes.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The canvas bar's busy indicator was a spinner and a hard-coded "Working",
which says nothing about what is being waited on. Issue #35 asks for
feedback on the stage of processing.

Add BusyMessage to the view model and give SetUiForLongTask an optional
message, defaulting to the old label so call sites with nothing more
specific to say need no argument. Pass real labels at the slow
operations: perspective correction, un-warp, tri-fold, grid straighten,
edge correction, crop, resize, object erase, edge detection, capture,
paste, and project open/save.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Middle-drag panning used the four-arrow SizeAll cursor; issue #35 asks
for the "grabbing" state instead.

WPF ships no grab cursor and the project carries no binary assets, so
draw a closed-hand glyph at runtime and pack it as an in-memory .cur.
Construction is wrapped so any failure falls back to SizeAll — a cursor
is not worth breaking panning over.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
"Allow outside" and "Show mini map" reset on every launch. Add a small
JSON-backed settings store next to the recent-project data in
%LocalAppData%\MagickCrop, following the same pattern as
RecentProjectsManager, and seed both toggles from it at startup.

Turning "Allow outside" off also now pulls handles that are already past
the image edge back inside, rather than only affecting the next drag.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@TheJoeFin
TheJoeFin merged commit e142075 into dev Aug 2, 2026
2 checks passed
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.

1 participant