== Action and NLA Editor Transform ==
authorJoshua Leung <aligorith@gmail.com>
Mon, 24 Sep 2007 11:29:25 +0000 (11:29 +0000)
committerJoshua Leung <aligorith@gmail.com>
Mon, 24 Sep 2007 11:29:25 +0000 (11:29 +0000)
I've refactored the Action and NLA Editor Transform tools to use the Transform System instead of setting up their own transform loops. This should have happened ages ago, but no-one got around to doing so.

* There are still a few bugs left to iron out of a few features, but on the whole it should work as well as it used to. These are: the values which get displayed when working with NLA-scaled actions may not all be correct yet; and the Time-Slide tool in the Action Editor is currently kindof broken.

* One of the main benefits of this work, is that it is now possible to use Numeric Input during Transforms.

* Also, a bug that meant that it was not possible to negatively scale keyframes in the Action Editor has been resolved.

source/blender/include/BIF_transform.h
source/blender/include/transform.h
source/blender/src/editaction.c
source/blender/src/editnla.c
source/blender/src/header_action.c
source/blender/src/transform.c
source/blender/src/transform_conversions.c
source/blender/src/transform_generics.c

index 9b27794252803e9ce0ee99416c41f23bdafad61b..eeb465135de6ef62a9ec99b9be830f6cf2283f97 100644 (file)
@@ -55,6 +55,9 @@
 #define TFM_BONE_ENVELOPE      16
 #define TFM_CURVE_SHRINKFATTEN         17
 #define TFM_BONE_ROLL          18
+#define TFM_TIME_TRANSLATE     19      
+#define TFM_TIME_SLIDE         20
+#define        TFM_TIME_SCALE          21
 
 /* TRANSFORM CONTEXTS */
 #define CTX_NONE                       0
index a06356e6531a7262913d2706a851b74009c7f294..b81ec202210a7294d7389b79c4dd919b7ca17e77 100644 (file)
@@ -339,6 +339,15 @@ int BoneEnvelope(TransInfo *t, short mval[2]);
 void initBoneRoll(TransInfo *t);
 int BoneRoll(TransInfo *t, short mval[2]);
 
+void initTimeTranslate(TransInfo *t);
+int TimeTranslate(TransInfo *t, short mval[2]);
+
+void initTimeSlide(TransInfo *t);
+int TimeSlide(TransInfo *t, short mval[2]);
+
+void initTimeScale(TransInfo *t);
+int TimeScale(TransInfo *t, short mval[2]);
+
 /*********************** transform_conversions.c ********** */
 struct ListBase;
 void flushTransUVs(TransInfo *t);
index 76fc21b13e6fa527b0ea9da3a18b548f3dc1c4e5..23e2a5aab6bca580f2a5474031e6f106cb5167e6 100644 (file)
@@ -80,6 +80,7 @@
 #include "BIF_screen.h"
 #include "BIF_space.h"
 #include "BIF_toolbox.h"
+#include "BIF_transform.h"
 
 #include "BSE_edit.h"
 #include "BSE_drawipo.h"
@@ -186,19 +187,6 @@ static void remake_meshaction_ipos (Ipo *ipo)
        }
 }
 
-static void meshkey_do_redraw (Key *key)
-{
-       if(key->ipo)
-               remake_meshaction_ipos(key->ipo);
-
-       DAG_object_flush_update(G.scene, OBACT, OB_RECALC_DATA);
-       
-       allspace(REMAKEIPO, 0);
-       allqueue(REDRAWACTION, 0);
-       allqueue(REDRAWIPO, 0);
-       allqueue(REDRAWNLA, 0);
-
-}
 
 /* **************************************************** */
 /* FILTER->EDIT STRUCTURES */
@@ -737,361 +725,9 @@ void *get_action_context (short *datatype)
 /* **************************************************** */
 /* TRANSFORM TOOLS */
 
