2097018fffbac36a580d4a34b24c01a6e849f43d
[blender.git] / release / scripts / keyingsets / keyingsets_utils.py
1 # This file defines a set of methods that are useful for various 
2 # Relative Keying Set (RKS) related operations, such as: callbacks
3 # for polling, iterator callbacks, and also generate callbacks. 
4 # All of these can be used in conjunction with the others. 
5
6 import bpy
7
8 ###########################
9 # General Utilities
10
11 # Append the specified property name on the the existing path
12 def path_add_property(path, prop):
13     if len(path):
14         return path + "." + prop;
15     else:
16         return prop;
17
18 ###########################
19 # Poll Callbacks
20
21 # selected objects
22 def RKS_POLL_selected_objects(ksi, context):
23     return context.active_object or len(context.selected_objects);
24     
25 # selected bones
26 def RKS_POLL_selected_bones(ksi, context):
27     # we must be in Pose Mode, and there must be some bones selected 
28     if (context.active_object) and (context.active_object.mode == 'POSE'):
29         if context.active_pose_bone or len(context.select_pose_bones):
30             return True;
31     
32     # nothing selected 
33     return False;
34
35
36 # selected bones or objects
37 def RKS_POLL_selected_items(ksi, context):
38     return RKS_POLL_selected_bones(ksi, context) or RKS_POLL_selected_objects(ksi, context);
39
40 ###########################
41 # Iterator Callbacks
42
43 # all selected objects or pose bones, depending on which we've got
44 def RKS_ITER_selected_item(ksi, context, ks):
45     if (context.active_object) and (context.active_object.mode == 'POSE'):
46         for bone in context.selected_pose_bones:
47             ksi.generate(context, ks, bone)
48     else:
49         for ob in context.selected_objects:
50             ksi.generate(context, ks, ob)
51
52 ###########################
53 # Generate Callbacks
54
55 # 'Available' F-Curves
56 def RKS_GEN_available(ksi, context, ks, data):
57     # try to get the animation data associated with the closest 
58     # ID-block to the data (neither of which may exist/be easy to find)
59     id_block = data.id_data
60     try:
61         adt = id_block.animation_data
62     except:
63         # there isn't any animation data available 
64         return;
65         
66     # there must also be an active action...
67     if adt.action is None:
68         return;
69         
70     # for each F-Curve, include an path to key it
71     # NOTE: we don't need to set the group settings here
72     for fcu in adt.action.fcurves:
73         ks.add_path(id_block, fcu.rna_path, index=fcu.array_index)
74     
75 # ------
76
77 # get ID block and based ID path for transform generators
78 def get_transform_generators_base_info(data):
79     # ID-block for the data 
80     id_block = data.id_data
81     
82     # get base path and grouping method/name
83     if isinstance(data, bpy.types.ID):
84         # no path in this case
85         path = ""
86         
87         # data on ID-blocks directly should get grouped by the KeyingSet
88         grouping = None;
89     else:
90         # get the path to the ID-block
91         path = data.path_to_id()
92         
93         try:
94             # try to use the name of the data element to group the F-Curve
95             grouping = data.name
96         except:
97             # fallback on the KeyingSet name
98             grouping = None;
99         
100     # return the ID-block and the path
101     return id_block, path, grouping
102
103 # Location 
104 def RKS_GEN_location(ksi, context, ks, data):
105     # get id-block and path info
106     id_block, base_path, grouping= get_transform_generators_base_info(data)
107     
108     # add the property name to the base path
109     path = path_add_property(base_path, "location")
110     
111     # add Keying Set entry for this...
112     if grouping:
113         ks.add_path(id_block, path, grouping_method='NAMED', group_name=grouping)
114     else:
115         ks.add_path(id_block, path)
116
117 # Rotation 
118 def RKS_GEN_rotation(ksi, context, ks, data):
119     # get id-block and path info
120     id_block, base_path, grouping= get_transform_generators_base_info(data)
121     
122     # add the property name to the base path
123     #   rotation mode affects the property used
124     if data.rotation_mode == 'QUATERNION':
125         path = path_add_property(base_path, "rotation_quaternion")
126     elif data.rotation_mode == 'AXISANGLE':
127         path = path_add_property(base_path, "rotation_axis_angle")
128     else:
129         path = path_add_property(base_path, "rotation_euler")
130     
131     # add Keying Set entry for this...
132     if grouping:
133         ks.add_path(id_block, path, grouping_method='NAMED', group_name=grouping)
134     else:
135         ks.add_path(id_block, path)
136
137 # Scaling 
138 def RKS_GEN_scaling(ksi, context, ks, data):
139     # get id-block and path info
140     id_block, base_path, grouping= get_transform_generators_base_info(data)
141     
142     # add the property name to the base path
143     path = path_add_property(base_path, "scale")
144     
145     # add Keying Set entry for this...
146     if grouping:
147         ks.add_path(id_block, path, grouping_method='NAMED', group_name=grouping)
148     else:
149         ks.add_path(id_block, path)
150
151 ###########################
152 # Un-needed stuff which is here to just shut up the warnings...
153
154 classes = []
155
156 def register():
157     register = bpy.types.register
158     for cls in classes:
159         register(cls)
160
161
162 def unregister():
163     unregister = bpy.types.unregister
164     for cls in classes:
165         unregister(cls)
166
167 if __name__ == "__main__":
168     register()
169
170 ###########################