NLA SoC: Start of 'Meta' Strips
[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         /* get editor data */
738         if (ANIM_animdata_get_context(C, &ac) == 0)
739                 return OPERATOR_CANCELLED;
740                 
741         /* get a list of the editable tracks being shown in the NLA */
742         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_NLATRACKS | ANIMFILTER_FOREDIT);
743         ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
744         
745         /* since we're potentially moving strips from lower tracks to higher tracks, we should
746          * loop over the tracks in reverse order to avoid moving earlier strips up multiple tracks
747          */
748         for (ale= anim_data.last; ale; ale= ale->prev) {
749                 NlaTrack *nlt= (NlaTrack *)ale->data;
750                 NlaTrack *nltn= nlt->next;
751                 NlaStrip *strip, *stripn;
752                 
753                 /* if this track has no tracks after it, skip for now... */
754                 if (nltn == NULL)
755                         continue;
756                 
757                 /* for every selected strip, try to move */
758                 for (strip= nlt->strips.first; strip; strip= stripn) {
759                         stripn= strip->next;
760                         
761                         if (strip->flag & NLASTRIP_FLAG_SELECT) {
762                                 /* check if the track above has room for this strip */
763                                 if (BKE_nlatrack_has_space(nltn, strip->start, strip->end)) {
764                                         /* remove from its current track, and add to the one above (it 'should' work, so no need to worry) */
765                                         BLI_remlink(&nlt->strips, strip);
766                                         BKE_nlatrack_add_strip(nltn, strip);
767                                 }
768                         }
769                 }
770         }
771         
772         /* free temp data */
773         BLI_freelistN(&anim_data);
774         
775         /* set notifier that things have changed */
776         ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_BOTH);
777         WM_event_add_notifier(C, NC_SCENE, NULL);
778         
779         /* done */
780         return OPERATOR_FINISHED;
781 }
782
783 void NLA_OT_move_up (wmOperatorType *ot)
784 {
785         /* identifiers */
786         ot->name= "Move Strips Up";
787         ot->idname= "NLA_OT_move_up";
788         ot->description= "Move selected strips up a track if there's room.";
789         
790         /* api callbacks */
791         ot->exec= nlaedit_move_up_exec;
792         ot->poll= nlaop_poll_tweakmode_off;
793         
794         /* flags */
795         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
796 }
797
798 /* ******************** Move Strips Down Operator ************************** */
799 /* Tries to move the selected strips into the track above if possible. */
800
801 static int nlaedit_move_down_exec (bContext *C, wmOperator *op)
802 {
803         bAnimContext ac;
804         
805         ListBase anim_data = {NULL, NULL};
806         bAnimListElem *ale;
807         int filter;
808         
809         /* get editor data */
810         if (ANIM_animdata_get_context(C, &ac) == 0)
811                 return OPERATOR_CANCELLED;
812                 
813         /* get a list of the editable tracks being shown in the NLA */
814         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_NLATRACKS | ANIMFILTER_FOREDIT);
815         ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
816         
817         /* loop through the tracks in normal order, since we're pushing strips down,
818          * strips won't get operated on twice
819          */
820         for (ale= anim_data.first; ale; ale= ale->next) {
821                 NlaTrack *nlt= (NlaTrack *)ale->data;
822                 NlaTrack *nltp= nlt->prev;
823                 NlaStrip *strip, *stripn;
824                 
825                 /* if this track has no tracks before it, skip for now... */
826                 if (nltp == NULL)
827                         continue;
828                 
829                 /* for every selected strip, try to move */
830                 for (strip= nlt->strips.first; strip; strip= stripn) {
831                         stripn= strip->next;
832                         
833                         if (strip->flag & NLASTRIP_FLAG_SELECT) {
834                                 /* check if the track below has room for this strip */
835                                 if (BKE_nlatrack_has_space(nltp, strip->start, strip->end)) {
836                                         /* remove from its current track, and add to the one above (it 'should' work, so no need to worry) */
837                                         BLI_remlink(&nlt->strips, strip);
838                                         BKE_nlatrack_add_strip(nltp, strip);
839                                 }
840                         }
841                 }
842         }
843         
844         /* free temp data */
845         BLI_freelistN(&anim_data);
846         
847         /* set notifier that things have changed */
848         ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_BOTH);
849         WM_event_add_notifier(C, NC_SCENE, NULL);
850         
851         /* done */
852         return OPERATOR_FINISHED;
853 }
854
855 void NLA_OT_move_down (wmOperatorType *ot)
856 {
857         /* identifiers */
858         ot->name= "Move Strips Down";
859         ot->idname= "NLA_OT_move_down";
860         ot->description= "Move selected strips down a track if there's room.";
861         
862         /* api callbacks */
863         ot->exec= nlaedit_move_down_exec;
864         ot->poll= nlaop_poll_tweakmode_off;
865         
866         /* flags */
867         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
868 }
869
870 /* ******************** Apply Scale Operator ***************************** */
871 /* Reset the scaling of the selected strips to 1.0f */
872
873 /* apply scaling to keyframe */
874 static short bezt_apply_nlamapping (BeztEditData *bed, BezTriple *bezt)
875 {
876         /* NLA-strip which has this scaling is stored in bed->data */
877         NlaStrip *strip= (NlaStrip *)bed->data;
878         
879         /* adjust all the times */
880         bezt->vec[0][0]= nlastrip_get_frame(strip, bezt->vec[0][0], NLATIME_CONVERT_MAP);
881         bezt->vec[1][0]= nlastrip_get_frame(strip, bezt->vec[1][0], NLATIME_CONVERT_MAP);
882         bezt->vec[2][0]= nlastrip_get_frame(strip, bezt->vec[2][0], NLATIME_CONVERT_MAP);
883         
884         /* nothing to return or else we exit */
885         return 0;
886 }
887
888 static int nlaedit_apply_scale_exec (bContext *C, wmOperator *op)
889 {
890         bAnimContext ac;
891         
892         ListBase anim_data = {NULL, NULL};
893         bAnimListElem *ale;
894         int filter;
895         
896         BeztEditData bed;
897         
898         /* get editor data */
899         if (ANIM_animdata_get_context(C, &ac) == 0)
900                 return OPERATOR_CANCELLED;
901                 
902         /* get a list of the editable tracks being shown in the NLA */
903         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_NLATRACKS | ANIMFILTER_FOREDIT);
904         ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
905         
906         /* init the editing data */
907         memset(&bed, 0, sizeof(BeztEditData));
908         
909         /* for each NLA-Track, apply scale of all selected strips */
910         for (ale= anim_data.first; ale; ale= ale->next) {
911                 NlaTrack *nlt= (NlaTrack *)ale->data;
912                 NlaStrip *strip;
913                 
914                 for (strip= nlt->strips.first; strip; strip= strip->next) {
915                         /* strip must be selected, and must be action-clip only (transitions don't have scale) */
916                         if ((strip->flag & NLASTRIP_FLAG_SELECT) && (strip->type == NLASTRIP_TYPE_CLIP)) {
917                                 /* if the referenced action is used by other strips, make this strip use its own copy */
918                                 if (strip->act == NULL) 
919                                         continue;
920                                 if (strip->act->id.us > 1) {
921                                         /* make a copy of the Action to work on */
922                                         bAction *act= copy_action(strip->act);
923                                         
924                                         /* set this as the new referenced action, decrementing the users of the old one */
925                                         strip->act->id.us--;
926                                         strip->act= act;
927                                 }
928                                 
929                                 /* setup iterator, and iterate over all the keyframes in the action, applying this scaling */
930                                 bed.data= strip;
931                                 ANIM_animchanneldata_keys_bezier_loop(&bed, strip->act, ALE_ACT, NULL, bezt_apply_nlamapping, calchandles_fcurve, 0);
932                                 
933                                 /* clear scale of strip now that it has been applied,
934                                  * and recalculate the extents of the action now that it has been scaled
935                                  * but leave everything else alone 
936                                  */
937                                 strip->scale= 1.0f;
938                                 calc_action_range(strip->act, &strip->actstart, &strip->actend, 1);
939                         }
940                 }
941         }
942         
943         /* free temp data */
944         BLI_freelistN(&anim_data);
945         
946         /* set notifier that things have changed */
947         ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_BOTH);
948         WM_event_add_notifier(C, NC_SCENE, NULL);
949         
950         /* done */
951         return OPERATOR_FINISHED;
952 }
953
954 void NLA_OT_apply_scale (wmOperatorType *ot)
955 {
956         /* identifiers */
957         ot->name= "Apply Scale";
958         ot->idname= "NLA_OT_apply_scale";
959         ot->description= "Apply scaling of selected strips to their referenced Actions.";
960         
961         /* api callbacks */
962         ot->exec= nlaedit_apply_scale_exec;
963         ot->poll= nlaop_poll_tweakmode_off;
964         
965         /* flags */
966         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
967 }
968
969 /* ******************** Clear Scale Operator ***************************** */
970 /* Reset the scaling of the selected strips to 1.0f */
971
972 static int nlaedit_clear_scale_exec (bContext *C, wmOperator *op)
973 {
974         bAnimContext ac;
975         
976         ListBase anim_data = {NULL, NULL};
977         bAnimListElem *ale;
978         int filter;
979         
980         /* get editor data */
981         if (ANIM_animdata_get_context(C, &ac) == 0)
982                 return OPERATOR_CANCELLED;
983                 
984         /* get a list of the editable tracks being shown in the NLA */
985         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_NLATRACKS | ANIMFILTER_FOREDIT);
986         ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
987         
988         /* for each NLA-Track, reset scale of all selected strips */
989         for (ale= anim_data.first; ale; ale= ale->next) {
990                 NlaTrack *nlt= (NlaTrack *)ale->data;
991                 NlaStrip *strip;
992                 
993                 for (strip= nlt->strips.first; strip; strip= strip->next) {
994                         /* strip must be selected, and must be action-clip only (transitions don't have scale) */
995                         if ((strip->flag & NLASTRIP_FLAG_SELECT) && (strip->type == NLASTRIP_TYPE_CLIP)) {
996                                 PointerRNA strip_ptr;
997                                 
998                                 RNA_pointer_create(NULL, &RNA_NlaStrip, strip, &strip_ptr);
999                                 RNA_float_set(&strip_ptr, "scale", 1.0f);
1000                         }
1001                 }
1002         }
1003         
1004         /* free temp data */
1005         BLI_freelistN(&anim_data);
1006         
1007         /* set notifier that things have changed */
1008         ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_BOTH);
1009         WM_event_add_notifier(C, NC_SCENE, NULL);
1010         
1011         /* done */
1012         return OPERATOR_FINISHED;
1013 }
1014
1015 void NLA_OT_clear_scale (wmOperatorType *ot)
1016 {
1017         /* identifiers */
1018         ot->name= "Clear Scale";
1019         ot->idname= "NLA_OT_clear_scale";
1020         ot->description= "Reset scaling of selected strips.";
1021         
1022         /* api callbacks */
1023         ot->exec= nlaedit_clear_scale_exec;
1024         ot->poll= nlaop_poll_tweakmode_off;
1025         
1026         /* flags */
1027         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1028 }
1029
1030 /* ******************** Snap Strips Operator ************************** */
1031 /* Moves the start-point of the selected strips to the specified places */
1032
1033 /* defines for snap keyframes tool */
1034 EnumPropertyItem prop_nlaedit_snap_types[] = {
1035         {NLAEDIT_SNAP_CFRA, "CFRA", 0, "Current frame", ""},
1036         {NLAEDIT_SNAP_NEAREST_FRAME, "NEAREST_FRAME", 0, "Nearest Frame", ""}, // XXX as single entry?
1037         {NLAEDIT_SNAP_NEAREST_SECOND, "NEAREST_SECOND", 0, "Nearest Second", ""}, // XXX as single entry?
1038         {NLAEDIT_SNAP_NEAREST_MARKER, "NEAREST_MARKER", 0, "Nearest Marker", ""},
1039         {0, NULL, 0, NULL, NULL}
1040 };
1041
1042 static int nlaedit_snap_exec (bContext *C, wmOperator *op)
1043 {
1044         bAnimContext ac;
1045         
1046         ListBase anim_data = {NULL, NULL};
1047         bAnimListElem *ale;
1048         int filter;
1049         
1050         Scene *scene= ac.scene;
1051         int mode = RNA_enum_get(op->ptr, "type");
1052         const float secf = (float)FPS;
1053         
1054         /* get editor data */
1055         if (ANIM_animdata_get_context(C, &ac) == 0)
1056                 return OPERATOR_CANCELLED;
1057                 
1058         /* get a list of the editable tracks being shown in the NLA */
1059         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_NLATRACKS | ANIMFILTER_FOREDIT);
1060         ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
1061         
1062         /* since we may add tracks, perform this in reverse order */
1063         for (ale= anim_data.last; ale; ale= ale->prev) {
1064                 ListBase tmp_strips = {NULL, NULL};
1065                 NlaTrack *nlt= (NlaTrack *)ale->data;
1066                 NlaStrip *strip, *stripn;
1067                 
1068                 /* first pass: move all selected strips to a separate buffer, and apply snapping to them */
1069                 for (strip= nlt->strips.first; strip; strip= stripn) {
1070                         stripn= strip->next;
1071                         
1072                         if (strip->flag & NLASTRIP_FLAG_SELECT) {
1073                                 float start, end;
1074                                 
1075                                 /* get the existing end-points */
1076                                 start= strip->start;
1077                                 end= strip->end;
1078                                 
1079                                 /* calculate new start position based on snapping mode */
1080                                 switch (mode) {
1081                                         case NLAEDIT_SNAP_CFRA: /* to current frame */
1082                                                 strip->start= (float)CFRA;
1083                                                 break;
1084                                         case NLAEDIT_SNAP_NEAREST_FRAME: /* to nearest frame */
1085                                                 strip->start= (float)(floor(start+0.5));
1086                                                 break;
1087                                         case NLAEDIT_SNAP_NEAREST_SECOND: /* to nearest second */
1088                                                 strip->start= ((float)floor(start/secf + 0.5f) * secf);
1089                                                 break;
1090                                         case NLAEDIT_SNAP_NEAREST_MARKER: /* to nearest marker */
1091                                                 strip->start= (float)ED_markers_find_nearest_marker_time(ac.markers, start);
1092                                                 break;
1093                                         default: /* just in case... no snapping */
1094                                                 strip->start= start;
1095                                                 break;
1096                                 }
1097                                 
1098                                 /* get new endpoint based on start-point (and old length) */
1099                                 strip->end= strip->start + (end - start);
1100                                 
1101                                 /* remove strip from track, and add to the temp buffer */
1102                                 BLI_remlink(&nlt->strips, strip);
1103                                 BLI_addtail(&tmp_strips, strip);
1104                         }
1105                 }
1106                 
1107                 // TODO: finish this...
1108         }
1109         
1110         /* free temp data */
1111         BLI_freelistN(&anim_data);
1112         
1113         /* set notifier that things have changed */
1114         ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_BOTH);
1115         WM_event_add_notifier(C, NC_SCENE, NULL);
1116         
1117         /* done */
1118         return OPERATOR_FINISHED;
1119 }
1120
1121 void NLA_OT_snap (wmOperatorType *ot)
1122 {
1123         /* identifiers */
1124         ot->name= "Snap Strips";
1125         ot->idname= "NLA_OT_snap";
1126         ot->description= "Move start of strips to specified time.";
1127         
1128         /* api callbacks */
1129         ot->invoke= WM_menu_invoke;
1130         ot->exec= nlaedit_snap_exec;
1131         ot->poll= nlaop_poll_tweakmode_off;
1132         
1133         /* flags */
1134         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1135         
1136         /* properties */
1137         RNA_def_enum(ot->srna, "type", prop_nlaedit_snap_types, 0, "Type", "");
1138 }
1139
1140 /* *********************************************** */
1141 /* NLA Modifiers */
1142
1143 /* ******************** Add F-Modifier Operator *********************** */
1144
1145 /* present a special customised popup menu for this, with some filtering */
1146 static int nla_fmodifier_add_invoke (bContext *C, wmOperator *op, wmEvent *event)
1147 {
1148         uiPopupMenu *pup;
1149         uiLayout *layout;
1150         int i;
1151         
1152         pup= uiPupMenuBegin(C, "Add F-Modifier", 0);
1153         layout= uiPupMenuLayout(pup);
1154         
1155         /* start from 1 to skip the 'Invalid' modifier type */
1156         for (i = 1; i < FMODIFIER_NUM_TYPES; i++) {
1157                 FModifierTypeInfo *fmi= get_fmodifier_typeinfo(i);
1158                 
1159                 /* check if modifier is valid for this context */
1160                 if (fmi == NULL)
1161                         continue;
1162                 if (i == FMODIFIER_TYPE_CYCLES) /* we already have repeat... */
1163                         continue;
1164                 
1165                 /* add entry to add this type of modifier */
1166                 uiItemEnumO(layout, fmi->name, 0, "NLA_OT_fmodifier_add", "type", i);
1167         }
1168         uiItemS(layout);
1169         
1170         uiPupMenuEnd(C, pup);
1171         
1172         return OPERATOR_CANCELLED;
1173 }
1174
1175 static int nla_fmodifier_add_exec(bContext *C, wmOperator *op)
1176 {
1177         bAnimContext ac;
1178         
1179         ListBase anim_data = {NULL, NULL};
1180         bAnimListElem *ale;
1181         int filter;
1182         
1183         FModifier *fcm;
1184         int type= RNA_enum_get(op->ptr, "type");
1185         short onlyActive = RNA_boolean_get(op->ptr, "only_active");
1186         
1187         /* get editor data */
1188         if (ANIM_animdata_get_context(C, &ac) == 0)
1189                 return OPERATOR_CANCELLED;
1190                 
1191         /* get a list of the editable tracks being shown in the NLA */
1192         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_NLATRACKS | ANIMFILTER_FOREDIT);
1193         ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
1194         
1195         /* for each NLA-Track, add the specified modifier to all selected strips */
1196         for (ale= anim_data.first; ale; ale= ale->next) {
1197                 NlaTrack *nlt= (NlaTrack *)ale->data;
1198                 NlaStrip *strip;
1199                 int i = 1;
1200                 
1201                 for (strip= nlt->strips.first; strip; strip=strip->next, i++) {
1202                         /* only add F-Modifier if on active strip? */
1203                         if ((onlyActive) && (strip->flag & NLASTRIP_FLAG_ACTIVE)==0)
1204                                 continue;
1205                         
1206                         /* add F-Modifier of specified type to selected, and make it the active one */
1207                         fcm= add_fmodifier(&strip->modifiers, type);
1208                         
1209                         if (fcm)
1210                                 set_active_fmodifier(&strip->modifiers, fcm);
1211                         else {
1212                                 char errormsg[128];
1213                                 sprintf(errormsg, "Modifier couldn't be added to (%s : %d). See console for details.", nlt->name, i);
1214                                 
1215                                 BKE_report(op->reports, RPT_ERROR, errormsg);
1216                         }
1217                 }
1218         }
1219         
1220         /* free temp data */
1221         BLI_freelistN(&anim_data);
1222         
1223         /* set notifier that things have changed */
1224         ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_BOTH);
1225         WM_event_add_notifier(C, NC_SCENE, NULL);
1226         
1227         /* done */
1228         return OPERATOR_FINISHED;
1229 }
1230  
1231 void NLA_OT_fmodifier_add (wmOperatorType *ot)
1232 {
1233         /* identifiers */
1234         ot->name= "Add F-Modifier";
1235         ot->idname= "NLA_OT_fmodifier_add";
1236         
1237         /* api callbacks */
1238         ot->invoke= nla_fmodifier_add_invoke;
1239         ot->exec= nla_fmodifier_add_exec;
1240         ot->poll= nlaop_poll_tweakmode_off; 
1241         
1242         /* flags */
1243         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1244         
1245         /* id-props */
1246         RNA_def_enum(ot->srna, "type", fmodifier_type_items, 0, "Type", "");
1247         RNA_def_boolean(ot->srna, "only_active", 0, "Only Active", "Only add F-Modifier of the specified type to the active strip.");
1248 }
1249
1250 /* *********************************************** */