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