Fix T52833: OBJ triangulate doesn't match viewport
[blender-addons.git] / space_view3d_modifier_tools.py
blob71a97a580da1dcaa409494a97ff0bd7654b694af
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 #
20 bl_info = {
21 "name": "Modifier Tools",
22 "author": "Meta Androcto, saidenka",
23 "version": (0, 2, 4),
24 "blender": (2, 77, 0),
25 "location": "Properties > Modifiers",
26 "description": "Modifiers Specials Show/Hide/Apply Selected",
27 "warning": "",
28 "wiki_url": "https://wiki.blender.org/index.php/Extensions:2.6"
29 "/Py/Scripts/3D_interaction/modifier_tools",
30 "category": "3D View"
33 import bpy
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
48 collect_names = []
50 for obj in bpy.context.selected_objects:
51 is_select = True
53 # copying context for the operator's override
54 contx = bpy.context.copy()
55 contx['object'] = obj
57 for mod in obj.modifiers[:]:
58 contx['modifier'] = mod
59 is_mod = True
60 try:
61 bpy.ops.object.modifier_apply(
62 contx, apply_as='DATA',
63 modifier=contx['modifier'].name
65 except:
66 obj_name = getattr(obj, "name", "NO NAME")
67 collect_names.append(obj_name)
68 message_b = True
69 pass
71 if is_select:
72 if is_mod:
73 message_a = "Applying modifiers on all Selected Objects"
74 else:
75 message_a = "No Modifiers on Selected Objects"
76 else:
77 self.report({"INFO"}, "No Selection. No changes applied")
78 return {'CANCELLED'}
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)")
84 self.report({"INFO"},
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)))
92 return {'FINISHED'}
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
106 message_a = ""
108 for obj in context.selected_objects:
109 is_select = True
110 modifiers = obj.modifiers[:]
111 for modi in modifiers:
112 is_mod = True
113 obj.modifiers.remove(modi)
115 if is_select:
116 if is_mod:
117 message_a = "Removing modifiers on all Selected Objects"
118 else:
119 message_a = "No Modifiers on Selected Objects"
120 else:
121 self.report({"INFO"}, "No Selection. No changes applied")
122 return {'CANCELLED'}
124 self.report({"INFO"}, message_a)
125 return {'FINISHED'}
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'}
134 @classmethod
135 def poll(cls, context):
136 return context.active_object is not None
138 def execute(self, context):
139 is_apply = True
140 message_a = ""
142 for mod in context.active_object.modifiers:
143 if mod.show_viewport:
144 is_apply = False
145 break
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
155 if is_apply:
156 message_a = "Displaying modifiers in the 3D View"
157 else:
158 message_a = "Hiding modifiers in the 3D View"
160 self.report({"INFO"}, message_a)
161 return {'FINISHED'}
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'}
170 @classmethod
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)):
177 vs = 0
178 for mod in obj.modifiers:
179 if (mod.show_expanded):
180 vs += 1
181 else:
182 vs -= 1
183 is_close = False
184 if (0 < vs):
185 is_close = True
186 for mod in obj.modifiers:
187 mod.show_expanded = not is_close
188 else:
189 self.report({'WARNING'}, "Not a single modifier to Expand/Collapse")
190 return {'CANCELLED'}
192 for area in context.screen.areas:
193 area.tag_redraw()
194 return {'FINISHED'}
197 # Menus #
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',
212 text="Viewport Vis")
213 row.operator(ToggleAllShowExpanded.bl_idname,
214 icon='FULLSCREEN_ENTER',
215 text="Toggle Stack")
218 def menu_func(self, context):
219 if (context.active_object):
220 if (len(context.active_object.modifiers)):
221 layout = self.layout
222 layout.separator()
223 layout.operator(ApplyAllModifiers.bl_idname,
224 icon='IMPORT',
225 text="Apply All Modifiers")
228 def register():
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)
238 def unregister():
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__":
249 register()