code cleanup: rename transform Slide operations to EdgeSlide.
[blender.git] / source / blender / editors / transform / transform.c
index 928b9c2fc628b50a73fe2ba4ff247076501e8a70..7cc6006970c8302e2a5ce5a6d3abd90fb72703e2 100644 (file)
@@ -29,7 +29,6 @@
  *  \ingroup edtransform
  */
 
  *  \ingroup edtransform
  */
 
-
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
@@ -37,9 +36,9 @@
 #include <float.h>
 
 #ifndef WIN32
 #include <float.h>
 
 #ifndef WIN32
-#include <unistd.h>
+#  include <unistd.h>
 #else
 #else
-#include <io.h>
+#  include <io.h>
 #endif
 
 #include "MEM_guardedalloc.h"
 #endif
 
 #include "MEM_guardedalloc.h"
 #include "DNA_movieclip_types.h"
 #include "DNA_scene_types.h"  /* PET modes */
 
 #include "DNA_movieclip_types.h"
 #include "DNA_scene_types.h"  /* PET modes */
 
-#include "RNA_access.h"
-
-#include "BIF_gl.h"
-#include "BIF_glutil.h"
+#include "BLI_utildefines.h"
+#include "BLI_math.h"
+#include "BLI_rect.h"
+#include "BLI_listbase.h"
+#include "BLI_string.h"
+#include "BLI_ghash.h"
+#include "BLI_linklist.h"
+#include "BLI_smallhash.h"
 
 #include "BKE_nla.h"
 #include "BKE_bmesh.h"
 
 #include "BKE_nla.h"
 #include "BKE_bmesh.h"
 #include "BKE_particle.h"
 #include "BKE_pointcache.h"
 #include "BKE_unit.h"
 #include "BKE_particle.h"
 #include "BKE_pointcache.h"
 #include "BKE_unit.h"
+#include "BKE_mask.h"
+
+#include "BIF_gl.h"
+#include "BIF_glutil.h"
 
 #include "ED_image.h"
 #include "ED_keyframing.h"
 
 #include "ED_image.h"
 #include "ED_keyframing.h"
 #include "ED_view3d.h"
 #include "ED_mesh.h"
 #include "ED_clip.h"
 #include "ED_view3d.h"
 #include "ED_mesh.h"
 #include "ED_clip.h"
+#include "ED_mask.h"
 
 
-#include "UI_view2d.h"
 #include "WM_types.h"
 #include "WM_api.h"
 
 #include "WM_types.h"
 #include "WM_api.h"
 
-#include "BLI_math.h"
-#include "BLI_blenlib.h"
-#include "BLI_utildefines.h"
-#include "BLI_ghash.h"
-#include "BLI_linklist.h"
-#include "BLI_smallhash.h"
-#include "BLI_array.h"
-
+#include "UI_view2d.h"
+#include "UI_interface_icons.h"
 #include "UI_resources.h"
 
 #include "UI_resources.h"
 
-//#include "blendef.h"
-//
-//#include "mydevice.h"
+#include "RNA_access.h"
 
 
-#include "transform.h"
+#include "BLF_api.h"
 
 
-#include <stdio.h>
+#include "transform.h"
 
 
-static void drawTransformApply(const struct bContext *C, struct ARegion *ar, void *arg);
+static void drawTransformApply(const struct bContext *C, ARegion *ar, void *arg);
 static int doEdgeSlide(TransInfo *t, float perc);
 
 /* ************************** SPACE DEPENDANT CODE **************************** */
 static int doEdgeSlide(TransInfo *t, float perc);
 
 /* ************************** SPACE DEPENDANT CODE **************************** */
@@ -125,32 +124,65 @@ void setTransformViewMatrices(TransInfo *t)
        calculateCenter2D(t);
 }
 
        calculateCenter2D(t);
 }
 
-static void convertViewVec2D(View2D *v2d, float vec[3], int dx, int dy)
+static void convertViewVec2D(View2D *v2d, float r_vec[3], int dx, int dy)
 {
        float divx, divy;
        
 {
        float divx, divy;
        
-       divx = v2d->mask.xmax - v2d->mask.xmin;
-       divy = v2d->mask.ymax - v2d->mask.ymin;
+       divx = BLI_rcti_size_x(&v2d->mask);
+       divy = BLI_rcti_size_y(&v2d->mask);
+
+       r_vec[0] = BLI_rctf_size_x(&v2d->cur) * dx / divx;
+       r_vec[1] = BLI_rctf_size_y(&v2d->cur) * dy / divy;
+       r_vec[2] = 0.0f;
+}
+
+static void convertViewVec2D_mask(View2D *v2d, float r_vec[3], int dx, int dy)
+{
+       float divx, divy;
+       float mulx, muly;
+
+       divx = BLI_rcti_size_x(&v2d->mask);
+       divy = BLI_rcti_size_y(&v2d->mask);
 
 
-       vec[0] = (v2d->cur.xmax - v2d->cur.xmin) * dx / divx;
-       vec[1] = (v2d->cur.ymax - v2d->cur.ymin) * dy / divy;
-       vec[2] = 0.0f;
+       mulx = BLI_rctf_size_x(&v2d->cur);
+       muly = BLI_rctf_size_y(&v2d->cur);
+
+       /* difference with convertViewVec2D */
+       /* clamp w/h, mask only */
+       if (mulx / divx < muly / divy) {
+               divy = divx;
+               muly = mulx;
+       }
+       else {
+               divx = divy;
+               mulx = muly;
+       }
+       /* end difference */
+
+       r_vec[0] = mulx * dx / divx;
+       r_vec[1] = muly * dy / divy;
+       r_vec[2] = 0.0f;
 }
 
 void convertViewVec(TransInfo *t, float r_vec[3], int dx, int dy)
 {
        if ((t->spacetype == SPACE_VIEW3D) && (t->ar->regiontype == RGN_TYPE_WINDOW)) {
 }
 
 void convertViewVec(TransInfo *t, float r_vec[3], int dx, int dy)
 {
        if ((t->spacetype == SPACE_VIEW3D) && (t->ar->regiontype == RGN_TYPE_WINDOW)) {
-               float mval_f[2];
-               mval_f[0] = dx;
-               mval_f[1] = dy;
+               const float mval_f[2] = {(float)dx, (float)dy};
                ED_view3d_win_to_delta(t->ar, mval_f, r_vec);
        }
        else if (t->spacetype == SPACE_IMAGE) {
                float aspx, aspy;
 
                ED_view3d_win_to_delta(t->ar, mval_f, r_vec);
        }
        else if (t->spacetype == SPACE_IMAGE) {
                float aspx, aspy;
 
-               convertViewVec2D(t->view, r_vec, dx, dy);
+               if (t->options & CTX_MASK) {
+
+                       convertViewVec2D_mask(t->view, r_vec, dx, dy);
+                       ED_space_image_get_aspect(t->sa->spacedata.first, &aspx, &aspy);
+               }
+               else {
+                       convertViewVec2D(t->view, r_vec, dx, dy);
+                       ED_space_image_get_uv_aspect(t->sa->spacedata.first, &aspx, &aspy);
+               }
 
 
-               ED_space_image_uv_aspect(t->sa->spacedata.first, &aspx, &aspy);
                r_vec[0] *= aspx;
                r_vec[1] *= aspy;
        }
                r_vec[0] *= aspx;
                r_vec[1] *= aspy;
        }
@@ -161,26 +193,14 @@ void convertViewVec(TransInfo *t, float r_vec[3], int dx, int dy)
                convertViewVec2D(&t->ar->v2d, r_vec, dx, dy);
        }
        else if (t->spacetype == SPACE_CLIP) {
                convertViewVec2D(&t->ar->v2d, r_vec, dx, dy);
        }
        else if (t->spacetype == SPACE_CLIP) {
-               View2D *v2d = t->view;
-               float divx, divy;
-               float mulx, muly;
-               float aspx = 1.0f, aspy = 1.0f;
-
-               divx = v2d->mask.xmax - v2d->mask.xmin;
-               divy = v2d->mask.ymax - v2d->mask.ymin;
-
-               mulx = (v2d->cur.xmax - v2d->cur.xmin);
-               muly = (v2d->cur.ymax - v2d->cur.ymin);
+               float aspx, aspy;
 
                if (t->options & CTX_MASK) {
 
                if (t->options & CTX_MASK) {
-                       /* clamp w/h, mask only */
-                       divx = divy = maxf(divx, divy);
-                       mulx = muly = minf(mulx, muly);
+                       convertViewVec2D_mask(t->view, r_vec, dx, dy);
+               }
+               else {
+                       convertViewVec2D(t->view, r_vec, dx, dy);
                }
                }
-
-               r_vec[0] = mulx * (dx) / divx;
-               r_vec[1] = muly * (dy) / divy;
-               r_vec[2] = 0.0f;
 
                if (t->options & CTX_MOVIECLIP) {
                        ED_space_clip_get_aspect_dimension_aware(t->sa->spacedata.first, &aspx, &aspy);
 
                if (t->options & CTX_MOVIECLIP) {
                        ED_space_clip_get_aspect_dimension_aware(t->sa->spacedata.first, &aspx, &aspy);
@@ -189,6 +209,11 @@ void convertViewVec(TransInfo *t, float r_vec[3], int dx, int dy)
                        /* TODO - NOT WORKING, this isnt so bad since its only display aspect */
                        ED_space_clip_get_aspect(t->sa->spacedata.first, &aspx, &aspy);
                }
                        /* TODO - NOT WORKING, this isnt so bad since its only display aspect */
                        ED_space_clip_get_aspect(t->sa->spacedata.first, &aspx, &aspy);
                }
+               else {
+                       /* should never happen, quiet warnings */
+                       BLI_assert(0);
+                       aspx = aspy = 1.0f;
+               }
 
                r_vec[0] *= aspx;
                r_vec[1] *= aspy;
 
                r_vec[0] *= aspx;
                r_vec[1] *= aspy;
@@ -202,17 +227,47 @@ void convertViewVec(TransInfo *t, float r_vec[3], int dx, int dy)
 void projectIntView(TransInfo *t, const float vec[3], int adr[2])
 {
        if (t->spacetype == SPACE_VIEW3D) {
 void projectIntView(TransInfo *t, const float vec[3], int adr[2])
 {
        if (t->spacetype == SPACE_VIEW3D) {
-               if (t->ar->regiontype == RGN_TYPE_WINDOW)
-                       project_int_noclip(t->ar, vec, adr);
+               if (t->ar->regiontype == RGN_TYPE_WINDOW) {
+                       if (ED_view3d_project_int_global(t->ar, vec, adr, V3D_PROJ_TEST_NOP) != V3D_PROJ_RET_OK) {
+                               adr[0] = (int)2140000000.0f;  /* this is what was done in 2.64, perhaps we can be smarter? */
+                               adr[1] = (int)2140000000.0f;
+                       }
+               }
        }
        else if (t->spacetype == SPACE_IMAGE) {
        }
        else if (t->spacetype == SPACE_IMAGE) {
-               float aspx, aspy, v[2];
+               SpaceImage *sima = t->sa->spacedata.first;
+
+               if (t->options & CTX_MASK) {
+                       /* not working quite right, TODO (see below too) */
+                       float aspx, aspy;
+                       float v[2];
 
 
-               ED_space_image_uv_aspect(t->sa->spacedata.first, &aspx, &aspy);
-               v[0] = vec[0] / aspx;
-               v[1] = vec[1] / aspy;
+                       ED_space_image_get_aspect(sima, &aspx, &aspy);
 
 
-               UI_view2d_to_region_no_clip(t->view, v[0], v[1], adr, adr + 1);
+                       copy_v2_v2(v, vec);
+
+                       v[0] = v[0] / aspx;
+                       v[1] = v[1] / aspy;
+
+                       BKE_mask_coord_to_image(sima->image, &sima->iuser, v, v);
+
+                       v[0] = v[0] / aspx;
+                       v[1] = v[1] / aspy;
+
+                       ED_image_point_pos__reverse(sima, t->ar, v, v);
+
+                       adr[0] = v[0];
+                       adr[1] = v[1];
+               }
+               else {
+                       float aspx, aspy, v[2];
+
+                       ED_space_image_get_uv_aspect(t->sa->spacedata.first, &aspx, &aspy);
+                       v[0] = vec[0] / aspx;
+                       v[1] = vec[1] / aspy;
+
+                       UI_view2d_to_region_no_clip(t->view, v[0], v[1], adr, adr + 1);
+               }
        }
        else if (t->spacetype == SPACE_ACTION) {
                int out[2] = {0, 0};
        }
        else if (t->spacetype == SPACE_ACTION) {
                int out[2] = {0, 0};
@@ -223,7 +278,7 @@ void projectIntView(TransInfo *t, const float vec[3], int adr[2])
                        //vec[0] = vec[0]/((t->scene->r.frs_sec / t->scene->r.frs_sec_base));
                        /* same as below */
                        UI_view2d_to_region_no_clip((View2D *)t->view, vec[0], vec[1], out, out + 1);
                        //vec[0] = vec[0]/((t->scene->r.frs_sec / t->scene->r.frs_sec_base));
                        /* same as below */
                        UI_view2d_to_region_no_clip((View2D *)t->view, vec[0], vec[1], out, out + 1);
-               } 
+               }
                else
 #endif
                {
                else
 #endif
                {
@@ -248,20 +303,47 @@ void projectIntView(TransInfo *t, const float vec[3], int adr[2])
                adr[1] = out[1];
        }
        else if (t->spacetype == SPACE_CLIP) {
                adr[1] = out[1];
        }
        else if (t->spacetype == SPACE_CLIP) {
-               float v[2];
-               float aspx = 1.0f, aspy = 1.0f;
+               SpaceClip *sc = t->sa->spacedata.first;
+
+               if (t->options & CTX_MASK) {
+                       /* not working quite right, TODO (see above too) */
+                       float aspx, aspy;
+                       float v[2];
+
+                       ED_space_clip_get_aspect(sc, &aspx, &aspy);
+
+                       copy_v2_v2(v, vec);
+
+                       v[0] = v[0] / aspx;
+                       v[1] = v[1] / aspy;
+
+                       BKE_mask_coord_to_movieclip(sc->clip, &sc->user, v, v);
 
 
-               copy_v2_v2(v, vec);
+                       v[0] = v[0] / aspx;
+                       v[1] = v[1] / aspy;
 
 
-               if (t->options & CTX_MOVIECLIP)
+                       ED_clip_point_stable_pos__reverse(sc, t->ar, v, v);
+
+                       adr[0] = v[0];
+                       adr[1] = v[1];
+               }
+               else if (t->options & CTX_MOVIECLIP) {
+                       float v[2], aspx, aspy;
+
+                       copy_v2_v2(v, vec);
                        ED_space_clip_get_aspect_dimension_aware(t->sa->spacedata.first, &aspx, &aspy);
                        ED_space_clip_get_aspect_dimension_aware(t->sa->spacedata.first, &aspx, &aspy);
-               else if (t->options & CTX_MASK)
-                       ED_space_clip_get_aspect(t->sa->spacedata.first, &aspx, &aspy);
 
 
-               v[0] /= aspx;
-               v[1] /= aspy;
+                       v[0] /= aspx;
+                       v[1] /= aspy;
 
 
-               UI_view2d_to_region_no_clip(t->view, v[0], v[1], adr, adr + 1);
+                       UI_view2d_to_region_no_clip(t->view, v[0], v[1], adr, adr + 1);
+               }
+               else {
+                       BLI_assert(0);
+               }
+       }
+       else if (t->spacetype == SPACE_NODE) {
+               UI_view2d_to_region_no_clip((View2D *)t->view, vec[0], vec[1], adr, adr + 1);
        }
 }
 
        }
 }
 
@@ -271,7 +353,12 @@ void projectFloatView(TransInfo *t, const float vec[3], float adr[2])
                case SPACE_VIEW3D:
                {
                        if (t->ar->regiontype == RGN_TYPE_WINDOW) {
                case SPACE_VIEW3D:
                {
                        if (t->ar->regiontype == RGN_TYPE_WINDOW) {
-                               project_float_noclip(t->ar, vec, adr);
+                               /* allow points behind the view [#33643] */
+                               if (ED_view3d_project_float_global(t->ar, vec, adr, V3D_PROJ_TEST_NOP) != V3D_PROJ_RET_OK) {
+                                       /* XXX, 2.64 and prior did this, weak! */
+                                       adr[0] = t->ar->winx / 2.0f;
+                                       adr[1] = t->ar->winy / 2.0f;
+                               }
                                return;
                        }
                        break;
                                return;
                        }
                        break;
@@ -300,13 +387,13 @@ void applyAspectRatio(TransInfo *t, float vec[2])
 
                if ((sima->flag & SI_COORDFLOATS) == 0) {
                        int width, height;
 
                if ((sima->flag & SI_COORDFLOATS) == 0) {
                        int width, height;
-                       ED_space_image_size(sima, &width, &height);
+                       ED_space_image_get_size(sima, &width, &height);
 
                        vec[0] *= width;
                        vec[1] *= height;
                }
 
 
                        vec[0] *= width;
                        vec[1] *= height;
                }
 
-               ED_space_image_uv_aspect(sima, &aspx, &aspy);
+               ED_space_image_get_uv_aspect(sima, &aspx, &aspy);
                vec[0] /= aspx;
                vec[1] /= aspy;
        }
                vec[0] /= aspx;
                vec[1] /= aspy;
        }
@@ -340,13 +427,13 @@ void removeAspectRatio(TransInfo *t, float vec[2])
 
                if ((sima->flag & SI_COORDFLOATS) == 0) {
                        int width, height;
 
                if ((sima->flag & SI_COORDFLOATS) == 0) {
                        int width, height;
-                       ED_space_image_size(sima, &width, &height);
+                       ED_space_image_get_size(sima, &width, &height);
 
                        vec[0] /= width;
                        vec[1] /= height;
                }
 
 
                        vec[0] /= width;
                        vec[1] /= height;
                }
 
-               ED_space_image_uv_aspect(sima, &aspx, &aspy);
+               ED_space_image_get_uv_aspect(sima, &aspx, &aspy);
                vec[0] *= aspx;
                vec[1] *= aspy;
        }
                vec[0] *= aspx;
                vec[1] *= aspy;
        }
