From dd43ea4e9e4cb3ca82931e6cd3938c1994367355 Mon Sep 17 00:00:00 2001 From: Eitan Traurig Date: Wed, 7 May 2025 08:06:52 +0200 Subject: [PATCH] UI: Add "Remove All Materials" operator Added a new operator `OBJECT_OT_material_slot_remove_all` that removes all materials from the material slots of selected objects This was inspired by a request proposal on RCS. Pull Request: https://projects.blender.org/blender/blender/pulls/138402 --- scripts/startup/bl_ui/properties_material.py | 1 + .../bl_ui/properties_material_gpencil.py | 1 + scripts/startup/bl_ui/space_view3d.py | 1 + .../blender/editors/render/render_intern.hh | 1 + source/blender/editors/render/render_ops.cc | 1 + .../blender/editors/render/render_shading.cc | 65 +++++++++++++++++++ 6 files changed, 70 insertions(+) diff --git a/scripts/startup/bl_ui/properties_material.py b/scripts/startup/bl_ui/properties_material.py index aafb02c2645..64f1be77bc8 100644 --- a/scripts/startup/bl_ui/properties_material.py +++ b/scripts/startup/bl_ui/properties_material.py @@ -21,6 +21,7 @@ class MATERIAL_MT_context_menu(Menu): layout.operator("object.material_slot_copy") layout.operator("material.paste", icon='PASTEDOWN') layout.operator("object.material_slot_remove_unused") + layout.operator("object.material_slot_remove_all") class MATERIAL_UL_matslots(UIList): diff --git a/scripts/startup/bl_ui/properties_material_gpencil.py b/scripts/startup/bl_ui/properties_material_gpencil.py index 4e7b59416a2..68c34f037dc 100644 --- a/scripts/startup/bl_ui/properties_material_gpencil.py +++ b/scripts/startup/bl_ui/properties_material_gpencil.py @@ -40,6 +40,7 @@ class GPENCIL_MT_material_context_menu(Menu): ).only_active = False layout.operator("object.material_slot_remove_unused") + layout.operator("object.material_slot_remove_all") class GPENCIL_UL_matslots(UIList): diff --git a/scripts/startup/bl_ui/space_view3d.py b/scripts/startup/bl_ui/space_view3d.py index 0e104f7604a..bc56ffef258 100644 --- a/scripts/startup/bl_ui/space_view3d.py +++ b/scripts/startup/bl_ui/space_view3d.py @@ -3351,6 +3351,7 @@ class VIEW3D_MT_object_cleanup(Menu): layout.separator() layout.operator("object.material_slot_remove_unused", text="Remove Unused Material Slots") + layout.operator("object.material_slot_remove_all", text="Remove All Materials") class VIEW3D_MT_object_asset(Menu): diff --git a/source/blender/editors/render/render_intern.hh b/source/blender/editors/render/render_intern.hh index 8903cadb12a..5effe1b1672 100644 --- a/source/blender/editors/render/render_intern.hh +++ b/source/blender/editors/render/render_intern.hh @@ -24,6 +24,7 @@ void OBJECT_OT_material_slot_deselect(wmOperatorType *ot); void OBJECT_OT_material_slot_copy(wmOperatorType *ot); void OBJECT_OT_material_slot_move(wmOperatorType *ot); void OBJECT_OT_material_slot_remove_unused(wmOperatorType *ot); +void OBJECT_OT_material_slot_remove_all(wmOperatorType *ot); void MATERIAL_OT_new(wmOperatorType *ot); void TEXTURE_OT_new(wmOperatorType *ot); diff --git a/source/blender/editors/render/render_ops.cc b/source/blender/editors/render/render_ops.cc index c3814818a86..e7250f99f19 100644 --- a/source/blender/editors/render/render_ops.cc +++ b/source/blender/editors/render/render_ops.cc @@ -26,6 +26,7 @@ void ED_operatortypes_render() WM_operatortype_append(OBJECT_OT_material_slot_copy); WM_operatortype_append(OBJECT_OT_material_slot_move); WM_operatortype_append(OBJECT_OT_material_slot_remove_unused); + WM_operatortype_append(OBJECT_OT_material_slot_remove_all); WM_operatortype_append(OBJECT_OT_lightprobe_cache_bake); WM_operatortype_append(OBJECT_OT_lightprobe_cache_free); diff --git a/source/blender/editors/render/render_shading.cc b/source/blender/editors/render/render_shading.cc index d1109a304b6..2c5e10a1491 100644 --- a/source/blender/editors/render/render_shading.cc +++ b/source/blender/editors/render/render_shading.cc @@ -740,6 +740,71 @@ void OBJECT_OT_material_slot_remove_unused(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } +static wmOperatorStatus material_slot_remove_all_exec(bContext *C, wmOperator *op) +{ + /* Removing material slots in edit mode screws things up, see bug #21822. */ + Object *ob_active = CTX_data_active_object(C); + if (ob_active && BKE_object_is_in_editmode(ob_active)) { + BKE_report(op->reports, RPT_ERROR, "Unable to remove material slot in edit mode"); + return OPERATOR_CANCELLED; + } + Main *bmain = CTX_data_main(C); + int removed = 0; + + Vector objects = object_array_for_shading_edit_mode_disabled(C); + for (Object *ob : objects) { + int actcol = ob->actcol; + for (int slot = 1; slot <= ob->totcol; slot++) { + while (slot <= ob->totcol) { + ob->actcol = slot; + BKE_object_material_slot_remove(bmain, ob); + + if (actcol >= slot) { + actcol--; + } + + removed++; + } + } + ob->actcol = actcol; + + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + } + + if (!removed) { + return OPERATOR_CANCELLED; + } + + BKE_reportf(op->reports, RPT_INFO, "Removed %d materials", removed); + + if (ob_active->mode == OB_MODE_TEXTURE_PAINT) { + Scene *scene = CTX_data_scene(C); + ED_paint_proj_mesh_data_check(*scene, *ob_active, nullptr, nullptr, nullptr, nullptr); + WM_event_add_notifier(C, NC_SCENE | ND_TOOLSETTINGS, nullptr); + } + + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob_active); + WM_event_add_notifier(C, NC_OBJECT | ND_OB_SHADING, ob_active); + WM_event_add_notifier(C, NC_MATERIAL | ND_SHADING_PREVIEW, ob_active); + + return OPERATOR_FINISHED; +} + +void OBJECT_OT_material_slot_remove_all(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Remove All Materials"; + ot->idname = "OBJECT_OT_material_slot_remove_all"; + ot->description = "Remove all materials"; + + /* api callbacks */ + ot->exec = material_slot_remove_all_exec; + ot->poll = object_materials_supported_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + /** \} */ /* -------------------------------------------------------------------- */