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 /* why isn't this used? */
1174 static void UNUSED_FUNCTION(NLA_OT_bake)(wmOperatorType *ot)
1177 ot->name = "Bake Strips";
1178 ot->idname = "NLA_OT_bake";
1179 ot->description = "Bake all strips of selected AnimData blocks";
1182 ot->exec = nlaedit_bake_exec;
1183 ot->poll = nlaop_poll_tweakmode_off;
1186 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1189 /* *********************************************** */
1190 /* NLA Editing Operations (Modifying) */
1192 /* ******************** Toggle Muting Operator ************************** */
1193 /* Toggles whether strips are muted or not */
1195 static int nlaedit_toggle_mute_exec(bContext *C, wmOperator *UNUSED(op))
1199 ListBase anim_data = {NULL, NULL};
1203 /* get editor data */
1204 if (ANIM_animdata_get_context(C, &ac) == 0)
1205 return OPERATOR_CANCELLED;
1207 /* get a list of the editable tracks being shown in the NLA */
1208 filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
1209 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
1211 /* go over all selected strips */
1212 for (ale = anim_data.first; ale; ale = ale->next) {
1213 NlaTrack *nlt = (NlaTrack *)ale->data;
1216 /* for every selected strip, toggle muting */
1217 for (strip = nlt->strips.first; strip; strip = strip->next) {
1218 if (strip->flag & NLASTRIP_FLAG_SELECT) {
1219 /* just flip the mute flag for now */
1220 // TODO: have a pre-pass to check if mute all or unmute all?
1221 strip->flag ^= NLASTRIP_FLAG_MUTED;
1226 /* free temp data */
1227 BLI_freelistN(&anim_data);
1229 /* set notifier that things have changed */
1230 WM_event_add_notifier(C, NC_ANIMATION | ND_NLA | NA_EDITED, NULL);
1233 return OPERATOR_FINISHED;
1236 void NLA_OT_mute_toggle(wmOperatorType *ot)
1239 ot->name = "Toggle Muting";
1240 ot->idname = "NLA_OT_mute_toggle";
1241 ot->description = "Mute or un-mute selected strips";
1244 ot->exec = nlaedit_toggle_mute_exec;
1245 ot->poll = nlaop_poll_tweakmode_off;
1248 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1251 /* ******************** Swap Strips Operator ************************** */
1252 /* Tries to exchange strips within their owner tracks */
1254 static int nlaedit_swap_exec(bContext *C, wmOperator *op)
1258 ListBase anim_data = {NULL, NULL};
1262 /* get editor data */
1263 if (ANIM_animdata_get_context(C, &ac) == 0)
1264 return OPERATOR_CANCELLED;
1266 /* get a list of the editable tracks being shown in the NLA */
1267 filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
1268 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
1270 /* consider each track in turn */
1271 for (ale = anim_data.first; ale; ale = ale->next) {
1272 NlaTrack *nlt = (NlaTrack *)ale->data;
1274 NlaStrip *strip, *stripN = NULL;
1275 NlaStrip *sa = NULL, *sb = NULL;
1277 /* make temporary metastrips so that entire islands of selections can be moved around */
1278 BKE_nlastrips_make_metas(&nlt->strips, 1);
1280 /* special case: if there is only 1 island (i.e. temp meta BUT NOT unselected/normal/normal-meta strips) left after this,
1281 * and this island has two strips inside it, then we should be able to just swap these still...
1283 if ((nlt->strips.first == nlt->strips.last) && (nlt->strips.first != NULL)) {
1284 NlaStrip *mstrip = (NlaStrip *)nlt->strips.first;
1286 if ((mstrip->flag & NLASTRIP_FLAG_TEMP_META) && (BLI_countlist(&mstrip->strips) == 2)) {
1287 /* remove this temp meta, so that we can see the strips inside */
1288 BKE_nlastrips_clear_metas(&nlt->strips, 0, 1);
1292 /* get two selected strips only (these will be metas due to prev step) to operate on
1293 * - only allow swapping 2, as with more the context becomes unclear
1295 for (strip = nlt->strips.first; strip; strip = stripN) {
1296 stripN = strip->next;
1298 if (strip->flag & NLASTRIP_FLAG_SELECT) {
1299 /* first or second strip? */
1301 /* store as first */
1304 else if (sb == NULL) {
1305 /* store as second */
1309 /* too many selected */
1316 /* too many selected warning */
1317 BKE_reportf(op->reports, RPT_WARNING,
1318 "Too many clusters of strips selected in NLA Track (%s): needs exactly 2 to be selected",
1321 else if (sa == NULL) {
1322 /* no warning as this is just a common case, and it may get annoying when doing multiple tracks */
1324 else if (sb == NULL) {
1325 /* too few selected warning */
1326 BKE_reportf(op->reports, RPT_WARNING,
1327 "Too few clusters of strips selected in NLA Track (%s): needs exactly 2 to be selected",
1331 float nsa[2], nsb[2];
1333 /* remove these strips from the track, so that we can test if they can fit in the proposed places */
1334 BLI_remlink(&nlt->strips, sa);
1335 BLI_remlink(&nlt->strips, sb);
1337 /* calculate new extents for strips */
1340 nsa[1] = sb->start + (sa->end - sa->start);
1343 nsb[1] = sa->start + (sb->end - sb->start);
1345 /* check if the track has room for the strips to be swapped */
1346 if (BKE_nlastrips_has_space(&nlt->strips, nsa[0], nsa[1]) &&
1347 BKE_nlastrips_has_space(&nlt->strips, nsb[0], nsb[1]))
1349 /* set new extents for strips then */
1352 BKE_nlameta_flush_transforms(sa);
1356 BKE_nlameta_flush_transforms(sb);
1359 /* not enough room to swap, so show message */
1360 if ((sa->flag & NLASTRIP_FLAG_TEMP_META) || (sb->flag & NLASTRIP_FLAG_TEMP_META)) {
1361 BKE_report(op->reports, RPT_WARNING,
1362 "Cannot swap selected strips as they will not be able to fit in their new places");
1365 BKE_reportf(op->reports, RPT_WARNING,
1366 "Cannot swap '%s' and '%s' as one or both will not be able to fit in their new places",
1367 sa->name, sb->name);
1371 /* add strips back to track now */
1372 BKE_nlatrack_add_strip(nlt, sa);
1373 BKE_nlatrack_add_strip(nlt, sb);
1376 /* clear (temp) metastrips */
1377 BKE_nlastrips_clear_metas(&nlt->strips, 0, 1);
1380 /* free temp data */
1381 BLI_freelistN(&anim_data);
1383 /* refresh auto strip properties */
1384 ED_nla_postop_refresh(&ac);
1386 /* set notifier that things have changed */
1387 WM_event_add_notifier(C, NC_ANIMATION | ND_NLA | NA_EDITED, NULL);
1390 return OPERATOR_FINISHED;
1393 void NLA_OT_swap(wmOperatorType *ot)
1396 ot->name = "Swap Strips";
1397 ot->idname = "NLA_OT_swap";
1398 ot->description = "Swap order of selected strips within tracks";
1401 ot->exec = nlaedit_swap_exec;
1402 ot->poll = nlaop_poll_tweakmode_off;
1405 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1408 /* ******************** Move Strips Up Operator ************************** */
1409 /* Tries to move the selected strips into the track above if possible. */
1411 static int nlaedit_move_up_exec(bContext *C, wmOperator *UNUSED(op))
1415 ListBase anim_data = {NULL, NULL};
1419 /* get editor data */
1420 if (ANIM_animdata_get_context(C, &ac) == 0)
1421 return OPERATOR_CANCELLED;
1423 /* get a list of the editable tracks being shown in the NLA */
1424 filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
1425 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
1427 /* since we're potentially moving strips from lower tracks to higher tracks, we should
1428 * loop over the tracks in reverse order to avoid moving earlier strips up multiple tracks
1430 for (ale = anim_data.last; ale; ale = ale->prev) {
1431 NlaTrack *nlt = (NlaTrack *)ale->data;
1432 NlaTrack *nltn = nlt->next;
1433 NlaStrip *strip, *stripn;
1435 /* if this track has no tracks after it, skip for now... */
1439 /* for every selected strip, try to move */
1440 for (strip = nlt->strips.first; strip; strip = stripn) {
1441 stripn = strip->next;
1443 if (strip->flag & NLASTRIP_FLAG_SELECT) {
1444 /* check if the track above has room for this strip */
1445 if (BKE_nlatrack_has_space(nltn, strip->start, strip->end)) {
1446 /* remove from its current track, and add to the one above (it 'should' work, so no need to worry) */
1447 BLI_remlink(&nlt->strips, strip);
1448 BKE_nlatrack_add_strip(nltn, strip);
1454 /* free temp data */
1455 BLI_freelistN(&anim_data);
1457 /* refresh auto strip properties */
1458 ED_nla_postop_refresh(&ac);
1460 /* set notifier that things have changed */
1461 WM_event_add_notifier(C, NC_ANIMATION | ND_NLA | NA_EDITED, NULL);
1464 return OPERATOR_FINISHED;
1467 void NLA_OT_move_up(wmOperatorType *ot)
1470 ot->name = "Move Strips Up";
1471 ot->idname = "NLA_OT_move_up";
1472 ot->description = "Move selected strips up a track if there's room";
1475 ot->exec = nlaedit_move_up_exec;
1476 ot->poll = nlaop_poll_tweakmode_off;
1479 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1482 /* ******************** Move Strips Down Operator ************************** */
1483 /* Tries to move the selected strips into the track above if possible. */
1485 static int nlaedit_move_down_exec(bContext *C, wmOperator *UNUSED(op))
1489 ListBase anim_data = {NULL, NULL};
1493 /* get editor data */
1494 if (ANIM_animdata_get_context(C, &ac) == 0)
1495 return OPERATOR_CANCELLED;
1497 /* get a list of the editable tracks being shown in the NLA */
1498 filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
1499 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
1501 /* loop through the tracks in normal order, since we're pushing strips down,
1502 * strips won't get operated on twice
1504 for (ale = anim_data.first; ale; ale = ale->next) {
1505 NlaTrack *nlt = (NlaTrack *)ale->data;
1506 NlaTrack *nltp = nlt->prev;
1507 NlaStrip *strip, *stripn;
1509 /* if this track has no tracks before it, skip for now... */
1513 /* for every selected strip, try to move */
1514 for (strip = nlt->strips.first; strip; strip = stripn) {
1515 stripn = strip->next;
1517 if (strip->flag & NLASTRIP_FLAG_SELECT) {
1518 /* check if the track below has room for this strip */
1519 if (BKE_nlatrack_has_space(nltp, strip->start, strip->end)) {
1520 /* remove from its current track, and add to the one above (it 'should' work, so no need to worry) */
1521 BLI_remlink(&nlt->strips, strip);
1522 BKE_nlatrack_add_strip(nltp, strip);
1528 /* free temp data */
1529 BLI_freelistN(&anim_data);
1531 /* refresh auto strip properties */
1532 ED_nla_postop_refresh(&ac);
1534 /* set notifier that things have changed */
1535 WM_event_add_notifier(C, NC_ANIMATION | ND_NLA | NA_EDITED, NULL);
1538 return OPERATOR_FINISHED;
1541 void NLA_OT_move_down(wmOperatorType *ot)
1544 ot->name = "Move Strips Down";
1545 ot->idname = "NLA_OT_move_down";
1546 ot->description = "Move selected strips down a track if there's room";
1549 ot->exec = nlaedit_move_down_exec;
1550 ot->poll = nlaop_poll_tweakmode_off;
1553 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1556 /* ******************** Sync Action Length Operator ***************************** */
1557 /* Recalculate the extents of the action ranges used for the selected strips */
1559 static int nlaedit_sync_actlen_exec(bContext *C, wmOperator *op)
1563 ListBase anim_data = {NULL, NULL};
1566 short active_only = RNA_boolean_get(op->ptr, "active");
1568 /* get editor data */
1569 if (ANIM_animdata_get_context(C, &ac) == 0)
1570 return OPERATOR_CANCELLED;
1572 /* get a list of the editable tracks being shown in the NLA */
1573 filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
1574 if (active_only) filter |= ANIMFILTER_ACTIVE;
1575 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
1577 /* for each NLA-Track, apply scale of all selected strips */
1578 for (ale = anim_data.first; ale; ale = ale->next) {
1579 NlaTrack *nlt = (NlaTrack *)ale->data;
1582 for (strip = nlt->strips.first; strip; strip = strip->next) {
1583 /* strip selection/active status check */
1585 if ((strip->flag & NLASTRIP_FLAG_ACTIVE) == 0)
1589 if ((strip->flag & NLASTRIP_FLAG_SELECT) == 0)
1593 /* must be action-clip only (transitions don't have scale) */
1594 if (strip->type == NLASTRIP_TYPE_CLIP) {
1595 if (strip->act == NULL)
1598 /* recalculate the length of the action */
1599 calc_action_range(strip->act, &strip->actstart, &strip->actend, 0);
1601 /* adjust the strip extents in response to this */
1602 BKE_nlastrip_recalculate_bounds(strip);
1607 /* free temp data */
1608 BLI_freelistN(&anim_data);
1610 /* set notifier that things have changed */
1611 WM_event_add_notifier(C, NC_ANIMATION | ND_NLA | NA_EDITED, NULL);
1614 return OPERATOR_FINISHED;
1617 void NLA_OT_action_sync_length(wmOperatorType *ot)
1620 ot->name = "Sync Action Length";
1621 ot->idname = "NLA_OT_action_sync_length";
1622 ot->description = "Synchronize the length of the referenced Action with the length used in the strip";
1625 ot->exec = nlaedit_sync_actlen_exec;
1626 ot->poll = ED_operator_nla_active; // XXX: is this satisfactory... probably requires a check for active strip...
1629 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1632 ot->prop = RNA_def_boolean(ot->srna, "active", 1, "Active Strip Only", "Only sync the active length for the active strip");
1635 /* ******************** Apply Scale Operator ***************************** */
1636 /* Reset the scaling of the selected strips to 1.0f */
1638 /* apply scaling to keyframe */
1639 static short bezt_apply_nlamapping(KeyframeEditData *ked, BezTriple *bezt)
1641 /* NLA-strip which has this scaling is stored in ked->data */
1642 NlaStrip *strip = (NlaStrip *)ked->data;
1644 /* adjust all the times */
1645 bezt->vec[0][0] = nlastrip_get_frame(strip, bezt->vec[0][0], NLATIME_CONVERT_MAP);
1646 bezt->vec[1][0] = nlastrip_get_frame(strip, bezt->vec[1][0], NLATIME_CONVERT_MAP);
1647 bezt->vec[2][0] = nlastrip_get_frame(strip, bezt->vec[2][0], NLATIME_CONVERT_MAP);
1649 /* nothing to return or else we exit */
1653 static int nlaedit_apply_scale_exec(bContext *C, wmOperator *UNUSED(op))
1657 ListBase anim_data = {NULL, NULL};
1661 KeyframeEditData ked = {{NULL}};
1663 /* get editor data */
1664 if (ANIM_animdata_get_context(C, &ac) == 0)
1665 return OPERATOR_CANCELLED;
1667 /* get a list of the editable tracks being shown in the NLA */
1668 filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
1669 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
1671 /* init the editing data */
1673 /* for each NLA-Track, apply scale of all selected strips */
1674 for (ale = anim_data.first; ale; ale = ale->next) {
1675 NlaTrack *nlt = (NlaTrack *)ale->data;
1678 for (strip = nlt->strips.first; strip; strip = strip->next) {
1679 /* strip must be selected, and must be action-clip only (transitions don't have scale) */
1680 if ((strip->flag & NLASTRIP_FLAG_SELECT) && (strip->type == NLASTRIP_TYPE_CLIP)) {
1681 /* if the referenced action is used by other strips, make this strip use its own copy */
1682 if (strip->act == NULL)
1684 if (strip->act->id.us > 1) {
1685 /* make a copy of the Action to work on */
1686 bAction *act = BKE_action_copy(strip->act);
1688 /* set this as the new referenced action, decrementing the users of the old one */
1689 strip->act->id.us--;
1693 /* setup iterator, and iterate over all the keyframes in the action, applying this scaling */
1695 ANIM_animchanneldata_keyframes_loop(&ked, ac.ads, strip->act, ALE_ACT, NULL, bezt_apply_nlamapping, calchandles_fcurve);
1697 /* clear scale of strip now that it has been applied,
1698 * and recalculate the extents of the action now that it has been scaled
1699 * but leave everything else alone
1701 strip->scale = 1.0f;
1702 calc_action_range(strip->act, &strip->actstart, &strip->actend, 0);
1707 /* free temp data */
1708 BLI_freelistN(&anim_data);
1710 /* set notifier that things have changed */
1711 WM_event_add_notifier(C, NC_ANIMATION | ND_NLA | NA_EDITED, NULL);
1714 return OPERATOR_FINISHED;
1717 void NLA_OT_apply_scale(wmOperatorType *ot)
1720 ot->name = "Apply Scale";
1721 ot->idname = "NLA_OT_apply_scale";
1722 ot->description = "Apply scaling of selected strips to their referenced Actions";
1725 ot->exec = nlaedit_apply_scale_exec;
1726 ot->poll = nlaop_poll_tweakmode_off;
1729 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1732 /* ******************** Clear Scale Operator ***************************** */
1733 /* Reset the scaling of the selected strips to 1.0f */
1735 static int nlaedit_clear_scale_exec(bContext *C, wmOperator *UNUSED(op))
1739 ListBase anim_data = {NULL, NULL};
1743 /* get editor data */
1744 if (ANIM_animdata_get_context(C, &ac) == 0)
1745 return OPERATOR_CANCELLED;
1747 /* get a list of the editable tracks being shown in the NLA */
1748 filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
1749 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
1751 /* for each NLA-Track, reset scale of all selected strips */
1752 for (ale = anim_data.first; ale; ale = ale->next) {
1753 NlaTrack *nlt = (NlaTrack *)ale->data;
1756 for (strip = nlt->strips.first; strip; strip = strip->next) {
1757 /* strip must be selected, and must be action-clip only (transitions don't have scale) */
1758 if ((strip->flag & NLASTRIP_FLAG_SELECT) && (strip->type == NLASTRIP_TYPE_CLIP)) {
1759 PointerRNA strip_ptr;
1761 RNA_pointer_create(NULL, &RNA_NlaStrip, strip, &strip_ptr);
1762 RNA_float_set(&strip_ptr, "scale", 1.0f);
1767 /* free temp data */
1768 BLI_freelistN(&anim_data);
1770 /* refresh auto strip properties */
1771 ED_nla_postop_refresh(&ac);
1773 /* set notifier that things have changed */
1774 WM_event_add_notifier(C, NC_ANIMATION | ND_NLA | NA_EDITED, NULL);
1777 return OPERATOR_FINISHED;
1780 void NLA_OT_clear_scale(wmOperatorType *ot)
1783 ot->name = "Clear Scale";
1784 ot->idname = "NLA_OT_clear_scale";
1785 ot->description = "Reset scaling of selected strips";
1788 ot->exec = nlaedit_clear_scale_exec;
1789 ot->poll = nlaop_poll_tweakmode_off;
1792 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1795 /* ******************** Snap Strips Operator ************************** */
1796 /* Moves the start-point of the selected strips to the specified places */
1798 /* defines for snap keyframes tool */
1799 static EnumPropertyItem prop_nlaedit_snap_types[] = {
1800 {NLAEDIT_SNAP_CFRA, "CFRA", 0, "Current frame", ""},
1801 {NLAEDIT_SNAP_NEAREST_FRAME, "NEAREST_FRAME", 0, "Nearest Frame", ""}, // XXX as single entry?
1802 {NLAEDIT_SNAP_NEAREST_SECOND, "NEAREST_SECOND", 0, "Nearest Second", ""}, // XXX as single entry?
1803 {NLAEDIT_SNAP_NEAREST_MARKER, "NEAREST_MARKER", 0, "Nearest Marker", ""},
1804 {0, NULL, 0, NULL, NULL}
1807 static int nlaedit_snap_exec(bContext *C, wmOperator *op)
1811 ListBase anim_data = {NULL, NULL};
1816 int mode = RNA_enum_get(op->ptr, "type");
1819 /* get editor data */
1820 if (ANIM_animdata_get_context(C, &ac) == 0)
1821 return OPERATOR_CANCELLED;
1823 /* get a list of the editable tracks being shown in the NLA */
1824 filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
1825 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
1827 /* get some necessary vars */
1831 /* since we may add tracks, perform this in reverse order */
1832 for (ale = anim_data.last; ale; ale = ale->prev) {
1833 ListBase tmp_strips = {NULL, NULL};
1834 AnimData *adt = ale->adt;
1835 NlaTrack *nlt = (NlaTrack *)ale->data;
1836 NlaStrip *strip, *stripn;
1839 /* create meta-strips from the continuous chains of selected strips */
1840 BKE_nlastrips_make_metas(&nlt->strips, 1);
1842 /* apply the snapping to all the temp meta-strips, then put them in a separate list to be added
1843 * back to the original only if they still fit
1845 for (strip = nlt->strips.first; strip; strip = stripn) {
1846 stripn = strip->next;
1848 if (strip->flag & NLASTRIP_FLAG_TEMP_META) {
1851 /* get the existing end-points */
1852 start = strip->start;
1855 /* calculate new start position based on snapping mode */
1857 case NLAEDIT_SNAP_CFRA: /* to current frame */
1858 strip->start = (float)CFRA;
1860 case NLAEDIT_SNAP_NEAREST_FRAME: /* to nearest frame */
1861 strip->start = floorf(start + 0.5f);
1863 case NLAEDIT_SNAP_NEAREST_SECOND: /* to nearest second */
1864 strip->start = floorf(start / secf + 0.5f) * secf;
1866 case NLAEDIT_SNAP_NEAREST_MARKER: /* to nearest marker */
1867 strip->start = (float)ED_markers_find_nearest_marker_time(ac.markers, start);
1869 default: /* just in case... no snapping */
1870 strip->start = start;
1874 /* get new endpoint based on start-point (and old length) */
1875 strip->end = strip->start + (end - start);
1877 /* apply transforms to meta-strip to its children */
1878 BKE_nlameta_flush_transforms(strip);
1880 /* remove strip from track, and add to the temp buffer */
1881 BLI_remlink(&nlt->strips, strip);
1882 BLI_addtail(&tmp_strips, strip);
1886 /* try adding each meta-strip back to the track one at a time, to make sure they'll fit */
1887 for (strip = tmp_strips.first; strip; strip = stripn) {
1888 stripn = strip->next;
1890 /* remove from temp-strips list */
1891 BLI_remlink(&tmp_strips, strip);
1893 /* in case there's no space in the current track, try adding */
1894 if (BKE_nlatrack_add_strip(nlt, strip) == 0) {
1895 /* need to add a new track above the current one */
1896 track = add_nlatrack(adt, nlt);
1897 BKE_nlatrack_add_strip(track, strip);
1899 /* clear temp meta-strips on this new track, as we may not be able to get back to it */
1900 BKE_nlastrips_clear_metas(&track->strips, 0, 1);
1904 /* remove the meta-strips now that we're done */
1905 BKE_nlastrips_clear_metas(&nlt->strips, 0, 1);
1908 /* free temp data */
1909 BLI_freelistN(&anim_data);
1911 /* refresh auto strip properties */
1912 ED_nla_postop_refresh(&ac);
1914 /* set notifier that things have changed */
1915 WM_event_add_notifier(C, NC_ANIMATION | ND_NLA | NA_EDITED, NULL);
1918 return OPERATOR_FINISHED;
1921 void NLA_OT_snap(wmOperatorType *ot)
1924 ot->name = "Snap Strips";
1925 ot->idname = "NLA_OT_snap";
1926 ot->description = "Move start of strips to specified time";
1929 ot->invoke = WM_menu_invoke;
1930 ot->exec = nlaedit_snap_exec;
1931 ot->poll = nlaop_poll_tweakmode_off;
1934 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1937 ot->prop = RNA_def_enum(ot->srna, "type", prop_nlaedit_snap_types, 0, "Type", "");
1940 /* *********************************************** */
1943 /* ******************** Add F-Modifier Operator *********************** */
1945 /* present a special customised popup menu for this, with some filtering */
1946 static int nla_fmodifier_add_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *UNUSED(event))
1952 pup = uiPupMenuBegin(C, "Add F-Modifier", ICON_NONE);
1953 layout = uiPupMenuLayout(pup);
1955 /* start from 1 to skip the 'Invalid' modifier type */
1956 for (i = 1; i < FMODIFIER_NUM_TYPES; i++) {
1957 FModifierTypeInfo *fmi = get_fmodifier_typeinfo(i);
1959 /* check if modifier is valid for this context */
1962 if (i == FMODIFIER_TYPE_CYCLES) /* we already have repeat... */
1965 /* add entry to add this type of modifier */
1966 uiItemEnumO(layout, "NLA_OT_fmodifier_add", fmi->name, 0, "type", i);
1970 uiPupMenuEnd(C, pup);
1972 return OPERATOR_CANCELLED;
1975 static int nla_fmodifier_add_exec(bContext *C, wmOperator *op)
1979 ListBase anim_data = {NULL, NULL};
1984 int type = RNA_enum_get(op->ptr, "type");
1985 short onlyActive = RNA_boolean_get(op->ptr, "only_active");
1987 /* get editor data */
1988 if (ANIM_animdata_get_context(C, &ac) == 0)
1989 return OPERATOR_CANCELLED;
1991 /* get a list of the editable tracks being shown in the NLA */
1992 filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
1993 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
1995 /* for each NLA-Track, add the specified modifier to all selected strips */
1996 for (ale = anim_data.first; ale; ale = ale->next) {
1997 NlaTrack *nlt = (NlaTrack *)ale->data;
2000 for (strip = nlt->strips.first; strip; strip = strip->next) {
2001 /* can F-Modifier be added to the current strip? */
2003 /* if not active, cannot add since we're only adding to active strip */
2004 if ((strip->flag & NLASTRIP_FLAG_ACTIVE) == 0)
2008 /* strip must be selected, since we're not just doing active */
2009 if ((strip->flag & NLASTRIP_FLAG_SELECT) == 0)
2013 /* sound clips are not affected by FModifiers */
2014 if (strip->type == NLASTRIP_TYPE_SOUND)
2017 /* add F-Modifier of specified type to selected, and make it the active one */
2018 fcm = add_fmodifier(&strip->modifiers, type);
2021 set_active_fmodifier(&strip->modifiers, fcm);
2023 BKE_reportf(op->reports, RPT_ERROR,
2024 "Modifier couldn't be added to (%s : %s) (see console for details)",
2025 nlt->name, strip->name);
2030 /* free temp data */
2031 BLI_freelistN(&anim_data);
2033 /* set notifier that things have changed */
2034 WM_event_add_notifier(C, NC_ANIMATION | ND_NLA | NA_EDITED, NULL);
2037 return OPERATOR_FINISHED;
2040 void NLA_OT_fmodifier_add(wmOperatorType *ot)
2043 ot->name = "Add F-Modifier";
2044 ot->idname = "NLA_OT_fmodifier_add";
2045 ot->description = "Add a F-Modifier of the specified type to the selected NLA-Strips";
2048 ot->invoke = nla_fmodifier_add_invoke;
2049 ot->exec = nla_fmodifier_add_exec;
2050 ot->poll = nlaop_poll_tweakmode_off;
2053 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2056 ot->prop = RNA_def_enum(ot->srna, "type", fmodifier_type_items, 0, "Type", "");
2057 RNA_def_boolean(ot->srna, "only_active", 0, "Only Active", "Only add a F-Modifier of the specified type to the active strip");
2060 /* ******************** Copy F-Modifiers Operator *********************** */
2062 static int nla_fmodifier_copy_exec(bContext *C, wmOperator *op)
2065 ListBase anim_data = {NULL, NULL};
2069 /* get editor data */
2070 if (ANIM_animdata_get_context(C, &ac) == 0)
2071 return OPERATOR_CANCELLED;
2073 /* clear buffer first */
2074 free_fmodifiers_copybuf();
2076 /* get a list of the editable tracks being shown in the NLA */
2077 filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
2078 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
2080 /* for each NLA-Track, add the specified modifier to all selected strips */
2081 for (ale = anim_data.first; ale; ale = ale->next) {
2082 NlaTrack *nlt = (NlaTrack *)ale->data;
2085 for (strip = nlt->strips.first; strip; strip = strip->next) {
2086 /* only add F-Modifier if on active strip? */
2087 if ((strip->flag & NLASTRIP_FLAG_ACTIVE) == 0)
2090 // TODO: when 'active' vs 'all' boolean is added, change last param!
2091 ok += ANIM_fmodifiers_copy_to_buf(&strip->modifiers, 0);
2095 /* successful or not? */
2097 BKE_report(op->reports, RPT_ERROR, "No F-Modifiers available to be copied");
2098 return OPERATOR_CANCELLED;
2101 return OPERATOR_FINISHED;
2104 void NLA_OT_fmodifier_copy(wmOperatorType *ot)
2107 ot->name = "Copy F-Modifiers";
2108 ot->idname = "NLA_OT_fmodifier_copy";
2109 ot->description = "Copy the F-Modifier(s) of the active NLA-Strip";
2112 ot->exec = nla_fmodifier_copy_exec;
2113 ot->poll = nlaop_poll_tweakmode_off;
2116 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2119 //ot->prop = RNA_def_boolean(ot->srna, "all", 1, "All F-Modifiers", "Copy all the F-Modifiers, instead of just the active one");
2122 /* ******************** Paste F-Modifiers Operator *********************** */
2124 static int nla_fmodifier_paste_exec(bContext *C, wmOperator *op)
2127 ListBase anim_data = {NULL, NULL};
2131 /* get editor data */
2132 if (ANIM_animdata_get_context(C, &ac) == 0)
2133 return OPERATOR_CANCELLED;
2135 /* get a list of the editable tracks being shown in the NLA */
2136 filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_SEL | ANIMFILTER_FOREDIT);
2137 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
2139 /* for each NLA-Track, add the specified modifier to all selected strips */
2140 for (ale = anim_data.first; ale; ale = ale->next) {
2141 NlaTrack *nlt = (NlaTrack *)ale->data;
2144 for (strip = nlt->strips.first; strip; strip = strip->next) {
2145 // TODO: do we want to replace existing modifiers? add user pref for that!
2146 ok += ANIM_fmodifiers_paste_from_buf(&strip->modifiers, 0);
2151 BLI_freelistN(&anim_data);
2153 /* successful or not? */
2155 /* set notifier that things have changed */
2156 /* set notifier that things have changed */
2157 WM_event_add_notifier(C, NC_ANIMATION | ND_NLA | NA_EDITED, NULL);
2158 return OPERATOR_FINISHED;
2161 BKE_report(op->reports, RPT_ERROR, "No F-Modifiers to paste");
2162 return OPERATOR_CANCELLED;
2166 void NLA_OT_fmodifier_paste(wmOperatorType *ot)
2169 ot->name = "Paste F-Modifiers";
2170 ot->idname = "NLA_OT_fmodifier_paste";
2171 ot->description = "Add copied F-Modifiers to the selected NLA-Strips";
2174 ot->exec = nla_fmodifier_paste_exec;
2175 ot->poll = nlaop_poll_tweakmode_off;
2178 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2181 /* *********************************************** */