UI: Use bool rather then int/short's where possible
[blender.git] / source / blender / editors / transform / transform.c
index a0e2b16218db9fef8952d47a8e56dace18555d82..825a8c973a253aac0656e5346ddcf2b1f397127c 100644 (file)
 #include "BLI_string.h"
 #include "BLI_ghash.h"
 #include "BLI_linklist.h"
-#include "BLI_smallhash.h"
 
 #include "BKE_nla.h"
-#include "BKE_bmesh.h"
+#include "BKE_editmesh_bvh.h"
 #include "BKE_context.h"
 #include "BKE_constraint.h"
 #include "BKE_global.h"
@@ -83,6 +82,7 @@
 #include "ED_mesh.h"
 #include "ED_clip.h"
 #include "ED_mask.h"
+#include "ED_node.h"
 
 #include "WM_types.h"
 #include "WM_api.h"
@@ -106,15 +106,105 @@ 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 void len_v3_ensure(float v[3], const float length);
+static void postInputRotation(TransInfo *t, float values[3]);
 
-static bool transdata_check_local_center(TransInfo *t)
+
+/* Transform Callbacks */
+static void initBend(TransInfo *t);
+static eRedrawFlag handleEventBend(TransInfo *t, const struct wmEvent *event);
+static void Bend(TransInfo *t, const int mval[2]);
+
+static void initShear(TransInfo *t);
+static eRedrawFlag handleEventShear(TransInfo *t, const struct wmEvent *event);
+static void applyShear(TransInfo *t, const int mval[2]);
+
+static void initResize(TransInfo *t);
+static void applyResize(TransInfo *t, const int mval[2]);
+
+static void initSkinResize(TransInfo *t);
+static void applySkinResize(TransInfo *t, const int mval[2]);
+
+static void initTranslation(TransInfo *t);
+static void applyTranslation(TransInfo *t, const int mval[2]);
+
+static void initToSphere(TransInfo *t);
+static void applyToSphere(TransInfo *t, const int mval[2]);
+
+static void initRotation(TransInfo *t);
+static void applyRotation(TransInfo *t, const int mval[2]);
+
+static void initShrinkFatten(TransInfo *t);
+static void applyShrinkFatten(TransInfo *t, const int mval[2]);
+
+static void initTilt(TransInfo *t);
+static void applyTilt(TransInfo *t, const int mval[2]);
+
+static void initCurveShrinkFatten(TransInfo *t);
+static void applyCurveShrinkFatten(TransInfo *t, const int mval[2]);
+
+static void initMaskShrinkFatten(TransInfo *t);
+static void applyMaskShrinkFatten(TransInfo *t, const int mval[2]);
+
+static void initTrackball(TransInfo *t);
+static void applyTrackball(TransInfo *t, const int mval[2]);
+
+static void initPushPull(TransInfo *t);
+static void applyPushPull(TransInfo *t, const int mval[2]);
+
+static void initBevelWeight(TransInfo *t);
+static void applyBevelWeight(TransInfo *t, const int mval[2]);
+
+static void initCrease(TransInfo *t);
+static void applyCrease(TransInfo *t, const int mval[2]);
+
+static void initBoneSize(TransInfo *t);
+static void applyBoneSize(TransInfo *t, const int mval[2]);
+
+static void initBoneEnvelope(TransInfo *t);
+static void applyBoneEnvelope(TransInfo *t, const int mval[2]);
+
+static void initBoneRoll(TransInfo *t);
+static void applyBoneRoll(TransInfo *t, const int mval[2]);
+
+static void initEdgeSlide(TransInfo *t);
+static eRedrawFlag handleEventEdgeSlide(TransInfo *t, const struct wmEvent *event);
+static void applyEdgeSlide(TransInfo *t, const int mval[2]);
+
+static void initVertSlide(TransInfo *t);
+static eRedrawFlag handleEventVertSlide(TransInfo *t, const struct wmEvent *event);
+static void applyVertSlide(TransInfo *t, const int mval[2]);
+
+static void initTimeTranslate(TransInfo *t);
+static void applyTimeTranslate(TransInfo *t, const int mval[2]);
+
+static void initTimeSlide(TransInfo *t);
+static void applyTimeSlide(TransInfo *t, const int mval[2]);
+
+static void initTimeScale(TransInfo *t);
+static void applyTimeScale(TransInfo *t, const int mval[2]);
+
+static void initBakeTime(TransInfo *t);
+static void applyBakeTime(TransInfo *t, const int mval[2]);
+
+static void initMirror(TransInfo *t);
+static void applyMirror(TransInfo *t, const int mval[2]);
+
+static void initAlign(TransInfo *t);
+static void applyAlign(TransInfo *t, const int mval[2]);
+
+static void initSeqSlide(TransInfo *t);
+static void applySeqSlide(TransInfo *t, const int mval[2]);
+/* end transform callbacks */
+
+
+static bool transdata_check_local_center(TransInfo *t, short around)
 {
-       return ((t->around == V3D_LOCAL) && (
+       return ((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_MBALL) ||
-                   (t->obedit && t->obedit->type == OB_ARMATURE) ||
-                   (t->spacetype == SPACE_IPO))
+                   (t->obedit && ELEM4(t->obedit->type, OB_MESH, OB_CURVE, OB_MBALL, OB_ARMATURE)) ||
+                   (t->spacetype == SPACE_IPO) ||
+                   (t->options & (CTX_MOVIECLIP | CTX_MASK)))
                );
 }
 
@@ -385,20 +475,15 @@ void projectFloatViewEx(TransInfo *t, const float vec[3], float adr[2], const eV
                        }
                        break;
                }
-               case SPACE_IMAGE:
-               case SPACE_CLIP:
-               case SPACE_IPO:
-               case SPACE_NLA:
+               default:
                {
-                       int a[2];
+                       int a[2] = {0, 0};
                        projectIntView(t, vec, a);
                        adr[0] = a[0];
                        adr[1] = a[1];
-                       return;
+                       break;
                }
        }
-
-       zero_v2(adr);
 }
 void projectFloatView(TransInfo *t, const float vec[3], float adr[2])
 {
@@ -490,9 +575,6 @@ static void viewRedrawForce(const bContext *C, TransInfo *t)
                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))
@@ -591,20 +673,6 @@ static void viewRedrawPost(bContext *C, TransInfo *t)
 
 /* ************************** TRANSFORMATIONS **************************** */
 
-void BIF_selectOrientation(void)
-{
-#if 0 // TRANSFORM_FIX_ME
-       short val;
-       char *str_menu = BIF_menustringTransformOrientation("Orientation");
-       val = pupmenu(str_menu);
-       MEM_freeN(str_menu);
-
-       if (val >= 0) {
-               G.vd->twmode = val;
-       }
-#endif
-}
-
 static void view_editmove(unsigned short UNUSED(event))
 {
 #if 0 // TRANSFORM_FIX_ME
@@ -871,11 +939,18 @@ int transformEvent(TransInfo *t, const wmEvent *event)
 {
        float mati[3][3] = MAT3_UNITY;
        char cmode = constraintModeToChar(t);
-       int handled = 1;
-       
+       bool handled = false;
+
        t->redraw |= handleMouseInput(t, &t->mouse, event);
 
-       if (event->type == MOUSEMOVE) {
+       /* Handle modal numinput events first, if already activated. */
+       if (((event->val == KM_PRESS) || (event->type == EVT_MODAL_MAP)) &&
+           hasNumInput(&t->num) && handleNumInput(t->context, &(t->num), event))
+       {
+               t->redraw |= TREDRAW_HARD;
+               handled = true;
+       }
+       else if (event->type == MOUSEMOVE) {
                if (t->modifiers & MOD_CONSTRAINT_SELECT)
                        t->con.mode |= CON_SELECT;
 
@@ -884,7 +959,6 @@ int transformEvent(TransInfo *t, const wmEvent *event)
                // t->redraw |= TREDRAW_SOFT; /* Use this for soft redraw. Might cause flicker in object mode */
                t->redraw |= TREDRAW_HARD;
 
-
                if (t->state == TRANS_STARTING) {
                        t->state = TRANS_RUNNING;
                }
@@ -893,40 +967,40 @@ int transformEvent(TransInfo *t, const wmEvent *event)
 
                // Snapping mouse move events
                t->redraw |= handleSnapping(t, event);
+               handled = true;
        }
-
        /* handle modal keymap first */
-       if (event->type == EVT_MODAL_MAP) {
+       else if (event->type == EVT_MODAL_MAP) {
                switch (event->val) {
                        case TFM_MODAL_CANCEL:
                                t->state = TRANS_CANCEL;
+                               handled = true;
                                break;
                        case TFM_MODAL_CONFIRM:
                                t->state = TRANS_CONFIRM;
+                               handled = true;
                                break;
                        case TFM_MODAL_TRANSLATE:
                                /* only switch when... */
                                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);
-                                       }
+                                       resetTransModal(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);
+                                       handled = true;
                                }
                                else if (t->mode == TFM_SEQ_SLIDE) {
                                        t->flag ^= T_ALT_TRANSFORM;
                                        t->redraw |= TREDRAW_HARD;
+                                       handled = true;
                                }
                                else {
                                        if (t->obedit && t->obedit->type == OB_MESH) {
                                                if ((t->mode == TFM_TRANSLATION) && (t->spacetype == SPACE_VIEW3D)) {
+                                                       resetTransModal(t);
                                                        resetTransRestrictions(t);
                                                        restoreTransObjects(t);
 
@@ -946,6 +1020,7 @@ int transformEvent(TransInfo *t, const wmEvent *event)
                                                        }
                                                        initSnapping(t, NULL); // need to reinit after mode change
                                                        t->redraw |= TREDRAW_HARD;
+                                                       handled = true;
                                                        WM_event_add_mousemove(t->context);
                                                }
                                        }
@@ -955,6 +1030,7 @@ int transformEvent(TransInfo *t, const wmEvent *event)
 
                                                        t->flag ^= T_ALT_TRANSFORM;
                                                        t->redraw |= TREDRAW_HARD;
+                                                       handled = true;
                                                }
                                        }
                                }
@@ -962,8 +1038,8 @@ int transformEvent(TransInfo *t, const wmEvent *event)
                        case TFM_MODAL_ROTATE:
                                /* only switch when... */
                                if (!(t->options & CTX_TEXTURE) && !(t->options & (CTX_MOVIECLIP | CTX_MASK))) {
-                                       if (ELEM4(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL, TFM_TRANSLATION) ) {
-                                               
+                                       if (ELEM6(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL, TFM_TRANSLATION, TFM_EDGE_SLIDE, TFM_VERT_SLIDE)) {
+                                               resetTransModal(t);
                                                resetTransRestrictions(t);
                                                
                                                if (t->mode == TFM_ROTATION) {
@@ -976,21 +1052,25 @@ int transformEvent(TransInfo *t, const wmEvent *event)
                                                }
                                                initSnapping(t, NULL); // need to reinit after mode change
                                                t->redraw |= TREDRAW_HARD;
+                                               handled = true;
                                        }
                                }
                                break;
                        case TFM_MODAL_RESIZE:
                                /* only switch when... */
-                               if (ELEM3(t->mode, TFM_ROTATION, TFM_TRANSLATION, TFM_TRACKBALL) ) {
+                               if (ELEM5(t->mode, TFM_ROTATION, TFM_TRANSLATION, TFM_TRACKBALL, TFM_EDGE_SLIDE, TFM_VERT_SLIDE)) {
+                                       resetTransModal(t);
                                        resetTransRestrictions(t);
                                        restoreTransObjects(t);
                                        initResize(t);
                                        initSnapping(t, NULL); // need to reinit after mode change
                                        t->redraw |= TREDRAW_HARD;
+                                       handled = true;
                                }
                                else if (t->mode == TFM_SHRINKFATTEN) {
                                        t->flag ^= T_ALT_TRANSFORM;
                                        t->redraw |= TREDRAW_HARD;
+                                       handled = true;
                                }
                                else if (t->mode == TFM_RESIZE) {
                                        if (t->options & CTX_MOVIECLIP) {
@@ -998,6 +1078,7 @@ int transformEvent(TransInfo *t, const wmEvent *event)
 
                                                t->flag ^= T_ALT_TRANSFORM;
                                                t->redraw |= TREDRAW_HARD;
+                                               handled = true;
                                        }
                                }
                                break;
@@ -1005,14 +1086,17 @@ int transformEvent(TransInfo *t, const wmEvent *event)
                        case TFM_MODAL_SNAP_INV_ON:
                                t->modifiers |= MOD_SNAP_INVERT;
                                t->redraw |= TREDRAW_HARD;
+                               handled = true;
                                break;
                        case TFM_MODAL_SNAP_INV_OFF:
                                t->modifiers &= ~MOD_SNAP_INVERT;
                                t->redraw |= TREDRAW_HARD;
+                               handled = true;
                                break;
                        case TFM_MODAL_SNAP_TOGGLE:
                                t->modifiers ^= MOD_SNAP;
                                t->redraw |= TREDRAW_HARD;
+                               handled = true;
                                break;
                        case TFM_MODAL_AXIS_X:
                                if ((t->flag & T_NO_CONSTRAINT) == 0) {
@@ -1028,6 +1112,7 @@ int transformEvent(TransInfo *t, const wmEvent *event)
                                                }
                                        }
                                        t->redraw |= TREDRAW_HARD;
+                                       handled = true;
                                }
                                break;
                        case TFM_MODAL_AXIS_Y:
@@ -1044,6 +1129,7 @@ int transformEvent(TransInfo *t, const wmEvent *event)
                                                }
                                        }
                                        t->redraw |= TREDRAW_HARD;
+                                       handled = true;
                                }
                                break;
                        case TFM_MODAL_AXIS_Z:
@@ -1055,6 +1141,7 @@ int transformEvent(TransInfo *t, const wmEvent *event)
                                                setUserConstraint(t, t->current_orientation, (CON_AXIS2), IFACE_("along %s Z"));
                                        }
                                        t->redraw |= TREDRAW_HARD;
+                                       handled = true;
                                }
                                break;
                        case TFM_MODAL_PLANE_X:
@@ -1066,6 +1153,7 @@ int transformEvent(TransInfo *t, const wmEvent *event)
                                                setUserConstraint(t, t->current_orientation, (CON_AXIS1 | CON_AXIS2), IFACE_("locking %s X"));
                                        }
                                        t->redraw |= TREDRAW_HARD;
+                                       handled = true;
                                }
                                break;
                        case TFM_MODAL_PLANE_Y:
@@ -1077,6 +1165,7 @@ int transformEvent(TransInfo *t, const wmEvent *event)
                                                setUserConstraint(t, t->current_orientation, (CON_AXIS0 | CON_AXIS2), IFACE_("locking %s Y"));
                                        }
                                        t->redraw |= TREDRAW_HARD;
+                                       handled = true;
                                }
                                break;
                        case TFM_MODAL_PLANE_Z:
@@ -1088,23 +1177,26 @@ int transformEvent(TransInfo *t, const wmEvent *event)
                                                setUserConstraint(t, t->current_orientation, (CON_AXIS0 | CON_AXIS1), IFACE_("locking %s Z"));
                                        }
                                        t->redraw |= TREDRAW_HARD;
+                                       handled = true;
                                }
                                break;
                        case TFM_MODAL_CONS_OFF:
                                if ((t->flag & T_NO_CONSTRAINT) == 0) {
                                        stopConstraint(t);
                                        t->redraw |= TREDRAW_HARD;
+                                       handled = true;
                                }
                                break;
                        case TFM_MODAL_ADD_SNAP:
                                addSnapPoint(t);
                                t->redraw |= TREDRAW_HARD;
+                               handled = true;
                                break;
                        case TFM_MODAL_REMOVE_SNAP:
                                removeSnapPoint(t);
                                t->redraw |= TREDRAW_HARD;
+                               handled = true;
                                break;
-                               
                        case TFM_MODAL_PROPSIZE:
                                /* MOUSEPAN usage... */
                                if (t->flag & T_PROP_EDIT) {
@@ -1113,76 +1205,69 @@ int transformEvent(TransInfo *t, const wmEvent *event)
                                        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;
+                                       handled = true;
                                }
-                               t->redraw |= TREDRAW_HARD;
                                break;
-                               
                        case TFM_MODAL_PROPSIZE_UP:
                                if (t->flag & T_PROP_EDIT) {
                                        t->prop_size *= 1.1f;
                                        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;
+                                       handled = true;
                                }
-                               t->redraw |= TREDRAW_HARD;
                                break;
                        case TFM_MODAL_PROPSIZE_DOWN:
                                if (t->flag & T_PROP_EDIT) {
                                        t->prop_size *= 0.90909090f;
                                        calculatePropRatio(t);
+                                       t->redraw |= TREDRAW_HARD;
+                                       handled = true;
                                }
-                               t->redraw |= TREDRAW_HARD;
                                break;
                        case TFM_MODAL_EDGESLIDE_UP:
                        case TFM_MODAL_EDGESLIDE_DOWN:
                                t->redraw |= TREDRAW_HARD;
+                               handled = true;
                                break;
                        case TFM_MODAL_AUTOIK_LEN_INC:
-                               if (t->flag & T_AUTOIK)
+                               if (t->flag & T_AUTOIK) {
                                        transform_autoik_update(t, 1);
-                               t->redraw |= TREDRAW_HARD;
+                                       t->redraw |= TREDRAW_HARD;
+                                       handled = true;
+                               }
                                break;
                        case TFM_MODAL_AUTOIK_LEN_DEC:
-                               if (t->flag & T_AUTOIK) 
+                               if (t->flag & T_AUTOIK) {
                                        transform_autoik_update(t, -1);
-                               t->redraw |= TREDRAW_HARD;
+                                       t->redraw |= TREDRAW_HARD;
+                                       handled = true;
+                               }
                                break;
                        default:
-                               handled = 0;
                                break;
                }
-
-               // Modal numinput events
-               t->redraw |= handleNumInput(&(t->num), event);
        }
        /* else do non-mapped events */
        else if (event->val == KM_PRESS) {
                switch (event->type) {
                        case RIGHTMOUSE:
                                t->state = TRANS_CANCEL;
+                               handled = true;
                                break;
                        /* enforce redraw of transform when modifiers are used */
                        case LEFTSHIFTKEY:
                        case RIGHTSHIFTKEY:
                                t->modifiers |= MOD_CONSTRAINT_PLANE;
                                t->redraw |= TREDRAW_HARD;
+                               handled = true;
                                break;
 
                        case SPACEKEY:
-                               if ((t->spacetype == SPACE_VIEW3D) && event->alt) {
-#if 0 // TRANSFORM_FIX_ME
-                                       int mval[2];
-
-                                       getmouseco_sc(mval);
-                                       BIF_selectOrientation();
-                                       calc_manipulator_stats(curarea);
-                                       copy_m3_m4(t->spacemtx, G.vd->twmat);
-                                       warp_pointer(mval[0], mval[1]);
-#endif
-                               }
-                               else {
-                                       t->state = TRANS_CONFIRM;
-                               }
+                               t->state = TRANS_CONFIRM;
+                               handled = true;
                                break;
 
                        case MIDDLEMOUSE:
@@ -1214,40 +1299,47 @@ int transformEvent(TransInfo *t, const wmEvent *event)
                                                }
                                        }
                                        t->redraw |= TREDRAW_HARD;
+                                       handled = true;
                                }
                                break;
                        case ESCKEY:
                                t->state = TRANS_CANCEL;
+                               handled = true;
                                break;
                        case PADENTER:
                        case RETKEY:
                                t->state = TRANS_CONFIRM;
+                               handled = true;
                                break;
                        case GKEY:
                                /* only switch when... */
                                if (ELEM3(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL) ) {
+                                       resetTransModal(t);
                                        resetTransRestrictions(t);
                                        restoreTransObjects(t);
                                        initTranslation(t);
                                        initSnapping(t, NULL); // need to reinit after mode change
                                        t->redraw |= TREDRAW_HARD;
+                                       handled = true;
                                }
                                break;
                        case SKEY:
                                /* only switch when... */
                                if (ELEM3(t->mode, TFM_ROTATION, TFM_TRANSLATION, TFM_TRACKBALL) ) {
+                                       resetTransModal(t);
                                        resetTransRestrictions(t);
                                        restoreTransObjects(t);
                                        initResize(t);
                                        initSnapping(t, NULL); // need to reinit after mode change
                                        t->redraw |= TREDRAW_HARD;
+                                       handled = true;
                                }
                                break;
                        case RKEY:
                                /* only switch when... */
                                if (!(t->options & CTX_TEXTURE)) {
                                        if (ELEM4(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL, TFM_TRANSLATION) ) {
-
+                                               resetTransModal(t);
                                                resetTransRestrictions(t);
 
                                                if (t->mode == TFM_ROTATION) {
@@ -1260,6 +1352,7 @@ int transformEvent(TransInfo *t, const wmEvent *event)
                                                }
                                                initSnapping(t, NULL); // need to reinit after mode change
                                                t->redraw |= TREDRAW_HARD;
+                                               handled = true;
                                        }
                                }
                                break;
@@ -1268,23 +1361,27 @@ int transformEvent(TransInfo *t, const wmEvent *event)
                                        t->flag ^= T_PROP_CONNECTED;
                                        sort_trans_data_dist(t);
                                        calculatePropRatio(t);
-                                       t->redraw = 1;
+                                       t->redraw = TREDRAW_HARD;
+                                       handled = true;
                                }
                                else {
                                        stopConstraint(t);
                                        t->redraw |= TREDRAW_HARD;
+                                       handled = true;
                                }
                                break;
                        case XKEY:
                        case YKEY:
                        case ZKEY:
                                transform_event_xyz_constraint(t, event->type, cmode);
+                               handled = true;
                                break;
                        case OKEY:
                                if (t->flag & T_PROP_EDIT && event->shift) {
                                        t->prop_mode = (t->prop_mode + 1) % PROP_MODE_MAX;
                                        calculatePropRatio(t);
                                        t->redraw |= TREDRAW_HARD;
+                                       handled = true;
                                }
                                break;
                        case PADPLUSKEY:
@@ -1293,8 +1390,9 @@ int transformEvent(TransInfo *t, const wmEvent *event)
                                        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;
