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