10b25beddff198324d06d711b4a81b836d7dd850
[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., 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
65 #include "BIF_transform.h"
66
67 #include "RNA_access.h"
68 #include "RNA_define.h"
69 #include "RNA_enum_types.h"
70
71 #include "WM_api.h"
72 #include "WM_types.h"
73
74 #include "UI_interface.h"
75 #include "UI_resources.h"
76 #include "UI_view2d.h"
77
78 #include "nla_intern.h" // own include
79 #include "nla_private.h" // FIXME... maybe this shouldn't be included?
80
81 /* *********************************************** */
82 /* 'Special' Editing */
83
84 /* ******************** Tweak-Mode Operators ***************************** */
85 /* 'Tweak mode' allows the action referenced by the active NLA-strip to be edited 
86  * as if it were the normal Active-Action of its AnimData block. 
87  */
88
89 static int nlaedit_enable_tweakmode_exec (bContext *C, wmOperator *op)
90 {
91         bAnimContext ac;
92         
93         ListBase anim_data = {NULL, NULL};
94         bAnimListElem *ale;
95         int filter;
96         int ok=0;
97         
98         /* get editor data */
99         if (ANIM_animdata_get_context(C, &ac) == 0)
100                 return OPERATOR_CANCELLED;
101                 
102         /* get a list of the AnimData blocks being shown in the NLA */
103         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_ANIMDATA);
104         ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
105         
106         /* if no blocks, popup error? */
107         if (anim_data.first == NULL) {
108                 BKE_report(op->reports, RPT_ERROR, "No AnimData blocks to enter tweakmode for");
109                 return OPERATOR_CANCELLED;
110         }       
111         
112         /* for each AnimData block with NLA-data, try setting it in tweak-mode */
113         for (ale= anim_data.first; ale; ale= ale->next) {
114                 AnimData *adt= ale->data;
115                 
116                 /* try entering tweakmode if valid */
117                 ok += BKE_nla_tweakmode_enter(adt);
118         }
119         
120         /* free temp data */
121         BLI_freelistN(&anim_data);
122         
123         /* if we managed to enter tweakmode on at least one AnimData block, 
124          * set the flag for this in the active scene and send notifiers
125          */
126         if (ac.scene && ok) {
127                 /* set editing flag */
128                 ac.scene->flag |= SCE_NLA_EDIT_ON;
129                 
130                 /* set notifier that things have changed */
131                 ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_BOTH);
132                 WM_event_add_notifier(C, NC_SCENE, NULL);
133         }
134         else {
135                 BKE_report(op->reports, RPT_ERROR, "No active strip(s) to enter tweakmode on.");
136                 return OPERATOR_CANCELLED;
137         }
138         
139         /* done */
140         return OPERATOR_FINISHED;
141 }
142  
143 void NLA_OT_tweakmode_enter (wmOperatorType *ot)
144 {
145         /* identifiers */
146         ot->name= "Enter Tweak Mode";
147         ot->idname= "NLA_OT_tweakmode_enter";
148         ot->description= "Enter tweaking mode for the action referenced by the active strip.";
149         
150         /* api callbacks */
151         ot->exec= nlaedit_enable_tweakmode_exec;
152         ot->poll= nlaop_poll_tweakmode_off;
153         
154         /* flags */
155         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
156 }
157
158 /* ------------- */
159
160 static int nlaedit_disable_tweakmode_exec (bContext *C, wmOperator *op)
161 {
162         bAnimContext ac;
163         
164         ListBase anim_data = {NULL, NULL};
165         bAnimListElem *ale;
166         int filter;
167         
168         /* get editor data */
169         if (ANIM_animdata_get_context(C, &ac) == 0)
170                 return OPERATOR_CANCELLED;
171                 
172         /* get a list of the AnimData blocks being shown in the NLA */
173         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_ANIMDATA);
174         ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
175         
176         /* if no blocks, popup error? */
177         if (anim_data.first == NULL) {
178                 BKE_report(op->reports, RPT_ERROR, "No AnimData blocks to enter tweakmode for");
179                 return OPERATOR_CANCELLED;
180         }       
181         
182         /* for each AnimData block with NLA-data, try exitting tweak-mode */
183         for (ale= anim_data.first; ale; ale= ale->next) {
184                 AnimData *adt= ale->data;
185                 
186                 /* try entering tweakmode if valid */
187                 BKE_nla_tweakmode_exit(adt);
188         }
189         
190         /* free temp data */
191         BLI_freelistN(&anim_data);
192         
193         /* if we managed to enter tweakmode on at least one AnimData block, 
194          * set the flag for this in the active scene and send notifiers
195          */
196         if (ac.scene) {
197                 /* clear editing flag */
198                 ac.scene->flag &= ~SCE_NLA_EDIT_ON;
199                 
200                 /* set notifier that things have changed */
201                 ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_BOTH);
202                 WM_event_add_notifier(C, NC_SCENE, NULL);
203         }
204         
205         /* done */
206         return OPERATOR_FINISHED;
207 }
208  
209 void NLA_OT_tweakmode_exit (wmOperatorType *ot)
210 {
211         /* identifiers */
212         ot->name= "Exit Tweak Mode";
213         ot->idname= "NLA_OT_tweakmode_exit";
214         ot->description= "Exit tweaking mode for the action referenced by the active strip.";
215         
216         /* api callbacks */
217         ot->exec= nlaedit_disable_tweakmode_exec;
218         ot->poll= nlaop_poll_tweakmode_on;
219         
220         /* flags */
221         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
222 }
223
224 /* *********************************************** */
225 /* NLA Editing Operations (Constructive/Destructive) */
226
227 /* ******************** Add Action-Clip Operator ***************************** */
228 /* Add a new Action-Clip strip to the active track (or the active block if no space in the track) */
229
230 /* pop up menu allowing user to choose the action to use */
231 static int nlaedit_add_actionclip_invoke (bContext *C, wmOperator *op, wmEvent *evt)
232 {
233         Main *m= CTX_data_main(C);
234         bAction *act;
235         uiPopupMenu *pup;
236         uiLayout *layout;
237         
238         pup= uiPupMenuBegin(C, "Add Action Clip", 0);
239         layout= uiPupMenuLayout(pup);
240         
241         /* loop through Actions in Main database, adding as items in the menu */
242         for (act= m->action.first; act; act= act->id.next)
243                 uiItemStringO(layout, act->id.name+2, 0, "NLA_OT_add_actionclip", "action", act->id.name);
244         uiItemS(layout);
245         
246         uiPupMenuEnd(C, pup);
247         
248         return OPERATOR_CANCELLED;
249 }
250
251 /* add the specified action as new strip */
252 static int nlaedit_add_actionclip_exec (bContext *C, wmOperator *op)
253 {
254         bAnimContext ac;
255         Scene *scene;
256         
257         ListBase anim_data = {NULL, NULL};
258         bAnimListElem *ale;
259         int filter, items;
260         
261         bAction *act = NULL;
262         char actname[22];
263         float cfra;
264         
265         /* get editor data */
266         if (ANIM_animdata_get_context(C, &ac) == 0)
267                 return OPERATOR_CANCELLED;
268                 
269         scene= ac.scene;
270         cfra= (float)CFRA;
271                 
272         /* get action to use */
273         RNA_string_get(op->ptr, "action", actname);
274         act= (bAction *)find_id("AC", actname+2);
275         
276         if (act == NULL) {
277                 BKE_report(op->reports, RPT_ERROR, "No valid Action to add.");
278                 //printf("Add strip - actname = '%s' \n", actname);
279                 return OPERATOR_CANCELLED;
280         }
281         
282         /* get a list of the editable tracks being shown in the NLA
283          *      - this is limited to active ones for now, but could be expanded to 
284          */
285         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_ACTIVE | ANIMFILTER_NLATRACKS | ANIMFILTER_FOREDIT);
286         items= ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
287         
288         if (items == 0) {
289                 BKE_report(op->reports, RPT_ERROR, "No active track(s) to add strip to.");
290                 return OPERATOR_CANCELLED;
291         }
292         
293         /* for every active track, try to add strip to free space in track or to the top of the stack if no space */
294         for (ale= anim_data.first; ale; ale= ale->next) {
295                 NlaTrack *nlt= (NlaTrack *)ale->data;
296                 AnimData *adt= BKE_animdata_from_id(ale->id);
297                 NlaStrip *strip= NULL;
298                 
299                 /* create a new strip, and offset it to start on the current frame */
300                 strip= add_nlastrip(act);
301                 
302                 strip->end              += (cfra - strip->start);
303                 strip->start     = cfra;
304                 
305                 /* firstly try adding strip to our current track, but if that fails, add to a new track */
306                 if (BKE_nlatrack_add_strip(nlt, strip) == 0) {
307                         /* trying to add to the current failed (no space), 
308                          * so add a new track to the stack, and add to that...
309                          */
310                         nlt= add_nlatrack(adt, NULL);
311                         BKE_nlatrack_add_strip(nlt, strip);
312                 }
313         }
314         
315         /* free temp data */
316         BLI_freelistN(&anim_data);
317         
318         /* set notifier that things have changed */
319         ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_BOTH);
320         WM_event_add_notifier(C, NC_SCENE, NULL);
321         
322         /* done */
323         return OPERATOR_FINISHED;
324 }
325
326 void NLA_OT_add_actionclip (wmOperatorType *ot)
327 {
328         /* identifiers */
329         ot->name= "Add Action Strip";
330         ot->idname= "NLA_OT_add_actionclip";
331         ot->description= "Add an Action-Clip strip (i.e. an NLA Strip referencing an Action) to the active track.";
332         
333         /* api callbacks */
334         ot->invoke= nlaedit_add_actionclip_invoke;
335         ot->exec= nlaedit_add_actionclip_exec;
336         ot->poll= nlaop_poll_tweakmode_off;
337         
338         /* flags */
339         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
340         
341         /* props */
342                 // TODO: this would be nicer as an ID-pointer...
343         RNA_def_string(ot->srna, "action", "", 21, "Action", "Name of Action to add as a new Action-Clip Strip.");
344 }
345
346 /* ******************** Add Transition Operator ***************************** */
347 /* Add a new transition strip between selected strips */
348
349 /* add the specified action as new strip */
350 static int nlaedit_add_transition_exec (bContext *C, wmOperator *op)
351 {
352         bAnimContext ac;
353         
354         ListBase anim_data = {NULL, NULL};
355         bAnimListElem *ale;
356         int filter;
357         
358         int done = 0;
359         
360         /* get editor data */
361         if (ANIM_animdata_get_context(C, &ac) == 0)
362                 return OPERATOR_CANCELLED;
363         
364         /* get a list of the editable tracks being shown in the NLA */
365         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_NLATRACKS | ANIMFILTER_FOREDIT);
366         ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
367         
368         /* for each track, find pairs of strips to add transitions to */
369         for (ale= anim_data.first; ale; ale= ale->next) {
370                 NlaTrack *nlt= (NlaTrack *)ale->data;
371                 NlaStrip *s1, *s2;
372                 
373                 /* get initial pair of strips */
374                 if ELEM(nlt->strips.first, NULL, nlt->strips.last)
375                         continue;
376                 s1= nlt->strips.first;
377                 s2= s1->next;
378                 
379                 /* loop over strips */
380                 for (; s1 && s2; s1=s2, s2=s2->next) {
381                         NlaStrip *strip;
382                         
383                         /* check if both are selected */
384                         if ELEM(0, (s1->flag & NLASTRIP_FLAG_SELECT), (s2->flag & NLASTRIP_FLAG_SELECT))
385                                 continue;
386                         /* check if there's space between the two */
387                         if (IS_EQ(s1->end, s2->start))
388                                 continue;
389                         /* make neither one is a transition 
390                          *      - although this is impossible to create with the standard tools, 
391                          *        the user may have altered the settings
392                          */
393                         if (ELEM(NLASTRIP_TYPE_TRANSITION, s1->type, s2->type))
394                                 continue;
395                                 
396                         /* allocate new strip */
397                         strip= MEM_callocN(sizeof(NlaStrip), "NlaStrip");
398                         BLI_insertlinkafter(&nlt->strips, s1, strip);
399                         
400                         /* set the type */
401                         strip->type= NLASTRIP_TYPE_TRANSITION;
402                         
403                         /* generic settings 
404                          *      - selected flag to highlight this to the user
405                          *      - auto-blends to ensure that blend in/out values are automatically 
406                          *        determined by overlaps of strips
407                          */
408                         strip->flag = NLASTRIP_FLAG_SELECT|NLASTRIP_FLAG_AUTO_BLENDS;
409                         
410                         /* range is simply defined as the endpoints of the adjacent strips */
411                         strip->start    = s1->end;
412                         strip->end              = s2->start;
413                         
414                         /* scale and repeat aren't of any use, but shouldn't ever be 0 */
415                         strip->scale= 1.0f;
416                         strip->repeat = 1.0f;
417                         
418                         /* make note of this */
419                         done++;
420                 }
421         }
422         
423         /* free temp data */
424         BLI_freelistN(&anim_data);
425         
426         /* was anything added? */
427         if (done) {
428                 /* set notifier that things have changed */
429                 ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_BOTH);
430                 WM_event_add_notifier(C, NC_SCENE, NULL);
431                 
432                 /* done */
433                 return OPERATOR_FINISHED;
434         }
435         else {
436                 BKE_report(op->reports, RPT_ERROR, "Needs at least a pair of adjacent selected strips.");
437                 return OPERATOR_CANCELLED;
438         }
439 }
440
441 void NLA_OT_add_transition (wmOperatorType *ot)
442 {
443         /* identifiers */
444         ot->name= "Add Transition";
445         ot->idname= "NLA_OT_add_transition";
446         ot->description= "Add a transition strip between two adjacent selected strips.";
447         
448         /* api callbacks */
449         ot->exec= nlaedit_add_transition_exec;
450         ot->poll= nlaop_poll_tweakmode_off;
451         
452         /* flags */
453         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
454 }
455
456 /* ******************** Duplicate Strips Operator ************************** */
457 /* Duplicates the selected NLA-Strips, putting them on new tracks above the one
458  * the originals were housed in.
459  */
460  
461 static int nlaedit_duplicate_exec (bContext *C, wmOperator *op)
462 {
463         bAnimContext ac;
464         
465         ListBase anim_data = {NULL, NULL};
466         bAnimListElem *ale;
467         int filter;
468         
469         short done = 0;
470         
471         /* get editor data */
472         if (ANIM_animdata_get_context(C, &ac) == 0)
473                 return OPERATOR_CANCELLED;
474                 
475         /* get a list of editable tracks being shown in the NLA */
476         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_NLATRACKS | ANIMFILTER_FOREDIT);
477         ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
478         
479         /* duplicate strips in tracks starting from the last one so that we're 
480          * less likely to duplicate strips we just duplicated...
481          */
482         for (ale= anim_data.last; ale; ale= ale->prev) {
483                 NlaTrack *nlt= (NlaTrack *)ale->data;
484                 AnimData *adt= BKE_animdata_from_id(ale->id);
485                 NlaStrip *strip, *nstrip, *next;
486                 NlaTrack *track;
487                 
488                 for (strip= nlt->strips.first; strip; strip= next) {
489                         next= strip->next;
490                         
491                         /* if selected, split the strip at its midpoint */
492                         if (strip->flag & NLASTRIP_FLAG_SELECT) {
493                                 /* make a copy (assume that this is possible) */
494                                 nstrip= copy_nlastrip(strip);
495                                 
496                                 /* in case there's no space in the track above, or we haven't got a reference to it yet, try adding */
497                                 if (BKE_nlatrack_add_strip(nlt->next, nstrip) == 0) {
498                                         /* need to add a new track above the one above the current one
499                                          *      - if the current one is the last one, nlt->next will be NULL, which defaults to adding 
500                                          *        at the top of the stack anyway...
501                                          */
502                                         track= add_nlatrack(adt, nlt->next);
503                                         BKE_nlatrack_add_strip(track, nstrip);
504                                 }
505                                 
506                                 /* deselect the original and the active flag */
507                                 strip->flag &= ~(NLASTRIP_FLAG_SELECT|NLASTRIP_FLAG_ACTIVE);
508                                 
509                                 done++;
510                         }
511                 }
512         }
513         
514         /* free temp data */
515         BLI_freelistN(&anim_data);
516         
517         if (done) {
518                 /* set notifier that things have changed */
519                 ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_BOTH);
520                 WM_event_add_notifier(C, NC_SCENE, NULL);
521                 
522                 /* done */
523                 return OPERATOR_FINISHED;
524         }
525         else
526                 return OPERATOR_CANCELLED;
527 }
528
529 static int nlaedit_duplicate_invoke(bContext *C, wmOperator *op, wmEvent *event)
530 {
531         nlaedit_duplicate_exec(C, op);
532         
533         RNA_int_set(op->ptr, "mode", TFM_TIME_TRANSLATE); // XXX
534         WM_operator_name_call(C, "TFM_OT_transform", WM_OP_INVOKE_REGION_WIN, op->ptr);
535
536         return OPERATOR_FINISHED;
537 }
538
539 void NLA_OT_duplicate (wmOperatorType *ot)
540 {
541         /* identifiers */
542         ot->name= "Duplicate Strips";
543         ot->idname= "NLA_OT_duplicate";
544         ot->description= "Duplicate selected NLA-Strips, adding the new strips in new tracks above the originals.";
545         
546         /* api callbacks */
547         ot->invoke= nlaedit_duplicate_invoke;
548         ot->exec= nlaedit_duplicate_exec;
549         ot->poll= nlaop_poll_tweakmode_off;
550         
551         /* flags */
552         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
553         
554         /* to give to transform */
555         RNA_def_int(ot->srna, "mode", TFM_TRANSLATION, 0, INT_MAX, "Mode", "", 0, INT_MAX);
556 }
557
558 /* ******************** Delete Strips Operator ***************************** */
559 /* Deletes the selected NLA-Strips */
560
561 static int nlaedit_delete_exec (bContext *C, wmOperator *op)
562 {
563         bAnimContext ac;
564         
565         ListBase anim_data = {NULL, NULL};
566         bAnimListElem *ale;
567         int filter;
568         
569         /* get editor data */
570         if (ANIM_animdata_get_context(C, &ac) == 0)
571                 return OPERATOR_CANCELLED;
572                 
573         /* get a list of the editable tracks being shown in the NLA */
574         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_NLATRACKS | ANIMFILTER_FOREDIT);
575         ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
576         
577         /* for each NLA-Track, delete all selected strips */
578         for (ale= anim_data.first; ale; ale= ale->next) {
579                 NlaTrack *nlt= (NlaTrack *)ale->data;
580                 NlaStrip *strip, *nstrip;
581                 
582                 for (strip= nlt->strips.first; strip; strip= nstrip) {
583                         nstrip= strip->next;
584                         
585                         /* if selected, delete */
586                         if (strip->flag & NLASTRIP_FLAG_SELECT) {
587                                 /* if a strip either side of this was a transition, delete those too */
588                                 if ((strip->prev) && (strip->prev->type == NLASTRIP_TYPE_TRANSITION)) 
589                                         free_nlastrip(&nlt->strips, strip->prev);
590                                 if ((nstrip) && (nstrip->type == NLASTRIP_TYPE_TRANSITION)) {
591                                         nstrip= nstrip->next;
592                                         free_nlastrip(&nlt->strips, strip->next);
593                                 }
594                                 
595                                 /* finally, delete this strip */
596                                 free_nlastrip(&nlt->strips, strip);
597                         }
598                 }
599         }
600         
601         /* free temp data */
602         BLI_freelistN(&anim_data);
603         
604         /* set notifier that things have changed */
605         ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_BOTH);
606         WM_event_add_notifier(C, NC_SCENE, NULL);
607         
608         /* done */
609         return OPERATOR_FINISHED;
610 }
611
612 void NLA_OT_delete (wmOperatorType *ot)
613 {
614         /* identifiers */
615         ot->name= "Delete Strips";
616         ot->idname= "NLA_OT_delete";
617         ot->description= "Delete selected strips.";
618         
619         /* api callbacks */
620         ot->exec= nlaedit_delete_exec;
621         ot->poll= nlaop_poll_tweakmode_off;
622         
623         /* flags */
624         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
625 }
626
627 /* ******************** Split Strips Operator ***************************** */
628 /* Splits the selected NLA-Strips into two strips at the midpoint of the strip */
629 // TODO's? 
630 //      - multiple splits
631 //      - variable-length splits?
632
633 static int nlaedit_split_exec (bContext *C, wmOperator *op)
634 {
635         bAnimContext ac;
636         
637         ListBase anim_data = {NULL, NULL};
638         bAnimListElem *ale;
639         int filter;
640         
641         /* get editor data */
642         if (ANIM_animdata_get_context(C, &ac) == 0)
643                 return OPERATOR_CANCELLED;
644                 
645         /* get a list of editable tracks being shown in the NLA */
646         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_NLATRACKS | ANIMFILTER_FOREDIT);
647         ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
648         
649         /* for each NLA-Track, split all selected strips into two strips */
650         for (ale= anim_data.first; ale; ale= ale->next) {
651                 NlaTrack *nlt= (NlaTrack *)ale->data;
652                 NlaStrip *strip, *nstrip, *next;
653                 
654                 for (strip= nlt->strips.first; strip; strip= next) {
655                         next= strip->next;
656                         
657                         /* if selected, split the strip at its midpoint */
658                         if (strip->flag & NLASTRIP_FLAG_SELECT) {
659                                 float midframe, midaframe, len;
660                                 
661                                 /* calculate the frames to do the splitting at */
662                                         /* strip extents */
663                                 len= strip->end - strip->start;
664                                 if (IS_EQ(len, 0.0f)) 
665                                         continue;
666                                 else
667                                         midframe= strip->start + (len / 2.0f);
668                                         
669                                         /* action range */
670                                 len= strip->actend - strip->actstart;
671                                 if (IS_EQ(len, 0.0f))
672                                         midaframe= strip->actend;
673                                 else
674                                         midaframe= strip->actstart + (len / 2.0f);
675                                 
676                                 /* make a copy (assume that this is possible) and append
677                                  * it immediately after the current strip
678                                  */
679                                 nstrip= copy_nlastrip(strip);
680                                 BLI_insertlinkafter(&nlt->strips, strip, nstrip);
681                                 
682                                 /* set the endpoint of the first strip and the start of the new strip 
683                                  * to the midframe values calculated above
684                                  */
685                                 strip->end= midframe;
686                                 nstrip->start= midframe;
687                                 
688                                 strip->actend= midaframe;
689                                 nstrip->actstart= midaframe;
690                                 
691                                 /* clear the active flag from the copy */
692                                 nstrip->flag &= ~NLASTRIP_FLAG_ACTIVE;
693                         }
694                 }
695         }
696         
697         /* free temp data */
698         BLI_freelistN(&anim_data);
699         
700         /* set notifier that things have changed */
701         ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_BOTH);
702         WM_event_add_notifier(C, NC_SCENE, NULL);
703         
704         /* done */
705         return OPERATOR_FINISHED;
706 }
707
708 void NLA_OT_split (wmOperatorType *ot)
709 {
710         /* identifiers */
711         ot->name= "Split Strips";
712         ot->idname= "NLA_OT_split";
713         ot->description= "Split selected strips at their midpoints.";
714         
715         /* api callbacks */
716         ot->exec= nlaedit_split_exec;
717         ot->poll= nlaop_poll_tweakmode_off;
718         
719         /* flags */
720         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
721 }
722
723 /* *********************************************** */
724 /* NLA Editing Operations (Modifying) */
725
726 /* ******************** Move Strips Up Operator ************************** */
727 /* Tries to move the selected strips into the track above if possible. */
728
729 static int nlaedit_move_up_exec (bContext *C, wmOperator *op)
730 {
731         bAnimContext ac;
732         
733         ListBase anim_data = {NULL, NULL};
734         bAnimListElem *ale;
735         int filter;
736         
737         BeztEditData bed;
738         
739         /* get editor data */
740         if (ANIM_animdata_get_context(C, &ac) == 0)
741                 return OPERATOR_CANCELLED;
742                 
743         /* get a list of the editable tracks being shown in the NLA */
744         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_NLATRACKS | ANIMFILTER_FOREDIT);
745         ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
746         
747         /* init the editing data */
748         memset(&bed, 0, sizeof(BeztEditData));
749         
750         /* since we're potentially moving strips from lower tracks to higher tracks, we should
751          * loop over the tracks in reverse order to avoid moving earlier strips up multiple tracks
752          */
753         for (ale= anim_data.last; ale; ale= ale->prev) {
754                 NlaTrack *nlt= (NlaTrack *)ale->data;
755                 NlaTrack *nltn= nlt->next;
756                 NlaStrip *strip, *stripn;
757                 
758                 /* if this track has no tracks after it, skip for now... */
759                 if (nltn == NULL)
760                         continue;
761                 
762                 /* for every selected strip, try to move */
763                 for (strip= nlt->strips.first; strip; strip= stripn) {
764                         stripn= strip->next;
765                         
766                         if (strip->flag & NLASTRIP_FLAG_SELECT) {
767                                 /* check if the track above has room for this strip */
768                                 if (BKE_nlatrack_has_space(nltn, strip->start, strip->end)) {
769                                         /* remove from its current track, and add to the one above (it 'should' work, so no need to worry) */
770                                         BLI_remlink(&nlt->strips, strip);
771                                         BKE_nlatrack_add_strip(nltn, strip);
772                                 }
773                         }
774                 }
775         }
776         
777         /* free temp data */
778         BLI_freelistN(&anim_data);
779         
780         /* set notifier that things have changed */
781         ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_BOTH);
782         WM_event_add_notifier(C, NC_SCENE, NULL);
783         
784         /* done */
785         return OPERATOR_FINISHED;
786 }
787
788 void NLA_OT_move_up (wmOperatorType *ot)
789 {
790         /* identifiers */
791         ot->name= "Move Strips Up";
792         ot->idname= "NLA_OT_move_up";
793         ot->description= "Move selected strips up a track if there's room.";
794         
795         /* api callbacks */
796         ot->exec= nlaedit_move_up_exec;
797         ot->poll= nlaop_poll_tweakmode_off;
798         
799         /* flags */
800         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
801 }
802
803 /* ******************** Move Strips Down Operator ************************** */
804 /* Tries to move the selected strips into the track above if possible. */
805
806 static int nlaedit_move_down_exec (bContext *C, wmOperator *op)
807 {
808         bAnimContext ac;
809         
810         ListBase anim_data = {NULL, NULL};
811         bAnimListElem *ale;
812         int filter;
813         
814         BeztEditData bed;
815         
816         /* get editor data */
817         if (ANIM_animdata_get_context(C, &ac) == 0)
818                 return OPERATOR_CANCELLED;
819                 
820         /* get a list of the editable tracks being shown in the NLA */
821         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_NLATRACKS | ANIMFILTER_FOREDIT);
822         ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
823         
824         /* init the editing data */
825         memset(&bed, 0, sizeof(BeztEditData));
826         
827         /* loop through the tracks in normal order, since we're pushing strips down,
828          * strips won't get operated on twice
829          */
830         for (ale= anim_data.first; ale; ale= ale->next) {
831                 NlaTrack *nlt= (NlaTrack *)ale->data;
832                 NlaTrack *nltp= nlt->prev;
833                 NlaStrip *strip, *stripn;
834                 
835                 /* if this track has no tracks before it, skip for now... */
836                 if (nltp == NULL)
837                         continue;
838                 
839                 /* for every selected strip, try to move */
840                 for (strip= nlt->strips.first; strip; strip= stripn) {
841                         stripn= strip->next;
842                         
843                         if (strip->flag & NLASTRIP_FLAG_SELECT) {
844                                 /* check if the track below has room for this strip */
845                                 if (BKE_nlatrack_has_space(nltp, strip->start, strip->end)) {
846                                         /* remove from its current track, and add to the one above (it 'should' work, so no need to worry) */
847                                         BLI_remlink(&nlt->strips, strip);
848                                         BKE_nlatrack_add_strip(nltp, strip);
849                                 }
850                         }
851                 }
852         }
853         
854         /* free temp data */
855         BLI_freelistN(&anim_data);
856         
857         /* set notifier that things have changed */
858         ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_BOTH);
859         WM_event_add_notifier(C, NC_SCENE, NULL);
860         
861         /* done */
862         return OPERATOR_FINISHED;
863 }
864
865 void NLA_OT_move_down (wmOperatorType *ot)
866 {
867         /* identifiers */
868         ot->name= "Move Strips Down";
869         ot->idname= "NLA_OT_move_down";
870         ot->description= "Move selected strips down a track if there's room.";
871         
872         /* api callbacks */
873         ot->exec= nlaedit_move_down_exec;
874         ot->poll= nlaop_poll_tweakmode_off;
875         
876         /* flags */
877         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
878 }
879
880 /* ******************** Apply Scale Operator ***************************** */
881 /* Reset the scaling of the selected strips to 1.0f */
882
883 /* apply scaling to keyframe */
884 static short bezt_apply_nlamapping (BeztEditData *bed, BezTriple *bezt)
885 {
886         /* NLA-strip which has this scaling is stored in bed->data */
887         NlaStrip *strip= (NlaStrip *)bed->data;
888         
889         /* adjust all the times */
890         bezt->vec[0][0]= nlastrip_get_frame(strip, bezt->vec[0][0], NLATIME_CONVERT_MAP);
891         bezt->vec[1][0]= nlastrip_get_frame(strip, bezt->vec[1][0], NLATIME_CONVERT_MAP);
892         bezt->vec[2][0]= nlastrip_get_frame(strip, bezt->vec[2][0], NLATIME_CONVERT_MAP);
893         
894         /* nothing to return or else we exit */
895         return 0;
896 }
897
898 static int nlaedit_apply_scale_exec (bContext *C, wmOperator *op)
899 {
900         bAnimContext ac;
901         
902         ListBase anim_data = {NULL, NULL};
903         bAnimListElem *ale;
904         int filter;
905         
906         BeztEditData bed;
907         
908         /* get editor data */
909         if (ANIM_animdata_get_context(C, &ac) == 0)
910                 return OPERATOR_CANCELLED;
911                 
912         /* get a list of the editable tracks being shown in the NLA */
913         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_NLATRACKS | ANIMFILTER_FOREDIT);
914         ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
915         
916         /* init the editing data */
917         memset(&bed, 0, sizeof(BeztEditData));
918         
919         /* for each NLA-Track, apply scale of all selected strips */
920         for (ale= anim_data.first; ale; ale= ale->next) {
921                 NlaTrack *nlt= (NlaTrack *)ale->data;
922                 NlaStrip *strip;
923                 
924                 for (strip= nlt->strips.first; strip; strip= strip->next) {
925                         /* strip must be selected, and must be action-clip only (transitions don't have scale) */
926                         if ((strip->flag & NLASTRIP_FLAG_SELECT) && (strip->type == NLASTRIP_TYPE_CLIP)) {
927                                 /* if the referenced action is used by other strips, make this strip use its own copy */
928                                 if (strip->act == NULL) 
929                                         continue;
930                                 if (strip->act->id.us > 1) {
931                                         /* make a copy of the Action to work on */
932                                         bAction *act= copy_action(strip->act);
933                                         
934                                         /* set this as the new referenced action, decrementing the users of the old one */
935                                         strip->act->id.us--;
936                                         strip->act= act;
937                                 }
938                                 
939                                 /* setup iterator, and iterate over all the keyframes in the action, applying this scaling */
940                                 bed.data= strip;
941                                 ANIM_animchanneldata_keys_bezier_loop(&bed, strip->act, ALE_ACT, NULL, bezt_apply_nlamapping, calchandles_fcurve, 0);
942                                 
943                                 /* clear scale of strip now that it has been applied,
944                                  * and recalculate the extents of the action now that it has been scaled
945                                  * but leave everything else alone 
946                                  */
947                                 strip->scale= 1.0f;
948                                 calc_action_range(strip->act, &strip->actstart, &strip->actend, 1);
949                         }
950                 }
951         }
952         
953         /* free temp data */
954         BLI_freelistN(&anim_data);
955         
956         /* set notifier that things have changed */
957         ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_BOTH);
958         WM_event_add_notifier(C, NC_SCENE, NULL);
959         
960         /* done */
961         return OPERATOR_FINISHED;
962 }
963
964 void NLA_OT_apply_scale (wmOperatorType *ot)
965 {
966         /* identifiers */
967         ot->name= "Apply Scale";
968         ot->idname= "NLA_OT_apply_scale";
969         ot->description= "Apply scaling of selected strips to their referenced Actions.";
970         
971         /* api callbacks */
972         ot->exec= nlaedit_apply_scale_exec;
973         ot->poll= nlaop_poll_tweakmode_off;
974         
975         /* flags */
976         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
977 }
978
979 /* ******************** Clear Scale Operator ***************************** */
980 /* Reset the scaling of the selected strips to 1.0f */
981
982 static int nlaedit_clear_scale_exec (bContext *C, wmOperator *op)
983 {
984         bAnimContext ac;
985         
986         ListBase anim_data = {NULL, NULL};
987         bAnimListElem *ale;
988         int filter;
989         
990         /* get editor data */
991         if (ANIM_animdata_get_context(C, &ac) == 0)
992                 return OPERATOR_CANCELLED;
993                 
994         /* get a list of the editable tracks being shown in the NLA */
995         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_NLATRACKS | ANIMFILTER_FOREDIT);
996         ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
997         
998         /* for each NLA-Track, reset scale of all selected strips */
999         for (ale= anim_data.first; ale; ale= ale->next) {
1000                 NlaTrack *nlt= (NlaTrack *)ale->data;
1001                 NlaStrip *strip;
1002                 
1003                 for (strip= nlt->strips.first; strip; strip= strip->next) {
1004                         /* strip must be selected, and must be action-clip only (transitions don't have scale) */
1005                         if ((strip->flag & NLASTRIP_FLAG_SELECT) && (strip->type == NLASTRIP_TYPE_CLIP)) {
1006                                 PointerRNA strip_ptr;
1007                                 
1008                                 RNA_pointer_create(NULL, &RNA_NlaStrip, strip, &strip_ptr);
1009                                 RNA_float_set(&strip_ptr, "scale", 1.0f);
1010                         }
1011                 }
1012         }
1013         
1014         /* free temp data */
1015         BLI_freelistN(&anim_data);
1016         
1017         /* set notifier that things have changed */
1018         ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_BOTH);
1019         WM_event_add_notifier(C, NC_SCENE, NULL);
1020         
1021         /* done */
1022         return OPERATOR_FINISHED;
1023 }
1024
1025 void NLA_OT_clear_scale (wmOperatorType *ot)
1026 {
1027         /* identifiers */
1028         ot->name= "Clear Scale";
1029         ot->idname= "NLA_OT_clear_scale";
1030         ot->description= "Reset scaling of selected strips.";
1031         
1032         /* api callbacks */
1033         ot->exec= nlaedit_clear_scale_exec;
1034         ot->poll= nlaop_poll_tweakmode_off;
1035         
1036         /* flags */
1037         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1038 }
1039
1040 /* *********************************************** */
1041 /* NLA Modifiers */
1042
1043 /* ******************** Add F-Modifier Operator *********************** */
1044
1045 /* present a special customised popup menu for this, with some filtering */
1046 static int nla_fmodifier_add_invoke (bContext *C, wmOperator *op, wmEvent *event)
1047 {
1048         uiPopupMenu *pup;
1049         uiLayout *layout;
1050         int i;
1051         
1052         pup= uiPupMenuBegin(C, "Add F-Modifier", 0);
1053         layout= uiPupMenuLayout(pup);
1054         
1055         /* start from 1 to skip the 'Invalid' modifier type */
1056         for (i = 1; i < FMODIFIER_NUM_TYPES; i++) {
1057                 FModifierTypeInfo *fmi= get_fmodifier_typeinfo(i);
1058                 
1059                 /* check if modifier is valid for this context */
1060                 if (fmi == NULL)
1061                         continue;
1062                 if (i == FMODIFIER_TYPE_CYCLES) /* we already have repeat... */
1063                         continue;
1064                 
1065                 /* add entry to add this type of modifier */
1066                 uiItemEnumO(layout, fmi->name, 0, "NLA_OT_fmodifier_add", "type", i);
1067         }
1068         uiItemS(layout);
1069         
1070         uiPupMenuEnd(C, pup);
1071         
1072         return OPERATOR_CANCELLED;
1073 }
1074
1075 static int nla_fmodifier_add_exec(bContext *C, wmOperator *op)
1076 {
1077         bAnimContext ac;
1078         
1079         ListBase anim_data = {NULL, NULL};
1080         bAnimListElem *ale;
1081         int filter;
1082         
1083         FModifier *fcm;
1084         int type= RNA_enum_get(op->ptr, "type");
1085         short onlyActive = RNA_boolean_get(op->ptr, "only_active");
1086         
1087         /* get editor data */
1088         if (ANIM_animdata_get_context(C, &ac) == 0)
1089                 return OPERATOR_CANCELLED;
1090                 
1091         /* get a list of the editable tracks being shown in the NLA */
1092         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_NLATRACKS | ANIMFILTER_FOREDIT);
1093         ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
1094         
1095         /* for each NLA-Track, add the specified modifier to all selected strips */
1096         for (ale= anim_data.first; ale; ale= ale->next) {
1097                 NlaTrack *nlt= (NlaTrack *)ale->data;
1098                 NlaStrip *strip;
1099                 int i = 1;
1100                 
1101                 for (strip= nlt->strips.first; strip; strip=strip->next, i++) {
1102                         /* only add F-Modifier if on active strip? */
1103                         if ((onlyActive) && (strip->flag & NLASTRIP_FLAG_ACTIVE)==0)
1104                                 continue;
1105                         
1106                         /* add F-Modifier of specified type to selected, and make it the active one */
1107                         fcm= add_fmodifier(&strip->modifiers, type);
1108                         
1109                         if (fcm)
1110                                 set_active_fmodifier(&strip->modifiers, fcm);
1111                         else {
1112                                 char errormsg[128];
1113                                 sprintf(errormsg, "Modifier couldn't be added to (%s : %d). See console for details.", nlt->name, i);
1114                                 
1115                                 BKE_report(op->reports, RPT_ERROR, errormsg);
1116                         }
1117                 }
1118         }
1119         
1120         /* free temp data */
1121         BLI_freelistN(&anim_data);
1122         
1123         /* set notifier that things have changed */
1124         ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_BOTH);
1125         WM_event_add_notifier(C, NC_SCENE, NULL);
1126         
1127         /* done */
1128         return OPERATOR_FINISHED;
1129 }
1130  
1131 void NLA_OT_fmodifier_add (wmOperatorType *ot)
1132 {
1133         /* identifiers */
1134         ot->name= "Add F-Modifier";
1135         ot->idname= "NLA_OT_fmodifier_add";
1136         
1137         /* api callbacks */
1138         ot->invoke= nla_fmodifier_add_invoke;
1139         ot->exec= nla_fmodifier_add_exec;
1140         ot->poll= nlaop_poll_tweakmode_off; 
1141         
1142         /* flags */
1143         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1144         
1145         /* id-props */
1146         RNA_def_enum(ot->srna, "type", fmodifier_type_items, 0, "Type", "");
1147         RNA_def_boolean(ot->srna, "only_active", 0, "Only Active", "Only add F-Modifier of the specified type to the active strip.");
1148 }
1149
1150 /* *********************************************** */