1 # ##### BEGIN GPL LICENSE BLOCK #####
3 # This program is free software; you can redistribute it and/or
4 # modify it under the terms of the GNU General Public License
5 # as published by the Free Software Foundation; either version 2
6 # of the License, or (at your option) any later version.
8 # This program is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # GNU General Public License for more details.
13 # You should have received a copy of the GNU General Public License
14 # along with this program; if not, write to the Free Software Foundation,
15 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 # ##### END GPL LICENSE BLOCK #####
18 # by meta-androcto, saidenka #
21 "name": "Modifier Tools",
22 "author": "Meta Androcto, saidenka",
24 "blender": (2, 77, 0),
25 "location": "Properties > Modifiers",
26 "description": "Modifiers Specials Show/Hide/Apply Selected",
28 "wiki_url": "https://wiki.blender.org/index.php/Extensions:2.6"
29 "/Py/Scripts/3D_interaction/modifier_tools",
34 from bpy
.types
import Operator
37 class ApplyAllModifiers(Operator
):
38 bl_idname
= "object.apply_all_modifiers"
39 bl_label
= "Apply All"
40 bl_description
= ("Apply All modifiers of the selected object(s) \n"
41 "Active object has to have modifiers for the option to show up")
42 bl_options
= {'REGISTER', 'UNDO'}
44 def execute(self
, context
):
45 is_select
, is_mod
= False, False
46 message_a
, message_b
= "", ""
47 # collect names for objects failed to apply modifiers
50 for obj
in bpy
.context
.selected_objects
:
53 # copying context for the operator's override
54 contx
= bpy
.context
.copy()
57 for mod
in obj
.modifiers
[:]:
58 contx
['modifier'] = mod
61 bpy
.ops
.object.modifier_apply(
62 contx
, apply_as
='DATA',
63 modifier
=contx
['modifier'].name
66 obj_name
= getattr(obj
, "name", "NO NAME")
67 collect_names
.append(obj_name
)
73 message_a
= "Applying modifiers on all Selected Objects"
75 message_a
= "No Modifiers on Selected Objects"
77 self
.report({"INFO"}, "No Selection. No changes applied")
80 # applying failed for some objects, show report
81 message_obj
= (",".join(collect_names
) if collect_names
and
82 len(collect_names
) < 8 else "some objects (Check System Console)")
85 (message_a
if not message_b
else
86 "Applying modifiers failed for {}".format(message_obj
)))
88 if (collect_names
and message_obj
== "some objects (Check System Console)"):
89 print("\n[Modifier Tools]\n\nApplying failed on:"
90 "\n\n{} \n".format(", ".join(collect_names
)))
95 class DeleteAllModifiers(Operator
):
96 bl_idname
= "object.delete_all_modifiers"
97 bl_label
= "Remove All"
98 bl_description
= "Remove All modifiers of the selected object(s)"
99 bl_options
= {'REGISTER', 'UNDO'}
101 def invoke(self
, context
, event
):
102 return context
.window_manager
.invoke_confirm(self
, event
)
104 def execute(self
, context
):
105 is_select
, is_mod
= False, False
108 for obj
in context
.selected_objects
:
110 modifiers
= obj
.modifiers
[:]
111 for modi
in modifiers
:
113 obj
.modifiers
.remove(modi
)
117 message_a
= "Removing modifiers on all Selected Objects"
119 message_a
= "No Modifiers on Selected Objects"
121 self
.report({"INFO"}, "No Selection. No changes applied")
124 self
.report({"INFO"}, message_a
)
128 class ToggleApplyModifiersView(Operator
):
129 bl_idname
= "object.toggle_apply_modifiers_view"
130 bl_label
= "Hide Viewport"
131 bl_description
= "Shows/Hide modifiers of the active / selected object(s) in 3d View"
132 bl_options
= {'REGISTER'}
135 def poll(cls
, context
):
136 return context
.active_object
is not None
138 def execute(self
, context
):
142 for mod
in context
.active_object
.modifiers
:
143 if mod
.show_viewport
:
147 # active object - no selection
148 for mod
in context
.active_object
.modifiers
:
149 mod
.show_viewport
= is_apply
151 for obj
in context
.selected_objects
:
152 for mod
in obj
.modifiers
:
153 mod
.show_viewport
= is_apply
156 message_a
= "Displaying modifiers in the 3D View"
158 message_a
= "Hiding modifiers in the 3D View"
160 self
.report({"INFO"}, message_a
)
164 class ToggleAllShowExpanded(Operator
):
165 bl_idname
= "wm.toggle_all_show_expanded"
166 bl_label
= "Expand/Collapse All"
167 bl_description
= "Expand/Collapse Modifier Stack"
168 bl_options
= {'REGISTER'}
171 def poll(cls
, context
):
172 return context
.active_object
is not None
174 def execute(self
, context
):
175 obj
= context
.active_object
176 if (len(obj
.modifiers
)):
178 for mod
in obj
.modifiers
:
179 if (mod
.show_expanded
):
186 for mod
in obj
.modifiers
:
187 mod
.show_expanded
= not is_close
189 self
.report({'WARNING'}, "Not a single modifier to Expand/Collapse")
192 for area
in context
.screen
.areas
:
198 def menu(self
, context
):
199 if (context
.active_object
):
200 if (len(context
.active_object
.modifiers
)):
201 col
= self
.layout
.column(align
=True)
203 row
= col
.row(align
=True)
204 row
.operator(ApplyAllModifiers
.bl_idname
,
205 icon
='IMPORT', text
="Apply All")
206 row
.operator(DeleteAllModifiers
.bl_idname
,
207 icon
='X', text
="Delete All")
209 row
= col
.row(align
=True)
210 row
.operator(ToggleApplyModifiersView
.bl_idname
,
211 icon
='RESTRICT_VIEW_OFF',
213 row
.operator(ToggleAllShowExpanded
.bl_idname
,
214 icon
='FULLSCREEN_ENTER',
218 def menu_func(self
, context
):
219 if (context
.active_object
):
220 if (len(context
.active_object
.modifiers
)):
223 layout
.operator(ApplyAllModifiers
.bl_idname
,
225 text
="Apply All Modifiers")
229 bpy
.utils
.register_module(__name__
)
231 # Add "Specials" menu to the "Modifiers" menu
232 bpy
.types
.DATA_PT_modifiers
.prepend(menu
)
234 # Add apply operator to the Apply 3D View Menu
235 bpy
.types
.VIEW3D_MT_object_apply
.append(menu_func
)
239 # Remove "Specials" menu from the "Modifiers" menu.
240 bpy
.types
.DATA_PT_modifiers
.remove(menu
)
242 # Remove apply operator to the Apply 3D View Menu
243 bpy
.types
.VIEW3D_MT_object_apply
.remove(menu_func
)
245 bpy
.utils
.unregister_module(__name__
)
248 if __name__
== "__main__":