Merge pull request #4753 from dotCooCoo/feat/lock-unselected-objects-key

Object: Cmd/Ctrl+Alt+Shift+2 locks every unselected object
This commit is contained in:
BFlat
2026-10-31 04:01:26 +07:00
committed by GitHub
6 changed files with 249 additions and 20 deletions
+38 -14
View File
@@ -56,6 +56,15 @@ pub fn specs() -> Vec<CommandSpec> {
has_selection_outside_isolation,
|s, _| other_layers(s, true)
),
cmd!(
"object.lock.unselected",
"Unselected Artwork",
["Object", "Lock"],
Some("Cmd+Alt+Shift+2"),
"{} lock unselected artwork in one undo step, including unselected members of partly selected groups, clipping groups and compound paths, and guides while Lock Guides is on; hidden art and art on locked layers stay unlocked; a selected layer's art counts as selected; in isolation, only art inside the isolated object is affected; object.unlockAll unlocks locked art document-wide → {count}",
has_selection,
|s, _| unselected_art(s, true)
),
cmd!(
"object.hide.above",
"All Artwork Above",
@@ -81,7 +90,7 @@ pub fn specs() -> Vec<CommandSpec> {
Some("Cmd+Alt+Shift+3"),
"{} hide, in one undo step, every object select.all takes that is not selected and holds no selected object; in a group that holds one it hides the other members one by one, and a clip group, compound path or other object that holds one stays as it is; the objects of a selected layer count as selected; while Lock Guides is on, guide paths count as selected and stay as they are; object.showAll shows them again; disabled in isolation mode → {count}",
has_selection_outside_isolation,
hide_unselected
|s, _| unselected_art(s, false)
),
cmd!(
"object.transformEach",
@@ -321,15 +330,24 @@ fn other_layers(s: &mut Session, lock: bool) -> Result<Value> {
Ok(json!({ "count": n }))
}
/// The objects [`super::select::walk_selectable`] visits that are not among the selected objects `roots` and hold none of
/// them. The objects of a selected layer count as selected. Guide paths are left out while `guides_locked`, and so are
/// the objects that hold one. The walk goes into a plain group that holds a selected object or such a guide path; a
/// clip group, a Shaper group, a compound path and every other object that holds one is left out with its members.
fn unselected(d: &vectorcraft_doc::Document, iso: Option<NodeId>, selection: &[NodeId], roots: &[NodeId], guides_locked: bool) -> Vec<NodeId> {
/// Returns the objects [`super::select::walk_selectable`] visits that are not among the selected objects `roots` and
/// hold none of them. A selected layer's objects count as selected. The walk goes into a plain group, but not a Shaper
/// group, that holds a selected object. With `lock`, it also goes into a clip group or compound path that holds one,
/// and includes guide paths while `guides_locked`. Without `lock`, guide paths and the objects that hold one are left
/// out while `guides_locked`; a clip group, Shaper group, compound path and every other object that holds a selected
/// object or such a guide are left out with their members.
fn unselected(
d: &vectorcraft_doc::Document,
iso: Option<NodeId>,
selection: &[NodeId],
roots: &[NodeId],
guides_locked: bool,
lock: bool,
) -> Vec<NodeId> {
let mut roots: HashSet<NodeId> = roots.iter().copied().collect();
roots.extend(selection.iter().filter_map(|id| d.node(*id)).filter(|n| n.is_layer()).flat_map(|l| l.layer_art(true)));
let mut kept: Vec<NodeId> = roots.iter().copied().collect();
if guides_locked {
if guides_locked && !lock {
super::select::walk_selectable(d, iso, |n| {
if matches!(n.kind, NodeKind::Path { guide: true, .. }) {
kept.push(n.id);
@@ -344,24 +362,30 @@ fn unselected(d: &vectorcraft_doc::Document, iso: Option<NodeId>, selection: &[N
out.push(n.id);
return false;
}
!roots.contains(&n.id) && matches!(n.kind, NodeKind::Group { clip: false, .. }) && n.extras().shaper.is_none()
!roots.contains(&n.id)
&& (matches!(n.kind, NodeKind::Group { clip: false, .. }) && n.extras().shaper.is_none()
|| lock && (matches!(n.kind, NodeKind::Group { clip: true, .. } | NodeKind::Compound { .. })))
});
out
}
fn hide_unselected(s: &mut Session, _: &Value) -> Result<Value> {
fn unselected_art(s: &mut Session, lock: bool) -> Result<Value> {
let roots = selected_roots_to_transform(s)?;
let guides_locked = s.menu.guides_locked;
let st = s.doc()?;
let ids = unselected(&st.doc, st.isolation, &st.selection.objects, &roots, guides_locked);
// With nothing to hide, the document and its undo history stay as they are.
let ids = unselected(&st.doc, st.isolation, &st.selection.objects, &roots, guides_locked, lock);
// With nothing to lock (Lock) or hide (Hide), the document and its undo history stay as they are.
if !ids.is_empty() {
s.edit("Hide", |d, _| {
// Hiding moves no node in the tree, so the paths found up front stay right.
s.edit(if lock { "Lock" } else { "Hide" }, |d, _| {
// Locking and hiding move no node in the tree, so the paths found up front stay right.
let paths = d.index_paths(ids.iter().copied());
for id in &ids {
if let Some(n) = paths.get(id).and_then(|p| d.node_mut_at(p)) {
n.visible = false;
if lock {
n.locked = true;
} else {
n.visible = false;
}
}
}
Ok(())
+159 -5
View File
@@ -518,8 +518,9 @@ fn lock_and_hide_with_nothing_to_lock_or_hide_record_no_undo_step() {
/// Hide › Unselected Artwork hides, in one undo step, each object that is not selected and holds no selected object:
/// here `b`, the member `n` of the group that holds the selected `m`, and `p` on another layer. The selected objects,
/// that group, the clip group that holds the selected `c2` with all its members, a locked object, the art on a locked
/// layer and an object hidden before stay as they are, and so does the selection. Show All shows them again.
/// that group, the clip group that holds the selected `c2` with all its members, the compound path that holds the
/// selected `hole` with both paths, a guide under Lock Guides, a locked object, the art on a locked layer and an
/// object hidden before stay as they are, and so does the selection. Show All shows them again.
#[test]
fn hide_unselected_artwork_hides_every_object_that_is_not_selected() {
let mut s = session();
@@ -534,6 +535,14 @@ fn hide_unselected_artwork_hides_every_object_that_is_not_selected() {
let c3 = rect(&mut s, 80.0, 0.0, 30.0, 30.0);
sel(&mut s, &[c1, c2, c3]);
let clip = id_of(&s.execute("object.clippingMask.make", &json!({})).unwrap());
let outer = rect(&mut s, 0.0, 200.0, 100.0, 100.0);
let hole = rect(&mut s, 40.0, 240.0, 20.0, 20.0);
sel(&mut s, &[outer, hole]);
let compound = id_of(&s.execute("object.compoundPath.make", &json!({})).unwrap());
let guide = rect(&mut s, 200.0, 0.0, 10.0, 10.0);
sel(&mut s, &[guide]);
s.execute("view.guides.make", &json!({})).unwrap();
s.execute("view.guides.lock", &json!({"locked": true})).unwrap();
let k = rect(&mut s, 120.0, 0.0, 10.0, 10.0);
s.execute("layer.setProps", &json!({"id": k.0, "locked": true})).unwrap();
let h = rect(&mut s, 140.0, 0.0, 10.0, 10.0);
@@ -544,13 +553,13 @@ fn hide_unselected_artwork_hides_every_object_that_is_not_selected() {
let q = rect(&mut s, 20.0, 100.0, 10.0, 10.0);
s.execute("layer.setProps", &json!({"id": locked_layer.0, "locked": true})).unwrap();
let shown = |s: &Session, ids: &[NodeId]| ids.iter().map(|id| node(s, *id).visible).collect::<Vec<_>>();
sel(&mut s, &[a, m, c2]);
sel(&mut s, &[a, m, c2, hole]);
let steps = undo_len(&s);
assert_eq!(s.execute("object.hide.unselected", &json!({})).unwrap(), json!({"count": 3}));
assert_eq!(shown(&s, &[b, n, p, h]), [false; 4]);
assert_eq!(shown(&s, &[a, m, g, c1, c2, c3, clip, k, q]), [true; 9]);
assert_eq!(shown(&s, &[a, m, g, c1, c2, c3, clip, compound, outer, hole, guide, k, q]), [true; 13]);
assert!(node(&s, k).locked);
assert_eq!((undo_len(&s), selected(&s)), (steps + 1, vec![a, m, c2]));
assert_eq!((undo_len(&s), selected(&s)), (steps + 1, vec![a, m, c2, hole]));
s.execute("edit.undo", &json!({})).unwrap();
assert_eq!(shown(&s, &[b, n, p]), [true; 3]);
s.execute("edit.redo", &json!({})).unwrap();
@@ -650,6 +659,151 @@ fn hide_unselected_artwork_keeps_groups_with_locked_guides_and_the_selected_laye
assert_eq!(selected(&s), [other]);
}
/// Lock Unselected Artwork locks `b`, `n` in the group that holds selected `m`, `p` on another layer, and the clip
/// group's unselected members `c1` and clipping path `c3` in one undo step labeled "Lock". The clip group container,
/// `c2`, the selected objects, group `g`, hidden object `h` and art `q` on a locked layer stay unlocked. `k` was locked
/// before. The selection stays as it is. Unlock All unlocks all six locked objects and selects them.
#[test]
fn lock_unselected_artwork_locks_every_object_that_is_not_selected() {
let mut s = session();
let a = rect(&mut s, 0.0, 0.0, 10.0, 10.0);
let b = rect(&mut s, 20.0, 0.0, 10.0, 10.0);
let m = rect(&mut s, 40.0, 0.0, 10.0, 10.0);
let n = rect(&mut s, 60.0, 0.0, 10.0, 10.0);
sel(&mut s, &[m, n]);
let g = id_of(&s.execute("object.group", &json!({})).unwrap());
let c1 = rect(&mut s, 80.0, 0.0, 10.0, 10.0);
let c2 = rect(&mut s, 85.0, 5.0, 10.0, 10.0);
let c3 = rect(&mut s, 80.0, 0.0, 30.0, 30.0);
sel(&mut s, &[c1, c2, c3]);
let clip = id_of(&s.execute("object.clippingMask.make", &json!({})).unwrap());
let k = rect(&mut s, 120.0, 0.0, 10.0, 10.0);
s.execute("layer.setProps", &json!({"id": k.0, "locked": true})).unwrap();
let h = rect(&mut s, 140.0, 0.0, 10.0, 10.0);
s.execute("layer.setProps", &json!({"id": h.0, "visible": false})).unwrap();
s.execute("layer.new", &json!({})).unwrap();
let p = rect(&mut s, 0.0, 100.0, 10.0, 10.0);
let locked_layer = id_of(&s.execute("layer.new", &json!({})).unwrap());
let q = rect(&mut s, 20.0, 100.0, 10.0, 10.0);
s.execute("layer.setProps", &json!({"id": locked_layer.0, "locked": true})).unwrap();
let locked = |s: &Session, ids: &[NodeId]| ids.iter().map(|id| node(s, *id).locked).collect::<Vec<_>>();
sel(&mut s, &[a, m, c2]);
let steps = undo_len(&s);
assert_eq!(s.execute("object.lock.unselected", &json!({})).unwrap(), json!({"count": 5}));
assert_eq!(locked(&s, &[b, n, p, c1, c3, k]), [true; 6]);
assert_eq!(locked(&s, &[a, m, g, c2, clip, h, q]), [false; 7]);
assert_eq!((undo_len(&s), selected(&s)), (steps + 1, vec![a, m, c2]));
assert_eq!(s.doc().unwrap().history.undo.last().unwrap().label, "Lock");
s.execute("edit.undo", &json!({})).unwrap();
assert_eq!(locked(&s, &[b, n, p]), [false; 3]);
s.execute("edit.redo", &json!({})).unwrap();
assert_eq!(locked(&s, &[b, n, p]), [true; 3]);
assert_eq!(s.execute("object.unlockAll", &json!({})).unwrap(), json!({"count": 6}));
assert_eq!(locked(&s, &[b, n, p, c1, c3, k]), [false; 6]);
let mut unlocked = selected(&s);
unlocked.sort();
let mut want = vec![b, n, p, c1, c3, k];
want.sort();
assert_eq!(unlocked, want);
}
/// Lock Unselected Artwork affects only the isolated group's other members. Lock Guides does not protect an unselected
/// guide from this command. With nothing left to lock it records no undo step.
#[test]
fn lock_unselected_artwork_scopes_isolation_and_locks_guides() {
let mut s = session();
let guide = rect(&mut s, 0.0, 0.0, 10.0, 10.0);
sel(&mut s, &[guide]);
s.execute("view.guides.make", &json!({})).unwrap();
s.execute("view.guides.lock", &json!({"locked": true})).unwrap();
let out = rect(&mut s, 20.0, 0.0, 10.0, 10.0);
let m = rect(&mut s, 40.0, 0.0, 10.0, 10.0);
let n = rect(&mut s, 60.0, 0.0, 10.0, 10.0);
sel(&mut s, &[m, n]);
let g = id_of(&s.execute("object.group", &json!({})).unwrap());
let lock = |s: &mut Session| s.execute("object.lock.unselected", &json!({})).unwrap();
let locked = |s: &Session, ids: &[NodeId]| ids.iter().map(|id| node(s, *id).locked).collect::<Vec<_>>();
s.execute("object.isolate", &json!({"id": g.0})).unwrap();
select_with_a_step_to_redo(&mut s, &[m]);
let info = find_command("object.lock.unselected").unwrap().info(&s);
assert!(info.enabled, "{info:?}");
let before = undo_len(&s);
assert_eq!(lock(&mut s), json!({"count": 1}));
assert_eq!(locked(&s, &[m, n, out, guide]), [false, true, false, false]);
assert_eq!((undo_len(&s), selected(&s)), (before + 1, vec![m]));
s.execute("object.exitIsolation", &json!({})).unwrap();
sel(&mut s, &[m]);
assert!(find_command("object.lock.unselected").unwrap().info(&s).enabled);
assert_eq!(lock(&mut s), json!({"count": 2}));
assert_eq!(locked(&s, &[n, out, guide, g, m]), [true, true, true, false, false]);
select_with_a_step_to_redo(&mut s, &[m]);
let before = history(&s);
assert_eq!(lock(&mut s), json!({"count": 0}));
assert_eq!(history(&s), before);
s.execute("view.guides.lock", &json!({"locked": false})).unwrap();
}
/// Lock Unselected Artwork locks the unselected path of a partly selected compound path, but needs a selection.
#[test]
fn lock_unselected_artwork_descends_into_compound_and_needs_selection() {
let mut s = session();
let outer = rect(&mut s, 0.0, 0.0, 100.0, 100.0);
let hole = rect(&mut s, 40.0, 40.0, 20.0, 20.0);
sel(&mut s, &[outer, hole]);
let compound = id_of(&s.execute("object.compoundPath.make", &json!({})).unwrap());
s.execute("select.none", &json!({})).unwrap();
let before = history(&s);
assert!(!find_command("object.lock.unselected").unwrap().info(&s).enabled);
assert!(matches!(s.execute("object.lock.unselected", &json!({})), Err(EngineError::Disabled(..))));
assert_eq!(history(&s), before);
sel(&mut s, &[hole]);
assert_eq!(s.execute("object.lock.unselected", &json!({})).unwrap(), json!({"count": 1}));
assert!(node(&s, outer).locked);
assert!(!node(&s, hole).locked);
assert!(!node(&s, compound).locked);
assert_eq!(selected(&s), [hole]);
}
/// Lock Unselected Artwork leaves all art on a selected layer unlocked and locks unselected art on another layer.
#[test]
fn lock_unselected_artwork_keeps_a_selected_layers_art() {
let mut s = session();
let selected_layer = id_of(&s.execute("layer.new", &json!({})).unwrap());
let a = rect(&mut s, 0.0, 0.0, 10.0, 10.0);
let b = rect(&mut s, 20.0, 0.0, 10.0, 10.0);
s.execute("layer.new", &json!({})).unwrap();
let other = rect(&mut s, 40.0, 0.0, 10.0, 10.0);
sel(&mut s, &[selected_layer]);
assert_eq!(s.execute("object.lock.unselected", &json!({})).unwrap(), json!({"count": 1}));
assert_eq!([a, b, other].map(|id| node(&s, id).locked), [false, false, true]);
assert_eq!(selected(&s), [selected_layer]);
}
/// In a plain group, Lock and Hide Unselected Artwork affect the same members of identical documents.
#[test]
fn lock_and_hide_unselected_artwork_choose_the_same_objects() {
let prepare = || {
let mut s = session();
let a = rect(&mut s, 0.0, 0.0, 10.0, 10.0);
let b = rect(&mut s, 20.0, 0.0, 10.0, 10.0);
let m = rect(&mut s, 40.0, 0.0, 10.0, 10.0);
let n = rect(&mut s, 60.0, 0.0, 10.0, 10.0);
sel(&mut s, &[m, n]);
let g = id_of(&s.execute("object.group", &json!({})).unwrap());
sel(&mut s, &[a, m]);
(s, [a, b, m, n, g])
};
let (mut locked, lock_ids) = prepare();
let (mut hidden, hide_ids) = prepare();
assert_eq!(lock_ids, hide_ids);
assert_eq!(locked.execute("object.lock.unselected", &json!({})).unwrap(), json!({"count": 2}));
assert_eq!(hidden.execute("object.hide.unselected", &json!({})).unwrap(), json!({"count": 2}));
let changed_by_lock: Vec<_> = lock_ids.into_iter().filter(|id| node(&locked, *id).locked).collect();
let changed_by_hide: Vec<_> = hide_ids.into_iter().filter(|id| !node(&hidden, *id).visible).collect();
assert_eq!(changed_by_lock, changed_by_hide);
assert_eq!(changed_by_lock, [lock_ids[1], lock_ids[3]]);
}
// ---------- Transform Each ----------
#[test]
+5
View File
@@ -677,7 +677,11 @@ fn lock_and_hide_menus_are_greyed_out_in_isolation_mode() {
app.run("file.new", json!({})).unwrap();
let a = app.run("shape.rectangle", json!({"x": 10, "y": 10, "width": 50, "height": 50})).unwrap()["id"].clone();
let b = app.run("shape.rectangle", json!({"x": 80, "y": 10, "width": 50, "height": 50})).unwrap()["id"].clone();
app.run("select.none", json!({})).unwrap();
let lock_unselected = |app: &VectorcraftApp| crate::menus::enabled(app, "object.lock.unselected");
assert!(!lock_unselected(&app), "nothing selected");
app.run("select.set", json!({"ids": [a, b.clone()]})).unwrap();
assert!(lock_unselected(&app), "selection present");
let g = app.run("object.group", json!({})).unwrap()["id"].clone();
let lock_and_hide: Vec<String> = menu_entries(&app)
.into_iter()
@@ -712,6 +716,7 @@ fn lock_and_hide_menus_are_greyed_out_in_isolation_mode() {
app.run("object.isolate", json!({"id": g.clone()})).unwrap();
app.run("select.set", json!({"ids": [b]})).unwrap();
assert_eq!(shown(&app), [false, false, false, false, false, false, false, false, false, true], "in isolation mode");
assert!(lock_unselected(&app), "shortcut command remains enabled in isolation");
app.run("object.exitIsolation", json!({})).unwrap();
app.run("select.set", json!({"ids": [g]})).unwrap();
assert_eq!(shown(&app), [true; 10], "after Exit Isolation Mode");
+37
View File
@@ -336,6 +336,43 @@ fn cmd_alt_shift_j_opens_average_and_join() {
assert_eq!(app.ui.dialog.as_ref().map(|d| d.str("to")).as_deref(), Some("smooth"), "the choice confirmed last");
}
/// Cmd+Alt+Shift+2 locks unselected artwork, including inside an isolated group.
#[test]
fn cmd_alt_shift_2_locks_unselected_artwork() {
let mut app = VectorcraftApp::new(vectorcraft_engine::Session::new(), Default::default());
app.session.execute("file.new", &json!({"width": 200, "height": 200})).unwrap();
assert_eq!(crate::menus::shortcut_of("object.lock.unselected"), Some("Cmd+Alt+Shift+2"));
assert_eq!(crate::menus::shortcut_of("object.hide.unselected"), Some("Cmd+Alt+Shift+3"));
assert!(!crate::menus::menu_tree_named(true).iter().any(|(_, items)| format!("{items:?}").contains("object.lock.unselected")));
let rect = |app: &mut VectorcraftApp, x: f64| {
let r = app.session.execute("shape.rectangle", &json!({"x": x, "y": 10, "width": 20, "height": 20})).unwrap();
vectorcraft_doc::NodeId(r["id"].as_u64().unwrap())
};
let (a, b) = (rect(&mut app, 10.0), rect(&mut app, 50.0));
app.session.execute("select.none", &json!({})).unwrap();
assert!(!crate::menus::enabled(&app, "object.lock.unselected"), "nothing selected");
let locked = |app: &VectorcraftApp| [a, b].map(|id| app.session.doc().unwrap().doc.node(id).unwrap().locked);
let two = |modifiers| egui::Event::Key { key: Key::Num2, physical_key: None, pressed: true, repeat: false, modifiers };
app.session.execute("select.set", &json!({"ids": [a.0]})).unwrap();
assert!(crate::menus::enabled(&app, "object.lock.unselected"), "selection present");
frame(&mut app, vec![two(Modifiers::COMMAND | Modifiers::ALT | Modifiers::SHIFT)]);
assert_eq!(locked(&app), [false, true]);
frame(&mut app, vec![two(Modifiers::COMMAND | Modifiers::ALT)]);
assert_eq!(locked(&app), [false, false], "Cmd+Alt+2 unlocks all");
app.session.execute("select.set", &json!({"ids": [a.0]})).unwrap();
frame(&mut app, vec![two(Modifiers::COMMAND)]);
assert_eq!(locked(&app), [true, false], "Cmd+2 locks the selection");
// The shortcut uses the isolated group as its scope.
app.session.execute("object.unlockAll", &json!({})).unwrap();
app.session.execute("select.set", &json!({"ids": [a.0, b.0]})).unwrap();
let g = app.session.execute("object.group", &json!({})).unwrap()["id"].as_u64().unwrap();
app.session.execute("object.isolate", &json!({"id": g})).unwrap();
app.session.execute("select.set", &json!({"ids": [a.0]})).unwrap();
assert!(crate::menus::enabled(&app, "object.lock.unselected"));
frame(&mut app, vec![two(Modifiers::COMMAND | Modifiers::ALT | Modifiers::SHIFT)]);
assert_eq!(locked(&app), [false, true], "unselected member locks in isolation mode");
}
/// Cmd+Shift+B while the Type tool edits text is Type › Bold, not Hide Bounding Box (#724).
#[test]
fn cmd_shift_b_while_typing_is_bold_not_the_bounding_box() {
+8
View File
@@ -1398,6 +1398,14 @@ selected. While Lock Guides is on, the guide paths count as selected and stay as
hide it records no undo step. In isolation mode the menu item is disabled, and the command returns the error "exit
isolation mode first" and changes nothing.
`object.lock.unselected` (Cmd+Alt+Shift+2; shortcut and command, with no Object › Lock menu item) locks unselected
artwork in one undo step and returns `{count}`. In a partly selected group, clipping group, or compound path, it locks
the unselected members and leaves the container and selected members unlocked. It includes unselected guides even
while Lock Guides is on. Hidden art and art on locked layers stay individually unlocked; a selected layer's artwork
counts as selected. In ordinary isolation mode it locks only unselected art inside the isolated object. The selection
stays as it is. `object.unlockAll` unlocks and selects all locked artwork in the document, including art locked before
this command. With nothing to lock it records no undo step.
These Select menu commands select only the objects that `select.all` selects and the objects inside them: every
`select.same.*` and `select.object.*` command except `select.object.slices`, `select.nextAbove`, `select.nextBelow`
and `select.recall`. They leave out hidden and locked objects with the objects inside them, the objects on hidden,
+2 -1
View File
@@ -962,7 +962,8 @@ Moved from the ROADMAP's "Shipped so far" on 2026-10-10. Update it when a featur
The Libraries panel holds gradients and patterns: its + button adds the selection's fill or stroke gradient or pattern, a gradient or pattern swatch dragged from the Swatches panel is added, and a click paints the selection through the active Fill/Stroke proxy, a pattern bringing its definition and swatch into the document.
Object › Lock › All Artwork Above and Object › Hide › All Artwork Above deselect the selected objects they lock or hide, the key object included.
Object › Hide › Unselected Artwork (Cmd/Ctrl+Alt+Shift+3, `object.hide.unselected`) hides, in one undo step, every object Select All takes that is not selected and holds no selected object; the members of a group that holds a selected object are hidden one by one, and Object › Show All shows them again. It is disabled in isolation mode. Public references: [Default keyboard shortcuts](https://web.archive.org/web/20260726060015/https://helpx.adobe.com/illustrator/using/default-keyboard-shortcuts.html), "Hide unselected artwork"; [How to lock, hide, and delete objects in Illustrator](https://web.archive.org/web/20220303070637/https://helpx.adobe.com/illustrator/using/locking-hiding-deleting-objects.html), which says the Show All and Hide menus are unavailable in isolation mode.
In isolation mode, the items of Object › Lock and Object › Hide, Unlock All and Show All are greyed out ([lock, hide, and delete objects](https://web.archive.org/web/20220303070637/https://helpx.adobe.com/illustrator/using/locking-hiding-deleting-objects.html)); the Contextual Task Bar's Lock button is greyed out too, the Properties panel's Quick Actions have no Lock, and the commands return an error. Pattern editing mode and opacity mask editing do not count as isolation mode for them.
Cmd/Ctrl+Alt+Shift+2 (`object.lock.unselected`) locks unselected artwork in one undo step and has no Object › Lock menu item. It locks unselected members of partly selected groups, clipping groups and compound paths, and unselected guides while Lock Guides is on. In ordinary isolation mode it locks only unselected art inside the isolated object. Object › Unlock All unlocks all locked art in the document. The [public shortcut page](https://web.archive.org/web/20260726060015/https://helpx.adobe.com/illustrator/using/default-keyboard-shortcuts.html) calls the action "Lock all deselected artwork".
In isolation mode, the visible items of Object › Lock and Object › Hide, Unlock All and Show All are greyed out ([lock, hide, and delete objects](https://web.archive.org/web/20220303070637/https://helpx.adobe.com/illustrator/using/locking-hiding-deleting-objects.html)); the shortcut-only `object.lock.unselected` command remains enabled with a selection. The Contextual Task Bar's Lock button is greyed out too, the Properties panel's Quick Actions have no Lock, and the other Lock and Hide commands return an error. Pattern editing mode and opacity mask editing do not count as isolation mode for them.
Liquify (its brush Width, Height and Angle, Intensity, Detail, Simplify, Twirl Rate, Complexity, Horizontal and Vertical), Puppet Warp (its Expand and each pin's angle), Transform in Perspective (its depth), Nudge in Perspective (its direction) and Move Plane (its location or distance) refuse a value other than a number or null, such as "40", Draw in Perspective refuses a click point that is not two numbers, and Width Profile refuses a point that is not three numbers; each leaves the document and its undo history as they were.
Object › Lock › All Artwork Above and Object › Hide › All Artwork Above go through each top-level layer once, checking each object that is not selected against the selected objects below it: with 100 tiles selected under 25,000 rectangles, Lock took 6.4 s and now takes under 0.1 s, and with all of 5,001 objects selected it took 8.8 s and now takes under 0.1 s.
Object › Unlock All and Object › Show All clicked in the in-window menu bar with Shift+Alt (Shift+Option) held unlock or show only the objects inside the groups that hold the selected objects ([lock, hide, and delete objects](https://web.archive.org/web/20230623025912/https://helpx.adobe.com/illustrator/using/locking-hiding-deleting-objects.html)); `object.unlockAll` and `object.showAll` take `scope: "group"` for it.