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
path: root/source
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 /source
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.
Diffstat (limited to 'source')
-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);