batch remove .'s used with RNA_def_struct_ui_text
[blender.git] / source / blender / editors / space_graph / graph_edit.c
1 /**
2  * $Id$
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 "AUD_C-API.h"
40
41 #include "MEM_guardedalloc.h"
42
43 #include "BLI_blenlib.h"
44 #include "BLI_math.h"
45
46 #include "DNA_anim_types.h"
47 #include "DNA_action_types.h"
48 #include "DNA_armature_types.h"
49 #include "DNA_camera_types.h"
50 #include "DNA_curve_types.h"
51 #include "DNA_object_types.h"
52 #include "DNA_screen_types.h"
53 #include "DNA_scene_types.h"
54 #include "DNA_space_types.h"
55 #include "DNA_constraint_types.h"
56 #include "DNA_key_types.h"
57 #include "DNA_lamp_types.h"
58 #include "DNA_material_types.h"
59 #include "DNA_userdef_types.h"
60 #include "DNA_gpencil_types.h"
61 #include "DNA_windowmanager_types.h"
62
63 #include "RNA_access.h"
64 #include "RNA_define.h"
65 #include "RNA_enum_types.h"
66
67 #include "BKE_action.h"
68 #include "BKE_depsgraph.h"
69 #include "BKE_fcurve.h"
70 #include "BKE_key.h"
71 #include "BKE_material.h"
72 #include "BKE_nla.h"
73 #include "BKE_object.h"
74 #include "BKE_context.h"
75 #include "BKE_report.h"
76 #include "BKE_utildefines.h"
77
78 #include "UI_interface.h"
79 #include "UI_view2d.h"
80
81 #include "ED_anim_api.h"
82 #include "ED_keyframing.h"
83 #include "ED_keyframes_draw.h"
84 #include "ED_keyframes_edit.h"
85 #include "ED_screen.h"
86 #include "ED_space_api.h"
87 #include "ED_transform.h"
88
89 #include "WM_api.h"
90 #include "WM_types.h"
91
92 #include "graph_intern.h"
93
94 /* ************************************************************************** */
95 /* KEYFRAME-RANGE STUFF */
96
97 /* *************************** Calculate Range ************************** */
98
99 /* Get the min/max keyframes*/
100 /* note: it should return total boundbox, filter for selection only can be argument... */
101 void get_graph_keyframe_extents (bAnimContext *ac, float *xmin, float *xmax, float *ymin, float *ymax)
102 {
103         ListBase anim_data = {NULL, NULL};
104         bAnimListElem *ale;
105         int filter;
106         
107         /* get data to filter, from Dopesheet */
108         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE | ANIMFILTER_CURVESONLY);
109         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
110         
111         /* set large values to try to override */
112         if (xmin) *xmin= 999999999.0f;
113         if (xmax) *xmax= -999999999.0f;
114         if (ymin) *ymin= 999999999.0f;
115         if (ymax) *ymax= -999999999.0f;
116         
117         /* check if any channels to set range with */
118         if (anim_data.first) {
119                 /* go through channels, finding max extents */
120                 for (ale= anim_data.first; ale; ale= ale->next) {
121                         AnimData *adt= ANIM_nla_mapping_get(ac, ale);
122                         FCurve *fcu= (FCurve *)ale->key_data;
123                         float txmin, txmax, tymin, tymax;
124                         float unitFac;
125                         
126                         /* get range */
127                         calc_fcurve_bounds(fcu, &txmin, &txmax, &tymin, &tymax);
128                         
129                         /* apply NLA scaling */
130                         if (adt) {
131                                 txmin= BKE_nla_tweakedit_remap(adt, txmin, NLATIME_CONVERT_MAP);
132                                 txmax= BKE_nla_tweakedit_remap(adt, txmax, NLATIME_CONVERT_MAP);
133                         }
134                         
135                         /* apply unit corrections */
136                         unitFac= ANIM_unit_mapping_get_factor(ac->scene, ale->id, fcu, 0);
137                         tymin *= unitFac;
138                         tymax *= unitFac;
139                         
140                         /* try to set cur using these values, if they're more extreme than previously set values */
141                         if ((xmin) && (txmin < *xmin))          *xmin= txmin;
142                         if ((xmax) && (txmax > *xmax))          *xmax= txmax;
143                         if ((ymin) && (tymin < *ymin))          *ymin= tymin;
144                         if ((ymax) && (tymax > *ymax))          *ymax= tymax;
145                 }
146                 
147                 /* free memory */
148                 BLI_freelistN(&anim_data);
149         }
150         else {
151                 /* set default range */
152                 if (ac->scene) {
153                         if (xmin) *xmin= (float)ac->scene->r.sfra;
154                         if (xmax) *xmax= (float)ac->scene->r.efra;
155                 }
156                 else {
157                         if (xmin) *xmin= -5;
158                         if (xmax) *xmax= 100;
159                 }
160                 
161                 if (ymin) *ymin= -5;
162                 if (ymax) *ymax= 5;
163         }
164 }
165
166 /* ****************** Automatic Preview-Range Operator ****************** */
167
168 static int graphkeys_previewrange_exec(bContext *C, wmOperator *op)
169 {
170         bAnimContext ac;
171         Scene *scene;
172         float min, max;
173         
174         /* get editor data */
175         if (ANIM_animdata_get_context(C, &ac) == 0)
176                 return OPERATOR_CANCELLED;
177         if (ac.scene == NULL)
178                 return OPERATOR_CANCELLED;
179         else
180                 scene= ac.scene;
181         
182         /* set the range directly */
183         get_graph_keyframe_extents(&ac, &min, &max, NULL, NULL);
184         scene->r.flag |= SCER_PRV_RANGE;
185         scene->r.psfra= (int)floor(min + 0.5f);
186         scene->r.pefra= (int)floor(max + 0.5f);
187         
188         /* set notifier that things have changed */
189         // XXX err... there's nothing for frame ranges yet, but this should do fine too
190         WM_event_add_notifier(C, NC_SCENE|ND_FRAME, ac.scene); 
191         
192         return OPERATOR_FINISHED;
193 }
194  
195 void GRAPH_OT_previewrange_set (wmOperatorType *ot)
196 {
197         /* identifiers */
198         ot->name= "Auto-Set Preview Range";
199         ot->idname= "GRAPH_OT_previewrange_set";
200         
201         /* api callbacks */
202         ot->exec= graphkeys_previewrange_exec;
203         ot->poll= graphop_visible_keyframes_poll;
204         
205         /* flags */
206         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
207 }
208
209 /* ****************** View-All Operator ****************** */
210
211 static int graphkeys_viewall_exec(bContext *C, wmOperator *op)
212 {
213         bAnimContext ac;
214         View2D *v2d;
215         float extra;
216         
217         /* get editor data */
218         if (ANIM_animdata_get_context(C, &ac) == 0)
219                 return OPERATOR_CANCELLED;
220         v2d= &ac.ar->v2d;
221         
222         /* set the horizontal range, with an extra offset so that the extreme keys will be in view */
223         get_graph_keyframe_extents(&ac, &v2d->cur.xmin, &v2d->cur.xmax, &v2d->cur.ymin, &v2d->cur.ymax);
224         
225         extra= 0.1f * (v2d->cur.xmax - v2d->cur.xmin);
226         v2d->cur.xmin -= extra;
227         v2d->cur.xmax += extra;
228         
229         extra= 0.1f * (v2d->cur.ymax - v2d->cur.ymin);
230         v2d->cur.ymin -= extra;
231         v2d->cur.ymax += extra;
232         
233         /* do View2D syncing */
234         UI_view2d_sync(CTX_wm_screen(C), CTX_wm_area(C), v2d, V2D_LOCK_COPY);
235         
236         /* set notifier that things have changed */
237         ED_area_tag_redraw(CTX_wm_area(C));
238         
239         return OPERATOR_FINISHED;
240 }
241  
242 void GRAPH_OT_view_all (wmOperatorType *ot)
243 {
244         /* identifiers */
245         ot->name= "View All";
246         ot->idname= "GRAPH_OT_view_all";
247         ot->description= "Reset viewable area to show full keyframe range";
248         
249         /* api callbacks */
250         ot->exec= graphkeys_viewall_exec;
251         ot->poll= graphop_visible_keyframes_poll;
252         
253         /* flags */
254         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
255 }
256
257 /* ******************** Create Ghost-Curves Operator *********************** */
258 /* This operator samples the data of the selected F-Curves to F-Points, storing them
259  * as 'ghost curves' in the active Graph Editor
260  */
261
262 /* Bake each F-Curve into a set of samples, and store as a ghost curve */
263 static void create_ghost_curves (bAnimContext *ac, int start, int end)
264 {       
265         SpaceIpo *sipo= (SpaceIpo *)ac->sa->spacedata.first;
266         ListBase anim_data = {NULL, NULL};
267         bAnimListElem *ale;
268         int filter;
269         
270         /* free existing ghost curves */
271         free_fcurves(&sipo->ghostCurves);
272         
273         /* sanity check */
274         if (start >= end) {
275                 printf("Error: Frame range for Ghost F-Curve creation is inappropriate \n");
276                 return;
277         }
278         
279         /* filter data */
280         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE | ANIMFILTER_SEL | ANIMFILTER_CURVESONLY);
281         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
282         
283         /* loop through filtered data and add keys between selected keyframes on every frame  */
284         for (ale= anim_data.first; ale; ale= ale->next) {
285                 FCurve *fcu= (FCurve *)ale->key_data;
286                 FCurve *gcu= MEM_callocN(sizeof(FCurve), "Ghost FCurve");
287                 AnimData *adt= ANIM_nla_mapping_get(ac, ale);
288                 ChannelDriver *driver= fcu->driver;
289                 FPoint *fpt;
290                 float unitFac;
291                 int cfra;               
292                 
293                 /* disable driver so that it don't muck up the sampling process */
294                 fcu->driver= NULL;
295                 
296                 /* calculate unit-mapping factor */
297                 unitFac= ANIM_unit_mapping_get_factor(ac->scene, ale->id, fcu, 0);
298                 
299                 /* create samples, but store them in a new curve 
300                  *      - we cannot use fcurve_store_samples() as that will only overwrite the original curve 
301                  */
302                 gcu->fpt= fpt= MEM_callocN(sizeof(FPoint)*(end-start+1), "Ghost FPoint Samples");
303                 gcu->totvert= end - start + 1;
304                 
305                 /* use the sampling callback at 1-frame intervals from start to end frames */
306                 for (cfra= start; cfra <= end; cfra++, fpt++) {
307                         float cfrae= BKE_nla_tweakedit_remap(adt, cfra, NLATIME_CONVERT_UNMAP);
308                         
309                         fpt->vec[0]= cfrae;
310                         fpt->vec[1]= fcurve_samplingcb_evalcurve(fcu, NULL, cfrae);
311                 }
312                 
313                 /* set color of ghost curve 
314                  *      - make the color slightly darker
315                  */
316                 gcu->color[0]= fcu->color[0] - 0.07f;
317                 gcu->color[1]= fcu->color[1] - 0.07f;
318                 gcu->color[2]= fcu->color[2] - 0.07f;
319                 
320                 /* store new ghost curve */
321                 BLI_addtail(&sipo->ghostCurves, gcu);
322                 
323                 /* restore driver */
324                 fcu->driver= driver;
325         }
326         
327         /* admin and redraws */
328         BLI_freelistN(&anim_data);
329 }
330
331 /* ------------------- */
332
333 static int graphkeys_create_ghostcurves_exec(bContext *C, wmOperator *op)
334 {
335         bAnimContext ac;
336         View2D *v2d;
337         int start, end;
338         
339         /* get editor data */
340         if (ANIM_animdata_get_context(C, &ac) == 0)
341                 return OPERATOR_CANCELLED;
342                 
343         /* ghost curves are snapshots of the visible portions of the curves, so set range to be the visible range */
344         v2d= &ac.ar->v2d;
345         start= (int)v2d->cur.xmin;
346         end= (int)v2d->cur.xmax;
347         
348         /* bake selected curves into a ghost curve */
349         create_ghost_curves(&ac, start, end);
350         
351         /* update this editor only */
352         ED_area_tag_redraw(CTX_wm_area(C));
353         
354         return OPERATOR_FINISHED;
355 }
356  
357 void GRAPH_OT_ghost_curves_create (wmOperatorType *ot)
358 {
359         /* identifiers */
360         ot->name= "Create Ghost Curves";
361         ot->idname= "GRAPH_OT_ghost_curves_create";
362         ot->description= "Create snapshot (Ghosts) of selected F-Curves as background aid for active Graph Editor";
363         
364         /* api callbacks */
365         ot->exec= graphkeys_create_ghostcurves_exec;
366         ot->poll= graphop_visible_keyframes_poll;
367         
368         /* flags */
369         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
370         
371         // todo: add props for start/end frames
372 }
373
374 /* ******************** Clear Ghost-Curves Operator *********************** */
375 /* This operator clears the 'ghost curves' for the active Graph Editor */
376
377 static int graphkeys_clear_ghostcurves_exec(bContext *C, wmOperator *op)
378 {
379         bAnimContext ac;
380         SpaceIpo *sipo;
381         
382         /* get editor data */
383         if (ANIM_animdata_get_context(C, &ac) == 0)
384                 return OPERATOR_CANCELLED;
385         sipo= (SpaceIpo *)ac.sa->spacedata.first;
386                 
387         /* if no ghost curves, don't do anything */
388         if (sipo->ghostCurves.first == NULL)
389                 return OPERATOR_CANCELLED;
390         
391         /* free ghost curves */
392         free_fcurves(&sipo->ghostCurves);
393         
394         /* update this editor only */
395         ED_area_tag_redraw(CTX_wm_area(C));
396         
397         return OPERATOR_FINISHED;
398 }
399  
400 void GRAPH_OT_ghost_curves_clear (wmOperatorType *ot)
401 {
402         /* identifiers */
403         ot->name= "Clear Ghost Curves";
404         ot->idname= "GRAPH_OT_ghost_curves_clear";
405         ot->description= "Clear F-Curve snapshots (Ghosts) for active Graph Editor";
406         
407         /* api callbacks */
408         ot->exec= graphkeys_clear_ghostcurves_exec;
409         ot->poll= ED_operator_ipo_active;
410         
411         /* flags */
412         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
413 }
414
415 /* ************************************************************************** */
416 /* GENERAL STUFF */
417
418 /* ******************** Insert Keyframes Operator ************************* */
419
420 /* defines for insert keyframes tool */
421 EnumPropertyItem prop_graphkeys_insertkey_types[] = {
422         {1, "ALL", 0, "All Channels", ""},
423         {2, "SEL", 0, "Only Selected Channels", ""},
424         {0, NULL, 0, NULL, NULL}
425 };
426
427 /* this function is responsible for snapping keyframes to frame-times */
428 static void insert_graph_keys(bAnimContext *ac, short mode) 
429 {
430         ListBase anim_data = {NULL, NULL};
431         bAnimListElem *ale;
432         int filter;
433         
434         Scene *scene= ac->scene;
435         float cfra= (float)CFRA;
436         short flag = 0;
437         
438         /* filter data */
439         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_CURVESONLY);
440         if (mode == 2) filter |= ANIMFILTER_SEL;
441         
442         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
443         
444         /* init keyframing flag */
445         flag = ANIM_get_keyframing_flags(scene, 1);
446         
447         /* insert keyframes */
448         for (ale= anim_data.first; ale; ale= ale->next) {
449                 AnimData *adt= ANIM_nla_mapping_get(ac, ale);
450                 FCurve *fcu= (FCurve *)ale->key_data;
451                 
452                 /* adjust current frame for NLA-mapping */
453                 if (adt)
454                         cfra= BKE_nla_tweakedit_remap(adt, (float)CFRA, NLATIME_CONVERT_UNMAP);
455                 else 
456                         cfra= (float)CFRA;
457                         
458                 /* if there's an id */
459                 if (ale->id)
460                         insert_keyframe(ale->id, NULL, ((fcu->grp)?(fcu->grp->name):(NULL)), fcu->rna_path, fcu->array_index, cfra, flag);
461                 else
462                         insert_vert_fcurve(fcu, cfra, fcu->curval, 0);
463         }
464         
465         BLI_freelistN(&anim_data);
466 }
467
468 /* ------------------- */
469
470 static int graphkeys_insertkey_exec(bContext *C, wmOperator *op)
471 {
472         bAnimContext ac;
473         short mode;
474         
475         /* get editor data */
476         if (ANIM_animdata_get_context(C, &ac) == 0)
477                 return OPERATOR_CANCELLED;
478         if (ac.datatype == ANIMCONT_GPENCIL)
479                 return OPERATOR_CANCELLED;
480                 
481         /* which channels to affect? */
482         mode= RNA_enum_get(op->ptr, "type");
483         
484         /* insert keyframes */
485         insert_graph_keys(&ac, mode);
486         
487         /* validate keyframes after editing */
488         ANIM_editkeyframes_refresh(&ac);
489         
490         /* set notifier that keyframes have changed */
491         WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME_EDIT, NULL);
492         
493         return OPERATOR_FINISHED;
494 }
495
496 void GRAPH_OT_keyframe_insert (wmOperatorType *ot)
497 {
498         /* identifiers */
499         ot->name= "Insert Keyframes";
500         ot->idname= "GRAPH_OT_keyframe_insert";
501         ot->description= "Insert keyframes for the specified channels";
502         
503         /* api callbacks */
504         ot->invoke= WM_menu_invoke;
505         ot->exec= graphkeys_insertkey_exec;
506         ot->poll= graphop_editable_keyframes_poll;
507         
508         /* flags */
509         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
510         
511         /* id-props */
512         ot->prop= RNA_def_enum(ot->srna, "type", prop_graphkeys_insertkey_types, 0, "Type", "");
513 }
514
515 /* ******************** Click-Insert Keyframes Operator ************************* */
516
517 static int graphkeys_click_insert_exec (bContext *C, wmOperator *op)
518 {
519         bAnimContext ac;
520         bAnimListElem *ale;
521         AnimData *adt;
522         FCurve *fcu;
523         float frame, val;
524         
525         /* get animation context */
526         if (ANIM_animdata_get_context(C, &ac) == 0)
527                 return OPERATOR_CANCELLED;
528         
529         /* get active F-Curve 'anim-list-element' */
530         ale= get_active_fcurve_channel(&ac);
531         if (ELEM(NULL, ale, ale->data)) {
532                 if (ale) MEM_freeN(ale);
533                 return OPERATOR_CANCELLED;
534         }
535         fcu = ale->data;
536         
537         /* get frame and value from props */
538         frame= RNA_float_get(op->ptr, "frame");
539         val= RNA_float_get(op->ptr, "value");
540         
541         /* apply inverse NLA-mapping to frame to get correct time in un-scaled action */
542         adt= ANIM_nla_mapping_get(&ac, ale);
543         frame= BKE_nla_tweakedit_remap(adt, frame, NLATIME_CONVERT_UNMAP);
544         
545         /* apply inverse unit-mapping to value to get correct value for F-Curves */
546         val *= ANIM_unit_mapping_get_factor(ac.scene, ale->id, fcu, 1);
547         
548         /* insert keyframe on the specified frame + value */
549         insert_vert_fcurve(fcu, frame, val, 0);
550         
551         /* free temp data */
552         MEM_freeN(ale);
553         
554         /* set notifier that keyframes have changed */
555         WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME_EDIT, NULL);
556         
557         /* done */
558         return OPERATOR_FINISHED;
559 }
560
561 static int graphkeys_click_insert_invoke (bContext *C, wmOperator *op, wmEvent *evt)
562 {
563         bAnimContext ac;
564         ARegion *ar;
565         View2D *v2d;
566         int mval[2];
567         float x, y;
568         
569         /* get animation context */
570         if (ANIM_animdata_get_context(C, &ac) == 0)
571                 return OPERATOR_CANCELLED;
572         
573         /* store mouse coordinates in View2D space, into the operator's properties */
574         ar= ac.ar;
575         v2d= &ar->v2d;
576         
577         mval[0]= (evt->x - ar->winrct.xmin);
578         mval[1]= (evt->y - ar->winrct.ymin);
579         
580         UI_view2d_region_to_view(v2d, mval[0], mval[1], &x, &y);
581         
582         RNA_float_set(op->ptr, "frame", x);
583         RNA_float_set(op->ptr, "value", y);
584         
585         /* run exec now */
586         return graphkeys_click_insert_exec(C, op);
587 }
588
589 void GRAPH_OT_click_insert (wmOperatorType *ot)
590 {
591         /* identifiers */
592         ot->name= "Click-Insert Keyframes";
593         ot->idname= "GRAPH_OT_click_insert";
594         ot->description= "Insert new keyframe at the cursor position for the active F-Curve";
595         
596         /* api callbacks */
597         ot->invoke= graphkeys_click_insert_invoke;
598         ot->exec= graphkeys_click_insert_exec;
599         ot->poll= graphop_active_fcurve_poll;
600         
601         /* flags */
602         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
603         
604         /* properties */
605         RNA_def_float(ot->srna, "frame", 1.0f, -FLT_MAX, FLT_MAX, "Frame Number", "Frame to insert keyframe on", 0, 100);
606         RNA_def_float(ot->srna, "value", 1.0f, -FLT_MAX, FLT_MAX, "Value", "Value for keyframe on", 0, 100);
607 }
608
609 /* ******************** Copy/Paste Keyframes Operator ************************* */
610 /* NOTE: the backend code for this is shared with the dopesheet editor */
611
612 static short copy_graph_keys (bAnimContext *ac)
613 {       
614         ListBase anim_data = {NULL, NULL};
615         int filter, ok=0;
616         
617         /* clear buffer first */
618         free_anim_copybuf();
619         
620         /* filter data */
621         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE | ANIMFILTER_CURVESONLY);
622         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
623         
624         /* copy keyframes */
625         ok= copy_animedit_keys(ac, &anim_data);
626         
627         /* clean up */
628         BLI_freelistN(&anim_data);
629
630         return ok;
631 }
632
633 static short paste_graph_keys (bAnimContext *ac)
634 {       
635         ListBase anim_data = {NULL, NULL};
636         int filter, ok=0;
637         
638         /* filter data */
639         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE | ANIMFILTER_SEL | ANIMFILTER_FOREDIT | ANIMFILTER_CURVESONLY);
640         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
641         
642         /* paste keyframes */
643         ok= paste_animedit_keys(ac, &anim_data);
644         
645         /* clean up */
646         BLI_freelistN(&anim_data);
647
648         return ok;
649 }
650
651 /* ------------------- */
652
653 static int graphkeys_copy_exec(bContext *C, wmOperator *op)
654 {
655         bAnimContext ac;
656         
657         /* get editor data */
658         if (ANIM_animdata_get_context(C, &ac) == 0)
659                 return OPERATOR_CANCELLED;
660         
661         /* copy keyframes */
662         if (copy_graph_keys(&ac)) {     
663                 BKE_report(op->reports, RPT_ERROR, "No keyframes copied to keyframes copy/paste buffer");
664                 return OPERATOR_CANCELLED;
665         }
666         
667         /* just return - no operator needed here (no changes) */
668         return OPERATOR_FINISHED;
669 }
670  
671 void GRAPH_OT_copy (wmOperatorType *ot)
672 {
673         /* identifiers */
674         ot->name= "Copy Keyframes";
675         ot->idname= "GRAPH_OT_copy";
676         ot->description= "Copy selected keyframes to the copy/paste buffer";
677         
678         /* api callbacks */
679         ot->exec= graphkeys_copy_exec;
680         ot->poll= graphop_editable_keyframes_poll;
681         
682         /* flags */
683         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
684 }
685
686
687
688 static int graphkeys_paste_exec(bContext *C, wmOperator *op)
689 {
690         bAnimContext ac;
691         
692         /* get editor data */
693         if (ANIM_animdata_get_context(C, &ac) == 0)
694                 return OPERATOR_CANCELLED;
695         
696         /* paste keyframes */
697         if (paste_graph_keys(&ac)) {
698                 BKE_report(op->reports, RPT_ERROR, "No keyframes to paste");
699                 return OPERATOR_CANCELLED;
700         }
701         
702         /* validate keyframes after editing */
703         ANIM_editkeyframes_refresh(&ac);
704         
705         /* set notifier that keyframes have changed */
706         WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME_EDIT, NULL);
707         
708         return OPERATOR_FINISHED;
709 }
710  
711 void GRAPH_OT_paste (wmOperatorType *ot)
712 {
713         /* identifiers */
714         ot->name= "Paste Keyframes";
715         ot->idname= "GRAPH_OT_paste";
716         ot->description= "Paste keyframes from copy/paste buffer for the selected channels, starting on the current frame";
717         
718         /* api callbacks */
719         ot->exec= graphkeys_paste_exec;
720         ot->poll= graphop_editable_keyframes_poll;
721         
722         /* flags */
723         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
724 }
725
726 /* ******************** Duplicate Keyframes Operator ************************* */
727
728 static void duplicate_graph_keys (bAnimContext *ac)
729 {
730         ListBase anim_data = {NULL, NULL};
731         bAnimListElem *ale;
732         int filter;
733         
734         /* filter data */
735         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE| ANIMFILTER_FOREDIT | ANIMFILTER_CURVESONLY);
736         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
737         
738         /* loop through filtered data and delete selected keys */
739         for (ale= anim_data.first; ale; ale= ale->next) {
740                 duplicate_fcurve_keys((FCurve *)ale->key_data);
741         }
742         
743         /* free filtered list */
744         BLI_freelistN(&anim_data);
745 }
746
747 /* ------------------- */
748
749 static int graphkeys_duplicate_exec(bContext *C, wmOperator *op)
750 {
751         bAnimContext ac;
752         
753         /* get editor data */
754         if (ANIM_animdata_get_context(C, &ac) == 0)
755                 return OPERATOR_CANCELLED;
756                 
757         /* duplicate keyframes */
758         duplicate_graph_keys(&ac);
759         
760         /* validate keyframes after editing */
761         ANIM_editkeyframes_refresh(&ac);
762         
763         /* set notifier that keyframes have changed */
764         WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME_EDIT, NULL);
765         
766         return OPERATOR_FINISHED;
767 }
768
769 static int graphkeys_duplicate_invoke(bContext *C, wmOperator *op, wmEvent *event)
770 {
771         graphkeys_duplicate_exec(C, op);
772         
773         RNA_int_set(op->ptr, "mode", TFM_TRANSLATION);
774         WM_operator_name_call(C, "TRANSFORM_OT_transform", WM_OP_INVOKE_REGION_WIN, op->ptr);
775
776         return OPERATOR_FINISHED;
777 }
778  
779 void GRAPH_OT_duplicate (wmOperatorType *ot)
780 {
781         /* identifiers */
782         ot->name= "Duplicate Keyframes";
783         ot->idname= "GRAPH_OT_duplicate";
784         ot->description= "Make a copy of all selected keyframes";
785         
786         /* api callbacks */
787         ot->invoke= graphkeys_duplicate_invoke;
788         ot->exec= graphkeys_duplicate_exec;
789         ot->poll= graphop_editable_keyframes_poll;
790         
791         /* flags */
792         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
793         
794         /* to give to transform */
795         RNA_def_int(ot->srna, "mode", TFM_TRANSLATION, 0, INT_MAX, "Mode", "", 0, INT_MAX);
796 }
797
798 /* ******************** Delete Keyframes Operator ************************* */
799
800 static void delete_graph_keys (bAnimContext *ac)
801 {
802         ListBase anim_data = {NULL, NULL};
803         bAnimListElem *ale;
804         int filter;
805         
806         /* filter data */
807         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE| ANIMFILTER_FOREDIT | ANIMFILTER_CURVESONLY);
808         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
809         
810         /* loop through filtered data and delete selected keys */
811         for (ale= anim_data.first; ale; ale= ale->next) {
812                 FCurve *fcu= (FCurve *)ale->key_data;
813                 AnimData *adt= ale->adt;
814                 
815                 /* delete selected keyframes only */
816                 delete_fcurve_keys(fcu); 
817                 
818                 /* Only delete curve too if it won't be doing anything anymore */
819                 if ((fcu->totvert == 0) && (list_has_suitable_fmodifier(&fcu->modifiers, 0, FMI_TYPE_GENERATE_CURVE) == 0))
820                         ANIM_fcurve_delete_from_animdata(ac, adt, fcu);
821         }
822         
823         /* free filtered list */
824         BLI_freelistN(&anim_data);
825 }
826
827 /* ------------------- */
828
829 static int graphkeys_delete_exec(bContext *C, wmOperator *op)
830 {
831         bAnimContext ac;
832         
833         /* get editor data */
834         if (ANIM_animdata_get_context(C, &ac) == 0)
835                 return OPERATOR_CANCELLED;
836                 
837         /* delete keyframes */
838         delete_graph_keys(&ac);
839         
840         /* validate keyframes after editing */
841         ANIM_editkeyframes_refresh(&ac);
842         
843         /* set notifier that keyframes have changed */
844         WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME_EDIT, NULL);
845         
846         return OPERATOR_FINISHED;
847 }
848  
849 void GRAPH_OT_delete (wmOperatorType *ot)
850 {
851         /* identifiers */
852         ot->name= "Delete Keyframes";
853         ot->idname= "GRAPH_OT_delete";
854         ot->description= "Remove all selected keyframes";
855         
856         /* api callbacks */
857         ot->invoke= WM_operator_confirm;
858         ot->exec= graphkeys_delete_exec;
859         ot->poll= graphop_editable_keyframes_poll;
860         
861         /* flags */
862         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
863 }
864
865 /* ******************** Clean Keyframes Operator ************************* */
866
867 static void clean_graph_keys (bAnimContext *ac, float thresh)
868 {       
869         ListBase anim_data = {NULL, NULL};
870         bAnimListElem *ale;
871         int filter;
872         
873         /* filter data */
874         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE| ANIMFILTER_FOREDIT | ANIMFILTER_SEL | ANIMFILTER_CURVESONLY);
875         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
876         
877         /* loop through filtered data and clean curves */
878         for (ale= anim_data.first; ale; ale= ale->next)
879                 clean_fcurve((FCurve *)ale->key_data, thresh);
880         
881         /* free temp data */
882         BLI_freelistN(&anim_data);
883 }
884
885 /* ------------------- */
886
887 static int graphkeys_clean_exec(bContext *C, wmOperator *op)
888 {
889         bAnimContext ac;
890         float thresh;
891         
892         /* get editor data */
893         if (ANIM_animdata_get_context(C, &ac) == 0)
894                 return OPERATOR_CANCELLED;
895                 
896         /* get cleaning threshold */
897         thresh= RNA_float_get(op->ptr, "threshold");
898         
899         /* clean keyframes */
900         clean_graph_keys(&ac, thresh);
901         
902         /* validate keyframes after editing */
903         ANIM_editkeyframes_refresh(&ac);
904         
905         /* set notifier that keyframes have changed */
906         WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME_EDIT, NULL);
907         
908         return OPERATOR_FINISHED;
909 }
910  
911 void GRAPH_OT_clean (wmOperatorType *ot)
912 {
913         /* identifiers */
914         ot->name= "Clean Keyframes";
915         ot->idname= "GRAPH_OT_clean";
916         ot->description= "Simplify F-Curves by removing closely spaced keyframes";
917         
918         /* api callbacks */
919         //ot->invoke=  // XXX we need that number popup for this! 
920         ot->exec= graphkeys_clean_exec;
921         ot->poll= graphop_editable_keyframes_poll;
922         
923         /* flags */
924         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
925         
926         /* properties */
927         ot->prop= RNA_def_float(ot->srna, "threshold", 0.001f, 0.0f, FLT_MAX, "Threshold", "", 0.0f, 1000.0f);
928 }
929
930 /* ******************** Bake F-Curve Operator *********************** */
931 /* This operator bakes the data of the selected F-Curves to F-Points */
932
933 /* Bake each F-Curve into a set of samples */
934 static void bake_graph_curves (bAnimContext *ac, int start, int end)
935 {       
936         ListBase anim_data = {NULL, NULL};
937         bAnimListElem *ale;
938         int filter;
939         
940         /* filter data */
941         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE | ANIMFILTER_SEL | ANIMFILTER_FOREDIT | ANIMFILTER_CURVESONLY);
942         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
943         
944         /* loop through filtered data and add keys between selected keyframes on every frame  */
945         for (ale= anim_data.first; ale; ale= ale->next) {
946                 FCurve *fcu= (FCurve *)ale->key_data;
947                 ChannelDriver *driver= fcu->driver;
948                 
949                 /* disable driver so that it don't muck up the sampling process */
950                 fcu->driver= NULL;
951                 
952                 /* create samples */
953                 fcurve_store_samples(fcu, NULL, start, end, fcurve_samplingcb_evalcurve);
954                 
955                 /* restore driver */
956                 fcu->driver= driver;
957         }
958         
959         /* admin and redraws */
960         BLI_freelistN(&anim_data);
961 }
962
963 /* ------------------- */
964
965 static int graphkeys_bake_exec(bContext *C, wmOperator *op)
966 {
967         bAnimContext ac;
968         Scene *scene= NULL;
969         int start, end;
970         
971         /* get editor data */
972         if (ANIM_animdata_get_context(C, &ac) == 0)
973                 return OPERATOR_CANCELLED;
974                 
975         /* for now, init start/end from preview-range extents */
976         // TODO: add properties for this 
977         scene= ac.scene;
978         start= PSFRA;
979         end= PEFRA;
980         
981         /* bake keyframes */
982         bake_graph_curves(&ac, start, end);
983         
984         /* validate keyframes after editing */
985         ANIM_editkeyframes_refresh(&ac);
986         
987         /* set notifier that keyframes have changed */
988         // NOTE: some distinction between order/number of keyframes and type should be made?
989         WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME_EDIT, NULL);
990         
991         return OPERATOR_FINISHED;
992 }
993  
994 void GRAPH_OT_bake (wmOperatorType *ot)
995 {
996         /* identifiers */
997         ot->name= "Bake Curve";
998         ot->idname= "GRAPH_OT_bake";
999         ot->description= "Bake selected F-Curves to a set of sampled points defining a similar curve";
1000         
1001         /* api callbacks */
1002         ot->invoke= WM_operator_confirm; // FIXME...
1003         ot->exec= graphkeys_bake_exec;
1004         ot->poll= graphop_selected_fcurve_poll; 
1005         
1006         /* flags */
1007         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1008         
1009         // todo: add props for start/end frames
1010 }
1011
1012 /* ******************** Sound Bake F-Curve Operator *********************** */
1013 /* This operator bakes the given sound to the selected F-Curves */
1014
1015 /* ------------------- */
1016
1017 /* Custom data storage passed to the F-Sample-ing function,
1018  * which provides the necessary info for baking the sound
1019  */
1020 typedef struct tSoundBakeInfo {
1021         float *samples;
1022         int length;
1023         int cfra;
1024 } tSoundBakeInfo;
1025
1026 /* ------------------- */
1027
1028 /* Sampling callback used to determine the value from the sound to
1029  * save in the F-Curve at the specified frame
1030  */
1031 static float fcurve_samplingcb_sound (FCurve *fcu, void *data, float evaltime)
1032 {
1033         tSoundBakeInfo *sbi= (tSoundBakeInfo *)data;
1034
1035         int position = evaltime - sbi->cfra;
1036         if((position < 0) || (position >= sbi->length))
1037                 return 0.0f;
1038
1039         return sbi->samples[position];
1040 }
1041
1042 /* ------------------- */
1043
1044 static int graphkeys_sound_bake_exec(bContext *C, wmOperator *op)
1045 {
1046         bAnimContext ac;
1047         ListBase anim_data = {NULL, NULL};
1048         bAnimListElem *ale;
1049         int filter;
1050
1051         tSoundBakeInfo sbi;
1052         Scene *scene= NULL;
1053         int start, end;
1054
1055         char path[FILE_MAX];
1056
1057         /* get editor data */
1058         if (ANIM_animdata_get_context(C, &ac) == 0)
1059                 return OPERATOR_CANCELLED;
1060
1061         RNA_string_get(op->ptr, "path", path);
1062
1063         scene= ac.scene;        /* current scene */
1064
1065         /* store necessary data for the baking steps */
1066         sbi.samples = AUD_readSoundBuffer(path,
1067                                                                           RNA_float_get(op->ptr, "low"),
1068                                                                           RNA_float_get(op->ptr, "high"),
1069                                                                           RNA_float_get(op->ptr, "attack"),
1070                                                                           RNA_float_get(op->ptr, "release"),
1071                                                                           RNA_float_get(op->ptr, "threshold"),
1072                                                                           RNA_boolean_get(op->ptr, "accumulate"),
1073                                                                           RNA_boolean_get(op->ptr, "additive"),
1074                                                                           RNA_boolean_get(op->ptr, "square"),
1075                                                                           RNA_float_get(op->ptr, "sthreshold"),
1076                                                                           FPS, &sbi.length);
1077
1078         if (sbi.samples == NULL) {
1079                 BKE_report(op->reports, RPT_ERROR, "Unsupported audio format");
1080                 return OPERATOR_CANCELLED;
1081         }
1082
1083         /* determine extents of the baking */
1084         sbi.cfra = start = CFRA;
1085         end = CFRA + sbi.length - 1;
1086
1087         /* filter anim channels */
1088         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE | ANIMFILTER_SEL | ANIMFILTER_FOREDIT | ANIMFILTER_CURVESONLY);
1089         ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
1090
1091         /* loop through all selected F-Curves, replacing its data with the sound samples */
1092         for (ale= anim_data.first; ale; ale= ale->next) {
1093                 FCurve *fcu= (FCurve *)ale->key_data;
1094                 
1095                 /* sample the sound */
1096                 fcurve_store_samples(fcu, &sbi, start, end, fcurve_samplingcb_sound);
1097         }
1098
1099         /* free sample data */
1100         free(sbi.samples);
1101
1102         /* admin and redraws */
1103         BLI_freelistN(&anim_data);
1104
1105         /* validate keyframes after editing */
1106         ANIM_editkeyframes_refresh(&ac);
1107
1108         /* set notifier that 'keyframes' have changed */
1109         WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME_EDIT, NULL);
1110
1111         return OPERATOR_FINISHED;
1112 }
1113
1114 static int graphkeys_sound_bake_invoke (bContext *C, wmOperator *op, wmEvent *event)
1115 {
1116         bAnimContext ac;
1117
1118         /* verify editor data */
1119         if (ANIM_animdata_get_context(C, &ac) == 0)
1120                 return OPERATOR_CANCELLED;
1121
1122         return WM_operator_filesel(C, op, event);
1123 }
1124
1125 void GRAPH_OT_sound_bake (wmOperatorType *ot)
1126 {
1127         /* identifiers */
1128         ot->name= "Bake Sound to F-Curves";
1129         ot->idname= "GRAPH_OT_sound_bake";
1130         ot->description= "Bakes a sound wave to selected F-Curves";
1131
1132         /* api callbacks */
1133         ot->invoke= graphkeys_sound_bake_invoke;
1134         ot->exec= graphkeys_sound_bake_exec;
1135         ot->poll= graphop_selected_fcurve_poll;
1136
1137         /* flags */
1138         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1139
1140         /* properties */
1141         WM_operator_properties_filesel(ot, FOLDERFILE|SOUNDFILE|MOVIEFILE, FILE_SPECIAL, FILE_OPENFILE);
1142         RNA_def_float(ot->srna, "low", 0.0f, 0.0, 100000.0, "Lowest frequency", "", 0.1, 1000.00);
1143         RNA_def_float(ot->srna, "high", 100000.0, 0.0, 100000.0, "Highest frequency", "", 0.1, 1000.00);
1144         RNA_def_float(ot->srna, "attack", 0.005, 0.0, 2.0, "Attack time", "", 0.01, 0.1);
1145         RNA_def_float(ot->srna, "release", 0.2, 0.0, 5.0, "Release time", "", 0.01, 0.2);
1146         RNA_def_float(ot->srna, "threshold", 0.0, 0.0, 1.0, "Threshold", "", 0.01, 0.1);
1147         RNA_def_boolean(ot->srna, "accumulate", 0, "Accumulate", "");
1148         RNA_def_boolean(ot->srna, "additive", 0, "Additive", "");
1149         RNA_def_boolean(ot->srna, "square", 0, "Square", "");
1150         RNA_def_float(ot->srna, "sthreshold", 0.1, 0.0, 1.0, "Square Threshold", "", 0.01, 0.1);
1151 }
1152
1153 /* ******************** Sample Keyframes Operator *********************** */
1154 /* This operator 'bakes' the values of the curve into new keyframes between pairs
1155  * of selected keyframes. It is useful for creating keyframes for tweaking overlap.
1156  */
1157
1158 /* Evaluates the curves between each selected keyframe on each frame, and keys the value  */
1159 static void sample_graph_keys (bAnimContext *ac)
1160 {       
1161         ListBase anim_data = {NULL, NULL};
1162         bAnimListElem *ale;
1163         int filter;
1164         
1165         /* filter data */
1166         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE| ANIMFILTER_FOREDIT | ANIMFILTER_CURVESONLY);
1167         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
1168         
1169         /* loop through filtered data and add keys between selected keyframes on every frame  */
1170         for (ale= anim_data.first; ale; ale= ale->next)
1171                 sample_fcurve((FCurve *)ale->key_data);
1172         
1173         /* admin and redraws */
1174         BLI_freelistN(&anim_data);
1175 }
1176
1177 /* ------------------- */
1178
1179 static int graphkeys_sample_exec(bContext *C, wmOperator *op)
1180 {
1181         bAnimContext ac;
1182         
1183         /* get editor data */
1184         if (ANIM_animdata_get_context(C, &ac) == 0)
1185                 return OPERATOR_CANCELLED;
1186         
1187         /* sample keyframes */
1188         sample_graph_keys(&ac);
1189         
1190         /* validate keyframes after editing */
1191         ANIM_editkeyframes_refresh(&ac);
1192         
1193         /* set notifier that keyframes have changed */
1194         WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME_EDIT, NULL);
1195         
1196         return OPERATOR_FINISHED;
1197 }
1198  
1199 void GRAPH_OT_sample (wmOperatorType *ot)
1200 {
1201         /* identifiers */
1202         ot->name= "Sample Keyframes";
1203         ot->idname= "GRAPH_OT_sample";
1204         ot->description= "Add keyframes on every frame between the selected keyframes";
1205         
1206         /* api callbacks */
1207         ot->exec= graphkeys_sample_exec;
1208         ot->poll= graphop_editable_keyframes_poll;
1209         
1210         /* flags */
1211         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1212 }
1213
1214
1215 /* ************************************************************************** */
1216 /* SETTINGS STUFF */
1217
1218 /* ******************** Set Extrapolation-Type Operator *********************** */
1219
1220 /* defines for set extrapolation-type for selected keyframes tool */
1221 EnumPropertyItem prop_graphkeys_expo_types[] = {
1222         {FCURVE_EXTRAPOLATE_CONSTANT, "CONSTANT", 0, "Constant Extrapolation", ""},
1223         {FCURVE_EXTRAPOLATE_LINEAR, "LINEAR", 0, "Linear Extrapolation", ""},
1224         {0, NULL, 0, NULL, NULL}
1225 };
1226
1227 /* this function is responsible for setting extrapolation mode for keyframes */
1228 static void setexpo_graph_keys(bAnimContext *ac, short mode) 
1229 {
1230         ListBase anim_data = {NULL, NULL};
1231         bAnimListElem *ale;
1232         int filter;
1233         
1234         /* filter data */
1235         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE| ANIMFILTER_FOREDIT | ANIMFILTER_CURVESONLY);
1236         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
1237         
1238         /* loop through setting mode per F-Curve */
1239         for (ale= anim_data.first; ale; ale= ale->next) {
1240                 FCurve *fcu= (FCurve *)ale->data;
1241                 fcu->extend= mode;
1242         }
1243         
1244         /* cleanup */
1245         BLI_freelistN(&anim_data);
1246 }
1247
1248 /* ------------------- */
1249
1250 static int graphkeys_expo_exec(bContext *C, wmOperator *op)
1251 {
1252         bAnimContext ac;
1253         short mode;
1254         
1255         /* get editor data */
1256         if (ANIM_animdata_get_context(C, &ac) == 0)
1257                 return OPERATOR_CANCELLED;
1258                 
1259         /* get handle setting mode */
1260         mode= RNA_enum_get(op->ptr, "type");
1261         
1262         /* set handle type */
1263         setexpo_graph_keys(&ac, mode);
1264         
1265         /* validate keyframes after editing */
1266         ANIM_editkeyframes_refresh(&ac);
1267         
1268         /* set notifier that keyframe properties have changed */
1269         WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME_PROP, NULL);
1270         
1271         return OPERATOR_FINISHED;
1272 }
1273  
1274 void GRAPH_OT_extrapolation_type (wmOperatorType *ot)
1275 {
1276         /* identifiers */
1277         ot->name= "Set Keyframe Extrapolation";
1278         ot->idname= "GRAPH_OT_extrapolation_type";
1279         ot->description= "Set extrapolation mode for selected F-Curves";
1280         
1281         /* api callbacks */
1282         ot->invoke= WM_menu_invoke;
1283         ot->exec= graphkeys_expo_exec;
1284         ot->poll= graphop_editable_keyframes_poll;
1285         
1286         /* flags */
1287         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1288         
1289         /* id-props */
1290         ot->prop= RNA_def_enum(ot->srna, "type", prop_graphkeys_expo_types, 0, "Type", "");
1291 }
1292
1293 /* ******************** Set Interpolation-Type Operator *********************** */
1294
1295 /* this function is responsible for setting interpolation mode for keyframes */
1296 static void setipo_graph_keys(bAnimContext *ac, short mode) 
1297 {
1298         ListBase anim_data = {NULL, NULL};
1299         bAnimListElem *ale;
1300         int filter;
1301         BeztEditFunc set_cb= ANIM_editkeyframes_ipo(mode);
1302         
1303         /* filter data */
1304         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE| ANIMFILTER_FOREDIT | ANIMFILTER_CURVESONLY);
1305         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
1306         
1307         /* loop through setting BezTriple interpolation
1308          * Note: we do not supply BeztEditData to the looper yet. Currently that's not necessary here...
1309          */
1310         for (ale= anim_data.first; ale; ale= ale->next)
1311                 ANIM_fcurve_keys_bezier_loop(NULL, ale->key_data, NULL, set_cb, calchandles_fcurve);
1312         
1313         /* cleanup */
1314         BLI_freelistN(&anim_data);
1315 }
1316
1317 /* ------------------- */
1318
1319 static int graphkeys_ipo_exec(bContext *C, wmOperator *op)
1320 {
1321         bAnimContext ac;
1322         short mode;
1323         
1324         /* get editor data */
1325         if (ANIM_animdata_get_context(C, &ac) == 0)
1326                 return OPERATOR_CANCELLED;
1327                 
1328         /* get handle setting mode */
1329         mode= RNA_enum_get(op->ptr, "type");
1330         
1331         /* set handle type */
1332         setipo_graph_keys(&ac, mode);
1333         
1334         /* validate keyframes after editing */
1335         ANIM_editkeyframes_refresh(&ac);
1336         
1337         /* set notifier that keyframe properties have changed */
1338         WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME_PROP, NULL);
1339         
1340         return OPERATOR_FINISHED;
1341 }
1342  
1343 void GRAPH_OT_interpolation_type (wmOperatorType *ot)
1344 {
1345         /* identifiers */
1346         ot->name= "Set Keyframe Interpolation";
1347         ot->idname= "GRAPH_OT_interpolation_type";
1348         ot->description= "Set interpolation mode for the F-Curve segments starting from the selected keyframes";
1349         
1350         /* api callbacks */
1351         ot->invoke= WM_menu_invoke;
1352         ot->exec= graphkeys_ipo_exec;
1353         ot->poll= graphop_editable_keyframes_poll;
1354         
1355         /* flags */
1356         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1357         
1358         /* id-props */
1359         ot->prop= RNA_def_enum(ot->srna, "type", beztriple_interpolation_mode_items, 0, "Type", "");
1360 }
1361
1362 /* ******************** Set Handle-Type Operator *********************** */
1363
1364 EnumPropertyItem graphkeys_handle_type_items[] = {
1365         {HD_FREE, "FREE", 0, "Free", ""},
1366         {HD_VECT, "VECTOR", 0, "Vector", ""},
1367         {HD_ALIGN, "ALIGNED", 0, "Aligned", ""},
1368         {0, "", 0, "", ""},
1369         {HD_AUTO, "AUTO", 0, "Auto", "Handles that are automatically adjusted upon moving the keyframe. Whole curve."},
1370         {HD_AUTO_ANIM, "ANIM_CLAMPED", 0, "Auto Clamped", "Auto handles clamped to not overshoot. Whole curve."},
1371         {0, NULL, 0, NULL, NULL}};
1372
1373 /* ------------------- */
1374
1375 /* this function is responsible for setting handle-type of selected keyframes */
1376 static void sethandles_graph_keys(bAnimContext *ac, short mode) 
1377 {
1378         ListBase anim_data = {NULL, NULL};
1379         bAnimListElem *ale;
1380         int filter;
1381         
1382         BeztEditFunc edit_cb= ANIM_editkeyframes_handles(mode);
1383         BeztEditFunc sel_cb= ANIM_editkeyframes_ok(BEZT_OK_SELECTED);
1384         
1385         /* filter data */
1386         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_CURVESONLY);
1387         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
1388         
1389         /* loop through setting flags for handles 
1390          * Note: we do not supply BeztEditData to the looper yet. Currently that's not necessary here...
1391          */
1392         for (ale= anim_data.first; ale; ale= ale->next) {
1393                 FCurve *fcu= (FCurve *)ale->key_data;
1394                 
1395                 /* any selected keyframes for editing? */
1396                 if (ANIM_fcurve_keys_bezier_loop(NULL, fcu, NULL, sel_cb, NULL)) {
1397                         /* for auto/auto-clamped, toggle the auto-handles flag on the F-Curve */
1398                         if (mode == HD_AUTO_ANIM)
1399                                 fcu->flag |= FCURVE_AUTO_HANDLES;
1400                         else if (mode == HD_AUTO)
1401                                 fcu->flag &= ~FCURVE_AUTO_HANDLES;
1402                         
1403                         /* change type of selected handles */
1404                         ANIM_fcurve_keys_bezier_loop(NULL, fcu, NULL, edit_cb, calchandles_fcurve);
1405                 }
1406         }
1407         
1408         /* cleanup */
1409         BLI_freelistN(&anim_data);
1410 }
1411 /* ------------------- */
1412
1413 static int graphkeys_handletype_exec(bContext *C, wmOperator *op)
1414 {
1415         bAnimContext ac;
1416         short mode;
1417         
1418         /* get editor data */
1419         if (ANIM_animdata_get_context(C, &ac) == 0)
1420                 return OPERATOR_CANCELLED;
1421                 
1422         /* get handle setting mode */
1423         mode= RNA_enum_get(op->ptr, "type");
1424         
1425         /* set handle type */
1426         sethandles_graph_keys(&ac, mode);
1427         
1428         /* validate keyframes after editing */
1429         ANIM_editkeyframes_refresh(&ac);
1430         
1431         /* set notifier that keyframe properties have changed */
1432         WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME_PROP, NULL);
1433         
1434         return OPERATOR_FINISHED;
1435 }
1436  
1437  void GRAPH_OT_handle_type (wmOperatorType *ot)
1438 {
1439         /* identifiers */
1440         ot->name= "Set Keyframe Handle Type";
1441         ot->idname= "GRAPH_OT_handle_type";
1442         ot->description= "Set type of handle for selected keyframes";
1443         
1444         /* api callbacks */
1445         ot->invoke= WM_menu_invoke;
1446         ot->exec= graphkeys_handletype_exec;
1447         ot->poll= graphop_editable_keyframes_poll;
1448         
1449         /* flags */
1450         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1451         
1452         /* id-props */
1453         ot->prop= RNA_def_enum(ot->srna, "type", graphkeys_handle_type_items, 0, "Type", "");
1454 }
1455
1456 /* ************************************************************************** */
1457 /* TRANSFORM STUFF */
1458
1459 /* ***************** 'Euler Filter' Operator **************************** */
1460 /* Euler filter tools (as seen in Maya), are necessary for working with 'baked'
1461  * rotation curves (with Euler rotations). The main purpose of such tools is to
1462  * resolve any discontinuities that may arise in the curves due to the clamping
1463  * of values to -180 degrees to 180 degrees.
1464  */
1465
1466 #if 0 // XXX this is not ready for the primetime yet
1467  
1468 /* set of three euler-rotation F-Curves */
1469 typedef struct tEulerFilter {
1470         ID *id;                                                 /* ID-block which owns the channels */
1471         FCurve (*fcurves)[3];                   /* 3 Pointers to F-Curves */                            
1472 } tEulerFilter;
1473  
1474 static int graphkeys_euler_filter_exec (bContext *C, wmOperator *op)
1475 {
1476         bAnimContext ac;
1477         
1478         ListBase anim_data= {NULL, NULL};
1479         bAnimListElem *ale;
1480         int filter;
1481         
1482         ListBase eulers = {NULL, NULL};
1483         tEulerFilter *euf= NULL;        
1484         
1485         /* get editor data */
1486         if (ANIM_animdata_get_context(C, &ac) == 0)
1487                 return OPERATOR_CANCELLED;
1488                 
1489         /* The process is done in two passes:
1490          *       1) Sets of three related rotation curves are identified from the selected channels,
1491          *              and are stored as a single 'operation unit' for the next step
1492          *       2) Each set of three F-Curves is processed for each keyframe, with the values being
1493          *              processed according to one of several ways.
1494          */
1495          
1496         /* step 1: extract only the rotation f-curves */
1497         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_SEL | ANIMFILTER_CURVEVISIBLE | ANIMFILTER_CURVESONLY | ANIMFILTER_FOREDIT);
1498         ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
1499         
1500         for (ale= anim_data.first; ale; ale= ale->next) {
1501                 FCurve *fcu = (FCurve *)ale->data;
1502                 
1503                 /* check if this is an appropriate F-Curve 
1504                  *      - only rotation curves
1505                  *      - for pchan curves, make sure we're only using the euler curves
1506                  */
1507                 if (strstr(fcu->rna_path, "rotation_euler") == 0)
1508                         continue;
1509                 
1510                 /* check if current set of 3-curves is suitable to add this curve to 
1511                  *      - things like whether the current set of curves is 'full' should be checked later only
1512                  *      - first check if id-blocks are compatible
1513                  */
1514                 if ((euf) && (ale->id != euf->id)) {
1515                         /* if the paths match, add this curve to the set of curves */
1516                         // NOTE: simple string compare for now... could be a bit more fancy...
1517                         
1518                 }
1519                 else {
1520                         /* just add to a new block */
1521                         euf= MEM_callocN(sizeof(tEulerFilter), "tEulerFilter");
1522                         BLI_addtail(&eulers, euf);
1523                         
1524                         euf->id= ale->id;
1525                         euf->fcurves[fcu->array_index]= fcu;
1526                 }
1527         }
1528         BLI_freelistN(&anim_data);
1529         
1530         /* step 2: go through each set of curves, processing the values at each keyframe 
1531          *      - it is assumed that there must be a full set of keyframes at each keyframe position
1532          */
1533         for (euf= eulers.first; euf; euf= euf->next) {
1534                 
1535         }
1536         BLI_freelistN(&eulers);
1537         
1538         return OPERATOR_FINISHED;
1539 }
1540  
1541 void GRAPH_OT_euler_filter (wmOperatorType *ot)
1542 {
1543         /* identifiers */
1544         ot->name= "Euler Filter";
1545         ot->idname= "GRAPH_OT_euler_filter";
1546         
1547         /* api callbacks */
1548         ot->exec= graphkeys_euler_filter_exec;
1549         ot->poll= graphop_editable_keyframes_poll;
1550         
1551         /* flags */
1552         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1553 }
1554
1555 #endif // XXX this is not ready for the primetime yet
1556
1557 /* ***************** Jump to Selected Frames Operator *********************** */
1558
1559 /* snap current-frame indicator to 'average time' of selected keyframe */
1560 static int graphkeys_framejump_exec(bContext *C, wmOperator *op)
1561 {
1562         bAnimContext ac;
1563         ListBase anim_data= {NULL, NULL};
1564         bAnimListElem *ale;
1565         int filter;
1566         BeztEditData bed;
1567         
1568         /* get editor data */
1569         if (ANIM_animdata_get_context(C, &ac) == 0)
1570                 return OPERATOR_CANCELLED;
1571         
1572         /* init edit data */
1573         memset(&bed, 0, sizeof(BeztEditData));
1574         
1575         /* loop over action data, averaging values */
1576         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE | ANIMFILTER_CURVESONLY);
1577         ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
1578         
1579         for (ale= anim_data.first; ale; ale= ale->next) {
1580                 AnimData *adt= ANIM_nla_mapping_get(&ac, ale);
1581                 
1582                 /* apply unit corrections */
1583                 ANIM_unit_mapping_apply_fcurve(ac.scene, ale->id, ale->key_data, ANIM_UNITCONV_ONLYKEYS);
1584                 
1585                 if (adt) {
1586                         ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, 1); 
1587                         ANIM_fcurve_keys_bezier_loop(&bed, ale->key_data, NULL, bezt_calc_average, NULL);
1588                         ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 1, 1); 
1589                 }
1590                 else
1591                         ANIM_fcurve_keys_bezier_loop(&bed, ale->key_data, NULL, bezt_calc_average, NULL);
1592                 
1593                 /* unapply unit corrections */
1594                 ANIM_unit_mapping_apply_fcurve(ac.scene, ale->id, ale->key_data, ANIM_UNITCONV_RESTORE|ANIM_UNITCONV_ONLYKEYS);
1595         }
1596         
1597         BLI_freelistN(&anim_data);
1598         
1599         /* set the new current frame and cursor values, based on the average time and value */
1600         if (bed.i1) {
1601                 SpaceIpo *sipo= ac.sa->spacedata.first;
1602                 Scene *scene= ac.scene;
1603                 
1604                 /* take the average values, rounding to the nearest int for the current frame */
1605                 CFRA= (int)floor((bed.f1 / bed.i1) + 0.5f);
1606                 sipo->cursorVal= bed.f2 / (float)bed.i1;
1607         }
1608         
1609         /* set notifier that things have changed */
1610         WM_event_add_notifier(C, NC_SCENE|ND_FRAME, ac.scene);
1611         
1612         return OPERATOR_FINISHED;
1613 }
1614
1615 void GRAPH_OT_frame_jump (wmOperatorType *ot)
1616 {
1617         /* identifiers */
1618         ot->name= "Jump to Frame";
1619         ot->idname= "GRAPH_OT_frame_jump";
1620         ot->description= "Set the current frame to the average frame of the selected keyframes";
1621         
1622         /* api callbacks */
1623         ot->exec= graphkeys_framejump_exec;
1624         ot->poll= graphop_visible_keyframes_poll;
1625         
1626         /* flags */
1627         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1628 }
1629
1630 /* ******************** Snap Keyframes Operator *********************** */
1631
1632 /* defines for snap keyframes tool */
1633 EnumPropertyItem prop_graphkeys_snap_types[] = {
1634         {GRAPHKEYS_SNAP_CFRA, "CFRA", 0, "Current Frame", ""},
1635         {GRAPHKEYS_SNAP_VALUE, "VALUE", 0, "Cursor Value", ""},
1636         {GRAPHKEYS_SNAP_NEAREST_FRAME, "NEAREST_FRAME", 0, "Nearest Frame", ""}, // XXX as single entry?
1637         {GRAPHKEYS_SNAP_NEAREST_SECOND, "NEAREST_SECOND", 0, "Nearest Second", ""}, // XXX as single entry?
1638         {GRAPHKEYS_SNAP_NEAREST_MARKER, "NEAREST_MARKER", 0, "Nearest Marker", ""},
1639         {GRAPHKEYS_SNAP_HORIZONTAL, "HORIZONTAL", 0, "Flatten Handles", ""},
1640         {0, NULL, 0, NULL, NULL}
1641 };
1642
1643 /* this function is responsible for snapping keyframes to frame-times */
1644 static void snap_graph_keys(bAnimContext *ac, short mode) 
1645 {
1646         ListBase anim_data = {NULL, NULL};
1647         bAnimListElem *ale;
1648         int filter;
1649         
1650         BeztEditData bed;
1651         BeztEditFunc edit_cb;
1652         
1653         /* filter data */
1654         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_CURVESONLY);
1655         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
1656         
1657         /* get beztriple editing callbacks */
1658         edit_cb= ANIM_editkeyframes_snap(mode);
1659         
1660         memset(&bed, 0, sizeof(BeztEditData)); 
1661         bed.scene= ac->scene;
1662         if (mode == GRAPHKEYS_SNAP_NEAREST_MARKER) {
1663                 bed.list.first= (ac->markers) ? ac->markers->first : NULL;
1664                 bed.list.last= (ac->markers) ? ac->markers->last : NULL;
1665         }
1666         else if (mode == GRAPHKEYS_SNAP_VALUE) {
1667                 SpaceIpo *sipo= (SpaceIpo *)ac->sa->spacedata.first;
1668                 bed.f1= (sipo) ? sipo->cursorVal : 0.0f;
1669         }
1670         
1671         /* snap keyframes */
1672         for (ale= anim_data.first; ale; ale= ale->next) {
1673                 AnimData *adt= ANIM_nla_mapping_get(ac, ale);
1674                 
1675                 /* apply unit corrections */
1676                 ANIM_unit_mapping_apply_fcurve(ac->scene, ale->id, ale->key_data, 0);
1677                 
1678                 if (adt) {
1679                         ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, 1); 
1680                         ANIM_fcurve_keys_bezier_loop(&bed, ale->key_data, NULL, edit_cb, calchandles_fcurve);
1681                         ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 1, 1);
1682                 }
1683                 else 
1684                         ANIM_fcurve_keys_bezier_loop(&bed, ale->key_data, NULL, edit_cb, calchandles_fcurve);
1685                         
1686                 /* apply unit corrections */
1687                 ANIM_unit_mapping_apply_fcurve(ac->scene, ale->id, ale->key_data, ANIM_UNITCONV_RESTORE);
1688         }
1689         
1690         BLI_freelistN(&anim_data);
1691 }
1692
1693 /* ------------------- */
1694
1695 static int graphkeys_snap_exec(bContext *C, wmOperator *op)
1696 {
1697         bAnimContext ac;
1698         short mode;
1699         
1700         /* get editor data */
1701         if (ANIM_animdata_get_context(C, &ac) == 0)
1702                 return OPERATOR_CANCELLED;
1703                 
1704         /* get snapping mode */
1705         mode= RNA_enum_get(op->ptr, "type");
1706         
1707         /* snap keyframes */
1708         snap_graph_keys(&ac, mode);
1709         
1710         /* validate keyframes after editing */
1711         ANIM_editkeyframes_refresh(&ac);
1712         
1713         /* set notifier that keyframes have changed */
1714         WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME_EDIT, NULL);
1715         
1716         return OPERATOR_FINISHED;
1717 }
1718  
1719 void GRAPH_OT_snap (wmOperatorType *ot)
1720 {
1721         /* identifiers */
1722         ot->name= "Snap Keys";
1723         ot->idname= "GRAPH_OT_snap";
1724         ot->description= "Snap selected keyframes to the chosen times/values";
1725         
1726         /* api callbacks */
1727         ot->invoke= WM_menu_invoke;
1728         ot->exec= graphkeys_snap_exec;
1729         ot->poll= graphop_editable_keyframes_poll;
1730         
1731         /* flags */
1732         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1733         
1734         /* id-props */
1735         ot->prop= RNA_def_enum(ot->srna, "type", prop_graphkeys_snap_types, 0, "Type", "");
1736 }
1737
1738 /* ******************** Mirror Keyframes Operator *********************** */
1739
1740 /* defines for mirror keyframes tool */
1741 EnumPropertyItem prop_graphkeys_mirror_types[] = {
1742         {GRAPHKEYS_MIRROR_CFRA, "CFRA", 0, "By Times over Current Frame", ""},
1743         {GRAPHKEYS_MIRROR_VALUE, "VALUE", 0, "By Values over Cursor Value", ""},
1744         {GRAPHKEYS_MIRROR_YAXIS, "YAXIS", 0, "By Times over Time=0", ""},
1745         {GRAPHKEYS_MIRROR_XAXIS, "XAXIS", 0, "By Values over Value=0", ""},
1746         {GRAPHKEYS_MIRROR_MARKER, "MARKER", 0, "By Times over First Selected Marker", ""},
1747         {0, NULL, 0, NULL, NULL}
1748 };
1749
1750 /* this function is responsible for mirroring keyframes */
1751 static void mirror_graph_keys(bAnimContext *ac, short mode) 
1752 {
1753         ListBase anim_data = {NULL, NULL};
1754         bAnimListElem *ale;
1755         int filter;
1756         
1757         BeztEditData bed;
1758         BeztEditFunc edit_cb;
1759         
1760         /* get beztriple editing callbacks */
1761         edit_cb= ANIM_editkeyframes_mirror(mode);
1762         
1763         memset(&bed, 0, sizeof(BeztEditData)); 
1764         bed.scene= ac->scene;
1765         
1766         /* for 'first selected marker' mode, need to find first selected marker first! */
1767         // XXX should this be made into a helper func in the API?
1768         if (mode == GRAPHKEYS_MIRROR_MARKER) {
1769                 TimeMarker *marker= NULL;
1770                 
1771                 /* find first selected marker */
1772                 if (ac->markers) {
1773                         for (marker= ac->markers->first; marker; marker=marker->next) {
1774                                 if (marker->flag & SELECT) {
1775                                         break;
1776                                 }
1777                         }
1778                 }
1779                 
1780                 /* store marker's time (if available) */
1781                 if (marker)
1782                         bed.f1= (float)marker->frame;
1783                 else
1784                         return;
1785         }
1786         else if (mode == GRAPHKEYS_MIRROR_VALUE) {
1787                 SpaceIpo *sipo= (SpaceIpo *)ac->sa->spacedata.first;
1788                 bed.f1= (sipo) ? sipo->cursorVal : 0.0f;
1789         }
1790         
1791         /* filter data */
1792         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE| ANIMFILTER_FOREDIT | ANIMFILTER_CURVESONLY);
1793         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
1794         
1795         /* mirror keyframes */
1796         for (ale= anim_data.first; ale; ale= ale->next) {
1797                 AnimData *adt= ANIM_nla_mapping_get(ac, ale);
1798                 
1799                 /* apply unit corrections */
1800                 ANIM_unit_mapping_apply_fcurve(ac->scene, ale->id, ale->key_data, ANIM_UNITCONV_ONLYKEYS);
1801                 
1802                 if (adt) {
1803                         ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, 1); 
1804                         ANIM_fcurve_keys_bezier_loop(&bed, ale->key_data, NULL, edit_cb, calchandles_fcurve);
1805                         ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 1, 1);
1806                 }
1807                 else 
1808                         ANIM_fcurve_keys_bezier_loop(&bed, ale->key_data, NULL, edit_cb, calchandles_fcurve);
1809                         
1810                 /* unapply unit corrections */
1811                 ANIM_unit_mapping_apply_fcurve(ac->scene, ale->id, ale->key_data, ANIM_UNITCONV_ONLYKEYS|ANIM_UNITCONV_RESTORE);
1812         }
1813         
1814         BLI_freelistN(&anim_data);
1815 }
1816
1817 /* ------------------- */
1818
1819 static int graphkeys_mirror_exec(bContext *C, wmOperator *op)
1820 {
1821         bAnimContext ac;
1822         short mode;
1823         
1824         /* get editor data */
1825         if (ANIM_animdata_get_context(C, &ac) == 0)
1826                 return OPERATOR_CANCELLED;
1827                 
1828         /* get mirroring mode */
1829         mode= RNA_enum_get(op->ptr, "type");
1830         
1831         /* mirror keyframes */
1832         mirror_graph_keys(&ac, mode);
1833         
1834         /* validate keyframes after editing */
1835         ANIM_editkeyframes_refresh(&ac);
1836         
1837         /* set notifier that keyframes have changed */
1838         WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME_EDIT, NULL);
1839         
1840         return OPERATOR_FINISHED;
1841 }
1842  
1843 void GRAPH_OT_mirror (wmOperatorType *ot)
1844 {
1845         /* identifiers */
1846         ot->name= "Mirror Keys";
1847         ot->idname= "GRAPH_OT_mirror";
1848         ot->description= "Flip selected keyframes over the selected mirror line";
1849         
1850         /* api callbacks */
1851         ot->invoke= WM_menu_invoke;
1852         ot->exec= graphkeys_mirror_exec;
1853         ot->poll= graphop_editable_keyframes_poll;
1854         
1855         /* flags */
1856         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1857         
1858         /* id-props */
1859         ot->prop= RNA_def_enum(ot->srna, "type", prop_graphkeys_mirror_types, 0, "Type", "");
1860 }
1861
1862 /* ******************** Smooth Keyframes Operator *********************** */
1863
1864 static int graphkeys_smooth_exec(bContext *C, wmOperator *op)
1865 {
1866         bAnimContext ac;
1867         ListBase anim_data = {NULL, NULL};
1868         bAnimListElem *ale;
1869         int filter;
1870         
1871         /* get editor data */
1872         if (ANIM_animdata_get_context(C, &ac) == 0)
1873                 return OPERATOR_CANCELLED;
1874         
1875         /* filter data */
1876         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE| ANIMFILTER_FOREDIT | ANIMFILTER_CURVESONLY);
1877         ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
1878         
1879         /* smooth keyframes */
1880         for (ale= anim_data.first; ale; ale= ale->next) {
1881                 /* For now, we can only smooth by flattening handles AND smoothing curve values.
1882                  * Perhaps the mode argument could be removed, as that functionality is offerred through 
1883                  * Snap->Flatten Handles anyway.
1884                  */
1885                 smooth_fcurve(ale->key_data);
1886         }
1887         BLI_freelistN(&anim_data);
1888         
1889         /* validate keyframes after editing */
1890         ANIM_editkeyframes_refresh(&ac);
1891         
1892         /* set notifier that keyframes have changed */
1893         WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME_EDIT, NULL);
1894         
1895         return OPERATOR_FINISHED;
1896 }
1897  
1898 void GRAPH_OT_smooth (wmOperatorType *ot)
1899 {
1900         /* identifiers */
1901         ot->name= "Smooth Keys";
1902         ot->idname= "GRAPH_OT_smooth";
1903         ot->description= "Apply weighted moving means to make selected F-Curves less bumpy";
1904         
1905         /* api callbacks */
1906         ot->exec= graphkeys_smooth_exec;
1907         ot->poll= graphop_editable_keyframes_poll;
1908         
1909         /* flags */
1910         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1911 }
1912
1913 /* ************************************************************************** */
1914 /* F-CURVE MODIFIERS */
1915
1916 /* ******************** Add F-Modifier Operator *********************** */
1917
1918 /* present a special customised popup menu for this, with some filtering */
1919 static int graph_fmodifier_add_invoke (bContext *C, wmOperator *op, wmEvent *event)
1920 {
1921         uiPopupMenu *pup;
1922         uiLayout *layout;
1923         int i;
1924         
1925         pup= uiPupMenuBegin(C, "Add F-Curve Modifier", 0);
1926         layout= uiPupMenuLayout(pup);
1927         
1928         /* start from 1 to skip the 'Invalid' modifier type */
1929         for (i = 1; i < FMODIFIER_NUM_TYPES; i++) {
1930                 FModifierTypeInfo *fmi= get_fmodifier_typeinfo(i);
1931                 PointerRNA props_ptr;
1932                 
1933                 /* check if modifier is valid for this context */
1934                 if (fmi == NULL)
1935                         continue;
1936                 
1937                 /* create operator menu item with relevant properties filled in */
1938                 props_ptr= uiItemFullO(layout, fmi->name, 0, "GRAPH_OT_fmodifier_add", NULL, WM_OP_EXEC_REGION_WIN, UI_ITEM_O_RETURN_PROPS);
1939                         /* the only thing that gets set from the menu is the type of F-Modifier to add */
1940                 RNA_enum_set(&props_ptr, "type", i);
1941                         /* the following properties are just repeats of existing ones... */
1942                 RNA_boolean_set(&props_ptr, "only_active", RNA_boolean_get(op->ptr, "only_active"));
1943         }
1944         uiItemS(layout);
1945         
1946         uiPupMenuEnd(C, pup);
1947         
1948         return OPERATOR_CANCELLED;
1949 }
1950
1951 static int graph_fmodifier_add_exec(bContext *C, wmOperator *op)
1952 {
1953         bAnimContext ac;
1954         ListBase anim_data = {NULL, NULL};
1955         bAnimListElem *ale;
1956         int filter;
1957         short type;
1958         
1959         /* get editor data */
1960         if (ANIM_animdata_get_context(C, &ac) == 0)
1961                 return OPERATOR_CANCELLED;
1962         
1963         /* get type of modifier to add */
1964         type= RNA_enum_get(op->ptr, "type");
1965         
1966         /* filter data */
1967         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_CURVESONLY);
1968         if (RNA_boolean_get(op->ptr, "only_active"))
1969                 filter |= ANIMFILTER_ACTIVE;
1970         else
1971                 filter |= (ANIMFILTER_SEL|ANIMFILTER_CURVEVISIBLE);
1972         ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
1973         
1974         /* smooth keyframes */
1975         for (ale= anim_data.first; ale; ale= ale->next) {
1976                 FCurve *fcu= (FCurve *)ale->data;
1977                 FModifier *fcm;
1978                 
1979                 /* add F-Modifier of specified type to active F-Curve, and make it the active one */
1980                 fcm= add_fmodifier(&fcu->modifiers, type);
1981                 if (fcm)
1982                         set_active_fmodifier(&fcu->modifiers, fcm);
1983                 else { // TODO: stop when this happens?
1984                         BKE_report(op->reports, RPT_ERROR, "Modifier couldn't be added. See console for details.");
1985                         break;
1986                 }
1987         }
1988         BLI_freelistN(&anim_data);
1989         
1990         /* validate keyframes after editing */
1991         ANIM_editkeyframes_refresh(&ac);
1992         
1993         /* set notifier that things have changed */
1994         // FIXME: this really isn't the best description for it...
1995         WM_event_add_notifier(C, NC_ANIMATION, NULL);
1996         
1997         return OPERATOR_FINISHED;
1998 }
1999  
2000 void GRAPH_OT_fmodifier_add (wmOperatorType *ot)
2001 {
2002         /* identifiers */
2003         ot->name= "Add F-Curve Modifier";
2004         ot->idname= "GRAPH_OT_fmodifier_add";
2005         ot->description= "Add F-Modifiers to the selected F-Curves";
2006         
2007         /* api callbacks */
2008         ot->invoke= graph_fmodifier_add_invoke;
2009         ot->exec= graph_fmodifier_add_exec;
2010         ot->poll= graphop_selected_fcurve_poll; 
2011         
2012         /* flags */
2013         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2014         
2015         /* id-props */
2016         ot->prop= RNA_def_enum(ot->srna, "type", fmodifier_type_items, 0, "Type", "");
2017         RNA_def_boolean(ot->srna, "only_active", 1, "Only Active", "Only add F-Modifier to active F-Curve.");
2018 }
2019
2020 /* ************************************************************************** */