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