mirror of
https://github.com/storytold/photocraft.git
synced 2026-11-11 02:30:43 -06:00
Delete with several layers selected deletes them, not the active layer's targeted mask (#4025) (#4078)
This commit is contained in:
@@ -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() {
|
||||
|
||||
Reference in New Issue
Block a user