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