Layers: renaming a layer or object commits on Enter or a click elsewhere

The name field asked for focus every frame, which took it back from
Enter, Escape or a click elsewhere, so lost_focus never fired and the
rename was never committed. It now asks only while opening, as the
Artboards panel's name field does.

Fixes #165

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01U9TrG4w49oSRYbP3cqxA3D
This commit is contained in:
theironchef
2026-10-05 10:51:46 -07:00
co-authored by Claude Opus 5.5
parent 1c46c4c654
commit 11740c9731
+34 -1
View File
@@ -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();