At last... this merge should finally do the trick!
[blender.git] / source / blender / editors / transform / transform.c
index 7faeef0bd6ad4f96aa5e3b477562a6f0914e21c8..ded6edbbb0e278ad656ac731224c63b1648543a7 100644 (file)
@@ -45,6 +45,7 @@
 
 #include "MEM_guardedalloc.h"
 
+#include "DNA_anim_types.h"
 #include "DNA_armature_types.h"
 #include "DNA_action_types.h"  /* for some special action-editor settings */
 #include "DNA_constraint_types.h"
@@ -76,9 +77,9 @@
 //#include "BIF_editmesh.h"
 //#include "BIF_editsima.h"
 //#include "BIF_editparticle.h"
-//#include "BIF_editaction.h" 
 
-#include "BKE_action.h" /* get_action_frame */
+#include "BKE_action.h"
+#include "BKE_nla.h"
 //#include "BKE_bad_level_calls.h"/* popmenu and error */
 #include "BKE_bmesh.h"
 #include "BKE_context.h"
 #include "BKE_utildefines.h"
 #include "BKE_context.h"
 
-//#include "BSE_drawipo.h"
-//#include "BSE_editnla_types.h"       /* for NLAWIDTH */
-//#include "BSE_editaction_types.h"
-//#include "BSE_time.h"
 //#include "BSE_view.h"
 
 #include "ED_image.h"
 #include "ED_screen.h"
 #include "ED_space_api.h"
+#include "ED_markers.h"
 #include "ED_util.h"
 #include "ED_view3d.h"
 
 
 #include "PIL_time.h"                  /* sleep                                */
 
+#include "UI_resources.h"
+
 //#include "blendef.h"
 //
 //#include "mydevice.h"
 
 #include "transform.h"
 
-/* ************************** Dashed help line **************************** */
-
-
-/* bad frontbuffer call... because it is used in transform after force_draw() */
-static void helpline(TransInfo *t, float *vec)
-{
-#if 0 // TRANSFORM_FIX_ME
-       float vecrot[3], cent[2];
-       short mval[2];
-       
-       VECCOPY(vecrot, vec);
-       if(t->flag & T_EDIT) {
-               Object *ob= t->obedit;
-               if(ob) Mat4MulVecfl(ob->obmat, vecrot);
-       }
-       else if(t->flag & T_POSE) {
-               Object *ob=t->poseobj;
-               if(ob) Mat4MulVecfl(ob->obmat, vecrot);
-       }
-       
-       getmouseco_areawin(mval);
-       projectFloatView(t, vecrot, cent);      // no overflow in extreme cases
-
-       persp(PERSP_WIN);
-       
-       glDrawBuffer(GL_FRONT);
-       
-       BIF_ThemeColor(TH_WIRE);
-       
-       setlinestyle(3);
-       glBegin(GL_LINE_STRIP); 
-       glVertex2sv(mval); 
-       glVertex2fv(cent); 
-       glEnd();
-       setlinestyle(0);
-       
-       persp(PERSP_VIEW);
-       bglFlush(); // flush display for frontbuffer
-       glDrawBuffer(GL_BACK);
-#endif
-}
-
 /* ************************** SPACE DEPENDANT CODE **************************** */
 
 void setTransformViewMatrices(TransInfo *t)
