# ##### BEGIN GPL LICENSE BLOCK #####
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#n
# ##### END GPL LICENSE BLOCK #####
bl_info = {
"name": "Classic Add Menus with Accelerator",
"author": "Duarte Farrajota Ramos",
"version": (1, 1),
"blender": (4, 00, 0),
"location": "Properties > Modifiers, 3D View > Add Menu",
"description": "Brings back classic add modifier and add object menus with accelarator keys",
"warning": "",
"doc_url": "http://duarteramos.pt/addons.html",
"category": "UI",
}
import bpy
from bpy.utils import register_class
from bpy.types import (
Header,
Menu,
Panel,
)
from bpy.app.translations import (
pgettext_iface as iface_,
pgettext_tip as tip_,
contexts as i18n_contexts,
)
class VIEW3D_MT_mesh_add_classic(Menu):
bl_idname = "VIEW3D_MT_mesh_add_classic"
bl_label = "Mesh"
##bl_options = {'SEARCH_ON_KEY_PRESS'}
def draw(self, _context):
layout = self.layout
layout.operator_context = 'INVOKE_REGION_WIN'
layout.operator("mesh.primitive_plane_add", text="Plane", icon='MESH_PLANE')
layout.operator("mesh.primitive_cube_add", text="Cube", icon='MESH_CUBE')
layout.operator("mesh.primitive_circle_add", text="Circle", icon='MESH_CIRCLE')
layout.operator("mesh.primitive_uv_sphere_add", text="UV Sphere", icon='MESH_UVSPHERE')
layout.operator("mesh.primitive_ico_sphere_add", text="Ico Sphere", icon='MESH_ICOSPHERE')
layout.operator("mesh.primitive_cylinder_add", text="Cylinder", icon='MESH_CYLINDER')
layout.operator("mesh.primitive_cone_add", text="Cone", icon='MESH_CONE')
layout.operator("mesh.primitive_torus_add", text="Torus", icon='MESH_TORUS')
layout.separator()
layout.operator("mesh.primitive_grid_add", text="Grid", icon='MESH_GRID')
layout.operator("mesh.primitive_monkey_add", text="Monkey", icon='MESH_MONKEY')
layout.template_node_operator_asset_menu_items(catalog_path="Add")
class VIEW3D_MT_curve_add_classic(Menu):
bl_idname = "VIEW3D_MT_curve_add_classic"
bl_label = "Curve"
##bl_options = {'SEARCH_ON_KEY_PRESS'}
def draw(self, context):
layout = self.layout
layout.operator_context = 'INVOKE_REGION_WIN'
layout.operator("curve.primitive_bezier_curve_add", text="Bezier", icon='CURVE_BEZCURVE')
layout.operator("curve.primitive_bezier_circle_add", text="Circle", icon='CURVE_BEZCIRCLE')
layout.separator()
layout.operator("curve.primitive_nurbs_curve_add", text="Nurbs Curve", icon='CURVE_NCURVE')
layout.operator("curve.primitive_nurbs_circle_add", text="Nurbs Circle", icon='CURVE_NCIRCLE')
layout.operator("curve.primitive_nurbs_path_add", text="Path", icon='CURVE_PATH')
layout.separator()
layout.operator("object.curves_empty_hair_add", text="Empty Hair", icon='CURVES_DATA')
layout.operator("object.quick_fur", text="Fur", icon='CURVES_DATA')
experimental = context.preferences.experimental
if experimental.use_new_curves_tools:
layout.operator("object.curves_random_add", text="Random", icon='CURVES_DATA')
class VIEW3D_MT_surface_add_classic(Menu):
bl_idname = "VIEW3D_MT_surface_add_classic"
bl_label = "Surface"
##bl_options = {'SEARCH_ON_KEY_PRESS'}
def draw(self, _context):
layout = self.layout
layout.operator_context = 'INVOKE_REGION_WIN'
layout.operator("surface.primitive_nurbs_surface_curve_add", text="Nurbs Curve", icon='SURFACE_NCURVE')
layout.operator("surface.primitive_nurbs_surface_circle_add", text="Nurbs Circle", icon='SURFACE_NCIRCLE')
layout.operator("surface.primitive_nurbs_surface_surface_add", text="Nurbs Surface", icon='SURFACE_NSURFACE')
layout.operator("surface.primitive_nurbs_surface_cylinder_add",
text="Nurbs Cylinder", icon='SURFACE_NCYLINDER')
layout.operator("surface.primitive_nurbs_surface_sphere_add", text="Nurbs Sphere", icon='SURFACE_NSPHERE')
layout.operator("surface.primitive_nurbs_surface_torus_add", text="Nurbs Torus", icon='SURFACE_NTORUS')
class VIEW3D_MT_edit_metaball_context_menu_classic(Menu):
bl_label = "Metaball"
def draw(self, _context):
layout = self.layout
layout.operator_context = 'INVOKE_REGION_WIN'
# Add
layout.operator("mball.duplicate_move")
layout.separator()
# Modify
layout.menu("VIEW3D_MT_mirror")
layout.menu("VIEW3D_MT_snap")
layout.separator()
# Remove
layout.operator_context = 'EXEC_REGION_WIN'
layout.operator("mball.delete_metaelems", text="Delete")
class VIEW3D_MT_metaball_add_classic(Menu):
bl_idname = "VIEW3D_MT_metaball_add_classic"
bl_label = "Metaball"
##bl_options = {'SEARCH_ON_KEY_PRESS'}
def draw(self, _context):
layout = self.layout
layout.operator_context = 'INVOKE_REGION_WIN'
layout.operator_enum("object.metaball_add", "type")
class VIEW3D_MT_armature_add_classic(Menu):
bl_idname = "VIEW3D_MT_armature_add_classic"
bl_label = "Armature"
#bl_options = {'SEARCH_ON_KEY_PRESS'}
def draw(self, _context):
layout = self.layout
layout.operator_context = 'EXEC_REGION_WIN'
layout.operator("object.armature_add", text="Single Bone", icon='BONE_DATA')
class VIEW3D_MT_light_add_classic(Menu):
bl_idname = "VIEW3D_MT_light_add_classic"
bl_context = i18n_contexts.id_light
bl_label = "Light"
#bl_options = {'SEARCH_ON_KEY_PRESS'}
def draw(self, _context):
layout = self.layout
layout.operator_context = 'INVOKE_REGION_WIN'
layout.operator_enum("object.light_add", "type")
class VIEW3D_MT_lightprobe_add_classic(Menu):
bl_idname = "VIEW3D_MT_lightprobe_add_classic"
bl_label = "Light Probe"
#bl_options = {'SEARCH_ON_KEY_PRESS'}
def draw(self, _context):
layout = self.layout
layout.operator_context = 'INVOKE_REGION_WIN'
layout.operator_enum("object.lightprobe_add", "type")
class VIEW3D_MT_camera_add_classic(Menu):
bl_idname = "VIEW3D_MT_camera_add_classic"
bl_label = "Camera"
#bl_options = {'SEARCH_ON_KEY_PRESS'}
def draw(self, _context):
layout = self.layout
layout.operator_context = 'EXEC_REGION_WIN'
layout.operator("object.camera_add", text="Camera", icon='OUTLINER_OB_CAMERA')
class VIEW3D_MT_volume_add_classic(Menu):
bl_idname = "VIEW3D_MT_volume_add_classic"
bl_label = "Volume"
bl_translation_context = i18n_contexts.id_id
#bl_options = {'SEARCH_ON_KEY_PRESS'}
def draw(self, _context):
layout = self.layout
layout.operator("object.volume_import", text="Import OpenVDB...", icon='OUTLINER_DATA_VOLUME')
layout.operator("object.volume_add", text="Empty",
text_ctxt=i18n_contexts.id_volume,
icon='OUTLINER_DATA_VOLUME')
class VIEW3D_MT_grease_pencil_add_classic(Menu):
bl_idname = "VIEW3D_MT_grease_pencil_add_classic"
bl_label = "Grease Pencil"
#bl_options = {'SEARCH_ON_KEY_PRESS'}
def draw(self, _context):
layout = self.layout
layout.operator("object.grease_pencil_add", text="Empty", icon='EMPTY_AXIS').type = 'EMPTY'
layout.operator("object.grease_pencil_add", text="Stroke", icon='STROKE').type = 'STROKE'
layout.operator("object.grease_pencil_add", text="Suzanne", icon='MONKEY').type = 'MONKEY'
class VIEW3D_MT_add_classic(Menu):
bl_label = "Add"
bl_translation_context = i18n_contexts.operator_default
#bl_options = {'SEARCH_ON_KEY_PRESS'}
def draw(self, context):
layout = self.layout
if layout.operator_context == 'EXEC_REGION_WIN':
layout.operator_context = 'INVOKE_REGION_WIN'
layout.operator("WM_OT_search_single_menu", text="Search...", icon='VIEWZOOM').menu_idname = "VIEW3D_MT_add"
layout.separator()
# NOTE: don't use 'EXEC_SCREEN' or operators won't get the `v3d` context.
# NOTE: was `EXEC_AREA`, but this context does not have the `rv3d`, which prevents
# "align_view" to work on first call (see #32719).
layout.operator_context = 'EXEC_REGION_WIN'
# layout.operator_menu_enum("object.mesh_add", "type", text="Mesh", icon='OUTLINER_OB_MESH')
layout.menu("VIEW3D_MT_mesh_add_classic", icon='OUTLINER_OB_MESH')
# layout.operator_menu_enum("object.curve_add", "type", text="Curve", icon='OUTLINER_OB_CURVE')
layout.menu("VIEW3D_MT_curve_add_classic", icon='OUTLINER_OB_CURVE')
# layout.operator_menu_enum("object.surface_add", "type", text="Surface", icon='OUTLINER_OB_SURFACE')
layout.menu("VIEW3D_MT_surface_add_classic", icon='OUTLINER_OB_SURFACE')
layout.menu("VIEW3D_MT_metaball_add_classic", text="Metaball", icon='OUTLINER_OB_META')
layout.operator("object.text_add", text="Text", icon='OUTLINER_OB_FONT')
if context.preferences.experimental.use_new_point_cloud_type:
layout.operator("object.pointcloud_add", text="Point Cloud", icon='OUTLINER_OB_POINTCLOUD')
layout.menu("VIEW3D_MT_volume_add_classic", text="Volume", text_ctxt=i18n_contexts.id_id, icon='OUTLINER_OB_VOLUME')
if context.preferences.experimental.use_grease_pencil_version3:
layout.menu("VIEW3D_MT_grease_pencil_add_classic", text="Grease Pencil", icon='OUTLINER_OB_GREASEPENCIL')
else:
layout.operator_menu_enum(
"object.gpencil_add",
"type",
text="Grease Pencil",
icon='OUTLINER_OB_GREASEPENCIL')
layout.separator()
if VIEW3D_MT_armature_add_classic.is_extended():
layout.menu("VIEW3D_MT_armature_add_classic", icon='OUTLINER_OB_ARMATURE')
else:
layout.operator("object.armature_add", text="Armature", icon='OUTLINER_OB_ARMATURE')
layout.operator("object.add", text="Lattice", icon='OUTLINER_OB_LATTICE').type = 'LATTICE'
layout.separator()
layout.operator_menu_enum("object.empty_add", "type", text="Empty",
text_ctxt=i18n_contexts.id_id,
icon='OUTLINER_OB_EMPTY')
layout.menu("VIEW3D_MT_image_add_classic", text="Image", icon='OUTLINER_OB_IMAGE')
layout.separator()
layout.menu("VIEW3D_MT_light_add_classic", icon='OUTLINER_OB_LIGHT')
layout.menu("VIEW3D_MT_lightprobe_add_classic", icon='OUTLINER_OB_LIGHTPROBE')
layout.separator()
if VIEW3D_MT_camera_add_classic.is_extended():
layout.menu("VIEW3D_MT_camera_add_classic", icon='OUTLINER_OB_CAMERA')
else:
VIEW3D_MT_camera_add_classic.draw(self, context)
layout.separator()
layout.operator("object.speaker_add", text="Speaker", icon='OUTLINER_OB_SPEAKER')
layout.separator()
layout.operator_menu_enum("object.effector_add", "type", text="Force Field", icon='OUTLINER_OB_FORCE_FIELD')
layout.separator()
has_collections = bool(bpy.data.collections)
col = layout.column()
col.enabled = has_collections
if not has_collections or len(bpy.data.collections) > 10:
col.operator_context = 'INVOKE_REGION_WIN'
col.operator(
"object.collection_instance_add",
text="Collection Instance..." if has_collections else "No Collections to Instance",
icon='OUTLINER_OB_GROUP_INSTANCE',
)
else:
col.operator_menu_enum(
"object.collection_instance_add",
"collection",
text="Collection Instance",
icon='OUTLINER_OB_GROUP_INSTANCE',
)
class VIEW3D_MT_image_add_classic(Menu):
bl_label = "Add Image"
#bl_options = {'SEARCH_ON_KEY_PRESS'}
def draw(self, _context):
layout = self.layout
layout.operator("object.load_reference_image", text="Reference", icon='IMAGE_REFERENCE')
layout.operator("object.load_background_image", text="Background", icon='IMAGE_BACKGROUND')
#############################################################################################################################
Registration
classes = (
VIEW3D_MT_mesh_add_classic,
VIEW3D_MT_curve_add_classic,
VIEW3D_MT_surface_add_classic,
VIEW3D_MT_metaball_add_classic,
VIEW3D_MT_armature_add_classic,
VIEW3D_MT_light_add_classic,
VIEW3D_MT_lightprobe_add_classic,
VIEW3D_MT_camera_add_classic,
VIEW3D_MT_volume_add_classic,
VIEW3D_MT_add_classic,
)
Draw modifiers menu
def drawmodifiers(self, context):
layout = self.layout
layout.operator_menu_enum("object.modifier_add", "type")
#############################################################################################################################
Registration
Store keymaps here to access after registration
addon_keymaps = []
def register():
for cls in classes:
register_class(cls)
# Append button to the properties Window > Modifier Tab
bpy.types.DATA_PT_modifiers.prepend(drawmodifiers)
bpy.types
#Keymaps###########################################################
wm = bpy.context.window_manager
kc = wm.keyconfigs.addon
if not kc:
print('No keyconfig path found. Adding new')
return
#3D View Global
km = kc.keymaps.new(name = "3D View", space_type = "VIEW_3D")
kmi = km.keymap_items.new("wm.call_menu", 'A', value = "PRESS", shift = True, ctrl = True)
kmi.properties.name = "VIEW3D_MT_add_classic"
def unregister():
for cls in reversed(classes):
unregister_class(cls)
bpy.types.DATA_PT_modifiers.remove(drawmodifiers)
if name == "main":
register()