Put the repair tool on the photograph
A third chip beside Crop and Local, and the mode strip's own comment predicted the shape: a mode that arms a gesture on the canvas and scopes the column. Click a mark to cover it, drag the disc to move the repair, drag the source circle to say where the patch comes from, Delete to remove it. The source starts two and a half radii towards the middle of the frame, which is FR-DEV-8's automatic placement in its cheap form — dust sits on skies and skies are smooth, so it is usually right and always one drag from fixed. Two things are drawn deliberately. The circles are the size the repairs actually are, because whether a disc covers a speck is the whole judgement being made and a fixed-size dot would say nothing about it; the reach around them is padded to a touch target so a spot on a dust mark can still be picked up on a phone. And only the selected repair shows its source: a dusty sky carries a dozen, and two dozen circles with nothing saying which belongs to which is less information rather than more. The panel edits what is stored while the canvas draws what is mapped, and the two are pushed separately for that reason — a slider deriving its value from the drawn radius would move differently at different zoom levels. It is also the one panel built from SliderRow rather than a live track: a repair has no OpId to coalesce a drag under, so a row that fires once per gesture is what keeps undo one step per decision. Verified as far as this environment allows: the strip renders and the column re-scopes, photographed under XWayland. Synthetic clicks do not reach this application, so the gestures are as-written rather than as-felt, and docs/spot-removal.md says so. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -673,6 +673,14 @@ export enum ViewMode {
|
||||
/// The region map is drawn, a click on the photograph selects, and the
|
||||
/// column is the mask stack and the selected layer's adjustments.
|
||||
local,
|
||||
/// TRACES: FR-DEV-8
|
||||
/// The repairs are drawn on the photograph, a click places one, and the
|
||||
/// column describes whichever is selected.
|
||||
///
|
||||
/// A mode rather than a panel button for the reason the enum exists at
|
||||
/// all: arming a click on the canvas is something only one tool may be
|
||||
/// doing at a time, and two flags could both be true.
|
||||
spots,
|
||||
}
|
||||
|
||||
/// The strip: what the photographer is working on.
|
||||
@@ -741,15 +749,17 @@ export component ModeStrip inherits Rectangle {
|
||||
// than as an underline, so at a glance the strip reads as two runs
|
||||
// and it is never ambiguous which half a lit entry belongs to.
|
||||
//
|
||||
// **Where a brush goes.** Painting a mask is a third mode of exactly
|
||||
// this shape — it arms a canvas gesture and scopes the column — so it
|
||||
// joins this list and the `ViewMode` enum, and needs nothing else here.
|
||||
// `MaskSource::Brush` and the stroke calls on `MaskLayer` land in the
|
||||
// core separately; what is missing on this side is only the canvas
|
||||
// interaction, which is the gradient handles' neighbour.
|
||||
// **Where a canvas tool goes.** A mode that arms a gesture on the
|
||||
// photograph and scopes the column joins this list and the `ViewMode`
|
||||
// enum, and needs nothing else here. *Repair* is the first to arrive
|
||||
// that way (FR-DEV-8); painting a mask is the same shape and still to
|
||||
// come — `MaskSource::Brush` and the stroke calls on `MaskLayer`
|
||||
// already exist in the core, and what is missing on this side is only
|
||||
// the canvas interaction the repairs now have a pattern for.
|
||||
for entry in [
|
||||
{ label: "Crop", value: ViewMode.crop },
|
||||
{ label: "Local", value: ViewMode.local },
|
||||
{ label: "Repair", value: ViewMode.spots },
|
||||
]: mode-chip := TouchArea {
|
||||
width: mode-name.preferred-width + 2 * Theme.gap-sm;
|
||||
height: Theme.touch-target;
|
||||
|
||||
Reference in New Issue
Block a user