Layers, layer names and undo stack

I am having trouble with understanding how the undo stack is working with layers. I am seeing a couple of odd phenomena here following is a small example… Run the following script with the posted files (one has all top level layers, the other has some sublayers). What it does is “randomize” all the top level layer names, and then restore them back to their original names via a lookup table (why I am doing this I will explain later, the code is part of a larger project).

The script actually executes fine and does what it is supposed to (to see, set a breakpoint at the pass in the main def), the problem happens if you hit the Undo button after running the script. You cannot get back to the original file state, it will undo the restoration of the names from random, but not the randomization in the first place. So the file is left with random layer names.

I don’t know if this is inevitable due to how layers are dealt with in the Undo stack or if something can be done to make this work better… I actually thought of clearing the undo stack at the end of the script, but that would not be very nice… :stuck_out_tongue_winking_eye:

Thx, --Mitch

LayerRandomizeRestoreUndo.py (933 Bytes)

LayerEx1.3dm (24.9 KB)

LayerEx2.3dm (25.4 KB)

You may need to add a custom undo event. If you store the “state” of before and “after”, you can restore and the old state when the user runs _Undo. Also think about _Redo!

http://4.rhino3d.com/5/rhinocommon/html/M_Rhino_RhinoDoc_AddCustomUndoEvent.htm

Yeah, thanks Menno, except I wouldn’t have the slightest idea how to go about doing that… :confused:

Apologies, I was not at my computer when I wrote my suggestion. I think it is a bug because the layer has its original name, but this is not showing the GUI. Giving an additional CommitChanges will fix it:

Also includes the way to handle undo and redo custom events.

import scriptcontext as sc
import Rhino, uuid, System



def RandomizeTopLevelLayers():
    #randomize top level layer names by adding unique uuid to layer name
    
    tl_dic={}
    for layer in sc.doc.Layers:
        if layer.ParentLayerId == System.Guid.Empty:
            #layer is a top level layer
            random_name=str(uuid.uuid4())
            new_name=random_name
            tl_dic[new_name]=layer.Name
            layer.Name=new_name
            layer.CommitChanges()
    sc.sticky["layer_random"] = tl_dic

def RestoreTopLevelLayers():
    #restore top level layer names using previously created dictionary
    tl_dic = sc.sticky["layer_random"]
    for layer in sc.doc.Layers:
        if layer.Name in tl_dic:
                layer.Name=tl_dic[layer.Name]
                layer.CommitChanges()
                
def UndoHandler(sender, args):
    print args
    if args.CreatedByRedo:
        print "REDOING"
        sc.doc.AddCustomUndoEvent("Undo/redo random layer", UndoHandler)
        print "REDO DONE"
    else:
        print "UNDOING"
        tl_dic = sc.sticky["layer_random"]
        # the layer has its original name, but this is not 
        # showing in Rhino. By giving an additional CommitChanges
        # that is solved. This is, as far as I can see, a bug.
        for layer in sc.doc.Layers:
            layer.Name = layer.Name
            layer.CommitChanges();
        sc.doc.AddCustomUndoEvent("Undo/redo random layer", UndoHandler)
        print "UNDO DONE"
                
def LayerRandomizeRestoreUndo():
    RandomizeTopLevelLayers()
    RestoreTopLevelLayers()
    sc.doc.AddCustomUndoEvent("Undo/redo random layer", UndoHandler);
    
LayerRandomizeRestoreUndo()


Hi Menno,

Thanks… Without actually creating the undo handler, I cannot get it to work just trying to run the re-naming procedure twice… --Mitch