@@ -242,7 +200,8 @@ void convertViewVec(TransInfo *t, float *vec, short dx, short dy)
 void projectIntView(TransInfo *t, float *vec, int *adr)
 {
        if (t->spacetype==SPACE_VIEW3D) {
-               project_int_noclip(t->ar, vec, adr);
+               if(t->ar->regiontype == RGN_TYPE_WINDOW)
+                       project_int_noclip(t->ar, vec, adr);
        }
        else if(t->spacetype==SPACE_IMAGE) {
                float aspx, aspy, v[2];
@@ -272,7 +231,8 @@ void projectIntView(TransInfo *t, float *vec, int *adr)
 void projectFloatView(TransInfo *t, float *vec, float *adr)
 {
        if (t->spacetype==SPACE_VIEW3D) {
-               project_float_noclip(t->ar, vec, adr);
+               if(t->ar->regiontype == RGN_TYPE_WINDOW)
+                       project_float_noclip(t->ar, vec, adr);
        }
        else if(t->spacetype==SPACE_IMAGE) {
                int a[2];
@@ -359,6 +319,9 @@ static void viewRedrawForce(bContext *C, TransInfo *t)
                else 
                        ED_area_tag_redraw(t->sa);
        }
+       else if (t->spacetype == SPACE_NLA) {
+               ED_area_tag_redraw(t->sa); // XXX this should use a notifier instead!
+       }
        else if(t->spacetype == SPACE_NODE)
        {
                //ED_area_tag_redraw(t->sa);
@@ -639,6 +602,7 @@ void transformEvent(TransInfo *t, wmEvent *event)
                                resetTransRestrictions(t); 
                                restoreTransObjects(t);
                                initTranslation(t);
+                               initSnapping(t, NULL); // need to reinit after mode change
                                t->redraw = 1;
                        }
                        break;
@@ -648,6 +612,7 @@ void transformEvent(TransInfo *t, wmEvent *event)
                                resetTransRestrictions(t); 
                                restoreTransObjects(t);
                                initResize(t);
+                               initSnapping(t, NULL); // need to reinit after mode change
                                t->redraw = 1;
                        }
                        break;
@@ -665,6 +630,7 @@ void transformEvent(TransInfo *t, wmEvent *event)
                                        restoreTransObjects(t);
                                        initRotation(t);
                                }
+                               initSnapping(t, NULL); // need to reinit after mode change
                                t->redraw = 1;
                        }
                        break;
@@ -934,6 +900,231 @@ int calculateTransformCenter(bContext *C, wmEvent *event, int centerMode, float
        return success;
 }
 
