== "Extend" Transform Mode for Action + NLA Editors ==

Peach Request:
Now the Action and NLA editors have the "Extend" transform mode first seen in the Sequence Editor. Just use the EKEY to start transforming.

It works like Grab, except it only moves the keyframes/side of NLA-strip that was on the same side of the current-frame marker as the mouse was when transform started.
This commit is contained in:
2007-11-06 11:41:09 +00:00
parent f66aeb7a74
commit 9cd76a6609
7 changed files with 175 additions and 38 deletions

View File

@@ -58,6 +58,7 @@
#define TFM_TIME_TRANSLATE 19
#define TFM_TIME_SLIDE 20
#define TFM_TIME_SCALE 21
#define TFM_TIME_EXTEND 22
/* TRANSFORM CONTEXTS */
#define CTX_NONE 0

View File

@@ -739,6 +739,12 @@ void transform_action_keys (int mode, int dummy)
Transform();
}
break;
case 'e':
{
initTransform(TFM_TIME_EXTEND, CTX_NONE);
Transform();
}
break;
}
}
@@ -2646,6 +2652,11 @@ void winqreadactionspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
}
break;
case EKEY:
if (mval[0] >= ACTWIDTH)
transform_action_keys('e', 0);
break;
case GKEY:
if (G.qual & LR_CTRLKEY) {
transform_markers('g', 0);

View File

@@ -995,6 +995,12 @@ void transform_nlachannel_keys(int mode, int dummy)
Transform();
}
break;
case 'e':
{
initTransform(TFM_TIME_EXTEND, CTX_NONE);
Transform();
}
break;
}
}
@@ -1791,6 +1797,13 @@ void winqreadnlaspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
break;
case EKEY:
if (mval[0] >= NLAWIDTH) {
transform_nlachannel_keys ('e', 0);
update_for_newframe_muted();
}
break;
case GKEY:
if (mval[0]>=NLAWIDTH) {
if (G.qual & LR_CTRLKEY) {

View File

@@ -114,7 +114,6 @@ enum {
enum {
ACTMENU_KEY_DUPLICATE = 0,
ACTMENU_KEY_DELETE,
ACTMENU_KEY_BAKE,
ACTMENU_KEY_CLEAN
};
@@ -128,7 +127,8 @@ enum {
enum {
ACTMENU_KEY_TRANSFORM_MOVE = 0,
ACTMENU_KEY_TRANSFORM_SCALE,
ACTMENU_KEY_TRANSFORM_SLIDE
ACTMENU_KEY_TRANSFORM_SLIDE,
ACTMENU_KEY_TRANSFORM_EXTEND
};
enum {
@@ -594,6 +594,9 @@ static void do_action_keymenu_transformmenu(void *arg, int event)
case ACTMENU_KEY_TRANSFORM_SLIDE:
transform_action_keys('t', 0);
break;
case ACTMENU_KEY_TRANSFORM_EXTEND:
transform_action_keys('e', 0);
break;
}
scrarea_queue_winredraw(curarea);
@@ -611,6 +614,9 @@ static uiBlock *action_keymenu_transformmenu(void *arg_unused)
uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1,
"Grab/Move|G", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0,
ACTMENU_KEY_TRANSFORM_MOVE, "");
uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1,
"Grab/Extend from Frame|E", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0,
ACTMENU_KEY_TRANSFORM_EXTEND, "");
uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1,
"Scale|S", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0,
ACTMENU_KEY_TRANSFORM_SCALE, "");

View File

@@ -276,6 +276,10 @@ static void do_nla_strip_transformmenu(void *arg, int event)
transform_nlachannel_keys('s', 0);
update_for_newframe_muted();
break;
case 2: /* extend */
transform_nlachannel_keys('e', 0);
update_for_newframe_muted();
break;
}
allqueue(REDRAWVIEW3D, 0);
}
@@ -289,8 +293,10 @@ static uiBlock *nla_strip_transformmenu(void *arg_unused)
uiBlockSetButmFunc(block, do_nla_strip_transformmenu, NULL);
uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Grab/Move|G", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 0, "");
uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Grab/Extend from Frame|E", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 2, "");
uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Scale|S", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 1, "");
uiBlockSetDirection(block, UI_RIGHT);
uiTextBoundsBlock(block, 60);
return block;

