# How to extract commands such as single dupliverts

To my understanding now Blender has many single commands that can be run via python commands and those commands are embedded into UI scripts.

For example the command for Duplication.

layout.prop(ob, "dupli_type", expand=True)


Now if I click Verts the Consol will write:

bpy.ops.object.duplicates_make_real()
bpy.context.object.dupli_type = 'NONE'
bpy.context.object.use_dupli_vertices_rotation = True
bpy.context.object.dupli_faces_scale = 1
bpy.context.object.dupli_type = 'VERTS'


I try to understand how for example I could only display None, Verts, and Faces plus their settings Rotate and Scale and package that into a box layout.

col = layout.row()
split = col.split(percentage=1.0)
box = split.column().box()

row = box.row()
row.label('Geometry Instancing')
row = box.row()
row.operator("context.object.dupli_type = 'VERTS'", text="VERTS")
row.prop(ob, "dupli_faces_scale", text="Inherit Scale")


But this only generates the button for scale and does not draw the Verts Type button. I assume this has something to do with the way how the object.dupli_type is called and the type declared.

I hope the way I explained this makes sense. In the end I would like to generate slimmer UI interfaces for my students so that they are only presented with Values/options usable for ID. Frame and Group is not a function we would use in product design.

The row of "dupli_type" options [None, Frame, Verts, Faces, Group] comes from what is called an EnumProperty. Blender uses this as a radio-box-like interface to give you a choice from a list. The item you select determines which elements of the UI become visible.

Right-Click on the Verts button, pick Edit Source, go to the TextEditor and open properties_object.py it will show at the line where that UI element is referenced.

The Duplication panel's draw is like this. Notice that the 5 possible states are covered by the if-elif-elif-elif. Notably the choice for NONE results in no drawing at all because it isn't in any of those tests. There's nothing to show in the case of 'NONE' so a 5th logic statement is redundant.

def draw(self, context):
layout = self.layout

ob = context.object

layout.prop(ob, "dupli_type", expand=True)

if ob.dupli_type == 'FRAMES':
split = layout.split()

col = split.column(align=True)
col.prop(ob, "dupli_frames_start", text="Start")
col.prop(ob, "dupli_frames_end", text="End")

col = split.column(align=True)
col.prop(ob, "dupli_frames_on", text="On")
col.prop(ob, "dupli_frames_off", text="Off")

layout.prop(ob, "use_dupli_frames_speed", text="Speed")

elif ob.dupli_type == 'VERTS':
layout.prop(ob, "use_dupli_vertices_rotation", text="Rotation")

elif ob.dupli_type == 'FACES':
row = layout.row()
row.prop(ob, "use_dupli_faces_scale", text="Scale")
sub = row.row()
sub.active = ob.use_dupli_faces_scale
sub.prop(ob, "dupli_faces_scale", text="Inherit Scale")

elif ob.dupli_type == 'GROUP':
layout.prop(ob, "dupli_group", text="Group")


To make a custom panel for this you need to make a custom (deputy) EnumProperty, which should include some code to update the real property.

import bpy

class HelloWorldPanel(bpy.types.Panel):
"""Creates a Panel in the Object properties window"""
bl_label = "Hello World Panel"
bl_idname = "OBJECT_PT_hello"
bl_space_type = 'PROPERTIES'
bl_region_type = 'WINDOW'
bl_context = "object"

def draw(self, context):
layout = self.layout
ob = context.object

layout.prop(ob, "deputy_dupli_type", expand=True)

if ob.deputy_dupli_type == 'VERTS':
layout.prop(ob, "use_dupli_vertices_rotation", text="Rotation")

elif ob.deputy_dupli_type == 'FACES':
row = layout.row()
row.prop(ob, "use_dupli_faces_scale", text="Scale")
sub = row.row()
sub.active = ob.use_dupli_faces_scale
sub.prop(ob, "dupli_faces_scale", text="Inherit Scale")

def register():
# give all objects a new property (also known as an attribute)
# called "deputy_duply_type".
bpy.types.Object.deputy_dupli_type = bpy.props.EnumProperty(
items=[
('NONE', 'NONE', "", 0),
('VERTS', 'VERTS', "", 1),
('FACES', 'FACES', "", 2)
],
default='NONE',
update=lambda s, c: setattr(s, 'dupli_type', s.deputy_dupli_type)
)
bpy.utils.register_class(HelloWorldPanel)

def unregister():
bpy.utils.unregister_class(HelloWorldPanel)
del bpy.types.Object.deputy_dupli_type

if __name__ == "__main__":
register()


The downside in this case is that changes made back in the original Duplication Panel are not reflected in the state of your new deputy_dupli_type property. This may lead to some confusion, but if you aren't using the original panels then it isn't a problem.

Some code clarification:

update=lambda s, c: setattr(s, 'dupli_type', s.deputy_dupli_type)


The take-away from this line is (even if it looks like gibberish):

• Once the user picks a different option from the object.deputy_dupli_type, this triggers the object's dupli_type attribute to be set to the same value as the newly selected option.
• Good point about using the original code in case the foundation will change something. Thank you for the scrip! – Claas Kuhnen Jan 2 '16 at 18:15
• I didn't make myself clear then. My concern was if you can edit these properties in two distinct places (HelloWorldPanel and the original Duplication panel) then only the edits in HelloWorldPanel will be updated in the Duplication panel, and not vice versa. ..This is because there's no way to override the orignal dupli_type's update function. Don't worry if this doesn't make sense. You'll notice what I mean sooner or later. – zeffii Jan 2 '16 at 20:43
• Thank you very much for all the help - this is so useful - sorry that my qyestions must make your fingernails roll up ;) – Claas Kuhnen Jan 3 '16 at 5:04
• that's OK @ClaasKuhnen these are simple questions with sometimes complex answers. Customizing existing UI is very necessary, there's tonnes of stuff I don't use and don't need to see. – zeffii Jan 3 '16 at 8:24