+typedef enum {
+       UP,
+       DOWN,
+       LEFT,
+       RIGHT
+} ArrowDirection;
+static void drawArrow(ArrowDirection d, short offset, short length, short size)
+{
+       switch(d)
+       {
+               case LEFT:
+                       offset = -offset;
+                       length = -length;
+                       size = -size;
+               case RIGHT:
+                       glBegin(GL_LINES); 
+                       glVertex2s( offset, 0); 
+                       glVertex2s( offset + length, 0); 
+                       glVertex2s( offset + length, 0); 
+                       glVertex2s( offset + length - size, -size); 
+                       glVertex2s( offset + length, 0); 
+                       glVertex2s( offset + length - size,  size);
+                       glEnd(); 
+                       break;
+               case DOWN:
+                       offset = -offset;
+                       length = -length;
+                       size = -size;
+               case UP:
+                       glBegin(GL_LINES); 
+                       glVertex2s( 0, offset); 
+                       glVertex2s( 0, offset + length); 
+                       glVertex2s( 0, offset + length); 
+                       glVertex2s(-size, offset + length - size); 
+                       glVertex2s( 0, offset + length); 
+                       glVertex2s( size, offset + length - size);
+                       glEnd(); 
+                       break;
+       }
+}
+
+static void drawArrowHead(ArrowDirection d, short size)
+{
+       switch(d)
+       {
+               case LEFT:
+                       size = -size;
+               case RIGHT:
+                       glBegin(GL_LINES); 
+                       glVertex2s( 0, 0); 
+                       glVertex2s( -size, -size); 
+                       glVertex2s( 0, 0); 
+                       glVertex2s( -size,  size);
+                       glEnd(); 
+                       break;
+               case DOWN:
+                       size = -size;
+               case UP:
+                       glBegin(GL_LINES); 
+                       glVertex2s( 0, 0); 
+                       glVertex2s(-size, -size); 
+                       glVertex2s( 0, 0); 
+                       glVertex2s( size, -size);
+                       glEnd(); 
+                       break;
+       }
+}
+
+static void drawArc(float size, float angle_start, float angle_end, int segments)
+{
+       float delta = (angle_end - angle_start) / segments;
+       float angle;
+       
+       glBegin(GL_LINE_STRIP);
+       
+       for( angle = angle_start; angle < angle_end; angle += delta)
+       {
+               glVertex2f( cosf(angle) * size, sinf(angle) * size);
+       }
+       glVertex2f( cosf(angle_end) * size, sinf(angle_end) * size);
+       
+       glEnd();
+}
+
+void drawHelpline(const struct bContext *C, TransInfo *t)
+{
+       if (t->helpline != HLP_NONE && !(t->flag & T_USES_MANIPULATOR))
+       {
+               float vecrot[3], cent[2];
+               
+               VECCOPY(vecrot, t->center);
+               if(t->flag & T_EDIT) {
+                       Object *ob= t->obedit;
+                       if(ob) Mat4MulVecfl(ob->obmat, vecrot);
+               }
+               else if(t->flag & T_POSE) {
+                       Object *ob=t->poseobj;
+                       if(ob) Mat4MulVecfl(ob->obmat, vecrot);
+               }
+               
+               projectFloatView(t, vecrot, cent);      // no overflow in extreme cases
+       
+               glDisable(GL_DEPTH_TEST);
+
+               glMatrixMode(GL_PROJECTION);
+               glPushMatrix();
+               glMatrixMode(GL_MODELVIEW);
+               glPushMatrix();
+
+               ED_region_pixelspace(t->ar);
+               
+               switch(t->helpline)
+               {
+                       case HLP_SPRING:
+                               UI_ThemeColor(TH_WIRE);
+                               
+                               setlinestyle(3);
+                               glBegin(GL_LINE_STRIP); 
+                               glVertex2sv(t->mval); 
+                               glVertex2fv(cent); 
+                               glEnd();
+
+                               glTranslatef(t->mval[0], t->mval[1], 0);
+                               glRotatef(-180 / M_PI * atan2f(cent[0] - t->mval[0], cent[1] - t->mval[1]), 0, 0, 1);
+
+                               setlinestyle(0);
+                               glLineWidth(3.0);
+                               drawArrow(UP, 5, 10, 5);
+                               drawArrow(DOWN, 5, 10, 5);
+                               glLineWidth(1.0);
+                               break;
+                       case HLP_HARROW:
+                               UI_ThemeColor(TH_WIRE);
+
+                               glTranslatef(t->mval[0], t->mval[1], 0);
+
+                               glLineWidth(3.0);
+                               drawArrow(RIGHT, 5, 10, 5);
+                               drawArrow(LEFT, 5, 10, 5);
+                               glLineWidth(1.0);
+                               break;
+                       case HLP_VARROW:
+                               UI_ThemeColor(TH_WIRE);
+
+                               glTranslatef(t->mval[0], t->mval[1], 0);
+
+                               glLineWidth(3.0);
+                               glBegin(GL_LINES); 
+                               drawArrow(UP, 5, 10, 5);
+                               drawArrow(DOWN, 5, 10, 5);
+                               glLineWidth(1.0);
+                               break;
+                       case HLP_ANGLE:
+                               {
+                                       float dx = t->mval[0] - cent[0], dy = t->mval[1] - cent[1];
+                                       float angle = atan2f(dy, dx);
+                                       float dist = sqrtf(dx*dx + dy*dy);
+                                       float delta_angle = MIN2(15 / dist, M_PI/4);
+                                       float spacing_angle = MIN2(5 / dist, M_PI/12);
+                                       UI_ThemeColor(TH_WIRE);
+       
+                                       setlinestyle(3);
+                                       glBegin(GL_LINE_STRIP); 
+                                       glVertex2sv(t->mval); 
+                                       glVertex2fv(cent); 
+                                       glEnd();
+                                       
+                                       glTranslatef(cent[0], cent[1], 0);
+       
+                                       setlinestyle(0);
+                                       glLineWidth(3.0);
+                                       drawArc(dist, angle - delta_angle, angle - spacing_angle, 10);
+                                       drawArc(dist, angle + spacing_angle, angle + delta_angle, 10);
+                                       
+                                       glPushMatrix();
+
+                                       glTranslatef(cosf(angle - delta_angle) * dist, sinf(angle - delta_angle) * dist, 0);
+                                       glRotatef(180 / M_PI * (angle - delta_angle), 0, 0, 1);
+                                       
+                                       drawArrowHead(DOWN, 5);
+                                       
+                                       glPopMatrix();
+
+                                       glTranslatef(cosf(angle + delta_angle) * dist, sinf(angle + delta_angle) * dist, 0);
+                                       glRotatef(180 / M_PI * (angle + delta_angle), 0, 0, 1);
+
+                                       drawArrowHead(UP, 5);
+
+                                       glLineWidth(1.0);
+                                       break;
+                               }
+                               case HLP_TRACKBALL:
+                               {
+                                       char col[3], col2[3];
+                                       UI_GetThemeColor3ubv(TH_GRID, col);
+       
+                                       glTranslatef(t->mval[0], t->mval[1], 0);
+       
+                                       glLineWidth(3.0);
+       
+                                       UI_make_axis_color(col, col2, 'x');
+                                       glColor3ubv((GLubyte *)col2);
+       
+                                       drawArrow(RIGHT, 5, 10, 5);
+                                       drawArrow(LEFT, 5, 10, 5);
+       
+                                       UI_make_axis_color(col, col2, 'y');
+                                       glColor3ubv((GLubyte *)col2);
+       
+                                       drawArrow(UP, 5, 10, 5);
+                                       drawArrow(DOWN, 5, 10, 5);
+                                       glLineWidth(1.0);
+                                       break;
+                               }
+               }
+               
+               glMatrixMode(GL_PROJECTION);
+               glPopMatrix();
+               glMatrixMode(GL_MODELVIEW);
+               glPopMatrix();
+               
+               glEnable(GL_DEPTH_TEST);
+       }
+}
+
 void drawTransform(const struct bContext *C, struct ARegion *ar, void *arg)
 {
        TransInfo *t = arg;
@@ -941,11 +1132,12 @@ void drawTransform(const struct bContext *C, struct ARegion *ar, void *arg)
        drawConstraint(C, t);
        drawPropCircle(C, t);
        drawSnapping(C, t);
+       drawHelpline(C, t);
 }
 
 void saveTransform(bContext *C, TransInfo *t, wmOperator *op)
 {
-       Scene *sce = CTX_data_scene(C);
+       ToolSettings *ts = CTX_data_tool_settings(C);
        int constraint_axis[3] = {0, 0, 0};
        int proportional = 0;
 
@@ -983,9 +1175,8 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op)
                RNA_boolean_set(op->ptr, "mirror", t->flag & T_MIRROR);
        }
        
