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