-/* initialise the transform data - create transverts */
-static TransVert *transform_action_init (int *tvtot, float *minx, float *maxx)
-{
-       ListBase act_data = {NULL, NULL};
-       bActListElem *ale;
-       TransVert *tv;
-       void *data;
-       short datatype;
-       int filter;
-       int count= 0;
-       float min= 0, max= 0;
-       int i;
-       
-       /* initialise the values being passed by reference */
-       *tvtot = *minx = *maxx = 0;
-       
-       /* determine what type of data we are operating on */
-       data = get_action_context(&datatype);
-       if (data == NULL) return NULL;
-       
-       /* filter data */
-       filter= (ACTFILTER_VISIBLE | ACTFILTER_FOREDIT | ACTFILTER_IPOKEYS);
-       actdata_filter(&act_data, filter, data, datatype);
-       
-       /* loop 1: fully select ipo-keys and count how many BezTriples are selected */
-       for (ale= act_data.first; ale; ale= ale->next)
-               count += fullselect_ipo_keys(ale->key_data);
-       
-       /* stop if trying to build list if nothing selected */
-       if (count == 0) {
-               /* cleanup temp list */
-               BLI_freelistN(&act_data);
-               return NULL;
-       }
-               
-       /* Build the transvert structure */
-       tv = MEM_callocN (sizeof(TransVert) * count, "transVert");
-       
-       /* loop 2: build transvert structure */
-       for (ale= act_data.first; ale; ale= ale->next)
-               *tvtot = add_trans_ipo_keys(ale->key_data, tv, *tvtot);
-               
-       /* min max, only every other three */
-       min= max= tv[1].loc[0];
-       for (i=1; i<count; i+=3) {
-               if(min>tv[i].loc[0]) min= tv[i].loc[0];
-               if(max<tv[i].loc[0]) max= tv[i].loc[0];
-       }
-       *minx= min;
-       *maxx= max;
-       
-       /* cleanup temp list */
-       BLI_freelistN(&act_data);
-       
-       /* return created transverts */
-       return tv;
-} 
-
-/* main transform loop for action editor 
- * NOTE: yes, this is a very long function that really should be converted to
- * using the transform system proper 
- */
-static short transform_action_loop (TransVert *tv, int tvtot, char mode, short context, float minx, float maxx)
-{
-       Object *ob= OBACT;
-       float deltax, startx;
-       float cenf[2];
-       float sval[2], cval[2], lastcval[2]={0,0};
-       float fac=0.0f, secf= ((float)G.scene->r.frs_sec);
-       int     loop=1, invert=0;
-       int     i;
-       short cancel=0, firsttime=1;
-       short mvals[2], mvalc[2], cent[2];
-       char str[256];
-       
-       /* Do the event loop */
-       cent[0] = curarea->winx + (G.saction->v2d.hor.xmax)/2;
-       cent[1] = curarea->winy + (G.saction->v2d.hor.ymax)/2;
-       areamouseco_to_ipoco(G.v2d, cent, &cenf[0], &cenf[1]);
-
-       getmouseco_areawin (mvals);
-       areamouseco_to_ipoco(G.v2d, mvals, &sval[0], &sval[1]);
-
-       if (NLA_ACTION_SCALED)
-               sval[0]= get_action_frame(OBACT, sval[0]);
-       
-       /* used for drawing */
-       if (mode=='t') {
-               G.saction->flag |= SACTION_MOVING;
-               G.saction->timeslide= sval[0];
-       }
-       
-       startx=sval[0];
-       while (loop) {
-               if (mode=='t' && minx==maxx)
-                       break;
-               
-               /* 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++) {
-                               tv[i].loc[0]=tv[i].oldloc[0];
-                               tv[i].loc[1]=tv[i].oldloc[1];
-                       }
-               } 
-               else {
-                       getmouseco_areawin (mvalc);
-                       areamouseco_to_ipoco(G.v2d, mvalc, &cval[0], &cval[1]);
-                       
-                       if (NLA_ACTION_SCALED)
-                               cval[0]= get_action_frame(OBACT, cval[0]);
-
-                       if (mode=='t')
-                               G.saction->timeslide= cval[0];
-                       
-                       if (!firsttime && lastcval[0]==cval[0] && lastcval[1]==cval[1]) {
-                               PIL_sleep_ms(1);
-                       } 
-                       else {
-                               short autosnap= 0;
-                               
-                               /* determine mode of keyframe snapping/autosnap */
-                               if (mode != 't') {
-                                       switch (G.saction->autosnap) {
-                                       case SACTSNAP_OFF:
-                                               if (G.qual == LR_CTRLKEY) 
-                                                       autosnap= SACTSNAP_STEP;
-                                               else if (G.qual == LR_SHIFTKEY)
-                                                       autosnap= SACTSNAP_FRAME;
-                                               else
-                                                       autosnap= SACTSNAP_OFF;
-                                               break;
-                                       case SACTSNAP_STEP:
-                                               autosnap= (G.qual==LR_CTRLKEY)? SACTSNAP_OFF: SACTSNAP_STEP;
-                                               break;
-                                       case SACTSNAP_FRAME:
-                                               autosnap= (G.qual==LR_SHIFTKEY)? SACTSNAP_OFF: SACTSNAP_FRAME;
-                                               break;
-                                       }
-                               }
-                               
-                               for (i=0; i<tvtot; i++) {
-                                       tv[i].loc[0]=tv[i].oldloc[0];
-
-                                       switch (mode) {
-                                       case 't':
-                                               if( sval[0] > minx && sval[0] < maxx) {
-                                                       float timefac, cvalc= CLAMPIS(cval[0], minx, maxx);
-                                                       
-                                                       /* left half */
-                                                       if(tv[i].oldloc[0] < sval[0]) {
-                                                               timefac= ( sval[0] - tv[i].oldloc[0])/(sval[0] - minx);
-                                                               tv[i].loc[0]= cvalc - timefac*( cvalc - minx);
-                                                       }
-                                                       else {
-                                                               timefac= (tv[i].oldloc[0] - sval[0])/(maxx - sval[0]);
-                                                               tv[i].loc[0]= cvalc + timefac*(maxx- cvalc);
-                                                       }
-                                               }
-                                               break;
-                                       case 'g':
-                                               if (NLA_ACTION_SCALED && context==ACTCONT_ACTION) {
-                                                       deltax = get_action_frame_inv(OBACT, cval[0]);
-                                                       deltax -= get_action_frame_inv(OBACT, sval[0]);
-                                                       
-                                                       if (autosnap == SACTSNAP_STEP) {
-                                                               if (G.saction->flag & SACTION_DRAWTIME) 
-                                                                       deltax= (float)( floor((deltax/secf) + 0.5f) * secf );
-                                                               else
-                                                                       deltax= (float)( floor(deltax + 0.5f) );
-                                                       }
-                                                       
-                                                       fac = get_action_frame_inv(OBACT, tv[i].loc[0]);
-                                                       fac += deltax;
-                                                       tv[i].loc[0] = get_action_frame(OBACT, fac);
-                                               }
-                                               else {
-                                                       deltax = cval[0] - sval[0];
-                                                       fac= deltax;
-                                                       
-                                                       if (autosnap == SACTSNAP_STEP) {
-                                                               if (G.saction->flag & SACTION_DRAWTIME)
-                                                                       fac= (float)( floor((deltax/secf) + 0.5f) * secf );
-                                                               else
-                                                                       fac= (float)( floor(fac + 0.5f) );
-                                                       }
-                                                       
-                                                       tv[i].loc[0]+=fac;
-                                               }
-                                               break;
-                                       case 's':
-                                               startx=mvals[0]-(ACTWIDTH/2+(curarea->winrct.xmax-curarea->winrct.xmin)/2);
-                                               deltax=mvalc[0]-(ACTWIDTH/2+(curarea->winrct.xmax-curarea->winrct.xmin)/2);
-                                               fac= fabs(deltax/startx);
-                                               
-                                               if (autosnap == SACTSNAP_STEP) {
-                                                       if (G.saction->flag & SACTION_DRAWTIME)
-                                                               fac= (float)( floor(fac/secf + 0.5f) * secf );
-                                                       else
-                                                               fac= (float)( floor(fac + 0.5f) );
-                                               }
-                                               
-                                               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 (NLA_ACTION_SCALED && context==ACTCONT_ACTION)
-                                                       startx= get_action_frame(OBACT, startx);
-                                                       
-                                               tv[i].loc[0]-= startx;
-                                               tv[i].loc[0]*=fac;
-                                               tv[i].loc[0]+= startx;
-                                               
-                                               break;
-                                       }
-                                       
-                                       /* snap key to nearest frame? */
-                                       if (autosnap == SACTSNAP_FRAME) {
-                                               float snapval;
-                                               
-                                               /* convert frame to nla-action time (if needed) */
-                                               if (NLA_ACTION_SCALED && context==ACTCONT_ACTION) 
-                                                       snapval= get_action_frame_inv(OBACT, tv[i].loc[0]);
-                                               else
-                                                       snapval= tv[i].loc[0];
-                                               
-                                               /* snap to nearest frame */
-                                               if (G.saction->flag & SACTION_DRAWTIME)
-                                                       snapval= (float)( floor((snapval/secf) + 0.5f) * secf );
-                                               else
-                                                       snapval= (float)( floor(snapval+0.5f) );
-                                                       
-                                               /* convert frame out of nla-action time */
-                                               if (NLA_ACTION_SCALED && context==ACTCONT_ACTION)
-                                                       tv[i].loc[0]= get_action_frame(OBACT, snapval);
-                                               else
-                                                       tv[i].loc[0]= snapval;
-                                       }
-                               }
-       
-                               if (mode=='s') {
-                                       sprintf(str, "scaleX: %.3f", fac);
-                                       headerprint(str);
-                               }
-                               else if (mode=='g') {
-                                       if (NLA_ACTION_SCALED && context==ACTCONT_ACTION) {
-                                               /* recalculate the delta based on 'visual' times */
-                                               fac = get_action_frame_inv(OBACT, cval[0]);
-                                               fac -= get_action_frame_inv(OBACT, sval[0]);
-                                       }
-                                       
-                                       if (autosnap == SACTSNAP_STEP) {
-                                               if (G.saction->flag & SACTION_DRAWTIME)
-                                                       fac= floor(fac/secf + 0.5f);
-                                               else
-                                                       fac= floor(fac + 0.5f);
-                                       }
-                                       else if (autosnap == SACTSNAP_FRAME) {
-                                               if (G.saction->flag & SACTION_DRAWTIME)
-                                                       fac= fac / secf;
-                                       }
-                                       
-                                       sprintf(str, "deltaX: %.3f", fac);
-                                       headerprint(str);
-                               }
-                               else if (mode=='t') {
-                                       fac= 2.0*(cval[0]-sval[0])/(maxx-minx);
-                                       CLAMP(fac, -1.0f, 1.0f);
-                                       
-                                       sprintf(str, "TimeSlide: %.3f", fac);
-                                       headerprint(str);
-                               }
-               
-                               if (G.saction->lock) {
-                                       if (context == ACTCONT_ACTION) {
-                                               if(ob) {
-                                                       ob->ctime= -1234567.0f;
-                                                       if(ob->pose || ob_get_key(ob))
-                                                               DAG_object_flush_update(G.scene, ob, OB_RECALC);
-                                                       else
-                                                               DAG_object_flush_update(G.scene, ob, OB_RECALC_OB);
-                                               }
-                                               force_draw_plus(SPACE_VIEW3D, 0);
-                                       }
-                                       else if (context == ACTCONT_SHAPEKEY) {
-                                               DAG_object_flush_update(G.scene, OBACT, OB_RECALC_OB|OB_RECALC_DATA);
-                               allqueue (REDRAWVIEW3D, 0);
-                               allqueue (REDRAWACTION, 0);
-                               allqueue (REDRAWIPO, 0);
-                               allqueue(REDRAWNLA, 0);
-                                               allqueue(REDRAWTIME, 0);
-                               force_draw_all(0);
-                                       }
-                               }
-                               else {
-                                       force_draw(0);
-                               }
-                       }
-               }
-               
-               lastcval[0]= cval[0];
-               lastcval[1]= cval[1];
-               firsttime= 0;
-       }
-       
-       return cancel;
-}
-
 /* main call to start transforming keyframes */
