Blender  V2.93
action_data.c
Go to the documentation of this file.
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) 2015 Blender Foundation
17  * This is a new part of Blender
18  */
19 
24 #include <float.h>
25 #include <math.h>
26 #include <stdlib.h>
27 #include <string.h>
28 
29 #include "BLI_utildefines.h"
30 
31 #include "BLT_translation.h"
32 
33 #include "DNA_anim_types.h"
34 #include "DNA_gpencil_types.h"
35 #include "DNA_key_types.h"
36 #include "DNA_mask_types.h"
37 #include "DNA_object_types.h"
38 #include "DNA_scene_types.h"
39 
40 #include "RNA_access.h"
41 #include "RNA_define.h"
42 #include "RNA_enum_types.h"
43 
44 #include "BKE_action.h"
45 #include "BKE_context.h"
46 #include "BKE_fcurve.h"
47 #include "BKE_key.h"
48 #include "BKE_lib_id.h"
49 #include "BKE_nla.h"
50 #include "BKE_report.h"
51 #include "BKE_scene.h"
52 
53 #include "UI_view2d.h"
54 
55 #include "ED_anim_api.h"
56 #include "ED_gpencil.h"
57 #include "ED_keyframes_edit.h"
58 #include "ED_keyframing.h"
59 #include "ED_markers.h"
60 #include "ED_mask.h"
61 #include "ED_screen.h"
62 
63 #include "WM_api.h"
64 #include "WM_types.h"
65 
66 #include "UI_interface.h"
67 
68 #include "action_intern.h"
69 
70 /* ************************************************************************** */
71 /* ACTION CREATION */
72 
73 /* Helper function to find the active AnimData block from the Action Editor context */
75 {
78  AnimData *adt = NULL;
79 
80  /* Get AnimData block to use */
81  if (saction->mode == SACTCONT_ACTION) {
82  /* Currently, "Action Editor" means object-level only... */
83  if (ob) {
84  adt = ob->adt;
85  }
86  }
87  else if (saction->mode == SACTCONT_SHAPEKEY) {
88  Key *key = BKE_key_from_object(ob);
89  if (key) {
90  adt = key->adt;
91  }
92  }
93 
94  return adt;
95 }
96 
97 /* -------------------------------------------------------------------- */
98 
99 /* Create new action */
101 {
103  bAction *action;
104 
105  /* create action - the way to do this depends on whether we've got an
106  * existing one there already, in which case we make a copy of it
107  * (which is useful for "versioning" actions within the same file)
108  */
109  if (oldact && GS(oldact->id.name) == ID_AC) {
110  /* make a copy of the existing action */
111  action = (bAction *)BKE_id_copy(CTX_data_main(C), &oldact->id);
112  }
113  else {
114  /* just make a new (empty) action */
115  action = BKE_action_add(CTX_data_main(C), "Action");
116  }
117 
118  /* when creating new ID blocks, there is already 1 user (as for all new datablocks),
119  * but the RNA pointer code will assign all the proper users instead, so we compensate
120  * for that here
121  */
122  BLI_assert(action->id.us == 1);
123  id_us_min(&action->id);
124 
125  /* set ID-Root type */
126  if (area->spacetype == SPACE_ACTION) {
127  SpaceAction *saction = (SpaceAction *)area->spacedata.first;
128 
129  if (saction->mode == SACTCONT_SHAPEKEY) {
130  action->idroot = ID_KE;
131  }
132  else {
133  action->idroot = ID_OB;
134  }
135  }
136 
137  return action;
138 }
139 
140 /* Change the active action used by the action editor */
142 {
143  bScreen *screen = CTX_wm_screen(C);
145 
146  PointerRNA ptr, idptr;
147  PropertyRNA *prop;
148 
149  /* create RNA pointers and get the property */
150  RNA_pointer_create(&screen->id, &RNA_SpaceDopeSheetEditor, saction, &ptr);
151  prop = RNA_struct_find_property(&ptr, "action");
152 
153  /* NOTE: act may be NULL here, so better to just use a cast here */
154  RNA_id_pointer_create((ID *)act, &idptr);
155 
156  /* set the new pointer, and force a refresh */
157  RNA_property_pointer_set(&ptr, prop, idptr, NULL);
158  RNA_property_update(C, &ptr, prop);
159 }
160 
161 /* ******************** New Action Operator *********************** */
162 
163 /* Criteria:
164  * 1) There must be an dopesheet/action editor, and it must be in a mode which uses actions...
165  * OR
166  * The NLA Editor is active (i.e. Animation Data panel -> new action)
167  * 2) The associated AnimData block must not be in tweak-mode.
168  */
170 {
172 
173  /* Check tweak-mode is off (as you don't want to be tampering with the action in that case) */
174  /* NOTE: unlike for pushdown,
175  * this operator needs to be run when creating an action from nothing... */
179 
180  /* For now, actions are only for the active object, and on object and shapekey levels... */
181  if (saction->mode == SACTCONT_ACTION) {
182  /* XXX: This assumes that actions are assigned to the active object in this mode */
183  if (ob) {
184  if ((ob->adt == NULL) || (ob->adt->flag & ADT_NLA_EDIT_ON) == 0) {
185  return true;
186  }
187  }
188  }
189  else if (saction->mode == SACTCONT_SHAPEKEY) {
190  Key *key = BKE_key_from_object(ob);
191  if (key) {
192  if ((key->adt == NULL) || (key->adt->flag & ADT_NLA_EDIT_ON) == 0) {
193  return true;
194  }
195  }
196  }
197  }
198  else if (ED_operator_nla_active(C)) {
199  if (!(scene->flag & SCE_NLA_EDIT_ON)) {
200  return true;
201  }
202  }
203 
204  /* something failed... */
205  return false;
206 }
207 
209 {
210  PointerRNA ptr, idptr;
211  PropertyRNA *prop;
212 
213  bAction *oldact = NULL;
214  AnimData *adt = NULL;
215  /* hook into UI */
217 
218  if (prop) {
219  /* The operator was called from a button. */
220  PointerRNA oldptr;
221 
222  oldptr = RNA_property_pointer_get(&ptr, prop);
223  oldact = (bAction *)oldptr.owner_id;
224 
225  /* stash the old action to prevent it from being lost */
226  if (ptr.type == &RNA_AnimData) {
227  adt = ptr.data;
228  }
229  else if (ptr.type == &RNA_SpaceDopeSheetEditor) {
231  }
232  }
233  else {
235  oldact = adt->action;
236  }
237  {
238  bAction *action = NULL;
239 
240  /* Perform stashing operation - But only if there is an action */
241  if (adt && oldact) {
242  /* stash the action */
244  /* The stash operation will remove the user already
245  * (and unlink the action from the AnimData action slot).
246  * Hence, we must unset the ref to the action in the
247  * action editor too (if this is where we're being called from)
248  * first before setting the new action once it is created,
249  * or else the user gets decremented twice!
250  */
252  SpaceAction *saction = ptr.data;
253  saction->action = NULL;
254  }
255  }
256  else {
257 #if 0
258  printf("WARNING: Failed to stash %s. It may already exist in the NLA stack though\n",
259  oldact->id.name);
260 #endif
261  }
262  }
263 
264  /* create action */
265  action = action_create_new(C, oldact);
266 
267  if (prop) {
268  /* set this new action
269  * NOTE: we can't use actedit_change_action, as this function is also called from the NLA
270  */
271  RNA_id_pointer_create(&action->id, &idptr);
272  RNA_property_pointer_set(&ptr, prop, idptr, NULL);
273  RNA_property_update(C, &ptr, prop);
274  }
275  }
276 
277  /* set notifier that keyframes have changed */
279 
280  return OPERATOR_FINISHED;
281 }
282 
284 {
285  /* identifiers */
286  ot->name = "New Action";
287  ot->idname = "ACTION_OT_new";
288  ot->description = "Create new action";
289 
290  /* api callbacks */
293 
294  /* flags */
296 }
297 
298 /* ******************* Action Push-Down Operator ******************** */
299 
300 /* Criteria:
301  * 1) There must be an dopesheet/action editor, and it must be in a mode which uses actions
302  * 2) There must be an action active
303  * 3) The associated AnimData block must not be in tweak-mode
304  */
306 {
310 
311  /* Check for AnimData, Actions, and that tweak-mode is off. */
312  if (adt && saction->action) {
313  /* NOTE: We check this for the AnimData block in question and not the global flag,
314  * as the global flag may be left dirty by some of the browsing ops here.
315  */
316  if (!(adt->flag & ADT_NLA_EDIT_ON)) {
317  return true;
318  }
319  }
320  }
321 
322  /* something failed... */
323  return false;
324 }
325 
327 {
330 
331  /* Do the deed... */
332  if (adt) {
333  /* Perform the push-down operation
334  * - This will deal with all the AnimData-side user-counts. */
335  if (action_has_motion(adt->action) == 0) {
336  /* action may not be suitable... */
337  BKE_report(op->reports, RPT_WARNING, "Action must have at least one keyframe or F-Modifier");
338  return OPERATOR_CANCELLED;
339  }
340 
341  /* action can be safely added */
342  const Object *ob = CTX_data_active_object(C);
344 
345  /* Stop displaying this action in this editor
346  * NOTE: The editor itself doesn't set a user...
347  */
348  saction->action = NULL;
349  }
350 
351  /* Send notifiers that stuff has changed */
353  return OPERATOR_FINISHED;
354 }
355 
357 {
358  /* identifiers */
359  ot->name = "Push Down Action";
360  ot->idname = "ACTION_OT_push_down";
361  ot->description = "Push action down on to the NLA stack as a new strip";
362 
363  /* callbacks */
366 
367  /* flags */
369 }
370 
371 /* ******************* Action Stash Operator ******************** */
372 
374 {
377 
378  /* Perform stashing operation */
379  if (adt) {
380  /* don't do anything if this action is empty... */
381  if (action_has_motion(adt->action) == 0) {
382  /* action may not be suitable... */
383  BKE_report(op->reports, RPT_WARNING, "Action must have at least one keyframe or F-Modifier");
384  return OPERATOR_CANCELLED;
385  }
386 
387  /* stash the action */
390  /* The stash operation will remove the user already,
391  * so the flushing step later shouldn't double up
392  * the user-count fixes. Hence, we must unset this ref
393  * first before setting the new action.
394  */
395  saction->action = NULL;
396  }
397  else {
398  /* action has already been added - simply warn about this, and clear */
399  BKE_report(op->reports, RPT_ERROR, "Action has already been stashed");
400  }
401 
402  /* clear action refs from editor, and then also the backing data (not necessary) */
404  }
405 
406  /* Send notifiers that stuff has changed */
408  return OPERATOR_FINISHED;
409 }
410 
412 {
413  /* identifiers */
414  ot->name = "Stash Action";
415  ot->idname = "ACTION_OT_stash";
416  ot->description = "Store this action in the NLA stack as a non-contributing strip for later use";
417 
418  /* callbacks */
421 
422  /* flags */
424 
425  /* properties */
427  "create_new",
428  true,
429  "Create New Action",
430  "Create a new action once the existing one has been safely stored");
431 }
432 
433 /* ----------------- */
434 
435 /* Criteria:
436  * 1) There must be an dopesheet/action editor, and it must be in a mode which uses actions
437  * 2) The associated AnimData block must not be in tweak-mode
438  */
440 {
443 
444  /* Check tweak-mode is off (as you don't want to be tampering with the action in that case) */
445  /* NOTE: unlike for pushdown,
446  * this operator needs to be run when creating an action from nothing... */
447  if (adt) {
448  if (!(adt->flag & ADT_NLA_EDIT_ON)) {
449  return true;
450  }
451  }
452  else {
453  /* There may not be any action/animdata yet, so, just fallback to the global setting
454  * (which may not be totally valid yet if the action editor was used and things are
455  * now in an inconsistent state)
456  */
459 
460  if (!(scene->flag & SCE_NLA_EDIT_ON)) {
461  /* For now, actions are only for the active object, and on object and shapekey levels... */
462  return ELEM(saction->mode, SACTCONT_ACTION, SACTCONT_SHAPEKEY);
463  }
464  }
465  }
466 
467  /* something failed... */
468  return false;
469 }
470 
472 {
475 
476  /* Check for no action... */
477  if (saction->action == NULL) {
478  /* just create a new action */
479  bAction *action = action_create_new(C, NULL);
480  actedit_change_action(C, action);
481  }
482  else if (adt) {
483  /* Perform stashing operation */
484  if (action_has_motion(adt->action) == 0) {
485  /* don't do anything if this action is empty... */
486  BKE_report(op->reports, RPT_WARNING, "Action must have at least one keyframe or F-Modifier");
487  return OPERATOR_CANCELLED;
488  }
489 
490  /* stash the action */
493  bAction *new_action = NULL;
494 
495  /* Create new action not based on the old one
496  * (since the "new" operator already does that). */
497  new_action = action_create_new(C, NULL);
498 
499  /* The stash operation will remove the user already,
500  * so the flushing step later shouldn't double up
501  * the user-count fixes. Hence, we must unset this ref
502  * first before setting the new action.
503  */
504  saction->action = NULL;
505  actedit_change_action(C, new_action);
506  }
507  else {
508  /* action has already been added - simply warn about this, and clear */
509  BKE_report(op->reports, RPT_ERROR, "Action has already been stashed");
511  }
512  }
513 
514  /* Send notifiers that stuff has changed */
516  return OPERATOR_FINISHED;
517 }
518 
520 {
521  /* identifiers */
522  ot->name = "Stash Action";
523  ot->idname = "ACTION_OT_stash_and_create";
524  ot->description =
525  "Store this action in the NLA stack as a non-contributing strip for later use, and create a "
526  "new action";
527 
528  /* callbacks */
531 
532  /* flags */
534 }
535 
536 /* ************************************************************************** */
537 /* ACTION UNLINK */
538 
539 /* ******************* Action Unlink Operator ******************** */
540 /* We use a custom unlink operator here, as there are some technicalities which need special care:
541  * 1) When in Tweak Mode, it shouldn't be possible to unlink the active action,
542  * or else, everything turns to custard.
543  * 2) If the Action doesn't have any other users, the user should at least get
544  * a warning that it is going to get lost.
545  * 3) We need a convenient way to exit Tweak Mode from the Action Editor
546  */
547 
549  bContext *C, ID *id, AnimData *adt, bAction *act, ReportList *reports, bool force_delete)
550 {
552 
553  /* If the old action only has a single user (that it's about to lose),
554  * warn user about it
555  *
556  * TODO: Maybe we should just save it for them? But then, there's the problem of
557  * trying to get rid of stuff that's actually unwanted!
558  */
559  if (act->id.us == 1) {
560  BKE_reportf(reports,
561  RPT_WARNING,
562  "Action '%s' will not be saved, create Fake User or Stash in NLA Stack to retain",
563  act->id.name + 2);
564  }
565 
566  /* Clear Fake User and remove action stashing strip (if present) */
567  if (force_delete) {
568  /* Remove stashed strip binding this action to this datablock */
569  /* XXX: we cannot unlink it from *OTHER* datablocks that may also be stashing it,
570  * but GE users only seem to use/care about single-object binding for now so this
571  * should be fine
572  */
573  if (adt) {
574  NlaTrack *nlt, *nlt_next;
575  NlaStrip *strip, *nstrip;
576 
577  for (nlt = adt->nla_tracks.first; nlt; nlt = nlt_next) {
578  nlt_next = nlt->next;
579 
580  if (strstr(nlt->name, DATA_("[Action Stash]"))) {
581  for (strip = nlt->strips.first; strip; strip = nstrip) {
582  nstrip = strip->next;
583 
584  if (strip->act == act) {
585  /* Remove this strip, and the track too if it doesn't have anything else */
586  BKE_nlastrip_free(&nlt->strips, strip, true);
587 
588  if (nlt->strips.first == NULL) {
589  BLI_assert(nstrip == NULL);
590  BKE_nlatrack_free(&adt->nla_tracks, nlt, true);
591  }
592  }
593  }
594  }
595  }
596  }
597 
598  /* Clear Fake User */
599  id_fake_user_clear(&act->id);
600  }
601 
602  /* If in Tweak Mode, don't unlink. Instead, this
603  * becomes a shortcut to exit Tweak Mode instead
604  */
605  if ((adt) && (adt->flag & ADT_NLA_EDIT_ON)) {
606  /* Exit Tweak Mode */
608 
609  /* Flush this to the Action Editor (if that's where this change was initiated) */
610  if (area->spacetype == SPACE_ACTION) {
612  }
613  }
614  else {
615  /* Unlink normally - Setting it to NULL should be enough to get the old one unlinked */
616  if (area->spacetype == SPACE_ACTION) {
617  /* clear action editor -> action */
619  }
620  else {
621  /* clear AnimData -> action */
622  PointerRNA ptr;
623  PropertyRNA *prop;
624 
625  /* create AnimData RNA pointers */
626  RNA_pointer_create(id, &RNA_AnimData, adt, &ptr);
627  prop = RNA_struct_find_property(&ptr, "action");
628 
629  /* clear... */
631  RNA_property_update(C, &ptr, prop);
632  }
633  }
634 }
635 
636 /* -------------------------- */
637 
639 {
643 
644  /* Only when there's an active action, in the right modes... */
645  if (saction->action && adt) {
646  return true;
647  }
648  }
649 
650  /* something failed... */
651  return false;
652 }
653 
655 {
657  bool force_delete = RNA_boolean_get(op->ptr, "force_delete");
658 
659  if (adt && adt->action) {
660  ED_animedit_unlink_action(C, NULL, adt, adt->action, op->reports, force_delete);
661  }
662 
663  return OPERATOR_FINISHED;
664 }
665 
666 static int action_unlink_invoke(bContext *C, wmOperator *op, const wmEvent *event)
667 {
668  /* NOTE: this is hardcoded to match the behavior for the unlink button
669  * (in interface_templates.c). */
670  RNA_boolean_set(op->ptr, "force_delete", event->shift != 0);
671  return action_unlink_exec(C, op);
672 }
673 
675 {
676  PropertyRNA *prop;
677 
678  /* identifiers */
679  ot->name = "Unlink Action";
680  ot->idname = "ACTION_OT_unlink";
681  ot->description = "Unlink this action from the active action slot (and/or exit Tweak Mode)";
682 
683  /* callbacks */
687 
688  /* properties */
689  prop = RNA_def_boolean(ot->srna,
690  "force_delete",
691  false,
692  "Force Delete",
693  "Clear Fake User and remove "
694  "copy stashed in this data-block's NLA stack");
696 }
697 
698 /* ************************************************************************** */
699 /* ACTION BROWSING */
700 
701 /* Try to find NLA Strip to use for action layer up/down tool */
702 static NlaStrip *action_layer_get_nlastrip(ListBase *strips, float ctime)
703 {
704  NlaStrip *strip;
705 
706  for (strip = strips->first; strip; strip = strip->next) {
707  /* Can we use this? */
708  if (IN_RANGE_INCL(ctime, strip->start, strip->end)) {
709  /* in range - use this one */
710  return strip;
711  }
712  if ((ctime < strip->start) && (strip->prev == NULL)) {
713  /* before first - use this one */
714  return strip;
715  }
716  if ((ctime > strip->end) && (strip->next == NULL)) {
717  /* after last - use this one */
718  return strip;
719  }
720  }
721 
722  /* nothing suitable found... */
723  return NULL;
724 }
725 
726 /* Switch NLA Strips/Actions */
728  AnimData *adt, NlaTrack *old_track, NlaStrip *old_strip, NlaTrack *nlt, NlaStrip *strip)
729 {
730  /* Exit tweak-mode on old strip
731  * NOTE: We need to manually clear this stuff ourselves, as tweak-mode exit doesn't do it
732  */
734 
735  if (old_strip) {
737  }
738  if (old_track) {
739  old_track->flag &= ~(NLATRACK_ACTIVE | NLATRACK_SELECTED);
740  }
741 
742  /* Make this one the active one instead */
744  nlt->flag |= NLATRACK_ACTIVE;
745 
746  /* Copy over "solo" flag - This is useful for stashed actions... */
747  if (old_track) {
748  if (old_track->flag & NLATRACK_SOLO) {
749  old_track->flag &= ~NLATRACK_SOLO;
750  nlt->flag |= NLATRACK_SOLO;
751  }
752  }
753  else {
754  /* NLA muting <==> Solo Tracks */
755  if (adt->flag & ADT_NLA_EVAL_OFF) {
756  /* disable NLA muting */
757  adt->flag &= ~ADT_NLA_EVAL_OFF;
758 
759  /* mark this track as being solo */
760  adt->flag |= ADT_NLA_SOLO_TRACK;
761  nlt->flag |= NLATRACK_SOLO;
762 
763  /* TODO: Needs rest-pose flushing (when we get reference track) */
764  }
765  }
766 
767  /* Enter tweak-mode again - hopefully we're now "it" */
769  BLI_assert(adt->actstrip == strip);
770 }
771 
772 /* ********************** One Layer Up Operator ************************** */
773 
775 {
776  /* Action Editor's action editing modes only */
779  if (adt) {
780  /* only allow if we're in tweak-mode, and there's something above us... */
781  if (adt->flag & ADT_NLA_EDIT_ON) {
782  /* We need to check if there are any tracks above the active one
783  * since the track the action comes from is not stored in AnimData
784  */
785  if (adt->nla_tracks.last) {
786  NlaTrack *nlt = (NlaTrack *)adt->nla_tracks.last;
787 
788  if (nlt->flag & NLATRACK_DISABLED) {
789  /* A disabled track will either be the track itself,
790  * or one of the ones above it.
791  *
792  * If this is the top-most one, there is the possibility
793  * that there is no active action. For now, we let this
794  * case return true too, so that there is a natural way
795  * to "move to an empty layer", even though this means
796  * that we won't actually have an action.
797  */
798  // return (adt->tmpact != NULL);
799  return true;
800  }
801  }
802  }
803  }
804  }
805 
806  /* something failed... */
807  return false;
808 }
809 
811 {
813  NlaTrack *act_track;
814 
816  float ctime = BKE_scene_frame_get(scene);
817 
818  /* Get active track */
819  act_track = BKE_nlatrack_find_tweaked(adt);
820 
821  if (act_track == NULL) {
822  BKE_report(op->reports, RPT_ERROR, "Could not find current NLA Track");
823  return OPERATOR_CANCELLED;
824  }
825 
826  /* Find next action, and hook it up */
827  if (act_track->next) {
828  NlaTrack *nlt;
829 
830  /* Find next action to use */
831  for (nlt = act_track->next; nlt; nlt = nlt->next) {
832  NlaStrip *strip = action_layer_get_nlastrip(&nlt->strips, ctime);
833 
834  if (strip) {
835  action_layer_switch_strip(adt, act_track, adt->actstrip, nlt, strip);
836  break;
837  }
838  }
839  }
840  else {
841  /* No more actions (strips) - Go back to editing the original active action
842  * NOTE: This will mean exiting tweak-mode...
843  */
845 
846  /* Deal with solo flags...
847  * Assume: Solo Track == NLA Muting
848  */
849  if (adt->flag & ADT_NLA_SOLO_TRACK) {
850  /* turn off solo flags on tracks */
851  act_track->flag &= ~NLATRACK_SOLO;
852  adt->flag &= ~ADT_NLA_SOLO_TRACK;
853 
854  /* turn on NLA muting (to keep same effect) */
855  adt->flag |= ADT_NLA_EVAL_OFF;
856 
857  /* TODO: Needs rest-pose flushing (when we get reference track) */
858  }
859  }
860 
861  /* Update the action that this editor now uses
862  * NOTE: The calls above have already handled the user-count/anim-data side of things. */
864  return OPERATOR_FINISHED;
865 }
866 
868 {
869  /* identifiers */
870  ot->name = "Next Layer";
871  ot->idname = "ACTION_OT_layer_next";
872  ot->description =
873  "Switch to editing action in animation layer above the current action in the NLA Stack";
874 
875  /* callbacks */
878 
879  /* flags */
881 }
882 
883 /* ********************* One Layer Down Operator ************************* */
884 
886 {
887  /* Action Editor's action editing modes only */
890  if (adt) {
891  if (adt->flag & ADT_NLA_EDIT_ON) {
892  /* Tweak Mode: We need to check if there are any tracks below the active one
893  * that we can move to */
894  if (adt->nla_tracks.first) {
895  NlaTrack *nlt = (NlaTrack *)adt->nla_tracks.first;
896 
897  /* Since the first disabled track is the track being tweaked/edited,
898  * we can simplify things by only checking the first track:
899  * - If it is disabled, this is the track being tweaked,
900  * so there can't be anything below it
901  * - Otherwise, there is at least 1 track below the tweaking
902  * track that we can descend to
903  */
904  if ((nlt->flag & NLATRACK_DISABLED) == 0) {
905  /* not disabled = there are actions below the one being tweaked */
906  return true;
907  }
908  }
909  }
910  else {
911  /* Normal Mode: If there are any tracks, we can try moving to those */
912  return (adt->nla_tracks.first != NULL);
913  }
914  }
915  }
916 
917  /* something failed... */
918  return false;
919 }
920 
922 {
924  NlaTrack *act_track;
925  NlaTrack *nlt;
926 
928  float ctime = BKE_scene_frame_get(scene);
929 
930  /* Sanity Check */
931  if (adt == NULL) {
932  BKE_report(
933  op->reports, RPT_ERROR, "Internal Error: Could not find Animation Data/NLA Stack to use");
934  return OPERATOR_CANCELLED;
935  }
936 
937  /* Get active track */
938  act_track = BKE_nlatrack_find_tweaked(adt);
939 
940  /* If there is no active track, that means we are using the active action... */
941  if (act_track) {
942  /* Active Track - Start from the one below it */
943  nlt = act_track->prev;
944  }
945  else {
946  /* Active Action - Use the top-most track */
947  nlt = adt->nla_tracks.last;
948  }
949 
950  /* Find previous action and hook it up */
951  for (; nlt; nlt = nlt->prev) {
952  NlaStrip *strip = action_layer_get_nlastrip(&nlt->strips, ctime);
953 
954  if (strip) {
955  action_layer_switch_strip(adt, act_track, adt->actstrip, nlt, strip);
956  break;
957  }
958  }
959 
960  /* Update the action that this editor now uses
961  * NOTE: The calls above have already handled the user-count/animdata side of things. */
963  return OPERATOR_FINISHED;
964 }
965 
967 {
968  /* identifiers */
969  ot->name = "Previous Layer";
970  ot->idname = "ACTION_OT_layer_prev";
971  ot->description =
972  "Switch to editing action in animation layer below the current action in the NLA Stack";
973 
974  /* callbacks */
977 
978  /* flags */
980 }
981 
982 /* ************************************************************************** */
Blender kernel action and pose functionality.
bool action_has_motion(const struct bAction *act)
struct bAction * BKE_action_add(struct Main *bmain, const char name[])
Definition: action.c:320
struct ScrArea * CTX_wm_area(const bContext *C)
Definition: context.c:714
struct Scene * CTX_data_scene(const bContext *C)
Definition: context.c:1034
struct Object * CTX_data_active_object(const bContext *C)
Definition: context.c:1279
struct bScreen * CTX_wm_screen(const bContext *C)
Definition: context.c:709
struct SpaceLink * CTX_wm_space_data(const bContext *C)
Definition: context.c:719
struct Main * CTX_data_main(const bContext *C)
Definition: context.c:1018
struct Key * BKE_key_from_object(const struct Object *ob)
struct ID * BKE_id_copy(struct Main *bmain, const struct ID *id)
void id_us_min(struct ID *id)
Definition: lib_id.c:297
void id_fake_user_clear(struct ID *id)
Definition: lib_id.c:336
void BKE_nla_action_pushdown(struct AnimData *adt, const bool is_liboverride)
Definition: nla.c:1957
bool BKE_nla_action_stash(struct AnimData *adt, const bool is_liboverride)
Definition: nla.c:1883
bool BKE_nla_tweakmode_enter(struct AnimData *adt)
Definition: nla.c:2034
void BKE_nla_tweakmode_exit(struct AnimData *adt)
Definition: nla.c:2148
void BKE_nlastrip_free(ListBase *strips, struct NlaStrip *strip, bool do_id_user)
Definition: nla.c:72
struct NlaTrack * BKE_nlatrack_find_tweaked(struct AnimData *adt)
Definition: nla.c:1020
void BKE_nlatrack_free(ListBase *tracks, struct NlaTrack *nlt, bool do_id_user)
Definition: nla.c:114
void BKE_report(ReportList *reports, ReportType type, const char *message)
Definition: report.c:104
void BKE_reportf(ReportList *reports, ReportType type, const char *format,...) ATTR_PRINTF_FORMAT(3
float BKE_scene_frame_get(const struct Scene *scene)
#define BLI_assert(a)
Definition: BLI_assert.h:58
#define UNUSED(x)
#define ELEM(...)
#define IN_RANGE_INCL(a, b, c)
#define DATA_(msgid)
#define ID_IS_OVERRIDE_LIBRARY(_id)
Definition: DNA_ID.h:445
@ ID_KE
Definition: DNA_ID_enums.h:70
@ ID_AC
Definition: DNA_ID_enums.h:79
@ ID_OB
Definition: DNA_ID_enums.h:59
@ SACTCONT_ACTION
@ SACTCONT_SHAPEKEY
@ NLASTRIP_FLAG_ACTIVE
@ NLASTRIP_FLAG_SELECT
@ ADT_NLA_SOLO_TRACK
@ ADT_NLA_EVAL_OFF
@ ADT_NLA_EDIT_ON
@ NLATRACK_SOLO
@ NLATRACK_ACTIVE
@ NLATRACK_DISABLED
@ NLATRACK_SELECTED
Object is a sort of wrapper for general info.
#define SCE_NLA_EDIT_ON
@ SPACE_ACTION
@ OPERATOR_CANCELLED
@ OPERATOR_FINISHED
bool ED_operator_nla_active(struct bContext *C)
Definition: screen_ops.c:334
bool ED_operator_action_active(struct bContext *C)
Definition: screen_ops.c:282
StructRNA RNA_SpaceDopeSheetEditor
StructRNA RNA_AnimData
@ PROP_SKIP_SAVE
Definition: RNA_types.h:204
#define C
Definition: RandGen.cpp:39
void UI_context_active_but_prop_get_templateID(struct bContext *C, struct PointerRNA *r_ptr, struct PropertyRNA **r_prop)
#define ND_NLA_ACTCHANGE
Definition: WM_types.h:398
@ OPTYPE_UNDO
Definition: WM_types.h:155
@ OPTYPE_REGISTER
Definition: WM_types.h:153
#define NC_ANIMATION
Definition: WM_types.h:289
#define NA_ADDED
Definition: WM_types.h:464
#define ND_KEYFRAME
Definition: WM_types.h:394
static bool action_unlink_poll(bContext *C)
Definition: action_data.c:638
void ACTION_OT_layer_prev(wmOperatorType *ot)
Definition: action_data.c:966
void ACTION_OT_push_down(wmOperatorType *ot)
Definition: action_data.c:356
static bool action_new_poll(bContext *C)
Definition: action_data.c:169
static void actedit_change_action(bContext *C, bAction *act)
Definition: action_data.c:141
static bAction * action_create_new(bContext *C, bAction *oldact)
Definition: action_data.c:100
static int action_stash_exec(bContext *C, wmOperator *op)
Definition: action_data.c:373
void ACTION_OT_unlink(wmOperatorType *ot)
Definition: action_data.c:674
static bool action_layer_prev_poll(bContext *C)
Definition: action_data.c:885
static bool action_stash_create_poll(bContext *C)
Definition: action_data.c:439
static int action_new_exec(bContext *C, wmOperator *UNUSED(op))
Definition: action_data.c:208
void ED_animedit_unlink_action(bContext *C, ID *id, AnimData *adt, bAction *act, ReportList *reports, bool force_delete)
Definition: action_data.c:548
static bool action_pushdown_poll(bContext *C)
Definition: action_data.c:305
void ACTION_OT_stash_and_create(wmOperatorType *ot)
Definition: action_data.c:519
AnimData * ED_actedit_animdata_from_context(bContext *C)
Definition: action_data.c:74
static int action_layer_next_exec(bContext *C, wmOperator *op)
Definition: action_data.c:810
void ACTION_OT_stash(wmOperatorType *ot)
Definition: action_data.c:411
static void action_layer_switch_strip(AnimData *adt, NlaTrack *old_track, NlaStrip *old_strip, NlaTrack *nlt, NlaStrip *strip)
Definition: action_data.c:727
static int action_unlink_exec(bContext *C, wmOperator *op)
Definition: action_data.c:654
static int action_stash_create_exec(bContext *C, wmOperator *op)
Definition: action_data.c:471
void ACTION_OT_new(wmOperatorType *ot)
Definition: action_data.c:283
void ACTION_OT_layer_next(wmOperatorType *ot)
Definition: action_data.c:867
static int action_pushdown_exec(bContext *C, wmOperator *op)
Definition: action_data.c:326
static int action_layer_prev_exec(bContext *C, wmOperator *op)
Definition: action_data.c:921
static bool action_layer_next_poll(bContext *C)
Definition: action_data.c:774
static NlaStrip * action_layer_get_nlastrip(ListBase *strips, float ctime)
Definition: action_data.c:702
static int action_unlink_invoke(bContext *C, wmOperator *op, const wmEvent *event)
Definition: action_data.c:666
Scene scene
#define GS(x)
Definition: iris.c:241
static void area(int d1, int d2, int e1, int e2, float weights[2])
void RNA_pointer_create(ID *id, StructRNA *type, void *data, PointerRNA *r_ptr)
Definition: rna_access.c:146
void RNA_id_pointer_create(ID *id, PointerRNA *r_ptr)
Definition: rna_access.c:122
void RNA_property_pointer_set(PointerRNA *ptr, PropertyRNA *prop, PointerRNA ptr_value, ReportList *reports)
Definition: rna_access.c:3673
void RNA_boolean_set(PointerRNA *ptr, const char *name, bool value)
Definition: rna_access.c:6272
const PointerRNA PointerRNA_NULL
Definition: rna_access.c:71
PointerRNA RNA_property_pointer_get(PointerRNA *ptr, PropertyRNA *prop)
Definition: rna_access.c:3641
PropertyRNA * RNA_struct_find_property(PointerRNA *ptr, const char *identifier)
Definition: rna_access.c:866
void RNA_property_update(bContext *C, PointerRNA *ptr, PropertyRNA *prop)
Definition: rna_access.c:2317
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:6261
PropertyRNA * RNA_def_boolean(StructOrFunctionRNA *cont_, const char *identifier, bool default_value, const char *ui_name, const char *ui_description)
Definition: rna_define.c:3481
void RNA_def_property_flag(PropertyRNA *prop, PropertyFlag flag)
Definition: rna_define.c:1512
bAction * action
NlaStrip * actstrip
ListBase nla_tracks
Definition: DNA_ID.h:273
int us
Definition: DNA_ID.h:293
char name[66]
Definition: DNA_ID.h:283
struct AnimData * adt
Definition: DNA_key_types.h:81
void * last
Definition: DNA_listBase.h:47
void * first
Definition: DNA_listBase.h:47
struct NlaStrip * next
struct NlaStrip * prev
bAction * act
ListBase strips
struct NlaTrack * next
char name[64]
struct NlaTrack * prev
struct AnimData * adt
struct StructRNA * type
Definition: RNA_types.h:51
void * data
Definition: RNA_types.h:52
struct ID * owner_id
Definition: RNA_types.h:50
short flag
bAction * action
short shift
Definition: WM_types.h:618
int(* invoke)(struct bContext *, struct wmOperator *, const struct wmEvent *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:752
const char * name
Definition: WM_types.h:721
const char * idname
Definition: WM_types.h:723
bool(* poll)(struct bContext *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:776
struct StructRNA * srna
Definition: WM_types.h:802
const char * description
Definition: WM_types.h:726
int(* exec)(struct bContext *, struct wmOperator *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:736
PropertyRNA * prop
Definition: WM_types.h:814
struct ReportList * reports
struct PointerRNA * ptr
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
PointerRNA * ptr
Definition: wm_files.c:3157
wmOperatorType * ot
Definition: wm_files.c:3156