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