View File

@@ -938,6 +938,7 @@ void initTransform(int mode, int context) {
/* EVIL! posemode code can switch translation to rotate when 1 bone is selected. will be removed (ton) */
/* EVIL2: we gave as argument also texture space context bit... was cleared */
/* EVIL3: extend mode for animation editors also switches modes... but is best way to avoid duplicate code */
mode = Trans.mode;
calculatePropRatio(&Trans);
@@ -1004,6 +1005,10 @@ void initTransform(int mode, int context) {
case TFM_TIME_SCALE:
initTimeScale(&Trans);
break;
case TFM_TIME_EXTEND:
/* now that transdata has been made, do like for TFM_TIME_TRANSLATE */
initTimeTranslate(&Trans);
break;
}
}

View File

@@ -113,6 +113,7 @@
#include "BIF_toolbox.h"
#include "BSE_view.h"
#include "BSE_drawipo.h"
#include "BSE_edit.h"
#include "BSE_editipo.h"
#include "BSE_editipo_types.h"
@@ -2049,7 +2050,48 @@ void flushTransIpoData(TransInfo *t)
/* ********************* ACTION/NLA EDITOR ****************** */
/* This function tests if a point is on the "mouse" side of the cursor/frame-marking */
static short FrameOnMouseSide(char side, float frame, float cframe)
{
/* both sides, so it doesn't matter */
if (side == 'B') return 1;
/* only on the named side */
if (side == 'R')
return (frame >= cframe) ? 1 : 0;
else
return (frame <= cframe) ? 1 : 0;
}
/* fully select selected beztriples, but only include if it's on the right side of cfra */
static int count_ipo_keys(Ipo *ipo, char side, float cfra)
{
IpoCurve *icu;
BezTriple *bezt;
int i, count = 0;
if (ipo == NULL)
return count;
/* only include points that occur on the right side of cfra */
for (icu= ipo->curve.first; icu; icu= icu->next) {
for (i=0, bezt=icu->bezt; i < icu->totvert; i++, bezt++) {
if (bezt->f2) {
/* fully select the other two keys */
bezt->f1 |= 1;
bezt->f3 |= 1;
/* increment by 3, as there are 3 points (3 * x-coordinates) that need transform */
if (FrameOnMouseSide(side, bezt->vec[1][0], cfra))
count += 3;
}
}
}
return count;
}
/* This function assigns the information to transdata */
static void TimeToTransData(TransData *td, float *time, Object *ob)
{
/* memory is calloc'ed, so that should zero everything nicely for us */
@@ -2065,9 +2107,12 @@ static void TimeToTransData(TransData *td, float *time, Object *ob)
/* This function advances the address to which td points to, so it must return
* the new address so that the next time new transform data is added, it doesn't
* overwrite the existing ones... i.e. td = IpoToTransData(td, ipo, ob);
* overwrite the existing ones... i.e. td = IpoToTransData(td, ipo, ob, side, cfra);
*
* The 'side' argument is needed for the extend mode. 'B' = both sides, 'R'/'L' mean only data
* on the named side are used.
*/
static TransData *IpoToTransData(TransData *td, Ipo *ipo, Object *ob)
static TransData *IpoToTransData(TransData *td, Ipo *ipo, Object *ob, char side, float cfra)
{
IpoCurve *icu;
BezTriple *bezt;
@@ -2077,9 +2122,11 @@ static TransData *IpoToTransData(TransData *td, Ipo *ipo, Object *ob)
return td;
for (icu= ipo->curve.first; icu; icu= icu->next) {
/* only add selected keyframes (for now, proportional edit is not enabled) */
for (i=0, bezt=icu->bezt; i < icu->totvert; i++, bezt++) {
/* only add selected keyframes (for now, proportional edit is not enabled) */
if (BEZSELECTED(bezt)) {
/* only add if on the right 'side' of the current frame */
if (FrameOnMouseSide(side, bezt->vec[1][0], cfra)) {
/* each control point needs to be added separetely */
TimeToTransData(td, bezt->vec[0], ob);
td++;
@@ -2092,6 +2139,7 @@ static TransData *IpoToTransData(TransData *td, Ipo *ipo, Object *ob)
}
}
}
}
return td;
}
@@ -2108,6 +2156,8 @@ static void createTransActionData(TransInfo *t)
int filter;
int count=0;
float cfra;
char side;
/* determine what type of data we are operating on */
data = get_action_context(&datatype);
@@ -2121,9 +2171,30 @@ static void createTransActionData(TransInfo *t)
if (NLA_ACTION_SCALED)
ob= OBACT;
/* which side of the current frame should be allowed */
if (t->mode == TFM_TIME_EXTEND) {
/* only side on which mouse is gets transformed */
float xmouse, ymouse;
areamouseco_to_ipoco(G.v2d, t->imval, &xmouse, &ymouse);
side = (xmouse > CFRA) ? 'R' : 'L';
}
else {
/* normal transform - both sides of current frame are considered */
side = 'B';
}
/* convert current-frame to action-time (slightly less accurate, espcially under
* higher scaling ratios, but is faster than converting all points)
*/
if (ob)
cfra = get_action_frame(ob, CFRA);
else
cfra = CFRA;
/* loop 1: fully select ipo-keys and count how many BezTriples are selected */
for (ale= act_data.first; ale; ale= ale->next)
count += fullselect_ipo_keys(ale->key_data);
count += count_ipo_keys(ale->key_data, side, cfra);
/* stop if trying to build list if nothing selected */
if (count == 0) {
@@ -2143,7 +2214,7 @@ static void createTransActionData(TransInfo *t)
for (ale= act_data.first; ale; ale= ale->next) {
Ipo *ipo= (Ipo *)ale->key_data;
td= IpoToTransData(td, ipo, ob);
td= IpoToTransData(td, ipo, ob, side, cfra);
}
/* check if we're supposed to be setting minx/maxx for TimeSlide */
@@ -2178,17 +2249,32 @@ static void createTransNlaData(TransInfo *t)
TransData *td = NULL;
int count=0, i;
float cfra;
char side;
/* which side of the current frame should be allowed */
if (t->mode == TFM_TIME_EXTEND) {
/* only side on which mouse is gets transformed */
float xmouse, ymouse;
areamouseco_to_ipoco(G.v2d, t->imval, &xmouse, &ymouse);
side = (xmouse > CFRA) ? 'R' : 'L';
}
else {
/* normal transform - both sides of current frame are considered */
side = 'B';
}
/* Ensure that partial selections result in beztriple selections */
for (base=G.scene->base.first; base; base=base->next) {
/* Check object ipos */
i= fullselect_ipo_keys(base->object->ipo);
i= count_ipo_keys(base->object->ipo, side, CFRA);
if (i) base->flag |= BA_HAS_RECALC_OB;
count += i;
/* Check object constraint ipos */
for (conchan=base->object->constraintChannels.first; conchan; conchan=conchan->next)
count += fullselect_ipo_keys(conchan->ipo);
count += count_ipo_keys(conchan->ipo, side, CFRA);
/* skip actions and nlastrips if object is collapsed */
if (base->object->nlaflag & OB_NLA_COLLAPSED)
@@ -2203,9 +2289,11 @@ static void createTransNlaData(TransInfo *t)
break;
}
if (strip==NULL) {
cfra = get_action_frame(base->object, CFRA);
for (achan=base->object->action->chanbase.first; achan; achan=achan->next) {
if (EDITABLE_ACHAN(achan)) {
i= fullselect_ipo_keys(achan->ipo);
i= count_ipo_keys(achan->ipo, side, cfra);
if (i) base->flag |= BA_HAS_RECALC_OB|BA_HAS_RECALC_DATA;
count += i;
@@ -2213,7 +2301,7 @@ static void createTransNlaData(TransInfo *t)
if (EXPANDED_ACHAN(achan) && FILTER_CON_ACHAN(achan)) {
for (conchan=achan->constraintChannels.first; conchan; conchan=conchan->next) {
if (EDITABLE_CONCHAN(conchan))
count += fullselect_ipo_keys(conchan->ipo);
count += count_ipo_keys(conchan->ipo, side, cfra);
}
}
}
@@ -2225,7 +2313,9 @@ static void createTransNlaData(TransInfo *t)
for (strip=base->object->nlastrips.first; strip; strip=strip->next) {
if (strip->flag & ACTSTRIP_SELECT) {
base->flag |= BA_HAS_RECALC_OB|BA_HAS_RECALC_DATA;
count += 2;
if (FrameOnMouseSide(side, strip->start, CFRA)) count++;
if (FrameOnMouseSide(side, strip->end, CFRA)) count++;
}
}
}
@@ -2243,12 +2333,12 @@ static void createTransNlaData(TransInfo *t)
for (base=G.scene->base.first; base; base=base->next) {
/* Manipulate object ipos */
/* - no scaling of keyframe times is allowed here */
td= IpoToTransData(td, base->object->ipo, NULL);
td= IpoToTransData(td, base->object->ipo, NULL, side, CFRA);
/* Manipulate object constraint ipos */
/* - no scaling of keyframe times is allowed here */
for (conchan=base->object->constraintChannels.first; conchan; conchan=conchan->next)
td= IpoToTransData(td, conchan->ipo, NULL);
td= IpoToTransData(td, conchan->ipo, NULL, side, CFRA);
/* skip actions and nlastrips if object collapsed */
if (base->object->nlaflag & OB_NLA_COLLAPSED)
@@ -2265,15 +2355,17 @@ static void createTransNlaData(TransInfo *t)
/* can include if no strip found */
if (strip==NULL) {
cfra = get_action_frame(base->object, CFRA);
for (achan=base->object->action->chanbase.first; achan; achan=achan->next) {
if (EDITABLE_ACHAN(achan)) {
td= IpoToTransData(td, achan->ipo, base->object);
td= IpoToTransData(td, achan->ipo, base->object, side, cfra);
/* Manipulate action constraint ipos */
if (EXPANDED_ACHAN(achan) && FILTER_CON_ACHAN(achan)) {
for (conchan=achan->constraintChannels.first; conchan; conchan=conchan->next) {
if (EDITABLE_CONCHAN(conchan))
td= IpoToTransData(td, conchan->ipo, base->object);
td= IpoToTransData(td, conchan->ipo, base->object, side, cfra);
}
}
}
@@ -2285,10 +2377,12 @@ static void createTransNlaData(TransInfo *t)
for (strip=base->object->nlastrips.first; strip; strip=strip->next) {
if (strip->flag & ACTSTRIP_SELECT) {
/* first TransData is the start, second is the end */
if (FrameOnMouseSide(side, strip->start, CFRA)) {
td->val = &strip->start;
td->ival = strip->start;
td++;
}
if (FrameOnMouseSide(side, strip->end, CFRA)) {
td->val = &strip->end;
td->ival = strip->end;
td++;
@@ -2296,6 +2390,7 @@ static void createTransNlaData(TransInfo *t)
}
}
}
}
/* **************** IpoKey stuff, for Object TransData ********** */