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