From 59aa61b8be4b49d7781dc907eb74331b7527e2ea Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Mon, 29 Sep 2025 16:37:35 +0200 Subject: [PATCH] UI: Interleave essentials modifiers in "Generate" menu Hardocde the position of the essentials assets in the menu, for consistent alphabetical order and a clearer indication of the different between the nodes and builtin "Array" modifiers (the old one is now called "Array (Legacy)"). Pull Request: https://projects.blender.org/blender/blender/pulls/146887 --- .../startup/bl_ui/properties_data_modifier.py | 29 +++++++++++++++---- source/blender/editors/include/ED_object.hh | 4 ++- .../editors/object/add_modifier_assets.cc | 23 +++++++++++++-- source/blender/makesrna/intern/rna_ui_api.cc | 7 +++-- 4 files changed, 52 insertions(+), 11 deletions(-) diff --git a/scripts/startup/bl_ui/properties_data_modifier.py b/scripts/startup/bl_ui/properties_data_modifier.py index 7a0d47cd0af..f99cc9633d0 100644 --- a/scripts/startup/bl_ui/properties_data_modifier.py +++ b/scripts/startup/bl_ui/properties_data_modifier.py @@ -4,6 +4,9 @@ import bpy from bpy.types import Panel, Menu, Operator +from bpy.app.translations import ( + pgettext_n as n_, +) class ModifierButtonsPanel: @@ -25,16 +28,29 @@ class ModifierAddMenu: MODIFIER_TYPES_I18N_CONTEXT = bpy.types.Modifier.bl_rna.properties["type"].translation_context @classmethod - def operator_modifier_add(cls, layout, mod_type): + def operator_modifier_add(cls, layout, mod_type, text=None, no_icon=False): + label = text if text else cls.MODIFIER_TYPES_TO_LABELS[mod_type] layout.operator( "object.modifier_add", - text=cls.MODIFIER_TYPES_TO_LABELS[mod_type], + text=label, # 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], + icon='NONE' if no_icon else cls.MODIFIER_TYPES_TO_ICONS[mod_type], ).type = mod_type + @classmethod + def operator_modifier_add_asset(cls, layout, name, icon='NONE'): + props = layout.operator( + "object.modifier_add_node_group", + text=name, + text_ctxt=cls.MODIFIER_TYPES_I18N_CONTEXT, + icon=icon, + ) + props.asset_library_type = 'ESSENTIALS' + props.asset_library_identifier = "" + props.relative_asset_identifier = "geometry_nodes/geometry_nodes_essentials.blend/NodeTree/" + name + class DATA_PT_modifiers(ModifierButtonsPanel, Panel): bl_label = "Modifiers" @@ -132,12 +148,14 @@ class OBJECT_MT_modifier_add_generate(ModifierAddMenu, Menu): 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_asset(layout, 'Array', icon='MOD_ARRAY') + self.operator_modifier_add(layout, 'ARRAY', text=n_("Array (Legacy)"), no_icon=True) 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_asset(layout, n_('Curve to Tube')) self.operator_modifier_add(layout, 'DECIMATE') self.operator_modifier_add(layout, 'EDGE_SPLIT') if ob_type == 'MESH': @@ -150,6 +168,7 @@ class OBJECT_MT_modifier_add_generate(ModifierAddMenu, Menu): self.operator_modifier_add(layout, 'MULTIRES') if ob_type in {'MESH', 'CURVE', 'FONT', 'SURFACE'}: self.operator_modifier_add(layout, 'REMESH') + self.operator_modifier_add_asset(layout, n_('Scatter on Surface')) self.operator_modifier_add(layout, 'SCREW') if ob_type == 'MESH': self.operator_modifier_add(layout, 'SKIN') @@ -175,7 +194,7 @@ class OBJECT_MT_modifier_add_generate(ModifierAddMenu, Menu): 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) + layout.template_modifier_asset_menu_items(catalog_path=self.bl_label, skip_essentials=True) class OBJECT_MT_modifier_add_deform(ModifierAddMenu, Menu): diff --git a/source/blender/editors/include/ED_object.hh b/source/blender/editors/include/ED_object.hh index b1dbbc52e2e..77566b1cfa0 100644 --- a/source/blender/editors/include/ED_object.hh +++ b/source/blender/editors/include/ED_object.hh @@ -609,6 +609,8 @@ void data_xform_by_mat4(XFormObjectData &xod, const float4x4 &transform); void data_xform_restore(XFormObjectData &xod); void data_xform_tag_update(XFormObjectData &xod); -void ui_template_modifier_asset_menu_items(uiLayout &layout, StringRef catalog_path); +void ui_template_modifier_asset_menu_items(uiLayout &layout, + StringRef catalog_path, + bool skip_essentials); } // namespace blender::ed::object diff --git a/source/blender/editors/object/add_modifier_assets.cc b/source/blender/editors/object/add_modifier_assets.cc index 93c89c72d24..cdd58d4b01f 100644 --- a/source/blender/editors/object/add_modifier_assets.cc +++ b/source/blender/editors/object/add_modifier_assets.cc @@ -85,6 +85,7 @@ static void catalog_assets_draw(const bContext *C, Menu *menu) if (!menu_path) { return; } + const int skip_essentials = CTX_data_int_get(C, "skip_essentials").value_or(0); const Span assets = tree.assets_per_path.lookup( menu_path->data()); const asset_system::AssetCatalogTreeItem *catalog_item = tree.catalogs.find_item( @@ -96,16 +97,30 @@ static void catalog_assets_draw(const bContext *C, Menu *menu) } uiLayout *layout = menu->layout; - layout->separator(); + + bool first = true; + const auto ensure_separator = [&]() { + if (first) { + layout->separator(); + first = false; + } + }; wmOperatorType *ot = WM_operatortype_find("OBJECT_OT_modifier_add_node_group", true); for (const asset_system::AssetRepresentation *asset : assets) { + if (skip_essentials) { + if (asset->owner_asset_library().library_reference()->type == ASSET_LIBRARY_ESSENTIALS) { + continue; + } + } + ensure_separator(); PointerRNA props_ptr = layout->op( ot, IFACE_(asset->get_name()), ICON_NONE, wm::OpCallContext::InvokeDefault, UI_ITEM_NONE); asset::operator_asset_reference_props_set(*asset, props_ptr); } catalog_item->foreach_child([&](const asset_system::AssetCatalogTreeItem &item) { + ensure_separator(); asset::draw_menu_for_catalog(item, "OBJECT_MT_add_modifier_catalog_assets", *layout); }); } @@ -388,7 +403,9 @@ void object_modifier_add_asset_register() WM_operatortype_append(OBJECT_OT_modifier_add_node_group); } -void ui_template_modifier_asset_menu_items(uiLayout &layout, const StringRef catalog_path) +void ui_template_modifier_asset_menu_items(uiLayout &layout, + const StringRef catalog_path, + const bool skip_essentials) { asset::AssetItemTree &tree = *get_static_item_tree(); const asset_system::AssetCatalogTreeItem *item = tree.catalogs.find_root_item(catalog_path); @@ -400,9 +417,9 @@ void ui_template_modifier_asset_menu_items(uiLayout &layout, const StringRef cat if (!all_library) { return; } - layout.separator(); uiLayout *col = &layout.column(false); col->context_string_set("asset_catalog_path", item->catalog_path().str()); + col->context_int_set("skip_essentials", skip_essentials); col->menu_contents("OBJECT_MT_add_modifier_catalog_assets"); } diff --git a/source/blender/makesrna/intern/rna_ui_api.cc b/source/blender/makesrna/intern/rna_ui_api.cc index f4922a797b0..cb59bd16436 100644 --- a/source/blender/makesrna/intern/rna_ui_api.cc +++ b/source/blender/makesrna/intern/rna_ui_api.cc @@ -915,10 +915,12 @@ static void rna_uiLayout_template_node_operator_asset_menu_items(uiLayout *layou } static void rna_uiLayout_template_modifier_asset_menu_items(uiLayout *layout, - const char *catalog_path) + const char *catalog_path, + const bool skip_essentials) { using namespace blender; - ed::object::ui_template_modifier_asset_menu_items(*layout, StringRef(catalog_path)); + ed::object::ui_template_modifier_asset_menu_items( + *layout, StringRef(catalog_path), skip_essentials); } static void rna_uiLayout_template_node_operator_root_items(uiLayout *layout, bContext *C) @@ -2150,6 +2152,7 @@ void RNA_api_ui_layout(StructRNA *srna) "template_modifier_asset_menu_items", "rna_uiLayout_template_modifier_asset_menu_items"); parm = RNA_def_string(func, "catalog_path", nullptr, 0, "", ""); + parm = RNA_def_boolean(func, "skip_essentials", false, "", ""); func = RNA_def_function(srna, "template_node_operator_asset_menu_items",