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