I am writing an Add Mesh Operator by sub-classing the bpy.types.Operator
and bpy_extras.object_utils.AddObjectHelper
. As my object is comprised of a series of components I thought it best to group them using Property Groups i.e. sub-classing bpy.types.PropertyGroup
. These property groups are assigned as attributes of the operator using bpy.props.PointerProperty
.
Seems this is the defacto manner of doing so.
Magically this works more or less straight out of the box with the caveat that the PointerProperty
is drawn as an empty block by the Operators default draw method, which I have not overwritten. An example is shown below.
So being reasonably savvy with these things I get the impression that the default draw method, provided, I believe by the bpy.types.operator
class, does not appear to handle the drawing of pointer properties which seems fair enough. After all no one wants to go all the way down the rabbit hole for UI code. What is the best strategy for drawing a 'nested' set of properties ?
I figured that the Operator's draw method might interrogate the PropertyGroup
to see if it supported a draw method it could execute but it does not. The alternative is to provide a draw method to the operator but this (due to my lack of knowledge) prevents the location and rotation properties from showing. Blender is mature enough that there ought to be some guidelines on this but I haven't had any luck finding any over the past day. I goggled some source code but there was not much to go on there or at least travelling up the class hierarchy didn't show me where the default draw method resides, I must have missed it.
I've attached the code I have below for clarity. It appends a menu under the new mesh menu (Shift+A > Mesh > New Mesh).
# Package Dependencies
import bpy
import bpy_extras
from math import *
from mathutils import *
# Package Information
bl_info = {
"name" : "NAME",
"location" : "View3D > Add > Mesh > New MESH",
"category" : "Add MESH",
"description" : "This adds a MESH",
#"warning" : "Alpha Release, much still to do...",
"author" : "Carel",
#"support" : "TESTING",
#"wiki_url" : "",
#"tracker_url" : "",
"version" : (0, 1),
"blender" : (2, 69, 0),
}
# Mesh Properties
class MeshProperties(bpy.types.PropertyGroup) :
"""MESH properties"""
Height = bpy.props.FloatProperty(
name = "Height",
description = "The height",
default = 5.0,
min = 0.0,
max = 100.0,
unit = 'LENGTH')
Width = bpy.props.FloatProperty(
name = "Width",
description = "The width",
default = 5.0,
min = 0.0,
max = 100.0,
unit = 'LENGTH')
Length = bpy.props.FloatProperty(
name = "Length",
description = "The Length",
default = 5.0,
min = 0.0,
max = 100.0)
# Failed draw method
# def draw(self, context) :
# layout = self.layout
# layout.label(text="Inner Sanctum")
class MESH_OT_primitive_Mesh_add(bpy.types.Operator, bpy_extras.object_utils.AddObjectHelper) :
"""Creates Mesh"""
bl_idname = "mesh.primitive_mesh_add"
bl_label = "Add Mesh"
bl_options = {'REGISTER', 'UNDO'} # , 'PRESET'}
dims = bpy.props.PointerProperty(name ="Dimensions", type=MeshProperties)
def add_Mesh(self) :
print(dir(self.dims))
tvrts = [(self.dims.Width*cos(radians(theta)), self.dims.Length*sin(radians(theta)), self.dims.Height) for theta in range(0,360,90)]
bvrts = [(self.dims.Width*cos(radians(theta)), self.dims.Length*sin(radians(theta)), -self.dims.Height) for theta in range(0,360,90)]
verts = [item for list in zip(tvrts,bvrts) for item in list]
edges = []
faces = list(zip(range(0,len(verts),2),range(1,len(verts),2),range(3,len(verts),2),range(2,len(verts),2))) + [(len(verts)-1,len(verts)-2,0,1)]
return verts, edges, faces
def execute(self, context) :
v,e,f = self.add_Mesh()
me = bpy.data.meshes.new(name="Mesh")
me.from_pydata(v, e, f)
bpy_extras.object_utils.object_data_add(context, me, operator=self)
return {"FINISHED"}
# def draw(self, context) :
# layout = self.layout
# layout.label(text=str(dir(self.properties)))
# layout.label(text="Yeah alright")
def addMeshMenu(self, context) :
self.layout.operator(MESH_OT_primitive_Mesh_add.bl_idname, text="Add Mesh")
def register():
bpy.utils.register_class(MeshProperties)
bpy.utils.register_class(MESH_OT_primitive_Mesh_add)
bpy.types.INFO_MT_mesh_add.append(addMeshMenu)
def unregister():
bpy.utils.unregister_class(MESH_OT_primitive_Mesh_add)
bpy.utils.unregister_class(MeshProperties)
bpy.types.INFO_MT_mesh_add.remove(addMeshMenu)
if __name__ == "__main__" :
register()
options
property as discussed here. The hope being that blender would naturally expand pointer properties. $\endgroup$