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