Keyframing Bugfixes and Feature Requests:
[blender.git] / source / blender / editors / space_action / action_edit.c
1 /**
2  * $Id$
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19  *
20  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
21  * All rights reserved.
22  *
23  * The Original Code is: all of this file.
24  *
25  * Contributor(s): Joshua Leung
26  *
27  * ***** END GPL LICENSE BLOCK *****
28  */
29
30 #include <math.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <float.h>
34
35 #ifdef HAVE_CONFIG_H
36 #include <config.h>
37 #endif
38
39 #include "MEM_guardedalloc.h"
40
41 #include "BLI_blenlib.h"
42 #include "BLI_math.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_nla.h"
71 #include "BKE_object.h"
72 #include "BKE_context.h"
73 #include "BKE_report.h"
74 #include "BKE_utildefines.h"
75
76 #include "UI_view2d.h"
77
78 #include "ED_anim_api.h"
79 #include "ED_keyframing.h"
80 #include "ED_keyframes_draw.h"
81 #include "ED_keyframes_edit.h"
82 #include "ED_screen.h"
83 #include "ED_space_api.h"
84 #include "ED_transform.h"
85
86 #include "WM_api.h"
87 #include "WM_types.h"
88
89 #include "UI_interface.h"
90
91 #include "action_intern.h"
92
93 /* ************************************************************************** */
94 /* ACTION MANAGEMENT */
95
96 /* ******************** New Action Operator *********************** */
97
98 static int act_new_exec(bContext *C, wmOperator *op)
99 {
100         bAction *action;
101         PointerRNA ptr, idptr;
102         PropertyRNA *prop;
103
104         // XXX need to restore behaviour to copy old actions...
105         action= add_empty_action("Action");
106
107         /* hook into UI */
108         uiIDContextProperty(C, &ptr, &prop);
109
110         if(prop) {
111                 /* when creating new ID blocks, use is already 1, but RNA
112                  * pointer se also increases user, so this compensates it */
113                 action->id.us--;
114
115                 RNA_id_pointer_create(&action->id, &idptr);
116                 RNA_property_pointer_set(&ptr, prop, idptr);
117                 RNA_property_update(C, &ptr, prop);
118         }
119
120         /* set notifier that keyframes have changed */
121         WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME_EDIT, NULL);
122         
123         return OPERATOR_FINISHED;
124 }
125  
126 void ACTION_OT_new (wmOperatorType *ot)
127 {
128         /* identifiers */
129         ot->name= "New";
130         ot->idname= "ACTION_OT_new";
131         ot->description= "Create new action.";
132         
133         /* api callbacks */
134         ot->exec= act_new_exec;
135                 // NOTE: this is used in the NLA too...
136         //ot->poll= ED_operator_action_active;
137         
138         /* flags */
139         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
140 }
141
142 /* ************************************************************************** */
143 /* KEYFRAME-RANGE STUFF */
144
145 /* *************************** Calculate Range ************************** */
146
147 /* Get the min/max keyframes*/
148 static void get_keyframe_extents (bAnimContext *ac, float *min, float *max)
149 {
150         ListBase anim_data = {NULL, NULL};
151         bAnimListElem *ale;
152         int filter;
153         
154         /* get data to filter, from Action or Dopesheet */
155         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_SEL | ANIMFILTER_CURVESONLY);
156         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
157         
158         /* set large values to try to override */
159         *min= 999999999.0f;
160         *max= -999999999.0f;
161         
162         /* check if any channels to set range with */
163         if (anim_data.first) {
164                 /* go through channels, finding max extents */
165                 for (ale= anim_data.first; ale; ale= ale->next) {
166                         AnimData *adt= ANIM_nla_mapping_get(ac, ale);
167                         FCurve *fcu= (FCurve *)ale->key_data;
168                         float tmin, tmax;
169                         
170                         /* get range and apply necessary scaling before */
171                         calc_fcurve_range(fcu, &tmin, &tmax);
172                         
173                         if (adt) {
174                                 tmin= BKE_nla_tweakedit_remap(adt, tmin, NLATIME_CONVERT_MAP);
175                                 tmax= BKE_nla_tweakedit_remap(adt, tmax, NLATIME_CONVERT_MAP);
176                         }
177                         
178                         /* try to set cur using these values, if they're more extreme than previously set values */
179                         *min= MIN2(*min, tmin);
180                         *max= MAX2(*max, tmax);
181                 }
182                 
183                 /* free memory */
184                 BLI_freelistN(&anim_data);
185         }
186         else {
187                 /* set default range */
188                 if (ac->scene) {
189                         *min= (float)ac->scene->r.sfra;
190                         *max= (float)ac->scene->r.efra;
191                 }
192                 else {
193                         *min= -5;
194                         *max= 100;
195                 }
196         }
197 }
198
199 /* ****************** Automatic Preview-Range Operator ****************** */
200
201 static int actkeys_previewrange_exec(bContext *C, wmOperator *op)
202 {
203         bAnimContext ac;
204         Scene *scene;
205         float min, max;
206         
207         /* get editor data */
208         if (ANIM_animdata_get_context(C, &ac) == 0)
209                 return OPERATOR_CANCELLED;
210         if (ac.scene == NULL)
211                 return OPERATOR_CANCELLED;
212         else
213                 scene= ac.scene;
214         
215         /* set the range directly */
216         get_keyframe_extents(&ac, &min, &max);
217         scene->r.psfra= (int)floor(min + 0.5f);
218         scene->r.pefra= (int)floor(max + 0.5f);
219         
220         /* set notifier that things have changed */
221         // XXX err... there's nothing for frame ranges yet, but this should do fine too
222         WM_event_add_notifier(C, NC_SCENE|ND_FRAME, ac.scene); 
223         
224         return OPERATOR_FINISHED;
225 }
226  
227 void ACTION_OT_previewrange_set (wmOperatorType *ot)
228 {
229         /* identifiers */
230         ot->name= "Auto-Set Preview Range";
231         ot->idname= "ACTION_OT_previewrange_set";
232         ot->description= "Set Preview Range based on extents of selected Keyframes.";
233         
234         /* api callbacks */
235         ot->exec= actkeys_previewrange_exec;
236         ot->poll= ED_operator_action_active;
237         
238         /* flags */
239         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
240 }
241
242 /* ****************** View-All Operator ****************** */
243
244 static int actkeys_viewall_exec(bContext *C, wmOperator *op)
245 {
246         bAnimContext ac;
247         View2D *v2d;
248         float extra;
249         
250         /* get editor data */
251         if (ANIM_animdata_get_context(C, &ac) == 0)
252                 return OPERATOR_CANCELLED;
253         v2d= &ac.ar->v2d;
254         
255         /* set the horizontal range, with an extra offset so that the extreme keys will be in view */
256         get_keyframe_extents(&ac, &v2d->cur.xmin, &v2d->cur.xmax);
257         
258         extra= 0.1f * (v2d->cur.xmax - v2d->cur.xmin);
259         v2d->cur.xmin -= extra;
260         v2d->cur.xmax += extra;
261         
262         /* set vertical range */
263         v2d->cur.ymax= 0.0f;
264         v2d->cur.ymin= (float)-(v2d->mask.ymax - v2d->mask.ymin);
265         
266         /* do View2D syncing */
267         UI_view2d_sync(CTX_wm_screen(C), CTX_wm_area(C), v2d, V2D_LOCK_COPY);
268         
269         /* just redraw this view */
270         ED_area_tag_redraw(CTX_wm_area(C));
271         
272         return OPERATOR_FINISHED;
273 }
274  
275 void ACTION_OT_view_all (wmOperatorType *ot)
276 {
277         /* identifiers */
278         ot->name= "View All";
279         ot->idname= "ACTION_OT_view_all";
280         ot->description= "Reset viewable area to show full keyframe range.";
281         
282         /* api callbacks */
283         ot->exec= actkeys_viewall_exec;
284         ot->poll= ED_operator_action_active;
285         
286         /* flags */
287         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
288 }
289
290 /* ************************************************************************** */
291 /* GENERAL STUFF */
292
293 /* ******************** Copy/Paste Keyframes Operator ************************* */
294 /* NOTE: the backend code for this is shared with the graph editor */
295
296 static short copy_action_keys (bAnimContext *ac)
297 {       
298         ListBase anim_data = {NULL, NULL};
299         int filter, ok=0;
300         
301         /* clear buffer first */
302         free_anim_copybuf();
303         
304         /* filter data */
305         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVESONLY);
306         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
307         
308         /* copy keyframes */
309         ok= copy_animedit_keys(ac, &anim_data);
310         
311         /* clean up */
312         BLI_freelistN(&anim_data);
313
314         return ok;
315 }
316
317
318 static short paste_action_keys (bAnimContext *ac)
319 {       
320         ListBase anim_data = {NULL, NULL};
321         int filter, ok=0;
322         
323         /* filter data */
324         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_SEL | ANIMFILTER_FOREDIT | ANIMFILTER_CURVESONLY);
325         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
326         
327         /* paste keyframes */
328         ok= paste_animedit_keys(ac, &anim_data);
329         
330         /* clean up */
331         BLI_freelistN(&anim_data);
332
333         return ok;
334 }
335
336 /* ------------------- */
337
338 static int actkeys_copy_exec(bContext *C, wmOperator *op)
339 {
340         bAnimContext ac;
341         
342         /* get editor data */
343         if (ANIM_animdata_get_context(C, &ac) == 0)
344                 return OPERATOR_CANCELLED;
345         
346         /* copy keyframes */
347         if (ac.datatype == ANIMCONT_GPENCIL) {
348                 // FIXME...
349         }
350         else {
351                 if (copy_action_keys(&ac)) {    
352                         BKE_report(op->reports, RPT_ERROR, "No keyframes copied to keyframes copy/paste buffer");
353                         return OPERATOR_CANCELLED;
354                 }
355         }
356         
357         return OPERATOR_FINISHED;
358 }
359  
360 void ACTION_OT_copy (wmOperatorType *ot)
361 {
362         /* identifiers */
363         ot->name= "Copy Keyframes";
364         ot->idname= "ACTION_OT_copy";
365         ot->description= "Copy selected keyframes to the copy/paste buffer.";
366         
367         /* api callbacks */
368         ot->exec= actkeys_copy_exec;
369         ot->poll= ED_operator_action_active;
370         
371         /* flags */
372         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
373 }
374
375
376
377 static int actkeys_paste_exec(bContext *C, wmOperator *op)
378 {
379         bAnimContext ac;
380         
381         /* get editor data */
382         if (ANIM_animdata_get_context(C, &ac) == 0)
383                 return OPERATOR_CANCELLED;
384         
385         /* paste keyframes */
386         if (ac.datatype == ANIMCONT_GPENCIL) {
387                 // FIXME...
388         }
389         else {
390                 if (paste_action_keys(&ac)) {
391                         BKE_report(op->reports, RPT_ERROR, "No keyframes to paste");
392                         return OPERATOR_CANCELLED;
393                 }
394         }
395         
396         /* validate keyframes after editing */
397         ANIM_editkeyframes_refresh(&ac);
398         
399         /* set notifier that keyframes have changed */
400         WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME_EDIT, NULL);
401         
402         return OPERATOR_FINISHED;
403 }
404  
405 void ACTION_OT_paste (wmOperatorType *ot)
406 {
407         /* identifiers */
408         ot->name= "Paste Keyframes";
409         ot->idname= "ACTION_OT_paste";
410         ot->description= "Paste keyframes from copy/paste buffer for the selected channels, starting on the current frame.";
411         
412         /* api callbacks */
413         ot->exec= actkeys_paste_exec;
414         ot->poll= ED_operator_action_active;
415         
416         /* flags */
417         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
418 }
419
420 /* ******************** Insert Keyframes Operator ************************* */
421
422 /* defines for insert keyframes tool */
423 EnumPropertyItem prop_actkeys_insertkey_types[] = {
424         {1, "ALL", 0, "All Channels", ""},
425         {2, "SEL", 0, "Only Selected Channels", ""},
426         {3, "GROUP", 0, "In Active Group", ""}, // xxx not in all cases
427         {0, NULL, 0, NULL, NULL}
428 };
429
430 /* this function is responsible for snapping keyframes to frame-times */
431 static void insert_action_keys(bAnimContext *ac, short mode) 
432 {
433         ListBase anim_data = {NULL, NULL};
434         bAnimListElem *ale;
435         int filter;
436         
437         Scene *scene= ac->scene;
438         float cfra= (float)CFRA;
439         short flag = 0;
440         
441         /* filter data */
442         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_CURVESONLY);
443         if (mode == 2)                  filter |= ANIMFILTER_SEL;
444         else if (mode == 3)     filter |= ANIMFILTER_ACTGROUPED;
445         
446         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
447         
448         /* init keyframing flag */
449         flag = ANIM_get_keyframing_flags(scene, 1);
450         
451         /* insert keyframes */
452         for (ale= anim_data.first; ale; ale= ale->next) {
453                 AnimData *adt= ANIM_nla_mapping_get(ac, ale);
454                 FCurve *fcu= (FCurve *)ale->key_data;
455                 
456                 /* adjust current frame for NLA-scaling */
457                 if (adt)
458                         cfra= BKE_nla_tweakedit_remap(adt, (float)CFRA, NLATIME_CONVERT_UNMAP);
459                 else 
460                         cfra= (float)CFRA;
461                         
462                 /* if there's an id */
463                 if (ale->id)
464                         insert_keyframe(ale->id, NULL, ((fcu->grp)?(fcu->grp->name):(NULL)), fcu->rna_path, fcu->array_index, cfra, flag);
465                 else
466                         insert_vert_fcurve(fcu, cfra, fcu->curval, 0);
467         }
468         
469         BLI_freelistN(&anim_data);
470 }
471
472 /* ------------------- */
473
474 static int actkeys_insertkey_exec(bContext *C, wmOperator *op)
475 {
476         bAnimContext ac;
477         short mode;
478         
479         /* get editor data */
480         if (ANIM_animdata_get_context(C, &ac) == 0)
481                 return OPERATOR_CANCELLED;
482         if (ac.datatype == ANIMCONT_GPENCIL)
483                 return OPERATOR_CANCELLED;
484                 
485         /* what channels to affect? */
486         mode= RNA_enum_get(op->ptr, "type");
487         
488         /* insert keyframes */
489         insert_action_keys(&ac, mode);
490         
491         /* validate keyframes after editing */
492         ANIM_editkeyframes_refresh(&ac);
493         
494         /* set notifier that keyframes have changed */
495         WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME_EDIT, NULL);
496         
497         return OPERATOR_FINISHED;
498 }
499
500 void ACT_OT_keyframe_insert (wmOperatorType *ot)
501 {
502         /* identifiers */
503         ot->name= "Insert Keyframes";
504         ot->idname= "ACT_OT_keyframe_insert";
505         ot->description= "Insert keyframes for the specified channels.";
506         
507         /* api callbacks */
508         ot->invoke= WM_menu_invoke;
509         ot->exec= actkeys_insertkey_exec;
510         ot->poll= ED_operator_action_active;
511         
512         /* flags */
513         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
514         
515         /* id-props */
516         RNA_def_enum(ot->srna, "type", prop_actkeys_insertkey_types, 0, "Type", "");
517 }
518
519 /* ******************** Duplicate Keyframes Operator ************************* */
520
521 static void duplicate_action_keys (bAnimContext *ac)
522 {
523         ListBase anim_data = {NULL, NULL};
524         bAnimListElem *ale;
525         int filter;
526         
527         /* filter data */
528         if (ac->datatype == ANIMCONT_GPENCIL)
529                 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_FOREDIT);
530         else
531                 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_CURVESONLY);
532         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
533         
534         /* loop through filtered data and delete selected keys */
535         for (ale= anim_data.first; ale; ale= ale->next) {
536                 //if (ale->type == ANIMTYPE_GPLAYER)
537                 //      delete_gplayer_frames((bGPDlayer *)ale->data);
538                 //else
539                         duplicate_fcurve_keys((FCurve *)ale->key_data);
540         }
541         
542         /* free filtered list */
543         BLI_freelistN(&anim_data);
544 }
545
546 /* ------------------- */
547
548 static int actkeys_duplicate_exec(bContext *C, wmOperator *op)
549 {
550         bAnimContext ac;
551         
552         /* get editor data */
553         if (ANIM_animdata_get_context(C, &ac) == 0)
554                 return OPERATOR_CANCELLED;
555                 
556         /* duplicate keyframes */
557         duplicate_action_keys(&ac);
558         
559         /* validate keyframes after editing */
560         ANIM_editkeyframes_refresh(&ac);
561         
562         /* set notifier that keyframes have changed */
563         WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME_EDIT, NULL);
564         
565         return OPERATOR_FINISHED; // xxx - start transform
566 }
567
568 static int actkeys_duplicate_invoke(bContext *C, wmOperator *op, wmEvent *event)
569 {
570         actkeys_duplicate_exec(C, op);
571         
572         RNA_int_set(op->ptr, "mode", TFM_TIME_TRANSLATE);
573         WM_operator_name_call(C, "TRANSFORM_OT_transform", WM_OP_INVOKE_REGION_WIN, op->ptr);
574
575         return OPERATOR_FINISHED;
576 }
577  
578 void ACTION_OT_duplicate (wmOperatorType *ot)
579 {
580         /* identifiers */
581         ot->name= "Duplicate Keyframes";
582         ot->idname= "ACTION_OT_duplicate";
583         ot->description= "Make a copy of all selected keyframes.";
584         
585         /* api callbacks */
586         ot->invoke= actkeys_duplicate_invoke;
587         ot->exec= actkeys_duplicate_exec;
588         ot->poll= ED_operator_action_active;
589         
590         /* flags */
591         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
592         
593         /* to give to transform */
594         RNA_def_int(ot->srna, "mode", TFM_TIME_TRANSLATE, 0, INT_MAX, "Mode", "", 0, INT_MAX);
595 }
596
597 /* ******************** Delete Keyframes Operator ************************* */
598
599 static void delete_action_keys (bAnimContext *ac)
600 {
601         ListBase anim_data = {NULL, NULL};
602         bAnimListElem *ale;
603         int filter;
604         
605         /* filter data */
606         if (ac->datatype == ANIMCONT_GPENCIL)
607                 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_FOREDIT);
608         else
609                 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_CURVESONLY);
610         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
611         
612         /* loop through filtered data and delete selected keys */
613         for (ale= anim_data.first; ale; ale= ale->next) {
614                 if (ale->type != ANIMTYPE_GPLAYER) {
615                         FCurve *fcu= (FCurve *)ale->key_data;
616                         AnimData *adt= ale->adt;
617                         
618                         /* delete selected keyframes only */
619                         delete_fcurve_keys(fcu); 
620                         
621                         /* Only delete curve too if it won't be doing anything anymore */
622                         if ((fcu->totvert == 0) && (list_has_suitable_fmodifier(&fcu->modifiers, 0, FMI_TYPE_GENERATE_CURVE) == 0))
623                                 ANIM_fcurve_delete_from_animdata(ac, adt, fcu);
624                 }
625                 //else
626                 //      delete_gplayer_frames((bGPDlayer *)ale->data);
627         }
628         
629         /* free filtered list */
630         BLI_freelistN(&anim_data);
631 }
632
633 /* ------------------- */
634
635 static int actkeys_delete_exec(bContext *C, wmOperator *op)
636 {
637         bAnimContext ac;
638         
639         /* get editor data */
640         if (ANIM_animdata_get_context(C, &ac) == 0)
641                 return OPERATOR_CANCELLED;
642                 
643         /* delete keyframes */
644         delete_action_keys(&ac);
645         
646         /* validate keyframes after editing */
647         ANIM_editkeyframes_refresh(&ac);
648         
649         /* set notifier that keyframes have changed */
650         WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME_EDIT, NULL);
651         
652         return OPERATOR_FINISHED;
653 }
654  
655 void ACTION_OT_delete (wmOperatorType *ot)
656 {
657         /* identifiers */
658         ot->name= "Delete Keyframes";
659         ot->idname= "ACTION_OT_delete";
660         ot->description= "Remove all selected keyframes.";
661         
662         /* api callbacks */
663         ot->invoke= WM_operator_confirm;
664         ot->exec= actkeys_delete_exec;
665         ot->poll= ED_operator_action_active;
666         
667         /* flags */
668         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
669 }
670
671 /* ******************** Clean Keyframes Operator ************************* */
672
673 static void clean_action_keys (bAnimContext *ac, float thresh)
674 {       
675         ListBase anim_data = {NULL, NULL};
676         bAnimListElem *ale;
677         int filter;
678         
679         /* filter data */
680         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_SEL | ANIMFILTER_CURVESONLY);
681         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
682         
683         /* loop through filtered data and clean curves */
684         for (ale= anim_data.first; ale; ale= ale->next)
685                 clean_fcurve((FCurve *)ale->key_data, thresh);
686         
687         /* free temp data */
688         BLI_freelistN(&anim_data);
689 }
690
691 /* ------------------- */
692
693 static int actkeys_clean_exec(bContext *C, wmOperator *op)
694 {
695         bAnimContext ac;
696         float thresh;
697         
698         /* get editor data */
699         if (ANIM_animdata_get_context(C, &ac) == 0)
700                 return OPERATOR_CANCELLED;
701         if (ac.datatype == ANIMCONT_GPENCIL)
702                 return OPERATOR_PASS_THROUGH;
703                 
704         /* get cleaning threshold */
705         thresh= RNA_float_get(op->ptr, "threshold");
706         
707         /* clean keyframes */
708         clean_action_keys(&ac, thresh);
709         
710         /* validate keyframes after editing */
711         ANIM_editkeyframes_refresh(&ac);
712         
713         /* set notifier that keyframes have changed */
714         WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME_EDIT, NULL);
715         
716         return OPERATOR_FINISHED;
717 }
718  
719 void ACTION_OT_clean (wmOperatorType *ot)
720 {
721         /* identifiers */
722         ot->name= "Clean Keyframes";
723         ot->idname= "ACTION_OT_clean";
724         ot->description= "Simplify F-Curves by removing closely spaced keyframes.";
725         
726         /* api callbacks */
727         //ot->invoke=  // XXX we need that number popup for this! 
728         ot->exec= actkeys_clean_exec;
729         ot->poll= ED_operator_action_active;
730         
731         /* flags */
732         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
733         
734         /* properties */
735         RNA_def_float(ot->srna, "threshold", 0.001f, 0.0f, FLT_MAX, "Threshold", "", 0.0f, 1000.0f);
736 }
737
738 /* ******************** Sample Keyframes Operator *********************** */
739
740 /* Evaluates the curves between each selected keyframe on each frame, and keys the value  */
741 static void sample_action_keys (bAnimContext *ac)
742 {       
743         ListBase anim_data = {NULL, NULL};
744         bAnimListElem *ale;
745         int filter;
746         
747         /* filter data */
748         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_CURVESONLY);
749         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
750         
751         /* loop through filtered data and add keys between selected keyframes on every frame  */
752         for (ale= anim_data.first; ale; ale= ale->next)
753                 sample_fcurve((FCurve *)ale->key_data);
754         
755         /* admin and redraws */
756         BLI_freelistN(&anim_data);
757 }
758
759 /* ------------------- */
760
761 static int actkeys_sample_exec(bContext *C, wmOperator *op)
762 {
763         bAnimContext ac;
764         
765         /* get editor data */
766         if (ANIM_animdata_get_context(C, &ac) == 0)
767                 return OPERATOR_CANCELLED;
768         if (ac.datatype == ANIMCONT_GPENCIL)
769                 return OPERATOR_PASS_THROUGH;
770         
771         /* sample keyframes */
772         sample_action_keys(&ac);
773         
774         /* validate keyframes after editing */
775         ANIM_editkeyframes_refresh(&ac);
776         
777         /* set notifier that keyframes have changed */
778         WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME_EDIT, NULL);
779         
780         return OPERATOR_FINISHED;
781 }
782  
783 void ACTION_OT_sample (wmOperatorType *ot)
784 {
785         /* identifiers */
786         ot->name= "Sample Keyframes";
787         ot->idname= "ACTION_OT_sample";
788         ot->description= "Add keyframes on every frame between the selected keyframes.";
789         
790         /* api callbacks */
791         ot->exec= actkeys_sample_exec;
792         ot->poll= ED_operator_action_active;
793         
794         /* flags */
795         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
796 }
797
798 /* ************************************************************************** */
799 /* SETTINGS STUFF */
800
801 /* ******************** Set Extrapolation-Type Operator *********************** */
802
803 /* defines for set extrapolation-type for selected keyframes tool */
804 EnumPropertyItem prop_actkeys_expo_types[] = {
805         {FCURVE_EXTRAPOLATE_CONSTANT, "CONSTANT", 0, "Constant Extrapolation", ""},
806         {FCURVE_EXTRAPOLATE_LINEAR, "LINEAR", 0, "Linear Extrapolation", ""},
807         {0, NULL, 0, NULL, NULL}
808 };
809
810 /* this function is responsible for setting extrapolation mode for keyframes */
811 static void setexpo_action_keys(bAnimContext *ac, short mode) 
812 {
813         ListBase anim_data = {NULL, NULL};
814         bAnimListElem *ale;
815         int filter;
816         
817         /* filter data */
818         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_CURVESONLY);
819         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
820         
821         /* loop through setting mode per F-Curve */
822         for (ale= anim_data.first; ale; ale= ale->next) {
823                 FCurve *fcu= (FCurve *)ale->data;
824                 fcu->extend= mode;
825         }
826         
827         /* cleanup */
828         BLI_freelistN(&anim_data);
829 }
830
831 /* ------------------- */
832
833 static int actkeys_expo_exec(bContext *C, wmOperator *op)
834 {
835         bAnimContext ac;
836         short mode;
837         
838         /* get editor data */
839         if (ANIM_animdata_get_context(C, &ac) == 0)
840                 return OPERATOR_CANCELLED;
841         if (ac.datatype == ANIMCONT_GPENCIL) 
842                 return OPERATOR_PASS_THROUGH;
843                 
844         /* get handle setting mode */
845         mode= RNA_enum_get(op->ptr, "type");
846         
847         /* set handle type */
848         setexpo_action_keys(&ac, mode);
849         
850         /* validate keyframes after editing */
851         ANIM_editkeyframes_refresh(&ac);
852         
853         /* set notifier that keyframe properties have changed */
854         WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME_PROP, NULL);
855         
856         return OPERATOR_FINISHED;
857 }
858  
859 void ACTION_OT_extrapolation_type (wmOperatorType *ot)
860 {
861         /* identifiers */
862         ot->name= "Set Keyframe Extrapolation";
863         ot->idname= "ACTION_OT_extrapolation_type";
864         ot->description= "Set extrapolation mode for selected F-Curves.";
865         
866         /* api callbacks */
867         ot->invoke= WM_menu_invoke;
868         ot->exec= actkeys_expo_exec;
869         ot->poll= ED_operator_action_active;
870         
871         /* flags */
872         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
873         
874         /* id-props */
875         RNA_def_enum(ot->srna, "type", prop_actkeys_expo_types, 0, "Type", "");
876 }
877
878 /* ******************** Set Interpolation-Type Operator *********************** */
879
880 /* this function is responsible for setting interpolation mode for keyframes */
881 static void setipo_action_keys(bAnimContext *ac, short mode) 
882 {
883         ListBase anim_data = {NULL, NULL};
884         bAnimListElem *ale;
885         int filter;
886         BeztEditFunc set_cb= ANIM_editkeyframes_ipo(mode);
887         
888         /* filter data */
889         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_CURVESONLY);
890         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
891         
892         /* loop through setting BezTriple interpolation
893          * Note: we do not supply BeztEditData to the looper yet. Currently that's not necessary here...
894          */
895         for (ale= anim_data.first; ale; ale= ale->next)
896                 ANIM_fcurve_keys_bezier_loop(NULL, ale->key_data, NULL, set_cb, calchandles_fcurve);
897         
898         /* cleanup */
899         BLI_freelistN(&anim_data);
900 }
901
902 /* ------------------- */
903
904 static int actkeys_ipo_exec(bContext *C, wmOperator *op)
905 {
906         bAnimContext ac;
907         short mode;
908         
909         /* get editor data */
910         if (ANIM_animdata_get_context(C, &ac) == 0)
911                 return OPERATOR_CANCELLED;
912         if (ac.datatype == ANIMCONT_GPENCIL) 
913                 return OPERATOR_PASS_THROUGH;
914                 
915         /* get handle setting mode */
916         mode= RNA_enum_get(op->ptr, "type");
917         
918         /* set handle type */
919         setipo_action_keys(&ac, mode);
920         
921         /* validate keyframes after editing */
922         ANIM_editkeyframes_refresh(&ac);
923         
924         /* set notifier that keyframe properties have changed */
925         WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME_PROP, NULL);
926         
927         return OPERATOR_FINISHED;
928 }
929  
930 void ACTION_OT_interpolation_type (wmOperatorType *ot)
931 {
932         /* identifiers */
933         ot->name= "Set Keyframe Interpolation";
934         ot->idname= "ACTION_OT_interpolation_type";
935         ot->description= "Set interpolation mode for the F-Curve segments starting from the selected keyframes.";
936         
937         /* api callbacks */
938         ot->invoke= WM_menu_invoke;
939         ot->exec= actkeys_ipo_exec;
940         ot->poll= ED_operator_action_active;
941         
942         /* flags */
943         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
944         
945         /* id-props */
946         RNA_def_enum(ot->srna, "type", beztriple_interpolation_mode_items, 0, "Type", "");
947 }
948
949 /* ******************** Set Handle-Type Operator *********************** */
950
951 /* this function is responsible for setting handle-type of selected keyframes */
952 static void sethandles_action_keys(bAnimContext *ac, short mode) 
953 {
954         ListBase anim_data = {NULL, NULL};
955         bAnimListElem *ale;
956         int filter;
957         BeztEditFunc set_cb= ANIM_editkeyframes_handles(mode);
958         
959         /* filter data */
960         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_CURVESONLY);
961         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
962         
963         /* loop through setting flags for handles 
964          * Note: we do not supply BeztEditData to the looper yet. Currently that's not necessary here...
965          */
966         for (ale= anim_data.first; ale; ale= ale->next) {
967                 if (mode == -1) {       
968                         BeztEditFunc toggle_cb;
969                         
970                         /* check which type of handle to set (free or aligned) 
971                          *      - check here checks for handles with free alignment already
972                          */
973                         if (ANIM_fcurve_keys_bezier_loop(NULL, ale->key_data, NULL, set_cb, NULL))
974                                 toggle_cb= ANIM_editkeyframes_handles(HD_FREE);
975                         else
976                                 toggle_cb= ANIM_editkeyframes_handles(HD_ALIGN);
977                                 
978                         /* set handle-type */
979                         ANIM_fcurve_keys_bezier_loop(NULL, ale->key_data, NULL, toggle_cb, calchandles_fcurve);
980                 }
981                 else {
982                         /* directly set handle-type */
983                         ANIM_fcurve_keys_bezier_loop(NULL, ale->key_data, NULL, set_cb, calchandles_fcurve);
984                 }
985         }
986         
987         /* cleanup */
988         BLI_freelistN(&anim_data);
989 }
990
991 /* ------------------- */
992
993 static int actkeys_handletype_exec(bContext *C, wmOperator *op)
994 {
995         bAnimContext ac;
996         short mode;
997         
998         /* get editor data */
999         if (ANIM_animdata_get_context(C, &ac) == 0)
1000                 return OPERATOR_CANCELLED;
1001         if (ac.datatype == ANIMCONT_GPENCIL) 
1002                 return OPERATOR_PASS_THROUGH;
1003                 
1004         /* get handle setting mode */
1005         mode= RNA_enum_get(op->ptr, "type");
1006         
1007         /* set handle type */
1008         sethandles_action_keys(&ac, mode);
1009         
1010         /* validate keyframes after editing */
1011         ANIM_editkeyframes_refresh(&ac);
1012         
1013         /* set notifier that keyframe properties have changed */
1014         WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME_PROP, NULL);
1015         
1016         return OPERATOR_FINISHED;
1017 }
1018  
1019 void ACTION_OT_handle_type (wmOperatorType *ot)
1020 {
1021         /* identifiers */
1022         ot->name= "Set Keyframe Handle Type";
1023         ot->idname= "ACTION_OT_handle_type";
1024         ot->description= "Set type of handle for selected keyframes.";
1025         
1026         /* api callbacks */
1027         ot->invoke= WM_menu_invoke;
1028         ot->exec= actkeys_handletype_exec;
1029         ot->poll= ED_operator_action_active;
1030         
1031         /* flags */
1032         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1033         
1034         /* id-props */
1035         RNA_def_enum(ot->srna, "type", beztriple_handle_type_items, 0, "Type", "");
1036 }
1037
1038 /* ******************** Set Keyframe-Type Operator *********************** */
1039
1040 /* this function is responsible for setting interpolation mode for keyframes */
1041 static void setkeytype_action_keys(bAnimContext *ac, short mode) 
1042 {
1043         ListBase anim_data = {NULL, NULL};
1044         bAnimListElem *ale;
1045         int filter;
1046         BeztEditFunc set_cb= ANIM_editkeyframes_keytype(mode);
1047         
1048         /* filter data */
1049         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_CURVESONLY);
1050         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
1051         
1052         /* loop through setting BezTriple interpolation
1053          * Note: we do not supply BeztEditData to the looper yet. Currently that's not necessary here...
1054          */
1055         for (ale= anim_data.first; ale; ale= ale->next)
1056                 ANIM_fcurve_keys_bezier_loop(NULL, ale->key_data, NULL, set_cb, NULL);
1057         
1058         /* cleanup */
1059         BLI_freelistN(&anim_data);
1060 }
1061
1062 /* ------------------- */
1063
1064 static int actkeys_keytype_exec(bContext *C, wmOperator *op)
1065 {
1066         bAnimContext ac;
1067         short mode;
1068         
1069         /* get editor data */
1070         if (ANIM_animdata_get_context(C, &ac) == 0)
1071                 return OPERATOR_CANCELLED;
1072         if (ac.datatype == ANIMCONT_GPENCIL) 
1073                 return OPERATOR_PASS_THROUGH;
1074                 
1075         /* get handle setting mode */
1076         mode= RNA_enum_get(op->ptr, "type");
1077         
1078         /* set handle type */
1079         setkeytype_action_keys(&ac, mode);
1080         
1081         /* validate keyframes after editing */
1082         ANIM_editkeyframes_refresh(&ac);
1083         
1084         /* set notifier that keyframe properties have changed */
1085         WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME_PROP, NULL);
1086         
1087         return OPERATOR_FINISHED;
1088 }
1089  
1090 void ACTION_OT_keyframe_type (wmOperatorType *ot)
1091 {
1092         /* identifiers */
1093         ot->name= "Set Keyframe Type";
1094         ot->idname= "ACTION_OT_keyframe_type";
1095         ot->description= "Set type of keyframe for the seleced keyframes.";
1096         
1097         /* api callbacks */
1098         ot->invoke= WM_menu_invoke;
1099         ot->exec= actkeys_keytype_exec;
1100         ot->poll= ED_operator_action_active;
1101         
1102         /* flags */
1103         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1104         
1105         /* id-props */
1106         RNA_def_enum(ot->srna, "type", beztriple_keyframe_type_items, 0, "Type", "");
1107 }
1108
1109 /* ************************************************************************** */
1110 /* TRANSFORM STUFF */
1111
1112 /* ***************** Jump to Selected Frames Operator *********************** */
1113
1114 /* snap current-frame indicator to 'average time' of selected keyframe */
1115 static int actkeys_framejump_exec(bContext *C, wmOperator *op)
1116 {
1117         bAnimContext ac;
1118         ListBase anim_data= {NULL, NULL};
1119         bAnimListElem *ale;
1120         int filter;
1121         BeztEditData bed;
1122         
1123         /* get editor data */
1124         if (ANIM_animdata_get_context(C, &ac) == 0)
1125                 return OPERATOR_CANCELLED;
1126         
1127         /* init edit data */
1128         memset(&bed, 0, sizeof(BeztEditData));
1129         
1130         /* loop over action data, averaging values */
1131         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVESONLY);
1132         ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
1133         
1134         for (ale= anim_data.first; ale; ale= ale->next) {
1135                 AnimData *adt= ANIM_nla_mapping_get(&ac, ale);
1136                 
1137                 if (adt) {
1138                         ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, 1); 
1139                         ANIM_fcurve_keys_bezier_loop(&bed, ale->key_data, NULL, bezt_calc_average, NULL);
1140                         ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 1, 1);
1141                 }
1142                 else
1143                         ANIM_fcurve_keys_bezier_loop(&bed, ale->key_data, NULL, bezt_calc_average, NULL);
1144         }
1145         
1146         BLI_freelistN(&anim_data);
1147         
1148         /* set the new current frame value, based on the average time */
1149         if (bed.i1) {
1150                 Scene *scene= ac.scene;
1151                 CFRA= (int)floor((bed.f1 / bed.i1) + 0.5f);
1152         }
1153         
1154         /* set notifier that things have changed */
1155         WM_event_add_notifier(C, NC_SCENE|ND_FRAME, ac.scene);
1156         
1157         return OPERATOR_FINISHED;
1158 }
1159
1160 void ACTION_OT_frame_jump (wmOperatorType *ot)
1161 {
1162         /* identifiers */
1163         ot->name= "Jump to Frame";
1164         ot->idname= "ACTION_OT_frame_jump";
1165         ot->description= "Set the current frame to the average frame of the selected keyframes.";
1166         
1167         /* api callbacks */
1168         ot->exec= actkeys_framejump_exec;
1169         ot->poll= ED_operator_action_active;
1170         
1171         /* flags */
1172         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1173 }
1174
1175 /* ******************** Snap Keyframes Operator *********************** */
1176
1177 /* defines for snap keyframes tool */
1178 EnumPropertyItem prop_actkeys_snap_types[] = {
1179         {ACTKEYS_SNAP_CFRA, "CFRA", 0, "Current frame", ""},
1180         {ACTKEYS_SNAP_NEAREST_FRAME, "NEAREST_FRAME", 0, "Nearest Frame", ""}, // XXX as single entry?
1181         {ACTKEYS_SNAP_NEAREST_SECOND, "NEAREST_SECOND", 0, "Nearest Second", ""}, // XXX as single entry?
1182         {ACTKEYS_SNAP_NEAREST_MARKER, "NEAREST_MARKER", 0, "Nearest Marker", ""},
1183         {0, NULL, 0, NULL, NULL}
1184 };
1185
1186 /* this function is responsible for snapping keyframes to frame-times */
1187 static void snap_action_keys(bAnimContext *ac, short mode) 
1188 {
1189         ListBase anim_data = {NULL, NULL};
1190         bAnimListElem *ale;
1191         int filter;
1192         
1193         BeztEditData bed;
1194         BeztEditFunc edit_cb;
1195         
1196         /* filter data */
1197         if (ac->datatype == ANIMCONT_GPENCIL)
1198                 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_FOREDIT);
1199         else
1200                 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_CURVESONLY);
1201         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
1202         
1203         /* get beztriple editing callbacks */
1204         edit_cb= ANIM_editkeyframes_snap(mode);
1205         
1206         memset(&bed, 0, sizeof(BeztEditData)); 
1207         bed.scene= ac->scene;
1208         if (mode == ACTKEYS_SNAP_NEAREST_MARKER) {
1209                 bed.list.first= (ac->markers) ? ac->markers->first : NULL;
1210                 bed.list.last= (ac->markers) ? ac->markers->last : NULL;
1211         }
1212         
1213         /* snap keyframes */
1214         for (ale= anim_data.first; ale; ale= ale->next) {
1215                 AnimData *adt= ANIM_nla_mapping_get(ac, ale);
1216                 
1217                 if (adt) {
1218                         ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, 1); 
1219                         ANIM_fcurve_keys_bezier_loop(&bed, ale->key_data, NULL, edit_cb, calchandles_fcurve);
1220                         ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 1, 1);
1221                 }
1222                 //else if (ale->type == ACTTYPE_GPLAYER)
1223                 //      snap_gplayer_frames(ale->data, mode);
1224                 else 
1225                         ANIM_fcurve_keys_bezier_loop(&bed, ale->key_data, NULL, edit_cb, calchandles_fcurve);
1226         }
1227         BLI_freelistN(&anim_data);
1228 }
1229
1230 /* ------------------- */
1231
1232 static int actkeys_snap_exec(bContext *C, wmOperator *op)
1233 {
1234         bAnimContext ac;
1235         short mode;
1236         
1237         /* get editor data */
1238         if (ANIM_animdata_get_context(C, &ac) == 0)
1239                 return OPERATOR_CANCELLED;
1240                 
1241         /* get snapping mode */
1242         mode= RNA_enum_get(op->ptr, "type");
1243         
1244         /* snap keyframes */
1245         snap_action_keys(&ac, mode);
1246         
1247         /* validate keyframes after editing */
1248         ANIM_editkeyframes_refresh(&ac);
1249         
1250         /* set notifier that keyframes have changed */
1251         WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME_EDIT, NULL);
1252         
1253         return OPERATOR_FINISHED;
1254 }
1255  
1256 void ACTION_OT_snap (wmOperatorType *ot)
1257 {
1258         /* identifiers */
1259         ot->name= "Snap Keys";
1260         ot->idname= "ACTION_OT_snap";
1261         ot->description= "Snap selected keyframes to the times specified.";
1262         
1263         /* api callbacks */
1264         ot->invoke= WM_menu_invoke;
1265         ot->exec= actkeys_snap_exec;
1266         ot->poll= ED_operator_action_active;
1267         
1268         /* flags */
1269         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1270         
1271         /* id-props */
1272         RNA_def_enum(ot->srna, "type", prop_actkeys_snap_types, 0, "Type", "");
1273 }
1274
1275 /* ******************** Mirror Keyframes Operator *********************** */
1276
1277 /* defines for mirror keyframes tool */
1278 EnumPropertyItem prop_actkeys_mirror_types[] = {
1279         {ACTKEYS_MIRROR_CFRA, "CFRA", 0, "By Times over Current frame", ""},
1280         {ACTKEYS_MIRROR_YAXIS, "YAXIS", 0, "By Times over Time=0", ""},
1281         {ACTKEYS_MIRROR_XAXIS, "XAXIS", 0, "By Values over Value=0", ""},
1282         {ACTKEYS_MIRROR_MARKER, "MARKER", 0, "By Times over First Selected Marker", ""},
1283         {0, NULL, 0, NULL, NULL}
1284 };
1285
1286 /* this function is responsible for mirroring keyframes */
1287 static void mirror_action_keys(bAnimContext *ac, short mode) 
1288 {
1289         ListBase anim_data = {NULL, NULL};
1290         bAnimListElem *ale;
1291         int filter;
1292         
1293         BeztEditData bed;
1294         BeztEditFunc edit_cb;
1295         
1296         /* get beztriple editing callbacks */
1297         edit_cb= ANIM_editkeyframes_mirror(mode);
1298         
1299         memset(&bed, 0, sizeof(BeztEditData)); 
1300         bed.scene= ac->scene;
1301         
1302         /* for 'first selected marker' mode, need to find first selected marker first! */
1303         // XXX should this be made into a helper func in the API?
1304         if (mode == ACTKEYS_MIRROR_MARKER) {
1305                 TimeMarker *marker= NULL;
1306                 
1307                 /* find first selected marker */
1308                 if (ac->markers) {
1309                         for (marker= ac->markers->first; marker; marker=marker->next) {
1310                                 if (marker->flag & SELECT) {
1311                                         break;
1312                                 }
1313                         }
1314                 }
1315                 
1316                 /* store marker's time (if available) */
1317                 if (marker)
1318                         bed.f1= (float)marker->frame;
1319                 else
1320                         return;
1321         }
1322         
1323         /* filter data */
1324         if (ac->datatype == ANIMCONT_GPENCIL)
1325                 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_FOREDIT);
1326         else
1327                 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_CURVESONLY);
1328         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
1329         
1330         /* mirror keyframes */
1331         for (ale= anim_data.first; ale; ale= ale->next) {
1332                 AnimData *adt= ANIM_nla_mapping_get(ac, ale);
1333                 
1334                 if (adt) {
1335                         ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, 1); 
1336                         ANIM_fcurve_keys_bezier_loop(&bed, ale->key_data, NULL, edit_cb, calchandles_fcurve);
1337                         ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 1, 1);
1338                 }
1339                 //else if (ale->type == ACTTYPE_GPLAYER)
1340                 //      snap_gplayer_frames(ale->data, mode);
1341                 else 
1342                         ANIM_fcurve_keys_bezier_loop(&bed, ale->key_data, NULL, edit_cb, calchandles_fcurve);
1343         }
1344         BLI_freelistN(&anim_data);
1345 }
1346
1347 /* ------------------- */
1348
1349 static int actkeys_mirror_exec(bContext *C, wmOperator *op)
1350 {
1351         bAnimContext ac;
1352         short mode;
1353         
1354         /* get editor data */
1355         if (ANIM_animdata_get_context(C, &ac) == 0)
1356                 return OPERATOR_CANCELLED;
1357                 
1358         /* get mirroring mode */
1359         mode= RNA_enum_get(op->ptr, "type");
1360         
1361         /* mirror keyframes */
1362         mirror_action_keys(&ac, mode);
1363         
1364         /* validate keyframes after editing */
1365         ANIM_editkeyframes_refresh(&ac);
1366         
1367         /* set notifier that keyframes have changed */
1368         WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME_EDIT, NULL);
1369         
1370         return OPERATOR_FINISHED;
1371 }
1372  
1373 void ACTION_OT_mirror (wmOperatorType *ot)
1374 {
1375         /* identifiers */
1376         ot->name= "Mirror Keys";
1377         ot->idname= "ACTION_OT_mirror";
1378         ot->description= "Flip selected keyframes over the selected mirror line.";
1379         
1380         /* api callbacks */
1381         ot->invoke= WM_menu_invoke;
1382         ot->exec= actkeys_mirror_exec;
1383         ot->poll= ED_operator_action_active;
1384         
1385         /* flags */
1386         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1387         
1388         /* id-props */
1389         RNA_def_enum(ot->srna, "type", prop_actkeys_mirror_types, 0, "Type", "");
1390 }
1391
1392 /* ************************************************************************** */