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$
  • $\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 '16 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 '16 at 10:14
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$
  • $\begingroup$ Thanks, that's really helpful. I've edited your post to include the rotation and position information. $\endgroup$ – Carel Jan 5 '16 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 '16 at 9:31
  • $\begingroup$ gist.github.com/zeffii/248ece121205617c15d0 $\endgroup$ – zeffii Jan 5 '16 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 '16 at 9:44
  • 1
    $\begingroup$ cool, it's edit UI to fit taste :) $\endgroup$ – zeffii Jan 5 '16 at 10:22

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.