-/*     NOTE: someday, this should be integrated with the transform system
- *             instead of relying on our own methods
- */
 void transform_action_keys (int mode, int dummy)
 {
-       Object *ob= OBACT;
-       TransVert *tv;
-       int tvtot= 0;
-       short cancel;
-       float minx, maxx;
-       
        void *data;
        short datatype;
        
@@ -1099,44 +735,26 @@ void transform_action_keys (int mode, int dummy)
        data = get_action_context(&datatype);
        if (data == NULL) return;
        
-       /* initialise transform */
-       tv= transform_action_init(&tvtot, &minx, &maxx);
-       if (tv == NULL) return;
-       
-       /* do transform loop */
-       cancel= transform_action_loop(tv, tvtot, mode, datatype, minx, maxx); 
-       
-       /* cleanup */
-       if (datatype == ACTCONT_ACTION) {
-               /* Update the curve */
-               /* Depending on the lock status, draw necessary views */
-               if(ob) {
-                       ob->ctime= -1234567.0f;
-
-                       if(ob->pose || ob_get_key(ob))
-                               DAG_object_flush_update(G.scene, ob, OB_RECALC);
-                       else
-                               DAG_object_flush_update(G.scene, ob, OB_RECALC_OB);
+       switch (mode) {
+               case 'g':
+               {
+                       initTransform(TFM_TIME_TRANSLATE, CTX_NONE);
+                       Transform();
                }
-               
-               remake_action_ipos((bAction *)data);
-
-               G.saction->flag &= ~SACTION_MOVING;
-               
-               if (cancel==0) BIF_undo_push("Transform Action"); // does it have to be here?
-               allqueue(REDRAWVIEW3D, 0);
-               allqueue(REDRAWACTION, 0);
-               allqueue(REDRAWNLA, 0);
-               allqueue(REDRAWIPO, 0);
-               allqueue(REDRAWTIME, 0);
-       }
-       else if (datatype == ACTCONT_SHAPEKEY) {
-               /* fix up the Ipocurves and redraw stuff */
-           meshkey_do_redraw((Key *)data);
-               if (cancel==0) BIF_undo_push("Transform Action");
+                       break;
+               case 's':
+               {
+                       initTransform(TFM_TIME_SCALE, CTX_NONE);
+                       Transform();
+               }
+                       break;
+               case 't':
+               {
+                       initTransform(TFM_TIME_SLIDE, CTX_NONE);
+                       Transform();
+               }
+                       break;
        }
-       
-       MEM_freeN(tv);
 }
 
 /* ----------------------------------------- */
index 9115665afa0420b5084fe838db355401f61f56f6..8c506b2c9251d5638111a387e8602900dc98e8eb 100644 (file)
@@ -73,6 +73,7 @@
 #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"
@@ -975,291 +976,20 @@ 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]= {0.0f, 0.0f};
-       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 */
-                                               if (EXPANDED_ACHAN(chan) && FILTER_CON_ACHAN(chan)) {
-                                                       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);
-
-               /* 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;
-                       }
-                       
-                       /* can include - no selected strip is action */
-                       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 */
-                                               if (EXPANDED_ACHAN(chan) && FILTER_CON_ACHAN(chan)) {
-                                                       for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next) {
-                                                               if (EDITABLE_CONCHAN(conchan))
-                                                                       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;
-                               };
-                       }
-               }
-               
-               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;
-                       }
+       switch (mode) {
+               case 'g':
+               {
+                       initTransform(TFM_TIME_TRANSLATE, CTX_NONE);
+                       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 's':
+               {
+                       initTransform(TFM_TIME_SCALE, CTX_NONE);
+                       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)
index d8afe0fd1f17e262402d4dbd16c9db26c214b018..71aac0e81bbd7a7180a4a45a4421709aa20d338e 100644 (file)
@@ -597,10 +597,10 @@ static void do_action_keymenu_transformmenu(void *arg, int event)
                        transform_action_keys('g', 0);
                        break;
                case ACTMENU_KEY_TRANSFORM_SCALE:
-                       transform_action_keys ('s', 0);
+                       transform_action_keys('s', 0);
                        break;
                case ACTMENU_KEY_TRANSFORM_SLIDE:
-                       transform_action_keys ('t', 0);
+                       transform_action_keys('t', 0);
                        break;
        }
 
index e8512d08d04027bc2adb09428b8082a66e8cad10..3189e959ede8ab4a569d37058e5841a7ab875abf 100644 (file)
@@ -48,6 +48,7 @@
 #include "MEM_guardedalloc.h"
 
 #include "DNA_armature_types.h"
+#include "DNA_action_types.h"  /* for some special action-editor settings */
 #include "DNA_ipo_types.h"             /* some silly ipo flag  */
 #include "DNA_listBase.h"
 #include "DNA_meshdata_types.h"
 #include "BIF_editmesh.h"
 #include "BIF_editsima.h"
 #include "BIF_drawimage.h"             /* uvco_to_areaco_noclip */
+#include "BIF_editaction.h" 
 
+#include "BKE_action.h" /* get_action_frame */
 #include "BKE_global.h"
 #include "BKE_utildefines.h"
 #include "BKE_bad_level_calls.h"/* popmenu and error   */
 
+#include "BSE_drawipo.h"
+#include "BSE_editnla_types.h" /* for NLAWIDTH */
 #include "BSE_view.h"
 
 #include "BLI_arithb.h"
@@ -350,7 +355,7 @@ void convertDisplayNumToVec(float *num, float *vec)
 
 static void viewRedrawForce(TransInfo *t)
 {
-       if(t->spacetype==SPACE_VIEW3D)
+       if(ELEM4(t->spacetype, SPACE_VIEW3D, SPACE_ACTION, SPACE_NLA, SPACE_IPO))
                force_draw(0);
        else if(t->spacetype==SPACE_IMAGE) {
                if(G.sima->lock) force_draw_plus(SPACE_VIEW3D, 0);
@@ -368,6 +373,14 @@ static void viewRedrawPost(TransInfo *t)
                allqueue(REDRAWIMAGE, 0);
                allqueue(REDRAWVIEW3D, 0);
        }
+       else if(ELEM3(t->spacetype, SPACE_ACTION, SPACE_NLA, SPACE_IPO)) {
+               allqueue(REDRAWVIEW3D, 0);
+               allqueue(REDRAWACTION, 0);
+               allqueue(REDRAWNLA, 0);
+               allqueue(REDRAWIPO, 0);
+               allqueue(REDRAWTIME, 0);
+               allqueue(REDRAWBUTSOBJECT, 0);
+       }
 
        scrarea_queue_headredraw(curarea);
 }
@@ -492,6 +505,12 @@ static char *transform_to_undostr(TransInfo *t)
                        return "Bone Width";
                case TFM_BONE_ENVELOPE:
                        return "Bone Envelope";
+               case TFM_TIME_TRANSLATE:
+                       return "Translate Anim. Data";
+               case TFM_TIME_SCALE:
+                       return "Scale Anim. Data";
+               case TFM_TIME_SLIDE:
+                       return "Time Slide";
        }
        return "Transform";
 }
