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