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 "ED_anim_api.h"
76 #include "ED_keyframing.h"
77 #include "ED_keyframes_draw.h"
78 #include "ED_keyframes_edit.h"
79 #include "ED_screen.h"
80 #include "ED_space_api.h"
85 #include "graph_intern.h"
87 #if 0 // XXX code to be sanitied for new system
89 /* ************************************************************************** */
90 /* KEYFRAME-RANGE STUFF */
92 /* *************************** Calculate Range ************************** */
94 /* Get the min/max keyframes*/
95 static void get_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;
112 if (ymin) *ymin= -10;
115 /* check if any channels to set range with */
116 if (anim_data.first) {
117 /* go through channels, finding max extents */
118 for (ale= anim_data.first; ale; ale= ale->next) {
119 Object *nob= ANIM_nla_mapping_get(ac, ale);
120 FCurve *fcu= (FCurve *)ale->key_data;
123 /* get range and apply necessary scaling before */
124 calc_fcurve_range(fcu, &tmin, &tmax);
127 tmin= get_action_frame_inv(nob, tmin);
128 tmax= get_action_frame_inv(nob, tmax);
131 /* try to set cur using these values, if they're more extreme than previously set values */
132 if (xmin) *xmin= MIN2(*xmin, tmin);
133 if (xmax) *xmax= MAX2(*xmax, tmax);
137 BLI_freelistN(&anim_data);
140 /* set default range */
142 if (xmin) *xmin= (float)ac->scene->r.sfra;
143 if (xmax) *xmax= (float)ac->scene->r.efra;
147 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_keyframe_extents(&ac, &min, &max);
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_keyframe_extents(&ac, &v2d->cur.xmin, &v2d->cur.xmax, &v2d->cur.ymin, &v2d->cur.ymax);
210 extra= 0.05f * (v2d->cur.xmax - v2d->cur.xmin);
211 v2d->cur.xmin -= extra;
212 v2d->cur.xmax += extra;
214 extra= 0.05f * (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;
241 /* ************************************************************************** */
247 /* ******************** Copy/Paste Keyframes Operator ************************* */
248 /* - The copy/paste buffer currently stores a set of Action Channels, with temporary
249 * IPO-blocks, and also temporary IpoCurves which only contain the selected keyframes.
250 * - Only pastes between compatable data is possible (i.e. same achan->name, ipo-curve type, etc.)
251 * Unless there is only one element in the buffer, names are also tested to check for compatability.
252 * - All pasted frames are offset by the same amount. This is calculated as the difference in the times of
253 * the current frame and the 'first keyframe' (i.e. the earliest one in all channels).
254 * - The earliest frame is calculated per copy operation.
258 /* globals for copy/paste data (like for other copy/paste buffers) */
259 ListBase actcopybuf = {NULL, NULL};
260 static float actcopy_firstframe= 999999999.0f;
262 /* This function frees any MEM_calloc'ed copy/paste buffer data */
263 // XXX find some header to put this in!
264 void free_actcopybuf ()
268 /* free_fcurve() frees F-Curve memory too, but we don't need to do remlink first, as we're freeing all
269 * channels anyway, and the freeing func only cares about the data it's given
271 for (fcu= actcopybuf.first; fcu; fcu= fcn) {
276 actcopybuf.first= actcopybuf.last= NULL;
277 actcopy_firstframe= 999999999.0f;
281 /* ------------------- */
283 /* This function adds data to the copy/paste buffer, freeing existing data first
284 * Only the selected action channels gets their selected keyframes copied.
286 static short copy_graph_keys (bAnimContext *ac)
288 #if 0 // XXX old animation system
289 ListBase anim_data = {NULL, NULL};
293 /* clear buffer first */
297 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE| ANIMFILTER_SEL | ANIMFILTER_IPOKEYS);
298 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
300 /* assume that each of these is an ipo-block */
301 for (ale= anim_data.first; ale; ale= ale->next) {
302 bActionChannel *achan;
303 Ipo *ipo= ale->key_data;
309 /* coerce an action-channel out of owner */
310 if (ale->ownertype == ANIMTYPE_ACHAN) {
311 bActionChannel *achanO= ale->owner;
312 achan= MEM_callocN(sizeof(bActionChannel), "ActCopyPasteAchan");
313 strcpy(achan->name, achanO->name);
315 else if (ale->ownertype == ANIMTYPE_SHAPEKEY) {
316 achan= MEM_callocN(sizeof(bActionChannel), "ActCopyPasteAchan");
317 strcpy(achan->name, "#ACP_ShapeKey");
321 BLI_addtail(&actcopybuf, achan);
323 /* add constraint channel if needed, then add new ipo-block */
324 if (ale->type == ANIMTYPE_CONCHAN) {
325 bConstraintChannel *conchanO= ale->data;
326 bConstraintChannel *conchan;
328 conchan= MEM_callocN(sizeof(bConstraintChannel), "ActCopyPasteConchan");
329 strcpy(conchan->name, conchanO->name);
330 BLI_addtail(&achan->constraintChannels, conchan);
332 conchan->ipo= ipn= MEM_callocN(sizeof(Ipo), "ActCopyPasteIpo");
335 achan->ipo= ipn= MEM_callocN(sizeof(Ipo), "ActCopyPasteIpo");
337 ipn->blocktype = ipo->blocktype;
339 /* now loop through curves, and only copy selected keyframes */
340 for (icu= ipo->curve.first; icu; icu= icu->next) {
341 /* allocate a new curve */
342 icn= MEM_callocN(sizeof(IpoCurve), "ActCopyPasteIcu");
343 icn->blocktype = icu->blocktype;
344 icn->adrcode = icu->adrcode;
345 BLI_addtail(&ipn->curve, icn);
347 /* find selected BezTriples to add to the buffer (and set first frame) */
348 for (i=0, bezt=icu->bezt; i < icu->totvert; i++, bezt++) {
349 if (BEZSELECTED(bezt)) {
350 /* add to buffer ipo-curve */
351 //insert_bezt_icu(icn, bezt); // XXX
353 /* check if this is the earliest frame encountered so far */
354 if (bezt->vec[1][0] < actcopy_firstframe)
355 actcopy_firstframe= bezt->vec[1][0];
361 /* check if anything ended up in the buffer */
362 if (ELEM(NULL, actcopybuf.first, actcopybuf.last))
363 // error("Nothing copied to buffer");
366 /* free temp memory */
367 BLI_freelistN(&anim_data);
368 #endif // XXX old animation system
370 /* everything went fine */
374 static short paste_graph_keys (bAnimContext *ac)
376 #if 0 // XXX old animation system
377 ListBase anim_data = {NULL, NULL};
381 const Scene *scene= (ac->scene);
382 const float offset = (float)(CFRA - actcopy_firstframe);
383 char *actname = NULL, *conname = NULL;
386 /* check if buffer is empty */
387 if (ELEM(NULL, actcopybuf.first, actcopybuf.last)) {
388 //error("No data in buffer to paste");
391 /* check if single channel in buffer (disregard names if so) */
392 if (actcopybuf.first == actcopybuf.last)
396 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE| ANIMFILTER_SEL | ANIMFILTER_FOREDIT | ANIMFILTER_IPOKEYS);
397 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
399 /* from selected channels */
400 for (ale= anim_data.first; ale; ale= ale->next) {
402 bActionChannel *achan;
407 /* find suitable IPO-block from buffer to paste from */
408 for (achan= actcopybuf.first; achan; achan= achan->next) {
409 /* try to match data */
410 if (ale->ownertype == ANIMTYPE_ACHAN) {
411 bActionChannel *achant= ale->owner;
413 /* check if we have a corresponding action channel */
414 if ((no_name) || (strcmp(achan->name, achant->name)==0)) {
415 actname= achant->name;
417 /* check if this is a constraint channel */
418 if (ale->type == ANIMTYPE_CONCHAN) {
419 bConstraintChannel *conchant= ale->data;
420 bConstraintChannel *conchan;
422 for (conchan=achan->constraintChannels.first; conchan; conchan=conchan->next) {
423 if (strcmp(conchan->name, conchant->name)==0) {
424 conname= conchant->name;
425 ipo_src= conchan->ipo;
437 else if (ale->ownertype == ANIMTYPE_SHAPEKEY) {
438 /* check if this action channel is "#ACP_ShapeKey" */
439 if ((no_name) || (strcmp(achan->name, "#ACP_ShapeKey")==0)) {
447 /* this shouldn't happen, but it might */
451 /* loop over curves, pasting keyframes */
452 for (ico= ipo_src->curve.first; ico; ico= ico->next) {
453 /* get IPO-curve to paste to (IPO-curve might not exist for destination, so gets created) */
454 //icu= verify_ipocurve(ale->id, ico->blocktype, actname, conname, NULL, ico->adrcode, 1);
458 /* just start pasting, with the the first keyframe on the current frame, and so on */
459 for (i=0, bezt=ico->bezt; i < ico->totvert; i++, bezt++) {
460 /* temporarily apply offset to src beztriple while copying */
461 bezt->vec[0][0] += offset;
462 bezt->vec[1][0] += offset;
463 bezt->vec[2][0] += offset;
465 /* insert the keyframe */
466 //insert_bezt_icu(icu, bezt); // XXX
468 /* un-apply offset from src beztriple after copying */
469 bezt->vec[0][0] -= offset;
470 bezt->vec[1][0] -= offset;
471 bezt->vec[2][0] -= offset;
474 /* recalculate channel's handles? */
475 //calchandles_fcurve(fcu);
480 /* free temp memory */
481 BLI_freelistN(&anim_data);
482 #endif // XXX old animation system
487 /* ------------------- */
489 static int graphkeys_copy_exec(bContext *C, wmOperator *op)
493 /* get editor data */
494 if (ANIM_animdata_get_context(C, &ac) == 0)
495 return OPERATOR_CANCELLED;
498 if (copy_graph_keys(&ac)) {
499 // XXX errors - need a way to inform the user
500 printf("Action Copy: No keyframes copied to copy-paste buffer\n");
503 /* set notifier tha things have changed */
504 ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_KEYFRAMES_VALUES);
506 return OPERATOR_FINISHED;
509 void GRAPHEDIT_OT_keyframes_copy (wmOperatorType *ot)
512 ot->name= "Copy Keyframes";
513 ot->idname= "GRAPHEDIT_OT_keyframes_copy";
516 ot->exec= graphkeys_copy_exec;
517 ot->poll= ED_operator_areaactive;
520 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
525 static int graphkeys_paste_exec(bContext *C, wmOperator *op)
529 /* get editor data */
530 if (ANIM_animdata_get_context(C, &ac) == 0)
531 return OPERATOR_CANCELLED;
533 /* paste keyframes */
534 if (paste_graph_keys(&ac)) {
535 // XXX errors - need a way to inform the user
536 printf("Action Paste: Nothing to paste, as Copy-Paste buffer was empty.\n");
539 /* validate keyframes after editing */
540 ANIM_editkeyframes_refresh(&ac);
542 /* set notifier tha things have changed */
543 ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_KEYFRAMES_VALUES);
545 return OPERATOR_FINISHED;
548 void GRAPHEDIT_OT_keyframes_paste (wmOperatorType *ot)
551 ot->name= "Paste Keyframes";
552 ot->idname= "GRAPHEDIT_OT_keyframes_paste";
555 ot->exec= graphkeys_paste_exec;
556 ot->poll= ED_operator_areaactive;
559 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
562 #endif // XXX code to be sanitied for new system
564 /* ******************** Delete Keyframes Operator ************************* */
566 static void delete_graph_keys (bAnimContext *ac)
568 ListBase anim_data = {NULL, NULL};
573 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE| ANIMFILTER_FOREDIT | ANIMFILTER_CURVESONLY);
574 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
576 /* loop through filtered data and delete selected keys */
577 for (ale= anim_data.first; ale; ale= ale->next) {
578 delete_fcurve_keys((FCurve *)ale->key_data); // XXX... this doesn't delete empty curves anymore
581 /* free filtered list */
582 BLI_freelistN(&anim_data);
585 /* ------------------- */
587 static int graphkeys_delete_exec(bContext *C, wmOperator *op)
591 /* get editor data */
592 if (ANIM_animdata_get_context(C, &ac) == 0)
593 return OPERATOR_CANCELLED;
595 /* delete keyframes */
596 delete_graph_keys(&ac);
598 /* validate keyframes after editing */
599 ANIM_editkeyframes_refresh(&ac);
601 /* set notifier tha things have changed */
602 ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_KEYFRAMES_VALUES);
604 return OPERATOR_FINISHED;
607 void GRAPHEDIT_OT_keyframes_delete (wmOperatorType *ot)
610 ot->name= "Delete Keyframes";
611 ot->idname= "GRAPHEDIT_OT_keyframes_delete";
614 ot->invoke= WM_operator_confirm;
615 ot->exec= graphkeys_delete_exec;
616 ot->poll= ED_operator_areaactive;
619 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
622 /* ******************** Clean Keyframes Operator ************************* */
624 static void clean_graph_keys (bAnimContext *ac, float thresh)
626 ListBase anim_data = {NULL, NULL};
631 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE| ANIMFILTER_FOREDIT | ANIMFILTER_SEL | ANIMFILTER_CURVESONLY);
632 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
634 /* loop through filtered data and clean curves */
635 for (ale= anim_data.first; ale; ale= ale->next)
636 clean_fcurve((FCurve *)ale->key_data, thresh);
639 BLI_freelistN(&anim_data);
642 /* ------------------- */
644 static int graphkeys_clean_exec(bContext *C, wmOperator *op)
649 /* get editor data */
650 if (ANIM_animdata_get_context(C, &ac) == 0)
651 return OPERATOR_CANCELLED;
653 /* get cleaning threshold */
654 thresh= RNA_float_get(op->ptr, "threshold");
656 /* clean keyframes */
657 clean_graph_keys(&ac, thresh);
659 /* validate keyframes after editing */
660 ANIM_editkeyframes_refresh(&ac);
662 /* set notifier tha things have changed */
663 ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_KEYFRAMES_VALUES);
665 return OPERATOR_FINISHED;
668 void GRAPHEDIT_OT_keyframes_clean (wmOperatorType *ot)
671 ot->name= "Clean Keyframes";
672 ot->idname= "GRAPHEDIT_OT_keyframes_clean";
675 //ot->invoke= // XXX we need that number popup for this!
676 ot->exec= graphkeys_clean_exec;
677 ot->poll= ED_operator_areaactive;
680 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
683 RNA_def_float(ot->srna, "threshold", 0.001f, 0.0f, FLT_MAX, "Threshold", "", 0.0f, 1000.0f);
686 /* ******************** Sample Keyframes Operator *********************** */
688 // XXX some of the common parts (with DopeSheet) should be unified in animation module...
690 /* little cache for values... */
691 typedef struct tempFrameValCache {
695 /* Evaluates the curves between each selected keyframe on each frame, and keys the value */
696 static void sample_graph_keys (bAnimContext *ac)
698 ListBase anim_data = {NULL, NULL};
703 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE| ANIMFILTER_FOREDIT | ANIMFILTER_CURVESONLY);
704 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
706 /* loop through filtered data and add keys between selected keyframes on every frame */
707 for (ale= anim_data.first; ale; ale= ale->next) {
708 FCurve *fcu= (FCurve *)ale->key_data;
709 BezTriple *bezt, *start=NULL, *end=NULL;
710 tempFrameValCache *value_cache, *fp;
714 /* find selected keyframes... once pair has been found, add keyframes */
715 for (i=0, bezt=fcu->bezt; i < fcu->totvert; i++, bezt++) {
716 /* check if selected, and which end this is */
717 if (BEZSELECTED(bezt)) {
722 /* cache values then add keyframes using these values, as adding
723 * keyframes while sampling will affect the outcome...
725 range= (int)( ceil(end->vec[1][0] - start->vec[1][0]) );
726 sfra= (int)( floor(start->vec[1][0]) );
729 value_cache= MEM_callocN(sizeof(tempFrameValCache)*range, "IcuFrameValCache");
732 for (n=0, fp=value_cache; n<range && fp; n++, fp++) {
733 fp->frame= (float)(sfra + n);
734 fp->val= evaluate_fcurve(fcu, fp->frame);
737 /* add keyframes with these */
738 for (n=0, fp=value_cache; n<range && fp; n++, fp++) {
739 insert_vert_fcurve(fcu, fp->frame, fp->val, 1);
742 /* free temp cache */
743 MEM_freeN(value_cache);
745 /* as we added keyframes, we need to compensate so that bezt is at the right place */
746 bezt = fcu->bezt + i + range - 1;
750 /* bezt was selected, so it now marks the start of a whole new chain to search */
755 /* just set start keyframe */
762 /* recalculate channel's handles? */
763 calchandles_fcurve(fcu);
766 /* admin and redraws */
767 BLI_freelistN(&anim_data);
770 /* ------------------- */
772 static int graphkeys_sample_exec(bContext *C, wmOperator *op)
776 /* get editor data */
777 if (ANIM_animdata_get_context(C, &ac) == 0)
778 return OPERATOR_CANCELLED;
780 /* sample keyframes */
781 sample_graph_keys(&ac);
783 /* validate keyframes after editing */
784 ANIM_editkeyframes_refresh(&ac);
786 /* set notifier tha things have changed */
787 ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_KEYFRAMES_VALUES);
789 return OPERATOR_FINISHED;
792 void GRAPHEDIT_OT_keyframes_sample (wmOperatorType *ot)
795 ot->name= "Sample Keyframes";
796 ot->idname= "GRAPHEDIT_OT_keyframes_sample";
799 ot->exec= graphkeys_sample_exec;
800 ot->poll= ED_operator_areaactive;
803 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
807 /* ************************************************************************** */
810 /* ******************** Set Extrapolation-Type Operator *********************** */
812 /* defines for set extrapolation-type for selected keyframes tool */
813 EnumPropertyItem prop_graphkeys_expo_types[] = {
814 {FCURVE_EXTRAPOLATE_CONSTANT, "CONSTANT", "Constant Extrapolation", ""},
815 {FCURVE_EXTRAPOLATE_LINEAR, "LINEAR", "Linear Extrapolation", ""},
816 {0, NULL, NULL, NULL}
819 /* this function is responsible for setting extrapolation mode for keyframes */
820 static void setexpo_graph_keys(bAnimContext *ac, short mode)
822 ListBase anim_data = {NULL, NULL};
827 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE| ANIMFILTER_FOREDIT | ANIMFILTER_CURVESONLY);
828 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
830 /* loop through setting mode per F-Curve */
831 for (ale= anim_data.first; ale; ale= ale->next) {
832 FCurve *fcu= (FCurve *)ale->data;
837 BLI_freelistN(&anim_data);
840 /* ------------------- */
842 static int graphkeys_expo_exec(bContext *C, wmOperator *op)
847 /* get editor data */
848 if (ANIM_animdata_get_context(C, &ac) == 0)
849 return OPERATOR_CANCELLED;
851 /* get handle setting mode */
852 mode= RNA_enum_get(op->ptr, "type");
854 /* set handle type */
855 setexpo_graph_keys(&ac, mode);
857 /* validate keyframes after editing */
858 ANIM_editkeyframes_refresh(&ac);
860 /* set notifier tha things have changed */
861 ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_KEYFRAMES_VALUES);
863 return OPERATOR_FINISHED;
866 void GRAPHEDIT_OT_keyframes_extrapolation_type (wmOperatorType *ot)
869 ot->name= "Set Keyframe Extrapolation";
870 ot->idname= "GRAPHEDIT_OT_keyframes_extrapolation_type";
873 ot->invoke= WM_menu_invoke;
874 ot->exec= graphkeys_expo_exec;
875 ot->poll= ED_operator_areaactive;
878 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
881 RNA_def_enum(ot->srna, "type", prop_graphkeys_expo_types, 0, "Type", "");
884 /* ******************** Set Interpolation-Type Operator *********************** */
886 /* defines for set ipo-type for selected keyframes tool */
887 EnumPropertyItem prop_graphkeys_ipo_types[] = {
888 {BEZT_IPO_CONST, "CONSTANT", "Constant Interpolation", ""},
889 {BEZT_IPO_LIN, "LINEAR", "Linear Interpolation", ""},
890 {BEZT_IPO_BEZ, "BEZIER", "Bezier Interpolation", ""},
891 {0, NULL, NULL, NULL}
894 /* this function is responsible for setting interpolation mode for keyframes */
895 static void setipo_graph_keys(bAnimContext *ac, short mode)
897 ListBase anim_data = {NULL, NULL};
900 BeztEditFunc set_cb= ANIM_editkeyframes_ipo(mode);
903 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE| ANIMFILTER_FOREDIT | ANIMFILTER_CURVESONLY);
904 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
906 /* loop through setting BezTriple interpolation
907 * Note: we do not supply BeztEditData to the looper yet. Currently that's not necessary here...
909 for (ale= anim_data.first; ale; ale= ale->next)
910 ANIM_fcurve_keys_bezier_loop(NULL, ale->key_data, NULL, set_cb, calchandles_fcurve);
913 BLI_freelistN(&anim_data);
916 /* ------------------- */
918 static int graphkeys_ipo_exec(bContext *C, wmOperator *op)
923 /* get editor data */
924 if (ANIM_animdata_get_context(C, &ac) == 0)
925 return OPERATOR_CANCELLED;
927 /* get handle setting mode */
928 mode= RNA_enum_get(op->ptr, "type");
930 /* set handle type */
931 setipo_graph_keys(&ac, mode);
933 /* validate keyframes after editing */
934 ANIM_editkeyframes_refresh(&ac);
936 /* set notifier tha things have changed */
937 ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_KEYFRAMES_VALUES);
939 return OPERATOR_FINISHED;
942 void GRAPHEDIT_OT_keyframes_interpolation_type (wmOperatorType *ot)
945 ot->name= "Set Keyframe Interpolation";
946 ot->idname= "GRAPHEDIT_OT_keyframes_interpolation_type";
949 ot->invoke= WM_menu_invoke;
950 ot->exec= graphkeys_ipo_exec;
951 ot->poll= ED_operator_areaactive;
954 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
957 RNA_def_enum(ot->srna, "type", prop_graphkeys_ipo_types, 0, "Type", "");
960 /* ******************** Set Handle-Type Operator *********************** */
962 /* defines for set handle-type for selected keyframes tool */
963 EnumPropertyItem prop_graphkeys_handletype_types[] = {
964 {HD_AUTO, "AUTO", "Auto Handles", ""},
965 {HD_VECT, "VECTOR", "Vector Handles", ""},
966 {HD_FREE, "FREE", "Free Handles", ""},
967 {HD_ALIGN, "ALIGN", "Aligned Handles", ""},
968 // {-1, "TOGGLE", "Toggle between Free and Aligned Handles", ""},
969 {0, NULL, NULL, NULL}
972 /* this function is responsible for setting handle-type of selected keyframes */
973 static void sethandles_graph_keys(bAnimContext *ac, short mode)
975 ListBase anim_data = {NULL, NULL};
978 BeztEditFunc set_cb= ANIM_editkeyframes_handles(mode);
981 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE| ANIMFILTER_FOREDIT | ANIMFILTER_CURVESONLY);
982 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
984 /* loop through setting flags for handles
985 * Note: we do not supply BeztEditData to the looper yet. Currently that's not necessary here...
987 // XXX we might need to supply BeztEditData to get it to only affect selected handles
988 for (ale= anim_data.first; ale; ale= ale->next) {
990 BeztEditFunc toggle_cb;
992 /* check which type of handle to set (free or aligned)
993 * - check here checks for handles with free alignment already
995 if (ANIM_fcurve_keys_bezier_loop(NULL, ale->key_data, NULL, set_cb, NULL))
996 toggle_cb= ANIM_editkeyframes_handles(HD_FREE);
998 toggle_cb= ANIM_editkeyframes_handles(HD_ALIGN);
1000 /* set handle-type */
1001 ANIM_fcurve_keys_bezier_loop(NULL, ale->key_data, NULL, toggle_cb, calchandles_fcurve);
1004 /* directly set handle-type */
1005 ANIM_fcurve_keys_bezier_loop(NULL, ale->key_data, NULL, set_cb, calchandles_fcurve);
1010 BLI_freelistN(&anim_data);
1013 /* ------------------- */
1015 static int graphkeys_handletype_exec(bContext *C, wmOperator *op)
1020 /* get editor data */
1021 if (ANIM_animdata_get_context(C, &ac) == 0)
1022 return OPERATOR_CANCELLED;
1024 /* get handle setting mode */
1025 mode= RNA_enum_get(op->ptr, "type");
1027 /* set handle type */
1028 sethandles_graph_keys(&ac, mode);
1030 /* validate keyframes after editing */
1031 ANIM_editkeyframes_refresh(&ac);
1033 /* set notifier tha things have changed */
1034 ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_KEYFRAMES_VALUES);
1036 return OPERATOR_FINISHED;
1039 void GRAPHEDIT_OT_keyframes_handletype (wmOperatorType *ot)
1042 ot->name= "Set Keyframe Handle Type";
1043 ot->idname= "GRAPHEDIT_OT_keyframes_handletype";
1046 ot->invoke= WM_menu_invoke;
1047 ot->exec= graphkeys_handletype_exec;
1048 ot->poll= ED_operator_areaactive;
1051 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1054 RNA_def_enum(ot->srna, "type", prop_graphkeys_handletype_types, 0, "Type", "");
1057 /* ************************************************************************** */
1058 /* TRANSFORM STUFF */
1060 /* ***************** Snap Current Frame Operator *********************** */
1062 /* helper callback for graphkeys_cfrasnap_exec() -> used to help get the average time of all selected beztriples */
1063 // TODO: if some other code somewhere needs this, it'll be time to port this over to keyframes_edit.c!!!
1064 static short bezt_calc_average(BeztEditData *bed, BezTriple *bezt)
1066 /* only if selected */
1067 if (bezt->f2 & SELECT) {
1068 /* store average time in float (only do rounding at last step */
1069 bed->f1 += bezt->vec[1][0];
1071 /* increment number of items */
1078 /* snap current-frame indicator to 'average time' of selected keyframe */
1079 static int graphkeys_cfrasnap_exec(bContext *C, wmOperator *op)
1082 ListBase anim_data= {NULL, NULL};
1087 /* get editor data */
1088 if (ANIM_animdata_get_context(C, &ac) == 0)
1089 return OPERATOR_CANCELLED;
1091 /* init edit data */
1092 memset(&bed, 0, sizeof(BeztEditData));
1094 /* loop over action data, averaging values */
1095 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE| ANIMFILTER_CURVESONLY);
1096 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
1098 for (ale= anim_data.first; ale; ale= ale->next)
1099 ANIM_fcurve_keys_bezier_loop(&bed, ale->key_data, NULL, bezt_calc_average, NULL);
1101 BLI_freelistN(&anim_data);
1103 /* set the new current frame value, based on the average time */
1105 Scene *scene= ac.scene;
1106 CFRA= (int)floor((bed.f1 / bed.i1) + 0.5f);
1109 /* set notifier tha things have changed */
1110 WM_event_add_notifier(C, NC_SCENE|ND_FRAME, ac.scene);
1112 return OPERATOR_FINISHED;
1115 void GRAPHEDIT_OT_keyframes_cfrasnap (wmOperatorType *ot)
1118 ot->name= "Snap Current Frame to Keys";
1119 ot->idname= "GRAPHEDIT_OT_keyframes_cfrasnap";
1122 ot->exec= graphkeys_cfrasnap_exec;
1123 ot->poll= ED_operator_areaactive;
1126 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1129 /* ******************** Snap Keyframes Operator *********************** */
1131 /* defines for snap keyframes tool */
1132 EnumPropertyItem prop_graphkeys_snap_types[] = {
1133 {GRAPHKEYS_SNAP_CFRA, "CFRA", "Current frame", ""},
1134 {GRAPHKEYS_SNAP_NEAREST_FRAME, "NEAREST_FRAME", "Nearest Frame", ""}, // XXX as single entry?
1135 {GRAPHKEYS_SNAP_NEAREST_SECOND, "NEAREST_SECOND", "Nearest Second", ""}, // XXX as single entry?
1136 {GRAPHKEYS_SNAP_NEAREST_MARKER, "NEAREST_MARKER", "Nearest Marker", ""},
1137 {GRAPHKEYS_SNAP_HORIZONTAL, "HORIZONTAL", "Flatten Handles", ""},
1138 {0, NULL, NULL, NULL}
1141 /* this function is responsible for snapping keyframes to frame-times */
1142 static void snap_graph_keys(bAnimContext *ac, short mode)
1144 ListBase anim_data = {NULL, NULL};
1149 BeztEditFunc edit_cb;
1152 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE| ANIMFILTER_FOREDIT | ANIMFILTER_CURVESONLY);
1153 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
1155 /* get beztriple editing callbacks */
1156 edit_cb= ANIM_editkeyframes_snap(mode);
1158 memset(&bed, 0, sizeof(BeztEditData));
1159 bed.scene= ac->scene;
1161 /* snap keyframes */
1162 for (ale= anim_data.first; ale; ale= ale->next) {
1163 Object *nob= ANIM_nla_mapping_get(ac, ale);
1166 ANIM_nla_mapping_apply_fcurve(nob, ale->key_data, 0, 1);
1167 ANIM_fcurve_keys_bezier_loop(&bed, ale->key_data, NULL, edit_cb, calchandles_fcurve);
1168 ANIM_nla_mapping_apply_fcurve(nob, ale->key_data, 1, 1);
1171 ANIM_fcurve_keys_bezier_loop(&bed, ale->key_data, NULL, edit_cb, calchandles_fcurve);
1173 BLI_freelistN(&anim_data);
1176 /* ------------------- */
1178 static int graphkeys_snap_exec(bContext *C, wmOperator *op)
1183 /* get editor data */
1184 if (ANIM_animdata_get_context(C, &ac) == 0)
1185 return OPERATOR_CANCELLED;
1187 /* get snapping mode */
1188 mode= RNA_enum_get(op->ptr, "type");
1190 /* snap keyframes */
1191 snap_graph_keys(&ac, mode);
1193 /* validate keyframes after editing */
1194 ANIM_editkeyframes_refresh(&ac);
1196 /* set notifier tha things have changed */
1197 ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_KEYFRAMES_VALUES);
1199 return OPERATOR_FINISHED;
1202 void GRAPHEDIT_OT_keyframes_snap (wmOperatorType *ot)
1205 ot->name= "Snap Keys";
1206 ot->idname= "GRAPHEDIT_OT_keyframes_snap";
1209 ot->invoke= WM_menu_invoke;
1210 ot->exec= graphkeys_snap_exec;
1211 ot->poll= ED_operator_areaactive;
1214 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1217 RNA_def_enum(ot->srna, "type", prop_graphkeys_snap_types, 0, "Type", "");
1220 /* ******************** Mirror Keyframes Operator *********************** */
1222 /* defines for mirror keyframes tool */
1223 EnumPropertyItem prop_graphkeys_mirror_types[] = {
1224 {GRAPHKEYS_MIRROR_CFRA, "CFRA", "Current frame", ""},
1225 {GRAPHKEYS_MIRROR_YAXIS, "YAXIS", "Vertical Axis", ""},
1226 {GRAPHKEYS_MIRROR_XAXIS, "XAXIS", "Horizontal Axis", ""},
1227 {GRAPHKEYS_MIRROR_MARKER, "MARKER", "First Selected Marker", ""},
1228 {0, NULL, NULL, NULL}
1231 /* this function is responsible for mirroring keyframes */
1232 static void mirror_graph_keys(bAnimContext *ac, short mode)
1234 ListBase anim_data = {NULL, NULL};
1239 BeztEditFunc edit_cb;
1241 /* get beztriple editing callbacks */
1242 edit_cb= ANIM_editkeyframes_mirror(mode);
1244 memset(&bed, 0, sizeof(BeztEditData));
1245 bed.scene= ac->scene;
1247 /* for 'first selected marker' mode, need to find first selected marker first! */
1248 // XXX should this be made into a helper func in the API?
1249 if (mode == GRAPHKEYS_MIRROR_MARKER) {
1250 Scene *scene= ac->scene;
1251 TimeMarker *marker= NULL;
1253 /* find first selected marker */
1254 for (marker= scene->markers.first; marker; marker=marker->next) {
1255 if (marker->flag & SELECT) {
1260 /* store marker's time (if available) */
1262 bed.f1= (float)marker->frame;
1268 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE| ANIMFILTER_FOREDIT | ANIMFILTER_CURVESONLY);
1269 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
1271 /* mirror keyframes */
1272 for (ale= anim_data.first; ale; ale= ale->next) {
1273 Object *nob= ANIM_nla_mapping_get(ac, ale);
1276 ANIM_nla_mapping_apply_fcurve(nob, ale->key_data, 0, 1);
1277 ANIM_fcurve_keys_bezier_loop(&bed, ale->key_data, NULL, edit_cb, calchandles_fcurve);
1278 ANIM_nla_mapping_apply_fcurve(nob, ale->key_data, 1, 1);
1281 ANIM_fcurve_keys_bezier_loop(&bed, ale->key_data, NULL, edit_cb, calchandles_fcurve);
1283 BLI_freelistN(&anim_data);
1286 /* ------------------- */
1288 static int graphkeys_mirror_exec(bContext *C, wmOperator *op)
1293 /* get editor data */
1294 if (ANIM_animdata_get_context(C, &ac) == 0)
1295 return OPERATOR_CANCELLED;
1297 /* get mirroring mode */
1298 mode= RNA_enum_get(op->ptr, "type");
1300 /* mirror keyframes */
1301 mirror_graph_keys(&ac, mode);
1303 /* validate keyframes after editing */
1304 ANIM_editkeyframes_refresh(&ac);
1306 /* set notifier tha things have changed */
1307 ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_KEYFRAMES_VALUES);
1309 return OPERATOR_FINISHED;
1312 void GRAPHEDIT_OT_keyframes_mirror (wmOperatorType *ot)
1315 ot->name= "Mirror Keys";
1316 ot->idname= "GRAPHEDIT_OT_keyframes_mirror";
1319 ot->invoke= WM_menu_invoke;
1320 ot->exec= graphkeys_mirror_exec;
1321 ot->poll= ED_operator_areaactive;
1324 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1327 RNA_def_enum(ot->srna, "type", prop_graphkeys_mirror_types, 0, "Type", "");
1330 /* ******************** Smooth Keyframes Operator *********************** */
1332 static int graphkeys_smooth_exec(bContext *C, wmOperator *op)
1335 ListBase anim_data = {NULL, NULL};
1339 /* get editor data */
1340 if (ANIM_animdata_get_context(C, &ac) == 0)
1341 return OPERATOR_CANCELLED;
1344 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE| ANIMFILTER_FOREDIT | ANIMFILTER_CURVESONLY);
1345 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
1347 /* smooth keyframes */
1348 for (ale= anim_data.first; ale; ale= ale->next) {
1349 /* For now, we can only smooth by flattening handles AND smoothing curve values.
1350 * Perhaps the mode argument could be removed, as that functionality is offerred through
1351 * Snap->Flatten Handles anyway.
1353 smooth_fcurve(ale->key_data);
1355 BLI_freelistN(&anim_data);
1357 /* validate keyframes after editing */
1358 ANIM_editkeyframes_refresh(&ac);
1360 /* set notifier tha things have changed */
1361 ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_KEYFRAMES_VALUES);
1363 return OPERATOR_FINISHED;
1366 void GRAPHEDIT_OT_keyframes_smooth (wmOperatorType *ot)
1369 ot->name= "Smooth Keys";
1370 ot->idname= "GRAPHEDIT_OT_keyframes_smooth";
1373 ot->exec= graphkeys_smooth_exec;
1374 ot->poll= ED_operator_areaactive;
1377 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1380 /* ************************************************************************** */