+                                       handled = true;
                                }
-                               t->redraw = 1;
                                break;
                        case PAGEUPKEY:
                        case WHEELDOWNMOUSE:
@@ -1304,14 +1402,16 @@ int transformEvent(TransInfo *t, const wmEvent *event)
                                else {
                                        view_editmove(event->type);
                                }
-                               t->redraw = 1;
+                               t->redraw = TREDRAW_HARD;
+                               handled = true;
                                break;
                        case PADMINUS:
                                if (event->alt && t->flag & T_PROP_EDIT) {
                                        t->prop_size *= 0.90909090f;
                                        calculatePropRatio(t);
+                                       t->redraw = TREDRAW_HARD;
+                                       handled = true;
                                }
-                               t->redraw = 1;
                                break;
                        case PAGEDOWNKEY:
                        case WHEELUPMOUSE:
@@ -1321,27 +1421,23 @@ int transformEvent(TransInfo *t, const wmEvent *event)
                                else {
                                        view_editmove(event->type);
                                }
-                               t->redraw = 1;
+                               t->redraw = TREDRAW_HARD;
+                               handled = true;
                                break;
                        case LEFTALTKEY:
                        case RIGHTALTKEY:
                                if (ELEM(t->spacetype, SPACE_SEQ, SPACE_VIEW3D)) {
                                        t->flag |= T_ALT_TRANSFORM;
                                        t->redraw |= TREDRAW_HARD;
+                                       handled = true;
                                }
-
                                break;
                        default:
-                               handled = 0;
                                break;
                }
 
-               // Numerical input events
-               t->redraw |= handleNumInput(&(t->num), event);
-
-               // Snapping key events
+               /* Snapping key events */
                t->redraw |= handleSnapping(t, event);
-
        }
        else if (event->val == KM_RELEASE) {
                switch (event->type) {
@@ -1349,6 +1445,7 @@ int transformEvent(TransInfo *t, const wmEvent *event)
                        case RIGHTSHIFTKEY:
                                t->modifiers &= ~MOD_CONSTRAINT_PLANE;
                                t->redraw |= TREDRAW_HARD;
+                               handled = true;
                                break;
 
                        case MIDDLEMOUSE:
@@ -1356,24 +1453,18 @@ int transformEvent(TransInfo *t, const wmEvent *event)
                                        t->modifiers &= ~MOD_CONSTRAINT_SELECT;
                                        postSelectConstraint(t);
                                        t->redraw |= TREDRAW_HARD;
+                                       handled = true;
                                }
                                break;
-//             case LEFTMOUSE:
-//             case RIGHTMOUSE:
-//                     if (WM_modal_tweak_exit(event, t->event_type))
-////                   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;
+                                       handled = true;
                                }
-
                                break;
                        default:
-                               handled = 0;
                                break;
                }
 
@@ -1385,13 +1476,19 @@ int transformEvent(TransInfo *t, const wmEvent *event)
                        }
                }
        }
-       else
-               handled = 0;
 
        // Per transform event, if present
-       if (t->handleEvent)
+       if (t->handleEvent && !handled)
                t->redraw |= t->handleEvent(t, event);
 
+       /* Try to init modal numinput now, if possible. */
+       if (!(handled || t->redraw) && ((event->val == KM_PRESS) || (event->type == EVT_MODAL_MAP)) &&
+           handleNumInput(t->context, &(t->num), event))
+       {
+               t->redraw |= TREDRAW_HARD;
+               handled = true;
+       }
+
        if (handled || t->redraw) {
                return 0;
        }
@@ -1400,7 +1497,7 @@ int transformEvent(TransInfo *t, const wmEvent *event)
        }
 }
 
-int calculateTransformCenter(bContext *C, int centerMode, float cent3d[3], int cent2d[2])
+int calculateTransformCenter(bContext *C, int centerMode, float cent3d[3], float cent2d[2])
 {
        TransInfo *t = MEM_callocN(sizeof(TransInfo), "TransInfo data");
        int success;
@@ -1408,11 +1505,11 @@ int calculateTransformCenter(bContext *C, int centerMode, float cent3d[3], int c
        t->state = TRANS_RUNNING;
 
        /* avoid calculating PET */
-       t->options = CTX_NONE | CTX_NO_PET;
+       t->options = CTX_NO_PET;
 
        t->mode = TFM_DUMMY;
 
-       initTransInfo(C, t, NULL, NULL);    // internal data, mouse, vectors
+       initTransInfo(C, t, NULL, NULL);
 
        /* avoid doing connectivity lookups (when V3D_LOCAL is set) */
        t->around = V3D_CENTER;
@@ -1430,7 +1527,7 @@ int calculateTransformCenter(bContext *C, int centerMode, float cent3d[3], int c
                calculateCenter(t);
 
                if (cent2d) {
-                       copy_v2_v2_int(cent2d, t->center2d);
+                       copy_v2_v2(cent2d, t->center2d);
                }
 
                if (cent3d) {
@@ -1463,6 +1560,7 @@ static void drawArrow(ArrowDirection d, short offset, short length, short size)
                        offset = -offset;
                        length = -length;
                        size = -size;
+                       /* fall-through */
                case RIGHT:
                        glBegin(GL_LINES);
                        glVertex2s(offset, 0);
@@ -1473,10 +1571,12 @@ static void drawArrow(ArrowDirection d, short offset, short length, short size)
                        glVertex2s(offset + length - size,  size);
                        glEnd();
                        break;
+
                case DOWN:
                        offset = -offset;
                        length = -length;
                        size = -size;
+                       /* fall-through */
                case UP:
                        glBegin(GL_LINES);
                        glVertex2s(0, offset);
@@ -1495,6 +1595,7 @@ static void drawArrowHead(ArrowDirection d, short size)
        switch (d) {
                case LEFT:
                        size = -size;
+                       /* fall-through */
                case RIGHT:
                        glBegin(GL_LINES);
                        glVertex2s(0, 0);
@@ -1503,8 +1604,10 @@ static void drawArrowHead(ArrowDirection d, short size)
                        glVertex2s(-size,  size);
                        glEnd();
                        break;
+
                case DOWN:
                        size = -size;
+                       /* fall-through */
                case UP:
                        glBegin(GL_LINES);
                        glVertex2s(0, 0);
@@ -1696,7 +1799,7 @@ static void drawAutoKeyWarning(TransInfo *UNUSED(t), ARegion *ar)
 
        ED_region_visible_rect(ar, &rect);
        
-       BLF_width_and_height_default(printable, &printable_size[0], &printable_size[1]);
+       BLF_width_and_height_default(printable, BLF_DRAW_STR_DUMMY_MAX, &printable_size[0], &printable_size[1]);
        
        xco = rect.xmax - (int)printable_size[0] - 10;
        yco = rect.ymax - (int)printable_size[1] - 10;
@@ -1706,9 +1809,9 @@ static void drawAutoKeyWarning(TransInfo *UNUSED(t), ARegion *ar)
         */
        UI_ThemeColorShade(TH_TEXT_HI, -50);
 #ifdef WITH_INTERNATIONAL
-       BLF_draw_default(xco, ar->winy - 17, 0.0f, printable, sizeof(printable));
+       BLF_draw_default(xco, ar->winy - 17, 0.0f, printable, BLF_DRAW_STR_DUMMY_MAX);
 #else
-       BLF_draw_default_ascii(xco, ar->winy - 17, 0.0f, printable, sizeof(printable));
+       BLF_draw_default_ascii(xco, ar->winy - 17, 0.0f, printable, BLF_DRAW_STR_DUMMY_MAX);
 #endif
        
        /* autokey recording icon... */
@@ -1766,42 +1869,49 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op)
        }
 
        /* convert flag to enum */
-       switch (t->flag & (T_PROP_EDIT | T_PROP_CONNECTED)) {
+       switch (t->flag & T_PROP_EDIT_ALL) {
+               case T_PROP_EDIT:
+                       proportional = PROP_EDIT_ON;
+                       break;
                case (T_PROP_EDIT | T_PROP_CONNECTED):
                        proportional = PROP_EDIT_CONNECTED;
                        break;
-               case T_PROP_EDIT:
-                       proportional = PROP_EDIT_ON;
+               case (T_PROP_EDIT | T_PROP_PROJECTED):
+                       proportional = PROP_EDIT_PROJECTED;
                        break;
                default:
                        proportional = PROP_EDIT_OFF;
+                       break;
        }
 
        // If modal, save settings back in scene if not set as operator argument
        if (t->flag & T_MODAL) {
-
                /* save settings if not set in operator */
-               if ((prop = RNA_struct_find_property(op->ptr, "proportional")) &&
-                   !RNA_property_is_set(op->ptr, prop))
-               {
-                       if (t->obedit)
-                               ts->proportional = proportional;
-                       else if (t->options & CTX_MASK)
-                               ts->proportional_mask = (proportional != PROP_EDIT_OFF);
-                       else
-                               ts->proportional_objects = (proportional != PROP_EDIT_OFF);
-               }
 
-               if ((prop = RNA_struct_find_property(op->ptr, "proportional_size")) &&
-                   !RNA_property_is_set(op->ptr, prop))
-               {
-                       ts->proportional_size = t->prop_size;
-               }
+               /* skip saving proportional edit if it was not actually used */
+               if (!(t->options & CTX_NO_PET)) {
+                       if ((prop = RNA_struct_find_property(op->ptr, "proportional")) &&
+                               !RNA_property_is_set(op->ptr, prop))
+                       {
+                               if (t->obedit)
+                                       ts->proportional = proportional;
+                               else if (t->options & CTX_MASK)
+                                       ts->proportional_mask = (proportional != PROP_EDIT_OFF);
+                               else
+                                       ts->proportional_objects = (proportional != PROP_EDIT_OFF);
+                       }
 
-               if ((prop = RNA_struct_find_property(op->ptr, "proportional_edit_falloff")) &&
-                   !RNA_property_is_set(op->ptr, prop))
-               {
-                       ts->prop_mode = t->prop_mode;
+                       if ((prop = RNA_struct_find_property(op->ptr, "proportional_size")) &&
+                               !RNA_property_is_set(op->ptr, prop))
+                       {
+                               ts->proportional_size = t->prop_size;
+                       }
+
+                       if ((prop = RNA_struct_find_property(op->ptr, "proportional_edit_falloff")) &&
+                               !RNA_property_is_set(op->ptr, prop))
+                       {
+                               ts->prop_mode = t->prop_mode;
+                       }
                }
                
                /* do we check for parameter? */
@@ -1881,7 +1991,7 @@ int initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *even
                        options |= CTX_TEXTURE;
                }
        }
-       
+
        t->options = options;
 
        t->mode = mode;
@@ -1901,9 +2011,7 @@ int initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *even
                t->launch_event = LEFTMOUSE;
        }
 
-       if (!initTransInfo(C, t, op, event)) {  /* internal data, mouse, vectors */
-               return 0;
-       }
+       initTransInfo(C, t, op, event);
 
        if (t->spacetype == SPACE_VIEW3D) {
                //calc_manipulator_stats(curarea);
@@ -1923,12 +2031,13 @@ int initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *even
        else if (t->spacetype == SPACE_CLIP) {
                unit_m3(t->spacemtx);
                t->draw_handle_view = ED_region_draw_cb_activate(t->ar->type, drawTransformView, t, REGION_DRAW_POST_VIEW);
+               t->draw_handle_cursor = WM_paint_cursor_activate(CTX_wm_manager(C), helpline_poll, drawHelpline, t);
        }
        else if (t->spacetype == SPACE_NODE) {
                unit_m3(t->spacemtx);
                /*t->draw_handle_apply = ED_region_draw_cb_activate(t->ar->type, drawTransformApply, t, REGION_DRAW_PRE_VIEW);*/
                t->draw_handle_view = ED_region_draw_cb_activate(t->ar->type, drawTransformView, t, REGION_DRAW_POST_VIEW);
-               /*t->draw_handle_cursor = WM_paint_cursor_activate(CTX_wm_manager(C), helpline_poll, drawHelpline, t);*/
+               t->draw_handle_cursor = WM_paint_cursor_activate(CTX_wm_manager(C), helpline_poll, drawHelpline, t);
        }
        else
                unit_m3(t->spacemtx);
@@ -1940,17 +2049,20 @@ int initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *even
                return 0;
        }
 
-       /* Stupid code to have Ctrl-Click on manipulator work ok */
        if (event) {
-               /* do this only for translation/rotation/resize due to only this
+               /* keymap for shortcut header prints */
+               t->keymap = WM_keymap_active(CTX_wm_manager(C), op->type->modalkeymap);
+
+               /* Stupid code to have Ctrl-Click on manipulator work ok
+                *
+                * do this only for translation/rotation/resize due to only this
                 * moded are available from manipulator and doing such check could
                 * lead to keymap conflicts for other modes (see #31584)
                 */
                if (ELEM3(mode, TFM_TRANSLATION, TFM_ROTATION, TFM_RESIZE)) {
-                       wmKeyMap *keymap = WM_keymap_active(CTX_wm_manager(C), op->type->modalkeymap);
                        wmKeyMapItem *kmi;
 
-                       for (kmi = keymap->items.first; kmi; kmi = kmi->next) {
+                       for (kmi = t->keymap->items.first; kmi; kmi = kmi->next) {
                                if (kmi->propvalue == TFM_MODAL_SNAP_INV_ON && kmi->val == KM_PRESS) {
                                        if ((ELEM(kmi->type, LEFTCTRLKEY, RIGHTCTRLKEY) &&   event->ctrl)  ||
                                            (ELEM(kmi->type, LEFTSHIFTKEY, RIGHTSHIFTKEY) && event->shift) ||
@@ -1963,11 +2075,8 @@ int initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *even
                                }
                        }
                }
-
        }
 
-       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) */
@@ -1999,8 +2108,8 @@ int initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *even
                case TFM_SHEAR:
                        initShear(t);
                        break;
-               case TFM_WARP:
-                       initWarp(t);
+               case TFM_BEND:
+                       initBend(t);
                        break;
                case TFM_SHRINKFATTEN:
                        initShrinkFatten(t);
@@ -2030,8 +2139,8 @@ int initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *even
                                initBoneEnvelope(t);
                        else
                                initBoneSize(t);
+                       break;
                }
-               break;
                case TFM_BONE_ENVELOPE:
                        initBoneEnvelope(t);
                        break;
@@ -2080,9 +2189,6 @@ int initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *even
                case TFM_MIRROR:
                        initMirror(t);
                        break;
-               case TFM_BEVEL:
-                       initBevel(t);
-                       break;
                case TFM_BWEIGHT:
                        initBevelWeight(t);
                        break;
@@ -2214,17 +2320,6 @@ int transformEnd(bContext *C, TransInfo *t)
                /* send events out for redraws */
                viewRedrawPost(C, t);
 
-               /*  Undo as last, certainly after special_trans_update! */
-
-               if (t->state == TRANS_CANCEL) {
-//                     if (t->undostr) ED_undo_push(C, t->undostr);
-               }
-               else {
-//                     if (t->undostr) ED_undo_push(C, t->undostr);
-//                     else ED_undo_push(C, transform_to_undostr(t));
-               }
-               t->undostr = NULL;
-
                viewRedrawForce(C, t);
        }
 
@@ -2235,7 +2330,7 @@ int transformEnd(bContext *C, TransInfo *t)
 
 /* ************************** TRANSFORM LOCKS **************************** */
 
-static void protectedTransBits(short protectflag, float *vec)
+static void protectedTransBits(short protectflag, float vec[3])
 {
        if (protectflag & OB_LOCK_LOCX)
                vec[0] = 0.0f;
@@ -2245,7 +2340,7 @@ static void protectedTransBits(short protectflag, float *vec)
                vec[2] = 0.0f;
 }
 
-static void protectedSizeBits(short protectflag, float *size)
+static void protectedSizeBits(short protectflag, float size[3])
 {
        if (protectflag & OB_LOCK_SCALEX)
                size[0] = 1.0f;
@@ -2255,7 +2350,7 @@ static void protectedSizeBits(short protectflag, float *size)
                size[2] = 1.0f;
 }
 
-static void protectedRotateBits(short protectflag, float *eul, float *oldeul)
+static void protectedRotateBits(short protectflag, float eul[3], const float oldeul[3])
 {
        if (protectflag & OB_LOCK_ROTX)
                eul[0] = oldeul[0];
@@ -2310,7 +2405,7 @@ static void protectedAxisAngleBits(short protectflag, float axis[3], float *angl
 }
 
 /* this function only does the delta rotation */
-static void protectedQuaternionBits(short protectflag, float *quat, float *oldquat)
+static void protectedQuaternionBits(short protectflag, float quat[4], const float oldquat[4])
 {
        /* check that protection flags are set */
        if ((protectflag & (OB_LOCK_ROTX | OB_LOCK_ROTY | OB_LOCK_ROTZ | OB_LOCK_ROTW)) == 0)
@@ -2614,187 +2709,226 @@ static void constraintSizeLim(TransInfo *t, TransData *td)
        }
 }
 
-/* ************************** WARP *************************** */
 
-static void postInputWarp(TransInfo *t, float values[3])
-{
-       mul_v3_fl(values, (float)(M_PI * 2));
+/* -------------------------------------------------------------------- */
+/* Transform (Bend) */
 
-       if (t->customData) { /* non-null value indicates reversed input */
-               negate_v3(values);
-       }
-}
+/** \name Transform Bend
+ * \{ */
 
-void initWarp(TransInfo *t)
+struct BendCustomData {
+       float warp_sta[3];
+       float warp_end[3];
+
+       float warp_nor[3];
+       float warp_tan[3];
+
+       /* for applying the mouse distance */
+       float warp_init_dist;
+};
+
+static void initBend(TransInfo *t)
 {
-       float max[3], min[3];
-       int i;
+       const float mval_fl[2] = {UNPACK2(t->mval)};
+       const float *curs;
+       float tvec[3];
+       struct BendCustomData *data;
        
-       t->mode = TFM_WARP;
-       t->transform = Warp;
-       t->handleEvent = handleEventWarp;
+       t->mode = TFM_BEND;
+       t->transform = Bend;
+       t->handleEvent = handleEventBend;
        
-       setInputPostFct(&t->mouse, postInputWarp);
-       initMouseInputMode(t, &t->mouse, INPUT_HORIZONTAL_RATIO);
+       setInputPostFct(&t->mouse, postInputRotation);
+       initMouseInputMode(t, &t->mouse, INPUT_ANGLE_SPRING);
        
-       t->idx_max = 0;
-       t->num.idx_max = 0;
+       t->idx_max = 1;
+       t->num.idx_max = 1;
        t->snap[0] = 0.0f;
-       t->snap[1] = 5.0f / 180.0f * (float)M_PI;
-       t->snap[2] = 1.0f / 180.0f * (float)M_PI;
-       
-       t->num.increment = 1.0f;
+       t->snap[1] = DEG2RAD(5.0);
+       t->snap[2] = DEG2RAD(1.0);
+
+       copy_v3_fl(t->num.val_inc, t->snap[1]);
+       t->num.unit_sys = t->scene->unit.system;
+       t->num.unit_use_radians = (t->scene->unit.system_rotation == USER_UNIT_ROT_RADIANS);
+       t->num.unit_type[0] = B_UNIT_ROTATION;
+       t->num.unit_type[1] = B_UNIT_LENGTH;
 
        t->flag |= T_NO_CONSTRAINT;
-       
-       /* we need min/max in view space */
-       for (i = 0; i < t->total; i++) {
-               float center[3];
-               copy_v3_v3(center, t->data[i].center);
-               mul_m3_v3(t->data[i].mtx, center);
-               mul_m4_v3(t->viewmat, center);
-               sub_v3_v3(center, t->viewmat[3]);
-               if (i) {
-                       minmax_v3v3_v3(min, max, center);
-               }
-               else {
-                       copy_v3_v3(max, center);
-                       copy_v3_v3(min, center);
-               }
+
+       //copy_v3_v3(t->center, ED_view3d_cursor3d_get(t->scene, t->view));
+       calculateCenterCursor(t);
+
+       t->val = 0.0f;
+
+       data = MEM_callocN(sizeof(*data), __func__);
+
+       curs = ED_view3d_cursor3d_get(t->scene, t->view);
+       copy_v3_v3(data->warp_sta, curs);
+       ED_view3d_win_to_3d(t->ar, curs, mval_fl, data->warp_end);
+
+       copy_v3_v3(data->warp_nor, t->viewinv[2]);
+       if (t->flag & T_EDIT) {
+               sub_v3_v3(data->warp_sta, t->obedit->obmat[3]);
+               sub_v3_v3(data->warp_end, t->obedit->obmat[3]);
        }
+       normalize_v3(data->warp_nor);
 
-       mid_v3_v3v3(t->center, min, max);
+       /* tangent */
+       sub_v3_v3v3(tvec, data->warp_end, data->warp_sta);
+       cross_v3_v3v3(data->warp_tan, tvec, data->warp_nor);
+       normalize_v3(data->warp_tan);
 
-       if (max[0] == min[0])
-               max[0] += 0.1f;  /* not optimal, but flipping is better than invalid garbage (i.e. division by zero!) */
-       t->val = (max[0] - min[0]) / 2.0f; /* t->val is X dimension projected boundbox */
+       data->warp_init_dist = len_v3v3(data->warp_end, data->warp_sta);
+
+       t->customData = data;
 }
 
-int handleEventWarp(TransInfo *t, const wmEvent *event)
+static eRedrawFlag handleEventBend(TransInfo *UNUSED(t), const wmEvent *event)
 {
-       int status = 0;
+       eRedrawFlag status = TREDRAW_NOTHING;
        
        if (event->type == MIDDLEMOUSE && event->val == KM_PRESS) {
-               // Use customData pointer to signal warp direction
-               if (t->customData == NULL)
-                       t->customData = (void *)1;
-               else
-                       t->customData = NULL;
-               
-               status = 1;
+               status = TREDRAW_HARD;
        }
        
        return status;
 }
 
-int Warp(TransInfo *t, const int UNUSED(mval[2]))
+static void Bend(TransInfo *t, const int UNUSED(mval[2]))
 {
        TransData *td = t->data;
-       float vec[3], circumfac, dist, phi0, co, si, cursor[3], gcursor[3];
-       const float *curs;
+       float vec[3];
+       float pivot[3];
+       float warp_end_radius[3];
        int i;
        char str[MAX_INFO_LEN];
-       
-       curs = give_cursor(t->scene, t->view);
-       /*
-        * gcursor is the one used for helpline.
-        * It has to be in the same space as the drawing loop
-        * (that means it needs to be in the object's space when in edit mode and
-        *  in global space in object mode)
-        *
-        * cursor is used for calculations.
-        * It needs to be in view space, but we need to take object's offset
-        * into account if in Edit mode.
-        */
-       copy_v3_v3(cursor, curs);
-       copy_v3_v3(gcursor, cursor);
-       if (t->flag & T_EDIT) {
-               sub_v3_v3(cursor, t->obedit->obmat[3]);
-               sub_v3_v3(gcursor, t->obedit->obmat[3]);
-               mul_m3_v3(t->data->smtx, gcursor);
+       const struct BendCustomData *data = t->customData;
+       const bool is_clamp = (t->flag & T_ALT_TRANSFORM) == 0;
+
+       union {
+               struct { float angle, scale; };
+               float vector[2];
+       } values;
+
+       /* amount of radians for bend */
+       copy_v2_v2(values.vector, t->values);
+
+#if 0
+       snapGrid(t, angle_rad);
+#else
+       /* hrmf, snapping radius is using 'angle' steps, need to convert to something else
+        * this isnt essential but nicer to give reasonable snapping values for radius */
+       if (t->tsnap.mode == SCE_SNAP_MODE_INCREMENT) {
+               const float radius_snap = 0.1f;
+               const float snap_hack = (t->snap[1] * data->warp_init_dist) / radius_snap;
+               values.scale *= snap_hack;
+               snapGridIncrement(t, values.vector);
+               values.scale /= snap_hack;
        }
-       mul_m4_v3(t->viewmat, cursor);
-       sub_v3_v3(cursor, t->viewmat[3]);
-       
-       /* amount of radians for warp */
-       circumfac = t->values[0];
-       
-       snapGrid(t, &circumfac);
-       applyNumInput(&t->num, &circumfac);
+#endif
        
        /* header print for NumInput */
        if (hasNumInput(&t->num)) {
-               char c[NUM_STR_REP_LEN];
+               char c[NUM_STR_REP_LEN * 2];
                
+               applyNumInput(&t->num, values.vector);
+
                outputNumInput(&(t->num), c);
                
-               BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Warp: %s"), c);
+               BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Bend Angle: %s Radius: %s Alt, Clamp %s"),
+                            &c[0], &c[NUM_STR_REP_LEN],
+                            WM_bool_as_string(is_clamp));
 
-               circumfac = DEG2RADF(circumfac);
+               values.scale = values.scale / data->warp_init_dist;
        }
        else {
                /* default header print */
-               BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Warp: %.3f"), RAD2DEGF(circumfac));
+               BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Bend Angle: %.3f Radius: %.4f, Alt, Clamp %s"),
+                            RAD2DEGF(values.angle), values.scale * data->warp_init_dist,
+                            WM_bool_as_string(is_clamp));
        }
        
-       t->values[0] = circumfac;
+       copy_v2_v2(t->values, values.vector);
 
-       circumfac /= 2; /* only need 180 on each side to make 360 */
+       values.angle *= -1.0f;
+       values.scale *= data->warp_init_dist;
        
+       /* calc 'data->warp_end' from 'data->warp_end_init' */
+       copy_v3_v3(warp_end_radius, data->warp_end);
+       dist_ensure_v3_v3fl(warp_end_radius, data->warp_sta, values.scale);
+       /* done */
+
+       /* calculate pivot */
+       copy_v3_v3(pivot, data->warp_sta);
+       if (values.angle > 0.0f) {
+               madd_v3_v3fl(pivot, data->warp_tan, -values.scale * shell_angle_to_dist((float)M_PI_2 - values.angle));
+       }
+       else {
+               madd_v3_v3fl(pivot, data->warp_tan, +values.scale * shell_angle_to_dist((float)M_PI_2 + values.angle));
+       }
+
        for (i = 0; i < t->total; i++, td++) {
-               float loc[3];
+               float mat[3][3];
+               float delta[3];
+               float fac, fac_scaled;
+
                if (td->flag & TD_NOACTION)
                        break;
                
                if (td->flag & TD_SKIP)
                        continue;
-               
-               /* translate point to center, rotate in such a way that outline==distance */
+
+               if (UNLIKELY(values.angle == 0.0f)) {
+                       copy_v3_v3(td->loc, td->iloc);
+                       continue;
+               }
+
                copy_v3_v3(vec, td->iloc);
                mul_m3_v3(td->mtx, vec);
-               mul_m4_v3(t->viewmat, vec);
-               sub_v3_v3(vec, t->viewmat[3]);
-               
-               dist = vec[0] - cursor[0];
-               
-               /* t->val is X dimension projected boundbox */
-               phi0 = (circumfac * dist / t->val);
-               
-               vec[1] = (vec[1] - cursor[1]);
-               
-               co = cosf(phi0);
-               si = sinf(phi0);
-               loc[0] = -si * vec[1] + cursor[0];
-               loc[1] = co * vec[1] + cursor[1];
-               loc[2] = vec[2];
-               
-               mul_m4_v3(t->viewinv, loc);
-               sub_v3_v3(loc, t->viewinv[3]);
-               mul_m3_v3(td->smtx, loc);
-               
-               sub_v3_v3(loc, td->iloc);
-               mul_v3_fl(loc, td->factor);
-               add_v3_v3v3(td->loc, td->iloc, loc);
+
+               fac = line_point_factor_v3(vec, data->warp_sta, warp_end_radius);
+               if (is_clamp) {
+                       CLAMP(fac, 0.0f, 1.0f);
+               }
+
+               fac_scaled = fac * td->factor;
+               axis_angle_normalized_to_mat3(mat, data->warp_nor, values.angle * fac_scaled);
+               interp_v3_v3v3(delta, data->warp_sta, warp_end_radius, fac_scaled);
+               sub_v3_v3(delta, data->warp_sta);
+
+               /* delta is subtracted, rotation adds back this offset */
+               sub_v3_v3(vec, delta);
+
+               sub_v3_v3(vec, pivot);
+               mul_m3_v3(mat, vec);
+               add_v3_v3(vec, pivot);
+
+               mul_m3_v3(td->smtx, vec);
+               copy_v3_v3(td->loc, vec);
        }
        
        recalcData(t);
        
        ED_area_headerprint(t->sa, str);
-       
-       return 1;
 }
+/** \} */
+
 
-/* ************************** SHEAR *************************** */
+/* -------------------------------------------------------------------- */
+/* Transform (Shear) */
+
+/** \name Transform Shear
+ * \{ */
 
 static void postInputShear(TransInfo *UNUSED(t), float values[3])
 {
        mul_v3_fl(values, 0.05f);
 }
 
-void initShear(TransInfo *t)
+static void initShear(TransInfo *t)
 {
        t->mode = TFM_SHEAR;
-       t->transform = Shear;
+       t->transform = applyShear;
        t->handleEvent = handleEventShear;
        
        setInputPostFct(&t->mouse, postInputShear);
@@ -2805,15 +2939,17 @@ void initShear(TransInfo *t)
        t->snap[0] = 0.0f;
        t->snap[1] = 0.1f;
        t->snap[2] = t->snap[1] * 0.1f;
-       
-       t->num.increment = 0.1f;
+
+       copy_v3_fl(t->num.val_inc, t->snap[1]);
+       t->num.unit_sys = t->scene->unit.system;
+       t->num.unit_type[0] = B_UNIT_NONE;  /* Don't think we have any unit here? */
 
        t->flag |= T_NO_CONSTRAINT;
 }
 
-int handleEventShear(TransInfo *t, const wmEvent *event)
+static eRedrawFlag handleEventShear(TransInfo *t, const wmEvent *event)
 {
-       int status = 0;
+       eRedrawFlag status = TREDRAW_NOTHING;
        
        if (event->type == MIDDLEMOUSE && event->val == KM_PRESS) {
                // Use customData pointer to signal Shear direction
@@ -2826,26 +2962,26 @@ int handleEventShear(TransInfo *t, const wmEvent *event)
                        t->customData = NULL;
                }
 
-               status = 1;
+               status = TREDRAW_HARD;
        }
        else if (event->type == XKEY && event->val == KM_PRESS) {
                initMouseInputMode(t, &t->mouse, INPUT_HORIZONTAL_ABSOLUTE);
                t->customData = NULL;
                
-               status = 1;
+               status = TREDRAW_HARD;
        }
        else if (event->type == YKEY && event->val == KM_PRESS) {
                initMouseInputMode(t, &t->mouse, INPUT_VERTICAL_ABSOLUTE);
                t->customData = (void *)1;
                
-               status = 1;
+               status = TREDRAW_HARD;
        }
        
        return status;
 }
 
 
-int Shear(TransInfo *t, const int UNUSED(mval[2]))
+static void applyShear(TransInfo *t, const int UNUSED(mval[2]))
 {
        TransData *td = t->data;
        float vec[3];
@@ -2859,7 +2995,7 @@ int Shear(TransInfo *t, const int UNUSED(mval[2]))
        
        value = t->values[0];
        
-       snapGrid(t, &value);
+       snapGridIncrement(t, &value);
        
        applyNumInput(&t->num, &value);
        
@@ -2919,25 +3055,33 @@ int Shear(TransInfo *t, const int UNUSED(mval[2]))
        recalcData(t);
        
        ED_area_headerprint(t->sa, str);
-
-       return 1;
 }
+/** \} */
+
 
-/* ************************** RESIZE *************************** */
+/* -------------------------------------------------------------------- */
+/* Transform (Resize) */
 
-void initResize(TransInfo *t)
+/** \name Transform Resize
+ * \{ */
+
+static void initResize(TransInfo *t)
 {
        t->mode = TFM_RESIZE;
-       t->transform = Resize;
+       t->transform = applyResize;
        
        initMouseInputMode(t, &t->mouse, INPUT_SPRING_FLIP);
        
        t->flag |= T_NULL_ONE;
-       t->num.flag |= NUM_NULL_ONE;
+       t->num.val_flag[0] |= NUM_NULL_ONE;
+       t->num.val_flag[1] |= NUM_NULL_ONE;
+       t->num.val_flag[2] |= NUM_NULL_ONE;
        t->num.flag |= NUM_AFFECT_ALL;
        if (!t->obedit) {
                t->flag |= T_NO_ZERO;
-               t->num.flag |= NUM_NO_ZERO;
+               t->num.val_flag[0] |= NUM_NO_ZERO;
+               t->num.val_flag[1] |= NUM_NO_ZERO;
+               t->num.val_flag[2] |= NUM_NO_ZERO;
        }
        
        t->idx_max = 2;
@@ -2946,11 +3090,14 @@ void initResize(TransInfo *t)
        t->snap[1] = 0.1f;
        t->snap[2] = t->snap[1] * 0.1f;
 
-       t->num.increment = t->snap[1];
+       copy_v3_fl(t->num.val_inc, t->snap[1]);
+       t->num.unit_sys = t->scene->unit.system;
+       t->num.unit_type[0] = B_UNIT_NONE;
+       t->num.unit_type[1] = B_UNIT_NONE;
+       t->num.unit_type[2] = B_UNIT_NONE;
 }
 
-/* We assume str is MAX_INFO_LEN long. */
-static void headerResize(TransInfo *t, float vec[3], char *str)
+static void headerResize(TransInfo *t, float vec[3], char str[MAX_INFO_LEN])
 {
        char tvec[NUM_STR_REP_LEN * 3];
        size_t ofs = 0;
@@ -2976,6 +3123,7 @@ static void headerResize(TransInfo *t, float vec[3], char *str)
                        case 2:
                                ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, 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);
+                               break;
                }
        }
        else {
@@ -2989,7 +3137,7 @@ static void headerResize(TransInfo *t, float vec[3], char *str)
                }
        }
 
