SOLVED Layer Selection Python

Check for the active bit by GetBit(c4d.BIT_ACTIVE) to test whether a layer is selected.
Layers are GeListNodes, so you can get from one layer object to the other with the usual functions GetNext(), GetDown() etc.

Also, you are not looking at "only the children". The object you get from GetLayerObjectRoot() is a GeListHead, not a LayerObject, so you need to go from root either to the first layer in the list by GetDown(), or you get the full layer list on the top level(!) by GetChildren().

Each of these layers in the returned list can have children, though, since layers form a full tree structure. So if you want to visit all layers, you need to recurse into the child lists as well. E.g.:

import c4d

def visitLayer(layer):
    if layer == None: return
    print (layer.GetName(), "Selected" if layer.GetBit(c4d.BIT_ACTIVE) else "Unselected")
    visitLayer(layer.GetDown())
    visitLayer(layer.GetNext())
    
def main():
    first = doc.GetLayerObjectRoot().GetDown()
    visitLayer(first)

if __name__=='__main__':
    main()

Also, you are not looking at "only the children". The object you get from GetLayerObjectRoot() is a GeListHead, not a LayerObject, so you need to go from root either to the first layer in the list by GetDown(), or you get the full layer list on the top level(!) by GetChildren().

Each of these layers in the returned list can have children, though, since layers form a full tree structure. So if you want to visit all layers, you need to recurse into the child lists as well. E.g.:

import c4d

def visitLayer(layer):
    if layer == None: return
    print (layer.GetName(), "Selected" if layer.GetBit(c4d.BIT_ACTIVE) else "Unselected")
    visitLayer(layer.GetDown())
    visitLayer(layer.GetNext())
    
def main():
    first = doc.GetLayerObjectRoot().GetDown()
    visitLayer(first)

if __name__=='__main__':
    main()

Hello @roman,

thank you for reaching out to us. And thank you @Cairyn for providing an answer. A minor problem with the answer provided by @Cairyn is that it is recursive. We recommend walking node graphs iteratively and not recursively, because of the vastness of node graphs in Cinema 4D and danger of producing stack overflows when walking them recusively. In this case, the case of layers, it is unlikely that one will hit the recursion limit of Python (one thousand recursions by default on most systems¹) or produce a stack overflow in C++ (depends on many things).

Cheers,
Ferdinand

¹ The recursion limit of Python is defined and set in sys via sys.get/setrecursionlimit. One can raise the limit of one thousand which is rather conservative, but if it is set to high, it will then fail to prevent what it is intended for: to prevent stack overflows and crashing the Python interpereter.

This post is deleted!

@cairyn said in Layer Selection Python:

Also, you are not looking at "only the children". The object you get from GetLayerObjectRoot() is a GeListHead, not a LayerObject, so you need to go from root either to the first layer in the list by GetDown(), or you get the full layer list on the top level(!) by GetChildren().

Each of these layers in the returned list can have children, though, since layers form a full tree structure. So if you want to visit all layers, you need to recurse into the child lists as well. E.g.:

import c4d

def visitLayer(layer):
    if layer == None: return
    print (layer.GetName(), "Selected" if layer.GetBit(c4d.BIT_ACTIVE) else "Unselected")
    visitLayer(layer.GetDown())
    visitLayer(layer.GetNext())
    
def main():
    first = doc.GetLayerObjectRoot().GetDown()
    visitLayer(first)

if __name__=='__main__':
    main()

Thank you a lot Cairyn!!!

@cairyn, i don't understand just one thing how should i change a code if i want to do it with selected objects not for all.

import c4d

def visitLayer(layer):
if layer == None: return
print (layer.GetName())
doc.AddUndo(c4d.UNDOTYPE_CHANGE, layer)
layer [c4d.ID_LAYER_VIEW] = 1
visitLayer(layer.GetDown())
visitLayer(layer.GetNext())

def main():
doc.StartUndo()
first = doc.GetLayerObjectRoot().GetDown()
visitLayer (first)

doc.EndUndo()
c4d.EventAdd()

if name=='main':
main()

@roman If you mean handle only the selected layers then you just need to insert a check for the active bit:

print (layer.GetName())
if layer.GetBit(c4d.BIT_ACTIVE) :
    doc.AddUndo(c4d.UNDOTYPE_CHANGE, layer)
    layer [c4d.ID_LAYER_VIEW] = 1

If you really mean selected objects, I'm not sure what you mean as your code doesn't refer to any objects?

@cairyn
For example, we have 20 layers and i need to change visibility just for 2 layers in this list. That's what i meant when i talked about selected layers.

I tried to use same code but it showed to me first layer in list....while i want to work with active layers which i have selected.

And i wanted to ask which command delete layer?

Sorry for stupid questions, but SDK a little bit unobvious.

@roman Just insert the code from my last post into the overall script.

Here, I did it for you this time:

import c4d

def visitLayer(layer):
    while layer != None:
        if layer.GetBit(c4d.BIT_ACTIVE) :
            doc.AddUndo(c4d.UNDOTYPE_CHANGE, layer)
            layer [c4d.ID_LAYER_VIEW] = not layer [c4d.ID_LAYER_VIEW]
        visitLayer(layer.GetDown())
        layer = layer.GetNext()
    
def main():
    doc.StartUndo()
    first = doc.GetLayerObjectRoot().GetDown()
    visitLayer(first)
    doc.EndUndo()
    c4d.EventAdd()

if __name__=='__main__':
    main()

This script toggles the editor visibility of the currently selected layers. Execute it twice to get the original visibility state back.

Note:

  1. Since Ferdinand didn't like the overall recursion, I replaced the next-recursion with a while loop. The depth recursion is still there but if you manage to break the Python stack with your nested layer setup, your amount of layers is sus.
  2. Layers do not have a method to get a list of selected elements last time I looked, so you need to traverse the whole layer tree and check the BIT_ACTIVE for each.

(If you are not happy about the structure of Maxon's API documentation, I do have many beginner-oriented lessons and examples in my course https://www.patreon.com/cairyn -- although Patreon is admittedly not ideal for searching; I really need to make this into a proper book.)

As for deleting a layer, a LayerObject is a BaseList2D which is a GeListNode, so you can use the Remove method. Like here:

import c4d

def visitLayer(layer):
    while layer != None:
        nextLayer = layer.GetNext()
        if layer.GetBit(c4d.BIT_ACTIVE) :
            doc.AddUndo(c4d.UNDOTYPE_DELETE, layer)
            layer.Remove()
        else:
            visitLayer(layer.GetDown())
        layer = nextLayer
    
def main():
    doc.StartUndo()
    first = doc.GetLayerObjectRoot().GetDown()
    visitLayer(first)
    doc.EndUndo()
    c4d.EventAdd()

if __name__=='__main__':
    main()

The infrastructure of C4D will remove the objects from that layer and throw the layer away once there are no more references.

Note: Since the layer tree is a linked structure, you will need to pay extra attention to the tree walking, be it recursion or iteration, when you remove layers out of the structure. That's why the visitLayer function looks a bit different here.

@cairyn Thank you again. I will check your patreon