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:
@@ -219,6 +219,24 @@ export component AppWindow inherits Window {
|
||||
callback undo();
|
||||
callback redo();
|
||||
|
||||
// --- before and after (FR-DEV-7) ---
|
||||
|
||||
/// TRACES: FR-DEV-7
|
||||
/// Whether the canvas is currently showing the unedited original.
|
||||
///
|
||||
/// Rust owns it, and the ownership is the point: this is *not* a history
|
||||
/// position and must never become one. Held down, the canvas renders the
|
||||
/// photograph with the adjustments taken off and the framing left on; let
|
||||
/// go, the edit comes back. Nothing is recorded, so a photographer can
|
||||
/// check whether they have overcooked a frame without paying two steps of
|
||||
/// undo for the look.
|
||||
in property <bool> showing-original: false;
|
||||
/// The comparison is being held, or has been let go.
|
||||
///
|
||||
/// Both edges through one callback rather than a press and a release, so
|
||||
/// the two cannot get out of step and strand the view on the original.
|
||||
callback compare-original(bool);
|
||||
|
||||
/// Every step, newest first. Rust owns the order and stamps each row with
|
||||
/// its own position in the stack, so nothing here does arithmetic to turn
|
||||
/// a row back into a step.
|
||||
@@ -2182,11 +2200,30 @@ in property <bool> panel-visible: true;
|
||||
// the canvas is noticed.
|
||||
key-released(event) => {
|
||||
root.shift-held = event.modifiers.shift;
|
||||
// TRACES: FR-DEV-7
|
||||
// Letting go of backslash puts the edit back. The
|
||||
// release has to be handled here and not inferred
|
||||
// from the next press, or a photographer who holds
|
||||
// it and then reaches for a slider would be
|
||||
// adjusting an image they cannot see.
|
||||
if (event.text == "\\") {
|
||||
root.compare-original(false);
|
||||
return accept;
|
||||
}
|
||||
return reject;
|
||||
}
|
||||
|
||||
key-pressed(event) => {
|
||||
root.shift-held = event.modifiers.shift;
|
||||
// TRACES: FR-DEV-7
|
||||
// Hold backslash to see the unedited original.
|
||||
// Rust ignores a repeat that says what it already
|
||||
// knows, so the key repeating under a long look
|
||||
// costs nothing.
|
||||
if (event.text == "\\") {
|
||||
root.compare-original(true);
|
||||
return accept;
|
||||
}
|
||||
// Ctrl+Z and Ctrl+Shift+Z (FR-DEV-5). Both cases
|
||||
// of the letter, because the logical key that
|
||||
// reaches us carries the shift: holding it for
|
||||
@@ -2335,6 +2372,33 @@ in property <bool> panel-visible: true;
|
||||
// frame nobody was looking at the middle of.
|
||||
clicked => { root.inspect-toggled(-1, -1); }
|
||||
}
|
||||
|
||||
// TRACES: FR-DEV-7 | FR-DEV-3b | NFR-A11Y-2
|
||||
// The unedited original, for as long as it is held.
|
||||
//
|
||||
// **A hold rather than a split screen.** A split view
|
||||
// halves the working image, which on the tablet this
|
||||
// column was sized for leaves neither half worth
|
||||
// judging; and the comparison a photographer actually
|
||||
// describes making is a flick back and forth, not two
|
||||
// pictures side by side. A hold is also the cheaper
|
||||
// thing to build: one extra render of a graph that is
|
||||
// already there, against a second canvas that would
|
||||
// have to be laid out, sized and kept in step.
|
||||
//
|
||||
// Press-and-hold is the same gesture with a finger and
|
||||
// with a mouse, which is what FR-DEV-3b's mapping
|
||||
// wants — no long-press timer, no mode, and no way to
|
||||
// be left in it. The keyboard's backslash does the
|
||||
// same thing on both edges; see the focus scope below.
|
||||
Button {
|
||||
text: "Before";
|
||||
enabled: root.adjust-enabled;
|
||||
active: root.showing-original;
|
||||
accessible-checkable: true;
|
||||
accessible-checked: root.showing-original;
|
||||
held(down) => { root.compare-original(down); }
|
||||
}
|
||||
}
|
||||
|
||||
// The photo roll, along the foot of the canvas.
|
||||
|
||||
@@ -68,6 +68,25 @@ export component Button inherits Rectangle {
|
||||
in property <bool> active: false;
|
||||
|
||||
callback clicked();
|
||||
/// TRACES: FR-DEV-7 | FR-UI-3
|
||||
/// The button is down, or is no longer down.
|
||||
///
|
||||
/// Almost every button acts on release and ignores this. A *held* control
|
||||
/// is the exception — "show me the original while I am holding this" — and
|
||||
/// `clicked` describes only the end of that gesture, by which time the
|
||||
/// thing being looked at has gone.
|
||||
///
|
||||
/// Here rather than in a second component because the two are one button
|
||||
/// in every other respect: the same box, the same states, the same 44pt
|
||||
/// target grown around a compact rectangle. A `HoldButton` beside this one
|
||||
/// would be sixty duplicated lines and a second place for the press
|
||||
/// treatment to drift, which is the failure this file's preamble is about.
|
||||
///
|
||||
/// Reported from the pointer rather than from `touch.pressed`, so that a
|
||||
/// press cancelled by the system — a call arriving, a gesture claimed by
|
||||
/// the shell — puts the button up. A held comparison that stuck on would
|
||||
/// leave the photographer editing the original.
|
||||
callback held(bool);
|
||||
|
||||
accessible-role: button;
|
||||
accessible-label: root.text;
|
||||
@@ -115,6 +134,15 @@ export component Button inherits Rectangle {
|
||||
y: (parent.height - self.height) / 2;
|
||||
mouse-cursor: root.enabled ? MouseCursor.pointer : MouseCursor.default;
|
||||
clicked => { root.clicked(); }
|
||||
pointer-event(ev) => {
|
||||
if (ev.kind == PointerEventKind.down) {
|
||||
root.held(true);
|
||||
}
|
||||
if (ev.kind == PointerEventKind.up
|
||||
|| ev.kind == PointerEventKind.cancel) {
|
||||
root.held(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HorizontalLayout {
|
||||
|
||||
Reference in New Issue
Block a user