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