diff --git a/crates/engine/src/cmd/arrange.rs b/crates/engine/src/cmd/arrange.rs index 26afec87..43cfcf3c 100644 --- a/crates/engine/src/cmd/arrange.rs +++ b/crates/engine/src/cmd/arrange.rs @@ -332,8 +332,12 @@ fn zorder(s: &mut Session, p: &Value, z: Z) -> Result { } } if matches!(z, Z::Back) { - for (k, i) in ids.iter().enumerate() { - doc.reorder(*i, k)?; + let mut next: std::collections::HashMap = std::collections::HashMap::new(); + for i in &ids { + let Some(pp) = doc.get(*i)?.parent else { continue }; + let k = next.entry(pp).or_insert(0); + doc.reorder(*i, *k)?; + *k += 1; } } ok() diff --git a/crates/engine/src/tests.rs b/crates/engine/src/tests.rs index bfcc1ec3..9ddefb9f 100644 --- a/crates/engine/src/tests.rs +++ b/crates/engine/src/tests.rs @@ -274,6 +274,28 @@ fn a_layer_alone_on_the_page_has_nothing_to_align_to() { assert_eq!(s.doc().unwrap().world_bounds(inner).unwrap().x1, 200.0); } +#[test] +fn send_to_back_across_frames_counts_per_parent() { + let mut s = sess(); + let make = |s: &mut Session, p: Value| id(&s.execute("node.create", &p).unwrap()); + let fa = make(&mut s, json!({"type": "frame", "x": 0, "y": 0, "width": 200, "height": 200})); + let fb = make(&mut s, json!({"type": "frame", "x": 300, "y": 0, "width": 200, "height": 200})); + let rect = |parent: NodeId| json!({"type": "rectangle", "parent": parent, "x": 10, "y": 10, "width": 20, "height": 20}); + let a: Vec = (0..2).map(|_| make(&mut s, rect(fa))).collect(); + let b: Vec = (0..3).map(|_| make(&mut s, rect(fb))).collect(); + let idx = |s: &Session, n: NodeId| s.doc().unwrap().index_in_parent(n); + assert_eq!(idx(&s, a[1]), Some(1)); + assert_eq!(idx(&s, b[2]), Some(2)); + s.execute("arrange.back", &json!({"ids": [a[1], b[2]]})).unwrap(); + assert_eq!(idx(&s, a[1]), Some(0), "top of frame A at the back"); + assert_eq!(idx(&s, b[2]), Some(0), "top of frame B at the back"); + // Two from B plus one from A: each parent's selection ends at 0..n in its original order. + s.execute("arrange.back", &json!({"ids": [b[1], a[0], b[0]]})).unwrap(); + let kids = |s: &Session, f: NodeId| s.doc().unwrap().node(f).unwrap().children.clone(); + assert_eq!(kids(&s, fa), vec![a[0], a[1]]); + assert_eq!(kids(&s, fb), vec![b[0], b[1], b[2]]); +} + #[test] fn copy_paste_and_duplicate() { let mut s = sess();