diff options
author | Joshua Leung <aligorith@gmail.com> | 2009-06-05 09:18:07 +0400 |
---|---|---|
committer | Joshua Leung <aligorith@gmail.com> | 2009-06-05 09:18:07 +0400 |
commit | 5c21c176fa0a571f3ba47af8ad2c7906a5dc375f (patch) | |
tree | e20d22f19ad35ade19954bf55a7dab65204f2f51 /source/blender/editors | |
parent | f6cac5bec7418b58fe250c65293e85a8f0095cb2 (diff) |
NLA SoC: Operators for 'tweaking' strip actions (TAB-Key for both)
In this commit, I've introduced the mechanism by which actions already referenced by strips used in the NLA can be edited (or 'tweaked'). To use, simply select a strip you wish to edit, and hit that TAB key to start tweaking that strip's action, and hit TAB again once you're done.
What happens when you enter 'tweak mode':
1) The action of the active strip temporarily becomes the 'active action' of the AnimData block. You are now able to edit this in one of the Animation Editors (DopeSheet/Action, Graph Editors) as per normal (i.e. sliding keyframes around, inserting keyframes, etc.). The 'action-line' will therefore get drawn immediately above the active track containing the active strip, so that it's clear that that's what we're editing.
2) All the NLA-tracks (and all the strips within them) that occur after the track that the active strip lived in get disabled while you're in tweakmode. This is equivalent to travelling back to an earlier state in a construction history stack.
3) The active NLA track also gets disabled while in tweakmode, since it would otherwise interfere with the correct functioning of the tweaking for the action of interest.
4) The 'real' active action (i.e. the one displaced by the active strip's action) gets put into temp storage, and will be restored after you exit tweakmode.
5) Any strips which also reference the action being tweaked will get highlighted in red shading to indicate that you may be making some changes to the action which you don't really want to make for the other users too.
Please note though, that this is only a rough prototype of this functionality, with some niceties still to come. i.e.:
* NLA-tracks after the active track should still get drawn above the 'tweaking action line', but perhaps with different appearance?
* Various tools will still need awareness of this to prevent corrupting operations from taking place. How to proceed is still undecided...
* When exiting tweak-mode, the strip the action came from still needs some form of syncing with the modified action... there are a few tricky issues here that will need to be solved
* Evaluation code doesn't totally take this into account yet...
---
Also, fixed a number of bugs with various code (notably selection, and also a few drawing bugs)
Diffstat (limited to 'source/blender/editors')
-rw-r--r-- | source/blender/editors/animation/anim_channels.c | 12 | ||||
-rw-r--r-- | source/blender/editors/animation/anim_filter.c | 118 | ||||
-rw-r--r-- | source/blender/editors/include/ED_anim_api.h | 6 | ||||
-rw-r--r-- | source/blender/editors/include/ED_screen.h | 1 | ||||
-rw-r--r-- | source/blender/editors/screen/screen_ops.c | 6 | ||||
-rw-r--r-- | source/blender/editors/space_action/action_select.c | 4 | ||||
-rw-r--r-- | source/blender/editors/space_graph/graph_select.c | 2 | ||||
-rw-r--r-- | source/blender/editors/space_nla/nla_channels.c | 2 | ||||
-rw-r--r-- | source/blender/editors/space_nla/nla_draw.c | 81 | ||||
-rw-r--r-- | source/blender/editors/space_nla/nla_edit.c | 137 | ||||
-rw-r--r-- | source/blender/editors/space_nla/nla_intern.h | 8 | ||||
-rw-r--r-- | source/blender/editors/space_nla/nla_ops.c | 56 | ||||
-rw-r--r-- | source/blender/editors/space_nla/nla_select.c | 3 |
13 files changed, 389 insertions, 47 deletions
diff --git a/source/blender/editors/animation/anim_channels.c b/source/blender/editors/animation/anim_channels.c index 658bff73978..59fb56f3c35 100644 --- a/source/blender/editors/animation/anim_channels.c +++ b/source/blender/editors/animation/anim_channels.c @@ -90,14 +90,13 @@ /* -------------------------- Exposed API ----------------------------------- */ /* Set the given animation-channel as the active one for the active context */ -void ANIM_set_active_channel (void *data, short datatype, int filter, void *channel_data, short channel_type) +void ANIM_set_active_channel (bAnimContext *ac, void *data, short datatype, int filter, void *channel_data, short channel_type) { ListBase anim_data = {NULL, NULL}; bAnimListElem *ale; /* try to build list of filtered items */ - // XXX we don't need/supply animcontext for now, since in this case, there's nothing really essential there that isn't already covered - ANIM_animdata_filter(NULL, &anim_data, filter, data, datatype); + ANIM_animdata_filter(ac, &anim_data, filter, data, datatype); if (anim_data.first == NULL) return; @@ -151,8 +150,7 @@ void ANIM_set_active_channel (void *data, short datatype, int filter, void *chan case ANIMTYPE_NLATRACK: { NlaTrack *nlt= (NlaTrack *)channel_data; - - ACHANNEL_SET_FLAG(nlt, ACHANNEL_SETFLAG_CLEAR, NLATRACK_ACTIVE); + nlt->flag |= NLATRACK_ACTIVE; } break; } @@ -1474,7 +1472,7 @@ static void mouse_anim_channels (bAnimContext *ac, float x, int channel_index, s /* if group is selected now, make group the 'active' one in the visible list */ if (agrp->flag & AGRP_SELECTED) - ANIM_set_active_channel(ac->data, ac->datatype, filter, agrp, ANIMTYPE_GROUP); + ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, agrp, ANIMTYPE_GROUP); } } break; @@ -1520,7 +1518,7 @@ static void mouse_anim_channels (bAnimContext *ac, float x, int channel_index, s /* if F-Curve is selected now, make F-Curve the 'active' one in the visible list */ if (fcu->flag & FCURVE_SELECTED) - ANIM_set_active_channel(ac->data, ac->datatype, filter, fcu, ANIMTYPE_FCURVE); + ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, fcu, ANIMTYPE_FCURVE); } } break; diff --git a/source/blender/editors/animation/anim_filter.c b/source/blender/editors/animation/anim_filter.c index ed526bd99a0..32405571b57 100644 --- a/source/blender/editors/animation/anim_filter.c +++ b/source/blender/editors/animation/anim_filter.c @@ -343,19 +343,33 @@ short ANIM_animdata_get_context (const bContext *C, bAnimContext *ac) /* quick macro to test if AnimData is usable for NLA */ #define ANIMDATA_HAS_NLA(id) ((id)->adt && (id)->adt->nla_tracks.first) -/* quick macro to test for all three avove usability tests, performing the appropriate provided + +/* Quick macro to test for all three avove usability tests, performing the appropriate provided * action for each when the AnimData context is appropriate. * - * Priority order for this goes (most important, to least): NLA, Drivers, Keyframes + * Priority order for this goes (most important, to least): AnimData blocks, NLA, Drivers, Keyframes. + * + * For this to work correctly, a standard set of data needs to be available within the scope that this + * gets called in: + * - ListBase anim_data; + * - bDopeSheet *ads; + * - bAnimListElem *ale; + * - int items; * * - id: ID block which should have an AnimData pointer following it immediately, to use + * - adtOk: line or block of code to execute for AnimData-blocks case (usually ANIMDATA_ADD_ANIMDATA) * - nlaOk: line or block of code to execute for NLA case * - driversOk: line or block of code to execute for Drivers case * - keysOk: line or block of code for Keyframes case */ -#define ANIMDATA_FILTER_CASES(id, nlaOk, driversOk, keysOk) \ +#define ANIMDATA_FILTER_CASES(id, adtOk, nlaOk, driversOk, keysOk) \ {\ - if (ads->filterflag & ADS_FILTER_ONLYNLA) {\ + if (filter_mode & ANIMFILTER_ANIMDATA) {\ + if ((id)->adt) {\ + adtOk\ + }\ + }\ + else if (ads->filterflag & ADS_FILTER_ONLYNLA) {\ if (ANIMDATA_HAS_NLA(id)) {\ nlaOk\ }\ @@ -376,6 +390,18 @@ short ANIM_animdata_get_context (const bContext *C, bAnimContext *ac) } +/* quick macro to add a pointer to an AnimData block as a channel */ +#define ANIMDATA_ADD_ANIMDATA(id) \ + {\ + ale= make_new_animlistelem((id)->adt, ANIMTYPE_ANIMDATA, NULL, ANIMTYPE_NONE, (ID *)id);\ + if (ale) {\ + BLI_addtail(anim_data, ale);\ + items++;\ + }\ + } + + + /* quick macro to test if a anim-channel (F-Curve, Group, etc.) is selected in an acceptable way */ #define ANIMCHANNEL_SELOK(test_func) \ ( !(filter_mode & (ANIMFILTER_SEL|ANIMFILTER_UNSEL)) || \ @@ -713,6 +739,11 @@ static int animdata_filter_nla (ListBase *anim_data, AnimData *adt, int filter_m items++; } } + + /* if we're in NLA-tweakmode, if this track was active, that means that it was the last active one */ + // FIXME: the channels after should still get drawn, just 'differently', and after an active-action channel + if ((adt->flag & ADT_NLA_EDIT_ON) && (nlt->flag & NLATRACK_ACTIVE)) + break; } } } @@ -890,6 +921,7 @@ static int animdata_filter_dopesheet_mats (ListBase *anim_data, bDopeSheet *ads, /* check if ok */ ANIMDATA_FILTER_CASES(ma, + { /* AnimData blocks - do nothing... */ }, ok=1;, ok=1;, ok=1;) @@ -933,6 +965,7 @@ static int animdata_filter_dopesheet_mats (ListBase *anim_data, bDopeSheet *ads, /* add material's animation data */ if (FILTER_MAT_OBJD(ma) || (filter_mode & ANIMFILTER_CURVESONLY)) { ANIMDATA_FILTER_CASES(ma, + { /* AnimData blocks - do nothing... */ }, items += animdata_filter_nla(anim_data, ma->adt, filter_mode, ma, ANIMTYPE_DSMAT, (ID *)ma);, items += animdata_filter_fcurves(anim_data, ma->adt->drivers.first, NULL, ma, ANIMTYPE_DSMAT, filter_mode, (ID *)ma);, items += animdata_filter_action(anim_data, ma->adt->action, filter_mode, ma, ANIMTYPE_DSMAT, (ID *)ma);) @@ -998,6 +1031,7 @@ static int animdata_filter_dopesheet_obdata (ListBase *anim_data, bDopeSheet *ad if ((expanded) || (filter_mode & ANIMFILTER_CURVESONLY)) { /* filtering for channels - nla, drivers, keyframes */ ANIMDATA_FILTER_CASES(iat, + { /* AnimData blocks - do nothing... */ }, items+= animdata_filter_nla(anim_data, iat->adt, filter_mode, iat, type, (ID *)iat);, items+= animdata_filter_fcurves(anim_data, adt->drivers.first, NULL, iat, type, filter_mode, (ID *)iat);, items += animdata_filter_action(anim_data, iat->adt->action, filter_mode, iat, type, (ID *)iat);) @@ -1036,6 +1070,7 @@ static int animdata_filter_dopesheet_ob (ListBase *anim_data, bDopeSheet *ads, B if (ob->adt) { adt= ob->adt; ANIMDATA_FILTER_CASES(ob, + { /* AnimData blocks - do nothing... */ }, { /* nla */ #if 0 /* include nla-expand widget? */ @@ -1091,6 +1126,7 @@ static int animdata_filter_dopesheet_ob (ListBase *anim_data, bDopeSheet *ads, B if ((key) && !(ads->filterflag & ADS_FILTER_NOSHAPEKEYS)) { adt= key->adt; ANIMDATA_FILTER_CASES(key, + { /* AnimData blocks - do nothing... */ }, { /* nla */ #if 0 /* include nla-expand widget? */ @@ -1151,6 +1187,7 @@ static int animdata_filter_dopesheet_ob (ListBase *anim_data, bDopeSheet *ads, B if ((ads->filterflag & ADS_FILTER_NOCAM) == 0) { ANIMDATA_FILTER_CASES(ca, + { /* AnimData blocks - do nothing... */ }, obdata_ok= 1;, obdata_ok= 1;, obdata_ok= 1;) @@ -1163,6 +1200,7 @@ static int animdata_filter_dopesheet_ob (ListBase *anim_data, bDopeSheet *ads, B if ((ads->filterflag & ADS_FILTER_NOLAM) == 0) { ANIMDATA_FILTER_CASES(la, + { /* AnimData blocks - do nothing... */ }, obdata_ok= 1;, obdata_ok= 1;, obdata_ok= 1;) @@ -1175,6 +1213,7 @@ static int animdata_filter_dopesheet_ob (ListBase *anim_data, bDopeSheet *ads, B if ((ads->filterflag & ADS_FILTER_NOCUR) == 0) { ANIMDATA_FILTER_CASES(cu, + { /* AnimData blocks - do nothing... */ }, obdata_ok= 1;, obdata_ok= 1;, obdata_ok= 1;) @@ -1216,6 +1255,7 @@ static int animdata_filter_dopesheet_scene (ListBase *anim_data, bDopeSheet *ads if ((ads->filterflag & ADS_FILTER_NOSCE) == 0) { adt= sce->adt; ANIMDATA_FILTER_CASES(sce, + { /* AnimData blocks - do nothing... */ }, { /* nla */ #if 0 /* include nla-expand widget? */ @@ -1266,9 +1306,10 @@ static int animdata_filter_dopesheet_scene (ListBase *anim_data, bDopeSheet *ads /* world */ if ((wo && wo->adt) && !(ads->filterflag & ADS_FILTER_NOWOR)) { - /* Action, Drivers, or NLA for World */ + /* Action, Drivers, or NLA for World */ adt= wo->adt; ANIMDATA_FILTER_CASES(wo, + { /* AnimData blocks - do nothing... */ }, { /* nla */ #if 0 /* include nla-expand widget? */ @@ -1327,6 +1368,7 @@ static int animdata_filter_dopesheet (ListBase *anim_data, bDopeSheet *ads, int { Scene *sce= (Scene *)ads->source; Base *base; + bAnimListElem *ale; int items = 0; /* check that we do indeed have a scene */ @@ -1342,11 +1384,25 @@ static int animdata_filter_dopesheet (ListBase *anim_data, bDopeSheet *ads, int /* check filtering-flags if ok */ ANIMDATA_FILTER_CASES(sce, + { + /* for the special AnimData blocks only case, we only need to add + * the block if it is valid... then other cases just get skipped (hence ok=0) + */ + ANIMDATA_ADD_ANIMDATA(sce); + sceOk=0; + }, sceOk= !(ads->filterflag & ADS_FILTER_NOSCE);, sceOk= !(ads->filterflag & ADS_FILTER_NOSCE);, sceOk= !(ads->filterflag & ADS_FILTER_NOSCE);) if (sce->world) { ANIMDATA_FILTER_CASES(sce->world, + { + /* for the special AnimData blocks only case, we only need to add + * the block if it is valid... then other cases just get skipped (hence ok=0) + */ + ANIMDATA_ADD_ANIMDATA(sce->world); + worOk=0; + }, worOk= !(ads->filterflag & ADS_FILTER_NOWOR);, worOk= !(ads->filterflag & ADS_FILTER_NOWOR);, worOk= !(ads->filterflag & ADS_FILTER_NOWOR);) @@ -1395,12 +1451,26 @@ static int animdata_filter_dopesheet (ListBase *anim_data, bDopeSheet *ads, int actOk= 0; keyOk= 0; ANIMDATA_FILTER_CASES(ob, + { + /* for the special AnimData blocks only case, we only need to add + * the block if it is valid... then other cases just get skipped (hence ok=0) + */ + ANIMDATA_ADD_ANIMDATA(ob); + actOk=0; + }, actOk= 1;, actOk= 1;, actOk= 1;) if (key) { /* shapekeys */ ANIMDATA_FILTER_CASES(key, + { + /* for the special AnimData blocks only case, we only need to add + * the block if it is valid... then other cases just get skipped (hence ok=0) + */ + ANIMDATA_ADD_ANIMDATA(key); + keyOk=0; + }, keyOk= 1;, keyOk= 1;, keyOk= 1;) @@ -1419,6 +1489,13 @@ static int animdata_filter_dopesheet (ListBase *anim_data, bDopeSheet *ads, int /* if material has relevant animation data, break */ ANIMDATA_FILTER_CASES(ma, + { + /* for the special AnimData blocks only case, we only need to add + * the block if it is valid... then other cases just get skipped (hence ok=0) + */ + ANIMDATA_ADD_ANIMDATA(ma); + matOk=0; + }, matOk= 1;, matOk= 1;, matOk= 1;) @@ -1435,6 +1512,13 @@ static int animdata_filter_dopesheet (ListBase *anim_data, bDopeSheet *ads, int Camera *ca= (Camera *)ob->data; dataOk= 0; ANIMDATA_FILTER_CASES(ca, + if ((ads->filterflag & ADS_FILTER_NOCAM)==0) { + /* for the special AnimData blocks only case, we only need to add + * the block if it is valid... then other cases just get skipped (hence ok=0) + */ + ANIMDATA_ADD_ANIMDATA(ca); + dataOk=0; + }, dataOk= !(ads->filterflag & ADS_FILTER_NOCAM);, dataOk= !(ads->filterflag & ADS_FILTER_NOCAM);, dataOk= !(ads->filterflag & ADS_FILTER_NOCAM);) @@ -1445,11 +1529,35 @@ static int animdata_filter_dopesheet (ListBase *anim_data, bDopeSheet *ads, int Lamp *la= (Lamp *)ob->data; dataOk= 0; ANIMDATA_FILTER_CASES(la, + if ((ads->filterflag & ADS_FILTER_NOLAM)==0) { + /* for the special AnimData blocks only case, we only need to add + * the block if it is valid... then other cases just get skipped (hence ok=0) + */ + ANIMDATA_ADD_ANIMDATA(la); + dataOk=0; + }, dataOk= !(ads->filterflag & ADS_FILTER_NOLAM);, dataOk= !(ads->filterflag & ADS_FILTER_NOLAM);, dataOk= !(ads->filterflag & ADS_FILTER_NOLAM);) } break; + case OB_CURVE: /* ------- Curve ---------- */ + { + Curve *cu= (Curve *)ob->data; + dataOk= 0; + ANIMDATA_FILTER_CASES(cu, + if ((ads->filterflag & ADS_FILTER_NOCUR)==0) { + /* for the special AnimData blocks only case, we only need to add + * the block if it is valid... then other cases just get skipped (hence ok=0) + */ + ANIMDATA_ADD_ANIMDATA(cu); + dataOk=0; + }, + dataOk= !(ads->filterflag & ADS_FILTER_NOCUR);, + dataOk= !(ads->filterflag & ADS_FILTER_NOCUR);, + dataOk= !(ads->filterflag & ADS_FILTER_NOCUR);) + } + break; default: /* --- other --- */ dataOk= 0; break; diff --git a/source/blender/editors/include/ED_anim_api.h b/source/blender/editors/include/ED_anim_api.h index cdd8b5c368c..dcaabb4b369 100644 --- a/source/blender/editors/include/ED_anim_api.h +++ b/source/blender/editors/include/ED_anim_api.h @@ -107,6 +107,7 @@ typedef struct bAnimListElem { // XXX was ACTTYPE_* typedef enum eAnim_ChannelType { ANIMTYPE_NONE= 0, + ANIMTYPE_ANIMDATA, ANIMTYPE_SPECIALDATA, ANIMTYPE_SCENE, @@ -162,6 +163,7 @@ typedef enum eAnimFilter_Flags { ANIMFILTER_ACTGROUPED = (1<<6), /* belongs to the active actiongroup */ ANIMFILTER_CURVEVISIBLE = (1<<7), /* F-Curve is visible for editing/viewing in Graph Editor */ ANIMFILTER_ACTIVE = (1<<8), /* channel should be 'active' */ // FIXME: this is only relevant for F-Curves for now + ANIMFILTER_ANIMDATA = (1<<9), /* only return the underlying AnimData blocks (not the tracks, etc.) data comes from */ } eAnimFilter_Flags; @@ -254,7 +256,7 @@ short ANIM_animdata_context_getdata(bAnimContext *ac); void ANIM_deselect_anim_channels(void *data, short datatype, short test, short sel); /* Set the 'active' channel of type channel_type, in the given action */ -void ANIM_set_active_channel(void *data, short datatype, int filter, void *channel_data, short channel_type); +void ANIM_set_active_channel(bAnimContext *ac, void *data, short datatype, int filter, void *channel_data, short channel_type); /* --------------- Settings and/or Defines -------------- */ @@ -308,6 +310,8 @@ void ipo_rainbow(int cur, int tot, float *out); /* ------------- NLA-Mapping ----------------------- */ /* anim_draw.c */ +// XXX these are soon to be depreceated? + /* Obtain the Object providing NLA-scaling for the given channel if applicable */ struct Object *ANIM_nla_mapping_get(bAnimContext *ac, bAnimListElem *ale); diff --git a/source/blender/editors/include/ED_screen.h b/source/blender/editors/include/ED_screen.h index c2beb34e7b5..e3b6572c03a 100644 --- a/source/blender/editors/include/ED_screen.h +++ b/source/blender/editors/include/ED_screen.h @@ -118,6 +118,7 @@ int ED_operator_node_active(struct bContext *C); int ED_operator_ipo_active(struct bContext *C); int ED_operator_sequencer_active(struct bContext *C); int ED_operator_image_active(struct bContext *C); +int ED_operator_nla_active(struct bContext *C); int ED_operator_object_active(struct bContext *C); int ED_operator_editmesh(struct bContext *C); diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c index be952558b6c..db1a39ed056 100644 --- a/source/blender/editors/screen/screen_ops.c +++ b/source/blender/editors/screen/screen_ops.c @@ -164,6 +164,7 @@ int ED_operator_node_active(bContext *C) return 0; } +// XXX rename int ED_operator_ipo_active(bContext *C) { return ed_spacetype_test(C, SPACE_IPO); @@ -179,6 +180,11 @@ int ED_operator_image_active(bContext *C) return ed_spacetype_test(C, SPACE_IMAGE); } +int ED_operator_nla_active(bContext *C) +{ + return ed_spacetype_test(C, SPACE_NLA); +} + int ED_operator_object_active(bContext *C) { return NULL != CTX_data_active_object(C); diff --git a/source/blender/editors/space_action/action_select.c b/source/blender/editors/space_action/action_select.c index f64cd0f707c..d8ed3fd1068 100644 --- a/source/blender/editors/space_action/action_select.c +++ b/source/blender/editors/space_action/action_select.c @@ -862,13 +862,13 @@ static void mouse_action_keys (bAnimContext *ac, int mval[2], short select_mode, bActionGroup *agrp= ale->data; agrp->flag |= AGRP_SELECTED; - ANIM_set_active_channel(ac->data, ac->datatype, filter, agrp, ANIMTYPE_GROUP); + ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, agrp, ANIMTYPE_GROUP); } else if (ale->type == ANIMTYPE_FCURVE) { FCurve *fcu= ale->data; fcu->flag |= FCURVE_SELECTED; - ANIM_set_active_channel(ac->data, ac->datatype, filter, fcu, ANIMTYPE_FCURVE); + ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, fcu, ANIMTYPE_FCURVE); } } else if (ac->datatype == ANIMCONT_GPENCIL) { diff --git a/source/blender/editors/space_graph/graph_select.c b/source/blender/editors/space_graph/graph_select.c index bb923ca6f95..21320b60ead 100644 --- a/source/blender/editors/space_graph/graph_select.c +++ b/source/blender/editors/space_graph/graph_select.c @@ -722,7 +722,7 @@ static void mouse_graph_keys (bAnimContext *ac, int mval[], short select_mode, s /* set active F-Curve (NOTE: sync the filter flags with findnearest_fcurve_vert) */ if (fcu->flag & FCURVE_SELECTED) { filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE | ANIMFILTER_CURVESONLY); - ANIM_set_active_channel(ac->data, ac->datatype, filter, fcu, ANIMTYPE_FCURVE); + ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, fcu, ANIMTYPE_FCURVE); } } diff --git a/source/blender/editors/space_nla/nla_channels.c b/source/blender/editors/space_nla/nla_channels.c index a839ccbf3d6..8db85ffa0b1 100644 --- a/source/blender/editors/space_nla/nla_channels.c +++ b/source/blender/editors/space_nla/nla_channels.c @@ -349,7 +349,7 @@ static void mouse_nla_channels (bAnimContext *ac, float x, int channel_index, sh /* if NLA-Track is selected now, make NLA-Track the 'active' one in the visible list */ if (nlt->flag & NLATRACK_SELECTED) - ANIM_set_active_channel(ac->data, ac->datatype, filter, nlt, ANIMTYPE_NLATRACK); + ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, nlt, ANIMTYPE_NLATRACK); } } break; diff --git a/source/blender/editors/space_nla/nla_draw.c b/source/blender/editors/space_nla/nla_draw.c index 85bf733df87..6c4c64ea272 100644 --- a/source/blender/editors/space_nla/nla_draw.c +++ b/source/blender/editors/space_nla/nla_draw.c @@ -137,7 +137,7 @@ static void nla_draw_strip (AnimData *adt, NlaTrack *nlt, NlaStrip *strip, View2 /* only need to draw here if there's no strip before since * it only applies in such a situation */ - if (strip->prev) { + if (strip->prev == NULL) { /* set the drawing color to the color of the strip, but with very faint alpha */ glColor4f(color[0], color[1], color[2], 0.15f); @@ -563,15 +563,20 @@ void draw_nla_channel_list (bAnimContext *ac, SpaceNla *snla, ARegion *ar) else special= ICON_LAYER_USED; - if (nlt->flag & NLATRACK_MUTED) - mute = ICON_MUTE_IPO_ON; - else - mute = ICON_MUTE_IPO_OFF; - - if (EDITABLE_NLT(nlt)) - protect = ICON_UNLOCKED; - else - protect = ICON_LOCKED; + /* if this track is active and we're tweaking it, don't draw these toggles */ + // TODO: need a special macro for this... + if ( ((nlt->flag & NLATRACK_ACTIVE) && (nlt->flag & NLATRACK_DISABLED)) == 0 ) + { + if (nlt->flag & NLATRACK_MUTED) + mute = ICON_MUTE_IPO_ON; + else + mute = ICON_MUTE_IPO_OFF; + + if (EDITABLE_NLT(nlt)) + protect = ICON_UNLOCKED; + else + protect = ICON_LOCKED; + } sel = SEL_NLT(nlt); strcpy(name, nlt->name); @@ -636,18 +641,29 @@ void draw_nla_channel_list (bAnimContext *ac, SpaceNla *snla, ARegion *ar) } else if (group == 5) { /* Action Line */ - if (ale->data) - glColor3f(0.8f, 0.2f, 0.0f); // reddish color - hardcoded for now - else - glColor3f(0.6f, 0.5f, 0.5f); // greyish-red color - hardcoded for now - + AnimData *adt= BKE_animdata_from_id(ale->id); + + // TODO: if tweaking some action, use the same color as for the tweaked track (quick hack done for now) + if (adt && (adt->flag & ADT_NLA_EDIT_ON)) { + // greenish color (same as tweaking strip) - hardcoded for now + glColor3f(0.3f, 0.95f, 0.1f); + } + else { + if (ale->data) + glColor3f(0.8f, 0.2f, 0.0f); // reddish color - hardcoded for now + else + glColor3f(0.6f, 0.5f, 0.5f); // greyish-red color - hardcoded for now + } + offset += 7 * indent; /* only on top two corners, to show that this channel sits on top of the preceeding ones */ uiSetRoundBox((1|2)); - /* draw slightly shifted up vertically to look like it has more separtion from other channels */ - gl_round_box(GL_POLYGON, x+offset, yminc+NLACHANNEL_SKIP, (float)NLACHANNEL_NAMEWIDTH, ymaxc+NLACHANNEL_SKIP, 8); + /* draw slightly shifted up vertically to look like it has more separtion from other channels, + * but we then need to slightly shorten it so that it doesn't look like it overlaps + */ + gl_round_box(GL_POLYGON, x+offset, yminc+NLACHANNEL_SKIP, (float)NLACHANNEL_NAMEWIDTH, ymaxc+NLACHANNEL_SKIP-1, 8); /* clear group value, otherwise we cause errors... */ group = 0; @@ -709,20 +725,29 @@ void draw_nla_channel_list (bAnimContext *ac, SpaceNla *snla, ARegion *ar) UI_icon_draw((float)(NLACHANNEL_NAMEWIDTH-offset), ydatac, mute); } - /* draw action 'push-down' - only for NLA-Action lines, and only when there's an action */ + /* draw NLA-action line 'status-icons' - only when there's an action */ if ((ale->type == ANIMTYPE_NLAACTION) && (ale->data)) { - offset += 16; + AnimData *adt= BKE_animdata_from_id(ale->id); - /* XXX firstly draw a little rect to help identify that it's different from the toggles */ - glBegin(GL_LINE_LOOP); - glVertex2f((float)NLACHANNEL_NAMEWIDTH-offset-1, y-7); - glVertex2f((float)NLACHANNEL_NAMEWIDTH-offset-1, y+9); - glVertex2f((float)NLACHANNEL_NAMEWIDTH-1, y+9); - glVertex2f((float)NLACHANNEL_NAMEWIDTH-1, y-7); - glEnd(); // GL_LINES + offset += 16; - /* now draw the icon */ - UI_icon_draw((float)NLACHANNEL_NAMEWIDTH-offset, ydatac, ICON_FREEZE); + /* now draw some indicator icons */ + if ((adt) && (adt->flag & ADT_NLA_EDIT_ON)) { + /* 'tweaking action' - not a button */ + UI_icon_draw((float)NLACHANNEL_NAMEWIDTH-offset, ydatac, ICON_EDIT); + } + else { + /* XXX firstly draw a little rect to help identify that it's different from the toggles */ + glBegin(GL_LINE_LOOP); + glVertex2f((float)NLACHANNEL_NAMEWIDTH-offset-1, y-7); + glVertex2f((float)NLACHANNEL_NAMEWIDTH-offset-1, y+9); + glVertex2f((float)NLACHANNEL_NAMEWIDTH-1, y+9); + glVertex2f((float)NLACHANNEL_NAMEWIDTH-1, y-7); + glEnd(); // GL_LINES + + /* 'push down' icon for normal active-actions */ + UI_icon_draw((float)NLACHANNEL_NAMEWIDTH-offset, ydatac, ICON_FREEZE); + } } glDisable(GL_BLEND); diff --git a/source/blender/editors/space_nla/nla_edit.c b/source/blender/editors/space_nla/nla_edit.c index ce9ae7de7a9..f7053957667 100644 --- a/source/blender/editors/space_nla/nla_edit.c +++ b/source/blender/editors/space_nla/nla_edit.c @@ -68,6 +68,143 @@ #include "nla_intern.h" // own include /* *********************************************** */ +/* General Editing */ + +/* ******************** Tweak-Mode Operators ***************************** */ +/* 'Tweak mode' allows the action referenced by the active NLA-strip to be edited + * as if it were the normal Active-Action of its AnimData block. + */ + +static int nlaedit_enable_tweakmode_exec (bContext *C, wmOperator *op) +{ + bAnimContext ac; + + ListBase anim_data = {NULL, NULL}; + bAnimListElem *ale; + int filter; + int ok=0; + + /* get editor data */ + if (ANIM_animdata_get_context(C, &ac) == 0) + return OPERATOR_CANCELLED; + + /* get a list of the AnimData blocks being shown in the NLA */ + filter= (ANIMFILTER_VISIBLE | ANIMFILTER_ANIMDATA); + ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype); + + /* if no blocks, popup error? */ + if (anim_data.first == NULL) { + BKE_report(op->reports, RPT_ERROR, "No AnimData blocks to enter tweakmode for"); + return OPERATOR_CANCELLED; + } + + /* for each AnimData block with NLA-data, try setting it in tweak-mode */ + for (ale= anim_data.first; ale; ale= ale->next) { + AnimData *adt= ale->data; + + /* try entering tweakmode if valid */ + ok += BKE_nla_tweakmode_enter(adt); + } + + /* free temp data */ + BLI_freelistN(&anim_data); + + /* if we managed to enter tweakmode on at least one AnimData block, + * set the flag for this in the active scene and send notifiers + */ + if (ac.scene && ok) { + /* set editing flag */ + ac.scene->flag |= SCE_NLA_EDIT_ON; + + /* set notifier that things have changed */ + ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_BOTH); + WM_event_add_notifier(C, NC_SCENE, NULL); + } + + /* done */ + return OPERATOR_FINISHED; +} + +void NLAEDIT_OT_tweakmode_enter (wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Enter Tweak Mode"; + ot->idname= "NLAEDIT_OT_tweakmode_enter"; + ot->description= "Enter tweaking mode for the action referenced by the active strip."; + + /* api callbacks */ + ot->exec= nlaedit_enable_tweakmode_exec; + ot->poll= nlaop_poll_tweakmode_off; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; +} + +/* ------------- */ + +static int nlaedit_disable_tweakmode_exec (bContext *C, wmOperator *op) +{ + bAnimContext ac; + + ListBase anim_data = {NULL, NULL}; + bAnimListElem *ale; + int filter; + + /* get editor data */ + if (ANIM_animdata_get_context(C, &ac) == 0) + return OPERATOR_CANCELLED; + + /* get a list of the AnimData blocks being shown in the NLA */ + filter= (ANIMFILTER_VISIBLE | ANIMFILTER_ANIMDATA); + ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype); + + /* if no blocks, popup error? */ + if (anim_data.first == NULL) { + BKE_report(op->reports, RPT_ERROR, "No AnimData blocks to enter tweakmode for"); + return OPERATOR_CANCELLED; + } + + /* for each AnimData block with NLA-data, try exitting tweak-mode */ + for (ale= anim_data.first; ale; ale= ale->next) { + AnimData *adt= ale->data; + + /* try entering tweakmode if valid */ + BKE_nla_tweakmode_exit(adt); + } + + /* free temp data */ + BLI_freelistN(&anim_data); + + /* if we managed to enter tweakmode on at least one AnimData block, + * set the flag for this in the active scene and send notifiers + */ + if (ac.scene) { + /* clear editing flag */ + ac.scene->flag &= ~SCE_NLA_EDIT_ON; + + /* set notifier that things have changed */ + ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_BOTH); + WM_event_add_notifier(C, NC_SCENE, NULL); + } + + /* done */ + return OPERATOR_FINISHED; +} + +void NLAEDIT_OT_tweakmode_exit (wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Exit Tweak Mode"; + ot->idname= "NLAEDIT_OT_tweakmode_exit"; + ot->description= "Exit tweaking mode for the action referenced by the active strip."; + + /* api callbacks */ + ot->exec= nlaedit_disable_tweakmode_exec; + ot->poll= nlaop_poll_tweakmode_on; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; +} /* *********************************************** */ diff --git a/source/blender/editors/space_nla/nla_intern.h b/source/blender/editors/space_nla/nla_intern.h index 448b823bd4b..a7188a7cccd 100644 --- a/source/blender/editors/space_nla/nla_intern.h +++ b/source/blender/editors/space_nla/nla_intern.h @@ -76,6 +76,9 @@ void NLAEDIT_OT_click_select(wmOperatorType *ot); /* **************************************** */ /* nla_edit.c */ +void NLAEDIT_OT_tweakmode_enter(wmOperatorType *ot); +void NLAEDIT_OT_tweakmode_exit(wmOperatorType *ot); + /* **************************************** */ /* nla_channels.c */ @@ -85,6 +88,11 @@ void NLA_OT_channels_click(wmOperatorType *ot); /* **************************************** */ /* nla_ops.c */ +int nlaop_poll_tweakmode_off(bContext *C); +int nlaop_poll_tweakmode_on (bContext *C); + +/* --- */ + void nla_operatortypes(void); void nla_keymap(wmWindowManager *wm); diff --git a/source/blender/editors/space_nla/nla_ops.c b/source/blender/editors/space_nla/nla_ops.c index 167686c99f9..057e4b05656 100644 --- a/source/blender/editors/space_nla/nla_ops.c +++ b/source/blender/editors/space_nla/nla_ops.c @@ -65,6 +65,51 @@ #include "nla_intern.h" // own include +/* ************************** poll callbacks for operators **********************************/ + +/* tweakmode is NOT enabled */ +int nlaop_poll_tweakmode_off (bContext *C) +{ + Scene *scene; + + /* for now, we check 2 things: + * 1) active editor must be NLA + * 2) tweakmode is currently set as a 'per-scene' flag + * so that it will affect entire NLA data-sets, + * but not all AnimData blocks will be in tweakmode for + * various reasons + */ + if (ED_operator_nla_active(C) == 0) + return 0; + + scene= CTX_data_scene(C); + if ((scene == NULL) || (scene->flag & SCE_NLA_EDIT_ON)) + return 0; + + return 1; +} + +/* tweakmode IS enabled */ +int nlaop_poll_tweakmode_on (bContext *C) +{ + Scene *scene; + + /* for now, we check 2 things: + * 1) active editor must be NLA + * 2) tweakmode is currently set as a 'per-scene' flag + * so that it will affect entire NLA data-sets, + * but not all AnimData blocks will be in tweakmode for + * various reasons + */ + if (ED_operator_nla_active(C) == 0) + return 0; + + scene= CTX_data_scene(C); + if ((scene == NULL) || !(scene->flag & SCE_NLA_EDIT_ON)) + return 0; + + return 1; +} /* ************************** registration - operator types **********************************/ @@ -77,6 +122,10 @@ void nla_operatortypes(void) /* select */ WM_operatortype_append(NLAEDIT_OT_click_select); WM_operatortype_append(NLAEDIT_OT_select_all_toggle); + + /* edit */ + WM_operatortype_append(NLAEDIT_OT_tweakmode_enter); + WM_operatortype_append(NLAEDIT_OT_tweakmode_exit); } /* ************************** registration - keymaps **********************************/ @@ -130,6 +179,13 @@ static void nla_keymap_main (wmWindowManager *wm, ListBase *keymap) WM_keymap_add_item(keymap, "NLAEDIT_OT_select_all_toggle", AKEY, KM_PRESS, 0, 0); RNA_boolean_set(WM_keymap_add_item(keymap, "NLAEDIT_OT_select_all_toggle", IKEY, KM_PRESS, KM_CTRL, 0)->ptr, "invert", 1); + /* editing */ + /* tweakmode + * - enter and exit are separate operators with the same hotkey... + * This works as they use different poll()'s + */ + WM_keymap_add_item(keymap, "NLAEDIT_OT_tweakmode_enter", TABKEY, KM_PRESS, 0, 0); + WM_keymap_add_item(keymap, "NLAEDIT_OT_tweakmode_exit", TABKEY, KM_PRESS, 0, 0); /* transform system */ //transform_keymap_for_space(wm, keymap, SPACE_NLA); diff --git a/source/blender/editors/space_nla/nla_select.c b/source/blender/editors/space_nla/nla_select.c index 0626d9febe4..2e3d5572711 100644 --- a/source/blender/editors/space_nla/nla_select.c +++ b/source/blender/editors/space_nla/nla_select.c @@ -300,8 +300,7 @@ static void mouse_nla_strips (bAnimContext *ac, int mval[2], short select_mode) NlaTrack *nlt= (NlaTrack *)ale->data; nlt->flag |= NLATRACK_SELECTED; - if (nlt->flag & NLATRACK_SELECTED) - ANIM_set_active_channel(ac->data, ac->datatype, filter, nlt, ANIMTYPE_NLATRACK); + ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, nlt, ANIMTYPE_NLATRACK); } } |