diff --git a/crates/ui-egui/src/panels/layers.rs b/crates/ui-egui/src/panels/layers.rs index 2a86bbe34..228499fb2 100644 --- a/crates/ui-egui/src/panels/layers.rs +++ b/crates/ui-egui/src/panels/layers.rs @@ -202,7 +202,11 @@ fn row( Some((rid, mut buf)) if rid == n.id.0 => { let mut child = ui.new_child(egui::UiBuilder::new().max_rect(name_rect)); let te = child.add(egui::TextEdit::singleline(&mut buf).desired_width(name_rect.width()).font(font.clone())); - te.request_focus(); + // Focus the field as it opens. Asking every frame took the focus back from Enter, + // Escape or a click elsewhere, so the rename never ended. + if !te.has_focus() && !te.lost_focus() { + te.request_focus(); + } if te.lost_focus() { ui.data_mut(|d| d.remove::<(u64, String)>(rename_id)); if child.input(|i| !i.key_pressed(egui::Key::Escape)) && buf != name { @@ -587,6 +591,35 @@ mod tests { assert_eq!(st.doc.node_count(), count); } + #[test] + fn renaming_a_layer_commits_on_enter_and_escape_cancels() { + 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 name = |app: &VectorcraftApp| app.session.doc().unwrap().doc.layers[0].display_name(); + let ctx = egui::Context::default(); + let key = |key| egui::Event::Key { key, physical_key: None, pressed: true, repeat: false, modifiers: egui::Modifiers::NONE }; + let select_all = + egui::Event::Key { key: egui::Key::A, physical_key: None, pressed: true, repeat: false, modifiers: egui::Modifiers::COMMAND }; + // What a double-click on the row does: the name field opens with the name. + let open = |app: &mut VectorcraftApp| { + ctx.data_mut(|d| d.insert_temp(egui::Id::new("layers-rename"), (layer.0, name(app)))); + frame(app, &ctx, vec![], false); + frame(app, &ctx, vec![], false); + }; + open(&mut app); + frame(&mut app, &ctx, vec![select_all.clone(), egui::Event::Text("Sky".into())], false); + frame(&mut app, &ctx, vec![key(egui::Key::Enter)], false); + frame(&mut app, &ctx, vec![], false); + assert_eq!(name(&app), "Sky", "Enter keeps the new name"); + assert!(ctx.data(|d| d.get_temp::<(u64, String)>(egui::Id::new("layers-rename"))).is_none(), "and closes the field"); + open(&mut app); + frame(&mut app, &ctx, vec![select_all, egui::Event::Text("Ground".into())], false); + frame(&mut app, &ctx, vec![key(egui::Key::Escape)], false); + frame(&mut app, &ctx, vec![], false); + assert_eq!(name(&app), "Sky", "Escape cancels"); + } + #[test] fn masks_underline_dashed_and_mask_editing_lists_only_the_mask() { let (mut app, _, [a, _]) = two_rects();