4 * ***** BEGIN GPL LICENSE BLOCK *****
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 * The Original Code is Copyright (C) 2009 Blender Foundation, Joshua Leung
21 * All rights reserved.
24 * Contributor(s): Joshua Leung (major recode)
26 * ***** END GPL LICENSE BLOCK *****
29 /** \file blender/editors/space_nla/nla_edit.c
38 #include "DNA_anim_types.h"
39 #include "DNA_object_types.h"
40 #include "DNA_scene_types.h"
42 #include "MEM_guardedalloc.h"
44 #include "BLI_blenlib.h"
47 #include "BLI_utildefines.h"
49 #include "BKE_action.h"
50 #include "BKE_fcurve.h"
52 #include "BKE_context.h"
54 #include "BKE_report.h"
55 #include "BKE_screen.h"
57 #include "ED_anim_api.h"
58 #include "ED_keyframes_edit.h"
59 #include "ED_markers.h"
60 #include "ED_screen.h"
61 #include "ED_transform.h"
63 #include "RNA_access.h"
64 #include "RNA_define.h"
65 #include "RNA_enum_types.h"
70 #include "UI_interface.h"
71 #include "UI_resources.h"
72 #include "UI_view2d.h"
74 #include "nla_intern.h" // own include
75 #include "nla_private.h" // FIXME... maybe this shouldn't be included?
77 /* *********************************************** */
78 /* Utilities exported to other places... */
80 /* Perform validation for blending/extend settings */
81 void ED_nla_postop_refresh (bAnimContext *ac)
83 ListBase anim_data = {NULL, NULL};
85 short filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_ANIMDATA | ANIMFILTER_FOREDIT);
87 /* get blocks to work on */
88 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
90 for (ale= anim_data.first; ale; ale= ale->next) {
91 /* performing auto-blending, extend-mode validation, etc. */
92 BKE_nla_validate_state(ale->data);
95 /* free temp memory */
96 BLI_freelistN(&anim_data);
99 /* *********************************************** */
100 /* 'Special' Editing */
102 /* ******************** Tweak-Mode Operators ***************************** */
103 /* 'Tweak mode' allows the action referenced by the active NLA-strip to be edited
104 * as if it were the normal Active-Action of its AnimData block.
107 static int nlaedit_enable_tweakmode_exec (bContext *C, wmOperator *op)
111 ListBase anim_data = {NULL, NULL};
116 /* get editor data */
117 if (ANIM_animdata_get_context(C, &ac) == 0)
118 return OPERATOR_CANCELLED;
120 /* get a list of the AnimData blocks being shown in the NLA */
121 filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_ANIMDATA);
122 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
124 /* if no blocks, popup error? */
125 if (anim_data.first == NULL) {
126 BKE_report(op->reports, RPT_ERROR, "No AnimData blocks to enter tweakmode for");
127 return OPERATOR_CANCELLED;
130 /* for each AnimData block with NLA-data, try setting it in tweak-mode */
131 for (ale= anim_data.first; ale; ale= ale->next) {
132 AnimData *adt= ale->data;
134 /* try entering tweakmode if valid */
135 ok += BKE_nla_tweakmode_enter(adt);
139 BLI_freelistN(&anim_data);
141 /* if we managed to enter tweakmode on at least one AnimData block,
142 * set the flag for this in the active scene and send notifiers
144 if (ac.scene && ok) {
145 /* set editing flag */
146 ac.scene->flag |= SCE_NLA_EDIT_ON;
148 /* set notifier that things have changed */
149 WM_event_add_notifier(C, NC_ANIMATION|ND_NLA_ACTCHANGE, NULL);
152 BKE_report(op->reports, RPT_ERROR, "No active strip(s) to enter tweakmode on.");
153 return OPERATOR_CANCELLED;
157 return OPERATOR_FINISHED;
160 void NLA_OT_tweakmode_enter (wmOperatorType *ot)
163 ot->name= "Enter Tweak Mode";
164 ot->idname= "NLA_OT_tweakmode_enter";
165 ot->description= "Enter tweaking mode for the action referenced by the active strip";
168 ot->exec= nlaedit_enable_tweakmode_exec;
169 ot->poll= nlaop_poll_tweakmode_off;
172 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
177 static int nlaedit_disable_tweakmode_exec (bContext *C, wmOperator *op)
181 ListBase anim_data = {NULL, NULL};
185 /* get editor data */
186 if (ANIM_animdata_get_context(C, &ac) == 0)
187 return OPERATOR_CANCELLED;
189 /* get a list of the AnimData blocks being shown in the NLA */
190 filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_ANIMDATA);
191 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
193 /* if no blocks, popup error? */
194 if (anim_data.first == NULL) {
195 BKE_report(op->reports, RPT_ERROR, "No AnimData blocks to enter tweakmode for");
196 return OPERATOR_CANCELLED;
199 /* for each AnimData block with NLA-data, try exitting tweak-mode */
200 for (ale= anim_data.first; ale; ale= ale->next) {
201 AnimData *adt= ale->data;
203 /* try entering tweakmode if valid */
204 BKE_nla_tweakmode_exit(adt);
208 BLI_freelistN(&anim_data);
210 /* if we managed to enter tweakmode on at least one AnimData block,
211 * set the flag for this in the active scene and send notifiers
214 /* clear editing flag */
215 ac.scene->flag &= ~SCE_NLA_EDIT_ON;
217 /* set notifier that things have changed */
218 WM_event_add_notifier(C, NC_ANIMATION|ND_NLA_ACTCHANGE, NULL);
222 return OPERATOR_FINISHED;
225 void NLA_OT_tweakmode_exit (wmOperatorType *ot)
228 ot->name= "Exit Tweak Mode";
229 ot->idname= "NLA_OT_tweakmode_exit";
230 ot->description= "Exit tweaking mode for the action referenced by the active strip";
233 ot->exec= nlaedit_disable_tweakmode_exec;
234 ot->poll= nlaop_poll_tweakmode_on;
237 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
240 /* *********************************************** */
241 /* NLA Strips Range Stuff */
243 /* *************************** Calculate Range ************************** */
245 /* Get the min/max strip extents */
246 static void get_nlastrip_extents (bAnimContext *ac, float *min, float *max, const short onlySel)
248 ListBase anim_data = {NULL, NULL};
252 /* get data to filter */
253 filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_NODUPLIS);
254 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
256 /* set large values to try to override */
260 /* check if any channels to set range with */
261 if (anim_data.first) {
262 /* go through channels, finding max extents */
263 for (ale= anim_data.first; ale; ale= ale->next) {
264 NlaTrack *nlt = (NlaTrack *)ale->data;
267 for (strip = nlt->strips.first; strip; strip = strip->next) {
268 /* only consider selected strips? */
269 if ((onlySel == 0) || (strip->flag & NLASTRIP_FLAG_SELECT)) {
270 /* extend range if appropriate */
271 *min = MIN2(*min, strip->start);
272 *max = MAX2(*max, strip->end);
278 BLI_freelistN(&anim_data);
281 /* set default range */
283 *min= (float)ac->scene->r.sfra;
284 *max= (float)ac->scene->r.efra;
293 /* ****************** View-All Operator ****************** */
295 static int nlaedit_viewall(bContext *C, const short onlySel)
301 /* get editor data */
302 if (ANIM_animdata_get_context(C, &ac) == 0)
303 return OPERATOR_CANCELLED;
306 /* set the horizontal range, with an extra offset so that the extreme keys will be in view */
307 get_nlastrip_extents(&ac, &v2d->cur.xmin, &v2d->cur.xmax, onlySel);
309 extra= 0.1f * (v2d->cur.xmax - v2d->cur.xmin);
310 v2d->cur.xmin -= extra;
311 v2d->cur.xmax += extra;
313 /* set vertical range */
315 v2d->cur.ymin= (float)-(v2d->mask.ymax - v2d->mask.ymin);
317 /* do View2D syncing */
318 UI_view2d_sync(CTX_wm_screen(C), CTX_wm_area(C), v2d, V2D_LOCK_COPY);
320 /* just redraw this view */
321 ED_area_tag_redraw(CTX_wm_area(C));
323 return OPERATOR_FINISHED;
328 static int nlaedit_viewall_exec(bContext *C, wmOperator *UNUSED(op))
331 return nlaedit_viewall(C, FALSE);
334 static int nlaedit_viewsel_exec(bContext *C, wmOperator *UNUSED(op))
337 return nlaedit_viewall(C, TRUE);
340 void NLA_OT_view_all (wmOperatorType *ot)
343 ot->name= "View All";
344 ot->idname= "NLA_OT_view_all";
345 ot->description= "Reset viewable area to show full strips range";
348 ot->exec= nlaedit_viewall_exec;
349 ot->poll= ED_operator_nla_active;
352 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
355 void NLA_OT_view_selected (wmOperatorType *ot)
358 ot->name= "View Selected";
359 ot->idname= "NLA_OT_view_selected";
360 ot->description= "Reset viewable area to show selected strips range";
363 ot->exec= nlaedit_viewsel_exec;
364 ot->poll= ED_operator_nla_active;
367 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
370 /* *********************************************** */
371 /* NLA Editing Operations (Constructive/Destructive) */
373 /* ******************** Add Action-Clip Operator ***************************** */
374 /* Add a new Action-Clip strip to the active track (or the active block if no space in the track) */
377 /* add the specified action as new strip */
378 static int nlaedit_add_actionclip_exec (bContext *C, wmOperator *op)
383 ListBase anim_data = {NULL, NULL};
392 /* get editor data */
393 if (ANIM_animdata_get_context(C, &ac) == 0)
394 return OPERATOR_CANCELLED;
399 /* get action to use */
400 act= BLI_findlink(&CTX_data_main(C)->action, RNA_enum_get(op->ptr, "action"));
403 BKE_report(op->reports, RPT_ERROR, "No valid Action to add.");
404 //printf("Add strip - actname = '%s' \n", actname);
405 return OPERATOR_CANCELLED;
407 else if (act->idroot == 0) {
408 /* hopefully in this case (i.e. library of userless actions), the user knows what they're doing... */
409 BKE_reportf(op->reports, RPT_WARNING,
410 "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",
414 /* get a list of the editable tracks being shown in the NLA
415 * - this is limited to active ones for now, but could be expanded to
417 filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_ACTIVE | ANIMFILTER_FOREDIT);
418 items= ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
421 BKE_report(op->reports, RPT_ERROR, "No active track(s) to add strip to.");
422 return OPERATOR_CANCELLED;
425 /* for every active track, try to add strip to free space in track or to the top of the stack if no space */
426 for (ale= anim_data.first; ale; ale= ale->next) {
427 NlaTrack *nlt= (NlaTrack *)ale->data;
428 AnimData *adt= ale->adt;
429 NlaStrip *strip= NULL;
431 /* sanity check: only apply actions of the right type for this ID
432 * NOTE: in the case that this hasn't been set, we've already warned the user about this already
434 if ((act->idroot) && (act->idroot != GS(ale->id->name))) {
435 BKE_reportf(op->reports, RPT_ERROR,
436 "Couldn't add action '%s' as it cannot be used relative to ID-blocks of type '%s'",
437 act->id.name+2, ale->id->name);
441 /* create a new strip, and offset it to start on the current frame */
442 strip= add_nlastrip(act);
444 strip->end += (cfra - strip->start);
447 /* firstly try adding strip to our current track, but if that fails, add to a new track */
448 if (BKE_nlatrack_add_strip(nlt, strip) == 0) {
449 /* trying to add to the current failed (no space),
450 * so add a new track to the stack, and add to that...
452 nlt= add_nlatrack(adt, NULL);
453 BKE_nlatrack_add_strip(nlt, strip);
457 BKE_nlastrip_validate_name(adt, strip);
461 BLI_freelistN(&anim_data);
463 /* refresh auto strip properties */
464 ED_nla_postop_refresh(&ac);
466 /* set notifier that things have changed */
467 WM_event_add_notifier(C, NC_ANIMATION|ND_NLA|NA_EDITED, NULL);
470 return OPERATOR_FINISHED;
473 void NLA_OT_actionclip_add (wmOperatorType *ot)
478 ot->name= "Add Action Strip";
479 ot->idname= "NLA_OT_actionclip_add";
480 ot->description= "Add an Action-Clip strip (i.e. an NLA Strip referencing an Action) to the active track";
483 ot->invoke= WM_enum_search_invoke;
484 ot->exec= nlaedit_add_actionclip_exec;
485 ot->poll= nlaop_poll_tweakmode_off;
488 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
491 // TODO: this would be nicer as an ID-pointer...
492 prop= RNA_def_enum(ot->srna, "action", DummyRNA_NULL_items, 0, "Action", "");
493 RNA_def_enum_funcs(prop, RNA_action_itemf);
497 /* ******************** Add Transition Operator ***************************** */
498 /* Add a new transition strip between selected strips */
500 static int nlaedit_add_transition_exec (bContext *C, wmOperator *op)
504 ListBase anim_data = {NULL, NULL};
510 /* get editor data */
511 if (ANIM_animdata_get_context(C, &ac) == 0)
512 return OPERATOR_CANCELLED;
514 /* get a list of the editable tracks being shown in the NLA */
515 filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
516 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
518 /* for each track, find pairs of strips to add transitions to */
519 for (ale= anim_data.first; ale; ale= ale->next) {
520 NlaTrack *nlt= (NlaTrack *)ale->data;
521 AnimData *adt= ale->adt;
524 /* get initial pair of strips */
525 if ELEM(nlt->strips.first, NULL, nlt->strips.last)
527 s1= nlt->strips.first;
530 /* loop over strips */
531 for (; s1 && s2; s1=s2, s2=s2->next) {
534 /* check if both are selected */
535 if ELEM(0, (s1->flag & NLASTRIP_FLAG_SELECT), (s2->flag & NLASTRIP_FLAG_SELECT))
537 /* check if there's space between the two */
538 if (IS_EQ(s1->end, s2->start))
540 /* make sure neither one is a transition
541 * - although this is impossible to create with the standard tools,
542 * the user may have altered the settings
544 if (ELEM(NLASTRIP_TYPE_TRANSITION, s1->type, s2->type))
546 /* also make sure neither one is a soundclip */
547 if (ELEM(NLASTRIP_TYPE_SOUND, s1->type, s2->type))
550 /* allocate new strip */
551 strip= MEM_callocN(sizeof(NlaStrip), "NlaStrip");
552 BLI_insertlinkafter(&nlt->strips, s1, strip);
555 strip->type= NLASTRIP_TYPE_TRANSITION;
558 * - selected flag to highlight this to the user
559 * - auto-blends to ensure that blend in/out values are automatically
560 * determined by overlaps of strips
562 strip->flag = NLASTRIP_FLAG_SELECT|NLASTRIP_FLAG_AUTO_BLENDS;
564 /* range is simply defined as the endpoints of the adjacent strips */
565 strip->start = s1->end;
566 strip->end = s2->start;
568 /* scale and repeat aren't of any use, but shouldn't ever be 0 */
570 strip->repeat = 1.0f;
573 BKE_nlastrip_validate_name(adt, strip);
575 /* make note of this */
581 BLI_freelistN(&anim_data);
583 /* was anything added? */
585 /* refresh auto strip properties */
586 ED_nla_postop_refresh(&ac);
588 /* set notifier that things have changed */
589 WM_event_add_notifier(C, NC_ANIMATION|ND_NLA|NA_EDITED, NULL);
592 return OPERATOR_FINISHED;
595 BKE_report(op->reports, RPT_ERROR, "Needs at least a pair of adjacent selected strips with a gap between them.");
596 return OPERATOR_CANCELLED;
600 void NLA_OT_transition_add (wmOperatorType *ot)
603 ot->name= "Add Transition";
604 ot->idname= "NLA_OT_transition_add";
605 ot->description= "Add a transition strip between two adjacent selected strips";
608 ot->exec= nlaedit_add_transition_exec;
609 ot->poll= nlaop_poll_tweakmode_off;
612 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
615 /* ******************** Add Sound Clip Operator ***************************** */
616 /* Add a new sound clip */
618 static int nlaedit_add_sound_exec (bContext *C, wmOperator *op)
622 ListBase anim_data = {NULL, NULL};
629 /* get editor data */
630 if (ANIM_animdata_get_context(C, &ac) == 0)
631 return OPERATOR_CANCELLED;
636 /* get a list of the editable tracks being shown in the NLA */
637 filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_SEL | ANIMFILTER_FOREDIT);
638 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
640 /* for each track, add sound clips if it belongs to a speaker */
641 // TODO: what happens if there aren't any tracks... well that's a more general problem for later
642 for (ale= anim_data.first; ale; ale= ale->next) {
643 Object *ob = (Object *)ale->id; /* may not be object until we actually check! */
645 AnimData *adt = ale->adt;
646 NlaTrack *nlt= (NlaTrack *)ale->data;
649 /* does this belong to speaker - assumed to live on Object level only */
650 if ((GS(ale->id->name) != ID_OB) || (ob->type != OB_SPEAKER))
653 /* create a new strip, and offset it to start on the current frame */
654 strip= add_nla_soundstrip(ac.scene, ob->data);
656 strip->start += cfra;
659 /* firstly try adding strip to our current track, but if that fails, add to a new track */
660 if (BKE_nlatrack_add_strip(nlt, strip) == 0) {
661 /* trying to add to the current failed (no space),
662 * so add a new track to the stack, and add to that...
664 nlt= add_nlatrack(adt, NULL);
665 BKE_nlatrack_add_strip(nlt, strip);
669 BKE_nlastrip_validate_name(adt, strip);
673 BLI_freelistN(&anim_data);
675 /* refresh auto strip properties */
676 ED_nla_postop_refresh(&ac);
678 /* set notifier that things have changed */
679 WM_event_add_notifier(C, NC_ANIMATION|ND_NLA|NA_EDITED, NULL);
682 return OPERATOR_FINISHED;
685 void NLA_OT_soundclip_add (wmOperatorType *ot)
688 ot->name= "Add Sound Clip";
689 ot->idname= "NLA_OT_soundclip_add";
690 ot->description= "Add a strip for controlling when speaker plays its sound clip";
693 ot->exec= nlaedit_add_sound_exec;
694 ot->poll= nlaop_poll_tweakmode_off;
697 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
700 /* ******************** Add Meta-Strip Operator ***************************** */
701 /* Add new meta-strips incorporating the selected strips */
703 /* add the specified action as new strip */
704 static int nlaedit_add_meta_exec (bContext *C, wmOperator *UNUSED(op))
708 ListBase anim_data = {NULL, NULL};
712 /* get editor data */
713 if (ANIM_animdata_get_context(C, &ac) == 0)
714 return OPERATOR_CANCELLED;
716 /* get a list of the editable tracks being shown in the NLA */
717 filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
718 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
720 /* for each track, find pairs of strips to add transitions to */
721 for (ale= anim_data.first; ale; ale= ale->next) {
722 NlaTrack *nlt= (NlaTrack *)ale->data;
723 AnimData *adt= ale->adt;
726 /* create meta-strips from the continuous chains of selected strips */
727 BKE_nlastrips_make_metas(&nlt->strips, 0);
730 for (strip= nlt->strips.first; strip; strip= strip->next) {
731 /* auto-name this strip if selected (that means it is a meta) */
732 if (strip->flag & NLASTRIP_FLAG_SELECT)
733 BKE_nlastrip_validate_name(adt, strip);
738 BLI_freelistN(&anim_data);
740 /* set notifier that things have changed */
741 WM_event_add_notifier(C, NC_ANIMATION|ND_NLA|NA_EDITED, NULL);
744 return OPERATOR_FINISHED;
747 void NLA_OT_meta_add (wmOperatorType *ot)
750 ot->name= "Add Meta-Strips";
751 ot->idname= "NLA_OT_meta_add";
752 ot->description= "Add new meta-strips incorporating the selected strips";
755 ot->exec= nlaedit_add_meta_exec;
756 ot->poll= nlaop_poll_tweakmode_off;
759 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
762 /* ******************** Remove Meta-Strip Operator ***************************** */
763 /* Separate out the strips held by the selected meta-strips */
765 static int nlaedit_remove_meta_exec (bContext *C, wmOperator *UNUSED(op))
769 ListBase anim_data = {NULL, NULL};
773 /* get editor data */
774 if (ANIM_animdata_get_context(C, &ac) == 0)
775 return OPERATOR_CANCELLED;
777 /* get a list of the editable tracks being shown in the NLA */
778 filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
779 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
781 /* for each track, find pairs of strips to add transitions to */
782 for (ale= anim_data.first; ale; ale= ale->next) {
783 NlaTrack *nlt= (NlaTrack *)ale->data;
785 /* clear all selected meta-strips, regardless of whether they are temporary or not */
786 BKE_nlastrips_clear_metas(&nlt->strips, 1, 0);
790 BLI_freelistN(&anim_data);
792 /* set notifier that things have changed */
793 WM_event_add_notifier(C, NC_ANIMATION|ND_NLA|NA_EDITED, NULL);
796 return OPERATOR_FINISHED;
799 void NLA_OT_meta_remove (wmOperatorType *ot)
802 ot->name= "Remove Meta-Strips";
803 ot->idname= "NLA_OT_meta_remove";
804 ot->description= "Separate out the strips held by the selected meta-strips";
807 ot->exec= nlaedit_remove_meta_exec;
808 ot->poll= nlaop_poll_tweakmode_off;
811 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
814 /* ******************** Duplicate Strips Operator ************************** */
815 /* Duplicates the selected NLA-Strips, putting them on new tracks above the one
816 * the originals were housed in.
819 static int nlaedit_duplicate_exec (bContext *C, wmOperator *UNUSED(op))
823 ListBase anim_data = {NULL, NULL};
829 /* get editor data */
830 if (ANIM_animdata_get_context(C, &ac) == 0)
831 return OPERATOR_CANCELLED;
833 /* get a list of editable tracks being shown in the NLA */
834 filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
835 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
837 /* duplicate strips in tracks starting from the last one so that we're
838 * less likely to duplicate strips we just duplicated...
840 for (ale= anim_data.last; ale; ale= ale->prev) {
841 NlaTrack *nlt= (NlaTrack *)ale->data;
842 AnimData *adt= ale->adt;
843 NlaStrip *strip, *nstrip, *next;
846 for (strip= nlt->strips.first; strip; strip= next) {
849 /* if selected, split the strip at its midpoint */
850 if (strip->flag & NLASTRIP_FLAG_SELECT) {
851 /* make a copy (assume that this is possible) */
852 nstrip= copy_nlastrip(strip);
854 /* in case there's no space in the track above, or we haven't got a reference to it yet, try adding */
855 if (BKE_nlatrack_add_strip(nlt->next, nstrip) == 0) {
856 /* need to add a new track above the one above the current one
857 * - if the current one is the last one, nlt->next will be NULL, which defaults to adding
858 * at the top of the stack anyway...
860 track= add_nlatrack(adt, nlt->next);
861 BKE_nlatrack_add_strip(track, nstrip);
864 /* deselect the original and the active flag */
865 strip->flag &= ~(NLASTRIP_FLAG_SELECT|NLASTRIP_FLAG_ACTIVE);
867 /* auto-name newly created strip */
868 BKE_nlastrip_validate_name(adt, nstrip);
876 BLI_freelistN(&anim_data);
879 /* refresh auto strip properties */
880 ED_nla_postop_refresh(&ac);
882 /* set notifier that things have changed */
883 WM_event_add_notifier(C, NC_ANIMATION|ND_NLA|NA_EDITED, NULL);
886 return OPERATOR_FINISHED;
889 return OPERATOR_CANCELLED;
892 static int nlaedit_duplicate_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
894 nlaedit_duplicate_exec(C, op);
896 RNA_enum_set(op->ptr, "mode", TFM_TRANSLATION);
897 WM_operator_name_call(C, "TRANSFORM_OT_transform", WM_OP_INVOKE_REGION_WIN, op->ptr);
899 return OPERATOR_FINISHED;
902 void NLA_OT_duplicate (wmOperatorType *ot)
905 ot->name= "Duplicate Strips";
906 ot->idname= "NLA_OT_duplicate";
907 ot->description= "Duplicate selected NLA-Strips, adding the new strips in new tracks above the originals";
910 ot->invoke= nlaedit_duplicate_invoke;
911 ot->exec= nlaedit_duplicate_exec;
912 ot->poll= nlaop_poll_tweakmode_off;
915 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
917 /* to give to transform */
918 RNA_def_enum(ot->srna, "mode", transform_mode_types, TFM_TRANSLATION, "Mode", "");
921 /* ******************** Delete Strips Operator ***************************** */
922 /* Deletes the selected NLA-Strips */
924 static int nlaedit_delete_exec (bContext *C, wmOperator *UNUSED(op))
928 ListBase anim_data = {NULL, NULL};
932 /* get editor data */
933 if (ANIM_animdata_get_context(C, &ac) == 0)
934 return OPERATOR_CANCELLED;
936 /* get a list of the editable tracks being shown in the NLA */
937 filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
938 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
940 /* for each NLA-Track, delete all selected strips */
941 for (ale= anim_data.first; ale; ale= ale->next) {
942 NlaTrack *nlt= (NlaTrack *)ale->data;
943 NlaStrip *strip, *nstrip;
945 for (strip= nlt->strips.first; strip; strip= nstrip) {
948 /* if selected, delete */
949 if (strip->flag & NLASTRIP_FLAG_SELECT) {
950 /* if a strip either side of this was a transition, delete those too */
951 if ((strip->prev) && (strip->prev->type == NLASTRIP_TYPE_TRANSITION))
952 free_nlastrip(&nlt->strips, strip->prev);
953 if ((nstrip) && (nstrip->type == NLASTRIP_TYPE_TRANSITION)) {
954 nstrip= nstrip->next;
955 free_nlastrip(&nlt->strips, strip->next);
958 /* finally, delete this strip */
959 free_nlastrip(&nlt->strips, strip);
965 BLI_freelistN(&anim_data);
967 /* refresh auto strip properties */
968 ED_nla_postop_refresh(&ac);
970 /* set notifier that things have changed */
971 WM_event_add_notifier(C, NC_ANIMATION|ND_NLA|NA_EDITED, NULL);
974 return OPERATOR_FINISHED;
977 void NLA_OT_delete (wmOperatorType *ot)
980 ot->name= "Delete Strips";
981 ot->idname= "NLA_OT_delete";
982 ot->description= "Delete selected strips";
985 ot->exec= nlaedit_delete_exec;
986 ot->poll= nlaop_poll_tweakmode_off;
989 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
992 /* ******************** Split Strips Operator ***************************** */
993 /* Splits the selected NLA-Strips into two strips at the midpoint of the strip */
996 // - variable-length splits?
998 /* split a given Action-Clip strip */
999 static void nlaedit_split_strip_actclip (AnimData *adt, NlaTrack *nlt, NlaStrip *strip, float cfra)
1002 float splitframe, splitaframe;
1004 /* calculate the frames to do the splitting at
1005 * - use current frame if within extents of strip
1007 if ((cfra > strip->start) && (cfra < strip->end)) {
1008 /* use the current frame */
1010 splitaframe= nlastrip_get_frame(strip, cfra, NLATIME_CONVERT_UNMAP);
1013 /* split in the middle */
1017 len= strip->end - strip->start;
1018 if (IS_EQ(len, 0.0f))
1021 splitframe= strip->start + (len / 2.0f);
1024 len= strip->actend - strip->actstart;
1025 if (IS_EQ(len, 0.0f))
1026 splitaframe= strip->actend;
1028 splitaframe= strip->actstart + (len / 2.0f);
1031 /* make a copy (assume that this is possible) and append
1032 * it immediately after the current strip
1034 nstrip= copy_nlastrip(strip);
1035 BLI_insertlinkafter(&nlt->strips, strip, nstrip);
1037 /* set the endpoint of the first strip and the start of the new strip
1038 * to the splitframe values calculated above
1040 strip->end= splitframe;
1041 nstrip->start= splitframe;
1043 if ((splitaframe > strip->actstart) && (splitaframe < strip->actend)) {
1044 /* only do this if we're splitting down the middle... */
1045 strip->actend= splitaframe;
1046 nstrip->actstart= splitaframe;
1049 /* clear the active flag from the copy */
1050 nstrip->flag &= ~NLASTRIP_FLAG_ACTIVE;
1052 /* auto-name the new strip */
1053 BKE_nlastrip_validate_name(adt, nstrip);
1056 /* split a given Meta strip */
1057 static void nlaedit_split_strip_meta (NlaTrack *nlt, NlaStrip *strip)
1059 /* simply ungroup it for now... */
1060 BKE_nlastrips_clear_metastrip(&nlt->strips, strip);
1065 static int nlaedit_split_exec (bContext *C, wmOperator *UNUSED(op))
1069 ListBase anim_data = {NULL, NULL};
1073 /* get editor data */
1074 if (ANIM_animdata_get_context(C, &ac) == 0)
1075 return OPERATOR_CANCELLED;
1077 /* get a list of editable tracks being shown in the NLA */
1078 filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
1079 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
1081 /* for each NLA-Track, split all selected strips into two strips */
1082 for (ale= anim_data.first; ale; ale= ale->next) {
1083 NlaTrack *nlt= (NlaTrack *)ale->data;
1084 AnimData *adt= ale->adt;
1085 NlaStrip *strip, *next;
1087 for (strip= nlt->strips.first; strip; strip= next) {
1090 /* if selected, split the strip at its midpoint */
1091 if (strip->flag & NLASTRIP_FLAG_SELECT) {
1092 /* splitting method depends on the type of strip */
1093 switch (strip->type) {
1094 case NLASTRIP_TYPE_CLIP: /* action-clip */
1095 nlaedit_split_strip_actclip(adt, nlt, strip, (float)ac.scene->r.cfra);
1098 case NLASTRIP_TYPE_META: /* meta-strips need special handling */
1099 nlaedit_split_strip_meta(nlt, strip);
1102 default: /* for things like Transitions, do not split! */
1109 /* free temp data */
1110 BLI_freelistN(&anim_data);
1112 /* refresh auto strip properties */
1113 ED_nla_postop_refresh(&ac);
1115 /* set notifier that things have changed */
1116 WM_event_add_notifier(C, NC_ANIMATION|ND_NLA|NA_EDITED, NULL);
1119 return OPERATOR_FINISHED;
1122 void NLA_OT_split (wmOperatorType *ot)
1125 ot->name= "Split Strips";
1126 ot->idname= "NLA_OT_split";
1127 ot->description= "Split selected strips at their midpoints";
1130 ot->exec= nlaedit_split_exec;
1131 ot->poll= nlaop_poll_tweakmode_off;
1134 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1137 /* ******************** Bake Strips Operator ***************************** */
1138 /* Bakes the NLA Strips for the active AnimData blocks */
1140 static int nlaedit_bake_exec (bContext *C, wmOperator *UNUSED(op))
1144 ListBase anim_data = {NULL, NULL};
1149 /* get editor data */
1150 if (ANIM_animdata_get_context(C, &ac) == 0)
1151 return OPERATOR_CANCELLED;
1153 /* get a list of the editable tracks being shown in the NLA */
1154 filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_ANIMDATA | ANIMFILTER_FOREDIT);
1155 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
1157 /* for each AnimData block, bake strips to animdata... */
1158 for (ale= anim_data.first; ale; ale= ale->next) {
1159 //BKE_nla_bake(ac.scene, ale->id, ale->data, flag);
1162 /* free temp data */
1163 BLI_freelistN(&anim_data);
1165 /* refresh auto strip properties */
1166 ED_nla_postop_refresh(&ac);
1168 /* set notifier that things have changed */
1169 WM_event_add_notifier(C, NC_ANIMATION|ND_NLA|NA_EDITED, NULL);
1172 return OPERATOR_FINISHED;
1175 static void NLA_OT_bake (wmOperatorType *ot)
1178 ot->name= "Bake Strips";
1179 ot->idname= "NLA_OT_bake";
1180 ot->description= "Bake all strips of selected AnimData blocks";
1183 ot->exec= nlaedit_bake_exec;
1184 ot->poll= nlaop_poll_tweakmode_off;
1187 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1190 /* *********************************************** */
1191 /* NLA Editing Operations (Modifying) */
1193 /* ******************** Toggle Muting Operator ************************** */
1194 /* Toggles whether strips are muted or not */
1196 static int nlaedit_toggle_mute_exec (bContext *C, wmOperator *UNUSED(op))
1200 ListBase anim_data = {NULL, NULL};
1204 /* get editor data */
1205 if (ANIM_animdata_get_context(C, &ac) == 0)
1206 return OPERATOR_CANCELLED;
1208 /* get a list of the editable tracks being shown in the NLA */
1209 filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
1210 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
1212 /* go over all selected strips */
1213 for (ale= anim_data.first; ale; ale= ale->next) {
1214 NlaTrack *nlt= (NlaTrack *)ale->data;
1217 /* for every selected strip, toggle muting */
1218 for (strip= nlt->strips.first; strip; strip= strip->next) {
1219 if (strip->flag & NLASTRIP_FLAG_SELECT) {
1220 /* just flip the mute flag for now */
1221 // TODO: have a pre-pass to check if mute all or unmute all?
1222 strip->flag ^= NLASTRIP_FLAG_MUTED;
1227 /* free temp data */
1228 BLI_freelistN(&anim_data);
1230 /* set notifier that things have changed */
1231 WM_event_add_notifier(C, NC_ANIMATION|ND_NLA|NA_EDITED, NULL);
1234 return OPERATOR_FINISHED;
1237 void NLA_OT_mute_toggle (wmOperatorType *ot)
1240 ot->name= "Toggle Muting";
1241 ot->idname= "NLA_OT_mute_toggle";
1242 ot->description= "Mute or un-mute selected strips";
1245 ot->exec= nlaedit_toggle_mute_exec;
1246 ot->poll= nlaop_poll_tweakmode_off;
1249 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1252 /* ******************** Swap Strips Operator ************************** */
1253 /* Tries to exchange strips within their owner tracks */
1255 static int nlaedit_swap_exec (bContext *C, wmOperator *op)
1259 ListBase anim_data = {NULL, NULL};
1263 /* get editor data */
1264 if (ANIM_animdata_get_context(C, &ac) == 0)
1265 return OPERATOR_CANCELLED;
1267 /* get a list of the editable tracks being shown in the NLA */
1268 filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
1269 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
1271 /* consider each track in turn */
1272 for (ale= anim_data.first; ale; ale= ale->next) {
1273 NlaTrack *nlt= (NlaTrack *)ale->data;
1275 NlaStrip *strip, *stripN=NULL;
1276 NlaStrip *sa=NULL, *sb=NULL;
1278 /* make temporary metastrips so that entire islands of selections can be moved around */
1279 BKE_nlastrips_make_metas(&nlt->strips, 1);
1281 /* special case: if there is only 1 island (i.e. temp meta BUT NOT unselected/normal/normal-meta strips) left after this,
1282 * and this island has two strips inside it, then we should be able to just swap these still...
1284 if ((nlt->strips.first == nlt->strips.last) && (nlt->strips.first != NULL)) {
1285 NlaStrip *mstrip = (NlaStrip *)nlt->strips.first;
1287 if ((mstrip->flag & NLASTRIP_FLAG_TEMP_META) && (BLI_countlist(&mstrip->strips) == 2))
1289 /* remove this temp meta, so that we can see the strips inside */
1290 BKE_nlastrips_clear_metas(&nlt->strips, 0, 1);
1294 /* get two selected strips only (these will be metas due to prev step) to operate on
1295 * - only allow swapping 2, as with more the context becomes unclear
1297 for (strip = nlt->strips.first; strip; strip = stripN) {
1298 stripN = strip->next;
1300 if (strip->flag & NLASTRIP_FLAG_SELECT) {
1301 /* first or second strip? */
1303 /* store as first */
1306 else if (sb == NULL) {
1307 /* store as second */
1311 /* too many selected */
1318 /* too many selected warning */
1319 BKE_reportf(op->reports, RPT_WARNING,
1320 "Too many clusters of strips selected in NLA Track (%s). Needs exactly 2 to be selected.",
1323 else if (sa == NULL) {
1324 /* no warning as this is just a common case, and it may get annoying when doing multiple tracks */
1326 else if (sb == NULL) {
1327 /* too few selected warning */
1328 BKE_reportf(op->reports, RPT_WARNING,
1329 "Too few clusters of strips selected in NLA Track (%s). Needs exactly 2 to be selected.",
1333 float nsa[2], nsb[2];
1335 /* remove these strips from the track, so that we can test if they can fit in the proposed places */
1336 BLI_remlink(&nlt->strips, sa);
1337 BLI_remlink(&nlt->strips, sb);
1339 /* calculate new extents for strips */
1342 nsa[1] = sb->start + (sa->end - sa->start);
1345 nsb[1] = sa->start + (sb->end - sb->start);
1347 /* check if the track has room for the strips to be swapped */
1348 if (BKE_nlastrips_has_space(&nlt->strips, nsa[0], nsa[1]) &&
1349 BKE_nlastrips_has_space(&nlt->strips, nsb[0], nsb[1]))
1351 /* set new extents for strips then */
1354 BKE_nlameta_flush_transforms(sa);
1358 BKE_nlameta_flush_transforms(sb);
1361 /* not enough room to swap, so show message */
1362 if ((sa->flag & NLASTRIP_FLAG_TEMP_META) || (sb->flag & NLASTRIP_FLAG_TEMP_META)) {
1363 BKE_report(op->reports, RPT_WARNING,
1364 "Cannot swap selected strips as they will not be able to fit in their new places");
1367 BKE_reportf(op->reports, RPT_WARNING,
1368 "Cannot swap '%s' and '%s' as one or both will not be able to fit in their new places",
1369 sa->name, sb->name);
1373 /* add strips back to track now */
1374 BKE_nlatrack_add_strip(nlt, sa);
1375 BKE_nlatrack_add_strip(nlt, sb);
1378 /* clear (temp) metastrips */
1379 BKE_nlastrips_clear_metas(&nlt->strips, 0, 1);
1382 /* free temp data */
1383 BLI_freelistN(&anim_data);
1385 /* refresh auto strip properties */
1386 ED_nla_postop_refresh(&ac);
1388 /* set notifier that things have changed */
1389 WM_event_add_notifier(C, NC_ANIMATION|ND_NLA|NA_EDITED, NULL);
1392 return OPERATOR_FINISHED;
1395 void NLA_OT_swap (wmOperatorType *ot)
1398 ot->name= "Swap Strips";
1399 ot->idname= "NLA_OT_swap";
1400 ot->description= "Swap order of selected strips within tracks";
1403 ot->exec= nlaedit_swap_exec;
1404 ot->poll= nlaop_poll_tweakmode_off;
1407 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1410 /* ******************** Move Strips Up Operator ************************** */
1411 /* Tries to move the selected strips into the track above if possible. */
1413 static int nlaedit_move_up_exec (bContext *C, wmOperator *UNUSED(op))
1417 ListBase anim_data = {NULL, NULL};
1421 /* get editor data */
1422 if (ANIM_animdata_get_context(C, &ac) == 0)
1423 return OPERATOR_CANCELLED;
1425 /* get a list of the editable tracks being shown in the NLA */
1426 filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
1427 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
1429 /* since we're potentially moving strips from lower tracks to higher tracks, we should
1430 * loop over the tracks in reverse order to avoid moving earlier strips up multiple tracks
1432 for (ale= anim_data.last; ale; ale= ale->prev) {
1433 NlaTrack *nlt= (NlaTrack *)ale->data;
1434 NlaTrack *nltn= nlt->next;
1435 NlaStrip *strip, *stripn;
1437 /* if this track has no tracks after it, skip for now... */
1441 /* for every selected strip, try to move */
1442 for (strip= nlt->strips.first; strip; strip= stripn) {
1443 stripn= strip->next;
1445 if (strip->flag & NLASTRIP_FLAG_SELECT) {
1446 /* check if the track above has room for this strip */
1447 if (BKE_nlatrack_has_space(nltn, strip->start, strip->end)) {
1448 /* remove from its current track, and add to the one above (it 'should' work, so no need to worry) */
1449 BLI_remlink(&nlt->strips, strip);
1450 BKE_nlatrack_add_strip(nltn, strip);
1456 /* free temp data */
1457 BLI_freelistN(&anim_data);
1459 /* refresh auto strip properties */
1460 ED_nla_postop_refresh(&ac);
1462 /* set notifier that things have changed */
1463 WM_event_add_notifier(C, NC_ANIMATION|ND_NLA|NA_EDITED, NULL);
1466 return OPERATOR_FINISHED;
1469 void NLA_OT_move_up (wmOperatorType *ot)
1472 ot->name= "Move Strips Up";
1473 ot->idname= "NLA_OT_move_up";
1474 ot->description= "Move selected strips up a track if there's room";
1477 ot->exec= nlaedit_move_up_exec;
1478 ot->poll= nlaop_poll_tweakmode_off;
1481 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1484 /* ******************** Move Strips Down Operator ************************** */
1485 /* Tries to move the selected strips into the track above if possible. */
1487 static int nlaedit_move_down_exec (bContext *C, wmOperator *UNUSED(op))
1491 ListBase anim_data = {NULL, NULL};
1495 /* get editor data */
1496 if (ANIM_animdata_get_context(C, &ac) == 0)
1497 return OPERATOR_CANCELLED;
1499 /* get a list of the editable tracks being shown in the NLA */
1500 filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
1501 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
1503 /* loop through the tracks in normal order, since we're pushing strips down,
1504 * strips won't get operated on twice
1506 for (ale= anim_data.first; ale; ale= ale->next) {
1507 NlaTrack *nlt= (NlaTrack *)ale->data;
1508 NlaTrack *nltp= nlt->prev;
1509 NlaStrip *strip, *stripn;
1511 /* if this track has no tracks before it, skip for now... */
1515 /* for every selected strip, try to move */
1516 for (strip= nlt->strips.first; strip; strip= stripn) {
1517 stripn= strip->next;
1519 if (strip->flag & NLASTRIP_FLAG_SELECT) {
1520 /* check if the track below has room for this strip */
1521 if (BKE_nlatrack_has_space(nltp, strip->start, strip->end)) {
1522 /* remove from its current track, and add to the one above (it 'should' work, so no need to worry) */
1523 BLI_remlink(&nlt->strips, strip);
1524 BKE_nlatrack_add_strip(nltp, strip);
1530 /* free temp data */
1531 BLI_freelistN(&anim_data);
1533 /* refresh auto strip properties */
1534 ED_nla_postop_refresh(&ac);
1536 /* set notifier that things have changed */
1537 WM_event_add_notifier(C, NC_ANIMATION|ND_NLA|NA_EDITED, NULL);
1540 return OPERATOR_FINISHED;
1543 void NLA_OT_move_down (wmOperatorType *ot)
1546 ot->name= "Move Strips Down";
1547 ot->idname= "NLA_OT_move_down";
1548 ot->description= "Move selected strips down a track if there's room";
1551 ot->exec= nlaedit_move_down_exec;
1552 ot->poll= nlaop_poll_tweakmode_off;
1555 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1558 /* ******************** Sync Action Length Operator ***************************** */
1559 /* Recalculate the extents of the action ranges used for the selected strips */
1561 static int nlaedit_sync_actlen_exec (bContext *C, wmOperator *op)
1565 ListBase anim_data = {NULL, NULL};
1568 short active_only= RNA_boolean_get(op->ptr, "active");
1570 /* get editor data */
1571 if (ANIM_animdata_get_context(C, &ac) == 0)
1572 return OPERATOR_CANCELLED;
1574 /* get a list of the editable tracks being shown in the NLA */
1575 filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
1576 if (active_only) filter |= ANIMFILTER_ACTIVE;
1577 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
1579 /* for each NLA-Track, apply scale of all selected strips */
1580 for (ale= anim_data.first; ale; ale= ale->next) {
1581 NlaTrack *nlt= (NlaTrack *)ale->data;
1584 for (strip= nlt->strips.first; strip; strip= strip->next) {
1585 /* strip selection/active status check */
1587 if ((strip->flag & NLASTRIP_FLAG_ACTIVE) == 0)
1591 if ((strip->flag & NLASTRIP_FLAG_SELECT) == 0)
1595 /* must be action-clip only (transitions don't have scale) */
1596 if (strip->type == NLASTRIP_TYPE_CLIP) {
1597 if (strip->act == NULL)
1600 /* recalculate the length of the action */
1601 calc_action_range(strip->act, &strip->actstart, &strip->actend, 0);
1603 /* adjust the strip extents in response to this */
1604 BKE_nlastrip_recalculate_bounds(strip);
1609 /* free temp data */
1610 BLI_freelistN(&anim_data);
1612 /* set notifier that things have changed */
1613 WM_event_add_notifier(C, NC_ANIMATION|ND_NLA|NA_EDITED, NULL);
1616 return OPERATOR_FINISHED;
1619 void NLA_OT_action_sync_length (wmOperatorType *ot)
1622 ot->name= "Sync Action Length";
1623 ot->idname= "NLA_OT_action_sync_length";
1624 ot->description= "Synchronise the length of the referenced Action with the lengths used in the strip";
1627 ot->exec= nlaedit_sync_actlen_exec;
1628 ot->poll= ED_operator_nla_active; // XXX: is this satisfactory... probably requires a check for active strip...
1631 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1634 ot->prop= RNA_def_boolean(ot->srna, "active", 1, "Active Strip Only", "Only sync the active length for the active strip.");
1637 /* ******************** Apply Scale Operator ***************************** */
1638 /* Reset the scaling of the selected strips to 1.0f */
1640 /* apply scaling to keyframe */
1641 static short bezt_apply_nlamapping (KeyframeEditData *ked, BezTriple *bezt)
1643 /* NLA-strip which has this scaling is stored in ked->data */
1644 NlaStrip *strip= (NlaStrip *)ked->data;
1646 /* adjust all the times */
1647 bezt->vec[0][0]= nlastrip_get_frame(strip, bezt->vec[0][0], NLATIME_CONVERT_MAP);
1648 bezt->vec[1][0]= nlastrip_get_frame(strip, bezt->vec[1][0], NLATIME_CONVERT_MAP);
1649 bezt->vec[2][0]= nlastrip_get_frame(strip, bezt->vec[2][0], NLATIME_CONVERT_MAP);
1651 /* nothing to return or else we exit */
1655 static int nlaedit_apply_scale_exec (bContext *C, wmOperator *UNUSED(op))
1659 ListBase anim_data = {NULL, NULL};
1663 KeyframeEditData ked= {{NULL}};
1665 /* get editor data */
1666 if (ANIM_animdata_get_context(C, &ac) == 0)
1667 return OPERATOR_CANCELLED;
1669 /* get a list of the editable tracks being shown in the NLA */
1670 filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
1671 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
1673 /* init the editing data */
1675 /* for each NLA-Track, apply scale of all selected strips */
1676 for (ale= anim_data.first; ale; ale= ale->next) {
1677 NlaTrack *nlt= (NlaTrack *)ale->data;
1680 for (strip= nlt->strips.first; strip; strip= strip->next) {
1681 /* strip must be selected, and must be action-clip only (transitions don't have scale) */
1682 if ((strip->flag & NLASTRIP_FLAG_SELECT) && (strip->type == NLASTRIP_TYPE_CLIP)) {
1683 /* if the referenced action is used by other strips, make this strip use its own copy */
1684 if (strip->act == NULL)
1686 if (strip->act->id.us > 1) {
1687 /* make a copy of the Action to work on */
1688 bAction *act= copy_action(strip->act);
1690 /* set this as the new referenced action, decrementing the users of the old one */
1691 strip->act->id.us--;
1695 /* setup iterator, and iterate over all the keyframes in the action, applying this scaling */
1697 ANIM_animchanneldata_keyframes_loop(&ked, ac.ads, strip->act, ALE_ACT, NULL, bezt_apply_nlamapping, calchandles_fcurve);
1699 /* clear scale of strip now that it has been applied,
1700 * and recalculate the extents of the action now that it has been scaled
1701 * but leave everything else alone
1704 calc_action_range(strip->act, &strip->actstart, &strip->actend, 0);
1709 /* free temp data */
1710 BLI_freelistN(&anim_data);
1712 /* set notifier that things have changed */
1713 WM_event_add_notifier(C, NC_ANIMATION|ND_NLA|NA_EDITED, NULL);
1716 return OPERATOR_FINISHED;
1719 void NLA_OT_apply_scale (wmOperatorType *ot)
1722 ot->name= "Apply Scale";
1723 ot->idname= "NLA_OT_apply_scale";
1724 ot->description= "Apply scaling of selected strips to their referenced Actions";
1727 ot->exec= nlaedit_apply_scale_exec;
1728 ot->poll= nlaop_poll_tweakmode_off;
1731 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1734 /* ******************** Clear Scale Operator ***************************** */
1735 /* Reset the scaling of the selected strips to 1.0f */
1737 static int nlaedit_clear_scale_exec (bContext *C, wmOperator *UNUSED(op))
1741 ListBase anim_data = {NULL, NULL};
1745 /* get editor data */
1746 if (ANIM_animdata_get_context(C, &ac) == 0)
1747 return OPERATOR_CANCELLED;
1749 /* get a list of the editable tracks being shown in the NLA */
1750 filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
1751 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
1753 /* for each NLA-Track, reset scale of all selected strips */
1754 for (ale= anim_data.first; ale; ale= ale->next) {
1755 NlaTrack *nlt= (NlaTrack *)ale->data;
1758 for (strip= nlt->strips.first; strip; strip= strip->next) {
1759 /* strip must be selected, and must be action-clip only (transitions don't have scale) */
1760 if ((strip->flag & NLASTRIP_FLAG_SELECT) && (strip->type == NLASTRIP_TYPE_CLIP)) {
1761 PointerRNA strip_ptr;
1763 RNA_pointer_create(NULL, &RNA_NlaStrip, strip, &strip_ptr);
1764 RNA_float_set(&strip_ptr, "scale", 1.0f);
1769 /* free temp data */
1770 BLI_freelistN(&anim_data);
1772 /* refresh auto strip properties */
1773 ED_nla_postop_refresh(&ac);
1775 /* set notifier that things have changed */
1776 WM_event_add_notifier(C, NC_ANIMATION|ND_NLA|NA_EDITED, NULL);
1779 return OPERATOR_FINISHED;
1782 void NLA_OT_clear_scale (wmOperatorType *ot)
1785 ot->name= "Clear Scale";
1786 ot->idname= "NLA_OT_clear_scale";
1787 ot->description= "Reset scaling of selected strips";
1790 ot->exec= nlaedit_clear_scale_exec;
1791 ot->poll= nlaop_poll_tweakmode_off;
1794 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1797 /* ******************** Snap Strips Operator ************************** */
1798 /* Moves the start-point of the selected strips to the specified places */
1800 /* defines for snap keyframes tool */
1801 static EnumPropertyItem prop_nlaedit_snap_types[] = {
1802 {NLAEDIT_SNAP_CFRA, "CFRA", 0, "Current frame", ""},
1803 {NLAEDIT_SNAP_NEAREST_FRAME, "NEAREST_FRAME", 0, "Nearest Frame", ""}, // XXX as single entry?
1804 {NLAEDIT_SNAP_NEAREST_SECOND, "NEAREST_SECOND", 0, "Nearest Second", ""}, // XXX as single entry?
1805 {NLAEDIT_SNAP_NEAREST_MARKER, "NEAREST_MARKER", 0, "Nearest Marker", ""},
1806 {0, NULL, 0, NULL, NULL}
1809 static int nlaedit_snap_exec (bContext *C, wmOperator *op)
1813 ListBase anim_data = {NULL, NULL};
1818 int mode = RNA_enum_get(op->ptr, "type");
1821 /* get editor data */
1822 if (ANIM_animdata_get_context(C, &ac) == 0)
1823 return OPERATOR_CANCELLED;
1825 /* get a list of the editable tracks being shown in the NLA */
1826 filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
1827 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
1829 /* get some necessary vars */
1833 /* since we may add tracks, perform this in reverse order */
1834 for (ale= anim_data.last; ale; ale= ale->prev) {
1835 ListBase tmp_strips = {NULL, NULL};
1836 AnimData *adt= ale->adt;
1837 NlaTrack *nlt= (NlaTrack *)ale->data;
1838 NlaStrip *strip, *stripn;
1841 /* create meta-strips from the continuous chains of selected strips */
1842 BKE_nlastrips_make_metas(&nlt->strips, 1);
1844 /* apply the snapping to all the temp meta-strips, then put them in a separate list to be added
1845 * back to the original only if they still fit
1847 for (strip= nlt->strips.first; strip; strip= stripn) {
1848 stripn= strip->next;
1850 if (strip->flag & NLASTRIP_FLAG_TEMP_META) {
1853 /* get the existing end-points */
1854 start= strip->start;
1857 /* calculate new start position based on snapping mode */
1859 case NLAEDIT_SNAP_CFRA: /* to current frame */
1860 strip->start= (float)CFRA;
1862 case NLAEDIT_SNAP_NEAREST_FRAME: /* to nearest frame */
1863 strip->start= (float)(floor(start+0.5));
1865 case NLAEDIT_SNAP_NEAREST_SECOND: /* to nearest second */
1866 strip->start= ((float)floor(start/secf + 0.5f) * secf);
1868 case NLAEDIT_SNAP_NEAREST_MARKER: /* to nearest marker */
1869 strip->start= (float)ED_markers_find_nearest_marker_time(ac.markers, start);
1871 default: /* just in case... no snapping */
1872 strip->start= start;
1876 /* get new endpoint based on start-point (and old length) */
1877 strip->end= strip->start + (end - start);
1879 /* apply transforms to meta-strip to its children */
1880 BKE_nlameta_flush_transforms(strip);
1882 /* remove strip from track, and add to the temp buffer */
1883 BLI_remlink(&nlt->strips, strip);
1884 BLI_addtail(&tmp_strips, strip);
1888 /* try adding each meta-strip back to the track one at a time, to make sure they'll fit */
1889 for (strip= tmp_strips.first; strip; strip= stripn) {
1890 stripn= strip->next;
1892 /* remove from temp-strips list */
1893 BLI_remlink(&tmp_strips, strip);
1895 /* in case there's no space in the current track, try adding */
1896 if (BKE_nlatrack_add_strip(nlt, strip) == 0) {
1897 /* need to add a new track above the current one */
1898 track= add_nlatrack(adt, nlt);
1899 BKE_nlatrack_add_strip(track, strip);
1901 /* clear temp meta-strips on this new track, as we may not be able to get back to it */
1902 BKE_nlastrips_clear_metas(&track->strips, 0, 1);
1906 /* remove the meta-strips now that we're done */
1907 BKE_nlastrips_clear_metas(&nlt->strips, 0, 1);
1910 /* free temp data */
1911 BLI_freelistN(&anim_data);
1913 /* refresh auto strip properties */
1914 ED_nla_postop_refresh(&ac);
1916 /* set notifier that things have changed */
1917 WM_event_add_notifier(C, NC_ANIMATION|ND_NLA|NA_EDITED, NULL);
1920 return OPERATOR_FINISHED;
1923 void NLA_OT_snap (wmOperatorType *ot)
1926 ot->name= "Snap Strips";
1927 ot->idname= "NLA_OT_snap";
1928 ot->description= "Move start of strips to specified time";
1931 ot->invoke= WM_menu_invoke;
1932 ot->exec= nlaedit_snap_exec;
1933 ot->poll= nlaop_poll_tweakmode_off;
1936 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1939 ot->prop= RNA_def_enum(ot->srna, "type", prop_nlaedit_snap_types, 0, "Type", "");
1942 /* *********************************************** */
1945 /* ******************** Add F-Modifier Operator *********************** */
1947 /* present a special customised popup menu for this, with some filtering */
1948 static int nla_fmodifier_add_invoke (bContext *C, wmOperator *UNUSED(op), wmEvent *UNUSED(event))
1954 pup= uiPupMenuBegin(C, "Add F-Modifier", ICON_NONE);
1955 layout= uiPupMenuLayout(pup);
1957 /* start from 1 to skip the 'Invalid' modifier type */
1958 for (i = 1; i < FMODIFIER_NUM_TYPES; i++) {
1959 FModifierTypeInfo *fmi= get_fmodifier_typeinfo(i);
1961 /* check if modifier is valid for this context */
1964 if (i == FMODIFIER_TYPE_CYCLES) /* we already have repeat... */
1967 /* add entry to add this type of modifier */
1968 uiItemEnumO(layout, "NLA_OT_fmodifier_add", fmi->name, 0, "type", i);
1972 uiPupMenuEnd(C, pup);
1974 return OPERATOR_CANCELLED;
1977 static int nla_fmodifier_add_exec(bContext *C, wmOperator *op)
1981 ListBase anim_data = {NULL, NULL};
1986 int type= RNA_enum_get(op->ptr, "type");
1987 short onlyActive = RNA_boolean_get(op->ptr, "only_active");
1989 /* get editor data */
1990 if (ANIM_animdata_get_context(C, &ac) == 0)
1991 return OPERATOR_CANCELLED;
1993 /* get a list of the editable tracks being shown in the NLA */
1994 filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
1995 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
1997 /* for each NLA-Track, add the specified modifier to all selected strips */
1998 for (ale= anim_data.first; ale; ale= ale->next) {
1999 NlaTrack *nlt= (NlaTrack *)ale->data;
2002 for (strip= nlt->strips.first; strip; strip=strip->next) {
2003 /* can F-Modifier be added to the current strip? */
2005 /* if not active, cannot add since we're only adding to active strip */
2006 if ((strip->flag & NLASTRIP_FLAG_ACTIVE)==0)
2010 /* strip must be selected, since we're not just doing active */
2011 if ((strip->flag & NLASTRIP_FLAG_SELECT)==0)
2015 /* sound clips are not affected by FModifiers */
2016 if (strip->type == NLASTRIP_TYPE_SOUND)
2019 /* add F-Modifier of specified type to selected, and make it the active one */
2020 fcm= add_fmodifier(&strip->modifiers, type);
2023 set_active_fmodifier(&strip->modifiers, fcm);
2025 BKE_reportf(op->reports, RPT_ERROR,
2026 "Modifier couldn't be added to (%s : %s). See console for details.",
2027 nlt->name, strip->name);
2032 /* free temp data */
2033 BLI_freelistN(&anim_data);
2035 /* set notifier that things have changed */
2036 WM_event_add_notifier(C, NC_ANIMATION|ND_NLA|NA_EDITED, NULL);
2039 return OPERATOR_FINISHED;
2042 void NLA_OT_fmodifier_add (wmOperatorType *ot)
2045 ot->name= "Add F-Modifier";
2046 ot->idname= "NLA_OT_fmodifier_add";
2047 ot->description= "Add F-Modifier of the specified type to the selected NLA-Strips";
2050 ot->invoke= nla_fmodifier_add_invoke;
2051 ot->exec= nla_fmodifier_add_exec;
2052 ot->poll= nlaop_poll_tweakmode_off;
2055 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2058 ot->prop= RNA_def_enum(ot->srna, "type", fmodifier_type_items, 0, "Type", "");
2059 RNA_def_boolean(ot->srna, "only_active", 0, "Only Active", "Only add F-Modifier of the specified type to the active strip.");
2062 /* ******************** Copy F-Modifiers Operator *********************** */
2064 static int nla_fmodifier_copy_exec(bContext *C, wmOperator *op)
2067 ListBase anim_data = {NULL, NULL};
2071 /* get editor data */
2072 if (ANIM_animdata_get_context(C, &ac) == 0)
2073 return OPERATOR_CANCELLED;
2075 /* clear buffer first */
2076 free_fmodifiers_copybuf();
2078 /* get a list of the editable tracks being shown in the NLA */
2079 filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
2080 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
2082 /* for each NLA-Track, add the specified modifier to all selected strips */
2083 for (ale= anim_data.first; ale; ale= ale->next) {
2084 NlaTrack *nlt= (NlaTrack *)ale->data;
2087 for (strip= nlt->strips.first; strip; strip=strip->next) {
2088 /* only add F-Modifier if on active strip? */
2089 if ((strip->flag & NLASTRIP_FLAG_ACTIVE)==0)
2092 // TODO: when 'active' vs 'all' boolean is added, change last param!
2093 ok += ANIM_fmodifiers_copy_to_buf(&strip->modifiers, 0);
2097 /* successful or not? */
2099 BKE_report(op->reports, RPT_ERROR, "No F-Modifiers available to be copied");
2100 return OPERATOR_CANCELLED;
2103 return OPERATOR_FINISHED;
2106 void NLA_OT_fmodifier_copy (wmOperatorType *ot)
2109 ot->name= "Copy F-Modifiers";
2110 ot->idname= "NLA_OT_fmodifier_copy";
2111 ot->description= "Copy the F-Modifier(s) of the active NLA-Strip";
2114 ot->exec= nla_fmodifier_copy_exec;
2115 ot->poll= nlaop_poll_tweakmode_off;
2118 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2121 //ot->prop = RNA_def_boolean(ot->srna, "all", 1, "All F-Modifiers", "Copy all the F-Modifiers, instead of just the active one");
2124 /* ******************** Paste F-Modifiers Operator *********************** */
2126 static int nla_fmodifier_paste_exec(bContext *C, wmOperator *op)
2129 ListBase anim_data = {NULL, NULL};
2133 /* get editor data */
2134 if (ANIM_animdata_get_context(C, &ac) == 0)
2135 return OPERATOR_CANCELLED;
2137 /* get a list of the editable tracks being shown in the NLA */
2138 filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_SEL | ANIMFILTER_FOREDIT);
2139 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
2141 /* for each NLA-Track, add the specified modifier to all selected strips */
2142 for (ale= anim_data.first; ale; ale= ale->next) {
2143 NlaTrack *nlt= (NlaTrack *)ale->data;
2146 for (strip= nlt->strips.first; strip; strip=strip->next) {
2147 // TODO: do we want to replace existing modifiers? add user pref for that!
2148 ok += ANIM_fmodifiers_paste_from_buf(&strip->modifiers, 0);
2153 BLI_freelistN(&anim_data);
2155 /* successful or not? */
2157 /* set notifier that things have changed */
2158 /* set notifier that things have changed */
2159 WM_event_add_notifier(C, NC_ANIMATION|ND_NLA|NA_EDITED, NULL);
2160 return OPERATOR_FINISHED;
2163 BKE_report(op->reports, RPT_ERROR, "No F-Modifiers to paste");
2164 return OPERATOR_CANCELLED;
2168 void NLA_OT_fmodifier_paste (wmOperatorType *ot)
2171 ot->name= "Paste F-Modifiers";
2172 ot->idname= "NLA_OT_fmodifier_paste";
2173 ot->description= "Add copied F-Modifiers to the selected NLA-Strips";
2176 ot->exec= nla_fmodifier_paste_exec;
2177 ot->poll= nlaop_poll_tweakmode_off;
2180 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2183 /* *********************************************** */