[gimp] app: use the newly added tool widgets in the transform tools



commit a5f3808505fc1157e0ff0732d9a68a48576bbedf
Author: Michael Natterer <mitch gimp org>
Date:   Sat Jun 17 03:02:01 2017 +0200

    app: use the newly added tool widgets in the transform tools

 app/tools/gimphandletransformtool.c  |   14 +-
 app/tools/gimpperspectivetool.c      |  157 +++--
 app/tools/gimprotatetool.c           |  195 +++---
 app/tools/gimpscaletool.c            |  246 +++-----
 app/tools/gimpsheartool.c            |  215 ++++---
 app/tools/gimptransformoptions.c     |    4 +-
 app/tools/gimptransformtool.c        |  680 +++++++------------
 app/tools/gimptransformtool.h        |   75 +--
 app/tools/gimpunifiedtransformtool.c | 1240 +++-------------------------------
 9 files changed, 800 insertions(+), 2026 deletions(-)
---
diff --git a/app/tools/gimphandletransformtool.c b/app/tools/gimphandletransformtool.c
index 7e12556..09e1502 100644
--- a/app/tools/gimphandletransformtool.c
+++ b/app/tools/gimphandletransformtool.c
@@ -105,7 +105,8 @@ static void   gimp_handle_transform_tool_dialog         (GimpTransformTool  *tr_
 static void   gimp_handle_transform_tool_dialog_update  (GimpTransformTool  *tr_tool);
 static void   gimp_handle_transform_tool_prepare        (GimpTransformTool  *tr_tool);
 static void   gimp_handle_transform_tool_motion         (GimpTransformTool  *tr_tool);
-static void   gimp_handle_transform_tool_recalc_matrix  (GimpTransformTool  *tr_tool);
+static void   gimp_handle_transform_tool_recalc_matrix  (GimpTransformTool  *tr_tool,
+                                                         GimpToolWidget     *widget);
 static gchar *gimp_handle_transform_tool_get_undo_desc  (GimpTransformTool  *tr_tool);
 static TransformAction
               gimp_handle_transform_tool_pick_function  (GimpTransformTool  *tr_tool,
@@ -115,9 +116,7 @@ static TransformAction
 static void   gimp_handle_transform_tool_cursor_update  (GimpTransformTool  *tr_tool,
                                                          GimpCursorType     *cursor,
                                                          GimpCursorModifier *modifier);
-static void   gimp_handle_transform_tool_draw_gui       (GimpTransformTool  *tr_tool,
-                                                         gint                handle_w,
-                                                         gint                handle_h);
+static void   gimp_handle_transform_tool_draw_gui       (GimpTransformTool  *tr_tool);
 
 static gboolean       is_handle_position_valid          (GimpTransformTool  *tr_tool,
                                                          gint                active_handle);
@@ -606,7 +605,8 @@ gimp_handle_transform_tool_motion (GimpTransformTool *tr_tool)
 }
 
 static void
-gimp_handle_transform_tool_recalc_matrix (GimpTransformTool *tr_tool)
+gimp_handle_transform_tool_recalc_matrix (GimpTransformTool *tr_tool,
+                                          GimpToolWidget    *widget)
 {
   GimpHandleTransformTool *ht_tool = GIMP_HANDLE_TRANSFORM_TOOL (tr_tool);
   gdouble                  coeff[8 * 9];
@@ -765,9 +765,7 @@ gimp_handle_transform_tool_cursor_update (GimpTransformTool  *tr_tool,
 }
 
 static void
-gimp_handle_transform_tool_draw_gui (GimpTransformTool *tr_tool,
-                                     gint               handle_w,
-                                     gint               handle_h)
+gimp_handle_transform_tool_draw_gui (GimpTransformTool *tr_tool)
 {
   GimpDrawTool *draw_tool = GIMP_DRAW_TOOL (tr_tool);
   gint          i;
diff --git a/app/tools/gimpperspectivetool.c b/app/tools/gimpperspectivetool.c
index c912b52..baa8fe4 100644
--- a/app/tools/gimpperspectivetool.c
+++ b/app/tools/gimpperspectivetool.c
@@ -17,8 +17,6 @@
 
 #include "config.h"
 
-#include <string.h>
-
 #include <gegl.h>
 #include <gtk/gtk.h>
 
@@ -29,12 +27,12 @@
 
 #include "core/gimp-transform-utils.h"
 #include "core/gimpimage.h"
-#include "core/gimpdrawable-transform.h"
 
 #include "widgets/gimphelp-ids.h"
 
 #include "display/gimpdisplay.h"
 #include "display/gimptoolgui.h"
+#include "display/gimptooltransformgrid.h"
 
 #include "gimpperspectivetool.h"
 #include "gimptoolcontrol.h"
@@ -59,12 +57,16 @@ enum
 
 /*  local function prototypes  */
 
-static void    gimp_perspective_tool_dialog        (GimpTransformTool *tr_tool);
-static void    gimp_perspective_tool_dialog_update (GimpTransformTool *tr_tool);
-static void    gimp_perspective_tool_prepare       (GimpTransformTool *tr_tool);
-static void    gimp_perspective_tool_motion        (GimpTransformTool *tr_tool);
-static void    gimp_perspective_tool_recalc_matrix (GimpTransformTool *tr_tool);
-static gchar * gimp_perspective_tool_get_undo_desc (GimpTransformTool *tr_tool);
+static void             gimp_perspective_tool_dialog         (GimpTransformTool *tr_tool);
+static void             gimp_perspective_tool_dialog_update  (GimpTransformTool *tr_tool);
+static void             gimp_perspective_tool_prepare        (GimpTransformTool *tr_tool);
+static GimpToolWidget * gimp_perspective_tool_get_widget     (GimpTransformTool *tr_tool);
+static void             gimp_perspective_tool_recalc_matrix  (GimpTransformTool *tr_tool,
+                                                              GimpToolWidget    *widget);
+static gchar          * gimp_perspective_tool_get_undo_desc  (GimpTransformTool *tr_tool);
+
+static void             gimp_perspective_tool_widget_changed (GimpToolWidget    *widget,
+                                                              GimpTransformTool *tr_tool);
 
 
 G_DEFINE_TYPE (GimpPerspectiveTool, gimp_perspective_tool,
@@ -97,7 +99,7 @@ gimp_perspective_tool_class_init (GimpPerspectiveToolClass *klass)
   trans_class->dialog        = gimp_perspective_tool_dialog;
   trans_class->dialog_update = gimp_perspective_tool_dialog_update;
   trans_class->prepare       = gimp_perspective_tool_prepare;
-  trans_class->motion        = gimp_perspective_tool_motion;
+  trans_class->get_widget    = gimp_perspective_tool_get_widget;
   trans_class->recalc_matrix = gimp_perspective_tool_recalc_matrix;
   trans_class->get_undo_desc = gimp_perspective_tool_get_undo_desc;
 }
@@ -111,13 +113,9 @@ gimp_perspective_tool_init (GimpPerspectiveTool *perspective_tool)
   gimp_tool_control_set_tool_cursor (tool->control,
                                      GIMP_TOOL_CURSOR_PERSPECTIVE);
 
-  tr_tool->progress_text      = _("Perspective transformation");
-
-  tr_tool->use_grid           = TRUE;
-  tr_tool->use_corner_handles = TRUE;
-  tr_tool->use_center_handle  = TRUE;
-
-  tr_tool->does_perspective   = TRUE;
+  tr_tool->progress_text    = _("Perspective transformation");
+  tr_tool->use_grid         = TRUE;
+  tr_tool->does_perspective = TRUE;
 }
 
 static void
@@ -185,54 +183,50 @@ gimp_perspective_tool_prepare (GimpTransformTool  *tr_tool)
   tr_tool->trans_info[Y3] = (gdouble) tr_tool->y2;
 }
 
-static void
-gimp_perspective_tool_motion (GimpTransformTool *transform_tool)
+static GimpToolWidget *
+gimp_perspective_tool_get_widget (GimpTransformTool *tr_tool)
 {
-  gdouble diff_x, diff_y;
-
-  diff_x = transform_tool->curx - transform_tool->lastx;
-  diff_y = transform_tool->cury - transform_tool->lasty;
-
-  switch (transform_tool->function)
-    {
-    case TRANSFORM_HANDLE_NW:
-      transform_tool->trans_info[X0] += diff_x;
-      transform_tool->trans_info[Y0] += diff_y;
-      break;
-
-    case TRANSFORM_HANDLE_NE:
-      transform_tool->trans_info[X1] += diff_x;
-      transform_tool->trans_info[Y1] += diff_y;
-      break;
-
-    case TRANSFORM_HANDLE_SW:
-      transform_tool->trans_info[X2] += diff_x;
-      transform_tool->trans_info[Y2] += diff_y;
-      break;
-
-    case TRANSFORM_HANDLE_SE:
-      transform_tool->trans_info[X3] += diff_x;
-      transform_tool->trans_info[Y3] += diff_y;
-      break;
-
-    case TRANSFORM_HANDLE_CENTER:
-      transform_tool->trans_info[X0] += diff_x;
-      transform_tool->trans_info[Y0] += diff_y;
-      transform_tool->trans_info[X1] += diff_x;
-      transform_tool->trans_info[Y1] += diff_y;
-      transform_tool->trans_info[X2] += diff_x;
-      transform_tool->trans_info[Y2] += diff_y;
-      transform_tool->trans_info[X3] += diff_x;
-      transform_tool->trans_info[Y3] += diff_y;
-      break;
-
-    default:
-      break;
-    }
+  GimpTool             *tool    = GIMP_TOOL (tr_tool);
+  GimpTransformOptions *options = GIMP_TRANSFORM_TOOL_GET_OPTIONS (tr_tool);
+  GimpDisplayShell     *shell   = gimp_display_get_shell (tool->display);
+  GimpToolWidget       *widget;
+
+  widget = gimp_tool_transform_grid_new (shell,
+                                         &tr_tool->transform,
+                                         tr_tool->x1,
+                                         tr_tool->y1,
+                                         tr_tool->x2,
+                                         tr_tool->y2,
+                                         options->grid_type,
+                                         options->grid_size);
+
+  g_object_set (widget,
+                "inside-function",         GIMP_TRANSFORM_FUNCTION_PERSPECTIVE,
+                "outside-function",        GIMP_TRANSFORM_FUNCTION_PERSPECTIVE,
+                "use-perspective-handles", TRUE,
+                "use-center-handle",       TRUE,
+                "constrain-move",          options->constrain_move,
+                "constrain-scale",         options->constrain_scale,
+                "constrain-rotate",        options->constrain_rotate,
+                "constrain-shear",         options->constrain_shear,
+                "constrain-perspective",   options->constrain_perspective,
+                "frompivot-scale",         options->frompivot_scale,
+                "frompivot-shear",         options->frompivot_shear,
+                "frompivot-perspective",   options->frompivot_perspective,
+                "cornersnap",              options->cornersnap,
+                "fixedpivot",              options->fixedpivot,
+                NULL);
+
+  g_signal_connect (widget, "changed",
+                    G_CALLBACK (gimp_perspective_tool_widget_changed),
+                    tr_tool);
+
+  return widget;
 }
 
 static void
-gimp_perspective_tool_recalc_matrix (GimpTransformTool *tr_tool)
+gimp_perspective_tool_recalc_matrix (GimpTransformTool *tr_tool,
+                                     GimpToolWidget    *widget)
 {
   gimp_matrix3_identity (&tr_tool->transform);
   gimp_transform_matrix_perspective (&tr_tool->transform,
@@ -248,6 +242,15 @@ gimp_perspective_tool_recalc_matrix (GimpTransformTool *tr_tool)
                                      tr_tool->trans_info[Y2],
                                      tr_tool->trans_info[X3],
                                      tr_tool->trans_info[Y3]);
+
+  if (widget)
+    g_object_set (widget,
+                  "transform", &tr_tool->transform,
+                  "x1",        (gdouble) tr_tool->x1,
+                  "y1",        (gdouble) tr_tool->y1,
+                  "x2",        (gdouble) tr_tool->x2,
+                  "y2",        (gdouble) tr_tool->y2,
+                  NULL);
 }
 
 static gchar *
@@ -255,3 +258,35 @@ gimp_perspective_tool_get_undo_desc (GimpTransformTool *tr_tool)
 {
   return g_strdup (C_("undo-type", "Perspective"));
 }
+
+static void
+gimp_perspective_tool_widget_changed (GimpToolWidget    *widget,
+                                      GimpTransformTool *tr_tool)
+{
+  GimpMatrix3 *transform;
+
+  g_object_get (widget,
+                "transform", &transform,
+                NULL);
+
+  gimp_matrix3_transform_point (transform,
+                                tr_tool->x1, tr_tool->y1,
+                                &tr_tool->trans_info[X0],
+                                &tr_tool->trans_info[Y0]);
+  gimp_matrix3_transform_point (transform,
+                                tr_tool->x2, tr_tool->y1,
+                                &tr_tool->trans_info[X1],
+                                &tr_tool->trans_info[Y1]);
+  gimp_matrix3_transform_point (transform,
+                                tr_tool->x1, tr_tool->y2,
+                                &tr_tool->trans_info[X2],
+                                &tr_tool->trans_info[Y2]);
+  gimp_matrix3_transform_point (transform,
+                                tr_tool->x2, tr_tool->y2,
+                                &tr_tool->trans_info[X3],
+                                &tr_tool->trans_info[Y3]);
+
+  g_free (transform);
+
+  gimp_transform_tool_recalc_matrix (tr_tool, NULL);
+}
diff --git a/app/tools/gimprotatetool.c b/app/tools/gimprotatetool.c
index ba76ccd..44dffff 100644
--- a/app/tools/gimprotatetool.c
+++ b/app/tools/gimprotatetool.c
@@ -17,8 +17,6 @@
 
 #include "config.h"
 
-#include <string.h>
-
 #include <gegl.h>
 #include <gtk/gtk.h>
 #include <gdk/gdkkeysyms.h>
@@ -36,6 +34,7 @@
 #include "display/gimpdisplay.h"
 #include "display/gimpdisplayshell.h"
 #include "display/gimptoolgui.h"
+#include "display/gimptoolrotategrid.h"
 
 #include "gimprotatetool.h"
 #include "gimptoolcontrol.h"
@@ -48,33 +47,35 @@
 enum
 {
   ANGLE,
-  REAL_ANGLE,
   PIVOT_X,
   PIVOT_Y
 };
 
-#define FIFTEEN_DEG  (G_PI / 12.0)
 
-#define SB_WIDTH     10
+#define SB_WIDTH 10
 
 
 /*  local function prototypes  */
 
-static gboolean  gimp_rotate_tool_key_press     (GimpTool           *tool,
-                                                 GdkEventKey        *kevent,
-                                                 GimpDisplay        *display);
+static gboolean         gimp_rotate_tool_key_press      (GimpTool           *tool,
+                                                         GdkEventKey        *kevent,
+                                                         GimpDisplay        *display);
+
+static void             gimp_rotate_tool_dialog         (GimpTransformTool  *tr_tool);
+static void             gimp_rotate_tool_dialog_update  (GimpTransformTool  *tr_tool);
+static void             gimp_rotate_tool_prepare        (GimpTransformTool  *tr_tool);
+static GimpToolWidget * gimp_rotate_tool_get_widget     (GimpTransformTool *tr_tool);
+static void             gimp_rotate_tool_recalc_matrix  (GimpTransformTool  *tr_tool,
+                                                         GimpToolWidget     *widget);
+static gchar          * gimp_rotate_tool_get_undo_desc  (GimpTransformTool  *tr_tool);
 
-static void      gimp_rotate_tool_dialog        (GimpTransformTool  *tr_tool);
-static void      gimp_rotate_tool_dialog_update (GimpTransformTool  *tr_tool);
-static void      gimp_rotate_tool_prepare       (GimpTransformTool  *tr_tool);
-static void      gimp_rotate_tool_motion        (GimpTransformTool  *tr_tool);
-static void      gimp_rotate_tool_recalc_matrix (GimpTransformTool  *tr_tool);
-static gchar   * gimp_rotate_tool_get_undo_desc (GimpTransformTool  *tr_tool);
+static void             gimp_rotate_tool_widget_changed (GimpToolWidget    *widget,
+                                                         GimpTransformTool *tr_tool);
 
-static void      rotate_angle_changed           (GtkAdjustment      *adj,
-                                                 GimpTransformTool  *tr_tool);
-static void      rotate_center_changed          (GtkWidget          *entry,
-                                                GimpTransformTool   *tr_tool);
+static void             rotate_angle_changed            (GtkAdjustment      *adj,
+                                                         GimpTransformTool  *tr_tool);
+static void             rotate_center_changed           (GtkWidget          *entry,
+                                                         GimpTransformTool   *tr_tool);
 
 
 G_DEFINE_TYPE (GimpRotateTool, gimp_rotate_tool, GIMP_TYPE_TRANSFORM_TOOL)
@@ -110,7 +111,7 @@ gimp_rotate_tool_class_init (GimpRotateToolClass *klass)
   trans_class->dialog          = gimp_rotate_tool_dialog;
   trans_class->dialog_update   = gimp_rotate_tool_dialog_update;
   trans_class->prepare         = gimp_rotate_tool_prepare;
-  trans_class->motion          = gimp_rotate_tool_motion;
+  trans_class->get_widget      = gimp_rotate_tool_get_widget;
   trans_class->recalc_matrix   = gimp_rotate_tool_recalc_matrix;
   trans_class->get_undo_desc   = gimp_rotate_tool_get_undo_desc;
 
@@ -125,10 +126,8 @@ gimp_rotate_tool_init (GimpRotateTool *rotate_tool)
 
   gimp_tool_control_set_tool_cursor (tool->control, GIMP_TOOL_CURSOR_ROTATE);
 
-  tr_tool->progress_text    = _("Rotating");
-
-  tr_tool->use_grid         = TRUE;
-  tr_tool->use_pivot_handle = TRUE;
+  tr_tool->progress_text = _("Rotating");
+  tr_tool->use_grid      = TRUE;
 }
 
 static gboolean
@@ -258,13 +257,9 @@ gimp_rotate_tool_prepare (GimpTransformTool *tr_tool)
   gdouble         xres;
   gdouble         yres;
 
-  tr_tool->px = (gdouble) (tr_tool->x1 + tr_tool->x2) / 2.0;
-  tr_tool->py = (gdouble) (tr_tool->y1 + tr_tool->y2) / 2.0;
-
-  tr_tool->trans_info[ANGLE]      = 0.0;
-  tr_tool->trans_info[REAL_ANGLE] = 0.0;
-  tr_tool->trans_info[PIVOT_X]    = tr_tool->px;
-  tr_tool->trans_info[PIVOT_Y]    = tr_tool->py;
+  tr_tool->trans_info[ANGLE]   = 0.0;
+  tr_tool->trans_info[PIVOT_X] = (gdouble) (tr_tool->x1 + tr_tool->x2) / 2.0;
+  tr_tool->trans_info[PIVOT_Y] = (gdouble) (tr_tool->y1 + tr_tool->y2) / 2.0;
 
   gimp_image_get_resolution (image, &xres, &yres);
 
