Animall: make UI more aligned to Blender's conventions
[blender-addons.git] / animation_animall.py
blobf13c8b12406e629249279449c3c0817b79a8f962
1 # SPDX-License-Identifier: GPL-2.0-or-later
3 bl_info = {
4 "name": "AnimAll",
5 "author": "Daniel Salazar (ZanQdo), Damien Picard (pioverfour)",
6 "version": (0, 9, 6),
7 "blender": (3, 3, 0),
8 "location": "3D View > Toolbox > Animation tab > AnimAll",
9 "description": "Allows animation of mesh, lattice, curve and surface data",
10 "warning": "",
11 "doc_url": "{BLENDER_MANUAL_URL}/addons/animation/animall.html",
12 "category": "Animation",
15 import bpy
16 from bpy.types import (
17 Operator,
18 Panel,
19 AddonPreferences,
21 from bpy.props import (
22 BoolProperty,
23 StringProperty,
25 from bpy.app.handlers import persistent
28 # Property Definitions
29 class AnimallProperties(bpy.types.PropertyGroup):
30 key_selected: BoolProperty(
31 name="Key Selected Only",
32 description="Insert keyframes only on selected elements",
33 default=False)
35 # Generic attributes
36 key_point_location: BoolProperty(
37 name="Location",
38 description="Insert keyframes on point locations",
39 default=False)
40 key_shape_key: BoolProperty(
41 name="Shape Key",
42 description="Insert keyframes on active Shape Key layer",
43 default=False)
44 key_material_index: BoolProperty(
45 name="Material Index",
46 description="Insert keyframes on face material indices",
47 default=False)
49 # Mesh attributes
50 key_vertex_bevel: BoolProperty(
51 name="Vertex Bevel",
52 description="Insert keyframes on vertex bevel weight",
53 default=False)
54 # key_vertex_crease: BoolProperty(
55 # name="Vertex Crease",
56 # description="Insert keyframes on vertex crease weight",
57 # default=False)
58 key_vertex_group: BoolProperty(
59 name="Vertex Group",
60 description="Insert keyframes on active vertex group values",
61 default=False)
63 key_edge_bevel: BoolProperty(
64 name="Edge Bevel",
65 description="Insert keyframes on edge bevel weight",
66 default=False)
67 key_edge_crease: BoolProperty(
68 name="Edge Crease",
69 description="Insert keyframes on edge creases",
70 default=False)
72 key_attribute: BoolProperty(
73 name="Attribute",
74 description="Insert keyframes on active attribute values",
75 default=False)
76 key_uvs: BoolProperty(
77 name="UVs",
78 description="Insert keyframes on active UV coordinates",
79 default=False)
81 # Curve and surface attributes
82 key_radius: BoolProperty(
83 name="Radius",
84 description="Insert keyframes on point radius (Shrink/Fatten)",
85 default=False)
86 key_tilt: BoolProperty(
87 name="Tilt",
88 description="Insert keyframes on point tilt",
89 default=False)
92 # Utility functions
94 def refresh_ui_keyframes():
95 try:
96 for area in bpy.context.screen.areas:
97 if area.type in ('TIMELINE', 'GRAPH_EDITOR', 'DOPESHEET_EDITOR'):
98 area.tag_redraw()
99 except:
100 pass
103 def insert_key(data, key, group=None):
104 try:
105 if group is not None:
106 data.keyframe_insert(key, group=group)
107 else:
108 data.keyframe_insert(key)
109 except:
110 pass
113 def delete_key(data, key):
114 try:
115 data.keyframe_delete(key)
116 except:
117 pass
120 def is_selected_vert_loop(data, loop_i):
121 """Get selection status of vertex corresponding to a loop"""
122 vertex_index = data.loops[loop_i].vertex_index
123 return data.vertices[vertex_index].select
126 # GUI (Panel)
128 class VIEW3D_PT_animall(Panel):
129 bl_space_type = 'VIEW_3D'
130 bl_region_type = 'UI'
131 bl_category = "Animate"
132 bl_label = 'AnimAll'
134 @classmethod
135 def poll(self, context):
136 return context.active_object and context.active_object.type in {'MESH', 'LATTICE', 'CURVE', 'SURFACE'}
138 def draw(self, context):
139 obj = context.active_object
140 animall_properties = context.scene.animall_properties
142 layout = self.layout
144 layout.use_property_split = True
145 layout.use_property_decorate = False
147 split = layout.split(factor=0.4, align=True)
148 split.label(text='')
149 split.label(text=' Key:')
151 if obj.type == 'LATTICE':
152 col = layout.column(align=True)
153 col.prop(animall_properties, "key_point_location")
154 col.prop(animall_properties, "key_shape_key")
156 elif obj.type == 'MESH':
157 col = layout.column(heading="Points", align=True)
158 col.prop(animall_properties, "key_point_location")
159 col.prop(animall_properties, "key_vertex_bevel", text="Bevel")
160 col.prop(animall_properties, "key_vertex_group", text="Vertex Groups")
162 col = layout.column(heading="Edges", align=True)
163 col.prop(animall_properties, "key_edge_bevel", text="Bevel")
164 col.prop(animall_properties, "key_edge_crease", text="Crease")
166 col = layout.column(heading="Faces", align=True)
167 col.prop(animall_properties, "key_material_index")
169 col = layout.column(heading="Others", align=True)
170 col.prop(animall_properties, "key_attribute")
171 col.prop(animall_properties, "key_uvs")
172 col.prop(animall_properties, "key_shape_key")
174 # Vertex group update operator
175 if (obj.data.animation_data is not None
176 and obj.data.animation_data.action is not None):
177 for fcurve in context.active_object.data.animation_data.action.fcurves:
178 if fcurve.data_path.startswith("vertex_colors"):
179 col = layout.column(align=True)
180 col.label(text="Object includes old-style vertex colors. Consider updating them.", icon="ERROR")
181 col.operator("anim.update_vertex_color_animation_animall", icon="FILE_REFRESH")
182 break
184 elif obj.type in {'CURVE', 'SURFACE'}:
185 col = layout.column(align=True)
186 col.prop(animall_properties, "key_point_location")
187 col.prop(animall_properties, "key_radius")
188 col.prop(animall_properties, "key_tilt")
189 col.prop(animall_properties, "key_material_index")
190 col.prop(animall_properties, "key_shape_key")
192 if animall_properties.key_shape_key:
193 shape_key = obj.active_shape_key
194 shape_key_index = obj.active_shape_key_index
196 if shape_key_index > 0:
197 col = layout.column(align=True)
198 row = col.row(align=True)
199 row.prop(shape_key, "value", text=shape_key.name, icon="SHAPEKEY_DATA")
200 row.prop(obj, "show_only_shape_key", text="")
201 if shape_key.value < 1:
202 col.label(text='Maybe set "%s" to 1.0?' % shape_key.name, icon="INFO")
203 elif shape_key is not None:
204 col = layout.column(align=True)
205 col.label(text="Cannot key on Basis Shape", icon="ERROR")
206 else:
207 col = layout.column(align=True)
208 col.label(text="No active Shape Key", icon="ERROR")
210 if animall_properties.key_point_location:
211 col.label(text='"Location" and "Shape Key" are redundant?', icon="INFO")
213 col = layout.column(align=True)
214 col.prop(animall_properties, "key_selected")
216 row = layout.row(align=True)
217 row.operator("anim.insert_keyframe_animall", icon="KEY_HLT")
218 row.operator("anim.delete_keyframe_animall", icon="KEY_DEHLT")
219 row = layout.row()
220 row.operator("anim.clear_animation_animall", icon="CANCEL")
223 class ANIM_OT_insert_keyframe_animall(Operator):
224 bl_label = "Insert Key"
225 bl_idname = "anim.insert_keyframe_animall"
226 bl_description = "Insert a Keyframe"
227 bl_options = {'REGISTER', 'UNDO'}
229 def execute(op, context):
230 animall_properties = context.scene.animall_properties
232 if context.mode == 'OBJECT':
233 objects = context.selected_objects
234 else:
235 objects = context.objects_in_mode_unique_data[:]
237 mode = context.object.mode
239 # Separate loop for lattices, curves and surfaces, since keyframe insertion
240 # has to happen in Edit Mode, otherwise points move back upon mode switch...
241 # (except for curve shape keys)
242 for obj in [o for o in objects if o.type in {'CURVE', 'SURFACE', 'LATTICE'}]:
243 data = obj.data
245 if obj.type == 'LATTICE':
246 if animall_properties.key_shape_key:
247 if obj.active_shape_key_index > 0:
248 sk_name = obj.active_shape_key.name
249 for p_i, point in enumerate(obj.active_shape_key.data):
250 if not animall_properties.key_selected or data.points[p_i].select:
251 insert_key(point, 'co', group="%s Point %s" % (sk_name, p_i))
253 if animall_properties.key_point_location:
254 for p_i, point in enumerate(data.points):
255 if not animall_properties.key_selected or point.select:
256 insert_key(point, 'co_deform', group="Point %s" % p_i)
258 else:
259 if animall_properties.key_material_index:
260 for s_i, spline in enumerate(data.splines):
261 if (not animall_properties.key_selected
262 or any(point.select for point in spline.points)
263 or any(point.select_control_point for point in spline.bezier_points)):
264 insert_key(spline, 'material_index', group="Spline %s" % s_i)
266 for s_i, spline in enumerate(data.splines):
267 if spline.type == 'BEZIER':
268 for v_i, CV in enumerate(spline.bezier_points):
269 if (not animall_properties.key_selected
270 or CV.select_control_point
271 or CV.select_left_handle
272 or CV.select_right_handle):
273 if animall_properties.key_point_location:
274 insert_key(CV, 'co', group="Spline %s CV %s" % (s_i, v_i))
275 insert_key(CV, 'handle_left', group="Spline %s CV %s" % (s_i, v_i))
276 insert_key(CV, 'handle_right', group="Spline %s CV %s" % (s_i, v_i))
278 if animall_properties.key_radius:
279 insert_key(CV, 'radius', group="Spline %s CV %s" % (s_i, v_i))
281 if animall_properties.key_tilt:
282 insert_key(CV, 'tilt', group="Spline %s CV %s" % (s_i, v_i))
284 elif spline.type in ('POLY', 'NURBS'):
285 for v_i, CV in enumerate(spline.points):
286 if not animall_properties.key_selected or CV.select:
287 if animall_properties.key_point_location:
288 insert_key(CV, 'co', group="Spline %s CV %s" % (s_i, v_i))
290 if animall_properties.key_radius:
291 insert_key(CV, 'radius', group="Spline %s CV %s" % (s_i, v_i))
293 if animall_properties.key_tilt:
294 insert_key(CV, 'tilt', group="Spline %s CV %s" % (s_i, v_i))
296 bpy.ops.object.mode_set(mode='OBJECT')
298 for obj in [o for o in objects if o.type in {'MESH', 'CURVE', 'SURFACE'}]:
299 data = obj.data
300 if obj.type == 'MESH':
301 if animall_properties.key_point_location:
302 for v_i, vert in enumerate(data.vertices):
303 if not animall_properties.key_selected or vert.select:
304 insert_key(vert, 'co', group="Vertex %s" % v_i)
306 if animall_properties.key_vertex_bevel:
307 for v_i, vert in enumerate(data.vertices):
308 if not animall_properties.key_selected or vert.select:
309 insert_key(vert, 'bevel_weight', group="Vertex %s" % v_i)
310 # if animall_properties.key_vertex_crease:
311 # for v_i, vert in enumerate(data.vertices):
312 # if not animall_properties.key_selected or vert.select:
313 # insert_key(vert, 'crease', group="Vertex %s" % v_i)
315 if animall_properties.key_vertex_group:
316 for v_i, vert in enumerate(data.vertices):
317 if not animall_properties.key_selected or vert.select:
318 for group in vert.groups:
319 insert_key(group, 'weight', group="Vertex %s" % v_i)
321 if animall_properties.key_edge_bevel:
322 for e_i, edge in enumerate(data.edges):
323 if not animall_properties.key_selected or edge.select:
324 insert_key(edge, 'bevel_weight', group="Edge %s" % e_i)
326 if animall_properties.key_edge_crease:
327 for e_i, edge in enumerate(data.edges):
328 if not animall_properties.key_selected or edge.select:
329 insert_key(edge, 'crease', group="Edge %s" % e_i)
331 if animall_properties.key_material_index:
332 for p_i, polygon in enumerate(data.polygons):
333 if not animall_properties.key_selected or polygon.select:
334 insert_key(polygon, 'material_index', group="Face %s" % p_i)
336 if animall_properties.key_attribute:
337 if data.attributes.active is not None:
338 attribute = data.attributes.active
339 if attribute.data_type != 'STRING':
340 # Cannot animate string attributes?
341 if attribute.data_type in {'FLOAT', 'INT', 'BOOLEAN', 'INT8'}:
342 attribute_key = "value"
343 elif attribute.data_type in {'FLOAT_COLOR', 'BYTE_COLOR'}:
344 attribute_key = "color"
345 elif attribute.data_type in {'FLOAT_VECTOR', 'FLOAT2'}:
346 attribute_key = "vector"
348 if attribute.domain == 'POINT':
349 group = "Vertex %s"
350 elif attribute.domain == 'EDGE':
351 group = "Edge %s"
352 elif attribute.domain == 'FACE':
353 group = "Face %s"
354 elif attribute.domain == 'CORNER':
355 group = "Loop %s"
357 for e_i, _attribute_data in enumerate(attribute.data):
358 if (not animall_properties.key_selected
359 or attribute.domain == 'POINT' and data.vertices[e_i].select
360 or attribute.domain == 'EDGE' and data.edges[e_i].select
361 or attribute.domain == 'FACE' and data.polygons[e_i].select
362 or attribute.domain == 'CORNER' and is_selected_vert_loop(data, e_i)):
363 insert_key(data, f'attributes["{attribute.name}"].data[{e_i}].{attribute_key}',
364 group=group % e_i)
366 if animall_properties.key_uvs:
367 if data.uv_layers.active is not None:
368 for uv_i, uv in enumerate(data.uv_layers.active.data):
369 if not animall_properties.key_selected or uv.select:
370 insert_key(uv, 'uv', group="UV layer %s" % uv_i)
372 if animall_properties.key_shape_key:
373 if obj.active_shape_key_index > 0:
374 sk_name = obj.active_shape_key.name
375 for v_i, vert in enumerate(obj.active_shape_key.data):
376 if not animall_properties.key_selected or data.vertices[v_i].select:
377 insert_key(vert, 'co', group="%s Vertex %s" % (sk_name, v_i))
379 elif obj.type in {'CURVE', 'SURFACE'}:
380 # Shape key keys have to be inserted in object mode for curves...
381 if animall_properties.key_shape_key:
382 sk_name = obj.active_shape_key.name
383 global_spline_index = 0 # numbering for shape keys, which have flattened indices
384 for s_i, spline in enumerate(data.splines):
385 if spline.type == 'BEZIER':
386 for v_i, CV in enumerate(spline.bezier_points):
387 if (not animall_properties.key_selected
388 or CV.select_control_point
389 or CV.select_left_handle
390 or CV.select_right_handle):
391 if obj.active_shape_key_index > 0:
392 CV = obj.active_shape_key.data[global_spline_index]
393 insert_key(CV, 'co', group="%s Spline %s CV %s" % (sk_name, s_i, v_i))
394 insert_key(CV, 'handle_left', group="%s Spline %s CV %s" % (sk_name, s_i, v_i))
395 insert_key(CV, 'handle_right', group="%s Spline %s CV %s" % (sk_name, s_i, v_i))
396 insert_key(CV, 'radius', group="%s Spline %s CV %s" % (sk_name, s_i, v_i))
397 insert_key(CV, 'tilt', group="%s Spline %s CV %s" % (sk_name, s_i, v_i))
398 global_spline_index += 1
400 elif spline.type in ('POLY', 'NURBS'):
401 for v_i, CV in enumerate(spline.points):
402 if not animall_properties.key_selected or CV.select:
403 if obj.active_shape_key_index > 0:
404 CV = obj.active_shape_key.data[global_spline_index]
405 insert_key(CV, 'co', group="%s Spline %s CV %s" % (sk_name, s_i, v_i))
406 insert_key(CV, 'radius', group="%s Spline %s CV %s" % (sk_name, s_i, v_i))
407 insert_key(CV, 'tilt', group="%s Spline %s CV %s" % (sk_name, s_i, v_i))
408 global_spline_index += 1
410 bpy.ops.object.mode_set(mode=mode)
411 refresh_ui_keyframes()
413 return {'FINISHED'}
416 class ANIM_OT_delete_keyframe_animall(Operator):
417 bl_label = "Delete Key"
418 bl_idname = "anim.delete_keyframe_animall"
419 bl_description = "Delete a Keyframe"
420 bl_options = {'REGISTER', 'UNDO'}
423 def execute(op, context):
424 animall_properties = context.scene.animall_properties
426 if context.mode == 'OBJECT':
427 objects = context.selected_objects
428 else:
429 objects = context.objects_in_mode_unique_data[:]
431 mode = context.object.mode
433 for obj in objects:
434 data = obj.data
435 if obj.type == 'MESH':
436 if animall_properties.key_point_location:
437 for vert in data.vertices:
438 if not animall_properties.key_selected or vert.select:
439 delete_key(vert, 'co')
441 if animall_properties.key_vertex_bevel:
442 for vert in data.vertices:
443 if not animall_properties.key_selected or vert.select:
444 delete_key(vert, 'bevel_weight')
446 if animall_properties.key_vertex_group:
447 for vert in data.vertices:
448 if not animall_properties.key_selected or vert.select:
449 for group in vert.groups:
450 delete_key(group, 'weight')
452 # if animall_properties.key_vcrease:
453 # for vert in data.vertices:
454 # if not animall_properties.key_selected or vert.select:
455 # delete_key(vert, 'crease')
457 if animall_properties.key_edge_bevel:
458 for edge in data.edges:
459 if not animall_properties.key_selected or edge.select:
460 delete_key(edge, 'bevel_weight')
462 if animall_properties.key_edge_crease:
463 for edge in data.edges:
464 if not animall_properties.key_selected or vert.select:
465 delete_key(edge, 'crease')
467 if animall_properties.key_shape_key:
468 if obj.active_shape_key:
469 for v_i, vert in enumerate(obj.active_shape_key.data):
470 if not animall_properties.key_selected or data.vertices[v_i].select:
471 delete_key(vert, 'co')
473 if animall_properties.key_uvs:
474 if data.uv_layers.active is not None:
475 for uv in data.uv_layers.active.data:
476 if not animall_properties.key_selected or uv.select:
477 delete_key(uv, 'uv')
479 if animall_properties.key_attribute:
480 if data.attributes.active is not None:
481 attribute = data.attributes.active
482 if attribute.data_type != 'STRING':
483 # Cannot animate string attributes?
484 if attribute.data_type in {'FLOAT', 'INT', 'BOOLEAN', 'INT8'}:
485 attribute_key = "value"
486 elif attribute.data_type in {'FLOAT_COLOR', 'BYTE_COLOR'}:
487 attribute_key = "color"
488 elif attribute.data_type in {'FLOAT_VECTOR', 'FLOAT2'}:
489 attribute_key = "vector"
491 for e_i, _attribute_data in enumerate(attribute.data):
492 if (not animall_properties.key_selected
493 or attribute.domain == 'POINT' and data.vertices[e_i].select
494 or attribute.domain == 'EDGE' and data.edges[e_i].select
495 or attribute.domain == 'FACE' and data.polygons[e_i].select
496 or attribute.domain == 'CORNER' and is_selected_vert_loop(data, e_i)):
497 delete_key(data, f'attributes["{attribute.name}"].data[{e_i}].{attribute_key}')
499 elif obj.type == 'LATTICE':
500 if animall_properties.key_shape_key:
501 if obj.active_shape_key:
502 for point in obj.active_shape_key.data:
503 delete_key(point, 'co')
505 if animall_properties.key_point_location:
506 for point in data.points:
507 if not animall_properties.key_selected or point.select:
508 delete_key(point, 'co_deform')
510 elif obj.type in {'CURVE', 'SURFACE'}:
511 # run this outside the splines loop (only once)
512 if animall_properties.key_shape_key:
513 if obj.active_shape_key_index > 0:
514 for CV in obj.active_shape_key.data:
515 delete_key(CV, 'co')
516 delete_key(CV, 'handle_left')
517 delete_key(CV, 'handle_right')
519 for spline in data.splines:
520 if spline.type == 'BEZIER':
521 for CV in spline.bezier_points:
522 if (not animall_properties.key_selected
523 or CV.select_control_point
524 or CV.select_left_handle
525 or CV.select_right_handle):
526 if animall_properties.key_point_location:
527 delete_key(CV, 'co')
528 delete_key(CV, 'handle_left')
529 delete_key(CV, 'handle_right')
530 if animall_properties.key_radius:
531 delete_key(CV, 'radius')
532 if animall_properties.key_tilt:
533 delete_key(CV, 'tilt')
535 elif spline.type in ('POLY', 'NURBS'):
536 for CV in spline.points:
537 if not animall_properties.key_selected or CV.select:
538 if animall_properties.key_point_location:
539 delete_key(CV, 'co')
540 if animall_properties.key_radius:
541 delete_key(CV, 'radius')
542 if animall_properties.key_tilt:
543 delete_key(CV, 'tilt')
545 refresh_ui_keyframes()
547 return {'FINISHED'}
550 class ANIM_OT_clear_animation_animall(Operator):
551 bl_label = "Clear Animation"
552 bl_idname = "anim.clear_animation_animall"
553 bl_description = ("Delete all keyframes for this object\n"
554 "If in a specific case it doesn't work\n"
555 "try to delete the keys manually")
556 bl_options = {'REGISTER', 'UNDO'}
558 def invoke(self, context, event):
559 wm = context.window_manager
560 return wm.invoke_confirm(self, event)
562 def execute(self, context):
563 if context.mode == 'OBJECT':
564 objects = context.selected_objects
565 else:
566 objects = context.objects_in_mode_unique_data
568 for obj in objects:
569 try:
570 data = obj.data
571 data.animation_data_clear()
572 except:
573 self.report({'WARNING'}, "Clear Animation could not be performed")
574 return {'CANCELLED'}
576 refresh_ui_keyframes()
578 return {'FINISHED'}
581 class ANIM_OT_update_vertex_color_animation_animall(Operator):
582 bl_label = "Update Vertex Color Animation"
583 bl_idname = "anim.update_vertex_color_animation_animall"
584 bl_description = "Update old vertex color channel formats from pre-3.3 versions"
585 bl_options = {'REGISTER', 'UNDO'}
587 @classmethod
588 def poll(self, context):
589 if (context.active_object is None
590 or context.active_object.type != 'MESH'
591 or context.active_object.data.animation_data is None
592 or context.active_object.data.animation_data.action is None):
593 return False
594 for fcurve in context.active_object.data.animation_data.action.fcurves:
595 if fcurve.data_path.startswith("vertex_colors"):
596 return True
598 def execute(self, context):
599 for fcurve in context.active_object.data.animation_data.action.fcurves:
600 if fcurve.data_path.startswith("vertex_colors"):
601 fcurve.data_path = fcurve.data_path.replace("vertex_colors", "attributes")
602 return {'FINISHED'}
604 # Add-ons Preferences Update Panel
606 # Define Panel classes for updating
607 panels = [
608 VIEW3D_PT_animall
612 def update_panel(self, context):
613 message = "AnimAll: Updating Panel locations has failed"
614 try:
615 for panel in panels:
616 if "bl_rna" in panel.__dict__:
617 bpy.utils.unregister_class(panel)
619 for panel in panels:
620 panel.bl_category = context.preferences.addons[__name__].preferences.category
621 bpy.utils.register_class(panel)
623 except Exception as e:
624 print("\n[{}]\n{}\n\nError:\n{}".format(__name__, message, e))
625 pass
628 class AnimallAddonPreferences(AddonPreferences):
629 # this must match the addon name, use '__package__'
630 # when defining this in a submodule of a python package.
631 bl_idname = __name__
633 category: StringProperty(
634 name="Tab Category",
635 description="Choose a name for the category of the panel",
636 default="Animate",
637 update=update_panel
640 def draw(self, context):
641 layout = self.layout
642 row = layout.row()
643 col = row.column()
645 col.label(text="Tab Category:")
646 col.prop(self, "category", text="")
649 def register():
650 bpy.utils.register_class(AnimallProperties)
651 bpy.types.Scene.animall_properties = bpy.props.PointerProperty(type=AnimallProperties)
652 bpy.utils.register_class(VIEW3D_PT_animall)
653 bpy.utils.register_class(ANIM_OT_insert_keyframe_animall)
654 bpy.utils.register_class(ANIM_OT_delete_keyframe_animall)
655 bpy.utils.register_class(ANIM_OT_clear_animation_animall)
656 bpy.utils.register_class(ANIM_OT_update_vertex_color_animation_animall)
657 bpy.utils.register_class(AnimallAddonPreferences)
658 update_panel(None, bpy.context)
661 def unregister():
662 del bpy.types.Scene.animall_properties
663 bpy.utils.unregister_class(AnimallProperties)
664 bpy.utils.unregister_class(VIEW3D_PT_animall)
665 bpy.utils.unregister_class(ANIM_OT_insert_keyframe_animall)
666 bpy.utils.unregister_class(ANIM_OT_delete_keyframe_animall)
667 bpy.utils.unregister_class(ANIM_OT_clear_animation_animall)
668 bpy.utils.unregister_class(ANIM_OT_update_vertex_color_animation_animall)
669 bpy.utils.unregister_class(AnimallAddonPreferences)
671 if __name__ == "__main__":
672 register()