From 4ad625eef18e50337bf7232ec9b7deef434a34b6 Mon Sep 17 00:00:00 2001 From: Yasas Sri <164534752+Yasas-Sri@users.noreply.github.com> Date: Thu, 15 Oct 2026 06:09:24 +0530 Subject: [PATCH] Escape selects a text box or WordArt, so Delete removes it (#1538) (#1604) Co-authored-by: Brandon Thomas --- crates/ui-egui/src/keys.rs | 10 ++++++---- crates/ui-egui/src/lib.rs | 27 +++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 4 deletions(-) diff --git a/crates/ui-egui/src/keys.rs b/crates/ui-egui/src/keys.rs index 872a20bb5..49b90eb5a 100644 --- a/crates/ui-egui/src/keys.rs +++ b/crates/ui-egui/src/keys.rs @@ -369,14 +369,16 @@ pub fn canvas_events(app: &mut WordApp, ctx: &egui::Context) { app.canvas.context_menu_from_keys = true; continue; } - // Escape leaves a text box to just after it in the body. + // Escape in a text box (or WordArt) selects the box itself, so Delete then removes + // it (#1538). The anchor position is just after the box's object character. if key == Key::Escape && crate::canvas::in_text_box(app) - && app.session.sel.is_collapsed() && let wordcraft_doc::StoryRef::Part(id) = app.session.sel.focus.story - && let Some(pos) = app.session.doc.text_box_anchor(id) + && let Some(end) = app.session.doc.text_box_anchor(id) + && let Some(off) = end.off.checked_sub(wordcraft_doc::para::OBJ.len_utf8()) { - let _ = app.run("caret.set", json!({"pos": pos})); + let start = wordcraft_doc::Pos { off, ..end.clone() }; + let _ = app.run("select.range", json!({"anchor": start, "focus": end})); continue; } if key == Key::Escape && matches!(app.session.sel.focus.story, wordcraft_doc::StoryRef::Part(_)) && app.session.sel.is_collapsed() { diff --git a/crates/ui-egui/src/lib.rs b/crates/ui-egui/src/lib.rs index 1048fc916..5666750b8 100644 --- a/crates/ui-egui/src/lib.rs +++ b/crates/ui-egui/src/lib.rs @@ -4658,6 +4658,33 @@ mod tests { assert_eq!(h.state().session.doc.plain_text(wordcraft_doc::StoryRef::Body), "Kilns"); } + /// #1538: inserting WordArt leaves its text selected, so Delete erased only the text and the + /// empty box stayed. Escape now selects the box itself, Delete removes it, and a second Escape + /// is back to a caret in the body. + #[test] + fn escape_selects_a_wordart_box_and_delete_removes_it() { + let mut a = app(); + let id = a.run("insert.wordArt", json!({})).unwrap()["story"].as_u64().unwrap() as u32; + assert!(canvas::in_text_box(&a), "the WordArt's text is selected after inserting it"); + let mut h = harness(a); + h.run_steps(4); + h.key_press(egui::Key::Escape); + h.run_steps(2); + assert!(wordcraft_engine::cmd::objects::object_selection(&h.state().session).is_some(), "Escape selects the box"); + h.key_press(egui::Key::Delete); + h.run_steps(2); + assert_eq!(h.state().session.doc.text_box_anchor(id), None, "Delete removed the WordArt"); + assert!(h.state_mut().session.undo(), "one undo brings it back"); + assert!(h.state().session.doc.text_box_anchor(id).is_some()); + h.run_steps(2); + h.key_press(egui::Key::Escape); + h.run_steps(2); + h.key_press(egui::Key::Escape); + h.run_steps(2); + let s = &h.state().session; + assert!(s.sel.is_collapsed() && s.sel.focus.story == wordcraft_doc::StoryRef::Body, "a second Escape leaves a caret in the body"); + } + /// #1218: Ctrl+Q resets the paragraph formatting and nothing else; it also closed the window /// (asking to save) on Windows and Linux. ⌘Q still quits on the Mac. #[test]