svn merge -r 15392:15551 https://svn.blender.org/svnroot/bf-blender/trunk/blender
[blender.git] / source / blender / src / editnla.c
index e91b645295e425fb2318ef62d0f7562c981290ff..dbc0deecb2cae140def1e887f362347c3d67e03a 100644 (file)
@@ -1,15 +1,12 @@
 /**
 /**
-* $Id$
-*
- * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ * $Id$
+ *
+ * ***** BEGIN GPL BLOCK *****
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
  * as published by the Free Software Foundation; either version 2
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
  * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version. The Blender
- * Foundation also sells licenses for use in proprietary software under
- * the Blender License.  See http://www.blender.org/BL/ for information
- * about this.
+ * of the License, or (at your option) any later version. 
  *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  *
  * Contributor(s): none yet.
  *
  *
  * Contributor(s): none yet.
  *
- * ***** END GPL/BL DUAL LICENSE BLOCK *****
-* This file is a horrible mess: An attmept to cram some
-* final functionality into blender before it is too late.
-*
-* Hopefully it can be tidied up at a later date...
+ * ***** END GPL *****
+ *
+ * This file is a horrible mess: An attmept to cram some
+ * final functionality into blender before it is too late.
+ *
+ * Hopefully it can be tidied up at a later date...
 */
 
 #include <stdlib.h>
 */
 
 #include <stdlib.h>
 
 #include "PIL_time.h"
 
 
 #include "PIL_time.h"
 
-#include "BKE_action.h"
-#include "BKE_global.h"
-#include "BKE_ipo.h"
-#include "BKE_library.h"
-#include "BKE_main.h"
-#include "BKE_nla.h"
-
 #include "MEM_guardedalloc.h"
 
 #include "BLI_blenlib.h"
 
 #include "MEM_guardedalloc.h"
 
 #include "BLI_blenlib.h"
 
+#include "DNA_action_types.h"
+#include "DNA_constraint_types.h"
+#include "DNA_curve_types.h"
+#include "DNA_ipo_types.h"
+#include "DNA_object_types.h"
+#include "DNA_nla_types.h"
 #include "DNA_screen_types.h"
 #include "DNA_space_types.h"
 #include "DNA_scene_types.h"
 #include "DNA_screen_types.h"
 #include "DNA_space_types.h"
 #include "DNA_scene_types.h"
-#include "DNA_ipo_types.h"
-#include "DNA_curve_types.h"
-#include "DNA_object_types.h"
 #include "DNA_userdef_types.h"
 #include "DNA_userdef_types.h"
-#include "DNA_action_types.h"
-#include "DNA_nla_types.h"
-#include "DNA_constraint_types.h"
+
+#include "BKE_action.h"
+#include "BKE_blender.h"
+#include "BKE_depsgraph.h"
+#include "BKE_group.h"
+#include "BKE_global.h"
+#include "BKE_ipo.h"
+#include "BKE_library.h"
+#include "BKE_main.h"
+#include "BKE_nla.h"
+#include "BKE_utildefines.h"
 
 #include "BIF_screen.h"
 #include "BIF_interface.h"
 
 #include "BIF_screen.h"
 #include "BIF_interface.h"
 #include "BIF_editview.h"
 #include "BIF_toolbox.h"
 #include "BIF_editnla.h"
 #include "BIF_editview.h"
 #include "BIF_toolbox.h"
 #include "BIF_editnla.h"
+#include "BIF_editaction.h"
+#include "BIF_transform.h"
 
 #include "BSE_editipo.h"
 #include "BSE_editnla_types.h"
 #include "BSE_headerbuttons.h"
 #include "BSE_drawipo.h"
 
 #include "BSE_editipo.h"
 #include "BSE_editnla_types.h"
 #include "BSE_headerbuttons.h"
 #include "BSE_drawipo.h"
+#include "BSE_editaction_types.h"
 #include "BSE_trans_types.h"
 #include "BSE_edit.h"
 #include "BSE_filesel.h"
 #include "BDR_editobject.h"
 #include "BSE_drawnla.h"
 #include "BSE_trans_types.h"
 #include "BSE_edit.h"
 #include "BSE_filesel.h"
 #include "BDR_editobject.h"
 #include "BSE_drawnla.h"
+#include "BSE_time.h"
 
 #include "blendef.h"
 #include "mydevice.h"
 
 #include "blendef.h"
 #include "mydevice.h"
@@ -96,10 +102,6 @@ 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);
 static void mouse_nlachannels(short mval[2]);
 static bAction *get_nearest_nlachannel_ac_key (float *index, short *sel);
 static Base *get_nearest_nlastrip (bActionStrip **rstrip, short *sel);
 static void mouse_nlachannels(short mval[2]);
-static void add_nlablock(short mval[2]);
-static void convert_nla(short mval[2]);
-extern int count_nla_levels(void);     /* From drawnla.c */
-extern int nla_filter (Base* base, int flags); /* From drawnla.c */
 
 /* ******************** SPACE: NLA ********************** */
 
 
 /* ******************** SPACE: NLA ********************** */
 
