Layers: a plain click on another row lets go of the selected guide (#7340)

This commit is contained in:
datatimp
2026-11-13 23:44:33 -05:00
parent 1e4e3534f5
commit 2610d97cd4
4 changed files with 51 additions and 3 deletions
+7 -1
View File
@@ -81,7 +81,9 @@ pub(super) fn drag_ghost(ui: &Ui, view: &View, src: NodeId, pos: egui::Pos2) {
}
/// Resolve the row clicked this frame: plain (highlight it), Ctrl/Cmd (toggle it) or Shift
/// (highlight the rows from the last one clicked down to it).
/// (highlight the rows from the last one clicked down to it). A plain click also lets go of the
/// selected ruler guides, keeping the selected art (#7340): a guide's row picks it the way a
/// highlight picks a row, so picking another row alone drops it.
pub(super) fn resolve_click(ui: &Ui, view: &View, list: &[Row], out: &mut Out) {
let Some((id, m)) = out.click.take() else { return };
let anchor: Option<NodeId> = ui.data(|d| d.get_temp(key("anchor")));
@@ -95,6 +97,10 @@ pub(super) fn resolve_click(ui: &Ui, view: &View, list: &[Row], out: &mut Out) {
widgets::apply_row_click(&mut rows, &click);
out.rows_after_click = Some(rows);
let ids = |rows: &[NodeId]| rows.iter().map(|r| r.0).collect::<Vec<_>>();
if matches!(click, widgets::RowClick::Only(_)) && !view.guides.is_empty() {
// Toggled out of the selection, so the selected art stays.
out.actions.push(("guide.select".into(), json!({"indexes": view.guides, "toggle": true})));
}
out.actions.push(match click {
widgets::RowClick::Only(id) => ("layer.setCurrent".into(), json!({"id": id.0})),
widgets::RowClick::Toggle(id) => ("layer.highlight".into(), json!({"ids": [id.0], "mode": "toggle"})),
+42
View File
@@ -987,6 +987,48 @@ fn guide_rows_are_deleted_with_the_trash_and_delete() {
assert!(kept(&app));
}
/// A plain click on another row lets go of the guide a guide row selected, keeping the selected
/// art, so a guide can be dropped without Ctrl/Cmd-clicking its own row (#7340); a Ctrl/Cmd click
/// on a row adds to the pick and keeps it.
#[test]
fn a_plain_row_click_lets_go_of_the_selected_guide() {
let mut app = VectorcraftApp::new(Session::new(), Default::default());
let run = |app: &mut VectorcraftApp, id: &str, p: serde_json::Value| app.session.execute(id, &p).unwrap();
run(&mut app, "file.new", json!({"width": 200, "height": 200}));
let rect = NodeId(run(&mut app, "shape.rectangle", json!({"x": 0, "y": 0, "width": 20, "height": 20}))["id"].as_u64().unwrap());
run(&mut app, "guide.add", json!({"vertical": true, "pos": 50}));
run(&mut app, "select.none", json!({}));
expand(&mut app, &json!({})).unwrap();
let ctx = egui::Context::default();
// Rows top down: Layer 1, its guide (no target circle), the rectangle.
let (circles, _) = frame(&mut app, &ctx, vec![], false);
assert_eq!(circles.len(), 2);
let guide_row = egui::pos2(150.0, (circles[0].y + circles[1].y) / 2.0);
let rect_row = egui::pos2(150.0, circles[1].y);
let guides = |app: &VectorcraftApp| {
let st = app.session.active().unwrap();
vectorcraft_engine::cmd::guide_indexes(&st.doc, &st.selection.guides)
};
let art = |app: &VectorcraftApp| app.session.active().unwrap().selection.objects.clone();
// Guide, then the rectangle's row: the guide is let go and the rectangle's row highlighted.
click_with(&mut app, &ctx, guide_row, egui::Modifiers::NONE);
assert_eq!(guides(&app), [0]);
click_with(&mut app, &ctx, rect_row, egui::Modifiers::NONE);
assert!(guides(&app).is_empty(), "a plain row click drops the guide");
assert_eq!(app.session.active().unwrap().highlighted_rows(), [rect]);
// Art and a guide selected together: a plain row click drops only the guide.
run(&mut app, "select.all", json!({}));
click_with(&mut app, &ctx, guide_row, egui::Modifiers::SHIFT);
assert_eq!((guides(&app), art(&app)), (vec![0], vec![rect]));
click_with(&mut app, &ctx, egui::pos2(150.0, circles[0].y), egui::Modifiers::NONE);
assert!(guides(&app).is_empty());
assert_eq!(art(&app), [rect], "the selected art stays");
// A Ctrl/Cmd click on a row adds that row to the highlight and keeps the guide.
click_with(&mut app, &ctx, guide_row, egui::Modifiers::NONE);
click_with(&mut app, &ctx, rect_row, egui::Modifiers::COMMAND);
assert_eq!(guides(&app), [0], "a Ctrl/Cmd row click keeps the guide");
}
/// The selection squares drawn: (big ones on rows whose object is selected, small ones on rows
/// holding selected art).
fn squares(app: &mut VectorcraftApp, ctx: &egui::Context) -> (usize, usize) {
+1 -1
View File
@@ -1165,7 +1165,7 @@ Moved from the ROADMAP's "Shipped so far" on 2026-10-10. Update it when a featur
The Blob Brush Tool Options' tip preview is the Angle slider for screen readers, with the Angle in degrees as its value: a click or a drag in it points the Angle at the pointer and gives it the keyboard focus, Tab reaches it after the Roundness field, and the arrow keys step the Angle by 1° (10° with Shift, Home and End to −180° and 180°).
The Blob Brush Tool Options also have Fidelity, which the reference app's [Blob Brush options](https://web.archive.org/web/20261012042029/https://helpx.adobe.com/illustrator/desktop/paint-and-fill/learn-painting-basics/blob-brush-options-and-best-practices.html) list as setting how far the pointer moves before the path gets a new anchor point. The range and default are VectorCraft's own values: the Pencil's logarithmic slider from Accurate (0.01 pt) to Smooth (20 pt) and its field (up to 100 pt), 1.5 pt by default and kept with the tool's options. The brush follows the stroke fitted at the Fidelity, as a Pencil stroke is fitted: a low value follows the drag closely, jitter included, and a higher one gives smoother curves (`path.blob` `fidelity`).
A Blob Brush stroke merges with the topmost path of its fill color and no stroke that it touches, and with the other such paths it touches in the same group or layer that are next to that path in stacking order with no other kind of object between them; matching paths in other groups or layers are left alone, as the Blob Brush tool guidelines in [Paint with fills and strokes](https://web.archive.org/web/20241219085603/https://helpx.adobe.com/illustrator/using/painting-fills-strokes.html) describe (`path.blob`).
- **Ruler guides as layer objects:** a guide goes on the current layer, shows, hides, locks and is deleted with it, is listed in the Layers panel (its row selects it) and moves to another layer (`guide.setLayer`, or its row dragged onto that layer's rows); guides on a hidden or locked layer can't be selected, moved or deleted, Duplicate copies a layer's guides and Merge Selected and Flatten Artwork keep them on the merged layer; guides from files saved before guides had layers go on the top visible, unlocked layer when the document opens. A guide's row has its own eye and lock, which hide or lock that guide alone in one undo step and take part in a drag down either column ([help page](https://helpx.adobe.com/in_hi/tutorial-builder/user-guide/illustrator-tutorial-builder/-ai--examples-of-common-coach-marks.html) lists a Guide among the Layers panel's items); a hidden guide is not drawn and does not snap, a locked one is drawn and snaps but can't be selected, moved or deleted, and its own state is kept through save and reopen and while its layer is hidden or locked (`layer.setProps` on its `guide.list` id). Object › Lock › Selection and Object › Hide › Selection lock or hide a selected guide with the selected art, and Unlock All and Show All unlock or show such guides and select them ([help page](https://help.adobe.com/archive/en_US/illustrator/cs3/illustrator_cs3_help.pdf) for Lock and Hide Selection). A guide row dropped on the panel's trash deletes its guide, the trash deletes a guide its row selected, and after a click on a guide row Delete deletes the guide rather than the rows highlighted before ([help page](https://helpx.adobe.com/illustrator/desktop/measure-and-align/grids-and-guides/align-graphic-objects-with-guides.html) for deleting a selected guide). Not done: guides stacked among the art of their layer (they are listed above it). Lock Guides also locks the objects made into guides: they can't be selected, moved or deleted (#1543); they are drawn in the guide colour and style of Preferences, and a dragged selection snaps to ruler guides with Smart Guides on (#1583, fixes #1534). Preferences › Guides & Grid › Lock Guides by Default locks guides when the app starts; it is off by default, and new guides can still be dragged out of a ruler while guides are locked. The Transform panel shows a selected ruler guide's X or Y, and typing a value moves it (#1659, part of #1597). This is not established by the documentation we could find: the public help pages on guides, rulers and the Transform, Control and Properties panels (read again on 2026-10-14) describe selecting and dragging unlocked guides and the panels' X and Y for a selection, not a guide's position in a panel, and the one public statement of it is a user's [community answer](https://community.adobe.com/questions-652/adding-a-new-custom-guide-785586), which is not documentation. It is kept as a convenience pending the owner's decision, with no parity claim and nothing counted towards a score.
- **Ruler guides as layer objects:** a guide goes on the current layer, shows, hides, locks and is deleted with it, is listed in the Layers panel (its row selects it) and moves to another layer (`guide.setLayer`, or its row dragged onto that layer's rows); guides on a hidden or locked layer can't be selected, moved or deleted, Duplicate copies a layer's guides and Merge Selected and Flatten Artwork keep them on the merged layer; guides from files saved before guides had layers go on the top visible, unlocked layer when the document opens. A guide's row has its own eye and lock, which hide or lock that guide alone in one undo step and take part in a drag down either column ([help page](https://helpx.adobe.com/in_hi/tutorial-builder/user-guide/illustrator-tutorial-builder/-ai--examples-of-common-coach-marks.html) lists a Guide among the Layers panel's items); a hidden guide is not drawn and does not snap, a locked one is drawn and snaps but can't be selected, moved or deleted, and its own state is kept through save and reopen and while its layer is hidden or locked (`layer.setProps` on its `guide.list` id). Object › Lock › Selection and Object › Hide › Selection lock or hide a selected guide with the selected art, and Unlock All and Show All unlock or show such guides and select them ([help page](https://help.adobe.com/archive/en_US/illustrator/cs3/illustrator_cs3_help.pdf) for Lock and Hide Selection). A guide row dropped on the panel's trash deletes its guide, the trash deletes a guide its row selected, and after a click on a guide row Delete deletes the guide rather than the rows highlighted before ([help page](https://helpx.adobe.com/illustrator/desktop/measure-and-align/grids-and-guides/align-graphic-objects-with-guides.html) for deleting a selected guide). A plain click on another row lets go of a guide its row selected, keeping the selected art, as a plain click on a row picks that row alone; a Ctrl/Cmd or Shift click keeps it (#7340, `panels::layers` test `a_plain_row_click_lets_go_of_the_selected_guide`). Not done: guides stacked among the art of their layer (they are listed above it). Lock Guides also locks the objects made into guides: they can't be selected, moved or deleted (#1543); they are drawn in the guide colour and style of Preferences, and a dragged selection snaps to ruler guides with Smart Guides on (#1583, fixes #1534). Preferences › Guides & Grid › Lock Guides by Default locks guides when the app starts; it is off by default, and new guides can still be dragged out of a ruler while guides are locked. The Transform panel shows a selected ruler guide's X or Y, and typing a value moves it (#1659, part of #1597). This is not established by the documentation we could find: the public help pages on guides, rulers and the Transform, Control and Properties panels (read again on 2026-10-14) describe selecting and dragging unlocked guides and the panels' X and Y for a selection, not a guide's position in a panel, and the one public statement of it is a user's [community answer](https://community.adobe.com/questions-652/adding-a-new-custom-guide-785586), which is not documentation. It is kept as a convenience pending the owner's decision, with no parity claim and nothing counted towards a score.
- **Releasing ruler guides:** View › Guides › Release Guides turns the selected ruler guides into paths with no fill or stroke. An artboard guide becomes a line across its artboard, and a canvas guide becomes a line across the artboards (`view.guides.release {index?, ids?}`). A Cmd/Ctrl+Shift double-click with the Selection, Direct Selection or Group Selection tool releases the ruler guide or guide path under the pointer.
- **Layers panel:** every layer, sublayer, group and object is a clickable row at any depth: a click highlights it and makes its layer current (new art goes there), Shift-click a range, Ctrl/Cmd-click toggles. Sublayers are no longer treated as objects: clicks, marquees, Select All and the Select menu take the art inside them, and each sublayer selects in its own colour. Selection squares on rows with selected art (click selects a row's art, Shift adds or removes; dragging the square moves the selection to another row, Alt copies), the eye and lock on every row with drag-down-the-column (one undo step), Ctrl/Cmd-click an eye for per-layer Outline, Alt-click an eye or lock to hide or lock the other layers (again: show or unlock them all), triangles with Alt to open or close everything inside, drag and drop rows above, below or into layers and groups with a drop line (Alt copies) and a dimmed copy of the row under the pointer (layers dropped in the empty space under the last row go below the bottom layer, #2260; dropped on the trash rows are deleted, on New Layer duplicated, as in Illustrator), inline rename, Delete key on highlighted rows. Buttons and the full panel menu: New Layer/Sublayer (Alt: options, Ctrl: on top), Duplicate, Delete, Options for Selection, clipping mask, isolation, Locate Object, Merge Selected, Flatten Artwork, Collect in New Layer, Collect for Export (As Single Asset, As Multiple Assets), Release to Layers (Sequence and Build), Reverse Order, Template, Hide/Outline/Lock Others and Show/Preview/Unlock All, Paste Remembers Layers, Panel Options (row size, thumbnails per kind, Show Layers Only). Right-clicking a layer, sublayer, group or object row offers Collect for Export for that row, or for every highlighted row when it is one of them; guide and blend spine rows have no context menu. Layer Options: name, colour (presets, each with a chip of its colour, or custom), Template, Lock, Show, Print, Preview (outline drawing and clicking) and Dim Images to %. Every operation is a command (`layer.move`, `layer.highlight`, `layer.merge`…) with validation against cycles and invalid nesting. A document opens with only its top-level layers open; the rows left open are saved in the native file (nothing is written for the default) and reopen that way. Only the rows scrolled into view are laid out, from a row list made once per change: a layer of 5,000 groups of 10 paths, all open, draws the panel in 0.4 ms a frame instead of about 29 s (#638).
With Paste Remembers Layers on, art copied from a sublayer pastes back into that sublayer, as [the help page](https://help.adobe.com/archive/en_US/illustrator/cs5/illustrator_cs5_help.pdf#page=223) describes art going back to the layer it was copied from: in the same document while the sublayer is still there, two sublayers of the same name in different layers kept apart; in another document by the names of the sublayer and the layers around it. These rules are VectorCraft's own: a missing sublayer is made inside its layer (a missing layer on top, with the sublayer inside it), in the paste's one undo step; of layers with the same names, the topmost chain that matches the most names wins, a shown and unlocked one first; a matched layer that is hidden or locked, or inside one that is, refuses the paste, and nothing is pasted.
+1 -1
View File
@@ -250,7 +250,7 @@ tools, never checked side by side) isn't captured row by row.
| A double-click on a ruler adds a guide at the pointer: a vertical one on the top ruler, a horizontal one on the left ruler (swapped in a view turned 90°, where the rulers read the other document axis; the nearer axis in between), exactly where the pointer is (no snapping), shown even with guides hidden, one undo step (`guide.add`); both clicks of the pair must be on that ruler, and the first adds nothing. The [public page on rulers](https://helpx.adobe.com/illustrator/desktop/measure-and-align/grids-and-guides/use-rulers.html) doesn't describe this gesture, so it follows the request in #5239 | done | #5239; an artboard guide with the Artboard tool, as a drag from a ruler makes one; `canvas/tests.rs` `double_clicking_a_ruler_adds_a_guide_at_that_position`, `a_canvas_click_then_a_ruler_click_adds_no_guide`, `a_ruler_double_click_follows_a_rotated_view` |
| Escape cancels an existing ruler-guide press, move or copy | done | Selection and Direct/Group Selection; app-input regressions cover preselected guides, document/interaction-start selection, Undo/Redo and saved state, later on-canvas motion/release and temporary borrowing from idle Pen. All eight checks and the Direct Selection Escape control passed in current full CI. [Validation evidence](target-app-parity.md#evidence-what-ships-today-by-area) |
| Ruler origin: corner drag with preview, snapped as a drawn point is (Smart Guides, Snap to Point and the ruler guides, pixels, the grid), double-click reset to the active artboard, relative X/Y fields, native save/reopen | done | #1212; `document.setRulerOrigin`, `document.resetRulerOrigin`; geometry and command coordinates stay absolute |
| Ruler guides as Layers rows: shown, hidden, locked and deleted with their layer; rows dragged to another layer; each row's own eye and lock; a row dropped on the trash deletes its guide | done | `guide.setLayer`; guides from older files go on a layer; `layer.setProps` on a guide's id hides or locks it alone; Object › Lock/Hide › Selection, Unlock All and Show All reach guides; `guide.remove {indexes}` |
| Ruler guides as Layers rows: shown, hidden, locked and deleted with their layer; rows dragged to another layer; each row's own eye and lock; a row dropped on the trash deletes its guide; a plain click on another row lets go of the guide | done | `guide.setLayer`; guides from older files go on a layer; `layer.setProps` on a guide's id hides or locks it alone; Object › Lock/Hide › Selection, Unlock All and Show All reach guides; `guide.remove {indexes}`; #7340 |
| Objects made into guides: drawn in the guide colour and style of Preferences; Lock Guides locks them too (no select, move or delete); a dragged selection snaps to ruler guides with Smart Guides on, by the nearest point of the path when pressed on its stroke or beside its edge, so the path lands exactly on the guide | done | #1534 (#1543, #1583); #3701 |
| A selected ruler guide's X or Y in the Transform panel; typing a value moves it | not scored | #1659 (part of #1597); several guides move together; not in Properties or the Control bar. Not established by the documentation we could find: the help pages on guides, rulers and the Transform, Control and Properties panels (read again on 2026-10-14) don't describe it, and the one public statement is a user's [community answer](https://community.adobe.com/questions-652/adding-a-new-custom-guide-785586), which is not documentation. Kept as a convenience pending the owner's decision; no parity claim |
| Alt swaps a ruler guide's orientation while dragging | missing | Alt-drag copies the selected guides ([Use rulers](https://helpx.adobe.com/illustrator/desktop/measure-and-align/grids-and-guides/use-rulers.html)); `guide.move` `{copy: true}` |