NLA SoC: Separating out F-Modifier API
[blender-staging.git] / source / blender / editors / animation / keyframing.c
1 /**
2  * $Id$
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19  *
20  * The Original Code is Copyright (C) 2009 Blender Foundation, Joshua Leung
21  * All rights reserved.
22  *
23  * The Original Code is: all of this file.
24  *
25  * Contributor(s): Joshua Leung (full recode)
26  *
27  * ***** END GPL LICENSE BLOCK *****
28  */
29  
30 #include <stdio.h>
31 #include <stddef.h>
32 #include <string.h>
33 #include <math.h>
34 #include <float.h>
35
36 #include "MEM_guardedalloc.h"
37
38 #include "BLI_blenlib.h"
39 #include "BLI_arithb.h"
40 #include "BLI_dynstr.h"
41
42 #include "DNA_anim_types.h"
43 #include "DNA_action_types.h"
44 #include "DNA_armature_types.h"
45 #include "DNA_constraint_types.h"
46 #include "DNA_key_types.h"
47 #include "DNA_object_types.h"
48 #include "DNA_material_types.h"
49 #include "DNA_scene_types.h"
50 #include "DNA_userdef_types.h"
51 #include "DNA_windowmanager_types.h"
52
53 #include "BKE_animsys.h"
54 #include "BKE_action.h"
55 #include "BKE_constraint.h"
56 #include "BKE_fcurve.h"
57 #include "BKE_global.h"
58 #include "BKE_utildefines.h"
59 #include "BKE_context.h"
60 #include "BKE_report.h"
61 #include "BKE_key.h"
62 #include "BKE_material.h"
63
64 #include "ED_anim_api.h"
65 #include "ED_keyframing.h"
66 #include "ED_keyframes_edit.h"
67 #include "ED_screen.h"
68 #include "ED_util.h"
69
70 #include "UI_interface.h"
71
72 #include "WM_api.h"
73 #include "WM_types.h"
74
75 #include "RNA_access.h"
76 #include "RNA_define.h"
77 #include "RNA_types.h"
78
79 #include "anim_intern.h"
80
81 /* ******************************************* */
82 /* Animation Data Validation */
83
84 /* Get (or add relevant data to be able to do so) the Active Action for the given 
85  * Animation Data block, given an ID block where the Animation Data should reside.
86  */
87 bAction *verify_adt_action (ID *id, short add)
88 {
89         AnimData *adt;
90         
91         /* init animdata if none available yet */
92         adt= BKE_animdata_from_id(id);
93         if ((adt == NULL) && (add))
94                 adt= BKE_id_add_animdata(id);
95         if (adt == NULL) { 
96                 /* if still none (as not allowed to add, or ID doesn't have animdata for some reason) */
97                 printf("ERROR: Couldn't add AnimData (ID = %s) \n", (id) ? (id->name) : "<None>");
98                 return NULL;
99         }
100                 
101         /* init action if none available yet */
102         // TODO: need some wizardry to handle NLA stuff correct
103         if ((adt->action == NULL) && (add))
104                 adt->action= add_empty_action("Action");
105                 
106         /* return the action */
107         return adt->action;
108 }
109
110 /* Get (or add relevant data to be able to do so) F-Curve from the Active Action, 
111  * for the given Animation Data block. This assumes that all the destinations are valid.
112  */
113 FCurve *verify_fcurve (bAction *act, const char group[], const char rna_path[], const int array_index, short add)
114 {
115         bActionGroup *grp;
116         FCurve *fcu;
117         
118         /* sanity checks */
119         if ELEM(NULL, act, rna_path)
120                 return NULL;
121                 
122         /* try to find f-curve matching for this setting 
123          *      - add if not found and allowed to add one
124          *              TODO: add auto-grouping support? how this works will need to be resolved
125          */
126         if (act)
127                 fcu= list_find_fcurve(&act->curves, rna_path, array_index);
128         else
129                 fcu= NULL;
130         
131         if ((fcu == NULL) && (add)) {
132                 /* use default settings to make a F-Curve */
133                 fcu= MEM_callocN(sizeof(FCurve), "FCurve");
134                 
135                 fcu->flag = (FCURVE_VISIBLE|FCURVE_AUTO_HANDLES|FCURVE_SELECTED);
136                 if (act->curves.first==NULL) 
137                         fcu->flag |= FCURVE_ACTIVE;     /* first one added active */
138                         
139                 /* store path - make copy, and store that */
140                 fcu->rna_path= BLI_strdupn(rna_path, strlen(rna_path));
141                 fcu->array_index= array_index;
142                 
143                 /* if a group name has been provided, try to add or find a group, then add F-Curve to it */
144                 if (group) {
145                         /* try to find group */
146                         grp= action_groups_find_named(act, group);
147                         
148                         /* no matching groups, so add one */
149                         if (grp == NULL) {
150                                 /* Add a new group, and make it active */
151                                 grp= MEM_callocN(sizeof(bActionGroup), "bActionGroup");
152                                 
153                                 grp->flag = AGRP_SELECTED;
154                                 BLI_snprintf(grp->name, 64, group);
155                                 
156                                 BLI_addtail(&act->groups, grp);
157                                 BLI_uniquename(&act->groups, grp, "Group", '.', offsetof(bActionGroup, name), 64);
158                         }
159                         
160                         /* add F-Curve to group */
161                         action_groups_add_channel(act, grp, fcu);
162                 }
163                 else {
164                         /* just add F-Curve to end of Action's list */
165                         BLI_addtail(&act->curves, fcu);
166                 }
167         }
168         
169         /* return the F-Curve */
170         return fcu;
171 }
172
173 /* ************************************************** */
174 /* KEYFRAME INSERTION */
175
176 /* -------------- BezTriple Insertion -------------------- */
177
178 /* threshold for inserting keyframes - threshold here should be good enough for now, but should become userpref */
179 #define BEZT_INSERT_THRESH      0.00001f
180
181 /* Binary search algorithm for finding where to insert BezTriple. (for use by insert_bezt_icu)
182  * Returns the index to insert at (data already at that index will be offset if replace is 0)
183  */
184 static int binarysearch_bezt_index (BezTriple array[], float frame, int arraylen, short *replace)
185 {
186         int start=0, end=arraylen;
187         int loopbreaker= 0, maxloop= arraylen * 2;
188         
189         /* initialise replace-flag first */
190         *replace= 0;
191         
192         /* sneaky optimisations (don't go through searching process if...):
193          *      - keyframe to be added is to be added out of current bounds
194          *      - keyframe to be added would replace one of the existing ones on bounds
195          */
196         if ((arraylen <= 0) || (array == NULL)) {
197                 printf("Warning: binarysearch_bezt_index() encountered invalid array \n");
198                 return 0;
199         }
200         else {
201                 /* check whether to add before/after/on */
202                 float framenum;
203                 
204                 /* 'First' Keyframe (when only one keyframe, this case is used) */
205                 framenum= array[0].vec[1][0];
206                 if (IS_EQT(frame, framenum, BEZT_INSERT_THRESH)) {
207                         *replace = 1;
208                         return 0;
209                 }
210                 else if (frame < framenum)
211                         return 0;
212                         
213                 /* 'Last' Keyframe */
214                 framenum= array[(arraylen-1)].vec[1][0];
215                 if (IS_EQT(frame, framenum, BEZT_INSERT_THRESH)) {
216                         *replace= 1;
217                         return (arraylen - 1);
218                 }
219                 else if (frame > framenum)
220                         return arraylen;
221         }
222         
223         
224         /* most of the time, this loop is just to find where to put it
225          * 'loopbreaker' is just here to prevent infinite loops 
226          */
227         for (loopbreaker=0; (start <= end) && (loopbreaker < maxloop); loopbreaker++) {
228                 /* compute and get midpoint */
229                 int mid = start + ((end - start) / 2);  /* we calculate the midpoint this way to avoid int overflows... */
230                 float midfra= array[mid].vec[1][0];
231                 
232                 /* check if exactly equal to midpoint */
233                 if (IS_EQT(frame, midfra, BEZT_INSERT_THRESH)) {
234                         *replace = 1;
235                         return mid;
236                 }
237                 
238                 /* repeat in upper/lower half */
239                 if (frame > midfra)
240                         start= mid + 1;
241                 else if (frame < midfra)
242                         end= mid - 1;
243         }
244         
245         /* print error if loop-limit exceeded */
246         if (loopbreaker == (maxloop-1)) {
247                 printf("Error: binarysearch_bezt_index() was taking too long \n");
248                 
249                 // include debug info 
250                 printf("\tround = %d: start = %d, end = %d, arraylen = %d \n", loopbreaker, start, end, arraylen);
251         }
252         
253         /* not found, so return where to place it */
254         return start;
255 }
256
257 /* This function adds a given BezTriple to an F-Curve. It will allocate 
258  * memory for the array if needed, and will insert the BezTriple into a
259  * suitable place in chronological order.
260  * 
261  * NOTE: any recalculate of the F-Curve that needs to be done will need to 
262  *              be done by the caller.
263  */
264 int insert_bezt_fcurve (FCurve *fcu, BezTriple *bezt)
265 {
266         BezTriple *newb;
267         int i= 0;
268         
269         if (fcu->bezt) {
270                 short replace = -1;
271                 i = binarysearch_bezt_index(fcu->bezt, bezt->vec[1][0], fcu->totvert, &replace);
272                 
273                 if (replace) {                  
274                         /* sanity check: 'i' may in rare cases exceed arraylen */
275                         // FIXME: do not overwrite handletype if just replacing...?
276                         if ((i >= 0) && (i < fcu->totvert))
277                                 *(fcu->bezt + i) = *bezt;
278                 }
279                 else {
280                         /* add new */
281                         newb= MEM_callocN((fcu->totvert+1)*sizeof(BezTriple), "beztriple");
282                         
283                         /* add the beztriples that should occur before the beztriple to be pasted (originally in ei->icu) */
284                         if (i > 0)
285                                 memcpy(newb, fcu->bezt, i*sizeof(BezTriple));
286                         
287                         /* add beztriple to paste at index i */
288                         *(newb + i)= *bezt;
289                         
290                         /* add the beztriples that occur after the beztriple to be pasted (originally in icu) */
291                         if (i < fcu->totvert) 
292                                 memcpy(newb+i+1, fcu->bezt+i, (fcu->totvert-i)*sizeof(BezTriple));
293                         
294                         /* replace (+ free) old with new */
295                         MEM_freeN(fcu->bezt);
296                         fcu->bezt= newb;
297                         
298                         fcu->totvert++;
299                 }
300         }
301         else {
302                 // TODO: need to check for old sample-data now...
303                 fcu->bezt= MEM_callocN(sizeof(BezTriple), "beztriple");
304                 *(fcu->bezt)= *bezt;
305                 fcu->totvert= 1;
306         }
307         
308         
309         /* we need to return the index, so that some tools which do post-processing can 
310          * detect where we added the BezTriple in the array
311          */
312         return i;
313 }
314
315 /* This function is a wrapper for insert_bezt_icu, and should be used when
316  * adding a new keyframe to a curve, when the keyframe doesn't exist anywhere
317  * else yet. 
318  * 
319  * 'fast' - is only for the python API where importing BVH's would take an extreamly long time.
320  */
321 void insert_vert_fcurve (FCurve *fcu, float x, float y, short fast)
322 {
323         BezTriple beztr;
324         int a;
325         
326         /* set all three points, for nicer start position */
327         memset(&beztr, 0, sizeof(BezTriple));
328         beztr.vec[0][0]= x; 
329         beztr.vec[0][1]= y;
330         beztr.vec[1][0]= x;
331         beztr.vec[1][1]= y;
332         beztr.vec[2][0]= x;
333         beztr.vec[2][1]= y;
334         beztr.ipo= U.ipo_new; /* use default interpolation mode here... */
335         beztr.f1= beztr.f2= beztr.f3= SELECT;
336         beztr.h1= beztr.h2= HD_AUTO; // XXX what about when we replace an old one?
337         
338         /* add temp beztriple to keyframes */
339         a= insert_bezt_fcurve(fcu, &beztr);
340         
341         /* what if 'a' is a negative index? 
342          * for now, just exit to prevent any segfaults
343          */
344         if (a < 0) return;
345         
346         /* don't recalculate handles if fast is set
347          *      - this is a hack to make importers faster
348          *      - we may calculate twice (see editipo_changed(), due to autohandle needing two calculations)
349          */
350         if (!fast) calchandles_fcurve(fcu);
351         
352         /* set handletype and interpolation */
353         if (fcu->totvert > 2) {
354                 BezTriple *bezt= (fcu->bezt + a);
355                 char h1, h2;
356                 
357                 /* set handles (autohandles by default) */
358                 h1= h2= HD_AUTO;
359                 
360                 if (a > 0) h1= (bezt-1)->h2;
361                 if (a < fcu->totvert-1) h2= (bezt+1)->h1;
362                 
363                 bezt->h1= h1;
364                 bezt->h2= h2;
365                 
366                 /* set interpolation from previous (if available) */
367                 if (a > 0) bezt->ipo= (bezt-1)->ipo;
368                 else if (a < fcu->totvert-1) bezt->ipo= (bezt+1)->ipo;
369                         
370                 /* don't recalculate handles if fast is set
371                  *      - this is a hack to make importers faster
372                  *      - we may calculate twice (see editipo_changed(), due to autohandle needing two calculations)
373                  */
374                 if (!fast) calchandles_fcurve(fcu);
375         }
376 }
377
378 /* -------------- 'Smarter' Keyframing Functions -------------------- */
379 /* return codes for new_key_needed */
380 enum {
381         KEYNEEDED_DONTADD = 0,
382         KEYNEEDED_JUSTADD,
383         KEYNEEDED_DELPREV,
384         KEYNEEDED_DELNEXT
385 } eKeyNeededStatus;
386
387 /* This helper function determines whether a new keyframe is needed */
388 /* Cases where keyframes should not be added:
389  *      1. Keyframe to be added bewteen two keyframes with similar values
390  *      2. Keyframe to be added on frame where two keyframes are already situated
391  *      3. Keyframe lies at point that intersects the linear line between two keyframes
392  */
393 static short new_key_needed (FCurve *fcu, float cFrame, float nValue) 
394 {
395         BezTriple *bezt=NULL, *prev=NULL;
396         int totCount, i;
397         float valA = 0.0f, valB = 0.0f;
398         
399         /* safety checking */
400         if (fcu == NULL) return KEYNEEDED_JUSTADD;
401         totCount= fcu->totvert;
402         if (totCount == 0) return KEYNEEDED_JUSTADD;
403         
404         /* loop through checking if any are the same */
405         bezt= fcu->bezt;
406         for (i=0; i<totCount; i++) {
407                 float prevPosi=0.0f, prevVal=0.0f;
408                 float beztPosi=0.0f, beztVal=0.0f;
409                         
410                 /* get current time+value */    
411                 beztPosi= bezt->vec[1][0];
412                 beztVal= bezt->vec[1][1];
413                         
414                 if (prev) {
415                         /* there is a keyframe before the one currently being examined */               
416                         
417                         /* get previous time+value */
418                         prevPosi= prev->vec[1][0];
419                         prevVal= prev->vec[1][1];
420                         
421                         /* keyframe to be added at point where there are already two similar points? */
422                         if (IS_EQ(prevPosi, cFrame) && IS_EQ(beztPosi, cFrame) && IS_EQ(beztPosi, prevPosi)) {
423                                 return KEYNEEDED_DONTADD;
424                         }
425                         
426                         /* keyframe between prev+current points ? */
427                         if ((prevPosi <= cFrame) && (cFrame <= beztPosi)) {
428                                 /* is the value of keyframe to be added the same as keyframes on either side ? */
429                                 if (IS_EQ(prevVal, nValue) && IS_EQ(beztVal, nValue) && IS_EQ(prevVal, beztVal)) {
430                                         return KEYNEEDED_DONTADD;
431                                 }
432                                 else {
433                                         float realVal;
434                                         
435                                         /* get real value of curve at that point */
436                                         realVal= evaluate_fcurve(fcu, cFrame);
437                                         
438                                         /* compare whether it's the same as proposed */
439                                         if (IS_EQ(realVal, nValue)) 
440                                                 return KEYNEEDED_DONTADD;
441                                         else 
442                                                 return KEYNEEDED_JUSTADD;
443                                 }
444                         }
445                         
446                         /* new keyframe before prev beztriple? */
447                         if (cFrame < prevPosi) {
448                                 /* A new keyframe will be added. However, whether the previous beztriple
449                                  * stays around or not depends on whether the values of previous/current
450                                  * beztriples and new keyframe are the same.
451                                  */
452                                 if (IS_EQ(prevVal, nValue) && IS_EQ(beztVal, nValue) && IS_EQ(prevVal, beztVal))
453                                         return KEYNEEDED_DELNEXT;
454                                 else 
455                                         return KEYNEEDED_JUSTADD;
456                         }
457                 }
458                 else {
459                         /* just add a keyframe if there's only one keyframe 
460                          * and the new one occurs before the exisiting one does.
461                          */
462                         if ((cFrame < beztPosi) && (totCount==1))
463                                 return KEYNEEDED_JUSTADD;
464                 }
465                 
466                 /* continue. frame to do not yet passed (or other conditions not met) */
467                 if (i < (totCount-1)) {
468                         prev= bezt;
469                         bezt++;
470                 }
471                 else
472                         break;
473         }
474         
475         /* Frame in which to add a new-keyframe occurs after all other keys
476          * -> If there are at least two existing keyframes, then if the values of the
477          *       last two keyframes and the new-keyframe match, the last existing keyframe
478          *       gets deleted as it is no longer required.
479          * -> Otherwise, a keyframe is just added. 1.0 is added so that fake-2nd-to-last
480          *       keyframe is not equal to last keyframe.
481          */
482         bezt= (fcu->bezt + (fcu->totvert - 1));
483         valA= bezt->vec[1][1];
484         
485         if (prev)
486                 valB= prev->vec[1][1];
487         else 
488                 valB= bezt->vec[1][1] + 1.0f; 
489                 
490         if (IS_EQ(valA, nValue) && IS_EQ(valA, valB)) 
491                 return KEYNEEDED_DELPREV;
492         else 
493                 return KEYNEEDED_JUSTADD;
494 }
495
496 /* ------------------ RNA Data-Access Functions ------------------ */
497
498 /* Try to read value using RNA-properties obtained already */
499 static float setting_get_rna_value (PointerRNA *ptr, PropertyRNA *prop, int index)
500 {
501         float value= 0.0f;
502         
503         switch (RNA_property_type(prop)) {
504                 case PROP_BOOLEAN:
505                         if (RNA_property_array_length(prop))
506                                 value= (float)RNA_property_boolean_get_index(ptr, prop, index);
507                         else
508                                 value= (float)RNA_property_boolean_get(ptr, prop);
509                         break;
510                 case PROP_INT:
511                         if (RNA_property_array_length(prop))
512                                 value= (float)RNA_property_int_get_index(ptr, prop, index);
513                         else
514                                 value= (float)RNA_property_int_get(ptr, prop);
515                         break;
516                 case PROP_FLOAT:
517                         if (RNA_property_array_length(prop))
518                                 value= RNA_property_float_get_index(ptr, prop, index);
519                         else
520                                 value= RNA_property_float_get(ptr, prop);
521                         break;
522                 case PROP_ENUM:
523                         value= (float)RNA_property_enum_get(ptr, prop);
524                         break;
525                 default:
526                         break;
527         }
528         
529         return value;
530 }
531
532 /* ------------------ 'Visual' Keyframing Functions ------------------ */
533
534 /* internal status codes for visualkey_can_use */
535 enum {
536         VISUALKEY_NONE = 0,
537         VISUALKEY_LOC,
538         VISUALKEY_ROT,
539 };
540
541 /* This helper function determines if visual-keyframing should be used when  
542  * inserting keyframes for the given channel. As visual-keyframing only works
543  * on Object and Pose-Channel blocks, this should only get called for those 
544  * blocktypes, when using "standard" keying but 'Visual Keying' option in Auto-Keying 
545  * settings is on.
546  */
547 static short visualkey_can_use (PointerRNA *ptr, PropertyRNA *prop)
548 {
549         bConstraint *con= NULL;
550         short searchtype= VISUALKEY_NONE;
551         char *identifier= NULL;
552         
553         /* validate data */
554         // TODO: this check is probably not needed, but it won't hurt
555         if (ELEM3(NULL, ptr, ptr->data, prop))
556                 return 0;
557                 
558         /* get first constraint and determine type of keyframe constraints to check for 
559          *      - constraints can be on either Objects or PoseChannels, so we only check if the
560          *        ptr->type is RNA_Object or RNA_PoseChannel, which are the RNA wrapping-info for
561          *        those structs, allowing us to identify the owner of the data 
562          */
563         if (ptr->type == &RNA_Object) {
564                 /* Object */
565                 Object *ob= (Object *)ptr->data;
566                 
567                 con= ob->constraints.first;
568                 identifier= (char *)RNA_property_identifier(prop);
569         }
570         else if (ptr->type == &RNA_PoseChannel) {
571                 /* Pose Channel */
572                 bPoseChannel *pchan= (bPoseChannel *)ptr->data;
573                 
574                 con= pchan->constraints.first;
575                 identifier= (char *)RNA_property_identifier(prop);
576         }
577         
578         /* check if any data to search using */
579         if (ELEM(NULL, con, identifier))
580                 return 0;
581                 
582         /* location or rotation identifiers only... */
583         if (strstr(identifier, "location"))
584                 searchtype= VISUALKEY_LOC;
585         else if (strstr(identifier, "rotation"))
586                 searchtype= VISUALKEY_ROT;
587         else {
588                 printf("visualkey_can_use() failed: identifier - '%s' \n", identifier);
589                 return 0;
590         }
591         
592         
593         /* only search if a searchtype and initial constraint are available */
594         if (searchtype && con) {
595                 for (; con; con= con->next) {
596                         /* only consider constraint if it is not disabled, and has influence */
597                         if (con->flag & CONSTRAINT_DISABLE) continue;
598                         if (con->enforce == 0.0f) continue;
599                         
600                         /* some constraints may alter these transforms */
601                         switch (con->type) {
602                                 /* multi-transform constraints */
603                                 case CONSTRAINT_TYPE_CHILDOF:
604                                         return 1;
605                                 case CONSTRAINT_TYPE_TRANSFORM:
606                                         return 1;
607                                 case CONSTRAINT_TYPE_FOLLOWPATH:
608                                         return 1;
609                                 case CONSTRAINT_TYPE_KINEMATIC:
610                                         return 1;
611                                         
612                                 /* single-transform constraits  */
613                                 case CONSTRAINT_TYPE_TRACKTO:
614                                         if (searchtype==VISUALKEY_ROT) return 1;
615                                         break;
616                                 case CONSTRAINT_TYPE_ROTLIMIT:
617                                         if (searchtype==VISUALKEY_ROT) return 1;
618                                         break;
619                                 case CONSTRAINT_TYPE_LOCLIMIT:
620                                         if (searchtype==VISUALKEY_LOC) return 1;
621                                         break;
622                                 case CONSTRAINT_TYPE_ROTLIKE:
623                                         if (searchtype==VISUALKEY_ROT) return 1;
624                                         break;
625                                 case CONSTRAINT_TYPE_DISTLIMIT:
626                                         if (searchtype==VISUALKEY_LOC) return 1;
627                                         break;
628                                 case CONSTRAINT_TYPE_LOCLIKE:
629                                         if (searchtype==VISUALKEY_LOC) return 1;
630                                         break;
631                                 case CONSTRAINT_TYPE_LOCKTRACK:
632                                         if (searchtype==VISUALKEY_ROT) return 1;
633                                         break;
634                                 case CONSTRAINT_TYPE_MINMAX:
635                                         if (searchtype==VISUALKEY_LOC) return 1;
636                                         break;
637                                 
638                                 default:
639                                         break;
640                         }
641                 }
642         }
643         
644         /* when some condition is met, this function returns, so here it can be 0 */
645         return 0;
646 }
647
648 /* This helper function extracts the value to use for visual-keyframing 
649  * In the event that it is not possible to perform visual keying, try to fall-back
650  * to using the default method. Assumes that all data it has been passed is valid.
651  */
652 static float visualkey_get_value (PointerRNA *ptr, PropertyRNA *prop, int array_index)
653 {
654         char *identifier= (char *)RNA_property_identifier(prop);
655         
656         /* handle for Objects or PoseChannels only 
657          *      - constraints can be on either Objects or PoseChannels, so we only check if the
658          *        ptr->type is RNA_Object or RNA_PoseChannel, which are the RNA wrapping-info for
659          *        those structs, allowing us to identify the owner of the data 
660          *      - assume that array_index will be sane
661          */
662         if (ptr->type == &RNA_Object) {
663                 Object *ob= (Object *)ptr->data;
664                 
665                 /* parented objects are not supported, as the effects of the parent
666                  * are included in the matrix, which kindof beats the point
667                  */
668                 if (ob->parent == NULL) {
669                         /* only Location or Rotation keyframes are supported now */
670                         if (strstr(identifier, "location")) {
671                                 return ob->obmat[3][array_index];
672                         }
673                         else if (strstr(identifier, "rotation")) {
674                                 float eul[3];
675                                 
676                                 Mat4ToEul(ob->obmat, eul);
677                                 return eul[array_index];
678                         }
679                 }
680         }
681         else if (ptr->type == &RNA_PoseChannel) {
682                 Object *ob= (Object *)ptr->id.data; /* we assume that this is always set, and is an object */
683                 bPoseChannel *pchan= (bPoseChannel *)ptr->data;
684                 float tmat[4][4];
685                 
686                 /* Although it is not strictly required for this particular space conversion, 
687                  * arg1 must not be null, as there is a null check for the other conversions to
688                  * be safe. Therefore, the active object is passed here, and in many cases, this
689                  * will be what owns the pose-channel that is getting this anyway.
690                  */
691                 Mat4CpyMat4(tmat, pchan->pose_mat);
692                 constraint_mat_convertspace(ob, pchan, tmat, CONSTRAINT_SPACE_POSE, CONSTRAINT_SPACE_LOCAL);
693                 
694                 /* Loc, Rot/Quat keyframes are supported... */
695                 if (strstr(identifier, "location")) {
696                         /* only use for non-connected bones */
697                         if ((pchan->bone->parent) && !(pchan->bone->flag & BONE_CONNECTED))
698                                 return tmat[3][array_index];
699                         else if (pchan->bone->parent == NULL)
700                                 return tmat[3][array_index];
701                 }
702                 else if (strstr(identifier, "euler_rotation")) {
703                         float eul[3];
704                         
705                         /* euler-rotation test before standard rotation, as standard rotation does quats */
706                         Mat4ToEul(tmat, eul);
707                         return eul[array_index];
708                 }
709                 else if (strstr(identifier, "rotation")) {
710                         float trimat[3][3], quat[4];
711                         
712                         Mat3CpyMat4(trimat, tmat);
713                         Mat3ToQuat_is_ok(trimat, quat);
714                         
715                         return quat[array_index];
716                 }
717         }
718         
719         /* as the function hasn't returned yet, read value from system in the default way */
720         return setting_get_rna_value(ptr, prop, array_index);
721 }
722
723 /* ------------------------- Insert Key API ------------------------- */
724
725 /* Main Keyframing API call:
726  *      Use this when validation of necessary animation data isn't necessary as it
727  *      already exists. It will insert a keyframe using the current value being keyframed.
728  *      
729  *      The flag argument is used for special settings that alter the behaviour of
730  *      the keyframe insertion. These include the 'visual' keyframing modes, quick refresh,
731  *      and extra keyframe filtering.
732  */
733 short insert_keyframe (ID *id, bAction *act, const char group[], const char rna_path[], int array_index, float cfra, short flag)
734 {       
735         PointerRNA id_ptr, ptr;
736         PropertyRNA *prop;
737         FCurve *fcu;
738         
739         /* validate pointer first - exit if failure */
740         RNA_id_pointer_create(id, &id_ptr);
741         if ((RNA_path_resolve(&id_ptr, rna_path, &ptr, &prop) == 0) || (prop == NULL)) {
742                 printf("Insert Key: Could not insert keyframe, as RNA Path is invalid for the given ID (ID = %s, Path = %s)\n", id->name, rna_path);
743                 return 0;
744         }
745         
746         /* get F-Curve - if no action is provided, keyframe to the default one attached to this ID-block */
747         if (act == NULL)
748                 act= verify_adt_action(id, 1);
749         fcu= verify_fcurve(act, group, rna_path, array_index, 1);
750         
751         /* only continue if we have an F-Curve to add keyframe to */
752         if (fcu) {
753                 float curval= 0.0f;
754                 
755                 /* set additional flags for the F-Curve (i.e. only integer values) */
756                 fcu->flag &= ~(FCURVE_INT_VALUES|FCURVE_DISCRETE_VALUES);
757                 switch (RNA_property_type(prop)) {
758                         case PROP_FLOAT:
759                                 /* do nothing */
760                                 break;
761                         case PROP_INT:
762                                 /* do integer (only 'whole' numbers) interpolation between all points */
763                                 fcu->flag |= FCURVE_INT_VALUES;
764                                 break;
765                         default:
766                                 /* do 'discrete' (i.e. enum, boolean values which cannot take any intermediate
767                                  * values at all) interpolation between all points
768                                  *      - however, we must also ensure that evaluated values are only integers still
769                                  */
770                                 fcu->flag |= (FCURVE_DISCRETE_VALUES|FCURVE_INT_VALUES);
771                                 break;
772                 }
773                 
774                 /* apply special time tweaking */
775                         // XXX check on this stuff...
776                 if (GS(id->name) == ID_OB) {
777                         //Object *ob= (Object *)id;
778                         
779                         /* apply NLA-scaling (if applicable) */
780                         //cfra= get_action_frame(ob, cfra);
781                         
782                         /* ancient time-offset cruft */
783                         //if ( (ob->ipoflag & OB_OFFS_OB) && (give_timeoffset(ob)) ) {
784                         //      /* actually frametofloat calc again! */
785                         //      cfra-= give_timeoffset(ob)*scene->r.framelen;
786                         //}
787                 }
788                 
789                 /* obtain value to give keyframe */
790                 if ( (flag & INSERTKEY_MATRIX) && 
791                          (visualkey_can_use(&ptr, prop)) ) 
792                 {
793                         /* visual-keying is only available for object and pchan datablocks, as 
794                          * it works by keyframing using a value extracted from the final matrix 
795                          * instead of using the kt system to extract a value.
796                          */
797                         curval= visualkey_get_value(&ptr, prop, array_index);
798                 }
799                 else {
800                         /* read value from system */
801                         curval= setting_get_rna_value(&ptr, prop, array_index);
802                 }
803                 
804                 /* only insert keyframes where they are needed */
805                 if (flag & INSERTKEY_NEEDED) {
806                         short insert_mode;
807                         
808                         /* check whether this curve really needs a new keyframe */
809                         insert_mode= new_key_needed(fcu, cfra, curval);
810                         
811                         /* insert new keyframe at current frame */
812                         if (insert_mode)
813                                 insert_vert_fcurve(fcu, cfra, curval, (flag & INSERTKEY_FAST));
814                         
815                         /* delete keyframe immediately before/after newly added */
816                         switch (insert_mode) {
817                                 case KEYNEEDED_DELPREV:
818                                         delete_fcurve_key(fcu, fcu->totvert-2, 1);
819                                         break;
820                                 case KEYNEEDED_DELNEXT:
821                                         delete_fcurve_key(fcu, 1, 1);
822                                         break;
823                         }
824                         
825                         /* only return success if keyframe added */
826                         if (insert_mode)
827                                 return 1;
828                 }
829                 else {
830                         /* just insert keyframe */
831                         insert_vert_fcurve(fcu, cfra, curval, (flag & INSERTKEY_FAST));
832                         
833                         /* return success */
834                         return 1;
835                 }
836         }
837         
838         /* no F-Curve to add keyframes to */
839         printf("ERROR: no F-Curve to add keyframes to \n");
840         
841         /* return failure */
842         return 0;
843 }
844
845 /* ************************************************** */
846 /* KEYFRAME DELETION */
847
848 /* Main Keyframing API call:
849  *      Use this when validation of necessary animation data isn't necessary as it
850  *      already exists. It will delete a keyframe at the current frame.
851  *      
852  *      The flag argument is used for special settings that alter the behaviour of
853  *      the keyframe deletion. These include the quick refresh options.
854  */
855 short delete_keyframe (ID *id, bAction *act, const char group[], const char rna_path[], int array_index, float cfra, short flag)
856 {
857         FCurve *fcu = NULL;
858         
859         /* get F-Curve
860          * Note: here is one of the places where we don't want new Action + F-Curve added!
861          *              so 'add' var must be 0
862          */
863         if (act == NULL) {
864                 /* if no action is provided, use the default one attached to this ID-block */
865                 AnimData *adt= BKE_animdata_from_id(id);
866                 act= adt->action;
867         }
868         /* we don't check the validity of the path here yet, but it should be ok... */
869         fcu= verify_fcurve(act, group, rna_path, array_index, 0);
870         
871         /* only continue if we have an F-Curve to remove keyframes from */
872         if (act && fcu) {
873                 short found = -1;
874                 int i;
875                 
876                 /* apply special time tweaking */
877                 if (GS(id->name) == ID_OB) {
878                         //Object *ob= (Object *)id;
879                         
880                         /* apply NLA-scaling (if applicable) */
881                         //      cfra= get_action_frame(ob, cfra);
882                         
883                         /* ancient time-offset cruft */
884                         //if ( (ob->ipoflag & OB_OFFS_OB) && (give_timeoffset(ob)) ) {
885                         //      /* actually frametofloat calc again! */
886                         //      cfra-= give_timeoffset(ob)*scene->r.framelen;
887                         //}
888                 }
889                 
890                 /* try to find index of beztriple to get rid of */
891                 i = binarysearch_bezt_index(fcu->bezt, cfra, fcu->totvert, &found);
892                 if (found) {                    
893                         /* delete the key at the index (will sanity check + do recalc afterwards) */
894                         delete_fcurve_key(fcu, i, 1);
895                         
896                         /* Only delete curve too if there are no points (we don't need to check for drivers, as they're kept separate) */
897                         if (fcu->totvert == 0) {
898                                 BLI_remlink(&act->curves, fcu);
899                                 free_fcurve(fcu);
900                         }
901                         
902                         /* return success */
903                         return 1;
904                 }
905         }
906         
907         /* return failure */
908         return 0;
909 }
910
911 /* ******************************************* */
912 /* KEYFRAME MODIFICATION */
913
914 /* mode for commonkey_modifykey */
915 enum {
916         COMMONKEY_MODE_INSERT = 0,
917         COMMONKEY_MODE_DELETE,
918 } eCommonModifyKey_Modes;
919
920 /* Polling callback for use with ANIM_*_keyframe() operators
921  * This is based on the standard ED_operator_areaactive callback,
922  * except that it does special checks for a few spacetypes too...
923  */
924 static int modify_key_op_poll(bContext *C)
925 {
926         ScrArea *sa= CTX_wm_area(C);
927         Scene *scene= CTX_data_scene(C);
928         
929         /* if no area or active scene */
930         if (ELEM(NULL, sa, scene)) 
931                 return 0;
932         
933         /* if Outliner, only allow in DataBlocks view */
934         if (sa->spacetype == SPACE_OUTLINER) {
935                 SpaceOops *so= (SpaceOops *)CTX_wm_space_data(C);
936                 
937                 if ((so->outlinevis != SO_DATABLOCKS))
938                         return 0;
939         }
940         
941         /* TODO: checks for other space types can be added here */
942         
943         /* should be fine */
944         return 1;
945 }
946
947 /* Insert Key Operator ------------------------ */
948
949 static int insert_key_exec (bContext *C, wmOperator *op)
950 {
951         ListBase dsources = {NULL, NULL};
952         Scene *scene= CTX_data_scene(C);
953         KeyingSet *ks= NULL;
954         int type= RNA_int_get(op->ptr, "type");
955         float cfra= (float)CFRA; // XXX for now, don't bother about all the yucky offset crap
956         short success;
957         
958         /* type is the Keying Set the user specified to use when calling the operator:
959          *      - type == 0: use scene's active Keying Set
960          *      - type > 0: use a user-defined Keying Set from the active scene
961          *      - type < 0: use a builtin Keying Set
962          */
963         if (type == 0) 
964                 type= scene->active_keyingset;
965         if (type > 0)
966                 ks= BLI_findlink(&scene->keyingsets, scene->active_keyingset-1);
967         else
968                 ks= BLI_findlink(&builtin_keyingsets, -type-1);
969                 
970         /* report failures */
971         if (ks == NULL) {
972                 BKE_report(op->reports, RPT_ERROR, "No active Keying Set");
973                 return OPERATOR_CANCELLED;
974         }
975         
976         /* get context info for relative Keying Sets */
977         if ((ks->flag & KEYINGSET_ABSOLUTE) == 0) {
978                 /* exit if no suitable data obtained */
979                 if (modifykey_get_context_data(C, &dsources, ks) == 0) {
980                         BKE_report(op->reports, RPT_ERROR, "No suitable context info for active Keying Set");
981                         return OPERATOR_CANCELLED;
982                 }
983         }
984         
985         /* try to insert keyframes for the channels specified by KeyingSet */
986         success= modify_keyframes(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra);
987         printf("KeyingSet '%s' - Successfully added %d Keyframes \n", ks->name, success);
988         
989         /* report failure? */
990         if (success == 0)
991                 BKE_report(op->reports, RPT_WARNING, "Keying Set failed to insert any keyframes");
992         
993         /* free temp context-data if available */
994         if (dsources.first) {
995                 /* we assume that there is no extra data that needs to be freed from here... */
996                 BLI_freelistN(&dsources);
997         }
998         
999         /* send updates */
1000         ED_anim_dag_flush_update(C);    
1001         
1002         /* for now, only send ND_KEYS for KeyingSets */
1003         WM_event_add_notifier(C, ND_KEYS, NULL);
1004         
1005         return OPERATOR_FINISHED;
1006 }
1007
1008 void ANIM_OT_insert_keyframe (wmOperatorType *ot)
1009 {
1010         /* identifiers */
1011         ot->name= "Insert Keyframe";
1012         ot->idname= "ANIM_OT_insert_keyframe";
1013         
1014         /* callbacks */
1015         ot->exec= insert_key_exec; 
1016         ot->poll= modify_key_op_poll;
1017         
1018         /* flags */
1019         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1020         
1021         /* settings */
1022         RNA_def_int(ot->srna, "type", 0, INT_MIN, INT_MAX, "Keying Set Number", "Index (determined internally) of the Keying Set to use", 0, 1);
1023 }
1024
1025 /* Insert Key Operator (With Menu) ------------------------ */
1026
1027 /* XXX 
1028  * This operator pops up a menu which sets gets the index of the keyingset to use,
1029  * setting the global settings, and calling the insert-keyframe operator using these
1030  * settings
1031  */
1032
1033 static int insert_key_menu_invoke (bContext *C, wmOperator *op, wmEvent *event)
1034 {
1035         Scene *scene= CTX_data_scene(C);
1036         KeyingSet *ks;
1037         uiPopupMenu *pup;
1038         uiLayout *layout;
1039         int i = 0;
1040         
1041         pup= uiPupMenuBegin(C, "Insert Keyframe", 0);
1042         layout= uiPupMenuLayout(pup);
1043         
1044         /* active Keying Set */
1045         uiItemIntO(layout, "Active Keying Set", 0, "ANIM_OT_insert_keyframe_menu", "type", i++);
1046         uiItemS(layout);
1047         
1048         /* user-defined Keying Sets 
1049          *      - these are listed in the order in which they were defined for the active scene
1050          */
1051         if (scene->keyingsets.first) {
1052                 for (ks= scene->keyingsets.first; ks; ks= ks->next)
1053                         uiItemIntO(layout, ks->name, 0, "ANIM_OT_insert_keyframe_menu", "type", i++);
1054                 uiItemS(layout);
1055         }
1056         
1057         /* builtin Keying Sets */
1058         // XXX polling the entire list may lag
1059         i= -1;
1060         for (ks= builtin_keyingsets.first; ks; ks= ks->next) {
1061                 /* only show KeyingSet if context is suitable */
1062                 if (keyingset_context_ok_poll(C, ks)) {
1063                         uiItemIntO(layout, ks->name, 0, "ANIM_OT_insert_keyframe_menu", "type", i--);
1064                 }
1065         }
1066         
1067         uiPupMenuEnd(C, pup);
1068         
1069         return OPERATOR_CANCELLED;
1070 }
1071  
1072 void ANIM_OT_insert_keyframe_menu (wmOperatorType *ot)
1073 {
1074         /* identifiers */
1075         ot->name= "Insert Keyframe";
1076         ot->idname= "ANIM_OT_insert_keyframe_menu";
1077         
1078         /* callbacks */
1079         ot->invoke= insert_key_menu_invoke;
1080         ot->exec= insert_key_exec; 
1081         ot->poll= ED_operator_areaactive;
1082         
1083         /* flags */
1084         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1085         
1086         /* properties
1087          *      - NOTE: here the type is int not enum, since many of the indicies here are determined dynamically
1088          */
1089         RNA_def_int(ot->srna, "type", 0, INT_MIN, INT_MAX, "Keying Set Number", "Index (determined internally) of the Keying Set to use", 0, 1);
1090 }
1091
1092 /* Delete Key Operator ------------------------ */
1093
1094 static int delete_key_exec (bContext *C, wmOperator *op)
1095 {
1096         ListBase dsources = {NULL, NULL};
1097         Scene *scene= CTX_data_scene(C);
1098         KeyingSet *ks= NULL;    
1099         int type= RNA_int_get(op->ptr, "type");
1100         float cfra= (float)CFRA; // XXX for now, don't bother about all the yucky offset crap
1101         short success;
1102         
1103         /* type is the Keying Set the user specified to use when calling the operator:
1104          *      - type == 0: use scene's active Keying Set
1105          *      - type > 0: use a user-defined Keying Set from the active scene
1106          *      - type < 0: use a builtin Keying Set
1107          */
1108         if (type == 0) 
1109                 type= scene->active_keyingset;
1110         if (type > 0)
1111                 ks= BLI_findlink(&scene->keyingsets, scene->active_keyingset-1);
1112         else
1113                 ks= BLI_findlink(&builtin_keyingsets, -type-1);
1114         
1115         /* report failure */
1116         if (ks == NULL) {
1117                 BKE_report(op->reports, RPT_ERROR, "No active Keying Set");
1118                 return OPERATOR_CANCELLED;
1119         }
1120         
1121         /* get context info for relative Keying Sets */
1122         if ((ks->flag & KEYINGSET_ABSOLUTE) == 0) {
1123                 /* exit if no suitable data obtained */
1124                 if (modifykey_get_context_data(C, &dsources, ks) == 0) {
1125                         BKE_report(op->reports, RPT_ERROR, "No suitable context info for active Keying Set");
1126                         return OPERATOR_CANCELLED;
1127                 }
1128         }
1129         
1130         /* try to insert keyframes for the channels specified by KeyingSet */
1131         success= modify_keyframes(C, &dsources, NULL, ks, MODIFYKEY_MODE_DELETE, cfra);
1132         printf("KeyingSet '%s' - Successfully removed %d Keyframes \n", ks->name, success);
1133         
1134         /* report failure? */
1135         if (success == 0)
1136                 BKE_report(op->reports, RPT_WARNING, "Keying Set failed to remove any keyframes");
1137         
1138         /* free temp context-data if available */
1139         if (dsources.first) {
1140                 /* we assume that there is no extra data that needs to be freed from here... */
1141                 BLI_freelistN(&dsources);
1142         }
1143         
1144         /* send updates */
1145         ED_anim_dag_flush_update(C);    
1146         
1147         /* for now, only send ND_KEYS for KeyingSets */
1148         WM_event_add_notifier(C, ND_KEYS, NULL);
1149         
1150         return OPERATOR_FINISHED;
1151 }
1152
1153 void ANIM_OT_delete_keyframe (wmOperatorType *ot)
1154 {
1155         /* identifiers */
1156         ot->name= "Delete Keyframe";
1157         ot->idname= "ANIM_OT_delete_keyframe";
1158         
1159         /* callbacks */
1160         ot->exec= delete_key_exec; 
1161         ot->poll= modify_key_op_poll;
1162         
1163         /* flags */
1164         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1165         
1166         /* properties
1167          *      - NOTE: here the type is int not enum, since many of the indicies here are determined dynamically
1168          */
1169         RNA_def_int(ot->srna, "type", 0, INT_MIN, INT_MAX, "Keying Set Number", "Index (determined internally) of the Keying Set to use", 0, 1);
1170 }
1171
1172 /* Delete Key Operator ------------------------ */
1173
1174 /* XXX WARNING:
1175  * This is currently just a basic operator, which work in 3d-view context on objects only. 
1176  * Should this be kept? It does have advantages over a version which requires selecting a keyingset to use...
1177  * -- Joshua Leung, Jan 2009
1178  */
1179  
1180 static int delete_key_old_exec (bContext *C, wmOperator *op)
1181 {
1182         Scene *scene= CTX_data_scene(C);
1183         float cfra= (float)CFRA; // XXX for now, don't bother about all the yucky offset crap
1184         
1185         // XXX more comprehensive tests will be needed
1186         CTX_DATA_BEGIN(C, Base*, base, selected_bases) 
1187         {
1188                 Object *ob= base->object;
1189                 ID *id= (ID *)ob;
1190                 FCurve *fcu, *fcn;
1191                 short success= 0;
1192                 
1193                 /* loop through all curves in animdata and delete keys on this frame */
1194                 if (ob->adt) {
1195                         AnimData *adt= ob->adt;
1196                         bAction *act= adt->action;
1197                         
1198                         for (fcu= act->curves.first; fcu; fcu= fcn) {
1199                                 fcn= fcu->next;
1200                                 success+= delete_keyframe(id, NULL, NULL, fcu->rna_path, fcu->array_index, cfra, 0);
1201                         }
1202                 }
1203                 
1204                 printf("Ob '%s' - Successfully removed %d keyframes \n", id->name+2, success);
1205                 
1206                 ob->recalc |= OB_RECALC_OB;
1207         }
1208         CTX_DATA_END;
1209         
1210         /* send updates */
1211         ED_anim_dag_flush_update(C);    
1212         
1213         WM_event_add_notifier(C, NC_OBJECT|ND_KEYS, NULL);
1214         
1215         return OPERATOR_FINISHED;
1216 }
1217
1218 void ANIM_OT_delete_keyframe_old (wmOperatorType *ot)
1219 {
1220         /* identifiers */
1221         ot->name= "Delete Keyframe";
1222         ot->idname= "ANIM_OT_delete_keyframe_old";
1223         
1224         /* callbacks */
1225         ot->invoke= WM_operator_confirm;
1226         ot->exec= delete_key_old_exec; 
1227         
1228         ot->poll= ED_operator_areaactive;
1229         
1230         /* flags */
1231         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1232 }
1233
1234
1235 /* Insert Key Button Operator ------------------------ */
1236
1237 static int insert_key_button_exec (bContext *C, wmOperator *op)
1238 {
1239         Scene *scene= CTX_data_scene(C);
1240         PointerRNA ptr;
1241         PropertyRNA *prop= NULL;
1242         char *path;
1243         float cfra= (float)CFRA; // XXX for now, don't bother about all the yucky offset crap
1244         short success= 0;
1245         int a, index, length, all= RNA_boolean_get(op->ptr, "all");
1246         
1247         /* try to insert keyframe using property retrieved from UI */
1248         memset(&ptr, 0, sizeof(PointerRNA));
1249         uiAnimContextProperty(C, &ptr, &prop, &index);
1250         
1251         if ((ptr.data && prop) && RNA_property_animateable(&ptr, prop)) {
1252                 path= RNA_path_from_ID_to_property(&ptr, prop);
1253                 
1254                 if (path) {
1255                         if (all) {
1256                                 length= RNA_property_array_length(prop);
1257                                 
1258                                 if(length) index= 0;
1259                                 else length= 1;
1260                         }
1261                         else
1262                                 length= 1;
1263                         
1264                         for (a=0; a<length; a++)
1265                                 success+= insert_keyframe(ptr.id.data, NULL, NULL, path, index+a, cfra, 0);
1266                         
1267                         MEM_freeN(path);
1268                 }
1269                 else {
1270                         if (G.f & G_DEBUG)
1271                                 printf("Button Insert-Key: no path to property \n");
1272                         BKE_report(op->reports, RPT_WARNING, "Failed to resolve path to property. Try using a Keying Set instead.");
1273                 }
1274         }
1275         else if (G.f & G_DEBUG) {
1276                 printf("ptr.data = %p, prop = %p,", ptr.data, prop);
1277                 if(prop)
1278                         printf("animateable = %d \n", RNA_property_animateable(&ptr, prop));
1279                 else
1280                         printf("animateable = NULL \n");
1281         }
1282         
1283         if (success) {
1284                 /* send updates */
1285                 ED_anim_dag_flush_update(C);    
1286                 
1287                 /* for now, only send ND_KEYS for KeyingSets */
1288                 WM_event_add_notifier(C, ND_KEYS, NULL);
1289         }
1290         
1291         return (success)? OPERATOR_FINISHED: OPERATOR_CANCELLED;
1292 }
1293
1294 void ANIM_OT_insert_keyframe_button (wmOperatorType *ot)
1295 {
1296         /* identifiers */
1297         ot->name= "Insert Keyframe";
1298         ot->idname= "ANIM_OT_insert_keyframe_button";
1299         
1300         /* callbacks */
1301         ot->exec= insert_key_button_exec; 
1302         ot->poll= modify_key_op_poll;
1303         
1304         /* flags */
1305         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1306
1307         /* properties */
1308         RNA_def_boolean(ot->srna, "all", 1, "All", "Insert a keyframe for all element of the array.");
1309 }
1310
1311 /* Delete Key Button Operator ------------------------ */
1312
1313 static int delete_key_button_exec (bContext *C, wmOperator *op)
1314 {
1315         Scene *scene= CTX_data_scene(C);
1316         PointerRNA ptr;
1317         PropertyRNA *prop= NULL;
1318         char *path;
1319         float cfra= (float)CFRA; // XXX for now, don't bother about all the yucky offset crap
1320         short success= 0;
1321         int a, index, length, all= RNA_boolean_get(op->ptr, "all");
1322         
1323         /* try to insert keyframe using property retrieved from UI */
1324         memset(&ptr, 0, sizeof(PointerRNA));
1325         uiAnimContextProperty(C, &ptr, &prop, &index);
1326
1327         if (ptr.data && prop) {
1328                 path= RNA_path_from_ID_to_property(&ptr, prop);
1329                 
1330                 if (path) {
1331                         if (all) {
1332                                 length= RNA_property_array_length(prop);
1333                                 
1334                                 if(length) index= 0;
1335                                 else length= 1;
1336                         }
1337                         else
1338                                 length= 1;
1339                         
1340                         for (a=0; a<length; a++)
1341                                 success+= delete_keyframe(ptr.id.data, NULL, NULL, path, index+a, cfra, 0);
1342                         
1343                         MEM_freeN(path);
1344                 }
1345                 else if (G.f & G_DEBUG)
1346                         printf("Button Delete-Key: no path to property \n");
1347         }
1348         else if (G.f & G_DEBUG) {
1349                 printf("ptr.data = %p, prop = %p \n", ptr.data, prop);
1350         }
1351         
1352         
1353         if(success) {
1354                 /* send updates */
1355                 ED_anim_dag_flush_update(C);    
1356                 
1357                 /* for now, only send ND_KEYS for KeyingSets */
1358                 WM_event_add_notifier(C, ND_KEYS, NULL);
1359         }
1360         
1361         return (success)? OPERATOR_FINISHED: OPERATOR_CANCELLED;
1362 }
1363
1364 void ANIM_OT_delete_keyframe_button (wmOperatorType *ot)
1365 {
1366         /* identifiers */
1367         ot->name= "Delete Keyframe";
1368         ot->idname= "ANIM_OT_delete_keyframe_button";
1369         
1370         /* callbacks */
1371         ot->exec= delete_key_button_exec; 
1372         ot->poll= modify_key_op_poll;
1373         
1374         /* flags */
1375         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1376
1377         /* properties */
1378         RNA_def_boolean(ot->srna, "all", 1, "All", "Delete keyfames from all elements of the array.");
1379 }
1380
1381 /* ******************************************* */
1382 /* KEYFRAME DETECTION */
1383
1384 /* --------------- API/Per-Datablock Handling ------------------- */
1385
1386 /* Checks whether an Action has a keyframe for a given frame 
1387  * Since we're only concerned whether a keyframe exists, we can simply loop until a match is found...
1388  */
1389 short action_frame_has_keyframe (bAction *act, float frame, short filter)
1390 {
1391         FCurve *fcu;
1392         
1393         /* can only find if there is data */
1394         if (act == NULL)
1395                 return 0;
1396                 
1397         /* if only check non-muted, check if muted */
1398         if ((filter & ANIMFILTER_KEYS_MUTED) || (act->flag & ACT_MUTED))
1399                 return 0;
1400         
1401         /* loop over F-Curves, using binary-search to try to find matches 
1402          *      - this assumes that keyframes are only beztriples
1403          */
1404         for (fcu= act->curves.first; fcu; fcu= fcu->next) {
1405                 /* only check if there are keyframes (currently only of type BezTriple) */
1406                 if (fcu->bezt && fcu->totvert) {
1407                         /* we either include all regardless of muting, or only non-muted  */
1408                         if ((filter & ANIMFILTER_KEYS_MUTED) || (fcu->flag & FCURVE_MUTED)==0) {
1409                                 short replace = -1;
1410                                 int i = binarysearch_bezt_index(fcu->bezt, frame, fcu->totvert, &replace);
1411                                 
1412                                 /* binarysearch_bezt_index will set replace to be 0 or 1
1413                                  *      - obviously, 1 represents a match
1414                                  */
1415                                 if (replace) {                  
1416                                         /* sanity check: 'i' may in rare cases exceed arraylen */
1417                                         if ((i >= 0) && (i < fcu->totvert))
1418                                                 return 1;
1419                                 }
1420                         }
1421                 }
1422         }
1423         
1424         /* nothing found */
1425         return 0;
1426 }
1427
1428 /* Checks whether an Object has a keyframe for a given frame */
1429 short object_frame_has_keyframe (Object *ob, float frame, short filter)
1430 {
1431         /* error checking */
1432         if (ob == NULL)
1433                 return 0;
1434         
1435         /* check own animation data - specifically, the action it contains */
1436         if ((ob->adt) && (ob->adt->action)) {
1437                 if (action_frame_has_keyframe(ob->adt->action, frame, filter))
1438                         return 1;
1439         }
1440         
1441         /* try shapekey keyframes (if available, and allowed by filter) */
1442         if ( !(filter & ANIMFILTER_KEYS_LOCAL) && !(filter & ANIMFILTER_KEYS_NOSKEY) ) {
1443                 Key *key= ob_get_key(ob);
1444                 
1445                 /* shapekeys can have keyframes ('Relative Shape Keys') 
1446                  * or depend on time (old 'Absolute Shape Keys') 
1447                  */
1448                  
1449                         /* 1. test for relative (with keyframes) */
1450                 if (id_frame_has_keyframe((ID *)key, frame, filter))
1451                         return 1;
1452                         
1453                         /* 2. test for time */
1454                 // TODO... yet to be implemented (this feature may evolve before then anyway)
1455         }
1456         
1457         /* try materials */
1458         if ( !(filter & ANIMFILTER_KEYS_LOCAL) && !(filter & ANIMFILTER_KEYS_NOMAT) ) {
1459                 /* if only active, then we can skip a lot of looping */
1460                 if (filter & ANIMFILTER_KEYS_ACTIVE) {
1461                         Material *ma= give_current_material(ob, (ob->actcol + 1));
1462                         
1463                         /* we only retrieve the active material... */
1464                         if (id_frame_has_keyframe((ID *)ma, frame, filter))
1465                                 return 1;
1466                 }
1467                 else {
1468                         int a;
1469                         
1470                         /* loop over materials */
1471                         for (a=0; a<ob->totcol; a++) {
1472                                 Material *ma= give_current_material(ob, a+1);
1473                                 
1474                                 if (id_frame_has_keyframe((ID *)ma, frame, filter))
1475                                         return 1;
1476                         }
1477                 }
1478         }
1479         
1480         /* nothing found */
1481         return 0;
1482 }
1483
1484 /* --------------- API ------------------- */
1485
1486 /* Checks whether a keyframe exists for the given ID-block one the given frame */
1487 short id_frame_has_keyframe (ID *id, float frame, short filter)
1488 {
1489         /* sanity checks */
1490         if (id == NULL)
1491                 return 0;
1492         
1493         /* perform special checks for 'macro' types */
1494         switch (GS(id->name)) {
1495                 case ID_OB: /* object */
1496                         return object_frame_has_keyframe((Object *)id, frame, filter);
1497                         break;
1498                         
1499                 case ID_SCE: /* scene */
1500                 // XXX TODO... for now, just use 'normal' behaviour
1501                 //      break;
1502                 
1503                 default:        /* 'normal type' */
1504                 {
1505                         AnimData *adt= BKE_animdata_from_id(id);
1506                         
1507                         /* only check keyframes in active action */
1508                         if (adt)
1509                                 return action_frame_has_keyframe(adt->action, frame, filter);
1510                 }
1511                         break;
1512         }
1513         
1514         
1515         /* no keyframe found */
1516         return 0;
1517 }
1518
1519 /* ************************************************** */