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