== Action Editor -> Auto-Snap ==

There's a new selection-box on the header of the action editor, which
sets the mode of auto-snapping for transforms. By default auto-snapping
is off.

There are 3 modes of auto-snap:
* Off - transforms per normal
* Frame Step - grid-step transform (may have errors with scaled actions)
* Nearest Frame - true snap-to-frame (takes into account nla-scaling)

These translate to the following hotkeys when transforming:
* Off - no keys press/held (as it's always been)
* Frame Step - Ctrl (as it's always been)
* Nearest Frame - Shift (replaces old shift-key behaviour which was not useful)
This commit is contained in:
Joshua Leung 2007-01-09 22:27:27 +00:00
parent 9b3862b4c0
commit 970dbb2e79
3 changed files with 104 additions and 12 deletions

@ -116,7 +116,7 @@ typedef struct SpaceAction {
View2D v2d;
bAction *action;
int flag;
short flag, autosnap;
short pin, actnr, lock, actwidth;
float timeslide;
} SpaceAction;
@ -132,6 +132,11 @@ typedef struct SpaceAction {
#define SACTION_MOVING 1 /* during transform */
#define SACTION_SLIDERS 2 /* show sliders (if relevant) - limited to shape keys for now */
/* SpaceAction AutoSnap Settings */
#define SACTSNAP_OFF 0 /* no auto-snap */
#define SACTSNAP_STEP 1 /* snap to 1.0 frame intervals */
#define SACTSNAP_FRAME 2 /* snap to actual frames (nla-action time) */
/* Pose->flag */
#define POSE_RECALC 1
#define POSE_LOCKED 2

@ -1092,6 +1092,27 @@ void transform_actionchannel_keys(int mode, int dummy)
if (!firsttime && lastcval[0]==cval[0] && lastcval[1]==cval[1]) {
PIL_sleep_ms(1);
} else {
short autosnap= 0;
/* determine mode of keyframe snapping/autosnap */
if (mode != 't') {
switch (G.saction->autosnap) {
case SACTSNAP_OFF:
if (G.qual == LR_CTRLKEY)
autosnap= SACTSNAP_STEP;
else if (G.qual == LR_SHIFTKEY)
autosnap= SACTSNAP_FRAME;
else
autosnap= SACTSNAP_OFF;
break;
case SACTSNAP_STEP:
autosnap= (G.qual==LR_CTRLKEY)? SACTSNAP_OFF: SACTSNAP_STEP;
break;
case SACTSNAP_FRAME:
autosnap= (G.qual==LR_SHIFTKEY)? SACTSNAP_OFF: SACTSNAP_FRAME;
break;
}
}
for (i=0; i<tvtot; i++){
tv[i].loc[0]=tv[i].oldloc[0];
@ -1113,11 +1134,14 @@ void transform_actionchannel_keys(int mode, int dummy)
}
break;
case 'g':
deltax = cval[0]-sval[0];
deltax = cval[0] - sval[0];
fac= deltax;
apply_keyb_grid(&fac, 0.0, 1.0, 0.1, U.flag & USER_AUTOGRABGRID);
if (autosnap == SACTSNAP_STEP) {
/* NOTE: this doesn't take into account NLA scaling */
fac= 1.0f*floor(fac/1.0f + 0.5f);
}
tv[i].loc[0]+=fac;
break;
case 's':
@ -1125,8 +1149,11 @@ void transform_actionchannel_keys(int mode, int dummy)
deltax=mvalc[0]-(ACTWIDTH/2+(curarea->winrct.xmax-curarea->winrct.xmin)/2);
fac= fabs(deltax/startx);
apply_keyb_grid(&fac, 0.0, 0.2, 0.1, U.flag & USER_AUTOSIZEGRID);
if (autosnap == SACTSNAP_STEP) {
/* NOTE: this doesn't take into account NLA scaling */
fac= 1.0f*floor(fac/1.0f + 0.5f);
}
if (invert){
if (i % 03 == 0){
memcpy (tv[i].loc, tv[i].oldloc, sizeof(tv[i+2].oldloc));
@ -1147,6 +1174,26 @@ void transform_actionchannel_keys(int mode, int dummy)
break;
}
/* snap key to nearest frame? */
if (autosnap == SACTSNAP_FRAME) {
float snapval;
/* convert frame to nla-action time (if needed) */
if (G.saction->pin==0 && OBACT)
snapval= get_action_frame_inv(OBACT, tv[i].loc[0]);
else
snapval= tv[i].loc[0];
/* snap to nearest frame */
snapval= (float)(floor(snapval+0.5));
/* convert frame out of nla-action time */
if (G.saction->pin==0 && OBACT)
tv[i].loc[0]= get_action_frame(OBACT, snapval);
else
tv[i].loc[0]= snapval;
}
}
if (mode=='s'){
@ -1308,6 +1355,28 @@ void transform_meshchannel_keys(char mode, Key *key)
if (!firsttime && lastcval[0]==cval[0] && lastcval[1]==cval[1]) {
PIL_sleep_ms(1);
} else {
short autosnap= 0;
/* determine mode of keyframe snapping/autosnap */
if (mode != 't') {
switch (G.saction->autosnap) {
case SACTSNAP_OFF:
if (G.qual == LR_CTRLKEY)
autosnap= SACTSNAP_STEP;
else if (G.qual == LR_SHIFTKEY)
autosnap= SACTSNAP_FRAME;
else
autosnap= SACTSNAP_OFF;
break;
case SACTSNAP_STEP:
autosnap= (G.qual==LR_CTRLKEY)? SACTSNAP_OFF: SACTSNAP_FRAME;
break;
case SACTSNAP_FRAME:
autosnap= (G.qual==LR_SHIFTKEY)? SACTSNAP_OFF: SACTSNAP_FRAME;
break;
}
}
for (i=0; i<tvtot; i++){
tv[i].loc[0]=tv[i].oldloc[0];
@ -1316,8 +1385,10 @@ void transform_meshchannel_keys(char mode, Key *key)
deltax = cval[0]-sval[0];
fac= deltax;
apply_keyb_grid(&fac, 0.0, 1.0, 0.1,
U.flag & USER_AUTOGRABGRID);
if (autosnap == SACTSNAP_STEP) {
/* NOTE: this doesn't take into account NLA scaling */
fac= 1.0f*floor(fac/1.0f + 0.5f);
}
tv[i].loc[0]+=fac;
break;
@ -1328,8 +1399,10 @@ void transform_meshchannel_keys(char mode, Key *key)
-curarea->winrct.xmin)/2);
fac= fabs(deltax/startx);
apply_keyb_grid(&fac, 0.0, 0.2, 0.1,
U.flag & USER_AUTOSIZEGRID);
if (autosnap == SACTSNAP_FRAME) {
/* NOTE: this doesn't take into account NLA scaling */
fac= 1.0f*floor(fac/1.0f + 0.5f);
}
if (invert){
if (i % 03 == 0){
@ -1351,6 +1424,11 @@ void transform_meshchannel_keys(char mode, Key *key)
break;
}
/* auto-snap key to nearest frame? */
if (autosnap == SACTSNAP_FRAME) {
tv[i].loc[0]= (float)(floor(tv[i].loc[0]+0.5));
}
}
}
/* Display a message showing the magnitude of

@ -1270,14 +1270,23 @@ void action_buttons(void)
uiClearButLock();
/* draw LOCK */
/* draw AUTOSNAP */
xco+= 8;
uiDefIconTextButS(block, ICONTEXTROW,B_REDR, ICON_PROP_OFF,
"Auto-Snap Keys %t|Off %x0|Frame Step %x1|Nearest Frame %x2",
xco,0,XIC+10,YIC, &(G.saction->autosnap), 0, 1, 0, 0,
"Auto-snapping mode for keys when transforming");
xco+= (XIC + 18);
/* draw LOCK*/
uiDefIconButS(block, ICONTOG, 1, ICON_UNLOCKED, xco, 0, XIC, YIC,
&(G.saction->lock), 0, 0, 0, 0,
"Updates other affected window spaces automatically "
"to reflect changes in real time");
/* always as last */
curarea->headbutlen = xco + 2*XIC;