Merge branch 'master' into blender2.8
[blender.git] / source / blender / editors / transform / transform.c
index 69e8ebf5ca45eb8ba3ac64aabbbf5323df4e959d..405c621301743762c56e278bd9e39e2e9983b896 100644 (file)
@@ -43,6 +43,7 @@
 #include "DNA_mask_types.h"
 #include "DNA_movieclip_types.h"
 #include "DNA_scene_types.h"  /* PET modes */
+#include "DNA_workspace_types.h"
 
 #include "BLI_alloca.h"
 #include "BLI_utildefines.h"
 #include "BKE_constraint.h"
 #include "BKE_particle.h"
 #include "BKE_unit.h"
+#include "BKE_scene.h"
 #include "BKE_mask.h"
 #include "BKE_report.h"
+#include "BKE_workspace.h"
+
+#include "DEG_depsgraph.h"
 
-#include "BIF_gl.h"
 #include "BIF_glutil.h"
 
+#include "GPU_immediate.h"
+#include "GPU_immediate_util.h"
+#include "GPU_matrix.h"
+
 #include "ED_image.h"
 #include "ED_keyframing.h"
 #include "ED_screen.h"
@@ -103,7 +111,7 @@ static void drawEdgeSlide(TransInfo *t);
 static void drawVertSlide(TransInfo *t);
 static void postInputRotation(TransInfo *t, float values[3]);
 
-static void ElementRotation(TransInfo *t, TransData *td, float mat[3][3], const short around);
+static void ElementRotation(TransInfo *t, TransDataContainer *tc, TransData *td, float mat[3][3], const short around);
 static void initSnapSpatial(TransInfo *t, float r_snap[3]);
 
 
@@ -204,7 +212,8 @@ static bool transdata_check_local_center(TransInfo *t, short around)
 {
        return ((around == V3D_AROUND_LOCAL_ORIGINS) && (
                    (t->flag & (T_OBJECT | T_POSE)) ||
-                   (t->obedit && ELEM(t->obedit->type, OB_MESH, OB_CURVE, OB_MBALL, OB_ARMATURE)) ||
+                   /* implicit: (t->flag & T_EDIT) */
+                   (ELEM(t->obedit_type, OB_MESH, OB_CURVE, OB_MBALL, OB_ARMATURE)) ||
                    (t->spacetype == SPACE_IPO) ||
                    (t->options & (CTX_MOVIECLIP | CTX_MASK | CTX_PAINT_CURVE)))
                );
@@ -213,7 +222,7 @@ static bool transdata_check_local_center(TransInfo *t, short around)
 bool transdata_check_local_islands(TransInfo *t, short around)
 {
        return ((around == V3D_AROUND_LOCAL_ORIGINS) && (
-               (t->obedit && ELEM(t->obedit->type, OB_MESH))));
+               (ELEM(t->obedit_type, OB_MESH))));
 }
 
 /* ************************** SPACE DEPENDANT CODE **************************** */
@@ -238,6 +247,7 @@ void setTransformViewMatrices(TransInfo *t)
        }
 
        calculateCenter2D(t);
+       calculateCenterLocal(t, t->center_global);
 }
 
 void setTransformViewAspect(TransInfo *t, float r_aspect[3])
@@ -612,8 +622,12 @@ static void viewRedrawForce(const bContext *C, TransInfo *t)
                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);
