svn merge -r 15392:15551 https://svn.blender.org/svnroot/bf-blender/trunk/blender
[blender.git] / source / blender / src / editnla.c
index 1684cbf6883f868268907bc99dbffebf802f0fe4..dbc0deecb2cae140def1e887f362347c3d67e03a 100644 (file)
@@ -62,6 +62,7 @@
 #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_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_editaction_types.h"
 #include "BSE_trans_types.h"
 #include "BSE_edit.h"
 #include "BSE_filesel.h"
@@ -185,26 +188,180 @@ void shift_nlastrips_down(void) {
 void synchronize_action_strips(void)
 {
        Base *base;
+       Object *ob;
        bActionStrip *strip;
        
        for (base=G.scene->base.first; base; base=base->next) {
-               for (strip = base->object->nlastrips.last; strip; strip=strip->prev) {
+               /* get object first */
+               ob= base->object;
+               
+               /* 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 mapping= (strip->end - strip->start)/(strip->actend - strip->actstart);
+                               if ((strip->actstart!=actstart) || (strip->actend!=actend)) {           
+                                       float offset = strip->scale * (actstart - strip->actstart);
+                                       float actlen = actend - actstart;
                                        
-                                       strip->start+= mapping*(actstart - strip->actstart);
-                                       strip->end+= mapping*(actend - strip->actend);
+                                       strip->start += offset;
+                                       strip->end = (strip->scale * strip->repeat * actlen) + strip->start;
                                        
                                        strip->actstart= actstart;
                                        strip->actend= actend;
                                }
                        }
                }
+               
+               /* 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;
+                               }
+                               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 */
+                                       
+                                       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 */
+                                       
+                                       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 ( 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 if (IN_RANGE(nr[0], strip->start, strip->end) && 
+                                               (IN_RANGE(nr[1], strip->start, strip->end)==0) )
+                               {
+                                       /* next strip intersects end of current */
+                                       
+                                       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));
+                       }
+               }
        }
        
 }
@@ -220,15 +377,41 @@ void reset_action_strips(int val)
                
                for (strip = base->object->nlastrips.last; strip; strip=strip->prev) {
                        if (strip->flag & ACTSTRIP_SELECT) {
-                               if(val==2) {
-                                       calc_action_range(strip->act, &strip->actstart, &strip->actend, 1);
-                               }
-                               else if(val==1) {
-                                       float mapping= (strip->actend - strip->actstart)/(strip->end - strip->start);
-                                       
-                                       strip->end= strip->start + mapping*(strip->end - strip->start);
+                               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;
+                                       case 2:
+                                       {
+                                               /* reset action-range */
+                                               calc_action_range(strip->act, &strip->actstart, &strip->actend, 1);
+                                       }
+                                               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;
                                }
-                               base->object->ctime= -1234567.0f;       // eveil! 
+                               base->object->ctime= -1234567.0f;       // evil! 
                                DAG_object_flush_update(G.scene, base->object, OB_RECALC_OB|OB_RECALC_DATA);
                        }
                }
@@ -245,9 +428,16 @@ void snap_action_strips(int snap_mode)
        bActionStrip *strip;
        
        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) {
@@ -269,11 +459,40 @@ void snap_action_strips(int snap_mode)
                                                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);