-       if (RNA_struct_find_property(op->ptr, "constraint_mode"))
+       if (RNA_struct_find_property(op->ptr, "constraint_axis"))
        {
-               RNA_int_set(op->ptr, "constraint_mode", t->con.mode);
                RNA_int_set(op->ptr, "constraint_orientation", t->current_orientation);
 
                if (t->con.mode & CON_APPLY)
@@ -1007,8 +1198,8 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op)
        // XXX If modal, save settings back in scene
        if (t->flag & T_MODAL)
        {
-               sce->prop_mode = t->prop_mode;
-               sce->proportional = proportional;
+               ts->prop_mode = t->prop_mode;
+               ts->proportional = proportional;
 
                if(t->spacetype == SPACE_VIEW3D)
                {
@@ -1036,18 +1227,11 @@ int initTransform(bContext *C, TransInfo *t, wmOperator *op, wmEvent *event, int
                return 0;
        }
 
-       initTransformOrientation(C, t);
-
        if(t->spacetype == SPACE_VIEW3D)
        {
                //calc_manipulator_stats(curarea);
-               if (t->ar->regiontype == RGN_TYPE_WINDOW)
-               {
-                       RegionView3D *rv3d = t->ar->regiondata;
-                       Mat3CpyMat4(t->spacemtx, rv3d->twmat);
-               }
-               Mat3Ortho(t->spacemtx);
-               
+               initTransformOrientation(C, t);
+       
                t->draw_handle = ED_region_draw_cb_activate(t->ar->type, drawTransform, t, REGION_DRAW_POST);
        }
        else if(t->spacetype == SPACE_IMAGE) {
@@ -1064,7 +1248,7 @@ int initTransform(bContext *C, TransInfo *t, wmOperator *op, wmEvent *event, int
                return 0;
        }
 
-       initSnapping(t); // Initialize snapping data AFTER mode flags
+       initSnapping(t, op); // Initialize snapping data AFTER mode flags
 
        /* EVIL! posemode code can switch translation to rotate when 1 bone is selected. will be removed (ton) */
        /* EVIL2: we gave as argument also texture space context bit... was cleared */
@@ -1819,7 +2003,7 @@ void initWarp(TransInfo *t)
        t->snap[2] = 1.0f;
        
        t->flag |= T_NO_CONSTRAINT;
-
+       
        /* we need min/max in view space */
        for(i = 0; i < t->total; i++) {
                float center[3];
@@ -1955,8 +2139,6 @@ int Warp(TransInfo *t, short mval[2])
        
        ED_area_headerprint(t->sa, str);
        
-       helpline(t, gcursor);
-       
        return 1;
 }
 
@@ -2077,8 +2259,6 @@ int Shear(TransInfo *t, short mval[2])
 
        ED_area_headerprint(t->sa, str);
 
-       helpline (t, t->center);
-
        return 1;
 }
 
@@ -2182,7 +2362,7 @@ static void ElementResize(TransInfo *t, TransData *td, float mat[3][3]) {
                }
                else if (t->flag & T_EDIT) {
                        
-                       if(t->around==V3D_LOCAL && (t->scene->selectmode & SCE_SELECT_FACE)) {
+                       if(t->around==V3D_LOCAL && (t->settings->selectmode & SCE_SELECT_FACE)) {
                                VECCOPY(center, td->center);
                        }
                        else {
@@ -2355,8 +2535,6 @@ int Resize(TransInfo *t, short mval[2])
 
        ED_area_headerprint(t->sa, str);
 
-       if(!(t->flag & T_USES_MANIPULATOR)) helpline (t, t->center);
-
        return 1;
 }
 
@@ -2380,7 +2558,7 @@ void initToSphere(TransInfo *t)
        
        t->num.flag |= NUM_NULL_ONE | NUM_NO_NEGATIVE;
        t->flag |= T_NO_CONSTRAINT;
-
+       
        // Calculate average radius
        for(i = 0 ; i < t->total; i++, td++) {
                t->val += VecLenf(t->center, td->iloc);
@@ -2485,7 +2663,7 @@ static void ElementRotation(TransInfo *t, TransData *td, float mat[3][3], short
                }
                else {
                        /* !TODO! Make this if not rely on G */
-                       if(around==V3D_LOCAL && (t->scene->selectmode & SCE_SELECT_FACE)) {
+                       if(around==V3D_LOCAL && (t->settings->selectmode & SCE_SELECT_FACE)) {
                                center = td->center;
                        }
                }
@@ -2782,8 +2960,6 @@ int Rotation(TransInfo *t, short mval[2])
 
        ED_area_headerprint(t->sa, str);
 
-       if(!(t->flag & T_USES_MANIPULATOR)) helpline (t, t->center);
-
        return 1;
 }
 
@@ -2889,8 +3065,6 @@ int Trackball(TransInfo *t, short mval[2])
        
        ED_area_headerprint(t->sa, str);
        
-       if(!(t->flag & T_USES_MANIPULATOR)) helpline (t, t->center);
-       
        return 1;
 }
 
@@ -2955,7 +3129,7 @@ static void headerTranslation(TransInfo *t, float vec[3], char *str) {
                sprintf(distvec, "%.4f", dist);
                
        if(t->flag & T_AUTOIK) {
-               short chainlen= t->scene->toolsettings->autoik_chainlen;
+               short chainlen= t->settings->autoik_chainlen;
                
                if(chainlen)
                        sprintf(autoik, "AutoIK-Len: %d", chainlen);
@@ -3236,8 +3410,6 @@ int Tilt(TransInfo *t, short mval[2])
 
        ED_area_headerprint(t->sa, str);
 
-       helpline (t, t->center);
-
        return 1;
 }
 
@@ -3302,8 +3474,6 @@ int CurveShrinkFatten(TransInfo *t, short mval[2])
        
        ED_area_headerprint(t->sa, str);
        
-       if(!(t->flag & T_USES_MANIPULATOR)) helpline (t, t->center);
-       
        return 1;
 }
 
@@ -3575,8 +3745,6 @@ int BevelWeight(TransInfo *t, short mval[2])
 
        ED_area_headerprint(t->sa, str);
 
-       helpline (t, t->center);
-
        return 1;
 }
 
@@ -3651,8 +3819,6 @@ int Crease(TransInfo *t, short mval[2])
 
        ED_area_headerprint(t->sa, str);
 
-       helpline (t, t->center);
-
        return 1;
 }
 
@@ -3768,8 +3934,6 @@ int BoneSize(TransInfo *t, short mval[2])
        
        ED_area_headerprint(t->sa, str);
        
-       if(!(t->flag & T_USES_MANIPULATOR)) helpline (t, t->center);
-       
        return 1;
 }
 
@@ -3836,8 +4000,6 @@ int BoneEnvelope(TransInfo *t, short mval[2])
        
        ED_area_headerprint(t->sa, str);
        
-       if(!(t->flag & T_USES_MANIPULATOR)) helpline (t, t->center);
-       
        return 1;
 }
 
