From 8c8ac373001ed984dd87f159ae4c38f33f04c56d Mon Sep 17 00:00:00 2001 From: theironchef <6278036+theironchef@users.noreply.github.com> Date: Mon, 5 Oct 2026 10:58:54 -0700 Subject: [PATCH] Layers: an open rename stays with its document Node ids are per document, so a rename left open while another document came to the front renamed that document's node with the same id. The panel drops an open rename when the document it shows changes. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01U9TrG4w49oSRYbP3cqxA3D --- crates/ui-egui/src/panels/layers.rs | 32 +++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/crates/ui-egui/src/panels/layers.rs b/crates/ui-egui/src/panels/layers.rs index 228499fb..81985c7b 100644 --- a/crates/ui-egui/src/panels/layers.rs +++ b/crates/ui-egui/src/panels/layers.rs @@ -25,6 +25,18 @@ fn expanded_id() -> egui::Id { pub fn show(app: &mut VectorcraftApp, ui: &mut Ui) { let t = Tokens::get(ui.ctx()); let Some(st) = app.session.active() else { return }; + // A rename belongs to the document it started in (node ids are per document): drop it when + // another document shows, so it can't rename that document's node with the same id. + let shown_doc = egui::Id::new("layers-doc"); + let before = ui.data(|d| d.get_temp::(shown_doc)); + if before != Some(st.uid) { + ui.data_mut(|d| { + if before.is_some() { + d.remove::<(u64, String)>(egui::Id::new("layers-rename")); + } + d.insert_temp(shown_doc, st.uid); + }); + } let doc = st.doc.clone(); let sel: HashSet = st.selection.objects.iter().copied().collect(); let target = st.selection.target; @@ -620,6 +632,26 @@ mod tests { assert_eq!(name(&app), "Sky", "Escape cancels"); } + #[test] + fn an_open_rename_does_not_follow_into_another_document() { + let mut app = VectorcraftApp::new(Session::new(), Default::default()); + app.session.execute("file.new", &json!({"width": 100, "height": 100})).unwrap(); + let layer = app.session.doc().unwrap().doc.layers[0].id; + let ctx = egui::Context::default(); + frame(&mut app, &ctx, vec![], false); + ctx.data_mut(|d| d.insert_temp(egui::Id::new("layers-rename"), (layer.0, "Renamed in the first".to_string()))); + frame(&mut app, &ctx, vec![], false); + // A second document, whose first layer has the same node id, comes to the front. + app.session.execute("file.new", &json!({"width": 100, "height": 100})).unwrap(); + assert_eq!(app.session.doc().unwrap().doc.layers[0].id, layer); + let enter = egui::Event::Key { key: egui::Key::Enter, physical_key: None, pressed: true, repeat: false, modifiers: egui::Modifiers::NONE }; + frame(&mut app, &ctx, vec![], false); + frame(&mut app, &ctx, vec![enter], false); + frame(&mut app, &ctx, vec![], false); + assert_eq!(app.session.doc().unwrap().doc.layers[0].display_name(), "Layer 1"); + assert!(ctx.data(|d| d.get_temp::<(u64, String)>(egui::Id::new("layers-rename"))).is_none()); + } + #[test] fn masks_underline_dashed_and_mask_editing_lists_only_the_mask() { let (mut app, _, [a, _]) = two_rects();