From eca167fbcaac33beb7976452aa55ed2963665f3c Mon Sep 17 00:00:00 2001 From: Chris Want Date: Thu, 30 Jan 2003 06:19:49 +0000 Subject: Extra selection support for the action window, including: - border select initiated in the channel names border selects the channels and constraint channels. - right click or border select initiated in the horizontal scroll causes blender to select all keys for the selected frames. - right click or border select in the vertical scroll causes blender to select all keys for the channel or constraint channels that are to the left of the selection. --- source/blender/include/BSE_editipo.h | 5 + source/blender/src/editaction.c | 535 ++++++++++++++++++++++++++++------- source/blender/src/editipo.c | 199 +++++++++++-- source/blender/src/editnla.c | 51 ++-- 4 files changed, 649 insertions(+), 141 deletions(-) diff --git a/source/blender/include/BSE_editipo.h b/source/blender/include/BSE_editipo.h index 938b228a84e..40650b6f27f 100644 --- a/source/blender/include/BSE_editipo.h +++ b/source/blender/include/BSE_editipo.h @@ -98,6 +98,7 @@ void join_ipo(void); void ipo_snapmenu(void); void mouse_select_ipo(void); void sethandles_ipo(int code); +void select_ipo_bezier_keys(struct Ipo *ipo, int selectmode); void set_ipotype(void); void borderselect_ipo(void); void del_ipo(void); @@ -140,6 +141,10 @@ int add_trans_ipo_keys(struct Ipo *ipo, struct TransVert *tv, int tvtot); void duplicate_ipo_keys(struct Ipo *ipo); void borderselect_ipo_key(struct Ipo *ipo, float xmin, float xmax, int val); void select_ipo_key(struct Ipo *ipo, float selx, int sel); +void select_icu_key(struct IpoCurve *icu, float selx, int selectmode); +int select_bezier_add(struct BezTriple *bezt); +int select_bezier_subtract(struct BezTriple *bezt); +int select_bezier_invert(struct BezTriple *bezt); #endif /* BSE_EDITIPO_H */ diff --git a/source/blender/src/editaction.c b/source/blender/src/editaction.c index 1289b44a0b0..1eb06c398f4 100644 --- a/source/blender/src/editaction.c +++ b/source/blender/src/editaction.c @@ -105,9 +105,10 @@ extern int count_action_levels (bAction *act); static void insertactionkey(bAction *act, bActionChannel *achan, bPoseChannel *chan, int adrcode, short makecurve, float time); static void flip_name (char *name); -static void mouse_actionchannels(bAction *act, short *mval); +static void mouse_actionchannels(bAction *act, short *mval, + short *mvalo, int selectmode); static void borderselect_action(void); -static void mouse_action(void); +static void mouse_action(int selectmode); static bActionChannel *get_nearest_actionchannel_key (float *index, short *sel, bConstraintChannel **conchan); static void delete_actionchannels(void); static void delete_actionchannel_keys(void); @@ -397,7 +398,7 @@ static bActionChannel *get_nearest_actionchannel_key (float *index, short *sel, return firstchan; } -static void mouse_action(void) +static void mouse_action(int selectmode) { bAction *act; short sel; @@ -415,19 +416,22 @@ static void mouse_action(void) chan=get_nearest_actionchannel_key(&selx, &sel, &conchan); if (chan){ - if (!(G.qual & LR_SHIFTKEY)){ + if (selectmode == SELECT_REPLACE) { + if (sel == 0) + selectmode = SELECT_ADD; + else + selectmode = SELECT_SUBTRACT; deselect_actionchannel_keys(act, 0); deselect_actionchannels(act, 0); act->achan = chan; chan->flag |= ACHAN_SELECTED; hilight_channel (act, chan, 1); - sel = 0; } if (conchan) - select_ipo_key(conchan->ipo, selx, sel); + select_ipo_key(conchan->ipo, selx, selectmode); else - select_ipo_key(chan->ipo, selx, sel); + select_ipo_key(chan->ipo, selx, selectmode); allqueue(REDRAWIPO, 0); allqueue(REDRAWVIEW3D, 0); @@ -441,7 +445,7 @@ static void borderselect_action(void) { rcti rect; rctf rectf; - int val; + int val, selectmode; short mval[2]; bActionChannel *chan; bConstraintChannel *conchan; @@ -449,12 +453,17 @@ static void borderselect_action(void) float ymin, ymax; act=G.saction->action; - val= get_border (&rect, 3); + if (!act) return; - if (val){ + if ( (val = get_border(&rect, 3)) ){ + if (val == LEFTMOUSE) + selectmode = SELECT_ADD; + else + selectmode = SELECT_SUBTRACT; + mval[0]= rect.xmin; mval[1]= rect.ymin+2; areamouseco_to_ipoco(G.v2d, mval, &rectf.xmin, &rectf.ymin); @@ -468,15 +477,17 @@ static void borderselect_action(void) /* Check action */ ymin=ymax-(CHANNELHEIGHT+CHANNELSKIP); if (!((ymax < rectf.ymin) || (ymin > rectf.ymax))) - borderselect_ipo_key(chan->ipo, rectf.xmin, rectf.xmax, val); - + borderselect_ipo_key(chan->ipo, rectf.xmin, rectf.xmax, + selectmode); + ymax=ymin; /* Check constraints */ for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next){ ymin=ymax-(CHANNELHEIGHT+CHANNELSKIP); if (!((ymax < rectf.ymin) || (ymin > rectf.ymax))) - borderselect_ipo_key(conchan->ipo, rectf.xmin, rectf.xmax, val); + borderselect_ipo_key(conchan->ipo, rectf.xmin, rectf.xmax, + selectmode); ymax=ymin; } @@ -1115,111 +1126,159 @@ static void hilight_channel (bAction *act, bActionChannel *chan, short select) } } -static void mouse_actionchannels(bAction *act, short *mval) -{ +static int select_channel(bAction *act, bActionChannel *chan, + int selectmode) { + /* Select the channel based on the selection mode + */ + int flag; + + switch (selectmode) { + case SELECT_ADD: + chan->flag |= ACHAN_SELECTED; + break; + case SELECT_SUBTRACT: + chan->flag &= ~ACHAN_SELECTED; + break; + case SELECT_INVERT: + chan->flag ^= ACHAN_SELECTED; + break; + } + flag = (chan->flag & ACHAN_SELECTED) ? 1 : 0; + + hilight_channel(act, chan, flag); + select_poseelement_by_name(chan->name, flag); + + return flag; +} + +static int select_constraint_channel(bAction *act, + bConstraintChannel *conchan, + int selectmode) { + /* Select the constraint channel based on the selection mode + */ + int flag; + + switch (selectmode) { + case SELECT_ADD: + conchan->flag |= CONSTRAINT_CHANNEL_SELECT; + break; + case SELECT_SUBTRACT: + conchan->flag &= ~CONSTRAINT_CHANNEL_SELECT; + break; + case SELECT_INVERT: + conchan->flag ^= CONSTRAINT_CHANNEL_SELECT; + break; + } + flag = (conchan->flag & CONSTRAINT_CHANNEL_SELECT) ? 1 : 0; + + return flag; +} + + +static void mouse_actionchannels(bAction *act, short *mval, + short *mvalo, int selectmode) { + /* Select action channels, based on mouse values. + * If mvalo is NULL we assume it is a one click + * action, other wise we treat it like it is a + * border select with mval[0],mval[1] and + * mvalo[0], mvalo[1] forming the corners of + * a rectangle. + */ bActionChannel *chan; - bConstraintChannel *clickconchan=NULL; float click; - int wsize; - int sel; + int clickmin, clickmax; + int wsize, sel; bConstraintChannel *conchan; - + if (!act) return; + + if (selectmode == SELECT_REPLACE) { + deselect_actionchannels (act, 0); + selectmode = SELECT_ADD; + } + /* wsize is the greatest possible height (in pixels) that would be + * needed to draw all of the action channels and constraint + * channels. + */ wsize = (count_action_levels (act)*(CHANNELHEIGHT+CHANNELSKIP)); - click = (wsize-(mval[1]+G.v2d->cur.ymin)); click += CHANNELHEIGHT/2; click /= (CHANNELHEIGHT+CHANNELSKIP); + + clickmin = (int) click; - if (click<0) + /* Only one click */ + if (mvalo == NULL) { + clickmax = clickmin; + } + /* Two click values (i.e., border select */ + else { + click = (wsize-(mvalo[1]+G.v2d->cur.ymin)); + click += CHANNELHEIGHT/2; + click /= (CHANNELHEIGHT+CHANNELSKIP); + + if ( ((int) click) < clickmin) { + clickmax = clickmin; + clickmin = (int) click; + } + else { + clickmax = (int) click; + } + } + + if (clickmax < 0) { return; + } - for (chan = act->chanbase.first; chan; chan=chan->next){ - if ((int)click==0) - break; + /* clickmin and clickmax now coorespond to indices into + * the collection of channels and constraint channels. + * What we need to do is apply the selection mode on all + * channels and constraint channels between these indices. + * This is done by traversing the channels and constraint + * channels, for each item decrementing clickmin and clickmax. + * When clickmin is less than zero we start selecting stuff, + * until clickmax is less than zero or we run out of channels + * and constraint channels. + */ - click--; + for (chan = act->chanbase.first; chan; chan=chan->next){ + if (clickmax < 0) break; - /* Check for click in a constraint */ - for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next){ - if ((int)click==0){ - clickconchan=conchan; - chan=act->chanbase.last; - break; + if ( clickmin <= 0) { + /* Select the channel with the given mode. If the + * channel is freshly selected then set it to the + * active channel for the action + */ + sel = (chan->flag & ACHAN_SELECTED); + if ( select_channel(act, chan, selectmode) && !sel ) { + act->achan = chan; } - click--; } - } + --clickmin; + --clickmax; - if (!chan){ - if (clickconchan){ - if (clickconchan->flag & CONSTRAINT_CHANNEL_SELECT) - sel = 0; - else - sel =1; - - /* Channel names clicking */ - if (G.qual & LR_SHIFTKEY){ - // select_poseelement_by_name(chan->name, !(chan->flag & ACHAN_SELECTED)); - if (clickconchan->flag & CONSTRAINT_CHANNEL_SELECT){ - clickconchan->flag &= ~CONSTRAINT_CHANNEL_SELECT; - // hilight_channel(act, chan, 0); - } - else{ - clickconchan->flag |= CONSTRAINT_CHANNEL_SELECT; - // hilight_channel(act, chan, 1); - } - } - else{ - deselect_actionchannels (act, 0); // Auto clear - clickconchan->flag |= CONSTRAINT_CHANNEL_SELECT; - // hilight_channel(act, chan, 1); - // act->achan = chan; - // select_poseelement_by_name(chan->name, 1); + /* Check for click in a constraint */ + for (conchan=chan->constraintChannels.first; + conchan; conchan=conchan->next){ + if (clickmax < 0) break; + if ( clickmin <= 0) { + select_constraint_channel(act, conchan, selectmode); } - + --clickmin; + --clickmax; } - else - return; } - else{ - /* Choose the mode */ - if (chan->flag & ACHAN_SELECTED) - sel = 0; - else - sel =1; - - /* Channel names clicking */ - if (G.qual & LR_SHIFTKEY){ - select_poseelement_by_name(chan->name, !(chan->flag & ACHAN_SELECTED)); - if (chan->flag & ACHAN_SELECTED){ - chan->flag &= ~ACHAN_SELECTED; - hilight_channel(act, chan, 0); - } - else{ - chan->flag |= ACHAN_SELECTED; - hilight_channel(act, chan, 1); - } - } - else{ - deselect_actionchannels (act, 0); // Auto clear - chan->flag |= ACHAN_SELECTED; - hilight_channel(act, chan, 1); - act->achan = chan; - select_poseelement_by_name(chan->name, 1); - } - } allqueue (REDRAWIPO, 0); allqueue (REDRAWVIEW3D, 0); allqueue (REDRAWACTION, 0); - allqueue(REDRAWNLA, 0); - + allqueue (REDRAWNLA, 0); } + static void delete_actionchannel_keys(void) { bAction *act; @@ -1376,6 +1435,221 @@ static void set_ipotype_actionchannels(void) { allqueue(REDRAWNLA, 0); } +void select_all_keys_frames(bAction *act, short *mval, + short *mvalo, int selectmode) { + + /* This function tries to select all action keys in + * every channel for a given range of keyframes that + * are within the mouse values mval and mvalo (usually + * the result of a border select). If mvalo is passed as + * NULL then the selection is treated as a one-click and + * the function tries to select all keys within half a + * frame of the click point. + */ + + rcti rect; + rctf rectf; + bActionChannel *chan; + bConstraintChannel *conchan; + + if (!act) + return; + + if (selectmode == SELECT_REPLACE) { + deselect_actionchannel_keys(act, 0); + selectmode = SELECT_ADD; + } + + if (mvalo == NULL) { + rect.xmin = rect.xmax = mval[0]; + rect.ymin = rect.ymax = mval[1]; + } + else { + if (mval[0] < mvalo[0] ) { + rect.xmin = mval[0]; + rect.xmax = mvalo[0]; + } + else { + rect.xmin = mvalo[0]; + rect.xmax = mval[0]; + } + if (mval[1] < mvalo[1] ) { + rect.ymin = mval[1]; + rect.ymax = mvalo[1]; + } + else { + rect.ymin = mvalo[1]; + rect.ymax = mval[1]; + } + } + + mval[0]= rect.xmin; + mval[1]= rect.ymin+2; + areamouseco_to_ipoco(G.v2d, mval, &rectf.xmin, &rectf.ymin); + mval[0]= rect.xmax; + mval[1]= rect.ymax-2; + areamouseco_to_ipoco(G.v2d, mval, &rectf.xmax, &rectf.ymax); + + if (mvalo == NULL) { + rectf.xmin = rectf.xmin - 0.5; + rectf.xmax = rectf.xmax + 0.5; + } + + for (chan=act->chanbase.first; chan; chan=chan->next){ + borderselect_ipo_key(chan->ipo, rectf.xmin, rectf.xmax, + selectmode); + for (conchan=chan->constraintChannels.first; conchan; + conchan=conchan->next){ + borderselect_ipo_key(conchan->ipo, rectf.xmin, rectf.xmax, + selectmode); + } + } + allqueue(REDRAWNLA, 0); + allqueue(REDRAWACTION, 0); + allqueue(REDRAWIPO, 0); +} + + +void select_all_keys_channels(bAction *act, short *mval, + short *mvalo, int selectmode) { + bActionChannel *chan; + float click; + int clickmin, clickmax; + int wsize; + bConstraintChannel *conchan; + + /* This function selects all the action keys that + * are in the mouse selection range defined by + * the ordered pairs mval and mvalo (usually + * these 2 are obtained from a border select). + * If mvalo is NULL, then the selection is + * treated like a one-click action, and at most + * one channel is selected. + */ + + /* If the action is null then abort + */ + if (!act) + return; + + if (selectmode == SELECT_REPLACE) { + deselect_actionchannel_keys(act, 0); + selectmode = SELECT_ADD; + } + + /* wsize is the greatest possible height (in pixels) that would be + * needed to draw all of the action channels and constraint + * channels. + */ + wsize = (count_action_levels (act)*(CHANNELHEIGHT+CHANNELSKIP)); + + click = (wsize-(mval[1]+G.v2d->cur.ymin)); + click += CHANNELHEIGHT/2; + click /= (CHANNELHEIGHT+CHANNELSKIP); + + clickmin = (int) click; + + /* Only one click */ + if (mvalo == NULL) { + clickmax = clickmin; + } + /* Two click values (i.e., border select) */ + else { + click = (wsize-(mvalo[1]+G.v2d->cur.ymin)); + click += CHANNELHEIGHT/2; + click /= (CHANNELHEIGHT+CHANNELSKIP); + + if ( ((int) click) < clickmin) { + clickmax = clickmin; + clickmin = (int) click; + } + else { + clickmax = (int) click; + } + } + + if (clickmax < 0) { + return; + } + + for (chan = act->chanbase.first; chan; chan=chan->next){ + if (clickmax < 0) break; + + if ( clickmin <= 0) { + /* Select the channel with the given mode. If the + * channel is freshly selected then set it to the + * active channel for the action + */ + select_ipo_bezier_keys(chan->ipo, selectmode); + } + --clickmin; + --clickmax; + + /* Check for click in a constraint */ + for (conchan=chan->constraintChannels.first; + conchan; conchan=conchan->next){ + if (clickmax < 0) break; + if ( clickmin <= 0) { + select_ipo_bezier_keys(chan->ipo, selectmode); + } + --clickmin; + --clickmax; + } + } + + allqueue (REDRAWIPO, 0); + allqueue (REDRAWVIEW3D, 0); + allqueue (REDRAWACTION, 0); + allqueue (REDRAWNLA, 0); + +} + +static void borderselect_function(void (*select_func)(bAction *act, + short *mval, + short *mvalo, + int selectmode)) { + /* This function executes an arbitrary selection + * function as part of a border select. This + * way the same function that is used for + * right click selection points can generally + * be used as the argument to this function + */ + rcti rect; + short mval[2], mvalo[2]; + bAction *act; + int val; + + /* Get the selected action, exit if none are selected + */ + act=G.saction->action; + if (!act) + return; + + /* Let the user draw a border (or abort) + */ + if ( (val=get_border (&rect, 3)) ) { + mval[0]= rect.xmin; + mval[1]= rect.ymin+2; + mvalo[0]= rect.xmax; + mvalo[1]= rect.ymax-2; + + /* if the left mouse was used, do an additive + * selection with the user defined selection + * function. + */ + if (val == LEFTMOUSE) + select_func(act, mval, mvalo, SELECT_ADD); + + /* if the right mouse was used, do a subtractive + * selection with the user defined selection + * function. + */ + else if (val == RIGHTMOUSE) + select_func(act, mval, mvalo, SELECT_SUBTRACT); + } + +} + void winqreadactionspace(unsigned short event, short val, char ascii) { SpaceAction *saction; @@ -1465,14 +1739,85 @@ void winqreadactionspace(unsigned short event, short val, char ascii) break; case BKEY: - borderselect_action(); + /* If the border select is initiated in the + * part of the action window where the channel + * names reside, then select the channels + */ + if (mval[0]ACTWIDTH){ do { diff --git a/source/blender/src/editipo.c b/source/blender/src/editipo.c index 0f2f10c7eff..d1b5585824a 100644 --- a/source/blender/src/editipo.c +++ b/source/blender/src/editipo.c @@ -2790,6 +2790,36 @@ int selected_bezier_loop(int (*looptest)(EditIpo *), return 0; } +int select_bezier_add(BezTriple *bezt) { + /* Select the bezier triple */ + bezt->f1 |= 1; + bezt->f2 |= 1; + bezt->f3 |= 1; + return 0; +} + +int select_bezier_subtract(BezTriple *bezt) { + /* Deselect the bezier triple */ + bezt->f1 &= ~1; + bezt->f2 &= ~1; + bezt->f3 &= ~1; + return 0; +} + +int select_bezier_invert(BezTriple *bezt) { + /* Invert the selection for the bezier triple */ + bezt->f2 ^= 1; + if ( bezt->f2 & 1 ) { + bezt->f1 |= 1; + bezt->f3 |= 1; + } + else { + bezt->f1 &= ~1; + bezt->f3 &= ~1; + } + return 0; +} + int set_bezier_auto(BezTriple *bezt) { /* Sets the selected bezier handles to type 'auto' @@ -2877,6 +2907,25 @@ int vis_edit_icu_bez(EditIpo *ei) { return ISPOIN4(ei, flag & IPO_VISIBLE, flag & IPO_EDIT, icu, icu->bezt); } +void select_ipo_bezier_keys(Ipo *ipo, int selectmode) +{ + /* Select all of the beziers in all + * of the Ipo curves belonging to the + * Ipo, using the selection mode. + */ + switch (selectmode) { + case SELECT_ADD: + ipo_keys_bezier_loop(ipo, select_bezier_add, NULL); + break; + case SELECT_SUBTRACT: + ipo_keys_bezier_loop(ipo, select_bezier_subtract, NULL); + break; + case SELECT_INVERT: + ipo_keys_bezier_loop(ipo, select_bezier_invert, NULL); + break; + } +} + void sethandles_ipo_keys(Ipo *ipo, int code) { /* this function lets you set bezier handles all to @@ -5426,54 +5475,152 @@ void duplicate_ipo_keys(Ipo *ipo) } } -void borderselect_ipo_key(Ipo *ipo, float xmin, float xmax, int val) +void borderselect_icu_key(IpoCurve *icu, float xmin, float xmax, + int (*select_function)(BezTriple *)) { + /* Selects all bezier triples in the Ipocurve + * between times xmin and xmax, using the selection + * function. + */ + int i; + + /* loop through all of the bezier triples in + * the Ipocurve -- if the triple occurs between + * times xmin and xmax then select it using the selection + * function + */ + for (i=0; itotvert; i++){ + if (icu->bezt[i].vec[1][0] > xmin && icu->bezt[i].vec[1][0] < xmax ){ + select_function(&(icu->bezt[i])); + } + } +} + +void borderselect_ipo_key(Ipo *ipo, float xmin, float xmax, int selectmode) +{ + /* Selects all bezier triples in each Ipocurve of the + * Ipo between times xmin and xmax, using the selection mode. + */ + IpoCurve *icu; + int (*select_function)(BezTriple *); + /* If the ipo is no good then return */ if (!ipo) return; + /* Set the selection function based on the + * selection mode. + */ + switch(selectmode) { + case SELECT_ADD: + select_function = select_bezier_add; + break; + case SELECT_SUBTRACT: + select_function = select_bezier_subtract; + break; + case SELECT_INVERT: + select_function = select_bezier_invert; + break; + default: + return; + } + + /* loop through all of the bezier triples in all + * of the Ipocurves -- if the triple occurs between + * times xmin and xmax then select it using the selection + * function + */ for (icu=ipo->curve.first; icu; icu=icu->next){ - for (i=0; itotvert; i++){ - if (icu->bezt[i].vec[1][0] > xmin && icu->bezt[i].vec[1][0] < xmax ){ - if (val==1){ - icu->bezt[i].f1 |= 1; - icu->bezt[i].f2 |= 1; - icu->bezt[i].f3 |= 1; - } - else{ - icu->bezt[i].f1 &= ~1; - icu->bezt[i].f2 &= ~1; - icu->bezt[i].f3 &= ~1; - } - } - } + borderselect_icu_key(icu, xmin, xmax, select_function); } } -void select_ipo_key(Ipo *ipo, float selx, int sel) +void select_ipo_key(Ipo *ipo, float selx, int selectmode) { + /* Selects all bezier triples in each Ipocurve of the + * Ipo at time selx, using the selection mode. + */ int i; IpoCurve *icu; + int (*select_function)(BezTriple *); + /* If the ipo is no good then return */ if (!ipo) return; + /* Set the selection function based on the + * selection mode. + */ + switch(selectmode) { + case SELECT_ADD: + select_function = select_bezier_add; + break; + case SELECT_SUBTRACT: + select_function = select_bezier_subtract; + break; + case SELECT_INVERT: + select_function = select_bezier_invert; + break; + default: + return; + } + + /* loop through all of the bezier triples in all + * of the Ipocurves -- if the triple occurs at + * time selx then select it using the selection + * function + */ for (icu=ipo->curve.first; icu; icu=icu->next){ for (i=0; itotvert; i++){ if (icu->bezt[i].vec[1][0]==selx){ - if (sel) { - icu->bezt[i].f1 &= ~1; - icu->bezt[i].f2 &= ~1; - icu->bezt[i].f3 &= ~1; - } - else { - icu->bezt[i].f1 |= 1; - icu->bezt[i].f2 |= 1; - icu->bezt[i].f3 |= 1; - } + select_function(&(icu->bezt[i])); } } } } + +void select_icu_key(IpoCurve *icu, float selx, int selectmode) +{ + /* Selects all bezier triples in the Ipocurve + * at time selx, using the selection mode. + * This is kind of sloppy the obvious similarities + * with the above function, forgive me ... + */ + int i; + int (*select_function)(BezTriple *); + + /* If the icu is no good then return */ + if (!icu) + return; + + /* Set the selection function based on the + * selection mode. + */ + switch(selectmode) { + case SELECT_ADD: + select_function = select_bezier_add; + break; + case SELECT_SUBTRACT: + select_function = select_bezier_subtract; + break; + case SELECT_INVERT: + select_function = select_bezier_invert; + break; + default: + return; + } + + /* loop through all of the bezier triples in + * the Ipocurve -- if the triple occurs at + * time selx then select it using the selection + * function + */ + for (i=0; itotvert; i++){ + if (icu->bezt[i].vec[1][0]==selx){ + select_function(&(icu->bezt[i])); + } + } + +} diff --git a/source/blender/src/editnla.c b/source/blender/src/editnla.c index 66311538ac4..d12ce9ca71e 100644 --- a/source/blender/src/editnla.c +++ b/source/blender/src/editnla.c @@ -101,7 +101,7 @@ static void delete_nlachannel_keys(void); static void delete_nlachannels(void); static void duplicate_nlachannel_keys(void); static void borderselect_nla(void); -static void mouse_nla(void); +static void mouse_nla(int selectmode); static Base *get_nearest_nlachannel_ob_key (float *index, short *sel); static bAction *get_nearest_nlachannel_ac_key (float *index, short *sel); static Base *get_nearest_nlastrip (bActionStrip **rstrip, short *sel); @@ -200,8 +200,12 @@ int calc_memleak (void* ptr){ } break; case RIGHTMOUSE: - if (mval[0]>=NLAWIDTH) - mouse_nla(); + if (mval[0]>=NLAWIDTH) { + if(G.qual & LR_SHIFTKEY) + mouse_nla(SELECT_INVERT); + else + mouse_nla(SELECT_REPLACE); + } else mouse_nlachannels(mval); break; @@ -1034,15 +1038,18 @@ static void borderselect_nla(void) Base *base; rcti rect; rctf rectf; - int val; + int val, selectmode; short mval[2]; float ymin, ymax; bActionStrip *strip; bConstraintChannel *conchan; - val= get_border (&rect, 3); - - if (val){ + if ( (val = get_border (&rect, 3)) ){ + if (val == LEFTMOUSE) + selectmode = SELECT_ADD; + else + selectmode = SELECT_SUBTRACT; + mval[0]= rect.xmin; mval[1]= rect.ymin+2; areamouseco_to_ipoco(G.v2d, mval, &rectf.xmin, &rectf.ymin); @@ -1059,7 +1066,8 @@ static void borderselect_nla(void) ymin=ymax-(NLACHANNELHEIGHT+NLACHANNELSKIP); if (base->object->ipo){ if (!((ymax < rectf.ymin) || (ymin > rectf.ymax))) - borderselect_ipo_key(base->object->ipo, rectf.xmin, rectf.xmax, val); + borderselect_ipo_key(base->object->ipo, rectf.xmin, rectf.xmax, + selectmode); } ymax=ymin; @@ -1067,7 +1075,8 @@ static void borderselect_nla(void) for (conchan=base->object->constraintChannels.first; conchan; conchan=conchan->next){ ymin=ymax-(NLACHANNELHEIGHT+NLACHANNELSKIP); if (!((ymax < rectf.ymin) || (ymin > rectf.ymax))) - borderselect_ipo_key(conchan->ipo, rectf.xmin, rectf.xmax, val); + borderselect_ipo_key(conchan->ipo, rectf.xmin, rectf.xmax, + selectmode); ymax=ymin; } @@ -1079,10 +1088,12 @@ static void borderselect_nla(void) if (!((ymax < rectf.ymin) || (ymin > rectf.ymax))){ for (chan=base->object->action->chanbase.first; chan; chan=chan->next){ - borderselect_ipo_key(chan->ipo, rectf.xmin, rectf.xmax, val); + borderselect_ipo_key(chan->ipo, rectf.xmin, rectf.xmax, + selectmode); /* Check action constraint ipos */ for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next) - borderselect_ipo_key(conchan->ipo, rectf.xmin, rectf.xmax, val); + borderselect_ipo_key(conchan->ipo, rectf.xmin, rectf.xmax, + selectmode); } } } @@ -1115,7 +1126,7 @@ static void borderselect_nla(void) } } -static void mouse_nla(void) +static void mouse_nla(int selectmode) { short sel; float selx; @@ -1131,16 +1142,16 @@ static void mouse_nla(void) /* Try object ipo selection */ base=get_nearest_nlachannel_ob_key(&selx, &sel); if (base){ - if (!(G.qual & LR_SHIFTKEY)){ + if (selectmode == SELECT_REPLACE){ deselect_nlachannel_keys(0); - sel = 0; + selectmode = SELECT_ADD; } - select_ipo_key(base->object->ipo, selx, sel); + select_ipo_key(base->object->ipo, selx, selectmode); /* Try object constraint selection */ for (conchan=base->object->constraintChannels.first; conchan; conchan=conchan->next) - select_ipo_key(conchan->ipo, selx, sel); + select_ipo_key(conchan->ipo, selx, selectmode); allqueue(REDRAWIPO, 0); @@ -1152,16 +1163,16 @@ static void mouse_nla(void) /* Try action ipo selection */ act=get_nearest_nlachannel_ac_key(&selx, &sel); if (act){ - if (!(G.qual & LR_SHIFTKEY)){ + if (selectmode == SELECT_REPLACE){ deselect_nlachannel_keys(0); - sel = 0; + selectmode = SELECT_ADD; } for (chan=act->chanbase.first; chan; chan=chan->next){ - select_ipo_key(chan->ipo, selx, sel); + select_ipo_key(chan->ipo, selx, selectmode); /* Try action constraint selection */ for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next) - select_ipo_key(conchan->ipo, selx, sel); + select_ipo_key(conchan->ipo, selx, selectmode); } allqueue(REDRAWIPO, 0); -- cgit v1.2.3