Point at something grey and let the pipeline work out the rest
FR-DEV-3 has asked for "white balance (temperature/tint, and picker)" since it was written, and only the first half existed. `WidgetKind::WhitePoint` was in the vocabulary and `develop::supported` answered false for it, so the node degraded to two sliders — correct behaviour that had quietly become the only behaviour. Sampling a neutral is the first move of the global tonal pass and every colour judgement afterwards is measured against where the grey was put, so guessing at two sliders until a wall stops looking green is the wrong way round. The awkward part is that a picker genuinely needs to know how far a hundred units of temperature move red against blue, and that number is declared in the node's own file. So the inversion lives in `dr_pipeline::neutral` rather than in the interface: the canvas hands over a colour, the core finds the operation that asked to be driven by a pixel and bisects its declared response until the sample comes back grey. Nothing in `ui/` names white balance, and nothing holds a second copy of a response that would be wrong the first time somebody adjusted the range. A bisection rather than a closed-form inverse because only monotonicity is part of the bargain — the expression is free to become a table tomorrow. The result is rounded to the precision the control is drawn at, which is not cosmetic: unrounded, sampling something already neutral lands a ten-thousandth off zero, and the photograph comes back modified with an undo step for a correction of nothing. On the panel side this needed one distinction the generated path was missing. `is_on_canvas` was being read as "and so the panel draws nothing for it", which is right for a crop — four edge fractions are not controls anyone drags in a list — and wrong for an eyedropper, which *writes* temperature and tint and leaves them exactly the controls a photographer reaches for next. So a sampling widget keeps its sliders and puts the affordance that arms the canvas in the group's heading, built like the reset beside it. One click, one sample, one history step: `Edit::Action` never coalesces, and there is no hover preview to fill the stack with temperatures nobody chose. Declaring the presentation also groups temperature and tint under one undo step, where they were two. That follows from what `Presentation` means and reads correctly — white balance is one decision — but it is a change, and worth saying so.
This commit is contained in:
@@ -170,6 +170,24 @@ pub enum WidgetKind {
|
||||
/// On-canvas brush strokes.
|
||||
BrushMask,
|
||||
/// An eyedropper bound to the canvas, setting white balance from a pixel.
|
||||
///
|
||||
/// **The one widget that reads the photograph rather than driving it**,
|
||||
/// and that is what gives it a contract the others do not need. A curve
|
||||
/// tells its frontend where its points are and the frontend moves them; an
|
||||
/// eyedropper is handed a colour and has to work out what the parameters
|
||||
/// should become, which is only possible if the operation says enough
|
||||
/// about itself to be inverted:
|
||||
///
|
||||
/// * The first two parameters in [`Presentation::params`] are its axes —
|
||||
/// the first trading red against blue, the second green against
|
||||
/// magenta — and each is monotonic in its axis.
|
||||
/// * The operation publishes exactly three uniforms: the linear
|
||||
/// per-channel gains, in red, green, blue order.
|
||||
///
|
||||
/// The same kind of contract [`Self::ToneCurve`] carries when it says its
|
||||
/// parameters are point coordinates interleaved, and it is checked rather
|
||||
/// than trusted — see [`crate::neutral`], which does the inverting so that
|
||||
/// no frontend has to hold a second copy of the declared response.
|
||||
WhitePoint,
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user