diff --git a/crates/ui-egui/src/panels/tests_appearance.rs b/crates/ui-egui/src/panels/tests_appearance.rs index 4abb4be5d..1fee26cc6 100644 --- a/crates/ui-egui/src/panels/tests_appearance.rs +++ b/crates/ui-egui/src/panels/tests_appearance.rs @@ -1013,6 +1013,25 @@ fn after_a_row_click_delete_reaches_the_layers_panel_not_edit_clear() { assert!(d.node(rect).is_some(), "the rectangle on Layer 1 stays"); } +/// A tool that claims Delete and Backspace (the Artboard tool's active artboard) leaves them to a +/// clicked Layers row. +#[test] +fn after_a_row_click_delete_reaches_the_layers_panel_not_the_artboard_tool() { + for key in [egui::Key::Delete, egui::Key::Backspace] { + let ctx = drop_ctx(); + let mut app = app_with_rect(); + run(&mut app, "layer.new", json!({})); + run(&mut app, "artboard.new", json!({"width": 200, "height": 100})); + app.select_tool("artboard"); + let texts = frame_events(&ctx, &mut app, vec![], boxed_layers); + let row = text_rect(&texts, "Layer 2").center(); + app_click(&ctx, &mut app, row, boxed_layers); + app_key(&ctx, &mut app, key, boxed_layers); + let d = &app.session.active().unwrap().doc; + assert_eq!((d.layers.len(), d.artboards.len()), (1, 2), "{key:?}: Layer 2 is deleted, both artboards stay"); + } +} + /// "Opacity:" is a link to the Transparency panel ("Click to edit"), whatever modifiers are held: on /// a stroke's Opacity row it makes that stroke the active row first; on the object's own Opacity row /// no fill/stroke is active. diff --git a/crates/ui-egui/src/shortcuts.rs b/crates/ui-egui/src/shortcuts.rs index 4bbb75fbe..0d4023963 100644 --- a/crates/ui-egui/src/shortcuts.rs +++ b/crates/ui-egui/src/shortcuts.rs @@ -325,14 +325,14 @@ pub fn handle(app: &mut VectorcraftApp, ctx: &egui::Context) { busy_tool_keys(app, ctx, view); return; } - if claimed_tool_keys(app, ctx, view) { + // A plain Delete or Backspace after a click on a Layers or Appearance row is that panel's (it + // removes the highlighted rows), not a tool's (the Artboard tool's) or Edit › Clear's. + let rows_keys = crate::panels::rows_take_delete(ctx); + if claimed_tool_keys(app, ctx, view, rows_keys) { return; } // Command, panel and tool shortcuts. A bound shifted punctuation chord uses its key press; - // other text keys use the typed character below. A plain Delete or Backspace after a click on - // a Layers or Appearance row is that panel's (it removes the highlighted rows), not - // Edit › Clear's. - let rows_keys = crate::panels::rows_take_delete(ctx); + // other text keys use the typed character below. let row_key = |chord: &craft_keymap::Chord| { rows_keys && chord.is_plain() && !chord.mods.shift && matches!(chord.key, craft_keymap::Key::Delete | craft_keymap::Key::Backspace) }; @@ -657,9 +657,11 @@ fn busy_tool_keys(app: &mut VectorcraftApp, ctx: &egui::Context, view: ViewInfo) } } -/// Give keys claimed by the active tool precedence over their command shortcuts. -fn claimed_tool_keys(app: &mut VectorcraftApp, ctx: &egui::Context, view: ViewInfo) -> bool { +/// Give keys claimed by the active tool precedence over their command shortcuts, except a plain +/// Delete or Backspace while a panel's rows have them (`rows_keys`). +fn claimed_tool_keys(app: &mut VectorcraftApp, ctx: &egui::Context, view: ViewInfo, rows_keys: bool) -> bool { let m = ctx.input(|i| i.modifiers); + let rows_take = |k: Key| rows_keys && m.is_none() && matches!(k, Key::Delete | Key::Backspace); for (k, tk) in [ (Key::Delete, ToolKey::Delete), (Key::Backspace, ToolKey::Backspace), @@ -670,7 +672,7 @@ fn claimed_tool_keys(app: &mut VectorcraftApp, ctx: &egui::Context, view: ViewIn // The Smart Pen Tool's Tab while it draws a path (the key otherwise hides the panels). (Key::Tab, ToolKey::Tab), ] { - if ctx.input(|i| i.key_pressed(k)) && app.session.tool_claims_key(tk, view) && ctx.input_mut(|i| i.consume_key(m, k)) { + if !rows_take(k) && ctx.input(|i| i.key_pressed(k)) && app.session.tool_claims_key(tk, view) && ctx.input_mut(|i| i.consume_key(m, k)) { let r = app.session.tool_key(tk, crate::canvas::mods(m, false), view); // Keyboard actions can change the Artboard tool's active board too. Keep the // navigator aligned with its valid survivor, as pointer dispatch does.