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