Extra selection support for the action window, including:
authorChris Want <cwant@ualberta.ca>
Thu, 30 Jan 2003 06:19:49 +0000 (06:19 +0000)
committerChris Want <cwant@ualberta.ca>
Thu, 30 Jan 2003 06:19:49 +0000 (06:19 +0000)
  - 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
source/blender/src/editaction.c
source/blender/src/editipo.c
source/blender/src/editnla.c

index 938b228a84e33b61c5a67cb83daa6c3171ce21a1..40650b6f27f44de3becdbfd9ae581f84f9316ba3 100644 (file)
@@ -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 */
 
index 1289b44a0b0f460452f61b7943c8000a344b33b5..1eb06c398f4e9e7611cfa4df4f5bc329e68f9dea 100644 (file)
@@ -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 {
index 0f2f10c7eff9e3e78b1c0f956db2c3a355ad3e49..d1b5585824a8f309c6873de50b4c05b45769ca46 100644 (file)
@@ -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]));
+        }
+    }
+
+}
index 66311538ac4bca1ef21b0a0a17fdf579ff8fe00b..d12ce9ca71e6cba73e4d7b67d97532fb091d046a 100644 (file)
@@ -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);