From 762bd6b927e1347ed422034b2c3e26efe9994738 Mon Sep 17 00:00:00 2001 From: mateususa <150644469+mateususa@users.noreply.github.com> Date: Thu, 8 Oct 2026 19:19:59 -0700 Subject: [PATCH] Artboard tool: Delete and Backspace delete the active artboard The Artboard tool handled Delete/Backspace in Tool::key, but never claimed the keys through Tool::claims_key. The UI only routes Delete/Backspace to a tool that claims them, so the keypress went to the Clear shortcut instead and the artboard stayed. The existing tests called the tool directly and missed it. The tool now claims Delete/Backspace while no drag is in progress and more than one artboard exists. With only one artboard left, the keys stay with the shortcut. Co-Authored-By: Claude Opus 5.5 --- crates/engine/src/tests_xform.rs | 7 +++++-- crates/tools/src/xform/artboard.rs | 16 +++++++++++++--- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/crates/engine/src/tests_xform.rs b/crates/engine/src/tests_xform.rs index e790a65b..524adf23 100644 --- a/crates/engine/src/tests_xform.rs +++ b/crates/engine/src/tests_xform.rs @@ -247,10 +247,13 @@ fn artboard_tool_moves_with_art_creates_and_deletes() { assert_eq!(s.doc().unwrap().doc.artboards.len(), 2); assert_eq!(s.tool_options()["active"], 1); assert_eq!(s.doc().unwrap().doc.artboards[1].rect, Rect::new(1000.0, 0.0, 1200.0, 100.0)); - // Delete it. + // Delete it: the tool takes the key ahead of the Clear shortcut (the UI only hands Delete to a + // tool that claims it). + assert!(s.tool_claims_key(ToolKey::Delete, ViewInfo::default())); s.tool_key(ToolKey::Delete, Mods::default(), ViewInfo::default()).unwrap(); assert_eq!(s.doc().unwrap().doc.artboards.len(), 1); - // The last artboard can't be deleted. + // The last artboard can't be deleted, so Delete stays the shortcut's. + assert!(!s.tool_claims_key(ToolKey::Delete, ViewInfo::default())); s.tool_key(ToolKey::Delete, Mods::default(), ViewInfo::default()).unwrap(); assert_eq!(s.doc().unwrap().doc.artboards.len(), 1); } diff --git a/crates/tools/src/xform/artboard.rs b/crates/tools/src/xform/artboard.rs index 97d7df09..e20e19cf 100644 --- a/crates/tools/src/xform/artboard.rs +++ b/crates/tools/src/xform/artboard.rs @@ -259,10 +259,19 @@ impl Tool for ArtboardTool { } } + /// Delete/Backspace remove the active artboard ahead of the Clear shortcut, which would only + /// delete selected art; with one artboard left (it can't be deleted) they stay the shortcut's. + fn claims_key(&self, cx: &ToolContext, key: ToolKey) -> bool { + matches!(key, ToolKey::Delete | ToolKey::Backspace) + && self.drag.is_none() + && cx.doc.artboards.len() > 1 + && self.active < cx.doc.artboards.len() + } + fn key(&mut self, cx: &ToolContext, key: ToolKey, _mods: Mods) -> Vec { match key { - ToolKey::Delete | ToolKey::Backspace if self.drag.is_none() => { - if cx.doc.artboards.len() <= 1 || self.active >= cx.doc.artboards.len() { + ToolKey::Delete | ToolKey::Backspace => { + if !self.claims_key(cx, key) { return vec![]; } let i = self.active; @@ -522,7 +531,8 @@ mod tests { let a = t.pointer(&cx, &ev(PointerKind::Up, 1100.0, 1050.0)); assert_eq!(a[0], Action::Exec("artboard.new".into(), json!({"x": 1000.0, "y": 1000.0, "width": 100.0, "height": 50.0}))); assert_eq!(a[1], Action::Notify("created".into())); - // Delete removes the active artboard. + // Delete removes the active artboard, ahead of the Clear shortcut. + assert!(t.claims_key(&cx, ToolKey::Delete) && t.claims_key(&cx, ToolKey::Backspace)); assert_eq!(t.key(&cx, ToolKey::Delete, Mods::default()), vec![Action::Exec("artboard.delete".into(), json!({"index": 1}))]); assert_eq!(t.key(&cx, ToolKey::Escape, Mods::default()), vec![Action::SwitchTool("selection".into())]); }