2 * $Id: editaction.c 17746 2008-12-08 11:19:44Z aligorith $
4 * ***** BEGIN GPL LICENSE BLOCK *****
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.
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.
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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
21 * All rights reserved.
23 * The Original Code is: all of this file.
25 * Contributor(s): Joshua Leung
27 * ***** END GPL LICENSE BLOCK *****
39 #include "MEM_guardedalloc.h"
41 #include "BLI_blenlib.h"
42 #include "BLI_arithb.h"
44 #include "DNA_listBase.h"
45 #include "DNA_action_types.h"
46 #include "DNA_armature_types.h"
47 #include "DNA_camera_types.h"
48 #include "DNA_curve_types.h"
49 #include "DNA_ipo_types.h"
50 #include "DNA_object_types.h"
51 #include "DNA_screen_types.h"
52 #include "DNA_scene_types.h"
53 #include "DNA_space_types.h"
54 #include "DNA_constraint_types.h"
55 #include "DNA_key_types.h"
56 #include "DNA_lamp_types.h"
57 #include "DNA_material_types.h"
58 #include "DNA_userdef_types.h"
59 #include "DNA_gpencil_types.h"
60 #include "DNA_windowmanager_types.h"
62 #include "RNA_access.h"
63 #include "RNA_define.h"
65 #include "BKE_action.h"
66 #include "BKE_depsgraph.h"
69 #include "BKE_material.h"
70 #include "BKE_object.h"
71 #include "BKE_context.h"
72 #include "BKE_utildefines.h"
74 #include "UI_view2d.h"
76 #include "ED_anim_api.h"
77 #include "ED_keyframing.h"
78 #include "ED_keyframes_draw.h"
79 #include "ED_keyframes_edit.h"
80 #include "ED_screen.h"
81 #include "ED_space_api.h"
86 #include "action_intern.h"
88 /* ************************************************************************** */
96 /* ******************** Delete Keyframes Operator ************************* */
98 static void delete_action_keys (bAnimContext *ac)
100 ListBase anim_data = {NULL, NULL};
105 if (ac->datatype == ANIMCONT_GPENCIL)
106 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_FOREDIT);
108 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_IPOKEYS);
109 ANIM_animdata_filter(&anim_data, filter, ac->data, ac->datatype);
111 /* loop through filtered data and delete selected keys */
112 for (ale= anim_data.first; ale; ale= ale->next) {
113 //if (ale->type == ANIMTYPE_GPLAYER)
114 // delete_gplayer_frames((bGPDlayer *)ale->data);
116 delete_ipo_keys((Ipo *)ale->key_data);
119 /* free filtered list */
120 BLI_freelistN(&anim_data);
123 /* ------------------- */
125 static int actkeys_delete_exec(bContext *C, wmOperator *op)
129 /* get editor data */
130 if (ANIM_animdata_get_context(C, &ac) == 0)
131 return OPERATOR_CANCELLED;
133 /* delete keyframes */
134 delete_action_keys(&ac);
136 /* validate keyframes after editing */
137 ANIM_editkeyframes_refresh(&ac);
139 /* set notifier tha things have changed */
140 ED_area_tag_redraw(CTX_wm_area(C)); // FIXME... should be updating 'keyframes' data context or so instead!
142 return OPERATOR_FINISHED;
145 void ACT_OT_keyframes_delete (wmOperatorType *ot)
148 ot->name= "Delete Keyframes";
149 ot->idname= "ACT_OT_keyframes_delete";
152 ot->exec= actkeys_delete_exec;
153 ot->poll= ED_operator_areaactive;
156 ot->flag= OPTYPE_REGISTER/*|OPTYPE_UNDO*/;
159 /* ******************** Clean Keyframes Operator ************************* */
161 static void clean_action_keys (bAnimContext *ac, float thresh)
163 ListBase anim_data = {NULL, NULL};
168 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_SEL | ANIMFILTER_ONLYICU);
169 ANIM_animdata_filter(&anim_data, filter, ac->data, ac->datatype);
171 /* loop through filtered data and clean curves */
172 for (ale= anim_data.first; ale; ale= ale->next)
173 clean_ipo_curve((IpoCurve *)ale->key_data, thresh);
176 BLI_freelistN(&anim_data);
179 /* ------------------- */
181 static int actkeys_clean_exec(bContext *C, wmOperator *op)
186 /* get editor data */
187 if (ANIM_animdata_get_context(C, &ac) == 0)
188 return OPERATOR_CANCELLED;
189 if (ac.datatype == ANIMCONT_GPENCIL)
190 return OPERATOR_PASS_THROUGH;
192 /* get cleaning threshold */
193 thresh= RNA_float_get(op->ptr, "threshold");
195 /* clean keyframes */
196 clean_action_keys(&ac, thresh);
198 /* validate keyframes after editing */
199 ANIM_editkeyframes_refresh(&ac);
201 /* set notifier tha things have changed */
202 ED_area_tag_redraw(CTX_wm_area(C)); // FIXME... should be updating 'keyframes' data context or so instead!
204 return OPERATOR_FINISHED;
207 void ACT_OT_keyframes_clean (wmOperatorType *ot)
212 ot->name= "Clean Keyframes";
213 ot->idname= "ACT_OT_keyframes_clean";
216 //ot->invoke= // XXX we need that number popup for this!
217 ot->exec= actkeys_clean_exec;
218 ot->poll= ED_operator_areaactive;
221 ot->flag= OPTYPE_REGISTER/*|OPTYPE_UNDO*/;
224 prop= RNA_def_property(ot->srna, "threshold", PROP_FLOAT, PROP_NONE);
225 RNA_def_property_float_default(prop, 0.001f);
228 /* ******************** Sample Keyframes Operator *********************** */
230 /* little cache for values... */
231 typedef struct tempFrameValCache {
235 /* Evaluates the curves between each selected keyframe on each frame, and keys the value */
236 static void sample_action_keys (bAnimContext *ac)
238 ListBase anim_data = {NULL, NULL};
243 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_ONLYICU);
244 ANIM_animdata_filter(&anim_data, filter, ac->data, ac->datatype);
246 /* loop through filtered data and add keys between selected keyframes on every frame */
247 for (ale= anim_data.first; ale; ale= ale->next) {
248 IpoCurve *icu= (IpoCurve *)ale->key_data;
249 BezTriple *bezt, *start=NULL, *end=NULL;
250 tempFrameValCache *value_cache, *fp;
254 /* find selected keyframes... once pair has been found, add keyframes */
255 for (i=0, bezt=icu->bezt; i < icu->totvert; i++, bezt++) {
256 /* check if selected, and which end this is */
257 if (BEZSELECTED(bezt)) {
262 /* cache values then add keyframes using these values, as adding
263 * keyframes while sampling will affect the outcome...
265 range= (int)( ceil(end->vec[1][0] - start->vec[1][0]) );
266 sfra= (int)( floor(start->vec[1][0]) );
269 value_cache= MEM_callocN(sizeof(tempFrameValCache)*range, "IcuFrameValCache");
272 for (n=0, fp=value_cache; n<range && fp; n++, fp++) {
273 fp->frame= (float)(sfra + n);
274 fp->val= eval_icu(icu, fp->frame);
277 /* add keyframes with these */
278 for (n=0, fp=value_cache; n<range && fp; n++, fp++) {
279 insert_vert_icu(icu, fp->frame, fp->val, 1);
282 /* free temp cache */
283 MEM_freeN(value_cache);
285 /* as we added keyframes, we need to compensate so that bezt is at the right place */
286 bezt = icu->bezt + i + range - 1;
290 /* bezt was selected, so it now marks the start of a whole new chain to search */
295 /* just set start keyframe */
302 /* recalculate channel's handles? */
303 calchandles_ipocurve(icu);
306 /* admin and redraws */
307 BLI_freelistN(&anim_data);
310 /* ------------------- */
312 static int actkeys_sample_exec(bContext *C, wmOperator *op)
316 /* get editor data */
317 if (ANIM_animdata_get_context(C, &ac) == 0)
318 return OPERATOR_CANCELLED;
319 if (ac.datatype == ANIMCONT_GPENCIL)
320 return OPERATOR_PASS_THROUGH;
322 /* sample keyframes */
323 sample_action_keys(&ac);
325 /* validate keyframes after editing */
326 ANIM_editkeyframes_refresh(&ac);
328 /* set notifier tha things have changed */
329 ED_area_tag_redraw(CTX_wm_area(C)); // FIXME... should be updating 'keyframes' data context or so instead!
331 return OPERATOR_FINISHED;
334 void ACT_OT_keyframes_sample (wmOperatorType *ot)
337 ot->name= "Sample Keyframes";
338 ot->idname= "ACT_OT_keyframes_sample";
341 ot->exec= actkeys_sample_exec;
342 ot->poll= ED_operator_areaactive;
345 ot->flag= OPTYPE_REGISTER/*|OPTYPE_UNDO*/;
348 /* ************************************************************************** */
351 /* ******************** Set Extrapolation-Type Operator *********************** */
353 /* defines for set ipo-type for selected keyframes tool */
354 EnumPropertyItem prop_actkeys_expo_types[] = {
355 {IPO_HORIZ, "CONSTANT", "Constant", ""},
356 {IPO_DIR, "DIRECTIONAL", "Extrapolation", ""},
357 {IPO_CYCL, "CYCLIC", "Cyclic", ""},
358 {IPO_CYCLX, "CYCLIC_EXTRAPOLATION", "Cyclic Extrapolation", ""},
359 {0, NULL, NULL, NULL}
362 /* this function is responsible for setting extrapolation mode for keyframes */
363 static void setexpo_action_keys(bAnimContext *ac, short mode)
365 ListBase anim_data = {NULL, NULL};
370 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_IPOKEYS);
371 ANIM_animdata_filter(&anim_data, filter, ac->data, ac->datatype);
373 /* loop through setting mode per ipo-curve */
374 for (ale= anim_data.first; ale; ale= ale->next)
375 setexprap_ipoloop(ale->key_data, mode);
378 BLI_freelistN(&anim_data);
381 /* ------------------- */
383 static int actkeys_expo_exec(bContext *C, wmOperator *op)
388 /* get editor data */
389 if (ANIM_animdata_get_context(C, &ac) == 0)
390 return OPERATOR_CANCELLED;
391 if (ac.datatype == ANIMCONT_GPENCIL)
392 return OPERATOR_PASS_THROUGH;
394 /* get handle setting mode */
395 mode= RNA_enum_get(op->ptr, "type");
397 /* set handle type */
398 setexpo_action_keys(&ac, mode);
400 /* validate keyframes after editing */
401 ANIM_editkeyframes_refresh(&ac);
403 /* set notifier tha things have changed */
404 ED_area_tag_redraw(CTX_wm_area(C)); // FIXME... should be updating 'keyframes' data context or so instead!
406 return OPERATOR_FINISHED;
409 void ACT_OT_keyframes_expotype (wmOperatorType *ot)
414 ot->name= "Set Keyframe Extrapolation";
415 ot->idname= "ACT_OT_keyframes_expotype";
418 ot->invoke= WM_menu_invoke;
419 ot->exec= actkeys_expo_exec;
420 ot->poll= ED_operator_areaactive;
423 ot->flag= OPTYPE_REGISTER/*|OPTYPE_UNDO*/;
426 prop= RNA_def_property(ot->srna, "type", PROP_ENUM, PROP_NONE);
427 RNA_def_property_enum_items(prop, prop_actkeys_expo_types);
430 /* ******************** Set Interpolation-Type Operator *********************** */
432 /* defines for set ipo-type for selected keyframes tool */
433 EnumPropertyItem prop_actkeys_ipo_types[] = {
434 {IPO_CONST, "CONSTANT", "Constant Interpolation", ""},
435 {IPO_LIN, "LINEAR", "Linear Interpolation", ""},
436 {IPO_BEZ, "BEZIER", "Bezier Interpolation", ""},
437 {0, NULL, NULL, NULL}
440 /* this function is responsible for setting interpolation mode for keyframes */
441 static void setipo_action_keys(bAnimContext *ac, short mode)
443 ListBase anim_data = {NULL, NULL};
446 BeztEditFunc set_cb= ANIM_editkeyframes_ipo(mode);
449 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_IPOKEYS);
450 ANIM_animdata_filter(&anim_data, filter, ac->data, ac->datatype);
452 /* loop through setting BezTriple interpolation
453 * Note: we do not supply BeztEditData to the looper yet. Currently that's not necessary here...
455 for (ale= anim_data.first; ale; ale= ale->next)
456 ipo_keys_bezier_loop(NULL, ale->key_data, NULL, set_cb, ANIM_editkeyframes_ipocurve_ipotype);
459 BLI_freelistN(&anim_data);
462 /* ------------------- */
464 static int actkeys_ipo_exec(bContext *C, wmOperator *op)
469 /* get editor data */
470 if (ANIM_animdata_get_context(C, &ac) == 0)
471 return OPERATOR_CANCELLED;
472 if (ac.datatype == ANIMCONT_GPENCIL)
473 return OPERATOR_PASS_THROUGH;
475 /* get handle setting mode */
476 mode= RNA_enum_get(op->ptr, "type");
478 /* set handle type */
479 setipo_action_keys(&ac, mode);
481 /* validate keyframes after editing */
482 ANIM_editkeyframes_refresh(&ac);
484 /* set notifier tha things have changed */
485 ED_area_tag_redraw(CTX_wm_area(C)); // FIXME... should be updating 'keyframes' data context or so instead!
487 return OPERATOR_FINISHED;
490 void ACT_OT_keyframes_ipotype (wmOperatorType *ot)
495 ot->name= "Set Keyframe Interpolation";
496 ot->idname= "ACT_OT_keyframes_ipotype";
499 ot->invoke= WM_menu_invoke;
500 ot->exec= actkeys_ipo_exec;
501 ot->poll= ED_operator_areaactive;
504 ot->flag= OPTYPE_REGISTER/*|OPTYPE_UNDO*/;
507 prop= RNA_def_property(ot->srna, "type", PROP_ENUM, PROP_NONE);
508 RNA_def_property_enum_items(prop, prop_actkeys_ipo_types);
511 /* ******************** Set Handle-Type Operator *********************** */
513 /* defines for set handle-type for selected keyframes tool */
514 EnumPropertyItem prop_actkeys_handletype_types[] = {
515 {HD_AUTO, "AUTO", "Auto Handles", ""},
516 {HD_VECT, "VECTOR", "Vector Handles", ""},
517 {HD_FREE, "FREE", "Free Handles", ""},
518 {HD_ALIGN, "ALIGN", "Aligned Handles", ""},
519 // {-1, "TOGGLE", "Toggle between Free and Aligned Handles", ""},
520 {0, NULL, NULL, NULL}
523 /* this function is responsible for setting handle-type of selected keyframes */
524 static void sethandles_action_keys(bAnimContext *ac, short mode)
526 ListBase anim_data = {NULL, NULL};
529 BeztEditFunc set_cb= ANIM_editkeyframes_handles(mode);
532 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_IPOKEYS);
533 ANIM_animdata_filter(&anim_data, filter, ac->data, ac->datatype);
535 /* loop through setting flags for handles
536 * Note: we do not supply BeztEditData to the looper yet. Currently that's not necessary here...
538 for (ale= anim_data.first; ale; ale= ale->next) {
540 BeztEditFunc toggle_cb;
542 /* check which type of handle to set (free or aligned)
543 * - check here checks for handles with free alignment already
545 if (ipo_keys_bezier_loop(NULL, ale->key_data, NULL, set_cb, NULL))
546 toggle_cb= ANIM_editkeyframes_handles(HD_FREE);
548 toggle_cb= ANIM_editkeyframes_handles(HD_ALIGN);
550 /* set handle-type */
551 ipo_keys_bezier_loop(NULL, ale->key_data, NULL, toggle_cb, calchandles_ipocurve);
554 /* directly set handle-type */
555 ipo_keys_bezier_loop(NULL, ale->key_data, NULL, set_cb, calchandles_ipocurve);
560 BLI_freelistN(&anim_data);
563 /* ------------------- */
565 static int actkeys_handletype_exec(bContext *C, wmOperator *op)
570 /* get editor data */
571 if (ANIM_animdata_get_context(C, &ac) == 0)
572 return OPERATOR_CANCELLED;
573 if (ac.datatype == ANIMCONT_GPENCIL)
574 return OPERATOR_PASS_THROUGH;
576 /* get handle setting mode */
577 mode= RNA_enum_get(op->ptr, "type");
579 /* set handle type */
580 sethandles_action_keys(&ac, mode);
582 /* validate keyframes after editing */
583 ANIM_editkeyframes_refresh(&ac);
585 /* set notifier tha things have changed */
586 ED_area_tag_redraw(CTX_wm_area(C)); // FIXME... should be updating 'keyframes' data context or so instead!
588 return OPERATOR_FINISHED;
591 void ACT_OT_keyframes_handletype (wmOperatorType *ot)
596 ot->name= "Set Keyframe Handle Type";
597 ot->idname= "ACT_OT_keyframes_handletype";
600 ot->invoke= WM_menu_invoke;
601 ot->exec= actkeys_handletype_exec;
602 ot->poll= ED_operator_areaactive;
605 ot->flag= OPTYPE_REGISTER/*|OPTYPE_UNDO*/;
608 prop= RNA_def_property(ot->srna, "type", PROP_ENUM, PROP_NONE);
609 RNA_def_property_enum_items(prop, prop_actkeys_handletype_types);
612 /* ************************************************************************** */
613 /* TRANSFORM STUFF */
615 /* ***************** Snap Current Frame Operator *********************** */
617 /* helper callback for actkeys_cfrasnap_exec() -> used to help get the average time of all selected beztriples */
618 // TODO: if some other code somewhere needs this, it'll be time to port this over to keyframes_edit.c!!!
619 static short bezt_calc_average(BeztEditData *bed, BezTriple *bezt)
621 /* only if selected */
622 if (bezt->f2 & SELECT) {
623 /* store average time in float (only do rounding at last step */
624 bed->f1 += bezt->vec[1][0];
626 /* increment number of items */
633 /* snap current-frame indicator to 'average time' of selected keyframe */
634 static int actkeys_cfrasnap_exec(bContext *C, wmOperator *op)
637 ListBase anim_data= {NULL, NULL};
642 /* get editor data */
643 if (ANIM_animdata_get_context(C, &ac) == 0)
644 return OPERATOR_CANCELLED;
647 memset(&bed, 0, sizeof(BeztEditData));
649 /* loop over action data, averaging values */
650 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_IPOKEYS);
651 ANIM_animdata_filter(&anim_data, filter, ac.data, ac.datatype);
653 for (ale= anim_data.first; ale; ale= ale->next)
654 ipo_keys_bezier_loop(&bed, ale->key_data, NULL, bezt_calc_average, NULL);
656 BLI_freelistN(&anim_data);
658 /* set the new current frame value, based on the average time */
660 Scene *scene= ac.scene;
661 CFRA= (int)floor((bed.f1 / bed.i1) + 0.5f);
664 /* set notifier tha things have changed */
665 WM_event_add_notifier(C, NC_SCENE|ND_FRAME, ac.scene);
667 return OPERATOR_FINISHED;
670 void ACT_OT_keyframes_cfrasnap (wmOperatorType *ot)
673 ot->name= "Snap Current Frame to Keys";
674 ot->idname= "ACT_OT_keyframes_cfrasnap";
677 ot->exec= actkeys_cfrasnap_exec;
678 ot->poll= ED_operator_areaactive;
681 ot->flag= OPTYPE_REGISTER/*|OPTYPE_UNDO*/;
684 /* ******************** Snap Keyframes Operator *********************** */
686 /* defines for snap keyframes tool */
687 EnumPropertyItem prop_actkeys_snap_types[] = {
688 {ACTKEYS_SNAP_CFRA, "CFRA", "Current frame", ""},
689 {ACTKEYS_SNAP_NEAREST_FRAME, "NEAREST_FRAME", "Nearest Frame", ""}, // XXX as single entry?
690 {ACTKEYS_SNAP_NEAREST_SECOND, "NEAREST_SECOND", "Nearest Second", ""}, // XXX as single entry?
691 {ACTKEYS_SNAP_NEAREST_MARKER, "NEAREST_MARKER", "Nearest Marker", ""},
692 {0, NULL, NULL, NULL}
695 /* this function is responsible for snapping keyframes to frame-times */
696 static void snap_action_keys(bAnimContext *ac, short mode)
698 ListBase anim_data = {NULL, NULL};
703 BeztEditFunc edit_cb;
706 if (ac->datatype == ANIMCONT_GPENCIL)
707 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_FOREDIT);
709 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_IPOKEYS);
710 ANIM_animdata_filter(&anim_data, filter, ac->data, ac->datatype);
712 /* get beztriple editing callbacks */
713 edit_cb= ANIM_editkeyframes_snap(mode);
715 memset(&bed, 0, sizeof(BeztEditData));
716 bed.scene= ac->scene;
719 for (ale= anim_data.first; ale; ale= ale->next) {
720 Object *nob= ANIM_nla_mapping_get(ac, ale);
723 ANIM_nla_mapping_apply(nob, ale->key_data, 0, 1);
724 ipo_keys_bezier_loop(&bed, ale->key_data, NULL, edit_cb, calchandles_ipocurve);
725 ANIM_nla_mapping_apply(nob, ale->key_data, 1, 1);
727 //else if (ale->type == ACTTYPE_GPLAYER)
728 // snap_gplayer_frames(ale->data, mode);
730 ipo_keys_bezier_loop(&bed, ale->key_data, NULL, edit_cb, calchandles_ipocurve);
732 BLI_freelistN(&anim_data);
735 /* ------------------- */
737 static int actkeys_snap_exec(bContext *C, wmOperator *op)
742 /* get editor data */
743 if (ANIM_animdata_get_context(C, &ac) == 0)
744 return OPERATOR_CANCELLED;
746 /* get snapping mode */
747 mode= RNA_enum_get(op->ptr, "type");
750 snap_action_keys(&ac, mode);
752 /* validate keyframes after editing */
753 ANIM_editkeyframes_refresh(&ac);
755 /* set notifier tha things have changed */
756 ED_area_tag_redraw(CTX_wm_area(C)); // FIXME... should be updating 'keyframes' data context or so instead!
758 return OPERATOR_FINISHED;
761 void ACT_OT_keyframes_snap (wmOperatorType *ot)
766 ot->name= "Snap Keys";
767 ot->idname= "ACT_OT_keyframes_snap";
770 ot->invoke= WM_menu_invoke;
771 ot->exec= actkeys_snap_exec;
772 ot->poll= ED_operator_areaactive;
775 ot->flag= OPTYPE_REGISTER/*|OPTYPE_UNDO*/;
778 prop= RNA_def_property(ot->srna, "type", PROP_ENUM, PROP_NONE);
779 RNA_def_property_enum_items(prop, prop_actkeys_snap_types);
782 /* ******************** Mirror Keyframes Operator *********************** */
784 /* defines for mirror keyframes tool */
785 EnumPropertyItem prop_actkeys_mirror_types[] = {
786 {ACTKEYS_MIRROR_CFRA, "CFRA", "Current frame", ""},
787 {ACTKEYS_MIRROR_YAXIS, "YAXIS", "Vertical Axis", ""},
788 {ACTKEYS_MIRROR_XAXIS, "XAXIS", "Horizontal Axis", ""},
789 {ACTKEYS_MIRROR_MARKER, "MARKER", "First Selected Marker", ""},
790 {0, NULL, NULL, NULL}
793 /* this function is responsible for mirroring keyframes */
794 static void mirror_action_keys(bAnimContext *ac, short mode)
796 ListBase anim_data = {NULL, NULL};
801 BeztEditFunc edit_cb;
803 /* get beztriple editing callbacks */
804 edit_cb= ANIM_editkeyframes_mirror(mode);
806 memset(&bed, 0, sizeof(BeztEditData));
807 bed.scene= ac->scene;
809 /* for 'first selected marker' mode, need to find first selected marker first! */
810 // XXX should this be made into a helper func in the API?
811 if (mode == ACTKEYS_MIRROR_MARKER) {
812 Scene *scene= ac->scene;
813 TimeMarker *marker= NULL;
815 /* find first selected marker */
816 for (marker= scene->markers.first; marker; marker=marker->next) {
817 if (marker->flag & SELECT) {
822 /* store marker's time (if available) */
824 bed.f1= marker->frame;
830 if (ac->datatype == ANIMCONT_GPENCIL)
831 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_FOREDIT);
833 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_IPOKEYS);
834 ANIM_animdata_filter(&anim_data, filter, ac->data, ac->datatype);
836 /* mirror keyframes */
837 for (ale= anim_data.first; ale; ale= ale->next) {
838 Object *nob= ANIM_nla_mapping_get(ac, ale);
841 ANIM_nla_mapping_apply(nob, ale->key_data, 0, 1);
842 ipo_keys_bezier_loop(&bed, ale->key_data, NULL, edit_cb, calchandles_ipocurve);
843 ANIM_nla_mapping_apply(nob, ale->key_data, 1, 1);
845 //else if (ale->type == ACTTYPE_GPLAYER)
846 // snap_gplayer_frames(ale->data, mode);
848 ipo_keys_bezier_loop(&bed, ale->key_data, NULL, edit_cb, calchandles_ipocurve);
850 BLI_freelistN(&anim_data);
853 /* ------------------- */
855 static int actkeys_mirror_exec(bContext *C, wmOperator *op)
860 /* get editor data */
861 if (ANIM_animdata_get_context(C, &ac) == 0)
862 return OPERATOR_CANCELLED;
864 /* get mirroring mode */
865 mode= RNA_enum_get(op->ptr, "type");
867 /* mirror keyframes */
868 mirror_action_keys(&ac, mode);
870 /* validate keyframes after editing */
871 ANIM_editkeyframes_refresh(&ac);
873 /* set notifier tha things have changed */
874 ED_area_tag_redraw(CTX_wm_area(C)); // FIXME... should be updating 'keyframes' data context or so instead!
876 return OPERATOR_FINISHED;
879 void ACT_OT_keyframes_mirror (wmOperatorType *ot)
884 ot->name= "Mirror Keys";
885 ot->idname= "ACT_OT_keyframes_mirror";
888 ot->invoke= WM_menu_invoke;
889 ot->exec= actkeys_mirror_exec;
890 ot->poll= ED_operator_areaactive;
893 ot->flag= OPTYPE_REGISTER/*|OPTYPE_UNDO*/;
896 prop= RNA_def_property(ot->srna, "type", PROP_ENUM, PROP_NONE);
897 RNA_def_property_enum_items(prop, prop_actkeys_mirror_types);
900 /* ************************************************************************** */