-       if (t->flag & (T_PROP_EDIT | T_PROP_CONNECTED)) {
+       if (t->flag & T_PROP_EDIT_ALL) {
                ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_(" Proportional size: %.2f"), t->prop_size);
        }
 }
@@ -3044,11 +3192,16 @@ static void ElementResize(TransInfo *t, TransData *td, float mat[3][3])
        }
        
        /* local constraint shouldn't alter center */
-       if (transdata_check_local_center(t)) {
+       if (transdata_check_local_center(t, t->around)) {
                copy_v3_v3(center, td->center);
        }
        else if (t->options & CTX_MOVIECLIP) {
-               copy_v3_v3(center, td->center);
+               if (td->flag & TD_INDIVIDUAL_SCALE) {
+                       copy_v3_v3(center, td->center);
+               }
+               else {
+                       copy_v3_v3(center, t->center);
+               }
        }
        else {
                copy_v3_v3(center, t->center);
@@ -3120,7 +3273,7 @@ static void ElementResize(TransInfo *t, TransData *td, float mat[3][3])
        constraintTransLim(t, td);
 }
 
-int Resize(TransInfo *t, const int mval[2])
+static void applyResize(TransInfo *t, const int mval[2])
 {
        TransData *td;
        float size[3], mat[3][3];
@@ -3138,7 +3291,7 @@ int Resize(TransInfo *t, const int mval[2])
        
        size[0] = size[1] = size[2] = ratio;
        
-       snapGrid(t, size);
+       snapGridIncrement(t, size);
        
        if (hasNumInput(&t->num)) {
                applyNumInput(&t->num, size);
@@ -3187,7 +3340,7 @@ int Resize(TransInfo *t, const int mval[2])
                /* vertices in the radius of the brush end */
                /* outside the clipping area               */
                /* XXX HACK - dg */
-               if (t->flag & (T_PROP_EDIT | T_PROP_CONNECTED)) {
+               if (t->flag & T_PROP_EDIT_ALL) {
                        clipUVData(t);
                }
        }
@@ -3195,25 +3348,33 @@ int Resize(TransInfo *t, const int mval[2])
        recalcData(t);
        
        ED_area_headerprint(t->sa, str);
-       
-       return 1;
 }
+/** \} */
 
-/* ************************** SKIN *************************** */
 
-void initSkinResize(TransInfo *t)
+/* -------------------------------------------------------------------- */
+/* Transform (Skin) */
+
+/** \name Transform Skin
+ * \{ */
+
+static void initSkinResize(TransInfo *t)
 {
        t->mode = TFM_SKIN_RESIZE;
-       t->transform = SkinResize;
+       t->transform = applySkinResize;
        
        initMouseInputMode(t, &t->mouse, INPUT_SPRING_FLIP);
        
        t->flag |= T_NULL_ONE;
-       t->num.flag |= NUM_NULL_ONE;
+       t->num.val_flag[0] |= NUM_NULL_ONE;
+       t->num.val_flag[1] |= NUM_NULL_ONE;
+       t->num.val_flag[2] |= NUM_NULL_ONE;
        t->num.flag |= NUM_AFFECT_ALL;
        if (!t->obedit) {
                t->flag |= T_NO_ZERO;
-               t->num.flag |= NUM_NO_ZERO;
+               t->num.val_flag[0] |= NUM_NO_ZERO;
+               t->num.val_flag[1] |= NUM_NO_ZERO;
+               t->num.val_flag[2] |= NUM_NO_ZERO;
        }
        
        t->idx_max = 2;
@@ -3222,10 +3383,14 @@ void initSkinResize(TransInfo *t)
        t->snap[1] = 0.1f;
        t->snap[2] = t->snap[1] * 0.1f;
 
-       t->num.increment = t->snap[1];
+       copy_v3_fl(t->num.val_inc, t->snap[1]);
+       t->num.unit_sys = t->scene->unit.system;
+       t->num.unit_type[0] = B_UNIT_NONE;
+       t->num.unit_type[1] = B_UNIT_NONE;
+       t->num.unit_type[2] = B_UNIT_NONE;
 }
 
-int SkinResize(TransInfo *t, const int UNUSED(mval[2]))
+static void applySkinResize(TransInfo *t, const int UNUSED(mval[2]))
 {
        TransData *td;
        float size[3], mat[3][3];
@@ -3236,7 +3401,7 @@ int SkinResize(TransInfo *t, const int UNUSED(mval[2]))
        ratio = t->values[0];
        size[0] = size[1] = size[2] = ratio;
        
-       snapGrid(t, size);
+       snapGridIncrement(t, size);
        
        if (hasNumInput(&t->num)) {
                applyNumInput(&t->num, size);
@@ -3285,19 +3450,23 @@ int SkinResize(TransInfo *t, const int UNUSED(mval[2]))
        recalcData(t);
        
        ED_area_headerprint(t->sa, str);
-       
-       return 1;
 }
+/** \} */
 
-/* ************************** TOSPHERE *************************** */
 
-void initToSphere(TransInfo *t)
+/* -------------------------------------------------------------------- */
+/* Transform (ToSphere) */
+
+/** \name Transform ToSphere
+ * \{ */
+
+static void initToSphere(TransInfo *t)
 {
        TransData *td = t->data;
        int i;
        
        t->mode = TFM_TOSPHERE;
-       t->transform = ToSphere;
+       t->transform = applyToSphere;
        
        initMouseInputMode(t, &t->mouse, INPUT_HORIZONTAL_RATIO);
        
@@ -3307,9 +3476,11 @@ void initToSphere(TransInfo *t)
        t->snap[1] = 0.1f;
        t->snap[2] = t->snap[1] * 0.1f;
        
-       t->num.increment = t->snap[1];
+       copy_v3_fl(t->num.val_inc, t->snap[1]);
+       t->num.unit_sys = t->scene->unit.system;
+       t->num.unit_type[0] = B_UNIT_NONE;
 
-       t->num.flag |= NUM_NULL_ONE | NUM_NO_NEGATIVE;
+       t->num.val_flag[0] |= NUM_NULL_ONE | NUM_NO_NEGATIVE;
        t->flag |= T_NO_CONSTRAINT;
        
        // Calculate average radius
@@ -3320,7 +3491,7 @@ void initToSphere(TransInfo *t)
        t->val /= (float)t->total;
 }
 
-int ToSphere(TransInfo *t, const int UNUSED(mval[2]))
+static void applyToSphere(TransInfo *t, const int UNUSED(mval[2]))
 {
        float vec[3];
        float ratio, radius;
@@ -3330,7 +3501,7 @@ int ToSphere(TransInfo *t, const int UNUSED(mval[2]))
        
        ratio = t->values[0];
        
-       snapGrid(t, &ratio);
+       snapGridIncrement(t, &ratio);
        
        applyNumInput(&t->num, &ratio);
        
@@ -3378,12 +3549,15 @@ int ToSphere(TransInfo *t, const int UNUSED(mval[2]))
        recalcData(t);
        
        ED_area_headerprint(t->sa, str);
-       
-       return 1;
 }
+/** \} */
 
-/* ************************** ROTATION *************************** */
 
+/* -------------------------------------------------------------------- */
+/* Transform (Rotation) */
+
+/** \name Transform Rotation
+ * \{ */
 
 static void postInputRotation(TransInfo *t, float values[3])
 {
@@ -3392,10 +3566,10 @@ static void postInputRotation(TransInfo *t, float values[3])
        }
 }
 
-void initRotation(TransInfo *t)
+static void initRotation(TransInfo *t)
 {
        t->mode = TFM_ROTATION;
-       t->transform = Rotation;
+       t->transform = applyRotation;
        
        setInputPostFct(&t->mouse, postInputRotation);
        initMouseInputMode(t, &t->mouse, INPUT_ANGLE);
@@ -3403,10 +3577,13 @@ void initRotation(TransInfo *t)
        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->snap[1] = DEG2RAD(5.0);
+       t->snap[2] = DEG2RAD(1.0);
        
-       t->num.increment = 1.0f;
+       copy_v3_fl(t->num.val_inc, t->snap[2]);
+       t->num.unit_sys = t->scene->unit.system;
+       t->num.unit_use_radians = (t->scene->unit.system_rotation == USER_UNIT_ROT_RADIANS);
+       t->num.unit_type[0] = B_UNIT_ROTATION;
 
        if (t->flag & T_2D_EDIT)
                t->flag |= T_NO_CONSTRAINT;
@@ -3424,9 +3601,7 @@ static void ElementRotation(TransInfo *t, TransData *td, float mat[3][3], short
        const float *center;
 
        /* local constraint shouldn't alter center */
-       if (transdata_check_local_center(t) ||
-           ((around == V3D_LOCAL) && (t->options & CTX_MOVIECLIP)))
-       {
+       if (transdata_check_local_center(t, around)) {
                center = td->center;
        }
        else {
@@ -3641,13 +3816,13 @@ static void ElementRotation(TransInfo *t, TransData *td, float mat[3][3], short
        }
 }
 
-static void applyRotation(TransInfo *t, float angle, float axis[3])
+static void applyRotationValue(TransInfo *t, float angle, float axis[3])
 {
        TransData *td = t->data;
        float mat[3][3];
        int i;
        
-       vec_rot_to_mat3(mat, axis, angle);
+       axis_angle_normalized_to_mat3(mat, axis, angle);
        
        for (i = 0; i < t->total; i++, td++) {
                
@@ -3659,17 +3834,17 @@ static void applyRotation(TransInfo *t, float angle, float axis[3])
                
                if (t->con.applyRot) {
                        t->con.applyRot(t, td, axis, NULL);
-                       vec_rot_to_mat3(mat, axis, angle * td->factor);
+                       axis_angle_normalized_to_mat3(mat, axis, angle * td->factor);
                }
                else if (t->flag & T_PROP_EDIT) {
-                       vec_rot_to_mat3(mat, axis, angle * td->factor);
+                       axis_angle_normalized_to_mat3(mat, axis, angle * td->factor);
                }
                
                ElementRotation(t, td, mat, t->around);
        }
 }
 
-int Rotation(TransInfo *t, const int UNUSED(mval[2]))
+static void applyRotation(TransInfo *t, const int UNUSED(mval[2]))
 {
        char str[MAX_INFO_LEN];
        size_t ofs = 0;
@@ -3678,7 +3853,7 @@ int Rotation(TransInfo *t, const int UNUSED(mval[2]))
 
        final = t->values[0];
 
-       snapGrid(t, &final);
+       snapGridIncrement(t, &final);
 
        if ((t->con.mode & CON_APPLY) && t->con.applyRot) {
                t->con.applyRot(t, NULL, t->axis, NULL);
@@ -3699,58 +3874,65 @@ int Rotation(TransInfo *t, const int UNUSED(mval[2]))
                
                ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("Rot: %s %s %s"), &c[0], t->con.text, t->proptext);
 
-               /* Clamp between -180 and 180 */
-               final = angle_wrap_rad(DEG2RADF(final));
+               /* Clamp between -PI and PI */
+               final = angle_wrap_rad(final);
        }
        else {
                ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("Rot: %.2f%s %s"),
                                    RAD2DEGF(final), t->con.text, t->proptext);
        }
        
-       if (t->flag & (T_PROP_EDIT | T_PROP_CONNECTED)) {
+       if (t->flag & T_PROP_EDIT_ALL) {
                ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_(" Proportional size: %.2f"), t->prop_size);
        }
 
        t->values[0] = final;
        
-       applyRotation(t, final, t->axis);
+       applyRotationValue(t, final, t->axis);
        
        recalcData(t);
        
        ED_area_headerprint(t->sa, str);
-       
-       return 1;
 }
+/** \} */
 
 
-/* ************************** TRACKBALL *************************** */
+/* -------------------------------------------------------------------- */
+/* Transform (Rotation - Trackball) */
 
-void initTrackball(TransInfo *t)
+/** \name Transform Rotation - Trackball
+ * \{ */
+
+static void initTrackball(TransInfo *t)
 {
        t->mode = TFM_TRACKBALL;
-       t->transform = Trackball;
+       t->transform = applyTrackball;
 
        initMouseInputMode(t, &t->mouse, INPUT_TRACKBALL);
 
        t->idx_max = 1;
        t->num.idx_max = 1;
        t->snap[0] = 0.0f;
-       t->snap[1] = (float)((5.0 / 180) * M_PI);
-       t->snap[2] = t->snap[1] * 0.2f;
+       t->snap[1] = DEG2RAD(5.0);
+       t->snap[2] = DEG2RAD(1.0);
 
-       t->num.increment = 1.0f;
+       copy_v3_fl(t->num.val_inc, t->snap[2]);
+       t->num.unit_sys = t->scene->unit.system;
+       t->num.unit_use_radians = (t->scene->unit.system_rotation == USER_UNIT_ROT_RADIANS);
+       t->num.unit_type[0] = B_UNIT_ROTATION;
+       t->num.unit_type[1] = B_UNIT_ROTATION;
 
        t->flag |= T_NO_CONSTRAINT;
 }
 
-static void applyTrackball(TransInfo *t, float axis1[3], float axis2[3], float angles[2])
+static void applyTrackballValue(TransInfo *t, const float axis1[3], const float axis2[3], float angles[2])
 {
        TransData *td = t->data;
        float mat[3][3], smat[3][3], totmat[3][3];
        int i;
 
-       vec_rot_to_mat3(smat, axis1, angles[0]);
-       vec_rot_to_mat3(totmat, axis2, angles[1]);
+       axis_angle_normalized_to_mat3(smat, axis1, angles[0]);
+       axis_angle_normalized_to_mat3(totmat, axis2, angles[1]);
 
        mul_m3_m3m3(mat, smat, totmat);
 
@@ -3762,8 +3944,8 @@ static void applyTrackball(TransInfo *t, float axis1[3], float axis2[3], float a
                        continue;
 
                if (t->flag & T_PROP_EDIT) {
-                       vec_rot_to_mat3(smat, axis1, td->factor * angles[0]);
-                       vec_rot_to_mat3(totmat, axis2, td->factor * angles[1]);
+                       axis_angle_normalized_to_mat3(smat, axis1, td->factor * angles[0]);
+                       axis_angle_normalized_to_mat3(totmat, axis2, td->factor * angles[1]);
 
                        mul_m3_m3m3(mat, smat, totmat);
                }
@@ -3772,7 +3954,7 @@ static void applyTrackball(TransInfo *t, float axis1[3], float axis2[3], float a
        }
 }
 
-int Trackball(TransInfo *t, const int UNUSED(mval[2]))
+static void applyTrackball(TransInfo *t, const int UNUSED(mval[2]))
 {
        char str[MAX_INFO_LEN];
        size_t ofs = 0;
@@ -3788,7 +3970,7 @@ int Trackball(TransInfo *t, const int UNUSED(mval[2]))
        phi[0] = t->values[0];
        phi[1] = t->values[1];
 
-       snapGrid(t, phi);
+       snapGridIncrement(t, phi);
 
        if (hasNumInput(&t->num)) {
                char c[NUM_STR_REP_LEN * 2];
@@ -3799,39 +3981,40 @@ int Trackball(TransInfo *t, const int UNUSED(mval[2]))
 
                ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, 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 {
                ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("Trackball: %.2f %.2f %s"),
                                    RAD2DEGF(phi[0]), RAD2DEGF(phi[1]), t->proptext);
        }
 
-       if (t->flag & (T_PROP_EDIT | T_PROP_CONNECTED)) {
+       if (t->flag & T_PROP_EDIT_ALL) {
                ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_(" Proportional size: %.2f"), t->prop_size);
        }
 
-       vec_rot_to_mat3(smat, axis1, phi[0]);
-       vec_rot_to_mat3(totmat, axis2, phi[1]);
+       axis_angle_normalized_to_mat3(smat, axis1, phi[0]);
+       axis_angle_normalized_to_mat3(totmat, axis2, phi[1]);
 
        mul_m3_m3m3(mat, smat, totmat);
 
        // TRANSFORM_FIX_ME
        //copy_m3_m3(t->mat, mat);      // used in manipulator
 
-       applyTrackball(t, axis1, axis2, phi);
+       applyTrackballValue(t, axis1, axis2, phi);
 
        recalcData(t);
 
        ED_area_headerprint(t->sa, str);
-
-       return 1;
 }
+/** \} */
 
-/* ************************** TRANSLATION *************************** */
 
-void initTranslation(TransInfo *t)
+/* -------------------------------------------------------------------- */
+/* Transform (Translation) */
+
+/** \name Transform Translation
+ * \{ */
+
+static void initTranslation(TransInfo *t)
 {
        if (t->spacetype == SPACE_ACTION) {
                /* this space uses time translate */
@@ -3839,7 +4022,7 @@ void initTranslation(TransInfo *t)
        }
 
        t->mode = TFM_TRANSLATION;
-       t->transform = Translation;
+       t->transform = applyTranslation;
 
        initMouseInputMode(t, &t->mouse, INPUT_VECTOR);
 
@@ -3863,19 +4046,23 @@ void initTranslation(TransInfo *t)
        }
        else if (t->spacetype == SPACE_NODE) {
                t->snap[0] = 0.0f;
-               t->snap[1] = 125.0f;
-               t->snap[2] = 25.0f;
+               t->snap[1] = ED_node_grid_size() * NODE_GRID_STEPS;
+               t->snap[2] = ED_node_grid_size();
        }
        else {
                t->snap[0] = 0.0f;
                t->snap[1] = t->snap[2] = 1.0f;
        }
 
-       t->num.increment = t->snap[1];
+       copy_v3_fl(t->num.val_inc, t->snap[1]);
+       t->num.unit_sys = t->scene->unit.system;
+       t->num.unit_type[0] = B_UNIT_LENGTH;
+       t->num.unit_type[1] = B_UNIT_LENGTH;
+       t->num.unit_type[2] = B_UNIT_LENGTH;
+
 }
 
-/* We assume str is MAX_INFO_LEN long. */
-static void headerTranslation(TransInfo *t, float vec[3], char *str)
+static void headerTranslation(TransInfo *t, float vec[3], char str[MAX_INFO_LEN])
 {
        size_t ofs = 0;
        char tvec[NUM_STR_REP_LEN * 3];
@@ -3899,7 +4086,7 @@ static void headerTranslation(TransInfo *t, float vec[3], char *str)
 
                        for (i = 0; i < 3; i++) {
                                bUnit_AsString(&tvec[NUM_STR_REP_LEN * i], NUM_STR_REP_LEN, dvec[i] * t->scene->unit.scale_length,
-                                              4, t->scene->unit.system, B_UNIT_LENGTH, do_split, 1);
+                                              4, t->scene->unit.system, B_UNIT_LENGTH, do_split, true);
                        }
                }
                else {
@@ -3911,7 +4098,7 @@ static void headerTranslation(TransInfo *t, float vec[3], char *str)
 
        if (!(t->flag & T_2D_EDIT) && t->scene->unit.system)
                bUnit_AsString(distvec, sizeof(distvec), dist * t->scene->unit.scale_length, 4, t->scene->unit.system,
-                              B_UNIT_LENGTH, t->scene->unit.flag & USER_UNIT_OPT_SPLIT, 0);
+                              B_UNIT_LENGTH, t->scene->unit.flag & USER_UNIT_OPT_SPLIT, false);
        else if (dist > 1e10f || dist < -1e10f)     /* prevent string buffer overflow */
                BLI_snprintf(distvec, NUM_STR_REP_LEN, "%.4e", dist);
        else
@@ -3942,6 +4129,7 @@ static void headerTranslation(TransInfo *t, float vec[3], char *str)
                                ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, "D: %s   D: %s  D: %s (%s)%s %s  %s",
                                                    &tvec[0], &tvec[NUM_STR_REP_LEN], &tvec[NUM_STR_REP_LEN * 2], distvec,
                                                    t->con.text, t->proptext, autoik);
+                               break;
                }
        }
        else {
@@ -3956,12 +4144,12 @@ static void headerTranslation(TransInfo *t, float vec[3], char *str)
                }
        }
 