@@ -109,31 +111,31 @@ void shift_nlastrips_up(void) {
        bActionStrip *strip, *prevstrip;
 
        for (base=G.scene->base.first; base; base=base->next) {
        bActionStrip *strip, *prevstrip;
 
        for (base=G.scene->base.first; base; base=base->next) {
-               if (base->object->type == OB_ARMATURE) {
-
-                       for (strip = base->object->nlastrips.first; 
-                                strip; strip=strip->next){
-                               if (strip->flag & ACTSTRIP_SELECT) {
-                                       if ( (prevstrip = strip->prev) ) {
-                                               if (prevstrip->prev)
-                                                       prevstrip->prev->next = strip;
-                                               if (strip->next)
-                                                       strip->next->prev = prevstrip;
-                                               strip->prev = prevstrip->prev;
-                                               prevstrip->next = strip->next;
-                                               strip->next = prevstrip;
-                                               prevstrip->prev = strip;
-
-                                               if (prevstrip == base->object->nlastrips.first)
-                                                       base->object->nlastrips.first = strip;
-                                               if (strip == base->object->nlastrips.last)
-                                                       base->object->nlastrips.last = prevstrip;
-
-                                               strip = prevstrip;
-                                       }
-                                       else {
-                                               break;
-                                       }
+               if (base->object->nlaflag & OB_NLA_COLLAPSED)
+                       continue;
+               
+               for (strip = base->object->nlastrips.first; 
+                        strip; strip=strip->next){
+                       if (strip->flag & ACTSTRIP_SELECT) {
+                               if ( (prevstrip = strip->prev) ) {
+                                       if (prevstrip->prev)
+                                               prevstrip->prev->next = strip;
+                                       if (strip->next)
+                                               strip->next->prev = prevstrip;
+                                       strip->prev = prevstrip->prev;
+                                       prevstrip->next = strip->next;
+                                       strip->next = prevstrip;
+                                       prevstrip->prev = strip;
+
+                                       if (prevstrip == base->object->nlastrips.first)
+                                               base->object->nlastrips.first = strip;
+                                       if (strip == base->object->nlastrips.last)
+                                               base->object->nlastrips.last = prevstrip;
+
+                                       strip = prevstrip;
+                               }
+                               else {
+                                       break;
                                }
                        }
                }
                                }
                        }
                }
@@ -149,294 +151,431 @@ void shift_nlastrips_down(void) {
        bActionStrip *strip, *nextstrip;
 
        for (base=G.scene->base.first; base; base=base->next) {
        bActionStrip *strip, *nextstrip;
 
        for (base=G.scene->base.first; base; base=base->next) {
-               if (base->object->type == OB_ARMATURE) {
-                       for (strip = base->object->nlastrips.last; 
-                                strip; strip=strip->prev){
-                               if (strip->flag & ACTSTRIP_SELECT) {
-                                       if ( (nextstrip = strip->next) ) {
-                                               if (nextstrip->next)
-                                                       nextstrip->next->prev = strip;
-                                               if (strip->prev)
-                                                       strip->prev->next = nextstrip;
-                                               strip->next = nextstrip->next;
-                                               nextstrip->prev = strip->prev;
-                                               strip->prev = nextstrip;
-                                               nextstrip->next = strip;
-
-                                               if (nextstrip == base->object->nlastrips.last)
-                                                       base->object->nlastrips.last = strip;
-                                               if (strip == base->object->nlastrips.first)
-                                                       base->object->nlastrips.first = nextstrip;
-
-                                               strip = nextstrip;
-                                       }
-                                       else {
-                                               break;
-                                       }
+               if (base->object->nlaflag & OB_NLA_COLLAPSED)
+                       continue;
+               
+               for (strip = base->object->nlastrips.last; 
+                        strip; strip=strip->prev){
+                       if (strip->flag & ACTSTRIP_SELECT) {
+                               if ( (nextstrip = strip->next) ) {
+                                       if (nextstrip->next)
+                                               nextstrip->next->prev = strip;
+                                       if (strip->prev)
+                                               strip->prev->next = nextstrip;
+                                       strip->next = nextstrip->next;
+                                       nextstrip->prev = strip->prev;
+                                       strip->prev = nextstrip;
+                                       nextstrip->next = strip;
+
+                                       if (nextstrip == base->object->nlastrips.last)
+                                               base->object->nlastrips.last = strip;
+                                       if (strip == base->object->nlastrips.first)
+                                               base->object->nlastrips.first = nextstrip;
+
+                                       strip = nextstrip;
+                               }
+                               else {
+                                       break;
                                }
                        }
                }
        }
                                }
                        }
                }
        }
+       
        BIF_undo_push("Shift NLA strips");
        allqueue (REDRAWNLA, 0);
        BIF_undo_push("Shift NLA strips");
        allqueue (REDRAWNLA, 0);
-
 }
 
 }
 
-void winqreadnlaspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
+void synchronize_action_strips(void)
 {
 {
-       unsigned short event= evt->event;
-       short val= evt->val;
-       SpaceNla *snla = curarea->spacedata.first;
-       int doredraw= 0;
-       short   mval[2];
-       float dx,dy;
-       int     cfra;
-       short mousebut = L_MOUSE;
-       
-       if (curarea->win==0) return;
-       if (!snla) return;
+       Base *base;
+       Object *ob;
+       bActionStrip *strip;
        
        
-       if(val) {
-               if( uiDoBlocks(&curarea->uiblocks, event)!=UI_NOTHING ) event= 0;
+       for (base=G.scene->base.first; base; base=base->next) {
+               /* get object first */
+               ob= base->object;
                
                
-               /* swap mouse buttons based on user preference */
-               if (U.flag & USER_LMOUSESELECT) {
-                       if (event == LEFTMOUSE) {
-                               event = RIGHTMOUSE;
-                               mousebut = L_MOUSE;
-                       } else if (event == RIGHTMOUSE) {
-                               event = LEFTMOUSE;
-                               mousebut = R_MOUSE;
+               /* step 1: adjust strip-lengths */
+               //      FIXME: this seems very buggy
+               for (strip = ob->nlastrips.last; strip; strip=strip->prev) {
+                       if (strip->flag & ACTSTRIP_LOCK_ACTION) {
+                               float actstart, actend;
+                               
+                               calc_action_range(strip->act, &actstart, &actend, 1);
+                               
+                               if ((strip->actstart!=actstart) || (strip->actend!=actend)) {           
+                                       float offset = strip->scale * (actstart - strip->actstart);
+                                       float actlen = actend - actstart;
+                                       
+                                       strip->start += offset;
+                                       strip->end = (strip->scale * strip->repeat * actlen) + strip->start;
+                                       
+                                       strip->actstart= actstart;
+                                       strip->actend= actend;
+                               }
                        }
                }
                
                        }
                }
                
-               getmouseco_areawin(mval);
-               
-               switch(event) {
-               case UI_BUT_EVENT:
-                       do_nlabuts(val); // in drawnla.c
-                       break;
-               
-               case HOMEKEY:
-                       do_nla_buttons(B_NLAHOME);
-                       break;
-
-               case EQUALKEY:
-               case PAGEUPKEY:
-                       shift_nlastrips_up();
-                       break;
-
-               case MINUSKEY:
-               case PAGEDOWNKEY:
-                       shift_nlastrips_down();
-                       break;
-
-               case AKEY:
-                       if (G.qual & LR_SHIFTKEY){
-                               add_nlablock(mval);
-                               allqueue (REDRAWNLA, 0);
-                               allqueue (REDRAWVIEW3D, 0);
-                       }
-                       else{
-                               if (mval[0]>=NLAWIDTH)
-                                       deselect_nlachannel_keys(1);
-                               else{
-                                       deselect_nlachannels(1);
-                                       allqueue (REDRAWVIEW3D, 0);
+               /* step 2: adjust blendin/out values for each strip if option is turned on */
+               for (strip= ob->nlastrips.first; strip; strip=strip->next) {
+                       if (strip->flag & ACTSTRIP_AUTO_BLENDS) {
+                               bActionStrip *prev= strip->prev;
+                               bActionStrip *next= strip->next;
+                               float pr[2], nr[2];
+                               
+                               strip->blendin = 0.0f;
+                               strip->blendout = 0.0f;
+                               
+                               /* setup test ranges */
+                               if (prev && next) {
+                                       /* init range for previous strip */
+                                       pr[0]= prev->start;
+                                       pr[1]= prev->end;
+                                       
+                                       /* init range for next strip */
+                                       nr[0]= next->start;
+                                       nr[1]= next->end;
                                }
                                }
-                               allqueue (REDRAWNLA, 0);
-                               allqueue (REDRAWIPO, 0);
-                               BIF_undo_push("(De)select all NLA");
-                       }
-                       break;
-
-               case BKEY:
-                       borderselect_nla();
-                       break;
-
-               case CKEY:
-                       convert_nla(mval);
-                       break;
-                       
-               case DKEY:
-                       if (G.qual & LR_SHIFTKEY && mval[0]>=NLAWIDTH){
-                               duplicate_nlachannel_keys();
-                               update_for_newframe_muted();
-                       }
-                       break;
-
-               case GKEY:
-                       if (mval[0]>=NLAWIDTH)
-                               transform_nlachannel_keys ('g');
-                       update_for_newframe_muted();
-                       break;
-
-               case NKEY:
-                       if(G.qual==0) {
-                               toggle_blockhandler(curarea, NLA_HANDLER_PROPERTIES, UI_PNL_TO_MOUSE);
-                               scrarea_queue_winredraw(curarea);
-                       }
-                       break;
-
-               case SKEY:
-                       if (mval[0]>=NLAWIDTH)
-                               transform_nlachannel_keys ('s');
-                       update_for_newframe_muted();
-                       break;
-
-               case DELKEY:
-               case XKEY:
-                       if (mval[0]>=NLAWIDTH)
-                               delete_nlachannel_keys ();
-                       else
-                               delete_nlachannels();
-                       update_for_newframe_muted();
-                       break;
-               
-               /* LEFTMOUSE and RIGHTMOUSE event codes can be swapped above,
-                * based on user preference USER_LMOUSESELECT
-                */
-               case LEFTMOUSE:
-                       if(view2dmove(LEFTMOUSE)); // only checks for sliders
-                       else if (mval[0]>NLAWIDTH){
-                               do {
-                                       getmouseco_areawin(mval);
+                               else if (prev) {
+                                       /* next strip's range is same as previous strip's range  */
+                                       pr[0] = nr[0] = prev->start;
+                                       pr[1] = nr[1] = prev->end;
+                               }
+                               else if (next) {
+                                       /* previous strip's range is same as next strip's range */
+                                       pr[0] = nr[0] = next->start;
+                                       pr[1] = nr[1] = next->end;
+                               }
+                               else {
+                                       /* there shouldn't be any more strips to loop through for this operation */
+                                       break;
+                               }
+                               
+                               /* test various cases */
+                               if ( IN_RANGE(pr[1], strip->start, strip->end) && 
+                                       (IN_RANGE(pr[0], strip->start, strip->end)==0) )
+                               {
+                                       /* previous strip intersects start of current */
                                        
                                        
-                                       areamouseco_to_ipoco(G.v2d, mval, &dx, &dy);
+                                       if ( IN_RANGE(nr[1], strip->start, strip->end) && 
+                                               (IN_RANGE(nr[0], strip->start, strip->end)==0) )
+                                       {
+                                               /* next strip also intersects start of current */
+                                               if (nr[1] < pr[1])
+                                                       strip->blendin= nr[1] - strip->start;
+                                               else
+                                                       strip->blendin= pr[1] - strip->start;
+                                       }
+                                       else if (IN_RANGE(nr[0], strip->start, strip->end) && 
+                                                       (IN_RANGE(nr[1], strip->start, strip->end)==0))
+                                       {
+                                               /* next strip intersects end of current */
+                                               strip->blendout= strip->end - nr[0];
+                                               strip->blendin= pr[1] - strip->start;
+                                       }
+                                       else {
+                                               /* only previous strip intersects current */
+                                               strip->blendin= pr[1] - strip->start;
+                                       }
+                               }
+                               else if (IN_RANGE(pr[0], strip->start, strip->end) && 
+                                               (IN_RANGE(pr[1], strip->start, strip->end)==0) )
+                               {
+                                       /* previous strip intersects end of current */
                                        
                                        
-                                       cfra= (int)dx;
-                                       if(cfra< 1) cfra= 1;
+                                       if ( IN_RANGE(nr[0], strip->start, strip->end) && 
+                                               (IN_RANGE(nr[1], strip->start, strip->end)==0) )
+                                       {
+                                               /* next strip also intersects end of current */
+                                               if (nr[1] > pr[1])
+                                                       strip->blendout= strip->end - nr[0];
+                                               else
+                                                       strip->blendout= strip->end - pr[0];
+                                       }
+                                       else if (IN_RANGE(nr[1], strip->start, strip->end) && 
+                                                       (IN_RANGE(nr[0], strip->start, strip->end)==0))
+                                       {
+                                               /* next strip intersects start of current */
+                                               strip->blendin= nr[1] - strip->start;
+                                               strip->blendout= strip->end - pr[0];
+                                       }
+                                       else {
+                                               /* only previous strip intersects current */
+                                               strip->blendout= strip->end - pr[0];
+                                       }
+                               }
+                               else if (IN_RANGE(nr[1], strip->start, strip->end) && 
+                                               (IN_RANGE(nr[0], strip->start, strip->end)==0) )
+                               {
+                                       /* next strip intersects start of current */
                                        
                                        
-                                       if( cfra!=CFRA ) {
-                                               CFRA= cfra;
-                                               update_for_newframe();
-                                               force_draw_plus(SPACE_VIEW3D, 1);
-                                               force_draw_plus(SPACE_IPO, 1);
+                                       if ( IN_RANGE(pr[1], strip->start, strip->end) && 
+                                               (IN_RANGE(pr[0], strip->start, strip->end)==0) )
+                                       {
+                                               /* previous strip also intersects start of current */
+                                               if (pr[1] < nr[1])
+                                                       strip->blendin= pr[1] - strip->start;
+                                               else
+                                                       strip->blendin= nr[1] - strip->start;
+                                       }
+                                       else if (IN_RANGE(pr[0], strip->start, strip->end) && 
+                                                       (IN_RANGE(pr[1], strip->start, strip->end)==0))
+                                       {
+                                               /* previous strip intersects end of current */
+                                               strip->blendout= strip->end - pr[0];
+                                               strip->blendin= nr[1] - strip->start;
+                                       }
+                                       else {
+                                               /* only next strip intersects current */
+                                               strip->blendin= nr[1] - strip->start;
                                        }
                                        }
-                                       else PIL_sleep_ms(30);
+                               }
+                               else if (IN_RANGE(nr[0], strip->start, strip->end) && 
+                                               (IN_RANGE(nr[1], strip->start, strip->end)==0) )
+                               {
+                                       /* next strip intersects end of current */
                                        
                                        
-                               } while(get_mbut() & mousebut);
-                       }
-                       break;
-               case RIGHTMOUSE:
-                       if (mval[0]>=NLAWIDTH) {
-                               if(G.qual & LR_SHIFTKEY)
-                                       mouse_nla(SELECT_INVERT);
-                               else
-                                       mouse_nla(SELECT_REPLACE);
+                                       if ( IN_RANGE(pr[0], strip->start, strip->end) && 
+                                               (IN_RANGE(pr[1], strip->start, strip->end)==0) )
+                                       {
+                                               /* previous strip also intersects end of current */
+                                               if (pr[1] > nr[1])
+                                                       strip->blendout= strip->end - pr[0];
+                                               else
+                                                       strip->blendout= strip->end - nr[0];
+                                       }
+                                       else if (IN_RANGE(pr[1], strip->start, strip->end) && 
+                                                       (IN_RANGE(pr[0], strip->start, strip->end)==0))
+                                       {
+                                               /* previous strip intersects start of current */
+                                               strip->blendin= pr[1] - strip->start;
+                                               strip->blendout= strip->end - nr[0];
+                                       }
+                                       else {
+                                               /* only next strip intersects current */
+                                               strip->blendout= strip->end - nr[0];
+                                       }
+                               }
+                               
+                               /* make sure blending stays in ranges */
+                               CLAMP(strip->blendin, 0, (strip->end-strip->start));
+                               CLAMP(strip->blendout, 0, (strip->end-strip->start));
                        }
                        }
-                       else
-                               mouse_nlachannels(mval);
-                       break;
-
-               case PADPLUSKEY:
-                       view2d_zoom(G.v2d, 0.1154, sa->winx, sa->winy);
-                       test_view2d(G.v2d, sa->winx, sa->winy);
-                       doredraw= 1;
-                       break;
-               case PADMINUS:
-                       view2d_zoom(G.v2d, -0.15, sa->winx, sa->winy);
-                       test_view2d(G.v2d, sa->winx, sa->winy);
-                       doredraw= 1;
-                       break;
-               case MIDDLEMOUSE:
-               case WHEELUPMOUSE:
-               case WHEELDOWNMOUSE:
-                       view2dmove(event);      /* in drawipo.c */
-                       break;
                }
        }
        
                }
        }
        
-       if(doredraw) scrarea_queue_winredraw(curarea);
 }
 
 }
 
-static void convert_nla(short mval[2])
+void reset_action_strips(int val)
 {
 {
-       short event;
-       float   ymax, ymin;
        Base *base;
        Base *base;
-       float x,y;
-       int sel=0;
-       bActionStrip *strip, *nstrip;
-       /* Find out what strip we're over */
-       ymax = count_nla_levels() * (NLACHANNELSKIP+NLACHANNELHEIGHT);
-       ymax+= NLACHANNELHEIGHT/2;
-       
-       areamouseco_to_ipoco(G.v2d, mval, &x, &y);
+       bActionStrip *strip;
        
        
-       for (base=G.scene->base.first; base; base=base->next){
-               if (nla_filter(base, 0)){
-                       /* Check object ipo */
-                       ymin=ymax-(NLACHANNELSKIP+NLACHANNELHEIGHT);
-                       if (y>=ymin && y<=ymax)
-                               break;
-                       ymax=ymin;
-                       
-                       if (base->object->type==OB_ARMATURE){
-                               /* Check action ipo */
-                               ymin=ymax-(NLACHANNELSKIP+NLACHANNELHEIGHT);
-                               if (y>=ymin && y<=ymax)
-                                       break;
-                               ymax=ymin;
-                               
-                               /* Check nlastrips */
-                               for (strip=base->object->nlastrips.first; strip; strip=strip->next){
-                                       ymin=ymax-(NLACHANNELSKIP+NLACHANNELHEIGHT);
-                                       if (y>=ymin && y<=ymax){
-                                               sel = 1;
+       for (base=G.scene->base.first; base; base=base->next) {
+               if (base->object->nlaflag & OB_NLA_COLLAPSED)
+                       continue;
+               
+               for (strip = base->object->nlastrips.last; strip; strip=strip->prev) {
+                       if (strip->flag & ACTSTRIP_SELECT) {
+                               switch (val) {
+                                       case 1:
+                                       {
+                                               /* clear scaling - reset to 1.0 without touching keys */
+                                               float actlen= (strip->actend - strip->actstart);
+                                               
+                                               strip->scale= 1.0f;
+                                               strip->end= (strip->repeat * actlen) + strip->start;
+                                       }
                                                break;
                                                break;
+                                       case 2:
+                                       {
+                                               /* reset action-range */
+                                               calc_action_range(strip->act, &strip->actstart, &strip->actend, 1);
                                        }
                                        }
-                                       ymax=ymin;
+                                               break;
+                                       case 3:
+                                       {
+                                               /* apply scale to keys - scale is reset to 1.0f, but keys stay at the same times */
+                                               bActionChannel *achan;
+                                               
+                                               if (strip->act) {
+                                                       for (achan= strip->act->chanbase.first; achan; achan= achan->next) {
+                                                               actstrip_map_ipo_keys(base->object, achan->ipo, 0, 0);
+                                                       }
+                                                       
+                                                       /* now we can reset scale */
+                                                       calc_action_range(strip->act, &strip->actstart, &strip->actend, 1);
+                                                       strip->scale= 1.0f;
+                                                       strip->end = (strip->repeat * (strip->actend - strip->actstart)) + strip->start;
+                                               }
+                                       }
+                                               break;
                                }
                                }
-                               if (sel)
-                                       break;
+                               base->object->ctime= -1234567.0f;       // evil! 
+                               DAG_object_flush_update(G.scene, base->object, OB_RECALC_OB|OB_RECALC_DATA);
                        }
                }
        }
                        }
                }
        }
+       BIF_undo_push("Reset NLA strips");
+       allqueue (REDRAWVIEW3D, 0);
+       allqueue (REDRAWACTION, 0);
+       allqueue (REDRAWNLA, 0);
+}
+
+void snap_action_strips(int snap_mode)
+{
+       Base *base;
+       bActionStrip *strip;
        
        
-       if (!base)
-               return;
-       
-       if (base->object->type==OB_ARMATURE){
-               event = pupmenu("Convert%t|Action to NLA Strip%x1");
-               switch (event){
-               case 1:
-                       if (base->object->action){
-                               /* Make new actionstrip */
-                               nstrip = MEM_callocN(sizeof(bActionStrip), "bActionStrip");
-                               
-                               deselect_nlachannel_keys(0);
-                               
-                               /* Link the action to the nstrip */
-                               nstrip->act = base->object->action;
-                               nstrip->actstart = calc_action_start(base->object->action);     /* MAKE THIS THE FIRST FRAME OF THE ACTION */
-                               nstrip->actend = calc_action_end(base->object->action);
-                               nstrip->start = nstrip->actstart;
-                               nstrip->end = nstrip->actend;
-                               nstrip->flag = ACTSTRIP_SELECT;
-                               nstrip->repeat = 1.0;
-                                                               
-                               BLI_addtail(&base->object->nlastrips, nstrip);
-                               
-                               /* Unlink action */
-                               base->object->action = NULL;
-                               
-                               BIF_undo_push("Convert NLA");
-                               allqueue (REDRAWNLA, 0);
+       for (base=G.scene->base.first; base; base=base->next) {
+               /* object has ipo - these keyframes should be able to be snapped, even if strips are collapsed */
+               if (base->object->ipo) {
+                       snap_ipo_keys(base->object->ipo, snap_mode);
+               }
+               
+               /* object is collapsed - action and nla strips not shown/editable */
+               if (base->object->nlaflag & OB_NLA_COLLAPSED)
+                       continue;
+               
+               /* snap action strips */
+               for (strip = base->object->nlastrips.last; strip; strip=strip->prev) {
+                       if (strip->flag & ACTSTRIP_SELECT) {
+                               if (snap_mode==1) {
+                                       /* nearest frame */
+                                       strip->start= floor(strip->start+0.5);
+                                       strip->end= floor(strip->end+0.5);
+                               }
+                               else if (snap_mode==2) {
+                                       /* current frame */
+                                       float diff;
+                                       if (CFRA < strip->start) {
+                                               diff = (strip->start - CFRA);
+                                               strip->start -= diff;
+                                               strip->end -= diff;
+                                       }
+                                       else {
+                                               diff = (CFRA - strip->start);
+                                               strip->start += diff;
+                                               strip->end += diff;
+                                       }
+                               }
+                               else if (snap_mode==3) {
+                                       /* nearest second */
+                                       float secf = FPS;
+                                       strip->start= (float)(floor(strip->start/secf + 0.5f) * secf);
+                                       strip->end= (float)(floor(strip->end/secf + 0.5f) * secf);
+                               }
                        }
                        }
+               }
+               
+               /* object has action */
+               if (base->object->action) {
+                       ListBase act_data = {NULL, NULL};
+                       bActListElem *ale;
+                       int filter;
                        
                        
+                       /* filter action data */
+                       filter= (ACTFILTER_VISIBLE | ACTFILTER_FOREDIT | ACTFILTER_IPOKEYS);
+                       actdata_filter(&act_data, filter, base->object->action, ACTCONT_ACTION);
                        
                        
-                       break;
-               default:
-                       break;
+                       /* snap to frame */
+                       for (ale= act_data.first; ale; ale= ale->next) {
+                               actstrip_map_ipo_keys(base->object, ale->key_data, 0, 1); 
+                               snap_ipo_keys(ale->key_data, snap_mode);
+                               actstrip_map_ipo_keys(base->object, ale->key_data, 1, 1);
+                       }
+                       BLI_freelistN(&act_data);
+                       
+                       remake_action_ipos(base->object->action);
                }
        }
                }
        }
+       BIF_undo_push("Snap NLA strips");
+       allqueue (REDRAWVIEW3D, 0);
+       allqueue (REMAKEIPO, 0);
+       allqueue (REDRAWIPO, 0);
+       allqueue (REDRAWACTION, 0);
+       allqueue (REDRAWNLA, 0);
 }
 
 }
 
-static Base *nla_base=NULL;    /* global, bad, bad! put it in nla space later, or recode the 2 functions below (ton) */
+static void set_active_strip(Object *ob, bActionStrip *act)
+{
+       bActionStrip *strip;
+       
+       /* make sure all other strips are not active */
+       for (strip = ob->nlastrips.first; strip; strip=strip->next)
+               strip->flag &= ~ACTSTRIP_ACTIVE;
+       
+       /* act is new active strip */
+       if (act) {
+               /* set active flag for this strip */
+               act->flag |= ACTSTRIP_ACTIVE;
+               
+               /* check if active action will still be the same one */
+               if (ob->action != act->act) {
+                       /* clear object's links with its current action (if present) */
+                       if (ob->action) {
+                               ob->action->id.us--;
+                       }
+                       
+                       /* only set object's action to active strip's action if possible */
+                       if (act->act->id.lib) {
+                               ob->action= NULL;
+                       }
+                       else {
+                               ob->action= act->act;
+                               id_us_plus(&ob->action->id);
+                       }       
+                       
+                       /* request redrawing in relevant spaces */
+                       allqueue(REDRAWIPO, 0);
+                       allqueue(REDRAWVIEW3D, 0);
+                       allqueue(REDRAWACTION, 0);
+                       allqueue(REDRAWNLA, 0);
+                       
+                       /* when only showing action (i.e. nla-override off), 
+                        * reset pose to restpose for armatures 
+                        */
+                       if ((ob->nlaflag & OB_NLA_OVERRIDE)==0) {
+                               if (ob->type == OB_ARMATURE)
+                                       rest_pose(ob->pose);
+                       }
+                       
+                       /* flush depsgraph */
+                       ob->ctime= -1234567.0f; // evil! 
+                       DAG_object_flush_update(G.scene, ob, OB_RECALC_OB|OB_RECALC_DATA);
+               }
+       }       
+}
+
+void convert_nla(void)
+{
+       bActionStrip *strip;
+       Object *ob= OBACT;
+       char str[128];
+       short event;
+       
+       if ((ob==NULL)||(ob->action==NULL)) {
+               error("Need active Object to convert Action to NLA Strip");
+               return;
+       }
+       
+       sprintf(str, "Convert Action%%t|%s to NLA Strip%%x1", ob->action->id.name+2);
+       event = pupmenu(str);
+       
+       if (event==1) {
+               if (ob->action) {
+                       deselect_nlachannel_keys(0);
+                       strip = convert_action_to_strip(ob); //creates a new NLA strip from the action in given object
+                       set_active_strip(ob, strip);
+                       BIF_undo_push("Convert NLA");
+                       allqueue (REDRAWNLA, 0);
+               }
+       }
+}
 
 static void add_nla_block(short event)
 {
 
 static void add_nla_block(short event)
 {
+       Object *ob= OBACT;
        bAction *act=NULL;
        bActionStrip *strip;
        int             cur;
        bAction *act=NULL;
        bActionStrip *strip;
        int             cur;
@@ -461,104 +600,118 @@ static void add_nla_block(short event)
        
        /* Link the action to the strip */
        strip->act = act;
        
        /* Link the action to the strip */
        strip->act = act;
-       strip->actstart = 1.0;
-       strip->actend = calc_action_end(act);
-       strip->start = G.scene->r.cfra; /* Should be mval[0] */
+       id_us_plus(&act->id);
+       calc_action_range(strip->act, &strip->actstart, &strip->actend, 1);
+       strip->start = G.scene->r.cfra;         /* could be mval[0] another time... */
        strip->end = strip->start + (strip->actend-strip->actstart);
        strip->end = strip->start + (strip->actend-strip->actstart);
-       strip->flag = ACTSTRIP_SELECT;
-       strip->repeat = 1.0;
+               /* simple prevention of zero strips */
+       if(strip->start>strip->end-2) 
+               strip->end= strip->start+100;
+       strip->repeat = strip->scale= 1.0f;
        
        
-       act->id.us++;
+       strip->flag = ACTSTRIP_SELECT|ACTSTRIP_LOCK_ACTION;
        
        
-       BLI_addtail(&nla_base->object->nlastrips, strip);
+       find_stridechannel(ob, strip);
+       set_active_strip(ob, strip);
+       strip->object= group_get_member_with_action(ob->dup_group, act);
+       if(strip->object)
+               id_lib_extern(&strip->object->id);      /* checks lib data, sets correct flag for saving then */
+
+       if(ob->nlastrips.first == NULL)
+               ob->nlaflag |= OB_NLA_OVERRIDE;
+       
+       BLI_addtail(&ob->nlastrips, strip);
 
        BIF_undo_push("Add NLA strip");
 }
 
 
        BIF_undo_push("Add NLA strip");
 }
 
+static void add_nla_block_by_name(char name[32], Object *ob, short hold, short add, float repeat)
+{
+       bAction *act=NULL;
+       bActionStrip *strip;
+       int             cur;
+
+       if (name){
+               for (cur = 1, act=G.main->action.first; act; act=act->id.next, cur++){
+                       if (strcmp(name,act->id.name)==0) {
+                               break;
+                       }
+               }
+       }
+       
+       /* Bail out if no action was chosen */
+       if (!act){
+               return;
+       }
+       
+       /* Initialize the new action block */
+       strip = MEM_callocN(sizeof(bActionStrip), "bActionStrip");
+       strip->scale= 1.0f;
+       
+       deselect_nlachannel_keys(0);
+       
+       /* Link the action to the strip */
+       strip->act = act;
+       calc_action_range(strip->act, &strip->actstart, &strip->actend, 1);
+       strip->start = G.scene->r.cfra;         /* could be mval[0] another time... */
+       strip->end = strip->start + (strip->actend-strip->actstart);
+               /* simple prevention of zero strips */
+       if(strip->start>strip->end-2) 
+               strip->end= strip->start+100;
+       
+       strip->flag = ACTSTRIP_SELECT|ACTSTRIP_LOCK_ACTION; //|ACTSTRIP_USEMATCH;
+       
+       if (hold==1)
+               strip->flag = strip->flag|ACTSTRIP_HOLDLASTFRAME;
+               
+       if (add==1)
+               strip->mode = ACTSTRIPMODE_ADD;
+       
+       find_stridechannel(ob, strip);
+       
+       set_active_strip(ob, strip);
+       
+       strip->repeat = repeat;
+       
+       act->id.us++;
+       
+       if(ob->nlastrips.first == NULL)
+               ob->nlaflag |= OB_NLA_OVERRIDE;
+               
+       BLI_addtail(&ob->nlastrips, strip);
+}
+
 static void add_nla_databrowse_callback(unsigned short val)
 {
        /* val is not used, databrowse needs it to optional pass an event */
        short event;
        
 static void add_nla_databrowse_callback(unsigned short val)
 {
        /* val is not used, databrowse needs it to optional pass an event */
        short event;
        
-       if(nla_base==NULL) return;
+       if(OBACT==NULL) return;
        
        event= G.snla->menunr;  /* set by databrowse or pupmenu */
        
        add_nla_block(event);
 }
 
        
        event= G.snla->menunr;  /* set by databrowse or pupmenu */
        
        add_nla_block(event);
 }
 
-static void add_nlablock(short mval[2])
+/* Adds strip to to active Object */
+void add_nlablock(void)
 {
 {
-       /* Make sure we are over an armature */
-       Base *base;
-       float ymin, ymax;
-       float x, y;
-       rctf    rectf;
+       Object *ob= OBACT;
        short event;
        short event;
-       char *str;
-       short nr;
-       bConstraintChannel *conchan=NULL;
-
-       areamouseco_to_ipoco(G.v2d, mval, &x, &y);
-       
-       mval[0]-=7;
-       areamouseco_to_ipoco(G.v2d, mval, &rectf.xmin, &rectf.ymin);
+       short nr=0;
+       char *str, title[64];
        
        
-       mval[0]+=14;
-       areamouseco_to_ipoco(G.v2d, mval, &rectf.xmax, &rectf.ymax);
-
-       ymax = count_nla_levels();      
-       ymax*= (NLACHANNELHEIGHT + NLACHANNELSKIP);
-       ymax+= NLACHANNELHEIGHT/2;
-
-       for (base=G.scene->base.first; base; base=base->next){
-               /* Handle object ipo selection */
-               if (nla_filter(base, 0)){
-                       
-                       /* Area that encloses object name (or ipo) */
-                       ymin=ymax-(NLACHANNELHEIGHT+NLACHANNELSKIP);
-
-                       /* Area that encloses constraint channels */
-                       for (conchan=base->object->constraintChannels.first; 
-                                conchan; conchan=conchan->next){
-                               ymin-=(NLACHANNELHEIGHT+NLACHANNELSKIP);
-                       }
-
-                       if (base->object->type==OB_ARMATURE){
-                               /* Area that encloses selected action, if
-                                * present
-                                */
-                               if (base->object->action)
-                                       ymin-=(NLACHANNELHEIGHT+NLACHANNELSKIP);
-
-                               /* Area that encloses nla strips */
-                               ymin-=(NLACHANNELHEIGHT+NLACHANNELSKIP)*
-                                       (BLI_countlist(&base->object->nlastrips));
-                       }
-
-                       /* Test to see the mouse is in an armature area */
-                       if (base->object->type==OB_ARMATURE){
-                               if (!((ymax < rectf.ymin) || (ymin > rectf.ymax)))
-                                       break;          
-                       }
-                       
-                       ymax=ymin;
-               }
-       }       
-       
-       /* global... for the call above, because the NLA system seems not to have an 'active strip' stored */
-       nla_base= base;
-       
-       /* Make sure we have an armature */
-       if (!base){
-               error ("Not an armature");
+       if(ob==NULL) {
+               error("Need active Object to add NLA strips");
                return;
        }
        
                return;
        }
        
+       sprintf(title, "Add Action strip to: %s", ob->id.name+2);
+       
        /* Popup action menu */
        /* Popup action menu */
-       IDnames_to_pupstring(&str, "Add Action", NULL, &G.main->action, (ID *)G.scene, &nr);
+       IDnames_to_pupstring(&str, title, NULL, &G.main->action, (ID *)G.scene, &nr);
        
        
-       if(strncmp(str+13, "DataBrow", 8)==0) {
+       if(nr==-2) {
                MEM_freeN(str);
 
                activate_databrowse((ID *)NULL, ID_AC, 0, 0, &G.snla->menunr, 
                MEM_freeN(str);
 
                activate_databrowse((ID *)NULL, ID_AC, 0, 0, &G.snla->menunr, 
@@ -567,138 +720,199 @@ static void add_nlablock(short mval[2])
                return;                 
        }
        else {
                return;                 
        }
        else {
-               event = pupmenu(str);
+               event = pupmenu_col(str, 20);
                MEM_freeN(str);
                add_nla_block(event);
        }
                MEM_freeN(str);
                add_nla_block(event);
        }
+}
+
+/* Creates a new action, and makes a new actionstrip of that */
+void add_empty_nlablock(void)
+{
+       Object *ob= OBACT;
+       bAction *act= NULL;
+       bActionStrip *strip;
+       
+       /* check for active object first - will add strip to active object */
+       if (ob == NULL) 
+               return;
+               
+       /* make new action */
+       if ((ob->type == OB_ARMATURE) && (ob->flag & OB_POSEMODE))
+               act= add_empty_action("ObAction");
+       else
+               act= add_empty_action("Action");
+               
+       /* make a new strip for it */
+       add_nla_block_by_name(act->id.name, ob, 0, 1, 1.0f);
+       strip= ob->nlastrips.last; 
+       
+       /* change some settings of the strip - try to avoid bad scaling */
+       if ((EFRA-CFRA) < 100) {
+               strip->flag |= ACTSTRIP_AUTO_BLENDS;
+               strip->flag &= ~ACTSTRIP_LOCK_ACTION;
+               strip->actstart = CFRA;
+               strip->actend = CFRA + 100;
+               
+               strip->start = CFRA;
+               strip->end = CFRA + 100;
+       }
+       else {
+               strip->flag |= ACTSTRIP_AUTO_BLENDS;
+               strip->flag &= ~ACTSTRIP_LOCK_ACTION;
+               strip->actstart = CFRA;
+               strip->actend = EFRA;
+               
+               strip->start = CFRA;
+               strip->end = EFRA;
+       }
        
        
-       /* Ton: this is a callback for databrowse too
-          Hos: no, I don't think it is
-          add_nla_block(0);
-       */
+       BIF_undo_push("Add NLA strip");
 }
 
 }
 
-static void mouse_nlachannels(short mval[2])
+/* Adds strip to to active Object */
+static void relink_active_strip(void)
 {
 {
-       /* Find which strip has been clicked */
-//     bActionChannel *chan;
-       bConstraintChannel *conchan=NULL;
+       Object *ob= OBACT;
        bActionStrip *strip;
        bActionStrip *strip;
-       float   click, x,y;
-       int             wsize;
-       int             sel;
+       bAction *act;
+       short event;
+       short cur;
+       char *str;
+       
+       if(ob==NULL) return;
+       if(ob->nlaflag & OB_NLA_COLLAPSED) return;
+       
+       for (strip = ob->nlastrips.first; strip; strip=strip->next)
+               if(strip->flag & ACTSTRIP_ACTIVE)
+                       break;
+       
+       if(strip==NULL) return;
+       
+       /* Popup action menu */
+       IDnames_to_pupstring(&str, "Relink Action strip", NULL, &G.main->action, (ID *)G.scene, NULL);
+       if(str) {
+               event = pupmenu_col(str, 20);
+               MEM_freeN(str);
+               
+               for (cur = 1, act=G.main->action.first; act; act=act->id.next, cur++){
+                       if (cur==event){
+                               break;
+                       }
+               }
+               
+               if(act) {
+                       if(strip->act) strip->act->id.us--;
+                       strip->act = act;
+                       id_us_plus(&act->id);
+                       
+                       allqueue(REDRAWVIEW3D, 0);
+                       allqueue(REDRAWACTION, 0);
+                       allqueue(REDRAWNLA, 0);
+               }
+       }
+}
+
+
+
+/* Left hand side of channels display, selects objects */
+static void mouse_nlachannels(short mval[2])
+{
+       bActionStrip *strip= NULL;
        Base    *base;
        Base    *base;
+       Object *ob=NULL;
+       float   x,y;
+       int             click, obclick=0, actclick=0;
+       int             wsize;
        
        wsize = (count_nla_levels ()*(NLACHANNELHEIGHT+NLACHANNELSKIP));
        wsize+= NLACHANNELHEIGHT/2;
 
        
        wsize = (count_nla_levels ()*(NLACHANNELHEIGHT+NLACHANNELSKIP));
        wsize+= NLACHANNELHEIGHT/2;
 
-    areamouseco_to_ipoco(G.v2d, mval, &x, &y);
-    click = ((wsize - y) / (NLACHANNELHEIGHT+NLACHANNELSKIP));
-
+       areamouseco_to_ipoco(G.v2d, mval, &x, &y);
+       click = (int)floor( ((float)wsize - y) / (NLACHANNELHEIGHT+NLACHANNELSKIP));
+       
        if (click<0)
                return;
 
        for (base = G.scene->base.first; base; base=base->next){
        if (click<0)
                return;
 
        for (base = G.scene->base.first; base; base=base->next){
-               if (nla_filter(base, 0)) {
+               if (nla_filter(base)) {
+                       ob= base->object;
+                       
                        /* See if this is a base selected */
                        /* See if this is a base selected */
-                       if ((int)click==0)
+                       if (click==0) {
+                               obclick= 1;
                                break;
                                break;
-                       
+                       }
                        click--;
                        
                        click--;
                        
-                       /* Check for click in a constraint */
-                       for (conchan=base->object->constraintChannels.first; conchan; conchan=conchan->next){
-                               if ((int)click==0){
-                                       base=G.scene->base.last;
-                                       break;
-                               }
-                               click--;
-                       }
-
-                       /* See if this is an action */
-                       if (base->object->type==OB_ARMATURE && base->object->action){
-                               if ((int)click==0){
-                                       break;
+                       /* see if any strips under object */
+                       if ((ob->nlaflag & OB_NLA_COLLAPSED)==0) {
+                               /* See if this is an action */
+                               if (ob->action){
+                                       if (click==0) {
+                                               actclick= 1;
+                                               break;
+                                       }
+                                       click--;
                                }
                                }
-                               click--;
-                       }
 
 
-                       /* See if this is an nla strip */
-                       for (strip = base->object->nlastrips.first; strip; strip=strip->next){
-                               if ((int)click==0){
-                                       base=G.scene->base.last;
-                                       break;
+                               /* See if this is an nla strip */
+                               if(ob->nlastrips.first) {
+                                       for (strip = ob->nlastrips.first; strip; strip=strip->next){
+                                               if (click==0) break;
+                                               click--;                                
+                                       }
+                                       if (strip && click==0) break;
                                }
                                }
-                               click--;                                
                        }
                }
        }
 
                        }
                }
        }
 
-       if (!base && !conchan)
+       if (!base)
                return;
 
                return;
 
-       /* Handle constraint strip selection */
-       if (conchan){
-               if (conchan->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 (conchan->flag & CONSTRAINT_CHANNEL_SELECT){
-                               conchan->flag &= ~CONSTRAINT_CHANNEL_SELECT;
-                               //      hilight_channel(act, chan, 0);
-                       }
-                       else{
-                               conchan->flag |= CONSTRAINT_CHANNEL_SELECT;
-                               //      hilight_channel(act, chan, 1);
-                       }
-               }
-               else{
-                       deselect_nlachannels (0);       // Auto clear
-                       conchan->flag |= CONSTRAINT_CHANNEL_SELECT;
-                       //      hilight_channel(act, chan, 1);
-                       //      act->achan = chan;
-                       //      select_poseelement_by_name(chan->name, 1);
-               }
-               
+       /* Handle object strip selection */
+       if (G.qual & LR_SHIFTKEY) {
+               if (base->flag & SELECT) base->flag &= ~SELECT;
+               else base->flag |= SELECT;
        }
        }
+       else {
+               deselect_nlachannels (0);       // Auto clear
+               base->flag |= SELECT;
+       }
+       ob->flag= base->flag;
        
        
-       /* Handle object strip selection */
-       else if (base) {
-               
-               /* Choose the mode */
-               if (base->flag & 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 (base->flag & SELECT) {
-                               base->flag &= ~SELECT;
-               //              hilight_channel(act, chan, 0);
-                       }
-                       else {
-                               base->flag |= SELECT;
-               //              hilight_channel(act, chan, 1);
-                       }
-               }
-               else {
-                       deselect_nlachannels (0);       // Auto clear
-                       base->flag |= SELECT;
-               //      hilight_channel(act, chan, 1);
-               //      act->achan = chan;
-               //      select_poseelement_by_name(chan->name, 1);
-               }
-               
+       if(base!=BASACT) set_active_base(base);
+       
+       if(actclick) /* de-activate all strips */
+               set_active_strip(ob, NULL);
+       else if(strip) {
+               if(mval[0] >= (NLAWIDTH-16)) /* toggle strip muting */
+                       strip->flag ^= ACTSTRIP_MUTE;
+               else /* set action */
+                       set_active_strip(ob, strip);
        }
        }
-       allqueue (REDRAWIPO, 0);
-       allqueue (REDRAWVIEW3D, 0);
-       allqueue (REDRAWACTION, 0);
+
+       /* icon toggles beside strip */
+       if (obclick && mval[0]<20) {
+               /* collapse option for NLA object strip */
+               ob->nlaflag ^= OB_NLA_COLLAPSED;
+       }
+       else if(obclick && mval[0]<36) {
+               /* override option for NLA */
+               ob->nlaflag ^= OB_NLA_OVERRIDE;
+       }
+       else if((obclick) && (ob->ipo) && (mval[0] >= (NLAWIDTH-16))) {
+               /* mute Object IPO-block */
+               ob->ipo->muteipo = (ob->ipo->muteipo)? 0: 1;
+       }
+       
+       ob->ctime= -1234567.0f; // eveil! 
+       DAG_object_flush_update(G.scene, ob, OB_RECALC_OB|OB_RECALC_DATA);
+
+       allqueue(REDRAWIPO, 0);
+       allqueue(REDRAWVIEW3D, 0);
+       allqueue(REDRAWACTION, 0);
        allqueue(REDRAWNLA, 0);
        
 }
        allqueue(REDRAWNLA, 0);
        
 }
@@ -713,8 +927,7 @@ void deselect_nlachannel_keys (int test)
        
        /* Determine if this is selection or deselection */
        if (test){
        
        /* Determine if this is selection or deselection */
        if (test){
-               for (base=G.scene->base.first; base && sel; base=base->next){
-                       
+               for (base=G.scene->base.first; base && sel; base=base->next){           
                        /* Test object ipos */
                        if (is_ipo_key_selected(base->object->ipo)){
                                sel = 0;
                        /* Test object ipos */
                        if (is_ipo_key_selected(base->object->ipo)){
                                sel = 0;
@@ -731,9 +944,13 @@ void deselect_nlachannel_keys (int test)
                                }
                        }
                        
                                }
                        }
                        
+                       /* check if collapsed */
+                       if (base->object->nlaflag & OB_NLA_COLLAPSED)
+                               continue;
+                       
                        /* Test action ipos */
                        if (sel){
                        /* Test action ipos */
                        if (sel){
-                               if (base->object->type==OB_ARMATURE && base->object->action){
+                               if (base->object->action){
                                        for (chan=base->object->action->chanbase.first; chan; chan=chan->next){
                                                if (is_ipo_key_selected(chan->ipo)){
                                                        sel=0;
                                        for (chan=base->object->action->chanbase.first; chan; chan=chan->next){
                                                if (is_ipo_key_selected(chan->ipo)){
                                                        sel=0;
@@ -755,12 +972,10 @@ void deselect_nlachannel_keys (int test)
                        
                        /* Test NLA strips */
                        if (sel){
                        
                        /* Test NLA strips */
                        if (sel){
-                               if (base->object->type==OB_ARMATURE){
-                                       for (strip=base->object->nlastrips.first; strip; strip=strip->next){
-                                               if (strip->flag & ACTSTRIP_SELECT){
-                                                       sel = 0;
-                                                       break;
-                                               }
+                               for (strip=base->object->nlastrips.first; strip; strip=strip->next){
+                                       if (strip->flag & ACTSTRIP_SELECT){
+                                               sel = 0;
+                                               break;
                                        }
                                }
                        }
                                        }
                                }
                        }
@@ -771,18 +986,21 @@ void deselect_nlachannel_keys (int test)
        
        
        /* Set the flags */
        
        
        /* Set the flags */
-       for (base=G.scene->base.first; base; base=base->next){
+       for (base=G.scene->base.first; base; base=base->next){          
                /* Set the object ipos */
                set_ipo_key_selection(base->object->ipo, sel);
                /* Set the object ipos */
                set_ipo_key_selection(base->object->ipo, sel);
-
                
                /* Set the object constraint ipos */
                for (conchan=base->object->constraintChannels.first; conchan; conchan=conchan->next){
                        set_ipo_key_selection(conchan->ipo, sel);                       
                }
 
                
                /* Set the object constraint ipos */
                for (conchan=base->object->constraintChannels.first; conchan; conchan=conchan->next){
                        set_ipo_key_selection(conchan->ipo, sel);                       
                }
 
+               /* check if collapsed */
+               if (base->object->nlaflag & OB_NLA_COLLAPSED)
+                       continue;
+               
                /* Set the action ipos */
                /* Set the action ipos */
-               if (base->object->type==OB_ARMATURE && base->object->action){
+               if (base->object->action){
                        for (chan=base->object->action->chanbase.first; chan; chan=chan->next){
                                set_ipo_key_selection(chan->ipo, sel);
                                /* Set the action constraint ipos */
                        for (chan=base->object->action->chanbase.first; chan; chan=chan->next){
                                set_ipo_key_selection(chan->ipo, sel);
                                /* Set the action constraint ipos */
@@ -792,13 +1010,11 @@ void deselect_nlachannel_keys (int test)
                }
                
                /* Set the nlastrips */
                }
                
                /* Set the nlastrips */
-               if (base->object->type==OB_ARMATURE){
-                       for (strip=base->object->nlastrips.first; strip; strip=strip->next){
-                               if (sel)
-                                       strip->flag |= ACTSTRIP_SELECT;
-                               else
-                                       strip->flag &= ~ACTSTRIP_SELECT;
-                       }
+               for (strip=base->object->nlastrips.first; strip; strip=strip->next){
+                       if (sel)
+                               strip->flag |= ACTSTRIP_SELECT;
+                       else
+                               strip->flag &= ~ACTSTRIP_SELECT;
                }
        }
 }
                }
        }
 }
@@ -818,241 +1034,30 @@ static void recalc_all_ipos(void)
        }
 }
 
        }
 }
 
-void transform_nlachannel_keys(char mode)
+void transform_nlachannel_keys(int mode, int dummy)
 {
 {
-       Base *base;
-       TransVert *tv;
-       int /*sel=0,*/  i;
-       short   mvals[2], mvalc[2];
-       //      short    cent[2];
-       float   sval[2], cval[2], lastcval[2];
-       short   cancel=0;
-       float   fac=0.0F;
-       int             loop=1;
-       int             tvtot=0;
-       float   deltax, startx;
-       //      float   cenf[2];
-       int             invert=0, firsttime=1;
-       char    str[256];
-       bActionChannel *chan;
-       bActionStrip *strip;
-       bConstraintChannel *conchan;
-
-       /* Ensure that partial selections result in beztriple selections */
-       for (base=G.scene->base.first; base; base=base->next){
-
-               /* Check object ipos */
-               tvtot+=fullselect_ipo_keys(base->object->ipo);
-               
-               /* Check object constraint ipos */
-               for(conchan=base->object->constraintChannels.first; conchan; conchan=conchan->next)
-                       tvtot+=fullselect_ipo_keys(conchan->ipo);                       
-               
-               /* Check action ipos */
-               if (base->object->type == OB_ARMATURE && base->object->action){
-                       for (chan=base->object->action->chanbase.first; chan; chan=chan->next){
-                               tvtot+=fullselect_ipo_keys(chan->ipo);
-                               
-                               /* Check action constraint ipos */
-                               for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next)
-                                       tvtot+=fullselect_ipo_keys(conchan->ipo);
-                       }
-               
-               }
-
-               /* Check nlastrips */
-               if (base->object->type==OB_ARMATURE){
-                       for (strip=base->object->nlastrips.first; strip; strip=strip->next){
-                               if (strip->flag & ACTSTRIP_SELECT)
-                                       tvtot+=2;
-                       }
-               }
-       }
-       
-       /* If nothing is selected, bail out */
-       if (!tvtot)
-               return;
-       
-       
-       /* Build the transvert structure */
-       tv = MEM_callocN (sizeof(TransVert) * tvtot, "transVert");
-       tvtot=0;
-       for (base=G.scene->base.first; base; base=base->next){
-               /* Manipulate object ipos */
-               tvtot=add_trans_ipo_keys(base->object->ipo, tv, tvtot);
-
-               /* Manipulate object constraint ipos */
-               for (conchan=base->object->constraintChannels.first; conchan; conchan=conchan->next)
-                       tvtot=add_trans_ipo_keys(conchan->ipo, tv, tvtot);
+       short context = (U.flag & USER_DRAGIMMEDIATE)?CTX_TWEAK:CTX_NONE;
 
 
-               /* Manipulate action ipos */
-               if (base->object->type==OB_ARMATURE && base->object->action){
-                       for (chan=base->object->action->chanbase.first; chan; chan=chan->next){
-                               tvtot=add_trans_ipo_keys(chan->ipo, tv, tvtot);
-
-                               /* Manipulate action constraint ipos */
-                               for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next)
-                                       tvtot=add_trans_ipo_keys(conchan->ipo, tv, tvtot);
-                       }
-               }
-
-               /* Manipulate nlastrips */
-               for (strip=base->object->nlastrips.first; strip; strip=strip->next){
-                       if (strip->flag & ACTSTRIP_SELECT){
-                               tv[tvtot+0].val=&strip->start;
-                               tv[tvtot+1].val=&strip->end;
-                               
-                               tv[tvtot+0].oldval = strip->start;
-                               tv[tvtot+1].oldval = strip->end;
-                               
-                               tvtot+=2;
-                       }
-               }
-       }
-       
-       /* Do the event loop */
-       //      cent[0] = curarea->winx + (G.snla->v2d.hor.xmax)/2;
-       //      cent[1] = curarea->winy + (G.snla->v2d.hor.ymax)/2;
-       
-       //      areamouseco_to_ipoco(cent, &cenf[0], &cenf[1]);
-       
-       getmouseco_areawin (mvals);
-       areamouseco_to_ipoco(G.v2d, mvals, &sval[0], &sval[1]);
-       
-       startx=sval[0];
-       while (loop) {
-               /*              Get the input */
-               /*              If we're cancelling, reset transformations */
-               /*                      Else calc new transformation */
-               /*              Perform the transformations */
-               while (qtest()) {
-                       short val;
-                       unsigned short event= extern_qread(&val);
-                       
-                       if (val) {
-                               switch (event) {
-                               case LEFTMOUSE:
-                               case SPACEKEY:
-                               case RETKEY:
-                                       loop=0;
-                                       break;
-                               case XKEY:
-                                       break;
-                               case ESCKEY:
-                               case RIGHTMOUSE:
-                                       cancel=1;
-                                       loop=0;
-                                       break;
-                               default:
-                                       arrows_move_cursor(event);
-                                       break;
-                               };
-                       }
+       switch (mode) {
+               case 'g':
+               {
+                       initTransform(TFM_TIME_TRANSLATE, context);
+                       Transform();
                }
                }
-               
-               if (cancel) {
-                       for (i=0; i<tvtot; i++) {
-                               if (tv[i].loc){
-                                       tv[i].loc[0]=tv[i].oldloc[0];
-                                       tv[i].loc[1]=tv[i].oldloc[1];
-                               }
-                               if (tv[i].val)
-                                       tv[i].val[0]=tv[i].oldval;
-                       }
+                       break;
+               case 's':
+               {
+                       initTransform(TFM_TIME_SCALE, context);
+                       Transform();
                }
                }
-               else {
-                       getmouseco_areawin (mvalc);
-                       areamouseco_to_ipoco(G.v2d, mvalc, &cval[0], &cval[1]);
-                       
-                       if (!firsttime && lastcval[0]==cval[0] && lastcval[1]==cval[1]) {
-                               PIL_sleep_ms(1);
-                       }
-                       else {
-                               for (i=0; i<tvtot; i++){
-                                       if (tv[i].loc)
-                                               tv[i].loc[0]=tv[i].oldloc[0];
-                                       if (tv[i].val)
-                                               tv[i].val[0]=tv[i].oldval;
-                                       
-                                       switch (mode){
-                                       case 'g':
-                                               deltax = cval[0]-sval[0];
-                                               fac= deltax;
-                                               
-                                               apply_keyb_grid(&fac, 0.0F, 1.0F, 0.1F, U.flag & USER_AUTOGRABGRID);
-                                               
-                                               if (tv[i].loc)
-                                                       tv[i].loc[0]+=fac;
-                                               if (tv[i].val)
-                                                       tv[i].val[0]+=fac;
-                                               break;
-                                       case 's': 
-                                               startx=mvals[0]-(NLAWIDTH/2+(curarea->winrct.xmax-curarea->winrct.xmin)/2);
-                                               deltax=mvalc[0]-(NLAWIDTH/2+(curarea->winrct.xmax-curarea->winrct.xmin)/2);
-                                               fac= (float)fabs(deltax/startx);
-                                               
-                                               apply_keyb_grid(&fac, 0.0F, 0.2F, 0.1F, U.flag & USER_AUTOSIZEGRID);
-                                               
-                                               if (invert){
-                                                       if (i % 03 == 0){
-                                                               memcpy (tv[i].loc, tv[i].oldloc, sizeof(tv[i+2].oldloc));
-                                                       }
-                                                       if (i % 03 == 2){
-                                                               memcpy (tv[i].loc, tv[i].oldloc, sizeof(tv[i-2].oldloc));
-                                                       }
-                                                       
-                                                       fac*=-1;
-                                               }
-                                               startx= (G.scene->r.cfra);
-                                               
-                                               if (tv[i].loc){
-                                                       tv[i].loc[0]-= startx;
-                                                       tv[i].loc[0]*=fac;
-                                                       tv[i].loc[0]+= startx;
-                                               }
-                                               if (tv[i].val){
-                                                       tv[i].val[0]-= startx;
-                                                       tv[i].val[0]*=fac;
-                                                       tv[i].val[0]+= startx;
-                                               }
-                                               
-                                               break;
-                                       }
-                               }
-                       }
-                       
-                       if (mode=='s'){
-                               sprintf(str, "sizeX: %.3f", fac);
-                               headerprint(str);
-                       }
-                       else if (mode=='g'){
-                               sprintf(str, "deltaX: %.3f", fac);
-                               headerprint(str);
-                       }
-                       
-                       if (G.snla->lock){
-                               allqueue (REDRAWVIEW3D, 0);
-                               allqueue (REDRAWNLA, 0);
-                               allqueue (REDRAWIPO, 0);
-                               force_draw_all(0);
-                       }
-                       else {
-                               addqueue (curarea->win, REDRAWALL, 0);
-                               force_draw(0);
-                       }
+                       break;
+               case 'e':
+               {
+                       initTransform(TFM_TIME_EXTEND, context);
+                       Transform();
                }
                }
-               
-               lastcval[0]= cval[0];
-               lastcval[1]= cval[1];
-               firsttime= 0;
+                       break;
        }
        }
-       
-       if(cancel==0) BIF_undo_push("Select all NLA");
-       recalc_all_ipos();      // bad
-       allqueue (REDRAWVIEW3D, 0);
-       allqueue (REDRAWNLA, 0);
-       allqueue (REDRAWIPO, 0);
-       MEM_freeN (tv);
 }
 
 void delete_nlachannel_keys(void)
 }
 
 void delete_nlachannel_keys(void)
@@ -1061,12 +1066,8 @@ void delete_nlachannel_keys(void)
        bActionChannel *chan;
        bConstraintChannel *conchan;
        bActionStrip *strip, *nextstrip;
        bActionChannel *chan;
        bConstraintChannel *conchan;
        bActionStrip *strip, *nextstrip;
-       
-       if (!okee("Erase selected keys"))
-               return;
-       
+               
        for (base = G.scene->base.first; base; base=base->next){
        for (base = G.scene->base.first; base; base=base->next){
-
                /* Delete object ipos */
                delete_ipo_keys(base->object->ipo);
                
                /* Delete object ipos */
                delete_ipo_keys(base->object->ipo);
                
@@ -1074,31 +1075,39 @@ void delete_nlachannel_keys(void)
                for(conchan=base->object->constraintChannels.first; conchan; conchan=conchan->next)
                        delete_ipo_keys(conchan->ipo);
 
                for(conchan=base->object->constraintChannels.first; conchan; conchan=conchan->next)
                        delete_ipo_keys(conchan->ipo);
 
+               /* skip actions and nlastrips if object collapsed */
+               if (base->object->nlaflag & OB_NLA_COLLAPSED)
+                       continue;
+                       
                /* Delete NLA strips */
                /* Delete NLA strips */
-               if (base->object->type==OB_ARMATURE){
-                       for (strip = base->object->nlastrips.first; strip; strip=nextstrip){
-                               nextstrip=strip->next;
-                               if (strip->flag & ACTSTRIP_SELECT){
-                                       free_actionstrip(strip);
-                                       BLI_remlink(&base->object->nlastrips, strip);
-                                       MEM_freeN(strip);
-                               }
+               for (strip = base->object->nlastrips.first; strip; strip=nextstrip){
+                       nextstrip=strip->next;
+                       if (strip->flag & ACTSTRIP_SELECT){
+                               free_actionstrip(strip);
+                               BLI_remlink(&base->object->nlastrips, strip);
+                               MEM_freeN(strip);
                        }
                }
                
                /* Delete action ipos */
                        }
                }
                
                /* Delete action ipos */
-               if (base->object->type==OB_ARMATURE && base->object->action){
+               if (base->object->action){
                        for (chan=base->object->action->chanbase.first; chan; chan=chan->next){
                        for (chan=base->object->action->chanbase.first; chan; chan=chan->next){
-                               delete_ipo_keys(chan->ipo);
+                               if (EDITABLE_ACHAN(chan))
+                                       delete_ipo_keys(chan->ipo);
+                                       
                                /* Delete action constraint keys */
                                /* Delete action constraint keys */
-                               for(conchan=chan->constraintChannels.first; conchan; conchan=conchan->next)
-                                       delete_ipo_keys(conchan->ipo);
+                               for(conchan=chan->constraintChannels.first; conchan; conchan=conchan->next){
+                                       if (EDITABLE_CONCHAN(conchan))
+                                               delete_ipo_keys(conchan->ipo);
+                               }
                        }
                }
        }
        
                        }
                }
        }
        
-       BIF_undo_push("Delete NLA keys");
        recalc_all_ipos();      // bad
        recalc_all_ipos();      // bad
+       synchronize_action_strips();
+       
+       BIF_undo_push("Delete NLA keys");
        allspace(REMAKEIPO,0);
        allqueue (REDRAWVIEW3D, 0);
        allqueue(REDRAWNLA, 0);
        allspace(REMAKEIPO,0);
        allqueue (REDRAWVIEW3D, 0);
        allqueue(REDRAWNLA, 0);
@@ -1113,47 +1122,54 @@ void duplicate_nlachannel_keys(void)
        bActionStrip *strip, *laststrip;
        
        /* Find selected items */
        bActionStrip *strip, *laststrip;
        
        /* Find selected items */
-       for (base = G.scene->base.first; base; base=base->next){
+       for (base = G.scene->base.first; base; base=base->next){        
                /* Duplicate object keys */
                duplicate_ipo_keys(base->object->ipo);
                
                /* Duplicate object constraint keys */
                for(conchan=base->object->constraintChannels.first; conchan; conchan=conchan->next)
                        duplicate_ipo_keys(conchan->ipo);
                /* Duplicate object keys */
                duplicate_ipo_keys(base->object->ipo);
                
                /* Duplicate object constraint keys */
                for(conchan=base->object->constraintChannels.first; conchan; conchan=conchan->next)
                        duplicate_ipo_keys(conchan->ipo);
-
+               
+               /* skip actions and nlastrips if object collapsed */
+               if (base->object->nlaflag & OB_NLA_COLLAPSED)
+                       continue;
+                       
                /* Duplicate nla strips */
                /* Duplicate nla strips */
-               if (base->object->type == OB_ARMATURE){
-                       laststrip = base->object->nlastrips.last;
-                       for (strip=base->object->nlastrips.first; strip; strip=strip->next){
-                               if (strip->flag & ACTSTRIP_SELECT){
-                                       bActionStrip *newstrip;
-                                       
-                                       copy_actionstrip(&newstrip, &strip);
-                                       
-                                       BLI_addtail(&base->object->nlastrips, newstrip);
-                                       
-                                       strip->flag &= ~ACTSTRIP_SELECT;
-                                       newstrip->flag |= ACTSTRIP_SELECT;
-                                       
-                               }
-                               if (strip==laststrip)
-                                       break;
+               laststrip = base->object->nlastrips.last;
+               for (strip=base->object->nlastrips.first; strip; strip=strip->next){
+                       if (strip->flag & ACTSTRIP_SELECT){
+                               bActionStrip *newstrip;
+                               
+                               copy_actionstrip(&newstrip, &strip);
+                               
+                               BLI_addtail(&base->object->nlastrips, newstrip);
+                               
+                               strip->flag &= ~ACTSTRIP_SELECT;
+                               newstrip->flag |= ACTSTRIP_SELECT;
+                               set_active_strip(base->object, newstrip);
+
                        }
                        }
+                       if (strip==laststrip)
+                               break;
                }
                
                /* Duplicate actionchannel keys */
                }
                
                /* Duplicate actionchannel keys */
-               if (base->object->type == OB_ARMATURE && base->object->action){
+               if (base->object->action){
                        for (chan=base->object->action->chanbase.first; chan; chan=chan->next){
                        for (chan=base->object->action->chanbase.first; chan; chan=chan->next){
-                               duplicate_ipo_keys(chan->ipo);
+                               if (EDITABLE_ACHAN(chan))
+                                       duplicate_ipo_keys(chan->ipo);
+                                       
                                /* Duplicate action constraint keys */
                                /* Duplicate action constraint keys */
-                               for(conchan=chan->constraintChannels.first; conchan; conchan=conchan->next)
-                                       duplicate_ipo_keys(conchan->ipo);
+                               for(conchan=chan->constraintChannels.first; conchan; conchan=conchan->next) {
+                                       if (EDITABLE_CONCHAN(conchan))
+                                               duplicate_ipo_keys(conchan->ipo);
+                               }
                        }
                }
        }
        
        BIF_undo_push("Duplicate NLA");
                        }
                }
        }
        
        BIF_undo_push("Duplicate NLA");
-       transform_nlachannel_keys ('g');
+       transform_nlachannel_keys ('g', 0);
 }
 
 void borderselect_nla(void)
 }
 
 void borderselect_nla(void)
@@ -1168,11 +1184,11 @@ void borderselect_nla(void)
        bConstraintChannel *conchan;
        
        if ( (val = get_border (&rect, 3)) ){
        bConstraintChannel *conchan;
        
        if ( (val = get_border (&rect, 3)) ){
-    if (val == LEFTMOUSE)
-      selectmode = SELECT_ADD;
-    else
-      selectmode = SELECT_SUBTRACT;
-
+           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);
                mval[0]= rect.xmin;
                mval[1]= rect.ymin+2;
                areamouseco_to_ipoco(G.v2d, mval, &rectf.xmin, &rectf.ymin);
@@ -1182,90 +1198,98 @@ void borderselect_nla(void)
                
                ymax = count_nla_levels();
                ymax*= (NLACHANNELHEIGHT+NLACHANNELSKIP);
                
                ymax = count_nla_levels();
                ymax*= (NLACHANNELHEIGHT+NLACHANNELSKIP);
-               
+               ymax+= (NLACHANNELHEIGHT+NLACHANNELSKIP)/2;
+       
                for (base=G.scene->base.first; base; base=base->next){
                for (base=G.scene->base.first; base; base=base->next){
-                       /* Check object ipos */
-                       if (nla_filter(base, 0)){
+                       if (nla_filter(base)) {
+                               
                                ymin=ymax-(NLACHANNELHEIGHT+NLACHANNELSKIP);
                                ymin=ymax-(NLACHANNELHEIGHT+NLACHANNELSKIP);
+                               
+                               /* Check object ipos */
                                if (base->object->ipo){
                                        if (!((ymax < rectf.ymin) || (ymin > rectf.ymax)))
                                                borderselect_ipo_key(base->object->ipo, rectf.xmin, rectf.xmax,
                                  selectmode);
                                }
                                if (base->object->ipo){
                                        if (!((ymax < rectf.ymin) || (ymin > rectf.ymax)))
                                                borderselect_ipo_key(base->object->ipo, rectf.xmin, rectf.xmax,
                                  selectmode);
                                }
-                               ymax=ymin;
-
                                /* Check object constraint ipos */
                                for (conchan=base->object->constraintChannels.first; conchan; conchan=conchan->next){
                                /* Check object constraint ipos */
                                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,
                                  selectmode);
                                        if (!((ymax < rectf.ymin) || (ymin > rectf.ymax)))
                                                borderselect_ipo_key(conchan->ipo, rectf.xmin, rectf.xmax,
                                  selectmode);
-                                       ymax=ymin;
                                }
                                }
-
+                               
+                               ymax=ymin;
+                               
+                               /* skip actions and nlastrips if object collapsed */
+                               if (base->object->nlaflag & OB_NLA_COLLAPSED)
+                                       continue;
+                               
                                /* Check action ipos */
                                /* Check action ipos */
-                               if (ACTIVE_ARMATURE(base)){
+                               if (base->object->action){
+                                       bActionChannel *chan;
+                                       float xmin, xmax;
+                                       
                                        ymin=ymax-(NLACHANNELHEIGHT+NLACHANNELSKIP);
                                        ymin=ymax-(NLACHANNELHEIGHT+NLACHANNELSKIP);
-                                       if (base->object->action){
-                                               bActionChannel *chan;
-                                               
-                                               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,
-                                     selectmode);
-                                                               /* Check action constraint ipos */
-                                                               for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next)
-                                                                       borderselect_ipo_key(conchan->ipo, rectf.xmin, rectf.xmax,
-                                       selectmode);
-                                                       }
+                                       
+                                       /* if action is mapped in NLA, it returns a correction */
+                                       xmin= get_action_frame(base->object, rectf.xmin);
+                                       xmax= get_action_frame(base->object, rectf.xmax);
+                                       
+                                       if (!((ymax < rectf.ymin) || (ymin > rectf.ymax))){
+                                               for (chan=base->object->action->chanbase.first; chan; chan=chan->next){
+                                                       borderselect_ipo_key(chan->ipo, xmin, xmax, selectmode);
+                                                       /* Check action constraint ipos */
+                                                       for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next)
+                                                               borderselect_ipo_key(conchan->ipo, xmin, xmax, selectmode);
                                                }
                                        }
                                                }
                                        }
+
                                        ymax=ymin;
                                        ymax=ymin;
-                               }       /* End of if armature */
+                               }       /* End of if action */
                                
                                /* Skip nlastrips */
                                
                                /* Skip nlastrips */
-                               if (base->object->type==OB_ARMATURE){
-                                       for (strip=base->object->nlastrips.first; strip; strip=strip->next){
-                                               ymin=ymax-(NLACHANNELHEIGHT+NLACHANNELSKIP);
-                                               //
-                                               if (!((ymax < rectf.ymin) || (ymin > rectf.ymax))){
-                                                       if (!((rectf.xmax<strip->start) || (rectf.xmin>strip->end))){
-                                                               if (val==1)
-                                                                       strip->flag |= ACTSTRIP_SELECT;
-                                                               else
-                                                                       strip->flag &= ~ACTSTRIP_SELECT;
-                                                       }
+                               for (strip=base->object->nlastrips.first; strip; strip=strip->next){
+                                       ymin=ymax-(NLACHANNELHEIGHT+NLACHANNELSKIP);
+                                       //
+                                       if (!((ymax < rectf.ymin) || (ymin > rectf.ymax))){
+                                               if (!((rectf.xmax<strip->start) || (rectf.xmin>strip->end))){
+                                                       if (val==1)
+                                                               strip->flag |= ACTSTRIP_SELECT;
+                                                       else
+                                                               strip->flag &= ~ACTSTRIP_SELECT;
                                                }
                                                }
-                                               
-                                               ymax=ymin;
                                        }
                                        }
+                                       
+                                       ymax=ymin;
                                }
                                }
-                               
-                       }       /* End of object filter */
+                       }
                }       
                BIF_undo_push("Border select NLA");
                }       
                BIF_undo_push("Border select NLA");
