fix(studio): a dust spot is a place on the photo, so the angle carries it too
This commit is contained in:
+31
-13
@@ -1499,20 +1499,30 @@ export function Workspace() {
|
||||
[remember, setAdjustment]
|
||||
);
|
||||
|
||||
// The ROTATE strip and the two mirrors are the only things that move the photo
|
||||
// under the marks already on it, and a mark is a place on the photo, not a
|
||||
// place on the screen: turn the frame and every spot the dust brush laid down
|
||||
// has to turn with it, or the repair slides off its mote and the mote is
|
||||
// uncovered again (shared/utils/orientation.ts). One undo step, like the turn
|
||||
// itself — UNDO hands back the frame AND the marks of the frame before it.
|
||||
// The ROTATE strip, the STRAIGHTEN ruler and the two mirrors are the only
|
||||
// things that move the photo under the marks already on it, and a mark is a
|
||||
// place on the photo, not a place on the screen: move the frame and every spot
|
||||
// the dust brush laid down has to move with it, or the repair slides off its
|
||||
// mote and the mote is uncovered again (shared/utils/orientation.ts). One undo
|
||||
// step, like the move itself — UNDO hands back the frame AND the marks of the
|
||||
// frame before it.
|
||||
// The frame the marks are drawn in is the state above, read through a ref so a
|
||||
// STRAIGHTEN drag reads the angle it handed over last rather than the one the
|
||||
// last render saw — the pointer outruns the render, and a mark carried twice
|
||||
// from the same angle would land short. The reading is taken where the move is
|
||||
// asked for, never inside the update: by the time React runs that, the ref
|
||||
// holds the frame the user has just moved to.
|
||||
const orientRef = useRef<Orientation>({ rot: rotation, straighten, flipH, flipV });
|
||||
orientRef.current = { rot: rotation, straighten, flipH, flipV };
|
||||
const carryMarks = useCallback(
|
||||
(next: Orientation) => {
|
||||
const from = { ...orientRef.current };
|
||||
setRecipe((prev) => ({
|
||||
...prev,
|
||||
adjustments: layMarks(prev.adjustments, { rot: rotation, flipH, flipV }, next, photoDims),
|
||||
adjustments: layMarks(prev.adjustments, from, next, photoDims),
|
||||
}));
|
||||
},
|
||||
[rotation, flipH, flipV, photoDims]
|
||||
[photoDims]
|
||||
);
|
||||
|
||||
// FX's HEAL brush writes the spots the same way a knob writes its value: one
|
||||
@@ -1668,13 +1678,21 @@ export function Workspace() {
|
||||
// dragging the ruler is one undo step instead of one per degree.
|
||||
const setStraightenOnce = useCallback(
|
||||
(v: number) => {
|
||||
const next = Math.max(-180, Math.min(180, Math.round(v)));
|
||||
const from = orientRef.current;
|
||||
if (next === from.straighten) return;
|
||||
if (!sliderEditRef.current) {
|
||||
sliderEditRef.current = true;
|
||||
remember();
|
||||
}
|
||||
setStraighten(Math.max(-180, Math.min(180, Math.round(v))));
|
||||
// The angle is drawn on the photo like the quarter turn is, so the marks go
|
||||
// with it — and the ref moves with them, so the next notch of a drag is a
|
||||
// step from here and not from the last render.
|
||||
carryMarks({ rot: from.rot, straighten: next, flipH: from.flipH, flipV: from.flipV });
|
||||
orientRef.current = { ...from, straighten: next };
|
||||
setStraighten(next);
|
||||
},
|
||||
[remember]
|
||||
[carryMarks, remember]
|
||||
);
|
||||
|
||||
// The mark's box on the photo writes through one door: dragging moves x/y,
|
||||
@@ -2871,7 +2889,7 @@ export function Workspace() {
|
||||
const next = v === 'reset' ? 0 : (Number(v) as 0 | 90 | 180 | 270);
|
||||
// RESET levels the whole frame, angle and mirrors included.
|
||||
const level = v === 'reset';
|
||||
carryMarks({ rot: next, flipH: level ? false : flipH, flipV: level ? false : flipV });
|
||||
carryMarks({ rot: next, straighten: level ? 0 : straighten, flipH: level ? false : flipH, flipV: level ? false : flipV });
|
||||
setRotation(next);
|
||||
if (level) {
|
||||
setStraighten(0);
|
||||
@@ -3779,7 +3797,7 @@ export function Workspace() {
|
||||
active: flipH,
|
||||
onClick: () => {
|
||||
remember();
|
||||
carryMarks({ rot: rotation, flipH: !flipH, flipV });
|
||||
carryMarks({ rot: rotation, straighten, flipH: !flipH, flipV });
|
||||
setFlipH((v) => !v);
|
||||
},
|
||||
},
|
||||
@@ -3789,7 +3807,7 @@ export function Workspace() {
|
||||
active: flipV,
|
||||
onClick: () => {
|
||||
remember();
|
||||
carryMarks({ rot: rotation, flipH, flipV: !flipV });
|
||||
carryMarks({ rot: rotation, straighten, flipH, flipV: !flipV });
|
||||
setFlipV((v) => !v);
|
||||
},
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user