+                       
+                       /* 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);
 }
@@ -282,26 +501,47 @@ 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;
        
-       if(act) {
+       /* act is new active strip */
+       if (act) {
+               /* set active flag for this strip */
                act->flag |= ACTSTRIP_ACTIVE;
-       
-               if(ob->action!=act->act) {
-                       if(ob->action) ob->action->id.us--;
-                       if(act->act->id.lib) {
+               
+               /* 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);
-                       ob->ctime= -1234567.0f; // eveil! 
+                       
+                       /* 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);
                }
        }       
@@ -367,7 +607,7 @@ static void add_nla_block(short event)
                /* simple prevention of zero strips */
        if(strip->start>strip->end-2) 
                strip->end= strip->start+100;
-       strip->repeat = 1.0;
+       strip->repeat = strip->scale= 1.0f;
        
        strip->flag = ACTSTRIP_SELECT|ACTSTRIP_LOCK_ACTION;
        
@@ -377,6 +617,9 @@ static void add_nla_block(short event)
        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");
@@ -403,6 +646,7 @@ static void add_nla_block_by_name(char name[32], Object *ob, short hold, short a
        
        /* Initialize the new action block */
        strip = MEM_callocN(sizeof(bActionStrip), "bActionStrip");
+       strip->scale= 1.0f;
        
        deselect_nlachannel_keys(0);
        
@@ -431,9 +675,10 @@ static void add_nla_block_by_name(char name[32], Object *ob, short hold, short a
        
        act->id.us++;
        
+       if(ob->nlastrips.first == NULL)
+               ob->nlaflag |= OB_NLA_OVERRIDE;
+               
        BLI_addtail(&ob->nlastrips, strip);
-
-       BIF_undo_push("Add NLA strip");
 }
 
 static void add_nla_databrowse_callback(unsigned short val)
@@ -486,6 +731,7 @@ 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) 
@@ -493,12 +739,35 @@ void add_empty_nlablock(void)
                
        /* make new action */
        if ((ob->type == OB_ARMATURE) && (ob->flag & OB_POSEMODE))
-               act= add_empty_action(ID_AR);
+               act= add_empty_action("ObAction");
        else
-               act= add_empty_action(ID_OB);
+               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;
+       }
+       
+       BIF_undo_push("Add NLA strip");
 }
 
 /* Adds strip to to active Object */
@@ -617,8 +886,12 @@ static void mouse_nlachannels(short mval[2])
        
        if(actclick) /* de-activate all strips */
                set_active_strip(ob, NULL);
-       else if(strip) /* set action */
-               set_active_strip(ob, strip);
+       else if(strip) {
+               if(mval[0] >= (NLAWIDTH-16)) /* toggle strip muting */
+                       strip->flag ^= ACTSTRIP_MUTE;
+               else /* set action */
+                       set_active_strip(ob, strip);
+       }
 
        /* icon toggles beside strip */
        if (obclick && mval[0]<20) {
@@ -629,6 +902,10 @@ static void mouse_nlachannels(short mval[2])
                /* 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);
@@ -759,285 +1036,28 @@ static void recalc_all_ipos(void)
 
 void transform_nlachannel_keys(int mode, int dummy)
 {
-       Base *base;
-       TransVert *tv;
-       bActionChannel *chan;
-       bActionStrip *strip;
-       bConstraintChannel *conchan;
-       float   sval[2], cval[2], lastcval[2];
-       float   fac=0.0F;
-       float   deltax, startx;
-       int i;
-       int             loop=1;
-       int             tvtot=0;
-       int             invert=0, firsttime=1;
-       short   mvals[2], mvalc[2];
-       short   cancel=0;
-       char    str[256];
-
-       /* Ensure that partial selections result in beztriple selections */
-       for (base=G.scene->base.first; base; base=base->next){
-               /* Check object ipos */
-               i= fullselect_ipo_keys(base->object->ipo);
-               if(i) base->flag |= BA_HAS_RECALC_OB;
-               tvtot+=i;
-               
-               /* Check object constraint ipos */
-               for(conchan=base->object->constraintChannels.first; conchan; conchan=conchan->next)
-                       tvtot+=fullselect_ipo_keys(conchan->ipo);                       
-               
-               /* skip actions and nlastrips if object is collapsed */
-               if (base->object->nlaflag & OB_NLA_COLLAPSED)
-                       continue;
-               
-               /* Check action ipos */
-               if (base->object->action){
-                       /* exclude if strip is selected too */
-                       for (strip=base->object->nlastrips.first; strip; strip=strip->next){
-                               if (strip->flag & ACTSTRIP_SELECT)
-                                       if(strip->act==base->object->action)
-                                               break;
-                       }
-                       if(strip==NULL) {
-                               
-                               for (chan=base->object->action->chanbase.first; chan; chan=chan->next){
-                                       if (EDITABLE_ACHAN(chan)) {
-                                               i= fullselect_ipo_keys(chan->ipo);
-                                               if(i) base->flag |= BA_HAS_RECALC_OB|BA_HAS_RECALC_DATA;
-                                               tvtot+=i;
-                                       }
-                                       
-                                       /* Check action constraint ipos */
-                                       for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next) {
-                                               if (EDITABLE_CONCHAN(conchan))
-                                                       tvtot+=fullselect_ipo_keys(conchan->ipo);
-                                       }
-                               }
-                       }               
-               }
-
-               /* Check nlastrips */
-               for (strip=base->object->nlastrips.first; strip; strip=strip->next){
-                       if (strip->flag & ACTSTRIP_SELECT) {
-                               base->flag |= BA_HAS_RECALC_OB|BA_HAS_RECALC_DATA;
-                               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;
 
-               /* skip actions and nlastrips if object collapsed */
-               if (base->object->nlaflag & OB_NLA_COLLAPSED)
-                       continue;
-                       
-               /* Manipulate action ipos */
-               if (base->object->action){
-                       /* exclude if strip is selected too */
-                       for (strip=base->object->nlastrips.first; strip; strip=strip->next){
-                               if (strip->flag & ACTSTRIP_SELECT)
-                                       if(strip->act==base->object->action)
-                                               break;
-                       }
-                       if(strip==NULL) {
-                               
-                               for (chan=base->object->action->chanbase.first; chan; chan=chan->next){
-                                       if (EDITABLE_ACHAN(chan))
-                                               tvtot=add_trans_ipo_keys(chan->ipo, tv, tvtot);
-
-                                       /* Manipulate action constraint ipos */
-                                       for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next) {
-                                               if (EDITABLE_CONCHAN(conchan))
-                                                       tvtot=add_trans_ipo_keys(conchan->ipo, tv, tvtot);
-                                       }
-                               }
-                       }
+       switch (mode) {
+               case 'g':
+               {
+                       initTransform(TFM_TIME_TRANSLATE, context);
+                       Transform();
                }
-
-               /* 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;
-                               };
-                       }
-               }
-               
-               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(10);
-                       }
-                       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, "scaleX: %.3f", fac);
-                                       headerprint(str);
-                               }
-                               else if (mode=='g'){
-                                       sprintf(str, "deltaX: %.3f", fac);
-                                       headerprint(str);
-                               }
-                               
-                               if (G.snla->lock) {
-                                       for (base=G.scene->base.first; base; base=base->next){
-                                               if(base->flag & BA_HAS_RECALC_OB)
-                                                       base->object->recalc |= OB_RECALC_OB;
-                                               if(base->flag & BA_HAS_RECALC_DATA)
-                                                       base->object->recalc |= OB_RECALC_DATA;
-                                               
-                                               if(base->object->recalc) base->object->ctime= -1234567.0f;      // eveil! 
-                                       }
-                                       
-                                       DAG_scene_flush_update(G.scene, screen_view3d_layers());
-                                       
-                                       force_draw_all(0);
-                               }
-                               else {
-                                       force_draw(0);
-                               }
-                       }
+                       break;
+               case 'e':
+               {
+                       initTransform(TFM_TIME_EXTEND, context);
+                       Transform();
                }
-               
-               lastcval[0]= cval[0];
-               lastcval[1]= cval[1];
-               firsttime= 0;
+                       break;
        }
-       
-       synchronize_action_strips();
-       
-       /* cleanup */
-       for (base=G.scene->base.first; base; base=base->next)
-               base->flag &= ~(BA_HAS_RECALC_OB|BA_HAS_RECALC_DATA);
-       
-       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)
@@ -1084,10 +1104,10 @@ void delete_nlachannel_keys(void)
                }
        }
        
+       recalc_all_ipos();      // bad
        synchronize_action_strips();
        
        BIF_undo_push("Delete NLA keys");
-       recalc_all_ipos();      // bad
        allspace(REMAKEIPO,0);
        allqueue (REDRAWVIEW3D, 0);
        allqueue(REDRAWNLA, 0);
@@ -1245,11 +1265,7 @@ void borderselect_nla(void)
                        }
                }       
                BIF_undo_push("Border select NLA");
