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) 2009 Blender Foundation, Joshua Leung
19 * All rights reserved.
22 * Contributor(s): Joshua Leung (major recode)
24 * ***** END GPL LICENSE BLOCK *****
27 /** \file blender/editors/space_nla/nla_edit.c
36 #include "DNA_anim_types.h"
37 #include "DNA_object_types.h"
38 #include "DNA_scene_types.h"
40 #include "MEM_guardedalloc.h"
42 #include "BLI_blenlib.h"
45 #include "BLI_utildefines.h"
47 #include "BKE_action.h"
48 #include "BKE_fcurve.h"
50 #include "BKE_context.h"
52 #include "BKE_report.h"
53 #include "BKE_screen.h"
55 #include "ED_anim_api.h"
56 #include "ED_keyframes_edit.h"
57 #include "ED_markers.h"
58 #include "ED_screen.h"
59 #include "ED_transform.h"
61 #include "RNA_access.h"
62 #include "RNA_define.h"
63 #include "RNA_enum_types.h"
68 #include "UI_interface.h"
69 #include "UI_resources.h"
70 #include "UI_view2d.h"
72 #include "nla_intern.h" // own include
73 #include "nla_private.h" // FIXME... maybe this shouldn't be included?
75 /* *********************************************** */
76 /* Utilities exported to other places... */
78 /* Perform validation for blending/extend settings */
79 void ED_nla_postop_refresh(bAnimContext *ac)
81 ListBase anim_data = {NULL, NULL};
83 short filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_ANIMDATA | ANIMFILTER_FOREDIT);
85 /* get blocks to work on */
86 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
88 for (ale = anim_data.first; ale; ale = ale->next) {
89 /* performing auto-blending, extend-mode validation, etc. */
90 BKE_nla_validate_state(ale->data);
93 /* free temp memory */
94 BLI_freelistN(&anim_data);
97 /* *********************************************** */
98 /* 'Special' Editing */
100 /* ******************** Tweak-Mode Operators ***************************** */
101 /* 'Tweak mode' allows the action referenced by the active NLA-strip to be edited
102 * as if it were the normal Active-Action of its AnimData block.
105 static int nlaedit_enable_tweakmode_exec(bContext *C, wmOperator *op)
109 ListBase anim_data = {NULL, NULL};
114 /* get editor data */
115 if (ANIM_animdata_get_context(C, &ac) == 0)
116 return OPERATOR_CANCELLED;
118 /* get a list of the AnimData blocks being shown in the NLA */
119 filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_ANIMDATA);
120 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
122 /* if no blocks, popup error? */
123 if (anim_data.first == NULL) {
124 BKE_report(op->reports, RPT_ERROR, "No AnimData blocks to enter tweakmode for");
125 return OPERATOR_CANCELLED;
128 /* for each AnimData block with NLA-data, try setting it in tweak-mode */
129 for (ale = anim_data.first; ale; ale = ale->next) {
130 AnimData *adt = ale->data;
132 /* try entering tweakmode if valid */
133 ok += BKE_nla_tweakmode_enter(adt);
137 BLI_freelistN(&anim_data);
139 /* if we managed to enter tweakmode on at least one AnimData block,
140 * set the flag for this in the active scene and send notifiers
142 if (ac.scene && ok) {
143 /* set editing flag */
144 ac.scene->flag |= SCE_NLA_EDIT_ON;
146 /* set notifier that things have changed */
147 WM_event_add_notifier(C, NC_ANIMATION | ND_NLA_ACTCHANGE, NULL);
150 BKE_report(op->reports, RPT_ERROR, "No active strip(s) to enter tweakmode on");
151 return OPERATOR_CANCELLED;
155 return OPERATOR_FINISHED;
158 void NLA_OT_tweakmode_enter(wmOperatorType *ot)
161 ot->name = "Enter Tweak Mode";
162 ot->idname = "NLA_OT_tweakmode_enter";
163 ot->description = "Enter tweaking mode for the action referenced by the active strip";
166 ot->exec = nlaedit_enable_tweakmode_exec;
167 ot->poll = nlaop_poll_tweakmode_off;
170 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
175 static int nlaedit_disable_tweakmode_exec(bContext *C, wmOperator *op)
179 ListBase anim_data = {NULL, NULL};
183 /* get editor data */
184 if (ANIM_animdata_get_context(C, &ac) == 0)
185 return OPERATOR_CANCELLED;
187 /* get a list of the AnimData blocks being shown in the NLA */
188 filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_ANIMDATA);
189 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
191 /* if no blocks, popup error? */
192 if (anim_data.first == NULL) {
193 BKE_report(op->reports, RPT_ERROR, "No AnimData blocks to enter tweakmode for");
194 return OPERATOR_CANCELLED;
197 /* for each AnimData block with NLA-data, try exitting tweak-mode */
198 for (ale = anim_data.first; ale; ale = ale->next) {
199 AnimData *adt = ale->data;
201 /* try entering tweakmode if valid */
202 BKE_nla_tweakmode_exit(adt);
206 BLI_freelistN(&anim_data);
208 /* if we managed to enter tweakmode on at least one AnimData block,
209 * set the flag for this in the active scene and send notifiers
212 /* clear editing flag */
213 ac.scene->flag &= ~SCE_NLA_EDIT_ON;
215 /* set notifier that things have changed */
216 WM_event_add_notifier(C, NC_ANIMATION | ND_NLA_ACTCHANGE, NULL);
220 return OPERATOR_FINISHED;
223 void NLA_OT_tweakmode_exit(wmOperatorType *ot)
226 ot->name = "Exit Tweak Mode";
227 ot->idname = "NLA_OT_tweakmode_exit";
228 ot->description = "Exit tweaking mode for the action referenced by the active strip";
231 ot->exec = nlaedit_disable_tweakmode_exec;
232 ot->poll = nlaop_poll_tweakmode_on;
235 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
238 /* *********************************************** */
239 /* NLA Strips Range Stuff */
241 /* *************************** Calculate Range ************************** */
243 /* Get the min/max strip extents */
244 static void get_nlastrip_extents(bAnimContext *ac, float *min, float *max, const short onlySel)
246 ListBase anim_data = {NULL, NULL};
250 /* get data to filter */
251 filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_NODUPLIS);
252 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
254 /* set large values to try to override */
256 *max = -999999999.0f;
258 /* check if any channels to set range with */
259 if (anim_data.first) {
260 /* go through channels, finding max extents */
261 for (ale = anim_data.first; ale; ale = ale->next) {
262 NlaTrack *nlt = (NlaTrack *)ale->data;
265 for (strip = nlt->strips.first; strip; strip = strip->next) {
266 /* only consider selected strips? */
267 if ((onlySel == 0) || (strip->flag & NLASTRIP_FLAG_SELECT)) {
268 /* extend range if appropriate */
269 *min = minf(*min, strip->start);
270 *max = maxf(*max, strip->end);
276 BLI_freelistN(&anim_data);
279 /* set default range */
281 *min = (float)ac->scene->r.sfra;
282 *max = (float)ac->scene->r.efra;
291 /* ****************** View-All Operator ****************** */
293 static int nlaedit_viewall(bContext *C, const short onlySel)
299 /* get editor data */
300 if (ANIM_animdata_get_context(C, &ac) == 0)
301 return OPERATOR_CANCELLED;
304 /* set the horizontal range, with an extra offset so that the extreme keys will be in view */
305 get_nlastrip_extents(&ac, &v2d->cur.xmin, &v2d->cur.xmax, onlySel);
307 extra = 0.1f * BLI_rctf_size_x(&v2d->cur);
308 v2d->cur.xmin -= extra;
309 v2d->cur.xmax += extra;
311 /* set vertical range */
312 v2d->cur.ymax = 0.0f;
313 v2d->cur.ymin = (float)-BLI_rcti_size_y(&v2d->mask);
315 /* do View2D syncing */
316 UI_view2d_sync(CTX_wm_screen(C), CTX_wm_area(C), v2d, V2D_LOCK_COPY);
318 /* just redraw this view */
319 ED_area_tag_redraw(CTX_wm_area(C));
321 return OPERATOR_FINISHED;
326 static int nlaedit_viewall_exec(bContext *C, wmOperator *UNUSED(op))
329 return nlaedit_viewall(C, FALSE);
332 static int nlaedit_viewsel_exec(bContext *C, wmOperator *UNUSED(op))
335 return nlaedit_viewall(C, TRUE);
338 void NLA_OT_view_all(wmOperatorType *ot)
341 ot->name = "View All";
342 ot->idname = "NLA_OT_view_all";
343 ot->description = "Reset viewable area to show full strips range";
346 ot->exec = nlaedit_viewall_exec;
347 ot->poll = ED_operator_nla_active;
350 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
353 void NLA_OT_view_selected(wmOperatorType *ot)
356 ot->name = "View Selected";
357 ot->idname = "NLA_OT_view_selected";
358 ot->description = "Reset viewable area to show selected strips range";
361 ot->exec = nlaedit_viewsel_exec;
362 ot->poll = ED_operator_nla_active;
365 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
368 /* *********************************************** */
369 /* NLA Editing Operations (Constructive/Destructive) */
371 /* ******************** Add Action-Clip Operator ***************************** */
372 /* Add a new Action-Clip strip to the active track (or the active block if no space in the track) */
375 /* add the specified action as new strip */
376 static int nlaedit_add_actionclip_exec(bContext *C, wmOperator *op)
381 ListBase anim_data = {NULL, NULL};
390 /* get editor data */
391 if (ANIM_animdata_get_context(C, &ac) == 0)
392 return OPERATOR_CANCELLED;
397 /* get action to use */
398 act = BLI_findlink(&CTX_data_main(C)->action, RNA_enum_get(op->ptr, "action"));
401 BKE_report(op->reports, RPT_ERROR, "No valid Action to add");
402 //printf("Add strip - actname = '%s'\n", actname);
403 return OPERATOR_CANCELLED;
405 else if (act->idroot == 0) {
406 /* hopefully in this case (i.e. library of userless actions), the user knows what they're doing... */
407 BKE_reportf(op->reports, RPT_WARNING,
408 "Action '%s' does not specify what datablocks it can be used on. Try setting the 'ID Root Type' setting from the Datablocks Editor for this Action to avoid future problems",
412 /* get a list of the editable tracks being shown in the NLA
413 * - this is limited to active ones for now, but could be expanded to
415 filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_ACTIVE | ANIMFILTER_FOREDIT);
416 items = ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
419 BKE_report(op->reports, RPT_ERROR, "No active track(s) to add strip to");
420 return OPERATOR_CANCELLED;
423 /* for every active track, try to add strip to free space in track or to the top of the stack if no space */
424 for (ale = anim_data.first; ale; ale = ale->next) {
425 NlaTrack *nlt = (NlaTrack *)ale->data;
426 AnimData *adt = ale->adt;
427 NlaStrip *strip = NULL;
429 /* sanity check: only apply actions of the right type for this ID
430 * NOTE: in the case that this hasn't been set, we've already warned the user about this already
432 if ((act->idroot) && (act->idroot != GS(ale->id->name))) {
433 BKE_reportf(op->reports, RPT_ERROR,
434 "Couldn't add action '%s' as it cannot be used relative to ID-blocks of type '%s'",
435 act->id.name + 2, ale->id->name);
439 /* create a new strip, and offset it to start on the current frame */
440 strip = add_nlastrip(act);
442 strip->end += (cfra - strip->start);
445 /* firstly try adding strip to our current track, but if that fails, add to a new track */
446 if (BKE_nlatrack_add_strip(nlt, strip) == 0) {
447 /* trying to add to the current failed (no space),
448 * so add a new track to the stack, and add to that...
450 nlt = add_nlatrack(adt, NULL);
451 BKE_nlatrack_add_strip(nlt, strip);
455 BKE_nlastrip_validate_name(adt, strip);
459 BLI_freelistN(&anim_data);
461 /* refresh auto strip properties */
462 ED_nla_postop_refresh(&ac);
464 /* set notifier that things have changed */
465 WM_event_add_notifier(C, NC_ANIMATION | ND_NLA | NA_EDITED, NULL);
468 return OPERATOR_FINISHED;
471 void NLA_OT_actionclip_add(wmOperatorType *ot)
476 ot->name = "Add Action Strip";
477 ot->idname = "NLA_OT_actionclip_add";
478 ot->description = "Add an Action-Clip strip (i.e. an NLA Strip referencing an Action) to the active track";
481 ot->invoke = WM_enum_search_invoke;
482 ot->exec = nlaedit_add_actionclip_exec;
483 ot->poll = nlaop_poll_tweakmode_off;
486 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
489 // TODO: this would be nicer as an ID-pointer...
490 prop = RNA_def_enum(ot->srna, "action", DummyRNA_NULL_items, 0, "Action", "");
491 RNA_def_enum_funcs(prop, RNA_action_itemf);
495 /* ******************** Add Transition Operator ***************************** */
496 /* Add a new transition strip between selected strips */
498 static int nlaedit_add_transition_exec(bContext *C, wmOperator *op)
502 ListBase anim_data = {NULL, NULL};
508 /* get editor data */
509 if (ANIM_animdata_get_context(C, &ac) == 0)
510 return OPERATOR_CANCELLED;
512 /* get a list of the editable tracks being shown in the NLA */
513 filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
514 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
516 /* for each track, find pairs of strips to add transitions to */
517 for (ale = anim_data.first; ale; ale = ale->next) {
518 NlaTrack *nlt = (NlaTrack *)ale->data;
519 AnimData *adt = ale->adt;
522 /* get initial pair of strips */
523 if (ELEM(nlt->strips.first, NULL, nlt->strips.last))
525 s1 = nlt->strips.first;
528 /* loop over strips */
529 for (; s1 && s2; s1 = s2, s2 = s2->next) {
532 /* check if both are selected */
533 if (ELEM(0, (s1->flag & NLASTRIP_FLAG_SELECT), (s2->flag & NLASTRIP_FLAG_SELECT)))
535 /* check if there's space between the two */
536 if (IS_EQF(s1->end, s2->start))
538 /* make sure neither one is a transition
539 * - although this is impossible to create with the standard tools,
540 * the user may have altered the settings
542 if (ELEM(NLASTRIP_TYPE_TRANSITION, s1->type, s2->type))
544 /* also make sure neither one is a soundclip */
545 if (ELEM(NLASTRIP_TYPE_SOUND, s1->type, s2->type))
548 /* allocate new strip */
549 strip = MEM_callocN(sizeof(NlaStrip), "NlaStrip");
550 BLI_insertlinkafter(&nlt->strips, s1, strip);
553 strip->type = NLASTRIP_TYPE_TRANSITION;
556 * - selected flag to highlight this to the user
557 * - auto-blends to ensure that blend in/out values are automatically
558 * determined by overlaps of strips
560 strip->flag = NLASTRIP_FLAG_SELECT | NLASTRIP_FLAG_AUTO_BLENDS;
562 /* range is simply defined as the endpoints of the adjacent strips */
563 strip->start = s1->end;
564 strip->end = s2->start;
566 /* scale and repeat aren't of any use, but shouldn't ever be 0 */
568 strip->repeat = 1.0f;
571 BKE_nlastrip_validate_name(adt, strip);
573 /* make note of this */
579 BLI_freelistN(&anim_data);
581 /* was anything added? */
583 /* refresh auto strip properties */
584 ED_nla_postop_refresh(&ac);
586 /* set notifier that things have changed */
587 WM_event_add_notifier(C, NC_ANIMATION | ND_NLA | NA_EDITED, NULL);
590 return OPERATOR_FINISHED;
593 BKE_report(op->reports, RPT_ERROR, "Needs at least a pair of adjacent selected strips with a gap between them");
594 return OPERATOR_CANCELLED;
598 void NLA_OT_transition_add(wmOperatorType *ot)
601 ot->name = "Add Transition";
602 ot->idname = "NLA_OT_transition_add";
603 ot->description = "Add a transition strip between two adjacent selected strips";
606 ot->exec = nlaedit_add_transition_exec;
607 ot->poll = nlaop_poll_tweakmode_off;
610 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
613 /* ******************** Add Sound Clip Operator ***************************** */
614 /* Add a new sound clip */
616 static int nlaedit_add_sound_exec(bContext *C, wmOperator *UNUSED(op))
620 ListBase anim_data = {NULL, NULL};
627 /* get editor data */
628 if (ANIM_animdata_get_context(C, &ac) == 0)
629 return OPERATOR_CANCELLED;
634 /* get a list of the editable tracks being shown in the NLA */
635 filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_SEL | ANIMFILTER_FOREDIT);
636 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
638 /* for each track, add sound clips if it belongs to a speaker */
639 // TODO: what happens if there aren't any tracks... well that's a more general problem for later
640 for (ale = anim_data.first; ale; ale = ale->next) {
641 Object *ob = (Object *)ale->id; /* may not be object until we actually check! */
643 AnimData *adt = ale->adt;
644 NlaTrack *nlt = (NlaTrack *)ale->data;
647 /* does this belong to speaker - assumed to live on Object level only */
648 if ((GS(ale->id->name) != ID_OB) || (ob->type != OB_SPEAKER))
651 /* create a new strip, and offset it to start on the current frame */
652 strip = add_nla_soundstrip(ac.scene, ob->data);
654 strip->start += cfra;
657 /* firstly try adding strip to our current track, but if that fails, add to a new track */
658 if (BKE_nlatrack_add_strip(nlt, strip) == 0) {
659 /* trying to add to the current failed (no space),
660 * so add a new track to the stack, and add to that...
662 nlt = add_nlatrack(adt, NULL);
663 BKE_nlatrack_add_strip(nlt, strip);
667 BKE_nlastrip_validate_name(adt, strip);
671 BLI_freelistN(&anim_data);
673 /* refresh auto strip properties */
674 ED_nla_postop_refresh(&ac);
676 /* set notifier that things have changed */
677 WM_event_add_notifier(C, NC_ANIMATION | ND_NLA | NA_EDITED, NULL);
680 return OPERATOR_FINISHED;
683 void NLA_OT_soundclip_add(wmOperatorType *ot)
686 ot->name = "Add Sound Clip";
687 ot->idname = "NLA_OT_soundclip_add";
688 ot->description = "Add a strip for controlling when speaker plays its sound clip";
691 ot->exec = nlaedit_add_sound_exec;
692 ot->poll = nlaop_poll_tweakmode_off;
695 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
698 /* ******************** Add Meta-Strip Operator ***************************** */
699 /* Add new meta-strips incorporating the selected strips */
701 /* add the specified action as new strip */
702 static int nlaedit_add_meta_exec(bContext *C, wmOperator *UNUSED(op))
706 ListBase anim_data = {NULL, NULL};
710 /* get editor data */
711 if (ANIM_animdata_get_context(C, &ac) == 0)
712 return OPERATOR_CANCELLED;
714 /* get a list of the editable tracks being shown in the NLA */
715 filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
716 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
718 /* for each track, find pairs of strips to add transitions to */
719 for (ale = anim_data.first; ale; ale = ale->next) {
720 NlaTrack *nlt = (NlaTrack *)ale->data;
721 AnimData *adt = ale->adt;
724 /* create meta-strips from the continuous chains of selected strips */
725 BKE_nlastrips_make_metas(&nlt->strips, 0);
728 for (strip = nlt->strips.first; strip; strip = strip->next) {
729 /* auto-name this strip if selected (that means it is a meta) */
730 if (strip->flag & NLASTRIP_FLAG_SELECT)
731 BKE_nlastrip_validate_name(adt, strip);
736 BLI_freelistN(&anim_data);
738 /* set notifier that things have changed */
739 WM_event_add_notifier(C, NC_ANIMATION | ND_NLA | NA_EDITED, NULL);
742 return OPERATOR_FINISHED;
745 void NLA_OT_meta_add(wmOperatorType *ot)
748 ot->name = "Add Meta-Strips";
749 ot->idname = "NLA_OT_meta_add";
750 ot->description = "Add new meta-strips incorporating the selected strips";
753 ot->exec = nlaedit_add_meta_exec;
754 ot->poll = nlaop_poll_tweakmode_off;
757 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
760 /* ******************** Remove Meta-Strip Operator ***************************** */
761 /* Separate out the strips held by the selected meta-strips */
763 static int nlaedit_remove_meta_exec(bContext *C, wmOperator *UNUSED(op))
767 ListBase anim_data = {NULL, NULL};
771 /* get editor data */
772 if (ANIM_animdata_get_context(C, &ac) == 0)
773 return OPERATOR_CANCELLED;
775 /* get a list of the editable tracks being shown in the NLA */
776 filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
777 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
779 /* for each track, find pairs of strips to add transitions to */
780 for (ale = anim_data.first; ale; ale = ale->next) {
781 NlaTrack *nlt = (NlaTrack *)ale->data;
783 /* clear all selected meta-strips, regardless of whether they are temporary or not */
784 BKE_nlastrips_clear_metas(&nlt->strips, 1, 0);
788 BLI_freelistN(&anim_data);
790 /* set notifier that things have changed */
791 WM_event_add_notifier(C, NC_ANIMATION | ND_NLA | NA_EDITED, NULL);
794 return OPERATOR_FINISHED;
797 void NLA_OT_meta_remove(wmOperatorType *ot)
800 ot->name = "Remove Meta-Strips";
801 ot->idname = "NLA_OT_meta_remove";
802 ot->description = "Separate out the strips held by the selected meta-strips";
805 ot->exec = nlaedit_remove_meta_exec;
806 ot->poll = nlaop_poll_tweakmode_off;
809 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
812 /* ******************** Duplicate Strips Operator ************************** */
813 /* Duplicates the selected NLA-Strips, putting them on new tracks above the one
814 * the originals were housed in.
817 static int nlaedit_duplicate_exec(bContext *C, wmOperator *UNUSED(op))
821 ListBase anim_data = {NULL, NULL};
827 /* get editor data */
828 if (ANIM_animdata_get_context(C, &ac) == 0)
829 return OPERATOR_CANCELLED;
831 /* get a list of editable tracks being shown in the NLA */
832 filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
833 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
835 /* duplicate strips in tracks starting from the last one so that we're
836 * less likely to duplicate strips we just duplicated...
838 for (ale = anim_data.last; ale; ale = ale->prev) {
839 NlaTrack *nlt = (NlaTrack *)ale->data;
840 AnimData *adt = ale->adt;
841 NlaStrip *strip, *nstrip, *next;
844 for (strip = nlt->strips.first; strip; strip = next) {
847 /* if selected, split the strip at its midpoint */
848 if (strip->flag & NLASTRIP_FLAG_SELECT) {
849 /* make a copy (assume that this is possible) */
850 nstrip = copy_nlastrip(strip);
852 /* in case there's no space in the track above, or we haven't got a reference to it yet, try adding */
853 if (BKE_nlatrack_add_strip(nlt->next, nstrip) == 0) {
854 /* need to add a new track above the one above the current one
855 * - if the current one is the last one, nlt->next will be NULL, which defaults to adding
856 * at the top of the stack anyway...
858 track = add_nlatrack(adt, nlt->next);
859 BKE_nlatrack_add_strip(track, nstrip);
862 /* deselect the original and the active flag */
863 strip->flag &= ~(NLASTRIP_FLAG_SELECT | NLASTRIP_FLAG_ACTIVE);
865 /* auto-name newly created strip */
866 BKE_nlastrip_validate_name(adt, nstrip);
874 BLI_freelistN(&anim_data);
877 /* refresh auto strip properties */
878 ED_nla_postop_refresh(&ac);
880 /* set notifier that things have changed */
881 WM_event_add_notifier(C, NC_ANIMATION | ND_NLA | NA_EDITED, NULL);
884 return OPERATOR_FINISHED;
887 return OPERATOR_CANCELLED;
890 static int nlaedit_duplicate_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
892 nlaedit_duplicate_exec(C, op);
894 RNA_enum_set(op->ptr, "mode", TFM_TRANSLATION);
895 WM_operator_name_call(C, "TRANSFORM_OT_transform", WM_OP_INVOKE_REGION_WIN, op->ptr);
897 return OPERATOR_FINISHED;
900 void NLA_OT_duplicate(wmOperatorType *ot)
903 ot->name = "Duplicate Strips";
904 ot->idname = "NLA_OT_duplicate";
905 ot->description = "Duplicate selected NLA-Strips, adding the new strips in new tracks above the originals";
908 ot->invoke = nlaedit_duplicate_invoke;
909 ot->exec = nlaedit_duplicate_exec;
910 ot->poll = nlaop_poll_tweakmode_off;
913 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
915 /* to give to transform */
916 RNA_def_enum(ot->srna, "mode", transform_mode_types, TFM_TRANSLATION, "Mode", "");
919 /* ******************** Delete Strips Operator ***************************** */
920 /* Deletes the selected NLA-Strips */
922 static int nlaedit_delete_exec(bContext *C, wmOperator *UNUSED(op))
926 ListBase anim_data = {NULL, NULL};
930 /* get editor data */
931 if (ANIM_animdata_get_context(C, &ac) == 0)
932 return OPERATOR_CANCELLED;
934 /* get a list of the editable tracks being shown in the NLA */
935 filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
936 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
938 /* for each NLA-Track, delete all selected strips */
939 for (ale = anim_data.first; ale; ale = ale->next) {
940 NlaTrack *nlt = (NlaTrack *)ale->data;
941 NlaStrip *strip, *nstrip;
943 for (strip = nlt->strips.first; strip; strip = nstrip) {
944 nstrip = strip->next;
946 /* if selected, delete */
947 if (strip->flag & NLASTRIP_FLAG_SELECT) {
948 /* if a strip either side of this was a transition, delete those too */
949 if ((strip->prev) && (strip->prev->type == NLASTRIP_TYPE_TRANSITION))
950 free_nlastrip(&nlt->strips, strip->prev);
951 if ((nstrip) && (nstrip->type == NLASTRIP_TYPE_TRANSITION)) {
952 nstrip = nstrip->next;
953 free_nlastrip(&nlt->strips, strip->next);
956 /* finally, delete this strip */
957 free_nlastrip(&nlt->strips, strip);
963 BLI_freelistN(&anim_data);
965 /* refresh auto strip properties */
966 ED_nla_postop_refresh(&ac);
968 /* set notifier that things have changed */
969 WM_event_add_notifier(C, NC_ANIMATION | ND_NLA | NA_EDITED, NULL);
972 return OPERATOR_FINISHED;
975 void NLA_OT_delete(wmOperatorType *ot)
978 ot->name = "Delete Strips";
979 ot->idname = "NLA_OT_delete";
980 ot->description = "Delete selected strips";
983 ot->exec = nlaedit_delete_exec;
984 ot->poll = nlaop_poll_tweakmode_off;
987 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
990 /* ******************** Split Strips Operator ***************************** */
991 /* Splits the selected NLA-Strips into two strips at the midpoint of the strip */
994 // - variable-length splits?
996 /* split a given Action-Clip strip */
997 static void nlaedit_split_strip_actclip(AnimData *adt, NlaTrack *nlt, NlaStrip *strip, float cfra)
1000 float splitframe, splitaframe;
1002 /* calculate the frames to do the splitting at
1003 * - use current frame if within extents of strip
1005 if ((cfra > strip->start) && (cfra < strip->end)) {
1006 /* use the current frame */
1008 splitaframe = nlastrip_get_frame(strip, cfra, NLATIME_CONVERT_UNMAP);
1011 /* split in the middle */
1015 len = strip->end - strip->start;
1016 if (IS_EQF(len, 0.0f))
1019 splitframe = strip->start + (len / 2.0f);
1022 len = strip->actend - strip->actstart;
1023 if (IS_EQF(len, 0.0f))
1024 splitaframe = strip->actend;
1026 splitaframe = strip->actstart + (len / 2.0f);
1029 /* make a copy (assume that this is possible) and append
1030 * it immediately after the current strip
1032 nstrip = copy_nlastrip(strip);
1033 BLI_insertlinkafter(&nlt->strips, strip, nstrip);
1035 /* set the endpoint of the first strip and the start of the new strip
1036 * to the splitframe values calculated above
1038 strip->end = splitframe;
1039 nstrip->start = splitframe;
1041 if ((splitaframe > strip->actstart) && (splitaframe < strip->actend)) {
1042 /* only do this if we're splitting down the middle... */
1043 strip->actend = splitaframe;
1044 nstrip->actstart = splitaframe;
1047 /* clear the active flag from the copy */
1048 nstrip->flag &= ~NLASTRIP_FLAG_ACTIVE;
1050 /* auto-name the new strip */
1051 BKE_nlastrip_validate_name(adt, nstrip);
1054 /* split a given Meta strip */
1055 static void nlaedit_split_strip_meta(NlaTrack *nlt, NlaStrip *strip)
1057 /* simply ungroup it for now... */
1058 BKE_nlastrips_clear_metastrip(&nlt->strips, strip);
1063 static int nlaedit_split_exec(bContext *C, wmOperator *UNUSED(op))
1067 ListBase anim_data = {NULL, NULL};
1071 /* get editor data */
1072 if (ANIM_animdata_get_context(C, &ac) == 0)
1073 return OPERATOR_CANCELLED;
1075 /* get a list of editable tracks being shown in the NLA */
1076 filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
1077 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
1079 /* for each NLA-Track, split all selected strips into two strips */
1080 for (ale = anim_data.first; ale; ale = ale->next) {
1081 NlaTrack *nlt = (NlaTrack *)ale->data;
1082 AnimData *adt = ale->adt;
1083 NlaStrip *strip, *next;
1085 for (strip = nlt->strips.first; strip; strip = next) {
1088 /* if selected, split the strip at its midpoint */
1089 if (strip->flag & NLASTRIP_FLAG_SELECT) {
1090 /* splitting method depends on the type of strip */
1091 switch (strip->type) {
1092 case NLASTRIP_TYPE_CLIP: /* action-clip */
1093 nlaedit_split_strip_actclip(adt, nlt, strip, (float)ac.scene->r.cfra);
1096 case NLASTRIP_TYPE_META: /* meta-strips need special handling */
1097 nlaedit_split_strip_meta(nlt, strip);
1100 default: /* for things like Transitions, do not split! */
1107 /* free temp data */
1108 BLI_freelistN(&anim_data);
1110 /* refresh auto strip properties */
1111 ED_nla_postop_refresh(&ac);
1113 /* set notifier that things have changed */
1114 WM_event_add_notifier(C, NC_ANIMATION | ND_NLA | NA_EDITED, NULL);
1117 return OPERATOR_FINISHED;
1120 void NLA_OT_split(wmOperatorType *ot)
1123 ot->name = "Split Strips";
1124 ot->idname = "NLA_OT_split";
1125 ot->description = "Split selected strips at their midpoints";
1128 ot->exec = nlaedit_split_exec;
1129 ot->poll = nlaop_poll_tweakmode_off;
1132 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1135 /* ******************** Bake Strips Operator ***************************** */
1136 /* Bakes the NLA Strips for the active AnimData blocks */
1138 static int nlaedit_bake_exec(bContext *C, wmOperator *UNUSED(op))
1142 ListBase anim_data = {NULL, NULL};
1147 /* get editor data */
1148 if (ANIM_animdata_get_context(C, &ac) == 0)
1149 return OPERATOR_CANCELLED;
1151 /* get a list of the editable tracks being shown in the NLA */
1152 filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_ANIMDATA | ANIMFILTER_FOREDIT);
1153 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
1155 /* for each AnimData block, bake strips to animdata... */
1156 for (ale = anim_data.first; ale; ale = ale->next) {
1157 //BKE_nla_bake(ac.scene, ale->id, ale->data, flag);
1160 /* free temp data */
1161 BLI_freelistN(&anim_data);
1163 /* refresh auto strip properties */
1164 ED_nla_postop_refresh(&ac);
1166 /* set notifier that things have changed */
1167 WM_event_add_notifier(C, NC_ANIMATION | ND_NLA | NA_EDITED, NULL);
1170 return OPERATOR_FINISHED;
1173 static void NLA_OT_bake(wmOperatorType *ot)
1176 ot->name = "Bake Strips";
1177 ot->idname = "NLA_OT_bake";
1178 ot->description = "Bake all strips of selected AnimData blocks";
1181 ot->exec = nlaedit_bake_exec;
1182 ot->poll = nlaop_poll_tweakmode_off;
1185 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1188 /* *********************************************** */
1189 /* NLA Editing Operations (Modifying) */
1191 /* ******************** Toggle Muting Operator ************************** */
1192 /* Toggles whether strips are muted or not */
1194 static int nlaedit_toggle_mute_exec(bContext *C, wmOperator *UNUSED(op))
1198 ListBase anim_data = {NULL, NULL};
1202 /* get editor data */
1203 if (ANIM_animdata_get_context(C, &ac) == 0)
1204 return OPERATOR_CANCELLED;
1206 /* get a list of the editable tracks being shown in the NLA */
1207 filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
1208 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
1210 /* go over all selected strips */
1211 for (ale = anim_data.first; ale; ale = ale->next) {
1212 NlaTrack *nlt = (NlaTrack *)ale->data;
1215 /* for every selected strip, toggle muting */
1216 for (strip = nlt->strips.first; strip; strip = strip->next) {
1217 if (strip->flag & NLASTRIP_FLAG_SELECT) {
1218 /* just flip the mute flag for now */
1219 // TODO: have a pre-pass to check if mute all or unmute all?
1220 strip->flag ^= NLASTRIP_FLAG_MUTED;
1225 /* free temp data */
1226 BLI_freelistN(&anim_data);
1228 /* set notifier that things have changed */
1229 WM_event_add_notifier(C, NC_ANIMATION | ND_NLA | NA_EDITED, NULL);
1232 return OPERATOR_FINISHED;
1235 void NLA_OT_mute_toggle(wmOperatorType *ot)
1238 ot->name = "Toggle Muting";
1239 ot->idname = "NLA_OT_mute_toggle";
1240 ot->description = "Mute or un-mute selected strips";
1243 ot->exec = nlaedit_toggle_mute_exec;
1244 ot->poll = nlaop_poll_tweakmode_off;
1247 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1250 /* ******************** Swap Strips Operator ************************** */
1251 /* Tries to exchange strips within their owner tracks */
1253 static int nlaedit_swap_exec(bContext *C, wmOperator *op)
1257 ListBase anim_data = {NULL, NULL};
1261 /* get editor data */
1262 if (ANIM_animdata_get_context(C, &ac) == 0)
1263 return OPERATOR_CANCELLED;
1265 /* get a list of the editable tracks being shown in the NLA */
1266 filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
1267 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
1269 /* consider each track in turn */
1270 for (ale = anim_data.first; ale; ale = ale->next) {
1271 NlaTrack *nlt = (NlaTrack *)ale->data;
1273 NlaStrip *strip, *stripN = NULL;
1274 NlaStrip *sa = NULL, *sb = NULL;
1276 /* make temporary metastrips so that entire islands of selections can be moved around */
1277 BKE_nlastrips_make_metas(&nlt->strips, 1);
1279 /* special case: if there is only 1 island (i.e. temp meta BUT NOT unselected/normal/normal-meta strips) left after this,
1280 * and this island has two strips inside it, then we should be able to just swap these still...
1282 if ((nlt->strips.first == nlt->strips.last) && (nlt->strips.first != NULL)) {
1283 NlaStrip *mstrip = (NlaStrip *)nlt->strips.first;
1285 if ((mstrip->flag & NLASTRIP_FLAG_TEMP_META) && (BLI_countlist(&mstrip->strips) == 2)) {
1286 /* remove this temp meta, so that we can see the strips inside */
1287 BKE_nlastrips_clear_metas(&nlt->strips, 0, 1);
1291 /* get two selected strips only (these will be metas due to prev step) to operate on
1292 * - only allow swapping 2, as with more the context becomes unclear
1294 for (strip = nlt->strips.first; strip; strip = stripN) {
1295 stripN = strip->next;
1297 if (strip->flag & NLASTRIP_FLAG_SELECT) {
1298 /* first or second strip? */
1300 /* store as first */
1303 else if (sb == NULL) {
1304 /* store as second */
1308 /* too many selected */
1315 /* too many selected warning */
1316 BKE_reportf(op->reports, RPT_WARNING,
1317 "Too many clusters of strips selected in NLA Track (%s): needs exactly 2 to be selected",
1320 else if (sa == NULL) {
1321 /* no warning as this is just a common case, and it may get annoying when doing multiple tracks */
1323 else if (sb == NULL) {
1324 /* too few selected warning */
1325 BKE_reportf(op->reports, RPT_WARNING,
1326 "Too few clusters of strips selected in NLA Track (%s): needs exactly 2 to be selected",
1330 float nsa[2], nsb[2];
1332 /* remove these strips from the track, so that we can test if they can fit in the proposed places */
1333 BLI_remlink(&nlt->strips, sa);
1334 BLI_remlink(&nlt->strips, sb);
1336 /* calculate new extents for strips */
1339 nsa[1] = sb->start + (sa->end - sa->start);
1342 nsb[1] = sa->start + (sb->end - sb->start);
1344 /* check if the track has room for the strips to be swapped */
1345 if (BKE_nlastrips_has_space(&nlt->strips, nsa[0], nsa[1]) &&
1346 BKE_nlastrips_has_space(&nlt->strips, nsb[0], nsb[1]))
1348 /* set new extents for strips then */
1351 BKE_nlameta_flush_transforms(sa);
1355 BKE_nlameta_flush_transforms(sb);
1358 /* not enough room to swap, so show message */
1359 if ((sa->flag & NLASTRIP_FLAG_TEMP_META) || (sb->flag & NLASTRIP_FLAG_TEMP_META)) {
1360 BKE_report(op->reports, RPT_WARNING,
1361 "Cannot swap selected strips as they will not be able to fit in their new places");
1364 BKE_reportf(op->reports, RPT_WARNING,
1365 "Cannot swap '%s' and '%s' as one or both will not be able to fit in their new places",
1366 sa->name, sb->name);
1370 /* add strips back to track now */
1371 BKE_nlatrack_add_strip(nlt, sa);
1372 BKE_nlatrack_add_strip(nlt, sb);
1375 /* clear (temp) metastrips */
1376 BKE_nlastrips_clear_metas(&nlt->strips, 0, 1);
1379 /* free temp data */
1380 BLI_freelistN(&anim_data);
1382 /* refresh auto strip properties */
1383 ED_nla_postop_refresh(&ac);
1385 /* set notifier that things have changed */
1386 WM_event_add_notifier(C, NC_ANIMATION | ND_NLA | NA_EDITED, NULL);
1389 return OPERATOR_FINISHED;
1392 void NLA_OT_swap(wmOperatorType *ot)
1395 ot->name = "Swap Strips";
1396 ot->idname = "NLA_OT_swap";
1397 ot->description = "Swap order of selected strips within tracks";
1400 ot->exec = nlaedit_swap_exec;
1401 ot->poll = nlaop_poll_tweakmode_off;
1404 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1407 /* ******************** Move Strips Up Operator ************************** */
1408 /* Tries to move the selected strips into the track above if possible. */
1410 static int nlaedit_move_up_exec(bContext *C, wmOperator *UNUSED(op))
1414 ListBase anim_data = {NULL, NULL};
1418 /* get editor data */
1419 if (ANIM_animdata_get_context(C, &ac) == 0)
1420 return OPERATOR_CANCELLED;
1422 /* get a list of the editable tracks being shown in the NLA */
1423 filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
1424 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
1426 /* since we're potentially moving strips from lower tracks to higher tracks, we should
1427 * loop over the tracks in reverse order to avoid moving earlier strips up multiple tracks
1429 for (ale = anim_data.last; ale; ale = ale->prev) {
1430 NlaTrack *nlt = (NlaTrack *)ale->data;
1431 NlaTrack *nltn = nlt->next;
1432 NlaStrip *strip, *stripn;
1434 /* if this track has no tracks after it, skip for now... */
1438 /* for every selected strip, try to move */
1439 for (strip = nlt->strips.first; strip; strip = stripn) {
1440 stripn = strip->next;
1442 if (strip->flag & NLASTRIP_FLAG_SELECT) {
1443 /* check if the track above has room for this strip */
1444 if (BKE_nlatrack_has_space(nltn, strip->start, strip->end)) {
1445 /* remove from its current track, and add to the one above (it 'should' work, so no need to worry) */
1446 BLI_remlink(&nlt->strips, strip);
1447 BKE_nlatrack_add_strip(nltn, strip);
1453 /* free temp data */
1454 BLI_freelistN(&anim_data);
1456 /* refresh auto strip properties */
1457 ED_nla_postop_refresh(&ac);
1459 /* set notifier that things have changed */
1460 WM_event_add_notifier(C, NC_ANIMATION | ND_NLA | NA_EDITED, NULL);
1463 return OPERATOR_FINISHED;
1466 void NLA_OT_move_up(wmOperatorType *ot)
1469 ot->name = "Move Strips Up";
1470 ot->idname = "NLA_OT_move_up";
1471 ot->description = "Move selected strips up a track if there's room";
1474 ot->exec = nlaedit_move_up_exec;
1475 ot->poll = nlaop_poll_tweakmode_off;
1478 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1481 /* ******************** Move Strips Down Operator ************************** */
1482 /* Tries to move the selected strips into the track above if possible. */
1484 static int nlaedit_move_down_exec(bContext *C, wmOperator *UNUSED(op))
1488 ListBase anim_data = {NULL, NULL};
1492 /* get editor data */
1493 if (ANIM_animdata_get_context(C, &ac) == 0)
1494 return OPERATOR_CANCELLED;
1496 /* get a list of the editable tracks being shown in the NLA */
1497 filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
1498 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
1500 /* loop through the tracks in normal order, since we're pushing strips down,
1501 * strips won't get operated on twice
1503 for (ale = anim_data.first; ale; ale = ale->next) {
1504 NlaTrack *nlt = (NlaTrack *)ale->data;
1505 NlaTrack *nltp = nlt->prev;
1506 NlaStrip *strip, *stripn;
1508 /* if this track has no tracks before it, skip for now... */
1512 /* for every selected strip, try to move */
1513 for (strip = nlt->strips.first; strip; strip = stripn) {
1514 stripn = strip->next;
1516 if (strip->flag & NLASTRIP_FLAG_SELECT) {
1517 /* check if the track below has room for this strip */
1518 if (BKE_nlatrack_has_space(nltp, strip->start, strip->end)) {
1519 /* remove from its current track, and add to the one above (it 'should' work, so no need to worry) */
1520 BLI_remlink(&nlt->strips, strip);
1521 BKE_nlatrack_add_strip(nltp, strip);
1527 /* free temp data */
1528 BLI_freelistN(&anim_data);
1530 /* refresh auto strip properties */
1531 ED_nla_postop_refresh(&ac);
1533 /* set notifier that things have changed */
1534 WM_event_add_notifier(C, NC_ANIMATION | ND_NLA | NA_EDITED, NULL);
1537 return OPERATOR_FINISHED;
1540 void NLA_OT_move_down(wmOperatorType *ot)
1543 ot->name = "Move Strips Down";
1544 ot->idname = "NLA_OT_move_down";
1545 ot->description = "Move selected strips down a track if there's room";
1548 ot->exec = nlaedit_move_down_exec;
1549 ot->poll = nlaop_poll_tweakmode_off;
1552 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1555 /* ******************** Sync Action Length Operator ***************************** */
1556 /* Recalculate the extents of the action ranges used for the selected strips */
1558 static int nlaedit_sync_actlen_exec(bContext *C, wmOperator *op)
1562 ListBase anim_data = {NULL, NULL};
1565 short active_only = RNA_boolean_get(op->ptr, "active");
1567 /* get editor data */
1568 if (ANIM_animdata_get_context(C, &ac) == 0)
1569 return OPERATOR_CANCELLED;
1571 /* get a list of the editable tracks being shown in the NLA */
1572 filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
1573 if (active_only) filter |= ANIMFILTER_ACTIVE;
1574 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
1576 /* for each NLA-Track, apply scale of all selected strips */
1577 for (ale = anim_data.first; ale; ale = ale->next) {
1578 NlaTrack *nlt = (NlaTrack *)ale->data;
1581 for (strip = nlt->strips.first; strip; strip = strip->next) {
1582 /* strip selection/active status check */
1584 if ((strip->flag & NLASTRIP_FLAG_ACTIVE) == 0)
1588 if ((strip->flag & NLASTRIP_FLAG_SELECT) == 0)
1592 /* must be action-clip only (transitions don't have scale) */
1593 if (strip->type == NLASTRIP_TYPE_CLIP) {
1594 if (strip->act == NULL)
1597 /* recalculate the length of the action */
1598 calc_action_range(strip->act, &strip->actstart, &strip->actend, 0);
1600 /* adjust the strip extents in response to this */
1601 BKE_nlastrip_recalculate_bounds(strip);
1606 /* free temp data */
1607 BLI_freelistN(&anim_data);
1609 /* set notifier that things have changed */
1610 WM_event_add_notifier(C, NC_ANIMATION | ND_NLA | NA_EDITED, NULL);
1613 return OPERATOR_FINISHED;
1616 void NLA_OT_action_sync_length(wmOperatorType *ot)
1619 ot->name = "Sync Action Length";
1620 ot->idname = "NLA_OT_action_sync_length";
1621 ot->description = "Synchronize the length of the referenced Action with the length used in the strip";
1624 ot->exec = nlaedit_sync_actlen_exec;
1625 ot->poll = ED_operator_nla_active; // XXX: is this satisfactory... probably requires a check for active strip...
1628 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1631 ot->prop = RNA_def_boolean(ot->srna, "active", 1, "Active Strip Only", "Only sync the active length for the active strip");
1634 /* ******************** Apply Scale Operator ***************************** */
1635 /* Reset the scaling of the selected strips to 1.0f */
1637 /* apply scaling to keyframe */
1638 static short bezt_apply_nlamapping(KeyframeEditData *ked, BezTriple *bezt)
1640 /* NLA-strip which has this scaling is stored in ked->data */
1641 NlaStrip *strip = (NlaStrip *)ked->data;
1643 /* adjust all the times */
1644 bezt->vec[0][0] = nlastrip_get_frame(strip, bezt->vec[0][0], NLATIME_CONVERT_MAP);
1645 bezt->vec[1][0] = nlastrip_get_frame(strip, bezt->vec[1][0], NLATIME_CONVERT_MAP);
1646 bezt->vec[2][0] = nlastrip_get_frame(strip, bezt->vec[2][0], NLATIME_CONVERT_MAP);
1648 /* nothing to return or else we exit */
1652 static int nlaedit_apply_scale_exec(bContext *C, wmOperator *UNUSED(op))
1656 ListBase anim_data = {NULL, NULL};
1660 KeyframeEditData ked = {{NULL}};
1662 /* get editor data */
1663 if (ANIM_animdata_get_context(C, &ac) == 0)
1664 return OPERATOR_CANCELLED;
1666 /* get a list of the editable tracks being shown in the NLA */
1667 filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
1668 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
1670 /* init the editing data */
1672 /* for each NLA-Track, apply scale of all selected strips */
1673 for (ale = anim_data.first; ale; ale = ale->next) {
1674 NlaTrack *nlt = (NlaTrack *)ale->data;
1677 for (strip = nlt->strips.first; strip; strip = strip->next) {
1678 /* strip must be selected, and must be action-clip only (transitions don't have scale) */
1679 if ((strip->flag & NLASTRIP_FLAG_SELECT) && (strip->type == NLASTRIP_TYPE_CLIP)) {
1680 /* if the referenced action is used by other strips, make this strip use its own copy */
1681 if (strip->act == NULL)
1683 if (strip->act->id.us > 1) {
1684 /* make a copy of the Action to work on */
1685 bAction *act = BKE_action_copy(strip->act);
1687 /* set this as the new referenced action, decrementing the users of the old one */
1688 strip->act->id.us--;
1692 /* setup iterator, and iterate over all the keyframes in the action, applying this scaling */
1694 ANIM_animchanneldata_keyframes_loop(&ked, ac.ads, strip->act, ALE_ACT, NULL, bezt_apply_nlamapping, calchandles_fcurve);
1696 /* clear scale of strip now that it has been applied,
1697 * and recalculate the extents of the action now that it has been scaled
1698 * but leave everything else alone
1700 strip->scale = 1.0f;
1701 calc_action_range(strip->act, &strip->actstart, &strip->actend, 0);
1706 /* free temp data */
1707 BLI_freelistN(&anim_data);
1709 /* set notifier that things have changed */
1710 WM_event_add_notifier(C, NC_ANIMATION | ND_NLA | NA_EDITED, NULL);
1713 return OPERATOR_FINISHED;
1716 void NLA_OT_apply_scale(wmOperatorType *ot)
1719 ot->name = "Apply Scale";
1720 ot->idname = "NLA_OT_apply_scale";
1721 ot->description = "Apply scaling of selected strips to their referenced Actions";
1724 ot->exec = nlaedit_apply_scale_exec;
1725 ot->poll = nlaop_poll_tweakmode_off;
1728 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1731 /* ******************** Clear Scale Operator ***************************** */
1732 /* Reset the scaling of the selected strips to 1.0f */
1734 static int nlaedit_clear_scale_exec(bContext *C, wmOperator *UNUSED(op))
1738 ListBase anim_data = {NULL, NULL};
1742 /* get editor data */
1743 if (ANIM_animdata_get_context(C, &ac) == 0)
1744 return OPERATOR_CANCELLED;
1746 /* get a list of the editable tracks being shown in the NLA */
1747 filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
1748 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
1750 /* for each NLA-Track, reset scale of all selected strips */
1751 for (ale = anim_data.first; ale; ale = ale->next) {
1752 NlaTrack *nlt = (NlaTrack *)ale->data;
1755 for (strip = nlt->strips.first; strip; strip = strip->next) {
1756 /* strip must be selected, and must be action-clip only (transitions don't have scale) */
1757 if ((strip->flag & NLASTRIP_FLAG_SELECT) && (strip->type == NLASTRIP_TYPE_CLIP)) {
1758 PointerRNA strip_ptr;
1760 RNA_pointer_create(NULL, &RNA_NlaStrip, strip, &strip_ptr);
1761 RNA_float_set(&strip_ptr, "scale", 1.0f);
1766 /* free temp data */
1767 BLI_freelistN(&anim_data);
1769 /* refresh auto strip properties */
1770 ED_nla_postop_refresh(&ac);
1772 /* set notifier that things have changed */
1773 WM_event_add_notifier(C, NC_ANIMATION | ND_NLA | NA_EDITED, NULL);
1776 return OPERATOR_FINISHED;
1779 void NLA_OT_clear_scale(wmOperatorType *ot)
1782 ot->name = "Clear Scale";
1783 ot->idname = "NLA_OT_clear_scale";
1784 ot->description = "Reset scaling of selected strips";
1787 ot->exec = nlaedit_clear_scale_exec;
1788 ot->poll = nlaop_poll_tweakmode_off;
1791 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1794 /* ******************** Snap Strips Operator ************************** */
1795 /* Moves the start-point of the selected strips to the specified places */
1797 /* defines for snap keyframes tool */
1798 static EnumPropertyItem prop_nlaedit_snap_types[] = {
1799 {NLAEDIT_SNAP_CFRA, "CFRA", 0, "Current frame", ""},
1800 {NLAEDIT_SNAP_NEAREST_FRAME, "NEAREST_FRAME", 0, "Nearest Frame", ""}, // XXX as single entry?
1801 {NLAEDIT_SNAP_NEAREST_SECOND, "NEAREST_SECOND", 0, "Nearest Second", ""}, // XXX as single entry?
1802 {NLAEDIT_SNAP_NEAREST_MARKER, "NEAREST_MARKER", 0, "Nearest Marker", ""},
1803 {0, NULL, 0, NULL, NULL}
1806 static int nlaedit_snap_exec(bContext *C, wmOperator *op)
1810 ListBase anim_data = {NULL, NULL};
1815 int mode = RNA_enum_get(op->ptr, "type");
1818 /* get editor data */
1819 if (ANIM_animdata_get_context(C, &ac) == 0)
1820 return OPERATOR_CANCELLED;
1822 /* get a list of the editable tracks being shown in the NLA */
1823 filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
1824 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
1826 /* get some necessary vars */
1830 /* since we may add tracks, perform this in reverse order */
1831 for (ale = anim_data.last; ale; ale = ale->prev) {
1832 ListBase tmp_strips = {NULL, NULL};
1833 AnimData *adt = ale->adt;
1834 NlaTrack *nlt = (NlaTrack *)ale->data;
1835 NlaStrip *strip, *stripn;
1838 /* create meta-strips from the continuous chains of selected strips */
1839 BKE_nlastrips_make_metas(&nlt->strips, 1);
1841 /* apply the snapping to all the temp meta-strips, then put them in a separate list to be added
1842 * back to the original only if they still fit
1844 for (strip = nlt->strips.first; strip; strip = stripn) {
1845 stripn = strip->next;
1847 if (strip->flag & NLASTRIP_FLAG_TEMP_META) {
1850 /* get the existing end-points */
1851 start = strip->start;
1854 /* calculate new start position based on snapping mode */
1856 case NLAEDIT_SNAP_CFRA: /* to current frame */
1857 strip->start = (float)CFRA;
1859 case NLAEDIT_SNAP_NEAREST_FRAME: /* to nearest frame */
1860 strip->start = floorf(start + 0.5f);
1862 case NLAEDIT_SNAP_NEAREST_SECOND: /* to nearest second */
1863 strip->start = floorf(start / secf + 0.5f) * secf;
1865 case NLAEDIT_SNAP_NEAREST_MARKER: /* to nearest marker */
1866 strip->start = (float)ED_markers_find_nearest_marker_time(ac.markers, start);
1868 default: /* just in case... no snapping */
1869 strip->start = start;
1873 /* get new endpoint based on start-point (and old length) */
1874 strip->end = strip->start + (end - start);
1876 /* apply transforms to meta-strip to its children */
1877 BKE_nlameta_flush_transforms(strip);
1879 /* remove strip from track, and add to the temp buffer */
1880 BLI_remlink(&nlt->strips, strip);
1881 BLI_addtail(&tmp_strips, strip);
1885 /* try adding each meta-strip back to the track one at a time, to make sure they'll fit */
1886 for (strip = tmp_strips.first; strip; strip = stripn) {
1887 stripn = strip->next;
1889 /* remove from temp-strips list */
1890 BLI_remlink(&tmp_strips, strip);
1892 /* in case there's no space in the current track, try adding */
1893 if (BKE_nlatrack_add_strip(nlt, strip) == 0) {
1894 /* need to add a new track above the current one */
1895 track = add_nlatrack(adt, nlt);
1896 BKE_nlatrack_add_strip(track, strip);
1898 /* clear temp meta-strips on this new track, as we may not be able to get back to it */
1899 BKE_nlastrips_clear_metas(&track->strips, 0, 1);
1903 /* remove the meta-strips now that we're done */
1904 BKE_nlastrips_clear_metas(&nlt->strips, 0, 1);
1907 /* free temp data */
1908 BLI_freelistN(&anim_data);
1910 /* refresh auto strip properties */
1911 ED_nla_postop_refresh(&ac);
1913 /* set notifier that things have changed */
1914 WM_event_add_notifier(C, NC_ANIMATION | ND_NLA | NA_EDITED, NULL);
1917 return OPERATOR_FINISHED;
1920 void NLA_OT_snap(wmOperatorType *ot)
1923 ot->name = "Snap Strips";
1924 ot->idname = "NLA_OT_snap";
1925 ot->description = "Move start of strips to specified time";
1928 ot->invoke = WM_menu_invoke;
1929 ot->exec = nlaedit_snap_exec;
1930 ot->poll = nlaop_poll_tweakmode_off;
1933 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1936 ot->prop = RNA_def_enum(ot->srna, "type", prop_nlaedit_snap_types, 0, "Type", "");
1939 /* *********************************************** */
1942 /* ******************** Add F-Modifier Operator *********************** */
1944 /* present a special customised popup menu for this, with some filtering */
1945 static int nla_fmodifier_add_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *UNUSED(event))
1951 pup = uiPupMenuBegin(C, "Add F-Modifier", ICON_NONE);
1952 layout = uiPupMenuLayout(pup);
1954 /* start from 1 to skip the 'Invalid' modifier type */
1955 for (i = 1; i < FMODIFIER_NUM_TYPES; i++) {
1956 FModifierTypeInfo *fmi = get_fmodifier_typeinfo(i);
1958 /* check if modifier is valid for this context */
1961 if (i == FMODIFIER_TYPE_CYCLES) /* we already have repeat... */
1964 /* add entry to add this type of modifier */
1965 uiItemEnumO(layout, "NLA_OT_fmodifier_add", fmi->name, 0, "type", i);
1969 uiPupMenuEnd(C, pup);
1971 return OPERATOR_CANCELLED;
1974 static int nla_fmodifier_add_exec(bContext *C, wmOperator *op)
1978 ListBase anim_data = {NULL, NULL};
1983 int type = RNA_enum_get(op->ptr, "type");
1984 short onlyActive = RNA_boolean_get(op->ptr, "only_active");
1986 /* get editor data */
1987 if (ANIM_animdata_get_context(C, &ac) == 0)
1988 return OPERATOR_CANCELLED;
1990 /* get a list of the editable tracks being shown in the NLA */
1991 filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
1992 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
1994 /* for each NLA-Track, add the specified modifier to all selected strips */
1995 for (ale = anim_data.first; ale; ale = ale->next) {
1996 NlaTrack *nlt = (NlaTrack *)ale->data;
1999 for (strip = nlt->strips.first; strip; strip = strip->next) {
2000 /* can F-Modifier be added to the current strip? */
2002 /* if not active, cannot add since we're only adding to active strip */
2003 if ((strip->flag & NLASTRIP_FLAG_ACTIVE) == 0)
2007 /* strip must be selected, since we're not just doing active */
2008 if ((strip->flag & NLASTRIP_FLAG_SELECT) == 0)
2012 /* sound clips are not affected by FModifiers */
2013 if (strip->type == NLASTRIP_TYPE_SOUND)
2016 /* add F-Modifier of specified type to selected, and make it the active one */
2017 fcm = add_fmodifier(&strip->modifiers, type);
2020 set_active_fmodifier(&strip->modifiers, fcm);
2022 BKE_reportf(op->reports, RPT_ERROR,
2023 "Modifier couldn't be added to (%s : %s) (see console for details)",
2024 nlt->name, strip->name);
2029 /* free temp data */
2030 BLI_freelistN(&anim_data);
2032 /* set notifier that things have changed */
2033 WM_event_add_notifier(C, NC_ANIMATION | ND_NLA | NA_EDITED, NULL);
2036 return OPERATOR_FINISHED;
2039 void NLA_OT_fmodifier_add(wmOperatorType *ot)
2042 ot->name = "Add F-Modifier";
2043 ot->idname = "NLA_OT_fmodifier_add";
2044 ot->description = "Add a F-Modifier of the specified type to the selected NLA-Strips";
2047 ot->invoke = nla_fmodifier_add_invoke;
2048 ot->exec = nla_fmodifier_add_exec;
2049 ot->poll = nlaop_poll_tweakmode_off;
2052 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2055 ot->prop = RNA_def_enum(ot->srna, "type", fmodifier_type_items, 0, "Type", "");
2056 RNA_def_boolean(ot->srna, "only_active", 0, "Only Active", "Only add a F-Modifier of the specified type to the active strip");
2059 /* ******************** Copy F-Modifiers Operator *********************** */
2061 static int nla_fmodifier_copy_exec(bContext *C, wmOperator *op)
2064 ListBase anim_data = {NULL, NULL};
2068 /* get editor data */
2069 if (ANIM_animdata_get_context(C, &ac) == 0)
2070 return OPERATOR_CANCELLED;
2072 /* clear buffer first */
2073 free_fmodifiers_copybuf();
2075 /* get a list of the editable tracks being shown in the NLA */
2076 filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
2077 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
2079 /* for each NLA-Track, add the specified modifier to all selected strips */
2080 for (ale = anim_data.first; ale; ale = ale->next) {
2081 NlaTrack *nlt = (NlaTrack *)ale->data;
2084 for (strip = nlt->strips.first; strip; strip = strip->next) {
2085 /* only add F-Modifier if on active strip? */
2086 if ((strip->flag & NLASTRIP_FLAG_ACTIVE) == 0)
2089 // TODO: when 'active' vs 'all' boolean is added, change last param!
2090 ok += ANIM_fmodifiers_copy_to_buf(&strip->modifiers, 0);
2094 /* successful or not? */
2096 BKE_report(op->reports, RPT_ERROR, "No F-Modifiers available to be copied");
2097 return OPERATOR_CANCELLED;
2100 return OPERATOR_FINISHED;
2103 void NLA_OT_fmodifier_copy(wmOperatorType *ot)
2106 ot->name = "Copy F-Modifiers";
2107 ot->idname = "NLA_OT_fmodifier_copy";
2108 ot->description = "Copy the F-Modifier(s) of the active NLA-Strip";
2111 ot->exec = nla_fmodifier_copy_exec;
2112 ot->poll = nlaop_poll_tweakmode_off;
2115 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2118 //ot->prop = RNA_def_boolean(ot->srna, "all", 1, "All F-Modifiers", "Copy all the F-Modifiers, instead of just the active one");
2121 /* ******************** Paste F-Modifiers Operator *********************** */
2123 static int nla_fmodifier_paste_exec(bContext *C, wmOperator *op)
2126 ListBase anim_data = {NULL, NULL};
2130 /* get editor data */
2131 if (ANIM_animdata_get_context(C, &ac) == 0)
2132 return OPERATOR_CANCELLED;
2134 /* get a list of the editable tracks being shown in the NLA */
2135 filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_SEL | ANIMFILTER_FOREDIT);
2136 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
2138 /* for each NLA-Track, add the specified modifier to all selected strips */
2139 for (ale = anim_data.first; ale; ale = ale->next) {
2140 NlaTrack *nlt = (NlaTrack *)ale->data;
2143 for (strip = nlt->strips.first; strip; strip = strip->next) {
2144 // TODO: do we want to replace existing modifiers? add user pref for that!
2145 ok += ANIM_fmodifiers_paste_from_buf(&strip->modifiers, 0);
2150 BLI_freelistN(&anim_data);
2152 /* successful or not? */
2154 /* set notifier that things have changed */
2155 /* set notifier that things have changed */
2156 WM_event_add_notifier(C, NC_ANIMATION | ND_NLA | NA_EDITED, NULL);
2157 return OPERATOR_FINISHED;
2160 BKE_report(op->reports, RPT_ERROR, "No F-Modifiers to paste");
2161 return OPERATOR_CANCELLED;
2165 void NLA_OT_fmodifier_paste(wmOperatorType *ot)
2168 ot->name = "Paste F-Modifiers";
2169 ot->idname = "NLA_OT_fmodifier_paste";
2170 ot->description = "Add copied F-Modifiers to the selected NLA-Strips";
2173 ot->exec = nla_fmodifier_paste_exec;
2174 ot->poll = nlaop_poll_tweakmode_off;
2177 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2180 /* *********************************************** */