The basic idea is very simple. Whenever a supported menu is open, one can just
start typing and this opens a search that contains all the (nested) menu entries.
The main downside is that this collides with accelerator keys. Those are the
underlined characters in each menu. For now, we just enable this new searching
behavior in a few selected menus: Node Add Menu, View3D Add Menu and
Modifier Add Menu.
This new functionality can be enabled for a menu by setting
`bl_options = {'SEARCH_ON_KEY_PRESS'}` to true in the menu type.
The status bar shows `Type to search...` when a menu is opened that supports search.
Pull Request: https://projects.blender.org/blender/blender/pulls/110855
253 lines
12 KiB
Python
253 lines
12 KiB
Python
# SPDX-FileCopyrightText: 2009-2023 Blender Authors
|
|
#
|
|
# SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
import bpy
|
|
from bpy.types import Panel, Menu, Operator
|
|
|
|
|
|
class ModifierButtonsPanel:
|
|
bl_space_type = 'PROPERTIES'
|
|
bl_region_type = 'WINDOW'
|
|
bl_context = "modifier"
|
|
bl_options = {'HIDE_HEADER'}
|
|
|
|
|
|
class DATA_PT_modifiers(ModifierButtonsPanel, Panel):
|
|
bl_label = "Modifiers"
|
|
|
|
@classmethod
|
|
def poll(cls, context):
|
|
ob = context.object
|
|
return ob and ob.type != 'GPENCIL'
|
|
|
|
def draw(self, _context):
|
|
layout = self.layout
|
|
layout.operator("wm.call_menu", text="Add Modifier", icon='ADD').name = "OBJECT_MT_modifier_add"
|
|
layout.template_modifiers()
|
|
|
|
|
|
class OBJECT_MT_modifier_add(Menu):
|
|
bl_label = "Add Modifier"
|
|
bl_options = {'SEARCH_ON_KEY_PRESS'}
|
|
|
|
def draw(self, context):
|
|
layout = self.layout
|
|
ob_type = context.object.type
|
|
geometry_nodes_supported = ob_type in {'MESH', 'CURVE', 'CURVES', 'FONT', 'SURFACE', 'VOLUME', 'POINTCLOUD'}
|
|
if geometry_nodes_supported:
|
|
layout.operator("object.modifier_add", text="Empty Modifier").type = 'NODES'
|
|
layout.separator()
|
|
if ob_type in {'MESH', 'CURVE', 'FONT', 'SURFACE', 'LATTICE'}:
|
|
layout.menu("OBJECT_MT_modifier_add_edit")
|
|
if ob_type in {'MESH', 'CURVE', 'FONT', 'SURFACE', 'VOLUME'}:
|
|
layout.menu("OBJECT_MT_modifier_add_generate")
|
|
if ob_type in {'MESH', 'CURVE', 'FONT', 'SURFACE', 'LATTICE', 'VOLUME'}:
|
|
layout.menu("OBJECT_MT_modifier_add_deform")
|
|
if ob_type in {'MESH', 'CURVE', 'FONT', 'SURFACE', 'LATTICE'}:
|
|
layout.menu("OBJECT_MT_modifier_add_physics")
|
|
|
|
if geometry_nodes_supported:
|
|
layout.menu_contents("OBJECT_MT_modifier_add_root_catalogs")
|
|
|
|
|
|
class OBJECT_MT_modifier_add_edit(Menu):
|
|
bl_label = "Edit"
|
|
|
|
def draw(self, context):
|
|
layout = self.layout
|
|
ob_type = context.object.type
|
|
if ob_type == 'MESH':
|
|
layout.operator(
|
|
"object.modifier_add",
|
|
text="Data Transfer",
|
|
icon='MOD_DATA_TRANSFER',
|
|
).type = 'DATA_TRANSFER'
|
|
if ob_type in {'MESH', 'CURVE', 'FONT', 'SURFACE', 'LATTICE'}:
|
|
layout.operator("object.modifier_add", text="Mesh Cache", icon='MOD_MESHDEFORM').type = 'MESH_CACHE'
|
|
if ob_type in {'MESH', 'CURVE', 'FONT', 'SURFACE'}:
|
|
layout.operator(
|
|
"object.modifier_add",
|
|
text="Mesh Sequence Cache",
|
|
icon='MOD_MESHDEFORM',
|
|
).type = 'MESH_SEQUENCE_CACHE'
|
|
if ob_type == 'MESH':
|
|
layout.operator("object.modifier_add", text="Normal Edit", icon='MOD_NORMALEDIT').type = 'NORMAL_EDIT'
|
|
layout.operator(
|
|
"object.modifier_add",
|
|
text="Weighted Normal",
|
|
icon='MOD_NORMALEDIT',
|
|
).type = 'WEIGHTED_NORMAL'
|
|
layout.operator("object.modifier_add", text="UV Project", icon='MOD_UVPROJECT').type = 'UV_PROJECT'
|
|
layout.operator("object.modifier_add", text="UV Warp", icon='MOD_UVPROJECT').type = 'UV_WARP'
|
|
layout.operator(
|
|
"object.modifier_add",
|
|
text="Vertex Weight Edit",
|
|
icon='MOD_VERTEX_WEIGHT',
|
|
).type = 'VERTEX_WEIGHT_EDIT'
|
|
layout.operator(
|
|
"object.modifier_add",
|
|
text="Vertex Weight Mix",
|
|
icon='MOD_VERTEX_WEIGHT',
|
|
).type = 'VERTEX_WEIGHT_MIX'
|
|
layout.operator(
|
|
"object.modifier_add",
|
|
text="Vertex Weight Proximity",
|
|
icon='MOD_VERTEX_WEIGHT',
|
|
).type = 'VERTEX_WEIGHT_PROXIMITY'
|
|
layout.template_modifier_asset_menu_items(catalog_path=self.bl_label)
|
|
|
|
|
|
class OBJECT_MT_modifier_add_generate(Menu):
|
|
bl_label = "Generate"
|
|
|
|
def draw(self, context):
|
|
layout = self.layout
|
|
ob_type = context.object.type
|
|
if ob_type in {'MESH', 'CURVE', 'FONT', 'SURFACE'}:
|
|
layout.operator("object.modifier_add", text="Array", icon='MOD_ARRAY').type = 'ARRAY'
|
|
layout.operator("object.modifier_add", text="Bevel", icon='MOD_BEVEL').type = 'BEVEL'
|
|
if ob_type == 'MESH':
|
|
layout.operator("object.modifier_add", text="Boolean", icon='MOD_BOOLEAN').type = 'BOOLEAN'
|
|
if ob_type in {'MESH', 'CURVE', 'FONT', 'SURFACE'}:
|
|
layout.operator("object.modifier_add", text="Build", icon='MOD_BUILD').type = 'BUILD'
|
|
layout.operator("object.modifier_add", text="Decimate", icon='MOD_DECIM').type = 'DECIMATE'
|
|
layout.operator("object.modifier_add", text="Edge Split", icon='MOD_EDGESPLIT').type = 'EDGE_SPLIT'
|
|
if ob_type == 'MESH':
|
|
layout.operator("object.modifier_add", text="Mask", icon='MOD_MASK').type = 'MASK'
|
|
if ob_type in {'MESH', 'CURVE', 'FONT', 'SURFACE'}:
|
|
layout.operator("object.modifier_add", text="Mirror", icon='MOD_MIRROR').type = 'MIRROR'
|
|
if ob_type == 'VOLUME':
|
|
layout.operator("object.modifier_add", text="Mesh to Volume", icon='VOLUME_DATA').type = 'MESH_TO_VOLUME'
|
|
if ob_type == 'MESH':
|
|
layout.operator("object.modifier_add", text="Multiresolution", icon='MOD_MULTIRES').type = 'MULTIRES'
|
|
if ob_type in {'MESH', 'CURVE', 'FONT', 'SURFACE'}:
|
|
layout.operator("object.modifier_add", text="Remesh", icon='MOD_REMESH').type = 'REMESH'
|
|
layout.operator("object.modifier_add", text="Screw", icon='MOD_SCREW').type = 'SCREW'
|
|
if ob_type == 'MESH':
|
|
layout.operator("object.modifier_add", text="Skin", icon='MOD_SKIN').type = 'SKIN'
|
|
if ob_type in {'MESH', 'CURVE', 'FONT', 'SURFACE'}:
|
|
layout.operator("object.modifier_add", text="Solidify", icon='MOD_SOLIDIFY').type = 'SOLIDIFY'
|
|
layout.operator("object.modifier_add", text="Subdivision Surface", icon='MOD_SUBSURF').type = 'SUBSURF'
|
|
layout.operator("object.modifier_add", text="Triangulate", icon='MOD_TRIANGULATE').type = 'TRIANGULATE'
|
|
if ob_type == 'MESH':
|
|
layout.operator("object.modifier_add", text="Volume to Mesh", icon='VOLUME_DATA').type = 'VOLUME_TO_MESH'
|
|
if ob_type in {'MESH', 'CURVE', 'FONT', 'SURFACE'}:
|
|
layout.operator("object.modifier_add", text="Weld", icon='AUTOMERGE_OFF').type = 'WELD'
|
|
if ob_type == 'MESH':
|
|
layout.operator("object.modifier_add", text="Wireframe", icon='MOD_WIREFRAME').type = 'WIREFRAME'
|
|
layout.template_modifier_asset_menu_items(catalog_path=self.bl_label)
|
|
|
|
|
|
class OBJECT_MT_modifier_add_deform(Menu):
|
|
bl_label = "Deform"
|
|
|
|
def draw(self, context):
|
|
layout = self.layout
|
|
ob_type = context.object.type
|
|
if ob_type in {'MESH', 'CURVE', 'FONT', 'SURFACE', 'LATTICE'}:
|
|
layout.operator("object.modifier_add", text="Armature", icon='MOD_ARMATURE').type = 'ARMATURE'
|
|
layout.operator("object.modifier_add", text="Cast", icon='MOD_CAST').type = 'CAST'
|
|
layout.operator("object.modifier_add", text="Curve", icon='MOD_CURVE').type = 'CURVE'
|
|
if ob_type == 'MESH':
|
|
layout.operator("object.modifier_add", text="Displace", icon='MOD_DISPLACE').type = 'DISPLACE'
|
|
if ob_type in {'MESH', 'CURVE', 'FONT', 'SURFACE', 'LATTICE'}:
|
|
layout.operator("object.modifier_add", text="Hook", icon='HOOK').type = 'HOOK'
|
|
if ob_type == 'MESH':
|
|
layout.operator("object.modifier_add", text="Laplacian Deform",
|
|
icon='MOD_MESHDEFORM').type = 'LAPLACIANDEFORM'
|
|
if ob_type in {'MESH', 'CURVE', 'FONT', 'SURFACE', 'LATTICE'}:
|
|
layout.operator("object.modifier_add", text="Lattice", icon='MOD_LATTICE').type = 'LATTICE'
|
|
layout.operator("object.modifier_add", text="Mesh Deform", icon='MOD_MESHDEFORM').type = 'MESH_DEFORM'
|
|
layout.operator("object.modifier_add", text="Shrinkwrap", icon='MOD_SHRINKWRAP').type = 'SHRINKWRAP'
|
|
layout.operator("object.modifier_add", text="Simple Deform", icon='MOD_SIMPLEDEFORM').type = 'SIMPLE_DEFORM'
|
|
if ob_type in {'MESH', 'CURVE', 'FONT', 'SURFACE'}:
|
|
layout.operator("object.modifier_add", text="Smooth", icon='MOD_SMOOTH').type = 'SMOOTH'
|
|
if ob_type == 'MESH':
|
|
layout.operator(
|
|
"object.modifier_add",
|
|
text="Smooth Corrective",
|
|
icon='MOD_SMOOTH',
|
|
).type = 'CORRECTIVE_SMOOTH'
|
|
layout.operator("object.modifier_add", text="Smooth Laplacian", icon='MOD_SMOOTH').type = 'LAPLACIANSMOOTH'
|
|
layout.operator("object.modifier_add", text="Surface Deform", icon='MOD_MESHDEFORM').type = 'SURFACE_DEFORM'
|
|
if ob_type in {'MESH', 'CURVE', 'FONT', 'SURFACE', 'LATTICE'}:
|
|
layout.operator("object.modifier_add", text="Warp", icon='MOD_WARP').type = 'WARP'
|
|
layout.operator("object.modifier_add", text="Wave", icon='MOD_WAVE').type = 'WAVE'
|
|
if ob_type == 'VOLUME':
|
|
layout.operator("object.modifier_add", text="Volume Displace", icon='VOLUME_DATA').type = 'VOLUME_DISPLACE'
|
|
layout.template_modifier_asset_menu_items(catalog_path=self.bl_label)
|
|
|
|
|
|
class OBJECT_MT_modifier_add_physics(Menu):
|
|
bl_label = "Physics"
|
|
|
|
def draw(self, context):
|
|
layout = self.layout
|
|
ob_type = context.object.type
|
|
if ob_type == 'MESH':
|
|
layout.operator("object.modifier_add", text="Cloth", icon='MOD_CLOTH').type = 'CLOTH'
|
|
layout.operator("object.modifier_add", text="Collision", icon='MOD_PHYSICS').type = 'COLLISION'
|
|
layout.operator("object.modifier_add", text="Dynamic Paint", icon='MOD_DYNAMICPAINT').type = 'DYNAMIC_PAINT'
|
|
layout.operator("object.modifier_add", text="Explode", icon='MOD_EXPLODE').type = 'EXPLODE'
|
|
layout.operator("object.modifier_add", text="Fluid", icon='MOD_FLUIDSIM').type = 'FLUID'
|
|
layout.operator("object.modifier_add", text="Ocean", icon='MOD_OCEAN').type = 'OCEAN'
|
|
layout.operator(
|
|
"object.modifier_add",
|
|
text="Particle Instance",
|
|
icon='MOD_PARTICLE_INSTANCE',
|
|
).type = 'PARTICLE_INSTANCE'
|
|
layout.operator(
|
|
"object.modifier_add",
|
|
text="Particle System",
|
|
icon='MOD_PARTICLES',
|
|
).type = 'PARTICLE_SYSTEM'
|
|
if ob_type in {'MESH', 'CURVE', 'FONT', 'SURFACE', 'LATTICE'}:
|
|
layout.operator("object.modifier_add", text="Soft Body", icon='MOD_SOFT').type = 'SOFT_BODY'
|
|
layout.template_modifier_asset_menu_items(catalog_path=self.bl_label)
|
|
|
|
|
|
class DATA_PT_gpencil_modifiers(ModifierButtonsPanel, Panel):
|
|
bl_label = "Modifiers"
|
|
|
|
@classmethod
|
|
def poll(cls, context):
|
|
ob = context.object
|
|
return ob and ob.type == 'GPENCIL'
|
|
|
|
def draw(self, _context):
|
|
layout = self.layout
|
|
layout.operator_menu_enum("object.gpencil_modifier_add", "type")
|
|
layout.template_grease_pencil_modifiers()
|
|
|
|
|
|
class AddModifierMenu(Operator):
|
|
bl_idname = "object.add_modifier_menu"
|
|
bl_label = "Add Modifier"
|
|
|
|
@classmethod
|
|
def poll(cls, context):
|
|
space = context.space_data
|
|
return space and space.type == 'PROPERTIES' and space.context == "MODIFIER"
|
|
|
|
def invoke(self, context, event):
|
|
return bpy.ops.wm.call_menu(name="OBJECT_MT_modifier_add")
|
|
|
|
|
|
classes = (
|
|
DATA_PT_modifiers,
|
|
OBJECT_MT_modifier_add,
|
|
OBJECT_MT_modifier_add_edit,
|
|
OBJECT_MT_modifier_add_generate,
|
|
OBJECT_MT_modifier_add_deform,
|
|
OBJECT_MT_modifier_add_physics,
|
|
DATA_PT_gpencil_modifiers,
|
|
AddModifierMenu,
|
|
)
|
|
|
|
if __name__ == "__main__": # only for live edit.
|
|
from bpy.utils import register_class
|
|
|
|
for cls in classes:
|
|
register_class(cls)
|