Layers: Alt-click an eye or lock runs Hide/Lock Others and Show/Unlock All (review of #301)
Illustrator's Alt-click on a layer's eye hides the other layers and, once they are hidden, shows every layer again; the lock column does the same with Lock Others and Unlock All Layers. Reuse the panel menu's commands (one undo step each, named as the menu items) instead of toggling the row's siblings, so a sublayer's or an object's row stands for its top-level layer. Document it in the ROADMAP and docs/mcp.md. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
59212cb0d4
commit
c074a8031f
|
|
@ -116,7 +116,7 @@ grade by behaviour against `plan/illustrator/`, not by whether a menu item exist
|
|||
- **Temporary tools:** Cmd with any other tool drags with the selection tool used last (Selection, Direct Selection or Group Selection). Held Space pans and Cmd+Space zooms (Cmd+Alt+Space out) whatever the tool.
|
||||
- **Panel drag and drop:** art dragged off the canvas onto the Symbols panel becomes a symbol, and a symbol dragged onto the canvas places an instance where it is dropped.
|
||||
- **Tool double-clicks:** double-clicking a tool's button opens its options: Hand fits the artboard in the window, Zoom shows 100 %, Rotate, Scale, Reflect and Shear open their Object › Transform dialogs, Gradient, Eyedropper, Blend and the Liquify tools their panels or options.
|
||||
- **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, 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, the trash deletes), 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, 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). Layer Options: name, colour (presets 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.
|
||||
- **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, the trash deletes), 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, 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). Layer Options: name, colour (presets 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.
|
||||
- **Drawing aids:** Smart Guides and snapping, guides dragged out of the rulers, and Draw Normal / Behind / Inside modes.
|
||||
- **Views:** the status bar's artboard navigator (first, previous, next, last; `view.goToArtboard`) goes to an artboard and fits it, and Fit Artboard in Window and Actual Size show the navigator's artboard.
|
||||
- **Geometry and effects:**
|
||||
|
|
|
|||
|
|
@ -11,7 +11,9 @@
|
|||
//! another row moves the selected art there (Alt copies it).
|
||||
//! - The eye and lock columns toggle a row (`layer.setProps`); dragging down a column sets every
|
||||
//! row it passes to the same state, in one undo step. Ctrl/Cmd-click an eye switches the layer
|
||||
//! between Preview and Outline.
|
||||
//! between Preview and Outline. Alt-click an eye hides the other layers (`layer.hideOthers`), or
|
||||
//! shows every layer when they are hidden (`layer.showAll`); Alt-click a lock does the same with
|
||||
//! `layer.lockOthers` and `layer.unlockAll`.
|
||||
//! - Dragging rows moves them above, below or into a layer or group (`layer.move`, a drop line or
|
||||
//! a box shows where); Alt copies them; dropped on the trash they are deleted.
|
||||
//! - The triangle opens or closes a row; Alt-click does the same to everything inside it.
|
||||
|
|
@ -543,19 +545,19 @@ fn row(ui: &mut Ui, view: &View, n: &Node, depth: usize, clip_path: bool, expand
|
|||
}
|
||||
}
|
||||
|
||||
/// Alt-clicking row `n`'s eye or lock (`prop`: `visible` or `locked`) toggles that column for the
|
||||
/// other items beside it (the other layers for a layer), in one step: hides or locks them while
|
||||
/// any of them is shown or unlocked, else shows or unlocks them all. → the action, if there are
|
||||
/// others.
|
||||
fn others_action(doc: &Document, n: &Node, prop: &str) -> Option<(String, Value)> {
|
||||
let siblings = doc.children(doc.parent_of(n.id))?;
|
||||
let others: Vec<&Node> = siblings.iter().map(|c| &**c).filter(|c| c.id != n.id).collect();
|
||||
if others.is_empty() {
|
||||
return None;
|
||||
}
|
||||
let value = if prop == "visible" { !others.iter().any(|o| o.visible) } else { others.iter().any(|o| !o.locked) };
|
||||
let ids: Vec<u64> = others.iter().map(|o| o.id.0).collect();
|
||||
Some(("layer.setProps".into(), json!({ "ids": ids, prop: value })))
|
||||
/// Alt-clicking row `n`'s eye (`eye`) or lock: Hide Others or Lock Others, every top-level layer
|
||||
/// but the one holding the row; when they all are hidden (locked) already, Show All Layers (Unlock
|
||||
/// All Layers). Each is one undo step.
|
||||
fn others_action(doc: &Document, n: &Node, eye: bool) -> (String, Value) {
|
||||
let own = doc.layer_of(n.id);
|
||||
let mut others = doc.layers.iter().filter(|l| Some(l.id) != own);
|
||||
let cmd = match (eye, if eye { others.any(|l| l.visible) } else { others.any(|l| !l.locked) }) {
|
||||
(true, true) => "layer.hideOthers",
|
||||
(true, false) => "layer.showAll",
|
||||
(false, true) => "layer.lockOthers",
|
||||
(false, false) => "layer.unlockAll",
|
||||
};
|
||||
(cmd.into(), json!({ "ids": [n.id.0] }))
|
||||
}
|
||||
|
||||
/// The eye and lock columns of row `n` at `r`.
|
||||
|
|
@ -590,7 +592,7 @@ fn eye_and_lock(ui: &mut Ui, view: &View, n: &Node, r: egui::Rect, out: &mut Out
|
|||
let m = ui.input(|i| i.modifiers);
|
||||
if er.clicked() {
|
||||
if m.alt {
|
||||
out.actions.extend(others_action(view.doc, n, "visible"));
|
||||
out.actions.push(others_action(view.doc, n, true));
|
||||
} else if m.command && n.is_layer() {
|
||||
// Ctrl/Cmd-click: Preview ↔ Outline for this layer.
|
||||
out.actions.push(("layer.setProps".into(), json!({"ids": [n.id.0], "preview": !preview})));
|
||||
|
|
@ -599,7 +601,7 @@ fn eye_and_lock(ui: &mut Ui, view: &View, n: &Node, r: egui::Rect, out: &mut Out
|
|||
}
|
||||
}
|
||||
if lr.clicked() && m.alt {
|
||||
out.actions.extend(others_action(view.doc, n, "locked"));
|
||||
out.actions.push(others_action(view.doc, n, false));
|
||||
} else if lr.clicked() {
|
||||
out.actions.push(("layer.setProps".into(), json!({"ids": [n.id.0], "locked": !n.locked})));
|
||||
}
|
||||
|
|
@ -1039,12 +1041,26 @@ mod tests {
|
|||
assert_eq!(undo(&app), before + 1);
|
||||
click(&mut app, eye, true);
|
||||
assert_eq!(state(&app), [(true, false); 3]);
|
||||
// Alt-click its lock: the others lock.
|
||||
// Alt-click its lock: the others lock; again, every layer unlocks.
|
||||
click(&mut app, lock, true);
|
||||
assert_eq!(state(&app), [(true, true), (true, false), (true, true)]);
|
||||
assert_eq!(app.session.active().unwrap().history.undo.last().map(|u| u.label.as_str()), Some("Lock Others"));
|
||||
// A plain click still toggles only that layer.
|
||||
click(&mut app, eye, false);
|
||||
assert_eq!(state(&app), [(true, true), (false, false), (true, true)]);
|
||||
click(&mut app, lock, true);
|
||||
assert_eq!(state(&app), [(true, false), (false, false), (true, false)]);
|
||||
// A sublayer's row stands for its top-level layer: the other layers hide.
|
||||
click(&mut app, eye, false);
|
||||
let layer2 = app.session.active().unwrap().doc.layers[1].id.0;
|
||||
let sub = run(&mut app, "layer.newSublayer", json!({"parent": layer2}));
|
||||
// Rows: Layer 3, Layer 2, its sublayer, Layer 1.
|
||||
let (circles, _) = frame(&mut app, &ctx, vec![], false);
|
||||
assert_eq!(circles.len(), 4);
|
||||
click(&mut app, egui::pos2(12.0, circles[2].y), true);
|
||||
assert_eq!(state(&app), [(false, false), (true, false), (false, false)]);
|
||||
let doc = &app.session.active().unwrap().doc;
|
||||
assert!(doc.node(NodeId(sub["id"].as_u64().unwrap())).unwrap().visible);
|
||||
}
|
||||
|
||||
/// A document with two rectangles on one layer → (app, layer, [bottom, top]).
|
||||
|
|
|
|||
|
|
@ -752,7 +752,8 @@ and `layerRows`, the rows highlighted in the panel.
|
|||
templates stay), `layer.collectInNew {ids?}`, `layer.releaseToLayers {id?, build?}` and
|
||||
`layer.releaseToLayersBuild` (each object of a layer or group in a sublayer of its own; Build adds up copies),
|
||||
`layer.reverse {ids?}`, `layer.template {ids?, on?}`, `layer.hideOthers` / `layer.showAll`,
|
||||
`layer.outlineOthers` / `layer.previewAll`, `layer.lockOthers` / `layer.unlockAll`, `layer.pasteRemembersLayers`,
|
||||
`layer.outlineOthers` / `layer.previewAll`, `layer.lockOthers` / `layer.unlockAll` (Alt-clicking an eye or a lock
|
||||
runs Hide or Lock Others for the row's layer, or Show or Unlock All when the others already are), `layer.pasteRemembersLayers`,
|
||||
`object.isolate {id}` / `object.exitIsolation`.
|
||||
- **Dialogs and panel state** (control channel and the app's MCP): `ui.layerOptions {ids?}` and `ui.newLayer
|
||||
{sublayer?}` open Layer Options (dialog `layerOptions`: name, color, template, locked, visible, printable, preview,
|
||||
|
|
|
|||
Loading…
Reference in New Issue