@@ -299,78 +294,65 @@ gimp_rotate_tool_prepare (GimpTransformTool *tr_tool)
                                      tr_tool);
 }
 
-static void
-gimp_rotate_tool_motion (GimpTransformTool *tr_tool)
+static GimpToolWidget *
+gimp_rotate_tool_get_widget (GimpTransformTool *tr_tool)
 {
+  GimpTool             *tool    = GIMP_TOOL (tr_tool);
   GimpTransformOptions *options = GIMP_TRANSFORM_TOOL_GET_OPTIONS (tr_tool);
-  gdouble               angle1, angle2, angle;
-  gdouble               px, py;
-  gdouble               x1, y1, x2, y2;
-
-  if (tr_tool->function == TRANSFORM_HANDLE_PIVOT)
-    {
-      tr_tool->trans_info[PIVOT_X] = tr_tool->curx;
-      tr_tool->trans_info[PIVOT_Y] = tr_tool->cury;
-
-      return;
-    }
-
-  px = tr_tool->trans_info[PIVOT_X];
-  py = tr_tool->trans_info[PIVOT_Y];
-
-  x1 = tr_tool->curx  - px;
-  x2 = tr_tool->lastx - px;
-  y1 = py - tr_tool->cury;
-  y2 = py - tr_tool->lasty;
-
-  /*  find the first angle  */
-  angle1 = atan2 (y1, x1);
-
-  /*  find the angle  */
-  angle2 = atan2 (y2, x2);
-
-  angle = angle2 - angle1;
-
-  if (angle > G_PI || angle < -G_PI)
-    angle = angle2 - ((angle1 < 0) ? 2.0 * G_PI + angle1 : angle1 - 2.0 * G_PI);
-
-  /*  increment the transform tool's angle  */
-  tr_tool->trans_info[REAL_ANGLE] += angle;
-
-  /*  limit the angle to between -180 and 180 degrees  */
-  if (tr_tool->trans_info[REAL_ANGLE] < - G_PI)
-    {
-      tr_tool->trans_info[REAL_ANGLE] += 2.0 * G_PI;
-    }
-  else if (tr_tool->trans_info[REAL_ANGLE] > G_PI)
-    {
-      tr_tool->trans_info[REAL_ANGLE] -= 2.0 * G_PI;
-    }
+  GimpDisplayShell     *shell   = gimp_display_get_shell (tool->display);
+  GimpToolWidget       *widget;
+
+  widget = gimp_tool_rotate_grid_new (shell,
+                                      tr_tool->x1,
+                                      tr_tool->y1,
+                                      tr_tool->x2,
+                                      tr_tool->y2,
+                                      tr_tool->trans_info[PIVOT_X],
+                                      tr_tool->trans_info[PIVOT_Y],
+                                      tr_tool->trans_info[ANGLE]);
+
+  g_object_set (widget,
+                "guide-type",              options->grid_type,
+                "n-guides",                options->grid_size,
+                "inside-function",         GIMP_TRANSFORM_FUNCTION_ROTATE,
+                "outside-function",        GIMP_TRANSFORM_FUNCTION_ROTATE,
+                "use-pivot-handle",        TRUE,
+                "constrain-move",          options->constrain_move,
+                "constrain-scale",         options->constrain_scale,
+                "constrain-rotate",        options->constrain_rotate,
+                "constrain-shear",         options->constrain_shear,
+                "constrain-perspective",   options->constrain_perspective,
+                "frompivot-scale",         options->frompivot_scale,
+                "frompivot-shear",         options->frompivot_shear,
+                "frompivot-perspective",   options->frompivot_perspective,
+                "cornersnap",              options->cornersnap,
+                "fixedpivot",              options->fixedpivot,
+                NULL);
+
+  g_signal_connect (widget, "changed",
+                    G_CALLBACK (gimp_rotate_tool_widget_changed),
+                    tr_tool);
 
-  /*  constrain the angle to 15-degree multiples if ctrl is held down  */
-  if (options->constrain_rotate)
-    {
-      tr_tool->trans_info[ANGLE] =
-        FIFTEEN_DEG * (gint) ((tr_tool->trans_info[REAL_ANGLE] +
-                               FIFTEEN_DEG / 2.0) / FIFTEEN_DEG);
-    }
-  else
-    {
-      tr_tool->trans_info[ANGLE] = tr_tool->trans_info[REAL_ANGLE];
-    }
+  return widget;
 }
 
 static void
-gimp_rotate_tool_recalc_matrix (GimpTransformTool *tr_tool)
+gimp_rotate_tool_recalc_matrix (GimpTransformTool *tr_tool,
+                                GimpToolWidget    *widget)
 {
-  tr_tool->px = tr_tool->trans_info[PIVOT_X];
-  tr_tool->py = tr_tool->trans_info[PIVOT_Y];
-
   gimp_matrix3_identity (&tr_tool->transform);
   gimp_transform_matrix_rotate_center (&tr_tool->transform,
-                                       tr_tool->px,
-                                       tr_tool->py,
+                                       tr_tool->trans_info[PIVOT_X],
+                                       tr_tool->trans_info[PIVOT_Y],
                                        tr_tool->trans_info[ANGLE]);
+
+  if (widget)
+    g_object_set (widget,
+                  "transform", &tr_tool->transform,
+                  "angle",     tr_tool->trans_info[ANGLE],
+                  "pivot-x",   tr_tool->trans_info[PIVOT_X],
+                  "pivot-y",   tr_tool->trans_info[PIVOT_Y],
+                  NULL);
 }
 
 static gchar *
@@ -384,6 +366,19 @@ gimp_rotate_tool_get_undo_desc (GimpTransformTool  *tr_tool)
 }
 
 static void
+gimp_rotate_tool_widget_changed (GimpToolWidget    *widget,
+                                 GimpTransformTool *tr_tool)
+{
+  g_object_get (widget,
+                "angle",   &tr_tool->trans_info[ANGLE],
+                "pivot-x", &tr_tool->trans_info[PIVOT_X],
+                "pivot-y", &tr_tool->trans_info[PIVOT_Y],
+                NULL);
+
+  gimp_transform_tool_recalc_matrix (tr_tool, NULL);
+}
+
+static void
 rotate_angle_changed (GtkAdjustment     *adj,
                       GimpTransformTool *tr_tool)
 {
@@ -393,15 +388,11 @@ rotate_angle_changed (GtkAdjustment     *adj,
 
   if (ABS (value - tr_tool->trans_info[ANGLE]) > ANGLE_EPSILON)
     {
-      gimp_draw_tool_pause (GIMP_DRAW_TOOL (tr_tool));
-
-      tr_tool->trans_info[REAL_ANGLE] = tr_tool->trans_info[ANGLE] = value;
+      tr_tool->trans_info[ANGLE] = value;
 
       gimp_transform_tool_push_internal_undo (tr_tool);
 
-      gimp_transform_tool_recalc_matrix (tr_tool);
-
-      gimp_draw_tool_resume (GIMP_DRAW_TOOL (tr_tool));
+      gimp_transform_tool_recalc_matrix (tr_tool, tr_tool->widget);
     }
 
 #undef ANGLE_EPSILON
@@ -417,17 +408,11 @@ rotate_center_changed (GtkWidget         *widget,
   if ((px != tr_tool->trans_info[PIVOT_X]) ||
       (py != tr_tool->trans_info[PIVOT_Y]))
     {
-      gimp_draw_tool_pause (GIMP_DRAW_TOOL (tr_tool));
-
       tr_tool->trans_info[PIVOT_X] = px;
       tr_tool->trans_info[PIVOT_Y] = py;
-      tr_tool->px = px;
-      tr_tool->py = py;
 
       gimp_transform_tool_push_internal_undo (tr_tool);
 
-      gimp_transform_tool_recalc_matrix (tr_tool);
-
-      gimp_draw_tool_resume (GIMP_DRAW_TOOL (tr_tool));
+      gimp_transform_tool_recalc_matrix (tr_tool, tr_tool->widget);
     }
 }
diff --git a/app/tools/gimpscaletool.c b/app/tools/gimpscaletool.c
index c5cf5bd..320b694 100644
--- a/app/tools/gimpscaletool.c
+++ b/app/tools/gimpscaletool.c
@@ -29,7 +29,6 @@
 
 #include "core/gimp-transform-utils.h"
 #include "core/gimpimage.h"
-#include "core/gimpdrawable-transform.h"
 
 #include "widgets/gimphelp-ids.h"
 #include "widgets/gimpsizebox.h"
@@ -37,6 +36,7 @@
 #include "display/gimpdisplay.h"
 #include "display/gimpdisplayshell.h"
 #include "display/gimptoolgui.h"
+#include "display/gimptooltransformgrid.h"
 
 #include "gimpscaletool.h"
 #include "gimptoolcontrol.h"
@@ -51,26 +51,26 @@ enum
   X0,
   Y0,
   X1,
-  Y1,
-  X2,
-  Y2,
-  X3,
-  Y3
+  Y1
 };
 
 
 /*  local function prototypes  */
 
-static void    gimp_scale_tool_dialog        (GimpTransformTool  *tr_tool);
-static void    gimp_scale_tool_dialog_update (GimpTransformTool  *tr_tool);
-static void    gimp_scale_tool_prepare       (GimpTransformTool  *tr_tool);
-static void    gimp_scale_tool_motion        (GimpTransformTool  *tr_tool);
-static void    gimp_scale_tool_recalc_matrix (GimpTransformTool  *tr_tool);
-static gchar * gimp_scale_tool_get_undo_desc (GimpTransformTool  *tr_tool);
+static void             gimp_scale_tool_dialog         (GimpTransformTool *tr_tool);
+static void             gimp_scale_tool_dialog_update  (GimpTransformTool *tr_tool);
+static void             gimp_scale_tool_prepare        (GimpTransformTool *tr_tool);
+static GimpToolWidget * gimp_scale_tool_get_widget     (GimpTransformTool *tr_tool);
+static void             gimp_scale_tool_recalc_matrix  (GimpTransformTool *tr_tool,
+                                                        GimpToolWidget    *widget);
+static gchar          * gimp_scale_tool_get_undo_desc  (GimpTransformTool *tr_tool);
 
-static void    gimp_scale_tool_size_notify   (GtkWidget          *box,
-                                              GParamSpec         *pspec,
-                                              GimpTransformTool  *tr_tool);
+static void             gimp_scale_tool_widget_changed (GimpToolWidget    *widget,
+                                                        GimpTransformTool *tr_tool);
+
+static void             gimp_scale_tool_size_notify    (GtkWidget         *box,
+                                                        GParamSpec        *pspec,
+                                                        GimpTransformTool *tr_tool);
 
 
 G_DEFINE_TYPE (GimpScaleTool, gimp_scale_tool, GIMP_TYPE_TRANSFORM_TOOL)
@@ -103,7 +103,7 @@ gimp_scale_tool_class_init (GimpScaleToolClass *klass)
   trans_class->dialog          = gimp_scale_tool_dialog;
   trans_class->dialog_update   = gimp_scale_tool_dialog_update;
   trans_class->prepare         = gimp_scale_tool_prepare;
-  trans_class->motion          = gimp_scale_tool_motion;
+  trans_class->get_widget      = gimp_scale_tool_get_widget;
   trans_class->recalc_matrix   = gimp_scale_tool_recalc_matrix;
   trans_class->get_undo_desc   = gimp_scale_tool_get_undo_desc;
 
@@ -118,12 +118,8 @@ gimp_scale_tool_init (GimpScaleTool *scale_tool)
 
   gimp_tool_control_set_tool_cursor (tool->control, GIMP_TOOL_CURSOR_RESIZE);
 
-  tr_tool->progress_text      = _("Scaling");
-
-  tr_tool->use_grid           = TRUE;
-  tr_tool->use_corner_handles = TRUE;
-  tr_tool->use_side_handles   = TRUE;
-  tr_tool->use_center_handle  = TRUE;
+  tr_tool->progress_text = _("Scaling");
+  tr_tool->use_grid      = TRUE;
 }
 
 static void
@@ -135,9 +131,11 @@ static void
 gimp_scale_tool_dialog_update (GimpTransformTool *tr_tool)
 {
   GimpTransformOptions *options = GIMP_TRANSFORM_TOOL_GET_OPTIONS (tr_tool);
+  gint                  width;
+  gint                  height;
 
-  gint width  = ROUND (tr_tool->trans_info[X1] - tr_tool->trans_info[X0]);
-  gint height = ROUND (tr_tool->trans_info[Y1] - tr_tool->trans_info[Y0]);
+  width  = ROUND (tr_tool->trans_info[X1] - tr_tool->trans_info[X0]);
+  height = ROUND (tr_tool->trans_info[Y1] - tr_tool->trans_info[Y0]);
 
   g_object_set (GIMP_SCALE_TOOL (tr_tool)->box,
                 "width",       width,
@@ -193,131 +191,51 @@ gimp_scale_tool_prepare (GimpTransformTool *tr_tool)
                     tr_tool);
 }
 
-static void
-gimp_scale_tool_motion (GimpTransformTool *tr_tool)
+static GimpToolWidget *
+gimp_scale_tool_get_widget (GimpTransformTool *tr_tool)
 {
+  GimpTool             *tool    = GIMP_TOOL (tr_tool);
   GimpTransformOptions *options = GIMP_TRANSFORM_TOOL_GET_OPTIONS (tr_tool);
-  gdouble              *x1;
-  gdouble              *y1;
-  gdouble              *x2;
-  gdouble              *y2;
-  gint                  dir_x;
-  gint                  dir_y;
-  gdouble               diff_x = tr_tool->curx - tr_tool->lastx;
-  gdouble               diff_y = tr_tool->cury - tr_tool->lasty;
-
-  switch (tr_tool->function)
-    {
-    case TRANSFORM_HANDLE_N:
-      diff_x = 0; /* and fall through */
-    case TRANSFORM_HANDLE_NW:
-      x1 = &tr_tool->trans_info[X0];
-      y1 = &tr_tool->trans_info[Y0];
-      x2 = &tr_tool->trans_info[X1];
-      y2 = &tr_tool->trans_info[Y1];
-      dir_x = dir_y = 1;
-      break;
-
-    case TRANSFORM_HANDLE_E:
-      diff_y = 0; /* and fall through */
-    case TRANSFORM_HANDLE_NE:
-      x1 = &tr_tool->trans_info[X1];
-      y1 = &tr_tool->trans_info[Y0];
-      x2 = &tr_tool->trans_info[X0];
-      y2 = &tr_tool->trans_info[Y1];
-      dir_x = -1;
-      dir_y = 1;
-      break;
-
-    case TRANSFORM_HANDLE_W:
-      diff_y = 0; /* and fall through */
-    case TRANSFORM_HANDLE_SW:
-      x1 = &tr_tool->trans_info[X0];
-      y1 = &tr_tool->trans_info[Y1];
-      x2 = &tr_tool->trans_info[X1];
-      y2 = &tr_tool->trans_info[Y0];
-      dir_x = 1;
-      dir_y = -1;
-      break;
-
-    case TRANSFORM_HANDLE_S:
-      diff_x = 0; /* and fall through */
-    case TRANSFORM_HANDLE_SE:
-      x1 = &tr_tool->trans_info[X1];
-      y1 = &tr_tool->trans_info[Y1];
-      x2 = &tr_tool->trans_info[X0];
-      y2 = &tr_tool->trans_info[Y0];
-      dir_x = dir_y = -1;
-      break;
-
-    case TRANSFORM_HANDLE_CENTER:
-      tr_tool->trans_info[X0] += diff_x;
-      tr_tool->trans_info[Y0] += diff_y;
-      tr_tool->trans_info[X1] += diff_x;
-      tr_tool->trans_info[Y1] += diff_y;
-      tr_tool->trans_info[X2] += diff_x;
-      tr_tool->trans_info[Y2] += diff_y;
-      tr_tool->trans_info[X3] += diff_x;
-      tr_tool->trans_info[Y3] += diff_y;
-      return;
-
-    default:
-      return;
-    }
-
-  *x1 += diff_x;
-  *y1 += diff_y;
-
-  /*  if control is being held, constrain the aspect ratio  */
-  if (options->constrain_scale)
-    {
-      /*  FIXME: improve this  */
-      gdouble h = tr_tool->trans_info[Y1] - tr_tool->trans_info[Y0];
-
-      switch (tr_tool->function)
-        {
-        case TRANSFORM_HANDLE_NW:
-        case TRANSFORM_HANDLE_SW:
-          tr_tool->trans_info[X0] =
-            tr_tool->trans_info[X1] - tr_tool->aspect * h;
-          break;
-
-        case TRANSFORM_HANDLE_NE:
-        case TRANSFORM_HANDLE_SE:
-          tr_tool->trans_info[X1] =
-            tr_tool->trans_info[X0] + tr_tool->aspect * h;
-          break;
-
-        default:
-          break;
-        }
-    }
+  GimpDisplayShell     *shell   = gimp_display_get_shell (tool->display);
+  GimpToolWidget       *widget;
+
+  widget = gimp_tool_transform_grid_new (shell,
+                                         &tr_tool->transform,
+                                         tr_tool->x1,
+                                         tr_tool->y1,
+                                         tr_tool->x2,
+                                         tr_tool->y2,
+                                         options->grid_type,
+                                         options->grid_size);
+
+  g_object_set (widget,
+                "inside-function",         GIMP_TRANSFORM_FUNCTION_SCALE,
+                "outside-function",        GIMP_TRANSFORM_FUNCTION_SCALE,
+                "use-corner-handles",      TRUE,
+                "use-side-handles",        TRUE,
+                "use-center-handle",       TRUE,
+                "constrain-move",          options->constrain_move,
+                "constrain-scale",         options->constrain_scale,
+                "constrain-rotate",        options->constrain_rotate,
+                "constrain-shear",         options->constrain_shear,
+                "constrain-perspective",   options->constrain_perspective,
+                "frompivot-scale",         options->frompivot_scale,
+                "frompivot-shear",         options->frompivot_shear,
+                "frompivot-perspective",   options->frompivot_perspective,
+                "cornersnap",              options->cornersnap,
+                "fixedpivot",              options->fixedpivot,
+                NULL);
 
-  if (dir_x > 0)
-    {
-      if (*x1 >= *x2)
-        *x1 = *x2 - 1;
-    }
-  else
-    {
-      if (*x1 <= *x2)
-        *x1 = *x2 + 1;
-    }
+  g_signal_connect (widget, "changed",
+                    G_CALLBACK (gimp_scale_tool_widget_changed),
+                    tr_tool);
 
-  if (dir_y > 0)
-    {
-      if (*y1 >= *y2)
-        *y1 = *y2 - 1;
-    }
-  else
-    {
-      if (*y1 <= *y2)
-        *y1 = *y2 + 1;
-    }
+  return widget;
 }
 
 static void
