From 6e460aab8a3cedd6c80211e29ebcfd412edbcbee Mon Sep 17 00:00:00 2001 From: driftee <48539371+driftee@users.noreply.github.com> Date: Sun, 18 Oct 2026 22:38:54 +0800 Subject: [PATCH] fix(transform): isolate nested preview siblings (#7280) --- crates/ui-egui/src/transform_tool.rs | 35 ++++++++++++++++++++++------ 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/crates/ui-egui/src/transform_tool.rs b/crates/ui-egui/src/transform_tool.rs index d46ef189bc..d14046db9d 100644 --- a/crates/ui-egui/src/transform_tool.rs +++ b/crates/ui-egui/src/transform_tool.rs @@ -792,13 +792,11 @@ fn preview_image( (None, Some(s)) if layer.is_some_and(|l| matches!(l.content, LayerContent::Raster(_))) => Some(s), _ => { let mut solo = doc.clone(); - for l in solo.layers.iter_mut() { - if l.id != id && doc.layer(id).is_some_and(|_| !contains(l, id)) { - l.visible = false; - } else { - // Its clipping base is hidden here, which would clip it away entirely (#5239). - l.clipped = false; - } + show_only(&mut solo.layers, &[id]); + // Its clipping base is hidden here, which would clip it away entirely (#5239). + // Clear the target itself, not only the top-level group that contains it. + if let Some(l) = solo.layer_mut(id) { + l.clipped = false; } if let Some(l) = solo.layer_mut(id).filter(|_| bare) { l.effects.enabled = false; @@ -4747,6 +4745,29 @@ mod tests { assert!(pv.texture.size()[0] as f64 >= t.rect[2] - t.rect[0]); } + #[test] + fn nested_group_preview_excludes_its_siblings() { + use photocraft_color::PixelFormat; + use photocraft_doc::Layer; + + let mut app = app_with_square(64, photocraft_geom::Rect::new(8, 8, 24, 24)); + let st = app.session.active_mut().unwrap(); + let doc = Arc::make_mut(&mut st.doc); + let target_pixels = doc.layers.pop().unwrap(); + let mut sibling = Layer::raster("sibling", PixelFormat::RGBA8); + sibling.surface_mut().unwrap().fill_rect(photocraft_geom::Rect::new(12, 12, 20, 20), &[0.0, 0.0, 1.0, 1.0]); + let target = Layer::group("target", vec![target_pixels]); + let target_id = target.id; + doc.layers.push(Layer::group("parent", vec![target, sibling])); + + let (image, _) = preview_image(&st.doc, target_id, None, photocraft_geom::Rect::new(8, 8, 24, 24), 4096, false); + assert_eq!( + image.pixels[8 * image.size[0] + 8], + Color32::from_rgb(255, 0, 0), + "a sibling in the parent group must not be baked into the moving texture" + ); + } + /// The textured meshes `draw_content` paints for the moving pixels (not the box or handles). fn preview_meshes(app: &PhotocraftApp, xf: &ViewXform) -> Vec { let ctx = gpu_ctx();