Let the crop be held to a ratio while it is dragged
A photographer cropping for a print, a phone wallpaper or a 16:9 frame is not choosing four edges — they are choosing one edge and a known shape. Free-dragging every corner made them do that arithmetic by eye on every drag, and get it slightly wrong. The panel now offers Free, Original, 1:1, 3:2, 4:3 and 16:9, with a Portrait switch for the ones that have two orientations. Original follows the frame rather than naming a number, so it stays right on the next photograph from another body and after a quarter turn. **The ratio is of output pixels, and the rect is not.** `CropRect` is stored in fractions of a frame that is not itself square, so holding a shape needs the frame's size — `ratio * height / width` of the frame. Skipping that gives a "1:1" crop that is square only on a square photograph, which is the one case nobody would test on, so the conversion lives in `CropRect::with_aspect` where it is explained and pinned by a test that asserts the fractions are *not* equal. Two decisions worth recording: The reshaped rect **grows** onto the ratio rather than shrinking onto it, then scales down only as far as the frame's edge demands. Fitting inside instead makes a one-axis drag do nothing at all — the other axis clamps the first straight back, and the handle simply refuses to move. The overlay now reports **which corner the drag is holding**, because reshaping onto a ratio has to know which corner is nailed down and only the handle that took the press knows that. A move reports no corner and keeps its shape: reshaping about a centre would pull an over-moved rect smaller instead of sliding it along the edge. The lock lives with the window rather than the session. A `DevelopSession` is per image, and cropping a set of frames to one shape is exactly when the lock earns its place. It is not an edit and reaches no sidecar — what is saved is the rectangle it produced. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
+17
-2
@@ -37,8 +37,16 @@ export component CropOverlay inherits Rectangle {
|
||||
in property <float> crop-w: 1.0;
|
||||
in property <float> crop-h: 1.0;
|
||||
|
||||
/// A dragged crop rect, in the same fractions.
|
||||
callback crop-changed(float, float, float, float);
|
||||
/// A dragged crop rect — `x`, `y`, `width`, `height`, then the corner the
|
||||
/// drag is holding as a `0`/`1` pair, or `-1, -1` where the whole rect is
|
||||
/// being moved and its shape must not be touched.
|
||||
///
|
||||
/// The corner is what an aspect lock needs and cannot infer: reshaping a
|
||||
/// rect onto a ratio has to know which of its corners is nailed down, and
|
||||
/// only the handle that took the press knows that. It is reported as the
|
||||
/// held corner rather than as the fixed one because that is what is
|
||||
/// written here — Rust takes the opposite corner.
|
||||
callback crop-changed(float, float, float, float, float, float);
|
||||
|
||||
|
||||
property <length> rx: root.crop-x * self.width;
|
||||
@@ -153,6 +161,11 @@ export component CropOverlay inherits Rectangle {
|
||||
self.start-y + self.fraction-y(self.mouse-y) - self.from-y,
|
||||
root.crop-w,
|
||||
root.crop-h,
|
||||
// No corner: a move keeps the shape it already has,
|
||||
// and an over-drag should slide along the edge rather
|
||||
// than be reshaped back inside.
|
||||
-1,
|
||||
-1,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -232,6 +245,8 @@ export component CropOverlay inherits Rectangle {
|
||||
corner.hy == 0 ? self.oy + self.dy : self.oy,
|
||||
corner.hx == 0 ? self.ow - self.dx : self.ow + self.dx,
|
||||
corner.hy == 0 ? self.oh - self.dy : self.oh + self.dy,
|
||||
corner.hx,
|
||||
corner.hy,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user