Undo while in Modal Mode

Is there a way to undo an operation that was performed in Modal Mode, while remaining in Modal Mode?

For example, I am creating objects based on user clicks, and I would like to be able to undo (delete) just the most recent object that was created, while continuing to run modal. Adding bl_options = {‘REGISTER’, ‘UNDO’} undoes the entire modal operation, what I would like is to undo a single operation (eg event.type == ‘LEFTMOUSE’) and still return {‘RUNNING_MODAL’}.

Thanks for your ideas.

Maybe try to manually push an undo step after creating the object?

Thanks for the suggestion Stan Pancakes. This gets at the desired functionality as long as the ctrl-Z is also added as recognized input (a key step I had forgotten):

elif event.ctrl and event.type == ‘Z’ and event.value == ‘PRESS’:
bpy.ops.ed.undo()

However, I am having trouble undoing consistently. If I add an undo_push() before the creation of my new object, the first ctrl-Z removes the two most recently created objects, then each successive ctrl-Z removes a single object at a time. If I add a second undo_push() to the end of the object creation code, then the first ctrl-Z removes the single most recently created object as desired, but it has to be executed twice for each successive removal. Does anybody see what is happening here?

elif event.type == ‘M’ and event.value == ‘PRESS’:
bpy.ops.ed.undo_push(message=“undo1”)
### create new object here, code functions correctly

#bpy.ops.ed.undo_push(message="undo2")

Thanks for your help!

There is probably another undo_push that is happening within some of the operators you are using in your click code? For example, if you use

 bpy.ops.mesh.primitive_something_add() 

as part of the code that generates your objects, that operator might have an undo built in.

However if you are adding your objects this way…


my_prim_mesh = bpy.data.meshes.new('My Primitive")
#make some mesh data here#
my_prim = bpy.data.objects.new("My Primitive")
my_prim.data = my_prim_mesh
context.scene.objects.link(my_prim)

Then you can then write you own “undo” function which actually just deletes and unlinks the most recent object if that is truly all you need. Blender undo snapshots might be memory heavy so all those undo snapshots you are making within your modal might not be necessary if it’s a very specific reversal event that you need to happen.

In Polystrips and Contours, we use a custom data class to store our retopology mesh data, so for our undo() support, we cache a copy of our own data structure…wasn’t that fun to learn (it was my personal nightmare).

best,
Patrick

also, just for fun, try a single undo push after your new object is created.

Thanks patmo, I think my problem is indeed related to an undo built into an operation that I wasn’t thinking about. Thanks for your tips!

Great! glad we could help

You could try the following:

bpy.ops.mesh.primitive_something_add(context.copy(), ‘EXEC_DEFAULT’, False)

The third positional parameter is a boolean for undo. If you run an operator from Python console and set it to True, Redo will be enabled. In your case, setting it to False should prevent it from pushing to the undo stack.