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 *****
33 #include "DNA_anim_types.h"
34 #include "DNA_action_types.h"
35 #include "DNA_nla_types.h"
36 #include "DNA_object_types.h"
37 #include "DNA_space_types.h"
38 #include "DNA_scene_types.h"
39 #include "DNA_screen_types.h"
40 #include "DNA_windowmanager_types.h"
42 #include "MEM_guardedalloc.h"
44 #include "BLI_blenlib.h"
48 #include "BKE_animsys.h"
49 #include "BKE_action.h"
50 #include "BKE_fcurve.h"
52 #include "BKE_context.h"
53 #include "BKE_library.h"
55 #include "BKE_report.h"
56 #include "BKE_screen.h"
57 #include "BKE_utildefines.h"
59 #include "ED_anim_api.h"
60 #include "ED_keyframes_edit.h"
61 #include "ED_markers.h"
62 #include "ED_space_api.h"
63 #include "ED_screen.h"
64 #include "ED_transform.h"
66 #include "RNA_access.h"
67 #include "RNA_define.h"
68 #include "RNA_enum_types.h"
73 #include "UI_interface.h"
74 #include "UI_resources.h"
75 #include "UI_view2d.h"
77 #include "nla_intern.h" // own include
78 #include "nla_private.h" // FIXME... maybe this shouldn't be included?
80 /* *********************************************** */
81 /* Utilities exported to other places... */
83 /* Perform validation for blending/extend settings */
84 void ED_nla_postop_refresh (bAnimContext *ac)
86 ListBase anim_data = {NULL, NULL};
88 short filter= (ANIMFILTER_VISIBLE | ANIMFILTER_ANIMDATA | ANIMFILTER_FOREDIT);
90 /* get blocks to work on */
91 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
93 for (ale= anim_data.first; ale; ale= ale->next) {
94 /* performing auto-blending, extend-mode validation, etc. */
95 BKE_nla_validate_state(ale->data);
98 /* free temp memory */
99 BLI_freelistN(&anim_data);
102 /* *********************************************** */
103 /* 'Special' Editing */
105 /* ******************** Tweak-Mode Operators ***************************** */
106 /* 'Tweak mode' allows the action referenced by the active NLA-strip to be edited
107 * as if it were the normal Active-Action of its AnimData block.
110 static int nlaedit_enable_tweakmode_exec (bContext *C, wmOperator *op)
114 ListBase anim_data = {NULL, NULL};
119 /* get editor data */
120 if (ANIM_animdata_get_context(C, &ac) == 0)
121 return OPERATOR_CANCELLED;
123 /* get a list of the AnimData blocks being shown in the NLA */
124 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_ANIMDATA);
125 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
127 /* if no blocks, popup error? */
128 if (anim_data.first == NULL) {
129 BKE_report(op->reports, RPT_ERROR, "No AnimData blocks to enter tweakmode for");
130 return OPERATOR_CANCELLED;
133 /* for each AnimData block with NLA-data, try setting it in tweak-mode */
134 for (ale= anim_data.first; ale; ale= ale->next) {
135 AnimData *adt= ale->data;
137 /* try entering tweakmode if valid */
138 ok += BKE_nla_tweakmode_enter(adt);
142 BLI_freelistN(&anim_data);
144 /* if we managed to enter tweakmode on at least one AnimData block,
145 * set the flag for this in the active scene and send notifiers
147 if (ac.scene && ok) {
148 /* set editing flag */
149 ac.scene->flag |= SCE_NLA_EDIT_ON;
151 /* set notifier that things have changed */
152 WM_event_add_notifier(C, NC_ANIMATION|ND_NLA_ACTCHANGE, NULL);
155 BKE_report(op->reports, RPT_ERROR, "No active strip(s) to enter tweakmode on.");
156 return OPERATOR_CANCELLED;
160 return OPERATOR_FINISHED;
163 void NLA_OT_tweakmode_enter (wmOperatorType *ot)
166 ot->name= "Enter Tweak Mode";
167 ot->idname= "NLA_OT_tweakmode_enter";
168 ot->description= "Enter tweaking mode for the action referenced by the active strip";
171 ot->exec= nlaedit_enable_tweakmode_exec;
172 ot->poll= nlaop_poll_tweakmode_off;
175 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
180 static int nlaedit_disable_tweakmode_exec (bContext *C, wmOperator *op)
184 ListBase anim_data = {NULL, NULL};
188 /* get editor data */
189 if (ANIM_animdata_get_context(C, &ac) == 0)
190 return OPERATOR_CANCELLED;
192 /* get a list of the AnimData blocks being shown in the NLA */
193 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_ANIMDATA);
194 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
196 /* if no blocks, popup error? */
197 if (anim_data.first == NULL) {
198 BKE_report(op->reports, RPT_ERROR, "No AnimData blocks to enter tweakmode for");
199 return OPERATOR_CANCELLED;
202 /* for each AnimData block with NLA-data, try exitting tweak-mode */
203 for (ale= anim_data.first; ale; ale= ale->next) {
204 AnimData *adt= ale->data;
206 /* try entering tweakmode if valid */
207 BKE_nla_tweakmode_exit(adt);
211 BLI_freelistN(&anim_data);
213 /* if we managed to enter tweakmode on at least one AnimData block,
214 * set the flag for this in the active scene and send notifiers
217 /* clear editing flag */
218 ac.scene->flag &= ~SCE_NLA_EDIT_ON;
220 /* set notifier that things have changed */
221 WM_event_add_notifier(C, NC_ANIMATION|ND_NLA_ACTCHANGE, NULL);
225 return OPERATOR_FINISHED;
228 void NLA_OT_tweakmode_exit (wmOperatorType *ot)
231 ot->name= "Exit Tweak Mode";
232 ot->idname= "NLA_OT_tweakmode_exit";
233 ot->description= "Exit tweaking mode for the action referenced by the active strip";
236 ot->exec= nlaedit_disable_tweakmode_exec;
237 ot->poll= nlaop_poll_tweakmode_on;
240 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
243 /* *********************************************** */
244 /* NLA Editing Operations (Constructive/Destructive) */
246 /* ******************** Add Action-Clip Operator ***************************** */
247 /* Add a new Action-Clip strip to the active track (or the active block if no space in the track) */
250 /* add the specified action as new strip */
251 static int nlaedit_add_actionclip_exec (bContext *C, wmOperator *op)
256 ListBase anim_data = {NULL, NULL};
264 /* get editor data */
265 if (ANIM_animdata_get_context(C, &ac) == 0)
266 return OPERATOR_CANCELLED;
271 /* get action to use */
272 act= BLI_findlink(&CTX_data_main(C)->action, RNA_enum_get(op->ptr, "type"));
275 BKE_report(op->reports, RPT_ERROR, "No valid Action to add.");
276 //printf("Add strip - actname = '%s' \n", actname);
277 return OPERATOR_CANCELLED;
280 /* get a list of the editable tracks being shown in the NLA
281 * - this is limited to active ones for now, but could be expanded to
283 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_ACTIVE | ANIMFILTER_NLATRACKS | ANIMFILTER_FOREDIT);
284 items= ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
287 BKE_report(op->reports, RPT_ERROR, "No active track(s) to add strip to.");
288 return OPERATOR_CANCELLED;
291 /* for every active track, try to add strip to free space in track or to the top of the stack if no space */
292 for (ale= anim_data.first; ale; ale= ale->next) {
293 NlaTrack *nlt= (NlaTrack *)ale->data;
294 AnimData *adt= ale->adt;
295 NlaStrip *strip= NULL;
297 /* create a new strip, and offset it to start on the current frame */
298 strip= add_nlastrip(act);
300 strip->end += (cfra - strip->start);
303 /* firstly try adding strip to our current track, but if that fails, add to a new track */
304 if (BKE_nlatrack_add_strip(nlt, strip) == 0) {
305 /* trying to add to the current failed (no space),
306 * so add a new track to the stack, and add to that...
308 nlt= add_nlatrack(adt, NULL);
309 BKE_nlatrack_add_strip(nlt, strip);
313 BKE_nlastrip_validate_name(adt, strip);
317 BLI_freelistN(&anim_data);
319 /* refresh auto strip properties */
320 ED_nla_postop_refresh(&ac);
322 /* set notifier that things have changed */
323 WM_event_add_notifier(C, NC_ANIMATION|ND_NLA_EDIT, NULL);
326 return OPERATOR_FINISHED;
329 void NLA_OT_actionclip_add (wmOperatorType *ot)
334 ot->name= "Add Action Strip";
335 ot->idname= "NLA_OT_actionclip_add";
336 ot->description= "Add an Action-Clip strip (i.e. an NLA Strip referencing an Action) to the active track";
339 ot->invoke= WM_enum_search_invoke;
340 ot->exec= nlaedit_add_actionclip_exec;
341 ot->poll= nlaop_poll_tweakmode_off;
344 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
347 // TODO: this would be nicer as an ID-pointer...
348 prop= RNA_def_enum(ot->srna, "type", DummyRNA_NULL_items, 0, "Type", "");
349 RNA_def_enum_funcs(prop, RNA_action_itemf);
353 /* ******************** Add Transition Operator ***************************** */
354 /* Add a new transition strip between selected strips */
356 static int nlaedit_add_transition_exec (bContext *C, wmOperator *op)
360 ListBase anim_data = {NULL, NULL};
366 /* get editor data */
367 if (ANIM_animdata_get_context(C, &ac) == 0)
368 return OPERATOR_CANCELLED;
370 /* get a list of the editable tracks being shown in the NLA */
371 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_NLATRACKS | ANIMFILTER_FOREDIT);
372 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
374 /* for each track, find pairs of strips to add transitions to */
375 for (ale= anim_data.first; ale; ale= ale->next) {
376 NlaTrack *nlt= (NlaTrack *)ale->data;
377 AnimData *adt= ale->adt;
380 /* get initial pair of strips */
381 if ELEM(nlt->strips.first, NULL, nlt->strips.last)
383 s1= nlt->strips.first;
386 /* loop over strips */
387 for (; s1 && s2; s1=s2, s2=s2->next) {
390 /* check if both are selected */
391 if ELEM(0, (s1->flag & NLASTRIP_FLAG_SELECT), (s2->flag & NLASTRIP_FLAG_SELECT))
393 /* check if there's space between the two */
394 if (IS_EQ(s1->end, s2->start))
396 /* make neither one is a transition
397 * - although this is impossible to create with the standard tools,
398 * the user may have altered the settings
400 if (ELEM(NLASTRIP_TYPE_TRANSITION, s1->type, s2->type))
403 /* allocate new strip */
404 strip= MEM_callocN(sizeof(NlaStrip), "NlaStrip");
405 BLI_insertlinkafter(&nlt->strips, s1, strip);
408 strip->type= NLASTRIP_TYPE_TRANSITION;
411 * - selected flag to highlight this to the user
412 * - auto-blends to ensure that blend in/out values are automatically
413 * determined by overlaps of strips
415 strip->flag = NLASTRIP_FLAG_SELECT|NLASTRIP_FLAG_AUTO_BLENDS;
417 /* range is simply defined as the endpoints of the adjacent strips */
418 strip->start = s1->end;
419 strip->end = s2->start;
421 /* scale and repeat aren't of any use, but shouldn't ever be 0 */
423 strip->repeat = 1.0f;
426 BKE_nlastrip_validate_name(adt, strip);
428 /* make note of this */
434 BLI_freelistN(&anim_data);
436 /* was anything added? */
438 /* refresh auto strip properties */
439 ED_nla_postop_refresh(&ac);
441 /* set notifier that things have changed */
442 WM_event_add_notifier(C, NC_ANIMATION|ND_NLA_EDIT, NULL);
445 return OPERATOR_FINISHED;
448 BKE_report(op->reports, RPT_ERROR, "Needs at least a pair of adjacent selected strips with a gap between them.");
449 return OPERATOR_CANCELLED;
453 void NLA_OT_transition_add (wmOperatorType *ot)
456 ot->name= "Add Transition";
457 ot->idname= "NLA_OT_transition_add";
458 ot->description= "Add a transition strip between two adjacent selected strips";
461 ot->exec= nlaedit_add_transition_exec;
462 ot->poll= nlaop_poll_tweakmode_off;
465 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
468 /* ******************** Add Meta-Strip Operator ***************************** */
469 /* Add new meta-strips incorporating the selected strips */
471 /* add the specified action as new strip */
472 static int nlaedit_add_meta_exec (bContext *C, wmOperator *op)
476 ListBase anim_data = {NULL, NULL};
480 /* get editor data */
481 if (ANIM_animdata_get_context(C, &ac) == 0)
482 return OPERATOR_CANCELLED;
484 /* get a list of the editable tracks being shown in the NLA */
485 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_NLATRACKS | ANIMFILTER_FOREDIT);
486 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
488 /* for each track, find pairs of strips to add transitions to */
489 for (ale= anim_data.first; ale; ale= ale->next) {
490 NlaTrack *nlt= (NlaTrack *)ale->data;
491 AnimData *adt= ale->adt;
494 /* create meta-strips from the continuous chains of selected strips */
495 BKE_nlastrips_make_metas(&nlt->strips, 0);
498 for (strip= nlt->strips.first; strip; strip= strip->next) {
499 /* auto-name this strip if selected (that means it is a meta) */
500 if (strip->flag & NLASTRIP_FLAG_SELECT)
501 BKE_nlastrip_validate_name(adt, strip);
506 BLI_freelistN(&anim_data);
508 /* set notifier that things have changed */
509 WM_event_add_notifier(C, NC_ANIMATION|ND_NLA_EDIT, NULL);
512 return OPERATOR_FINISHED;
515 void NLA_OT_meta_add (wmOperatorType *ot)
518 ot->name= "Add Meta-Strips";
519 ot->idname= "NLA_OT_meta_add";
520 ot->description= "Add new meta-strips incorporating the selected strips";
523 ot->exec= nlaedit_add_meta_exec;
524 ot->poll= nlaop_poll_tweakmode_off;
527 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
530 /* ******************** Remove Meta-Strip Operator ***************************** */
531 /* Separate out the strips held by the selected meta-strips */
533 static int nlaedit_remove_meta_exec (bContext *C, wmOperator *op)
537 ListBase anim_data = {NULL, NULL};
541 /* get editor data */
542 if (ANIM_animdata_get_context(C, &ac) == 0)
543 return OPERATOR_CANCELLED;
545 /* get a list of the editable tracks being shown in the NLA */
546 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_NLATRACKS | ANIMFILTER_FOREDIT);
547 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
549 /* for each track, find pairs of strips to add transitions to */
550 for (ale= anim_data.first; ale; ale= ale->next) {
551 NlaTrack *nlt= (NlaTrack *)ale->data;
553 /* clear all selected meta-strips, regardless of whether they are temporary or not */
554 BKE_nlastrips_clear_metas(&nlt->strips, 1, 0);
558 BLI_freelistN(&anim_data);
560 /* set notifier that things have changed */
561 WM_event_add_notifier(C, NC_ANIMATION|ND_NLA_EDIT, NULL);
564 return OPERATOR_FINISHED;
567 void NLA_OT_meta_remove (wmOperatorType *ot)
570 ot->name= "Remove Meta-Strips";
571 ot->idname= "NLA_OT_meta_remove";
572 ot->description= "Separate out the strips held by the selected meta-strips";
575 ot->exec= nlaedit_remove_meta_exec;
576 ot->poll= nlaop_poll_tweakmode_off;
579 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
582 /* ******************** Duplicate Strips Operator ************************** */
583 /* Duplicates the selected NLA-Strips, putting them on new tracks above the one
584 * the originals were housed in.
587 static int nlaedit_duplicate_exec (bContext *C, wmOperator *op)
591 ListBase anim_data = {NULL, NULL};
597 /* get editor data */
598 if (ANIM_animdata_get_context(C, &ac) == 0)
599 return OPERATOR_CANCELLED;
601 /* get a list of editable tracks being shown in the NLA */
602 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_NLATRACKS | ANIMFILTER_FOREDIT);
603 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
605 /* duplicate strips in tracks starting from the last one so that we're
606 * less likely to duplicate strips we just duplicated...
608 for (ale= anim_data.last; ale; ale= ale->prev) {
609 NlaTrack *nlt= (NlaTrack *)ale->data;
610 AnimData *adt= ale->adt;
611 NlaStrip *strip, *nstrip, *next;
614 for (strip= nlt->strips.first; strip; strip= next) {
617 /* if selected, split the strip at its midpoint */
618 if (strip->flag & NLASTRIP_FLAG_SELECT) {
619 /* make a copy (assume that this is possible) */
620 nstrip= copy_nlastrip(strip);
622 /* in case there's no space in the track above, or we haven't got a reference to it yet, try adding */
623 if (BKE_nlatrack_add_strip(nlt->next, nstrip) == 0) {
624 /* need to add a new track above the one above the current one
625 * - if the current one is the last one, nlt->next will be NULL, which defaults to adding
626 * at the top of the stack anyway...
628 track= add_nlatrack(adt, nlt->next);
629 BKE_nlatrack_add_strip(track, nstrip);
632 /* deselect the original and the active flag */
633 strip->flag &= ~(NLASTRIP_FLAG_SELECT|NLASTRIP_FLAG_ACTIVE);
636 BKE_nlastrip_validate_name(adt, strip);
644 BLI_freelistN(&anim_data);
647 /* refresh auto strip properties */
648 ED_nla_postop_refresh(&ac);
650 /* set notifier that things have changed */
651 WM_event_add_notifier(C, NC_ANIMATION|ND_NLA_EDIT, NULL);
654 return OPERATOR_FINISHED;
657 return OPERATOR_CANCELLED;
660 static int nlaedit_duplicate_invoke(bContext *C, wmOperator *op, wmEvent *event)
662 nlaedit_duplicate_exec(C, op);
664 RNA_int_set(op->ptr, "mode", TFM_TIME_TRANSLATE); // XXX
665 WM_operator_name_call(C, "TRANSFORM_OT_transform", WM_OP_INVOKE_REGION_WIN, op->ptr);
667 return OPERATOR_FINISHED;
670 void NLA_OT_duplicate (wmOperatorType *ot)
673 ot->name= "Duplicate Strips";
674 ot->idname= "NLA_OT_duplicate";
675 ot->description= "Duplicate selected NLA-Strips, adding the new strips in new tracks above the originals";
678 ot->invoke= nlaedit_duplicate_invoke;
679 ot->exec= nlaedit_duplicate_exec;
680 ot->poll= nlaop_poll_tweakmode_off;
683 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
685 /* to give to transform */
686 RNA_def_int(ot->srna, "mode", TFM_TRANSLATION, 0, INT_MAX, "Mode", "", 0, INT_MAX);
689 /* ******************** Delete Strips Operator ***************************** */
690 /* Deletes the selected NLA-Strips */
692 static int nlaedit_delete_exec (bContext *C, wmOperator *op)
696 ListBase anim_data = {NULL, NULL};
700 /* get editor data */
701 if (ANIM_animdata_get_context(C, &ac) == 0)
702 return OPERATOR_CANCELLED;
704 /* get a list of the editable tracks being shown in the NLA */
705 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_NLATRACKS | ANIMFILTER_FOREDIT);
706 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
708 /* for each NLA-Track, delete all selected strips */
709 for (ale= anim_data.first; ale; ale= ale->next) {
710 NlaTrack *nlt= (NlaTrack *)ale->data;
711 NlaStrip *strip, *nstrip;
713 for (strip= nlt->strips.first; strip; strip= nstrip) {
716 /* if selected, delete */
717 if (strip->flag & NLASTRIP_FLAG_SELECT) {
718 /* if a strip either side of this was a transition, delete those too */
719 if ((strip->prev) && (strip->prev->type == NLASTRIP_TYPE_TRANSITION))
720 free_nlastrip(&nlt->strips, strip->prev);
721 if ((nstrip) && (nstrip->type == NLASTRIP_TYPE_TRANSITION)) {
722 nstrip= nstrip->next;
723 free_nlastrip(&nlt->strips, strip->next);
726 /* finally, delete this strip */
727 free_nlastrip(&nlt->strips, strip);
733 BLI_freelistN(&anim_data);
735 /* refresh auto strip properties */
736 ED_nla_postop_refresh(&ac);
738 /* set notifier that things have changed */
739 WM_event_add_notifier(C, NC_ANIMATION|ND_NLA_EDIT, NULL);
742 return OPERATOR_FINISHED;
745 void NLA_OT_delete (wmOperatorType *ot)
748 ot->name= "Delete Strips";
749 ot->idname= "NLA_OT_delete";
750 ot->description= "Delete selected strips";
753 ot->exec= nlaedit_delete_exec;
754 ot->poll= nlaop_poll_tweakmode_off;
757 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
760 /* ******************** Split Strips Operator ***************************** */
761 /* Splits the selected NLA-Strips into two strips at the midpoint of the strip */
764 // - variable-length splits?
766 /* split a given Action-Clip strip */
767 static void nlaedit_split_strip_actclip (AnimData *adt, NlaTrack *nlt, NlaStrip *strip, float cfra)
770 float splitframe, splitaframe;
772 /* calculate the frames to do the splitting at
773 * - use current frame if within extents of strip
775 if ((cfra > strip->start) && (cfra < strip->end)) {
776 /* use the current frame */
778 splitaframe= nlastrip_get_frame(strip, cfra, NLATIME_CONVERT_UNMAP);
781 /* split in the middle */
785 len= strip->end - strip->start;
786 if (IS_EQ(len, 0.0f))
789 splitframe= strip->start + (len / 2.0f);
792 len= strip->actend - strip->actstart;
793 if (IS_EQ(len, 0.0f))
794 splitaframe= strip->actend;
796 splitaframe= strip->actstart + (len / 2.0f);
799 /* make a copy (assume that this is possible) and append
800 * it immediately after the current strip
802 nstrip= copy_nlastrip(strip);
803 BLI_insertlinkafter(&nlt->strips, strip, nstrip);
805 /* set the endpoint of the first strip and the start of the new strip
806 * to the splitframe values calculated above
808 strip->end= splitframe;
809 nstrip->start= splitframe;
811 if ((splitaframe > strip->actstart) && (splitaframe < strip->actend)) {
812 /* only do this if we're splitting down the middle... */
813 strip->actend= splitaframe;
814 nstrip->actstart= splitaframe;
817 /* clear the active flag from the copy */
818 nstrip->flag &= ~NLASTRIP_FLAG_ACTIVE;
820 /* auto-name the new strip */
821 BKE_nlastrip_validate_name(adt, nstrip);
824 /* split a given Meta strip */
825 static void nlaedit_split_strip_meta (AnimData *adt, NlaTrack *nlt, NlaStrip *strip)
827 /* simply ungroup it for now... */
828 BKE_nlastrips_clear_metastrip(&nlt->strips, strip);
833 static int nlaedit_split_exec (bContext *C, wmOperator *op)
837 ListBase anim_data = {NULL, NULL};
841 /* get editor data */
842 if (ANIM_animdata_get_context(C, &ac) == 0)
843 return OPERATOR_CANCELLED;
845 /* get a list of editable tracks being shown in the NLA */
846 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_NLATRACKS | ANIMFILTER_FOREDIT);
847 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
849 /* for each NLA-Track, split all selected strips into two strips */
850 for (ale= anim_data.first; ale; ale= ale->next) {
851 NlaTrack *nlt= (NlaTrack *)ale->data;
852 AnimData *adt= ale->adt;
853 NlaStrip *strip, *next;
855 for (strip= nlt->strips.first; strip; strip= next) {
858 /* if selected, split the strip at its midpoint */
859 if (strip->flag & NLASTRIP_FLAG_SELECT) {
860 /* splitting method depends on the type of strip */
861 switch (strip->type) {
862 case NLASTRIP_TYPE_CLIP: /* action-clip */
863 nlaedit_split_strip_actclip(adt, nlt, strip, (float)ac.scene->r.cfra);
866 case NLASTRIP_TYPE_META: /* meta-strips need special handling */
867 nlaedit_split_strip_meta(adt, nlt, strip);
870 default: /* for things like Transitions, do not split! */
878 BLI_freelistN(&anim_data);
880 /* refresh auto strip properties */
881 ED_nla_postop_refresh(&ac);
883 /* set notifier that things have changed */
884 WM_event_add_notifier(C, NC_ANIMATION|ND_NLA_EDIT, NULL);
887 return OPERATOR_FINISHED;
890 void NLA_OT_split (wmOperatorType *ot)
893 ot->name= "Split Strips";
894 ot->idname= "NLA_OT_split";
895 ot->description= "Split selected strips at their midpoints";
898 ot->exec= nlaedit_split_exec;
899 ot->poll= nlaop_poll_tweakmode_off;
902 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
905 /* ******************** Bake Strips Operator ***************************** */
906 /* Bakes the NLA Strips for the active AnimData blocks */
908 static int nlaedit_bake_exec (bContext *C, wmOperator *op)
912 ListBase anim_data = {NULL, NULL};
916 /* get editor data */
917 if (ANIM_animdata_get_context(C, &ac) == 0)
918 return OPERATOR_CANCELLED;
920 /* get a list of the editable tracks being shown in the NLA */
921 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_ANIMDATA | ANIMFILTER_FOREDIT);
922 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
924 /* for each AnimData block, bake strips to animdata... */
925 for (ale= anim_data.first; ale; ale= ale->next) {
930 BLI_freelistN(&anim_data);
932 /* refresh auto strip properties */
933 ED_nla_postop_refresh(&ac);
935 /* set notifier that things have changed */
936 WM_event_add_notifier(C, NC_ANIMATION|ND_NLA_EDIT, NULL);
939 return OPERATOR_FINISHED;
942 void NLA_OT_bake (wmOperatorType *ot)
945 ot->name= "Bake Strips";
946 ot->idname= "NLA_OT_bake";
947 ot->description= "Bake all strips of selected AnimData blocks";
950 ot->exec= nlaedit_bake_exec;
951 ot->poll= nlaop_poll_tweakmode_off;
954 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
957 /* *********************************************** */
958 /* NLA Editing Operations (Modifying) */
960 /* ******************** Toggle Muting Operator ************************** */
961 /* Toggles whether strips are muted or not */
963 static int nlaedit_toggle_mute_exec (bContext *C, wmOperator *op)
967 ListBase anim_data = {NULL, NULL};
971 /* get editor data */
972 if (ANIM_animdata_get_context(C, &ac) == 0)
973 return OPERATOR_CANCELLED;
975 /* get a list of the editable tracks being shown in the NLA */
976 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_NLATRACKS | ANIMFILTER_FOREDIT);
977 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
979 /* go over all selected strips */
980 for (ale= anim_data.first; ale; ale= ale->next) {
981 NlaTrack *nlt= (NlaTrack *)ale->data;
984 /* for every selected strip, toggle muting */
985 for (strip= nlt->strips.first; strip; strip= strip->next) {
986 if (strip->flag & NLASTRIP_FLAG_SELECT) {
987 /* just flip the mute flag for now */
988 // TODO: have a pre-pass to check if mute all or unmute all?
989 strip->flag ^= NLASTRIP_FLAG_MUTED;
995 BLI_freelistN(&anim_data);
997 /* set notifier that things have changed */
998 WM_event_add_notifier(C, NC_ANIMATION|ND_NLA_EDIT, NULL);
1001 return OPERATOR_FINISHED;
1004 void NLA_OT_mute_toggle (wmOperatorType *ot)
1007 ot->name= "Toggle Muting";
1008 ot->idname= "NLA_OT_mute_toggle";
1009 ot->description= "Mute or un-muted selected strips";
1012 ot->exec= nlaedit_toggle_mute_exec;
1013 ot->poll= nlaop_poll_tweakmode_off;
1016 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1019 /* ******************** Move Strips Up Operator ************************** */
1020 /* Tries to move the selected strips into the track above if possible. */
1022 static int nlaedit_move_up_exec (bContext *C, wmOperator *op)
1026 ListBase anim_data = {NULL, NULL};
1030 /* get editor data */
1031 if (ANIM_animdata_get_context(C, &ac) == 0)
1032 return OPERATOR_CANCELLED;
1034 /* get a list of the editable tracks being shown in the NLA */
1035 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_NLATRACKS | ANIMFILTER_FOREDIT);
1036 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
1038 /* since we're potentially moving strips from lower tracks to higher tracks, we should
1039 * loop over the tracks in reverse order to avoid moving earlier strips up multiple tracks
1041 for (ale= anim_data.last; ale; ale= ale->prev) {
1042 NlaTrack *nlt= (NlaTrack *)ale->data;
1043 NlaTrack *nltn= nlt->next;
1044 NlaStrip *strip, *stripn;
1046 /* if this track has no tracks after it, skip for now... */
1050 /* for every selected strip, try to move */
1051 for (strip= nlt->strips.first; strip; strip= stripn) {
1052 stripn= strip->next;
1054 if (strip->flag & NLASTRIP_FLAG_SELECT) {
1055 /* check if the track above has room for this strip */
1056 if (BKE_nlatrack_has_space(nltn, strip->start, strip->end)) {
1057 /* remove from its current track, and add to the one above (it 'should' work, so no need to worry) */
1058 BLI_remlink(&nlt->strips, strip);
1059 BKE_nlatrack_add_strip(nltn, strip);
1065 /* free temp data */
1066 BLI_freelistN(&anim_data);
1068 /* refresh auto strip properties */
1069 ED_nla_postop_refresh(&ac);
1071 /* set notifier that things have changed */
1072 WM_event_add_notifier(C, NC_ANIMATION|ND_NLA_EDIT, NULL);
1075 return OPERATOR_FINISHED;
1078 void NLA_OT_move_up (wmOperatorType *ot)
1081 ot->name= "Move Strips Up";
1082 ot->idname= "NLA_OT_move_up";
1083 ot->description= "Move selected strips up a track if there's room";
1086 ot->exec= nlaedit_move_up_exec;
1087 ot->poll= nlaop_poll_tweakmode_off;
1090 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1093 /* ******************** Move Strips Down Operator ************************** */
1094 /* Tries to move the selected strips into the track above if possible. */
1096 static int nlaedit_move_down_exec (bContext *C, wmOperator *op)
1100 ListBase anim_data = {NULL, NULL};
1104 /* get editor data */
1105 if (ANIM_animdata_get_context(C, &ac) == 0)
1106 return OPERATOR_CANCELLED;
1108 /* get a list of the editable tracks being shown in the NLA */
1109 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_NLATRACKS | ANIMFILTER_FOREDIT);
1110 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
1112 /* loop through the tracks in normal order, since we're pushing strips down,
1113 * strips won't get operated on twice
1115 for (ale= anim_data.first; ale; ale= ale->next) {
1116 NlaTrack *nlt= (NlaTrack *)ale->data;
1117 NlaTrack *nltp= nlt->prev;
1118 NlaStrip *strip, *stripn;
1120 /* if this track has no tracks before it, skip for now... */
1124 /* for every selected strip, try to move */
1125 for (strip= nlt->strips.first; strip; strip= stripn) {
1126 stripn= strip->next;
1128 if (strip->flag & NLASTRIP_FLAG_SELECT) {
1129 /* check if the track below has room for this strip */
1130 if (BKE_nlatrack_has_space(nltp, strip->start, strip->end)) {
1131 /* remove from its current track, and add to the one above (it 'should' work, so no need to worry) */
1132 BLI_remlink(&nlt->strips, strip);
1133 BKE_nlatrack_add_strip(nltp, strip);
1139 /* free temp data */
1140 BLI_freelistN(&anim_data);
1142 /* refresh auto strip properties */
1143 ED_nla_postop_refresh(&ac);
1145 /* set notifier that things have changed */
1146 WM_event_add_notifier(C, NC_ANIMATION|ND_NLA_EDIT, NULL);
1149 return OPERATOR_FINISHED;
1152 void NLA_OT_move_down (wmOperatorType *ot)
1155 ot->name= "Move Strips Down";
1156 ot->idname= "NLA_OT_move_down";
1157 ot->description= "Move selected strips down a track if there's room";
1160 ot->exec= nlaedit_move_down_exec;
1161 ot->poll= nlaop_poll_tweakmode_off;
1164 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1167 /* ******************** Sync Action Length Operator ***************************** */
1168 /* Recalculate the extents of the action ranges used for the selected strips */
1170 static int nlaedit_sync_actlen_exec (bContext *C, wmOperator *op)
1174 ListBase anim_data = {NULL, NULL};
1177 short active_only= RNA_boolean_get(op->ptr, "active");
1179 /* get editor data */
1180 if (ANIM_animdata_get_context(C, &ac) == 0)
1181 return OPERATOR_CANCELLED;
1183 /* get a list of the editable tracks being shown in the NLA */
1184 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_NLATRACKS | ANIMFILTER_FOREDIT);
1185 if (active_only) filter |= ANIMFILTER_ACTIVE;
1186 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
1188 /* for each NLA-Track, apply scale of all selected strips */
1189 for (ale= anim_data.first; ale; ale= ale->next) {
1190 NlaTrack *nlt= (NlaTrack *)ale->data;
1193 for (strip= nlt->strips.first; strip; strip= strip->next) {
1194 /* strip selection/active status check */
1196 if ((strip->flag & NLASTRIP_FLAG_ACTIVE) == 0)
1200 if ((strip->flag & NLASTRIP_FLAG_SELECT) == 0)
1204 /* must be action-clip only (transitions don't have scale) */
1205 if (strip->type == NLASTRIP_TYPE_CLIP) {
1206 if (strip->act == NULL)
1209 /* recalculate the length of the action */
1210 calc_action_range(strip->act, &strip->actstart, &strip->actend, 0);
1212 /* adjust the strip extents in response to this */
1213 BKE_nlastrip_recalculate_bounds(strip);
1218 /* free temp data */
1219 BLI_freelistN(&anim_data);
1221 /* set notifier that things have changed */
1222 WM_event_add_notifier(C, NC_ANIMATION|ND_NLA_EDIT, NULL);
1225 return OPERATOR_FINISHED;
1228 void NLA_OT_action_sync_length (wmOperatorType *ot)
1231 ot->name= "Sync Action Length";
1232 ot->idname= "NLA_OT_action_sync_length";
1233 ot->description= "Sychronise the length of the referenced Action with the lengths used in the strip";
1236 ot->exec= nlaedit_sync_actlen_exec;
1237 ot->poll= ED_operator_nla_active; // XXX: is this satisfactory... probably requires a check for active strip...
1240 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1243 ot->prop= RNA_def_boolean(ot->srna, "active", 1, "Active Strip Only", "Only sync the active length for the active strip.");
1246 /* ******************** Apply Scale Operator ***************************** */
1247 /* Reset the scaling of the selected strips to 1.0f */
1249 /* apply scaling to keyframe */
1250 static short bezt_apply_nlamapping (BeztEditData *bed, BezTriple *bezt)
1252 /* NLA-strip which has this scaling is stored in bed->data */
1253 NlaStrip *strip= (NlaStrip *)bed->data;
1255 /* adjust all the times */
1256 bezt->vec[0][0]= nlastrip_get_frame(strip, bezt->vec[0][0], NLATIME_CONVERT_MAP);
1257 bezt->vec[1][0]= nlastrip_get_frame(strip, bezt->vec[1][0], NLATIME_CONVERT_MAP);
1258 bezt->vec[2][0]= nlastrip_get_frame(strip, bezt->vec[2][0], NLATIME_CONVERT_MAP);
1260 /* nothing to return or else we exit */
1264 static int nlaedit_apply_scale_exec (bContext *C, wmOperator *op)
1268 ListBase anim_data = {NULL, NULL};
1274 /* get editor data */
1275 if (ANIM_animdata_get_context(C, &ac) == 0)
1276 return OPERATOR_CANCELLED;
1278 /* get a list of the editable tracks being shown in the NLA */
1279 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_NLATRACKS | ANIMFILTER_FOREDIT);
1280 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
1282 /* init the editing data */
1283 memset(&bed, 0, sizeof(BeztEditData));
1285 /* for each NLA-Track, apply scale of all selected strips */
1286 for (ale= anim_data.first; ale; ale= ale->next) {
1287 NlaTrack *nlt= (NlaTrack *)ale->data;
1290 for (strip= nlt->strips.first; strip; strip= strip->next) {
1291 /* strip must be selected, and must be action-clip only (transitions don't have scale) */
1292 if ((strip->flag & NLASTRIP_FLAG_SELECT) && (strip->type == NLASTRIP_TYPE_CLIP)) {
1293 /* if the referenced action is used by other strips, make this strip use its own copy */
1294 if (strip->act == NULL)
1296 if (strip->act->id.us > 1) {
1297 /* make a copy of the Action to work on */
1298 bAction *act= copy_action(strip->act);
1300 /* set this as the new referenced action, decrementing the users of the old one */
1301 strip->act->id.us--;
1305 /* setup iterator, and iterate over all the keyframes in the action, applying this scaling */
1307 ANIM_animchanneldata_keys_bezier_loop(&bed, strip->act, ALE_ACT, NULL, bezt_apply_nlamapping, calchandles_fcurve, 0);
1309 /* clear scale of strip now that it has been applied,
1310 * and recalculate the extents of the action now that it has been scaled
1311 * but leave everything else alone
1314 calc_action_range(strip->act, &strip->actstart, &strip->actend, 0);
1319 /* free temp data */
1320 BLI_freelistN(&anim_data);
1322 /* set notifier that things have changed */
1323 WM_event_add_notifier(C, NC_ANIMATION|ND_NLA_EDIT, NULL);
1326 return OPERATOR_FINISHED;
1329 void NLA_OT_apply_scale (wmOperatorType *ot)
1332 ot->name= "Apply Scale";
1333 ot->idname= "NLA_OT_apply_scale";
1334 ot->description= "Apply scaling of selected strips to their referenced Actions";
1337 ot->exec= nlaedit_apply_scale_exec;
1338 ot->poll= nlaop_poll_tweakmode_off;
1341 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1344 /* ******************** Clear Scale Operator ***************************** */
1345 /* Reset the scaling of the selected strips to 1.0f */
1347 static int nlaedit_clear_scale_exec (bContext *C, wmOperator *op)
1351 ListBase anim_data = {NULL, NULL};
1355 /* get editor data */
1356 if (ANIM_animdata_get_context(C, &ac) == 0)
1357 return OPERATOR_CANCELLED;
1359 /* get a list of the editable tracks being shown in the NLA */
1360 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_NLATRACKS | ANIMFILTER_FOREDIT);
1361 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
1363 /* for each NLA-Track, reset scale of all selected strips */
1364 for (ale= anim_data.first; ale; ale= ale->next) {
1365 NlaTrack *nlt= (NlaTrack *)ale->data;
1368 for (strip= nlt->strips.first; strip; strip= strip->next) {
1369 /* strip must be selected, and must be action-clip only (transitions don't have scale) */
1370 if ((strip->flag & NLASTRIP_FLAG_SELECT) && (strip->type == NLASTRIP_TYPE_CLIP)) {
1371 PointerRNA strip_ptr;
1373 RNA_pointer_create(NULL, &RNA_NlaStrip, strip, &strip_ptr);
1374 RNA_float_set(&strip_ptr, "scale", 1.0f);
1379 /* free temp data */
1380 BLI_freelistN(&anim_data);
1382 /* refresh auto strip properties */
1383 ED_nla_postop_refresh(&ac);
1385 /* set notifier that things have changed */
1386 WM_event_add_notifier(C, NC_ANIMATION|ND_NLA_EDIT, NULL);
1389 return OPERATOR_FINISHED;
1392 void NLA_OT_clear_scale (wmOperatorType *ot)
1395 ot->name= "Clear Scale";
1396 ot->idname= "NLA_OT_clear_scale";
1397 ot->description= "Reset scaling of selected strips";
1400 ot->exec= nlaedit_clear_scale_exec;
1401 ot->poll= nlaop_poll_tweakmode_off;
1404 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1407 /* ******************** Snap Strips Operator ************************** */
1408 /* Moves the start-point of the selected strips to the specified places */
1410 /* defines for snap keyframes tool */
1411 EnumPropertyItem prop_nlaedit_snap_types[] = {
1412 {NLAEDIT_SNAP_CFRA, "CFRA", 0, "Current frame", ""},
1413 {NLAEDIT_SNAP_NEAREST_FRAME, "NEAREST_FRAME", 0, "Nearest Frame", ""}, // XXX as single entry?
1414 {NLAEDIT_SNAP_NEAREST_SECOND, "NEAREST_SECOND", 0, "Nearest Second", ""}, // XXX as single entry?
1415 {NLAEDIT_SNAP_NEAREST_MARKER, "NEAREST_MARKER", 0, "Nearest Marker", ""},
1416 {0, NULL, 0, NULL, NULL}
1419 static int nlaedit_snap_exec (bContext *C, wmOperator *op)
1423 ListBase anim_data = {NULL, NULL};
1428 int mode = RNA_enum_get(op->ptr, "type");
1431 /* get editor data */
1432 if (ANIM_animdata_get_context(C, &ac) == 0)
1433 return OPERATOR_CANCELLED;
1435 /* get a list of the editable tracks being shown in the NLA */
1436 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_NLATRACKS | ANIMFILTER_FOREDIT);
1437 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
1439 /* get some necessary vars */
1443 /* since we may add tracks, perform this in reverse order */
1444 for (ale= anim_data.last; ale; ale= ale->prev) {
1445 ListBase tmp_strips = {NULL, NULL};
1446 AnimData *adt= ale->adt;
1447 NlaTrack *nlt= (NlaTrack *)ale->data;
1448 NlaStrip *strip, *stripn;
1451 /* create meta-strips from the continuous chains of selected strips */
1452 BKE_nlastrips_make_metas(&nlt->strips, 1);
1454 /* apply the snapping to all the temp meta-strips, then put them in a separate list to be added
1455 * back to the original only if they still fit
1457 for (strip= nlt->strips.first; strip; strip= stripn) {
1458 stripn= strip->next;
1460 if (strip->flag & NLASTRIP_FLAG_TEMP_META) {
1463 /* get the existing end-points */
1464 start= strip->start;
1467 /* calculate new start position based on snapping mode */
1469 case NLAEDIT_SNAP_CFRA: /* to current frame */
1470 strip->start= (float)CFRA;
1472 case NLAEDIT_SNAP_NEAREST_FRAME: /* to nearest frame */
1473 strip->start= (float)(floor(start+0.5));
1475 case NLAEDIT_SNAP_NEAREST_SECOND: /* to nearest second */
1476 strip->start= ((float)floor(start/secf + 0.5f) * secf);
1478 case NLAEDIT_SNAP_NEAREST_MARKER: /* to nearest marker */
1479 strip->start= (float)ED_markers_find_nearest_marker_time(ac.markers, start);
1481 default: /* just in case... no snapping */
1482 strip->start= start;
1486 /* get new endpoint based on start-point (and old length) */
1487 strip->end= strip->start + (end - start);
1489 /* apply transforms to meta-strip to its children */
1490 BKE_nlameta_flush_transforms(strip);
1492 /* remove strip from track, and add to the temp buffer */
1493 BLI_remlink(&nlt->strips, strip);
1494 BLI_addtail(&tmp_strips, strip);
1498 /* try adding each meta-strip back to the track one at a time, to make sure they'll fit */
1499 for (strip= tmp_strips.first; strip; strip= stripn) {
1500 stripn= strip->next;
1502 /* remove from temp-strips list */
1503 BLI_remlink(&tmp_strips, strip);
1505 /* in case there's no space in the current track, try adding */
1506 if (BKE_nlatrack_add_strip(nlt, strip) == 0) {
1507 /* need to add a new track above the current one */
1508 track= add_nlatrack(adt, nlt);
1509 BKE_nlatrack_add_strip(track, strip);
1511 /* clear temp meta-strips on this new track, as we may not be able to get back to it */
1512 BKE_nlastrips_clear_metas(&track->strips, 0, 1);
1516 /* remove the meta-strips now that we're done */
1517 BKE_nlastrips_clear_metas(&nlt->strips, 0, 1);
1520 /* free temp data */
1521 BLI_freelistN(&anim_data);
1523 /* refresh auto strip properties */
1524 ED_nla_postop_refresh(&ac);
1526 /* set notifier that things have changed */
1527 WM_event_add_notifier(C, NC_ANIMATION|ND_NLA_EDIT, NULL);
1530 return OPERATOR_FINISHED;
1533 void NLA_OT_snap (wmOperatorType *ot)
1536 ot->name= "Snap Strips";
1537 ot->idname= "NLA_OT_snap";
1538 ot->description= "Move start of strips to specified time";
1541 ot->invoke= WM_menu_invoke;
1542 ot->exec= nlaedit_snap_exec;
1543 ot->poll= nlaop_poll_tweakmode_off;
1546 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1549 ot->prop= RNA_def_enum(ot->srna, "type", prop_nlaedit_snap_types, 0, "Type", "");
1552 /* *********************************************** */
1555 /* ******************** Add F-Modifier Operator *********************** */
1557 /* present a special customised popup menu for this, with some filtering */
1558 static int nla_fmodifier_add_invoke (bContext *C, wmOperator *op, wmEvent *event)
1564 pup= uiPupMenuBegin(C, "Add F-Modifier", 0);
1565 layout= uiPupMenuLayout(pup);
1567 /* start from 1 to skip the 'Invalid' modifier type */
1568 for (i = 1; i < FMODIFIER_NUM_TYPES; i++) {
1569 FModifierTypeInfo *fmi= get_fmodifier_typeinfo(i);
1571 /* check if modifier is valid for this context */
1574 if (i == FMODIFIER_TYPE_CYCLES) /* we already have repeat... */
1577 /* add entry to add this type of modifier */
1578 uiItemEnumO(layout, fmi->name, 0, "NLA_OT_fmodifier_add", "type", i);
1582 uiPupMenuEnd(C, pup);
1584 return OPERATOR_CANCELLED;
1587 static int nla_fmodifier_add_exec(bContext *C, wmOperator *op)
1591 ListBase anim_data = {NULL, NULL};
1596 int type= RNA_enum_get(op->ptr, "type");
1597 short onlyActive = RNA_boolean_get(op->ptr, "only_active");
1599 /* get editor data */
1600 if (ANIM_animdata_get_context(C, &ac) == 0)
1601 return OPERATOR_CANCELLED;
1603 /* get a list of the editable tracks being shown in the NLA */
1604 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_NLATRACKS | ANIMFILTER_FOREDIT);
1605 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
1607 /* for each NLA-Track, add the specified modifier to all selected strips */
1608 for (ale= anim_data.first; ale; ale= ale->next) {
1609 NlaTrack *nlt= (NlaTrack *)ale->data;
1613 for (strip= nlt->strips.first; strip; strip=strip->next, i++) {
1614 /* only add F-Modifier if on active strip? */
1615 if ((onlyActive) && (strip->flag & NLASTRIP_FLAG_ACTIVE)==0)
1618 /* add F-Modifier of specified type to selected, and make it the active one */
1619 fcm= add_fmodifier(&strip->modifiers, type);
1622 set_active_fmodifier(&strip->modifiers, fcm);
1625 sprintf(errormsg, "Modifier couldn't be added to (%s : %d). See console for details.", nlt->name, i);
1627 BKE_report(op->reports, RPT_ERROR, errormsg);
1632 /* free temp data */
1633 BLI_freelistN(&anim_data);
1635 /* set notifier that things have changed */
1636 WM_event_add_notifier(C, NC_ANIMATION|ND_NLA_EDIT, NULL);
1639 return OPERATOR_FINISHED;
1642 void NLA_OT_fmodifier_add (wmOperatorType *ot)
1645 ot->name= "Add F-Modifier";
1646 ot->idname= "NLA_OT_fmodifier_add";
1649 ot->invoke= nla_fmodifier_add_invoke;
1650 ot->exec= nla_fmodifier_add_exec;
1651 ot->poll= nlaop_poll_tweakmode_off;
1654 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1657 ot->prop= RNA_def_enum(ot->srna, "type", fmodifier_type_items, 0, "Type", "");
1658 RNA_def_boolean(ot->srna, "only_active", 0, "Only Active", "Only add F-Modifier of the specified type to the active strip.");
1661 /* ******************** Copy F-Modifiers Operator *********************** */
1663 static int nla_fmodifier_copy_exec(bContext *C, wmOperator *op)
1666 ListBase anim_data = {NULL, NULL};
1670 /* get editor data */
1671 if (ANIM_animdata_get_context(C, &ac) == 0)
1672 return OPERATOR_CANCELLED;
1674 /* clear buffer first */
1675 free_fmodifiers_copybuf();
1677 /* get a list of the editable tracks being shown in the NLA */
1678 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_NLATRACKS | ANIMFILTER_FOREDIT);
1679 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
1681 /* for each NLA-Track, add the specified modifier to all selected strips */
1682 for (ale= anim_data.first; ale; ale= ale->next) {
1683 NlaTrack *nlt= (NlaTrack *)ale->data;
1686 for (strip= nlt->strips.first; strip; strip=strip->next) {
1687 /* only add F-Modifier if on active strip? */
1688 if ((strip->flag & NLASTRIP_FLAG_ACTIVE)==0)
1691 // TODO: when 'active' vs 'all' boolean is added, change last param!
1692 ok += ANIM_fmodifiers_copy_to_buf(&strip->modifiers, 0);
1696 /* successful or not? */
1698 BKE_report(op->reports, RPT_ERROR, "No F-Modifiers available to be copied");
1699 return OPERATOR_CANCELLED;
1702 return OPERATOR_FINISHED;
1705 void NLA_OT_fmodifier_copy (wmOperatorType *ot)
1708 ot->name= "Copy F-Modifiers";
1709 ot->idname= "NLA_OT_fmodifier_copy";
1710 ot->description= "Copy the F-Modifier(s) of the active NLA-Strip.";
1713 ot->exec= nla_fmodifier_copy_exec;
1714 ot->poll= nlaop_poll_tweakmode_off;
1717 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1720 //ot->prop = RNA_def_boolean(ot->srna, "all", 1, "All F-Modifiers", "Copy all the F-Modifiers, instead of just the active one");
1723 /* ******************** Paste F-Modifiers Operator *********************** */
1725 static int nla_fmodifier_paste_exec(bContext *C, wmOperator *op)
1728 ListBase anim_data = {NULL, NULL};
1732 /* get editor data */
1733 if (ANIM_animdata_get_context(C, &ac) == 0)
1734 return OPERATOR_CANCELLED;
1736 /* get a list of the editable tracks being shown in the NLA */
1737 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_NLATRACKS | ANIMFILTER_SEL | ANIMFILTER_FOREDIT);
1738 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
1740 /* for each NLA-Track, add the specified modifier to all selected strips */
1741 for (ale= anim_data.first; ale; ale= ale->next) {
1742 NlaTrack *nlt= (NlaTrack *)ale->data;
1745 for (strip= nlt->strips.first; strip; strip=strip->next) {
1746 // TODO: do we want to replace existing modifiers? add user pref for that!
1747 ok += ANIM_fmodifiers_paste_from_buf(&strip->modifiers, 0);
1752 BLI_freelistN(&anim_data);
1754 /* successful or not? */
1756 /* set notifier that things have changed */
1757 /* set notifier that things have changed */
1758 WM_event_add_notifier(C, NC_ANIMATION|ND_NLA_EDIT, NULL);
1759 return OPERATOR_FINISHED;
1762 BKE_report(op->reports, RPT_ERROR, "No F-Modifiers to paste");
1763 return OPERATOR_CANCELLED;
1767 void NLA_OT_fmodifier_paste (wmOperatorType *ot)
1770 ot->name= "Paste F-Modifiers";
1771 ot->idname= "NLA_OT_fmodifier_paste";
1772 ot->description= "Add copied F-Modifiers to the selected NLA-Strips";
1775 ot->exec= nla_fmodifier_paste_exec;
1776 ot->poll= nlaop_poll_tweakmode_off;
1779 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1782 /* *********************************************** */