2.5 - Action Editor / Animation Stuff:
[blender-staging.git] / source / blender / editors / space_action / action_edit_keyframes.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_listBase.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_ipo_types.h"
50 #include "DNA_object_types.h"
51 #include "DNA_screen_types.h"
52 #include "DNA_scene_types.h"
53 #include "DNA_space_types.h"
54 #include "DNA_constraint_types.h"
55 #include "DNA_key_types.h"
56 #include "DNA_lamp_types.h"
57 #include "DNA_material_types.h"
58 #include "DNA_userdef_types.h"
59 #include "DNA_gpencil_types.h"
60 #include "DNA_windowmanager_types.h"
61
62 #include "RNA_access.h"
63 #include "RNA_define.h"
64
65 #include "BKE_action.h"
66 #include "BKE_depsgraph.h"
67 #include "BKE_ipo.h"
68 #include "BKE_key.h"
69 #include "BKE_material.h"
70 #include "BKE_object.h"
71 #include "BKE_context.h"
72 #include "BKE_utildefines.h"
73
74 #include "UI_view2d.h"
75
76 #include "ED_anim_api.h"
77 #include "ED_keyframing.h"
78 #include "ED_keyframes_draw.h"
79 #include "ED_keyframes_edit.h"
80 #include "ED_screen.h"
81 #include "ED_space_api.h"
82
83 #include "WM_api.h"
84 #include "WM_types.h"
85
86 #include "action_intern.h"
87
88 /* ************************************************************************** */
89 /* GENERAL STUFF */
90
91 // TODO:
92 //      - delete
93 //      - insert key
94 //      - copy/paste
95
96 /* ******************** Delete Keyframes Operator ************************* */
97
98 static void delete_action_keys (bAnimContext *ac)
99 {
100         ListBase anim_data = {NULL, NULL};
101         bAnimListElem *ale;
102         int filter;
103         
104         /* filter data */
105         if (ac->datatype == ANIMCONT_GPENCIL)
106                 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_FOREDIT);
107         else
108                 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_IPOKEYS);
109         ANIM_animdata_filter(&anim_data, filter, ac->data, ac->datatype);
110         
111         /* loop through filtered data and delete selected keys */
112         for (ale= anim_data.first; ale; ale= ale->next) {
113                 //if (ale->type == ANIMTYPE_GPLAYER)
114                 //      delete_gplayer_frames((bGPDlayer *)ale->data);
115                 //else
116                         delete_ipo_keys((Ipo *)ale->key_data);
117         }
118         
119         /* free filtered list */
120         BLI_freelistN(&anim_data);
121 }
122
123 /* ------------------- */
124
125 static int actkeys_delete_exec(bContext *C, wmOperator *op)
126 {
127         bAnimContext ac;
128         
129         /* get editor data */
130         if (ANIM_animdata_get_context(C, &ac) == 0)
131                 return OPERATOR_CANCELLED;
132                 
133         /* delete keyframes */
134         delete_action_keys(&ac);
135         
136         /* validate keyframes after editing */
137         ANIM_editkeyframes_refresh(&ac);
138         
139         /* set notifier tha things have changed */
140         ED_area_tag_redraw(CTX_wm_area(C)); // FIXME... should be updating 'keyframes' data context or so instead!
141         
142         return OPERATOR_FINISHED;
143 }
144  
145 void ACT_OT_keyframes_delete (wmOperatorType *ot)
146 {
147         /* identifiers */
148         ot->name= "Delete Keyframes";
149         ot->idname= "ACT_OT_keyframes_delete";
150         
151         /* api callbacks */
152         ot->exec= actkeys_delete_exec;
153         ot->poll= ED_operator_areaactive;
154         
155         /* flags */
156         ot->flag= OPTYPE_REGISTER/*|OPTYPE_UNDO*/;
157 }
158
159 /* ******************** Clean Keyframes Operator ************************* */
160
161 static void clean_action_keys (bAnimContext *ac, float thresh)
162 {       
163         ListBase anim_data = {NULL, NULL};
164         bAnimListElem *ale;
165         int filter;
166         
167         /* filter data */
168         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_SEL | ANIMFILTER_ONLYICU);
169         ANIM_animdata_filter(&anim_data, filter, ac->data, ac->datatype);
170         
171         /* loop through filtered data and clean curves */
172         for (ale= anim_data.first; ale; ale= ale->next)
173                 clean_ipo_curve((IpoCurve *)ale->key_data, thresh);
174         
175         /* free temp data */
176         BLI_freelistN(&anim_data);
177 }
178
179 /* ------------------- */
180
181 static int actkeys_clean_exec(bContext *C, wmOperator *op)
182 {
183         bAnimContext ac;
184         float thresh;
185         
186         /* get editor data */
187         if (ANIM_animdata_get_context(C, &ac) == 0)
188                 return OPERATOR_CANCELLED;
189         if (ac.datatype == ANIMCONT_GPENCIL)
190                 return OPERATOR_PASS_THROUGH;
191                 
192         /* get cleaning threshold */
193         thresh= RNA_float_get(op->ptr, "threshold");
194         
195         /* clean keyframes */
196         clean_action_keys(&ac, thresh);
197         
198         /* validate keyframes after editing */
199         ANIM_editkeyframes_refresh(&ac);
200         
201         /* set notifier tha things have changed */
202         ED_area_tag_redraw(CTX_wm_area(C)); // FIXME... should be updating 'keyframes' data context or so instead!
203         
204         return OPERATOR_FINISHED;
205 }
206  
207 void ACT_OT_keyframes_clean (wmOperatorType *ot)
208 {
209         PropertyRNA *prop;
210         
211         /* identifiers */
212         ot->name= "Clean Keyframes";
213         ot->idname= "ACT_OT_keyframes_clean";
214         
215         /* api callbacks */
216         //ot->invoke=  // XXX we need that number popup for this! 
217         ot->exec= actkeys_clean_exec;
218         ot->poll= ED_operator_areaactive;
219         
220         /* flags */
221         ot->flag= OPTYPE_REGISTER/*|OPTYPE_UNDO*/;
222         
223         /* properties */
224         prop= RNA_def_property(ot->srna, "threshold", PROP_FLOAT, PROP_NONE);
225         RNA_def_property_float_default(prop, 0.001f);
226 }
227
228 /* ******************** Sample Keyframes Operator *********************** */
229
230 /* little cache for values... */
231 typedef struct tempFrameValCache {
232         float frame, val;
233 } tempFrameValCache;
234
235 /* Evaluates the curves between each selected keyframe on each frame, and keys the value  */
236 static void sample_action_keys (bAnimContext *ac)
237 {       
238         ListBase anim_data = {NULL, NULL};
239         bAnimListElem *ale;
240         int filter;
241         
242         /* filter data */
243         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_ONLYICU);
244         ANIM_animdata_filter(&anim_data, filter, ac->data, ac->datatype);
245         
246         /* loop through filtered data and add keys between selected keyframes on every frame  */
247         for (ale= anim_data.first; ale; ale= ale->next) {
248                 IpoCurve *icu= (IpoCurve *)ale->key_data;
249                 BezTriple *bezt, *start=NULL, *end=NULL;
250                 tempFrameValCache *value_cache, *fp;
251                 int sfra, range;
252                 int i, n;
253                 
254                 /* find selected keyframes... once pair has been found, add keyframes  */
255                 for (i=0, bezt=icu->bezt; i < icu->totvert; i++, bezt++) {
256                         /* check if selected, and which end this is */
257                         if (BEZSELECTED(bezt)) {
258                                 if (start) {
259                                         /* set end */
260                                         end= bezt;
261                                         
262                                         /* cache values then add keyframes using these values, as adding
263                                          * keyframes while sampling will affect the outcome...
264                                          */
265                                         range= (int)( ceil(end->vec[1][0] - start->vec[1][0]) );
266                                         sfra= (int)( floor(start->vec[1][0]) );
267                                         
268                                         if (range) {
269                                                 value_cache= MEM_callocN(sizeof(tempFrameValCache)*range, "IcuFrameValCache");
270                                                 
271                                                 /*      sample values   */
272                                                 for (n=0, fp=value_cache; n<range && fp; n++, fp++) {
273                                                         fp->frame= (float)(sfra + n);
274                                                         fp->val= eval_icu(icu, fp->frame);
275                                                 }
276                                                 
277                                                 /*      add keyframes with these        */
278                                                 for (n=0, fp=value_cache; n<range && fp; n++, fp++) {
279                                                         insert_vert_icu(icu, fp->frame, fp->val, 1);
280                                                 }
281                                                 
282                                                 /* free temp cache */
283                                                 MEM_freeN(value_cache);
284                                                 
285                                                 /* as we added keyframes, we need to compensate so that bezt is at the right place */
286                                                 bezt = icu->bezt + i + range - 1;
287                                                 i += (range - 1);
288                                         }
289                                         
290                                         /* bezt was selected, so it now marks the start of a whole new chain to search */
291                                         start= bezt;
292                                         end= NULL;
293                                 }
294                                 else {
295                                         /* just set start keyframe */
296                                         start= bezt;
297                                         end= NULL;
298                                 }
299                         }
300                 }
301                 
302                 /* recalculate channel's handles? */
303                 calchandles_ipocurve(icu);
304         }
305         
306         /* admin and redraws */
307         BLI_freelistN(&anim_data);
308 }
309
310 /* ------------------- */
311
312 static int actkeys_sample_exec(bContext *C, wmOperator *op)
313 {
314         bAnimContext ac;
315         
316         /* get editor data */
317         if (ANIM_animdata_get_context(C, &ac) == 0)
318                 return OPERATOR_CANCELLED;
319         if (ac.datatype == ANIMCONT_GPENCIL)
320                 return OPERATOR_PASS_THROUGH;
321         
322         /* sample keyframes */
323         sample_action_keys(&ac);
324         
325         /* validate keyframes after editing */
326         ANIM_editkeyframes_refresh(&ac);
327         
328         /* set notifier tha things have changed */
329         ED_area_tag_redraw(CTX_wm_area(C)); // FIXME... should be updating 'keyframes' data context or so instead!
330         
331         return OPERATOR_FINISHED;
332 }
333  
334 void ACT_OT_keyframes_sample (wmOperatorType *ot)
335 {
336         /* identifiers */
337         ot->name= "Sample Keyframes";
338         ot->idname= "ACT_OT_keyframes_sample";
339         
340         /* api callbacks */
341         ot->exec= actkeys_sample_exec;
342         ot->poll= ED_operator_areaactive;
343         
344         /* flags */
345         ot->flag= OPTYPE_REGISTER/*|OPTYPE_UNDO*/;
346 }
347
348 /* ************************************************************************** */
349 /* SETTINGS STUFF */
350
351 /* ******************** Set Extrapolation-Type Operator *********************** */
352
353 /* defines for set ipo-type for selected keyframes tool */
354 EnumPropertyItem prop_actkeys_expo_types[] = {
355         {IPO_HORIZ, "CONSTANT", "Constant", ""},
356         {IPO_DIR, "DIRECTIONAL", "Extrapolation", ""},
357         {IPO_CYCL, "CYCLIC", "Cyclic", ""},
358         {IPO_CYCLX, "CYCLIC_EXTRAPOLATION", "Cyclic Extrapolation", ""},
359         {0, NULL, NULL, NULL}
360 };
361
362 /* this function is responsible for setting extrapolation mode for keyframes */
363 static void setexpo_action_keys(bAnimContext *ac, short mode) 
364 {
365         ListBase anim_data = {NULL, NULL};
366         bAnimListElem *ale;
367         int filter;
368         
369         /* filter data */
370         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_IPOKEYS);
371         ANIM_animdata_filter(&anim_data, filter, ac->data, ac->datatype);
372         
373         /* loop through setting mode per ipo-curve */
374         for (ale= anim_data.first; ale; ale= ale->next)
375                 setexprap_ipoloop(ale->key_data, mode);
376         
377         /* cleanup */
378         BLI_freelistN(&anim_data);
379 }
380
381 /* ------------------- */
382
383 static int actkeys_expo_exec(bContext *C, wmOperator *op)
384 {
385         bAnimContext ac;
386         short mode;
387         
388         /* get editor data */
389         if (ANIM_animdata_get_context(C, &ac) == 0)
390                 return OPERATOR_CANCELLED;
391         if (ac.datatype == ANIMCONT_GPENCIL) 
392                 return OPERATOR_PASS_THROUGH;
393                 
394         /* get handle setting mode */
395         mode= RNA_enum_get(op->ptr, "type");
396         
397         /* set handle type */
398         setexpo_action_keys(&ac, mode);
399         
400         /* validate keyframes after editing */
401         ANIM_editkeyframes_refresh(&ac);
402         
403         /* set notifier tha things have changed */
404         ED_area_tag_redraw(CTX_wm_area(C)); // FIXME... should be updating 'keyframes' data context or so instead!
405         
406         return OPERATOR_FINISHED;
407 }
408  
409 void ACT_OT_keyframes_expotype (wmOperatorType *ot)
410 {
411         PropertyRNA *prop;
412         
413         /* identifiers */
414         ot->name= "Set Keyframe Extrapolation";
415         ot->idname= "ACT_OT_keyframes_expotype";
416         
417         /* api callbacks */
418         ot->invoke= WM_menu_invoke;
419         ot->exec= actkeys_expo_exec;
420         ot->poll= ED_operator_areaactive;
421         
422         /* flags */
423         ot->flag= OPTYPE_REGISTER/*|OPTYPE_UNDO*/;
424         
425         /* id-props */
426         prop= RNA_def_property(ot->srna, "type", PROP_ENUM, PROP_NONE);
427         RNA_def_property_enum_items(prop, prop_actkeys_expo_types);
428 }
429
430 /* ******************** Set Interpolation-Type Operator *********************** */
431
432 /* defines for set ipo-type for selected keyframes tool */
433 EnumPropertyItem prop_actkeys_ipo_types[] = {
434         {IPO_CONST, "CONSTANT", "Constant Interpolation", ""},
435         {IPO_LIN, "LINEAR", "Linear Interpolation", ""},
436         {IPO_BEZ, "BEZIER", "Bezier Interpolation", ""},
437         {0, NULL, NULL, NULL}
438 };
439
440 /* this function is responsible for setting interpolation mode for keyframes */
441 static void setipo_action_keys(bAnimContext *ac, short mode) 
442 {
443         ListBase anim_data = {NULL, NULL};
444         bAnimListElem *ale;
445         int filter;
446         BeztEditFunc set_cb= ANIM_editkeyframes_ipo(mode);
447         
448         /* filter data */
449         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_IPOKEYS);
450         ANIM_animdata_filter(&anim_data, filter, ac->data, ac->datatype);
451         
452         /* loop through setting BezTriple interpolation
453          * Note: we do not supply BeztEditData to the looper yet. Currently that's not necessary here...
454          */
455         for (ale= anim_data.first; ale; ale= ale->next)
456                 ipo_keys_bezier_loop(NULL, ale->key_data, NULL, set_cb, ANIM_editkeyframes_ipocurve_ipotype);
457         
458         /* cleanup */
459         BLI_freelistN(&anim_data);
460 }
461
462 /* ------------------- */
463
464 static int actkeys_ipo_exec(bContext *C, wmOperator *op)
465 {
466         bAnimContext ac;
467         short mode;
468         
469         /* get editor data */
470         if (ANIM_animdata_get_context(C, &ac) == 0)
471                 return OPERATOR_CANCELLED;
472         if (ac.datatype == ANIMCONT_GPENCIL) 
473                 return OPERATOR_PASS_THROUGH;
474                 
475         /* get handle setting mode */
476         mode= RNA_enum_get(op->ptr, "type");
477         
478         /* set handle type */
479         setipo_action_keys(&ac, mode);
480         
481         /* validate keyframes after editing */
482         ANIM_editkeyframes_refresh(&ac);
483         
484         /* set notifier tha things have changed */
485         ED_area_tag_redraw(CTX_wm_area(C)); // FIXME... should be updating 'keyframes' data context or so instead!
486         
487         return OPERATOR_FINISHED;
488 }
489  
490 void ACT_OT_keyframes_ipotype (wmOperatorType *ot)
491 {
492         PropertyRNA *prop;
493         
494         /* identifiers */
495         ot->name= "Set Keyframe Interpolation";
496         ot->idname= "ACT_OT_keyframes_ipotype";
497         
498         /* api callbacks */
499         ot->invoke= WM_menu_invoke;
500         ot->exec= actkeys_ipo_exec;
501         ot->poll= ED_operator_areaactive;
502         
503         /* flags */
504         ot->flag= OPTYPE_REGISTER/*|OPTYPE_UNDO*/;
505         
506         /* id-props */
507         prop= RNA_def_property(ot->srna, "type", PROP_ENUM, PROP_NONE);
508         RNA_def_property_enum_items(prop, prop_actkeys_ipo_types);
509 }
510
511 /* ******************** Set Handle-Type Operator *********************** */
512
513 /* defines for set handle-type for selected keyframes tool */
514 EnumPropertyItem prop_actkeys_handletype_types[] = {
515         {HD_AUTO, "AUTO", "Auto Handles", ""},
516         {HD_VECT, "VECTOR", "Vector Handles", ""},
517         {HD_FREE, "FREE", "Free Handles", ""},
518         {HD_ALIGN, "ALIGN", "Aligned Handles", ""},
519 //      {-1, "TOGGLE", "Toggle between Free and Aligned Handles", ""},
520         {0, NULL, NULL, NULL}
521 };
522
523 /* this function is responsible for setting handle-type of selected keyframes */
524 static void sethandles_action_keys(bAnimContext *ac, short mode) 
525 {
526         ListBase anim_data = {NULL, NULL};
527         bAnimListElem *ale;
528         int filter;
529         BeztEditFunc set_cb= ANIM_editkeyframes_handles(mode);
530         
531         /* filter data */
532         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_IPOKEYS);
533         ANIM_animdata_filter(&anim_data, filter, ac->data, ac->datatype);
534         
535         /* loop through setting flags for handles 
536          * Note: we do not supply BeztEditData to the looper yet. Currently that's not necessary here...
537          */
538         for (ale= anim_data.first; ale; ale= ale->next) {
539                 if (mode == -1) {       
540                         BeztEditFunc toggle_cb;
541                         
542                         /* check which type of handle to set (free or aligned) 
543                          *      - check here checks for handles with free alignment already
544                          */
545                         if (ipo_keys_bezier_loop(NULL, ale->key_data, NULL, set_cb, NULL))
546                                 toggle_cb= ANIM_editkeyframes_handles(HD_FREE);
547                         else
548                                 toggle_cb= ANIM_editkeyframes_handles(HD_ALIGN);
549                                 
550                         /* set handle-type */
551                         ipo_keys_bezier_loop(NULL, ale->key_data, NULL, toggle_cb, calchandles_ipocurve);
552                 }
553                 else {
554                         /* directly set handle-type */
555                         ipo_keys_bezier_loop(NULL, ale->key_data, NULL, set_cb, calchandles_ipocurve);
556                 }
557         }
558         
559         /* cleanup */
560         BLI_freelistN(&anim_data);
561 }
562
563 /* ------------------- */
564
565 static int actkeys_handletype_exec(bContext *C, wmOperator *op)
566 {
567         bAnimContext ac;
568         short mode;
569         
570         /* get editor data */
571         if (ANIM_animdata_get_context(C, &ac) == 0)
572                 return OPERATOR_CANCELLED;
573         if (ac.datatype == ANIMCONT_GPENCIL) 
574                 return OPERATOR_PASS_THROUGH;
575                 
576         /* get handle setting mode */
577         mode= RNA_enum_get(op->ptr, "type");
578         
579         /* set handle type */
580         sethandles_action_keys(&ac, mode);
581         
582         /* validate keyframes after editing */
583         ANIM_editkeyframes_refresh(&ac);
584         
585         /* set notifier tha things have changed */
586         ED_area_tag_redraw(CTX_wm_area(C)); // FIXME... should be updating 'keyframes' data context or so instead!
587         
588         return OPERATOR_FINISHED;
589 }
590  
591 void ACT_OT_keyframes_handletype (wmOperatorType *ot)
592 {
593         PropertyRNA *prop;
594         
595         /* identifiers */
596         ot->name= "Set Keyframe Handle Type";
597         ot->idname= "ACT_OT_keyframes_handletype";
598         
599         /* api callbacks */
600         ot->invoke= WM_menu_invoke;
601         ot->exec= actkeys_handletype_exec;
602         ot->poll= ED_operator_areaactive;
603         
604         /* flags */
605         ot->flag= OPTYPE_REGISTER/*|OPTYPE_UNDO*/;
606         
607         /* id-props */
608         prop= RNA_def_property(ot->srna, "type", PROP_ENUM, PROP_NONE);
609         RNA_def_property_enum_items(prop, prop_actkeys_handletype_types);
610 }
611
612 /* ************************************************************************** */
613 /* TRANSFORM STUFF */
614
615 /* ***************** Snap Current Frame Operator *********************** */
616
617 /* helper callback for actkeys_cfrasnap_exec() -> used to help get the average time of all selected beztriples */
618 // TODO: if some other code somewhere needs this, it'll be time to port this over to keyframes_edit.c!!!
619 static short bezt_calc_average(BeztEditData *bed, BezTriple *bezt)
620 {
621         /* only if selected */
622         if (bezt->f2 & SELECT) {
623                 /* store average time in float (only do rounding at last step */
624                 bed->f1 += bezt->vec[1][0];
625                 
626                 /* increment number of items */
627                 bed->i1++;
628         }
629         
630         return 0;
631 }
632
633 /* snap current-frame indicator to 'average time' of selected keyframe */
634 static int actkeys_cfrasnap_exec(bContext *C, wmOperator *op)
635 {
636         bAnimContext ac;
637         ListBase anim_data= {NULL, NULL};
638         bAnimListElem *ale;
639         int filter;
640         BeztEditData bed;
641         
642         /* get editor data */
643         if (ANIM_animdata_get_context(C, &ac) == 0)
644                 return OPERATOR_CANCELLED;
645         
646         /* init edit data */
647         memset(&bed, 0, sizeof(BeztEditData));
648         
649         /* loop over action data, averaging values */
650         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_IPOKEYS);
651         ANIM_animdata_filter(&anim_data, filter, ac.data, ac.datatype);
652         
653         for (ale= anim_data.first; ale; ale= ale->next)
654                 ipo_keys_bezier_loop(&bed, ale->key_data, NULL, bezt_calc_average, NULL);
655         
656         BLI_freelistN(&anim_data);
657         
658         /* set the new current frame value, based on the average time */
659         if (bed.i1) {
660                 Scene *scene= ac.scene;
661                 CFRA= (int)floor((bed.f1 / bed.i1) + 0.5f);
662         }
663         
664         /* set notifier tha things have changed */
665         WM_event_add_notifier(C, NC_SCENE|ND_FRAME, ac.scene);
666         
667         return OPERATOR_FINISHED;
668 }
669
670 void ACT_OT_keyframes_cfrasnap (wmOperatorType *ot)
671 {
672         /* identifiers */
673         ot->name= "Snap Current Frame to Keys";
674         ot->idname= "ACT_OT_keyframes_cfrasnap";
675         
676         /* api callbacks */
677         ot->exec= actkeys_cfrasnap_exec;
678         ot->poll= ED_operator_areaactive;
679         
680         /* flags */
681         ot->flag= OPTYPE_REGISTER/*|OPTYPE_UNDO*/;
682 }
683
684 /* ******************** Snap Keyframes Operator *********************** */
685
686 /* defines for snap keyframes tool */
687 EnumPropertyItem prop_actkeys_snap_types[] = {
688         {ACTKEYS_SNAP_CFRA, "CFRA", "Current frame", ""},
689         {ACTKEYS_SNAP_NEAREST_FRAME, "NEAREST_FRAME", "Nearest Frame", ""}, // XXX as single entry?
690         {ACTKEYS_SNAP_NEAREST_SECOND, "NEAREST_SECOND", "Nearest Second", ""}, // XXX as single entry?
691         {ACTKEYS_SNAP_NEAREST_MARKER, "NEAREST_MARKER", "Nearest Marker", ""},
692         {0, NULL, NULL, NULL}
693 };
694
695 /* this function is responsible for snapping keyframes to frame-times */
696 static void snap_action_keys(bAnimContext *ac, short mode) 
697 {
698         ListBase anim_data = {NULL, NULL};
699         bAnimListElem *ale;
700         int filter;
701         
702         BeztEditData bed;
703         BeztEditFunc edit_cb;
704         
705         /* filter data */
706         if (ac->datatype == ANIMCONT_GPENCIL)
707                 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_FOREDIT);
708         else
709                 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_IPOKEYS);
710         ANIM_animdata_filter(&anim_data, filter, ac->data, ac->datatype);
711         
712         /* get beztriple editing callbacks */
713         edit_cb= ANIM_editkeyframes_snap(mode);
714         
715         memset(&bed, 0, sizeof(BeztEditData)); 
716         bed.scene= ac->scene;
717         
718         /* snap keyframes */
719         for (ale= anim_data.first; ale; ale= ale->next) {
720                 Object *nob= ANIM_nla_mapping_get(ac, ale);
721                 
722                 if (nob) {
723                         ANIM_nla_mapping_apply(nob, ale->key_data, 0, 1); 
724                         ipo_keys_bezier_loop(&bed, ale->key_data, NULL, edit_cb, calchandles_ipocurve);
725                         ANIM_nla_mapping_apply(nob, ale->key_data, 1, 1);
726                 }
727                 //else if (ale->type == ACTTYPE_GPLAYER)
728                 //      snap_gplayer_frames(ale->data, mode);
729                 else 
730                         ipo_keys_bezier_loop(&bed, ale->key_data, NULL, edit_cb, calchandles_ipocurve);
731         }
732         BLI_freelistN(&anim_data);
733 }
734
735 /* ------------------- */
736
737 static int actkeys_snap_exec(bContext *C, wmOperator *op)
738 {
739         bAnimContext ac;
740         short mode;
741         
742         /* get editor data */
743         if (ANIM_animdata_get_context(C, &ac) == 0)
744                 return OPERATOR_CANCELLED;
745                 
746         /* get snapping mode */
747         mode= RNA_enum_get(op->ptr, "type");
748         
749         /* snap keyframes */
750         snap_action_keys(&ac, mode);
751         
752         /* validate keyframes after editing */
753         ANIM_editkeyframes_refresh(&ac);
754         
755         /* set notifier tha things have changed */
756         ED_area_tag_redraw(CTX_wm_area(C)); // FIXME... should be updating 'keyframes' data context or so instead!
757         
758         return OPERATOR_FINISHED;
759 }
760  
761 void ACT_OT_keyframes_snap (wmOperatorType *ot)
762 {
763         PropertyRNA *prop;
764         
765         /* identifiers */
766         ot->name= "Snap Keys";
767         ot->idname= "ACT_OT_keyframes_snap";
768         
769         /* api callbacks */
770         ot->invoke= WM_menu_invoke;
771         ot->exec= actkeys_snap_exec;
772         ot->poll= ED_operator_areaactive;
773         
774         /* flags */
775         ot->flag= OPTYPE_REGISTER/*|OPTYPE_UNDO*/;
776         
777         /* id-props */
778         prop= RNA_def_property(ot->srna, "type", PROP_ENUM, PROP_NONE);
779         RNA_def_property_enum_items(prop, prop_actkeys_snap_types);
780 }
781
782 /* ******************** Mirror Keyframes Operator *********************** */
783
784 /* defines for mirror keyframes tool */
785 EnumPropertyItem prop_actkeys_mirror_types[] = {
786         {ACTKEYS_MIRROR_CFRA, "CFRA", "Current frame", ""},
787         {ACTKEYS_MIRROR_YAXIS, "YAXIS", "Vertical Axis", ""},
788         {ACTKEYS_MIRROR_XAXIS, "XAXIS", "Horizontal Axis", ""},
789         {ACTKEYS_MIRROR_MARKER, "MARKER", "First Selected Marker", ""},
790         {0, NULL, NULL, NULL}
791 };
792
793 /* this function is responsible for mirroring keyframes */
794 static void mirror_action_keys(bAnimContext *ac, short mode) 
795 {
796         ListBase anim_data = {NULL, NULL};
797         bAnimListElem *ale;
798         int filter;
799         
800         BeztEditData bed;
801         BeztEditFunc edit_cb;
802         
803         /* get beztriple editing callbacks */
804         edit_cb= ANIM_editkeyframes_mirror(mode);
805         
806         memset(&bed, 0, sizeof(BeztEditData)); 
807         bed.scene= ac->scene;
808         
809         /* for 'first selected marker' mode, need to find first selected marker first! */
810         // XXX should this be made into a helper func in the API?
811         if (mode == ACTKEYS_MIRROR_MARKER) {
812                 Scene *scene= ac->scene;
813                 TimeMarker *marker= NULL;
814                 
815                 /* find first selected marker */
816                 for (marker= scene->markers.first; marker; marker=marker->next) {
817                         if (marker->flag & SELECT) {
818                                 break;
819                         }
820                 }
821                 
822                 /* store marker's time (if available) */
823                 if (marker)
824                         bed.f1= marker->frame;
825                 else
826                         return;
827         }
828         
829         /* filter data */
830         if (ac->datatype == ANIMCONT_GPENCIL)
831                 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_FOREDIT);
832         else
833                 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_IPOKEYS);
834         ANIM_animdata_filter(&anim_data, filter, ac->data, ac->datatype);
835         
836         /* mirror keyframes */
837         for (ale= anim_data.first; ale; ale= ale->next) {
838                 Object *nob= ANIM_nla_mapping_get(ac, ale);
839                 
840                 if (nob) {
841                         ANIM_nla_mapping_apply(nob, ale->key_data, 0, 1); 
842                         ipo_keys_bezier_loop(&bed, ale->key_data, NULL, edit_cb, calchandles_ipocurve);
843                         ANIM_nla_mapping_apply(nob, ale->key_data, 1, 1);
844                 }
845                 //else if (ale->type == ACTTYPE_GPLAYER)
846                 //      snap_gplayer_frames(ale->data, mode);
847                 else 
848                         ipo_keys_bezier_loop(&bed, ale->key_data, NULL, edit_cb, calchandles_ipocurve);
849         }
850         BLI_freelistN(&anim_data);
851 }
852
853 /* ------------------- */
854
855 static int actkeys_mirror_exec(bContext *C, wmOperator *op)
856 {
857         bAnimContext ac;
858         short mode;
859         
860         /* get editor data */
861         if (ANIM_animdata_get_context(C, &ac) == 0)
862                 return OPERATOR_CANCELLED;
863                 
864         /* get mirroring mode */
865         mode= RNA_enum_get(op->ptr, "type");
866         
867         /* mirror keyframes */
868         mirror_action_keys(&ac, mode);
869         
870         /* validate keyframes after editing */
871         ANIM_editkeyframes_refresh(&ac);
872         
873         /* set notifier tha things have changed */
874         ED_area_tag_redraw(CTX_wm_area(C)); // FIXME... should be updating 'keyframes' data context or so instead!
875         
876         return OPERATOR_FINISHED;
877 }
878  
879 void ACT_OT_keyframes_mirror (wmOperatorType *ot)
880 {
881         PropertyRNA *prop;
882         
883         /* identifiers */
884         ot->name= "Mirror Keys";
885         ot->idname= "ACT_OT_keyframes_mirror";
886         
887         /* api callbacks */
888         ot->invoke= WM_menu_invoke;
889         ot->exec= actkeys_mirror_exec;
890         ot->poll= ED_operator_areaactive;
891         
892         /* flags */
893         ot->flag= OPTYPE_REGISTER/*|OPTYPE_UNDO*/;
894         
895         /* id-props */
896         prop= RNA_def_property(ot->srna, "type", PROP_ENUM, PROP_NONE);
897         RNA_def_property_enum_items(prop, prop_actkeys_mirror_types);
898 }
899
900 /* ************************************************************************** */