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_utildefines.h"
73 #include "UI_view2d.h"
75 #include "BIF_transform.h"
77 #include "ED_anim_api.h"
78 #include "ED_keyframing.h"
79 #include "ED_keyframes_draw.h"
80 #include "ED_keyframes_edit.h"
81 #include "ED_screen.h"
82 #include "ED_space_api.h"
87 #include "graph_intern.h"
89 /* ************************************************************************** */
90 /* KEYFRAME-RANGE STUFF */
92 /* *************************** Calculate Range ************************** */
94 /* Get the min/max keyframes*/
95 static void get_graph_keyframe_extents (bAnimContext *ac, float *xmin, float *xmax, float *ymin, float *ymax)
97 ListBase anim_data = {NULL, NULL};
101 /* get data to filter, from Dopesheet */
102 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE | ANIMFILTER_SEL | ANIMFILTER_FOREDIT | ANIMFILTER_CURVESONLY);
103 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
105 /* set large values to try to override */
106 if (xmin) *xmin= 999999999.0f;
107 if (xmax) *xmax= -999999999.0f;
108 if (ymin) *ymin= 999999999.0f;
109 if (ymax) *ymax= -999999999.0f;
111 /* check if any channels to set range with */
112 if (anim_data.first) {
113 /* go through channels, finding max extents */
114 for (ale= anim_data.first; ale; ale= ale->next) {
115 Object *nob= NULL; //ANIM_nla_mapping_get(ac, ale);
116 FCurve *fcu= (FCurve *)ale->key_data;
119 /* get range and apply necessary scaling before */
120 calc_fcurve_bounds(fcu, &tmin, &tmax, ymin, ymax);
123 tmin= get_action_frame_inv(nob, tmin);
124 tmax= get_action_frame_inv(nob, tmax);
127 /* try to set cur using these values, if they're more extreme than previously set values */
128 if (xmin) *xmin= MIN2(*xmin, tmin);
129 if (xmax) *xmax= MAX2(*xmax, tmax);
133 BLI_freelistN(&anim_data);
136 /* set default range */
138 if (xmin) *xmin= (float)ac->scene->r.sfra;
139 if (xmax) *xmax= (float)ac->scene->r.efra;
143 if (xmax) *xmax= 100;
151 /* ****************** Automatic Preview-Range Operator ****************** */
153 static int graphkeys_previewrange_exec(bContext *C, wmOperator *op)
159 /* get editor data */
160 if (ANIM_animdata_get_context(C, &ac) == 0)
161 return OPERATOR_CANCELLED;
162 if (ac.scene == NULL)
163 return OPERATOR_CANCELLED;
167 /* set the range directly */
168 get_graph_keyframe_extents(&ac, &min, &max, NULL, NULL);
169 scene->r.psfra= (int)floor(min + 0.5f);
170 scene->r.pefra= (int)floor(max + 0.5f);
172 /* set notifier that things have changed */
173 // XXX err... there's nothing for frame ranges yet, but this should do fine too
174 WM_event_add_notifier(C, NC_SCENE|ND_FRAME, ac.scene);
176 return OPERATOR_FINISHED;
179 void GRAPHEDIT_OT_set_previewrange (wmOperatorType *ot)
182 ot->name= "Auto-Set Preview Range";
183 ot->idname= "GRAPHEDIT_OT_set_previewrange";
186 ot->exec= graphkeys_previewrange_exec;
187 ot->poll= ED_operator_areaactive;
190 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
193 /* ****************** View-All Operator ****************** */
195 static int graphkeys_viewall_exec(bContext *C, wmOperator *op)
201 /* get editor data */
202 if (ANIM_animdata_get_context(C, &ac) == 0)
203 return OPERATOR_CANCELLED;
206 /* set the horizontal range, with an extra offset so that the extreme keys will be in view */
207 get_graph_keyframe_extents(&ac, &v2d->cur.xmin, &v2d->cur.xmax, &v2d->cur.ymin, &v2d->cur.ymax);
209 extra= 0.1f * (v2d->cur.xmax - v2d->cur.xmin);
210 v2d->cur.xmin -= extra;
211 v2d->cur.xmax += extra;
213 extra= 0.1f * (v2d->cur.ymax - v2d->cur.ymin);
214 v2d->cur.ymin -= extra;
215 v2d->cur.ymax += extra;
217 /* do View2D syncing */
218 UI_view2d_sync(CTX_wm_screen(C), CTX_wm_area(C), v2d, V2D_LOCK_COPY);
220 /* set notifier that things have changed */
221 ED_area_tag_redraw(CTX_wm_area(C));
223 return OPERATOR_FINISHED;
226 void GRAPHEDIT_OT_view_all (wmOperatorType *ot)
229 ot->name= "View All";
230 ot->idname= "GRAPHEDIT_OT_view_all";
233 ot->exec= graphkeys_viewall_exec;
234 ot->poll= ED_operator_areaactive;
237 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
241 /* ************************************************************************** */
246 /* ******************** Copy/Paste Keyframes Operator ************************* */
247 /* NOTE: the backend code for this is shared with the dopesheet editor */
249 static short copy_graph_keys (bAnimContext *ac)
251 ListBase anim_data = {NULL, NULL};
254 /* clear buffer first */
258 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE | ANIMFILTER_SEL | ANIMFILTER_CURVESONLY);
259 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
262 ok= copy_animedit_keys(ac, &anim_data);
265 BLI_freelistN(&anim_data);
269 static short paste_graph_keys (bAnimContext *ac)
271 ListBase anim_data = {NULL, NULL};
275 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE | ANIMFILTER_SEL | ANIMFILTER_FOREDIT | ANIMFILTER_CURVESONLY);
276 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
278 /* paste keyframes */
279 ok= paste_animedit_keys(ac, &anim_data);
282 BLI_freelistN(&anim_data);
285 /* ------------------- */
287 static int graphkeys_copy_exec(bContext *C, wmOperator *op)
291 /* get editor data */
292 if (ANIM_animdata_get_context(C, &ac) == 0)
293 return OPERATOR_CANCELLED;
296 if (copy_graph_keys(&ac)) {
297 // XXX errors - need a way to inform the user
298 printf("Graph Copy: No keyframes copied to copy-paste buffer\n");
301 /* set notifier tha things have changed */
302 ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_KEYFRAMES_VALUES);
304 return OPERATOR_FINISHED;
307 void GRAPHEDIT_OT_keyframes_copy (wmOperatorType *ot)
310 ot->name= "Copy Keyframes";
311 ot->idname= "GRAPHEDIT_OT_keyframes_copy";
314 ot->exec= graphkeys_copy_exec;
315 ot->poll= ED_operator_areaactive;
318 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
323 static int graphkeys_paste_exec(bContext *C, wmOperator *op)
327 /* get editor data */
328 if (ANIM_animdata_get_context(C, &ac) == 0)
329 return OPERATOR_CANCELLED;
331 /* paste keyframes */
332 if (paste_graph_keys(&ac)) {
333 // XXX errors - need a way to inform the user
334 printf("Graph Paste: Nothing to paste, as Copy-Paste buffer was empty.\n");
337 /* validate keyframes after editing */
338 ANIM_editkeyframes_refresh(&ac);
340 /* set notifier tha things have changed */
341 ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_KEYFRAMES_VALUES);
343 return OPERATOR_FINISHED;
346 void GRAPHEDIT_OT_keyframes_paste (wmOperatorType *ot)
349 ot->name= "Paste Keyframes";
350 ot->idname= "GRAPHEDIT_OT_keyframes_paste";
353 ot->exec= graphkeys_paste_exec;
354 ot->poll= ED_operator_areaactive;
357 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
360 /* ******************** Duplicate Keyframes Operator ************************* */
362 static void duplicate_graph_keys (bAnimContext *ac)
364 ListBase anim_data = {NULL, NULL};
369 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE| ANIMFILTER_FOREDIT | ANIMFILTER_CURVESONLY);
370 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
372 /* loop through filtered data and delete selected keys */
373 for (ale= anim_data.first; ale; ale= ale->next) {
374 duplicate_fcurve_keys((FCurve *)ale->key_data);
377 /* free filtered list */
378 BLI_freelistN(&anim_data);
381 /* ------------------- */
383 static int graphkeys_duplicate_exec(bContext *C, wmOperator *op)
387 /* get editor data */
388 if (ANIM_animdata_get_context(C, &ac) == 0)
389 return OPERATOR_CANCELLED;
391 /* duplicate keyframes */
392 duplicate_graph_keys(&ac);
394 /* validate keyframes after editing */
395 ANIM_editkeyframes_refresh(&ac);
397 /* set notifier tha things have changed */
398 ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_KEYFRAMES_VALUES);
400 return OPERATOR_FINISHED;
403 static int graphkeys_duplicate_invoke(bContext *C, wmOperator *op, wmEvent *event)
405 graphkeys_duplicate_exec(C, op);
407 RNA_int_set(op->ptr, "mode", TFM_TRANSLATION);
408 WM_operator_name_call(C, "TFM_OT_transform", WM_OP_INVOKE_REGION_WIN, op->ptr);
410 return OPERATOR_FINISHED;
413 void GRAPHEDIT_OT_keyframes_duplicate (wmOperatorType *ot)
416 ot->name= "Duplicate Keyframes";
417 ot->idname= "GRAPHEDIT_OT_keyframes_duplicate";
420 ot->invoke= graphkeys_duplicate_invoke;
421 ot->exec= graphkeys_duplicate_exec;
422 ot->poll= ED_operator_areaactive;
425 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
427 /* to give to transform */
428 RNA_def_int(ot->srna, "mode", TFM_TRANSLATION, 0, INT_MAX, "Mode", "", 0, INT_MAX);
431 /* ******************** Delete Keyframes Operator ************************* */
433 static void delete_graph_keys (bAnimContext *ac)
435 ListBase anim_data = {NULL, NULL};
440 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE| ANIMFILTER_FOREDIT | ANIMFILTER_CURVESONLY);
441 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
443 /* loop through filtered data and delete selected keys */
444 for (ale= anim_data.first; ale; ale= ale->next) {
445 delete_fcurve_keys((FCurve *)ale->key_data); // XXX... this doesn't delete empty curves anymore
448 /* free filtered list */
449 BLI_freelistN(&anim_data);
452 /* ------------------- */
454 static int graphkeys_delete_exec(bContext *C, wmOperator *op)
458 /* get editor data */
459 if (ANIM_animdata_get_context(C, &ac) == 0)
460 return OPERATOR_CANCELLED;
462 /* delete keyframes */
463 delete_graph_keys(&ac);
465 /* validate keyframes after editing */
466 ANIM_editkeyframes_refresh(&ac);
468 /* set notifier tha things have changed */
469 ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_KEYFRAMES_VALUES);
471 return OPERATOR_FINISHED;
474 void GRAPHEDIT_OT_keyframes_delete (wmOperatorType *ot)
477 ot->name= "Delete Keyframes";
478 ot->idname= "GRAPHEDIT_OT_keyframes_delete";
481 ot->invoke= WM_operator_confirm;
482 ot->exec= graphkeys_delete_exec;
483 ot->poll= ED_operator_areaactive;
486 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
489 /* ******************** Clean Keyframes Operator ************************* */
491 static void clean_graph_keys (bAnimContext *ac, float thresh)
493 ListBase anim_data = {NULL, NULL};
498 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE| ANIMFILTER_FOREDIT | ANIMFILTER_SEL | ANIMFILTER_CURVESONLY);
499 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
501 /* loop through filtered data and clean curves */
502 for (ale= anim_data.first; ale; ale= ale->next)
503 clean_fcurve((FCurve *)ale->key_data, thresh);
506 BLI_freelistN(&anim_data);
509 /* ------------------- */
511 static int graphkeys_clean_exec(bContext *C, wmOperator *op)
516 /* get editor data */
517 if (ANIM_animdata_get_context(C, &ac) == 0)
518 return OPERATOR_CANCELLED;
520 /* get cleaning threshold */
521 thresh= RNA_float_get(op->ptr, "threshold");
523 /* clean keyframes */
524 clean_graph_keys(&ac, thresh);
526 /* validate keyframes after editing */
527 ANIM_editkeyframes_refresh(&ac);
529 /* set notifier tha things have changed */
530 ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_KEYFRAMES_VALUES);
532 return OPERATOR_FINISHED;
535 void GRAPHEDIT_OT_keyframes_clean (wmOperatorType *ot)
538 ot->name= "Clean Keyframes";
539 ot->idname= "GRAPHEDIT_OT_keyframes_clean";
542 //ot->invoke= // XXX we need that number popup for this!
543 ot->exec= graphkeys_clean_exec;
544 ot->poll= ED_operator_areaactive;
547 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
550 RNA_def_float(ot->srna, "threshold", 0.001f, 0.0f, FLT_MAX, "Threshold", "", 0.0f, 1000.0f);
553 /* ******************** Sample Keyframes Operator *********************** */
555 // XXX some of the common parts (with DopeSheet) should be unified in animation module...
557 /* little cache for values... */
558 typedef struct tempFrameValCache {
562 /* Evaluates the curves between each selected keyframe on each frame, and keys the value */
563 static void sample_graph_keys (bAnimContext *ac)
565 ListBase anim_data = {NULL, NULL};
570 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE| ANIMFILTER_FOREDIT | ANIMFILTER_CURVESONLY);
571 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
573 /* loop through filtered data and add keys between selected keyframes on every frame */
574 for (ale= anim_data.first; ale; ale= ale->next) {
575 FCurve *fcu= (FCurve *)ale->key_data;
576 BezTriple *bezt, *start=NULL, *end=NULL;
577 tempFrameValCache *value_cache, *fp;
581 /* find selected keyframes... once pair has been found, add keyframes */
582 for (i=0, bezt=fcu->bezt; i < fcu->totvert; i++, bezt++) {
583 /* check if selected, and which end this is */
584 if (BEZSELECTED(bezt)) {
589 /* cache values then add keyframes using these values, as adding
590 * keyframes while sampling will affect the outcome...
592 range= (int)( ceil(end->vec[1][0] - start->vec[1][0]) );
593 sfra= (int)( floor(start->vec[1][0]) );
596 value_cache= MEM_callocN(sizeof(tempFrameValCache)*range, "IcuFrameValCache");
599 for (n=0, fp=value_cache; n<range && fp; n++, fp++) {
600 fp->frame= (float)(sfra + n);
601 fp->val= evaluate_fcurve(fcu, fp->frame);
604 /* add keyframes with these */
605 for (n=0, fp=value_cache; n<range && fp; n++, fp++) {
606 insert_vert_fcurve(fcu, fp->frame, fp->val, 1);
609 /* free temp cache */
610 MEM_freeN(value_cache);
612 /* as we added keyframes, we need to compensate so that bezt is at the right place */
613 bezt = fcu->bezt + i + range - 1;
617 /* bezt was selected, so it now marks the start of a whole new chain to search */
622 /* just set start keyframe */
629 /* recalculate channel's handles? */
630 calchandles_fcurve(fcu);
633 /* admin and redraws */
634 BLI_freelistN(&anim_data);
637 /* ------------------- */
639 static int graphkeys_sample_exec(bContext *C, wmOperator *op)
643 /* get editor data */
644 if (ANIM_animdata_get_context(C, &ac) == 0)
645 return OPERATOR_CANCELLED;
647 /* sample keyframes */
648 sample_graph_keys(&ac);
650 /* validate keyframes after editing */
651 ANIM_editkeyframes_refresh(&ac);
653 /* set notifier tha things have changed */
654 ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_KEYFRAMES_VALUES);
656 return OPERATOR_FINISHED;
659 void GRAPHEDIT_OT_keyframes_sample (wmOperatorType *ot)
662 ot->name= "Sample Keyframes";
663 ot->idname= "GRAPHEDIT_OT_keyframes_sample";
666 ot->exec= graphkeys_sample_exec;
667 ot->poll= ED_operator_areaactive;
670 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
674 /* ************************************************************************** */
677 /* ******************** Set Extrapolation-Type Operator *********************** */
679 /* defines for set extrapolation-type for selected keyframes tool */
680 EnumPropertyItem prop_graphkeys_expo_types[] = {
681 {FCURVE_EXTRAPOLATE_CONSTANT, "CONSTANT", "Constant Extrapolation", ""},
682 {FCURVE_EXTRAPOLATE_LINEAR, "LINEAR", "Linear Extrapolation", ""},
683 {0, NULL, NULL, NULL}
686 /* this function is responsible for setting extrapolation mode for keyframes */
687 static void setexpo_graph_keys(bAnimContext *ac, short mode)
689 ListBase anim_data = {NULL, NULL};
694 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE| ANIMFILTER_FOREDIT | ANIMFILTER_CURVESONLY);
695 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
697 /* loop through setting mode per F-Curve */
698 for (ale= anim_data.first; ale; ale= ale->next) {
699 FCurve *fcu= (FCurve *)ale->data;
704 BLI_freelistN(&anim_data);
707 /* ------------------- */
709 static int graphkeys_expo_exec(bContext *C, wmOperator *op)
714 /* get editor data */
715 if (ANIM_animdata_get_context(C, &ac) == 0)
716 return OPERATOR_CANCELLED;
718 /* get handle setting mode */
719 mode= RNA_enum_get(op->ptr, "type");
721 /* set handle type */
722 setexpo_graph_keys(&ac, mode);
724 /* validate keyframes after editing */
725 ANIM_editkeyframes_refresh(&ac);
727 /* set notifier tha things have changed */
728 ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_KEYFRAMES_VALUES);
730 return OPERATOR_FINISHED;
733 void GRAPHEDIT_OT_keyframes_extrapolation_type (wmOperatorType *ot)
736 ot->name= "Set Keyframe Extrapolation";
737 ot->idname= "GRAPHEDIT_OT_keyframes_extrapolation_type";
740 ot->invoke= WM_menu_invoke;
741 ot->exec= graphkeys_expo_exec;
742 ot->poll= ED_operator_areaactive;
745 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
748 RNA_def_enum(ot->srna, "type", prop_graphkeys_expo_types, 0, "Type", "");
751 /* ******************** Set Interpolation-Type Operator *********************** */
753 /* defines for set ipo-type for selected keyframes tool */
754 EnumPropertyItem prop_graphkeys_ipo_types[] = {
755 {BEZT_IPO_CONST, "CONSTANT", "Constant Interpolation", ""},
756 {BEZT_IPO_LIN, "LINEAR", "Linear Interpolation", ""},
757 {BEZT_IPO_BEZ, "BEZIER", "Bezier Interpolation", ""},
758 {0, NULL, NULL, NULL}
761 /* this function is responsible for setting interpolation mode for keyframes */
762 static void setipo_graph_keys(bAnimContext *ac, short mode)
764 ListBase anim_data = {NULL, NULL};
767 BeztEditFunc set_cb= ANIM_editkeyframes_ipo(mode);
770 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE| ANIMFILTER_FOREDIT | ANIMFILTER_CURVESONLY);
771 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
773 /* loop through setting BezTriple interpolation
774 * Note: we do not supply BeztEditData to the looper yet. Currently that's not necessary here...
776 for (ale= anim_data.first; ale; ale= ale->next)
777 ANIM_fcurve_keys_bezier_loop(NULL, ale->key_data, NULL, set_cb, calchandles_fcurve);
780 BLI_freelistN(&anim_data);
783 /* ------------------- */
785 static int graphkeys_ipo_exec(bContext *C, wmOperator *op)
790 /* get editor data */
791 if (ANIM_animdata_get_context(C, &ac) == 0)
792 return OPERATOR_CANCELLED;
794 /* get handle setting mode */
795 mode= RNA_enum_get(op->ptr, "type");
797 /* set handle type */
798 setipo_graph_keys(&ac, mode);
800 /* validate keyframes after editing */
801 ANIM_editkeyframes_refresh(&ac);
803 /* set notifier tha things have changed */
804 ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_KEYFRAMES_VALUES);
806 return OPERATOR_FINISHED;
809 void GRAPHEDIT_OT_keyframes_interpolation_type (wmOperatorType *ot)
812 ot->name= "Set Keyframe Interpolation";
813 ot->idname= "GRAPHEDIT_OT_keyframes_interpolation_type";
816 ot->invoke= WM_menu_invoke;
817 ot->exec= graphkeys_ipo_exec;
818 ot->poll= ED_operator_areaactive;
821 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
824 RNA_def_enum(ot->srna, "type", prop_graphkeys_ipo_types, 0, "Type", "");
827 /* ******************** Set Handle-Type Operator *********************** */
829 /* defines for set handle-type for selected keyframes tool */
830 EnumPropertyItem prop_graphkeys_handletype_types[] = {
831 {HD_AUTO, "AUTO", "Auto Handles", ""},
832 {HD_VECT, "VECTOR", "Vector Handles", ""},
833 {HD_FREE, "FREE", "Free Handles", ""},
834 {HD_ALIGN, "ALIGN", "Aligned Handles", ""},
835 // {-1, "TOGGLE", "Toggle between Free and Aligned Handles", ""},
836 {0, NULL, NULL, NULL}
839 /* this function is responsible for setting handle-type of selected keyframes */
840 static void sethandles_graph_keys(bAnimContext *ac, short mode)
842 ListBase anim_data = {NULL, NULL};
845 BeztEditFunc set_cb= ANIM_editkeyframes_handles(mode);
848 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE| ANIMFILTER_FOREDIT | ANIMFILTER_CURVESONLY);
849 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
851 /* loop through setting flags for handles
852 * Note: we do not supply BeztEditData to the looper yet. Currently that's not necessary here...
854 // XXX we might need to supply BeztEditData to get it to only affect selected handles
855 for (ale= anim_data.first; ale; ale= ale->next) {
857 BeztEditFunc toggle_cb;
859 /* check which type of handle to set (free or aligned)
860 * - check here checks for handles with free alignment already
862 if (ANIM_fcurve_keys_bezier_loop(NULL, ale->key_data, NULL, set_cb, NULL))
863 toggle_cb= ANIM_editkeyframes_handles(HD_FREE);
865 toggle_cb= ANIM_editkeyframes_handles(HD_ALIGN);
867 /* set handle-type */
868 ANIM_fcurve_keys_bezier_loop(NULL, ale->key_data, NULL, toggle_cb, calchandles_fcurve);
871 /* directly set handle-type */
872 ANIM_fcurve_keys_bezier_loop(NULL, ale->key_data, NULL, set_cb, calchandles_fcurve);
877 BLI_freelistN(&anim_data);
880 /* ------------------- */
882 static int graphkeys_handletype_exec(bContext *C, wmOperator *op)
887 /* get editor data */
888 if (ANIM_animdata_get_context(C, &ac) == 0)
889 return OPERATOR_CANCELLED;
891 /* get handle setting mode */
892 mode= RNA_enum_get(op->ptr, "type");
894 /* set handle type */
895 sethandles_graph_keys(&ac, mode);
897 /* validate keyframes after editing */
898 ANIM_editkeyframes_refresh(&ac);
900 /* set notifier tha things have changed */
901 ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_KEYFRAMES_VALUES);
903 return OPERATOR_FINISHED;
906 void GRAPHEDIT_OT_keyframes_handletype (wmOperatorType *ot)
909 ot->name= "Set Keyframe Handle Type";
910 ot->idname= "GRAPHEDIT_OT_keyframes_handletype";
913 ot->invoke= WM_menu_invoke;
914 ot->exec= graphkeys_handletype_exec;
915 ot->poll= ED_operator_areaactive;
918 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
921 RNA_def_enum(ot->srna, "type", prop_graphkeys_handletype_types, 0, "Type", "");
924 /* ************************************************************************** */
925 /* TRANSFORM STUFF */
927 /* ***************** Snap Current Frame Operator *********************** */
929 /* helper callback for graphkeys_cfrasnap_exec() -> used to help get the average time of all selected beztriples */
930 // TODO: if some other code somewhere needs this, it'll be time to port this over to keyframes_edit.c!!!
931 static short bezt_calc_average(BeztEditData *bed, BezTriple *bezt)
933 /* only if selected */
934 if (bezt->f2 & SELECT) {
935 /* store average time in float (only do rounding at last step */
936 bed->f1 += bezt->vec[1][0];
938 /* increment number of items */
945 /* snap current-frame indicator to 'average time' of selected keyframe */
946 static int graphkeys_cfrasnap_exec(bContext *C, wmOperator *op)
949 ListBase anim_data= {NULL, NULL};
954 /* get editor data */
955 if (ANIM_animdata_get_context(C, &ac) == 0)
956 return OPERATOR_CANCELLED;
959 memset(&bed, 0, sizeof(BeztEditData));
961 /* loop over action data, averaging values */
962 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE| ANIMFILTER_CURVESONLY);
963 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
965 for (ale= anim_data.first; ale; ale= ale->next)
966 ANIM_fcurve_keys_bezier_loop(&bed, ale->key_data, NULL, bezt_calc_average, NULL);
968 BLI_freelistN(&anim_data);
970 /* set the new current frame value, based on the average time */
972 Scene *scene= ac.scene;
973 CFRA= (int)floor((bed.f1 / bed.i1) + 0.5f);
976 /* set notifier tha things have changed */
977 WM_event_add_notifier(C, NC_SCENE|ND_FRAME, ac.scene);
979 return OPERATOR_FINISHED;
982 void GRAPHEDIT_OT_keyframes_cfrasnap (wmOperatorType *ot)
985 ot->name= "Snap Current Frame to Keys";
986 ot->idname= "GRAPHEDIT_OT_keyframes_cfrasnap";
989 ot->exec= graphkeys_cfrasnap_exec;
990 ot->poll= ED_operator_areaactive;
993 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
996 /* ******************** Snap Keyframes Operator *********************** */
998 /* defines for snap keyframes tool */
999 EnumPropertyItem prop_graphkeys_snap_types[] = {
1000 {GRAPHKEYS_SNAP_CFRA, "CFRA", "Current frame", ""},
1001 {GRAPHKEYS_SNAP_NEAREST_FRAME, "NEAREST_FRAME", "Nearest Frame", ""}, // XXX as single entry?
1002 {GRAPHKEYS_SNAP_NEAREST_SECOND, "NEAREST_SECOND", "Nearest Second", ""}, // XXX as single entry?
1003 {GRAPHKEYS_SNAP_NEAREST_MARKER, "NEAREST_MARKER", "Nearest Marker", ""},
1004 {GRAPHKEYS_SNAP_HORIZONTAL, "HORIZONTAL", "Flatten Handles", ""},
1005 {0, NULL, NULL, NULL}
1008 /* this function is responsible for snapping keyframes to frame-times */
1009 static void snap_graph_keys(bAnimContext *ac, short mode)
1011 ListBase anim_data = {NULL, NULL};
1016 BeztEditFunc edit_cb;
1019 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE| ANIMFILTER_FOREDIT | ANIMFILTER_CURVESONLY);
1020 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
1022 /* get beztriple editing callbacks */
1023 edit_cb= ANIM_editkeyframes_snap(mode);
1025 memset(&bed, 0, sizeof(BeztEditData));
1026 bed.scene= ac->scene;
1028 /* snap keyframes */
1029 for (ale= anim_data.first; ale; ale= ale->next) {
1030 Object *nob= ANIM_nla_mapping_get(ac, ale);
1033 ANIM_nla_mapping_apply_fcurve(nob, ale->key_data, 0, 1);
1034 ANIM_fcurve_keys_bezier_loop(&bed, ale->key_data, NULL, edit_cb, calchandles_fcurve);
1035 ANIM_nla_mapping_apply_fcurve(nob, ale->key_data, 1, 1);
1038 ANIM_fcurve_keys_bezier_loop(&bed, ale->key_data, NULL, edit_cb, calchandles_fcurve);
1040 BLI_freelistN(&anim_data);
1043 /* ------------------- */
1045 static int graphkeys_snap_exec(bContext *C, wmOperator *op)
1050 /* get editor data */
1051 if (ANIM_animdata_get_context(C, &ac) == 0)
1052 return OPERATOR_CANCELLED;
1054 /* get snapping mode */
1055 mode= RNA_enum_get(op->ptr, "type");
1057 /* snap keyframes */
1058 snap_graph_keys(&ac, mode);
1060 /* validate keyframes after editing */
1061 ANIM_editkeyframes_refresh(&ac);
1063 /* set notifier tha things have changed */
1064 ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_KEYFRAMES_VALUES);
1066 return OPERATOR_FINISHED;
1069 void GRAPHEDIT_OT_keyframes_snap (wmOperatorType *ot)
1072 ot->name= "Snap Keys";
1073 ot->idname= "GRAPHEDIT_OT_keyframes_snap";
1076 ot->invoke= WM_menu_invoke;
1077 ot->exec= graphkeys_snap_exec;
1078 ot->poll= ED_operator_areaactive;
1081 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1084 RNA_def_enum(ot->srna, "type", prop_graphkeys_snap_types, 0, "Type", "");
1087 /* ******************** Mirror Keyframes Operator *********************** */
1089 /* defines for mirror keyframes tool */
1090 EnumPropertyItem prop_graphkeys_mirror_types[] = {
1091 {GRAPHKEYS_MIRROR_CFRA, "CFRA", "Current frame", ""},
1092 {GRAPHKEYS_MIRROR_YAXIS, "YAXIS", "Vertical Axis", ""},
1093 {GRAPHKEYS_MIRROR_XAXIS, "XAXIS", "Horizontal Axis", ""},
1094 {GRAPHKEYS_MIRROR_MARKER, "MARKER", "First Selected Marker", ""},
1095 {0, NULL, NULL, NULL}
1098 /* this function is responsible for mirroring keyframes */
1099 static void mirror_graph_keys(bAnimContext *ac, short mode)
1101 ListBase anim_data = {NULL, NULL};
1106 BeztEditFunc edit_cb;
1108 /* get beztriple editing callbacks */
1109 edit_cb= ANIM_editkeyframes_mirror(mode);
1111 memset(&bed, 0, sizeof(BeztEditData));
1112 bed.scene= ac->scene;
1114 /* for 'first selected marker' mode, need to find first selected marker first! */
1115 // XXX should this be made into a helper func in the API?
1116 if (mode == GRAPHKEYS_MIRROR_MARKER) {
1117 Scene *scene= ac->scene;
1118 TimeMarker *marker= NULL;
1120 /* find first selected marker */
1121 for (marker= scene->markers.first; marker; marker=marker->next) {
1122 if (marker->flag & SELECT) {
1127 /* store marker's time (if available) */
1129 bed.f1= (float)marker->frame;
1135 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE| ANIMFILTER_FOREDIT | ANIMFILTER_CURVESONLY);
1136 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
1138 /* mirror keyframes */
1139 for (ale= anim_data.first; ale; ale= ale->next) {
1140 Object *nob= ANIM_nla_mapping_get(ac, ale);
1143 ANIM_nla_mapping_apply_fcurve(nob, ale->key_data, 0, 1);
1144 ANIM_fcurve_keys_bezier_loop(&bed, ale->key_data, NULL, edit_cb, calchandles_fcurve);
1145 ANIM_nla_mapping_apply_fcurve(nob, ale->key_data, 1, 1);
1148 ANIM_fcurve_keys_bezier_loop(&bed, ale->key_data, NULL, edit_cb, calchandles_fcurve);
1150 BLI_freelistN(&anim_data);
1153 /* ------------------- */
1155 static int graphkeys_mirror_exec(bContext *C, wmOperator *op)
1160 /* get editor data */
1161 if (ANIM_animdata_get_context(C, &ac) == 0)
1162 return OPERATOR_CANCELLED;
1164 /* get mirroring mode */
1165 mode= RNA_enum_get(op->ptr, "type");
1167 /* mirror keyframes */
1168 mirror_graph_keys(&ac, mode);
1170 /* validate keyframes after editing */
1171 ANIM_editkeyframes_refresh(&ac);
1173 /* set notifier tha things have changed */
1174 ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_KEYFRAMES_VALUES);
1176 return OPERATOR_FINISHED;
1179 void GRAPHEDIT_OT_keyframes_mirror (wmOperatorType *ot)
1182 ot->name= "Mirror Keys";
1183 ot->idname= "GRAPHEDIT_OT_keyframes_mirror";
1186 ot->invoke= WM_menu_invoke;
1187 ot->exec= graphkeys_mirror_exec;
1188 ot->poll= ED_operator_areaactive;
1191 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1194 RNA_def_enum(ot->srna, "type", prop_graphkeys_mirror_types, 0, "Type", "");
1197 /* ******************** Smooth Keyframes Operator *********************** */
1199 static int graphkeys_smooth_exec(bContext *C, wmOperator *op)
1202 ListBase anim_data = {NULL, NULL};
1206 /* get editor data */
1207 if (ANIM_animdata_get_context(C, &ac) == 0)
1208 return OPERATOR_CANCELLED;
1211 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE| ANIMFILTER_FOREDIT | ANIMFILTER_CURVESONLY);
1212 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
1214 /* smooth keyframes */
1215 for (ale= anim_data.first; ale; ale= ale->next) {
1216 /* For now, we can only smooth by flattening handles AND smoothing curve values.
1217 * Perhaps the mode argument could be removed, as that functionality is offerred through
1218 * Snap->Flatten Handles anyway.
1220 smooth_fcurve(ale->key_data);
1222 BLI_freelistN(&anim_data);
1224 /* validate keyframes after editing */
1225 ANIM_editkeyframes_refresh(&ac);
1227 /* set notifier tha things have changed */
1228 ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_KEYFRAMES_VALUES);
1230 return OPERATOR_FINISHED;
1233 void GRAPHEDIT_OT_keyframes_smooth (wmOperatorType *ot)
1236 ot->name= "Smooth Keys";
1237 ot->idname= "GRAPHEDIT_OT_keyframes_smooth";
1240 ot->exec= graphkeys_smooth_exec;
1241 ot->poll= ED_operator_areaactive;
1244 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1247 /* ************************************************************************** */