Keying Sets: Wrapped KeyingSets in RNA
[blender.git] / source / blender / editors / animation / keyframing.c
1 /* Testing code for 2.5 animation system 
2  * Copyright 2009, Joshua Leung
3  */
4  
5 #include <stdio.h>
6 #include <stddef.h>
7 #include <string.h>
8 #include <math.h>
9 #include <float.h>
10
11 #include "MEM_guardedalloc.h"
12
13 #include "BLI_blenlib.h"
14 #include "BLI_arithb.h"
15 #include "BLI_dynstr.h"
16
17 #include "DNA_anim_types.h"
18 #include "DNA_action_types.h"
19 #include "DNA_armature_types.h"
20 #include "DNA_constraint_types.h"
21 #include "DNA_key_types.h"
22 #include "DNA_object_types.h"
23 #include "DNA_material_types.h"
24 #include "DNA_scene_types.h"
25 #include "DNA_userdef_types.h"
26 #include "DNA_windowmanager_types.h"
27
28 #include "BKE_animsys.h"
29 #include "BKE_action.h"
30 #include "BKE_fcurve.h"
31 #include "BKE_utildefines.h"
32 #include "BKE_context.h"
33 #include "BKE_report.h"
34 #include "BKE_key.h"
35 #include "BKE_material.h"
36
37 #include "ED_anim_api.h"
38 #include "ED_keyframing.h"
39 #include "ED_keyframes_edit.h"
40 #include "ED_screen.h"
41 #include "ED_util.h"
42
43 #include "UI_interface.h"
44
45 #include "WM_api.h"
46 #include "WM_types.h"
47
48 #include "RNA_access.h"
49 #include "RNA_define.h"
50 #include "RNA_types.h"
51
52 /* ************************************************** */
53 /* LOCAL TYPES AND DEFINES */
54
55 /* ----------- Common KeyData Sources ------------ */
56
57 /* temporary struct to gather data combos to keyframe */
58 typedef struct bCommonKeySrc {
59         struct bCommonKeySrc *next, *prev;
60                 
61                 /* general data/destination-source settings */
62         ID *id;                                 /* id-block this comes from */
63         char *rna_path;                 /* base path to use */  // xxx.... maybe we don't need this?
64         
65                 /* specific cases */
66         bPoseChannel *pchan;    /* only needed when doing recalcs... */
67 } bCommonKeySrc;
68
69 /* ******************************************* */
70 /* Animation Data Validation */
71
72 /* Get (or add relevant data to be able to do so) F-Curve from the Active Action, 
73  * for the given Animation Data block. This assumes that all the destinations are valid.
74  */
75 FCurve *verify_fcurve (ID *id, const char group[], const char rna_path[], const int array_index, short add)
76 {
77         AnimData *adt;
78         bAction *act;
79         bActionGroup *grp;
80         FCurve *fcu;
81         
82         /* sanity checks */
83         if ELEM(NULL, id, rna_path)
84                 return NULL;
85         
86         /* init animdata if none available yet */
87         adt= BKE_animdata_from_id(id);
88         if ((adt == NULL) && (add))
89                 adt= BKE_id_add_animdata(id);
90         if (adt == NULL) { 
91                 /* if still none (as not allowed to add, or ID doesn't have animdata for some reason) */
92                 return NULL;
93         }
94                 
95         /* init action if none available yet */
96         // TODO: need some wizardry to handle NLA stuff correct
97         if ((adt->action == NULL) && (add))
98                 adt->action= add_empty_action("Action");
99         act= adt->action;
100                 
101         /* try to find f-curve matching for this setting 
102          *      - add if not found and allowed to add one
103          *              TODO: add auto-grouping support? how this works will need to be resolved
104          */
105         if (act)
106                 fcu= list_find_fcurve(&act->curves, rna_path, array_index);
107         else
108                 fcu= NULL;
109         
110         if ((fcu == NULL) && (add)) {
111                 /* use default settings to make a F-Curve */
112                 fcu= MEM_callocN(sizeof(FCurve), "FCurve");
113                 
114                 fcu->flag = (FCURVE_VISIBLE|FCURVE_AUTO_HANDLES|FCURVE_SELECTED);
115                 if (act->curves.first==NULL) 
116                         fcu->flag |= FCURVE_ACTIVE;     /* first one added active */
117                         
118                 /* store path - make copy, and store that */
119                 fcu->rna_path= BLI_strdupn(rna_path, strlen(rna_path));
120                 fcu->array_index= array_index;
121                 
122                 /* set additional flags */
123                 // TODO: need to set the FCURVE_INT_VALUES flag must be set if property is not float!
124                 
125                 
126                 /* if a group name has been provided, try to add or find a group, then add F-Curve to it */
127                 if (group) {
128                         /* try to find group */
129                         grp= action_groups_find_named(act, group);
130                         
131                         /* no matching groups, so add one */
132                         if (grp == NULL) {
133                                 /* Add a new group, and make it active */
134                                 grp= MEM_callocN(sizeof(bActionGroup), "bActionGroup");
135                                 
136                                 grp->flag |= (AGRP_ACTIVE|AGRP_SELECTED|AGRP_EXPANDED);
137                                 BLI_snprintf(grp->name, 64, group);
138                                 
139                                 BLI_addtail(&act->groups, grp);
140                                 BLI_uniquename(&act->groups, grp, "Group", offsetof(bActionGroup, name), 64);
141                                 
142                                 set_active_action_group(act, grp, 1);
143                         }
144                         
145                         /* add F-Curve to group */
146                         action_groups_add_channel(act, grp, fcu);
147                 }
148                 else {
149                         /* just add F-Curve to end of Action's list */
150                         BLI_addtail(&act->curves, fcu);
151                 }
152         }
153         
154         /* return the F-Curve */
155         return fcu;
156 }
157
158 /* ************************************************** */
159 /* KEYFRAME INSERTION */
160
161 /* -------------- BezTriple Insertion -------------------- */
162
163 /* threshold for inserting keyframes - threshold here should be good enough for now, but should become userpref */
164 #define BEZT_INSERT_THRESH      0.00001f
165
166 /* Binary search algorithm for finding where to insert BezTriple. (for use by insert_bezt_icu)
167  * Returns the index to insert at (data already at that index will be offset if replace is 0)
168  */
169 static int binarysearch_bezt_index (BezTriple array[], float frame, int arraylen, short *replace)
170 {
171         int start=0, end=arraylen;
172         int loopbreaker= 0, maxloop= arraylen * 2;
173         
174         /* initialise replace-flag first */
175         *replace= 0;
176         
177         /* sneaky optimisations (don't go through searching process if...):
178          *      - keyframe to be added is to be added out of current bounds
179          *      - keyframe to be added would replace one of the existing ones on bounds
180          */
181         if ((arraylen <= 0) || (array == NULL)) {
182                 printf("Warning: binarysearch_bezt_index() encountered invalid array \n");
183                 return 0;
184         }
185         else {
186                 /* check whether to add before/after/on */
187                 float framenum;
188                 
189                 /* 'First' Keyframe (when only one keyframe, this case is used) */
190                 framenum= array[0].vec[1][0];
191                 if (IS_EQT(frame, framenum, BEZT_INSERT_THRESH)) {
192                         *replace = 1;
193                         return 0;
194                 }
195                 else if (frame < framenum)
196                         return 0;
197                         
198                 /* 'Last' Keyframe */
199                 framenum= array[(arraylen-1)].vec[1][0];
200                 if (IS_EQT(frame, framenum, BEZT_INSERT_THRESH)) {
201                         *replace= 1;
202                         return (arraylen - 1);
203                 }
204                 else if (frame > framenum)
205                         return arraylen;
206         }
207         
208         
209         /* most of the time, this loop is just to find where to put it
210          * 'loopbreaker' is just here to prevent infinite loops 
211          */
212         for (loopbreaker=0; (start <= end) && (loopbreaker < maxloop); loopbreaker++) {
213                 /* compute and get midpoint */
214                 int mid = (start + end) / 2;
215                 float midfra= array[mid].vec[1][0];
216                 
217                 /* check if exactly equal to midpoint */
218                 if (IS_EQT(frame, midfra, BEZT_INSERT_THRESH)) {
219                         *replace = 1;
220                         return mid;
221                 }
222                 
223                 /* repeat in upper/lower half */
224                 if (frame > midfra)
225                         start= mid + 1;
226                 else if (frame < midfra)
227                         end= mid - 1;
228         }
229         
230         /* print error if loop-limit exceeded */
231         if (loopbreaker == (maxloop-1)) {
232                 printf("Error: binarysearch_bezt_index() was taking too long \n");
233                 
234                 // include debug info 
235                 printf("\tround = %d: start = %d, end = %d, arraylen = %d \n", loopbreaker, start, end, arraylen);
236         }
237         
238         /* not found, so return where to place it */
239         return start;
240 }
241
242 /* This function adds a given BezTriple to an F-Curve. It will allocate 
243  * memory for the array if needed, and will insert the BezTriple into a
244  * suitable place in chronological order.
245  * 
246  * NOTE: any recalculate of the F-Curve that needs to be done will need to 
247  *              be done by the caller.
248  */
249 int insert_bezt_fcurve (FCurve *fcu, BezTriple *bezt)
250 {
251         BezTriple *newb;
252         int i= 0;
253         
254         if (fcu->bezt) {
255                 short replace = -1;
256                 i = binarysearch_bezt_index(fcu->bezt, bezt->vec[1][0], fcu->totvert, &replace);
257                 
258                 if (replace) {                  
259                         /* sanity check: 'i' may in rare cases exceed arraylen */
260                         // FIXME: do not overwrite handletype if just replacing...?
261                         if ((i >= 0) && (i < fcu->totvert))
262                                 *(fcu->bezt + i) = *bezt;
263                 }
264                 else {
265                         /* add new */
266                         newb= MEM_callocN((fcu->totvert+1)*sizeof(BezTriple), "beztriple");
267                         
268                         /* add the beztriples that should occur before the beztriple to be pasted (originally in ei->icu) */
269                         if (i > 0)
270                                 memcpy(newb, fcu->bezt, i*sizeof(BezTriple));
271                         
272                         /* add beztriple to paste at index i */
273                         *(newb + i)= *bezt;
274                         
275                         /* add the beztriples that occur after the beztriple to be pasted (originally in icu) */
276                         if (i < fcu->totvert) 
277                                 memcpy(newb+i+1, fcu->bezt+i, (fcu->totvert-i)*sizeof(BezTriple));
278                         
279                         /* replace (+ free) old with new */
280                         MEM_freeN(fcu->bezt);
281                         fcu->bezt= newb;
282                         
283                         fcu->totvert++;
284                 }
285         }
286         else {
287                 // TODO: need to check for old sample-data now...
288                 fcu->bezt= MEM_callocN(sizeof(BezTriple), "beztriple");
289                 *(fcu->bezt)= *bezt;
290                 fcu->totvert= 1;
291         }
292         
293         
294         /* we need to return the index, so that some tools which do post-processing can 
295          * detect where we added the BezTriple in the array
296          */
297         return i;
298 }
299
300 /* This function is a wrapper for insert_bezt_icu, and should be used when
301  * adding a new keyframe to a curve, when the keyframe doesn't exist anywhere
302  * else yet. 
303  * 
304  * 'fast' - is only for the python API where importing BVH's would take an extreamly long time.
305  */
306 void insert_vert_fcurve (FCurve *fcu, float x, float y, short fast)
307 {
308         BezTriple beztr;
309         int a;
310         
311         /* set all three points, for nicer start position */
312         memset(&beztr, 0, sizeof(BezTriple));
313         beztr.vec[0][0]= x; 
314         beztr.vec[0][1]= y;
315         beztr.vec[1][0]= x;
316         beztr.vec[1][1]= y;
317         beztr.vec[2][0]= x;
318         beztr.vec[2][1]= y;
319         beztr.ipo= U.ipo_new; /* use default interpolation mode here... */
320         beztr.f1= beztr.f2= beztr.f3= SELECT;
321         beztr.h1= beztr.h2= HD_AUTO; // XXX what about when we replace an old one?
322         
323         /* add temp beztriple to keyframes */
324         a= insert_bezt_fcurve(fcu, &beztr);
325         
326         /* what if 'a' is a negative index? 
327          * for now, just exit to prevent any segfaults
328          */
329         if (a < 0) return;
330         
331         /* don't recalculate handles if fast is set
332          *      - this is a hack to make importers faster
333          *      - we may calculate twice (see editipo_changed(), due to autohandle needing two calculations)
334          */
335         if (!fast) calchandles_fcurve(fcu);
336         
337         /* set handletype and interpolation */
338         if (fcu->totvert > 2) {
339                 BezTriple *bezt= (fcu->bezt + a);
340                 char h1, h2;
341                 
342                 /* set handles (autohandles by default) */
343                 h1= h2= HD_AUTO;
344                 
345                 if (a > 0) h1= (bezt-1)->h2;
346                 if (a < fcu->totvert-1) h2= (bezt+1)->h1;
347                 
348                 bezt->h1= h1;
349                 bezt->h2= h2;
350                 
351                 /* set interpolation from previous (if available) */
352                 if (a > 0) bezt->ipo= (bezt-1)->ipo;
353                 else if (a < fcu->totvert-1) bezt->ipo= (bezt+1)->ipo;
354                         
355                 /* don't recalculate handles if fast is set
356                  *      - this is a hack to make importers faster
357                  *      - we may calculate twice (see editipo_changed(), due to autohandle needing two calculations)
358                  */
359                 if (!fast) calchandles_fcurve(fcu);
360         }
361 }
362
363 /* -------------- 'Smarter' Keyframing Functions -------------------- */
364 /* return codes for new_key_needed */
365 enum {
366         KEYNEEDED_DONTADD = 0,
367         KEYNEEDED_JUSTADD,
368         KEYNEEDED_DELPREV,
369         KEYNEEDED_DELNEXT
370 } eKeyNeededStatus;
371
372 /* This helper function determines whether a new keyframe is needed */
373 /* Cases where keyframes should not be added:
374  *      1. Keyframe to be added bewteen two keyframes with similar values
375  *      2. Keyframe to be added on frame where two keyframes are already situated
376  *      3. Keyframe lies at point that intersects the linear line between two keyframes
377  */
378 static short new_key_needed (FCurve *fcu, float cFrame, float nValue) 
379 {
380         BezTriple *bezt=NULL, *prev=NULL;
381         int totCount, i;
382         float valA = 0.0f, valB = 0.0f;
383         
384         /* safety checking */
385         if (fcu == NULL) return KEYNEEDED_JUSTADD;
386         totCount= fcu->totvert;
387         if (totCount == 0) return KEYNEEDED_JUSTADD;
388         
389         /* loop through checking if any are the same */
390         bezt= fcu->bezt;
391         for (i=0; i<totCount; i++) {
392                 float prevPosi=0.0f, prevVal=0.0f;
393                 float beztPosi=0.0f, beztVal=0.0f;
394                         
395                 /* get current time+value */    
396                 beztPosi= bezt->vec[1][0];
397                 beztVal= bezt->vec[1][1];
398                         
399                 if (prev) {
400                         /* there is a keyframe before the one currently being examined */               
401                         
402                         /* get previous time+value */
403                         prevPosi= prev->vec[1][0];
404                         prevVal= prev->vec[1][1];
405                         
406                         /* keyframe to be added at point where there are already two similar points? */
407                         if (IS_EQ(prevPosi, cFrame) && IS_EQ(beztPosi, cFrame) && IS_EQ(beztPosi, prevPosi)) {
408                                 return KEYNEEDED_DONTADD;
409                         }
410                         
411                         /* keyframe between prev+current points ? */
412                         if ((prevPosi <= cFrame) && (cFrame <= beztPosi)) {
413                                 /* is the value of keyframe to be added the same as keyframes on either side ? */
414                                 if (IS_EQ(prevVal, nValue) && IS_EQ(beztVal, nValue) && IS_EQ(prevVal, beztVal)) {
415                                         return KEYNEEDED_DONTADD;
416                                 }
417                                 else {
418                                         float realVal;
419                                         
420                                         /* get real value of curve at that point */
421                                         realVal= evaluate_fcurve(fcu, cFrame);
422                                         
423                                         /* compare whether it's the same as proposed */
424                                         if (IS_EQ(realVal, nValue)) 
425                                                 return KEYNEEDED_DONTADD;
426                                         else 
427                                                 return KEYNEEDED_JUSTADD;
428                                 }
429                         }
430                         
431                         /* new keyframe before prev beztriple? */
432                         if (cFrame < prevPosi) {
433                                 /* A new keyframe will be added. However, whether the previous beztriple
434                                  * stays around or not depends on whether the values of previous/current
435                                  * beztriples and new keyframe are the same.
436                                  */
437                                 if (IS_EQ(prevVal, nValue) && IS_EQ(beztVal, nValue) && IS_EQ(prevVal, beztVal))
438                                         return KEYNEEDED_DELNEXT;
439                                 else 
440                                         return KEYNEEDED_JUSTADD;
441                         }
442                 }
443                 else {
444                         /* just add a keyframe if there's only one keyframe 
445                          * and the new one occurs before the exisiting one does.
446                          */
447                         if ((cFrame < beztPosi) && (totCount==1))
448                                 return KEYNEEDED_JUSTADD;
449                 }
450                 
451                 /* continue. frame to do not yet passed (or other conditions not met) */
452                 if (i < (totCount-1)) {
453                         prev= bezt;
454                         bezt++;
455                 }
456                 else
457                         break;
458         }
459         
460         /* Frame in which to add a new-keyframe occurs after all other keys
461          * -> If there are at least two existing keyframes, then if the values of the
462          *       last two keyframes and the new-keyframe match, the last existing keyframe
463          *       gets deleted as it is no longer required.
464          * -> Otherwise, a keyframe is just added. 1.0 is added so that fake-2nd-to-last
465          *       keyframe is not equal to last keyframe.
466          */
467         bezt= (fcu->bezt + (fcu->totvert - 1));
468         valA= bezt->vec[1][1];
469         
470         if (prev)
471                 valB= prev->vec[1][1];
472         else 
473                 valB= bezt->vec[1][1] + 1.0f; 
474                 
475         if (IS_EQ(valA, nValue) && IS_EQ(valA, valB)) 
476                 return KEYNEEDED_DELPREV;
477         else 
478                 return KEYNEEDED_JUSTADD;
479 }
480
481 /* ------------------ RNA Data-Access Functions ------------------ */
482
483 /* Try to read value using RNA-properties obtained already */
484 static float setting_get_rna_value (PointerRNA *ptr, PropertyRNA *prop, int index)
485 {
486         float value= 0.0f;
487         
488         switch (RNA_property_type(ptr, prop)) {
489                 case PROP_BOOLEAN:
490                         if (RNA_property_array_length(ptr, prop))
491                                 value= (float)RNA_property_boolean_get_index(ptr, prop, index);
492                         else
493                                 value= (float)RNA_property_boolean_get(ptr, prop);
494                         break;
495                 case PROP_INT:
496                         if (RNA_property_array_length(ptr, prop))
497                                 value= (float)RNA_property_int_get_index(ptr, prop, index);
498                         else
499                                 value= (float)RNA_property_int_get(ptr, prop);
500                         break;
501                 case PROP_FLOAT:
502                         if (RNA_property_array_length(ptr, prop))
503                                 value= RNA_property_float_get_index(ptr, prop, index);
504                         else
505                                 value= RNA_property_float_get(ptr, prop);
506                         break;
507                 case PROP_ENUM:
508                         value= (float)RNA_property_enum_get(ptr, prop);
509                         break;
510                 default:
511                         break;
512         }
513         
514         return value;
515 }
516
517 /* ------------------ 'Visual' Keyframing Functions ------------------ */
518
519 /* internal status codes for visualkey_can_use */
520 enum {
521         VISUALKEY_NONE = 0,
522         VISUALKEY_LOC,
523         VISUALKEY_ROT,
524 };
525
526 /* This helper function determines if visual-keyframing should be used when  
527  * inserting keyframes for the given channel. As visual-keyframing only works
528  * on Object and Pose-Channel blocks, this should only get called for those 
529  * blocktypes, when using "standard" keying but 'Visual Keying' option in Auto-Keying 
530  * settings is on.
531  */
532 static short visualkey_can_use (PointerRNA *ptr, PropertyRNA *prop)
533 {
534         //Object *ob= NULL;
535         bConstraint *con= NULL;
536         short searchtype= VISUALKEY_NONE;
537         
538 #if 0 //  XXX old animation system      
539         /* validate data */
540         if ((id == NULL) || (GS(id->name)!=ID_OB) || !(ELEM(blocktype, ID_OB, ID_PO))) 
541                 return 0;       
542         
543         /* get first constraint and determine type of keyframe constraints to check for*/
544         ob= (Object *)id;
545         
546         if (blocktype == ID_OB) {
547                 con= ob->constraints.first;
548                 
549                 if (ELEM3(adrcode, OB_LOC_X, OB_LOC_Y, OB_LOC_Z))
550                         searchtype= VISUALKEY_LOC;
551                 else if (ELEM3(adrcode, OB_ROT_X, OB_ROT_Y, OB_ROT_Z))
552                         searchtype= VISUALKEY_ROT;
553         }
554         else if (blocktype == ID_PO) {
555                 bPoseChannel *pchan= get_pose_channel(ob->pose, actname);
556                 con= pchan->constraints.first;
557                 
558                 if (ELEM3(adrcode, AC_LOC_X, AC_LOC_Y, AC_LOC_Z))
559                         searchtype= VISUALKEY_LOC;
560                 else if (ELEM4(adrcode, AC_QUAT_W, AC_QUAT_X, AC_QUAT_Y, AC_QUAT_Z))
561                         searchtype= VISUALKEY_ROT;
562         }
563 #endif
564         
565         /* only search if a searchtype and initial constraint are available */
566         if (searchtype && con) {
567                 for (; con; con= con->next) {
568                         /* only consider constraint if it is not disabled, and has influence */
569                         if (con->flag & CONSTRAINT_DISABLE) continue;
570                         if (con->enforce == 0.0f) continue;
571                         
572                         /* some constraints may alter these transforms */
573                         switch (con->type) {
574                                 /* multi-transform constraints */
575                                 case CONSTRAINT_TYPE_CHILDOF:
576                                         return 1;
577                                 case CONSTRAINT_TYPE_TRANSFORM:
578                                         return 1;
579                                 case CONSTRAINT_TYPE_FOLLOWPATH:
580                                         return 1;
581                                 case CONSTRAINT_TYPE_KINEMATIC:
582                                         return 1;
583                                         
584                                 /* single-transform constraits  */
585                                 case CONSTRAINT_TYPE_TRACKTO:
586                                         if (searchtype==VISUALKEY_ROT) return 1;
587                                         break;
588                                 case CONSTRAINT_TYPE_ROTLIMIT:
589                                         if (searchtype==VISUALKEY_ROT) return 1;
590                                         break;
591                                 case CONSTRAINT_TYPE_LOCLIMIT:
592                                         if (searchtype==VISUALKEY_LOC) return 1;
593                                         break;
594                                 case CONSTRAINT_TYPE_ROTLIKE:
595                                         if (searchtype==VISUALKEY_ROT) return 1;
596                                         break;
597                                 case CONSTRAINT_TYPE_DISTLIMIT:
598                                         if (searchtype==VISUALKEY_LOC) return 1;
599                                         break;
600                                 case CONSTRAINT_TYPE_LOCLIKE:
601                                         if (searchtype==VISUALKEY_LOC) return 1;
602                                         break;
603                                 case CONSTRAINT_TYPE_LOCKTRACK:
604                                         if (searchtype==VISUALKEY_ROT) return 1;
605                                         break;
606                                 case CONSTRAINT_TYPE_MINMAX:
607                                         if (searchtype==VISUALKEY_LOC) return 1;
608                                         break;
609                                 
610                                 default:
611                                         break;
612                         }
613                 }
614         }
615         
616         /* when some condition is met, this function returns, so here it can be 0 */
617         return 0;
618 }
619
620 /* This helper function extracts the value to use for visual-keyframing 
621  * In the event that it is not possible to perform visual keying, try to fall-back
622  * to using the default method. Assumes that all data it has been passed is valid.
623  */
624 // xxx... ptr here should be struct that data is in.... prop is the channel that's being used
625 static float visualkey_get_value (PointerRNA *ptr, PropertyRNA *prop, int array_index)
626 {
627 #if 0 // XXX old animation system
628         Object *ob;
629         void *poin = NULL;
630         int index, vartype;
631         
632         /* validate situtation */
633         if ((id==NULL) || (GS(id->name)!=ID_OB) || (ELEM(blocktype, ID_OB, ID_PO)==0))
634                 return 0.0f;
635                 
636         /* get object */
637         ob= (Object *)id;
638         
639         /* only valid for objects or posechannels */
640         if (blocktype == ID_OB) {
641                 /* parented objects are not supported, as the effects of the parent
642                  * are included in the matrix, which kindof beats the point
643                  */
644                 if (ob->parent == NULL) {
645                         /* only Location or Rotation keyframes are supported now */
646                         if (ELEM3(adrcode, OB_LOC_X, OB_LOC_Y, OB_LOC_Z)) {
647                                 /* assumes that OB_LOC_Z > OB_LOC_Y > OB_LOC_X */
648                                 index= adrcode - OB_LOC_X;
649                                 
650                                 return ob->obmat[3][index];
651                         }
652                         else if (ELEM3(adrcode, OB_ROT_X, OB_ROT_Y, OB_ROT_Z)) {
653                                 float eul[3];
654                                 
655                                 /* assumes that OB_ROT_Z > OB_ROT_Y > OB_ROT_X */
656                                 index= adrcode - OB_ROT_X;
657                                 
658                                 Mat4ToEul(ob->obmat, eul);
659                                 return eul[index]*(5.72958f);
660                         }
661                 }
662         }
663         else if (blocktype == ID_PO) {
664                 bPoseChannel *pchan;
665                 float tmat[4][4];
666                 
667                 /* get data to use */
668                 pchan= get_pose_channel(ob->pose, actname);
669                 
670                 /* Although it is not strictly required for this particular space conversion, 
671                  * arg1 must not be null, as there is a null check for the other conversions to
672                  * be safe. Therefore, the active object is passed here, and in many cases, this
673                  * will be what owns the pose-channel that is getting this anyway.
674                  */
675                 Mat4CpyMat4(tmat, pchan->pose_mat);
676                 constraint_mat_convertspace(ob, pchan, tmat, CONSTRAINT_SPACE_POSE, CONSTRAINT_SPACE_LOCAL);
677                 
678                 /* Loc, Rot/Quat keyframes are supported... */
679                 if (ELEM3(adrcode, AC_LOC_X, AC_LOC_Y, AC_LOC_Z)) {
680                         /* assumes that AC_LOC_Z > AC_LOC_Y > AC_LOC_X */
681                         index= adrcode - AC_LOC_X;
682                         
683                         /* only use for non-connected bones */
684                         if ((pchan->bone->parent) && !(pchan->bone->flag & BONE_CONNECTED))
685                                 return tmat[3][index];
686                         else if (pchan->bone->parent == NULL)
687                                 return tmat[3][index];
688                 }
689                 else if (ELEM4(adrcode, AC_QUAT_W, AC_QUAT_X, AC_QUAT_Y, AC_QUAT_Z)) {
690                         float trimat[3][3], quat[4];
691                         
692                         /* assumes that AC_QUAT_Z > AC_QUAT_Y > AC_QUAT_X > AC_QUAT_W */
693                         index= adrcode - AC_QUAT_W;
694                         
695                         Mat3CpyMat4(trimat, tmat);
696                         Mat3ToQuat_is_ok(trimat, quat);
697                         
698                         return quat[index];
699                 }
700         }
701 #endif  // XXX old animation system
702         
703         /* as the function hasn't returned yet, read value from system in the default way */
704         return setting_get_rna_value(ptr, prop, array_index);
705 }
706
707 /* ------------------------- Insert Key API ------------------------- */
708
709 /* Main Keyframing API call:
710  *      Use this when validation of necessary animation data isn't necessary as it
711  *      already exists. It will insert a keyframe using the current value being keyframed.
712  *      
713  *      The flag argument is used for special settings that alter the behaviour of
714  *      the keyframe insertion. These include the 'visual' keyframing modes, quick refresh,
715  *      and extra keyframe filtering.
716  */
717 short insertkey (ID *id, const char group[], const char rna_path[], int array_index, float cfra, short flag)
718 {       
719         PointerRNA id_ptr, ptr;
720         PropertyRNA *prop;
721         FCurve *fcu;
722         
723         /* validate pointer first - exit if failure*/
724         RNA_id_pointer_create(id, &id_ptr);
725         if (RNA_path_resolve(&id_ptr, rna_path, &ptr, &prop) == 0) {
726                 printf("Insert Key: Could not insert keyframe, as RNA Path is invalid for the given ID \n");
727                 return 0;
728         }
729         
730         /* get F-Curve */
731         fcu= verify_fcurve(id, group, rna_path, array_index, 1);
732         
733         /* only continue if we have an F-Curve to add keyframe to */
734         if (fcu) {
735                 float curval= 0.0f;
736                 
737                 /* apply special time tweaking */
738                         // XXX check on this stuff...
739                 if (GS(id->name) == ID_OB) {
740                         //Object *ob= (Object *)id;
741                         
742                         /* apply NLA-scaling (if applicable) */
743                         //cfra= get_action_frame(ob, cfra);
744                         
745                         /* ancient time-offset cruft */
746                         //if ( (ob->ipoflag & OB_OFFS_OB) && (give_timeoffset(ob)) ) {
747                         //      /* actually frametofloat calc again! */
748                         //      cfra-= give_timeoffset(ob)*scene->r.framelen;
749                         //}
750                 }
751                 
752                 /* obtain value to give keyframe */
753                 if ( (flag & INSERTKEY_MATRIX) && 
754                          (visualkey_can_use(&ptr, prop)) ) 
755                 {
756                         /* visual-keying is only available for object and pchan datablocks, as 
757                          * it works by keyframing using a value extracted from the final matrix 
758                          * instead of using the kt system to extract a value.
759                          */
760                         curval= visualkey_get_value(&ptr, prop, array_index);
761                 }
762                 else {
763                         /* read value from system */
764                         curval= setting_get_rna_value(&ptr, prop, array_index);
765                 }
766                 
767                 /* only insert keyframes where they are needed */
768                 if (flag & INSERTKEY_NEEDED) {
769                         short insert_mode;
770                         
771                         /* check whether this curve really needs a new keyframe */
772                         insert_mode= new_key_needed(fcu, cfra, curval);
773                         
774                         /* insert new keyframe at current frame */
775                         if (insert_mode)
776                                 insert_vert_fcurve(fcu, cfra, curval, (flag & INSERTKEY_FAST));
777                         
778                         /* delete keyframe immediately before/after newly added */
779                         switch (insert_mode) {
780                                 case KEYNEEDED_DELPREV:
781                                         delete_fcurve_key(fcu, fcu->totvert-2, 1);
782                                         break;
783                                 case KEYNEEDED_DELNEXT:
784                                         delete_fcurve_key(fcu, 1, 1);
785                                         break;
786                         }
787                         
788                         /* only return success if keyframe added */
789                         if (insert_mode)
790                                 return 1;
791                 }
792                 else {
793                         /* just insert keyframe */
794                         insert_vert_fcurve(fcu, cfra, curval, (flag & INSERTKEY_FAST));
795                         
796                         /* return success */
797                         return 1;
798                 }
799         }
800         
801         /* return failure */
802         return 0;
803 }
804
805 /* ************************************************** */
806 /* KEYFRAME DELETION */
807
808 /* Main Keyframing API call:
809  *      Use this when validation of necessary animation data isn't necessary as it
810  *      already exists. It will delete a keyframe at the current frame.
811  *      
812  *      The flag argument is used for special settings that alter the behaviour of
813  *      the keyframe deletion. These include the quick refresh options.
814  */
815 short deletekey (ID *id, const char group[], const char rna_path[], int array_index, float cfra, short flag)
816 {
817         AnimData *adt;
818         FCurve *fcu;
819         
820         /* get F-Curve
821          * Note: here is one of the places where we don't want new Action + F-Curve added!
822          *              so 'add' var must be 0
823          */
824         // XXX we don't check the validity of the path here yet, but it should be ok...
825         fcu= verify_fcurve(id, group, rna_path, array_index, 0);
826         adt= BKE_animdata_from_id(id);
827         
828         /* only continue if we have an ipo-curve to remove keyframes from */
829         if (adt && adt->action && fcu) {
830                 bAction *act= adt->action;
831                 short found = -1;
832                 int i;
833                 
834                 /* apply special time tweaking */
835                 if (GS(id->name) == ID_OB) {
836                         //Object *ob= (Object *)id;
837                         
838                         /* apply NLA-scaling (if applicable) */
839                         //      cfra= get_action_frame(ob, cfra);
840                         
841                         /* ancient time-offset cruft */
842                         //if ( (ob->ipoflag & OB_OFFS_OB) && (give_timeoffset(ob)) ) {
843                         //      /* actually frametofloat calc again! */
844                         //      cfra-= give_timeoffset(ob)*scene->r.framelen;
845                         //}
846                 }
847                 
848                 /* try to find index of beztriple to get rid of */
849                 i = binarysearch_bezt_index(fcu->bezt, cfra, fcu->totvert, &found);
850                 if (found) {                    
851                         /* delete the key at the index (will sanity check + do recalc afterwards) */
852                         delete_fcurve_key(fcu, i, 1);
853                         
854                         /* Only delete curve too if there are no points (we don't need to check for drivers, as they're kept separate) */
855                         // XXX how do we handle drivers then?
856                         if (fcu->totvert == 0) {
857                                 BLI_remlink(&act->curves, fcu);
858                                 free_fcurve(fcu);
859                         }
860                         
861                         /* return success */
862                         return 1;
863                 }
864         }
865         
866         /* return failure */
867         return 0;
868 }
869
870 /* ******************************************* */
871 /* KEYFRAME MODIFICATION */
872
873 /* mode for common_modifykey */
874 enum {
875         COMMONKEY_MODE_INSERT = 0,
876         COMMONKEY_MODE_DELETE,
877 } eCommonModifyKey_Modes;
878
879
880 /* Build menu-string of available keying-sets (allocates memory for string)
881  * NOTE: mode must not be longer than 64 chars
882  */
883 char *ANIM_build_keyingsets_menu (ListBase *list, short for_edit)
884 {
885         DynStr *pupds= BLI_dynstr_new();
886         KeyingSet *ks;
887         char buf[64];
888         char *str;
889         int i;
890         
891         /* add title first */
892         BLI_dynstr_append(pupds, "Keying Sets%t|");
893         
894         /* add dummy entries for none-active */
895         if (for_edit) { 
896                 BLI_dynstr_append(pupds, "Add New%x-1|");
897                 BLI_dynstr_append(pupds, " %x0|");
898         }
899         else
900                 BLI_dynstr_append(pupds, "<No Keying Set Active>%x0|");
901         
902         /* loop through keyingsets, adding them */
903         for (ks=list->first, i=1; ks; ks=ks->next, i++) {
904                 if (for_edit == 0)
905                         BLI_dynstr_append(pupds, "KS: ");
906                 
907                 BLI_dynstr_append(pupds, ks->name);
908                 BLI_snprintf( buf, 64, "%%x%d%s", i, ((ks->next)?"|":"") );
909                 BLI_dynstr_append(pupds, buf);
910         }
911         
912         /* convert to normal MEM_malloc'd string */
913         str= BLI_dynstr_get_cstring(pupds);
914         BLI_dynstr_free(pupds);
915         
916         return str;
917 }
918
919 #if 0 // XXX old keyingsets code based on adrcodes... to be restored in due course
920
921 /* --------- KeyingSet Adrcode Getters ------------ */
922
923 /* initialise a channel-getter storage */
924 static void ks_adrcodegetter_init (bKS_AdrcodeGetter *kag, bKeyingSet *ks, bCommonKeySrc *cks)
925 {
926         /* error checking */
927         if (kag == NULL)
928                 return;
929         
930         if (ELEM(NULL, ks, cks)) {
931                 /* set invalid settings that won't cause harm */
932                 kag->ks= NULL;
933                 kag->cks= NULL;
934                 kag->index= -2;
935                 kag->tot= 0;
936         }
937         else {
938                 /* store settings */
939                 kag->ks= ks;
940                 kag->cks= cks;
941                 
942                 /* - index is -1, as that allows iterators to return first element
943                  * - tot is chan_num by default, but may get overriden if -1 is encountered (for extension-type getters)
944                  */
945                 kag->index= -1;
946                 kag->tot= ks->chan_num;
947         }
948 }
949
950 /* 'default' channel-getter that will be used when iterating through keyingset's channels 
951  *       - iteration will stop when adrcode <= 0 is encountered, so we use that as escape
952  */
953 static short ks_getnextadrcode_default (bKS_AdrcodeGetter *kag)
954 {       
955         bKeyingSet *ks= (kag)? kag->ks : NULL;
956         
957         /* error checking */
958         if (ELEM(NULL, kag, ks)) return 0;
959         if (kag->tot <= 0) return 0;
960         
961         kag->index++;
962         if ((kag->index < 0) || (kag->index >= kag->tot)) return 0;
963         
964         /* return the adrcode stored at index then */
965         return ks->adrcodes[kag->index];
966 }
967
968 /* add map flag (for MTex channels, as certain ones need special offset) */
969 static short ks_getnextadrcode_addmap (bKS_AdrcodeGetter *kag)
970 {
971         short adrcode= ks_getnextadrcode_default(kag);
972         
973         /* if there was an adrcode returned, assume that kag stuff is set ok */
974         if (adrcode) {
975                 bCommonKeySrc *cks= kag->cks;
976                 bKeyingSet *ks= kag->ks;
977                 
978                 if (ELEM3(ks->blocktype, ID_MA, ID_LA, ID_WO)) {
979                         switch (adrcode) {
980                                 case MAP_OFS_X: case MAP_OFS_Y: case MAP_OFS_Z:
981                                 case MAP_SIZE_X: case MAP_SIZE_Y: case MAP_SIZE_Z:
982                                 case MAP_R: case MAP_G: case MAP_B: case MAP_DVAR:
983                                 case MAP_COLF: case MAP_NORF: case MAP_VARF: case MAP_DISP:
984                                         adrcode += cks->map;
985                                         break;
986                         }
987                 }
988         }
989         
990         /* adrcode must be returned! */
991         return adrcode;
992 }
993
994 /* extend posechannel keyingsets with rotation info (when KAG_CHAN_EXTEND is encountered) 
995  *      - iteration will stop when adrcode <= 0 is encountered, so we use that as escape
996  *      - when we encounter KAG_CHAN_EXTEND as adrcode, start returning our own
997  */
998 static short ks_getnextadrcode_pchanrot (bKS_AdrcodeGetter *kag)
999 {       
1000         /* hardcoded adrcode channels used here only 
1001          *      - length is keyed-channels + 1 (last item must be 0 to escape)
1002          */
1003         static short quat_adrcodes[5] = {AC_QUAT_W, AC_QUAT_X, AC_QUAT_Y, AC_QUAT_Z, 0};
1004         static short eul_adrcodes[4] = {AC_EUL_X, AC_EUL_Y, AC_EUL_Z, 0};
1005                 
1006         /* useful variables */
1007         bKeyingSet *ks= (kag)? kag->ks : NULL;
1008         bCommonKeySrc *cks= (kag) ? kag->cks : NULL;
1009         short index, adrcode;
1010         
1011         /* error checking */
1012         if (ELEM3(NULL, kag, ks, cks)) return 0;
1013         if (ks->chan_num <= 0) return 0;
1014         
1015         /* get index 
1016          *      - if past the last item (kag->tot), return stuff from our static arrays
1017          *      - otherwise, just keep returning stuff from the keyingset (but check out for -1!) 
1018          */
1019         kag->index++;
1020         if (kag->index < 0)
1021                 return 0;
1022         
1023         /* normal (static stuff) */
1024         if (kag->index < kag->tot) {
1025                 /* get adrcode, and return if not KAG_CHAN_EXTEND (i.e. point for start of iteration) */
1026                 adrcode= ks->adrcodes[kag->index];
1027                 
1028                 if (adrcode != KAG_CHAN_EXTEND) 
1029                         return adrcode;
1030                 else    
1031                         kag->tot= kag->index;
1032         }
1033                 
1034         /* based on current rotation-mode
1035          *      - index can be at most 5, if we are to prevent segfaults
1036          */
1037         index= kag->index - kag->tot;
1038         if ((index < 0) || (index > 5))
1039                 return 0;
1040         
1041         if (cks->pchan && cks->pchan->rotmode)
1042                 return eul_adrcodes[index];
1043         else
1044                 return quat_adrcodes[index];
1045 }
1046
1047 /* ------------- KeyingSet Defines ------------ */
1048 /* Note: these must all be named with the defks_* prefix, otherwise the template macro will not work! */
1049
1050 /* macro for defining keyingset contexts */
1051 #define KSC_TEMPLATE(ctx_name) {&defks_##ctx_name[0], NULL, sizeof(defks_##ctx_name)/sizeof(bKeyingSet)}
1052
1053 /* --- */
1054
1055 /* check if option not available for deleting keys */
1056 static short incl_non_del_keys (bKeyingSet *ks, const char mode[])
1057 {
1058         /* as optimisation, assume that it is sufficient to check only first letter
1059          * of mode (int comparison should be faster than string!)
1060          */
1061         //if (strcmp(mode, "Delete")==0)
1062         if (mode && mode[0]=='D')
1063                 return 0;
1064         
1065         return 1;
1066 }
1067
1068 /* Object KeyingSets  ------ */
1069
1070 /* check if include shapekey entry  */
1071 static short incl_v3d_ob_shapekey (bKeyingSet *ks, const char mode[])
1072 {
1073         //Object *ob= (G.obedit)? (G.obedit) : (OBACT); // XXX
1074         Object *ob= NULL;
1075         char *newname= NULL;
1076         
1077         if(ob==NULL)
1078                 return 0;
1079         
1080         /* not available for delete mode */
1081         if (strcmp(mode, "Delete")==0)
1082                 return 0;
1083         
1084         /* check if is geom object that can get shapekeys */
1085         switch (ob->type) {
1086                 /* geometry? */
1087                 case OB_MESH:           newname= "Mesh";                break;
1088                 case OB_CURVE:          newname= "Curve";               break;
1089                 case OB_SURF:           newname= "Surface";             break;
1090                 case OB_LATTICE:        newname= "Lattice";             break;
1091                 
1092                 /* not geometry! */
1093                 default:
1094                         return 0;
1095         }
1096         
1097         /* if ks is shapekey entry (this could be callled for separator before too!) */
1098         if (ks->flag == -3)
1099                 BLI_strncpy(ks->name, newname, sizeof(ks->name));
1100         
1101         /* if it gets here, it's ok */
1102         return 1;
1103 }
1104
1105 /* array for object keyingset defines */
1106 bKeyingSet defks_v3d_object[] = 
1107 {
1108         /* include_cb, adrcode-getter, name, blocktype, flag, chan_num, adrcodes */
1109         {NULL, "Loc", ID_OB, 0, 3, {OB_LOC_X,OB_LOC_Y,OB_LOC_Z}},
1110         {NULL, "Rot", ID_OB, 0, 3, {OB_ROT_X,OB_ROT_Y,OB_ROT_Z}},
1111         {NULL, "Scale", ID_OB, 0, 3, {OB_SIZE_X,OB_SIZE_Y,OB_SIZE_Z}},
1112         
1113         {NULL, "%l", 0, -1, 0, {0}}, // separator
1114         
1115         {NULL, "LocRot", ID_OB, 0, 6, 
1116                 {OB_LOC_X,OB_LOC_Y,OB_LOC_Z,
1117                  OB_ROT_X,OB_ROT_Y,OB_ROT_Z}},
1118                  
1119         {NULL, "LocScale", ID_OB, 0, 6, 
1120                 {OB_LOC_X,OB_LOC_Y,OB_LOC_Z,
1121                  OB_SIZE_X,OB_SIZE_Y,OB_SIZE_Z}},
1122                  
1123         {NULL, "LocRotScale", ID_OB, 0, 9, 
1124                 {OB_LOC_X,OB_LOC_Y,OB_LOC_Z,
1125                  OB_ROT_X,OB_ROT_Y,OB_ROT_Z,
1126                  OB_SIZE_X,OB_SIZE_Y,OB_SIZE_Z}},
1127                  
1128         {NULL, "RotScale", ID_OB, 0, 6, 
1129                 {OB_ROT_X,OB_ROT_Y,OB_ROT_Z,
1130                  OB_SIZE_X,OB_SIZE_Y,OB_SIZE_Z}},
1131         
1132         {incl_non_del_keys, "%l", 0, -1, 0, {0}}, // separator
1133         
1134         {incl_non_del_keys, "VisualLoc", ID_OB, INSERTKEY_MATRIX, 3, {OB_LOC_X,OB_LOC_Y,OB_LOC_Z}},
1135         {incl_non_del_keys, "VisualRot", ID_OB, INSERTKEY_MATRIX, 3, {OB_ROT_X,OB_ROT_Y,OB_ROT_Z}},
1136         
1137         {incl_non_del_keys, "VisualLocRot", ID_OB, INSERTKEY_MATRIX, 6, 
1138                 {OB_LOC_X,OB_LOC_Y,OB_LOC_Z,
1139                  OB_ROT_X,OB_ROT_Y,OB_ROT_Z}},
1140         
1141         {NULL, "%l", 0, -1, 0, {0}}, // separator
1142         
1143         {NULL, "Layer", ID_OB, 0, 1, {OB_LAY}}, // icky option...
1144         {NULL, "Available", ID_OB, -2, 0, {0}},
1145         
1146         {incl_v3d_ob_shapekey, "%l%l", 0, -1, 0, {0}}, // separator (linked to shapekey entry)
1147         {incl_v3d_ob_shapekey, "<ShapeKey>", ID_OB, -3, 0, {0}}
1148 };
1149
1150 /* PoseChannel KeyingSets  ------ */
1151
1152 /* array for posechannel keyingset defines */
1153 bKeyingSet defks_v3d_pchan[] = 
1154 {
1155         /* include_cb, name, blocktype, flag, chan_num, adrcodes */
1156         {NULL, "Loc", ID_PO, 0, 3, {AC_LOC_X,AC_LOC_Y,AC_LOC_Z}},
1157         {NULL, "Rot", ID_PO, COMMONKEY_PCHANROT, 1, {KAG_CHAN_EXTEND}},
1158         {NULL, "Scale", ID_PO, 0, 3, {AC_SIZE_X,AC_SIZE_Y,AC_SIZE_Z}},
1159         
1160         {NULL, "%l", 0, -1, 0, {0}}, // separator
1161         
1162         {NULL, "LocRot", ID_PO, COMMONKEY_PCHANROT, 4, 
1163                 {AC_LOC_X,AC_LOC_Y,AC_LOC_Z,
1164                  KAG_CHAN_EXTEND}},
1165                  
1166         {NULL, "LocScale", ID_PO, 0, 6, 
1167                 {AC_LOC_X,AC_LOC_Y,AC_LOC_Z,
1168                  AC_SIZE_X,AC_SIZE_Y,AC_SIZE_Z}},
1169                  
1170         {NULL, "LocRotScale", ID_PO, COMMONKEY_PCHANROT, 7, 
1171                 {AC_LOC_X,AC_LOC_Y,AC_LOC_Z,AC_SIZE_X,AC_SIZE_Y,AC_SIZE_Z, 
1172                  KAG_CHAN_EXTEND}},
1173                  
1174         {NULL, "RotScale", ID_PO, 0, 4, 
1175                 {AC_SIZE_X,AC_SIZE_Y,AC_SIZE_Z, 
1176                  KAG_CHAN_EXTEND}},
1177         
1178         {incl_non_del_keys, "%l", 0, -1, 0, {0}}, // separator
1179         
1180         {incl_non_del_keys, "VisualLoc", ID_PO, INSERTKEY_MATRIX, 3, {AC_LOC_X,AC_LOC_Y,AC_LOC_Z}},
1181         {incl_non_del_keys, "VisualRot", ID_PO, INSERTKEY_MATRIX|COMMONKEY_PCHANROT, 1, {KAG_CHAN_EXTEND}},
1182         
1183         {incl_non_del_keys, "VisualLocRot", ID_PO, INSERTKEY_MATRIX|COMMONKEY_PCHANROT, 4, 
1184                 {AC_LOC_X,AC_LOC_Y,AC_LOC_Z, KAG_CHAN_EXTEND}},
1185         
1186         {NULL, "%l", 0, -1, 0, {0}}, // separator
1187         
1188         {NULL, "Available", ID_PO, -2, 0, {0}}
1189 };
1190
1191 /* Material KeyingSets  ------ */
1192
1193 /* array for material keyingset defines */
1194 bKeyingSet defks_buts_shading_mat[] = 
1195 {
1196         /* include_cb, name, blocktype, flag, chan_num, adrcodes */
1197         {NULL, "RGB", ID_MA, 0, 3, {MA_COL_R,MA_COL_G,MA_COL_B}},
1198         {NULL, "Alpha", ID_MA, 0, 1, {MA_ALPHA}},
1199         {NULL, "Halo Size", ID_MA, 0, 1, {MA_HASIZE}},
1200         {NULL, "Mode", ID_MA, 0, 1, {MA_MODE}}, // evil bitflags
1201         
1202         {NULL, "%l", 0, -1, 0, {0}}, // separator
1203         
1204         {NULL, "All Color", ID_MA, 0, 18, 
1205                 {MA_COL_R,MA_COL_G,MA_COL_B,
1206                  MA_ALPHA,MA_HASIZE, MA_MODE,
1207                  MA_SPEC_R,MA_SPEC_G,MA_SPEC_B,
1208                  MA_REF,MA_EMIT,MA_AMB,MA_SPEC,MA_HARD,
1209                  MA_MODE,MA_TRANSLU,MA_ADD}},
1210                  
1211         {NULL, "All Mirror", ID_MA, 0, 5, 
1212                 {MA_RAYM,MA_FRESMIR,MA_FRESMIRI,
1213                  MA_FRESTRA,MA_FRESTRAI}},
1214         
1215         {NULL, "%l", 0, -1, 0, {0}}, // separator
1216         
1217         {NULL, "Ofs", ID_MA, COMMONKEY_ADDMAP, 3, {MAP_OFS_X,MAP_OFS_Y,MAP_OFS_Z}},
1218         {NULL, "Size", ID_MA, COMMONKEY_ADDMAP, 3, {MAP_SIZE_X,MAP_SIZE_Y,MAP_SIZE_Z}},
1219         
1220         {NULL, "All Mapping", ID_MA, COMMONKEY_ADDMAP, 14, 
1221                 {MAP_OFS_X,MAP_OFS_Y,MAP_OFS_Z,
1222                  MAP_SIZE_X,MAP_SIZE_Y,MAP_SIZE_Z,
1223                  MAP_R,MAP_G,MAP_B,MAP_DVAR,
1224                  MAP_COLF,MAP_NORF,MAP_VARF,MAP_DISP}},
1225         
1226         {NULL, "%l", 0, -1, 0, {0}}, // separator
1227         
1228         {NULL, "Available", ID_MA, -2, 0, {0}}
1229 };
1230
1231 /* World KeyingSets  ------ */
1232
1233 /* array for world keyingset defines */
1234 bKeyingSet defks_buts_shading_wo[] = 
1235 {
1236         /* include_cb, name, blocktype, flag, chan_num, adrcodes */
1237         {NULL, "Zenith RGB", ID_WO, 0, 3, {WO_ZEN_R,WO_ZEN_G,WO_ZEN_B}},
1238         {NULL, "Horizon RGB", ID_WO, 0, 3, {WO_HOR_R,WO_HOR_G,WO_HOR_B}},
1239         
1240         {NULL, "%l", 0, -1, 0, {0}}, // separator
1241         
1242         {NULL, "Mist", ID_WO, 0, 4, {WO_MISI,WO_MISTDI,WO_MISTSTA,WO_MISTHI}},
1243         {NULL, "Stars", ID_WO, 0, 5, {WO_STAR_R,WO_STAR_G,WO_STAR_B,WO_STARDIST,WO_STARSIZE}},
1244         
1245         
1246         {NULL, "%l", 0, -1, 0, {0}}, // separator
1247         
1248         {NULL, "Ofs", ID_WO, COMMONKEY_ADDMAP, 3, {MAP_OFS_X,MAP_OFS_Y,MAP_OFS_Z}},
1249         {NULL, "Size", ID_WO, COMMONKEY_ADDMAP, 3, {MAP_SIZE_X,MAP_SIZE_Y,MAP_SIZE_Z}},
1250         
1251         {NULL, "All Mapping", ID_WO, COMMONKEY_ADDMAP, 14, 
1252                 {MAP_OFS_X,MAP_OFS_Y,MAP_OFS_Z,
1253                  MAP_SIZE_X,MAP_SIZE_Y,MAP_SIZE_Z,
1254                  MAP_R,MAP_G,MAP_B,MAP_DVAR,
1255                  MAP_COLF,MAP_NORF,MAP_VARF,MAP_DISP}},
1256         
1257         {NULL, "%l", 0, -1, 0, {0}}, // separator
1258         
1259         {NULL, "Available", ID_WO, -2, 0, {0}}
1260 };
1261
1262 /* Lamp KeyingSets  ------ */
1263
1264 /* array for lamp keyingset defines */
1265 bKeyingSet defks_buts_shading_la[] = 
1266 {
1267         /* include_cb, name, blocktype, flag, chan_num, adrcodes */
1268         {NULL, "RGB", ID_LA, 0, 3, {LA_COL_R,LA_COL_G,LA_COL_B}},
1269         {NULL, "Energy", ID_LA, 0, 1, {LA_ENERGY}},
1270         {NULL, "Spot Size", ID_LA, 0, 1, {LA_SPOTSI}},
1271         
1272         {NULL, "%l", 0, -1, 0, {0}}, // separator
1273         
1274         {NULL, "Ofs", ID_LA, COMMONKEY_ADDMAP, 3, {MAP_OFS_X,MAP_OFS_Y,MAP_OFS_Z}},
1275         {NULL, "Size", ID_LA, COMMONKEY_ADDMAP, 3, {MAP_SIZE_X,MAP_SIZE_Y,MAP_SIZE_Z}},
1276         
1277         {NULL, "All Mapping", ID_LA, COMMONKEY_ADDMAP, 14, 
1278                 {MAP_OFS_X,MAP_OFS_Y,MAP_OFS_Z,
1279                  MAP_SIZE_X,MAP_SIZE_Y,MAP_SIZE_Z,
1280                  MAP_R,MAP_G,MAP_B,MAP_DVAR,
1281                  MAP_COLF,MAP_NORF,MAP_VARF,MAP_DISP}},
1282         
1283         {NULL, "%l", 0, -1, 0, {0}}, // separator
1284         
1285         {NULL, "Available", ID_LA, -2, 0, {0}}
1286 };
1287
1288 /* Texture KeyingSets  ------ */
1289
1290 /* array for texture keyingset defines */
1291 bKeyingSet defks_buts_shading_tex[] = 
1292 {
1293         /* include_cb, name, blocktype, flag, chan_num, adrcodes */
1294         {NULL, "Clouds", ID_TE, 0, 5, 
1295                 {TE_NSIZE,TE_NDEPTH,TE_NTYPE,
1296                  TE_MG_TYP,TE_N_BAS1}},
1297         
1298         {NULL, "Marble", ID_TE, 0, 7, 
1299                 {TE_NSIZE,TE_NDEPTH,TE_NTYPE,
1300                  TE_TURB,TE_MG_TYP,TE_N_BAS1,TE_N_BAS2}},
1301                  
1302         {NULL, "Stucci", ID_TE, 0, 5, 
1303                 {TE_NSIZE,TE_NTYPE,TE_TURB,
1304                  TE_MG_TYP,TE_N_BAS1}},
1305                  
1306         {NULL, "Wood", ID_TE, 0, 6, 
1307                 {TE_NSIZE,TE_NTYPE,TE_TURB,
1308                  TE_MG_TYP,TE_N_BAS1,TE_N_BAS2}},
1309                  
1310         {NULL, "Magic", ID_TE, 0, 2, {TE_NDEPTH,TE_TURB}},
1311         
1312         {NULL, "Blend", ID_TE, 0, 1, {TE_MG_TYP}},      
1313                 
1314         {NULL, "Musgrave", ID_TE, 0, 6, 
1315                 {TE_MG_TYP,TE_MGH,TE_MG_LAC,
1316                  TE_MG_OCT,TE_MG_OFF,TE_MG_GAIN}},
1317                  
1318         {NULL, "Voronoi", ID_TE, 0, 9, 
1319                 {TE_VNW1,TE_VNW2,TE_VNW3,TE_VNW4,
1320                 TE_VNMEXP,TE_VN_DISTM,TE_VN_COLT,
1321                 TE_ISCA,TE_NSIZE}},
1322                 
1323         {NULL, "Distorted Noise", ID_TE, 0, 4, 
1324                 {TE_MG_OCT,TE_MG_OFF,TE_MG_GAIN,TE_DISTA}},
1325         
1326         {NULL, "Color Filter", ID_TE, 0, 5, 
1327                 {TE_COL_R,TE_COL_G,TE_COL_B,TE_BRIGHT,TE_CONTRA}},
1328         
1329         {NULL, "%l", 0, -1, 0, {0}}, // separator
1330         
1331         {NULL, "Available", ID_TE, -2, 0, {0}}
1332 };
1333
1334 /* Object Buttons KeyingSets  ------ */
1335
1336 /* check if include particles entry  */
1337 static short incl_buts_ob (bKeyingSet *ks, const char mode[])
1338 {
1339         //Object *ob= OBACT; // xxx
1340         Object *ob= NULL;
1341         /* only if object is mesh type */
1342         
1343         if(ob==NULL) return 0;
1344         return (ob->type == OB_MESH);
1345 }
1346
1347 /* array for texture keyingset defines */
1348 bKeyingSet defks_buts_object[] = 
1349 {
1350         /* include_cb, name, blocktype, flag, chan_num, adrcodes */
1351         {incl_buts_ob, "Surface Damping", ID_OB, 0, 1, {OB_PD_SDAMP}},
1352         {incl_buts_ob, "Random Damping", ID_OB, 0, 1, {OB_PD_RDAMP}},
1353         {incl_buts_ob, "Permeability", ID_OB, 0, 1, {OB_PD_PERM}},
1354         
1355         {NULL, "%l", 0, -1, 0, {0}}, // separator
1356         
1357         {NULL, "Force Strength", ID_OB, 0, 1, {OB_PD_FSTR}},
1358         {NULL, "Force Falloff", ID_OB, 0, 1, {OB_PD_FFALL}},
1359         
1360         {NULL, "%l", 0, -1, 0, {0}}, // separator
1361         
1362         {NULL, "Available", ID_OB, -2, 0, {0}}  // this will include ob-transforms too!
1363 };
1364
1365 /* Camera Buttons KeyingSets  ------ */
1366
1367 /* check if include internal-renderer entry  */
1368 static short incl_buts_cam1 (bKeyingSet *ks, const char mode[])
1369 {
1370         Scene *scene= NULL; // FIXME this will cause a crash, but we need an extra arg first!
1371         /* only if renderer is internal renderer */
1372         return (scene->r.renderer==R_INTERN);
1373 }
1374
1375 /* check if include external-renderer entry  */
1376 static short incl_buts_cam2 (bKeyingSet *ks, const char mode[])
1377 {
1378         Scene *scene= NULL; // FIXME this will cause a crash, but we need an extra arg first!
1379         /* only if renderer is internal renderer */
1380         return (scene->r.renderer!=R_INTERN);
1381 }
1382
1383 /* array for camera keyingset defines */
1384 bKeyingSet defks_buts_cam[] = 
1385 {
1386         /* include_cb, name, blocktype, flag, chan_num, adrcodes */
1387         {NULL, "Lens", ID_CA, 0, 1, {CAM_LENS}},
1388         {NULL, "Clipping", ID_CA, 0, 2, {CAM_STA,CAM_END}},
1389         {NULL, "Focal Distance", ID_CA, 0, 1, {CAM_YF_FDIST}},
1390         
1391         {NULL, "%l", 0, -1, 0, {0}}, // separator
1392         
1393         
1394         {incl_buts_cam2, "Aperture", ID_CA, 0, 1, {CAM_YF_APERT}},
1395         {incl_buts_cam1, "Viewplane Shift", ID_CA, 0, 2, {CAM_SHIFT_X,CAM_SHIFT_Y}},
1396         
1397         {NULL, "%l", 0, -1, 0, {0}}, // separator
1398         
1399         {NULL, "Available", ID_CA, -2, 0, {0}}
1400 };
1401
1402 /* --- */
1403
1404 /* Keying Context Defines - Must keep in sync with enumeration (eKS_Contexts) */
1405 bKeyingContext ks_contexts[] = 
1406 {
1407         KSC_TEMPLATE(v3d_object),
1408         KSC_TEMPLATE(v3d_pchan),
1409         
1410         KSC_TEMPLATE(buts_shading_mat),
1411         KSC_TEMPLATE(buts_shading_wo),
1412         KSC_TEMPLATE(buts_shading_la),
1413         KSC_TEMPLATE(buts_shading_tex),
1414
1415         KSC_TEMPLATE(buts_object),
1416         KSC_TEMPLATE(buts_cam)
1417 };
1418
1419 /* Keying Context Enumeration - Must keep in sync with definitions*/
1420 typedef enum eKS_Contexts {
1421         KSC_V3D_OBJECT = 0,
1422         KSC_V3D_PCHAN,
1423         
1424         KSC_BUTS_MAT,
1425         KSC_BUTS_WO,
1426         KSC_BUTS_LA,
1427         KSC_BUTS_TEX,
1428         
1429         KSC_BUTS_OB,
1430         KSC_BUTS_CAM,
1431         
1432                 /* make sure this last one remains untouched! */
1433         KSC_TOT_TYPES
1434 } eKS_Contexts;
1435
1436
1437 /* ---------------- KeyingSet Tools ------------------- */
1438
1439 /* helper for commonkey_context_get() -  get keyingsets for 3d-view */
1440 static void commonkey_context_getv3d (const bContext *C, ListBase *sources, bKeyingContext **ksc)
1441 {
1442         Scene *scene= CTX_data_scene(C);
1443         Object *ob;
1444         IpoCurve *icu;
1445         
1446         if ((OBACT) && (OBACT->flag & OB_POSEMODE)) {
1447                 bPoseChannel *pchan;
1448                 
1449                 /* pose-level */
1450                 ob= OBACT;
1451                 *ksc= &ks_contexts[KSC_V3D_PCHAN];
1452                         // XXX
1453                 //set_pose_keys(ob);  /* sets pchan->flag to POSE_KEY if bone selected, and clears if not */
1454                 
1455                 /* loop through posechannels */
1456                 for (pchan=ob->pose->chanbase.first; pchan; pchan=pchan->next) {
1457                         if (pchan->flag & POSE_KEY) {
1458                                 bCommonKeySrc *cks;
1459                                 
1460                                 /* add new keyframing destination */
1461                                 cks= MEM_callocN(sizeof(bCommonKeySrc), "bCommonKeySrc");
1462                                 BLI_addtail(sources, cks);
1463                                 
1464                                 /* set id-block to key to, and action */
1465                                 cks->id= (ID *)ob;
1466                                 cks->act= ob->action;
1467                                 
1468                                 /* set pchan */
1469                                 cks->pchan= pchan;
1470                                 cks->actname= pchan->name;
1471                         }
1472                 }
1473         }
1474         else {
1475                 /* object-level */
1476                 *ksc= &ks_contexts[KSC_V3D_OBJECT];
1477                 
1478                 /* loop through bases */
1479                 // XXX but we're only supposed to do this on editable ones, not just selected ones!
1480                 CTX_DATA_BEGIN(C, Base*, base, selected_bases) {
1481                         bCommonKeySrc *cks;
1482                         
1483                         /* add new keyframing destination */
1484                         cks= MEM_callocN(sizeof(bCommonKeySrc), "bCommonKeySrc");
1485                         BLI_addtail(sources, cks);
1486                         
1487                         /* set id-block to key to */
1488                         ob= base->object;
1489                         cks->id= (ID *)ob;
1490                         
1491                         /* when ob's keyframes are in an action, default to using 'Object' as achan name */
1492                         if (ob->ipoflag & OB_ACTION_OB)
1493                                 cks->actname= "Object";
1494                         
1495                         /* set ipo-flags */
1496                         // TODO: add checks for lib-linked data
1497                         if ((ob->ipo) || (ob->action)) {
1498                                 if (ob->ipo) {
1499                                         cks->ipo= ob->ipo;
1500                                 }
1501                                 else {
1502                                         bActionChannel *achan;
1503                                         
1504                                         cks->act= ob->action;
1505                                         achan= get_action_channel(ob->action, cks->actname);
1506                                         
1507                                         if (achan && achan->ipo)
1508                                                 cks->ipo= achan->ipo;
1509                                 }
1510                                 /* cks->ipo can be NULL while editing */
1511                                 if(cks->ipo) {
1512                                         /* deselect all ipo-curves */
1513                                         for (icu= cks->ipo->curve.first; icu; icu= icu->next) {
1514                                                 icu->flag &= ~IPO_SELECT;
1515                                         }
1516                                 }
1517                         }
1518                 }
1519                 CTX_DATA_END;
1520         }
1521 }
1522
1523 /* helper for commonkey_context_get() -  get keyingsets for buttons window */
1524 static void commonkey_context_getsbuts (const bContext *C, ListBase *sources, bKeyingContext **ksc)
1525 {
1526 #if 0 // XXX dunno what's the future of this stuff...   
1527         bCommonKeySrc *cks;
1528         
1529         /* check on tab-type */
1530         switch (G.buts->mainb) {
1531         case CONTEXT_SHADING:   /* ------------- Shading buttons ---------------- */
1532                 /* subtabs include "Material", "Texture", "Lamp", "World"*/
1533                 switch (G.buts->tab[CONTEXT_SHADING]) {
1534                         case TAB_SHADING_MAT: /* >------------- Material Tab -------------< */
1535                         {
1536                                 Material *ma= editnode_get_active_material(G.buts->lockpoin);
1537                                 
1538                                 if (ma) {
1539                                         /* add new keyframing destination */
1540                                         cks= MEM_callocN(sizeof(bCommonKeySrc), "bCommonKeySrc");
1541                                         BLI_addtail(sources, cks); 
1542                                         
1543                                         /* set data */
1544                                         cks->id= (ID *)ma;
1545                                         cks->ipo= ma->ipo;
1546                                         cks->map= texchannel_to_adrcode(ma->texact);
1547                                         
1548                                         /* set keyingsets */
1549                                         *ksc= &ks_contexts[KSC_BUTS_MAT];
1550                                         return;
1551                                 }
1552                         }
1553                                 break;
1554                         case TAB_SHADING_WORLD: /* >------------- World Tab -------------< */
1555                         {
1556                                 World *wo= G.buts->lockpoin;
1557                                 
1558                                 if (wo) {
1559                                         /* add new keyframing destination */
1560                                         cks= MEM_callocN(sizeof(bCommonKeySrc), "bCommonKeySrc");
1561                                         BLI_addtail(sources, cks); 
1562                                         
1563                                         /* set data */
1564                                         cks->id= (ID *)wo;
1565                                         cks->ipo= wo->ipo;
1566                                         cks->map= texchannel_to_adrcode(wo->texact);
1567                                         
1568                                         /* set keyingsets */
1569                                         *ksc= &ks_contexts[KSC_BUTS_WO];
1570                                         return;
1571                                 }
1572                         }
1573                                 break;
1574                         case TAB_SHADING_LAMP: /* >------------- Lamp Tab -------------< */
1575                         {
1576                                 Lamp *la= G.buts->lockpoin;
1577                                 
1578                                 if (la) {
1579                                         /* add new keyframing destination */
1580                                         cks= MEM_callocN(sizeof(bCommonKeySrc), "bCommonKeySrc");
1581                                         BLI_addtail(sources, cks); 
1582                                         
1583                                         /* set data */
1584                                         cks->id= (ID *)la;
1585                                         cks->ipo= la->ipo;
1586                                         cks->map= texchannel_to_adrcode(la->texact);
1587                                         
1588                                         /* set keyingsets */
1589                                         *ksc= &ks_contexts[KSC_BUTS_LA];
1590                                         return;
1591                                 }
1592                         }
1593                                 break;
1594                         case TAB_SHADING_TEX: /* >------------- Texture Tab -------------< */
1595                         {
1596                                 Tex *tex= G.buts->lockpoin;
1597                                 
1598                                 if (tex) {
1599                                         /* add new keyframing destination */
1600                                         cks= MEM_callocN(sizeof(bCommonKeySrc), "bCommonKeySrc");
1601                                         BLI_addtail(sources, cks); 
1602                                         
1603                                         /* set data */
1604                                         cks->id= (ID *)tex;
1605                                         cks->ipo= tex->ipo;
1606                                         
1607                                         /* set keyingsets */
1608                                         *ksc= &ks_contexts[KSC_BUTS_TEX];
1609                                         return;
1610                                 }
1611                         }
1612                                 break;
1613                 }
1614                 break;
1615         
1616         case CONTEXT_OBJECT:    /* ------------- Object buttons ---------------- */
1617                 {
1618                         Object *ob= OBACT;
1619                         
1620                         if (ob) {
1621                                 /* add new keyframing destination */
1622                                 cks= MEM_callocN(sizeof(bCommonKeySrc), "bCommonKeySrc");
1623                                 BLI_addtail(sources, cks);
1624                                 
1625                                 /* set id-block to key to */
1626                                 cks->id= (ID *)ob;
1627                                 cks->ipo= ob->ipo;
1628                                 
1629                                 /* set keyingsets */
1630                                 *ksc= &ks_contexts[KSC_BUTS_OB];
1631                                 return;
1632                         }
1633                 }
1634                 break;
1635         
1636         case CONTEXT_EDITING:   /* ------------- Editing buttons ---------------- */
1637                 {
1638                         Object *ob= OBACT;
1639                         
1640                         if ((ob) && (ob->type==OB_CAMERA) && (G.buts->lockpoin)) { /* >---------------- camera buttons ---------------< */
1641                                 Camera *ca= G.buts->lockpoin;
1642                                 
1643                                 /* add new keyframing destination */
1644                                 cks= MEM_callocN(sizeof(bCommonKeySrc), "bCommonKeySrc");
1645                                 BLI_addtail(sources, cks);
1646                                 
1647                                 /* set id-block to key to */
1648                                 cks->id= (ID *)ca;
1649                                 cks->ipo= ca->ipo;
1650                                 
1651                                 /* set keyingsets */
1652                                 *ksc= &ks_contexts[KSC_BUTS_CAM];
1653                                 return;
1654                         }
1655                 }
1656                 break;
1657         }
1658 #endif // XXX end of buttons stuff to port...
1659         
1660         /* if nothing happened... */
1661         *ksc= NULL;
1662 }
1663
1664
1665 /* get keyingsets for appropriate context */
1666 static void commonkey_context_get (const bContext *C, ScrArea *sa, short mode, ListBase *sources, bKeyingContext **ksc)
1667 {
1668         /* get current view if no view is defined */
1669         if (sa == NULL)
1670                 sa= CTX_wm_area(C);
1671         
1672         /* check view type */
1673         switch (sa->spacetype) {
1674                 /* 3d view - first one tested as most often used */
1675                 case SPACE_VIEW3D:
1676                 {
1677                         commonkey_context_getv3d(C, sources, ksc);
1678                 }
1679                         break;
1680                         
1681                 /* buttons view */
1682                 case SPACE_BUTS:
1683                 {
1684                         commonkey_context_getsbuts(C, sources, ksc);
1685                 }
1686                         break;
1687                         
1688                 /* spaces with their own methods */
1689                 case SPACE_IPO:
1690                         //if (mode == COMMONKEY_MODE_INSERT)
1691                         //      insertkey_editipo(); // XXX old calls...
1692                         return;
1693                 case SPACE_ACTION:
1694                         //if (mode == COMMONKEY_MODE_INSERT)
1695                         //      insertkey_action(); // XXX old calls...
1696                         return;
1697                         
1698                 /* timeline view - keyframe buttons */
1699                 case SPACE_TIME:
1700                 {
1701                         bScreen *sc= CTX_wm_screen(C);
1702                         ScrArea *sab;
1703                         int bigarea= 0;
1704                         
1705                         /* try to find largest 3d-view available 
1706                          * (mostly of the time, this is what when user will want this,
1707                          *  as it's a standard feature in all other apps) 
1708                          */
1709                         //sab= find_biggest_area_of_type(SPACE_VIEW3D);
1710                         sab= NULL; // XXX for now...
1711                         if (sab) {
1712                                 commonkey_context_getv3d(C, sources, ksc);
1713                                 return;
1714                         }
1715                         
1716                         /* if not found, sab is now NULL, so perform own biggest area test */
1717                         for (sa= sc->areabase.first; sa; sa= sa->next) { // XXX this has changed!
1718                                 int area= sa->winx * sa->winy;
1719                                 
1720                                 if (sa->spacetype != SPACE_TIME) {
1721                                         if ( (!sab) || (area > bigarea) ) {
1722                                                 sab= sa;
1723                                                 bigarea= area;
1724                                         }
1725                                 }
1726                         }
1727                         
1728                         /* use whichever largest area was found (it shouldn't be a time window) */
1729                         if (sab)
1730                                 commonkey_context_get(C, sab, mode, sources, ksc);
1731                 }
1732                         break;
1733         }
1734 }
1735
1736 /* flush updates after all operations */
1737 static void commonkey_context_finish (const bContext *C, ListBase *sources)
1738 {
1739         ScrArea *curarea= CTX_wm_area(C);
1740         Scene *scene= CTX_data_scene(C);
1741         
1742         /* check view type */
1743         switch (curarea->spacetype) {
1744                 /* 3d view - first one tested as most often used */
1745                 case SPACE_VIEW3D:
1746                 {
1747                         /* either pose or object level */
1748                         if (OBACT && (OBACT->pose)) {   
1749                                 //Object *ob= OBACT;
1750                                 
1751                                 /* recalculate ipo handles, etc. */
1752                                 // XXX this method has been removed!
1753                                 //if (ob->action)
1754                                 //      remake_action_ipos(ob->action);
1755                                 
1756                                 /* recalculate bone-paths on adding new keyframe? */
1757                                 // XXX missing function
1758                                 // TODO: currently, there is no setting to turn this on/off globally
1759                                 //if (ob->pose->flag & POSE_RECALCPATHS)
1760                                 //      pose_recalculate_paths(ob);
1761                         }
1762                         else {
1763                                 bCommonKeySrc *cks;
1764                                 
1765                                 /* loop over bases (as seen in sources) */
1766                                 for (cks= sources->first; cks; cks= cks->next) {
1767                                         Object *ob= (Object *)cks->id;
1768                                         
1769                                         /* simply set recalc flag */
1770                                         ob->recalc |= OB_RECALC_OB;
1771                                 }
1772                         }
1773                 }
1774                         break;
1775         }
1776 }
1777
1778 /* flush refreshes after undo */
1779 static void commonkey_context_refresh (bContext *C)
1780 {
1781         ScrArea *curarea= CTX_wm_area(C);
1782         
1783         /* check view type */
1784         switch (curarea->spacetype) {
1785                 /* 3d view - first one tested as most often used */
1786                 case SPACE_VIEW3D:
1787                 {
1788                         /* do refreshes */
1789                         ED_anim_dag_flush_update(C);
1790                 }
1791                         break;
1792                         
1793                 /* buttons window */
1794                 case SPACE_BUTS:
1795                 {
1796                         //allspace(REMAKEIPO, 0);
1797                         //allqueue(REDRAWVIEW3D, 0);
1798                         //allqueue(REDRAWMARKER, 0);
1799                 }
1800                         break;
1801         }
1802 }
1803
1804 /* --- */
1805
1806 /* Get the keying set that was chosen by the user from the menu */
1807 static bKeyingSet *get_keyingset_fromcontext (bKeyingContext *ksc, short index)
1808 {
1809         /* check if index is valid */
1810         if (ELEM(NULL, ksc, ksc->keyingsets))
1811                 return NULL;
1812         if ((index < 1) || (index > ksc->tot))
1813                 return NULL;
1814                 
1815         /* index starts from 1, and should directly correspond to keyingset in array */
1816         return (bKeyingSet *)(ksc->keyingsets + (index - 1));
1817 }
1818
1819 /* ---------------- Keyframe Management API -------------------- */
1820
1821 /* Display a menu for handling the insertion of keyframes based on the active view */
1822 void common_modifykey (bContext *C, short mode)
1823 {
1824         ListBase dsources = {NULL, NULL};
1825         bKeyingContext *ksc= NULL;
1826         bCommonKeySrc *cks;
1827         bKeyingSet *ks = NULL;
1828         char *menustr, buf[64];
1829         short menu_nr;
1830         
1831         /* check if mode is valid */
1832         if (ELEM(mode, COMMONKEY_MODE_INSERT, COMMONKEY_MODE_DELETE)==0)
1833                 return;
1834         
1835         /* delegate to other functions or get keyingsets to use 
1836          *      - if the current area doesn't have its own handling, there will be data returned...
1837          */
1838         commonkey_context_get(C, NULL, mode, &dsources, &ksc);
1839         
1840         /* check that there is data to operate on */
1841         if (ELEM(NULL, dsources.first, ksc)) {
1842                 BLI_freelistN(&dsources);
1843                 return;
1844         }
1845         
1846         /* get menu and process it */
1847         if (mode == COMMONKEY_MODE_DELETE)
1848                 menustr= build_keyingsets_menu(ksc, "Delete");
1849         else
1850                 menustr= build_keyingsets_menu(ksc, "Insert");
1851         // XXX: this goes to the invoke!
1852         //menu_nr= pupmenu(menustr);
1853         //if (menustr) MEM_freeN(menustr);
1854         menu_nr = -1; // XXX for now
1855         
1856         /* no item selected or shapekey entry? */
1857         if (menu_nr < 1) {
1858                 /* free temp sources */
1859                 BLI_freelistN(&dsources);
1860                 
1861                 /* check if insert new shapekey */
1862                 // XXX missing function!
1863                 //if ((menu_nr == 0) && (mode == COMMONKEY_MODE_INSERT))
1864                 //      insert_shapekey(OBACT);
1865                 //else 
1866                         ksc->lastused= NULL;
1867                         
1868                 return;
1869         }
1870         else {
1871                 /* try to get keyingset */
1872                 ks= get_keyingset_fromcontext(ksc, menu_nr);
1873                 
1874                 if (ks == NULL) {
1875                         BLI_freelistN(&dsources);
1876                         return;
1877                 }
1878         }
1879         
1880         /* loop over each destination, applying the keying set */
1881         for (cks= dsources.first; cks; cks= cks->next) {
1882                 short success= 0;
1883                 
1884                 /* special hacks for 'available' option */
1885                 if (ks->flag == -2) {
1886                         IpoCurve *icu= NULL, *icn= NULL;
1887                         
1888                         /* get first IPO-curve */
1889                         if (cks->act && cks->actname) {
1890                                 bActionChannel *achan= get_action_channel(cks->act, cks->actname);
1891                                 
1892                                 // FIXME: what about constraint channels?
1893                                 if (achan && achan->ipo)
1894                                         icu= achan->ipo->curve.first; 
1895                         }
1896                         else if(cks->ipo)
1897                                 icu= cks->ipo->curve.first;
1898                                 
1899                         /* we get adrcodes directly from IPO curves (see method below...) */
1900                         for (; icu; icu= icn) {
1901                                 short flag;
1902                                 
1903                                 /* get next ipo-curve in case current is deleted */
1904                                 icn= icu->next;
1905                                 
1906                                 /* insert mode or delete mode */
1907                                 if (mode == COMMONKEY_MODE_DELETE) {
1908                                         /* local flags only add on to global flags */
1909                                         flag = 0;
1910                                         
1911                                         /* delete keyframe */
1912                                         success += deletekey(cks->id, ks->blocktype, cks->actname, cks->constname, icu->adrcode, flag);
1913                                 }
1914                                 else {
1915                                         /* local flags only add on to global flags */
1916                                         flag = ks->flag;
1917                                         if (IS_AUTOKEY_FLAG(AUTOMATKEY)) flag |= INSERTKEY_MATRIX;
1918                                         if (IS_AUTOKEY_FLAG(INSERTNEEDED)) flag |= INSERTKEY_NEEDED;
1919                                         // if (IS_AUTOKEY_MODE(EDITKEYS)) flag |= INSERTKEY_REPLACE;
1920                                         
1921                                         /* insert keyframe */
1922                                         success += insertkey(cks->id, ks->blocktype, cks->actname, cks->constname, icu->adrcode, flag);
1923                                 }
1924                         }
1925                 }
1926                 else {
1927                         bKS_AdrcodeGetter kag;
1928                         short (*get_next_adrcode)(bKS_AdrcodeGetter *);
1929                         int adrcode;
1930                         
1931                         /* initialise keyingset channel iterator */
1932                         ks_adrcodegetter_init(&kag, ks, cks);
1933                         
1934                         /* get iterator - only one can be in use at a time... the flags should be mutually exclusive in this regard */
1935                         if (ks->flag & COMMONKEY_PCHANROT)
1936                                 get_next_adrcode= ks_getnextadrcode_pchanrot;
1937                         else if (ks->flag & COMMONKEY_ADDMAP)
1938                                 get_next_adrcode= ks_getnextadrcode_addmap;
1939                         else
1940                                 get_next_adrcode= ks_getnextadrcode_default;
1941                         
1942                         /* loop over channels available in keyingset */
1943                         for (adrcode= get_next_adrcode(&kag); adrcode > 0; adrcode= get_next_adrcode(&kag)) {
1944                                 short flag;
1945                                 
1946                                 /* insert mode or delete mode */
1947                                 if (mode == COMMONKEY_MODE_DELETE) {
1948                                         /* local flags only add on to global flags */
1949                                         flag = 0;
1950                                         //flag &= ~COMMONKEY_MODES;
1951                                         
1952                                         /* delete keyframe */
1953                                         success += deletekey(cks->id, ks->blocktype, cks->actname, cks->constname, adrcode, flag);
1954                                 }
1955                                 else {
1956                                         /* local flags only add on to global flags */
1957                                         flag = ks->flag;
1958                                         if (IS_AUTOKEY_FLAG(AUTOMATKEY)) flag |= INSERTKEY_MATRIX;
1959                                         if (IS_AUTOKEY_FLAG(INSERTNEEDED)) flag |= INSERTKEY_NEEDED;
1960                                         // if (IS_AUTOKEY_MODE(EDITKEYS)) flag |= INSERTKEY_REPLACE;
1961                                         flag &= ~COMMONKEY_MODES;
1962                                         
1963                                         /* insert keyframe */
1964                                         success += insertkey(cks->id, ks->blocktype, cks->actname, cks->constname, adrcode, flag);
1965                                 }
1966                         }
1967                 }
1968                 
1969                 /* special handling for some key-sources */
1970                 if (success) {
1971                         /* set pose recalc-paths flag */
1972                         if (cks->pchan) {
1973                                 Object *ob= (Object *)cks->id;
1974                                 bPoseChannel *pchan= cks->pchan;
1975                                 
1976                                 /* set flag to trigger path recalc */
1977                                 if (pchan->path) 
1978                                         ob->pose->flag |= POSE_RECALCPATHS;
1979                                         
1980                                 /* clear unkeyed flag (it doesn't matter if it's set or not) */
1981                                         // XXX old animation system
1982                                 //if (pchan->bone)
1983                                 //      pchan->bone->flag &= ~BONE_UNKEYED;
1984                         }
1985                         
1986                         // XXX for new system, need to remove overrides
1987                 }
1988         }
1989         
1990         /* apply post-keying flushes for this data sources */
1991         commonkey_context_finish(C, &dsources);
1992         
1993         /* free temp data */
1994         BLI_freelistN(&dsources);
1995         
1996         /* queue updates for contexts */
1997         commonkey_context_refresh(C);
1998 }
1999
2000 #endif // XXX old keyingsets code based on adrcodes... to be restored in due course
2001
2002 /* Given a KeyingSet and context info (if required), modify keyframes for the channels specified
2003  * by the KeyingSet. This takes into account many of the different combinations of using KeyingSets.
2004  * Returns the number of channels that keyframes were added to
2005  */
2006 static int commonkey_modifykey (ListBase *dsources, KeyingSet *ks, short mode, float cfra)
2007 {
2008         KS_Path *ksp;
2009         int kflag, success= 0;
2010         char *groupname= NULL;
2011         
2012         /* get flags to use */
2013         if (mode == COMMONKEY_MODE_INSERT) {
2014                 /* use KeyingSet's flags as base */
2015                 kflag= ks->keyingflag;
2016                 
2017                 /* suppliment with info from the context */
2018                 if (IS_AUTOKEY_FLAG(AUTOMATKEY)) kflag |= INSERTKEY_MATRIX;
2019                 if (IS_AUTOKEY_FLAG(INSERTNEEDED)) kflag |= INSERTKEY_NEEDED;
2020                 // if (IS_AUTOKEY_MODE(EDITKEYS)) flag |= INSERTKEY_REPLACE;
2021         }
2022         else if (mode == COMMONKEY_MODE_DELETE)
2023                 kflag= 0;
2024         
2025         /* check if the KeyingSet is absolute or not (i.e. does it requires sources info) */
2026         if (ks->flag & KEYINGSET_ABSOLUTE) {
2027                 /* Absolute KeyingSets are simpler to use, as all the destination info has already been
2028                  * provided by the user, and is stored, ready to use, in the KeyingSet paths.
2029                  */
2030                 for (ksp= ks->paths.first; ksp; ksp= ksp->next) {
2031                         int arraylen, i;
2032                         
2033                         /* get pointer to name of group to add channels to */
2034                         if (ksp->groupmode == KSP_GROUP_NONE)
2035                                 groupname= NULL;
2036                         else if (ksp->groupmode == KSP_GROUP_KSNAME)
2037                                 groupname= ks->name;
2038                         else
2039                                 groupname= ksp->group;
2040                         
2041                         /* init arraylen and i - arraylen should be greater than i so that
2042                          * normal non-array entries get keyframed correctly
2043                          */
2044                         i= ksp->array_index;
2045                         arraylen= i+1;
2046                         
2047                         /* get length of array if whole array option is enabled */
2048                         if (ksp->flag & KSP_FLAG_WHOLE_ARRAY) {
2049                                 PointerRNA id_ptr, ptr;
2050                                 PropertyRNA *prop;
2051                                 
2052                                 RNA_id_pointer_create(ksp->id, &id_ptr);
2053                                 if (RNA_path_resolve(&id_ptr, ksp->rna_path, &ptr, &prop))
2054                                         arraylen= RNA_property_array_length(&ptr, prop);
2055                         }
2056                         
2057                         /* for each possible index, perform operation 
2058                          *      - assume that arraylen is greater than index
2059                          */
2060                         for (; i < arraylen; i++) {
2061                                 /* action to take depends on mode */
2062                                 if (mode == COMMONKEY_MODE_INSERT)
2063                                         success+= insertkey(ksp->id, groupname, ksp->rna_path, i, cfra, kflag);
2064                                 else if (mode == COMMONKEY_MODE_DELETE)
2065                                         success+= deletekey(ksp->id, groupname,  ksp->rna_path, i, cfra, kflag);
2066                         }
2067                         
2068                         // TODO: set recalc tags on the ID?
2069                 }
2070         }
2071 #if 0 // XXX still need to figure out how to get such keyingsets working
2072         else if (dsources) {
2073                 /* for each one of the 'sources', resolve the template markers and expand arrays, then insert keyframes */
2074                 bCommonKeySrc *cks;
2075                 char *path = NULL;
2076                 int index=0, tot=0;
2077                 
2078                 /* for each 'source' for keyframe data, resolve each of the paths from the KeyingSet */
2079                 for (cks= dsources->first; cks; cks= cks->next) {
2080                         
2081                 }
2082         }
2083 #endif // XXX still need to figure out how to get such 
2084         
2085         return success;
2086 }
2087
2088 /* Insert Key Operator ------------------------ */
2089
2090 /* XXX WARNING:
2091  * This is currently just a basic operator, which work in 3d-view context on objects/bones only
2092  * and will insert keyframes for a few settings only. This is until it becomes clear how
2093  * to separate (or not) the process for RNA-path creation between context + keyingsets.
2094  * 
2095  * -- Joshua Leung, Jan 2009
2096  */
2097
2098 /* defines for basic insert-key testing operator  */
2099         // XXX this will definitely be replaced
2100 EnumPropertyItem prop_insertkey_types[] = {
2101         {0, "KEYINGSET", "Active KeyingSet", ""},
2102         {1, "OBLOC", "Object Location", ""},
2103         {2, "OBROT", "Object Rotation", ""},
2104         {3, "OBSCALE", "Object Scale", ""},
2105         {4, "MAT_COL", "Active Material - Color", ""},
2106         {5, "PCHANLOC", "Pose-Channel Location", ""},
2107         {6, "PCHANROT", "Pose-Channel Rotation", ""},
2108         {7, "PCHANSCALE", "Pose-Channel Scale", ""},
2109         {0, NULL, NULL, NULL}
2110 };
2111
2112 static int insert_key_invoke (bContext *C, wmOperator *op, wmEvent *event)
2113 {
2114         Object *ob= CTX_data_active_object(C);
2115         uiMenuItem *head;
2116         
2117         if (ob == NULL)
2118                 return OPERATOR_CANCELLED;
2119                 
2120         head= uiPupMenuBegin("Insert Keyframe", 0);
2121         
2122         /* active keyingset */
2123         uiMenuItemEnumO(head, "", 0, "ANIM_OT_insert_keyframe", "type", 0);
2124         
2125         /* selective inclusion */
2126         if ((ob->pose) && (ob->flag & OB_POSEMODE)) {
2127                 /* bone types */        
2128                 uiMenuItemEnumO(head, "", 0, "ANIM_OT_insert_keyframe", "type", 5);
2129                 uiMenuItemEnumO(head, "", 0, "ANIM_OT_insert_keyframe", "type", 6);
2130                 uiMenuItemEnumO(head, "", 0, "ANIM_OT_insert_keyframe", "type", 7);
2131         }
2132         else {
2133                 /* object types */
2134                 uiMenuItemEnumO(head, "", 0, "ANIM_OT_insert_keyframe", "type", 1);
2135                 uiMenuItemEnumO(head, "", 0, "ANIM_OT_insert_keyframe", "type", 2);
2136                 uiMenuItemEnumO(head, "", 0, "ANIM_OT_insert_keyframe", "type", 3);
2137                 uiMenuItemEnumO(head, "", 0, "ANIM_OT_insert_keyframe", "type", 4);
2138         }
2139         
2140         uiPupMenuEnd(C, head);
2141         
2142         return OPERATOR_CANCELLED;
2143 }
2144  
2145 static int insert_key_exec (bContext *C, wmOperator *op)
2146 {
2147         Scene *scene= CTX_data_scene(C);
2148         short mode= RNA_enum_get(op->ptr, "type");
2149         float cfra= (float)CFRA; // XXX for now, don't bother about all the yucky offset crap
2150         
2151         /* for now, handle 'active keyingset' one separately */
2152         if (mode == 0) {
2153                 ListBase dsources = {NULL, NULL};
2154                 KeyingSet *ks= NULL;
2155                 short success;
2156                 
2157                 /* try to get KeyingSet */
2158                 if (scene->active_keyingset > 0)
2159                         ks= BLI_findlink(&scene->keyingsets, scene->active_keyingset-1);
2160                 /* report failure */
2161                 if (ks == NULL) {
2162                         BKE_report(op->reports, RPT_ERROR, "No active Keying Set");
2163                         return OPERATOR_CANCELLED;
2164                 }
2165                 
2166                 /* try to insert keyframes for the channels specified by KeyingSet */
2167                 success= commonkey_modifykey(&dsources, ks, COMMONKEY_MODE_INSERT, cfra);
2168                 printf("KeyingSet '%s' - Successfully added %d Keyframes \n", ks->name, success);
2169                 
2170                 /* report failure */
2171                 if (success == 0) {
2172                         BKE_report(op->reports, RPT_WARNING, "Keying Set failed to insert any keyframes");
2173                         return OPERATOR_CANCELLED; // XXX?
2174                 }
2175                 else
2176                         return OPERATOR_FINISHED;
2177         }
2178         else {
2179                 // more comprehensive tests will be needed
2180                 CTX_DATA_BEGIN(C, Base*, base, selected_bases) 
2181                 {
2182                         Object *ob= base->object;
2183                         ID *id= (ID *)ob;
2184                         short success= 0;
2185                         
2186                         /* check which keyframing mode chosen for this object */
2187                         if (mode < 4) {
2188                                 /* object-based keyframes */
2189                                 switch (mode) {
2190                                 case 4: /* color of active material (only for geometry...) */
2191                                         // NOTE: this is just a demo... but ideally we'd go through materials instead of active one only so reference stays same
2192                                         // XXX no group for now
2193                                         success+= insertkey(id, NULL, "active_material.diffuse_color", 0, cfra, 0);
2194                                         success+= insertkey(id, NULL, "active_material.diffuse_color", 1, cfra, 0);
2195                                         success+= insertkey(id, NULL, "active_material.diffuse_color", 2, cfra, 0);
2196                                         break;
2197                                 case 3: /* object scale */
2198                                         success+= insertkey(id, "Object Transforms", "scale", 0, cfra, 0);
2199                                         success+= insertkey(id, "Object Transforms", "scale", 1, cfra, 0);
2200                                         success+= insertkey(id, "Object Transforms", "scale", 2, cfra, 0);
2201                                         break;
2202                                 case 2: /* object rotation */
2203                                         success+= insertkey(id, "Object Transforms", "rotation", 0, cfra, 0);
2204                                         success+= insertkey(id, "Object Transforms", "rotation", 1, cfra, 0);
2205                                         success+= insertkey(id, "Object Transforms", "rotation", 2, cfra, 0);
2206                                         break;
2207                                 case 1: /* object location */
2208                                         success+= insertkey(id, "Object Transforms", "location", 0, cfra, 0);
2209                                         success+= insertkey(id, "Object Transforms", "location", 1, cfra, 0);
2210                                         success+= insertkey(id, "Object Transforms", "location", 2, cfra, 0);
2211                                         break;
2212                                 }
2213                                 
2214                                 ob->recalc |= OB_RECALC_OB;
2215                         }
2216                         else if ((ob->pose) && (ob->flag & OB_POSEMODE)) {
2217                                 /* PoseChannel based keyframes */
2218                                 bPoseChannel *pchan;
2219                                 
2220                                 for (pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
2221                                         /* only if selected */
2222                                         if ((pchan->bone) && (pchan->bone->flag & BONE_SELECTED)) {
2223                                                 char buf[512];
2224                                                 
2225                                                 switch (mode) {
2226                                                 case 6: /* pchan scale */
2227                                                         sprintf(buf, "pose.pose_channels[\"%s\"].scale", pchan->name);
2228                                                         success+= insertkey(id, pchan->name, buf, 0, cfra, 0);
2229                                                         success+= insertkey(id, pchan->name, buf, 1, cfra, 0);
2230                                                         success+= insertkey(id, pchan->name, buf, 2, cfra, 0);
2231                                                         break;
2232                                                 case 5: /* pchan rotation */
2233                                                         if (pchan->rotmode == PCHAN_ROT_QUAT) {
2234                                                                 sprintf(buf, "pose.pose_channels[\"%s\"].rotation", pchan->name);
2235                                                                 success+= insertkey(id, pchan->name, buf, 0, cfra, 0);
2236                                                                 success+= insertkey(id, pchan->name, buf, 1, cfra, 0);
2237                                                                 success+= insertkey(id, pchan->name, buf, 2, cfra, 0);
2238                                                                 success+= insertkey(id, pchan->name, buf, 3, cfra, 0);
2239                                                         }
2240                                                         else {
2241                                                                 sprintf(buf, "pose.pose_channels[\"%s\"].euler_rotation", pchan->name);
2242                                                                 success+= insertkey(id, pchan->name, buf, 0, cfra, 0);
2243                                                                 success+= insertkey(id, pchan->name, buf, 1, cfra, 0);
2244                                                                 success+= insertkey(id, pchan->name, buf, 2, cfra, 0);
2245                                                         }
2246                                                         break;
2247                                                 default: /* pchan location */
2248                                                         sprintf(buf, "pose.pose_channels[\"%s\"].location", pchan->name);
2249                                                         success+= insertkey(id, pchan->name, buf, 0, cfra, 0);
2250                                                         success+= insertkey(id, pchan->name, buf, 1, cfra, 0);
2251                                                         success+= insertkey(id, pchan->name, buf, 2, cfra, 0);
2252                                                         break;
2253                                                 }
2254                                         }
2255                                 }
2256                                 
2257                                 ob->recalc |= OB_RECALC_OB;
2258                         }
2259                         
2260                         printf("Ob '%s' - Successfully added %d Keyframes \n", id->name+2, success);
2261                 }
2262                 CTX_DATA_END;
2263         }
2264         
2265         /* send updates */
2266         ED_anim_dag_flush_update(C);    
2267         
2268         if (mode == 4) // material color requires different notifiers
2269                 WM_event_add_notifier(C, NC_MATERIAL|ND_KEYS, NULL);
2270         else
2271                 WM_event_add_notifier(C, NC_OBJECT|ND_KEYS, NULL);
2272         
2273         return OPERATOR_FINISHED;
2274 }
2275
2276 void ANIM_OT_insert_keyframe (wmOperatorType *ot)
2277 {
2278         PropertyRNA *prop;
2279         
2280         /* identifiers */
2281         ot->name= "Insert Keyframe";
2282         ot->idname= "ANIM_OT_insert_keyframe";
2283         
2284         /* callbacks */
2285         ot->invoke= insert_key_invoke;
2286         ot->exec= insert_key_exec; 
2287         ot->poll= ED_operator_areaactive;
2288         
2289         /* flags */
2290         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2291         
2292         /* properties */
2293                 // XXX update this for the latest RNA stuff styles...
2294         prop= RNA_def_property(ot->srna, "type", PROP_ENUM, PROP_NONE);
2295         RNA_def_property_enum_items(prop, prop_insertkey_types);
2296 }
2297
2298 /* Delete Key Operator ------------------------ */
2299
2300 /* XXX WARNING:
2301  * This is currently just a basic operator, which work in 3d-view context on objects only. 
2302  * -- Joshua Leung, Jan 2009
2303  */
2304  
2305 static int delete_key_exec (bContext *C, wmOperator *op)
2306 {
2307         Scene *scene= CTX_data_scene(C);
2308         float cfra= (float)CFRA; // XXX for now, don't bother about all the yucky offset crap
2309         
2310         // XXX more comprehensive tests will be needed
2311         CTX_DATA_BEGIN(C, Base*, base, selected_bases) 
2312         {
2313                 Object *ob= base->object;
2314                 ID *id= (ID *)ob;
2315                 FCurve *fcu, *fcn;
2316                 short success= 0;
2317                 
2318                 /* loop through all curves in animdata and delete keys on this frame */
2319                 if (ob->adt) {
2320                         AnimData *adt= ob->adt;
2321                         bAction *act= adt->action;
2322                         
2323                         for (fcu= act->curves.first; fcu; fcu= fcn) {
2324                                 fcn= fcu->next;
2325                                 success+= deletekey(id, NULL, fcu->rna_path, fcu->array_index, cfra, 0);
2326                         }
2327                 }
2328                 
2329                 printf("Ob '%s' - Successfully removed %d keyframes \n", id->name+2, success);
2330                 
2331                 ob->recalc |= OB_RECALC_OB;
2332         }
2333         CTX_DATA_END;
2334         
2335         /* send updates */
2336         ED_anim_dag_flush_update(C);    
2337         
2338                 // XXX what if it was a material keyframe?
2339         WM_event_add_notifier(C, NC_OBJECT|ND_KEYS, NULL);
2340         
2341         return OPERATOR_FINISHED;
2342 }
2343
2344 void ANIM_OT_delete_keyframe (wmOperatorType *ot)
2345 {
2346         /* identifiers */
2347         ot->name= "Delete Keyframe";
2348         ot->idname= "ANIM_OT_delete_keyframe";
2349         
2350         /* callbacks */
2351         ot->invoke= WM_operator_confirm; // XXX we will need our own one eventually, to cope with the dynamic menus...
2352         ot->exec= delete_key_exec; 
2353         
2354         ot->poll= ED_operator_areaactive;
2355         
2356         /* flags */
2357         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2358 }
2359
2360 /* ******************************************* */
2361 /* KEYFRAME DETECTION */
2362
2363 /* --------------- API/Per-Datablock Handling ------------------- */
2364
2365 /* Checks whether an IPO-block has a keyframe for a given frame 
2366  * Since we're only concerned whether a keyframe exists, we can simply loop until a match is found...
2367  */
2368 short action_frame_has_keyframe (bAction *act, float frame, short filter)
2369 {
2370         FCurve *fcu;
2371         
2372         /* can only find if there is data */
2373         if (act == NULL)
2374                 return 0;
2375                 
2376         /* if only check non-muted, check if muted */
2377         if ((filter & ANIMFILTER_KEYS_MUTED) || (act->flag & ACT_MUTED))
2378                 return 0;
2379         
2380         /* loop over F-Curves, using binary-search to try to find matches 
2381          *      - this assumes that keyframes are only beztriples
2382          */
2383         for (fcu= act->curves.first; fcu; fcu= fcu->next) {
2384                 /* only check if there are keyframes (currently only of type BezTriple) */
2385                 if (fcu->bezt && fcu->totvert) {
2386                         /* we either include all regardless of muting, or only non-muted  */
2387                         if ((filter & ANIMFILTER_KEYS_MUTED) || (fcu->flag & FCURVE_MUTED)==0) {
2388                                 short replace = -1;
2389                                 int i = binarysearch_bezt_index(fcu->bezt, frame, fcu->totvert, &replace);
2390                                 
2391                                 /* binarysearch_bezt_index will set replace to be 0 or 1
2392                                  *      - obviously, 1 represents a match
2393                                  */
2394                                 if (replace) {                  
2395                                         /* sanity check: 'i' may in rare cases exceed arraylen */
2396                                         if ((i >= 0) && (i < fcu->totvert))
2397                                                 return 1;
2398                                 }
2399                         }
2400                 }
2401         }
2402         
2403         /* nothing found */
2404         return 0;
2405 }
2406
2407 /* Checks whether an Object has a keyframe for a given frame */
2408 short object_frame_has_keyframe (Object *ob, float frame, short filter)
2409 {
2410         /* error checking */
2411         if (ob == NULL)
2412                 return 0;
2413         
2414         /* check own animation data - specifically, the action it contains */
2415         if ((ob->adt) && (ob->adt->action)) {
2416                 if (action_frame_has_keyframe(ob->adt->action, frame, filter))
2417                         return 1;
2418         }
2419         
2420         /* try shapekey keyframes (if available, and allowed by filter) */
2421         if ( !(filter & ANIMFILTER_KEYS_LOCAL) && !(filter & ANIMFILTER_KEYS_NOSKEY) ) {
2422                 Key *key= ob_get_key(ob);
2423                 
2424                 /* shapekeys can have keyframes ('Relative Shape Keys') 
2425                  * or depend on time (old 'Absolute Shape Keys') 
2426                  */
2427                  
2428                         /* 1. test for relative (with keyframes) */
2429                 if (id_frame_has_keyframe((ID *)key, frame, filter))
2430                         return 1;
2431                         
2432                         /* 2. test for time */
2433                 // TODO... yet to be implemented (this feature may evolve before then anyway)
2434         }
2435         
2436         /* try materials */
2437         if ( !(filter & ANIMFILTER_KEYS_LOCAL) && !(filter & ANIMFILTER_KEYS_NOMAT) ) {
2438                 /* if only active, then we can skip a lot of looping */
2439                 if (filter & ANIMFILTER_KEYS_ACTIVE) {
2440                         Material *ma= give_current_material(ob, (ob->actcol + 1));
2441                         
2442                         /* we only retrieve the active material... */
2443                         if (id_frame_has_keyframe((ID *)ma, frame, filter))
2444                                 return 1;
2445                 }
2446                 else {
2447                         int a;
2448                         
2449                         /* loop over materials */
2450                         for (a=0; a<ob->totcol; a++) {
2451                                 Material *ma= give_current_material(ob, a+1);
2452                                 
2453                                 if (id_frame_has_keyframe((ID *)ma, frame, filter))
2454                                         return 1;
2455                         }
2456                 }
2457         }
2458         
2459         /* nothing found */
2460         return 0;
2461 }
2462
2463 /* --------------- API ------------------- */
2464
2465 /* Checks whether a keyframe exists for the given ID-block one the given frame */
2466 short id_frame_has_keyframe (ID *id, float frame, short filter)
2467 {
2468         /* sanity checks */
2469         if (id == NULL)
2470                 return 0;
2471         
2472         /* perform special checks for 'macro' types */
2473         switch (GS(id->name)) {
2474                 case ID_OB: /* object */
2475                         return object_frame_has_keyframe((Object *)id, frame, filter);
2476                         break;
2477                         
2478                 case ID_SCE: /* scene */
2479                 // XXX TODO... for now, just use 'normal' behaviour
2480                 //      break;
2481                 
2482                 default:        /* 'normal type' */
2483                 {
2484                         AnimData *adt= BKE_animdata_from_id(id);
2485                         
2486                         /* only check keyframes in active action */
2487                         if (adt)
2488                                 return action_frame_has_keyframe(adt->action, frame, filter);
2489                 }
2490                         break;
2491         }
2492         
2493         
2494         /* no keyframe found */
2495         return 0;
2496 }
2497
2498 /* ************************************************** */