@@ -376,7 +463,10 @@ static void viewRedrawForce(const bContext *C, TransInfo *t)
                        WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL);
                else
                        WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
                        WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL);
                else
                        WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
-               
+
+               if (t->mode == TFM_EDGE_SLIDE && (t->settings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT))
+                       WM_event_add_notifier(C, NC_GEOM | ND_DATA, NULL);
+
                /* for realtime animation record - send notifiers recognised by animation editors */
                // XXX: is this notifier a lame duck?
                if ((t->animtimer) && IS_AUTOKEY_ON(t->scene))
                /* 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))
@@ -384,11 +474,11 @@ static void viewRedrawForce(const bContext *C, TransInfo *t)
                
        }
        else if (t->spacetype == SPACE_ACTION) {
                
        }
        else if (t->spacetype == SPACE_ACTION) {
-               //SpaceAction *saction= (SpaceAction *)t->sa->spacedata.first;
+               //SpaceAction *saction = (SpaceAction *)t->sa->spacedata.first;
                WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
        }
        else if (t->spacetype == SPACE_IPO) {
                WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
        }
        else if (t->spacetype == SPACE_IPO) {
-               //SpaceIpo *sipo= (SpaceIpo *)t->sa->spacedata.first;
+               //SpaceIpo *sipo = (SpaceIpo *)t->sa->spacedata.first;
                WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
        }
        else if (t->spacetype == SPACE_NLA) {
                WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
        }
        else if (t->spacetype == SPACE_NLA) {
@@ -402,10 +492,17 @@ static void viewRedrawForce(const bContext *C, TransInfo *t)
                WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, NULL);
        }
        else if (t->spacetype == SPACE_IMAGE) {
                WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, NULL);
        }
        else if (t->spacetype == SPACE_IMAGE) {
-               // XXX how to deal with lock?
-               SpaceImage *sima = (SpaceImage *)t->sa->spacedata.first;
-               if (sima->lock) WM_event_add_notifier(C, NC_GEOM | ND_DATA, t->obedit->data);
-               else ED_area_tag_redraw(t->sa);
+               if (t->options & CTX_MASK) {
+                       Mask *mask = CTX_data_edit_mask(C);
+
+                       WM_event_add_notifier(C, NC_MASK | NA_EDITED, mask);
+               }
+               else {
+                       // XXX how to deal with lock?
+                       SpaceImage *sima = (SpaceImage *)t->sa->spacedata.first;
+                       if (sima->lock) WM_event_add_notifier(C, NC_GEOM | ND_DATA, t->obedit->data);
+                       else ED_area_tag_redraw(t->sa);
+               }
        }
        else if (t->spacetype == SPACE_CLIP) {
                SpaceClip *sc = (SpaceClip *)t->sa->spacedata.first;
        }
        else if (t->spacetype == SPACE_CLIP) {
                SpaceClip *sc = (SpaceClip *)t->sa->spacedata.first;
@@ -419,7 +516,7 @@ static void viewRedrawForce(const bContext *C, TransInfo *t)
                        WM_event_add_notifier(C, NC_MOVIECLIP | NA_EDITED, clip);
                }
                else if (ED_space_clip_check_show_maskedit(sc)) {
                        WM_event_add_notifier(C, NC_MOVIECLIP | NA_EDITED, clip);
                }
                else if (ED_space_clip_check_show_maskedit(sc)) {
-                       Mask *mask = ED_space_clip_get_mask(sc);
+                       Mask *mask = CTX_data_edit_mask(C);
 
                        WM_event_add_notifier(C, NC_MASK | NA_EDITED, mask);
                }
 
                        WM_event_add_notifier(C, NC_MASK | NA_EDITED, mask);
                }
@@ -434,6 +531,10 @@ static void viewRedrawPost(bContext *C, TransInfo *t)
                /* if autokeying is enabled, send notifiers that keyframes were added */
                if (IS_AUTOKEY_ON(t->scene))
                        WM_main_add_notifier(NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
                /* if autokeying is enabled, send notifiers that keyframes were added */
                if (IS_AUTOKEY_ON(t->scene))
                        WM_main_add_notifier(NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
+
+               /* redraw UV editor */
+               if (t->mode == TFM_EDGE_SLIDE && (t->settings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT))
+                       WM_event_add_notifier(C, NC_GEOM | ND_DATA, NULL);
                
                /* XXX temp, first hack to get auto-render in compositor work (ton) */
                WM_event_add_notifier(C, NC_SCENE | ND_TRANSFORM_DONE, CTX_data_scene(C));
                
                /* XXX temp, first hack to get auto-render in compositor work (ton) */
                WM_event_add_notifier(C, NC_SCENE | ND_TRANSFORM_DONE, CTX_data_scene(C));
@@ -589,6 +690,9 @@ static void view_editmove(unsigned short UNUSED(event))
 #define TFM_MODAL_EDGESLIDE_UP 24
 #define TFM_MODAL_EDGESLIDE_DOWN 25
 
 #define TFM_MODAL_EDGESLIDE_UP 24
 #define TFM_MODAL_EDGESLIDE_DOWN 25
 
+/* for analog input, like trackpad */
+#define TFM_MODAL_PROPSIZE             26
+
 /* called in transform_ops.c, on each regeneration of keymaps */
 wmKeyMap *transform_modal_keymap(wmKeyConfig *keyconf)
 {
 /* called in transform_ops.c, on each regeneration of keymaps */
 wmKeyMap *transform_modal_keymap(wmKeyConfig *keyconf)
 {
@@ -618,6 +722,7 @@ wmKeyMap *transform_modal_keymap(wmKeyConfig *keyconf)
                {TFM_MODAL_AUTOIK_LEN_DEC, "AUTOIK_CHAIN_LEN_DOWN", 0, "Decrease Max AutoIK Chain Length", ""},
                {TFM_MODAL_EDGESLIDE_UP, "EDGESLIDE_EDGE_NEXT", 0, "Select next Edge Slide Edge", ""},
                {TFM_MODAL_EDGESLIDE_DOWN, "EDGESLIDE_PREV_NEXT", 0, "Select previous Edge Slide Edge", ""},
                {TFM_MODAL_AUTOIK_LEN_DEC, "AUTOIK_CHAIN_LEN_DOWN", 0, "Decrease Max AutoIK Chain Length", ""},
                {TFM_MODAL_EDGESLIDE_UP, "EDGESLIDE_EDGE_NEXT", 0, "Select next Edge Slide Edge", ""},
                {TFM_MODAL_EDGESLIDE_DOWN, "EDGESLIDE_PREV_NEXT", 0, "Select previous Edge Slide Edge", ""},
+               {TFM_MODAL_PROPSIZE, "PROPORTIONAL_SIZE", 0, "Adjust Proportional Influence", ""},
                {0, NULL, 0, NULL, NULL}
        };
        
                {0, NULL, 0, NULL, NULL}
        };
        
@@ -653,6 +758,7 @@ wmKeyMap *transform_modal_keymap(wmKeyConfig *keyconf)
        WM_modalkeymap_add_item(keymap, PAGEDOWNKEY, KM_PRESS, 0, 0, TFM_MODAL_PROPSIZE_DOWN);
        WM_modalkeymap_add_item(keymap, WHEELDOWNMOUSE, KM_PRESS, 0, 0, TFM_MODAL_PROPSIZE_UP);
        WM_modalkeymap_add_item(keymap, WHEELUPMOUSE, KM_PRESS, 0, 0, TFM_MODAL_PROPSIZE_DOWN);
        WM_modalkeymap_add_item(keymap, PAGEDOWNKEY, KM_PRESS, 0, 0, TFM_MODAL_PROPSIZE_DOWN);
        WM_modalkeymap_add_item(keymap, WHEELDOWNMOUSE, KM_PRESS, 0, 0, TFM_MODAL_PROPSIZE_UP);
        WM_modalkeymap_add_item(keymap, WHEELUPMOUSE, KM_PRESS, 0, 0, TFM_MODAL_PROPSIZE_DOWN);
+       WM_modalkeymap_add_item(keymap, MOUSEPAN, 0, 0, 0, TFM_MODAL_PROPSIZE);
 
        WM_modalkeymap_add_item(keymap, WHEELDOWNMOUSE, KM_PRESS, KM_ALT, 0, TFM_MODAL_EDGESLIDE_UP);
        WM_modalkeymap_add_item(keymap, WHEELUPMOUSE, KM_PRESS, KM_ALT, 0, TFM_MODAL_EDGESLIDE_DOWN);
 
        WM_modalkeymap_add_item(keymap, WHEELDOWNMOUSE, KM_PRESS, KM_ALT, 0, TFM_MODAL_EDGESLIDE_UP);
        WM_modalkeymap_add_item(keymap, WHEELUPMOUSE, KM_PRESS, KM_ALT, 0, TFM_MODAL_EDGESLIDE_DOWN);
@@ -736,7 +842,7 @@ int transformEvent(TransInfo *t, wmEvent *event)
        float mati[3][3] = MAT3_UNITY;
        char cmode = constraintModeToChar(t);
        int handled = 1;
        float mati[3][3] = MAT3_UNITY;
        char cmode = constraintModeToChar(t);
        int handled = 1;
-
+       
        t->redraw |= handleMouseInput(t, &t->mouse, event);
 
        if (event->type == MOUSEMOVE) {
        t->redraw |= handleMouseInput(t, &t->mouse, event);
 
        if (event->type == MOUSEMOVE) {
@@ -927,11 +1033,24 @@ int transformEvent(TransInfo *t, wmEvent *event)
                                removeSnapPoint(t);
                                t->redraw |= TREDRAW_HARD;
                                break;
                                removeSnapPoint(t);
                                t->redraw |= TREDRAW_HARD;
                                break;
+                               
+                       case TFM_MODAL_PROPSIZE:
+                               /* MOUSEPAN usage... */
+                               if (t->flag & T_PROP_EDIT) {
+                                       float fac = 1.0f + 0.005f *(event->y - event->prevy);
+                                       t->prop_size *= fac;
+                                       if (t->spacetype == SPACE_VIEW3D && t->persp != RV3D_ORTHO)
+                                               t->prop_size = min_ff(t->prop_size, ((View3D *)t->view)->far);
+                                       calculatePropRatio(t);
+                               }
+                               t->redraw |= TREDRAW_HARD;
+                               break;
+                               
                        case TFM_MODAL_PROPSIZE_UP:
                                if (t->flag & T_PROP_EDIT) {
                                        t->prop_size *= 1.1f;
                                        if (t->spacetype == SPACE_VIEW3D && t->persp != RV3D_ORTHO)
                        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 = MIN2(t->prop_size, ((View3D *)t->view)->far);
+                                               t->prop_size = min_ff(t->prop_size, ((View3D *)t->view)->far);
                                        calculatePropRatio(t);
                                }
                                t->redraw |= TREDRAW_HARD;
                                        calculatePropRatio(t);
                                }
                                t->redraw |= TREDRAW_HARD;
@@ -1101,7 +1220,7 @@ int transformEvent(TransInfo *t, wmEvent *event)
                                if (event->alt && t->flag & T_PROP_EDIT) {
                                        t->prop_size *= 1.1f;
                                        if (t->spacetype == SPACE_VIEW3D && t->persp != RV3D_ORTHO)
                                if (event->alt && t->flag & T_PROP_EDIT) {
                                        t->prop_size *= 1.1f;
                                        if (t->spacetype == SPACE_VIEW3D && t->persp != RV3D_ORTHO)
-                                               t->prop_size = MIN2(t->prop_size, ((View3D *)t->view)->far);
+                                               t->prop_size = min_ff(t->prop_size, ((View3D *)t->view)->far);
                                        calculatePropRatio(t);
                                }
                                t->redraw = 1;
                                        calculatePropRatio(t);
                                }
                                t->redraw = 1;
@@ -1128,6 +1247,14 @@ int transformEvent(TransInfo *t, wmEvent *event)
                                }
                                else view_editmove(event->type);
                                t->redraw = 1;
                                }
                                else view_editmove(event->type);
                                t->redraw = 1;
+                               break;
+                       case LEFTALTKEY:
+                       case RIGHTALTKEY:
+                               if (ELEM(t->spacetype, SPACE_SEQ, SPACE_VIEW3D)) {
+                                       t->flag |= T_ALT_TRANSFORM;
+                                       t->redraw |= TREDRAW_HARD;
+                               }
+
                                break;
                        default:
                                handled = 0;
                                break;
                        default:
                                handled = 0;
@@ -1162,6 +1289,14 @@ int transformEvent(TransInfo *t, wmEvent *event)
 ////                   if (t->options & CTX_TWEAK)
 //                             t->state = TRANS_CONFIRM;
 //                     break;
 ////                   if (t->options & CTX_TWEAK)
 //                             t->state = TRANS_CONFIRM;
 //                     break;
+                       case LEFTALTKEY:
+                       case RIGHTALTKEY:
+                               if (ELEM(t->spacetype, SPACE_SEQ, SPACE_VIEW3D)) {
+                                       t->flag &= ~T_ALT_TRANSFORM;
+                                       t->redraw |= TREDRAW_HARD;
+                               }
+
+                               break;
                        default:
                                handled = 0;
                                break;
                        default:
                                handled = 0;
                                break;
@@ -1175,15 +1310,19 @@ int transformEvent(TransInfo *t, wmEvent *event)
                        }
                }
        }
                        }
                }
        }