@@ -3902,8 +4064,6 @@ int BoneRoll(TransInfo *t, short mval[2])
 
        ED_area_headerprint(t->sa, str);
 
-       if(!(t->flag & T_USES_MANIPULATOR)) helpline (t, t->center);
-
        return 1;
 }
 
@@ -3980,8 +4140,6 @@ int BakeTime(TransInfo *t, short mval[2])
 
        ED_area_headerprint(t->sa, str);
 
-       helpline (t, t->center);
-
        return 1;
 }
 
@@ -4096,7 +4254,7 @@ int Align(TransInfo *t, short mval[2])
                        VECCOPY(t->center, td->center);
                }
                else {
-                       if(t->scene->selectmode & SCE_SELECT_FACE) {
+                       if(t->settings->selectmode & SCE_SELECT_FACE) {
                                VECCOPY(t->center, td->center);
                        }
                }
@@ -4196,7 +4354,7 @@ static short getAnimEdit_DrawTime(TransInfo *t)
 /* This function is used by Animation Editor specific transform functions to do 
  * the Snap Keyframe to Nearest Frame/Marker
  */
-static void doAnimEdit_SnapFrame(TransInfo *t, TransData *td, Object *ob, short autosnap)
+static void doAnimEdit_SnapFrame(TransInfo *t, TransData *td, AnimData *adt, short autosnap)
 {
        /* snap key to nearest frame? */
        if (autosnap == SACTSNAP_FRAME) {
@@ -4206,8 +4364,8 @@ static void doAnimEdit_SnapFrame(TransInfo *t, TransData *td, Object *ob, short
                double val;
                
                /* convert frame to nla-action time (if needed) */
-               if (ob
-                       val= get_action_frame_inv(ob, *(td->val));
+               if (adt
+                       val= BKE_nla_tweakedit_remap(adt, *(td->val), 1);
                else
                        val= *(td->val);
                
@@ -4218,8 +4376,8 @@ static void doAnimEdit_SnapFrame(TransInfo *t, TransData *td, Object *ob, short
                        val= (float)( floor(val+0.5f) );
                        
                /* convert frame out of nla-action time */
-               if (ob)
-                       *(td->val)= get_action_frame(ob, val);
+               if (adt)
+                       *(td->val)= BKE_nla_tweakedit_remap(adt, val, 0);
                else
                        *(td->val)= val;
        }
@@ -4228,18 +4386,18 @@ static void doAnimEdit_SnapFrame(TransInfo *t, TransData *td, Object *ob, short
                float val;
                
                /* convert frame to nla-action time (if needed) */
-               if (ob
-                       val= get_action_frame_inv(ob, *(td->val));
+               if (adt
+                       val= BKE_nla_tweakedit_remap(adt, *(td->val), 1);
                else
                        val= *(td->val);
                
                /* snap to nearest marker */
-               // XXX missing function!
-               //val= (float)find_nearest_marker_time(val);
+               // TODO: need some more careful checks for where data comes from
+               val= (float)ED_markers_find_nearest_marker_time(&t->scene->markers, val);
                
                /* convert frame out of nla-action time */
-               if (ob)
-                       *(td->val)= get_action_frame(ob, val);
+               if (adt)
+                       *(td->val)= BKE_nla_tweakedit_remap(adt, val, 0);
                else
                        *(td->val)= val;
        }
@@ -4312,13 +4470,14 @@ static void applyTimeTranslate(TransInfo *t, float 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,
+               /* it is assumed that td->extra is a pointer to the AnimData,
                 * whose active action is where this keyframe comes from 
+                * (this is only valid when not in NLA)
                 */
-               Object *ob= td->ob;
+               AnimData *adt= (t->spacetype != SPACE_NLA) ? td->extra : NULL;
                
-               /* check if any need to apply nla-scaling */
-               if (ob) {
+               /* check if any need to apply nla-mapping */
+               if (adt) {
                        deltax = t->values[0];
                        
                        if (autosnap == SACTSNAP_STEP) {
@@ -4328,9 +4487,9 @@ static void applyTimeTranslate(TransInfo *t, float sval)
                                        deltax= (float)( floor(deltax + 0.5f) );
                        }
                        
-                       val = get_action_frame_inv(ob, td->ival);
+                       val = BKE_nla_tweakedit_remap(adt, td->ival, 1);
                        val += deltax;
-                       *(td->val) = get_action_frame(ob, val);
+                       *(td->val) = BKE_nla_tweakedit_remap(adt, val, 0);
                }
                else {
                        deltax = val = t->values[0];
@@ -4346,7 +4505,7 @@ static void applyTimeTranslate(TransInfo *t, float sval)
                }
                
                /* apply nearest snapping */
-               doAnimEdit_SnapFrame(t, td, ob, autosnap);
+               doAnimEdit_SnapFrame(t, td, adt, autosnap);
        }
 }
 
@@ -4446,15 +4605,16 @@ static void applyTimeSlide(TransInfo *t, float 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,
+               /* it is assumed that td->extra is a pointer to the AnimData,
                 * whose active action is where this keyframe comes from 
+                * (this is only valid when not in NLA)
                 */
-               Object *ob= td->ob;
+               AnimData *adt= (t->spacetype != SPACE_NLA) ? td->extra : NULL;
                float cval = t->values[0];
                
-               /* apply scaling to necessary values */
-               if (ob)
-                       cval= get_action_frame(ob, cval);
+               /* apply NLA-mapping to necessary values */
+               if (adt)
+                       cval= BKE_nla_tweakedit_remap(adt, cval, 0);
                
                /* only apply to data if in range */
                if ((sval > minx) && (sval < maxx)) {
@@ -4512,6 +4672,7 @@ void initTimeScale(TransInfo *t)
        t->transform = TimeScale;
        
        initMouseInputMode(t, &t->mouse, INPUT_NONE);
+       t->helpline = HLP_SPRING; /* set manually because we don't use a predefined input */
 
        t->flag |= T_NULL_ONE;
        t->num.flag |= NUM_NULL_ONE;
@@ -4548,10 +4709,11 @@ static void applyTimeScale(TransInfo *t) {
        
        
        for (i = 0 ; i < t->total; i++, td++) {
-               /* it is assumed that td->ob is a pointer to the object,
+               /* it is assumed that td->extra is a pointer to the AnimData,
                 * whose active action is where this keyframe comes from 
+                * (this is only valid when not in NLA)
                 */
-               Object *ob= td->ob;
+               AnimData *adt= (t->spacetype != SPACE_NLA) ? td->extra : NULL;
                float startx= CFRA;
                float fac= t->values[0];
                
@@ -4562,9 +4724,9 @@ static void applyTimeScale(TransInfo *t) {
                                fac= (float)( floor(fac + 0.5f) );
                }
                
-               /* check if any need to apply nla-scaling */
-               if (ob)
-                       startx= get_action_frame(ob, startx);
+               /* check if any need to apply nla-mapping */
+               if (adt)
+                       startx= BKE_nla_tweakedit_remap(adt, startx, 0);
                        
                /* now, calculate the new value */
                *(td->val) = td->ival - startx;
@@ -4572,7 +4734,7 @@ static void applyTimeScale(TransInfo *t) {
                *(td->val) += startx;
                
                /* apply nearest snapping */
-               doAnimEdit_SnapFrame(t, td, ob, autosnap);
+               doAnimEdit_SnapFrame(t, td, adt, autosnap);
        }
 }
 
@@ -4586,18 +4748,6 @@ int TimeScale(TransInfo *t, short mval[2])
        sval= t->imval[0];
        cval= mval[0];
        
-       // XXX ewww... we need a better factor!
-#if 0 // TRANSFORM_FIX_ME              
-       switch (t->spacetype) {
-               case SPACE_ACTION:
-                       width= ACTWIDTH;
-                       break;
-               case SPACE_NLA:
-                       width= NLAWIDTH;
-                       break;
-       }
-#endif
-       
        /* calculate scaling factor */
        startx= sval-(width/2+(t->ar->winx)/2);
        deltax= cval-(width/2+(t->ar->winx)/2);