Files
test/scripts/startup/bl_ui/properties_data_modifier.py
Dalai Felinto 420dfebbb8 UI: Add Modifier: Move Geometry Nodes last
With Blender 5.0 a few modifier assets are bundled. This makes the
Geometry Nodes modifier even more of a special modifier which isn't
intended for many people to use.

As such this PR moves it to the end to be a bit less prominent.

| 4.5 | PR | PR |
| - | - | - |
|<img width="217" alt="Screenshot 2025-09-22 at 16.10.17.png" src="attachments/c12fedc4-549e-4b7b-bc28-c990e17a679e">|<img width="182" alt="Screenshot 2025-09-22 at 16.11.18.png" src="attachments/ce80702e-95dd-441a-8d36-c41f64d03a64">|<img width="214" alt="Screenshot 2025-09-22 at 16.11.45.png" src="attachments/5b07d5e9-b133-4fc5-a5a4-a1989929e58e">|

The PR column shows the changes proposed here in two scenarios: with and another without Unassigned assets.

Ref: !146590
2025-09-22 18:59:36 +02:00

305 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
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 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")
if geometry_nodes_supported:
layout.separator()
self.operator_modifier_add(layout, 'NODES')
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', '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 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.
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_normals,
OBJECT_MT_modifier_add_physics,
OBJECT_MT_modifier_add_color,
AddModifierMenu,
)
if __name__ == "__main__": # only for live edit.
from bpy.utils import register_class
for cls in classes:
register_class(cls)