First merge with 2.5 branch.
[blender.git] / source / blender / editors / space_graph / graph_edit.c
1 /**
2  * $Id: editaction.c 17746 2008-12-08 11:19:44Z aligorith $
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19  *
20  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
21  * All rights reserved.
22  *
23  * The Original Code is: all of this file.
24  *
25  * Contributor(s): Joshua Leung
26  *
27  * ***** END GPL LICENSE BLOCK *****
28  */
29
30 #include <math.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <float.h>
34
35 #ifdef HAVE_CONFIG_H
36 #include <config.h>
37 #endif
38
39 #include "MEM_guardedalloc.h"
40
41 #include "BLI_blenlib.h"
42 #include "BLI_arithb.h"
43
44 #include "DNA_anim_types.h"
45 #include "DNA_action_types.h"
46 #include "DNA_armature_types.h"
47 #include "DNA_camera_types.h"
48 #include "DNA_curve_types.h"
49 #include "DNA_object_types.h"
50 #include "DNA_screen_types.h"
51 #include "DNA_scene_types.h"
52 #include "DNA_space_types.h"
53 #include "DNA_constraint_types.h"
54 #include "DNA_key_types.h"
55 #include "DNA_lamp_types.h"
56 #include "DNA_material_types.h"
57 #include "DNA_userdef_types.h"
58 #include "DNA_gpencil_types.h"
59 #include "DNA_windowmanager_types.h"
60
61 #include "RNA_access.h"
62 #include "RNA_define.h"
63 #include "RNA_enum_types.h"
64
65 #include "BKE_action.h"
66 #include "BKE_depsgraph.h"
67 #include "BKE_fcurve.h"
68 #include "BKE_key.h"
69 #include "BKE_material.h"
70 #include "BKE_object.h"
71 #include "BKE_context.h"
72 #include "BKE_report.h"
73 #include "BKE_utildefines.h"
74
75 #include "UI_view2d.h"
76
77 #include "BIF_transform.h"
78
79 #include "ED_anim_api.h"
80 #include "ED_keyframing.h"
81 #include "ED_keyframes_draw.h"
82 #include "ED_keyframes_edit.h"
83 #include "ED_screen.h"
84 #include "ED_space_api.h"
85
86 #include "WM_api.h"
87 #include "WM_types.h"
88
89 #include "graph_intern.h"
90
91 /* ************************************************************************** */
92 /* KEYFRAME-RANGE STUFF */
93
94 /* *************************** Calculate Range ************************** */
95
96 /* Get the min/max keyframes*/
97 static void get_graph_keyframe_extents (bAnimContext *ac, float *xmin, float *xmax, float *ymin, float *ymax)
98 {
99         ListBase anim_data = {NULL, NULL};
100         bAnimListElem *ale;
101         int filter;
102         
103         /* get data to filter, from Dopesheet */
104         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE | ANIMFILTER_SEL | ANIMFILTER_FOREDIT | ANIMFILTER_CURVESONLY);
105         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
106         
107         /* set large values to try to override */
108         if (xmin) *xmin= 999999999.0f;
109         if (xmax) *xmax= -999999999.0f;
110         if (ymin) *ymin= 999999999.0f;
111         if (ymax) *ymax= -999999999.0f;
112         
113         /* check if any channels to set range with */
114         if (anim_data.first) {
115                 /* go through channels, finding max extents */
116                 for (ale= anim_data.first; ale; ale= ale->next) {
117                         Object *nob= NULL; //ANIM_nla_mapping_get(ac, ale);
118                         FCurve *fcu= (FCurve *)ale->key_data;
119                         float tmin, tmax;
120                         
121                         /* get range and apply necessary scaling before */
122                         calc_fcurve_bounds(fcu, &tmin, &tmax, ymin, ymax);
123                         
124                         if (nob) {
125                                 tmin= get_action_frame_inv(nob, tmin);
126                                 tmax= get_action_frame_inv(nob, tmax);
127                         }
128                         
129                         /* try to set cur using these values, if they're more extreme than previously set values */
130                         if (xmin) *xmin= MIN2(*xmin, tmin);
131                         if (xmax) *xmax= MAX2(*xmax, tmax);
132                 }
133                 
134                 /* free memory */
135                 BLI_freelistN(&anim_data);
136         }
137         else {
138                 /* set default range */
139                 if (ac->scene) {
140                         if (xmin) *xmin= (float)ac->scene->r.sfra;
141                         if (xmax) *xmax= (float)ac->scene->r.efra;
142                 }
143                 else {
144                         if (xmin) *xmin= -5;
145                         if (xmax) *xmax= 100;
146                 }
147                 
148                 if (ymin) *ymin= -5;
149                 if (ymax) *ymax= 5;
150         }
151 }
152
153 /* ****************** Automatic Preview-Range Operator ****************** */
154
155 static int graphkeys_previewrange_exec(bContext *C, wmOperator *op)
156 {
157         bAnimContext ac;
158         Scene *scene;
159         float min, max;
160         
161         /* get editor data */
162         if (ANIM_animdata_get_context(C, &ac) == 0)
163                 return OPERATOR_CANCELLED;
164         if (ac.scene == NULL)
165                 return OPERATOR_CANCELLED;
166         else
167                 scene= ac.scene;
168         
169         /* set the range directly */
170         get_graph_keyframe_extents(&ac, &min, &max, NULL, NULL);
171         scene->r.psfra= (int)floor(min + 0.5f);
172         scene->r.pefra= (int)floor(max + 0.5f);
173         
174         /* set notifier that things have changed */
175         // XXX err... there's nothing for frame ranges yet, but this should do fine too
176         WM_event_add_notifier(C, NC_SCENE|ND_FRAME, ac.scene); 
177         
178         return OPERATOR_FINISHED;
179 }
180  
181 void GRAPHEDIT_OT_previewrange_set (wmOperatorType *ot)
182 {
183         /* identifiers */
184         ot->name= "Auto-Set Preview Range";
185         ot->idname= "GRAPHEDIT_OT_previewrange_set";
186         
187         /* api callbacks */
188         ot->exec= graphkeys_previewrange_exec;
189         ot->poll= ED_operator_areaactive;
190         
191         /* flags */
192         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
193 }
194
195 /* ****************** View-All Operator ****************** */
196
197 static int graphkeys_viewall_exec(bContext *C, wmOperator *op)
198 {
199         bAnimContext ac;
200         View2D *v2d;
201         float extra;
202         
203         /* get editor data */
204         if (ANIM_animdata_get_context(C, &ac) == 0)
205                 return OPERATOR_CANCELLED;
206         v2d= &ac.ar->v2d;
207         
208         /* set the horizontal range, with an extra offset so that the extreme keys will be in view */
209         get_graph_keyframe_extents(&ac, &v2d->cur.xmin, &v2d->cur.xmax, &v2d->cur.ymin, &v2d->cur.ymax);
210         
211         extra= 0.1f * (v2d->cur.xmax - v2d->cur.xmin);
212         v2d->cur.xmin -= extra;
213         v2d->cur.xmax += extra;
214         
215         extra= 0.1f * (v2d->cur.ymax - v2d->cur.ymin);
216         v2d->cur.ymin -= extra;
217         v2d->cur.ymax += extra;
218         
219         /* do View2D syncing */
220         UI_view2d_sync(CTX_wm_screen(C), CTX_wm_area(C), v2d, V2D_LOCK_COPY);
221         
222         /* set notifier that things have changed */
223         ED_area_tag_redraw(CTX_wm_area(C));
224         
225         return OPERATOR_FINISHED;
226 }
227  
228 void GRAPHEDIT_OT_view_all (wmOperatorType *ot)
229 {
230         /* identifiers */
231         ot->name= "View All";
232         ot->idname= "GRAPHEDIT_OT_view_all";
233         
234         /* api callbacks */
235         ot->exec= graphkeys_viewall_exec;
236         ot->poll= ED_operator_areaactive;
237         
238         /* flags */
239         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
240 }
241
242 /* ******************** Create Ghost-Curves Operator *********************** */
243 /* This operator samples the data of the selected F-Curves to F-Points, storing them
244  * as 'ghost curves' in the active Graph Editor
245  */
246
247 /* Bake each F-Curve into a set of samples, and store as a ghost curve */
248 static void create_ghost_curves (bAnimContext *ac, int start, int end)
249 {       
250         SpaceIpo *sipo= (SpaceIpo *)ac->sa->spacedata.first;
251         ListBase anim_data = {NULL, NULL};
252         bAnimListElem *ale;
253         int filter;
254         
255         /* free existing ghost curves */
256         free_fcurves(&sipo->ghostCurves);
257         
258         /* sanity check */
259         if (start >= end) {
260                 printf("Error: Frame range for Ghost F-Curve creation is inappropriate \n");
261                 return;
262         }
263         
264         /* filter data */
265         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE | ANIMFILTER_SEL | ANIMFILTER_CURVESONLY);
266         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
267         
268         /* loop through filtered data and add keys between selected keyframes on every frame  */
269         for (ale= anim_data.first; ale; ale= ale->next) {
270                 FCurve *fcu= (FCurve *)ale->key_data;
271                 FCurve *gcu= MEM_callocN(sizeof(FCurve), "Ghost FCurve");
272                 ChannelDriver *driver= fcu->driver;
273                 FPoint *fpt;
274                 int cfra;               
275                 
276                 /* disable driver so that it don't muck up the sampling process */
277                 fcu->driver= NULL;
278                 
279                 /* create samples, but store them in a new curve 
280                  *      - we cannot use fcurve_store_samples() as that will only overwrite the original curve 
281                  */
282                 gcu->fpt= fpt= MEM_callocN(sizeof(FPoint)*(end-start+1), "Ghost FPoint Samples");
283                 gcu->totvert= end - start + 1;
284                 
285                 /* use the sampling callback at 1-frame intervals from start to end frames */
286                 for (cfra= start; cfra <= end; cfra++, fpt++) {
287                         fpt->vec[0]= (float)cfra;
288                         fpt->vec[1]= fcurve_samplingcb_evalcurve(fcu, NULL, (float)cfra);
289                 }
290                 
291                 /* set color of ghost curve 
292                  *      - make the color slightly darker
293                  */
294                 gcu->color[0]= fcu->color[0] - 0.07f;
295                 gcu->color[1]= fcu->color[1] - 0.07f;
296                 gcu->color[2]= fcu->color[2] - 0.07f;
297                 
298                 /* store new ghost curve */
299                 BLI_addtail(&sipo->ghostCurves, gcu);
300                 
301                 /* restore driver */
302                 fcu->driver= driver;
303         }
304         
305         /* admin and redraws */
306         BLI_freelistN(&anim_data);
307 }
308
309 /* ------------------- */
310
311 static int graphkeys_create_ghostcurves_exec(bContext *C, wmOperator *op)
312 {
313         bAnimContext ac;
314         View2D *v2d;
315         int start, end;
316         
317         /* get editor data */
318         if (ANIM_animdata_get_context(C, &ac) == 0)
319                 return OPERATOR_CANCELLED;
320                 
321         /* ghost curves are snapshots of the visible portions of the curves, so set range to be the visible range */
322         v2d= &ac.ar->v2d;
323         start= (int)v2d->cur.xmin;
324         end= (int)v2d->cur.xmax;
325         
326         /* bake selected curves into a ghost curve */
327         create_ghost_curves(&ac, start, end);
328         
329         /* update this editor only */
330         ED_area_tag_redraw(CTX_wm_area(C));
331         
332         return OPERATOR_FINISHED;
333 }
334  
335 void GRAPHEDIT_OT_ghost_curves_create (wmOperatorType *ot)
336 {
337         /* identifiers */
338         ot->name= "Create Ghost Curves";
339         ot->idname= "GRAPHEDIT_OT_ghost_curves_create";
340         ot->description= "Create snapshot (Ghosts) of selected F-Curves as background aid for active Graph Editor.";
341         
342         /* api callbacks */
343         ot->exec= graphkeys_create_ghostcurves_exec;
344         ot->poll= ED_operator_areaactive;
345         
346         /* flags */
347         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
348         
349         // todo: add props for start/end frames
350 }
351
352 /* ******************** Clear Ghost-Curves Operator *********************** */
353 /* This operator clears the 'ghost curves' for the active Graph Editor */
354
355 static int graphkeys_clear_ghostcurves_exec(bContext *C, wmOperator *op)
356 {
357         bAnimContext ac;
358         SpaceIpo *sipo;
359         
360         /* get editor data */
361         if (ANIM_animdata_get_context(C, &ac) == 0)
362                 return OPERATOR_CANCELLED;
363         sipo= (SpaceIpo *)ac.sa->spacedata.first;
364                 
365         /* if no ghost curves, don't do anything */
366         if (sipo->ghostCurves.first == NULL)
367                 return OPERATOR_CANCELLED;
368         
369         /* free ghost curves */
370         free_fcurves(&sipo->ghostCurves);
371         
372         /* update this editor only */
373         ED_area_tag_redraw(CTX_wm_area(C));
374         
375         return OPERATOR_FINISHED;
376 }
377  
378 void GRAPHEDIT_OT_ghost_curves_clear (wmOperatorType *ot)
379 {
380         /* identifiers */
381         ot->name= "Create Ghost Curves";
382         ot->idname= "GRAPHEDIT_OT_ghost_curves_clear";
383         ot->description= "Clear F-Curve snapshots (Ghosts) for active Graph Editor.";
384         
385         /* api callbacks */
386         ot->exec= graphkeys_clear_ghostcurves_exec;
387         ot->poll= ED_operator_areaactive;
388         
389         /* flags */
390         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
391 }
392
393 /* ************************************************************************** */
394 /* GENERAL STUFF */
395
396 // TODO: insertkey
397
398 /* ******************** Click-Insert Keyframes Operator ************************* */
399
400 static int graphkeys_click_insert_exec (bContext *C, wmOperator *op)
401 {
402         bAnimContext ac;
403         bAnimListElem *ale;
404         float frame, val;
405         
406         /* get animation context */
407         if (ANIM_animdata_get_context(C, &ac) == 0)
408                 return OPERATOR_CANCELLED;
409         
410         /* get active F-Curve 'anim-list-element' */
411         ale= get_active_fcurve_channel(&ac);
412         if (ELEM(NULL, ale, ale->data)) {
413                 if (ale) MEM_freeN(ale);
414                 return OPERATOR_CANCELLED;
415         }
416                 
417         /* get frame and value from props */
418         frame= RNA_float_get(op->ptr, "frame");
419         val= RNA_float_get(op->ptr, "value");
420         
421         /* insert keyframe on the specified frame + value */
422         insert_vert_fcurve((FCurve *)ale->data, frame, val, 0);
423         
424         /* free temp data */
425         MEM_freeN(ale);
426         
427         /* set notifier that things have changed */
428         ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_KEYFRAMES_VALUES);
429         
430         /* done */
431         return OPERATOR_FINISHED;
432 }
433
434 static int graphkeys_click_insert_invoke (bContext *C, wmOperator *op, wmEvent *evt)
435 {
436         bAnimContext ac;
437         ARegion *ar;
438         View2D *v2d;
439         int mval[2];
440         float x, y;
441         
442         /* get animation context */
443         if (ANIM_animdata_get_context(C, &ac) == 0)
444                 return OPERATOR_CANCELLED;
445         
446         /* store mouse coordinates in View2D space, into the operator's properties */
447         ar= ac.ar;
448         v2d= &ar->v2d;
449         
450         mval[0]= (evt->x - ar->winrct.xmin);
451         mval[1]= (evt->y - ar->winrct.ymin);
452         
453         UI_view2d_region_to_view(v2d, mval[0], mval[1], &x, &y);
454         
455         RNA_float_set(op->ptr, "frame", x);
456         RNA_float_set(op->ptr, "value", y);
457         
458         /* run exec now */
459         return graphkeys_click_insert_exec(C, op);
460 }
461
462 void GRAPHEDIT_OT_keyframes_click_insert (wmOperatorType *ot)
463 {
464         /* identifiers */
465         ot->name= "Click-Insert Keyframes";
466         ot->idname= "GRAPHEDIT_OT_keyframes_click_insert";
467         
468         /* api callbacks */
469         ot->invoke= graphkeys_click_insert_invoke;
470         ot->exec= graphkeys_click_insert_exec;
471         ot->poll= ED_operator_areaactive; // XXX active + editable poll
472         
473         /* flags */
474         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
475         
476         /* properties */
477         RNA_def_float(ot->srna, "frame", 1.0f, -FLT_MAX, FLT_MAX, "Frame Number", "Frame to insert keyframe on", 0, 100);
478         RNA_def_float(ot->srna, "value", 1.0f, -FLT_MAX, FLT_MAX, "Value", "Value for keyframe on", 0, 100);
479 }
480
481 /* ******************** Copy/Paste Keyframes Operator ************************* */
482 /* NOTE: the backend code for this is shared with the dopesheet editor */
483
484 static short copy_graph_keys (bAnimContext *ac)
485 {       
486         ListBase anim_data = {NULL, NULL};
487         int filter, ok=0;
488         
489         /* clear buffer first */
490         free_anim_copybuf();
491         
492         /* filter data */
493         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE | ANIMFILTER_CURVESONLY);
494         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
495         
496         /* copy keyframes */
497         ok= copy_animedit_keys(ac, &anim_data);
498         
499         /* clean up */
500         BLI_freelistN(&anim_data);
501
502         return ok;
503 }
504
505 static short paste_graph_keys (bAnimContext *ac)
506 {       
507         ListBase anim_data = {NULL, NULL};
508         int filter, ok=0;
509         
510         /* filter data */
511         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE | ANIMFILTER_SEL | ANIMFILTER_FOREDIT | ANIMFILTER_CURVESONLY);
512         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
513         
514         /* paste keyframes */
515         ok= paste_animedit_keys(ac, &anim_data);
516         
517         /* clean up */
518         BLI_freelistN(&anim_data);
519
520         return ok;
521 }
522
523 /* ------------------- */
524
525 static int graphkeys_copy_exec(bContext *C, wmOperator *op)
526 {
527         bAnimContext ac;
528         
529         /* get editor data */
530         if (ANIM_animdata_get_context(C, &ac) == 0)
531                 return OPERATOR_CANCELLED;
532         
533         /* copy keyframes */
534         if (copy_graph_keys(&ac)) {     
535                 BKE_report(op->reports, RPT_ERROR, "No keyframes copied to keyframes copy/paste buffer");
536                 return OPERATOR_CANCELLED;
537         }
538         
539         /* set notifier that things have changed */
540         ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_KEYFRAMES_VALUES);
541         
542         return OPERATOR_FINISHED;
543 }
544  
545 void GRAPHEDIT_OT_keyframes_copy (wmOperatorType *ot)
546 {
547         /* identifiers */
548         ot->name= "Copy Keyframes";
549         ot->idname= "GRAPHEDIT_OT_keyframes_copy";
550         
551         /* api callbacks */
552         ot->exec= graphkeys_copy_exec;
553         ot->poll= ED_operator_areaactive;
554         
555         /* flags */
556         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
557 }
558
559
560
561 static int graphkeys_paste_exec(bContext *C, wmOperator *op)
562 {
563         bAnimContext ac;
564         
565         /* get editor data */
566         if (ANIM_animdata_get_context(C, &ac) == 0)
567                 return OPERATOR_CANCELLED;
568         
569         /* paste keyframes */
570         if (paste_graph_keys(&ac)) {
571                 BKE_report(op->reports, RPT_ERROR, "No keyframes to paste");
572                 return OPERATOR_CANCELLED;
573         }
574         
575         /* validate keyframes after editing */
576         ANIM_editkeyframes_refresh(&ac);
577         
578         /* set notifier that things have changed */
579         ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_KEYFRAMES_VALUES);
580         
581         return OPERATOR_FINISHED;
582 }
583  
584 void GRAPHEDIT_OT_keyframes_paste (wmOperatorType *ot)
585 {
586         /* identifiers */
587         ot->name= "Paste Keyframes";
588         ot->idname= "GRAPHEDIT_OT_keyframes_paste";
589         
590         /* api callbacks */
591         ot->exec= graphkeys_paste_exec;
592         ot->poll= ED_operator_areaactive;
593         
594         /* flags */
595         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
596 }
597
598 /* ******************** Duplicate Keyframes Operator ************************* */
599
600 static void duplicate_graph_keys (bAnimContext *ac)
601 {
602         ListBase anim_data = {NULL, NULL};
603         bAnimListElem *ale;
604         int filter;
605         
606         /* filter data */
607         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE| ANIMFILTER_FOREDIT | ANIMFILTER_CURVESONLY);
608         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
609         
610         /* loop through filtered data and delete selected keys */
611         for (ale= anim_data.first; ale; ale= ale->next) {
612                 duplicate_fcurve_keys((FCurve *)ale->key_data);
613         }
614         
615         /* free filtered list */
616         BLI_freelistN(&anim_data);
617 }
618
619 /* ------------------- */
620
621 static int graphkeys_duplicate_exec(bContext *C, wmOperator *op)
622 {
623         bAnimContext ac;
624         
625         /* get editor data */
626         if (ANIM_animdata_get_context(C, &ac) == 0)
627                 return OPERATOR_CANCELLED;
628                 
629         /* duplicate keyframes */
630         duplicate_graph_keys(&ac);
631         
632         /* validate keyframes after editing */
633         ANIM_editkeyframes_refresh(&ac);
634         
635         /* set notifier that things have changed */
636         ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_KEYFRAMES_VALUES);
637         
638         return OPERATOR_FINISHED;
639 }
640
641 static int graphkeys_duplicate_invoke(bContext *C, wmOperator *op, wmEvent *event)
642 {
643         graphkeys_duplicate_exec(C, op);
644         
645         RNA_int_set(op->ptr, "mode", TFM_TRANSLATION);
646         WM_operator_name_call(C, "TFM_OT_transform", WM_OP_INVOKE_REGION_WIN, op->ptr);
647
648         return OPERATOR_FINISHED;
649 }
650  
651 void GRAPHEDIT_OT_keyframes_duplicate (wmOperatorType *ot)
652 {
653         /* identifiers */
654         ot->name= "Duplicate Keyframes";
655         ot->idname= "GRAPHEDIT_OT_keyframes_duplicate";
656         
657         /* api callbacks */
658         ot->invoke= graphkeys_duplicate_invoke;
659         ot->exec= graphkeys_duplicate_exec;
660         ot->poll= ED_operator_areaactive;
661         
662         /* flags */
663         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
664         
665         /* to give to transform */
666         RNA_def_int(ot->srna, "mode", TFM_TRANSLATION, 0, INT_MAX, "Mode", "", 0, INT_MAX);
667 }
668
669 /* ******************** Delete Keyframes Operator ************************* */
670
671 static void delete_graph_keys (bAnimContext *ac)
672 {
673         ListBase anim_data = {NULL, NULL};
674         bAnimListElem *ale;
675         int filter;
676         
677         /* filter data */
678         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE| ANIMFILTER_FOREDIT | ANIMFILTER_CURVESONLY);
679         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
680         
681         /* loop through filtered data and delete selected keys */
682         for (ale= anim_data.first; ale; ale= ale->next) {
683                 delete_fcurve_keys((FCurve *)ale->key_data); // XXX... this doesn't delete empty curves anymore
684         }
685         
686         /* free filtered list */
687         BLI_freelistN(&anim_data);
688 }
689
690 /* ------------------- */
691
692 static int graphkeys_delete_exec(bContext *C, wmOperator *op)
693 {
694         bAnimContext ac;
695         
696         /* get editor data */
697         if (ANIM_animdata_get_context(C, &ac) == 0)
698                 return OPERATOR_CANCELLED;
699                 
700         /* delete keyframes */
701         delete_graph_keys(&ac);
702         
703         /* validate keyframes after editing */
704         ANIM_editkeyframes_refresh(&ac);
705         
706         /* set notifier that things have changed */
707         ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_KEYFRAMES_VALUES);
708         
709         return OPERATOR_FINISHED;
710 }
711  
712 void GRAPHEDIT_OT_keyframes_delete (wmOperatorType *ot)
713 {
714         /* identifiers */
715         ot->name= "Delete Keyframes";
716         ot->idname= "GRAPHEDIT_OT_keyframes_delete";
717         
718         /* api callbacks */
719         ot->invoke= WM_operator_confirm;
720         ot->exec= graphkeys_delete_exec;
721         ot->poll= ED_operator_areaactive;
722         
723         /* flags */
724         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
725 }
726
727 /* ******************** Clean Keyframes Operator ************************* */
728
729 static void clean_graph_keys (bAnimContext *ac, float thresh)
730 {       
731         ListBase anim_data = {NULL, NULL};
732         bAnimListElem *ale;
733         int filter;
734         
735         /* filter data */
736         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE| ANIMFILTER_FOREDIT | ANIMFILTER_SEL | ANIMFILTER_CURVESONLY);
737         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
738         
739         /* loop through filtered data and clean curves */
740         for (ale= anim_data.first; ale; ale= ale->next)
741                 clean_fcurve((FCurve *)ale->key_data, thresh);
742         
743         /* free temp data */
744         BLI_freelistN(&anim_data);
745 }
746
747 /* ------------------- */
748
749 static int graphkeys_clean_exec(bContext *C, wmOperator *op)
750 {
751         bAnimContext ac;
752         float thresh;
753         
754         /* get editor data */
755         if (ANIM_animdata_get_context(C, &ac) == 0)
756                 return OPERATOR_CANCELLED;
757                 
758         /* get cleaning threshold */
759         thresh= RNA_float_get(op->ptr, "threshold");
760         
761         /* clean keyframes */
762         clean_graph_keys(&ac, thresh);
763         
764         /* validate keyframes after editing */
765         ANIM_editkeyframes_refresh(&ac);
766         
767         /* set notifier that things have changed */
768         ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_KEYFRAMES_VALUES);
769         
770         return OPERATOR_FINISHED;
771 }
772  
773 void GRAPHEDIT_OT_keyframes_clean (wmOperatorType *ot)
774 {
775         /* identifiers */
776         ot->name= "Clean Keyframes";
777         ot->idname= "GRAPHEDIT_OT_keyframes_clean";
778         
779         /* api callbacks */
780         //ot->invoke=  // XXX we need that number popup for this! 
781         ot->exec= graphkeys_clean_exec;
782         ot->poll= ED_operator_areaactive;
783         
784         /* flags */
785         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
786         
787         /* properties */
788         RNA_def_float(ot->srna, "threshold", 0.001f, 0.0f, FLT_MAX, "Threshold", "", 0.0f, 1000.0f);
789 }
790
791 /* ******************** Bake F-Curve Operator *********************** */
792 /* This operator bakes the data of the selected F-Curves to F-Points */
793
794 /* Bake each F-Curve into a set of samples */
795 static void bake_graph_curves (bAnimContext *ac, int start, int end)
796 {       
797         ListBase anim_data = {NULL, NULL};
798         bAnimListElem *ale;
799         int filter;
800         
801         /* filter data */
802         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE | ANIMFILTER_SEL | ANIMFILTER_FOREDIT | ANIMFILTER_CURVESONLY);
803         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
804         
805         /* loop through filtered data and add keys between selected keyframes on every frame  */
806         for (ale= anim_data.first; ale; ale= ale->next) {
807                 FCurve *fcu= (FCurve *)ale->key_data;
808                 ChannelDriver *driver= fcu->driver;
809                 
810                 /* disable driver so that it don't muck up the sampling process */
811                 fcu->driver= NULL;
812                 
813                 /* create samples */
814                 fcurve_store_samples(fcu, NULL, start, end, fcurve_samplingcb_evalcurve);
815                 
816                 /* restore driver */
817                 fcu->driver= driver;
818         }
819         
820         /* admin and redraws */
821         BLI_freelistN(&anim_data);
822 }
823
824 /* ------------------- */
825
826 static int graphkeys_bake_exec(bContext *C, wmOperator *op)
827 {
828         bAnimContext ac;
829         Scene *scene= NULL;
830         int start, end;
831         
832         /* get editor data */
833         if (ANIM_animdata_get_context(C, &ac) == 0)
834                 return OPERATOR_CANCELLED;
835                 
836         /* for now, init start/end from preview-range extents */
837         // TODO: add properties for this 
838         scene= ac.scene;
839         start= PSFRA;
840         end= PEFRA;
841         
842         /* bake keyframes */
843         bake_graph_curves(&ac, start, end);
844         
845         /* validate keyframes after editing */
846         ANIM_editkeyframes_refresh(&ac);
847         
848         /* set notifier that things have changed */
849         ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_KEYFRAMES_VALUES);
850         
851         return OPERATOR_FINISHED;
852 }
853  
854 void GRAPHEDIT_OT_keyframes_bake (wmOperatorType *ot)
855 {
856         /* identifiers */
857         ot->name= "Bake Curve";
858         ot->idname= "GRAPHEDIT_OT_keyframes_bake";
859         
860         /* api callbacks */
861         ot->invoke= WM_operator_confirm; // FIXME...
862         ot->exec= graphkeys_bake_exec;
863         ot->poll= ED_operator_areaactive;
864         
865         /* flags */
866         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
867         
868         // todo: add props for start/end frames
869 }
870
871 /* ******************** Sample Keyframes Operator *********************** */
872 /* This operator 'bakes' the values of the curve into new keyframes between pairs
873  * of selected keyframes. It is useful for creating keyframes for tweaking overlap.
874  */
875
876 // XXX some of the common parts (with DopeSheet) should be unified in animation module...
877
878 /* little cache for values... */
879 typedef struct tempFrameValCache {
880         float frame, val;
881 } tempFrameValCache;
882
883 /* Evaluates the curves between each selected keyframe on each frame, and keys the value  */
884 static void sample_graph_keys (bAnimContext *ac)
885 {       
886         ListBase anim_data = {NULL, NULL};
887         bAnimListElem *ale;
888         int filter;
889         
890         /* filter data */
891         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE| ANIMFILTER_FOREDIT | ANIMFILTER_CURVESONLY);
892         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
893         
894         /* loop through filtered data and add keys between selected keyframes on every frame  */
895         for (ale= anim_data.first; ale; ale= ale->next) {
896                 FCurve *fcu= (FCurve *)ale->key_data;
897                 BezTriple *bezt, *start=NULL, *end=NULL;
898                 tempFrameValCache *value_cache, *fp;
899                 int sfra, range;
900                 int i, n;
901                 
902                 /* find selected keyframes... once pair has been found, add keyframes  */
903                 for (i=0, bezt=fcu->bezt; i < fcu->totvert; i++, bezt++) {
904                         /* check if selected, and which end this is */
905                         if (BEZSELECTED(bezt)) {
906                                 if (start) {
907                                         /* set end */
908                                         end= bezt;
909                                         
910                                         /* cache values then add keyframes using these values, as adding
911                                          * keyframes while sampling will affect the outcome...
912                                          */
913                                         range= (int)( ceil(end->vec[1][0] - start->vec[1][0]) );
914                                         sfra= (int)( floor(start->vec[1][0]) );
915                                         
916                                         if (range) {
917                                                 value_cache= MEM_callocN(sizeof(tempFrameValCache)*range, "IcuFrameValCache");
918                                                 
919                                                 /*      sample values   */
920                                                 for (n=0, fp=value_cache; n<range && fp; n++, fp++) {
921                                                         fp->frame= (float)(sfra + n);
922                                                         fp->val= evaluate_fcurve(fcu, fp->frame);
923                                                 }
924                                                 
925                                                 /*      add keyframes with these        */
926                                                 for (n=0, fp=value_cache; n<range && fp; n++, fp++) {
927                                                         insert_vert_fcurve(fcu, fp->frame, fp->val, 1);
928                                                 }
929                                                 
930                                                 /* free temp cache */
931                                                 MEM_freeN(value_cache);
932                                                 
933                                                 /* as we added keyframes, we need to compensate so that bezt is at the right place */
934                                                 bezt = fcu->bezt + i + range - 1;
935                                                 i += (range - 1);
936                                         }
937                                         
938                                         /* bezt was selected, so it now marks the start of a whole new chain to search */
939                                         start= bezt;
940                                         end= NULL;
941                                 }
942                                 else {
943                                         /* just set start keyframe */
944                                         start= bezt;
945                                         end= NULL;
946                                 }
947                         }
948                 }
949                 
950                 /* recalculate channel's handles? */
951                 calchandles_fcurve(fcu);
952         }
953         
954         /* admin and redraws */
955         BLI_freelistN(&anim_data);
956 }
957
958 /* ------------------- */
959
960 static int graphkeys_sample_exec(bContext *C, wmOperator *op)
961 {
962         bAnimContext ac;
963         
964         /* get editor data */
965         if (ANIM_animdata_get_context(C, &ac) == 0)
966                 return OPERATOR_CANCELLED;
967         
968         /* sample keyframes */
969         sample_graph_keys(&ac);
970         
971         /* validate keyframes after editing */
972         ANIM_editkeyframes_refresh(&ac);
973         
974         /* set notifier that things have changed */
975         ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_KEYFRAMES_VALUES);
976         
977         return OPERATOR_FINISHED;
978 }
979  
980 void GRAPHEDIT_OT_keyframes_sample (wmOperatorType *ot)
981 {
982         /* identifiers */
983         ot->name= "Sample Keyframes";
984         ot->idname= "GRAPHEDIT_OT_keyframes_sample";
985         
986         /* api callbacks */
987         ot->exec= graphkeys_sample_exec;
988         ot->poll= ED_operator_areaactive;
989         
990         /* flags */
991         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
992 }
993
994
995 /* ************************************************************************** */
996 /* SETTINGS STUFF */
997
998 /* ******************** Set Extrapolation-Type Operator *********************** */
999
1000 /* defines for set extrapolation-type for selected keyframes tool */
1001 EnumPropertyItem prop_graphkeys_expo_types[] = {
1002         {FCURVE_EXTRAPOLATE_CONSTANT, "CONSTANT", "Constant Extrapolation", ""},
1003         {FCURVE_EXTRAPOLATE_LINEAR, "LINEAR", "Linear Extrapolation", ""},
1004         {0, NULL, NULL, NULL}
1005 };
1006
1007 /* this function is responsible for setting extrapolation mode for keyframes */
1008 static void setexpo_graph_keys(bAnimContext *ac, short mode) 
1009 {
1010         ListBase anim_data = {NULL, NULL};
1011         bAnimListElem *ale;
1012         int filter;
1013         
1014         /* filter data */
1015         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE| ANIMFILTER_FOREDIT | ANIMFILTER_CURVESONLY);
1016         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
1017         
1018         /* loop through setting mode per F-Curve */
1019         for (ale= anim_data.first; ale; ale= ale->next) {
1020                 FCurve *fcu= (FCurve *)ale->data;
1021                 fcu->extend= mode;
1022         }
1023         
1024         /* cleanup */
1025         BLI_freelistN(&anim_data);
1026 }
1027
1028 /* ------------------- */
1029
1030 static int graphkeys_expo_exec(bContext *C, wmOperator *op)
1031 {
1032         bAnimContext ac;
1033         short mode;
1034         
1035         /* get editor data */
1036         if (ANIM_animdata_get_context(C, &ac) == 0)
1037                 return OPERATOR_CANCELLED;
1038                 
1039         /* get handle setting mode */
1040         mode= RNA_enum_get(op->ptr, "type");
1041         
1042         /* set handle type */
1043         setexpo_graph_keys(&ac, mode);
1044         
1045         /* validate keyframes after editing */
1046         ANIM_editkeyframes_refresh(&ac);
1047         
1048         /* set notifier that things have changed */
1049         ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_KEYFRAMES_VALUES);
1050         
1051         return OPERATOR_FINISHED;
1052 }
1053  
1054 void GRAPHEDIT_OT_keyframes_extrapolation_type (wmOperatorType *ot)
1055 {
1056         /* identifiers */
1057         ot->name= "Set Keyframe Extrapolation";
1058         ot->idname= "GRAPHEDIT_OT_keyframes_extrapolation_type";
1059         
1060         /* api callbacks */
1061         ot->invoke= WM_menu_invoke;
1062         ot->exec= graphkeys_expo_exec;
1063         ot->poll= ED_operator_areaactive;
1064         
1065         /* flags */
1066         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1067         
1068         /* id-props */
1069         RNA_def_enum(ot->srna, "type", prop_graphkeys_expo_types, 0, "Type", "");
1070 }
1071
1072 /* ******************** Set Interpolation-Type Operator *********************** */
1073
1074 /* this function is responsible for setting interpolation mode for keyframes */
1075 static void setipo_graph_keys(bAnimContext *ac, short mode) 
1076 {
1077         ListBase anim_data = {NULL, NULL};
1078         bAnimListElem *ale;
1079         int filter;
1080         BeztEditFunc set_cb= ANIM_editkeyframes_ipo(mode);
1081         
1082         /* filter data */
1083         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE| ANIMFILTER_FOREDIT | ANIMFILTER_CURVESONLY);
1084         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
1085         
1086         /* loop through setting BezTriple interpolation
1087          * Note: we do not supply BeztEditData to the looper yet. Currently that's not necessary here...
1088          */
1089         for (ale= anim_data.first; ale; ale= ale->next)
1090                 ANIM_fcurve_keys_bezier_loop(NULL, ale->key_data, NULL, set_cb, calchandles_fcurve);
1091         
1092         /* cleanup */
1093         BLI_freelistN(&anim_data);
1094 }
1095
1096 /* ------------------- */
1097
1098 static int graphkeys_ipo_exec(bContext *C, wmOperator *op)
1099 {
1100         bAnimContext ac;
1101         short mode;
1102         
1103         /* get editor data */
1104         if (ANIM_animdata_get_context(C, &ac) == 0)
1105                 return OPERATOR_CANCELLED;
1106                 
1107         /* get handle setting mode */
1108         mode= RNA_enum_get(op->ptr, "type");
1109         
1110         /* set handle type */
1111         setipo_graph_keys(&ac, mode);
1112         
1113         /* validate keyframes after editing */
1114         ANIM_editkeyframes_refresh(&ac);
1115         
1116         /* set notifier that things have changed */
1117         ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_KEYFRAMES_VALUES);
1118         
1119         return OPERATOR_FINISHED;
1120 }
1121  
1122 void GRAPHEDIT_OT_keyframes_interpolation_type (wmOperatorType *ot)
1123 {
1124         /* identifiers */
1125         ot->name= "Set Keyframe Interpolation";
1126         ot->idname= "GRAPHEDIT_OT_keyframes_interpolation_type";
1127         
1128         /* api callbacks */
1129         ot->invoke= WM_menu_invoke;
1130         ot->exec= graphkeys_ipo_exec;
1131         ot->poll= ED_operator_areaactive;
1132         
1133         /* flags */
1134         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1135         
1136         /* id-props */
1137         RNA_def_enum(ot->srna, "type", beztriple_interpolation_mode_items, 0, "Type", "");
1138 }
1139
1140 /* ******************** Set Handle-Type Operator *********************** */
1141
1142 /* this function is responsible for setting handle-type of selected keyframes */
1143 static void sethandles_graph_keys(bAnimContext *ac, short mode) 
1144 {
1145         ListBase anim_data = {NULL, NULL};
1146         bAnimListElem *ale;
1147         int filter;
1148         BeztEditFunc set_cb= ANIM_editkeyframes_handles(mode);
1149         
1150         /* filter data */
1151         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE| ANIMFILTER_FOREDIT | ANIMFILTER_CURVESONLY);
1152         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
1153         
1154         /* loop through setting flags for handles 
1155          * Note: we do not supply BeztEditData to the looper yet. Currently that's not necessary here...
1156          */
1157         // XXX we might need to supply BeztEditData to get it to only affect selected handles
1158         for (ale= anim_data.first; ale; ale= ale->next) {
1159                 if (mode == -1) {       
1160                         BeztEditFunc toggle_cb;
1161                         
1162                         /* check which type of handle to set (free or aligned) 
1163                          *      - check here checks for handles with free alignment already
1164                          */
1165                         if (ANIM_fcurve_keys_bezier_loop(NULL, ale->key_data, NULL, set_cb, NULL))
1166                                 toggle_cb= ANIM_editkeyframes_handles(HD_FREE);
1167                         else
1168                                 toggle_cb= ANIM_editkeyframes_handles(HD_ALIGN);
1169                                 
1170                         /* set handle-type */
1171                         ANIM_fcurve_keys_bezier_loop(NULL, ale->key_data, NULL, toggle_cb, calchandles_fcurve);
1172                 }
1173                 else {
1174                         /* directly set handle-type */
1175                         ANIM_fcurve_keys_bezier_loop(NULL, ale->key_data, NULL, set_cb, calchandles_fcurve);
1176                 }
1177         }
1178         
1179         /* cleanup */
1180         BLI_freelistN(&anim_data);
1181 }
1182
1183 /* ------------------- */
1184
1185 static int graphkeys_handletype_exec(bContext *C, wmOperator *op)
1186 {
1187         bAnimContext ac;
1188         short mode;
1189         
1190         /* get editor data */
1191         if (ANIM_animdata_get_context(C, &ac) == 0)
1192                 return OPERATOR_CANCELLED;
1193                 
1194         /* get handle setting mode */
1195         mode= RNA_enum_get(op->ptr, "type");
1196         
1197         /* set handle type */
1198         sethandles_graph_keys(&ac, mode);
1199         
1200         /* validate keyframes after editing */
1201         ANIM_editkeyframes_refresh(&ac);
1202         
1203         /* set notifier that things have changed */
1204         ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_KEYFRAMES_VALUES);
1205         
1206         return OPERATOR_FINISHED;
1207 }
1208  
1209 void GRAPHEDIT_OT_keyframes_handletype (wmOperatorType *ot)
1210 {
1211         /* identifiers */
1212         ot->name= "Set Keyframe Handle Type";
1213         ot->idname= "GRAPHEDIT_OT_keyframes_handletype";
1214         
1215         /* api callbacks */
1216         ot->invoke= WM_menu_invoke;
1217         ot->exec= graphkeys_handletype_exec;
1218         ot->poll= ED_operator_areaactive;
1219         
1220         /* flags */
1221         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1222         
1223         /* id-props */
1224         RNA_def_enum(ot->srna, "type", beztriple_handle_type_items, 0, "Type", "");
1225 }
1226
1227 /* ************************************************************************** */
1228 /* TRANSFORM STUFF */
1229
1230 /* ***************** 'Euler Filter' Operator **************************** */
1231 /* Euler filter tools (as seen in Maya), are necessary for working with 'baked'
1232  * rotation curves (with Euler rotations). The main purpose of such tools is to
1233  * resolve any discontinuities that may arise in the curves due to the clamping
1234  * of values to -180 degrees to 180 degrees.
1235  */
1236
1237 #if 0 // XXX this is not ready for the primetime yet
1238  
1239 /* set of three euler-rotation F-Curves */
1240 typedef struct tEulerFilter {
1241         ID *id;                                                 /* ID-block which owns the channels */
1242         FCurve *fcu1, *fcu2, *fcu3;             /* x,y,z rotation curves */
1243         int i1, i2, i3;                                 /* current index for each curve */
1244 } tEulerFilter;
1245  
1246 static int graphkeys_euler_filter_exec (bContext *C, wmOperator *op)
1247 {
1248         bAnimContext ac;
1249         
1250         ListBase anim_data= {NULL, NULL};
1251         bAnimListElem *ale;
1252         int filter;
1253         
1254         ListBase eulers = {NULL, NULL};
1255         tEulerFilter *euf= NULL;        
1256         
1257         /* get editor data */
1258         if (ANIM_animdata_get_context(C, &ac) == 0)
1259                 return OPERATOR_CANCELLED;
1260                 
1261         /* The process is done in two passes:
1262          *       1) Sets of three related rotation curves are identified from the selected channels,
1263          *              and are stored as a single 'operation unit' for the next step
1264          *       2) Each set of three F-Curves is processed for each keyframe, with the values being
1265          *              processed according to one of several ways.
1266          */
1267          
1268         /* step 1: extract only the rotation f-curves */
1269         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_SEL | ANIMFILTER_CURVEVISIBLE | ANIMFILTER_CURVESONLY);
1270         ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
1271         
1272         for (ale= anim_data.first; ale; ale= ale->next) {
1273                 FCurve *fcu = (FCurve *)ale->data;
1274                 
1275                 /* check if this is an appropriate F-Curve 
1276                  *      - only rotation curves
1277                  *      - for pchan curves, make sure we're only using the euler curves
1278                  */
1279                 if (ELEM(0, fcu->rna_path, strstr(fcu->rna_path, "rotation")))
1280                         continue;
1281                 if (strstr(fcu->rna_path, "pose.pose_channels")) {
1282                         if (strstr(fcu->rna_path, "euler_rotation") == 0)
1283                                 continue;
1284                 }
1285                 
1286                 /* check if current set of 3-curves is suitable to add this curve to 
1287                  *      - things like whether the current set of curves is 'full' should be checked later only
1288                  *      - first check if id-blocks are compatible
1289                  */
1290                 if ((euf) && (ale->id != euf->id)) {
1291                         
1292                 }
1293         }
1294         
1295         // XXX for now
1296         return OPERATOR_CANCELLED;
1297 }
1298  
1299 void GRAPHEDIT_OT_keyframes_euler_filter (wmOperatorType *ot)
1300 {
1301         /* identifiers */
1302         ot->name= "Euler Filter";
1303         ot->idname= "GRAPHEDIT_OT_keyframes_euler_filter";
1304         
1305         /* api callbacks */
1306         ot->exec= graphkeys_euler_filter_exec;
1307         ot->poll= ED_operator_areaactive;
1308         
1309         /* flags */
1310         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1311 }
1312
1313 #endif // XXX this is not ready for the primetime yet
1314
1315 /* ***************** Snap Current Frame Operator *********************** */
1316
1317 /* snap current-frame indicator to 'average time' of selected keyframe */
1318 static int graphkeys_cfrasnap_exec(bContext *C, wmOperator *op)
1319 {
1320         bAnimContext ac;
1321         ListBase anim_data= {NULL, NULL};
1322         bAnimListElem *ale;
1323         int filter;
1324         BeztEditData bed;
1325         
1326         /* get editor data */
1327         if (ANIM_animdata_get_context(C, &ac) == 0)
1328                 return OPERATOR_CANCELLED;
1329         
1330         /* init edit data */
1331         memset(&bed, 0, sizeof(BeztEditData));
1332         
1333         /* loop over action data, averaging values */
1334         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE| ANIMFILTER_CURVESONLY);
1335         ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
1336         
1337         for (ale= anim_data.first; ale; ale= ale->next)
1338                 ANIM_fcurve_keys_bezier_loop(&bed, ale->key_data, NULL, bezt_calc_average, NULL);
1339         
1340         BLI_freelistN(&anim_data);
1341         
1342         /* set the new current frame value, based on the average time */
1343         if (bed.i1) {
1344                 Scene *scene= ac.scene;
1345                 CFRA= (int)floor((bed.f1 / bed.i1) + 0.5f);
1346         }
1347         
1348         /* set notifier that things have changed */
1349         WM_event_add_notifier(C, NC_SCENE|ND_FRAME, ac.scene);
1350         
1351         return OPERATOR_FINISHED;
1352 }
1353
1354 void GRAPHEDIT_OT_keyframes_cfrasnap (wmOperatorType *ot)
1355 {
1356         /* identifiers */
1357         ot->name= "Snap Current Frame to Keys";
1358         ot->idname= "GRAPHEDIT_OT_keyframes_cfrasnap";
1359         
1360         /* api callbacks */
1361         ot->exec= graphkeys_cfrasnap_exec;
1362         ot->poll= ED_operator_areaactive;
1363         
1364         /* flags */
1365         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1366 }
1367
1368 /* ******************** Snap Keyframes Operator *********************** */
1369
1370 /* defines for snap keyframes tool */
1371 EnumPropertyItem prop_graphkeys_snap_types[] = {
1372         {GRAPHKEYS_SNAP_CFRA, "CFRA", "Current frame", ""},
1373         {GRAPHKEYS_SNAP_NEAREST_FRAME, "NEAREST_FRAME", "Nearest Frame", ""}, // XXX as single entry?
1374         {GRAPHKEYS_SNAP_NEAREST_SECOND, "NEAREST_SECOND", "Nearest Second", ""}, // XXX as single entry?
1375         {GRAPHKEYS_SNAP_NEAREST_MARKER, "NEAREST_MARKER", "Nearest Marker", ""},
1376         {GRAPHKEYS_SNAP_HORIZONTAL, "HORIZONTAL", "Flatten Handles", ""},
1377         {0, NULL, NULL, NULL}
1378 };
1379
1380 /* this function is responsible for snapping keyframes to frame-times */
1381 static void snap_graph_keys(bAnimContext *ac, short mode) 
1382 {
1383         ListBase anim_data = {NULL, NULL};
1384         bAnimListElem *ale;
1385         int filter;
1386         
1387         BeztEditData bed;
1388         BeztEditFunc edit_cb;
1389         
1390         /* filter data */
1391         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE| ANIMFILTER_FOREDIT | ANIMFILTER_CURVESONLY);
1392         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
1393         
1394         /* get beztriple editing callbacks */
1395         edit_cb= ANIM_editkeyframes_snap(mode);
1396         
1397         memset(&bed, 0, sizeof(BeztEditData)); 
1398         bed.scene= ac->scene;
1399         
1400         /* snap keyframes */
1401         for (ale= anim_data.first; ale; ale= ale->next) {
1402                 Object *nob= ANIM_nla_mapping_get(ac, ale);
1403                 
1404                 if (nob) {
1405                         ANIM_nla_mapping_apply_fcurve(nob, ale->key_data, 0, 1); 
1406                         ANIM_fcurve_keys_bezier_loop(&bed, ale->key_data, NULL, edit_cb, calchandles_fcurve);
1407                         ANIM_nla_mapping_apply_fcurve(nob, ale->key_data, 1, 1);
1408                 }
1409                 else 
1410                         ANIM_fcurve_keys_bezier_loop(&bed, ale->key_data, NULL, edit_cb, calchandles_fcurve);
1411         }
1412         BLI_freelistN(&anim_data);
1413 }
1414
1415 /* ------------------- */
1416
1417 static int graphkeys_snap_exec(bContext *C, wmOperator *op)
1418 {
1419         bAnimContext ac;
1420         short mode;
1421         
1422         /* get editor data */
1423         if (ANIM_animdata_get_context(C, &ac) == 0)
1424                 return OPERATOR_CANCELLED;
1425                 
1426         /* get snapping mode */
1427         mode= RNA_enum_get(op->ptr, "type");
1428         
1429         /* snap keyframes */
1430         snap_graph_keys(&ac, mode);
1431         
1432         /* validate keyframes after editing */
1433         ANIM_editkeyframes_refresh(&ac);
1434         
1435         /* set notifier that things have changed */
1436         ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_KEYFRAMES_VALUES);
1437         
1438         return OPERATOR_FINISHED;
1439 }
1440  
1441 void GRAPHEDIT_OT_keyframes_snap (wmOperatorType *ot)
1442 {
1443         /* identifiers */
1444         ot->name= "Snap Keys";
1445         ot->idname= "GRAPHEDIT_OT_keyframes_snap";
1446         
1447         /* api callbacks */
1448         ot->invoke= WM_menu_invoke;
1449         ot->exec= graphkeys_snap_exec;
1450         ot->poll= ED_operator_areaactive;
1451         
1452         /* flags */
1453         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1454         
1455         /* id-props */
1456         RNA_def_enum(ot->srna, "type", prop_graphkeys_snap_types, 0, "Type", "");
1457 }
1458
1459 /* ******************** Mirror Keyframes Operator *********************** */
1460
1461 /* defines for mirror keyframes tool */
1462 EnumPropertyItem prop_graphkeys_mirror_types[] = {
1463         {GRAPHKEYS_MIRROR_CFRA, "CFRA", "Current frame", ""},
1464         {GRAPHKEYS_MIRROR_YAXIS, "YAXIS", "Vertical Axis", ""},
1465         {GRAPHKEYS_MIRROR_XAXIS, "XAXIS", "Horizontal Axis", ""},
1466         {GRAPHKEYS_MIRROR_MARKER, "MARKER", "First Selected Marker", ""},
1467         {0, NULL, NULL, NULL}
1468 };
1469
1470 /* this function is responsible for mirroring keyframes */
1471 static void mirror_graph_keys(bAnimContext *ac, short mode) 
1472 {
1473         ListBase anim_data = {NULL, NULL};
1474         bAnimListElem *ale;
1475         int filter;
1476         
1477         BeztEditData bed;
1478         BeztEditFunc edit_cb;
1479         
1480         /* get beztriple editing callbacks */
1481         edit_cb= ANIM_editkeyframes_mirror(mode);
1482         
1483         memset(&bed, 0, sizeof(BeztEditData)); 
1484         bed.scene= ac->scene;
1485         
1486         /* for 'first selected marker' mode, need to find first selected marker first! */
1487         // XXX should this be made into a helper func in the API?
1488         if (mode == GRAPHKEYS_MIRROR_MARKER) {
1489                 Scene *scene= ac->scene;
1490                 TimeMarker *marker= NULL;
1491                 
1492                 /* find first selected marker */
1493                 for (marker= scene->markers.first; marker; marker=marker->next) {
1494                         if (marker->flag & SELECT) {
1495                                 break;
1496                         }
1497                 }
1498                 
1499                 /* store marker's time (if available) */
1500                 if (marker)
1501                         bed.f1= (float)marker->frame;
1502                 else
1503                         return;
1504         }
1505         
1506         /* filter data */
1507         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE| ANIMFILTER_FOREDIT | ANIMFILTER_CURVESONLY);
1508         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
1509         
1510         /* mirror keyframes */
1511         for (ale= anim_data.first; ale; ale= ale->next) {
1512                 Object *nob= ANIM_nla_mapping_get(ac, ale);
1513                 
1514                 if (nob) {
1515                         ANIM_nla_mapping_apply_fcurve(nob, ale->key_data, 0, 1); 
1516                         ANIM_fcurve_keys_bezier_loop(&bed, ale->key_data, NULL, edit_cb, calchandles_fcurve);
1517                         ANIM_nla_mapping_apply_fcurve(nob, ale->key_data, 1, 1);
1518                 }
1519                 else 
1520                         ANIM_fcurve_keys_bezier_loop(&bed, ale->key_data, NULL, edit_cb, calchandles_fcurve);
1521         }
1522         BLI_freelistN(&anim_data);
1523 }
1524
1525 /* ------------------- */
1526
1527 static int graphkeys_mirror_exec(bContext *C, wmOperator *op)
1528 {
1529         bAnimContext ac;
1530         short mode;
1531         
1532         /* get editor data */
1533         if (ANIM_animdata_get_context(C, &ac) == 0)
1534                 return OPERATOR_CANCELLED;
1535                 
1536         /* get mirroring mode */
1537         mode= RNA_enum_get(op->ptr, "type");
1538         
1539         /* mirror keyframes */
1540         mirror_graph_keys(&ac, mode);
1541         
1542         /* validate keyframes after editing */
1543         ANIM_editkeyframes_refresh(&ac);
1544         
1545         /* set notifier that things have changed */
1546         ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_KEYFRAMES_VALUES);
1547         
1548         return OPERATOR_FINISHED;
1549 }
1550  
1551 void GRAPHEDIT_OT_keyframes_mirror (wmOperatorType *ot)
1552 {
1553         /* identifiers */
1554         ot->name= "Mirror Keys";
1555         ot->idname= "GRAPHEDIT_OT_keyframes_mirror";
1556         
1557         /* api callbacks */
1558         ot->invoke= WM_menu_invoke;
1559         ot->exec= graphkeys_mirror_exec;
1560         ot->poll= ED_operator_areaactive;
1561         
1562         /* flags */
1563         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1564         
1565         /* id-props */
1566         RNA_def_enum(ot->srna, "type", prop_graphkeys_mirror_types, 0, "Type", "");
1567 }
1568
1569 /* ******************** Smooth Keyframes Operator *********************** */
1570
1571 static int graphkeys_smooth_exec(bContext *C, wmOperator *op)
1572 {
1573         bAnimContext ac;
1574         ListBase anim_data = {NULL, NULL};
1575         bAnimListElem *ale;
1576         int filter;
1577         
1578         /* get editor data */
1579         if (ANIM_animdata_get_context(C, &ac) == 0)
1580                 return OPERATOR_CANCELLED;
1581         
1582         /* filter data */
1583         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE| ANIMFILTER_FOREDIT | ANIMFILTER_CURVESONLY);
1584         ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
1585         
1586         /* smooth keyframes */
1587         for (ale= anim_data.first; ale; ale= ale->next) {
1588                 /* For now, we can only smooth by flattening handles AND smoothing curve values.
1589                  * Perhaps the mode argument could be removed, as that functionality is offerred through 
1590                  * Snap->Flatten Handles anyway.
1591                  */
1592                 smooth_fcurve(ale->key_data);
1593         }
1594         BLI_freelistN(&anim_data);
1595         
1596         /* validate keyframes after editing */
1597         ANIM_editkeyframes_refresh(&ac);
1598         
1599         /* set notifier that things have changed */
1600         ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_KEYFRAMES_VALUES);
1601         
1602         return OPERATOR_FINISHED;
1603 }
1604  
1605 void GRAPHEDIT_OT_keyframes_smooth (wmOperatorType *ot)
1606 {
1607         /* identifiers */
1608         ot->name= "Smooth Keys";
1609         ot->idname= "GRAPHEDIT_OT_keyframes_smooth";
1610         
1611         /* api callbacks */
1612         ot->exec= graphkeys_smooth_exec;
1613         ot->poll= ED_operator_areaactive;
1614         
1615         /* flags */
1616         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1617 }
1618
1619 /* ************************************************************************** */
1620 /* F-CURVE MODIFIERS */
1621
1622 /* ******************** Add F-Curve Modifier Operator *********************** */
1623
1624 static int graph_fmodifier_add_exec(bContext *C, wmOperator *op)
1625 {
1626         bAnimContext ac;
1627         bAnimListElem *ale;
1628         FCurve *fcu;
1629         FModifier *fcm;
1630         short type;
1631         
1632         /* get editor data */
1633         if (ANIM_animdata_get_context(C, &ac) == 0)
1634                 return OPERATOR_CANCELLED;
1635                 
1636                 // xxx call the raw methods here instead?
1637         ale= get_active_fcurve_channel(&ac);
1638         if (ale == NULL) 
1639                 return OPERATOR_CANCELLED;
1640         
1641         fcu= (FCurve *)ale->data;
1642         MEM_freeN(ale);
1643         if (fcu == NULL) 
1644                 return OPERATOR_CANCELLED;
1645                 
1646         /* get type of modifier to add */
1647         type= RNA_enum_get(op->ptr, "type");
1648         
1649         /* add F-Modifier of specified type to active F-Curve, and make it the active one */
1650         fcm= fcurve_add_modifier(fcu, type);
1651         if (fcm)
1652                 fcurve_set_active_modifier(fcu, fcm);
1653         else {
1654                 BKE_report(op->reports, RPT_ERROR, "Modifier couldn't be added. See console for details.");
1655                 return OPERATOR_CANCELLED;
1656         }
1657         
1658         /* validate keyframes after editing */
1659         ANIM_editkeyframes_refresh(&ac);
1660         
1661         /* set notifier that things have changed */
1662         ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_BOTH);
1663         
1664         return OPERATOR_FINISHED;
1665 }
1666  
1667 void GRAPHEDIT_OT_fmodifier_add (wmOperatorType *ot)
1668 {
1669         /* identifiers */
1670         ot->name= "Add F-Curve Modifier";
1671         ot->idname= "GRAPHEDIT_OT_fmodifier_add";
1672         
1673         /* api callbacks */
1674         ot->invoke= WM_menu_invoke;
1675         ot->exec= graph_fmodifier_add_exec;
1676         ot->poll= ED_operator_areaactive; // XXX need active F-Curve
1677         
1678         /* flags */
1679         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1680         
1681         /* id-props */
1682         RNA_def_enum(ot->srna, "type", fmodifier_type_items, 0, "Type", "");
1683 }
1684
1685 /* ************************************************************************** */