ac04dc7d1a8ece09b75b602a7d01016dc7046f40
[blender.git] / source / blender / editors / animation / keyframes_edit.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) 2008 Blender Foundation
21  *
22  * Contributor(s): Joshua Leung
23  *
24  * ***** END GPL LICENSE BLOCK *****
25  */
26
27 #include <stdlib.h>
28 #include <string.h>
29 #include <math.h>
30 #include <float.h>
31
32 #include "MEM_guardedalloc.h"
33
34 #include "BLI_blenlib.h"
35 #include "BLI_arithb.h"
36
37 #include "DNA_anim_types.h"
38 #include "DNA_action_types.h"
39 #include "DNA_curve_types.h"
40 #include "DNA_key_types.h"
41 #include "DNA_object_types.h"
42 #include "DNA_space_types.h"
43 #include "DNA_scene_types.h"
44 #include "DNA_world_types.h"
45
46 #include "BKE_action.h"
47 #include "BKE_fcurve.h"
48 #include "BKE_key.h"
49 #include "BKE_utildefines.h"
50
51 #include "ED_anim_api.h"
52 #include "ED_keyframes_edit.h"
53 #include "ED_markers.h"
54
55 /* This file defines an API and set of callback-operators for non-destructive editing of keyframe data.
56  *
57  * Two API functions are defined for actually performing the operations on the data:
58  *                      ANIM_fcurve_keys_bezier_loop()
59  * which take the data they operate on, a few callbacks defining what operations to perform.
60  *
61  * As operators which work on keyframes usually apply the same operation on all BezTriples in 
62  * every channel, the code has been optimised providing a set of functions which will get the 
63  * appropriate bezier-modify function to set. These functions (ANIM_editkeyframes_*) will need
64  * to be called before getting any channels.
65  * 
66  * A set of 'validation' callbacks are provided for checking if a BezTriple should be operated on.
67  * These should only be used when using a 'general' BezTriple editor (i.e. selection setters which 
68  * don't check existing selection status).
69  * 
70  * - Joshua Leung, Dec 2008
71  */
72
73 /* ************************************************************************** */
74 /* Keyframe Editing Loops - Exposed API */
75
76 /* --------------------------- Base Functions ------------------------------------ */
77
78 /* This function is used to loop over BezTriples in the given F-Curve, applying a given 
79  * operation on them, and optionally applies an F-Curve validation function afterwards.
80  */
81 short ANIM_fcurve_keys_bezier_loop(BeztEditData *bed, FCurve *fcu, BeztEditFunc bezt_ok, BeztEditFunc bezt_cb, FcuEditFunc fcu_cb) 
82 {
83     BezTriple *bezt;
84         int b;
85         
86         /* sanity check */
87         if (ELEM(NULL, fcu, fcu->bezt))
88                 return 0;
89         
90         /* if function to apply to bezier curves is set, then loop through executing it on beztriples */
91     if (bezt_cb) {
92                 /* if there's a validation func, include that check in the loop 
93                  * (this is should be more efficient than checking for it in every loop)
94                  */
95                 if (bezt_ok) {
96                         for (b=0, bezt=fcu->bezt; b < fcu->totvert; b++, bezt++) {
97                                 /* Only operate on this BezTriple if it fullfills the criteria of the validation func */
98                                 if (bezt_ok(bed, bezt)) {
99                                         /* Exit with return-code '1' if function returns positive
100                                          * This is useful if finding if some BezTriple satisfies a condition.
101                                          */
102                                 if (bezt_cb(bed, bezt)) return 1;
103                                 }
104                         }
105                 }
106                 else {
107                         for (b=0, bezt=fcu->bezt; b < fcu->totvert; b++, bezt++) {
108                                 /* Exit with return-code '1' if function returns positive
109                                  * This is useful if finding if some BezTriple satisfies a condition.
110                                  */
111                         if (bezt_cb(bed, bezt)) return 1;
112                         }
113                 }
114     }
115
116     /* if fcu_cb (F-Curve post-editing callback) has been specified then execute it */
117     if (fcu_cb)
118         fcu_cb(fcu);
119         
120         /* done */      
121     return 0;
122 }
123
124 /* -------------------------------- Further Abstracted (Not Exposed Directly) ----------------------------- */
125
126 /* This function is used to loop over the keyframe data in an Action Group */
127 static short agrp_keys_bezier_loop(BeztEditData *bed, bActionGroup *agrp, BeztEditFunc bezt_ok, BeztEditFunc bezt_cb, FcuEditFunc fcu_cb)
128 {
129         FCurve *fcu;
130         
131         /* sanity check */
132         if (agrp == NULL)
133                 return 0;
134         
135         /* only iterate over the F-Curves that are in this group */
136         for (fcu= agrp->channels.first; fcu && fcu->grp==agrp; fcu= fcu->next) {
137                 if (ANIM_fcurve_keys_bezier_loop(bed, fcu, bezt_ok, bezt_cb, fcu_cb))
138                         return 1;
139         }
140         
141         return 0;
142 }
143
144 /* This function is used to loop over the keyframe data in an Action */
145 static short act_keys_bezier_loop(BeztEditData *bed, bAction *act, BeztEditFunc bezt_ok, BeztEditFunc bezt_cb, FcuEditFunc fcu_cb)
146 {
147         FCurve *fcu;
148         
149         /* sanity check */
150         if (act == NULL)
151                 return 0;
152         
153         /* just loop through all F-Curves */
154         for (fcu= act->curves.first; fcu; fcu= fcu->next) {
155                 if (ANIM_fcurve_keys_bezier_loop(bed, fcu, bezt_ok, bezt_cb, fcu_cb))
156                         return 1;
157         }
158         
159         return 0;
160 }
161
162 /* This function is used to loop over the keyframe data of an AnimData block */
163 static short adt_keys_bezier_loop(BeztEditData *bed, AnimData *adt, BeztEditFunc bezt_ok, BeztEditFunc bezt_cb, FcuEditFunc fcu_cb, int filterflag)
164 {
165         /* sanity check */
166         if (adt == NULL)
167                 return 0;
168         
169         /* drivers or actions? */
170         if (filterflag & ADS_FILTER_ONLYDRIVERS) {
171                 FCurve *fcu;
172                 
173                 /* just loop through all F-Curves acting as Drivers */
174                 for (fcu= adt->drivers.first; fcu; fcu= fcu->next) {
175                         if (ANIM_fcurve_keys_bezier_loop(bed, fcu, bezt_ok, bezt_cb, fcu_cb))
176                                 return 1;
177                 }
178         }
179         else if (adt->action) {
180                 /* call the function for actions */
181                 if (act_keys_bezier_loop(bed, adt->action, bezt_ok, bezt_cb, fcu_cb))
182                         return 1;
183         }
184         
185         return 0;
186 }
187
188 /* This function is used to loop over the keyframe data in an Object */
189 static short ob_keys_bezier_loop(BeztEditData *bed, Object *ob, BeztEditFunc bezt_ok, BeztEditFunc bezt_cb, FcuEditFunc fcu_cb, int filterflag)
190 {
191         Key *key= ob_get_key(ob);
192         
193         /* sanity check */
194         if (ob == NULL)
195                 return 0;
196         
197         /* firstly, Object's own AnimData */
198         if (ob->adt) 
199                 adt_keys_bezier_loop(bed, ob->adt, bezt_ok, bezt_cb, fcu_cb, filterflag);
200         
201         /* shapekeys */
202         if ((key && key->adt) && !(filterflag & ADS_FILTER_NOSHAPEKEYS))
203                 adt_keys_bezier_loop(bed, key->adt, bezt_ok, bezt_cb, fcu_cb, filterflag);
204                 
205         // FIXME: add materials, etc. (but drawing code doesn't do it yet too! :)
206         
207         return 0;
208 }
209
210 /* This function is used to loop over the keyframe data in a Scene */
211 static short scene_keys_bezier_loop(BeztEditData *bed, Scene *sce, BeztEditFunc bezt_ok, BeztEditFunc bezt_cb, FcuEditFunc fcu_cb, int filterflag)
212 {
213         World *wo= (sce) ? sce->world : NULL;
214         
215         /* sanity check */
216         if (sce == NULL)
217                 return 0;
218         
219         /* Scene's own animation */
220         if (sce->adt)
221                 adt_keys_bezier_loop(bed, sce->adt, bezt_ok, bezt_cb, fcu_cb, filterflag);
222         
223         /* World */
224         if (wo && wo->adt)
225                 adt_keys_bezier_loop(bed, wo->adt, bezt_ok, bezt_cb, fcu_cb, filterflag);
226         
227         return 0;
228 }
229
230 /* --- */
231
232 /* This function is used to apply operation to all keyframes, regardless of the type */
233 short ANIM_animchannel_keys_bezier_loop(BeztEditData *bed, bAnimListElem *ale, BeztEditFunc bezt_ok, BeztEditFunc bezt_cb, FcuEditFunc fcu_cb, int filterflag)
234 {
235         /* sanity checks */
236         if (ale == NULL)
237                 return 0;
238         
239         /* method to use depends on the type of keyframe data */
240         switch (ale->datatype) {
241                 /* direct keyframe data (these loops are exposed) */
242                 case ALE_FCURVE: /* F-Curve */
243                         return ANIM_fcurve_keys_bezier_loop(bed, ale->key_data, bezt_ok, bezt_cb, fcu_cb);
244                 
245                 /* indirect 'summaries' (these are not exposed directly) 
246                  * NOTE: must keep this code in sync with the drawing code and also the filtering code!
247                  */
248                 case ALE_GROUP: /* action group */
249                         return agrp_keys_bezier_loop(bed, (bActionGroup *)ale->data, bezt_ok, bezt_cb, fcu_cb);
250                 case ALE_ACT: /* action */
251                         return act_keys_bezier_loop(bed, (bAction *)ale->data, bezt_ok, bezt_cb, fcu_cb);
252                         
253                 case ALE_OB: /* object */
254                         return ob_keys_bezier_loop(bed, (Object *)ale->key_data, bezt_ok, bezt_cb, fcu_cb, filterflag);
255                 case ALE_SCE: /* scene */
256                         return scene_keys_bezier_loop(bed, (Scene *)ale->data, bezt_ok, bezt_cb, fcu_cb, filterflag);
257         }
258         
259         return 0;
260 }
261
262 /* This function is used to apply operation to all keyframes, regardless of the type without needed an AnimListElem wrapper */
263 short ANIM_animchanneldata_keys_bezier_loop(BeztEditData *bed, void *data, int keytype, BeztEditFunc bezt_ok, BeztEditFunc bezt_cb, FcuEditFunc fcu_cb, int filterflag)
264 {
265         /* sanity checks */
266         if (data == NULL)
267                 return 0;
268         
269         /* method to use depends on the type of keyframe data */
270         switch (keytype) {
271                 /* direct keyframe data (these loops are exposed) */
272                 case ALE_FCURVE: /* F-Curve */
273                         return ANIM_fcurve_keys_bezier_loop(bed, data, bezt_ok, bezt_cb, fcu_cb);
274                 
275                 /* indirect 'summaries' (these are not exposed directly) 
276                  * NOTE: must keep this code in sync with the drawing code and also the filtering code!
277                  */
278                 case ALE_GROUP: /* action group */
279                         return agrp_keys_bezier_loop(bed, (bActionGroup *)data, bezt_ok, bezt_cb, fcu_cb);
280                 case ALE_ACT: /* action */
281                         return act_keys_bezier_loop(bed, (bAction *)data, bezt_ok, bezt_cb, fcu_cb);
282                         
283                 case ALE_OB: /* object */
284                         return ob_keys_bezier_loop(bed, (Object *)data, bezt_ok, bezt_cb, fcu_cb, filterflag);
285                 case ALE_SCE: /* scene */
286                         return scene_keys_bezier_loop(bed, (Scene *)data, bezt_ok, bezt_cb, fcu_cb, filterflag);
287         }
288         
289         return 0;
290 }
291
292 /* ************************************************************************** */
293 /* Keyframe Integrity Tools */
294
295 /* Rearrange keyframes if some are out of order */
296 // used to be recalc_*_ipos() where * was object or action
297 void ANIM_editkeyframes_refresh(bAnimContext *ac)
298 {
299         ListBase anim_data = {NULL, NULL};
300         bAnimListElem *ale;
301         int filter;
302         
303         /* filter animation data */
304         filter= ANIMFILTER_CURVESONLY; 
305         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
306         
307         /* loop over ipo-curves that are likely to have been edited, and check them */
308         for (ale= anim_data.first; ale; ale= ale->next) {
309                 FCurve *fcu= ale->key_data;
310                 
311                 /* make sure keyframes in F-curve are all in order, and handles are in valid positions */
312                 sort_time_fcurve(fcu);
313                 testhandles_fcurve(fcu);
314         }
315         
316         /* free temp data */
317         BLI_freelistN(&anim_data);
318 }
319
320 /* ************************************************************************** */
321 /* BezTriple Validation Callbacks */
322
323 static short ok_bezier_frame(BeztEditData *bed, BezTriple *bezt)
324 {
325         /* frame is stored in f1 property (this float accuracy check may need to be dropped?) */
326         return IS_EQ(bezt->vec[1][0], bed->f1);
327 }
328
329 static short ok_bezier_framerange(BeztEditData *bed, BezTriple *bezt)
330 {
331         /* frame range is stored in float properties */
332         return ((bezt->vec[1][0] > bed->f1) && (bezt->vec[1][0] < bed->f2));
333 }
334
335 static short ok_bezier_selected(BeztEditData *bed, BezTriple *bezt)
336 {
337         /* this macro checks all beztriple handles for selection... */
338         return BEZSELECTED(bezt);
339 }
340
341 static short ok_bezier_value(BeztEditData *bed, BezTriple *bezt)
342 {
343         /* value is stored in f1 property 
344          *      - this float accuracy check may need to be dropped?
345          *      - should value be stored in f2 instead so that we won't have conflicts when using f1 for frames too?
346          */
347         return IS_EQ(bezt->vec[1][1], bed->f1);
348 }
349
350 static short ok_bezier_valuerange(BeztEditData *bed, BezTriple *bezt)
351 {
352         /* value range is stored in float properties */
353         return ((bezt->vec[1][1] > bed->f1) && (bezt->vec[1][1] < bed->f2));
354 }
355
356 static short ok_bezier_region(BeztEditData *bed, BezTriple *bezt)
357 {
358         /* rect is stored in data property (it's of type rectf, but may not be set) */
359         if (bed->data)
360                 return BLI_in_rctf(bed->data, bezt->vec[1][0], bezt->vec[1][1]);
361         else 
362                 return 0;
363 }
364
365
366 BeztEditFunc ANIM_editkeyframes_ok(short mode)
367 {
368         /* eEditKeyframes_Validate */
369         switch (mode) {
370                 case BEZT_OK_FRAME: /* only if bezt falls on the right frame (float) */
371                         return ok_bezier_frame;
372                 case BEZT_OK_FRAMERANGE: /* only if bezt falls within the specified frame range (floats) */
373                         return ok_bezier_framerange;
374                 case BEZT_OK_SELECTED:  /* only if bezt is selected (self) */
375                         return ok_bezier_selected;
376                 case BEZT_OK_VALUE: /* only if bezt value matches (float) */
377                         return ok_bezier_value;
378                 case BEZT_OK_VALUERANGE: /* only if bezier falls within the specified value range (floats) */
379                         return ok_bezier_valuerange;
380                 case BEZT_OK_REGION: /* only if bezier falls within the specified rect (data -> rectf) */
381                         return ok_bezier_region;
382                 default: /* nothing was ok */
383                         return NULL;
384         }
385 }
386
387 /* ******************************************* */
388 /* Assorted Utility Functions */
389
390 /* helper callback for <animeditor>_cfrasnap_exec() -> used to help get the average time of all selected beztriples */
391 short bezt_calc_average(BeztEditData *bed, BezTriple *bezt)
392 {
393         /* only if selected */
394         if (bezt->f2 & SELECT) {
395                 /* store average time in float (only do rounding at last step */
396                 bed->f1 += bezt->vec[1][0];
397                 
398                 /* increment number of items */
399                 bed->i1++;
400         }
401         
402         return 0;
403 }
404
405 /* helper callback for columnselect_<animeditor>_keys() -> populate list CfraElems with frame numbers from selected beztriples */
406 short bezt_to_cfraelem(BeztEditData *bed, BezTriple *bezt)
407 {
408         /* only if selected */
409         if (bezt->f2 & SELECT) {
410                 CfraElem *ce= MEM_callocN(sizeof(CfraElem), "cfraElem");
411                 BLI_addtail(&bed->list, ce);
412                 
413                 ce->cfra= bezt->vec[1][0];
414         }
415         
416         return 0;
417 }
418
419 /* ******************************************* */
420 /* Transform */
421
422 static short snap_bezier_nearest(BeztEditData *bed, BezTriple *bezt)
423 {
424         if (bezt->f2 & SELECT)
425                 bezt->vec[1][0]= (float)(floor(bezt->vec[1][0]+0.5));
426         return 0;
427 }
428
429 static short snap_bezier_nearestsec(BeztEditData *bed, BezTriple *bezt)
430 {
431         const Scene *scene= bed->scene;
432         const float secf = (float)FPS;
433         
434         if (bezt->f2 & SELECT)
435                 bezt->vec[1][0]= ((float)floor(bezt->vec[1][0]/secf + 0.5f) * secf);
436         return 0;
437 }
438
439 static short snap_bezier_cframe(BeztEditData *bed, BezTriple *bezt)
440 {
441         const Scene *scene= bed->scene;
442         if (bezt->f2 & SELECT)
443                 bezt->vec[1][0]= (float)CFRA;
444         return 0;
445 }
446
447 static short snap_bezier_nearmarker(BeztEditData *bed, BezTriple *bezt)
448 {
449         if (bezt->f2 & SELECT)
450                 bezt->vec[1][0]= (float)ED_markers_find_nearest_marker_time(&bed->list, bezt->vec[1][0]);
451         return 0;
452 }
453
454 static short snap_bezier_horizontal(BeztEditData *bed, BezTriple *bezt)
455 {
456         if (bezt->f2 & SELECT) {
457                 bezt->vec[0][1]= bezt->vec[2][1]= (float)floor(bezt->vec[1][1] + 0.5f);
458                 if ((bezt->h1==HD_AUTO) || (bezt->h1==HD_VECT)) bezt->h1= HD_ALIGN;
459                 if ((bezt->h2==HD_AUTO) || (bezt->h2==HD_VECT)) bezt->h2= HD_ALIGN;
460         }
461         return 0;       
462 }
463
464
465 BeztEditFunc ANIM_editkeyframes_snap(short type)
466 {
467         /* eEditKeyframes_Snap */
468         switch (type) {
469                 case SNAP_KEYS_NEARFRAME: /* snap to nearest frame */
470                         return snap_bezier_nearest;
471                 case SNAP_KEYS_CURFRAME: /* snap to current frame */
472                         return snap_bezier_cframe;
473                 case SNAP_KEYS_NEARMARKER: /* snap to nearest marker */
474                         return snap_bezier_nearmarker;
475                 case SNAP_KEYS_NEARSEC: /* snap to nearest second */
476                         return snap_bezier_nearestsec;
477                 case SNAP_KEYS_HORIZONTAL: /* snap handles to same value */
478                         return snap_bezier_horizontal;
479                 default: /* just in case */
480                         return snap_bezier_nearest;
481         }
482 }
483
484 /* --------- */
485
486 static short mirror_bezier_cframe(BeztEditData *bed, BezTriple *bezt)
487 {
488         const Scene *scene= bed->scene;
489         float diff;
490         
491         if (bezt->f2 & SELECT) {
492                 diff= ((float)CFRA - bezt->vec[1][0]);
493                 bezt->vec[1][0]= ((float)CFRA + diff);
494         }
495         
496         return 0;
497 }
498
499 static short mirror_bezier_yaxis(BeztEditData *bed, BezTriple *bezt)
500 {
501         float diff;
502         
503         if (bezt->f2 & SELECT) {
504                 diff= (0.0f - bezt->vec[1][0]);
505                 bezt->vec[1][0]= (0.0f + diff);
506         }
507         
508         return 0;
509 }
510
511 static short mirror_bezier_xaxis(BeztEditData *bed, BezTriple *bezt)
512 {
513         float diff;
514         
515         if (bezt->f2 & SELECT) {
516                 diff= (0.0f - bezt->vec[1][1]);
517                 bezt->vec[1][1]= (0.0f + diff);
518         }
519         
520         return 0;
521 }
522
523 static short mirror_bezier_marker(BeztEditData *bed, BezTriple *bezt)
524 {
525         /* mirroring time stored in f1 */
526         if (bezt->f2 & SELECT) {
527                 const float diff= (bed->f1 - bezt->vec[1][0]);
528                 bezt->vec[1][0]= (bed->f1 + diff);
529         }
530         
531         return 0;
532 }
533
534 /* Note: for markers case, need to set global vars (eww...) */
535 // calchandles_fcurve
536 BeztEditFunc ANIM_editkeyframes_mirror(short type)
537 {
538         switch (type) {
539                 case MIRROR_KEYS_CURFRAME: /* mirror over current frame */
540                         return mirror_bezier_cframe;
541                 case MIRROR_KEYS_YAXIS: /* mirror over frame 0 */
542                         return mirror_bezier_yaxis;
543                 case MIRROR_KEYS_XAXIS: /* mirror over value 0 */
544                         return mirror_bezier_xaxis;
545                 case MIRROR_KEYS_MARKER: /* mirror over marker */
546                         return mirror_bezier_marker; 
547                 default: /* just in case */
548                         return mirror_bezier_yaxis;
549                         break;
550         }
551 }
552
553 /* ******************************************* */
554 /* Settings */
555
556 /* Sets the selected bezier handles to type 'auto' */
557 static short set_bezier_auto(BeztEditData *bed, BezTriple *bezt) 
558 {
559         if((bezt->f1  & SELECT) || (bezt->f3 & SELECT)) {
560                 if (bezt->f1 & SELECT) bezt->h1= 1; /* the secret code for auto */
561                 if (bezt->f3 & SELECT) bezt->h2= 1;
562                 
563                 /* if the handles are not of the same type, set them
564                  * to type free
565                  */
566                 if (bezt->h1 != bezt->h2) {
567                         if ELEM(bezt->h1, HD_ALIGN, HD_AUTO) bezt->h1= HD_FREE;
568                         if ELEM(bezt->h2, HD_ALIGN, HD_AUTO) bezt->h2= HD_FREE;
569                 }
570         }
571         return 0;
572 }
573
574 /* Sets the selected bezier handles to type 'vector'  */
575 static short set_bezier_vector(BeztEditData *bed, BezTriple *bezt) 
576 {
577         if ((bezt->f1 & SELECT) || (bezt->f3 & SELECT)) {
578                 if (bezt->f1 & SELECT) bezt->h1= HD_VECT;
579                 if (bezt->f3 & SELECT) bezt->h2= HD_VECT;
580                 
581                 /* if the handles are not of the same type, set them
582                  * to type free
583                  */
584                 if (bezt->h1 != bezt->h2) {
585                         if ELEM(bezt->h1, HD_ALIGN, HD_AUTO) bezt->h1= HD_FREE;
586                         if ELEM(bezt->h2, HD_ALIGN, HD_AUTO) bezt->h2= HD_FREE;
587                 }
588         }
589         return 0;
590 }
591
592 /* Queries if the handle should be set to 'free' or 'align' */
593 static short bezier_isfree(BeztEditData *bed, BezTriple *bezt) 
594 {
595         if ((bezt->f1 & SELECT) && (bezt->h1)) return 1;
596         if ((bezt->f3 & SELECT) && (bezt->h2)) return 1;
597         return 0;
598 }
599
600 /* Sets selected bezier handles to type 'align' */
601 static short set_bezier_align(BeztEditData *bed, BezTriple *bezt) 
602 {       
603         if (bezt->f1 & SELECT) bezt->h1= HD_ALIGN;
604         if (bezt->f3 & SELECT) bezt->h2= HD_ALIGN;
605         return 0;
606 }
607
608 /* Sets selected bezier handles to type 'free'  */
609 static short set_bezier_free(BeztEditData *bed, BezTriple *bezt) 
610 {
611         if (bezt->f1 & SELECT) bezt->h1= HD_FREE;
612         if (bezt->f3 & SELECT) bezt->h2= HD_FREE;
613         return 0;
614 }
615
616 /* Set all Bezier Handles to a single type */
617 // calchandles_fcurve
618 BeztEditFunc ANIM_editkeyframes_handles(short code)
619 {
620         switch (code) {
621                 case HD_AUTO: /* auto */
622                         return set_bezier_auto;
623                 case HD_VECT: /* vector */
624                         return set_bezier_vector;
625                 case HD_FREE: /* free */
626                         return set_bezier_free;
627                 case HD_ALIGN: /* align */
628                         return set_bezier_align;
629                 
630                 default: /* free or align? */
631                         return bezier_isfree;
632         }
633 }
634
635 /* ------- */
636
637 static short set_bezt_constant(BeztEditData *bed, BezTriple *bezt) 
638 {
639         if (bezt->f2 & SELECT) 
640                 bezt->ipo= BEZT_IPO_CONST;
641         return 0;
642 }
643
644 static short set_bezt_linear(BeztEditData *bed, BezTriple *bezt) 
645 {
646         if (bezt->f2 & SELECT) 
647                 bezt->ipo= BEZT_IPO_LIN;
648         return 0;
649 }
650
651 static short set_bezt_bezier(BeztEditData *bed, BezTriple *bezt) 
652 {
653         if (bezt->f2 & SELECT) 
654                 bezt->ipo= BEZT_IPO_BEZ;
655         return 0;
656 }
657
658 /* Set the interpolation type of the selected BezTriples in each F-Curve to the specified one */
659 // ANIM_editkeyframes_ipocurve_ipotype() !
660 BeztEditFunc ANIM_editkeyframes_ipo(short code)
661 {
662         switch (code) {
663                 case BEZT_IPO_CONST: /* constant */
664                         return set_bezt_constant;
665                 case BEZT_IPO_LIN: /* linear */ 
666                         return set_bezt_linear;
667                 default: /* bezier */
668                         return set_bezt_bezier;
669         }
670 }
671
672 /* ------- */
673
674 static short set_keytype_keyframe(BeztEditData *bed, BezTriple *bezt) 
675 {
676         if (bezt->f2 & SELECT) 
677                 BEZKEYTYPE(bezt)= BEZT_KEYTYPE_KEYFRAME;
678         return 0;
679 }
680
681 static short set_keytype_breakdown(BeztEditData *bed, BezTriple *bezt) 
682 {
683         if (bezt->f2 & SELECT) 
684                 BEZKEYTYPE(bezt)= BEZT_KEYTYPE_BREAKDOWN;
685         return 0;
686 }
687
688 /* Set the interpolation type of the selected BezTriples in each F-Curve to the specified one */
689 BeztEditFunc ANIM_editkeyframes_keytype(short code)
690 {
691         switch (code) {
692                 case BEZT_KEYTYPE_BREAKDOWN: /* breakdown */
693                         return set_keytype_breakdown;
694                         
695                 case BEZT_KEYTYPE_KEYFRAME: /* proper keyframe */       
696                 default:
697                         return set_keytype_keyframe;
698         }
699 }
700
701 /* ******************************************* */
702 /* Selection */
703
704 static short select_bezier_add(BeztEditData *bed, BezTriple *bezt) 
705 {
706         /* Select the bezier triple */
707         BEZ_SEL(bezt);
708         return 0;
709 }
710
711 static short select_bezier_subtract(BeztEditData *bed, BezTriple *bezt) 
712 {
713         /* Deselect the bezier triple */
714         BEZ_DESEL(bezt);
715         return 0;
716 }
717
718 static short select_bezier_invert(BeztEditData *bed, BezTriple *bezt) 
719 {
720         /* Invert the selection for the bezier triple */
721         bezt->f2 ^= SELECT;
722         if (bezt->f2 & SELECT) {
723                 bezt->f1 |= SELECT;
724                 bezt->f3 |= SELECT;
725         }
726         else {
727                 bezt->f1 &= ~SELECT;
728                 bezt->f3 &= ~SELECT;
729         }
730         return 0;
731 }
732
733 // NULL
734 BeztEditFunc ANIM_editkeyframes_select(short selectmode)
735 {
736         switch (selectmode) {
737                 case SELECT_ADD: /* add */
738                         return select_bezier_add;
739                 case SELECT_SUBTRACT: /* subtract */
740                         return select_bezier_subtract;
741                 case SELECT_INVERT: /* invert */
742                         return select_bezier_invert;
743                 default: /* replace (need to clear all, then add) */
744                         return select_bezier_add;
745         }
746 }