-       if (t->flag & (T_PROP_EDIT | T_PROP_CONNECTED)) {
+       if (t->flag & T_PROP_EDIT_ALL) {
                ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_(" Proportional size: %.2f"), t->prop_size);
        }
 }
 
-static void applyTranslation(TransInfo *t, float vec[3])
+static void applyTranslationValue(TransInfo *t, float vec[3])
 {
        TransData *td = t->data;
        float tvec[3];
@@ -4028,7 +4216,7 @@ static void applyTranslation(TransInfo *t, float vec[3])
 }
 
 /* uses t->vec to store actual translation in */
-int Translation(TransInfo *t, const int UNUSED(mval[2]))
+static void applyTranslation(TransInfo *t, const int UNUSED(mval[2]))
 {
        char str[MAX_INFO_LEN];
 
@@ -4044,7 +4232,7 @@ int Translation(TransInfo *t, const int UNUSED(mval[2]))
                headerTranslation(t, pvec, str);
        }
        else {
-               snapGrid(t, t->values);
+               snapGridIncrement(t, t->values);
                applyNumInput(&t->num, t->values);
                if (hasNumInput(&t->num)) {
                        removeAspectRatio(t, t->values);
@@ -4053,17 +4241,17 @@ int Translation(TransInfo *t, const int UNUSED(mval[2]))
                headerTranslation(t, t->values, str);
        }
 
-       applyTranslation(t, t->values);
+       applyTranslationValue(t, t->values);
 
        /* evil hack - redo translation if clipping needed */
        if (t->flag & T_CLIP_UV && clipUVTransform(t, t->values, 0)) {
-               applyTranslation(t, t->values);
+               applyTranslationValue(t, t->values);
 
                /* In proportional edit it can happen that */
                /* vertices in the radius of the brush end */
                /* outside the clipping area               */
                /* XXX HACK - dg */
-               if (t->flag & (T_PROP_EDIT | T_PROP_CONNECTED)) {
+               if (t->flag & T_PROP_EDIT_ALL) {
                        clipUVData(t);
                }
        }
@@ -4071,13 +4259,17 @@ int Translation(TransInfo *t, const int UNUSED(mval[2]))
        recalcData(t);
 
        ED_area_headerprint(t->sa, str);
-
-       return 1;
 }
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+/* Transform (Shrink-Fatten) */
 
-/* ************************** SHRINK/FATTEN *************************** */
+/** \name Transform Shrink-Fatten
+ * \{ */
 
-void initShrinkFatten(TransInfo *t)
+static void initShrinkFatten(TransInfo *t)
 {
        // If not in mesh edit mode, fallback to Resize
        if (t->obedit == NULL || t->obedit->type != OB_MESH) {
@@ -4085,7 +4277,7 @@ void initShrinkFatten(TransInfo *t)
        }
        else {
                t->mode = TFM_SHRINKFATTEN;
-               t->transform = ShrinkFatten;
+               t->transform = applyShrinkFatten;
 
                initMouseInputMode(t, &t->mouse, INPUT_VERTICAL_ABSOLUTE);
 
@@ -4095,14 +4287,16 @@ void initShrinkFatten(TransInfo *t)
                t->snap[1] = 1.0f;
                t->snap[2] = t->snap[1] * 0.1f;
 
-               t->num.increment = t->snap[1];
+               copy_v3_fl(t->num.val_inc, t->snap[1]);
+               t->num.unit_sys = t->scene->unit.system;
+               t->num.unit_type[0] = B_UNIT_LENGTH;
 
                t->flag |= T_NO_CONSTRAINT;
        }
 }
 
 
-int ShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
+static void applyShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
 {
        float distance;
        int i;
@@ -4112,7 +4306,7 @@ int ShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
 
        distance = -t->values[0];
 
-       snapGrid(t, &distance);
+       snapGridIncrement(t, &distance);
 
        applyNumInput(&t->num, &distance);
 
@@ -4133,14 +4327,14 @@ int ShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
        }
        ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, ", (");
 
-       {
+       if (t->keymap) {
                wmKeyMapItem *kmi = WM_modalkeymap_find_propvalue(t->keymap, TFM_MODAL_RESIZE);
                if (kmi) {
                        ofs += WM_keymap_item_to_string(kmi, str + ofs, MAX_INFO_LEN - ofs);
                }
        }
        BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_(" or Alt) Even Thickness %s"),
-                    (t->flag & T_ALT_TRANSFORM) ? IFACE_("ON") : IFACE_("OFF"));
+                    WM_bool_as_string((t->flag & T_ALT_TRANSFORM) != 0));
        /* done with header string */
 
 
@@ -4166,33 +4360,39 @@ int ShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
        recalcData(t);
 
        ED_area_headerprint(t->sa, str);
-
-       return 1;
 }
+/** \} */
+
 
-/* ************************** TILT *************************** */
+/* -------------------------------------------------------------------- */
+/* Transform (Tilt) */
 
-void initTilt(TransInfo *t)
+/** \name Transform Tilt
+ * \{ */
+
+static void initTilt(TransInfo *t)
 {
        t->mode = TFM_TILT;
-       t->transform = Tilt;
+       t->transform = applyTilt;
 
        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->snap[1] = DEG2RAD(5.0);
+       t->snap[2] = DEG2RAD(1.0);
 
-       t->num.increment = t->snap[1];
+       copy_v3_fl(t->num.val_inc, t->snap[2]);
+       t->num.unit_sys = t->scene->unit.system;
+       t->num.unit_use_radians = (t->scene->unit.system_rotation == USER_UNIT_ROT_RADIANS);
+       t->num.unit_type[0] = B_UNIT_ROTATION;
 
        t->flag |= T_NO_CONSTRAINT | T_NO_PROJECT;
 }
 
 
-
-int Tilt(TransInfo *t, const int UNUSED(mval[2]))
+static void applyTilt(TransInfo *t, const int UNUSED(mval[2]))
 {
        TransData *td = t->data;
        int i;
@@ -4202,7 +4402,7 @@ int Tilt(TransInfo *t, const int UNUSED(mval[2]))
 
        final = t->values[0];
 
-       snapGrid(t, &final);
+       snapGridIncrement(t, &final);
 
        if (hasNumInput(&t->num)) {
                char c[NUM_STR_REP_LEN];
@@ -4213,8 +4413,6 @@ int Tilt(TransInfo *t, const int UNUSED(mval[2]))
 
                BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Tilt: %s° %s"), &c[0], t->proptext);
 
-               final = DEG2RADF(final);
-
                /* XXX For some reason, this seems needed for this op, else RNA prop is not updated... :/ */
                t->values[0] = final;
        }
@@ -4237,17 +4435,20 @@ int Tilt(TransInfo *t, const int UNUSED(mval[2]))
        recalcData(t);
 
        ED_area_headerprint(t->sa, str);
-
-       return 1;
 }
+/** \} */
+
 
+/* -------------------------------------------------------------------- */
+/* Transform (Curve Shrink/Fatten) */
 
-/* ******************** Curve Shrink/Fatten *************** */
+/** \name Transform Curve Shrink/Fatten
+ * \{ */
 
-void initCurveShrinkFatten(TransInfo *t)
+static void initCurveShrinkFatten(TransInfo *t)
 {
        t->mode = TFM_CURVE_SHRINKFATTEN;
-       t->transform = CurveShrinkFatten;
+       t->transform = applyCurveShrinkFatten;
 
        initMouseInputMode(t, &t->mouse, INPUT_SPRING);
 
@@ -4257,15 +4458,17 @@ void initCurveShrinkFatten(TransInfo *t)
        t->snap[1] = 0.1f;
        t->snap[2] = t->snap[1] * 0.1f;
 
-       t->num.increment = t->snap[1];
+       copy_v3_fl(t->num.val_inc, t->snap[1]);
+       t->num.unit_sys = t->scene->unit.system;
+       t->num.unit_type[0] = B_UNIT_NONE;
 
        t->flag |= T_NO_ZERO;
-       t->num.flag |= NUM_NO_ZERO;
+       t->num.val_flag[0] |= NUM_NO_ZERO;
 
        t->flag |= T_NO_CONSTRAINT;
 }
 
-int CurveShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
+static void applyCurveShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
 {
        TransData *td = t->data;
        float ratio;
@@ -4274,7 +4477,7 @@ int CurveShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
 
        ratio = t->values[0];
 
-       snapGrid(t, &ratio);
+       snapGridIncrement(t, &ratio);
 
        applyNumInput(&t->num, &ratio);
 
@@ -4307,15 +4510,20 @@ int CurveShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
        recalcData(t);
 
        ED_area_headerprint(t->sa, str);
-
-       return 1;
 }
+/** \} */
 
 
-void initMaskShrinkFatten(TransInfo *t)
+/* -------------------------------------------------------------------- */
+/* Transform (Mask Shrink/Fatten) */
+
+/** \name Transform Mask Shrink/Fatten
+ * \{ */
+
+static void initMaskShrinkFatten(TransInfo *t)
 {
        t->mode = TFM_MASK_SHRINKFATTEN;
-       t->transform = MaskShrinkFatten;
+       t->transform = applyMaskShrinkFatten;
 
        initMouseInputMode(t, &t->mouse, INPUT_SPRING);
 
@@ -4325,15 +4533,17 @@ void initMaskShrinkFatten(TransInfo *t)
        t->snap[1] = 0.1f;
        t->snap[2] = t->snap[1] * 0.1f;
 
-       t->num.increment = t->snap[1];
+       copy_v3_fl(t->num.val_inc, t->snap[1]);
+       t->num.unit_sys = t->scene->unit.system;
+       t->num.unit_type[0] = B_UNIT_NONE;
 
        t->flag |= T_NO_ZERO;
-       t->num.flag |= NUM_NO_ZERO;
+       t->num.val_flag[0] |= NUM_NO_ZERO;
 
        t->flag |= T_NO_CONSTRAINT;
 }
 
-int MaskShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
+static void applyMaskShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
 {
        TransData *td;
        float ratio;
@@ -4342,7 +4552,7 @@ int MaskShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
 
        ratio = t->values[0];
 
-       snapGrid(t, &ratio);
+       snapGridIncrement(t, &ratio);
 
        applyNumInput(&t->num, &ratio);
 
@@ -4396,16 +4606,20 @@ int MaskShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
        recalcData(t);
 
        ED_area_headerprint(t->sa, str);
-
-       return 1;
 }
+/** \} */
+
 
-/* ************************** PUSH/PULL *************************** */
+/* -------------------------------------------------------------------- */
+/* Transform (Push/Pull) */
 
-void initPushPull(TransInfo *t)
+/** \name Transform Push/Pull
+ * \{ */
+
+static void initPushPull(TransInfo *t)
 {
        t->mode = TFM_PUSHPULL;
-       t->transform = PushPull;
+       t->transform = applyPushPull;
 
        initMouseInputMode(t, &t->mouse, INPUT_VERTICAL_ABSOLUTE);
 
@@ -4415,11 +4629,13 @@ void initPushPull(TransInfo *t)
        t->snap[1] = 1.0f;
        t->snap[2] = t->snap[1] * 0.1f;
 
-       t->num.increment = t->snap[1];
+       copy_v3_fl(t->num.val_inc, t->snap[1]);
+       t->num.unit_sys = t->scene->unit.system;
+       t->num.unit_type[0] = B_UNIT_LENGTH;
 }
 
 
-int PushPull(TransInfo *t, const int UNUSED(mval[2]))
+static void applyPushPull(TransInfo *t, const int UNUSED(mval[2]))
 {
        float vec[3], axis[3];
        float distance;
@@ -4429,7 +4645,7 @@ int PushPull(TransInfo *t, const int UNUSED(mval[2]))
 
        distance = t->values[0];
 
-       snapGrid(t, &distance);
+       snapGridIncrement(t, &distance);
 
        applyNumInput(&t->num, &distance);
 
@@ -4481,131 +4697,20 @@ int PushPull(TransInfo *t, const int UNUSED(mval[2]))
        recalcData(t);
 
        ED_area_headerprint(t->sa, str);
-
-       return 1;
 }
+/** \} */
 