@@ -884,6 +903,15 @@ void initTransform(int mode, int context) {
        case TFM_BONE_ROLL:
                initBoneRoll(&Trans);
                break;
+       case TFM_TIME_TRANSLATE:
+               initTimeTranslate(&Trans);
+               break;
+       case TFM_TIME_SLIDE:
+               initTimeSlide(&Trans);
+               break;
+       case TFM_TIME_SCALE:
+               initTimeScale(&Trans);
+               break;
        }
 }
 
@@ -3191,6 +3219,477 @@ void Mirror(short mode)
        viewRedrawPost(&Trans);
 }
 
+/* ************************** ANIM EDITORS - TRANSFORM TOOLS *************************** */
+
+/* ---------------- Special Helpers for Various Settings ------------- */
+
+/* This function returns the snapping 'mode' for Animation Editors only 
+ * We cannot use the standard snapping due to NLA-strip scaling complexities.
+ */
+static short getAnimEdit_SnapMode(TransInfo *t)
+{
+       short autosnap= SACTSNAP_OFF;
+       
+       /* currently, some of these are only for the action editor */
+       if (t->spacetype == SPACE_ACTION && G.saction) {
+               switch (G.saction->autosnap) {
+               case SACTSNAP_OFF:
+                       if (G.qual == LR_CTRLKEY) 
+                               autosnap= SACTSNAP_STEP;
+                       else if (G.qual == LR_SHIFTKEY)
+                               autosnap= SACTSNAP_FRAME;
+                       else
+                               autosnap= SACTSNAP_OFF;
+                       break;
+               case SACTSNAP_STEP:
+                       autosnap= (G.qual==LR_CTRLKEY)? SACTSNAP_OFF: SACTSNAP_STEP;
+                       break;
+               case SACTSNAP_FRAME:
+                       autosnap= (G.qual==LR_SHIFTKEY)? SACTSNAP_OFF: SACTSNAP_FRAME;
+                       break;
+               }
+       }
+       else {
+               if (G.qual == LR_CTRLKEY) 
+                       autosnap= SACTSNAP_STEP;
+               else if (G.qual == LR_SHIFTKEY)
+                       autosnap= SACTSNAP_FRAME;
+               else
+                       autosnap= SACTSNAP_OFF;
+       }
+       
+       return autosnap;
+}
+
+/* This function is used for testing if an Animation Editor is displaying
+ * its data in frames or seconds (and the data needing to be edited as such).
+ * Returns 1 if in seconds, 0 if in frames 
+ */
+static short getAnimEdit_DrawTime(TransInfo *t)
+{
+       short drawtime;
+       
+       /* currently, some of these are only for the action editor */
+       if (t->spacetype == SPACE_ACTION && G.saction) {
+               if (G.saction->flag & SACTION_DRAWTIME) 
+                       drawtime = 1;
+               else
+                       drawtime = 0;
+       }
+       else {
+               drawtime = 0;
+       }
+       
+       return drawtime;
+}      
+
+
+/* This function is used by Animation Editor specific transform functions to do 
+ * the Snap Keyframe to Nearest Keyframe
+ */
+static void doAnimEdit_SnapFrame(TransInfo *t, TransData *td, Object *ob, short autosnap)
+{
+       /* snap key to nearest frame? */
+       if (autosnap == SACTSNAP_FRAME) {
+               short doTime= getAnimEdit_DrawTime(t);
+               float secf= ((float)G.scene->r.frs_sec);
+               float val;
+               
+               /* convert frame to nla-action time (if needed) */
+               if (ob) 
+                       val= get_action_frame_inv(ob, *(td->val));
+               else
+                       val= *(td->val);
+               
+               /* do the snapping to nearest frame/second */
+               if (doTime)
+                       val= (float)( floor((val/secf) + 0.5f) * secf );
+               else
+                       val= (float)( floor(val+0.5f) );
+                       
+               /* convert frame out of nla-action time */
+               if (ob)
+                       *(td->val)= get_action_frame(ob, val);
+               else
+                       *(td->val)= val;
+       }
+}
+
+/* ----------------- Translation ----------------------- */
+
+void initTimeTranslate(TransInfo *t) 
+{
+       t->mode = TFM_TIME_TRANSLATE;
+       t->transform = TimeTranslate;
+
+       /* num-input has max of (n-1) */
+       t->idx_max = 0;
+       t->num.flag = 0;
+       t->num.idx_max = t->idx_max;
+       
+       /* initialise snap like for everything else */
+       t->snap[0] = 0.0f; 
+       t->snap[1] = t->snap[2] = 1.0f;
+}
+
+static void headerTimeTranslate(TransInfo *t, char *str) 
+{
+       char tvec[60];
+       
+       /* if numeric input is active, use results from that, otherwise apply snapping to result */
+       if (hasNumInput(&t->num)) {
+               outputNumInput(&(t->num), tvec);
+       }
+       else {
+               short autosnap= getAnimEdit_SnapMode(t);
+               short doTime = getAnimEdit_DrawTime(t);
+               float secf= ((float)G.scene->r.frs_sec);
+               float val= t->fac;
+               
+               /* take into account scaling (for Action Editor only) */
+               if ((t->spacetype == SPACE_ACTION) && (NLA_ACTION_SCALED)) {
+                       float cval, sval[2];
+                       
+                       /* recalculate the delta based on 'visual' times */
+                       areamouseco_to_ipoco(G.v2d, t->imval, &sval[0], &sval[1]);
+                       cval= sval[0] + t->fac;
+                       
+                       val = get_action_frame_inv(OBACT, cval);
+                       val -= get_action_frame_inv(OBACT, sval[0]);
+               }       
+               
+               /* apply snapping + frame->seconds conversions */
+               if (autosnap == SACTSNAP_STEP) {
+                       if (doTime)
+                               val= floor(val/secf + 0.5f);
+                       else
+                               val= floor(val + 0.5f);
+               }
+               else {
+                       if (doTime)
+                               val= val / secf;
+               }
+               
+               sprintf(&tvec[0], "%.4f", val);
+       }
+               
+       sprintf(str, "DeltaX: %s", &tvec[0]);
+}
+
+static void applyTimeTranslate(TransInfo *t, float sval) 
+{
+       TransData *td = t->data;
+       int i;
+       
+       short doTime= getAnimEdit_DrawTime(t);
+       float secf= ((float)G.scene->r.frs_sec);
+       
+       short autosnap= getAnimEdit_SnapMode(t);
+       float cval= sval + t->fac;
+       
+       float deltax, val;
+       
+       /* it doesn't matter whether we apply to t->data or t->data2d, but t->data2d is more convenient */
+       for (i = 0 ; i < t->total; i++, td++) {
+               /* it is assumed that td->ob is a pointer to the object,
+                * whose active action is where this keyframe comes from 
+                */
+               Object *ob= td->ob;
+               
+               /* check if any need to apply nla-scaling */
+               if (ob) {
+                       deltax = get_action_frame_inv(ob, cval);
+                       deltax -= get_action_frame_inv(ob, sval);
+                       
+                       if (autosnap == SACTSNAP_STEP) {
+                               if (doTime) 
+                                       deltax= (float)( floor((deltax/secf) + 0.5f) * secf );
+                               else
+                                       deltax= (float)( floor(deltax + 0.5f) );
+                       }
+                       
+                       val = get_action_frame_inv(ob, td->ival);
+                       val += deltax;
+                       *(td->val) = get_action_frame(ob, val);
+               }
+               else {
+                       deltax = val = t->fac;
+                       
+                       if (autosnap == SACTSNAP_STEP) {
+                               if (doTime)
+                                       val= (float)( floor((deltax/secf) + 0.5f) * secf );
+                               else
+                                       val= (float)( floor(val + 0.5f) );
+                       }
+                       
+                       *(td->val) = td->ival + val;
+               }
+               
+               /* apply snap-to-nearest-frame? */
+               doAnimEdit_SnapFrame(t, td, ob, autosnap);
+       }
+}
+
+int TimeTranslate(TransInfo *t, short mval[2]) 
+{
+       float cval[2], sval[2];
+       char str[200];
+       
+       /* calculate translation amount from mouse movement - in 'time-grid space' */
+       areamouseco_to_ipoco(G.v2d, mval, &cval[0], &cval[1]);
+       areamouseco_to_ipoco(G.v2d, t->imval, &sval[0], &sval[1]);
+       
+       /* we only need to calculate effect for time (applyTimeTranslate only needs that) */
+       t->fac= cval[0] - sval[0];
+       
+       /* handle numeric-input stuff */
+       t->vec[0] = t->fac;
+       applyNumInput(&t->num, &t->vec[0]);
+       t->fac = t->vec[0];
+       headerTimeTranslate(t, str);
+       
+       applyTimeTranslate(t, sval[0]);
+
+       recalcData(t);
+
+       headerprint(str);
+       
+       viewRedrawForce(t);
+
+       return 1;
+}
+
+/* ----------------- Time Slide ----------------------- */
+
+void initTimeSlide(TransInfo *t) 
+{
+       /* this tool is only really available in the Action Editor... */
+       if (t->spacetype == SPACE_ACTION) {
+               /* set flag for drawing stuff*/
+               G.saction->flag |= SACTION_MOVING;
+       }
+       
+       t->mode = TFM_TIME_SLIDE;
+       t->transform = TimeSlide;
+       t->flag |= T_FREE_CUSTOMDATA;
+
+       /* num-input has max of (n-1) */
+       t->idx_max = 0;
+       t->num.flag = 0;
+       t->num.idx_max = t->idx_max;
+       
+       /* initialise snap like for everything else */
+       t->snap[0] = 0.0f; 
+       t->snap[1] = t->snap[2] = 1.0f;
+}
+
+static void headerTimeSlide(TransInfo *t, float sval, char *str) 
+{
+       char tvec[60];
+       
+       if (hasNumInput(&t->num)) {
+               outputNumInput(&(t->num), tvec);
+       }
+       else {
+               float minx= *((float *)(t->customData));
+               float maxx= *((float *)(t->customData + 1));
+               float cval= t->fac;
+               float val;
+                       
+               val= 2.0*(cval-sval) / (maxx-minx);
+               CLAMP(val, -1.0f, 1.0f);
+               
+               sprintf(&tvec[0], "%.4f", val);
+       }
+               
+       sprintf(str, "TimeSlide: %s", &tvec[0]);
+}
+
+static void applyTimeSlide(TransInfo *t, float sval) 
+{
+       TransData *td = t->data;
+       int i;
+       
+       float minx= *((float *)(t->customData));
+       float maxx= *((float *)(t->customData + 1));
+       
+       /* set value for drawing black line */
+       if (t->spacetype == SPACE_ACTION) {
+               G.saction->timeslide= t->fac;
+               
+               if (NLA_ACTION_SCALED)
+                       sval= get_action_frame(OBACT, sval);
+       }
+       
+       /* it doesn't matter whether we apply to t->data or t->data2d, but t->data2d is more convenient */
+       for (i = 0 ; i < t->total; i++, td++) {
+               /* it is assumed that td->ob is a pointer to the object,
+                * whose active action is where this keyframe comes from 
+                */
+               Object *ob= td->ob;
+               float cval = t->fac;
+               
+               /* apply scaling to necessary values */
+               if (ob)
+                       cval= get_action_frame(ob, cval);
+               
+               /* only apply to data if in range */
+               if (sval > minx && sval < maxx) {
+                       float cvalc= CLAMPIS(cval, minx, maxx);
+                       float timefac;
+                       
+                       /* left half? */
+                       if (td->ival < sval) {
+                               timefac= (sval - td->ival) / (sval - minx);
+                               *(td->val)= cvalc - timefac * (cvalc - minx);
+                       }
+                       else {
+                               timefac= (td->ival - sval) / (maxx - sval);
+                               *(td->val)= cvalc + timefac * (maxx - cvalc);
+                       }
+               }
+       }
+}
+
+int TimeSlide(TransInfo *t, short mval[2]) 
+{
+       float cval[2], sval[2];
+       char str[200];
+       
+       /* calculate mouse co-ordinates */
+       areamouseco_to_ipoco(G.v2d, mval, &cval[0], &cval[1]);
+       areamouseco_to_ipoco(G.v2d, t->imval, &sval[0], &sval[1]);
+       
+       /* calculate fake value to work with */
+       t->fac= cval[0];
+       
+       /* handle numeric-input stuff */
+       t->vec[0] = t->fac;
+       applyNumInput(&t->num, &t->vec[0]);
+       t->fac = t->vec[0];
+       headerTimeSlide(t, sval[0], str);
+       
+       applyTimeSlide(t, sval[0]);
+
+       recalcData(t);
+
+       headerprint(str);
+       
+       viewRedrawForce(t);
+
+       return 1;
+}
+
+/* ----------------- Scaling ----------------------- */
+
+void initTimeScale(TransInfo *t) 
+{
+       t->mode = TFM_TIME_SCALE;
+       t->transform = TimeScale;
+
+       t->flag |= T_NULL_ONE;
+       t->num.flag |= NUM_NULL_ONE;
+       
+       /* num-input has max of (n-1) */
+       t->idx_max = 0;
+       t->num.flag = 0;
+       t->num.idx_max = t->idx_max;
+       
+       /* initialise snap like for everything else */
+       t->snap[0] = 0.0f; 
+       t->snap[1] = t->snap[2] = 1.0f;
+}
+
+static void headerTimeScale(TransInfo *t, char *str) {
+       char tvec[60];
+       
+       if (hasNumInput(&t->num))
+               outputNumInput(&(t->num), tvec);
+       else
+               sprintf(&tvec[0], "%.4f", t->fac);
+               
+       sprintf(str, "ScaleX: %s", &tvec[0]);
+}
+
+static void applyTimeScale(TransInfo *t) {
+       TransData *td = t->data;
+       int i;
+       
+       short autosnap= getAnimEdit_SnapMode(t);
+       short doTime= getAnimEdit_DrawTime(t);
+       float secf= ((float)G.scene->r.frs_sec);
+       
+       
+       for (i = 0 ; i < t->total; i++, td++) {
+               /* it is assumed that td->ob is a pointer to the object,
+                * whose active action is where this keyframe comes from 
+                */
+               Object *ob= td->ob;
+               float startx= CFRA;
+               float fac= t->fac;
+               
+               if (autosnap == SACTSNAP_STEP) {
+                       if (doTime)
+                               fac= (float)( floor(fac/secf + 0.5f) * secf );
+                       else
+                               fac= (float)( floor(fac + 0.5f) );
+               }
+               
+               /* check if any need to apply nla-scaling */
+               if (ob)
+                       startx= get_action_frame(ob, startx);
+                       
+               /* now, calculate the new value */
+               *(td->val) = td->ival - startx;
+               *(td->val) *= fac;
+               *(td->val) += startx;
+               
+               /* apply snap-to-nearest-frame? */
+               doAnimEdit_SnapFrame(t, td, ob, autosnap);
+       }
+}
+
+int TimeScale(TransInfo *t, short mval[2]) 
+{
+       float cval, sval;
+       float deltax, startx;
+       float width= 0.0f;
+       char str[200];
+       
+       sval= t->imval[0];
+       cval= mval[0];
+       
+       switch (t->spacetype) {
+               case SPACE_ACTION:
+                       width= ACTWIDTH;
+                       break;
+               case SPACE_NLA:
+                       width= NLAWIDTH;
+                       break;
+       }
+       
+       /* calculate scaling factor */
+       startx= sval-(width/2+(curarea->winrct.xmax-curarea->winrct.xmin)/2);
+       deltax= cval-(width/2+(curarea->winrct.xmax-curarea->winrct.xmin)/2);
+       t->fac = deltax / startx;
+       
+       /* handle numeric-input stuff */
+       t->vec[0] = t->fac;
+       applyNumInput(&t->num, &t->vec[0]);
+       t->fac = t->vec[0];
+       headerTimeScale(t, str);
+       
+       applyTimeScale(t);
+
+       recalcData(t);
+
+       headerprint(str);
+       
+       viewRedrawForce(t);
+
+       return 1;
+}
+
 /* ************************************ */
 
 void BIF_TransformSetUndo(char *str)
