Blender 2.8 - Add view 3d menu

I’m trying to append a new menu in the 3dView header with no success. Any idea ?

maquette

import bpy

class VIEW3D_MT_menu(bpy.types.Menu):
    bl_label = "Test"

    def draw(self, context):
        self.layout.operator("mesh.primitive_monkey_add")

def addmenu_callback(self, context):
    self.layout.menu("VIEW3D_MT_menu")


def register():
    bpy.utils.register_class(VIEW3D_MT_menu)
    bpy.types.VIEW3D_MT_editor_menus.append(addmenu_callback)
    #bpy.types.VIEW3D_HT_header.append(addmenu_callback)  

def unregister():
    bpy.types.VIEW3D_MT_editor_menus.remove(addmenu_callback)
    #bpy.types.VIEW3D_HT_header.remove(addmenu_callback)  
    bpy.utils.register_class(VIEW3D_MT_menu)


if __name__ == "__main__":
	register()
3 Likes

What you have works. It places it after the Shading overlays. Append places at the end and prepend places at the beginning. As far as trying to get it in a specific location. The only way to prolly do that is edit the main .py file.

import bpy

class VIEW3D_MT_menu(bpy.types.Menu):
    bl_label = "Test"

    def draw(self, context):
        self.layout.operator("mesh.primitive_monkey_add")

def addmenu_callback(self, context):
    self.layout.menu("VIEW3D_MT_menu")


def register():
    bpy.utils.register_class(VIEW3D_MT_menu)
    bpy.types.VIEW3D_HT_header.append(addmenu_callback)  

def unregister():
    bpy.types.VIEW3D_HT_header.remove(addmenu_callback)  
    bpy.utils.unregister_class(VIEW3D_MT_menu)


if __name__ == "__main__":
	register()
2 Likes

Thank you for the answer, I’ve also noticed that appending to VIEW3D_HT_header class works, but i don’t undersand why it does not works for VIEW3D_MT_editor_menus class. This one inherit from bpy.types.Menu and embed others menu in it’s layout; maybe the append functionnality is just not implemented for this bpy type, anyone can confirm this ?

1 Like

OK, check this out. It seems to get added ,but for some reason it doesn’t show in 3D View.

Run this first

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

		row = layout.row()
		row.menu("VIEW3D_MT_editor_menus")


def register():
	bpy.utils.register_class(HelloWorldPanel)


def unregister():
	bpy.utils.unregister_class(HelloWorldPanel)


if __name__ == "__main__":
	register()

then this

import bpy

class VIEW3D_MT_menu(bpy.types.Menu):
	bl_label = "Test"

	def draw(self, context):
		self.layout.operator("mesh.primitive_monkey_add")

		
def addmenu_callback(self, context):	
	self.layout.menu("VIEW3D_MT_menu")    
	


def register():
	bpy.utils.register_class(VIEW3D_MT_menu)
	bpy.types.VIEW3D_MT_editor_menus.append(addmenu_callback)  

def unregister():
	bpy.types.VIEW3D_MT_editor_menus.remove(addmenu_callback)  
	bpy.utils.unregister_class(VIEW3D_MT_menu)


if __name__ == "__main__":
	register()
1 Like

Thanks for the investigation, I openned a new issue on the bugs tracker : https://developer.blender.org/T58937

Hello,

I find this topic searching how to add a menu to the 3d view. I find a solution to do it (on Blender 3.6.5) and I wanted to share with you in case that help someone else.

To print your menu at the middle of the bar, you have to rewrite the full top bar and add your menu wherever you like.
You can get the code source with a right click on the Object menu of the top bar , then click “Edit source”.

That will open you the python code at the correct class which manage the view3d bar UI. Now you can copy the class in your script modify it by adding your menu with layout.menu("VIEW3D_MT_menu_name") then register the class.

Here is an example with the custom menu template :

import bpy
from bpy.types import Menu

# I needed to keep this import from the source code too make it work, but I don't now why
from bpy.app.translations import contexts as i18n_contexts

# Your custom menu
class VIEW3D_MT_custom_menu(Menu):
    bl_label = "My menu"
    
    def draw(self, _context):
        layout = self.layout
        
        layout.label(text="Hello world!")
        layout.operator("object.shade_smooth")