-/* ************************** BEVEL **************************** */
-
-void initBevel(TransInfo *t)
-{
-       t->transform = Bevel;
-       t->handleEvent = handleEventBevel;
-
-       initMouseInputMode(t, &t->mouse, INPUT_HORIZONTAL_ABSOLUTE);
-
-       t->mode = TFM_BEVEL;
-       t->flag |= T_NO_CONSTRAINT;
-       t->num.flag |= NUM_NO_NEGATIVE;
-
-       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];
-
-       /* DON'T KNOW WHY THIS IS NEEDED */
-       if (G.editBMesh->imval[0] == 0 && G.editBMesh->imval[1] == 0) {
-               /* save the initial mouse co */
-               G.editBMesh->imval[0] = t->imval[0];
-               G.editBMesh->imval[1] = t->imval[1];
-       }
-       else {
-               /* restore the mouse co from a previous call to initTransform() */
-               t->imval[0] = G.editBMesh->imval[0];
-               t->imval[1] = G.editBMesh->imval[1];
-       }
-}
-
-int handleEventBevel(TransInfo *t, const wmEvent *event)
-{
-       if (event->val == KM_PRESS) {
-               if (!G.editBMesh) return 0;
-
-               switch (event->type) {
-                       case MIDDLEMOUSE:
-                               G.editBMesh->options ^= BME_BEVEL_VERT;
-                               t->state = TRANS_CANCEL;
-                               return 1;
-                       //case PADPLUSKEY:
-                       //      G.editBMesh->options ^= BME_BEVEL_RES;
-                       //      G.editBMesh->res += 1;
-                       //      if (G.editBMesh->res > 4) {
-                       //              G.editBMesh->res = 4;
-                       //      }
-                       //      t->state = TRANS_CANCEL;
-                       //      return 1;
-                       //case PADMINUS:
-                       //      G.editBMesh->options ^= BME_BEVEL_RES;
-                       //      G.editBMesh->res -= 1;
-                       //      if (G.editBMesh->res < 0) {
-                       //              G.editBMesh->res = 0;
-                       //      }
-                       //      t->state = TRANS_CANCEL;
-                       //      return 1;
-                       default:
-                               return 0;
-               }
-       }
-       return 0;
-}
-
-int Bevel(TransInfo *t, const int UNUSED(mval[2]))
-{
-       float distance, d;
-       int i;
-       char str[MAX_INFO_LEN];
-       const char *mode;
-       TransData *td = t->data;
-
-       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);
-
-       snapGrid(t, &distance);
-
-       applyNumInput(&t->num, &distance);
-
-       /* header print for NumInput */
-       if (hasNumInput(&t->num)) {
-               char c[NUM_STR_REP_LEN];
 
-               outputNumInput(&(t->num), c);
+/* -------------------------------------------------------------------- */
+/* Transform (Bevel Weight) */
 
-               BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Bevel - Dist: %s, Mode: %s (MMB to toggle))"), c, mode);
-       }
-       else {
-               /* default header print */
-               BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Bevel - Dist: %.4f, Mode: %s (MMB to toggle))"), distance, mode);
-       }
+/** \name Transform Bevel Weight
+ * \{ */
 
-       if (distance < 0) distance = -distance;
-       for (i = 0; i < t->total; i++, td++) {
-               if (td->axismtx[1][0] > 0 && distance > td->axismtx[1][0]) {
-                       d = td->axismtx[1][0];
-               }
-               else {
-                       d = distance;
-               }
-               madd_v3_v3v3fl(td->loc, td->center, td->axismtx[0], (*td->val) * d);
-       }
-
-       recalcData(t);
-
-       ED_area_headerprint(t->sa, str);
-
-       return 1;
-}
-
-/* ************************** BEVEL WEIGHT *************************** */
-
-void initBevelWeight(TransInfo *t)
+static void initBevelWeight(TransInfo *t)
 {
        t->mode = TFM_BWEIGHT;
-       t->transform = BevelWeight;
+       t->transform = applyBevelWeight;
 
        initMouseInputMode(t, &t->mouse, INPUT_SPRING);
 
@@ -4615,12 +4720,14 @@ void initBevelWeight(TransInfo *t)
        t->snap[1] = 0.1f;
        t->snap[2] = t->snap[1] * 0.1f;
 
-       t->num.increment = t->snap[1];
+       copy_v3_fl(t->num.val_inc, t->snap[1]);
+       t->num.unit_sys = t->scene->unit.system;
+       t->num.unit_type[0] = B_UNIT_NONE;
 
        t->flag |= T_NO_CONSTRAINT | T_NO_PROJECT;
 }
 
-int BevelWeight(TransInfo *t, const int UNUSED(mval[2]))
+static void applyBevelWeight(TransInfo *t, const int UNUSED(mval[2]))
 {
        TransData *td = t->data;
        float weight;
@@ -4632,7 +4739,7 @@ int BevelWeight(TransInfo *t, const int UNUSED(mval[2]))
        weight -= 1.0f;
        if (weight > 1.0f) weight = 1.0f;
 
-       snapGrid(t, &weight);
+       snapGridIncrement(t, &weight);
 
        applyNumInput(&t->num, &weight);
 
@@ -4669,16 +4776,20 @@ int BevelWeight(TransInfo *t, const int UNUSED(mval[2]))
        recalcData(t);
 
        ED_area_headerprint(t->sa, str);
-
-       return 1;
 }
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+/* Transform (Crease) */
 
-/* ************************** CREASE *************************** */
+/** \name Transform Crease
+ * \{ */
 
-void initCrease(TransInfo *t)
+static void initCrease(TransInfo *t)
 {
        t->mode = TFM_CREASE;
-       t->transform = Crease;
+       t->transform = applyCrease;
 
        initMouseInputMode(t, &t->mouse, INPUT_SPRING);
 
@@ -4688,12 +4799,14 @@ void initCrease(TransInfo *t)
        t->snap[1] = 0.1f;
        t->snap[2] = t->snap[1] * 0.1f;
 
-       t->num.increment = t->snap[1];
+       copy_v3_fl(t->num.val_inc, t->snap[1]);
+       t->num.unit_sys = t->scene->unit.system;
+       t->num.unit_type[0] = B_UNIT_NONE;
 
        t->flag |= T_NO_CONSTRAINT | T_NO_PROJECT;
 }
 
-int Crease(TransInfo *t, const int UNUSED(mval[2]))
+static void applyCrease(TransInfo *t, const int UNUSED(mval[2]))
 {
        TransData *td = t->data;
        float crease;
@@ -4705,7 +4818,7 @@ int Crease(TransInfo *t, const int UNUSED(mval[2]))
        crease -= 1.0f;
        if (crease > 1.0f) crease = 1.0f;
 
-       snapGrid(t, &crease);
+       snapGridIncrement(t, &crease);
 
        applyNumInput(&t->num, &crease);
 
@@ -4745,32 +4858,41 @@ int Crease(TransInfo *t, const int UNUSED(mval[2]))
        recalcData(t);
 
        ED_area_headerprint(t->sa, str);
-
-       return 1;
 }
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+/* Transform (EditBone (B-bone) width scaling) */
 
-/* ******************** EditBone (B-bone) width scaling *************** */
+/** \name Transform B-bone width scaling
+ * \{ */
 
-void initBoneSize(TransInfo *t)
+static void initBoneSize(TransInfo *t)
 {
        t->mode = TFM_BONESIZE;
-       t->transform = BoneSize;
+       t->transform = applyBoneSize;
 
        initMouseInputMode(t, &t->mouse, INPUT_SPRING_FLIP);
 
        t->idx_max = 2;
        t->num.idx_max = 2;
-       t->num.flag |= NUM_NULL_ONE;
+       t->num.val_flag[0] |= NUM_NULL_ONE;
+       t->num.val_flag[1] |= NUM_NULL_ONE;
+       t->num.val_flag[2] |= NUM_NULL_ONE;
        t->num.flag |= NUM_AFFECT_ALL;
        t->snap[0] = 0.0f;
        t->snap[1] = 0.1f;
        t->snap[2] = t->snap[1] * 0.1f;
 
-       t->num.increment = t->snap[1];
+       copy_v3_fl(t->num.val_inc, t->snap[1]);
+       t->num.unit_sys = t->scene->unit.system;
+       t->num.unit_type[0] = B_UNIT_NONE;
+       t->num.unit_type[1] = B_UNIT_NONE;
+       t->num.unit_type[2] = B_UNIT_NONE;
 }
 
