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_anim_types.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_object_types.h"
50 #include "DNA_screen_types.h"
51 #include "DNA_scene_types.h"
52 #include "DNA_space_types.h"
53 #include "DNA_constraint_types.h"
54 #include "DNA_key_types.h"
55 #include "DNA_lamp_types.h"
56 #include "DNA_material_types.h"
57 #include "DNA_userdef_types.h"
58 #include "DNA_gpencil_types.h"
59 #include "DNA_windowmanager_types.h"
61 #include "RNA_access.h"
62 #include "RNA_define.h"
64 #include "BKE_action.h"
65 #include "BKE_depsgraph.h"
66 #include "BKE_fcurve.h"
68 #include "BKE_material.h"
69 #include "BKE_object.h"
70 #include "BKE_context.h"
71 #include "BKE_report.h"
72 #include "BKE_utildefines.h"
74 #include "UI_view2d.h"
76 #include "BIF_transform.h"
78 #include "ED_anim_api.h"
79 #include "ED_keyframing.h"
80 #include "ED_keyframes_draw.h"
81 #include "ED_keyframes_edit.h"
82 #include "ED_screen.h"
83 #include "ED_space_api.h"
88 #include "graph_intern.h"
90 /* ************************************************************************** */
91 /* KEYFRAME-RANGE STUFF */
93 /* *************************** Calculate Range ************************** */
95 /* Get the min/max keyframes*/
96 static void get_graph_keyframe_extents (bAnimContext *ac, float *xmin, float *xmax, float *ymin, float *ymax)
98 ListBase anim_data = {NULL, NULL};
102 /* get data to filter, from Dopesheet */
103 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE | ANIMFILTER_SEL | ANIMFILTER_FOREDIT | ANIMFILTER_CURVESONLY);
104 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
106 /* set large values to try to override */
107 if (xmin) *xmin= 999999999.0f;
108 if (xmax) *xmax= -999999999.0f;
109 if (ymin) *ymin= 999999999.0f;
110 if (ymax) *ymax= -999999999.0f;
112 /* check if any channels to set range with */
113 if (anim_data.first) {
114 /* go through channels, finding max extents */
115 for (ale= anim_data.first; ale; ale= ale->next) {
116 Object *nob= NULL; //ANIM_nla_mapping_get(ac, ale);
117 FCurve *fcu= (FCurve *)ale->key_data;
120 /* get range and apply necessary scaling before */
121 calc_fcurve_bounds(fcu, &tmin, &tmax, ymin, ymax);
124 tmin= get_action_frame_inv(nob, tmin);
125 tmax= get_action_frame_inv(nob, tmax);
128 /* try to set cur using these values, if they're more extreme than previously set values */
129 if (xmin) *xmin= MIN2(*xmin, tmin);
130 if (xmax) *xmax= MAX2(*xmax, tmax);
134 BLI_freelistN(&anim_data);
137 /* set default range */
139 if (xmin) *xmin= (float)ac->scene->r.sfra;
140 if (xmax) *xmax= (float)ac->scene->r.efra;
144 if (xmax) *xmax= 100;
152 /* ****************** Automatic Preview-Range Operator ****************** */
154 static int graphkeys_previewrange_exec(bContext *C, wmOperator *op)
160 /* get editor data */
161 if (ANIM_animdata_get_context(C, &ac) == 0)
162 return OPERATOR_CANCELLED;
163 if (ac.scene == NULL)
164 return OPERATOR_CANCELLED;
168 /* set the range directly */
169 get_graph_keyframe_extents(&ac, &min, &max, NULL, NULL);
170 scene->r.psfra= (int)floor(min + 0.5f);
171 scene->r.pefra= (int)floor(max + 0.5f);
173 /* set notifier that things have changed */
174 // XXX err... there's nothing for frame ranges yet, but this should do fine too
175 WM_event_add_notifier(C, NC_SCENE|ND_FRAME, ac.scene);
177 return OPERATOR_FINISHED;
180 void GRAPHEDIT_OT_set_previewrange (wmOperatorType *ot)
183 ot->name= "Auto-Set Preview Range";
184 ot->idname= "GRAPHEDIT_OT_set_previewrange";
187 ot->exec= graphkeys_previewrange_exec;
188 ot->poll= ED_operator_areaactive;
191 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
194 /* ****************** View-All Operator ****************** */
196 static int graphkeys_viewall_exec(bContext *C, wmOperator *op)
202 /* get editor data */
203 if (ANIM_animdata_get_context(C, &ac) == 0)
204 return OPERATOR_CANCELLED;
207 /* set the horizontal range, with an extra offset so that the extreme keys will be in view */
208 get_graph_keyframe_extents(&ac, &v2d->cur.xmin, &v2d->cur.xmax, &v2d->cur.ymin, &v2d->cur.ymax);
210 extra= 0.1f * (v2d->cur.xmax - v2d->cur.xmin);
211 v2d->cur.xmin -= extra;
212 v2d->cur.xmax += extra;
214 extra= 0.1f * (v2d->cur.ymax - v2d->cur.ymin);
215 v2d->cur.ymin -= extra;
216 v2d->cur.ymax += extra;
218 /* do View2D syncing */
219 UI_view2d_sync(CTX_wm_screen(C), CTX_wm_area(C), v2d, V2D_LOCK_COPY);
221 /* set notifier that things have changed */
222 ED_area_tag_redraw(CTX_wm_area(C));
224 return OPERATOR_FINISHED;
227 void GRAPHEDIT_OT_view_all (wmOperatorType *ot)
230 ot->name= "View All";
231 ot->idname= "GRAPHEDIT_OT_view_all";
234 ot->exec= graphkeys_viewall_exec;
235 ot->poll= ED_operator_areaactive;
238 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
242 /* ************************************************************************** */
247 /* ******************** Copy/Paste Keyframes Operator ************************* */
248 /* NOTE: the backend code for this is shared with the dopesheet editor */
250 static short copy_graph_keys (bAnimContext *ac)
252 ListBase anim_data = {NULL, NULL};
255 /* clear buffer first */
259 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE | ANIMFILTER_SEL | ANIMFILTER_CURVESONLY);
260 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
263 ok= copy_animedit_keys(ac, &anim_data);
266 BLI_freelistN(&anim_data);
271 static short paste_graph_keys (bAnimContext *ac)
273 ListBase anim_data = {NULL, NULL};
277 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE | ANIMFILTER_SEL | ANIMFILTER_FOREDIT | ANIMFILTER_CURVESONLY);
278 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
280 /* paste keyframes */
281 ok= paste_animedit_keys(ac, &anim_data);
284 BLI_freelistN(&anim_data);
289 /* ------------------- */
291 static int graphkeys_copy_exec(bContext *C, wmOperator *op)
295 /* get editor data */
296 if (ANIM_animdata_get_context(C, &ac) == 0)
297 return OPERATOR_CANCELLED;
300 if (copy_graph_keys(&ac)) {
301 BKE_report(op->reports, RPT_ERROR, "No keyframes copied to keyframes copy/paste buffer");
302 return OPERATOR_CANCELLED;
305 /* set notifier tha things have changed */
306 ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_KEYFRAMES_VALUES);
308 return OPERATOR_FINISHED;
311 void GRAPHEDIT_OT_keyframes_copy (wmOperatorType *ot)
314 ot->name= "Copy Keyframes";
315 ot->idname= "GRAPHEDIT_OT_keyframes_copy";
318 ot->exec= graphkeys_copy_exec;
319 ot->poll= ED_operator_areaactive;
322 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
327 static int graphkeys_paste_exec(bContext *C, wmOperator *op)
331 /* get editor data */
332 if (ANIM_animdata_get_context(C, &ac) == 0)
333 return OPERATOR_CANCELLED;
335 /* paste keyframes */
336 if (paste_graph_keys(&ac)) {
337 BKE_report(op->reports, RPT_ERROR, "No keyframes to paste");
338 return OPERATOR_CANCELLED;
341 /* validate keyframes after editing */
342 ANIM_editkeyframes_refresh(&ac);
344 /* set notifier tha things have changed */
345 ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_KEYFRAMES_VALUES);
347 return OPERATOR_FINISHED;
350 void GRAPHEDIT_OT_keyframes_paste (wmOperatorType *ot)
353 ot->name= "Paste Keyframes";
354 ot->idname= "GRAPHEDIT_OT_keyframes_paste";
357 ot->exec= graphkeys_paste_exec;
358 ot->poll= ED_operator_areaactive;
361 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
364 /* ******************** Duplicate Keyframes Operator ************************* */
366 static void duplicate_graph_keys (bAnimContext *ac)
368 ListBase anim_data = {NULL, NULL};
373 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE| ANIMFILTER_FOREDIT | ANIMFILTER_CURVESONLY);
374 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
376 /* loop through filtered data and delete selected keys */
377 for (ale= anim_data.first; ale; ale= ale->next) {
378 duplicate_fcurve_keys((FCurve *)ale->key_data);
381 /* free filtered list */
382 BLI_freelistN(&anim_data);
385 /* ------------------- */
387 static int graphkeys_duplicate_exec(bContext *C, wmOperator *op)
391 /* get editor data */
392 if (ANIM_animdata_get_context(C, &ac) == 0)
393 return OPERATOR_CANCELLED;
395 /* duplicate keyframes */
396 duplicate_graph_keys(&ac);
398 /* validate keyframes after editing */
399 ANIM_editkeyframes_refresh(&ac);
401 /* set notifier tha things have changed */
402 ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_KEYFRAMES_VALUES);
404 return OPERATOR_FINISHED;
407 static int graphkeys_duplicate_invoke(bContext *C, wmOperator *op, wmEvent *event)
409 graphkeys_duplicate_exec(C, op);
411 RNA_int_set(op->ptr, "mode", TFM_TRANSLATION);
412 WM_operator_name_call(C, "TFM_OT_transform", WM_OP_INVOKE_REGION_WIN, op->ptr);
414 return OPERATOR_FINISHED;
417 void GRAPHEDIT_OT_keyframes_duplicate (wmOperatorType *ot)
420 ot->name= "Duplicate Keyframes";
421 ot->idname= "GRAPHEDIT_OT_keyframes_duplicate";
424 ot->invoke= graphkeys_duplicate_invoke;
425 ot->exec= graphkeys_duplicate_exec;
426 ot->poll= ED_operator_areaactive;
429 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
431 /* to give to transform */
432 RNA_def_int(ot->srna, "mode", TFM_TRANSLATION, 0, INT_MAX, "Mode", "", 0, INT_MAX);
435 /* ******************** Delete Keyframes Operator ************************* */
437 static void delete_graph_keys (bAnimContext *ac)
439 ListBase anim_data = {NULL, NULL};
444 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE| ANIMFILTER_FOREDIT | ANIMFILTER_CURVESONLY);
445 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
447 /* loop through filtered data and delete selected keys */
448 for (ale= anim_data.first; ale; ale= ale->next) {
449 delete_fcurve_keys((FCurve *)ale->key_data); // XXX... this doesn't delete empty curves anymore
452 /* free filtered list */
453 BLI_freelistN(&anim_data);
456 /* ------------------- */
458 static int graphkeys_delete_exec(bContext *C, wmOperator *op)
462 /* get editor data */
463 if (ANIM_animdata_get_context(C, &ac) == 0)
464 return OPERATOR_CANCELLED;
466 /* delete keyframes */
467 delete_graph_keys(&ac);
469 /* validate keyframes after editing */
470 ANIM_editkeyframes_refresh(&ac);
472 /* set notifier tha things have changed */
473 ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_KEYFRAMES_VALUES);
475 return OPERATOR_FINISHED;
478 void GRAPHEDIT_OT_keyframes_delete (wmOperatorType *ot)
481 ot->name= "Delete Keyframes";
482 ot->idname= "GRAPHEDIT_OT_keyframes_delete";
485 ot->invoke= WM_operator_confirm;
486 ot->exec= graphkeys_delete_exec;
487 ot->poll= ED_operator_areaactive;
490 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
493 /* ******************** Clean Keyframes Operator ************************* */
495 static void clean_graph_keys (bAnimContext *ac, float thresh)
497 ListBase anim_data = {NULL, NULL};
502 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE| ANIMFILTER_FOREDIT | ANIMFILTER_SEL | ANIMFILTER_CURVESONLY);
503 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
505 /* loop through filtered data and clean curves */
506 for (ale= anim_data.first; ale; ale= ale->next)
507 clean_fcurve((FCurve *)ale->key_data, thresh);
510 BLI_freelistN(&anim_data);
513 /* ------------------- */
515 static int graphkeys_clean_exec(bContext *C, wmOperator *op)
520 /* get editor data */
521 if (ANIM_animdata_get_context(C, &ac) == 0)
522 return OPERATOR_CANCELLED;
524 /* get cleaning threshold */
525 thresh= RNA_float_get(op->ptr, "threshold");
527 /* clean keyframes */
528 clean_graph_keys(&ac, thresh);
530 /* validate keyframes after editing */
531 ANIM_editkeyframes_refresh(&ac);
533 /* set notifier tha things have changed */
534 ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_KEYFRAMES_VALUES);
536 return OPERATOR_FINISHED;
539 void GRAPHEDIT_OT_keyframes_clean (wmOperatorType *ot)
542 ot->name= "Clean Keyframes";
543 ot->idname= "GRAPHEDIT_OT_keyframes_clean";
546 //ot->invoke= // XXX we need that number popup for this!
547 ot->exec= graphkeys_clean_exec;
548 ot->poll= ED_operator_areaactive;
551 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
554 RNA_def_float(ot->srna, "threshold", 0.001f, 0.0f, FLT_MAX, "Threshold", "", 0.0f, 1000.0f);
557 /* ******************** Sample Keyframes Operator *********************** */
559 // XXX some of the common parts (with DopeSheet) should be unified in animation module...
561 /* little cache for values... */
562 typedef struct tempFrameValCache {
566 /* Evaluates the curves between each selected keyframe on each frame, and keys the value */
567 static void sample_graph_keys (bAnimContext *ac)
569 ListBase anim_data = {NULL, NULL};
574 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE| ANIMFILTER_FOREDIT | ANIMFILTER_CURVESONLY);
575 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
577 /* loop through filtered data and add keys between selected keyframes on every frame */
578 for (ale= anim_data.first; ale; ale= ale->next) {
579 FCurve *fcu= (FCurve *)ale->key_data;
580 BezTriple *bezt, *start=NULL, *end=NULL;
581 tempFrameValCache *value_cache, *fp;
585 /* find selected keyframes... once pair has been found, add keyframes */
586 for (i=0, bezt=fcu->bezt; i < fcu->totvert; i++, bezt++) {
587 /* check if selected, and which end this is */
588 if (BEZSELECTED(bezt)) {
593 /* cache values then add keyframes using these values, as adding
594 * keyframes while sampling will affect the outcome...
596 range= (int)( ceil(end->vec[1][0] - start->vec[1][0]) );
597 sfra= (int)( floor(start->vec[1][0]) );
600 value_cache= MEM_callocN(sizeof(tempFrameValCache)*range, "IcuFrameValCache");
603 for (n=0, fp=value_cache; n<range && fp; n++, fp++) {
604 fp->frame= (float)(sfra + n);
605 fp->val= evaluate_fcurve(fcu, fp->frame);
608 /* add keyframes with these */
609 for (n=0, fp=value_cache; n<range && fp; n++, fp++) {
610 insert_vert_fcurve(fcu, fp->frame, fp->val, 1);
613 /* free temp cache */
614 MEM_freeN(value_cache);
616 /* as we added keyframes, we need to compensate so that bezt is at the right place */
617 bezt = fcu->bezt + i + range - 1;
621 /* bezt was selected, so it now marks the start of a whole new chain to search */
626 /* just set start keyframe */
633 /* recalculate channel's handles? */
634 calchandles_fcurve(fcu);
637 /* admin and redraws */
638 BLI_freelistN(&anim_data);
641 /* ------------------- */
643 static int graphkeys_sample_exec(bContext *C, wmOperator *op)
647 /* get editor data */
648 if (ANIM_animdata_get_context(C, &ac) == 0)
649 return OPERATOR_CANCELLED;
651 /* sample keyframes */
652 sample_graph_keys(&ac);
654 /* validate keyframes after editing */
655 ANIM_editkeyframes_refresh(&ac);
657 /* set notifier tha things have changed */
658 ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_KEYFRAMES_VALUES);
660 return OPERATOR_FINISHED;
663 void GRAPHEDIT_OT_keyframes_sample (wmOperatorType *ot)
666 ot->name= "Sample Keyframes";
667 ot->idname= "GRAPHEDIT_OT_keyframes_sample";
670 ot->exec= graphkeys_sample_exec;
671 ot->poll= ED_operator_areaactive;
674 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
678 /* ************************************************************************** */
681 /* ******************** Set Extrapolation-Type Operator *********************** */
683 /* defines for set extrapolation-type for selected keyframes tool */
684 EnumPropertyItem prop_graphkeys_expo_types[] = {
685 {FCURVE_EXTRAPOLATE_CONSTANT, "CONSTANT", "Constant Extrapolation", ""},
686 {FCURVE_EXTRAPOLATE_LINEAR, "LINEAR", "Linear Extrapolation", ""},
687 {0, NULL, NULL, NULL}
690 /* this function is responsible for setting extrapolation mode for keyframes */
691 static void setexpo_graph_keys(bAnimContext *ac, short mode)
693 ListBase anim_data = {NULL, NULL};
698 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE| ANIMFILTER_FOREDIT | ANIMFILTER_CURVESONLY);
699 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
701 /* loop through setting mode per F-Curve */
702 for (ale= anim_data.first; ale; ale= ale->next) {
703 FCurve *fcu= (FCurve *)ale->data;
708 BLI_freelistN(&anim_data);
711 /* ------------------- */
713 static int graphkeys_expo_exec(bContext *C, wmOperator *op)
718 /* get editor data */
719 if (ANIM_animdata_get_context(C, &ac) == 0)
720 return OPERATOR_CANCELLED;
722 /* get handle setting mode */
723 mode= RNA_enum_get(op->ptr, "type");
725 /* set handle type */
726 setexpo_graph_keys(&ac, mode);
728 /* validate keyframes after editing */
729 ANIM_editkeyframes_refresh(&ac);
731 /* set notifier tha things have changed */
732 ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_KEYFRAMES_VALUES);
734 return OPERATOR_FINISHED;
737 void GRAPHEDIT_OT_keyframes_extrapolation_type (wmOperatorType *ot)
740 ot->name= "Set Keyframe Extrapolation";
741 ot->idname= "GRAPHEDIT_OT_keyframes_extrapolation_type";
744 ot->invoke= WM_menu_invoke;
745 ot->exec= graphkeys_expo_exec;
746 ot->poll= ED_operator_areaactive;
749 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
752 RNA_def_enum(ot->srna, "type", prop_graphkeys_expo_types, 0, "Type", "");
755 /* ******************** Set Interpolation-Type Operator *********************** */
757 /* defines for set ipo-type for selected keyframes tool */
758 EnumPropertyItem prop_graphkeys_ipo_types[] = {
759 {BEZT_IPO_CONST, "CONSTANT", "Constant Interpolation", ""},
760 {BEZT_IPO_LIN, "LINEAR", "Linear Interpolation", ""},
761 {BEZT_IPO_BEZ, "BEZIER", "Bezier Interpolation", ""},
762 {0, NULL, NULL, NULL}
765 /* this function is responsible for setting interpolation mode for keyframes */
766 static void setipo_graph_keys(bAnimContext *ac, short mode)
768 ListBase anim_data = {NULL, NULL};
771 BeztEditFunc set_cb= ANIM_editkeyframes_ipo(mode);
774 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE| ANIMFILTER_FOREDIT | ANIMFILTER_CURVESONLY);
775 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
777 /* loop through setting BezTriple interpolation
778 * Note: we do not supply BeztEditData to the looper yet. Currently that's not necessary here...
780 for (ale= anim_data.first; ale; ale= ale->next)
781 ANIM_fcurve_keys_bezier_loop(NULL, ale->key_data, NULL, set_cb, calchandles_fcurve);
784 BLI_freelistN(&anim_data);
787 /* ------------------- */
789 static int graphkeys_ipo_exec(bContext *C, wmOperator *op)
794 /* get editor data */
795 if (ANIM_animdata_get_context(C, &ac) == 0)
796 return OPERATOR_CANCELLED;
798 /* get handle setting mode */
799 mode= RNA_enum_get(op->ptr, "type");
801 /* set handle type */
802 setipo_graph_keys(&ac, mode);
804 /* validate keyframes after editing */
805 ANIM_editkeyframes_refresh(&ac);
807 /* set notifier tha things have changed */
808 ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_KEYFRAMES_VALUES);
810 return OPERATOR_FINISHED;
813 void GRAPHEDIT_OT_keyframes_interpolation_type (wmOperatorType *ot)
816 ot->name= "Set Keyframe Interpolation";
817 ot->idname= "GRAPHEDIT_OT_keyframes_interpolation_type";
820 ot->invoke= WM_menu_invoke;
821 ot->exec= graphkeys_ipo_exec;
822 ot->poll= ED_operator_areaactive;
825 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
828 RNA_def_enum(ot->srna, "type", prop_graphkeys_ipo_types, 0, "Type", "");
831 /* ******************** Set Handle-Type Operator *********************** */
833 /* defines for set handle-type for selected keyframes tool */
834 EnumPropertyItem prop_graphkeys_handletype_types[] = {
835 {HD_AUTO, "AUTO", "Auto Handles", ""},
836 {HD_VECT, "VECTOR", "Vector Handles", ""},
837 {HD_FREE, "FREE", "Free Handles", ""},
838 {HD_ALIGN, "ALIGN", "Aligned Handles", ""},
839 // {-1, "TOGGLE", "Toggle between Free and Aligned Handles", ""},
840 {0, NULL, NULL, NULL}
843 /* this function is responsible for setting handle-type of selected keyframes */
844 static void sethandles_graph_keys(bAnimContext *ac, short mode)
846 ListBase anim_data = {NULL, NULL};
849 BeztEditFunc set_cb= ANIM_editkeyframes_handles(mode);
852 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE| ANIMFILTER_FOREDIT | ANIMFILTER_CURVESONLY);
853 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
855 /* loop through setting flags for handles
856 * Note: we do not supply BeztEditData to the looper yet. Currently that's not necessary here...
858 // XXX we might need to supply BeztEditData to get it to only affect selected handles
859 for (ale= anim_data.first; ale; ale= ale->next) {
861 BeztEditFunc toggle_cb;
863 /* check which type of handle to set (free or aligned)
864 * - check here checks for handles with free alignment already
866 if (ANIM_fcurve_keys_bezier_loop(NULL, ale->key_data, NULL, set_cb, NULL))
867 toggle_cb= ANIM_editkeyframes_handles(HD_FREE);
869 toggle_cb= ANIM_editkeyframes_handles(HD_ALIGN);
871 /* set handle-type */
872 ANIM_fcurve_keys_bezier_loop(NULL, ale->key_data, NULL, toggle_cb, calchandles_fcurve);
875 /* directly set handle-type */
876 ANIM_fcurve_keys_bezier_loop(NULL, ale->key_data, NULL, set_cb, calchandles_fcurve);
881 BLI_freelistN(&anim_data);
884 /* ------------------- */
886 static int graphkeys_handletype_exec(bContext *C, wmOperator *op)
891 /* get editor data */
892 if (ANIM_animdata_get_context(C, &ac) == 0)
893 return OPERATOR_CANCELLED;
895 /* get handle setting mode */
896 mode= RNA_enum_get(op->ptr, "type");
898 /* set handle type */
899 sethandles_graph_keys(&ac, mode);
901 /* validate keyframes after editing */
902 ANIM_editkeyframes_refresh(&ac);
904 /* set notifier tha things have changed */
905 ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_KEYFRAMES_VALUES);
907 return OPERATOR_FINISHED;
910 void GRAPHEDIT_OT_keyframes_handletype (wmOperatorType *ot)
913 ot->name= "Set Keyframe Handle Type";
914 ot->idname= "GRAPHEDIT_OT_keyframes_handletype";
917 ot->invoke= WM_menu_invoke;
918 ot->exec= graphkeys_handletype_exec;
919 ot->poll= ED_operator_areaactive;
922 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
925 RNA_def_enum(ot->srna, "type", prop_graphkeys_handletype_types, 0, "Type", "");
928 /* ************************************************************************** */
929 /* TRANSFORM STUFF */
931 /* ***************** Snap Current Frame Operator *********************** */
933 /* helper callback for graphkeys_cfrasnap_exec() -> used to help get the average time of all selected beztriples */
934 // TODO: if some other code somewhere needs this, it'll be time to port this over to keyframes_edit.c!!!
935 static short bezt_calc_average(BeztEditData *bed, BezTriple *bezt)
937 /* only if selected */
938 if (bezt->f2 & SELECT) {
939 /* store average time in float (only do rounding at last step */
940 bed->f1 += bezt->vec[1][0];
942 /* increment number of items */
949 /* snap current-frame indicator to 'average time' of selected keyframe */
950 static int graphkeys_cfrasnap_exec(bContext *C, wmOperator *op)
953 ListBase anim_data= {NULL, NULL};
958 /* get editor data */
959 if (ANIM_animdata_get_context(C, &ac) == 0)
960 return OPERATOR_CANCELLED;
963 memset(&bed, 0, sizeof(BeztEditData));
965 /* loop over action data, averaging values */
966 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE| ANIMFILTER_CURVESONLY);
967 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
969 for (ale= anim_data.first; ale; ale= ale->next)
970 ANIM_fcurve_keys_bezier_loop(&bed, ale->key_data, NULL, bezt_calc_average, NULL);
972 BLI_freelistN(&anim_data);
974 /* set the new current frame value, based on the average time */
976 Scene *scene= ac.scene;
977 CFRA= (int)floor((bed.f1 / bed.i1) + 0.5f);
980 /* set notifier tha things have changed */
981 WM_event_add_notifier(C, NC_SCENE|ND_FRAME, ac.scene);
983 return OPERATOR_FINISHED;
986 void GRAPHEDIT_OT_keyframes_cfrasnap (wmOperatorType *ot)
989 ot->name= "Snap Current Frame to Keys";
990 ot->idname= "GRAPHEDIT_OT_keyframes_cfrasnap";
993 ot->exec= graphkeys_cfrasnap_exec;
994 ot->poll= ED_operator_areaactive;
997 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1000 /* ******************** Snap Keyframes Operator *********************** */
1002 /* defines for snap keyframes tool */
1003 EnumPropertyItem prop_graphkeys_snap_types[] = {
1004 {GRAPHKEYS_SNAP_CFRA, "CFRA", "Current frame", ""},
1005 {GRAPHKEYS_SNAP_NEAREST_FRAME, "NEAREST_FRAME", "Nearest Frame", ""}, // XXX as single entry?
1006 {GRAPHKEYS_SNAP_NEAREST_SECOND, "NEAREST_SECOND", "Nearest Second", ""}, // XXX as single entry?
1007 {GRAPHKEYS_SNAP_NEAREST_MARKER, "NEAREST_MARKER", "Nearest Marker", ""},
1008 {GRAPHKEYS_SNAP_HORIZONTAL, "HORIZONTAL", "Flatten Handles", ""},
1009 {0, NULL, NULL, NULL}
1012 /* this function is responsible for snapping keyframes to frame-times */
1013 static void snap_graph_keys(bAnimContext *ac, short mode)
1015 ListBase anim_data = {NULL, NULL};
1020 BeztEditFunc edit_cb;
1023 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE| ANIMFILTER_FOREDIT | ANIMFILTER_CURVESONLY);
1024 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
1026 /* get beztriple editing callbacks */
1027 edit_cb= ANIM_editkeyframes_snap(mode);
1029 memset(&bed, 0, sizeof(BeztEditData));
1030 bed.scene= ac->scene;
1032 /* snap keyframes */
1033 for (ale= anim_data.first; ale; ale= ale->next) {
1034 Object *nob= ANIM_nla_mapping_get(ac, ale);
1037 ANIM_nla_mapping_apply_fcurve(nob, ale->key_data, 0, 1);
1038 ANIM_fcurve_keys_bezier_loop(&bed, ale->key_data, NULL, edit_cb, calchandles_fcurve);
1039 ANIM_nla_mapping_apply_fcurve(nob, ale->key_data, 1, 1);
1042 ANIM_fcurve_keys_bezier_loop(&bed, ale->key_data, NULL, edit_cb, calchandles_fcurve);
1044 BLI_freelistN(&anim_data);
1047 /* ------------------- */
1049 static int graphkeys_snap_exec(bContext *C, wmOperator *op)
1054 /* get editor data */
1055 if (ANIM_animdata_get_context(C, &ac) == 0)
1056 return OPERATOR_CANCELLED;
1058 /* get snapping mode */
1059 mode= RNA_enum_get(op->ptr, "type");
1061 /* snap keyframes */
1062 snap_graph_keys(&ac, mode);
1064 /* validate keyframes after editing */
1065 ANIM_editkeyframes_refresh(&ac);
1067 /* set notifier tha things have changed */
1068 ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_KEYFRAMES_VALUES);
1070 return OPERATOR_FINISHED;
1073 void GRAPHEDIT_OT_keyframes_snap (wmOperatorType *ot)
1076 ot->name= "Snap Keys";
1077 ot->idname= "GRAPHEDIT_OT_keyframes_snap";
1080 ot->invoke= WM_menu_invoke;
1081 ot->exec= graphkeys_snap_exec;
1082 ot->poll= ED_operator_areaactive;
1085 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1088 RNA_def_enum(ot->srna, "type", prop_graphkeys_snap_types, 0, "Type", "");
1091 /* ******************** Mirror Keyframes Operator *********************** */
1093 /* defines for mirror keyframes tool */
1094 EnumPropertyItem prop_graphkeys_mirror_types[] = {
1095 {GRAPHKEYS_MIRROR_CFRA, "CFRA", "Current frame", ""},
1096 {GRAPHKEYS_MIRROR_YAXIS, "YAXIS", "Vertical Axis", ""},
1097 {GRAPHKEYS_MIRROR_XAXIS, "XAXIS", "Horizontal Axis", ""},
1098 {GRAPHKEYS_MIRROR_MARKER, "MARKER", "First Selected Marker", ""},
1099 {0, NULL, NULL, NULL}
1102 /* this function is responsible for mirroring keyframes */
1103 static void mirror_graph_keys(bAnimContext *ac, short mode)
1105 ListBase anim_data = {NULL, NULL};
1110 BeztEditFunc edit_cb;
1112 /* get beztriple editing callbacks */
1113 edit_cb= ANIM_editkeyframes_mirror(mode);
1115 memset(&bed, 0, sizeof(BeztEditData));
1116 bed.scene= ac->scene;
1118 /* for 'first selected marker' mode, need to find first selected marker first! */
1119 // XXX should this be made into a helper func in the API?
1120 if (mode == GRAPHKEYS_MIRROR_MARKER) {
1121 Scene *scene= ac->scene;
1122 TimeMarker *marker= NULL;
1124 /* find first selected marker */
1125 for (marker= scene->markers.first; marker; marker=marker->next) {
1126 if (marker->flag & SELECT) {
1131 /* store marker's time (if available) */
1133 bed.f1= (float)marker->frame;
1139 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE| ANIMFILTER_FOREDIT | ANIMFILTER_CURVESONLY);
1140 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
1142 /* mirror keyframes */
1143 for (ale= anim_data.first; ale; ale= ale->next) {
1144 Object *nob= ANIM_nla_mapping_get(ac, ale);
1147 ANIM_nla_mapping_apply_fcurve(nob, ale->key_data, 0, 1);
1148 ANIM_fcurve_keys_bezier_loop(&bed, ale->key_data, NULL, edit_cb, calchandles_fcurve);
1149 ANIM_nla_mapping_apply_fcurve(nob, ale->key_data, 1, 1);
1152 ANIM_fcurve_keys_bezier_loop(&bed, ale->key_data, NULL, edit_cb, calchandles_fcurve);
1154 BLI_freelistN(&anim_data);
1157 /* ------------------- */
1159 static int graphkeys_mirror_exec(bContext *C, wmOperator *op)
1164 /* get editor data */
1165 if (ANIM_animdata_get_context(C, &ac) == 0)
1166 return OPERATOR_CANCELLED;
1168 /* get mirroring mode */
1169 mode= RNA_enum_get(op->ptr, "type");
1171 /* mirror keyframes */
1172 mirror_graph_keys(&ac, mode);
1174 /* validate keyframes after editing */
1175 ANIM_editkeyframes_refresh(&ac);
1177 /* set notifier tha things have changed */
1178 ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_KEYFRAMES_VALUES);
1180 return OPERATOR_FINISHED;
1183 void GRAPHEDIT_OT_keyframes_mirror (wmOperatorType *ot)
1186 ot->name= "Mirror Keys";
1187 ot->idname= "GRAPHEDIT_OT_keyframes_mirror";
1190 ot->invoke= WM_menu_invoke;
1191 ot->exec= graphkeys_mirror_exec;
1192 ot->poll= ED_operator_areaactive;
1195 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1198 RNA_def_enum(ot->srna, "type", prop_graphkeys_mirror_types, 0, "Type", "");
1201 /* ******************** Smooth Keyframes Operator *********************** */
1203 static int graphkeys_smooth_exec(bContext *C, wmOperator *op)
1206 ListBase anim_data = {NULL, NULL};
1210 /* get editor data */
1211 if (ANIM_animdata_get_context(C, &ac) == 0)
1212 return OPERATOR_CANCELLED;
1215 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE| ANIMFILTER_FOREDIT | ANIMFILTER_CURVESONLY);
1216 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
1218 /* smooth keyframes */
1219 for (ale= anim_data.first; ale; ale= ale->next) {
1220 /* For now, we can only smooth by flattening handles AND smoothing curve values.
1221 * Perhaps the mode argument could be removed, as that functionality is offerred through
1222 * Snap->Flatten Handles anyway.
1224 smooth_fcurve(ale->key_data);
1226 BLI_freelistN(&anim_data);
1228 /* validate keyframes after editing */
1229 ANIM_editkeyframes_refresh(&ac);
1231 /* set notifier tha things have changed */
1232 ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_KEYFRAMES_VALUES);
1234 return OPERATOR_FINISHED;
1237 void GRAPHEDIT_OT_keyframes_smooth (wmOperatorType *ot)
1240 ot->name= "Smooth Keys";
1241 ot->idname= "GRAPHEDIT_OT_keyframes_smooth";
1244 ot->exec= graphkeys_smooth_exec;
1245 ot->poll= ED_operator_areaactive;
1248 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1251 /* ************************************************************************** */