Merging with trunk up to r38631.
[blender.git] / source / blender / editors / space_nla / nla_edit.c
1 /*
2  * $Id$
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
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. 
10  *
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.
15  *
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.
19  *
20  * The Original Code is Copyright (C) 2009 Blender Foundation, Joshua Leung
21  * All rights reserved.
22  *
23  * 
24  * Contributor(s): Joshua Leung (major recode)
25  *
26  * ***** END GPL LICENSE BLOCK *****
27  */
28
29 /** \file blender/editors/space_nla/nla_edit.c
30  *  \ingroup spnla
31  */
32
33
34 #include <string.h>
35 #include <stdio.h>
36 #include <math.h>
37
38 #include "DNA_anim_types.h"
39 #include "DNA_scene_types.h"
40
41 #include "MEM_guardedalloc.h"
42
43 #include "BLI_blenlib.h"
44 #include "BLI_math.h"
45 #include "BLI_rand.h"
46 #include "BLI_utildefines.h"
47
48 #include "BKE_action.h"
49 #include "BKE_fcurve.h"
50 #include "BKE_nla.h"
51 #include "BKE_context.h"
52 #include "BKE_main.h"
53 #include "BKE_report.h"
54 #include "BKE_screen.h"
55
56 #include "ED_anim_api.h"
57 #include "ED_keyframes_edit.h"
58 #include "ED_markers.h"
59 #include "ED_screen.h"
60 #include "ED_transform.h"
61
62 #include "RNA_access.h"
63 #include "RNA_define.h"
64 #include "RNA_enum_types.h"
65
66 #include "WM_api.h"
67 #include "WM_types.h"
68
69 #include "UI_interface.h"
70 #include "UI_resources.h"
71 #include "UI_view2d.h"
72
73 #include "nla_intern.h" // own include
74 #include "nla_private.h" // FIXME... maybe this shouldn't be included?
75
76 /* *********************************************** */
77 /* Utilities exported to other places... */
78
79 /* Perform validation for blending/extend settings */
80 void ED_nla_postop_refresh (bAnimContext *ac)
81 {
82         ListBase anim_data = {NULL, NULL};
83         bAnimListElem *ale;
84         short filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_ANIMDATA | ANIMFILTER_FOREDIT);
85         
86         /* get blocks to work on */
87         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
88         
89         for (ale= anim_data.first; ale; ale= ale->next) {
90                 /* performing auto-blending, extend-mode validation, etc. */
91                 BKE_nla_validate_state(ale->data);
92         }
93         
94         /* free temp memory */
95         BLI_freelistN(&anim_data);
96 }
97
98 /* *********************************************** */
99 /* 'Special' Editing */
100
101 /* ******************** Tweak-Mode Operators ***************************** */
102 /* 'Tweak mode' allows the action referenced by the active NLA-strip to be edited 
103  * as if it were the normal Active-Action of its AnimData block. 
104  */
105
106 static int nlaedit_enable_tweakmode_exec (bContext *C, wmOperator *op)
107 {
108         bAnimContext ac;
109         
110         ListBase anim_data = {NULL, NULL};
111         bAnimListElem *ale;
112         int filter;
113         int ok=0;
114         
115         /* get editor data */
116         if (ANIM_animdata_get_context(C, &ac) == 0)
117                 return OPERATOR_CANCELLED;
118                 
119         /* get a list of the AnimData blocks being shown in the NLA */
120         filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_ANIMDATA);
121         ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
122         
123         /* if no blocks, popup error? */
124         if (anim_data.first == NULL) {
125                 BKE_report(op->reports, RPT_ERROR, "No AnimData blocks to enter tweakmode for");
126                 return OPERATOR_CANCELLED;
127         }       
128         
129         /* for each AnimData block with NLA-data, try setting it in tweak-mode */
130         for (ale= anim_data.first; ale; ale= ale->next) {
131                 AnimData *adt= ale->data;
132                 
133                 /* try entering tweakmode if valid */
134                 ok += BKE_nla_tweakmode_enter(adt);
135         }
136         
137         /* free temp data */
138         BLI_freelistN(&anim_data);
139         
140         /* if we managed to enter tweakmode on at least one AnimData block, 
141          * set the flag for this in the active scene and send notifiers
142          */
143         if (ac.scene && ok) {
144                 /* set editing flag */
145                 ac.scene->flag |= SCE_NLA_EDIT_ON;
146                 
147                 /* set notifier that things have changed */
148                 WM_event_add_notifier(C, NC_ANIMATION|ND_NLA_ACTCHANGE, NULL);
149         }
150         else {
151                 BKE_report(op->reports, RPT_ERROR, "No active strip(s) to enter tweakmode on.");
152                 return OPERATOR_CANCELLED;
153         }
154         
155         /* done */
156         return OPERATOR_FINISHED;
157 }
158  
159 void NLA_OT_tweakmode_enter (wmOperatorType *ot)
160 {
161         /* identifiers */
162         ot->name= "Enter Tweak Mode";
163         ot->idname= "NLA_OT_tweakmode_enter";
164         ot->description= "Enter tweaking mode for the action referenced by the active strip";
165         
166         /* api callbacks */
167         ot->exec= nlaedit_enable_tweakmode_exec;
168         ot->poll= nlaop_poll_tweakmode_off;
169         
170         /* flags */
171         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
172 }
173
174 /* ------------- */
175
176 static int nlaedit_disable_tweakmode_exec (bContext *C, wmOperator *op)
177 {
178         bAnimContext ac;
179         
180         ListBase anim_data = {NULL, NULL};
181         bAnimListElem *ale;
182         int filter;
183         
184         /* get editor data */
185         if (ANIM_animdata_get_context(C, &ac) == 0)
186                 return OPERATOR_CANCELLED;
187                 
188         /* get a list of the AnimData blocks being shown in the NLA */
189         filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_ANIMDATA);
190         ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
191         
192         /* if no blocks, popup error? */
193         if (anim_data.first == NULL) {
194                 BKE_report(op->reports, RPT_ERROR, "No AnimData blocks to enter tweakmode for");
195                 return OPERATOR_CANCELLED;
196         }       
197         
198         /* for each AnimData block with NLA-data, try exitting tweak-mode */
199         for (ale= anim_data.first; ale; ale= ale->next) {
200                 AnimData *adt= ale->data;
201                 
202                 /* try entering tweakmode if valid */
203                 BKE_nla_tweakmode_exit(adt);
204         }
205         
206         /* free temp data */
207         BLI_freelistN(&anim_data);
208         
209         /* if we managed to enter tweakmode on at least one AnimData block, 
210          * set the flag for this in the active scene and send notifiers
211          */
212         if (ac.scene) {
213                 /* clear editing flag */
214                 ac.scene->flag &= ~SCE_NLA_EDIT_ON;
215                 
216                 /* set notifier that things have changed */
217                 WM_event_add_notifier(C, NC_ANIMATION|ND_NLA_ACTCHANGE, NULL);
218         }
219         
220         /* done */
221         return OPERATOR_FINISHED;
222 }
223  
224 void NLA_OT_tweakmode_exit (wmOperatorType *ot)
225 {
226         /* identifiers */
227         ot->name= "Exit Tweak Mode";
228         ot->idname= "NLA_OT_tweakmode_exit";
229         ot->description= "Exit tweaking mode for the action referenced by the active strip";
230         
231         /* api callbacks */
232         ot->exec= nlaedit_disable_tweakmode_exec;
233         ot->poll= nlaop_poll_tweakmode_on;
234         
235         /* flags */
236         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
237 }
238
239 /* *********************************************** */
240 /* NLA Strips Range Stuff */
241
242 /* *************************** Calculate Range ************************** */
243
244 /* Get the min/max strip extents */
245 static void get_nlastrip_extents (bAnimContext *ac, float *min, float *max, const short onlySel)
246 {
247         ListBase anim_data = {NULL, NULL};
248         bAnimListElem *ale;
249         int filter;
250         
251         /* get data to filter */
252         filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_NODUPLIS);
253         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
254         
255         /* set large values to try to override */
256         *min= 999999999.0f;
257         *max= -999999999.0f;
258         
259         /* check if any channels to set range with */
260         if (anim_data.first) {
261                 /* go through channels, finding max extents */
262                 for (ale= anim_data.first; ale; ale= ale->next) {
263                         NlaTrack *nlt = (NlaTrack *)ale->data;
264                         NlaStrip *strip;
265                         
266                         for (strip = nlt->strips.first; strip; strip = strip->next) {
267                                 /* only consider selected strips? */
268                                 if ((onlySel == 0) || (strip->flag & NLASTRIP_FLAG_SELECT)) {
269                                         /* extend range if appropriate */
270                                         *min = MIN2(*min, strip->start);
271                                         *max = MAX2(*max, strip->end);
272                                 }
273                         }
274                 }
275                 
276                 /* free memory */
277                 BLI_freelistN(&anim_data);
278         }
279         else {
280                 /* set default range */
281                 if (ac->scene) {
282                         *min= (float)ac->scene->r.sfra;
283                         *max= (float)ac->scene->r.efra;
284                 }
285                 else {
286                         *min= -5;
287                         *max= 100;
288                 }
289         }
290 }
291
292 /* ****************** View-All Operator ****************** */
293
294 static int nlaedit_viewall(bContext *C, const short onlySel)
295 {
296         bAnimContext ac;
297         View2D *v2d;
298         float extra;
299         
300         /* get editor data */
301         if (ANIM_animdata_get_context(C, &ac) == 0)
302                 return OPERATOR_CANCELLED;
303         v2d= &ac.ar->v2d;
304         
305         /* set the horizontal range, with an extra offset so that the extreme keys will be in view */
306         get_nlastrip_extents(&ac, &v2d->cur.xmin, &v2d->cur.xmax, onlySel);
307         
308         extra= 0.1f * (v2d->cur.xmax - v2d->cur.xmin);
309         v2d->cur.xmin -= extra;
310         v2d->cur.xmax += extra;
311         
312         /* set vertical range */
313         v2d->cur.ymax= 0.0f;
314         v2d->cur.ymin= (float)-(v2d->mask.ymax - v2d->mask.ymin);
315         
316         /* do View2D syncing */
317         UI_view2d_sync(CTX_wm_screen(C), CTX_wm_area(C), v2d, V2D_LOCK_COPY);
318         
319         /* just redraw this view */
320         ED_area_tag_redraw(CTX_wm_area(C));
321         
322         return OPERATOR_FINISHED;
323 }
324
325 /* ......... */
326
327 static int nlaedit_viewall_exec(bContext *C, wmOperator *UNUSED(op))
328 {       
329         /* whole range */
330         return nlaedit_viewall(C, FALSE);
331 }
332
333 static int nlaedit_viewsel_exec(bContext *C, wmOperator *UNUSED(op))
334 {
335         /* only selected */
336         return nlaedit_viewall(C, TRUE);
337 }
338  
339 void NLA_OT_view_all (wmOperatorType *ot)
340 {
341         /* identifiers */
342         ot->name= "View All";
343         ot->idname= "NLA_OT_view_all";
344         ot->description= "Reset viewable area to show full strips range";
345         
346         /* api callbacks */
347         ot->exec= nlaedit_viewall_exec;
348         ot->poll= ED_operator_nla_active;
349         
350         /* flags */
351         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
352 }
353
354 void NLA_OT_view_selected (wmOperatorType *ot)
355 {
356         /* identifiers */
357         ot->name= "View Selected";
358         ot->idname= "NLA_OT_view_selected";
359         ot->description= "Reset viewable area to show selected strips range";
360         
361         /* api callbacks */
362         ot->exec= nlaedit_viewsel_exec;
363         ot->poll= ED_operator_nla_active;
364         
365         /* flags */
366         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
367 }
368
369 /* *********************************************** */
370 /* NLA Editing Operations (Constructive/Destructive) */
371
372 /* ******************** Add Action-Clip Operator ***************************** */
373 /* Add a new Action-Clip strip to the active track (or the active block if no space in the track) */
374
375
376 /* add the specified action as new strip */
377 static int nlaedit_add_actionclip_exec (bContext *C, wmOperator *op)
378 {
379         bAnimContext ac;
380         Scene *scene;
381         
382         ListBase anim_data = {NULL, NULL};
383         bAnimListElem *ale;
384         size_t items;
385         int filter;
386
387         bAction *act;
388
389         float cfra;
390         
391         /* get editor data */
392         if (ANIM_animdata_get_context(C, &ac) == 0)
393                 return OPERATOR_CANCELLED;
394                 
395         scene= ac.scene;
396         cfra= (float)CFRA;
397                 
398         /* get action to use */
399         act= BLI_findlink(&CTX_data_main(C)->action, RNA_enum_get(op->ptr, "action"));
400         
401         if (act == NULL) {
402                 BKE_report(op->reports, RPT_ERROR, "No valid Action to add.");
403                 //printf("Add strip - actname = '%s' \n", actname);
404                 return OPERATOR_CANCELLED;
405         }
406         else if (act->idroot == 0) {
407                 /* hopefully in this case (i.e. library of userless actions), the user knows what they're doing... */
408                 BKE_reportf(op->reports, RPT_WARNING,
409                         "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",
410                         act->id.name+2);
411         }
412         
413         /* get a list of the editable tracks being shown in the NLA
414          *      - this is limited to active ones for now, but could be expanded to 
415          */
416         filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_ACTIVE | ANIMFILTER_FOREDIT);
417         items= ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
418         
419         if (items == 0) {
420                 BKE_report(op->reports, RPT_ERROR, "No active track(s) to add strip to.");
421                 return OPERATOR_CANCELLED;
422         }
423         
424         /* for every active track, try to add strip to free space in track or to the top of the stack if no space */
425         for (ale= anim_data.first; ale; ale= ale->next) {
426                 NlaTrack *nlt= (NlaTrack *)ale->data;
427                 AnimData *adt= ale->adt;
428                 NlaStrip *strip= NULL;
429                 
430                 /* sanity check: only apply actions of the right type for this ID 
431                  * NOTE: in the case that this hasn't been set, we've already warned the user about this already
432                  */
433                 if ((act->idroot) && (act->idroot != GS(ale->id->name))) {
434                         BKE_reportf(op->reports, RPT_ERROR, 
435                                 "Couldn't add action '%s' as it cannot be used relative to ID-blocks of type '%s'",
436                                 act->id.name+2, ale->id->name);
437                         continue;
438                 }
439                 
440                 /* create a new strip, and offset it to start on the current frame */
441                 strip= add_nlastrip(act);
442                 
443                 strip->end              += (cfra - strip->start);
444                 strip->start     = cfra;
445                 
446                 /* firstly try adding strip to our current track, but if that fails, add to a new track */
447                 if (BKE_nlatrack_add_strip(nlt, strip) == 0) {
448                         /* trying to add to the current failed (no space), 
449                          * so add a new track to the stack, and add to that...
450                          */
451                         nlt= add_nlatrack(adt, NULL);
452                         BKE_nlatrack_add_strip(nlt, strip);
453                 }
454                 
455                 /* auto-name it */
456                 BKE_nlastrip_validate_name(adt, strip);
457         }
458         
459         /* free temp data */
460         BLI_freelistN(&anim_data);
461         
462         /* refresh auto strip properties */
463         ED_nla_postop_refresh(&ac);
464         
465         /* set notifier that things have changed */
466         WM_event_add_notifier(C, NC_ANIMATION|ND_NLA|NA_EDITED, NULL);
467         
468         /* done */
469         return OPERATOR_FINISHED;
470 }
471
472 void NLA_OT_actionclip_add (wmOperatorType *ot)
473 {
474         PropertyRNA *prop;
475
476         /* identifiers */
477         ot->name= "Add Action Strip";
478         ot->idname= "NLA_OT_actionclip_add";
479         ot->description= "Add an Action-Clip strip (i.e. an NLA Strip referencing an Action) to the active track";
480         
481         /* api callbacks */
482         ot->invoke= WM_enum_search_invoke;
483         ot->exec= nlaedit_add_actionclip_exec;
484         ot->poll= nlaop_poll_tweakmode_off;
485         
486         /* flags */
487         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
488         
489         /* props */
490                 // TODO: this would be nicer as an ID-pointer...
491         prop= RNA_def_enum(ot->srna, "action", DummyRNA_NULL_items, 0, "Action", "");
492         RNA_def_enum_funcs(prop, RNA_action_itemf);
493         ot->prop= prop;
494 }
495
496 /* ******************** Add Transition Operator ***************************** */
497 /* Add a new transition strip between selected strips */
498
499 static int nlaedit_add_transition_exec (bContext *C, wmOperator *op)
500 {
501         bAnimContext ac;
502         
503         ListBase anim_data = {NULL, NULL};
504         bAnimListElem *ale;
505         int filter;
506         
507         int done = 0;
508         
509         /* get editor data */
510         if (ANIM_animdata_get_context(C, &ac) == 0)
511                 return OPERATOR_CANCELLED;
512         
513         /* get a list of the editable tracks being shown in the NLA */
514         filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
515         ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
516         
517         /* for each track, find pairs of strips to add transitions to */
518         for (ale= anim_data.first; ale; ale= ale->next) {
519                 NlaTrack *nlt= (NlaTrack *)ale->data;
520                 AnimData *adt= ale->adt;
521                 NlaStrip *s1, *s2;
522                 
523                 /* get initial pair of strips */
524                 if ELEM(nlt->strips.first, NULL, nlt->strips.last)
525                         continue;
526                 s1= nlt->strips.first;
527                 s2= s1->next;
528                 
529                 /* loop over strips */
530                 for (; s1 && s2; s1=s2, s2=s2->next) {
531                         NlaStrip *strip;
532                         
533                         /* check if both are selected */
534                         if ELEM(0, (s1->flag & NLASTRIP_FLAG_SELECT), (s2->flag & NLASTRIP_FLAG_SELECT))
535                                 continue;
536                         /* check if there's space between the two */
537                         if (IS_EQ(s1->end, s2->start))
538                                 continue;
539                         /* make neither one is a transition 
540                          *      - although this is impossible to create with the standard tools, 
541                          *        the user may have altered the settings
542                          */
543                         if (ELEM(NLASTRIP_TYPE_TRANSITION, s1->type, s2->type))
544                                 continue;
545                                 
546                         /* allocate new strip */
547                         strip= MEM_callocN(sizeof(NlaStrip), "NlaStrip");
548                         BLI_insertlinkafter(&nlt->strips, s1, strip);
549                         
550                         /* set the type */
551                         strip->type= NLASTRIP_TYPE_TRANSITION;
552                         
553                         /* generic settings 
554                          *      - selected flag to highlight this to the user
555                          *      - auto-blends to ensure that blend in/out values are automatically 
556                          *        determined by overlaps of strips
557                          */
558                         strip->flag = NLASTRIP_FLAG_SELECT|NLASTRIP_FLAG_AUTO_BLENDS;
559                         
560                         /* range is simply defined as the endpoints of the adjacent strips */
561                         strip->start    = s1->end;
562                         strip->end              = s2->start;
563                         
564                         /* scale and repeat aren't of any use, but shouldn't ever be 0 */
565                         strip->scale= 1.0f;
566                         strip->repeat = 1.0f;
567                         
568                         /* auto-name it */
569                         BKE_nlastrip_validate_name(adt, strip);
570                         
571                         /* make note of this */
572                         done++;
573                 }
574         }
575         
576         /* free temp data */
577         BLI_freelistN(&anim_data);
578         
579         /* was anything added? */
580         if (done) {
581                 /* refresh auto strip properties */
582                 ED_nla_postop_refresh(&ac);
583                 
584                 /* set notifier that things have changed */
585                 WM_event_add_notifier(C, NC_ANIMATION|ND_NLA|NA_EDITED, NULL);
586                 
587                 /* done */
588                 return OPERATOR_FINISHED;
589         }
590         else {
591                 BKE_report(op->reports, RPT_ERROR, "Needs at least a pair of adjacent selected strips with a gap between them.");
592                 return OPERATOR_CANCELLED;
593         }
594 }
595
596 void NLA_OT_transition_add (wmOperatorType *ot)
597 {
598         /* identifiers */
599         ot->name= "Add Transition";
600         ot->idname= "NLA_OT_transition_add";
601         ot->description= "Add a transition strip between two adjacent selected strips";
602         
603         /* api callbacks */
604         ot->exec= nlaedit_add_transition_exec;
605         ot->poll= nlaop_poll_tweakmode_off;
606         
607         /* flags */
608         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
609 }
610
611 /* ******************** Add Meta-Strip Operator ***************************** */
612 /* Add new meta-strips incorporating the selected strips */
613
614 /* add the specified action as new strip */
615 static int nlaedit_add_meta_exec (bContext *C, wmOperator *UNUSED(op))
616 {
617         bAnimContext ac;
618         
619         ListBase anim_data = {NULL, NULL};
620         bAnimListElem *ale;
621         int filter;
622         
623         /* get editor data */
624         if (ANIM_animdata_get_context(C, &ac) == 0)
625                 return OPERATOR_CANCELLED;
626         
627         /* get a list of the editable tracks being shown in the NLA */
628         filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
629         ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
630         
631         /* for each track, find pairs of strips to add transitions to */
632         for (ale= anim_data.first; ale; ale= ale->next) {
633                 NlaTrack *nlt= (NlaTrack *)ale->data;
634                 AnimData *adt= ale->adt;
635                 NlaStrip *strip;
636                 
637                 /* create meta-strips from the continuous chains of selected strips */
638                 BKE_nlastrips_make_metas(&nlt->strips, 0);
639                 
640                 /* name the metas */
641                 for (strip= nlt->strips.first; strip; strip= strip->next) {
642                         /* auto-name this strip if selected (that means it is a meta) */
643                         if (strip->flag & NLASTRIP_FLAG_SELECT)
644                                 BKE_nlastrip_validate_name(adt, strip);
645                 }
646         }
647         
648         /* free temp data */
649         BLI_freelistN(&anim_data);
650         
651         /* set notifier that things have changed */
652         WM_event_add_notifier(C, NC_ANIMATION|ND_NLA|NA_EDITED, NULL);
653         
654         /* done */
655         return OPERATOR_FINISHED;
656 }
657
658 void NLA_OT_meta_add (wmOperatorType *ot)
659 {
660         /* identifiers */
661         ot->name= "Add Meta-Strips";
662         ot->idname= "NLA_OT_meta_add";
663         ot->description= "Add new meta-strips incorporating the selected strips";
664         
665         /* api callbacks */
666         ot->exec= nlaedit_add_meta_exec;
667         ot->poll= nlaop_poll_tweakmode_off;
668         
669         /* flags */
670         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
671 }
672
673 /* ******************** Remove Meta-Strip Operator ***************************** */
674 /* Separate out the strips held by the selected meta-strips */
675
676 static int nlaedit_remove_meta_exec (bContext *C, wmOperator *UNUSED(op))
677 {
678         bAnimContext ac;
679         
680         ListBase anim_data = {NULL, NULL};
681         bAnimListElem *ale;
682         int filter;
683         
684         /* get editor data */
685         if (ANIM_animdata_get_context(C, &ac) == 0)
686                 return OPERATOR_CANCELLED;
687         
688         /* get a list of the editable tracks being shown in the NLA */
689         filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
690         ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
691         
692         /* for each track, find pairs of strips to add transitions to */
693         for (ale= anim_data.first; ale; ale= ale->next) {
694                 NlaTrack *nlt= (NlaTrack *)ale->data;
695                 
696                 /* clear all selected meta-strips, regardless of whether they are temporary or not */
697                 BKE_nlastrips_clear_metas(&nlt->strips, 1, 0);
698         }
699         
700         /* free temp data */
701         BLI_freelistN(&anim_data);
702         
703         /* set notifier that things have changed */
704         WM_event_add_notifier(C, NC_ANIMATION|ND_NLA|NA_EDITED, NULL);
705         
706         /* done */
707         return OPERATOR_FINISHED;
708 }
709
710 void NLA_OT_meta_remove (wmOperatorType *ot)
711 {
712         /* identifiers */
713         ot->name= "Remove Meta-Strips";
714         ot->idname= "NLA_OT_meta_remove";
715         ot->description= "Separate out the strips held by the selected meta-strips";
716         
717         /* api callbacks */
718         ot->exec= nlaedit_remove_meta_exec;
719         ot->poll= nlaop_poll_tweakmode_off;
720         
721         /* flags */
722         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
723 }
724
725 /* ******************** Duplicate Strips Operator ************************** */
726 /* Duplicates the selected NLA-Strips, putting them on new tracks above the one
727  * the originals were housed in.
728  */
729  
730 static int nlaedit_duplicate_exec (bContext *C, wmOperator *UNUSED(op))
731 {
732         bAnimContext ac;
733         
734         ListBase anim_data = {NULL, NULL};
735         bAnimListElem *ale;
736         int filter;
737         
738         short done = 0;
739         
740         /* get editor data */
741         if (ANIM_animdata_get_context(C, &ac) == 0)
742                 return OPERATOR_CANCELLED;
743                 
744         /* get a list of editable tracks being shown in the NLA */
745         filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
746         ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
747         
748         /* duplicate strips in tracks starting from the last one so that we're 
749          * less likely to duplicate strips we just duplicated...
750          */
751         for (ale= anim_data.last; ale; ale= ale->prev) {
752                 NlaTrack *nlt= (NlaTrack *)ale->data;
753                 AnimData *adt= ale->adt;
754                 NlaStrip *strip, *nstrip, *next;
755                 NlaTrack *track;
756                 
757                 for (strip= nlt->strips.first; strip; strip= next) {
758                         next= strip->next;
759                         
760                         /* if selected, split the strip at its midpoint */
761                         if (strip->flag & NLASTRIP_FLAG_SELECT) {
762                                 /* make a copy (assume that this is possible) */
763                                 nstrip= copy_nlastrip(strip);
764                                 
765                                 /* in case there's no space in the track above, or we haven't got a reference to it yet, try adding */
766                                 if (BKE_nlatrack_add_strip(nlt->next, nstrip) == 0) {
767                                         /* need to add a new track above the one above the current one
768                                          *      - if the current one is the last one, nlt->next will be NULL, which defaults to adding 
769                                          *        at the top of the stack anyway...
770                                          */
771                                         track= add_nlatrack(adt, nlt->next);
772                                         BKE_nlatrack_add_strip(track, nstrip);
773                                 }
774                                 
775                                 /* deselect the original and the active flag */
776                                 strip->flag &= ~(NLASTRIP_FLAG_SELECT|NLASTRIP_FLAG_ACTIVE);
777                                 
778                                 /* auto-name newly created strip */
779                                 BKE_nlastrip_validate_name(adt, nstrip);
780                                 
781                                 done++;
782                         }
783                 }
784         }
785         
786         /* free temp data */
787         BLI_freelistN(&anim_data);
788         
789         if (done) {
790                 /* refresh auto strip properties */
791                 ED_nla_postop_refresh(&ac);
792                 
793                 /* set notifier that things have changed */
794                 WM_event_add_notifier(C, NC_ANIMATION|ND_NLA|NA_EDITED, NULL);
795                 
796                 /* done */
797                 return OPERATOR_FINISHED;
798         }
799         else
800                 return OPERATOR_CANCELLED;
801 }
802
803 static int nlaedit_duplicate_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
804 {
805         nlaedit_duplicate_exec(C, op);
806         
807         RNA_enum_set(op->ptr, "mode", TFM_TRANSLATION);
808         WM_operator_name_call(C, "TRANSFORM_OT_transform", WM_OP_INVOKE_REGION_WIN, op->ptr);
809
810         return OPERATOR_FINISHED;
811 }
812
813 void NLA_OT_duplicate (wmOperatorType *ot)
814 {
815         /* identifiers */
816         ot->name= "Duplicate Strips";
817         ot->idname= "NLA_OT_duplicate";
818         ot->description= "Duplicate selected NLA-Strips, adding the new strips in new tracks above the originals";
819         
820         /* api callbacks */
821         ot->invoke= nlaedit_duplicate_invoke;
822         ot->exec= nlaedit_duplicate_exec;
823         ot->poll= nlaop_poll_tweakmode_off;
824         
825         /* flags */
826         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
827         
828         /* to give to transform */
829         RNA_def_enum(ot->srna, "mode", transform_mode_types, TFM_TRANSLATION, "Mode", "");
830 }
831
832 /* ******************** Delete Strips Operator ***************************** */
833 /* Deletes the selected NLA-Strips */
834
835 static int nlaedit_delete_exec (bContext *C, wmOperator *UNUSED(op))
836 {
837         bAnimContext ac;
838         
839         ListBase anim_data = {NULL, NULL};
840         bAnimListElem *ale;
841         int filter;
842         
843         /* get editor data */
844         if (ANIM_animdata_get_context(C, &ac) == 0)
845                 return OPERATOR_CANCELLED;
846                 
847         /* get a list of the editable tracks being shown in the NLA */
848         filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
849         ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
850         
851         /* for each NLA-Track, delete all selected strips */
852         for (ale= anim_data.first; ale; ale= ale->next) {
853                 NlaTrack *nlt= (NlaTrack *)ale->data;
854                 NlaStrip *strip, *nstrip;
855                 
856                 for (strip= nlt->strips.first; strip; strip= nstrip) {
857                         nstrip= strip->next;
858                         
859                         /* if selected, delete */
860                         if (strip->flag & NLASTRIP_FLAG_SELECT) {
861                                 /* if a strip either side of this was a transition, delete those too */
862                                 if ((strip->prev) && (strip->prev->type == NLASTRIP_TYPE_TRANSITION)) 
863                                         free_nlastrip(&nlt->strips, strip->prev);
864                                 if ((nstrip) && (nstrip->type == NLASTRIP_TYPE_TRANSITION)) {
865                                         nstrip= nstrip->next;
866                                         free_nlastrip(&nlt->strips, strip->next);
867                                 }
868                                 
869                                 /* finally, delete this strip */
870                                 free_nlastrip(&nlt->strips, strip);
871                         }
872                 }
873         }
874         
875         /* free temp data */
876         BLI_freelistN(&anim_data);
877         
878         /* refresh auto strip properties */
879         ED_nla_postop_refresh(&ac);
880         
881         /* set notifier that things have changed */
882         WM_event_add_notifier(C, NC_ANIMATION|ND_NLA|NA_EDITED, NULL);
883         
884         /* done */
885         return OPERATOR_FINISHED;
886 }
887
888 void NLA_OT_delete (wmOperatorType *ot)
889 {
890         /* identifiers */
891         ot->name= "Delete Strips";
892         ot->idname= "NLA_OT_delete";
893         ot->description= "Delete selected strips";
894         
895         /* api callbacks */
896         ot->exec= nlaedit_delete_exec;
897         ot->poll= nlaop_poll_tweakmode_off;
898         
899         /* flags */
900         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
901 }
902
903 /* ******************** Split Strips Operator ***************************** */
904 /* Splits the selected NLA-Strips into two strips at the midpoint of the strip */
905 // TODO's? 
906 //      - multiple splits
907 //      - variable-length splits?
908
909 /* split a given Action-Clip strip */
910 static void nlaedit_split_strip_actclip (AnimData *adt, NlaTrack *nlt, NlaStrip *strip, float cfra)
911 {
912         NlaStrip *nstrip;
913         float splitframe, splitaframe;
914         
915         /* calculate the frames to do the splitting at 
916          *      - use current frame if within extents of strip 
917          */
918         if ((cfra > strip->start) && (cfra < strip->end)) {
919                 /* use the current frame */
920                 splitframe= cfra;
921                 splitaframe= nlastrip_get_frame(strip, cfra, NLATIME_CONVERT_UNMAP);
922         }
923         else {
924                 /* split in the middle */
925                 float len;
926                         
927                         /* strip extents */
928                 len= strip->end - strip->start;
929                 if (IS_EQ(len, 0.0f)) 
930                         return;
931                 else
932                         splitframe= strip->start + (len / 2.0f);
933                         
934                         /* action range */
935                 len= strip->actend - strip->actstart;
936                 if (IS_EQ(len, 0.0f))
937                         splitaframe= strip->actend;
938                 else
939                         splitaframe= strip->actstart + (len / 2.0f);
940         }
941         
942         /* make a copy (assume that this is possible) and append
943          * it immediately after the current strip
944          */
945         nstrip= copy_nlastrip(strip);
946         BLI_insertlinkafter(&nlt->strips, strip, nstrip);
947         
948         /* set the endpoint of the first strip and the start of the new strip 
949          * to the splitframe values calculated above
950          */
951         strip->end= splitframe;
952         nstrip->start= splitframe;
953         
954         if ((splitaframe > strip->actstart) && (splitaframe < strip->actend)) {
955                 /* only do this if we're splitting down the middle...  */
956                 strip->actend= splitaframe;
957                 nstrip->actstart= splitaframe;
958         }
959         
960         /* clear the active flag from the copy */
961         nstrip->flag &= ~NLASTRIP_FLAG_ACTIVE;
962         
963         /* auto-name the new strip */
964         BKE_nlastrip_validate_name(adt, nstrip);
965 }
966
967 /* split a given Meta strip */
968 static void nlaedit_split_strip_meta (NlaTrack *nlt, NlaStrip *strip)
969 {
970         /* simply ungroup it for now...  */
971         BKE_nlastrips_clear_metastrip(&nlt->strips, strip);
972 }
973
974 /* ----- */
975
976 static int nlaedit_split_exec (bContext *C, wmOperator *UNUSED(op))
977 {
978         bAnimContext ac;
979         
980         ListBase anim_data = {NULL, NULL};
981         bAnimListElem *ale;
982         int filter;
983         
984         /* get editor data */
985         if (ANIM_animdata_get_context(C, &ac) == 0)
986                 return OPERATOR_CANCELLED;
987                 
988         /* get a list of editable tracks being shown in the NLA */
989         filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
990         ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
991         
992         /* for each NLA-Track, split all selected strips into two strips */
993         for (ale= anim_data.first; ale; ale= ale->next) {
994                 NlaTrack *nlt= (NlaTrack *)ale->data;
995                 AnimData *adt= ale->adt;
996                 NlaStrip *strip, *next;
997                 
998                 for (strip= nlt->strips.first; strip; strip= next) {
999                         next= strip->next;
1000                         
1001                         /* if selected, split the strip at its midpoint */
1002                         if (strip->flag & NLASTRIP_FLAG_SELECT) {
1003                                 /* splitting method depends on the type of strip */
1004                                 switch (strip->type) {
1005                                         case NLASTRIP_TYPE_CLIP: /* action-clip */
1006                                                 nlaedit_split_strip_actclip(adt, nlt, strip, (float)ac.scene->r.cfra);
1007                                                 break;
1008                                                 
1009                                         case NLASTRIP_TYPE_META: /* meta-strips need special handling */
1010                                                 nlaedit_split_strip_meta(nlt, strip);
1011                                                 break;
1012                                         
1013                                         default: /* for things like Transitions, do not split! */
1014                                                 break;
1015                                 }
1016                         }
1017                 }
1018         }
1019         
1020         /* free temp data */
1021         BLI_freelistN(&anim_data);
1022         
1023         /* refresh auto strip properties */
1024         ED_nla_postop_refresh(&ac);
1025         
1026         /* set notifier that things have changed */
1027         WM_event_add_notifier(C, NC_ANIMATION|ND_NLA|NA_EDITED, NULL);
1028         
1029         /* done */
1030         return OPERATOR_FINISHED;
1031 }
1032
1033 void NLA_OT_split (wmOperatorType *ot)
1034 {
1035         /* identifiers */
1036         ot->name= "Split Strips";
1037         ot->idname= "NLA_OT_split";
1038         ot->description= "Split selected strips at their midpoints";
1039         
1040         /* api callbacks */
1041         ot->exec= nlaedit_split_exec;
1042         ot->poll= nlaop_poll_tweakmode_off;
1043         
1044         /* flags */
1045         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1046 }
1047
1048 /* ******************** Bake Strips Operator ***************************** */
1049 /* Bakes the NLA Strips for the active AnimData blocks */
1050
1051 static int nlaedit_bake_exec (bContext *C, wmOperator *UNUSED(op))
1052 {
1053         bAnimContext ac;
1054         
1055         ListBase anim_data = {NULL, NULL};
1056         bAnimListElem *ale;
1057         int filter;
1058 //      int flag = 0;
1059         
1060         /* get editor data */
1061         if (ANIM_animdata_get_context(C, &ac) == 0)
1062                 return OPERATOR_CANCELLED;
1063                 
1064         /* get a list of the editable tracks being shown in the NLA */
1065         filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_ANIMDATA | ANIMFILTER_FOREDIT);
1066         ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
1067         
1068         /* for each AnimData block, bake strips to animdata... */
1069         for (ale= anim_data.first; ale; ale= ale->next) {
1070                 //BKE_nla_bake(ac.scene, ale->id, ale->data, flag);
1071         }
1072         
1073         /* free temp data */
1074         BLI_freelistN(&anim_data);
1075         
1076         /* refresh auto strip properties */
1077         ED_nla_postop_refresh(&ac);
1078         
1079         /* set notifier that things have changed */
1080         WM_event_add_notifier(C, NC_ANIMATION|ND_NLA|NA_EDITED, NULL);
1081         
1082         /* done */
1083         return OPERATOR_FINISHED;
1084 }
1085
1086 static void NLA_OT_bake (wmOperatorType *ot)
1087 {
1088         /* identifiers */
1089         ot->name= "Bake Strips";
1090         ot->idname= "NLA_OT_bake";
1091         ot->description= "Bake all strips of selected AnimData blocks";
1092         
1093         /* api callbacks */
1094         ot->exec= nlaedit_bake_exec;
1095         ot->poll= nlaop_poll_tweakmode_off;
1096         
1097         /* flags */
1098         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1099 }
1100
1101 /* *********************************************** */
1102 /* NLA Editing Operations (Modifying) */
1103
1104 /* ******************** Toggle Muting Operator ************************** */
1105 /* Toggles whether strips are muted or not */
1106
1107 static int nlaedit_toggle_mute_exec (bContext *C, wmOperator *UNUSED(op))
1108 {
1109         bAnimContext ac;
1110         
1111         ListBase anim_data = {NULL, NULL};
1112         bAnimListElem *ale;
1113         int filter;
1114         
1115         /* get editor data */
1116         if (ANIM_animdata_get_context(C, &ac) == 0)
1117                 return OPERATOR_CANCELLED;
1118                 
1119         /* get a list of the editable tracks being shown in the NLA */
1120         filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
1121         ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
1122         
1123         /* go over all selected strips */
1124         for (ale= anim_data.first; ale; ale= ale->next) {
1125                 NlaTrack *nlt= (NlaTrack *)ale->data;
1126                 NlaStrip *strip;
1127                 
1128                 /* for every selected strip, toggle muting  */
1129                 for (strip= nlt->strips.first; strip; strip= strip->next) {
1130                         if (strip->flag & NLASTRIP_FLAG_SELECT) {
1131                                 /* just flip the mute flag for now */
1132                                 // TODO: have a pre-pass to check if mute all or unmute all?
1133                                 strip->flag ^= NLASTRIP_FLAG_MUTED;
1134                         }
1135                 }
1136         }
1137         
1138         /* free temp data */
1139         BLI_freelistN(&anim_data);
1140         
1141         /* set notifier that things have changed */
1142         WM_event_add_notifier(C, NC_ANIMATION|ND_NLA|NA_EDITED, NULL);
1143         
1144         /* done */
1145         return OPERATOR_FINISHED;
1146 }
1147
1148 void NLA_OT_mute_toggle (wmOperatorType *ot)
1149 {
1150         /* identifiers */
1151         ot->name= "Toggle Muting";
1152         ot->idname= "NLA_OT_mute_toggle";
1153         ot->description= "Mute or un-mute selected strips";
1154         
1155         /* api callbacks */
1156         ot->exec= nlaedit_toggle_mute_exec;
1157         ot->poll= nlaop_poll_tweakmode_off;
1158         
1159         /* flags */
1160         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1161 }
1162
1163 /* ******************** Swap Strips Operator ************************** */
1164 /* Tries to exchange strips within their owner tracks */
1165
1166 static int nlaedit_swap_exec (bContext *C, wmOperator *op)
1167 {
1168         bAnimContext ac;
1169         
1170         ListBase anim_data = {NULL, NULL};
1171         bAnimListElem *ale;
1172         int filter;
1173         
1174         /* get editor data */
1175         if (ANIM_animdata_get_context(C, &ac) == 0)
1176                 return OPERATOR_CANCELLED;
1177                 
1178         /* get a list of the editable tracks being shown in the NLA */
1179         filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
1180         ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
1181         
1182         /* consider each track in turn */
1183         for (ale= anim_data.first; ale; ale= ale->next) {
1184                 NlaTrack *nlt= (NlaTrack *)ale->data;
1185                 
1186                 NlaStrip *strip, *stripN=NULL;
1187                 NlaStrip *sa=NULL, *sb=NULL;
1188                 
1189                 /* make temporary metastrips so that entire islands of selections can be moved around */
1190                 BKE_nlastrips_make_metas(&nlt->strips, 1);
1191                 
1192                 /* special case: if there is only 1 island (i.e. temp meta BUT NOT unselected/normal/normal-meta strips) left after this, 
1193                  * and this island has two strips inside it, then we should be able to just swap these still...
1194                  */
1195                 if ((nlt->strips.first == nlt->strips.last) && (nlt->strips.first != NULL)) {
1196                         NlaStrip *mstrip = (NlaStrip *)nlt->strips.first;
1197                         
1198                         if ((mstrip->flag & NLASTRIP_FLAG_TEMP_META) && (BLI_countlist(&mstrip->strips) == 2)) 
1199                         {
1200                                 /* remove this temp meta, so that we can see the strips inside */
1201                                 BKE_nlastrips_clear_metas(&nlt->strips, 0, 1);
1202                         }
1203                 }
1204                 
1205                 /* get two selected strips only (these will be metas due to prev step) to operate on
1206                  *      - only allow swapping 2, as with more the context becomes unclear
1207                  */
1208                 for (strip = nlt->strips.first; strip; strip = stripN) {
1209                         stripN = strip->next;
1210                         
1211                         if (strip->flag & NLASTRIP_FLAG_SELECT) {
1212                                 /* first or second strip? */
1213                                 if (sa == NULL) {
1214                                         /* store as first */
1215                                         sa = strip;
1216                                 }
1217                                 else if (sb == NULL) {
1218                                         /* store as second */
1219                                         sb = strip;
1220                                 }
1221                                 else {
1222                                         /* too many selected */
1223                                         break;
1224                                 }
1225                         }
1226                 }
1227                 
1228                 if (strip) {
1229                         /* too many selected warning */
1230                         BKE_reportf(op->reports, RPT_WARNING, 
1231                                 "Too many clusters of strips selected in NLA Track (%s). Needs exactly 2 to be selected.",
1232                                 nlt->name);
1233                 }
1234                 else if (sa == NULL) {
1235                         /* no warning as this is just a common case, and it may get annoying when doing multiple tracks */
1236                 }
1237                 else if (sb == NULL) {
1238                         /* too few selected warning */
1239                         BKE_reportf(op->reports, RPT_WARNING,
1240                                 "Too few clusters of strips selected in NLA Track (%s). Needs exactly 2 to be selected.",
1241                                 nlt->name);
1242                 }
1243                 else {
1244                         float nsa[2], nsb[2];
1245                         
1246                         /* remove these strips from the track, so that we can test if they can fit in the proposed places */
1247                         BLI_remlink(&nlt->strips, sa);
1248                         BLI_remlink(&nlt->strips, sb);
1249                         
1250                         /* calculate new extents for strips */
1251                                 /* a --> b */
1252                         nsa[0] = sb->start;
1253                         nsa[1] = sb->start + (sa->end - sa->start);
1254                                 /* b --> a */
1255                         nsb[0] = sa->start;
1256                         nsb[1] = sa->start + (sb->end - sb->start);
1257                         
1258                         /* check if the track has room for the strips to be swapped */
1259                         if (BKE_nlastrips_has_space(&nlt->strips, nsa[0], nsa[1]) && 
1260                                 BKE_nlastrips_has_space(&nlt->strips, nsb[0], nsb[1]))
1261                         {
1262                                 /* set new extents for strips then */
1263                                 sa->start = nsa[0];
1264                                 sa->end   = nsa[1];
1265                                 BKE_nlameta_flush_transforms(sa);
1266                                 
1267                                 sb->start = nsb[0];
1268                                 sb->end   = nsb[1];
1269                                 BKE_nlameta_flush_transforms(sb);
1270                         }
1271                         else {
1272                                 /* not enough room to swap, so show message */
1273                                 if ((sa->flag & NLASTRIP_FLAG_TEMP_META) || (sb->flag & NLASTRIP_FLAG_TEMP_META)) {
1274                                         BKE_report(op->reports, RPT_WARNING,
1275                                                 "Cannot swap selected strips as they will not be able to fit in their new places");
1276                                 }
1277                                 else {
1278                                         BKE_reportf(op->reports, RPT_WARNING,   
1279                                                 "Cannot swap '%s' and '%s' as one or both will not be able to fit in their new places",
1280                                                 sa->name, sb->name);
1281                                 }
1282                         }
1283                         
1284                         /* add strips back to track now */
1285                         BKE_nlatrack_add_strip(nlt, sa);
1286                         BKE_nlatrack_add_strip(nlt, sb);
1287                 }
1288                 
1289                 /* clear (temp) metastrips */
1290                 BKE_nlastrips_clear_metas(&nlt->strips, 0, 1);
1291         }
1292         
1293         /* free temp data */
1294         BLI_freelistN(&anim_data);
1295         
1296         /* refresh auto strip properties */
1297         ED_nla_postop_refresh(&ac);
1298         
1299         /* set notifier that things have changed */
1300         WM_event_add_notifier(C, NC_ANIMATION|ND_NLA|NA_EDITED, NULL);
1301         
1302         /* done */
1303         return OPERATOR_FINISHED;
1304 }
1305
1306 void NLA_OT_swap (wmOperatorType *ot)
1307 {
1308         /* identifiers */
1309         ot->name= "Swap Strips";
1310         ot->idname= "NLA_OT_swap";
1311         ot->description= "Swap order of selected strips within tracks";
1312         
1313         /* api callbacks */
1314         ot->exec= nlaedit_swap_exec;
1315         ot->poll= nlaop_poll_tweakmode_off;
1316         
1317         /* flags */
1318         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1319 }
1320
1321 /* ******************** Move Strips Up Operator ************************** */
1322 /* Tries to move the selected strips into the track above if possible. */
1323
1324 static int nlaedit_move_up_exec (bContext *C, wmOperator *UNUSED(op))
1325 {
1326         bAnimContext ac;
1327         
1328         ListBase anim_data = {NULL, NULL};
1329         bAnimListElem *ale;
1330         int filter;
1331         
1332         /* get editor data */
1333         if (ANIM_animdata_get_context(C, &ac) == 0)
1334                 return OPERATOR_CANCELLED;
1335                 
1336         /* get a list of the editable tracks being shown in the NLA */
1337         filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
1338         ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
1339         
1340         /* since we're potentially moving strips from lower tracks to higher tracks, we should
1341          * loop over the tracks in reverse order to avoid moving earlier strips up multiple tracks
1342          */
1343         for (ale= anim_data.last; ale; ale= ale->prev) {
1344                 NlaTrack *nlt= (NlaTrack *)ale->data;
1345                 NlaTrack *nltn= nlt->next;
1346                 NlaStrip *strip, *stripn;
1347                 
1348                 /* if this track has no tracks after it, skip for now... */
1349                 if (nltn == NULL)
1350                         continue;
1351                 
1352                 /* for every selected strip, try to move */
1353                 for (strip= nlt->strips.first; strip; strip= stripn) {
1354                         stripn= strip->next;
1355                         
1356                         if (strip->flag & NLASTRIP_FLAG_SELECT) {
1357                                 /* check if the track above has room for this strip */
1358                                 if (BKE_nlatrack_has_space(nltn, strip->start, strip->end)) {
1359                                         /* remove from its current track, and add to the one above (it 'should' work, so no need to worry) */
1360                                         BLI_remlink(&nlt->strips, strip);
1361                                         BKE_nlatrack_add_strip(nltn, strip);
1362                                 }
1363                         }
1364                 }
1365         }
1366         
1367         /* free temp data */
1368         BLI_freelistN(&anim_data);
1369         
1370         /* refresh auto strip properties */
1371         ED_nla_postop_refresh(&ac);
1372         
1373         /* set notifier that things have changed */
1374         WM_event_add_notifier(C, NC_ANIMATION|ND_NLA|NA_EDITED, NULL);
1375         
1376         /* done */
1377         return OPERATOR_FINISHED;
1378 }
1379
1380 void NLA_OT_move_up (wmOperatorType *ot)
1381 {
1382         /* identifiers */
1383         ot->name= "Move Strips Up";
1384         ot->idname= "NLA_OT_move_up";
1385         ot->description= "Move selected strips up a track if there's room";
1386         
1387         /* api callbacks */
1388         ot->exec= nlaedit_move_up_exec;
1389         ot->poll= nlaop_poll_tweakmode_off;
1390         
1391         /* flags */
1392         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1393 }
1394
1395 /* ******************** Move Strips Down Operator ************************** */
1396 /* Tries to move the selected strips into the track above if possible. */
1397
1398 static int nlaedit_move_down_exec (bContext *C, wmOperator *UNUSED(op))
1399 {
1400         bAnimContext ac;
1401         
1402         ListBase anim_data = {NULL, NULL};
1403         bAnimListElem *ale;
1404         int filter;
1405         
1406         /* get editor data */
1407         if (ANIM_animdata_get_context(C, &ac) == 0)
1408                 return OPERATOR_CANCELLED;
1409                 
1410         /* get a list of the editable tracks being shown in the NLA */
1411         filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
1412         ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
1413         
1414         /* loop through the tracks in normal order, since we're pushing strips down,
1415          * strips won't get operated on twice
1416          */
1417         for (ale= anim_data.first; ale; ale= ale->next) {
1418                 NlaTrack *nlt= (NlaTrack *)ale->data;
1419                 NlaTrack *nltp= nlt->prev;
1420                 NlaStrip *strip, *stripn;
1421                 
1422                 /* if this track has no tracks before it, skip for now... */
1423                 if (nltp == NULL)
1424                         continue;
1425                 
1426                 /* for every selected strip, try to move */
1427                 for (strip= nlt->strips.first; strip; strip= stripn) {
1428                         stripn= strip->next;
1429                         
1430                         if (strip->flag & NLASTRIP_FLAG_SELECT) {
1431                                 /* check if the track below has room for this strip */
1432                                 if (BKE_nlatrack_has_space(nltp, strip->start, strip->end)) {
1433                                         /* remove from its current track, and add to the one above (it 'should' work, so no need to worry) */
1434                                         BLI_remlink(&nlt->strips, strip);
1435                                         BKE_nlatrack_add_strip(nltp, strip);
1436                                 }
1437                         }
1438                 }
1439         }
1440         
1441         /* free temp data */
1442         BLI_freelistN(&anim_data);
1443         
1444         /* refresh auto strip properties */
1445         ED_nla_postop_refresh(&ac);
1446         
1447         /* set notifier that things have changed */
1448         WM_event_add_notifier(C, NC_ANIMATION|ND_NLA|NA_EDITED, NULL);
1449         
1450         /* done */
1451         return OPERATOR_FINISHED;
1452 }
1453
1454 void NLA_OT_move_down (wmOperatorType *ot)
1455 {
1456         /* identifiers */
1457         ot->name= "Move Strips Down";
1458         ot->idname= "NLA_OT_move_down";
1459         ot->description= "Move selected strips down a track if there's room";
1460         
1461         /* api callbacks */
1462         ot->exec= nlaedit_move_down_exec;
1463         ot->poll= nlaop_poll_tweakmode_off;
1464         
1465         /* flags */
1466         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1467 }
1468
1469 /* ******************** Sync Action Length Operator ***************************** */
1470 /* Recalculate the extents of the action ranges used for the selected strips  */
1471
1472 static int nlaedit_sync_actlen_exec (bContext *C, wmOperator *op)
1473 {
1474         bAnimContext ac;
1475         
1476         ListBase anim_data = {NULL, NULL};
1477         bAnimListElem *ale;
1478         int filter;
1479         short active_only= RNA_boolean_get(op->ptr, "active");
1480         
1481         /* get editor data */
1482         if (ANIM_animdata_get_context(C, &ac) == 0)
1483                 return OPERATOR_CANCELLED;
1484                 
1485         /* get a list of the editable tracks being shown in the NLA */
1486         filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
1487         if (active_only) filter |= ANIMFILTER_ACTIVE;
1488         ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
1489         
1490         /* for each NLA-Track, apply scale of all selected strips */
1491         for (ale= anim_data.first; ale; ale= ale->next) {
1492                 NlaTrack *nlt= (NlaTrack *)ale->data;
1493                 NlaStrip *strip;
1494                 
1495                 for (strip= nlt->strips.first; strip; strip= strip->next) {
1496                         /* strip selection/active status check */
1497                         if (active_only) {
1498                                 if ((strip->flag & NLASTRIP_FLAG_ACTIVE) == 0)
1499                                         continue;
1500                         }
1501                         else {
1502                                 if ((strip->flag & NLASTRIP_FLAG_SELECT) == 0)
1503                                         continue;
1504                         }
1505                         
1506                         /* must be action-clip only (transitions don't have scale) */
1507                         if (strip->type == NLASTRIP_TYPE_CLIP) {
1508                                 if (strip->act == NULL) 
1509                                         continue;
1510                                         
1511                                 /* recalculate the length of the action */
1512                                 calc_action_range(strip->act, &strip->actstart, &strip->actend, 0);
1513                                 
1514                                 /* adjust the strip extents in response to this */
1515                                 BKE_nlastrip_recalculate_bounds(strip);
1516                         }
1517                 }
1518         }
1519         
1520         /* free temp data */
1521         BLI_freelistN(&anim_data);
1522         
1523         /* set notifier that things have changed */
1524         WM_event_add_notifier(C, NC_ANIMATION|ND_NLA|NA_EDITED, NULL);
1525         
1526         /* done */
1527         return OPERATOR_FINISHED;
1528 }
1529
1530 void NLA_OT_action_sync_length (wmOperatorType *ot)
1531 {
1532         /* identifiers */
1533         ot->name= "Sync Action Length";
1534         ot->idname= "NLA_OT_action_sync_length";
1535         ot->description= "Synchronise the length of the referenced Action with the lengths used in the strip";
1536         
1537         /* api callbacks */
1538         ot->exec= nlaedit_sync_actlen_exec;
1539         ot->poll= ED_operator_nla_active; // XXX: is this satisfactory... probably requires a check for active strip...
1540         
1541         /* flags */
1542         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1543         
1544         /* properties */
1545         ot->prop= RNA_def_boolean(ot->srna, "active", 1, "Active Strip Only", "Only sync the active length for the active strip.");
1546 }
1547
1548 /* ******************** Apply Scale Operator ***************************** */
1549 /* Reset the scaling of the selected strips to 1.0f */
1550
1551 /* apply scaling to keyframe */
1552 static short bezt_apply_nlamapping (KeyframeEditData *ked, BezTriple *bezt)
1553 {
1554         /* NLA-strip which has this scaling is stored in ked->data */
1555         NlaStrip *strip= (NlaStrip *)ked->data;
1556         
1557         /* adjust all the times */
1558         bezt->vec[0][0]= nlastrip_get_frame(strip, bezt->vec[0][0], NLATIME_CONVERT_MAP);
1559         bezt->vec[1][0]= nlastrip_get_frame(strip, bezt->vec[1][0], NLATIME_CONVERT_MAP);
1560         bezt->vec[2][0]= nlastrip_get_frame(strip, bezt->vec[2][0], NLATIME_CONVERT_MAP);
1561         
1562         /* nothing to return or else we exit */
1563         return 0;
1564 }
1565
1566 static int nlaedit_apply_scale_exec (bContext *C, wmOperator *UNUSED(op))
1567 {
1568         bAnimContext ac;
1569         
1570         ListBase anim_data = {NULL, NULL};
1571         bAnimListElem *ale;
1572         int filter;
1573         
1574         KeyframeEditData ked= {{NULL}};
1575         
1576         /* get editor data */
1577         if (ANIM_animdata_get_context(C, &ac) == 0)
1578                 return OPERATOR_CANCELLED;
1579                 
1580         /* get a list of the editable tracks being shown in the NLA */
1581         filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
1582         ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
1583         
1584         /* init the editing data */
1585         
1586         /* for each NLA-Track, apply scale of all selected strips */
1587         for (ale= anim_data.first; ale; ale= ale->next) {
1588                 NlaTrack *nlt= (NlaTrack *)ale->data;
1589                 NlaStrip *strip;
1590                 
1591                 for (strip= nlt->strips.first; strip; strip= strip->next) {
1592                         /* strip must be selected, and must be action-clip only (transitions don't have scale) */
1593                         if ((strip->flag & NLASTRIP_FLAG_SELECT) && (strip->type == NLASTRIP_TYPE_CLIP)) {
1594                                 /* if the referenced action is used by other strips, make this strip use its own copy */
1595                                 if (strip->act == NULL) 
1596                                         continue;
1597                                 if (strip->act->id.us > 1) {
1598                                         /* make a copy of the Action to work on */
1599                                         bAction *act= copy_action(strip->act);
1600                                         
1601                                         /* set this as the new referenced action, decrementing the users of the old one */
1602                                         strip->act->id.us--;
1603                                         strip->act= act;
1604                                 }
1605                                 
1606                                 /* setup iterator, and iterate over all the keyframes in the action, applying this scaling */
1607                                 ked.data= strip;
1608                                 ANIM_animchanneldata_keyframes_loop(&ked, ac.ads, strip->act, ALE_ACT, NULL, bezt_apply_nlamapping, calchandles_fcurve);
1609                                 
1610                                 /* clear scale of strip now that it has been applied,
1611                                  * and recalculate the extents of the action now that it has been scaled
1612                                  * but leave everything else alone 
1613                                  */
1614                                 strip->scale= 1.0f;
1615                                 calc_action_range(strip->act, &strip->actstart, &strip->actend, 0);
1616                         }
1617                 }
1618         }
1619         
1620         /* free temp data */
1621         BLI_freelistN(&anim_data);
1622         
1623         /* set notifier that things have changed */
1624         WM_event_add_notifier(C, NC_ANIMATION|ND_NLA|NA_EDITED, NULL);
1625         
1626         /* done */
1627         return OPERATOR_FINISHED;
1628 }
1629
1630 void NLA_OT_apply_scale (wmOperatorType *ot)
1631 {
1632         /* identifiers */
1633         ot->name= "Apply Scale";
1634         ot->idname= "NLA_OT_apply_scale";
1635         ot->description= "Apply scaling of selected strips to their referenced Actions";
1636         
1637         /* api callbacks */
1638         ot->exec= nlaedit_apply_scale_exec;
1639         ot->poll= nlaop_poll_tweakmode_off;
1640         
1641         /* flags */
1642         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1643 }
1644
1645 /* ******************** Clear Scale Operator ***************************** */
1646 /* Reset the scaling of the selected strips to 1.0f */
1647
1648 static int nlaedit_clear_scale_exec (bContext *C, wmOperator *UNUSED(op))
1649 {
1650         bAnimContext ac;
1651         
1652         ListBase anim_data = {NULL, NULL};
1653         bAnimListElem *ale;
1654         int filter;
1655         
1656         /* get editor data */
1657         if (ANIM_animdata_get_context(C, &ac) == 0)
1658                 return OPERATOR_CANCELLED;
1659                 
1660         /* get a list of the editable tracks being shown in the NLA */
1661         filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
1662         ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
1663         
1664         /* for each NLA-Track, reset scale of all selected strips */
1665         for (ale= anim_data.first; ale; ale= ale->next) {
1666                 NlaTrack *nlt= (NlaTrack *)ale->data;
1667                 NlaStrip *strip;
1668                 
1669                 for (strip= nlt->strips.first; strip; strip= strip->next) {
1670                         /* strip must be selected, and must be action-clip only (transitions don't have scale) */
1671                         if ((strip->flag & NLASTRIP_FLAG_SELECT) && (strip->type == NLASTRIP_TYPE_CLIP)) {
1672                                 PointerRNA strip_ptr;
1673                                 
1674                                 RNA_pointer_create(NULL, &RNA_NlaStrip, strip, &strip_ptr);
1675                                 RNA_float_set(&strip_ptr, "scale", 1.0f);
1676                         }
1677                 }
1678         }
1679         
1680         /* free temp data */
1681         BLI_freelistN(&anim_data);
1682         
1683         /* refresh auto strip properties */
1684         ED_nla_postop_refresh(&ac);
1685         
1686         /* set notifier that things have changed */
1687         WM_event_add_notifier(C, NC_ANIMATION|ND_NLA|NA_EDITED, NULL);
1688         
1689         /* done */
1690         return OPERATOR_FINISHED;
1691 }
1692
1693 void NLA_OT_clear_scale (wmOperatorType *ot)
1694 {
1695         /* identifiers */
1696         ot->name= "Clear Scale";
1697         ot->idname= "NLA_OT_clear_scale";
1698         ot->description= "Reset scaling of selected strips";
1699         
1700         /* api callbacks */
1701         ot->exec= nlaedit_clear_scale_exec;
1702         ot->poll= nlaop_poll_tweakmode_off;
1703         
1704         /* flags */
1705         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1706 }
1707
1708 /* ******************** Snap Strips Operator ************************** */
1709 /* Moves the start-point of the selected strips to the specified places */
1710
1711 /* defines for snap keyframes tool */
1712 static EnumPropertyItem prop_nlaedit_snap_types[] = {
1713         {NLAEDIT_SNAP_CFRA, "CFRA", 0, "Current frame", ""},
1714         {NLAEDIT_SNAP_NEAREST_FRAME, "NEAREST_FRAME", 0, "Nearest Frame", ""}, // XXX as single entry?
1715         {NLAEDIT_SNAP_NEAREST_SECOND, "NEAREST_SECOND", 0, "Nearest Second", ""}, // XXX as single entry?
1716         {NLAEDIT_SNAP_NEAREST_MARKER, "NEAREST_MARKER", 0, "Nearest Marker", ""},
1717         {0, NULL, 0, NULL, NULL}
1718 };
1719
1720 static int nlaedit_snap_exec (bContext *C, wmOperator *op)
1721 {
1722         bAnimContext ac;
1723         
1724         ListBase anim_data = {NULL, NULL};
1725         bAnimListElem *ale;
1726         int filter;
1727         
1728         Scene *scene;
1729         int mode = RNA_enum_get(op->ptr, "type");
1730         float secf;
1731         
1732         /* get editor data */
1733         if (ANIM_animdata_get_context(C, &ac) == 0)
1734                 return OPERATOR_CANCELLED;
1735                 
1736         /* get a list of the editable tracks being shown in the NLA */
1737         filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
1738         ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
1739         
1740         /* get some necessary vars */
1741         scene= ac.scene;
1742         secf= (float)FPS;
1743         
1744         /* since we may add tracks, perform this in reverse order */
1745         for (ale= anim_data.last; ale; ale= ale->prev) {
1746                 ListBase tmp_strips = {NULL, NULL};
1747                 AnimData *adt= ale->adt;
1748                 NlaTrack *nlt= (NlaTrack *)ale->data;
1749                 NlaStrip *strip, *stripn;
1750                 NlaTrack *track;
1751                 
1752                 /* create meta-strips from the continuous chains of selected strips */
1753                 BKE_nlastrips_make_metas(&nlt->strips, 1);
1754                 
1755                 /* apply the snapping to all the temp meta-strips, then put them in a separate list to be added
1756                  * back to the original only if they still fit
1757                  */
1758                 for (strip= nlt->strips.first; strip; strip= stripn) {
1759                         stripn= strip->next;
1760                         
1761                         if (strip->flag & NLASTRIP_FLAG_TEMP_META) {
1762                                 float start, end;
1763                                 
1764                                 /* get the existing end-points */
1765                                 start= strip->start;
1766                                 end= strip->end;
1767                                 
1768                                 /* calculate new start position based on snapping mode */
1769                                 switch (mode) {
1770                                         case NLAEDIT_SNAP_CFRA: /* to current frame */
1771                                                 strip->start= (float)CFRA;
1772                                                 break;
1773                                         case NLAEDIT_SNAP_NEAREST_FRAME: /* to nearest frame */
1774                                                 strip->start= (float)(floor(start+0.5));
1775                                                 break;
1776                                         case NLAEDIT_SNAP_NEAREST_SECOND: /* to nearest second */
1777                                                 strip->start= ((float)floor(start/secf + 0.5f) * secf);
1778                                                 break;
1779                                         case NLAEDIT_SNAP_NEAREST_MARKER: /* to nearest marker */
1780                                                 strip->start= (float)ED_markers_find_nearest_marker_time(ac.markers, start);
1781                                                 break;
1782                                         default: /* just in case... no snapping */
1783                                                 strip->start= start;
1784                                                 break;
1785                                 }
1786                                 
1787                                 /* get new endpoint based on start-point (and old length) */
1788                                 strip->end= strip->start + (end - start);
1789                                 
1790                                 /* apply transforms to meta-strip to its children */
1791                                 BKE_nlameta_flush_transforms(strip);
1792                                 
1793                                 /* remove strip from track, and add to the temp buffer */
1794                                 BLI_remlink(&nlt->strips, strip);
1795                                 BLI_addtail(&tmp_strips, strip);
1796                         }
1797                 }
1798                 
1799                 /* try adding each meta-strip back to the track one at a time, to make sure they'll fit */
1800                 for (strip= tmp_strips.first; strip; strip= stripn) {
1801                         stripn= strip->next;
1802                         
1803                         /* remove from temp-strips list */
1804                         BLI_remlink(&tmp_strips, strip);
1805                         
1806                         /* in case there's no space in the current track, try adding */
1807                         if (BKE_nlatrack_add_strip(nlt, strip) == 0) {
1808                                 /* need to add a new track above the current one */
1809                                 track= add_nlatrack(adt, nlt);
1810                                 BKE_nlatrack_add_strip(track, strip);
1811                                 
1812                                 /* clear temp meta-strips on this new track, as we may not be able to get back to it */
1813                                 BKE_nlastrips_clear_metas(&track->strips, 0, 1);
1814                         }
1815                 }
1816                 
1817                 /* remove the meta-strips now that we're done */
1818                 BKE_nlastrips_clear_metas(&nlt->strips, 0, 1);
1819         }
1820         
1821         /* free temp data */
1822         BLI_freelistN(&anim_data);
1823         
1824         /* refresh auto strip properties */
1825         ED_nla_postop_refresh(&ac);
1826         
1827         /* set notifier that things have changed */
1828         WM_event_add_notifier(C, NC_ANIMATION|ND_NLA|NA_EDITED, NULL);
1829         
1830         /* done */
1831         return OPERATOR_FINISHED;
1832 }
1833
1834 void NLA_OT_snap (wmOperatorType *ot)
1835 {
1836         /* identifiers */
1837         ot->name= "Snap Strips";
1838         ot->idname= "NLA_OT_snap";
1839         ot->description= "Move start of strips to specified time";
1840         
1841         /* api callbacks */
1842         ot->invoke= WM_menu_invoke;
1843         ot->exec= nlaedit_snap_exec;
1844         ot->poll= nlaop_poll_tweakmode_off;
1845         
1846         /* flags */
1847         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1848         
1849         /* properties */
1850         ot->prop= RNA_def_enum(ot->srna, "type", prop_nlaedit_snap_types, 0, "Type", "");
1851 }
1852
1853 /* *********************************************** */
1854 /* NLA Modifiers */
1855
1856 /* ******************** Add F-Modifier Operator *********************** */
1857
1858 /* present a special customised popup menu for this, with some filtering */
1859 static int nla_fmodifier_add_invoke (bContext *C, wmOperator *UNUSED(op), wmEvent *UNUSED(event))
1860 {
1861         uiPopupMenu *pup;
1862         uiLayout *layout;
1863         int i;
1864         
1865         pup= uiPupMenuBegin(C, "Add F-Modifier", ICON_NONE);
1866         layout= uiPupMenuLayout(pup);
1867         
1868         /* start from 1 to skip the 'Invalid' modifier type */
1869         for (i = 1; i < FMODIFIER_NUM_TYPES; i++) {
1870                 FModifierTypeInfo *fmi= get_fmodifier_typeinfo(i);
1871                 
1872                 /* check if modifier is valid for this context */
1873                 if (fmi == NULL)
1874                         continue;
1875                 if (i == FMODIFIER_TYPE_CYCLES) /* we already have repeat... */
1876                         continue;
1877                 
1878                 /* add entry to add this type of modifier */
1879                 uiItemEnumO(layout, "NLA_OT_fmodifier_add", fmi->name, 0, "type", i);
1880         }
1881         uiItemS(layout);
1882         
1883         uiPupMenuEnd(C, pup);
1884         
1885         return OPERATOR_CANCELLED;
1886 }
1887
1888 static int nla_fmodifier_add_exec(bContext *C, wmOperator *op)
1889 {
1890         bAnimContext ac;
1891         
1892         ListBase anim_data = {NULL, NULL};
1893         bAnimListElem *ale;
1894         int filter;
1895         
1896         FModifier *fcm;
1897         int type= RNA_enum_get(op->ptr, "type");
1898         short onlyActive = RNA_boolean_get(op->ptr, "only_active");
1899         
1900         /* get editor data */
1901         if (ANIM_animdata_get_context(C, &ac) == 0)
1902                 return OPERATOR_CANCELLED;
1903                 
1904         /* get a list of the editable tracks being shown in the NLA */
1905         filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
1906         ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
1907         
1908         /* for each NLA-Track, add the specified modifier to all selected strips */
1909         for (ale= anim_data.first; ale; ale= ale->next) {
1910                 NlaTrack *nlt= (NlaTrack *)ale->data;
1911                 NlaStrip *strip;
1912                 
1913                 for (strip= nlt->strips.first; strip; strip=strip->next) {
1914                         /* can F-Modifier be added to the current strip? */
1915                         if (onlyActive) {
1916                                 /* if not active, cannot add since we're only adding to active strip */
1917                                 if ((strip->flag & NLASTRIP_FLAG_ACTIVE)==0)
1918                                         continue;
1919                         }
1920                         else {
1921                                 /* strip must be selected, since we're not just doing active */
1922                                 if ((strip->flag & NLASTRIP_FLAG_SELECT)==0)
1923                                         continue;
1924                         }
1925                         
1926                         /* add F-Modifier of specified type to selected, and make it the active one */
1927                         fcm= add_fmodifier(&strip->modifiers, type);
1928                         
1929                         if (fcm)
1930                                 set_active_fmodifier(&strip->modifiers, fcm);
1931                         else {
1932                                 BKE_reportf(op->reports, RPT_ERROR,
1933                                         "Modifier couldn't be added to (%s : %s). See console for details.", 
1934                                         nlt->name, strip->name);
1935                         }
1936                 }
1937         }
1938         
1939         /* free temp data */
1940         BLI_freelistN(&anim_data);
1941         
1942         /* set notifier that things have changed */
1943         WM_event_add_notifier(C, NC_ANIMATION|ND_NLA|NA_EDITED, NULL);
1944         
1945         /* done */
1946         return OPERATOR_FINISHED;
1947 }
1948  
1949 void NLA_OT_fmodifier_add (wmOperatorType *ot)
1950 {
1951         /* identifiers */
1952         ot->name= "Add F-Modifier";
1953         ot->idname= "NLA_OT_fmodifier_add";
1954         ot->description= "Add F-Modifier of the specified type to the selected NLA-Strips";
1955         
1956         /* api callbacks */
1957         ot->invoke= nla_fmodifier_add_invoke;
1958         ot->exec= nla_fmodifier_add_exec;
1959         ot->poll= nlaop_poll_tweakmode_off; 
1960         
1961         /* flags */
1962         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1963         
1964         /* id-props */
1965         ot->prop= RNA_def_enum(ot->srna, "type", fmodifier_type_items, 0, "Type", "");
1966         RNA_def_boolean(ot->srna, "only_active", 0, "Only Active", "Only add F-Modifier of the specified type to the active strip.");
1967 }
1968
1969 /* ******************** Copy F-Modifiers Operator *********************** */
1970
1971 static int nla_fmodifier_copy_exec(bContext *C, wmOperator *op)
1972 {
1973         bAnimContext ac;
1974         ListBase anim_data = {NULL, NULL};
1975         bAnimListElem *ale;
1976         int filter, ok=0;
1977         
1978         /* get editor data */
1979         if (ANIM_animdata_get_context(C, &ac) == 0)
1980                 return OPERATOR_CANCELLED;
1981         
1982         /* clear buffer first */
1983         free_fmodifiers_copybuf();
1984         
1985         /* get a list of the editable tracks being shown in the NLA */
1986         filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
1987         ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
1988         
1989         /* for each NLA-Track, add the specified modifier to all selected strips */
1990         for (ale= anim_data.first; ale; ale= ale->next) {
1991                 NlaTrack *nlt= (NlaTrack *)ale->data;
1992                 NlaStrip *strip;
1993                 
1994                 for (strip= nlt->strips.first; strip; strip=strip->next) {
1995                         /* only add F-Modifier if on active strip? */
1996                         if ((strip->flag & NLASTRIP_FLAG_ACTIVE)==0)
1997                                 continue;
1998                                 
1999                         // TODO: when 'active' vs 'all' boolean is added, change last param!
2000                         ok += ANIM_fmodifiers_copy_to_buf(&strip->modifiers, 0);
2001                 }
2002         }
2003         
2004         /* successful or not? */
2005         if (ok == 0) {
2006                 BKE_report(op->reports, RPT_ERROR, "No F-Modifiers available to be copied");
2007                 return OPERATOR_CANCELLED;
2008         }
2009         else
2010                 return OPERATOR_FINISHED;
2011 }
2012  
2013 void NLA_OT_fmodifier_copy (wmOperatorType *ot)
2014 {
2015         /* identifiers */
2016         ot->name= "Copy F-Modifiers";
2017         ot->idname= "NLA_OT_fmodifier_copy";
2018         ot->description= "Copy the F-Modifier(s) of the active NLA-Strip";
2019         
2020         /* api callbacks */
2021         ot->exec= nla_fmodifier_copy_exec;
2022         ot->poll= nlaop_poll_tweakmode_off; 
2023         
2024         /* flags */
2025         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2026         
2027         /* id-props */
2028         //ot->prop = RNA_def_boolean(ot->srna, "all", 1, "All F-Modifiers", "Copy all the F-Modifiers, instead of just the active one");
2029 }
2030
2031 /* ******************** Paste F-Modifiers Operator *********************** */
2032
2033 static int nla_fmodifier_paste_exec(bContext *C, wmOperator *op)
2034 {
2035         bAnimContext ac;
2036         ListBase anim_data = {NULL, NULL};
2037         bAnimListElem *ale;
2038         int filter, ok=0;
2039         
2040         /* get editor data */
2041         if (ANIM_animdata_get_context(C, &ac) == 0)
2042                 return OPERATOR_CANCELLED;
2043         
2044         /* get a list of the editable tracks being shown in the NLA */
2045         filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_SEL | ANIMFILTER_FOREDIT);
2046         ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
2047         
2048         /* for each NLA-Track, add the specified modifier to all selected strips */
2049         for (ale= anim_data.first; ale; ale= ale->next) {
2050                 NlaTrack *nlt= (NlaTrack *)ale->data;
2051                 NlaStrip *strip;
2052                 
2053                 for (strip= nlt->strips.first; strip; strip=strip->next) {
2054                         // TODO: do we want to replace existing modifiers? add user pref for that!
2055                         ok += ANIM_fmodifiers_paste_from_buf(&strip->modifiers, 0);
2056                 }
2057         }
2058         
2059         /* clean up */
2060         BLI_freelistN(&anim_data);
2061         
2062         /* successful or not? */
2063         if (ok) {
2064                 /* set notifier that things have changed */
2065                 /* set notifier that things have changed */
2066                 WM_event_add_notifier(C, NC_ANIMATION|ND_NLA|NA_EDITED, NULL);
2067                 return OPERATOR_FINISHED;
2068         }
2069         else {
2070                 BKE_report(op->reports, RPT_ERROR, "No F-Modifiers to paste");
2071                 return OPERATOR_CANCELLED;
2072         }
2073 }
2074  
2075 void NLA_OT_fmodifier_paste (wmOperatorType *ot)
2076 {
2077         /* identifiers */
2078         ot->name= "Paste F-Modifiers";
2079         ot->idname= "NLA_OT_fmodifier_paste";
2080         ot->description= "Add copied F-Modifiers to the selected NLA-Strips";
2081         
2082         /* api callbacks */
2083         ot->exec= nla_fmodifier_paste_exec;
2084         ot->poll= nlaop_poll_tweakmode_off;
2085         
2086         /* flags */
2087         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2088 }
2089
2090 /* *********************************************** */