-/* We assume str is MAX_INFO_LEN long. */
-static void headerBoneSize(TransInfo *t, float vec[3], char *str)
+static void headerBoneSize(TransInfo *t, float vec[3], char str[MAX_INFO_LEN])
 {
        char tvec[NUM_STR_REP_LEN * 3];
        if (hasNumInput(&t->num)) {
@@ -4816,7 +4938,7 @@ static void ElementBoneSize(TransInfo *t, TransData *td, float mat[3][3])
        td->loc[1] = oldy;
 }
 
-int BoneSize(TransInfo *t, const int mval[2])
+static void applyBoneSize(TransInfo *t, const int mval[2])
 {
        TransData *td = t->data;
        float size[3], mat[3][3];
@@ -4835,7 +4957,7 @@ int BoneSize(TransInfo *t, const int mval[2])
        
        size[0] = size[1] = size[2] = ratio;
        
-       snapGrid(t, size);
+       snapGridIncrement(t, size);
        
        if (hasNumInput(&t->num)) {
                applyNumInput(&t->num, size);
@@ -4865,17 +4987,20 @@ int BoneSize(TransInfo *t, const int mval[2])
        recalcData(t);
        
        ED_area_headerprint(t->sa, str);
-       
-       return 1;
 }
+/** \} */
+
 
+/* -------------------------------------------------------------------- */
+/* Transform (Bone Envelope) */
 
-/* ******************** EditBone envelope *************** */
+/** \name Transform Bone Envelope
+ * \{ */
 
-void initBoneEnvelope(TransInfo *t)
+static void initBoneEnvelope(TransInfo *t)
 {
        t->mode = TFM_BONE_ENVELOPE;
-       t->transform = BoneEnvelope;
+       t->transform = applyBoneEnvelope;
        
        initMouseInputMode(t, &t->mouse, INPUT_SPRING);
        
@@ -4885,12 +5010,14 @@ void initBoneEnvelope(TransInfo *t)
        t->snap[1] = 0.1f;
        t->snap[2] = t->snap[1] * 0.1f;
        
-       t->num.increment = t->snap[1];
+       copy_v3_fl(t->num.val_inc, t->snap[1]);
+       t->num.unit_sys = t->scene->unit.system;
+       t->num.unit_type[0] = B_UNIT_NONE;
 
        t->flag |= T_NO_CONSTRAINT | T_NO_PROJECT;
 }
 
-int BoneEnvelope(TransInfo *t, const int UNUSED(mval[2]))
+static void applyBoneEnvelope(TransInfo *t, const int UNUSED(mval[2]))
 {
        TransData *td = t->data;
        float ratio;
@@ -4899,7 +5026,7 @@ int BoneEnvelope(TransInfo *t, const int UNUSED(mval[2]))
        
        ratio = t->values[0];
        
-       snapGrid(t, &ratio);
+       snapGridIncrement(t, &ratio);
        
        applyNumInput(&t->num, &ratio);
        
@@ -4933,11 +5060,16 @@ int BoneEnvelope(TransInfo *t, const int UNUSED(mval[2]))
        recalcData(t);
        
        ED_area_headerprint(t->sa, str);
-       
-       return 1;
 }
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+/* Transform (Edge Slide) */
+
+/** \name Transform Edge Slide
+ * \{ */
 
-/* ********************  Edge Slide   *************** */
 static BMEdge *get_other_edge(BMVert *v, BMEdge *e)
 {
        BMIter iter;
@@ -4952,6 +5084,26 @@ static BMEdge *get_other_edge(BMVert *v, BMEdge *e)
        return NULL;
 }
 
+/* interpoaltes along a line made up of 2 segments (used for edge slide) */
+static void interp_line_v3_v3v3v3(float p[3], const float v1[3], const float v2[3], const float v3[3], const float t)
+{
+       float t_mid, t_delta;
+
+       /* could be pre-calculated */
+       t_mid = line_point_factor_v3(v2, v1, v3);
+
+       t_delta = t - t_mid;
+       if (fabsf(t_delta) < FLT_EPSILON) {
+               copy_v3_v3(p, v2);
+       }
+       else if (t_delta < 0.0f) {
+               interp_v3_v3v3(p, v1, v2, t / t_mid);
+       }
+       else {
+               interp_v3_v3v3(p, v2, v3, (t - t_mid) / (1.0f - t_mid));
+       }
+}
+
 static void len_v3_ensure(float v[3], const float length)
 {
        normalize_v3(v);
@@ -4977,7 +5129,7 @@ static bool bm_loop_calc_opposite_co(BMLoop *l_tmp,
                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))
+                                       l_tmp->v->co, plane_no))
                {
                        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 */
@@ -5013,12 +5165,11 @@ static BMLoop *get_next_loop(BMVert *v, BMLoop *l,
        int i = 0;
 
        BLI_assert(BM_edge_share_vert(e_prev, e_next) == v);
+       BLI_assert(BM_vert_in_edge(l->e, v));
 
        l_first = l;
        do {
-               l = BM_face_other_edge_loop(l->f, l->e, v);
-               if (l->radial_next == l)
-                       return NULL;
+               l = BM_loop_other_edge_loop(l, v);
                
                if (l->e == e_next) {
                        if (i) {
@@ -5076,18 +5227,17 @@ static BMLoop *get_next_loop(BMVert *v, BMLoop *l,
                        i += 1;
                }
 
-               if (BM_face_other_edge_loop(l->f, l->e, v)->e == e_next) {
+               if (BM_loop_other_edge_loop(l, 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);
+                       return BM_loop_other_edge_loop(l, v);
                }
-               
-               BLI_assert(l != l->radial_next);
-               l = l->radial_next;
-       } while (l != l_first);
+
+       } while ((l != l->radial_next) &&
+                ((l = l->radial_next) != l_first));
 
        if (i) {
                len_v3_ensure(vec_accum, vec_accum_len / (float)i);
@@ -5128,7 +5278,7 @@ static void calcNonProportionalEdgeSlide(TransInfo *t, EdgeSlideData *sld, const
 
                for (i = 0; i < sld->totsv; i++, sv++) {
                        /* Set length */
-                       sv->edge_len = len_v3v3(sv->upvec, sv->downvec);
+                       sv->edge_len = len_v3v3(sv->dir_a, sv->dir_b);
 
                        ED_view3d_project_float_v2_m4(ar, sv->v->co, v_proj, projectMat);
                        dist = len_squared_v2v2(mval, v_proj);
@@ -5143,26 +5293,25 @@ static void calcNonProportionalEdgeSlide(TransInfo *t, EdgeSlideData *sld, const
        }
 }
 
-static int createEdgeSlideVerts(TransInfo *t)
+static bool createEdgeSlideVerts(TransInfo *t)
 {
-       BMEditMesh *em = BMEdit_FromObject(t->obedit);
+       BMEditMesh *em = BKE_editmesh_from_object(t->obedit);
        BMesh *bm = em->bm;
        BMIter iter;
-       BMEdge *e, *e1;
-       BMVert *v, *v2;
+       BMEdge *e;
+       BMVert *v;
        TransDataEdgeSlideVert *sv_array;
        int sv_tot;
        BMBVHTree *btree;
-       SmallHash table;
+       int *sv_table;  /* BMVert -> sv_array index */
        EdgeSlideData *sld = MEM_callocN(sizeof(*sld), "sld");
        View3D *v3d = NULL;
        RegionView3D *rv3d = NULL;
        ARegion *ar = t->ar;
        float projectMat[4][4];
        float mval[2] = {(float)t->mval[0], (float)t->mval[1]};
-       float start[3] = {0.0f, 0.0f, 0.0f}, end[3] = {0.0f, 0.0f, 0.0f};
-       float vec[3], vec2[3] /*, lastvec[3], size, dis=0.0, z */ /* UNUSED */;
-       float dir[3], maxdist, (*loop_dir)[3], *loop_maxdist;
+       float mval_start[2], mval_end[2];
+       float mval_dir[3], maxdist, (*loop_dir)[3], *loop_maxdist;
        int numsel, i, j, loop_nr, l_nr;
        int use_btree_disp;
 
@@ -5172,16 +5321,18 @@ static int createEdgeSlideVerts(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);
+       if ((t->settings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT) &&
+           /* don't do this at all for non-basis shape keys, too easy to
+                * accidentally break uv maps or vertex colors then */
+           (bm->shapenr <= 1))
+       {
+               sld->use_origfaces = true;
        }
        else {
-               btree = NULL;
+               sld->use_origfaces = false;
        }
 
-       sld->is_proportional = TRUE;
+       sld->is_proportional = true;
        sld->curr_sv_index = 0;
        sld->flipped_vtx = FALSE;
 
@@ -5192,11 +5343,7 @@ static int createEdgeSlideVerts(TransInfo *t)
        else {
                ED_view3d_ob_project_mat_get(rv3d, t->obedit, projectMat);
        }
-       
-       BLI_smallhash_init(&sld->vhash);
-       BLI_smallhash_init(&sld->origfaces);
-       BLI_smallhash_init(&table);
-       
+
        /*ensure valid selection*/
        BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
                if (BM_elem_flag_test(v, BM_ELEM_SELECT)) {
@@ -5214,41 +5361,43 @@ static int createEdgeSlideVerts(TransInfo *t)
 
                        if (numsel == 0 || numsel > 2) {
                                MEM_freeN(sld);
-                               if (btree)
-                                       BMBVH_FreeBVH(btree);
-                               return 0; /* invalid edge selection */
+                               return false; /* invalid edge selection */
                        }
                }
        }
 
        BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
                if (BM_elem_flag_test(e, BM_ELEM_SELECT)) {
-                       if (!BM_edge_is_manifold(e)) {
+                       /* note, any edge with loops can work, but we won't get predictable results, so bail out */
+                       if (!BM_edge_is_manifold(e) && !BM_edge_is_boundary(e)) {
+                               /* can edges with at least once face user */
                                MEM_freeN(sld);
-                               if (btree)
-                                       BMBVH_FreeBVH(btree);
-                               return 0; /* can only handle exactly 2 faces around each edge */
+                               return false;
                        }
                }
        }
 
+       sv_table = MEM_mallocN(sizeof(*sv_table) * bm->totvert, __func__);
+
        j = 0;
-       BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
+       BM_ITER_MESH_INDEX (v, &iter, bm, BM_VERTS_OF_MESH, i) {
                if (BM_elem_flag_test(v, BM_ELEM_SELECT)) {
                        BM_elem_flag_enable(v, BM_ELEM_TAG);
-                       BLI_smallhash_insert(&table, (uintptr_t)v, SET_INT_IN_POINTER(j));
+                       sv_table[i] = j;
                        j += 1;
                }
                else {
                        BM_elem_flag_disable(v, BM_ELEM_TAG);
+                       sv_table[i] = -1;
                }
+               BM_elem_index_set(v, i); /* set_inline */
        }
+       bm->elem_index_dirty &= ~BM_VERT;
 
        if (!j) {
                MEM_freeN(sld);
-               if (btree)
-                       BMBVH_FreeBVH(btree);
-               return 0;
+               MEM_freeN(sv_table);
+               return false;
        }
 
        sv_tot = j;
@@ -5256,7 +5405,8 @@ static int createEdgeSlideVerts(TransInfo *t)
        loop_nr = 0;
 
        while (1) {
-               BMLoop *l, *l1, *l2;
+               float vec_a[3], vec_b[3];
+               BMLoop *l_a, *l_b;
                BMVert *v_first;
 
                v = NULL;
@@ -5296,88 +5446,159 @@ static int createEdgeSlideVerts(TransInfo *t)
 
                BM_elem_flag_disable(v, BM_ELEM_TAG);
 
-               l1 = l2 = l = NULL;
-               l1 = e->l;
-               l2 = e->l->radial_next;
+               l_a = e->l;
+               l_b = e->l->radial_next;
+
+               /* regarding e_next, use get_next_loop()'s improved interpolation where possible */
+               {
+                       BMEdge *e_next = get_other_edge(v, e);
+                       if (e_next) {
+                               get_next_loop(v, l_a, e, e_next, vec_a);
+                       }
+                       else {
+                               BMLoop *l_tmp = BM_loop_other_edge_loop(l_a, v);
+                               if (BM_vert_edge_count_nonwire(v) == 2)
+                                       get_next_loop(v, l_a, e, l_tmp->e, vec_a);
+                               else
+                                       sub_v3_v3v3(vec_a, BM_edge_other_vert(l_tmp->e, v)->co, v->co);
+                       }
+               }
 
-               l = BM_face_other_edge_loop(l1->f, l1->e, v);
-               sub_v3_v3v3(vec, BM_edge_other_vert(l->e, v)->co, v->co);
+               /* !BM_edge_is_boundary(e); */
+               if (l_b != l_a) {
+                       BMEdge *e_next = get_other_edge(v, e);
+                       if (e_next) {
+                               get_next_loop(v, l_b, e, e_next, vec_b);
+                       }
+                       else {
+                               BMLoop *l_tmp = BM_loop_other_edge_loop(l_b, v);
+                               if (BM_vert_edge_count_nonwire(v) == 2)
+                                       get_next_loop(v, l_b, e, l_tmp->e, vec_b);
+                               else
+                                       sub_v3_v3v3(vec_b, BM_edge_other_vert(l_tmp->e, v)->co, v->co);
 
-               if (l2 != l1) {
-                       l = BM_face_other_edge_loop(l2->f, l2->e, v);
-                       sub_v3_v3v3(vec2, BM_edge_other_vert(l->e, v)->co, v->co);
+                       }
                }
                else {
-                       l2 = NULL;
+                       l_b = NULL;
                }
 
                /*iterate over the loop*/
                v_first = v;
                do {
+                       bool l_a_ok_prev;
+                       bool l_b_ok_prev;
                        TransDataEdgeSlideVert *sv;
+                       BMVert *v_prev;
+                       BMEdge *e_prev;
 
                        /* 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));
+                       BLI_assert(v != NULL);
+                       BLI_assert(sv_table[BM_elem_index_get(v)] != -1);
+                       sv = &sv_array[sv_table[BM_elem_index_get(v)]];
                        sv->v = v;
-                       sv->origvert = *v;
+                       copy_v3_v3(sv->v_co_orig, v->co);
                        sv->loop_nr = loop_nr;
 
-                       copy_v3_v3(sv->upvec, vec);
-                       if (l2)
-                               copy_v3_v3(sv->downvec, vec2);
-
-                       l = BM_face_other_edge_loop(l1->f, l1->e, v);
-                       sv->up = BM_edge_other_vert(l->e, v);
+                       if (l_a) {
+                               BMLoop *l_tmp = BM_loop_other_edge_loop(l_a, v);
+                               sv->v_a = BM_edge_other_vert(l_tmp->e, v);
+                               copy_v3_v3(sv->dir_a, vec_a);
+                       }
 
-                       if (l2) {
-                               l = BM_face_other_edge_loop(l2->f, l2->e, v);
-                               sv->down = BM_edge_other_vert(l->e, v);
+                       if (l_b) {
+                               BMLoop *l_tmp = BM_loop_other_edge_loop(l_b, v);
+                               sv->v_b = BM_edge_other_vert(l_tmp->e, v);
+                               copy_v3_v3(sv->dir_b, vec_b);
                        }
 
-                       v2 = v, v = BM_edge_other_vert(e, v);
+                       v_prev = v;
+                       v = BM_edge_other_vert(e, v);
 
-                       e1 = e;
+                       e_prev = e;
                        e = get_other_edge(v, e);
+
                        if (!e) {
-                               BLI_assert(BLI_smallhash_haskey(&table, (uintptr_t)v) != false);
-                               sv = sv_array + GET_INT_FROM_POINTER(BLI_smallhash_lookup(&table, (uintptr_t)v));
+                               BLI_assert(v != NULL);
+                               BLI_assert(sv_table[BM_elem_index_get(v)] != -1);
+                               sv = &sv_array[sv_table[BM_elem_index_get(v)]];
                                sv->v = v;
-                               sv->origvert = *v;
+                               copy_v3_v3(sv->v_co_orig, v->co);
                                sv->loop_nr = loop_nr;
-                               
-                               l = BM_face_other_edge_loop(l1->f, l1->e, v);
-                               sv->up = BM_edge_other_vert(l->e, v);
-                               sub_v3_v3v3(sv->upvec, BM_edge_other_vert(l->e, v)->co, v->co);
-
-                               if (l2) {
-                                       l = BM_face_other_edge_loop(l2->f, l2->e, v);
-                                       sv->down = BM_edge_other_vert(l->e, v);
-                                       sub_v3_v3v3(sv->downvec, BM_edge_other_vert(l->e, v)->co, v->co);
+
+                               if (l_a) {
+                                       BMLoop *l_tmp = BM_loop_other_edge_loop(l_a, v);
+                                       sv->v_a = BM_edge_other_vert(l_tmp->e, v);
+                                       if (BM_vert_edge_count_nonwire(v) == 2) {
+                                               get_next_loop(v, l_a, e_prev, l_tmp->e, sv->dir_a);
+                                       }
+                                       else {
+                                               sub_v3_v3v3(sv->dir_a, BM_edge_other_vert(l_tmp->e, v)->co, v->co);
+                                       }
+                               }
+
+                               if (l_b) {
+                                       BMLoop *l_tmp = BM_loop_other_edge_loop(l_b, v);
+                                       sv->v_b = BM_edge_other_vert(l_tmp->e, v);
+                                       if (BM_vert_edge_count_nonwire(v) == 2) {
+                                               get_next_loop(v, l_b, e_prev, l_tmp->e, sv->dir_b);
+                                       }
+                                       else {
+                                               sub_v3_v3v3(sv->dir_b, BM_edge_other_vert(l_tmp->e, v)->co, v->co);
+                                       }
                                }
 
                                BM_elem_flag_disable(v, BM_ELEM_TAG);
-                               BM_elem_flag_disable(v2, BM_ELEM_TAG);
+                               BM_elem_flag_disable(v_prev, BM_ELEM_TAG);
 
                                break;
                        }
-
-                       l1 = get_next_loop(v, l1, e1, e, vec);
-                       l2 = l2 ? get_next_loop(v, l2, e1, e, vec2) : NULL;
-
-                       if (UNLIKELY(l1 == NULL && l2 != NULL)) {
-                               l1 = l2;
-                               l2 = NULL;
-                               swap_v3_v3(vec, vec2);
+                       l_a_ok_prev = (l_a != NULL);
+                       l_b_ok_prev = (l_b != NULL);
+
+                       l_a = l_a ? get_next_loop(v, l_a, e_prev, e, vec_a) : NULL;
+                       l_b = l_b ? get_next_loop(v, l_b, e_prev, e, vec_b) : NULL;
+
+                       /* find the opposite loop if it was missing previously */
+                       if      (l_a == NULL && l_b && (l_b->radial_next != l_b)) l_a = l_b->radial_next;
+                       else if (l_b == NULL && l_a && (l_a->radial_next != l_a)) l_b = l_a->radial_next;
+
+                       /* if there are non-contiguous faces, we can still recover the loops of the new edges faces */
+                       /* note!, the behavior in this case means edges may move in opposite directions,
+                        * this could be made to work more usefully. */
+                       if (!(l_a && l_b) && (e->l != NULL)) {
+                               if (l_a_ok_prev) {
+                                       l_a = e->l;
+                                       if (l_a->radial_next != l_a) {
+                                               l_b = l_a->radial_next;
+                                       }
+                               }
+                               else if (l_b_ok_prev) {
+                                       l_b = e->l;
+                                       if (l_b->radial_next != l_b) {
+                                               l_a = l_b->radial_next;
+                                       }
+                               }
                        }
 
                        BM_elem_flag_disable(v, BM_ELEM_TAG);
-                       BM_elem_flag_disable(v2, BM_ELEM_TAG);
-               } while (e != v_first->e && l1);
+                       BM_elem_flag_disable(v_prev, BM_ELEM_TAG);
+               } while ((e != v_first->e) && (l_a || l_b));
 
                loop_nr++;
        }
 
+       /* use for visibility checks */
+       use_btree_disp = (v3d && t->obedit->dt > OB_WIRE && v3d->drawtype > OB_WIRE);
+
+       if (use_btree_disp) {
+               btree = BKE_bmbvh_new_from_editmesh(em, BMBVH_RESPECT_HIDDEN, NULL, false);
+       }
+       else {
+               btree = NULL;
+       }
+
+
        /* EDBM_flag_disable_all(em, BM_ELEM_SELECT); */
 
        sld->sv = sv_array;
@@ -5385,25 +5606,27 @@ static int createEdgeSlideVerts(TransInfo *t)
        
        /* find mouse vectors, the global one, and one per loop in case we have
         * multiple loops selected, in case they are oriented different */
-       zero_v3(dir);
+       zero_v3(mval_dir);
        maxdist = -1.0f;
 
        loop_dir = MEM_callocN(sizeof(float) * 3 * loop_nr, "sv loop_dir");
-       loop_maxdist = MEM_callocN(sizeof(float) * loop_nr, "sv loop_maxdist");
-       for (j = 0; j < loop_nr; j++)
-               loop_maxdist[j] = -1.0f;
+       loop_maxdist = MEM_mallocN(sizeof(float) * loop_nr, "sv loop_maxdist");
+       fill_vn_fl(loop_maxdist, loop_nr, -1.0f);
 
        BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
                if (BM_elem_flag_test(e, BM_ELEM_SELECT)) {
                        BMIter iter2;
                        BMEdge *e2;
-                       float vec1[3], d;
+                       float d;
 
                        /* search cross edges for visible edge to the mouse cursor,
                         * then use the shared vertex to calculate screen vector*/
                        for (i = 0; i < 2; i++) {
                                v = i ? e->v1 : e->v2;
                                BM_ITER_ELEM (e2, &iter2, v, BM_EDGES_OF_VERT) {
+                                       /* screen-space coords */
+                                       float sco_a[3], sco_b[3];
+
                                        if (BM_elem_flag_test(e2, BM_ELEM_SELECT))
                                                continue;
 
@@ -5412,115 +5635,115 @@ static int createEdgeSlideVerts(TransInfo *t)
                                                continue;
                                        }
 
-                                       BLI_assert(BLI_smallhash_haskey(&table, (uintptr_t)v) != false);
-                                       j = GET_INT_FROM_POINTER(BLI_smallhash_lookup(&table, (uintptr_t)v));
+                                       BLI_assert(sv_table[BM_elem_index_get(v)] != -1);
+                                       j = sv_table[BM_elem_index_get(v)];
 
-                                       if (sv_array[j].down) {
-                                               ED_view3d_project_float_v3_m4(ar, sv_array[j].down->co, vec1, projectMat);
+                                       if (sv_array[j].v_b) {
+                                               ED_view3d_project_float_v3_m4(ar, sv_array[j].v_b->co, sco_b, projectMat);
                                        }
                                        else {
-                                               add_v3_v3v3(vec1, v->co, sv_array[j].downvec);
-                                               ED_view3d_project_float_v3_m4(ar, vec1, vec1, projectMat);
+                                               add_v3_v3v3(sco_b, v->co, sv_array[j].dir_b);
+                                               ED_view3d_project_float_v3_m4(ar, sco_b, sco_b, projectMat);
                                        }
                                        
-                                       if (sv_array[j].up) {
-                                               ED_view3d_project_float_v3_m4(ar, sv_array[j].up->co, vec2, projectMat);
+                                       if (sv_array[j].v_a) {
+                                               ED_view3d_project_float_v3_m4(ar, sv_array[j].v_a->co, sco_a, projectMat);
                                        }
                                        else {
-                                               add_v3_v3v3(vec2, v->co, sv_array[j].upvec);
-                                               ED_view3d_project_float_v3_m4(ar, vec2, vec2, projectMat);
+                                               add_v3_v3v3(sco_a, v->co, sv_array[j].dir_a);
+                                               ED_view3d_project_float_v3_m4(ar, sco_a, sco_a, projectMat);
                                        }
                                        
                                        /* global direction */
-                                       d = dist_to_line_segment_v2(mval, vec1, vec2);
-                                       if (maxdist == -1.0f || d < maxdist) {
+                                       d = dist_to_line_segment_v2(mval, sco_b, sco_a);
+                                       if ((maxdist == -1.0f) ||
+                                           /* intentionally use 2d size on 3d vector */
+                                           (d < maxdist && (len_squared_v2v2(sco_b, sco_a) > 0.1f)))
+                                       {
                                                maxdist = d;
-                                               sub_v3_v3v3(dir, vec1, vec2);
+                                               sub_v3_v3v3(mval_dir, sco_b, sco_a);
                                        }
 
                                        /* per loop direction */
                                        l_nr = sv_array[j].loop_nr;
                                        if (loop_maxdist[l_nr] == -1.0f || d < loop_maxdist[l_nr]) {
                                                loop_maxdist[l_nr] = d;
-                                               sub_v3_v3v3(loop_dir[l_nr], vec1, vec2);
+                                               sub_v3_v3v3(loop_dir[l_nr], sco_b, sco_a);
                                        }
                                }
                        }
                }
        }
 
+       /* possible all of the edge loops are pointing directly at the view */
+       if (UNLIKELY(len_squared_v2(mval_dir) < 0.1f)) {
+               mval_dir[0] = 0.0f;
+               mval_dir[1] = 100.0f;
+       }
+
        bmesh_edit_begin(bm, BMO_OPTYPE_FLAG_UNTAN_MULTIRES);
 
+       if (sld->use_origfaces) {
+               sld->origfaces = BLI_ghash_ptr_new(__func__);
+               sld->bm_origfaces = BM_mesh_create(&bm_mesh_allocsize_default);
+               /* we need to have matching customdata */
+               BM_mesh_copy_init_customdata(sld->bm_origfaces, bm, NULL);
+       }
+
        /*create copies of faces for customdata projection*/
        sv_array = sld->sv;
        for (i = 0; i < sld->totsv; i++, sv_array++) {
-               BMIter fiter, liter;
+               BMIter fiter;
                BMFace *f;
-               BMLoop *l;
                
-               BM_ITER_ELEM (f, &fiter, sv_array->v, BM_FACES_OF_VERT) {
-                       
-                       if (!BLI_smallhash_haskey(&sld->origfaces, (uintptr_t)f)) {
-                               BMFace *copyf = BM_face_copy(bm, f, TRUE, TRUE);
-                               
-                               BM_face_select_set(bm, copyf, FALSE);
-                               BM_elem_flag_enable(copyf, BM_ELEM_HIDDEN);
-                               BM_ITER_ELEM (l, &liter, copyf, BM_LOOPS_OF_FACE) {
-                                       BM_vert_select_set(bm, l->v, FALSE);
-                                       BM_elem_flag_enable(l->v, BM_ELEM_HIDDEN);
-                                       BM_edge_select_set(bm, l->e, FALSE);
-                                       BM_elem_flag_enable(l->e, BM_ELEM_HIDDEN);
-                               }
 
-                               BLI_smallhash_insert(&sld->origfaces, (uintptr_t)f, copyf);
+               if (sld->use_origfaces) {
+                       BM_ITER_ELEM (f, &fiter, sv_array->v, BM_FACES_OF_VERT) {
+                               if (!BLI_ghash_haskey(sld->origfaces, f)) {
+                                       BMFace *f_copy = BM_face_copy(sld->bm_origfaces, bm, f, true, true);
+                                       BLI_ghash_insert(sld->origfaces, f, f_copy);
+                               }
                        }
                }
 
-               BLI_smallhash_insert(&sld->vhash, (uintptr_t)sv_array->v, sv_array);
-
-               /* switch up/down if loop direction is different from global direction */
+               /* switch a/b if loop direction is different from global direction */
                l_nr = sv_array->loop_nr;
-               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);
+               if (dot_v3v3(loop_dir[l_nr], mval_dir) < 0.0f) {
+                       swap_v3_v3(sv_array->dir_a, sv_array->dir_b);
+                       SWAP(BMVert *, sv_array->v_a, sv_array->v_b);
                }
        }
 
        if (rv3d)
                calcNonProportionalEdgeSlide(t, sld, mval);
 
-       sld->origfaces_init = true;
        sld->em = em;
-       
+
        /*zero out start*/
-       zero_v3(start);
+       zero_v2(mval_start);
 
        /*dir holds a vector along edge loop*/
-       copy_v3_v3(end, dir);
-       mul_v3_fl(end, 0.5f);
+       copy_v2_v2(mval_end, mval_dir);
+       mul_v2_fl(mval_end, 0.5f);
        
-       sld->start[0] = t->mval[0] + start[0];
-       sld->start[1] = t->mval[1] + start[1];
+       sld->mval_start[0] = t->mval[0] + mval_start[0];
+       sld->mval_start[1] = t->mval[1] + mval_start[1];
 
-       sld->end[0] = t->mval[0] + end[0];
-       sld->end[1] = t->mval[1] + end[1];
+       sld->mval_end[0] = t->mval[0] + mval_end[0];
+       sld->mval_end[1] = t->mval[1] + mval_end[1];
        
        sld->perc = 0.0f;
        
        t->customData = sld;
        
-       BLI_smallhash_release(&table);
+       MEM_freeN(sv_table);
        if (btree) {
-               BMBVH_FreeBVH(btree);
+               BKE_bmbvh_free(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;
+       return true;
 }
 
 void projectEdgeSlideData(TransInfo *t, bool is_final)
@@ -5528,174 +5751,159 @@ void projectEdgeSlideData(TransInfo *t, bool is_final)
        EdgeSlideData *sld = t->customData;
        TransDataEdgeSlideVert *sv;
        BMEditMesh *em = sld->em;
-       SmallHash visit;
        int i;
 
-       if (!em)
-               return;
-       
-       if (!(t->settings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT))
-               return;
-
-       /* don't do this at all for non-basis shape keys, too easy to
-        * accidentally break uv maps or vertex colors then */
-       if (em->bm->shapenr > 1)
+       if (sld->use_origfaces == false) {
                return;
+       }
 
-       BLI_smallhash_init(&visit);
-       
        for (i = 0, sv = sld->sv; i < sld->totsv; sv++, i++) {
                BMIter fiter;
-               BMFace *f;
-
-               /* BMESH_TODO, this interpolates between vertex/loops which are not moved
-                * (are only apart of a face attached to a slide vert), couldn't we iterate BM_LOOPS_OF_VERT
-                * here and only interpolate those? */
-               BM_ITER_ELEM (f, &fiter, sv->v, BM_FACES_OF_VERT) {
-                       BMIter liter;
-                       BMLoop *l;
+               BMLoop *l;
 
+               BM_ITER_ELEM (l, &fiter, sv->v, BM_LOOPS_OF_VERT) {
                        BMFace *f_copy;      /* the copy of 'f' */
                        BMFace *f_copy_flip; /* the copy of 'f' or detect if we need to flip to the shorter side. */
-
-                       char is_sel, is_hide;
-
-                       
-                       if (BLI_smallhash_haskey(&visit, (uintptr_t)f))
-                               continue;
                        
-                       BLI_smallhash_insert(&visit, (uintptr_t)f, NULL);
-                       
-                       /* the face attributes of the copied face will get
-                        * copied over, so its necessary to save the selection
-                        * and hidden state*/
-                       is_sel = BM_elem_flag_test(f, BM_ELEM_SELECT);
-                       is_hide = BM_elem_flag_test(f, BM_ELEM_HIDDEN);
-                       
-                       f_copy = BLI_smallhash_lookup(&sld->origfaces, (uintptr_t)f);
+                       f_copy = BLI_ghash_lookup(sld->origfaces, l->f);
                        
                        /* project onto copied projection face */
-                       BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
-                               /* only affected verts will get interpolated */
-                               char affected = FALSE;
-                               f_copy_flip = f_copy;
-
-                               if (BM_elem_flag_test(l->e, BM_ELEM_SELECT) || BM_elem_flag_test(l->prev->e, BM_ELEM_SELECT)) {
-                                       /* the loop is attached of the selected edges that are sliding */
-                                       BMLoop *l_ed_sel = l;
-                                       
-                                       if (!BM_elem_flag_test(l->e, BM_ELEM_SELECT))
-                                               l_ed_sel = l_ed_sel->prev;
-                                       
-                                       if (sld->perc < 0.0f) {
-                                               if (BM_vert_in_face(l_ed_sel->radial_next->f, sv->down)) {
-                                                       f_copy_flip = BLI_smallhash_lookup(&sld->origfaces, (uintptr_t)l_ed_sel->radial_next->f);
-                                               }
+                       f_copy_flip = f_copy;
+
+                       if (BM_elem_flag_test(l->e, BM_ELEM_SELECT) || BM_elem_flag_test(l->prev->e, BM_ELEM_SELECT)) {
+                               /* the loop is attached of the selected edges that are sliding */
+                               BMLoop *l_ed_sel = l;
+
+                               if (!BM_elem_flag_test(l->e, BM_ELEM_SELECT))
+                                       l_ed_sel = l_ed_sel->prev;
+
+                               if (sld->perc < 0.0f) {
+                                       if (BM_vert_in_face(l_ed_sel->radial_next->f, sv->v_b)) {
+                                               f_copy_flip = BLI_ghash_lookup(sld->origfaces, l_ed_sel->radial_next->f);
                                        }
-                                       else if (sld->perc > 0.0f) {
-                                               if (BM_vert_in_face(l_ed_sel->radial_next->f, sv->up)) {
-                                                       f_copy_flip = BLI_smallhash_lookup(&sld->origfaces, (uintptr_t)l_ed_sel->radial_next->f);
-                                               }
+                               }
+                               else if (sld->perc > 0.0f) {
+                                       if (BM_vert_in_face(l_ed_sel->radial_next->f, sv->v_a)) {
+                                               f_copy_flip = BLI_ghash_lookup(sld->origfaces, l_ed_sel->radial_next->f);
                                        }
+                               }
 
-                                       BLI_assert(f_copy_flip != NULL);
-                                       if (!f_copy_flip) {
-                                               continue;  /* shouldn't happen, but protection */
+                               BLI_assert(f_copy_flip != NULL);
+                               if (!f_copy_flip) {
+                                       continue;  /* shouldn't happen, but protection */
+                               }
+                       }
+                       else {
+                               /* the loop is attached to only one vertex and not a selected edge,
+                                * this means we have to find a selected edges face going in the right direction
+                                * to copy from else we get bad distortion see: [#31080] */
+                               BMIter eiter;
+                               BMEdge *e_sel;
+
+                               BLI_assert(l->v == sv->v);
+                               BM_ITER_ELEM (e_sel, &eiter, sv->v, BM_EDGES_OF_VERT) {
+                                       if (BM_elem_flag_test(e_sel, BM_ELEM_SELECT)) {
+                                               break;
                                        }
-
-                                       affected = TRUE;
                                }
-                               else {
-                                       /* the loop is attached to only one vertex and not a selected edge,
-                                        * this means we have to find a selected edges face going in the right direction
-                                        * to copy from else we get bad distortion see: [#31080] */
-                                       BMIter eiter;
-                                       BMEdge *e_sel;
-
-                                       BM_ITER_ELEM (e_sel, &eiter, l->v, BM_EDGES_OF_VERT) {
-                                               if (BM_elem_flag_test(e_sel, BM_ELEM_SELECT)) {
-                                                       break;
+
+                               if (e_sel) {
+                                       /* warning if the UV's are not contiguous, this will copy from the _wrong_ UVs
+                                        * in fact whenever the face being copied is not 'f_copy' this can happen,
+                                        * we could be a lot smarter about this but would need to deal with every UV channel or
+                                        * add a way to mask out lauers when calling #BM_loop_interp_from_face() */
+
+                                       /*
+                                        *        +    +----------------+
+                                        *         \   |                |
+                                        * (this) l_adj|                |
+                                        *           \ |                |
+                                        *            \|      e_sel     |
+                                        *  +----------+----------------+  <- the edge we are sliding.
+                                        *            /|sv->v           |
+                                        *           / |                |
+                                        *   (or) l_adj|                |
+                                        *         /   |                |
+                                        *        +    +----------------+
+                                        * (above)
+                                        * 'other connected loops', attached to sv->v slide faces.
+                                        *
+                                        * NOTE: The faces connected to the edge may not have contiguous UV's
+                                        *       so step around the loops to find l_adj.
+                                        *       However if the 'other loops' are not cotiguous it will still give problems.
+                                        *
+                                        *       A full solution to this would have to store
+                                        *       per-customdata-layer map of which loops are contiguous
+                                        *       and take this into account when interpolating.
+                                        *
+                                        * NOTE: If l_adj's edge isnt manifold then use then
+                                        *       interpolate the loop from its own face.
+                                        *       Can happen when 'other connected loops' are disconnected from the face-fan.
+                                        */
+
+                                       BMLoop *l_adj = NULL;
+                                       if (sld->perc < 0.0f) {
+                                               if (BM_vert_in_face(e_sel->l->f, sv->v_b)) {
+                                                       l_adj = e_sel->l;
+                                               }
+                                               else if (BM_vert_in_face(e_sel->l->radial_next->f, sv->v_b)) {
+                                                       l_adj = e_sel->l->radial_next;
+                                               }
+                                       }
+                                       else if (sld->perc > 0.0f) {
+                                               if (BM_vert_in_face(e_sel->l->f, sv->v_a)) {
+                                                       l_adj = e_sel->l;
+                                               }
+                                               else if (BM_vert_in_face(e_sel->l->radial_next->f, sv->v_a)) {
+                                                       l_adj = e_sel->l->radial_next;
                                                }
                                        }
 
-                                       if (e_sel) {
-                                               /* warning if the UV's are not contiguous, this will copy from the _wrong_ UVs
-                                                * in fact whenever the face being copied is not 'f_copy' this can happen,
-                                                * we could be a lot smarter about this but would need to deal with every UV channel or
-                                                * add a way to mask out lauers when calling #BM_loop_interp_from_face() */
-                                               if (sld->perc < 0.0f) {
-                                                       if (BM_vert_in_face(e_sel->l->f, sv->down)) {
-                                                               f_copy_flip = BLI_smallhash_lookup(&sld->origfaces, (uintptr_t)e_sel->l->f);
-                                                       }
-                                                       else if (BM_vert_in_face(e_sel->l->radial_next->f, sv->down)) {
-                                                               f_copy_flip = BLI_smallhash_lookup(&sld->origfaces,
-                                                                                                  (uintptr_t)e_sel->l->radial_next->f);
-                                                       }
-
+                                       /* step across to the face */
+                                       if (l_adj) {
+                                               l_adj = BM_loop_other_edge_loop(l_adj, sv->v);
+                                               if (!BM_edge_is_boundary(l_adj->e)) {
+                                                       l_adj = l_adj->radial_next;
                                                }
-                                               else if (sld->perc > 0.0f) {
-                                                       if (BM_vert_in_face(e_sel->l->f, sv->up)) {
-                                                               f_copy_flip = BLI_smallhash_lookup(&sld->origfaces, (uintptr_t)e_sel->l->f);
-                                                       }
-                                                       else if (BM_vert_in_face(e_sel->l->radial_next->f, sv->up)) {
-                                                               f_copy_flip = BLI_smallhash_lookup(&sld->origfaces,
-                                                                                                  (uintptr_t)e_sel->l->radial_next->f);
-                                                       }
+                                               else {
+                                                       /* disconnected face-fan, fallback to self */
+                                                       l_adj = l;
                                                }
 
-                                               affected = TRUE;
+                                               f_copy_flip = BLI_ghash_lookup(sld->origfaces, l_adj->f);
                                        }
-
                                }
+                       }
 
-                               if (!affected)
-                                       continue;
-
-                               /* only loop data, no vertex data since that contains shape keys,
-                                * and we do not want to mess up other shape keys */
-                               BM_loop_interp_from_face(em->bm, l, f_copy_flip, FALSE, FALSE);
+                       /* only loop data, no vertex data since that contains shape keys,
+                        * 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 (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);
-                                       }
+                       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);
                                }
                        }
                        
                        /* make sure face-attributes are correct (e.g. MTexPoly) */
-                       BM_elem_attrs_copy(em->bm, em->bm, f_copy, f);
-                       
-                       /* restore selection and hidden flags */
-                       BM_face_select_set(em->bm, f, is_sel);
-                       if (!is_hide) {
-                               /* this check is a workaround for bug, see note - [#30735],
-                                * without this edge can be hidden and selected */
-                               BM_elem_hide_set(em->bm, f, is_hide);
-                       }
+                       BM_elem_attrs_copy(sld->bm_origfaces, em->bm, f_copy, l->f);
                }
        }
-
-       BLI_smallhash_release(&visit);
 }
 
 void freeEdgeSlideTempFaces(EdgeSlideData *sld)
 {
-       if (sld->origfaces_init) {
-               SmallHashIter hiter;
-               BMFace *copyf;
-
-               copyf = BLI_smallhash_iternew(&sld->origfaces, &hiter, NULL);
-               for (; copyf; copyf = BLI_smallhash_iternext(&hiter, NULL)) {
-                       BM_face_verts_kill(sld->em->bm, copyf);
+       if (sld->use_origfaces) {
+               if (sld->bm_origfaces) {
+                       BM_mesh_free(sld->bm_origfaces);
+                       sld->bm_origfaces = NULL;
                }
 
-               BLI_smallhash_release(&sld->origfaces);
-
-               sld->origfaces_init = false;
-
-               /* arrays are dirty from removing faces: EDBM_index_arrays_free */
-               EDBM_update_generic(sld->em, FALSE, TRUE);
+               if (sld->origfaces) {
+                       BLI_ghash_free(sld->origfaces, NULL, NULL);
+                       sld->origfaces = NULL;
+               }
        }
 }
 
@@ -5704,30 +5912,12 @@ void freeEdgeSlideVerts(TransInfo *t)
 {
        EdgeSlideData *sld = t->customData;
        
-#if 0 /*BMESH_TODO*/
-       if (me->drawflag & ME_DRAWEXTRA_EDGELEN) {
-               TransDataEdgeSlideVert *sv;
-               LinkNode *look = sld->vertlist;
-               GHash *vertgh = sld->vhash;
-               while (look) {
-                       sv  = BLI_ghash_lookup(vertgh, (EditVert *)look->link);
-                       if (sv != NULL) {
-                               sv->up->f &= !SELECT;
-                               sv->down->f &= !SELECT;
-                       }
-                       look = look->next;
-               }
-       }
-#endif
-       
        if (!sld)
                return;
        
        freeEdgeSlideTempFaces(sld);
 
        bmesh_edit_end(sld->em->bm, BMO_OPTYPE_FLAG_UNTAN_MULTIRES);
-
-       BLI_smallhash_release(&sld->vhash);
        
        MEM_freeN(sld->sv);
        MEM_freeN(sld);
@@ -5737,12 +5927,12 @@ void freeEdgeSlideVerts(TransInfo *t)
        recalcData(t);
 }
 
-void initEdgeSlide(TransInfo *t)
+static void initEdgeSlide(TransInfo *t)
 {
        EdgeSlideData *sld;
 
        t->mode = TFM_EDGE_SLIDE;
-       t->transform = EdgeSlide;
+       t->transform = applyEdgeSlide;
        t->handleEvent = handleEventEdgeSlide;
 
        if (!createEdgeSlideVerts(t)) {
@@ -5758,7 +5948,7 @@ void initEdgeSlide(TransInfo *t)
        t->customFree = freeEdgeSlideVerts;
 
        /* set custom point first if you want value to be initialized by init */
-       setCustomPoints(t, &t->mouse, sld->end, sld->start);
+       setCustomPoints(t, &t->mouse, sld->mval_end, sld->mval_start);
        initMouseInputMode(t, &t->mouse, INPUT_CUSTOM_RATIO_FLIP);
        
        t->idx_max = 0;
@@ -5767,12 +5957,14 @@ void initEdgeSlide(TransInfo *t)
        t->snap[1] = 0.1f;
        t->snap[2] = t->snap[1] * 0.1f;
 
-       t->num.increment = t->snap[1];
+       copy_v3_fl(t->num.val_inc, t->snap[1]);
+       t->num.unit_sys = t->scene->unit.system;
+       t->num.unit_type[0] = B_UNIT_NONE;
 
        t->flag |= T_NO_CONSTRAINT | T_NO_PROJECT;
 }
 
-int handleEventEdgeSlide(struct TransInfo *t, const struct wmEvent *event)
+static eRedrawFlag handleEventEdgeSlide(struct TransInfo *t, const struct wmEvent *event)
 {
        if (t->mode == TFM_EDGE_SLIDE) {
                EdgeSlideData *sld = t->customData;
@@ -5782,7 +5974,7 @@ int handleEventEdgeSlide(struct TransInfo *t, const struct wmEvent *event)
                                case EKEY:
                                        if (event->val == KM_PRESS) {
                                                sld->is_proportional = !sld->is_proportional;
-                                               return 1;
+                                               return TREDRAW_HARD;
                                        }
                                        break;
                                case FKEY:
@@ -5791,7 +5983,7 @@ int handleEventEdgeSlide(struct TransInfo *t, const struct wmEvent *event)
                                                if (sld->is_proportional == FALSE) {
                                                        sld->flipped_vtx = !sld->flipped_vtx;
                                                }
-                                               return 1;
+                                               return TREDRAW_HARD;
                                        }
                                        break;
                                }
@@ -5809,36 +6001,33 @@ int handleEventEdgeSlide(struct TransInfo *t, const struct wmEvent *event)
                                                        break;
                                                }
                                        }
+                                       break;
                                }
                                default:
                                        break;
                        }
                }
        }
-       return 0;
+       return TREDRAW_NOTHING;
 }
 
-void drawEdgeSlide(const struct bContext *C, TransInfo *t)
+static void drawEdgeSlide(const struct bContext *C, TransInfo *t)
 {
        if (t->mode == TFM_EDGE_SLIDE) {
                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;
+                       float co_a[3], co_b[3], co_mark[3];
                        TransDataEdgeSlideVert *curr_sv = &sld->sv[sld->curr_sv_index];
+                       const float fac = (sld->perc + 1.0f) / 2.0f;
                        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;
 
-                       add_v3_v3v3(v1, curr_sv->origvert.co, curr_sv->upvec);
-                       add_v3_v3v3(v2, curr_sv->origvert.co, curr_sv->downvec);
-
-                       interp_v = (sld->perc + 1.0f) / 2.0f;
-                       interp_v3_v3v3(marker, v2, v1, interp_v);
+                       add_v3_v3v3(co_a, curr_sv->v_co_orig, curr_sv->dir_a);
+                       add_v3_v3v3(co_b, curr_sv->v_co_orig, curr_sv->dir_b);
 
                        if (v3d && v3d->zbuf)
                                glDisable(GL_DEPTH_TEST);
@@ -5854,30 +6043,37 @@ void drawEdgeSlide(const struct bContext *C, TransInfo *t)
                        glLineWidth(line_size);
                        UI_ThemeColorShadeAlpha(TH_EDGE_SELECT, 80, alpha_shade);
                        glBegin(GL_LINES);
-                       glVertex3fv(curr_sv->up->co);
-                       glVertex3fv(curr_sv->origvert.co);
-                       glVertex3fv(curr_sv->down->co);
-                       glVertex3fv(curr_sv->origvert.co);
+                       if (curr_sv->v_a) {
+                               glVertex3fv(curr_sv->v_a->co);
+                               glVertex3fv(curr_sv->v_co_orig);
+                       }
+                       if (curr_sv->v_b) {
+                               glVertex3fv(curr_sv->v_b->co);
+                               glVertex3fv(curr_sv->v_co_orig);
+                       }
                        bglEnd();
 
 
                        UI_ThemeColorShadeAlpha(TH_SELECT, -30, alpha_shade);
                        glPointSize(ctrl_size);
+                       bglBegin(GL_POINTS);
                        if (sld->flipped_vtx) {
-                               bglBegin(GL_POINTS);
-                               bglVertex3fv(curr_sv->down->co);
-                               bglEnd();
+                               if (curr_sv->v_b) bglVertex3fv(curr_sv->v_b->co);
                        }
                        else {
-                               bglBegin(GL_POINTS);
-                               bglVertex3fv(curr_sv->up->co);
-                               bglEnd();
+                               if (curr_sv->v_a) bglVertex3fv(curr_sv->v_a->co);
                        }
+                       bglEnd();
 
                        UI_ThemeColorShadeAlpha(TH_SELECT, 255, alpha_shade);
                        glPointSize(guide_size);
                        bglBegin(GL_POINTS);
-                       bglVertex3fv(marker);
+#if 0
+                       interp_v3_v3v3(co_mark, co_b, co_a, fac);
+                       bglVertex3fv(co_mark);
+#endif
+                       interp_line_v3_v3v3v3(co_mark, co_b, curr_sv->v_co_orig, co_a, fac);
+                       bglVertex3fv(co_mark);
                        bglEnd();
 
 
@@ -5905,44 +6101,44 @@ static int doEdgeSlide(TransInfo *t, float perc)
                for (i = 0; i < sld->totsv; i++, sv++) {
                        float vec[3];
                        if (perc > 0.0f) {
-                               copy_v3_v3(vec, sv->upvec);
+                               copy_v3_v3(vec, sv->dir_a);
                                mul_v3_fl(vec, perc);
-                               add_v3_v3v3(sv->v->co, sv->origvert.co, vec);
+                               add_v3_v3v3(sv->v->co, sv->v_co_orig, vec);
                        }
                        else {
-                               copy_v3_v3(vec, sv->downvec);
+                               copy_v3_v3(vec, sv->dir_b);
                                mul_v3_fl(vec, -perc);
-                               add_v3_v3v3(sv->v->co, sv->origvert.co, vec);
+                               add_v3_v3v3(sv->v->co, sv->v_co_orig, vec);
                        }
                }
        }
        else {
                /**
                 * 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
+                * a/b 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)
+                * \note len_v3v3(curr_sv->dir_a, curr_sv->dir_b)
                 * is the same as the distance between the original vert locations, same goes for the lines below.
                 */
                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];
+               float co_a[3];
+               float co_b[3];
 
                for (i = 0; i < sld->totsv; i++, sv++) {
                        if (sv->edge_len > FLT_EPSILON) {
                                const float fac = min_ff(sv->edge_len, curr_length_perc) / sv->edge_len;
 
-                               add_v3_v3v3(up_co, sv->origvert.co, sv->upvec);
-                               add_v3_v3v3(down_co, sv->origvert.co, sv->downvec);
+                               add_v3_v3v3(co_a, sv->v_co_orig, sv->dir_a);
+                               add_v3_v3v3(co_b, sv->v_co_orig, sv->dir_b);
 
                                if (sld->flipped_vtx) {
-                                       interp_v3_v3v3(sv->v->co, down_co, up_co, fac);
+                                       interp_line_v3_v3v3v3(sv->v->co, co_b, sv->v_co_orig, co_a, fac);
                                }
                                else {
-                                       interp_v3_v3v3(sv->v->co, up_co, down_co, fac);
+                                       interp_line_v3_v3v3v3(sv->v->co, co_a, sv->v_co_orig, co_b, fac);
                                }
                        }
                }
@@ -5953,7 +6149,7 @@ static int doEdgeSlide(TransInfo *t, float perc)
        return 1;
 }
 
-int EdgeSlide(TransInfo *t, const int UNUSED(mval[2]))
+static void applyEdgeSlide(TransInfo *t, const int UNUSED(mval[2]))
 {
        char str[MAX_INFO_LEN];
        float final;
@@ -5961,12 +6157,9 @@ int EdgeSlide(TransInfo *t, const int UNUSED(mval[2]))
        bool flipped = sld->flipped_vtx;
        bool is_proportional = sld->is_proportional;
 
-       const char *on_str = IFACE_("ON");
-       const char *off_str = IFACE_("OFF");
-
        final = t->values[0];
 
-       snapGrid(t, &final);
+       snapGridIncrement(t, &final);
 
        /* only do this so out of range values are not displayed */
        CLAMP(final, -1.0f, 1.0f);
@@ -5978,50 +6171,58 @@ int EdgeSlide(TransInfo *t, const int UNUSED(mval[2]))
 
                outputNumInput(&(t->num), c);
 
-               BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Edge Slide: %s (E)ven: %s, (F)lipped: %s"),
-                            &c[0], !is_proportional ? on_str : off_str, flipped ? on_str : off_str);
+               if (is_proportional) {
+                       BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Edge Slide: %s (E)ven: %s"),
+                                    &c[0], WM_bool_as_string(!is_proportional));
+               }
+               else {
+                       BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Edge Slide: %s (E)ven: %s, (F)lipped: %s"),
+                                    &c[0], WM_bool_as_string(!is_proportional), WM_bool_as_string(flipped));
+               }
+       }
+       else if (is_proportional) {
+               BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Edge Slide: %.4f (E)ven: %s"),
+                            final, WM_bool_as_string(!is_proportional));
        }
        else {
                BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Edge Slide: %.4f (E)ven: %s, (F)lipped: %s"),
-                            final, !is_proportional ? on_str : off_str, flipped ? on_str : off_str);
+                            final, WM_bool_as_string(!is_proportional), WM_bool_as_string(flipped));
        }
 
        CLAMP(final, -1.0f, 1.0f);
 
        t->values[0] = final;
 
-       /*do stuff here*/
-       if (t->customData) {
-               doEdgeSlide(t, final);
-       }
-       else {
-               BLI_strncpy(str, IFACE_("Invalid Edge Selection"), MAX_INFO_LEN);
-               t->state = TRANS_CANCEL;
-       }
+       /* do stuff here */
+       doEdgeSlide(t, final);
 
        recalcData(t);
 
        ED_area_headerprint(t->sa, str);
-
-       return 1;
 }
+/** \} */
+
 
+/* -------------------------------------------------------------------- */
+/* Transform (Vert Slide) */
+
+/** \name Transform Vert Slide
+ * \{ */
 
-/* ******************** Vert Slide *************** */
 static void calcVertSlideCustomPoints(struct TransInfo *t)
 {
        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]};
+       const int mval_start[2] = {co_orig[0], co_orig[1]};
+       const int mval_end[2]   = {co_curr[0], co_curr[1]};
 
        if (sld->flipped_vtx && sld->is_proportional == false) {
-               setCustomPoints(t, &t->mouse, start, end);
+               setCustomPoints(t, &t->mouse, mval_start, mval_end);
        }
        else {
-               setCustomPoints(t, &t->mouse, end, start);
+               setCustomPoints(t, &t->mouse, mval_end, mval_start);
        }
 }
 
@@ -6088,9 +6289,9 @@ static void calcVertSlideMouseActiveEdges(struct TransInfo *t, const int mval[2]
        }
 }
 
-static int createVertSlideVerts(TransInfo *t)
+static bool createVertSlideVerts(TransInfo *t)
 {
-       BMEditMesh *em = BMEdit_FromObject(t->obedit);
+       BMEditMesh *em = BKE_editmesh_from_object(t->obedit);
        BMesh *bm = em->bm;
        BMIter iter;
        BMIter eiter;
@@ -6145,7 +6346,7 @@ static int createVertSlideVerts(TransInfo *t)
 
        if (!j) {
                MEM_freeN(sld);
-               return 0;
+               return false;
        }
 
        sv_array = MEM_callocN(sizeof(TransDataVertSlideVert) * j, "sv_array");
@@ -6216,7 +6417,7 @@ static int createVertSlideVerts(TransInfo *t)
                calcVertSlideMouseActiveEdges(t, t->mval);
        }
 
-       return 1;
+       return true;
 }
 
 void freeVertSlideVerts(TransInfo *t)
@@ -6244,12 +6445,12 @@ void freeVertSlideVerts(TransInfo *t)
        recalcData(t);
 }
 
-void initVertSlide(TransInfo *t)
+static void initVertSlide(TransInfo *t)
 {
        VertSlideData *sld;
 
        t->mode = TFM_VERT_SLIDE;
-       t->transform = VertSlide;
+       t->transform = applyVertSlide;
        t->handleEvent = handleEventVertSlide;
 
        if (!createVertSlideVerts(t)) {
@@ -6274,12 +6475,14 @@ void initVertSlide(TransInfo *t)
        t->snap[1] = 0.1f;
        t->snap[2] = t->snap[1] * 0.1f;
 
-       t->num.increment = t->snap[1];
+       copy_v3_fl(t->num.val_inc, t->snap[1]);
+       t->num.unit_sys = t->scene->unit.system;
+       t->num.unit_type[0] = B_UNIT_NONE;
 
        t->flag |= T_NO_CONSTRAINT | T_NO_PROJECT;
 }
 
-int handleEventVertSlide(struct TransInfo *t, const struct wmEvent *event)
+static eRedrawFlag handleEventVertSlide(struct TransInfo *t, const struct wmEvent *event)
 {
        if (t->mode == TFM_VERT_SLIDE) {
                VertSlideData *sld = t->customData;
@@ -6292,7 +6495,7 @@ int handleEventVertSlide(struct TransInfo *t, const struct wmEvent *event)
                                                if (sld->flipped_vtx) {
                                                        calcVertSlideCustomPoints(t);
                                                }
-                                               return 1;
+                                               return TREDRAW_HARD;
                                        }
                                        break;
                                case FKEY:
@@ -6300,7 +6503,7 @@ int handleEventVertSlide(struct TransInfo *t, const struct wmEvent *event)
                                        if (event->val == KM_PRESS) {
                                                sld->flipped_vtx = !sld->flipped_vtx;
                                                calcVertSlideCustomPoints(t);
-                                               return 1;
+                                               return TREDRAW_HARD;
                                        }
                                        break;
                                }
@@ -6310,7 +6513,7 @@ int handleEventVertSlide(struct TransInfo *t, const struct wmEvent *event)
                                        if (event->val == KM_PRESS) {
                                                t->flag ^= T_ALT_TRANSFORM;
                                                calcVertSlideCustomPoints(t);
-                                               return 1;
+                                               return TREDRAW_HARD;
                                        }
                                        break;
                                }
@@ -6339,13 +6542,14 @@ int handleEventVertSlide(struct TransInfo *t, const struct wmEvent *event)
                                                calcVertSlideMouseActiveEdges(t, event->mval);
                                        }
                                        calcVertSlideCustomPoints(t);
+                                       break;
                                }
                                default:
                                        break;
                        }
                }
        }
