1
$\begingroup$

enter image description here

Hi, I´m aiming to create panels with menus and submenus in the TOOLS area type just like in the picture to the LEFT. Blender pops up a shortcut menu (with shift+a) and I see it´s got arrows pointing to a submenu populated with options.

I saw the py demos on the text editor, but none of those make a main panel nesting sub panels. I want to be able to contract/expand the panel and thus reveal or hide the subPanels. The 2nd level of menu branching will

$\endgroup$
  • 1
    $\begingroup$ Welcome to bse Pierre. There are a number of addons in blender that use expanding panels and or menus in the tool area. The source code can be viewed by right clicking and selecting "view source". Doing this on the Add menu in the 3D view header 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:00
  • 1
    $\begingroup$ This answer shows expanding panels. For menus this answer shows using operator_menu_enum to add a submenu. $\endgroup$ – sambler Sep 20 '17 at 11:09
2
$\begingroup$

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

enter image description here

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)
$\endgroup$
  • $\begingroup$ Great code. It works wonderfully. Is there a way to offset the first menu by 100+ pixels in X from where the mouse clicks? or is there any chance to open the menu pop up in a specific coordinate relative to % of the screen space? $\endgroup$ – Pierre Schiller Sep 21 '17 at 17:21
  • $\begingroup$ Not that I know of. Even if that's possible, it doesn't makes sense from the user point of view IMHO. However, that's might worth a new question @PierreSchiller $\endgroup$ – brockmann Sep 21 '17 at 18:44

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.