99f18a2e653398633bec12d7bdec21862d1ea65b
[blender.git] / source / blender / editors / space_action / action_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
64 #include "BKE_action.h"
65 #include "BKE_depsgraph.h"
66 #include "BKE_fcurve.h"
67 #include "BKE_key.h"
68 #include "BKE_material.h"
69 #include "BKE_object.h"
70 #include "BKE_context.h"
71 #include "BKE_utildefines.h"
72
73 #include "UI_view2d.h"
74
75 #include "BIF_transform.h"
76
77 #include "ED_anim_api.h"
78 #include "ED_keyframing.h"
79 #include "ED_keyframes_draw.h"
80 #include "ED_keyframes_edit.h"
81 #include "ED_screen.h"
82 #include "ED_space_api.h"
83
84 #include "WM_api.h"
85 #include "WM_types.h"
86
87 #include "action_intern.h"
88
89 /* ************************************************************************** */
90 /* KEYFRAME-RANGE STUFF */
91
92 /* *************************** Calculate Range ************************** */
93
94 /* Get the min/max keyframes*/
95 static void get_keyframe_extents (bAnimContext *ac, float *min, float *max)
96 {
97         ListBase anim_data = {NULL, NULL};
98         bAnimListElem *ale;
99         int filter;
100         
101         /* get data to filter, from Action or Dopesheet */
102         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_SEL | ANIMFILTER_FOREDIT | ANIMFILTER_CURVESONLY);
103         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
104         
105         /* set large values to try to override */
106         *min= 999999999.0f;
107         *max= -999999999.0f;
108         
109         /* check if any channels to set range with */
110         if (anim_data.first) {
111                 /* go through channels, finding max extents */
112                 for (ale= anim_data.first; ale; ale= ale->next) {
113                         Object *nob= ANIM_nla_mapping_get(ac, ale);
114                         FCurve *fcu= (FCurve *)ale->key_data;
115                         float tmin, tmax;
116                         
117                         /* get range and apply necessary scaling before */
118                         calc_fcurve_range(fcu, &tmin, &tmax);
119                         
120                         if (nob) {
121                                 tmin= get_action_frame_inv(nob, tmin);
122                                 tmax= get_action_frame_inv(nob, tmax);
123                         }
124                         
125                         /* try to set cur using these values, if they're more extreme than previously set values */
126                         *min= MIN2(*min, tmin);
127                         *max= MAX2(*max, tmax);
128                 }
129                 
130                 /* free memory */
131                 BLI_freelistN(&anim_data);
132         }
133         else {
134                 /* set default range */
135                 if (ac->scene) {
136                         *min= (float)ac->scene->r.sfra;
137                         *max= (float)ac->scene->r.efra;
138                 }
139                 else {
140                         *min= -5;
141                         *max= 100;
142                 }
143         }
144 }
145
146 /* ****************** Automatic Preview-Range Operator ****************** */
147
148 static int actkeys_previewrange_exec(bContext *C, wmOperator *op)
149 {
150         bAnimContext ac;
151         Scene *scene;
152         float min, max;
153         
154         /* get editor data */
155         if (ANIM_animdata_get_context(C, &ac) == 0)
156                 return OPERATOR_CANCELLED;
157         if (ac.scene == NULL)
158                 return OPERATOR_CANCELLED;
159         else
160                 scene= ac.scene;
161         
162         /* set the range directly */
163         get_keyframe_extents(&ac, &min, &max);
164         scene->r.psfra= (int)floor(min + 0.5f);
165         scene->r.pefra= (int)floor(max + 0.5f);
166         
167         /* set notifier that things have changed */
168         // XXX err... there's nothing for frame ranges yet, but this should do fine too
169         WM_event_add_notifier(C, NC_SCENE|ND_FRAME, ac.scene); 
170         
171         return OPERATOR_FINISHED;
172 }
173  
174 void ACT_OT_set_previewrange (wmOperatorType *ot)
175 {
176         /* identifiers */
177         ot->name= "Auto-Set Preview Range";
178         ot->idname= "ACT_OT_set_previewrange";
179         
180         /* api callbacks */
181         ot->exec= actkeys_previewrange_exec;
182         ot->poll= ED_operator_areaactive;
183         
184         /* flags */
185         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
186 }
187
188 /* ****************** View-All Operator ****************** */
189
190 static int actkeys_viewall_exec(bContext *C, wmOperator *op)
191 {
192         bAnimContext ac;
193         View2D *v2d;
194         float extra;
195         
196         /* get editor data */
197         if (ANIM_animdata_get_context(C, &ac) == 0)
198                 return OPERATOR_CANCELLED;
199         v2d= &ac.ar->v2d;
200         
201         /* set the horizontal range, with an extra offset so that the extreme keys will be in view */
202         get_keyframe_extents(&ac, &v2d->cur.xmin, &v2d->cur.xmax);
203         
204         extra= 0.1f * (v2d->cur.xmax - v2d->cur.xmin);
205         v2d->cur.xmin -= extra;
206         v2d->cur.xmax += extra;
207         
208         /* set vertical range */
209         v2d->cur.ymax= 0.0f;
210         v2d->cur.ymin= (float)-(v2d->mask.ymax - v2d->mask.ymin);
211         
212         /* do View2D syncing */
213         UI_view2d_sync(CTX_wm_screen(C), CTX_wm_area(C), v2d, V2D_LOCK_COPY);
214         
215         /* set notifier that things have changed */
216         ED_area_tag_redraw(CTX_wm_area(C));
217         
218         return OPERATOR_FINISHED;
219 }
220  
221 void ACT_OT_view_all (wmOperatorType *ot)
222 {
223         /* identifiers */
224         ot->name= "View All";
225         ot->idname= "ACT_OT_view_all";
226         
227         /* api callbacks */
228         ot->exec= actkeys_viewall_exec;
229         ot->poll= ED_operator_areaactive;
230         
231         /* flags */
232         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
233 }
234
235 /* ************************************************************************** */
236 /* GENERAL STUFF */
237
238 /* ******************** Copy/Paste Keyframes Operator ************************* */
239 /* NOTE: the backend code for this is shared with the graph editor */
240
241 static short copy_action_keys (bAnimContext *ac)
242 {       
243         ListBase anim_data = {NULL, NULL};
244         int filter, ok=0;
245         
246         /* clear buffer first */
247         free_anim_copybuf();
248         
249         /* filter data */
250         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_SEL | ANIMFILTER_CURVESONLY);
251         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
252         
253         /* copy keyframes */
254         ok= copy_animedit_keys(ac, &anim_data);
255         
256         /* clean up */
257         BLI_freelistN(&anim_data);
258 }
259
260
261 static short paste_action_keys (bAnimContext *ac)
262 {       
263         ListBase anim_data = {NULL, NULL};
264         int filter, ok=0;
265         
266         /* filter data */
267         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_SEL | ANIMFILTER_FOREDIT | ANIMFILTER_CURVESONLY);
268         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
269         
270         /* paste keyframes */
271         ok= paste_animedit_keys(ac, &anim_data);
272         
273         /* clean up */
274         BLI_freelistN(&anim_data);
275 }
276
277 /* ------------------- */
278
279 static int actkeys_copy_exec(bContext *C, wmOperator *op)
280 {
281         bAnimContext ac;
282         
283         /* get editor data */
284         if (ANIM_animdata_get_context(C, &ac) == 0)
285                 return OPERATOR_CANCELLED;
286         
287         /* copy keyframes */
288         if (ac.datatype == ANIMCONT_GPENCIL) {
289                 // FIXME...
290         }
291         else {
292                 if (copy_action_keys(&ac)) {    
293                         // XXX errors - need a way to inform the user 
294                         printf("Action Copy: No keyframes copied to copy-paste buffer\n");
295                 }
296         }
297         
298         /* set notifier tha things have changed */
299         ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_KEYFRAMES_VALUES);
300         
301         return OPERATOR_FINISHED;
302 }
303  
304 void ACT_OT_keyframes_copy (wmOperatorType *ot)
305 {
306         /* identifiers */
307         ot->name= "Copy Keyframes";
308         ot->idname= "ACT_OT_keyframes_copy";
309         
310         /* api callbacks */
311         ot->exec= actkeys_copy_exec;
312         ot->poll= ED_operator_areaactive;
313         
314         /* flags */
315         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
316 }
317
318
319
320 static int actkeys_paste_exec(bContext *C, wmOperator *op)
321 {
322         bAnimContext ac;
323         
324         /* get editor data */
325         if (ANIM_animdata_get_context(C, &ac) == 0)
326                 return OPERATOR_CANCELLED;
327         
328         /* paste keyframes */
329         if (ac.datatype == ANIMCONT_GPENCIL) {
330                 // FIXME...
331         }
332         else {
333                 if (paste_action_keys(&ac)) {
334                         // XXX errors - need a way to inform the user 
335                         printf("Action Paste: Nothing to paste, as Copy-Paste buffer was empty.\n");
336                 }
337         }
338         
339         /* validate keyframes after editing */
340         ANIM_editkeyframes_refresh(&ac);
341         
342         /* set notifier tha things have changed */
343         ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_KEYFRAMES_VALUES);
344         
345         return OPERATOR_FINISHED;
346 }
347  
348 void ACT_OT_keyframes_paste (wmOperatorType *ot)
349 {
350         /* identifiers */
351         ot->name= "Paste Keyframes";
352         ot->idname= "ACT_OT_keyframes_paste";
353         
354         /* api callbacks */
355         ot->exec= actkeys_paste_exec;
356         ot->poll= ED_operator_areaactive;
357         
358         /* flags */
359         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
360 }
361
362 /* ******************** Insert Keyframes Operator ************************* */
363
364 /* defines for insert keyframes tool */
365 EnumPropertyItem prop_actkeys_insertkey_types[] = {
366         {1, "ALL", "All Channels", ""},
367         {2, "SEL", "Only Selected Channels", ""},
368         {3, "GROUP", "In Active Group", ""}, // xxx not in all cases
369         {0, NULL, NULL, NULL}
370 };
371
372 /* this function is responsible for snapping keyframes to frame-times */
373 static void insert_action_keys(bAnimContext *ac, short mode) 
374 {
375         ListBase anim_data = {NULL, NULL};
376         bAnimListElem *ale;
377         int filter;
378         
379         Scene *scene= ac->scene;
380         float cfra= (float)CFRA;
381         short flag = 0;
382         
383         /* filter data */
384         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_CURVESONLY);
385         if (mode == 2)                  filter |= ANIMFILTER_SEL;
386         else if (mode == 3)     filter |= ANIMFILTER_ACTGROUPED;
387         
388         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
389         
390         /* init keyframing flag */
391         if (IS_AUTOKEY_FLAG(AUTOMATKEY)) flag |= INSERTKEY_MATRIX;
392         if (IS_AUTOKEY_FLAG(INSERTNEEDED)) flag |= INSERTKEY_NEEDED;
393         // if (IS_AUTOKEY_MODE(EDITKEYS)) flag |= INSERTKEY_REPLACE;
394         
395         /* insert keyframes */
396         for (ale= anim_data.first; ale; ale= ale->next) {
397                 //Object *nob= ANIM_nla_mapping_get(ac, ale);
398                 FCurve *fcu= (FCurve *)ale->key_data;
399                 
400                 /* adjust current frame for NLA-scaling */
401                 //if (nob)
402                 //      cfra= get_action_frame(nob, CFRA);
403                 //else 
404                 //      cfra= (float)CFRA;
405                         
406                 /* if there's an id */
407                 if (ale->id)
408                         insertkey(ale->id, ((fcu->grp)?(fcu->grp->name):(NULL)), fcu->rna_path, fcu->array_index, cfra, flag);
409                 else
410                         insert_vert_fcurve(fcu, cfra, fcu->curval, 0);
411         }
412         
413         BLI_freelistN(&anim_data);
414 }
415
416 /* ------------------- */
417
418 static int actkeys_insertkey_exec(bContext *C, wmOperator *op)
419 {
420         bAnimContext ac;
421         short mode;
422         
423         /* get editor data */
424         if (ANIM_animdata_get_context(C, &ac) == 0)
425                 return OPERATOR_CANCELLED;
426         if (ac.datatype == ANIMCONT_GPENCIL)
427                 return OPERATOR_CANCELLED;
428                 
429         /* get snapping mode */
430         mode= RNA_enum_get(op->ptr, "type");
431         
432         /* snap keyframes */
433         insert_action_keys(&ac, mode);
434         
435         /* validate keyframes after editing */
436         ANIM_editkeyframes_refresh(&ac);
437         
438         /* set notifier tha things have changed */
439         ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_KEYFRAMES_VALUES);
440         
441         return OPERATOR_FINISHED;
442 }
443
444 void ACT_OT_keyframes_insert (wmOperatorType *ot)
445 {
446         /* identifiers */
447         ot->name= "Insert Keyframes";
448         ot->idname= "ACT_OT_keyframes_insert";
449         
450         /* api callbacks */
451         ot->invoke= WM_menu_invoke;
452         ot->exec= actkeys_insertkey_exec;
453         ot->poll= ED_operator_areaactive;
454         
455         /* flags */
456         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
457         
458         /* id-props */
459         RNA_def_enum(ot->srna, "type", prop_actkeys_insertkey_types, 0, "Type", "");
460 }
461
462 /* ******************** Duplicate Keyframes Operator ************************* */
463
464 static void duplicate_action_keys (bAnimContext *ac)
465 {
466         ListBase anim_data = {NULL, NULL};
467         bAnimListElem *ale;
468         int filter;
469         
470         /* filter data */
471         if (ac->datatype == ANIMCONT_GPENCIL)
472                 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_FOREDIT);
473         else
474                 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_CURVESONLY);
475         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
476         
477         /* loop through filtered data and delete selected keys */
478         for (ale= anim_data.first; ale; ale= ale->next) {
479                 //if (ale->type == ANIMTYPE_GPLAYER)
480                 //      delete_gplayer_frames((bGPDlayer *)ale->data);
481                 //else
482                         duplicate_fcurve_keys((FCurve *)ale->key_data);
483         }
484         
485         /* free filtered list */
486         BLI_freelistN(&anim_data);
487 }
488
489 /* ------------------- */
490
491 static int actkeys_duplicate_exec(bContext *C, wmOperator *op)
492 {
493         bAnimContext ac;
494         
495         /* get editor data */
496         if (ANIM_animdata_get_context(C, &ac) == 0)
497                 return OPERATOR_CANCELLED;
498                 
499         /* duplicate keyframes */
500         duplicate_action_keys(&ac);
501         
502         /* validate keyframes after editing */
503         ANIM_editkeyframes_refresh(&ac);
504         
505         /* set notifier tha things have changed */
506         ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_KEYFRAMES_VALUES);
507         
508         return OPERATOR_FINISHED; // xxx - start transform
509 }
510
511 static int actkeys_duplicate_invoke(bContext *C, wmOperator *op, wmEvent *event)
512 {
513         actkeys_duplicate_exec(C, op);
514         
515         RNA_int_set(op->ptr, "mode", TFM_TIME_TRANSLATE);
516         WM_operator_name_call(C, "TFM_OT_transform", WM_OP_INVOKE_REGION_WIN, op->ptr);
517
518         return OPERATOR_FINISHED;
519 }
520  
521 void ACT_OT_keyframes_duplicate (wmOperatorType *ot)
522 {
523         /* identifiers */
524         ot->name= "Duplicate Keyframes";
525         ot->idname= "ACT_OT_keyframes_duplicate";
526         
527         /* api callbacks */
528         ot->invoke= actkeys_duplicate_invoke;
529         ot->exec= actkeys_duplicate_exec;
530         ot->poll= ED_operator_areaactive;
531         
532         /* flags */
533         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
534         
535         /* to give to transform */
536         RNA_def_int(ot->srna, "mode", TFM_TIME_TRANSLATE, 0, INT_MAX, "Mode", "", 0, INT_MAX);
537 }
538
539 /* ******************** Delete Keyframes Operator ************************* */
540
541 static void delete_action_keys (bAnimContext *ac)
542 {
543         ListBase anim_data = {NULL, NULL};
544         bAnimListElem *ale;
545         int filter;
546         
547         /* filter data */
548         if (ac->datatype == ANIMCONT_GPENCIL)
549                 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_FOREDIT);
550         else
551                 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_CURVESONLY);
552         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
553         
554         /* loop through filtered data and delete selected keys */
555         for (ale= anim_data.first; ale; ale= ale->next) {
556                 //if (ale->type == ANIMTYPE_GPLAYER)
557                 //      delete_gplayer_frames((bGPDlayer *)ale->data);
558                 //else
559                         delete_fcurve_keys((FCurve *)ale->key_data); // XXX... this doesn't delete empty curves anymore
560         }
561         
562         /* free filtered list */
563         BLI_freelistN(&anim_data);
564 }
565
566 /* ------------------- */
567
568 static int actkeys_delete_exec(bContext *C, wmOperator *op)
569 {
570         bAnimContext ac;
571         
572         /* get editor data */
573         if (ANIM_animdata_get_context(C, &ac) == 0)
574                 return OPERATOR_CANCELLED;
575                 
576         /* delete keyframes */
577         delete_action_keys(&ac);
578         
579         /* validate keyframes after editing */
580         ANIM_editkeyframes_refresh(&ac);
581         
582         /* set notifier tha things have changed */
583         ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_KEYFRAMES_VALUES);
584         
585         return OPERATOR_FINISHED;
586 }
587  
588 void ACT_OT_keyframes_delete (wmOperatorType *ot)
589 {
590         /* identifiers */
591         ot->name= "Delete Keyframes";
592         ot->idname= "ACT_OT_keyframes_delete";
593         
594         /* api callbacks */
595         ot->invoke= WM_operator_confirm;
596         ot->exec= actkeys_delete_exec;
597         ot->poll= ED_operator_areaactive;
598         
599         /* flags */
600         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
601 }
602
603 /* ******************** Clean Keyframes Operator ************************* */
604
605 static void clean_action_keys (bAnimContext *ac, float thresh)
606 {       
607         ListBase anim_data = {NULL, NULL};
608         bAnimListElem *ale;
609         int filter;
610         
611         /* filter data */
612         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_SEL | ANIMFILTER_CURVESONLY);
613         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
614         
615         /* loop through filtered data and clean curves */
616         for (ale= anim_data.first; ale; ale= ale->next)
617                 clean_fcurve((FCurve *)ale->key_data, thresh);
618         
619         /* free temp data */
620         BLI_freelistN(&anim_data);
621 }
622
623 /* ------------------- */
624
625 static int actkeys_clean_exec(bContext *C, wmOperator *op)
626 {
627         bAnimContext ac;
628         float thresh;
629         
630         /* get editor data */
631         if (ANIM_animdata_get_context(C, &ac) == 0)
632                 return OPERATOR_CANCELLED;
633         if (ac.datatype == ANIMCONT_GPENCIL)
634                 return OPERATOR_PASS_THROUGH;
635                 
636         /* get cleaning threshold */
637         thresh= RNA_float_get(op->ptr, "threshold");
638         
639         /* clean keyframes */
640         clean_action_keys(&ac, thresh);
641         
642         /* validate keyframes after editing */
643         ANIM_editkeyframes_refresh(&ac);
644         
645         /* set notifier tha things have changed */
646         ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_KEYFRAMES_VALUES);
647         
648         return OPERATOR_FINISHED;
649 }
650  
651 void ACT_OT_keyframes_clean (wmOperatorType *ot)
652 {
653         /* identifiers */
654         ot->name= "Clean Keyframes";
655         ot->idname= "ACT_OT_keyframes_clean";
656         
657         /* api callbacks */
658         //ot->invoke=  // XXX we need that number popup for this! 
659         ot->exec= actkeys_clean_exec;
660         ot->poll= ED_operator_areaactive;
661         
662         /* flags */
663         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
664         
665         /* properties */
666         RNA_def_float(ot->srna, "threshold", 0.001f, 0.0f, FLT_MAX, "Threshold", "", 0.0f, 1000.0f);
667 }
668
669 /* ******************** Sample Keyframes Operator *********************** */
670
671 /* little cache for values... */
672 typedef struct tempFrameValCache {
673         float frame, val;
674 } tempFrameValCache;
675
676 /* Evaluates the curves between each selected keyframe on each frame, and keys the value  */
677 static void sample_action_keys (bAnimContext *ac)
678 {       
679         ListBase anim_data = {NULL, NULL};
680         bAnimListElem *ale;
681         int filter;
682         
683         /* filter data */
684         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_CURVESONLY);
685         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
686         
687         /* loop through filtered data and add keys between selected keyframes on every frame  */
688         for (ale= anim_data.first; ale; ale= ale->next) {
689                 FCurve *fcu= (FCurve *)ale->key_data;
690                 BezTriple *bezt, *start=NULL, *end=NULL;
691                 tempFrameValCache *value_cache, *fp;
692                 int sfra, range;
693                 int i, n;
694                 
695                 /* find selected keyframes... once pair has been found, add keyframes  */
696                 for (i=0, bezt=fcu->bezt; i < fcu->totvert; i++, bezt++) {
697                         /* check if selected, and which end this is */
698                         if (BEZSELECTED(bezt)) {
699                                 if (start) {
700                                         /* set end */
701                                         end= bezt;
702                                         
703                                         /* cache values then add keyframes using these values, as adding
704                                          * keyframes while sampling will affect the outcome...
705                                          */
706                                         range= (int)( ceil(end->vec[1][0] - start->vec[1][0]) );
707                                         sfra= (int)( floor(start->vec[1][0]) );
708                                         
709                                         if (range) {
710                                                 value_cache= MEM_callocN(sizeof(tempFrameValCache)*range, "IcuFrameValCache");
711                                                 
712                                                 /*      sample values   */
713                                                 for (n=0, fp=value_cache; n<range && fp; n++, fp++) {
714                                                         fp->frame= (float)(sfra + n);
715                                                         fp->val= evaluate_fcurve(fcu, fp->frame);
716                                                 }
717                                                 
718                                                 /*      add keyframes with these        */
719                                                 for (n=0, fp=value_cache; n<range && fp; n++, fp++) {
720                                                         insert_vert_fcurve(fcu, fp->frame, fp->val, 1);
721                                                 }
722                                                 
723                                                 /* free temp cache */
724                                                 MEM_freeN(value_cache);
725                                                 
726                                                 /* as we added keyframes, we need to compensate so that bezt is at the right place */
727                                                 bezt = fcu->bezt + i + range - 1;
728                                                 i += (range - 1);
729                                         }
730                                         
731                                         /* bezt was selected, so it now marks the start of a whole new chain to search */
732                                         start= bezt;
733                                         end= NULL;
734                                 }
735                                 else {
736                                         /* just set start keyframe */
737                                         start= bezt;
738                                         end= NULL;
739                                 }
740                         }
741                 }
742                 
743                 /* recalculate channel's handles? */
744                 calchandles_fcurve(fcu);
745         }
746         
747         /* admin and redraws */
748         BLI_freelistN(&anim_data);
749 }
750
751 /* ------------------- */
752
753 static int actkeys_sample_exec(bContext *C, wmOperator *op)
754 {
755         bAnimContext ac;
756         
757         /* get editor data */
758         if (ANIM_animdata_get_context(C, &ac) == 0)
759                 return OPERATOR_CANCELLED;
760         if (ac.datatype == ANIMCONT_GPENCIL)
761                 return OPERATOR_PASS_THROUGH;
762         
763         /* sample keyframes */
764         sample_action_keys(&ac);
765         
766         /* validate keyframes after editing */
767         ANIM_editkeyframes_refresh(&ac);
768         
769         /* set notifier tha things have changed */
770         ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_KEYFRAMES_VALUES);
771         
772         return OPERATOR_FINISHED;
773 }
774  
775 void ACT_OT_keyframes_sample (wmOperatorType *ot)
776 {
777         /* identifiers */
778         ot->name= "Sample Keyframes";
779         ot->idname= "ACT_OT_keyframes_sample";
780         
781         /* api callbacks */
782         ot->exec= actkeys_sample_exec;
783         ot->poll= ED_operator_areaactive;
784         
785         /* flags */
786         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
787 }
788
789 /* ************************************************************************** */
790 /* SETTINGS STUFF */
791
792 /* ******************** Set Extrapolation-Type Operator *********************** */
793
794 /* defines for set extrapolation-type for selected keyframes tool */
795 EnumPropertyItem prop_actkeys_expo_types[] = {
796         {FCURVE_EXTRAPOLATE_CONSTANT, "CONSTANT", "Constant Extrapolation", ""},
797         {FCURVE_EXTRAPOLATE_LINEAR, "LINEAR", "Linear Extrapolation", ""},
798         {0, NULL, NULL, NULL}
799 };
800
801 /* this function is responsible for setting extrapolation mode for keyframes */
802 static void setexpo_action_keys(bAnimContext *ac, short mode) 
803 {
804         ListBase anim_data = {NULL, NULL};
805         bAnimListElem *ale;
806         int filter;
807         
808         /* filter data */
809         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_CURVESONLY);
810         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
811         
812         /* loop through setting mode per F-Curve */
813         for (ale= anim_data.first; ale; ale= ale->next) {
814                 FCurve *fcu= (FCurve *)ale->data;
815                 fcu->extend= mode;
816         }
817         
818         /* cleanup */
819         BLI_freelistN(&anim_data);
820 }
821
822 /* ------------------- */
823
824 static int actkeys_expo_exec(bContext *C, wmOperator *op)
825 {
826         bAnimContext ac;
827         short mode;
828         
829         /* get editor data */
830         if (ANIM_animdata_get_context(C, &ac) == 0)
831                 return OPERATOR_CANCELLED;
832         if (ac.datatype == ANIMCONT_GPENCIL) 
833                 return OPERATOR_PASS_THROUGH;
834                 
835         /* get handle setting mode */
836         mode= RNA_enum_get(op->ptr, "type");
837         
838         /* set handle type */
839         setexpo_action_keys(&ac, mode);
840         
841         /* validate keyframes after editing */
842         ANIM_editkeyframes_refresh(&ac);
843         
844         /* set notifier tha things have changed */
845         ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_KEYFRAMES_VALUES);
846         
847         return OPERATOR_FINISHED;
848 }
849  
850 void ACT_OT_keyframes_extrapolation_type (wmOperatorType *ot)
851 {
852         /* identifiers */
853         ot->name= "Set Keyframe Extrapolation";
854         ot->idname= "ACT_OT_keyframes_extrapolation_type";
855         
856         /* api callbacks */
857         ot->invoke= WM_menu_invoke;
858         ot->exec= actkeys_expo_exec;
859         ot->poll= ED_operator_areaactive;
860         
861         /* flags */
862         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
863         
864         /* id-props */
865         RNA_def_enum(ot->srna, "type", prop_actkeys_expo_types, 0, "Type", "");
866 }
867
868 /* ******************** Set Interpolation-Type Operator *********************** */
869
870 /* defines for set ipo-type for selected keyframes tool */
871 EnumPropertyItem prop_actkeys_ipo_types[] = {
872         {BEZT_IPO_CONST, "CONSTANT", "Constant Interpolation", ""},
873         {BEZT_IPO_LIN, "LINEAR", "Linear Interpolation", ""},
874         {BEZT_IPO_BEZ, "BEZIER", "Bezier Interpolation", ""},
875         {0, NULL, NULL, NULL}
876 };
877
878 /* this function is responsible for setting interpolation mode for keyframes */
879 static void setipo_action_keys(bAnimContext *ac, short mode) 
880 {
881         ListBase anim_data = {NULL, NULL};
882         bAnimListElem *ale;
883         int filter;
884         BeztEditFunc set_cb= ANIM_editkeyframes_ipo(mode);
885         
886         /* filter data */
887         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_CURVESONLY);
888         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
889         
890         /* loop through setting BezTriple interpolation
891          * Note: we do not supply BeztEditData to the looper yet. Currently that's not necessary here...
892          */
893         for (ale= anim_data.first; ale; ale= ale->next)
894                 ANIM_fcurve_keys_bezier_loop(NULL, ale->key_data, NULL, set_cb, calchandles_fcurve);
895         
896         /* cleanup */
897         BLI_freelistN(&anim_data);
898 }
899
900 /* ------------------- */
901
902 static int actkeys_ipo_exec(bContext *C, wmOperator *op)
903 {
904         bAnimContext ac;
905         short mode;
906         
907         /* get editor data */
908         if (ANIM_animdata_get_context(C, &ac) == 0)
909                 return OPERATOR_CANCELLED;
910         if (ac.datatype == ANIMCONT_GPENCIL) 
911                 return OPERATOR_PASS_THROUGH;
912                 
913         /* get handle setting mode */
914         mode= RNA_enum_get(op->ptr, "type");
915         
916         /* set handle type */
917         setipo_action_keys(&ac, mode);
918         
919         /* validate keyframes after editing */
920         ANIM_editkeyframes_refresh(&ac);
921         
922         /* set notifier tha things have changed */
923         ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_KEYFRAMES_VALUES);
924         
925         return OPERATOR_FINISHED;
926 }
927  
928 void ACT_OT_keyframes_interpolation_type (wmOperatorType *ot)
929 {
930         /* identifiers */
931         ot->name= "Set Keyframe Interpolation";
932         ot->idname= "ACT_OT_keyframes_interpolation_type";
933         
934         /* api callbacks */
935         ot->invoke= WM_menu_invoke;
936         ot->exec= actkeys_ipo_exec;
937         ot->poll= ED_operator_areaactive;
938         
939         /* flags */
940         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
941         
942         /* id-props */
943         RNA_def_enum(ot->srna, "type", prop_actkeys_ipo_types, 0, "Type", "");
944 }
945
946 /* ******************** Set Handle-Type Operator *********************** */
947
948 /* defines for set handle-type for selected keyframes tool */
949 EnumPropertyItem prop_actkeys_handletype_types[] = {
950         {HD_AUTO, "AUTO", "Auto Handles", ""},
951         {HD_VECT, "VECTOR", "Vector Handles", ""},
952         {HD_FREE, "FREE", "Free Handles", ""},
953         {HD_ALIGN, "ALIGN", "Aligned Handles", ""},
954 //      {-1, "TOGGLE", "Toggle between Free and Aligned Handles", ""},
955         {0, NULL, NULL, NULL}
956 };
957
958 /* this function is responsible for setting handle-type of selected keyframes */
959 static void sethandles_action_keys(bAnimContext *ac, short mode) 
960 {
961         ListBase anim_data = {NULL, NULL};
962         bAnimListElem *ale;
963         int filter;
964         BeztEditFunc set_cb= ANIM_editkeyframes_handles(mode);
965         
966         /* filter data */
967         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_CURVESONLY);
968         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
969         
970         /* loop through setting flags for handles 
971          * Note: we do not supply BeztEditData to the looper yet. Currently that's not necessary here...
972          */
973         for (ale= anim_data.first; ale; ale= ale->next) {
974                 if (mode == -1) {       
975                         BeztEditFunc toggle_cb;
976                         
977                         /* check which type of handle to set (free or aligned) 
978                          *      - check here checks for handles with free alignment already
979                          */
980                         if (ANIM_fcurve_keys_bezier_loop(NULL, ale->key_data, NULL, set_cb, NULL))
981                                 toggle_cb= ANIM_editkeyframes_handles(HD_FREE);
982                         else
983                                 toggle_cb= ANIM_editkeyframes_handles(HD_ALIGN);
984                                 
985                         /* set handle-type */
986                         ANIM_fcurve_keys_bezier_loop(NULL, ale->key_data, NULL, toggle_cb, calchandles_fcurve);
987                 }
988                 else {
989                         /* directly set handle-type */
990                         ANIM_fcurve_keys_bezier_loop(NULL, ale->key_data, NULL, set_cb, calchandles_fcurve);
991                 }
992         }
993         
994         /* cleanup */
995         BLI_freelistN(&anim_data);
996 }
997
998 /* ------------------- */
999
1000 static int actkeys_handletype_exec(bContext *C, wmOperator *op)
1001 {
1002         bAnimContext ac;
1003         short mode;
1004         
1005         /* get editor data */
1006         if (ANIM_animdata_get_context(C, &ac) == 0)
1007                 return OPERATOR_CANCELLED;
1008         if (ac.datatype == ANIMCONT_GPENCIL) 
1009                 return OPERATOR_PASS_THROUGH;
1010                 
1011         /* get handle setting mode */
1012         mode= RNA_enum_get(op->ptr, "type");
1013         
1014         /* set handle type */
1015         sethandles_action_keys(&ac, mode);
1016         
1017         /* validate keyframes after editing */
1018         ANIM_editkeyframes_refresh(&ac);
1019         
1020         /* set notifier tha things have changed */
1021         ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_KEYFRAMES_VALUES);
1022         
1023         return OPERATOR_FINISHED;
1024 }
1025  
1026 void ACT_OT_keyframes_handletype (wmOperatorType *ot)
1027 {
1028         /* identifiers */
1029         ot->name= "Set Keyframe Handle Type";
1030         ot->idname= "ACT_OT_keyframes_handletype";
1031         
1032         /* api callbacks */
1033         ot->invoke= WM_menu_invoke;
1034         ot->exec= actkeys_handletype_exec;
1035         ot->poll= ED_operator_areaactive;
1036         
1037         /* flags */
1038         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1039         
1040         /* id-props */
1041         RNA_def_enum(ot->srna, "type", prop_actkeys_handletype_types, 0, "Type", "");
1042 }
1043
1044 /* ************************************************************************** */
1045 /* TRANSFORM STUFF */
1046
1047 /* ***************** Snap Current Frame Operator *********************** */
1048
1049 /* helper callback for actkeys_cfrasnap_exec() -> used to help get the average time of all selected beztriples */
1050 // TODO: if some other code somewhere needs this, it'll be time to port this over to keyframes_edit.c!!!
1051 static short bezt_calc_average(BeztEditData *bed, BezTriple *bezt)
1052 {
1053         /* only if selected */
1054         if (bezt->f2 & SELECT) {
1055                 /* store average time in float (only do rounding at last step */
1056                 bed->f1 += bezt->vec[1][0];
1057                 
1058                 /* increment number of items */
1059                 bed->i1++;
1060         }
1061         
1062         return 0;
1063 }
1064
1065 /* snap current-frame indicator to 'average time' of selected keyframe */
1066 static int actkeys_cfrasnap_exec(bContext *C, wmOperator *op)
1067 {
1068         bAnimContext ac;
1069         ListBase anim_data= {NULL, NULL};
1070         bAnimListElem *ale;
1071         int filter;
1072         BeztEditData bed;
1073         
1074         /* get editor data */
1075         if (ANIM_animdata_get_context(C, &ac) == 0)
1076                 return OPERATOR_CANCELLED;
1077         
1078         /* init edit data */
1079         memset(&bed, 0, sizeof(BeztEditData));
1080         
1081         /* loop over action data, averaging values */
1082         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVESONLY);
1083         ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
1084         
1085         for (ale= anim_data.first; ale; ale= ale->next)
1086                 ANIM_fcurve_keys_bezier_loop(&bed, ale->key_data, NULL, bezt_calc_average, NULL);
1087         
1088         BLI_freelistN(&anim_data);
1089         
1090         /* set the new current frame value, based on the average time */
1091         if (bed.i1) {
1092                 Scene *scene= ac.scene;
1093                 CFRA= (int)floor((bed.f1 / bed.i1) + 0.5f);
1094         }
1095         
1096         /* set notifier tha things have changed */
1097         WM_event_add_notifier(C, NC_SCENE|ND_FRAME, ac.scene);
1098         
1099         return OPERATOR_FINISHED;
1100 }
1101
1102 void ACT_OT_keyframes_cfrasnap (wmOperatorType *ot)
1103 {
1104         /* identifiers */
1105         ot->name= "Snap Current Frame to Keys";
1106         ot->idname= "ACT_OT_keyframes_cfrasnap";
1107         
1108         /* api callbacks */
1109         ot->exec= actkeys_cfrasnap_exec;
1110         ot->poll= ED_operator_areaactive;
1111         
1112         /* flags */
1113         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1114 }
1115
1116 /* ******************** Snap Keyframes Operator *********************** */
1117
1118 /* defines for snap keyframes tool */
1119 EnumPropertyItem prop_actkeys_snap_types[] = {
1120         {ACTKEYS_SNAP_CFRA, "CFRA", "Current frame", ""},
1121         {ACTKEYS_SNAP_NEAREST_FRAME, "NEAREST_FRAME", "Nearest Frame", ""}, // XXX as single entry?
1122         {ACTKEYS_SNAP_NEAREST_SECOND, "NEAREST_SECOND", "Nearest Second", ""}, // XXX as single entry?
1123         {ACTKEYS_SNAP_NEAREST_MARKER, "NEAREST_MARKER", "Nearest Marker", ""},
1124         {0, NULL, NULL, NULL}
1125 };
1126
1127 /* this function is responsible for snapping keyframes to frame-times */
1128 static void snap_action_keys(bAnimContext *ac, short mode) 
1129 {
1130         ListBase anim_data = {NULL, NULL};
1131         bAnimListElem *ale;
1132         int filter;
1133         
1134         BeztEditData bed;
1135         BeztEditFunc edit_cb;
1136         
1137         /* filter data */
1138         if (ac->datatype == ANIMCONT_GPENCIL)
1139                 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_FOREDIT);
1140         else
1141                 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_CURVESONLY);
1142         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
1143         
1144         /* get beztriple editing callbacks */
1145         edit_cb= ANIM_editkeyframes_snap(mode);
1146         
1147         memset(&bed, 0, sizeof(BeztEditData)); 
1148         bed.scene= ac->scene;
1149         
1150         /* snap keyframes */
1151         for (ale= anim_data.first; ale; ale= ale->next) {
1152                 Object *nob= ANIM_nla_mapping_get(ac, ale);
1153                 
1154                 if (nob) {
1155                         ANIM_nla_mapping_apply_fcurve(nob, ale->key_data, 0, 1); 
1156                         ANIM_fcurve_keys_bezier_loop(&bed, ale->key_data, NULL, edit_cb, calchandles_fcurve);
1157                         ANIM_nla_mapping_apply_fcurve(nob, ale->key_data, 1, 1);
1158                 }
1159                 //else if (ale->type == ACTTYPE_GPLAYER)
1160                 //      snap_gplayer_frames(ale->data, mode);
1161                 else 
1162                         ANIM_fcurve_keys_bezier_loop(&bed, ale->key_data, NULL, edit_cb, calchandles_fcurve);
1163         }
1164         BLI_freelistN(&anim_data);
1165 }
1166
1167 /* ------------------- */
1168
1169 static int actkeys_snap_exec(bContext *C, wmOperator *op)
1170 {
1171         bAnimContext ac;
1172         short mode;
1173         
1174         /* get editor data */
1175         if (ANIM_animdata_get_context(C, &ac) == 0)
1176                 return OPERATOR_CANCELLED;
1177                 
1178         /* get snapping mode */
1179         mode= RNA_enum_get(op->ptr, "type");
1180         
1181         /* snap keyframes */
1182         snap_action_keys(&ac, mode);
1183         
1184         /* validate keyframes after editing */
1185         ANIM_editkeyframes_refresh(&ac);
1186         
1187         /* set notifier tha things have changed */
1188         ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_KEYFRAMES_VALUES);
1189         
1190         return OPERATOR_FINISHED;
1191 }
1192  
1193 void ACT_OT_keyframes_snap (wmOperatorType *ot)
1194 {
1195         /* identifiers */
1196         ot->name= "Snap Keys";
1197         ot->idname= "ACT_OT_keyframes_snap";
1198         
1199         /* api callbacks */
1200         ot->invoke= WM_menu_invoke;
1201         ot->exec= actkeys_snap_exec;
1202         ot->poll= ED_operator_areaactive;
1203         
1204         /* flags */
1205         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1206         
1207         /* id-props */
1208         RNA_def_enum(ot->srna, "type", prop_actkeys_snap_types, 0, "Type", "");
1209 }
1210
1211 /* ******************** Mirror Keyframes Operator *********************** */
1212
1213 /* defines for mirror keyframes tool */
1214 EnumPropertyItem prop_actkeys_mirror_types[] = {
1215         {ACTKEYS_MIRROR_CFRA, "CFRA", "Current frame", ""},
1216         {ACTKEYS_MIRROR_YAXIS, "YAXIS", "Vertical Axis", ""},
1217         {ACTKEYS_MIRROR_XAXIS, "XAXIS", "Horizontal Axis", ""},
1218         {ACTKEYS_MIRROR_MARKER, "MARKER", "First Selected Marker", ""},
1219         {0, NULL, NULL, NULL}
1220 };
1221
1222 /* this function is responsible for mirroring keyframes */
1223 static void mirror_action_keys(bAnimContext *ac, short mode) 
1224 {
1225         ListBase anim_data = {NULL, NULL};
1226         bAnimListElem *ale;
1227         int filter;
1228         
1229         BeztEditData bed;
1230         BeztEditFunc edit_cb;
1231         
1232         /* get beztriple editing callbacks */
1233         edit_cb= ANIM_editkeyframes_mirror(mode);
1234         
1235         memset(&bed, 0, sizeof(BeztEditData)); 
1236         bed.scene= ac->scene;
1237         
1238         /* for 'first selected marker' mode, need to find first selected marker first! */
1239         // XXX should this be made into a helper func in the API?
1240         if (mode == ACTKEYS_MIRROR_MARKER) {
1241                 Scene *scene= ac->scene;
1242                 TimeMarker *marker= NULL;
1243                 
1244                 /* find first selected marker */
1245                 for (marker= scene->markers.first; marker; marker=marker->next) {
1246                         if (marker->flag & SELECT) {
1247                                 break;
1248                         }
1249                 }
1250                 
1251                 /* store marker's time (if available) */
1252                 if (marker)
1253                         bed.f1= (float)marker->frame;
1254                 else
1255                         return;
1256         }
1257         
1258         /* filter data */
1259         if (ac->datatype == ANIMCONT_GPENCIL)
1260                 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_FOREDIT);
1261         else
1262                 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_CURVESONLY);
1263         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
1264         
1265         /* mirror keyframes */
1266         for (ale= anim_data.first; ale; ale= ale->next) {
1267                 Object *nob= ANIM_nla_mapping_get(ac, ale);
1268                 
1269                 if (nob) {
1270                         ANIM_nla_mapping_apply_fcurve(nob, ale->key_data, 0, 1); 
1271                         ANIM_fcurve_keys_bezier_loop(&bed, ale->key_data, NULL, edit_cb, calchandles_fcurve);
1272                         ANIM_nla_mapping_apply_fcurve(nob, ale->key_data, 1, 1);
1273                 }
1274                 //else if (ale->type == ACTTYPE_GPLAYER)
1275                 //      snap_gplayer_frames(ale->data, mode);
1276                 else 
1277                         ANIM_fcurve_keys_bezier_loop(&bed, ale->key_data, NULL, edit_cb, calchandles_fcurve);
1278         }
1279         BLI_freelistN(&anim_data);
1280 }
1281
1282 /* ------------------- */
1283
1284 static int actkeys_mirror_exec(bContext *C, wmOperator *op)
1285 {
1286         bAnimContext ac;
1287         short mode;
1288         
1289         /* get editor data */
1290         if (ANIM_animdata_get_context(C, &ac) == 0)
1291                 return OPERATOR_CANCELLED;
1292                 
1293         /* get mirroring mode */
1294         mode= RNA_enum_get(op->ptr, "type");
1295         
1296         /* mirror keyframes */
1297         mirror_action_keys(&ac, mode);
1298         
1299         /* validate keyframes after editing */
1300         ANIM_editkeyframes_refresh(&ac);
1301         
1302         /* set notifier tha things have changed */
1303         ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_KEYFRAMES_VALUES);
1304         
1305         return OPERATOR_FINISHED;
1306 }
1307  
1308 void ACT_OT_keyframes_mirror (wmOperatorType *ot)
1309 {
1310         /* identifiers */
1311         ot->name= "Mirror Keys";
1312         ot->idname= "ACT_OT_keyframes_mirror";
1313         
1314         /* api callbacks */
1315         ot->invoke= WM_menu_invoke;
1316         ot->exec= actkeys_mirror_exec;
1317         ot->poll= ED_operator_areaactive;
1318         
1319         /* flags */
1320         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1321         
1322         /* id-props */
1323         RNA_def_enum(ot->srna, "type", prop_actkeys_mirror_types, 0, "Type", "");
1324 }
1325
1326 /* ************************************************************************** */