-       return 0;
+       return TREDRAW_NOTHING;
 }
 
 static void drawVertSlide(const struct bContext *C, TransInfo *t)
@@ -6359,7 +6563,7 @@ static void drawVertSlide(const struct bContext *C, TransInfo *t)
                        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 int alpha_shade = -160;
                        const bool is_clamp = !(t->flag & T_ALT_TRANSFORM);
                        int i;
 
@@ -6462,7 +6666,7 @@ static int doVertSlide(TransInfo *t, float perc)
        return 1;
 }
 
-int VertSlide(TransInfo *t, const int UNUSED(mval[2]))
+static void applyVertSlide(TransInfo *t, const int UNUSED(mval[2]))
 {
        char str[MAX_INFO_LEN];
        size_t ofs = 0;
@@ -6473,12 +6677,9 @@ int VertSlide(TransInfo *t, const int UNUSED(mval[2]))
        const bool is_clamp = !(t->flag & T_ALT_TRANSFORM);
        const bool is_constrained = !(is_clamp == false || hasNumInput(&t->num));
 
-       const char *on_str = IFACE_("ON");
-       const char *off_str = IFACE_("OFF");
-
        final = t->values[0];
 
-       snapGrid(t, &final);
+       snapGridIncrement(t, &final);
 
        /* only do this so out of range values are not displayed */
        if (is_constrained) {
@@ -6496,51 +6697,51 @@ int VertSlide(TransInfo *t, const int UNUSED(mval[2]))
        else {
                ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, "%.4f ", final);
        }
-       ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("(E)ven: %s, "), !is_proportional ? on_str : off_str);
+       ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("(E)ven: %s, "), WM_bool_as_string(!is_proportional));
        if (!is_proportional) {
-               ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("(F)lipped: %s, "), flipped ? on_str : off_str);
+               ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("(F)lipped: %s, "), WM_bool_as_string(flipped));
        }
