== Action Editor - Editing Goodies ==

* Peach Request - Added Ctrl-PageUp/Down to jump to next/previous keyframe (respectively), just like elsewhere in Blender.

* As a result, Action Channel rearranging has been remapped so that:
  - Ctrl-Shift-PageUp/Down is move to top/bottom
  - Shift-PageUp/Down is move up/down

* Added a hotkey ("accentgravekey", i.e. ~/`) to toggle whether all Action Channel levels are expanded or not. This affects all visible Action Channels.

* Added Ctrl-Numpad+ and Ctrl-Numpad- to expand and collapse all Action Channel levels by one level (as appropriate). This only affect selected Action Channels.
This commit is contained in:
Joshua Leung
2008-01-09 12:07:38 +00:00
parent 048170bc6f
commit 8b78a5cf35
3 changed files with 277 additions and 43 deletions

View File

@@ -118,6 +118,7 @@ void sample_action_keys(void);
void column_select_action_keys(int mode);
void selectall_action_keys(short mval[], short mode, short selectmode);
void markers_selectkeys_between(void);
void nextprev_action_keyframe(short dir);
/* Action Data Copying */
void free_actcopybuf(void);
@@ -130,6 +131,9 @@ void down_sel_action(void);
void top_sel_action(void);
void bottom_sel_action(void);
void expand_all_action(void);
void openclose_level_action(short mode);
/* IPO/Handle Types */
void sethandles_action_keys(int code);
void action_set_ipo_flags(short mode, short event);

View File

@@ -2149,6 +2149,7 @@ void selectall_action_keys (short mval[], short mode, short select_mode)
allqueue(REDRAWIPO, 0);
}
/* Selects all visible keyframes between the specified markers */
void markers_selectkeys_between (void)
{
ListBase act_data = {NULL, NULL};
@@ -2188,6 +2189,7 @@ void markers_selectkeys_between (void)
BLI_freelistN(&act_data);
}
/* Selects all the keyframes on either side of the current frame (depends on which side the mouse is on) */
void selectkeys_leftright (short leftright, short select_mode)
{
ListBase act_data = {NULL, NULL};
@@ -2206,12 +2208,12 @@ void selectkeys_leftright (short leftright, short select_mode)
data = get_action_context(&datatype);
if (data == NULL) return;
if (leftright==1) {
if (leftright == 1) {
min = -MAXFRAMEF;
max = (float)CFRA+0.1f;
max = (float)(CFRA + 0.1f);
}
else {
min = (float)CFRA-0.1f;
min = (float)(CFRA - 0.1f);
max = MAXFRAMEF;
}
@@ -2219,7 +2221,7 @@ void selectkeys_leftright (short leftright, short select_mode)
filter= (ACTFILTER_VISIBLE | ACTFILTER_IPOKEYS);
actdata_filter(&act_data, filter, data, datatype);
/* select keys to the right */
/* select keys on the side where most data occurs */
for (ale= act_data.first; ale; ale= ale->next) {
if(NLA_ACTION_SCALED && datatype==ACTCONT_ACTION) {
actstrip_map_ipo_keys(OBACT, ale->key_data, 0, 1);
@@ -2237,22 +2239,95 @@ void selectkeys_leftright (short leftright, short select_mode)
allqueue(REDRAWNLA, 0);
allqueue(REDRAWACTION, 0);
allqueue(REDRAWIPO, 0);
}
/* ----------------------------------------- */
/* Jumps to the frame where the next/previous keyframe (that is visible) occurs
* dir: indicates direction
*/
void nextprev_action_keyframe (short dir)
{
ListBase act_data = {NULL, NULL};
bActListElem *ale;
int filter;
void *data;
short datatype;
ListBase elems= {NULL, NULL};
CfraElem *ce, *nearest=NULL;
float dist, min_dist= 1000000;
/* determine what type of data we are operating on */
data = get_action_context(&datatype);
if (data == NULL) return;
/* abort if no direction */
if (dir == 0)
return;
/* get list of keyframes that can be used (in global-time) */
filter= (ACTFILTER_VISIBLE | ACTFILTER_IPOKEYS);
actdata_filter(&act_data, filter, data, datatype);
for (ale= act_data.first; ale; ale= ale->next) {
if (NLA_ACTION_SCALED && datatype==ACTCONT_ACTION) {
actstrip_map_ipo_keys(OBACT, ale->key_data, 0, 1);
make_cfra_list(ale->key_data, &elems);
actstrip_map_ipo_keys(OBACT, ale->key_data, 1, 1);
}
else
make_cfra_list(ale->key_data, &elems);
}
BLI_freelistN(&act_data);
/* find nearest keyframe to current frame */
for (ce= elems.first; ce; ce= ce->next) {
dist= ABS(ce->cfra - CFRA);
if (dist < min_dist) {
min_dist= dist;
nearest= ce;
}
}
/* if a nearest keyframe was found, use the one either side */
if (nearest) {
short changed= 0;
if ((dir > 0) && (nearest->next)) {
CFRA= nearest->next->cfra;
changed= 1;
}
else if ((dir < 0) && (nearest->prev)) {
CFRA= nearest->prev->cfra;
changed= 1;
}
if (changed) {
update_for_newframe();
allqueue(REDRAWALL, 0);
}
}
/* free temp data */
BLI_freelistN(&elems);
}
/* ----------------------------------------- */
/* This function makes a list of the selected keyframes
* in the ipo curves it has been passed
*/
static void make_sel_cfra_list(Ipo *ipo, ListBase *elems)
static void make_sel_cfra_list (Ipo *ipo, ListBase *elems)
{
IpoCurve *icu;
if (ipo == NULL) return;
for(icu= ipo->curve.first; icu; icu= icu->next) {
for (icu= ipo->curve.first; icu; icu= icu->next) {
BezTriple *bezt;
int a= 0;
@@ -2266,7 +2341,7 @@ static void make_sel_cfra_list(Ipo *ipo, ListBase *elems)
/* This function selects all key frames in the same column(s) as a already selected key(s)
* or marker(s), or all the keyframes on a particular frame (triggered by a RMB on x-scrollbar)
*/
void column_select_action_keys(int mode)
void column_select_action_keys (int mode)
{
ListBase elems= {NULL, NULL};
CfraElem *ce;
@@ -2329,6 +2404,7 @@ void column_select_action_keys(int mode)
BLI_freelistN(&elems);
}
/* some quick defines for borderselect modes */
enum {
ACTEDIT_BORDERSEL_ALL = 0,
@@ -2713,9 +2789,9 @@ void top_sel_action ()
act = G.saction->action;
if (!act) return;
for (achan= act->chanbase.first; achan; achan= achan->next){
for (achan= act->chanbase.first; achan; achan= achan->next) {
if (VISIBLE_ACHAN(achan)) {
if (SEL_ACHAN(achan) && !(achan->flag & ACHAN_MOVED)){
if (SEL_ACHAN(achan) && !(achan->flag & ACHAN_MOVED)) {
/* take it out off the chain keep data */
BLI_remlink (&act->chanbase, achan);
/* make it first element */
@@ -2727,12 +2803,12 @@ void top_sel_action ()
}
}
/* clear temp flags */
for (achan= act->chanbase.first; achan; achan= achan->next){
for (achan= act->chanbase.first; achan; achan= achan->next) {
achan->flag = achan->flag & ~ACHAN_MOVED;
}
/* Clean up and redraw stuff */
remake_action_ipos (act);
remake_action_ipos(act);
BIF_undo_push("Top Action channel");
allspace(REMAKEIPO, 0);
allqueue(REDRAWACTION, 0);
@@ -2751,7 +2827,7 @@ void up_sel_action ()
for (achan=act->chanbase.first; achan; achan= achan->next) {
if (VISIBLE_ACHAN(achan)) {
if (SEL_ACHAN(achan) && !(achan->flag & ACHAN_MOVED)){
if (SEL_ACHAN(achan) && !(achan->flag & ACHAN_MOVED)) {
prev = achan->prev;
if (prev) {
/* take it out off the chain keep data */
@@ -2766,12 +2842,12 @@ void up_sel_action ()
}
}
/* clear temp flags */
for (achan=act->chanbase.first; achan; achan= achan->next){
for (achan=act->chanbase.first; achan; achan= achan->next) {
achan->flag = achan->flag & ~ACHAN_MOVED;
}
/* Clean up and redraw stuff */
remake_action_ipos (act);
remake_action_ipos(act);
BIF_undo_push("Up Action channel");
allspace(REMAKEIPO, 0);
allqueue(REDRAWACTION, 0);
@@ -2790,7 +2866,7 @@ void down_sel_action ()
for (achan= act->chanbase.last; achan; achan= achan->prev) {
if (VISIBLE_ACHAN(achan)) {
if (SEL_ACHAN(achan) && !(achan->flag & ACHAN_MOVED)){
if (SEL_ACHAN(achan) && !(achan->flag & ACHAN_MOVED)) {
next = achan->next;
if (next) next = next->next;
if (next) {
@@ -2811,12 +2887,12 @@ void down_sel_action ()
}
}
/* clear temp flags */
for (achan= act->chanbase.first; achan; achan= achan->next){
for (achan= act->chanbase.first; achan; achan= achan->next) {
achan->flag = achan->flag & ~ACHAN_MOVED;
}
/* Clean up and redraw stuff */
remake_action_ipos (act);
remake_action_ipos(act);
BIF_undo_push("Down Action channel");
allspace(REMAKEIPO, 0);
allqueue(REDRAWACTION, 0);
@@ -2850,7 +2926,7 @@ void bottom_sel_action ()
}
/* Clean up and redraw stuff */
remake_action_ipos (act);
remake_action_ipos(act);
BIF_undo_push("Bottom Action channel");
allspace(REMAKEIPO, 0);
allqueue(REDRAWACTION, 0);
@@ -2858,6 +2934,84 @@ void bottom_sel_action ()
allqueue(REDRAWNLA, 0);
}
/* Expand all channels to show full hierachy */
void expand_all_action (void)
{
bAction *act;
bActionChannel *achan;
short mode= 0;
/* Get the selected action, exit if none are selected */
// TODO: really this should be done with the "action editor api" stuff, but this will suffice for now
act = G.saction->action;
if (act == NULL) return;
/* check if expand all, or close all */
for (achan=act->chanbase.first; achan; achan= achan->next) {
if (VISIBLE_ACHAN(achan)) {
if (EXPANDED_ACHAN(achan))
mode= 1;
break;
}
}
/* expand/collapse depending on mode */
for (achan=act->chanbase.first; achan; achan= achan->next) {
if (VISIBLE_ACHAN(achan)) {
if (mode == 1)
achan->flag |= (ACHAN_EXPANDED|ACHAN_SHOWIPO|ACHAN_SHOWCONS);
else
achan->flag &= ~(ACHAN_EXPANDED|ACHAN_SHOWIPO|ACHAN_SHOWCONS);
}
}
/* Cleanup and do redraws */
BIF_undo_push("Expand Action Hierachy");
allqueue(REDRAWACTION, 0);
}
/* For visible channels, expand/collapse one level */
void openclose_level_action (short mode)
{
bAction *act;
bActionChannel *achan;
/* Get the selected action, exit if none are selected */
// TODO: really this should be done with the "action editor api" stuff, but this will suffice for now
act = G.saction->action;
if (act == NULL) return;
/* Abort if no operation required */
if (mode == 0) return;
/* Only affect selected channels */
for (achan=act->chanbase.first; achan; achan= achan->next) {
if (VISIBLE_ACHAN(achan) && SEL_ACHAN(achan)) {
if (EXPANDED_ACHAN(achan)) {
if (FILTER_IPO_ACHAN(achan) || FILTER_CON_ACHAN(achan)) {
if (mode < 0)
achan->flag &= ~(ACHAN_SHOWIPO|ACHAN_SHOWCONS);
}
else {
if (mode > 0)
achan->flag |= (ACHAN_SHOWIPO|ACHAN_SHOWCONS);
else
achan->flag &= ~ACHAN_EXPANDED;
}
}
else {
if (mode > 0)
achan->flag |= ACHAN_EXPANDED;
}
}
}
/* Cleanup and do redraws */
BIF_undo_push("Expand/Collapse Action Level");
allqueue(REDRAWACTION, 0);
}
/* **************************************************** */
/* ACTION MARKERS (PoseLib features) */
/* NOTE: yes, these duplicate code from edittime.c a bit, but these do a bit more...
@@ -3243,30 +3397,40 @@ void winqreadactionspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
case PAGEUPKEY:
if (datatype == ACTCONT_ACTION) {
if(G.qual & LR_SHIFTKEY)
if (G.qual == (LR_CTRLKEY|LR_SHIFTKEY))
top_sel_action();
else if (G.qual & LR_CTRLKEY)
else if (G.qual == LR_SHIFTKEY)
up_sel_action();
else if (G.qual == LR_CTRLKEY)
nextprev_action_keyframe(1);
else
nextprev_marker(1);
}
else if (datatype == ACTCONT_SHAPEKEY) {
/* only jump to markers possible (key channels can't be moved yet) */
nextprev_marker(1);
if (G.qual == LR_CTRLKEY)
nextprev_action_keyframe(1);
else
nextprev_marker(1);
}
break;
case PAGEDOWNKEY:
if (datatype == ACTCONT_ACTION) {
if(G.qual & LR_SHIFTKEY)
if (G.qual == (LR_CTRLKEY|LR_SHIFTKEY))
bottom_sel_action();
else if (G.qual & LR_CTRLKEY)
else if (G.qual == LR_SHIFTKEY)
down_sel_action();
else if (G.qual == LR_CTRLKEY)
nextprev_action_keyframe(-1);
else
nextprev_marker(-1);
}
else if (datatype == ACTCONT_SHAPEKEY) {
/* only jump to markers possible (key channels can't be moved yet) */
nextprev_marker(-1);
if (G.qual == LR_CTRLKEY)
nextprev_action_keyframe(-1);
else
nextprev_marker(-1);
}
break;
@@ -3356,20 +3520,39 @@ void winqreadactionspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
mouse_action(select_mode);
}
break;
case ACCENTGRAVEKEY:
if (datatype == ACTCONT_ACTION)
expand_all_action();
break;
case PADPLUSKEY:
view2d_zoom(G.v2d, 0.1154, sa->winx, sa->winy);
test_view2d(G.v2d, sa->winx, sa->winy);
view2d_do_locks(curarea, V2D_LOCK_COPY);
doredraw= 1;
if (G.qual == LR_CTRLKEY) {
if (datatype == ACTCONT_ACTION)
openclose_level_action(1);
}
else {
view2d_zoom(G.v2d, 0.1154, sa->winx, sa->winy);
test_view2d(G.v2d, sa->winx, sa->winy);
view2d_do_locks(curarea, V2D_LOCK_COPY);
doredraw= 1;
}
break;
case PADMINUS:
view2d_zoom(G.v2d, -0.15, sa->winx, sa->winy);
test_view2d(G.v2d, sa->winx, sa->winy);
view2d_do_locks(curarea, V2D_LOCK_COPY);
if (G.qual == LR_CTRLKEY) {
if (datatype == ACTCONT_ACTION)
openclose_level_action(-1);
}
else {
view2d_zoom(G.v2d, -0.15, sa->winx, sa->winy);
test_view2d(G.v2d, sa->winx, sa->winy);
view2d_do_locks(curarea, V2D_LOCK_COPY);
doredraw= 1;
}
break;
doredraw= 1;
break;
case MIDDLEMOUSE:
case WHEELUPMOUSE:
case WHEELDOWNMOUSE:

View File

@@ -92,8 +92,13 @@ enum {
ACTMENU_VIEW_SLIDERS,
ACTMENU_VIEW_NEXTMARKER,
ACTMENU_VIEW_PREVMARKER,
ACTMENU_VIEW_NEXTKEYFRAME,
ACTMENU_VIEW_PREVKEYFRAME,
ACTMENU_VIEW_TIME,
ACTMENU_VIEW_NOHIDE
ACTMENU_VIEW_NOHIDE,
ACTMENU_VIEW_OPENLEVELS,
ACTMENU_VIEW_CLOSELEVELS,
ACTMENU_VIEW_EXPANDALL
};
enum {
@@ -286,7 +291,7 @@ static void do_action_viewmenu(void *arg, int event)
break;
case ACTMENU_VIEW_LOCK:
G.v2d->flag ^= V2D_VIEWLOCK;
if(G.v2d->flag & V2D_VIEWLOCK)
if (G.v2d->flag & V2D_VIEWLOCK)
view2d_do_locks(curarea, 0);
break;
case ACTMENU_VIEW_SLIDERS: /* Show sliders (when applicable) */
@@ -295,10 +300,10 @@ static void do_action_viewmenu(void *arg, int event)
case ACTMENU_VIEW_MAXIMIZE: /* Maximize Window */
/* using event B_FULL */
break;
case ACTMENU_VIEW_NEXTMARKER: /* jump to next marker */
case ACTMENU_VIEW_NEXTMARKER: /* Jump to next marker */
nextprev_marker(1);
break;
case ACTMENU_VIEW_PREVMARKER: /* jump to previous marker */
case ACTMENU_VIEW_PREVMARKER: /* Jump to previous marker */
nextprev_marker(-1);
break;
case ACTMENU_VIEW_TIME: /* switch between frames and seconds display */
@@ -307,6 +312,21 @@ static void do_action_viewmenu(void *arg, int event)
case ACTMENU_VIEW_NOHIDE: /* Show hidden channels */
G.saction->flag ^= SACTION_NOHIDE;
break;
case ACTMENU_VIEW_NEXTKEYFRAME: /* Jump to next keyframe */
nextprev_action_keyframe(1);
break;
case ACTMENU_VIEW_PREVKEYFRAME: /* Jump to previous keyframe */
nextprev_action_keyframe(-1);
break;
case ACTMENU_VIEW_OPENLEVELS: /* Unfold channels one step */
openclose_level_action(1);
break;
case ACTMENU_VIEW_CLOSELEVELS: /* Fold channels one step */
openclose_level_action(-1);
break;
case ACTMENU_VIEW_EXPANDALL: /* Expands all channels */
expand_all_action();
break;
}
allqueue(REDRAWVIEW3D, 0);
}
@@ -363,6 +383,26 @@ static uiBlock *action_viewmenu(void *arg_unused)
menuwidth, 19, NULL, 0.0, 0.0, 1,
ACTMENU_VIEW_AUTOUPDATE, "");
uiDefBut(block, SEPR, 0, "", 0, yco-=6,
menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
/* only if editing action... */
// TODO: improve this code!
if (G.saction->action) {
uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1,
"Toggle Show Hierachy|~", 0, yco-=20,
menuwidth, 19, NULL, 0.0, 0.0, 0, ACTMENU_VIEW_EXPANDALL, "");
uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1,
"Expand One Level|Ctrl NumPad+", 0, yco-=20,
menuwidth, 19, NULL, 0.0, 0.0, 0, ACTMENU_VIEW_OPENLEVELS, "");
uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1,
"Collapse One Level|Ctrl NumPad-", 0, yco-=20,
menuwidth, 19, NULL, 0.0, 0.0, 0, ACTMENU_VIEW_CLOSELEVELS, "");
}
uiDefBut(block, SEPR, 0, "", 0, yco-=6,
menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
@@ -372,6 +412,13 @@ static uiBlock *action_viewmenu(void *arg_unused)
uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1,
"Jump To Prev Marker|PageDown", 0, yco-=20,
menuwidth, 19, NULL, 0.0, 0.0, 0, ACTMENU_VIEW_PREVMARKER, "");
uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1,
"Jump To Next Keyframe|Ctrl PageUp", 0, yco-=20,
menuwidth, 19, NULL, 0.0, 0.0, 0, ACTMENU_VIEW_NEXTKEYFRAME, "");
uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1,
"Jump To Prev Keyframe|Ctrl PageDown", 0, yco-=20,
menuwidth, 19, NULL, 0.0, 0.0, 0, ACTMENU_VIEW_PREVKEYFRAME, "");
uiDefBut(block, SEPR, 0, "", 0, yco-=6,
menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
@@ -850,11 +897,11 @@ static uiBlock *action_keymenu_chanposmenu(void *arg_unused)
uiBlockSetButmFunc(block, do_action_keymenu_chanposmenu, NULL);
uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1,
"Move Up|Ctrl Page Up", 0, yco-=20,
"Move Up|Shift Page Up", 0, yco-=20,
menuwidth, 19, NULL, 0.0, 0.0, 0,
ACTMENU_KEY_CHANPOS_MOVE_CHANNEL_UP, "");
uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1,
"Move Down|Ctrl Page Down", 0, yco-=20,
"Move Down|Shift Page Down", 0, yco-=20,
menuwidth, 19, NULL, 0.0, 0.0, 0,
ACTMENU_KEY_CHANPOS_MOVE_CHANNEL_DOWN, "");
@@ -862,11 +909,11 @@ static uiBlock *action_keymenu_chanposmenu(void *arg_unused)
menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1,
"Move to Top|Shift Page Up", 0, yco-=20,
"Move to Top|Ctrl Shift Page Up", 0, yco-=20,
menuwidth, 19, NULL, 0.0, 0.0, 0,
ACTMENU_KEY_CHANPOS_MOVE_CHANNEL_TOP, "");
uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1,
"Move to Bottom|Shift Page Down", 0, yco-=20,
"Move to Bottom|Ctrl Shift Page Down", 0, yco-=20,
menuwidth, 19, NULL, 0.0, 0.0, 0,
ACTMENU_KEY_CHANPOS_MOVE_CHANNEL_BOTTOM, "");