Declare as many menus as you like and concatenate them by calling each menu within the previous menu by layout.menu(menu_identifier)
.

You can even automatically draw a button to call your menu without declaring any extra operator by layout.operator("wm.call_menu").name="menu_identifier"
.
Code ripped from How to create a custom UI? and combined with Templates > Python > Ui Menu.
bl_info = {
"name": "Add-on Template",
"description": "",
"author": "",
"version": (0, 0, 1),
"blender": (2, 70, 0),
"location": "3D View > Tools",
"warning": "", # used for warning icon and text in addons panel
"wiki_url": "",
"tracker_url": "",
"category": "Development"
}
import bpy
# ------------------------------------------------------------------------
# custom menus
# ------------------------------------------------------------------------
class MyCustomMenu(bpy.types.Menu):
bl_label = "First Menu"
bl_idname = "OBJECT_MT_custom_menu"
def draw(self, context):
layout = self.layout
layout.label(text="Hello First Menu!", icon='WORLD_DATA')
# call the second custom menu
layout.menu("OBJECT_MT_sub_menu", icon="COLLAPSEMENU")
# use an operator enum property to populate a sub-menu
layout.operator_menu_enum("object.select_by_type",
property="type",
text="Select All Objects by Type...",
)
class MyCustomSubMenu(bpy.types.Menu):
bl_label = "Sub Menu"
bl_idname = "OBJECT_MT_sub_menu"
def draw(self, context):
layout = self.layout
layout.label(text="Hello Second Menu!", icon='WORLD_DATA')
# call another menu
layout.operator("wm.call_menu", text="Unwrap").name = "VIEW3D_MT_uv_map"
# just for fun call the first one again
layout.menu("OBJECT_MT_sub_sub_menu", icon="COLLAPSEMENU")
class MyCustomSubSubMenu(bpy.types.Menu):
bl_label = "Sub Sub Menu"
bl_idname = "OBJECT_MT_sub_sub_menu"
def draw(self, context):
layout = self.layout
layout.label(text="Hello Third Menu!", icon='WORLD_DATA')
# ------------------------------------------------------------------------
# my tool in objectmode
# ------------------------------------------------------------------------
class OBJECT_PT_my_panel(bpy.types.Panel):
bl_idname = "OBJECT_PT_my_panel"
bl_label = "My Panel"
bl_space_type = "VIEW_3D"
bl_region_type = "TOOLS"
bl_category = "Tools"
bl_context = "objectmode"
'''
@classmethod
def poll(self,context):
return context.object is not None
'''
def draw(self, context):
layout = self.layout
scene = context.scene
mytool = scene.my_tool
layout.prop(mytool, "my_int")
layout.prop(mytool, "my_enum", text="")
layout.operator("wm.call_menu", text="Call My Menu").name = "OBJECT_MT_custom_menu"
# ------------------------------------------------------------------------
# settings
# ------------------------------------------------------------------------
class MySettings(bpy.types.PropertyGroup):
my_int = bpy.props.IntProperty(
name = "Int Value",
description="A integer property",
default = 23,
min = 10,
max = 100
)
my_enum = bpy.props.EnumProperty(
name="Dropdown:",
description="Apply Data to attribute.",
items=[ ('OP1', "Option 1", ""),
('OP2', "Option 2", ""),
('OP3', "Option 3", ""),
]
)
# ------------------------------------------------------------------------
# register and unregister the classes
# ------------------------------------------------------------------------
def register():
bpy.utils.register_module(__name__)
bpy.types.Scene.my_tool = bpy.props.PointerProperty(type=MySettings)
def unregister():
bpy.utils.unregister_module(__name__)
del bpy.types.Scene.my_tool
if __name__ == "__main__":
register()
# The menu can also be called from scripts
# bpy.ops.wm.call_menu(name=CustomMenu.bl_idname)
layout.menu("INFO_MT_mesh_add", text="Add")
Please make some effort to code this yourself, then if you come into difficulties write a question based on that. $\endgroup$ – batFINGER Sep 20 '17 at 11:00operator_menu_enum
to add a submenu. $\endgroup$ – sambler Sep 20 '17 at 11:09