index ce572d56ce434ab0ce8fa04176112f74d1e01d57..618c19087626b0d67e104018851ca24c75b041e0 100644 (file)
@@ -58,6 +58,7 @@
 #include "DNA_meshdata_types.h"
 #include "DNA_meta_types.h"
 #include "DNA_modifier_types.h"
+#include "DNA_nla_types.h"
 #include "DNA_object_types.h"
 #include "DNA_object_force.h"
 #include "DNA_scene_types.h"
@@ -85,6 +86,8 @@
 #include "BKE_global.h"
 #include "BKE_ipo.h"
 #include "BKE_lattice.h"
+#include "BKE_key.h"
+#include "BKE_main.h"
 #include "BKE_mball.h"
 #include "BKE_mesh.h"
 #include "BKE_modifier.h"
 #include "BIF_editconstraint.h"
 #include "BIF_editarmature.h"
 #include "BIF_editmesh.h"
+#include "BIF_editnla.h"
 #include "BIF_editsima.h"
 #include "BIF_gl.h"
 #include "BIF_poseobject.h"
 #include "BSE_edit.h"
 #include "BSE_editipo.h"
 #include "BSE_editipo_types.h"
+#include "BSE_editaction_types.h"
 
 #include "BDR_editobject.h"            // reset_slowparents()
 #include "BDR_unwrapper.h"
