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