Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Want <cwant@ualberta.ca>2003-01-30 09:19:49 +0300
committerChris Want <cwant@ualberta.ca>2003-01-30 09:19:49 +0300
commiteca167fbcaac33beb7976452aa55ed2963665f3c (patch)
treed4f7b4269f02a210372fcf61c3ba9961f198ecab
parente250a269473639b887f406bd386a03577aef5edf (diff)
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.
-rw-r--r--source/blender/include/BSE_editipo.h5
-rw-r--r--source/blender/src/editaction.c535
-rw-r--r--source/blender/src/editipo.c199
-rw-r--r--source/blender/src/editnla.c51
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){
+ borderselect_function(mouse_actionchannels);
+ }
+
+ /* If the border select is initiated in the
+ * vertical scrollbar, then (de)select all keys
+ * for the channels in the selection region
+ */
+ else if (IN_2D_VERT_SCROLL(mval)) {
+ borderselect_function(select_all_keys_channels);
+ }
+
+ /* If the border select is initiated in the
+ * horizontal scrollbar, then (de)select all keys
+ * for the keyframes in the selection region
+ */
+ else if (IN_2D_HORIZ_SCROLL(mval)) {
+ borderselect_function(select_all_keys_frames);
+ }
+
+ /* Other wise, select the action keys
+ */
+ else {
+ borderselect_action();
+ }
break;
case RIGHTMOUSE:
- if (mval[0]<ACTWIDTH)
- mouse_actionchannels(act, mval);
- else
- mouse_action();
+ /* Right clicking in the channel area selects the
+ * channel or constraint channel
+ */
+ if (mval[0]<ACTWIDTH) {
+ if(G.qual & LR_SHIFTKEY)
+ mouse_actionchannels(act, mval, NULL,
+ SELECT_INVERT);
+ else
+ mouse_actionchannels(act, mval, NULL,
+ SELECT_REPLACE);
+ }
+
+ /* Right clicking in the vertical scrollbar selects
+ * all of the keys for that channel at that height
+ */
+ else if (IN_2D_VERT_SCROLL(mval)) {
+ if(G.qual & LR_SHIFTKEY)
+ select_all_keys_channels(act, mval, NULL,
+ SELECT_INVERT);
+ else
+ select_all_keys_channels(act, mval, NULL,
+ SELECT_REPLACE);
+ }
+
+ /* Right clicking in the horizontal scrollbar selects
+ * all of the keys within 0.5 of the nearest integer
+ * frame
+ */
+ else if (IN_2D_HORIZ_SCROLL(mval)) {
+ if(G.qual & LR_SHIFTKEY)
+ select_all_keys_frames(act, mval, NULL,
+ SELECT_INVERT);
+ else
+ select_all_keys_frames(act, mval, NULL,
+ SELECT_REPLACE);
+ }
+
+ /* Clicking in the main area of the action window
+ * selects keys
+ */
+ else {
+ if(G.qual & LR_SHIFTKEY)
+ mouse_action(SELECT_INVERT);
+ else
+ mouse_action(SELECT_REPLACE);
+ }
break;
+
case LEFTMOUSE:
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; i<icu->totvert; 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; i<icu->totvert; 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; i<icu->totvert; 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; i<icu->totvert; 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);