-gimp_scale_tool_recalc_matrix (GimpTransformTool *tr_tool)
+gimp_scale_tool_recalc_matrix (GimpTransformTool *tr_tool,
+                               GimpToolWidget    *widget)
 {
   gimp_matrix3_identity (&tr_tool->transform);
   gimp_transform_matrix_scale (&tr_tool->transform,
@@ -329,6 +247,15 @@ gimp_scale_tool_recalc_matrix (GimpTransformTool *tr_tool)
                                tr_tool->trans_info[Y0],
                                tr_tool->trans_info[X1] - tr_tool->trans_info[X0],
                                tr_tool->trans_info[Y1] - tr_tool->trans_info[Y0]);
+
+  if (widget)
+    g_object_set (widget,
+                  "transform", &tr_tool->transform,
+                  "x1",        (gdouble) tr_tool->x1,
+                  "y1",        (gdouble) tr_tool->y1,
+                  "x2",        (gdouble) tr_tool->x2,
+                  "y2",        (gdouble) tr_tool->y2,
+                  NULL);
 }
 
 static gchar *
@@ -342,6 +269,30 @@ gimp_scale_tool_get_undo_desc (GimpTransformTool *tr_tool)
 }
 
 static void
+gimp_scale_tool_widget_changed (GimpToolWidget    *widget,
+                                GimpTransformTool *tr_tool)
+{
+  GimpMatrix3 *transform;
+
+  g_object_get (widget,
+                "transform", &transform,
+                NULL);
+
+  gimp_matrix3_transform_point (transform,
+                                tr_tool->x1, tr_tool->y1,
+                                &tr_tool->trans_info[X0],
+                                &tr_tool->trans_info[Y0]);
+  gimp_matrix3_transform_point (transform,
+                                tr_tool->x2, tr_tool->y2,
+                                &tr_tool->trans_info[X1],
+                                &tr_tool->trans_info[Y1]);
+
+  g_free (transform);
+
+  gimp_transform_tool_recalc_matrix (tr_tool, NULL);
+}
+
+static void
 gimp_scale_tool_size_notify (GtkWidget         *box,
                              GParamSpec        *pspec,
                              GimpTransformTool *tr_tool)
@@ -366,16 +317,12 @@ gimp_scale_tool_size_notify (GtkWidget         *box,
 
       if ((width != old_width) || (height != old_height))
         {
-          gimp_draw_tool_pause (GIMP_DRAW_TOOL (tr_tool));
-
           tr_tool->trans_info[X1] = tr_tool->trans_info[X0] + width;
           tr_tool->trans_info[Y1] = tr_tool->trans_info[Y0] + height;
 
           gimp_transform_tool_push_internal_undo (tr_tool);
 
-          gimp_transform_tool_recalc_matrix (tr_tool);
-
-          gimp_draw_tool_resume (GIMP_DRAW_TOOL (tr_tool));
+          gimp_transform_tool_recalc_matrix (tr_tool, tr_tool->widget);
         }
     }
   else if (! strcmp (pspec->name, "keep-aspect"))
@@ -396,11 +343,6 @@ gimp_scale_tool_size_notify (GtkWidget         *box,
                         "height", &height,
                         NULL);
 
-          /*  Take the aspect ratio from the size box when the user
-           *  activates the constraint by pressing the chain button.
-           */
-          tr_tool->aspect = (gdouble) width / (gdouble) height;
-
           g_object_set (options,
                         "constrain-scale", constrain,
                         NULL);
diff --git a/app/tools/gimpsheartool.c b/app/tools/gimpsheartool.c
index 68f4620..6bd2118 100644
--- a/app/tools/gimpsheartool.c
+++ b/app/tools/gimpsheartool.c
@@ -17,9 +17,6 @@
 
 #include "config.h"
 
-#include <stdlib.h>
-#include <string.h>
-
 #include <gegl.h>
 #include <gtk/gtk.h>
 
@@ -33,7 +30,9 @@
 #include "widgets/gimphelp-ids.h"
 #include "widgets/gimpspinscale.h"
 
+#include "display/gimpdisplay.h"
 #include "display/gimptoolgui.h"
+#include "display/gimptoolsheargrid.h"
 
 #include "gimpsheartool.h"
 #include "gimptoolcontrol.h"
@@ -45,31 +44,33 @@
 /*  index into trans_info array  */
 enum
 {
-  HORZ_OR_VERT,
-  XSHEAR,
-  YSHEAR
+  ORIENTATION,
+  SHEAR_X,
+  SHEAR_Y
 };
 
-/*  the minimum movement before direction of shear can be determined (pixels) */
-#define MIN_MOVE     5
 
-#define SB_WIDTH     10
+#define SB_WIDTH 10
 
 
 /*  local function prototypes  */
 
-static void    gimp_shear_tool_dialog        (GimpTransformTool  *tr_tool);
-static void    gimp_shear_tool_dialog_update (GimpTransformTool  *tr_tool);
+static void             gimp_shear_tool_dialog         (GimpTransformTool *tr_tool);
+static void             gimp_shear_tool_dialog_update  (GimpTransformTool *tr_tool);
+
+static void             gimp_shear_tool_prepare        (GimpTransformTool *tr_tool);
+static GimpToolWidget * gimp_shear_tool_get_widget     (GimpTransformTool *tr_tool);
+static void             gimp_shear_tool_recalc_matrix  (GimpTransformTool *tr_tool,
+                                                        GimpToolWidget    *widget);
+static gchar          * gimp_shear_tool_get_undo_desc  (GimpTransformTool *tr_tool);
 
-static void    gimp_shear_tool_prepare       (GimpTransformTool  *tr_tool);
-static void    gimp_shear_tool_motion        (GimpTransformTool  *tr_tool);
-static void    gimp_shear_tool_recalc_matrix (GimpTransformTool  *tr_tool);
-static gchar * gimp_shear_tool_get_undo_desc (GimpTransformTool  *tr_tool);
+static void             gimp_shear_tool_widget_changed (GimpToolWidget    *widget,
+                                                        GimpTransformTool *tr_tool);
 
-static void    shear_x_mag_changed           (GtkAdjustment      *adj,
-                                              GimpTransformTool  *tr_tool);
-static void    shear_y_mag_changed           (GtkAdjustment      *adj,
-                                              GimpTransformTool  *tr_tool);
+static void             shear_x_mag_changed            (GtkAdjustment     *adj,
+                                                        GimpTransformTool *tr_tool);
+static void             shear_y_mag_changed            (GtkAdjustment     *adj,
+                                                        GimpTransformTool *tr_tool);
 
 
 G_DEFINE_TYPE (GimpShearTool, gimp_shear_tool, GIMP_TYPE_TRANSFORM_TOOL)
@@ -100,7 +101,7 @@ gimp_shear_tool_class_init (GimpShearToolClass *klass)
   trans_class->dialog          = gimp_shear_tool_dialog;
   trans_class->dialog_update   = gimp_shear_tool_dialog_update;
   trans_class->prepare         = gimp_shear_tool_prepare;
-  trans_class->motion          = gimp_shear_tool_motion;
+  trans_class->get_widget      = gimp_shear_tool_get_widget;
   trans_class->recalc_matrix   = gimp_shear_tool_recalc_matrix;
   trans_class->get_undo_desc   = gimp_shear_tool_get_undo_desc;
 
@@ -116,7 +117,6 @@ gimp_shear_tool_init (GimpShearTool *shear_tool)
   gimp_tool_control_set_tool_cursor (tool->control, GIMP_TOOL_CURSOR_SHEAR);
 
   tr_tool->progress_text = _("Shearing");
-
   tr_tool->use_grid      = TRUE;
 }
 
@@ -160,83 +160,75 @@ gimp_shear_tool_dialog_update (GimpTransformTool *tr_tool)
 {
   GimpShearTool *shear = GIMP_SHEAR_TOOL (tr_tool);
 
-  gtk_adjustment_set_value (shear->x_adj, tr_tool->trans_info[XSHEAR]);
-  gtk_adjustment_set_value (shear->y_adj, tr_tool->trans_info[YSHEAR]);
+  gtk_adjustment_set_value (shear->x_adj, tr_tool->trans_info[SHEAR_X]);
+  gtk_adjustment_set_value (shear->y_adj, tr_tool->trans_info[SHEAR_Y]);
 }
 
 static void
 gimp_shear_tool_prepare (GimpTransformTool *tr_tool)
 {
-  tr_tool->trans_info[HORZ_OR_VERT] = GIMP_ORIENTATION_UNKNOWN;
-  tr_tool->trans_info[XSHEAR]       = 0.0;
-  tr_tool->trans_info[YSHEAR]       = 0.0;
+  tr_tool->trans_info[ORIENTATION] = GIMP_ORIENTATION_UNKNOWN;
+  tr_tool->trans_info[SHEAR_X]      = 0.0;
+  tr_tool->trans_info[SHEAR_Y]      = 0.0;
 }
 
-static void
-gimp_shear_tool_motion (GimpTransformTool *tr_tool)
+static GimpToolWidget *
+gimp_shear_tool_get_widget (GimpTransformTool *tr_tool)
 {
-  gdouble diffx = tr_tool->curx - tr_tool->lastx;
-  gdouble diffy = tr_tool->cury - tr_tool->lasty;
-
-  /*  If we haven't yet decided on which way to control shearing
-   *  decide using the maximum differential
-   */
-
-  if (tr_tool->trans_info[HORZ_OR_VERT] == GIMP_ORIENTATION_UNKNOWN)
-    {
-      if (ABS (diffx) > MIN_MOVE || ABS (diffy) > MIN_MOVE)
-        {
-          if (ABS (diffx) > ABS (diffy))
-            {
-              tr_tool->trans_info[HORZ_OR_VERT] = GIMP_ORIENTATION_HORIZONTAL;
-              tr_tool->trans_info[XSHEAR] = 0.0;
-            }
-          else
-            {
-              tr_tool->trans_info[HORZ_OR_VERT] = GIMP_ORIENTATION_VERTICAL;
-              tr_tool->trans_info[XSHEAR] = 0.0;
-            }
-        }
-      /*  set the current coords to the last ones  */
-      else
-        {
-          tr_tool->curx = tr_tool->lastx;
-          tr_tool->cury = tr_tool->lasty;
-        }
-    }
+  GimpTool             *tool    = GIMP_TOOL (tr_tool);
+  GimpTransformOptions *options = GIMP_TRANSFORM_TOOL_GET_OPTIONS (tr_tool);
+  GimpDisplayShell     *shell   = gimp_display_get_shell (tool->display);
+  GimpToolWidget       *widget;
+
+  widget = gimp_tool_shear_grid_new (shell,
+                                     tr_tool->x1,
+                                     tr_tool->y1,
+                                     tr_tool->x2,
+                                     tr_tool->y2,
+                                     tr_tool->trans_info[ORIENTATION],
+                                     tr_tool->trans_info[SHEAR_X],
+                                     tr_tool->trans_info[SHEAR_Y]);
+
+  g_object_set (widget,
+                "guide-type",              options->grid_type,
+                "n-guides",                options->grid_size,
+                "inside-function",         GIMP_TRANSFORM_FUNCTION_SHEAR,
+                "outside-function",        GIMP_TRANSFORM_FUNCTION_SHEAR,
+                "constrain-move",          options->constrain_move,
+                "constrain-scale",         options->constrain_scale,
+                "constrain-rotate",        options->constrain_rotate,
+                "constrain-shear",         options->constrain_shear,
+                "constrain-perspective",   options->constrain_perspective,
+                "frompivot-scale",         options->frompivot_scale,
+                "frompivot-shear",         TRUE,
+                "frompivot-perspective",   options->frompivot_perspective,
+                "cornersnap",              options->cornersnap,
+                "fixedpivot",              options->fixedpivot,
+                NULL);
+
+  g_signal_connect (widget, "changed",
+                    G_CALLBACK (gimp_shear_tool_widget_changed),
+                    tr_tool);
 
-  /*  if the direction is known, keep track of the magnitude  */
-  if (tr_tool->trans_info[HORZ_OR_VERT] == GIMP_ORIENTATION_HORIZONTAL)
-    {
-      if (tr_tool->cury > (tr_tool->ty1 + tr_tool->ty3) / 2)
-        tr_tool->trans_info[XSHEAR] += diffx;
-      else
-        tr_tool->trans_info[XSHEAR] -= diffx;
-    }
-  else if (tr_tool->trans_info[HORZ_OR_VERT] == GIMP_ORIENTATION_VERTICAL)
-    {
-      if (tr_tool->curx > (tr_tool->tx1 + tr_tool->tx2) / 2)
-        tr_tool->trans_info[YSHEAR] += diffy;
-      else
-        tr_tool->trans_info[YSHEAR] -= diffy;
-    }
+  return widget;
 }
 
 static void
