Hold one key to see the photograph before you touched it

FR-DEV-7 asks for the current edit against the unedited original and nothing
implemented it. What the develop view had was history navigation, which
*changes* the edit rather than previewing against it — so the only way to
look was to undo, look, and redo, and that puts two real steps on the stack
at exactly the moment a photographer suspects they have overcooked a frame
and is least sure of what they are doing.

Holding the "Before" button, or backslash, renders the graph with every
adjustment stripped and hands it straight back afterwards: the same
suspend-render-restore shape the crop overlay already uses to show an
uncropped frame and an export uses to suspend the zoom. Nothing is recorded,
no rows are re-synced, and the photograph is still modified when the key
comes up — the panel goes on describing the edit the photographer has,
because only the canvas is answering a question.

The framing deliberately stays on. A held comparison is a question about
tone and colour, and re-cropping the canvas under someone's thumb would move
the detail they are comparing; worse, the zoom is a rectangle of the *framed*
image, so dropping the crop at 4× would quietly show a different part of the
photograph rather than the same part unedited. What the crop took away is
already compared in Compose, which shows the whole frame.

Not a split screen: that halves the working image on the tablet this column
was sized for, and the comparison photographers describe making is a flick
back and forth rather than two pictures side by side. Press-and-hold is one
gesture on a finger and on a mouse, which is what FR-DEV-3b's mapping wants,
and it has no mode to be stranded in — the button reports both edges, so a
press the system cancels puts the original down too.
This commit is contained in:
2026-09-06 19:01:51 +02:00
parent 9b674a88d8
commit 2584b9ecbc
5 changed files with 291 additions and 48 deletions
+44
View File
@@ -370,6 +370,14 @@ fn reset_view_state(window: &AppWindow) {
// previous image's history.
window.set_can_undo(false);
window.set_can_redo(false);
// TRACES: FR-DEV-7
// And the comparison goes down with them. Unlike the inspection point
// below it, this is not a way of looking at a folder: it is a question
// about one photograph's edit, asked while holding something. A key
// release that arrived after the next frame had opened would put the view
// back anyway, but a press that opens the next photograph — the roll is a
// tap away — must not carry a held original onto it.
window.set_showing_original(false);
// TRACES: FR-DSP-7
// Emptied rather than left standing: the previous photograph's histogram
// beside the next one's filename is a confident, precise lie, and the gap
@@ -1821,11 +1829,19 @@ pub fn run(paths: Vec<PathBuf>) -> Result<()> {
h = (h / 2).max(1);
}
// TRACES: FR-DEV-7
// Three renders of one graph, chosen here because this is the one
// path every frame takes — so a comparison held while a slider is
// still settling shows the original at full resolution too, rather
// than reverting the moment anything else asks for a redraw.
//
// Crop mode shows the whole frame, or the area being cropped away
// would not be on screen for the handles to drag across. The
// overlay draws the rect on top of it.
let rendered = if window.get_view_mode() == ViewMode::Crop {
s.render_uncropped(w, h).map(|(image, _, _)| image)
} else if window.get_showing_original() {
s.render_original(w, h)
} else {
s.render(w, h)
};
@@ -2789,6 +2805,34 @@ pub fn run(paths: Vec<PathBuf>) -> Result<()> {
}
});
}
{
// TRACES: FR-DEV-7
// Holding the comparison, and letting it go.
//
// **No rows are synced and no history is touched**, and both absences
// are the feature. The panel is describing the edit the photographer
// still has; only the canvas changes, and it changes back. This is the
// whole difference between a comparison and the undo-look-redo that
// had to stand in for one — that put two real steps on the stack at
// the moment somebody was least sure of what they were doing.
//
// A full frame rather than a draft: comparing a half-resolution
// original against a sharp edit would show a difference the edit does
// not have, which is the one thing this must not do.
let weak = window.as_weak();
let render_now = render_now.clone();
window.on_compare_original(move |on| {
let Some(w) = weak.upgrade() else { return };
// A held key repeats. Answering a repeat with a re-render would
// spend a full-resolution pass per keystroke to arrive back at the
// frame already on screen.
if w.get_showing_original() == on {
return;
}
w.set_showing_original(on);
render_now(&w, false);
});
}
// TRACES: FR-DEV-5 | FR-DEV-7
// Clicking a row. Arriving six steps away costs what arriving from one