diff --git a/crates/engine/src/cmd/appearance.rs b/crates/engine/src/cmd/appearance.rs index df691490f..3da1cb56c 100644 --- a/crates/engine/src/cmd/appearance.rs +++ b/crates/engine/src/cmd/appearance.rs @@ -615,12 +615,16 @@ fn reduce_basic(s: &mut Session, p: &Value) -> Result { // When every object comes out as it was, the document and its undo history stay as they are. let before = s.doc()?.doc.clone(); // The Appearance panel's active row (a row of the first selected object's stack, and in each - // other target the row equal to it there), when the command acts on that selection. - let active = match s.appearance_item() { - Some(index) - if p.get("ids").is_none() && p.get("id").is_none() && !targets_contents(p)? && s.doc()?.selection.subjects().first() == ids.first() => - { - items_per_target(&before, &ids, &[index], true) + // other target the row equal to it there), when the command acts on that selection. The targets + // are in paint order, so the first selected object can be any of them. + let first = s.doc()?.selection.subjects().first().and_then(|f| ids.iter().position(|id| id == f)); + let active = match (s.appearance_item(), first) { + (Some(index), Some(k)) if p.get("ids").is_none() && p.get("id").is_none() && !targets_contents(p)? => { + let mut from = ids.clone(); + from.swap(0, k); + let mut rows = items_per_target(&before, &from, &[index], true); + rows.swap(0, k); + rows } _ => vec![Vec::new(); ids.len()], }; diff --git a/crates/engine/src/tests/appearance.rs b/crates/engine/src/tests/appearance.rs index 490622812..3a56ff7f1 100644 --- a/crates/engine/src/tests/appearance.rs +++ b/crates/engine/src/tests/appearance.rs @@ -444,6 +444,25 @@ fn reduce_to_basic_keeps_the_active_row() { assert_eq!(stroke(&n, 1).width, 1.0); } +/// The active row is a row of the first selected object even when that object paints above the +/// others; another object without an equal row keeps its topmost fill. +#[test] +fn reduce_to_basic_keeps_the_active_row_of_the_first_selected_object() { + let mut s = session(); + let a = rect(&mut s, 50.0); + run(&mut s, "appearance.addFill", json!({})); + run(&mut s, "appearance.setItem", json!({"index": 2, "color": "#0000ff"})); // [Fill, Stroke, Fill blue] + let b = rect(&mut s, 200.0); + run(&mut s, "appearance.addFill", json!({})); + run(&mut s, "appearance.setItem", json!({"index": 0, "color": "#00ff00"})); + run(&mut s, "appearance.setItem", json!({"index": 2, "color": "#ff0000"})); // [Fill green, Stroke, Fill red] + run(&mut s, "select.set", json!({"ids": [b.0, a.0]})); + run(&mut s, "appearance.setActiveItem", json!({"index": 0})); + run(&mut s, "appearance.reduceToBasic", json!({})); + assert_eq!(fill_paint(&node(&s, b), 0).color().unwrap().to_hex(), "#00ff00"); + assert_eq!(fill_paint(&node(&s, a), 0).color().unwrap().to_hex(), "#0000ff"); +} + /// How many steps there are to undo and to redo, and whether the document has unsaved changes. fn history(s: &Session) -> (usize, usize, bool) { let st = s.doc().unwrap();