diff options
Diffstat (limited to 'source/blender/editors/space_action/action_data.c')
-rw-r--r-- | source/blender/editors/space_action/action_data.c | 322 |
1 files changed, 322 insertions, 0 deletions
diff --git a/source/blender/editors/space_action/action_data.c b/source/blender/editors/space_action/action_data.c index d3693608a1f..111cb5257da 100644 --- a/source/blender/editors/space_action/action_data.c +++ b/source/blender/editors/space_action/action_data.c @@ -51,6 +51,7 @@ #include "RNA_define.h" #include "RNA_enum_types.h" +#include "BKE_animsys.h" #include "BKE_action.h" #include "BKE_fcurve.h" #include "BKE_global.h" @@ -58,6 +59,7 @@ #include "BKE_key.h" #include "BKE_main.h" #include "BKE_nla.h" +#include "BKE_scene.h" #include "BKE_context.h" #include "BKE_report.h" @@ -507,3 +509,323 @@ void ACTION_OT_stash_and_create(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } +/* ************************************************************************** */ +/* ACTION BROWSING */ + +/* Get the NLA Track that the active action comes from, since this is not stored in AnimData */ +/* TODO: Move this to blenkernel/nla.c */ +static NlaTrack *nla_tweak_track_get(AnimData *adt) +{ + NlaTrack *nlt; + + /* sanity check */ + if (adt == NULL) + return NULL; + + /* Since the track itself gets disabled, we want the first disabled... */ + for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) { + if (nlt->flag & (NLATRACK_ACTIVE | NLATRACK_DISABLED)) { + /* For good measure, make sure that strip actually exists there */ + if (BLI_findindex(&nlt->strips, adt->actstrip) != -1) { + return nlt; + } + else if (G.debug & G_DEBUG) { + printf("%s: Active strip (%p, %s) not in NLA track found (%p, %s)\n", + __func__, + adt->actstrip, (adt->actstrip) ? adt->actstrip->name : "<None>", + nlt, (nlt) ? nlt->name : "<None>"); + } + } + } + + /* Not found! */ + return NULL; +} + +/* ********************** One Layer Up Operator ************************** */ + +static int action_layer_next_poll(bContext *C) +{ + /* Action Editor's action editing modes only */ + if (ED_operator_action_active(C)) { + AnimData *adt = actedit_animdata_from_context(C); + if (adt) { + /* only allow if we're in tweakmode, and there's something above us... */ + if (adt->flag & ADT_NLA_EDIT_ON) { + /* We need to check if there are any tracks above the active one + * since the track the action comes from is not stored in AnimData + */ + if (adt->nla_tracks.last) { + NlaTrack *nlt = (NlaTrack *)adt->nla_tracks.last; + + if (nlt->flag & NLATRACK_DISABLED) { + /* A disabled track will either be the track itself, + * or one of the ones above it. + * + * If this is the top-most one, there is the possibility + * that there is no active action. For now, we let this + * case return true too, so that there is a natural way + * to "move to an empty layer", even though this means + * that we won't actually have an action. + */ + // return (adt->tmpact != NULL); + return true; + } + } + } + } + } + + /* something failed... */ + return false; +} + +static int action_layer_next_exec(bContext *C, wmOperator *op) +{ + AnimData *adt = actedit_animdata_from_context(C); + NlaTrack *act_track; + + Scene *scene = CTX_data_scene(C); + float ctime = BKE_scene_frame_get(scene); + + /* Get active track */ + act_track = nla_tweak_track_get(adt); + + if (act_track == NULL) { + BKE_report(op->reports, RPT_ERROR, "Could not find current NLA Track"); + return OPERATOR_CANCELLED; + } + + /* Find next action, and hook it up */ + if (act_track->next) { + NlaTrack *nlt; + NlaStrip *strip; + bool found = false; + + /* Find next action to use */ + for (nlt = act_track->next; nlt && !found; nlt = nlt->next) { + for (strip = nlt->strips.first; strip; strip = strip->next) { + /* Can we use this? */ + if (IN_RANGE_INCL(ctime, strip->start, strip->end)) { + /* in range - use this one */ + found = true; + } + else if ((ctime < strip->start) && (strip->prev == NULL)) { + /* before first - use this one */ + found = true; + } + else if ((ctime > strip->end) && (strip->next == NULL)) { + /* after last - use this one */ + found = true; + } + + /* Apply... */ + if (found) { + NlaStrip *old_strip = adt->actstrip; + + /* Exit tweakmode on old strip + * NOTE: We need to manually clear this stuff ourselves, as tweakmode exit doesn't do it + */ + BKE_nla_tweakmode_exit(adt); + + old_strip->flag &= ~(NLASTRIP_FLAG_ACTIVE | NLASTRIP_FLAG_SELECT); + act_track->flag &= ~(NLATRACK_ACTIVE | NLATRACK_SELECTED); + + /* Make this one the active one instead */ + strip->flag |= (NLASTRIP_FLAG_ACTIVE | NLASTRIP_FLAG_SELECT); + nlt->flag |= NLATRACK_ACTIVE; + + /* Copy over "solo" flag - This is useful for stashed actions... */ + if (act_track->flag & NLATRACK_SOLO) { + act_track->flag &= ~NLATRACK_SOLO; + nlt->flag |= NLATRACK_SOLO; + } + + /* Enter tweakmode again - hopefully we're now "it" */ + BKE_nla_tweakmode_enter(adt); + BLI_assert(adt->actstrip == strip); + + break; + } + } + } + } + else { + /* No more actions - Go back to editing the original active action + * NOTE: This will mean exiting tweakmode... + */ + BKE_nla_tweakmode_exit(adt); + + /* Deal with solo flags... */ + // XXX: if solo, turn off NLA while we edit this action? + act_track->flag &= ~NLATRACK_SOLO; + adt->flag &= ~ADT_NLA_SOLO_TRACK; + } + + /* Update the action that this editor now uses + * NOTE: The calls above have already handled the usercount/animdata side of things + */ + actedit_change_action(C, adt->action); + return OPERATOR_FINISHED; +} + +void ACTION_OT_layer_next(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Next Layer"; + ot->idname = "ACTION_OT_layer_next"; + ot->description = "Edit action in animation layer above the current action in the NLA Stack"; + + /* callbacks */ + ot->exec = action_layer_next_exec; + ot->poll = action_layer_next_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +/* ********************* One Layer Down Operator ************************* */ + +static int action_layer_prev_poll(bContext *C) +{ + /* Action Editor's action editing modes only */ + if (ED_operator_action_active(C)) { + AnimData *adt = actedit_animdata_from_context(C); + if (adt) { + if (adt->flag & ADT_NLA_EDIT_ON) { + /* Tweak Mode: We need to check if there are any tracks below the active one that we can move to */ + if (adt->nla_tracks.first) { + NlaTrack *nlt = (NlaTrack *)adt->nla_tracks.first; + + /* Since the first disabled track is the track being tweaked/edited, + * we can simplify things by only checking the first track: + * - If it is disabled, this is the track being tweaked, + * so there can't be anything below it + * - Otherwise, there is at least 1 track below the tweaking + * track that we can descend to + */ + if ((nlt->flag & NLATRACK_DISABLED) == 0) { + /* not disabled = there are actions below the one being tweaked */ + return true; + } + } + } + else { + /* Normal Mode: If there are any tracks, we can try moving to those */ + return (adt->nla_tracks.first != NULL); + } + } + } + + /* something failed... */ + return false; +} + +static int action_layer_prev_exec(bContext *C, wmOperator *op) +{ + AnimData *adt = actedit_animdata_from_context(C); + NlaTrack *act_track; + + NlaTrack *nlt; + NlaStrip *strip; + bool found = false; + + Scene *scene = CTX_data_scene(C); + float ctime = BKE_scene_frame_get(scene); + + /* Sanity Check */ + if (adt == NULL) { + BKE_report(op->reports, RPT_ERROR, "Internal Error: Could not find Animation Data/NLA Stack to use"); + return OPERATOR_CANCELLED; + } + + /* Get active track */ + act_track = nla_tweak_track_get(adt); + + /* If there is no active track, that means we are using the active action... */ + if (act_track) { + /* Active Track - Start from the one below it */ + nlt = act_track->prev; + } + else { + /* Active Action - Use the top-most track */ + nlt = adt->nla_tracks.last; + } + + /* Find previous action and hook it up */ + for (; nlt && !found; nlt = nlt->prev) { + for (strip = nlt->strips.first; strip; strip = strip->next) { + /* Can we use this? */ + if (IN_RANGE_INCL(ctime, strip->start, strip->end)) { + /* in range - use this one */ + found = true; + } + else if ((ctime < strip->start) && (strip->prev == NULL)) { + /* before first - use this one */ + found = true; + } + else if ((ctime > strip->end) && (strip->next == NULL)) { + /* after last - use this one */ + found = true; + } + + /* Apply... */ + if (found) { + NlaStrip *old_strip = adt->actstrip; + + /* Exit tweakmode on old strip + * NOTE: We need to manually clear this stuff ourselves, as tweakmode exit doesn't do it + */ + BKE_nla_tweakmode_exit(adt); + + if (old_strip) { + old_strip->flag &= ~(NLASTRIP_FLAG_ACTIVE | NLASTRIP_FLAG_SELECT); + } + if (act_track) { + act_track->flag &= ~(NLATRACK_ACTIVE | NLATRACK_SELECTED); + } + + /* Make this one the active one instead */ + strip->flag |= (NLASTRIP_FLAG_ACTIVE | NLASTRIP_FLAG_SELECT); + nlt->flag |= NLATRACK_ACTIVE; + + /* Copy over "solo" flag - This is useful for stashed actions... */ + if (act_track) { + if (act_track->flag & NLATRACK_SOLO) { + act_track->flag &= ~NLATRACK_SOLO; + nlt->flag |= NLATRACK_SOLO; + } + } + + /* Enter tweakmode again - hopefully we're now "it" */ + BKE_nla_tweakmode_enter(adt); + BLI_assert(adt->actstrip == strip); + + break; + } + } + } + + /* Update the action that this editor now uses + * NOTE: The calls above have already handled the usercount/animdata side of things + */ + actedit_change_action(C, adt->action); + return OPERATOR_FINISHED; +} + +void ACTION_OT_layer_prev(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Previous Layer"; + ot->idname = "ACTION_OT_layer_prev"; + ot->description = "Edit action in animation layer below the current action in the NLA Stack"; + + /* callbacks */ + ot->exec = action_layer_prev_exec; + ot->poll = action_layer_prev_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +/* ************************************************************************** */ |