From f4b5029714404d7ebbc8b6391448d3e49691fb3c Mon Sep 17 00:00:00 2001 From: theironchef <6278036+theironchef@users.noreply.github.com> Date: Wed, 7 Oct 2026 07:36:20 -0700 Subject: [PATCH 1/2] Fix #335: Left/Right arrows change a grid's columns while dragging While a tool was busy (a drag in progress) the shortcut handler passed only Up and Down to it, so the Rectangular and Polar Grid tools never saw Left/Right, which add and remove columns (radial dividers). All four arrows now go to the busy tool; the tools that use arrows for something else (Gradient, Perspective Selection) ignore them while busy. Co-Authored-By: Claude Opus 5.5 --- crates/ui-egui/src/shortcuts.rs | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/crates/ui-egui/src/shortcuts.rs b/crates/ui-egui/src/shortcuts.rs index 52e61f3c..f2daf869 100644 --- a/crates/ui-egui/src/shortcuts.rs +++ b/crates/ui-egui/src/shortcuts.rs @@ -280,7 +280,10 @@ pub fn handle(app: &mut VectorcraftApp, ctx: &egui::Context) { crate::menus::invoke(app, id, json!({})); } if busy { - for (k, tk) in [(Key::ArrowUp, ToolKey::Up), (Key::ArrowDown, ToolKey::Down)] { + // The arrows while dragging: a polygon's sides, a grid's rows (↑/↓) and columns (←/→)… + let arrows = + [(Key::ArrowUp, ToolKey::Up), (Key::ArrowDown, ToolKey::Down), (Key::ArrowLeft, ToolKey::Left), (Key::ArrowRight, ToolKey::Right)]; + for (k, tk) in arrows { if ctx.input_mut(|i| i.consume_key(Modifiers::NONE, k)) { let _ = app.session.tool_key(tk, Mods::default(), view); } @@ -447,6 +450,34 @@ mod tests { assert_eq!(app.session.doc().unwrap().doc.layers[0].children().unwrap().len(), 8); } + /// While a grid is dragged out, ↑/↓ change its rows and ←/→ its columns. + #[test] + fn arrows_while_dragging_a_grid_change_its_rows_and_columns() { + use vectorcraft_tools::{PointerEvent, PointerKind}; + let mut app = VectorcraftApp::new(vectorcraft_engine::Session::new(), Default::default()); + app.session.execute("file.new", &json!({"width": 400, "height": 300})).unwrap(); + app.select_tool("rectangularGrid"); + let view = app.view_info(); + // Drag a grid out, pressing `keys` on the way: its (horizontal, vertical) dividers. + let grid = |app: &mut VectorcraftApp, keys: &[Key]| { + app.session.pointer(&PointerEvent::new(PointerKind::Down, 100.0, 80.0), view).unwrap(); + app.session.pointer(&PointerEvent::new(PointerKind::Drag, 300.0, 220.0), view).unwrap(); + for &key in keys { + let press = egui::Event::Key { key, physical_key: None, pressed: true, repeat: false, modifiers: Modifiers::NONE }; + frame(app, vec![press]); + } + app.session.pointer(&PointerEvent::new(PointerKind::Up, 300.0, 220.0), view).unwrap(); + let d = &app.session.doc().unwrap().doc; + let g = d.layers[0].children().unwrap().last().unwrap().clone(); + let vectorcraft_doc::NodeKind::Group { children, .. } = &g.kind else { panic!("not a grid: {:?}", g.kind) }; + let bounds: Vec<_> = children.iter().filter_map(|c| c.geometric_bounds()).collect(); + (bounds.iter().filter(|b| b.height() < 0.5).count(), bounds.iter().filter(|b| b.width() < 0.5).count()) + }; + let (rows, columns) = grid(&mut app, &[]); + assert_eq!(grid(&mut app, &[Key::ArrowRight, Key::ArrowRight, Key::ArrowUp]), (rows + 1, columns + 2)); + assert_eq!(grid(&mut app, &[Key::ArrowLeft, Key::ArrowDown]), (rows, columns + 1)); + } + #[test] fn comma_and_period_reapply_the_last_colour_and_gradient() { let mut app = VectorcraftApp::new(vectorcraft_engine::Session::new(), Default::default()); From f17c34a067c8e5ddda2fc893cc52c4a5af11dc0f Mon Sep 17 00:00:00 2001 From: bflatastic Date: Thu, 8 Oct 2026 02:22:37 +0700 Subject: [PATCH 2/2] Grid tools: note the arrow keys in the ROADMAP (review of #336) Co-Authored-By: Claude Opus 5.5 --- ROADMAP.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ROADMAP.md b/ROADMAP.md index fd86c079..427f3753 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -106,7 +106,7 @@ grade by behaviour against `plan/illustrator/`, not by whether a menu item exist - **Tools:** - **Selection:** Selection, Direct/Group Selection, Magic Wand, Lasso. - **Drawing:** Pen, Curvature, anchor tools, Pencil, Paintbrush, Blob Brush, Smooth, Path Eraser, Join. Direction handles dragged with Direct Selection or the Anchor Point tool snap to smart guides, and Shift keeps them at 45° steps from their anchor. - - **Shapes:** all shape tools (including Flare) and the line, arc, spiral and grid tools. Space held while dragging out a shape, line, arc, spiral or grid moves it at its current size. + - **Shapes:** all shape tools (including Flare) and the line, arc, spiral and grid tools. Space held while dragging out a shape, line, arc, spiral or grid moves it at its current size. While a grid is dragged out, Up/Down change its rows (concentric dividers) and Left/Right its columns (radial dividers). - **Cutting:** Eraser, Scissors, Knife, Mirror & Cut, Line Cut and Rectangle Cut (real geometry, compound paths keep their holes). - **Transform:** Rotate, Reflect, Scale, Shear (click or Alt-click snaps the reference point to anchors and centres), Reshape, Free Transform (free and perspective distort and shear, switched by the keys held during a handle drag). - **Live Corners:** drag a live rectangle's corner widgets (Selection or Direct Selection) to round all corners, with a radius readout. Corners stay circular when the rectangle is scaled unevenly or along its own sides when rotated (the radius keeps its size, or scales by the mean scale with Scale Corners on); only a shear distorts them.