The `Lineart` and `Opacity` modifier appear at the bottom of their respective menus instead of following alphabetical order. There doesn't seem to be any conceivable reason to do this, and it is inconsistent with how the modifiers were laid out in older Blender versions. Fixes the order of the modifiers. Pull Request: https://projects.blender.org/blender/blender/pulls/130080
319 lines
13 KiB
Python
319 lines
13 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 ModifierAddMenu:
|
|
MODIFIER_TYPES_TO_LABELS = {
|
|
enum_it.identifier: enum_it.name
|
|
for enum_it in bpy.types.Modifier.bl_rna.properties["type"].enum_items_static
|
|
}
|
|
MODIFIER_TYPES_TO_ICONS = {
|
|
enum_it.identifier: enum_it.icon
|
|
for enum_it in bpy.types.Modifier.bl_rna.properties["type"].enum_items_static
|
|
}
|
|
MODIFIER_TYPES_I18N_CONTEXT = bpy.types.Modifier.bl_rna.properties["type"].translation_context
|
|
|
|
@classmethod
|
|
def operator_modifier_add(cls, layout, mod_type):
|
|
layout.operator(
|
|
"object.modifier_add",
|
|
text=cls.MODIFIER_TYPES_TO_LABELS[mod_type],
|
|
# Although these are operators, the label actually comes from an (enum) property,
|
|
# so the property's translation context must be used here.
|
|
text_ctxt=cls.MODIFIER_TYPES_I18N_CONTEXT,
|
|
icon=cls.MODIFIER_TYPES_TO_ICONS[mod_type],
|
|
).type = mod_type
|
|
|
|
|
|
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(ModifierAddMenu, Menu):
|
|
bl_label = "Add Modifier"
|
|
bl_options = {'SEARCH_ON_KEY_PRESS'}
|
|
|
|
def draw(self, context):
|
|
layout = self.layout
|
|
ob = context.object
|
|
if not ob:
|
|
return
|
|
ob_type = ob.type
|
|
geometry_nodes_supported = ob_type in {
|
|
'MESH', 'CURVE', 'CURVES',
|
|
'FONT', 'VOLUME', 'POINTCLOUD', 'GREASEPENCIL',
|
|
}
|
|
|
|
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 = "OBJECT_MT_modifier_add"
|
|
layout.separator()
|
|
|
|
layout.operator_context = 'INVOKE_REGION_WIN'
|
|
|
|
if geometry_nodes_supported:
|
|
self.operator_modifier_add(layout, 'NODES')
|
|
layout.separator()
|
|
if ob_type in {'MESH', 'CURVE', 'CURVES', 'FONT', 'SURFACE', 'LATTICE', 'GREASEPENCIL', 'POINTCLOUD'}:
|
|
layout.menu("OBJECT_MT_modifier_add_edit")
|
|
if ob_type in {'MESH', 'CURVE', 'FONT', 'SURFACE', 'VOLUME', 'GREASEPENCIL'}:
|
|
layout.menu("OBJECT_MT_modifier_add_generate")
|
|
if ob_type in {'MESH', 'CURVE', 'FONT', 'SURFACE', 'LATTICE', 'VOLUME', 'GREASEPENCIL'}:
|
|
layout.menu("OBJECT_MT_modifier_add_deform")
|
|
if ob_type in {'MESH'}:
|
|
layout.menu("OBJECT_MT_modifier_add_normals")
|
|
if ob_type in {'MESH', 'CURVE', 'FONT', 'SURFACE', 'LATTICE'}:
|
|
layout.menu("OBJECT_MT_modifier_add_physics")
|
|
if ob_type in {'GREASEPENCIL'}:
|
|
layout.menu("OBJECT_MT_modifier_add_color")
|
|
|
|
if geometry_nodes_supported:
|
|
layout.menu_contents("OBJECT_MT_modifier_add_root_catalogs")
|
|
|
|
|
|
class OBJECT_MT_modifier_add_edit(ModifierAddMenu, Menu):
|
|
bl_label = "Edit"
|
|
bl_options = {'SEARCH_ON_KEY_PRESS'}
|
|
|
|
def draw(self, context):
|
|
layout = self.layout
|
|
ob_type = context.object.type
|
|
if ob_type == 'MESH':
|
|
self.operator_modifier_add(layout, 'DATA_TRANSFER')
|
|
if ob_type in {'MESH', 'CURVE', 'FONT', 'SURFACE', 'LATTICE'}:
|
|
self.operator_modifier_add(layout, 'MESH_CACHE')
|
|
if ob_type in {'MESH', 'CURVE', 'CURVES', 'FONT', 'SURFACE', 'POINTCLOUD'}:
|
|
self.operator_modifier_add(layout, 'MESH_SEQUENCE_CACHE')
|
|
if ob_type == 'MESH':
|
|
self.operator_modifier_add(layout, 'UV_PROJECT')
|
|
self.operator_modifier_add(layout, 'UV_WARP')
|
|
self.operator_modifier_add(layout, 'VERTEX_WEIGHT_EDIT')
|
|
self.operator_modifier_add(layout, 'VERTEX_WEIGHT_MIX')
|
|
self.operator_modifier_add(layout, 'VERTEX_WEIGHT_PROXIMITY')
|
|
if ob_type == 'GREASEPENCIL':
|
|
self.operator_modifier_add(layout, 'GREASE_PENCIL_TEXTURE')
|
|
self.operator_modifier_add(layout, 'GREASE_PENCIL_TIME')
|
|
self.operator_modifier_add(layout, 'GREASE_PENCIL_VERTEX_WEIGHT_PROXIMITY')
|
|
self.operator_modifier_add(layout, 'GREASE_PENCIL_VERTEX_WEIGHT_ANGLE')
|
|
layout.template_modifier_asset_menu_items(catalog_path=self.bl_label)
|
|
|
|
|
|
class OBJECT_MT_modifier_add_generate(ModifierAddMenu, Menu):
|
|
bl_label = "Generate"
|
|
bl_options = {'SEARCH_ON_KEY_PRESS'}
|
|
|
|
def draw(self, context):
|
|
layout = self.layout
|
|
ob_type = context.object.type
|
|
if ob_type in {'MESH', 'CURVE', 'FONT', 'SURFACE'}:
|
|
self.operator_modifier_add(layout, 'ARRAY')
|
|
self.operator_modifier_add(layout, 'BEVEL')
|
|
if ob_type == 'MESH':
|
|
self.operator_modifier_add(layout, 'BOOLEAN')
|
|
if ob_type in {'MESH', 'CURVE', 'FONT', 'SURFACE'}:
|
|
self.operator_modifier_add(layout, 'BUILD')
|
|
self.operator_modifier_add(layout, 'DECIMATE')
|
|
self.operator_modifier_add(layout, 'EDGE_SPLIT')
|
|
if ob_type == 'MESH':
|
|
self.operator_modifier_add(layout, 'MASK')
|
|
if ob_type in {'MESH', 'CURVE', 'FONT', 'SURFACE'}:
|
|
self.operator_modifier_add(layout, 'MIRROR')
|
|
if ob_type == 'VOLUME':
|
|
self.operator_modifier_add(layout, 'MESH_TO_VOLUME')
|
|
if ob_type == 'MESH':
|
|
self.operator_modifier_add(layout, 'MULTIRES')
|
|
if ob_type in {'MESH', 'CURVE', 'FONT', 'SURFACE'}:
|
|
self.operator_modifier_add(layout, 'REMESH')
|
|
self.operator_modifier_add(layout, 'SCREW')
|
|
if ob_type == 'MESH':
|
|
self.operator_modifier_add(layout, 'SKIN')
|
|
if ob_type in {'MESH', 'CURVE', 'FONT', 'SURFACE'}:
|
|
self.operator_modifier_add(layout, 'SOLIDIFY')
|
|
self.operator_modifier_add(layout, 'SUBSURF')
|
|
self.operator_modifier_add(layout, 'TRIANGULATE')
|
|
if ob_type == 'MESH':
|
|
self.operator_modifier_add(layout, 'VOLUME_TO_MESH')
|
|
if ob_type in {'MESH', 'CURVE', 'FONT', 'SURFACE'}:
|
|
self.operator_modifier_add(layout, 'WELD')
|
|
if ob_type == 'MESH':
|
|
self.operator_modifier_add(layout, 'WIREFRAME')
|
|
if ob_type == 'GREASEPENCIL':
|
|
self.operator_modifier_add(layout, 'GREASE_PENCIL_ARRAY')
|
|
self.operator_modifier_add(layout, 'GREASE_PENCIL_BUILD')
|
|
self.operator_modifier_add(layout, 'GREASE_PENCIL_DASH')
|
|
self.operator_modifier_add(layout, 'GREASE_PENCIL_ENVELOPE')
|
|
self.operator_modifier_add(layout, 'GREASE_PENCIL_LENGTH')
|
|
self.operator_modifier_add(layout, 'LINEART')
|
|
self.operator_modifier_add(layout, 'GREASE_PENCIL_MIRROR')
|
|
self.operator_modifier_add(layout, 'GREASE_PENCIL_MULTIPLY')
|
|
self.operator_modifier_add(layout, 'GREASE_PENCIL_OUTLINE')
|
|
self.operator_modifier_add(layout, 'GREASE_PENCIL_SIMPLIFY')
|
|
self.operator_modifier_add(layout, 'GREASE_PENCIL_SUBDIV')
|
|
layout.template_modifier_asset_menu_items(catalog_path=self.bl_label)
|
|
|
|
|
|
class OBJECT_MT_modifier_add_deform(ModifierAddMenu, Menu):
|
|
bl_label = "Deform"
|
|
bl_options = {'SEARCH_ON_KEY_PRESS'}
|
|
|
|
def draw(self, context):
|
|
layout = self.layout
|
|
ob_type = context.object.type
|
|
if ob_type in {'MESH', 'CURVE', 'FONT', 'SURFACE', 'LATTICE'}:
|
|
self.operator_modifier_add(layout, 'ARMATURE')
|
|
self.operator_modifier_add(layout, 'CAST')
|
|
self.operator_modifier_add(layout, 'CURVE')
|
|
if ob_type == 'MESH':
|
|
self.operator_modifier_add(layout, 'DISPLACE')
|
|
if ob_type in {'MESH', 'CURVE', 'FONT', 'SURFACE', 'LATTICE'}:
|
|
self.operator_modifier_add(layout, 'HOOK')
|
|
if ob_type == 'MESH':
|
|
self.operator_modifier_add(layout, 'LAPLACIANDEFORM')
|
|
if ob_type in {'MESH', 'CURVE', 'FONT', 'SURFACE', 'LATTICE'}:
|
|
self.operator_modifier_add(layout, 'LATTICE')
|
|
self.operator_modifier_add(layout, 'MESH_DEFORM')
|
|
self.operator_modifier_add(layout, 'SHRINKWRAP')
|
|
self.operator_modifier_add(layout, 'SIMPLE_DEFORM')
|
|
if ob_type in {'MESH', 'CURVE', 'FONT', 'SURFACE'}:
|
|
self.operator_modifier_add(layout, 'SMOOTH')
|
|
if ob_type == 'MESH':
|
|
self.operator_modifier_add(layout, 'CORRECTIVE_SMOOTH')
|
|
self.operator_modifier_add(layout, 'LAPLACIANSMOOTH')
|
|
self.operator_modifier_add(layout, 'SURFACE_DEFORM')
|
|
if ob_type in {'MESH', 'CURVE', 'FONT', 'SURFACE', 'LATTICE'}:
|
|
self.operator_modifier_add(layout, 'WARP')
|
|
self.operator_modifier_add(layout, 'WAVE')
|
|
if ob_type == 'VOLUME':
|
|
self.operator_modifier_add(layout, 'VOLUME_DISPLACE')
|
|
if ob_type == 'GREASEPENCIL':
|
|
self.operator_modifier_add(layout, 'GREASE_PENCIL_ARMATURE')
|
|
self.operator_modifier_add(layout, 'GREASE_PENCIL_HOOK')
|
|
self.operator_modifier_add(layout, 'GREASE_PENCIL_LATTICE')
|
|
self.operator_modifier_add(layout, 'GREASE_PENCIL_NOISE')
|
|
self.operator_modifier_add(layout, 'GREASE_PENCIL_OFFSET')
|
|
self.operator_modifier_add(layout, 'GREASE_PENCIL_SHRINKWRAP')
|
|
self.operator_modifier_add(layout, 'GREASE_PENCIL_SMOOTH')
|
|
self.operator_modifier_add(layout, 'GREASE_PENCIL_THICKNESS')
|
|
layout.template_modifier_asset_menu_items(catalog_path=self.bl_label)
|
|
|
|
|
|
class OBJECT_MT_modifier_add_normals(ModifierAddMenu, Menu):
|
|
bl_label = "Normals"
|
|
bl_options = {'SEARCH_ON_KEY_PRESS'}
|
|
|
|
def draw(self, context):
|
|
layout = self.layout
|
|
ob_type = context.object.type
|
|
if ob_type == 'MESH':
|
|
self.operator_modifier_add(layout, 'NORMAL_EDIT')
|
|
self.operator_modifier_add(layout, 'WEIGHTED_NORMAL')
|
|
layout.template_modifier_asset_menu_items(catalog_path=self.bl_label)
|
|
|
|
|
|
class OBJECT_MT_modifier_add_physics(ModifierAddMenu, Menu):
|
|
bl_label = "Physics"
|
|
bl_options = {'SEARCH_ON_KEY_PRESS'}
|
|
|
|
def draw(self, context):
|
|
layout = self.layout
|
|
ob_type = context.object.type
|
|
if ob_type == 'MESH':
|
|
self.operator_modifier_add(layout, 'CLOTH')
|
|
self.operator_modifier_add(layout, 'COLLISION')
|
|
self.operator_modifier_add(layout, 'DYNAMIC_PAINT')
|
|
self.operator_modifier_add(layout, 'EXPLODE')
|
|
self.operator_modifier_add(layout, 'FLUID')
|
|
self.operator_modifier_add(layout, 'OCEAN')
|
|
self.operator_modifier_add(layout, 'PARTICLE_INSTANCE')
|
|
self.operator_modifier_add(layout, 'PARTICLE_SYSTEM')
|
|
if ob_type in {'MESH', 'CURVE', 'FONT', 'SURFACE', 'LATTICE'}:
|
|
self.operator_modifier_add(layout, 'SOFT_BODY')
|
|
layout.template_modifier_asset_menu_items(catalog_path=self.bl_label)
|
|
|
|
|
|
class OBJECT_MT_modifier_add_color(ModifierAddMenu, Menu):
|
|
bl_label = "Color"
|
|
bl_options = {'SEARCH_ON_KEY_PRESS'}
|
|
|
|
def draw(self, context):
|
|
layout = self.layout
|
|
ob_type = context.object.type
|
|
if ob_type == 'GREASEPENCIL':
|
|
self.operator_modifier_add(layout, 'GREASE_PENCIL_COLOR')
|
|
self.operator_modifier_add(layout, 'GREASE_PENCIL_OPACITY')
|
|
self.operator_modifier_add(layout, 'GREASE_PENCIL_TINT')
|
|
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):
|
|
# NOTE: This operator only exists to add a poll to the add modifier shortcut in the property editor.
|
|
object = context.object
|
|
space = context.space_data
|
|
if object and object.type == 'GPENCIL':
|
|
return False
|
|
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_normals,
|
|
OBJECT_MT_modifier_add_physics,
|
|
OBJECT_MT_modifier_add_color,
|
|
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)
|