1
$\begingroup$

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.

enter image description here

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()
$\endgroup$
2
  • $\begingroup$ @zeffii I included a MWE. Quite odd for me really i usually post a MNWE (Minimal Non-Working Example). Hope it provides sufficient clarity. I believe the proper way to fix this is to provide a draw method for my operator. Which reduces my question to the best way of doing so ? $\endgroup$
    – Carel
    Jan 1, 2016 at 20:40
  • $\begingroup$ Originally I should have inquired more about the options property as discussed here. The hope being that blender would naturally expand pointer properties. $\endgroup$
    – Carel
    Jan 18, 2016 at 10:14

1 Answer 1

2
$\begingroup$

You were close. Stick this in MESH_OT_primitive_Mesh_add

def draw(self, context):
    layout = self.layout
    # Alignment
    col = layout.column(align=True)
    col.prop(self, 'view_align')
    # Location
    col = layout.column(align=True)
    col.label(text="Location")
    col.prop(self, 'location', text="")
    # Rotation
    col = layout.column(align=True)
    col.label(text="Rotation")
    col.prop(self, 'rotation', text="")
    # Other code here
    col = layout.column()
    col.prop(self.dims, "Height")
    col.prop(self.dims, "Width")
    col.prop(self.dims, "Length")

enter image description here

$\endgroup$
5
  • $\begingroup$ Thanks, that's really helpful. I've edited your post to include the rotation and position information. $\endgroup$
    – Carel
    Jan 5, 2016 at 8:51
  • $\begingroup$ I was trying to find a proper fix for it and re-edit the edit, but you're like a tiger on the response time :P $\endgroup$
    – Carel
    Jan 5, 2016 at 9:31
  • $\begingroup$ gist.github.com/zeffii/248ece121205617c15d0 $\endgroup$
    – zeffii
    Jan 5, 2016 at 9:39
  • $\begingroup$ I'm more for gist.github.com/Carelvd/15e4a61aff93076419eb which I finally found in the add torus script, this allows for a more blender like interface (P.S. the tiger quib was a compliment, thanks once again) $\endgroup$
    – Carel
    Jan 5, 2016 at 9:44
  • 1
    $\begingroup$ cool, it's edit UI to fit taste :) $\endgroup$
    – zeffii
    Jan 5, 2016 at 10:22

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .