diff --git a/crates/engine/src/cmd/layer.rs b/crates/engine/src/cmd/layer.rs index 757de37a7..8b0e9392a 100644 --- a/crates/engine/src/cmd/layer.rs +++ b/crates/engine/src/cmd/layer.rs @@ -29,8 +29,8 @@ pub fn specs() -> Vec { "New Layer…", ["Window", "Layers"], Some("Cmd+L"), - "{name?, top?: bool, below?: bool, color?, template?, locked?, visible?, printable?, preview?, dimImages?} a layer directly above the current layer, at its level (a sublayer beside a current sublayer); `top`: above all layers (Ctrl/Cmd-click the button); `below`: directly below the current layer, at its level (Ctrl/Cmd+Alt-click the button), not with `top`. Options as layer.setProps → {id}", - has_doc, + "{name?, top?: bool, below?: bool, color?, template?, locked?, visible?, printable?, preview?, dimImages?} a layer directly above the current layer, at its level (a sublayer beside a current sublayer); `top`: above all layers (Ctrl/Cmd-click the button); `below`: directly below the current layer, at its level (Ctrl/Cmd+Alt-click the button), not with `top`. Options as layer.setProps; refused while an opacity mask is edited (the Layers panel lists only the mask) → {id}", + super::maskedit::outside_mask_editing, new_layer ), cmd!( @@ -38,8 +38,8 @@ pub fn specs() -> Vec { "New Sublayer…", ["Window", "Layers"], None, - "{parent?: layer id (default: the highlighted row's layer, else the current layer), bottom?: bool, name?, …options as layer.new} a sublayer on top of the parent's contents; `bottom`: under the parent's contents, above a clipping layer's clipping path (Ctrl/Cmd+Alt-click the button) → {id}", - has_doc, + "{parent?: layer id (default: the highlighted row's layer, else the current layer), bottom?: bool, name?, …options as layer.new} a sublayer on top of the parent's contents; `bottom`: under the parent's contents, above a clipping layer's clipping path (Ctrl/Cmd+Alt-click the button); refused while an opacity mask is edited → {id}", + super::maskedit::outside_mask_editing, new_sublayer ), cmd!( diff --git a/crates/engine/src/tests/opacitymask.rs b/crates/engine/src/tests/opacitymask.rs index 2a8cbf4ca..c2db4f368 100644 --- a/crates/engine/src/tests/opacitymask.rs +++ b/crates/engine/src/tests/opacitymask.rs @@ -151,6 +151,23 @@ fn mask_options_already_set_record_no_undo_step() { assert!(s.execute("transparency.setOpacityMask", &json!({"id": a.0})).is_err(), "no flag given"); } +/// #4538: while a mask is edited the Layers panel lists only the mask, so New Layer and New +/// Sublayer are refused instead of adding layers no row shows; they work again afterwards. +#[test] +fn new_layers_are_refused_while_a_mask_is_edited() { + let mut s = session(); + editing_mask(&mut s); + let layers = doc(&s).layers.len(); + for cmd in ["layer.new", "layer.newSublayer"] { + assert!(s.execute(cmd, &json!({})).is_err(), "{cmd} while the mask is edited"); + } + assert_eq!(doc(&s).layers.len(), layers); + s.execute("transparency.stopEditingOpacityMask", &json!({})).unwrap(); + let layers = doc(&s).layers.len(); + s.execute("layer.new", &json!({})).unwrap(); + assert_eq!(doc(&s).layers.len(), layers + 1); +} + #[test] fn release_while_editing_leaves_editing_first() { let mut s = session(); diff --git a/docs/mcp.md b/docs/mcp.md index 134ae18ad..fc9d738e7 100644 --- a/docs/mcp.md +++ b/docs/mcp.md @@ -2225,7 +2225,8 @@ and `layerRows`, the rows highlighted in the panel. - **Buttons**: `layer.new {name?, top?, below?, …options}` (above the current layer at its level; `top` with Ctrl/Cmd; `below`, directly below the current layer at its level, with Ctrl/Cmd+Alt), `layer.newSublayer {parent?, bottom?, name?, …options}` (on top of the parent's contents; `bottom`, under them but - above a clipping layer's clipping path, with Ctrl/Cmd+Alt), `layer.delete {ids?}` (rows with what they hold; the + above a clipping layer's clipping path, with Ctrl/Cmd+Alt; both refused while an opacity mask is edited), + `layer.delete {ids?}` (rows with what they hold; the last layer stays), `layer.locate {id?}` (highlights the selected object's row; the panel opens the rows around it) and `layer.clippingMask.toggle`. - **Panel menu**: `layer.duplicate {ids?}`, `layer.merge {ids?}` (into the layer highlighted last, keeping the