Blender V4.3
nla_edit.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2009 Blender Authors, Joshua Leung. All rights reserved.
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
9#include <cmath>
10#include <cstdio>
11#include <cstring>
12
13#include "DNA_anim_types.h"
14#include "DNA_object_types.h"
15#include "DNA_scene_types.h"
16
17#include "MEM_guardedalloc.h"
18
19#include "BLI_utildefines.h"
20
21#include "BLT_translation.hh"
22
23#include "BKE_context.hh"
24#include "BKE_fcurve.hh"
25#include "BKE_lib_id.hh"
26#include "BKE_main.hh"
27#include "BKE_nla.hh"
28#include "BKE_report.hh"
29
30#include "ED_anim_api.hh"
31#include "ED_keyframes_edit.hh"
32#include "ED_markers.hh"
33#include "ED_screen.hh"
34
35#include "RNA_access.hh"
36#include "RNA_define.hh"
37#include "RNA_enum_types.hh"
38#include "RNA_prototypes.hh"
39
40#include "UI_interface_icons.hh"
41
42#include "WM_api.hh"
43#include "WM_types.hh"
44
46
47#include "UI_view2d.hh"
48
49#include "ANIM_action.hh"
50#include "ANIM_action_legacy.hh"
51
52#include "nla_intern.hh"
53#include "nla_private.h"
54
55/* -------------------------------------------------------------------- */
60{
61 ListBase anim_data = {nullptr, nullptr};
64
65 /* get blocks to work on */
66 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, eAnimCont_Types(ac->datatype));
67
68 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
69 if (!ale->adt) {
70 continue;
71 }
72 /* performing auto-blending, extend-mode validation, etc. */
73 BKE_nla_validate_state(static_cast<AnimData *>(ale->data));
74
75 ale->update |= ANIM_UPDATE_DEPS;
76 }
77
78 /* free temp memory */
79 ANIM_animdata_update(ac, &anim_data);
80 ANIM_animdata_freelist(&anim_data);
81}
82
85/* 'Special' Editing */
86
87/* 'Tweak mode' allows the action referenced by the active NLA-strip to be edited
88 * as if it were the normal Active-Action of its AnimData block.
89 */
90
91/* -------------------------------------------------------------------- */
96{
97 bAnimContext ac;
98
99 ListBase anim_data = {nullptr, nullptr};
100
101 const bool do_solo = RNA_boolean_get(op->ptr, "isolate_action");
102 const bool use_upper_stack_evaluation = RNA_boolean_get(op->ptr, "use_upper_stack_evaluation");
103 bool ok = false;
104
105 /* get editor data */
106 if (ANIM_animdata_get_context(C, &ac) == 0) {
107 return OPERATOR_CANCELLED;
108 }
109
110 /* get a list of the AnimData blocks being shown in the NLA */
113 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, eAnimCont_Types(ac.datatype));
114
115 /* if no blocks, popup error? */
116 if (BLI_listbase_is_empty(&anim_data)) {
117 BKE_report(op->reports, RPT_ERROR, "No AnimData blocks to enter tweak mode for");
118 return OPERATOR_CANCELLED;
119 }
120
121 /* for each AnimData block with NLA-data, try setting it in tweak-mode */
122 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
123 if (ale->type != ANIMTYPE_ANIMDATA) {
124 continue;
125 }
126 AnimData *adt = static_cast<AnimData *>(ale->data);
127 BLI_assert(adt);
128
129 if (use_upper_stack_evaluation) {
131 }
132 else {
133 adt->flag &= ~ADT_NLA_EVAL_UPPER_TRACKS;
134 }
135
136 /* Try entering tweak-mode if valid. */
137 ok |= BKE_nla_tweakmode_enter({*ale->id, *adt});
138
139 /* mark the active track as being "solo"? */
140 if (do_solo && adt->actstrip) {
142
143 if (nlt && !(nlt->flag & NLATRACK_SOLO)) {
144 BKE_nlatrack_solo_toggle(adt, nlt);
145 }
146 }
147
148 ale->update |= ANIM_UPDATE_DEPS;
149 }
150
151 /* free temp data */
152 ANIM_animdata_update(&ac, &anim_data);
153 ANIM_animdata_freelist(&anim_data);
154
155 /* If we managed to enter tweak-mode on at least one AnimData block,
156 * set the flag for this in the active scene and send notifiers. */
157 if (ac.scene && ok) {
158 /* set editing flag */
160
161 /* set notifier that things have changed */
163 }
164 else {
165 BKE_report(op->reports, RPT_ERROR, "No active strip(s) to enter tweak mode on");
166 return OPERATOR_CANCELLED;
167 }
168
169 /* done */
170 return OPERATOR_FINISHED;
171}
172
174{
175 PropertyRNA *prop;
176
177 /* identifiers */
178 ot->name = "Enter Tweak Mode";
179 ot->idname = "NLA_OT_tweakmode_enter";
180 ot->description =
181 "Enter tweaking mode for the action referenced by the active strip to edit its keyframes";
182
183 /* api callbacks */
186
187 /* flags */
189
190 /* properties */
191 prop = RNA_def_boolean(ot->srna,
192 "isolate_action",
193 false,
194 "Isolate Action",
195 "Enable 'solo' on the NLA Track containing the active strip, "
196 "to edit it without seeing the effects of the NLA stack");
198
199 prop = RNA_def_boolean(ot->srna,
200 "use_upper_stack_evaluation",
201 false,
202 "Evaluate Upper Stack",
203 "In tweak mode, display the effects of the tracks above the tweak strip");
205}
206
209/* -------------------------------------------------------------------- */
214{
215 ListBase anim_data = {nullptr, nullptr};
216
217 /* get a list of the AnimData blocks being shown in the NLA */
220 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, eAnimCont_Types(ac->datatype));
221
222 /* if no blocks, popup error? */
223 if (BLI_listbase_is_empty(&anim_data)) {
224 BKE_report(ac->reports, RPT_ERROR, "No AnimData blocks in tweak mode to exit from");
225 return false;
226 }
227
228 /* For each AnimData block with NLA-data, try exiting tweak-mode. */
229 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
230 AnimData *adt = static_cast<AnimData *>(ale->data);
231
232 /* clear solo flags */
233 if (do_solo && (adt->flag & ADT_NLA_SOLO_TRACK) && (adt->flag & ADT_NLA_EDIT_ON)) {
234 BKE_nlatrack_solo_toggle(adt, nullptr);
235 }
236
237 /* To be sure that we're doing everything right, just exit tweak-mode. */
238 BKE_nla_tweakmode_exit({*ale->id, *adt});
239
240 ale->update |= ANIM_UPDATE_DEPS;
241 }
242
243 /* free temp data */
244 ANIM_animdata_update(ac, &anim_data);
245 ANIM_animdata_freelist(&anim_data);
246
247 /* Clear the tweak-mode flag in the active scene and send notifiers. */
248 if (ac->scene) {
249 /* clear editing flag */
250 ac->scene->flag &= ~SCE_NLA_EDIT_ON;
251
252 /* set notifier that things have changed */
254 }
255
256 /* done */
257 return true;
258}
259
260/* Exit tweak-mode operator callback. */
262{
263 bAnimContext ac;
264
265 const bool do_solo = RNA_boolean_get(op->ptr, "isolate_action");
266 bool ok = false;
267
268 /* get editor data */
269 if (ANIM_animdata_get_context(C, &ac) == 0) {
270 return OPERATOR_CANCELLED;
271 }
272
273 /* perform operation */
274 ok = nlaedit_disable_tweakmode(&ac, do_solo);
275
276 /* success? */
277 if (ok) {
278 return OPERATOR_FINISHED;
279 }
280 return OPERATOR_CANCELLED;
281}
282
284{
285 PropertyRNA *prop;
286
287 /* identifiers */
288 ot->name = "Exit Tweak Mode";
289 ot->idname = "NLA_OT_tweakmode_exit";
290 ot->description = "Exit tweaking mode for the action referenced by the active strip";
291
292 /* api callbacks */
295
296 /* flags */
298
299 /* properties */
300 prop = RNA_def_boolean(ot->srna,
301 "isolate_action",
302 false,
303 "Isolate Action",
304 "Disable 'solo' on any of the NLA Tracks after exiting tweak mode "
305 "to get things back to normal");
307}
308
311/* NLA Strips Range Stuff */
312
313/* -------------------------------------------------------------------- */
317/* Get the min/max strip extents */
318static void get_nlastrip_extents(bAnimContext *ac, float *min, float *max, const bool only_sel)
319{
320 ListBase anim_data = {nullptr, nullptr};
321 bool found_bounds = false;
322
323 /* get data to filter */
326 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, eAnimCont_Types(ac->datatype));
327
328 /* set large values to try to override */
329 *min = 999999999.0f;
330 *max = -999999999.0f;
331
332 /* check if any tracks to set range with */
333 if (anim_data.first) {
334 /* go through tracks, finding max extents */
335 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
336 NlaTrack *nlt = static_cast<NlaTrack *>(ale->data);
337
338 LISTBASE_FOREACH (NlaStrip *, strip, &nlt->strips) {
339 /* only consider selected strips? */
340 if ((only_sel == false) || (strip->flag & NLASTRIP_FLAG_SELECT)) {
341 /* extend range if appropriate */
342 *min = std::min(*min, strip->start);
343 *max = std::max(*max, strip->end);
344
345 found_bounds = true;
346 }
347 }
348 }
349
350 /* free memory */
351 ANIM_animdata_freelist(&anim_data);
352 }
353
354 /* set default range if nothing happened */
355 if (found_bounds == false) {
356 if (ac->scene) {
357 *min = float(ac->scene->r.sfra);
358 *max = float(ac->scene->r.efra);
359 }
360 else {
361 *min = -5;
362 *max = 100;
363 }
364 }
365}
366
369/* -------------------------------------------------------------------- */
374{
375 bAnimContext ac;
376 Scene *scene;
377 float min, max;
378
379 /* get editor data */
380 if (ANIM_animdata_get_context(C, &ac) == 0) {
381 return OPERATOR_CANCELLED;
382 }
383
384 if (ac.scene == nullptr) {
385 return OPERATOR_CANCELLED;
386 }
387
388 scene = ac.scene;
389
390 /* set the range directly */
391 get_nlastrip_extents(&ac, &min, &max, true);
392 scene->r.flag |= SCER_PRV_RANGE;
393 scene->r.psfra = round_fl_to_int(min);
394 scene->r.pefra = round_fl_to_int(max);
395
396 /* set notifier that things have changed */
397 /* XXX err... there's nothing for frame ranges yet, but this should do fine too */
399
400 return OPERATOR_FINISHED;
401}
402
404{
405 /* identifiers */
406 ot->name = "Set Preview Range to Selected";
407 ot->idname = "NLA_OT_previewrange_set";
408 ot->description = "Set Preview Range based on extends of selected strips";
409
410 /* api callbacks */
413
414 /* flags */
416}
417
420/* -------------------------------------------------------------------- */
431static bool nla_tracks_get_selected_extents(bAnimContext *ac, float *r_min, float *r_max)
432{
433 ListBase anim_data = {nullptr, nullptr};
434
435 SpaceNla *snla = reinterpret_cast<SpaceNla *>(ac->sl);
436 /* NOTE: not bool, since we want prioritize individual tracks over expanders. */
437 short found = 0;
438
439 /* get all items - we need to do it this way */
442 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, eAnimCont_Types(ac->datatype));
443
444 /* loop through all tracks, finding the first one that's selected */
445 float ymax = NLATRACK_FIRST_TOP(ac);
446
447 for (bAnimListElem *ale = static_cast<bAnimListElem *>(anim_data.first); ale;
448 ale = ale->next, ymax -= NLATRACK_STEP(snla))
449 {
451
452 /* must be selected... */
453 if (acf && acf->has_setting(ac, ale, ACHANNEL_SETTING_SELECT) &&
455 {
456 /* update best estimate */
457 *r_min = ymax - NLATRACK_HEIGHT(snla);
458 *r_max = ymax;
459
460 /* is this high enough priority yet? */
461 found = acf->channel_role;
462
463 /* only stop our search when we've found an actual track
464 * - data-block expanders get less priority so that we don't abort prematurely
465 */
466 if (found == ACHANNEL_ROLE_CHANNEL) {
467 break;
468 }
469 }
470 }
471
472 /* free all temp data */
473 ANIM_animdata_freelist(&anim_data);
474
475 return (found != 0);
476}
477
478static int nlaedit_viewall(bContext *C, const bool only_sel)
479{
480 bAnimContext ac;
481 View2D *v2d;
482 float extra;
483
484 /* get editor data */
485 if (ANIM_animdata_get_context(C, &ac) == 0) {
486 return OPERATOR_CANCELLED;
487 }
488 v2d = &ac.region->v2d;
489
490 /* set the horizontal range, with an extra offset so that the extreme keys will be in view */
491 get_nlastrip_extents(&ac, &v2d->cur.xmin, &v2d->cur.xmax, only_sel);
492
493 extra = 0.1f * BLI_rctf_size_x(&v2d->cur);
494 v2d->cur.xmin -= extra;
495 v2d->cur.xmax += extra;
496
497 /* set vertical range */
498 if (only_sel == false) {
499 /* view all -> the summary track is usually the shows everything,
500 * and resides right at the top... */
501 v2d->cur.ymax = 0.0f;
502 v2d->cur.ymin = float(-BLI_rcti_size_y(&v2d->mask));
503 }
504 else {
505 /* locate first selected track (or the active one), and frame those */
506 float ymin = v2d->cur.ymin;
507 float ymax = v2d->cur.ymax;
508
509 if (nla_tracks_get_selected_extents(&ac, &ymin, &ymax)) {
510 /* recenter the view so that this range is in the middle */
511 float ymid = (ymax - ymin) / 2.0f + ymin;
512 float x_center;
513
514 UI_view2d_center_get(v2d, &x_center, nullptr);
515 UI_view2d_center_set(v2d, x_center, ymid);
516 }
517 }
518
519 /* do View2D syncing */
521
522 /* just redraw this view */
524
525 return OPERATOR_FINISHED;
526}
527
528/* ......... */
529
531{
532 /* whole range */
533 return nlaedit_viewall(C, false);
534}
535
537{
538 /* only selected */
539 return nlaedit_viewall(C, true);
540}
541
543{
544 /* identifiers */
545 ot->name = "Frame All";
546 ot->idname = "NLA_OT_view_all";
547 ot->description = "Reset viewable area to show full strips range";
548
549 /* api callbacks */
552
553 /* flags */
554 ot->flag = 0;
555}
556
558{
559 /* identifiers */
560 ot->name = "Frame Selected";
561 ot->idname = "NLA_OT_view_selected";
562 ot->description = "Reset viewable area to show selected strips range";
563
564 /* api callbacks */
567
568 /* flags */
569 ot->flag = 0;
570}
571
574/* -------------------------------------------------------------------- */
579{
580 const int smooth_viewtx = WM_operator_smooth_viewtx_get(op);
581 ANIM_center_frame(C, smooth_viewtx);
582 return OPERATOR_FINISHED;
583}
584
586{
587 /* identifiers */
588 ot->name = "Go to Current Frame";
589 ot->idname = "NLA_OT_view_frame";
590 ot->description = "Move the view to the current frame";
591
592 /* api callbacks */
595
596 /* flags */
597 ot->flag = 0;
598}
599
602/* NLA Editing Operations (Constructive/Destructive) */
603
604/* -------------------------------------------------------------------- */
611/* Get a list of the editable tracks being shown in the NLA. */
618
620{
621 /* Get editor data. */
622 bAnimContext ac;
623 if (ANIM_animdata_get_context(C, &ac) == 0) {
624 return OPERATOR_CANCELLED;
625 }
626
627 ListBase anim_data = {nullptr, nullptr};
628 const size_t items = nlaedit_get_editable_tracks(&ac, &anim_data);
629
630 if (items == 0) {
632 RPT_ERROR,
633 "No active track(s) to add strip to, select an existing track or add one before "
634 "trying again");
635 return OPERATOR_CANCELLED;
636 }
637
638 return WM_enum_search_invoke(C, op, event);
639}
640
641/* add the specified action as new strip */
643{
644 Main *bmain = CTX_data_main(C);
645 bAnimContext ac;
646
647 ListBase anim_data = {nullptr, nullptr};
648
649 /* get editor data */
650 if (ANIM_animdata_get_context(C, &ac) == 0) {
651 return OPERATOR_CANCELLED;
652 }
653
654 Scene *scene = ac.scene;
655 float cfra = float(scene->r.cfra);
656
657 /* get action to use */
658 bAction *act = static_cast<bAction *>(
659 BLI_findlink(&bmain->actions, RNA_enum_get(op->ptr, "action")));
660
661 if (act == nullptr) {
662 BKE_report(op->reports, RPT_ERROR, "No valid action to add");
663 // printf("Add strip - actname = '%s'\n", actname);
664 return OPERATOR_CANCELLED;
665 }
667 /* hopefully in this case (i.e. library of userless actions),
668 * the user knows what they're doing... */
671 "Action '%s' does not specify what data-blocks it can be used on "
672 "(try setting the 'ID Root Type' setting from the data-blocks editor "
673 "for this action to avoid future problems)",
674 act->id.name + 2);
675 }
676
677 /* add tracks to empty but selected animdata blocks so that strips can be added to those directly
678 * without having to manually add tracks first
679 */
681
682 nlaedit_get_editable_tracks(&ac, &anim_data);
683
684 /* for every active track,
685 * try to add strip to free space in track or to the top of the stack if no space */
686
687 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
688 NlaTrack *nlt = static_cast<NlaTrack *>(ale->data);
689 AnimData *adt = ale->adt;
690 NlaStrip *strip = nullptr;
691 const bool is_liboverride = ID_IS_OVERRIDE_LIBRARY(ale->id);
692
693 /* Sanity check: only apply actions of the right type for this ID.
694 * NOTE: in the case that this hasn't been set,
695 * we've already warned the user about this already
696 */
697 if ((act->idroot) && (act->idroot != GS(ale->id->name))) {
699 op->reports,
700 RPT_ERROR,
701 "Could not add action '%s' as it cannot be used relative to ID-blocks of type '%s'",
702 act->id.name + 2,
703 ale->id->name);
704 continue;
705 }
706
707 /* create a new strip, and offset it to start on the current frame */
708 BLI_assert(ale->id);
709 BLI_assert_msg(GS(ale->id->name) != ID_AC,
710 "Expecting the owner of an ALE to be the animated ID, not the Action");
711 ID &animated_id = *ale->id;
712 strip = BKE_nlastrip_new(act, animated_id);
713
714 strip->end += (cfra - strip->start);
715 strip->start = cfra;
716
717 /* firstly try adding strip to our current track, but if that fails, add to a new track */
718 if (BKE_nlatrack_add_strip(nlt, strip, is_liboverride) == 0) {
719 /* trying to add to the current failed (no space),
720 * so add a new track to the stack, and add to that...
721 */
722 nlt = BKE_nlatrack_new_tail(&adt->nla_tracks, is_liboverride);
724 BKE_nlatrack_add_strip(nlt, strip, is_liboverride);
725 }
726
727 /* auto-name it */
728 BKE_nlastrip_validate_name(adt, strip);
729 }
730
731 /* free temp data */
732 ANIM_animdata_freelist(&anim_data);
733
734 /* refresh auto strip properties */
736
738
739 /* set notifier that things have changed */
741
742 /* done */
743 return OPERATOR_FINISHED;
744}
745
747{
748 PropertyRNA *prop;
749
750 /* identifiers */
751 ot->name = "Add Action Strip";
752 ot->idname = "NLA_OT_actionclip_add";
753 ot->description =
754 "Add an Action-Clip strip (i.e. an NLA Strip referencing an Action) to the active track";
755
756 /* api callbacks */
760
761 /* flags */
763
764 /* props */
765 /* TODO: this would be nicer as an ID-pointer. */
766 prop = RNA_def_enum(ot->srna, "action", rna_enum_dummy_NULL_items, 0, "Action", "");
769 ot->prop = prop;
770}
771
774/* -------------------------------------------------------------------- */
781{
782 bAnimContext ac;
783
784 ListBase anim_data = {nullptr, nullptr};
785
786 bool done = false;
787
788 /* get editor data */
789 if (ANIM_animdata_get_context(C, &ac) == 0) {
790 return OPERATOR_CANCELLED;
791 }
792
793 /* get a list of the editable tracks being shown in the NLA */
796 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, eAnimCont_Types(ac.datatype));
797
798 /* for each track, find pairs of strips to add transitions to */
799 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
800 NlaTrack *nlt = static_cast<NlaTrack *>(ale->data);
801 AnimData *adt = ale->adt;
802 NlaStrip *s1, *s2;
803
804 /* get initial pair of strips */
805 if (ELEM(nlt->strips.first, nullptr, nlt->strips.last)) {
806 continue;
807 }
808 s1 = static_cast<NlaStrip *>(nlt->strips.first);
809 s2 = s1->next;
810
811 /* loop over strips */
812 for (; s1 && s2; s1 = s2, s2 = s2->next) {
813 NlaStrip *strip;
814
815 /* check if both are selected */
816 if (ELEM(0, (s1->flag & NLASTRIP_FLAG_SELECT), (s2->flag & NLASTRIP_FLAG_SELECT))) {
817 continue;
818 }
819 /* check if there's space between the two */
820 if (IS_EQF(s1->end, s2->start)) {
821 continue;
822 }
823 /* make sure neither one is a transition
824 * - although this is impossible to create with the standard tools,
825 * the user may have altered the settings
826 */
827 if (ELEM(NLASTRIP_TYPE_TRANSITION, s1->type, s2->type)) {
828 continue;
829 }
830 /* also make sure neither one is a soundclip */
831 if (ELEM(NLASTRIP_TYPE_SOUND, s1->type, s2->type)) {
832 continue;
833 }
834
835 /* allocate new strip */
836 strip = MEM_cnew<NlaStrip>("NlaStrip");
837 BLI_insertlinkafter(&nlt->strips, s1, strip);
838
839 /* set the type */
841
842 /* generic settings
843 * - selected flag to highlight this to the user
844 * - auto-blends to ensure that blend in/out values are automatically
845 * determined by overlaps of strips
846 */
848
849 /* range is simply defined as the endpoints of the adjacent strips */
850 strip->start = s1->end;
851 strip->end = s2->start;
852
853 /* scale and repeat aren't of any use, but shouldn't ever be 0 */
854 strip->scale = 1.0f;
855 strip->repeat = 1.0f;
856
857 /* auto-name it */
858 BKE_nlastrip_validate_name(adt, strip);
859
860 /* make note of this */
861 done = true;
862 }
863 }
864
865 /* free temp data */
866 ANIM_animdata_freelist(&anim_data);
867
868 /* was anything added? */
869 if (done) {
870 /* refresh auto strip properties */
872
873 /* set notifier that things have changed */
875
876 /* done */
877 return OPERATOR_FINISHED;
878 }
879
881 RPT_ERROR,
882 "Needs at least a pair of adjacent selected strips with a gap between them");
883 return OPERATOR_CANCELLED;
884}
885
887{
888 /* identifiers */
889 ot->name = "Add Transition";
890 ot->idname = "NLA_OT_transition_add";
891 ot->description = "Add a transition strip between two adjacent selected strips";
892
893 /* api callbacks */
896
897 /* flags */
899}
900
903/* -------------------------------------------------------------------- */
908{
909 Main *bmain = CTX_data_main(C);
910 bAnimContext ac;
911
912 ListBase anim_data = {nullptr, nullptr};
913
914 /* get editor data */
915 if (ANIM_animdata_get_context(C, &ac) == 0) {
916 return OPERATOR_CANCELLED;
917 }
918
919 Scene *scene = ac.scene;
920 int cfra = scene->r.cfra;
921
922 /* get a list of the editable tracks being shown in the NLA */
925 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, eAnimCont_Types(ac.datatype));
926
927 /* for each track, add sound clips if it belongs to a speaker */
928 /* TODO: what happens if there aren't any tracks,
929 * well that's a more general problem for later. */
930 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
931 Object *ob = reinterpret_cast<Object *>(
932 ale->id); /* may not be object until we actually check! */
933
934 AnimData *adt = ale->adt;
935 NlaTrack *nlt = static_cast<NlaTrack *>(ale->data);
936 const bool is_liboverride = ID_IS_OVERRIDE_LIBRARY(ale->id);
937
938 /* does this belong to speaker - assumed to live on Object level only */
939 if ((GS(ale->id->name) != ID_OB) || (ob->type != OB_SPEAKER)) {
940 continue;
941 }
942
943 /* create a new strip, and offset it to start on the current frame */
944 NlaStrip *strip = BKE_nla_add_soundstrip(bmain, ac.scene, static_cast<Speaker *>(ob->data));
945
946 strip->start += cfra;
947 strip->end += cfra;
948
949 /* firstly try adding strip to our current track, but if that fails, add to a new track */
950 if (BKE_nlatrack_add_strip(nlt, strip, is_liboverride) == 0) {
951 /* trying to add to the current failed (no space),
952 * so add a new track to the stack, and add to that...
953 */
954 nlt = BKE_nlatrack_new_tail(&adt->nla_tracks, is_liboverride);
956 BKE_nlatrack_add_strip(nlt, strip, is_liboverride);
957 }
958
959 /* auto-name it */
960 BKE_nlastrip_validate_name(adt, strip);
961 }
962
963 /* free temp data */
964 ANIM_animdata_freelist(&anim_data);
965
966 /* refresh auto strip properties */
968
969 /* set notifier that things have changed */
971
972 /* done */
973 return OPERATOR_FINISHED;
974}
975
977{
978 /* identifiers */
979 ot->name = "Add Sound Clip";
980 ot->idname = "NLA_OT_soundclip_add";
981 ot->description = "Add a strip for controlling when speaker plays its sound clip";
982
983 /* api callbacks */
986
987 /* flags */
989}
990
993/* -------------------------------------------------------------------- */
999/* add the specified action as new strip */
1001{
1002 bAnimContext ac;
1003
1004 ListBase anim_data = {nullptr, nullptr};
1005
1006 /* get editor data */
1007 if (ANIM_animdata_get_context(C, &ac) == 0) {
1008 return OPERATOR_CANCELLED;
1009 }
1010
1011 /* get a list of the editable tracks being shown in the NLA */
1014 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, eAnimCont_Types(ac.datatype));
1015
1016 /* for each track, find pairs of strips to add transitions to */
1017 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
1018 NlaTrack *nlt = static_cast<NlaTrack *>(ale->data);
1019 AnimData *adt = ale->adt;
1020
1021 if (BKE_nlatrack_is_nonlocal_in_liboverride(ale->id, nlt)) {
1022 /* No making meta-strips in non-local tracks of override data. */
1023 continue;
1024 }
1025
1026 /* create meta-strips from the continuous chains of selected strips */
1027 BKE_nlastrips_make_metas(&nlt->strips, false);
1028
1029 /* name the metas */
1030 LISTBASE_FOREACH (NlaStrip *, strip, &nlt->strips) {
1031 /* auto-name this strip if selected (that means it is a meta) */
1032 if (strip->flag & NLASTRIP_FLAG_SELECT) {
1033 BKE_nlastrip_validate_name(adt, strip);
1034 }
1035 }
1036
1037 ale->update |= ANIM_UPDATE_DEPS;
1038 }
1039
1040 /* free temp data */
1041 ANIM_animdata_update(&ac, &anim_data);
1042 ANIM_animdata_freelist(&anim_data);
1043
1044 /* set notifier that things have changed */
1046
1047 /* done */
1048 return OPERATOR_FINISHED;
1049}
1050
1052{
1053 /* identifiers */
1054 ot->name = "Add Meta-Strips";
1055 ot->idname = "NLA_OT_meta_add";
1056 ot->description = "Add new meta-strips incorporating the selected strips";
1057
1058 /* api callbacks */
1061
1062 /* flags */
1064}
1065
1068/* -------------------------------------------------------------------- */
1075{
1076 bAnimContext ac;
1077
1078 ListBase anim_data = {nullptr, nullptr};
1079
1080 /* get editor data */
1081 if (ANIM_animdata_get_context(C, &ac) == 0) {
1082 return OPERATOR_CANCELLED;
1083 }
1084
1085 /* get a list of the editable tracks being shown in the NLA */
1088 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, eAnimCont_Types(ac.datatype));
1089
1090 /* for each track, find pairs of strips to add transitions to */
1091 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
1092 NlaTrack *nlt = static_cast<NlaTrack *>(ale->data);
1093
1094 if (BKE_nlatrack_is_nonlocal_in_liboverride(ale->id, nlt)) {
1095 /* No removing meta-strips from non-local tracks of override data. */
1096 continue;
1097 }
1098
1099 /* clear all selected meta-strips, regardless of whether they are temporary or not */
1100 BKE_nlastrips_clear_metas(&nlt->strips, true, false);
1101
1102 ale->update |= ANIM_UPDATE_DEPS;
1103 }
1104
1105 /* free temp data */
1106 ANIM_animdata_update(&ac, &anim_data);
1107 ANIM_animdata_freelist(&anim_data);
1108
1109 /* set notifier that things have changed */
1111
1112 /* done */
1113 return OPERATOR_FINISHED;
1114}
1115
1117{
1118 /* identifiers */
1119 ot->name = "Remove Meta-Strips";
1120 ot->idname = "NLA_OT_meta_remove";
1121 ot->description = "Separate out the strips held by the selected meta-strips";
1122
1123 /* api callbacks */
1126
1127 /* flags */
1129}
1130
1133/* -------------------------------------------------------------------- */
1141{
1142 bAnimContext ac;
1143
1144 ListBase anim_data = {nullptr, nullptr};
1145
1146 bool linked = RNA_boolean_get(op->ptr, "linked");
1147 bool done = false;
1148
1149 /* get editor data */
1150 if (ANIM_animdata_get_context(C, &ac) == 0) {
1151 return OPERATOR_CANCELLED;
1152 }
1153
1154 /* get a list of editable tracks being shown in the NLA */
1157 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, eAnimCont_Types(ac.datatype));
1158
1159 /* duplicate strips in tracks starting from the last one so that we're
1160 * less likely to duplicate strips we just duplicated...
1161 */
1162 LISTBASE_FOREACH_BACKWARD (bAnimListElem *, ale, &anim_data) {
1163 NlaTrack *nlt = static_cast<NlaTrack *>(ale->data);
1164 AnimData *adt = ale->adt;
1165 NlaStrip *strip, *nstrip, *next;
1166 NlaTrack *track;
1167
1168 /* NOTE: We allow this operator in override context because it is almost always (from possible
1169 * default user interactions) paired with the transform one, which will ensure that the new
1170 * strip ends up in a valid (local) track. */
1171
1172 const bool is_liboverride = ID_IS_OVERRIDE_LIBRARY(ale->id);
1173 for (strip = static_cast<NlaStrip *>(nlt->strips.first); strip; strip = next) {
1174 next = strip->next;
1175
1176 /* if selected, split the strip at its midpoint */
1177 if (strip->flag & NLASTRIP_FLAG_SELECT) {
1178 /* make a copy (assume that this is possible) */
1179 nstrip = BKE_nlastrip_copy(ac.bmain, strip, linked, 0);
1180
1181 /* in case there's no space in the track above,
1182 * or we haven't got a reference to it yet, try adding */
1183 if (BKE_nlatrack_add_strip(nlt->next, nstrip, is_liboverride) == 0) {
1184 track = BKE_nlatrack_new_after(&adt->nla_tracks, nlt->next, is_liboverride);
1185 BKE_nlatrack_set_active(&adt->nla_tracks, track);
1186 BKE_nlatrack_add_strip(track, nstrip, is_liboverride);
1187 }
1188
1189 /* deselect the original and the active flag */
1191
1192 /* auto-name newly created strip */
1193 BKE_nlastrip_validate_name(adt, nstrip);
1194
1195 done = true;
1196 }
1197 }
1198 }
1199
1200 /* free temp data */
1201 ANIM_animdata_freelist(&anim_data);
1202
1203 if (done) {
1204 /* refresh auto strip properties */
1206
1207 if (!linked) {
1209 }
1210
1211 /* set notifier that things have changed */
1213
1214 /* done */
1215 return OPERATOR_FINISHED;
1216 }
1217
1218 return OPERATOR_CANCELLED;
1219}
1220
1221static int nlaedit_duplicate_invoke(bContext *C, wmOperator *op, const wmEvent * /*event*/)
1222{
1224
1225 return OPERATOR_FINISHED;
1226}
1227
1229{
1230 /* identifiers */
1231 ot->name = "Duplicate Strips";
1232 ot->idname = "NLA_OT_duplicate";
1233 ot->description = "Duplicate selected NLA-Strips, adding the new strips to new track(s)";
1234
1235 /* api callbacks */
1239
1240 /* flags */
1242
1243 /* own properties */
1245 "linked",
1246 false,
1247 "Linked",
1248 "When duplicating strips, assign new copies of the actions they use");
1249}
1250
1253/* -------------------------------------------------------------------- */
1260{
1261 bAnimContext ac;
1262
1263 ListBase anim_data = {nullptr, nullptr};
1264
1265 /* get editor data */
1266 if (ANIM_animdata_get_context(C, &ac) == 0) {
1267 return OPERATOR_CANCELLED;
1268 }
1269
1270 /* get a list of the editable tracks being shown in the NLA */
1273 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, eAnimCont_Types(ac.datatype));
1274
1275 /* for each NLA-Track, delete all selected strips */
1276 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
1277 NlaTrack *nlt = static_cast<NlaTrack *>(ale->data);
1278 NlaStrip *strip, *nstrip;
1279
1280 if (BKE_nlatrack_is_nonlocal_in_liboverride(ale->id, nlt)) {
1281 /* No deletion of strips in non-local tracks of override data. */
1282 continue;
1283 }
1284
1285 for (strip = static_cast<NlaStrip *>(nlt->strips.first); strip; strip = nstrip) {
1286 nstrip = strip->next;
1287
1288 /* if selected, delete */
1289 if (strip->flag & NLASTRIP_FLAG_SELECT) {
1290 /* Fix for #109430. Defensively exit tweak mode before deleting
1291 * the active strip. */
1292 if (ale->adt && ale->adt->actstrip == strip) {
1293 BKE_nla_tweakmode_exit({*ale->id, *ale->adt});
1294 }
1295
1296 /* if a strip either side of this was a transition, delete those too */
1297 if ((strip->prev) && (strip->prev->type == NLASTRIP_TYPE_TRANSITION)) {
1298 BKE_nlastrip_remove_and_free(&nlt->strips, strip->prev, true);
1299 }
1300 if ((nstrip) && (nstrip->type == NLASTRIP_TYPE_TRANSITION)) {
1301 nstrip = nstrip->next;
1302 BKE_nlastrip_remove_and_free(&nlt->strips, strip->next, true);
1303 }
1304
1305 /* finally, delete this strip */
1306 BKE_nlastrip_remove_and_free(&nlt->strips, strip, true);
1307 }
1308 }
1309 }
1310
1311 /* free temp data */
1312 ANIM_animdata_freelist(&anim_data);
1313
1314 /* refresh auto strip properties */
1316
1318
1319 /* set notifier that things have changed */
1321
1322 /* done */
1323 return OPERATOR_FINISHED;
1324}
1325
1327{
1328 /* identifiers */
1329 ot->name = "Delete Strips";
1330 ot->idname = "NLA_OT_delete";
1331 ot->description = "Delete selected strips";
1332
1333 /* api callbacks */
1336
1337 /* flags */
1339}
1340
1343/* -------------------------------------------------------------------- */
1353/* split a given Action-Clip strip */
1355 Main *bmain, AnimData *adt, NlaTrack *nlt, NlaStrip *strip, float cfra)
1356{
1357 NlaStrip *nstrip;
1358 float splitframe, splitaframe;
1359
1360 /* calculate the frames to do the splitting at
1361 * - use current frame if within extents of strip
1362 */
1363 if ((cfra > strip->start) && (cfra < strip->end)) {
1364 /* use the current frame */
1365 splitframe = cfra;
1366 splitaframe = nlastrip_get_frame(strip, cfra, NLATIME_CONVERT_UNMAP);
1367 }
1368 else {
1369 /* split in the middle */
1370 float len;
1371
1372 /* strip extents */
1373 len = strip->end - strip->start;
1374 if (IS_EQF(len, 0.0f)) {
1375 return;
1376 }
1377
1378 splitframe = strip->start + (len / 2.0f);
1379
1380 /* action range */
1381 len = strip->actend - strip->actstart;
1382 if (IS_EQF(len, 0.0f)) {
1383 splitaframe = strip->actend;
1384 }
1385 else {
1386 splitaframe = strip->actstart + (len / 2.0f);
1387 }
1388 }
1389
1390 /* make a copy (assume that this is possible) and append
1391 * it immediately after the current strip
1392 */
1393 nstrip = BKE_nlastrip_copy(bmain, strip, true, 0);
1394 BLI_insertlinkafter(&nlt->strips, strip, nstrip);
1395
1396 /* Set the endpoint of the first strip and the start of the new strip
1397 * to the split-frame values calculated above.
1398 */
1399 strip->end = splitframe;
1400 nstrip->start = splitframe;
1401
1402 if ((splitaframe > strip->actstart) && (splitaframe < strip->actend)) {
1403 /* only do this if we're splitting down the middle... */
1404 strip->actend = splitaframe;
1405 nstrip->actstart = splitaframe;
1406 }
1407
1408 /* Make sure Sync Length is off. With that setting on, entering and exiting tweak mode would
1409 * effectively undo the split, because both the old and the new strip will be at the length of
1410 * the Action again. */
1411 strip->flag &= ~NLASTRIP_FLAG_SYNC_LENGTH;
1413
1414 /* auto-name the new strip */
1415 BKE_nlastrip_validate_name(adt, nstrip);
1416}
1417
1418/* split a given Meta strip */
1420{
1421 /* simply ungroup it for now... */
1423}
1424
1425/* ----- */
1426
1428{
1429 bAnimContext ac;
1430
1431 ListBase anim_data = {nullptr, nullptr};
1432
1433 /* get editor data */
1434 if (ANIM_animdata_get_context(C, &ac) == 0) {
1435 return OPERATOR_CANCELLED;
1436 }
1437
1438 /* get a list of editable tracks being shown in the NLA */
1441 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, eAnimCont_Types(ac.datatype));
1442
1443 /* for each NLA-Track, split all selected strips into two strips */
1444 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
1445 NlaTrack *nlt = static_cast<NlaTrack *>(ale->data);
1446 AnimData *adt = ale->adt;
1447 NlaStrip *strip, *next;
1448
1449 if (BKE_nlatrack_is_nonlocal_in_liboverride(ale->id, nlt)) {
1450 /* No splitting of strips in non-local tracks of override data. */
1451 continue;
1452 }
1453
1454 for (strip = static_cast<NlaStrip *>(nlt->strips.first); strip; strip = next) {
1455 next = strip->next;
1456
1457 /* if selected, split the strip at its midpoint */
1458 if (strip->flag & NLASTRIP_FLAG_SELECT) {
1459 /* splitting method depends on the type of strip */
1460 switch (strip->type) {
1461 case NLASTRIP_TYPE_CLIP: /* action-clip */
1462 nlaedit_split_strip_actclip(ac.bmain, adt, nlt, strip, float(ac.scene->r.cfra));
1463 break;
1464
1465 case NLASTRIP_TYPE_META: /* meta-strips need special handling */
1466 nlaedit_split_strip_meta(nlt, strip);
1467 break;
1468
1469 default: /* for things like Transitions, do not split! */
1470 break;
1471 }
1472 }
1473 }
1474 }
1475
1476 /* free temp data */
1477 ANIM_animdata_freelist(&anim_data);
1478
1479 /* refresh auto strip properties */
1481
1482 /* set notifier that things have changed */
1484
1485 /* done */
1486 return OPERATOR_FINISHED;
1487}
1488
1490{
1491 /* identifiers */
1492 ot->name = "Split Strips";
1493 ot->idname = "NLA_OT_split";
1494 ot->description = "Split selected strips at their midpoints";
1495
1496 /* api callbacks */
1499
1500 /* flags */
1502}
1503
1506/* NLA Editing Operations (Modifying) */
1507
1508/* -------------------------------------------------------------------- */
1515{
1516 bAnimContext ac;
1517
1518 ListBase anim_data = {nullptr, nullptr};
1519
1520 /* get editor data */
1521 if (ANIM_animdata_get_context(C, &ac) == 0) {
1522 return OPERATOR_CANCELLED;
1523 }
1524
1525 /* get a list of the editable tracks being shown in the NLA */
1528 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, eAnimCont_Types(ac.datatype));
1529
1530 /* go over all selected strips */
1531 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
1532 NlaTrack *nlt = static_cast<NlaTrack *>(ale->data);
1533
1534 /* For every selected strip, toggle muting. */
1535 LISTBASE_FOREACH (NlaStrip *, strip, &nlt->strips) {
1536 if (strip->flag & NLASTRIP_FLAG_SELECT) {
1537 /* just flip the mute flag for now */
1538 /* TODO: have a pre-pass to check if mute all or unmute all? */
1539 strip->flag ^= NLASTRIP_FLAG_MUTED;
1540
1541 /* tag AnimData to get recalculated */
1542 ale->update |= ANIM_UPDATE_DEPS;
1543 }
1544 }
1545 }
1546
1547 /* cleanup */
1548 ANIM_animdata_update(&ac, &anim_data);
1549 ANIM_animdata_freelist(&anim_data);
1550
1551 /* set notifier that things have changed */
1553
1554 /* done */
1555 return OPERATOR_FINISHED;
1556}
1557
1559{
1560 /* identifiers */
1561 ot->name = "Toggle Muting";
1562 ot->idname = "NLA_OT_mute_toggle";
1563 ot->description = "Mute or un-mute selected strips";
1564
1565 /* api callbacks */
1568
1569 /* flags */
1571}
1572
1575/* -------------------------------------------------------------------- */
1582{
1583 bAnimContext ac;
1584
1585 ListBase anim_data = {nullptr, nullptr};
1586
1587 /* get editor data */
1588 if (ANIM_animdata_get_context(C, &ac) == 0) {
1589 return OPERATOR_CANCELLED;
1590 }
1591
1592 /* get a list of the editable tracks being shown in the NLA */
1595 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, eAnimCont_Types(ac.datatype));
1596
1597 /* consider each track in turn */
1598 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
1599 NlaTrack *nlt = static_cast<NlaTrack *>(ale->data);
1600
1601 NlaStrip *strip, *stripN = nullptr;
1602 NlaStrip *area = nullptr, *sb = nullptr;
1603 const bool is_liboverride = ID_IS_OVERRIDE_LIBRARY(ale->id);
1604
1605 if (BKE_nlatrack_is_nonlocal_in_liboverride(ale->id, nlt)) {
1606 /* No re-ordering of strips within non-local tracks of override data. */
1607 continue;
1608 }
1609
1610 /* Make temporary meta-strips so that entire islands of selections can be moved around. */
1611 BKE_nlastrips_make_metas(&nlt->strips, true);
1612
1613 /* special case: if there is only 1 island
1614 * (i.e. temp meta BUT NOT unselected/normal/normal-meta strips) left after this,
1615 * and this island has two strips inside it, then we should be able to just swap these still...
1616 */
1617 if (BLI_listbase_is_empty(&nlt->strips) == false) {
1618 NlaStrip *mstrip = static_cast<NlaStrip *>(nlt->strips.first);
1619
1620 if ((mstrip->flag & NLASTRIP_FLAG_TEMP_META) &&
1622 {
1623 /* remove this temp meta, so that we can see the strips inside */
1624 BKE_nlastrips_clear_metas(&nlt->strips, false, true);
1625 }
1626 }
1627
1628 /* get two selected strips only (these will be metas due to prev step) to operate on
1629 * - only allow swapping 2, as with more the context becomes unclear
1630 */
1631 for (strip = static_cast<NlaStrip *>(nlt->strips.first); strip; strip = stripN) {
1632 stripN = strip->next;
1633
1634 if (strip->flag & NLASTRIP_FLAG_SELECT) {
1635 /* first or second strip? */
1636 if (area == nullptr) {
1637 /* store as first */
1638 area = strip;
1639 }
1640 else if (sb == nullptr) {
1641 /* store as second */
1642 sb = strip;
1643 }
1644 else {
1645 /* too many selected */
1646 break;
1647 }
1648 }
1649 }
1650
1651 if (strip) {
1652 /* too many selected warning */
1654 op->reports,
1656 "Too many clusters of strips selected in NLA Track (%s): needs exactly 2 to be selected",
1657 nlt->name);
1658 }
1659 else if (area == nullptr) {
1660 /* no warning as this is just a common case,
1661 * and it may get annoying when doing multiple tracks */
1662 }
1663 else if (sb == nullptr) {
1664 /* too few selected warning */
1666 op->reports,
1668 "Too few clusters of strips selected in NLA Track (%s): needs exactly 2 to be selected",
1669 nlt->name);
1670 }
1671 else {
1672 float nsa[2], nsb[2];
1673
1674 /* remove these strips from the track,
1675 * so that we can test if they can fit in the proposed places */
1676 BLI_remlink(&nlt->strips, area);
1677 BLI_remlink(&nlt->strips, sb);
1678
1679 /* calculate new extents for strips */
1680 /* a --> b */
1681 nsa[0] = sb->start;
1682 nsa[1] = sb->start + (area->end - area->start);
1683 /* b --> a */
1684 nsb[0] = area->start;
1685 nsb[1] = area->start + (sb->end - sb->start);
1686
1687 /* check if the track has room for the strips to be swapped */
1688 if (BKE_nlastrips_has_space(&nlt->strips, nsa[0], nsa[1]) &&
1689 BKE_nlastrips_has_space(&nlt->strips, nsb[0], nsb[1]) && (nsb[1] <= nsa[0]))
1690 {
1691 /* set new extents for strips then */
1692 area->start = nsa[0];
1693 area->end = nsa[1];
1695
1696 sb->start = nsb[0];
1697 sb->end = nsb[1];
1699 }
1700 else {
1701 /* not enough room to swap, so show message */
1702 if (nsb[1] > nsa[0]) {
1703 BKE_report(op->reports,
1705 "Cannot swap selected strips because they will overlap each other in their "
1706 "new places");
1707 }
1708 else if ((area->flag & NLASTRIP_FLAG_TEMP_META) || (sb->flag & NLASTRIP_FLAG_TEMP_META)) {
1709 BKE_report(
1710 op->reports,
1712 "Cannot swap selected strips as they will not be able to fit in their new places");
1713 }
1714 else {
1715 BKE_reportf(op->reports,
1717 "Cannot swap '%s' and '%s' as one or both will not be able to fit in their "
1718 "new places",
1719 area->name,
1720 sb->name);
1721 }
1722 }
1723
1724 /* add strips back to track now */
1725 BKE_nlatrack_add_strip(nlt, area, is_liboverride);
1726 BKE_nlatrack_add_strip(nlt, sb, is_liboverride);
1727 }
1728
1729 /* Clear (temp) meta-strips. */
1730 BKE_nlastrips_clear_metas(&nlt->strips, false, true);
1731 }
1732
1733 /* free temp data */
1734 ANIM_animdata_freelist(&anim_data);
1735
1736 /* refresh auto strip properties */
1738
1739 /* set notifier that things have changed */
1742
1743 /* done */
1744 return OPERATOR_FINISHED;
1745}
1746
1748{
1749 /* identifiers */
1750 ot->name = "Swap Strips";
1751 ot->idname = "NLA_OT_swap";
1752 ot->description = "Swap order of selected strips within tracks";
1753
1754 /* api callbacks */
1757
1758 /* flags */
1760}
1761
1764/* -------------------------------------------------------------------- */
1771{
1772 bAnimContext ac;
1773
1774 ListBase anim_data = {nullptr, nullptr};
1775
1776 /* get editor data */
1777 if (ANIM_animdata_get_context(C, &ac) == 0) {
1778 return OPERATOR_CANCELLED;
1779 }
1780
1781 /* get a list of the editable tracks being shown in the NLA */
1784 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, eAnimCont_Types(ac.datatype));
1785
1786 /* since we're potentially moving strips from lower tracks to higher tracks, we should
1787 * loop over the tracks in reverse order to avoid moving earlier strips up multiple tracks
1788 */
1789 LISTBASE_FOREACH_BACKWARD (bAnimListElem *, ale, &anim_data) {
1790 NlaTrack *nlt = static_cast<NlaTrack *>(ale->data);
1791 NlaTrack *nltn = nlt->next;
1792 NlaStrip *stripn;
1793
1794 const bool is_liboverride = ID_IS_OVERRIDE_LIBRARY(ale->id);
1795
1796 /* if this track has no tracks after it, skip for now... */
1797 if (nltn == nullptr) {
1798 continue;
1799 }
1800
1801 if (BKE_nlatrack_is_nonlocal_in_liboverride(ale->id, nlt) ||
1803 {
1804 /* No moving of strips in non-local tracks of override data. */
1805 continue;
1806 }
1807
1808 /* for every selected strip, try to move */
1809 for (NlaStrip *strip = static_cast<NlaStrip *>(nlt->strips.first); strip; strip = stripn) {
1810 stripn = strip->next;
1811
1812 if (strip->flag & NLASTRIP_FLAG_SELECT) {
1813 /* check if the track above has room for this strip */
1814 if (BKE_nlatrack_has_space(nltn, strip->start, strip->end)) {
1815 /* remove from its current track, and add to the one above
1816 * (it 'should' work, so no need to worry) */
1817 BKE_nlatrack_remove_strip(nlt, strip);
1818 BKE_nlatrack_add_strip(nltn, strip, is_liboverride);
1819 }
1820 }
1821 }
1822 }
1823
1824 /* free temp data */
1825 ANIM_animdata_freelist(&anim_data);
1826
1827 /* refresh auto strip properties */
1829
1830 /* set notifier that things have changed */
1833
1834 /* done */
1835 return OPERATOR_FINISHED;
1836}
1837
1839{
1840 /* identifiers */
1841 ot->name = "Move Strips Up";
1842 ot->idname = "NLA_OT_move_up";
1843 ot->description = "Move selected strips up a track if there's room";
1844
1845 /* api callbacks */
1848
1849 /* flags */
1851}
1852
1855/* -------------------------------------------------------------------- */
1862{
1863 bAnimContext ac;
1864
1865 ListBase anim_data = {nullptr, nullptr};
1866
1867 /* get editor data */
1868 if (ANIM_animdata_get_context(C, &ac) == 0) {
1869 return OPERATOR_CANCELLED;
1870 }
1871
1872 /* get a list of the editable tracks being shown in the NLA */
1875 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, eAnimCont_Types(ac.datatype));
1876
1877 /* loop through the tracks in normal order, since we're pushing strips down,
1878 * strips won't get operated on twice
1879 */
1880 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
1881 NlaTrack *nlt = static_cast<NlaTrack *>(ale->data);
1882 NlaTrack *nltp = nlt->prev;
1883 NlaStrip *stripn;
1884
1885 const bool is_liboverride = ID_IS_OVERRIDE_LIBRARY(ale->id);
1886
1887 /* if this track has no tracks before it, skip for now... */
1888 if (nltp == nullptr) {
1889 continue;
1890 }
1891
1892 if (BKE_nlatrack_is_nonlocal_in_liboverride(ale->id, nlt) ||
1894 {
1895 /* No moving of strips in non-local tracks of override data. */
1896 continue;
1897 }
1898
1899 /* for every selected strip, try to move */
1900 for (NlaStrip *strip = static_cast<NlaStrip *>(nlt->strips.first); strip; strip = stripn) {
1901 stripn = strip->next;
1902
1903 if (strip->flag & NLASTRIP_FLAG_SELECT) {
1904 /* check if the track below has room for this strip */
1905 if (BKE_nlatrack_has_space(nltp, strip->start, strip->end)) {
1906 /* remove from its current track, and add to the one above
1907 * (it 'should' work, so no need to worry) */
1908 BKE_nlatrack_remove_strip(nlt, strip);
1909 BKE_nlatrack_add_strip(nltp, strip, is_liboverride);
1910 }
1911 }
1912 }
1913 }
1914
1915 /* free temp data */
1916 ANIM_animdata_freelist(&anim_data);
1917
1918 /* refresh auto strip properties */
1920
1921 /* set notifier that things have changed */
1924
1925 /* done */
1926 return OPERATOR_FINISHED;
1927}
1928
1930{
1931 /* identifiers */
1932 ot->name = "Move Strips Down";
1933 ot->idname = "NLA_OT_move_down";
1934 ot->description = "Move selected strips down a track if there's room";
1935
1936 /* api callbacks */
1939
1940 /* flags */
1942}
1943
1946/* -------------------------------------------------------------------- */
1953{
1954 bAnimContext ac;
1955
1956 ListBase anim_data = {nullptr, nullptr};
1957 const bool active_only = RNA_boolean_get(op->ptr, "active");
1958
1959 /* get editor data */
1960 if (ANIM_animdata_get_context(C, &ac) == 0) {
1961 return OPERATOR_CANCELLED;
1962 }
1963
1964 /* get a list of the editable tracks being shown in the NLA */
1967 if (active_only) {
1968 filter |= ANIMFILTER_ACTIVE;
1969 }
1970 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, eAnimCont_Types(ac.datatype));
1971
1972 /* for each NLA-Track, apply scale of all selected strips */
1973 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
1974 NlaTrack *nlt = static_cast<NlaTrack *>(ale->data);
1975
1976 LISTBASE_FOREACH (NlaStrip *, strip, &nlt->strips) {
1977 /* strip selection/active status check */
1978 if (active_only) {
1979 if ((strip->flag & NLASTRIP_FLAG_ACTIVE) == 0) {
1980 continue;
1981 }
1982 }
1983 else {
1984 if ((strip->flag & NLASTRIP_FLAG_SELECT) == 0) {
1985 continue;
1986 }
1987 }
1988
1989 /* must be action-clip only (transitions don't have scale) */
1990 if (strip->type == NLASTRIP_TYPE_CLIP) {
1991 if (strip->act == nullptr) {
1992 continue;
1993 }
1994
1996
1997 ale->update |= ANIM_UPDATE_DEPS;
1998 }
1999 }
2000 }
2001
2002 /* free temp data */
2003 ANIM_animdata_update(&ac, &anim_data);
2004 ANIM_animdata_freelist(&anim_data);
2005
2006 /* set notifier that things have changed */
2008
2009 /* done */
2010 return OPERATOR_FINISHED;
2011}
2012
2014{
2015 /* identifiers */
2016 ot->name = "Sync Action Length";
2017 ot->idname = "NLA_OT_action_sync_length";
2018 ot->description =
2019 "Synchronize the length of the referenced Action with the length used in the strip";
2020
2021 /* api callbacks */
2024
2025 /* flags */
2027
2028 /* properties */
2030 "active",
2031 true,
2032 "Active Strip Only",
2033 "Only sync the active length for the active strip");
2034}
2035
2038/* -------------------------------------------------------------------- */
2045{
2046 Main *bmain = CTX_data_main(C);
2047 bAnimContext ac;
2048
2049 ListBase anim_data = {nullptr, nullptr};
2050 bool copied = false;
2051
2052 /* get editor data */
2053 if (ANIM_animdata_get_context(C, &ac) == 0) {
2054 return OPERATOR_CANCELLED;
2055 }
2056
2057 /* get a list of the editable tracks being shown in the NLA */
2060 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, eAnimCont_Types(ac.datatype));
2061
2062 /* Ensure that each action used only has a single user
2063 * - This is done in reverse order so that the original strips are
2064 * likely to still get to keep their action
2065 */
2066 LISTBASE_FOREACH_BACKWARD (bAnimListElem *, ale, &anim_data) {
2067 NlaTrack *nlt = static_cast<NlaTrack *>(ale->data);
2068
2069 LISTBASE_FOREACH_BACKWARD (NlaStrip *, strip, &nlt->strips) {
2070 /* must be action-clip only (as only these have actions) */
2071 if ((strip->flag & NLASTRIP_FLAG_SELECT) && (strip->type == NLASTRIP_TYPE_CLIP)) {
2072 if (strip->act == nullptr) {
2073 continue;
2074 }
2075
2076 /* multi-user? */
2077 if (ID_REAL_USERS(strip->act) > 1) {
2078 /* make a new copy of the action for us to use (it will have 1 user already) */
2079 bAction *new_action = reinterpret_cast<bAction *>(BKE_id_copy(bmain, &strip->act->id));
2080
2081 /* decrement user count of our existing action */
2082 id_us_min(&strip->act->id);
2083
2084 /* switch to the new copy */
2085 strip->act = new_action;
2086
2087 ale->update |= ANIM_UPDATE_DEPS;
2088 copied = true;
2089 }
2090 }
2091 }
2092 }
2093
2094 /* free temp data */
2095 ANIM_animdata_update(&ac, &anim_data);
2096 ANIM_animdata_freelist(&anim_data);
2097
2098 if (copied) {
2100 }
2101
2102 /* set notifier that things have changed */
2104
2105 /* done */
2106 return OPERATOR_FINISHED;
2107}
2108
2109static int nlaedit_make_single_user_invoke(bContext *C, wmOperator *op, const wmEvent * /*event*/)
2110{
2111 if (RNA_boolean_get(op->ptr, "confirm")) {
2113 C,
2114 op,
2115 IFACE_("Make Selected Strips Single-User"),
2116 IFACE_("Linked actions will be duplicated for each selected strip."),
2117 IFACE_("Make Single"),
2119 false);
2120 }
2121 return nlaedit_make_single_user_exec(C, op);
2122}
2123
2125{
2126 /* identifiers */
2127 ot->name = "Make Single User";
2128 ot->idname = "NLA_OT_make_single_user";
2129 ot->description = "Make linked action local to each strip";
2130
2131 /* api callbacks */
2135
2136 /* flags */
2139}
2140
2143/* -------------------------------------------------------------------- */
2149/* apply scaling to keyframe */
2151{
2152 /* NLA-strip which has this scaling is stored in ked->data */
2153 NlaStrip *strip = static_cast<NlaStrip *>(ked->data);
2154
2155 /* adjust all the times */
2156 bezt->vec[0][0] = nlastrip_get_frame(strip, bezt->vec[0][0], NLATIME_CONVERT_MAP);
2157 bezt->vec[1][0] = nlastrip_get_frame(strip, bezt->vec[1][0], NLATIME_CONVERT_MAP);
2158 bezt->vec[2][0] = nlastrip_get_frame(strip, bezt->vec[2][0], NLATIME_CONVERT_MAP);
2159
2160 /* nothing to return or else we exit */
2161 return 0;
2162}
2163
2165{
2166 Main *bmain = CTX_data_main(C);
2167 bAnimContext ac;
2168
2169 ListBase anim_data = {nullptr, nullptr};
2170 bool copied = false;
2171
2172 KeyframeEditData ked = {{nullptr}};
2173
2174 /* get editor data */
2175 if (ANIM_animdata_get_context(C, &ac) == 0) {
2176 return OPERATOR_CANCELLED;
2177 }
2178
2179 /* get a list of the editable tracks being shown in the NLA */
2182 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, eAnimCont_Types(ac.datatype));
2183
2184 /* for each NLA-Track, apply scale of all selected strips */
2185 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
2186 NlaTrack *nlt = static_cast<NlaTrack *>(ale->data);
2187
2188 LISTBASE_FOREACH (NlaStrip *, strip, &nlt->strips) {
2189 /* strip must be selected, and must be action-clip only
2190 * (transitions don't have scale) */
2191 if ((strip->flag & NLASTRIP_FLAG_SELECT) && (strip->type == NLASTRIP_TYPE_CLIP)) {
2192 if (strip->act == nullptr || ID_IS_OVERRIDE_LIBRARY(strip->act) ||
2193 !ID_IS_EDITABLE(strip->act))
2194 {
2195 continue;
2196 }
2197 /* if the referenced action is used by other strips,
2198 * make this strip use its own copy */
2199 if (strip->act->id.us > 1) {
2200 /* make a copy of the Action to work on */
2201 bAction *act = reinterpret_cast<bAction *>(BKE_id_copy(bmain, &strip->act->id));
2202
2203 /* set this as the new referenced action,
2204 * decrementing the users of the old one */
2205 id_us_min(&strip->act->id);
2206 strip->act = act;
2207
2208 copied = true;
2209 }
2210
2211 /* setup iterator, and iterate over all the keyframes in the action,
2212 * applying this scaling */
2213 ked.data = strip;
2215 ac.ads,
2216 strip->act,
2217 ALE_ACT,
2218 nullptr,
2221
2222 /* clear scale of strip now that it has been applied,
2223 * and recalculate the extents of the action now that it has been scaled
2224 * but leave everything else alone
2225 */
2226 const float start = nlastrip_get_frame(strip, strip->actstart, NLATIME_CONVERT_MAP);
2227 const float end = nlastrip_get_frame(strip, strip->actend, NLATIME_CONVERT_MAP);
2228
2229 if (strip->act->flag & ACT_FRAME_RANGE) {
2230 strip->act->frame_start = nlastrip_get_frame(
2231 strip, strip->act->frame_start, NLATIME_CONVERT_MAP);
2232 strip->act->frame_end = nlastrip_get_frame(
2233 strip, strip->act->frame_end, NLATIME_CONVERT_MAP);
2234 }
2235
2236 strip->scale = 1.0f;
2237 strip->actstart = start;
2238 strip->actend = end;
2239
2240 ale->update |= ANIM_UPDATE_DEPS;
2241 }
2242 }
2243 }
2244
2245 /* free temp data */
2246 ANIM_animdata_update(&ac, &anim_data);
2247 ANIM_animdata_freelist(&anim_data);
2248
2249 if (copied) {
2251 }
2252
2253 /* set notifier that things have changed */
2255
2256 /* done */
2257 return OPERATOR_FINISHED;
2258}
2259
2261{
2262 /* identifiers */
2263 ot->name = "Apply Scale";
2264 ot->idname = "NLA_OT_apply_scale";
2265 ot->description = "Apply scaling of selected strips to their referenced Actions";
2266
2267 /* api callbacks */
2270
2271 /* flags */
2273}
2274
2277/* -------------------------------------------------------------------- */
2284{
2285 bAnimContext ac;
2286
2287 ListBase anim_data = {nullptr, nullptr};
2288
2289 /* get editor data */
2290 if (ANIM_animdata_get_context(C, &ac) == 0) {
2291 return OPERATOR_CANCELLED;
2292 }
2293
2294 /* get a list of the editable tracks being shown in the NLA */
2297 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, eAnimCont_Types(ac.datatype));
2298
2299 /* for each NLA-Track, reset scale of all selected strips */
2300 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
2301 NlaTrack *nlt = static_cast<NlaTrack *>(ale->data);
2302
2303 LISTBASE_FOREACH (NlaStrip *, strip, &nlt->strips) {
2304 /* strip must be selected, and must be action-clip only
2305 * (transitions don't have scale) */
2306 if ((strip->flag & NLASTRIP_FLAG_SELECT) && (strip->type == NLASTRIP_TYPE_CLIP)) {
2307 PointerRNA strip_ptr = RNA_pointer_create(nullptr, &RNA_NlaStrip, strip);
2308 RNA_float_set(&strip_ptr, "scale", 1.0f);
2309 }
2310 }
2311 }
2312
2313 /* free temp data */
2314 ANIM_animdata_freelist(&anim_data);
2315
2316 /* refresh auto strip properties */
2318
2319 /* set notifier that things have changed */
2321
2322 /* done */
2323 return OPERATOR_FINISHED;
2324}
2325
2327{
2328 /* identifiers */
2329 ot->name = "Clear Scale";
2330 ot->idname = "NLA_OT_clear_scale";
2331 ot->description = "Reset scaling of selected strips";
2332
2333 /* api callbacks */
2336
2337 /* flags */
2339}
2340
2343/* -------------------------------------------------------------------- */
2349/* defines for snap keyframes tool */
2351 {NLAEDIT_SNAP_CFRA, "CFRA", 0, "Selection to Current Frame", ""},
2352 /* XXX as single entry? */
2353 {NLAEDIT_SNAP_NEAREST_FRAME, "NEAREST_FRAME", 0, "Selection to Nearest Frame", ""},
2354 /* XXX as single entry? */
2355 {NLAEDIT_SNAP_NEAREST_SECOND, "NEAREST_SECOND", 0, "Selection to Nearest Second", ""},
2356 {NLAEDIT_SNAP_NEAREST_MARKER, "NEAREST_MARKER", 0, "Selection to Nearest Marker", ""},
2357 {0, nullptr, 0, nullptr, nullptr},
2358};
2359
2361{
2362 bAnimContext ac;
2363
2364 ListBase anim_data = {nullptr, nullptr};
2365
2366 Scene *scene;
2367 int mode = RNA_enum_get(op->ptr, "type");
2368 float secf;
2369
2370 /* get editor data */
2371 if (ANIM_animdata_get_context(C, &ac) == 0) {
2372 return OPERATOR_CANCELLED;
2373 }
2374
2375 /* get a list of the editable tracks being shown in the NLA */
2378 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, eAnimCont_Types(ac.datatype));
2379
2380 /* get some necessary vars */
2381 scene = ac.scene;
2382 secf = float(FPS);
2383
2384 bool any_added = false;
2385
2386 /* since we may add tracks, perform this in reverse order */
2387 LISTBASE_FOREACH_BACKWARD (bAnimListElem *, ale, &anim_data) {
2388 ListBase tmp_strips = {nullptr, nullptr};
2389 AnimData *adt = ale->adt;
2390 NlaTrack *nlt = static_cast<NlaTrack *>(ale->data);
2391 NlaStrip *stripn;
2392 NlaTrack *track;
2393
2394 const bool is_liboverride = ID_IS_OVERRIDE_LIBRARY(ale->id);
2395
2396 /* create meta-strips from the continuous chains of selected strips */
2397 BKE_nlastrips_make_metas(&nlt->strips, true);
2398
2399 /* apply the snapping to all the temp meta-strips, then put them in a separate list to be added
2400 * back to the original only if they still fit
2401 */
2402 for (NlaStrip *strip = static_cast<NlaStrip *>(nlt->strips.first); strip; strip = stripn) {
2403 stripn = strip->next;
2404
2405 if (strip->flag & NLASTRIP_FLAG_TEMP_META) {
2406 float start, end;
2407
2408 /* get the existing end-points */
2409 start = strip->start;
2410 end = strip->end;
2411
2412 /* calculate new start position based on snapping mode */
2413 switch (mode) {
2414 case NLAEDIT_SNAP_CFRA: /* to current frame */
2415 strip->start = float(scene->r.cfra);
2416 break;
2417 case NLAEDIT_SNAP_NEAREST_FRAME: /* to nearest frame */
2418 strip->start = floorf(start + 0.5f);
2419 break;
2420 case NLAEDIT_SNAP_NEAREST_SECOND: /* to nearest second */
2421 strip->start = floorf(start / secf + 0.5f) * secf;
2422 break;
2423 case NLAEDIT_SNAP_NEAREST_MARKER: /* to nearest marker */
2424 strip->start = float(ED_markers_find_nearest_marker_time(ac.markers, start));
2425 break;
2426 default: /* just in case... no snapping */
2427 strip->start = start;
2428 break;
2429 }
2430
2431 /* get new endpoint based on start-point (and old length) */
2432 strip->end = strip->start + (end - start);
2433
2434 /* apply transforms to meta-strip to its children */
2436
2437 /* remove strip from track, and add to the temp buffer */
2438 BLI_remlink(&nlt->strips, strip);
2439 BLI_addtail(&tmp_strips, strip);
2440 }
2441 }
2442
2443 /* try adding each meta-strip back to the track one at a time, to make sure they'll fit */
2444 for (NlaStrip *strip = static_cast<NlaStrip *>(tmp_strips.first); strip; strip = stripn) {
2445 stripn = strip->next;
2446
2447 /* remove from temp-strips list */
2448 BLI_remlink(&tmp_strips, strip);
2449
2450 /* in case there's no space in the current track, try adding */
2451 if (BKE_nlatrack_add_strip(nlt, strip, is_liboverride) == 0) {
2452 /* need to add a new track above the current one */
2453 track = BKE_nlatrack_new_after(&adt->nla_tracks, nlt, is_liboverride);
2454 BKE_nlatrack_set_active(&adt->nla_tracks, track);
2455 BKE_nlatrack_add_strip(track, strip, is_liboverride);
2456
2457 /* clear temp meta-strips on this new track,
2458 * as we may not be able to get back to it */
2459 BKE_nlastrips_clear_metas(&track->strips, false, true);
2460
2461 any_added = true;
2462 }
2463 }
2464
2465 /* remove the meta-strips now that we're done */
2466 BKE_nlastrips_clear_metas(&nlt->strips, false, true);
2467
2468 /* tag for recalculating the animation */
2469 ale->update |= ANIM_UPDATE_DEPS;
2470 }
2471
2472 /* cleanup */
2473 ANIM_animdata_update(&ac, &anim_data);
2474 ANIM_animdata_freelist(&anim_data);
2475
2476 /* refresh auto strip properties */
2478
2479 /* set notifier that things have changed */
2481 if (any_added) {
2483 }
2484
2485 /* done */
2486 return OPERATOR_FINISHED;
2487}
2488
2490{
2491 /* identifiers */
2492 ot->name = "Snap Strips";
2493 ot->idname = "NLA_OT_snap";
2494 ot->description = "Move start of strips to specified time";
2495
2496 /* api callbacks */
2500
2501 /* flags */
2503
2504 /* properties */
2505 ot->prop = RNA_def_enum(ot->srna, "type", prop_nlaedit_snap_types, 0, "Type", "");
2506}
2507
2510/* NLA Modifiers */
2511
2512/* -------------------------------------------------------------------- */
2517 PointerRNA * /*ptr*/,
2518 PropertyRNA * /*prop*/,
2519 bool *r_free)
2520{
2521 EnumPropertyItem *item = nullptr;
2522 int totitem = 0;
2523 int i = 0;
2524
2525 if (C == nullptr) {
2527 }
2528
2529 /* start from 1 to skip the 'Invalid' modifier type */
2530 for (i = 1; i < FMODIFIER_NUM_TYPES; i++) {
2532 int index;
2533
2534 /* check if modifier is valid for this context */
2535 if (fmi == nullptr) {
2536 continue;
2537 }
2538 if (i == FMODIFIER_TYPE_CYCLES) { /* we already have repeat... */
2539 continue;
2540 }
2541
2543 if (index != -1) { /* Not all types are implemented yet... */
2544 RNA_enum_item_add(&item, &totitem, &rna_enum_fmodifier_type_items[index]);
2545 }
2546 }
2547
2548 RNA_enum_item_end(&item, &totitem);
2549 *r_free = true;
2550
2551 return item;
2552}
2553
2555{
2556 bAnimContext ac;
2557
2558 ListBase anim_data = {nullptr, nullptr};
2559
2560 FModifier *fcm;
2561 int type = RNA_enum_get(op->ptr, "type");
2562 const bool active_only = RNA_boolean_get(op->ptr, "only_active");
2563
2564 /* get editor data */
2565 if (ANIM_animdata_get_context(C, &ac) == 0) {
2566 return OPERATOR_CANCELLED;
2567 }
2568
2569 /* get a list of the editable tracks being shown in the NLA */
2572 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, eAnimCont_Types(ac.datatype));
2573
2574 /* for each NLA-Track, add the specified modifier to all selected strips */
2575 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
2576 NlaTrack *nlt = static_cast<NlaTrack *>(ale->data);
2577
2578 if (BKE_nlatrack_is_nonlocal_in_liboverride(ale->id, nlt)) {
2579 /* No adding f-modifiers to strips in non-local tracks of override data. */
2580 continue;
2581 }
2582
2583 LISTBASE_FOREACH (NlaStrip *, strip, &nlt->strips) {
2584 /* can F-Modifier be added to the current strip? */
2585 if (active_only) {
2586 /* if not active, cannot add since we're only adding to active strip */
2587 if ((strip->flag & NLASTRIP_FLAG_ACTIVE) == 0) {
2588 continue;
2589 }
2590 }
2591 else {
2592 /* strip must be selected, since we're not just doing active */
2593 if ((strip->flag & NLASTRIP_FLAG_SELECT) == 0) {
2594 continue;
2595 }
2596 }
2597
2598 /* sound clips are not affected by FModifiers */
2599 if (strip->type == NLASTRIP_TYPE_SOUND) {
2600 continue;
2601 }
2602
2603 /* add F-Modifier of specified type to selected, and make it the active one */
2604 fcm = add_fmodifier(&strip->modifiers, type, nullptr);
2605
2606 if (fcm) {
2607 set_active_fmodifier(&strip->modifiers, fcm);
2608 ale->update |= ANIM_UPDATE_DEPS;
2609 }
2610 else {
2611 BKE_reportf(op->reports,
2612 RPT_ERROR,
2613 "Modifier could not be added to (%s : %s) (see console for details)",
2614 nlt->name,
2615 strip->name);
2616 }
2617 }
2618 }
2619
2620 /* free temp data */
2621 ANIM_animdata_update(&ac, &anim_data);
2622 ANIM_animdata_freelist(&anim_data);
2623
2624 /* set notifier that things have changed */
2626
2627 /* done */
2628 return OPERATOR_FINISHED;
2629}
2630
2632{
2633 PropertyRNA *prop;
2634
2635 /* identifiers */
2636 ot->name = "Add F-Modifier";
2637 ot->idname = "NLA_OT_fmodifier_add";
2638 ot->description = "Add F-Modifier to the active/selected NLA-Strips";
2639
2640 /* api callbacks */
2644
2645 /* flags */
2647
2648 /* id-props */
2649 ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_fmodifier_type_items, 0, "Type", "");
2652
2653 prop = RNA_def_boolean(ot->srna,
2654 "only_active",
2655 true,
2656 "Only Active",
2657 "Only add a F-Modifier of the specified type to the active strip");
2659}
2660
2663/* -------------------------------------------------------------------- */
2668{
2669 bAnimContext ac;
2670 ListBase anim_data = {nullptr, nullptr};
2671 bool ok = false;
2672
2673 /* get editor data */
2674 if (ANIM_animdata_get_context(C, &ac) == 0) {
2675 return OPERATOR_CANCELLED;
2676 }
2677
2678 /* clear buffer first */
2680
2681 /* get a list of the editable tracks being shown in the NLA */
2684 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, eAnimCont_Types(ac.datatype));
2685
2686 /* for each NLA-Track, add the specified modifier to all selected strips */
2687 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
2688 NlaTrack *nlt = static_cast<NlaTrack *>(ale->data);
2689
2690 LISTBASE_FOREACH (NlaStrip *, strip, &nlt->strips) {
2691 /* only add F-Modifier if on active strip? */
2692 if ((strip->flag & NLASTRIP_FLAG_ACTIVE) == 0) {
2693 continue;
2694 }
2695
2696 /* TODO: when 'active' vs 'all' boolean is added, change last param! */
2697 ok |= ANIM_fmodifiers_copy_to_buf(&strip->modifiers, false);
2698 }
2699 }
2700
2701 /* free temp data */
2702 ANIM_animdata_freelist(&anim_data);
2703
2704 /* successful or not? */
2705 if (ok == 0) {
2706 BKE_report(op->reports, RPT_ERROR, "No F-Modifiers available to be copied");
2707 return OPERATOR_CANCELLED;
2708 }
2709
2710 /* no updates needed - copy is non-destructive operation */
2711 return OPERATOR_FINISHED;
2712}
2713
2715{
2716 /* identifiers */
2717 ot->name = "Copy F-Modifiers";
2718 ot->idname = "NLA_OT_fmodifier_copy";
2719 ot->description = "Copy the F-Modifier(s) of the active NLA-Strip";
2720
2721 /* api callbacks */
2724
2725 /* flags */
2727
2728 /* id-props */
2729#if 0
2731 "all",
2732 1,
2733 "All F-Modifiers",
2734 "Copy all the F-Modifiers, instead of just the active one");
2735#endif
2736}
2737
2740/* -------------------------------------------------------------------- */
2745{
2746 bAnimContext ac;
2747 ListBase anim_data = {nullptr, nullptr};
2748 int ok = 0;
2749
2750 const bool active_only = RNA_boolean_get(op->ptr, "only_active");
2751 const bool replace = RNA_boolean_get(op->ptr, "replace");
2752
2753 /* get editor data */
2754 if (ANIM_animdata_get_context(C, &ac) == 0) {
2755 return OPERATOR_CANCELLED;
2756 }
2757
2758 /* get a list of the editable tracks being shown in the NLA */
2761 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, eAnimCont_Types(ac.datatype));
2762
2763 /* for each NLA-Track, add the specified modifier to all selected strips */
2764 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
2765 NlaTrack *nlt = static_cast<NlaTrack *>(ale->data);
2766
2767 if (BKE_nlatrack_is_nonlocal_in_liboverride(ale->id, nlt)) {
2768 /* No pasting in non-local tracks of override data. */
2769 continue;
2770 }
2771
2772 LISTBASE_FOREACH (NlaStrip *, strip, &nlt->strips) {
2773 /* can F-Modifier be added to the current strip? */
2774 if (active_only) {
2775 /* if not active, cannot add since we're only adding to active strip */
2776 if ((strip->flag & NLASTRIP_FLAG_ACTIVE) == 0) {
2777 continue;
2778 }
2779 }
2780 else {
2781 /* strip must be selected, since we're not just doing active */
2782 if ((strip->flag & NLASTRIP_FLAG_SELECT) == 0) {
2783 continue;
2784 }
2785 }
2786
2787 /* paste FModifiers from buffer */
2788 ok += ANIM_fmodifiers_paste_from_buf(&strip->modifiers, replace, nullptr);
2789 ale->update |= ANIM_UPDATE_DEPS;
2790 }
2791 }
2792
2793 /* clean up */
2794 ANIM_animdata_update(&ac, &anim_data);
2795 ANIM_animdata_freelist(&anim_data);
2796
2797 /* successful or not? */
2798 if (ok) {
2800 return OPERATOR_FINISHED;
2801 }
2802
2803 BKE_report(op->reports, RPT_ERROR, "No F-Modifiers to paste");
2804 return OPERATOR_CANCELLED;
2805}
2806
2808{
2809 /* identifiers */
2810 ot->name = "Paste F-Modifiers";
2811 ot->idname = "NLA_OT_fmodifier_paste";
2812 ot->description = "Add copied F-Modifiers to the selected NLA-Strips";
2813
2814 /* api callbacks */
2817
2818 /* flags */
2820
2821 /* properties */
2823 ot->srna, "only_active", true, "Only Active", "Only paste F-Modifiers on active strip");
2825
2827 ot->srna,
2828 "replace",
2829 false,
2830 "Replace Existing",
2831 "Replace existing F-Modifiers, instead of just appending to the end of the existing list");
2832}
2833
Functions and classes to work with Actions.
Functions for backward compatibility with the legacy Action API.
bScreen * CTX_wm_screen(const bContext *C)
ScrArea * CTX_wm_area(const bContext *C)
Main * CTX_data_main(const bContext *C)
const FModifierTypeInfo * get_fmodifier_typeinfo(int type)
void BKE_fcurve_handles_recalc(FCurve *fcu)
FModifier * add_fmodifier(ListBase *modifiers, int type, FCurve *owner_fcu)
void set_active_fmodifier(ListBase *modifiers, FModifier *fcm)
ID * BKE_id_copy(Main *bmain, const ID *id)
Definition lib_id.cc:765
void id_us_min(ID *id)
Definition lib_id.cc:359
void BKE_nlameta_flush_transforms(NlaStrip *mstrip)
void BKE_nlastrip_remove_and_free(ListBase *strips, NlaStrip *strip, const bool do_id_user)
bool BKE_nlatrack_add_strip(NlaTrack *nlt, NlaStrip *strip, bool is_liboverride)
void BKE_nlastrips_clear_metastrip(ListBase *strips, NlaStrip *strip)
void BKE_nlastrip_recalculate_bounds_sync_action(NlaStrip *strip)
void BKE_nlastrips_clear_metas(ListBase *strips, bool only_sel, bool only_temp)
void BKE_nla_tweakmode_exit(OwnedAnimData owned_adt)
NlaStrip * BKE_nlastrip_copy(Main *bmain, NlaStrip *strip, bool use_same_action, int flag)
void BKE_nla_validate_state(AnimData *adt)
void BKE_nlatrack_solo_toggle(AnimData *adt, NlaTrack *nlt)
void BKE_nlatrack_set_active(ListBase *tracks, NlaTrack *nlt)
NlaStrip * BKE_nlastrip_new(bAction *act, ID &animated_id)
void BKE_nlatrack_remove_strip(NlaTrack *track, NlaStrip *strip)
@ NLATIME_CONVERT_MAP
Definition BKE_nla.hh:516
@ NLATIME_CONVERT_UNMAP
Definition BKE_nla.hh:513
NlaTrack * BKE_nlatrack_new_after(ListBase *nla_tracks, NlaTrack *prev, bool is_liboverride)
bool BKE_nlastrips_has_space(ListBase *strips, float start, float end)
NlaTrack * BKE_nlatrack_new_tail(ListBase *nla_tracks, const bool is_liboverride)
NlaTrack * BKE_nlatrack_find_tweaked(AnimData *adt)
bool BKE_nla_tweakmode_enter(OwnedAnimData owned_adt)
bool BKE_nlatrack_has_space(NlaTrack *nlt, float start, float end)
NlaStrip * BKE_nla_add_soundstrip(Main *bmain, Scene *scene, Speaker *speaker)
bool BKE_nlatrack_is_nonlocal_in_liboverride(const ID *id, const NlaTrack *nlt)
void BKE_nlastrip_validate_name(AnimData *adt, NlaStrip *strip)
void BKE_nlastrips_make_metas(ListBase *strips, bool is_temp)
void BKE_reportf(ReportList *reports, eReportType type, const char *format,...) ATTR_PRINTF_FORMAT(3
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition report.cc:125
#define BLI_assert(a)
Definition BLI_assert.h:50
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:57
BLI_INLINE bool BLI_listbase_is_empty(const struct ListBase *lb)
#define LISTBASE_FOREACH(type, var, list)
#define LISTBASE_FOREACH_BACKWARD(type, var, list)
void BLI_insertlinkafter(struct ListBase *listbase, void *vprevlink, void *vnewlink) ATTR_NONNULL(1)
Definition listbase.cc:331
void * BLI_findlink(const struct ListBase *listbase, int number) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
BLI_INLINE bool BLI_listbase_count_is_equal_to(const struct ListBase *listbase, const int count_cmp)
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:110
void BLI_remlink(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:130
MINLINE int round_fl_to_int(float a)
BLI_INLINE int BLI_rcti_size_y(const struct rcti *rct)
Definition BLI_rect.h:193
BLI_INLINE float BLI_rctf_size_x(const struct rctf *rct)
Definition BLI_rect.h:197
#define ELEM(...)
#define IS_EQF(a, b)
#define BLT_I18NCONTEXT_ID_ACTION
#define IFACE_(msgid)
void DEG_relations_tag_update(Main *bmain)
#define ID_IS_EDITABLE(_id)
Definition DNA_ID.h:658
#define ID_REAL_USERS(id)
Definition DNA_ID.h:637
#define ID_IS_OVERRIDE_LIBRARY(_id)
Definition DNA_ID.h:683
@ ID_AC
@ ID_OB
@ ACT_FRAME_RANGE
@ NLASTRIP_FLAG_ACTIVE
@ NLASTRIP_FLAG_TEMP_META
@ NLASTRIP_FLAG_AUTO_BLENDS
@ NLASTRIP_FLAG_MUTED
@ NLASTRIP_FLAG_SELECT
@ NLASTRIP_FLAG_SYNC_LENGTH
@ ADT_NLA_SOLO_TRACK
@ ADT_NLA_EVAL_UPPER_TRACKS
@ ADT_NLA_EDIT_ON
@ FMODIFIER_TYPE_CYCLES
@ FMODIFIER_NUM_TYPES
@ NLASTRIP_TYPE_SOUND
@ NLASTRIP_TYPE_META
@ NLASTRIP_TYPE_TRANSITION
@ NLASTRIP_TYPE_CLIP
@ NLATRACK_SOLO
Object is a sort of wrapper for general info.
@ OB_SPEAKER
@ SCER_PRV_RANGE
@ SCE_NLA_EDIT_ON
#define FPS
@ ANIMTYPE_ANIMDATA
@ ACHANNEL_ROLE_CHANNEL
#define NLATRACK_FIRST_TOP(ac)
@ ALE_ACT
#define NLATRACK_STEP(snla)
@ ANIM_UPDATE_DEPS
eAnimCont_Types
@ ACHANNEL_SETTING_SELECT
eAnimFilter_Flags
@ ANIMFILTER_ACTIVE
@ ANIMFILTER_FOREDIT
@ ANIMFILTER_ANIMDATA
@ ANIMFILTER_DATA_VISIBLE
@ ANIMFILTER_LIST_VISIBLE
@ ANIMFILTER_LIST_CHANNELS
@ ANIMFILTER_NODUPLIS
@ ANIMFILTER_FCURVESONLY
@ ANIMFILTER_SEL
#define NLATRACK_HEIGHT(snla)
void ED_area_tag_redraw(ScrArea *area)
Definition area.cc:708
bool ED_operator_nla_active(bContext *C)
Read Guarded memory(de)allocation.
const EnumPropertyItem * RNA_action_itemf(bContext *C, PointerRNA *ptr, PropertyRNA *prop, bool *r_free)
@ PROP_ENUM_NO_TRANSLATE
Definition RNA_types.hh:321
@ PROP_SKIP_SAVE
Definition RNA_types.hh:245
@ ALERT_ICON_WARNING
void UI_view2d_sync(bScreen *screen, ScrArea *area, View2D *v2dcur, int flag)
Definition view2d.cc:861
#define V2D_LOCK_COPY
Definition UI_view2d.hh:85
void UI_view2d_center_get(const View2D *v2d, float *r_x, float *r_y)
Definition view2d.cc:1934
void UI_view2d_center_set(View2D *v2d, float x, float y)
Definition view2d.cc:1944
@ OPTYPE_UNDO
Definition WM_types.hh:162
@ OPTYPE_REGISTER
Definition WM_types.hh:160
#define ND_NLA_ACTCHANGE
Definition WM_types.hh:465
#define NC_ANIMATION
Definition WM_types.hh:355
#define NC_SCENE
Definition WM_types.hh:345
#define NA_ADDED
Definition WM_types.hh:552
#define NA_EDITED
Definition WM_types.hh:550
#define ND_FRAME
Definition WM_types.hh:401
#define NA_REMOVED
Definition WM_types.hh:553
#define ND_NLA_ORDER
Definition WM_types.hh:467
#define ND_NLA
Definition WM_types.hh:464
const bAnimChannelType * ANIM_channel_get_typeinfo(bAnimListElem *ale)
short ANIM_channel_setting_get(bAnimContext *ac, bAnimListElem *ale, eAnimChannel_Settings setting)
void ANIM_animdata_freelist(ListBase *anim_data)
Definition anim_deps.cc:457
void ANIM_animdata_update(bAnimContext *ac, ListBase *anim_data)
Definition anim_deps.cc:350
void ANIM_center_frame(bContext *C, int smooth_viewtx)
Definition anim_draw.cc:663
bool ANIM_animdata_get_context(const bContext *C, bAnimContext *ac)
size_t ANIM_animdata_filter(bAnimContext *ac, ListBase *anim_data, const eAnimFilter_Flags filter_mode, void *data, const eAnimCont_Types datatype)
int ED_markers_find_nearest_marker_time(ListBase *markers, float x)
float nlastrip_get_frame(NlaStrip *strip, float cframe, short mode)
#define floorf(x)
int len
draw_view in_light_buf[] float
bool ANIM_fmodifiers_paste_from_buf(ListBase *modifiers, bool replace, FCurve *curve)
void ANIM_fmodifiers_copybuf_free()
bool ANIM_fmodifiers_copy_to_buf(ListBase *modifiers, bool active)
#define GS(x)
Definition iris.cc:202
short ANIM_animchanneldata_keyframes_loop(KeyframeEditData *ked, bDopeSheet *ads, void *data, int keytype, KeyframeEditFunc key_ok, KeyframeEditFunc key_cb, FcuEditFunc fcu_cb)
static ulong * next
bool action_treat_as_legacy(const bAction &action)
void NLA_OT_view_frame(wmOperatorType *ot)
Definition nla_edit.cc:585
static int nlaedit_snap_exec(bContext *C, wmOperator *op)
Definition nla_edit.cc:2360
static int nlaedit_delete_exec(bContext *C, wmOperator *)
Definition nla_edit.cc:1259
static int nlaedit_add_transition_exec(bContext *C, wmOperator *op)
Definition nla_edit.cc:780
void NLA_OT_view_all(wmOperatorType *ot)
Definition nla_edit.cc:542
static int nlaedit_add_sound_exec(bContext *C, wmOperator *)
Definition nla_edit.cc:907
void NLA_OT_fmodifier_add(wmOperatorType *ot)
Definition nla_edit.cc:2631
static int nlaedit_sync_actlen_exec(bContext *C, wmOperator *op)
Definition nla_edit.cc:1952
void NLA_OT_split(wmOperatorType *ot)
Definition nla_edit.cc:1489
void NLA_OT_tweakmode_exit(wmOperatorType *ot)
Definition nla_edit.cc:283
static int nla_fmodifier_add_exec(bContext *C, wmOperator *op)
Definition nla_edit.cc:2554
static bool nla_tracks_get_selected_extents(bAnimContext *ac, float *r_min, float *r_max)
Definition nla_edit.cc:431
void ED_nla_postop_refresh(bAnimContext *ac)
Definition nla_edit.cc:59
static int nlaedit_viewall(bContext *C, const bool only_sel)
Definition nla_edit.cc:478
static int nlaedit_viewsel_exec(bContext *C, wmOperator *)
Definition nla_edit.cc:536
void NLA_OT_soundclip_add(wmOperatorType *ot)
Definition nla_edit.cc:976
static int nlaedit_apply_scale_exec(bContext *C, wmOperator *)
Definition nla_edit.cc:2164
static int nlaedit_previewrange_exec(bContext *C, wmOperator *)
Definition nla_edit.cc:373
void NLA_OT_tweakmode_enter(wmOperatorType *ot)
Definition nla_edit.cc:173
void NLA_OT_clear_scale(wmOperatorType *ot)
Definition nla_edit.cc:2326
void NLA_OT_make_single_user(wmOperatorType *ot)
Definition nla_edit.cc:2124
void NLA_OT_meta_add(wmOperatorType *ot)
Definition nla_edit.cc:1051
static void get_nlastrip_extents(bAnimContext *ac, float *min, float *max, const bool only_sel)
Definition nla_edit.cc:318
static int nla_fmodifier_paste_exec(bContext *C, wmOperator *op)
Definition nla_edit.cc:2744
void NLA_OT_meta_remove(wmOperatorType *ot)
Definition nla_edit.cc:1116
static int nlaedit_get_editable_tracks(bAnimContext *ac, ListBase *anim_data)
Definition nla_edit.cc:612
void NLA_OT_snap(wmOperatorType *ot)
Definition nla_edit.cc:2489
static int nlaedit_disable_tweakmode_exec(bContext *C, wmOperator *op)
Definition nla_edit.cc:261
static int nlaedit_clear_scale_exec(bContext *C, wmOperator *)
Definition nla_edit.cc:2283
static int nlaedit_viewall_exec(bContext *C, wmOperator *)
Definition nla_edit.cc:530
void NLA_OT_swap(wmOperatorType *ot)
Definition nla_edit.cc:1747
static int nlaedit_toggle_mute_exec(bContext *C, wmOperator *)
Definition nla_edit.cc:1514
static int nlaedit_make_single_user_exec(bContext *C, wmOperator *)
Definition nla_edit.cc:2044
void NLA_OT_mute_toggle(wmOperatorType *ot)
Definition nla_edit.cc:1558
void NLA_OT_move_up(wmOperatorType *ot)
Definition nla_edit.cc:1838
static void nlaedit_split_strip_meta(NlaTrack *nlt, NlaStrip *strip)
Definition nla_edit.cc:1419
void NLA_OT_delete(wmOperatorType *ot)
Definition nla_edit.cc:1326
static int nlaedit_move_down_exec(bContext *C, wmOperator *)
Definition nla_edit.cc:1861
static int nlaedit_make_single_user_invoke(bContext *C, wmOperator *op, const wmEvent *)
Definition nla_edit.cc:2109
void NLA_OT_previewrange_set(wmOperatorType *ot)
Definition nla_edit.cc:403
void NLA_OT_fmodifier_copy(wmOperatorType *ot)
Definition nla_edit.cc:2714
void NLA_OT_move_down(wmOperatorType *ot)
Definition nla_edit.cc:1929
static int nlaedit_split_exec(bContext *C, wmOperator *)
Definition nla_edit.cc:1427
static int nlaedit_add_actionclip_invoke(bContext *C, wmOperator *op, const wmEvent *event)
Definition nla_edit.cc:619
void NLA_OT_transition_add(wmOperatorType *ot)
Definition nla_edit.cc:886
static int nlaedit_viewframe_exec(bContext *C, wmOperator *op)
Definition nla_edit.cc:578
static const EnumPropertyItem * nla_fmodifier_itemf(bContext *C, PointerRNA *, PropertyRNA *, bool *r_free)
Definition nla_edit.cc:2516
static int nlaedit_duplicate_exec(bContext *C, wmOperator *op)
Definition nla_edit.cc:1140
void NLA_OT_view_selected(wmOperatorType *ot)
Definition nla_edit.cc:557
static int nlaedit_duplicate_invoke(bContext *C, wmOperator *op, const wmEvent *)
Definition nla_edit.cc:1221
static int nlaedit_enable_tweakmode_exec(bContext *C, wmOperator *op)
Definition nla_edit.cc:95
static int nlaedit_move_up_exec(bContext *C, wmOperator *)
Definition nla_edit.cc:1770
static int nlaedit_remove_meta_exec(bContext *C, wmOperator *)
Definition nla_edit.cc:1074
void NLA_OT_duplicate(wmOperatorType *ot)
Definition nla_edit.cc:1228
static void nlaedit_split_strip_actclip(Main *bmain, AnimData *adt, NlaTrack *nlt, NlaStrip *strip, float cfra)
Definition nla_edit.cc:1354
bool nlaedit_disable_tweakmode(bAnimContext *ac, bool do_solo)
Definition nla_edit.cc:213
static int nlaedit_add_actionclip_exec(bContext *C, wmOperator *op)
Definition nla_edit.cc:642
static int nlaedit_add_meta_exec(bContext *C, wmOperator *)
Definition nla_edit.cc:1000
void NLA_OT_actionclip_add(wmOperatorType *ot)
Definition nla_edit.cc:746
void NLA_OT_fmodifier_paste(wmOperatorType *ot)
Definition nla_edit.cc:2807
void NLA_OT_action_sync_length(wmOperatorType *ot)
Definition nla_edit.cc:2013
static int nla_fmodifier_copy_exec(bContext *C, wmOperator *op)
Definition nla_edit.cc:2667
static int nlaedit_swap_exec(bContext *C, wmOperator *op)
Definition nla_edit.cc:1581
void NLA_OT_apply_scale(wmOperatorType *ot)
Definition nla_edit.cc:2260
static const EnumPropertyItem prop_nlaedit_snap_types[]
Definition nla_edit.cc:2350
static short bezt_apply_nlamapping(KeyframeEditData *ked, BezTriple *bezt)
Definition nla_edit.cc:2150
bool nlaop_poll_tweakmode_on(bContext *C)
Definition nla_ops.cc:50
bool nlaop_poll_tweakmode_off(bContext *C)
Definition nla_ops.cc:28
@ NLAEDIT_SNAP_NEAREST_MARKER
Definition nla_intern.hh:61
@ NLAEDIT_SNAP_NEAREST_SECOND
Definition nla_intern.hh:60
@ NLAEDIT_SNAP_NEAREST_FRAME
Definition nla_intern.hh:59
@ NLAEDIT_SNAP_CFRA
Definition nla_intern.hh:58
bool nlaedit_add_tracks_empty(bAnimContext *ac)
void RNA_float_set(PointerRNA *ptr, const char *name, float value)
int RNA_enum_from_value(const EnumPropertyItem *item, const int value)
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
PointerRNA RNA_pointer_create(ID *id, StructRNA *type, void *data)
int RNA_enum_get(PointerRNA *ptr, const char *name)
PropertyRNA * RNA_def_enum(StructOrFunctionRNA *cont_, const char *identifier, const EnumPropertyItem *items, const int default_value, const char *ui_name, const char *ui_description)
void RNA_enum_item_end(EnumPropertyItem **items, int *totitem)
void RNA_enum_item_add(EnumPropertyItem **items, int *totitem, const EnumPropertyItem *item)
PropertyRNA * RNA_def_boolean(StructOrFunctionRNA *cont_, const char *identifier, const bool default_value, const char *ui_name, const char *ui_description)
void RNA_def_property_translation_context(PropertyRNA *prop, const char *context)
void RNA_def_property_flag(PropertyRNA *prop, PropertyFlag flag)
void RNA_def_enum_funcs(PropertyRNA *prop, EnumPropertyItemFunc itemfunc)
const EnumPropertyItem rna_enum_fmodifier_type_items[]
Definition rna_fcurve.cc:38
const EnumPropertyItem rna_enum_dummy_NULL_items[]
Definition rna_rna.cc:29
#define min(a, b)
Definition sort.c:32
NlaStrip * actstrip
ListBase nla_tracks
float vec[3][3]
Definition DNA_ID.h:413
char name[66]
Definition DNA_ID.h:425
void * last
void * first
ListBase actions
Definition BKE_main.hh:233
struct NlaStrip * next
ListBase strips
struct NlaStrip * prev
ListBase strips
struct NlaTrack * next
char name[64]
struct NlaTrack * prev
struct RenderData r
bool(* has_setting)(bAnimContext *ac, bAnimListElem *ale, eAnimChannel_Settings setting)
eAnimChannel_Role channel_role
SpaceLink * sl
ListBase * markers
eAnimCont_Types datatype
bDopeSheet * ads
ReportList * reports
ARegion * region
float xmax
float xmin
float ymax
float ymin
const char * name
Definition WM_types.hh:990
bool(* poll)(bContext *C) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1042
const char * idname
Definition WM_types.hh:992
int(* invoke)(bContext *C, wmOperator *op, const wmEvent *event) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1022
int(* exec)(bContext *C, wmOperator *op) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1006
const char * description
Definition WM_types.hh:996
PropertyRNA * prop
Definition WM_types.hh:1092
StructRNA * srna
Definition WM_types.hh:1080
struct ReportList * reports
struct PointerRNA * ptr
float max
void WM_main_add_notifier(uint type, void *reference)
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
wmOperatorType * ot
Definition wm_files.cc:4125
void WM_operator_properties_confirm_or_exec(wmOperatorType *ot)
int WM_menu_invoke(bContext *C, wmOperator *op, const wmEvent *)
int WM_operator_confirm_ex(bContext *C, wmOperator *op, const char *title, const char *message, const char *confirm_text, int icon, bool cancel_default)
int WM_operator_smooth_viewtx_get(const wmOperator *op)
int WM_enum_search_invoke(bContext *C, wmOperator *op, const wmEvent *)