Cleanup: remove redundant, invalid info from headers
[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 blender/editors/animation/keyframes_edit.c
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 check them */
415         for (ale = anim_data.first; ale; ale = ale->next) {
416                 FCurve *fcu = ale->key_data;
417
418                 /* make sure keyframes in F-Curve are all in order, and handles are in valid positions */
419                 sort_time_fcurve(fcu);
420                 calchandles_fcurve(fcu);
421         }
422
423         /* free temp data */
424         ANIM_animdata_freelist(&anim_data);
425 }
426
427 /* ************************************************************************** */
428 /* BezTriple Validation Callbacks */
429
430 /* ------------------------ */
431 /* Some macros to make this easier... */
432
433 /* run the given check on the 3 handles
434  * - check should be a macro, which takes the handle index as its single arg, which it substitutes later
435  * - requires that a var, of type short, is named 'ok', and has been initialized to 0
436  */
437 #define KEYFRAME_OK_CHECKS(check) \
438         { \
439                 CHECK_TYPE(ok, short); \
440                 if (check(1)) \
441                         ok |= KEYFRAME_OK_KEY; \
442                  \
443                 if (ked && (ked->iterflags & KEYFRAME_ITER_INCL_HANDLES)) { \
444                         if (check(0)) \
445                                 ok |= KEYFRAME_OK_H1; \
446                         if (check(2)) \
447                                 ok |= KEYFRAME_OK_H2; \
448                 } \
449         } (void)0
450
451 /* ------------------------ */
452
453 static short ok_bezier_frame(KeyframeEditData *ked, BezTriple *bezt)
454 {
455         short ok = 0;
456
457         /* frame is stored in f1 property (this float accuracy check may need to be dropped?) */
458 #define KEY_CHECK_OK(_index) IS_EQF(bezt->vec[_index][0], ked->f1)
459         KEYFRAME_OK_CHECKS(KEY_CHECK_OK);
460 #undef KEY_CHECK_OK
461
462         /* return ok flags */
463         return ok;
464 }
465
466 static short ok_bezier_framerange(KeyframeEditData *ked, BezTriple *bezt)
467 {
468         short ok = 0;
469
470         /* frame range is stored in float properties */
471 #define KEY_CHECK_OK(_index) ((bezt->vec[_index][0] > ked->f1) && (bezt->vec[_index][0] < ked->f2))
472         KEYFRAME_OK_CHECKS(KEY_CHECK_OK);
473 #undef KEY_CHECK_OK
474
475         /* return ok flags */
476         return ok;
477 }
478
479 static short ok_bezier_selected(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
480 {
481         /* this macro checks all beztriple handles for selection...
482          * only one of the verts has to be selected for this to be ok...
483          */
484         if (BEZT_ISSEL_ANY(bezt))
485                 return KEYFRAME_OK_ALL;
486         else
487                 return 0;
488 }
489
490 static short ok_bezier_value(KeyframeEditData *ked, BezTriple *bezt)
491 {
492         short ok = 0;
493
494         /* value is stored in f1 property
495          * - this float accuracy check may need to be dropped?
496          * - should value be stored in f2 instead so that we won't have conflicts when using f1 for frames too?
497          */
498 #define KEY_CHECK_OK(_index) IS_EQF(bezt->vec[_index][1], ked->f1)
499         KEYFRAME_OK_CHECKS(KEY_CHECK_OK);
500 #undef KEY_CHECK_OK
501
502         /* return ok flags */
503         return ok;
504 }
505
506 static short ok_bezier_valuerange(KeyframeEditData *ked, BezTriple *bezt)
507 {
508         short ok = 0;
509
510         /* value range is stored in float properties */
511 #define KEY_CHECK_OK(_index) ((bezt->vec[_index][1] > ked->f1) && (bezt->vec[_index][1] < ked->f2))
512         KEYFRAME_OK_CHECKS(KEY_CHECK_OK);
513 #undef KEY_CHECK_OK
514
515         /* return ok flags */
516         return ok;
517 }
518
519 static short ok_bezier_region(KeyframeEditData *ked, BezTriple *bezt)
520 {
521         /* rect is stored in data property (it's of type rectf, but may not be set) */
522         if (ked->data) {
523                 short ok = 0;
524
525 #define KEY_CHECK_OK(_index) BLI_rctf_isect_pt_v(ked->data, bezt->vec[_index])
526                 KEYFRAME_OK_CHECKS(KEY_CHECK_OK);
527 #undef KEY_CHECK_OK
528
529                 /* return ok flags */
530                 return ok;
531         }
532         else
533                 return 0;
534 }
535
536 /**
537  * Called from #ok_bezier_region_lasso and #ok_bezier_channel_lasso
538  */
539 bool keyframe_region_lasso_test(
540         const KeyframeEdit_LassoData *data_lasso,
541         const float xy[2])
542 {
543         if (BLI_rctf_isect_pt_v(data_lasso->rectf_scaled, xy)) {
544                 float xy_view[2];
545
546                 BLI_rctf_transform_pt_v(data_lasso->rectf_view, data_lasso->rectf_scaled, xy_view, xy);
547
548                 if (BLI_lasso_is_point_inside(data_lasso->mcords, data_lasso->mcords_tot, xy_view[0], xy_view[1], INT_MAX)) {
549                         return true;
550                 }
551         }
552
553         return false;
554 }
555
556 static short ok_bezier_region_lasso(KeyframeEditData *ked, BezTriple *bezt)
557 {
558         /* check for lasso customdata (KeyframeEdit_LassoData) */
559         if (ked->data) {
560                 short ok = 0;
561
562 #define KEY_CHECK_OK(_index) keyframe_region_lasso_test(ked->data, bezt->vec[_index])
563                 KEYFRAME_OK_CHECKS(KEY_CHECK_OK);
564 #undef KEY_CHECK_OK
565
566                 /* return ok flags */
567                 return ok;
568         }
569         else
570                 return 0;
571 }
572
573 static short ok_bezier_channel_lasso(KeyframeEditData *ked, BezTriple *bezt)
574 {
575         /* check for lasso customdata (KeyframeEdit_LassoData) */
576         if (ked->data) {
577                 KeyframeEdit_LassoData *data = ked->data;
578                 float pt[2];
579
580                 /* late-binding remap of the x values (for summary channels) */
581                 /* XXX: Ideally we reset, but it should be fine just leaving it as-is
582                  * as the next channel will reset it properly, while the next summary-channel
583                  * curve will also reset by itself...
584                  */
585                 if (ked->iterflags & (KED_F1_NLA_UNMAP | KED_F2_NLA_UNMAP)) {
586                         data->rectf_scaled->xmin = ked->f1;
587                         data->rectf_scaled->xmax = ked->f2;
588                 }
589
590                 /* only use the x-coordinate of the point; the y is the channel range... */
591                 pt[0] = bezt->vec[1][0];
592                 pt[1] = ked->channel_y;
593
594                 if (keyframe_region_lasso_test(data, pt))
595                         return KEYFRAME_OK_KEY;
596         }
597         return 0;
598 }
599
600 /**
601  * Called from #ok_bezier_region_circle and #ok_bezier_channel_circle
602  */
603 bool keyframe_region_circle_test(
604         const KeyframeEdit_CircleData *data_circle,
605         const float xy[2])
606 {
607         if (BLI_rctf_isect_pt_v(data_circle->rectf_scaled, xy)) {
608                 float xy_view[2];
609
610                 BLI_rctf_transform_pt_v(data_circle->rectf_view, data_circle->rectf_scaled, xy_view, xy);
611
612                 xy_view[0] = xy_view[0] - data_circle->mval[0];
613                 xy_view[1] = xy_view[1] - data_circle->mval[1];
614                 return len_squared_v2(xy_view) < data_circle->radius_squared;
615         }
616
617         return false;
618 }
619
620
621 static short ok_bezier_region_circle(KeyframeEditData *ked, BezTriple *bezt)
622 {
623         /* check for circle select customdata (KeyframeEdit_CircleData) */
624         if (ked->data) {
625                 short ok = 0;
626
627 #define KEY_CHECK_OK(_index) keyframe_region_circle_test(ked->data, bezt->vec[_index])
628                 KEYFRAME_OK_CHECKS(KEY_CHECK_OK);
629 #undef KEY_CHECK_OK
630
631                 /* return ok flags */
632                 return ok;
633         }
634         else
635                 return 0;
636 }
637
638 static short ok_bezier_channel_circle(KeyframeEditData *ked, BezTriple *bezt)
639 {
640         /* check for circle select customdata (KeyframeEdit_CircleData) */
641         if (ked->data) {
642                 KeyframeEdit_CircleData *data = ked->data;
643                 float pt[2];
644
645                 /* late-binding remap of the x values (for summary channels) */
646                 /* XXX: Ideally we reset, but it should be fine just leaving it as-is
647                  * as the next channel will reset it properly, while the next summary-channel
648                  * curve will also reset by itself...
649                  */
650                 if (ked->iterflags & (KED_F1_NLA_UNMAP | KED_F2_NLA_UNMAP)) {
651                         data->rectf_scaled->xmin = ked->f1;
652                         data->rectf_scaled->xmax = ked->f2;
653                 }
654
655                 /* only use the x-coordinate of the point; the y is the channel range... */
656                 pt[0] = bezt->vec[1][0];
657                 pt[1] = ked->channel_y;
658
659                 if (keyframe_region_circle_test(data, pt))
660                         return KEYFRAME_OK_KEY;
661         }
662         return 0;
663 }
664
665
666 KeyframeEditFunc ANIM_editkeyframes_ok(short mode)
667 {
668         /* eEditKeyframes_Validate */
669         switch (mode) {
670                 case BEZT_OK_FRAME:
671                         /* only if bezt falls on the right frame (float) */
672                         return ok_bezier_frame;
673                 case BEZT_OK_FRAMERANGE:
674                         /* only if bezt falls within the specified frame range (floats) */
675                         return ok_bezier_framerange;
676                 case BEZT_OK_SELECTED:
677                         /* only if bezt is selected (self) */
678                         return ok_bezier_selected;
679                 case BEZT_OK_VALUE:
680                         /* only if bezt value matches (float) */
681                         return ok_bezier_value;
682                 case BEZT_OK_VALUERANGE:
683                         /* only if bezier falls within the specified value range (floats) */
684                         return ok_bezier_valuerange;
685                 case BEZT_OK_REGION:
686                         /* only if bezier falls within the specified rect (data -> rectf) */
687                         return ok_bezier_region;
688                 case BEZT_OK_REGION_LASSO:
689                         /* only if the point falls within KeyframeEdit_LassoData defined data */
690                         return ok_bezier_region_lasso;
691                 case BEZT_OK_REGION_CIRCLE:
692                         /* only if the point falls within KeyframeEdit_CircleData defined data */
693                         return ok_bezier_region_circle;
694                 case BEZT_OK_CHANNEL_LASSO:
695                         /* same as BEZT_OK_REGION_LASSO, but we're only using the x-value of the points */
696                         return ok_bezier_channel_lasso;
697                 case BEZT_OK_CHANNEL_CIRCLE:
698                         /* same as BEZT_OK_REGION_CIRCLE, but we're only using the x-value of the points */
699                         return ok_bezier_channel_circle;
700                 default: /* nothing was ok */
701                         return NULL;
702         }
703 }
704
705 /* ******************************************* */
706 /* Assorted Utility Functions */
707
708 /**
709  * Helper callback for <animeditor>_cfrasnap_exec() ->
710  * used to help get the average time of all selected beztriples
711  */
712 short bezt_calc_average(KeyframeEditData *ked, BezTriple *bezt)
713 {
714         /* only if selected */
715         if (bezt->f2 & SELECT) {
716                 /* store average time in float 1 (only do rounding at last step) */
717                 ked->f1 += bezt->vec[1][0];
718
719                 /* store average value in float 2 (only do rounding at last step)
720                  * - this isn't always needed, but some operators may also require this
721                  */
722                 ked->f2 += bezt->vec[1][1];
723
724                 /* increment number of items */
725                 ked->i1++;
726         }
727
728         return 0;
729 }
730
731 /* helper callback for columnselect_<animeditor>_keys() -> populate
732  * list CfraElems with frame numbers from selected beztriples */
733 short bezt_to_cfraelem(KeyframeEditData *ked, BezTriple *bezt)
734 {
735         /* only if selected */
736         if (bezt->f2 & SELECT) {
737                 CfraElem *ce = MEM_callocN(sizeof(CfraElem), "cfraElem");
738                 BLI_addtail(&ked->list, ce);
739
740                 ce->cfra = bezt->vec[1][0];
741         }
742
743         return 0;
744 }
745
746 /* used to remap times from one range to another
747  * requires:  ked->data = KeyframeEditCD_Remap
748  */
749 void bezt_remap_times(KeyframeEditData *ked, BezTriple *bezt)
750 {
751         KeyframeEditCD_Remap *rmap = (KeyframeEditCD_Remap *)ked->data;
752         const float scale = (rmap->newMax - rmap->newMin) / (rmap->oldMax - rmap->oldMin);
753
754         /* perform transform on all three handles unless indicated otherwise */
755         // TODO: need to include some checks for that
756
757         bezt->vec[0][0] = scale * (bezt->vec[0][0] - rmap->oldMin) + rmap->newMin;
758         bezt->vec[1][0] = scale * (bezt->vec[1][0] - rmap->oldMin) + rmap->newMin;
759         bezt->vec[2][0] = scale * (bezt->vec[2][0] - rmap->oldMin) + rmap->newMin;
760 }
761
762 /* ******************************************* */
763 /* Transform */
764
765 /* snaps the keyframe to the nearest frame */
766 static short snap_bezier_nearest(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
767 {
768         if (bezt->f2 & SELECT)
769                 bezt->vec[1][0] = (float)(floorf(bezt->vec[1][0] + 0.5f));
770         return 0;
771 }
772
773 /* snaps the keyframe to the nearest second */
774 static short snap_bezier_nearestsec(KeyframeEditData *ked, BezTriple *bezt)
775 {
776         const Scene *scene = ked->scene;
777         const float secf = (float)FPS;
778
779         if (bezt->f2 & SELECT)
780                 bezt->vec[1][0] = (floorf(bezt->vec[1][0] / secf + 0.5f) * secf);
781         return 0;
782 }
783
784 /* snaps the keyframe to the current frame */
785 static short snap_bezier_cframe(KeyframeEditData *ked, BezTriple *bezt)
786 {
787         const Scene *scene = ked->scene;
788         if (bezt->f2 & SELECT)
789                 bezt->vec[1][0] = (float)CFRA;
790         return 0;
791 }
792
793 /* snaps the keyframe time to the nearest marker's frame */
794 static short snap_bezier_nearmarker(KeyframeEditData *ked, BezTriple *bezt)
795 {
796         if (bezt->f2 & SELECT)
797                 bezt->vec[1][0] = (float)ED_markers_find_nearest_marker_time(&ked->list, bezt->vec[1][0]);
798         return 0;
799 }
800
801 /* make the handles have the same value as the key */
802 static short snap_bezier_horizontal(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
803 {
804         if (bezt->f2 & SELECT) {
805                 bezt->vec[0][1] = bezt->vec[2][1] = bezt->vec[1][1];
806
807                 if (ELEM(bezt->h1, HD_AUTO, HD_AUTO_ANIM, HD_VECT)) bezt->h1 = HD_ALIGN;
808                 if (ELEM(bezt->h2, HD_AUTO, HD_AUTO_ANIM, HD_VECT)) bezt->h2 = HD_ALIGN;
809         }
810         return 0;
811 }
812
813 /* frame to snap to is stored in the custom data -> first float value slot */
814 static short snap_bezier_time(KeyframeEditData *ked, BezTriple *bezt)
815 {
816         if (bezt->f2 & SELECT)
817                 bezt->vec[1][0] = ked->f1;
818         return 0;
819 }
820
821 /* value to snap to is stored in the custom data -> first float value slot */
822 static short snap_bezier_value(KeyframeEditData *ked, BezTriple *bezt)
823 {
824         if (bezt->f2 & SELECT)
825                 bezt->vec[1][1] = ked->f1;
826         return 0;
827 }
828
829 KeyframeEditFunc ANIM_editkeyframes_snap(short type)
830 {
831         /* eEditKeyframes_Snap */
832         switch (type) {
833                 case SNAP_KEYS_NEARFRAME: /* snap to nearest frame */
834                         return snap_bezier_nearest;
835                 case SNAP_KEYS_CURFRAME: /* snap to current frame */
836                         return snap_bezier_cframe;
837                 case SNAP_KEYS_NEARMARKER: /* snap to nearest marker */
838                         return snap_bezier_nearmarker;
839                 case SNAP_KEYS_NEARSEC: /* snap to nearest second */
840                         return snap_bezier_nearestsec;
841                 case SNAP_KEYS_HORIZONTAL: /* snap handles to same value */
842                         return snap_bezier_horizontal;
843                 case SNAP_KEYS_TIME: /* snap to given frame/time */
844                         return snap_bezier_time;
845                 case SNAP_KEYS_VALUE: /* snap to given value */
846                         return snap_bezier_value;
847                 default: /* just in case */
848                         return snap_bezier_nearest;
849         }
850 }
851
852 /* --------- */
853
854 static void mirror_bezier_xaxis_ex(BezTriple *bezt, const float center)
855 {
856         float diff;
857         int i;
858
859         for (i = 0; i < 3; i++) {
860                 diff = (center - bezt->vec[i][0]);
861                 bezt->vec[i][0] = (center + diff);
862         }
863         swap_v3_v3(bezt->vec[0], bezt->vec[2]);
864
865         SWAP(char, bezt->h1, bezt->h2);
866         SWAP(char, bezt->f1, bezt->f3);
867 }
868
869 static void mirror_bezier_yaxis_ex(BezTriple *bezt, const float center)
870 {
871         float diff;
872         int i;
873
874         for (i = 0; i < 3; i++) {
875                 diff = (center - bezt->vec[i][1]);
876                 bezt->vec[i][1] = (center + diff);
877         }
878 }
879
880 static short mirror_bezier_cframe(KeyframeEditData *ked, BezTriple *bezt)
881 {
882         const Scene *scene = ked->scene;
883
884         if (bezt->f2 & SELECT) {
885                 mirror_bezier_xaxis_ex(bezt, CFRA);
886         }
887
888         return 0;
889 }
890
891 static short mirror_bezier_yaxis(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
892 {
893         if (bezt->f2 & SELECT) {
894                 /* Yes, names are inverted, we are mirroring across y axis, hence along x axis... */
895                 mirror_bezier_xaxis_ex(bezt, 0.0f);
896         }
897
898         return 0;
899 }
900
901 static short mirror_bezier_xaxis(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
902 {
903         if (bezt->f2 & SELECT) {
904                 /* Yes, names are inverted, we are mirroring across x axis, hence along y axis... */
905                 mirror_bezier_yaxis_ex(bezt, 0.0f);
906         }
907
908         return 0;
909 }
910
911 static short mirror_bezier_marker(KeyframeEditData *ked, BezTriple *bezt)
912 {
913         /* mirroring time stored in f1 */
914         if (bezt->f2 & SELECT) {
915                 mirror_bezier_xaxis_ex(bezt, ked->f1);
916         }
917
918         return 0;
919 }
920
921 static short mirror_bezier_time(KeyframeEditData *ked, BezTriple *bezt)
922 {
923         /* value to mirror over is stored in f1 */
924         if (bezt->f2 & SELECT) {
925                 mirror_bezier_xaxis_ex(bezt, ked->f1);
926         }
927
928         return 0;
929 }
930
931 static short mirror_bezier_value(KeyframeEditData *ked, BezTriple *bezt)
932 {
933         /* value to mirror over is stored in the custom data -> first float value slot */
934         if (bezt->f2 & SELECT) {
935                 mirror_bezier_yaxis_ex(bezt, ked->f1);
936         }
937
938         return 0;
939 }
940
941 /* Note: for markers and 'value', the values to use must be supplied as the first float value */
942 // calchandles_fcurve
943 KeyframeEditFunc ANIM_editkeyframes_mirror(short type)
944 {
945         switch (type) {
946                 case MIRROR_KEYS_CURFRAME: /* mirror over current frame */
947                         return mirror_bezier_cframe;
948                 case MIRROR_KEYS_YAXIS: /* mirror over frame 0 */
949                         return mirror_bezier_yaxis;
950                 case MIRROR_KEYS_XAXIS: /* mirror over value 0 */
951                         return mirror_bezier_xaxis;
952                 case MIRROR_KEYS_MARKER: /* mirror over marker */
953                         return mirror_bezier_marker;
954                 case MIRROR_KEYS_TIME: /* mirror over frame/time */
955                         return mirror_bezier_time;
956                 case MIRROR_KEYS_VALUE: /* mirror over given value */
957                         return mirror_bezier_value;
958                 default: /* just in case */
959                         return mirror_bezier_yaxis;
960         }
961 }
962
963 /* ******************************************* */
964 /* Settings */
965
966 /* standard validation step for a few of these (implemented as macro for inlining without fn-call overhead):
967  * "if the handles are not of the same type, set them to type free"
968  */
969 #define ENSURE_HANDLES_MATCH(bezt)                                            \
970         if (bezt->h1 != bezt->h2) {                                               \
971                 if (ELEM(bezt->h1, HD_ALIGN, HD_AUTO, HD_AUTO_ANIM))                  \
972                         bezt->h1 = HD_FREE;                                               \
973                 if (ELEM(bezt->h2, HD_ALIGN, HD_AUTO, HD_AUTO_ANIM))                  \
974                         bezt->h2 = HD_FREE;                                               \
975         } (void)0
976
977 /* Sets the selected bezier handles to type 'auto' */
978 static short set_bezier_auto(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
979 {
980         if ((bezt->f1 & SELECT) || (bezt->f3 & SELECT)) {
981                 if (bezt->f1 & SELECT) bezt->h1 = HD_AUTO;
982                 if (bezt->f3 & SELECT) bezt->h2 = HD_AUTO;
983
984                 ENSURE_HANDLES_MATCH(bezt);
985         }
986         return 0;
987 }
988
989 /* Sets the selected bezier handles to type 'auto-clamped'
990  * NOTE: this is like auto above, but they're handled a bit different
991  */
992 static short set_bezier_auto_clamped(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
993 {
994         if ((bezt->f1 & SELECT) || (bezt->f3 & SELECT)) {
995                 if (bezt->f1 & SELECT) bezt->h1 = HD_AUTO_ANIM;
996                 if (bezt->f3 & SELECT) bezt->h2 = HD_AUTO_ANIM;
997
998                 ENSURE_HANDLES_MATCH(bezt);
999         }
1000         return 0;
1001 }
1002
1003 /* Sets the selected bezier handles to type 'vector'  */
1004 static short set_bezier_vector(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
1005 {
1006         if (bezt->f1 & SELECT) bezt->h1 = HD_VECT;
1007         if (bezt->f3 & SELECT) bezt->h2 = HD_VECT;
1008         return 0;
1009 }
1010
1011 /* Queries if the handle should be set to 'free' or 'align' */
1012 // NOTE: this was used for the 'toggle free/align' option
1013 //              currently this isn't used, but may be restored later
1014 static short bezier_isfree(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
1015 {
1016         if ((bezt->f1 & SELECT) && (bezt->h1)) return 1;
1017         if ((bezt->f3 & SELECT) && (bezt->h2)) return 1;
1018         return 0;
1019 }
1020
1021 /* Sets selected bezier handles to type 'align' */
1022 static short set_bezier_align(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
1023 {
1024         if (bezt->f1 & SELECT) bezt->h1 = HD_ALIGN;
1025         if (bezt->f3 & SELECT) bezt->h2 = HD_ALIGN;
1026         return 0;
1027 }
1028
1029 /* Sets selected bezier handles to type 'free'  */
1030 static short set_bezier_free(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
1031 {
1032         if (bezt->f1 & SELECT) bezt->h1 = HD_FREE;
1033         if (bezt->f3 & SELECT) bezt->h2 = HD_FREE;
1034         return 0;
1035 }
1036
1037 /* Set all selected Bezier Handles to a single type */
1038 // calchandles_fcurve
1039 KeyframeEditFunc ANIM_editkeyframes_handles(short code)
1040 {
1041         switch (code) {
1042                 case HD_AUTO: /* auto */
1043                         return set_bezier_auto;
1044                 case HD_AUTO_ANIM: /* auto clamped */
1045                         return set_bezier_auto_clamped;
1046
1047                 case HD_VECT: /* vector */
1048                         return set_bezier_vector;
1049                 case HD_FREE: /* free */
1050                         return set_bezier_free;
1051                 case HD_ALIGN: /* align */
1052                         return set_bezier_align;
1053
1054                 default: /* check for toggle free or align? */
1055                         return bezier_isfree;
1056         }
1057 }
1058
1059 /* ------- */
1060
1061 static short set_bezt_constant(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
1062 {
1063         if (bezt->f2 & SELECT)
1064                 bezt->ipo = BEZT_IPO_CONST;
1065         return 0;
1066 }
1067
1068 static short set_bezt_linear(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
1069 {
1070         if (bezt->f2 & SELECT)
1071                 bezt->ipo = BEZT_IPO_LIN;
1072         return 0;
1073 }
1074
1075 static short set_bezt_bezier(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
1076 {
1077         if (bezt->f2 & SELECT)
1078                 bezt->ipo = BEZT_IPO_BEZ;
1079         return 0;
1080 }
1081
1082 static short set_bezt_back(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
1083 {
1084         if (bezt->f2 & SELECT)
1085                 bezt->ipo = BEZT_IPO_BACK;
1086         return 0;
1087 }
1088
1089 static short set_bezt_bounce(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
1090 {
1091         if (bezt->f2 & SELECT)
1092                 bezt->ipo = BEZT_IPO_BOUNCE;
1093         return 0;
1094 }
1095
1096 static short set_bezt_circle(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
1097 {
1098         if (bezt->f2 & SELECT)
1099                 bezt->ipo = BEZT_IPO_CIRC;
1100         return 0;
1101 }
1102
1103 static short set_bezt_cubic(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
1104 {
1105         if (bezt->f2 & SELECT)
1106                 bezt->ipo = BEZT_IPO_CUBIC;
1107         return 0;
1108 }
1109
1110 static short set_bezt_elastic(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
1111 {
1112         if (bezt->f2 & SELECT)
1113                 bezt->ipo = BEZT_IPO_ELASTIC;
1114         return 0;
1115 }
1116
1117 static short set_bezt_expo(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
1118 {
1119         if (bezt->f2 & SELECT)
1120                 bezt->ipo = BEZT_IPO_EXPO;
1121         return 0;
1122 }
1123
1124 static short set_bezt_quad(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
1125 {
1126         if (bezt->f2 & SELECT)
1127                 bezt->ipo = BEZT_IPO_QUAD;
1128         return 0;
1129 }
1130
1131 static short set_bezt_quart(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
1132 {
1133         if (bezt->f2 & SELECT)
1134                 bezt->ipo = BEZT_IPO_QUART;
1135         return 0;
1136 }
1137
1138 static short set_bezt_quint(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
1139 {
1140         if (bezt->f2 & SELECT)
1141                 bezt->ipo = BEZT_IPO_QUINT;
1142         return 0;
1143 }
1144
1145 static short set_bezt_sine(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
1146 {
1147         if (bezt->f2 & SELECT)
1148                 bezt->ipo = BEZT_IPO_SINE;
1149         return 0;
1150 }
1151
1152 /* Set the interpolation type of the selected BezTriples in each F-Curve to the specified one */
1153 // ANIM_editkeyframes_ipocurve_ipotype() !
1154 KeyframeEditFunc ANIM_editkeyframes_ipo(short code)
1155 {
1156         switch (code) {
1157                 /* interpolation */
1158                 case BEZT_IPO_CONST: /* constant */
1159                         return set_bezt_constant;
1160                 case BEZT_IPO_LIN: /* linear */
1161                         return set_bezt_linear;
1162
1163                 /* easing */
1164                 case BEZT_IPO_BACK:
1165                         return set_bezt_back;
1166                 case BEZT_IPO_BOUNCE:
1167                         return set_bezt_bounce;
1168                 case BEZT_IPO_CIRC:
1169                         return set_bezt_circle;
1170                 case BEZT_IPO_CUBIC:
1171                         return set_bezt_cubic;
1172                 case BEZT_IPO_ELASTIC:
1173                         return set_bezt_elastic;
1174                 case BEZT_IPO_EXPO:
1175                         return set_bezt_expo;
1176                 case BEZT_IPO_QUAD:
1177                         return set_bezt_quad;
1178                 case BEZT_IPO_QUART:
1179                         return set_bezt_quart;
1180                 case BEZT_IPO_QUINT:
1181                         return set_bezt_quint;
1182                 case BEZT_IPO_SINE:
1183                         return set_bezt_sine;
1184
1185                 default: /* bezier */
1186                         return set_bezt_bezier;
1187         }
1188 }
1189
1190 /* ------- */
1191
1192 static short set_keytype_keyframe(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
1193 {
1194         if (bezt->f2 & SELECT)
1195                 BEZKEYTYPE(bezt) = BEZT_KEYTYPE_KEYFRAME;
1196         return 0;
1197 }
1198
1199 static short set_keytype_breakdown(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
1200 {
1201         if (bezt->f2 & SELECT)
1202                 BEZKEYTYPE(bezt) = BEZT_KEYTYPE_BREAKDOWN;
1203         return 0;
1204 }
1205
1206 static short set_keytype_extreme(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
1207 {
1208         if (bezt->f2 & SELECT)
1209                 BEZKEYTYPE(bezt) = BEZT_KEYTYPE_EXTREME;
1210         return 0;
1211 }
1212
1213 static short set_keytype_jitter(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
1214 {
1215         if (bezt->f2 & SELECT)
1216                 BEZKEYTYPE(bezt) = BEZT_KEYTYPE_JITTER;
1217         return 0;
1218 }
1219
1220 static short set_keytype_moving_hold(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
1221 {
1222         if (bezt->f2 & SELECT)
1223                 BEZKEYTYPE(bezt) = BEZT_KEYTYPE_MOVEHOLD;
1224         return 0;
1225 }
1226
1227 /* Set the interpolation type of the selected BezTriples in each F-Curve to the specified one */
1228 KeyframeEditFunc ANIM_editkeyframes_keytype(short code)
1229 {
1230         switch (code) {
1231                 case BEZT_KEYTYPE_BREAKDOWN: /* breakdown */
1232                         return set_keytype_breakdown;
1233
1234                 case BEZT_KEYTYPE_EXTREME: /* extreme keyframe */
1235                         return set_keytype_extreme;
1236
1237                 case BEZT_KEYTYPE_JITTER: /* jitter keyframe */
1238                         return set_keytype_jitter;
1239
1240                 case BEZT_KEYTYPE_MOVEHOLD: /* moving hold */
1241                         return set_keytype_moving_hold;
1242
1243                 case BEZT_KEYTYPE_KEYFRAME: /* proper keyframe */
1244                 default:
1245                         return set_keytype_keyframe;
1246         }
1247 }
1248
1249 /* ------- */
1250
1251 static short set_easingtype_easein(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
1252 {
1253         if (bezt->f2 & SELECT)
1254                 bezt->easing = BEZT_IPO_EASE_IN;
1255         return 0;
1256 }
1257
1258 static short set_easingtype_easeout(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
1259 {
1260         if (bezt->f2 & SELECT)
1261                 bezt->easing = BEZT_IPO_EASE_OUT;
1262         return 0;
1263 }
1264
1265 static short set_easingtype_easeinout(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
1266 {
1267         if (bezt->f2 & SELECT)
1268                 bezt->easing = BEZT_IPO_EASE_IN_OUT;
1269         return 0;
1270 }
1271
1272 static short set_easingtype_easeauto(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
1273 {
1274         if (bezt->f2 & SELECT)
1275                 bezt->easing = BEZT_IPO_EASE_AUTO;
1276         return 0;
1277 }
1278
1279 /* Set the easing type of the selected BezTriples in each F-Curve to the specified one */
1280 KeyframeEditFunc ANIM_editkeyframes_easing(short mode)
1281 {
1282         switch (mode) {
1283                 case BEZT_IPO_EASE_IN: /* ease in */
1284                         return set_easingtype_easein;
1285
1286                 case BEZT_IPO_EASE_OUT: /* ease out */
1287                         return set_easingtype_easeout;
1288
1289                 case BEZT_IPO_EASE_IN_OUT: /* both */
1290                         return set_easingtype_easeinout;
1291
1292                 default: /* auto */
1293                         return set_easingtype_easeauto;
1294         }
1295 }
1296
1297 /* ******************************************* */
1298 /* Selection */
1299
1300 static short select_bezier_add(KeyframeEditData *ked, BezTriple *bezt)
1301 {
1302         /* if we've got info on what to select, use it, otherwise select all */
1303         if ((ked) && (ked->iterflags & KEYFRAME_ITER_INCL_HANDLES)) {
1304                 if (ked->curflags & KEYFRAME_OK_KEY)
1305                         bezt->f2 |= SELECT;
1306                 if (ked->curflags & KEYFRAME_OK_H1)
1307                         bezt->f1 |= SELECT;
1308                 if (ked->curflags & KEYFRAME_OK_H2)
1309                         bezt->f3 |= SELECT;
1310         }
1311         else {
1312                 BEZT_SEL_ALL(bezt);
1313         }
1314
1315         return 0;
1316 }
1317
1318 static short select_bezier_subtract(KeyframeEditData *ked, BezTriple *bezt)
1319 {
1320         /* if we've got info on what to deselect, use it, otherwise deselect all */
1321         if ((ked) && (ked->iterflags & KEYFRAME_ITER_INCL_HANDLES)) {
1322                 if (ked->curflags & KEYFRAME_OK_KEY)
1323                         bezt->f2 &= ~SELECT;
1324                 if (ked->curflags & KEYFRAME_OK_H1)
1325                         bezt->f1 &= ~SELECT;
1326                 if (ked->curflags & KEYFRAME_OK_H2)
1327                         bezt->f3 &= ~SELECT;
1328         }
1329         else {
1330                 BEZT_DESEL_ALL(bezt);
1331         }
1332
1333         return 0;
1334 }
1335
1336 static short select_bezier_invert(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
1337 {
1338         /* Invert the selection for the whole bezier triple */
1339         bezt->f2 ^= SELECT;
1340         if (bezt->f2 & SELECT) {
1341                 bezt->f1 |= SELECT;
1342                 bezt->f3 |= SELECT;
1343         }
1344         else {
1345                 bezt->f1 &= ~SELECT;
1346                 bezt->f3 &= ~SELECT;
1347         }
1348         return 0;
1349 }
1350
1351 KeyframeEditFunc ANIM_editkeyframes_select(short selectmode)
1352 {
1353         switch (selectmode) {
1354                 case SELECT_ADD: /* add */
1355                         return select_bezier_add;
1356                 case SELECT_SUBTRACT: /* subtract */
1357                         return select_bezier_subtract;
1358                 case SELECT_INVERT: /* invert */
1359                         return select_bezier_invert;
1360                 default: /* replace (need to clear all, then add) */
1361                         return select_bezier_add;
1362         }
1363 }
1364
1365 /* ******************************************* */
1366 /* Selection Maps */
1367
1368 /* Selection maps are simply fancy names for char arrays that store on/off
1369  * info for whether the selection status. The main purpose for these is to
1370  * allow extra info to be tagged to the keyframes without influencing their
1371  * values or having to be removed later.
1372  */
1373
1374 /* ----------- */
1375
1376 static short selmap_build_bezier_more(KeyframeEditData *ked, BezTriple *bezt)
1377 {
1378         FCurve *fcu = ked->fcu;
1379         char *map = ked->data;
1380         int i = ked->curIndex;
1381
1382         /* if current is selected, just make sure it stays this way */
1383         if (BEZT_ISSEL_ANY(bezt)) {
1384                 map[i] = 1;
1385                 return 0;
1386         }
1387
1388         /* if previous is selected, that means that selection should extend across */
1389         if (i > 0) {
1390                 BezTriple *prev = bezt - 1;
1391
1392                 if (BEZT_ISSEL_ANY(prev)) {
1393                         map[i] = 1;
1394                         return 0;
1395                 }
1396         }
1397
1398         /* if next is selected, that means that selection should extend across */
1399         if (i < (fcu->totvert - 1)) {
1400                 BezTriple *next = bezt + 1;
1401
1402                 if (BEZT_ISSEL_ANY(next)) {
1403                         map[i] = 1;
1404                         return 0;
1405                 }
1406         }
1407
1408         return 0;
1409 }
1410
1411 static short selmap_build_bezier_less(KeyframeEditData *ked, BezTriple *bezt)
1412 {
1413         FCurve *fcu = ked->fcu;
1414         char *map = ked->data;
1415         int i = ked->curIndex;
1416
1417         /* if current is selected, check the left/right keyframes
1418          * since it might need to be deselected (but otherwise no)
1419          */
1420         if (BEZT_ISSEL_ANY(bezt)) {
1421                 /* if previous is not selected, we're on the tip of an iceberg */
1422                 if (i > 0) {
1423                         BezTriple *prev = bezt - 1;
1424
1425                         if (BEZT_ISSEL_ANY(prev) == 0)
1426                                 return 0;
1427                 }
1428                 else if (i == 0) {
1429                         /* current keyframe is selected at an endpoint, so should get deselected */
1430                         return 0;
1431                 }
1432
1433                 /* if next is not selected, we're on the tip of an iceberg */
1434                 if (i < (fcu->totvert - 1)) {
1435                         BezTriple *next = bezt + 1;
1436
1437                         if (BEZT_ISSEL_ANY(next) == 0)
1438                                 return 0;
1439                 }
1440                 else if (i == (fcu->totvert - 1)) {
1441                         /* current keyframe is selected at an endpoint, so should get deselected */
1442                         return 0;
1443                 }
1444
1445                 /* if we're still here, that means that keyframe should remain untouched */
1446                 map[i] = 1;
1447         }
1448
1449         return 0;
1450 }
1451
1452 /* Get callback for building selection map */
1453 KeyframeEditFunc ANIM_editkeyframes_buildselmap(short mode)
1454 {
1455         switch (mode) {
1456                 case SELMAP_LESS: /* less */
1457                         return selmap_build_bezier_less;
1458
1459                 case SELMAP_MORE: /* more */
1460                 default:
1461                         return selmap_build_bezier_more;
1462         }
1463 }
1464
1465 /* ----------- */
1466
1467 /* flush selection map values to the given beztriple */
1468 short bezt_selmap_flush(KeyframeEditData *ked, BezTriple *bezt)
1469 {
1470         const char *map = ked->data;
1471         short on = map[ked->curIndex];
1472
1473         /* select or deselect based on whether the map allows it or not */
1474         if (on) {
1475                 BEZT_SEL_ALL(bezt);
1476         }
1477         else {
1478                 BEZT_DESEL_ALL(bezt);
1479         }
1480
1481         return 0;
1482 }