Cleanup: style, use braces for blenkernel
[blender.git] / source / blender / blenkernel / intern / nla.c
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2009 Blender Foundation, Joshua Leung
17  * All rights reserved.
18  */
19
20 /** \file
21  * \ingroup bke
22  */
23
24 #include <stdlib.h>
25 #include <stddef.h>
26 #include <stdio.h>
27 #include <string.h>
28 #include <math.h>
29 #include <float.h>
30
31 #include "CLG_log.h"
32
33 #include "MEM_guardedalloc.h"
34
35 #include "BLI_utildefines.h"
36 #include "BLI_listbase.h"
37 #include "BLI_string.h"
38 #include "BLI_string_utils.h"
39 #include "BLI_ghash.h"
40
41 #include "BLT_translation.h"
42
43 #include "DNA_anim_types.h"
44 #include "DNA_scene_types.h"
45 #include "DNA_sound_types.h"
46 #include "DNA_speaker_types.h"
47
48 #include "BKE_action.h"
49 #include "BKE_fcurve.h"
50 #include "BKE_global.h"
51 #include "BKE_library.h"
52 #include "BKE_main.h"
53 #include "BKE_nla.h"
54
55 #ifdef WITH_AUDASPACE
56 #  include <AUD_Special.h>
57 #endif
58
59 #include "RNA_access.h"
60 #include "nla_private.h"
61
62 static CLG_LogRef LOG = {"bke.nla"};
63
64 /* *************************************************** */
65 /* Data Management */
66
67 /* Freeing ------------------------------------------- */
68
69 /* Remove the given NLA strip from the NLA track it occupies, free the strip's data,
70  * and the strip itself.
71  */
72 void BKE_nlastrip_free(ListBase *strips, NlaStrip *strip, bool do_id_user)
73 {
74   NlaStrip *cs, *csn;
75
76   /* sanity checks */
77   if (strip == NULL) {
78     return;
79   }
80
81   /* free child-strips */
82   for (cs = strip->strips.first; cs; cs = csn) {
83     csn = cs->next;
84     BKE_nlastrip_free(&strip->strips, cs, do_id_user);
85   }
86
87   /* remove reference to action */
88   if (strip->act != NULL && do_id_user) {
89     id_us_min(&strip->act->id);
90   }
91
92   /* free remapping info */
93   //if (strip->remap)
94   //  BKE_animremap_free();
95
96   /* free own F-Curves */
97   free_fcurves(&strip->fcurves);
98
99   /* free own F-Modifiers */
100   free_fmodifiers(&strip->modifiers);
101
102   /* free the strip itself */
103   if (strips) {
104     BLI_freelinkN(strips, strip);
105   }
106   else {
107     MEM_freeN(strip);
108   }
109 }
110
111 /* Remove the given NLA track from the set of NLA tracks, free the track's data,
112  * and the track itself.
113  */
114 void BKE_nlatrack_free(ListBase *tracks, NlaTrack *nlt, bool do_id_user)
115 {
116   NlaStrip *strip, *stripn;
117
118   /* sanity checks */
119   if (nlt == NULL) {
120     return;
121   }
122
123   /* free strips */
124   for (strip = nlt->strips.first; strip; strip = stripn) {
125     stripn = strip->next;
126     BKE_nlastrip_free(&nlt->strips, strip, do_id_user);
127   }
128
129   /* free NLA track itself now */
130   if (tracks) {
131     BLI_freelinkN(tracks, nlt);
132   }
133   else {
134     MEM_freeN(nlt);
135   }
136 }
137
138 /* Free the elements of type NLA Tracks provided in the given list, but do not free
139  * the list itself since that is not free-standing
140  */
141 void BKE_nla_tracks_free(ListBase *tracks, bool do_id_user)
142 {
143   NlaTrack *nlt, *nltn;
144
145   /* sanity checks */
146   if (ELEM(NULL, tracks, tracks->first)) {
147     return;
148   }
149
150   /* free tracks one by one */
151   for (nlt = tracks->first; nlt; nlt = nltn) {
152     nltn = nlt->next;
153     BKE_nlatrack_free(tracks, nlt, do_id_user);
154   }
155
156   /* clear the list's pointers to be safe */
157   BLI_listbase_clear(tracks);
158 }
159
160 /* Copying ------------------------------------------- */
161
162 /**
163  * Copy NLA strip
164  *
165  * \param use_same_action: When true, the existing action is used (instead of being duplicated)
166  * \param flag: Control ID pointers management, see LIB_ID_CREATE_.../LIB_ID_COPY_... flags in BKE_library.h
167  */
168 NlaStrip *BKE_nlastrip_copy(Main *bmain,
169                             NlaStrip *strip,
170                             const bool use_same_action,
171                             const int flag)
172 {
173   NlaStrip *strip_d;
174   NlaStrip *cs, *cs_d;
175
176   const bool do_id_user = (flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0;
177
178   /* sanity check */
179   if (strip == NULL) {
180     return NULL;
181   }
182
183   /* make a copy */
184   strip_d = MEM_dupallocN(strip);
185   strip_d->next = strip_d->prev = NULL;
186
187   /* handle action */
188   if (strip_d->act) {
189     if (use_same_action) {
190       if (do_id_user) {
191         /* increase user-count of action */
192         id_us_plus(&strip_d->act->id);
193       }
194     }
195     else {
196       /* use a copy of the action instead (user count shouldn't have changed yet) */
197       BKE_id_copy_ex(bmain, &strip_d->act->id, (ID **)&strip_d->act, flag);
198     }
199   }
200
201   /* copy F-Curves and modifiers */
202   copy_fcurves(&strip_d->fcurves, &strip->fcurves);
203   copy_fmodifiers(&strip_d->modifiers, &strip->modifiers);
204
205   /* make a copy of all the child-strips, one at a time */
206   BLI_listbase_clear(&strip_d->strips);
207
208   for (cs = strip->strips.first; cs; cs = cs->next) {
209     cs_d = BKE_nlastrip_copy(bmain, cs, use_same_action, flag);
210     BLI_addtail(&strip_d->strips, cs_d);
211   }
212
213   /* return the strip */
214   return strip_d;
215 }
216
217 /**
218  * Copy a single NLA Track.
219  * \param flag: Control ID pointers management, see LIB_ID_CREATE_.../LIB_ID_COPY_... flags in BKE_library.h
220  */
221 NlaTrack *BKE_nlatrack_copy(Main *bmain,
222                             NlaTrack *nlt,
223                             const bool use_same_actions,
224                             const int flag)
225 {
226   NlaStrip *strip, *strip_d;
227   NlaTrack *nlt_d;
228
229   /* sanity check */
230   if (nlt == NULL) {
231     return NULL;
232   }
233
234   /* make a copy */
235   nlt_d = MEM_dupallocN(nlt);
236   nlt_d->next = nlt_d->prev = NULL;
237
238   /* make a copy of all the strips, one at a time */
239   BLI_listbase_clear(&nlt_d->strips);
240
241   for (strip = nlt->strips.first; strip; strip = strip->next) {
242     strip_d = BKE_nlastrip_copy(bmain, strip, use_same_actions, flag);
243     BLI_addtail(&nlt_d->strips, strip_d);
244   }
245
246   /* return the copy */
247   return nlt_d;
248 }
249
250 /**
251  * Copy all NLA data.
252  * \param flag: Control ID pointers management, see LIB_ID_CREATE_.../LIB_ID_COPY_... flags in BKE_library.h
253  */
254 void BKE_nla_tracks_copy(Main *bmain, ListBase *dst, ListBase *src, const int flag)
255 {
256   NlaTrack *nlt, *nlt_d;
257
258   /* sanity checks */
259   if (ELEM(NULL, dst, src)) {
260     return;
261   }
262
263   /* clear out the destination list first for precautions... */
264   BLI_listbase_clear(dst);
265
266   /* copy each NLA-track, one at a time */
267   for (nlt = src->first; nlt; nlt = nlt->next) {
268     /* make a copy, and add the copy to the destination list */
269     // XXX: we need to fix this sometime
270     nlt_d = BKE_nlatrack_copy(bmain, nlt, true, flag);
271     BLI_addtail(dst, nlt_d);
272   }
273 }
274
275 /* Adding ------------------------------------------- */
276
277 /* Add a NLA Track to the given AnimData
278  * - prev: NLA-Track to add the new one after
279  */
280 NlaTrack *BKE_nlatrack_add(AnimData *adt, NlaTrack *prev)
281 {
282   NlaTrack *nlt;
283
284   /* sanity checks */
285   if (adt == NULL) {
286     return NULL;
287   }
288
289   /* allocate new track */
290   nlt = MEM_callocN(sizeof(NlaTrack), "NlaTrack");
291
292   /* set settings requiring the track to not be part of the stack yet */
293   nlt->flag = NLATRACK_SELECTED;
294   nlt->index = BLI_listbase_count(&adt->nla_tracks);
295
296   /* add track to stack, and make it the active one */
297   if (prev) {
298     BLI_insertlinkafter(&adt->nla_tracks, prev, nlt);
299   }
300   else {
301     BLI_addtail(&adt->nla_tracks, nlt);
302   }
303   BKE_nlatrack_set_active(&adt->nla_tracks, nlt);
304
305   /* must have unique name, but we need to seed this */
306   strcpy(nlt->name, "NlaTrack");
307   BLI_uniquename(
308       &adt->nla_tracks, nlt, DATA_("NlaTrack"), '.', offsetof(NlaTrack, name), sizeof(nlt->name));
309
310   /* return the new track */
311   return nlt;
312 }
313
314 /* Create a NLA Strip referencing the given Action */
315 NlaStrip *BKE_nlastrip_new(bAction *act)
316 {
317   NlaStrip *strip;
318
319   /* sanity checks */
320   if (act == NULL) {
321     return NULL;
322   }
323
324   /* allocate new strip */
325   strip = MEM_callocN(sizeof(NlaStrip), "NlaStrip");
326
327   /* generic settings
328    * - selected flag to highlight this to the user
329    * - (XXX) disabled Auto-Blends, as this was often causing some unwanted effects
330    * - (XXX) synchronization of strip-length in accordance with changes to action-length
331    *   is not done though, since this should only really happens in editmode for strips now
332    *   though this decision is still subject to further review...
333    */
334   strip->flag = NLASTRIP_FLAG_SELECT;
335
336   /* assign the action reference */
337   strip->act = act;
338   id_us_plus(&act->id);
339
340   /* determine initial range
341    * - strip length cannot be 0... ever...
342    */
343   calc_action_range(strip->act, &strip->actstart, &strip->actend, 0);
344
345   strip->start = strip->actstart;
346   strip->end = (IS_EQF(strip->actstart, strip->actend)) ? (strip->actstart + 1.0f) :
347                                                           (strip->actend);
348
349   /* strip should be referenced as-is */
350   strip->scale = 1.0f;
351   strip->repeat = 1.0f;
352
353   /* return the new strip */
354   return strip;
355 }
356
357 /* Add new NLA-strip to the top of the NLA stack - i.e. into the last track if space, or a new one otherwise */
358 NlaStrip *BKE_nlastack_add_strip(AnimData *adt, bAction *act)
359 {
360   NlaStrip *strip;
361   NlaTrack *nlt;
362
363   /* sanity checks */
364   if (ELEM(NULL, adt, act)) {
365     return NULL;
366   }
367
368   /* create a new NLA strip */
369   strip = BKE_nlastrip_new(act);
370   if (strip == NULL) {
371     return NULL;
372   }
373
374   /* firstly try adding strip to last track, but if that fails, add to a new track */
375   if (BKE_nlatrack_add_strip(adt->nla_tracks.last, strip) == 0) {
376     /* trying to add to the last track failed (no track or no space),
377      * so add a new track to the stack, and add to that...
378      */
379     nlt = BKE_nlatrack_add(adt, NULL);
380     BKE_nlatrack_add_strip(nlt, strip);
381   }
382
383   /* automatically name it too */
384   BKE_nlastrip_validate_name(adt, strip);
385
386   /* returns the strip added */
387   return strip;
388 }
389
390 /* Add a NLA Strip referencing the given speaker's sound */
391 NlaStrip *BKE_nla_add_soundstrip(Scene *scene, Speaker *speaker)
392 {
393   NlaStrip *strip = MEM_callocN(sizeof(NlaStrip), "NlaSoundStrip");
394
395   /* if speaker has a sound, set the strip length to the length of the sound,
396    * otherwise default to length of 10 frames
397    */
398 #ifdef WITH_AUDASPACE
399   if (speaker->sound) {
400     AUD_SoundInfo info = AUD_getInfo(speaker->sound->playback_handle);
401
402     strip->end = (float)ceil((double)info.length * FPS);
403   }
404   else
405 #endif
406   {
407     strip->end = 10.0f;
408     /* quiet compiler warnings */
409     (void)scene;
410     (void)speaker;
411   }
412
413   /* general settings */
414   strip->type = NLASTRIP_TYPE_SOUND;
415
416   strip->flag = NLASTRIP_FLAG_SELECT;
417   strip->extendmode = NLASTRIP_EXTEND_NOTHING; /* nothing to extend... */
418
419   /* strip should be referenced as-is */
420   strip->scale = 1.0f;
421   strip->repeat = 1.0f;
422
423   /* return this strip */
424   return strip;
425 }
426
427 /* *************************************************** */
428 /* NLA Evaluation <-> Editing Stuff */
429
430 /* Strip Mapping ------------------------------------- */
431
432 /* non clipped mapping for strip-time <-> global time (for Action-Clips)
433  * invert = convert action-strip time to global time
434  */
435 static float nlastrip_get_frame_actionclip(NlaStrip *strip, float cframe, short mode)
436 {
437   float actlength, scale;
438   // float repeat; // UNUSED
439
440   /* get number of repeats */
441   if (IS_EQF(strip->repeat, 0.0f)) {
442     strip->repeat = 1.0f;
443   }
444   // repeat = strip->repeat; // UNUSED
445
446   /* scaling */
447   if (IS_EQF(strip->scale, 0.0f)) {
448     strip->scale = 1.0f;
449   }
450   scale = fabsf(
451       strip->scale); /* scale must be positive - we've got a special flag for reversing */
452
453   /* length of referenced action */
454   actlength = strip->actend - strip->actstart;
455   if (IS_EQF(actlength, 0.0f)) {
456     actlength = 1.0f;
457   }
458
459   /* reversed = play strip backwards */
460   if (strip->flag & NLASTRIP_FLAG_REVERSE) {
461     /* FIXME: this won't work right with Graph Editor? */
462     if (mode == NLATIME_CONVERT_MAP) {
463       return strip->end - scale * (cframe - strip->actstart);
464     }
465     else if (mode == NLATIME_CONVERT_UNMAP) {
466       return (strip->end + (strip->actstart * scale - cframe)) / scale;
467     }
468     else { /* if (mode == NLATIME_CONVERT_EVAL) */
469       if (IS_EQF((float)cframe, strip->end) && IS_EQF(strip->repeat, floorf(strip->repeat))) {
470         /* this case prevents the motion snapping back to the first frame at the end of the strip
471          * by catching the case where repeats is a whole number, which means that the end of the strip
472          * could also be interpreted as the end of the start of a repeat
473          */
474         return strip->actstart;
475       }
476       else {
477         /* - the 'fmod(..., actlength * scale)' is needed to get the repeats working
478          * - the '/ scale' is needed to ensure that scaling influences the timing within the repeat
479          */
480         return strip->actend - fmodf(cframe - strip->start, actlength * scale) / scale;
481       }
482     }
483   }
484   else {
485     if (mode == NLATIME_CONVERT_MAP) {
486       return strip->start + scale * (cframe - strip->actstart);
487     }
488     else if (mode == NLATIME_CONVERT_UNMAP) {
489       return strip->actstart + (cframe - strip->start) / scale;
490     }
491     else { /* if (mode == NLATIME_CONVERT_EVAL) */
492       if (IS_EQF(cframe, strip->end) && IS_EQF(strip->repeat, floorf(strip->repeat))) {
493         /* this case prevents the motion snapping back to the first frame at the end of the strip
494          * by catching the case where repeats is a whole number, which means that the end of the strip
495          * could also be interpreted as the end of the start of a repeat
496          */
497         return strip->actend;
498       }
499       else {
500         /* - the 'fmod(..., actlength * scale)' is needed to get the repeats working
501          * - the '/ scale' is needed to ensure that scaling influences the timing within the repeat
502          */
503         return strip->actstart + fmodf(cframe - strip->start, actlength * scale) / scale;
504       }
505     }
506   }
507 }
508
509 /* non clipped mapping for strip-time <-> global time (for Transitions)
510  * invert = convert action-strip time to global time
511  */
512 static float nlastrip_get_frame_transition(NlaStrip *strip, float cframe, short mode)
513 {
514   float length;
515
516   /* length of strip */
517   length = strip->end - strip->start;
518
519   /* reversed = play strip backwards */
520   if (strip->flag & NLASTRIP_FLAG_REVERSE) {
521     if (mode == NLATIME_CONVERT_MAP) {
522       return strip->end - (length * cframe);
523     }
524     else {
525       return (strip->end - cframe) / length;
526     }
527   }
528   else {
529     if (mode == NLATIME_CONVERT_MAP) {
530       return (length * cframe) + strip->start;
531     }
532     else {
533       return (cframe - strip->start) / length;
534     }
535   }
536 }
537
538 /* non clipped mapping for strip-time <-> global time
539  *  mode = eNlaTime_ConvertModes[] -> NLATIME_CONVERT_*
540  *
541  * only secure for 'internal' (i.e. within AnimSys evaluation) operations,
542  * but should not be directly relied on for stuff which interacts with editors
543  */
544 float nlastrip_get_frame(NlaStrip *strip, float cframe, short mode)
545 {
546   switch (strip->type) {
547     case NLASTRIP_TYPE_META: /* meta - for now, does the same as transition (is really just an empty container) */
548     case NLASTRIP_TYPE_TRANSITION: /* transition */
549       return nlastrip_get_frame_transition(strip, cframe, mode);
550
551     case NLASTRIP_TYPE_CLIP: /* action-clip (default) */
552     default:
553       return nlastrip_get_frame_actionclip(strip, cframe, mode);
554   }
555 }
556
557 /* Non clipped mapping for strip-time <-> global time
558  * mode = eNlaTime_ConvertModes -> NLATIME_CONVERT_*
559  *
560  * Public API method - perform this mapping using the given AnimData block
561  * and perform any necessary sanity checks on the value
562  */
563 float BKE_nla_tweakedit_remap(AnimData *adt, float cframe, short mode)
564 {
565   NlaStrip *strip;
566
567   /* sanity checks
568    * - obviously we've got to have some starting data
569    * - when not in tweakmode, the active Action does not have any scaling applied :)
570    * - when in tweakmode, if the no-mapping flag is set, do not map
571    */
572   if ((adt == NULL) || (adt->flag & ADT_NLA_EDIT_ON) == 0 || (adt->flag & ADT_NLA_EDIT_NOMAP)) {
573     return cframe;
574   }
575
576   /* if the active-strip info has been stored already, access this, otherwise look this up
577    * and store for (very probable) future usage
578    */
579   if (adt->act_track == NULL) {
580     if (adt->actstrip) {
581       adt->act_track = BKE_nlatrack_find_tweaked(adt);
582     }
583     else {
584       adt->act_track = BKE_nlatrack_find_active(&adt->nla_tracks);
585     }
586   }
587   if (adt->actstrip == NULL) {
588     adt->actstrip = BKE_nlastrip_find_active(adt->act_track);
589   }
590   strip = adt->actstrip;
591
592   /* sanity checks
593    * - in rare cases, we may not be able to find this strip for some reason (internal error)
594    * - for now, if the user has defined a curve to control the time, this correction cannot be performed
595    *   reliably...
596    */
597   if ((strip == NULL) || (strip->flag & NLASTRIP_FLAG_USR_TIME)) {
598     return cframe;
599   }
600
601   /* perform the correction now... */
602   return nlastrip_get_frame(strip, cframe, mode);
603 }
604
605 /* *************************************************** */
606 /* NLA API */
607
608 /* List of Strips ------------------------------------ */
609 /* (these functions are used for NLA-Tracks and also for nested/meta-strips) */
610
611 /* Check if there is any space in the given list to add the given strip */
612 bool BKE_nlastrips_has_space(ListBase *strips, float start, float end)
613 {
614   NlaStrip *strip;
615
616   /* sanity checks */
617   if ((strips == NULL) || IS_EQF(start, end)) {
618     return false;
619   }
620   if (start > end) {
621     puts("BKE_nlastrips_has_space() error... start and end arguments swapped");
622     SWAP(float, start, end);
623   }
624
625   /* loop over NLA strips checking for any overlaps with this area... */
626   for (strip = strips->first; strip; strip = strip->next) {
627     /* if start frame of strip is past the target end-frame, that means that
628      * we've gone past the window we need to check for, so things are fine
629      */
630     if (strip->start >= end) {
631       return true;
632     }
633
634     /* if the end of the strip is greater than either of the boundaries, the range
635      * must fall within the extents of the strip
636      */
637     if ((strip->end > start) || (strip->end > end)) {
638       return false;
639     }
640   }
641
642   /* if we are still here, we haven't encountered any overlapping strips */
643   return true;
644 }
645
646 /* Rearrange the strips in the track so that they are always in order
647  * (usually only needed after a strip has been moved)
648  */
649 void BKE_nlastrips_sort_strips(ListBase *strips)
650 {
651   ListBase tmp = {NULL, NULL};
652   NlaStrip *strip, *sstrip, *stripn;
653
654   /* sanity checks */
655   if (ELEM(NULL, strips, strips->first)) {
656     return;
657   }
658
659   /* we simply perform insertion sort on this list, since it is assumed that per track,
660    * there are only likely to be at most 5-10 strips
661    */
662   for (strip = strips->first; strip; strip = stripn) {
663     short not_added = 1;
664
665     stripn = strip->next;
666
667     /* remove this strip from the list, and add it to the new list, searching from the end of
668      * the list, assuming that the lists are in order
669      */
670     BLI_remlink(strips, strip);
671
672     for (sstrip = tmp.last; sstrip; sstrip = sstrip->prev) {
673       /* check if add after */
674       if (sstrip->end <= strip->start) {
675         BLI_insertlinkafter(&tmp, sstrip, strip);
676         not_added = 0;
677         break;
678       }
679     }
680
681     /* add before first? */
682     if (not_added) {
683       BLI_addhead(&tmp, strip);
684     }
685   }
686
687   /* reassign the start and end points of the strips */
688   strips->first = tmp.first;
689   strips->last = tmp.last;
690 }
691
692 /* Add the given NLA-Strip to the given list of strips, assuming that it
693  * isn't currently a member of another list
694  */
695 bool BKE_nlastrips_add_strip(ListBase *strips, NlaStrip *strip)
696 {
697   NlaStrip *ns;
698   bool not_added = true;
699
700   /* sanity checks */
701   if (ELEM(NULL, strips, strip)) {
702     return false;
703   }
704
705   /* check if any space to add */
706   if (BKE_nlastrips_has_space(strips, strip->start, strip->end) == 0) {
707     return false;
708   }
709
710   /* find the right place to add the strip to the nominated track */
711   for (ns = strips->first; ns; ns = ns->next) {
712     /* if current strip occurs after the new strip, add it before */
713     if (ns->start >= strip->end) {
714       BLI_insertlinkbefore(strips, ns, strip);
715       not_added = 0;
716       break;
717     }
718   }
719   if (not_added) {
720     /* just add to the end of the list of the strips then... */
721     BLI_addtail(strips, strip);
722   }
723
724   /* added... */
725   return true;
726 }
727
728 /* Meta-Strips ------------------------------------ */
729
730 /* Convert 'islands' (i.e. continuous string of) selected strips to be
731  * contained within 'Meta-Strips' which act as strips which contain strips.
732  * temp: are the meta-strips to be created 'temporary' ones used for transforms?
733  */
734 void BKE_nlastrips_make_metas(ListBase *strips, bool is_temp)
735 {
736   NlaStrip *mstrip = NULL;
737   NlaStrip *strip, *stripn;
738
739   /* sanity checks */
740   if (ELEM(NULL, strips, strips->first)) {
741     return;
742   }
743
744   /* group all continuous chains of selected strips into meta-strips */
745   for (strip = strips->first; strip; strip = stripn) {
746     stripn = strip->next;
747
748     if (strip->flag & NLASTRIP_FLAG_SELECT) {
749       /* if there is an existing meta-strip, add this strip to it, otherwise, create a new one */
750       if (mstrip == NULL) {
751         /* add a new meta-strip, and add it before the current strip that it will replace... */
752         mstrip = MEM_callocN(sizeof(NlaStrip), "Meta-NlaStrip");
753         mstrip->type = NLASTRIP_TYPE_META;
754         BLI_insertlinkbefore(strips, strip, mstrip);
755
756         /* set flags */
757         mstrip->flag = NLASTRIP_FLAG_SELECT;
758
759         /* set temp flag if appropriate (i.e. for transform-type editing) */
760         if (is_temp) {
761           mstrip->flag |= NLASTRIP_FLAG_TEMP_META;
762         }
763
764         /* set default repeat/scale values to prevent warnings */
765         mstrip->repeat = mstrip->scale = 1.0f;
766
767         /* make its start frame be set to the start frame of the current strip */
768         mstrip->start = strip->start;
769       }
770
771       /* remove the selected strips from the track, and add to the meta */
772       BLI_remlink(strips, strip);
773       BLI_addtail(&mstrip->strips, strip);
774
775       /* expand the meta's dimensions to include the newly added strip- i.e. its last frame */
776       mstrip->end = strip->end;
777     }
778     else {
779       /* current strip wasn't selected, so the end of 'island' of selected strips has been reached,
780        * so stop adding strips to the current meta
781        */
782       mstrip = NULL;
783     }
784   }
785 }
786
787 /* Split a meta-strip into a set of normal strips */
788 void BKE_nlastrips_clear_metastrip(ListBase *strips, NlaStrip *strip)
789 {
790   NlaStrip *cs, *csn;
791
792   /* sanity check */
793   if (ELEM(NULL, strips, strip)) {
794     return;
795   }
796
797   /* move each one of the meta-strip's children before the meta-strip
798    * in the list of strips after unlinking them from the meta-strip
799    */
800   for (cs = strip->strips.first; cs; cs = csn) {
801     csn = cs->next;
802     BLI_remlink(&strip->strips, cs);
803     BLI_insertlinkbefore(strips, strip, cs);
804   }
805
806   /* free the meta-strip now */
807   BKE_nlastrip_free(strips, strip, true);
808 }
809
810 /* Remove meta-strips (i.e. flatten the list of strips) from the top-level of the list of strips
811  * sel: only consider selected meta-strips, otherwise all meta-strips are removed
812  * onlyTemp: only remove the 'temporary' meta-strips used for transforms
813  */
814 void BKE_nlastrips_clear_metas(ListBase *strips, bool only_sel, bool only_temp)
815 {
816   NlaStrip *strip, *stripn;
817
818   /* sanity checks */
819   if (ELEM(NULL, strips, strips->first)) {
820     return;
821   }
822
823   /* remove meta-strips fitting the criteria of the arguments */
824   for (strip = strips->first; strip; strip = stripn) {
825     stripn = strip->next;
826
827     /* check if strip is a meta-strip */
828     if (strip->type == NLASTRIP_TYPE_META) {
829       /* if check if selection and 'temporary-only' considerations are met */
830       if ((!only_sel) || (strip->flag & NLASTRIP_FLAG_SELECT)) {
831         if ((!only_temp) || (strip->flag & NLASTRIP_FLAG_TEMP_META)) {
832           BKE_nlastrips_clear_metastrip(strips, strip);
833         }
834       }
835     }
836   }
837 }
838
839 /* Add the given NLA-Strip to the given Meta-Strip, assuming that the
840  * strip isn't attached to any list of strips
841  */
842 bool BKE_nlameta_add_strip(NlaStrip *mstrip, NlaStrip *strip)
843 {
844   /* sanity checks */
845   if (ELEM(NULL, mstrip, strip)) {
846     return false;
847   }
848
849   /* firstly, check if the meta-strip has space for this */
850   if (BKE_nlastrips_has_space(&mstrip->strips, strip->start, strip->end) == 0) {
851     return false;
852   }
853
854   /* check if this would need to be added to the ends of the meta,
855    * and subsequently, if the neighboring strips allow us enough room
856    */
857   if (strip->start < mstrip->start) {
858     /* check if strip to the left (if it exists) ends before the
859      * start of the strip we're trying to add
860      */
861     if ((mstrip->prev == NULL) || (mstrip->prev->end <= strip->start)) {
862       /* add strip to start of meta's list, and expand dimensions */
863       BLI_addhead(&mstrip->strips, strip);
864       mstrip->start = strip->start;
865
866       return true;
867     }
868     else { /* failed... no room before */
869       return false;
870     }
871   }
872   else if (strip->end > mstrip->end) {
873     /* check if strip to the right (if it exists) starts before the
874      * end of the strip we're trying to add
875      */
876     if ((mstrip->next == NULL) || (mstrip->next->start >= strip->end)) {
877       /* add strip to end of meta's list, and expand dimensions */
878       BLI_addtail(&mstrip->strips, strip);
879       mstrip->end = strip->end;
880
881       return true;
882     }
883     else { /* failed... no room after */
884       return false;
885     }
886   }
887   else {
888     /* just try to add to the meta-strip (no dimension changes needed) */
889     return BKE_nlastrips_add_strip(&mstrip->strips, strip);
890   }
891 }
892
893 /* Adjust the settings of NLA-Strips contained within a Meta-Strip (recursively),
894  * until the Meta-Strips children all fit within the Meta-Strip's new dimensions
895  */
896 void BKE_nlameta_flush_transforms(NlaStrip *mstrip)
897 {
898   NlaStrip *strip;
899   float oStart, oEnd, offset;
900   float oLen, nLen;
901   short scaleChanged = 0;
902
903   /* sanity checks
904    * - strip must exist
905    * - strip must be a meta-strip with some contents
906    */
907   if (ELEM(NULL, mstrip, mstrip->strips.first)) {
908     return;
909   }
910   if (mstrip->type != NLASTRIP_TYPE_META) {
911     return;
912   }
913
914   /* get the original start/end points, and calculate the start-frame offset
915    * - these are simply the start/end frames of the child strips,
916    *   since we assume they weren't transformed yet
917    */
918   oStart = ((NlaStrip *)mstrip->strips.first)->start;
919   oEnd = ((NlaStrip *)mstrip->strips.last)->end;
920   offset = mstrip->start - oStart;
921
922   /* optimization:
923    * don't flush if nothing changed yet
924    * TODO: maybe we need a flag to say always flush?
925    */
926   if (IS_EQF(oStart, mstrip->start) && IS_EQF(oEnd, mstrip->end)) {
927     return;
928   }
929
930   /* check if scale changed */
931   oLen = oEnd - oStart;
932   nLen = mstrip->end - mstrip->start;
933   if (IS_EQF(nLen, oLen) == 0) {
934     scaleChanged = 1;
935   }
936
937   /* for each child-strip, calculate new start/end points based on this new info */
938   for (strip = mstrip->strips.first; strip; strip = strip->next) {
939     if (scaleChanged) {
940       float p1, p2;
941
942       /* compute positions of endpoints relative to old extents of strip */
943       p1 = (strip->start - oStart) / oLen;
944       p2 = (strip->end - oStart) / oLen;
945
946       /* apply new strip endpoints using the proportions, then wait for second pass to flush scale properly */
947       strip->start = (p1 * nLen) + mstrip->start;
948       strip->end = (p2 * nLen) + mstrip->start;
949     }
950     else {
951       /* just apply the changes in offset to both ends of the strip */
952       strip->start += offset;
953       strip->end += offset;
954     }
955   }
956
957   /* apply a second pass over child strips, to finish up unfinished business */
958   for (strip = mstrip->strips.first; strip; strip = strip->next) {
959     /* only if scale changed, need to perform RNA updates */
960     if (scaleChanged) {
961       PointerRNA ptr;
962
963       /* use RNA updates to compute scale properly */
964       RNA_pointer_create(NULL, &RNA_NlaStrip, strip, &ptr);
965
966       RNA_float_set(&ptr, "frame_start", strip->start);
967       RNA_float_set(&ptr, "frame_end", strip->end);
968     }
969
970     /* finally, make sure the strip's children (if it is a meta-itself), get updated */
971     BKE_nlameta_flush_transforms(strip);
972   }
973 }
974
975 /* NLA-Tracks ---------------------------------------- */
976
977 /* Find the active NLA-track for the given stack */
978 NlaTrack *BKE_nlatrack_find_active(ListBase *tracks)
979 {
980   NlaTrack *nlt;
981
982   /* sanity check */
983   if (ELEM(NULL, tracks, tracks->first)) {
984     return NULL;
985   }
986
987   /* try to find the first active track */
988   for (nlt = tracks->first; nlt; nlt = nlt->next) {
989     if (nlt->flag & NLATRACK_ACTIVE) {
990       return nlt;
991     }
992   }
993
994   /* none found */
995   return NULL;
996 }
997
998 /* Get the NLA Track that the active action/action strip comes from,
999  * since this info is not stored in AnimData. It also isn't as simple
1000  * as just using the active track, since multiple tracks may have been
1001  * entered at the same time.
1002  */
1003 NlaTrack *BKE_nlatrack_find_tweaked(AnimData *adt)
1004 {
1005   NlaTrack *nlt;
1006
1007   /* sanity check */
1008   if (adt == NULL) {
1009     return NULL;
1010   }
1011
1012   /* Since the track itself gets disabled, we want the first disabled... */
1013   for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) {
1014     if (nlt->flag & (NLATRACK_ACTIVE | NLATRACK_DISABLED)) {
1015       /* For good measure, make sure that strip actually exists there */
1016       if (BLI_findindex(&nlt->strips, adt->actstrip) != -1) {
1017         return nlt;
1018       }
1019       else if (G.debug & G_DEBUG) {
1020         printf("%s: Active strip (%p, %s) not in NLA track found (%p, %s)\n",
1021                __func__,
1022                adt->actstrip,
1023                (adt->actstrip) ? adt->actstrip->name : "<None>",
1024                nlt,
1025                nlt->name);
1026       }
1027     }
1028   }
1029
1030   /* Not found! */
1031   return NULL;
1032 }
1033
1034 /* Toggle the 'solo' setting for the given NLA-track, making sure that it is the only one
1035  * that has this status in its AnimData block.
1036  */
1037 void BKE_nlatrack_solo_toggle(AnimData *adt, NlaTrack *nlt)
1038 {
1039   NlaTrack *nt;
1040
1041   /* sanity check */
1042   if (ELEM(NULL, adt, adt->nla_tracks.first)) {
1043     return;
1044   }
1045
1046   /* firstly, make sure 'solo' flag for all tracks is disabled */
1047   for (nt = adt->nla_tracks.first; nt; nt = nt->next) {
1048     if (nt != nlt) {
1049       nt->flag &= ~NLATRACK_SOLO;
1050     }
1051   }
1052
1053   /* now, enable 'solo' for the given track if appropriate */
1054   if (nlt) {
1055     /* toggle solo status */
1056     nlt->flag ^= NLATRACK_SOLO;
1057
1058     /* set or clear solo-status on AnimData */
1059     if (nlt->flag & NLATRACK_SOLO) {
1060       adt->flag |= ADT_NLA_SOLO_TRACK;
1061     }
1062     else {
1063       adt->flag &= ~ADT_NLA_SOLO_TRACK;
1064     }
1065   }
1066   else {
1067     adt->flag &= ~ADT_NLA_SOLO_TRACK;
1068   }
1069 }
1070
1071 /* Make the given NLA-track the active one for the given stack. If no track is provided,
1072  * this function can be used to simply deactivate all the NLA tracks in the given stack too.
1073  */
1074 void BKE_nlatrack_set_active(ListBase *tracks, NlaTrack *nlt_a)
1075 {
1076   NlaTrack *nlt;
1077
1078   /* sanity check */
1079   if (ELEM(NULL, tracks, tracks->first)) {
1080     return;
1081   }
1082
1083   /* deactivate all the rest */
1084   for (nlt = tracks->first; nlt; nlt = nlt->next) {
1085     nlt->flag &= ~NLATRACK_ACTIVE;
1086   }
1087
1088   /* set the given one as the active one */
1089   if (nlt_a) {
1090     nlt_a->flag |= NLATRACK_ACTIVE;
1091   }
1092 }
1093
1094 /* Check if there is any space in the given track to add a strip of the given length */
1095 bool BKE_nlatrack_has_space(NlaTrack *nlt, float start, float end)
1096 {
1097   /* sanity checks
1098    * - track must exist
1099    * - track must be editable
1100    * - bounds cannot be equal (0-length is nasty)
1101    */
1102   if ((nlt == NULL) || (nlt->flag & NLATRACK_PROTECTED) || IS_EQF(start, end)) {
1103     return false;
1104   }
1105
1106   if (start > end) {
1107     puts("BKE_nlatrack_has_space() error... start and end arguments swapped");
1108     SWAP(float, start, end);
1109   }
1110
1111   /* check if there's any space left in the track for a strip of the given length */
1112   return BKE_nlastrips_has_space(&nlt->strips, start, end);
1113 }
1114
1115 /* Rearrange the strips in the track so that they are always in order
1116  * (usually only needed after a strip has been moved)
1117  */
1118 void BKE_nlatrack_sort_strips(NlaTrack *nlt)
1119 {
1120   /* sanity checks */
1121   if (ELEM(NULL, nlt, nlt->strips.first)) {
1122     return;
1123   }
1124
1125   /* sort the strips with a more generic function */
1126   BKE_nlastrips_sort_strips(&nlt->strips);
1127 }
1128
1129 /* Add the given NLA-Strip to the given NLA-Track, assuming that it
1130  * isn't currently attached to another one
1131  */
1132 bool BKE_nlatrack_add_strip(NlaTrack *nlt, NlaStrip *strip)
1133 {
1134   /* sanity checks */
1135   if (ELEM(NULL, nlt, strip)) {
1136     return false;
1137   }
1138
1139   /* do not allow adding strips if this track is locked */
1140   if (nlt->flag & NLATRACK_PROTECTED) {
1141     return false;
1142   }
1143
1144   /* try to add the strip to the track using a more generic function */
1145   return BKE_nlastrips_add_strip(&nlt->strips, strip);
1146 }
1147
1148 /* Get the extents of the given NLA-Track including gaps between strips,
1149  * returning whether this succeeded or not
1150  */
1151 bool BKE_nlatrack_get_bounds(NlaTrack *nlt, float bounds[2])
1152 {
1153   NlaStrip *strip;
1154
1155   /* initialize bounds */
1156   if (bounds) {
1157     bounds[0] = bounds[1] = 0.0f;
1158   }
1159   else {
1160     return false;
1161   }
1162
1163   /* sanity checks */
1164   if (ELEM(NULL, nlt, nlt->strips.first)) {
1165     return false;
1166   }
1167
1168   /* lower bound is first strip's start frame */
1169   strip = nlt->strips.first;
1170   bounds[0] = strip->start;
1171
1172   /* upper bound is last strip's end frame */
1173   strip = nlt->strips.last;
1174   bounds[1] = strip->end;
1175
1176   /* done */
1177   return true;
1178 }
1179
1180 /* NLA Strips -------------------------------------- */
1181
1182 /* Find the active NLA-strip within the given track */
1183 NlaStrip *BKE_nlastrip_find_active(NlaTrack *nlt)
1184 {
1185   NlaStrip *strip;
1186
1187   /* sanity check */
1188   if (ELEM(NULL, nlt, nlt->strips.first)) {
1189     return NULL;
1190   }
1191
1192   /* try to find the first active strip */
1193   for (strip = nlt->strips.first; strip; strip = strip->next) {
1194     if (strip->flag & NLASTRIP_FLAG_ACTIVE) {
1195       return strip;
1196     }
1197   }
1198
1199   /* none found */
1200   return NULL;
1201 }
1202
1203 /* Make the given NLA-Strip the active one within the given block */
1204 void BKE_nlastrip_set_active(AnimData *adt, NlaStrip *strip)
1205 {
1206   NlaTrack *nlt;
1207   NlaStrip *nls;
1208
1209   /* sanity checks */
1210   if (adt == NULL) {
1211     return;
1212   }
1213
1214   /* loop over tracks, deactivating*/
1215   for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) {
1216     for (nls = nlt->strips.first; nls; nls = nls->next) {
1217       if (nls != strip) {
1218         nls->flag &= ~NLASTRIP_FLAG_ACTIVE;
1219       }
1220       else {
1221         nls->flag |= NLASTRIP_FLAG_ACTIVE;
1222       }
1223     }
1224   }
1225 }
1226
1227 /* Does the given NLA-strip fall within the given bounds (times)? */
1228 bool BKE_nlastrip_within_bounds(NlaStrip *strip, float min, float max)
1229 {
1230   const float stripLen = (strip) ? strip->end - strip->start : 0.0f;
1231   const float boundsLen = fabsf(max - min);
1232
1233   /* sanity checks */
1234   if ((strip == NULL) || IS_EQF(stripLen, 0.0f) || IS_EQF(boundsLen, 0.0f)) {
1235     return false;
1236   }
1237
1238   /* only ok if at least part of the strip is within the bounding window
1239    * - first 2 cases cover when the strip length is less than the bounding area
1240    * - second 2 cases cover when the strip length is greater than the bounding area
1241    */
1242   if ((stripLen < boundsLen) &&
1243       !(IN_RANGE(strip->start, min, max) || IN_RANGE(strip->end, min, max))) {
1244     return false;
1245   }
1246   if ((stripLen > boundsLen) &&
1247       !(IN_RANGE(min, strip->start, strip->end) || IN_RANGE(max, strip->start, strip->end))) {
1248     return false;
1249   }
1250
1251   /* should be ok! */
1252   return true;
1253 }
1254
1255 /* Ensure that strip doesn't overlap those around it after resizing by offsetting those which follow */
1256 static void nlastrip_fix_resize_overlaps(NlaStrip *strip)
1257 {
1258   /* next strips - do this first, since we're often just getting longer */
1259   if (strip->next) {
1260     NlaStrip *nls = strip->next;
1261     float offset = 0.0f;
1262
1263     if (nls->type == NLASTRIP_TYPE_TRANSITION) {
1264       /* transition strips should grow/shrink to accommodate the resized strip,
1265        * but if the strip's bounds now exceed the transition, we're forced to
1266        * offset everything to maintain the balance
1267        */
1268       if (strip->end <= nls->start) {
1269         /* grow the transition to fill the void */
1270         nls->start = strip->end;
1271       }
1272       else if (strip->end < nls->end) {
1273         /* shrink the transition to give the strip room */
1274         nls->start = strip->end;
1275       }
1276       else {
1277         /* shrink transition down to 1 frame long (so that it can still be found),
1278          * then offset everything else by the remaining defict to give the strip room
1279          */
1280         nls->start = nls->end - 1.0f;
1281         offset = ceilf(
1282             strip->end -
1283             nls->start); /* XXX: review whether preventing fractionals is good here... */
1284
1285         /* apply necessary offset to ensure that the strip has enough space */
1286         for (; nls; nls = nls->next) {
1287           nls->start += offset;
1288           nls->end += offset;
1289         }
1290       }
1291     }
1292     else if (strip->end > nls->start) {
1293       /* NOTE: need to ensure we don't have a fractional frame offset, even if that leaves a gap,
1294        * otherwise it will be very hard to get rid of later
1295        */
1296       offset = ceilf(strip->end - nls->start);
1297
1298       /* apply to times of all strips in this direction */
1299       for (; nls; nls = nls->next) {
1300         nls->start += offset;
1301         nls->end += offset;
1302       }
1303     }
1304   }
1305
1306   /* previous strips - same routine as before */
1307   /* NOTE: when strip bounds are recalculated, this is not considered! */
1308   if (strip->prev) {
1309     NlaStrip *nls = strip->prev;
1310     float offset = 0.0f;
1311
1312     if (nls->type == NLASTRIP_TYPE_TRANSITION) {
1313       /* transition strips should grow/shrink to accommodate the resized strip,
1314        * but if the strip's bounds now exceed the transition, we're forced to
1315        * offset everything to maintain the balance
1316        */
1317       if (strip->start >= nls->end) {
1318         /* grow the transition to fill the void */
1319         nls->end = strip->start;
1320       }
1321       else if (strip->start > nls->start) {
1322         /* shrink the transition to give the strip room */
1323         nls->end = strip->start;
1324       }
1325       else {
1326         /* shrink transition down to 1 frame long (so that it can still be found),
1327          * then offset everything else by the remaining defict to give the strip room
1328          */
1329         nls->end = nls->start + 1.0f;
1330         offset = ceilf(
1331             nls->end -
1332             strip->start); /* XXX: review whether preventing fractionals is good here... */
1333
1334         /* apply necessary offset to ensure that the strip has enough space */
1335         for (; nls; nls = nls->next) {
1336           nls->start -= offset;
1337           nls->end -= offset;
1338         }
1339       }
1340     }
1341     else if (strip->start < nls->end) {
1342       /* NOTE: need to ensure we don't have a fractional frame offset, even if that leaves a gap,
1343        * otherwise it will be very hard to get rid of later
1344        */
1345       offset = ceilf(nls->end - strip->start);
1346
1347       /* apply to times of all strips in this direction */
1348       for (; nls; nls = nls->prev) {
1349         nls->start -= offset;
1350         nls->end -= offset;
1351       }
1352     }
1353   }
1354 }
1355
1356 /* Recalculate the start and end frames for the current strip, after changing
1357  * the extents of the action or the mapping (repeats or scale factor) info
1358  */
1359 void BKE_nlastrip_recalculate_bounds(NlaStrip *strip)
1360 {
1361   float actlen, mapping;
1362
1363   /* sanity checks
1364    * - must have a strip
1365    * - can only be done for action clips
1366    */
1367   if ((strip == NULL) || (strip->type != NLASTRIP_TYPE_CLIP)) {
1368     return;
1369   }
1370
1371   /* calculate new length factors */
1372   actlen = strip->actend - strip->actstart;
1373   if (IS_EQF(actlen, 0.0f)) {
1374     actlen = 1.0f;
1375   }
1376
1377   mapping = strip->scale * strip->repeat;
1378
1379   /* adjust endpoint of strip in response to this */
1380   if (IS_EQF(mapping, 0.0f) == 0) {
1381     strip->end = (actlen * mapping) + strip->start;
1382   }
1383
1384   /* make sure we don't overlap our neighbors */
1385   nlastrip_fix_resize_overlaps(strip);
1386 }
1387
1388 /* Is the given NLA-strip the first one to occur for the given AnimData block */
1389 // TODO: make this an api method if necessary, but need to add prefix first
1390 static bool nlastrip_is_first(AnimData *adt, NlaStrip *strip)
1391 {
1392   NlaTrack *nlt;
1393   NlaStrip *ns;
1394
1395   /* sanity checks */
1396   if (ELEM(NULL, adt, strip)) {
1397     return false;
1398   }
1399
1400   /* check if strip has any strips before it */
1401   if (strip->prev) {
1402     return false;
1403   }
1404
1405   /* check other tracks to see if they have a strip that's earlier */
1406   /* TODO: or should we check that the strip's track is also the first? */
1407   for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) {
1408     /* only check the first strip, assuming that they're all in order */
1409     ns = nlt->strips.first;
1410     if (ns) {
1411       if (ns->start < strip->start) {
1412         return false;
1413       }
1414     }
1415   }
1416
1417   /* should be first now */
1418   return true;
1419 }
1420
1421 /* Animated Strips ------------------------------------------- */
1422
1423 /* Check if the given NLA-Track has any strips with own F-Curves */
1424 bool BKE_nlatrack_has_animated_strips(NlaTrack *nlt)
1425 {
1426   NlaStrip *strip;
1427
1428   /* sanity checks */
1429   if (ELEM(NULL, nlt, nlt->strips.first)) {
1430     return false;
1431   }
1432
1433   /* check each strip for F-Curves only (don't care about whether the flags are set) */
1434   for (strip = nlt->strips.first; strip; strip = strip->next) {
1435     if (strip->fcurves.first) {
1436       return true;
1437     }
1438   }
1439
1440   /* none found */
1441   return false;
1442 }
1443
1444 /* Check if given NLA-Tracks have any strips with own F-Curves */
1445 bool BKE_nlatracks_have_animated_strips(ListBase *tracks)
1446 {
1447   NlaTrack *nlt;
1448
1449   /* sanity checks */
1450   if (ELEM(NULL, tracks, tracks->first)) {
1451     return false;
1452   }
1453
1454   /* check each track, stopping on the first hit */
1455   for (nlt = tracks->first; nlt; nlt = nlt->next) {
1456     if (BKE_nlatrack_has_animated_strips(nlt)) {
1457       return true;
1458     }
1459   }
1460
1461   /* none found */
1462   return false;
1463 }
1464
1465 /* Validate the NLA-Strips 'control' F-Curves based on the flags set*/
1466 void BKE_nlastrip_validate_fcurves(NlaStrip *strip)
1467 {
1468   FCurve *fcu;
1469
1470   /* sanity checks */
1471   if (strip == NULL) {
1472     return;
1473   }
1474
1475   /* if controlling influence... */
1476   if (strip->flag & NLASTRIP_FLAG_USR_INFLUENCE) {
1477     /* try to get F-Curve */
1478     fcu = list_find_fcurve(&strip->fcurves, "influence", 0);
1479
1480     /* add one if not found */
1481     if (fcu == NULL) {
1482       /* make new F-Curve */
1483       fcu = MEM_callocN(sizeof(FCurve), "NlaStrip FCurve");
1484       BLI_addtail(&strip->fcurves, fcu);
1485
1486       /* set default flags */
1487       fcu->flag = (FCURVE_VISIBLE | FCURVE_SELECTED);
1488       fcu->auto_smoothing = FCURVE_SMOOTH_CONT_ACCEL;
1489
1490       /* store path - make copy, and store that */
1491       fcu->rna_path = BLI_strdupn("influence", 9);
1492
1493       /* insert keyframe to ensure current value stays on first refresh */
1494       fcu->bezt = MEM_callocN(sizeof(BezTriple), "nlastrip influence bezt");
1495       fcu->totvert = 1;
1496
1497       fcu->bezt->vec[1][0] = strip->start;
1498       fcu->bezt->vec[1][1] = strip->influence;
1499     }
1500   }
1501
1502   /* if controlling time... */
1503   if (strip->flag & NLASTRIP_FLAG_USR_TIME) {
1504     /* try to get F-Curve */
1505     fcu = list_find_fcurve(&strip->fcurves, "strip_time", 0);
1506
1507     /* add one if not found */
1508     if (fcu == NULL) {
1509       /* make new F-Curve */
1510       fcu = MEM_callocN(sizeof(FCurve), "NlaStrip FCurve");
1511       BLI_addtail(&strip->fcurves, fcu);
1512
1513       /* set default flags */
1514       fcu->flag = (FCURVE_VISIBLE | FCURVE_SELECTED);
1515       fcu->auto_smoothing = FCURVE_SMOOTH_CONT_ACCEL;
1516
1517       /* store path - make copy, and store that */
1518       fcu->rna_path = BLI_strdupn("strip_time", 10);
1519
1520       /* TODO: insert a few keyframes to ensure default behavior? */
1521     }
1522   }
1523 }
1524
1525 /* Check if the given RNA pointer + property combo should be handled by
1526  * NLA strip curves or not.
1527  */
1528 bool BKE_nlastrip_has_curves_for_property(const PointerRNA *ptr, const PropertyRNA *prop)
1529 {
1530   /* sanity checks */
1531   if (ELEM(NULL, ptr, prop)) {
1532     return false;
1533   }
1534
1535   /* 1) Must be NLA strip */
1536   if (ptr->type == &RNA_NlaStrip) {
1537     /* 2) Must be one of the predefined properties */
1538     static PropertyRNA *prop_influence = NULL;
1539     static PropertyRNA *prop_time = NULL;
1540     static bool needs_init = true;
1541
1542     /* Init the properties on first use */
1543     if (needs_init) {
1544       prop_influence = RNA_struct_type_find_property(&RNA_NlaStrip, "influence");
1545       prop_time = RNA_struct_type_find_property(&RNA_NlaStrip, "strip_time");
1546
1547       needs_init = false;
1548     }
1549
1550     /* Check if match */
1551     if (ELEM(prop, prop_influence, prop_time)) {
1552       return true;
1553     }
1554   }
1555
1556   /* No criteria met */
1557   return false;
1558 }
1559
1560 /* Sanity Validation ------------------------------------ */
1561
1562 static bool nla_editbone_name_check(void *arg, const char *name)
1563 {
1564   return BLI_ghash_haskey((GHash *)arg, (const void *)name);
1565 }
1566
1567 /* Find (and set) a unique name for a strip from the whole AnimData block
1568  * Uses a similar method to the BLI method, but is implemented differently
1569  * as we need to ensure that the name is unique over several lists of tracks,
1570  * not just a single track.
1571  */
1572 void BKE_nlastrip_validate_name(AnimData *adt, NlaStrip *strip)
1573 {
1574   GHash *gh;
1575   NlaStrip *tstrip;
1576   NlaTrack *nlt;
1577
1578   /* sanity checks */
1579   if (ELEM(NULL, adt, strip)) {
1580     return;
1581   }
1582
1583   /* give strip a default name if none already */
1584   if (strip->name[0] == 0) {
1585     switch (strip->type) {
1586       case NLASTRIP_TYPE_CLIP: /* act-clip */
1587         BLI_strncpy(strip->name,
1588                     (strip->act) ? (strip->act->id.name + 2) : ("<No Action>"),
1589                     sizeof(strip->name));
1590         break;
1591       case NLASTRIP_TYPE_TRANSITION: /* transition */
1592         BLI_strncpy(strip->name, "Transition", sizeof(strip->name));
1593         break;
1594       case NLASTRIP_TYPE_META: /* meta */
1595         BLI_strncpy(strip->name, "Meta", sizeof(strip->name));
1596         break;
1597       default:
1598         BLI_strncpy(strip->name, "NLA Strip", sizeof(strip->name));
1599         break;
1600     }
1601   }
1602
1603   /* build a hash-table of all the strips in the tracks
1604    * - this is easier than iterating over all the tracks+strips hierarchy every time
1605    *   (and probably faster)
1606    */
1607   gh = BLI_ghash_str_new("nlastrip_validate_name gh");
1608
1609   for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) {
1610     for (tstrip = nlt->strips.first; tstrip; tstrip = tstrip->next) {
1611       /* don't add the strip of interest */
1612       if (tstrip == strip) {
1613         continue;
1614       }
1615
1616       /* use the name of the strip as the key, and the strip as the value, since we're mostly interested in the keys */
1617       BLI_ghash_insert(gh, tstrip->name, tstrip);
1618     }
1619   }
1620
1621   /* if the hash-table has a match for this name, try other names...
1622    * - in an extreme case, it might not be able to find a name, but then everything else in Blender would fail too :)
1623    */
1624   BLI_uniquename_cb(nla_editbone_name_check,
1625                     (void *)gh,
1626                     DATA_("NlaStrip"),
1627                     '.',
1628                     strip->name,
1629                     sizeof(strip->name));
1630
1631   /* free the hash... */
1632   BLI_ghash_free(gh, NULL, NULL);
1633 }
1634
1635 /* ---- */
1636
1637 /* Get strips which overlap the given one at the start/end of its range
1638  * - strip: strip that we're finding overlaps for
1639  * - track: nla-track that the overlapping strips should be found from
1640  * - start, end: frames for the offending endpoints
1641  */
1642 static void nlastrip_get_endpoint_overlaps(NlaStrip *strip,
1643                                            NlaTrack *track,
1644                                            float **start,
1645                                            float **end)
1646 {
1647   NlaStrip *nls;
1648
1649   /* find strips that overlap over the start/end of the given strip,
1650    * but which don't cover the entire length
1651    */
1652   /* TODO: this scheme could get quite slow for doing this on many strips... */
1653   for (nls = track->strips.first; nls; nls = nls->next) {
1654     /* check if strip overlaps (extends over or exactly on) the entire range of the strip we're validating */
1655     if ((nls->start <= strip->start) && (nls->end >= strip->end)) {
1656       *start = NULL;
1657       *end = NULL;
1658       return;
1659     }
1660
1661     /* check if strip doesn't even occur anywhere near... */
1662     if (nls->end < strip->start) {
1663       continue; /* skip checking this strip... not worthy of mention */
1664     }
1665     if (nls->start > strip->end) {
1666       return; /* the range we're after has already passed */
1667     }
1668
1669     /* if this strip is not part of an island of continuous strips, it can be used
1670      * - this check needs to be done for each end of the strip we try and use...
1671      */
1672     if ((nls->next == NULL) || IS_EQF(nls->next->start, nls->end) == 0) {
1673       if ((nls->end > strip->start) && (nls->end < strip->end)) {
1674         *start = &nls->end;
1675       }
1676     }
1677     if ((nls->prev == NULL) || IS_EQF(nls->prev->end, nls->start) == 0) {
1678       if ((nls->start < strip->end) && (nls->start > strip->start)) {
1679         *end = &nls->start;
1680       }
1681     }
1682   }
1683 }
1684
1685 /* Determine auto-blending for the given strip */
1686 static void BKE_nlastrip_validate_autoblends(NlaTrack *nlt, NlaStrip *nls)
1687 {
1688   float *ps = NULL, *pe = NULL;
1689   float *ns = NULL, *ne = NULL;
1690
1691   /* sanity checks */
1692   if (ELEM(NULL, nls, nlt)) {
1693     return;
1694   }
1695   if ((nlt->prev == NULL) && (nlt->next == NULL)) {
1696     return;
1697   }
1698   if ((nls->flag & NLASTRIP_FLAG_AUTO_BLENDS) == 0) {
1699     return;
1700   }
1701
1702   /* get test ranges */
1703   if (nlt->prev) {
1704     nlastrip_get_endpoint_overlaps(nls, nlt->prev, &ps, &pe);
1705   }
1706   if (nlt->next) {
1707     nlastrip_get_endpoint_overlaps(nls, nlt->next, &ns, &ne);
1708   }
1709
1710   /* set overlaps for this strip
1711    * - don't use the values obtained though if the end in question
1712    *   is directly followed/preceded by another strip, forming an
1713    *   'island' of continuous strips
1714    */
1715   if ((ps || ns) && ((nls->prev == NULL) || IS_EQF(nls->prev->end, nls->start) == 0)) {
1716     /* start overlaps - pick the largest overlap */
1717     if (((ps && ns) && (*ps > *ns)) || (ps)) {
1718       nls->blendin = *ps - nls->start;
1719     }
1720     else {
1721       nls->blendin = *ns - nls->start;
1722     }
1723   }
1724   else { /* no overlap allowed/needed */
1725     nls->blendin = 0.0f;
1726   }
1727
1728   if ((pe || ne) && ((nls->next == NULL) || IS_EQF(nls->next->start, nls->end) == 0)) {
1729     /* end overlaps - pick the largest overlap */
1730     if (((pe && ne) && (*pe > *ne)) || (pe)) {
1731       nls->blendout = nls->end - *pe;
1732     }
1733     else {
1734       nls->blendout = nls->end - *ne;
1735     }
1736   }
1737   else { /* no overlap allowed/needed */
1738     nls->blendout = 0.0f;
1739   }
1740 }
1741
1742 /* Ensure that auto-blending and other settings are set correctly */
1743 void BKE_nla_validate_state(AnimData *adt)
1744 {
1745   NlaStrip *strip, *fstrip = NULL;
1746   NlaTrack *nlt;
1747
1748   /* sanity checks */
1749   if (ELEM(NULL, adt, adt->nla_tracks.first)) {
1750     return;
1751   }
1752
1753   /* adjust blending values for auto-blending, and also do an initial pass to find the earliest strip */
1754   for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) {
1755     for (strip = nlt->strips.first; strip; strip = strip->next) {
1756       /* auto-blending first */
1757       BKE_nlastrip_validate_autoblends(nlt, strip);
1758
1759       /* extend mode - find first strip */
1760       if ((fstrip == NULL) || (strip->start < fstrip->start)) {
1761         fstrip = strip;
1762       }
1763     }
1764   }
1765
1766   /* second pass over the strips to adjust the extend-mode to fix any problems */
1767   for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) {
1768     for (strip = nlt->strips.first; strip; strip = strip->next) {
1769       /* apart from 'nothing' option which user has to explicitly choose, we don't really know if
1770        * we should be overwriting the extend setting (but assume that's what the user wanted)
1771        */
1772       /* TODO: 1 solution is to tie this in with auto-blending... */
1773       if (strip->extendmode != NLASTRIP_EXTEND_NOTHING) {
1774         /* 1) First strip must be set to extend hold, otherwise, stuff before acts dodgy
1775          * 2) Only overwrite extend mode if *not* changing it will most probably result in
1776          * occlusion problems, which will occur if...
1777          * - blendmode = REPLACE
1778          * - all channels the same (this is fiddly to test, so is currently assumed)
1779          *
1780          * Should fix problems such as [#29869]
1781          */
1782         if (strip == fstrip) {
1783           strip->extendmode = NLASTRIP_EXTEND_HOLD;
1784         }
1785         else if (strip->blendmode == NLASTRIP_MODE_REPLACE) {
1786           strip->extendmode = NLASTRIP_EXTEND_HOLD_FORWARD;
1787         }
1788       }
1789     }
1790   }
1791 }
1792
1793 /* Action Stashing -------------------------------------- */
1794
1795 /* name of stashed tracks - the translation stuff is included here to save extra work */
1796 #define STASH_TRACK_NAME DATA_("[Action Stash]")
1797
1798 /* Check if an action is "stashed" in the NLA already
1799  *
1800  * The criteria for this are:
1801  *   1) The action in question lives in a "stash" track
1802  *   2) We only check first-level strips. That is, we will not check inside meta strips.
1803  */
1804 bool BKE_nla_action_is_stashed(AnimData *adt, bAction *act)
1805 {
1806   NlaTrack *nlt;
1807   NlaStrip *strip;
1808
1809   for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) {
1810     if (strstr(nlt->name, STASH_TRACK_NAME)) {
1811       for (strip = nlt->strips.first; strip; strip = strip->next) {
1812         if (strip->act == act) {
1813           return true;
1814         }
1815       }
1816     }
1817   }
1818
1819   return false;
1820 }
1821
1822 /* "Stash" an action (i.e. store it as a track/layer in the NLA, but non-contributing)
1823  * to retain it in the file for future uses
1824  */
1825 bool BKE_nla_action_stash(AnimData *adt)
1826 {
1827   NlaTrack *prev_track = NULL;
1828   NlaTrack *nlt;
1829   NlaStrip *strip;
1830
1831   /* sanity check */
1832   if (ELEM(NULL, adt, adt->action)) {
1833     CLOG_ERROR(&LOG, "Invalid argument - %p %p", adt, adt->action);
1834     return false;
1835   }
1836
1837   /* do not add if it is already stashed */
1838   if (BKE_nla_action_is_stashed(adt, adt->action)) {
1839     return false;
1840   }
1841
1842   /* create a new track, and add this immediately above the previous stashing track */
1843   for (prev_track = adt->nla_tracks.last; prev_track; prev_track = prev_track->prev) {
1844     if (strstr(prev_track->name, STASH_TRACK_NAME)) {
1845       break;
1846     }
1847   }
1848
1849   nlt = BKE_nlatrack_add(adt, prev_track);
1850   BLI_assert(nlt != NULL);
1851
1852   /* we need to ensure that if there wasn't any previous instance, it must go to tbe bottom of the stack */
1853   if (prev_track == NULL) {
1854     BLI_remlink(&adt->nla_tracks, nlt);
1855     BLI_addhead(&adt->nla_tracks, nlt);
1856   }
1857
1858   BLI_strncpy(nlt->name, STASH_TRACK_NAME, sizeof(nlt->name));
1859   BLI_uniquename(
1860       &adt->nla_tracks, nlt, STASH_TRACK_NAME, '.', offsetof(NlaTrack, name), sizeof(nlt->name));
1861
1862   /* add the action as a strip in this new track
1863    * NOTE: a new user is created here
1864    */
1865   strip = BKE_nlastrip_new(adt->action);
1866   BLI_assert(strip != NULL);
1867
1868   BKE_nlatrack_add_strip(nlt, strip);
1869   BKE_nlastrip_validate_name(adt, strip);
1870
1871   /* mark the stash track and strip so that they doesn't disturb the stack animation,
1872    * and are unlikely to draw attention to itself (or be accidentally bumped around)
1873    *
1874    * NOTE: this must be done *after* adding the strip to the track, or else
1875    *       the strip locking will prevent the strip from getting added
1876    */
1877   nlt->flag = (NLATRACK_MUTED | NLATRACK_PROTECTED);
1878   strip->flag &= ~(NLASTRIP_FLAG_SELECT | NLASTRIP_FLAG_ACTIVE);
1879
1880   /* also mark the strip for auto syncing the length, so that the strips accurately
1881    * reflect the length of the action
1882    * XXX: we could do with some extra flags here to prevent repeats/scaling options from working!
1883    */
1884   strip->flag |= NLASTRIP_FLAG_SYNC_LENGTH;
1885
1886   /* succeeded */
1887   return true;
1888 }
1889
1890 /* Core Tools ------------------------------------------- */
1891
1892 /* For the given AnimData block, add the active action to the NLA
1893  * stack (i.e. 'push-down' action). The UI should only allow this
1894  * for normal editing only (i.e. not in editmode for some strip's action),
1895  * so no checks for this are performed.
1896  */
1897 /* TODO: maybe we should have checks for this too... */
1898 void BKE_nla_action_pushdown(AnimData *adt)
1899 {
1900   NlaStrip *strip;
1901   const bool is_first = (adt) && (adt->nla_tracks.first == NULL);
1902
1903   /* sanity checks */
1904   /* TODO: need to report the error for this */
1905   if (ELEM(NULL, adt, adt->action)) {
1906     return;
1907   }
1908
1909   /* if the action is empty, we also shouldn't try to add to stack,
1910    * as that will cause us grief down the track
1911    */
1912   /* TODO: what about modifiers? */
1913   if (action_has_motion(adt->action) == 0) {
1914     CLOG_ERROR(&LOG, "action has no data");
1915     return;
1916   }
1917
1918   /* add a new NLA strip to the track, which references the active action */
1919   strip = BKE_nlastack_add_strip(adt, adt->action);
1920
1921   /* do other necessary work on strip */
1922   if (strip) {
1923     /* clear reference to action now that we've pushed it onto the stack */
1924     id_us_min(&adt->action->id);
1925     adt->action = NULL;
1926
1927     /* copy current "action blending" settings from adt to the strip,
1928      * as it was keyframed with these settings, so omitting them will
1929      * change the effect  [T54233]
1930      *
1931      * NOTE: We only do this when there are no tracks
1932      */
1933     if (is_first == false) {
1934       strip->blendmode = adt->act_blendmode;
1935       strip->influence = adt->act_influence;
1936       strip->extendmode = adt->act_extendmode;
1937
1938       if (adt->act_influence < 1.0f) {
1939         /* enable "user-controlled" influence (which will insert a default keyframe)
1940          * so that the influence doesn't get lost on the new update
1941          *
1942          * NOTE: An alternative way would have been to instead hack the influence
1943          * to not get always get reset to full strength if NLASTRIP_FLAG_USR_INFLUENCE
1944          * is disabled but auto-blending isn't being used. However, that approach
1945          * is a bit hacky/hard to discover, and may cause backwards compatibility issues,
1946          * so it's better to just do it this way.
1947          */
1948         strip->flag |= NLASTRIP_FLAG_USR_INFLUENCE;
1949         BKE_nlastrip_validate_fcurves(strip);
1950       }
1951     }
1952
1953     /* if the strip is the first one in the track it lives in, check if there
1954      * are strips in any other tracks that may be before this, and set the extend
1955      * mode accordingly
1956      */
1957     if (nlastrip_is_first(adt, strip) == 0) {
1958       /* not first, so extend mode can only be NLASTRIP_EXTEND_HOLD_FORWARD not NLASTRIP_EXTEND_HOLD,
1959        * so that it doesn't override strips in previous tracks
1960        */
1961       /* FIXME: this needs to be more automated, since user can rearrange strips */
1962       if (strip->extendmode == NLASTRIP_EXTEND_HOLD) {
1963         strip->extendmode = NLASTRIP_EXTEND_HOLD_FORWARD;
1964       }
1965     }
1966
1967     /* make strip the active one... */
1968     BKE_nlastrip_set_active(adt, strip);
1969   }
1970 }
1971
1972 /* Find the active strip + track combo, and set them up as the tweaking track,
1973  * and return if successful or not.
1974  */
1975 bool BKE_nla_tweakmode_enter(AnimData *adt)
1976 {
1977   NlaTrack *nlt, *activeTrack = NULL;
1978   NlaStrip *strip, *activeStrip = NULL;
1979
1980   /* verify that data is valid */
1981   if (ELEM(NULL, adt, adt->nla_tracks.first)) {
1982     return false;
1983   }
1984
1985   /* if block is already in tweakmode, just leave, but we should report
1986    * that this block is in tweakmode (as our returncode)
1987    */
1988   if (adt->flag & ADT_NLA_EDIT_ON) {
1989     return true;
1990   }
1991
1992   /* go over the tracks, finding the active one, and its active strip
1993    * - if we cannot find both, then there's nothing to do
1994    */
1995   for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) {
1996     /* check if active */
1997     if (nlt->flag & NLATRACK_ACTIVE) {
1998       /* store reference to this active track */
1999       activeTrack = nlt;
2000
2001       /* now try to find active strip */
2002       activeStrip = BKE_nlastrip_find_active(nlt);
2003       break;
2004     }
2005   }
2006
2007   /* There are situations where we may have multiple strips selected and we want to enter tweakmode on all
2008    * of those at once. Usually in those cases, it will usually just be a single strip per AnimData.
2009    * In such cases, compromise and take the last selected track and/or last selected strip [#28468]
2010    */
2011   if (activeTrack == NULL) {
2012     /* try last selected track for active strip */
2013     for (nlt = adt->nla_tracks.last; nlt; nlt = nlt->prev) {
2014       if (nlt->flag & NLATRACK_SELECTED) {
2015         /* assume this is the active track */
2016         activeTrack = nlt;
2017
2018         /* try to find active strip */
2019         activeStrip = BKE_nlastrip_find_active(nlt);
2020         break;
2021       }
2022     }
2023   }
2024   if ((activeTrack) && (activeStrip == NULL)) {
2025     /* no active strip in active or last selected track; compromise for first selected (assuming only single)... */
2026     for (strip = activeTrack->strips.first; strip; strip = strip->next) {
2027       if (strip->flag & (NLASTRIP_FLAG_SELECT | NLASTRIP_FLAG_ACTIVE)) {
2028         activeStrip = strip;
2029         break;
2030       }
2031     }
2032   }
2033
2034   if (ELEM(NULL, activeTrack, activeStrip, activeStrip->act)) {
2035     if (G.debug & G_DEBUG) {
2036       printf("NLA tweakmode enter - neither active requirement found\n");
2037       printf("\tactiveTrack = %p, activeStrip = %p\n", (void *)activeTrack, (void *)activeStrip);
2038     }
2039     return false;
2040   }
2041
2042   /* go over all the tracks up to the active one, tagging each strip that uses the same
2043    * action as the active strip, but leaving everything else alone
2044    */
2045   for (nlt = activeTrack->prev; nlt; nlt = nlt->prev) {
2046     for (strip = nlt->strips.first; strip; strip = strip->next) {
2047       if (strip->act == activeStrip->act) {
2048         strip->flag |= NLASTRIP_FLAG_TWEAKUSER;
2049       }
2050       else {
2051         strip->flag &= ~NLASTRIP_FLAG_TWEAKUSER;
2052       }
2053     }
2054   }
2055
2056   /* tag all other strips in active track that uses the same action as the active strip */
2057   for (strip = activeTrack->strips.first; strip; strip = strip->next) {
2058     if ((strip->act == activeStrip->act) && (strip != activeStrip)) {
2059       strip->flag |= NLASTRIP_FLAG_TWEAKUSER;
2060     }
2061     else {
2062       strip->flag &= ~NLASTRIP_FLAG_TWEAKUSER;
2063     }
2064   }
2065
2066   /* go over all the tracks after AND INCLUDING the active one, tagging them as being disabled
2067    * - the active track needs to also be tagged, otherwise, it'll overlap with the tweaks going on
2068    */
2069   for (nlt = activeTrack; nlt; nlt = nlt->next) {
2070     nlt->flag |= NLATRACK_DISABLED;
2071   }
2072
2073   /* handle AnimData level changes:
2074    * - 'real' active action to temp storage (no need to change user-counts)
2075    * - action of active strip set to be the 'active action', and have its usercount incremented
2076    * - editing-flag for this AnimData block should also get turned on (for more efficient restoring)
2077    * - take note of the active strip for mapping-correction of keyframes in the action being edited
2078    */
2079   adt->tmpact = adt->action;
2080   adt->action = activeStrip->act;
2081   adt->act_track = activeTrack;
2082   adt->actstrip = activeStrip;
2083   id_us_plus(&activeStrip->act->id);
2084   adt->flag |= ADT_NLA_EDIT_ON;
2085
2086   /* done! */
2087   return true;
2088 }
2089
2090 /* Exit tweakmode for this AnimData block */
2091 void BKE_nla_tweakmode_exit(AnimData *adt)
2092 {
2093   NlaStrip *strip;
2094   NlaTrack *nlt;
2095
2096   /* verify that data is valid */
2097   if (ELEM(NULL, adt, adt->nla_tracks.first)) {
2098     return;
2099   }
2100
2101   /* hopefully the flag is correct - skip if not on */
2102   if ((adt->flag & ADT_NLA_EDIT_ON) == 0) {
2103     return;
2104   }
2105
2106   /* sync the length of the user-strip with the new state of the action
2107    * but only if the user has explicitly asked for this to happen
2108    * (see [#34645] for things to be careful about)
2109    */
2110   if ((adt->actstrip) && (adt->actstrip->flag & NLASTRIP_FLAG_SYNC_LENGTH)) {
2111     strip = adt->actstrip;
2112
2113     /* must be action-clip only (transitions don't have scale) */
2114     if ((strip->type == NLASTRIP_TYPE_CLIP) && (strip->act)) {
2115       /* recalculate the length of the action */
2116       calc_action_range(strip->act, &strip->actstart, &strip->actend, 0);
2117
2118       /* adjust the strip extents in response to this */
2119       BKE_nlastrip_recalculate_bounds(strip);
2120     }
2121   }
2122
2123   /* for all Tracks, clear the 'disabled' flag
2124    * for all Strips, clear the 'tweak-user' flag
2125    */
2126   for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) {
2127     nlt->flag &= ~NLATRACK_DISABLED;
2128
2129     for (strip = nlt->strips.first; strip; strip = strip->next) {
2130       /* sync strip extents if this strip uses the same action */
2131       if ((adt->actstrip) && (adt->actstrip->act == strip->act) &&
2132           (strip->flag & NLASTRIP_FLAG_SYNC_LENGTH)) {
2133         /* recalculate the length of the action */
2134         calc_action_range(strip->act, &strip->actstart, &strip->actend, 0);
2135
2136         /* adjust the strip extents in response to this */
2137         BKE_nlastrip_recalculate_bounds(strip);
2138       }
2139
2140       /* clear tweakuser flag */
2141       strip->flag &= ~NLASTRIP_FLAG_TWEAKUSER;
2142     }
2143   }
2144
2145   /* handle AnimData level changes:
2146    * - 'temporary' active action needs its usercount decreased, since we're removing this reference
2147    * - 'real' active action is restored from storage
2148    * - storage pointer gets cleared (to avoid having bad notes hanging around)
2149    * - editing-flag for this AnimData block should also get turned off
2150    * - clear pointer to active strip
2151    */
2152   if (adt->action) {
2153     id_us_min(&adt->action->id);
2154   }
2155   adt->action = adt->tmpact;
2156   adt->tmpact = NULL;
2157   adt->act_track = NULL;
2158   adt->actstrip = NULL;
2159   adt->flag &= ~ADT_NLA_EDIT_ON;
2160 }