Keep an edit under a name, not just on the clipboard
FR-DEV-6 asks for three things — named presets, copy/paste between images, and batch-apply to a selection. The last two have been here for a while; this is the first. The format is the sidecar's, deliberately. A preset *is* the non-default half of a version, so the lines are the same lines keyed the same way, which makes the two files diffable against each other and lets someone debugging an edit paste a block from one into the other. One file rather than one per preset: a preset per file makes the name a path, and every name then has to survive a filesystem — a `/` becomes a directory, a name differing only in case collides on one platform and not another, and renaming becomes two operations that can half-fail. As a key in a document it is none of those. Unknown *parameters* needed no machinery. `Preset` already holds whatever keys it is given and resolves them against the descriptors only at apply time, so one written by a newer build survives by being stored. Only lines that are not `op.param = float` at all are preserved verbatim, which is the sidecar's version-skew promise made here too. Applying is the paste path with a different source, so a preset reaches a selection through the sidecar read-modify-write that was already there: no graph, no decode, no GPU, forty files or one. Two smaller decisions worth the record. A library that fails to parse is held empty in memory and *not* written back over — settings regenerate themselves and this is work, so a parse failure must not be the moment it is destroyed. And every save persists immediately and rolls the in-memory copy back if the write fails, so the sheet never lists a preset the file does not have. The grid's "Presets" button is gated on the selection alone, unlike the "Paste to 40" beside it. That button needs a clipboard armed this session; the preset list is whatever was saved last month, and hiding it behind an unrelated action is what makes a feature only its author knows about. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -850,6 +850,9 @@ component HeaderActions inherits HorizontalLayout {
|
||||
callback export-selection();
|
||||
callback cancel-export();
|
||||
callback paste-settings-to-selection();
|
||||
/// TRACES: FR-DEV-6
|
||||
/// Open the named-preset sheet over the selection.
|
||||
callback open-presets();
|
||||
callback remove-from-collection();
|
||||
/// Open the sheet that files the selection in a collection.
|
||||
callback add-to-collection();
|
||||
@@ -931,6 +934,20 @@ component HeaderActions inherits HorizontalLayout {
|
||||
clicked => { root.paste-settings-to-selection(); }
|
||||
}
|
||||
|
||||
// TRACES: FR-DEV-6
|
||||
// The saved settings, beside the copied ones.
|
||||
//
|
||||
// Gated on the selection alone, unlike the paste beside it: that button
|
||||
// needs a clipboard *this session*, where the preset list is whatever the
|
||||
// photographer saved last month. Requiring an armed clipboard here would
|
||||
// hide the saved presets behind an unrelated action — which is the shape
|
||||
// of bug that makes a feature only its author knows about (FR-UI-4).
|
||||
if root.selected-count > 0: Button {
|
||||
text: "Presets";
|
||||
y: root.centred ? (root.row-height - self.height) / 2 : 0;
|
||||
clicked => { root.open-presets(); }
|
||||
}
|
||||
|
||||
// TRACES: FR-EXP-7 | NFR-ARCH-3
|
||||
// Export the selection, and stop the batch that is running.
|
||||
//
|
||||
@@ -1332,6 +1349,8 @@ export component LibraryGrid inherits Rectangle {
|
||||
in property <bool> settings-armed: false;
|
||||
in property <string> settings-summary;
|
||||
callback paste-settings-to-selection();
|
||||
/// TRACES: FR-DEV-6
|
||||
callback open-presets();
|
||||
|
||||
// TRACES: FR-EXP-7
|
||||
// Exporting the selection. The grid owns neither the settings that decide
|
||||
@@ -1698,6 +1717,7 @@ export component LibraryGrid inherits Rectangle {
|
||||
export-selection => { root.export-selection(); }
|
||||
cancel-export => { root.cancel-export(); }
|
||||
paste-settings-to-selection => { root.paste-settings-to-selection(); }
|
||||
open-presets => { root.open-presets(); }
|
||||
remove-from-collection => { root.remove-from-collection(); }
|
||||
select-mode: root.select-mode;
|
||||
toggle-select-mode => { root.toggle-select-mode(); }
|
||||
@@ -1783,6 +1803,7 @@ export component LibraryGrid inherits Rectangle {
|
||||
export-selection => { root.export-selection(); }
|
||||
cancel-export => { root.cancel-export(); }
|
||||
paste-settings-to-selection => { root.paste-settings-to-selection(); }
|
||||
open-presets => { root.open-presets(); }
|
||||
remove-from-collection => { root.remove-from-collection(); }
|
||||
select-mode: root.select-mode;
|
||||
toggle-select-mode => { root.toggle-select-mode(); }
|
||||
|
||||
Reference in New Issue
Block a user