diff --git a/scripts/startup/bl_ui/properties_data_modifier.py b/scripts/startup/bl_ui/properties_data_modifier.py index e31d5258612..9da5a1f7a2d 100644 --- a/scripts/startup/bl_ui/properties_data_modifier.py +++ b/scripts/startup/bl_ui/properties_data_modifier.py @@ -56,7 +56,10 @@ class OBJECT_MT_modifier_add(ModifierAddMenu, Menu): def draw(self, context): layout = self.layout - ob_type = context.object.type + ob = context.object + if not ob: + return + ob_type = ob.type geometry_nodes_supported = ob_type in { 'MESH', 'CURVE', 'CURVES', 'FONT', 'VOLUME', 'POINTCLOUD', 'GREASEPENCIL', diff --git a/scripts/startup/bl_ui/space_view3d.py b/scripts/startup/bl_ui/space_view3d.py index 18ff478453e..e181ec8b588 100644 --- a/scripts/startup/bl_ui/space_view3d.py +++ b/scripts/startup/bl_ui/space_view3d.py @@ -2889,6 +2889,7 @@ class VIEW3D_MT_object(Menu): layout.menu("VIEW3D_MT_object_relations") layout.menu("VIEW3D_MT_object_parent") layout.menu("VIEW3D_MT_object_constraints") + layout.menu("VIEW3D_MT_object_modifiers") layout.menu("VIEW3D_MT_object_track") layout.menu("VIEW3D_MT_make_links") @@ -3357,6 +3358,20 @@ class VIEW3D_MT_object_constraints(Menu): layout.operator("object.constraints_clear") +class VIEW3D_MT_object_modifiers(Menu): + bl_label = "Modifiers" + + def draw(self, _context): + layout = self.layout + + layout.menu("OBJECT_MT_modifier_add", text="Add") + layout.operator("object.modifiers_copy_to_selected", text="Copy to Selected") + + layout.separator() + + layout.operator("object.modifiers_clear") + + class VIEW3D_MT_object_quick_effects(Menu): bl_label = "Quick Effects" @@ -9136,6 +9151,7 @@ classes = ( VIEW3D_MT_object_track, VIEW3D_MT_object_collection, VIEW3D_MT_object_constraints, + VIEW3D_MT_object_modifiers, VIEW3D_MT_object_quick_effects, VIEW3D_MT_object_showhide, VIEW3D_MT_object_cleanup, diff --git a/source/blender/editors/object/add_modifier_assets.cc b/source/blender/editors/object/add_modifier_assets.cc index 7dc030db361..e78657c068f 100644 --- a/source/blender/editors/object/add_modifier_assets.cc +++ b/source/blender/editors/object/add_modifier_assets.cc @@ -338,7 +338,7 @@ static int modifier_add_asset_exec(bContext *C, wmOperator *op) static int modifier_add_asset_invoke(bContext *C, wmOperator *op, const wmEvent *event) { - if (event->modifier & KM_ALT) { + if (event->modifier & KM_ALT || CTX_wm_view3d(C)) { RNA_boolean_set(op->ptr, "use_selected_objects", true); } return modifier_add_asset_exec(C, op); diff --git a/source/blender/editors/object/object_intern.hh b/source/blender/editors/object/object_intern.hh index 197f5dc1606..76fb44f7dc5 100644 --- a/source/blender/editors/object/object_intern.hh +++ b/source/blender/editors/object/object_intern.hh @@ -195,6 +195,7 @@ ModifierData *edit_modifier_property_get(wmOperator *op, Object *ob, int type); void OBJECT_OT_modifier_add(wmOperatorType *ot); void OBJECT_OT_modifier_remove(wmOperatorType *ot); +void OBJECT_OT_modifiers_clear(wmOperatorType *ot); void OBJECT_OT_modifier_move_up(wmOperatorType *ot); void OBJECT_OT_modifier_move_down(wmOperatorType *ot); void OBJECT_OT_modifier_move_to_index(wmOperatorType *ot); @@ -203,6 +204,7 @@ void OBJECT_OT_modifier_apply_as_shapekey(wmOperatorType *ot); void OBJECT_OT_modifier_convert(wmOperatorType *ot); void OBJECT_OT_modifier_copy(wmOperatorType *ot); void OBJECT_OT_modifier_copy_to_selected(wmOperatorType *ot); +void OBJECT_OT_modifiers_copy_to_selected(wmOperatorType *ot); void OBJECT_OT_modifier_set_active(wmOperatorType *ot); void OBJECT_OT_multires_subdivide(wmOperatorType *ot); void OBJECT_OT_multires_reshape(wmOperatorType *ot); diff --git a/source/blender/editors/object/object_modifier.cc b/source/blender/editors/object/object_modifier.cc index a85ca9a49d9..aa50147db81 100644 --- a/source/blender/editors/object/object_modifier.cc +++ b/source/blender/editors/object/object_modifier.cc @@ -1290,7 +1290,7 @@ void modifier_register_use_selected_objects_prop(wmOperatorType *ot) false, "Selected Objects", "Affect all selected objects instead of just the active object"); - RNA_def_property_flag(prop, PROP_SKIP_SAVE); + RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN); } /* ------------------------------------------------------------------- */ @@ -1321,7 +1321,7 @@ static int modifier_add_exec(bContext *C, wmOperator *op) static int modifier_add_invoke(bContext *C, wmOperator *op, const wmEvent *event) { - if (event->modifier & KM_ALT) { + if (event->modifier & KM_ALT || CTX_wm_view3d(C)) { RNA_boolean_set(op->ptr, "use_selected_objects", true); } if (!RNA_struct_property_is_set(op->ptr, "type")) { @@ -1641,6 +1641,32 @@ void OBJECT_OT_modifier_remove(wmOperatorType *ot) modifier_register_use_selected_objects_prop(ot); } +static int modifiers_clear_exec(bContext *C, wmOperator * /*op*/) +{ + Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); + + CTX_DATA_BEGIN (C, Object *, object, selected_editable_objects) { + modifiers_clear(bmain, scene, object); + WM_main_add_notifier(NC_OBJECT | ND_MODIFIER | NA_REMOVED, object); + } + CTX_DATA_END; + + return OPERATOR_FINISHED; +} + +void OBJECT_OT_modifiers_clear(wmOperatorType *ot) +{ + ot->name = "Clear Object Modifiers"; + ot->description = "Clear all modifiers from the selected objects"; + ot->idname = "OBJECT_OT_modifiers_clear"; + + ot->exec = modifiers_clear_exec; + ot->poll = ED_operator_object_active_local_editable; + + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + /** \} */ /* ------------------------------------------------------------------- */ @@ -2287,6 +2313,60 @@ void OBJECT_OT_modifier_copy_to_selected(wmOperatorType *ot) edit_modifier_properties(ot); } +static int object_modifiers_copy_exec(bContext *C, wmOperator *op) +{ + Main *bmain = CTX_data_main(C); + const Scene *scene = CTX_data_scene(C); + Object *active_object = context_active_object(C); + + Vector selected_objects; + CTX_data_selected_objects(C, &selected_objects); + CTX_DATA_BEGIN (C, Object *, object, selected_objects) { + if (object == active_object) { + continue; + } + LISTBASE_FOREACH (const ModifierData *, md, &active_object->modifiers) { + if (modifier_copy_to_object(bmain, scene, active_object, md, object, op->reports)) { + WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER | NA_ADDED, object); + } + } + } + CTX_DATA_END; + + return OPERATOR_FINISHED; + + DEG_relations_tag_update(bmain); + + WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER | NA_ADDED, nullptr); + + return OPERATOR_FINISHED; +} + +static bool modifiers_copy_to_selected_poll(bContext *C) +{ + if (!ED_operator_object_active_editable(C)) { + return false; + } + Object *active_object = context_active_object(C); + if (BLI_listbase_is_empty(&active_object->modifiers)) { + CTX_wm_operator_poll_msg_set(C, "Active object has no modifiers"); + return false; + } + return true; +} + +void OBJECT_OT_modifiers_copy_to_selected(wmOperatorType *ot) +{ + ot->name = "Copy Modifiers to Selected Objects"; + ot->idname = "OBJECT_OT_modifiers_copy_to_selected"; + ot->description = "Copy modifiers to other selected objects"; + + ot->exec = object_modifiers_copy_exec; + ot->poll = modifiers_copy_to_selected_poll; + + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + /** \} */ /* ------------------------------------------------------------------- */ diff --git a/source/blender/editors/object/object_ops.cc b/source/blender/editors/object/object_ops.cc index 588c79046c2..fa975d92761 100644 --- a/source/blender/editors/object/object_ops.cc +++ b/source/blender/editors/object/object_ops.cc @@ -119,6 +119,7 @@ void operatortypes_object() WM_operatortype_append(OBJECT_OT_modifier_add); WM_operatortype_append(OBJECT_OT_modifier_remove); + WM_operatortype_append(OBJECT_OT_modifiers_clear); WM_operatortype_append(OBJECT_OT_modifier_move_up); WM_operatortype_append(OBJECT_OT_modifier_move_down); WM_operatortype_append(OBJECT_OT_modifier_move_to_index); @@ -127,6 +128,7 @@ void operatortypes_object() WM_operatortype_append(OBJECT_OT_modifier_convert); WM_operatortype_append(OBJECT_OT_modifier_copy); WM_operatortype_append(OBJECT_OT_modifier_copy_to_selected); + WM_operatortype_append(OBJECT_OT_modifiers_copy_to_selected); WM_operatortype_append(OBJECT_OT_modifier_set_active); WM_operatortype_append(OBJECT_OT_multires_subdivide); WM_operatortype_append(OBJECT_OT_multires_reshape);