Isolate Selection

Thx for speedy reply.
Yeah, it’s sort of a weird one.

Here’s a script that seems to work; only tested a few times so far.

I made Aliases ‘Iso’ and ‘Uniso’ that just run the same script.

I’ve been using Isolate more now that it works reliably with Undo, and the locked objects were getting annoying.

# Rhino Python
# Toggle Isolate/Unisolate:
# - First run: isolate selection (never show locked objs / locked layers)
# - Second run: restore previous layer visibility + per-object hidden + per-object locked

import rhinoscriptsyntax as rs
import scriptcontext as sc

_STICKY_KEY = "IsolateNoLocked_toggle_state"

def _capture_state():
    # Capture by GUID (rs uses GUIDs everywhere reliably)
    prev_obj_hidden = {}
    prev_obj_locked = {}
    for oid in rs.AllObjects(select=False, include_lights=True, include_grips=False):
        prev_obj_hidden[oid] = rs.IsObjectHidden(oid)
        prev_obj_locked[oid] = rs.IsObjectLocked(oid)

    prev_layer_visible = {}
    for layer_name in rs.LayerNames():
        # Using name here because rs layer funcs are name-based.
        # (If you rename layers during isolate, restore could miss; usually fine.)
        prev_layer_visible[layer_name] = rs.IsLayerVisible(layer_name)

    sc.sticky[_STICKY_KEY] = {
        "obj_hidden": prev_obj_hidden,
        "obj_locked": prev_obj_locked,
        "layer_visible": prev_layer_visible,
    }

def _hide_locked_layers():
    for layer_name in rs.LayerNames():
        if rs.IsLayerLocked(layer_name) and rs.IsLayerVisible(layer_name):
            rs.LayerVisible(layer_name, False)

def _is_on_locked_layer(oid):
    layer_name = rs.ObjectLayer(oid)
    return bool(layer_name) and rs.IsLayerLocked(layer_name)

def isolate():
    ids = rs.GetObjects(
        "Select objects to isolate (locked objects / locked layers will not be shown)",
        preselect=True, select=True
    )
    if not ids:
        return

    sel = set(ids)

    _capture_state()
    _hide_locked_layers()

    all_ids = rs.AllObjects(select=False, include_lights=True, include_grips=False) or []
    to_show = []
    to_hide = []

    for oid in all_ids:
        if oid in sel and (not rs.IsObjectLocked(oid)) and (not _is_on_locked_layer(oid)):
            to_show.append(oid)
        else:
            to_hide.append(oid)

    # Hide everything else. Need to unlock temporarily for visibility changes.
    locked_to_hide = [oid for oid in to_hide if rs.IsObjectLocked(oid)]
    if locked_to_hide:
        rs.UnlockObjects(locked_to_hide)

    if to_hide:
        rs.HideObjects(to_hide)

    # Relock the ones we temporarily unlocked (keep their lock state as-is for now)
    if locked_to_hide:
        rs.LockObjects(locked_to_hide)

    # Show the allowed set (should already be unlocked by definition, but show anyway)
    if to_show:
        rs.ShowObjects(to_show)

    rs.Redraw()

def unisolate():
    state = sc.sticky.get(_STICKY_KEY)
    if not state:
        print("No IsolateNoLocked state found to restore.")
        return

    obj_hidden = state.get("obj_hidden", {})
    obj_locked = state.get("obj_locked", {})
    layer_visible = state.get("layer_visible", {})

    # Restore layer visibility first
    for layer_name, was_visible in layer_visible.items():
        if rs.IsLayer(layer_name):
            rs.LayerVisible(layer_name, was_visible)

    # Compute what to show/hide based on previous state
    all_ids = rs.AllObjects(select=False, include_lights=True, include_grips=False) or []
    to_show = []
    to_hide = []

    for oid in all_ids:
        if oid in obj_hidden:
            if obj_hidden[oid]:
                to_hide.append(oid)
            else:
                to_show.append(oid)

    # Unlock anything we need to change visibility for
    locked_to_change = [oid for oid in set(to_show + to_hide) if rs.IsObjectLocked(oid)]
    if locked_to_change:
        rs.UnlockObjects(locked_to_change)

    if to_show:
        rs.ShowObjects(to_show)
    if to_hide:
        rs.HideObjects(to_hide)

    # Restore lock states exactly as they were
    to_lock = []
    to_unlock = []
    for oid in all_ids:
        if oid in obj_locked:
            if obj_locked[oid]:
                to_lock.append(oid)
            else:
                to_unlock.append(oid)

    if to_lock:
        rs.LockObjects(to_lock)
    if to_unlock:
        rs.UnlockObjects(to_unlock)

    sc.sticky.pop(_STICKY_KEY, None)
    rs.Redraw()

def main():
    if sc.sticky.get(_STICKY_KEY):
        unisolate()
    else:
        isolate()

main()

So nice of you to post! I’ve got my own versions of these now, but I appreciate the post :slight_smile: