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