Cleanup: style, use braces for editors
[blender.git] / source / blender / editors / animation / keyframes_edit.c
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2008 Blender Foundation
17  */
18
19 /** \file
20  * \ingroup edanimation
21  */
22
23 #include <stdlib.h>
24 #include <string.h>
25 #include <math.h>
26 #include <float.h>
27
28 #include "MEM_guardedalloc.h"
29
30 #include "BLI_blenlib.h"
31 #include "BLI_utildefines.h"
32 #include "BLI_lasso_2d.h"
33 #include "BLI_math.h"
34
35 #include "DNA_anim_types.h"
36 #include "DNA_object_types.h"
37 #include "DNA_scene_types.h"
38
39 #include "BKE_fcurve.h"
40 #include "BKE_nla.h"
41
42 #include "ED_anim_api.h"
43 #include "ED_keyframes_edit.h"
44 #include "ED_markers.h"
45
46 /* This file defines an API and set of callback-operators for
47  * non-destructive editing of keyframe data.
48  *
49  * Two API functions are defined for actually performing the operations on the data:
50  * ANIM_fcurve_keyframes_loop()
51  * which take the data they operate on, a few callbacks defining what operations to perform.
52  *
53  * As operators which work on keyframes usually apply the same operation on all BezTriples in
54  * every channel, the code has been optimized providing a set of functions which will get the
55  * appropriate bezier-modify function to set. These functions (ANIM_editkeyframes_*) will need
56  * to be called before getting any channels.
57  *
58  * A set of 'validation' callbacks are provided for checking if a BezTriple should be operated on.
59  * These should only be used when using a 'general' BezTriple editor (i.e. selection setters which
60  * don't check existing selection status).
61  *
62  * - Joshua Leung, Dec 2008
63  */
64
65 /* ************************************************************************** */
66 /* Keyframe Editing Loops - Exposed API */
67
68 /* --------------------------- Base Functions ------------------------------------ */
69
70 /* This function is used to loop over BezTriples in the given F-Curve, applying a given
71  * operation on them, and optionally applies an F-Curve validation function afterwards.
72  */
73 // TODO: make this function work on samples too...
74 short ANIM_fcurve_keyframes_loop(KeyframeEditData *ked,
75                                  FCurve *fcu,
76                                  KeyframeEditFunc key_ok,
77                                  KeyframeEditFunc key_cb,
78                                  FcuEditFunc fcu_cb)
79 {
80   BezTriple *bezt;
81   short ok = 0;
82   unsigned int i;
83
84   /* sanity check */
85   if (ELEM(NULL, fcu, fcu->bezt)) {
86     return 0;
87   }
88
89   /* set the F-Curve into the editdata so that it can be accessed */
90   if (ked) {
91     ked->fcu = fcu;
92     ked->curIndex = 0;
93     ked->curflags = ok;
94   }
95
96   /* if function to apply to bezier curves is set, then loop through executing it on beztriples */
97   if (key_cb) {
98     /* if there's a validation func, include that check in the loop
99      * (this is should be more efficient than checking for it in every loop)
100      */
101     if (key_ok) {
102       for (bezt = fcu->bezt, i = 0; i < fcu->totvert; bezt++, i++) {
103         if (ked) {
104           /* advance the index, and reset the ok flags (to not influence the result) */
105           ked->curIndex = i;
106           ked->curflags = 0;
107         }
108
109         /* Only operate on this BezTriple if it fulfills the criteria of the validation func */
110         if ((ok = key_ok(ked, bezt))) {
111           if (ked) {
112             ked->curflags = ok;
113           }
114
115           /* Exit with return-code '1' if function returns positive
116            * This is useful if finding if some BezTriple satisfies a condition.
117            */
118           if (key_cb(ked, bezt)) {
119             return 1;
120           }
121         }
122       }
123     }
124     else {
125       for (bezt = fcu->bezt, i = 0; i < fcu->totvert; bezt++, i++) {
126         if (ked) {
127           ked->curIndex = i;
128         }
129
130         /* Exit with return-code '1' if function returns positive
131          * This is useful if finding if some BezTriple satisfies a condition.
132          */
133         if (key_cb(ked, bezt)) {
134           return 1;
135         }
136       }
137     }
138   }
139
140   /* unset the F-Curve from the editdata now that it's done */
141   if (ked) {
142     ked->fcu = NULL;
143     ked->curIndex = 0;
144     ked->curflags = 0;
145   }
146
147   /* if fcu_cb (F-Curve post-editing callback) has been specified then execute it */
148   if (fcu_cb) {
149     fcu_cb(fcu);
150   }
151
152   /* done */
153   return 0;
154 }
155
156 /* --------------------- Further Abstracted (Not Exposed Directly) ----------------------------- */
157
158 /* This function is used to loop over the keyframe data in an Action Group */
159 static short agrp_keyframes_loop(KeyframeEditData *ked,
160                                  bActionGroup *agrp,
161                                  KeyframeEditFunc key_ok,
162                                  KeyframeEditFunc key_cb,
163                                  FcuEditFunc fcu_cb)
164 {
165   FCurve *fcu;
166
167   /* sanity check */
168   if (agrp == NULL) {
169     return 0;
170   }
171
172   /* only iterate over the F-Curves that are in this group */
173   for (fcu = agrp->channels.first; fcu && fcu->grp == agrp; fcu = fcu->next) {
174     if (ANIM_fcurve_keyframes_loop(ked, fcu, key_ok, key_cb, fcu_cb)) {
175       return 1;
176     }
177   }
178
179   return 0;
180 }
181
182 /* This function is used to loop over the keyframe data in an Action */
183 static short act_keyframes_loop(KeyframeEditData *ked,
184                                 bAction *act,
185                                 KeyframeEditFunc key_ok,
186                                 KeyframeEditFunc key_cb,
187                                 FcuEditFunc fcu_cb)
188 {
189   FCurve *fcu;
190
191   /* sanity check */
192   if (act == NULL) {
193     return 0;
194   }
195
196   /* just loop through all F-Curves */
197   for (fcu = act->curves.first; fcu; fcu = fcu->next) {
198     if (ANIM_fcurve_keyframes_loop(ked, fcu, key_ok, key_cb, fcu_cb)) {
199       return 1;
200     }
201   }
202
203   return 0;
204 }
205
206 /* This function is used to loop over the keyframe data in an Object */
207 static short ob_keyframes_loop(KeyframeEditData *ked,
208                                bDopeSheet *ads,
209                                Object *ob,
210                                KeyframeEditFunc key_ok,
211                                KeyframeEditFunc key_cb,
212                                FcuEditFunc fcu_cb)
213 {
214   bAnimContext ac = {NULL};
215   ListBase anim_data = {NULL, NULL};
216   bAnimListElem *ale;
217   int filter;
218   int ret = 0;
219
220   bAnimListElem dummychan = {NULL};
221   Base dummybase = {NULL};
222
223   if (ob == NULL) {
224     return 0;
225   }
226
227   /* create a dummy wrapper data to work with */
228   dummybase.object = ob;
229
230   dummychan.type = ANIMTYPE_OBJECT;
231   dummychan.data = &dummybase;
232   dummychan.id = &ob->id;
233   dummychan.adt = ob->adt;
234
235   ac.ads = ads;
236   ac.data = &dummychan;
237   ac.datatype = ANIMCONT_CHANNEL;
238
239   /* get F-Curves to take keyframes from */
240   filter = ANIMFILTER_DATA_VISIBLE;  // curves only
241   ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
242
243   /* loop through each F-Curve, applying the operation as required, but stopping on the first one */
244   for (ale = anim_data.first; ale; ale = ale->next) {
245     if (ANIM_fcurve_keyframes_loop(ked, (FCurve *)ale->data, key_ok, key_cb, fcu_cb)) {
246       ret = 1;
247       break;
248     }
249   }
250
251   ANIM_animdata_freelist(&anim_data);
252
253   /* return return code - defaults to zero if nothing happened */
254   return ret;
255 }
256
257 /* This function is used to loop over the keyframe data in a Scene */
258 static short scene_keyframes_loop(KeyframeEditData *ked,
259                                   bDopeSheet *ads,
260                                   Scene *sce,
261                                   KeyframeEditFunc key_ok,
262                                   KeyframeEditFunc key_cb,
263                                   FcuEditFunc fcu_cb)
264 {
265   bAnimContext ac = {NULL};
266   ListBase anim_data = {NULL, NULL};
267   bAnimListElem *ale;
268   int filter;
269   int ret = 0;
270
271   bAnimListElem dummychan = {NULL};
272
273   if (sce == NULL) {
274     return 0;
275   }
276
277   /* create a dummy wrapper data to work with */
278   dummychan.type = ANIMTYPE_SCENE;
279   dummychan.data = sce;
280   dummychan.id = &sce->id;
281   dummychan.adt = sce->adt;
282
283   ac.ads = ads;
284   ac.data = &dummychan;
285   ac.datatype = ANIMCONT_CHANNEL;
286
287   /* get F-Curves to take keyframes from */
288   filter = ANIMFILTER_DATA_VISIBLE;  // curves only
289   ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
290
291   /* loop through each F-Curve, applying the operation as required, but stopping on the first one */
292   for (ale = anim_data.first; ale; ale = ale->next) {
293     if (ANIM_fcurve_keyframes_loop(ked, (FCurve *)ale->data, key_ok, key_cb, fcu_cb)) {
294       ret = 1;
295       break;
296     }
297   }
298
299   ANIM_animdata_freelist(&anim_data);
300
301   /* return return code - defaults to zero if nothing happened */
302   return ret;
303 }
304
305 /* This function is used to loop over the keyframe data in a DopeSheet summary */
306 static short summary_keyframes_loop(KeyframeEditData *ked,
307                                     bAnimContext *ac,
308                                     KeyframeEditFunc key_ok,
309                                     KeyframeEditFunc key_cb,
310                                     FcuEditFunc fcu_cb)
311 {
312   ListBase anim_data = {NULL, NULL};
313   bAnimListElem *ale;
314   int filter, ret_code = 0;
315
316   /* sanity check */
317   if (ac == NULL) {
318     return 0;
319   }
320
321   /* get F-Curves to take keyframes from */
322   filter = ANIMFILTER_DATA_VISIBLE;
323   ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
324
325   /* loop through each F-Curve, working on the keyframes until the first curve aborts */
326   for (ale = anim_data.first; ale; ale = ale->next) {
327     switch (ale->datatype) {
328       case ALE_MASKLAY:
329       case ALE_GPFRAME:
330         break;
331
332       case ALE_FCURVE:
333       default: {
334         if (ked && ked->iterflags) {
335           /* make backups of the current values, so that a localised fix
336            * (e.g. NLA time remapping) can be applied to these values
337            */
338           float f1 = ked->f1;
339           float f2 = ked->f2;
340
341           if (ked->iterflags & (KED_F1_NLA_UNMAP | KED_F2_NLA_UNMAP)) {
342             AnimData *adt = ANIM_nla_mapping_get(ac, ale);
343
344             if (ked->iterflags & KED_F1_NLA_UNMAP) {
345               ked->f1 = BKE_nla_tweakedit_remap(adt, f1, NLATIME_CONVERT_UNMAP);
346             }
347             if (ked->iterflags & KED_F2_NLA_UNMAP) {
348               ked->f2 = BKE_nla_tweakedit_remap(adt, f2, NLATIME_CONVERT_UNMAP);
349             }
350           }
351
352           /* now operate on the channel as per normal */
353           ret_code = ANIM_fcurve_keyframes_loop(ked, ale->data, key_ok, key_cb, fcu_cb);
354
355           /* reset */
356           ked->f1 = f1;
357           ked->f2 = f2;
358         }
359         else {
360           /* no special handling required... */
361           ret_code = ANIM_fcurve_keyframes_loop(ked, ale->data, key_ok, key_cb, fcu_cb);
362         }
363         break;
364       }
365     }
366
367     if (ret_code) {
368       break;
369     }
370   }
371
372   ANIM_animdata_freelist(&anim_data);
373
374   return ret_code;
375 }
376
377 /* --- */
378
379 /* This function is used to apply operation to all keyframes, regardless of the type */
380 short ANIM_animchannel_keyframes_loop(KeyframeEditData *ked,
381                                       bDopeSheet *ads,
382                                       bAnimListElem *ale,
383                                       KeyframeEditFunc key_ok,
384                                       KeyframeEditFunc key_cb,
385                                       FcuEditFunc fcu_cb)
386 {
387   /* sanity checks */
388   if (ale == NULL) {
389     return 0;
390   }
391
392   /* method to use depends on the type of keyframe data */
393   switch (ale->datatype) {
394     /* direct keyframe data (these loops are exposed) */
395     case ALE_FCURVE: /* F-Curve */
396       return ANIM_fcurve_keyframes_loop(ked, ale->key_data, key_ok, key_cb, fcu_cb);
397
398     /* indirect 'summaries' (these are not exposed directly)
399      * NOTE: must keep this code in sync with the drawing code and also the filtering code!
400      */
401     case ALE_GROUP: /* action group */
402       return agrp_keyframes_loop(ked, (bActionGroup *)ale->data, key_ok, key_cb, fcu_cb);
403     case ALE_ACT: /* action */
404       return act_keyframes_loop(ked, (bAction *)ale->key_data, key_ok, key_cb, fcu_cb);
405
406     case ALE_OB: /* object */
407       return ob_keyframes_loop(ked, ads, (Object *)ale->key_data, key_ok, key_cb, fcu_cb);
408     case ALE_SCE: /* scene */
409       return scene_keyframes_loop(ked, ads, (Scene *)ale->data, key_ok, key_cb, fcu_cb);
410     case ALE_ALL: /* 'all' (DopeSheet summary) */
411       return summary_keyframes_loop(ked, (bAnimContext *)ale->data, key_ok, key_cb, fcu_cb);
412   }
413
414   return 0;
415 }
416
417 /* This function is used to apply operation to all keyframes,
418  * regardless of the type without needed an AnimListElem wrapper */
419 short ANIM_animchanneldata_keyframes_loop(KeyframeEditData *ked,
420                                           bDopeSheet *ads,
421                                           void *data,
422                                           int keytype,
423                                           KeyframeEditFunc key_ok,
424                                           KeyframeEditFunc key_cb,
425                                           FcuEditFunc fcu_cb)
426 {
427   /* sanity checks */
428   if (data == NULL) {
429     return 0;
430   }
431
432   /* method to use depends on the type of keyframe data */
433   switch (keytype) {
434     /* direct keyframe data (these loops are exposed) */
435     case ALE_FCURVE: /* F-Curve */
436       return ANIM_fcurve_keyframes_loop(ked, data, key_ok, key_cb, fcu_cb);
437
438     /* indirect 'summaries' (these are not exposed directly)
439      * NOTE: must keep this code in sync with the drawing code and also the filtering code!
440      */
441     case ALE_GROUP: /* action group */
442       return agrp_keyframes_loop(ked, (bActionGroup *)data, key_ok, key_cb, fcu_cb);
443     case ALE_ACT: /* action */
444       return act_keyframes_loop(ked, (bAction *)data, key_ok, key_cb, fcu_cb);
445
446     case ALE_OB: /* object */
447       return ob_keyframes_loop(ked, ads, (Object *)data, key_ok, key_cb, fcu_cb);
448     case ALE_SCE: /* scene */
449       return scene_keyframes_loop(ked, ads, (Scene *)data, key_ok, key_cb, fcu_cb);
450     case ALE_ALL: /* 'all' (DopeSheet summary) */
451       return summary_keyframes_loop(ked, (bAnimContext *)data, key_ok, key_cb, fcu_cb);
452   }
453
454   return 0;
455 }
456
457 /* ************************************************************************** */
458 /* Keyframe Integrity Tools */
459
460 /* Rearrange keyframes if some are out of order */
461 // used to be recalc_*_ipos() where * was object or action
462 void ANIM_editkeyframes_refresh(bAnimContext *ac)
463 {
464   ListBase anim_data = {NULL, NULL};
465   bAnimListElem *ale;
466   int filter;
467
468   /* filter animation data */
469   filter = ANIMFILTER_DATA_VISIBLE;
470   ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
471
472   /* Loop over F-Curves that are likely to have been edited, and tag them to
473    * ensure the keyframes are in order and handles are in a valid position. */
474   for (ale = anim_data.first; ale; ale = ale->next) {
475     ale->update |= ANIM_UPDATE_DEPS | ANIM_UPDATE_HANDLES | ANIM_UPDATE_ORDER;
476   }
477
478   /* free temp data */
479   ANIM_animdata_update(ac, &anim_data);
480   ANIM_animdata_freelist(&anim_data);
481 }
482
483 /* ************************************************************************** */
484 /* BezTriple Validation Callbacks */
485
486 /* ------------------------ */
487 /* Some macros to make this easier... */
488
489 /* run the given check on the 3 handles:
490  * - Check should be a macro, which takes the handle index as its single arg,
491  *   which it substitutes later.
492  * - Requires that a var, of type short, is named 'ok',
493  *   and has been initialized to 0.
494  */
495 #define KEYFRAME_OK_CHECKS(check) \
496   { \
497     CHECK_TYPE(ok, short); \
498     if (check(1)) \
499       ok |= KEYFRAME_OK_KEY; \
500 \
501     if (ked && (ked->iterflags & KEYFRAME_ITER_INCL_HANDLES)) { \
502       if (check(0)) \
503         ok |= KEYFRAME_OK_H1; \
504       if (check(2)) \
505         ok |= KEYFRAME_OK_H2; \
506     } \
507   } \
508   (void)0
509
510 /* ------------------------ */
511
512 static short ok_bezier_frame(KeyframeEditData *ked, BezTriple *bezt)
513 {
514   short ok = 0;
515
516   /* frame is stored in f1 property (this float accuracy check may need to be dropped?) */
517 #define KEY_CHECK_OK(_index) IS_EQF(bezt->vec[_index][0], ked->f1)
518   KEYFRAME_OK_CHECKS(KEY_CHECK_OK);
519 #undef KEY_CHECK_OK
520
521   /* return ok flags */
522   return ok;
523 }
524
525 static short ok_bezier_framerange(KeyframeEditData *ked, BezTriple *bezt)
526 {
527   short ok = 0;
528
529   /* frame range is stored in float properties */
530 #define KEY_CHECK_OK(_index) ((bezt->vec[_index][0] > ked->f1) && (bezt->vec[_index][0] < ked->f2))
531   KEYFRAME_OK_CHECKS(KEY_CHECK_OK);
532 #undef KEY_CHECK_OK
533
534   /* return ok flags */
535   return ok;
536 }
537
538 static short ok_bezier_selected(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
539 {
540   /* this macro checks all beztriple handles for selection...
541    * only one of the verts has to be selected for this to be ok...
542    */
543   if (BEZT_ISSEL_ANY(bezt)) {
544     return KEYFRAME_OK_ALL;
545   }
546   else {
547     return 0;
548   }
549 }
550
551 static short ok_bezier_value(KeyframeEditData *ked, BezTriple *bezt)
552 {
553   short ok = 0;
554
555   /* Value is stored in f1 property:
556    * - This float accuracy check may need to be dropped?
557    * - Should value be stored in f2 instead
558    *   so that we won't have conflicts when using f1 for frames too?
559    */
560 #define KEY_CHECK_OK(_index) IS_EQF(bezt->vec[_index][1], ked->f1)
561   KEYFRAME_OK_CHECKS(KEY_CHECK_OK);
562 #undef KEY_CHECK_OK
563
564   /* return ok flags */
565   return ok;
566 }
567
568 static short ok_bezier_valuerange(KeyframeEditData *ked, BezTriple *bezt)
569 {
570   short ok = 0;
571
572   /* value range is stored in float properties */
573 #define KEY_CHECK_OK(_index) ((bezt->vec[_index][1] > ked->f1) && (bezt->vec[_index][1] < ked->f2))
574   KEYFRAME_OK_CHECKS(KEY_CHECK_OK);
575 #undef KEY_CHECK_OK
576
577   /* return ok flags */
578   return ok;
579 }
580
581 static short ok_bezier_region(KeyframeEditData *ked, BezTriple *bezt)
582 {
583   /* rect is stored in data property (it's of type rectf, but may not be set) */
584   if (ked->data) {
585     short ok = 0;
586
587 #define KEY_CHECK_OK(_index) BLI_rctf_isect_pt_v(ked->data, bezt->vec[_index])
588     KEYFRAME_OK_CHECKS(KEY_CHECK_OK);
589 #undef KEY_CHECK_OK
590
591     /* return ok flags */
592     return ok;
593   }
594   else {
595     return 0;
596   }
597 }
598
599 /**
600  * Called from #ok_bezier_region_lasso and #ok_bezier_channel_lasso
601  */
602 bool keyframe_region_lasso_test(const KeyframeEdit_LassoData *data_lasso, const float xy[2])
603 {
604   if (BLI_rctf_isect_pt_v(data_lasso->rectf_scaled, xy)) {
605     float xy_view[2];
606
607     BLI_rctf_transform_pt_v(data_lasso->rectf_view, data_lasso->rectf_scaled, xy_view, xy);
608
609     if (BLI_lasso_is_point_inside(
610             data_lasso->mcords, data_lasso->mcords_tot, xy_view[0], xy_view[1], INT_MAX)) {
611       return true;
612     }
613   }
614
615   return false;
616 }
617
618 static short ok_bezier_region_lasso(KeyframeEditData *ked, BezTriple *bezt)
619 {
620   /* check for lasso customdata (KeyframeEdit_LassoData) */
621   if (ked->data) {
622     short ok = 0;
623
624 #define KEY_CHECK_OK(_index) keyframe_region_lasso_test(ked->data, bezt->vec[_index])
625     KEYFRAME_OK_CHECKS(KEY_CHECK_OK);
626 #undef KEY_CHECK_OK
627
628     /* return ok flags */
629     return ok;
630   }
631   else {
632     return 0;
633   }
634 }
635
636 static short ok_bezier_channel_lasso(KeyframeEditData *ked, BezTriple *bezt)
637 {
638   /* check for lasso customdata (KeyframeEdit_LassoData) */
639   if (ked->data) {
640     KeyframeEdit_LassoData *data = ked->data;
641     float pt[2];
642
643     /* late-binding remap of the x values (for summary channels) */
644     /* XXX: Ideally we reset, but it should be fine just leaving it as-is
645      * as the next channel will reset it properly, while the next summary-channel
646      * curve will also reset by itself...
647      */
648     if (ked->iterflags & (KED_F1_NLA_UNMAP | KED_F2_NLA_UNMAP)) {
649       data->rectf_scaled->xmin = ked->f1;
650       data->rectf_scaled->xmax = ked->f2;
651     }
652
653     /* only use the x-coordinate of the point; the y is the channel range... */
654     pt[0] = bezt->vec[1][0];
655     pt[1] = ked->channel_y;
656
657     if (keyframe_region_lasso_test(data, pt)) {
658       return KEYFRAME_OK_KEY;
659     }
660   }
661   return 0;
662 }
663
664 /**
665  * Called from #ok_bezier_region_circle and #ok_bezier_channel_circle
666  */
667 bool keyframe_region_circle_test(const KeyframeEdit_CircleData *data_circle, const float xy[2])
668 {
669   if (BLI_rctf_isect_pt_v(data_circle->rectf_scaled, xy)) {
670     float xy_view[2];
671
672     BLI_rctf_transform_pt_v(data_circle->rectf_view, data_circle->rectf_scaled, xy_view, xy);
673
674     xy_view[0] = xy_view[0] - data_circle->mval[0];
675     xy_view[1] = xy_view[1] - data_circle->mval[1];
676     return len_squared_v2(xy_view) < data_circle->radius_squared;
677   }
678
679   return false;
680 }
681
682 static short ok_bezier_region_circle(KeyframeEditData *ked, BezTriple *bezt)
683 {
684   /* check for circle select customdata (KeyframeEdit_CircleData) */
685   if (ked->data) {
686     short ok = 0;
687
688 #define KEY_CHECK_OK(_index) keyframe_region_circle_test(ked->data, bezt->vec[_index])
689     KEYFRAME_OK_CHECKS(KEY_CHECK_OK);
690 #undef KEY_CHECK_OK
691
692     /* return ok flags */
693     return ok;
694   }
695   else {
696     return 0;
697   }
698 }
699
700 static short ok_bezier_channel_circle(KeyframeEditData *ked, BezTriple *bezt)
701 {
702   /* check for circle select customdata (KeyframeEdit_CircleData) */
703   if (ked->data) {
704     KeyframeEdit_CircleData *data = ked->data;
705     float pt[2];
706
707     /* late-binding remap of the x values (for summary channels) */
708     /* XXX: Ideally we reset, but it should be fine just leaving it as-is
709      * as the next channel will reset it properly, while the next summary-channel
710      * curve will also reset by itself...
711      */
712     if (ked->iterflags & (KED_F1_NLA_UNMAP | KED_F2_NLA_UNMAP)) {
713       data->rectf_scaled->xmin = ked->f1;
714       data->rectf_scaled->xmax = ked->f2;
715     }
716
717     /* only use the x-coordinate of the point; the y is the channel range... */
718     pt[0] = bezt->vec[1][0];
719     pt[1] = ked->channel_y;
720
721     if (keyframe_region_circle_test(data, pt)) {
722       return KEYFRAME_OK_KEY;
723     }
724   }
725   return 0;
726 }
727
728 KeyframeEditFunc ANIM_editkeyframes_ok(short mode)
729 {
730   /* eEditKeyframes_Validate */
731   switch (mode) {
732     case BEZT_OK_FRAME:
733       /* only if bezt falls on the right frame (float) */
734       return ok_bezier_frame;
735     case BEZT_OK_FRAMERANGE:
736       /* only if bezt falls within the specified frame range (floats) */
737       return ok_bezier_framerange;
738     case BEZT_OK_SELECTED:
739       /* only if bezt is selected (self) */
740       return ok_bezier_selected;
741     case BEZT_OK_VALUE:
742       /* only if bezt value matches (float) */
743       return ok_bezier_value;
744     case BEZT_OK_VALUERANGE:
745       /* only if bezier falls within the specified value range (floats) */
746       return ok_bezier_valuerange;
747     case BEZT_OK_REGION:
748       /* only if bezier falls within the specified rect (data -> rectf) */
749       return ok_bezier_region;
750     case BEZT_OK_REGION_LASSO:
751       /* only if the point falls within KeyframeEdit_LassoData defined data */
752       return ok_bezier_region_lasso;
753     case BEZT_OK_REGION_CIRCLE:
754       /* only if the point falls within KeyframeEdit_CircleData defined data */
755       return ok_bezier_region_circle;
756     case BEZT_OK_CHANNEL_LASSO:
757       /* same as BEZT_OK_REGION_LASSO, but we're only using the x-value of the points */
758       return ok_bezier_channel_lasso;
759     case BEZT_OK_CHANNEL_CIRCLE:
760       /* same as BEZT_OK_REGION_CIRCLE, but we're only using the x-value of the points */
761       return ok_bezier_channel_circle;
762     default: /* nothing was ok */
763       return NULL;
764   }
765 }
766
767 /* ******************************************* */
768 /* Assorted Utility Functions */
769
770 /**
771  * Helper callback for <animeditor>_cfrasnap_exec() ->
772  * used to help get the average time of all selected beztriples
773  */
774 short bezt_calc_average(KeyframeEditData *ked, BezTriple *bezt)
775 {
776   /* only if selected */
777   if (bezt->f2 & SELECT) {
778     /* store average time in float 1 (only do rounding at last step) */
779     ked->f1 += bezt->vec[1][0];
780
781     /* store average value in float 2 (only do rounding at last step)
782      * - this isn't always needed, but some operators may also require this
783      */
784     ked->f2 += bezt->vec[1][1];
785
786     /* increment number of items */
787     ked->i1++;
788   }
789
790   return 0;
791 }
792
793 /* helper callback for columnselect_<animeditor>_keys() -> populate
794  * list CfraElems with frame numbers from selected beztriples */
795 short bezt_to_cfraelem(KeyframeEditData *ked, BezTriple *bezt)
796 {
797   /* only if selected */
798   if (bezt->f2 & SELECT) {
799     CfraElem *ce = MEM_callocN(sizeof(CfraElem), "cfraElem");
800     BLI_addtail(&ked->list, ce);
801
802     ce->cfra = bezt->vec[1][0];
803   }
804
805   return 0;
806 }
807
808 /* used to remap times from one range to another
809  * requires:  ked->data = KeyframeEditCD_Remap
810  */
811 void bezt_remap_times(KeyframeEditData *ked, BezTriple *bezt)
812 {
813   KeyframeEditCD_Remap *rmap = (KeyframeEditCD_Remap *)ked->data;
814   const float scale = (rmap->newMax - rmap->newMin) / (rmap->oldMax - rmap->oldMin);
815
816   /* perform transform on all three handles unless indicated otherwise */
817   // TODO: need to include some checks for that
818
819   bezt->vec[0][0] = scale * (bezt->vec[0][0] - rmap->oldMin) + rmap->newMin;
820   bezt->vec[1][0] = scale * (bezt->vec[1][0] - rmap->oldMin) + rmap->newMin;
821   bezt->vec[2][0] = scale * (bezt->vec[2][0] - rmap->oldMin) + rmap->newMin;
822 }
823
824 /* ******************************************* */
825 /* Transform */
826
827 /* snaps the keyframe to the nearest frame */
828 static short snap_bezier_nearest(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
829 {
830   if (bezt->f2 & SELECT) {
831     bezt->vec[1][0] = (float)(floorf(bezt->vec[1][0] + 0.5f));
832   }
833   return 0;
834 }
835
836 /* snaps the keyframe to the nearest second */
837 static short snap_bezier_nearestsec(KeyframeEditData *ked, BezTriple *bezt)
838 {
839   const Scene *scene = ked->scene;
840   const float secf = (float)FPS;
841
842   if (bezt->f2 & SELECT) {
843     bezt->vec[1][0] = (floorf(bezt->vec[1][0] / secf + 0.5f) * secf);
844   }
845   return 0;
846 }
847
848 /* snaps the keyframe to the current frame */
849 static short snap_bezier_cframe(KeyframeEditData *ked, BezTriple *bezt)
850 {
851   const Scene *scene = ked->scene;
852   if (bezt->f2 & SELECT) {
853     bezt->vec[1][0] = (float)CFRA;
854   }
855   return 0;
856 }
857
858 /* snaps the keyframe time to the nearest marker's frame */
859 static short snap_bezier_nearmarker(KeyframeEditData *ked, BezTriple *bezt)
860 {
861   if (bezt->f2 & SELECT) {
862     bezt->vec[1][0] = (float)ED_markers_find_nearest_marker_time(&ked->list, bezt->vec[1][0]);
863   }
864   return 0;
865 }
866
867 /* make the handles have the same value as the key */
868 static short snap_bezier_horizontal(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
869 {
870   if (bezt->f2 & SELECT) {
871     bezt->vec[0][1] = bezt->vec[2][1] = bezt->vec[1][1];
872
873     if (ELEM(bezt->h1, HD_AUTO, HD_AUTO_ANIM, HD_VECT)) {
874       bezt->h1 = HD_ALIGN;
875     }
876     if (ELEM(bezt->h2, HD_AUTO, HD_AUTO_ANIM, HD_VECT)) {
877       bezt->h2 = HD_ALIGN;
878     }
879   }
880   return 0;
881 }
882
883 /* frame to snap to is stored in the custom data -> first float value slot */
884 static short snap_bezier_time(KeyframeEditData *ked, BezTriple *bezt)
885 {
886   if (bezt->f2 & SELECT) {
887     bezt->vec[1][0] = ked->f1;
888   }
889   return 0;
890 }
891
892 /* value to snap to is stored in the custom data -> first float value slot */
893 static short snap_bezier_value(KeyframeEditData *ked, BezTriple *bezt)
894 {
895   if (bezt->f2 & SELECT) {
896     bezt->vec[1][1] = ked->f1;
897   }
898   return 0;
899 }
900
901 KeyframeEditFunc ANIM_editkeyframes_snap(short type)
902 {
903   /* eEditKeyframes_Snap */
904   switch (type) {
905     case SNAP_KEYS_NEARFRAME: /* snap to nearest frame */
906       return snap_bezier_nearest;
907     case SNAP_KEYS_CURFRAME: /* snap to current frame */
908       return snap_bezier_cframe;
909     case SNAP_KEYS_NEARMARKER: /* snap to nearest marker */
910       return snap_bezier_nearmarker;
911     case SNAP_KEYS_NEARSEC: /* snap to nearest second */
912       return snap_bezier_nearestsec;
913     case SNAP_KEYS_HORIZONTAL: /* snap handles to same value */
914       return snap_bezier_horizontal;
915     case SNAP_KEYS_TIME: /* snap to given frame/time */
916       return snap_bezier_time;
917     case SNAP_KEYS_VALUE: /* snap to given value */
918       return snap_bezier_value;
919     default: /* just in case */
920       return snap_bezier_nearest;
921   }
922 }
923
924 /* --------- */
925
926 static void mirror_bezier_xaxis_ex(BezTriple *bezt, const float center)
927 {
928   float diff;
929   int i;
930
931   for (i = 0; i < 3; i++) {
932     diff = (center - bezt->vec[i][0]);
933     bezt->vec[i][0] = (center + diff);
934   }
935   swap_v3_v3(bezt->vec[0], bezt->vec[2]);
936
937   SWAP(char, bezt->h1, bezt->h2);
938   SWAP(char, bezt->f1, bezt->f3);
939 }
940
941 static void mirror_bezier_yaxis_ex(BezTriple *bezt, const float center)
942 {
943   float diff;
944   int i;
945
946   for (i = 0; i < 3; i++) {
947     diff = (center - bezt->vec[i][1]);
948     bezt->vec[i][1] = (center + diff);
949   }
950 }
951
952 static short mirror_bezier_cframe(KeyframeEditData *ked, BezTriple *bezt)
953 {
954   const Scene *scene = ked->scene;
955
956   if (bezt->f2 & SELECT) {
957     mirror_bezier_xaxis_ex(bezt, CFRA);
958   }
959
960   return 0;
961 }
962
963 static short mirror_bezier_yaxis(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
964 {
965   if (bezt->f2 & SELECT) {
966     /* Yes, names are inverted, we are mirroring across y axis, hence along x axis... */
967     mirror_bezier_xaxis_ex(bezt, 0.0f);
968   }
969
970   return 0;
971 }
972
973 static short mirror_bezier_xaxis(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
974 {
975   if (bezt->f2 & SELECT) {
976     /* Yes, names are inverted, we are mirroring across x axis, hence along y axis... */
977     mirror_bezier_yaxis_ex(bezt, 0.0f);
978   }
979
980   return 0;
981 }
982
983 static short mirror_bezier_marker(KeyframeEditData *ked, BezTriple *bezt)
984 {
985   /* mirroring time stored in f1 */
986   if (bezt->f2 & SELECT) {
987     mirror_bezier_xaxis_ex(bezt, ked->f1);
988   }
989
990   return 0;
991 }
992
993 static short mirror_bezier_time(KeyframeEditData *ked, BezTriple *bezt)
994 {
995   /* value to mirror over is stored in f1 */
996   if (bezt->f2 & SELECT) {
997     mirror_bezier_xaxis_ex(bezt, ked->f1);
998   }
999
1000   return 0;
1001 }
1002
1003 static short mirror_bezier_value(KeyframeEditData *ked, BezTriple *bezt)
1004 {
1005   /* value to mirror over is stored in the custom data -> first float value slot */
1006   if (bezt->f2 & SELECT) {
1007     mirror_bezier_yaxis_ex(bezt, ked->f1);
1008   }
1009
1010   return 0;
1011 }
1012
1013 /* Note: for markers and 'value', the values to use must be supplied as the first float value */
1014 // calchandles_fcurve
1015 KeyframeEditFunc ANIM_editkeyframes_mirror(short type)
1016 {
1017   switch (type) {
1018     case MIRROR_KEYS_CURFRAME: /* mirror over current frame */
1019       return mirror_bezier_cframe;
1020     case MIRROR_KEYS_YAXIS: /* mirror over frame 0 */
1021       return mirror_bezier_yaxis;
1022     case MIRROR_KEYS_XAXIS: /* mirror over value 0 */
1023       return mirror_bezier_xaxis;
1024     case MIRROR_KEYS_MARKER: /* mirror over marker */
1025       return mirror_bezier_marker;
1026     case MIRROR_KEYS_TIME: /* mirror over frame/time */
1027       return mirror_bezier_time;
1028     case MIRROR_KEYS_VALUE: /* mirror over given value */
1029       return mirror_bezier_value;
1030     default: /* just in case */
1031       return mirror_bezier_yaxis;
1032   }
1033 }
1034
1035 /* ******************************************* */
1036 /* Settings */
1037
1038 /**
1039  * Standard validation step for a few of these
1040  * (implemented as macro for inlining without fn-call overhead):
1041  * "if the handles are not of the same type, set them to type free".
1042  */
1043 #define ENSURE_HANDLES_MATCH(bezt) \
1044   if (bezt->h1 != bezt->h2) { \
1045     if (ELEM(bezt->h1, HD_ALIGN, HD_AUTO, HD_AUTO_ANIM)) \
1046       bezt->h1 = HD_FREE; \
1047     if (ELEM(bezt->h2, HD_ALIGN, HD_AUTO, HD_AUTO_ANIM)) \
1048       bezt->h2 = HD_FREE; \
1049   } \
1050   (void)0
1051
1052 /* Sets the selected bezier handles to type 'auto' */
1053 static short set_bezier_auto(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
1054 {
1055   if ((bezt->f1 & SELECT) || (bezt->f3 & SELECT)) {
1056     if (bezt->f1 & SELECT) {
1057       bezt->h1 = HD_AUTO;
1058     }
1059     if (bezt->f3 & SELECT) {
1060       bezt->h2 = HD_AUTO;
1061     }
1062
1063     ENSURE_HANDLES_MATCH(bezt);
1064   }
1065   return 0;
1066 }
1067
1068 /* Sets the selected bezier handles to type 'auto-clamped'
1069  * NOTE: this is like auto above, but they're handled a bit different
1070  */
1071 static short set_bezier_auto_clamped(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
1072 {
1073   if ((bezt->f1 & SELECT) || (bezt->f3 & SELECT)) {
1074     if (bezt->f1 & SELECT) {
1075       bezt->h1 = HD_AUTO_ANIM;
1076     }
1077     if (bezt->f3 & SELECT) {
1078       bezt->h2 = HD_AUTO_ANIM;
1079     }
1080
1081     ENSURE_HANDLES_MATCH(bezt);
1082   }
1083   return 0;
1084 }
1085
1086 /* Sets the selected bezier handles to type 'vector'  */
1087 static short set_bezier_vector(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
1088 {
1089   if (bezt->f1 & SELECT) {
1090     bezt->h1 = HD_VECT;
1091   }
1092   if (bezt->f3 & SELECT) {
1093     bezt->h2 = HD_VECT;
1094   }
1095   return 0;
1096 }
1097
1098 /* Queries if the handle should be set to 'free' or 'align' */
1099 // NOTE: this was used for the 'toggle free/align' option
1100 //      currently this isn't used, but may be restored later
1101 static short bezier_isfree(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
1102 {
1103   if ((bezt->f1 & SELECT) && (bezt->h1)) {
1104     return 1;
1105   }
1106   if ((bezt->f3 & SELECT) && (bezt->h2)) {
1107     return 1;
1108   }
1109   return 0;
1110 }
1111
1112 /* Sets selected bezier handles to type 'align' */
1113 static short set_bezier_align(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
1114 {
1115   if (bezt->f1 & SELECT) {
1116     bezt->h1 = HD_ALIGN;
1117   }
1118   if (bezt->f3 & SELECT) {
1119     bezt->h2 = HD_ALIGN;
1120   }
1121   return 0;
1122 }
1123
1124 /* Sets selected bezier handles to type 'free'  */
1125 static short set_bezier_free(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
1126 {
1127   if (bezt->f1 & SELECT) {
1128     bezt->h1 = HD_FREE;
1129   }
1130   if (bezt->f3 & SELECT) {
1131     bezt->h2 = HD_FREE;
1132   }
1133   return 0;
1134 }
1135
1136 /* Set all selected Bezier Handles to a single type */
1137 // calchandles_fcurve
1138 KeyframeEditFunc ANIM_editkeyframes_handles(short code)
1139 {
1140   switch (code) {
1141     case HD_AUTO: /* auto */
1142       return set_bezier_auto;
1143     case HD_AUTO_ANIM: /* auto clamped */
1144       return set_bezier_auto_clamped;
1145
1146     case HD_VECT: /* vector */
1147       return set_bezier_vector;
1148     case HD_FREE: /* free */
1149       return set_bezier_free;
1150     case HD_ALIGN: /* align */
1151       return set_bezier_align;
1152
1153     default: /* check for toggle free or align? */
1154       return bezier_isfree;
1155   }
1156 }
1157
1158 /* ------- */
1159
1160 static short set_bezt_constant(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
1161 {
1162   if (bezt->f2 & SELECT) {
1163     bezt->ipo = BEZT_IPO_CONST;
1164   }
1165   return 0;
1166 }
1167
1168 static short set_bezt_linear(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
1169 {
1170   if (bezt->f2 & SELECT) {
1171     bezt->ipo = BEZT_IPO_LIN;
1172   }
1173   return 0;
1174 }
1175
1176 static short set_bezt_bezier(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
1177 {
1178   if (bezt->f2 & SELECT) {
1179     bezt->ipo = BEZT_IPO_BEZ;
1180   }
1181   return 0;
1182 }
1183
1184 static short set_bezt_back(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
1185 {
1186   if (bezt->f2 & SELECT) {
1187     bezt->ipo = BEZT_IPO_BACK;
1188   }
1189   return 0;
1190 }
1191
1192 static short set_bezt_bounce(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
1193 {
1194   if (bezt->f2 & SELECT) {
1195     bezt->ipo = BEZT_IPO_BOUNCE;
1196   }
1197   return 0;
1198 }
1199
1200 static short set_bezt_circle(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
1201 {
1202   if (bezt->f2 & SELECT) {
1203     bezt->ipo = BEZT_IPO_CIRC;
1204   }
1205   return 0;
1206 }
1207
1208 static short set_bezt_cubic(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
1209 {
1210   if (bezt->f2 & SELECT) {
1211     bezt->ipo = BEZT_IPO_CUBIC;
1212   }
1213   return 0;
1214 }
1215
1216 static short set_bezt_elastic(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
1217 {
1218   if (bezt->f2 & SELECT) {
1219     bezt->ipo = BEZT_IPO_ELASTIC;
1220   }
1221   return 0;
1222 }
1223
1224 static short set_bezt_expo(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
1225 {
1226   if (bezt->f2 & SELECT) {
1227     bezt->ipo = BEZT_IPO_EXPO;
1228   }
1229   return 0;
1230 }
1231
1232 static short set_bezt_quad(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
1233 {
1234   if (bezt->f2 & SELECT) {
1235     bezt->ipo = BEZT_IPO_QUAD;
1236   }
1237   return 0;
1238 }
1239
1240 static short set_bezt_quart(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
1241 {
1242   if (bezt->f2 & SELECT) {
1243     bezt->ipo = BEZT_IPO_QUART;
1244   }
1245   return 0;
1246 }
1247
1248 static short set_bezt_quint(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
1249 {
1250   if (bezt->f2 & SELECT) {
1251     bezt->ipo = BEZT_IPO_QUINT;
1252   }
1253   return 0;
1254 }
1255
1256 static short set_bezt_sine(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
1257 {
1258   if (bezt->f2 & SELECT) {
1259     bezt->ipo = BEZT_IPO_SINE;
1260   }
1261   return 0;
1262 }
1263
1264 /* Set the interpolation type of the selected BezTriples in each F-Curve to the specified one */
1265 // ANIM_editkeyframes_ipocurve_ipotype() !
1266 KeyframeEditFunc ANIM_editkeyframes_ipo(short code)
1267 {
1268   switch (code) {
1269     /* interpolation */
1270     case BEZT_IPO_CONST: /* constant */
1271       return set_bezt_constant;
1272     case BEZT_IPO_LIN: /* linear */
1273       return set_bezt_linear;
1274
1275     /* easing */
1276     case BEZT_IPO_BACK:
1277       return set_bezt_back;
1278     case BEZT_IPO_BOUNCE:
1279       return set_bezt_bounce;
1280     case BEZT_IPO_CIRC:
1281       return set_bezt_circle;
1282     case BEZT_IPO_CUBIC:
1283       return set_bezt_cubic;
1284     case BEZT_IPO_ELASTIC:
1285       return set_bezt_elastic;
1286     case BEZT_IPO_EXPO:
1287       return set_bezt_expo;
1288     case BEZT_IPO_QUAD:
1289       return set_bezt_quad;
1290     case BEZT_IPO_QUART:
1291       return set_bezt_quart;
1292     case BEZT_IPO_QUINT:
1293       return set_bezt_quint;
1294     case BEZT_IPO_SINE:
1295       return set_bezt_sine;
1296
1297     default: /* bezier */
1298       return set_bezt_bezier;
1299   }
1300 }
1301
1302 /* ------- */
1303
1304 static short set_keytype_keyframe(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
1305 {
1306   if (bezt->f2 & SELECT) {
1307     BEZKEYTYPE(bezt) = BEZT_KEYTYPE_KEYFRAME;
1308   }
1309   return 0;
1310 }
1311
1312 static short set_keytype_breakdown(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
1313 {
1314   if (bezt->f2 & SELECT) {
1315     BEZKEYTYPE(bezt) = BEZT_KEYTYPE_BREAKDOWN;
1316   }
1317   return 0;
1318 }
1319
1320 static short set_keytype_extreme(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
1321 {
1322   if (bezt->f2 & SELECT) {
1323     BEZKEYTYPE(bezt) = BEZT_KEYTYPE_EXTREME;
1324   }
1325   return 0;
1326 }
1327
1328 static short set_keytype_jitter(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
1329 {
1330   if (bezt->f2 & SELECT) {
1331     BEZKEYTYPE(bezt) = BEZT_KEYTYPE_JITTER;
1332   }
1333   return 0;
1334 }
1335
1336 static short set_keytype_moving_hold(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
1337 {
1338   if (bezt->f2 & SELECT) {
1339     BEZKEYTYPE(bezt) = BEZT_KEYTYPE_MOVEHOLD;
1340   }
1341   return 0;
1342 }
1343
1344 /* Set the interpolation type of the selected BezTriples in each F-Curve to the specified one */
1345 KeyframeEditFunc ANIM_editkeyframes_keytype(short code)
1346 {
1347   switch (code) {
1348     case BEZT_KEYTYPE_BREAKDOWN: /* breakdown */
1349       return set_keytype_breakdown;
1350
1351     case BEZT_KEYTYPE_EXTREME: /* extreme keyframe */
1352       return set_keytype_extreme;
1353
1354     case BEZT_KEYTYPE_JITTER: /* jitter keyframe */
1355       return set_keytype_jitter;
1356
1357     case BEZT_KEYTYPE_MOVEHOLD: /* moving hold */
1358       return set_keytype_moving_hold;
1359
1360     case BEZT_KEYTYPE_KEYFRAME: /* proper keyframe */
1361     default:
1362       return set_keytype_keyframe;
1363   }
1364 }
1365
1366 /* ------- */
1367
1368 static short set_easingtype_easein(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
1369 {
1370   if (bezt->f2 & SELECT) {
1371     bezt->easing = BEZT_IPO_EASE_IN;
1372   }
1373   return 0;
1374 }
1375
1376 static short set_easingtype_easeout(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
1377 {
1378   if (bezt->f2 & SELECT) {
1379     bezt->easing = BEZT_IPO_EASE_OUT;
1380   }
1381   return 0;
1382 }
1383
1384 static short set_easingtype_easeinout(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
1385 {
1386   if (bezt->f2 & SELECT) {
1387     bezt->easing = BEZT_IPO_EASE_IN_OUT;
1388   }
1389   return 0;
1390 }
1391
1392 static short set_easingtype_easeauto(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
1393 {
1394   if (bezt->f2 & SELECT) {
1395     bezt->easing = BEZT_IPO_EASE_AUTO;
1396   }
1397   return 0;
1398 }
1399
1400 /* Set the easing type of the selected BezTriples in each F-Curve to the specified one */
1401 KeyframeEditFunc ANIM_editkeyframes_easing(short mode)
1402 {
1403   switch (mode) {
1404     case BEZT_IPO_EASE_IN: /* ease in */
1405       return set_easingtype_easein;
1406
1407     case BEZT_IPO_EASE_OUT: /* ease out */
1408       return set_easingtype_easeout;
1409
1410     case BEZT_IPO_EASE_IN_OUT: /* both */
1411       return set_easingtype_easeinout;
1412
1413     default: /* auto */
1414       return set_easingtype_easeauto;
1415   }
1416 }
1417
1418 /* ******************************************* */
1419 /* Selection */
1420
1421 static short select_bezier_add(KeyframeEditData *ked, BezTriple *bezt)
1422 {
1423   /* if we've got info on what to select, use it, otherwise select all */
1424   if ((ked) && (ked->iterflags & KEYFRAME_ITER_INCL_HANDLES)) {
1425     if (ked->curflags & KEYFRAME_OK_KEY) {
1426       bezt->f2 |= SELECT;
1427     }
1428     if (ked->curflags & KEYFRAME_OK_H1) {
1429       bezt->f1 |= SELECT;
1430     }
1431     if (ked->curflags & KEYFRAME_OK_H2) {
1432       bezt->f3 |= SELECT;
1433     }
1434   }
1435   else {
1436     BEZT_SEL_ALL(bezt);
1437   }
1438
1439   return 0;
1440 }
1441
1442 static short select_bezier_subtract(KeyframeEditData *ked, BezTriple *bezt)
1443 {
1444   /* if we've got info on what to deselect, use it, otherwise deselect all */
1445   if ((ked) && (ked->iterflags & KEYFRAME_ITER_INCL_HANDLES)) {
1446     if (ked->curflags & KEYFRAME_OK_KEY) {
1447       bezt->f2 &= ~SELECT;
1448     }
1449     if (ked->curflags & KEYFRAME_OK_H1) {
1450       bezt->f1 &= ~SELECT;
1451     }
1452     if (ked->curflags & KEYFRAME_OK_H2) {
1453       bezt->f3 &= ~SELECT;
1454     }
1455   }
1456   else {
1457     BEZT_DESEL_ALL(bezt);
1458   }
1459
1460   return 0;
1461 }
1462
1463 static short select_bezier_invert(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
1464 {
1465   /* Invert the selection for the whole bezier triple */
1466   bezt->f2 ^= SELECT;
1467   if (bezt->f2 & SELECT) {
1468     bezt->f1 |= SELECT;
1469     bezt->f3 |= SELECT;
1470   }
1471   else {
1472     bezt->f1 &= ~SELECT;
1473     bezt->f3 &= ~SELECT;
1474   }
1475   return 0;
1476 }
1477
1478 KeyframeEditFunc ANIM_editkeyframes_select(short selectmode)
1479 {
1480   switch (selectmode) {
1481     case SELECT_ADD: /* add */
1482       return select_bezier_add;
1483     case SELECT_SUBTRACT: /* subtract */
1484       return select_bezier_subtract;
1485     case SELECT_INVERT: /* invert */
1486       return select_bezier_invert;
1487     default: /* replace (need to clear all, then add) */
1488       return select_bezier_add;
1489   }
1490 }
1491
1492 /* ******************************************* */
1493 /* Selection Maps */
1494
1495 /* Selection maps are simply fancy names for char arrays that store on/off
1496  * info for whether the selection status. The main purpose for these is to
1497  * allow extra info to be tagged to the keyframes without influencing their
1498  * values or having to be removed later.
1499  */
1500
1501 /* ----------- */
1502
1503 static short selmap_build_bezier_more(KeyframeEditData *ked, BezTriple *bezt)
1504 {
1505   FCurve *fcu = ked->fcu;
1506   char *map = ked->data;
1507   int i = ked->curIndex;
1508
1509   /* if current is selected, just make sure it stays this way */
1510   if (BEZT_ISSEL_ANY(bezt)) {
1511     map[i] = 1;
1512     return 0;
1513   }
1514
1515   /* if previous is selected, that means that selection should extend across */
1516   if (i > 0) {
1517     BezTriple *prev = bezt - 1;
1518
1519     if (BEZT_ISSEL_ANY(prev)) {
1520       map[i] = 1;
1521       return 0;
1522     }
1523   }
1524
1525   /* if next is selected, that means that selection should extend across */
1526   if (i < (fcu->totvert - 1)) {
1527     BezTriple *next = bezt + 1;
1528
1529     if (BEZT_ISSEL_ANY(next)) {
1530       map[i] = 1;
1531       return 0;
1532     }
1533   }
1534
1535   return 0;
1536 }
1537
1538 static short selmap_build_bezier_less(KeyframeEditData *ked, BezTriple *bezt)
1539 {
1540   FCurve *fcu = ked->fcu;
1541   char *map = ked->data;
1542   int i = ked->curIndex;
1543
1544   /* if current is selected, check the left/right keyframes
1545    * since it might need to be deselected (but otherwise no)
1546    */
1547   if (BEZT_ISSEL_ANY(bezt)) {
1548     /* if previous is not selected, we're on the tip of an iceberg */
1549     if (i > 0) {
1550       BezTriple *prev = bezt - 1;
1551
1552       if (BEZT_ISSEL_ANY(prev) == 0) {
1553         return 0;
1554       }
1555     }
1556     else if (i == 0) {
1557       /* current keyframe is selected at an endpoint, so should get deselected */
1558       return 0;
1559     }
1560
1561     /* if next is not selected, we're on the tip of an iceberg */
1562     if (i < (fcu->totvert - 1)) {
1563       BezTriple *next = bezt + 1;
1564
1565       if (BEZT_ISSEL_ANY(next) == 0) {
1566         return 0;
1567       }
1568     }
1569     else if (i == (fcu->totvert - 1)) {
1570       /* current keyframe is selected at an endpoint, so should get deselected */
1571       return 0;
1572     }
1573
1574     /* if we're still here, that means that keyframe should remain untouched */
1575     map[i] = 1;
1576   }
1577
1578   return 0;
1579 }
1580
1581 /* Get callback for building selection map */
1582 KeyframeEditFunc ANIM_editkeyframes_buildselmap(short mode)
1583 {
1584   switch (mode) {
1585     case SELMAP_LESS: /* less */
1586       return selmap_build_bezier_less;
1587
1588     case SELMAP_MORE: /* more */
1589     default:
1590       return selmap_build_bezier_more;
1591   }
1592 }
1593
1594 /* ----------- */
1595
1596 /* flush selection map values to the given beztriple */
1597 short bezt_selmap_flush(KeyframeEditData *ked, BezTriple *bezt)
1598 {
1599   const char *map = ked->data;
1600   short on = map[ked->curIndex];
1601
1602   /* select or deselect based on whether the map allows it or not */
1603   if (on) {
1604     BEZT_SEL_ALL(bezt);
1605   }
1606   else {
1607     BEZT_DESEL_ALL(bezt);
1608   }
1609
1610   return 0;
1611 }