Delete with several layers selected deletes them, not the active layer's targeted mask (#4025) (#4078)

This commit is contained in:
Marco Arnulfo
2026-10-12 18:52:43 -04:00
committed by GitHub
parent 9862dfbb09
commit cd36d1ea0d
2 changed files with 36 additions and 2 deletions
+6 -2
View File
@@ -257,7 +257,8 @@ pub fn dispatch_pressed(app: &mut PhotocraftApp, ctx: &egui::Context, focus: Foc
/// type or shape layer the key did nothing. A selection, a single channel or Quick Mask keeps Clear.
/// With the active layer's mask targeted the key edits the mask, never the layer's pixels: a
/// selection is filled with the background colour in the mask (Photoshop's Delete on a mask), and
/// with no selection the mask itself is deleted, as Layer › Layer Mask › Delete.
/// with no selection the mask itself is deleted, as Layer › Layer Mask › Delete, unless several
/// layers are selected: then they are deleted.
fn delete_key_command(app: &PhotocraftApp, id: String) -> String {
if id != "edit.clear" {
return id;
@@ -270,7 +271,10 @@ fn delete_key_command(app: &PhotocraftApp, id: String) -> String {
let solo_mask = colors_off && has_mask && !alpha_on && st.doc.quick_mask.is_none();
let layer_mask = st.channel_view.target == photocraft_engine::channel_cmds::ChannelTarget::LayerMask;
let mask = (app.ui.mask_target || solo_mask || layer_mask) && has_mask;
if mask && (composite || layer_mask) {
// Several selected layers outrank the active one's targeted mask (#4025): a new adjustment
// layer targets its mask, so the first press used to delete only that mask.
let several = st.selected_layers().len() > 1;
if mask && (composite || layer_mask) && !(several && composite && st.doc.selection.is_none()) {
let cmd = if st.doc.selection.is_some() { "edit.fillBackground" } else { "layer.layerMask.delete" };
return cmd.into();
}
@@ -524,6 +524,36 @@ fn delete_without_a_selection_deletes_every_selected_layer() {
assert_eq!(names(&h).len(), n - 2);
}
/// #4025: with several layers selected and no selection, a targeted mask on the active one doesn't
/// take the key: Delete removes the selected layers in one press, as it does with the layer
/// targeted. A selection still fills the targeted mask.
#[test]
fn delete_with_several_layers_selected_deletes_them_even_with_the_mask_targeted() {
let mut h = harness();
put_focus(&mut h, Place::Canvas);
let s = &mut h.state_mut().session;
let first = photocraft_doc::LayerId(s.execute("layer.newAdjustmentLayer.curves", json!({})).unwrap()["layer"].as_u64().unwrap());
let second = photocraft_doc::LayerId(s.execute("layer.newAdjustmentLayer.invert", json!({})).unwrap()["layer"].as_u64().unwrap());
s.execute("layer.select", json!({"layer": first.0, "mode": "add"})).unwrap();
let st = s.active().unwrap();
assert_eq!(st.selected_layers().len(), 2);
assert!(st.active_layer.and_then(|l| st.doc.layer(l)).is_some_and(|l| l.mask.is_some()), "the active adjustment layer has a mask");
assert!(st.doc.selection.is_some(), "the harness keeps a selection");
h.state_mut().ui.mask_target = true;
h.run_steps(2);
let n = names(&h).len();
press(&mut h, "Delete");
assert_eq!(logged(&h), ["edit.fillBackground"], "a selection edits the mask");
assert_eq!(names(&h).len(), n);
h.state_mut().session.execute("select.deselect", json!({})).unwrap();
h.run_steps(2);
press(&mut h, "Delete");
assert_eq!(logged(&h), ["layer.delete"]);
let doc = &h.state().session.active().unwrap().doc;
assert!(doc.layer(first).is_none() && doc.layer(second).is_none(), "both selected layers are gone");
assert_eq!(names(&h).len(), n - 2);
}
/// A selection keeps Edit › Clear: the selected pixels go, the layer stays.
#[test]
fn delete_with_a_selection_clears_it() {