minor pep8 edits, also added 'test_pep8' & 'test_cmake' to the GNUmakefile for conven...
[blender-staging.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
36 ###############################
37 # Built-In KeyingSets
38
39
40 # Location
41 class BUILTIN_KSI_Location(bpy.types.KeyingSetInfo):
42     bl_label = "Location"
43
44     # poll - use predefined callback for selected bones/objects
45     poll = keyingsets_utils.RKS_POLL_selected_items
46
47     # iterator - use callback for selected bones/objects
48     iterator = keyingsets_utils.RKS_ITER_selected_item
49
50     # generator - use callback for location
51     generate = keyingsets_utils.RKS_GEN_location
52
53
54 # Rotation
55 class BUILTIN_KSI_Rotation(bpy.types.KeyingSetInfo):
56     bl_label = "Rotation"
57
58     # poll - use predefined callback for selected bones/objects
59     poll = keyingsets_utils.RKS_POLL_selected_items
60
61     # iterator - use callback for selected bones/objects
62     iterator = keyingsets_utils.RKS_ITER_selected_item
63
64     # generator - use callback for location
65     generate = keyingsets_utils.RKS_GEN_rotation
66
67
68 # Scale
69 class BUILTIN_KSI_Scaling(bpy.types.KeyingSetInfo):
70     bl_label = "Scaling"
71
72     # poll - use predefined callback for selected bones/objects
73     poll = keyingsets_utils.RKS_POLL_selected_items
74
75     # iterator - use callback for selected bones/objects
76     iterator = keyingsets_utils.RKS_ITER_selected_item
77
78     # generator - use callback for location
79     generate = keyingsets_utils.RKS_GEN_scaling
80
81 # ------------
82
83
84 # LocRot
85 class BUILTIN_KSI_LocRot(bpy.types.KeyingSetInfo):
86     bl_label = "LocRot"
87
88     # poll - use predefined callback for selected bones/objects
89     poll = keyingsets_utils.RKS_POLL_selected_items
90
91     # iterator - use callback for selected bones/objects
92     iterator = keyingsets_utils.RKS_ITER_selected_item
93
94     # generator
95     def generate(self, context, ks, data):
96         # location
97         keyingsets_utils.RKS_GEN_location(self, context, ks, data)
98         # rotation
99         keyingsets_utils.RKS_GEN_rotation(self, context, ks, data)
100
101
102 # LocScale
103 class BUILTIN_KSI_LocScale(bpy.types.KeyingSetInfo):
104     bl_label = "LocScale"
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         # scale
117         keyingsets_utils.RKS_GEN_scaling(self, context, ks, data)
118
119
120 # LocRotScale
121 class BUILTIN_KSI_LocRotScale(bpy.types.KeyingSetInfo):
122     bl_label = "LocRotScale"
123
124     # poll - use predefined callback for selected bones/objects
125     poll = keyingsets_utils.RKS_POLL_selected_items
126
127     # iterator - use callback for selected bones/objects
128     iterator = keyingsets_utils.RKS_ITER_selected_item
129
130     # generator
131     def generate(self, context, ks, data):
132         # location
133         keyingsets_utils.RKS_GEN_location(self, context, ks, data)
134         # rotation
135         keyingsets_utils.RKS_GEN_rotation(self, context, ks, data)
136         # scale
137         keyingsets_utils.RKS_GEN_scaling(self, context, ks, data)
138
139
140 # RotScale
141 class BUILTIN_KSI_RotScale(bpy.types.KeyingSetInfo):
142     bl_label = "RotScale"
143
144     # poll - use predefined callback for selected bones/objects
145     poll = keyingsets_utils.RKS_POLL_selected_items
146
147     # iterator - use callback for selected bones/objects
148     iterator = keyingsets_utils.RKS_ITER_selected_item
149
150     # generator
151     def generate(self, context, ks, data):
152         # rotation
153         keyingsets_utils.RKS_GEN_rotation(self, context, ks, data)
154         # scaling
155         keyingsets_utils.RKS_GEN_scaling(self, context, ks, data)
156
157 # ------------
158
159
160 # Location
161 class BUILTIN_KSI_VisualLoc(bpy.types.KeyingSetInfo):
162     bl_label = "Visual Location"
163
164     bl_options = {'INSERTKEY_VISUAL'}
165
166     # poll - use predefined callback for selected bones/objects
167     poll = keyingsets_utils.RKS_POLL_selected_items
168
169     # iterator - use callback for selected bones/objects
170     iterator = keyingsets_utils.RKS_ITER_selected_item
171
172     # generator - use callback for location
173     generate = keyingsets_utils.RKS_GEN_location
174
175
176 # Rotation
177 class BUILTIN_KSI_VisualRot(bpy.types.KeyingSetInfo):
178     bl_label = "Visual Rotation"
179
180     bl_options = {'INSERTKEY_VISUAL'}
181
182     # poll - use predefined callback for selected bones/objects
183     poll = keyingsets_utils.RKS_POLL_selected_items
184
185     # iterator - use callback for selected bones/objects
186     iterator = keyingsets_utils.RKS_ITER_selected_item
187
188     # generator - use callback for rotation
189     generate = keyingsets_utils.RKS_GEN_rotation
190
191
192 # VisualLocRot
193 class BUILTIN_KSI_VisualLocRot(bpy.types.KeyingSetInfo):
194     bl_label = "Visual LocRot"
195
196     bl_options = {'INSERTKEY_VISUAL'}
197
198     # poll - use predefined callback for selected bones/objects
199     poll = keyingsets_utils.RKS_POLL_selected_items
200
201     # iterator - use callback for selected bones/objects
202     iterator = keyingsets_utils.RKS_ITER_selected_item
203
204     # generator
205     def generate(self, context, ks, data):
206         # location
207         keyingsets_utils.RKS_GEN_location(self, context, ks, data)
208         # rotation
209         keyingsets_utils.RKS_GEN_rotation(self, context, ks, data)
210
211 # ------------
212
213
214 # Available
215 class BUILTIN_KSI_Available(bpy.types.KeyingSetInfo):
216     bl_label = "Available"
217
218     # poll - use predefined callback for selected objects
219     # TODO: this should really check whether the selected object (or datablock)
220     #         has any animation data defined yet
221     poll = keyingsets_utils.RKS_POLL_selected_objects
222
223     # iterator - use callback for selected bones/objects
224     iterator = keyingsets_utils.RKS_ITER_selected_item
225
226     # generator - use callback for doing this
227     generate = keyingsets_utils.RKS_GEN_available
228
229 ###############################
230
231
232 # All properties that are likely to get animated in a character rig
233 class BUILTIN_KSI_WholeCharacter(bpy.types.KeyingSetInfo):
234     bl_label = "Whole Character"
235
236     # these prefixes should be avoided, as they are not really bones
237     # that animators should be touching (or need to touch)
238     badBonePrefixes = (
239         'DEF',
240         'GEO',
241         'MCH',
242         'ORG',
243         'COR',
244         'VIS',
245         # ... more can be added here as you need in your own rigs ...
246     )
247
248     # poll - pose-mode on active object only
249     def poll(ksi, context):
250         return ((context.active_object) and (context.active_object.pose) and
251                 (context.active_object.mode == 'POSE'))
252
253     # iterator - all bones regardless of selection
254     def iterator(ksi, context, ks):
255         for bone in context.active_object.pose.bones:
256             if not bone.name.startswith(BUILTIN_KSI_WholeCharacter.badBonePrefixes):
257                 ksi.generate(context, ks, bone)
258
259     # generator - all unlocked bone transforms + custom properties
260     def generate(ksi, context, ks, bone):
261         # loc, rot, scale - only include unlocked ones
262         ksi.doLoc(ks, bone)
263
264         if bone.rotation_mode in ('QUATERNION', 'AXIS_ANGLE'):
265             ksi.doRot4d(ks, bone)
266         else:
267             ksi.doRot3d(ks, bone)
268         ksi.doScale(ks, bone)
269
270         # custom props?
271         ksi.doCustomProps(ks, bone)
272
273     # ----------------
274
275     # helper to add some bone's property to the Keying Set
276     def addProp(ksi, ks, bone, prop, index=-1, use_groups=True):
277         # add the property name to the base path
278         id_path = bone.path_from_id()
279         id_block = bone.id_data
280
281         if prop.startswith('['):
282             # custom properties
283             path = id_path + prop
284         else:
285             # standard transforms/properties
286             path = keyingsets_utils.path_add_property(id_path, prop)
287
288         # add Keying Set entry for this...
289         if use_groups:
290             ks.paths.add(id_block, path, index, group_method='NAMED', group_name=bone.name)
291         else:
292             ks.paths.add(id_block, path, index)
293
294     # ----------------
295
296     # location properties
297     def doLoc(ksi, ks, bone):
298         if bone.lock_location == (False, False, False):
299             ksi.addProp(ks, bone, "location")
300         else:
301             for i in range(3):
302                 if not bone.lock_location[i]:
303                     ksi.addProp(ks, bone, "location", i)
304
305     # rotation properties
306     def doRot4d(ksi, ks, bone):
307         # rotation mode affects the property used
308         if bone.rotation_mode == 'QUATERNION':
309             prop = "rotation_quaternion"
310         elif bone.rotation_mode == 'AXIS_ANGLE':
311             prop = "rotation_axis_angle"
312
313         # add rotation properties if they will
314         if bone.lock_rotations_4d:
315             # can check individually
316             if (bone.lock_rotation == (False, False, False)) and (bone.lock_rotation_w == False):
317                 ksi.addProp(ks, bone, prop)
318             else:
319                 if bone.lock_rotation_w == False:
320                     ksi.addProp(ks, bone, prop, 0)  # w = 0
321
322                 for i in range(3):
323                     if not bone.lock_rotation[i]:
324                         ksi.addProp(ks, bone, prop, i + 1)  # i + 1, since here x,y,z = 1,2,3, and w=0
325         elif True not in bone.lock_rotation:
326             # if axis-angle rotations get locked as eulers, then it's too messy to allow anything
327             # other than all open unless we keyframe the whole lot
328             ksi.addProp(ks, bone, prop)
329
330     def doRot3d(ksi, ks, bone):
331         if bone.lock_rotation == (False, False, False):
332             ksi.addProp(ks, bone, "rotation_euler")
333         else:
334             for i in range(3):
335                 if not bone.lock_rotation[i]:
336                     ksi.addProp(ks, bone, "rotation_euler", i)
337
338     # scale properties
339     def doScale(ksi, ks, bone):
340         if bone.lock_scale == (0, 0, 0):
341             ksi.addProp(ks, bone, "scale")
342         else:
343             for i in range(3):
344                 if not bone.lock_scale[i]:
345                     ksi.addProp(ks, bone, "scale", i)
346
347     # ----------------
348
349     # custom properties
350     def doCustomProps(ksi, ks, bone):
351         # go over all custom properties for bone
352         for prop, val in bone.items():
353             # ignore special "_RNA_UI" used for UI editing
354             if prop == "_RNA_UI":
355                 continue
356
357             # for now, just add all of 'em
358             ksi.addProp(ks, bone, '["%s"]' % (prop))
359
360 ###############################
361
362
363 # Delta Location
364 class BUILTIN_KSI_DeltaLocation(bpy.types.KeyingSetInfo):
365     bl_label = "Delta Location"
366
367     # poll - selected objects only (and only if active object in object mode)
368     poll = keyingsets_utils.RKS_POLL_selected_objects
369
370     # iterator - selected objects only
371     iterator = keyingsets_utils.RKS_ITER_selected_objects
372
373     # generator - delta location channels only
374     def generate(ksi, context, ks, data):
375         # get id-block and path info
376         id_block, base_path, grouping = keyingsets_utils.get_transform_generators_base_info(data)
377
378         # add the property name to the base path
379         path = keyingsets_utils.path_add_property(base_path, "delta_location")
380
381         # add Keying Set entry for this...
382         if grouping:
383             ks.paths.add(id_block, path, group_method='NAMED', group_name=grouping)
384         else:
385             ks.paths.add(id_block, path)
386
387
388 # Delta Rotation
389 class BUILTIN_KSI_DeltaRotation(bpy.types.KeyingSetInfo):
390     bl_label = "Delta Rotation"
391
392     # poll - selected objects only (and only if active object in object mode)
393     poll = keyingsets_utils.RKS_POLL_selected_objects
394
395     # iterator - selected objects only
396     iterator = keyingsets_utils.RKS_ITER_selected_objects
397
398     # generator - delta location channels only
399     def generate(ksi, context, ks, data):
400         # get id-block and path info
401         id_block, base_path, grouping = keyingsets_utils.get_transform_generators_base_info(data)
402
403         # add the property name to the base path
404         #   rotation mode affects the property used
405         if data.rotation_mode == 'QUATERNION':
406             path = path_add_property(base_path, "delta_rotation_quaternion")
407         elif data.rotation_mode == 'AXIS_ANGLE':
408             # XXX: for now, this is not available yet
409             #path = path_add_property(base_path, "delta_rotation_axis_angle")
410             return
411         else:
412             path = keyingsets_utils.path_add_property(base_path, "delta_rotation_euler")
413
414         # add Keying Set entry for this...
415         if grouping:
416             ks.paths.add(id_block, path, group_method='NAMED', group_name=grouping)
417         else:
418             ks.paths.add(id_block, path)
419
420
421 # Delta Scale
422 class BUILTIN_KSI_DeltaScale(bpy.types.KeyingSetInfo):
423     bl_label = "Delta Scale"
424
425     # poll - selected objects only (and only if active object in object mode)
426     poll = keyingsets_utils.RKS_POLL_selected_objects
427
428     # iterator - selected objects only
429     iterator = keyingsets_utils.RKS_ITER_selected_objects
430
431     # generator - delta location channels only
432     def generate(ksi, context, ks, data):
433         # get id-block and path info
434         id_block, base_path, grouping = keyingsets_utils.get_transform_generators_base_info(data)
435
436         # add the property name to the base path
437         path = keyingsets_utils.path_add_property(base_path, "delta_scale")
438
439         # add Keying Set entry for this...
440         if grouping:
441             ks.paths.add(id_block, path, group_method='NAMED', group_name=grouping)
442         else:
443             ks.paths.add(id_block, path)
444
445 ###############################
446
447
448 def register():
449     bpy.utils.register_module(__name__)
450
451
452 def unregister():
453     bpy.utils.unregister_module(__name__)
454
455
456 if __name__ == "__main__":
457     register()