Put the edge controls where the mask is

Feather, falloff, grow/shrink/close/open and their amount, on the selected
layer. All four read the one distance field, so all four are live — nothing
recomputes except a compound morphology, and the session keys on that
separately so a feather drag rebuilds nothing.

Shown only for sources that go through the distance field. A gradient
carries its own falloff in its geometry, and offering a second one would be
two controls fighting over the same edge.

Picking an operation seeds a small amount if none is set. Selecting "Grow"
and seeing nothing happen would read as a broken control rather than as a
radius of zero.
This commit is contained in:
2026-08-22 08:39:17 +02:00
parent ec713585a5
commit 6163b63895
4 changed files with 223 additions and 1 deletions
+63
View File
@@ -47,6 +47,11 @@ pub(crate) fn sync(window: &AppWindow, session: &Rc<RefCell<Option<DevelopSessio
kind: s.mask_kind(&id).into(),
inverted: s.mask_inverted(&id),
opacity: s.mask_opacity(&id),
feather: s.mask_feather(&id),
falloff: s.mask_falloff(&id) as i32,
morphology: s.mask_morphology(&id) as i32,
morph_radius: s.mask_morph_radius(&id),
shapeable: s.mask_is_shapeable(&id),
id: id.into(),
label: label.into(),
enabled,
@@ -280,6 +285,64 @@ pub(crate) fn wire(
});
}
// --- the edge treatment -------------------------------------------------
//
// All four read one distance field, so all four are live: nothing here
// rebuilds anything except a compound morphology, which `develop` keys on
// separately.
{
let weak = window.as_weak();
let session = session.clone();
let redraw = redraw.clone();
window.on_mask_feather_changed(move |id, value| {
let Some(w) = weak.upgrade() else { return };
if let Some(s) = session.borrow_mut().as_mut() {
s.set_mask_feather(&id, value);
}
sync(&w, &session);
redraw(&w);
});
}
{
let weak = window.as_weak();
let session = session.clone();
let redraw = redraw.clone();
window.on_mask_falloff_picked(move |id, index| {
let Some(w) = weak.upgrade() else { return };
if let Some(s) = session.borrow_mut().as_mut() {
s.set_mask_falloff(&id, index.max(0) as usize);
}
sync(&w, &session);
redraw(&w);
});
}
{
let weak = window.as_weak();
let session = session.clone();
let redraw = redraw.clone();
window.on_mask_morphology_picked(move |id, index| {
let Some(w) = weak.upgrade() else { return };
if let Some(s) = session.borrow_mut().as_mut() {
s.set_mask_morphology(&id, index.max(0) as usize);
}
sync(&w, &session);
redraw(&w);
});
}
{
let weak = window.as_weak();
let session = session.clone();
let redraw = redraw.clone();
window.on_mask_morph_radius_changed(move |id, value| {
let Some(w) = weak.upgrade() else { return };
if let Some(s) = session.borrow_mut().as_mut() {
s.set_mask_morph_radius(&id, value);
}
sync(&w, &session);
redraw(&w);
});
}
// --- adding layers ------------------------------------------------------
{
let weak = window.as_weak();