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…
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!
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()