Keying Sets: Insert/Delete Keyframe Operator Buttons
[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                 /* if a group name has been provided, try to add or find a group, then add F-Curve to it */
123                 if (group) {
124                         /* try to find group */
125                         grp= action_groups_find_named(act, group);
126                         
127                         /* no matching groups, so add one */
128                         if (grp == NULL) {
129                                 /* Add a new group, and make it active */
130                                 grp= MEM_callocN(sizeof(bActionGroup), "bActionGroup");
131                                 
132                                 grp->flag |= (AGRP_ACTIVE|AGRP_SELECTED|AGRP_EXPANDED);
133                                 BLI_snprintf(grp->name, 64, group);
134                                 
135                                 BLI_addtail(&act->groups, grp);
136                                 BLI_uniquename(&act->groups, grp, "Group", offsetof(bActionGroup, name), 64);
137                                 
138                                 set_active_action_group(act, grp, 1);
139                         }
140                         
141                         /* add F-Curve to group */
142                         action_groups_add_channel(act, grp, fcu);
143                 }
144                 else {
145                         /* just add F-Curve to end of Action's list */
146                         BLI_addtail(&act->curves, fcu);
147                 }
148         }
149         
150         /* return the F-Curve */
151         return fcu;
152 }
153
154 /* ************************************************** */
155 /* KEYFRAME INSERTION */
156
157 /* -------------- BezTriple Insertion -------------------- */
158
159 /* threshold for inserting keyframes - threshold here should be good enough for now, but should become userpref */
160 #define BEZT_INSERT_THRESH      0.00001f
161
162 /* Binary search algorithm for finding where to insert BezTriple. (for use by insert_bezt_icu)
163  * Returns the index to insert at (data already at that index will be offset if replace is 0)
164  */
165 static int binarysearch_bezt_index (BezTriple array[], float frame, int arraylen, short *replace)
166 {
167         int start=0, end=arraylen;
168         int loopbreaker= 0, maxloop= arraylen * 2;
169         
170         /* initialise replace-flag first */
171         *replace= 0;
172         
173         /* sneaky optimisations (don't go through searching process if...):
174          *      - keyframe to be added is to be added out of current bounds
175          *      - keyframe to be added would replace one of the existing ones on bounds
176          */
177         if ((arraylen <= 0) || (array == NULL)) {
178                 printf("Warning: binarysearch_bezt_index() encountered invalid array \n");
179                 return 0;
180         }
181         else {
182                 /* check whether to add before/after/on */
183                 float framenum;
184                 
185                 /* 'First' Keyframe (when only one keyframe, this case is used) */
186                 framenum= array[0].vec[1][0];
187                 if (IS_EQT(frame, framenum, BEZT_INSERT_THRESH)) {
188                         *replace = 1;
189                         return 0;
190                 }
191                 else if (frame < framenum)
192                         return 0;
193                         
194                 /* 'Last' Keyframe */
195                 framenum= array[(arraylen-1)].vec[1][0];
196                 if (IS_EQT(frame, framenum, BEZT_INSERT_THRESH)) {
197                         *replace= 1;
198                         return (arraylen - 1);
199                 }
200                 else if (frame > framenum)
201                         return arraylen;
202         }
203         
204         
205         /* most of the time, this loop is just to find where to put it
206          * 'loopbreaker' is just here to prevent infinite loops 
207          */
208         for (loopbreaker=0; (start <= end) && (loopbreaker < maxloop); loopbreaker++) {
209                 /* compute and get midpoint */
210                 int mid = (start + end) / 2;
211                 float midfra= array[mid].vec[1][0];
212                 
213                 /* check if exactly equal to midpoint */
214                 if (IS_EQT(frame, midfra, BEZT_INSERT_THRESH)) {
215                         *replace = 1;
216                         return mid;
217                 }
218                 
219                 /* repeat in upper/lower half */
220                 if (frame > midfra)
221                         start= mid + 1;
222                 else if (frame < midfra)
223                         end= mid - 1;
224         }
225         
226         /* print error if loop-limit exceeded */
227         if (loopbreaker == (maxloop-1)) {
228                 printf("Error: binarysearch_bezt_index() was taking too long \n");
229                 
230                 // include debug info 
231                 printf("\tround = %d: start = %d, end = %d, arraylen = %d \n", loopbreaker, start, end, arraylen);
232         }
233         
234         /* not found, so return where to place it */
235         return start;
236 }
237
238 /* This function adds a given BezTriple to an F-Curve. It will allocate 
239  * memory for the array if needed, and will insert the BezTriple into a
240  * suitable place in chronological order.
241  * 
242  * NOTE: any recalculate of the F-Curve that needs to be done will need to 
243  *              be done by the caller.
244  */
245 int insert_bezt_fcurve (FCurve *fcu, BezTriple *bezt)
246 {
247         BezTriple *newb;
248         int i= 0;
249         
250         if (fcu->bezt) {
251                 short replace = -1;
252                 i = binarysearch_bezt_index(fcu->bezt, bezt->vec[1][0], fcu->totvert, &replace);
253                 
254                 if (replace) {                  
255                         /* sanity check: 'i' may in rare cases exceed arraylen */
256                         // FIXME: do not overwrite handletype if just replacing...?
257                         if ((i >= 0) && (i < fcu->totvert))
258                                 *(fcu->bezt + i) = *bezt;
259                 }
260                 else {
261                         /* add new */
262                         newb= MEM_callocN((fcu->totvert+1)*sizeof(BezTriple), "beztriple");
263                         
264                         /* add the beztriples that should occur before the beztriple to be pasted (originally in ei->icu) */
265                         if (i > 0)
266                                 memcpy(newb, fcu->bezt, i*sizeof(BezTriple));
267                         
268                         /* add beztriple to paste at index i */
269                         *(newb + i)= *bezt;
270                         
271                         /* add the beztriples that occur after the beztriple to be pasted (originally in icu) */
272                         if (i < fcu->totvert) 
273                                 memcpy(newb+i+1, fcu->bezt+i, (fcu->totvert-i)*sizeof(BezTriple));
274                         
275                         /* replace (+ free) old with new */
276                         MEM_freeN(fcu->bezt);
277                         fcu->bezt= newb;
278                         
279                         fcu->totvert++;
280                 }
281         }
282         else {
283                 // TODO: need to check for old sample-data now...
284                 fcu->bezt= MEM_callocN(sizeof(BezTriple), "beztriple");
285                 *(fcu->bezt)= *bezt;
286                 fcu->totvert= 1;
287         }
288         
289         
290         /* we need to return the index, so that some tools which do post-processing can 
291          * detect where we added the BezTriple in the array
292          */
293         return i;
294 }
295
296 /* This function is a wrapper for insert_bezt_icu, and should be used when
297  * adding a new keyframe to a curve, when the keyframe doesn't exist anywhere
298  * else yet. 
299  * 
300  * 'fast' - is only for the python API where importing BVH's would take an extreamly long time.
301  */
302 void insert_vert_fcurve (FCurve *fcu, float x, float y, short fast)
303 {
304         BezTriple beztr;
305         int a;
306         
307         /* set all three points, for nicer start position */
308         memset(&beztr, 0, sizeof(BezTriple));
309         beztr.vec[0][0]= x; 
310         beztr.vec[0][1]= y;
311         beztr.vec[1][0]= x;
312         beztr.vec[1][1]= y;
313         beztr.vec[2][0]= x;
314         beztr.vec[2][1]= y;
315         beztr.ipo= U.ipo_new; /* use default interpolation mode here... */
316         beztr.f1= beztr.f2= beztr.f3= SELECT;
317         beztr.h1= beztr.h2= HD_AUTO; // XXX what about when we replace an old one?
318         
319         /* add temp beztriple to keyframes */
320         a= insert_bezt_fcurve(fcu, &beztr);
321         
322         /* what if 'a' is a negative index? 
323          * for now, just exit to prevent any segfaults
324          */
325         if (a < 0) return;
326         
327         /* don't recalculate handles if fast is set
328          *      - this is a hack to make importers faster
329          *      - we may calculate twice (see editipo_changed(), due to autohandle needing two calculations)
330          */
331         if (!fast) calchandles_fcurve(fcu);
332         
333         /* set handletype and interpolation */
334         if (fcu->totvert > 2) {
335                 BezTriple *bezt= (fcu->bezt + a);
336                 char h1, h2;
337                 
338                 /* set handles (autohandles by default) */
339                 h1= h2= HD_AUTO;
340                 
341                 if (a > 0) h1= (bezt-1)->h2;
342                 if (a < fcu->totvert-1) h2= (bezt+1)->h1;
343                 
344                 bezt->h1= h1;
345                 bezt->h2= h2;
346                 
347                 /* set interpolation from previous (if available) */
348                 if (a > 0) bezt->ipo= (bezt-1)->ipo;
349                 else if (a < fcu->totvert-1) bezt->ipo= (bezt+1)->ipo;
350                         
351                 /* don't recalculate handles if fast is set
352                  *      - this is a hack to make importers faster
353                  *      - we may calculate twice (see editipo_changed(), due to autohandle needing two calculations)
354                  */
355                 if (!fast) calchandles_fcurve(fcu);
356         }
357 }
358
359 /* -------------- 'Smarter' Keyframing Functions -------------------- */
360 /* return codes for new_key_needed */
361 enum {
362         KEYNEEDED_DONTADD = 0,
363         KEYNEEDED_JUSTADD,
364         KEYNEEDED_DELPREV,
365         KEYNEEDED_DELNEXT
366 } eKeyNeededStatus;
367
368 /* This helper function determines whether a new keyframe is needed */
369 /* Cases where keyframes should not be added:
370  *      1. Keyframe to be added bewteen two keyframes with similar values
371  *      2. Keyframe to be added on frame where two keyframes are already situated
372  *      3. Keyframe lies at point that intersects the linear line between two keyframes
373  */
374 static short new_key_needed (FCurve *fcu, float cFrame, float nValue) 
375 {
376         BezTriple *bezt=NULL, *prev=NULL;
377         int totCount, i;
378         float valA = 0.0f, valB = 0.0f;
379         
380         /* safety checking */
381         if (fcu == NULL) return KEYNEEDED_JUSTADD;
382         totCount= fcu->totvert;
383         if (totCount == 0) return KEYNEEDED_JUSTADD;
384         
385         /* loop through checking if any are the same */
386         bezt= fcu->bezt;
387         for (i=0; i<totCount; i++) {
388                 float prevPosi=0.0f, prevVal=0.0f;
389                 float beztPosi=0.0f, beztVal=0.0f;
390                         
391                 /* get current time+value */    
392                 beztPosi= bezt->vec[1][0];
393                 beztVal= bezt->vec[1][1];
394                         
395                 if (prev) {
396                         /* there is a keyframe before the one currently being examined */               
397                         
398                         /* get previous time+value */
399                         prevPosi= prev->vec[1][0];
400                         prevVal= prev->vec[1][1];
401                         
402                         /* keyframe to be added at point where there are already two similar points? */
403                         if (IS_EQ(prevPosi, cFrame) && IS_EQ(beztPosi, cFrame) && IS_EQ(beztPosi, prevPosi)) {
404                                 return KEYNEEDED_DONTADD;
405                         }
406                         
407                         /* keyframe between prev+current points ? */
408                         if ((prevPosi <= cFrame) && (cFrame <= beztPosi)) {
409                                 /* is the value of keyframe to be added the same as keyframes on either side ? */
410                                 if (IS_EQ(prevVal, nValue) && IS_EQ(beztVal, nValue) && IS_EQ(prevVal, beztVal)) {
411                                         return KEYNEEDED_DONTADD;
412                                 }
413                                 else {
414                                         float realVal;
415                                         
416                                         /* get real value of curve at that point */
417                                         realVal= evaluate_fcurve(fcu, cFrame);
418                                         
419                                         /* compare whether it's the same as proposed */
420                                         if (IS_EQ(realVal, nValue)) 
421                                                 return KEYNEEDED_DONTADD;
422                                         else 
423                                                 return KEYNEEDED_JUSTADD;
424                                 }
425                         }
426                         
427                         /* new keyframe before prev beztriple? */
428                         if (cFrame < prevPosi) {
429                                 /* A new keyframe will be added. However, whether the previous beztriple
430                                  * stays around or not depends on whether the values of previous/current
431                                  * beztriples and new keyframe are the same.
432                                  */
433                                 if (IS_EQ(prevVal, nValue) && IS_EQ(beztVal, nValue) && IS_EQ(prevVal, beztVal))
434                                         return KEYNEEDED_DELNEXT;
435                                 else 
436                                         return KEYNEEDED_JUSTADD;
437                         }
438                 }
439                 else {
440                         /* just add a keyframe if there's only one keyframe 
441                          * and the new one occurs before the exisiting one does.
442                          */
443                         if ((cFrame < beztPosi) && (totCount==1))
444                                 return KEYNEEDED_JUSTADD;
445                 }
446                 
447                 /* continue. frame to do not yet passed (or other conditions not met) */
448                 if (i < (totCount-1)) {
449                         prev= bezt;
450                         bezt++;
451                 }
452                 else
453                         break;
454         }
455         
456         /* Frame in which to add a new-keyframe occurs after all other keys
457          * -> If there are at least two existing keyframes, then if the values of the
458          *       last two keyframes and the new-keyframe match, the last existing keyframe
459          *       gets deleted as it is no longer required.
460          * -> Otherwise, a keyframe is just added. 1.0 is added so that fake-2nd-to-last
461          *       keyframe is not equal to last keyframe.
462          */
463         bezt= (fcu->bezt + (fcu->totvert - 1));
464         valA= bezt->vec[1][1];
465         
466         if (prev)
467                 valB= prev->vec[1][1];
468         else 
469                 valB= bezt->vec[1][1] + 1.0f; 
470                 
471         if (IS_EQ(valA, nValue) && IS_EQ(valA, valB)) 
472                 return KEYNEEDED_DELPREV;
473         else 
474                 return KEYNEEDED_JUSTADD;
475 }
476
477 /* ------------------ RNA Data-Access Functions ------------------ */
478
479 /* Try to read value using RNA-properties obtained already */
480 static float setting_get_rna_value (PointerRNA *ptr, PropertyRNA *prop, int index)
481 {
482         float value= 0.0f;
483         
484         switch (RNA_property_type(ptr, prop)) {
485                 case PROP_BOOLEAN:
486                         if (RNA_property_array_length(ptr, prop))
487                                 value= (float)RNA_property_boolean_get_index(ptr, prop, index);
488                         else
489                                 value= (float)RNA_property_boolean_get(ptr, prop);
490                         break;
491                 case PROP_INT:
492                         if (RNA_property_array_length(ptr, prop))
493                                 value= (float)RNA_property_int_get_index(ptr, prop, index);
494                         else
495                                 value= (float)RNA_property_int_get(ptr, prop);
496                         break;
497                 case PROP_FLOAT:
498                         if (RNA_property_array_length(ptr, prop))
499                                 value= RNA_property_float_get_index(ptr, prop, index);
500                         else
501                                 value= RNA_property_float_get(ptr, prop);
502                         break;
503                 case PROP_ENUM:
504                         value= (float)RNA_property_enum_get(ptr, prop);
505                         break;
506                 default:
507                         break;
508         }
509         
510         return value;
511 }
512
513 /* ------------------ 'Visual' Keyframing Functions ------------------ */
514
515 /* internal status codes for visualkey_can_use */
516 enum {
517         VISUALKEY_NONE = 0,
518         VISUALKEY_LOC,
519         VISUALKEY_ROT,
520 };
521
522 /* This helper function determines if visual-keyframing should be used when  
523  * inserting keyframes for the given channel. As visual-keyframing only works
524  * on Object and Pose-Channel blocks, this should only get called for those 
525  * blocktypes, when using "standard" keying but 'Visual Keying' option in Auto-Keying 
526  * settings is on.
527  */
528 static short visualkey_can_use (PointerRNA *ptr, PropertyRNA *prop)
529 {
530         //Object *ob= NULL;
531         bConstraint *con= NULL;
532         short searchtype= VISUALKEY_NONE;
533         
534 #if 0 //  XXX old animation system      
535         /* validate data */
536         if ((id == NULL) || (GS(id->name)!=ID_OB) || !(ELEM(blocktype, ID_OB, ID_PO))) 
537                 return 0;       
538         
539         /* get first constraint and determine type of keyframe constraints to check for*/
540         ob= (Object *)id;
541         
542         if (blocktype == ID_OB) {
543                 con= ob->constraints.first;
544                 
545                 if (ELEM3(adrcode, OB_LOC_X, OB_LOC_Y, OB_LOC_Z))
546                         searchtype= VISUALKEY_LOC;
547                 else if (ELEM3(adrcode, OB_ROT_X, OB_ROT_Y, OB_ROT_Z))
548                         searchtype= VISUALKEY_ROT;
549         }
550         else if (blocktype == ID_PO) {
551                 bPoseChannel *pchan= get_pose_channel(ob->pose, actname);
552                 con= pchan->constraints.first;
553                 
554                 if (ELEM3(adrcode, AC_LOC_X, AC_LOC_Y, AC_LOC_Z))
555                         searchtype= VISUALKEY_LOC;
556                 else if (ELEM4(adrcode, AC_QUAT_W, AC_QUAT_X, AC_QUAT_Y, AC_QUAT_Z))
557                         searchtype= VISUALKEY_ROT;
558         }
559 #endif
560         
561         /* only search if a searchtype and initial constraint are available */
562         if (searchtype && con) {
563                 for (; con; con= con->next) {
564                         /* only consider constraint if it is not disabled, and has influence */
565                         if (con->flag & CONSTRAINT_DISABLE) continue;
566                         if (con->enforce == 0.0f) continue;
567                         
568                         /* some constraints may alter these transforms */
569                         switch (con->type) {
570                                 /* multi-transform constraints */
571                                 case CONSTRAINT_TYPE_CHILDOF:
572                                         return 1;
573                                 case CONSTRAINT_TYPE_TRANSFORM:
574                                         return 1;
575                                 case CONSTRAINT_TYPE_FOLLOWPATH:
576                                         return 1;
577                                 case CONSTRAINT_TYPE_KINEMATIC:
578                                         return 1;
579                                         
580                                 /* single-transform constraits  */
581                                 case CONSTRAINT_TYPE_TRACKTO:
582                                         if (searchtype==VISUALKEY_ROT) return 1;
583                                         break;
584                                 case CONSTRAINT_TYPE_ROTLIMIT:
585                                         if (searchtype==VISUALKEY_ROT) return 1;
586                                         break;
587                                 case CONSTRAINT_TYPE_LOCLIMIT:
588                                         if (searchtype==VISUALKEY_LOC) return 1;
589                                         break;
590                                 case CONSTRAINT_TYPE_ROTLIKE:
591                                         if (searchtype==VISUALKEY_ROT) return 1;
592                                         break;
593                                 case CONSTRAINT_TYPE_DISTLIMIT:
594                                         if (searchtype==VISUALKEY_LOC) return 1;
595                                         break;
596                                 case CONSTRAINT_TYPE_LOCLIKE:
597                                         if (searchtype==VISUALKEY_LOC) return 1;
598                                         break;
599                                 case CONSTRAINT_TYPE_LOCKTRACK:
600                                         if (searchtype==VISUALKEY_ROT) return 1;
601                                         break;
602                                 case CONSTRAINT_TYPE_MINMAX:
603                                         if (searchtype==VISUALKEY_LOC) return 1;
604                                         break;
605                                 
606                                 default:
607                                         break;
608                         }
609                 }
610         }
611         
612         /* when some condition is met, this function returns, so here it can be 0 */
613         return 0;
614 }
615
616 /* This helper function extracts the value to use for visual-keyframing 
617  * In the event that it is not possible to perform visual keying, try to fall-back
618  * to using the default method. Assumes that all data it has been passed is valid.
619  */
620 // xxx... ptr here should be struct that data is in.... prop is the channel that's being used
621 static float visualkey_get_value (PointerRNA *ptr, PropertyRNA *prop, int array_index)
622 {
623 #if 0 // XXX old animation system
624         Object *ob;
625         void *poin = NULL;
626         int index, vartype;
627         
628         /* validate situtation */
629         if ((id==NULL) || (GS(id->name)!=ID_OB) || (ELEM(blocktype, ID_OB, ID_PO)==0))
630                 return 0.0f;
631                 
632         /* get object */
633         ob= (Object *)id;
634         
635         /* only valid for objects or posechannels */
636         if (blocktype == ID_OB) {
637                 /* parented objects are not supported, as the effects of the parent
638                  * are included in the matrix, which kindof beats the point
639                  */
640                 if (ob->parent == NULL) {
641                         /* only Location or Rotation keyframes are supported now */
642                         if (ELEM3(adrcode, OB_LOC_X, OB_LOC_Y, OB_LOC_Z)) {
643                                 /* assumes that OB_LOC_Z > OB_LOC_Y > OB_LOC_X */
644                                 index= adrcode - OB_LOC_X;
645                                 
646                                 return ob->obmat[3][index];
647                         }
648                         else if (ELEM3(adrcode, OB_ROT_X, OB_ROT_Y, OB_ROT_Z)) {
649                                 float eul[3];
650                                 
651                                 /* assumes that OB_ROT_Z > OB_ROT_Y > OB_ROT_X */
652                                 index= adrcode - OB_ROT_X;
653                                 
654                                 Mat4ToEul(ob->obmat, eul);
655                                 return eul[index]*(5.72958f);
656                         }
657                 }
658         }
659         else if (blocktype == ID_PO) {
660                 bPoseChannel *pchan;
661                 float tmat[4][4];
662                 
663                 /* get data to use */
664                 pchan= get_pose_channel(ob->pose, actname);
665                 
666                 /* Although it is not strictly required for this particular space conversion, 
667                  * arg1 must not be null, as there is a null check for the other conversions to
668                  * be safe. Therefore, the active object is passed here, and in many cases, this
669                  * will be what owns the pose-channel that is getting this anyway.
670                  */
671                 Mat4CpyMat4(tmat, pchan->pose_mat);
672                 constraint_mat_convertspace(ob, pchan, tmat, CONSTRAINT_SPACE_POSE, CONSTRAINT_SPACE_LOCAL);
673                 
674                 /* Loc, Rot/Quat keyframes are supported... */
675                 if (ELEM3(adrcode, AC_LOC_X, AC_LOC_Y, AC_LOC_Z)) {
676                         /* assumes that AC_LOC_Z > AC_LOC_Y > AC_LOC_X */
677                         index= adrcode - AC_LOC_X;
678                         
679                         /* only use for non-connected bones */
680                         if ((pchan->bone->parent) && !(pchan->bone->flag & BONE_CONNECTED))
681                                 return tmat[3][index];
682                         else if (pchan->bone->parent == NULL)
683                                 return tmat[3][index];
684                 }
685                 else if (ELEM4(adrcode, AC_QUAT_W, AC_QUAT_X, AC_QUAT_Y, AC_QUAT_Z)) {
686                         float trimat[3][3], quat[4];
687                         
688                         /* assumes that AC_QUAT_Z > AC_QUAT_Y > AC_QUAT_X > AC_QUAT_W */
689                         index= adrcode - AC_QUAT_W;
690                         
691                         Mat3CpyMat4(trimat, tmat);
692                         Mat3ToQuat_is_ok(trimat, quat);
693                         
694                         return quat[index];
695                 }
696         }
697 #endif  // XXX old animation system
698         
699         /* as the function hasn't returned yet, read value from system in the default way */
700         return setting_get_rna_value(ptr, prop, array_index);
701 }
702
703 /* ------------------------- Insert Key API ------------------------- */
704
705 /* Main Keyframing API call:
706  *      Use this when validation of necessary animation data isn't necessary as it
707  *      already exists. It will insert a keyframe using the current value being keyframed.
708  *      
709  *      The flag argument is used for special settings that alter the behaviour of
710  *      the keyframe insertion. These include the 'visual' keyframing modes, quick refresh,
711  *      and extra keyframe filtering.
712  */
713 short insertkey (ID *id, const char group[], const char rna_path[], int array_index, float cfra, short flag)
714 {       
715         PointerRNA id_ptr, ptr;
716         PropertyRNA *prop;
717         FCurve *fcu;
718         
719         /* validate pointer first - exit if failure*/
720         RNA_id_pointer_create(id, &id_ptr);
721         if (RNA_path_resolve(&id_ptr, rna_path, &ptr, &prop) == 0) {
722                 printf("Insert Key: Could not insert keyframe, as RNA Path is invalid for the given ID \n");
723                 return 0;
724         }
725         
726         /* get F-Curve */
727         fcu= verify_fcurve(id, group, rna_path, array_index, 1);
728         
729         /* only continue if we have an F-Curve to add keyframe to */
730         if (fcu) {
731                 float curval= 0.0f;
732                 
733                 /* set additional flags for the F-Curve (i.e. only integer values) */
734                 if (RNA_property_type(&ptr, prop) != PROP_FLOAT)
735                         fcu->flag |= FCURVE_INT_VALUES;
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         /* 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=0, 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 /* NOTE:
2091  * This is one of the 'simpler new-style' Insert Keyframe operators which relies on Keying Sets.
2092  * For now, these are absolute Keying Sets only, so there is very little context info involved.
2093  *
2094  *      -- Joshua Leung, Feb 2009
2095  */
2096
2097 static int insert_key_exec (bContext *C, wmOperator *op)
2098 {
2099         ListBase dsources = {NULL, NULL};
2100         Scene *scene= CTX_data_scene(C);
2101         KeyingSet *ks= NULL;
2102         float cfra= (float)CFRA; // XXX for now, don't bother about all the yucky offset crap
2103         short success;
2104         
2105         /* try to get KeyingSet */
2106         if (scene->active_keyingset > 0)
2107                 ks= BLI_findlink(&scene->keyingsets, scene->active_keyingset-1);
2108         /* report failure */
2109         if (ks == NULL) {
2110                 BKE_report(op->reports, RPT_ERROR, "No active Keying Set");
2111                 return OPERATOR_CANCELLED;
2112         }
2113         
2114         /* try to insert keyframes for the channels specified by KeyingSet */
2115         success= commonkey_modifykey(&dsources, ks, COMMONKEY_MODE_INSERT, cfra);
2116         printf("KeyingSet '%s' - Successfully added %d Keyframes \n", ks->name, success);
2117         
2118         /* report failure? */
2119         if (success == 0)
2120                 BKE_report(op->reports, RPT_WARNING, "Keying Set failed to insert any keyframes");
2121         
2122         /* send updates */
2123         ED_anim_dag_flush_update(C);    
2124         
2125         /* for now, only send ND_KEYS for KeyingSets */
2126         WM_event_add_notifier(C, ND_KEYS, NULL);
2127         
2128         return OPERATOR_FINISHED;
2129 }
2130
2131 void ANIM_OT_insert_keyframe (wmOperatorType *ot)
2132 {
2133         /* identifiers */
2134         ot->name= "Insert Keyframe";
2135         ot->idname= "ANIM_OT_insert_keyframe";
2136         
2137         /* callbacks */
2138         ot->exec= insert_key_exec; 
2139         ot->poll= ED_operator_areaactive;
2140         
2141         /* flags */
2142         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2143 }
2144
2145 /* Delete Key Operator ------------------------ */
2146
2147 /* NOTE:
2148  * This is one of the 'simpler new-style' Insert Keyframe operators which relies on Keying Sets.
2149  * For now, these are absolute Keying Sets only, so there is very little context info involved.
2150  *
2151  *      -- Joshua Leung, Feb 2009
2152  */
2153  
2154 static int delete_key_exec (bContext *C, wmOperator *op)
2155 {
2156         ListBase dsources = {NULL, NULL};
2157         Scene *scene= CTX_data_scene(C);
2158         KeyingSet *ks= NULL;
2159         float cfra= (float)CFRA; // XXX for now, don't bother about all the yucky offset crap
2160         short success;
2161         
2162         /* try to get KeyingSet */
2163         if (scene->active_keyingset > 0)
2164                 ks= BLI_findlink(&scene->keyingsets, scene->active_keyingset-1);
2165         /* report failure */
2166         if (ks == NULL) {
2167                 BKE_report(op->reports, RPT_ERROR, "No active Keying Set");
2168                 return OPERATOR_CANCELLED;
2169         }
2170         
2171         /* try to insert keyframes for the channels specified by KeyingSet */
2172         success= commonkey_modifykey(&dsources, ks, COMMONKEY_MODE_DELETE, cfra);
2173         printf("KeyingSet '%s' - Successfully removed %d Keyframes \n", ks->name, success);
2174         
2175         /* report failure? */
2176         if (success == 0)
2177                 BKE_report(op->reports, RPT_WARNING, "Keying Set failed to remove any keyframes");
2178         
2179         /* send updates */
2180         ED_anim_dag_flush_update(C);    
2181         
2182         /* for now, only send ND_KEYS for KeyingSets */
2183         WM_event_add_notifier(C, ND_KEYS, NULL);
2184         
2185         return OPERATOR_FINISHED;
2186 }
2187
2188 void ANIM_OT_delete_keyframe (wmOperatorType *ot)
2189 {
2190         /* identifiers */
2191         ot->name= "Delete Keyframe";
2192         ot->idname= "ANIM_OT_delete_keyframe";
2193         
2194         /* callbacks */
2195         ot->exec= delete_key_exec; 
2196         
2197         ot->poll= ED_operator_areaactive;
2198         
2199         /* flags */
2200         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2201 }
2202
2203 /* Insert Key Operator ------------------------ */
2204
2205 /* XXX WARNING:
2206  * This is currently just a basic operator, which work in 3d-view context on objects/bones only
2207  * and will insert keyframes for a few settings only. This is until it becomes clear how
2208  * to separate (or not) the process for RNA-path creation between context + keyingsets.
2209  * 
2210  * -- Joshua Leung, Jan 2009
2211  */
2212
2213 /* defines for basic insert-key testing operator  */
2214         // XXX this will definitely be replaced
2215 EnumPropertyItem prop_insertkey_types[] = {
2216         {0, "KEYINGSET", "Active KeyingSet", ""},
2217         {1, "OBLOC", "Object Location", ""},
2218         {2, "OBROT", "Object Rotation", ""},
2219         {3, "OBSCALE", "Object Scale", ""},
2220         {4, "MAT_COL", "Active Material - Color", ""},
2221         {5, "PCHANLOC", "Pose-Channel Location", ""},
2222         {6, "PCHANROT", "Pose-Channel Rotation", ""},
2223         {7, "PCHANSCALE", "Pose-Channel Scale", ""},
2224         {0, NULL, NULL, NULL}
2225 };
2226
2227 static int insert_key_old_invoke (bContext *C, wmOperator *op, wmEvent *event)
2228 {
2229         Object *ob= CTX_data_active_object(C);
2230         uiMenuItem *head;
2231         
2232         if (ob == NULL)
2233                 return OPERATOR_CANCELLED;
2234                 
2235         head= uiPupMenuBegin("Insert Keyframe", 0);
2236         
2237         /* active keyingset */
2238         uiMenuItemEnumO(head, "", 0, "ANIM_OT_insert_keyframe", "type", 0);
2239         
2240         /* selective inclusion */
2241         if ((ob->pose) && (ob->flag & OB_POSEMODE)) {
2242                 /* bone types */        
2243                 uiMenuItemEnumO(head, "", 0, "ANIM_OT_insert_keyframe", "type", 5);
2244                 uiMenuItemEnumO(head, "", 0, "ANIM_OT_insert_keyframe", "type", 6);
2245                 uiMenuItemEnumO(head, "", 0, "ANIM_OT_insert_keyframe", "type", 7);
2246         }
2247         else {
2248                 /* object types */
2249                 uiMenuItemEnumO(head, "", 0, "ANIM_OT_insert_keyframe", "type", 1);
2250                 uiMenuItemEnumO(head, "", 0, "ANIM_OT_insert_keyframe", "type", 2);
2251                 uiMenuItemEnumO(head, "", 0, "ANIM_OT_insert_keyframe", "type", 3);
2252                 uiMenuItemEnumO(head, "", 0, "ANIM_OT_insert_keyframe", "type", 4);
2253         }
2254         
2255         uiPupMenuEnd(C, head);
2256         
2257         return OPERATOR_CANCELLED;
2258 }
2259  
2260 static int insert_key_old_exec (bContext *C, wmOperator *op)
2261 {
2262         Scene *scene= CTX_data_scene(C);
2263         short mode= RNA_enum_get(op->ptr, "type");
2264         float cfra= (float)CFRA; // XXX for now, don't bother about all the yucky offset crap
2265         
2266         /* for now, handle 'active keyingset' one separately */
2267         if (mode == 0) {
2268                 ListBase dsources = {NULL, NULL};
2269                 KeyingSet *ks= NULL;
2270                 short success;
2271                 
2272                 /* try to get KeyingSet */
2273                 if (scene->active_keyingset > 0)
2274                         ks= BLI_findlink(&scene->keyingsets, scene->active_keyingset-1);
2275                 /* report failure */
2276                 if (ks == NULL) {
2277                         BKE_report(op->reports, RPT_ERROR, "No active Keying Set");
2278                         return OPERATOR_CANCELLED;
2279                 }
2280                 
2281                 /* try to insert keyframes for the channels specified by KeyingSet */
2282                 success= commonkey_modifykey(&dsources, ks, COMMONKEY_MODE_INSERT, cfra);
2283                 printf("KeyingSet '%s' - Successfully added %d Keyframes \n", ks->name, success);
2284                 
2285                 /* report failure? */
2286                 if (success == 0)
2287                         BKE_report(op->reports, RPT_WARNING, "Keying Set failed to insert any keyframes");
2288         }
2289         else {
2290                 // more comprehensive tests will be needed
2291                 CTX_DATA_BEGIN(C, Base*, base, selected_bases) 
2292                 {
2293                         Object *ob= base->object;
2294                         ID *id= (ID *)ob;
2295                         short success= 0;
2296                         
2297                         /* check which keyframing mode chosen for this object */
2298                         if (mode < 4) {
2299                                 /* object-based keyframes */
2300                                 switch (mode) {
2301                                 case 4: /* color of active material (only for geometry...) */
2302                                         // NOTE: this is just a demo... but ideally we'd go through materials instead of active one only so reference stays same
2303                                         // XXX no group for now
2304                                         success+= insertkey(id, NULL, "active_material.diffuse_color", 0, cfra, 0);
2305                                         success+= insertkey(id, NULL, "active_material.diffuse_color", 1, cfra, 0);
2306                                         success+= insertkey(id, NULL, "active_material.diffuse_color", 2, cfra, 0);
2307                                         break;
2308                                 case 3: /* object scale */
2309                                         success+= insertkey(id, "Object Transforms", "scale", 0, cfra, 0);
2310                                         success+= insertkey(id, "Object Transforms", "scale", 1, cfra, 0);
2311                                         success+= insertkey(id, "Object Transforms", "scale", 2, cfra, 0);
2312                                         break;
2313                                 case 2: /* object rotation */
2314                                         success+= insertkey(id, "Object Transforms", "rotation", 0, cfra, 0);
2315                                         success+= insertkey(id, "Object Transforms", "rotation", 1, cfra, 0);
2316                                         success+= insertkey(id, "Object Transforms", "rotation", 2, cfra, 0);
2317                                         break;
2318                                 case 1: /* object location */
2319                                         success+= insertkey(id, "Object Transforms", "location", 0, cfra, 0);
2320                                         success+= insertkey(id, "Object Transforms", "location", 1, cfra, 0);
2321                                         success+= insertkey(id, "Object Transforms", "location", 2, cfra, 0);
2322                                         break;
2323                                 }
2324                                 
2325                                 ob->recalc |= OB_RECALC_OB;
2326                         }
2327                         else if ((ob->pose) && (ob->flag & OB_POSEMODE)) {
2328                                 /* PoseChannel based keyframes */
2329                                 bPoseChannel *pchan;
2330                                 
2331                                 for (pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
2332                                         /* only if selected */
2333                                         if ((pchan->bone) && (pchan->bone->flag & BONE_SELECTED)) {
2334                                                 char buf[512];
2335                                                 
2336                                                 switch (mode) {
2337                                                 case 6: /* pchan scale */
2338                                                         sprintf(buf, "pose.pose_channels[\"%s\"].scale", pchan->name);
2339                                                         success+= insertkey(id, pchan->name, buf, 0, cfra, 0);
2340                                                         success+= insertkey(id, pchan->name, buf, 1, cfra, 0);
2341                                                         success+= insertkey(id, pchan->name, buf, 2, cfra, 0);
2342                                                         break;
2343                                                 case 5: /* pchan rotation */
2344                                                         if (pchan->rotmode == PCHAN_ROT_QUAT) {
2345                                                                 sprintf(buf, "pose.pose_channels[\"%s\"].rotation", pchan->name);
2346                                                                 success+= insertkey(id, pchan->name, buf, 0, cfra, 0);
2347                                                                 success+= insertkey(id, pchan->name, buf, 1, cfra, 0);
2348                                                                 success+= insertkey(id, pchan->name, buf, 2, cfra, 0);
2349                                                                 success+= insertkey(id, pchan->name, buf, 3, cfra, 0);
2350                                                         }
2351                                                         else {
2352                                                                 sprintf(buf, "pose.pose_channels[\"%s\"].euler_rotation", pchan->name);
2353                                                                 success+= insertkey(id, pchan->name, buf, 0, cfra, 0);
2354                                                                 success+= insertkey(id, pchan->name, buf, 1, cfra, 0);
2355                                                                 success+= insertkey(id, pchan->name, buf, 2, cfra, 0);
2356                                                         }
2357                                                         break;
2358                                                 default: /* pchan location */
2359                                                         sprintf(buf, "pose.pose_channels[\"%s\"].location", pchan->name);
2360                                                         success+= insertkey(id, pchan->name, buf, 0, cfra, 0);
2361                                                         success+= insertkey(id, pchan->name, buf, 1, cfra, 0);
2362                                                         success+= insertkey(id, pchan->name, buf, 2, cfra, 0);
2363                                                         break;
2364                                                 }
2365                                         }
2366                                 }
2367                                 
2368                                 ob->recalc |= OB_RECALC_OB;
2369                         }
2370                         
2371                         printf("Ob '%s' - Successfully added %d Keyframes \n", id->name+2, success);
2372                 }
2373                 CTX_DATA_END;
2374         }
2375         
2376         /* send updates */
2377         ED_anim_dag_flush_update(C);    
2378         
2379         if (mode == 0) /* for now, only send ND_KEYS for KeyingSets */
2380                 WM_event_add_notifier(C, ND_KEYS, NULL);
2381         else if (mode == 4) /* material color requires different notifiers */
2382                 WM_event_add_notifier(C, NC_MATERIAL|ND_KEYS, NULL);
2383         else
2384                 WM_event_add_notifier(C, NC_OBJECT|ND_KEYS, NULL);
2385         
2386         return OPERATOR_FINISHED;
2387 }
2388
2389 void ANIM_OT_insert_keyframe_old (wmOperatorType *ot)
2390 {
2391         PropertyRNA *prop;
2392         
2393         /* identifiers */
2394         ot->name= "Insert Keyframe";
2395         ot->idname= "ANIM_OT_insert_keyframe_old";
2396         
2397         /* callbacks */
2398         ot->invoke= insert_key_old_invoke;
2399         ot->exec= insert_key_old_exec; 
2400         ot->poll= ED_operator_areaactive;
2401         
2402         /* flags */
2403         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2404         
2405         /* properties */
2406                 // XXX update this for the latest RNA stuff styles...
2407         prop= RNA_def_property(ot->srna, "type", PROP_ENUM, PROP_NONE);
2408         RNA_def_property_enum_items(prop, prop_insertkey_types);
2409 }
2410
2411 /* Delete Key Operator ------------------------ */
2412
2413 /* XXX WARNING:
2414  * This is currently just a basic operator, which work in 3d-view context on objects only. 
2415  * -- Joshua Leung, Jan 2009
2416  */
2417  
2418 static int delete_key_old_exec (bContext *C, wmOperator *op)
2419 {
2420         Scene *scene= CTX_data_scene(C);
2421         float cfra= (float)CFRA; // XXX for now, don't bother about all the yucky offset crap
2422         
2423         // XXX more comprehensive tests will be needed
2424         CTX_DATA_BEGIN(C, Base*, base, selected_bases) 
2425         {
2426                 Object *ob= base->object;
2427                 ID *id= (ID *)ob;
2428                 FCurve *fcu, *fcn;
2429                 short success= 0;
2430                 
2431                 /* loop through all curves in animdata and delete keys on this frame */
2432                 if (ob->adt) {
2433                         AnimData *adt= ob->adt;
2434                         bAction *act= adt->action;
2435                         
2436                         for (fcu= act->curves.first; fcu; fcu= fcn) {
2437                                 fcn= fcu->next;
2438                                 success+= deletekey(id, NULL, fcu->rna_path, fcu->array_index, cfra, 0);
2439                         }
2440                 }
2441                 
2442                 printf("Ob '%s' - Successfully removed %d keyframes \n", id->name+2, success);
2443                 
2444                 ob->recalc |= OB_RECALC_OB;
2445         }
2446         CTX_DATA_END;
2447         
2448         /* send updates */
2449         ED_anim_dag_flush_update(C);    
2450         
2451                 // XXX what if it was a material keyframe?
2452         WM_event_add_notifier(C, NC_OBJECT|ND_KEYS, NULL);
2453         
2454         return OPERATOR_FINISHED;
2455 }
2456
2457 void ANIM_OT_delete_keyframe_old (wmOperatorType *ot)
2458 {
2459         /* identifiers */
2460         ot->name= "Delete Keyframe";
2461         ot->idname= "ANIM_OT_delete_keyframe_old";
2462         
2463         /* callbacks */
2464         ot->invoke= WM_operator_confirm; // XXX we will need our own one eventually, to cope with the dynamic menus...
2465         ot->exec= delete_key_old_exec; 
2466         
2467         ot->poll= ED_operator_areaactive;
2468         
2469         /* flags */
2470         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2471 }
2472
2473 /* ******************************************* */
2474 /* KEYFRAME DETECTION */
2475
2476 /* --------------- API/Per-Datablock Handling ------------------- */
2477
2478 /* Checks whether an IPO-block has a keyframe for a given frame 
2479  * Since we're only concerned whether a keyframe exists, we can simply loop until a match is found...
2480  */
2481 short action_frame_has_keyframe (bAction *act, float frame, short filter)
2482 {
2483         FCurve *fcu;
2484         
2485         /* can only find if there is data */
2486         if (act == NULL)
2487                 return 0;
2488                 
2489         /* if only check non-muted, check if muted */
2490         if ((filter & ANIMFILTER_KEYS_MUTED) || (act->flag & ACT_MUTED))
2491                 return 0;
2492         
2493         /* loop over F-Curves, using binary-search to try to find matches 
2494          *      - this assumes that keyframes are only beztriples
2495          */
2496         for (fcu= act->curves.first; fcu; fcu= fcu->next) {
2497                 /* only check if there are keyframes (currently only of type BezTriple) */
2498                 if (fcu->bezt && fcu->totvert) {
2499                         /* we either include all regardless of muting, or only non-muted  */
2500                         if ((filter & ANIMFILTER_KEYS_MUTED) || (fcu->flag & FCURVE_MUTED)==0) {
2501                                 short replace = -1;
2502                                 int i = binarysearch_bezt_index(fcu->bezt, frame, fcu->totvert, &replace);
2503                                 
2504                                 /* binarysearch_bezt_index will set replace to be 0 or 1
2505                                  *      - obviously, 1 represents a match
2506                                  */
2507                                 if (replace) {                  
2508                                         /* sanity check: 'i' may in rare cases exceed arraylen */
2509                                         if ((i >= 0) && (i < fcu->totvert))
2510                                                 return 1;
2511                                 }
2512                         }
2513                 }
2514         }
2515         
2516         /* nothing found */
2517         return 0;
2518 }
2519
2520 /* Checks whether an Object has a keyframe for a given frame */
2521 short object_frame_has_keyframe (Object *ob, float frame, short filter)
2522 {
2523         /* error checking */
2524         if (ob == NULL)
2525                 return 0;
2526         
2527         /* check own animation data - specifically, the action it contains */
2528         if ((ob->adt) && (ob->adt->action)) {
2529                 if (action_frame_has_keyframe(ob->adt->action, frame, filter))
2530                         return 1;
2531         }
2532         
2533         /* try shapekey keyframes (if available, and allowed by filter) */
2534         if ( !(filter & ANIMFILTER_KEYS_LOCAL) && !(filter & ANIMFILTER_KEYS_NOSKEY) ) {
2535                 Key *key= ob_get_key(ob);
2536                 
2537                 /* shapekeys can have keyframes ('Relative Shape Keys') 
2538                  * or depend on time (old 'Absolute Shape Keys') 
2539                  */
2540                  
2541                         /* 1. test for relative (with keyframes) */
2542                 if (id_frame_has_keyframe((ID *)key, frame, filter))
2543                         return 1;
2544                         
2545                         /* 2. test for time */
2546                 // TODO... yet to be implemented (this feature may evolve before then anyway)
2547         }
2548         
2549         /* try materials */
2550         if ( !(filter & ANIMFILTER_KEYS_LOCAL) && !(filter & ANIMFILTER_KEYS_NOMAT) ) {
2551                 /* if only active, then we can skip a lot of looping */
2552                 if (filter & ANIMFILTER_KEYS_ACTIVE) {
2553                         Material *ma= give_current_material(ob, (ob->actcol + 1));
2554                         
2555                         /* we only retrieve the active material... */
2556                         if (id_frame_has_keyframe((ID *)ma, frame, filter))
2557                                 return 1;
2558                 }
2559                 else {
2560                         int a;
2561                         
2562                         /* loop over materials */
2563                         for (a=0; a<ob->totcol; a++) {
2564                                 Material *ma= give_current_material(ob, a+1);
2565                                 
2566                                 if (id_frame_has_keyframe((ID *)ma, frame, filter))
2567                                         return 1;
2568                         }
2569                 }
2570         }
2571         
2572         /* nothing found */
2573         return 0;
2574 }
2575
2576 /* --------------- API ------------------- */
2577
2578 /* Checks whether a keyframe exists for the given ID-block one the given frame */
2579 short id_frame_has_keyframe (ID *id, float frame, short filter)
2580 {
2581         /* sanity checks */
2582         if (id == NULL)
2583                 return 0;
2584         
2585         /* perform special checks for 'macro' types */
2586         switch (GS(id->name)) {
2587                 case ID_OB: /* object */
2588                         return object_frame_has_keyframe((Object *)id, frame, filter);
2589                         break;
2590                         
2591                 case ID_SCE: /* scene */
2592                 // XXX TODO... for now, just use 'normal' behaviour
2593                 //      break;
2594                 
2595                 default:        /* 'normal type' */
2596                 {
2597                         AnimData *adt= BKE_animdata_from_id(id);
2598                         
2599                         /* only check keyframes in active action */
2600                         if (adt)
2601                                 return action_frame_has_keyframe(adt->action, frame, filter);
2602                 }
2603                         break;
2604         }
2605         
2606         
2607         /* no keyframe found */
2608         return 0;
2609 }
2610
2611 /* ************************************************** */