d22fe763ad48baad48485938c33bdb296f402ecb
[blender-staging.git] / source / blender / editors / animation / keyingsets.c
1 /**
2  * $Id$
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19  *
20  * The Original Code is Copyright (C) 2009 Blender Foundation, Joshua Leung
21  * All rights reserved.
22  *
23  * The Original Code is: all of this file.
24  *
25  * Contributor(s): Joshua Leung (full recode)
26  *
27  * ***** END GPL LICENSE BLOCK *****
28  */
29  
30 #include <stdio.h>
31 #include <stddef.h>
32 #include <string.h>
33 #include <math.h>
34 #include <float.h>
35
36 #include "MEM_guardedalloc.h"
37
38 #include "BLI_blenlib.h"
39 #include "BLI_arithb.h"
40 #include "BLI_dynstr.h"
41
42 #include "DNA_anim_types.h"
43 #include "DNA_action_types.h"
44 #include "DNA_armature_types.h"
45 #include "DNA_constraint_types.h"
46 #include "DNA_key_types.h"
47 #include "DNA_object_types.h"
48 #include "DNA_material_types.h"
49 #include "DNA_scene_types.h"
50 #include "DNA_userdef_types.h"
51 #include "DNA_windowmanager_types.h"
52
53 #include "BKE_animsys.h"
54 #include "BKE_action.h"
55 #include "BKE_constraint.h"
56 #include "BKE_fcurve.h"
57 #include "BKE_utildefines.h"
58 #include "BKE_context.h"
59 #include "BKE_report.h"
60 #include "BKE_key.h"
61 #include "BKE_material.h"
62
63 #include "ED_anim_api.h"
64 #include "ED_keyframing.h"
65 #include "ED_keyframes_edit.h"
66 #include "ED_screen.h"
67 #include "ED_util.h"
68
69 #include "UI_interface.h"
70
71 #include "WM_api.h"
72 #include "WM_types.h"
73
74 #include "RNA_access.h"
75 #include "RNA_define.h"
76 #include "RNA_types.h"
77
78 #include "anim_intern.h"
79
80 /* ************************************************** */
81 /* KEYING SETS - EDITING API  */
82
83 /* UI API --------------------------------------------- */
84
85 /* Build menu-string of available keying-sets (allocates memory for string)
86  * NOTE: mode must not be longer than 64 chars
87  */
88 char *ANIM_build_keyingsets_menu (ListBase *list, short for_edit)
89 {
90         DynStr *pupds= BLI_dynstr_new();
91         KeyingSet *ks;
92         char buf[64];
93         char *str;
94         int i;
95         
96         /* add title first */
97         BLI_dynstr_append(pupds, "Keying Sets%t|");
98         
99         /* add dummy entries for none-active */
100         if (for_edit) { 
101                 BLI_dynstr_append(pupds, "Add New%x-1|");
102                 BLI_dynstr_append(pupds, " %x0|");
103         }
104         else
105                 BLI_dynstr_append(pupds, "No Keying Set%x0|");
106         
107         /* loop through keyingsets, adding them */
108         for (ks=list->first, i=1; ks; ks=ks->next, i++) {
109                 if (for_edit == 0)
110                         BLI_dynstr_append(pupds, "KS: ");
111                 
112                 BLI_dynstr_append(pupds, ks->name);
113                 BLI_snprintf( buf, 64, "%%x%d%s", i, ((ks->next)?"|":"") );
114                 BLI_dynstr_append(pupds, buf);
115         }
116         
117         /* convert to normal MEM_malloc'd string */
118         str= BLI_dynstr_get_cstring(pupds);
119         BLI_dynstr_free(pupds);
120         
121         return str;
122 }
123
124
125 /* ******************************************* */
126 /* KEYING SETS - BUILTIN */
127
128 #if 0 // XXX old keyingsets code based on adrcodes... to be restored in due course
129
130 /* ------------- KeyingSet Defines ------------ */
131 /* Note: these must all be named with the defks_* prefix, otherwise the template macro will not work! */
132
133 /* macro for defining keyingset contexts */
134 #define KSC_TEMPLATE(ctx_name) {&defks_##ctx_name[0], NULL, sizeof(defks_##ctx_name)/sizeof(bKeyingSet)}
135
136 /* --- */
137
138 /* check if option not available for deleting keys */
139 static short incl_non_del_keys (bKeyingSet *ks, const char mode[])
140 {
141         /* as optimisation, assume that it is sufficient to check only first letter
142          * of mode (int comparison should be faster than string!)
143          */
144         //if (strcmp(mode, "Delete")==0)
145         if (mode && mode[0]=='D')
146                 return 0;
147         
148         return 1;
149 }
150
151 /* Object KeyingSets  ------ */
152
153 /* check if include shapekey entry  */
154 static short incl_v3d_ob_shapekey (bKeyingSet *ks, const char mode[])
155 {
156         //Object *ob= (G.obedit)? (G.obedit) : (OBACT); // XXX
157         Object *ob= NULL;
158         char *newname= NULL;
159         
160         if(ob==NULL)
161                 return 0;
162         
163         /* not available for delete mode */
164         if (strcmp(mode, "Delete")==0)
165                 return 0;
166         
167         /* check if is geom object that can get shapekeys */
168         switch (ob->type) {
169                 /* geometry? */
170                 case OB_MESH:           newname= "Mesh";                break;
171                 case OB_CURVE:          newname= "Curve";               break;
172                 case OB_SURF:           newname= "Surface";             break;
173                 case OB_LATTICE:        newname= "Lattice";             break;
174                 
175                 /* not geometry! */
176                 default:
177                         return 0;
178         }
179         
180         /* if ks is shapekey entry (this could be callled for separator before too!) */
181         if (ks->flag == -3)
182                 BLI_strncpy(ks->name, newname, sizeof(ks->name));
183         
184         /* if it gets here, it's ok */
185         return 1;
186 }
187
188 /* array for object keyingset defines */
189 bKeyingSet defks_v3d_object[] = 
190 {
191         /* include_cb, adrcode-getter, name, blocktype, flag, chan_num, adrcodes */
192         {NULL, "Loc", ID_OB, 0, 3, {OB_LOC_X,OB_LOC_Y,OB_LOC_Z}},
193         {NULL, "Rot", ID_OB, 0, 3, {OB_ROT_X,OB_ROT_Y,OB_ROT_Z}},
194         {NULL, "Scale", ID_OB, 0, 3, {OB_SIZE_X,OB_SIZE_Y,OB_SIZE_Z}},
195         
196         {NULL, "%l", 0, -1, 0, {0}}, // separator
197         
198         {NULL, "LocRot", ID_OB, 0, 6, 
199                 {OB_LOC_X,OB_LOC_Y,OB_LOC_Z,
200                  OB_ROT_X,OB_ROT_Y,OB_ROT_Z}},
201                  
202         {NULL, "LocScale", ID_OB, 0, 6, 
203                 {OB_LOC_X,OB_LOC_Y,OB_LOC_Z,
204                  OB_SIZE_X,OB_SIZE_Y,OB_SIZE_Z}},
205                  
206         {NULL, "LocRotScale", ID_OB, 0, 9, 
207                 {OB_LOC_X,OB_LOC_Y,OB_LOC_Z,
208                  OB_ROT_X,OB_ROT_Y,OB_ROT_Z,
209                  OB_SIZE_X,OB_SIZE_Y,OB_SIZE_Z}},
210                  
211         {NULL, "RotScale", ID_OB, 0, 6, 
212                 {OB_ROT_X,OB_ROT_Y,OB_ROT_Z,
213                  OB_SIZE_X,OB_SIZE_Y,OB_SIZE_Z}},
214         
215         {incl_non_del_keys, "%l", 0, -1, 0, {0}}, // separator
216         
217         {incl_non_del_keys, "VisualLoc", ID_OB, INSERTKEY_MATRIX, 3, {OB_LOC_X,OB_LOC_Y,OB_LOC_Z}},
218         {incl_non_del_keys, "VisualRot", ID_OB, INSERTKEY_MATRIX, 3, {OB_ROT_X,OB_ROT_Y,OB_ROT_Z}},
219         
220         {incl_non_del_keys, "VisualLocRot", ID_OB, INSERTKEY_MATRIX, 6, 
221                 {OB_LOC_X,OB_LOC_Y,OB_LOC_Z,
222                  OB_ROT_X,OB_ROT_Y,OB_ROT_Z}},
223         
224         {NULL, "%l", 0, -1, 0, {0}}, // separator
225         
226         {NULL, "Layer", ID_OB, 0, 1, {OB_LAY}}, // icky option...
227         {NULL, "Available", ID_OB, -2, 0, {0}},
228         
229         {incl_v3d_ob_shapekey, "%l%l", 0, -1, 0, {0}}, // separator (linked to shapekey entry)
230         {incl_v3d_ob_shapekey, "<ShapeKey>", ID_OB, -3, 0, {0}}
231 };
232
233 /* PoseChannel KeyingSets  ------ */
234
235 /* array for posechannel keyingset defines */
236 bKeyingSet defks_v3d_pchan[] = 
237 {
238         /* include_cb, name, blocktype, flag, chan_num, adrcodes */
239         {NULL, "Loc", ID_PO, 0, 3, {AC_LOC_X,AC_LOC_Y,AC_LOC_Z}},
240         {NULL, "Rot", ID_PO, COMMONKEY_PCHANROT, 1, {KAG_CHAN_EXTEND}},
241         {NULL, "Scale", ID_PO, 0, 3, {AC_SIZE_X,AC_SIZE_Y,AC_SIZE_Z}},
242         
243         {NULL, "%l", 0, -1, 0, {0}}, // separator
244         
245         {NULL, "LocRot", ID_PO, COMMONKEY_PCHANROT, 4, 
246                 {AC_LOC_X,AC_LOC_Y,AC_LOC_Z,
247                  KAG_CHAN_EXTEND}},
248                  
249         {NULL, "LocScale", ID_PO, 0, 6, 
250                 {AC_LOC_X,AC_LOC_Y,AC_LOC_Z,
251                  AC_SIZE_X,AC_SIZE_Y,AC_SIZE_Z}},
252                  
253         {NULL, "LocRotScale", ID_PO, COMMONKEY_PCHANROT, 7, 
254                 {AC_LOC_X,AC_LOC_Y,AC_LOC_Z,AC_SIZE_X,AC_SIZE_Y,AC_SIZE_Z, 
255                  KAG_CHAN_EXTEND}},
256                  
257         {NULL, "RotScale", ID_PO, 0, 4, 
258                 {AC_SIZE_X,AC_SIZE_Y,AC_SIZE_Z, 
259                  KAG_CHAN_EXTEND}},
260         
261         {incl_non_del_keys, "%l", 0, -1, 0, {0}}, // separator
262         
263         {incl_non_del_keys, "VisualLoc", ID_PO, INSERTKEY_MATRIX, 3, {AC_LOC_X,AC_LOC_Y,AC_LOC_Z}},
264         {incl_non_del_keys, "VisualRot", ID_PO, INSERTKEY_MATRIX|COMMONKEY_PCHANROT, 1, {KAG_CHAN_EXTEND}},
265         
266         {incl_non_del_keys, "VisualLocRot", ID_PO, INSERTKEY_MATRIX|COMMONKEY_PCHANROT, 4, 
267                 {AC_LOC_X,AC_LOC_Y,AC_LOC_Z, KAG_CHAN_EXTEND}},
268         
269         {NULL, "%l", 0, -1, 0, {0}}, // separator
270         
271         {NULL, "Available", ID_PO, -2, 0, {0}}
272 };
273
274 /* Material KeyingSets  ------ */
275
276 /* array for material keyingset defines */
277 bKeyingSet defks_buts_shading_mat[] = 
278 {
279         /* include_cb, name, blocktype, flag, chan_num, adrcodes */
280         {NULL, "RGB", ID_MA, 0, 3, {MA_COL_R,MA_COL_G,MA_COL_B}},
281         {NULL, "Alpha", ID_MA, 0, 1, {MA_ALPHA}},
282         {NULL, "Halo Size", ID_MA, 0, 1, {MA_HASIZE}},
283         {NULL, "Mode", ID_MA, 0, 1, {MA_MODE}}, // evil bitflags
284         
285         {NULL, "%l", 0, -1, 0, {0}}, // separator
286         
287         {NULL, "All Color", ID_MA, 0, 18, 
288                 {MA_COL_R,MA_COL_G,MA_COL_B,
289                  MA_ALPHA,MA_HASIZE, MA_MODE,
290                  MA_SPEC_R,MA_SPEC_G,MA_SPEC_B,
291                  MA_REF,MA_EMIT,MA_AMB,MA_SPEC,MA_HARD,
292                  MA_MODE,MA_TRANSLU,MA_ADD}},
293                  
294         {NULL, "All Mirror", ID_MA, 0, 5, 
295                 {MA_RAYM,MA_FRESMIR,MA_FRESMIRI,
296                  MA_FRESTRA,MA_FRESTRAI}},
297         
298         {NULL, "%l", 0, -1, 0, {0}}, // separator
299         
300         {NULL, "Ofs", ID_MA, COMMONKEY_ADDMAP, 3, {MAP_OFS_X,MAP_OFS_Y,MAP_OFS_Z}},
301         {NULL, "Size", ID_MA, COMMONKEY_ADDMAP, 3, {MAP_SIZE_X,MAP_SIZE_Y,MAP_SIZE_Z}},
302         
303         {NULL, "All Mapping", ID_MA, COMMONKEY_ADDMAP, 14, 
304                 {MAP_OFS_X,MAP_OFS_Y,MAP_OFS_Z,
305                  MAP_SIZE_X,MAP_SIZE_Y,MAP_SIZE_Z,
306                  MAP_R,MAP_G,MAP_B,MAP_DVAR,
307                  MAP_COLF,MAP_NORF,MAP_VARF,MAP_DISP}},
308         
309         {NULL, "%l", 0, -1, 0, {0}}, // separator
310         
311         {NULL, "Available", ID_MA, -2, 0, {0}}
312 };
313
314 /* World KeyingSets  ------ */
315
316 /* array for world keyingset defines */
317 bKeyingSet defks_buts_shading_wo[] = 
318 {
319         /* include_cb, name, blocktype, flag, chan_num, adrcodes */
320         {NULL, "Zenith RGB", ID_WO, 0, 3, {WO_ZEN_R,WO_ZEN_G,WO_ZEN_B}},
321         {NULL, "Horizon RGB", ID_WO, 0, 3, {WO_HOR_R,WO_HOR_G,WO_HOR_B}},
322         
323         {NULL, "%l", 0, -1, 0, {0}}, // separator
324         
325         {NULL, "Mist", ID_WO, 0, 4, {WO_MISI,WO_MISTDI,WO_MISTSTA,WO_MISTHI}},
326         {NULL, "Stars", ID_WO, 0, 5, {WO_STAR_R,WO_STAR_G,WO_STAR_B,WO_STARDIST,WO_STARSIZE}},
327         
328         
329         {NULL, "%l", 0, -1, 0, {0}}, // separator
330         
331         {NULL, "Ofs", ID_WO, COMMONKEY_ADDMAP, 3, {MAP_OFS_X,MAP_OFS_Y,MAP_OFS_Z}},
332         {NULL, "Size", ID_WO, COMMONKEY_ADDMAP, 3, {MAP_SIZE_X,MAP_SIZE_Y,MAP_SIZE_Z}},
333         
334         {NULL, "All Mapping", ID_WO, COMMONKEY_ADDMAP, 14, 
335                 {MAP_OFS_X,MAP_OFS_Y,MAP_OFS_Z,
336                  MAP_SIZE_X,MAP_SIZE_Y,MAP_SIZE_Z,
337                  MAP_R,MAP_G,MAP_B,MAP_DVAR,
338                  MAP_COLF,MAP_NORF,MAP_VARF,MAP_DISP}},
339         
340         {NULL, "%l", 0, -1, 0, {0}}, // separator
341         
342         {NULL, "Available", ID_WO, -2, 0, {0}}
343 };
344
345 /* Lamp KeyingSets  ------ */
346
347 /* array for lamp keyingset defines */
348 bKeyingSet defks_buts_shading_la[] = 
349 {
350         /* include_cb, name, blocktype, flag, chan_num, adrcodes */
351         {NULL, "RGB", ID_LA, 0, 3, {LA_COL_R,LA_COL_G,LA_COL_B}},
352         {NULL, "Energy", ID_LA, 0, 1, {LA_ENERGY}},
353         {NULL, "Spot Size", ID_LA, 0, 1, {LA_SPOTSI}},
354         
355         {NULL, "%l", 0, -1, 0, {0}}, // separator
356         
357         {NULL, "Ofs", ID_LA, COMMONKEY_ADDMAP, 3, {MAP_OFS_X,MAP_OFS_Y,MAP_OFS_Z}},
358         {NULL, "Size", ID_LA, COMMONKEY_ADDMAP, 3, {MAP_SIZE_X,MAP_SIZE_Y,MAP_SIZE_Z}},
359         
360         {NULL, "All Mapping", ID_LA, COMMONKEY_ADDMAP, 14, 
361                 {MAP_OFS_X,MAP_OFS_Y,MAP_OFS_Z,
362                  MAP_SIZE_X,MAP_SIZE_Y,MAP_SIZE_Z,
363                  MAP_R,MAP_G,MAP_B,MAP_DVAR,
364                  MAP_COLF,MAP_NORF,MAP_VARF,MAP_DISP}},
365         
366         {NULL, "%l", 0, -1, 0, {0}}, // separator
367         
368         {NULL, "Available", ID_LA, -2, 0, {0}}
369 };
370
371 /* Texture KeyingSets  ------ */
372
373 /* array for texture keyingset defines */
374 bKeyingSet defks_buts_shading_tex[] = 
375 {
376         /* include_cb, name, blocktype, flag, chan_num, adrcodes */
377         {NULL, "Clouds", ID_TE, 0, 5, 
378                 {TE_NSIZE,TE_NDEPTH,TE_NTYPE,
379                  TE_MG_TYP,TE_N_BAS1}},
380         
381         {NULL, "Marble", ID_TE, 0, 7, 
382                 {TE_NSIZE,TE_NDEPTH,TE_NTYPE,
383                  TE_TURB,TE_MG_TYP,TE_N_BAS1,TE_N_BAS2}},
384                  
385         {NULL, "Stucci", ID_TE, 0, 5, 
386                 {TE_NSIZE,TE_NTYPE,TE_TURB,
387                  TE_MG_TYP,TE_N_BAS1}},
388                  
389         {NULL, "Wood", ID_TE, 0, 6, 
390                 {TE_NSIZE,TE_NTYPE,TE_TURB,
391                  TE_MG_TYP,TE_N_BAS1,TE_N_BAS2}},
392                  
393         {NULL, "Magic", ID_TE, 0, 2, {TE_NDEPTH,TE_TURB}},
394         
395         {NULL, "Blend", ID_TE, 0, 1, {TE_MG_TYP}},      
396                 
397         {NULL, "Musgrave", ID_TE, 0, 6, 
398                 {TE_MG_TYP,TE_MGH,TE_MG_LAC,
399                  TE_MG_OCT,TE_MG_OFF,TE_MG_GAIN}},
400                  
401         {NULL, "Voronoi", ID_TE, 0, 9, 
402                 {TE_VNW1,TE_VNW2,TE_VNW3,TE_VNW4,
403                 TE_VNMEXP,TE_VN_DISTM,TE_VN_COLT,
404                 TE_ISCA,TE_NSIZE}},
405                 
406         {NULL, "Distorted Noise", ID_TE, 0, 4, 
407                 {TE_MG_OCT,TE_MG_OFF,TE_MG_GAIN,TE_DISTA}},
408         
409         {NULL, "Color Filter", ID_TE, 0, 5, 
410                 {TE_COL_R,TE_COL_G,TE_COL_B,TE_BRIGHT,TE_CONTRA}},
411         
412         {NULL, "%l", 0, -1, 0, {0}}, // separator
413         
414         {NULL, "Available", ID_TE, -2, 0, {0}}
415 };
416
417 /* Object Buttons KeyingSets  ------ */
418
419 /* check if include particles entry  */
420 static short incl_buts_ob (bKeyingSet *ks, const char mode[])
421 {
422         //Object *ob= OBACT; // xxx
423         Object *ob= NULL;
424         /* only if object is mesh type */
425         
426         if(ob==NULL) return 0;
427         return (ob->type == OB_MESH);
428 }
429
430 /* array for texture keyingset defines */
431 bKeyingSet defks_buts_object[] = 
432 {
433         /* include_cb, name, blocktype, flag, chan_num, adrcodes */
434         {incl_buts_ob, "Surface Damping", ID_OB, 0, 1, {OB_PD_SDAMP}},
435         {incl_buts_ob, "Random Damping", ID_OB, 0, 1, {OB_PD_RDAMP}},
436         {incl_buts_ob, "Permeability", ID_OB, 0, 1, {OB_PD_PERM}},
437         
438         {NULL, "%l", 0, -1, 0, {0}}, // separator
439         
440         {NULL, "Force Strength", ID_OB, 0, 1, {OB_PD_FSTR}},
441         {NULL, "Force Falloff", ID_OB, 0, 1, {OB_PD_FFALL}},
442         
443         {NULL, "%l", 0, -1, 0, {0}}, // separator
444         
445         {NULL, "Available", ID_OB, -2, 0, {0}}  // this will include ob-transforms too!
446 };
447
448 /* Camera Buttons KeyingSets  ------ */
449
450 /* check if include internal-renderer entry  */
451 static short incl_buts_cam1 (bKeyingSet *ks, const char mode[])
452 {
453         Scene *scene= NULL; // FIXME this will cause a crash, but we need an extra arg first!
454         /* only if renderer is internal renderer */
455         return (scene->r.renderer==R_INTERN);
456 }
457
458 /* check if include external-renderer entry  */
459 static short incl_buts_cam2 (bKeyingSet *ks, const char mode[])
460 {
461         Scene *scene= NULL; // FIXME this will cause a crash, but we need an extra arg first!
462         /* only if renderer is internal renderer */
463         return (scene->r.renderer!=R_INTERN);
464 }
465
466 /* array for camera keyingset defines */
467 bKeyingSet defks_buts_cam[] = 
468 {
469         /* include_cb, name, blocktype, flag, chan_num, adrcodes */
470         {NULL, "Lens", ID_CA, 0, 1, {CAM_LENS}},
471         {NULL, "Clipping", ID_CA, 0, 2, {CAM_STA,CAM_END}},
472         {NULL, "Focal Distance", ID_CA, 0, 1, {CAM_YF_FDIST}},
473         
474         {NULL, "%l", 0, -1, 0, {0}}, // separator
475         
476         
477         {incl_buts_cam2, "Aperture", ID_CA, 0, 1, {CAM_YF_APERT}},
478         {incl_buts_cam1, "Viewplane Shift", ID_CA, 0, 2, {CAM_SHIFT_X,CAM_SHIFT_Y}},
479         
480         {NULL, "%l", 0, -1, 0, {0}}, // separator
481         
482         {NULL, "Available", ID_CA, -2, 0, {0}}
483 };
484
485 /* --- */
486
487 /* Keying Context Defines - Must keep in sync with enumeration (eKS_Contexts) */
488 bKeyingContext ks_contexts[] = 
489 {
490         KSC_TEMPLATE(v3d_object),
491         KSC_TEMPLATE(v3d_pchan),
492         
493         KSC_TEMPLATE(buts_shading_mat),
494         KSC_TEMPLATE(buts_shading_wo),
495         KSC_TEMPLATE(buts_shading_la),
496         KSC_TEMPLATE(buts_shading_tex),
497
498         KSC_TEMPLATE(buts_object),
499         KSC_TEMPLATE(buts_cam)
500 };
501
502 /* Keying Context Enumeration - Must keep in sync with definitions*/
503 typedef enum eKS_Contexts {
504         KSC_V3D_OBJECT = 0,
505         KSC_V3D_PCHAN,
506         
507         KSC_BUTS_MAT,
508         KSC_BUTS_WO,
509         KSC_BUTS_LA,
510         KSC_BUTS_TEX,
511         
512         KSC_BUTS_OB,
513         KSC_BUTS_CAM,
514         
515                 /* make sure this last one remains untouched! */
516         KSC_TOT_TYPES
517 } eKS_Contexts;
518
519
520 #endif // XXX old keyingsets code based on adrcodes... to be restored in due course
521
522 /* Macros for Declaring KeyingSets ------------------- */
523
524 /* A note about this system for declaring built-in Keying Sets:
525  *      One may ask, "What is the purpose of all of these macros and static arrays?" and 
526  *      "Why not call the KeyingSets API defined in BKE_animsys.h?". The answer is two-fold.
527  *      
528  *      1) Firstly, we use static arrays of struct definitions instead of function calls, as
529  *         it reduces the start-up overhead and allocated-memory footprint of Blender. If we called
530  *         the KeyingSets API to build these sets, the overhead of checking for unique names, allocating
531  *         memory for each and every path and KeyingSet, scattered around in RAM, all of which would increase
532  *         the startup time (which is totally unacceptable) and could lead to fragmentation+slower access times.
533  *      2) Since we aren't using function calls, we need a nice way of defining these KeyingSets in a way which
534  *         is easily readable and less prone to breakage from changes to the underlying struct definitions. Further,
535  *         adding additional entries SHOULD NOT require custom code to be written to access these new entries/sets. 
536  *         Therefore, here we have a system with nice, human-readable statements via macros, and static arrays which
537  *         are linked together using more special macros + struct definitions, allowing for such a generic + simple
538  *         initialisation function (init_builtin_keyingsets()) compared with that of something like the Nodes system.
539  *
540  * -- Joshua Leung, April 2009
541  */
542
543 /* Struct type for declaring builtin KeyingSets in as entries in static arrays*/
544 typedef struct bBuiltinKeyingSet {
545         KeyingSet ks;                   /* the KeyingSet to build */
546         int tot;                                /* the total number of paths defined */
547         KS_Path paths[64];              /* the paths for the KeyingSet to use */
548 } bBuiltinKeyingSet;
549
550         /* WARNING: the following macros must be kept in sync with the 
551          * struct definitions in DNA_anim_types.h! 
552          */
553
554 /* macro for defining a builtin KeyingSet */
555 #define BI_KS_DEFINE_BEGIN(name, keyingflag) \
556         {{NULL, NULL, {NULL, NULL}, name, KEYINGSET_BUILTIN, keyingflag},
557         
558 /* macro to finish defining a builtin KeyingSet */
559 #define BI_KS_DEFINE_END \
560         }
561         
562 /* macro to start defining paths for a builtin KeyingSet */
563 #define BI_KS_PATHS_BEGIN(tot) \
564         tot, {
565         
566 /* macro to finish defining paths for a builtin KeyingSet */
567 #define BI_KS_PATHS_END \
568         }
569         
570 /* macro for defining a builtin KeyingSet's path */
571 #define BI_KSP_DEFINE(id_type, templates, prop_path, array_index, flag, groupflag) \
572         {NULL, NULL, NULL, "", id_type, templates, prop_path, array_index, flag, groupflag}
573         
574 /* macro for defining a builtin KeyingSet with no paths (use in place of BI_KS_PAHTS_BEGIN/END block) */
575 #define BI_KS_PATHS_NONE \
576         0, {0}
577         
578 /* ---- */
579
580 /* Struct type for finding all the arrays of builtin KeyingSets */
581 typedef struct bBuiltinKSContext {
582         bBuiltinKeyingSet *bks;         /* array of KeyingSet definitions */
583         int tot;                                        /* number of KeyingSets in this array */
584 } bBuiltinKSContext;
585
586 /* macro for defining builtin KeyingSet sets 
587  * NOTE: all the arrays of sets must follow this naming convention!
588  */
589 #define BKSC_TEMPLATE(ctx_name) {&def_builtin_keyingsets_##ctx_name[0], sizeof(def_builtin_keyingsets_##ctx_name)/sizeof(bBuiltinKeyingSet)}
590
591
592 /* 3D-View Builtin KeyingSets ------------------------ */
593
594 static bBuiltinKeyingSet def_builtin_keyingsets_v3d[] =
595 {
596         /* Simple Keying Sets ************************************* */
597         /* Keying Set - "Location" ---------- */
598         BI_KS_DEFINE_BEGIN("Location", 0)
599                 BI_KS_PATHS_BEGIN(1)
600                         BI_KSP_DEFINE(ID_OB, KSP_TEMPLATE_OBJECT|KSP_TEMPLATE_PCHAN, "location", 0, KSP_FLAG_WHOLE_ARRAY, KSP_GROUP_TEMPLATE_ITEM) 
601                 BI_KS_PATHS_END
602         BI_KS_DEFINE_END,
603
604         /* Keying Set - "Rotation" ---------- */
605         BI_KS_DEFINE_BEGIN("Rotation", 0)
606                 BI_KS_PATHS_BEGIN(1)
607                         BI_KSP_DEFINE(ID_OB, KSP_TEMPLATE_OBJECT|KSP_TEMPLATE_PCHAN|KSP_TEMPLATE_PCHAN_ROT, "rotation", 0, KSP_FLAG_WHOLE_ARRAY, KSP_GROUP_TEMPLATE_ITEM) 
608                 BI_KS_PATHS_END
609         BI_KS_DEFINE_END,
610         
611         /* Keying Set - "Scaling" ---------- */
612         BI_KS_DEFINE_BEGIN("Scaling", 0)
613                 BI_KS_PATHS_BEGIN(1)
614                         BI_KSP_DEFINE(ID_OB, KSP_TEMPLATE_OBJECT|KSP_TEMPLATE_PCHAN, "scale", 0, KSP_FLAG_WHOLE_ARRAY, KSP_GROUP_TEMPLATE_ITEM) 
615                 BI_KS_PATHS_END
616         BI_KS_DEFINE_END,
617         
618         /* Compound Keying Sets *********************************** */
619         /* Keying Set - "LocRot" ---------- */
620         BI_KS_DEFINE_BEGIN("LocRot", 0)
621                 BI_KS_PATHS_BEGIN(2)
622                         BI_KSP_DEFINE(ID_OB, KSP_TEMPLATE_OBJECT|KSP_TEMPLATE_PCHAN, "location", 0, KSP_FLAG_WHOLE_ARRAY, KSP_GROUP_TEMPLATE_ITEM), 
623                         BI_KSP_DEFINE(ID_OB, KSP_TEMPLATE_OBJECT|KSP_TEMPLATE_PCHAN|KSP_TEMPLATE_PCHAN_ROT, "rotation", 0, KSP_FLAG_WHOLE_ARRAY, KSP_GROUP_TEMPLATE_ITEM) 
624                 BI_KS_PATHS_END
625         BI_KS_DEFINE_END,
626         
627         /* Keying Set - "LocRotScale" ---------- */
628         BI_KS_DEFINE_BEGIN("LocRotScale", 0)
629                 BI_KS_PATHS_BEGIN(3)
630                         BI_KSP_DEFINE(ID_OB, KSP_TEMPLATE_OBJECT|KSP_TEMPLATE_PCHAN, "location", 0, KSP_FLAG_WHOLE_ARRAY, KSP_GROUP_TEMPLATE_ITEM), 
631                         BI_KSP_DEFINE(ID_OB, KSP_TEMPLATE_OBJECT|KSP_TEMPLATE_PCHAN|KSP_TEMPLATE_PCHAN_ROT, "rotation", 0, KSP_FLAG_WHOLE_ARRAY, KSP_GROUP_TEMPLATE_ITEM), 
632                         BI_KSP_DEFINE(ID_OB, KSP_TEMPLATE_OBJECT|KSP_TEMPLATE_PCHAN, "scale", 0, KSP_FLAG_WHOLE_ARRAY, KSP_GROUP_TEMPLATE_ITEM) 
633                 BI_KS_PATHS_END
634         BI_KS_DEFINE_END,
635         
636         /* Keying Sets with Keying Flags ************************* */
637         /* Keying Set - "VisualLoc" ---------- */
638         BI_KS_DEFINE_BEGIN("VisualLoc", 0)
639                 BI_KS_PATHS_BEGIN(1)
640                         BI_KSP_DEFINE(ID_OB, KSP_TEMPLATE_OBJECT|KSP_TEMPLATE_PCHAN, "location", INSERTKEY_MATRIX, KSP_FLAG_WHOLE_ARRAY, KSP_GROUP_TEMPLATE_ITEM) 
641                 BI_KS_PATHS_END
642         BI_KS_DEFINE_END,
643
644         /* Keying Set - "Rotation" ---------- */
645         BI_KS_DEFINE_BEGIN("VisualRot", 0)
646                 BI_KS_PATHS_BEGIN(1)
647                         BI_KSP_DEFINE(ID_OB, KSP_TEMPLATE_OBJECT|KSP_TEMPLATE_PCHAN|KSP_TEMPLATE_PCHAN_ROT, "rotation", INSERTKEY_MATRIX, KSP_FLAG_WHOLE_ARRAY, KSP_GROUP_TEMPLATE_ITEM) 
648                 BI_KS_PATHS_END
649         BI_KS_DEFINE_END,
650         
651         /* Keying Set - "VisualLocRot" ---------- */
652         BI_KS_DEFINE_BEGIN("VisualLocRot", 0)
653                 BI_KS_PATHS_BEGIN(2)
654                         BI_KSP_DEFINE(ID_OB, KSP_TEMPLATE_OBJECT|KSP_TEMPLATE_PCHAN, "location", INSERTKEY_MATRIX, KSP_FLAG_WHOLE_ARRAY, KSP_GROUP_TEMPLATE_ITEM), 
655                         BI_KSP_DEFINE(ID_OB, KSP_TEMPLATE_OBJECT|KSP_TEMPLATE_PCHAN|KSP_TEMPLATE_PCHAN_ROT, "rotation", INSERTKEY_MATRIX, KSP_FLAG_WHOLE_ARRAY, KSP_GROUP_TEMPLATE_ITEM) 
656                 BI_KS_PATHS_END
657         BI_KS_DEFINE_END
658 };
659
660 /* All Builtin KeyingSets ------------------------ */
661
662 /* total number of builtin KeyingSet contexts */
663 #define MAX_BKSC_TYPES  1
664
665 /* array containing all the available builtin KeyingSets definition sets 
666  *      - size of this is MAX_BKSC_TYPES+1 so that we don't smash the stack
667  */
668 static bBuiltinKSContext def_builtin_keyingsets[MAX_BKSC_TYPES+1] =
669 {
670         BKSC_TEMPLATE(v3d)
671         /* add more contexts above this line... */
672 };
673
674
675 /* ListBase of these KeyingSets chained up ready for usage 
676  * NOTE: this is exported to keyframing.c for use...
677  */
678 ListBase builtin_keyingsets = {NULL, NULL};
679
680 /* Utility API ------------------------ */
681
682 /* Link up all of the builtin Keying Sets when starting up Blender
683  * This is called from WM_init() in wm_init_exit.c
684  */
685 void init_builtin_keyingsets (void)
686 {
687         bBuiltinKSContext *bksc;
688         bBuiltinKeyingSet *bks;
689         int bksc_i, bks_i;
690         
691         /* loop over all the sets of KeyingSets, setting them up, and chaining them to the builtins list */
692         for (bksc_i= 0, bksc= &def_builtin_keyingsets[0]; bksc_i < MAX_BKSC_TYPES; bksc_i++, bksc++)
693         {
694                 /* for each set definitions for a builtin KeyingSet, chain the paths to that KeyingSet and add */
695                 for (bks_i= 0, bks= bksc->bks; bks_i < bksc->tot; bks_i++, bks++)
696                 {
697                         KeyingSet *ks= &bks->ks;
698                         KS_Path *ksp;
699                         int pIndex;
700                         
701                         /* loop over paths, linking them to the KeyingSet and each other */
702                         for (pIndex= 0, ksp= &bks->paths[0]; pIndex < bks->tot; pIndex++, ksp++)
703                                 BLI_addtail(&ks->paths, ksp);
704                                 
705                         /* add KeyingSet to builtin sets list */
706                         BLI_addtail(&builtin_keyingsets, ks);
707                 }
708         }
709 }
710
711
712 /* Get the first builtin KeyingSet with the given name, which occurs after the given one (or start of list if none given) */
713 KeyingSet *ANIM_builtin_keyingset_get_named (KeyingSet *prevKS, char name[])
714 {
715         KeyingSet *ks, *first=NULL;
716         
717         /* sanity checks - any name to check? */
718         if (name[0] == 0)
719                 return NULL;
720         
721         /* get first KeyingSet to use */
722         if (prevKS && prevKS->next)
723                 first= prevKS->next;
724         else
725                 first= builtin_keyingsets.first;
726                 
727         /* loop over KeyingSets checking names */
728         for (ks= first; ks; ks= ks->next) {
729                 if (strcmp(name, ks->name) == 0)
730                         return ks;
731         }
732         
733         /* no matches found */
734         return NULL;
735 }
736
737 /* ******************************************* */
738 /* KEYFRAME MODIFICATION */
739
740 /* KeyingSet Menu Helpers ------------ */
741
742 /* Extract the maximum set of requirements from the KeyingSet */
743 static int keyingset_relative_get_templates (KeyingSet *ks)
744 {
745         KS_Path *ksp;
746         int templates= 0;
747         
748         /* loop over the paths (could be slow to do for a number of KeyingSets)? */
749         for (ksp= ks->paths.first; ksp; ksp= ksp->next) {
750                 /* add the destination's templates to the set of templates required for the set */
751                 templates |= ksp->templates;
752         }
753         
754         return templates;
755 }
756
757 /* Check if context data is suitable for the given absolute Keying Set */
758 short keyingset_context_ok_poll (bContext *C, KeyingSet *ks)
759 {
760         ScrArea *sa= CTX_wm_area(C);
761         
762         /* data retrieved from context depends on active editor */
763         if (sa == NULL) return 0;
764                 
765         switch (sa->spacetype) {
766                 case SPACE_VIEW3D:
767                 {
768                         Object *obact= CTX_data_active_object(C);
769                         
770                         /* if in posemode, check if 'pose-channels' requested for in KeyingSet */
771                         if ((obact && obact->pose) && (obact->mode & OB_MODE_POSE)) {
772                                 /* check for posechannels */
773                                 
774                         }
775                         else {
776                                 /* check for selected object */
777                                 
778                         }
779                 }
780                         break;
781         }
782         
783         
784         return 1;
785 }
786
787 /* KeyingSet Context Operations ------------ */
788
789 /* Get list of data-sources from context (in 3D-View) for inserting keyframes using the given relative Keying Set */
790 static short modifykey_get_context_v3d_data (bContext *C, ListBase *dsources, KeyingSet *ks)
791 {
792         bCommonKeySrc *cks;
793         Object *obact= CTX_data_active_object(C);
794         int templates; 
795         short ok= 0;
796         
797         /* get the templates in use in this KeyingSet which we should supply data for */
798         templates = keyingset_relative_get_templates(ks);
799         
800         /* check if the active object is in PoseMode (i.e. only deal with bones) */
801         // TODO: check with the templates to see what we really need to store 
802         if ((obact && obact->pose) && (obact->mode & OB_MODE_POSE)) {
803                 /* Pose Mode: Selected bones */
804 #if 0
805                 //set_pose_keys(ob);  /* sets pchan->flag to POSE_KEY if bone selected, and clears if not */
806                 
807                 /* loop through posechannels */
808                 //for (pchan=ob->pose->chanbase.first; pchan; pchan=pchan->next) {
809                 //      if (pchan->flag & POSE_KEY) {
810                 //      }
811                 //}
812 #endif
813                 
814                 CTX_DATA_BEGIN(C, bPoseChannel*, pchan, selected_pchans)
815                 {
816                         /* add a new keying-source */
817                         cks= MEM_callocN(sizeof(bCommonKeySrc), "bCommonKeySrc");
818                         BLI_addtail(dsources, cks);
819                         
820                         /* set necessary info */
821                         cks->id= &obact->id;
822                         cks->pchan= pchan;
823                         
824                         if (templates & KSP_TEMPLATE_CONSTRAINT)
825                                 cks->con= constraints_get_active(&pchan->constraints);
826                         
827                         ok= 1;
828                 }
829                 CTX_DATA_END;
830         }
831         else {
832                 /* Object Mode: Selected objects */
833                 CTX_DATA_BEGIN(C, Base*, base, selected_bases) 
834                 {
835                         Object *ob= base->object;
836                         
837                         /* add a new keying-source */
838                         cks= MEM_callocN(sizeof(bCommonKeySrc), "bCommonKeySrc");
839                         BLI_addtail(dsources, cks);
840                         
841                         /* set necessary info */
842                         cks->id= &ob->id;
843                         
844                         if (templates & KSP_TEMPLATE_CONSTRAINT)
845                                 cks->con= constraints_get_active(&ob->constraints);
846                         
847                         ok= 1;
848                 }
849                 CTX_DATA_END;
850         }
851         
852         /* return whether any data was extracted */
853         return ok;
854 }
855
856 /* Get list of data-sources from context for inserting keyframes using the given relative Keying Set */
857 short modifykey_get_context_data (bContext *C, ListBase *dsources, KeyingSet *ks)
858 {
859         ScrArea *sa= CTX_wm_area(C);
860         
861         /* for now, the active area is used to determine what set of contexts apply */
862         if (sa == NULL)
863                 return 0;
864                 
865         switch (sa->spacetype) {
866                 case SPACE_VIEW3D:      /* 3D-View: Selected Objects or Bones */
867                         return modifykey_get_context_v3d_data(C, dsources, ks);
868         }
869         
870         /* nothing happened */
871         return 0;
872
873
874 /* KeyingSet Operations (Insert/Delete Keyframes) ------------ */
875
876 /* Given a KeyingSet and context info (if required), modify keyframes for the channels specified
877  * by the KeyingSet. This takes into account many of the different combinations of using KeyingSets.
878  * Returns the number of channels that keyframes were added to
879  */
880 int modify_keyframes (bContext *C, ListBase *dsources, bAction *act, KeyingSet *ks, short mode, float cfra)
881 {
882         KS_Path *ksp;
883         int kflag=0, success= 0;
884         char *groupname= NULL;
885         
886         /* get flags to use */
887         if (mode == MODIFYKEY_MODE_INSERT) {
888                 /* use KeyingSet's flags as base */
889                 kflag= ks->keyingflag;
890                 
891                 /* suppliment with info from the context */
892                 if (IS_AUTOKEY_FLAG(AUTOMATKEY)) kflag |= INSERTKEY_MATRIX;
893                 if (IS_AUTOKEY_FLAG(INSERTNEEDED)) kflag |= INSERTKEY_NEEDED;
894                 // if (IS_AUTOKEY_MODE(EDITKEYS)) flag |= INSERTKEY_REPLACE;
895         }
896         else if (mode == MODIFYKEY_MODE_DELETE)
897                 kflag= 0;
898         
899         /* check if the KeyingSet is absolute or not (i.e. does it requires sources info) */
900         if (ks->flag & KEYINGSET_ABSOLUTE) {
901                 /* Absolute KeyingSets are simpler to use, as all the destination info has already been
902                  * provided by the user, and is stored, ready to use, in the KeyingSet paths.
903                  */
904                 for (ksp= ks->paths.first; ksp; ksp= ksp->next) {
905                         int arraylen, i;
906                         
907                         /* get pointer to name of group to add channels to */
908                         if (ksp->groupmode == KSP_GROUP_NONE)
909                                 groupname= NULL;
910                         else if (ksp->groupmode == KSP_GROUP_KSNAME)
911                                 groupname= ks->name;
912                         else
913                                 groupname= ksp->group;
914                         
915                         /* init arraylen and i - arraylen should be greater than i so that
916                          * normal non-array entries get keyframed correctly
917                          */
918                         i= ksp->array_index;
919                         arraylen= i;
920                         
921                         /* get length of array if whole array option is enabled */
922                         if (ksp->flag & KSP_FLAG_WHOLE_ARRAY) {
923                                 PointerRNA id_ptr, ptr;
924                                 PropertyRNA *prop;
925                                 
926                                 RNA_id_pointer_create(ksp->id, &id_ptr);
927                                 if (RNA_path_resolve(&id_ptr, ksp->rna_path, &ptr, &prop) && prop)
928                                         arraylen= RNA_property_array_length(prop);
929                         }
930                         
931                         /* we should do at least one step */
932                         if (arraylen == i)
933                                 arraylen++;
934                         
935                         /* for each possible index, perform operation 
936                          *      - assume that arraylen is greater than index
937                          */
938                         for (; i < arraylen; i++) {
939                                 /* action to take depends on mode */
940                                 if (mode == MODIFYKEY_MODE_INSERT)
941                                         success+= insert_keyframe(ksp->id, act, groupname, ksp->rna_path, i, cfra, kflag);
942                                 else if (mode == MODIFYKEY_MODE_DELETE)
943                                         success+= delete_keyframe(ksp->id, act, groupname, ksp->rna_path, i, cfra, kflag);
944                         }
945                         
946                         /* send notifiers and set recalc-flags */
947                         // TODO: hopefully this doesn't result in execessive flooding of the notifier stack
948                         if (C && ksp->id) {
949                                 switch (GS(ksp->id->name)) {
950                                         case ID_OB: /* Object (or Object-Related) Keyframes */
951                                         {
952                                                 Object *ob= (Object *)ksp->id;
953                                                 
954                                                 ob->recalc |= OB_RECALC;
955                                                 WM_event_add_notifier(C, NC_OBJECT|ND_KEYS, ksp->id);
956                                         }
957                                                 break;
958                                         case ID_MA: /* Material Keyframes */
959                                                 WM_event_add_notifier(C, NC_MATERIAL|ND_KEYS, ksp->id);
960                                                 break;
961                                         default: /* Any keyframes */
962                                                 WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME_EDIT, NULL);
963                                                 break;
964                                 }
965                         }
966                 }
967         }
968         else if (dsources && dsources->first) {
969                 /* for each one of the 'sources', resolve the template markers and expand arrays, then insert keyframes */
970                 bCommonKeySrc *cks;
971                 
972                 /* for each 'source' for keyframe data, resolve each of the paths from the KeyingSet */
973                 for (cks= dsources->first; cks; cks= cks->next) {
974                         /* for each path in KeyingSet, construct a path using the templates */
975                         for (ksp= ks->paths.first; ksp; ksp= ksp->next) {
976                                 DynStr *pathds= BLI_dynstr_new();
977                                 char *path = NULL;
978                                 int arraylen, i;
979                                 
980                                 /* set initial group name */
981                                 groupname= (cks->id) ? cks->id->name+2 : NULL;
982                                 
983                                 /* construct the path */
984                                 // FIXME: this currently only works with a few hardcoded cases
985                                 if ((ksp->templates & KSP_TEMPLATE_PCHAN) && (cks->pchan)) {
986                                         /* add basic pose-channel path access */
987                                         BLI_dynstr_append(pathds, "pose.pose_channels[\"");
988                                         BLI_dynstr_append(pathds, cks->pchan->name);
989                                         BLI_dynstr_append(pathds, "\"]");
990                                         
991                                         /* override default group name */
992                                         groupname= cks->pchan->name;
993                                 }
994                                 if ((ksp->templates & KSP_TEMPLATE_CONSTRAINT) && (cks->con)) {
995                                         /* add basic constraint path access */
996                                         BLI_dynstr_append(pathds, "constraints[\"");
997                                         BLI_dynstr_append(pathds, cks->con->name);
998                                         BLI_dynstr_append(pathds, "\"]");
999                                         
1000                                         /* override default group name */
1001                                         groupname= cks->con->name;
1002                                 }
1003                                 {
1004                                         /* add property stored in KeyingSet Path */
1005                                         if (BLI_dynstr_get_len(pathds))
1006                                                 BLI_dynstr_append(pathds, ".");
1007                                                 
1008                                         /* apply some further templates? */
1009                                         if ((ksp->templates & KSP_TEMPLATE_PCHAN_ROT) && (cks->pchan)) {
1010                                                 /* if this path is exactly "rotation", and the rotation mode is set to eulers,
1011                                                  * use "euler_rotation" instead so that rotations will be keyed correctly
1012                                                  */
1013                                                 if (strcmp(ksp->rna_path, "rotation")==0 && (cks->pchan->rotmode))
1014                                                         BLI_dynstr_append(pathds, "euler_rotation");
1015                                                 else
1016                                                         BLI_dynstr_append(pathds, ksp->rna_path);
1017                                         }
1018                                         else {
1019                                                 /* just directly use the path */
1020                                                 BLI_dynstr_append(pathds, ksp->rna_path);
1021                                         }
1022                                         
1023                                         /* convert to C-string */
1024                                         path= BLI_dynstr_get_cstring(pathds);
1025                                         BLI_dynstr_free(pathds);
1026                                 }
1027                                 
1028                                 /* get pointer to name of group to add channels to 
1029                                  *      - KSP_GROUP_TEMPLATE_ITEM is handled above while constructing the paths 
1030                                  */
1031                                 if (ksp->groupmode == KSP_GROUP_NONE)
1032                                         groupname= NULL;
1033                                 else if (ksp->groupmode == KSP_GROUP_KSNAME)
1034                                         groupname= ks->name;
1035                                 else if (ksp->groupmode == KSP_GROUP_NAMED)
1036                                         groupname= ksp->group;
1037                                 
1038                                 /* init arraylen and i - arraylen should be greater than i so that
1039                                  * normal non-array entries get keyframed correctly
1040                                  */
1041                                 i= ksp->array_index;
1042                                 arraylen= i+1;
1043                                 
1044                                 /* get length of array if whole array option is enabled */
1045                                 if (ksp->flag & KSP_FLAG_WHOLE_ARRAY) {
1046                                         PointerRNA id_ptr, ptr;
1047                                         PropertyRNA *prop;
1048                                         
1049                                         RNA_id_pointer_create(cks->id, &id_ptr);
1050                                         if (RNA_path_resolve(&id_ptr, path, &ptr, &prop) && prop)
1051                                                 arraylen= RNA_property_array_length(prop);
1052                                 }
1053                                 
1054                                 /* for each possible index, perform operation 
1055                                  *      - assume that arraylen is greater than index
1056                                  */
1057                                 for (; i < arraylen; i++) {
1058                                         /* action to take depends on mode */
1059                                         if (mode == MODIFYKEY_MODE_INSERT)
1060                                                 success+= insert_keyframe(cks->id, act, groupname, path, i, cfra, kflag);
1061                                         else if (mode == MODIFYKEY_MODE_DELETE)
1062                                                 success+= delete_keyframe(cks->id, act, groupname, path, i, cfra, kflag);
1063                                 }
1064                                 
1065                                 /* free the path */
1066                                 MEM_freeN(path);
1067                         }
1068                         
1069                         /* send notifiers and set recalc-flags */
1070                         // TODO: hopefully this doesn't result in execessive flooding of the notifier stack
1071                         if (C && cks->id) {
1072                                 switch (GS(cks->id->name)) {
1073                                         case ID_OB: /* Object (or Object-Related) Keyframes */
1074                                         {
1075                                                 Object *ob= (Object *)cks->id;
1076                                                 
1077                                                 ob->recalc |= OB_RECALC;
1078                                                 WM_event_add_notifier(C, NC_OBJECT|ND_KEYS, cks->id);
1079                                         }
1080                                                 break;
1081                                         case ID_MA: /* Material Keyframes */
1082                                                 WM_event_add_notifier(C, NC_MATERIAL|ND_KEYS, cks->id);
1083                                                 break;
1084                                         default: /* Any keyframes */
1085                                                 WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME_EDIT, NULL);
1086                                                 break;
1087                                 }
1088                         }
1089                 }
1090         }
1091         
1092         /* return the number of channels successfully affected */
1093         return success;
1094 }
1095
1096 /* ************************************************** */