@@ -1982,6 +1987,256 @@ int clipUVTransform(TransInfo *t, float *vec, int resize)
        return (clipx || clipy);
 }
 
+/* ********************* ACTION/NLA EDITOR ****************** */
+
+
+static void TimeToTransData(TransData *td, float *time, Object *ob)
+{
+       /* memory is calloc'ed, so that should zero everything nicely for us */
+       td->val = time;
+       td->ival = *(time);
+       
+       /* store the Object where this keyframe exists as a keyframe of the 
+        * active action as td->ob. Usually, this member is only used for constraints 
+        * drawing
+        */
+       td->ob= ob;
+}
+
+/* This function advances the address to which td points to, so it must return
+ * the new address so that the next time new transform data is added, it doesn't
+ * overwrite the existing ones...  i.e.   td = IpoToTransData(td, ipo, ob);
+ */
+static TransData *IpoToTransData(TransData *td, Ipo *ipo, Object *ob)
+{
+       IpoCurve *icu;
+       BezTriple *bezt;
+       int i;
+       
+       if (ipo == NULL)
+               return td;
+       
+       for (icu= ipo->curve.first; icu; icu= icu->next) {
+               /* only add selected keyframes (for now, proportional edit is not enabled) */
+               for (i=0, bezt=icu->bezt; i < icu->totvert; i++, bezt++) {
+                       if (BEZSELECTED(bezt)) {
+                               /* each control point needs to be added separetely */
+                               TimeToTransData(td, bezt->vec[0], ob);
+                               td++;
+                               
+                               TimeToTransData(td, bezt->vec[1], ob);
+                               td++;
+                               
+                               TimeToTransData(td, bezt->vec[2], ob);
+                               td++;
+                       }       
+               }
+       }
+       
+       return td;
+}
+
+static void createTransActionData(TransInfo *t)
+{
+       TransData *td = NULL;
+       Object *ob= NULL;
+       
+       ListBase act_data = {NULL, NULL};
+       bActListElem *ale;
+       void *data;
+       short datatype;
+       int filter;
+       
+       int count=0;
+       
+       /* determine what type of data we are operating on */
+       data = get_action_context(&datatype);
+       if (data == NULL) return;
+       
+       /* filter data */
+       filter= (ACTFILTER_VISIBLE | ACTFILTER_FOREDIT | ACTFILTER_IPOKEYS);
+       actdata_filter(&act_data, filter, data, datatype);
+       
+       /* is the action scaled? if so, the it should belong to the active object */
+       if (NLA_ACTION_SCALED)
+               ob= OBACT;
+       
+       /* loop 1: fully select ipo-keys and count how many BezTriples are selected */
+       for (ale= act_data.first; ale; ale= ale->next)
+               count += fullselect_ipo_keys(ale->key_data);
+       
+       /* stop if trying to build list if nothing selected */
+       if (count == 0) {
+               /* cleanup temp list */
+               BLI_freelistN(&act_data);
+               return;
+       }
+       
+       /* allocate memory for data */
+       t->total= count;
+       t->data= MEM_callocN(t->total*sizeof(TransData), "TransData(Action Editor)");
+       if (t->mode == TFM_TIME_SLIDE)
+               t->customData= MEM_callocN(sizeof(float)*2, "TimeSlide Min/Max");
+       
+       td= t->data;
+       /* loop 2: build transdata array */
+       for (ale= act_data.first; ale; ale= ale->next) {
+               Ipo *ipo= (Ipo *)ale->key_data;
+               
+               td= IpoToTransData(td, ipo, ob);
+       }
+       
+       /* check if we're supposed to be setting minx/maxx for TimeSlide */
+       if (t->mode == TFM_TIME_SLIDE) {
+               float min = 0, max = 0;
+               int i;
+               
+               td= (t->data + 1);
+               for (i=1; i < count; i+=3, td+=3) {
+                       if (min > *(td->val)) min= *(td->val);
+                       if (max < *(td->val)) max= *(td->val);
+               }
+               
+               /* minx/maxx values used by TimeSlide are stored as a 
+                * calloced 2-float array in t->customData. This gets freed
+                * in postTrans (T_FREE_CUSTOMDATA). 
+                */
+               *((float *)(t->customData)) = min;
+               *((float *)(t->customData + 1)) = max;
+       }
+       
+       /* cleanup temp list */
+       BLI_freelistN(&act_data);
+}
+
+static void createTransNLAData(TransInfo *t)
+{
+       Base *base;
+       bActionStrip *strip;
+       bActionChannel *achan;
+       bConstraintChannel *conchan;
+       
+       TransData *td = NULL;
+       int count=0, i;
+       
+       /* 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;
+               count += i;
+               
+               /* Check object constraint ipos */
+               for (conchan=base->object->constraintChannels.first; conchan; conchan=conchan->next)
+                       count += 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 (achan=base->object->action->chanbase.first; achan; achan=achan->next) {
+                                       if (EDITABLE_ACHAN(achan)) {
+                                               i= fullselect_ipo_keys(achan->ipo);
+                                               if (i) base->flag |= BA_HAS_RECALC_OB|BA_HAS_RECALC_DATA;
+                                               count += i;
+                                               
+                                               /* Check action constraint ipos */
+                                               if (EXPANDED_ACHAN(achan) && FILTER_CON_ACHAN(achan)) {
+                                                       for (conchan=achan->constraintChannels.first; conchan; conchan=conchan->next) {
+                                                               if (EDITABLE_CONCHAN(conchan))
+                                                                       count += 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;
+                               count += 2;
+                       }
+               }
+       }
+       
+       /* If nothing is selected, bail out */
+       if (count == 0)
+               return;
+       
+       /* allocate memory for data */
+       t->total= count;
+       t->data= MEM_callocN(t->total*sizeof(TransData), "TransData (NLA Editor)");
+       
+       /* build the transdata structure */
+       td= t->data;
+       for (base=G.scene->base.first; base; base=base->next) {
+               /* Manipulate object ipos */
+               /*      - no scaling of keyframe times is allowed here  */
+               td= IpoToTransData(td, base->object->ipo, NULL);
+               
+               /* Manipulate object constraint ipos */
+               /*      - no scaling of keyframe times is allowed here  */
+               for (conchan=base->object->constraintChannels.first; conchan; conchan=conchan->next)
+                       td= IpoToTransData(td, conchan->ipo, NULL);
+               
+               /* 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 that active action belongs to 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;
+                       }
+                       
+                       /* can include if no strip found */
+                       if (strip==NULL) {
+                               for (achan=base->object->action->chanbase.first; achan; achan=achan->next) {
+                                       if (EDITABLE_ACHAN(achan)) {
+                                               td= IpoToTransData(td, achan->ipo, base->object);
+                                               
+                                               /* Manipulate action constraint ipos */
+                                               if (EXPANDED_ACHAN(achan) && FILTER_CON_ACHAN(achan)) {
+                                                       for (conchan=achan->constraintChannels.first; conchan; conchan=conchan->next) {
+                                                               if (EDITABLE_CONCHAN(conchan))
+                                                                       td= IpoToTransData(td, conchan->ipo, base->object);
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+               }
+               
+               /* Manipulate nlastrips */
+               for (strip=base->object->nlastrips.first; strip; strip=strip->next) {
+                       if (strip->flag & ACTSTRIP_SELECT) {
+                               /* first TransData is the start, second is the end */
+                               td->val = &strip->start;
+                               td->ival = strip->start;
+                               td++;
+                               
+                               td->val = &strip->end;
+                               td->ival = strip->end;
+                               td++;
+                       }
+               }
+       }
+}
+
 /* **************** IpoKey stuff, for Object TransData ********** */
 
 /* storage of bezier triple. thats why -3 and +3! */
@@ -2414,8 +2669,23 @@ void autokeyframe_pose_cb_func(Object *ob, int tmode, short targetless_ik)
        }
 }
 
+/* very bad call!!! - copied from editnla.c!  */
+static void recalc_all_ipos(void)
+{
+       Ipo *ipo;
+       IpoCurve *icu;
+       
+       /* Go to each ipo */
+       for (ipo=G.main->ipo.first; ipo; ipo=ipo->id.next){
+               for (icu = ipo->curve.first; icu; icu=icu->next){
+                       sort_time_ipocurve(icu);
+                       testhandles_ipocurve(icu);
+               }
+       }
+}
+
 /* inserting keys, refresh ipo-keys, softbody, redraw events... (ton) */
-/* note; transdata has been freed already! */
+/* note: transdata has been freed already! */
 void special_aftertrans_update(TransInfo *t)
 {
        Object *ob;
@@ -2423,7 +2693,56 @@ void special_aftertrans_update(TransInfo *t)
        int redrawipo=0;
        int cancelled= (t->state == TRANS_CANCEL);
                
-       if(G.obedit) {
+       if(t->spacetype == SPACE_ACTION) {
+               void *data;
+               short datatype;
+               
+               /* determine what type of data we are operating on */
+               data = get_action_context(&datatype);
+               if (data == NULL) return;
+               ob = OBACT;
+               
+               if (datatype == ACTCONT_ACTION) {
+                       /* Update the curve */
+                       /* Depending on the lock status, draw necessary views */
+                       if (ob) {
+                               ob->ctime= -1234567.0f;
+                               
+                               if(ob->pose || ob_get_key(ob))
+                                       DAG_object_flush_update(G.scene, ob, OB_RECALC);
+                               else
+                                       DAG_object_flush_update(G.scene, ob, OB_RECALC_OB);
+                       }
+                       
+                       remake_action_ipos((bAction *)data);
+                       
+                       G.saction->flag &= ~SACTION_MOVING;
+               }
+               else if (datatype == ACTCONT_SHAPEKEY) {
+                       /* fix up the Ipocurves and redraw stuff */
+                       Key *key= (Key *)data;
+                       if (key->ipo) {
+                               IpoCurve *icu;
+                               
+                               for (icu = key->ipo->curve.first; icu; icu=icu->next) {
+                                       sort_time_ipocurve(icu);
+                                       testhandles_ipocurve(icu);
+                               }
+                       }
+                       
+                       DAG_object_flush_update(G.scene, OBACT, OB_RECALC_DATA);
+               }
+       }
+       else if(t->spacetype == SPACE_NLA) {
+               synchronize_action_strips();
+       
+               /* cleanup */
+               for (base=G.scene->base.first; base; base=base->next)
+                       base->flag &= ~(BA_HAS_RECALC_OB|BA_HAS_RECALC_DATA);
+               
+               recalc_all_ipos();      // bad
+       }
+       else if(G.obedit) {
                if(t->mode==TFM_BONESIZE || t->mode==TFM_BONE_ENVELOPE)
                        allqueue(REDRAWBUTSEDIT, 0);
                
@@ -2657,6 +2976,14 @@ void createTransData(TransInfo *t)
                        sort_trans_data_dist(t);
                }
        }
+       else if (t->spacetype == SPACE_ACTION) {
+               t->flag |= T_POINTS|T_2D_EDIT;
+               createTransActionData(t);
+       }
+       else if (t->spacetype == SPACE_NLA) {
+               t->flag |= T_POINTS|T_2D_EDIT;
+               createTransNLAData(t);
+       }
        else if (G.obedit) {
                t->ext = NULL;
                if (G.obedit->type == OB_MESH) {
index 357623ea4943301274eec23e198dd317bc3f0d76..562277ecff579495059648ece86256b3485283c8 100644 (file)
 #include "BIF_resources.h"
 #include "BIF_mywindow.h"
 #include "BIF_gl.h"
+#include "BIF_editaction.h"
 #include "BIF_editarmature.h"
 #include "BIF_editmesh.h"
+#include "BIF_editnla.h"
 #include "BIF_editsima.h"
 #include "BIF_meshtools.h"
 #include "BIF_retopo.h"
@@ -75,6 +77,7 @@
 #include "BKE_group.h"
 #include "BKE_ipo.h"
 #include "BKE_lattice.h"
+#include "BKE_key.h"
 #include "BKE_mesh.h"
 #include "BKE_modifier.h"
 #include "BKE_object.h"
@@ -85,6 +88,7 @@
 #endif
 
 #include "BSE_view.h"
+#include "BSE_editaction_types.h"
 #include "BDR_unwrapper.h"
 
 #include "BLI_arithb.h"
@@ -215,8 +219,47 @@ void recalcData(TransInfo *t)
 #ifdef WITH_VERSE
        struct TransData *td;
 #endif
+       
+       if (t->spacetype == SPACE_ACTION) {
+               Object *ob= OBACT;
+               void *data;
+               short context;
                
-       if (G.obedit) {
+               /* determine what type of data we are operating on */
+               data = get_action_context(&context);
+               if (data == NULL) return;
+       
+               if (G.saction->lock) {
+                       if (context == ACTCONT_ACTION) {
+                               if(ob) {
+                                       ob->ctime= -1234567.0f;
+                                       if(ob->pose || ob_get_key(ob))
+                                               DAG_object_flush_update(G.scene, ob, OB_RECALC);
+                                       else
+                                               DAG_object_flush_update(G.scene, ob, OB_RECALC_OB);
+                               }
+                       }
+                       else if (context == ACTCONT_SHAPEKEY) {
+                               DAG_object_flush_update(G.scene, OBACT, OB_RECALC_OB|OB_RECALC_DATA);
+                       }
+               }
+       }       
+       else if (t->spacetype == SPACE_NLA) {
+               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());
+               }
+       }
+       else if (G.obedit) {
                if (G.obedit->type == OB_MESH) {
                        if(t->spacetype==SPACE_IMAGE) {
                                flushTransUVs(t);