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