2 * ***** BEGIN GPL LICENSE BLOCK *****
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software Foundation,
16 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
19 * All rights reserved.
21 * The Original Code is: all of this file.
23 * Contributor(s): Joshua Leung
25 * ***** END GPL LICENSE BLOCK *****
28 /** \file blender/editors/space_action/action_edit.c
39 #include "BLI_blenlib.h"
41 #include "BLI_utildefines.h"
43 #include "BLT_translation.h"
45 #include "DNA_anim_types.h"
46 #include "DNA_gpencil_types.h"
47 #include "DNA_key_types.h"
48 #include "DNA_object_types.h"
49 #include "DNA_scene_types.h"
50 #include "DNA_mask_types.h"
52 #include "RNA_access.h"
53 #include "RNA_define.h"
54 #include "RNA_enum_types.h"
56 #include "BKE_action.h"
57 #include "BKE_fcurve.h"
58 #include "BKE_gpencil.h"
59 #include "BKE_global.h"
60 #include "BKE_library.h"
64 #include "BKE_context.h"
65 #include "BKE_report.h"
67 #include "UI_view2d.h"
69 #include "ED_anim_api.h"
70 #include "ED_gpencil.h"
71 #include "ED_keyframing.h"
72 #include "ED_keyframes_edit.h"
73 #include "ED_screen.h"
74 #include "ED_markers.h"
80 #include "UI_interface.h"
82 #include "action_intern.h"
85 /* ************************************************************************** */
86 /* POSE MARKERS STUFF */
88 /* *************************** Localise Markers ***************************** */
90 /* ensure that there is:
91 * 1) an active action editor
92 * 2) that the mode will have an active action available
93 * 3) that the set of markers being shown are the scene markers, not the list we're merging
94 * 4) that there are some selected markers
96 static int act_markers_make_local_poll(bContext *C)
98 SpaceAction *sact = CTX_wm_space_action(C);
105 if (ELEM(sact->mode, SACTCONT_ACTION, SACTCONT_SHAPEKEY) == 0)
107 if (sact->action == NULL)
111 if (sact->flag & SACTION_POSEMARKERS_SHOW)
115 return ED_markers_get_first_selected(ED_context_get_markers(C)) != NULL;
118 static int act_markers_make_local_exec(bContext *C, wmOperator *UNUSED(op))
120 ListBase *markers = ED_context_get_markers(C);
122 SpaceAction *sact = CTX_wm_space_action(C);
123 bAction *act = (sact) ? sact->action : NULL;
125 TimeMarker *marker, *markern = NULL;
128 if (ELEM(NULL, markers, act))
129 return OPERATOR_CANCELLED;
131 /* migrate markers */
132 for (marker = markers->first; marker; marker = markern) {
133 markern = marker->next;
135 /* move if marker is selected */
136 if (marker->flag & SELECT) {
137 BLI_remlink(markers, marker);
138 BLI_addtail(&act->markers, marker);
142 /* now enable the "show posemarkers only" setting, so that we can see that something did happen */
143 sact->flag |= SACTION_POSEMARKERS_SHOW;
145 /* notifiers - both sets, as this change affects both */
146 WM_event_add_notifier(C, NC_SCENE | ND_MARKERS, NULL);
147 WM_event_add_notifier(C, NC_ANIMATION | ND_MARKERS, NULL);
149 return OPERATOR_FINISHED;
152 void ACTION_OT_markers_make_local(wmOperatorType *ot)
155 ot->name = "Make Markers Local";
156 ot->idname = "ACTION_OT_markers_make_local";
157 ot->description = "Move selected scene markers to the active Action as local 'pose' markers";
160 ot->exec = act_markers_make_local_exec;
161 ot->poll = act_markers_make_local_poll;
164 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
167 /* ************************************************************************** */
168 /* KEYFRAME-RANGE STUFF */
170 /* *************************** Calculate Range ************************** */
172 /* Get the min/max keyframes*/
173 static bool get_keyframe_extents(bAnimContext *ac, float *min, float *max, const short onlySel)
175 ListBase anim_data = {NULL, NULL};
180 /* get data to filter, from Action or Dopesheet */
181 /* XXX: what is sel doing here?!
182 * Commented it, was breaking things (eg. the "auto preview range" tool). */
183 filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE /*| ANIMFILTER_SEL *//*| ANIMFILTER_CURVESONLY*/ | ANIMFILTER_NODUPLIS);
184 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
186 /* set large values to try to override */
188 *max = -999999999.0f;
190 /* check if any channels to set range with */
191 if (anim_data.first) {
192 /* go through channels, finding max extents */
193 for (ale = anim_data.first; ale; ale = ale->next) {
194 AnimData *adt = ANIM_nla_mapping_get(ac, ale);
195 if (ale->datatype == ALE_GPFRAME) {
196 bGPDlayer *gpl = ale->data;
199 /* find gp-frame which is less than or equal to cframe */
200 for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
201 const float framenum = (float)gpf->framenum;
202 *min = min_ff(*min, framenum);
203 *max = max_ff(*max, framenum);
207 else if (ale->datatype == ALE_MASKLAY) {
208 MaskLayer *masklay = ale->data;
209 MaskLayerShape *masklay_shape;
211 /* find mask layer which is less than or equal to cframe */
212 for (masklay_shape = masklay->splines_shapes.first;
214 masklay_shape = masklay_shape->next)
216 const float framenum = (float)masklay_shape->frame;
217 *min = min_ff(*min, framenum);
218 *max = max_ff(*max, framenum);
223 FCurve *fcu = (FCurve *)ale->key_data;
226 /* get range and apply necessary scaling before processing */
227 if (calc_fcurve_range(fcu, &tmin, &tmax, onlySel, false)) {
230 tmin = BKE_nla_tweakedit_remap(adt, tmin, NLATIME_CONVERT_MAP);
231 tmax = BKE_nla_tweakedit_remap(adt, tmax, NLATIME_CONVERT_MAP);
234 /* try to set cur using these values, if they're more extreme than previously set values */
235 *min = min_ff(*min, tmin);
236 *max = max_ff(*max, tmax);
242 if (fabsf(*max - *min) < 0.001f) {
248 ANIM_animdata_freelist(&anim_data);
251 /* set default range */
253 *min = (float)ac->scene->r.sfra;
254 *max = (float)ac->scene->r.efra;
265 /* ****************** Automatic Preview-Range Operator ****************** */
267 static int actkeys_previewrange_exec(bContext *C, wmOperator *UNUSED(op))
273 /* get editor data */
274 if (ANIM_animdata_get_context(C, &ac) == 0)
275 return OPERATOR_CANCELLED;
276 if (ac.scene == NULL)
277 return OPERATOR_CANCELLED;
281 /* set the range directly */
282 get_keyframe_extents(&ac, &min, &max, false);
283 scene->r.flag |= SCER_PRV_RANGE;
284 scene->r.psfra = floorf(min);
285 scene->r.pefra = ceilf(max);
287 if (scene->r.psfra == scene->r.pefra) {
288 scene->r.pefra = scene->r.psfra + 1;
291 /* set notifier that things have changed */
292 // XXX err... there's nothing for frame ranges yet, but this should do fine too
293 WM_event_add_notifier(C, NC_SCENE | ND_FRAME, ac.scene);
295 return OPERATOR_FINISHED;
298 void ACTION_OT_previewrange_set(wmOperatorType *ot)
301 ot->name = "Auto-Set Preview Range";
302 ot->idname = "ACTION_OT_previewrange_set";
303 ot->description = "Set Preview Range based on extents of selected Keyframes";
306 ot->exec = actkeys_previewrange_exec;
307 ot->poll = ED_operator_action_active;
310 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
313 /* ****************** View-All Operator ****************** */
316 * Find the extents of the active channel
318 * \param[out] min Bottom y-extent of channel
319 * \param[out] max Top y-extent of channel
320 * \return Success of finding a selected channel
322 static bool actkeys_channels_get_selected_extents(bAnimContext *ac, float *min, float *max)
324 ListBase anim_data = {NULL, NULL};
328 short found = 0; /* NOTE: not bool, since we want prioritise individual channels over expanders */
331 /* get all items - we need to do it this way */
332 filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS);
333 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
335 /* loop through all channels, finding the first one that's selected */
336 y = (float)ACHANNEL_FIRST;
338 for (ale = anim_data.first; ale; ale = ale->next) {
339 const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
341 /* must be selected... */
342 if (acf && acf->has_setting(ac, ale, ACHANNEL_SETTING_SELECT) &&
343 ANIM_channel_setting_get(ac, ale, ACHANNEL_SETTING_SELECT))
345 /* update best estimate */
346 *min = (float)(y - ACHANNEL_HEIGHT_HALF);
347 *max = (float)(y + ACHANNEL_HEIGHT_HALF);
349 /* is this high enough priority yet? */
350 found = acf->channel_role;
352 /* only stop our search when we've found an actual channel
353 * - datablock expanders get less priority so that we don't abort prematurely
355 if (found == ACHANNEL_ROLE_CHANNEL) {
360 /* adjust y-position for next one */
364 /* free all temp data */
365 ANIM_animdata_freelist(&anim_data);
370 static int actkeys_viewall(bContext *C, const bool only_sel)
374 float extra, min, max;
377 /* get editor data */
378 if (ANIM_animdata_get_context(C, &ac) == 0)
379 return OPERATOR_CANCELLED;
382 /* set the horizontal range, with an extra offset so that the extreme keys will be in view */
383 found = get_keyframe_extents(&ac, &min, &max, only_sel);
385 if (only_sel && (found == false))
386 return OPERATOR_CANCELLED;
391 extra = 0.1f * BLI_rctf_size_x(&v2d->cur);
392 v2d->cur.xmin -= extra;
393 v2d->cur.xmax += extra;
395 /* set vertical range */
396 if (only_sel == false) {
397 /* view all -> the summary channel is usually the shows everything, and resides right at the top... */
398 v2d->cur.ymax = 0.0f;
399 v2d->cur.ymin = (float)-BLI_rcti_size_y(&v2d->mask);
402 /* locate first selected channel (or the active one), and frame those */
403 float ymin = v2d->cur.ymin;
404 float ymax = v2d->cur.ymax;
406 if (actkeys_channels_get_selected_extents(&ac, &ymin, &ymax)) {
407 /* recenter the view so that this range is in the middle */
408 float ymid = (ymax - ymin) / 2.0f + ymin;
411 UI_view2d_center_get(v2d, &x_center, NULL);
412 UI_view2d_center_set(v2d, x_center, ymid);
416 /* do View2D syncing */
417 UI_view2d_sync(CTX_wm_screen(C), CTX_wm_area(C), v2d, V2D_LOCK_COPY);
419 /* just redraw this view */
420 ED_area_tag_redraw(CTX_wm_area(C));
422 return OPERATOR_FINISHED;
427 static int actkeys_viewall_exec(bContext *C, wmOperator *UNUSED(op))
430 return actkeys_viewall(C, false);
433 static int actkeys_viewsel_exec(bContext *C, wmOperator *UNUSED(op))
436 return actkeys_viewall(C, true);
441 void ACTION_OT_view_all(wmOperatorType *ot)
444 ot->name = "View All";
445 ot->idname = "ACTION_OT_view_all";
446 ot->description = "Reset viewable area to show full keyframe range";
449 ot->exec = actkeys_viewall_exec;
450 ot->poll = ED_operator_action_active;
453 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
456 void ACTION_OT_view_selected(wmOperatorType *ot)
459 ot->name = "View Selected";
460 ot->idname = "ACTION_OT_view_selected";
461 ot->description = "Reset viewable area to show selected keyframes range";
464 ot->exec = actkeys_viewsel_exec;
465 ot->poll = ED_operator_action_active;
468 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
471 /* ****************** View-All Operator ****************** */
473 static int actkeys_view_frame_exec(bContext *C, wmOperator *op)
475 const int smooth_viewtx = WM_operator_smooth_viewtx_get(op);
476 ANIM_center_frame(C, smooth_viewtx);
478 return OPERATOR_FINISHED;
481 void ACTION_OT_view_frame(wmOperatorType *ot)
484 ot->name = "View Frame";
485 ot->idname = "ACTION_OT_view_frame";
486 ot->description = "Reset viewable area to show range around current frame";
489 ot->exec = actkeys_view_frame_exec;
490 ot->poll = ED_operator_action_active;
493 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
496 /* ************************************************************************** */
499 /* ******************** Copy/Paste Keyframes Operator ************************* */
500 /* NOTE: the backend code for this is shared with the graph editor */
502 static short copy_action_keys(bAnimContext *ac)
504 ListBase anim_data = {NULL, NULL};
507 /* clear buffer first */
508 ANIM_fcurves_copybuf_free();
511 filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE /*| ANIMFILTER_CURVESONLY*/ | ANIMFILTER_NODUPLIS);
512 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
515 ok = copy_animedit_keys(ac, &anim_data);
518 ANIM_animdata_freelist(&anim_data);
524 static short paste_action_keys(bAnimContext *ac,
525 const eKeyPasteOffset offset_mode, const eKeyMergeMode merge_mode, bool flip)
527 ListBase anim_data = {NULL, NULL};
531 * - First time we try to filter more strictly, allowing only selected channels
532 * to allow copying animation between channels
533 * - Second time, we loosen things up if nothing was found the first time, allowing
534 * users to just paste keyframes back into the original curve again [#31670]
536 filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT /*| ANIMFILTER_CURVESONLY*/ | ANIMFILTER_NODUPLIS);
538 if (ANIM_animdata_filter(ac, &anim_data, filter | ANIMFILTER_SEL, ac->data, ac->datatype) == 0)
539 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
541 /* paste keyframes */
542 ok = paste_animedit_keys(ac, &anim_data, offset_mode, merge_mode, flip);
545 ANIM_animdata_freelist(&anim_data);
550 /* ------------------- */
552 static int actkeys_copy_exec(bContext *C, wmOperator *op)
556 /* get editor data */
557 if (ANIM_animdata_get_context(C, &ac) == 0)
558 return OPERATOR_CANCELLED;
561 if (ac.datatype == ANIMCONT_GPENCIL) {
562 if (ED_gpencil_anim_copybuf_copy(&ac) == false) {
563 /* Nothing got copied - An error about this should be been logged already */
564 return OPERATOR_CANCELLED;
567 else if (ac.datatype == ANIMCONT_MASK) {
569 BKE_report(op->reports, RPT_ERROR, "Keyframe pasting is not available for mask mode");
570 return OPERATOR_CANCELLED;
573 if (copy_action_keys(&ac)) {
574 BKE_report(op->reports, RPT_ERROR, "No keyframes copied to keyframes copy/paste buffer");
575 return OPERATOR_CANCELLED;
579 return OPERATOR_FINISHED;
582 void ACTION_OT_copy(wmOperatorType *ot)
585 ot->name = "Copy Keyframes";
586 ot->idname = "ACTION_OT_copy";
587 ot->description = "Copy selected keyframes to the copy/paste buffer";
590 ot->exec = actkeys_copy_exec;
591 ot->poll = ED_operator_action_active;
594 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
597 static int actkeys_paste_exec(bContext *C, wmOperator *op)
601 const eKeyPasteOffset offset_mode = RNA_enum_get(op->ptr, "offset");
602 const eKeyMergeMode merge_mode = RNA_enum_get(op->ptr, "merge");
603 const bool flipped = RNA_boolean_get(op->ptr, "flipped");
605 /* get editor data */
606 if (ANIM_animdata_get_context(C, &ac) == 0)
607 return OPERATOR_CANCELLED;
609 /* ac.reports by default will be the global reports list, which won't show warnings */
610 ac.reports = op->reports;
612 /* paste keyframes */
613 if (ac.datatype == ANIMCONT_GPENCIL) {
614 if (ED_gpencil_anim_copybuf_paste(&ac, offset_mode) == false) {
615 /* An error occurred - Reports should have been fired already */
616 return OPERATOR_CANCELLED;
619 else if (ac.datatype == ANIMCONT_MASK) {
621 BKE_report(op->reports, RPT_ERROR, "Keyframe pasting is not available for grease pencil or mask mode");
622 return OPERATOR_CANCELLED;
625 /* non-zero return means an error occurred while trying to paste */
626 if (paste_action_keys(&ac, offset_mode, merge_mode, flipped)) {
627 return OPERATOR_CANCELLED;
631 /* set notifier that keyframes have changed */
632 WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
634 return OPERATOR_FINISHED;
637 void ACTION_OT_paste(wmOperatorType *ot)
641 ot->name = "Paste Keyframes";
642 ot->idname = "ACTION_OT_paste";
643 ot->description = "Paste keyframes from copy/paste buffer for the selected channels, starting on the current frame";
646 // ot->invoke = WM_operator_props_popup; // better wait for action redo panel
647 ot->exec = actkeys_paste_exec;
648 ot->poll = ED_operator_action_active;
651 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
654 RNA_def_enum(ot->srna, "offset", rna_enum_keyframe_paste_offset_items, KEYFRAME_PASTE_OFFSET_CFRA_START, "Offset", "Paste time offset of keys");
655 RNA_def_enum(ot->srna, "merge", rna_enum_keyframe_paste_merge_items, KEYFRAME_PASTE_MERGE_MIX, "Type", "Method of merging pasted keys and existing");
656 prop = RNA_def_boolean(ot->srna, "flipped", false, "Flipped", "Paste keyframes from mirrored bones if they exist");
657 RNA_def_property_flag(prop, PROP_SKIP_SAVE);
660 /* ******************** Insert Keyframes Operator ************************* */
662 /* defines for insert keyframes tool */
663 static EnumPropertyItem prop_actkeys_insertkey_types[] = {
664 {1, "ALL", 0, "All Channels", ""},
665 {2, "SEL", 0, "Only Selected Channels", ""},
666 {3, "GROUP", 0, "In Active Group", ""}, /* XXX not in all cases */
667 {0, NULL, 0, NULL, NULL}
670 /* this function is responsible for inserting new keyframes */
671 static void insert_action_keys(bAnimContext *ac, short mode)
673 ListBase anim_data = {NULL, NULL};
677 ReportList *reports = ac->reports;
678 Scene *scene = ac->scene;
679 ToolSettings *ts = scene->toolsettings;
683 filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT /*| ANIMFILTER_CURVESONLY*/ | ANIMFILTER_NODUPLIS);
684 if (mode == 2) filter |= ANIMFILTER_SEL;
685 else if (mode == 3) filter |= ANIMFILTER_ACTGROUPED;
687 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
689 /* init keyframing flag */
690 flag = ANIM_get_keyframing_flags(scene, 1);
692 /* insert keyframes */
693 for (ale = anim_data.first; ale; ale = ale->next) {
694 AnimData *adt = ANIM_nla_mapping_get(ac, ale);
695 FCurve *fcu = (FCurve *)ale->key_data;
698 /* adjust current frame for NLA-scaling */
700 cfra = BKE_nla_tweakedit_remap(adt, (float)CFRA, NLATIME_CONVERT_UNMAP);
704 /* read value from property the F-Curve represents, or from the curve only?
705 * - ale->id != NULL: Typically, this means that we have enough info to try resolving the path
706 * - ale->owner != NULL: If this is set, then the path may not be resolvable from the ID alone,
707 * so it's easier for now to just read the F-Curve directly.
708 * (TODO: add the full-blown PointerRNA relative parsing case here...)
710 if (ale->id && !ale->owner) {
711 insert_keyframe(reports, ale->id, NULL, ((fcu->grp) ? (fcu->grp->name) : (NULL)), fcu->rna_path, fcu->array_index, cfra, ts->keyframe_type, flag);
714 const float curval = evaluate_fcurve(fcu, cfra);
715 insert_vert_fcurve(fcu, cfra, curval, ts->keyframe_type, 0);
718 ale->update |= ANIM_UPDATE_DEFAULT;
721 ANIM_animdata_update(ac, &anim_data);
722 ANIM_animdata_freelist(&anim_data);
725 /* this function is for inserting new grease pencil frames */
726 static void insert_gpencil_keys(bAnimContext *ac, short mode)
728 ListBase anim_data = {NULL, NULL};
732 Scene *scene = ac->scene;
733 ToolSettings *ts = scene->toolsettings;
734 eGP_GetFrame_Mode add_frame_mode;
737 filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS);
738 if (mode == 2) filter |= ANIMFILTER_SEL;
740 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
743 /* add a copy or a blank frame? */
744 if (ts->gpencil_flags & GP_TOOL_FLAG_RETAIN_LAST)
745 add_frame_mode = GP_GETFRAME_ADD_COPY; /* XXX: actframe may not be what we want? */
747 add_frame_mode = GP_GETFRAME_ADD_NEW;
750 /* insert gp frames */
751 for (ale = anim_data.first; ale; ale = ale->next) {
752 bGPDlayer *gpl = (bGPDlayer *)ale->data;
753 gpencil_layer_getframe(gpl, CFRA, add_frame_mode);
756 ANIM_animdata_update(ac, &anim_data);
757 ANIM_animdata_freelist(&anim_data);
760 /* ------------------- */
762 static int actkeys_insertkey_exec(bContext *C, wmOperator *op)
767 /* get editor data */
768 if (ANIM_animdata_get_context(C, &ac) == 0)
769 return OPERATOR_CANCELLED;
771 if (ac.datatype == ANIMCONT_MASK) {
772 BKE_report(op->reports, RPT_ERROR, "Insert Keyframes is not yet implemented for this mode");
773 return OPERATOR_CANCELLED;
776 /* what channels to affect? */
777 mode = RNA_enum_get(op->ptr, "type");
779 /* insert keyframes */
780 if (ac.datatype == ANIMCONT_GPENCIL) {
781 insert_gpencil_keys(&ac, mode);
784 insert_action_keys(&ac, mode);
787 /* set notifier that keyframes have changed */
788 WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_ADDED, NULL);
790 return OPERATOR_FINISHED;
793 void ACTION_OT_keyframe_insert(wmOperatorType *ot)
796 ot->name = "Insert Keyframes";
797 ot->idname = "ACTION_OT_keyframe_insert";
798 ot->description = "Insert keyframes for the specified channels";
801 ot->invoke = WM_menu_invoke;
802 ot->exec = actkeys_insertkey_exec;
803 ot->poll = ED_operator_action_active;
806 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
809 ot->prop = RNA_def_enum(ot->srna, "type", prop_actkeys_insertkey_types, 0, "Type", "");
812 /* ******************** Duplicate Keyframes Operator ************************* */
814 static void duplicate_action_keys(bAnimContext *ac)
816 ListBase anim_data = {NULL, NULL};
821 if (ELEM(ac->datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK))
822 filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS);
824 filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT /*| ANIMFILTER_CURVESONLY*/ | ANIMFILTER_NODUPLIS);
825 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
827 /* loop through filtered data and delete selected keys */
828 for (ale = anim_data.first; ale; ale = ale->next) {
829 if (ELEM(ale->type, ANIMTYPE_FCURVE, ANIMTYPE_NLACURVE))
830 duplicate_fcurve_keys((FCurve *)ale->key_data);
831 else if (ale->type == ANIMTYPE_GPLAYER)
832 ED_gplayer_frames_duplicate((bGPDlayer *)ale->data);
833 else if (ale->type == ANIMTYPE_MASKLAYER)
834 ED_masklayer_frames_duplicate((MaskLayer *)ale->data);
838 ale->update |= ANIM_UPDATE_DEFAULT;
841 ANIM_animdata_update(ac, &anim_data);
842 ANIM_animdata_freelist(&anim_data);
845 /* ------------------- */
847 static int actkeys_duplicate_exec(bContext *C, wmOperator *UNUSED(op))
851 /* get editor data */
852 if (ANIM_animdata_get_context(C, &ac) == 0)
853 return OPERATOR_CANCELLED;
855 /* duplicate keyframes */
856 duplicate_action_keys(&ac);
858 /* set notifier that keyframes have changed */
859 WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_ADDED, NULL);
861 return OPERATOR_FINISHED;
864 void ACTION_OT_duplicate(wmOperatorType *ot)
867 ot->name = "Duplicate Keyframes";
868 ot->idname = "ACTION_OT_duplicate";
869 ot->description = "Make a copy of all selected keyframes";
872 ot->exec = actkeys_duplicate_exec;
873 ot->poll = ED_operator_action_active;
876 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
879 /* ******************** Delete Keyframes Operator ************************* */
881 static bool delete_action_keys(bAnimContext *ac)
883 ListBase anim_data = {NULL, NULL};
886 bool changed_final = false;
889 if (ELEM(ac->datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK))
890 filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS);
892 filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT /*| ANIMFILTER_CURVESONLY*/ | ANIMFILTER_NODUPLIS);
893 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
895 /* loop through filtered data and delete selected keys */
896 for (ale = anim_data.first; ale; ale = ale->next) {
897 bool changed = false;
899 if (ale->type == ANIMTYPE_GPLAYER) {
900 changed = ED_gplayer_frames_delete((bGPDlayer *)ale->data);
902 else if (ale->type == ANIMTYPE_MASKLAYER) {
903 changed = ED_masklayer_frames_delete((MaskLayer *)ale->data);
906 FCurve *fcu = (FCurve *)ale->key_data;
907 AnimData *adt = ale->adt;
909 /* delete selected keyframes only */
910 changed = delete_fcurve_keys(fcu);
912 /* Only delete curve too if it won't be doing anything anymore */
913 if ((fcu->totvert == 0) && (list_has_suitable_fmodifier(&fcu->modifiers, 0, FMI_TYPE_GENERATE_CURVE) == 0)) {
914 ANIM_fcurve_delete_from_animdata(ac, adt, fcu);
915 ale->key_data = NULL;
920 ale->update |= ANIM_UPDATE_DEFAULT;
921 changed_final = true;
925 ANIM_animdata_update(ac, &anim_data);
926 ANIM_animdata_freelist(&anim_data);
928 return changed_final;
931 /* ------------------- */
933 static int actkeys_delete_exec(bContext *C, wmOperator *UNUSED(op))
937 /* get editor data */
938 if (ANIM_animdata_get_context(C, &ac) == 0)
939 return OPERATOR_CANCELLED;
941 /* delete keyframes */
942 if (!delete_action_keys(&ac))
943 return OPERATOR_CANCELLED;
945 /* set notifier that keyframes have changed */
946 WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_REMOVED, NULL);
948 return OPERATOR_FINISHED;
951 void ACTION_OT_delete(wmOperatorType *ot)
954 ot->name = "Delete Keyframes";
955 ot->idname = "ACTION_OT_delete";
956 ot->description = "Remove all selected keyframes";
959 ot->invoke = WM_operator_confirm;
960 ot->exec = actkeys_delete_exec;
961 ot->poll = ED_operator_action_active;
964 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
967 /* ******************** Clean Keyframes Operator ************************* */
969 static void clean_action_keys(bAnimContext *ac, float thresh, bool clean_chan)
971 ListBase anim_data = {NULL, NULL};
976 filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_SEL /*| ANIMFILTER_CURVESONLY*/ | ANIMFILTER_NODUPLIS);
977 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
979 /* loop through filtered data and clean curves */
980 for (ale = anim_data.first; ale; ale = ale->next) {
981 clean_fcurve(ac, ale, thresh, clean_chan);
983 ale->update |= ANIM_UPDATE_DEFAULT;
986 ANIM_animdata_update(ac, &anim_data);
987 ANIM_animdata_freelist(&anim_data);
990 /* ------------------- */
992 static int actkeys_clean_exec(bContext *C, wmOperator *op)
998 /* get editor data */
999 if (ANIM_animdata_get_context(C, &ac) == 0)
1000 return OPERATOR_CANCELLED;
1002 if (ELEM(ac.datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK)) {
1003 BKE_report(op->reports, RPT_ERROR, "Not implemented");
1004 return OPERATOR_PASS_THROUGH;
1007 /* get cleaning threshold */
1008 thresh = RNA_float_get(op->ptr, "threshold");
1009 clean_chan = RNA_boolean_get(op->ptr, "channels");
1011 /* clean keyframes */
1012 clean_action_keys(&ac, thresh, clean_chan);
1014 /* set notifier that keyframes have changed */
1015 WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
1017 return OPERATOR_FINISHED;
1020 void ACTION_OT_clean(wmOperatorType *ot)
1023 ot->name = "Clean Keyframes";
1024 ot->idname = "ACTION_OT_clean";
1025 ot->description = "Simplify F-Curves by removing closely spaced keyframes";
1028 //ot->invoke = // XXX we need that number popup for this!
1029 ot->exec = actkeys_clean_exec;
1030 ot->poll = ED_operator_action_active;
1033 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1036 ot->prop = RNA_def_float(ot->srna, "threshold", 0.001f, 0.0f, FLT_MAX, "Threshold", "", 0.0f, 1000.0f);
1037 RNA_def_boolean(ot->srna, "channels", false, "Channels", "");
1040 /* ******************** Sample Keyframes Operator *********************** */
1042 /* Evaluates the curves between each selected keyframe on each frame, and keys the value */
1043 static void sample_action_keys(bAnimContext *ac)
1045 ListBase anim_data = {NULL, NULL};
1050 filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT /*| ANIMFILTER_CURVESONLY*/ | ANIMFILTER_NODUPLIS);
1051 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
1053 /* loop through filtered data and add keys between selected keyframes on every frame */
1054 for (ale = anim_data.first; ale; ale = ale->next) {
1055 sample_fcurve((FCurve *)ale->key_data);
1057 ale->update |= ANIM_UPDATE_DEPS;
1060 ANIM_animdata_update(ac, &anim_data);
1061 ANIM_animdata_freelist(&anim_data);
1064 /* ------------------- */
1066 static int actkeys_sample_exec(bContext *C, wmOperator *op)
1070 /* get editor data */
1071 if (ANIM_animdata_get_context(C, &ac) == 0)
1072 return OPERATOR_CANCELLED;
1074 if (ELEM(ac.datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK)) {
1075 BKE_report(op->reports, RPT_ERROR, "Not implemented");
1076 return OPERATOR_PASS_THROUGH;
1079 /* sample keyframes */
1080 sample_action_keys(&ac);
1082 /* set notifier that keyframes have changed */
1083 WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
1085 return OPERATOR_FINISHED;
1088 void ACTION_OT_sample(wmOperatorType *ot)
1091 ot->name = "Sample Keyframes";
1092 ot->idname = "ACTION_OT_sample";
1093 ot->description = "Add keyframes on every frame between the selected keyframes";
1096 ot->exec = actkeys_sample_exec;
1097 ot->poll = ED_operator_action_active;
1100 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1103 /* ************************************************************************** */
1104 /* SETTINGS STUFF */
1106 /* ******************** Set Extrapolation-Type Operator *********************** */
1108 /* defines for make/clear cyclic extrapolation tools */
1109 #define MAKE_CYCLIC_EXPO -1
1110 #define CLEAR_CYCLIC_EXPO -2
1112 /* defines for set extrapolation-type for selected keyframes tool */
1113 static EnumPropertyItem prop_actkeys_expo_types[] = {
1114 {FCURVE_EXTRAPOLATE_CONSTANT, "CONSTANT", 0, "Constant Extrapolation", "Values on endpoint keyframes are held"},
1115 {FCURVE_EXTRAPOLATE_LINEAR, "LINEAR", 0, "Linear Extrapolation", "Straight-line slope of end segments are extended past the endpoint keyframes"},
1117 {MAKE_CYCLIC_EXPO, "MAKE_CYCLIC", 0, "Make Cyclic (F-Modifier)", "Add Cycles F-Modifier if one doesn't exist already"},
1118 {CLEAR_CYCLIC_EXPO, "CLEAR_CYCLIC", 0, "Clear Cyclic (F-Modifier)", "Remove Cycles F-Modifier if not needed anymore"},
1119 {0, NULL, 0, NULL, NULL}
1122 /* this function is responsible for setting extrapolation mode for keyframes */
1123 static void setexpo_action_keys(bAnimContext *ac, short mode)
1125 ListBase anim_data = {NULL, NULL};
1130 filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_SEL /*| ANIMFILTER_CURVESONLY*/ | ANIMFILTER_NODUPLIS);
1131 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
1133 /* loop through setting mode per F-Curve */
1134 for (ale = anim_data.first; ale; ale = ale->next) {
1135 FCurve *fcu = (FCurve *)ale->data;
1138 /* just set mode setting */
1142 /* shortcuts for managing Cycles F-Modifiers to make it easier to toggle cyclic animation
1143 * without having to go through FModifier UI in Graph Editor to do so
1145 if (mode == MAKE_CYCLIC_EXPO) {
1146 /* only add if one doesn't exist */
1147 if (list_has_suitable_fmodifier(&fcu->modifiers, FMODIFIER_TYPE_CYCLES, -1) == 0) {
1148 /* TODO: add some more preset versions which set different extrapolation options? */
1149 add_fmodifier(&fcu->modifiers, FMODIFIER_TYPE_CYCLES);
1152 else if (mode == CLEAR_CYCLIC_EXPO) {
1153 /* remove all the modifiers fitting this description */
1154 FModifier *fcm, *fcn = NULL;
1156 for (fcm = fcu->modifiers.first; fcm; fcm = fcn) {
1159 if (fcm->type == FMODIFIER_TYPE_CYCLES)
1160 remove_fmodifier(&fcu->modifiers, fcm);
1165 ale->update |= ANIM_UPDATE_DEFAULT;
1168 ANIM_animdata_update(ac, &anim_data);
1169 ANIM_animdata_freelist(&anim_data);
1172 /* ------------------- */
1174 static int actkeys_expo_exec(bContext *C, wmOperator *op)
1179 /* get editor data */
1180 if (ANIM_animdata_get_context(C, &ac) == 0)
1181 return OPERATOR_CANCELLED;
1183 if (ELEM(ac.datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK)) {
1184 BKE_report(op->reports, RPT_ERROR, "Not implemented");
1185 return OPERATOR_PASS_THROUGH;
1188 /* get handle setting mode */
1189 mode = RNA_enum_get(op->ptr, "type");
1191 /* set handle type */
1192 setexpo_action_keys(&ac, mode);
1194 /* set notifier that keyframe properties have changed */
1195 WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME_PROP, NULL);
1197 return OPERATOR_FINISHED;
1200 void ACTION_OT_extrapolation_type(wmOperatorType *ot)
1203 ot->name = "Set Keyframe Extrapolation";
1204 ot->idname = "ACTION_OT_extrapolation_type";
1205 ot->description = "Set extrapolation mode for selected F-Curves";
1208 ot->invoke = WM_menu_invoke;
1209 ot->exec = actkeys_expo_exec;
1210 ot->poll = ED_operator_action_active;
1213 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1216 ot->prop = RNA_def_enum(ot->srna, "type", prop_actkeys_expo_types, 0, "Type", "");
1219 /* ******************** Set Interpolation-Type Operator *********************** */
1221 /* this function is responsible for setting interpolation mode for keyframes */
1222 static void setipo_action_keys(bAnimContext *ac, short mode)
1224 ListBase anim_data = {NULL, NULL};
1227 KeyframeEditFunc set_cb = ANIM_editkeyframes_ipo(mode);
1230 filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT /*| ANIMFILTER_CURVESONLY*/ | ANIMFILTER_NODUPLIS);
1231 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
1233 /* loop through setting BezTriple interpolation
1234 * Note: we do not supply KeyframeEditData to the looper yet. Currently that's not necessary here...
1236 for (ale = anim_data.first; ale; ale = ale->next) {
1237 ANIM_fcurve_keyframes_loop(NULL, ale->key_data, NULL, set_cb, calchandles_fcurve);
1239 ale->update |= ANIM_UPDATE_DEFAULT;
1242 ANIM_animdata_update(ac, &anim_data);
1243 ANIM_animdata_freelist(&anim_data);
1246 /* ------------------- */
1248 static int actkeys_ipo_exec(bContext *C, wmOperator *op)
1253 /* get editor data */
1254 if (ANIM_animdata_get_context(C, &ac) == 0)
1255 return OPERATOR_CANCELLED;
1257 if (ELEM(ac.datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK)) {
1258 BKE_report(op->reports, RPT_ERROR, "Not implemented");
1259 return OPERATOR_PASS_THROUGH;
1262 /* get handle setting mode */
1263 mode = RNA_enum_get(op->ptr, "type");
1265 /* set handle type */
1266 setipo_action_keys(&ac, mode);
1268 /* set notifier that keyframe properties have changed */
1269 WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME_PROP, NULL);
1271 return OPERATOR_FINISHED;
1274 void ACTION_OT_interpolation_type(wmOperatorType *ot)
1277 ot->name = "Set Keyframe Interpolation";
1278 ot->idname = "ACTION_OT_interpolation_type";
1279 ot->description = "Set interpolation mode for the F-Curve segments starting from the selected keyframes";
1282 ot->invoke = WM_menu_invoke;
1283 ot->exec = actkeys_ipo_exec;
1284 ot->poll = ED_operator_action_active;
1287 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1290 ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_beztriple_interpolation_mode_items, 0, "Type", "");
1293 /* ******************** Set Handle-Type Operator *********************** */
1295 /* this function is responsible for setting handle-type of selected keyframes */
1296 static void sethandles_action_keys(bAnimContext *ac, short mode)
1298 ListBase anim_data = {NULL, NULL};
1302 KeyframeEditFunc edit_cb = ANIM_editkeyframes_handles(mode);
1303 KeyframeEditFunc sel_cb = ANIM_editkeyframes_ok(BEZT_OK_SELECTED);
1306 filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT /*| ANIMFILTER_CURVESONLY*/ | ANIMFILTER_NODUPLIS);
1307 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
1309 /* loop through setting flags for handles
1310 * Note: we do not supply KeyframeEditData to the looper yet. Currently that's not necessary here...
1312 for (ale = anim_data.first; ale; ale = ale->next) {
1313 FCurve *fcu = (FCurve *)ale->key_data;
1315 /* any selected keyframes for editing? */
1316 if (ANIM_fcurve_keyframes_loop(NULL, fcu, NULL, sel_cb, NULL)) {
1317 /* change type of selected handles */
1318 ANIM_fcurve_keyframes_loop(NULL, fcu, NULL, edit_cb, calchandles_fcurve);
1320 ale->update |= ANIM_UPDATE_DEFAULT;
1324 ANIM_animdata_update(ac, &anim_data);
1325 ANIM_animdata_freelist(&anim_data);
1328 /* ------------------- */
1330 static int actkeys_handletype_exec(bContext *C, wmOperator *op)
1335 /* get editor data */
1336 if (ANIM_animdata_get_context(C, &ac) == 0)
1337 return OPERATOR_CANCELLED;
1339 if (ELEM(ac.datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK)) {
1340 BKE_report(op->reports, RPT_ERROR, "Not implemented");
1341 return OPERATOR_PASS_THROUGH;
1344 /* get handle setting mode */
1345 mode = RNA_enum_get(op->ptr, "type");
1347 /* set handle type */
1348 sethandles_action_keys(&ac, mode);
1350 /* set notifier that keyframe properties have changed */
1351 WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME_PROP, NULL);
1353 return OPERATOR_FINISHED;
1356 void ACTION_OT_handle_type(wmOperatorType *ot)
1359 ot->name = "Set Keyframe Handle Type";
1360 ot->idname = "ACTION_OT_handle_type";
1361 ot->description = "Set type of handle for selected keyframes";
1364 ot->invoke = WM_menu_invoke;
1365 ot->exec = actkeys_handletype_exec;
1366 ot->poll = ED_operator_action_active;
1369 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1372 ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_keyframe_handle_type_items, 0, "Type", "");
1375 /* ******************** Set Keyframe-Type Operator *********************** */
1377 /* this function is responsible for setting keyframe type for keyframes */
1378 static void setkeytype_action_keys(bAnimContext *ac, short mode)
1380 ListBase anim_data = {NULL, NULL};
1383 KeyframeEditFunc set_cb = ANIM_editkeyframes_keytype(mode);
1386 filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT /*| ANIMFILTER_CURVESONLY*/ | ANIMFILTER_NODUPLIS);
1387 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
1389 /* loop through setting BezTriple interpolation
1390 * Note: we do not supply KeyframeEditData to the looper yet. Currently that's not necessary here...
1392 for (ale = anim_data.first; ale; ale = ale->next) {
1393 ANIM_fcurve_keyframes_loop(NULL, ale->key_data, NULL, set_cb, NULL);
1395 ale->update |= ANIM_UPDATE_DEPS | ANIM_UPDATE_HANDLES;
1398 ANIM_animdata_update(ac, &anim_data);
1399 ANIM_animdata_freelist(&anim_data);
1402 /* this function is responsible for setting the keyframe type for Grease Pencil frames */
1403 static void setkeytype_gpencil_keys(bAnimContext *ac, short mode)
1405 ListBase anim_data = {NULL, NULL};
1410 filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS);
1411 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
1413 /* loop through each layer */
1414 for (ale = anim_data.first; ale; ale = ale->next) {
1415 if (ale->type == ANIMTYPE_GPLAYER) {
1416 ED_gplayer_frames_keytype_set(ale->data, mode);
1417 ale->update |= ANIM_UPDATE_DEPS;
1421 ANIM_animdata_update(ac, &anim_data);
1422 ANIM_animdata_freelist(&anim_data);
1425 /* ------------------- */
1427 static int actkeys_keytype_exec(bContext *C, wmOperator *op)
1432 /* get editor data */
1433 if (ANIM_animdata_get_context(C, &ac) == 0)
1434 return OPERATOR_CANCELLED;
1436 if (ac.datatype == ANIMCONT_MASK) {
1437 BKE_report(op->reports, RPT_ERROR, "Not implemented for Masks");
1438 return OPERATOR_PASS_THROUGH;
1441 /* get handle setting mode */
1442 mode = RNA_enum_get(op->ptr, "type");
1444 /* set handle type */
1445 if (ac.datatype == ANIMCONT_GPENCIL) {
1446 setkeytype_gpencil_keys(&ac, mode);
1449 setkeytype_action_keys(&ac, mode);
1452 /* set notifier that keyframe properties have changed */
1453 WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME_PROP, NULL);
1455 return OPERATOR_FINISHED;
1458 void ACTION_OT_keyframe_type(wmOperatorType *ot)
1461 ot->name = "Set Keyframe Type";
1462 ot->idname = "ACTION_OT_keyframe_type";
1463 ot->description = "Set type of keyframe for the selected keyframes";
1466 ot->invoke = WM_menu_invoke;
1467 ot->exec = actkeys_keytype_exec;
1468 ot->poll = ED_operator_action_active;
1471 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1474 ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_beztriple_keyframe_type_items, 0, "Type", "");
1477 /* ************************************************************************** */
1478 /* TRANSFORM STUFF */
1480 /* ***************** Jump to Selected Frames Operator *********************** */
1482 static int actkeys_framejump_poll(bContext *C)
1484 /* prevent changes during render */
1488 return ED_operator_action_active(C);
1491 /* snap current-frame indicator to 'average time' of selected keyframe */
1492 static int actkeys_framejump_exec(bContext *C, wmOperator *UNUSED(op))
1495 ListBase anim_data = {NULL, NULL};
1498 KeyframeEditData ked = {{NULL}};
1500 /* get editor data */
1501 if (ANIM_animdata_get_context(C, &ac) == 0)
1502 return OPERATOR_CANCELLED;
1504 /* init edit data */
1505 /* loop over action data, averaging values */
1506 filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE /*| ANIMFILTER_CURVESONLY */ | ANIMFILTER_NODUPLIS);
1507 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
1509 for (ale = anim_data.first; ale; ale = ale->next) {
1510 AnimData *adt = ANIM_nla_mapping_get(&ac, ale);
1512 ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, 1);
1513 ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, bezt_calc_average, NULL);
1514 ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 1, 1);
1517 ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, bezt_calc_average, NULL);
1520 ANIM_animdata_freelist(&anim_data);
1522 /* set the new current frame value, based on the average time */
1524 Scene *scene = ac.scene;
1525 CFRA = iroundf(ked.f1 / ked.i1);
1529 /* set notifier that things have changed */
1530 WM_event_add_notifier(C, NC_SCENE | ND_FRAME, ac.scene);
1532 return OPERATOR_FINISHED;
1535 void ACTION_OT_frame_jump(wmOperatorType *ot)
1538 ot->name = "Jump to Keyframes";
1539 ot->idname = "ACTION_OT_frame_jump";
1540 ot->description = "Set the current frame to the average frame value of selected keyframes";
1543 ot->exec = actkeys_framejump_exec;
1544 ot->poll = actkeys_framejump_poll;
1547 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1550 /* ******************** Snap Keyframes Operator *********************** */
1552 /* defines for snap keyframes tool */
1553 static EnumPropertyItem prop_actkeys_snap_types[] = {
1554 {ACTKEYS_SNAP_CFRA, "CFRA", 0, "Current frame",
1555 "Snap selected keyframes to the current frame"},
1556 {ACTKEYS_SNAP_NEAREST_FRAME, "NEAREST_FRAME", 0, "Nearest Frame",
1557 "Snap selected keyframes to the nearest (whole) frame (use to fix accidental sub-frame offsets)"},
1558 {ACTKEYS_SNAP_NEAREST_SECOND, "NEAREST_SECOND", 0, "Nearest Second",
1559 "Snap selected keyframes to the nearest second"},
1560 {ACTKEYS_SNAP_NEAREST_MARKER, "NEAREST_MARKER", 0, "Nearest Marker",
1561 "Snap selected keyframes to the nearest marker"},
1562 {0, NULL, 0, NULL, NULL}
1565 /* this function is responsible for snapping keyframes to frame-times */
1566 static void snap_action_keys(bAnimContext *ac, short mode)
1568 ListBase anim_data = {NULL, NULL};
1572 KeyframeEditData ked = {{NULL}};
1573 KeyframeEditFunc edit_cb;
1576 if (ELEM(ac->datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK))
1577 filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
1579 filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT /*| ANIMFILTER_CURVESONLY*/ | ANIMFILTER_NODUPLIS);
1580 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
1582 /* get beztriple editing callbacks */
1583 edit_cb = ANIM_editkeyframes_snap(mode);
1585 ked.scene = ac->scene;
1586 if (mode == ACTKEYS_SNAP_NEAREST_MARKER) {
1587 ked.list.first = (ac->markers) ? ac->markers->first : NULL;
1588 ked.list.last = (ac->markers) ? ac->markers->last : NULL;
1591 /* snap keyframes */
1592 for (ale = anim_data.first; ale; ale = ale->next) {
1593 AnimData *adt = ANIM_nla_mapping_get(ac, ale);
1595 if (ale->type == ANIMTYPE_GPLAYER) {
1596 ED_gplayer_snap_frames(ale->data, ac->scene, mode);
1598 else if (ale->type == ANIMTYPE_MASKLAYER) {
1599 ED_masklayer_snap_frames(ale->data, ac->scene, mode);
1602 ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, 0);
1603 ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, edit_cb, calchandles_fcurve);
1604 ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 1, 0);
1607 ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, edit_cb, calchandles_fcurve);
1610 ale->update |= ANIM_UPDATE_DEFAULT;
1613 ANIM_animdata_update(ac, &anim_data);
1614 ANIM_animdata_freelist(&anim_data);
1617 /* ------------------- */
1619 static int actkeys_snap_exec(bContext *C, wmOperator *op)
1624 /* get editor data */
1625 if (ANIM_animdata_get_context(C, &ac) == 0)
1626 return OPERATOR_CANCELLED;
1628 /* get snapping mode */
1629 mode = RNA_enum_get(op->ptr, "type");
1631 /* snap keyframes */
1632 snap_action_keys(&ac, mode);
1634 /* set notifier that keyframes have changed */
1635 WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
1637 return OPERATOR_FINISHED;
1640 void ACTION_OT_snap(wmOperatorType *ot)
1643 ot->name = "Snap Keys";
1644 ot->idname = "ACTION_OT_snap";
1645 ot->description = "Snap selected keyframes to the times specified";
1648 ot->invoke = WM_menu_invoke;
1649 ot->exec = actkeys_snap_exec;
1650 ot->poll = ED_operator_action_active;
1653 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1656 ot->prop = RNA_def_enum(ot->srna, "type", prop_actkeys_snap_types, 0, "Type", "");
1659 /* ******************** Mirror Keyframes Operator *********************** */
1661 /* defines for mirror keyframes tool */
1662 static EnumPropertyItem prop_actkeys_mirror_types[] = {
1663 {ACTKEYS_MIRROR_CFRA, "CFRA", 0, "By Times over Current frame",
1664 "Flip times of selected keyframes using the current frame as the mirror line"},
1665 {ACTKEYS_MIRROR_XAXIS, "XAXIS", 0, "By Values over Value=0",
1666 "Flip values of selected keyframes (i.e. negative values become positive, and vice versa)"},
1667 {ACTKEYS_MIRROR_MARKER, "MARKER", 0, "By Times over First Selected Marker",
1668 "Flip times of selected keyframes using the first selected marker as the reference point"},
1669 {0, NULL, 0, NULL, NULL}
1672 /* this function is responsible for mirroring keyframes */
1673 static void mirror_action_keys(bAnimContext *ac, short mode)
1675 ListBase anim_data = {NULL, NULL};
1679 KeyframeEditData ked = {{NULL}};
1680 KeyframeEditFunc edit_cb;
1682 /* get beztriple editing callbacks */
1683 edit_cb = ANIM_editkeyframes_mirror(mode);
1685 ked.scene = ac->scene;
1687 /* for 'first selected marker' mode, need to find first selected marker first! */
1688 /* XXX should this be made into a helper func in the API? */
1689 if (mode == ACTKEYS_MIRROR_MARKER) {
1690 TimeMarker *marker = ED_markers_get_first_selected(ac->markers);
1693 ked.f1 = (float)marker->frame;
1699 if (ELEM(ac->datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK))
1700 filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS);
1702 filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT /*| ANIMFILTER_CURVESONLY*/ | ANIMFILTER_NODUPLIS);
1703 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
1705 /* mirror keyframes */
1706 for (ale = anim_data.first; ale; ale = ale->next) {
1707 AnimData *adt = ANIM_nla_mapping_get(ac, ale);
1709 if (ale->type == ANIMTYPE_GPLAYER) {
1710 ED_gplayer_mirror_frames(ale->data, ac->scene, mode);
1712 else if (ale->type == ANIMTYPE_MASKLAYER) {
1716 ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, 0);
1717 ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, edit_cb, calchandles_fcurve);
1718 ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 1, 0);
1721 ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, edit_cb, calchandles_fcurve);
1724 ale->update |= ANIM_UPDATE_DEFAULT;
1727 ANIM_animdata_update(ac, &anim_data);
1728 ANIM_animdata_freelist(&anim_data);
1731 /* ------------------- */
1733 static int actkeys_mirror_exec(bContext *C, wmOperator *op)
1738 /* get editor data */
1739 if (ANIM_animdata_get_context(C, &ac) == 0)
1740 return OPERATOR_CANCELLED;
1742 /* get mirroring mode */
1743 mode = RNA_enum_get(op->ptr, "type");
1745 /* mirror keyframes */
1746 mirror_action_keys(&ac, mode);
1748 /* set notifier that keyframes have changed */
1749 WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
1751 return OPERATOR_FINISHED;
1754 void ACTION_OT_mirror(wmOperatorType *ot)
1757 ot->name = "Mirror Keys";
1758 ot->idname = "ACTION_OT_mirror";
1759 ot->description = "Flip selected keyframes over the selected mirror line";
1762 ot->invoke = WM_menu_invoke;
1763 ot->exec = actkeys_mirror_exec;
1764 ot->poll = ED_operator_action_active;
1767 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1770 ot->prop = RNA_def_enum(ot->srna, "type", prop_actkeys_mirror_types, 0, "Type", "");
1773 /* ************************************************************************** */