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