3c7ce2778b619f494db7ac2b1aa1e462567788b0
[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         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_OPEN);
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 /* this function is responsible for setting handle-type of selected keyframes */
1365 static void sethandles_graph_keys(bAnimContext *ac, short mode) 
1366 {
1367         ListBase anim_data = {NULL, NULL};
1368         bAnimListElem *ale;
1369         int filter;
1370         BeztEditFunc set_cb= ANIM_editkeyframes_handles(mode);
1371         
1372         /* filter data */
1373         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE| ANIMFILTER_FOREDIT | ANIMFILTER_CURVESONLY);
1374         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
1375         
1376         /* loop through setting flags for handles 
1377          * Note: we do not supply BeztEditData to the looper yet. Currently that's not necessary here...
1378          */
1379         // XXX we might need to supply BeztEditData to get it to only affect selected handles
1380         for (ale= anim_data.first; ale; ale= ale->next) {
1381                 if (mode == -1) {       
1382                         BeztEditFunc toggle_cb;
1383                         
1384                         /* check which type of handle to set (free or aligned) 
1385                          *      - check here checks for handles with free alignment already
1386                          */
1387                         if (ANIM_fcurve_keys_bezier_loop(NULL, ale->key_data, NULL, set_cb, NULL))
1388                                 toggle_cb= ANIM_editkeyframes_handles(HD_FREE);
1389                         else
1390                                 toggle_cb= ANIM_editkeyframes_handles(HD_ALIGN);
1391                                 
1392                         /* set handle-type */
1393                         ANIM_fcurve_keys_bezier_loop(NULL, ale->key_data, NULL, toggle_cb, calchandles_fcurve);
1394                 }
1395                 else {
1396                         /* directly set handle-type */
1397                         ANIM_fcurve_keys_bezier_loop(NULL, ale->key_data, NULL, set_cb, calchandles_fcurve);
1398                 }
1399         }
1400         
1401         /* cleanup */
1402         BLI_freelistN(&anim_data);
1403 }
1404
1405 /* ------------------- */
1406
1407 static int graphkeys_handletype_exec(bContext *C, wmOperator *op)
1408 {
1409         bAnimContext ac;
1410         short mode;
1411         
1412         /* get editor data */
1413         if (ANIM_animdata_get_context(C, &ac) == 0)
1414                 return OPERATOR_CANCELLED;
1415                 
1416         /* get handle setting mode */
1417         mode= RNA_enum_get(op->ptr, "type");
1418         
1419         /* set handle type */
1420         sethandles_graph_keys(&ac, mode);
1421         
1422         /* validate keyframes after editing */
1423         ANIM_editkeyframes_refresh(&ac);
1424         
1425         /* set notifier that things have changed */
1426         WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME_PROP, NULL);
1427         
1428         return OPERATOR_FINISHED;
1429 }
1430  
1431 void GRAPH_OT_handle_type (wmOperatorType *ot)
1432 {
1433         /* identifiers */
1434         ot->name= "Set Keyframe Handle Type";
1435         ot->idname= "GRAPH_OT_handle_type";
1436         ot->description= "Set type of handle for selected keyframes.";
1437         
1438         /* api callbacks */
1439         ot->invoke= WM_menu_invoke;
1440         ot->exec= graphkeys_handletype_exec;
1441         ot->poll= graphop_editable_keyframes_poll;
1442         
1443         /* flags */
1444         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1445         
1446         /* id-props */
1447         ot->prop= RNA_def_enum(ot->srna, "type", beztriple_handle_type_items, 0, "Type", "");
1448 }
1449
1450 /* ************************************************************************** */
1451 /* TRANSFORM STUFF */
1452
1453 /* ***************** 'Euler Filter' Operator **************************** */
1454 /* Euler filter tools (as seen in Maya), are necessary for working with 'baked'
1455  * rotation curves (with Euler rotations). The main purpose of such tools is to
1456  * resolve any discontinuities that may arise in the curves due to the clamping
1457  * of values to -180 degrees to 180 degrees.
1458  */
1459
1460 #if 0 // XXX this is not ready for the primetime yet
1461  
1462 /* set of three euler-rotation F-Curves */
1463 typedef struct tEulerFilter {
1464         ID *id;                                                 /* ID-block which owns the channels */
1465         FCurve (*fcurves)[3];                   /* 3 Pointers to F-Curves */                            
1466 } tEulerFilter;
1467  
1468 static int graphkeys_euler_filter_exec (bContext *C, wmOperator *op)
1469 {
1470         bAnimContext ac;
1471         
1472         ListBase anim_data= {NULL, NULL};
1473         bAnimListElem *ale;
1474         int filter;
1475         
1476         ListBase eulers = {NULL, NULL};
1477         tEulerFilter *euf= NULL;        
1478         
1479         /* get editor data */
1480         if (ANIM_animdata_get_context(C, &ac) == 0)
1481                 return OPERATOR_CANCELLED;
1482                 
1483         /* The process is done in two passes:
1484          *       1) Sets of three related rotation curves are identified from the selected channels,
1485          *              and are stored as a single 'operation unit' for the next step
1486          *       2) Each set of three F-Curves is processed for each keyframe, with the values being
1487          *              processed according to one of several ways.
1488          */
1489          
1490         /* step 1: extract only the rotation f-curves */
1491         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_SEL | ANIMFILTER_CURVEVISIBLE | ANIMFILTER_CURVESONLY | ANIMFILTER_FOREDIT);
1492         ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
1493         
1494         for (ale= anim_data.first; ale; ale= ale->next) {
1495                 FCurve *fcu = (FCurve *)ale->data;
1496                 
1497                 /* check if this is an appropriate F-Curve 
1498                  *      - only rotation curves
1499                  *      - for pchan curves, make sure we're only using the euler curves
1500                  */
1501                 if (strstr(fcu->rna_path, "rotation_euler") == 0)
1502                         continue;
1503                 
1504                 /* check if current set of 3-curves is suitable to add this curve to 
1505                  *      - things like whether the current set of curves is 'full' should be checked later only
1506                  *      - first check if id-blocks are compatible
1507                  */
1508                 if ((euf) && (ale->id != euf->id)) {
1509                         /* if the paths match, add this curve to the set of curves */
1510                         // NOTE: simple string compare for now... could be a bit more fancy...
1511                         
1512                 }
1513                 else {
1514                         /* just add to a new block */
1515                         euf= MEM_callocN(sizeof(tEulerFilter), "tEulerFilter");
1516                         BLI_addtail(&eulers, euf);
1517                         
1518                         euf->id= ale->id;
1519                         euf->fcurves[fcu->array_index]= fcu;
1520                 }
1521         }
1522         BLI_freelistN(&anim_data);
1523         
1524         /* step 2: go through each set of curves, processing the values at each keyframe 
1525          *      - it is assumed that there must be a full set of keyframes at each keyframe position
1526          */
1527         for (euf= eulers.first; euf; euf= euf->next) {
1528                 
1529         }
1530         BLI_freelistN(&eulers);
1531         
1532         return OPERATOR_FINISHED;
1533 }
1534  
1535 void GRAPH_OT_euler_filter (wmOperatorType *ot)
1536 {
1537         /* identifiers */
1538         ot->name= "Euler Filter";
1539         ot->idname= "GRAPH_OT_euler_filter";
1540         
1541         /* api callbacks */
1542         ot->exec= graphkeys_euler_filter_exec;
1543         ot->poll= graphop_editable_keyframes_poll;
1544         
1545         /* flags */
1546         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1547 }
1548
1549 #endif // XXX this is not ready for the primetime yet
1550
1551 /* ***************** Jump to Selected Frames Operator *********************** */
1552
1553 /* snap current-frame indicator to 'average time' of selected keyframe */
1554 static int graphkeys_framejump_exec(bContext *C, wmOperator *op)
1555 {
1556         bAnimContext ac;
1557         ListBase anim_data= {NULL, NULL};
1558         bAnimListElem *ale;
1559         int filter;
1560         BeztEditData bed;
1561         
1562         /* get editor data */
1563         if (ANIM_animdata_get_context(C, &ac) == 0)
1564                 return OPERATOR_CANCELLED;
1565         
1566         /* init edit data */
1567         memset(&bed, 0, sizeof(BeztEditData));
1568         
1569         /* loop over action data, averaging values */
1570         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE | ANIMFILTER_CURVESONLY);
1571         ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
1572         
1573         for (ale= anim_data.first; ale; ale= ale->next) {
1574                 AnimData *adt= ANIM_nla_mapping_get(&ac, ale);
1575                 
1576                 /* apply unit corrections */
1577                 ANIM_unit_mapping_apply_fcurve(ac.scene, ale->id, ale->key_data, ANIM_UNITCONV_ONLYKEYS);
1578                 
1579                 if (adt) {
1580                         ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, 1); 
1581                         ANIM_fcurve_keys_bezier_loop(&bed, ale->key_data, NULL, bezt_calc_average, NULL);
1582                         ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 1, 1); 
1583                 }
1584                 else
1585                         ANIM_fcurve_keys_bezier_loop(&bed, ale->key_data, NULL, bezt_calc_average, NULL);
1586                 
1587                 /* unapply unit corrections */
1588                 ANIM_unit_mapping_apply_fcurve(ac.scene, ale->id, ale->key_data, ANIM_UNITCONV_RESTORE|ANIM_UNITCONV_ONLYKEYS);
1589         }
1590         
1591         BLI_freelistN(&anim_data);
1592         
1593         /* set the new current frame and cursor values, based on the average time and value */
1594         if (bed.i1) {
1595                 SpaceIpo *sipo= ac.sa->spacedata.first;
1596                 Scene *scene= ac.scene;
1597                 
1598                 /* take the average values, rounding to the nearest int for the current frame */
1599                 CFRA= (int)floor((bed.f1 / bed.i1) + 0.5f);
1600                 sipo->cursorVal= bed.f2 / (float)bed.i1;
1601         }
1602         
1603         /* set notifier that things have changed */
1604         WM_event_add_notifier(C, NC_SCENE|ND_FRAME, ac.scene);
1605         
1606         return OPERATOR_FINISHED;
1607 }
1608
1609 void GRAPH_OT_frame_jump (wmOperatorType *ot)
1610 {
1611         /* identifiers */
1612         ot->name= "Jump to Frame";
1613         ot->idname= "GRAPH_OT_frame_jump";
1614         ot->description= "Set the current frame to the average frame of the selected keyframes.";
1615         
1616         /* api callbacks */
1617         ot->exec= graphkeys_framejump_exec;
1618         ot->poll= graphop_visible_keyframes_poll;
1619         
1620         /* flags */
1621         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1622 }
1623
1624 /* ******************** Snap Keyframes Operator *********************** */
1625
1626 /* defines for snap keyframes tool */
1627 EnumPropertyItem prop_graphkeys_snap_types[] = {
1628         {GRAPHKEYS_SNAP_CFRA, "CFRA", 0, "Current Frame", ""},
1629         {GRAPHKEYS_SNAP_VALUE, "VALUE", 0, "Cursor Value", ""},
1630         {GRAPHKEYS_SNAP_NEAREST_FRAME, "NEAREST_FRAME", 0, "Nearest Frame", ""}, // XXX as single entry?
1631         {GRAPHKEYS_SNAP_NEAREST_SECOND, "NEAREST_SECOND", 0, "Nearest Second", ""}, // XXX as single entry?
1632         {GRAPHKEYS_SNAP_NEAREST_MARKER, "NEAREST_MARKER", 0, "Nearest Marker", ""},
1633         {GRAPHKEYS_SNAP_HORIZONTAL, "HORIZONTAL", 0, "Flatten Handles", ""},
1634         {0, NULL, 0, NULL, NULL}
1635 };
1636
1637 /* this function is responsible for snapping keyframes to frame-times */
1638 static void snap_graph_keys(bAnimContext *ac, short mode) 
1639 {
1640         ListBase anim_data = {NULL, NULL};
1641         bAnimListElem *ale;
1642         int filter;
1643         
1644         BeztEditData bed;
1645         BeztEditFunc edit_cb;
1646         
1647         /* filter data */
1648         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_CURVESONLY);
1649         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
1650         
1651         /* get beztriple editing callbacks */
1652         edit_cb= ANIM_editkeyframes_snap(mode);
1653         
1654         memset(&bed, 0, sizeof(BeztEditData)); 
1655         bed.scene= ac->scene;
1656         if (mode == GRAPHKEYS_SNAP_NEAREST_MARKER) {
1657                 bed.list.first= (ac->markers) ? ac->markers->first : NULL;
1658                 bed.list.last= (ac->markers) ? ac->markers->last : NULL;
1659         }
1660         else if (mode == GRAPHKEYS_SNAP_VALUE) {
1661                 SpaceIpo *sipo= (SpaceIpo *)ac->sa->spacedata.first;
1662                 bed.f1= (sipo) ? sipo->cursorVal : 0.0f;
1663         }
1664         
1665         /* snap keyframes */
1666         for (ale= anim_data.first; ale; ale= ale->next) {
1667                 AnimData *adt= ANIM_nla_mapping_get(ac, ale);
1668                 
1669                 /* apply unit corrections */
1670                 ANIM_unit_mapping_apply_fcurve(ac->scene, ale->id, ale->key_data, 0);
1671                 
1672                 if (adt) {
1673                         ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, 1); 
1674                         ANIM_fcurve_keys_bezier_loop(&bed, ale->key_data, NULL, edit_cb, calchandles_fcurve);
1675                         ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 1, 1);
1676                 }
1677                 else 
1678                         ANIM_fcurve_keys_bezier_loop(&bed, ale->key_data, NULL, edit_cb, calchandles_fcurve);
1679                         
1680                 /* apply unit corrections */
1681                 ANIM_unit_mapping_apply_fcurve(ac->scene, ale->id, ale->key_data, ANIM_UNITCONV_RESTORE);
1682         }
1683         
1684         BLI_freelistN(&anim_data);
1685 }
1686
1687 /* ------------------- */
1688
1689 static int graphkeys_snap_exec(bContext *C, wmOperator *op)
1690 {
1691         bAnimContext ac;
1692         short mode;
1693         
1694         /* get editor data */
1695         if (ANIM_animdata_get_context(C, &ac) == 0)
1696                 return OPERATOR_CANCELLED;
1697                 
1698         /* get snapping mode */
1699         mode= RNA_enum_get(op->ptr, "type");
1700         
1701         /* snap keyframes */
1702         snap_graph_keys(&ac, mode);
1703         
1704         /* validate keyframes after editing */
1705         ANIM_editkeyframes_refresh(&ac);
1706         
1707         /* set notifier that keyframes have changed */
1708         WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME_EDIT, NULL);
1709         
1710         return OPERATOR_FINISHED;
1711 }
1712  
1713 void GRAPH_OT_snap (wmOperatorType *ot)
1714 {
1715         /* identifiers */
1716         ot->name= "Snap Keys";
1717         ot->idname= "GRAPH_OT_snap";
1718         ot->description= "Snap selected keyframes to the chosen times/values.";
1719         
1720         /* api callbacks */
1721         ot->invoke= WM_menu_invoke;
1722         ot->exec= graphkeys_snap_exec;
1723         ot->poll= graphop_editable_keyframes_poll;
1724         
1725         /* flags */
1726         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1727         
1728         /* id-props */
1729         ot->prop= RNA_def_enum(ot->srna, "type", prop_graphkeys_snap_types, 0, "Type", "");
1730 }
1731
1732 /* ******************** Mirror Keyframes Operator *********************** */
1733
1734 /* defines for mirror keyframes tool */
1735 EnumPropertyItem prop_graphkeys_mirror_types[] = {
1736         {GRAPHKEYS_MIRROR_CFRA, "CFRA", 0, "By Times over Current Frame", ""},
1737         {GRAPHKEYS_MIRROR_VALUE, "VALUE", 0, "By Values over Cursor Value", ""},
1738         {GRAPHKEYS_MIRROR_YAXIS, "YAXIS", 0, "By Times over Time=0", ""},
1739         {GRAPHKEYS_MIRROR_XAXIS, "XAXIS", 0, "By Values over Value=0", ""},
1740         {GRAPHKEYS_MIRROR_MARKER, "MARKER", 0, "By Times over First Selected Marker", ""},
1741         {0, NULL, 0, NULL, NULL}
1742 };
1743
1744 /* this function is responsible for mirroring keyframes */
1745 static void mirror_graph_keys(bAnimContext *ac, short mode) 
1746 {
1747         ListBase anim_data = {NULL, NULL};
1748         bAnimListElem *ale;
1749         int filter;
1750         
1751         BeztEditData bed;
1752         BeztEditFunc edit_cb;
1753         
1754         /* get beztriple editing callbacks */
1755         edit_cb= ANIM_editkeyframes_mirror(mode);
1756         
1757         memset(&bed, 0, sizeof(BeztEditData)); 
1758         bed.scene= ac->scene;
1759         
1760         /* for 'first selected marker' mode, need to find first selected marker first! */
1761         // XXX should this be made into a helper func in the API?
1762         if (mode == GRAPHKEYS_MIRROR_MARKER) {
1763                 TimeMarker *marker= NULL;
1764                 
1765                 /* find first selected marker */
1766                 if (ac->markers) {
1767                         for (marker= ac->markers->first; marker; marker=marker->next) {
1768                                 if (marker->flag & SELECT) {
1769                                         break;
1770                                 }
1771                         }
1772                 }
1773                 
1774                 /* store marker's time (if available) */
1775                 if (marker)
1776                         bed.f1= (float)marker->frame;
1777                 else
1778                         return;
1779         }
1780         else if (mode == GRAPHKEYS_MIRROR_VALUE) {
1781                 SpaceIpo *sipo= (SpaceIpo *)ac->sa->spacedata.first;
1782                 bed.f1= (sipo) ? sipo->cursorVal : 0.0f;
1783         }
1784         
1785         /* filter data */
1786         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE| ANIMFILTER_FOREDIT | ANIMFILTER_CURVESONLY);
1787         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
1788         
1789         /* mirror keyframes */
1790         for (ale= anim_data.first; ale; ale= ale->next) {
1791                 AnimData *adt= ANIM_nla_mapping_get(ac, ale);
1792                 
1793                 /* apply unit corrections */
1794                 ANIM_unit_mapping_apply_fcurve(ac->scene, ale->id, ale->key_data, ANIM_UNITCONV_ONLYKEYS);
1795                 
1796                 if (adt) {
1797                         ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, 1); 
1798                         ANIM_fcurve_keys_bezier_loop(&bed, ale->key_data, NULL, edit_cb, calchandles_fcurve);
1799                         ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 1, 1);
1800                 }
1801                 else 
1802                         ANIM_fcurve_keys_bezier_loop(&bed, ale->key_data, NULL, edit_cb, calchandles_fcurve);
1803                         
1804                 /* unapply unit corrections */
1805                 ANIM_unit_mapping_apply_fcurve(ac->scene, ale->id, ale->key_data, ANIM_UNITCONV_ONLYKEYS|ANIM_UNITCONV_RESTORE);
1806         }
1807         
1808         BLI_freelistN(&anim_data);
1809 }
1810
1811 /* ------------------- */
1812
1813 static int graphkeys_mirror_exec(bContext *C, wmOperator *op)
1814 {
1815         bAnimContext ac;
1816         short mode;
1817         
1818         /* get editor data */
1819         if (ANIM_animdata_get_context(C, &ac) == 0)
1820                 return OPERATOR_CANCELLED;
1821                 
1822         /* get mirroring mode */
1823         mode= RNA_enum_get(op->ptr, "type");
1824         
1825         /* mirror keyframes */
1826         mirror_graph_keys(&ac, mode);
1827         
1828         /* validate keyframes after editing */
1829         ANIM_editkeyframes_refresh(&ac);
1830         
1831         /* set notifier that keyframes have changed */
1832         WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME_EDIT, NULL);
1833         
1834         return OPERATOR_FINISHED;
1835 }
1836  
1837 void GRAPH_OT_mirror (wmOperatorType *ot)
1838 {
1839         /* identifiers */
1840         ot->name= "Mirror Keys";
1841         ot->idname= "GRAPH_OT_mirror";
1842         ot->description= "Flip selected keyframes over the selected mirror line.";
1843         
1844         /* api callbacks */
1845         ot->invoke= WM_menu_invoke;
1846         ot->exec= graphkeys_mirror_exec;
1847         ot->poll= graphop_editable_keyframes_poll;
1848         
1849         /* flags */
1850         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1851         
1852         /* id-props */
1853         ot->prop= RNA_def_enum(ot->srna, "type", prop_graphkeys_mirror_types, 0, "Type", "");
1854 }
1855
1856 /* ******************** Smooth Keyframes Operator *********************** */
1857
1858 static int graphkeys_smooth_exec(bContext *C, wmOperator *op)
1859 {
1860         bAnimContext ac;
1861         ListBase anim_data = {NULL, NULL};
1862         bAnimListElem *ale;
1863         int filter;
1864         
1865         /* get editor data */
1866         if (ANIM_animdata_get_context(C, &ac) == 0)
1867                 return OPERATOR_CANCELLED;
1868         
1869         /* filter data */
1870         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE| ANIMFILTER_FOREDIT | ANIMFILTER_CURVESONLY);
1871         ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
1872         
1873         /* smooth keyframes */
1874         for (ale= anim_data.first; ale; ale= ale->next) {
1875                 /* For now, we can only smooth by flattening handles AND smoothing curve values.
1876                  * Perhaps the mode argument could be removed, as that functionality is offerred through 
1877                  * Snap->Flatten Handles anyway.
1878                  */
1879                 smooth_fcurve(ale->key_data);
1880         }
1881         BLI_freelistN(&anim_data);
1882         
1883         /* validate keyframes after editing */
1884         ANIM_editkeyframes_refresh(&ac);
1885         
1886         /* set notifier that keyframes have changed */
1887         WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME_EDIT, NULL);
1888         
1889         return OPERATOR_FINISHED;
1890 }
1891  
1892 void GRAPH_OT_smooth (wmOperatorType *ot)
1893 {
1894         /* identifiers */
1895         ot->name= "Smooth Keys";
1896         ot->idname= "GRAPH_OT_smooth";
1897         ot->description= "Apply weighted moving means to make selected F-Curves less bumpy.";
1898         
1899         /* api callbacks */
1900         ot->exec= graphkeys_smooth_exec;
1901         ot->poll= graphop_editable_keyframes_poll;
1902         
1903         /* flags */
1904         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1905 }
1906
1907 /* ************************************************************************** */
1908 /* F-CURVE MODIFIERS */
1909
1910 /* ******************** Add F-Modifier Operator *********************** */
1911
1912 /* present a special customised popup menu for this, with some filtering */
1913 static int graph_fmodifier_add_invoke (bContext *C, wmOperator *op, wmEvent *event)
1914 {
1915         uiPopupMenu *pup;
1916         uiLayout *layout;
1917         int i;
1918         
1919         pup= uiPupMenuBegin(C, "Add F-Curve Modifier", 0);
1920         layout= uiPupMenuLayout(pup);
1921         
1922         /* start from 1 to skip the 'Invalid' modifier type */
1923         for (i = 1; i < FMODIFIER_NUM_TYPES; i++) {
1924                 FModifierTypeInfo *fmi= get_fmodifier_typeinfo(i);
1925                 PointerRNA props_ptr;
1926                 
1927                 /* check if modifier is valid for this context */
1928                 if (fmi == NULL)
1929                         continue;
1930                 
1931                 /* create operator menu item with relevant properties filled in */
1932                 props_ptr= uiItemFullO(layout, fmi->name, 0, "GRAPH_OT_fmodifier_add", NULL, WM_OP_EXEC_REGION_WIN, UI_ITEM_O_RETURN_PROPS);
1933                         /* the only thing that gets set from the menu is the type of F-Modifier to add */
1934                 RNA_enum_set(&props_ptr, "type", i);
1935                         /* the following properties are just repeats of existing ones... */
1936                 RNA_boolean_set(&props_ptr, "only_active", RNA_boolean_get(op->ptr, "only_active"));
1937         }
1938         uiItemS(layout);
1939         
1940         uiPupMenuEnd(C, pup);
1941         
1942         return OPERATOR_CANCELLED;
1943 }
1944
1945 static int graph_fmodifier_add_exec(bContext *C, wmOperator *op)
1946 {
1947         bAnimContext ac;
1948         ListBase anim_data = {NULL, NULL};
1949         bAnimListElem *ale;
1950         int filter;
1951         short type;
1952         
1953         /* get editor data */
1954         if (ANIM_animdata_get_context(C, &ac) == 0)
1955                 return OPERATOR_CANCELLED;
1956         
1957         /* get type of modifier to add */
1958         type= RNA_enum_get(op->ptr, "type");
1959         
1960         /* filter data */
1961         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_CURVESONLY);
1962         if (RNA_boolean_get(op->ptr, "only_active"))
1963                 filter |= ANIMFILTER_ACTIVE;
1964         else
1965                 filter |= (ANIMFILTER_SEL|ANIMFILTER_CURVEVISIBLE);
1966         ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
1967         
1968         /* smooth keyframes */
1969         for (ale= anim_data.first; ale; ale= ale->next) {
1970                 FCurve *fcu= (FCurve *)ale->data;
1971                 FModifier *fcm;
1972                 
1973                 /* add F-Modifier of specified type to active F-Curve, and make it the active one */
1974                 fcm= add_fmodifier(&fcu->modifiers, type);
1975                 if (fcm)
1976                         set_active_fmodifier(&fcu->modifiers, fcm);
1977                 else { // TODO: stop when this happens?
1978                         BKE_report(op->reports, RPT_ERROR, "Modifier couldn't be added. See console for details.");
1979                         break;
1980                 }
1981         }
1982         BLI_freelistN(&anim_data);
1983         
1984         /* validate keyframes after editing */
1985         ANIM_editkeyframes_refresh(&ac);
1986         
1987         /* set notifier that things have changed */
1988         // FIXME: this really isn't the best description for it...
1989         WM_event_add_notifier(C, NC_ANIMATION, NULL);
1990         
1991         return OPERATOR_FINISHED;
1992 }
1993  
1994 void GRAPH_OT_fmodifier_add (wmOperatorType *ot)
1995 {
1996         /* identifiers */
1997         ot->name= "Add F-Curve Modifier";
1998         ot->idname= "GRAPH_OT_fmodifier_add";
1999         ot->description= "Add F-Modifiers to the selected F-Curves.";
2000         
2001         /* api callbacks */
2002         ot->invoke= graph_fmodifier_add_invoke;
2003         ot->exec= graph_fmodifier_add_exec;
2004         ot->poll= graphop_selected_fcurve_poll; 
2005         
2006         /* flags */
2007         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2008         
2009         /* id-props */
2010         RNA_def_enum(ot->srna, "type", fmodifier_type_items, 0, "Type", "");
2011         RNA_def_boolean(ot->srna, "only_active", 1, "Only Active", "Only add F-Modifier to active F-Curve.");
2012 }
2013
2014 /* ************************************************************************** */