+       else
+               handled = 0;
 
        // Per transform event, if present
        if (t->handleEvent)
                t->redraw |= t->handleEvent(t, event);
 
 
        // Per transform event, if present
        if (t->handleEvent)
                t->redraw |= t->handleEvent(t, event);
 
-       if (handled || t->redraw)
+       if (handled || t->redraw) {
                return 0;
                return 0;
-       else
+       }
+       else {
                return OPERATOR_PASS_THROUGH;
                return OPERATOR_PASS_THROUGH;
+       }
 }
 
 int calculateTransformCenter(bContext *C, int centerMode, float cent3d[3], int cent2d[2])
 }
 
 int calculateTransformCenter(bContext *C, int centerMode, float cent3d[3], int cent2d[2])
@@ -1302,10 +1441,11 @@ static void drawArc(float size, float angle_start, float angle_end, int segments
 {
        float delta = (angle_end - angle_start) / segments;
        float angle;
 {
        float delta = (angle_end - angle_start) / segments;
        float angle;
+       int a;
 
        glBegin(GL_LINE_STRIP);
 
 
        glBegin(GL_LINE_STRIP);
 
-       for (angle = angle_start; angle < angle_end; angle += delta) {
+       for (angle = angle_start, a = 0; a < segments; angle += delta, a++) {
                glVertex2f(cosf(angle) * size, sinf(angle) * size);
        }
        glVertex2f(cosf(angle_end) * size, sinf(angle_end) * size);
                glVertex2f(cosf(angle) * size, sinf(angle) * size);
        }
        glVertex2f(cosf(angle_end) * size, sinf(angle_end) * size);
@@ -1382,7 +1522,6 @@ static void drawHelpline(bContext *UNUSED(C), int x, int y, void *customdata)
                                glTranslatef(mval[0], mval[1], 0);
 
                                glLineWidth(3.0);
                                glTranslatef(mval[0], mval[1], 0);
 
                                glLineWidth(3.0);
-                               glBegin(GL_LINES);
                                drawArrow(UP, 5, 10, 5);
                                drawArrow(DOWN, 5, 10, 5);
                                glLineWidth(1.0);
                                drawArrow(UP, 5, 10, 5);
                                drawArrow(DOWN, 5, 10, 5);
                                glLineWidth(1.0);
@@ -1392,8 +1531,8 @@ static void drawHelpline(bContext *UNUSED(C), int x, int y, void *customdata)
                                float dx = t->mval[0] - cent[0], dy = t->mval[1] - cent[1];
                                float angle = atan2f(dy, dx);
                                float dist = sqrtf(dx * dx + dy * dy);
                                float dx = t->mval[0] - cent[0], dy = t->mval[1] - cent[1];
                                float angle = atan2f(dy, dx);
                                float dist = sqrtf(dx * dx + dy * dy);
-                               float delta_angle = MIN2(15.0f / dist, (float)M_PI / 4.0f);
-                               float spacing_angle = MIN2(5.0f / dist, (float)M_PI / 12.0f);
+                               float delta_angle = min_ff(15.0f / dist, (float)M_PI / 4.0f);
+                               float spacing_angle = min_ff(5.0f / dist, (float)M_PI / 12.0f);
                                UI_ThemeColor(TH_WIRE);
 
                                setlinestyle(3);
                                UI_ThemeColor(TH_WIRE);
 
                                setlinestyle(3);
@@ -1455,7 +1594,7 @@ static void drawHelpline(bContext *UNUSED(C), int x, int y, void *customdata)
        }
 }
 
        }
 }
 
