code cleanup: favor braces when blocks have mixed brace use.
[blender.git] / source / blender / editors / transform / transform.c
index 2e813aa..4aa5439 100644 (file)
 #include "DNA_movieclip_types.h"
 #include "DNA_scene_types.h"  /* PET modes */
 
-#include "RNA_access.h"
-
-#include "BIF_gl.h"
-#include "BIF_glutil.h"
-
-#include "BLF_api.h"
+#include "BLI_utildefines.h"
+#include "BLI_math.h"
+#include "BLI_rect.h"
+#include "BLI_listbase.h"
+#include "BLI_string.h"
+#include "BLI_ghash.h"
+#include "BLI_linklist.h"
+#include "BLI_smallhash.h"
 
 #include "BKE_nla.h"
 #include "BKE_bmesh.h"
@@ -69,6 +71,9 @@
 #include "BKE_unit.h"
 #include "BKE_mask.h"
 
+#include "BIF_gl.h"
+#include "BIF_glutil.h"
+
 #include "ED_image.h"
 #include "ED_keyframing.h"
 #include "ED_screen.h"
 #include "ED_clip.h"
 #include "ED_mask.h"
 
-#include "UI_view2d.h"
 #include "WM_types.h"
 #include "WM_api.h"
 
-#include "BLI_math.h"
-#include "BLI_blenlib.h"
-#include "BLI_utildefines.h"
-#include "BLI_ghash.h"
-#include "BLI_linklist.h"
-#include "BLI_smallhash.h"
-#include "BLI_array.h"
-
+#include "UI_view2d.h"
 #include "UI_interface_icons.h"
 #include "UI_resources.h"
 
+#include "RNA_access.h"
+
+#include "BLF_api.h"
+#include "BLF_translation.h"
+
 #include "transform.h"
 
 static void drawTransformApply(const struct bContext *C, ARegion *ar, void *arg);
 static int doEdgeSlide(TransInfo *t, float perc);
+static int doVertSlide(TransInfo *t, float perc);
+
+static void drawEdgeSlide(const struct bContext *C, TransInfo *t);
+static void drawVertSlide(const struct bContext *C, TransInfo *t);
+
+static bool transdata_check_local_center(TransInfo *t)
+{
+       return ((t->around == V3D_LOCAL) && (
+                   (t->flag & (T_OBJECT | T_POSE)) ||
+                   (t->obedit && t->obedit->type == OB_MESH && (t->settings->selectmode & (SCE_SELECT_EDGE | SCE_SELECT_FACE))) ||
+                   (t->obedit && t->obedit->type == OB_ARMATURE) ||
+                   (t->spacetype == SPACE_IPO))
+               );
+}
 
 /* ************************** SPACE DEPENDANT CODE **************************** */
 
@@ -223,11 +239,11 @@ void convertViewVec(TransInfo *t, float r_vec[3], int dx, int dy)
        }
 }
 
