Show the regions, click one, and adjust it
The local panel sits above the adjust panel because it decides what those sliders act on; below it, a photographer would set an exposure and only then discover which scope it landed in. Selecting a layer re-scopes the existing controls to that layer's chain — there is no second set of sliders, and there must not be, or every operation added to `ops/` would need a local twin. The overlay is drawn over the canvas rather than blended into the render, because it is a diagnostic and not an edit: it must not reach the histogram, an export, or the texture handed to the compositor. Nearest- neighbour always — the map's values are *names*, so smoothing between region 4 and region 9 invents a colour belonging to neither and softens exactly the edge the overlay exists to show. Picking gets its own touch area above the pan handler. Panning wants press-drag-release and picking wants a click; interleaving them in one handler is how a drag ends up selecting a region the user was scrolling past. Shift is tracked as window state because a TouchArea's click carries no modifiers. Three states a layer can be in are worth distinguishing, and each has a different remedy: stale needs re-segmenting, "no adjustment yet" needs a slider moved, and the ordinary case needs nothing said. A bare selection renders nothing and looks identical to a broken mask, which is the first thing a new user will hit. Known rough edge, commented where it happens: segmentation blocks the UI thread for about half a second. Moving it to a worker needs the develop session — GPU resources behind a RefCell shared with every callback — to be reachable from another thread, which is a restructuring rather than a change to the call. The button says "Finding regions…" first so the stall is announced rather than looking like a hang.
This commit is contained in:
@@ -770,6 +770,35 @@ impl DevelopSession {
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// What kind of mask a layer is — "regions", "linear", "radial".
|
||||
pub fn mask_kind(&self, id: &str) -> &'static str {
|
||||
self.graph
|
||||
.masks()
|
||||
.get(id)
|
||||
.map_or("", |l| l.source.kind())
|
||||
}
|
||||
|
||||
pub fn mask_inverted(&self, id: &str) -> bool {
|
||||
self.graph.masks().get(id).is_some_and(|l| l.invert)
|
||||
}
|
||||
|
||||
pub fn mask_opacity(&self, id: &str) -> f32 {
|
||||
self.graph.masks().get(id).map_or(1.0, |l| l.opacity)
|
||||
}
|
||||
|
||||
/// Whether a layer has any adjustment on it yet.
|
||||
///
|
||||
/// Distinct from `is_active`, which also asks whether the layer is enabled
|
||||
/// and visible. The panel wants specifically "you have made a selection
|
||||
/// and not yet done anything with it", because that state looks identical
|
||||
/// to a broken mask and is the most likely thing a first-time user hits.
|
||||
pub fn mask_is_adjusted(&self, id: &str) -> bool {
|
||||
self.graph
|
||||
.masks()
|
||||
.get(id)
|
||||
.is_some_and(|l| l.active_ops().next().is_some())
|
||||
}
|
||||
|
||||
pub fn active_mask(&self) -> Option<&str> {
|
||||
self.active_mask.as_deref()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user