Built-in primitive adders written in C (e.g. Icosphere) stay in EDIT mode while the user futzes with the settings (subdivisions, radius, etc.)
The inlcuded Torus addon, written in Python, stays in OBJECT mode.
I wrote my own primitive addon, and it’s critical for the user to be able to clearly see the mesh resolution. Staying in EDIT mode is thus necessary, as OBJECT mode looks too smooth.
Here’s the shell of my operator (all details removed):
class NewAirfoil(bpy.types.Operator):bl_idname = "aeroblender.new_airfoil"
bl_label = "New Airfoil"
bl_options = {'REGISTER',<b>'UNDO'</b>}
def execute(self, context):
[INDENT=2]MakeAirfoil() # Makes my primitive
[/INDENT]
[INDENT=2]<b>bpy.ops.object.mode_set(mode='EDIT')
</b>return {'FINISHED'}[/INDENT]
PROBLEM: Without the line in bold, I can’t see the mesh resolution (stays in OBJECT mode)
With the line in bold, the UNDO functionality appears to be broken. Each successive update appears to toggle between edit and object mode, and (strangely) a second object is often present that uses the default primitive parameters.
if you run this operator via spacebar menu, it will add a triangle and you can change the parameters while being in edit-mode:
import bpy
import bmesh
from bpy.props import IntProperty
class SimpleOperator(bpy.types.Operator):
"""Tooltip"""
bl_idname = "object.simple_operator"
bl_label = "Simple Object Operator"
bl_options = {'REGISTER', 'UNDO'}
x = IntProperty(default=2)
y = IntProperty(default=3)
z = IntProperty(default=5)
@classmethod
def poll(cls, context):
return context.edit_object is not None
def execute(self, context):
ob = context.edit_object
me = ob.data
bm = bmesh.from_edit_mesh(me)
v1 = bm.verts.new((0,0,self.z))
v2 = bm.verts.new((self.x,0,self.z))
v3 = bm.verts.new((0,self.y,self.z))
bm.faces.new((v1, v2, v3))
bmesh.update_edit_mesh(me, True, True)
return {'FINISHED'}
def register():
bpy.utils.register_class(SimpleOperator)
def unregister():
bpy.utils.unregister_class(SimpleOperator)
if __name__ == "__main__":
register()
you could add an invoke() to always start with certain default parameters (above script remembers last used settings and adds a triangle in the same place as previous one).
Problem here is that the newly added triangle shows black in solid mode, dunno why view doesn’t refresh… me.update() doesn’t help. Maybe a bug.
here’s a fixed version, no more black geometry (a call to update normals was required, thanks to ideasman42 for pointing that out) and always starting with (2,3,5) as input values:
import bpyimport bmesh
from bpy.props import IntProperty
class SimpleOperator(bpy.types.Operator):
"""Tooltip"""
bl_idname = "object.simple_operator"
bl_label = "Simple Object Operator"
bl_options = {'REGISTER', 'UNDO'}
x = IntProperty()
y = IntProperty()
z = IntProperty()
@classmethod
def poll(cls, context):
return context.edit_object is not None
def invoke(self, context, event):
self.x = 2
self.y = 3
self.z = 5
self.execute(context)
return {'FINISHED'}
def execute(self, context):
ob = context.edit_object
me = ob.data
bm = bmesh.from_edit_mesh(me)
v1 = bm.verts.new((0,0,self.z))
v2 = bm.verts.new((self.x,0,self.z))
v3 = bm.verts.new((0,self.y,self.z))
bm.faces.new((v1, v2, v3))
bm.normal_update()
bmesh.update_edit_mesh(me, True, True)
me.update()
return {'FINISHED'}
def register():
bpy.utils.register_class(SimpleOperator)
def unregister():
bpy.utils.unregister_class(SimpleOperator)
if __name__ == "__main__":
register()
It seems that the bug comes from switching back and forth between Object and Edit mode. If the operator stays permanently in one mode or the other, there’s no problem.
Is there something that fundamentally breaks with the “Undo” functionality when switching between modes in an operator?
To make this work I’d need to recode in B-mesh (currently I’m using “ops.mesh.from_py_data”). Not hard, but tedious.