-void projectIntView(TransInfo *t, const float vec[3], int adr[2])
+void projectIntViewEx(TransInfo *t, const float vec[3], int adr[2], const eV3DProjTest flag)
 {
        if (t->spacetype == SPACE_VIEW3D) {
                if (t->ar->regiontype == RGN_TYPE_WINDOW) {
-                       if (ED_view3d_project_int_global(t->ar, vec, adr, V3D_PROJ_TEST_NOP) != V3D_PROJ_RET_OK) {
+                       if (ED_view3d_project_int_global(t->ar, vec, adr, flag) != V3D_PROJ_RET_OK) {
                                adr[0] = (int)2140000000.0f;  /* this is what was done in 2.64, perhaps we can be smarter? */
                                adr[1] = (int)2140000000.0f;
                        }
@@ -345,14 +361,19 @@ void projectIntView(TransInfo *t, const float vec[3], int adr[2])
                UI_view2d_to_region_no_clip((View2D *)t->view, vec[0], vec[1], adr, adr + 1);
        }
 }
+void projectIntView(TransInfo *t, const float vec[3], int adr[2])
+{
+       projectIntViewEx(t, vec, adr, V3D_PROJ_TEST_NOP);
+}
 
-void projectFloatView(TransInfo *t, const float vec[3], float adr[2])
+void projectFloatViewEx(TransInfo *t, const float vec[3], float adr[2], const eV3DProjTest flag)
 {
        switch (t->spacetype) {
                case SPACE_VIEW3D:
                {
                        if (t->ar->regiontype == RGN_TYPE_WINDOW) {
-                               if (ED_view3d_project_float_global(t->ar, vec, adr, V3D_PROJ_TEST_NOP) != V3D_PROJ_RET_OK) {
+                               /* allow points behind the view [#33643] */
+                               if (ED_view3d_project_float_global(t->ar, vec, adr, flag) != V3D_PROJ_RET_OK) {
                                        /* XXX, 2.64 and prior did this, weak! */
                                        adr[0] = t->ar->winx / 2.0f;
                                        adr[1] = t->ar->winy / 2.0f;
@@ -376,6 +397,10 @@ void projectFloatView(TransInfo *t, const float vec[3], float adr[2])
 
        zero_v2(adr);
 }
+void projectFloatView(TransInfo *t, const float vec[3], float adr[2])
+{
+       projectFloatViewEx(t, vec, adr, V3D_PROJ_TEST_NOP);
+}
 
 void applyAspectRatio(TransInfo *t, float vec[2])
 {
@@ -461,7 +486,10 @@ static void viewRedrawForce(const bContext *C, TransInfo *t)
                        WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL);
                else
                        WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
-               
+
+               if (t->mode == TFM_EDGE_SLIDE && (t->settings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT))
+                       WM_event_add_notifier(C, NC_GEOM | ND_DATA, NULL);
+
                /* for realtime animation record - send notifiers recognised by animation editors */
                // XXX: is this notifier a lame duck?
                if ((t->animtimer) && IS_AUTOKEY_ON(t->scene))
@@ -469,11 +497,11 @@ static void viewRedrawForce(const bContext *C, TransInfo *t)
                
        }
        else if (t->spacetype == SPACE_ACTION) {
-               //SpaceAction *saction= (SpaceAction *)t->sa->spacedata.first;
+               //SpaceAction *saction = (SpaceAction *)t->sa->spacedata.first;
                WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
        }
        else if (t->spacetype == SPACE_IPO) {
-               //SpaceIpo *sipo= (SpaceIpo *)t->sa->spacedata.first;
+               //SpaceIpo *sipo = (SpaceIpo *)t->sa->spacedata.first;
                WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
        }
        else if (t->spacetype == SPACE_NLA) {
@@ -526,6 +554,10 @@ static void viewRedrawPost(bContext *C, TransInfo *t)
                /* if autokeying is enabled, send notifiers that keyframes were added */
                if (IS_AUTOKEY_ON(t->scene))
                        WM_main_add_notifier(NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
+
+               /* redraw UV editor */
+               if (t->mode == TFM_EDGE_SLIDE && (t->settings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT))
+                       WM_event_add_notifier(C, NC_GEOM | ND_DATA, NULL);
                
                /* XXX temp, first hack to get auto-render in compositor work (ton) */
                WM_event_add_notifier(C, NC_SCENE | ND_TRANSFORM_DONE, CTX_data_scene(C));
@@ -681,6 +713,9 @@ static void view_editmove(unsigned short UNUSED(event))
 #define TFM_MODAL_EDGESLIDE_UP 24
 #define TFM_MODAL_EDGESLIDE_DOWN 25
 
+/* for analog input, like trackpad */
+#define TFM_MODAL_PROPSIZE             26
+
 /* called in transform_ops.c, on each regeneration of keymaps */
 wmKeyMap *transform_modal_keymap(wmKeyConfig *keyconf)
 {
@@ -710,6 +745,7 @@ wmKeyMap *transform_modal_keymap(wmKeyConfig *keyconf)
                {TFM_MODAL_AUTOIK_LEN_DEC, "AUTOIK_CHAIN_LEN_DOWN", 0, "Decrease Max AutoIK Chain Length", ""},
                {TFM_MODAL_EDGESLIDE_UP, "EDGESLIDE_EDGE_NEXT", 0, "Select next Edge Slide Edge", ""},
                {TFM_MODAL_EDGESLIDE_DOWN, "EDGESLIDE_PREV_NEXT", 0, "Select previous Edge Slide Edge", ""},
+               {TFM_MODAL_PROPSIZE, "PROPORTIONAL_SIZE", 0, "Adjust Proportional Influence", ""},
                {0, NULL, 0, NULL, NULL}
        };
        
@@ -745,6 +781,7 @@ wmKeyMap *transform_modal_keymap(wmKeyConfig *keyconf)
        WM_modalkeymap_add_item(keymap, PAGEDOWNKEY, KM_PRESS, 0, 0, TFM_MODAL_PROPSIZE_DOWN);
        WM_modalkeymap_add_item(keymap, WHEELDOWNMOUSE, KM_PRESS, 0, 0, TFM_MODAL_PROPSIZE_UP);
        WM_modalkeymap_add_item(keymap, WHEELUPMOUSE, KM_PRESS, 0, 0, TFM_MODAL_PROPSIZE_DOWN);
+       WM_modalkeymap_add_item(keymap, MOUSEPAN, 0, 0, 0, TFM_MODAL_PROPSIZE);
 
        WM_modalkeymap_add_item(keymap, WHEELDOWNMOUSE, KM_PRESS, KM_ALT, 0, TFM_MODAL_EDGESLIDE_UP);
        WM_modalkeymap_add_item(keymap, WHEELUPMOUSE, KM_PRESS, KM_ALT, 0, TFM_MODAL_EDGESLIDE_DOWN);
@@ -762,22 +799,29 @@ static void transform_event_xyz_constraint(TransInfo *t, short key_type, char cm
        if (!(t->flag & T_NO_CONSTRAINT)) {
                int constraint_axis, constraint_plane;
                int edit_2d = (t->flag & T_2D_EDIT);
-               char msg1[] = "along _";
-               char msg2[] = "along %s _";
-               char msg3[] = "locking %s _";
+               const char *msg1 = "", *msg2 = "", *msg3 = "";
                char axis;
        
                /* Initialize */
                switch (key_type) {
                        case XKEY:
+                               msg1 = IFACE_("along X");
+                               msg2 = IFACE_("along %s X");
+                               msg3 = IFACE_("locking %s X");
                                axis = 'X';
                                constraint_axis = CON_AXIS0;
                                break;
                        case YKEY:
+                               msg1 = IFACE_("along Y");
+                               msg2 = IFACE_("along %s Y");
+                               msg3 = IFACE_("locking %s Y");
                                axis = 'Y';
                                constraint_axis = CON_AXIS1;
                                break;
                        case ZKEY:
+                               msg1 = IFACE_("along Z");
+                               msg2 = IFACE_("along %s Z");
+                               msg3 = IFACE_("locking %s Z");
                                axis = 'Z';
                                constraint_axis = CON_AXIS2;
                                break;
@@ -785,9 +829,6 @@ static void transform_event_xyz_constraint(TransInfo *t, short key_type, char cm
                                /* Invalid key */
                                return;
                }
-               msg1[sizeof(msg1) - 2] = axis;
-               msg2[sizeof(msg2) - 2] = axis;
-               msg3[sizeof(msg3) - 2] = axis;
                constraint_plane = ((CON_AXIS0 | CON_AXIS1 | CON_AXIS2) & (~constraint_axis));
 
                if (edit_2d && (key_type != ZKEY)) {
@@ -862,19 +903,56 @@ int transformEvent(TransInfo *t, wmEvent *event)
                                break;
                        case TFM_MODAL_TRANSLATE:
                                /* only switch when... */
-                               if (ELEM3(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL) ) {
+                               if (ELEM5(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL, TFM_EDGE_SLIDE, TFM_VERT_SLIDE)) {
+                                       if (t->mode == TFM_EDGE_SLIDE) {
+                                               freeEdgeSlideVerts(t);
+                                       }
+                                       else if (t->mode == TFM_VERT_SLIDE) {
+                                               freeVertSlideVerts(t);
+                                       }
                                        resetTransRestrictions(t);
                                        restoreTransObjects(t);
                                        initTranslation(t);
                                        initSnapping(t, NULL); // need to reinit after mode change
                                        t->redraw |= TREDRAW_HARD;
+                                       WM_event_add_mousemove(t->context);
                                }
-                               else if (t->mode == TFM_TRANSLATION) {
-                                       if (t->options & (CTX_MOVIECLIP | CTX_MASK)) {
-                                               restoreTransObjects(t);
+                               else if (t->mode == TFM_SEQ_SLIDE) {
+                                       t->flag ^= T_ALT_TRANSFORM;
+                                       t->redraw |= TREDRAW_HARD;
+                               }
+                               else {
+                                       if (t->obedit && t->obedit->type == OB_MESH) {
+                                               if ((t->mode == TFM_TRANSLATION) && (t->spacetype == SPACE_VIEW3D)) {
+                                                       resetTransRestrictions(t);
+                                                       restoreTransObjects(t);
 
-                                               t->flag ^= T_ALT_TRANSFORM;
-                                               t->redraw |= TREDRAW_HARD;
+                                                       /* first try edge slide */
+                                                       initEdgeSlide(t);
+                                                       /* if that fails, do vertex slide */
+                                                       if (t->state == TRANS_CANCEL) {
+                                                               t->state = TRANS_STARTING;
+                                                               initVertSlide(t);
+                                                       }
+                                                       /* vert slide can fail on unconnected vertices (rare but possible) */
+                                                       if (t->state == TRANS_CANCEL) {
+                                                               t->state = TRANS_STARTING;
+                                                               resetTransRestrictions(t);
+                                                               restoreTransObjects(t);
+                                                               initTranslation(t);
+                                                       }
+                                                       initSnapping(t, NULL); // need to reinit after mode change
+                                                       t->redraw |= TREDRAW_HARD;
+                                                       WM_event_add_mousemove(t->context);
+                                               }
+                                       }
+                                       else if (t->options & (CTX_MOVIECLIP | CTX_MASK)) {
+                                               if (t->mode == TFM_TRANSLATION) {
+                                                       restoreTransObjects(t);
+
+                                                       t->flag ^= T_ALT_TRANSFORM;
+                                                       t->redraw |= TREDRAW_HARD;
+                                               }
                                        }
                                }
                                break;
@@ -907,6 +985,10 @@ int transformEvent(TransInfo *t, wmEvent *event)
                                        initSnapping(t, NULL); // need to reinit after mode change
                                        t->redraw |= TREDRAW_HARD;
                                }
+                               else if (t->mode == TFM_SHRINKFATTEN) {
+                                       t->flag ^= T_ALT_TRANSFORM;
+                                       t->redraw |= TREDRAW_HARD;
+                               }
                                else if (t->mode == TFM_RESIZE) {
                                        if (t->options & CTX_MOVIECLIP) {
                                                restoreTransObjects(t);
@@ -936,10 +1018,10 @@ int transformEvent(TransInfo *t, wmEvent *event)
                                        }
                                        else {
                                                if (t->flag & T_2D_EDIT) {
-                                                       setUserConstraint(t, V3D_MANIP_GLOBAL, (CON_AXIS0), "along X");
+                                                       setUserConstraint(t, V3D_MANIP_GLOBAL, (CON_AXIS0), IFACE_("along X"));
                                                }
                                                else {
-                                                       setUserConstraint(t, t->current_orientation, (CON_AXIS0), "along %s X");
+                                                       setUserConstraint(t, t->current_orientation, (CON_AXIS0), IFACE_("along %s X"));
                                                }
                                        }
                                        t->redraw |= TREDRAW_HARD;
@@ -952,10 +1034,10 @@ int transformEvent(TransInfo *t, wmEvent *event)
                                        }
                                        else {
                                                if (t->flag & T_2D_EDIT) {
-                                                       setUserConstraint(t, V3D_MANIP_GLOBAL, (CON_AXIS1), "along Y");
+                                                       setUserConstraint(t, V3D_MANIP_GLOBAL, (CON_AXIS1), IFACE_("along Y"));
                                                }
                                                else {
-                                                       setUserConstraint(t, t->current_orientation, (CON_AXIS1), "along %s Y");
+                                                       setUserConstraint(t, t->current_orientation, (CON_AXIS1), IFACE_("along %s Y"));
                                                }
                                        }
                                        t->redraw |= TREDRAW_HARD;
@@ -967,7 +1049,7 @@ int transformEvent(TransInfo *t, wmEvent *event)
                                                stopConstraint(t);
                                        }
                                        else {
-                                               setUserConstraint(t, t->current_orientation, (CON_AXIS2), "along %s Z");
+                                               setUserConstraint(t, t->current_orientation, (CON_AXIS2), IFACE_("along %s Z"));
                                        }
                                        t->redraw |= TREDRAW_HARD;
                                }
@@ -978,7 +1060,7 @@ int transformEvent(TransInfo *t, wmEvent *event)
                                                stopConstraint(t);
                                        }
                                        else {
-                                               setUserConstraint(t, t->current_orientation, (CON_AXIS1 | CON_AXIS2), "locking %s X");
+                                               setUserConstraint(t, t->current_orientation, (CON_AXIS1 | CON_AXIS2), IFACE_("locking %s X"));
                                        }
                                        t->redraw |= TREDRAW_HARD;
                                }
@@ -989,7 +1071,7 @@ int transformEvent(TransInfo *t, wmEvent *event)
                                                stopConstraint(t);
                                        }
                                        else {
-                                               setUserConstraint(t, t->current_orientation, (CON_AXIS0 | CON_AXIS2), "locking %s Y");
+                                               setUserConstraint(t, t->current_orientation, (CON_AXIS0 | CON_AXIS2), IFACE_("locking %s Y"));
                                        }
                                        t->redraw |= TREDRAW_HARD;
                                }
@@ -1000,7 +1082,7 @@ int transformEvent(TransInfo *t, wmEvent *event)
                                                stopConstraint(t);
                                        }
                                        else {
-                                               setUserConstraint(t, t->current_orientation, (CON_AXIS0 | CON_AXIS1), "locking %s Z");
+                                               setUserConstraint(t, t->current_orientation, (CON_AXIS0 | CON_AXIS1), IFACE_("locking %s Z"));
                                        }
                                        t->redraw |= TREDRAW_HARD;
                                }
@@ -1019,6 +1101,19 @@ int transformEvent(TransInfo *t, wmEvent *event)
                                removeSnapPoint(t);
                                t->redraw |= TREDRAW_HARD;
                                break;
+                               
+                       case TFM_MODAL_PROPSIZE:
+                               /* MOUSEPAN usage... */
+                               if (t->flag & T_PROP_EDIT) {
+                                       float fac = 1.0f + 0.005f *(event->y - event->prevy);
+                                       t->prop_size *= fac;
+                                       if (t->spacetype == SPACE_VIEW3D && t->persp != RV3D_ORTHO)
+                                               t->prop_size = min_ff(t->prop_size, ((View3D *)t->view)->far);
+                                       calculatePropRatio(t);
+                               }
+                               t->redraw |= TREDRAW_HARD;
+                               break;
+                               
                        case TFM_MODAL_PROPSIZE_UP:
                                if (t->flag & T_PROP_EDIT) {
                                        t->prop_size *= 1.1f;
@@ -1092,7 +1187,7 @@ int transformEvent(TransInfo *t, wmEvent *event)
                                        /* exception for switching to dolly, or trackball, in camera view */
                                        if (t->flag & T_CAMERA) {
                                                if (t->mode == TFM_TRANSLATION)
-                                                       setLocalConstraint(t, (CON_AXIS2), "along local Z");
+                                                       setLocalConstraint(t, (CON_AXIS2), IFACE_("along local Z"));
                                                else if (t->mode == TFM_ROTATION) {
                                                        restoreTransObjects(t);
                                                        initTrackball(t);
@@ -1203,7 +1298,9 @@ int transformEvent(TransInfo *t, wmEvent *event)
                                if (t->flag & T_AUTOIK) {
                                        transform_autoik_update(t, 1);
                                }
-                               else view_editmove(event->type);
+                               else {
+                                       view_editmove(event->type);
+                               }
                                t->redraw = 1;
                                break;
                        case PADMINUS:
@@ -1218,8 +1315,18 @@ int transformEvent(TransInfo *t, wmEvent *event)
                                if (t->flag & T_AUTOIK) {
                                        transform_autoik_update(t, -1);
                                }
-                               else view_editmove(event->type);
+                               else {
+                                       view_editmove(event->type);
+                               }
                                t->redraw = 1;
+                               break;
+                       case LEFTALTKEY:
+                       case RIGHTALTKEY:
+                               if (ELEM(t->spacetype, SPACE_SEQ, SPACE_VIEW3D)) {
+                                       t->flag |= T_ALT_TRANSFORM;
+                                       t->redraw |= TREDRAW_HARD;
+                               }
+
                                break;
                        default:
                                handled = 0;
@@ -1254,6 +1361,14 @@ int transformEvent(TransInfo *t, wmEvent *event)
 ////                   if (t->options & CTX_TWEAK)
 //                             t->state = TRANS_CONFIRM;
 //                     break;
+                       case LEFTALTKEY:
+                       case RIGHTALTKEY:
+                               if (ELEM(t->spacetype, SPACE_SEQ, SPACE_VIEW3D)) {
+                                       t->flag &= ~T_ALT_TRANSFORM;
+                                       t->redraw |= TREDRAW_HARD;
+                               }
+
+                               break;
                        default:
                                handled = 0;
                                break;
@@ -1267,6 +1382,8 @@ int transformEvent(TransInfo *t, wmEvent *event)
                        }
                }
        }
+       else
+               handled = 0;
 
        // Per transform event, if present
        if (t->handleEvent)
@@ -1438,7 +1555,7 @@ static void drawHelpline(bContext *UNUSED(C), int x, int y, void *customdata)
                        if (ob) mul_m4_v3(ob->obmat, vecrot);
                }
 
-               projectFloatView(t, vecrot, cent);  // no overflow in extreme cases
+               projectFloatViewEx(t, vecrot, cent, V3D_PROJ_TEST_CLIP_ZERO);
 
                glPushMatrix();
 
@@ -1477,7 +1594,6 @@ static void drawHelpline(bContext *UNUSED(C), int x, int y, void *customdata)
                                glTranslatef(mval[0], mval[1], 0);
 
                                glLineWidth(3.0);
-                               glBegin(GL_LINES);
                                drawArrow(UP, 5, 10, 5);
                                drawArrow(DOWN, 5, 10, 5);
                                glLineWidth(1.0);
@@ -1557,26 +1673,36 @@ static void drawTransformView(const struct bContext *C, ARegion *UNUSED(ar), voi
        drawConstraint(t);
        drawPropCircle(C, t);
        drawSnapping(C, t);
-       drawNonPropEdge(C, t);
+
+       /* edge slide, vert slide */
+       drawEdgeSlide(C, t);
+       drawVertSlide(C, t);
 }
 
 /* just draw a little warning message in the top-right corner of the viewport to warn that autokeying is enabled */
 static void drawAutoKeyWarning(TransInfo *UNUSED(t), ARegion *ar)
 {
-       const char printable[] = "Auto Keying On";
+       rcti rect;
+       const char *printable = IFACE_("Auto Keying On");
        float      printable_size[2];
        int xco, yco;
 
+       ED_region_visible_rect(ar, &rect);
+       
        BLF_width_and_height_default(printable, &printable_size[0], &printable_size[1]);
        
-       xco = ar->winx - (int)printable_size[0] - 10;
-       yco = ar->winy - (int)printable_size[1] - 10;
+       xco = rect.xmax - (int)printable_size[0] - 10;
+       yco = rect.ymax - (int)printable_size[1] - 10;
        
        /* warning text (to clarify meaning of overlays)
         * - original color was red to match the icon, but that clashes badly with a less nasty border
         */
        UI_ThemeColorShade(TH_TEXT_HI, -50);
+#ifdef WITH_INTERNATIONAL
+       BLF_draw_default(xco, ar->winy - 17, 0.0f, printable, sizeof(printable));
+#else
        BLF_draw_default_ascii(xco, ar->winy - 17, 0.0f, printable, sizeof(printable));
+#endif
        
        /* autokey recording icon... */
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
@@ -1601,8 +1727,10 @@ static void drawTransformPixel(const struct bContext *UNUSED(C), ARegion *ar, vo
         */
        if ((U.autokey_flag & AUTOKEY_FLAG_NOWARNING) == 0) {
                if (ar == t->ar) {
-                       if (ob && autokeyframe_cfra_can_key(scene, &ob->id)) {
-                               drawAutoKeyWarning(t, ar);
+                       if (t->flag & (T_OBJECT | T_POSE)) {
+                               if (ob && autokeyframe_cfra_can_key(scene, &ob->id)) {
+                                       drawAutoKeyWarning(t, ar);
+                               }
                        }
                }
        }
@@ -1831,6 +1959,8 @@ int initTransform(bContext *C, TransInfo *t, wmOperator *op, wmEvent *event, int
 
        }
 
+       t->keymap = WM_keymap_active(CTX_wm_manager(C), op->type->modalkeymap);
+
        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) */
@@ -1901,6 +2031,9 @@ int initTransform(bContext *C, TransInfo *t, wmOperator *op, wmEvent *event, int
                case TFM_EDGE_SLIDE:
                        initEdgeSlide(t);
                        break;
+               case TFM_VERT_SLIDE:
+                       initVertSlide(t);
+                       break;
                case TFM_BONE_ROLL:
                        initBoneRoll(t);
                        break;
@@ -2032,12 +2165,6 @@ void transformApply(bContext *C, TransInfo *t)
                t->state = TRANS_CONFIRM;
        }
 
-       if (BKE_ptcache_get_continue_physics()) {
-               // TRANSFORM_FIX_ME
-               //do_screenhandlers(G.curscreen);
-               t->redraw |= TREDRAW_HARD;
-       }
-
        t->context = NULL;
 }
 
@@ -2230,8 +2357,8 @@ static void protectedQuaternionBits(short protectflag, float *quat, float *oldqu
 static void constraintTransLim(TransInfo *t, TransData *td)
 {
        if (td->con) {
-               bConstraintTypeInfo *ctiLoc = get_constraint_typeinfo(CONSTRAINT_TYPE_LOCLIMIT);
-               bConstraintTypeInfo *ctiDist = get_constraint_typeinfo(CONSTRAINT_TYPE_DISTLIMIT);
+               bConstraintTypeInfo *ctiLoc = BKE_get_constraint_typeinfo(CONSTRAINT_TYPE_LOCLIMIT);
+               bConstraintTypeInfo *ctiDist = BKE_get_constraint_typeinfo(CONSTRAINT_TYPE_DISTLIMIT);
                
                bConstraintOb cob = {NULL};
                bConstraint *con;
@@ -2250,7 +2377,7 @@ static void constraintTransLim(TransInfo *t, TransData *td)
                        ListBase targets = {NULL, NULL};
                        
                        /* only consider constraint if enabled */
-                       if (con->flag & CONSTRAINT_DISABLE) continue;
+                       if (con->flag & (CONSTRAINT_DISABLE | CONSTRAINT_OFF)) continue;
                        if (con->enforce == 0.0f) continue;
                        
                        /* only use it if it's tagged for this purpose (and the right type) */
@@ -2281,7 +2408,7 @@ static void constraintTransLim(TransInfo *t, TransData *td)
                                }
                                
                                /* get constraint targets if needed */
-                               get_constraint_targets_for_solving(con, &cob, &targets, ctime);
+                               BKE_get_constraint_targets_for_solving(con, &cob, &targets, ctime);
                                
                                /* do constraint */
                                cti->evaluate_constraint(con, &cob, &targets);
@@ -2333,7 +2460,7 @@ static void constraintob_from_transdata(bConstraintOb *cob, TransData *td)
 static void constraintRotLim(TransInfo *UNUSED(t), TransData *td)
 {
        if (td->con) {
-               bConstraintTypeInfo *cti = get_constraint_typeinfo(CONSTRAINT_TYPE_ROTLIMIT);
+               bConstraintTypeInfo *cti = BKE_get_constraint_typeinfo(CONSTRAINT_TYPE_ROTLIMIT);
                bConstraintOb cob;
                bConstraint *con;
                int do_limit = FALSE;
@@ -2341,7 +2468,7 @@ static void constraintRotLim(TransInfo *UNUSED(t), TransData *td)
                /* Evaluate valid constraints */
                for (con = td->con; con; con = con->next) {
                        /* only consider constraint if enabled */
-                       if (con->flag & CONSTRAINT_DISABLE) continue;
+                       if (con->flag & (CONSTRAINT_DISABLE | CONSTRAINT_OFF)) continue;
                        if (con->enforce == 0.0f) continue;
 
                        /* we're only interested in Limit-Rotation constraints */
@@ -2400,9 +2527,11 @@ static void constraintRotLim(TransInfo *UNUSED(t), TransData *td)
 static void constraintSizeLim(TransInfo *t, TransData *td)
 {
        if (td->con && td->ext) {
-               bConstraintTypeInfo *cti = get_constraint_typeinfo(CONSTRAINT_TYPE_SIZELIMIT);
+               bConstraintTypeInfo *cti = BKE_get_constraint_typeinfo(CONSTRAINT_TYPE_SIZELIMIT);
                bConstraintOb cob = {NULL};
                bConstraint *con;
+               float size_sign[3], size_abs[3];
+               int i;
                
                /* Make a temporary bConstraintOb for using these limit constraints
                 *  - they only care that cob->matrix is correctly set ;-)
@@ -2416,14 +2545,20 @@ static void constraintSizeLim(TransInfo *t, TransData *td)
                        /* Reset val if SINGLESIZE but using a constraint */
                        if (td->flag & TD_SINGLESIZE)
                                return;
+
+                       /* separate out sign to apply back later */
+                       for (i = 0; i < 3; i++) {
+                               size_sign[i] = signf(td->ext->size[i]);
+                               size_abs[i] = fabsf(td->ext->size[i]);
+                       }
                        
-                       size_to_mat4(cob.matrix, td->ext->size);
+                       size_to_mat4(cob.matrix, size_abs);
                }
                
                /* Evaluate valid constraints */
                for (con = td->con; con; con = con->next) {
                        /* only consider constraint if enabled */
-                       if (con->flag & CONSTRAINT_DISABLE) continue;
+                       if (con->flag & (CONSTRAINT_DISABLE | CONSTRAINT_OFF)) continue;
                        if (con->enforce == 0.0f) continue;
                        
                        /* we're only interested in Limit-Scale constraints */
@@ -2465,7 +2600,9 @@ static void constraintSizeLim(TransInfo *t, TransData *td)
                        if (td->flag & TD_SINGLESIZE)
                                return;
 
+                       /* extrace scale from matrix and apply back sign */
                        mat4_to_size(td->ext->size, cob.matrix);
+                       mul_v3_v3(td->ext->size, size_sign);
                }
        }
 }
@@ -2545,7 +2682,8 @@ int handleEventWarp(TransInfo *t, wmEvent *event)
 int Warp(TransInfo *t, const int UNUSED(mval[2]))
 {
        TransData *td = t->data;
-       float vec[3], circumfac, dist, phi0, co, si, *curs, cursor[3], gcursor[3];
+       float vec[3], circumfac, dist, phi0, co, si, cursor[3], gcursor[3];
+       const float *curs;
        int i;
        char str[50];
        
@@ -2582,13 +2720,13 @@ int Warp(TransInfo *t, const int UNUSED(mval[2]))
                
                outputNumInput(&(t->num), c);
                
-               sprintf(str, "Warp: %s", c);
+               sprintf(str, IFACE_("Warp: %s"), c);
 
                circumfac = DEG2RADF(circumfac);
        }
        else {
                /* default header print */
-               sprintf(str, "Warp: %.3f", RAD2DEGF(circumfac));
+               sprintf(str, IFACE_("Warp: %.3f"), RAD2DEGF(circumfac));
        }
        
        t->values[0] = circumfac;
@@ -2682,6 +2820,18 @@ int handleEventShear(TransInfo *t, wmEvent *event)
 
                status = 1;
        }
+       else if (event->type == XKEY && event->val == KM_PRESS) {
+               initMouseInputMode(t, &t->mouse, INPUT_HORIZONTAL_ABSOLUTE);
+               t->customData = NULL;
+               
+               status = 1;
+       }
+       else if (event->type == YKEY && event->val == KM_PRESS) {
+               initMouseInputMode(t, &t->mouse, INPUT_VERTICAL_ABSOLUTE);
+               t->customData = (void *)1;
+               
+               status = 1;
+       }
        
        return status;
 }
@@ -2711,11 +2861,11 @@ int Shear(TransInfo *t, const int UNUSED(mval[2]))
                
                outputNumInput(&(t->num), c);
                
-               sprintf(str, "Shear: %s %s", c, t->proptext);
+               sprintf(str, IFACE_("Shear: %s %s"), c, t->proptext);
        }
        else {
                /* default header print */
-               sprintf(str, "Shear: %.3f %s", value, t->proptext);
+               sprintf(str, IFACE_("Shear: %.3f %s (Press X or Y to set shear axis)"), value, t->proptext);
        }
        
        t->values[0] = value;
@@ -2807,40 +2957,50 @@ static void headerResize(TransInfo *t, float vec[3], char *str)
        if (t->con.mode & CON_APPLY) {
                switch (t->num.idx_max) {
                        case 0:
-                               spos += sprintf(spos, "Scale: %s%s %s", &tvec[0], t->con.text, t->proptext);
+                               spos += sprintf(spos, IFACE_("Scale: %s%s %s"), &tvec[0], t->con.text, t->proptext);
                                break;
                        case 1:
-                               spos += sprintf(spos, "Scale: %s : %s%s %s", &tvec[0], &tvec[NUM_STR_REP_LEN],
+                               spos += sprintf(spos, IFACE_("Scale: %s : %s%s %s"), &tvec[0], &tvec[NUM_STR_REP_LEN],
                                                t->con.text, t->proptext);
                                break;
                        case 2:
-                               spos += sprintf(spos, "Scale: %s : %s : %s%s %s", &tvec[0], &tvec[NUM_STR_REP_LEN],
+                               spos += sprintf(spos, IFACE_("Scale: %s : %s : %s%s %s"), &tvec[0], &tvec[NUM_STR_REP_LEN],
                                                &tvec[NUM_STR_REP_LEN * 2], t->con.text, t->proptext);
                }
        }
        else {
                if (t->flag & T_2D_EDIT) {
-                       spos += sprintf(spos, "Scale X: %s   Y: %s%s %s", &tvec[0], &tvec[NUM_STR_REP_LEN],
+                       spos += sprintf(spos, IFACE_("Scale X: %s   Y: %s%s %s"), &tvec[0], &tvec[NUM_STR_REP_LEN],
                                        t->con.text, t->proptext);
                }
                else {
-                       spos += sprintf(spos, "Scale X: %s   Y: %s  Z: %s%s %s", &tvec[0], &tvec[NUM_STR_REP_LEN],
+                       spos += sprintf(spos, IFACE_("Scale X: %s   Y: %s  Z: %s%s %s"), &tvec[0], &tvec[NUM_STR_REP_LEN],
                                        &tvec[NUM_STR_REP_LEN * 2], t->con.text, t->proptext);
                }
        }
        
        if (t->flag & (T_PROP_EDIT | T_PROP_CONNECTED)) {
-               spos += sprintf(spos, " Proportional size: %.2f", t->prop_size);
+               spos += sprintf(spos, IFACE_(" Proportional size: %.2f"), t->prop_size);
        }
 
        (void)spos;
 }
 
-#define SIGN(a)     (a<-FLT_EPSILON ? 1 : a>FLT_EPSILON ? 2 : 3)
-#define VECSIGNFLIP(a, b) ((SIGN(a[0]) & SIGN(b[0])) == 0 || (SIGN(a[1]) & SIGN(b[1])) == 0 || (SIGN(a[2]) & SIGN(b[2])) == 0)
+/* FLT_EPSILON is too small [#29633], 0.0000001f starts to flip */
+#define TX_FLIP_EPS 0.00001f
+BLI_INLINE int tx_sign(const float a)
+{
+       return (a < -TX_FLIP_EPS ? 1 : a > TX_FLIP_EPS ? 2 : 3);
+}
+BLI_INLINE int tx_vec_sign_flip(const float a[3], const float b[3])
+{
+       return ((tx_sign(a[0]) & tx_sign(b[0])) == 0 ||
+               (tx_sign(a[1]) & tx_sign(b[1])) == 0 ||
+               (tx_sign(a[2]) & tx_sign(b[2])) == 0);
+}
 
 /* smat is reference matrix, only scaled */
-static void TransMat3ToSize(float mat[][3], float smat[][3], float *size)
+static void TransMat3ToSize(float mat[3][3], float smat[3][3], float size[3])
 {
        float vec[3];
        
@@ -2852,9 +3012,9 @@ static void TransMat3ToSize(float mat[][3], float smat[][3], float *size)
        size[2] = normalize_v3(vec);
        
        /* first tried with dotproduct... but the sign flip is crucial */
-       if (VECSIGNFLIP(mat[0], smat[0]) ) size[0] = -size[0];
-       if (VECSIGNFLIP(mat[1], smat[1]) ) size[1] = -size[1];
-       if (VECSIGNFLIP(mat[2], smat[2]) ) size[2] = -size[2];
+       if (tx_vec_sign_flip(mat[0], smat[0]) ) size[0] = -size[0];
+       if (tx_vec_sign_flip(mat[1], smat[1]) ) size[1] = -size[1];
+       if (tx_vec_sign_flip(mat[2], smat[2]) ) size[2] = -size[2];
 }
 
 
@@ -2876,12 +3036,7 @@ static void ElementResize(TransInfo *t, TransData *td, float mat[3][3])
        }
        
        /* local constraint shouldn't alter center */
-       if ((t->around == V3D_LOCAL) &&
-           (   (t->flag & (T_OBJECT | T_POSE)) ||
-               ((t->flag & T_EDIT) && (t->settings->selectmode & (SCE_SELECT_EDGE | SCE_SELECT_FACE))) ||
-               (t->obedit && t->obedit->type == OB_ARMATURE))
-           )
-       {
+       if (transdata_check_local_center(t)) {
                copy_v3_v3(center, td->center);
        }
        else if (t->options & CTX_MOVIECLIP) {
@@ -3184,11 +3339,11 @@ int ToSphere(TransInfo *t, const int UNUSED(mval[2]))
                
                outputNumInput(&(t->num), c);
                
-               sprintf(str, "To Sphere: %s %s", c, t->proptext);
+               sprintf(str, IFACE_("To Sphere: %s %s"), c, t->proptext);
        }
        else {
                /* default header print */
-               sprintf(str, "To Sphere: %.4f %s", ratio, t->proptext);
+               sprintf(str, IFACE_("To Sphere: %.4f %s"), ratio, t->proptext);
        }
        
        
@@ -3258,20 +3413,16 @@ static void ElementRotation(TransInfo *t, TransData *td, float mat[3][3], short
 {
        float vec[3], totmat[3][3], smat[3][3];
        float eul[3], fmat[3][3], quat[4];
-       float *center = t->center;
+       const float *center;
 
        /* local constraint shouldn't alter center */
-       if (around == V3D_LOCAL) {
-               if (    (t->flag & (T_OBJECT | T_POSE)) ||
-                       (t->settings->selectmode & (SCE_SELECT_EDGE | SCE_SELECT_FACE)) ||
-                       (t->obedit && t->obedit->type == OB_ARMATURE))
-               {
-                       center = td->center;
-               }
-
-               if (t->options & CTX_MOVIECLIP) {
-                       center = td->center;
-               }
+       if (transdata_check_local_center(t) ||
+           ((around == V3D_LOCAL) && (t->options & CTX_MOVIECLIP)))
+       {
+               center = td->center;
+       }
+       else {
+               center = t->center;
        }
 
        if (t->flag & T_POINTS) {
@@ -3532,17 +3683,17 @@ int Rotation(TransInfo *t, const int UNUSED(mval[2]))
                
                outputNumInput(&(t->num), c);
                
-               spos += sprintf(spos, "Rot: %s %s %s", &c[0], t->con.text, t->proptext);
+               spos += sprintf(spos, IFACE_("Rot: %s %s %s"), &c[0], t->con.text, t->proptext);
 
                /* Clamp between -180 and 180 */
                final = angle_wrap_rad(DEG2RADF(final));
        }
        else {
-               spos += sprintf(spos, "Rot: %.2f%s %s", RAD2DEGF(final), t->con.text, t->proptext);
+               spos += sprintf(spos, IFACE_("Rot: %.2f%s %s"), RAD2DEGF(final), t->con.text, t->proptext);
        }
        
        if (t->flag & (T_PROP_EDIT | T_PROP_CONNECTED)) {
-               spos += sprintf(spos, " Proportional size: %.2f", t->prop_size);
+               spos += sprintf(spos, IFACE_(" Proportional size: %.2f"), t->prop_size);
        }
        (void)spos;
 
@@ -3631,17 +3782,17 @@ int Trackball(TransInfo *t, const int UNUSED(mval[2]))
 
                outputNumInput(&(t->num), c);
 
-               spos += sprintf(spos, "Trackball: %s %s %s", &c[0], &c[NUM_STR_REP_LEN], t->proptext);
+               spos += sprintf(spos, IFACE_("Trackball: %s %s %s"), &c[0], &c[NUM_STR_REP_LEN], t->proptext);
 
                phi[0] = DEG2RADF(phi[0]);
                phi[1] = DEG2RADF(phi[1]);
        }
        else {
-               spos += sprintf(spos, "Trackball: %.2f %.2f %s", RAD2DEGF(phi[0]), RAD2DEGF(phi[1]), t->proptext);
+               spos += sprintf(spos, IFACE_("Trackball: %.2f %.2f %s"), RAD2DEGF(phi[0]), RAD2DEGF(phi[1]), t->proptext);
        }
 
        if (t->flag & (T_PROP_EDIT | T_PROP_CONNECTED)) {
-               spos += sprintf(spos, " Proportional size: %.2f", t->prop_size);
+               spos += sprintf(spos, IFACE_(" Proportional size: %.2f"), t->prop_size);
        }
        (void)spos;
 
@@ -3752,7 +3903,7 @@ static void headerTranslation(TransInfo *t, float vec[3], char *str)
                short chainlen = t->settings->autoik_chainlen;
 
                if (chainlen)
-                       sprintf(autoik, "AutoIK-Len: %d", chainlen);
+                       sprintf(autoik, IFACE_("AutoIK-Len: %d"), chainlen);
                else
                        autoik[0] = '\0';
        }
@@ -3785,7 +3936,7 @@ static void headerTranslation(TransInfo *t, float vec[3], char *str)
        }
        
        if (t->flag & (T_PROP_EDIT | T_PROP_CONNECTED)) {
-               spos += sprintf(spos, " Proportional size: %.2f", t->prop_size);
+               spos += sprintf(spos, IFACE_(" Proportional size: %.2f"), t->prop_size);
        }
        (void)spos;
 }
@@ -3931,13 +4082,12 @@ void initShrinkFatten(TransInfo *t)
 }
 
 
-
 int ShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
 {
-       float vec[3];
        float distance;
        int i;
-       char str[64];
+       char str[128];
+       char *str_p;
        TransData *td = t->data;
 
        distance = -t->values[0];
@@ -3947,32 +4097,51 @@ int ShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
        applyNumInput(&t->num, &distance);
 
        /* header print for NumInput */
+       str_p = str;
+       str_p += BLI_snprintf(str_p, sizeof(str), IFACE_("Shrink/Fatten:"));
        if (hasNumInput(&t->num)) {
                char c[NUM_STR_REP_LEN];
-
                outputNumInput(&(t->num), c);
-
-               sprintf(str, "Shrink/Fatten: %s %s", c, t->proptext);
+               str_p += BLI_snprintf(str_p, sizeof(str) - (str_p - str), " %s", c);
        }
        else {
                /* default header print */
-               sprintf(str, "Shrink/Fatten: %.4f %s", distance, t->proptext);
+               str_p += BLI_snprintf(str_p, sizeof(str) - (str_p - str), " %.4f", distance);
+       }
+
+       if (t->proptext[0]) {
+               str_p += BLI_snprintf(str_p, sizeof(str) - (str_p - str), " %s", t->proptext);
+       }
+       str_p += BLI_snprintf(str_p, sizeof(str) - (str_p - str), ", (");
+
+       {
+               wmKeyMapItem *kmi = WM_modalkeymap_find_propvalue(t->keymap, TFM_MODAL_RESIZE);
+               if (kmi) {
+                       str_p += WM_keymap_item_to_string(kmi, str_p, sizeof(str) - (str_p - str));
+               }
        }
+       str_p += BLI_snprintf(str_p, sizeof(str) - (str_p - str), IFACE_(" or Alt) Even Thickness %s"),
+                             (t->flag & T_ALT_TRANSFORM) ? IFACE_("ON") : IFACE_("OFF"));
+       /* done with header string */
+
 
        t->values[0] = -distance;
 
        for (i = 0; i < t->total; i++, td++) {
+               float tdistance;  /* temp dist */
                if (td->flag & TD_NOACTION)
                        break;
 
                if (td->flag & TD_SKIP)
                        continue;
 
-               copy_v3_v3(vec, td->axismtx[2]);
-               mul_v3_fl(vec, distance);
-               mul_v3_fl(vec, td->factor);
+               /* get the final offset */
+               tdistance = distance * td->factor;
+               if (td->ext && (t->flag & T_ALT_TRANSFORM)) {
+                       tdistance *= td->ext->isize[0];  /* shell factor */
+               }
 
-               add_v3_v3v3(td->loc, td->iloc, vec);
+               madd_v3_v3v3fl(td->loc, td->iloc, td->axismtx[2], tdistance);
        }
 
        recalcData(t);
@@ -4023,7 +4192,7 @@ int Tilt(TransInfo *t, const int UNUSED(mval[2]))
 
                outputNumInput(&(t->num), c);
 
-               sprintf(str, "Tilt: %s° %s", &c[0], t->proptext);
+               sprintf(str, IFACE_("Tilt: %s° %s"), &c[0], t->proptext);
 
                final = DEG2RADF(final);
 
@@ -4031,7 +4200,7 @@ int Tilt(TransInfo *t, const int UNUSED(mval[2]))
                t->values[0] = final;
        }
        else {
-               sprintf(str, "Tilt: %.2f° %s", RAD2DEGF(final), t->proptext);
+               sprintf(str, IFACE_("Tilt: %.2f° %s"), RAD2DEGF(final), t->proptext);
        }
 
        for (i = 0; i < t->total; i++, td++) {
@@ -4095,10 +4264,10 @@ int CurveShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
                char c[NUM_STR_REP_LEN];
 
                outputNumInput(&(t->num), c);
-               sprintf(str, "Shrink/Fatten: %s", c);
+               sprintf(str, IFACE_("Shrink/Fatten: %s"), c);
        }
        else {
-               sprintf(str, "Shrink/Fatten: %3f", ratio);
+               sprintf(str, IFACE_("Shrink/Fatten: %3f"), ratio);
        }
 
        for (i = 0; i < t->total; i++, td++) {
@@ -4163,10 +4332,10 @@ int MaskShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
                char c[NUM_STR_REP_LEN];
 
                outputNumInput(&(t->num), c);
-               sprintf(str, "Feather Shrink/Fatten: %s", c);
+               sprintf(str, IFACE_("Feather Shrink/Fatten: %s"), c);
        }
        else {
-               sprintf(str, "Feather Shrink/Fatten: %3f", ratio);
+               sprintf(str, IFACE_("Feather Shrink/Fatten: %3f"), ratio);
        }
 
        /* detect if no points have feather yet */
@@ -4251,11 +4420,11 @@ int PushPull(TransInfo *t, const int UNUSED(mval[2]))
 
                outputNumInput(&(t->num), c);
 
-               sprintf(str, "Push/Pull: %s%s %s", c, t->con.text, t->proptext);
+               sprintf(str, IFACE_("Push/Pull: %s%s %s"), c, t->con.text, t->proptext);
        }
        else {
                /* default header print */
-               sprintf(str, "Push/Pull: %.4f%s %s", distance, t->con.text, t->proptext);
+               sprintf(str, IFACE_("Push/Pull: %.4f%s %s"), distance, t->con.text, t->proptext);
        }
 
        t->values[0] = distance;
@@ -4372,7 +4541,7 @@ int Bevel(TransInfo *t, const int UNUSED(mval[2]))
        const char *mode;
        TransData *td = t->data;
 
-       mode = (G.editBMesh->options & BME_BEVEL_VERT) ? "verts only" : "normal";
+       mode = (G.editBMesh->options & BME_BEVEL_VERT) ? IFACE_("verts only") : IFACE_("normal");
        distance = t->values[0] / 4; /* 4 just seemed a nice value to me, nothing special */
 
        distance = fabs(distance);
@@ -4387,11 +4556,11 @@ int Bevel(TransInfo *t, const int UNUSED(mval[2]))
 
                outputNumInput(&(t->num), c);
 
-               sprintf(str, "Bevel - Dist: %s, Mode: %s (MMB to toggle))", c, mode);
+               sprintf(str, IFACE_("Bevel - Dist: %s, Mode: %s (MMB to toggle))"), c, mode);
        }
        else {
                /* default header print */
-               sprintf(str, "Bevel - Dist: %.4f, Mode: %s (MMB to toggle))", distance, mode);
+               sprintf(str, IFACE_("Bevel - Dist: %.4f, Mode: %s (MMB to toggle))"), distance, mode);
        }
 
        if (distance < 0) distance = -distance;
@@ -4455,16 +4624,16 @@ int BevelWeight(TransInfo *t, const int UNUSED(mval[2]))
                outputNumInput(&(t->num), c);
 
                if (weight >= 0.0f)
-                       sprintf(str, "Bevel Weight: +%s %s", c, t->proptext);
+                       sprintf(str, IFACE_("Bevel Weight: +%s %s"), c, t->proptext);
                else
-                       sprintf(str, "Bevel Weight: %s %s", c, t->proptext);
+                       sprintf(str, IFACE_("Bevel Weight: %s %s"), c, t->proptext);
        }
        else {
                /* default header print */
                if (weight >= 0.0f)
-                       sprintf(str, "Bevel Weight: +%.3f %s", weight, t->proptext);
+                       sprintf(str, IFACE_("Bevel Weight: +%.3f %s"), weight, t->proptext);
                else
-                       sprintf(str, "Bevel Weight: %.3f %s", weight, t->proptext);
+                       sprintf(str, IFACE_("Bevel Weight: %.3f %s"), weight, t->proptext);
        }
 
        for (i = 0; i < t->total; i++, td++) {
@@ -4528,16 +4697,16 @@ int Crease(TransInfo *t, const int UNUSED(mval[2]))
                outputNumInput(&(t->num), c);
 
                if (crease >= 0.0f)
-                       sprintf(str, "Crease: +%s %s", c, t->proptext);
+                       sprintf(str, IFACE_("Crease: +%s %s"), c, t->proptext);
                else
-                       sprintf(str, "Crease: %s %s", c, t->proptext);
+                       sprintf(str, IFACE_("Crease: %s %s"), c, t->proptext);
        }
        else {
                /* default header print */
                if (crease >= 0.0f)
-                       sprintf(str, "Crease: +%.3f %s", crease, t->proptext);
+                       sprintf(str, IFACE_("Crease: +%.3f %s"), crease, t->proptext);
                else
-                       sprintf(str, "Crease: %.3f %s", crease, t->proptext);
+                       sprintf(str, IFACE_("Crease: %.3f %s"), crease, t->proptext);
        }
 
        for (i = 0; i < t->total; i++, td++) {
@@ -4596,14 +4765,14 @@ static void headerBoneSize(TransInfo *t, float vec[3], char *str)
        /* hmm... perhaps the y-axis values don't need to be shown? */
        if (t->con.mode & CON_APPLY) {
                if (t->num.idx_max == 0)
-                       sprintf(str, "ScaleB: %s%s %s", &tvec[0], t->con.text, t->proptext);
+                       sprintf(str, IFACE_("ScaleB: %s%s %s"), &tvec[0], t->con.text, t->proptext);
                else
-                       sprintf(str, "ScaleB: %s : %s : %s%s %s", &tvec[0], &tvec[NUM_STR_REP_LEN], &tvec[NUM_STR_REP_LEN * 2],
-                               t->con.text, t->proptext);
+                       sprintf(str, IFACE_("ScaleB: %s : %s : %s%s %s"), &tvec[0], &tvec[NUM_STR_REP_LEN],
+                               &tvec[NUM_STR_REP_LEN * 2], t->con.text, t->proptext);
        }
        else {
-               sprintf(str, "ScaleB X: %s  Y: %s  Z: %s%s %s", &tvec[0], &tvec[NUM_STR_REP_LEN], &tvec[NUM_STR_REP_LEN * 2],
-                       t->con.text, t->proptext);
+               sprintf(str, IFACE_("ScaleB X: %s  Y: %s  Z: %s%s %s"), &tvec[0], &tvec[NUM_STR_REP_LEN],
+                       &tvec[NUM_STR_REP_LEN * 2], t->con.text, t->proptext);
        }
 }
 
@@ -4719,10 +4888,10 @@ int BoneEnvelope(TransInfo *t, const int UNUSED(mval[2]))
                char c[NUM_STR_REP_LEN];
                
                outputNumInput(&(t->num), c);
-               sprintf(str, "Envelope: %s", c);
+               sprintf(str, IFACE_("Envelope: %s"), c);
        }
        else {
-               sprintf(str, "Envelope: %3f", ratio);
+               sprintf(str, IFACE_("Envelope: %3f"), ratio);
        }
        
        for (i = 0; i < t->total; i++, td++) {
@@ -4752,102 +4921,200 @@ int BoneEnvelope(TransInfo *t, const int UNUSED(mval[2]))
 static BMEdge *get_other_edge(BMVert *v, BMEdge *e)
 {
        BMIter iter;
-       BMEdge *e2;
+       BMEdge *e_iter;
 
-       BM_ITER_ELEM (e2, &iter, v, BM_EDGES_OF_VERT) {
-               if (BM_elem_flag_test(e2, BM_ELEM_SELECT) && e2 != e)
-                       return e2;
+       BM_ITER_ELEM (e_iter, &iter, v, BM_EDGES_OF_VERT) {
+               if (BM_elem_flag_test(e_iter, BM_ELEM_SELECT) && e_iter != e) {
+                       return e_iter;
+               }
        }
 
        return NULL;
 }
 
+static void len_v3_ensure(float v[3], const float length)
+{
+       normalize_v3(v);
+       mul_v3_fl(v, length);
+}
+
+/**
+ * Find the closest point on the ngon on the opposite side.
+ * used to set the edge slide distance for ngons.
+ */
+static bool bm_loop_calc_opposite_co(BMLoop *l_tmp,
+                                     const float plane_no[3],
+                                     float r_co[3])
+{
+       /* skip adjacent edges */
+       BMLoop *l_first = l_tmp->next;
+       BMLoop *l_last  = l_tmp->prev;
+       BMLoop *l_iter;
+       float dist = FLT_MAX;
+
+       l_iter = l_first;
+       do {
+               float tvec[3];
+               if (isect_line_plane_v3(tvec,
+                                       l_iter->v->co, l_iter->next->v->co,
+                                       l_tmp->v->co, plane_no, false))
+               {
+                       const float fac = line_point_factor_v3(tvec, l_iter->v->co, l_iter->next->v->co);
+                       /* allow some overlap to avoid missing the intersection because of float precision */
+                       if ((fac > -FLT_EPSILON) && (fac < 1.0f + FLT_EPSILON)) {
+                               /* likelyhood of multiple intersections per ngon is quite low,
+                                * it would have to loop back on its self, but better support it
+                                * so check for the closest opposite edge */
+                               const float tdist = len_v3v3(l_tmp->v->co, tvec);
+                               if (tdist < dist) {
+                                       copy_v3_v3(r_co, tvec);
+                                       dist = tdist;
+                               }
+                       }
+               }
+       } while ((l_iter = l_iter->next) != l_last);
+
+       return (dist != FLT_MAX);
+}
+
+/**
+ * Given 2 edges and a loop, step over the loops
+ * and calculate a direction to slide along.
+ *
+ * \param r_slide_vec the direction to slide,
+ * the length of the vector defines the slide distance.
+ */
 static BMLoop *get_next_loop(BMVert *v, BMLoop *l,
-                             BMEdge *olde, BMEdge *nexte, float vec[3])
+                             BMEdge *e_prev, BMEdge *e_next, float r_slide_vec[3])
 {
-       BMLoop *firstl;
-       float a[3] = {0.0f, 0.0f, 0.0f}, n[3] = {0.0f, 0.0f, 0.0f};
+       BMLoop *l_first;
+       float vec_accum[3] = {0.0f, 0.0f, 0.0f};
+       float vec_accum_len = 0.0f;
        int i = 0;
 
-       firstl = l;
+       BLI_assert(BM_edge_share_vert(e_prev, e_next) == v);
+
+       l_first = l;
        do {
                l = BM_face_other_edge_loop(l->f, l->e, v);
                if (l->radial_next == l)
                        return NULL;
                
-               if (l->e == nexte) {
+               if (l->e == e_next) {
                        if (i) {
-                               mul_v3_fl(a, 1.0f / (float)i);
+                               len_v3_ensure(vec_accum, vec_accum_len / (float)i);
                        }
                        else {
-                               float f1[3], f2[3], f3[3];
+                               /* When there is no edge to slide along,
+                                * we must slide along the vector defined by the face we're attach to */
+                               BMLoop *l_tmp = BM_face_vert_share_loop(l_first->f, v);
+
+                               BLI_assert(ELEM(l_tmp->e, e_prev, e_next) && ELEM(l_tmp->prev->e, e_prev, e_next));
 
-                               sub_v3_v3v3(f1, BM_edge_other_vert(olde, v)->co, v->co);
-                               sub_v3_v3v3(f2, BM_edge_other_vert(nexte, v)->co, v->co);
+                               if (l_tmp->f->len == 4) {
+                                       /* we could use code below, but in this case
+                                        * sliding diagonally across the quad works well */
+                                       sub_v3_v3v3(vec_accum, l_tmp->next->next->v->co, v->co);
+                               }
+                               else {
+                                       float tdir[3];
+                                       BM_loop_calc_face_direction(l_tmp, tdir);
+                                       cross_v3_v3v3(vec_accum, l_tmp->f->no, tdir);
+#if 0
+                                       /* rough guess, we can  do better! */
+                                       len_v3_ensure(vec_accum, (BM_edge_calc_length(e_prev) + BM_edge_calc_length(e_next)) / 2.0f);
+#else
+                                       /* be clever, check the opposite ngon edge to slide into.
+                                        * this gives best results */
+                                       {
+                                               float tvec[3];
+                                               float dist;
 
-                               cross_v3_v3v3(f3, f1, l->f->no);
-                               cross_v3_v3v3(a, f2, l->f->no);
-                               mul_v3_fl(a, -1.0f);
+                                               if (bm_loop_calc_opposite_co(l_tmp, tdir, tvec)) {
+                                                       dist = len_v3v3(l_tmp->v->co, tvec);
+                                               }
+                                               else {
+                                                       dist = (BM_edge_calc_length(e_prev) + BM_edge_calc_length(e_next)) / 2.0f;
+                                               }
 
-                               add_v3_v3(a, f3);
-                               mul_v3_fl(a, 0.5f);
+                                               len_v3_ensure(vec_accum, dist);
+                                       }
+#endif
+                               }
                        }
-                       
-                       copy_v3_v3(vec, a);
+
+                       copy_v3_v3(r_slide_vec, vec_accum);
                        return l;
                }
                else {
-                       sub_v3_v3v3(n, BM_edge_other_vert(l->e, v)->co, v->co);
-                       add_v3_v3v3(a, a, n);
+                       /* accumulate the normalized edge vector,
+                        * normalize so some edges don't skew the result */
+                       float tvec[3];
+                       sub_v3_v3v3(tvec, BM_edge_other_vert(l->e, v)->co, v->co);
+                       vec_accum_len += normalize_v3(tvec);
+                       add_v3_v3(vec_accum, tvec);
                        i += 1;
                }
 
-               if (BM_face_other_edge_loop(l->f, l->e, v)->e == nexte) {
-                       if (i)
-                               mul_v3_fl(a, 1.0f / (float)i);
-                       
-                       copy_v3_v3(vec, a);
+               if (BM_face_other_edge_loop(l->f, l->e, v)->e == e_next) {
+                       if (i) {
+                               len_v3_ensure(vec_accum, vec_accum_len / (float)i);
+                       }
+
+                       copy_v3_v3(r_slide_vec, vec_accum);
                        return BM_face_other_edge_loop(l->f, l->e, v);
                }
                
+               BLI_assert(l != l->radial_next);
                l = l->radial_next;
-       } while (l != firstl);
+       } while (l != l_first);
 
-       if (i)
-               mul_v3_fl(a, 1.0f / (float)i);
+       if (i) {
+               len_v3_ensure(vec_accum, vec_accum_len / (float)i);
+       }
        
-       copy_v3_v3(vec, a);
+       copy_v3_v3(r_slide_vec, vec_accum);
        
        return NULL;
 }
 
-static void calcNonProportionalEdgeSlide(TransInfo *t, SlideData *sld, const float mval[2])
+static void calcNonProportionalEdgeSlide(TransInfo *t, EdgeSlideData *sld, const float mval[2])
 {
-       TransDataSlideVert *sv = sld->sv;
+       TransDataEdgeSlideVert *sv = sld->sv;
 
        if (sld->totsv > 0) {
+               ARegion *ar = t->ar;
+               RegionView3D *rv3d = NULL;
+               float projectMat[4][4];
+
                int i = 0;
 
-               float v_proj[3];
+               float v_proj[2];
                float dist = 0;
                float min_dist = FLT_MAX;
 
-               float up_p[3];
-               float dw_p[3];
+               if (t->spacetype == SPACE_VIEW3D) {
+                       /* background mode support */
+                       rv3d = t->ar ? t->ar->regiondata : NULL;
+               }
+
+               if (!rv3d) {
+                       /* ok, let's try to survive this */
+                       unit_m4(projectMat);
+               }
+               else {
+                       ED_view3d_ob_project_mat_get(rv3d, t->obedit, projectMat);
+               }
 
                for (i = 0; i < sld->totsv; i++, sv++) {
                        /* Set length */
-                       add_v3_v3v3(up_p, sv->origvert.co, sv->upvec);
-                       add_v3_v3v3(dw_p, sv->origvert.co, sv->downvec);
-                       sv->edge_len = len_v3v3(dw_p, up_p);
-
-                       mul_v3_m4v3(v_proj, t->obedit->obmat, sv->v->co);
-                       if (ED_view3d_project_float_global(t->ar, v_proj, v_proj, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) {
-                               dist = len_squared_v2v2(mval, v_proj);
-                               if (dist < min_dist) {
-                                       min_dist = dist;
-                                       sld->curr_sv_index = i;
-                               }
+                       sv->edge_len = len_v3v3(sv->upvec, sv->downvec);
+
+                       ED_view3d_project_float_v2_m4(ar, sv->v->co, v_proj, projectMat);
+                       dist = len_squared_v2v2(mval, v_proj);
+                       if (dist < min_dist) {
+                               min_dist = dist;
+                               sld->curr_sv_index = i;
                        }
                }
        }
@@ -4856,17 +5123,18 @@ static void calcNonProportionalEdgeSlide(TransInfo *t, SlideData *sld, const flo
        }
 }
 
-static int createSlideVerts(TransInfo *t)
+static int createEdgeSlideVerts(TransInfo *t)
 {
        BMEditMesh *em = BMEdit_FromObject(t->obedit);
        BMesh *bm = em->bm;
        BMIter iter;
        BMEdge *e, *e1;
-       BMVert *v, *v2, *first;
-       TransDataSlideVert *sv_array;
-       BMBVHTree *btree = BMBVH_NewBVH(em, BMBVH_RESPECT_HIDDEN, NULL, NULL);
+       BMVert *v, *v2;
+       TransDataEdgeSlideVert *sv_array;
+       int sv_tot;
+       BMBVHTree *btree;
        SmallHash table;
-       SlideData *sld = MEM_callocN(sizeof(*sld), "sld");
+       EdgeSlideData *sld = MEM_callocN(sizeof(*sld), "sld");
        View3D *v3d = NULL;
        RegionView3D *rv3d = NULL;
        ARegion *ar = t->ar;
@@ -4876,6 +5144,7 @@ static int createSlideVerts(TransInfo *t)
        float vec[3], vec2[3] /*, lastvec[3], size, dis=0.0, z */ /* UNUSED */;
        float dir[3], maxdist, (*loop_dir)[3], *loop_maxdist;
        int numsel, i, j, loop_nr, l_nr;
+       int use_btree_disp;
 
        if (t->spacetype == SPACE_VIEW3D) {
                /* background mode support */
@@ -4883,6 +5152,15 @@ static int createSlideVerts(TransInfo *t)
                rv3d = t->ar ? t->ar->regiondata : NULL;
        }
 
+       use_btree_disp = (v3d && t->obedit->dt > OB_WIRE && v3d->drawtype > OB_WIRE);
+
+       if (use_btree_disp) {
+               btree = BMBVH_NewBVH(em, BMBVH_RESPECT_HIDDEN, NULL, NULL);
+       }
+       else {
+               btree = NULL;
+       }
+
        sld->is_proportional = TRUE;
        sld->curr_sv_index = 0;
        sld->flipped_vtx = FALSE;
@@ -4916,7 +5194,8 @@ static int createSlideVerts(TransInfo *t)
 
                        if (numsel == 0 || numsel > 2) {
                                MEM_freeN(sld);
-                               BMBVH_FreeBVH(btree);
+                               if (btree)
+                                       BMBVH_FreeBVH(btree);
                                return 0; /* invalid edge selection */
                        }
                }
@@ -4926,7 +5205,8 @@ static int createSlideVerts(TransInfo *t)
                if (BM_elem_flag_test(e, BM_ELEM_SELECT)) {
                        if (!BM_edge_is_manifold(e)) {
                                MEM_freeN(sld);
-                               BMBVH_FreeBVH(btree);
+                               if (btree)
+                                       BMBVH_FreeBVH(btree);
                                return 0; /* can only handle exactly 2 faces around each edge */
                        }
                }
@@ -4946,16 +5226,18 @@ static int createSlideVerts(TransInfo *t)
 
        if (!j) {
                MEM_freeN(sld);
-               BMBVH_FreeBVH(btree);
+               if (btree)
+                       BMBVH_FreeBVH(btree);
                return 0;
        }
 
-       sv_array = MEM_callocN(sizeof(TransDataSlideVert) * j, "sv_array");
+       sv_tot = j;
+       sv_array = MEM_callocN(sizeof(TransDataEdgeSlideVert) * sv_tot, "sv_array");
        loop_nr = 0;
 
-       j = 0;
        while (1) {
                BMLoop *l, *l1, *l2;
+               BMVert *v_first;
 
                v = NULL;
                BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
@@ -4970,7 +5252,7 @@ static int createSlideVerts(TransInfo *t)
                if (!v->e)
                        continue;
                
-               first = v;
+               v_first = v;
 
                /*walk along the edge loop*/
                e = v->e;
@@ -4990,7 +5272,7 @@ static int createSlideVerts(TransInfo *t)
                                break;
 
                        v = BM_edge_other_vert(e, v);
-               } while (e != first->e);
+               } while (e != v_first->e);
 
                BM_elem_flag_disable(v, BM_ELEM_TAG);
 
@@ -5010,10 +5292,13 @@ static int createSlideVerts(TransInfo *t)
                }
 
                /*iterate over the loop*/
-               first = v;
+               v_first = v;
                do {
-                       TransDataSlideVert *sv = sv_array + j;
+                       TransDataEdgeSlideVert *sv;
 
+                       /* XXX, 'sv' will initialize multiple times, this is suspicious. see [#34024] */
+                       BLI_assert(BLI_smallhash_haskey(&table, (uintptr_t)v) != false);
+                       sv = sv_array + GET_INT_FROM_POINTER(BLI_smallhash_lookup(&table, (uintptr_t)v));
                        sv->v = v;
                        sv->origvert = *v;
                        sv->loop_nr = loop_nr;
@@ -5035,9 +5320,8 @@ static int createSlideVerts(TransInfo *t)
                        e1 = e;
                        e = get_other_edge(v, e);
                        if (!e) {
-                               //v2=v, v = BM_edge_other_vert(l1->e, v);
-
-                               sv = sv_array + j + 1;
+                               BLI_assert(BLI_smallhash_haskey(&table, (uintptr_t)v) != false);
+                               sv = sv_array + GET_INT_FROM_POINTER(BLI_smallhash_lookup(&table, (uintptr_t)v));
                                sv->v = v;
                                sv->origvert = *v;
                                sv->loop_nr = loop_nr;
@@ -5054,19 +5338,22 @@ static int createSlideVerts(TransInfo *t)
 
                                BM_elem_flag_disable(v, BM_ELEM_TAG);
                                BM_elem_flag_disable(v2, BM_ELEM_TAG);
-                               
-                               j += 2;
+
                                break;
                        }
 
                        l1 = get_next_loop(v, l1, e1, e, vec);
                        l2 = l2 ? get_next_loop(v, l2, e1, e, vec2) : NULL;
 
-                       j += 1;
+                       if (UNLIKELY(l1 == NULL && l2 != NULL)) {
+                               l1 = l2;
+                               l2 = NULL;
+                               swap_v3_v3(vec, vec2);
+                       }
 
                        BM_elem_flag_disable(v, BM_ELEM_TAG);
                        BM_elem_flag_disable(v2, BM_ELEM_TAG);
-               } while (e != first->e && l1);
+               } while (e != v_first->e && l1);
 
                loop_nr++;
        }
@@ -5074,7 +5361,7 @@ static int createSlideVerts(TransInfo *t)
        /* EDBM_flag_disable_all(em, BM_ELEM_SELECT); */
 
        sld->sv = sv_array;
-       sld->totsv = j;
+       sld->totsv = sv_tot;
        
        /* find mouse vectors, the global one, and one per loop in case we have
         * multiple loops selected, in case they are oriented different */
@@ -5101,12 +5388,11 @@ static int createSlideVerts(TransInfo *t)
                                                continue;
 
                                        /* This test is only relevant if object is not wire-drawn! See [#32068]. */
-                                       if (v3d && t->obedit->dt > OB_WIRE && v3d->drawtype > OB_WIRE &&
-                                           !BMBVH_EdgeVisible(btree, e2, ar, v3d, t->obedit))
-                                       {
+                                       if (use_btree_disp && !BMBVH_EdgeVisible(btree, e2, ar, v3d, t->obedit)) {
                                                continue;
                                        }
 
+                                       BLI_assert(BLI_smallhash_haskey(&table, (uintptr_t)v) != false);
                                        j = GET_INT_FROM_POINTER(BLI_smallhash_lookup(&table, (uintptr_t)v));
 
                                        if (sv_array[j].down) {
@@ -5177,14 +5463,14 @@ static int createSlideVerts(TransInfo *t)
                if (dot_v3v3(loop_dir[l_nr], dir) < 0.0f) {
                        swap_v3_v3(sv_array->upvec, sv_array->downvec);
                        SWAP(BMVert, sv_array->vup, sv_array->vdown);
-                       SWAP(BMVert*, sv_array->up, sv_array->down);
+                       SWAP(BMVert *, sv_array->up, sv_array->down);
                }
        }
 
        if (rv3d)
                calcNonProportionalEdgeSlide(t, sld, mval);
 
-       sld->origfaces_init = TRUE;
+       sld->origfaces_init = true;
        sld->em = em;
        
        /*zero out start*/
@@ -5205,17 +5491,22 @@ static int createSlideVerts(TransInfo *t)
        t->customData = sld;
        
        BLI_smallhash_release(&table);
-       BMBVH_FreeBVH(btree);
+       if (btree) {
+               BMBVH_FreeBVH(btree);
+       }
        MEM_freeN(loop_dir);
        MEM_freeN(loop_maxdist);
-       
+
+       /* arrays are dirty from copying faces: EDBM_index_arrays_free */
+       EDBM_update_generic(em, FALSE, TRUE);
+
        return 1;
 }
 
-void projectSVData(TransInfo *t, int final)
+void projectEdgeSlideData(TransInfo *t, bool is_final)
 {
-       SlideData *sld = t->customData;
-       TransDataSlideVert *sv;
+       EdgeSlideData *sld = t->customData;
+       TransDataEdgeSlideVert *sv;
        BMEditMesh *em = sld->em;
        SmallHash visit;
        int i;
@@ -5334,7 +5625,7 @@ void projectSVData(TransInfo *t, int final)
                                        }
 
                                }
-                               
+
                                if (!affected)
                                        continue;
 
@@ -5342,7 +5633,7 @@ void projectSVData(TransInfo *t, int final)
                                 * and we do not want to mess up other shape keys */
                                BM_loop_interp_from_face(em->bm, l, f_copy_flip, FALSE, FALSE);
 
-                               if (final) {
+                               if (is_final) {
                                        BM_loop_interp_multires(em->bm, l, f_copy_flip);
                                        if (f_copy != f_copy_flip) {
                                                BM_loop_interp_multires(em->bm, l, f_copy);
@@ -5366,7 +5657,7 @@ void projectSVData(TransInfo *t, int final)
        BLI_smallhash_release(&visit);
 }
 
-void freeSlideTempFaces(SlideData *sld)
+void freeEdgeSlideTempFaces(EdgeSlideData *sld)
 {
        if (sld->origfaces_init) {
                SmallHashIter hiter;
@@ -5379,18 +5670,21 @@ void freeSlideTempFaces(SlideData *sld)
 
                BLI_smallhash_release(&sld->origfaces);
 
-               sld->origfaces_init = FALSE;
+               sld->origfaces_init = false;
+
+               /* arrays are dirty from removing faces: EDBM_index_arrays_free */
+               EDBM_update_generic(sld->em, FALSE, TRUE);
        }
 }
 
 
-void freeSlideVerts(TransInfo *t)
+void freeEdgeSlideVerts(TransInfo *t)
 {
-       SlideData *sld = t->customData;
+       EdgeSlideData *sld = t->customData;
        
 #if 0 /*BMESH_TODO*/
        if (me->drawflag & ME_DRAWEXTRA_EDGELEN) {
-               TransDataSlideVert *sv;
+               TransDataEdgeSlideVert *sv;
                LinkNode *look = sld->vertlist;
                GHash *vertgh = sld->vhash;
                while (look) {
@@ -5407,7 +5701,7 @@ void freeSlideVerts(TransInfo *t)
        if (!sld)
                return;
        
-       freeSlideTempFaces(sld);
+       freeEdgeSlideTempFaces(sld);
 
        bmesh_edit_end(sld->em->bm, BMO_OP_FLAG_UNTAN_MULTIRES);
 
@@ -5423,13 +5717,13 @@ void freeSlideVerts(TransInfo *t)
 
 void initEdgeSlide(TransInfo *t)
 {
-       SlideData *sld;
+       EdgeSlideData *sld;
 
        t->mode = TFM_EDGE_SLIDE;
        t->transform = EdgeSlide;
        t->handleEvent = handleEventEdgeSlide;
 
-       if (!createSlideVerts(t)) {
+       if (!createEdgeSlideVerts(t)) {
                t->state = TRANS_CANCEL;
                return;
        }
@@ -5439,11 +5733,11 @@ void initEdgeSlide(TransInfo *t)
        if (!sld)
                return;
 
-       t->customFree = freeSlideVerts;
+       t->customFree = freeEdgeSlideVerts;
 
        /* set custom point first if you want value to be initialized by init */
        setCustomPoints(t, &t->mouse, sld->end, sld->start);
-       initMouseInputMode(t, &t->mouse, INPUT_CUSTOM_RATIO);
+       initMouseInputMode(t, &t->mouse, INPUT_CUSTOM_RATIO_FLIP);
        
        t->idx_max = 0;
        t->num.idx_max = 0;
@@ -5459,7 +5753,7 @@ void initEdgeSlide(TransInfo *t)
 int handleEventEdgeSlide(struct TransInfo *t, struct wmEvent *event)
 {
        if (t->mode == TFM_EDGE_SLIDE) {
-               SlideData *sld = t->customData;
+               EdgeSlideData *sld = t->customData;
 
                if (sld) {
                        switch (event->type) {
@@ -5502,18 +5796,18 @@ int handleEventEdgeSlide(struct TransInfo *t, struct wmEvent *event)
        return 0;
 }
 
-void drawNonPropEdge(const struct bContext *C, TransInfo *t)
+void drawEdgeSlide(const struct bContext *C, TransInfo *t)
 {
        if (t->mode == TFM_EDGE_SLIDE) {
-               SlideData *sld = (SlideData *)t->customData;
+               EdgeSlideData *sld = (EdgeSlideData *)t->customData;
                /* Non-Prop mode */
                if (sld && sld->is_proportional == FALSE) {
                        View3D *v3d = CTX_wm_view3d(C);
                        float marker[3];
                        float v1[3], v2[3];
                        float interp_v;
-                       TransDataSlideVert *curr_sv = &sld->sv[sld->curr_sv_index];
-                       const float ctrl_size = UI_GetThemeValuef(TH_FACEDOT_SIZE) + 1.5;
+                       TransDataEdgeSlideVert *curr_sv = &sld->sv[sld->curr_sv_index];
+                       const float ctrl_size = UI_GetThemeValuef(TH_FACEDOT_SIZE) + 1.5f;
                        const float guide_size = ctrl_size - 0.5f;
                        const float line_size = UI_GetThemeValuef(TH_OUTLINE_WIDTH) + 0.5f;
                        const int alpha_shade = -30;
@@ -5578,9 +5872,8 @@ void drawNonPropEdge(const struct bContext *C, TransInfo *t)
 
 static int doEdgeSlide(TransInfo *t, float perc)
 {
-       SlideData *sld = t->customData;
-       TransDataSlideVert *svlist = sld->sv, *sv;
-       float vec[3];
+       EdgeSlideData *sld = t->customData;
+       TransDataEdgeSlideVert *svlist = sld->sv, *sv;
        int i;
 
        sld->perc = perc;
@@ -5588,6 +5881,7 @@ static int doEdgeSlide(TransInfo *t, float perc)
 
        if (sld->is_proportional == TRUE) {
                for (i = 0; i < sld->totsv; i++, sv++) {
+                       float vec[3];
                        if (perc > 0.0f) {
                                copy_v3_v3(vec, sv->upvec);
                                mul_v3_fl(vec, perc);
@@ -5605,25 +5899,34 @@ static int doEdgeSlide(TransInfo *t, float perc)
                 * Implementation note, non proportional mode ignores the starting positions and uses only the
                 * up/down verts, this could be changed/improved so the distance is still met but the verts are moved along
                 * their original path (which may not be straight), however how it works now is OK and matches 2.4x - Campbell
+                *
+                * \note len_v3v3(curr_sv->upvec, curr_sv->downvec)
+                * is the same as the distance between the original vert locations, same goes for the lines below.
                 */
-               TransDataSlideVert *curr_sv = &sld->sv[sld->curr_sv_index];
-               const float curr_length_perc = len_v3v3(curr_sv->up->co, curr_sv->down->co) *
-                                              (((sld->flipped_vtx ? perc : -perc) + 1.0f) / 2.0f);
+               TransDataEdgeSlideVert *curr_sv = &sld->sv[sld->curr_sv_index];
+               const float curr_length_perc = curr_sv->edge_len * (((sld->flipped_vtx ? perc : -perc) + 1.0f) / 2.0f);
+
+               float down_co[3];
+               float up_co[3];
 
                for (i = 0; i < sld->totsv; i++, sv++) {
-                       const float sv_length = len_v3v3(sv->up->co, sv->down->co);
-                       const float fac = min_ff(sv_length, curr_length_perc) / sv_length;
+                       if (sv->edge_len > FLT_EPSILON) {
+                               const float fac = min_ff(sv->edge_len, curr_length_perc) / sv->edge_len;
 
-                       if (sld->flipped_vtx) {
-                               interp_v3_v3v3(sv->v->co, sv->down->co, sv->up->co, fac);
-                       }
-                       else {
-                               interp_v3_v3v3(sv->v->co, sv->up->co, sv->down->co, fac);
+                               add_v3_v3v3(up_co, sv->origvert.co, sv->upvec);
+                               add_v3_v3v3(down_co, sv->origvert.co, sv->downvec);
+
+                               if (sld->flipped_vtx) {
+                                       interp_v3_v3v3(sv->v->co, down_co, up_co, fac);
+                               }
+                               else {
+                                       interp_v3_v3v3(sv->v->co, up_co, down_co, fac);
+                               }
                        }
                }
        }
        
-       projectSVData(t, 0);
+       projectEdgeSlideData(t, 0);
        
        return 1;
 }
@@ -5632,9 +5935,9 @@ int EdgeSlide(TransInfo *t, const int UNUSED(mval[2]))
 {
        char str[128];
        float final;
-       SlideData *sld =  t->customData;
-       int flipped = sld->flipped_vtx;
-       int is_proportional = sld->is_proportional;
+       EdgeSlideData *sld =  t->customData;
+       bool flipped = sld->flipped_vtx;
+       bool is_proportional = sld->is_proportional;
 
        final = t->values[0];
 
@@ -5650,12 +5953,12 @@ int EdgeSlide(TransInfo *t, const int UNUSED(mval[2]))
 
                outputNumInput(&(t->num), c);
 
-               BLI_snprintf(str, sizeof(str), "Edge Slide: %s (E)ven: %s, (F)lipped: %s",
-                            &c[0], !is_proportional ? "ON" : "OFF", flipped ? "ON" : "OFF");
+               BLI_snprintf(str, sizeof(str), IFACE_("Edge Slide: %s (E)ven: %s, (F)lipped: %s"),
+                            &c[0], !is_proportional ? IFACE_("ON") : IFACE_("OFF"), flipped ? IFACE_("ON") : IFACE_("OFF"));
        }
        else {
-               BLI_snprintf(str, sizeof(str), "Edge Slide: %.2f (E)ven: %s, (F)lipped: %s",
-                            final, !is_proportional ? "ON" : "OFF", flipped ? "ON" : "OFF");
+               BLI_snprintf(str, sizeof(str), IFACE_("Edge Slide: %.4f (E)ven: %s, (F)lipped: %s"),
+                            final, !is_proportional ? IFACE_("ON") : IFACE_("OFF"), flipped ? IFACE_("ON") : IFACE_("OFF"));
        }
 
        CLAMP(final, -1.0f, 1.0f);
@@ -5666,7 +5969,7 @@ int EdgeSlide(TransInfo *t, const int UNUSED(mval[2]))
        if (t->customData)
                doEdgeSlide(t, final);
        else {
-               strcpy(str, "Invalid Edge Selection");
+               strcpy(str, IFACE_("Invalid Edge Selection"));
                t->state = TRANS_CANCEL;
        }
 
@@ -5677,37 +5980,552 @@ int EdgeSlide(TransInfo *t, const int UNUSED(mval[2]))
        return 1;
 }
 
-/* ******************** EditBone roll *************** */
 
-void initBoneRoll(TransInfo *t)
+/* ******************** Vert Slide *************** */
+static void calcVertSlideCustomPoints(struct TransInfo *t)
 {
-       t->mode = TFM_BONE_ROLL;
-       t->transform = BoneRoll;
+       VertSlideData *sld = t->customData;
+       TransDataVertSlideVert *sv = &sld->sv[sld->curr_sv_index];
+       float *co_orig = sv->co_orig_2d;
+       float *co_curr = sv->co_link_orig_2d[sv->co_link_curr];
+       const int start[2] = {co_orig[0], co_orig[1]};
+       const int end[2]   = {co_curr[0], co_curr[1]};
 
-       initMouseInputMode(t, &t->mouse, INPUT_ANGLE);
+       if (sld->flipped_vtx && sld->is_proportional == false) {
+               setCustomPoints(t, &t->mouse, start, end);
+       }
+       else {
+               setCustomPoints(t, &t->mouse, end, start);
+       }
+}
 
-       t->idx_max = 0;
-       t->num.idx_max = 0;
-       t->snap[0] = 0.0f;
-       t->snap[1] = (float)((5.0 / 180) * M_PI);
-       t->snap[2] = t->snap[1] * 0.2f;
+/**
+ * Run once when initializing vert slide to find the reference edge
+ */
+static void calcVertSlideMouseActiveVert(struct TransInfo *t, const int mval[2])
+{
+       VertSlideData *sld = t->customData;
+       float mval_fl[2] = {UNPACK2(mval)};
+       TransDataVertSlideVert *sv;
 
-       t->num.increment = 1.0f;
+       /* set the vertex to use as a reference for the mouse direction 'curr_sv_index' */
+       float dist = 0.0f;
+       float min_dist = FLT_MAX;
+       int i;
 
-       t->flag |= T_NO_CONSTRAINT | T_NO_PROJECT;
+       for (i = 0, sv = sld->sv; i < sld->totsv; i++, sv++) {
+               dist = len_squared_v2v2(mval_fl, sv->co_orig_2d);
+               if (dist < min_dist) {
+                       min_dist = dist;
+                       sld->curr_sv_index = i;
+               }
+       }
 }
-
-int BoneRoll(TransInfo *t, const int UNUSED(mval[2]))
+/**
+ * Run while moving the mouse to slide along the edge matching the mouse direction
+ */
+static void calcVertSlideMouseActiveEdges(struct TransInfo *t, const int mval[2])
 {
-       TransData *td = t->data;
+       VertSlideData *sld = t->customData;
+       float mval_fl[2] = {UNPACK2(mval)};
+
+       float dir[2];
+       TransDataVertSlideVert *sv;
        int i;
-       char str[50];
 
-       float final;
+       /* first get the direction of the original vertex */
+       sub_v2_v2v2(dir, sld->sv[sld->curr_sv_index].co_orig_2d, mval_fl);
+       normalize_v2(dir);
+
+       for (i = 0, sv = sld->sv; i < sld->totsv; i++, sv++) {
+               if (sv->co_link_tot > 1) {
+                       float dir_dot_best = -FLT_MAX;
+                       int co_link_curr_best = -1;
+                       int j;
+
+                       for (j = 0; j < sv->co_link_tot; j++) {
+                               float tdir[2];
+                               float dir_dot;
+                               sub_v2_v2v2(tdir, sv->co_orig_2d, sv->co_link_orig_2d[j]);
+                               normalize_v2(tdir);
+                               dir_dot = dot_v2v2(dir, tdir);
+                               if (dir_dot > dir_dot_best) {
+                                       dir_dot_best = dir_dot;
+                                       co_link_curr_best = j;
+                               }
+                       }
 
-       final = t->values[0];
+                       if (co_link_curr_best != -1) {
+                               sv->co_link_curr = co_link_curr_best;
+                       }
+               }
+       }
+}
 
-       snapGrid(t, &final);
+static int createVertSlideVerts(TransInfo *t)
+{
+       BMEditMesh *em = BMEdit_FromObject(t->obedit);
+       BMesh *bm = em->bm;
+       BMIter iter;
+       BMIter eiter;
+       BMEdge *e;
+       BMVert *v;
+       TransDataVertSlideVert *sv_array;
+       VertSlideData *sld = MEM_callocN(sizeof(*sld), "sld");
+//     View3D *v3d = NULL;
+       RegionView3D *rv3d = NULL;
+       ARegion *ar = t->ar;
+       float projectMat[4][4];
+       int j;
+
+       if (t->spacetype == SPACE_VIEW3D) {
+               /* background mode support */
+//             v3d = t->sa ? t->sa->spacedata.first : NULL;
+               rv3d = ar ? ar->regiondata : NULL;
+       }
+
+       sld->is_proportional = true;
+       sld->curr_sv_index = 0;
+       sld->flipped_vtx = false;
+
+       if (!rv3d) {
+               /* ok, let's try to survive this */
+               unit_m4(projectMat);
+       }
+       else {
+               ED_view3d_ob_project_mat_get(rv3d, t->obedit, projectMat);
+       }
+
+       j = 0;
+       BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
+               bool ok = false;
+               if (BM_elem_flag_test(v, BM_ELEM_SELECT) && v->e) {
+                       BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
+                               if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN)) {
+                                       ok = true;
+                                       break;
+                               }
+                       }
+               }
+
+               if (ok) {
+                       BM_elem_flag_enable(v, BM_ELEM_TAG);
+                       j += 1;
+               }
+               else {
+                       BM_elem_flag_disable(v, BM_ELEM_TAG);
+               }
+       }
+
+       if (!j) {
+               MEM_freeN(sld);
+               return 0;
+       }
+
+       sv_array = MEM_callocN(sizeof(TransDataVertSlideVert) * j, "sv_array");
+
+       j = 0;
+       BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
+               if (BM_elem_flag_test(v, BM_ELEM_TAG)) {
+                       int k;
+                       sv_array[j].v = v;
+                       copy_v3_v3(sv_array[j].co_orig_3d, v->co);
+
+                       k = 0;
+                       BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
+                               if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN)) {
+                                       k++;
+                               }
+                       }
+
+                       sv_array[j].co_link_orig_3d = MEM_mallocN(sizeof(*sv_array[j].co_link_orig_3d) * k, __func__);
+                       sv_array[j].co_link_orig_2d = MEM_mallocN(sizeof(*sv_array[j].co_link_orig_2d) * k, __func__);
+                       sv_array[j].co_link_tot = k;
+
+                       k = 0;
+                       BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
+                               if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN)) {
+                                       BMVert *v_other = BM_edge_other_vert(e, v);
+                                       copy_v3_v3(sv_array[j].co_link_orig_3d[k], v_other->co);
+                                       if (ar) {
+                                               ED_view3d_project_float_v2_m4(ar,
+                                                                             sv_array[j].co_link_orig_3d[k],
+                                                                             sv_array[j].co_link_orig_2d[k],
+                                                                             projectMat);
+                                       }
+                                       else {
+                                               copy_v2_v2(sv_array[j].co_link_orig_2d[k],
+                                                          sv_array[j].co_link_orig_3d[k]);
+                                       }
+                                       k++;
+                               }
+                       }
+
+                       if (ar) {
+                               ED_view3d_project_float_v2_m4(ar,
+                                                             sv_array[j].co_orig_3d,
+                                                             sv_array[j].co_orig_2d,
+                                                             projectMat);
+                       }
+                       else {
+                               copy_v2_v2(sv_array[j].co_orig_2d,
+                                          sv_array[j].co_orig_3d);
+                       }
+
+                       j++;
+               }
+       }
+
+       sld->sv = sv_array;
+       sld->totsv = j;
+
+       sld->em = em;
+
+       sld->perc = 0.0f;
+
+       t->customData = sld;
+
+       if (rv3d) {
+               calcVertSlideMouseActiveVert(t, t->mval);
+               calcVertSlideMouseActiveEdges(t, t->mval);
+       }
+
+       return 1;
+}
+
+void freeVertSlideVerts(TransInfo *t)
+{
+       VertSlideData *sld = t->customData;
+
+       if (!sld)
+               return;
+
+
+       if (sld->totsv > 0) {
+               TransDataVertSlideVert *sv = sld->sv;
+               int i = 0;
+               for (i = 0; i < sld->totsv; i++, sv++) {
+                       MEM_freeN(sv->co_link_orig_2d);
+                       MEM_freeN(sv->co_link_orig_3d);
+               }
+       }
+
+       MEM_freeN(sld->sv);
+       MEM_freeN(sld);
+
+       t->customData = NULL;
+
+       recalcData(t);
+}
+
+void initVertSlide(TransInfo *t)
+{
+       VertSlideData *sld;
+
+       t->mode = TFM_VERT_SLIDE;
+       t->transform = VertSlide;
+       t->handleEvent = handleEventVertSlide;
+
+       if (!createVertSlideVerts(t)) {
+               t->state = TRANS_CANCEL;
+               return;
+       }
+
+       sld = t->customData;
+
+       if (!sld)
+               return;
+
+       t->customFree = freeVertSlideVerts;
+
+       /* set custom point first if you want value to be initialized by init */
+       calcVertSlideCustomPoints(t);
+       initMouseInputMode(t, &t->mouse, INPUT_CUSTOM_RATIO);
+
+       t->idx_max = 0;
+       t->num.idx_max = 0;
+       t->snap[0] = 0.0f;
+       t->snap[1] = 0.1f;
+       t->snap[2] = t->snap[1] * 0.1f;
+
+       t->num.increment = t->snap[1];
+
+       t->flag |= T_NO_CONSTRAINT | T_NO_PROJECT;
+}
+
+int handleEventVertSlide(struct TransInfo *t, struct wmEvent *event)
+{
+       if (t->mode == TFM_VERT_SLIDE) {
+               VertSlideData *sld = t->customData;
+
+               if (sld) {
+                       switch (event->type) {
+                               case EKEY:
+                                       if (event->val == KM_PRESS) {
+                                               sld->is_proportional = !sld->is_proportional;
+                                               if (sld->flipped_vtx) {
+                                                       calcVertSlideCustomPoints(t);
+                                               }
+                                               return 1;
+                                       }
+                                       break;
+                               case FKEY:
+                               {
+                                       if (event->val == KM_PRESS) {
+                                               sld->flipped_vtx = !sld->flipped_vtx;
+                                               calcVertSlideCustomPoints(t);
+                                               return 1;
+                                       }
+                                       break;
+                               }
+                               case CKEY:
+                               {
+                                       /* use like a modifier key */
+                                       if (event->val == KM_PRESS) {
+                                               t->flag ^= T_ALT_TRANSFORM;
+                                               calcVertSlideCustomPoints(t);
+                                               return 1;
+                                       }
+                                       break;
+                               }
+#if 0
+                               case EVT_MODAL_MAP:
+                               {
+                                       switch (event->val) {
+                                               case TFM_MODAL_EDGESLIDE_DOWN:
+                                               {
+                                                       sld->curr_sv_index = ((sld->curr_sv_index - 1) + sld->totsv) % sld->totsv;
+                                                       break;
+                                               }
+                                               case TFM_MODAL_EDGESLIDE_UP:
+                                               {
+                                                       sld->curr_sv_index = (sld->curr_sv_index + 1) % sld->totsv;
+                                                       break;
+                                               }
+                                       }
+                               }
+#endif
+                               case MOUSEMOVE:
+                               {
+                                       /* don't recalculat the best edge */
+                                       const bool is_clamp = !(t->flag & T_ALT_TRANSFORM);
+                                       if (is_clamp) {
+                                               calcVertSlideMouseActiveEdges(t, event->mval);
+                                       }
+                                       calcVertSlideCustomPoints(t);
+                               }
+                               default:
+                                       break;
+                       }
+               }
+       }
+       return 0;
+}
+
+static void drawVertSlide(const struct bContext *C, TransInfo *t)
+{
+       if (t->mode == TFM_VERT_SLIDE) {
+               VertSlideData *sld = (VertSlideData *)t->customData;
+               /* Non-Prop mode */
+               if (sld) {
+                       View3D *v3d = CTX_wm_view3d(C);
+                       TransDataVertSlideVert *curr_sv = &sld->sv[sld->curr_sv_index];
+                       TransDataVertSlideVert *sv;
+                       const float ctrl_size = UI_GetThemeValuef(TH_FACEDOT_SIZE) + 1.5f;
+                       const float line_size = UI_GetThemeValuef(TH_OUTLINE_WIDTH) + 0.5f;
+                       const int alpha_shade = -30;
+                       const bool is_clamp = !(t->flag & T_ALT_TRANSFORM);
+                       int i;
+
+                       if (v3d && v3d->zbuf)
+                               glDisable(GL_DEPTH_TEST);
+
+                       glEnable(GL_BLEND);
+                       glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+                       glPushAttrib(GL_CURRENT_BIT | GL_LINE_BIT | GL_POINT_BIT);
+                       glPushMatrix();
+
+                       glMultMatrixf(t->obedit->obmat);
+
+                       glLineWidth(line_size);
+                       UI_ThemeColorShadeAlpha(TH_EDGE_SELECT, 80, alpha_shade);
+                       glBegin(GL_LINES);
+                       if (is_clamp) {
+                               sv = sld->sv;
+                               for (i = 0; i < sld->totsv; i++, sv++) {
+                                       glVertex3fv(sv->co_orig_3d);
+                                       glVertex3fv(sv->co_link_orig_3d[sv->co_link_curr]);
+                               }
+                       }
+                       else {
+                               sv = sld->sv;
+                               for (i = 0; i < sld->totsv; i++, sv++) {
+                                       float a[3], b[3];
+                                       sub_v3_v3v3(a, sv->co_link_orig_3d[sv->co_link_curr], sv->co_orig_3d);
+                                       mul_v3_fl(a, 100.0f);
+                                       negate_v3_v3(b, a);
+                                       add_v3_v3(a, sv->co_orig_3d);
+                                       add_v3_v3(b, sv->co_orig_3d);
+
+                                       glVertex3fv(a);
+                                       glVertex3fv(b);
+                               }
+                       }
+                       bglEnd();
+
+                       glPointSize(ctrl_size);
+
+                       bglBegin(GL_POINTS);
+                       bglVertex3fv((sld->flipped_vtx && sld->is_proportional == FALSE) ?
+                                    curr_sv->co_link_orig_3d[curr_sv->co_link_curr] :
+                                    curr_sv->co_orig_3d);
+                       bglEnd();
+
+                       glPopMatrix();
+                       glPopAttrib();
+
+                       glDisable(GL_BLEND);
+
+                       if (v3d && v3d->zbuf)
+                               glEnable(GL_DEPTH_TEST);
+               }
+       }
+}
+
+static int doVertSlide(TransInfo *t, float perc)
+{
+       VertSlideData *sld = t->customData;
+       TransDataVertSlideVert *svlist = sld->sv, *sv;
+       int i;
+
+       sld->perc = perc;
+       sv = svlist;
+
+       if (sld->is_proportional == TRUE) {
+               for (i = 0; i < sld->totsv; i++, sv++) {
+                       interp_v3_v3v3(sv->v->co, sv->co_orig_3d, sv->co_link_orig_3d[sv->co_link_curr], perc);
+               }
+       }
+       else {
+               TransDataVertSlideVert *sv_curr = &sld->sv[sld->curr_sv_index];
+               const float edge_len_curr = len_v3v3(sv_curr->co_orig_3d, sv_curr->co_link_orig_3d[sv_curr->co_link_curr]);
+               const float tperc = perc * edge_len_curr;
+
+               for (i = 0; i < sld->totsv; i++, sv++) {
+                       float edge_len;
+                       float dir[3];
+
+                       sub_v3_v3v3(dir, sv->co_link_orig_3d[sv->co_link_curr], sv->co_orig_3d);
+                       edge_len = normalize_v3(dir);
+
+                       if (edge_len > FLT_EPSILON) {
+                               if (sld->flipped_vtx) {
+                                       madd_v3_v3v3fl(sv->v->co, sv->co_link_orig_3d[sv->co_link_curr], dir, -tperc);
+                               }
+                               else {
+                                       madd_v3_v3v3fl(sv->v->co, sv->co_orig_3d, dir, tperc);
+                               }
+                       }
+                       else {
+                               copy_v3_v3(sv->v->co, sv->co_orig_3d);
+                       }
+               }
+       }
+
+       return 1;
+}
+
+int VertSlide(TransInfo *t, const int UNUSED(mval[2]))
+{
+       char str[128];
+       char *str_p;
+       float final;
+       VertSlideData *sld =  t->customData;
+       const bool flipped = sld->flipped_vtx;
+       const bool is_proportional = sld->is_proportional;
+       const bool is_clamp = !(t->flag & T_ALT_TRANSFORM);
+       const bool is_constrained = !(is_clamp == false || hasNumInput(&t->num));
+
+       final = t->values[0];
+
+       snapGrid(t, &final);
+
+       /* only do this so out of range values are not displayed */
+       if (is_constrained) {
+               CLAMP(final, 0.0f, 1.0f);
+       }
+
+       /* header string */
+       str_p = str;
+       str_p += BLI_snprintf(str_p, sizeof(str), IFACE_("Vert Slide: "));
+       if (hasNumInput(&t->num)) {
+               char c[NUM_STR_REP_LEN];
+               applyNumInput(&t->num, &final);
+               outputNumInput(&(t->num), c);
+               str_p += BLI_snprintf(str_p, sizeof(str) - (str_p - str), "%s", &c[0]);
+       }
+       else {
+               str_p += BLI_snprintf(str_p, sizeof(str) - (str_p - str), "%.4f ", final);
+       }
+       str_p += BLI_snprintf(str_p, sizeof(str) - (str_p - str), IFACE_("(E)ven: %s, "),
+                             !is_proportional ? IFACE_("ON") : IFACE_("OFF"));
+       if (!is_proportional) {
+               str_p += BLI_snprintf(str_p, sizeof(str) - (str_p - str), IFACE_("(F)lipped: %s, "),
+                                     flipped ? IFACE_("ON") : IFACE_("OFF"));
+       }
+       str_p += BLI_snprintf(str_p, sizeof(str) - (str_p - str), IFACE_("Alt or (C)lamp: %s"),
+                             is_clamp ? IFACE_("ON") : IFACE_("OFF"));
+       /* done with header string */
+
+       /*do stuff here*/
+       if (t->customData) {
+               doVertSlide(t, final);
+       }
+       else {
+               strcpy(str, IFACE_("Invalid Vert Selection"));
+               t->state = TRANS_CANCEL;
+       }
+
+       recalcData(t);
+
+       ED_area_headerprint(t->sa, str);
+
+       return 1;
+}
+
+
+/* ******************** EditBone roll *************** */
+
+void initBoneRoll(TransInfo *t)
+{
+       t->mode = TFM_BONE_ROLL;
+       t->transform = BoneRoll;
+
+       initMouseInputMode(t, &t->mouse, INPUT_ANGLE);
+
+       t->idx_max = 0;
+       t->num.idx_max = 0;
+       t->snap[0] = 0.0f;
+       t->snap[1] = (float)((5.0 / 180) * M_PI);
+       t->snap[2] = t->snap[1] * 0.2f;
+
+       t->num.increment = 1.0f;
+
+       t->flag |= T_NO_CONSTRAINT | T_NO_PROJECT;
+}
+
+int BoneRoll(TransInfo *t, const int UNUSED(mval[2]))
+{
+       TransData *td = t->data;
+       int i;
+       char str[50];
+
+       float final;
+
+       final = t->values[0];
+
+       snapGrid(t, &final);
 
        if (hasNumInput(&t->num)) {
                char c[NUM_STR_REP_LEN];
@@ -5716,12 +6534,12 @@ int BoneRoll(TransInfo *t, const int UNUSED(mval[2]))
 
                outputNumInput(&(t->num), c);
 
-               sprintf(str, "Roll: %s", &c[0]);
+               sprintf(str, IFACE_("Roll: %s"), &c[0]);
 
                final = DEG2RADF(final);
        }
        else {
-               sprintf(str, "Roll: %.2f", RAD2DEGF(final));
+               sprintf(str, IFACE_("Roll: %.2f"), RAD2DEGF(final));
        }
 
        /* set roll values */
@@ -5787,16 +6605,16 @@ int BakeTime(TransInfo *t, const int mval[2])
                outputNumInput(&(t->num), c);
 
                if (time >= 0.0f)
-                       sprintf(str, "Time: +%s %s", c, t->proptext);
+                       sprintf(str, IFACE_("Time: +%s %s"), c, t->proptext);
                else
-                       sprintf(str, "Time: %s %s", c, t->proptext);
+                       sprintf(str, IFACE_("Time: %s %s"), c, t->proptext);
        }
        else {
                /* default header print */
                if (time >= 0.0f)
-                       sprintf(str, "Time: +%.3f %s", time, t->proptext);
+                       sprintf(str, IFACE_("Time: +%.3f %s"), time, t->proptext);
                else
-                       sprintf(str, "Time: %.3f %s", time, t->proptext);
+                       sprintf(str, IFACE_("Time: %.3f %s"), time, t->proptext);
        }
 
        for (i = 0; i < t->total; i++, td++) {
@@ -5856,7 +6674,7 @@ int Mirror(TransInfo *t, const int UNUSED(mval[2]))
                        t->con.applySize(t, NULL, mat);
                }
 
-               sprintf(str, "Mirror%s", t->con.text);
+               sprintf(str, IFACE_("Mirror%s"), t->con.text);
 
                for (i = 0, td = t->data; i < t->total; i++, td++) {
                        if (td->flag & TD_NOACTION)
@@ -5890,9 +6708,9 @@ int Mirror(TransInfo *t, const int UNUSED(mval[2]))
                recalcData(t);
 
                if (t->flag & T_2D_EDIT)
-                       ED_area_headerprint(t->sa, "Select a mirror axis (X, Y)");
+                       ED_area_headerprint(t->sa, IFACE_("Select a mirror axis (X, Y)"));
                else
-                       ED_area_headerprint(t->sa, "Select a mirror axis (X, Y, Z)");
+                       ED_area_headerprint(t->sa, IFACE_("Select a mirror axis (X, Y, Z)"));
        }
 
        return 1;
@@ -5949,7 +6767,7 @@ int Align(TransInfo *t, const int UNUSED(mval[2]))
 
        recalcData(t);
 
-       ED_area_headerprint(t->sa, "Align");
+       ED_area_headerprint(t->sa, IFACE_("Align"));
 
        return 1;
 }
@@ -5973,9 +6791,10 @@ void initSeqSlide(TransInfo *t)
        t->num.increment = t->snap[1];
 }
 
-static void headerSeqSlide(TransInfo *t, float val[2], char *str)
+static void headerSeqSlide(TransInfo *t, float val[2], char *str, size_t str_len)
 {
        char tvec[NUM_STR_REP_LEN * 3];
+       char *str_p;
 
        if (hasNumInput(&t->num)) {
                outputNumInput(&(t->num), tvec);
@@ -5984,7 +6803,17 @@ static void headerSeqSlide(TransInfo *t, float val[2], char *str)
                sprintf(&tvec[0], "%.0f, %.0f", val[0], val[1]);
        }
 
-       sprintf(str, "Sequence Slide: %s%s", &tvec[0], t->con.text);
+       str_p = str;
+       str_p += BLI_snprintf(str, str_len, IFACE_("Sequence Slide: %s%s, ("), &tvec[0], t->con.text);
+
+       {
+               wmKeyMapItem *kmi = WM_modalkeymap_find_propvalue(t->keymap, TFM_MODAL_TRANSLATE);
+               if (kmi) {
+                       str_p += WM_keymap_item_to_string(kmi, str_p, str_len - (str_p - str));
+               }
+       }
+       str_p += BLI_snprintf(str_p, str_len - (str_p - str), IFACE_(" or Alt) Expand to fit %s"),
+                             (t->flag & T_ALT_TRANSFORM) ? IFACE_("ON") : IFACE_("OFF"));
 }
 
 static void applySeqSlide(TransInfo *t, float val[2])
@@ -6028,7 +6857,7 @@ int SeqSlide(TransInfo *t, const int UNUSED(mval[2]))
        t->values[0] = floor(t->values[0] + 0.5f);
        t->values[1] = floor(t->values[1] + 0.5f);
 
-       headerSeqSlide(t, t->values, str);
+       headerSeqSlide(t, t->values, str, sizeof(str));
        applySeqSlide(t, t->values);
 
        recalcData(t);
@@ -6249,7 +7078,7 @@ static void headerTimeTranslate(TransInfo *t, char *str)
                        sprintf(&tvec[0], "%.4f", val);
        }
 
-       sprintf(str, "DeltaX: %s", &tvec[0]);
+       sprintf(str, IFACE_("DeltaX: %s"), &tvec[0]);
 }
 
 static void applyTimeTranslate(TransInfo *t, float UNUSED(sval))
@@ -6390,7 +7219,7 @@ static void headerTimeSlide(TransInfo *t, float sval, char *str)
                sprintf(&tvec[0], "%.4f", val);
        }
 
-       sprintf(str, "TimeSlide: %s", &tvec[0]);
+       sprintf(str, IFACE_("TimeSlide: %s"), &tvec[0]);
 }
 
 static void applyTimeSlide(TransInfo *t, float sval)
@@ -6522,7 +7351,7 @@ static void headerTimeScale(TransInfo *t, char *str)
        else
                sprintf(&tvec[0], "%.4f", t->values[0]);
 
-       sprintf(str, "ScaleX: %s", &tvec[0]);
+       sprintf(str, IFACE_("ScaleX: %s"), &tvec[0]);
 }
 
 static void applyTimeScale(TransInfo *t)
@@ -6589,5 +7418,12 @@ int TimeScale(TransInfo *t, const int UNUSED(mval[2]))
 void BIF_TransformSetUndo(const char *UNUSED(str))
 {
        // TRANSFORM_FIX_ME
-       //Trans.undostr= str;
+       //Trans.undostr = str;
+}
+
+
+/* TODO, move to: transform_queries.c */
+bool checkUseLocalCenter_GraphEdit(TransInfo *t)
+{
+       return ((t->around == V3D_LOCAL) && !ELEM3(t->mode, TFM_TRANSLATION, TFM_TIME_TRANSLATE, TFM_TIME_SLIDE));
 }