How to Solo a Layer



  • Hi,

    I just spent a bit of time debugging a couple issues when trying to Solo a Layer in the Layer Manager, and figured I would post my findings to save someone else some trouble:

    Q: How do you solo a layer?

    layer_root = doc.GetLayerObjectRoot()
    if not layer_root: return
    
    # Get the first layer in the scene
    layer = layer_root.GetDown()
    if not layer: return
    
    # Be sure to use the `rawdata` flag so that you get the stored layer state, not the "effective" layer state
    layer_data = layer.GetLayerData(doc, rawdata=True)
    
    start_solo_state = layer_data["solo"]
    solo_state = True
    
    layer_data["solo"] = True
    
    # SetLayerData needs a complete LayerData dict, it doesn't work with something like `{"solo": True}`
    # doing that will force all other layer state flags to be False
    layer.SetLayerData(doc, layer_data)
    
    # This isn't documented near SetLayerData, but you must call this method or C4D won't know to update the
    # solo state of layers in the scene.
    set_or_clear = 
    doc.ChangeNBit(c4d.NBIT_SOLO_LAYER, c4d.NBITCONTROL_SET)
    
    # Let C4D know something has changed to trigger a redraw
    c4d.EventAdd()
    

    Documentation Request:
    Please update the docs for SetLayerData to include an example like the above, and make a note that if you plan to SetLayerData you should call GetLayerData with rawdata=True.

    Thanks,

    Donovan

    -- Edit 2020/03/20 --

    Actually this isn't working well in all circumstances. If all layers are unsoloed I'm not getting the expected refresh.

    Okay, I think I figured out the issue (but haven't updated the logic above to account for it):

    If you turn off solo on all layers, you need to use doc.ChangeNBit(c4d.NBIT_SOLO_LAYER, c4d.NBITCONTROL_CLEAR), but if even one layer has the solo flag on, you need to use doc.ChangeNBit(c4d.NBIT_SOLO_LAYER, c4d.NBITCONTROL_SET).

    ...I think.



  • Did you look into the C++ docs on this issue? Because there you find a Layer Manual.



  • Hi @dskeith thanks for reaching out us.

    As pointed out by @PluginStudent, the NBIT_SOLO_LAYER behavior is explained in the Layer Manuel although it make sense to add a note to the Python API as well.

    With regard to a complete example, I've partially reworked your code to make sure that by executing the script multiple times you can run across all the solo configurations that the scene can handle.

    import c4d
    
    # Main function
    def main():
        layer_root = doc.GetLayerObjectRoot()
        if not layer_root: 
            return
    
        # Get the first layer in the scene
        layer = layer_root.GetDown()
        if not layer: 
            return
    
        soloSet = False
    
        while layer is not None:
            # Set `rawdata` to True flag so to get the original layer values without any additional global changes
            layer_data = layer.GetLayerData(doc, rawdata=True)
    
            # check the current layer solo state:
            if layer_data["solo"] == False:
                # if not "solo" then set to True
                layer_data["solo"] = True
                # update the layer
                layer.SetLayerData(doc, layer_data)
                # update the flag
                soloSet = True
                break
            
            # deactivate if layer solo was True
            layer_data["solo"] = False
            layer.SetLayerData(doc, layer_data)
    
            # go to next layer
            layer = layer.GetNext()
        
        # if one (or more) solo was set the set NBIT_SOLO_LAYER otherwise clear
        if soloSet == True:
            doc.ChangeNBit(c4d.NBIT_SOLO_LAYER, c4d.NBITCONTROL_SET)
        else:
            doc.ChangeNBit(c4d.NBIT_SOLO_LAYER, c4d.NBITCONTROL_CLEAR)
    
        # Add an event 
        c4d.EventAdd()
    
    # Execute main()
    if __name__=='__main__':
        main()
    

    Cheers