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