Cleanup: use `rna_enum_` prefix for RNA enums
[blender.git] / source / blender / editors / space_nla / nla_edit.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version. 
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2009 Blender Foundation, Joshua Leung
19  * All rights reserved.
20  *
21  * 
22  * Contributor(s): Joshua Leung (major recode)
23  *
24  * ***** END GPL LICENSE BLOCK *****
25  */
26
27 /** \file blender/editors/space_nla/nla_edit.c
28  *  \ingroup spnla
29  */
30
31
32 #include <string.h>
33 #include <stdio.h>
34 #include <math.h>
35
36 #include "DNA_anim_types.h"
37 #include "DNA_object_types.h"
38 #include "DNA_scene_types.h"
39
40 #include "MEM_guardedalloc.h"
41
42 #include "BLI_blenlib.h"
43 #include "BLI_math.h"
44 #include "BLI_utildefines.h"
45
46 #include "BLT_translation.h"
47
48 #include "BKE_action.h"
49 #include "BKE_fcurve.h"
50 #include "BKE_nla.h"
51 #include "BKE_context.h"
52 #include "BKE_library.h"
53 #include "BKE_main.h"
54 #include "BKE_report.h"
55 #include "BKE_screen.h"
56
57 #include "ED_anim_api.h"
58 #include "ED_keyframes_edit.h"
59 #include "ED_markers.h"
60 #include "ED_screen.h"
61 #include "ED_transform.h"
62
63 #include "RNA_access.h"
64 #include "RNA_define.h"
65 #include "RNA_enum_types.h"
66
67 #include "WM_api.h"
68 #include "WM_types.h"
69
70 #include "UI_interface.h"
71 #include "UI_resources.h"
72 #include "UI_view2d.h"
73
74 #include "nla_intern.h" // own include
75 #include "nla_private.h" // FIXME... maybe this shouldn't be included?
76
77 /* *********************************************** */
78 /* Utilities exported to other places... */
79
80 /* Perform validation for blending/extend settings */
81 void ED_nla_postop_refresh(bAnimContext *ac)
82 {
83         ListBase anim_data = {NULL, NULL};
84         bAnimListElem *ale;
85         short filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_ANIMDATA | ANIMFILTER_FOREDIT);
86         
87         /* get blocks to work on */
88         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
89         
90         for (ale = anim_data.first; ale; ale = ale->next) {
91                 /* performing auto-blending, extend-mode validation, etc. */
92                 BKE_nla_validate_state(ale->data);
93         }
94         
95         /* free temp memory */
96         ANIM_animdata_freelist(&anim_data);
97 }
98
99 /* *********************************************** */
100 /* 'Special' Editing */
101
102 /* ******************** Tweak-Mode Operators ***************************** */
103 /* 'Tweak mode' allows the action referenced by the active NLA-strip to be edited 
104  * as if it were the normal Active-Action of its AnimData block. 
105  */
106
107 static int nlaedit_enable_tweakmode_exec(bContext *C, wmOperator *op)
108 {
109         bAnimContext ac;
110         
111         ListBase anim_data = {NULL, NULL};
112         bAnimListElem *ale;
113         int filter;
114         
115         const bool do_solo = RNA_boolean_get(op->ptr, "isolate_action");
116         bool ok = false;
117         
118         /* get editor data */
119         if (ANIM_animdata_get_context(C, &ac) == 0)
120                 return OPERATOR_CANCELLED;
121                 
122         /* get a list of the AnimData blocks being shown in the NLA */
123         filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_ANIMDATA);
124         ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
125         
126         /* if no blocks, popup error? */
127         if (BLI_listbase_is_empty(&anim_data)) {
128                 BKE_report(op->reports, RPT_ERROR, "No AnimData blocks to enter tweak mode for");
129                 return OPERATOR_CANCELLED;
130         }
131         
132         /* for each AnimData block with NLA-data, try setting it in tweak-mode */
133         for (ale = anim_data.first; ale; ale = ale->next) {
134                 AnimData *adt = ale->data;
135                 
136                 /* try entering tweakmode if valid */
137                 ok |= BKE_nla_tweakmode_enter(adt);
138                 
139                 /* mark the active track as being "solo"? */
140                 if (do_solo && adt->actstrip) {
141                         NlaTrack *nlt = BKE_nlatrack_find_tweaked(adt);
142                         
143                         if (nlt && !(nlt->flag & NLATRACK_SOLO)) {
144                                 BKE_nlatrack_solo_toggle(adt, nlt);
145                         }
146                 }
147         }
148         
149         /* free temp data */
150         ANIM_animdata_freelist(&anim_data);
151         
152         /* if we managed to enter tweakmode on at least one AnimData block, 
153          * set the flag for this in the active scene and send notifiers
154          */
155         if (ac.scene && ok) {
156                 /* set editing flag */
157                 ac.scene->flag |= SCE_NLA_EDIT_ON;
158                 
159                 /* set notifier that things have changed */
160                 WM_event_add_notifier(C, NC_ANIMATION | ND_NLA_ACTCHANGE, NULL);
161         }
162         else {
163                 BKE_report(op->reports, RPT_ERROR, "No active strip(s) to enter tweak mode on");
164                 return OPERATOR_CANCELLED;
165         }
166         
167         /* done */
168         return OPERATOR_FINISHED;
169 }
170  
171 void NLA_OT_tweakmode_enter(wmOperatorType *ot)
172 {
173         PropertyRNA *prop;
174         
175         /* identifiers */
176         ot->name = "Enter Tweak Mode";
177         ot->idname = "NLA_OT_tweakmode_enter";
178         ot->description = "Enter tweaking mode for the action referenced by the active strip to edit its keyframes";
179         
180         /* api callbacks */
181         ot->exec = nlaedit_enable_tweakmode_exec;
182         ot->poll = nlaop_poll_tweakmode_off;
183         
184         /* flags */
185         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
186         
187         /* properties */
188         prop = RNA_def_boolean(ot->srna, "isolate_action", 0, "Isolate Action",
189                                "Enable 'solo' on the NLA Track containing the active strip, "
190                                "to edit it without seeing the effects of the NLA stack");
191         RNA_def_property_flag(prop, PROP_SKIP_SAVE);
192 }
193
194 /* ------------- */
195
196 /* NLA Editor internal API function for exiting tweakmode */
197 bool nlaedit_disable_tweakmode(bAnimContext *ac, bool do_solo)
198 {
199         ListBase anim_data = {NULL, NULL};
200         bAnimListElem *ale;
201         int filter;     
202         
203         /* get a list of the AnimData blocks being shown in the NLA */
204         filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_ANIMDATA);
205         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
206         
207         /* if no blocks, popup error? */
208         if (BLI_listbase_is_empty(&anim_data)) {
209                 BKE_report(ac->reports, RPT_ERROR, "No AnimData blocks in tweak mode to exit from");
210                 return false;
211         }
212         
213         /* for each AnimData block with NLA-data, try exitting tweak-mode */
214         for (ale = anim_data.first; ale; ale = ale->next) {
215                 AnimData *adt = ale->data;
216                 
217                 /* clear solo flags */
218                 if ((do_solo) & (adt->flag & ADT_NLA_SOLO_TRACK) &&
219                     (adt->flag & ADT_NLA_EDIT_ON)) 
220                 {
221                         BKE_nlatrack_solo_toggle(adt, NULL);
222                 }
223                 
224                 /* to be sure that we're doing everything right, just exit tweakmode... */
225                 BKE_nla_tweakmode_exit(adt);
226         }
227         
228         /* free temp data */
229         ANIM_animdata_freelist(&anim_data);
230         
231         /* if we managed to enter tweakmode on at least one AnimData block, 
232          * set the flag for this in the active scene and send notifiers
233          */
234         if (ac->scene) {
235                 /* clear editing flag */
236                 ac->scene->flag &= ~SCE_NLA_EDIT_ON;
237                 
238                 /* set notifier that things have changed */
239                 WM_main_add_notifier(NC_ANIMATION | ND_NLA_ACTCHANGE, NULL);
240         }
241         
242         /* done */
243         return true;
244 }
245
246 /* exit tweakmode operator callback */
247 static int nlaedit_disable_tweakmode_exec(bContext *C, wmOperator *op)
248 {
249         bAnimContext ac;
250         
251         const bool do_solo = RNA_boolean_get(op->ptr, "isolate_action");
252         bool ok = false;
253         
254         /* get editor data */
255         if (ANIM_animdata_get_context(C, &ac) == 0)
256                 return OPERATOR_CANCELLED;
257                 
258         /* perform operation */
259         ok = nlaedit_disable_tweakmode(&ac, do_solo);
260         
261         /* success? */
262         if (ok)
263                 return OPERATOR_FINISHED;
264         else
265                 return OPERATOR_CANCELLED;
266 }
267  
268 void NLA_OT_tweakmode_exit(wmOperatorType *ot)
269 {
270         PropertyRNA *prop;
271         
272         /* identifiers */
273         ot->name = "Exit Tweak Mode";
274         ot->idname = "NLA_OT_tweakmode_exit";
275         ot->description = "Exit tweaking mode for the action referenced by the active strip";
276         
277         /* api callbacks */
278         ot->exec = nlaedit_disable_tweakmode_exec;
279         ot->poll = nlaop_poll_tweakmode_on;
280         
281         /* flags */
282         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
283         
284         /* properties */
285         prop = RNA_def_boolean(ot->srna, "isolate_action", 0, "Isolate Action",
286                                "Disable 'solo' on any of the NLA Tracks after exiting tweak mode "
287                                "to get things back to normal");
288         RNA_def_property_flag(prop, PROP_SKIP_SAVE);
289 }
290
291 /* *********************************************** */
292 /* NLA Strips Range Stuff */
293
294 /* *************************** Calculate Range ************************** */
295
296 /* Get the min/max strip extents */
297 static void get_nlastrip_extents(bAnimContext *ac, float *min, float *max, const bool only_sel)
298 {
299         ListBase anim_data = {NULL, NULL};
300         bAnimListElem *ale;
301         int filter;
302         bool found_bounds = false;
303         
304         /* get data to filter */
305         filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_NODUPLIS);
306         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
307         
308         /* set large values to try to override */
309         *min = 999999999.0f;
310         *max = -999999999.0f;
311         
312         /* check if any channels to set range with */
313         if (anim_data.first) {
314                 /* go through channels, finding max extents */
315                 for (ale = anim_data.first; ale; ale = ale->next) {
316                         NlaTrack *nlt = (NlaTrack *)ale->data;
317                         NlaStrip *strip;
318                         
319                         for (strip = nlt->strips.first; strip; strip = strip->next) {
320                                 /* only consider selected strips? */
321                                 if ((only_sel == false) || (strip->flag & NLASTRIP_FLAG_SELECT)) {
322                                         /* extend range if appropriate */
323                                         *min = min_ff(*min, strip->start);
324                                         *max = max_ff(*max, strip->end);
325                                         
326                                         found_bounds = true;
327                                 }
328                         }
329                 }
330                 
331                 /* free memory */
332                 ANIM_animdata_freelist(&anim_data);
333         }
334         
335         /* set default range if nothing happened */
336         if (found_bounds == false) {
337                 if (ac->scene) {
338                         *min = (float)ac->scene->r.sfra;
339                         *max = (float)ac->scene->r.efra;
340                 }
341                 else {
342                         *min = -5;
343                         *max = 100;
344                 }
345         }
346 }
347
348 /* ****************** Automatic Preview-Range Operator ****************** */
349
350 static int nlaedit_previewrange_exec(bContext *C, wmOperator *UNUSED(op))
351 {
352         bAnimContext ac;
353         Scene *scene;
354         float min, max;
355         
356         /* get editor data */
357         if (ANIM_animdata_get_context(C, &ac) == 0)
358                 return OPERATOR_CANCELLED;
359         
360         if (ac.scene == NULL)
361                 return OPERATOR_CANCELLED;
362         else
363                 scene = ac.scene;
364         
365         /* set the range directly */
366         get_nlastrip_extents(&ac, &min, &max, true);
367         scene->r.flag |= SCER_PRV_RANGE;
368         scene->r.psfra = iroundf(min);
369         scene->r.pefra = iroundf(max);
370         
371         /* set notifier that things have changed */
372         // XXX err... there's nothing for frame ranges yet, but this should do fine too
373         WM_event_add_notifier(C, NC_SCENE | ND_FRAME, ac.scene);
374         
375         return OPERATOR_FINISHED;
376 }
377  
378 void NLA_OT_previewrange_set(wmOperatorType *ot)
379 {
380         /* identifiers */
381         ot->name = "Auto-Set Preview Range";
382         ot->idname = "NLA_OT_previewrange_set";
383         ot->description = "Automatically set Preview Range based on range of keyframes";
384         
385         /* api callbacks */
386         ot->exec = nlaedit_previewrange_exec;
387         ot->poll = ED_operator_nla_active;
388         
389         /* flags */
390         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
391 }
392
393 /* ****************** View-All Operator ****************** */
394
395 /**
396  * Find the extents of the active channel
397  *
398  * \param[out] min Bottom y-extent of channel
399  * \param[out] max Top y-extent of channel
400  * \return Success of finding a selected channel
401  */
402 static bool nla_channels_get_selected_extents(bAnimContext *ac, float *min, float *max)
403 {
404         ListBase anim_data = {NULL, NULL};
405         bAnimListElem *ale;
406         int filter;
407         
408         SpaceNla *snla = (SpaceNla *)ac->sl;
409         const float half_height = NLACHANNEL_HEIGHT_HALF(snla);
410         short found = 0; /* NOTE: not bool, since we want prioritise individual channels over expanders */
411         float y;
412         
413         /* get all items - we need to do it this way */
414         filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS);
415         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
416         
417         /* loop through all channels, finding the first one that's selected */
418         y = (float)NLACHANNEL_FIRST;
419         
420         for (ale = anim_data.first; ale; ale = ale->next) {
421                 const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
422                 
423                 /* must be selected... */
424                 if (acf && acf->has_setting(ac, ale, ACHANNEL_SETTING_SELECT) && 
425                     ANIM_channel_setting_get(ac, ale, ACHANNEL_SETTING_SELECT))
426                 {
427                         /* update best estimate */
428                         *min = (float)(y - half_height);
429                         *max = (float)(y + half_height);
430                         
431                         /* is this high enough priority yet? */
432                         found = acf->channel_role;
433                         
434                         /* only stop our search when we've found an actual channel
435                          * - datablock expanders get less priority so that we don't abort prematurely
436                          */
437                         if (found == ACHANNEL_ROLE_CHANNEL) {
438                                 break;
439                         }
440                 }
441                 
442                 /* adjust y-position for next one */
443                 y -= NLACHANNEL_STEP(snla);
444         }
445         
446         /* free all temp data */
447         ANIM_animdata_freelist(&anim_data);
448         
449         return (found != 0);
450 }
451
452 static int nlaedit_viewall(bContext *C, const bool only_sel)
453 {
454         bAnimContext ac;
455         View2D *v2d;
456         float extra;
457         
458         /* get editor data */
459         if (ANIM_animdata_get_context(C, &ac) == 0)
460                 return OPERATOR_CANCELLED;
461         v2d = &ac.ar->v2d;
462         
463         /* set the horizontal range, with an extra offset so that the extreme keys will be in view */
464         get_nlastrip_extents(&ac, &v2d->cur.xmin, &v2d->cur.xmax, only_sel);
465         
466         extra = 0.1f * BLI_rctf_size_x(&v2d->cur);
467         v2d->cur.xmin -= extra;
468         v2d->cur.xmax += extra;
469         
470         /* set vertical range */
471         if (only_sel == false) {
472                 /* view all -> the summary channel is usually the shows everything, and resides right at the top... */
473                 v2d->cur.ymax = 0.0f;
474                 v2d->cur.ymin = (float)-BLI_rcti_size_y(&v2d->mask);
475         }
476         else {
477                 /* locate first selected channel (or the active one), and frame those */
478                 float ymin = v2d->cur.ymin;
479                 float ymax = v2d->cur.ymax;
480                 
481                 if (nla_channels_get_selected_extents(&ac, &ymin, &ymax)) {
482                         /* recenter the view so that this range is in the middle */
483                         float ymid = (ymax - ymin) / 2.0f + ymin;
484                         float x_center;
485                         
486                         UI_view2d_center_get(v2d, &x_center, NULL);
487                         UI_view2d_center_set(v2d, x_center, ymid);
488                 }
489         }
490         
491         /* do View2D syncing */
492         UI_view2d_sync(CTX_wm_screen(C), CTX_wm_area(C), v2d, V2D_LOCK_COPY);
493         
494         /* just redraw this view */
495         ED_area_tag_redraw(CTX_wm_area(C));
496         
497         return OPERATOR_FINISHED;
498 }
499
500 /* ......... */
501
502 static int nlaedit_viewall_exec(bContext *C, wmOperator *UNUSED(op))
503 {       
504         /* whole range */
505         return nlaedit_viewall(C, false);
506 }
507
508 static int nlaedit_viewsel_exec(bContext *C, wmOperator *UNUSED(op))
509 {
510         /* only selected */
511         return nlaedit_viewall(C, true);
512 }
513  
514 void NLA_OT_view_all(wmOperatorType *ot)
515 {
516         /* identifiers */
517         ot->name = "View All";
518         ot->idname = "NLA_OT_view_all";
519         ot->description = "Reset viewable area to show full strips range";
520         
521         /* api callbacks */
522         ot->exec = nlaedit_viewall_exec;
523         ot->poll = ED_operator_nla_active;
524         
525         /* flags */
526         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
527 }
528
529 void NLA_OT_view_selected(wmOperatorType *ot)
530 {
531         /* identifiers */
532         ot->name = "View Selected";
533         ot->idname = "NLA_OT_view_selected";
534         ot->description = "Reset viewable area to show selected strips range";
535         
536         /* api callbacks */
537         ot->exec = nlaedit_viewsel_exec;
538         ot->poll = ED_operator_nla_active;
539         
540         /* flags */
541         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
542 }
543
544 /* *********************************************** */
545 /* NLA Editing Operations (Constructive/Destructive) */
546
547 /* ******************** Add Action-Clip Operator ***************************** */
548 /* Add a new Action-Clip strip to the active track (or the active block if no space in the track) */
549
550
551 /* add the specified action as new strip */
552 static int nlaedit_add_actionclip_exec(bContext *C, wmOperator *op)
553 {
554         bAnimContext ac;
555         Scene *scene;
556         
557         ListBase anim_data = {NULL, NULL};
558         bAnimListElem *ale;
559         size_t items;
560         int filter;
561
562         bAction *act;
563
564         float cfra;
565         
566         /* get editor data */
567         if (ANIM_animdata_get_context(C, &ac) == 0)
568                 return OPERATOR_CANCELLED;
569                 
570         scene = ac.scene;
571         cfra = (float)CFRA;
572                 
573         /* get action to use */
574         act = BLI_findlink(&CTX_data_main(C)->action, RNA_enum_get(op->ptr, "action"));
575         
576         if (act == NULL) {
577                 BKE_report(op->reports, RPT_ERROR, "No valid action to add");
578                 //printf("Add strip - actname = '%s'\n", actname);
579                 return OPERATOR_CANCELLED;
580         }
581         else if (act->idroot == 0) {
582                 /* hopefully in this case (i.e. library of userless actions), the user knows what they're doing... */
583                 BKE_reportf(op->reports, RPT_WARNING,
584                             "Action '%s' does not specify what datablocks it can be used on "
585                             "(try setting the 'ID Root Type' setting from the Datablocks Editor "
586                             "for this action to avoid future problems)",
587                             act->id.name + 2);
588         }
589         
590         /* add tracks to empty but selected animdata blocks so that strips can be added to those directly
591          * without having to manually add tracks first
592          */
593         nlaedit_add_tracks_empty(&ac);
594         
595         /* get a list of the editable tracks being shown in the NLA
596          *      - this is limited to active ones for now, but could be expanded to 
597          */
598         filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_ACTIVE | ANIMFILTER_FOREDIT);
599         items = ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
600         
601         if (items == 0) {
602                 BKE_report(op->reports, RPT_ERROR, 
603                            "No active track(s) to add strip to, select an existing track or add one before trying again");
604                 return OPERATOR_CANCELLED;
605         }
606         
607         /* for every active track, try to add strip to free space in track or to the top of the stack if no space */
608         for (ale = anim_data.first; ale; ale = ale->next) {
609                 NlaTrack *nlt = (NlaTrack *)ale->data;
610                 AnimData *adt = ale->adt;
611                 NlaStrip *strip = NULL;
612                 
613                 /* sanity check: only apply actions of the right type for this ID 
614                  * NOTE: in the case that this hasn't been set, we've already warned the user about this already
615                  */
616                 if ((act->idroot) && (act->idroot != GS(ale->id->name))) {
617                         BKE_reportf(op->reports, RPT_ERROR, 
618                                     "Could not add action '%s' as it cannot be used relative to ID-blocks of type '%s'",
619                                     act->id.name + 2, ale->id->name);
620                         continue;
621                 }
622                 
623                 /* create a new strip, and offset it to start on the current frame */
624                 strip = add_nlastrip(act);
625                 
626                 strip->end      += (cfra - strip->start);
627                 strip->start     = cfra;
628                 
629                 /* firstly try adding strip to our current track, but if that fails, add to a new track */
630                 if (BKE_nlatrack_add_strip(nlt, strip) == 0) {
631                         /* trying to add to the current failed (no space), 
632                          * so add a new track to the stack, and add to that...
633                          */
634                         nlt = add_nlatrack(adt, NULL);
635                         BKE_nlatrack_add_strip(nlt, strip);
636                 }
637                 
638                 /* auto-name it */
639                 BKE_nlastrip_validate_name(adt, strip);
640         }
641         
642         /* free temp data */
643         ANIM_animdata_freelist(&anim_data);
644         
645         /* refresh auto strip properties */
646         ED_nla_postop_refresh(&ac);
647         
648         /* set notifier that things have changed */
649         WM_event_add_notifier(C, NC_ANIMATION | ND_NLA | NA_EDITED, NULL);
650         
651         /* done */
652         return OPERATOR_FINISHED;
653 }
654
655 void NLA_OT_actionclip_add(wmOperatorType *ot)
656 {
657         PropertyRNA *prop;
658
659         /* identifiers */
660         ot->name = "Add Action Strip";
661         ot->idname = "NLA_OT_actionclip_add";
662         ot->description = "Add an Action-Clip strip (i.e. an NLA Strip referencing an Action) to the active track";
663         
664         /* api callbacks */
665         ot->invoke = WM_enum_search_invoke;
666         ot->exec = nlaedit_add_actionclip_exec;
667         ot->poll = nlaop_poll_tweakmode_off;
668         
669         /* flags */
670         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
671         
672         /* props */
673         // TODO: this would be nicer as an ID-pointer...
674         prop = RNA_def_enum(ot->srna, "action", DummyRNA_NULL_items, 0, "Action", "");
675         RNA_def_enum_funcs(prop, RNA_action_itemf);
676         RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE);
677         ot->prop = prop;
678 }
679
680 /* ******************** Add Transition Operator ***************************** */
681 /* Add a new transition strip between selected strips */
682
683 static int nlaedit_add_transition_exec(bContext *C, wmOperator *op)
684 {
685         bAnimContext ac;
686         
687         ListBase anim_data = {NULL, NULL};
688         bAnimListElem *ale;
689         int filter;
690         
691         bool done = false;
692         
693         /* get editor data */
694         if (ANIM_animdata_get_context(C, &ac) == 0)
695                 return OPERATOR_CANCELLED;
696         
697         /* get a list of the editable tracks being shown in the NLA */
698         filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
699         ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
700         
701         /* for each track, find pairs of strips to add transitions to */
702         for (ale = anim_data.first; ale; ale = ale->next) {
703                 NlaTrack *nlt = (NlaTrack *)ale->data;
704                 AnimData *adt = ale->adt;
705                 NlaStrip *s1, *s2;
706                 
707                 /* get initial pair of strips */
708                 if (ELEM(nlt->strips.first, NULL, nlt->strips.last))
709                         continue;
710                 s1 = nlt->strips.first;
711                 s2 = s1->next;
712                 
713                 /* loop over strips */
714                 for (; s1 && s2; s1 = s2, s2 = s2->next) {
715                         NlaStrip *strip;
716                         
717                         /* check if both are selected */
718                         if (ELEM(0, (s1->flag & NLASTRIP_FLAG_SELECT), (s2->flag & NLASTRIP_FLAG_SELECT)))
719                                 continue;
720                         /* check if there's space between the two */
721                         if (IS_EQF(s1->end, s2->start))
722                                 continue;
723                         /* make sure neither one is a transition 
724                          *      - although this is impossible to create with the standard tools, 
725                          *    the user may have altered the settings
726                          */
727                         if (ELEM(NLASTRIP_TYPE_TRANSITION, s1->type, s2->type))
728                                 continue;
729                         /* also make sure neither one is a soundclip */
730                         if (ELEM(NLASTRIP_TYPE_SOUND, s1->type, s2->type))
731                                 continue;
732                                 
733                         /* allocate new strip */
734                         strip = MEM_callocN(sizeof(NlaStrip), "NlaStrip");
735                         BLI_insertlinkafter(&nlt->strips, s1, strip);
736                         
737                         /* set the type */
738                         strip->type = NLASTRIP_TYPE_TRANSITION;
739                         
740                         /* generic settings 
741                          *      - selected flag to highlight this to the user
742                          *      - auto-blends to ensure that blend in/out values are automatically 
743                          *        determined by overlaps of strips
744                          */
745                         strip->flag = NLASTRIP_FLAG_SELECT | NLASTRIP_FLAG_AUTO_BLENDS;
746                         
747                         /* range is simply defined as the endpoints of the adjacent strips */
748                         strip->start = s1->end;
749                         strip->end   = s2->start;
750                         
751                         /* scale and repeat aren't of any use, but shouldn't ever be 0 */
752                         strip->scale = 1.0f;
753                         strip->repeat = 1.0f;
754                         
755                         /* auto-name it */
756                         BKE_nlastrip_validate_name(adt, strip);
757                         
758                         /* make note of this */
759                         done = true;
760                 }
761         }
762         
763         /* free temp data */
764         ANIM_animdata_freelist(&anim_data);
765         
766         /* was anything added? */
767         if (done) {
768                 /* refresh auto strip properties */
769                 ED_nla_postop_refresh(&ac);
770                 
771                 /* set notifier that things have changed */
772                 WM_event_add_notifier(C, NC_ANIMATION | ND_NLA | NA_EDITED, NULL);
773                 
774                 /* done */
775                 return OPERATOR_FINISHED;
776         }
777         else {
778                 BKE_report(op->reports, RPT_ERROR, "Needs at least a pair of adjacent selected strips with a gap between them");
779                 return OPERATOR_CANCELLED;
780         }
781 }
782
783 void NLA_OT_transition_add(wmOperatorType *ot)
784 {
785         /* identifiers */
786         ot->name = "Add Transition";
787         ot->idname = "NLA_OT_transition_add";
788         ot->description = "Add a transition strip between two adjacent selected strips";
789         
790         /* api callbacks */
791         ot->exec = nlaedit_add_transition_exec;
792         ot->poll = nlaop_poll_tweakmode_off;
793         
794         /* flags */
795         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
796 }
797
798 /* ******************** Add Sound Clip Operator ***************************** */
799 /* Add a new sound clip */
800
801 static int nlaedit_add_sound_exec(bContext *C, wmOperator *UNUSED(op))
802 {
803         bAnimContext ac;
804         
805         ListBase anim_data = {NULL, NULL};
806         bAnimListElem *ale;
807         int filter;
808         
809         Scene *scene;
810         int cfra;
811         
812         /* get editor data */
813         if (ANIM_animdata_get_context(C, &ac) == 0)
814                 return OPERATOR_CANCELLED;
815         
816         scene = ac.scene;
817         cfra = CFRA;
818         
819         /* get a list of the editable tracks being shown in the NLA */
820         filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_SEL | ANIMFILTER_FOREDIT);
821         ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
822         
823         /* for each track, add sound clips if it belongs to a speaker */
824         // TODO: what happens if there aren't any tracks... well that's a more general problem for later
825         for (ale = anim_data.first; ale; ale = ale->next) {
826                 Object *ob = (Object *)ale->id; /* may not be object until we actually check! */
827                 
828                 AnimData *adt = ale->adt;
829                 NlaTrack *nlt = (NlaTrack *)ale->data;
830                 NlaStrip *strip;
831                 
832                 /* does this belong to speaker - assumed to live on Object level only */
833                 if ((GS(ale->id->name) != ID_OB) || (ob->type != OB_SPEAKER))
834                         continue;
835                         
836                 /* create a new strip, and offset it to start on the current frame */
837                 strip = add_nla_soundstrip(ac.scene, ob->data);
838                 
839                 strip->start += cfra;
840                 strip->end   += cfra;
841                 
842                 /* firstly try adding strip to our current track, but if that fails, add to a new track */
843                 if (BKE_nlatrack_add_strip(nlt, strip) == 0) {
844                         /* trying to add to the current failed (no space), 
845                          * so add a new track to the stack, and add to that...
846                          */
847                         nlt = add_nlatrack(adt, NULL);
848                         BKE_nlatrack_add_strip(nlt, strip);
849                 }
850                 
851                 /* auto-name it */
852                 BKE_nlastrip_validate_name(adt, strip);
853         }
854         
855         /* free temp data */
856         ANIM_animdata_freelist(&anim_data);
857         
858         /* refresh auto strip properties */
859         ED_nla_postop_refresh(&ac);
860         
861         /* set notifier that things have changed */
862         WM_event_add_notifier(C, NC_ANIMATION | ND_NLA | NA_EDITED, NULL);
863         
864         /* done */
865         return OPERATOR_FINISHED;
866 }
867
868 void NLA_OT_soundclip_add(wmOperatorType *ot)
869 {
870         /* identifiers */
871         ot->name = "Add Sound Clip";
872         ot->idname = "NLA_OT_soundclip_add";
873         ot->description = "Add a strip for controlling when speaker plays its sound clip";
874         
875         /* api callbacks */
876         ot->exec = nlaedit_add_sound_exec;
877         ot->poll = nlaop_poll_tweakmode_off;
878         
879         /* flags */
880         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
881 }
882
883 /* ******************** Add Meta-Strip Operator ***************************** */
884 /* Add new meta-strips incorporating the selected strips */
885
886 /* add the specified action as new strip */
887 static int nlaedit_add_meta_exec(bContext *C, wmOperator *UNUSED(op))
888 {
889         bAnimContext ac;
890         
891         ListBase anim_data = {NULL, NULL};
892         bAnimListElem *ale;
893         int filter;
894         
895         /* get editor data */
896         if (ANIM_animdata_get_context(C, &ac) == 0)
897                 return OPERATOR_CANCELLED;
898         
899         /* get a list of the editable tracks being shown in the NLA */
900         filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
901         ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
902         
903         /* for each track, find pairs of strips to add transitions to */
904         for (ale = anim_data.first; ale; ale = ale->next) {
905                 NlaTrack *nlt = (NlaTrack *)ale->data;
906                 AnimData *adt = ale->adt;
907                 NlaStrip *strip;
908                 
909                 /* create meta-strips from the continuous chains of selected strips */
910                 BKE_nlastrips_make_metas(&nlt->strips, 0);
911                 
912                 /* name the metas */
913                 for (strip = nlt->strips.first; strip; strip = strip->next) {
914                         /* auto-name this strip if selected (that means it is a meta) */
915                         if (strip->flag & NLASTRIP_FLAG_SELECT)
916                                 BKE_nlastrip_validate_name(adt, strip);
917                 }
918         }
919         
920         /* free temp data */
921         ANIM_animdata_freelist(&anim_data);
922         
923         /* set notifier that things have changed */
924         WM_event_add_notifier(C, NC_ANIMATION | ND_NLA | NA_EDITED, NULL);
925         
926         /* done */
927         return OPERATOR_FINISHED;
928 }
929
930 void NLA_OT_meta_add(wmOperatorType *ot)
931 {
932         /* identifiers */
933         ot->name = "Add Meta-Strips";
934         ot->idname = "NLA_OT_meta_add";
935         ot->description = "Add new meta-strips incorporating the selected strips";
936         
937         /* api callbacks */
938         ot->exec = nlaedit_add_meta_exec;
939         ot->poll = nlaop_poll_tweakmode_off;
940         
941         /* flags */
942         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
943 }
944
945 /* ******************** Remove Meta-Strip Operator ***************************** */
946 /* Separate out the strips held by the selected meta-strips */
947
948 static int nlaedit_remove_meta_exec(bContext *C, wmOperator *UNUSED(op))
949 {
950         bAnimContext ac;
951         
952         ListBase anim_data = {NULL, NULL};
953         bAnimListElem *ale;
954         int filter;
955         
956         /* get editor data */
957         if (ANIM_animdata_get_context(C, &ac) == 0)
958                 return OPERATOR_CANCELLED;
959         
960         /* get a list of the editable tracks being shown in the NLA */
961         filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
962         ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
963         
964         /* for each track, find pairs of strips to add transitions to */
965         for (ale = anim_data.first; ale; ale = ale->next) {
966                 NlaTrack *nlt = (NlaTrack *)ale->data;
967                 
968                 /* clear all selected meta-strips, regardless of whether they are temporary or not */
969                 BKE_nlastrips_clear_metas(&nlt->strips, 1, 0);
970         }
971         
972         /* free temp data */
973         ANIM_animdata_freelist(&anim_data);
974         
975         /* set notifier that things have changed */
976         WM_event_add_notifier(C, NC_ANIMATION | ND_NLA | NA_EDITED, NULL);
977         
978         /* done */
979         return OPERATOR_FINISHED;
980 }
981
982 void NLA_OT_meta_remove(wmOperatorType *ot)
983 {
984         /* identifiers */
985         ot->name = "Remove Meta-Strips";
986         ot->idname = "NLA_OT_meta_remove";
987         ot->description = "Separate out the strips held by the selected meta-strips";
988         
989         /* api callbacks */
990         ot->exec = nlaedit_remove_meta_exec;
991         ot->poll = nlaop_poll_tweakmode_off;
992         
993         /* flags */
994         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
995 }
996
997 /* ******************** Duplicate Strips Operator ************************** */
998 /* Duplicates the selected NLA-Strips, putting them on new tracks above the one
999  * the originals were housed in.
1000  */
1001  
1002 static int nlaedit_duplicate_exec(bContext *C, wmOperator *op)
1003 {
1004         bAnimContext ac;
1005         
1006         ListBase anim_data = {NULL, NULL};
1007         bAnimListElem *ale;
1008         int filter;
1009         
1010         bool linked = RNA_boolean_get(op->ptr, "linked");
1011         bool done = false;
1012         
1013         /* get editor data */
1014         if (ANIM_animdata_get_context(C, &ac) == 0)
1015                 return OPERATOR_CANCELLED;
1016                 
1017         /* get a list of editable tracks being shown in the NLA */
1018         filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
1019         ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
1020         
1021         /* duplicate strips in tracks starting from the last one so that we're 
1022          * less likely to duplicate strips we just duplicated...
1023          */
1024         for (ale = anim_data.last; ale; ale = ale->prev) {
1025                 NlaTrack *nlt = (NlaTrack *)ale->data;
1026                 AnimData *adt = ale->adt;
1027                 NlaStrip *strip, *nstrip, *next;
1028                 NlaTrack *track;
1029                 
1030                 for (strip = nlt->strips.first; strip; strip = next) {
1031                         next = strip->next;
1032                         
1033                         /* if selected, split the strip at its midpoint */
1034                         if (strip->flag & NLASTRIP_FLAG_SELECT) {
1035                                 /* make a copy (assume that this is possible) */
1036                                 nstrip = copy_nlastrip(strip, linked);
1037                                 
1038                                 /* in case there's no space in the track above, or we haven't got a reference to it yet, try adding */
1039                                 if (BKE_nlatrack_add_strip(nlt->next, nstrip) == 0) {
1040                                         /* need to add a new track above the one above the current one
1041                                          *      - if the current one is the last one, nlt->next will be NULL, which defaults to adding 
1042                                          *        at the top of the stack anyway...
1043                                          */
1044                                         track = add_nlatrack(adt, nlt->next);
1045                                         BKE_nlatrack_add_strip(track, nstrip);
1046                                 }
1047                                 
1048                                 /* deselect the original and the active flag */
1049                                 strip->flag &= ~(NLASTRIP_FLAG_SELECT | NLASTRIP_FLAG_ACTIVE);
1050                                 
1051                                 /* auto-name newly created strip */
1052                                 BKE_nlastrip_validate_name(adt, nstrip);
1053                                 
1054                                 done = true;
1055                         }
1056                 }
1057         }
1058         
1059         /* free temp data */
1060         ANIM_animdata_freelist(&anim_data);
1061         
1062         if (done) {
1063                 /* refresh auto strip properties */
1064                 ED_nla_postop_refresh(&ac);
1065                 
1066                 /* set notifier that things have changed */
1067                 WM_event_add_notifier(C, NC_ANIMATION | ND_NLA | NA_EDITED, NULL);
1068                 
1069                 /* done */
1070                 return OPERATOR_FINISHED;
1071         }
1072         else
1073                 return OPERATOR_CANCELLED;
1074 }
1075
1076 static int nlaedit_duplicate_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
1077 {
1078         nlaedit_duplicate_exec(C, op);
1079         
1080         RNA_enum_set(op->ptr, "mode", TFM_TRANSLATION);
1081         WM_operator_name_call(C, "TRANSFORM_OT_transform", WM_OP_INVOKE_REGION_WIN, op->ptr);
1082
1083         return OPERATOR_FINISHED;
1084 }
1085
1086 void NLA_OT_duplicate(wmOperatorType *ot)
1087 {
1088         /* identifiers */
1089         ot->name = "Duplicate Strips";
1090         ot->idname = "NLA_OT_duplicate";
1091         ot->description = "Duplicate selected NLA-Strips, adding the new strips in new tracks above the originals";
1092         
1093         /* api callbacks */
1094         ot->invoke = nlaedit_duplicate_invoke;
1095         ot->exec = nlaedit_duplicate_exec;
1096         ot->poll = nlaop_poll_tweakmode_off;
1097         
1098         /* flags */
1099         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1100         
1101         /* own properties */
1102         ot->prop = RNA_def_boolean(ot->srna, "linked", false, "Linked", "When duplicating strips, assign new copies of the actions they use");
1103         
1104         /* to give to transform */
1105         RNA_def_enum(ot->srna, "mode", rna_enum_transform_mode_types, TFM_TRANSLATION, "Mode", "");
1106 }
1107
1108 /* ******************** Delete Strips Operator ***************************** */
1109 /* Deletes the selected NLA-Strips */
1110
1111 static int nlaedit_delete_exec(bContext *C, wmOperator *UNUSED(op))
1112 {
1113         bAnimContext ac;
1114         
1115         ListBase anim_data = {NULL, NULL};
1116         bAnimListElem *ale;
1117         int filter;
1118         
1119         /* get editor data */
1120         if (ANIM_animdata_get_context(C, &ac) == 0)
1121                 return OPERATOR_CANCELLED;
1122                 
1123         /* get a list of the editable tracks being shown in the NLA */
1124         filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
1125         ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
1126         
1127         /* for each NLA-Track, delete all selected strips */
1128         for (ale = anim_data.first; ale; ale = ale->next) {
1129                 NlaTrack *nlt = (NlaTrack *)ale->data;
1130                 NlaStrip *strip, *nstrip;
1131                 
1132                 for (strip = nlt->strips.first; strip; strip = nstrip) {
1133                         nstrip = strip->next;
1134                         
1135                         /* if selected, delete */
1136                         if (strip->flag & NLASTRIP_FLAG_SELECT) {
1137                                 /* if a strip either side of this was a transition, delete those too */
1138                                 if ((strip->prev) && (strip->prev->type == NLASTRIP_TYPE_TRANSITION)) 
1139                                         free_nlastrip(&nlt->strips, strip->prev);
1140                                 if ((nstrip) && (nstrip->type == NLASTRIP_TYPE_TRANSITION)) {
1141                                         nstrip = nstrip->next;
1142                                         free_nlastrip(&nlt->strips, strip->next);
1143                                 }
1144                                 
1145                                 /* finally, delete this strip */
1146                                 free_nlastrip(&nlt->strips, strip);
1147                         }
1148                 }
1149         }
1150         
1151         /* free temp data */
1152         ANIM_animdata_freelist(&anim_data);
1153         
1154         /* refresh auto strip properties */
1155         ED_nla_postop_refresh(&ac);
1156         
1157         /* set notifier that things have changed */
1158         WM_event_add_notifier(C, NC_ANIMATION | ND_NLA | NA_EDITED, NULL);
1159         
1160         /* done */
1161         return OPERATOR_FINISHED;
1162 }
1163
1164 void NLA_OT_delete(wmOperatorType *ot)
1165 {
1166         /* identifiers */
1167         ot->name = "Delete Strips";
1168         ot->idname = "NLA_OT_delete";
1169         ot->description = "Delete selected strips";
1170         
1171         /* api callbacks */
1172         ot->exec = nlaedit_delete_exec;
1173         ot->poll = nlaop_poll_tweakmode_off;
1174         
1175         /* flags */
1176         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1177 }
1178
1179 /* ******************** Split Strips Operator ***************************** */
1180 /* Splits the selected NLA-Strips into two strips at the midpoint of the strip */
1181 // TODO's? 
1182 //  - multiple splits
1183 //  - variable-length splits?
1184
1185 /* split a given Action-Clip strip */
1186 static void nlaedit_split_strip_actclip(AnimData *adt, NlaTrack *nlt, NlaStrip *strip, float cfra)
1187 {
1188         NlaStrip *nstrip;
1189         float splitframe, splitaframe;
1190         
1191         /* calculate the frames to do the splitting at 
1192          *      - use current frame if within extents of strip 
1193          */
1194         if ((cfra > strip->start) && (cfra < strip->end)) {
1195                 /* use the current frame */
1196                 splitframe = cfra;
1197                 splitaframe = nlastrip_get_frame(strip, cfra, NLATIME_CONVERT_UNMAP);
1198         }
1199         else {
1200                 /* split in the middle */
1201                 float len;
1202                         
1203                 /* strip extents */
1204                 len = strip->end - strip->start;
1205                 if (IS_EQF(len, 0.0f))
1206                         return;
1207                 else
1208                         splitframe = strip->start + (len / 2.0f);
1209                         
1210                 /* action range */
1211                 len = strip->actend - strip->actstart;
1212                 if (IS_EQF(len, 0.0f))
1213                         splitaframe = strip->actend;
1214                 else
1215                         splitaframe = strip->actstart + (len / 2.0f);
1216         }
1217         
1218         /* make a copy (assume that this is possible) and append
1219          * it immediately after the current strip
1220          */
1221         nstrip = copy_nlastrip(strip, true);
1222         BLI_insertlinkafter(&nlt->strips, strip, nstrip);
1223         
1224         /* set the endpoint of the first strip and the start of the new strip 
1225          * to the splitframe values calculated above
1226          */
1227         strip->end = splitframe;
1228         nstrip->start = splitframe;
1229         
1230         if ((splitaframe > strip->actstart) && (splitaframe < strip->actend)) {
1231                 /* only do this if we're splitting down the middle...  */
1232                 strip->actend = splitaframe;
1233                 nstrip->actstart = splitaframe;
1234         }
1235         
1236         /* clear the active flag from the copy */
1237         nstrip->flag &= ~NLASTRIP_FLAG_ACTIVE;
1238         
1239         /* auto-name the new strip */
1240         BKE_nlastrip_validate_name(adt, nstrip);
1241 }
1242
1243 /* split a given Meta strip */
1244 static void nlaedit_split_strip_meta(NlaTrack *nlt, NlaStrip *strip)
1245 {
1246         /* simply ungroup it for now...  */
1247         BKE_nlastrips_clear_metastrip(&nlt->strips, strip);
1248 }
1249
1250 /* ----- */
1251
1252 static int nlaedit_split_exec(bContext *C, wmOperator *UNUSED(op))
1253 {
1254         bAnimContext ac;
1255         
1256         ListBase anim_data = {NULL, NULL};
1257         bAnimListElem *ale;
1258         int filter;
1259         
1260         /* get editor data */
1261         if (ANIM_animdata_get_context(C, &ac) == 0)
1262                 return OPERATOR_CANCELLED;
1263                 
1264         /* get a list of editable tracks being shown in the NLA */
1265         filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
1266         ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
1267         
1268         /* for each NLA-Track, split all selected strips into two strips */
1269         for (ale = anim_data.first; ale; ale = ale->next) {
1270                 NlaTrack *nlt = (NlaTrack *)ale->data;
1271                 AnimData *adt = ale->adt;
1272                 NlaStrip *strip, *next;
1273                 
1274                 for (strip = nlt->strips.first; strip; strip = next) {
1275                         next = strip->next;
1276                         
1277                         /* if selected, split the strip at its midpoint */
1278                         if (strip->flag & NLASTRIP_FLAG_SELECT) {
1279                                 /* splitting method depends on the type of strip */
1280                                 switch (strip->type) {
1281                                         case NLASTRIP_TYPE_CLIP: /* action-clip */
1282                                                 nlaedit_split_strip_actclip(adt, nlt, strip, (float)ac.scene->r.cfra);
1283                                                 break;
1284                                                 
1285                                         case NLASTRIP_TYPE_META: /* meta-strips need special handling */
1286                                                 nlaedit_split_strip_meta(nlt, strip);
1287                                                 break;
1288                                         
1289                                         default: /* for things like Transitions, do not split! */
1290                                                 break;
1291                                 }
1292                         }
1293                 }
1294         }
1295         
1296         /* free temp data */
1297         ANIM_animdata_freelist(&anim_data);
1298         
1299         /* refresh auto strip properties */
1300         ED_nla_postop_refresh(&ac);
1301         
1302         /* set notifier that things have changed */
1303         WM_event_add_notifier(C, NC_ANIMATION | ND_NLA | NA_EDITED, NULL);
1304         
1305         /* done */
1306         return OPERATOR_FINISHED;
1307 }
1308
1309 void NLA_OT_split(wmOperatorType *ot)
1310 {
1311         /* identifiers */
1312         ot->name = "Split Strips";
1313         ot->idname = "NLA_OT_split";
1314         ot->description = "Split selected strips at their midpoints";
1315         
1316         /* api callbacks */
1317         ot->exec = nlaedit_split_exec;
1318         ot->poll = nlaop_poll_tweakmode_off;
1319         
1320         /* flags */
1321         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1322 }
1323
1324 /* ******************** Bake Strips Operator ***************************** */
1325 /* Bakes the NLA Strips for the active AnimData blocks */
1326
1327 static int nlaedit_bake_exec(bContext *C, wmOperator *UNUSED(op))
1328 {
1329         bAnimContext ac;
1330         
1331         ListBase anim_data = {NULL, NULL};
1332         bAnimListElem *ale;
1333         int filter;
1334 //      int flag = 0;
1335         
1336         /* get editor data */
1337         if (ANIM_animdata_get_context(C, &ac) == 0)
1338                 return OPERATOR_CANCELLED;
1339                 
1340         /* get a list of the editable tracks being shown in the NLA */
1341         filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_ANIMDATA | ANIMFILTER_FOREDIT);
1342         ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
1343         
1344         /* for each AnimData block, bake strips to animdata... */
1345         for (ale = anim_data.first; ale; ale = ale->next) {
1346                 //BKE_nla_bake(ac.scene, ale->id, ale->data, flag);
1347         }
1348         
1349         /* free temp data */
1350         ANIM_animdata_freelist(&anim_data);
1351         
1352         /* refresh auto strip properties */
1353         ED_nla_postop_refresh(&ac);
1354         
1355         /* set notifier that things have changed */
1356         WM_event_add_notifier(C, NC_ANIMATION | ND_NLA | NA_EDITED, NULL);
1357         
1358         /* done */
1359         return OPERATOR_FINISHED;
1360 }
1361
1362 /* why isn't this used? */
1363 static void UNUSED_FUNCTION(NLA_OT_bake)(wmOperatorType *ot)
1364 {
1365         /* identifiers */
1366         ot->name = "Bake Strips";
1367         ot->idname = "NLA_OT_bake";
1368         ot->description = "Bake all strips of selected AnimData blocks";
1369         
1370         /* api callbacks */
1371         ot->exec = nlaedit_bake_exec;
1372         ot->poll = nlaop_poll_tweakmode_off;
1373         
1374         /* flags */
1375         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1376 }
1377
1378 /* *********************************************** */
1379 /* NLA Editing Operations (Modifying) */
1380
1381 /* ******************** Toggle Muting Operator ************************** */
1382 /* Toggles whether strips are muted or not */
1383
1384 static int nlaedit_toggle_mute_exec(bContext *C, wmOperator *UNUSED(op))
1385 {
1386         bAnimContext ac;
1387         
1388         ListBase anim_data = {NULL, NULL};
1389         bAnimListElem *ale;
1390         int filter;
1391         
1392         /* get editor data */
1393         if (ANIM_animdata_get_context(C, &ac) == 0)
1394                 return OPERATOR_CANCELLED;
1395                 
1396         /* get a list of the editable tracks being shown in the NLA */
1397         filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
1398         ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
1399         
1400         /* go over all selected strips */
1401         for (ale = anim_data.first; ale; ale = ale->next) {
1402                 NlaTrack *nlt = (NlaTrack *)ale->data;
1403                 NlaStrip *strip;
1404                 
1405                 /* for every selected strip, toggle muting  */
1406                 for (strip = nlt->strips.first; strip; strip = strip->next) {
1407                         if (strip->flag & NLASTRIP_FLAG_SELECT) {
1408                                 /* just flip the mute flag for now */
1409                                 // TODO: have a pre-pass to check if mute all or unmute all?
1410                                 strip->flag ^= NLASTRIP_FLAG_MUTED;
1411                                 
1412                                 /* tag AnimData to get recalculated */
1413                                 ale->update |= ANIM_UPDATE_DEPS;
1414                         }
1415                 }
1416         }
1417         
1418         /* cleanup */
1419         ANIM_animdata_update(&ac, &anim_data);
1420         ANIM_animdata_freelist(&anim_data);
1421         
1422         /* set notifier that things have changed */
1423         WM_event_add_notifier(C, NC_ANIMATION | ND_NLA | NA_EDITED, NULL);
1424         
1425         /* done */
1426         return OPERATOR_FINISHED;
1427 }
1428
1429 void NLA_OT_mute_toggle(wmOperatorType *ot)
1430 {
1431         /* identifiers */
1432         ot->name = "Toggle Muting";
1433         ot->idname = "NLA_OT_mute_toggle";
1434         ot->description = "Mute or un-mute selected strips";
1435         
1436         /* api callbacks */
1437         ot->exec = nlaedit_toggle_mute_exec;
1438         ot->poll = nlaop_poll_tweakmode_off;
1439         
1440         /* flags */
1441         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1442 }
1443
1444 /* ******************** Swap Strips Operator ************************** */
1445 /* Tries to exchange strips within their owner tracks */
1446
1447 static int nlaedit_swap_exec(bContext *C, wmOperator *op)
1448 {
1449         bAnimContext ac;
1450         
1451         ListBase anim_data = {NULL, NULL};
1452         bAnimListElem *ale;
1453         int filter;
1454         
1455         /* get editor data */
1456         if (ANIM_animdata_get_context(C, &ac) == 0)
1457                 return OPERATOR_CANCELLED;
1458                 
1459         /* get a list of the editable tracks being shown in the NLA */
1460         filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
1461         ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
1462         
1463         /* consider each track in turn */
1464         for (ale = anim_data.first; ale; ale = ale->next) {
1465                 NlaTrack *nlt = (NlaTrack *)ale->data;
1466                 
1467                 NlaStrip *strip, *stripN = NULL;
1468                 NlaStrip *sa = NULL, *sb = NULL;
1469                 
1470                 /* make temporary metastrips so that entire islands of selections can be moved around */
1471                 BKE_nlastrips_make_metas(&nlt->strips, 1);
1472                 
1473                 /* special case: if there is only 1 island (i.e. temp meta BUT NOT unselected/normal/normal-meta strips) left after this, 
1474                  * and this island has two strips inside it, then we should be able to just swap these still...
1475                  */
1476                 if (BLI_listbase_is_empty(&nlt->strips) == false) {
1477                         NlaStrip *mstrip = (NlaStrip *)nlt->strips.first;
1478                         
1479                         if ((mstrip->flag & NLASTRIP_FLAG_TEMP_META) &&
1480                             (BLI_listbase_count_ex(&mstrip->strips, 3) == 2))
1481                         {
1482                                 /* remove this temp meta, so that we can see the strips inside */
1483                                 BKE_nlastrips_clear_metas(&nlt->strips, 0, 1);
1484                         }
1485                 }
1486                 
1487                 /* get two selected strips only (these will be metas due to prev step) to operate on
1488                  *  - only allow swapping 2, as with more the context becomes unclear
1489                  */
1490                 for (strip = nlt->strips.first; strip; strip = stripN) {
1491                         stripN = strip->next;
1492                         
1493                         if (strip->flag & NLASTRIP_FLAG_SELECT) {
1494                                 /* first or second strip? */
1495                                 if (sa == NULL) {
1496                                         /* store as first */
1497                                         sa = strip;
1498                                 }
1499                                 else if (sb == NULL) {
1500                                         /* store as second */
1501                                         sb = strip;
1502                                 }
1503                                 else {
1504                                         /* too many selected */
1505                                         break;
1506                                 }
1507                         }
1508                 }
1509                 
1510                 if (strip) {
1511                         /* too many selected warning */
1512                         BKE_reportf(op->reports, RPT_WARNING, 
1513                                     "Too many clusters of strips selected in NLA Track (%s): needs exactly 2 to be selected",
1514                                     nlt->name);
1515                 }
1516                 else if (sa == NULL) {
1517                         /* no warning as this is just a common case, and it may get annoying when doing multiple tracks */
1518                 }
1519                 else if (sb == NULL) {
1520                         /* too few selected warning */
1521                         BKE_reportf(op->reports, RPT_WARNING,
1522                                     "Too few clusters of strips selected in NLA Track (%s): needs exactly 2 to be selected",
1523                                     nlt->name);
1524                 }
1525                 else {
1526                         float nsa[2], nsb[2];
1527                         
1528                         /* remove these strips from the track, so that we can test if they can fit in the proposed places */
1529                         BLI_remlink(&nlt->strips, sa);
1530                         BLI_remlink(&nlt->strips, sb);
1531                         
1532                         /* calculate new extents for strips */
1533                         /* a --> b */
1534                         nsa[0] = sb->start;
1535                         nsa[1] = sb->start + (sa->end - sa->start);
1536                         /* b --> a */
1537                         nsb[0] = sa->start;
1538                         nsb[1] = sa->start + (sb->end - sb->start);
1539                         
1540                         /* check if the track has room for the strips to be swapped */
1541                         if (BKE_nlastrips_has_space(&nlt->strips, nsa[0], nsa[1]) && 
1542                             BKE_nlastrips_has_space(&nlt->strips, nsb[0], nsb[1]))
1543                         {
1544                                 /* set new extents for strips then */
1545                                 sa->start = nsa[0];
1546                                 sa->end   = nsa[1];
1547                                 BKE_nlameta_flush_transforms(sa);
1548                                 
1549                                 sb->start = nsb[0];
1550                                 sb->end   = nsb[1];
1551                                 BKE_nlameta_flush_transforms(sb);
1552                         }
1553                         else {
1554                                 /* not enough room to swap, so show message */
1555                                 if ((sa->flag & NLASTRIP_FLAG_TEMP_META) || (sb->flag & NLASTRIP_FLAG_TEMP_META)) {
1556                                         BKE_report(op->reports, RPT_WARNING,
1557                                                    "Cannot swap selected strips as they will not be able to fit in their new places");
1558                                 }
1559                                 else {
1560                                         BKE_reportf(op->reports, RPT_WARNING,
1561                                                     "Cannot swap '%s' and '%s' as one or both will not be able to fit in their new places",
1562                                                     sa->name, sb->name);
1563                                 }
1564                         }
1565                         
1566                         /* add strips back to track now */
1567                         BKE_nlatrack_add_strip(nlt, sa);
1568                         BKE_nlatrack_add_strip(nlt, sb);
1569                 }
1570                 
1571                 /* clear (temp) metastrips */
1572                 BKE_nlastrips_clear_metas(&nlt->strips, 0, 1);
1573         }
1574         
1575         /* free temp data */
1576         ANIM_animdata_freelist(&anim_data);
1577         
1578         /* refresh auto strip properties */
1579         ED_nla_postop_refresh(&ac);
1580         
1581         /* set notifier that things have changed */
1582         WM_event_add_notifier(C, NC_ANIMATION | ND_NLA | NA_EDITED, NULL);
1583         
1584         /* done */
1585         return OPERATOR_FINISHED;
1586 }
1587
1588 void NLA_OT_swap(wmOperatorType *ot)
1589 {
1590         /* identifiers */
1591         ot->name = "Swap Strips";
1592         ot->idname = "NLA_OT_swap";
1593         ot->description = "Swap order of selected strips within tracks";
1594         
1595         /* api callbacks */
1596         ot->exec = nlaedit_swap_exec;
1597         ot->poll = nlaop_poll_tweakmode_off;
1598         
1599         /* flags */
1600         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1601 }
1602
1603 /* ******************** Move Strips Up Operator ************************** */
1604 /* Tries to move the selected strips into the track above if possible. */
1605
1606 static int nlaedit_move_up_exec(bContext *C, wmOperator *UNUSED(op))
1607 {
1608         bAnimContext ac;
1609         
1610         ListBase anim_data = {NULL, NULL};
1611         bAnimListElem *ale;
1612         int filter;
1613         
1614         /* get editor data */
1615         if (ANIM_animdata_get_context(C, &ac) == 0)
1616                 return OPERATOR_CANCELLED;
1617                 
1618         /* get a list of the editable tracks being shown in the NLA */
1619         filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
1620         ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
1621         
1622         /* since we're potentially moving strips from lower tracks to higher tracks, we should
1623          * loop over the tracks in reverse order to avoid moving earlier strips up multiple tracks
1624          */
1625         for (ale = anim_data.last; ale; ale = ale->prev) {
1626                 NlaTrack *nlt = (NlaTrack *)ale->data;
1627                 NlaTrack *nltn = nlt->next;
1628                 NlaStrip *strip, *stripn;
1629                 
1630                 /* if this track has no tracks after it, skip for now... */
1631                 if (nltn == NULL)
1632                         continue;
1633                 
1634                 /* for every selected strip, try to move */
1635                 for (strip = nlt->strips.first; strip; strip = stripn) {
1636                         stripn = strip->next;
1637                         
1638                         if (strip->flag & NLASTRIP_FLAG_SELECT) {
1639                                 /* check if the track above has room for this strip */
1640                                 if (BKE_nlatrack_has_space(nltn, strip->start, strip->end)) {
1641                                         /* remove from its current track, and add to the one above (it 'should' work, so no need to worry) */
1642                                         BLI_remlink(&nlt->strips, strip);
1643                                         BKE_nlatrack_add_strip(nltn, strip);
1644                                 }
1645                         }
1646                 }
1647         }
1648         
1649         /* free temp data */
1650         ANIM_animdata_freelist(&anim_data);
1651         
1652         /* refresh auto strip properties */
1653         ED_nla_postop_refresh(&ac);
1654         
1655         /* set notifier that things have changed */
1656         WM_event_add_notifier(C, NC_ANIMATION | ND_NLA | NA_EDITED, NULL);
1657         
1658         /* done */
1659         return OPERATOR_FINISHED;
1660 }
1661
1662 void NLA_OT_move_up(wmOperatorType *ot)
1663 {
1664         /* identifiers */
1665         ot->name = "Move Strips Up";
1666         ot->idname = "NLA_OT_move_up";
1667         ot->description = "Move selected strips up a track if there's room";
1668         
1669         /* api callbacks */
1670         ot->exec = nlaedit_move_up_exec;
1671         ot->poll = nlaop_poll_tweakmode_off;
1672         
1673         /* flags */
1674         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1675 }
1676
1677 /* ******************** Move Strips Down Operator ************************** */
1678 /* Tries to move the selected strips into the track above if possible. */
1679
1680 static int nlaedit_move_down_exec(bContext *C, wmOperator *UNUSED(op))
1681 {
1682         bAnimContext ac;
1683         
1684         ListBase anim_data = {NULL, NULL};
1685         bAnimListElem *ale;
1686         int filter;
1687         
1688         /* get editor data */
1689         if (ANIM_animdata_get_context(C, &ac) == 0)
1690                 return OPERATOR_CANCELLED;
1691                 
1692         /* get a list of the editable tracks being shown in the NLA */
1693         filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
1694         ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
1695         
1696         /* loop through the tracks in normal order, since we're pushing strips down,
1697          * strips won't get operated on twice
1698          */
1699         for (ale = anim_data.first; ale; ale = ale->next) {
1700                 NlaTrack *nlt = (NlaTrack *)ale->data;
1701                 NlaTrack *nltp = nlt->prev;
1702                 NlaStrip *strip, *stripn;
1703                 
1704                 /* if this track has no tracks before it, skip for now... */
1705                 if (nltp == NULL)
1706                         continue;
1707                 
1708                 /* for every selected strip, try to move */
1709                 for (strip = nlt->strips.first; strip; strip = stripn) {
1710                         stripn = strip->next;
1711                         
1712                         if (strip->flag & NLASTRIP_FLAG_SELECT) {
1713                                 /* check if the track below has room for this strip */
1714                                 if (BKE_nlatrack_has_space(nltp, strip->start, strip->end)) {
1715                                         /* remove from its current track, and add to the one above (it 'should' work, so no need to worry) */
1716                                         BLI_remlink(&nlt->strips, strip);
1717                                         BKE_nlatrack_add_strip(nltp, strip);
1718                                 }
1719                         }
1720                 }
1721         }
1722         
1723         /* free temp data */
1724         ANIM_animdata_freelist(&anim_data);
1725         
1726         /* refresh auto strip properties */
1727         ED_nla_postop_refresh(&ac);
1728         
1729         /* set notifier that things have changed */
1730         WM_event_add_notifier(C, NC_ANIMATION | ND_NLA | NA_EDITED, NULL);
1731         
1732         /* done */
1733         return OPERATOR_FINISHED;
1734 }
1735
1736 void NLA_OT_move_down(wmOperatorType *ot)
1737 {
1738         /* identifiers */
1739         ot->name = "Move Strips Down";
1740         ot->idname = "NLA_OT_move_down";
1741         ot->description = "Move selected strips down a track if there's room";
1742         
1743         /* api callbacks */
1744         ot->exec = nlaedit_move_down_exec;
1745         ot->poll = nlaop_poll_tweakmode_off;
1746         
1747         /* flags */
1748         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1749 }
1750
1751 /* ******************** Sync Action Length Operator ***************************** */
1752 /* Recalculate the extents of the action ranges used for the selected strips  */
1753
1754 static int nlaedit_sync_actlen_exec(bContext *C, wmOperator *op)
1755 {
1756         bAnimContext ac;
1757         
1758         ListBase anim_data = {NULL, NULL};
1759         bAnimListElem *ale;
1760         int filter;
1761         const bool active_only = RNA_boolean_get(op->ptr, "active");
1762         
1763         /* get editor data */
1764         if (ANIM_animdata_get_context(C, &ac) == 0)
1765                 return OPERATOR_CANCELLED;
1766                 
1767         /* get a list of the editable tracks being shown in the NLA */
1768         filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
1769         if (active_only) filter |= ANIMFILTER_ACTIVE;
1770         ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
1771         
1772         /* for each NLA-Track, apply scale of all selected strips */
1773         for (ale = anim_data.first; ale; ale = ale->next) {
1774                 NlaTrack *nlt = (NlaTrack *)ale->data;
1775                 NlaStrip *strip;
1776                 
1777                 for (strip = nlt->strips.first; strip; strip = strip->next) {
1778                         /* strip selection/active status check */
1779                         if (active_only) {
1780                                 if ((strip->flag & NLASTRIP_FLAG_ACTIVE) == 0)
1781                                         continue;
1782                         }
1783                         else {
1784                                 if ((strip->flag & NLASTRIP_FLAG_SELECT) == 0)
1785                                         continue;
1786                         }
1787                         
1788                         /* must be action-clip only (transitions don't have scale) */
1789                         if (strip->type == NLASTRIP_TYPE_CLIP) {
1790                                 if (strip->act == NULL) 
1791                                         continue;
1792                                         
1793                                 /* recalculate the length of the action */
1794                                 calc_action_range(strip->act, &strip->actstart, &strip->actend, 0);
1795                                 
1796                                 /* adjust the strip extents in response to this */
1797                                 BKE_nlastrip_recalculate_bounds(strip);
1798                         }
1799                 }
1800         }
1801         
1802         /* free temp data */
1803         ANIM_animdata_freelist(&anim_data);
1804         
1805         /* set notifier that things have changed */
1806         WM_event_add_notifier(C, NC_ANIMATION | ND_NLA | NA_EDITED, NULL);
1807         
1808         /* done */
1809         return OPERATOR_FINISHED;
1810 }
1811
1812 void NLA_OT_action_sync_length(wmOperatorType *ot)
1813 {
1814         /* identifiers */
1815         ot->name = "Sync Action Length";
1816         ot->idname = "NLA_OT_action_sync_length";
1817         ot->description = "Synchronize the length of the referenced Action with the length used in the strip";
1818         
1819         /* api callbacks */
1820         ot->exec = nlaedit_sync_actlen_exec;
1821         ot->poll = nlaop_poll_tweakmode_off;
1822         
1823         /* flags */
1824         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1825         
1826         /* properties */
1827         ot->prop = RNA_def_boolean(ot->srna, "active", 1, "Active Strip Only", "Only sync the active length for the active strip");
1828 }
1829
1830 /* ******************** Make Single User ********************************* */
1831 /* Ensure that each strip has its own action */
1832
1833 static int nlaedit_make_single_user_exec(bContext *C, wmOperator *UNUSED(op))
1834 {
1835         bAnimContext ac;
1836         
1837         ListBase anim_data = {NULL, NULL};
1838         bAnimListElem *ale;
1839         int filter;
1840         
1841         /* get editor data */
1842         if (ANIM_animdata_get_context(C, &ac) == 0)
1843                 return OPERATOR_CANCELLED;
1844                 
1845         /* get a list of the editable tracks being shown in the NLA */
1846         filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
1847         ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
1848         
1849         /* Ensure that each action used only has a single user
1850          *   - This is done in reverse order so that the original strips are
1851          *     likely to still get to keep their action
1852          */
1853         for (ale = anim_data.last; ale; ale = ale->prev) {
1854                 NlaTrack *nlt = (NlaTrack *)ale->data;
1855                 NlaStrip *strip;
1856                 
1857                 for (strip = nlt->strips.last; strip; strip = strip->prev) {
1858                         /* must be action-clip only (as only these have actions) */
1859                         if ((strip->flag & NLASTRIP_FLAG_SELECT) && (strip->type == NLASTRIP_TYPE_CLIP)) {
1860                                 if (strip->act == NULL) 
1861                                         continue;
1862                                 
1863                                 /* multi-user? */
1864                                 if (ID_REAL_USERS(strip->act) > 1) {
1865                                         /* make a new copy of the action for us to use (it will have 1 user already) */
1866                                         bAction *new_action = BKE_action_copy(strip->act);
1867                                         
1868                                         /* decrement user count of our existing action */
1869                                         id_us_min(&strip->act->id);
1870                                         
1871                                         /* switch to the new copy */
1872                                         strip->act = new_action;
1873                                 }
1874                         }
1875                 }
1876         }
1877         
1878         /* free temp data */
1879         ANIM_animdata_freelist(&anim_data);
1880         
1881         /* set notifier that things have changed */
1882         WM_event_add_notifier(C, NC_ANIMATION | ND_NLA | NA_EDITED, NULL);
1883         
1884         /* done */
1885         return OPERATOR_FINISHED;
1886 }
1887
1888 void NLA_OT_make_single_user(wmOperatorType *ot)
1889 {
1890         /* identifiers */
1891         ot->name = "Make Single User";
1892         ot->idname = "NLA_OT_make_single_user";
1893         ot->description = "Ensure that each action is only used once in the set of strips selected";
1894         
1895         /* api callbacks */
1896         ot->invoke = WM_operator_confirm;
1897         ot->exec = nlaedit_make_single_user_exec;
1898         ot->poll = nlaop_poll_tweakmode_off;
1899         
1900         /* flags */
1901         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1902 }
1903
1904 /* ******************** Apply Scale Operator ***************************** */
1905 /* Reset the scaling of the selected strips to 1.0f */
1906
1907 /* apply scaling to keyframe */
1908 static short bezt_apply_nlamapping(KeyframeEditData *ked, BezTriple *bezt)
1909 {
1910         /* NLA-strip which has this scaling is stored in ked->data */
1911         NlaStrip *strip = (NlaStrip *)ked->data;
1912         
1913         /* adjust all the times */
1914         bezt->vec[0][0] = nlastrip_get_frame(strip, bezt->vec[0][0], NLATIME_CONVERT_MAP);
1915         bezt->vec[1][0] = nlastrip_get_frame(strip, bezt->vec[1][0], NLATIME_CONVERT_MAP);
1916         bezt->vec[2][0] = nlastrip_get_frame(strip, bezt->vec[2][0], NLATIME_CONVERT_MAP);
1917         
1918         /* nothing to return or else we exit */
1919         return 0;
1920 }
1921
1922 static int nlaedit_apply_scale_exec(bContext *C, wmOperator *UNUSED(op))
1923 {
1924         bAnimContext ac;
1925         
1926         ListBase anim_data = {NULL, NULL};
1927         bAnimListElem *ale;
1928         int filter;
1929         
1930         KeyframeEditData ked = {{NULL}};
1931         
1932         /* get editor data */
1933         if (ANIM_animdata_get_context(C, &ac) == 0)
1934                 return OPERATOR_CANCELLED;
1935                 
1936         /* get a list of the editable tracks being shown in the NLA */
1937         filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
1938         ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
1939         
1940         /* for each NLA-Track, apply scale of all selected strips */
1941         for (ale = anim_data.first; ale; ale = ale->next) {
1942                 NlaTrack *nlt = (NlaTrack *)ale->data;
1943                 NlaStrip *strip;
1944                 
1945                 for (strip = nlt->strips.first; strip; strip = strip->next) {
1946                         /* strip must be selected, and must be action-clip only (transitions don't have scale) */
1947                         if ((strip->flag & NLASTRIP_FLAG_SELECT) && (strip->type == NLASTRIP_TYPE_CLIP)) {
1948                                 /* if the referenced action is used by other strips, make this strip use its own copy */
1949                                 if (strip->act == NULL) 
1950                                         continue;
1951                                 if (strip->act->id.us > 1) {
1952                                         /* make a copy of the Action to work on */
1953                                         bAction *act = BKE_action_copy(strip->act);
1954                                         
1955                                         /* set this as the new referenced action, decrementing the users of the old one */
1956                                         id_us_min(&strip->act->id);
1957                                         strip->act = act;
1958                                 }
1959                                 
1960                                 /* setup iterator, and iterate over all the keyframes in the action, applying this scaling */
1961                                 ked.data = strip;
1962                                 ANIM_animchanneldata_keyframes_loop(&ked, ac.ads, strip->act, ALE_ACT, NULL, bezt_apply_nlamapping, calchandles_fcurve);
1963                                 
1964                                 /* clear scale of strip now that it has been applied,
1965                                  * and recalculate the extents of the action now that it has been scaled
1966                                  * but leave everything else alone 
1967                                  */
1968                                 strip->scale = 1.0f;
1969                                 calc_action_range(strip->act, &strip->actstart, &strip->actend, 0);
1970                         }
1971                 }
1972         }
1973         
1974         /* free temp data */
1975         ANIM_animdata_freelist(&anim_data);
1976         
1977         /* set notifier that things have changed */
1978         WM_event_add_notifier(C, NC_ANIMATION | ND_NLA | NA_EDITED, NULL);
1979         
1980         /* done */
1981         return OPERATOR_FINISHED;
1982 }
1983
1984 void NLA_OT_apply_scale(wmOperatorType *ot)
1985 {
1986         /* identifiers */
1987         ot->name = "Apply Scale";
1988         ot->idname = "NLA_OT_apply_scale";
1989         ot->description = "Apply scaling of selected strips to their referenced Actions";
1990         
1991         /* api callbacks */
1992         ot->exec = nlaedit_apply_scale_exec;
1993         ot->poll = nlaop_poll_tweakmode_off;
1994         
1995         /* flags */
1996         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1997 }
1998
1999 /* ******************** Clear Scale Operator ***************************** */
2000 /* Reset the scaling of the selected strips to 1.0f */
2001
2002 static int nlaedit_clear_scale_exec(bContext *C, wmOperator *UNUSED(op))
2003 {
2004         bAnimContext ac;
2005         
2006         ListBase anim_data = {NULL, NULL};
2007         bAnimListElem *ale;
2008         int filter;
2009         
2010         /* get editor data */
2011         if (ANIM_animdata_get_context(C, &ac) == 0)
2012                 return OPERATOR_CANCELLED;
2013                 
2014         /* get a list of the editable tracks being shown in the NLA */
2015         filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
2016         ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
2017         
2018         /* for each NLA-Track, reset scale of all selected strips */
2019         for (ale = anim_data.first; ale; ale = ale->next) {
2020                 NlaTrack *nlt = (NlaTrack *)ale->data;
2021                 NlaStrip *strip;
2022                 
2023                 for (strip = nlt->strips.first; strip; strip = strip->next) {
2024                         /* strip must be selected, and must be action-clip only (transitions don't have scale) */
2025                         if ((strip->flag & NLASTRIP_FLAG_SELECT) && (strip->type == NLASTRIP_TYPE_CLIP)) {
2026                                 PointerRNA strip_ptr;
2027                                 
2028                                 RNA_pointer_create(NULL, &RNA_NlaStrip, strip, &strip_ptr);
2029                                 RNA_float_set(&strip_ptr, "scale", 1.0f);
2030                         }
2031                 }
2032         }
2033         
2034         /* free temp data */
2035         ANIM_animdata_freelist(&anim_data);
2036         
2037         /* refresh auto strip properties */
2038         ED_nla_postop_refresh(&ac);
2039         
2040         /* set notifier that things have changed */
2041         WM_event_add_notifier(C, NC_ANIMATION | ND_NLA | NA_EDITED, NULL);
2042         
2043         /* done */
2044         return OPERATOR_FINISHED;
2045 }
2046
2047 void NLA_OT_clear_scale(wmOperatorType *ot)
2048 {
2049         /* identifiers */
2050         ot->name = "Clear Scale";
2051         ot->idname = "NLA_OT_clear_scale";
2052         ot->description = "Reset scaling of selected strips";
2053         
2054         /* api callbacks */
2055         ot->exec = nlaedit_clear_scale_exec;
2056         ot->poll = nlaop_poll_tweakmode_off;
2057         
2058         /* flags */
2059         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2060 }
2061
2062 /* ******************** Snap Strips Operator ************************** */
2063 /* Moves the start-point of the selected strips to the specified places */
2064
2065 /* defines for snap keyframes tool */
2066 static EnumPropertyItem prop_nlaedit_snap_types[] = {
2067         {NLAEDIT_SNAP_CFRA, "CFRA", 0, "Current Frame", ""},
2068         {NLAEDIT_SNAP_NEAREST_FRAME, "NEAREST_FRAME", 0, "Nearest Frame", ""}, // XXX as single entry?
2069         {NLAEDIT_SNAP_NEAREST_SECOND, "NEAREST_SECOND", 0, "Nearest Second", ""}, // XXX as single entry?
2070         {NLAEDIT_SNAP_NEAREST_MARKER, "NEAREST_MARKER", 0, "Nearest Marker", ""},
2071         {0, NULL, 0, NULL, NULL}
2072 };
2073
2074 static int nlaedit_snap_exec(bContext *C, wmOperator *op)
2075 {
2076         bAnimContext ac;
2077         
2078         ListBase anim_data = {NULL, NULL};
2079         bAnimListElem *ale;
2080         int filter;
2081         
2082         Scene *scene;
2083         int mode = RNA_enum_get(op->ptr, "type");
2084         float secf;
2085         
2086         /* get editor data */
2087         if (ANIM_animdata_get_context(C, &ac) == 0)
2088                 return OPERATOR_CANCELLED;
2089                 
2090         /* get a list of the editable tracks being shown in the NLA */
2091         filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
2092         ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
2093         
2094         /* get some necessary vars */
2095         scene = ac.scene;
2096         secf = (float)FPS;
2097         
2098         /* since we may add tracks, perform this in reverse order */
2099         for (ale = anim_data.last; ale; ale = ale->prev) {
2100                 ListBase tmp_strips = {NULL, NULL};
2101                 AnimData *adt = ale->adt;
2102                 NlaTrack *nlt = (NlaTrack *)ale->data;
2103                 NlaStrip *strip, *stripn;
2104                 NlaTrack *track;
2105                 
2106                 /* create meta-strips from the continuous chains of selected strips */
2107                 BKE_nlastrips_make_metas(&nlt->strips, 1);
2108                 
2109                 /* apply the snapping to all the temp meta-strips, then put them in a separate list to be added
2110                  * back to the original only if they still fit
2111                  */
2112                 for (strip = nlt->strips.first; strip; strip = stripn) {
2113                         stripn = strip->next;
2114                         
2115                         if (strip->flag & NLASTRIP_FLAG_TEMP_META) {
2116                                 float start, end;
2117                                 
2118                                 /* get the existing end-points */
2119                                 start = strip->start;
2120                                 end = strip->end;
2121                                 
2122                                 /* calculate new start position based on snapping mode */
2123                                 switch (mode) {
2124                                         case NLAEDIT_SNAP_CFRA: /* to current frame */
2125                                                 strip->start = (float)CFRA;
2126                                                 break;
2127                                         case NLAEDIT_SNAP_NEAREST_FRAME: /* to nearest frame */
2128                                                 strip->start = floorf(start + 0.5f);
2129                                                 break;
2130                                         case NLAEDIT_SNAP_NEAREST_SECOND: /* to nearest second */
2131                                                 strip->start = floorf(start / secf + 0.5f) * secf;
2132                                                 break;
2133                                         case NLAEDIT_SNAP_NEAREST_MARKER: /* to nearest marker */
2134                                                 strip->start = (float)ED_markers_find_nearest_marker_time(ac.markers, start);
2135                                                 break;
2136                                         default: /* just in case... no snapping */
2137                                                 strip->start = start;
2138                                                 break;
2139                                 }
2140                                 
2141                                 /* get new endpoint based on start-point (and old length) */
2142                                 strip->end = strip->start + (end - start);
2143                                 
2144                                 /* apply transforms to meta-strip to its children */
2145                                 BKE_nlameta_flush_transforms(strip);
2146                                 
2147                                 /* remove strip from track, and add to the temp buffer */
2148                                 BLI_remlink(&nlt->strips, strip);
2149                                 BLI_addtail(&tmp_strips, strip);
2150                         }
2151                 }
2152                 
2153                 /* try adding each meta-strip back to the track one at a time, to make sure they'll fit */
2154                 for (strip = tmp_strips.first; strip; strip = stripn) {
2155                         stripn = strip->next;
2156                         
2157                         /* remove from temp-strips list */
2158                         BLI_remlink(&tmp_strips, strip);
2159                         
2160                         /* in case there's no space in the current track, try adding */
2161                         if (BKE_nlatrack_add_strip(nlt, strip) == 0) {
2162                                 /* need to add a new track above the current one */
2163                                 track = add_nlatrack(adt, nlt);
2164                                 BKE_nlatrack_add_strip(track, strip);
2165                                 
2166                                 /* clear temp meta-strips on this new track, as we may not be able to get back to it */
2167                                 BKE_nlastrips_clear_metas(&track->strips, 0, 1);
2168                         }
2169                 }
2170                 
2171                 /* remove the meta-strips now that we're done */
2172                 BKE_nlastrips_clear_metas(&nlt->strips, 0, 1);
2173                 
2174                 /* tag for recalculating the animation */
2175                 ale->update |= ANIM_UPDATE_DEPS;
2176         }
2177         
2178         /* cleanup */
2179         ANIM_animdata_update(&ac, &anim_data);
2180         ANIM_animdata_freelist(&anim_data);
2181         
2182         /* refresh auto strip properties */
2183         ED_nla_postop_refresh(&ac);
2184         
2185         /* set notifier that things have changed */
2186         WM_event_add_notifier(C, NC_ANIMATION | ND_NLA | NA_EDITED, NULL);
2187         
2188         /* done */
2189         return OPERATOR_FINISHED;
2190 }
2191
2192 void NLA_OT_snap(wmOperatorType *ot)
2193 {
2194         /* identifiers */
2195         ot->name = "Snap Strips";
2196         ot->idname = "NLA_OT_snap";
2197         ot->description = "Move start of strips to specified time";
2198         
2199         /* api callbacks */
2200         ot->invoke = WM_menu_invoke;
2201         ot->exec = nlaedit_snap_exec;
2202         ot->poll = nlaop_poll_tweakmode_off;
2203         
2204         /* flags */
2205         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2206         
2207         /* properties */
2208         ot->prop = RNA_def_enum(ot->srna, "type", prop_nlaedit_snap_types, 0, "Type", "");
2209 }
2210
2211 /* *********************************************** */
2212 /* NLA Modifiers */
2213
2214 /* ******************** Add F-Modifier Operator *********************** */
2215
2216 /* present a special customised popup menu for this, with some filtering */
2217 static int nla_fmodifier_add_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *UNUSED(event))
2218 {
2219         uiPopupMenu *pup;
2220         uiLayout *layout;
2221         int i;
2222         
2223         pup = UI_popup_menu_begin(C, IFACE_("Add F-Modifier"), ICON_NONE);
2224         layout = UI_popup_menu_layout(pup);
2225         
2226         /* start from 1 to skip the 'Invalid' modifier type */
2227         for (i = 1; i < FMODIFIER_NUM_TYPES; i++) {
2228                 const FModifierTypeInfo *fmi = get_fmodifier_typeinfo(i);
2229                 
2230                 /* check if modifier is valid for this context */
2231                 if (fmi == NULL)
2232                         continue;
2233                 if (i == FMODIFIER_TYPE_CYCLES) /* we already have repeat... */
2234                         continue;
2235                 
2236                 /* add entry to add this type of modifier */
2237                 uiItemEnumO(layout, "NLA_OT_fmodifier_add", fmi->name, 0, "type", i);
2238         }
2239         uiItemS(layout);
2240         
2241         UI_popup_menu_end(C, pup);
2242         
2243         return OPERATOR_INTERFACE;
2244 }
2245
2246 static int nla_fmodifier_add_exec(bContext *C, wmOperator *op)
2247 {
2248         bAnimContext ac;
2249         
2250         ListBase anim_data = {NULL, NULL};
2251         bAnimListElem *ale;
2252         int filter;
2253         
2254         FModifier *fcm;
2255         int type = RNA_enum_get(op->ptr, "type");
2256         const bool active_only = RNA_boolean_get(op->ptr, "only_active");
2257         
2258         /* get editor data */
2259         if (ANIM_animdata_get_context(C, &ac) == 0)
2260                 return OPERATOR_CANCELLED;
2261                 
2262         /* get a list of the editable tracks being shown in the NLA */
2263         filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
2264         ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
2265         
2266         /* for each NLA-Track, add the specified modifier to all selected strips */
2267         for (ale = anim_data.first; ale; ale = ale->next) {
2268                 NlaTrack *nlt = (NlaTrack *)ale->data;
2269                 NlaStrip *strip;
2270                 
2271                 for (strip = nlt->strips.first; strip; strip = strip->next) {
2272                         /* can F-Modifier be added to the current strip? */
2273                         if (active_only) {
2274                                 /* if not active, cannot add since we're only adding to active strip */
2275                                 if ((strip->flag & NLASTRIP_FLAG_ACTIVE) == 0)
2276                                         continue;
2277                         }
2278                         else {
2279                                 /* strip must be selected, since we're not just doing active */
2280                                 if ((strip->flag & NLASTRIP_FLAG_SELECT) == 0)
2281                                         continue;
2282                         }
2283                         
2284                         /* sound clips are not affected by FModifiers */
2285                         if (strip->type == NLASTRIP_TYPE_SOUND)
2286                                 continue;
2287                         
2288                         /* add F-Modifier of specified type to selected, and make it the active one */
2289                         fcm = add_fmodifier(&strip->modifiers, type);
2290                         
2291                         if (fcm) {
2292                                 set_active_fmodifier(&strip->modifiers, fcm);
2293                                 ale->update |= ANIM_UPDATE_DEPS;
2294                         }
2295                         else {
2296                                 BKE_reportf(op->reports, RPT_ERROR,
2297                                             "Modifier could not be added to (%s : %s) (see console for details)",
2298                                             nlt->name, strip->name);
2299                         }
2300                 }
2301         }
2302         
2303         /* free temp data */
2304         ANIM_animdata_update(&ac, &anim_data);
2305         ANIM_animdata_freelist(&anim_data);
2306         
2307         /* set notifier that things have changed */
2308         WM_event_add_notifier(C, NC_ANIMATION | ND_NLA | NA_EDITED, NULL);
2309         
2310         /* done */
2311         return OPERATOR_FINISHED;
2312 }
2313  
2314 void NLA_OT_fmodifier_add(wmOperatorType *ot)
2315 {
2316         /* identifiers */
2317         ot->name = "Add F-Modifier";
2318         ot->idname = "NLA_OT_fmodifier_add";
2319         ot->description = "Add a F-Modifier of the specified type to the selected NLA-Strips";
2320         
2321         /* api callbacks */
2322         ot->invoke = nla_fmodifier_add_invoke;
2323         ot->exec = nla_fmodifier_add_exec;
2324         ot->poll = nlaop_poll_tweakmode_off; 
2325         
2326         /* flags */
2327         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2328         
2329         /* id-props */
2330         ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_fmodifier_type_items, 0, "Type", "");
2331         RNA_def_boolean(ot->srna, "only_active", 0, "Only Active", "Only add a F-Modifier of the specified type to the active strip");
2332 }
2333
2334 /* ******************** Copy F-Modifiers Operator *********************** */
2335
2336 static int nla_fmodifier_copy_exec(bContext *C, wmOperator *op)
2337 {
2338         bAnimContext ac;
2339         ListBase anim_data = {NULL, NULL};
2340         bAnimListElem *ale;
2341         int filter;
2342         bool ok = false;
2343         
2344         /* get editor data */
2345         if (ANIM_animdata_get_context(C, &ac) == 0)
2346                 return OPERATOR_CANCELLED;
2347         
2348         /* clear buffer first */
2349         free_fmodifiers_copybuf();
2350         
2351         /* get a list of the editable tracks being shown in the NLA */
2352         filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
2353         ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
2354         
2355         /* for each NLA-Track, add the specified modifier to all selected strips */
2356         for (ale = anim_data.first; ale; ale = ale->next) {
2357                 NlaTrack *nlt = (NlaTrack *)ale->data;
2358                 NlaStrip *strip;
2359                 
2360                 for (strip = nlt->strips.first; strip; strip = strip->next) {
2361                         /* only add F-Modifier if on active strip? */
2362                         if ((strip->flag & NLASTRIP_FLAG_ACTIVE) == 0)
2363                                 continue;
2364                                 
2365                         // TODO: when 'active' vs 'all' boolean is added, change last param!
2366                         ok |= ANIM_fmodifiers_copy_to_buf(&strip->modifiers, 0);
2367                 }
2368         }
2369         
2370         /* free temp data */
2371         ANIM_animdata_freelist(&anim_data);
2372         
2373         /* successful or not? */
2374         if (ok == 0) {
2375                 BKE_report(op->reports, RPT_ERROR, "No F-Modifiers available to be copied");
2376                 return OPERATOR_CANCELLED;
2377         }
2378         else {
2379                 /* no updates needed - copy is non-destructive operation */
2380                 return OPERATOR_FINISHED;
2381         }
2382 }
2383  
2384 void NLA_OT_fmodifier_copy(wmOperatorType *ot)
2385 {
2386         /* identifiers */
2387         ot->name = "Copy F-Modifiers";
2388         ot->idname = "NLA_OT_fmodifier_copy";
2389         ot->description = "Copy the F-Modifier(s) of the active NLA-Strip";
2390         
2391         /* api callbacks */
2392         ot->exec = nla_fmodifier_copy_exec;
2393         ot->poll = nlaop_poll_tweakmode_off; 
2394         
2395         /* flags */
2396         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2397         
2398         /* id-props */
2399         //ot->prop = RNA_def_boolean(ot->srna, "all", 1, "All F-Modifiers", "Copy all the F-Modifiers, instead of just the active one");
2400 }
2401
2402 /* ******************** Paste F-Modifiers Operator *********************** */
2403
2404 static int nla_fmodifier_paste_exec(bContext *C, wmOperator *op)
2405 {
2406         bAnimContext ac;
2407         ListBase anim_data = {NULL, NULL};
2408         bAnimListElem *ale;
2409         int filter, ok = 0;
2410         
2411         /* get editor data */
2412         if (ANIM_animdata_get_context(C, &ac) == 0)
2413                 return OPERATOR_CANCELLED;
2414         
2415         /* get a list of the editable tracks being shown in the NLA */
2416         filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_SEL | ANIMFILTER_FOREDIT);
2417         ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
2418         
2419         /* for each NLA-Track, add the specified modifier to all selected strips */
2420         for (ale = anim_data.first; ale; ale = ale->next) {
2421                 NlaTrack *nlt = (NlaTrack *)ale->data;
2422                 NlaStrip *strip;
2423                 
2424                 for (strip = nlt->strips.first; strip; strip = strip->next) {
2425                         // TODO: do we want to replace existing modifiers? add user pref for that!
2426                         ok += ANIM_fmodifiers_paste_from_buf(&strip->modifiers, 0);
2427                         ale->update |= ANIM_UPDATE_DEPS;
2428                 }
2429         }
2430         
2431         /* clean up */
2432         ANIM_animdata_update(&ac, &anim_data);
2433         ANIM_animdata_freelist(&anim_data);
2434         
2435         /* successful or not? */
2436         if (ok) {
2437                 WM_event_add_notifier(C, NC_ANIMATION | ND_NLA | NA_EDITED, NULL);
2438                 return OPERATOR_FINISHED;
2439         }
2440         else {
2441                 BKE_report(op->reports, RPT_ERROR, "No F-Modifiers to paste");
2442                 return OPERATOR_CANCELLED;
2443         }
2444 }
2445  
2446 void NLA_OT_fmodifier_paste(wmOperatorType *ot)
2447 {
2448         /* identifiers */
2449         ot->name = "Paste F-Modifiers";
2450         ot->idname = "NLA_OT_fmodifier_paste";
2451         ot->description = "Add copied F-Modifiers to the selected NLA-Strips";
2452         
2453         /* api callbacks */
2454         ot->exec = nla_fmodifier_paste_exec;
2455         ot->poll = nlaop_poll_tweakmode_off;
2456         
2457         /* flags */
2458         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2459 }
2460
2461 /* *********************************************** */