-               allqueue(REDRAWNLA, 0);
-               allqueue(REDRAWACTION, 0);
-               allqueue(REDRAWIPO, 0);
+               allqueue(REDRAWMARKER, 0);
        }
 }
 
        }
 }
 
+/* right hand side of window, does ipokeys, actionkeys or strips */
 static void mouse_nla(int selectmode)
 {
 static void mouse_nla(int selectmode)
 {
-       short sel;
-       float   selx;
-       short   mval[2];
        Base *base;
        bAction *act;
        bActionChannel *chan;
        bActionStrip *rstrip;
        bConstraintChannel *conchan;
        Base *base;
        bAction *act;
        bActionChannel *chan;
        bActionStrip *rstrip;
        bConstraintChannel *conchan;
+       TimeMarker *marker;
+       float   selx;
+       short   mval[2];
+       short sel, isdone=0;
        
        getmouseco_areawin (mval);
        
        
        getmouseco_areawin (mval);
        
-       /* Try object ipo selection */
+       /* Try object ipo or ob-constraint ipo selection */
        base= get_nearest_nlachannel_ob_key(&selx, &sel);
        base= get_nearest_nlachannel_ob_key(&selx, &sel);
+       marker=find_nearest_marker(SCE_MARKERS, 1);
        if (base) {
        if (base) {
+               isdone= 1;
+               
                if (selectmode == SELECT_REPLACE){
                        deselect_nlachannel_keys(0);
                        selectmode = SELECT_ADD;
                if (selectmode == SELECT_REPLACE){
                        deselect_nlachannel_keys(0);
                        selectmode = SELECT_ADD;
@@ -1276,71 +1300,89 @@ static void mouse_nla(int selectmode)
                /* Try object constraint selection */
                for (conchan=base->object->constraintChannels.first; conchan; conchan=conchan->next)
                        select_ipo_key(conchan->ipo, selx, selectmode);
                /* Try object constraint selection */
                for (conchan=base->object->constraintChannels.first; conchan; conchan=conchan->next)
                        select_ipo_key(conchan->ipo, selx, selectmode);
-               
-               
-               BIF_undo_push("Select NLA");
-               allqueue(REDRAWIPO, 0);
-               allqueue(REDRAWVIEW3D, 0);
-               allqueue(REDRAWNLA, 0);
-               return;
        }
        }
-
-       /* Try action ipo selection */
-       act= get_nearest_nlachannel_ac_key(&selx, &sel);
-       if (act) {
-               if (selectmode == SELECT_REPLACE){
-                       deselect_nlachannel_keys(0);
-                       selectmode = SELECT_ADD;
+       else if (marker) {
+               /* marker */            
+               if (selectmode == SELECT_REPLACE) {                     
+                       deselect_markers(0, 0);
+                       marker->flag |= SELECT;
                }
                }
-               
-               for (chan=act->chanbase.first; chan; chan=chan->next) {
-                       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, selectmode);
+               else if (selectmode == SELECT_INVERT) {
+                       if (marker->flag & SELECT)
+                               marker->flag &= ~SELECT;
+                       else
+                               marker->flag |= SELECT;
                }
                }
+               else if (selectmode == SELECT_ADD) 
+                       marker->flag |= SELECT;
+               else if (selectmode == SELECT_SUBTRACT)
+                       marker->flag &= ~SELECT;
                
                
-               BIF_undo_push("Select NLA");
-               allqueue(REDRAWIPO, 0);
-               allqueue(REDRAWVIEW3D, 0);
-               allqueue(REDRAWNLA, 0);
-               return;
+               std_rmouse_transform(transform_markers);
+               
+               allqueue(REDRAWMARKER, 0);
        }
        }
-       
-       /* Try nla strip selection */
-       base= get_nearest_nlastrip(&rstrip, &sel);
-       if (base){
-               if (!(G.qual & LR_SHIFTKEY)){
-                       deselect_nlachannel_keys(0);
-                       sel = 0;
+       else {
+               /* Try action ipo selection */
+               act= get_nearest_nlachannel_ac_key(&selx, &sel);
+               if (act) {
+                       isdone= 1;
+                       
+                       if (selectmode == SELECT_REPLACE){
+                               deselect_nlachannel_keys(0);
+                               selectmode = SELECT_ADD;
+                       }
+                       
+                       for (chan=act->chanbase.first; chan; chan=chan->next) {
+                               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, selectmode);
+                       }
                }
                }
+               else {
+       
+                       /* Try nla strip selection */
+                       base= get_nearest_nlastrip(&rstrip, &sel);
+                       if (base){
+                               isdone= 1;
+                               
+                               if (!(G.qual & LR_SHIFTKEY)){
+                                       deselect_nlachannel_keys(0);
+                                       sel = 0;
+                               }
+                               
+                               if (sel)
+                                       rstrip->flag &= ~ACTSTRIP_SELECT;
+                               else
+                                       rstrip->flag |= ACTSTRIP_SELECT;
+                               
+                               set_active_strip(base->object, rstrip);
+                               
+                               if(base!=BASACT) set_active_base(base);
+                       }
+               }
+       }
+       
+       if(isdone) {
+               std_rmouse_transform(transform_nlachannel_keys);
                
                
-               if (sel)
-                       rstrip->flag &= ~ACTSTRIP_SELECT;
-               else
-                       rstrip->flag |= ACTSTRIP_SELECT;
-               
-               BIF_undo_push("Select NLA");
                allqueue(REDRAWIPO, 0);
                allqueue(REDRAWVIEW3D, 0);
                allqueue(REDRAWNLA, 0);
                allqueue(REDRAWIPO, 0);
                allqueue(REDRAWVIEW3D, 0);
                allqueue(REDRAWNLA, 0);
-               return;
-               
        }
        }
-       
 }
 
 }
 
