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