Assorted tweaks for animation editors:
[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_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, "rotation_euler")) {
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_quaternion")) {
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                 // TODO: axis-angle...
662         }
663         
664         /* as the function hasn't returned yet, read value from system in the default way */
665         return setting_get_rna_value(ptr, prop, array_index);
666 }
667
668 /* ------------------------- Insert Key API ------------------------- */
669
670 /* Secondary Keyframing API call: 
671  *      Use this when validation of necessary animation data is not necessary, since an RNA-pointer to the necessary
672  *      data being keyframed, and a pointer to the F-Curve to use have both been provided.
673  *
674  *      The flag argument is used for special settings that alter the behaviour of
675  *      the keyframe insertion. These include the 'visual' keyframing modes, quick refresh,
676  *      and extra keyframe filtering.
677  */
678 short insert_keyframe_direct (PointerRNA ptr, PropertyRNA *prop, FCurve *fcu, float cfra, short flag)
679 {
680         float curval= 0.0f;
681         
682         /* no F-Curve to add keyframe to? */
683         if (fcu == NULL) {
684                 printf("ERROR: no F-Curve to add keyframes to \n");
685                 return 0;
686         }
687         /* F-Curve not editable? */
688         if ( (fcu->flag & FCURVE_PROTECTED) || ((fcu->grp) && (fcu->grp->flag & AGRP_PROTECTED)) ) {
689                 if (G.f & G_DEBUG)
690                         printf("WARNING: not inserting keyframe for locked F-Curve \n");
691                 return 0;
692         }
693         
694         /* if no property given yet, try to validate from F-Curve info */
695         if ((ptr.id.data == NULL) && (ptr.data==NULL)) {
696                 printf("ERROR: no RNA-pointer available to retrieve values for keyframing from\n");
697                 return 0;
698         }
699         if (prop == NULL) {
700                 PointerRNA tmp_ptr;
701                 
702                 /* try to get property we should be affecting */
703                 if ((RNA_path_resolve(&ptr, fcu->rna_path, &tmp_ptr, &prop) == 0) || (prop == NULL)) {
704                         /* property not found... */
705                         char *idname= (ptr.id.data) ? ((ID *)ptr.id.data)->name : "<No ID-Pointer>";
706                         
707                         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);
708                         return 0;
709                 }
710                 else {
711                         /* property found, so overwrite 'ptr' to make later code easier */
712                         ptr= tmp_ptr;
713                 }
714         }
715         
716         /* set additional flags for the F-Curve (i.e. only integer values) */
717         fcu->flag &= ~(FCURVE_INT_VALUES|FCURVE_DISCRETE_VALUES);
718         switch (RNA_property_type(prop)) {
719                 case PROP_FLOAT:
720                         /* do nothing */
721                         break;
722                 case PROP_INT:
723                         /* do integer (only 'whole' numbers) interpolation between all points */
724                         fcu->flag |= FCURVE_INT_VALUES;
725                         break;
726                 default:
727                         /* do 'discrete' (i.e. enum, boolean values which cannot take any intermediate
728                          * values at all) interpolation between all points
729                          *      - however, we must also ensure that evaluated values are only integers still
730                          */
731                         fcu->flag |= (FCURVE_DISCRETE_VALUES|FCURVE_INT_VALUES);
732                         break;
733         }
734         
735         /* obtain value to give keyframe */
736         if ( (flag & INSERTKEY_MATRIX) && 
737                  (visualkey_can_use(&ptr, prop)) ) 
738         {
739                 /* visual-keying is only available for object and pchan datablocks, as 
740                  * it works by keyframing using a value extracted from the final matrix 
741                  * instead of using the kt system to extract a value.
742                  */
743                 curval= visualkey_get_value(&ptr, prop, fcu->array_index);
744         }
745         else {
746                 /* read value from system */
747                 curval= setting_get_rna_value(&ptr, prop, fcu->array_index);
748         }
749         
750         /* only insert keyframes where they are needed */
751         if (flag & INSERTKEY_NEEDED) {
752                 short insert_mode;
753                 
754                 /* check whether this curve really needs a new keyframe */
755                 insert_mode= new_key_needed(fcu, cfra, curval);
756                 
757                 /* insert new keyframe at current frame */
758                 if (insert_mode)
759                         insert_vert_fcurve(fcu, cfra, curval, flag);
760                 
761                 /* delete keyframe immediately before/after newly added */
762                 switch (insert_mode) {
763                         case KEYNEEDED_DELPREV:
764                                 delete_fcurve_key(fcu, fcu->totvert-2, 1);
765                                 break;
766                         case KEYNEEDED_DELNEXT:
767                                 delete_fcurve_key(fcu, 1, 1);
768                                 break;
769                 }
770                 
771                 /* only return success if keyframe added */
772                 if (insert_mode)
773                         return 1;
774         }
775         else {
776                 /* just insert keyframe */
777                 insert_vert_fcurve(fcu, cfra, curval, flag);
778                 
779                 /* return success */
780                 return 1;
781         }
782         
783         /* failed */
784         return 0;
785 }
786
787 /* Main Keyframing API call:
788  *      Use this when validation of necessary animation data is necessary, since it may not exist yet.
789  *      
790  *      The flag argument is used for special settings that alter the behaviour of
791  *      the keyframe insertion. These include the 'visual' keyframing modes, quick refresh,
792  *      and extra keyframe filtering.
793  */
794 short insert_keyframe (ID *id, bAction *act, const char group[], const char rna_path[], int array_index, float cfra, short flag)
795 {       
796         PointerRNA id_ptr, ptr;
797         PropertyRNA *prop;
798         FCurve *fcu;
799         
800         /* validate pointer first - exit if failure */
801         RNA_id_pointer_create(id, &id_ptr);
802         if ((RNA_path_resolve(&id_ptr, rna_path, &ptr, &prop) == 0) || (prop == NULL)) {
803                 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);
804                 return 0;
805         }
806         
807         /* get F-Curve - if no action is provided, keyframe to the default one attached to this ID-block */
808         if (act == NULL) {
809                 AnimData *adt= BKE_animdata_from_id(id);
810                 
811                 /* get action to add F-Curve+keyframe to */
812                 act= verify_adt_action(id, 1);
813                 
814                 /* apply NLA-mapping to frame to use (if applicable) */
815                 cfra= BKE_nla_tweakedit_remap(adt, cfra, NLATIME_CONVERT_UNMAP);
816         }
817         fcu= verify_fcurve(act, group, rna_path, array_index, 1);
818         
819         /* apply special time tweaking */
820                 // XXX check on this stuff...
821         if (GS(id->name) == ID_OB) {
822                 //Object *ob= (Object *)id;
823                 
824                 /* ancient time-offset cruft */
825                 //if ( (ob->ipoflag & OB_OFFS_OB) && (give_timeoffset(ob)) ) {
826                 //      /* actually frametofloat calc again! */
827                 //      cfra-= give_timeoffset(ob)*scene->r.framelen;
828                 //}
829         }
830         
831         /* insert keyframe */
832         return insert_keyframe_direct(ptr, prop, fcu, cfra, flag);
833 }
834
835 /* ************************************************** */
836 /* KEYFRAME DELETION */
837
838 /* Main Keyframing API call:
839  *      Use this when validation of necessary animation data isn't necessary as it
840  *      already exists. It will delete a keyframe at the current frame.
841  *      
842  *      The flag argument is used for special settings that alter the behaviour of
843  *      the keyframe deletion. These include the quick refresh options.
844  */
845 short delete_keyframe (ID *id, bAction *act, const char group[], const char rna_path[], int array_index, float cfra, short flag)
846 {
847         FCurve *fcu = NULL;
848         
849         /* get F-Curve
850          * Note: here is one of the places where we don't want new Action + F-Curve added!
851          *              so 'add' var must be 0
852          */
853         if (act == NULL) {
854                 /* if no action is provided, use the default one attached to this ID-block */
855                 AnimData *adt= BKE_animdata_from_id(id);
856                 act= adt->action;
857                 
858                 /* apply NLA-mapping to frame to use (if applicable) */
859                 cfra= BKE_nla_tweakedit_remap(adt, cfra, NLATIME_CONVERT_UNMAP); 
860         }
861         /* we don't check the validity of the path here yet, but it should be ok... */
862         fcu= verify_fcurve(act, group, rna_path, array_index, 0);
863         
864         /* check if F-Curve exists and/or whether it can be edited */
865         if ELEM(NULL, act, fcu) {
866                 printf("ERROR: no F-Curve and/or Action to delete keyframe from \n");
867                 return 0;
868         }
869         if ( (fcu->flag & FCURVE_PROTECTED) || ((fcu->grp) && (fcu->grp->flag & AGRP_PROTECTED)) ) {
870                 if (G.f & G_DEBUG)
871                         printf("WARNING: not inserting keyframe for locked F-Curve \n");
872                 return 0;
873         }
874         
875         /* it should be fine to continue now... */
876         {
877                 short found = -1;
878                 int i;
879                 
880                 /* apply special time tweaking */
881                 if (GS(id->name) == ID_OB) {
882                         //Object *ob= (Object *)id;
883                         
884                         /* ancient time-offset cruft */
885                         //if ( (ob->ipoflag & OB_OFFS_OB) && (give_timeoffset(ob)) ) {
886                         //      /* actually frametofloat calc again! */
887                         //      cfra-= give_timeoffset(ob)*scene->r.framelen;
888                         //}
889                 }
890                 
891                 /* try to find index of beztriple to get rid of */
892                 i = binarysearch_bezt_index(fcu->bezt, cfra, fcu->totvert, &found);
893                 if (found) {                    
894                         /* delete the key at the index (will sanity check + do recalc afterwards) */
895                         delete_fcurve_key(fcu, i, 1);
896                         
897                         /* Only delete curve too if there are no points (we don't need to check for drivers, as they're kept separate) */
898                         if (fcu->totvert == 0) {
899                                 BLI_remlink(&act->curves, fcu);
900                                 free_fcurve(fcu);
901                         }
902                         
903                         /* return success */
904                         return 1;
905                 }
906         }
907         
908         /* return failure */
909         return 0;
910 }
911
912 /* ******************************************* */
913 /* KEYFRAME MODIFICATION */
914
915 /* mode for commonkey_modifykey */
916 enum {
917         COMMONKEY_MODE_INSERT = 0,
918         COMMONKEY_MODE_DELETE,
919 } eCommonModifyKey_Modes;
920
921 /* Polling callback for use with ANIM_*_keyframe() operators
922  * This is based on the standard ED_operator_areaactive callback,
923  * except that it does special checks for a few spacetypes too...
924  */
925 static int modify_key_op_poll(bContext *C)
926 {
927         ScrArea *sa= CTX_wm_area(C);
928         Scene *scene= CTX_data_scene(C);
929         SpaceOops *so= CTX_wm_space_outliner(C);
930         
931         /* if no area or active scene */
932         if (ELEM(NULL, sa, scene)) 
933                 return 0;
934         
935         /* if Outliner, only allow in DataBlocks view */
936         if (so && (so->outlinevis != SO_DATABLOCKS))
937                 return 0;
938         
939         /* TODO: checks for other space types can be added here */
940         
941         /* should be fine */
942         return 1;
943 }
944
945 /* Insert Key Operator ------------------------ */
946
947 static int insert_key_exec (bContext *C, wmOperator *op)
948 {
949         ListBase dsources = {NULL, NULL};
950         Scene *scene= CTX_data_scene(C);
951         KeyingSet *ks= NULL;
952         int type= RNA_int_get(op->ptr, "type");
953         float cfra= (float)CFRA; // XXX for now, don't bother about all the yucky offset crap
954         short success;
955         
956         /* type is the Keying Set the user specified to use when calling the operator:
957          *      - type == 0: use scene's active Keying Set
958          *      - type > 0: use a user-defined Keying Set from the active scene
959          *      - type < 0: use a builtin Keying Set
960          */
961         if (type == 0) 
962                 type= scene->active_keyingset;
963         if (type > 0)
964                 ks= BLI_findlink(&scene->keyingsets, scene->active_keyingset-1);
965         else
966                 ks= BLI_findlink(&builtin_keyingsets, -type-1);
967                 
968         /* report failures */
969         if (ks == NULL) {
970                 BKE_report(op->reports, RPT_ERROR, "No active Keying Set");
971                 return OPERATOR_CANCELLED;
972         }
973         
974         /* get context info for relative Keying Sets */
975         if ((ks->flag & KEYINGSET_ABSOLUTE) == 0) {
976                 /* exit if no suitable data obtained */
977                 if (modifykey_get_context_data(C, &dsources, ks) == 0) {
978                         BKE_report(op->reports, RPT_ERROR, "No suitable context info for active Keying Set");
979                         return OPERATOR_CANCELLED;
980                 }
981         }
982         
983         /* try to insert keyframes for the channels specified by KeyingSet */
984         success= modify_keyframes(scene, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra);
985         if (G.f & G_DEBUG)
986                 printf("KeyingSet '%s' - Successfully added %d Keyframes \n", ks->name, success);
987         
988         /* report failure? */
989         if (success == 0)
990                 BKE_report(op->reports, RPT_WARNING, "Keying Set failed to insert any keyframes");
991         else
992                 WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME_EDIT, NULL);
993         
994         /* free temp context-data if available */
995         if (dsources.first) {
996                 /* we assume that there is no extra data that needs to be freed from here... */
997                 BLI_freelistN(&dsources);
998         }
999         
1000         /* send updates */
1001         ED_anim_dag_flush_update(C);
1002         
1003         return OPERATOR_FINISHED;
1004 }
1005
1006 void ANIM_OT_insert_keyframe (wmOperatorType *ot)
1007 {
1008         /* identifiers */
1009         ot->name= "Insert Keyframe";
1010         ot->idname= "ANIM_OT_insert_keyframe";
1011         
1012         /* callbacks */
1013         ot->exec= insert_key_exec; 
1014         ot->poll= modify_key_op_poll;
1015         
1016         /* flags */
1017         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1018         
1019         /* settings */
1020         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);
1021 }
1022
1023 /* Insert Key Operator (With Menu) ------------------------ */
1024
1025 /* XXX 
1026  * This operator pops up a menu which sets gets the index of the keyingset to use,
1027  * setting the global settings, and calling the insert-keyframe operator using these
1028  * settings
1029  */
1030
1031 static int insert_key_menu_invoke (bContext *C, wmOperator *op, wmEvent *event)
1032 {
1033         Scene *scene= CTX_data_scene(C);
1034         KeyingSet *ks;
1035         uiPopupMenu *pup;
1036         uiLayout *layout;
1037         int i = 0;
1038         
1039         pup= uiPupMenuBegin(C, "Insert Keyframe", 0);
1040         layout= uiPupMenuLayout(pup);
1041         
1042         /* active Keying Set 
1043          *      - only include entry if it exists
1044          */
1045         if (scene->active_keyingset) {
1046                 uiItemIntO(layout, "Active Keying Set", 0, "ANIM_OT_insert_keyframe_menu", "type", i++);
1047                 uiItemS(layout);
1048         }
1049         else
1050                 i++;
1051         
1052         /* user-defined Keying Sets 
1053          *      - these are listed in the order in which they were defined for the active scene
1054          */
1055         if (scene->keyingsets.first) {
1056                 for (ks= scene->keyingsets.first; ks; ks= ks->next)
1057                         uiItemIntO(layout, ks->name, 0, "ANIM_OT_insert_keyframe_menu", "type", i++);
1058                 uiItemS(layout);
1059         }
1060         
1061         /* builtin Keying Sets */
1062         // XXX polling the entire list may lag
1063         i= -1;
1064         for (ks= builtin_keyingsets.first; ks; ks= ks->next) {
1065                 /* only show KeyingSet if context is suitable */
1066                 if (keyingset_context_ok_poll(C, ks)) {
1067                         uiItemIntO(layout, ks->name, 0, "ANIM_OT_insert_keyframe_menu", "type", i--);
1068                 }
1069         }
1070         
1071         uiPupMenuEnd(C, pup);
1072         
1073         return OPERATOR_CANCELLED;
1074 }
1075  
1076 void ANIM_OT_insert_keyframe_menu (wmOperatorType *ot)
1077 {
1078         /* identifiers */
1079         ot->name= "Insert Keyframe Menu";
1080         ot->idname= "ANIM_OT_insert_keyframe_menu";
1081         
1082         /* callbacks */
1083         ot->invoke= insert_key_menu_invoke;
1084         ot->exec= insert_key_exec; 
1085         ot->poll= ED_operator_areaactive;
1086         
1087         /* flags */
1088         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1089         
1090         /* properties
1091          *      - NOTE: here the type is int not enum, since many of the indicies here are determined dynamically
1092          */
1093         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);
1094 }
1095
1096 /* Delete Key Operator ------------------------ */
1097
1098 static int delete_key_exec (bContext *C, wmOperator *op)
1099 {
1100         ListBase dsources = {NULL, NULL};
1101         Scene *scene= CTX_data_scene(C);
1102         KeyingSet *ks= NULL;    
1103         int type= RNA_int_get(op->ptr, "type");
1104         float cfra= (float)CFRA; // XXX for now, don't bother about all the yucky offset crap
1105         short success;
1106         
1107         /* type is the Keying Set the user specified to use when calling the operator:
1108          *      - type == 0: use scene's active Keying Set
1109          *      - type > 0: use a user-defined Keying Set from the active scene
1110          *      - type < 0: use a builtin Keying Set
1111          */
1112         if (type == 0) 
1113                 type= scene->active_keyingset;
1114         if (type > 0)
1115                 ks= BLI_findlink(&scene->keyingsets, scene->active_keyingset-1);
1116         else
1117                 ks= BLI_findlink(&builtin_keyingsets, -type-1);
1118         
1119         /* report failure */
1120         if (ks == NULL) {
1121                 BKE_report(op->reports, RPT_ERROR, "No active Keying Set");
1122                 return OPERATOR_CANCELLED;
1123         }
1124         
1125         /* get context info for relative Keying Sets */
1126         if ((ks->flag & KEYINGSET_ABSOLUTE) == 0) {
1127                 /* exit if no suitable data obtained */
1128                 if (modifykey_get_context_data(C, &dsources, ks) == 0) {
1129                         BKE_report(op->reports, RPT_ERROR, "No suitable context info for active Keying Set");
1130                         return OPERATOR_CANCELLED;
1131                 }
1132         }
1133         
1134         /* try to insert keyframes for the channels specified by KeyingSet */
1135         success= modify_keyframes(scene, &dsources, NULL, ks, MODIFYKEY_MODE_DELETE, cfra);
1136         if (G.f & G_DEBUG)
1137                 printf("KeyingSet '%s' - Successfully removed %d Keyframes \n", ks->name, success);
1138         
1139         /* report failure? */
1140         if (success == 0)
1141                 BKE_report(op->reports, RPT_WARNING, "Keying Set failed to remove any keyframes");
1142         else
1143                 WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME_EDIT, NULL);
1144         
1145         /* free temp context-data if available */
1146         if (dsources.first) {
1147                 /* we assume that there is no extra data that needs to be freed from here... */
1148                 BLI_freelistN(&dsources);
1149         }
1150         
1151         /* send updates */
1152         ED_anim_dag_flush_update(C);    
1153         
1154         return OPERATOR_FINISHED;
1155 }
1156
1157 void ANIM_OT_delete_keyframe (wmOperatorType *ot)
1158 {
1159         /* identifiers */
1160         ot->name= "Delete Keyframe";
1161         ot->idname= "ANIM_OT_delete_keyframe";
1162         
1163         /* callbacks */
1164         ot->exec= delete_key_exec; 
1165         ot->poll= modify_key_op_poll;
1166         
1167         /* flags */
1168         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1169         
1170         /* properties
1171          *      - NOTE: here the type is int not enum, since many of the indicies here are determined dynamically
1172          */
1173         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);
1174 }
1175
1176 /* Delete Key Operator ------------------------ */
1177
1178 /* XXX WARNING:
1179  * This is currently just a basic operator, which work in 3d-view context on objects only. 
1180  * Should this be kept? It does have advantages over a version which requires selecting a keyingset to use...
1181  * -- Joshua Leung, Jan 2009
1182  */
1183  
1184 static int delete_key_v3d_exec (bContext *C, wmOperator *op)
1185 {
1186         Scene *scene= CTX_data_scene(C);
1187         float cfra= (float)CFRA; // XXX for now, don't bother about all the yucky offset crap
1188         
1189         // XXX more comprehensive tests will be needed
1190         CTX_DATA_BEGIN(C, Base*, base, selected_bases) 
1191         {
1192                 Object *ob= base->object;
1193                 ID *id= (ID *)ob;
1194                 FCurve *fcu, *fcn;
1195                 short success= 0;
1196                 
1197                 /* loop through all curves in animdata and delete keys on this frame */
1198                 if (ob->adt) {
1199                         AnimData *adt= ob->adt;
1200                         bAction *act= adt->action;
1201                         
1202                         for (fcu= act->curves.first; fcu; fcu= fcn) {
1203                                 fcn= fcu->next;
1204                                 success+= delete_keyframe(id, NULL, NULL, fcu->rna_path, fcu->array_index, cfra, 0);
1205                         }
1206                 }
1207                 
1208                 printf("Ob '%s' - Successfully removed %d keyframes \n", id->name+2, success);
1209                 
1210                 ob->recalc |= OB_RECALC_OB;
1211         }
1212         CTX_DATA_END;
1213         
1214         /* send updates */
1215         ED_anim_dag_flush_update(C);    
1216         
1217         WM_event_add_notifier(C, NC_OBJECT|ND_KEYS, NULL);
1218         
1219         return OPERATOR_FINISHED;
1220 }
1221
1222 void ANIM_OT_delete_keyframe_v3d (wmOperatorType *ot)
1223 {
1224         /* identifiers */
1225         ot->name= "Delete Keyframe";
1226         ot->idname= "ANIM_OT_delete_keyframe_v3d";
1227         
1228         /* callbacks */
1229         ot->invoke= WM_operator_confirm;
1230         ot->exec= delete_key_v3d_exec; 
1231         
1232         ot->poll= ED_operator_areaactive;
1233         
1234         /* flags */
1235         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1236 }
1237
1238
1239 /* Insert Key Button Operator ------------------------ */
1240
1241 static int insert_key_button_exec (bContext *C, wmOperator *op)
1242 {
1243         Scene *scene= CTX_data_scene(C);
1244         PointerRNA ptr;
1245         PropertyRNA *prop= NULL;
1246         char *path;
1247         float cfra= (float)CFRA; // XXX for now, don't bother about all the yucky offset crap
1248         short success= 0;
1249         int a, index, length, all= RNA_boolean_get(op->ptr, "all");
1250         short flag = 0;
1251         
1252         /* flags for inserting keyframes */
1253         if (IS_AUTOKEY_FLAG(AUTOMATKEY))
1254                 flag |= INSERTKEY_MATRIX;
1255         if (IS_AUTOKEY_FLAG(INSERTNEEDED))
1256                 flag |= INSERTKEY_NEEDED;
1257         if (IS_AUTOKEY_MODE(scene, EDITKEYS))
1258                 flag |= INSERTKEY_REPLACE;
1259         
1260         /* try to insert keyframe using property retrieved from UI */
1261         memset(&ptr, 0, sizeof(PointerRNA));
1262         uiAnimContextProperty(C, &ptr, &prop, &index);
1263         
1264         if ((ptr.data && prop) && RNA_property_animateable(&ptr, prop)) {
1265                 path= RNA_path_from_ID_to_property(&ptr, prop);
1266                 
1267                 if (path) {
1268                         if (all) {
1269                                 length= RNA_property_array_length(&ptr, prop);
1270                                 
1271                                 if(length) index= 0;
1272                                 else length= 1;
1273                         }
1274                         else
1275                                 length= 1;
1276                         
1277                         for (a=0; a<length; a++)
1278                                 success+= insert_keyframe(ptr.id.data, NULL, NULL, path, index+a, cfra, flag);
1279                         
1280                         MEM_freeN(path);
1281                 }
1282                 else if (ptr.type == &RNA_NlaStrip) {
1283                         /* handle special vars for NLA-strips */
1284                         NlaStrip *strip= (NlaStrip *)ptr.data;
1285                         FCurve *fcu= list_find_fcurve(&strip->fcurves, RNA_property_identifier(prop), flag);
1286                         
1287                         success+= insert_keyframe_direct(ptr, prop, fcu, cfra, 0);
1288                 }
1289                 else {
1290                         if (G.f & G_DEBUG)
1291                                 printf("Button Insert-Key: no path to property \n");
1292                         BKE_report(op->reports, RPT_WARNING, "Failed to resolve path to property. Try using a Keying Set instead.");
1293                 }
1294         }
1295         else if (G.f & G_DEBUG) {
1296                 printf("ptr.data = %p, prop = %p,", ptr.data, prop);
1297                 if(prop)
1298                         printf("animateable = %d \n", RNA_property_animateable(&ptr, prop));
1299                 else
1300                         printf("animateable = NULL \n");
1301         }
1302         
1303         if (success) {
1304                 /* send updates */
1305                 ED_anim_dag_flush_update(C);    
1306                 
1307                 /* for now, only send ND_KEYS for KeyingSets */
1308                 WM_event_add_notifier(C, ND_KEYS, NULL);
1309         }
1310         
1311         return (success)? OPERATOR_FINISHED: OPERATOR_CANCELLED;
1312 }
1313
1314 void ANIM_OT_insert_keyframe_button (wmOperatorType *ot)
1315 {
1316         /* identifiers */
1317         ot->name= "Insert Keyframe (Buttons)";
1318         ot->idname= "ANIM_OT_insert_keyframe_button";
1319         
1320         /* callbacks */
1321         ot->exec= insert_key_button_exec; 
1322         ot->poll= modify_key_op_poll;
1323         
1324         /* flags */
1325         ot->flag= OPTYPE_UNDO;
1326
1327         /* properties */
1328         RNA_def_boolean(ot->srna, "all", 1, "All", "Insert a keyframe for all element of the array.");
1329 }
1330
1331 /* Delete Key Button Operator ------------------------ */
1332
1333 static int delete_key_button_exec (bContext *C, wmOperator *op)
1334 {
1335         Scene *scene= CTX_data_scene(C);
1336         PointerRNA ptr;
1337         PropertyRNA *prop= NULL;
1338         char *path;
1339         float cfra= (float)CFRA; // XXX for now, don't bother about all the yucky offset crap
1340         short success= 0;
1341         int a, index, length, all= RNA_boolean_get(op->ptr, "all");
1342         
1343         /* try to insert keyframe using property retrieved from UI */
1344         memset(&ptr, 0, sizeof(PointerRNA));
1345         uiAnimContextProperty(C, &ptr, &prop, &index);
1346
1347         if (ptr.data && prop) {
1348                 path= RNA_path_from_ID_to_property(&ptr, prop);
1349                 
1350                 if (path) {
1351                         if (all) {
1352                                 length= RNA_property_array_length(&ptr, prop);
1353                                 
1354                                 if(length) index= 0;
1355                                 else length= 1;
1356                         }
1357                         else
1358                                 length= 1;
1359                         
1360                         for (a=0; a<length; a++)
1361                                 success+= delete_keyframe(ptr.id.data, NULL, NULL, path, index+a, cfra, 0);
1362                         
1363                         MEM_freeN(path);
1364                 }
1365                 else if (G.f & G_DEBUG)
1366                         printf("Button Delete-Key: no path to property \n");
1367         }
1368         else if (G.f & G_DEBUG) {
1369                 printf("ptr.data = %p, prop = %p \n", ptr.data, prop);
1370         }
1371         
1372         
1373         if(success) {
1374                 /* send updates */
1375                 ED_anim_dag_flush_update(C);    
1376                 
1377                 /* for now, only send ND_KEYS for KeyingSets */
1378                 WM_event_add_notifier(C, ND_KEYS, NULL);
1379         }
1380         
1381         return (success)? OPERATOR_FINISHED: OPERATOR_CANCELLED;
1382 }
1383
1384 void ANIM_OT_delete_keyframe_button (wmOperatorType *ot)
1385 {
1386         /* identifiers */
1387         ot->name= "Delete Keyframe (Buttons)";
1388         ot->idname= "ANIM_OT_delete_keyframe_button";
1389         
1390         /* callbacks */
1391         ot->exec= delete_key_button_exec; 
1392         ot->poll= modify_key_op_poll;
1393         
1394         /* flags */
1395         ot->flag= OPTYPE_UNDO;
1396
1397         /* properties */
1398         RNA_def_boolean(ot->srna, "all", 1, "All", "Delete keyfames from all elements of the array.");
1399 }
1400
1401 /* ******************************************* */
1402 /* AUTO KEYFRAME */
1403
1404 int autokeyframe_cfra_can_key(Scene *scene, ID *id)
1405 {
1406         float cfra= (float)CFRA; // XXX for now, this will do
1407         
1408         /* only filter if auto-key mode requires this */
1409         if (IS_AUTOKEY_ON(scene) == 0)
1410                 return 0;
1411                 
1412         if (IS_AUTOKEY_MODE(scene, NORMAL)) {
1413                 /* can insert anytime we like... */
1414                 return 1;
1415         }
1416         else /* REPLACE */ {
1417                 /* for whole block - only key if there's a keyframe on that frame already
1418                  *      this is a valid assumption when we're blocking + tweaking
1419                  */
1420                 return id_frame_has_keyframe(id, cfra, ANIMFILTER_KEYS_LOCAL);
1421         }
1422 }
1423
1424 /* ******************************************* */
1425 /* KEYFRAME DETECTION */
1426
1427 /* --------------- API/Per-Datablock Handling ------------------- */
1428
1429 /* Checks if some F-Curve has a keyframe for a given frame */
1430 short fcurve_frame_has_keyframe (FCurve *fcu, float frame, short filter)
1431 {
1432         /* quick sanity check */
1433         if (ELEM(NULL, fcu, fcu->bezt))
1434                 return 0;
1435         
1436         /* we either include all regardless of muting, or only non-muted  */
1437         if ((filter & ANIMFILTER_KEYS_MUTED) || (fcu->flag & FCURVE_MUTED)==0) {
1438                 short replace = -1;
1439                 int i = binarysearch_bezt_index(fcu->bezt, frame, fcu->totvert, &replace);
1440                 
1441                 /* binarysearch_bezt_index will set replace to be 0 or 1
1442                  *      - obviously, 1 represents a match
1443                  */
1444                 if (replace) {                  
1445                         /* sanity check: 'i' may in rare cases exceed arraylen */
1446                         if ((i >= 0) && (i < fcu->totvert))
1447                                 return 1;
1448                 }
1449         }
1450         
1451         return 0;
1452 }
1453
1454 /* Checks whether an Action has a keyframe for a given frame 
1455  * Since we're only concerned whether a keyframe exists, we can simply loop until a match is found...
1456  */
1457 short action_frame_has_keyframe (bAction *act, float frame, short filter)
1458 {
1459         FCurve *fcu;
1460         
1461         /* can only find if there is data */
1462         if (act == NULL)
1463                 return 0;
1464                 
1465         /* if only check non-muted, check if muted */
1466         if ((filter & ANIMFILTER_KEYS_MUTED) || (act->flag & ACT_MUTED))
1467                 return 0;
1468         
1469         /* loop over F-Curves, using binary-search to try to find matches 
1470          *      - this assumes that keyframes are only beztriples
1471          */
1472         for (fcu= act->curves.first; fcu; fcu= fcu->next) {
1473                 /* only check if there are keyframes (currently only of type BezTriple) */
1474                 if (fcu->bezt && fcu->totvert) {
1475                         if (fcurve_frame_has_keyframe(fcu, frame, filter))
1476                                 return 1;
1477                 }
1478         }
1479         
1480         /* nothing found */
1481         return 0;
1482 }
1483
1484 /* Checks whether an Object has a keyframe for a given frame */
1485 short object_frame_has_keyframe (Object *ob, float frame, short filter)
1486 {
1487         /* error checking */
1488         if (ob == NULL)
1489                 return 0;
1490         
1491         /* check own animation data - specifically, the action it contains */
1492         if ((ob->adt) && (ob->adt->action)) {
1493                 if (action_frame_has_keyframe(ob->adt->action, frame, filter))
1494                         return 1;
1495         }
1496         
1497         /* try shapekey keyframes (if available, and allowed by filter) */
1498         if ( !(filter & ANIMFILTER_KEYS_LOCAL) && !(filter & ANIMFILTER_KEYS_NOSKEY) ) {
1499                 Key *key= ob_get_key(ob);
1500                 
1501                 /* shapekeys can have keyframes ('Relative Shape Keys') 
1502                  * or depend on time (old 'Absolute Shape Keys') 
1503                  */
1504                  
1505                         /* 1. test for relative (with keyframes) */
1506                 if (id_frame_has_keyframe((ID *)key, frame, filter))
1507                         return 1;
1508                         
1509                         /* 2. test for time */
1510                 // TODO... yet to be implemented (this feature may evolve before then anyway)
1511         }
1512         
1513         /* try materials */
1514         if ( !(filter & ANIMFILTER_KEYS_LOCAL) && !(filter & ANIMFILTER_KEYS_NOMAT) ) {
1515                 /* if only active, then we can skip a lot of looping */
1516                 if (filter & ANIMFILTER_KEYS_ACTIVE) {
1517                         Material *ma= give_current_material(ob, (ob->actcol + 1));
1518                         
1519                         /* we only retrieve the active material... */
1520                         if (id_frame_has_keyframe((ID *)ma, frame, filter))
1521                                 return 1;
1522                 }
1523                 else {
1524                         int a;
1525                         
1526                         /* loop over materials */
1527                         for (a=0; a<ob->totcol; a++) {
1528                                 Material *ma= give_current_material(ob, a+1);
1529                                 
1530                                 if (id_frame_has_keyframe((ID *)ma, frame, filter))
1531                                         return 1;
1532                         }
1533                 }
1534         }
1535         
1536         /* nothing found */
1537         return 0;
1538 }
1539
1540 /* --------------- API ------------------- */
1541
1542 /* Checks whether a keyframe exists for the given ID-block one the given frame */
1543 short id_frame_has_keyframe (ID *id, float frame, short filter)
1544 {
1545         /* sanity checks */
1546         if (id == NULL)
1547                 return 0;
1548         
1549         /* perform special checks for 'macro' types */
1550         switch (GS(id->name)) {
1551                 case ID_OB: /* object */
1552                         return object_frame_has_keyframe((Object *)id, frame, filter);
1553                         break;
1554                         
1555                 case ID_SCE: /* scene */
1556                 // XXX TODO... for now, just use 'normal' behaviour
1557                 //      break;
1558                 
1559                 default:        /* 'normal type' */
1560                 {
1561                         AnimData *adt= BKE_animdata_from_id(id);
1562                         
1563                         /* only check keyframes in active action */
1564                         if (adt)
1565                                 return action_frame_has_keyframe(adt->action, frame, filter);
1566                 }
1567                         break;
1568         }
1569         
1570         
1571         /* no keyframe found */
1572         return 0;
1573 }
1574
1575 /* ************************************************** */