Let a preset name its film, and let a look reach only what it names
A preset could not choose a film stock. The stock is a choice of material rather than a parameter, so `Preset` — a map of `op.param = value` — had nowhere to hold it, and "Portra 400, printed" could not be saved, copied or shipped as a look. Worse, the film node's own sliders *were* parameters: a paste moved one stock's exposure and push onto whatever stock the target was on, and left the target's tables baked from the values it had just replaced. A preset now carries a `FilmRef` beside its parameters. It travels under whichever scope carries the film node, so the stock and its sliders are never split, and by the replacement rule every other parameter follows: applied at that scope, a preset without a film develops the target without one. `Preset::apply` returns the `FilmRebake` it owes, as `EditGraph::set_state` already did, because this crate cannot bake a stock; the develop session pays it before recording the step, and the batch paste writes the stock into each sidecar through `film_for`. The library file spells it `film =` / `film_print =`, as a sidecar does, and an older build keeps those lines as ones it does not understand. `EditState` keeps the film in its own field only: the parameters it captures leave it out, so one edit has one place to say which stock it is on. Second, a preset now has a reach. Replacement is right for a copy of a whole edit — "make these match" — and wrong for a look: a stock-only "Portra 400" applied that way would put the photograph's exposure, white balance and noise reduction back to default. `Reach::Named` replaces only the operations a preset names (whole operations, so a look that sets the blacks resets the whites beside them) and the film only if it names one. Saved edits and the clipboard keep `Reach::Whole`; the line `reach = named` is written only for the other, so existing libraries write the same bytes.
This commit is contained in:
@@ -547,7 +547,9 @@ impl DevelopSession {
|
||||
/// photograph nobody asked for, so every caller restores from a
|
||||
/// [`EditGraph::state`] taken first.
|
||||
pub(super) fn strip_adjustments(&mut self) {
|
||||
Preset::default().apply(&mut self.graph, Scope::adjustments());
|
||||
// The empty preset names no stock, so what it owes is nothing; the
|
||||
// film is cleared through the session below.
|
||||
let _ = Preset::default().apply(&mut self.graph, Scope::adjustments());
|
||||
*self.graph.masks_mut() = dr_pipeline::mask::MaskStack::new();
|
||||
*self.graph.spots_mut() = dr_pipeline::SpotSet::new();
|
||||
// Through the session rather than the graph: the baked tables live on
|
||||
|
||||
@@ -584,7 +584,12 @@ impl DevelopSession {
|
||||
/// The panel must be rebuilt from [`Self::rows`] afterwards: a paste moves
|
||||
/// values the sliders are showing, and nothing here pushes them.
|
||||
pub fn apply_settings(&mut self, preset: &Preset, scope: Scope) {
|
||||
preset.apply(&mut self.graph, scope);
|
||||
let rebake = preset.apply(&mut self.graph, scope);
|
||||
// TRACES: FR-DEV-3f
|
||||
// Before the step is recorded, so the history holds the photograph as
|
||||
// it now renders — on the preset's stock, baked from the film sliders
|
||||
// that just arrived with it.
|
||||
self.pay_film_debt(&rebake);
|
||||
// A paste is undoable, and is the action most in need of it: it
|
||||
// replaces everything in scope at once, so getting it wrong costs more
|
||||
// than any single control can.
|
||||
|
||||
Reference in New Issue
Block a user