1 # SPDX-FileCopyrightText: 2011-2022 Blender Foundation
3 # SPDX-License-Identifier: GPL-2.0-or-later
7 "author": "Daniel Salazar (ZanQdo), Damien Picard (pioverfour)",
10 "location": "3D View > Toolbox > Animation tab > AnimAll",
11 "description": "Allows animation of mesh, lattice, curve and surface data",
13 "doc_url": "{BLENDER_MANUAL_URL}/addons/animation/animall.html",
14 "category": "Animation",
18 from bpy
.types
import (Operator
, Panel
, AddonPreferences
)
19 from bpy
.props
import (BoolProperty
, StringProperty
)
20 from bpy
.app
.handlers
import persistent
21 from bpy
.app
.translations
import (pgettext_iface
as iface_
,
22 pgettext_data
as data_
)
23 from . import translations
26 # Property Definitions
27 class AnimallProperties(bpy
.types
.PropertyGroup
):
28 key_selected
: BoolProperty(
29 name
="Key Selected Only",
30 description
="Insert keyframes only on selected elements",
34 key_point_location
: BoolProperty(
36 description
="Insert keyframes on point locations",
38 key_shape_key
: BoolProperty(
40 description
="Insert keyframes on active Shape Key layer",
42 key_material_index
: BoolProperty(
43 name
="Material Index",
44 description
="Insert keyframes on face material indices",
48 key_vertex_bevel
: BoolProperty(
50 description
="Insert keyframes on vertex bevel weight",
52 # key_vertex_crease: BoolProperty(
53 # name="Vertex Crease",
54 # description="Insert keyframes on vertex crease weight",
56 key_vertex_group
: BoolProperty(
58 description
="Insert keyframes on active vertex group values",
61 key_edge_bevel
: BoolProperty(
63 description
="Insert keyframes on edge bevel weight",
65 key_edge_crease
: BoolProperty(
67 description
="Insert keyframes on edge creases",
70 key_attribute
: BoolProperty(
72 description
="Insert keyframes on active attribute values",
74 key_uvs
: BoolProperty(
76 description
="Insert keyframes on active UV coordinates",
79 # Curve and surface attributes
80 key_radius
: BoolProperty(
82 description
="Insert keyframes on point radius (Shrink/Fatten)",
84 key_tilt
: BoolProperty(
86 description
="Insert keyframes on point tilt",
92 def refresh_ui_keyframes():
94 for area
in bpy
.context
.screen
.areas
:
95 if area
.type in ('TIMELINE', 'GRAPH_EDITOR', 'DOPESHEET_EDITOR'):
101 def insert_key(data
, key
, group
=None):
103 if group
is not None:
104 data
.keyframe_insert(key
, group
=group
)
106 data
.keyframe_insert(key
)
111 def delete_key(data
, key
):
113 data
.keyframe_delete(key
)
118 def is_selected_vert_loop(data
, loop_i
):
119 """Get selection status of vertex corresponding to a loop"""
120 vertex_index
= data
.loops
[loop_i
].vertex_index
121 return data
.vertices
[vertex_index
].select
126 class VIEW3D_PT_animall(Panel
):
127 bl_space_type
= 'VIEW_3D'
128 bl_region_type
= 'UI'
129 bl_category
= "Animation"
133 def poll(self
, context
):
134 return context
.active_object
and context
.active_object
.type in {'MESH', 'LATTICE', 'CURVE', 'SURFACE'}
136 def draw_header(self
, context
):
140 row
.label (text
= 'AnimAll', icon
= 'ARMATURE_DATA')
142 def draw(self
, context
):
143 obj
= context
.active_object
144 animall_properties
= context
.scene
.animall_properties
148 layout
.label(text
='Key:')
150 layout
.use_property_split
= True
151 layout
.use_property_decorate
= False
153 if obj
.type == 'LATTICE':
154 col
= layout
.column(heading
="Points", align
=True)
155 col
.prop(animall_properties
, "key_point_location")
157 col
= layout
.column(heading
="Others", align
=True)
158 col
.prop(animall_properties
, "key_shape_key")
160 elif obj
.type == 'MESH':
161 col
= layout
.column(heading
="Points", align
=True)
162 col
.prop(animall_properties
, "key_point_location")
163 col
.prop(animall_properties
, "key_vertex_bevel", text
="Bevel")
164 col
.prop(animall_properties
, "key_vertex_group")
166 col
= layout
.column(heading
="Edges", align
=True)
167 col
.prop(animall_properties
, "key_edge_bevel", text
="Bevel")
168 col
.prop(animall_properties
, "key_edge_crease", text
="Crease")
170 col
= layout
.column(heading
="Faces", align
=True)
171 col
.prop(animall_properties
, "key_material_index")
173 col
= layout
.column(heading
="Others", align
=True)
174 col
.prop(animall_properties
, "key_attribute")
175 col
.prop(animall_properties
, "key_uvs")
176 col
.prop(animall_properties
, "key_shape_key")
178 # Vertex group update operator
179 if (obj
.data
.animation_data
is not None
180 and obj
.data
.animation_data
.action
is not None):
181 for fcurve
in context
.active_object
.data
.animation_data
.action
.fcurves
:
182 if fcurve
.data_path
.startswith("vertex_colors"):
183 col
= layout
.column(align
=True)
184 col
.label(text
="Object includes old-style vertex colors. Consider updating them.", icon
="ERROR")
185 col
.operator("anim.update_vertex_color_animation_animall", icon
="FILE_REFRESH")
188 elif obj
.type in {'CURVE', 'SURFACE'}:
189 col
= layout
.column(align
=True)
190 col
= layout
.column(heading
="Points", align
=True)
191 col
.prop(animall_properties
, "key_point_location")
192 col
.prop(animall_properties
, "key_radius")
193 col
.prop(animall_properties
, "key_tilt")
195 col
= layout
.column(heading
="Splines", align
=True)
196 col
.prop(animall_properties
, "key_material_index")
198 col
= layout
.column(heading
="Others", align
=True)
199 col
.prop(animall_properties
, "key_shape_key")
201 if animall_properties
.key_shape_key
:
202 shape_key
= obj
.active_shape_key
203 shape_key_index
= obj
.active_shape_key_index
205 if shape_key_index
> 0:
206 col
= layout
.column(align
=True)
207 row
= col
.row(align
=True)
208 row
.prop(shape_key
, "value", text
=shape_key
.name
, icon
="SHAPEKEY_DATA")
209 row
.prop(obj
, "show_only_shape_key", text
="")
210 if shape_key
.value
< 1:
211 col
.label(text
=iface_('Maybe set "%s" to 1.0?') % shape_key
.name
, icon
="INFO")
212 elif shape_key
is not None:
213 col
= layout
.column(align
=True)
214 col
.label(text
="Cannot key on Basis Shape", icon
="ERROR")
216 col
= layout
.column(align
=True)
217 col
.label(text
="No active Shape Key", icon
="ERROR")
219 if animall_properties
.key_point_location
:
220 col
.label(text
='"Location" and "Shape Key" are redundant?', icon
="INFO")
222 layout
.use_property_split
= False
225 row
.prop(animall_properties
, "key_selected")
227 row
= layout
.row(align
=True)
228 row
.operator("anim.insert_keyframe_animall", icon
="KEY_HLT")
229 row
.operator("anim.delete_keyframe_animall", icon
="KEY_DEHLT")
231 row
.operator("anim.clear_animation_animall", icon
="CANCEL")
234 class ANIM_OT_insert_keyframe_animall(Operator
):
235 bl_label
= "Insert Key"
236 bl_idname
= "anim.insert_keyframe_animall"
237 bl_description
= "Insert a Keyframe"
238 bl_options
= {'REGISTER', 'UNDO'}
240 def execute(self
, context
):
241 animall_properties
= context
.scene
.animall_properties
243 if context
.mode
== 'OBJECT':
244 objects
= context
.selected_objects
246 objects
= context
.objects_in_mode_unique_data
[:]
248 mode
= context
.object.mode
250 # Separate loop for lattices, curves and surfaces, since keyframe insertion
251 # has to happen in Edit Mode, otherwise points move back upon mode switch...
252 # (except for curve shape keys)
253 for obj
in [o
for o
in objects
if o
.type in {'CURVE', 'SURFACE', 'LATTICE'}]:
256 if obj
.type == 'LATTICE':
257 if animall_properties
.key_shape_key
:
258 if obj
.active_shape_key_index
> 0:
259 sk_name
= obj
.active_shape_key
.name
260 for p_i
, point
in enumerate(obj
.active_shape_key
.data
):
261 if not animall_properties
.key_selected
or data
.points
[p_i
].select
:
262 insert_key(point
, 'co', group
=data_("%s Point %s") % (sk_name
, p_i
))
264 if animall_properties
.key_point_location
:
265 for p_i
, point
in enumerate(data
.points
):
266 if not animall_properties
.key_selected
or point
.select
:
267 insert_key(point
, 'co_deform', group
=data_("Point %s") % p_i
)
270 if animall_properties
.key_material_index
:
271 for s_i
, spline
in enumerate(data
.splines
):
272 if (not animall_properties
.key_selected
273 or any(point
.select
for point
in spline
.points
)
274 or any(point
.select_control_point
for point
in spline
.bezier_points
)):
275 insert_key(spline
, 'material_index', group
=data_("Spline %s") % s_i
)
277 for s_i
, spline
in enumerate(data
.splines
):
278 if spline
.type == 'BEZIER':
279 for v_i
, CV
in enumerate(spline
.bezier_points
):
280 if (not animall_properties
.key_selected
281 or CV
.select_control_point
282 or CV
.select_left_handle
283 or CV
.select_right_handle
):
284 if animall_properties
.key_point_location
:
285 insert_key(CV
, 'co', group
=data_("Spline %s CV %s") % (s_i
, v_i
))
286 insert_key(CV
, 'handle_left', group
=data_("Spline %s CV %s") % (s_i
, v_i
))
287 insert_key(CV
, 'handle_right', group
=data_("Spline %s CV %s") % (s_i
, v_i
))
289 if animall_properties
.key_radius
:
290 insert_key(CV
, 'radius', group
=data_("Spline %s CV %s") % (s_i
, v_i
))
292 if animall_properties
.key_tilt
:
293 insert_key(CV
, 'tilt', group
=data_("Spline %s CV %s") % (s_i
, v_i
))
295 elif spline
.type in ('POLY', 'NURBS'):
296 for v_i
, CV
in enumerate(spline
.points
):
297 if not animall_properties
.key_selected
or CV
.select
:
298 if animall_properties
.key_point_location
:
299 insert_key(CV
, 'co', group
=data_("Spline %s CV %s") % (s_i
, v_i
))
301 if animall_properties
.key_radius
:
302 insert_key(CV
, 'radius', group
=data_("Spline %s CV %s") % (s_i
, v_i
))
304 if animall_properties
.key_tilt
:
305 insert_key(CV
, 'tilt', group
=data_("Spline %s CV %s") % (s_i
, v_i
))
307 bpy
.ops
.object.mode_set(mode
='OBJECT')
309 for obj
in [o
for o
in objects
if o
.type in {'MESH', 'CURVE', 'SURFACE'}]:
311 if obj
.type == 'MESH':
312 if animall_properties
.key_point_location
:
313 for v_i
, vert
in enumerate(data
.vertices
):
314 if not animall_properties
.key_selected
or vert
.select
:
315 insert_key(vert
, 'co', group
=data_("Vertex %s") % v_i
)
317 if animall_properties
.key_vertex_bevel
:
318 for v_i
, vert
in enumerate(data
.vertices
):
319 if not animall_properties
.key_selected
or vert
.select
:
320 insert_key(vert
, 'bevel_weight', group
=data_("Vertex %s") % v_i
)
321 # if animall_properties.key_vertex_crease:
322 # for v_i, vert in enumerate(data.vertices):
323 # if not animall_properties.key_selected or vert.select:
324 # insert_key(vert, 'crease', group=data_("Vertex %s") % v_i)
326 if animall_properties
.key_vertex_group
:
327 for v_i
, vert
in enumerate(data
.vertices
):
328 if not animall_properties
.key_selected
or vert
.select
:
329 for group
in vert
.groups
:
330 insert_key(group
, 'weight', group
=data_("Vertex %s") % v_i
)
332 if animall_properties
.key_edge_bevel
:
333 for e_i
, edge
in enumerate(data
.edges
):
334 if not animall_properties
.key_selected
or edge
.select
:
335 insert_key(edge
, 'bevel_weight', group
=data_("Edge %s") % e_i
)
337 if animall_properties
.key_edge_crease
:
338 for e_i
, edge
in enumerate(data
.edges
):
339 if not animall_properties
.key_selected
or edge
.select
:
340 insert_key(edge
, 'crease', group
=data_("Edge %s") % e_i
)
342 if animall_properties
.key_material_index
:
343 for p_i
, polygon
in enumerate(data
.polygons
):
344 if not animall_properties
.key_selected
or polygon
.select
:
345 insert_key(polygon
, 'material_index', group
=data_("Face %s") % p_i
)
347 if animall_properties
.key_attribute
:
348 if data
.attributes
.active
is not None:
349 attribute
= data
.attributes
.active
350 if attribute
.data_type
!= 'STRING':
351 # Cannot animate string attributes?
352 if attribute
.data_type
in {'FLOAT', 'INT', 'BOOLEAN', 'INT8'}:
353 attribute_key
= "value"
354 elif attribute
.data_type
in {'FLOAT_COLOR', 'BYTE_COLOR'}:
355 attribute_key
= "color"
356 elif attribute
.data_type
in {'FLOAT_VECTOR', 'FLOAT2'}:
357 attribute_key
= "vector"
359 if attribute
.domain
== 'POINT':
360 group
= data_("Vertex %s")
361 elif attribute
.domain
== 'EDGE':
362 group
= data_("Edge %s")
363 elif attribute
.domain
== 'FACE':
364 group
= data_("Face %s")
365 elif attribute
.domain
== 'CORNER':
366 group
= data_("Loop %s")
368 for e_i
, _attribute_data
in enumerate(attribute
.data
):
369 if (not animall_properties
.key_selected
370 or attribute
.domain
== 'POINT' and data
.vertices
[e_i
].select
371 or attribute
.domain
== 'EDGE' and data
.edges
[e_i
].select
372 or attribute
.domain
== 'FACE' and data
.polygons
[e_i
].select
373 or attribute
.domain
== 'CORNER' and is_selected_vert_loop(data
, e_i
)):
374 insert_key(data
, f
'attributes["{attribute.name}"].data[{e_i}].{attribute_key}',
377 if animall_properties
.key_uvs
:
378 if data
.uv_layers
.active
is not None:
379 for uv_i
, uv
in enumerate(data
.uv_layers
.active
.data
):
380 if not animall_properties
.key_selected
or uv
.select
:
381 insert_key(uv
, 'uv', group
=data_("UV layer %s") % uv_i
)
383 if animall_properties
.key_shape_key
:
384 if obj
.active_shape_key_index
> 0:
385 sk_name
= obj
.active_shape_key
.name
386 for v_i
, vert
in enumerate(obj
.active_shape_key
.data
):
387 if not animall_properties
.key_selected
or data
.vertices
[v_i
].select
:
388 insert_key(vert
, 'co', group
=data_("%s Vertex %s") % (sk_name
, v_i
))
390 elif obj
.type in {'CURVE', 'SURFACE'}:
391 # Shape key keys have to be inserted in object mode for curves...
392 if animall_properties
.key_shape_key
:
393 sk_name
= obj
.active_shape_key
.name
394 global_spline_index
= 0 # numbering for shape keys, which have flattened indices
395 for s_i
, spline
in enumerate(data
.splines
):
396 if spline
.type == 'BEZIER':
397 for v_i
, CV
in enumerate(spline
.bezier_points
):
398 if (not animall_properties
.key_selected
399 or CV
.select_control_point
400 or CV
.select_left_handle
401 or CV
.select_right_handle
):
402 if obj
.active_shape_key_index
> 0:
403 CV
= obj
.active_shape_key
.data
[global_spline_index
]
404 insert_key(CV
, 'co', group
=data_("%s Spline %s CV %s") % (sk_name
, s_i
, v_i
))
405 insert_key(CV
, 'handle_left', group
=data_("%s Spline %s CV %s") % (sk_name
, s_i
, v_i
))
406 insert_key(CV
, 'handle_right', group
=data_("%s Spline %s CV %s") % (sk_name
, s_i
, v_i
))
407 insert_key(CV
, 'radius', group
=data_("%s Spline %s CV %s") % (sk_name
, s_i
, v_i
))
408 insert_key(CV
, 'tilt', group
=data_("%s Spline %s CV %s") % (sk_name
, s_i
, v_i
))
409 global_spline_index
+= 1
411 elif spline
.type in ('POLY', 'NURBS'):
412 for v_i
, CV
in enumerate(spline
.points
):
413 if not animall_properties
.key_selected
or CV
.select
:
414 if obj
.active_shape_key_index
> 0:
415 CV
= obj
.active_shape_key
.data
[global_spline_index
]
416 insert_key(CV
, 'co', group
=data_("%s Spline %s CV %s") % (sk_name
, s_i
, v_i
))
417 insert_key(CV
, 'radius', group
=data_("%s Spline %s CV %s") % (sk_name
, s_i
, v_i
))
418 insert_key(CV
, 'tilt', group
=data_("%s Spline %s CV %s") % (sk_name
, s_i
, v_i
))
419 global_spline_index
+= 1
421 bpy
.ops
.object.mode_set(mode
=mode
)
422 refresh_ui_keyframes()
427 class ANIM_OT_delete_keyframe_animall(Operator
):
428 bl_label
= "Delete Key"
429 bl_idname
= "anim.delete_keyframe_animall"
430 bl_description
= "Delete a Keyframe"
431 bl_options
= {'REGISTER', 'UNDO'}
433 def execute(self
, context
):
434 animall_properties
= context
.scene
.animall_properties
436 if context
.mode
== 'OBJECT':
437 objects
= context
.selected_objects
439 objects
= context
.objects_in_mode_unique_data
[:]
441 mode
= context
.object.mode
445 if obj
.type == 'MESH':
446 bpy
.ops
.object.mode_set(mode
='OBJECT')
448 if animall_properties
.key_point_location
:
449 for vert
in data
.vertices
:
450 if not animall_properties
.key_selected
or vert
.select
:
451 delete_key(vert
, 'co')
453 if animall_properties
.key_vertex_bevel
:
454 for vert
in data
.vertices
:
455 if not animall_properties
.key_selected
or vert
.select
:
456 delete_key(vert
, 'bevel_weight')
458 if animall_properties
.key_vertex_group
:
459 for vert
in data
.vertices
:
460 if not animall_properties
.key_selected
or vert
.select
:
461 for group
in vert
.groups
:
462 delete_key(group
, 'weight')
464 # if animall_properties.key_vertex_crease:
465 # for vert in data.vertices:
466 # if not animall_properties.key_selected or vert.select:
467 # delete_key(vert, 'crease')
469 if animall_properties
.key_edge_bevel
:
470 for edge
in data
.edges
:
471 if not animall_properties
.key_selected
or edge
.select
:
472 delete_key(edge
, 'bevel_weight')
474 if animall_properties
.key_edge_crease
:
475 for edge
in data
.edges
:
476 if not animall_properties
.key_selected
or vert
.select
:
477 delete_key(edge
, 'crease')
479 if animall_properties
.key_shape_key
:
480 if obj
.active_shape_key
:
481 for v_i
, vert
in enumerate(obj
.active_shape_key
.data
):
482 if not animall_properties
.key_selected
or data
.vertices
[v_i
].select
:
483 delete_key(vert
, 'co')
485 if animall_properties
.key_uvs
:
486 if data
.uv_layers
.active
is not None:
487 for uv
in data
.uv_layers
.active
.data
:
488 if not animall_properties
.key_selected
or uv
.select
:
491 if animall_properties
.key_attribute
:
492 if data
.attributes
.active
is not None:
493 attribute
= data
.attributes
.active
494 if attribute
.data_type
!= 'STRING':
495 # Cannot animate string attributes?
496 if attribute
.data_type
in {'FLOAT', 'INT', 'BOOLEAN', 'INT8'}:
497 attribute_key
= "value"
498 elif attribute
.data_type
in {'FLOAT_COLOR', 'BYTE_COLOR'}:
499 attribute_key
= "color"
500 elif attribute
.data_type
in {'FLOAT_VECTOR', 'FLOAT2'}:
501 attribute_key
= "vector"
503 for e_i
, _attribute_data
in enumerate(attribute
.data
):
504 if (not animall_properties
.key_selected
505 or attribute
.domain
== 'POINT' and data
.vertices
[e_i
].select
506 or attribute
.domain
== 'EDGE' and data
.edges
[e_i
].select
507 or attribute
.domain
== 'FACE' and data
.polygons
[e_i
].select
508 or attribute
.domain
== 'CORNER' and is_selected_vert_loop(data
, e_i
)):
509 delete_key(data
, f
'attributes["{attribute.name}"].data[{e_i}].{attribute_key}')
511 bpy
.ops
.object.mode_set(mode
=mode
)
513 elif obj
.type == 'LATTICE':
514 if animall_properties
.key_shape_key
:
515 if obj
.active_shape_key
:
516 for point
in obj
.active_shape_key
.data
:
517 delete_key(point
, 'co')
519 if animall_properties
.key_point_location
:
520 for point
in data
.points
:
521 if not animall_properties
.key_selected
or point
.select
:
522 delete_key(point
, 'co_deform')
524 elif obj
.type in {'CURVE', 'SURFACE'}:
525 # Run this outside the splines loop (only once)
526 if animall_properties
.key_shape_key
:
527 if obj
.active_shape_key_index
> 0:
528 for CV
in obj
.active_shape_key
.data
:
530 delete_key(CV
, 'handle_left')
531 delete_key(CV
, 'handle_right')
533 for spline
in data
.splines
:
534 if spline
.type == 'BEZIER':
535 for CV
in spline
.bezier_points
:
536 if (not animall_properties
.key_selected
537 or CV
.select_control_point
538 or CV
.select_left_handle
539 or CV
.select_right_handle
):
540 if animall_properties
.key_point_location
:
542 delete_key(CV
, 'handle_left')
543 delete_key(CV
, 'handle_right')
544 if animall_properties
.key_radius
:
545 delete_key(CV
, 'radius')
546 if animall_properties
.key_tilt
:
547 delete_key(CV
, 'tilt')
549 elif spline
.type in ('POLY', 'NURBS'):
550 for CV
in spline
.points
:
551 if not animall_properties
.key_selected
or CV
.select
:
552 if animall_properties
.key_point_location
:
554 if animall_properties
.key_radius
:
555 delete_key(CV
, 'radius')
556 if animall_properties
.key_tilt
:
557 delete_key(CV
, 'tilt')
559 refresh_ui_keyframes()
564 class ANIM_OT_clear_animation_animall(Operator
):
565 bl_label
= "Clear Animation"
566 bl_idname
= "anim.clear_animation_animall"
567 bl_description
= ("Delete all keyframes for this object\n"
568 "If in a specific case it doesn't work\n"
569 "try to delete the keys manually")
570 bl_options
= {'REGISTER', 'UNDO'}
572 def invoke(self
, context
, event
):
573 wm
= context
.window_manager
574 return wm
.invoke_confirm(self
, event
)
576 def execute(self
, context
):
577 if context
.mode
== 'OBJECT':
578 objects
= context
.selected_objects
580 objects
= context
.objects_in_mode_unique_data
585 data
.animation_data_clear()
587 self
.report({'WARNING'}, "Clear Animation could not be performed")
590 refresh_ui_keyframes()
595 class ANIM_OT_update_vertex_color_animation_animall(Operator
):
596 bl_label
= "Update Vertex Color Animation"
597 bl_idname
= "anim.update_vertex_color_animation_animall"
598 bl_description
= "Update old vertex color channel formats from pre-3.3 versions"
599 bl_options
= {'REGISTER', 'UNDO'}
602 def poll(self
, context
):
603 if (context
.active_object
is None
604 or context
.active_object
.type != 'MESH'
605 or context
.active_object
.data
.animation_data
is None
606 or context
.active_object
.data
.animation_data
.action
is None):
608 for fcurve
in context
.active_object
.data
.animation_data
.action
.fcurves
:
609 if fcurve
.data_path
.startswith("vertex_colors"):
612 def execute(self
, context
):
613 for fcurve
in context
.active_object
.data
.animation_data
.action
.fcurves
:
614 if fcurve
.data_path
.startswith("vertex_colors"):
615 fcurve
.data_path
= fcurve
.data_path
.replace("vertex_colors", "attributes")
618 # Add-ons Preferences Update Panel
620 # Define Panel classes for updating
626 def update_panel(self
, context
):
627 message
= "AnimAll: Updating Panel locations has failed"
630 if "bl_rna" in panel
.__dict
__:
631 bpy
.utils
.unregister_class(panel
)
634 panel
.bl_category
= context
.preferences
.addons
[__name__
].preferences
.category
635 bpy
.utils
.register_class(panel
)
637 except Exception as e
:
638 print("\n[{}]\n{}\n\nError:\n{}".format(__name__
, message
, e
))
642 class AnimallAddonPreferences(AddonPreferences
):
643 # this must match the addon name, use '__package__'
644 # when defining this in a submodule of a python package.
647 category
: StringProperty(
649 description
="Choose a name for the category of the panel",
654 def draw(self
, context
):
659 col
.label(text
="Tab Category:")
660 col
.prop(self
, "category", text
="")
662 register_classes
, unregister_classes
= bpy
.utils
.register_classes_factory(
663 (AnimallProperties
, VIEW3D_PT_animall
, ANIM_OT_insert_keyframe_animall
,
664 ANIM_OT_delete_keyframe_animall
, ANIM_OT_clear_animation_animall
,
665 ANIM_OT_update_vertex_color_animation_animall
, AnimallAddonPreferences
))
669 bpy
.types
.Scene
.animall_properties
= bpy
.props
.PointerProperty(type=AnimallProperties
)
670 update_panel(None, bpy
.context
)
671 bpy
.app
.translations
.register(__name__
, translations
.translations_dict
)
674 bpy
.app
.translations
.unregister(__name__
)
675 del bpy
.types
.Scene
.animall_properties
678 if __name__
== "__main__":