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