# Recreate the whole menu bar
class VIEW3D_MT_editor_menus(Menu):
    bl_label = ""

    def draw(self, context):
        layout = self.layout
        obj = context.active_object
        mode_string = context.mode
        edit_object = context.edit_object
        gp_edit = obj and obj.mode in {'EDIT_GPENCIL', 'PAINT_GPENCIL', 'SCULPT_GPENCIL',
                                       'WEIGHT_GPENCIL', 'VERTEX_GPENCIL'}
        tool_settings = context.scene.tool_settings

        layout.menu("VIEW3D_MT_view")

        # Select Menu
        if gp_edit:
            if mode_string not in {'PAINT_GPENCIL', 'WEIGHT_GPENCIL'}:
                if (
                        mode_string == 'SCULPT_GPENCIL' and
                        (tool_settings.use_gpencil_select_mask_point or
                         tool_settings.use_gpencil_select_mask_stroke or
                         tool_settings.use_gpencil_select_mask_segment)
                ):
                    layout.menu("VIEW3D_MT_select_gpencil")
                elif mode_string == 'EDIT_GPENCIL':
                    layout.menu("VIEW3D_MT_select_gpencil")
                elif mode_string == 'VERTEX_GPENCIL':
                    layout.menu("VIEW3D_MT_select_gpencil")
        elif mode_string in {'PAINT_WEIGHT', 'PAINT_VERTEX', 'PAINT_TEXTURE'}:
            mesh = obj.data
            if mesh.use_paint_mask:
                layout.menu("VIEW3D_MT_select_paint_mask")
            elif mesh.use_paint_mask_vertex and mode_string in {'PAINT_WEIGHT', 'PAINT_VERTEX'}:
                layout.menu("VIEW3D_MT_select_paint_mask_vertex")
        elif mode_string not in {'SCULPT', 'SCULPT_CURVES'}:
            layout.menu("VIEW3D_MT_select_%s" % mode_string.lower())

        if gp_edit:
            pass
        elif mode_string == 'OBJECT':
            layout.menu("VIEW3D_MT_add", text="Add", text_ctxt=i18n_contexts.operator_default)
        elif mode_string == 'EDIT_MESH':
            layout.menu("VIEW3D_MT_mesh_add", text="Add", text_ctxt=i18n_contexts.operator_default)
        elif mode_string == 'EDIT_CURVE':
            layout.menu("VIEW3D_MT_curve_add", text="Add", text_ctxt=i18n_contexts.operator_default)
        elif mode_string == 'EDIT_SURFACE':
            layout.menu("VIEW3D_MT_surface_add", text="Add", text_ctxt=i18n_contexts.operator_default)
        elif mode_string == 'EDIT_METABALL':
            layout.menu("VIEW3D_MT_metaball_add", text="Add", text_ctxt=i18n_contexts.operator_default)
        elif mode_string == 'EDIT_ARMATURE':
            layout.menu("TOPBAR_MT_edit_armature_add", text="Add", text_ctxt=i18n_contexts.operator_default)

        if gp_edit:
            if obj and obj.mode == 'PAINT_GPENCIL':
                layout.menu("VIEW3D_MT_draw_gpencil")
            elif obj and obj.mode == 'EDIT_GPENCIL':
                layout.menu("VIEW3D_MT_edit_gpencil")
                layout.menu("VIEW3D_MT_edit_gpencil_stroke")
                layout.menu("VIEW3D_MT_edit_gpencil_point")
            elif obj and obj.mode == 'WEIGHT_GPENCIL':
                layout.menu("VIEW3D_MT_weight_gpencil")
            if obj and obj.mode == 'VERTEX_GPENCIL':
                layout.menu("VIEW3D_MT_paint_gpencil")

        elif edit_object:
            layout.menu("VIEW3D_MT_edit_%s" % edit_object.type.lower())

            if mode_string == 'EDIT_MESH':
                layout.menu("VIEW3D_MT_edit_mesh_vertices")
                layout.menu("VIEW3D_MT_edit_mesh_edges")
                layout.menu("VIEW3D_MT_edit_mesh_faces")
                layout.menu("VIEW3D_MT_uv_map", text="UV")
            elif mode_string in {'EDIT_CURVE', 'EDIT_SURFACE'}:
                layout.menu("VIEW3D_MT_edit_curve_ctrlpoints")
                layout.menu("VIEW3D_MT_edit_curve_segments")

        elif obj:
            if mode_string not in {'PAINT_TEXTURE', 'SCULPT_CURVES'}:
                layout.menu("VIEW3D_MT_%s" % mode_string.lower())
            if mode_string == 'SCULPT':
                layout.menu("VIEW3D_MT_mask")
                layout.menu("VIEW3D_MT_face_sets")
            if mode_string == 'SCULPT_CURVES':
                layout.menu("VIEW3D_MT_select_sculpt_curves")
                layout.menu("VIEW3D_MT_sculpt_curves")

        else:
            layout.menu("VIEW3D_MT_object")
            
        # Add your Custom menu
        layout.menu("VIEW3D_MT_custom_menu")


if __name__ == "__main__":  # only for live edit.
    from bpy.utils import register_class
    register_class(VIEW3D_MT_custom_menu)
    register_class(VIEW3D_MT_editor_menus)

Here you go !!!
Now you can see that a menu : “My menu” as appear.