diff --git a/crates/engine/src/cmd/perspgrid.rs b/crates/engine/src/cmd/perspgrid.rs index 5b622f430..822d88aad 100644 --- a/crates/engine/src/cmd/perspgrid.rs +++ b/crates/engine/src/cmd/perspgrid.rs @@ -29,7 +29,7 @@ pub fn specs() -> Vec { "Perspective Grid", [], None, - "{} → {grid: the model (as perspective.grid.set takes it), define: the Define Grid fields (as perspective.grid.define takes them), station: {x, y, distance} (the viewer: centre of vision on the horizon, distance to the picture plane, pt), defined: false while the document uses the default grid}", + "{} → {grid: the model (as perspective.grid.set takes it), define: the Define Grid fields (as perspective.grid.define takes them; name is the preset only while the grid still has its fields, else \"\" for custom: dragging the horizon, a vanishing point or the station point makes it custom, moving a plane does not), station: {x, y, distance} (the viewer: centre of vision on the horizon, distance to the picture plane, pt), defined: false while the document uses the default grid}", has_doc, grid_get ), @@ -222,7 +222,13 @@ pub(crate) fn grid_info(doc: &vectorcraft_doc::Document, g: &PerspectiveGrid) -> fn grid_get(s: &mut Session, _: &Value) -> Result { let doc = &s.doc()?.doc; - Ok(grid_info(doc, &grid_of(doc))) + let g = grid_of(doc); + let mut info = grid_info(doc, &g); + // The grid is its preset only while it has the preset's fields: a station point or vanishing + // point dragged since makes it a custom grid. + let def = g.definition(); + info["define"]["name"] = json!(s.preset_named(&def, &[&def.name])); + Ok(info) } fn grid_define(s: &mut Session, p: &Value) -> Result { diff --git a/crates/engine/src/tests/perspgrid.rs b/crates/engine/src/tests/perspgrid.rs index b2cb7cba9..07fce547d 100644 --- a/crates/engine/src/tests/perspgrid.rs +++ b/crates/engine/src/tests/perspgrid.rs @@ -342,6 +342,23 @@ fn lock_station_point_swings_the_other_vanishing_point() { assert!(n.viewing_angle() < 45.0); } +#[test] +fn a_grid_dragged_off_its_preset_reports_no_preset_name() { + let mut s = session(); + run(&mut s, "perspective.grid.preset", json!({"name": "[1P-Normal View]"})); + let name = |s: &mut Session| run(s, "perspective.grid.get", json!({}))["define"]["name"].clone(); + assert_eq!(name(&mut s), json!("[1P-Normal View]")); + // Moving a plane keeps the definition: still the preset. + run(&mut s, "perspective.plane.move", json!({"plane": "ground", "by": 50})); + assert_eq!(name(&mut s), json!("[1P-Normal View]")); + let g = grid(&s); + drag(&mut s, "perspectiveGrid", Point::new(g.vp_left, g.horizon), Point::new(g.vp_left - 40.0, g.horizon - 60.0)); + assert!(!near(grid(&s).horizon, g.horizon), "the horizon moved"); + assert_eq!(name(&mut s), json!(""), "a custom grid now"); + s.execute("edit.undo", &json!({})).unwrap(); + assert_eq!(name(&mut s), json!("[1P-Normal View]")); +} + #[test] fn snap_to_grid_lands_drawn_and_moved_art_on_gridlines() { let mut s = session(); diff --git a/docs/mcp.md b/docs/mcp.md index de4a76d6f..7bce52793 100644 --- a/docs/mcp.md +++ b/docs/mcp.md @@ -6053,7 +6053,9 @@ a stroke when it has `rect`. With both `rect` and `points`, the command also tou ## Perspective grid The grid is document data (`perspective.grid.set` edits the model directly). `perspective.grid.get` reads it: -`grid` (the model), `define` (the Define Grid fields), `station` (the viewer: `x` the centre of vision on the +`grid` (the model), `define` (the Define Grid fields; its `name` is the preset only while the grid still has that +preset's fields, else `""` for a custom grid, so dragging the horizon, a vanishing point or the station point clears it +and moving a plane does not), `station` (the viewer: `x` the centre of vision on the horizon `y`, `distance` from the picture plane, in points) and `defined` (false while the document uses the default grid). `perspective.grid.define` sets the grid from the Define Grid fields: `kind`, `units`, `scale` (`[artboard, real world]`), `gridline`, `angle` (the viewing angle, 0–90°), `distance` (the viewing distance),