-               allqueue(REDRAWTIME, 0);
-               allqueue(REDRAWIPO, 0);
-               allqueue(REDRAWACTION, 0);
-               allqueue(REDRAWNLA, 0);
-               allqueue(REDRAWSOUND, 0);
+               allqueue(REDRAWMARKER, 0);
        }
 }
 
@@ -1270,7 +1286,7 @@ static void mouse_nla(int selectmode)
        
        /* Try object ipo or ob-constraint ipo selection */
        base= get_nearest_nlachannel_ob_key(&selx, &sel);
-       marker=find_nearest_marker(1);
+       marker=find_nearest_marker(SCE_MARKERS, 1);
        if (base) {
                isdone= 1;
                
@@ -1304,11 +1320,7 @@ static void mouse_nla(int selectmode)
                
                std_rmouse_transform(transform_markers);
                
-               allqueue(REDRAWTIME, 0);
-               allqueue(REDRAWIPO, 0);
-               allqueue(REDRAWACTION, 0);
-               allqueue(REDRAWNLA, 0);
-               allqueue(REDRAWSOUND, 0);
+               allqueue(REDRAWMARKER, 0);
        }
        else {
                /* Try action ipo selection */
@@ -1734,7 +1746,7 @@ void winqreadnlaspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
        if (!snla) return;
        
        if(val) {
-               if( uiDoBlocks(&curarea->uiblocks, event)!=UI_NOTHING ) event= 0;
+               if( uiDoBlocks(&curarea->uiblocks, event, 1)!=UI_NOTHING ) event= 0;
                
                /* swap mouse buttons based on user preference */
                if (U.flag & USER_LMOUSESELECT) {
@@ -1767,11 +1779,7 @@ void winqreadnlaspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
                                        shift_nlastrips_up();
                                else {
                                        nextprev_marker(1);
-                                       allqueue(REDRAWTIME, 0);
-                                       allqueue(REDRAWIPO, 0);
-                                       allqueue(REDRAWACTION, 0);
-                                       allqueue(REDRAWNLA, 0);
-                                       allqueue(REDRAWSOUND, 0);
+                                       allqueue(REDRAWMARKER, 0);
                                }                               
                                break;
                                
@@ -1784,11 +1792,7 @@ void winqreadnlaspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
                                        shift_nlastrips_down();
                                else {
                                        nextprev_marker(-1);
-                                       allqueue(REDRAWTIME, 0);
-                                       allqueue(REDRAWIPO, 0);
-                                       allqueue(REDRAWACTION, 0);
-                                       allqueue(REDRAWNLA, 0);
-                                       allqueue(REDRAWSOUND, 0);
+                                       allqueue(REDRAWMARKER, 0);
                                }
                                break;
                                
@@ -1800,11 +1804,7 @@ void winqreadnlaspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
                                }
                                else if (G.qual & LR_CTRLKEY) {
                                        deselect_markers(1, 0);
-                                       allqueue(REDRAWTIME, 0);
-                                       allqueue(REDRAWIPO, 0);
-                                       allqueue(REDRAWACTION, 0);
-                                       allqueue(REDRAWNLA, 0);
-                                       allqueue(REDRAWSOUND, 0);
+                                       allqueue(REDRAWMARKER, 0);
                                }
                                else{
                                        if (mval[0]>=NLAWIDTH)
@@ -1853,6 +1853,13 @@ void winqreadnlaspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
                                
                                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) {
@@ -1873,11 +1880,7 @@ void winqreadnlaspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
                                        rename_marker();
                                else 
                                        break;
-                               allqueue(REDRAWTIME, 0);
-                               allqueue(REDRAWIPO, 0);
-                               allqueue(REDRAWACTION, 0);
-                               allqueue(REDRAWNLA, 0);
-                               allqueue(REDRAWSOUND, 0);
+                               allqueue(REDRAWMARKER, 0);
                                break;                          
                        
                        case NKEY:
@@ -1893,17 +1896,26 @@ void winqreadnlaspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
                                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|Clear Strip Scale%x1|Remap Start/End%x2");
-                                       if(val==1)
-                                               reset_action_strips(1);
-                                       else if(val==2)
-                                               reset_action_strips(2);
+                               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) {
-                                       val= pupmenu("Snap To%t|Nearest Frame%x1|Current Frame%x2");
-                                       if (val==1 || val==2)
+                               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 {
@@ -1913,23 +1925,30 @@ void winqreadnlaspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
                                }
                                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) {
-                                       val= pupmenu("Erase selected%t|Strips and/or Keys%x1|Markers%x2");
-                                       if (val==1) {
+                                       if (okee("Erase selected?")) {
                                                delete_nlachannel_keys();
                                                update_for_newframe_muted();
-                                       }
-                                       else if (val==2) {
+                                               
                                                remove_marker();
                                                
-                                               allqueue(REDRAWTIME, 0);
-                                               allqueue(REDRAWIPO, 0);
-                                               allqueue(REDRAWACTION, 0);
-                                               allqueue(REDRAWNLA, 0);
-                                               allqueue(REDRAWSOUND, 0);
-                                       }                               
+                                               allqueue(REDRAWMARKER, 0);
+                                       }
                                }
                                break;
                                
@@ -1945,7 +1964,7 @@ void winqreadnlaspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
                                                
                                                areamouseco_to_ipoco(G.v2d, mval, &dx, &dy);
                                                
-                                               cfra= (int)dx;
+                                               cfra= (int)(dx+0.5f);
                                                if(cfra< 1) cfra= 1;
                                                
                                                if( cfra!=CFRA ) {
@@ -2006,7 +2025,8 @@ void bake_all_to_action(void)
        ob = get_object_from_active_strip();
        if (ob) {
                if (ob->flag&OB_ARMATURE) {
-                       newAction = bake_obIPO_to_action(ob);
+                       //newAction = bake_obIPO_to_action(ob);
+                       newAction = NULL;
                        if (newAction) {
                                /* unlink the object's IPO */
                                ipo=ob->ipo;
@@ -2023,6 +2043,7 @@ void bake_all_to_action(void)
                                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");
                        }
                }
        }
@@ -2057,6 +2078,6 @@ void copy_action_modifiers(void)
        
        BIF_undo_push("Copy Action Modifiers");
        allqueue(REDRAWNLA, 0);
-       DAG_scene_flush_update(G.scene, screen_view3d_layers());
+       DAG_scene_flush_update(G.scene, screen_view3d_layers(), 0);
 }