-static Base *get_nearest_nlastrip (bActionStrip **rstrip, short *sel)
 /* This function is currently more complicated than it seems like it should be.
 * However, this will be needed once the nla strip timeline is more complex */
 /* This function is currently more complicated than it seems like it should be.
 * However, this will be needed once the nla strip timeline is more complex */
+static Base *get_nearest_nlastrip (bActionStrip **rstrip, short *sel)
 {
        Base *base, *firstbase=NULL;
 {
        Base *base, *firstbase=NULL;
-       short mval[2];
-       short foundsel = 0;
+       bActionStrip *strip, *firststrip=NULL, *foundstrip=NULL;
        rctf    rectf;
        float ymin, ymax;
        rctf    rectf;
        float ymin, ymax;
-       bActionStrip *strip, *firststrip=NULL, *foundstrip=NULL;
-       bConstraintChannel *conchan=NULL;
+       short mval[2];
+       short foundsel = 0;
 
        getmouseco_areawin (mval);
        
 
        getmouseco_areawin (mval);
        
@@ -1355,48 +1397,46 @@ static Base *get_nearest_nlastrip (bActionStrip **rstrip, short *sel)
        ymax+= NLACHANNELHEIGHT/2;
        
        for (base = G.scene->base.first; base; base=base->next){
        ymax+= NLACHANNELHEIGHT/2;
        
        for (base = G.scene->base.first; base; base=base->next){
-               if (nla_filter(base, 0)){
+               if (nla_filter(base)) {
+                       
                        /* Skip object ipos */
                        /* Skip object ipos */
-                       //      if (base->object->ipo)
                        ymax-=(NLACHANNELHEIGHT+NLACHANNELSKIP);
                        ymax-=(NLACHANNELHEIGHT+NLACHANNELSKIP);
+                       
+                       /* check if skip strips if collapsed */
+                       if (base->object->nlaflag & OB_NLA_COLLAPSED)
+                               continue;
 
 
-                       /* Skip constraint channels */
-                       for (conchan=base->object->constraintChannels.first; 
-                                conchan; conchan=conchan->next){
+                       /* Skip action ipos */
+                       if (base->object->action)
                                ymax-=(NLACHANNELHEIGHT+NLACHANNELSKIP);
                                ymax-=(NLACHANNELHEIGHT+NLACHANNELSKIP);
-                       }
-
-                       if (base->object->type==OB_ARMATURE){
-                               /* Skip action ipos */
-                               if (base->object->action)
-                                       ymax-=(NLACHANNELHEIGHT+NLACHANNELSKIP);
-                               for (strip=base->object->nlastrips.first; strip; strip=strip->next){
-                                       ymin=ymax-(NLACHANNELHEIGHT+NLACHANNELSKIP);
-                                       /* Do Ytest */
-                                       if (!((ymax < rectf.ymin) || (ymin > rectf.ymax))){
-                                               /* Do XTest */
-                                               if (!((rectf.xmax<strip->start) || (rectf.xmin>strip->end))){
-                                                       if (!firstbase){
-                                                               firstbase=base;
-                                                               firststrip=strip;
-                                                               *sel = strip->flag & ACTSTRIP_SELECT;
-                                                       }
-                                                       
-                                                       if (strip->flag & ACTSTRIP_SELECT){ 
-                                                               if (!foundsel){
-                                                                       foundsel=1;
-                                                                       foundstrip = strip;
-                                                               }
-                                                       }
-                                                       else if (foundsel && strip != foundstrip){
-                                                               *rstrip=strip;
-                                                               *sel = 0;
-                                                               return base;
+                       
+                       /* the strips */
+                       for (strip=base->object->nlastrips.first; strip; strip=strip->next){
+                               ymin=ymax-(NLACHANNELHEIGHT+NLACHANNELSKIP);
+                               /* Do Ytest */
+                               if (!((ymax < rectf.ymin) || (ymin > rectf.ymax))){
+                                       /* Do XTest */
+                                       if (!((rectf.xmax<strip->start) || (rectf.xmin>strip->end))){
+                                               if (!firstbase){
+                                                       firstbase=base;
+                                                       firststrip=strip;
+                                                       *sel = strip->flag & ACTSTRIP_SELECT;
+                                               }
+                                               
+                                               if (strip->flag & ACTSTRIP_SELECT){ 
+                                                       if (!foundsel){
+                                                               foundsel=1;
+                                                               foundstrip = strip;
                                                        }
                                                }
                                                        }
                                                }
+                                               else if (foundsel && strip != foundstrip){
+                                                       *rstrip=strip;
+                                                       *sel = 0;
+                                                       return base;
+                                               }
                                        }
                                        }
-                                       ymax=ymin;
                                }
                                }
+                               ymax=ymin;
                        }
                }
        }
                        }
                }
        }
@@ -1411,7 +1451,7 @@ static Base *get_nearest_nlachannel_ob_key (float *index, short *sel)
        Base *firstbase=NULL;
        bConstraintChannel *conchan;
        int     foundsel=0;
        Base *firstbase=NULL;
        bConstraintChannel *conchan;
        int     foundsel=0;
-       float firstvert=-1, foundx=-1;
+       float firstvertx=-1, foundx=-1;
        int i;
        short mval[2];
        float ymin, ymax;
        int i;
        short mval[2];
        float ymin, ymax;
@@ -1435,9 +1475,11 @@ static Base *get_nearest_nlachannel_ob_key (float *index, short *sel)
        *sel=0;
        
        for (base=G.scene->base.first; base; base=base->next){
        *sel=0;
        
        for (base=G.scene->base.first; base; base=base->next){
-               /* Handle object ipo selection */
-               if (nla_filter(base, 0)){
+               if (nla_filter(base)) {
+                       
                        ymin=ymax-(NLACHANNELHEIGHT+NLACHANNELSKIP);
                        ymin=ymax-(NLACHANNELHEIGHT+NLACHANNELSKIP);
+                       
+                       /* Handle object ipo selection */
                        if (base->object->ipo){
                                if (!((ymax < rectf.ymin) || (ymin > rectf.ymax))){
                                        for (icu=base->object->ipo->curve.first; icu; icu=icu->next){
                        if (base->object->ipo){
                                if (!((ymax < rectf.ymin) || (ymin > rectf.ymax))){
                                        for (icu=base->object->ipo->curve.first; icu; icu=icu->next){
@@ -1445,7 +1487,7 @@ static Base *get_nearest_nlachannel_ob_key (float *index, short *sel)
                                                        if (icu->bezt[i].vec[1][0] > rectf.xmin && icu->bezt[i].vec[1][0] <= rectf.xmax ){
                                                                if (!firstbase){
                                                                        firstbase=base;
                                                        if (icu->bezt[i].vec[1][0] > rectf.xmin && icu->bezt[i].vec[1][0] <= rectf.xmax ){
                                                                if (!firstbase){
                                                                        firstbase=base;
-                                                                       firstvert=icu->bezt[i].vec[1][0];
+                                                                       firstvertx=icu->bezt[i].vec[1][0];
                                                                        *sel = icu->bezt[i].f2 & 1;     
                                                                }
                                                                
                                                                        *sel = icu->bezt[i].f2 & 1;     
                                                                }
                                                                
@@ -1465,19 +1507,15 @@ static Base *get_nearest_nlachannel_ob_key (float *index, short *sel)
                                        }
                                }
                        }
                                        }
                                }
                        }
-               
-                       ymax=ymin;
-
                        /* Handle object constraint ipos */
                        for (conchan=base->object->constraintChannels.first; conchan; conchan=conchan->next){
                        /* Handle object constraint ipos */
                        for (conchan=base->object->constraintChannels.first; conchan; conchan=conchan->next){
-                               ymin=ymax-(NLACHANNELHEIGHT+NLACHANNELSKIP);
-                               if (!((ymax < rectf.ymin) || (ymin > rectf.ymax))){
+                               if ( !((ymax < rectf.ymin) || (ymin > rectf.ymax)) && conchan->ipo){
                                        for (icu=conchan->ipo->curve.first; icu; icu=icu->next){
                                                for (i=0; i<icu->totvert; i++){
                                                        if (icu->bezt[i].vec[1][0] > rectf.xmin && icu->bezt[i].vec[1][0] <= rectf.xmax ){
                                                                if (!firstbase){
                                                                        firstbase=base;
                                        for (icu=conchan->ipo->curve.first; icu; icu=icu->next){
                                                for (i=0; i<icu->totvert; i++){
                                                        if (icu->bezt[i].vec[1][0] > rectf.xmin && icu->bezt[i].vec[1][0] <= rectf.xmax ){
                                                                if (!firstbase){
                                                                        firstbase=base;
-                                                                       firstvert=icu->bezt[i].vec[1][0];
+                                                                       firstvertx=icu->bezt[i].vec[1][0];
                                                                        *sel = icu->bezt[i].f2 & 1;     
                                                                }
                                                                
                                                                        *sel = icu->bezt[i].f2 & 1;     
                                                                }
                                                                
@@ -1496,21 +1534,24 @@ static Base *get_nearest_nlachannel_ob_key (float *index, short *sel)
                                                }
                                        }
                                }
                                                }
                                        }
                                }
-                               ymax=ymin;
                        }
 
                        }
 
+                       ymax=ymin;
+                       
+                       /* Skip actions and nlastrips if object is collapsed */
+                       if (base->object->nlaflag & OB_NLA_COLLAPSED)
+                               continue;
+                       
                        /* Skip action ipos */
                        /* Skip action ipos */
-                       if (ACTIVE_ARMATURE(base)){
+                       if (base->object->action){
                                ymax-=(NLACHANNELHEIGHT+NLACHANNELSKIP);
                        }
                        /* Skip nlastrips */
                                ymax-=(NLACHANNELHEIGHT+NLACHANNELSKIP);
                        }
                        /* Skip nlastrips */
-                       if (base->object->type==OB_ARMATURE){
-                               ymax-=(NLACHANNELHEIGHT+NLACHANNELSKIP)*BLI_countlist(&base->object->nlastrips);
-                       }
+                       ymax-=(NLACHANNELHEIGHT+NLACHANNELSKIP)*BLI_countlist(&base->object->nlastrips);
                }
        }       
        
                }
        }       
        
-       *index=firstvert;
+       *index=firstvertx;
        return firstbase;
 }
 
        return firstbase;
 }
 
@@ -1519,14 +1560,14 @@ static bAction *get_nearest_nlachannel_ac_key (float *index, short *sel)
        Base *base;
        IpoCurve *icu;
        bAction *firstact=NULL;
        Base *base;
        IpoCurve *icu;
        bAction *firstact=NULL;
-       int     foundsel=0;
+       bActionChannel *chan;
+       bConstraintChannel *conchan;
+       rctf    rectf;
        float firstvert=-1, foundx=-1;
        float firstvert=-1, foundx=-1;
+       float ymin, ymax, xmin, xmax;
        int i;
        int i;
+       int     foundsel=0;
        short mval[2];
        short mval[2];
-       float ymin, ymax;
-       rctf    rectf;
-       bActionChannel *chan;
-       bConstraintChannel *conchan;
        
        *index=0;
        
        
        *index=0;
        
@@ -1547,47 +1588,60 @@ static bAction *get_nearest_nlachannel_ac_key (float *index, short *sel)
        
        for (base=G.scene->base.first; base; base=base->next){
                /* Handle object ipo selection */
        
        for (base=G.scene->base.first; base; base=base->next){
                /* Handle object ipo selection */
-               if (nla_filter(base, 0)){
-                       /* Skip object ipo */
+               if (nla_filter(base)) {
+                       
+                       /* Skip object ipo and ob-constraint ipo */
                        ymin=ymax-(NLACHANNELHEIGHT+NLACHANNELSKIP);
                        ymin=ymax-(NLACHANNELHEIGHT+NLACHANNELSKIP);
+                       
+                       /* skip this object if it is collapsed */
+                       if (base->object->nlaflag & OB_NLA_COLLAPSED)
+                               continue;
+                       
                        ymax=ymin;
                        
                        /* Handle action ipos */
                        ymax=ymin;
                        
                        /* Handle action ipos */
-                       if (ACTIVE_ARMATURE(base)){
+                       if (base->object->action){
+                               bAction *act= base->object->action;
+                               
+                               /* if action is mapped in NLA, it returns a correction */
+                               xmin= get_action_frame(base->object, rectf.xmin);
+                               xmax= get_action_frame(base->object, rectf.xmax);
+                               
                                ymin=ymax-(NLACHANNELHEIGHT+NLACHANNELSKIP);
                                if (!((ymax < rectf.ymin) || (ymin > rectf.ymax))){
                                ymin=ymax-(NLACHANNELHEIGHT+NLACHANNELSKIP);
                                if (!((ymax < rectf.ymin) || (ymin > rectf.ymax))){
-                                       for (chan=base->object->action->chanbase.first; chan; chan=chan->next){
-                                               for (icu=chan->ipo->curve.first; icu; icu=icu->next){
-                                                       for (i=0; i<icu->totvert; i++){
-                                                               if (icu->bezt[i].vec[1][0] > rectf.xmin && icu->bezt[i].vec[1][0] <= rectf.xmax ){
-                                                                       if (!firstact){
-                                                                               firstact=base->object->action;
-                                                                               firstvert=icu->bezt[i].vec[1][0];
-                                                                               *sel = icu->bezt[i].f2 & 1;     
-                                                                       }
-                                                                       
-                                                                       if (icu->bezt[i].f2 & 1){ 
-                                                                               if (!foundsel){
-                                                                                       foundsel=1;
-                                                                                       foundx = icu->bezt[i].vec[1][0];
+                                       for (chan=act->chanbase.first; chan; chan=chan->next){
+                                               if(chan->ipo) {
+                                                       for (icu=chan->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 (!firstact){
+                                                                                       firstact= act;
+                                                                                       firstvert=icu->bezt[i].vec[1][0];
+                                                                                       *sel = icu->bezt[i].f2 & 1;     
+                                                                               }
+                                                                               
+                                                                               if (icu->bezt[i].f2 & 1){ 
+                                                                                       if (!foundsel){
+                                                                                               foundsel=1;
+                                                                                               foundx = icu->bezt[i].vec[1][0];
+                                                                                       }
+                                                                               }
+                                                                               else if (foundsel && icu->bezt[i].vec[1][0] != foundx){
+                                                                                       *index=icu->bezt[i].vec[1][0];
+                                                                                       *sel = 0;
+                                                                                       return act;
                                                                                }
                                                                                }
-                                                                       }
-                                                                       else if (foundsel && icu->bezt[i].vec[1][0] != foundx){
-                                                                               *index=icu->bezt[i].vec[1][0];
-                                                                               *sel = 0;
-                                                                               return base->object->action;
                                                                        }
                                                                }
                                                        }
                                                }
                                                
                                                                        }
                                                                }
                                                        }
                                                }
                                                
-                                               
                                                for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next){
                                                        ymin=ymax-(NLACHANNELHEIGHT+NLACHANNELSKIP);
                                                for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next){
                                                        ymin=ymax-(NLACHANNELHEIGHT+NLACHANNELSKIP);
-                                                       if (!((ymax < rectf.ymin) || (ymin > rectf.ymax))){
+                                                       if ( !((ymax < rectf.ymin) || (ymin > rectf.ymax)) && conchan->ipo){
                                                                for (icu=conchan->ipo->curve.first; icu; icu=icu->next){
                                                                        for (i=0; i<icu->totvert; i++){
                                                                for (icu=conchan->ipo->curve.first; icu; icu=icu->next){
                                                                        for (i=0; i<icu->totvert; i++){
-                                                                               if (icu->bezt[i].vec[1][0] > rectf.xmin && icu->bezt[i].vec[1][0] <= rectf.xmax ){
+                                                                               if (icu->bezt[i].vec[1][0] > xmin && icu->bezt[i].vec[1][0] <= xmax ){
                                                                                        if (!firstact){
                                                                                                firstact=base->object->action;
                                                                                                firstvert=icu->bezt[i].vec[1][0];
                                                                                        if (!firstact){
                                                                                                firstact=base->object->action;
                                                                                                firstvert=icu->bezt[i].vec[1][0];
@@ -1619,9 +1673,7 @@ static bAction *get_nearest_nlachannel_ac_key (float *index, short *sel)
                        }
                        
                        /* Skip nlastrips */
                        }
                        
                        /* Skip nlastrips */
-                       if (base->object->type==OB_ARMATURE){
-                               ymax-=(NLACHANNELHEIGHT+NLACHANNELSKIP)*BLI_countlist(&base->object->nlastrips);
-                       }
+                       ymax-=(NLACHANNELHEIGHT+NLACHANNELSKIP)*BLI_countlist(&base->object->nlastrips);
                }
        }       
        
                }
        }       
        
@@ -1629,73 +1681,10 @@ static bAction *get_nearest_nlachannel_ac_key (float *index, short *sel)
        return firstact;
 }
 
        return firstact;
 }
 
-void clever_numbuts_nla(void){
-       bActionStrip *strip=NULL;
-       int but=0;
-               
-       /* Determine if an nla strip has been selected */
-       //strip = get_active_nlastrip();
-       if (!strip)
-               return;
-       
-       add_numbut(but++, LABEL, "Timeline Range:", 1.0, MAXFRAMEF, 0, 0);
-       add_numbut(but++, NUM|FLO, "Strip Start:", 1.0, MAXFRAMEF, &strip->start, "First frame in the timeline");
-       add_numbut(but++, NUM|FLO, "Strip End:", 1.0, MAXFRAMEF, &strip->end, "Last frame in the timeline");
-       add_numbut(but++, LABEL, "Action Range:", 1.0, MAXFRAMEF, 0, 0);
-       add_numbut(but++, NUM|FLO, "Action Start:", 1.0, MAXFRAMEF, &strip->actstart, "First frame of the action to map to the playrange");
-       add_numbut(but++, NUM|FLO, "Action End:", 1.0, MAXFRAMEF, &strip->actend, "Last frame of the action to map to the playrange");
-       add_numbut(but++, LABEL, "Blending:", 1.0, MAXFRAMEF, 0, 0);
-       add_numbut(but++, NUM|FLO, "Blend In:", 0.0, MAXFRAMEF, &strip->blendin, "Number of frames of ease-in");
-       add_numbut(but++, NUM|FLO, "Blend Out:", 0.0, MAXFRAMEF, &strip->blendout, "Number of frames of ease-out");
-       add_numbut(but++, LABEL, "Options:", 1.0, MAXFRAMEF, 0, 0);
-       add_numbut(but++, NUM|FLO, "Repeat:", 0.0001, MAXFRAMEF, &strip->repeat, "Number of times the action should repeat");
-       add_numbut(but++, NUM|FLO, "Stride:", 0.0001, MAXFRAMEF, &strip->stridelen, "Distance covered by one complete cycle of the action specified in the Action Range");
-       {
-               /* STUPID HACK BECAUSE NUMBUTS ARE BROKEN WITH MULTIPLE TOGGLES */
-               short hold= (strip->flag & ACTSTRIP_HOLDLASTFRAME) ? 1 : 0;
-               short frompath=(strip->flag & ACTSTRIP_USESTRIDE) ? 1 : 0;
-
-               add_numbut(but++, TOG|SHO, "Use Path", 0, 0, &frompath, "Plays action based on position on path & stride length.  Only valid for armatures that are parented to a path");
-               add_numbut(but++, TOG|SHO, "Hold", 0, 0, &hold, "Toggles whether or not to continue displaying the last frame past the end of the strip");
-               add_numbut(but++, TOG|SHO, "Add", 0, 0, &strip->mode, "Toggles additive blending mode");
-               
-               do_clever_numbuts("Action", but, REDRAW);
-               
-               /* STUPID HACK BECAUSE NUMBUTS ARE BROKEN WITH MULTIPLE TOGGLES */
-               if (hold) strip->flag |= ACTSTRIP_HOLDLASTFRAME;
-               else strip->flag &= ~ACTSTRIP_HOLDLASTFRAME;
-
-               if (frompath) strip->flag |= ACTSTRIP_USESTRIDE;
-               else strip->flag &= ~ACTSTRIP_USESTRIDE;
-               
-       }
-
-       if (strip->end<strip->start)
-               strip->end=strip->start;
-
-
-       if (strip->blendin>(strip->end-strip->start))
-               strip->blendin = strip->end-strip->start;
-
-       if (strip->blendout>(strip->end-strip->start))
-               strip->blendout = strip->end-strip->start;
-
-       if (strip->blendin > (strip->end-strip->start-strip->blendout))
-               strip->blendin = (strip->end-strip->start-strip->blendout);
-
-       if (strip->blendout > (strip->end-strip->start-strip->blendin))
-               strip->blendout = (strip->end-strip->start-strip->blendin);
-       
-       
-       update_for_newframe_muted();
-       allqueue (REDRAWNLA, 0);
-       allqueue (REDRAWVIEW3D, 0);
-}      
-
-void deselect_nlachannels(int test){
-       int sel = 1;
+void deselect_nlachannels(int test)
+{
        Base *base;
        Base *base;
-       bConstraintChannel *conchan;
+       int sel = 1;
 
        if (test){
                for (base=G.scene->base.first; base; base=base->next){
 
        if (test){
                for (base=G.scene->base.first; base; base=base->next){
@@ -1704,15 +1693,6 @@ void deselect_nlachannels(int test){
                                sel=0;
                                break;
                        }
                                sel=0;
                                break;
                        }
-
-                       /* Check constraint flags for previous selection */
-                       for (conchan=base->object->constraintChannels.first; conchan; conchan=conchan->next){
-                               if (conchan->flag & CONSTRAINT_CHANNEL_SELECT){
-                                       sel=0;
-                                       base = G.scene->base.last;
-                                       break;
-                               }
-                       }
                }
        }
        else
                }
        }
        else
@@ -1721,56 +1701,383 @@ void deselect_nlachannels(int test){
        /* Select objects */
        for (base=G.scene->base.first; base; base=base->next){
                if (sel){
        /* Select objects */
        for (base=G.scene->base.first; base; base=base->next){
                if (sel){
-                       if (nla_filter(base, 0))
+                       if (nla_filter(base))
                                base->flag |= SELECT;
                }
                else
                        base->flag &= ~SELECT;
                                base->flag |= SELECT;
                }
                else
                        base->flag &= ~SELECT;
-
-               /* Select constraint channels */
-               for (conchan=base->object->constraintChannels.first; conchan; conchan=conchan->next){
-                       if (sel){
-                               if (nla_filter(base, 0))
-                                       conchan->flag |= CONSTRAINT_CHANNEL_SELECT;
-                       }
-                       else
-                               conchan->flag &= ~CONSTRAINT_CHANNEL_SELECT;
-               }
+               
+               base->object->flag= base->flag;
        }       
 }
 
        }       
 }
 
-void delete_nlachannels(void){
-       Base *base;
-       bConstraintChannel *conchan, *nextchan;
-       int sel=0;
+static Object *get_object_from_active_strip(void) {
 
 
-       /* See if there is anything selected */
-       for (base = G.scene->base.first; base && (!sel); base=base->next){
-               /* Check constraints */
-               for (conchan=base->object->constraintChannels.first; conchan; conchan=conchan->next){
-                       if (conchan->flag & CONSTRAINT_CHANNEL_SELECT){
-                               sel = 1;
-                               break;
+       Base *base;
+       bActionStrip *strip;
+       
+       for (base=G.scene->base.first; base; base=base->next) {
+               if ((base->object->nlaflag & OB_NLA_COLLAPSED)==0) {
+                       for (strip = base->object->nlastrips.first; 
+                                strip; strip=strip->next){
+                               if (strip->flag & ACTSTRIP_SELECT) {
+                                       return base->object;
+                               }
                        }
                }
        }
                        }
                }
        }
+       return NULL;
+}
 
 
-       if (!sel)
-               return;
 
 
-       if (okee ("Delete selected channels")){
-               for (base=G.scene->base.first; base; base=base->next){
-                       for (conchan=base->object->constraintChannels.first; conchan; conchan=nextchan){
-                               nextchan = conchan->next;
+void winqreadnlaspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
+{
+       unsigned short event= evt->event;
+       short val= evt->val;
+       SpaceNla *snla = curarea->spacedata.first;
+       int doredraw= 0;
+       short   mval[2];
+       float dx,dy;
+       int     cfra;
+       short mousebut = L_MOUSE;
+       Object          *ob; //in shift-B / bake
+       
+       if (curarea->win==0) return;
+       if (!snla) return;
+       
+       if(val) {
+               if( uiDoBlocks(&curarea->uiblocks, event, 1)!=UI_NOTHING ) event= 0;
+               
+               /* swap mouse buttons based on user preference */
+               if (U.flag & USER_LMOUSESELECT) {
+                       if (event == LEFTMOUSE) {
+                               event = RIGHTMOUSE;
+                               mousebut = L_MOUSE;
+                       } else if (event == RIGHTMOUSE) {
+                               event = LEFTMOUSE;
+                               mousebut = R_MOUSE;
+                       }
+               }
+               
+               getmouseco_areawin(mval);
+               
+               switch(event) {
+                       case UI_BUT_EVENT:
+                               do_nlabuts(val); // in drawnla.c
+                               break;
+                               
+                       case HOMEKEY:
+                               do_nla_buttons(B_NLAHOME);
+                               break;
+                               
+                       case EQUALKEY:
+                               shift_nlastrips_up();
+                               break;
+                       
+                       case PAGEUPKEY:
+                               if (G.qual & LR_CTRLKEY)
+                                       shift_nlastrips_up();
+                               else {
+                                       nextprev_marker(1);
+                                       allqueue(REDRAWMARKER, 0);
+                               }                               
+                               break;
+                               
+                       case MINUSKEY:
+                               shift_nlastrips_down();
+                               break;
+                               
+                       case PAGEDOWNKEY:
+                               if (G.qual & LR_CTRLKEY)
+                                       shift_nlastrips_down();
+                               else {
+                                       nextprev_marker(-1);
+                                       allqueue(REDRAWMARKER, 0);
+                               }
+                               break;
+                               
+                       case AKEY:
+                               if (G.qual & LR_SHIFTKEY){
+                                       add_nlablock();
+                                       allqueue (REDRAWNLA, 0);
+                                       allqueue (REDRAWVIEW3D, 0);
+                               }
+                               else if (G.qual & LR_CTRLKEY) {
+                                       deselect_markers(1, 0);
+                                       allqueue(REDRAWMARKER, 0);
+                               }
+                               else{
+                                       if (mval[0]>=NLAWIDTH)
+                                               deselect_nlachannel_keys(1);
+                                       else{
+                                               deselect_nlachannels(1);
+                                               allqueue (REDRAWVIEW3D, 0);
+                                       }
+                                       allqueue (REDRAWNLA, 0);
+                                       allqueue (REDRAWIPO, 0);
+                                       BIF_undo_push("(De)select all NLA");
+                               }
+                               break;
+                               
+                       case BKEY:
+                               if (G.qual & LR_SHIFTKEY){
+                                       bake_all_to_action();
+                                       allqueue (REDRAWNLA, 0);
+                                   allqueue (REDRAWVIEW3D, 0);
+                                   BIF_undo_push("Bake All To Action");
+                                   ob = get_object_from_active_strip();
+                                   //build_match_caches(ob);
+                               }
+                               else if (G.qual & LR_CTRLKEY) 
+                                       borderselect_markers();
+                               else
+                                       borderselect_nla();
+                               break;
+                               
+                       case CKEY:
+                               if(G.qual==LR_CTRLKEY) {
+                                       if(okee("Copy Modifiers"))
+                                               copy_action_modifiers();
+                               }
+                               else convert_nla();
+                               break;
+                               
+                       case DKEY:
+                               if (G.qual == (LR_CTRLKEY|LR_SHIFTKEY) && mval[0]>=NLAWIDTH) {
+                                       duplicate_marker();
+                               }
+                               else if (G.qual & LR_SHIFTKEY && mval[0]>=NLAWIDTH){
+                                       duplicate_nlachannel_keys();
+                                       update_for_newframe_muted();
+                               }
+                               
+                               break;
+                               
+                       case EKEY:
+                               if (mval[0] >= NLAWIDTH) {
+                                       transform_nlachannel_keys ('e', 0);
+                                       update_for_newframe_muted();
+                               }
+                               break;
+                               
+                       case GKEY:
+                               if (mval[0]>=NLAWIDTH) {
+                                       if (G.qual & LR_CTRLKEY) {
+                                               transform_markers('g', 0);
+                                       }
+                                       else {
+                                               transform_nlachannel_keys ('g', 0);
+                                               update_for_newframe_muted();
+                                       }
+                               }
+                               break;
+                       
+                       case MKEY:
+                               /* marker operations */
+                               if (G.qual == 0)
+                                       add_marker(CFRA);
+                               else if (G.qual == LR_CTRLKEY)
+                                       rename_marker();
+                               else 
+                                       break;
+                               allqueue(REDRAWMARKER, 0);
+                               break;                          
+                       
+                       case NKEY:
+                               if(G.qual==0) {
+                                       toggle_blockhandler(curarea, NLA_HANDLER_PROPERTIES, UI_PNL_TO_MOUSE);
+                                       scrarea_queue_winredraw(curarea);
+                               }
+                               else if (G.qual & LR_SHIFTKEY) {
+                                       add_empty_nlablock();
+                               }
+                               break;
+                       case LKEY:
+                               relink_active_strip();
+                               break;
+                               
+                       case PKEY:
+                               if (G.qual & LR_CTRLKEY) /* set preview range */
+                                       anim_previewrange_set();
+                               else if (G.qual & LR_ALTKEY) /* clear preview range */
+                                       anim_previewrange_clear();
+                               allqueue(REDRAWMARKER, 0);
+                               break;
+                               
+                       case SKEY:
+                               if (G.qual==LR_ALTKEY) {
+                                       val= pupmenu("Action Strip Scale%t|Reset Strip Scale%x1|Remap Action Start/End%x2|Apply Scale%x3");
+                                       if (val > 0)
+                                               reset_action_strips(val);
+                               }
+                               else if (G.qual & LR_SHIFTKEY) {
+                                       if (snla->flag & SNLA_DRAWTIME)
+                                               val= pupmenu("Snap To%t|Nearest Second%x3|Current Time%x2");
+                                       else
+                                               val= pupmenu("Snap To%t|Nearest Frame%x1|Current Frame%x2");
+                                       if (ELEM3(val, 1, 2, 3))
+                                               snap_action_strips(val);
+                               }
+                               else {
+                                       if (mval[0]>=NLAWIDTH)
+                                               transform_nlachannel_keys ('s', 0);
+                                       update_for_newframe_muted();
+                               }
+                               break;
+                               
+                       case TKEY:
+                               if (G.qual & LR_CTRLKEY) {
+                                       val= pupmenu("Time value%t|Frames %x1|Seconds%x2");
+                                       
+                                       if (val > 0) {
+                                               if (val == 2) snla->flag |= SNLA_DRAWTIME;
+                                               else snla->flag &= ~SNLA_DRAWTIME;
+                                               
+                                               doredraw= 1;
+                                       }
+                               }                               
+                               break;
+                               
+                       case DELKEY:
+                       case XKEY:
+                               if (mval[0]>=NLAWIDTH) {
+                                       if (okee("Erase selected?")) {
+                                               delete_nlachannel_keys();
+                                               update_for_newframe_muted();
+                                               
+                                               remove_marker();
+                                               
+                                               allqueue(REDRAWMARKER, 0);
+                                       }
+                               }
+                               break;
                                
                                
-                               if (conchan->flag & CONSTRAINT_CHANNEL_SELECT){
-                                       if (conchan->ipo)
-                                               conchan->ipo->id.us--;
-                                       BLI_freelinkN(&base->object->constraintChannels, conchan);
+                               /* LEFTMOUSE and RIGHTMOUSE event codes can be swapped above,
+                               * based on user preference USER_LMOUSESELECT
+                               */
+                       case LEFTMOUSE:
+                               if(view2dmove(LEFTMOUSE))
+                                       break; // only checks for sliders
+                               else if (mval[0]>=snla->v2d.mask.xmin) {
+                                       do {
+                                               getmouseco_areawin(mval);
+                                               
+                                               areamouseco_to_ipoco(G.v2d, mval, &dx, &dy);
+                                               
+                                               cfra= (int)(dx+0.5f);
+                                               if(cfra< 1) cfra= 1;
+                                               
+                                               if( cfra!=CFRA ) {
+                                                       CFRA= cfra;
+                                                       update_for_newframe();
+                                                       force_draw_all(0);
+                                               }
+                                               else PIL_sleep_ms(30);
+                                               
+                                       } while(get_mbut() & mousebut);
+                                       break;
+                               }
+                                       /* else pass on! */
+                               case RIGHTMOUSE:
+                                       if (mval[0]>=snla->v2d.mask.xmin) {
+                                               if(G.qual & LR_SHIFTKEY)
+                                                       mouse_nla(SELECT_INVERT);
+                                               else
+                                                       mouse_nla(SELECT_REPLACE);
+                                       }
+                                       else
+                                               mouse_nlachannels(mval);
+                                       break;
+                                       
+                               case PADPLUSKEY:
+                                       view2d_zoom(G.v2d, 0.1154, sa->winx, sa->winy);
+                                       test_view2d(G.v2d, sa->winx, sa->winy);
+                                       view2d_do_locks(curarea, V2D_LOCK_COPY);
+                                       doredraw= 1;
+                                       break;
+                               case PADMINUS:
+                                       view2d_zoom(G.v2d, -0.15, sa->winx, sa->winy);
+                                       test_view2d(G.v2d, sa->winx, sa->winy);
+                                       view2d_do_locks(curarea, V2D_LOCK_COPY);
+                                       doredraw= 1;
+                                       break;
+                               case MIDDLEMOUSE:
+                               case WHEELUPMOUSE:
+                               case WHEELDOWNMOUSE:
+                                       view2dmove(event);      /* in drawipo.c */
+                                       break;
+               }
+       }
+       
+       if(doredraw) scrarea_queue_winredraw(curarea);
+}
+
+void bake_all_to_action(void)
+{
+       Object          *ob;
+       bAction         *newAction;
+       Ipo             *ipo;
+       ID              *id;
+       short           hold, add;
+       float           repeat;
+
+       /* burn object-level motion into a new action */
+       ob = get_object_from_active_strip();
+       if (ob) {
+               if (ob->flag&OB_ARMATURE) {
+                       //newAction = bake_obIPO_to_action(ob);
+                       newAction = NULL;
+                       if (newAction) {
+                               /* unlink the object's IPO */
+                               ipo=ob->ipo;
+                               if (ipo) {
+                                       id = &ipo->id;
+                                       if (id->us > 0)
+                                               id->us--;
+                                       ob->ipo = NULL;
                                }
                                }
+                               
+                               /* add the new Action to NLA as a strip */
+                               hold=1;
+                               add=1;
+                               repeat=1.0;
+                               printf("about to add nla block...\n");
+                               add_nla_block_by_name(newAction->id.name, ob, hold, add, repeat);
+                               BIF_undo_push("Add NLA strip");
                        }
                }
                        }
                }
-               BIF_undo_push("Delete NLA channels");
+       }
+}
 
 
+void copy_action_modifiers(void)
+{
+       bActionStrip *strip, *actstrip;
+       Object *ob= OBACT;
+       
+       if(ob==NULL)
+               return;
+       
+       /* active strip */
+       for (actstrip=ob->nlastrips.first; actstrip; actstrip=actstrip->next)
+               if(actstrip->flag & ACTSTRIP_ACTIVE)
+                       break;
+       if(actstrip==NULL)
+               return;
+       
+       /* copy to selected items */
+       for (strip=ob->nlastrips.first; strip; strip=strip->next){
+               if (strip->flag & ACTSTRIP_SELECT) {
+                       if(strip!=actstrip) {
+                               if (strip->modifiers.first)
+                                       BLI_freelistN(&strip->modifiers);
+                               if (actstrip->modifiers.first)
+                                       duplicatelist (&strip->modifiers, &actstrip->modifiers);
+                       }
+               }
        }
        }
+       
+       BIF_undo_push("Copy Action Modifiers");
+       allqueue(REDRAWNLA, 0);
+       DAG_scene_flush_update(G.scene, screen_view3d_layers(), 0);
 }
 }
+