WIP: capture sharpening
Checkpoint committed by the coordinator, not by the authoring agent: the session hit its API limit mid-task and left this work uncommitted. Committed so it survives, NOT because it is finished - expect failing tests and half-applied changes. The agent resumes from here.
This commit is contained in:
@@ -934,9 +934,19 @@ impl MaskLayer {
|
||||
/// the output's dimensions, so it is a property of the photograph and not
|
||||
/// of a region within it. There is no such thing as cropping part of an
|
||||
/// image.
|
||||
///
|
||||
/// The neighbourhood operations are absent for the same reason, and this
|
||||
/// filter is the visible half of the one [`Self::active_ops`] already
|
||||
/// applies. A layer's chain is fused into the point-operation pass; the
|
||||
/// detail stage runs once, afterwards, over the whole frame, so there is
|
||||
/// no seam through which a mask could reach it (see [`crate::detail`]).
|
||||
/// Offering the controls anyway would put a sharpening slider on a mask
|
||||
/// that moves and does nothing — which is worse than the control being
|
||||
/// absent, because absence is legible and a dead slider is not.
|
||||
pub fn capabilities(&self) -> Vec<crate::graph::OpCapability> {
|
||||
self.ops
|
||||
.iter()
|
||||
.filter(|op| op.detail().is_none())
|
||||
.map(|op| {
|
||||
let desc = op.descriptor();
|
||||
crate::graph::OpCapability {
|
||||
@@ -1625,4 +1635,38 @@ mod tests {
|
||||
let order: Vec<&str> = stack.layers().iter().map(|l| l.id.as_str()).collect();
|
||||
assert_eq!(order, ["m3", "m1", "m2"]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_layer_offers_no_control_it_cannot_honour() {
|
||||
// A layer's chain is fused into the point-operation pass, and the
|
||||
// detail stage runs once afterwards over the whole frame — so a
|
||||
// neighbourhood operation inside a mask has nowhere to run.
|
||||
// `active_ops` has always dropped them; this is the other half, which
|
||||
// stops the panel drawing a sharpening slider on a mask that would
|
||||
// move and change nothing.
|
||||
let layer = lit_layer("m1", 1.0);
|
||||
let global: Vec<&str> = crate::EditGraph::default_chain()
|
||||
.capabilities()
|
||||
.iter()
|
||||
.map(|c| c.id.0)
|
||||
.collect();
|
||||
let scoped: Vec<&str> = layer.capabilities().iter().map(|c| c.id.0).collect();
|
||||
|
||||
let detail: Vec<&str> = crate::ops::chain()
|
||||
.iter()
|
||||
.filter(|o| o.detail().is_some())
|
||||
.map(|o| o.descriptor().id.0)
|
||||
.collect();
|
||||
assert!(
|
||||
!detail.is_empty(),
|
||||
"the chain has neighbourhood operations, or this proves nothing"
|
||||
);
|
||||
for id in detail {
|
||||
assert!(global.contains(&id), "{id} is missing from the chain");
|
||||
assert!(
|
||||
!scoped.contains(&id),
|
||||
"{id} cannot run inside a mask and must not be offered there"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user