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