How to replicate "Select Object Layer" command?

I am trying to highlight the layer of the currently selected object in the layers dialog. Is there an API method for that?

I’m also curious if there’s any API to interact with Rhino’s menus (e.g. “Properties”, “Layers”, “Named Views”, etc.) in general.

Hi @Daniel_Krajnik, below does this using python:

import Rhino
import scriptcontext
import rhinoscriptsyntax as rs

def SelectObjectLayer():
    
    obj_id = rs.GetObject("Select Object", False, False)
    if not obj_id: return
    
    rh_obj = rs.coercerhinoobject(obj_id, True, True)
    layer_index = rh_obj.Attributes.LayerIndex
    
    scriptcontext.doc.Layers.Select([layer_index], True)
    
SelectObjectLayer()

you can pass multiple layer indices to the Select method as list.

There are many things which you can do, any specific one you want ?

_
c.

2 Likes

Thank you very much, that’s very helpful.

For example:

  • highlight the parent layer of the currently selected object
  • hide the parent layer of the currently selected object
  • collapse the parent layer of the currently selected object
  • collapse/expand all the layers

If you knew which part of Rhino’s API will be best to look into to build these command I would be really grateful.

Bonus:

  • fuzzy search by name :slight_smile:

This works similar as the first example, you just need to get the parent layer from the object’s layer:

import Rhino
import scriptcontext
import rhinoscriptsyntax as rs
import System

def SelectObjectParentLayer():
    
    obj_id = rs.GetObject("Select Object", False, False)
    if not obj_id: return
    
    rh_obj = rs.coercerhinoobject(obj_id, True, True)

    layer = scriptcontext.doc.Layers[rh_obj.Attributes.LayerIndex]
    
    parent_layer_id = layer.ParentLayerId
    if parent_layer_id != System.Guid.Empty:
        parent_layer = scriptcontext.doc.Layers.FindId(parent_layer_id)
        scriptcontext.doc.Layers.Select([parent_layer.LayerIndex], True)
    else:
        print "{} has no parent layer".format(layer.FullPath)
    
SelectObjectParentLayer()

It will print an error if the current object’s layer has no parent layer.

You can find layer visibility in the layer properties, eg. layer.Visible(False) would hide it. Note that you cannot hide a layer if it is the current layer. To find out if a layer is current or not, compare it’s layer index with the index returned by scriptcontext.doc.Layers.CurrentLayerIndex

Same goes for the collapsed/expanded state of a layer, eg. use layer.IsExpanded(False) to collapse it’s sub layers.

You mean layers by name or objects by name ?

_
c.

1 Like

Amazing, thank you. I will try these out now.

I was referring to layers, Rhino 8 WIP provides a search bar, but it’s not “fuzzy” (“key plan”, won’t find “key-plan”), it’s also impossible to assign a shortcut to it. Being able to search and “jump to”/highlight a layer in the dialog (without hiding the rest) would be a massive productivity boost.

You might try to use wildcards when entering text in the searchbar, eg. when entering “key*plan” it should find and highlight “key plan” and “key-plan”. I have not tested this in Rhino 8 WIP but i guess these default filtering rules should be working:

* = match zero or more characters
? = exactly one character
# = exactly one numeric (0-9) character
& = exactly one alpha (a-z, A-Z) character

They are located in the help under Filters. You could do the same via code by iterating all layers and comparing layer.Name with a regular expression.

_
c.

Oh I see, that makes sense. I wished by default it treated space for that wildcard, but this will work fine, as well.

Thanks, I will try to assemble something that may do that search from the command line.

No, space has a different meaning in that context. Note that when using regular expressions there are different rules. In case of your example, you could use this:

import Rhino
import scriptcontext
import rhinoscriptsyntax as rs
import re

def DoSomething():
    
    expression = re.compile("key.plan")
    indices = set()
    
    for layer in scriptcontext.doc.Layers:
        if expression.findall(layer.Name):
            indices.add(layer.LayerIndex)
    
    if indices:
        scriptcontext.doc.Layers.Select(indices, True)

DoSomething()

This will highlight “key-plan” and “key plan” or “key1plan” but not “Key-Plan”, so it is case sensitive…

_
c.

1 Like

Hmm… there seems to be an error:

Message: expected string for parameter 'text' but got 'NoneType'

Traceback:
  line 12, in DoSomething, "C:\Users\daniel.krajnik\AppData\Local\Temp\TempScript.py"
  line 18, in <module>, "C:\Users\daniel.krajnik\AppData\Local\Temp\TempScript.py"

I’ve tried a few regexes (regices/regex expressions) and the same error popped out each time.

I will have a look at it soon (it’s 10pm in Europe now), but it would be amazing to have it work.

Hi @Daniel_Krajnik, i get below using Rhino 7:

LayerRegEx

_
c.

I’ll try it on Rhino 7 then, I’m currently on 8 WIP (8.0.22291.12305, 2022-10-18) with SetDotNetRuntime=NETFramework

Hopefully, it will work. The result looks very promising! Exactly what I’ve been looking for…

how this script select layers of the selected viewport objects. i dont find it work for me. is ther anything else to do.

Are you using Rhino 8 or 7? New UI in Rhino 8 broke this script for me (last time used in December 2022), but it should work in Rhino 7

i tried this script and it worked in rhino 7.

Hi @Daniel_Krajnik, i’ve just tested the script above using regular expressions in Rhino 8 (8.0.23171.14305, 2023-06-20) and it works.

The script in my second post above also works in Rhino 8. Since its only for a single object, here is one for multiple objects:

import Rhino
import scriptcontext
import rhinoscriptsyntax as rs

def SelectObjectLayers():
    
    obj_ids = rs.GetObjects("Select Objects", 0, False, True, True)
    if not obj_ids: return
    
    rh_objs = [rs.coercerhinoobject(obj_id, True, True) for obj_id in obj_ids]
    indices = [rh_obj.Attributes.LayerIndex for rh_obj in rh_objs]
    
    scriptcontext.doc.Layers.Select(indices, True)
    
SelectObjectLayers()

Btw. Rhino 8 now has a new command _HighlightObjectLayers which does the same.

_
c.

1 Like

@clement thanks for checking, this problem occurred only as of December 2022 - I haven’t tried it since then. Glad to hear that it’s fixed now and exciting to hear that a native _HighlightObjectLayers to do that was added.

1 Like

Hi! Thank you for this share. Before I try it, how would you advise to change it so that when you run the script it selects all the objects on the layers of the current selection?!

So if I have an object A on layer ONE and object B on layer TWO selected, then when I run the script it would select all objects on layer (and maybe sublayers) ONE and TWO.

Honestly Rhino 8 I believe solved half of this problem but I still can;t find a native command to select all objects on a layer and sublayer, which also I can’t begin to understand why,

try this with some objects of each layer preselected: _-SelLayer

there is no native command for doing this with sublayers but it would be scriptable for sure.

_
c.

1 Like