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