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