-static void drawTransformView(const struct bContext *C, struct ARegion *UNUSED(ar), void *arg)
+static void drawTransformView(const struct bContext *C, ARegion *UNUSED(ar), void *arg)
 {
        TransInfo *t = arg;
 
 {
        TransInfo *t = arg;
 
@@ -1465,14 +1604,58 @@ static void drawTransformView(const struct bContext *C, struct ARegion *UNUSED(a
        drawNonPropEdge(C, t);
 }
 
        drawNonPropEdge(C, t);
 }
 
-#if 0
-static void drawTransformPixel(const struct bContext *UNUSED(C), struct ARegion *UNUSED(ar), void *UNUSED(arg))
+/* just draw a little warning message in the top-right corner of the viewport to warn that autokeying is enabled */
+static void drawAutoKeyWarning(TransInfo *UNUSED(t), ARegion *ar)
 {
 {
-//     TransInfo *t = arg;
-//
-//     drawHelpline(C, t->mval[0], t->mval[1], t);
+       rcti rect;
+       const char printable[] = "Auto Keying On";
+       float      printable_size[2];
+       int xco, yco;
+
+       ED_region_visible_rect(ar, &rect);
+       
+       BLF_width_and_height_default(printable, &printable_size[0], &printable_size[1]);
+       
+       xco = rect.xmax - (int)printable_size[0] - 10;
+       yco = rect.ymax - (int)printable_size[1] - 10;
+       
+       /* warning text (to clarify meaning of overlays)
+        * - original color was red to match the icon, but that clashes badly with a less nasty border
+        */
+       UI_ThemeColorShade(TH_TEXT_HI, -50);
+       BLF_draw_default_ascii(xco, ar->winy - 17, 0.0f, printable, sizeof(printable));
+       
+       /* autokey recording icon... */
+       glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+       glEnable(GL_BLEND);
+       
+       xco -= (ICON_DEFAULT_WIDTH + 2);
+       UI_icon_draw(xco, yco, ICON_REC);
+       
+       glDisable(GL_BLEND);
+}
+
+static void drawTransformPixel(const struct bContext *UNUSED(C), ARegion *ar, void *arg)
+{      
+       TransInfo *t = arg;
+       Scene *scene = t->scene;
+       Object *ob = OBACT;
+       
+       /* draw autokeyframing hint in the corner 
+        * - only draw if enabled (advanced users may be distracted/annoyed), 
+        *   for objects that will be autokeyframed (no point ohterwise),
+        *   AND only for the active region (as showing all is too overwhelming)
+        */
+       if ((U.autokey_flag & AUTOKEY_FLAG_NOWARNING) == 0) {
+               if (ar == t->ar) {
+                       if (t->flag & (T_OBJECT | T_POSE)) {
+                               if (ob && autokeyframe_cfra_can_key(scene, &ob->id)) {
+                                       drawAutoKeyWarning(t, ar);
+                               }
+                       }
+               }
+       }
 }
 }
-#endif
 
 void saveTransform(bContext *C, TransInfo *t, wmOperator *op)
 {
 
 void saveTransform(bContext *C, TransInfo *t, wmOperator *op)
 {
@@ -1642,7 +1825,7 @@ int initTransform(bContext *C, TransInfo *t, wmOperator *op, wmEvent *event, int
 
                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_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_pixel = ED_region_draw_cb_activate(t->ar->type, drawTransformPixel, t, REGION_DRAW_POST_PIXEL);
+               t->draw_handle_pixel = ED_region_draw_cb_activate(t->ar->type, drawTransformPixel, t, REGION_DRAW_POST_PIXEL);
                t->draw_handle_cursor = WM_paint_cursor_activate(CTX_wm_manager(C), helpline_poll, drawHelpline, t);
        }
        else if (t->spacetype == SPACE_IMAGE) {
                t->draw_handle_cursor = WM_paint_cursor_activate(CTX_wm_manager(C), helpline_poll, drawHelpline, t);
        }
        else if (t->spacetype == SPACE_IMAGE) {
@@ -1655,6 +1838,12 @@ int initTransform(bContext *C, TransInfo *t, wmOperator *op, wmEvent *event, int
                unit_m3(t->spacemtx);
                t->draw_handle_view = ED_region_draw_cb_activate(t->ar->type, drawTransformView, t, REGION_DRAW_POST_VIEW);
        }
                unit_m3(t->spacemtx);
                t->draw_handle_view = ED_region_draw_cb_activate(t->ar->type, drawTransformView, t, REGION_DRAW_POST_VIEW);
        }
+       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);*/
+       }
        else
                unit_m3(t->spacemtx);
 
        else
                unit_m3(t->spacemtx);
 
@@ -1667,19 +1856,25 @@ int initTransform(bContext *C, TransInfo *t, wmOperator *op, wmEvent *event, int
 
        /* Stupid code to have Ctrl-Click on manipulator work ok */
        if (event) {
 
        /* Stupid code to have Ctrl-Click on manipulator work ok */
        if (event) {
-               wmKeyMap *keymap = WM_keymap_active(CTX_wm_manager(C), op->type->modalkeymap);
-               wmKeyMapItem *kmi;
-
-               for (kmi = 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) ||
-                                   (ELEM(kmi->type, LEFTALTKEY, RIGHTALTKEY) &&     event->alt)   ||
-                                   ((kmi->type == OSKEY) &&                         event->oskey) )
-                               {
-                                       t->modifiers |= MOD_SNAP_INVERT;
+               /* 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) {
+                               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) ||
+                                           (ELEM(kmi->type, LEFTALTKEY, RIGHTALTKEY) &&     event->alt)   ||
+                                           ((kmi->type == OSKEY) &&                         event->oskey) )
+                                       {
+                                               t->modifiers |= MOD_SNAP_INVERT;
+                                       }
+                                       break;
                                }
                                }
-                               break;
                        }
                }
 
                        }
                }
 
@@ -1895,7 +2090,7 @@ void transformApply(bContext *C, TransInfo *t)
        t->context = NULL;
 }
 
        t->context = NULL;
 }
 
-static void drawTransformApply(const bContext *C, struct ARegion *UNUSED(ar), void *arg)
+static void drawTransformApply(const bContext *C, ARegion *UNUSED(ar), void *arg)
 {
        TransInfo *t = arg;
 
 {
        TransInfo *t = arg;
 
@@ -2084,8 +2279,8 @@ static void protectedQuaternionBits(short protectflag, float *quat, float *oldqu
 static void constraintTransLim(TransInfo *t, TransData *td)
 {
        if (td->con) {
 static void constraintTransLim(TransInfo *t, TransData *td)
 {
        if (td->con) {
-               bConstraintTypeInfo *ctiLoc = get_constraint_typeinfo(CONSTRAINT_TYPE_LOCLIMIT);
-               bConstraintTypeInfo *ctiDist = get_constraint_typeinfo(CONSTRAINT_TYPE_DISTLIMIT);
+               bConstraintTypeInfo *ctiLoc = BKE_get_constraint_typeinfo(CONSTRAINT_TYPE_LOCLIMIT);
+               bConstraintTypeInfo *ctiDist = BKE_get_constraint_typeinfo(CONSTRAINT_TYPE_DISTLIMIT);
                
                bConstraintOb cob = {NULL};
                bConstraint *con;
                
                bConstraintOb cob = {NULL};
                bConstraint *con;
@@ -2102,7 +2297,6 @@ static void constraintTransLim(TransInfo *t, TransData *td)
                for (con = td->con; con; con = con->next) {
                        bConstraintTypeInfo *cti = NULL;
                        ListBase targets = {NULL, NULL};
                for (con = td->con; con; con = con->next) {
                        bConstraintTypeInfo *cti = NULL;
                        ListBase targets = {NULL, NULL};
-                       float tmat[4][4];
                        
                        /* only consider constraint if enabled */
                        if (con->flag & CONSTRAINT_DISABLE) continue;
                        
                        /* only consider constraint if enabled */
                        if (con->flag & CONSTRAINT_DISABLE) continue;
@@ -2128,8 +2322,7 @@ static void constraintTransLim(TransInfo *t, TransData *td)
                                /* do space conversions */
                                if (con->ownspace == CONSTRAINT_SPACE_WORLD) {
                                        /* just multiply by td->mtx (this should be ok) */
                                /* do space conversions */
                                if (con->ownspace == CONSTRAINT_SPACE_WORLD) {
                                        /* just multiply by td->mtx (this should be ok) */
-                                       copy_m4_m4(tmat, cob.matrix);
-                                       mul_m4_m3m4(cob.matrix, td->mtx, tmat);
+                                       mul_m4_m3m4(cob.matrix, td->mtx, cob.matrix);
                                }
                                else if (con->ownspace != CONSTRAINT_SPACE_LOCAL) {
                                        /* skip... incompatable spacetype */
                                }
                                else if (con->ownspace != CONSTRAINT_SPACE_LOCAL) {
                                        /* skip... incompatable spacetype */
@@ -2137,16 +2330,15 @@ static void constraintTransLim(TransInfo *t, TransData *td)
                                }
                                
                                /* get constraint targets if needed */
                                }
                                
                                /* get constraint targets if needed */
-                               get_constraint_targets_for_solving(con, &cob, &targets, ctime);
+                               BKE_get_constraint_targets_for_solving(con, &cob, &targets, ctime);
                                
                                /* do constraint */
                                cti->evaluate_constraint(con, &cob, &targets);
                                
                                /* convert spaces again */
                                if (con->ownspace == CONSTRAINT_SPACE_WORLD) {
                                
                                /* do constraint */
                                cti->evaluate_constraint(con, &cob, &targets);
                                
                                /* convert spaces again */
                                if (con->ownspace == CONSTRAINT_SPACE_WORLD) {
-                                       /* just multiply by td->mtx (this should be ok) */
-                                       copy_m4_m4(tmat, cob.matrix);
-                                       mul_m4_m3m4(cob.matrix, td->smtx, tmat);
+                                       /* just multiply by td->smtx (this should be ok) */
+                                       mul_m4_m3m4(cob.matrix, td->smtx, cob.matrix);
                                }
                                
                                /* free targets list */
                                }
                                
                                /* free targets list */
@@ -2170,8 +2362,8 @@ static void constraintob_from_transdata(bConstraintOb *cob, TransData *td)
                if (td->ext->rotOrder == ROT_MODE_QUAT) {
                        /* quats */
                        /* objects and bones do normalization first too, otherwise
                if (td->ext->rotOrder == ROT_MODE_QUAT) {
                        /* quats */
                        /* objects and bones do normalization first too, otherwise
-                       * we don't necessarily end up with a rotation matrix, and
-                       * then conversion back to quat gives a different result */
+                        * we don't necessarily end up with a rotation matrix, and
+                        * then conversion back to quat gives a different result */
                        float quat[4];
                        normalize_qt_qt(quat, td->ext->quat);
                        quat_to_mat4(cob->matrix, quat);
                        float quat[4];
                        normalize_qt_qt(quat, td->ext->quat);
                        quat_to_mat4(cob->matrix, quat);
@@ -2190,22 +2382,21 @@ static void constraintob_from_transdata(bConstraintOb *cob, TransData *td)
 static void constraintRotLim(TransInfo *UNUSED(t), TransData *td)
 {
        if (td->con) {
 static void constraintRotLim(TransInfo *UNUSED(t), TransData *td)
 {
        if (td->con) {
-               bConstraintTypeInfo *cti = get_constraint_typeinfo(CONSTRAINT_TYPE_ROTLIMIT);
+               bConstraintTypeInfo *cti = BKE_get_constraint_typeinfo(CONSTRAINT_TYPE_ROTLIMIT);
                bConstraintOb cob;
                bConstraint *con;
                int do_limit = FALSE;
                bConstraintOb cob;
                bConstraint *con;
                int do_limit = FALSE;
-               
+
                /* Evaluate valid constraints */
                for (con = td->con; con; con = con->next) {
                        /* only consider constraint if enabled */
                        if (con->flag & CONSTRAINT_DISABLE) continue;
                        if (con->enforce == 0.0f) continue;
                /* Evaluate valid constraints */
                for (con = td->con; con; con = con->next) {
                        /* only consider constraint if enabled */
                        if (con->flag & CONSTRAINT_DISABLE) continue;
                        if (con->enforce == 0.0f) continue;
-                       
+
                        /* we're only interested in Limit-Rotation constraints */
                        if (con->type == CONSTRAINT_TYPE_ROTLIMIT) {
                                bRotLimitConstraint *data = con->data;
                        /* we're only interested in Limit-Rotation constraints */
                        if (con->type == CONSTRAINT_TYPE_ROTLIMIT) {
                                bRotLimitConstraint *data = con->data;
-                               float tmat[4][4];
-                               
+
                                /* only use it if it's tagged for this purpose */
                                if ((data->flag2 & LIMIT_TRANSFORM) == 0)
                                        continue;
                                /* only use it if it's tagged for this purpose */
                                if ((data->flag2 & LIMIT_TRANSFORM) == 0)
                                        continue;
@@ -2219,12 +2410,11 @@ static void constraintRotLim(TransInfo *UNUSED(t), TransData *td)
                                        constraintob_from_transdata(&cob, td);
                                        do_limit = TRUE;
                                }
                                        constraintob_from_transdata(&cob, td);
                                        do_limit = TRUE;
                                }
-                               
+
                                /* do space conversions */
                                if (con->ownspace == CONSTRAINT_SPACE_WORLD) {
                                        /* just multiply by td->mtx (this should be ok) */
                                /* do space conversions */
                                if (con->ownspace == CONSTRAINT_SPACE_WORLD) {
                                        /* just multiply by td->mtx (this should be ok) */
-                                       copy_m4_m4(tmat, cob.matrix);
-                                       mul_m4_m3m4(cob.matrix, td->mtx, tmat);
+                                       mul_m4_m3m4(cob.matrix, td->mtx, cob.matrix);
                                }
                                
                                /* do constraint */
                                }
                                
                                /* do constraint */
@@ -2232,9 +2422,8 @@ static void constraintRotLim(TransInfo *UNUSED(t), TransData *td)
                                
                                /* convert spaces again */
                                if (con->ownspace == CONSTRAINT_SPACE_WORLD) {
                                
                                /* convert spaces again */
                                if (con->ownspace == CONSTRAINT_SPACE_WORLD) {
-                                       /* just multiply by td->mtx (this should be ok) */
-                                       copy_m4_m4(tmat, cob.matrix);
-                                       mul_m4_m3m4(cob.matrix, td->smtx, tmat);
+                                       /* just multiply by td->smtx (this should be ok) */
+                                       mul_m4_m3m4(cob.matrix, td->smtx, cob.matrix);
                                }
                        }
                }
                                }
                        }
                }
@@ -2260,9 +2449,11 @@ static void constraintRotLim(TransInfo *UNUSED(t), TransData *td)
 static void constraintSizeLim(TransInfo *t, TransData *td)
 {
        if (td->con && td->ext) {
 static void constraintSizeLim(TransInfo *t, TransData *td)
 {
        if (td->con && td->ext) {
-               bConstraintTypeInfo *cti = get_constraint_typeinfo(CONSTRAINT_TYPE_SIZELIMIT);
+               bConstraintTypeInfo *cti = BKE_get_constraint_typeinfo(CONSTRAINT_TYPE_SIZELIMIT);
                bConstraintOb cob = {NULL};
                bConstraint *con;
                bConstraintOb cob = {NULL};
                bConstraint *con;
+               float size_sign[3], size_abs[3];
+               int i;
                
                /* Make a temporary bConstraintOb for using these limit constraints
                 *  - they only care that cob->matrix is correctly set ;-)
                
                /* Make a temporary bConstraintOb for using these limit constraints
                 *  - they only care that cob->matrix is correctly set ;-)
@@ -2276,8 +2467,14 @@ static void constraintSizeLim(TransInfo *t, TransData *td)
                        /* Reset val if SINGLESIZE but using a constraint */
                        if (td->flag & TD_SINGLESIZE)
                                return;
                        /* Reset val if SINGLESIZE but using a constraint */
                        if (td->flag & TD_SINGLESIZE)
                                return;
+
+                       /* separate out sign to apply back later */
+                       for (i = 0; i < 3; i++) {
+                               size_sign[i] = signf(td->ext->size[i]);
+                               size_abs[i] = fabsf(td->ext->size[i]);
+                       }
                        
                        
-                       size_to_mat4(cob.matrix, td->ext->size);
+                       size_to_mat4(cob.matrix, size_abs);
                }
                
                /* Evaluate valid constraints */
                }
                
                /* Evaluate valid constraints */
@@ -2289,7 +2486,6 @@ static void constraintSizeLim(TransInfo *t, TransData *td)
                        /* we're only interested in Limit-Scale constraints */
                        if (con->type == CONSTRAINT_TYPE_SIZELIMIT) {
                                bSizeLimitConstraint *data = con->data;
                        /* we're only interested in Limit-Scale constraints */
                        if (con->type == CONSTRAINT_TYPE_SIZELIMIT) {
                                bSizeLimitConstraint *data = con->data;
-                               float tmat[4][4];
                                
                                /* only use it if it's tagged for this purpose */
                                if ((data->flag2 & LIMIT_TRANSFORM) == 0)
                                
                                /* only use it if it's tagged for this purpose */
                                if ((data->flag2 & LIMIT_TRANSFORM) == 0)
@@ -2298,11 +2494,10 @@ static void constraintSizeLim(TransInfo *t, TransData *td)
                                /* do space conversions */
                                if (con->ownspace == CONSTRAINT_SPACE_WORLD) {
                                        /* just multiply by td->mtx (this should be ok) */
                                /* do space conversions */
                                if (con->ownspace == CONSTRAINT_SPACE_WORLD) {
                                        /* just multiply by td->mtx (this should be ok) */
-                                       copy_m4_m4(tmat, cob.matrix);
-                                       mul_m4_m3m4(cob.matrix, td->mtx, tmat);
+                                       mul_m4_m3m4(cob.matrix, td->mtx, cob.matrix);
                                }
                                else if (con->ownspace != CONSTRAINT_SPACE_LOCAL) {
                                }
                                else if (con->ownspace != CONSTRAINT_SPACE_LOCAL) {
-                                       /* skip... incompatable spacetype */
+                                       /* skip... incompatible spacetype */
                                        continue;
                                }
                                
                                        continue;
                                }
                                
@@ -2311,13 +2506,12 @@ static void constraintSizeLim(TransInfo *t, TransData *td)
                                
                                /* convert spaces again */
                                if (con->ownspace == CONSTRAINT_SPACE_WORLD) {
                                
                                /* convert spaces again */
                                if (con->ownspace == CONSTRAINT_SPACE_WORLD) {
-                                       /* just multiply by td->mtx (this should be ok) */
-                                       copy_m4_m4(tmat, cob.matrix);
-                                       mul_m4_m3m4(cob.matrix, td->smtx, tmat);
+                                       /* just multiply by td->smtx (this should be ok) */
+                                       mul_m4_m3m4(cob.matrix, td->smtx, cob.matrix);
                                }
                        }
                }
                                }
                        }
                }
-               
+
                /* copy results from cob->matrix */
                if ((td->flag & TD_SINGLESIZE) && !(t->con.mode & CON_APPLY)) {
                        /* scale val and reset size */
                /* copy results from cob->matrix */
                if ((td->flag & TD_SINGLESIZE) && !(t->con.mode & CON_APPLY)) {
                        /* scale val and reset size */
@@ -2327,8 +2521,10 @@ static void constraintSizeLim(TransInfo *t, TransData *td)
                        /* Reset val if SINGLESIZE but using a constraint */
                        if (td->flag & TD_SINGLESIZE)
                                return;
                        /* Reset val if SINGLESIZE but using a constraint */
                        if (td->flag & TD_SINGLESIZE)
                                return;
-                       
+
+                       /* extrace scale from matrix and apply back sign */
                        mat4_to_size(td->ext->size, cob.matrix);
                        mat4_to_size(td->ext->size, cob.matrix);
+                       mul_v3_v3(td->ext->size, size_sign);
                }
        }
 }
                }
        }
 }
@@ -2373,8 +2569,9 @@ void initWarp(TransInfo *t)
                mul_m3_v3(t->data[i].mtx, center);
                mul_m4_v3(t->viewmat, center);
                sub_v3_v3(center, t->viewmat[3]);
                mul_m3_v3(t->data[i].mtx, center);
                mul_m4_v3(t->viewmat, center);
                sub_v3_v3(center, t->viewmat[3]);
-               if (i)
+               if (i) {
                        minmax_v3v3_v3(min, max, center);
                        minmax_v3v3_v3(min, max, center);
+               }
                else {
                        copy_v3_v3(max, center);
                        copy_v3_v3(min, center);
                else {
                        copy_v3_v3(max, center);
                        copy_v3_v3(min, center);
@@ -2407,7 +2604,8 @@ int handleEventWarp(TransInfo *t, wmEvent *event)
 int Warp(TransInfo *t, const int UNUSED(mval[2]))
 {
        TransData *td = t->data;
 int Warp(TransInfo *t, const int UNUSED(mval[2]))
 {
        TransData *td = t->data;
-       float vec[3], circumfac, dist, phi0, co, si, *curs, cursor[3], gcursor[3];
+       float vec[3], circumfac, dist, phi0, co, si, cursor[3], gcursor[3];
+       const float *curs;
        int i;
        char str[50];
        
        int i;
        char str[50];
        
@@ -2440,7 +2638,7 @@ int Warp(TransInfo *t, const int UNUSED(mval[2]))
        
        /* header print for NumInput */
        if (hasNumInput(&t->num)) {
        
        /* header print for NumInput */
        if (hasNumInput(&t->num)) {
-               char c[20];
+               char c[NUM_STR_REP_LEN];
                
                outputNumInput(&(t->num), c);
                
                
                outputNumInput(&(t->num), c);
                
@@ -2544,6 +2742,18 @@ int handleEventShear(TransInfo *t, wmEvent *event)
 
                status = 1;
        }
 
                status = 1;
        }
+       else if (event->type == XKEY && event->val == KM_PRESS) {
+               initMouseInputMode(t, &t->mouse, INPUT_HORIZONTAL_ABSOLUTE);
+               t->customData = NULL;
+               
+               status = 1;
+       }
+       else if (event->type == YKEY && event->val == KM_PRESS) {
+               initMouseInputMode(t, &t->mouse, INPUT_VERTICAL_ABSOLUTE);
+               t->customData = (void *)1;
+               
+               status = 1;
+       }
        
        return status;
 }
        
        return status;
 }
@@ -2569,7 +2779,7 @@ int Shear(TransInfo *t, const int UNUSED(mval[2]))
        
        /* header print for NumInput */
        if (hasNumInput(&t->num)) {
        
        /* header print for NumInput */
        if (hasNumInput(&t->num)) {
-               char c[20];
+               char c[NUM_STR_REP_LEN];
                
                outputNumInput(&(t->num), c);
                
                
                outputNumInput(&(t->num), c);
                
@@ -2577,7 +2787,7 @@ int Shear(TransInfo *t, const int UNUSED(mval[2]))
        }
        else {
                /* default header print */
        }
        else {
                /* default header print */
-               sprintf(str, "Shear: %.3f %s", value, t->proptext);
+               sprintf(str, "Shear: %.3f %s (Press X or Y to set shear axis)", value, t->proptext);
        }
        
        t->values[0] = value;
        }
        
        t->values[0] = value;
@@ -2655,15 +2865,15 @@ void initResize(TransInfo *t)
 
 static void headerResize(TransInfo *t, float vec[3], char *str)
 {
 
 static void headerResize(TransInfo *t, float vec[3], char *str)
 {
-       char tvec[60];
+       char tvec[NUM_STR_REP_LEN * 3];
        char *spos = str;
        if (hasNumInput(&t->num)) {
                outputNumInput(&(t->num), tvec);
        }
        else {
        char *spos = str;
        if (hasNumInput(&t->num)) {
                outputNumInput(&(t->num), tvec);
        }
        else {
-               BLI_snprintf(&tvec[0],  20, "%.4f", vec[0]);
-               BLI_snprintf(&tvec[20], 20, "%.4f", vec[1]);
-               BLI_snprintf(&tvec[40], 20, "%.4f", vec[2]);
+               BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.4f", vec[0]);
+               BLI_snprintf(&tvec[NUM_STR_REP_LEN], NUM_STR_REP_LEN, "%.4f", vec[1]);
+               BLI_snprintf(&tvec[NUM_STR_REP_LEN * 2], NUM_STR_REP_LEN, "%.4f", vec[2]);
        }
        
        if (t->con.mode & CON_APPLY) {
        }
        
        if (t->con.mode & CON_APPLY) {
@@ -2672,17 +2882,23 @@ static void headerResize(TransInfo *t, float vec[3], char *str)
                                spos += sprintf(spos, "Scale: %s%s %s", &tvec[0], t->con.text, t->proptext);
                                break;
                        case 1:
                                spos += sprintf(spos, "Scale: %s%s %s", &tvec[0], t->con.text, t->proptext);
                                break;
                        case 1:
-                               spos += sprintf(spos, "Scale: %s : %s%s %s", &tvec[0], &tvec[20], t->con.text, t->proptext);
+                               spos += sprintf(spos, "Scale: %s : %s%s %s", &tvec[0], &tvec[NUM_STR_REP_LEN],
+                                               t->con.text, t->proptext);
                                break;
                        case 2:
                                break;
                        case 2:
-                               spos += sprintf(spos, "Scale: %s : %s : %s%s %s", &tvec[0], &tvec[20], &tvec[40], t->con.text, t->proptext);
+                               spos += sprintf(spos, "Scale: %s : %s : %s%s %s", &tvec[0], &tvec[NUM_STR_REP_LEN],
+                                               &tvec[NUM_STR_REP_LEN * 2], t->con.text, t->proptext);
                }
        }
        else {
                }
        }
        else {
-               if (t->flag & T_2D_EDIT)
-                       spos += sprintf(spos, "Scale X: %s   Y: %s%s %s", &tvec[0], &tvec[20], t->con.text, t->proptext);
-               else
-                       spos += sprintf(spos, "Scale X: %s   Y: %s  Z: %s%s %s", &tvec[0], &tvec[20], &tvec[40], t->con.text, t->proptext);
+               if (t->flag & T_2D_EDIT) {
+                       spos += sprintf(spos, "Scale X: %s   Y: %s%s %s", &tvec[0], &tvec[NUM_STR_REP_LEN],
+                                       t->con.text, t->proptext);
+               }
+               else {
+                       spos += sprintf(spos, "Scale X: %s   Y: %s  Z: %s%s %s", &tvec[0], &tvec[NUM_STR_REP_LEN],
+                                       &tvec[NUM_STR_REP_LEN * 2], t->con.text, t->proptext);
+               }
        }
        
        if (t->flag & (T_PROP_EDIT | T_PROP_CONNECTED)) {
        }
        
        if (t->flag & (T_PROP_EDIT | T_PROP_CONNECTED)) {
@@ -2692,11 +2908,21 @@ static void headerResize(TransInfo *t, float vec[3], char *str)
        (void)spos;
 }
 
        (void)spos;
 }
 
-#define SIGN(a)     (a<-FLT_EPSILON ? 1 : a>FLT_EPSILON ? 2 : 3)
-#define VECSIGNFLIP(a, b) ((SIGN(a[0]) & SIGN(b[0])) == 0 || (SIGN(a[1]) & SIGN(b[1])) == 0 || (SIGN(a[2]) & SIGN(b[2])) == 0)
+/* FLT_EPSILON is too small [#29633], 0.0000001f starts to flip */
+#define TX_FLIP_EPS 0.00001f
+BLI_INLINE int tx_sign(const float a)
+{
+       return (a < -TX_FLIP_EPS ? 1 : a > TX_FLIP_EPS ? 2 : 3);
+}
+BLI_INLINE int tx_vec_sign_flip(const float a[3], const float b[3])
+{
+       return ((tx_sign(a[0]) & tx_sign(b[0])) == 0 ||
+               (tx_sign(a[1]) & tx_sign(b[1])) == 0 ||
+               (tx_sign(a[2]) & tx_sign(b[2])) == 0);
+}
 
 /* smat is reference matrix, only scaled */
 
 /* smat is reference matrix, only scaled */
-static void TransMat3ToSize(float mat[][3], float smat[][3], float *size)
+static void TransMat3ToSize(float mat[3][3], float smat[3][3], float size[3])
 {
        float vec[3];
        
 {
        float vec[3];
        
@@ -2708,9 +2934,9 @@ static void TransMat3ToSize(float mat[][3], float smat[][3], float *size)
        size[2] = normalize_v3(vec);
        
        /* first tried with dotproduct... but the sign flip is crucial */
        size[2] = normalize_v3(vec);
        
        /* first tried with dotproduct... but the sign flip is crucial */
-       if (VECSIGNFLIP(mat[0], smat[0]) ) size[0] = -size[0];
-       if (VECSIGNFLIP(mat[1], smat[1]) ) size[1] = -size[1];
-       if (VECSIGNFLIP(mat[2], smat[2]) ) size[2] = -size[2];
+       if (tx_vec_sign_flip(mat[0], smat[0]) ) size[0] = -size[0];
+       if (tx_vec_sign_flip(mat[1], smat[1]) ) size[1] = -size[1];
+       if (tx_vec_sign_flip(mat[2], smat[2]) ) size[2] = -size[2];
 }
 
 
 }
 
 
@@ -2752,11 +2978,11 @@ static void ElementResize(TransInfo *t, TransData *td, float mat[3][3])
                
                if (t->flag & (T_OBJECT | T_TEXTURE | T_POSE)) {
                        float obsizemat[3][3];
                
                if (t->flag & (T_OBJECT | T_TEXTURE | T_POSE)) {
                        float obsizemat[3][3];
-                       // Reorient the size mat to fit the oriented object.
+                       /* Reorient the size mat to fit the oriented object. */
                        mul_m3_m3m3(obsizemat, tmat, td->axismtx);
                        mul_m3_m3m3(obsizemat, tmat, td->axismtx);
-                       //print_m3("obsizemat", obsizemat);
+                       /* print_m3("obsizemat", obsizemat); */
                        TransMat3ToSize(obsizemat, td->axismtx, fsize);
                        TransMat3ToSize(obsizemat, td->axismtx, fsize);
-                       //print_v3("fsize", fsize);
+                       /* print_v3("fsize", fsize); */
                }
                else {
                        mat3_to_size(fsize, tmat);
                }
                else {
                        mat3_to_size(fsize, tmat);
@@ -2764,7 +2990,7 @@ static void ElementResize(TransInfo *t, TransData *td, float mat[3][3])
                
                protectedSizeBits(td->protectflag, fsize);
                
                
                protectedSizeBits(td->protectflag, fsize);
                
-               if ((t->flag & T_V3D_ALIGN) == 0) {   // align mode doesn't resize objects itself
+               if ((t->flag & T_V3D_ALIGN) == 0) {   /* align mode doesn't resize objects itself */
                        if ((td->flag & TD_SINGLESIZE) && !(t->con.mode & CON_APPLY)) {
                                /* scale val and reset size */
                                *td->val = td->ival * (1 + (fsize[0] - 1) * td->factor);
                        if ((td->flag & TD_SINGLESIZE) && !(t->con.mode & CON_APPLY)) {
                                /* scale val and reset size */
                                *td->val = td->ival * (1 + (fsize[0] - 1) * td->factor);
@@ -2875,6 +3101,14 @@ int Resize(TransInfo *t, const int mval[2])
                
                for (i = 0, td = t->data; i < t->total; i++, td++)
                        ElementResize(t, td, mat);
                
                for (i = 0, td = t->data; i < t->total; i++, td++)
                        ElementResize(t, td, mat);
+
+               /* 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)) {
+                       clipUVData(t);
+               }
        }
        
        recalcData(t);
        }
        
        recalcData(t);
@@ -3028,7 +3262,7 @@ int ToSphere(TransInfo *t, const int UNUSED(mval[2]))
 
        /* header print for NumInput */
        if (hasNumInput(&t->num)) {
 
        /* header print for NumInput */
        if (hasNumInput(&t->num)) {
-               char c[20];
+               char c[NUM_STR_REP_LEN];
                
                outputNumInput(&(t->num), c);
                
                
                outputNumInput(&(t->num), c);
                
@@ -3231,7 +3465,7 @@ static void ElementRotation(TransInfo *t, TransData *td, float mat[3][3], short
                                /* this function works on end result */
                                protectedAxisAngleBits(td->protectflag, td->ext->rotAxis, td->ext->rotAngle, td->ext->irotAxis, td->ext->irotAngle);
                        }
                                /* this function works on end result */
                                protectedAxisAngleBits(td->protectflag, td->ext->rotAxis, td->ext->rotAngle, td->ext->irotAxis, td->ext->irotAngle);
                        }
-                       else { 
+                       else {
                                float eulmat[3][3];
                                
                                mul_m3_m3m3(totmat, mat, td->ext->r_mtx);
                                float eulmat[3][3];
                                
                                mul_m3_m3m3(totmat, mat, td->ext->r_mtx);
@@ -3374,7 +3608,7 @@ int Rotation(TransInfo *t, const int UNUSED(mval[2]))
        applySnapping(t, &final);
        
        if (hasNumInput(&t->num)) {
        applySnapping(t, &final);
        
        if (hasNumInput(&t->num)) {
-               char c[20];
+               char c[NUM_STR_REP_LEN];
                
                applyNumInput(&t->num, &final);
                
                
                applyNumInput(&t->num, &final);
                
@@ -3473,13 +3707,13 @@ int Trackball(TransInfo *t, const int UNUSED(mval[2]))
        snapGrid(t, phi);
 
        if (hasNumInput(&t->num)) {
        snapGrid(t, phi);
 
        if (hasNumInput(&t->num)) {
-               char c[40];
+               char c[NUM_STR_REP_LEN * 2];
 
                applyNumInput(&t->num, phi);
 
                outputNumInput(&(t->num), c);
 
 
                applyNumInput(&t->num, phi);
 
                outputNumInput(&(t->num), c);
 
-               spos += sprintf(spos, "Trackball: %s %s %s", &c[0], &c[20], t->proptext);
+               spos += sprintf(spos, "Trackball: %s %s %s", &c[0], &c[NUM_STR_REP_LEN], t->proptext);
 
                phi[0] = DEG2RADF(phi[0]);
                phi[1] = DEG2RADF(phi[1]);
 
                phi[0] = DEG2RADF(phi[0]);
                phi[1] = DEG2RADF(phi[1]);
@@ -3558,9 +3792,9 @@ void initTranslation(TransInfo *t)
 static void headerTranslation(TransInfo *t, float vec[3], char *str)
 {
        char *spos = str;
 static void headerTranslation(TransInfo *t, float vec[3], char *str)
 {
        char *spos = str;
-       char tvec[60];
-       char distvec[20];
-       char autoik[20];
+       char tvec[NUM_STR_REP_LEN * 3];
+       char distvec[NUM_STR_REP_LEN];
+       char autoik[NUM_STR_REP_LEN];
        float dist;
 
        if (hasNumInput(&t->num)) {
        float dist;
 
        if (hasNumInput(&t->num)) {
@@ -3577,13 +3811,15 @@ static void headerTranslation(TransInfo *t, float vec[3], char *str)
                if (!(t->flag & T_2D_EDIT) && t->scene->unit.system) {
                        int i, do_split = t->scene->unit.flag & USER_UNIT_OPT_SPLIT ? 1 : 0;
 
                if (!(t->flag & T_2D_EDIT) && t->scene->unit.system) {
                        int i, do_split = t->scene->unit.flag & USER_UNIT_OPT_SPLIT ? 1 : 0;
 
-                       for (i = 0; i < 3; i++)
-                               bUnit_AsString(&tvec[i * 20], 20, dvec[i] * t->scene->unit.scale_length, 4, t->scene->unit.system, B_UNIT_LENGTH, do_split, 1);
+                       for (i = 0; i < 3; i++) {
+                               bUnit_AsString(&tvec[i * NUM_STR_REP_LEN], NUM_STR_REP_LEN, dvec[i] * t->scene->unit.scale_length,
+                                              4, t->scene->unit.system, B_UNIT_LENGTH, do_split, 1);
+                       }
                }
                else {
                        sprintf(&tvec[0], "%.4f", dvec[0]);
                }
                else {
                        sprintf(&tvec[0], "%.4f", dvec[0]);
-                       sprintf(&tvec[20], "%.4f", dvec[1]);
-                       sprintf(&tvec[40], "%.4f", dvec[2]);
+                       sprintf(&tvec[NUM_STR_REP_LEN], "%.4f", dvec[1]);
+                       sprintf(&tvec[NUM_STR_REP_LEN * 2], "%.4f", dvec[2]);
                }
        }
 
                }
        }
 
@@ -3611,17 +3847,23 @@ static void headerTranslation(TransInfo *t, float vec[3], char *str)
                                spos += sprintf(spos, "D: %s (%s)%s %s  %s", &tvec[0], distvec, t->con.text, t->proptext, &autoik[0]);
                                break;
                        case 1:
                                spos += sprintf(spos, "D: %s (%s)%s %s  %s", &tvec[0], distvec, t->con.text, t->proptext, &autoik[0]);
                                break;
                        case 1:
-                               spos += sprintf(spos, "D: %s   D: %s (%s)%s %s  %s", &tvec[0], &tvec[20], distvec, t->con.text, t->proptext, &autoik[0]);
+                               spos += sprintf(spos, "D: %s   D: %s (%s)%s %s  %s", &tvec[0], &tvec[NUM_STR_REP_LEN],
+                                               distvec, t->con.text, t->proptext, &autoik[0]);
                                break;
                        case 2:
                                break;
                        case 2:
-                               spos += sprintf(spos, "D: %s   D: %s  D: %s (%s)%s %s  %s", &tvec[0], &tvec[20], &tvec[40], distvec, t->con.text, t->proptext, &autoik[0]);
+                               spos += sprintf(spos, "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[0]);
                }
        }
        else {
                }
        }
        else {
-               if (t->flag & T_2D_EDIT)
-                       spos += sprintf(spos, "Dx: %s   Dy: %s (%s)%s %s", &tvec[0], &tvec[20], distvec, t->con.text, t->proptext);
-               else
-                       spos += sprintf(spos, "Dx: %s   Dy: %s  Dz: %s (%s)%s %s  %s", &tvec[0], &tvec[20], &tvec[40], distvec, t->con.text, t->proptext, &autoik[0]);
+               if (t->flag & T_2D_EDIT) {
+                       spos += sprintf(spos, "Dx: %s   Dy: %s (%s)%s %s", &tvec[0], &tvec[NUM_STR_REP_LEN],
+                                       distvec, t->con.text, t->proptext);
+               }
+               else {
+                       spos += sprintf(spos, "Dx: %s   Dy: %s  Dz: %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[0]);
+               }
        }
        
        if (t->flag & (T_PROP_EDIT | T_PROP_CONNECTED)) {
        }
        
        if (t->flag & (T_PROP_EDIT | T_PROP_CONNECTED)) {
@@ -3725,9 +3967,18 @@ int Translation(TransInfo *t, const int UNUSED(mval[2]))
        applyTranslation(t, t->values);
 
        /* evil hack - redo translation if clipping needed */
        applyTranslation(t, t->values);
 
        /* evil hack - redo translation if clipping needed */
-       if (t->flag & T_CLIP_UV && clipUVTransform(t, t->values, 0))
+       if (t->flag & T_CLIP_UV && clipUVTransform(t, t->values, 0)) {
                applyTranslation(t, t->values);
 
                applyTranslation(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)) {
+                       clipUVData(t);
+               }
+       }
+
        recalcData(t);
 
        ED_area_headerprint(t->sa, str);
        recalcData(t);
 
        ED_area_headerprint(t->sa, str);
@@ -3762,10 +4013,8 @@ void initShrinkFatten(TransInfo *t)
 }
 
 
 }
 
 
-
 int ShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
 {
 int ShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
 {
-       float vec[3];
        float distance;
        int i;
        char str[64];
        float distance;
        int i;
        char str[64];
@@ -3779,7 +4028,7 @@ int ShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
 
        /* header print for NumInput */
        if (hasNumInput(&t->num)) {
 
        /* header print for NumInput */
        if (hasNumInput(&t->num)) {
-               char c[20];
+               char c[NUM_STR_REP_LEN];
 
                outputNumInput(&(t->num), c);
 
 
                outputNumInput(&(t->num), c);
 
@@ -3790,20 +4039,23 @@ int ShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
                sprintf(str, "Shrink/Fatten: %.4f %s", distance, t->proptext);
        }
 
                sprintf(str, "Shrink/Fatten: %.4f %s", distance, t->proptext);
        }
 
-       t->values[0] = distance;
+       t->values[0] = -distance;
 
        for (i = 0; i < t->total; i++, td++) {
 
        for (i = 0; i < t->total; i++, td++) {
+               float tdistance;  /* temp dist */
                if (td->flag & TD_NOACTION)
                        break;
 
                if (td->flag & TD_SKIP)
                        continue;
 
                if (td->flag & TD_NOACTION)
                        break;
 
                if (td->flag & TD_SKIP)
                        continue;
 
-               copy_v3_v3(vec, td->axismtx[2]);
-               mul_v3_fl(vec, distance);
-               mul_v3_fl(vec, td->factor);
+               /* get the final offset */
+               tdistance = distance * td->factor;
+               if (td->ext && (t->flag & T_ALT_TRANSFORM)) {
+                       tdistance *= td->ext->isize[0];  /* shell factor */
+               }
 
 
-               add_v3_v3v3(td->loc, td->iloc, vec);
+               madd_v3_v3v3fl(td->loc, td->iloc, td->axismtx[2], tdistance);
        }
 
        recalcData(t);
        }
 
        recalcData(t);
@@ -3848,18 +4100,21 @@ int Tilt(TransInfo *t, const int UNUSED(mval[2]))
        snapGrid(t, &final);
 
        if (hasNumInput(&t->num)) {
        snapGrid(t, &final);
 
        if (hasNumInput(&t->num)) {
-               char c[20];
+               char c[NUM_STR_REP_LEN];
 
                applyNumInput(&t->num, &final);
 
                outputNumInput(&(t->num), c);
 
 
                applyNumInput(&t->num, &final);
 
                outputNumInput(&(t->num), c);
 
-               sprintf(str, "Tilt: %s %s", &c[0], t->proptext);
+               sprintf(str, "Tilt: %s° %s", &c[0], t->proptext);
 
                final = DEG2RADF(final);
 
                final = DEG2RADF(final);
+
+               /* XXX For some reason, this seems needed for this op, else RNA prop is not updated... :/ */
+               t->values[0] = final;
        }
        else {
        }
        else {
-               sprintf(str, "Tilt: %.2f %s", RAD2DEGF(final), t->proptext);
+               sprintf(str, "Tilt: %.2f° %s", RAD2DEGF(final), t->proptext);
        }
 
        for (i = 0; i < t->total; i++, td++) {
        }
 
        for (i = 0; i < t->total; i++, td++) {
@@ -3920,7 +4175,7 @@ int CurveShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
 
        /* header print for NumInput */
        if (hasNumInput(&t->num)) {
 
        /* header print for NumInput */
        if (hasNumInput(&t->num)) {
-               char c[20];
+               char c[NUM_STR_REP_LEN];
 
                outputNumInput(&(t->num), c);
                sprintf(str, "Shrink/Fatten: %s", c);
 
                outputNumInput(&(t->num), c);
                sprintf(str, "Shrink/Fatten: %s", c);
@@ -3975,9 +4230,9 @@ void initMaskShrinkFatten(TransInfo *t)
 
 int MaskShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
 {
 
 int MaskShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
 {
-       TransData *td = t->data;
+       TransData *td;
        float ratio;
        float ratio;
-       int i;
+       int i, initial_feather = FALSE;
        char str[50];
 
        ratio = t->values[0];
        char str[50];
 
        ratio = t->values[0];
@@ -3988,16 +4243,33 @@ int MaskShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
 
        /* header print for NumInput */
        if (hasNumInput(&t->num)) {
 
        /* header print for NumInput */
        if (hasNumInput(&t->num)) {
-               char c[20];
+               char c[NUM_STR_REP_LEN];
 
                outputNumInput(&(t->num), c);
 
                outputNumInput(&(t->num), c);
-               sprintf(str, "Shrink/Fatten: %s", c);
+               sprintf(str, "Feather Shrink/Fatten: %s", c);
        }
        else {
        }
        else {
-               sprintf(str, "Shrink/Fatten: %3f", ratio);
+               sprintf(str, "Feather Shrink/Fatten: %3f", ratio);
        }
 
        }
 
-       for (i = 0; i < t->total; i++, td++) {
+       /* detect if no points have feather yet */
+       if (ratio > 1.0f) {
+               initial_feather = TRUE;
+
+               for (td = t->data, i = 0; i < t->total; i++, td++) {
+                       if (td->flag & TD_NOACTION)
+                               break;
+
+                       if (td->flag & TD_SKIP)
+                               continue;
+
+                       if (td->ival >= 0.001f)
+                               initial_feather = FALSE;
+               }
+       }
+
+       /* apply shrink/fatten */
+       for (td = t->data, i = 0; i < t->total; i++, td++) {
                if (td->flag & TD_NOACTION)
                        break;
 
                if (td->flag & TD_NOACTION)
                        break;
 
@@ -4005,7 +4277,11 @@ int MaskShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
                        continue;
 
                if (td->val) {
                        continue;
 
                if (td->val) {
-                       *td->val = td->ival * ratio;
+                       if (initial_feather)
+                               *td->val = td->ival + (ratio - 1.0f) * 0.01f;
+                       else
+                               *td->val = td->ival * ratio;
+
                        /* apply PET */
                        *td->val = (*td->val * td->factor) + ((1.0f - td->factor) * td->ival);
                        if (*td->val <= 0.0f) *td->val = 0.001f;
                        /* apply PET */
                        *td->val = (*td->val * td->factor) + ((1.0f - td->factor) * td->ival);
                        if (*td->val <= 0.0f) *td->val = 0.001f;
@@ -4054,7 +4330,7 @@ int PushPull(TransInfo *t, const int UNUSED(mval[2]))
 
        /* header print for NumInput */
        if (hasNumInput(&t->num)) {
 
        /* header print for NumInput */
        if (hasNumInput(&t->num)) {
-               char c[20];
+               char c[NUM_STR_REP_LEN];
 
                outputNumInput(&(t->num), c);
 
 
                outputNumInput(&(t->num), c);
 
@@ -4190,7 +4466,7 @@ int Bevel(TransInfo *t, const int UNUSED(mval[2]))
 
        /* header print for NumInput */
        if (hasNumInput(&t->num)) {
 
        /* header print for NumInput */
        if (hasNumInput(&t->num)) {
-               char c[20];
+               char c[NUM_STR_REP_LEN];
 
                outputNumInput(&(t->num), c);
 
 
                outputNumInput(&(t->num), c);
 
@@ -4257,7 +4533,7 @@ int BevelWeight(TransInfo *t, const int UNUSED(mval[2]))
 
        /* header print for NumInput */
        if (hasNumInput(&t->num)) {
 
        /* header print for NumInput */
        if (hasNumInput(&t->num)) {
-               char c[20];
+               char c[NUM_STR_REP_LEN];
 
                outputNumInput(&(t->num), c);
 
 
                outputNumInput(&(t->num), c);
 
@@ -4330,7 +4606,7 @@ int Crease(TransInfo *t, const int UNUSED(mval[2]))
 
        /* header print for NumInput */
        if (hasNumInput(&t->num)) {
 
        /* header print for NumInput */
        if (hasNumInput(&t->num)) {
-               char c[20];
+               char c[NUM_STR_REP_LEN];
 
                outputNumInput(&(t->num), c);
 
 
                outputNumInput(&(t->num), c);
 
@@ -4390,14 +4666,14 @@ void initBoneSize(TransInfo *t)
 
 static void headerBoneSize(TransInfo *t, float vec[3], char *str)
 {
 
 static void headerBoneSize(TransInfo *t, float vec[3], char *str)
 {
-       char tvec[60];
+       char tvec[NUM_STR_REP_LEN * 3];
        if (hasNumInput(&t->num)) {
                outputNumInput(&(t->num), tvec);
        }
        else {
                sprintf(&tvec[0], "%.4f", vec[0]);
        if (hasNumInput(&t->num)) {
                outputNumInput(&(t->num), tvec);
        }
        else {
                sprintf(&tvec[0], "%.4f", vec[0]);
-               sprintf(&tvec[20], "%.4f", vec[1]);
-               sprintf(&tvec[40], "%.4f", vec[2]);
+               sprintf(&tvec[NUM_STR_REP_LEN], "%.4f", vec[1]);
+               sprintf(&tvec[NUM_STR_REP_LEN * 2], "%.4f", vec[2]);
        }
 
        /* hmm... perhaps the y-axis values don't need to be shown? */
        }
 
        /* hmm... perhaps the y-axis values don't need to be shown? */
@@ -4405,10 +4681,12 @@ static void headerBoneSize(TransInfo *t, float vec[3], char *str)
                if (t->num.idx_max == 0)
                        sprintf(str, "ScaleB: %s%s %s", &tvec[0], t->con.text, t->proptext);
                else
                if (t->num.idx_max == 0)
                        sprintf(str, "ScaleB: %s%s %s", &tvec[0], t->con.text, t->proptext);
                else
-                       sprintf(str, "ScaleB: %s : %s : %s%s %s", &tvec[0], &tvec[20], &tvec[40], t->con.text, t->proptext);
+                       sprintf(str, "ScaleB: %s : %s : %s%s %s", &tvec[0], &tvec[NUM_STR_REP_LEN], &tvec[NUM_STR_REP_LEN * 2],
+                               t->con.text, t->proptext);
        }
        else {
        }
        else {
-               sprintf(str, "ScaleB X: %s  Y: %s  Z: %s%s %s", &tvec[0], &tvec[20], &tvec[40], t->con.text, t->proptext);
+               sprintf(str, "ScaleB X: %s  Y: %s  Z: %s%s %s", &tvec[0], &tvec[NUM_STR_REP_LEN], &tvec[NUM_STR_REP_LEN * 2],
+                       t->con.text, t->proptext);
        }
 }
 
        }
 }
 
@@ -4521,7 +4799,7 @@ int BoneEnvelope(TransInfo *t, const int UNUSED(mval[2]))
        
        /* header print for NumInput */
        if (hasNumInput(&t->num)) {
        
        /* header print for NumInput */
        if (hasNumInput(&t->num)) {
-               char c[20];
+               char c[NUM_STR_REP_LEN];
                
                outputNumInput(&(t->num), c);
                sprintf(str, "Envelope: %s", c);
                
                outputNumInput(&(t->num), c);
                sprintf(str, "Envelope: %s", c);
@@ -4594,8 +4872,7 @@ static BMLoop *get_next_loop(BMVert *v, BMLoop *l,
                                cross_v3_v3v3(a, f2, l->f->no);
                                mul_v3_fl(a, -1.0f);
 
                                cross_v3_v3v3(a, f2, l->f->no);
                                mul_v3_fl(a, -1.0f);
 
-                               add_v3_v3(a, f3);
-                               mul_v3_fl(a, 0.5f);
+                               mid_v3_v3v3(a, a, f3);
                        }
                        
                        copy_v3_v3(vec, a);
                        }
                        
                        copy_v3_v3(vec, a);
@@ -4616,7 +4893,7 @@ static BMLoop *get_next_loop(BMVert *v, BMLoop *l,
                }
                
                l = l->radial_next;
                }
                
                l = l->radial_next;
-       } while (l != firstl); 
+       } while (l != firstl);
 
        if (i)
                mul_v3_fl(a, 1.0f / (float)i);
 
        if (i)
                mul_v3_fl(a, 1.0f / (float)i);
@@ -4626,9 +4903,9 @@ static BMLoop *get_next_loop(BMVert *v, BMLoop *l,
        return NULL;
 }
 
        return NULL;
 }
 
-static void calcNonProportionalEdgeSlide(TransInfo *t, SlideData *sld, const float mval[2])
+static void calcNonProportionalEdgeSlide(TransInfo *t, EdgeSlideData *sld, const float mval[2])
 {
 {
-       TransDataSlideVert *sv = sld->sv;
+       TransDataEdgeSlideVert *sv = sld->sv;
 
        if (sld->totsv > 0) {
                int i = 0;
 
        if (sld->totsv > 0) {
                int i = 0;
@@ -4637,22 +4914,18 @@ static void calcNonProportionalEdgeSlide(TransInfo *t, SlideData *sld, const flo
                float dist = 0;
                float min_dist = FLT_MAX;
 
                float dist = 0;
                float min_dist = FLT_MAX;
 
-               float up_p[3];
-               float dw_p[3];
-
                for (i = 0; i < sld->totsv; i++, sv++) {
                        /* Set length */
                for (i = 0; i < sld->totsv; i++, sv++) {
                        /* Set length */
-                       add_v3_v3v3(up_p, sv->origvert.co, sv->upvec);
-                       add_v3_v3v3(dw_p, sv->origvert.co, sv->downvec);
-                       sv->edge_len = len_v3v3(dw_p, up_p);
+                       sv->edge_len = len_v3v3(sv->upvec, sv->downvec);
 
                        mul_v3_m4v3(v_proj, t->obedit->obmat, sv->v->co);
 
                        mul_v3_m4v3(v_proj, t->obedit->obmat, sv->v->co);
-                       project_float_noclip(t->ar, v_proj, v_proj);
-
-                       dist = len_squared_v2v2(mval, v_proj);
-                       if (dist < min_dist) {
-                               min_dist = dist;
-                               sld->curr_sv_index = i;
+                       /* allow points behind the view [#33643] */
+                       if (ED_view3d_project_float_global(t->ar, v_proj, v_proj, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) {
+                               dist = len_squared_v2v2(mval, v_proj);
+                               if (dist < min_dist) {
+                                       min_dist = dist;
+                                       sld->curr_sv_index = i;
+                               }
                        }
                }
        }
                        }
                }
        }
@@ -4661,27 +4934,27 @@ static void calcNonProportionalEdgeSlide(TransInfo *t, SlideData *sld, const flo
        }
 }
 
        }
 }
 
-static int createSlideVerts(TransInfo *t)
+static int createEdgeSlideVerts(TransInfo *t)
 {
 {
-       Mesh *me = t->obedit->data;
-       BMEditMesh *em = me->edit_btmesh;
+       BMEditMesh *em = BMEdit_FromObject(t->obedit);
        BMesh *bm = em->bm;
        BMesh *bm = em->bm;
-       BMIter iter, iter2;
-       BMEdge *e, *e1 /*, *ee, *le */ /* UNUSED */;
+       BMIter iter;
+       BMEdge *e, *e1;
        BMVert *v, *v2, *first;
        BMVert *v, *v2, *first;
-       BMLoop *l, *l1, *l2;
-       TransDataSlideVert *sv_array;
-       BMBVHTree *btree = BMBVH_NewBVH(em, BMBVH_RESPECT_HIDDEN, NULL, NULL);
+       TransDataEdgeSlideVert *sv_array;
+       BMBVHTree *btree;
        SmallHash table;
        SmallHash table;
-       SlideData *sld = MEM_callocN(sizeof(*sld), "sld");
+       EdgeSlideData *sld = MEM_callocN(sizeof(*sld), "sld");
        View3D *v3d = NULL;
        RegionView3D *rv3d = NULL;
        ARegion *ar = t->ar;
        float projectMat[4][4];
        float mval[2] = {(float)t->mval[0], (float)t->mval[1]};
        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}, dir[3], end[3] = {0.0f, 0.0f, 0.0f};
-       float vec[3], vec2[3], lastvec[3] /*, size, dis=0.0, z */ /* UNUSED */;
-       int numsel, i, j;
+       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;
+       int numsel, i, j, loop_nr, l_nr;
+       int use_btree_disp;
 
        if (t->spacetype == SPACE_VIEW3D) {
                /* background mode support */
 
        if (t->spacetype == SPACE_VIEW3D) {
                /* background mode support */
@@ -4689,6 +4962,15 @@ static int createSlideVerts(TransInfo *t)
                rv3d = t->ar ? t->ar->regiondata : NULL;
        }
 
                rv3d = t->ar ? t->ar->regiondata : NULL;
        }
 
+       use_btree_disp = (v3d && t->obedit->dt > OB_WIRE && v3d->drawtype > OB_WIRE);
+
+       if (use_btree_disp) {
+               btree = BMBVH_NewBVH(em, BMBVH_RESPECT_HIDDEN, NULL, NULL);
+       }
+       else {
+               btree = NULL;
+       }
+
        sld->is_proportional = TRUE;
        sld->curr_sv_index = 0;
        sld->flipped_vtx = FALSE;
        sld->is_proportional = TRUE;
        sld->curr_sv_index = 0;
        sld->flipped_vtx = FALSE;
@@ -4708,6 +4990,7 @@ static int createSlideVerts(TransInfo *t)
        /*ensure valid selection*/
        BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
                if (BM_elem_flag_test(v, BM_ELEM_SELECT)) {
        /*ensure valid selection*/
        BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
                if (BM_elem_flag_test(v, BM_ELEM_SELECT)) {
+                       BMIter iter2;
                        numsel = 0;
                        BM_ITER_ELEM (e, &iter2, v, BM_EDGES_OF_VERT) {
                                if (BM_elem_flag_test(e, BM_ELEM_SELECT)) {
                        numsel = 0;
                        BM_ITER_ELEM (e, &iter2, v, BM_EDGES_OF_VERT) {
                                if (BM_elem_flag_test(e, BM_ELEM_SELECT)) {
@@ -4721,7 +5004,8 @@ static int createSlideVerts(TransInfo *t)
 
                        if (numsel == 0 || numsel > 2) {
                                MEM_freeN(sld);
 
                        if (numsel == 0 || numsel > 2) {
                                MEM_freeN(sld);
-                               BMBVH_FreeBVH(btree);
+                               if (btree)
+                                       BMBVH_FreeBVH(btree);
                                return 0; /* invalid edge selection */
                        }
                }
                                return 0; /* invalid edge selection */
                        }
                }
@@ -4731,7 +5015,8 @@ static int createSlideVerts(TransInfo *t)
                if (BM_elem_flag_test(e, BM_ELEM_SELECT)) {
                        if (!BM_edge_is_manifold(e)) {
                                MEM_freeN(sld);
                if (BM_elem_flag_test(e, BM_ELEM_SELECT)) {
                        if (!BM_edge_is_manifold(e)) {
                                MEM_freeN(sld);
-                               BMBVH_FreeBVH(btree);
+                               if (btree)
+                                       BMBVH_FreeBVH(btree);
                                return 0; /* can only handle exactly 2 faces around each edge */
                        }
                }
                                return 0; /* can only handle exactly 2 faces around each edge */
                        }
                }
@@ -4751,14 +5036,18 @@ static int createSlideVerts(TransInfo *t)
 
        if (!j) {
                MEM_freeN(sld);
 
        if (!j) {
                MEM_freeN(sld);
-               BMBVH_FreeBVH(btree);
+               if (btree)
+                       BMBVH_FreeBVH(btree);
                return 0;
        }
 
                return 0;
        }
 
-       sv_array = MEM_callocN(sizeof(TransDataSlideVert) * j, "sv_array");
+       sv_array = MEM_callocN(sizeof(TransDataEdgeSlideVert) * j, "sv_array");
+       loop_nr = 0;
 
        j = 0;
        while (1) {
 
        j = 0;
        while (1) {
+               BMLoop *l, *l1, *l2;
+
                v = NULL;
                BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
                        if (BM_elem_flag_test(v, BM_ELEM_TAG))
                v = NULL;
                BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
                        if (BM_elem_flag_test(v, BM_ELEM_TAG))
@@ -4814,10 +5103,12 @@ static int createSlideVerts(TransInfo *t)
                /*iterate over the loop*/
                first = v;
                do {
                /*iterate over the loop*/
                first = v;
                do {
-                       TransDataSlideVert *sv = sv_array + j;
+                       TransDataEdgeSlideVert *sv = sv_array + j;
 
                        sv->v = v;
                        sv->origvert = *v;
 
                        sv->v = v;
                        sv->origvert = *v;
+                       sv->loop_nr = loop_nr;
+
                        copy_v3_v3(sv->upvec, vec);
                        if (l2)
                                copy_v3_v3(sv->downvec, vec2);
                        copy_v3_v3(sv->upvec, vec);
                        if (l2)
                                copy_v3_v3(sv->downvec, vec2);
@@ -4840,6 +5131,7 @@ static int createSlideVerts(TransInfo *t)
                                sv = sv_array + j + 1;
                                sv->v = v;
                                sv->origvert = *v;
                                sv = sv_array + j + 1;
                                sv->v = v;
                                sv->origvert = *v;
+                               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);
                                
                                l = BM_face_other_edge_loop(l1->f, l1->e, v);
                                sv->up = BM_edge_other_vert(l->e, v);
@@ -4866,61 +5158,75 @@ static int createSlideVerts(TransInfo *t)
                        BM_elem_flag_disable(v, BM_ELEM_TAG);
                        BM_elem_flag_disable(v2, BM_ELEM_TAG);
                } while (e != first->e && l1);
                        BM_elem_flag_disable(v, BM_ELEM_TAG);
                        BM_elem_flag_disable(v2, BM_ELEM_TAG);
                } while (e != first->e && l1);
+
+               loop_nr++;
        }
 
        }
 
-       //EDBM_flag_disable_all(em, BM_ELEM_SELECT);
+       /* EDBM_flag_disable_all(em, BM_ELEM_SELECT); */
 
        sld->sv = sv_array;
        sld->totsv = j;
        
 
        sld->sv = sv_array;
        sld->totsv = j;
        
-       /*find mouse vector*/
-       /* dis = z = -1.0f; */ /* UNUSED */
-       /* size = 50.0; */ /* UNUSED */
-       zero_v3(lastvec); zero_v3(dir);
-       /* ee = le = NULL; */ /* UNUSED */
+       /* 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);
+       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;
+
        BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
                if (BM_elem_flag_test(e, BM_ELEM_SELECT)) {
                        BMIter iter2;
                        BMEdge *e2;
        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], dis2, mval[2] = {t->mval[0], t->mval[1]}, d;
-                                               
+                       float vec1[3], d;
+
                        /* search cross edges for visible edge to the mouse cursor,
                         * then use the shared vertex to calculate screen vector*/
                        /* search cross edges for visible edge to the mouse cursor,
                         * then use the shared vertex to calculate screen vector*/
-                       dis2 = -1.0f;
                        for (i = 0; i < 2; i++) {
                                v = i ? e->v1 : e->v2;
                                BM_ITER_ELEM (e2, &iter2, v, BM_EDGES_OF_VERT) {
                                        if (BM_elem_flag_test(e2, BM_ELEM_SELECT))
                                                continue;
                        for (i = 0; i < 2; i++) {
                                v = i ? e->v1 : e->v2;
                                BM_ITER_ELEM (e2, &iter2, v, BM_EDGES_OF_VERT) {
                                        if (BM_elem_flag_test(e2, BM_ELEM_SELECT))
                                                continue;
-                                       
-                                       if (v3d && !BMBVH_EdgeVisible(btree, e2, ar, v3d, t->obedit))
+
+                                       /* This test is only relevant if object is not wire-drawn! See [#32068]. */
+                                       if (use_btree_disp && !BMBVH_EdgeVisible(btree, e2, ar, v3d, t->obedit)) {
                                                continue;
                                                continue;
-                                       
+                                       }
+
                                        j = GET_INT_FROM_POINTER(BLI_smallhash_lookup(&table, (uintptr_t)v));
 
                                        if (sv_array[j].down) {
                                        j = GET_INT_FROM_POINTER(BLI_smallhash_lookup(&table, (uintptr_t)v));
 
                                        if (sv_array[j].down) {
-                                               ED_view3d_project_float_v3(ar, sv_array[j].down->co, vec1, projectMat);
+                                               ED_view3d_project_float_v3_m4(ar, sv_array[j].down->co, vec1, projectMat);
                                        }
                                        else {
                                                add_v3_v3v3(vec1, v->co, sv_array[j].downvec);
                                        }
                                        else {
                                                add_v3_v3v3(vec1, v->co, sv_array[j].downvec);
-                                               ED_view3d_project_float_v3(ar, vec1, vec1, projectMat);
+                                               ED_view3d_project_float_v3_m4(ar, vec1, vec1, projectMat);
                                        }
                                        
                                        if (sv_array[j].up) {
                                        }
                                        
                                        if (sv_array[j].up) {
-                                               ED_view3d_project_float_v3(ar, sv_array[j].up->co, vec2, projectMat);
+                                               ED_view3d_project_float_v3_m4(ar, sv_array[j].up->co, vec2, projectMat);
                                        }
                                        else {
                                        }
                                        else {
-                                               add_v3_v3v3(vec1, v->co, sv_array[j].upvec);
-                                               ED_view3d_project_float_v3(ar, vec2, vec2, projectMat);
+                                               add_v3_v3v3(vec2, v->co, sv_array[j].upvec);
+                                               ED_view3d_project_float_v3_m4(ar, vec2, vec2, projectMat);
                                        }
                                        }
-
+                                       
+                                       /* global direction */
                                        d = dist_to_line_segment_v2(mval, vec1, vec2);
                                        d = dist_to_line_segment_v2(mval, vec1, vec2);
-                                       if (dis2 == -1.0f || d < dis2) {
-                                               dis2 = d;
-                                               /* ee = e2; */ /* UNUSED */
-                                               /* size = len_v3v3(vec1, vec2); */ /* UNUSED */
+                                       if (maxdist == -1.0f || d < maxdist) {
+                                               maxdist = d;
                                                sub_v3_v3v3(dir, vec1, vec2);
                                        }
                                                sub_v3_v3v3(dir, vec1, vec2);
                                        }
+
+                                       /* 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);
+                                       }
                                }
                        }
                }
                                }
                        }
                }
@@ -4954,6 +5260,14 @@ static int createSlideVerts(TransInfo *t)
                }
 
                BLI_smallhash_insert(&sld->vhash, (uintptr_t)sv_array->v, sv_array);
                }
 
                BLI_smallhash_insert(&sld->vhash, (uintptr_t)sv_array->v, sv_array);
+
+               /* switch up/down 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 (rv3d)
        }
 
        if (rv3d)
@@ -4964,7 +5278,7 @@ static int createSlideVerts(TransInfo *t)
        
        /*zero out start*/
        zero_v3(start);
        
        /*zero out start*/
        zero_v3(start);
-       
+
        /*dir holds a vector along edge loop*/
        copy_v3_v3(end, dir);
        mul_v3_fl(end, 0.5f);
        /*dir holds a vector along edge loop*/
        copy_v3_v3(end, dir);
        mul_v3_fl(end, 0.5f);
@@ -4980,19 +5294,25 @@ static int createSlideVerts(TransInfo *t)
        t->customData = sld;
        
        BLI_smallhash_release(&table);
        t->customData = sld;
        
        BLI_smallhash_release(&table);
-       BMBVH_FreeBVH(btree);
-       
+       if (btree) {
+               BMBVH_FreeBVH(btree);
+       }
+       MEM_freeN(loop_dir);
+       MEM_freeN(loop_maxdist);
+
+       /* arrays are dirty from copying faces: EDBM_index_arrays_free */
+       EDBM_update_generic(em, FALSE, TRUE);
+
        return 1;
 }
 
        return 1;
 }
 
-void projectSVData(TransInfo *t, int final)
+void projectEdgeSlideData(TransInfo *t, bool is_final)
 {
 {
-       SlideData *sld = t->customData;
-       TransDataSlideVert *sv;
+       EdgeSlideData *sld = t->customData;
+       TransDataEdgeSlideVert *sv;
        BMEditMesh *em = sld->em;
        SmallHash visit;
        int i;
        BMEditMesh *em = sld->em;
        SmallHash visit;
        int i;
-       short has_uv;
 
        if (!em)
                return;
 
        if (!em)
                return;
@@ -5005,16 +5325,12 @@ void projectSVData(TransInfo *t, int final)
        if (em->bm->shapenr > 1)
                return;
 
        if (em->bm->shapenr > 1)
                return;
 
-       has_uv = CustomData_has_layer(&(em->bm->ldata), CD_MLOOPUV);
-
        BLI_smallhash_init(&visit);
        
        for (i = 0, sv = sld->sv; i < sld->totsv; sv++, i++) {
                BMIter fiter;
                BMFace *f;
        BLI_smallhash_init(&visit);
        
        for (i = 0, sv = sld->sv; i < sld->totsv; sv++, i++) {
                BMIter fiter;
                BMFace *f;
-               BMIter liter_v;
-               BMLoop *l_v;
-               
+
                /* 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? */
                /* 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? */
@@ -5112,15 +5428,15 @@ void projectSVData(TransInfo *t, int final)
                                        }
 
                                }
                                        }
 
                                }
-                               
-                               if(!affected)
+
+                               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);
 
                                        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);
 
-                               if (final) {
+                               if (is_final) {
                                        BM_loop_interp_multires(em->bm, l, f_copy_flip);
                                        if (f_copy != f_copy_flip) {
                                                BM_loop_interp_multires(em->bm, l, f_copy);
                                        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);
@@ -5139,32 +5455,12 @@ void projectSVData(TransInfo *t, int final)
                                BM_elem_hide_set(em->bm, f, is_hide);
                        }
                }
                                BM_elem_hide_set(em->bm, f, is_hide);
                        }
                }
-
-               /* make sure every loop of the vertex has identical uv data. Use this temporarily to
-                * fix #31581 until proper data correction/ support for islands is done */
-               /* XXX - this only does the active UV layer which is not really good, should do _all_ uv's - campbell */
-               if (has_uv) {
-                       float uv_med[2] = {0.0, 0.0};
-                       int tot_loops = 0;
-                       BM_ITER_ELEM (l_v, &liter_v, sv->v, BM_LOOPS_OF_VERT) {
-                               MLoopUV *uv = CustomData_bmesh_get(&em->bm->ldata, l_v->head.data, CD_MLOOPUV);
-                               add_v2_v2(uv_med, uv->uv);
-                               tot_loops++;
-                       }
-
-                       mul_v2_fl(uv_med, 1.0/tot_loops);
-
-                       BM_ITER_ELEM (l_v, &liter_v, sv->v, BM_LOOPS_OF_VERT) {
-                               MLoopUV *uv = CustomData_bmesh_get(&em->bm->ldata, l_v->head.data, CD_MLOOPUV);
-                               copy_v2_v2(uv->uv, uv_med);
-                       }
-               }
        }
 
        BLI_smallhash_release(&visit);
 }
 
        }
 
        BLI_smallhash_release(&visit);
 }
 
-void freeSlideTempFaces(SlideData *sld)
+void freeEdgeSlideTempFaces(EdgeSlideData *sld)
 {
        if (sld->origfaces_init) {
                SmallHashIter hiter;
 {
        if (sld->origfaces_init) {
                SmallHashIter hiter;
@@ -5178,17 +5474,20 @@ void freeSlideTempFaces(SlideData *sld)
                BLI_smallhash_release(&sld->origfaces);
 
                sld->origfaces_init = FALSE;
                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);
        }
 }
 
 
        }
 }
 
 
-void freeSlideVerts(TransInfo *t)
+void freeEdgeSlideVerts(TransInfo *t)
 {
 {
-       SlideData *sld = t->customData;
+       EdgeSlideData *sld = t->customData;
        
 #if 0 /*BMESH_TODO*/
        if (me->drawflag & ME_DRAWEXTRA_EDGELEN) {
        
 #if 0 /*BMESH_TODO*/
        if (me->drawflag & ME_DRAWEXTRA_EDGELEN) {
-               TransDataSlideVert *sv;
+               TransDataEdgeSlideVert *sv;
                LinkNode *look = sld->vertlist;
                GHash *vertgh = sld->vhash;
                while (look) {
                LinkNode *look = sld->vertlist;
                GHash *vertgh = sld->vhash;
                while (look) {
@@ -5205,7 +5504,7 @@ void freeSlideVerts(TransInfo *t)
        if (!sld)
                return;
        
        if (!sld)
                return;
        
-       freeSlideTempFaces(sld);
+       freeEdgeSlideTempFaces(sld);
 
        bmesh_edit_end(sld->em->bm, BMO_OP_FLAG_UNTAN_MULTIRES);
 
 
        bmesh_edit_end(sld->em->bm, BMO_OP_FLAG_UNTAN_MULTIRES);
 
@@ -5221,13 +5520,13 @@ void freeSlideVerts(TransInfo *t)
 
 void initEdgeSlide(TransInfo *t)
 {
 
 void initEdgeSlide(TransInfo *t)
 {
-       SlideData *sld;
+       EdgeSlideData *sld;
 
        t->mode = TFM_EDGE_SLIDE;
        t->transform = EdgeSlide;
        t->handleEvent = handleEventEdgeSlide;
 
 
        t->mode = TFM_EDGE_SLIDE;
        t->transform = EdgeSlide;
        t->handleEvent = handleEventEdgeSlide;
 
-       if (!createSlideVerts(t)) {
+       if (!createEdgeSlideVerts(t)) {
                t->state = TRANS_CANCEL;
                return;
        }
                t->state = TRANS_CANCEL;
                return;
        }
@@ -5237,7 +5536,7 @@ void initEdgeSlide(TransInfo *t)
        if (!sld)
                return;
 
        if (!sld)
                return;
 
-       t->customFree = freeSlideVerts;
+       t->customFree = freeEdgeSlideVerts;
 
        /* set custom point first if you want value to be initialized by init */
        setCustomPoints(t, &t->mouse, sld->end, sld->start);
 
        /* set custom point first if you want value to be initialized by init */
        setCustomPoints(t, &t->mouse, sld->end, sld->start);
@@ -5257,7 +5556,7 @@ void initEdgeSlide(TransInfo *t)
 int handleEventEdgeSlide(struct TransInfo *t, struct wmEvent *event)
 {
        if (t->mode == TFM_EDGE_SLIDE) {
 int handleEventEdgeSlide(struct TransInfo *t, struct wmEvent *event)
 {
        if (t->mode == TFM_EDGE_SLIDE) {
-               SlideData *sld = t->customData;
+               EdgeSlideData *sld = t->customData;
 
                if (sld) {
                        switch (event->type) {
 
                if (sld) {
                        switch (event->type) {
@@ -5267,7 +5566,8 @@ int handleEventEdgeSlide(struct TransInfo *t, struct wmEvent *event)
                                                return 1;
                                        }
                                        break;
                                                return 1;
                                        }
                                        break;
-                               case FKEY: {
+                               case FKEY:
+                               {
                                        if (event->val == KM_PRESS) {
                                                if (sld->is_proportional == FALSE) {
                                                        sld->flipped_vtx = !sld->flipped_vtx;
                                        if (event->val == KM_PRESS) {
                                                if (sld->is_proportional == FALSE) {
                                                        sld->flipped_vtx = !sld->flipped_vtx;
@@ -5276,13 +5576,16 @@ int handleEventEdgeSlide(struct TransInfo *t, struct wmEvent *event)
                                        }
                                        break;
                                }
                                        }
                                        break;
                                }
-                               case EVT_MODAL_MAP: {
+                               case EVT_MODAL_MAP:
+                               {
                                        switch (event->val) {
                                        switch (event->val) {
-                                               case TFM_MODAL_EDGESLIDE_DOWN: {
+                                               case TFM_MODAL_EDGESLIDE_DOWN:
+                                               {
                                                        sld->curr_sv_index = ((sld->curr_sv_index - 1) + sld->totsv) % sld->totsv;
                                                        break;
                                                }
                                                        sld->curr_sv_index = ((sld->curr_sv_index - 1) + sld->totsv) % sld->totsv;
                                                        break;
                                                }
-                                               case TFM_MODAL_EDGESLIDE_UP: {
+                                               case TFM_MODAL_EDGESLIDE_UP:
+                                               {
                                                        sld->curr_sv_index = (sld->curr_sv_index + 1) % sld->totsv;
                                                        break;
                                                }
                                                        sld->curr_sv_index = (sld->curr_sv_index + 1) % sld->totsv;
                                                        break;
                                                }
@@ -5299,15 +5602,15 @@ int handleEventEdgeSlide(struct TransInfo *t, struct wmEvent *event)
 void drawNonPropEdge(const struct bContext *C, TransInfo *t)
 {
        if (t->mode == TFM_EDGE_SLIDE) {
 void drawNonPropEdge(const struct bContext *C, TransInfo *t)
 {
        if (t->mode == TFM_EDGE_SLIDE) {
-               SlideData *sld = (SlideData *)t->customData;
+               EdgeSlideData *sld = (EdgeSlideData *)t->customData;
                /* Non-Prop mode */
                if (sld && sld->is_proportional == FALSE) {
                        View3D *v3d = CTX_wm_view3d(C);
                        float marker[3];
                        float v1[3], v2[3];
                        float interp_v;
                /* Non-Prop mode */
                if (sld && sld->is_proportional == FALSE) {
                        View3D *v3d = CTX_wm_view3d(C);
                        float marker[3];
                        float v1[3], v2[3];
                        float interp_v;
-                       TransDataSlideVert *curr_sv = &sld->sv[sld->curr_sv_index];
-                       const float ctrl_size = UI_GetThemeValuef(TH_FACEDOT_SIZE) + 1.5;
+                       TransDataEdgeSlideVert *curr_sv = &sld->sv[sld->curr_sv_index];
+                       const float ctrl_size = UI_GetThemeValuef(TH_FACEDOT_SIZE) + 1.5f;
                        const float guide_size = ctrl_size - 0.5f;
                        const float line_size = UI_GetThemeValuef(TH_OUTLINE_WIDTH) + 0.5f;
                        const int alpha_shade = -30;
                        const float guide_size = ctrl_size - 0.5f;
                        const float line_size = UI_GetThemeValuef(TH_OUTLINE_WIDTH) + 0.5f;
                        const int alpha_shade = -30;
@@ -5372,52 +5675,61 @@ void drawNonPropEdge(const struct bContext *C, TransInfo *t)
 
 static int doEdgeSlide(TransInfo *t, float perc)
 {
 
 static int doEdgeSlide(TransInfo *t, float perc)
 {
-       SlideData *sld = t->customData;
-       TransDataSlideVert *svlist = sld->sv, *sv;
-       float vec[3];
+       EdgeSlideData *sld = t->customData;
+       TransDataEdgeSlideVert *svlist = sld->sv, *sv;
        int i;
 
        sld->perc = perc;
        int i;
 
        sld->perc = perc;
-
        sv = svlist;
        sv = svlist;
-       for (i = 0; i < sld->totsv; i++, sv++) {
-               if (sld->is_proportional == FALSE) {
-                       TransDataSlideVert *curr_sv = &sld->sv[sld->curr_sv_index];
-                       float cur_sel = curr_sv->edge_len;
-                       float cur_sv = sv->edge_len;
-                       float extd = 0.0f;
-                       float recip_cur_sv = 0.0f;
 
 
-                       if (cur_sel == 0.0f) cur_sel = 1.0f;
-                       if (cur_sv == 0.0f) cur_sv = 1.0f;
-
-                       recip_cur_sv = 1.0f / cur_sv;
-
-                       if (!sld->flipped_vtx) {
-                               extd = (cur_sv - cur_sel) * recip_cur_sv;
+       if (sld->is_proportional == TRUE) {
+               for (i = 0; i < sld->totsv; i++, sv++) {
+                       float vec[3];
+                       if (perc > 0.0f) {
+                               copy_v3_v3(vec, sv->upvec);
+                               mul_v3_fl(vec, perc);
+                               add_v3_v3v3(sv->v->co, sv->origvert.co, vec);
                        }
                        else {
                        }
                        else {
-                               extd = (cur_sel - cur_sv) * recip_cur_sv;
+                               copy_v3_v3(vec, sv->downvec);
+                               mul_v3_fl(vec, -perc);
+                               add_v3_v3v3(sv->v->co, sv->origvert.co, vec);
                        }
                        }
-
-                       extd += (sld->perc * cur_sel) * recip_cur_sv;
-                       CLAMP(extd, -1.0f, 1.0f);
-                       perc = extd;
                }
                }
+       }
+       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
+                * their original path (which may not be straight), however how it works now is OK and matches 2.4x - Campbell
+                *
+                * \note len_v3v3(curr_sv->upvec, curr_sv->downvec)
+                * is the same as the distance between the original vert locations, same goes for the lines below.
+                */
+               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);
 
 
-               if (perc > 0.0f) {
-                       copy_v3_v3(vec, sv->upvec);
-                       mul_v3_fl(vec, perc);
-                       add_v3_v3v3(sv->v->co, sv->origvert.co, vec);
-               }
-               else {
-                       copy_v3_v3(vec, sv->downvec);
-                       mul_v3_fl(vec, -perc);
-                       add_v3_v3v3(sv->v->co, sv->origvert.co, vec);
+               float down_co[3];
+               float up_co[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);
+
+                               if (sld->flipped_vtx) {
+                                       interp_v3_v3v3(sv->v->co, down_co, up_co, fac);
+                               }
+                               else {
+                                       interp_v3_v3v3(sv->v->co, up_co, down_co, fac);
+                               }
+                       }
                }
        }
        
                }
        }
        
-       projectSVData(t, 0);
+       projectEdgeSlideData(t, 0);
        
        return 1;
 }
        
        return 1;
 }
@@ -5426,7 +5738,7 @@ int EdgeSlide(TransInfo *t, const int UNUSED(mval[2]))
 {
        char str[128];
        float final;
 {
        char str[128];
        float final;
-       SlideData *sld =  t->customData;
+       EdgeSlideData *sld =  t->customData;
        int flipped = sld->flipped_vtx;
        int is_proportional = sld->is_proportional;
 
        int flipped = sld->flipped_vtx;
        int is_proportional = sld->is_proportional;
 
@@ -5438,7 +5750,7 @@ int EdgeSlide(TransInfo *t, const int UNUSED(mval[2]))
        CLAMP(final, -1.0f, 1.0f);
 
        if (hasNumInput(&t->num)) {
        CLAMP(final, -1.0f, 1.0f);
 
        if (hasNumInput(&t->num)) {
-               char c[20];
+               char c[NUM_STR_REP_LEN];
 
                applyNumInput(&t->num, &final);
 
 
                applyNumInput(&t->num, &final);
 
@@ -5504,7 +5816,7 @@ int BoneRoll(TransInfo *t, const int UNUSED(mval[2]))
        snapGrid(t, &final);
 
        if (hasNumInput(&t->num)) {
        snapGrid(t, &final);
 
        if (hasNumInput(&t->num)) {
-               char c[20];
+               char c[NUM_STR_REP_LEN];
 
                applyNumInput(&t->num, &final);
 
 
                applyNumInput(&t->num, &final);
 
@@ -5576,7 +5888,7 @@ int BakeTime(TransInfo *t, const int mval[2])
 
        /* header print for NumInput */
        if (hasNumInput(&t->num)) {
 
        /* header print for NumInput */
        if (hasNumInput(&t->num)) {
-               char c[20];
+               char c[NUM_STR_REP_LEN];
 
                outputNumInput(&(t->num), c);
 
 
                outputNumInput(&(t->num), c);
 
@@ -5769,7 +6081,7 @@ void initSeqSlide(TransInfo *t)
 
 static void headerSeqSlide(TransInfo *t, float val[2], char *str)
 {
 
 static void headerSeqSlide(TransInfo *t, float val[2], char *str)
 {
-       char tvec[60];
+       char tvec[NUM_STR_REP_LEN * 3];
 
        if (hasNumInput(&t->num)) {
                outputNumInput(&(t->num), tvec);
 
        if (hasNumInput(&t->num)) {
                outputNumInput(&(t->num), tvec);
@@ -5902,7 +6214,7 @@ static short getAnimEdit_DrawTime(TransInfo *t)
                SpaceIpo *sipo = (SpaceIpo *)t->sa->spacedata.first;
                
                drawtime = (sipo->flag & SIPO_DRAWTIME) ? 1 : 0;
                SpaceIpo *sipo = (SpaceIpo *)t->sa->spacedata.first;
                
                drawtime = (sipo->flag & SIPO_DRAWTIME) ? 1 : 0;
-       }       
+       }
        else {
                drawtime = 0;
        }
        else {
                drawtime = 0;
        }
@@ -6012,7 +6324,7 @@ void initTimeTranslate(TransInfo *t)
 
 static void headerTimeTranslate(TransInfo *t, char *str)
 {
 
 static void headerTimeTranslate(TransInfo *t, char *str)
 {
-       char tvec[60];
+       char tvec[NUM_STR_REP_LEN * 3];
 
        /* if numeric input is active, use results from that, otherwise apply snapping to result */
        if (hasNumInput(&t->num)) {
 
        /* if numeric input is active, use results from that, otherwise apply snapping to result */
        if (hasNumInput(&t->num)) {
@@ -6167,7 +6479,7 @@ void initTimeSlide(TransInfo *t)
 
 static void headerTimeSlide(TransInfo *t, float sval, char *str)
 {
 
 static void headerTimeSlide(TransInfo *t, float sval, char *str)
 {
-       char tvec[60];
+       char tvec[NUM_STR_REP_LEN * 3];
 
        if (hasNumInput(&t->num)) {
                outputNumInput(&(t->num), tvec);
 
        if (hasNumInput(&t->num)) {
                outputNumInput(&(t->num), tvec);
@@ -6309,7 +6621,7 @@ void initTimeScale(TransInfo *t)
 
 static void headerTimeScale(TransInfo *t, char *str)
 {
 
 static void headerTimeScale(TransInfo *t, char *str)
 {
-       char tvec[60];
+       char tvec[NUM_STR_REP_LEN * 3];
 
        if (hasNumInput(&t->num))
                outputNumInput(&(t->num), tvec);
 
        if (hasNumInput(&t->num))
                outputNumInput(&(t->num), tvec);
@@ -6383,5 +6695,5 @@ int TimeScale(TransInfo *t, const int UNUSED(mval[2]))
 void BIF_TransformSetUndo(const char *UNUSED(str))
 {
        // TRANSFORM_FIX_ME
 void BIF_TransformSetUndo(const char *UNUSED(str))
 {
        // TRANSFORM_FIX_ME
-       //Trans.undostr= str;
+       //Trans.undostr = str;
 }
 }