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.