+                       if (sima->lock) {
+                               WM_event_add_notifier(C, NC_GEOM | ND_DATA, OBEDIT_FROM_VIEW_LAYER(t->view_layer)->data);
+                       }
+                       else {
+                               ED_area_tag_redraw(t->sa);
+                       }
                }
        }
        else if (t->spacetype == SPACE_CLIP) {
@@ -1017,7 +1031,7 @@ int transformEvent(TransInfo *t, const wmEvent *event)
                                        handled = true;
                                }
                                else {
-                                       if (t->obedit && t->obedit->type == OB_MESH) {
+                                       if (t->obedit_type == OB_MESH) {
                                                if ((t->mode == TFM_TRANSLATION) && (t->spacetype == SPACE_VIEW3D)) {
                                                        restoreTransObjects(t);
                                                        resetTransModal(t);
@@ -1027,11 +1041,13 @@ int transformEvent(TransInfo *t, const wmEvent *event)
                                                        initEdgeSlide(t);
                                                        /* if that fails, do vertex slide */
                                                        if (t->state == TRANS_CANCEL) {
+                                                               resetTransModal(t);
                                                                t->state = TRANS_STARTING;
                                                                initVertSlide(t);
                                                        }
                                                        /* vert slide can fail on unconnected vertices (rare but possible) */
                                                        if (t->state == TRANS_CANCEL) {
+                                                               resetTransModal(t);
                                                                t->mode = TFM_TRANSLATION;
                                                                t->state = TRANS_STARTING;
                                                                restoreTransObjects(t);
@@ -1563,7 +1579,7 @@ bool calculateTransformCenter(bContext *C, int centerMode, float cent3d[3], floa
 
        t->around = centerMode;             // override userdefined mode
 
-       if (t->total == 0) {
+       if (t->data_len_all == 0) {
                success = false;
        }
        else {
@@ -1598,8 +1614,16 @@ typedef enum {
        LEFT,
        RIGHT
 } ArrowDirection;
+
+#define POS_INDEX 0
+/* NOTE: this --^ is a bit hackish, but simplifies Gwn_VertFormat usage among functions
+ * private to this file  - merwin
+ */
+
 static void drawArrow(ArrowDirection d, short offset, short length, short size)
 {
+       immBegin(GWN_PRIM_LINES, 6);
+
        switch (d) {
                case LEFT:
                        offset = -offset;
@@ -1607,14 +1631,12 @@ static void drawArrow(ArrowDirection d, short offset, short length, short size)
                        size = -size;
                        ATTR_FALLTHROUGH;
                case RIGHT:
-                       glBegin(GL_LINES);
-                       glVertex2s(offset, 0);
-                       glVertex2s(offset + length, 0);
-                       glVertex2s(offset + length, 0);
-                       glVertex2s(offset + length - size, -size);
-                       glVertex2s(offset + length, 0);
-                       glVertex2s(offset + length - size,  size);
-                       glEnd();
+                       immVertex2f(POS_INDEX, offset, 0);
+                       immVertex2f(POS_INDEX, offset + length, 0);
+                       immVertex2f(POS_INDEX, offset + length, 0);
+                       immVertex2f(POS_INDEX, offset + length - size, -size);
+                       immVertex2f(POS_INDEX, offset + length, 0);
+                       immVertex2f(POS_INDEX, offset + length - size,  size);
                        break;
 
                case DOWN:
@@ -1623,45 +1645,45 @@ static void drawArrow(ArrowDirection d, short offset, short length, short size)
                        size = -size;
                        ATTR_FALLTHROUGH;
                case UP:
-                       glBegin(GL_LINES);
-                       glVertex2s(0, offset);
-                       glVertex2s(0, offset + length);
-                       glVertex2s(0, offset + length);
-                       glVertex2s(-size, offset + length - size);
-                       glVertex2s(0, offset + length);
-                       glVertex2s(size, offset + length - size);
-                       glEnd();
+                       immVertex2f(POS_INDEX, 0, offset);
+                       immVertex2f(POS_INDEX, 0, offset + length);
+                       immVertex2f(POS_INDEX, 0, offset + length);
+                       immVertex2f(POS_INDEX, -size, offset + length - size);
+                       immVertex2f(POS_INDEX, 0, offset + length);
+                       immVertex2f(POS_INDEX, size, offset + length - size);
                        break;
        }
+
+       immEnd();
 }
 
 static void drawArrowHead(ArrowDirection d, short size)
 {
+       immBegin(GWN_PRIM_LINES, 4);
+
        switch (d) {
                case LEFT:
                        size = -size;
                        ATTR_FALLTHROUGH;
                case RIGHT:
-                       glBegin(GL_LINES);
-                       glVertex2s(0, 0);
-                       glVertex2s(-size, -size);
-                       glVertex2s(0, 0);
-                       glVertex2s(-size,  size);
-                       glEnd();
+                       immVertex2f(POS_INDEX, 0, 0);
+                       immVertex2f(POS_INDEX, -size, -size);
+                       immVertex2f(POS_INDEX, 0, 0);
+                       immVertex2f(POS_INDEX, -size,  size);
                        break;
 
                case DOWN:
                        size = -size;
                        ATTR_FALLTHROUGH;
                case UP:
-                       glBegin(GL_LINES);
-                       glVertex2s(0, 0);
-                       glVertex2s(-size, -size);
-                       glVertex2s(0, 0);
-                       glVertex2s(size, -size);
-                       glEnd();
+                       immVertex2f(POS_INDEX, 0, 0);
+                       immVertex2f(POS_INDEX, -size, -size);
+                       immVertex2f(POS_INDEX, 0, 0);
+                       immVertex2f(POS_INDEX, size, -size);
                        break;
        }
+
+       immEnd();
 }
 
 static void drawArc(float size, float angle_start, float angle_end, int segments)
@@ -1670,14 +1692,14 @@ static void drawArc(float size, float angle_start, float angle_end, int segments
        float angle;
        int a;
 
-       glBegin(GL_LINE_STRIP);
+       immBegin(GWN_PRIM_LINE_STRIP, segments + 1);
 
        for (angle = angle_start, a = 0; a < segments; angle += delta, a++) {
-               glVertex2f(cosf(angle) * size, sinf(angle) * size);
+               immVertex2f(POS_INDEX, cosf(angle) * size, sinf(angle) * size);
        }
-       glVertex2f(cosf(angle_end) * size, sinf(angle_end) * size);
+       immVertex2f(POS_INDEX, cosf(angle_end) * size, sinf(angle_end) * size);
 
-       glEnd();
+       immEnd();
 }
 
 static int helpline_poll(bContext *C)
@@ -1693,88 +1715,122 @@ static void drawHelpline(bContext *UNUSED(C), int x, int y, void *customdata)
 {
        TransInfo *t = (TransInfo *)customdata;
 
-       if (t->helpline != HLP_NONE && !(t->flag & T_USES_MANIPULATOR)) {
+       if (t->helpline != HLP_NONE) {
                float cent[2];
-               int mval[2];
-
-               mval[0] = x;
-               mval[1] = y;
+               float mval[3] = {
+                   x,
+                   y,
+                   0.0f,
+               };
+               float tmval[2] = {
+                   (float)t->mval[0],
+                   (float)t->mval[1],
+               };
 
                projectFloatViewEx(t, t->center_global, cent, V3D_PROJ_TEST_CLIP_ZERO);
 
-               glPushMatrix();
+               /* Offset the values for the area region. */
+               const float offset[2] = {
+                   t->ar->winrct.xmin,
+                   t->ar->winrct.ymin,
+               };
+
+               for (int i = 0; i < 2; i++) {
+                       cent[i] += offset[i];
+                       tmval[i] += offset[i];
+               }
+
+               gpuPushMatrix();
+
+               /* Dashed lines first. */
+               if (ELEM(t->helpline, HLP_SPRING, HLP_ANGLE)) {
+                       const uint shdr_pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+
+                       UNUSED_VARS_NDEBUG(shdr_pos); /* silence warning */
+                       BLI_assert(shdr_pos == POS_INDEX);
+
+                       glLineWidth(1.0f);
+
+                       immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
+
+                       float viewport_size[4];
+                       glGetFloatv(GL_VIEWPORT, viewport_size);
+                       immUniform2f("viewport_size", viewport_size[2], viewport_size[3]);
+
+                       immUniform1i("num_colors", 0);  /* "simple" mode */
+                       immUniformThemeColor(TH_VIEW_OVERLAY);
+                       immUniform1f("dash_width", 6.0f);
+                       immUniform1f("dash_factor", 0.5f);
+
+                       immBegin(GWN_PRIM_LINES, 2);
+                       immVertex2fv(POS_INDEX, cent);
+                       immVertex2f(POS_INDEX, tmval[0], tmval[1]);
+                       immEnd();
+
+                       immUnbindProgram();
+               }
+
+               /* And now, solid lines. */
+               unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+               UNUSED_VARS_NDEBUG(pos); /* silence warning */
+               BLI_assert(pos == POS_INDEX);
+               immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
 
                switch (t->helpline) {
                        case HLP_SPRING:
-                               UI_ThemeColor(TH_VIEW_OVERLAY);
+                               immUniformThemeColor(TH_VIEW_OVERLAY);
 
-                               setlinestyle(3);
-                               glLineWidth(1);
-                               glBegin(GL_LINES);
-                               glVertex2iv(t->mval);
-                               glVertex2fv(cent);
-                               glEnd();
+                               gpuTranslate3fv(mval);
+                               gpuRotateAxis(-RAD2DEGF(atan2f(cent[0] - tmval[0], cent[1] - tmval[1])), 'Z');
 
-                               glTranslate2iv(mval);
-                               glRotatef(-RAD2DEGF(atan2f(cent[0] - t->mval[0], cent[1] - t->mval[1])), 0, 0, 1);
-
-                               setlinestyle(0);
-                               glLineWidth(3.0);
+                               glLineWidth(3.0f);
                                drawArrow(UP, 5, 10, 5);
                                drawArrow(DOWN, 5, 10, 5);
                                break;
                        case HLP_HARROW:
-                               UI_ThemeColor(TH_VIEW_OVERLAY);
-
-                               glTranslate2iv(mval);
+                               immUniformThemeColor(TH_VIEW_OVERLAY);
+                               gpuTranslate3fv(mval);
 
-                               glLineWidth(3.0);
+                               glLineWidth(3.0f);
                                drawArrow(RIGHT, 5, 10, 5);
                                drawArrow(LEFT, 5, 10, 5);
                                break;
                        case HLP_VARROW:
-                               UI_ThemeColor(TH_VIEW_OVERLAY);
+                               immUniformThemeColor(TH_VIEW_OVERLAY);
 
-                               glTranslate2iv(mval);
+                               gpuTranslate3fv(mval);
 
-                               glLineWidth(3.0);
+                               glLineWidth(3.0f);
                                drawArrow(UP, 5, 10, 5);
                                drawArrow(DOWN, 5, 10, 5);
                                break;
                        case HLP_ANGLE:
                        {
-                               float dx = t->mval[0] - cent[0], dy = t->mval[1] - cent[1];
+                               float dx = tmval[0] - cent[0], dy = tmval[1] - cent[1];
                                float angle = atan2f(dy, dx);
                                float dist = hypotf(dx, dy);
                                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_VIEW_OVERLAY);
 
-                               setlinestyle(3);
-                               glLineWidth(1);
-                               glBegin(GL_LINES);
-                               glVertex2iv(t->mval);
-                               glVertex2fv(cent);
-                               glEnd();
+                               immUniformThemeColor(TH_VIEW_OVERLAY);
 
-                               glTranslatef(cent[0] - t->mval[0] + mval[0], cent[1] - t->mval[1] + mval[1], 0);
+                               gpuTranslate3f(cent[0] - tmval[0] + mval[0], cent[1] - tmval[1] + mval[1], 0);
 
-                               setlinestyle(0);
-                               glLineWidth(3.0);
+                               glLineWidth(3.0f);
                                drawArc(dist, angle - delta_angle, angle - spacing_angle, 10);
                                drawArc(dist, angle + spacing_angle, angle + delta_angle, 10);
 
-                               glPushMatrix();
+                               gpuPushMatrix();
 
-                               glTranslatef(cosf(angle - delta_angle) * dist, sinf(angle - delta_angle) * dist, 0);
-                               glRotatef(RAD2DEGF(angle - delta_angle), 0, 0, 1);
+                               gpuTranslate3f(cosf(angle - delta_angle) * dist, sinf(angle - delta_angle) * dist, 0);
+                               gpuRotateAxis(RAD2DEGF(angle - delta_angle), 'Z');
 
                                drawArrowHead(DOWN, 5);
 
-                               glPopMatrix();
+                               gpuPopMatrix();
 
-                               glTranslatef(cosf(angle + delta_angle) * dist, sinf(angle + delta_angle) * dist, 0);
-                               glRotatef(RAD2DEGF(angle + delta_angle), 0, 0, 1);
+                               gpuTranslate3f(cosf(angle + delta_angle) * dist, sinf(angle + delta_angle) * dist, 0);
+                               gpuRotateAxis(RAD2DEGF(angle + delta_angle), 'Z');
 
                                drawArrowHead(UP, 5);
                                break;
@@ -1784,18 +1840,18 @@ static void drawHelpline(bContext *UNUSED(C), int x, int y, void *customdata)
                                unsigned char col[3], col2[3];
                                UI_GetThemeColor3ubv(TH_GRID, col);
 
-                               glTranslate2iv(mval);
+                               gpuTranslate3fv(mval);
 
-                               glLineWidth(3.0);
+                               glLineWidth(3.0f);
 
                                UI_make_axis_color(col, col2, 'X');
-                               glColor3ubv((GLubyte *)col2);
+                               immUniformColor3ubv((GLubyte *)col2);
 
                                drawArrow(RIGHT, 5, 10, 5);
                                drawArrow(LEFT, 5, 10, 5);
 
                                UI_make_axis_color(col, col2, 'Y');
-                               glColor3ubv((GLubyte *)col2);
+                               immUniformColor3ubv((GLubyte *)col2);
 
                                drawArrow(UP, 5, 10, 5);
                                drawArrow(DOWN, 5, 10, 5);
@@ -1803,7 +1859,8 @@ static void drawHelpline(bContext *UNUSED(C), int x, int y, void *customdata)
                        }
                }
 
-               glPopMatrix();
+               immUnbindProgram();
+               gpuPopMatrix();
        }
 }
 
@@ -1811,7 +1868,7 @@ static void drawTransformView(const struct bContext *C, ARegion *UNUSED(ar), voi
 {
        TransInfo *t = arg;
 
-       glLineWidth(1.0);
+       glLineWidth(1.0f);
 
        drawConstraint(t);
        drawPropCircle(C, t);
@@ -1832,7 +1889,8 @@ static void drawAutoKeyWarning(TransInfo *UNUSED(t), ARegion *ar)
 
        ED_region_visible_rect(ar, &rect);
 
-       BLF_width_and_height_default(printable, BLF_DRAW_STR_DUMMY_MAX, &printable_size[0], &printable_size[1]);
+       const int font_id = BLF_default();
+       BLF_width_and_height(font_id, printable, BLF_DRAW_STR_DUMMY_MAX, &printable_size[0], &printable_size[1]);
 
        xco = (rect.xmax - U.widget_unit) - (int)printable_size[0];
        yco = (rect.ymax - U.widget_unit);
@@ -1840,7 +1898,9 @@ static void drawAutoKeyWarning(TransInfo *UNUSED(t), ARegion *ar)
        /* 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);
+       unsigned char color[3];
+       UI_GetThemeColorShade3ubv(TH_TEXT_HI, -50, color);
+       BLF_color3ubv(font_id, color);
 #ifdef WITH_INTERNATIONAL
        BLF_draw_default(xco, yco, 0.0f, printable, BLF_DRAW_STR_DUMMY_MAX);
 #else
@@ -1848,7 +1908,7 @@ static void drawAutoKeyWarning(TransInfo *UNUSED(t), ARegion *ar)
 #endif
 
        /* autokey recording icon... */
-       glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+       glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
        glEnable(GL_BLEND);
 
        xco -= U.widget_unit;
@@ -1863,7 +1923,8 @@ static void drawTransformPixel(const struct bContext *UNUSED(C), ARegion *ar, vo
 {
        TransInfo *t = arg;
        Scene *scene = t->scene;
-       Object *ob = OBACT;
+       ViewLayer *view_layer = t->view_layer;
+       Object *ob = OBACT(view_layer);
 
        /* draw autokeyframing hint in the corner
         * - only draw if enabled (advanced users may be distracted/annoyed),
@@ -1938,7 +1999,7 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op)
                                        ts->proportional_fcurve = proportional;
                                else if (t->spacetype == SPACE_ACTION)
                                        ts->proportional_action = proportional;
-                               else if (t->obedit)
+                               else if (t->obedit_type != -1)
                                        ts->proportional = proportional;
                                else if (t->options & CTX_MASK)
                                        ts->proportional_mask = (proportional != PROP_EDIT_OFF);
@@ -1970,9 +2031,10 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op)
                        if ((prop = RNA_struct_find_property(op->ptr, "constraint_orientation")) &&
                            !RNA_property_is_set(op->ptr, prop))
                        {
-                               View3D *v3d = t->view;
-
-                               v3d->twmode = t->current_orientation;
+                               t->scene->orientation_type = t->current_orientation;
+                               BLI_assert(((t->scene->orientation_index_custom == -1) && (t->custom_orientation == NULL)) ||
+                                          (BKE_scene_transform_orientation_get_index(
+                                                   t->scene, t->custom_orientation) == t->scene->orientation_index_custom));
                        }
                }
        }
@@ -1992,15 +2054,19 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op)
        }
 
        if ((prop = RNA_struct_find_property(op->ptr, "constraint_axis"))) {
-               /* constraint orientation can be global, event if user selects something else
-                * so use the orientation in the constraint if set
-                * */
-               if (t->con.mode & CON_APPLY) {
-                       RNA_enum_set(op->ptr, "constraint_orientation", t->con.orientation);
-               }
-               else {
-                       RNA_enum_set(op->ptr, "constraint_orientation", t->current_orientation);
+               /* constraint orientation can be global, even if user selects something else
+                * so use the orientation in the constraint if set */
+               short orientation = (t->con.mode & CON_APPLY) ? t->con.orientation : t->current_orientation;
+
+               if (orientation == V3D_MANIP_CUSTOM) {
+                       const int orientation_index_custom = BKE_scene_transform_orientation_get_index(
+                               t->scene, t->custom_orientation);
+
+                       /* Maybe we need a t->con.custom_orientation? Seems like it would always match t->custom_orientation. */
+                       orientation = V3D_MANIP_CUSTOM + orientation_index_custom;
+                       BLI_assert(orientation >= V3D_MANIP_CUSTOM);
                }
+               RNA_enum_set(op->ptr, "constraint_orientation", orientation);
 
                if (t->con.mode & CON_APPLY) {
                        if (t->con.mode & CON_AXIS0) {
@@ -2119,7 +2185,7 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
 
        createTransData(C, t);          // make TransData structs from selection
 
-       if (t->total == 0) {
+       if (t->data_len_all == 0) {
                postTrans(C, t);
                return 0;
        }
@@ -2164,6 +2230,63 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
        calculatePropRatio(t);
        calculateCenter(t);
 
+       /* Overwrite initial values if operator supplied a non-null vector.
+        *
+        * Run before init functions so 'values_modal_offset' can be applied on mouse input.
+        */
+       BLI_assert(is_zero_v4(t->values_modal_offset));
+       if ((prop = RNA_struct_find_property(op->ptr, "value")) && RNA_property_is_set(op->ptr, prop)) {
+               float values[4] = {0}; /* in case value isn't length 4, avoid uninitialized memory  */
+
+               if (RNA_property_array_check(prop)) {
+                       RNA_float_get_array(op->ptr, "value", values);
+               }
+               else {
+                       values[0] = RNA_float_get(op->ptr, "value");
+               }
+
+               copy_v4_v4(t->values, values);
+
+               if (t->flag & T_MODAL) {
+                       copy_v4_v4(t->values_modal_offset, values);
+                       t->redraw = TREDRAW_HARD;
+               }
+               else {
+                       copy_v4_v4(t->auto_values, values);
+                       t->flag |= T_AUTOVALUES;
+               }
+       }
+
+       /* Transformation axis from operator */
+       if ((prop = RNA_struct_find_property(op->ptr, "axis")) && RNA_property_is_set(op->ptr, prop)) {
+               RNA_property_float_get_array(op->ptr, prop, t->axis);
+               normalize_v3(t->axis);
+               copy_v3_v3(t->axis_orig, t->axis);
+       }
+
+       /* Constraint init from operator */
+       if ((prop = RNA_struct_find_property(op->ptr, "constraint_axis")) && RNA_property_is_set(op->ptr, prop)) {
+               int constraint_axis[3];
+
+               RNA_property_boolean_get_array(op->ptr, prop, constraint_axis);
+
+               if (constraint_axis[0] || constraint_axis[1] || constraint_axis[2]) {
+                       t->con.mode |= CON_APPLY;
+
+                       if (constraint_axis[0]) {
+                               t->con.mode |= CON_AXIS0;
+                       }
+                       if (constraint_axis[1]) {
+                               t->con.mode |= CON_AXIS1;
+                       }
+                       if (constraint_axis[2]) {
+                               t->con.mode |= CON_AXIS2;
+                       }
+
+                       setUserConstraint(t, t->current_orientation, t->con.mode, "%s");
+               }
+       }
+
        if (event) {
                /* Initialize accurate transform to settings requested by keymap. */
                bool use_accurate = false;
@@ -2223,7 +2346,9 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
                        break;
                case TFM_BONESIZE:
                {   /* used for both B-Bone width (bonesize) as for deform-dist (envelope) */
-                       bArmature *arm = t->poseobj->data;
+                       /* Note: we have to pick one, use the active object. */
+                       TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_OK(t);
+                       bArmature *arm = tc->poseobj->data;
                        if (arm->drawtype == ARM_ENVELOPE) {
                                initBoneEnvelope(t);
                                t->mode = TFM_BONE_ENVELOPE_DIST;
@@ -2310,55 +2435,6 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
                return 0;
        }
 
-       /* Transformation axis from operator */
-       if ((prop = RNA_struct_find_property(op->ptr, "axis")) && RNA_property_is_set(op->ptr, prop)) {
-               RNA_property_float_get_array(op->ptr, prop, t->axis);
-               normalize_v3(t->axis);
-               copy_v3_v3(t->axis_orig, t->axis);
-       }
-
-       /* Constraint init from operator */
-       if ((prop = RNA_struct_find_property(op->ptr, "constraint_axis")) && RNA_property_is_set(op->ptr, prop)) {
-               int constraint_axis[3];
-
-               RNA_property_boolean_get_array(op->ptr, prop, constraint_axis);
-
-               if (constraint_axis[0] || constraint_axis[1] || constraint_axis[2]) {
-                       t->con.mode |= CON_APPLY;
-
-                       if (constraint_axis[0]) {
-                               t->con.mode |= CON_AXIS0;
-                       }
-                       if (constraint_axis[1]) {
-                               t->con.mode |= CON_AXIS1;
-                       }
-                       if (constraint_axis[2]) {
-                               t->con.mode |= CON_AXIS2;
-                       }
-
-                       setUserConstraint(t, t->current_orientation, t->con.mode, "%s");
-               }
-       }
-
-       /* overwrite initial values if operator supplied a non-null vector
-        *
-        * keep last so we can apply the constraints space.
-        */
-       if ((prop = RNA_struct_find_property(op->ptr, "value")) && RNA_property_is_set(op->ptr, prop)) {
-               float values[4] = {0}; /* in case value isn't length 4, avoid uninitialized memory  */
-
-               if (RNA_property_array_check(prop)) {
-                       RNA_float_get_array(op->ptr, "value", values);
-               }
-               else {
-                       values[0] = RNA_float_get(op->ptr, "value");
-               }
-
-               copy_v4_v4(t->values, values);
-               copy_v4_v4(t->auto_values, values);
-               t->flag |= T_AUTOVALUES;
-       }
-
        t->context = NULL;
 
        return 1;
@@ -2621,7 +2697,7 @@ static void constraintTransLim(TransInfo *t, TransData *td)
                                }
 
                                /* get constraint targets if needed */
-                               BKE_constraint_targets_for_solving_get(con, &cob, &targets, ctime);
+                               BKE_constraint_targets_for_solving_get(t->depsgraph, con, &cob, &targets, ctime);
 
                                /* do constraint */
                                cti->evaluate_constraint(con, &cob, &targets);
@@ -2828,6 +2904,7 @@ static void constraintSizeLim(TransInfo *t, TransData *td)
  * \{ */
 
 struct BendCustomData {
+       /* All values are in global space. */
        float warp_sta[3];
        float warp_end[3];
 
@@ -2868,23 +2945,19 @@ static void initBend(TransInfo *t)
 
        //copy_v3_v3(t->center, ED_view3d_cursor3d_get(t->scene, t->view));
        if ((t->flag & T_OVERRIDE_CENTER) == 0) {
-               calculateCenterCursor(t, t->center);
+               calculateCenterCursor(t, t->center_global);
        }
-       calculateCenterGlobal(t, t->center, t->center_global);
+       calculateCenterLocal(t, t->center_global);
 
        t->val = 0.0f;
 
        data = MEM_callocN(sizeof(*data), __func__);
 
-       curs = ED_view3d_cursor3d_get(t->scene, t->view);
+       curs = ED_view3d_cursor3d_get(t->scene, t->view)->location;
        copy_v3_v3(data->warp_sta, curs);
        ED_view3d_win_to_3d(t->sa->spacedata.first, t->ar, curs, mval_fl, data->warp_end);
 
        copy_v3_v3(data->warp_nor, t->viewinv[2]);
-       if (t->flag & T_EDIT) {
-               sub_v3_v3(data->warp_sta, t->obedit->obmat[3]);
-               sub_v3_v3(data->warp_end, t->obedit->obmat[3]);
-       }
        normalize_v3(data->warp_nor);
 
        /* tangent */
@@ -2911,10 +2984,9 @@ static eRedrawFlag handleEventBend(TransInfo *UNUSED(t), const wmEvent *event)
 
 static void Bend(TransInfo *t, const int UNUSED(mval[2]))
 {
-       TransData *td = t->data;
        float vec[3];
-       float pivot[3];
-       float warp_end_radius[3];
+       float pivot_global[3];
+       float warp_end_radius_global[3];
        int i;
        char str[UI_MAX_DRAW_STR];
        const struct BendCustomData *data = t->custom.mode.data;
@@ -2969,64 +3041,87 @@ static void Bend(TransInfo *t, const int UNUSED(mval[2]))
        values.scale *= data->warp_init_dist;
 
        /* calc 'data->warp_end' from 'data->warp_end_init' */
-       copy_v3_v3(warp_end_radius, data->warp_end);
-       dist_ensure_v3_v3fl(warp_end_radius, data->warp_sta, values.scale);
+       copy_v3_v3(warp_end_radius_global, data->warp_end);
+       dist_ensure_v3_v3fl(warp_end_radius_global, data->warp_sta, values.scale);
        /* done */
 
        /* calculate pivot */
-       copy_v3_v3(pivot, data->warp_sta);
+       copy_v3_v3(pivot_global, data->warp_sta);
        if (values.angle > 0.0f) {
-               madd_v3_v3fl(pivot, data->warp_tan, -values.scale * shell_angle_to_dist((float)M_PI_2 - values.angle));
+               madd_v3_v3fl(pivot_global, data->warp_tan, -values.scale * shell_angle_to_dist((float)M_PI_2 - values.angle));
        }
        else {
-               madd_v3_v3fl(pivot, data->warp_tan, +values.scale * shell_angle_to_dist((float)M_PI_2 + values.angle));
+               madd_v3_v3fl(pivot_global, data->warp_tan, +values.scale * shell_angle_to_dist((float)M_PI_2 + values.angle));
        }
 
-       for (i = 0; i < t->total; i++, td++) {
-               float mat[3][3];
-               float delta[3];
-               float fac, fac_scaled;
-
-               if (td->flag & TD_NOACTION)
-                       break;
+       /* TODO(campbell): xform, compensate object center. */
+       FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+               TransData *td = tc->data;
 
-               if (td->flag & TD_SKIP)
-                       continue;
+               float warp_sta_local[3];
+               float warp_end_local[3];
+               float warp_end_radius_local[3];
+               float pivot_local[3];
 
-               if (UNLIKELY(values.angle == 0.0f)) {
-                       copy_v3_v3(td->loc, td->iloc);
-                       continue;
+               if (tc->use_local_mat) {
+                       sub_v3_v3v3(warp_sta_local, data->warp_sta, tc->mat[3]);
+                       sub_v3_v3v3(warp_end_local, data->warp_end, tc->mat[3]);
+                       sub_v3_v3v3(warp_end_radius_local, warp_end_radius_global, tc->mat[3]);
+                       sub_v3_v3v3(pivot_local, pivot_global, tc->mat[3]);
+               }
+               else {
+                       copy_v3_v3(warp_sta_local, data->warp_sta);
+                       copy_v3_v3(warp_end_local, data->warp_end);
+                       copy_v3_v3(warp_end_radius_local, warp_end_radius_global);
+                       copy_v3_v3(pivot_local, pivot_global);
                }
 
-               copy_v3_v3(vec, td->iloc);
-               mul_m3_v3(td->mtx, vec);
+               for (i = 0; i < tc->data_len; i++, td++) {
+                       float mat[3][3];
+                       float delta[3];
+                       float fac, fac_scaled;
 
-               fac = line_point_factor_v3(vec, data->warp_sta, warp_end_radius);
-               if (is_clamp) {
-                       CLAMP(fac, 0.0f, 1.0f);
-               }
+                       if (td->flag & TD_NOACTION)
+                               break;
+
+                       if (td->flag & TD_SKIP)
+                               continue;
 
-               fac_scaled = fac * td->factor;
-               axis_angle_normalized_to_mat3(mat, data->warp_nor, values.angle * fac_scaled);
-               interp_v3_v3v3(delta, data->warp_sta, warp_end_radius, fac_scaled);
-               sub_v3_v3(delta, data->warp_sta);
+                       if (UNLIKELY(values.angle == 0.0f)) {
+                               copy_v3_v3(td->loc, td->iloc);
+                               continue;
+                       }
 
-               /* delta is subtracted, rotation adds back this offset */
-               sub_v3_v3(vec, delta);
+                       copy_v3_v3(vec, td->iloc);
+                       mul_m3_v3(td->mtx, vec);
+
+                       fac = line_point_factor_v3(vec, warp_sta_local, warp_end_radius_local);
+                       if (is_clamp) {
+                               CLAMP(fac, 0.0f, 1.0f);
+                       }
 
-               sub_v3_v3(vec, pivot);
-               mul_m3_v3(mat, vec);
-               add_v3_v3(vec, pivot);
+                       fac_scaled = fac * td->factor;
+                       axis_angle_normalized_to_mat3(mat, data->warp_nor, values.angle * fac_scaled);
+                       interp_v3_v3v3(delta, warp_sta_local, warp_end_radius_local, fac_scaled);
+                       sub_v3_v3(delta, warp_sta_local);
 
-               mul_m3_v3(td->smtx, vec);
+                       /* delta is subtracted, rotation adds back this offset */
+                       sub_v3_v3(vec, delta);
 
-               /* rotation */
-               if ((t->flag & T_POINTS) == 0) {
-                       ElementRotation(t, td, mat, V3D_AROUND_LOCAL_ORIGINS);
-               }
+                       sub_v3_v3(vec, pivot_local);
+                       mul_m3_v3(mat, vec);
+                       add_v3_v3(vec, pivot_local);
+
+                       mul_m3_v3(td->smtx, vec);
+
+                       /* rotation */
+                       if ((t->flag & T_POINTS) == 0) {
+                               ElementRotation(t, tc, td, mat, V3D_AROUND_LOCAL_ORIGINS);
+                       }
 
-               /* location */
-               copy_v3_v3(td->loc, vec);
+                       /* location */
+                       copy_v3_v3(td->loc, vec);
+               }
        }
 
        recalcData(t);
@@ -3099,7 +3194,6 @@ static eRedrawFlag handleEventShear(TransInfo *t, const wmEvent *event)
 
 static void applyShear(TransInfo *t, const int UNUSED(mval[2]))
 {
-       TransData *td = t->data;
        float vec[3];
        float smat[3][3], tmat[3][3], totmat[3][3], persmat[3][3], persinv[3][3];
        float value;
@@ -3142,43 +3236,46 @@ static void applyShear(TransInfo *t, const int UNUSED(mval[2]))
        mul_m3_m3m3(tmat, smat, persmat);
        mul_m3_m3m3(totmat, persinv, tmat);
 
-       for (i = 0; i < t->total; i++, td++) {
-               const float *center, *co;
+       FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+               TransData *td = tc->data;
+               for (i = 0; i < tc->data_len; i++, td++) {
+                       const float *center, *co;
 
-               if (td->flag & TD_NOACTION)
-                       break;
+                       if (td->flag & TD_NOACTION)
+                               break;
 
-               if (td->flag & TD_SKIP)
-                       continue;
+                       if (td->flag & TD_SKIP)
+                               continue;
 
-               if (t->obedit) {
-                       float mat3[3][3];
-                       mul_m3_m3m3(mat3, totmat, td->mtx);
-                       mul_m3_m3m3(tmat, td->smtx, mat3);
-               }
-               else {
-                       copy_m3_m3(tmat, totmat);
-               }
+                       if (t->flag & T_EDIT) {
+                               float mat3[3][3];
+                               mul_m3_m3m3(mat3, totmat, td->mtx);
+                               mul_m3_m3m3(tmat, td->smtx, mat3);
+                       }
+                       else {
+                               copy_m3_m3(tmat, totmat);
+                       }
 
-               if (is_local_center) {
-                       center = td->center;
-                       co = td->loc;
-               }
-               else {
-                       center = t->center;
-                       co = td->center;
-               }
+                       if (is_local_center) {
+                               center = td->center;
+                               co = td->loc;
+                       }
+                       else {
+                               center = tc->center_local;
+                               co = td->center;
+                       }
 
-               sub_v3_v3v3(vec, co, center);
+                       sub_v3_v3v3(vec, co, center);
 
-               mul_m3_v3(tmat, vec);
+                       mul_m3_v3(tmat, vec);
 
-               add_v3_v3(vec, center);
-               sub_v3_v3(vec, co);
+                       add_v3_v3(vec, center);
+                       sub_v3_v3(vec, co);
 
-               mul_v3_fl(vec, td->factor);
+                       mul_v3_fl(vec, td->factor);
 
-               add_v3_v3v3(td->loc, td->iloc, vec);
+                       add_v3_v3v3(td->loc, td->iloc, vec);
+               }
        }
 
        recalcData(t);
@@ -3206,7 +3303,7 @@ static void initResize(TransInfo *t)
        t->num.val_flag[1] |= NUM_NULL_ONE;
        t->num.val_flag[2] |= NUM_NULL_ONE;
        t->num.flag |= NUM_AFFECT_ALL;
-       if (!t->obedit) {
+       if ((t->flag & T_EDIT) == 0) {
                t->flag |= T_NO_ZERO;
 #ifdef USE_NUM_NO_ZERO
                t->num.val_flag[0] |= NUM_NO_ZERO;
@@ -3290,7 +3387,7 @@ static void TransMat3ToSize(float mat[3][3], float smat[3][3], float size[3])
        if (dot_v3v3(rmat[2], smat[2]) < 0.0f) size[2] = -size[2];
 }
 
-static void ElementResize(TransInfo *t, TransData *td, float mat[3][3])
+static void ElementResize(TransInfo *t, TransDataContainer *tc, TransData *td, float mat[3][3])
 {
        float tmat[3][3], smat[3][3], center[3];
        float vec[3];
@@ -3304,7 +3401,7 @@ static void ElementResize(TransInfo *t, TransData *td, float mat[3][3])
        }
 
        if (t->con.applySize) {
-               t->con.applySize(t, td, tmat);
+               t->con.applySize(t, tc, td, tmat);
        }
 
        /* local constraint shouldn't alter center */
@@ -3316,11 +3413,11 @@ static void ElementResize(TransInfo *t, TransData *td, float mat[3][3])
                        copy_v3_v3(center, td->center);
                }
                else {
-                       copy_v3_v3(center, t->center);
+                       copy_v3_v3(center, tc->center_local);
                }
        }
        else {
-               copy_v3_v3(center, t->center);
+               copy_v3_v3(center, tc->center_local);
        }
 
        if (td->ext) {
@@ -3391,9 +3488,8 @@ static void ElementResize(TransInfo *t, TransData *td, float mat[3][3])
        constraintTransLim(t, td);
 }
 
-static void applyResize(TransInfo *t, const int mval[2])
+static void applyResize(TransInfo *t, const int UNUSED(mval[2]))
 {
-       TransData *td;
        float mat[3][3];
        int i;
        char str[UI_MAX_DRAW_STR];
@@ -3402,15 +3498,7 @@ static void applyResize(TransInfo *t, const int mval[2])
                copy_v3_v3(t->values, t->auto_values);
        }
        else {
-               float ratio;
-
-               /* for manipulator, center handle, the scaling can't be done relative to center */
-               if ((t->flag & T_USES_MANIPULATOR) && t->con.mode == 0) {
-                       ratio = 1.0f - ((t->mouse.imval[0] - mval[0]) + (t->mouse.imval[1] - mval[1])) / 100.0f;
-               }
-               else {
-                       ratio = t->values[0];
-               }
+               float ratio = t->values[0];
 
                copy_v3_fl(t->values, ratio);
 
@@ -3426,21 +3514,24 @@ static void applyResize(TransInfo *t, const int mval[2])
        size_to_mat3(mat, t->values);
 
        if (t->con.applySize) {
-               t->con.applySize(t, NULL, mat);
+               t->con.applySize(t, NULL, NULL, mat);
        }
 
        copy_m3_m3(t->mat, mat);    // used in manipulator
 
        headerResize(t, t->values, str);
 
-       for (i = 0, td = t->data; i < t->total; i++, td++) {
-               if (td->flag & TD_NOACTION)
-                       break;
+       FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+               TransData *td = tc->data;
+               for (i = 0; i < tc->data_len; i++, td++) {
+                       if (td->flag & TD_NOACTION)
+                               break;
 
-               if (td->flag & TD_SKIP)
-                       continue;
+                       if (td->flag & TD_SKIP)
+                               continue;
 
-               ElementResize(t, td, mat);
+                       ElementResize(t, tc, td, mat);
+               }
        }
 
        /* evil hack - redo resize if cliping needed */
@@ -3448,17 +3539,21 @@ static void applyResize(TransInfo *t, const int mval[2])
                size_to_mat3(mat, t->values);
 
                if (t->con.applySize)
-                       t->con.applySize(t, NULL, mat);
+                       t->con.applySize(t, NULL, NULL, 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_ALL) {
-                       clipUVData(t);
+               FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+                       TransData *td = tc->data;
+                       for (i = 0; i < tc->data_len; i++, td++)
+                               ElementResize(t, tc, 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_ALL) {
+                               clipUVData(t);
+                       }
                }
        }
 
@@ -3487,7 +3582,7 @@ static void initSkinResize(TransInfo *t)
        t->num.val_flag[1] |= NUM_NULL_ONE;
        t->num.val_flag[2] |= NUM_NULL_ONE;
        t->num.flag |= NUM_AFFECT_ALL;
-       if (!t->obedit) {
+       if ((t->flag & T_EDIT) == 0) {
                t->flag |= T_NO_ZERO;
 #ifdef USE_NUM_NO_ZERO
                t->num.val_flag[0] |= NUM_NO_ZERO;
@@ -3511,7 +3606,6 @@ static void initSkinResize(TransInfo *t)
 
 static void applySkinResize(TransInfo *t, const int UNUSED(mval[2]))
 {
-       TransData *td;
        float size[3], mat[3][3];
        int i;
        char str[UI_MAX_DRAW_STR];
@@ -3536,31 +3630,34 @@ static void applySkinResize(TransInfo *t, const int UNUSED(mval[2]))
 
        headerResize(t, size, str);
 
-       for (i = 0, td = t->data; i < t->total; i++, td++) {
-               float tmat[3][3], smat[3][3];
-               float fsize[3];
+       FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+               TransData *td = tc->data;
+               for (i = 0; i < tc->data_len; i++, td++) {
+                       float tmat[3][3], smat[3][3];
+                       float fsize[3];
 
-               if (td->flag & TD_NOACTION)
-                       break;
+                       if (td->flag & TD_NOACTION)
+                               break;
 
-               if (td->flag & TD_SKIP)
-                       continue;
+                       if (td->flag & TD_SKIP)
+                               continue;
 
-               if (t->flag & T_EDIT) {
-                       mul_m3_m3m3(smat, mat, td->mtx);
-                       mul_m3_m3m3(tmat, td->smtx, smat);
-               }
-               else {
-                       copy_m3_m3(tmat, mat);
-               }
+                       if (t->flag & T_EDIT) {
+                               mul_m3_m3m3(smat, mat, td->mtx);
+                               mul_m3_m3m3(tmat, td->smtx, smat);
+                       }
+                       else {
+                               copy_m3_m3(tmat, mat);
+                       }
 
-               if (t->con.applySize) {
-                       t->con.applySize(t, NULL, tmat);
-               }
+                       if (t->con.applySize) {
+                               t->con.applySize(t, NULL, NULL, tmat);
+                       }
 
-               mat3_to_size(fsize, tmat);
-               td->val[0] = td->ext->isize[0] * (1 + (fsize[0] - 1) * td->factor);
-               td->val[1] = td->ext->isize[1] * (1 + (fsize[1] - 1) * td->factor);
+                       mat3_to_size(fsize, tmat);
+                       td->val[0] = td->ext->isize[0] * (1 + (fsize[0] - 1) * td->factor);
+                       td->val[1] = td->ext->isize[1] * (1 + (fsize[1] - 1) * td->factor);
+               }
        }
 
        recalcData(t);
@@ -3578,7 +3675,6 @@ static void applySkinResize(TransInfo *t, const int UNUSED(mval[2]))
 
 static void initToSphere(TransInfo *t)
 {
-       TransData *td = t->data;
        int i;
 
        t->mode = TFM_TOSPHERE;
@@ -3600,11 +3696,14 @@ static void initToSphere(TransInfo *t)
        t->flag |= T_NO_CONSTRAINT;
 
        // Calculate average radius
-       for (i = 0; i < t->total; i++, td++) {
-               t->val += len_v3v3(t->center, td->iloc);
+       FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+               TransData *td = tc->data;
+               for (i = 0; i < tc->data_len; i++, td++) {
+                       t->val += len_v3v3(tc->center_local, td->iloc);
+               }
        }
 
-       t->val /= (float)t->total;
+       t->val /= (float)t->data_len_all;
 }
 
 static void applyToSphere(TransInfo *t, const int UNUSED(mval[2]))
@@ -3613,7 +3712,6 @@ static void applyToSphere(TransInfo *t, const int UNUSED(mval[2]))
        float ratio, radius;
        int i;
        char str[UI_MAX_DRAW_STR];
-       TransData *td = t->data;
 
        ratio = t->values[0];
 
@@ -3638,27 +3736,28 @@ static void applyToSphere(TransInfo *t, const int UNUSED(mval[2]))
                BLI_snprintf(str, sizeof(str), IFACE_("To Sphere: %.4f %s"), ratio, t->proptext);
        }
 
+       FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+               TransData *td = tc->data;
+               for (i = 0; i < tc->data_len; i++, td++) {
+                       float tratio;
+                       if (td->flag & TD_NOACTION)
+                               break;
 
-       for (i = 0; i < t->total; i++, td++) {
-               float tratio;
-               if (td->flag & TD_NOACTION)
-                       break;
-
-               if (td->flag & TD_SKIP)
-                       continue;
+                       if (td->flag & TD_SKIP)
+                               continue;
 
-               sub_v3_v3v3(vec, td->iloc, t->center);
+                       sub_v3_v3v3(vec, td->iloc, tc->center_local);
 
-               radius = normalize_v3(vec);
+                       radius = normalize_v3(vec);
 
-               tratio = ratio * td->factor;
+                       tratio = ratio * td->factor;
 
-               mul_v3_fl(vec, radius * (1.0f - tratio) + t->val * tratio);
+                       mul_v3_fl(vec, radius * (1.0f - tratio) + t->val * tratio);
 
-               add_v3_v3v3(td->loc, t->center, vec);
+                       add_v3_v3v3(td->loc, tc->center_local, vec);
+               }
        }
 
-
        recalcData(t);
 
        ED_area_headerprint(t->sa, str);
@@ -3675,7 +3774,7 @@ static void applyToSphere(TransInfo *t, const int UNUSED(mval[2]))
 static void postInputRotation(TransInfo *t, float values[3])
 {
        if ((t->con.mode & CON_APPLY) && t->con.applyRot) {
-               t->con.applyRot(t, NULL, t->axis, values);
+               t->con.applyRot(t, NULL, NULL, t->axis, values);
        }
 }
 
@@ -3720,7 +3819,7 @@ static void initRotation(TransInfo *t)
  *
  * Protected axis and other transform settings are taken into account.
  */
-static void ElementRotation_ex(TransInfo *t, TransData *td, float mat[3][3], const float *center)
+static void ElementRotation_ex(TransInfo *t, TransDataContainer *tc, TransData *td, float mat[3][3], const float *center)
 {
        float vec[3], totmat[3][3], smat[3][3];
        float eul[3], fmat[3][3], quat[4];
@@ -3764,18 +3863,14 @@ static void ElementRotation_ex(TransInfo *t, TransData *td, float mat[3][3], con
         * has been computed, it has to be converted back into the bone's space.
         */
        else if (t->flag & T_POSE) {
-               float pmtx[3][3], imtx[3][3];
-
                // Extract and invert armature object matrix
-               copy_m3_m4(pmtx, t->poseobj->obmat);
-               invert_m3_m3(imtx, pmtx);
 
                if ((td->flag & TD_NO_LOC) == 0) {
                        sub_v3_v3v3(vec, td->center, center);
 
-                       mul_m3_v3(pmtx, vec);   // To Global space
+                       mul_m3_v3(tc->mat3, vec);   // To Global space
                        mul_m3_v3(mat, vec);        // Applying rotation
-                       mul_m3_v3(imtx, vec);   // To Local space
+                       mul_m3_v3(tc->imat3, vec);  // To Local space
 
                        add_v3_v3(vec, center);
                        /* vec now is the location where the object has to be */
@@ -3787,11 +3882,11 @@ static void ElementRotation_ex(TransInfo *t, TransData *td, float mat[3][3], con
                                /* do nothing */
                        }
                        else if (td->flag & TD_PBONE_LOCAL_MTX_C) {
-                               mul_m3_v3(pmtx, vec);   // To Global space
+                               mul_m3_v3(tc->mat3, vec);        // To Global space
                                mul_m3_v3(td->ext->l_smtx, vec); // To Pose space (Local Location)
                        }
                        else {
-                               mul_m3_v3(pmtx, vec);   // To Global space
+                               mul_m3_v3(tc->mat3, vec); // To Global space
                                mul_m3_v3(td->smtx, vec); // To Pose space
                        }
 
@@ -3933,7 +4028,7 @@ static void ElementRotation_ex(TransInfo *t, TransData *td, float mat[3][3], con
        }
 }
 
-static void ElementRotation(TransInfo *t, TransData *td, float mat[3][3], const short around)
+static void ElementRotation(TransInfo *t, TransDataContainer *tc, TransData *td, float mat[3][3], const short around)
 {
        const float *center;
 
@@ -3942,37 +4037,39 @@ static void ElementRotation(TransInfo *t, TransData *td, float mat[3][3], const
                center = td->center;
        }
        else {
-               center = t->center;
+               center = tc->center_local;
        }
 
-       ElementRotation_ex(t, td, mat, center);
+       ElementRotation_ex(t, tc, td, mat, center);
 }
 
 static void applyRotationValue(TransInfo *t, float angle, float axis[3])
 {
-       TransData *td = t->data;
        float mat[3][3];
        int i;
 
        axis_angle_normalized_to_mat3(mat, axis, angle);
 
-       for (i = 0; i < t->total; i++, td++) {
+       FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+               TransData *td = tc->data;
+               for (i = 0; i < tc->data_len; i++, td++) {
 
-               if (td->flag & TD_NOACTION)
-                       break;
+                       if (td->flag & TD_NOACTION)
+                               break;
 
-               if (td->flag & TD_SKIP)
-                       continue;
+                       if (td->flag & TD_SKIP)
+                               continue;
 
-               if (t->con.applyRot) {
-                       t->con.applyRot(t, td, axis, NULL);
-                       axis_angle_normalized_to_mat3(mat, axis, angle * td->factor);
-               }
-               else if (t->flag & T_PROP_EDIT) {
-                       axis_angle_normalized_to_mat3(mat, axis, angle * td->factor);
-               }
+                       if (t->con.applyRot) {
+                               t->con.applyRot(t, tc, td, axis, NULL);
+                               axis_angle_normalized_to_mat3(mat, axis, angle * td->factor);
+                       }
+                       else if (t->flag & T_PROP_EDIT) {
+                               axis_angle_normalized_to_mat3(mat, axis, angle * td->factor);
+                       }
 
-               ElementRotation(t, td, mat, t->around);
+                       ElementRotation(t, tc, td, mat, t->around);
+               }
        }
 }
 
@@ -3988,7 +4085,7 @@ static void applyRotation(TransInfo *t, const int UNUSED(mval[2]))
        snapGridIncrement(t, &final);
 
        if ((t->con.mode & CON_APPLY) && t->con.applyRot) {
-               t->con.applyRot(t, NULL, t->axis, NULL);
+               t->con.applyRot(t, NULL, NULL, t->axis, NULL);
        }
        else {
                /* reset axis if constraint is not set */
@@ -4057,7 +4154,6 @@ static void initTrackball(TransInfo *t)
 
 static void applyTrackballValue(TransInfo *t, const float axis1[3], const float axis2[3], float angles[2])
 {
-       TransData *td = t->data;
        float mat[3][3];
        float axis[3];
        float angle;
@@ -4068,18 +4164,21 @@ static void applyTrackballValue(TransInfo *t, const float axis1[3], const float
        angle = normalize_v3(axis);
        axis_angle_normalized_to_mat3(mat, axis, angle);
 
-       for (i = 0; i < t->total; i++, td++) {
-               if (td->flag & TD_NOACTION)
-                       break;
+       FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+               TransData *td = tc->data;
+               for (i = 0; i < tc->data_len; i++, td++) {
+                       if (td->flag & TD_NOACTION)
+                               break;
 
-               if (td->flag & TD_SKIP)
-                       continue;
+                       if (td->flag & TD_SKIP)
+                               continue;
 
-               if (t->flag & T_PROP_EDIT) {
-                       axis_angle_normalized_to_mat3(mat, axis, td->factor * angle);
-               }
+                       if (t->flag & T_PROP_EDIT) {
+                               axis_angle_normalized_to_mat3(mat, axis, td->factor * angle);
+                       }
 
-               ElementRotation(t, td, mat, t->around);
+                       ElementRotation(t, tc, td, mat, t->around);
+               }
        }
 }
 
@@ -4334,81 +4433,83 @@ static void headerTranslation(TransInfo *t, const float vec[3], char str[UI_MAX_
 
 static void applyTranslationValue(TransInfo *t, const float vec[3])
 {
-       TransData *td = t->data;
+       const bool apply_snap_align_rotation = usingSnappingNormal(t);// && (t->tsnap.status & POINT_INIT);
        float tvec[3];
 
        /* The ideal would be "apply_snap_align_rotation" only when a snap point is found
         * so, maybe inside this function is not the best place to apply this rotation.
         * but you need "handle snapping rotation before doing the translation" (really?) */
-       const bool apply_snap_align_rotation = usingSnappingNormal(t);// && (t->tsnap.status & POINT_INIT);
-       float pivot[3];
-       if (apply_snap_align_rotation) {
-               copy_v3_v3(pivot, t->tsnap.snapTarget);
-               /* The pivot has to be in local-space (see T49494) */
-               if (t->flag & (T_EDIT | T_POSE)) {
-                       Object *ob = t->obedit ? t->obedit : t->poseobj;
-                       mul_m4_v3(ob->imat, pivot);
-               }
-       }
+       FOREACH_TRANS_DATA_CONTAINER (t, tc) {
 
-       for (int i = 0; i < t->total; i++, td++) {
-               if (td->flag & TD_NOACTION)
-                       break;
+               float pivot[3];
+               if (apply_snap_align_rotation) {
+                       copy_v3_v3(pivot, t->tsnap.snapTarget);
+                       /* The pivot has to be in local-space (see T49494) */
+                       if (tc->use_local_mat) {
+                               mul_m4_v3(tc->imat, pivot);
+                       }
+               }
 
-               if (td->flag & TD_SKIP)
-                       continue;
+               TransData *td = tc->data;
+               for (int i = 0; i < tc->data_len; i++, td++) {
+                       if (td->flag & TD_NOACTION)
+                               break;
 
-               float rotate_offset[3] = {0};
-               bool use_rotate_offset = false;
+                       if (td->flag & TD_SKIP)
+                               continue;
 
-               /* handle snapping rotation before doing the translation */
-               if (apply_snap_align_rotation) {
-                       float mat[3][3];
+                       float rotate_offset[3] = {0};
+                       bool use_rotate_offset = false;
 
-                       if (validSnappingNormal(t)) {
-                               const float *original_normal;
+                       /* handle snapping rotation before doing the translation */
+                       if (apply_snap_align_rotation) {
+                               float mat[3][3];
 
-                               /* In pose mode, we want to align normals with Y axis of bones... */
-                               if (t->flag & T_POSE)
-                                       original_normal = td->axismtx[1];
-                               else
-                                       original_normal = td->axismtx[2];
+                               if (validSnappingNormal(t)) {
+                                       const float *original_normal;
 
-                               rotation_between_vecs_to_mat3(mat, original_normal, t->tsnap.snapNormal);
-                       }
-                       else {
-                               unit_m3(mat);
-                       }
+                                       /* In pose mode, we want to align normals with Y axis of bones... */
+                                       if (t->flag & T_POSE)
+                                               original_normal = td->axismtx[1];
+                                       else
+                                               original_normal = td->axismtx[2];
+
+                                       rotation_between_vecs_to_mat3(mat, original_normal, t->tsnap.snapNormal);
+                               }
+                               else {
+                                       unit_m3(mat);
+                               }
 
-                       ElementRotation_ex(t, td, mat, pivot);
+                               ElementRotation_ex(t, tc, td, mat, pivot);
 
-                       if (td->loc) {
-                               use_rotate_offset = true;
-                               sub_v3_v3v3(rotate_offset, td->loc, td->iloc);
+                               if (td->loc) {
+                                       use_rotate_offset = true;
+                                       sub_v3_v3v3(rotate_offset, td->loc, td->iloc);
+                               }
                        }
-               }
 
-               if (t->con.applyVec) {
-                       float pvec[3];
-                       t->con.applyVec(t, td, vec, tvec, pvec);
-               }
-               else {
-                       copy_v3_v3(tvec, vec);
-               }
+                       if (t->con.applyVec) {
+                               float pvec[3];
+                               t->con.applyVec(t, tc, td, vec, tvec, pvec);
+                       }
+                       else {
+                               copy_v3_v3(tvec, vec);
+                       }
 
-               if (use_rotate_offset) {
-                       add_v3_v3(tvec, rotate_offset);
-               }
+                       if (use_rotate_offset) {
+                               add_v3_v3(tvec, rotate_offset);
+                       }
 
-               mul_m3_v3(td->smtx, tvec);
-               mul_v3_fl(tvec, td->factor);
+                       mul_m3_v3(td->smtx, tvec);
+                       mul_v3_fl(tvec, td->factor);
 
-               protectedTransBits(td->protectflag, tvec);
+                       protectedTransBits(td->protectflag, tvec);
 
-               if (td->loc)
-                       add_v3_v3v3(td->loc, td->iloc, tvec);
+                       if (td->loc)
+                               add_v3_v3v3(td->loc, td->iloc, tvec);
 
-               constraintTransLim(t, td);
+                       constraintTransLim(t, td);
+               }
        }
 }
 
@@ -4434,7 +4535,7 @@ static void applyTranslation(TransInfo *t, const int UNUSED(mval[2]))
 
        if (t->con.mode & CON_APPLY) {
                float pvec[3] = {0.0f, 0.0f, 0.0f};
-               t->con.applyVec(t, NULL, t->values, value_final, pvec);
+               t->con.applyVec(t, NULL, NULL, t->values, value_final, pvec);
                headerTranslation(t, pvec, str);
 
                /* only so we have re-usable value with redo, see T46741. */
@@ -4478,7 +4579,7 @@ static void applyTranslation(TransInfo *t, const int UNUSED(mval[2]))
 static void initShrinkFatten(TransInfo *t)
 {
        // If not in mesh edit mode, fallback to Resize
-       if (t->obedit == NULL || t->obedit->type != OB_MESH) {
+       if ((t->flag & T_EDIT) == 0 || (t->obedit_type != OB_MESH)) {
                initResize(t);
        }
        else {
@@ -4508,7 +4609,6 @@ static void applyShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
        int i;
        char str[UI_MAX_DRAW_STR];
        size_t ofs = 0;
-       TransData *td = t->data;
 
        distance = -t->values[0];
 
@@ -4545,21 +4645,24 @@ static void applyShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
                     WM_bool_as_string((t->flag & T_ALT_TRANSFORM) != 0));
        /* done with header string */
 
-       for (i = 0; i < t->total; i++, td++) {
-               float tdistance;  /* temp dist */
-               if (td->flag & TD_NOACTION)
-                       break;
+       FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+               TransData *td = tc->data;
+               for (i = 0; i < tc->data_len; i++, td++) {
+                       float tdistance;  /* temp dist */
+                       if (td->flag & TD_NOACTION)
+                               break;
 
-               if (td->flag & TD_SKIP)
-                       continue;
+                       if (td->flag & TD_SKIP)
+                               continue;
 
-               /* get the final offset */
-               tdistance = distance * td->factor;
-               if (td->ext && (t->flag & T_ALT_TRANSFORM)) {
-                       tdistance *= td->ext->isize[0];  /* shell factor */
-               }
+                       /* get the final offset */
+                       tdistance = distance * td->factor;
+                       if (td->ext && (t->flag & T_ALT_TRANSFORM)) {
+                               tdistance *= td->ext->isize[0];  /* shell factor */
+                       }
 
-               madd_v3_v3v3fl(td->loc, td->iloc, td->axismtx[2], tdistance);
+                       madd_v3_v3v3fl(td->loc, td->iloc, td->axismtx[2], tdistance);
+               }
        }
 
        recalcData(t);
@@ -4599,7 +4702,6 @@ static void initTilt(TransInfo *t)
 
 static void applyTilt(TransInfo *t, const int UNUSED(mval[2]))
 {
-       TransData *td = t->data;
        int i;
        char str[UI_MAX_DRAW_STR];
 
@@ -4627,15 +4729,18 @@ static void applyTilt(TransInfo *t, const int UNUSED(mval[2]))
                BLI_snprintf(str, sizeof(str), IFACE_("Tilt: %.2f° %s"), RAD2DEGF(final), t->proptext);
        }
 
-       for (i = 0; i < t->total; i++, td++) {
-               if (td->flag & TD_NOACTION)
-                       break;
+       FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+               TransData *td = tc->data;
+               for (i = 0; i < tc->data_len; i++, td++) {
+                       if (td->flag & TD_NOACTION)
+                               break;
 
-               if (td->flag & TD_SKIP)
-                       continue;
+                       if (td->flag & TD_SKIP)
+                               continue;
 
-               if (td->val) {
-                       *td->val = td->ival + final * td->factor;
+                       if (td->val) {
+                               *td->val = td->ival + final * td->factor;
+                       }
                }
        }
 
@@ -4679,7 +4784,6 @@ static void initCurveShrinkFatten(TransInfo *t)
 
 static void applyCurveShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
 {
-       TransData *td = t->data;
        float ratio;
        int i;
        char str[UI_MAX_DRAW_STR];
@@ -4703,18 +4807,21 @@ static void applyCurveShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
                BLI_snprintf(str, sizeof(str), IFACE_("Shrink/Fatten: %3f"), ratio);
        }
 
-       for (i = 0; i < t->total; i++, td++) {
-               if (td->flag & TD_NOACTION)
-                       break;
+       FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+               TransData *td = tc->data;
+               for (i = 0; i < tc->data_len; i++, td++) {
+                       if (td->flag & TD_NOACTION)
+                               break;
 
-               if (td->flag & TD_SKIP)
-                       continue;
+                       if (td->flag & TD_SKIP)
+                               continue;
 
-               if (td->val) {
-                       *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;
+                       if (td->val) {
+                               *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;
+                       }
                }
        }
 
@@ -4758,7 +4865,6 @@ static void initMaskShrinkFatten(TransInfo *t)
 
 static void applyMaskShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
 {
-       TransData *td;
        float ratio;
        int i;
        bool initial_feather = false;
@@ -4787,35 +4893,41 @@ static void applyMaskShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
        if (ratio > 1.0f) {
                initial_feather = true;
 
-               for (td = t->data, i = 0; i < t->total; i++, td++) {
-                       if (td->flag & TD_NOACTION)
-                               break;
+               FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+                       TransData *td = tc->data;
+                       for (i = 0; i < tc->data_len; i++, td++) {
+                               if (td->flag & TD_NOACTION)
+                                       break;
 
-                       if (td->flag & TD_SKIP)
-                               continue;
+                               if (td->flag & TD_SKIP)
+                                       continue;
 
-                       if (td->ival >= 0.001f)
-                               initial_feather = false;
+                               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;
+       FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+               TransData *td = tc->data;
+               for (td = tc->data, i = 0; i < tc->data_len; i++, td++) {
+                       if (td->flag & TD_NOACTION)
+                               break;
 
-               if (td->flag & TD_SKIP)
-                       continue;
+                       if (td->flag & TD_SKIP)
+                               continue;
 
-               if (td->val) {
-                       if (initial_feather)
-                               *td->val = td->ival + (ratio - 1.0f) * 0.01f;
-                       else
-                               *td->val = td->ival * ratio;
+                       if (td->val) {
+                               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;
+                       }
                }
        }
 
@@ -4859,7 +4971,6 @@ static void initGPShrinkFatten(TransInfo *t)
 
 static void applyGPShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
 {
-       TransData *td = t->data;
        float ratio;
        int i;
        char str[UI_MAX_DRAW_STR];
@@ -4883,18 +4994,21 @@ static void applyGPShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
                BLI_snprintf(str, sizeof(str), IFACE_("Shrink/Fatten: %3f"), ratio);
        }
 
-       for (i = 0; i < t->total; i++, td++) {
-               if (td->flag & TD_NOACTION)
-                       break;
+       FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+               TransData *td = tc->data;
+               for (i = 0; i < tc->data_len; i++, td++) {
+                       if (td->flag & TD_NOACTION)
+                               break;
 
-               if (td->flag & TD_SKIP)
-                       continue;
+                       if (td->flag & TD_SKIP)
+                               continue;
 
-               if (td->val) {
-                       *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;
+                       if (td->val) {
+                               *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;
+                       }
                }
        }
 
@@ -4936,7 +5050,6 @@ static void applyPushPull(TransInfo *t, const int UNUSED(mval[2]))
        float distance;
        int i;
        char str[UI_MAX_DRAW_STR];
-       TransData *td = t->data;
 
        distance = t->values[0];
 
@@ -4960,35 +5073,38 @@ static void applyPushPull(TransInfo *t, const int UNUSED(mval[2]))
        }
 
        if (t->con.applyRot && t->con.mode & CON_APPLY) {
-               t->con.applyRot(t, NULL, axis_global, NULL);
+               t->con.applyRot(t, NULL, NULL, axis_global, NULL);
        }
 
-       for (i = 0; i < t->total; i++, td++) {
-               if (td->flag & TD_NOACTION)
-                       break;
-
-               if (td->flag & TD_SKIP)
-                       continue;
+       FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+               TransData *td = tc->data;
+               for (i = 0; i < tc->data_len; i++, td++) {
+                       if (td->flag & TD_NOACTION)
+                               break;
 
-               sub_v3_v3v3(vec, t->center, td->center);
-               if (t->con.applyRot && t->con.mode & CON_APPLY) {
-                       float axis[3];
-                       copy_v3_v3(axis, axis_global);
-                       t->con.applyRot(t, td, axis, NULL);
+                       if (td->flag & TD_SKIP)
+                               continue;
 
-                       mul_m3_v3(td->smtx, axis);
-                       if (isLockConstraint(t)) {
-                               float dvec[3];
-                               project_v3_v3v3(dvec, vec, axis);
-                               sub_v3_v3(vec, dvec);
-                       }
-                       else {
-                               project_v3_v3v3(vec, vec, axis);
+                       sub_v3_v3v3(vec, tc->center_local, td->center);
+                       if (t->con.applyRot && t->con.mode & CON_APPLY) {
+                               float axis[3];
+                               copy_v3_v3(axis, axis_global);
+                               t->con.applyRot(t, tc, td, axis, NULL);
+
+                               mul_m3_v3(td->smtx, axis);
+                               if (isLockConstraint(t)) {
+                                       float dvec[3];
+                                       project_v3_v3v3(dvec, vec, axis);
+                                       sub_v3_v3(vec, dvec);
+                               }
+                               else {
+                                       project_v3_v3v3(vec, vec, axis);
+                               }
                        }
-               }
-               normalize_v3_length(vec, distance * td->factor);
+                       normalize_v3_length(vec, distance * td->factor);
 
-               add_v3_v3v3(td->loc, td->iloc, vec);
+                       add_v3_v3v3(td->loc, td->iloc, vec);
+               }
        }
 
        recalcData(t);
@@ -5026,7 +5142,6 @@ static void initBevelWeight(TransInfo *t)
 
 static void applyBevelWeight(TransInfo *t, const int UNUSED(mval[2]))
 {
-       TransData *td = t->data;
        float weight;
        int i;
        char str[UI_MAX_DRAW_STR];
@@ -5060,14 +5175,17 @@ static void applyBevelWeight(TransInfo *t, const int UNUSED(mval[2]))
                        BLI_snprintf(str, sizeof(str), IFACE_("Bevel Weight: %.3f %s"), weight, t->proptext);
        }
 
-       for (i = 0; i < t->total; i++, td++) {
-               if (td->flag & TD_NOACTION)
-                       break;
+       FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+               TransData *td = tc->data;
+               for (i = 0; i < tc->data_len; i++, td++) {
+                       if (td->flag & TD_NOACTION)
+                               break;
 
-               if (td->val) {
-                       *td->val = td->ival + weight * td->factor;
-                       if (*td->val < 0.0f) *td->val = 0.0f;
-                       if (*td->val > 1.0f) *td->val = 1.0f;
+                       if (td->val) {
+                               *td->val = td->ival + weight * td->factor;
+                               if (*td->val < 0.0f) *td->val = 0.0f;
+                               if (*td->val > 1.0f) *td->val = 1.0f;
+                       }
                }
        }
 
@@ -5106,7 +5224,6 @@ static void initCrease(TransInfo *t)
 
 static void applyCrease(TransInfo *t, const int UNUSED(mval[2]))
 {
-       TransData *td = t->data;
        float crease;
        int i;
        char str[UI_MAX_DRAW_STR];
@@ -5140,17 +5257,20 @@ static void applyCrease(TransInfo *t, const int UNUSED(mval[2]))
                        BLI_snprintf(str, sizeof(str), IFACE_("Crease: %.3f %s"), crease, t->proptext);
        }
 
-       for (i = 0; i < t->total; i++, td++) {
-               if (td->flag & TD_NOACTION)
-                       break;
+       FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+               TransData *td = tc->data;
+               for (i = 0; i < tc->data_len; i++, td++) {
+                       if (td->flag & TD_NOACTION)
+                               break;
 
-               if (td->flag & TD_SKIP)
-                       continue;
+                       if (td->flag & TD_SKIP)
+                               continue;
 
-               if (td->val) {
-                       *td->val = td->ival + crease * td->factor;
-                       if (*td->val < 0.0f) *td->val = 0.0f;
-                       if (*td->val > 1.0f) *td->val = 1.0f;
+                       if (td->val) {
+                               *td->val = td->ival + crease * td->factor;
+                               if (*td->val < 0.0f) *td->val = 0.0f;
+                               if (*td->val > 1.0f) *td->val = 1.0f;
+                       }
                }
        }
 
@@ -5217,7 +5337,7 @@ static void headerBoneSize(TransInfo *t, const float vec[3], char str[UI_MAX_DRA
        }
 }
 
-static void ElementBoneSize(TransInfo *t, TransData *td, float mat[3][3])
+static void ElementBoneSize(TransInfo *t, TransDataContainer *tc, TransData *td, float mat[3][3])
 {
        float tmat[3][3], smat[3][3], oldy;
        float sizemat[3][3];
@@ -5226,7 +5346,7 @@ static void ElementBoneSize(TransInfo *t, TransData *td, float mat[3][3])
        mul_m3_m3m3(tmat, td->smtx, smat);
 
        if (t->con.applySize) {
-               t->con.applySize(t, td, tmat);
+               t->con.applySize(t, tc, td, tmat);
        }
 
        /* we've tucked the scale in loc */
@@ -5237,23 +5357,13 @@ static void ElementBoneSize(TransInfo *t, TransData *td, float mat[3][3])
        td->loc[1] = oldy;
 }
 
-static void applyBoneSize(TransInfo *t, const int mval[2])
+static void applyBoneSize(TransInfo *t, const int UNUSED(mval[2]))
 {
-       TransData *td = t->data;
        float size[3], mat[3][3];
-       float ratio;
+       float ratio = t->values[0];
        int i;
        char str[UI_MAX_DRAW_STR];
 
-       // TRANSFORM_FIX_ME MOVE TO MOUSE INPUT
-       /* for manipulator, center handle, the scaling can't be done relative to center */
-       if ((t->flag & T_USES_MANIPULATOR) && t->con.mode == 0) {
-               ratio = 1.0f - ((t->mouse.imval[0] - mval[0]) + (t->mouse.imval[1] - mval[1])) / 100.0f;
-       }
-       else {
-               ratio = t->values[0];
-       }
-
        copy_v3_fl(size, ratio);
 
        snapGridIncrement(t, size);
@@ -5267,21 +5377,24 @@ static void applyBoneSize(TransInfo *t, const int mval[2])
        size_to_mat3(mat, size);
 
        if (t->con.applySize) {
-               t->con.applySize(t, NULL, mat);
+               t->con.applySize(t, NULL, NULL, mat);
        }
 
        copy_m3_m3(t->mat, mat);    // used in manipulator
 
        headerBoneSize(t, size, str);
 
-       for (i = 0; i < t->total; i++, td++) {
-               if (td->flag & TD_NOACTION)
-                       break;
+       FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+               TransData *td = tc->data;
+               for (i = 0; i < tc->data_len; i++, td++) {
+                       if (td->flag & TD_NOACTION)
+                               break;
 
-               if (td->flag & TD_SKIP)
-                       continue;
+                       if (td->flag & TD_SKIP)
+                               continue;
 
-               ElementBoneSize(t, td, mat);
+                       ElementBoneSize(t, tc, td, mat);
+               }
        }
 
        recalcData(t);
@@ -5319,7 +5432,6 @@ static void initBoneEnvelope(TransInfo *t)
 
 static void applyBoneEnvelope(TransInfo *t, const int UNUSED(mval[2]))
 {
-       TransData *td = t->data;
        float ratio;
        int i;
        char str[UI_MAX_DRAW_STR];
@@ -5343,19 +5455,22 @@ static void applyBoneEnvelope(TransInfo *t, const int UNUSED(mval[2]))
                BLI_snprintf(str, sizeof(str), IFACE_("Envelope: %3f"), ratio);
        }
 
-       for (i = 0; i < t->total; i++, td++) {
-               if (td->flag & TD_NOACTION)
-                       break;
+       FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+               TransData *td = tc->data;
+               for (i = 0; i < tc->data_len; i++, td++) {
+                       if (td->flag & TD_NOACTION)
+                               break;
 
-               if (td->flag & TD_SKIP)
-                       continue;
+                       if (td->flag & TD_SKIP)
+                               continue;
 
-               if (td->val) {
-                       /* if the old/original value was 0.0f, then just use ratio */
-                       if (td->ival)
-                               *td->val = td->ival * ratio;
-                       else
-                               *td->val = ratio;
+                       if (td->val) {
+                               /* if the old/original value was 0.0f, then just use ratio */
+                               if (td->ival)
+                                       *td->val = td->ival * ratio;
+                               else
+                                       *td->val = ratio;
+                       }
                }
        }
 
@@ -5372,9 +5487,9 @@ static void applyBoneEnvelope(TransInfo *t, const int UNUSED(mval[2]))
  * \{ */
 
 static void slide_origdata_init_flag(
-        TransInfo *t, SlideOrigData *sod)
+        TransInfo *t, TransDataContainer *tc, SlideOrigData *sod)
 {
-       BMEditMesh *em = BKE_editmesh_from_object(t->obedit);
+       BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
        BMesh *bm = em->bm;
        const bool has_layer_math = CustomData_has_math(&bm->ldata);
        const int cd_loop_mdisp_offset = CustomData_get_offset(&bm->ldata, CD_MDISPS);
@@ -5395,10 +5510,10 @@ static void slide_origdata_init_flag(
 }
 
 static void slide_origdata_init_data(
-        TransInfo *t, SlideOrigData *sod)
+        TransDataContainer *tc, SlideOrigData *sod)
 {
        if (sod->use_origfaces) {
-               BMEditMesh *em = BKE_editmesh_from_object(t->obedit);
+               BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
                BMesh *bm = em->bm;
 
                sod->origfaces = BLI_ghash_ptr_new(__func__);
@@ -5459,11 +5574,11 @@ static void slide_origdata_create_data_vert(
 }
 
 static void slide_origdata_create_data(
-        TransInfo *t, SlideOrigData *sod,
+        TransInfo *t, TransDataContainer *tc, SlideOrigData *sod,
         TransDataGenericSlideVert *sv_array, unsigned int v_stride, unsigned int v_num)
 {
        if (sod->use_origfaces) {
-               BMEditMesh *em = BKE_editmesh_from_object(t->obedit);
+               BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
                BMesh *bm = em->bm;
                unsigned int i;
                TransDataGenericSlideVert *sv;
@@ -5495,15 +5610,15 @@ static void slide_origdata_create_data(
                }
 
                if (t->flag & T_MIRROR) {
-                       TransData *td = t->data;
+                       TransData *td = tc->data;
                        TransDataGenericSlideVert *sv_mirror;
 
-                       sod->sv_mirror = MEM_callocN(sizeof(*sv_mirror) * t->total, __func__);
-                       sod->totsv_mirror = t->total;
+                       sod->sv_mirror = MEM_callocN(sizeof(*sv_mirror) * tc->data_len, __func__);
+                       sod->totsv_mirror = tc->data_len;
 
                        sv_mirror = sod->sv_mirror;
 
-                       for (i = 0; i < t->total; i++, td++) {
+                       for (i = 0; i < tc->data_len; i++, td++) {
                                BMVert *eve = td->extra;
                                if (eve) {
                                        sv_mirror->v = eve;
@@ -5657,12 +5772,12 @@ static void slide_origdata_interp_data_vert(
 }
 
 static void slide_origdata_interp_data(
-        TransInfo *t, SlideOrigData *sod,
+        Object *obedit, SlideOrigData *sod,
         TransDataGenericSlideVert *sv, unsigned int v_stride, unsigned int v_num,
         bool is_final)
 {
        if (sod->use_origfaces) {
-               BMEditMesh *em = BKE_editmesh_from_object(t->obedit);
+               BMEditMesh *em = BKE_editmesh_from_object(obedit);
                BMesh *bm = em->bm;
                unsigned int i;
                const bool has_mdisps = (sod->cd_loop_mdisp_offset != -1);
@@ -5725,7 +5840,7 @@ static void slide_origdata_free_date(
 
 static void calcEdgeSlideCustomPoints(struct TransInfo *t)
 {
-       EdgeSlideData *sld = t->custom.mode.data;
+       EdgeSlideData *sld = TRANS_DATA_CONTAINER_FIRST_OK(t)->custom.mode.data;
 
        setCustomPoints(t, &t->mouse, sld->mval_end, sld->mval_start);
 
@@ -5793,6 +5908,7 @@ static bool bm_loop_calc_opposite_co(BMLoop *l_tmp,
        BMLoop *l_last  = l_tmp->prev;
        BMLoop *l_iter;
        float dist = FLT_MAX;
+       bool found = false;
 
        l_iter = l_first;
        do {
@@ -5811,12 +5927,13 @@ static bool bm_loop_calc_opposite_co(BMLoop *l_tmp,
                                if (tdist < dist) {
                                        copy_v3_v3(r_co, tvec);
                                        dist = tdist;
+                                       found = true;
                                }
                        }
                }
        } while ((l_iter = l_iter->next) != l_last);
 
-       return (dist != FLT_MAX);
+       return found;
 }
 
 /**
@@ -5922,11 +6039,11 @@ static BMLoop *get_next_loop(BMVert *v, BMLoop *l,
  * Calculate screenspace `mval_start` / `mval_end`, optionally slide direction.
  */
 static void calcEdgeSlide_mval_range(
-        TransInfo *t, EdgeSlideData *sld, const int *sv_table, const int loop_nr,
+        TransInfo *t, TransDataContainer *tc, EdgeSlideData *sld, const int *sv_table, const int loop_nr,
         const float mval[2], const bool use_occlude_geometry, const bool use_calc_direction)
 {
        TransDataEdgeSlideVert *sv_array = sld->sv;
-       BMEditMesh *em = BKE_editmesh_from_object(t->obedit);
+       BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
        BMesh *bm = em->bm;
        ARegion *ar = t->ar;
        View3D *v3d = NULL;
@@ -5953,7 +6070,7 @@ static void calcEdgeSlide_mval_range(
                unit_m4(projectMat);
        }
        else {
-               ED_view3d_ob_project_mat_get(rv3d, t->obedit, projectMat);
+               ED_view3d_ob_project_mat_get(rv3d, tc->obedit, projectMat);
        }
 
        if (use_occlude_geometry) {
@@ -5995,7 +6112,9 @@ static void calcEdgeSlide_mval_range(
                                                continue;
 
                                        /* This test is only relevant if object is not wire-drawn! See [#32068]. */
-                                       if (use_occlude_geometry && !BMBVH_EdgeVisible(bmbvh, e_other, ar, v3d, t->obedit)) {
+                                       if (use_occlude_geometry &&
+                                           !BMBVH_EdgeVisible(bmbvh, e_other, t->depsgraph, ar, v3d, tc->obedit))
+                                       {
                                                continue;
                                        }
 
@@ -6082,7 +6201,7 @@ static void calcEdgeSlide_mval_range(
 }
 
 static void calcEdgeSlide_even(
-        TransInfo *t, EdgeSlideData *sld, const float mval[2])
+        TransInfo *t, TransDataContainer *tc, EdgeSlideData *sld, const float mval[2])
 {
        TransDataEdgeSlideVert *sv = sld->sv;
 
@@ -6107,7 +6226,7 @@ static void calcEdgeSlide_even(
                        unit_m4(projectMat);
                }
                else {
-                       ED_view3d_ob_project_mat_get(rv3d, t->obedit, projectMat);
+                       ED_view3d_ob_project_mat_get(rv3d, tc->obedit, projectMat);
                }
 
                for (i = 0; i < sld->totsv; i++, sv++) {
@@ -6127,9 +6246,9 @@ static void calcEdgeSlide_even(
        }
 }
 
-static bool createEdgeSlideVerts_double_side(TransInfo *t, bool use_even, bool flipped, bool use_clamp)
+static bool createEdgeSlideVerts_double_side(TransInfo *t, TransDataContainer *tc)
 {
-       BMEditMesh *em = BKE_editmesh_from_object(t->obedit);
+       BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
        BMesh *bm = em->bm;
        BMIter iter;
        BMEdge *e;
@@ -6144,13 +6263,9 @@ static bool createEdgeSlideVerts_double_side(TransInfo *t, bool use_even, bool f
        View3D *v3d = NULL;
        RegionView3D *rv3d = NULL;
 
-       slide_origdata_init_flag(t, &sld->orig_data);
+       slide_origdata_init_flag(t, tc, &sld->orig_data);
 
-       sld->use_even = use_even;
        sld->curr_sv_index = 0;
-       sld->flipped = flipped;
-       if (!use_clamp)
-               t->flag |= T_ALT_TRANSFORM;
 
        /*ensure valid selection*/
        BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
@@ -6466,25 +6581,23 @@ static bool createEdgeSlideVerts_double_side(TransInfo *t, bool use_even, bool f
        if (t->spacetype == SPACE_VIEW3D) {
                v3d = t->sa ? t->sa->spacedata.first : NULL;
                rv3d = t->ar ? t->ar->regiondata : NULL;
-               use_occlude_geometry = (v3d && t->obedit->dt > OB_WIRE && v3d->drawtype > OB_WIRE);
+               use_occlude_geometry = (v3d && TRANS_DATA_CONTAINER_FIRST_OK(t)->obedit->dt > OB_WIRE && v3d->drawtype > OB_WIRE);
        }
 
-       calcEdgeSlide_mval_range(t, sld, sv_table, loop_nr, mval, use_occlude_geometry, true);
+       calcEdgeSlide_mval_range(t, tc, sld, sv_table, loop_nr, mval, use_occlude_geometry, true);
 
        /* create copies of faces for customdata projection */
        bmesh_edit_begin(bm, BMO_OPTYPE_FLAG_UNTAN_MULTIRES);
-       slide_origdata_init_data(t, &sld->orig_data);
-       slide_origdata_create_data(t, &sld->orig_data, (TransDataGenericSlideVert *)sld->sv, sizeof(*sld->sv), sld->totsv);
+       slide_origdata_init_data(tc, &sld->orig_data);
+       slide_origdata_create_data(t, tc, &sld->orig_data, (TransDataGenericSlideVert *)sld->sv, sizeof(*sld->sv), sld->totsv);
 
        if (rv3d) {
-               calcEdgeSlide_even(t, sld, mval);
+               calcEdgeSlide_even(t, tc, sld, mval);
        }
 
        sld->em = em;
 
-       sld->perc = 0.0f;
-
-       t->custom.mode.data = sld;
+       tc->custom.mode.data = sld;
 
        MEM_freeN(sv_table);
 
@@ -6495,9 +6608,9 @@ static bool createEdgeSlideVerts_double_side(TransInfo *t, bool use_even, bool f
  * A simple version of #createEdgeSlideVerts_double_side
  * Which assumes the longest unselected.
  */
-static bool createEdgeSlideVerts_single_side(TransInfo *t, bool use_even, bool flipped, bool use_clamp)
+static bool createEdgeSlideVerts_single_side(TransInfo *t, TransDataContainer *tc)
 {
-       BMEditMesh *em = BKE_editmesh_from_object(t->obedit);
+       BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
        BMesh *bm = em->bm;
        BMIter iter;
        BMEdge *e;
@@ -6517,15 +6630,9 @@ static bool createEdgeSlideVerts_single_side(TransInfo *t, bool use_even, bool f
                rv3d = t->ar ? t->ar->regiondata : NULL;
        }
 
-       slide_origdata_init_flag(t, &sld->orig_data);
+       slide_origdata_init_flag(t, tc, &sld->orig_data);
 
-       sld->use_even = use_even;
        sld->curr_sv_index = 0;
-       /* happens to be best for single-sided */
-       sld->flipped = !flipped;
-       if (!use_clamp)
-               t->flag |= T_ALT_TRANSFORM;
-
        /* ensure valid selection */
        {
                int i = 0, j = 0;
@@ -6669,25 +6776,23 @@ static bool createEdgeSlideVerts_single_side(TransInfo *t, bool use_even, bool f
        if (t->spacetype == SPACE_VIEW3D) {
                v3d = t->sa ? t->sa->spacedata.first : NULL;
                rv3d = t->ar ? t->ar->regiondata : NULL;
-               use_occlude_geometry = (v3d && t->obedit->dt > OB_WIRE && v3d->drawtype > OB_WIRE);
+               use_occlude_geometry = (v3d && TRANS_DATA_CONTAINER_FIRST_OK(t)->obedit->dt > OB_WIRE && v3d->drawtype > OB_WIRE);
        }
 
-       calcEdgeSlide_mval_range(t, sld, sv_table, loop_nr, mval, use_occlude_geometry, false);
+       calcEdgeSlide_mval_range(t, tc, sld, sv_table, loop_nr, mval, use_occlude_geometry, false);
 
        /* create copies of faces for customdata projection */
        bmesh_edit_begin(bm, BMO_OPTYPE_FLAG_UNTAN_MULTIRES);
-       slide_origdata_init_data(t, &sld->orig_data);
-       slide_origdata_create_data(t, &sld->orig_data, (TransDataGenericSlideVert *)sld->sv, sizeof(*sld->sv), sld->totsv);
+       slide_origdata_init_data(tc, &sld->orig_data);
+       slide_origdata_create_data(t, tc, &sld->orig_data, (TransDataGenericSlideVert *)sld->sv, sizeof(*sld->sv), sld->totsv);
 
        if (rv3d) {
-               calcEdgeSlide_even(t, sld, mval);
+               calcEdgeSlide_even(t, tc, sld, mval);
        }
 
        sld->em = em;
 
-       sld->perc = 0.0f;
-
-       t->custom.mode.data = sld;
+       tc->custom.mode.data = sld;
 
        MEM_freeN(sv_table);
 
@@ -6696,14 +6801,16 @@ static bool createEdgeSlideVerts_single_side(TransInfo *t, bool use_even, bool f
 
 void projectEdgeSlideData(TransInfo *t, bool is_final)
 {
-       EdgeSlideData *sld = t->custom.mode.data;
-       SlideOrigData *sod = &sld->orig_data;
+       FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+               EdgeSlideData *sld = tc->custom.mode.data;
+               SlideOrigData *sod = &sld->orig_data;
 
-       if (sod->use_origfaces == false) {
-               return;
-       }
+               if (sod->use_origfaces == false) {
+                       return;
+               }
 
-       slide_origdata_interp_data(t, sod, (TransDataGenericSlideVert *)sld->sv, sizeof(*sld->sv), sld->totsv, is_final);
+               slide_origdata_interp_data(tc->obedit, sod, (TransDataGenericSlideVert *)sld->sv, sizeof(*sld->sv), sld->totsv, is_final);
+       }
 }
 
 void freeEdgeSlideTempFaces(EdgeSlideData *sld)
@@ -6711,7 +6818,7 @@ void freeEdgeSlideTempFaces(EdgeSlideData *sld)
        slide_origdata_free_date(&sld->orig_data);
 }
 
-void freeEdgeSlideVerts(TransInfo *UNUSED(t), TransCustomData *custom_data)
+void freeEdgeSlideVerts(TransInfo *UNUSED(t), TransDataContainer *UNUSED(tc), TransCustomData *custom_data)
 {
        EdgeSlideData *sld = custom_data->data;
 
@@ -6731,17 +6838,39 @@ void freeEdgeSlideVerts(TransInfo *UNUSED(t), TransCustomData *custom_data)
 static void initEdgeSlide_ex(TransInfo *t, bool use_double_side, bool use_even, bool flipped, bool use_clamp)
 {
        EdgeSlideData *sld;
-       bool ok;
+       bool ok = false;
 
        t->mode = TFM_EDGE_SLIDE;
        t->transform = applyEdgeSlide;
        t->handleEvent = handleEventEdgeSlide;
 
+       {
+               EdgeSlideParams *slp = MEM_callocN(sizeof(*slp), __func__);
+               slp->use_even = use_even;
+               slp->flipped = flipped;
+               /* happens to be best for single-sided */
+               if (use_double_side == false) {
+                       slp->flipped = !flipped;
+               }
+               slp->perc = 0.0f;
+
+               if (!use_clamp) {
+                       t->flag |= T_ALT_TRANSFORM;
+               }
+
+               t->custom.mode.data = slp;
+               t->custom.mode.use_free = true;
+       }
+
        if (use_double_side) {
-               ok = createEdgeSlideVerts_double_side(t, use_even, flipped, use_clamp);
+               FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+                       ok |= createEdgeSlideVerts_double_side(t, tc);
+               }
        }
        else {
-               ok = createEdgeSlideVerts_single_side(t, use_even, flipped, use_clamp);
+               FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+                       ok |= createEdgeSlideVerts_single_side(t, tc);
+               }
        }
 
        if (!ok) {
@@ -6749,12 +6878,13 @@ static void initEdgeSlide_ex(TransInfo *t, bool use_double_side, bool use_even,
                return;
        }
 
-       sld = t->custom.mode.data;
-
-       if (!sld)
-               return;
-
-       t->custom.mode.free_cb = freeEdgeSlideVerts;
+       FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+               sld = tc->custom.mode.data;
+               if (!sld) {
+                       continue;
+               }
+               tc->custom.mode.free_cb = freeEdgeSlideVerts;
+       }
 
        /* set custom point first if you want value to be initialized by init */
        calcEdgeSlideCustomPoints(t);
@@ -6781,20 +6911,20 @@ static void initEdgeSlide(TransInfo *t)
 static eRedrawFlag handleEventEdgeSlide(struct TransInfo *t, const struct wmEvent *event)
 {
        if (t->mode == TFM_EDGE_SLIDE) {
-               EdgeSlideData *sld = t->custom.mode.data;
+               EdgeSlideParams *slp = t->custom.mode.data;
 
-               if (sld) {
+               if (slp) {
                        switch (event->type) {
                                case EKEY:
                                        if (event->val == KM_PRESS) {
-                                               sld->use_even = !sld->use_even;
+                                               slp->use_even = !slp->use_even;
                                                calcEdgeSlideCustomPoints(t);
                                                return TREDRAW_HARD;
                                        }
                                        break;
                                case FKEY:
                                        if (event->val == KM_PRESS) {
-                                               sld->flipped = !sld->flipped;
+                                               slp->flipped = !slp->flipped;
                                                calcEdgeSlideCustomPoints(t);
                                                return TREDRAW_HARD;
                                        }
@@ -6808,6 +6938,7 @@ static eRedrawFlag handleEventEdgeSlide(struct TransInfo *t, const struct wmEven
                                        }
                                        break;
                                case EVT_MODAL_MAP:
+#if 0
                                        switch (event->val) {
                                                case TFM_MODAL_EDGESLIDE_DOWN:
                                                        sld->curr_sv_index = ((sld->curr_sv_index - 1) + sld->totsv) % sld->totsv;
@@ -6816,6 +6947,7 @@ static eRedrawFlag handleEventEdgeSlide(struct TransInfo *t, const struct wmEven
                                                        sld->curr_sv_index = (sld->curr_sv_index + 1) % sld->totsv;
                                                        return TREDRAW_HARD;
                                        }
+#endif
                                        break;
                                case MOUSEMOVE:
                                        calcEdgeSlideCustomPoints(t);
@@ -6830,12 +6962,13 @@ static eRedrawFlag handleEventEdgeSlide(struct TransInfo *t, const struct wmEven
 
 static void drawEdgeSlide(TransInfo *t)
 {
-       if ((t->mode == TFM_EDGE_SLIDE) && t->custom.mode.data) {
-               EdgeSlideData *sld = t->custom.mode.data;
+       if ((t->mode == TFM_EDGE_SLIDE) && TRANS_DATA_CONTAINER_FIRST_OK(t)->custom.mode.data) {
+               const EdgeSlideParams *slp = t->custom.mode.data;
+               EdgeSlideData *sld = TRANS_DATA_CONTAINER_FIRST_OK(t)->custom.mode.data;
                const bool is_clamp = !(t->flag & T_ALT_TRANSFORM);
 
                /* Even mode */
-               if ((sld->use_even == true) || (is_clamp == false)) {
+               if ((slp->use_even == true) || (is_clamp == false)) {
                        View3D *v3d = t->view;
                        const float line_size = UI_GetThemeValuef(TH_OUTLINE_WIDTH) + 0.5f;
 
@@ -6843,17 +6976,19 @@ static void drawEdgeSlide(TransInfo *t)
                                glDisable(GL_DEPTH_TEST);
 
                        glEnable(GL_BLEND);
-                       glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+                       glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+
+                       gpuPushMatrix();
+                       gpuMultMatrix(TRANS_DATA_CONTAINER_FIRST_OK(t)->obedit->obmat);
 
-                       glPushAttrib(GL_CURRENT_BIT | GL_LINE_BIT | GL_POINT_BIT);
-                       glPushMatrix();
+                       unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
 
-                       glMultMatrixf(t->obedit->obmat);
+                       immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
 
-                       if (sld->use_even == true) {
+                       if (slp->use_even == true) {
                                float co_a[3], co_b[3], co_mark[3];
                                TransDataEdgeSlideVert *curr_sv = &sld->sv[sld->curr_sv_index];
-                               const float fac = (sld->perc + 1.0f) / 2.0f;
+                               const float fac = (slp->perc + 1.0f) / 2.0f;
                                const float ctrl_size = UI_GetThemeValuef(TH_FACEDOT_SIZE) + 1.5f;
                                const float guide_size = ctrl_size - 0.5f;
                                const int alpha_shade = -30;
@@ -6862,39 +6997,35 @@ static void drawEdgeSlide(TransInfo *t)
                                add_v3_v3v3(co_b, curr_sv->v_co_orig, curr_sv->dir_side[1]);
 
                                glLineWidth(line_size);
-                               UI_ThemeColorShadeAlpha(TH_EDGE_SELECT, 80, alpha_shade);
-                               glBegin(GL_LINES);
+                               immUniformThemeColorShadeAlpha(TH_EDGE_SELECT, 80, alpha_shade);
+                               immBeginAtMost(GWN_PRIM_LINES, 4);
                                if (curr_sv->v_side[0]) {
-                                       glVertex3fv(curr_sv->v_side[0]->co);
-                                       glVertex3fv(curr_sv->v_co_orig);
+                                       immVertex3fv(pos, curr_sv->v_side[0]->co);
+                                       immVertex3fv(pos, curr_sv->v_co_orig);
                                }
                                if (curr_sv->v_side[1]) {
-                                       glVertex3fv(curr_sv->v_side[1]->co);
-                                       glVertex3fv(curr_sv->v_co_orig);
+                                       immVertex3fv(pos, curr_sv->v_side[1]->co);
+                                       immVertex3fv(pos, curr_sv->v_co_orig);
                                }
-                               glEnd();
+                               immEnd();
 
-                               UI_ThemeColorShadeAlpha(TH_SELECT, -30, alpha_shade);
+                               immUniformThemeColorShadeAlpha(TH_SELECT, -30, alpha_shade);
                                glPointSize(ctrl_size);
-                               glBegin(GL_POINTS);
-                               if (sld->flipped) {
-                                       if (curr_sv->v_side[1]) glVertex3fv(curr_sv->v_side[1]->co);
+                               immBegin(GWN_PRIM_POINTS, 1);
+                               if (slp->flipped) {
+                                       if (curr_sv->v_side[1]) immVertex3fv(pos, curr_sv->v_side[1]->co);
                                }
                                else {
-                                       if (curr_sv->v_side[0]) glVertex3fv(curr_sv->v_side[0]->co);
+                                       if (curr_sv->v_side[0]) immVertex3fv(pos, curr_sv->v_side[0]->co);
                                }
-                               glEnd();
+                               immEnd();
 
-                               UI_ThemeColorShadeAlpha(TH_SELECT, 255, alpha_shade);
+                               immUniformThemeColorShadeAlpha(TH_SELECT, 255, alpha_shade);
                                glPointSize(guide_size);
-                               glBegin(GL_POINTS);
-#if 0
-                               interp_v3_v3v3(co_mark, co_b, co_a, fac);
-                               glVertex3fv(co_mark);
-#endif
+                               immBegin(GWN_PRIM_POINTS, 1);
                                interp_line_v3_v3v3v3(co_mark, co_b, curr_sv->v_co_orig, co_a, fac);
-                               glVertex3fv(co_mark);
-                               glEnd();
+                               immVertex3fv(pos, co_mark);
+                               immEnd();
                        }
                        else {
                                if (is_clamp == false) {
@@ -6904,9 +7035,10 @@ static void drawEdgeSlide(TransInfo *t)
                                        const int alpha_shade = -160;
 
                                        glLineWidth(line_size);
-                                       UI_ThemeColorShadeAlpha(TH_EDGE_SELECT, 80, alpha_shade);
-                                       glBegin(GL_LINES);
+                                       immUniformThemeColorShadeAlpha(TH_EDGE_SELECT, 80, alpha_shade);
+                                       immBegin(GWN_PRIM_LINES, sld->totsv * 2);
 
+                                       /* TODO(campbell): Loop over all verts  */
                                        sv = sld->sv;
                                        for (i = 0; i < sld->totsv; i++, sv++) {
                                                float a[3], b[3];
@@ -6923,18 +7055,19 @@ static void drawEdgeSlide(TransInfo *t)
                                                add_v3_v3(a, sv->v_co_orig);
                                                add_v3_v3(b, sv->v_co_orig);
 
-                                               glVertex3fv(a);
-                                               glVertex3fv(b);
+                                               immVertex3fv(pos, a);
+                                               immVertex3fv(pos, b);
                                        }
-                                       glEnd();
+                                       immEnd();
                                }
                                else {
                                        BLI_assert(0);
                                }
                        }
 
-                       glPopMatrix();
-                       glPopAttrib();
+                       immUnbindProgram();
+
+                       gpuPopMatrix();
 
                        glDisable(GL_BLEND);
 
@@ -6946,38 +7079,43 @@ static void drawEdgeSlide(TransInfo *t)
 
 static void doEdgeSlide(TransInfo *t, float perc)
 {
-       EdgeSlideData *sld = t->custom.mode.data;
-       TransDataEdgeSlideVert *svlist = sld->sv, *sv;
-       int i;
+       EdgeSlideParams *slp = t->custom.mode.data;
+       EdgeSlideData *sld_active = TRANS_DATA_CONTAINER_FIRST_OK(t)->custom.mode.data;
 
-       sld->perc = perc;
-       sv = svlist;
+       slp->perc = perc;
 
-       if (sld->use_even == false) {
+       if (slp->use_even == false) {
                const bool is_clamp = !(t->flag & T_ALT_TRANSFORM);
                if (is_clamp) {
                        const int side_index = (perc < 0.0f);
                        const float perc_final = fabsf(perc);
-                       for (i = 0; i < sld->totsv; i++, sv++) {
-                               madd_v3_v3v3fl(sv->v->co, sv->v_co_orig, sv->dir_side[side_index], perc_final);
+                       FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+                               EdgeSlideData *sld = tc->custom.mode.data;
+                               TransDataEdgeSlideVert *sv = sld->sv;
+                               for (int i = 0; i < sld->totsv; i++, sv++) {
+                                       madd_v3_v3v3fl(sv->v->co, sv->v_co_orig, sv->dir_side[side_index], perc_final);
+                               }
+                               sld->curr_side_unclamp = side_index;
                        }
-
-                       sld->curr_side_unclamp = side_index;
                }
                else {
-                       const int side_index = sld->curr_side_unclamp;
-                       const float perc_init = fabsf(perc) * ((sld->curr_side_unclamp == (perc < 0.0f)) ? 1 : -1);
-                       for (i = 0; i < sld->totsv; i++, sv++) {
-                               float dir_flip[3];
-                               float perc_final = perc_init;
-                               if (!is_zero_v3(sv->dir_side[side_index])) {
-                                       copy_v3_v3(dir_flip, sv->dir_side[side_index]);
-                               }
-                               else {
-                                       copy_v3_v3(dir_flip, sv->dir_side[!side_index]);
-                                       perc_final *= -1;
+                       const float perc_init = fabsf(perc) * ((sld_active->curr_side_unclamp == (perc < 0.0f)) ? 1 : -1);
+                       const int side_index = sld_active->curr_side_unclamp;
+                       FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+                               EdgeSlideData *sld = tc->custom.mode.data;
+                               TransDataEdgeSlideVert *sv = sld->sv;
+                               for (int i = 0; i < sld->totsv; i++, sv++) {
+                                       float dir_flip[3];
+                                       float perc_final = perc_init;
+                                       if (!is_zero_v3(sv->dir_side[side_index])) {
+                                               copy_v3_v3(dir_flip, sv->dir_side[side_index]);
+                                       }
+                                       else {
+                                               copy_v3_v3(dir_flip, sv->dir_side[!side_index]);
+                                               perc_final *= -1;
+                                       }
+                                       madd_v3_v3v3fl(sv->v->co, sv->v_co_orig, dir_flip, perc_final);
                                }
-                               madd_v3_v3v3fl(sv->v->co, sv->v_co_orig, dir_flip, perc_final);
                        }
                }
        }
@@ -6990,24 +7128,28 @@ static void doEdgeSlide(TransInfo *t, float perc)
                 * \note len_v3v3(curr_sv->dir_side[0], curr_sv->dir_side[1])
                 * 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 ? perc : -perc) + 1.0f) / 2.0f);
+               TransDataEdgeSlideVert *curr_sv = &sld_active->sv[sld_active->curr_sv_index];
+               const float curr_length_perc = curr_sv->edge_len * (((slp->flipped ? perc : -perc) + 1.0f) / 2.0f);
 
                float co_a[3];
                float co_b[3];
 
-               for (i = 0; i < sld->totsv; i++, sv++) {
-                       if (sv->edge_len > FLT_EPSILON) {
-                               const float fac = min_ff(sv->edge_len, curr_length_perc) / sv->edge_len;
+               FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+                       EdgeSlideData *sld = tc->custom.mode.data;
+                       TransDataEdgeSlideVert *sv = sld->sv;
+                       for (int 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(co_a, sv->v_co_orig, sv->dir_side[0]);
-                               add_v3_v3v3(co_b, sv->v_co_orig, sv->dir_side[1]);
+                                       add_v3_v3v3(co_a, sv->v_co_orig, sv->dir_side[0]);
+                                       add_v3_v3v3(co_b, sv->v_co_orig, sv->dir_side[1]);
 
-                               if (sld->flipped) {
-                                       interp_line_v3_v3v3v3(sv->v->co, co_b, sv->v_co_orig, co_a, fac);
-                               }
-                               else {
-                                       interp_line_v3_v3v3v3(sv->v->co, co_a, sv->v_co_orig, co_b, fac);
+                                       if (slp->flipped) {
+                                               interp_line_v3_v3v3v3(sv->v->co, co_b, sv->v_co_orig, co_a, fac);
+                                       }
+                                       else {
+                                               interp_line_v3_v3v3v3(sv->v->co, co_a, sv->v_co_orig, co_b, fac);
+                                       }
                                }
                        }
                }
@@ -7019,9 +7161,9 @@ static void applyEdgeSlide(TransInfo *t, const int UNUSED(mval[2]))
        char str[UI_MAX_DRAW_STR];
        size_t ofs = 0;
        float final;
-       EdgeSlideData *sld =  t->custom.mode.data;
-       bool flipped = sld->flipped;
-       bool use_even = sld->use_even;
+       EdgeSlideParams *slp =  t->custom.mode.data;
+       bool flipped = slp->flipped;
+       bool use_even = slp->use_even;
        const bool is_clamp = !(t->flag & T_ALT_TRANSFORM);
        const bool is_constrained = !(is_clamp == false || hasNumInput(&t->num));
 
@@ -7073,7 +7215,8 @@ static void applyEdgeSlide(TransInfo *t, const int UNUSED(mval[2]))
 
 static void calcVertSlideCustomPoints(struct TransInfo *t)
 {
-       VertSlideData *sld = t->custom.mode.data;
+       VertSlideParams *slp = t->custom.mode.data;
+       VertSlideData *sld = TRANS_DATA_CONTAINER_FIRST_OK(t)->custom.mode.data;
        TransDataVertSlideVert *sv = &sld->sv[sld->curr_sv_index];
 
        const float *co_orig_3d = sv->co_orig_3d;
@@ -7090,7 +7233,7 @@ static void calcVertSlideCustomPoints(struct TransInfo *t)
        ARRAY_SET_ITEMS(mval_start, co_orig_2d[0] + mval_ofs[0], co_orig_2d[1] + mval_ofs[1]);
        ARRAY_SET_ITEMS(mval_end, co_curr_2d[0] + mval_ofs[0], co_curr_2d[1] + mval_ofs[1]);
 
-       if (sld->flipped && sld->use_even) {
+       if (slp->flipped && slp->use_even) {
                setCustomPoints(t, &t->mouse, mval_start, mval_end);
        }
        else {
@@ -7108,7 +7251,8 @@ static void calcVertSlideCustomPoints(struct TransInfo *t)
  */
 static void calcVertSlideMouseActiveVert(struct TransInfo *t, const int mval[2])
 {
-       VertSlideData *sld = t->custom.mode.data;
+       /* Active object may have no selected vertices. */
+       VertSlideData *sld = TRANS_DATA_CONTAINER_FIRST_OK(t)->custom.mode.data;
        float mval_fl[2] = {UNPACK2(mval)};
        TransDataVertSlideVert *sv;
 
@@ -7135,7 +7279,7 @@ static void calcVertSlideMouseActiveVert(struct TransInfo *t, const int mval[2])
  */
 static void calcVertSlideMouseActiveEdges(struct TransInfo *t, const int mval[2])
 {
-       VertSlideData *sld = t->custom.mode.data;
+       VertSlideData *sld = TRANS_DATA_CONTAINER_FIRST_OK(t)->custom.mode.data;
        float imval_fl[2] = {UNPACK2(t->mouse.imval)};
        float  mval_fl[2] = {UNPACK2(mval)};
 
@@ -7163,7 +7307,7 @@ static void calcVertSlideMouseActiveEdges(struct TransInfo *t, const int mval[2]
                                float dir_dot;
 
                                sub_v3_v3v3(tdir, sv->co_orig_3d, sv->co_link_orig_3d[j]);
-                               mul_mat3_m4_v3(t->obedit->obmat, tdir);
+                               mul_mat3_m4_v3(TRANS_DATA_CONTAINER_FIRST_OK(t)->obedit->obmat, tdir);
                                project_plane_v3_v3v3(tdir, tdir, t->viewinv[2]);
 
                                normalize_v3(tdir);
@@ -7181,9 +7325,9 @@ static void calcVertSlideMouseActiveEdges(struct TransInfo *t, const int mval[2]
        }
 }
 
-static bool createVertSlideVerts(TransInfo *t, bool use_even, bool flipped, bool use_clamp)
+static bool createVertSlideVerts(TransInfo *t, TransDataContainer *tc)
 {
-       BMEditMesh *em = BKE_editmesh_from_object(t->obedit);
+       BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
        BMesh *bm = em->bm;
        BMIter iter;
        BMIter eiter;
@@ -7193,13 +7337,9 @@ static bool createVertSlideVerts(TransInfo *t, bool use_even, bool flipped, bool
        VertSlideData *sld = MEM_callocN(sizeof(*sld), "sld");
        int j;
 
-       slide_origdata_init_flag(t, &sld->orig_data);
+       slide_origdata_init_flag(t, tc, &sld->orig_data);
 
-       sld->use_even = use_even;
        sld->curr_sv_index = 0;
-       sld->flipped = flipped;
-       if (!use_clamp)
-               t->flag |= T_ALT_TRANSFORM;
 
        j = 0;
        BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
@@ -7262,14 +7402,12 @@ static bool createVertSlideVerts(TransInfo *t, bool use_even, bool flipped, bool
        sld->totsv = j;
 
        bmesh_edit_begin(bm, BMO_OPTYPE_FLAG_UNTAN_MULTIRES);
-       slide_origdata_init_data(t, &sld->orig_data);
-       slide_origdata_create_data(t, &sld->orig_data, (TransDataGenericSlideVert *)sld->sv, sizeof(*sld->sv), sld->totsv);
+       slide_origdata_init_data(tc, &sld->orig_data);
+       slide_origdata_create_data(t, tc, &sld->orig_data, (TransDataGenericSlideVert *)sld->sv, sizeof(*sld->sv), sld->totsv);
 
        sld->em = em;
 
-       sld->perc = 0.0f;
-
-       t->custom.mode.data = sld;
+       tc->custom.mode.data = sld;
 
        /* most likely will be set below */
        unit_m4(sld->proj_mat);
@@ -7281,9 +7419,12 @@ static bool createVertSlideVerts(TransInfo *t, bool use_even, bool flipped, bool
 
                rv3d = ar ? ar->regiondata : NULL;
                if (rv3d) {
-                       ED_view3d_ob_project_mat_get(rv3d, t->obedit, sld->proj_mat);
+                       ED_view3d_ob_project_mat_get(rv3d, tc->obedit, sld->proj_mat);
                }
+       }
 
+       /* XXX, calc vert slide across all objects */
+       if (tc == t->data_container) {
                calcVertSlideMouseActiveVert(t, t->mval);
                calcVertSlideMouseActiveEdges(t, t->mval);
        }
@@ -7293,14 +7434,13 @@ static bool createVertSlideVerts(TransInfo *t, bool use_even, bool flipped, bool
 
 void projectVertSlideData(TransInfo *t, bool is_final)
 {
-       VertSlideData *sld = t->custom.mode.data;
-       SlideOrigData *sod = &sld->orig_data;
-
-       if (sod->use_origfaces == false) {
-               return;
+       FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+               VertSlideData *sld = tc->custom.mode.data;
+               SlideOrigData *sod = &sld->orig_data;
+               if (sod->use_origfaces == true) {
+                       slide_origdata_interp_data(tc->obedit, sod, (TransDataGenericSlideVert *)sld->sv, sizeof(*sld->sv), sld->totsv, is_final);
+               }
        }
-
-       slide_origdata_interp_data(t, sod, (TransDataGenericSlideVert *)sld->sv, sizeof(*sld->sv), sld->totsv, is_final);
 }
 
 void freeVertSlideTempFaces(VertSlideData *sld)
@@ -7308,7 +7448,7 @@ void freeVertSlideTempFaces(VertSlideData *sld)
        slide_origdata_free_date(&sld->orig_data);
 }
 
-void freeVertSlideVerts(TransInfo *UNUSED(t), TransCustomData *custom_data)
+void freeVertSlideVerts(TransInfo *UNUSED(t), TransDataContainer *UNUSED(tc), TransCustomData *custom_data)
 {
        VertSlideData *sld = custom_data->data;
 
@@ -7335,23 +7475,38 @@ void freeVertSlideVerts(TransInfo *UNUSED(t), TransCustomData *custom_data)
 
 static void initVertSlide_ex(TransInfo *t, bool use_even, bool flipped, bool use_clamp)
 {
-       VertSlideData *sld;
 
        t->mode = TFM_VERT_SLIDE;
        t->transform = applyVertSlide;
        t->handleEvent = handleEventVertSlide;
 
-       if (!createVertSlideVerts(t, use_even, flipped, use_clamp)) {
-               t->state = TRANS_CANCEL;
-               return;
+       {
+               VertSlideParams *slp = MEM_callocN(sizeof(*slp), __func__);
+               slp->use_even = use_even;
+               slp->flipped = flipped;
+               slp->perc = 0.0f;
+
+               if (!use_clamp) {
+                       t->flag |= T_ALT_TRANSFORM;
+               }
+
+               t->custom.mode.data = slp;
+               t->custom.mode.use_free = true;
        }
 
-       sld = t->custom.mode.data;
+       bool ok = false;
+       FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+               ok |= createVertSlideVerts(t, tc);
+               VertSlideData *sld = tc->custom.mode.data;
+               if (sld) {
+                       tc->custom.mode.free_cb = freeVertSlideVerts;
+               }
+       }
 
-       if (!sld)
+       if (ok == false) {
+               t->state = TRANS_CANCEL;
                return;
-
-       t->custom.mode.free_cb = freeVertSlideVerts;
+       }
 
        /* set custom point first if you want value to be initialized by init */
        calcVertSlideCustomPoints(t);
@@ -7378,14 +7533,14 @@ static void initVertSlide(TransInfo *t)
 static eRedrawFlag handleEventVertSlide(struct TransInfo *t, const struct wmEvent *event)
 {
        if (t->mode == TFM_VERT_SLIDE) {
-               VertSlideData *sld = t->custom.mode.data;
+               VertSlideParams *slp = t->custom.mode.data;
 
-               if (sld) {
+               if (slp) {
                        switch (event->type) {
                                case EKEY:
                                        if (event->val == KM_PRESS) {
-                                               sld->use_even = !sld->use_even;
-                                               if (sld->flipped) {
+                                               slp->use_even = !slp->use_even;
+                                               if (slp->flipped) {
                                                        calcVertSlideCustomPoints(t);
                                                }
                                                return TREDRAW_HARD;
@@ -7393,7 +7548,7 @@ static eRedrawFlag handleEventVertSlide(struct TransInfo *t, const struct wmEven
                                        break;
                                case FKEY:
                                        if (event->val == KM_PRESS) {
-                                               sld->flipped = !sld->flipped;
+                                               slp->flipped = !slp->flipped;
                                                calcVertSlideCustomPoints(t);
                                                return TREDRAW_HARD;
                                        }
@@ -7438,8 +7593,9 @@ static eRedrawFlag handleEventVertSlide(struct TransInfo *t, const struct wmEven
 
 static void drawVertSlide(TransInfo *t)
 {
-       if ((t->mode == TFM_VERT_SLIDE) && t->custom.mode.data) {
-               VertSlideData *sld = t->custom.mode.data;
+       if ((t->mode == TFM_VERT_SLIDE) && TRANS_DATA_CONTAINER_FIRST_OK(t)->custom.mode.data) {
+               const VertSlideParams *slp = t->custom.mode.data;
+               VertSlideData *sld = TRANS_DATA_CONTAINER_FIRST_OK(t)->custom.mode.data;
                const bool is_clamp = !(t->flag & T_ALT_TRANSFORM);
 
                /* Non-Prop mode */
@@ -7456,21 +7612,24 @@ static void drawVertSlide(TransInfo *t)
                                glDisable(GL_DEPTH_TEST);
 
                        glEnable(GL_BLEND);
-                       glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+                       glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
 
-                       glPushAttrib(GL_CURRENT_BIT | GL_LINE_BIT | GL_POINT_BIT);
-                       glPushMatrix();
-
-                       glMultMatrixf(t->obedit->obmat);
+                       gpuPushMatrix();
+                       gpuMultMatrix(TRANS_DATA_CONTAINER_FIRST_OK(t)->obedit->obmat);
 
                        glLineWidth(line_size);
-                       UI_ThemeColorShadeAlpha(TH_EDGE_SELECT, 80, alpha_shade);
-                       glBegin(GL_LINES);
+
+                       const uint shdr_pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+
+                       immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+                       immUniformThemeColorShadeAlpha(TH_EDGE_SELECT, 80, alpha_shade);
+
+                       immBegin(GWN_PRIM_LINES, sld->totsv * 2);
                        if (is_clamp) {
                                sv = sld->sv;
                                for (i = 0; i < sld->totsv; i++, sv++) {
-                                       glVertex3fv(sv->co_orig_3d);
-                                       glVertex3fv(sv->co_link_orig_3d[sv->co_link_curr]);
+                                       immVertex3fv(shdr_pos, sv->co_orig_3d);
+                                       immVertex3fv(shdr_pos, sv->co_link_orig_3d[sv->co_link_curr]);
                                }
                        }
                        else {
@@ -7483,21 +7642,21 @@ static void drawVertSlide(TransInfo *t)
                                        add_v3_v3(a, sv->co_orig_3d);
                                        add_v3_v3(b, sv->co_orig_3d);
 
-                                       glVertex3fv(a);
-                                       glVertex3fv(b);
+                                       immVertex3fv(shdr_pos, a);
+                                       immVertex3fv(shdr_pos, b);
                                }
                        }
-                       glEnd();
+                       immEnd();
 
                        glPointSize(ctrl_size);
 
-                       glBegin(GL_POINTS);
-                       glVertex3fv((sld->flipped && sld->use_even) ?
+                       immBegin(GWN_PRIM_POINTS, 1);
+                       immVertex3fv(shdr_pos, (slp->flipped && slp->use_even) ?
                                    curr_sv->co_link_orig_3d[curr_sv->co_link_curr] :
                                    curr_sv->co_orig_3d);
-                       glEnd();
+                       immEnd();
 
-                       glDisable(GL_BLEND);
+                       immUnbindProgram();
 
                        /* direction from active vertex! */
                        if ((t->mval[0] != t->mouse.imval[0]) ||
@@ -7511,29 +7670,38 @@ static void drawVertSlide(TransInfo *t)
                                mval_ofs[0] = t->mval[0] - t->mouse.imval[0];
                                mval_ofs[1] = t->mval[1] - t->mouse.imval[1];
 
-                               mul_v3_m4v3(co_orig_3d, t->obedit->obmat, curr_sv->co_orig_3d);
+                               mul_v3_m4v3(co_orig_3d, TRANS_DATA_CONTAINER_FIRST_OK(t)->obedit->obmat, curr_sv->co_orig_3d);
                                zfac = ED_view3d_calc_zfac(t->ar->regiondata, co_orig_3d, NULL);
 
                                ED_view3d_win_to_delta(t->ar, mval_ofs, co_dest_3d, zfac);
 
-                               invert_m4_m4(t->obedit->imat, t->obedit->obmat);
-                               mul_mat3_m4_v3(t->obedit->imat, co_dest_3d);
+                               invert_m4_m4(TRANS_DATA_CONTAINER_FIRST_OK(t)->obedit->imat, TRANS_DATA_CONTAINER_FIRST_OK(t)->obedit->obmat);
+                               mul_mat3_m4_v3(TRANS_DATA_CONTAINER_FIRST_OK(t)->obedit->imat, co_dest_3d);
 
                                add_v3_v3(co_dest_3d, curr_sv->co_orig_3d);
 
-                               glLineWidth(1);
-                               setlinestyle(1);
+                               glLineWidth(1.0f);
 
-                               cpack(0xffffff);
-                               glBegin(GL_LINES);
-                               glVertex3fv(curr_sv->co_orig_3d);
-                               glVertex3fv(co_dest_3d);
+                               immBindBuiltinProgram(GPU_SHADER_3D_LINE_DASHED_UNIFORM_COLOR);
 
-                               glEnd();
+                               float viewport_size[4];
+                               glGetFloatv(GL_VIEWPORT, viewport_size);
+                               immUniform2f("viewport_size", viewport_size[2], viewport_size[3]);
+
+                               immUniform1i("num_colors", 0);  /* "simple" mode */
+                               immUniformColor4f(1.0f, 1.0f, 1.0f, 1.0f);
+                               immUniform1f("dash_width", 6.0f);
+                               immUniform1f("dash_factor", 0.5f);
+
+                               immBegin(GWN_PRIM_LINES, 2);
+                               immVertex3fv(shdr_pos, curr_sv->co_orig_3d);
+                               immVertex3fv(shdr_pos, co_dest_3d);
+                               immEnd();
+
+                               immUnbindProgram();
                        }
 
-                       glPopMatrix();
-                       glPopAttrib();
+                       gpuPopMatrix();
 
                        if (v3d && v3d->zbuf)
                                glEnable(GL_DEPTH_TEST);
@@ -7543,41 +7711,46 @@ static void drawVertSlide(TransInfo *t)
 
 static void doVertSlide(TransInfo *t, float perc)
 {
-       VertSlideData *sld = t->custom.mode.data;
-       TransDataVertSlideVert *svlist = sld->sv, *sv;
-       int i;
+       VertSlideParams *slp = t->custom.mode.data;
 
-       sld->perc = perc;
-       sv = svlist;
+       slp->perc = perc;
 
-       if (sld->use_even == false) {
-               for (i = 0; i < sld->totsv; i++, sv++) {
-                       interp_v3_v3v3(sv->v->co, sv->co_orig_3d, sv->co_link_orig_3d[sv->co_link_curr], perc);
+       FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+               VertSlideData *sld = tc->custom.mode.data;
+               TransDataVertSlideVert *svlist = sld->sv, *sv;
+               int i;
+
+               sv = svlist;
+
+               if (slp->use_even == false) {
+                       for (i = 0; i < sld->totsv; i++, sv++) {
+                               interp_v3_v3v3(sv->v->co, sv->co_orig_3d, sv->co_link_orig_3d[sv->co_link_curr], perc);
+                       }
                }
-       }
-       else {
-               TransDataVertSlideVert *sv_curr = &sld->sv[sld->curr_sv_index];
-               const float edge_len_curr = len_v3v3(sv_curr->co_orig_3d, sv_curr->co_link_orig_3d[sv_curr->co_link_curr]);
-               const float tperc = perc * edge_len_curr;
+               else {
+                       TransDataVertSlideVert *sv_curr = &sld->sv[sld->curr_sv_index];
+                       const float edge_len_curr = len_v3v3(sv_curr->co_orig_3d, sv_curr->co_link_orig_3d[sv_curr->co_link_curr]);
+                       const float tperc = perc * edge_len_curr;
 
-               for (i = 0; i < sld->totsv; i++, sv++) {
-                       float edge_len;
-                       float dir[3];
+                       for (i = 0; i < sld->totsv; i++, sv++) {
+                               float edge_len;
+                               float dir[3];
 
-                       sub_v3_v3v3(dir, sv->co_link_orig_3d[sv->co_link_curr], sv->co_orig_3d);
-                       edge_len = normalize_v3(dir);
+                               sub_v3_v3v3(dir, sv->co_link_orig_3d[sv->co_link_curr], sv->co_orig_3d);
+                               edge_len = normalize_v3(dir);
 
-                       if (edge_len > FLT_EPSILON) {
-                               if (sld->flipped) {
-                                       madd_v3_v3v3fl(sv->v->co, sv->co_link_orig_3d[sv->co_link_curr], dir, -tperc);
+                               if (edge_len > FLT_EPSILON) {
+                                       if (slp->flipped) {
+                                               madd_v3_v3v3fl(sv->v->co, sv->co_link_orig_3d[sv->co_link_curr], dir, -tperc);
+                                       }
+                                       else {
+                                               madd_v3_v3v3fl(sv->v->co, sv->co_orig_3d, dir, tperc);
+                                       }
                                }
                                else {
-                                       madd_v3_v3v3fl(sv->v->co, sv->co_orig_3d, dir, tperc);
+                                       copy_v3_v3(sv->v->co, sv->co_orig_3d);
                                }
                        }
-                       else {
-                               copy_v3_v3(sv->v->co, sv->co_orig_3d);
-                       }
                }
        }
 }
@@ -7587,9 +7760,9 @@ static void applyVertSlide(TransInfo *t, const int UNUSED(mval[2]))
        char str[UI_MAX_DRAW_STR];
        size_t ofs = 0;
        float final;
-       VertSlideData *sld =  t->custom.mode.data;
-       const bool flipped = sld->flipped;
-       const bool use_even = sld->use_even;
+       VertSlideParams *slp =  t->custom.mode.data;
+       const bool flipped = slp->flipped;
+       const bool use_even = slp->use_even;
        const bool is_clamp = !(t->flag & T_ALT_TRANSFORM);
        const bool is_constrained = !(is_clamp == false || hasNumInput(&t->num));
 
@@ -7662,7 +7835,6 @@ static void initBoneRoll(TransInfo *t)
 
 static void applyBoneRoll(TransInfo *t, const int UNUSED(mval[2]))
 {
-       TransData *td = t->data;
        int i;
        char str[UI_MAX_DRAW_STR];
 
@@ -7688,14 +7860,17 @@ static void applyBoneRoll(TransInfo *t, const int UNUSED(mval[2]))
        }
 
        /* set roll values */
-       for (i = 0; i < t->total; i++, td++) {
-               if (td->flag & TD_NOACTION)
-                       break;
+       FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+               TransData *td = tc->data;
+               for (i = 0; i < tc->data_len; i++, td++) {
+                       if (td->flag & TD_NOACTION)
+                               break;
 
-               if (td->flag & TD_SKIP)
-                       continue;
+                       if (td->flag & TD_SKIP)
+                               continue;
 
-               *(td->val) = td->ival - final;
+                       *(td->val) = td->ival - final;
+               }
        }
 
        recalcData(t);
@@ -7729,7 +7904,6 @@ static void initBakeTime(TransInfo *t)
 
 static void applyBakeTime(TransInfo *t, const int mval[2])
 {
-       TransData *td = t->data;
        float time;
        int i;
        char str[UI_MAX_DRAW_STR];
@@ -7773,17 +7947,20 @@ static void applyBakeTime(TransInfo *t, const int mval[2])
                        BLI_snprintf(str, sizeof(str), IFACE_("Time: %.3f %s"), time, t->proptext);
        }
 
-       for (i = 0; i < t->total; i++, td++) {
-               if (td->flag & TD_NOACTION)
-                       break;
+       FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+               TransData *td = tc->data;
+               for (i = 0; i < tc->data_len; i++, td++) {
+                       if (td->flag & TD_NOACTION)
+                               break;
 
-               if (td->flag & TD_SKIP)
-                       continue;
+                       if (td->flag & TD_SKIP)
+                               continue;
 
-               if (td->val) {
-                       *td->val = td->ival + time * td->factor;
-                       if (td->ext->size && *td->val < *td->ext->size) *td->val = *td->ext->size;
-                       if (td->ext->quat && *td->val > *td->ext->quat) *td->val = *td->ext->quat;
+                       if (td->val) {
+                               *td->val = td->ival + time * td->factor;
+                               if (td->ext->size && *td->val < *td->ext->size) *td->val = *td->ext->size;
+                               if (td->ext->quat && *td->val > *td->ext->quat) *td->val = *td->ext->quat;
+                       }
                }
        }
 
@@ -7806,14 +7983,13 @@ static void initMirror(TransInfo *t)
        initMouseInputMode(t, &t->mouse, INPUT_NONE);
 
        t->flag |= T_NULL_ONE;
-       if (!t->obedit) {
+       if ((t->flag & T_EDIT) == 0) {
                t->flag |= T_NO_ZERO;
        }
 }
 
 static void applyMirror(TransInfo *t, const int UNUSED(mval[2]))
 {
-       TransData *td;
        float size[3], mat[3][3];
        int i;
        char str[UI_MAX_DRAW_STR];
@@ -7831,19 +8007,22 @@ static void applyMirror(TransInfo *t, const int UNUSED(mval[2]))
                size_to_mat3(mat, size);
 
                if (t->con.applySize) {
-                       t->con.applySize(t, NULL, mat);
+                       t->con.applySize(t, NULL, NULL, mat);
                }
 
                BLI_snprintf(str, sizeof(str), IFACE_("Mirror%s"), t->con.text);
 
-               for (i = 0, td = t->data; i < t->total; i++, td++) {
-                       if (td->flag & TD_NOACTION)
-                               break;
+               FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+                       TransData *td = tc->data;
+                       for (i = 0; i < tc->data_len; i++, td++) {
+                               if (td->flag & TD_NOACTION)
+                                       break;
 
-                       if (td->flag & TD_SKIP)
-                               continue;
+                               if (td->flag & TD_SKIP)
+                                       continue;
 
-                       ElementResize(t, td, mat);
+                               ElementResize(t, tc, td, mat);
+                       }
                }
 
                recalcData(t);
@@ -7855,14 +8034,17 @@ static void applyMirror(TransInfo *t, const int UNUSED(mval[2]))
 
                size_to_mat3(mat, size);
 
-               for (i = 0, td = t->data; i < t->total; i++, td++) {
-                       if (td->flag & TD_NOACTION)
-                               break;
+               FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+                       TransData *td = tc->data;
+                       for (i = 0; i < tc->data_len; i++, td++) {
+                               if (td->flag & TD_NOACTION)
+                                       break;
 
-                       if (td->flag & TD_SKIP)
-                               continue;
+                               if (td->flag & TD_SKIP)
+                                       continue;
 
-                       ElementResize(t, td, mat);
+                               ElementResize(t, tc, td, mat);
+                       }
                }
 
                recalcData(t);
@@ -7893,42 +8075,43 @@ static void initAlign(TransInfo *t)
 
 static void applyAlign(TransInfo *t, const int UNUSED(mval[2]))
 {
-       TransData *td = t->data;
        float center[3];
        int i;
 
-       /* saving original center */
-       copy_v3_v3(center, t->center);
 
-       for (i = 0; i < t->total; i++, td++) {
-               float mat[3][3], invmat[3][3];
+       FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+               /* saving original center */
+               copy_v3_v3(center, tc->center_local);
+               TransData *td = tc->data;
+               for (i = 0; i < tc->data_len; i++, td++) {
+                       float mat[3][3], invmat[3][3];
 
-               if (td->flag & TD_NOACTION)
-                       break;
+                       if (td->flag & TD_NOACTION)
+                               break;
 
-               if (td->flag & TD_SKIP)
-                       continue;
+                       if (td->flag & TD_SKIP)
+                               continue;
 
-               /* around local centers */
-               if (t->flag & (T_OBJECT | T_POSE)) {
-                       copy_v3_v3(t->center, td->center);
-               }
-               else {
-                       if (t->settings->selectmode & SCE_SELECT_FACE) {
-                               copy_v3_v3(t->center, td->center);
+                       /* around local centers */
+                       if (t->flag & (T_OBJECT | T_POSE)) {
+                               copy_v3_v3(tc->center_local, td->center);
+                       }
+                       else {
+                               if (t->settings->selectmode & SCE_SELECT_FACE) {
+                                       copy_v3_v3(tc->center_local, td->center);
+                               }
                        }
-               }
 
-               invert_m3_m3(invmat, td->axismtx);
+                       invert_m3_m3(invmat, td->axismtx);
 
-               mul_m3_m3m3(mat, t->spacemtx, invmat);
+                       mul_m3_m3m3(mat, t->spacemtx, invmat);
 
-               ElementRotation(t, td, mat, t->around);
+                       ElementRotation(t, tc, td, mat, t->around);
+               }
+               /* restoring original center */
+               copy_v3_v3(tc->center_local, center);
        }
 
-       /* restoring original center */
-       copy_v3_v3(t->center, center);
-
        recalcData(t);
 
        ED_area_headerprint(t->sa, IFACE_("Align"));
@@ -7989,17 +8172,19 @@ static void headerSeqSlide(TransInfo *t, const float val[2], char str[UI_MAX_DRA
 
 static void applySeqSlideValue(TransInfo *t, const float val[2])
 {
-       TransData *td = t->data;
        int i;
 
-       for (i = 0; i < t->total; i++, td++) {
-               if (td->flag & TD_NOACTION)
-                       break;
+       FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+               TransData *td = tc->data;
+               for (i = 0; i < tc->data_len; i++, td++) {
+                       if (td->flag & TD_NOACTION)
+                               break;
 
-               if (td->flag & TD_SKIP)
-                       continue;
+                       if (td->flag & TD_SKIP)
+                               continue;
 
-               madd_v2_v2v2fl(td->loc, td->iloc, val, td->factor);
+                       madd_v2_v2v2fl(td->loc, td->iloc, val, td->factor);
+               }
        }
 }
 
@@ -8012,7 +8197,7 @@ static void applySeqSlide(TransInfo *t, const int mval[2])
        if (t->con.mode & CON_APPLY) {
                float pvec[3] = {0.0f, 0.0f, 0.0f};
                float tvec[3];
-               t->con.applyVec(t, NULL, t->values, tvec, pvec);
+               t->con.applyVec(t, NULL, NULL, t->values, tvec, pvec);
                copy_v3_v3(t->values, tvec);
        }
        else {
@@ -8232,8 +8417,6 @@ static void headerTimeTranslate(TransInfo *t, char str[UI_MAX_DRAW_STR])
 
 static void applyTimeTranslateValue(TransInfo *t)
 {
-       TransData *td = t->data;
-       TransData2D *td2d = t->data2d;
        Scene *scene = t->scene;
        int i;
 
@@ -8242,46 +8425,50 @@ static void applyTimeTranslateValue(TransInfo *t)
 
        float deltax, val /* , valprev */;
 
-       /* it doesn't matter whether we apply to t->data or t->data2d, but t->data2d is more convenient */
-       for (i = 0; i < t->total; i++, td++, td2d++) {
-               /* it is assumed that td->extra is a pointer to the AnimData,
-                * whose active action is where this keyframe comes from
-                * (this is only valid when not in NLA)
-                */
-               AnimData *adt = (t->spacetype != SPACE_NLA) ? td->extra : NULL;
+       FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+               TransData *td = tc->data;
+               TransData2D *td2d = tc->data_2d;
+               /* it doesn't matter whether we apply to t->data or t->data2d, but t->data2d is more convenient */
+               for (i = 0; i < tc->data_len; i++, td++, td2d++) {
+                       /* it is assumed that td->extra is a pointer to the AnimData,
+                        * whose active action is where this keyframe comes from
+                        * (this is only valid when not in NLA)
+                        */
+                       AnimData *adt = (t->spacetype != SPACE_NLA) ? td->extra : NULL;
 
-               /* valprev = *td->val; */ /* UNUSED */
+                       /* valprev = *td->val; */ /* UNUSED */
 
-               /* check if any need to apply nla-mapping */
-               if (adt && (t->spacetype != SPACE_SEQ)) {
-                       deltax = t->values[0];
+                       /* check if any need to apply nla-mapping */
+                       if (adt && (t->spacetype != SPACE_SEQ)) {
+                               deltax = t->values[0];
 
-                       if (autosnap == SACTSNAP_TSTEP) {
-                               deltax = (float)(floor(((double)deltax / secf) + 0.5) * secf);
-                       }
-                       else if (autosnap == SACTSNAP_STEP) {
-                               deltax = floorf(deltax + 0.5f);
+                               if (autosnap == SACTSNAP_TSTEP) {
+                                       deltax = (float)(floor(((double)deltax / secf) + 0.5) * secf);
+                               }
+                               else if (autosnap == SACTSNAP_STEP) {
+                                       deltax = floorf(deltax + 0.5f);
+                               }
+
+                               val = BKE_nla_tweakedit_remap(adt, td->ival, NLATIME_CONVERT_MAP);
+                               val += deltax * td->factor;
+                               *(td->val) = BKE_nla_tweakedit_remap(adt, val, NLATIME_CONVERT_UNMAP);
                        }
+                       else {
+                               deltax = val = t->values[0];
 
-                       val = BKE_nla_tweakedit_remap(adt, td->ival, NLATIME_CONVERT_MAP);
-                       val += deltax * td->factor;
-                       *(td->val) = BKE_nla_tweakedit_remap(adt, val, NLATIME_CONVERT_UNMAP);
-               }
-               else {
-                       deltax = val = t->values[0];
+                               if (autosnap == SACTSNAP_TSTEP) {
+                                       val = (float)(floor(((double)deltax / secf) + 0.5) * secf);
+                               }
+                               else if (autosnap == SACTSNAP_STEP) {
+                                       val = floorf(val + 0.5f);
+                               }
 
-                       if (autosnap == SACTSNAP_TSTEP) {
-                               val = (float)(floor(((double)deltax / secf) + 0.5) * secf);
-                       }
-                       else if (autosnap == SACTSNAP_STEP) {
-                               val = floorf(val + 0.5f);
+                               *(td->val) = td->ival + val;
                        }
 
-                       *(td->val) = td->ival + val;
+                       /* apply nearest snapping */
+                       doAnimEdit_SnapFrame(t, td, td2d, adt, autosnap);
                }
-
-               /* apply nearest snapping */
-               doAnimEdit_SnapFrame(t, td, td2d, adt, autosnap);
        }
 }
 
@@ -8348,18 +8535,19 @@ static void initTimeSlide(TransInfo *t)
 
                float min = 999999999.0f, max = -999999999.0f;
                int i;
+               FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+                       TransData *td = tc->data;
+                       for (i = 0; i < tc->data_len; i++, td++) {
+                               AnimData *adt = (t->spacetype != SPACE_NLA) ? td->extra : NULL;
+                               float val = *(td->val);
 
-               TransData  *td = t->data;
-               for (i = 0; i < t->total; i++, td++) {
-                       AnimData *adt = (t->spacetype != SPACE_NLA) ? td->extra : NULL;
-                       float val = *(td->val);
-
-                       /* strip/action time to global (mapped) time */
-                       if (adt)
-                               val = BKE_nla_tweakedit_remap(adt, val, NLATIME_CONVERT_MAP);
+                               /* strip/action time to global (mapped) time */
+                               if (adt)
+                                       val = BKE_nla_tweakedit_remap(adt, val, NLATIME_CONVERT_MAP);
 
-                       if (min > val) min = val;
-                       if (max < val) max = val;
+                               if (min > val) min = val;
+                               if (max < val) max = val;
+                       }
                }
 
                if (min == max) {
@@ -8412,7 +8600,6 @@ static void headerTimeSlide(TransInfo *t, const float sval, char str[UI_MAX_DRAW
 
 static void applyTimeSlideValue(TransInfo *t, float sval)
 {
-       TransData *td = t->data;
        int i;
        const float *range = t->custom.mode.data;
        float minx = range[0];
@@ -8427,44 +8614,47 @@ static void applyTimeSlideValue(TransInfo *t, float sval)
        }
 
        /* it doesn't matter whether we apply to t->data or t->data2d, but t->data2d is more convenient */
-       for (i = 0; i < t->total; i++, td++) {
-               /* it is assumed that td->extra is a pointer to the AnimData,
-                * whose active action is where this keyframe comes from
-                * (this is only valid when not in NLA)
-                */
-               AnimData *adt = (t->spacetype != SPACE_NLA) ? td->extra : NULL;
-               float cval = t->values[0];
-
-               /* only apply to data if in range */
-               if ((sval > minx) && (sval < maxx)) {
-                       float cvalc = CLAMPIS(cval, minx, maxx);
-                       float ival = td->ival;
-                       float timefac;
-
-                       /* NLA mapping magic here works as follows:
-                        * - "ival" goes from strip time to global time
-                        * - calculation is performed into td->val in global time
-                        *   (since sval and min/max are all in global time)
-                        * - "td->val" then gets put back into strip time
+       FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+               TransData *td = tc->data;
+               for (i = 0; i < tc->data_len; i++, td++) {
+                       /* it is assumed that td->extra is a pointer to the AnimData,
+                        * whose active action is where this keyframe comes from
+                        * (this is only valid when not in NLA)
                         */
-                       if (adt) {
-                               /* strip to global */
-                               ival = BKE_nla_tweakedit_remap(adt, ival, NLATIME_CONVERT_MAP);
-                       }
+                       AnimData *adt = (t->spacetype != SPACE_NLA) ? td->extra : NULL;
+                       float cval = t->values[0];
+
+                       /* only apply to data if in range */
+                       if ((sval > minx) && (sval < maxx)) {
+                               float cvalc = CLAMPIS(cval, minx, maxx);
+                               float ival = td->ival;
+                               float timefac;
+
+                               /* NLA mapping magic here works as follows:
+                                * - "ival" goes from strip time to global time
+                                * - calculation is performed into td->val in global time
+                                *   (since sval and min/max are all in global time)
+                                * - "td->val" then gets put back into strip time
+                                */
+                               if (adt) {
+                                       /* strip to global */
+                                       ival = BKE_nla_tweakedit_remap(adt, ival, NLATIME_CONVERT_MAP);
+                               }
 
-                       /* left half? */
-                       if (ival < sval) {
-                               timefac = (sval - ival) / (sval - minx);
-                               *(td->val) = cvalc - timefac * (cvalc - minx);
-                       }
-                       else {
-                               timefac = (ival - sval) / (maxx - sval);
-                               *(td->val) = cvalc + timefac * (maxx - cvalc);
-                       }
+                               /* left half? */
+                               if (ival < sval) {
+                                       timefac = (sval - ival) / (sval - minx);
+                                       *(td->val) = cvalc - timefac * (cvalc - minx);
+                               }
+                               else {
+                                       timefac = (ival - sval) / (maxx - sval);
+                                       *(td->val) = cvalc + timefac * (maxx - cvalc);
+                               }
 
-                       if (adt) {
-                               /* global to strip */
-                               *(td->val) = BKE_nla_tweakedit_remap(adt, *(td->val), NLATIME_CONVERT_UNMAP);
+                               if (adt) {
+                                       /* global to strip */
+                                       *(td->val) = BKE_nla_tweakedit_remap(adt, *(td->val), NLATIME_CONVERT_UNMAP);
+                               }
                        }
                }
        }
@@ -8525,8 +8715,8 @@ static void initTimeScale(TransInfo *t)
        /* recalculate center2d to use CFRA and mouse Y, since that's
         * what is used in time scale */
        if ((t->flag & T_OVERRIDE_CENTER) == 0) {
-               t->center[0] = t->scene->r.cfra;
-               projectFloatView(t, t->center, center);
+               t->center_global[0] = t->scene->r.cfra;
+               projectFloatView(t, t->center_global, center);
                center[1] = t->mouse.imval[1];
        }
 
@@ -8567,39 +8757,40 @@ static void headerTimeScale(TransInfo *t, char str[UI_MAX_DRAW_STR])
 static void applyTimeScaleValue(TransInfo *t)
 {
        Scene *scene = t->scene;
-       TransData *td = t->data;
-       TransData2D *td2d = t->data2d;
        int i;
 
        const short autosnap = getAnimEdit_SnapMode(t);
        const double secf = FPS;
 
+       FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+               TransData *td = tc->data;
+               TransData2D *td2d = tc->data_2d;
+               for (i = 0; i < tc->data_len; i++, td++, td2d++) {
+                       /* it is assumed that td->extra is a pointer to the AnimData,
+                        * whose active action is where this keyframe comes from
+                        * (this is only valid when not in NLA)
+                        */
+                       AnimData *adt = (t->spacetype != SPACE_NLA) ? td->extra : NULL;
+                       float startx = CFRA;
+                       float fac = t->values[0];
 
-       for (i = 0; i < t->total; i++, td++, td2d++) {
-               /* it is assumed that td->extra is a pointer to the AnimData,
-                * whose active action is where this keyframe comes from
-                * (this is only valid when not in NLA)
-                */
-               AnimData *adt = (t->spacetype != SPACE_NLA) ? td->extra : NULL;
-               float startx = CFRA;
-               float fac = t->values[0];
-
-               if (autosnap == SACTSNAP_TSTEP) {
-                       fac = (float)(floor((double)fac / secf + 0.5) * secf);
-               }
-               else if (autosnap == SACTSNAP_STEP) {
-                       fac = floorf(fac + 0.5f);
-               }
+                       if (autosnap == SACTSNAP_TSTEP) {
+                               fac = (float)(floor((double)fac / secf + 0.5) * secf);
+                       }
+                       else if (autosnap == SACTSNAP_STEP) {
+                               fac = floorf(fac + 0.5f);
+                       }
 
-               /* check if any need to apply nla-mapping */
-               if (adt)
-                       startx = BKE_nla_tweakedit_remap(adt, startx, NLATIME_CONVERT_UNMAP);
+                       /* check if any need to apply nla-mapping */
+                       if (adt)
+                               startx = BKE_nla_tweakedit_remap(adt, startx, NLATIME_CONVERT_UNMAP);
 
-               /* now, calculate the new value */
-               *(td->val) = ((td->ival - startx) * fac) + startx;
+                       /* now, calculate the new value */
+                       *(td->val) = ((td->ival - startx) * fac) + startx;
 
-               /* apply nearest snapping */
-               doAnimEdit_SnapFrame(t, td, td2d, adt, autosnap);
+                       /* apply nearest snapping */
+                       doAnimEdit_SnapFrame(t, td, td2d, adt, autosnap);
+               }
        }
 }
 
@@ -8628,7 +8819,7 @@ bool checkUseAxisMatrix(TransInfo *t)
        /* currently only checks for editmode */
        if (t->flag & T_EDIT) {
                if ((t->around == V3D_AROUND_LOCAL_ORIGINS) &&
-                   (ELEM(t->obedit->type, OB_MESH, OB_CURVE, OB_MBALL, OB_ARMATURE)))
+                   (ELEM(t->obedit_type, OB_MESH, OB_CURVE, OB_MBALL, OB_ARMATURE)))
                {
                        /* not all editmode supports axis-matrix */
                        return true;