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
27 # Property Definitions
28 class AnimallProperties(bpy
.types
.PropertyGroup
):
29 key_selected
: BoolProperty(
30 name
="Key Selected Only",
31 description
="Insert keyframes only on selected elements",
35 key_point_location
: BoolProperty(
37 description
="Insert keyframes on point locations",
39 key_shape_key
: BoolProperty(
41 description
="Insert keyframes on active Shape Key layer",
43 key_material_index
: BoolProperty(
44 name
="Material Index",
45 description
="Insert keyframes on face material indices",
49 key_vertex_bevel
: BoolProperty(
51 description
="Insert keyframes on vertex bevel weight",
54 key_vertex_crease
: BoolProperty(
56 description
="Insert keyframes on vertex crease weight",
59 key_vertex_group
: BoolProperty(
61 description
="Insert keyframes on active vertex group values",
64 key_edge_bevel
: BoolProperty(
66 description
="Insert keyframes on edge bevel weight",
68 key_edge_crease
: BoolProperty(
70 description
="Insert keyframes on edge creases",
73 key_active_attribute
: BoolProperty(
74 name
="Active Attribute",
75 description
="Insert keyframes on active attribute values",
77 key_uvs
: BoolProperty(
79 description
="Insert keyframes on active UV coordinates",
82 # Curve and surface attributes
83 key_radius
: BoolProperty(
85 description
="Insert keyframes on point radius (Shrink/Fatten)",
87 key_tilt
: BoolProperty(
89 description
="Insert keyframes on point tilt",
95 def refresh_ui_keyframes():
97 for area
in bpy
.context
.screen
.areas
:
98 if area
.type in ('TIMELINE', 'GRAPH_EDITOR', 'DOPESHEET_EDITOR'):
104 def insert_key(data
, key
, group
=None):
106 if group
is not None:
107 data
.keyframe_insert(key
, group
=group
)
109 data
.keyframe_insert(key
)
114 def delete_key(data
, key
):
116 data
.keyframe_delete(key
)
121 def get_attribute(data
, name
, type=None, domain
=None):
122 if name
in data
.attributes
:
123 return data
.attributes
[name
]
124 if type is not None and domain
is not None:
125 return data
.attributes
.new(name
, type, domain
)
128 def get_attribute_paths(data
, attribute
, key_selected
):
129 # Cannot animate string attributes?
130 if attribute
.data_type
== 'STRING':
133 if attribute
.data_type
in {'FLOAT', 'INT', 'BOOLEAN', 'INT8'}:
134 attribute_key
= "value"
135 elif attribute
.data_type
in {'FLOAT_COLOR', 'BYTE_COLOR'}:
136 attribute_key
= "color"
137 elif attribute
.data_type
in {'FLOAT_VECTOR', 'FLOAT2'}:
138 attribute_key
= "vector"
140 if attribute
.domain
== 'POINT':
141 group
= data_("Vertex %s")
142 elif attribute
.domain
== 'EDGE':
143 group
= data_("Edge %s")
144 elif attribute
.domain
== 'FACE':
145 group
= data_("Face %s")
146 elif attribute
.domain
== 'CORNER':
147 group
= data_("Loop %s")
149 for e_i
, _attribute_data
in enumerate(attribute
.data
):
151 or attribute
.domain
== 'POINT' and data
.vertices
[e_i
].select
152 or attribute
.domain
== 'EDGE' and data
.edges
[e_i
].select
153 or attribute
.domain
== 'FACE' and data
.polygons
[e_i
].select
154 or attribute
.domain
== 'CORNER' and is_selected_vert_loop(data
, e_i
)):
155 yield (f
'attributes["{attribute.name}"].data[{e_i}].{attribute_key}', group
% e_i
)
158 def insert_attribute_key(data
, attribute
, key_selected
):
159 for path
, group
in get_attribute_paths(data
, attribute
, key_selected
):
161 insert_key(data
, path
, group
=group
)
164 def delete_attribute_key(data
, attribute
, key_selected
):
165 for path
, group
in get_attribute_paths(data
, attribute
, key_selected
):
167 delete_key(data
, path
)
170 def is_selected_vert_loop(data
, loop_i
):
171 """Get selection status of vertex corresponding to a loop"""
172 vertex_index
= data
.loops
[loop_i
].vertex_index
173 return data
.vertices
[vertex_index
].select
178 class VIEW3D_PT_animall(Panel
):
179 bl_space_type
= 'VIEW_3D'
180 bl_region_type
= 'UI'
181 bl_category
= "Animation"
185 def poll(self
, context
):
186 return context
.active_object
and context
.active_object
.type in {'MESH', 'LATTICE', 'CURVE', 'SURFACE'}
188 def draw_header(self
, context
):
192 row
.label (text
= 'AnimAll', icon
= 'ARMATURE_DATA')
194 def draw(self
, context
):
195 obj
= context
.active_object
196 animall_properties
= context
.scene
.animall_properties
200 layout
.label(text
='Key:')
202 layout
.use_property_split
= True
203 layout
.use_property_decorate
= False
205 if obj
.type == 'LATTICE':
206 col
= layout
.column(heading
="Points", align
=True)
207 col
.prop(animall_properties
, "key_point_location")
209 col
= layout
.column(heading
="Others", align
=True)
210 col
.prop(animall_properties
, "key_shape_key")
212 elif obj
.type == 'MESH':
213 col
= layout
.column(heading
="Points", align
=True)
214 col
.prop(animall_properties
, "key_point_location")
215 col
.prop(animall_properties
, "key_vertex_bevel", text
="Bevel")
216 col
.prop(animall_properties
, "key_vertex_crease", text
="Crease")
217 col
.prop(animall_properties
, "key_vertex_group")
219 col
= layout
.column(heading
="Edges", align
=True)
220 col
.prop(animall_properties
, "key_edge_bevel", text
="Bevel")
221 col
.prop(animall_properties
, "key_edge_crease", text
="Crease")
223 col
= layout
.column(heading
="Faces", align
=True)
224 col
.prop(animall_properties
, "key_material_index")
226 col
= layout
.column(heading
="Others", align
=True)
227 col
.prop(animall_properties
, "key_active_attribute")
228 col
.prop(animall_properties
, "key_uvs")
229 col
.prop(animall_properties
, "key_shape_key")
231 # Vertex group update operator
232 if (obj
.data
.animation_data
is not None
233 and obj
.data
.animation_data
.action
is not None):
234 for fcurve
in context
.active_object
.data
.animation_data
.action
.fcurves
:
235 if bpy
.ops
.anim
.update_attribute_animation_animall
.poll():
236 col
= layout
.column(align
=True)
237 col
.label(text
="Object includes old-style attributes. Consider updating them.", icon
="ERROR")
238 col
.operator("anim.update_attribute_animation_animall", icon
="FILE_REFRESH")
241 elif obj
.type in {'CURVE', 'SURFACE'}:
242 col
= layout
.column(align
=True)
243 col
= layout
.column(heading
="Points", align
=True)
244 col
.prop(animall_properties
, "key_point_location")
245 col
.prop(animall_properties
, "key_radius")
246 col
.prop(animall_properties
, "key_tilt")
248 col
= layout
.column(heading
="Splines", align
=True)
249 col
.prop(animall_properties
, "key_material_index")
251 col
= layout
.column(heading
="Others", align
=True)
252 col
.prop(animall_properties
, "key_shape_key")
254 if animall_properties
.key_shape_key
:
255 shape_key
= obj
.active_shape_key
256 shape_key_index
= obj
.active_shape_key_index
258 if shape_key_index
> 0:
259 col
= layout
.column(align
=True)
260 row
= col
.row(align
=True)
261 row
.prop(shape_key
, "value", text
=shape_key
.name
, icon
="SHAPEKEY_DATA")
262 row
.prop(obj
, "show_only_shape_key", text
="")
263 if shape_key
.value
< 1:
264 col
.label(text
=iface_('Maybe set "%s" to 1.0?') % shape_key
.name
, icon
="INFO")
265 elif shape_key
is not None:
266 col
= layout
.column(align
=True)
267 col
.label(text
="Cannot key on Basis Shape", icon
="ERROR")
269 col
= layout
.column(align
=True)
270 col
.label(text
="No active Shape Key", icon
="ERROR")
272 if animall_properties
.key_point_location
:
273 col
.label(text
='"Location" and "Shape Key" are redundant?', icon
="INFO")
275 layout
.use_property_split
= False
278 row
.prop(animall_properties
, "key_selected")
280 row
= layout
.row(align
=True)
281 row
.operator("anim.insert_keyframe_animall", icon
="KEY_HLT")
282 row
.operator("anim.delete_keyframe_animall", icon
="KEY_DEHLT")
284 row
.operator("anim.clear_animation_animall", icon
="CANCEL")
287 class ANIM_OT_insert_keyframe_animall(Operator
):
288 bl_label
= "Insert Key"
289 bl_idname
= "anim.insert_keyframe_animall"
290 bl_description
= "Insert a Keyframe"
291 bl_options
= {'REGISTER', 'UNDO'}
293 def execute(self
, context
):
294 animall_properties
= context
.scene
.animall_properties
296 if context
.mode
== 'OBJECT':
297 objects
= context
.selected_objects
299 objects
= context
.objects_in_mode_unique_data
[:]
301 mode
= context
.object.mode
303 # Separate loop for lattices, curves and surfaces, since keyframe insertion
304 # has to happen in Edit Mode, otherwise points move back upon mode switch...
305 # (except for curve shape keys)
306 for obj
in [o
for o
in objects
if o
.type in {'CURVE', 'SURFACE', 'LATTICE'}]:
309 if obj
.type == 'LATTICE':
310 if animall_properties
.key_shape_key
:
311 if obj
.active_shape_key_index
> 0:
312 sk_name
= obj
.active_shape_key
.name
313 for p_i
, point
in enumerate(obj
.active_shape_key
.data
):
314 if not animall_properties
.key_selected
or data
.points
[p_i
].select
:
315 insert_key(point
, 'co', group
=data_("%s Point %s") % (sk_name
, p_i
))
317 if animall_properties
.key_point_location
:
318 for p_i
, point
in enumerate(data
.points
):
319 if not animall_properties
.key_selected
or point
.select
:
320 insert_key(point
, 'co_deform', group
=data_("Point %s") % p_i
)
323 if animall_properties
.key_material_index
:
324 for s_i
, spline
in enumerate(data
.splines
):
325 if (not animall_properties
.key_selected
326 or any(point
.select
for point
in spline
.points
)
327 or any(point
.select_control_point
for point
in spline
.bezier_points
)):
328 insert_key(spline
, 'material_index', group
=data_("Spline %s") % s_i
)
330 for s_i
, spline
in enumerate(data
.splines
):
331 if spline
.type == 'BEZIER':
332 for v_i
, CV
in enumerate(spline
.bezier_points
):
333 if (not animall_properties
.key_selected
334 or CV
.select_control_point
335 or CV
.select_left_handle
336 or CV
.select_right_handle
):
337 if animall_properties
.key_point_location
:
338 insert_key(CV
, 'co', group
=data_("Spline %s CV %s") % (s_i
, v_i
))
339 insert_key(CV
, 'handle_left', group
=data_("Spline %s CV %s") % (s_i
, v_i
))
340 insert_key(CV
, 'handle_right', group
=data_("Spline %s CV %s") % (s_i
, v_i
))
342 if animall_properties
.key_radius
:
343 insert_key(CV
, 'radius', group
=data_("Spline %s CV %s") % (s_i
, v_i
))
345 if animall_properties
.key_tilt
:
346 insert_key(CV
, 'tilt', group
=data_("Spline %s CV %s") % (s_i
, v_i
))
348 elif spline
.type in ('POLY', 'NURBS'):
349 for v_i
, CV
in enumerate(spline
.points
):
350 if not animall_properties
.key_selected
or CV
.select
:
351 if animall_properties
.key_point_location
:
352 insert_key(CV
, 'co', group
=data_("Spline %s CV %s") % (s_i
, v_i
))
354 if animall_properties
.key_radius
:
355 insert_key(CV
, 'radius', group
=data_("Spline %s CV %s") % (s_i
, v_i
))
357 if animall_properties
.key_tilt
:
358 insert_key(CV
, 'tilt', group
=data_("Spline %s CV %s") % (s_i
, v_i
))
360 bpy
.ops
.object.mode_set(mode
='OBJECT')
362 for obj
in [o
for o
in objects
if o
.type in {'MESH', 'CURVE', 'SURFACE'}]:
364 if obj
.type == 'MESH':
365 if animall_properties
.key_point_location
:
366 for v_i
, vert
in enumerate(data
.vertices
):
367 if not animall_properties
.key_selected
or vert
.select
:
368 insert_key(vert
, 'co', group
=data_("Vertex %s") % v_i
)
370 if animall_properties
.key_vertex_bevel
:
371 attribute
= get_attribute(data
, "bevel_weight_vert", 'FLOAT', 'POINT')
372 insert_attribute_key(data
, attribute
, animall_properties
.key_selected
)
374 if animall_properties
.key_vertex_crease
:
375 attribute
= get_attribute(data
, "crease_vert", 'FLOAT', 'POINT')
376 insert_attribute_key(data
, attribute
, animall_properties
.key_selected
)
378 if animall_properties
.key_vertex_group
:
379 for v_i
, vert
in enumerate(data
.vertices
):
380 if not animall_properties
.key_selected
or vert
.select
:
381 for group
in vert
.groups
:
382 insert_key(group
, 'weight', group
=data_("Vertex %s") % v_i
)
384 if animall_properties
.key_edge_bevel
:
385 attribute
= get_attribute(data
, "bevel_weight_edge", 'FLOAT', 'EDGE')
386 insert_attribute_key(data
, attribute
, animall_properties
.key_selected
)
388 if animall_properties
.key_edge_crease
:
389 attribute
= get_attribute(data
, "crease_edge", 'FLOAT', 'EDGE')
390 insert_attribute_key(data
, attribute
, animall_properties
.key_selected
)
392 if animall_properties
.key_material_index
:
393 for p_i
, polygon
in enumerate(data
.polygons
):
394 if not animall_properties
.key_selected
or polygon
.select
:
395 insert_key(polygon
, 'material_index', group
=data_("Face %s") % p_i
)
397 if animall_properties
.key_active_attribute
:
398 if data
.attributes
.active
is not None:
399 for path
, group
in get_attribute_paths(
400 data
, data
.attributes
.active
,
401 animall_properties
.key_selected
):
403 insert_key(data
, path
, group
=group
)
405 if animall_properties
.key_uvs
:
406 if data
.uv_layers
.active
is not None:
407 for uv_i
, uv
in enumerate(data
.uv_layers
.active
.data
):
408 if not animall_properties
.key_selected
or uv
.select
:
409 insert_key(uv
, 'uv', group
=data_("UV layer %s") % uv_i
)
411 if animall_properties
.key_shape_key
:
412 if obj
.active_shape_key_index
> 0:
413 sk_name
= obj
.active_shape_key
.name
414 for v_i
, vert
in enumerate(obj
.active_shape_key
.data
):
415 if not animall_properties
.key_selected
or data
.vertices
[v_i
].select
:
416 insert_key(vert
, 'co', group
=data_("%s Vertex %s") % (sk_name
, v_i
))
418 elif obj
.type in {'CURVE', 'SURFACE'}:
419 # Shape key keys have to be inserted in object mode for curves...
420 if animall_properties
.key_shape_key
:
421 sk_name
= obj
.active_shape_key
.name
422 global_spline_index
= 0 # numbering for shape keys, which have flattened indices
423 for s_i
, spline
in enumerate(data
.splines
):
424 if spline
.type == 'BEZIER':
425 for v_i
, CV
in enumerate(spline
.bezier_points
):
426 if (not animall_properties
.key_selected
427 or CV
.select_control_point
428 or CV
.select_left_handle
429 or CV
.select_right_handle
):
430 if obj
.active_shape_key_index
> 0:
431 CV
= obj
.active_shape_key
.data
[global_spline_index
]
432 insert_key(CV
, 'co', group
=data_("%s Spline %s CV %s") % (sk_name
, s_i
, v_i
))
433 insert_key(CV
, 'handle_left', group
=data_("%s Spline %s CV %s") % (sk_name
, s_i
, v_i
))
434 insert_key(CV
, 'handle_right', group
=data_("%s Spline %s CV %s") % (sk_name
, s_i
, v_i
))
435 insert_key(CV
, 'radius', group
=data_("%s Spline %s CV %s") % (sk_name
, s_i
, v_i
))
436 insert_key(CV
, 'tilt', group
=data_("%s Spline %s CV %s") % (sk_name
, s_i
, v_i
))
437 global_spline_index
+= 1
439 elif spline
.type in ('POLY', 'NURBS'):
440 for v_i
, CV
in enumerate(spline
.points
):
441 if not animall_properties
.key_selected
or CV
.select
:
442 if obj
.active_shape_key_index
> 0:
443 CV
= obj
.active_shape_key
.data
[global_spline_index
]
444 insert_key(CV
, 'co', group
=data_("%s Spline %s CV %s") % (sk_name
, s_i
, v_i
))
445 insert_key(CV
, 'radius', group
=data_("%s Spline %s CV %s") % (sk_name
, s_i
, v_i
))
446 insert_key(CV
, 'tilt', group
=data_("%s Spline %s CV %s") % (sk_name
, s_i
, v_i
))
447 global_spline_index
+= 1
449 bpy
.ops
.object.mode_set(mode
=mode
)
450 refresh_ui_keyframes()
455 class ANIM_OT_delete_keyframe_animall(Operator
):
456 bl_label
= "Delete Key"
457 bl_idname
= "anim.delete_keyframe_animall"
458 bl_description
= "Delete a Keyframe"
459 bl_options
= {'REGISTER', 'UNDO'}
461 def execute(self
, context
):
462 animall_properties
= context
.scene
.animall_properties
464 if context
.mode
== 'OBJECT':
465 objects
= context
.selected_objects
467 objects
= context
.objects_in_mode_unique_data
[:]
469 mode
= context
.object.mode
473 if obj
.type == 'MESH':
474 bpy
.ops
.object.mode_set(mode
='OBJECT')
476 if animall_properties
.key_point_location
:
477 for vert
in data
.vertices
:
478 if not animall_properties
.key_selected
or vert
.select
:
479 delete_key(vert
, 'co')
481 if animall_properties
.key_vertex_bevel
:
482 attribute
= get_attribute(data
, "bevel_weight_vert", 'FLOAT', 'POINT')
483 if attribute
is not None:
484 delete_attribute_key(data
, attribute
, animall_properties
.key_selected
)
486 if animall_properties
.key_vertex_crease
:
487 attribute
= get_attribute(data
, "crease_vert", 'FLOAT', 'POINT')
488 if attribute
is not None:
489 delete_attribute_key(data
, attribute
, animall_properties
.key_selected
)
491 if animall_properties
.key_vertex_group
:
492 for vert
in data
.vertices
:
493 if not animall_properties
.key_selected
or vert
.select
:
494 for group
in vert
.groups
:
495 delete_key(group
, 'weight')
497 if animall_properties
.key_edge_bevel
:
498 attribute
= get_attribute(data
, "bevel_weight_edge", 'FLOAT', 'EDGE')
499 if attribute
is not None:
500 delete_attribute_key(data
, attribute
, animall_properties
.key_selected
)
502 if animall_properties
.key_edge_crease
:
503 attribute
= get_attribute(data
, "crease_edge", 'FLOAT', 'EDGE')
504 if attribute
is not None:
505 delete_attribute_key(data
, attribute
, animall_properties
.key_selected
)
507 if animall_properties
.key_material_index
:
508 for p_i
, polygon
in enumerate(data
.polygons
):
509 if not animall_properties
.key_selected
or polygon
.select
:
510 delete_key(polygon
, 'material_index')
512 if animall_properties
.key_shape_key
:
513 if obj
.active_shape_key
:
514 for v_i
, vert
in enumerate(obj
.active_shape_key
.data
):
515 if not animall_properties
.key_selected
or data
.vertices
[v_i
].select
:
516 delete_key(vert
, 'co')
518 if animall_properties
.key_uvs
:
519 if data
.uv_layers
.active
is not None:
520 for uv
in data
.uv_layers
.active
.data
:
521 if not animall_properties
.key_selected
or uv
.select
:
524 if animall_properties
.key_active_attribute
:
525 if data
.attributes
.active
is not None:
526 for path
, _group
in get_attribute_paths(
527 data
, data
.attributes
.active
,
528 animall_properties
.key_selected
):
530 delete_key(data
, path
)
532 bpy
.ops
.object.mode_set(mode
=mode
)
534 elif obj
.type == 'LATTICE':
535 if animall_properties
.key_shape_key
:
536 if obj
.active_shape_key
:
537 for point
in obj
.active_shape_key
.data
:
538 delete_key(point
, 'co')
540 if animall_properties
.key_point_location
:
541 for point
in data
.points
:
542 if not animall_properties
.key_selected
or point
.select
:
543 delete_key(point
, 'co_deform')
545 elif obj
.type in {'CURVE', 'SURFACE'}:
546 # Run this outside the splines loop (only once)
547 if animall_properties
.key_shape_key
:
548 if obj
.active_shape_key_index
> 0:
549 for CV
in obj
.active_shape_key
.data
:
551 delete_key(CV
, 'handle_left')
552 delete_key(CV
, 'handle_right')
554 for spline
in data
.splines
:
555 if spline
.type == 'BEZIER':
556 for CV
in spline
.bezier_points
:
557 if (not animall_properties
.key_selected
558 or CV
.select_control_point
559 or CV
.select_left_handle
560 or CV
.select_right_handle
):
561 if animall_properties
.key_point_location
:
563 delete_key(CV
, 'handle_left')
564 delete_key(CV
, 'handle_right')
565 if animall_properties
.key_radius
:
566 delete_key(CV
, 'radius')
567 if animall_properties
.key_tilt
:
568 delete_key(CV
, 'tilt')
570 elif spline
.type in ('POLY', 'NURBS'):
571 for CV
in spline
.points
:
572 if not animall_properties
.key_selected
or CV
.select
:
573 if animall_properties
.key_point_location
:
575 if animall_properties
.key_radius
:
576 delete_key(CV
, 'radius')
577 if animall_properties
.key_tilt
:
578 delete_key(CV
, 'tilt')
580 refresh_ui_keyframes()
585 class ANIM_OT_clear_animation_animall(Operator
):
586 bl_label
= "Clear Animation"
587 bl_idname
= "anim.clear_animation_animall"
588 bl_description
= ("Delete all keyframes for this object\n"
589 "If in a specific case it doesn't work\n"
590 "try to delete the keys manually")
591 bl_options
= {'REGISTER', 'UNDO'}
593 def invoke(self
, context
, event
):
594 wm
= context
.window_manager
595 return wm
.invoke_confirm(self
, event
)
597 def execute(self
, context
):
598 if context
.mode
== 'OBJECT':
599 objects
= context
.selected_objects
601 objects
= context
.objects_in_mode_unique_data
606 data
.animation_data_clear()
608 self
.report({'WARNING'}, "Clear Animation could not be performed")
611 refresh_ui_keyframes()
616 class ANIM_OT_update_attribute_animation_animall(Operator
):
617 bl_label
= "Update Attribute Animation"
618 bl_idname
= "anim.update_attribute_animation_animall"
619 bl_description
= "Update attributes from the old format"
620 bl_options
= {'REGISTER', 'UNDO'}
622 path_re
= re
.compile(r
"^vertex_colors|(vertices|edges)\[([0-9]+)\]\.(bevel_weight|crease)")
624 ("vertices", "bevel_weight"): ("bevel_weight_vert", "FLOAT", "POINT"),
625 ("edges", "bevel_weight"): ("bevel_weight_edge", "FLOAT", "POINT"),
626 ("vertices", "crease"): ("crease_vert", "FLOAT", "EDGE"),
627 ("edges", "crease"): ("crease_edge", "FLOAT", "EDGE"),
631 def poll(self
, context
):
632 if (context
.active_object
is None
633 or context
.active_object
.type != 'MESH'
634 or context
.active_object
.data
.animation_data
is None
635 or context
.active_object
.data
.animation_data
.action
is None):
637 for fcurve
in context
.active_object
.data
.animation_data
.action
.fcurves
:
638 if self
.path_re
.match(fcurve
.data_path
):
641 def execute(self
, context
):
642 for fcurve
in context
.active_object
.data
.animation_data
.action
.fcurves
:
643 if fcurve
.data_path
.startswith("vertex_colors"):
644 # Update pre-3.3 vertex colors
645 fcurve
.data_path
= fcurve
.data_path
.replace("vertex_colors", "attributes")
647 # Update pre-4.0 attributes
648 match
= self
.path_re
.match(fcurve
.data_path
)
651 domain
, index
, src_attribute
= match
.groups()
652 attribute
, type, domain
= self
.attribute_map
[(domain
, src_attribute
)]
653 get_attribute(context
.active_object
.data
, attribute
, type, domain
)
654 fcurve
.data_path
= f
'attributes["{attribute}"].data[{index}].value'
657 # Add-ons Preferences Update Panel
659 # Define Panel classes for updating
660 panels
= [VIEW3D_PT_animall
]
663 def update_panel(self
, context
):
664 message
= "AnimAll: Updating Panel locations has failed"
667 if "bl_rna" in panel
.__dict
__:
668 bpy
.utils
.unregister_class(panel
)
671 panel
.bl_category
= context
.preferences
.addons
[__name__
].preferences
.category
672 bpy
.utils
.register_class(panel
)
674 except Exception as e
:
675 print("\n[{}]\n{}\n\nError:\n{}".format(__name__
, message
, e
))
679 class AnimallAddonPreferences(AddonPreferences
):
680 # this must match the addon name, use '__package__'
681 # when defining this in a submodule of a python package.
684 category
: StringProperty(
686 description
="Choose a name for the category of the panel",
691 def draw(self
, context
):
696 col
.label(text
="Tab Category:")
697 col
.prop(self
, "category", text
="")
699 register_classes
, unregister_classes
= bpy
.utils
.register_classes_factory(
700 (AnimallProperties
, VIEW3D_PT_animall
, ANIM_OT_insert_keyframe_animall
,
701 ANIM_OT_delete_keyframe_animall
, ANIM_OT_clear_animation_animall
,
702 ANIM_OT_update_attribute_animation_animall
, AnimallAddonPreferences
))
706 bpy
.types
.Scene
.animall_properties
= bpy
.props
.PointerProperty(type=AnimallProperties
)
707 update_panel(None, bpy
.context
)
708 bpy
.app
.translations
.register(__name__
, translations
.translations_dict
)
711 bpy
.app
.translations
.unregister(__name__
)
712 del bpy
.types
.Scene
.animall_properties
715 if __name__
== "__main__":