-gimp_shear_tool_recalc_matrix (GimpTransformTool *tr_tool)
+gimp_shear_tool_recalc_matrix (GimpTransformTool *tr_tool,
+                               GimpToolWidget    *widget)
 {
   gdouble amount;
 
-  if (tr_tool->trans_info[XSHEAR] == 0.0 &&
-      tr_tool->trans_info[YSHEAR] == 0.0)
+  if (tr_tool->trans_info[SHEAR_X] == 0.0 &&
+      tr_tool->trans_info[SHEAR_Y] == 0.0)
     {
-      tr_tool->trans_info[HORZ_OR_VERT] = GIMP_ORIENTATION_UNKNOWN;
+      tr_tool->trans_info[ORIENTATION] = GIMP_ORIENTATION_UNKNOWN;
     }
 
-  if (tr_tool->trans_info[HORZ_OR_VERT] == GIMP_ORIENTATION_HORIZONTAL)
-    amount = tr_tool->trans_info[XSHEAR];
+  if (tr_tool->trans_info[ORIENTATION] == GIMP_ORIENTATION_HORIZONTAL)
+    amount = tr_tool->trans_info[SHEAR_X];
   else
-    amount = tr_tool->trans_info[YSHEAR];
+    amount = tr_tool->trans_info[SHEAR_Y];
 
   gimp_matrix3_identity (&tr_tool->transform);
   gimp_transform_matrix_shear (&tr_tool->transform,
@@ -244,17 +236,29 @@ gimp_shear_tool_recalc_matrix (GimpTransformTool *tr_tool)
                                tr_tool->y1,
                                tr_tool->x2 - tr_tool->x1,
                                tr_tool->y2 - tr_tool->y1,
-                               tr_tool->trans_info[HORZ_OR_VERT],
+                               tr_tool->trans_info[ORIENTATION],
                                amount);
+
+  if (widget)
+    g_object_set (widget,
+                  "transform",   &tr_tool->transform,
+                  "x1",          (gdouble) tr_tool->x1,
+                  "y1",          (gdouble) tr_tool->y1,
+                  "x2",          (gdouble) tr_tool->x2,
+                  "y2",          (gdouble) tr_tool->y2,
+                  "orientation", (gint) tr_tool->trans_info[ORIENTATION],
+                  "shear-x",     tr_tool->trans_info[SHEAR_X],
+                  "shear-y",     tr_tool->trans_info[SHEAR_Y],
+                  NULL);
 }
 
 static gchar *
 gimp_shear_tool_get_undo_desc (GimpTransformTool *tr_tool)
 {
-  gdouble x = tr_tool->trans_info[XSHEAR];
-  gdouble y = tr_tool->trans_info[YSHEAR];
+  gdouble x = tr_tool->trans_info[SHEAR_X];
+  gdouble y = tr_tool->trans_info[SHEAR_Y];
 
-  switch ((gint) tr_tool->trans_info[HORZ_OR_VERT])
+  switch ((gint) tr_tool->trans_info[ORIENTATION])
     {
     case GIMP_ORIENTATION_HORIZONTAL:
       return g_strdup_printf (C_("undo-type", "Shear horizontally by %-3.3g"),
@@ -272,25 +276,38 @@ gimp_shear_tool_get_undo_desc (GimpTransformTool *tr_tool)
 }
 
 static void
+gimp_shear_tool_widget_changed (GimpToolWidget    *widget,
+                                GimpTransformTool *tr_tool)
+{
+  GimpOrientationType orientation;
+
+  g_object_get (widget,
+                "orientation", &orientation,
+                "shear-x",     &tr_tool->trans_info[SHEAR_X],
+                "shear-y",     &tr_tool->trans_info[SHEAR_Y],
+                NULL);
+
+  tr_tool->trans_info[ORIENTATION] = orientation;
+
+  gimp_transform_tool_recalc_matrix (tr_tool, NULL);
+}
+
+static void
 shear_x_mag_changed (GtkAdjustment     *adj,
                      GimpTransformTool *tr_tool)
 {
   gdouble value = gtk_adjustment_get_value (adj);
 
-  if (value != tr_tool->trans_info[XSHEAR])
+  if (value != tr_tool->trans_info[SHEAR_X])
     {
-      gimp_draw_tool_pause (GIMP_DRAW_TOOL (tr_tool));
-
-      if (tr_tool->trans_info[HORZ_OR_VERT] == GIMP_ORIENTATION_UNKNOWN)
-        tr_tool->trans_info[HORZ_OR_VERT] = GIMP_ORIENTATION_HORIZONTAL;
+      if (tr_tool->trans_info[ORIENTATION] == GIMP_ORIENTATION_UNKNOWN)
+        tr_tool->trans_info[ORIENTATION] = GIMP_ORIENTATION_HORIZONTAL;
 
-      tr_tool->trans_info[XSHEAR] = value;
+      tr_tool->trans_info[SHEAR_X] = value;
 
       gimp_transform_tool_push_internal_undo (tr_tool);
 
-      gimp_transform_tool_recalc_matrix (tr_tool);
-
-      gimp_draw_tool_resume (GIMP_DRAW_TOOL (tr_tool));
+      gimp_transform_tool_recalc_matrix (tr_tool, tr_tool->widget);
     }
 }
 
@@ -300,19 +317,15 @@ shear_y_mag_changed (GtkAdjustment     *adj,
 {
   gdouble value = gtk_adjustment_get_value (adj);
 
-  if (value != tr_tool->trans_info[YSHEAR])
+  if (value != tr_tool->trans_info[SHEAR_Y])
     {
-      gimp_draw_tool_pause (GIMP_DRAW_TOOL (tr_tool));
-
-      if (tr_tool->trans_info[HORZ_OR_VERT] == GIMP_ORIENTATION_UNKNOWN)
-        tr_tool->trans_info[HORZ_OR_VERT] = GIMP_ORIENTATION_VERTICAL;
+      if (tr_tool->trans_info[ORIENTATION] == GIMP_ORIENTATION_UNKNOWN)
+        tr_tool->trans_info[ORIENTATION] = GIMP_ORIENTATION_VERTICAL;
 
-      tr_tool->trans_info[YSHEAR] = value;
+      tr_tool->trans_info[SHEAR_Y] = value;
 
       gimp_transform_tool_push_internal_undo (tr_tool);
 
-      gimp_transform_tool_recalc_matrix (tr_tool);
-
-      gimp_draw_tool_resume (GIMP_DRAW_TOOL (tr_tool));
+      gimp_transform_tool_recalc_matrix (tr_tool, tr_tool->widget);
     }
 }
diff --git a/app/tools/gimptransformoptions.c b/app/tools/gimptransformoptions.c
index bff81dd..7bc8237 100644
--- a/app/tools/gimptransformoptions.c
+++ b/app/tools/gimptransformoptions.c
@@ -617,8 +617,8 @@ gimp_transform_options_show_preview (GimpTransformOptions *options)
 {
   g_return_val_if_fail (GIMP_IS_TRANSFORM_OPTIONS (options), FALSE);
 
-  return (options->show_preview                           &&
-          options->type      == GIMP_TRANSFORM_TYPE_LAYER);
+  return (options->show_preview &&
+          options->type == GIMP_TRANSFORM_TYPE_LAYER);
 }
 
 
diff --git a/app/tools/gimptransformtool.c b/app/tools/gimptransformtool.c
index 22f2e07..e57bbd9 100644
--- a/app/tools/gimptransformtool.c
+++ b/app/tools/gimptransformtool.c
@@ -59,6 +59,7 @@
 #include "display/gimpdisplayshell.h"
 #include "display/gimpdisplayshell-transform.h"
 #include "display/gimptoolgui.h"
+#include "display/gimptoolwidget.h"
 
 #include "gimptoolcontrol.h"
 #include "gimptransformoptions.h"
@@ -139,14 +140,18 @@ static GeglBuffer *
                                                              GimpColorProfile     **buffer_profile,
                                                              gint                  *new_offset_x,
                                                              gint                  *new_offset_y);
-static void      gimp_transform_tool_real_draw_gui          (GimpTransformTool     *tr_tool,
-                                                             gint                   handle_w,
-                                                             gint                   handle_h);
-static TransformAction
-                 gimp_transform_tool_real_pick_function     (GimpTransformTool     *tr_tool,
-                                                             const GimpCoords      *coords,
-                                                             GdkModifierType        state,
-                                                             GimpDisplay           *display);
+
+static void      gimp_transform_tool_widget_changed         (GimpToolWidget        *widget,
+                                                             GimpTransformTool     *tr_tool);
+static void      gimp_transform_tool_widget_snap_offsets    (GimpToolWidget        *widget,
+                                                             gint                   offset_x,
+                                                             gint                   offset_y,
+                                                             gint                   width,
+                                                             gint                   height,
+                                                             GimpTransformTool     *tr_tool);
+static void      gimp_transform_tool_widget_status          (GimpToolWidget        *widget,
+                                                             const gchar           *status,
+                                                             GimpTransformTool     *tr_tool);
 
 static void      gimp_transform_tool_halt                   (GimpTransformTool     *tr_tool);
 static void      gimp_transform_tool_set_function           (GimpTransformTool     *tr_tool,
@@ -158,12 +163,7 @@ static void      gimp_transform_tool_prepare                (GimpTransformTool
                                                              GimpDisplay           *display);
 static void      gimp_transform_tool_transform              (GimpTransformTool     *tr_tool,
                                                              GimpDisplay           *display);
-static void      gimp_transform_tool_transform_bounding_box (GimpTransformTool     *tr_tool);
 
-static void      gimp_transform_tool_handles_recalc         (GimpTransformTool     *tr_tool,
-                                                             GimpDisplay           *display,
-                                                             gint                  *handle_w,
-                                                             gint                  *handle_h);
 static void      gimp_transform_tool_response               (GimpToolGui           *gui,
                                                              gint                   response_id,
                                                              GimpTransformTool     *tr_tool);
@@ -222,8 +222,8 @@ gimp_transform_tool_class_init (GimpTransformToolClass *klass)
   klass->recalc_matrix            = NULL;
   klass->get_undo_desc            = NULL;
   klass->transform                = gimp_transform_tool_real_transform;
-  klass->pick_function            = gimp_transform_tool_real_pick_function;
-  klass->draw_gui                 = gimp_transform_tool_real_draw_gui;
+  klass->pick_function            = NULL;
+  klass->draw_gui                 = NULL;
 
   klass->ok_button_label          = _("_Transform");
 }
@@ -316,7 +316,25 @@ gimp_transform_tool_initialize (GimpTool     *tool,
       gimp_transform_tool_prepare (tr_tool, display);
 
       /*  Recalculate the transform tool  */
-      gimp_transform_tool_recalc_matrix (tr_tool);
+      gimp_transform_tool_recalc_matrix (tr_tool, NULL);
+
+      /*  Get the on-canvas gui  */
+      if (GIMP_TRANSFORM_TOOL_GET_CLASS (tr_tool)->get_widget)
+        tr_tool->widget =
+          GIMP_TRANSFORM_TOOL_GET_CLASS (tr_tool)->get_widget (tr_tool);
+
+      if (tr_tool->widget)
+        {
+          g_signal_connect (tr_tool->widget, "changed",
+                            G_CALLBACK (gimp_transform_tool_widget_changed),
+                            tr_tool);
+          g_signal_connect (tr_tool->widget, "snap-offsets",
+                            G_CALLBACK (gimp_transform_tool_widget_snap_offsets),
+                            tr_tool);
+          g_signal_connect (tr_tool->widget, "status",
+                            G_CALLBACK (gimp_transform_tool_widget_status),
+                            tr_tool);
+        }
 
       /*  start drawing the bounding box and handles...  */
       gimp_draw_tool_start (GIMP_DRAW_TOOL (tool), display);
@@ -352,7 +370,7 @@ gimp_transform_tool_control (GimpTool       *tool,
 
     case GIMP_TOOL_ACTION_RESUME:
       gimp_transform_tool_bounds (tr_tool, display);
-      gimp_transform_tool_recalc_matrix (tr_tool);
+      gimp_transform_tool_recalc_matrix (tr_tool, tr_tool->widget);
       break;
 
     case GIMP_TOOL_ACTION_HALT:
@@ -377,6 +395,21 @@ gimp_transform_tool_button_press (GimpTool            *tool,
 {
   GimpTransformTool *tr_tool = GIMP_TRANSFORM_TOOL (tool);
 
+  if (tr_tool->widget)
+    {
+      gimp_tool_widget_hover (tr_tool->widget, coords, state, TRUE);
+
+      if (gimp_tool_widget_button_press (tr_tool->widget, coords, time, state,
+                                         press_type))
+        {
+          tr_tool->grab_widget = tr_tool->widget;
+        }
+
+      gimp_tool_control_activate (tool->control);
+
+      return;
+    }
+
   if (tr_tool->function == TRANSFORM_CREATING)
     GIMP_TOOL_GET_CLASS (tool)->oper_update (tool, coords, state, TRUE, display);
 
@@ -447,9 +480,18 @@ gimp_transform_tool_button_release (GimpTool              *tool,
 
   gimp_tool_control_halt (tool->control);
 
-  /*  if we are creating, there is nothing to be done...exit  */
-  if (tr_tool->function == TRANSFORM_CREATING && tr_tool->use_grid)
-    return;
+  if (tr_tool->grab_widget)
+    {
+      gimp_tool_widget_button_release (tr_tool->grab_widget,
+                                       coords, time, state, release_type);
+      tr_tool->grab_widget = NULL;
+    }
+  else
+    {
+      /*  if we are creating, there is nothing to be done...exit  */
+      if (tr_tool->function == TRANSFORM_CREATING && tr_tool->use_grid)
+        return;
+    }
 
   if (release_type != GIMP_BUTTON_RELEASE_CANCEL)
     {
@@ -465,7 +507,8 @@ gimp_transform_tool_button_release (GimpTool              *tool,
     }
   else
     {
-      gimp_draw_tool_pause (GIMP_DRAW_TOOL (tool));
+      if (! tr_tool->widget)
+        gimp_draw_tool_pause (GIMP_DRAW_TOOL (tool));
 
       /*  Restore the last saved state  */
       memcpy (tr_tool->trans_info, tr_tool->prev_trans_info,
@@ -475,9 +518,10 @@ gimp_transform_tool_button_release (GimpTool              *tool,
       gimp_transform_tool_bounds (tr_tool, display);
 
       /*  recalculate the tool's transformation matrix  */
-      gimp_transform_tool_recalc_matrix (tr_tool);
+      gimp_transform_tool_recalc_matrix (tr_tool, tr_tool->widget);
 
-      gimp_draw_tool_resume (GIMP_DRAW_TOOL (tool));
+      if (! tr_tool->widget)
+        gimp_draw_tool_resume (GIMP_DRAW_TOOL (tool));
     }
 }
 
@@ -490,6 +534,16 @@ gimp_transform_tool_motion (GimpTool         *tool,
 {
   GimpTransformTool *tr_tool = GIMP_TRANSFORM_TOOL (tool);
 
+  if (tr_tool->widget)
+    {
+      if (tr_tool->grab_widget)
+        {
+          gimp_tool_widget_motion (tr_tool->grab_widget, coords, time, state);
+        }
+
+      return;
+    }
+
   /*  if we are creating, there is nothing to be done so exit.  */
   if (tr_tool->function == TRANSFORM_CREATING || ! tr_tool->use_grid)
     return;
@@ -504,7 +558,7 @@ gimp_transform_tool_motion (GimpTool         *tool,
     {
       GIMP_TRANSFORM_TOOL_GET_CLASS (tr_tool)->motion (tr_tool);
 
-      gimp_transform_tool_recalc_matrix (tr_tool);
+      gimp_transform_tool_recalc_matrix (tr_tool, NULL);
     }
 
   tr_tool->lastx = tr_tool->curx;
@@ -590,99 +644,6 @@ gimp_transform_tool_modifier_key (GimpTool        *tool,
     }
 }
 
-static TransformAction
-gimp_transform_tool_real_pick_function (GimpTransformTool *tr_tool,
-                                        const GimpCoords  *coords,
-                                        GdkModifierType    state,
-                                        GimpDisplay       *display)
-{
-  GimpDrawTool   *draw_tool = GIMP_DRAW_TOOL (tr_tool);
-  TransformAction function  = TRANSFORM_HANDLE_NONE;
-
-  if (tr_tool->use_corner_handles)
-    {
-      gdouble closest_dist;
-      gdouble dist;
-
-      dist = gimp_draw_tool_calc_distance_square (draw_tool, display,
-                                                  coords->x, coords->y,
-                                                  tr_tool->tx1, tr_tool->ty1);
-      closest_dist = dist;
-      function = TRANSFORM_HANDLE_NW;
-
-      dist = gimp_draw_tool_calc_distance_square (draw_tool, display,
-                                                  coords->x, coords->y,
-                                                  tr_tool->tx2, tr_tool->ty2);
-      if (dist < closest_dist)
-        {
-          closest_dist = dist;
-          function = TRANSFORM_HANDLE_NE;
-        }
-
-      dist = gimp_draw_tool_calc_distance_square (draw_tool, display,
-                                                  coords->x, coords->y,
-                                                  tr_tool->tx3, tr_tool->ty3);
-      if (dist < closest_dist)
-        {
-          closest_dist = dist;
-          function = TRANSFORM_HANDLE_SW;
-        }
-
-      dist = gimp_draw_tool_calc_distance_square (draw_tool, display,
-                                                  coords->x, coords->y,
-                                                  tr_tool->tx4, tr_tool->ty4);
-      if (dist < closest_dist)
-        {
-          closest_dist = dist;
-          function = TRANSFORM_HANDLE_SE;
-        }
-    }
-
-  if (tr_tool->use_side_handles)
-    {
-      if (gimp_canvas_item_hit (tr_tool->handles[TRANSFORM_HANDLE_N],
-                                coords->x, coords->y))
-        {
-          function = TRANSFORM_HANDLE_N;
-        }
-      else if (gimp_canvas_item_hit (tr_tool->handles[TRANSFORM_HANDLE_E],
-                                     coords->x, coords->y))
-        {
-          function = TRANSFORM_HANDLE_E;
-        }
-      else if (gimp_canvas_item_hit (tr_tool->handles[TRANSFORM_HANDLE_S],
-                                     coords->x, coords->y))
-        {
-          function = TRANSFORM_HANDLE_S;
-        }
-      else if (gimp_canvas_item_hit (tr_tool->handles[TRANSFORM_HANDLE_W],
-                                     coords->x, coords->y))
-        {
-          function = TRANSFORM_HANDLE_W;
-        }
-    }
-
-  if (tr_tool->use_center_handle)
-    {
-      if (gimp_canvas_item_hit (tr_tool->handles[TRANSFORM_HANDLE_CENTER],
-                                coords->x, coords->y))
-        {
-          function = TRANSFORM_HANDLE_CENTER;
-        }
-    }
-
-  if (tr_tool->use_pivot_handle)
-    {
-      if (gimp_canvas_item_hit (tr_tool->handles[TRANSFORM_HANDLE_PIVOT],
-                                coords->x, coords->y))
-        {
-          function = TRANSFORM_HANDLE_PIVOT;
-        }
-    }
-
-  return function;
-}
-
 static void
 gimp_transform_tool_oper_update (GimpTool         *tool,
                                  const GimpCoords *coords,
@@ -694,16 +655,27 @@ gimp_transform_tool_oper_update (GimpTool         *tool,
   GimpDrawTool      *draw_tool = GIMP_DRAW_TOOL (tool);
   TransformAction    function  = TRANSFORM_HANDLE_NONE;
 
+  if (tr_tool->widget)
+    {
+      if (display == tool->display)
+        {
+          gimp_tool_widget_hover (tr_tool->widget, coords, state, proximity);
+        }
+
+      return;
+    }
+
   if (display != tool->display || draw_tool->item == NULL)
     {
       gimp_transform_tool_set_function (tr_tool, function);
       return;
     }
 
-  function = GIMP_TRANSFORM_TOOL_GET_CLASS (tr_tool)->pick_function (tr_tool,
-                                                                     coords,
-                                                                     state,
-                                                                     display);
+  if (GIMP_TRANSFORM_TOOL_GET_CLASS (tr_tool)->pick_function)
+    function = GIMP_TRANSFORM_TOOL_GET_CLASS (tr_tool)->pick_function (tr_tool,
+                                                                       coords,
+                                                                       state,
+                                                                       display);
 
   gimp_transform_tool_set_function (tr_tool, function);
 }
@@ -714,71 +686,27 @@ gimp_transform_tool_cursor_update (GimpTool         *tool,
                                    GdkModifierType   state,
                                    GimpDisplay      *display)
 {
-  GimpTransformTool  *tr_tool  = GIMP_TRANSFORM_TOOL (tool);
-  GimpImage          *image    = gimp_display_get_image (display);
-  GimpCursorType      cursor   = gimp_tool_control_get_cursor (tool->control);
-  GimpCursorModifier  modifier = GIMP_CURSOR_MODIFIER_NONE;
+  GimpTransformTool  *tr_tool     = GIMP_TRANSFORM_TOOL (tool);
+  GimpImage          *image       = gimp_display_get_image (display);
+  GimpCursorType      cursor      = GIMP_CURSOR_CROSSHAIR_SMALL;
+  GimpToolCursorType  tool_cursor = GIMP_TOOL_CURSOR_NONE;
+  GimpCursorModifier  modifier    = GIMP_CURSOR_MODIFIER_NONE;
 
-  if (tr_tool->use_corner_handles ||
-      tr_tool->use_side_handles)
+  if (tr_tool->widget)
     {
-      switch (tr_tool->function)
+      if (display == tool->display)
         {
-        case TRANSFORM_HANDLE_NW:
-          cursor = GIMP_CURSOR_CORNER_TOP_LEFT;
-          break;
-
-        case TRANSFORM_HANDLE_NE:
-          cursor = GIMP_CURSOR_CORNER_TOP_RIGHT;
-          break;
-
-        case TRANSFORM_HANDLE_SW:
-          cursor = GIMP_CURSOR_CORNER_BOTTOM_LEFT;
-          break;
-
-        case TRANSFORM_HANDLE_SE:
-          cursor = GIMP_CURSOR_CORNER_BOTTOM_RIGHT;
-          break;
-
-        case TRANSFORM_HANDLE_N:
-          cursor = GIMP_CURSOR_SIDE_TOP;
-          break;
-
-        case TRANSFORM_HANDLE_E:
-          cursor = GIMP_CURSOR_SIDE_RIGHT;
-          break;
-
-        case TRANSFORM_HANDLE_S:
-          cursor = GIMP_CURSOR_SIDE_BOTTOM;
-          break;
-
-        case TRANSFORM_HANDLE_W:
-          cursor = GIMP_CURSOR_SIDE_LEFT;
-          break;
-
-        default:
-          cursor = GIMP_CURSOR_CROSSHAIR_SMALL;
-          break;
+          gimp_tool_widget_get_cursor (tr_tool->widget,
+                                       coords, state,
+                                       &cursor, &tool_cursor, &modifier);
         }
     }
 
-  if (tr_tool->use_center_handle &&
-      tr_tool->function == TRANSFORM_HANDLE_CENTER)
-    {
-      modifier = GIMP_CURSOR_MODIFIER_MOVE;
-    }
-
-  if (GIMP_TRANSFORM_TOOL_GET_CLASS (tr_tool)->cursor_update)
-    {
-      GIMP_TRANSFORM_TOOL_GET_CLASS (tr_tool)->cursor_update (tr_tool,
-                                                              &cursor,
-                                                              &modifier);
-    }
-
   if (! gimp_transform_tool_check_active_item (tr_tool, image, TRUE, NULL))
     modifier = GIMP_CURSOR_MODIFIER_BAD;
 
   gimp_tool_control_set_cursor          (tool->control, cursor);
+  gimp_tool_control_set_tool_cursor     (tool->control, tool_cursor);
   gimp_tool_control_set_cursor_modifier (tool->control, modifier);
 
   GIMP_TOOL_CLASS (parent_class)->cursor_update (tool, coords, state, display);
@@ -831,7 +759,8 @@ gimp_transform_tool_undo (GimpTool    *tool,
 
   tr_tool->prev_trans_info = item->data;
 
-  gimp_draw_tool_pause (GIMP_DRAW_TOOL (tool));
+  if (! tr_tool->widget)
+    gimp_draw_tool_pause (GIMP_DRAW_TOOL (tool));
 
   /*  Restore the previous transformation info  */
   memcpy (tr_tool->trans_info, tr_tool->prev_trans_info,
@@ -841,9 +770,10 @@ gimp_transform_tool_undo (GimpTool    *tool,
   gimp_transform_tool_bounds (tr_tool, tool->display);
 
   /*  recalculate the tool's transformation matrix  */
-  gimp_transform_tool_recalc_matrix (tr_tool);
+  gimp_transform_tool_recalc_matrix (tr_tool, tr_tool->widget);
 
-  gimp_draw_tool_resume (GIMP_DRAW_TOOL (tool));
+  if (! tr_tool->widget)
+    gimp_draw_tool_resume (GIMP_DRAW_TOOL (tool));
 
   return TRUE;
 }
@@ -868,7 +798,8 @@ gimp_transform_tool_redo (GimpTool    *tool,
   tr_tool->redo_list = g_list_remove (tr_tool->redo_list,
                                       tr_tool->prev_trans_info);
 
-  gimp_draw_tool_pause (GIMP_DRAW_TOOL (tool));
+  if (! tr_tool->widget)
+    gimp_draw_tool_pause (GIMP_DRAW_TOOL (tool));
 
   /*  Restore the previous transformation info  */
   memcpy (tr_tool->trans_info, tr_tool->prev_trans_info,
@@ -878,9 +809,10 @@ gimp_transform_tool_redo (GimpTool    *tool,
   gimp_transform_tool_bounds (tr_tool, tool->display);
 
   /*  recalculate the tool's transformation matrix  */
-  gimp_transform_tool_recalc_matrix (tr_tool);
+  gimp_transform_tool_recalc_matrix (tr_tool, tr_tool->widget);
 
-  gimp_draw_tool_resume (GIMP_DRAW_TOOL (tool));
+  if (! tr_tool->widget)
+    gimp_draw_tool_resume (GIMP_DRAW_TOOL (tool));
 
   return TRUE;
 }
@@ -890,7 +822,8 @@ gimp_transform_tool_options_notify (GimpTool         *tool,
                                     GimpToolOptions  *options,
                                     const GParamSpec *pspec)
 {
-  GimpTransformTool *tr_tool = GIMP_TRANSFORM_TOOL (tool);
+  GimpTransformTool    *tr_tool    = GIMP_TRANSFORM_TOOL (tool);
+  GimpTransformOptions *tr_options = GIMP_TRANSFORM_TOOL_GET_OPTIONS (tool);
 
   GIMP_TOOL_CLASS (parent_class)->options_notify (tool, options, pspec);
 
@@ -900,166 +833,76 @@ gimp_transform_tool_options_notify (GimpTool         *tool,
       return;
     }
 
-  if (tr_tool->use_grid)
-    {
-      gimp_draw_tool_pause (GIMP_DRAW_TOOL (tr_tool));
+  if (! tr_tool->use_grid)
+    return;
+
+  if (! tr_tool->widget)
+    gimp_draw_tool_pause (GIMP_DRAW_TOOL (tr_tool));
 
-      if (! strcmp (pspec->name, "direction"))
+  if (! strcmp (pspec->name, "direction"))
+    {
+      if (tr_tool->widget || tr_tool->function != TRANSFORM_CREATING)
         {
-          if (tr_tool->function != TRANSFORM_CREATING)
+          if (tool->display)
             {
-              if (tool->display)
-                {
-                  /*  reget the selection bounds  */
-                  gimp_transform_tool_bounds (tr_tool, tool->display);
+              /*  reget the selection bounds  */
+              gimp_transform_tool_bounds (tr_tool, tool->display);
 
-                  /*  recalculate the tool's transformation matrix  */
-                  gimp_transform_tool_recalc_matrix (tr_tool);
-                }
+              /*  recalculate the tool's transformation matrix  */
+              gimp_transform_tool_recalc_matrix (tr_tool, tr_tool->widget);
             }
         }
-
-      if (tr_tool->function != TRANSFORM_CREATING)
-        {
-          gimp_transform_tool_transform_bounding_box (tr_tool);
-        }
-
-      gimp_draw_tool_resume (GIMP_DRAW_TOOL (tr_tool));
     }
 
-  if (g_str_has_prefix (pspec->name, "constrain-") ||
-      g_str_has_prefix (pspec->name, "frompivot-") ||
-      ! strcmp (pspec->name, "fixedpivot") ||
-      ! strcmp (pspec->name, "cornersnap"))
+  if (! tr_tool->widget)
+    gimp_draw_tool_resume (GIMP_DRAW_TOOL (tr_tool));
+
+  if (! strcmp (pspec->name, "show-preview"))
     {
-      gimp_transform_tool_dialog_update (tr_tool);
+      if (tr_tool->widget && tr_tool->preview)
+        gimp_canvas_item_set_visible (tr_tool->preview,
+                                      tr_options->show_preview);
     }
-}
-
-static void
-gimp_transform_tool_real_draw_gui (GimpTransformTool *tr_tool,
-                                   gint               handle_w,
-                                   gint               handle_h)
-{
-  GimpDrawTool *draw_tool = GIMP_DRAW_TOOL (tr_tool);
-
-  if (tr_tool->use_corner_handles)
+  else if (! strcmp (pspec->name, "preview-opacity"))
     {
-      tr_tool->handles[TRANSFORM_HANDLE_NW] =
-        gimp_draw_tool_add_handle (draw_tool,
-                                   GIMP_HANDLE_SQUARE,
-                                   tr_tool->tx1, tr_tool->ty1,
-                                   handle_w, handle_h,
-                                   GIMP_HANDLE_ANCHOR_CENTER);
-
-      tr_tool->handles[TRANSFORM_HANDLE_NE] =
-        gimp_draw_tool_add_handle (draw_tool,
-                                   GIMP_HANDLE_SQUARE,
-                                   tr_tool->tx2, tr_tool->ty2,
-                                   handle_w, handle_h,
-                                   GIMP_HANDLE_ANCHOR_CENTER);
-
-      tr_tool->handles[TRANSFORM_HANDLE_SW] =
-        gimp_draw_tool_add_handle (draw_tool,
-                                   GIMP_HANDLE_SQUARE,
-                                   tr_tool->tx3, tr_tool->ty3,
-                                   handle_w, handle_h,
-                                   GIMP_HANDLE_ANCHOR_CENTER);
-
-      tr_tool->handles[TRANSFORM_HANDLE_SE] =
-        gimp_draw_tool_add_handle (draw_tool,
-                                   GIMP_HANDLE_SQUARE,
-                                   tr_tool->tx4, tr_tool->ty4,
-                                   handle_w, handle_h,
-                                   GIMP_HANDLE_ANCHOR_CENTER);
+      if (tr_tool->widget && tr_tool->preview)
+        g_object_set (tr_tool->preview,
+                      "opacity", tr_options->preview_opacity,
+                      NULL);
     }
-
-  if (tr_tool->use_side_handles)
+  else if (! strcmp (pspec->name, "grid-type"))
     {
-      tr_tool->handles[TRANSFORM_HANDLE_N] =
-        gimp_draw_tool_add_handle (draw_tool,
-                                   GIMP_HANDLE_SQUARE,
-                                   (tr_tool->tx1 + tr_tool->tx2) / 2.0,
-                                   (tr_tool->ty1 + tr_tool->ty2) / 2.0,
-                                   handle_w, handle_h,
-                                   GIMP_HANDLE_ANCHOR_CENTER);
-
-      tr_tool->handles[TRANSFORM_HANDLE_E] =
-        gimp_draw_tool_add_handle (draw_tool,
-                                   GIMP_HANDLE_SQUARE,
-                                   (tr_tool->tx2 + tr_tool->tx4) / 2.0,
-                                   (tr_tool->ty2 + tr_tool->ty4) / 2.0,
-                                   handle_w, handle_h,
-                                   GIMP_HANDLE_ANCHOR_CENTER);
-
-      tr_tool->handles[TRANSFORM_HANDLE_S] =
-        gimp_draw_tool_add_handle (draw_tool,
-                                   GIMP_HANDLE_SQUARE,
-                                   (tr_tool->tx3 + tr_tool->tx4) / 2.0,
-                                   (tr_tool->ty3 + tr_tool->ty4) / 2.0,
-                                   handle_w, handle_h,
-                                   GIMP_HANDLE_ANCHOR_CENTER);
-
-      tr_tool->handles[TRANSFORM_HANDLE_W] =
-        gimp_draw_tool_add_handle (draw_tool,
-                                   GIMP_HANDLE_SQUARE,
-                                   (tr_tool->tx3 + tr_tool->tx1) / 2.0,
-                                   (tr_tool->ty3 + tr_tool->ty1) / 2.0,
-                                   handle_w, handle_h,
-                                   GIMP_HANDLE_ANCHOR_CENTER);
+      if (tr_tool->widget)
+        g_object_set (tr_tool->widget,
+                      "guide-type", tr_options->grid_type,
+                      NULL);
     }
-
-  if (tr_tool->use_pivot_handle)
+  else if (! strcmp (pspec->name, "grid-size"))
     {
-      GimpCanvasGroup *stroke_group;
-      gint             d = MIN (handle_w, handle_h);
-
-      if (tr_tool->use_center_handle)
-        d *= 2; /* so you can grab it from under the center handle */
-
-      stroke_group = gimp_draw_tool_add_stroke_group (draw_tool);
-
-      tr_tool->handles[TRANSFORM_HANDLE_PIVOT] = GIMP_CANVAS_ITEM (stroke_group);
-
-      gimp_draw_tool_push_group (draw_tool, stroke_group);
-
-      gimp_draw_tool_add_handle (draw_tool,
-                                 GIMP_HANDLE_CIRCLE,
-                                 tr_tool->tpx, tr_tool->tpy,
-                                 d, d,
-                                 GIMP_HANDLE_ANCHOR_CENTER);
-      gimp_draw_tool_add_handle (draw_tool,
-                                 GIMP_HANDLE_CROSS,
-                                 tr_tool->tpx, tr_tool->tpy,
-                                 d, d,
-                                 GIMP_HANDLE_ANCHOR_CENTER);
-
-      gimp_draw_tool_pop_group (draw_tool);
+      if (tr_tool->widget)
+        g_object_set (tr_tool->widget,
+                      "n-guides", tr_options->grid_size,
+                      NULL);
     }
-
-  if (tr_tool->use_center_handle)
+  else if (g_str_has_prefix (pspec->name, "constrain-") ||
+           g_str_has_prefix (pspec->name, "frompivot-") ||
+           ! strcmp (pspec->name, "fixedpivot") ||
+           ! strcmp (pspec->name, "cornersnap"))
     {
-      GimpCanvasGroup *stroke_group;
-      gint             d = MIN (handle_w, handle_h);
-
-      stroke_group = gimp_draw_tool_add_stroke_group (draw_tool);
-
-      tr_tool->handles[TRANSFORM_HANDLE_CENTER] = GIMP_CANVAS_ITEM (stroke_group);
+      if (tr_tool->widget)
+        {
+          gboolean value;
 
-      gimp_draw_tool_push_group (draw_tool, stroke_group);
+          g_object_get (options,
+                        pspec->name, &value,
+                        NULL);
 
-      gimp_draw_tool_add_handle (draw_tool,
-                                 GIMP_HANDLE_SQUARE,
-                                 tr_tool->tcx, tr_tool->tcy,
-                                 d, d,
-                                 GIMP_HANDLE_ANCHOR_CENTER);
-      gimp_draw_tool_add_handle (draw_tool,
-                                 GIMP_HANDLE_CROSS,
-                                 tr_tool->tcx, tr_tool->tcy,
-                                 d, d,
-                                 GIMP_HANDLE_ANCHOR_CENTER);
+          g_object_set (tr_tool->widget,
+                        pspec->name, value,
+                        NULL);
+        }
 
-      gimp_draw_tool_pop_group (draw_tool);
+      gimp_transform_tool_dialog_update (tr_tool);
     }
 }
 
@@ -1070,29 +913,44 @@ gimp_transform_tool_draw (GimpDrawTool *draw_tool)
   GimpTransformTool    *tr_tool = GIMP_TRANSFORM_TOOL (draw_tool);
   GimpTransformOptions *options = GIMP_TRANSFORM_TOOL_GET_OPTIONS (tool);
   GimpImage            *image   = gimp_display_get_image (tool->display);
-  gint                  handle_w;
-  gint                  handle_h;
 
   memset (tr_tool->handles, 0, sizeof (tr_tool->handles));
 
   if (tr_tool->use_grid)
     {
-      if (gimp_transform_options_show_preview (options))
+      gboolean show_preview = gimp_transform_options_show_preview (options);
+
+      if (tr_tool->widget || show_preview)
         {
           GimpMatrix3 matrix = tr_tool->transform;
 
           if (options->direction == GIMP_TRANSFORM_BACKWARD)
             gimp_matrix3_invert (&matrix);
 
-          gimp_draw_tool_add_transform_preview (draw_tool,
-                                                tool->drawable,
-                                                &matrix,
-                                                tr_tool->x1,
-                                                tr_tool->y1,
-                                                tr_tool->x2,
-                                                tr_tool->y2,
-                                                tr_tool->does_perspective,
-                                                options->preview_opacity);
+          tr_tool->preview =
+            gimp_draw_tool_add_transform_preview (draw_tool,
+                                                  tool->drawable,
+                                                  &matrix,
+                                                  tr_tool->x1,
+                                                  tr_tool->y1,
+                                                  tr_tool->x2,
+                                                  tr_tool->y2,
+                                                  tr_tool->does_perspective,
+                                                  options->preview_opacity);
+          g_object_add_weak_pointer (G_OBJECT (tr_tool->preview),
+                                     (gpointer) &tr_tool->preview);
+
+          if (tr_tool->widget)
+            gimp_canvas_item_set_visible (tr_tool->preview, show_preview);
+        }
+
+      if (tr_tool->widget)
+        {
+          GimpCanvasItem *item = gimp_tool_widget_get_item (tr_tool->widget);
+
+          gimp_draw_tool_add_item (draw_tool, item);
+
+          return;
         }
 
       gimp_draw_tool_add_transform_guides (draw_tool,
@@ -1105,10 +963,8 @@ gimp_transform_tool_draw (GimpDrawTool *draw_tool)
                                            tr_tool->y2);
     }
 
-  gimp_transform_tool_handles_recalc (tr_tool, tool->display,
-                                      &handle_w, &handle_h);
-
-  GIMP_TRANSFORM_TOOL_GET_CLASS (tr_tool)->draw_gui (tr_tool, handle_w, handle_h);
+  if (GIMP_TRANSFORM_TOOL_GET_CLASS (tr_tool)->draw_gui)
+    GIMP_TRANSFORM_TOOL_GET_CLASS (tr_tool)->draw_gui (tr_tool);
 
   if (tr_tool->handles[tr_tool->function])
     {
@@ -1460,6 +1316,59 @@ gimp_transform_tool_transform (GimpTransformTool *tr_tool,
 }
 
 static void
+gimp_transform_tool_widget_changed (GimpToolWidget    *widget,
+                                    GimpTransformTool *tr_tool)
+{
+  GimpTransformOptions *options = GIMP_TRANSFORM_TOOL_GET_OPTIONS (tr_tool);
+
+  if (tr_tool->preview)
+    {
+      GimpMatrix3 matrix = tr_tool->transform;
+
+      if (options->direction == GIMP_TRANSFORM_BACKWARD)
+        gimp_matrix3_invert (&matrix);
+
+      gimp_canvas_item_begin_change (tr_tool->preview);
+      g_object_set (tr_tool->preview,
+                    "transform", &matrix,
+                    NULL);
+      gimp_canvas_item_end_change (tr_tool->preview);
+    }
+}
+
+static void
+gimp_transform_tool_widget_snap_offsets (GimpToolWidget    *widget,
+                                         gint               offset_x,
+                                         gint               offset_y,
+                                         gint               width,
+                                         gint               height,
+                                         GimpTransformTool *tr_tool)
+{
+  GimpTool *tool = GIMP_TOOL (tr_tool);
+
+  gimp_tool_control_set_snap_offsets (tool->control,
+                                      offset_x, offset_y,
+                                      width, height);
+}
+
+static void
+gimp_transform_tool_widget_status (GimpToolWidget    *widget,
+                                   const gchar       *status,
+                                   GimpTransformTool *tr_tool)
+{
+  GimpTool *tool = GIMP_TOOL (tr_tool);
+
+  if (status)
+    {
+      gimp_tool_replace_status (tool, tool->display, "%s", status);
+    }
+  else
+    {
+      gimp_tool_pop_status (tool, tool->display);
+    }
+}
+
+static void
 gimp_transform_tool_halt (GimpTransformTool *tr_tool)
 {
   GimpTool *tool = GIMP_TOOL (tr_tool);
@@ -1467,6 +1376,8 @@ gimp_transform_tool_halt (GimpTransformTool *tr_tool)
   if (gimp_draw_tool_is_active (GIMP_DRAW_TOOL (tr_tool)))
     gimp_draw_tool_stop (GIMP_DRAW_TOOL (tr_tool));
 
+  g_clear_object (&tr_tool->widget);
+
   tr_tool->function = TRANSFORM_CREATING;
 
   if (tr_tool->gui)
@@ -1515,41 +1426,6 @@ gimp_transform_tool_set_function (GimpTransformTool *tr_tool,
     }
 }
 
-static void
-gimp_transform_tool_transform_bounding_box (GimpTransformTool *tr_tool)
-{
-  g_return_if_fail (GIMP_IS_TRANSFORM_TOOL (tr_tool));
-
-  gimp_matrix3_transform_point (&tr_tool->transform,
-                                tr_tool->x1, tr_tool->y1,
-                                &tr_tool->tx1, &tr_tool->ty1);
-  gimp_matrix3_transform_point (&tr_tool->transform,
-                                tr_tool->x2, tr_tool->y1,
-                                &tr_tool->tx2, &tr_tool->ty2);
-  gimp_matrix3_transform_point (&tr_tool->transform,
-                                tr_tool->x1, tr_tool->y2,
-                                &tr_tool->tx3, &tr_tool->ty3);
-  gimp_matrix3_transform_point (&tr_tool->transform,
-                                tr_tool->x2, tr_tool->y2,
-                                &tr_tool->tx4, &tr_tool->ty4);
-  gimp_matrix3_transform_point (&tr_tool->transform,
-                                tr_tool->px, tr_tool->py,
-                                &tr_tool->tpx, &tr_tool->tpy);
-
-  /* don't transform these */
-  tr_tool->tpx = tr_tool->px;
-  tr_tool->tpy = tr_tool->py;
-
-  tr_tool->tcx = (tr_tool->tx1 +
-                  tr_tool->tx2 +
-                  tr_tool->tx3 +
-                  tr_tool->tx4) / 4.0;
-  tr_tool->tcy = (tr_tool->ty1 +
-                  tr_tool->ty2 +
-                  tr_tool->ty3 +
-                  tr_tool->ty4) / 4.0;
-}
-
 static gboolean
 gimp_transform_tool_bounds (GimpTransformTool *tr_tool,
                             GimpDisplay       *display)
@@ -1630,50 +1506,10 @@ gimp_transform_tool_bounds (GimpTransformTool *tr_tool,
       break;
     }
 
-  tr_tool->aspect = ((gdouble) (tr_tool->x2 - tr_tool->x1) /
-                     (gdouble) (tr_tool->y2 - tr_tool->y1));
-
   return non_empty;
 }
 
 static void
-gimp_transform_tool_handles_recalc (GimpTransformTool *tr_tool,
-                                    GimpDisplay       *display,
-                                    gint              *handle_w,
-                                    gint              *handle_h)
-{
-  gint dx1, dy1;
-  gint dx2, dy2;
-  gint dx3, dy3;
-  gint dx4, dy4;
-  gint x1, y1;
-  gint x2, y2;
-
-  gimp_display_shell_transform_xy (gimp_display_get_shell (display),
-                                   tr_tool->tx1, tr_tool->ty1,
-                                   &dx1, &dy1);
-  gimp_display_shell_transform_xy (gimp_display_get_shell (display),
-                                   tr_tool->tx2, tr_tool->ty2,
-                                   &dx2, &dy2);
-  gimp_display_shell_transform_xy (gimp_display_get_shell (display),
-                                   tr_tool->tx3, tr_tool->ty3,
-                                   &dx3, &dy3);
-  gimp_display_shell_transform_xy (gimp_display_get_shell (display),
-                                   tr_tool->tx4, tr_tool->ty4,
-                                   &dx4, &dy4);
-
-  x1 = MIN4 (dx1, dx2, dx3, dx4);
-  y1 = MIN4 (dy1, dy2, dy3, dy4);
-  x2 = MAX4 (dx1, dx2, dx3, dx4);
-  y2 = MAX4 (dy1, dy2, dy3, dy4);
-
-  *handle_w = CLAMP ((x2 - x1) / 3,
-                     MIN_HANDLE_SIZE, GIMP_TOOL_HANDLE_SIZE_LARGE);
-  *handle_h = CLAMP ((y2 - y1) / 3,
-                     MIN_HANDLE_SIZE, GIMP_TOOL_HANDLE_SIZE_LARGE);
-}
-
-static void
 gimp_transform_tool_dialog (GimpTransformTool *tr_tool)
 {
   GimpTool         *tool      = GIMP_TOOL (tr_tool);
@@ -1736,14 +1572,14 @@ gimp_transform_tool_prepare (GimpTransformTool *tr_tool,
 }
 
 void
-gimp_transform_tool_recalc_matrix (GimpTransformTool *tr_tool)
+gimp_transform_tool_recalc_matrix (GimpTransformTool *tr_tool,
+                                   GimpToolWidget    *widget)
 {
   g_return_if_fail (GIMP_IS_TRANSFORM_TOOL (tr_tool));
+  g_return_if_fail (widget == NULL || GIMP_IS_TOOL_WIDGET (widget));
 
   if (GIMP_TRANSFORM_TOOL_GET_CLASS (tr_tool)->recalc_matrix)
-    GIMP_TRANSFORM_TOOL_GET_CLASS (tr_tool)->recalc_matrix (tr_tool);
-
-  gimp_transform_tool_transform_bounding_box (tr_tool);
+    GIMP_TRANSFORM_TOOL_GET_CLASS (tr_tool)->recalc_matrix (tr_tool, widget);
 
   gimp_transform_tool_dialog_update (tr_tool);
 
@@ -1776,7 +1612,8 @@ gimp_transform_tool_response (GimpToolGui       *gui,
 
       gimp_transform_tool_update_sensitivity (tr_tool);
 
-      gimp_draw_tool_pause (GIMP_DRAW_TOOL (tool));
+      if (! tr_tool->widget)
+        gimp_draw_tool_pause (GIMP_DRAW_TOOL (tool));
 
       /*  Restore the previous transformation info  */
       memcpy (tr_tool->trans_info, tr_tool->prev_trans_info,
@@ -1786,9 +1623,10 @@ gimp_transform_tool_response (GimpToolGui       *gui,
       gimp_transform_tool_bounds (tr_tool, display);
 
       /*  recalculate the tool's transformation matrix  */
-      gimp_transform_tool_recalc_matrix (tr_tool);
+      gimp_transform_tool_recalc_matrix (tr_tool, tr_tool->widget);
 
-      gimp_draw_tool_resume (GIMP_DRAW_TOOL (tool));
+      if (! tr_tool->widget)
+        gimp_draw_tool_resume (GIMP_DRAW_TOOL (tool));
 
       /*  update the undo actions / menu items  */
       gimp_image_flush (gimp_display_get_image (display));
diff --git a/app/tools/gimptransformtool.h b/app/tools/gimptransformtool.h
index df4e0e2..4e893da 100644
--- a/app/tools/gimptransformtool.h
+++ b/app/tools/gimptransformtool.h
@@ -89,16 +89,6 @@ struct _GimpTransformTool
 
   gint            x1, y1;             /*  upper left hand coordinate         */
   gint            x2, y2;             /*  lower right hand coords            */
-  gdouble         cx, cy;             /*  center point (for moving)          */
-  gdouble         px, py;             /*  pivot point (for rotation/scaling) */
-  gdouble         aspect;             /*  original aspect ratio              */
-
-  gdouble         tx1, ty1;           /*  transformed handle coords          */
-  gdouble         tx2, ty2;
-  gdouble         tx3, ty3;
-  gdouble         tx4, ty4;
-  gdouble         tcx, tcy;
-  gdouble         tpx, tpy;
 
   GimpMatrix3     transform;          /*  transformation matrix              */
   TransInfo       trans_info;         /*  transformation info                */
@@ -116,14 +106,14 @@ struct _GimpTransformTool
   TransformAction function;           /*  current tool activity              */
 
   gboolean        use_grid;           /*  does the tool use the grid         */
-  gboolean        use_corner_handles; /*  uses the corner handles            */
-  gboolean        use_side_handles;   /*  use handles at midpoints of edges  */
-  gboolean        use_center_handle;  /*  uses the center handle             */
-  gboolean        use_pivot_handle;   /*  use the pivot point handle         */
-
   gboolean        does_perspective;   /*  does the tool do non-affine
-                                          transformations                    */
+                                       *  transformations
+                                       */
+
+  GimpToolWidget *widget;
+  GimpToolWidget *grab_widget;
 
+  GimpCanvasItem *preview;
   GimpCanvasItem *handles[TRANSFORM_HANDLE_NUM];
 
   const gchar    *progress_text;
@@ -136,30 +126,32 @@ struct _GimpTransformToolClass
   GimpDrawToolClass  parent_class;
 
   /*  virtual functions  */
-  void            (* dialog)        (GimpTransformTool *tool);
-  void            (* dialog_update) (GimpTransformTool *tool);
-  void            (* prepare)       (GimpTransformTool *tool);
-  void            (* motion)        (GimpTransformTool *tool);
-  void            (* recalc_matrix) (GimpTransformTool *tool);
-  gchar         * (* get_undo_desc) (GimpTransformTool *tool);
-  TransformAction (* pick_function) (GimpTransformTool *tool,
-                                     const GimpCoords  *coords,
-                                     GdkModifierType    state,
-                                     GimpDisplay       *display);
-  void            (* cursor_update) (GimpTransformTool  *tr_tool,
-                                     GimpCursorType     *cursor,
-                                     GimpCursorModifier *modifier);
-  void            (* draw_gui)      (GimpTransformTool *tool,
-                                     gint               handle_w,
-                                     gint               handle_h);
-  GeglBuffer    * (* transform)     (GimpTransformTool *tool,
-                                     GimpItem          *item,
-                                     GeglBuffer        *orig_buffer,
-                                     gint               orig_offset_x,
-                                     gint               orig_offset_y,
-                                     GimpColorProfile **buffer_profile,
-                                     gint              *new_offset_x,
-                                     gint              *new_offset_y);
+  void             (* dialog)        (GimpTransformTool *tool);
+  void             (* dialog_update) (GimpTransformTool *tool);
+  void             (* prepare)       (GimpTransformTool *tool);
+
+  GimpToolWidget * (* get_widget)    (GimpTransformTool *tool);
+
+  void             (* motion)        (GimpTransformTool *tool);
+  void             (* recalc_matrix) (GimpTransformTool *tool,
+                                      GimpToolWidget    *widget);
+  gchar          * (* get_undo_desc) (GimpTransformTool *tool);
+  TransformAction  (* pick_function) (GimpTransformTool *tool,
+                                      const GimpCoords  *coords,
+                                      GdkModifierType    state,
+                                      GimpDisplay       *display);
+  void             (* cursor_update) (GimpTransformTool  *tr_tool,
+                                      GimpCursorType     *cursor,
+                                      GimpCursorModifier *modifier);
+  void             (* draw_gui)      (GimpTransformTool *tool);
+  GeglBuffer     * (* transform)     (GimpTransformTool *tool,
+                                      GimpItem          *item,
+                                      GeglBuffer        *orig_buffer,
+                                      gint               orig_offset_x,
+                                      gint               orig_offset_y,
+                                      GimpColorProfile **buffer_profile,
+                                      gint              *new_offset_x,
+                                      gint              *new_offset_y);
 
   const gchar *ok_button_label;
 };
@@ -167,7 +159,8 @@ struct _GimpTransformToolClass
 
 GType   gimp_transform_tool_get_type           (void) G_GNUC_CONST;
 
-void    gimp_transform_tool_recalc_matrix      (GimpTransformTool *tr_tool);
+void    gimp_transform_tool_recalc_matrix      (GimpTransformTool *tr_tool,
+                                                GimpToolWidget    *widget);
 void    gimp_transform_tool_push_internal_undo (GimpTransformTool *tr_tool);
 
 
diff --git a/app/tools/gimpunifiedtransformtool.c b/app/tools/gimpunifiedtransformtool.c
index 7be8a40..ee87287 100644
--- a/app/tools/gimpunifiedtransformtool.c
+++ b/app/tools/gimpunifiedtransformtool.c
@@ -17,8 +17,6 @@
 
 #include "config.h"
 
-#include <string.h>
-
 #include <gegl.h>
 #include <gtk/gtk.h>
 
@@ -28,22 +26,12 @@
 #include "tools-types.h"
 
 #include "core/gimp-transform-utils.h"
-#include "core/gimp-utils.h"
-#include "core/gimpchannel.h"
-#include "core/gimpdrawable-transform.h"
-#include "core/gimpimage.h"
-
-#include "vectors/gimpstroke.h"
-#include "vectors/gimpvectors.h"
 
 #include "widgets/gimphelp-ids.h"
 
-#include "display/gimpcanvasgroup.h"
-#include "display/gimpcanvashandle.h"
 #include "display/gimpdisplay.h"
-#include "display/gimpdisplayshell.h"
-#include "display/gimpdisplayshell-transform.h"
 #include "display/gimptoolgui.h"
+#include "display/gimptooltransformgrid.h"
 
 #include "gimptoolcontrol.h"
 #include "gimptransformoptions.h"
@@ -70,22 +58,16 @@ enum
 
 /*  local function prototypes  */
 
-static void            gimp_unified_transform_tool_dialog        (GimpTransformTool *tr_tool);
-static void            gimp_unified_transform_tool_dialog_update (GimpTransformTool *tr_tool);
-static void            gimp_unified_transform_tool_prepare       (GimpTransformTool *tr_tool);
-static void            gimp_unified_transform_tool_motion        (GimpTransformTool *tr_tool);
-static void            gimp_unified_transform_tool_recalc_matrix (GimpTransformTool *tr_tool);
-static gchar *         gimp_unified_transform_tool_get_undo_desc (GimpTransformTool *tr_tool);
-static TransformAction gimp_unified_transform_tool_pick_function (GimpTransformTool *tr_tool,
-                                                                  const GimpCoords  *coords,
-                                                                  GdkModifierType    state,
-                                                                  GimpDisplay       *display);
-static void            gimp_unified_transform_tool_cursor_update (GimpTransformTool  *tr_tool,
-                                                                  GimpCursorType     *cursor,
-                                                                  GimpCursorModifier *modifier);
-static void            gimp_unified_transform_tool_draw_gui      (GimpTransformTool *tr_tool,
-                                                                  gint               handle_w,
-                                                                  gint               handle_h);
+static void             gimp_unified_transform_tool_dialog         (GimpTransformTool *tr_tool);
+static void             gimp_unified_transform_tool_dialog_update  (GimpTransformTool *tr_tool);
+static void             gimp_unified_transform_tool_prepare        (GimpTransformTool *tr_tool);
+static GimpToolWidget * gimp_unified_transform_tool_get_widget     (GimpTransformTool *tr_tool);
+static void             gimp_unified_transform_tool_recalc_matrix  (GimpTransformTool *tr_tool,
+                                                                    GimpToolWidget    *widget);
+static gchar          * gimp_unified_transform_tool_get_undo_desc  (GimpTransformTool *tr_tool);
+
+static void             gimp_unified_transform_tool_widget_changed (GimpToolWidget    *widget,
+                                                                    GimpTransformTool *tr_tool);
 
 
 G_DEFINE_TYPE (GimpUnifiedTransformTool, gimp_unified_transform_tool,
@@ -118,12 +100,9 @@ gimp_unified_transform_tool_class_init (GimpUnifiedTransformToolClass *klass)
   trans_class->dialog        = gimp_unified_transform_tool_dialog;
   trans_class->dialog_update = gimp_unified_transform_tool_dialog_update;
   trans_class->prepare       = gimp_unified_transform_tool_prepare;
-  trans_class->motion        = gimp_unified_transform_tool_motion;
+  trans_class->get_widget    = gimp_unified_transform_tool_get_widget;
   trans_class->recalc_matrix = gimp_unified_transform_tool_recalc_matrix;
   trans_class->get_undo_desc = gimp_unified_transform_tool_get_undo_desc;
-  trans_class->pick_function = gimp_unified_transform_tool_pick_function;
-  trans_class->cursor_update = gimp_unified_transform_tool_cursor_update;
-  trans_class->draw_gui      = gimp_unified_transform_tool_draw_gui;
 }
 
 static void
@@ -131,630 +110,9 @@ gimp_unified_transform_tool_init (GimpUnifiedTransformTool *unified_tool)
 {
   GimpTransformTool *tr_tool = GIMP_TRANSFORM_TOOL (unified_tool);
 
-  tr_tool->progress_text      = _("Unified transform");
-
-  tr_tool->use_grid           = TRUE;
-  tr_tool->use_corner_handles = TRUE;
-
-  tr_tool->does_perspective   = TRUE;
-}
-
-static gboolean
-transform_is_convex (GimpVector2 *pos)
-{
-  return gimp_transform_polygon_is_convex (pos[0].x, pos[0].y,
-                                           pos[1].x, pos[1].y,
-                                           pos[2].x, pos[2].y,
-                                           pos[3].x, pos[3].y);
-}
-
-static inline gboolean
-vectorisnull (GimpVector2 v)
-{
-  return ((v.x == 0.0) && (v.y == 0.0));
-}
-
-static inline gdouble
-dotprod (GimpVector2 a,
-         GimpVector2 b)
-{
-  return a.x * b.x + a.y * b.y;
-}
-
-static inline gdouble
-norm (GimpVector2 a)
-{
-  return sqrt (dotprod (a, a));
-}
-
-static inline GimpVector2
-vectorsubtract (GimpVector2 a,
-                GimpVector2 b)
-{
-  GimpVector2 c;
-
-  c.x = a.x - b.x;
-  c.y = a.y - b.y;
-
-  return c;
-}
-
-static inline GimpVector2
-vectoradd (GimpVector2 a,
-           GimpVector2 b)
-{
-  GimpVector2 c;
-
-  c.x = a.x + b.x;
-  c.y = a.y + b.y;
-
-  return c;
-}
-
-static inline GimpVector2
-scalemult (GimpVector2 a,
-           gdouble     b)
-{
-  GimpVector2 c;
-
-  c.x = a.x * b;
-  c.y = a.y * b;
-
-  return c;
-}
-
-static inline GimpVector2
-vectorproject (GimpVector2 a,
-               GimpVector2 b)
-{
-  return scalemult (b, dotprod (a, b) / dotprod (b, b));
-}
-
-/* finds the clockwise angle between the vectors given, 0-2π */
-static inline gdouble
-calcangle (GimpVector2 a,
-           GimpVector2 b)
-{
-  gdouble angle, angle2;
-  gdouble length;
-
-  if (vectorisnull (a) || vectorisnull (b))
-    return 0.0;
-
-  length = norm (a) * norm (b);
-
-  angle = acos (dotprod (a, b)/length);
-  angle2 = b.y;
-  b.y = -b.x;
-  b.x = angle2;
-  angle2 = acos (dotprod (a, b)/length);
-
-  return ((angle2 > G_PI/2.) ? angle : 2*G_PI-angle);
-}
-
-static inline GimpVector2
-rotate2d (GimpVector2 p,
-          gdouble     angle)
-{
-  GimpVector2 ret;
-
-  ret.x = cos (angle) * p.x-sin (angle) * p.y;
-  ret.y = sin (angle) * p.x+cos (angle) * p.y;
-
-  return ret;
-}
-
-static inline GimpVector2
-lineintersect (GimpVector2 p1, GimpVector2 p2,
-               GimpVector2 q1, GimpVector2 q2)
-{
-  gdouble     denom, u;
-  GimpVector2 p;
-
-  denom = (q2.y - q1.y) * (p2.x - p1.x) - (q2.x - q1.x) * (p2.y - p1.y);
-  if (denom == 0.0)
-    {
-      p.x = (p1.x + p2.x + q1.x + q2.x) / 4;
-      p.y = (p1.y + p2.y + q1.y + q2.y) / 4;
-    }
-  else
-    {
-      u = (q2.x - q1.x) * (p1.y - q1.y) - (q2.y - q1.y) * (p1.x - q1.x);
-      u /= denom;
-
-      p.x = p1.x + u * (p2.x - p1.x);
-      p.y = p1.y + u * (p2.y - p1.y);
-    }
-
-  return p;
-}
-
-static inline GimpVector2
-get_pivot_delta (GimpTransformTool *tr_tool,
-                 GimpVector2       *oldpos,
-                 GimpVector2       *newpos,
-                 GimpVector2        pivot)
-{
-  GimpMatrix3 transform_before, transform_after;
-  GimpVector2 delta;
-
-  gimp_matrix3_identity (&transform_before);
-  gimp_matrix3_identity (&transform_after);
-
-  gimp_transform_matrix_perspective (&transform_before,
-                                     tr_tool->x1,
-                                     tr_tool->y1,
-                                     tr_tool->x2 - tr_tool->x1,
-                                     tr_tool->y2 - tr_tool->y1,
-                                     oldpos[0].x, oldpos[0].y,
-                                     oldpos[1].x, oldpos[1].y,
-                                     oldpos[2].x, oldpos[2].y,
-                                     oldpos[3].x, oldpos[3].y);
-  gimp_transform_matrix_perspective (&transform_after,
-                                     tr_tool->x1,
-                                     tr_tool->y1,
-                                     tr_tool->x2 - tr_tool->x1,
-                                     tr_tool->y2 - tr_tool->y1,
-                                     newpos[0].x, newpos[0].y,
-                                     newpos[1].x, newpos[1].y,
-                                     newpos[2].x, newpos[2].y,
-                                     newpos[3].x, newpos[3].y);
-  gimp_matrix3_invert (&transform_before);
-  gimp_matrix3_mult (&transform_after, &transform_before);
-  gimp_matrix3_transform_point (&transform_before,
-                                pivot.x, pivot.y, &delta.x, &delta.y);
-
-  delta = vectorsubtract (delta, pivot);
-
-  return delta;
-}
-
-static gboolean
-point_is_inside_polygon (gint     n,
-                         gdouble *x,
-                         gdouble *y,
-                         gdouble  px,
-                         gdouble  py)
-{
-  gint     i, j;
-  gboolean odd = FALSE;
-
-  for (i = 0, j = n - 1; i < n; j = i++)
-    {
-      if ((y[i] < py && y[j] >= py) ||
-          (y[j] < py && y[i] >= py))
-        {
-          if (x[i] + (py - y[i]) / (y[j] - y[i]) * (x[j] - x[i]) < px)
-            odd = !odd;
-        }
-    }
-
-  return odd;
-}
-
-static gboolean
-point_is_inside_polygon_pos (GimpVector2 *pos,
-                             GimpVector2  point)
-{
-  return point_is_inside_polygon (4,
-                                  (gdouble[4]){ pos[0].x, pos[1].x,
-                                                pos[3].x, pos[2].x },
-                                  (gdouble[4]){ pos[0].y, pos[1].y,
-                                                pos[3].y, pos[2].y },
-                                  point.x, point.y);
-}
-
-static const gchar *
-get_friendly_operation_name (TransformAction op)
-{
-  switch (op)
-    {
-    case TRANSFORM_HANDLE_NONE:
-      return "";
-    case TRANSFORM_HANDLE_NW_P:
-    case TRANSFORM_HANDLE_NE_P:
-    case TRANSFORM_HANDLE_SW_P:
-    case TRANSFORM_HANDLE_SE_P:
-      return "Change perspective";
-    case TRANSFORM_HANDLE_NW:
-    case TRANSFORM_HANDLE_NE:
-    case TRANSFORM_HANDLE_SW:
-    case TRANSFORM_HANDLE_SE:
-      return "Scale";
-    case TRANSFORM_HANDLE_N:
-    case TRANSFORM_HANDLE_S:
-    case TRANSFORM_HANDLE_E:
-    case TRANSFORM_HANDLE_W:
-      return "Scale";
-    case TRANSFORM_HANDLE_CENTER:
-      return "Move";
-    case TRANSFORM_HANDLE_PIVOT:
-      return "Move pivot";
-    case TRANSFORM_HANDLE_N_S:
-    case TRANSFORM_HANDLE_S_S:
-    case TRANSFORM_HANDLE_E_S:
-    case TRANSFORM_HANDLE_W_S:
-      return "Shear";
-    case TRANSFORM_HANDLE_ROTATION:
-      return "Rotate";
-    default:
-      g_assert_not_reached ();
-    }
-}
-
-static TransformAction
-gimp_unified_transform_tool_pick_function (GimpTransformTool *tr_tool,
-                                           const GimpCoords  *coords,
-                                           GdkModifierType    state,
-                                           GimpDisplay       *display)
-{
-  GimpTool        *tool = GIMP_TOOL (tr_tool);
-  TransformAction  ret = TRANSFORM_HANDLE_NONE;
-  TransformAction  i;
-
-  for (i = TRANSFORM_HANDLE_NONE + 1; i < TRANSFORM_HANDLE_NUM; i++)
-    {
-      if (tr_tool->handles[i] &&
-          gimp_canvas_item_hit (tr_tool->handles[i], coords->x, coords->y))
-        {
-          ret = i;
-          break;
-        }
-    }
-
-  if (ret == TRANSFORM_HANDLE_NONE)
-    {
-      /* points passed in clockwise order */
-      if (point_is_inside_polygon (4,
-                                   (gdouble[4]){ tr_tool->tx1, tr_tool->tx2,
-                                                 tr_tool->tx4, tr_tool->tx3 },
-                                   (gdouble[4]){ tr_tool->ty1, tr_tool->ty2,
-                                                 tr_tool->ty4, tr_tool->ty3 },
-                                   coords->x, coords->y))
-        ret = TRANSFORM_HANDLE_CENTER;
-      else
-        ret = TRANSFORM_HANDLE_ROTATION;
-    }
-
-  gimp_tool_pop_status (tool, tool->display);
-
-  if (ret != TRANSFORM_HANDLE_NONE)
-    gimp_tool_push_status (tool, tool->display, "%s",
-                           get_friendly_operation_name (ret));
-
-  return ret;
-}
-
-static void
-get_handle_geometry (GimpTransformTool *tr_tool,
-                     GimpVector2       *position,
-                     gdouble           *angle)
-{
-  GimpVector2 o[] = { { .x = tr_tool->tx1, .y = tr_tool->ty1 },
-                      { .x = tr_tool->tx2, .y = tr_tool->ty2 },
-                      { .x = tr_tool->tx3, .y = tr_tool->ty3 },
-                      { .x = tr_tool->tx4, .y = tr_tool->ty4 } };
-  GimpVector2 right = { .x = 1.0, .y = 0.0 };
-  GimpVector2 up    = { .x = 0.0, .y = 1.0 };
-
-  if (position)
-    {
-      position[0] = o[0];
-      position[1] = o[1];
-      position[2] = o[2];
-      position[3] = o[3];
-    }
-
-  angle[0] = calcangle (vectorsubtract (o[1], o[0]), right);
-  angle[1] = calcangle (vectorsubtract (o[3], o[2]), right);
-  angle[2] = calcangle (vectorsubtract (o[3], o[1]), up);
-  angle[3] = calcangle (vectorsubtract (o[2], o[0]), up);
-
-  angle[4] = (angle[0] + angle[3]) / 2.0;
-  angle[5] = (angle[0] + angle[2]) / 2.0;
-  angle[6] = (angle[1] + angle[3]) / 2.0;
-  angle[7] = (angle[1] + angle[2]) / 2.0;
-}
-
-static void
-gimp_unified_transform_tool_cursor_update (GimpTransformTool  *tr_tool,
-                                           GimpCursorType     *cursor,
-                                           GimpCursorModifier *modifier)
-{
-  GimpToolCursorType tool_cursor = GIMP_TOOL_CURSOR_NONE;
-  gdouble            angle[8];
-  gint               i;
-  GimpCursorType     map[8];
-  GimpVector2        pos[4], this, that;
-  gboolean           flip       = FALSE;
-  gboolean           side       = FALSE;
-  gboolean           set_cursor = TRUE;
-
-  map[0] = GIMP_CURSOR_CORNER_TOP_LEFT;
-  map[1] = GIMP_CURSOR_CORNER_TOP;
-  map[2] = GIMP_CURSOR_CORNER_TOP_RIGHT;
-  map[3] = GIMP_CURSOR_CORNER_RIGHT;
-  map[4] = GIMP_CURSOR_CORNER_BOTTOM_RIGHT;
-  map[5] = GIMP_CURSOR_CORNER_BOTTOM;
-  map[6] = GIMP_CURSOR_CORNER_BOTTOM_LEFT;
-  map[7] = GIMP_CURSOR_CORNER_LEFT;
-
-  get_handle_geometry (tr_tool, pos, angle);
-
-  for (i = 0; i < 8; i++)
-    angle[i] = round (angle[i] * 180.0 / G_PI / 45.0);
-
-  switch (tr_tool->function)
-    {
-    case TRANSFORM_HANDLE_NW_P:
-    case TRANSFORM_HANDLE_NW:
-      i = (gint) angle[4] + 0;
-      this = pos[0];
-      that = pos[3];
-      break;
-
-    case TRANSFORM_HANDLE_NE_P:
-    case TRANSFORM_HANDLE_NE:
-      i = (gint) angle[5] + 2;
-      this = pos[1];
-      that = pos[2];
-      break;
-
-    case TRANSFORM_HANDLE_SW_P:
-    case TRANSFORM_HANDLE_SW:
-      i = (gint) angle[6] + 6;
-      this = pos[2];
-      that = pos[1];
-      break;
-
-    case TRANSFORM_HANDLE_SE_P:
-    case TRANSFORM_HANDLE_SE:
-      i = (gint) angle[7] + 4;
-      this = pos[3];
-      that = pos[0];
-      break;
-
-    case TRANSFORM_HANDLE_N:
-    case TRANSFORM_HANDLE_N_S:
-      i = (gint) angle[0] + 1;
-      this = vectoradd (pos[0], pos[1]);
-      that = vectoradd (pos[2], pos[3]);
-      side = TRUE;
-      break;
-
-    case TRANSFORM_HANDLE_S:
-    case TRANSFORM_HANDLE_S_S:
-      i = (gint) angle[1] + 5;
-      this = vectoradd (pos[2], pos[3]);
-      that = vectoradd (pos[0], pos[1]);
-      side = TRUE;
-      break;
-
-    case TRANSFORM_HANDLE_E:
-    case TRANSFORM_HANDLE_E_S:
-      i = (gint) angle[2] + 3;
-      this = vectoradd (pos[1], pos[3]);
-      that = vectoradd (pos[0], pos[2]);
-      side = TRUE;
-      break;
-
-    case TRANSFORM_HANDLE_W:
-    case TRANSFORM_HANDLE_W_S:
-      i = (gint) angle[3] + 7;
-      this = vectoradd (pos[0], pos[2]);
-      that = vectoradd (pos[1], pos[3]);
-      side = TRUE;
-      break;
-
-    default:
-      set_cursor = FALSE;
-      break;
-    }
-
-  if (set_cursor)
-    {
-      i %= 8;
-
-      switch (map[i])
-        {
-        case GIMP_CURSOR_CORNER_TOP_LEFT:
-          if (this.x + this.y > that.x + that.y)
-            flip = TRUE;
-          break;
-        case GIMP_CURSOR_CORNER_TOP:
-          if (this.y > that.y)
-            flip = TRUE;
-          break;
-        case GIMP_CURSOR_CORNER_TOP_RIGHT:
-          if (this.x - this.y < that.x - that.y)
-            flip = TRUE;
-          break;
-        case GIMP_CURSOR_CORNER_RIGHT:
-          if (this.x < that.x)
-            flip = TRUE;
-          break;
-        case GIMP_CURSOR_CORNER_BOTTOM_RIGHT:
-          if (this.x + this.y < that.x + that.y)
-            flip = TRUE;
-          break;
-        case GIMP_CURSOR_CORNER_BOTTOM:
-          if (this.y < that.y)
-            flip = TRUE;
-          break;
-        case GIMP_CURSOR_CORNER_BOTTOM_LEFT:
-          if (this.x - this.y > that.x - that.y)
-            flip = TRUE;
-          break;
-        case GIMP_CURSOR_CORNER_LEFT:
-          if (this.x > that.x)
-            flip = TRUE;
-          break;
-        default:
-          g_assert_not_reached ();
-        }
-
-      if (flip)
-        *cursor = map[(i + 4) % 8];
-      else
-        *cursor = map[i];
-
-      if (side)
-        *cursor += 8;
-    }
-
-  /* parent class handles *cursor and *modifier for most handles */
-  switch (tr_tool->function)
-    {
-    case TRANSFORM_HANDLE_NONE:
-    case TRANSFORM_CREATING:
-      tool_cursor = GIMP_TOOL_CURSOR_NONE;
-      break;
-
-    case TRANSFORM_HANDLE_NW_P:
-    case TRANSFORM_HANDLE_NE_P:
-    case TRANSFORM_HANDLE_SW_P:
-    case TRANSFORM_HANDLE_SE_P:
-      tool_cursor = GIMP_TOOL_CURSOR_PERSPECTIVE;
-      break;
-
-    case TRANSFORM_HANDLE_NW:
-    case TRANSFORM_HANDLE_NE:
-    case TRANSFORM_HANDLE_SW:
-    case TRANSFORM_HANDLE_SE:
-    case TRANSFORM_HANDLE_N:
-    case TRANSFORM_HANDLE_S:
-    case TRANSFORM_HANDLE_E:
-    case TRANSFORM_HANDLE_W:
-      tool_cursor = GIMP_TOOL_CURSOR_RESIZE;
-      break;
-
-    case TRANSFORM_HANDLE_CENTER:
-      tool_cursor = GIMP_TOOL_CURSOR_MOVE;
-      break;
-
-    case TRANSFORM_HANDLE_PIVOT:
-      tool_cursor = GIMP_TOOL_CURSOR_ROTATE;
-      *modifier = GIMP_CURSOR_MODIFIER_MOVE;
-      break;
-
-    case TRANSFORM_HANDLE_N_S:
-    case TRANSFORM_HANDLE_S_S:
-    case TRANSFORM_HANDLE_E_S:
-    case TRANSFORM_HANDLE_W_S:
-      tool_cursor = GIMP_TOOL_CURSOR_SHEAR;
-      break;
-
-    case TRANSFORM_HANDLE_ROTATION:
-      tool_cursor = GIMP_TOOL_CURSOR_ROTATE;
-      break;
-
-    default:
-      g_assert_not_reached ();
-    }
-
-  /* parent class sets cursor and cursor_modifier */
-  gimp_tool_control_set_tool_cursor (GIMP_TOOL (tr_tool)->control, tool_cursor);
-}
-
-static void
-gimp_unified_transform_tool_draw_gui (GimpTransformTool *tr_tool,
-                                      gint               handle_w,
-                                      gint               handle_h)
-{
-  GimpDrawTool    *draw_tool = GIMP_DRAW_TOOL (tr_tool);
-  GimpCanvasGroup *stroke_group;
-  gint             d, i;
-  gdouble          angle[8];
-  GimpVector2      o[4], t[4];
-
-  get_handle_geometry (tr_tool, o, angle);
-
-  for (i = 0; i < 4; i++)
-    {
-      GimpCanvasItem *h;
-
-      /*  draw the scale handles  */
-      h = gimp_draw_tool_add_handle (draw_tool,
-                                     GIMP_HANDLE_SQUARE,
-                                     o[i].x, o[i].y,
-                                     handle_w * 1.5, handle_h * 1.5,
-                                     GIMP_HANDLE_ANCHOR_CENTER);
-      gimp_canvas_handle_set_angles (h, angle[i + 4], 0.0);
-      tr_tool->handles[TRANSFORM_HANDLE_NW + i] = h;
-
-      /*  draw the perspective handles  */
-      h = gimp_draw_tool_add_handle (draw_tool,
-                                     GIMP_HANDLE_DIAMOND,
-                                     o[i].x, o[i].y,
-                                     handle_w * 0.8, handle_h * 0.8,
-                                     GIMP_HANDLE_ANCHOR_CENTER);
-      gimp_canvas_handle_set_angles (h, angle[i + 4], 0.0);
-      tr_tool->handles[TRANSFORM_HANDLE_NW_P + i] = h;
-    }
-
-  /*  draw the side handles  */
-  t[0] = scalemult (vectoradd (o[0], o[1]), 0.5);
-  t[1] = scalemult (vectoradd (o[2], o[3]), 0.5);
-  t[2] = scalemult (vectoradd (o[1], o[3]), 0.5);
-  t[3] = scalemult (vectoradd (o[2], o[0]), 0.5);
-
-  for (i = 0; i < 4; i++)
-    {
-      GimpCanvasItem *h;
-
-      h = gimp_draw_tool_add_handle (draw_tool,
-                                     GIMP_HANDLE_SQUARE,
-                                     t[i].x, t[i].y,
-                                     handle_w, handle_h,
-                                     GIMP_HANDLE_ANCHOR_CENTER);
-      gimp_canvas_handle_set_angles (h, angle[i], 0.0);
-      tr_tool->handles[TRANSFORM_HANDLE_N + i] = h;
-    }
-
-  /*  draw the shear handles  */
-  t[0] = scalemult (vectoradd (           o[0]      , scalemult (o[1], 3.0)),
-                    0.25);
-  t[1] = scalemult (vectoradd (scalemult (o[2], 3.0),            o[3]      ),
-                    0.25);
-  t[2] = scalemult (vectoradd (           o[1]      , scalemult (o[3], 3.0)),
-                    0.25);
-  t[3] = scalemult (vectoradd (scalemult (o[2], 3.0),            o[0]      ),
-                    0.25);
-
-  for (i = 0; i < 4; i++)
-    {
-      GimpCanvasItem *h;
-
-      h = gimp_draw_tool_add_handle (draw_tool,
-                                     GIMP_HANDLE_FILLED_DIAMOND,
-                                     t[i].x, t[i].y,
-                                     handle_w, handle_h,
-                                     GIMP_HANDLE_ANCHOR_CENTER);
-      gimp_canvas_handle_set_angles (h, angle[i], 0.0);
-      tr_tool->handles[TRANSFORM_HANDLE_N_S + i] = h;
-    }
-
-  /*  draw the rotation center axis handle  */
-  d = MIN (handle_w, handle_h);
-
-  stroke_group = gimp_draw_tool_add_stroke_group (draw_tool);
-
-  tr_tool->handles[TRANSFORM_HANDLE_PIVOT] = GIMP_CANVAS_ITEM (stroke_group);
-
-  gimp_draw_tool_push_group (draw_tool, stroke_group);
-
-  gimp_draw_tool_add_handle (draw_tool,
-                             GIMP_HANDLE_CIRCLE,
-                             tr_tool->tpx, tr_tool->tpy,
-                             d, d,
-                             GIMP_HANDLE_ANCHOR_CENTER);
-  gimp_draw_tool_add_handle (draw_tool,
-                             GIMP_HANDLE_CROSS,
-                             tr_tool->tpx, tr_tool->tpy,
-                             d, d,
-                             GIMP_HANDLE_ANCHOR_CENTER);
-
-  gimp_draw_tool_pop_group (draw_tool);
+  tr_tool->progress_text    = _("Unified transform");
+  tr_tool->use_grid         = TRUE;
+  tr_tool->does_perspective = TRUE;
 }
 
 static void
@@ -825,489 +183,56 @@ gimp_unified_transform_tool_prepare (GimpTransformTool *tr_tool)
   tr_tool->trans_info[Y3] = (gdouble) tr_tool->y2;
 }
 
-static void
-gimp_unified_transform_tool_motion (GimpTransformTool *transform_tool)
+static GimpToolWidget *
+gimp_unified_transform_tool_get_widget (GimpTransformTool *tr_tool)
 {
-  GimpTransformOptions *options = GIMP_TRANSFORM_TOOL_GET_OPTIONS (transform_tool);
-  gdouble              *x[4], *y[4];
-  gdouble              *newpivot_x, *newpivot_y;
-
-  GimpVector2           oldpos[5], newpos[4];
-  GimpVector2           cur   = { .x = transform_tool->curx,
-                                  .y = transform_tool->cury };
-  GimpVector2           mouse = { .x = transform_tool->mousex,
-                                  .y = transform_tool->mousey };
-  GimpVector2           d;
-  GimpVector2           pivot;
-
-  gint                  i;
-
-  gboolean              fixedpivot = options->fixedpivot;
-
-  TransformAction       function = transform_tool->function;
-
-  for (i = 0; i < 4; i++)
-    {
-      x[i] = &transform_tool->trans_info[X0 + i * 2];
-      y[i] = &transform_tool->trans_info[Y0 + i * 2];
-      newpos[i].x = oldpos[i].x = transform_tool->prev_trans_info[0][X0 + i * 2];
-      newpos[i].y = oldpos[i].y = transform_tool->prev_trans_info[0][Y0 + i * 2];
-    }
-
-  /* put center point in this array too */
-  oldpos[4].x = (oldpos[0].x + oldpos[1].x + oldpos[2].x + oldpos[3].x) / 4.;
-  oldpos[4].y = (oldpos[0].y + oldpos[1].y + oldpos[2].y + oldpos[3].y) / 4.;
-
-  d = vectorsubtract (cur, mouse);
-
-  newpivot_x = &transform_tool->trans_info[PIVOT_X];
-  newpivot_y = &transform_tool->trans_info[PIVOT_Y];
-
-  pivot.x = transform_tool->prev_trans_info[0][PIVOT_X];
-  pivot.y = transform_tool->prev_trans_info[0][PIVOT_Y];
-
-  /* move */
-  if (function == TRANSFORM_HANDLE_CENTER)
-    {
-      if (options->constrain_move)
-        {
-          /* snap to 45 degree vectors from starting point */
-          gdouble angle = 16.0 * calcangle ((GimpVector2) { 1.0, 0.0 },
-                                            d) / (2.0 * G_PI);
-          gdouble dist  = norm (d) / sqrt (2);
-
-          if (angle < 1. || angle >= 15.)
-            d.y = 0;
-          else if (angle < 3.)
-            d.y = -(d.x = dist);
-          else if (angle < 5.)
-            d.x = 0;
-          else if (angle < 7.)
-            d.x = d.y = -dist;
-          else if (angle < 9.)
-            d.y = 0;
-          else if (angle < 11.)
-            d.x = -(d.y = dist);
-          else if (angle < 13.)
-            d.x = 0;
-          else if (angle < 15.)
-            d.x = d.y = dist;
-        }
-
-      for (i = 0; i < 4; i++)
-        newpos[i] = vectoradd (oldpos[i], d);
-    }
-
-  /* rotate */
-  if (function == TRANSFORM_HANDLE_ROTATION)
-    {
-      gdouble angle = calcangle (vectorsubtract (cur, pivot),
-                                 vectorsubtract (mouse, pivot));
-
-      if (options->constrain_rotate)
-        {
-          /* round to 15 degree multiple */
-          angle /= 2*G_PI/24.;
-          angle = round (angle);
-          angle *= 2*G_PI/24.;
-        }
-
-      for (i = 0; i < 4; i++)
-        newpos[i] = vectoradd (pivot,
-                               rotate2d (vectorsubtract (oldpos[i], pivot),
-                                         angle));
-
-      fixedpivot = TRUE;
-    }
-
-  /* move rotation axis */
-  if (function == TRANSFORM_HANDLE_PIVOT)
-    {
-      pivot = vectoradd (pivot, d);
-
-      if (options->cornersnap)
-        {
-          /* snap to corner points and center */
-          gint    closest = 0;
-          gdouble closest_dist = G_MAXDOUBLE, dist;
-
-          for (i = 0; i < 5; i++)
-            {
-              dist = norm (vectorsubtract (pivot, oldpos[i]));
-              if (dist < closest_dist)
-                {
-                  closest_dist = dist;
-                  closest = i;
-                }
-            }
-
-          if (closest_dist *
-              gimp_display_get_shell (GIMP_TOOL (transform_tool)->display)->scale_x < 50)
-            {
-              pivot = oldpos[closest];
-            }
-        }
-
-      fixedpivot = TRUE;
-    }
-
-  /* scaling via corner */
-  if (function == TRANSFORM_HANDLE_NW ||
-      function == TRANSFORM_HANDLE_NE ||
-      function == TRANSFORM_HANDLE_SE ||
-      function == TRANSFORM_HANDLE_SW)
-    {
-      /* Scaling through scale handles means translating one corner point,
-       * with all sides at constant angles.
-       */
-
-      gint this, left, right, opposite;
-
-      /* 0: northwest, 1: northeast, 2: southwest, 3: southeast */
-      if (function == TRANSFORM_HANDLE_NW)
-        {
-          this = 0; left = 1; right = 2; opposite = 3;
-        }
-      else if (function == TRANSFORM_HANDLE_NE)
-        {
-          this = 1; left = 3; right = 0; opposite = 2;
-        }
-      else if (function == TRANSFORM_HANDLE_SW)
-        {
-          this = 2; left = 0; right = 3; opposite = 1;
-        }
-      else if (function == TRANSFORM_HANDLE_SE)
-        {
-          this = 3; left = 2; right = 1; opposite = 0;
-        }
-      else
-        g_assert_not_reached ();
-
-      /* when the keep aspect transformation constraint is enabled,
-       * the translation shall only be along the diagonal that runs
-       * trough this corner point.
-       */
-      if (options->constrain_scale)
-        {
-          /* restrict to movement along the diagonal */
-          GimpVector2 diag = vectorsubtract (oldpos[this], oldpos[opposite]);
-
-          d = vectorproject (d, diag);
-        }
-
-      /* Move the corner being interacted with */
-      /*    rp---------tp
-       *   /           /\ <- d, the interaction vector
-       *  /           /  tp
-       * op----------/
-       *
-       */
-      newpos[this] = vectoradd (oldpos[this], d);
-
-      /* Where the corner to the right and left would go, need these to form
-       * lines to intersect with the sides */
-      /*    rp----------/
-       *   /\          /\
-       *  /  nr       /  nt
-       * op----------lp
-       *              \
-       *               nl
-       */
-
-      newpos[right] = vectoradd (oldpos[right], d);
-      newpos[left]  = vectoradd (oldpos[left], d);
-
-      /* Now we just need to find the intersection of op-rp and nr-nt.
-       *    rp----------/
-       *   /           /
-       *  /  nr==========nt
-       * op----------/
-       *
-       */
-      newpos[right] = lineintersect (newpos[right], newpos[this],
-                                     oldpos[opposite], oldpos[right]);
-      newpos[left]  = lineintersect (newpos[left], newpos[this],
-                                     oldpos[opposite], oldpos[left]);
-      /*    /-----------/
-       *   /           /
-       *  rp============nt
-       * op----------/
-       *
-       */
-
-      /*
-       *
-       *  /--------------/
-       * /--------------/
-       *
-       */
-
-      if (options->frompivot_scale &&
-          transform_is_convex (newpos) &&
-          transform_is_convex (oldpos))
-        {
-          /* transform the pivot point before the interaction and
-           * after, and move everything by this difference
-           */
-          //TODO the handle doesn't actually end up where the mouse cursor is
-          GimpVector2 delta = get_pivot_delta (transform_tool,
-                                               oldpos, newpos, pivot);
-          for (i = 0; i < 4; i++)
-            newpos[i] = vectorsubtract (newpos[i], delta);
-
-          fixedpivot = TRUE;
-        }
-    }
-
-  /* scaling via sides */
-  if (function == TRANSFORM_HANDLE_N ||
-      function == TRANSFORM_HANDLE_E ||
-      function == TRANSFORM_HANDLE_S ||
-      function == TRANSFORM_HANDLE_W)
-    {
-      gint        this_l, this_r, opp_l, opp_r;
-      GimpVector2 side_l, side_r, midline;
-
-      /* 0: northwest, 1: northeast, 2: southwest, 3: southeast */
-      if (function == TRANSFORM_HANDLE_N)
-        {
-          this_l = 1; this_r = 0;
-        }
-      else if (function == TRANSFORM_HANDLE_E)
-        {
-          this_l = 3; this_r = 1;
-        }
-      else if (function == TRANSFORM_HANDLE_S)
-        {
-          this_l = 2; this_r = 3;
-        }
-      else if (function == TRANSFORM_HANDLE_W)
-        {
-          this_l = 0; this_r = 2;
-        }
-      else
-        g_assert_not_reached ();
-
-      opp_l = 3 - this_r; opp_r = 3 - this_l;
-
-      side_l = vectorsubtract (oldpos[opp_l], oldpos[this_l]);
-      side_r = vectorsubtract (oldpos[opp_r], oldpos[this_r]);
-      midline = vectoradd (side_l, side_r);
-
-      /* restrict to movement along the midline */
-      d = vectorproject (d, midline);
-
-      if (options->constrain_scale)
-        {
-          GimpVector2 before, after, effective_pivot = pivot;
-          gdouble     distance;
-
-          if (! options->frompivot_scale)
-            {
-              /* center of the opposite side is pivot */
-              effective_pivot = scalemult (vectoradd (oldpos[opp_l],
-                                                      oldpos[opp_r]), 0.5);
-            }
-
-          /* get the difference between the distance from the pivot to
-           * where interaction started and the distance from the pivot
-           * to where cursor is now, and scale all corners distance
-           * from the pivot with this factor
-           */
-          before = vectorsubtract (effective_pivot, mouse);
-          after = vectorsubtract (effective_pivot, cur);
-          after = vectorproject (after, before);
-
-          distance = 0.5 * (after.x / before.x + after.y / before.y);
-
-          for (i = 0; i < 4; i++)
-            newpos[i] = vectoradd (effective_pivot,
-                                   scalemult (vectorsubtract (oldpos[i],
-                                                              effective_pivot),
-                                              distance));
-        }
-      else
-        {
-          /* just move the side */
-          newpos[this_l] = vectoradd (oldpos[this_l], d);
-          newpos[this_r] = vectoradd (oldpos[this_r], d);
-        }
-
-      if (! options->constrain_scale   &&
-          options->frompivot_scale     &&
-          transform_is_convex (newpos) &&
-          transform_is_convex (oldpos))
-        {
-          GimpVector2 delta = get_pivot_delta (transform_tool,
-                                               oldpos, newpos, pivot);
-          for (i = 0; i < 4; i++)
-            newpos[i] = vectorsubtract (newpos[i], delta);
-
-          fixedpivot = TRUE;
-        }
-    }
-
-  /* shear */
-  if (function == TRANSFORM_HANDLE_N_S ||
-      function == TRANSFORM_HANDLE_E_S ||
-      function == TRANSFORM_HANDLE_S_S ||
-      function == TRANSFORM_HANDLE_W_S)
-    {
-      gint this_l, this_r;
-
-      /* set up indices for this edge and the opposite edge */
-      if (function == TRANSFORM_HANDLE_N_S)
-        {
-          this_l = 1; this_r = 0;
-        }
-      else if (function == TRANSFORM_HANDLE_W_S)
-        {
-          this_l = 0; this_r = 2;
-        }
-      else if (function == TRANSFORM_HANDLE_S_S)
-        {
-          this_l = 2; this_r = 3;
-        }
-      else if (function == TRANSFORM_HANDLE_E_S)
-        {
-          this_l = 3; this_r = 1;
-        }
-      else
-        g_assert_not_reached ();
-
-      if (options->constrain_shear)
-        {
-          /* restrict to movement along the side */
-          GimpVector2 side = vectorsubtract (oldpos[this_r], oldpos[this_l]);
-
-          d = vectorproject (d, side);
-        }
-
-      newpos[this_l] = vectoradd (oldpos[this_l], d);
-      newpos[this_r] = vectoradd (oldpos[this_r], d);
-
-      if (options->frompivot_shear     &&
-          transform_is_convex (newpos) &&
-          transform_is_convex (oldpos))
-        {
-          GimpVector2 delta = get_pivot_delta (transform_tool,
-                                               oldpos, newpos, pivot);
-          for (i = 0; i < 4; i++)
-            newpos[i] = vectorsubtract (newpos[i], delta);
-
-          fixedpivot = TRUE;
-        }
-    }
-
-  /* perspective transform */
-  if (function == TRANSFORM_HANDLE_NW_P ||
-      function == TRANSFORM_HANDLE_NE_P ||
-      function == TRANSFORM_HANDLE_SE_P ||
-      function == TRANSFORM_HANDLE_SW_P)
-    {
-      gint this, left, right, opposite;
-
-      /* 0: northwest, 1: northeast, 2: southwest, 3: southeast */
-      if (function == TRANSFORM_HANDLE_NW_P)
-        {
-          this = 0; left = 1; right = 2; opposite = 3;
-        }
-      else if (function == TRANSFORM_HANDLE_NE_P)
-        {
-          this = 1; left = 3; right = 0; opposite = 2;
-        }
-      else if (function == TRANSFORM_HANDLE_SW_P)
-        {
-          this = 2; left = 0; right = 3; opposite = 1;
-        }
-      else if (function == TRANSFORM_HANDLE_SE_P)
-        {
-          this = 3; left = 2; right = 1; opposite = 0;
-        }
-      else
-        g_assert_not_reached ();
-
-      if (options->constrain_perspective)
-        {
-          /* when the constrain transformation constraint is enabled,
-           * the translation shall only be either along the side
-           * angles of the two sides that run to this corner point, or
-           * along the diagonal that runs trough this corner point.
-           */
-          GimpVector2 proj[4];
-          gdouble     rej[4];
-
-          for (i = 0; i < 4; i++)
-            {
-              if (i == this)
-                continue;
-
-              /* get the vectors along the sides and the diagonal */
-              proj[i] = vectorsubtract (oldpos[this], oldpos[i]);
-
-              /* project d on each candidate vector and see which has
-               * the shortest rejection
-               */
-              proj[i] = vectorproject (d, proj[i]);
-              rej[i] = norm (vectorsubtract (d, proj[i]));
-            }
-
-          if (rej[left] < rej[right] && rej[left] < rej[opposite])
-            d = proj[left];
-          else if (rej[right] < rej[opposite])
-            d = proj[right];
-          else
-            d = proj[opposite];
-        }
-
-      newpos[this] = vectoradd (oldpos[this], d);
-
-      if (options->frompivot_perspective &&
-          transform_is_convex (newpos)   &&
-          transform_is_convex (oldpos))
-        {
-          GimpVector2 delta = get_pivot_delta (transform_tool,
-                                               oldpos, newpos, pivot);
-
-          for (i = 0; i < 4; i++)
-            newpos[i] = vectorsubtract (newpos[i], delta);
-
-          fixedpivot = TRUE;
-        }
-    }
-
-  for (i = 0; i < 4; i++)
-    {
-      *x[i] = newpos[i].x;
-      *y[i] = newpos[i].y;
-    }
-
-  /* this will have been set to TRUE if an operation used the pivot in
-   * addition to being a user option
-   */
-  if (! fixedpivot                 &&
-      transform_is_convex (newpos) &&
-      transform_is_convex (oldpos) &&
-      point_is_inside_polygon_pos (oldpos, pivot))
-    {
-      GimpVector2 delta = get_pivot_delta (transform_tool,
-                                           oldpos, newpos, pivot);
-      pivot = vectoradd (pivot, delta);
-    }
-
-  /* set unconditionally: if options get toggled during operation, we
-   * have to move pivot back
-   */
-  *newpivot_x = pivot.x;
-  *newpivot_y = pivot.y;
+  GimpTool             *tool    = GIMP_TOOL (tr_tool);
+  GimpTransformOptions *options = GIMP_TRANSFORM_TOOL_GET_OPTIONS (tr_tool);
+  GimpDisplayShell     *shell   = gimp_display_get_shell (tool->display);
+  GimpToolWidget       *widget;
+
+  widget = gimp_tool_transform_grid_new (shell,
+                                         &tr_tool->transform,
+                                         tr_tool->x1,
+                                         tr_tool->y1,
+                                         tr_tool->x2,
+                                         tr_tool->y2,
+                                         options->grid_type,
+                                         options->grid_size);
+
+  g_object_set (widget,
+                "pivot-x",                 (tr_tool->x1 + tr_tool->x2) / 2.0,
+                "pivot-y",                 (tr_tool->y1 + tr_tool->y2) / 2.0,
+                "inside-function",         GIMP_TRANSFORM_FUNCTION_MOVE,
+                "outside-function",        GIMP_TRANSFORM_FUNCTION_ROTATE,
+                "use-corner-handles",      TRUE,
+                "use-perspective-handles", TRUE,
+                "use-side-handles",        TRUE,
+                "use-shear-handles",       TRUE,
+                "use-pivot-handle",        TRUE,
+                "constrain-move",          options->constrain_move,
+                "constrain-scale",         options->constrain_scale,
+                "constrain-rotate",        options->constrain_rotate,
+                "constrain-shear",         options->constrain_shear,
+                "constrain-perspective",   options->constrain_perspective,
+                "frompivot-scale",         options->frompivot_scale,
+                "frompivot-shear",         options->frompivot_shear,
+                "frompivot-perspective",   options->frompivot_perspective,
+                "cornersnap",              options->cornersnap,
+                "fixedpivot",              options->fixedpivot,
+                NULL);
+
+  g_signal_connect (widget, "changed",
+                    G_CALLBACK (gimp_unified_transform_tool_widget_changed),
+                    tr_tool);
+
+  return widget;
 }
 
 static void
-gimp_unified_transform_tool_recalc_matrix (GimpTransformTool *tr_tool)
+gimp_unified_transform_tool_recalc_matrix (GimpTransformTool *tr_tool,
+                                           GimpToolWidget    *widget)
 {
-  tr_tool->px = tr_tool->trans_info[PIVOT_X];
-  tr_tool->py = tr_tool->trans_info[PIVOT_Y];
-
   gimp_matrix3_identity (&tr_tool->transform);
   gimp_transform_matrix_perspective (&tr_tool->transform,
                                      tr_tool->x1,
@@ -1322,6 +247,17 @@ gimp_unified_transform_tool_recalc_matrix (GimpTransformTool *tr_tool)
                                      tr_tool->trans_info[Y2],
                                      tr_tool->trans_info[X3],
                                      tr_tool->trans_info[Y3]);
+
+  if (widget)
+    g_object_set (widget,
+                  "transform", &tr_tool->transform,
+                  "x1",        (gdouble) tr_tool->x1,
+                  "y1",        (gdouble) tr_tool->y1,
+                  "x2",        (gdouble) tr_tool->x2,
+                  "y2",        (gdouble) tr_tool->y2,
+                  "pivot-x",   tr_tool->trans_info[PIVOT_X],
+                  "pivot-y",   tr_tool->trans_info[PIVOT_Y],
+                  NULL);
 }
 
 static gchar *
@@ -1329,3 +265,37 @@ gimp_unified_transform_tool_get_undo_desc (GimpTransformTool *tr_tool)
 {
   return g_strdup (C_("undo-type", "Unified Transform"));
 }
+
+static void
+gimp_unified_transform_tool_widget_changed (GimpToolWidget    *widget,
+                                            GimpTransformTool *tr_tool)
+{
+  GimpMatrix3 *transform;
+
+  g_object_get (widget,
+                "transform", &transform,
+                "pivot-x",   &tr_tool->trans_info[PIVOT_X],
+                "pivot-y",   &tr_tool->trans_info[PIVOT_Y],
+                NULL);
+
+  gimp_matrix3_transform_point (transform,
+                                tr_tool->x1, tr_tool->y1,
+                                &tr_tool->trans_info[X0],
+                                &tr_tool->trans_info[Y0]);
+  gimp_matrix3_transform_point (transform,
+                                tr_tool->x2, tr_tool->y1,
+                                &tr_tool->trans_info[X1],
+                                &tr_tool->trans_info[Y1]);
+  gimp_matrix3_transform_point (transform,
+                                tr_tool->x1, tr_tool->y2,
+                                &tr_tool->trans_info[X2],
+                                &tr_tool->trans_info[Y2]);
+  gimp_matrix3_transform_point (transform,
+                                tr_tool->x2, tr_tool->y2,
+                                &tr_tool->trans_info[X3],
+                                &tr_tool->trans_info[Y3]);
+
+  g_free (transform);
+
+  gimp_transform_tool_recalc_matrix (tr_tool, NULL);
+}



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]