Fix uilists showing data names translated (reported on bf-translations ML by Satoshi...
[blender.git] / release / scripts / startup / keyingsets_builtins.py
1 # ##### BEGIN GPL LICENSE BLOCK #####
2 #
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.
7 #
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.
12 #
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.
16 #
17 # ##### END GPL LICENSE BLOCK #####
18
19 # <pep8 compliant>
20
21 """
22 Built-In Keying Sets
23 None of these Keying Sets should be removed, as these
24 are needed by various parts of Blender in order for them
25 to work correctly.
26
27 Beware also about changing the order that these are defined
28 here, since this can result in old files referring to the
29 wrong Keying Set as the active one, potentially resulting
30 in lost (i.e. unkeyed) animation.
31 """
32
33 import bpy
34 import keyingsets_utils
35 from bpy.types import KeyingSetInfo
36
37 ###############################
38 # Built-In KeyingSets
39
40
41 # "Defines"
42 # Keep these in sync with those in ED_keyframing.h!
43 ANIM_KS_LOCATION_ID = "Location"
44 ANIM_KS_ROTATION_ID = "Rotation"
45 ANIM_KS_SCALING_ID = "Scaling"
46 ANIM_KS_LOC_ROT_SCALE_ID = "LocRotScale"
47 ANIM_KS_AVAILABLE_ID = "Available"
48 ANIM_KS_WHOLE_CHARACTER_ID = "WholeCharacter"
49
50
51 # Location
52 class BUILTIN_KSI_Location(KeyingSetInfo):
53     """Insert a keyframe on each of the location channels"""
54     bl_idname = ANIM_KS_LOCATION_ID
55     bl_label = "Location"
56
57     # poll - use predefined callback for selected bones/objects
58     poll = keyingsets_utils.RKS_POLL_selected_items
59
60     # iterator - use callback for selected bones/objects
61     iterator = keyingsets_utils.RKS_ITER_selected_item
62
63     # generator - use callback for location
64     generate = keyingsets_utils.RKS_GEN_location
65
66
67 # Rotation
68 class BUILTIN_KSI_Rotation(KeyingSetInfo):
69     """Insert a keyframe on each of the rotation channels"""
70     bl_idname = ANIM_KS_ROTATION_ID
71     bl_label = "Rotation"
72
73     # poll - use predefined callback for selected bones/objects
74     poll = keyingsets_utils.RKS_POLL_selected_items
75
76     # iterator - use callback for selected bones/objects
77     iterator = keyingsets_utils.RKS_ITER_selected_item
78
79     # generator - use callback for rotation
80     generate = keyingsets_utils.RKS_GEN_rotation
81
82
83 # Scale
84 class BUILTIN_KSI_Scaling(KeyingSetInfo):
85     """Insert a keyframe on each of the scale channels"""
86     bl_idname = ANIM_KS_SCALING_ID
87     bl_label = "Scaling"
88
89     # poll - use predefined callback for selected bones/objects
90     poll = keyingsets_utils.RKS_POLL_selected_items
91
92     # iterator - use callback for selected bones/objects
93     iterator = keyingsets_utils.RKS_ITER_selected_item
94
95     # generator - use callback for scaling
96     generate = keyingsets_utils.RKS_GEN_scaling
97
98 # ------------
99
100
101 # LocRot
102 class BUILTIN_KSI_LocRot(KeyingSetInfo):
103     """Insert a keyframe on each of the location and rotation channels"""
104     bl_label = "LocRot"
105
106     # poll - use predefined callback for selected bones/objects
107     poll = keyingsets_utils.RKS_POLL_selected_items
108
109     # iterator - use callback for selected bones/objects
110     iterator = keyingsets_utils.RKS_ITER_selected_item
111
112     # generator
113     def generate(self, context, ks, data):
114         # location
115         keyingsets_utils.RKS_GEN_location(self, context, ks, data)
116         # rotation
117         keyingsets_utils.RKS_GEN_rotation(self, context, ks, data)
118
119
120 # LocScale
121 class BUILTIN_KSI_LocScale(KeyingSetInfo):
122     """Insert a keyframe on each of the location and scale channels"""
123     bl_label = "LocScale"
124
125     # poll - use predefined callback for selected bones/objects
126     poll = keyingsets_utils.RKS_POLL_selected_items
127
128     # iterator - use callback for selected bones/objects
129     iterator = keyingsets_utils.RKS_ITER_selected_item
130
131     # generator
132     def generate(self, context, ks, data):
133         # location
134         keyingsets_utils.RKS_GEN_location(self, context, ks, data)
135         # scale
136         keyingsets_utils.RKS_GEN_scaling(self, context, ks, data)
137
138
139 # LocRotScale
140 class BUILTIN_KSI_LocRotScale(KeyingSetInfo):
141     """
142     Insert a keyframe on each of the location, rotation, and scale channels
143     """
144     bl_idname = ANIM_KS_LOC_ROT_SCALE_ID
145     bl_label = "LocRotScale"
146
147     # poll - use predefined callback for selected bones/objects
148     poll = keyingsets_utils.RKS_POLL_selected_items
149
150     # iterator - use callback for selected bones/objects
151     iterator = keyingsets_utils.RKS_ITER_selected_item
152
153     # generator
154     def generate(self, context, ks, data):
155         # location
156         keyingsets_utils.RKS_GEN_location(self, context, ks, data)
157         # rotation
158         keyingsets_utils.RKS_GEN_rotation(self, context, ks, data)
159         # scale
160         keyingsets_utils.RKS_GEN_scaling(self, context, ks, data)
161
162
163 # RotScale
164 class BUILTIN_KSI_RotScale(KeyingSetInfo):
165     """Insert a keyframe on each of the rotation and scale channels"""
166     bl_label = "RotScale"
167
168     # poll - use predefined callback for selected bones/objects
169     poll = keyingsets_utils.RKS_POLL_selected_items
170
171     # iterator - use callback for selected bones/objects
172     iterator = keyingsets_utils.RKS_ITER_selected_item
173
174     # generator
175     def generate(self, context, ks, data):
176         # rotation
177         keyingsets_utils.RKS_GEN_rotation(self, context, ks, data)
178         # scaling
179         keyingsets_utils.RKS_GEN_scaling(self, context, ks, data)
180
181 # ------------
182
183
184 # VisualLocation
185 class BUILTIN_KSI_VisualLoc(KeyingSetInfo):
186     """
187     Insert a keyframe on each of the location channels, taking into account
188     effects of constraints and relationships
189     """
190     bl_label = "Visual Location"
191
192     bl_options = {'INSERTKEY_VISUAL'}
193
194     # poll - use predefined callback for selected bones/objects
195     poll = keyingsets_utils.RKS_POLL_selected_items
196
197     # iterator - use callback for selected bones/objects
198     iterator = keyingsets_utils.RKS_ITER_selected_item
199
200     # generator - use callback for location
201     generate = keyingsets_utils.RKS_GEN_location
202
203
204 # VisualRotation
205 class BUILTIN_KSI_VisualRot(KeyingSetInfo):
206     """
207     Insert a keyframe on each of the rotation channels, taking into account
208     effects of constraints and relationships
209     """
210     bl_label = "Visual Rotation"
211
212     bl_options = {'INSERTKEY_VISUAL'}
213
214     # poll - use predefined callback for selected bones/objects
215     poll = keyingsets_utils.RKS_POLL_selected_items
216
217     # iterator - use callback for selected bones/objects
218     iterator = keyingsets_utils.RKS_ITER_selected_item
219
220     # generator - use callback for rotation
221     generate = keyingsets_utils.RKS_GEN_rotation
222
223
224 # VisualScaling
225 class BUILTIN_KSI_VisualScaling(KeyingSetInfo):
226     """
227     Insert a keyframe on each of the scale channels, taking into account
228     effects of constraints and relationships
229     """
230     bl_label = "Visual Scaling"
231
232     bl_options = {'INSERTKEY_VISUAL'}
233
234     # poll - use predefined callback for selected bones/objects
235     poll = keyingsets_utils.RKS_POLL_selected_items
236
237     # iterator - use callback for selected bones/objects
238     iterator = keyingsets_utils.RKS_ITER_selected_item
239
240     # generator - use callback for location
241     generate = keyingsets_utils.RKS_GEN_scaling
242
243
244 # VisualLocRot
245 class BUILTIN_KSI_VisualLocRot(KeyingSetInfo):
246     """
247     Insert a keyframe on each of the location and rotation channels,
248     taking into account effects of constraints and relationships
249     """
250     bl_label = "Visual LocRot"
251
252     bl_options = {'INSERTKEY_VISUAL'}
253
254     # poll - use predefined callback for selected bones/objects
255     poll = keyingsets_utils.RKS_POLL_selected_items
256
257     # iterator - use callback for selected bones/objects
258     iterator = keyingsets_utils.RKS_ITER_selected_item
259
260     # generator
261     def generate(self, context, ks, data):
262         # location
263         keyingsets_utils.RKS_GEN_location(self, context, ks, data)
264         # rotation
265         keyingsets_utils.RKS_GEN_rotation(self, context, ks, data)
266
267
268 # VisualLocScale
269 class BUILTIN_KSI_VisualLocScale(KeyingSetInfo):
270     """
271     Insert a keyframe on each of the location and scaling channels,
272     taking into account effects of constraints and relationships
273     """
274     bl_label = "Visual LocScale"
275
276     bl_options = {'INSERTKEY_VISUAL'}
277
278     # poll - use predefined callback for selected bones/objects
279     poll = keyingsets_utils.RKS_POLL_selected_items
280
281     # iterator - use callback for selected bones/objects
282     iterator = keyingsets_utils.RKS_ITER_selected_item
283
284     # generator
285     def generate(self, context, ks, data):
286         # location
287         keyingsets_utils.RKS_GEN_location(self, context, ks, data)
288         # scaling
289         keyingsets_utils.RKS_GEN_scaling(self, context, ks, data)
290
291
292 # VisualLocRotScale
293 class BUILTIN_KSI_VisualLocRotScale(KeyingSetInfo):
294     """
295     Insert a keyframe on each of the location, rotation and scaling channels,
296     taking into account effects of constraints and relationships
297     """
298     bl_label = "Visual LocRotScale"
299
300     bl_options = {'INSERTKEY_VISUAL'}
301
302     # poll - use predefined callback for selected bones/objects
303     poll = keyingsets_utils.RKS_POLL_selected_items
304
305     # iterator - use callback for selected bones/objects
306     iterator = keyingsets_utils.RKS_ITER_selected_item
307
308     # generator
309     def generate(self, context, ks, data):
310         # location
311         keyingsets_utils.RKS_GEN_location(self, context, ks, data)
312         # rotation
313         keyingsets_utils.RKS_GEN_rotation(self, context, ks, data)
314         # scaling
315         keyingsets_utils.RKS_GEN_scaling(self, context, ks, data)
316
317
318 # VisualRotScale
319 class BUILTIN_KSI_VisualRotScale(KeyingSetInfo):
320     """
321     Insert a keyframe on each of the rotation and scaling channels,
322     taking into account effects of constraints and relationships
323     """
324     bl_label = "Visual RotScale"
325
326     bl_options = {'INSERTKEY_VISUAL'}
327
328     # poll - use predefined callback for selected bones/objects
329     poll = keyingsets_utils.RKS_POLL_selected_items
330
331     # iterator - use callback for selected bones/objects
332     iterator = keyingsets_utils.RKS_ITER_selected_item
333
334     # generator
335     def generate(self, context, ks, data):
336         # rotation
337         keyingsets_utils.RKS_GEN_rotation(self, context, ks, data)
338         # scaling
339         keyingsets_utils.RKS_GEN_scaling(self, context, ks, data)
340
341 # ------------
342
343
344 # Available
345 class BUILTIN_KSI_Available(KeyingSetInfo):
346     """Insert a keyframe on each of the already existing F-Curves"""
347     bl_idname = ANIM_KS_AVAILABLE_ID
348     bl_label = "Available"
349
350     # poll - selected objects or selected object with animation data
351     def poll(ksi, context):
352         ob = context.active_object
353         if ob:
354             # TODO: this fails if one animation-less object is active, but many others are selected
355             return ob.animation_data and ob.animation_data.action
356         else:
357             return bool(context.selected_objects)
358
359     # iterator - use callback for selected bones/objects
360     iterator = keyingsets_utils.RKS_ITER_selected_item
361
362     # generator - use callback for doing this
363     generate = keyingsets_utils.RKS_GEN_available
364
365 ###############################
366
367
368 # All properties that are likely to get animated in a character rig
369 class BUILTIN_KSI_WholeCharacter(KeyingSetInfo):
370     """
371     Insert a keyframe for all properties that are likely to get animated in a
372     character rig (useful when blocking out a shot)
373     """
374     bl_idname = ANIM_KS_WHOLE_CHARACTER_ID
375     bl_label = "Whole Character"
376
377     # these prefixes should be avoided, as they are not really bones
378     # that animators should be touching (or need to touch)
379     badBonePrefixes = (
380         'DEF',
381         'GEO',
382         'MCH',
383         'ORG',
384         'COR',
385         'VIS',
386         # ... more can be added here as you need in your own rigs ...
387     )
388
389     # poll - pose-mode on active object only
390     def poll(ksi, context):
391         return ((context.active_object) and (context.active_object.pose) and
392                 (context.active_object.mode == 'POSE'))
393
394     # iterator - all bones regardless of selection
395     def iterator(ksi, context, ks):
396         for bone in context.active_object.pose.bones:
397             if not bone.name.startswith(BUILTIN_KSI_WholeCharacter.badBonePrefixes):
398                 ksi.generate(context, ks, bone)
399
400     # generator - all unlocked bone transforms + custom properties
401     def generate(ksi, context, ks, bone):
402         # loc, rot, scale - only include unlocked ones
403         ksi.doLoc(ks, bone)
404
405         if bone.rotation_mode in {'QUATERNION', 'AXIS_ANGLE'}:
406             ksi.doRot4d(ks, bone)
407         else:
408             ksi.doRot3d(ks, bone)
409         ksi.doScale(ks, bone)
410
411         # custom props?
412         ksi.doCustomProps(ks, bone)
413
414     # ----------------
415
416     # helper to add some bone's property to the Keying Set
417     def addProp(ksi, ks, bone, prop, index=-1, use_groups=True):
418         # add the property name to the base path
419         id_path = bone.path_from_id()
420         id_block = bone.id_data
421
422         if prop.startswith('['):
423             # custom properties
424             path = id_path + prop
425         else:
426             # standard transforms/properties
427             path = keyingsets_utils.path_add_property(id_path, prop)
428
429         # add Keying Set entry for this...
430         if use_groups:
431             ks.paths.add(id_block, path, index, group_method='NAMED', group_name=bone.name)
432         else:
433             ks.paths.add(id_block, path, index)
434
435     # ----------------
436
437     # location properties
438     def doLoc(ksi, ks, bone):
439         if bone.lock_location == (False, False, False):
440             ksi.addProp(ks, bone, "location")
441         else:
442             for i in range(3):
443                 if not bone.lock_location[i]:
444                     ksi.addProp(ks, bone, "location", i)
445
446     # rotation properties
447     def doRot4d(ksi, ks, bone):
448         # rotation mode affects the property used
449         if bone.rotation_mode == 'QUATERNION':
450             prop = "rotation_quaternion"
451         elif bone.rotation_mode == 'AXIS_ANGLE':
452             prop = "rotation_axis_angle"
453
454         # add rotation properties if they will
455         if bone.lock_rotations_4d:
456             # can check individually
457             if (bone.lock_rotation == (False, False, False)) and (bone.lock_rotation_w is False):
458                 ksi.addProp(ks, bone, prop)
459             else:
460                 if bone.lock_rotation_w is False:
461                     ksi.addProp(ks, bone, prop, 0)  # w = 0
462
463                 for i in range(3):
464                     if not bone.lock_rotation[i]:
465                         ksi.addProp(ks, bone, prop, i + 1)  # i + 1, since here x/y/z = 1,2,3, and w=0
466         elif True not in bone.lock_rotation:
467             # if axis-angle rotations get locked as eulers, then it's too messy to allow anything
468             # other than all open unless we keyframe the whole lot
469             ksi.addProp(ks, bone, prop)
470
471     def doRot3d(ksi, ks, bone):
472         if bone.lock_rotation == (False, False, False):
473             ksi.addProp(ks, bone, "rotation_euler")
474         else:
475             for i in range(3):
476                 if not bone.lock_rotation[i]:
477                     ksi.addProp(ks, bone, "rotation_euler", i)
478
479     # scale properties
480     def doScale(ksi, ks, bone):
481         if bone.lock_scale == (0, 0, 0):
482             ksi.addProp(ks, bone, "scale")
483         else:
484             for i in range(3):
485                 if not bone.lock_scale[i]:
486                     ksi.addProp(ks, bone, "scale", i)
487
488     # ----------------
489
490     # custom properties
491     def doCustomProps(ksi, ks, bone):
492
493         prop_type_compat = {bpy.types.BoolProperty,
494                             bpy.types.IntProperty,
495                             bpy.types.FloatProperty}
496
497         # go over all custom properties for bone
498         for prop in bone.keys():
499             # ignore special "_RNA_UI" used for UI editing
500             if prop == "_RNA_UI":
501                 continue
502
503             # for now, just add all of 'em
504             prop_rna = type(bone).bl_rna.properties.get(prop, None)
505             if prop_rna is None:
506                 prop_path = '["%s"]' % prop
507                 if bone.path_resolve(prop_path, False).rna_type in prop_type_compat:
508                     ksi.addProp(ks, bone, prop_path)
509             elif prop_rna.is_animatable:
510                 ksi.addProp(ks, bone, prop)
511
512
513 ###############################
514
515
516 # Delta Location
517 class BUILTIN_KSI_DeltaLocation(KeyingSetInfo):
518     """Insert keyframes for additional location offset"""
519     bl_label = "Delta Location"
520
521     # poll - selected objects only (and only if active object in object mode)
522     poll = keyingsets_utils.RKS_POLL_selected_objects
523
524     # iterator - selected objects only
525     iterator = keyingsets_utils.RKS_ITER_selected_objects
526
527     # generator - delta location channels only
528     def generate(ksi, context, ks, data):
529         # get id-block and path info
530         id_block, base_path, grouping = keyingsets_utils.get_transform_generators_base_info(data)
531
532         # add the property name to the base path
533         path = keyingsets_utils.path_add_property(base_path, "delta_location")
534
535         # add Keying Set entry for this...
536         if grouping:
537             ks.paths.add(id_block, path, group_method='NAMED', group_name=grouping)
538         else:
539             ks.paths.add(id_block, path)
540
541
542 # Delta Rotation
543 class BUILTIN_KSI_DeltaRotation(KeyingSetInfo):
544     """Insert keyframes for additional rotation offset"""
545     bl_label = "Delta Rotation"
546
547     # poll - selected objects only (and only if active object in object mode)
548     poll = keyingsets_utils.RKS_POLL_selected_objects
549
550     # iterator - selected objects only
551     iterator = keyingsets_utils.RKS_ITER_selected_objects
552
553     # generator - delta location channels only
554     def generate(ksi, context, ks, data):
555         # get id-block and path info
556         id_block, base_path, grouping = keyingsets_utils.get_transform_generators_base_info(data)
557
558         # add the property name to the base path
559         #   rotation mode affects the property used
560         if data.rotation_mode == 'QUATERNION':
561             path = keyingsets_utils.path_add_property(base_path, "delta_rotation_quaternion")
562         elif data.rotation_mode == 'AXIS_ANGLE':
563             # XXX: for now, this is not available yet
564             #path = path_add_property(base_path, "delta_rotation_axis_angle")
565             return
566         else:
567             path = keyingsets_utils.path_add_property(base_path, "delta_rotation_euler")
568
569         # add Keying Set entry for this...
570         if grouping:
571             ks.paths.add(id_block, path, group_method='NAMED', group_name=grouping)
572         else:
573             ks.paths.add(id_block, path)
574
575
576 # Delta Scale
577 class BUILTIN_KSI_DeltaScale(KeyingSetInfo):
578     """Insert keyframes for additional scaling factor"""
579     bl_label = "Delta Scale"
580
581     # poll - selected objects only (and only if active object in object mode)
582     poll = keyingsets_utils.RKS_POLL_selected_objects
583
584     # iterator - selected objects only
585     iterator = keyingsets_utils.RKS_ITER_selected_objects
586
587     # generator - delta location channels only
588     def generate(ksi, context, ks, data):
589         # get id-block and path info
590         id_block, base_path, grouping = keyingsets_utils.get_transform_generators_base_info(data)
591
592         # add the property name to the base path
593         path = keyingsets_utils.path_add_property(base_path, "delta_scale")
594
595         # add Keying Set entry for this...
596         if grouping:
597             ks.paths.add(id_block, path, group_method='NAMED', group_name=grouping)
598         else:
599             ks.paths.add(id_block, path)
600
601 ###############################
602
603
604 def register():
605     bpy.utils.register_module(__name__)
606
607
608 def unregister():
609     bpy.utils.unregister_module(__name__)
610
611
612 if __name__ == "__main__":
613     register()