Hide Layers in Layer Panel via Eto.Form / Script

Hi, I use a template for all my models which has +150 layers, but frequently I only need say 10 in each actual model. Once the model is built, I can filter the layers that are visible in the Layers Panel by >Layers with Objects. Before the model is built I can use Filter > Selected Layers or any of the other objects. However, none of these options are satisfactory as scrolling through the list to shift click and filter at the start is annoying.

So, I started prepping an Eto,Forms / python script that is populated with all the layers in the file, each with a check box. I would like to be able to check the layers that I want visible, and press a button to act as a proxy or replicate the process of shift clicking a bunch of layers and filter the layers panel by selected layers. Is this possible? I’ve seen reference that this part of Rhino is not accessible via the API. Is this correct? Can you think of a workaround?

many thanks! Nick

Hi @nickdevlin,

See this old thread.

– Dale

Many thanks Dale, I really appreciate the response. I looked at the code you signposted to but couldn’t figure how to integrate it into my existing code. Full disclosure here - I’m a novice in the scripting department and get ChatGPT to do all the heavy lifting, but in this instance I couldn’t get it to integrate your functionality into this context.

I have an Eto.forms dialog with a checkboxlist. Each of the list items is the name of a layer in the file. Layers that are checked are kept on when the Apply button is pressed. Unchecked layers are turned off when apply is pressed. I then have to manually filter the layers visible in the UI by by showing On layers only. This isn’t a big hassle, but it would be awesome to integrate this into the script. I’ve copied the code below in it’s entirety.

If anyone has any pointers, I’d really appreciate it.

#! python 2
import Rhino
import Eto.Forms as forms
import Eto.Drawing as drawing
import scriptcontext as sc

#This turns on / off layers according to the checkbox status. The next stage is to explore if this 
information can be used to automatically run the layer filter in the UI?> 
 ## also needs adjusted to sort the layers maybe? 

 # Create a class for the dialog
class LayerListDialog(forms.Dialog[bool]):
def __init__(self):
    # Initialize the dialog
    self.Title = "Layer List"
    self.ClientSize = drawing.Size(400, 1000)
    self.Padding = drawing.Padding(10)
    self.Resizable = True
    
    # Dictionary to store checkboxes for each layer
    self.layer_checkboxes = {}
    
    # Create a scrollable container
    self.scrollable = forms.Scrollable()
    self.scrollable.Content = self.create_layer_table()
    
    # Add the scrollable container to the dialog layout
    layout = forms.DynamicLayout()
    layout.AddRow(self.scrollable)
    layout.Add(None)  # Add a spacer
    
    # Create a grid layout for the buttons
    button_layout = forms.TableLayout(Spacing=drawing.Size(10, 10), Padding=drawing.Padding(10))
    button_layout.Rows.Add(forms.TableRow())  # Add an empty row at the top
    
    # Create the Apply button
    self.ApplyButton = forms.Button(Text="Apply")
    self.ApplyButton.Click += self.on_apply_button_click
    self.ApplyButton.Size = drawing.Size(80, 30)
    
    # Create the Close button
    self.CloseButton = forms.Button(Text="Close")
    self.CloseButton.Click += self.on_ok_button_click
    self.CloseButton.Size = drawing.Size(80, 30)
    
    # Create the Check All button
    self.CheckAllButton = forms.Button(Text="Check All")
    self.CheckAllButton.Click += self.on_check_all_button_click
    self.CheckAllButton.Size = drawing.Size(80, 30)
    
    # Create the Uncheck All button
    self.UncheckAllButton = forms.Button(Text="Clear All")
    self.UncheckAllButton.Click += self.on_uncheck_all_button_click
    self.UncheckAllButton.Size = drawing.Size(80, 30)
    
    # Add buttons in the new layout
    button_layout.Rows.Add(forms.TableRow(self.CheckAllButton, self.ApplyButton))
    button_layout.Rows.Add(forms.TableRow(self.UncheckAllButton, self.CloseButton))
    
    # Add buttons to the layout underneath the scrollable container
    layout.AddRow(button_layout)
    
    # Set the dialog content
    self.Content = layout
    
    # Adjust the scrollable container dynamically when resized
    self.SizeChanged += self.on_size_changed

def create_layer_table(self):
    # Create a table layout to hold the checkboxes and layer names
    layer_table = forms.TableLayout()
    layer_table.Spacing = drawing.Size(5, 5)
    layer_table.Padding = drawing.Padding(5)
    layer_table.Rows.Add(forms.TableRow())  # Add an empty row at the top
    
    # Add each layer with a checkbox
    for layer in sc.doc.Layers:
        if not layer.IsDeleted:
            checkbox = forms.CheckBox()
            checkbox.Checked = layer.IsVisible
            self.layer_checkboxes[layer.Id] = checkbox
            label = forms.Label(Text=layer.FullPath)
            row = forms.TableRow(checkbox, label)
            layer_table.Rows.Add(row)
    
    layer_table.Rows.Add(forms.TableRow())  # Add an empty row at the bottom
    return layer_table

def on_size_changed(self, sender, e):
    # Update the scrollable container size when the dialog size changes
    self.scrollable.Width = self.ClientSize.Width - 20
    self.scrollable.Height = self.ClientSize.Height - 150  # Adjust height to make space for buttons

def on_ok_button_click(self, sender, e):
    # Close the dialog when Close is clicked
    self.Close(True)

def on_apply_button_click(self, sender, e):
    # Set the visibility of layers based on checkbox states
    for layer_id, checkbox in self.layer_checkboxes.items():
        layer = sc.doc.Layers.FindId(layer_id)
        if layer is not None:
            layer.IsVisible = checkbox.Checked
            layer.CommitChanges()  # Apply the change to the document
    
    # Redraw the document to reflect changes
    sc.doc.Views.Redraw()

def on_uncheck_all_button_click(self, sender, e):
    # Uncheck all checkboxes
    for checkbox in self.layer_checkboxes.values():
        checkbox.Checked = False

def on_check_all_button_click(self, sender, e):
    # Check all checkboxes
    for checkbox in self.layer_checkboxes.values():
        checkbox.Checked = True

# Show the dialog
  def show_layer_list_dialog():
  dialog = LayerListDialog()
   dialog.ShowModal(Rhino.UI.RhinoEtoApp.MainWindow)

  # Run the function to show the dialog
   if __name__ == "__main__":
   show_layer_list_dialog()

Hi @nickdevlin,

Does this help?

#! python 2
import Rhino
import rhinoscriptsyntax as rs
import scriptcontext as sc

def main():
    if sc.doc.Layers.Count <= 1:
        print("More than 1 layer required.")
        return
        
    items = []
    for layer in sc.doc.Layers:
        if layer.IsDeleted:
            continue
        if layer.Index == sc.doc.Layers.CurrentLayerIndex:
            continue
        items.append([layer.Name, layer.IsVisibleInUserInterface])
        
    title = 'Show/Hide Layers'
    message = 'Check to show, uncheck to hide:'
    rc = rs.CheckListBox(items, message, title)
    if not rc:
        return
    
    for item in rc:
        name = item[0]
        layer = sc.doc.Layers.FindName(name)
        if layer:
            state = item[1]
            if layer.IsVisibleInUserInterface != state:
                layer.IsVisibleInUserInterface = state
                layer.CommitChanges()
    
    # Redraw the layers panel
    sc.doc.Views.EnableRedraw(True, True, True)

if __name__ == "__main__":
    main()        

– Dale