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