-       ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("Alt or (C)lamp: %s"), is_clamp ? on_str : off_str);
+       ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("Alt or (C)lamp: %s"), WM_bool_as_string(is_clamp));
        /* done with header string */
 
-       /*do stuff here*/
-       if (t->customData) {
-               doVertSlide(t, final);
-       }
-       else {
-               BLI_strncpy(str, IFACE_("Invalid Vert Selection"), MAX_INFO_LEN);
-               t->state = TRANS_CANCEL;
-       }
+       /* do stuff here */
+       doVertSlide(t, final);
 
        recalcData(t);
 
        ED_area_headerprint(t->sa, str);
-
-       return 1;
 }
+/** \} */
+
 
+/* -------------------------------------------------------------------- */
+/* Transform (EditBone Roll) */
 
-/* ******************** EditBone roll *************** */
+/** \name Transform EditBone Roll
+ * \{ */
 
-void initBoneRoll(TransInfo *t)
+static void initBoneRoll(TransInfo *t)
 {
        t->mode = TFM_BONE_ROLL;
-       t->transform = BoneRoll;
+       t->transform = applyBoneRoll;
 
        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->snap[1] = DEG2RAD(5.0);
+       t->snap[2] = DEG2RAD(1.0);
 
-       t->num.increment = 1.0f;
+       copy_v3_fl(t->num.val_inc, t->snap[1]);
+       t->num.unit_sys = t->scene->unit.system;
+       t->num.unit_use_radians = (t->scene->unit.system_rotation == USER_UNIT_ROT_RADIANS);
+       t->num.unit_type[0] = B_UNIT_ROTATION;
 
        t->flag |= T_NO_CONSTRAINT | T_NO_PROJECT;
 }
 
-int BoneRoll(TransInfo *t, const int UNUSED(mval[2]))
+static void applyBoneRoll(TransInfo *t, const int UNUSED(mval[2]))
 {
        TransData *td = t->data;
        int i;
@@ -6550,7 +6751,7 @@ int BoneRoll(TransInfo *t, const int UNUSED(mval[2]))
 
        final = t->values[0];
 
-       snapGrid(t, &final);
+       snapGridIncrement(t, &final);
 
        if (hasNumInput(&t->num)) {
                char c[NUM_STR_REP_LEN];
@@ -6560,8 +6761,6 @@ int BoneRoll(TransInfo *t, const int UNUSED(mval[2]))
                outputNumInput(&(t->num), c);
 
                BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Roll: %s"), &c[0]);
-
-               final = DEG2RADF(final);
        }
        else {
                BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Roll: %.2f"), RAD2DEGF(final));
@@ -6581,15 +6780,19 @@ int BoneRoll(TransInfo *t, const int UNUSED(mval[2]))
        recalcData(t);
 
        ED_area_headerprint(t->sa, str);
-
-       return 1;
 }
+/** \} */
 
-/* ************************** BAKE TIME ******************* */
 
-void initBakeTime(TransInfo *t)
+/* -------------------------------------------------------------------- */
+/* Transform (Bake-Time) */
+
+/** \name Transform Bake-Time
+ * \{ */
+
+static void initBakeTime(TransInfo *t)
 {
-       t->transform = BakeTime;
+       t->transform = applyBakeTime;
        initMouseInputMode(t, &t->mouse, INPUT_NONE);
 
        t->idx_max = 0;
@@ -6598,10 +6801,12 @@ void initBakeTime(TransInfo *t)
        t->snap[1] = 1.0f;
        t->snap[2] = t->snap[1] * 0.1f;
 
-       t->num.increment = t->snap[1];
+       copy_v3_fl(t->num.val_inc, t->snap[1]);
+       t->num.unit_sys = t->scene->unit.system;
+       t->num.unit_type[0] = B_UNIT_NONE;  /* Don't think this uses units? */
 }
 
-int BakeTime(TransInfo *t, const int mval[2])
+static void applyBakeTime(TransInfo *t, const int mval[2])
 {
        TransData *td = t->data;
        float time;
@@ -6619,7 +6824,7 @@ int BakeTime(TransInfo *t, const int mval[2])
                time = (float)(t->center2d[0] - mval[0]) * fac;
        }
 
-       snapGrid(t, &time);
+       snapGridIncrement(t, &time);
 
        applyNumInput(&t->num, &time);
 
@@ -6659,15 +6864,19 @@ int BakeTime(TransInfo *t, const int mval[2])
        recalcData(t);
 
        ED_area_headerprint(t->sa, str);
-
-       return 1;
 }
+/** \} */
 
-/* ************************** MIRROR *************************** */
 
-void initMirror(TransInfo *t)
+/* -------------------------------------------------------------------- */
+/* Transform (Mirror) */
+
+/** \name Transform Mirror
+ * \{ */
+
+static void initMirror(TransInfo *t)
 {
-       t->transform = Mirror;
+       t->transform = applyMirror;
        initMouseInputMode(t, &t->mouse, INPUT_NONE);
 
        t->flag |= T_NULL_ONE;
@@ -6676,7 +6885,7 @@ void initMirror(TransInfo *t)
        }
 }
 
-int Mirror(TransInfo *t, const int UNUSED(mval[2]))
+static void applyMirror(TransInfo *t, const int UNUSED(mval[2]))
 {
        TransData *td;
        float size[3], mat[3][3];
@@ -6737,22 +6946,26 @@ int Mirror(TransInfo *t, const int UNUSED(mval[2]))
                else
                        ED_area_headerprint(t->sa, IFACE_("Select a mirror axis (X, Y, Z)"));
        }
-
-       return 1;
 }
+/** \} */
+
 
-/* ************************** ALIGN *************************** */
+/* -------------------------------------------------------------------- */
+/* Transform (Align) */
 
-void initAlign(TransInfo *t)
+/** \name Transform Align
+ * \{ */
+
+static void initAlign(TransInfo *t)
 {
        t->flag |= T_NO_CONSTRAINT;
 
-       t->transform = Align;
+       t->transform = applyAlign;
 
        initMouseInputMode(t, &t->mouse, INPUT_NONE);
 }
 
-int Align(TransInfo *t, const int UNUSED(mval[2]))
+static void applyAlign(TransInfo *t, const int UNUSED(mval[2]))
 {
        TransData *td = t->data;
        float center[3];
@@ -6793,15 +7006,19 @@ int Align(TransInfo *t, const int UNUSED(mval[2]))
        recalcData(t);
 
        ED_area_headerprint(t->sa, IFACE_("Align"));
-
-       return 1;
 }
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+/* Transform (Sequencer Slide) */
 
-/* ************************** SEQ SLIDE *************************** */
+/** \name Transform Sequencer Slide
+ * \{ */
 
-void initSeqSlide(TransInfo *t)
+static void initSeqSlide(TransInfo *t)
 {
-       t->transform = SeqSlide;
+       t->transform = applySeqSlide;
 
        initMouseInputMode(t, &t->mouse, INPUT_VECTOR);
 
@@ -6813,11 +7030,14 @@ void initSeqSlide(TransInfo *t)
        t->snap[1] = floor(t->scene->r.frs_sec / t->scene->r.frs_sec_base);
        t->snap[2] = 10.0f;
 
-       t->num.increment = t->snap[1];
+       copy_v3_fl(t->num.val_inc, t->snap[1]);
+       t->num.unit_sys = t->scene->unit.system;
+       /* Would be nice to have a time handling in units as well (supporting frames in addition to "natural" time...). */
+       t->num.unit_type[0] = B_UNIT_NONE;
+       t->num.unit_type[1] = B_UNIT_NONE;
 }
 
-/* We assume str is MAX_INFO_LEN long. */
-static void headerSeqSlide(TransInfo *t, float val[2], char *str)
+static void headerSeqSlide(TransInfo *t, float val[2], char str[MAX_INFO_LEN])
 {
        char tvec[NUM_STR_REP_LEN * 3];
        size_t ofs = 0;
@@ -6831,17 +7051,17 @@ static void headerSeqSlide(TransInfo *t, float val[2], char *str)
 
        ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("Sequence Slide: %s%s, ("), &tvec[0], t->con.text);
 
-       {
+       if (t->keymap) {
                wmKeyMapItem *kmi = WM_modalkeymap_find_propvalue(t->keymap, TFM_MODAL_TRANSLATE);
                if (kmi) {
                        ofs += WM_keymap_item_to_string(kmi, str + ofs, MAX_INFO_LEN - ofs);
                }
        }
        ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_(" or Alt) Expand to fit %s"),
-                           (t->flag & T_ALT_TRANSFORM) ? IFACE_("ON") : IFACE_("OFF"));
+                           WM_bool_as_string((t->flag & T_ALT_TRANSFORM) != 0));
 }
 
-static void applySeqSlide(TransInfo *t, float val[2])
+static void applySeqSlideValue(TransInfo *t, const float val[2])
 {
        TransData *td = t->data;
        int i;
@@ -6864,7 +7084,7 @@ static void applySeqSlide(TransInfo *t, float val[2])
        }
 }
 
-int SeqSlide(TransInfo *t, const int UNUSED(mval[2]))
+static void applySeqSlide(TransInfo *t, const int UNUSED(mval[2]))
 {
        char str[MAX_INFO_LEN];
 
@@ -6875,7 +7095,7 @@ int SeqSlide(TransInfo *t, const int UNUSED(mval[2]))
                copy_v3_v3(t->values, tvec);
        }
        else {
-               snapGrid(t, t->values);
+               snapGridIncrement(t, t->values);
                applyNumInput(&t->num, t->values);
        }
 
@@ -6883,19 +7103,23 @@ int SeqSlide(TransInfo *t, const int UNUSED(mval[2]))
        t->values[1] = floor(t->values[1] + 0.5f);
 
        headerSeqSlide(t, t->values, str);
-       applySeqSlide(t, t->values);
+       applySeqSlideValue(t, t->values);
 
        recalcData(t);
 
        ED_area_headerprint(t->sa, str);
-
-       return 1;
 }
+/** \} */
 
-/* ************************** ANIM EDITORS - TRANSFORM TOOLS *************************** */
 
-/* ---------------- Special Helpers for Various Settings ------------- */
+/* -------------------------------------------------------------------- */
+/* Animation Editors - Transform Utils
+ *
+ * Special Helpers for Various Settings
+ */
 
+/** \name Animation Editor Utils
+ * \{ */
 
 /* This function returns the snapping 'mode' for Animation Editors only
  * We cannot use the standard snapping due to NLA-strip scaling complexities.
@@ -7047,10 +7271,16 @@ static void doAnimEdit_SnapFrame(TransInfo *t, TransData *td, TransData2D *td2d,
                td2d->h2[0] = td2d->ih2[0] + *td->val - td->ival;
        }
 }
+/** \} */
 
-/* ----------------- Translation ----------------------- */
 
-void initTimeTranslate(TransInfo *t)
+/* -------------------------------------------------------------------- */
+/* Transform (Animation Translation) */
+
+/** \name Transform Animation Translation
+ * \{ */
+
+static void initTimeTranslate(TransInfo *t)
 {
        /* this tool is only really available in the Action Editor... */
        if (!ELEM(t->spacetype, SPACE_ACTION, SPACE_SEQ)) {
@@ -7058,7 +7288,7 @@ void initTimeTranslate(TransInfo *t)
        }
 
        t->mode = TFM_TIME_TRANSLATE;
-       t->transform = TimeTranslate;
+       t->transform = applyTimeTranslate;
 
        initMouseInputMode(t, &t->mouse, INPUT_NONE);
 
@@ -7071,11 +7301,13 @@ void initTimeTranslate(TransInfo *t)
        t->snap[0] = 0.0f;
        t->snap[1] = t->snap[2] = 1.0f;
 
-       t->num.increment = t->snap[1];
+       copy_v3_fl(t->num.val_inc, t->snap[1]);
+       t->num.unit_sys = t->scene->unit.system;
+       /* No time unit supporting frames currently... */
+       t->num.unit_type[0] = B_UNIT_NONE;
 }
 
-/* We assume str is MAX_INFO_LEN long. */
-static void headerTimeTranslate(TransInfo *t, char *str)
+static void headerTimeTranslate(TransInfo *t, char str[MAX_INFO_LEN])
 {
        char tvec[NUM_STR_REP_LEN * 3];
 
@@ -7111,7 +7343,7 @@ static void headerTimeTranslate(TransInfo *t, char *str)
        BLI_snprintf(str, MAX_INFO_LEN, IFACE_("DeltaX: %s"), &tvec[0]);
 }
 
-static void applyTimeTranslate(TransInfo *t, float UNUSED(sval))
+static void applyTimeTranslateValue(TransInfo *t, float UNUSED(sval))
 {
        TransData *td = t->data;
        TransData2D *td2d = t->data2d;
@@ -7168,7 +7400,7 @@ static void applyTimeTranslate(TransInfo *t, float UNUSED(sval))
        }
 }
 
-int TimeTranslate(TransInfo *t, const int mval[2])
+static void applyTimeTranslate(TransInfo *t, const int mval[2])
 {
        View2D *v2d = (View2D *)t->view;
        float cval[2], sval[2];
@@ -7187,18 +7419,22 @@ int TimeTranslate(TransInfo *t, const int mval[2])
        t->values[0] = t->vec[0];
        headerTimeTranslate(t, str);
 
-       applyTimeTranslate(t, sval[0]);
+       applyTimeTranslateValue(t, sval[0]);
 
        recalcData(t);
 
        ED_area_headerprint(t->sa, str);
-
-       return 1;
 }
+/** \} */
+
 
-/* ----------------- Time Slide ----------------------- */
+/* -------------------------------------------------------------------- */
+/* Transform (Animation Time Slide) */
 
-void initTimeSlide(TransInfo *t)
+/** \name Transform Animation Time Slide
+ * \{ */
+
+static void initTimeSlide(TransInfo *t)
 {
        /* this tool is only really available in the Action Editor... */
        if (t->spacetype == SPACE_ACTION) {
@@ -7213,7 +7449,7 @@ void initTimeSlide(TransInfo *t)
 
 
        t->mode = TFM_TIME_SLIDE;
-       t->transform = TimeSlide;
+       t->transform = applyTimeSlide;
        t->flag |= T_FREE_CUSTOMDATA;
 
        initMouseInputMode(t, &t->mouse, INPUT_NONE);
@@ -7227,11 +7463,13 @@ void initTimeSlide(TransInfo *t)
        t->snap[0] = 0.0f;
        t->snap[1] = t->snap[2] = 1.0f;
 
-       t->num.increment = t->snap[1];
+       copy_v3_fl(t->num.val_inc, t->snap[1]);
+       t->num.unit_sys = t->scene->unit.system;
+       /* No time unit supporting frames currently... */
+       t->num.unit_type[0] = B_UNIT_NONE;
 }
 
-/* We assume str is MAX_INFO_LEN long. */
-static void headerTimeSlide(TransInfo *t, float sval, char *str)
+static void headerTimeSlide(TransInfo *t, float sval, char str[MAX_INFO_LEN])
 {
        char tvec[NUM_STR_REP_LEN * 3];
 
@@ -7253,7 +7491,7 @@ static void headerTimeSlide(TransInfo *t, float sval, char *str)
        BLI_snprintf(str, MAX_INFO_LEN, IFACE_("TimeSlide: %s"), &tvec[0]);
 }
 
-static void applyTimeSlide(TransInfo *t, float sval)
+static void applyTimeSlideValue(TransInfo *t, float sval)
 {
        TransData *td = t->data;
        int i;
@@ -7300,7 +7538,7 @@ static void applyTimeSlide(TransInfo *t, float sval)
        }
 }
 
-int TimeSlide(TransInfo *t, const int mval[2])
+static void applyTimeSlide(TransInfo *t, const int mval[2])
 {
        View2D *v2d = (View2D *)t->view;
        float cval[2], sval[2];
@@ -7322,20 +7560,24 @@ int TimeSlide(TransInfo *t, const int mval[2])
        t->values[0] = (maxx - minx) * t->vec[0] / 2.0f + sval[0];
 
        headerTimeSlide(t, sval[0], str);
-       applyTimeSlide(t, sval[0]);
+       applyTimeSlideValue(t, sval[0]);
 
        recalcData(t);
 
        ED_area_headerprint(t->sa, str);
-
-       return 1;
 }
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+/* Transform (Animation Time Scale) */
 
-/* ----------------- Scaling ----------------------- */
+/** \name Transform Animation Time Scale
+ * \{ */
 
-void initTimeScale(TransInfo *t)
+static void initTimeScale(TransInfo *t)
 {
-       int center[2];
+       float center[2];
 
        /* this tool is only really available in the Action Editor
         * AND NLA Editor (for strip scaling)
@@ -7345,12 +7587,12 @@ void initTimeScale(TransInfo *t)
        }
 
        t->mode = TFM_TIME_SCALE;
-       t->transform = TimeScale;
+       t->transform = applyTimeScale;
 
        /* recalculate center2d to use CFRA and mouse Y, since that's
         * what is used in time scale */
        t->center[0] = t->scene->r.cfra;
-       projectIntView(t, t->center, center);
+       projectFloatView(t, t->center, center);
        center[1] = t->imval[1];
 
        /* force a reinit with the center2d used here */
@@ -7359,7 +7601,7 @@ void initTimeScale(TransInfo *t)
        initMouseInputMode(t, &t->mouse, INPUT_SPRING_FLIP);
 
        t->flag |= T_NULL_ONE;
-       t->num.flag |= NUM_NULL_ONE;
+       t->num.val_flag[0] |= NUM_NULL_ONE;
 
        /* num-input has max of (n-1) */
        t->idx_max = 0;
@@ -7370,11 +7612,12 @@ void initTimeScale(TransInfo *t)
        t->snap[0] = 0.0f;
        t->snap[1] = t->snap[2] = 1.0f;
 
-       t->num.increment = t->snap[1];
+       copy_v3_fl(t->num.val_inc, t->snap[1]);
+       t->num.unit_sys = t->scene->unit.system;
+       t->num.unit_type[0] = B_UNIT_NONE;
 }
 
-/* We assume str is MAX_INFO_LEN long. */
-static void headerTimeScale(TransInfo *t, char *str)
+static void headerTimeScale(TransInfo *t, char str[MAX_INFO_LEN])
 {
        char tvec[NUM_STR_REP_LEN * 3];
 
@@ -7386,7 +7629,7 @@ static void headerTimeScale(TransInfo *t, char *str)
        BLI_snprintf(str, MAX_INFO_LEN, IFACE_("ScaleX: %s"), &tvec[0]);
 }
 
-static void applyTimeScale(TransInfo *t)
+static void applyTimeScaleValue(TransInfo *t)
 {
        Scene *scene = t->scene;
        TransData *td = t->data;
@@ -7426,7 +7669,7 @@ static void applyTimeScale(TransInfo *t)
        }
 }
 
-int TimeScale(TransInfo *t, const int UNUSED(mval[2]))
+static void applyTimeScale(TransInfo *t, const int UNUSED(mval[2]))
 {
        char str[MAX_INFO_LEN];
        
@@ -7436,22 +7679,13 @@ int TimeScale(TransInfo *t, const int UNUSED(mval[2]))
        t->values[0] = t->vec[0];
        headerTimeScale(t, str);
 
-       applyTimeScale(t);
+       applyTimeScaleValue(t);
 
        recalcData(t);
 
        ED_area_headerprint(t->sa, str);
-
-       return 1;
-}
-
-/* ************************************ */
-
-void BIF_TransformSetUndo(const char *UNUSED(str))
-{
-       // TRANSFORM_FIX_ME
-       //Trans.undostr = str;
 }
+/** \} */
 
 
 /* TODO, move to: transform_queries.c */
@@ -7460,4 +7694,17 @@ bool checkUseLocalCenter_GraphEdit(TransInfo *t)
        return ((t->around == V3D_LOCAL) && !ELEM3(t->mode, TFM_TRANSLATION, TFM_TIME_TRANSLATE, TFM_TIME_SLIDE));
 }
 
+bool checkUseAxisMatrix(TransInfo *t)
+{
+       /* currenly only checks for editmode */
+       if (t->flag & T_EDIT) {
+               if ((t->around == V3D_LOCAL) && (ELEM4(t->obedit->type, OB_MESH, OB_CURVE, OB_MBALL, OB_ARMATURE))) {
+                       /* not all editmode supports axis-matrix */
+                       return true;
+               }
+       }
+
+       return false;
+}
+
 #undef MAX_INFO_LEN