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