Graph Editor: Added operator to 'bake' keyframe-based F-Curves to be composed of...
[blender-staging.git] / source / blender / editors / space_graph / graph_edit.c
1 /**
2  * $Id: editaction.c 17746 2008-12-08 11:19:44Z aligorith $
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19  *
20  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
21  * All rights reserved.
22  *
23  * The Original Code is: all of this file.
24  *
25  * Contributor(s): Joshua Leung
26  *
27  * ***** END GPL LICENSE BLOCK *****
28  */
29
30 #include <math.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <float.h>
34
35 #ifdef HAVE_CONFIG_H
36 #include <config.h>
37 #endif
38
39 #include "MEM_guardedalloc.h"
40
41 #include "BLI_blenlib.h"
42 #include "BLI_arithb.h"
43
44 #include "DNA_anim_types.h"
45 #include "DNA_action_types.h"
46 #include "DNA_armature_types.h"
47 #include "DNA_camera_types.h"
48 #include "DNA_curve_types.h"
49 #include "DNA_object_types.h"
50 #include "DNA_screen_types.h"
51 #include "DNA_scene_types.h"
52 #include "DNA_space_types.h"
53 #include "DNA_constraint_types.h"
54 #include "DNA_key_types.h"
55 #include "DNA_lamp_types.h"
56 #include "DNA_material_types.h"
57 #include "DNA_userdef_types.h"
58 #include "DNA_gpencil_types.h"
59 #include "DNA_windowmanager_types.h"
60
61 #include "RNA_access.h"
62 #include "RNA_define.h"
63
64 #include "BKE_action.h"
65 #include "BKE_depsgraph.h"
66 #include "BKE_fcurve.h"
67 #include "BKE_key.h"
68 #include "BKE_material.h"
69 #include "BKE_object.h"
70 #include "BKE_context.h"
71 #include "BKE_report.h"
72 #include "BKE_utildefines.h"
73
74 #include "UI_view2d.h"
75
76 #include "BIF_transform.h"
77
78 #include "ED_anim_api.h"
79 #include "ED_keyframing.h"
80 #include "ED_keyframes_draw.h"
81 #include "ED_keyframes_edit.h"
82 #include "ED_screen.h"
83 #include "ED_space_api.h"
84
85 #include "WM_api.h"
86 #include "WM_types.h"
87
88 #include "graph_intern.h"
89
90 /* ************************************************************************** */
91 /* KEYFRAME-RANGE STUFF */
92
93 /* *************************** Calculate Range ************************** */
94
95 /* Get the min/max keyframes*/
96 static void get_graph_keyframe_extents (bAnimContext *ac, float *xmin, float *xmax, float *ymin, float *ymax)
97 {
98         ListBase anim_data = {NULL, NULL};
99         bAnimListElem *ale;
100         int filter;
101         
102         /* get data to filter, from Dopesheet */
103         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE | ANIMFILTER_SEL | ANIMFILTER_FOREDIT | ANIMFILTER_CURVESONLY);
104         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
105         
106         /* set large values to try to override */
107         if (xmin) *xmin= 999999999.0f;
108         if (xmax) *xmax= -999999999.0f;
109         if (ymin) *ymin= 999999999.0f;
110         if (ymax) *ymax= -999999999.0f;
111         
112         /* check if any channels to set range with */
113         if (anim_data.first) {
114                 /* go through channels, finding max extents */
115                 for (ale= anim_data.first; ale; ale= ale->next) {
116                         Object *nob= NULL; //ANIM_nla_mapping_get(ac, ale);
117                         FCurve *fcu= (FCurve *)ale->key_data;
118                         float tmin, tmax;
119                         
120                         /* get range and apply necessary scaling before */
121                         calc_fcurve_bounds(fcu, &tmin, &tmax, ymin, ymax);
122                         
123                         if (nob) {
124                                 tmin= get_action_frame_inv(nob, tmin);
125                                 tmax= get_action_frame_inv(nob, tmax);
126                         }
127                         
128                         /* try to set cur using these values, if they're more extreme than previously set values */
129                         if (xmin) *xmin= MIN2(*xmin, tmin);
130                         if (xmax) *xmax= MAX2(*xmax, tmax);
131                 }
132                 
133                 /* free memory */
134                 BLI_freelistN(&anim_data);
135         }
136         else {
137                 /* set default range */
138                 if (ac->scene) {
139                         if (xmin) *xmin= (float)ac->scene->r.sfra;
140                         if (xmax) *xmax= (float)ac->scene->r.efra;
141                 }
142                 else {
143                         if (xmin) *xmin= -5;
144                         if (xmax) *xmax= 100;
145                 }
146                 
147                 if (ymin) *ymin= -5;
148                 if (ymax) *ymax= 5;
149         }
150 }
151
152 /* ****************** Automatic Preview-Range Operator ****************** */
153
154 static int graphkeys_previewrange_exec(bContext *C, wmOperator *op)
155 {
156         bAnimContext ac;
157         Scene *scene;
158         float min, max;
159         
160         /* get editor data */
161         if (ANIM_animdata_get_context(C, &ac) == 0)
162                 return OPERATOR_CANCELLED;
163         if (ac.scene == NULL)
164                 return OPERATOR_CANCELLED;
165         else
166                 scene= ac.scene;
167         
168         /* set the range directly */
169         get_graph_keyframe_extents(&ac, &min, &max, NULL, NULL);
170         scene->r.psfra= (int)floor(min + 0.5f);
171         scene->r.pefra= (int)floor(max + 0.5f);
172         
173         /* set notifier that things have changed */
174         // XXX err... there's nothing for frame ranges yet, but this should do fine too
175         WM_event_add_notifier(C, NC_SCENE|ND_FRAME, ac.scene); 
176         
177         return OPERATOR_FINISHED;
178 }
179  
180 void GRAPHEDIT_OT_set_previewrange (wmOperatorType *ot)
181 {
182         /* identifiers */
183         ot->name= "Auto-Set Preview Range";
184         ot->idname= "GRAPHEDIT_OT_set_previewrange";
185         
186         /* api callbacks */
187         ot->exec= graphkeys_previewrange_exec;
188         ot->poll= ED_operator_areaactive;
189         
190         /* flags */
191         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
192 }
193
194 /* ****************** View-All Operator ****************** */
195
196 static int graphkeys_viewall_exec(bContext *C, wmOperator *op)
197 {
198         bAnimContext ac;
199         View2D *v2d;
200         float extra;
201         
202         /* get editor data */
203         if (ANIM_animdata_get_context(C, &ac) == 0)
204                 return OPERATOR_CANCELLED;
205         v2d= &ac.ar->v2d;
206         
207         /* set the horizontal range, with an extra offset so that the extreme keys will be in view */
208         get_graph_keyframe_extents(&ac, &v2d->cur.xmin, &v2d->cur.xmax, &v2d->cur.ymin, &v2d->cur.ymax);
209         
210         extra= 0.1f * (v2d->cur.xmax - v2d->cur.xmin);
211         v2d->cur.xmin -= extra;
212         v2d->cur.xmax += extra;
213         
214         extra= 0.1f * (v2d->cur.ymax - v2d->cur.ymin);
215         v2d->cur.ymin -= extra;
216         v2d->cur.ymax += extra;
217         
218         /* do View2D syncing */
219         UI_view2d_sync(CTX_wm_screen(C), CTX_wm_area(C), v2d, V2D_LOCK_COPY);
220         
221         /* set notifier that things have changed */
222         ED_area_tag_redraw(CTX_wm_area(C));
223         
224         return OPERATOR_FINISHED;
225 }
226  
227 void GRAPHEDIT_OT_view_all (wmOperatorType *ot)
228 {
229         /* identifiers */
230         ot->name= "View All";
231         ot->idname= "GRAPHEDIT_OT_view_all";
232         
233         /* api callbacks */
234         ot->exec= graphkeys_viewall_exec;
235         ot->poll= ED_operator_areaactive;
236         
237         /* flags */
238         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
239 }
240
241
242 /* ************************************************************************** */
243 /* GENERAL STUFF */
244
245 // TODO: insertkey
246
247 /* ******************** Copy/Paste Keyframes Operator ************************* */
248 /* NOTE: the backend code for this is shared with the dopesheet editor */
249
250 static short copy_graph_keys (bAnimContext *ac)
251 {       
252         ListBase anim_data = {NULL, NULL};
253         int filter, ok=0;
254         
255         /* clear buffer first */
256         free_anim_copybuf();
257         
258         /* filter data */
259         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE | ANIMFILTER_SEL | ANIMFILTER_CURVESONLY);
260         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
261         
262         /* copy keyframes */
263         ok= copy_animedit_keys(ac, &anim_data);
264         
265         /* clean up */
266         BLI_freelistN(&anim_data);
267
268         return ok;
269 }
270
271 static short paste_graph_keys (bAnimContext *ac)
272 {       
273         ListBase anim_data = {NULL, NULL};
274         int filter, ok=0;
275         
276         /* filter data */
277         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE | ANIMFILTER_SEL | ANIMFILTER_FOREDIT | ANIMFILTER_CURVESONLY);
278         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
279         
280         /* paste keyframes */
281         ok= paste_animedit_keys(ac, &anim_data);
282         
283         /* clean up */
284         BLI_freelistN(&anim_data);
285
286         return ok;
287 }
288
289 /* ------------------- */
290
291 static int graphkeys_copy_exec(bContext *C, wmOperator *op)
292 {
293         bAnimContext ac;
294         
295         /* get editor data */
296         if (ANIM_animdata_get_context(C, &ac) == 0)
297                 return OPERATOR_CANCELLED;
298         
299         /* copy keyframes */
300         if (copy_graph_keys(&ac)) {     
301                 BKE_report(op->reports, RPT_ERROR, "No keyframes copied to keyframes copy/paste buffer");
302                 return OPERATOR_CANCELLED;
303         }
304         
305         /* set notifier tha things have changed */
306         ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_KEYFRAMES_VALUES);
307         
308         return OPERATOR_FINISHED;
309 }
310  
311 void GRAPHEDIT_OT_keyframes_copy (wmOperatorType *ot)
312 {
313         /* identifiers */
314         ot->name= "Copy Keyframes";
315         ot->idname= "GRAPHEDIT_OT_keyframes_copy";
316         
317         /* api callbacks */
318         ot->exec= graphkeys_copy_exec;
319         ot->poll= ED_operator_areaactive;
320         
321         /* flags */
322         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
323 }
324
325
326
327 static int graphkeys_paste_exec(bContext *C, wmOperator *op)
328 {
329         bAnimContext ac;
330         
331         /* get editor data */
332         if (ANIM_animdata_get_context(C, &ac) == 0)
333                 return OPERATOR_CANCELLED;
334         
335         /* paste keyframes */
336         if (paste_graph_keys(&ac)) {
337                 BKE_report(op->reports, RPT_ERROR, "No keyframes to paste");
338                 return OPERATOR_CANCELLED;
339         }
340         
341         /* validate keyframes after editing */
342         ANIM_editkeyframes_refresh(&ac);
343         
344         /* set notifier tha things have changed */
345         ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_KEYFRAMES_VALUES);
346         
347         return OPERATOR_FINISHED;
348 }
349  
350 void GRAPHEDIT_OT_keyframes_paste (wmOperatorType *ot)
351 {
352         /* identifiers */
353         ot->name= "Paste Keyframes";
354         ot->idname= "GRAPHEDIT_OT_keyframes_paste";
355         
356         /* api callbacks */
357         ot->exec= graphkeys_paste_exec;
358         ot->poll= ED_operator_areaactive;
359         
360         /* flags */
361         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
362 }
363
364 /* ******************** Duplicate Keyframes Operator ************************* */
365
366 static void duplicate_graph_keys (bAnimContext *ac)
367 {
368         ListBase anim_data = {NULL, NULL};
369         bAnimListElem *ale;
370         int filter;
371         
372         /* filter data */
373         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE| ANIMFILTER_FOREDIT | ANIMFILTER_CURVESONLY);
374         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
375         
376         /* loop through filtered data and delete selected keys */
377         for (ale= anim_data.first; ale; ale= ale->next) {
378                 duplicate_fcurve_keys((FCurve *)ale->key_data);
379         }
380         
381         /* free filtered list */
382         BLI_freelistN(&anim_data);
383 }
384
385 /* ------------------- */
386
387 static int graphkeys_duplicate_exec(bContext *C, wmOperator *op)
388 {
389         bAnimContext ac;
390         
391         /* get editor data */
392         if (ANIM_animdata_get_context(C, &ac) == 0)
393                 return OPERATOR_CANCELLED;
394                 
395         /* duplicate keyframes */
396         duplicate_graph_keys(&ac);
397         
398         /* validate keyframes after editing */
399         ANIM_editkeyframes_refresh(&ac);
400         
401         /* set notifier tha things have changed */
402         ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_KEYFRAMES_VALUES);
403         
404         return OPERATOR_FINISHED;
405 }
406
407 static int graphkeys_duplicate_invoke(bContext *C, wmOperator *op, wmEvent *event)
408 {
409         graphkeys_duplicate_exec(C, op);
410         
411         RNA_int_set(op->ptr, "mode", TFM_TRANSLATION);
412         WM_operator_name_call(C, "TFM_OT_transform", WM_OP_INVOKE_REGION_WIN, op->ptr);
413
414         return OPERATOR_FINISHED;
415 }
416  
417 void GRAPHEDIT_OT_keyframes_duplicate (wmOperatorType *ot)
418 {
419         /* identifiers */
420         ot->name= "Duplicate Keyframes";
421         ot->idname= "GRAPHEDIT_OT_keyframes_duplicate";
422         
423         /* api callbacks */
424         ot->invoke= graphkeys_duplicate_invoke;
425         ot->exec= graphkeys_duplicate_exec;
426         ot->poll= ED_operator_areaactive;
427         
428         /* flags */
429         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
430         
431         /* to give to transform */
432         RNA_def_int(ot->srna, "mode", TFM_TRANSLATION, 0, INT_MAX, "Mode", "", 0, INT_MAX);
433 }
434
435 /* ******************** Delete Keyframes Operator ************************* */
436
437 static void delete_graph_keys (bAnimContext *ac)
438 {
439         ListBase anim_data = {NULL, NULL};
440         bAnimListElem *ale;
441         int filter;
442         
443         /* filter data */
444         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE| ANIMFILTER_FOREDIT | ANIMFILTER_CURVESONLY);
445         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
446         
447         /* loop through filtered data and delete selected keys */
448         for (ale= anim_data.first; ale; ale= ale->next) {
449                 delete_fcurve_keys((FCurve *)ale->key_data); // XXX... this doesn't delete empty curves anymore
450         }
451         
452         /* free filtered list */
453         BLI_freelistN(&anim_data);
454 }
455
456 /* ------------------- */
457
458 static int graphkeys_delete_exec(bContext *C, wmOperator *op)
459 {
460         bAnimContext ac;
461         
462         /* get editor data */
463         if (ANIM_animdata_get_context(C, &ac) == 0)
464                 return OPERATOR_CANCELLED;
465                 
466         /* delete keyframes */
467         delete_graph_keys(&ac);
468         
469         /* validate keyframes after editing */
470         ANIM_editkeyframes_refresh(&ac);
471         
472         /* set notifier tha things have changed */
473         ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_KEYFRAMES_VALUES);
474         
475         return OPERATOR_FINISHED;
476 }
477  
478 void GRAPHEDIT_OT_keyframes_delete (wmOperatorType *ot)
479 {
480         /* identifiers */
481         ot->name= "Delete Keyframes";
482         ot->idname= "GRAPHEDIT_OT_keyframes_delete";
483         
484         /* api callbacks */
485         ot->invoke= WM_operator_confirm;
486         ot->exec= graphkeys_delete_exec;
487         ot->poll= ED_operator_areaactive;
488         
489         /* flags */
490         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
491 }
492
493 /* ******************** Clean Keyframes Operator ************************* */
494
495 static void clean_graph_keys (bAnimContext *ac, float thresh)
496 {       
497         ListBase anim_data = {NULL, NULL};
498         bAnimListElem *ale;
499         int filter;
500         
501         /* filter data */
502         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE| ANIMFILTER_FOREDIT | ANIMFILTER_SEL | ANIMFILTER_CURVESONLY);
503         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
504         
505         /* loop through filtered data and clean curves */
506         for (ale= anim_data.first; ale; ale= ale->next)
507                 clean_fcurve((FCurve *)ale->key_data, thresh);
508         
509         /* free temp data */
510         BLI_freelistN(&anim_data);
511 }
512
513 /* ------------------- */
514
515 static int graphkeys_clean_exec(bContext *C, wmOperator *op)
516 {
517         bAnimContext ac;
518         float thresh;
519         
520         /* get editor data */
521         if (ANIM_animdata_get_context(C, &ac) == 0)
522                 return OPERATOR_CANCELLED;
523                 
524         /* get cleaning threshold */
525         thresh= RNA_float_get(op->ptr, "threshold");
526         
527         /* clean keyframes */
528         clean_graph_keys(&ac, thresh);
529         
530         /* validate keyframes after editing */
531         ANIM_editkeyframes_refresh(&ac);
532         
533         /* set notifier tha things have changed */
534         ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_KEYFRAMES_VALUES);
535         
536         return OPERATOR_FINISHED;
537 }
538  
539 void GRAPHEDIT_OT_keyframes_clean (wmOperatorType *ot)
540 {
541         /* identifiers */
542         ot->name= "Clean Keyframes";
543         ot->idname= "GRAPHEDIT_OT_keyframes_clean";
544         
545         /* api callbacks */
546         //ot->invoke=  // XXX we need that number popup for this! 
547         ot->exec= graphkeys_clean_exec;
548         ot->poll= ED_operator_areaactive;
549         
550         /* flags */
551         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
552         
553         /* properties */
554         RNA_def_float(ot->srna, "threshold", 0.001f, 0.0f, FLT_MAX, "Threshold", "", 0.0f, 1000.0f);
555 }
556
557 /* ******************** Bake F-Curve Operator *********************** */
558 /* This operator bakes the data of the selected F-Curves to F-Points */
559
560 /* Bake each F-Curve into a set of samples */
561 static void bake_graph_curves (bAnimContext *ac, int start, int end)
562 {       
563         ListBase anim_data = {NULL, NULL};
564         bAnimListElem *ale;
565         int filter;
566         
567         /* filter data */
568         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE | ANIMFILTER_SEL | ANIMFILTER_FOREDIT | ANIMFILTER_CURVESONLY);
569         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
570         
571         /* loop through filtered data and add keys between selected keyframes on every frame  */
572         for (ale= anim_data.first; ale; ale= ale->next) {
573                 FCurve *fcu= (FCurve *)ale->key_data;
574                 ChannelDriver *driver= fcu->driver;
575                 
576                 /* disable driver so that it don't muck up the sampling process */
577                 fcu->driver= NULL;
578                 
579                 /* create samples */
580                 fcurve_store_samples(fcu, NULL, start, end, fcurve_samplingcb_evalcurve);
581                 
582                 /* restore driver */
583                 fcu->driver= driver;
584         }
585         
586         /* admin and redraws */
587         BLI_freelistN(&anim_data);
588 }
589
590 /* ------------------- */
591
592 static int graphkeys_bake_exec(bContext *C, wmOperator *op)
593 {
594         bAnimContext ac;
595         Scene *scene= NULL;
596         int start, end;
597         
598         /* get editor data */
599         if (ANIM_animdata_get_context(C, &ac) == 0)
600                 return OPERATOR_CANCELLED;
601                 
602         /* for now, init start/end from preview-range extents */
603         // TODO: add properties for this 
604         scene= ac.scene;
605         start= PSFRA;
606         end= PEFRA;
607         
608         /* bake keyframes */
609         bake_graph_curves(&ac, start, end);
610         
611         /* validate keyframes after editing */
612         ANIM_editkeyframes_refresh(&ac);
613         
614         /* set notifier tha things have changed */
615         ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_KEYFRAMES_VALUES);
616         
617         return OPERATOR_FINISHED;
618 }
619  
620 void GRAPHEDIT_OT_keyframes_bake (wmOperatorType *ot)
621 {
622         /* identifiers */
623         ot->name= "Bake Curve";
624         ot->idname= "GRAPHEDIT_OT_keyframes_bake";
625         
626         /* api callbacks */
627         ot->invoke= WM_operator_confirm; // FIXME...
628         ot->exec= graphkeys_bake_exec;
629         ot->poll= ED_operator_areaactive;
630         
631         /* flags */
632         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
633         
634         // todo: add props for start/end frames
635 }
636
637 /* ******************** Sample Keyframes Operator *********************** */
638 /* This operator 'bakes' the values of the curve into new keyframes between pairs
639  * of selected keyframes. It is useful for creating keyframes for tweaking overlap.
640  */
641
642 // XXX some of the common parts (with DopeSheet) should be unified in animation module...
643
644 /* little cache for values... */
645 typedef struct tempFrameValCache {
646         float frame, val;
647 } tempFrameValCache;
648
649 /* Evaluates the curves between each selected keyframe on each frame, and keys the value  */
650 static void sample_graph_keys (bAnimContext *ac)
651 {       
652         ListBase anim_data = {NULL, NULL};
653         bAnimListElem *ale;
654         int filter;
655         
656         /* filter data */
657         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE| ANIMFILTER_FOREDIT | ANIMFILTER_CURVESONLY);
658         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
659         
660         /* loop through filtered data and add keys between selected keyframes on every frame  */
661         for (ale= anim_data.first; ale; ale= ale->next) {
662                 FCurve *fcu= (FCurve *)ale->key_data;
663                 BezTriple *bezt, *start=NULL, *end=NULL;
664                 tempFrameValCache *value_cache, *fp;
665                 int sfra, range;
666                 int i, n;
667                 
668                 /* find selected keyframes... once pair has been found, add keyframes  */
669                 for (i=0, bezt=fcu->bezt; i < fcu->totvert; i++, bezt++) {
670                         /* check if selected, and which end this is */
671                         if (BEZSELECTED(bezt)) {
672                                 if (start) {
673                                         /* set end */
674                                         end= bezt;
675                                         
676                                         /* cache values then add keyframes using these values, as adding
677                                          * keyframes while sampling will affect the outcome...
678                                          */
679                                         range= (int)( ceil(end->vec[1][0] - start->vec[1][0]) );
680                                         sfra= (int)( floor(start->vec[1][0]) );
681                                         
682                                         if (range) {
683                                                 value_cache= MEM_callocN(sizeof(tempFrameValCache)*range, "IcuFrameValCache");
684                                                 
685                                                 /*      sample values   */
686                                                 for (n=0, fp=value_cache; n<range && fp; n++, fp++) {
687                                                         fp->frame= (float)(sfra + n);
688                                                         fp->val= evaluate_fcurve(fcu, fp->frame);
689                                                 }
690                                                 
691                                                 /*      add keyframes with these        */
692                                                 for (n=0, fp=value_cache; n<range && fp; n++, fp++) {
693                                                         insert_vert_fcurve(fcu, fp->frame, fp->val, 1);
694                                                 }
695                                                 
696                                                 /* free temp cache */
697                                                 MEM_freeN(value_cache);
698                                                 
699                                                 /* as we added keyframes, we need to compensate so that bezt is at the right place */
700                                                 bezt = fcu->bezt + i + range - 1;
701                                                 i += (range - 1);
702                                         }
703                                         
704                                         /* bezt was selected, so it now marks the start of a whole new chain to search */
705                                         start= bezt;
706                                         end= NULL;
707                                 }
708                                 else {
709                                         /* just set start keyframe */
710                                         start= bezt;
711                                         end= NULL;
712                                 }
713                         }
714                 }
715                 
716                 /* recalculate channel's handles? */
717                 calchandles_fcurve(fcu);
718         }
719         
720         /* admin and redraws */
721         BLI_freelistN(&anim_data);
722 }
723
724 /* ------------------- */
725
726 static int graphkeys_sample_exec(bContext *C, wmOperator *op)
727 {
728         bAnimContext ac;
729         
730         /* get editor data */
731         if (ANIM_animdata_get_context(C, &ac) == 0)
732                 return OPERATOR_CANCELLED;
733         
734         /* sample keyframes */
735         sample_graph_keys(&ac);
736         
737         /* validate keyframes after editing */
738         ANIM_editkeyframes_refresh(&ac);
739         
740         /* set notifier tha things have changed */
741         ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_KEYFRAMES_VALUES);
742         
743         return OPERATOR_FINISHED;
744 }
745  
746 void GRAPHEDIT_OT_keyframes_sample (wmOperatorType *ot)
747 {
748         /* identifiers */
749         ot->name= "Sample Keyframes";
750         ot->idname= "GRAPHEDIT_OT_keyframes_sample";
751         
752         /* api callbacks */
753         ot->exec= graphkeys_sample_exec;
754         ot->poll= ED_operator_areaactive;
755         
756         /* flags */
757         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
758 }
759
760
761 /* ************************************************************************** */
762 /* SETTINGS STUFF */
763
764 /* ******************** Set Extrapolation-Type Operator *********************** */
765
766 /* defines for set extrapolation-type for selected keyframes tool */
767 EnumPropertyItem prop_graphkeys_expo_types[] = {
768         {FCURVE_EXTRAPOLATE_CONSTANT, "CONSTANT", "Constant Extrapolation", ""},
769         {FCURVE_EXTRAPOLATE_LINEAR, "LINEAR", "Linear Extrapolation", ""},
770         {0, NULL, NULL, NULL}
771 };
772
773 /* this function is responsible for setting extrapolation mode for keyframes */
774 static void setexpo_graph_keys(bAnimContext *ac, short mode) 
775 {
776         ListBase anim_data = {NULL, NULL};
777         bAnimListElem *ale;
778         int filter;
779         
780         /* filter data */
781         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE| ANIMFILTER_FOREDIT | ANIMFILTER_CURVESONLY);
782         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
783         
784         /* loop through setting mode per F-Curve */
785         for (ale= anim_data.first; ale; ale= ale->next) {
786                 FCurve *fcu= (FCurve *)ale->data;
787                 fcu->extend= mode;
788         }
789         
790         /* cleanup */
791         BLI_freelistN(&anim_data);
792 }
793
794 /* ------------------- */
795
796 static int graphkeys_expo_exec(bContext *C, wmOperator *op)
797 {
798         bAnimContext ac;
799         short mode;
800         
801         /* get editor data */
802         if (ANIM_animdata_get_context(C, &ac) == 0)
803                 return OPERATOR_CANCELLED;
804                 
805         /* get handle setting mode */
806         mode= RNA_enum_get(op->ptr, "type");
807         
808         /* set handle type */
809         setexpo_graph_keys(&ac, mode);
810         
811         /* validate keyframes after editing */
812         ANIM_editkeyframes_refresh(&ac);
813         
814         /* set notifier tha things have changed */
815         ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_KEYFRAMES_VALUES);
816         
817         return OPERATOR_FINISHED;
818 }
819  
820 void GRAPHEDIT_OT_keyframes_extrapolation_type (wmOperatorType *ot)
821 {
822         /* identifiers */
823         ot->name= "Set Keyframe Extrapolation";
824         ot->idname= "GRAPHEDIT_OT_keyframes_extrapolation_type";
825         
826         /* api callbacks */
827         ot->invoke= WM_menu_invoke;
828         ot->exec= graphkeys_expo_exec;
829         ot->poll= ED_operator_areaactive;
830         
831         /* flags */
832         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
833         
834         /* id-props */
835         RNA_def_enum(ot->srna, "type", prop_graphkeys_expo_types, 0, "Type", "");
836 }
837
838 /* ******************** Set Interpolation-Type Operator *********************** */
839
840 /* defines for set ipo-type for selected keyframes tool */
841 EnumPropertyItem prop_graphkeys_ipo_types[] = {
842         {BEZT_IPO_CONST, "CONSTANT", "Constant Interpolation", ""},
843         {BEZT_IPO_LIN, "LINEAR", "Linear Interpolation", ""},
844         {BEZT_IPO_BEZ, "BEZIER", "Bezier Interpolation", ""},
845         {0, NULL, NULL, NULL}
846 };
847
848 /* this function is responsible for setting interpolation mode for keyframes */
849 static void setipo_graph_keys(bAnimContext *ac, short mode) 
850 {
851         ListBase anim_data = {NULL, NULL};
852         bAnimListElem *ale;
853         int filter;
854         BeztEditFunc set_cb= ANIM_editkeyframes_ipo(mode);
855         
856         /* filter data */
857         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE| ANIMFILTER_FOREDIT | ANIMFILTER_CURVESONLY);
858         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
859         
860         /* loop through setting BezTriple interpolation
861          * Note: we do not supply BeztEditData to the looper yet. Currently that's not necessary here...
862          */
863         for (ale= anim_data.first; ale; ale= ale->next)
864                 ANIM_fcurve_keys_bezier_loop(NULL, ale->key_data, NULL, set_cb, calchandles_fcurve);
865         
866         /* cleanup */
867         BLI_freelistN(&anim_data);
868 }
869
870 /* ------------------- */
871
872 static int graphkeys_ipo_exec(bContext *C, wmOperator *op)
873 {
874         bAnimContext ac;
875         short mode;
876         
877         /* get editor data */
878         if (ANIM_animdata_get_context(C, &ac) == 0)
879                 return OPERATOR_CANCELLED;
880                 
881         /* get handle setting mode */
882         mode= RNA_enum_get(op->ptr, "type");
883         
884         /* set handle type */
885         setipo_graph_keys(&ac, mode);
886         
887         /* validate keyframes after editing */
888         ANIM_editkeyframes_refresh(&ac);
889         
890         /* set notifier tha things have changed */
891         ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_KEYFRAMES_VALUES);
892         
893         return OPERATOR_FINISHED;
894 }
895  
896 void GRAPHEDIT_OT_keyframes_interpolation_type (wmOperatorType *ot)
897 {
898         /* identifiers */
899         ot->name= "Set Keyframe Interpolation";
900         ot->idname= "GRAPHEDIT_OT_keyframes_interpolation_type";
901         
902         /* api callbacks */
903         ot->invoke= WM_menu_invoke;
904         ot->exec= graphkeys_ipo_exec;
905         ot->poll= ED_operator_areaactive;
906         
907         /* flags */
908         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
909         
910         /* id-props */
911         RNA_def_enum(ot->srna, "type", prop_graphkeys_ipo_types, 0, "Type", "");
912 }
913
914 /* ******************** Set Handle-Type Operator *********************** */
915
916 /* defines for set handle-type for selected keyframes tool */
917 EnumPropertyItem prop_graphkeys_handletype_types[] = {
918         {HD_AUTO, "AUTO", "Auto Handles", ""},
919         {HD_VECT, "VECTOR", "Vector Handles", ""},
920         {HD_FREE, "FREE", "Free Handles", ""},
921         {HD_ALIGN, "ALIGN", "Aligned Handles", ""},
922 //      {-1, "TOGGLE", "Toggle between Free and Aligned Handles", ""},
923         {0, NULL, NULL, NULL}
924 };
925
926 /* this function is responsible for setting handle-type of selected keyframes */
927 static void sethandles_graph_keys(bAnimContext *ac, short mode) 
928 {
929         ListBase anim_data = {NULL, NULL};
930         bAnimListElem *ale;
931         int filter;
932         BeztEditFunc set_cb= ANIM_editkeyframes_handles(mode);
933         
934         /* filter data */
935         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE| ANIMFILTER_FOREDIT | ANIMFILTER_CURVESONLY);
936         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
937         
938         /* loop through setting flags for handles 
939          * Note: we do not supply BeztEditData to the looper yet. Currently that's not necessary here...
940          */
941         // XXX we might need to supply BeztEditData to get it to only affect selected handles
942         for (ale= anim_data.first; ale; ale= ale->next) {
943                 if (mode == -1) {       
944                         BeztEditFunc toggle_cb;
945                         
946                         /* check which type of handle to set (free or aligned) 
947                          *      - check here checks for handles with free alignment already
948                          */
949                         if (ANIM_fcurve_keys_bezier_loop(NULL, ale->key_data, NULL, set_cb, NULL))
950                                 toggle_cb= ANIM_editkeyframes_handles(HD_FREE);
951                         else
952                                 toggle_cb= ANIM_editkeyframes_handles(HD_ALIGN);
953                                 
954                         /* set handle-type */
955                         ANIM_fcurve_keys_bezier_loop(NULL, ale->key_data, NULL, toggle_cb, calchandles_fcurve);
956                 }
957                 else {
958                         /* directly set handle-type */
959                         ANIM_fcurve_keys_bezier_loop(NULL, ale->key_data, NULL, set_cb, calchandles_fcurve);
960                 }
961         }
962         
963         /* cleanup */
964         BLI_freelistN(&anim_data);
965 }
966
967 /* ------------------- */
968
969 static int graphkeys_handletype_exec(bContext *C, wmOperator *op)
970 {
971         bAnimContext ac;
972         short mode;
973         
974         /* get editor data */
975         if (ANIM_animdata_get_context(C, &ac) == 0)
976                 return OPERATOR_CANCELLED;
977                 
978         /* get handle setting mode */
979         mode= RNA_enum_get(op->ptr, "type");
980         
981         /* set handle type */
982         sethandles_graph_keys(&ac, mode);
983         
984         /* validate keyframes after editing */
985         ANIM_editkeyframes_refresh(&ac);
986         
987         /* set notifier tha things have changed */
988         ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_KEYFRAMES_VALUES);
989         
990         return OPERATOR_FINISHED;
991 }
992  
993 void GRAPHEDIT_OT_keyframes_handletype (wmOperatorType *ot)
994 {
995         /* identifiers */
996         ot->name= "Set Keyframe Handle Type";
997         ot->idname= "GRAPHEDIT_OT_keyframes_handletype";
998         
999         /* api callbacks */
1000         ot->invoke= WM_menu_invoke;
1001         ot->exec= graphkeys_handletype_exec;
1002         ot->poll= ED_operator_areaactive;
1003         
1004         /* flags */
1005         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1006         
1007         /* id-props */
1008         RNA_def_enum(ot->srna, "type", prop_graphkeys_handletype_types, 0, "Type", "");
1009 }
1010
1011 /* ************************************************************************** */
1012 /* TRANSFORM STUFF */
1013
1014 /* ***************** Snap Current Frame Operator *********************** */
1015
1016 /* helper callback for graphkeys_cfrasnap_exec() -> used to help get the average time of all selected beztriples */
1017 // TODO: if some other code somewhere needs this, it'll be time to port this over to keyframes_edit.c!!!
1018 static short bezt_calc_average(BeztEditData *bed, BezTriple *bezt)
1019 {
1020         /* only if selected */
1021         if (bezt->f2 & SELECT) {
1022                 /* store average time in float (only do rounding at last step */
1023                 bed->f1 += bezt->vec[1][0];
1024                 
1025                 /* increment number of items */
1026                 bed->i1++;
1027         }
1028         
1029         return 0;
1030 }
1031
1032 /* snap current-frame indicator to 'average time' of selected keyframe */
1033 static int graphkeys_cfrasnap_exec(bContext *C, wmOperator *op)
1034 {
1035         bAnimContext ac;
1036         ListBase anim_data= {NULL, NULL};
1037         bAnimListElem *ale;
1038         int filter;
1039         BeztEditData bed;
1040         
1041         /* get editor data */
1042         if (ANIM_animdata_get_context(C, &ac) == 0)
1043                 return OPERATOR_CANCELLED;
1044         
1045         /* init edit data */
1046         memset(&bed, 0, sizeof(BeztEditData));
1047         
1048         /* loop over action data, averaging values */
1049         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE| ANIMFILTER_CURVESONLY);
1050         ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
1051         
1052         for (ale= anim_data.first; ale; ale= ale->next)
1053                 ANIM_fcurve_keys_bezier_loop(&bed, ale->key_data, NULL, bezt_calc_average, NULL);
1054         
1055         BLI_freelistN(&anim_data);
1056         
1057         /* set the new current frame value, based on the average time */
1058         if (bed.i1) {
1059                 Scene *scene= ac.scene;
1060                 CFRA= (int)floor((bed.f1 / bed.i1) + 0.5f);
1061         }
1062         
1063         /* set notifier tha things have changed */
1064         WM_event_add_notifier(C, NC_SCENE|ND_FRAME, ac.scene);
1065         
1066         return OPERATOR_FINISHED;
1067 }
1068
1069 void GRAPHEDIT_OT_keyframes_cfrasnap (wmOperatorType *ot)
1070 {
1071         /* identifiers */
1072         ot->name= "Snap Current Frame to Keys";
1073         ot->idname= "GRAPHEDIT_OT_keyframes_cfrasnap";
1074         
1075         /* api callbacks */
1076         ot->exec= graphkeys_cfrasnap_exec;
1077         ot->poll= ED_operator_areaactive;
1078         
1079         /* flags */
1080         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1081 }
1082
1083 /* ******************** Snap Keyframes Operator *********************** */
1084
1085 /* defines for snap keyframes tool */
1086 EnumPropertyItem prop_graphkeys_snap_types[] = {
1087         {GRAPHKEYS_SNAP_CFRA, "CFRA", "Current frame", ""},
1088         {GRAPHKEYS_SNAP_NEAREST_FRAME, "NEAREST_FRAME", "Nearest Frame", ""}, // XXX as single entry?
1089         {GRAPHKEYS_SNAP_NEAREST_SECOND, "NEAREST_SECOND", "Nearest Second", ""}, // XXX as single entry?
1090         {GRAPHKEYS_SNAP_NEAREST_MARKER, "NEAREST_MARKER", "Nearest Marker", ""},
1091         {GRAPHKEYS_SNAP_HORIZONTAL, "HORIZONTAL", "Flatten Handles", ""},
1092         {0, NULL, NULL, NULL}
1093 };
1094
1095 /* this function is responsible for snapping keyframes to frame-times */
1096 static void snap_graph_keys(bAnimContext *ac, short mode) 
1097 {
1098         ListBase anim_data = {NULL, NULL};
1099         bAnimListElem *ale;
1100         int filter;
1101         
1102         BeztEditData bed;
1103         BeztEditFunc edit_cb;
1104         
1105         /* filter data */
1106         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE| ANIMFILTER_FOREDIT | ANIMFILTER_CURVESONLY);
1107         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
1108         
1109         /* get beztriple editing callbacks */
1110         edit_cb= ANIM_editkeyframes_snap(mode);
1111         
1112         memset(&bed, 0, sizeof(BeztEditData)); 
1113         bed.scene= ac->scene;
1114         
1115         /* snap keyframes */
1116         for (ale= anim_data.first; ale; ale= ale->next) {
1117                 Object *nob= ANIM_nla_mapping_get(ac, ale);
1118                 
1119                 if (nob) {
1120                         ANIM_nla_mapping_apply_fcurve(nob, ale->key_data, 0, 1); 
1121                         ANIM_fcurve_keys_bezier_loop(&bed, ale->key_data, NULL, edit_cb, calchandles_fcurve);
1122                         ANIM_nla_mapping_apply_fcurve(nob, ale->key_data, 1, 1);
1123                 }
1124                 else 
1125                         ANIM_fcurve_keys_bezier_loop(&bed, ale->key_data, NULL, edit_cb, calchandles_fcurve);
1126         }
1127         BLI_freelistN(&anim_data);
1128 }
1129
1130 /* ------------------- */
1131
1132 static int graphkeys_snap_exec(bContext *C, wmOperator *op)
1133 {
1134         bAnimContext ac;
1135         short mode;
1136         
1137         /* get editor data */
1138         if (ANIM_animdata_get_context(C, &ac) == 0)
1139                 return OPERATOR_CANCELLED;
1140                 
1141         /* get snapping mode */
1142         mode= RNA_enum_get(op->ptr, "type");
1143         
1144         /* snap keyframes */
1145         snap_graph_keys(&ac, mode);
1146         
1147         /* validate keyframes after editing */
1148         ANIM_editkeyframes_refresh(&ac);
1149         
1150         /* set notifier tha things have changed */
1151         ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_KEYFRAMES_VALUES);
1152         
1153         return OPERATOR_FINISHED;
1154 }
1155  
1156 void GRAPHEDIT_OT_keyframes_snap (wmOperatorType *ot)
1157 {
1158         /* identifiers */
1159         ot->name= "Snap Keys";
1160         ot->idname= "GRAPHEDIT_OT_keyframes_snap";
1161         
1162         /* api callbacks */
1163         ot->invoke= WM_menu_invoke;
1164         ot->exec= graphkeys_snap_exec;
1165         ot->poll= ED_operator_areaactive;
1166         
1167         /* flags */
1168         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1169         
1170         /* id-props */
1171         RNA_def_enum(ot->srna, "type", prop_graphkeys_snap_types, 0, "Type", "");
1172 }
1173
1174 /* ******************** Mirror Keyframes Operator *********************** */
1175
1176 /* defines for mirror keyframes tool */
1177 EnumPropertyItem prop_graphkeys_mirror_types[] = {
1178         {GRAPHKEYS_MIRROR_CFRA, "CFRA", "Current frame", ""},
1179         {GRAPHKEYS_MIRROR_YAXIS, "YAXIS", "Vertical Axis", ""},
1180         {GRAPHKEYS_MIRROR_XAXIS, "XAXIS", "Horizontal Axis", ""},
1181         {GRAPHKEYS_MIRROR_MARKER, "MARKER", "First Selected Marker", ""},
1182         {0, NULL, NULL, NULL}
1183 };
1184
1185 /* this function is responsible for mirroring keyframes */
1186 static void mirror_graph_keys(bAnimContext *ac, short mode) 
1187 {
1188         ListBase anim_data = {NULL, NULL};
1189         bAnimListElem *ale;
1190         int filter;
1191         
1192         BeztEditData bed;
1193         BeztEditFunc edit_cb;
1194         
1195         /* get beztriple editing callbacks */
1196         edit_cb= ANIM_editkeyframes_mirror(mode);
1197         
1198         memset(&bed, 0, sizeof(BeztEditData)); 
1199         bed.scene= ac->scene;
1200         
1201         /* for 'first selected marker' mode, need to find first selected marker first! */
1202         // XXX should this be made into a helper func in the API?
1203         if (mode == GRAPHKEYS_MIRROR_MARKER) {
1204                 Scene *scene= ac->scene;
1205                 TimeMarker *marker= NULL;
1206                 
1207                 /* find first selected marker */
1208                 for (marker= scene->markers.first; marker; marker=marker->next) {
1209                         if (marker->flag & SELECT) {
1210                                 break;
1211                         }
1212                 }
1213                 
1214                 /* store marker's time (if available) */
1215                 if (marker)
1216                         bed.f1= (float)marker->frame;
1217                 else
1218                         return;
1219         }
1220         
1221         /* filter data */
1222         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE| ANIMFILTER_FOREDIT | ANIMFILTER_CURVESONLY);
1223         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
1224         
1225         /* mirror keyframes */
1226         for (ale= anim_data.first; ale; ale= ale->next) {
1227                 Object *nob= ANIM_nla_mapping_get(ac, ale);
1228                 
1229                 if (nob) {
1230                         ANIM_nla_mapping_apply_fcurve(nob, ale->key_data, 0, 1); 
1231                         ANIM_fcurve_keys_bezier_loop(&bed, ale->key_data, NULL, edit_cb, calchandles_fcurve);
1232                         ANIM_nla_mapping_apply_fcurve(nob, ale->key_data, 1, 1);
1233                 }
1234                 else 
1235                         ANIM_fcurve_keys_bezier_loop(&bed, ale->key_data, NULL, edit_cb, calchandles_fcurve);
1236         }
1237         BLI_freelistN(&anim_data);
1238 }
1239
1240 /* ------------------- */
1241
1242 static int graphkeys_mirror_exec(bContext *C, wmOperator *op)
1243 {
1244         bAnimContext ac;
1245         short mode;
1246         
1247         /* get editor data */
1248         if (ANIM_animdata_get_context(C, &ac) == 0)
1249                 return OPERATOR_CANCELLED;
1250                 
1251         /* get mirroring mode */
1252         mode= RNA_enum_get(op->ptr, "type");
1253         
1254         /* mirror keyframes */
1255         mirror_graph_keys(&ac, mode);
1256         
1257         /* validate keyframes after editing */
1258         ANIM_editkeyframes_refresh(&ac);
1259         
1260         /* set notifier tha things have changed */
1261         ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_KEYFRAMES_VALUES);
1262         
1263         return OPERATOR_FINISHED;
1264 }
1265  
1266 void GRAPHEDIT_OT_keyframes_mirror (wmOperatorType *ot)
1267 {
1268         /* identifiers */
1269         ot->name= "Mirror Keys";
1270         ot->idname= "GRAPHEDIT_OT_keyframes_mirror";
1271         
1272         /* api callbacks */
1273         ot->invoke= WM_menu_invoke;
1274         ot->exec= graphkeys_mirror_exec;
1275         ot->poll= ED_operator_areaactive;
1276         
1277         /* flags */
1278         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1279         
1280         /* id-props */
1281         RNA_def_enum(ot->srna, "type", prop_graphkeys_mirror_types, 0, "Type", "");
1282 }
1283
1284 /* ******************** Smooth Keyframes Operator *********************** */
1285
1286 static int graphkeys_smooth_exec(bContext *C, wmOperator *op)
1287 {
1288         bAnimContext ac;
1289         ListBase anim_data = {NULL, NULL};
1290         bAnimListElem *ale;
1291         int filter;
1292         
1293         /* get editor data */
1294         if (ANIM_animdata_get_context(C, &ac) == 0)
1295                 return OPERATOR_CANCELLED;
1296         
1297         /* filter data */
1298         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE| ANIMFILTER_FOREDIT | ANIMFILTER_CURVESONLY);
1299         ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
1300         
1301         /* smooth keyframes */
1302         for (ale= anim_data.first; ale; ale= ale->next) {
1303                 /* For now, we can only smooth by flattening handles AND smoothing curve values.
1304                  * Perhaps the mode argument could be removed, as that functionality is offerred through 
1305                  * Snap->Flatten Handles anyway.
1306                  */
1307                 smooth_fcurve(ale->key_data);
1308         }
1309         BLI_freelistN(&anim_data);
1310         
1311         /* validate keyframes after editing */
1312         ANIM_editkeyframes_refresh(&ac);
1313         
1314         /* set notifier tha things have changed */
1315         ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_KEYFRAMES_VALUES);
1316         
1317         return OPERATOR_FINISHED;
1318 }
1319  
1320 void GRAPHEDIT_OT_keyframes_smooth (wmOperatorType *ot)
1321 {
1322         /* identifiers */
1323         ot->name= "Smooth Keys";
1324         ot->idname= "GRAPHEDIT_OT_keyframes_smooth";
1325         
1326         /* api callbacks */
1327         ot->exec= graphkeys_smooth_exec;
1328         ot->poll= ED_operator_areaactive;
1329         
1330         /* flags */
1331         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1332 }
1333
1334 /* ************************************************************************** */