[gimp/gimp-2-10] app: in GimpTransformGridTool, allow simultaneous forward and backward transforms



commit ca0699082826bb5b1ef8e86b0a2074ffca9c2d22
Author: Ell <ell_se yahoo com>
Date:   Mon Feb 4 10:30:18 2019 -0500

    app: in GimpTransformGridTool, allow simultaneous forward and backward transforms
    
    In GimpTransformGridTool, allow performing simultaneous forward
    (normal) and backward (corrective) transforms, by having each
    transform direction operate on an independent set of parameters.
    In other words, whereas the transform-grid tools previously had a
    single transform, which could be applied either normally or
    correctively using the "direction" tool-option, they now have two
    independent transforms, one applied normally and the other
    applied correctively, which are toggled using the "direction"
    option.  The overall transform is the combination of the backward
    transform, followed by the forward transform.
    
    Another way to think about it, is that the tool transforms a source
    shape into a destination shape.  The source shape is defined by the
    backward transform, and the destination shape is defined by the
    forward transform.  Wherewas previously only one of these shapes
    could be controlled (the other shape always being the item bounds),
    it's now possible to control both shapes in a single transform.
    The next commit will allow modifying both shapes simultaneously,
    making this even more useful.
    
    Note that since both transforms start off as the identity, using
    only one of the transform directions has the same behavior as
    before.
    
    (cherry picked from commit de8e81f81f356a704aba345e87c460e542570155)

 app/tools/gimpgenerictransformtool.c  |  52 +++---
 app/tools/gimpgenerictransformtool.h  |   2 +-
 app/tools/gimphandletransformtool.c   |  31 ++--
 app/tools/gimpperspectivetool.c       |  29 ++--
 app/tools/gimprotatetool.c            |  37 ++--
 app/tools/gimpscaletool.c             |  46 ++---
 app/tools/gimpsheartool.c             |  36 ++--
 app/tools/gimptransformgridtool.c     | 315 ++++++++++++++++++++++++----------
 app/tools/gimptransformgridtool.h     |  20 ++-
 app/tools/gimptransformgridtoolundo.c |  24 +--
 app/tools/gimptransformgridtoolundo.h |   2 +-
 app/tools/gimptransformtool.c         |  52 ++++--
 app/tools/gimptransformtool.h         |  21 +--
 app/tools/gimpunifiedtransformtool.c  |  33 ++--
 14 files changed, 434 insertions(+), 266 deletions(-)
---
diff --git a/app/tools/gimpgenerictransformtool.c b/app/tools/gimpgenerictransformtool.c
index 4d7a7c8595..d325c9d461 100644
--- a/app/tools/gimpgenerictransformtool.c
+++ b/app/tools/gimpgenerictransformtool.c
@@ -42,11 +42,11 @@
 
 /*  local function prototypes  */
 
-static void   gimp_generic_transform_tool_recalc_matrix (GimpTransformTool     *tr_tool);
-
-static void   gimp_generic_transform_tool_dialog        (GimpTransformGridTool *tg_tool);
-static void   gimp_generic_transform_tool_dialog_update (GimpTransformGridTool *tg_tool);
-static void   gimp_generic_transform_tool_prepare       (GimpTransformGridTool *tg_tool);
+static gboolean   gimp_generic_transform_tool_info_to_matrix (GimpTransformGridTool *tg_tool,
+                                                              GimpMatrix3           *transform);
+static void       gimp_generic_transform_tool_dialog         (GimpTransformGridTool *tg_tool);
+static void       gimp_generic_transform_tool_dialog_update  (GimpTransformGridTool *tg_tool);
+static void       gimp_generic_transform_tool_prepare        (GimpTransformGridTool *tg_tool);
 
 
 G_DEFINE_TYPE (GimpGenericTransformTool, gimp_generic_transform_tool,
@@ -58,14 +58,12 @@ G_DEFINE_TYPE (GimpGenericTransformTool, gimp_generic_transform_tool,
 static void
 gimp_generic_transform_tool_class_init (GimpGenericTransformToolClass *klass)
 {
-  GimpTransformToolClass     *tr_class = GIMP_TRANSFORM_TOOL_CLASS (klass);
   GimpTransformGridToolClass *tg_class = GIMP_TRANSFORM_GRID_TOOL_CLASS (klass);
 
-  tr_class->recalc_matrix = gimp_generic_transform_tool_recalc_matrix;
-
-  tg_class->dialog        = gimp_generic_transform_tool_dialog;
-  tg_class->dialog_update = gimp_generic_transform_tool_dialog_update;
-  tg_class->prepare       = gimp_generic_transform_tool_prepare;
+  tg_class->info_to_matrix = gimp_generic_transform_tool_info_to_matrix;
+  tg_class->dialog         = gimp_generic_transform_tool_dialog;
+  tg_class->dialog_update  = gimp_generic_transform_tool_dialog_update;
+  tg_class->prepare        = gimp_generic_transform_tool_prepare;
 }
 
 static void
@@ -73,21 +71,20 @@ gimp_generic_transform_tool_init (GimpGenericTransformTool *unified_tool)
 {
 }
 
-static void
-gimp_generic_transform_tool_recalc_matrix (GimpTransformTool *tr_tool)
+static gboolean
+gimp_generic_transform_tool_info_to_matrix (GimpTransformGridTool *tg_tool,
+                                            GimpMatrix3           *transform)
 {
-  GimpGenericTransformTool *generic = GIMP_GENERIC_TRANSFORM_TOOL (tr_tool);
+  GimpGenericTransformTool *generic = GIMP_GENERIC_TRANSFORM_TOOL (tg_tool);
 
-  if (GIMP_GENERIC_TRANSFORM_TOOL_GET_CLASS (generic)->recalc_points)
-    GIMP_GENERIC_TRANSFORM_TOOL_GET_CLASS (generic)->recalc_points (generic);
+  if (GIMP_GENERIC_TRANSFORM_TOOL_GET_CLASS (generic)->info_to_points)
+    GIMP_GENERIC_TRANSFORM_TOOL_GET_CLASS (generic)->info_to_points (generic);
 
-  gimp_matrix3_identity (&tr_tool->transform);
-  tr_tool->transform_valid =
-    gimp_transform_matrix_generic (&tr_tool->transform,
-                                   generic->input_points,
-                                   generic->output_points);
+  gimp_matrix3_identity (transform);
 
-  GIMP_TRANSFORM_TOOL_CLASS (parent_class)->recalc_matrix (tr_tool);
+  return gimp_transform_matrix_generic (transform,
+                                        generic->input_points,
+                                        generic->output_points);
 }
 
 static void
@@ -145,10 +142,14 @@ gimp_generic_transform_tool_dialog (GimpTransformGridTool *tg_tool)
 static void
 gimp_generic_transform_tool_dialog_update (GimpTransformGridTool *tg_tool)
 {
-  GimpTransformTool        *tr_tool = GIMP_TRANSFORM_TOOL (tg_tool);
   GimpGenericTransformTool *generic = GIMP_GENERIC_TRANSFORM_TOOL (tg_tool);
+  GimpMatrix3               transform;
+  gboolean                  transform_valid;
+
+  transform_valid = gimp_transform_grid_tool_info_to_matrix (tg_tool,
+                                                             &transform);
 
-  if (tr_tool->transform_valid)
+  if (transform_valid)
     {
       gint x, y;
 
@@ -161,8 +162,7 @@ gimp_generic_transform_tool_dialog_update (GimpTransformGridTool *tg_tool)
             {
               gchar buf[32];
 
-              g_snprintf (buf, sizeof (buf),
-                          "%10.5f", tr_tool->transform.coeff[y][x]);
+              g_snprintf (buf, sizeof (buf), "%10.5f", transform.coeff[y][x]);
 
               gtk_label_set_text (GTK_LABEL (generic->matrix_labels[y][x]), buf);
             }
diff --git a/app/tools/gimpgenerictransformtool.h b/app/tools/gimpgenerictransformtool.h
index 26e71a65af..8de1fc96be 100644
--- a/app/tools/gimpgenerictransformtool.h
+++ b/app/tools/gimpgenerictransformtool.h
@@ -49,7 +49,7 @@ struct _GimpGenericTransformToolClass
   GimpTransformGridToolClass  parent_class;
 
   /*  virtual functions  */
-  void   (* recalc_points) (GimpGenericTransformTool *generic);
+  void   (* info_to_points) (GimpGenericTransformTool *generic);
 };
 
 
diff --git a/app/tools/gimphandletransformtool.c b/app/tools/gimphandletransformtool.c
index 2d330a8538..bedbe6aefc 100644
--- a/app/tools/gimphandletransformtool.c
+++ b/app/tools/gimphandletransformtool.c
@@ -88,7 +88,7 @@ static GimpToolWidget * gimp_handle_transform_tool_get_widget     (GimpTransform
 static void             gimp_handle_transform_tool_update_widget  (GimpTransformGridTool    *tg_tool);
 static void             gimp_handle_transform_tool_widget_changed (GimpTransformGridTool    *tg_tool);
 
-static void             gimp_handle_transform_tool_recalc_points  (GimpGenericTransformTool *generic);
+static void             gimp_handle_transform_tool_info_to_points (GimpGenericTransformTool *generic);
 
 
 G_DEFINE_TYPE (GimpHandleTransformTool, gimp_handle_transform_tool,
@@ -123,17 +123,17 @@ gimp_handle_transform_tool_class_init (GimpHandleTransformToolClass *klass)
   GimpTransformGridToolClass    *tg_class   = GIMP_TRANSFORM_GRID_TOOL_CLASS (klass);
   GimpGenericTransformToolClass *generic_class = GIMP_GENERIC_TRANSFORM_TOOL_CLASS (klass);
 
-  tool_class->modifier_key     = gimp_handle_transform_tool_modifier_key;
+  tool_class->modifier_key      = gimp_handle_transform_tool_modifier_key;
 
-  tg_class->prepare            = gimp_handle_transform_tool_prepare;
-  tg_class->get_widget         = gimp_handle_transform_tool_get_widget;
-  tg_class->update_widget      = gimp_handle_transform_tool_update_widget;
-  tg_class->widget_changed     = gimp_handle_transform_tool_widget_changed;
+  tg_class->prepare             = gimp_handle_transform_tool_prepare;
+  tg_class->get_widget          = gimp_handle_transform_tool_get_widget;
+  tg_class->update_widget       = gimp_handle_transform_tool_update_widget;
+  tg_class->widget_changed      = gimp_handle_transform_tool_widget_changed;
 
-  generic_class->recalc_points = gimp_handle_transform_tool_recalc_points;
+  generic_class->info_to_points = gimp_handle_transform_tool_info_to_points;
 
-  tr_class->undo_desc          = C_("undo-type", "Handle transform");
-  tr_class->progress_text      = _("Handle transformation");
+  tr_class->undo_desc           = C_("undo-type", "Handle transform");
+  tr_class->progress_text       = _("Handle transformation");
 }
 
 static void
@@ -270,11 +270,16 @@ gimp_handle_transform_tool_get_widget (GimpTransformGridTool *tg_tool)
 static void
 gimp_handle_transform_tool_update_widget (GimpTransformGridTool *tg_tool)
 {
-  GimpTransformTool *tr_tool = GIMP_TRANSFORM_TOOL (tg_tool);
+  GimpMatrix3 transform;
+  gboolean    transform_valid;
+
+  GIMP_TRANSFORM_GRID_TOOL_CLASS (parent_class)->update_widget (tg_tool);
+
+  transform_valid = gimp_transform_grid_tool_info_to_matrix (tg_tool,
+                                                             &transform);
 
   g_object_set (tg_tool->widget,
-                "transform",   &tr_tool->transform,
-                "show-guides", tr_tool->transform_valid,
+                "show-guides", transform_valid,
                 "n-handles",   (gint) tg_tool->trans_info[N_HANDLES],
                 "orig-x1",     tg_tool->trans_info[OX0],
                 "orig-y1",     tg_tool->trans_info[OY0],
@@ -326,7 +331,7 @@ gimp_handle_transform_tool_widget_changed (GimpTransformGridTool *tg_tool)
 }
 
 static void
-gimp_handle_transform_tool_recalc_points (GimpGenericTransformTool *generic)
+gimp_handle_transform_tool_info_to_points (GimpGenericTransformTool *generic)
 {
   GimpTransformGridTool *tg_tool = GIMP_TRANSFORM_GRID_TOOL (generic);
 
diff --git a/app/tools/gimpperspectivetool.c b/app/tools/gimpperspectivetool.c
index 2cdf89be98..0599433618 100644
--- a/app/tools/gimpperspectivetool.c
+++ b/app/tools/gimpperspectivetool.c
@@ -59,7 +59,7 @@ static GimpToolWidget * gimp_perspective_tool_get_widget     (GimpTransformGridT
 static void             gimp_perspective_tool_update_widget  (GimpTransformGridTool    *tg_tool);
 static void             gimp_perspective_tool_widget_changed (GimpTransformGridTool    *tg_tool);
 
-static void             gimp_perspective_tool_recalc_points  (GimpGenericTransformTool *generic);
+static void             gimp_perspective_tool_info_to_points (GimpGenericTransformTool *generic);
 
 
 G_DEFINE_TYPE (GimpPerspectiveTool, gimp_perspective_tool,
@@ -93,15 +93,15 @@ gimp_perspective_tool_class_init (GimpPerspectiveToolClass *klass)
   GimpTransformGridToolClass    *tg_class      = GIMP_TRANSFORM_GRID_TOOL_CLASS (klass);
   GimpGenericTransformToolClass *generic_class = GIMP_GENERIC_TRANSFORM_TOOL_CLASS (klass);
 
-  tg_class->prepare            = gimp_perspective_tool_prepare;
-  tg_class->get_widget         = gimp_perspective_tool_get_widget;
-  tg_class->update_widget      = gimp_perspective_tool_update_widget;
-  tg_class->widget_changed     = gimp_perspective_tool_widget_changed;
+  tg_class->prepare             = gimp_perspective_tool_prepare;
+  tg_class->get_widget          = gimp_perspective_tool_get_widget;
+  tg_class->update_widget       = gimp_perspective_tool_update_widget;
+  tg_class->widget_changed      = gimp_perspective_tool_widget_changed;
 
-  generic_class->recalc_points = gimp_perspective_tool_recalc_points;
+  generic_class->info_to_points = gimp_perspective_tool_info_to_points;
 
-  tr_class->undo_desc          = C_("undo-type", "Perspective");
-  tr_class->progress_text      = _("Perspective transformation");
+  tr_class->undo_desc           = C_("undo-type", "Perspective");
+  tr_class->progress_text       = _("Perspective transformation");
 }
 
 static void
@@ -160,12 +160,13 @@ gimp_perspective_tool_update_widget (GimpTransformGridTool *tg_tool)
 {
   GimpTransformTool *tr_tool = GIMP_TRANSFORM_TOOL (tg_tool);
 
+  GIMP_TRANSFORM_GRID_TOOL_CLASS (parent_class)->update_widget (tg_tool);
+
   g_object_set (tg_tool->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,
+                "x1", (gdouble) tr_tool->x1,
+                "y1", (gdouble) tr_tool->y1,
+                "x2", (gdouble) tr_tool->x2,
+                "y2", (gdouble) tr_tool->y2,
                 NULL);
 }
 
@@ -202,7 +203,7 @@ gimp_perspective_tool_widget_changed (GimpTransformGridTool *tg_tool)
 }
 
 static void
-gimp_perspective_tool_recalc_points (GimpGenericTransformTool *generic)
+gimp_perspective_tool_info_to_points (GimpGenericTransformTool *generic)
 {
   GimpTransformTool     *tr_tool = GIMP_TRANSFORM_TOOL (generic);
   GimpTransformGridTool *tg_tool = GIMP_TRANSFORM_GRID_TOOL (generic);
diff --git a/app/tools/gimprotatetool.c b/app/tools/gimprotatetool.c
index 62b31e1615..4c1f3ba4cb 100644
--- a/app/tools/gimprotatetool.c
+++ b/app/tools/gimprotatetool.c
@@ -61,9 +61,9 @@ static gboolean         gimp_rotate_tool_key_press      (GimpTool              *
                                                          GdkEventKey           *kevent,
                                                          GimpDisplay           *display);
 
-static void             gimp_rotate_tool_recalc_matrix  (GimpTransformTool     *tr_tool);
-static gchar          * gimp_rotate_tool_get_undo_desc  (GimpTransformTool     *tr_tool);
-
+static gboolean         gimp_rotate_tool_info_to_matrix (GimpTransformGridTool *tg_tool,
+                                                         GimpMatrix3           *transform);
+static gchar          * gimp_rotate_tool_get_undo_desc  (GimpTransformGridTool *tg_tool);
 static void             gimp_rotate_tool_dialog         (GimpTransformGridTool *tg_tool);
 static void             gimp_rotate_tool_dialog_update  (GimpTransformGridTool *tg_tool);
 static void             gimp_rotate_tool_prepare        (GimpTransformGridTool *tg_tool);
@@ -108,9 +108,8 @@ gimp_rotate_tool_class_init (GimpRotateToolClass *klass)
 
   tool_class->key_press     = gimp_rotate_tool_key_press;
 
-  tr_class->recalc_matrix   = gimp_rotate_tool_recalc_matrix;
-  tr_class->get_undo_desc   = gimp_rotate_tool_get_undo_desc;
-
+  tg_class->info_to_matrix  = gimp_rotate_tool_info_to_matrix;
+  tg_class->get_undo_desc   = gimp_rotate_tool_get_undo_desc;
   tg_class->dialog          = gimp_rotate_tool_dialog;
   tg_class->dialog_update   = gimp_rotate_tool_dialog_update;
   tg_class->prepare         = gimp_rotate_tool_prepare;
@@ -169,24 +168,23 @@ gimp_rotate_tool_key_press (GimpTool    *tool,
   return GIMP_TOOL_CLASS (parent_class)->key_press (tool, kevent, display);
 }
 
-static void
-gimp_rotate_tool_recalc_matrix (GimpTransformTool *tr_tool)
+static gboolean
+gimp_rotate_tool_info_to_matrix (GimpTransformGridTool *tg_tool,
+                                 GimpMatrix3           *transform)
 {
-  GimpTransformGridTool *tg_tool = GIMP_TRANSFORM_GRID_TOOL (tr_tool);
-
-  gimp_matrix3_identity (&tr_tool->transform);
-  gimp_transform_matrix_rotate_center (&tr_tool->transform,
+  gimp_matrix3_identity (transform);
+  gimp_transform_matrix_rotate_center (transform,
                                        tg_tool->trans_info[PIVOT_X],
                                        tg_tool->trans_info[PIVOT_Y],
                                        tg_tool->trans_info[ANGLE]);
 
-  GIMP_TRANSFORM_TOOL_CLASS (parent_class)->recalc_matrix (tr_tool);
+  return TRUE;
 }
 
 static gchar *
-gimp_rotate_tool_get_undo_desc (GimpTransformTool *tr_tool)
+gimp_rotate_tool_get_undo_desc (GimpTransformGridTool *tg_tool)
 {
-  GimpTransformGridTool *tg_tool = GIMP_TRANSFORM_GRID_TOOL (tr_tool);
+  GimpTransformTool *tr_tool  = GIMP_TRANSFORM_TOOL (tg_tool);
 
   if (tg_tool->trans_info[PIVOT_X] == (tr_tool->x1 + tr_tool->x2) / 2.0 &&
       tg_tool->trans_info[PIVOT_Y] == (tr_tool->y1 + tr_tool->y2) / 2.0)
@@ -361,13 +359,12 @@ gimp_rotate_tool_get_widget (GimpTransformGridTool *tg_tool)
 static void
 gimp_rotate_tool_update_widget (GimpTransformGridTool *tg_tool)
 {
-  GimpTransformTool *tr_tool = GIMP_TRANSFORM_TOOL (tg_tool);
+  GIMP_TRANSFORM_GRID_TOOL_CLASS (parent_class)->update_widget (tg_tool);
 
   g_object_set (tg_tool->widget,
-                "transform", &tr_tool->transform,
-                "angle",     tg_tool->trans_info[ANGLE],
-                "pivot-x",   tg_tool->trans_info[PIVOT_X],
-                "pivot-y",   tg_tool->trans_info[PIVOT_Y],
+                "angle",   tg_tool->trans_info[ANGLE],
+                "pivot-x", tg_tool->trans_info[PIVOT_X],
+                "pivot-y", tg_tool->trans_info[PIVOT_Y],
                 NULL);
 }
 
diff --git a/app/tools/gimpscaletool.c b/app/tools/gimpscaletool.c
index f9a1b31645..987ffb0ab8 100644
--- a/app/tools/gimpscaletool.c
+++ b/app/tools/gimpscaletool.c
@@ -60,9 +60,9 @@ enum
 
 /*  local function prototypes  */
 
-static void             gimp_scale_tool_recalc_matrix  (GimpTransformTool     *tr_tool);
-static gchar          * gimp_scale_tool_get_undo_desc  (GimpTransformTool     *tr_tool);
-
+static gboolean         gimp_scale_tool_info_to_matrix (GimpTransformGridTool *tg_tool,
+                                                        GimpMatrix3           *transform);
+static gchar          * gimp_scale_tool_get_undo_desc  (GimpTransformGridTool *tg_tool);
 static void             gimp_scale_tool_dialog         (GimpTransformGridTool *tg_tool);
 static void             gimp_scale_tool_dialog_update  (GimpTransformGridTool *tg_tool);
 static void             gimp_scale_tool_prepare        (GimpTransformGridTool *tg_tool);
@@ -103,9 +103,8 @@ gimp_scale_tool_class_init (GimpScaleToolClass *klass)
   GimpTransformToolClass     *tr_class = GIMP_TRANSFORM_TOOL_CLASS (klass);
   GimpTransformGridToolClass *tg_class = GIMP_TRANSFORM_GRID_TOOL_CLASS (klass);
 
-  tr_class->recalc_matrix   = gimp_scale_tool_recalc_matrix;
-  tr_class->get_undo_desc   = gimp_scale_tool_get_undo_desc;
-
+  tg_class->info_to_matrix  = gimp_scale_tool_info_to_matrix;
+  tg_class->get_undo_desc   = gimp_scale_tool_get_undo_desc;
   tg_class->dialog          = gimp_scale_tool_dialog;
   tg_class->dialog_update   = gimp_scale_tool_dialog_update;
   tg_class->prepare         = gimp_scale_tool_prepare;
@@ -126,13 +125,14 @@ gimp_scale_tool_init (GimpScaleTool *scale_tool)
   gimp_tool_control_set_tool_cursor (tool->control, GIMP_TOOL_CURSOR_RESIZE);
 }
 
-static void
-gimp_scale_tool_recalc_matrix (GimpTransformTool *tr_tool)
+static gboolean
+gimp_scale_tool_info_to_matrix  (GimpTransformGridTool *tg_tool,
+                                 GimpMatrix3           *transform)
 {
-  GimpTransformGridTool *tg_tool = GIMP_TRANSFORM_GRID_TOOL (tr_tool);
+  GimpTransformTool *tr_tool = GIMP_TRANSFORM_TOOL (tg_tool);
 
-  gimp_matrix3_identity (&tr_tool->transform);
-  gimp_transform_matrix_scale (&tr_tool->transform,
+  gimp_matrix3_identity (transform);
+  gimp_transform_matrix_scale (transform,
                                tr_tool->x1,
                                tr_tool->y1,
                                tr_tool->x2 - tr_tool->x1,
@@ -142,15 +142,14 @@ gimp_scale_tool_recalc_matrix (GimpTransformTool *tr_tool)
                                tg_tool->trans_info[X1] - tg_tool->trans_info[X0],
                                tg_tool->trans_info[Y1] - tg_tool->trans_info[Y0]);
 
-  GIMP_TRANSFORM_TOOL_CLASS (parent_class)->recalc_matrix (tr_tool);
+  return TRUE;
 }
 
 static gchar *
-gimp_scale_tool_get_undo_desc (GimpTransformTool *tr_tool)
+gimp_scale_tool_get_undo_desc (GimpTransformGridTool *tg_tool)
 {
-  GimpTransformGridTool *tg_tool = GIMP_TRANSFORM_GRID_TOOL (tr_tool);
-  gint                   width;
-  gint                   height;
+  gint width;
+  gint height;
 
   width  = ROUND (tg_tool->trans_info[X1] - tg_tool->trans_info[X0]);
   height = ROUND (tg_tool->trans_info[Y1] - tg_tool->trans_info[Y0]);
@@ -262,15 +261,16 @@ gimp_scale_tool_update_widget (GimpTransformGridTool *tg_tool)
 {
   GimpTransformTool *tr_tool = GIMP_TRANSFORM_TOOL (tg_tool);
 
+  GIMP_TRANSFORM_GRID_TOOL_CLASS (parent_class)->update_widget (tg_tool);
+
   g_object_set (
     tg_tool->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",   (tg_tool->trans_info[X0] + tg_tool->trans_info[X1]) / 2.0,
-    "pivot-y",   (tg_tool->trans_info[Y0] + tg_tool->trans_info[Y1]) / 2.0,
+    "x1",      (gdouble) tr_tool->x1,
+    "y1",      (gdouble) tr_tool->y1,
+    "x2",      (gdouble) tr_tool->x2,
+    "y2",      (gdouble) tr_tool->y2,
+    "pivot-x", (tg_tool->trans_info[X0] + tg_tool->trans_info[X1]) / 2.0,
+    "pivot-y", (tg_tool->trans_info[Y0] + tg_tool->trans_info[Y1]) / 2.0,
     NULL);
 }
 
diff --git a/app/tools/gimpsheartool.c b/app/tools/gimpsheartool.c
index 3c7ebaf70f..95e0e6ad6f 100644
--- a/app/tools/gimpsheartool.c
+++ b/app/tools/gimpsheartool.c
@@ -55,9 +55,9 @@ enum
 
 /*  local function prototypes  */
 
-static void             gimp_shear_tool_recalc_matrix  (GimpTransformTool     *tr_tool);
-static gchar          * gimp_shear_tool_get_undo_desc  (GimpTransformTool     *tr_tool);
-
+static gboolean         gimp_shear_tool_info_to_matrix (GimpTransformGridTool *tg_tool,
+                                                        GimpMatrix3           *transform);
+static gchar          * gimp_shear_tool_get_undo_desc  (GimpTransformGridTool *tg_tool);
 static void             gimp_shear_tool_dialog         (GimpTransformGridTool *tg_tool);
 static void             gimp_shear_tool_dialog_update  (GimpTransformGridTool *tg_tool);
 static void             gimp_shear_tool_prepare        (GimpTransformGridTool *tg_tool);
@@ -99,9 +99,8 @@ gimp_shear_tool_class_init (GimpShearToolClass *klass)
   GimpTransformToolClass     *tr_class = GIMP_TRANSFORM_TOOL_CLASS (klass);
   GimpTransformGridToolClass *tg_class = GIMP_TRANSFORM_GRID_TOOL_CLASS (klass);
 
-  tr_class->recalc_matrix   = gimp_shear_tool_recalc_matrix;
-  tr_class->get_undo_desc   = gimp_shear_tool_get_undo_desc;
-
+  tg_class->info_to_matrix  = gimp_shear_tool_info_to_matrix;
+  tg_class->get_undo_desc   = gimp_shear_tool_get_undo_desc;
   tg_class->dialog          = gimp_shear_tool_dialog;
   tg_class->dialog_update   = gimp_shear_tool_dialog_update;
   tg_class->prepare         = gimp_shear_tool_prepare;
@@ -122,11 +121,12 @@ gimp_shear_tool_init (GimpShearTool *shear_tool)
   gimp_tool_control_set_tool_cursor (tool->control, GIMP_TOOL_CURSOR_SHEAR);
 }
 
-static void
-gimp_shear_tool_recalc_matrix (GimpTransformTool *tr_tool)
+static gboolean
+gimp_shear_tool_info_to_matrix (GimpTransformGridTool *tg_tool,
+                                GimpMatrix3           *transform)
 {
-  GimpTransformGridTool *tg_tool = GIMP_TRANSFORM_GRID_TOOL (tr_tool);
-  gdouble                amount;
+  GimpTransformTool *tr_tool = GIMP_TRANSFORM_TOOL (tg_tool);
+  gdouble            amount;
 
   if (tg_tool->trans_info[SHEAR_X] == 0.0 &&
       tg_tool->trans_info[SHEAR_Y] == 0.0)
@@ -139,8 +139,8 @@ gimp_shear_tool_recalc_matrix (GimpTransformTool *tr_tool)
   else
     amount = tg_tool->trans_info[SHEAR_Y];
 
-  gimp_matrix3_identity (&tr_tool->transform);
-  gimp_transform_matrix_shear (&tr_tool->transform,
+  gimp_matrix3_identity (transform);
+  gimp_transform_matrix_shear (transform,
                                tr_tool->x1,
                                tr_tool->y1,
                                tr_tool->x2 - tr_tool->x1,
@@ -148,15 +148,14 @@ gimp_shear_tool_recalc_matrix (GimpTransformTool *tr_tool)
                                tg_tool->trans_info[ORIENTATION],
                                amount);
 
-  GIMP_TRANSFORM_TOOL_CLASS (parent_class)->recalc_matrix (tr_tool);
+  return TRUE;
 }
 
 static gchar *
-gimp_shear_tool_get_undo_desc (GimpTransformTool *tr_tool)
+gimp_shear_tool_get_undo_desc (GimpTransformGridTool *tg_tool)
 {
-  GimpTransformGridTool *tg_tool = GIMP_TRANSFORM_GRID_TOOL (tr_tool);
-  gdouble                x       = tg_tool->trans_info[SHEAR_X];
-  gdouble                y       = tg_tool->trans_info[SHEAR_Y];
+  gdouble x = tg_tool->trans_info[SHEAR_X];
+  gdouble y = tg_tool->trans_info[SHEAR_Y];
 
   switch ((gint) tg_tool->trans_info[ORIENTATION])
     {
@@ -258,8 +257,9 @@ gimp_shear_tool_update_widget (GimpTransformGridTool *tg_tool)
 {
   GimpTransformTool *tr_tool = GIMP_TRANSFORM_TOOL (tg_tool);
 
+  GIMP_TRANSFORM_GRID_TOOL_CLASS (parent_class)->update_widget (tg_tool);
+
   g_object_set (tg_tool->widget,
-                "transform",   &tr_tool->transform,
                 "x1",          (gdouble) tr_tool->x1,
                 "y1",          (gdouble) tr_tool->y1,
                 "x2",          (gdouble) tr_tool->x2,
diff --git a/app/tools/gimptransformgridtool.c b/app/tools/gimptransformgridtool.c
index 8bb4e0656e..92eab7c8ad 100644
--- a/app/tools/gimptransformgridtool.c
+++ b/app/tools/gimptransformgridtool.c
@@ -59,6 +59,13 @@
 #define RESPONSE_RESET 1
 
 
+typedef struct
+{
+  GimpTransformDirection direction;
+  TransInfo              trans_infos[2];
+} UndoInfo;
+
+
 static void      gimp_transform_grid_tool_finalize           (GObject                *object);
 
 static gboolean  gimp_transform_grid_tool_initialize         (GimpTool               *tool,
@@ -108,6 +115,9 @@ static void      gimp_transform_grid_tool_options_notify     (GimpTool
 static void      gimp_transform_grid_tool_draw               (GimpDrawTool           *draw_tool);
 
 static void      gimp_transform_grid_tool_recalc_matrix      (GimpTransformTool      *tr_tool);
+static gchar   * gimp_transform_grid_tool_get_undo_desc      (GimpTransformTool      *tr_tool);
+static GimpTransformDirection gimp_transform_grid_tool_get_direction
+                                                             (GimpTransformTool      *tr_tool);
 static GeglBuffer * gimp_transform_grid_tool_transform       (GimpTransformTool      *tr_tool,
                                                               GimpItem               *item,
                                                               GeglBuffer             *orig_buffer,
@@ -117,6 +127,8 @@ static GeglBuffer * gimp_transform_grid_tool_transform       (GimpTransformTool
                                                               gint                   *new_offset_x,
                                                               gint                   *new_offset_y);
 
+static gchar  * gimp_transform_grid_tool_real_get_undo_desc  (GimpTransformGridTool  *tg_tool);
+static void     gimp_transform_grid_tool_real_update_widget  (GimpTransformGridTool  *tg_tool);
 static void     gimp_transform_grid_tool_real_widget_changed (GimpTransformGridTool  *tg_tool);
 static GeglBuffer * gimp_transform_grid_tool_real_transform  (GimpTransformGridTool  *tg_tool,
                                                               GimpItem               *item,
@@ -153,8 +165,8 @@ static void      gimp_transform_grid_tool_hide_active_item   (GimpTransformGridT
                                                               GimpItem               *item);
 static void      gimp_transform_grid_tool_show_active_item   (GimpTransformGridTool  *tg_tool);
 
-static TransInfo * trans_info_new  (void);
-static void        trans_info_free (TransInfo *info);
+static UndoInfo * undo_info_new  (void);
+static void       undo_info_free (UndoInfo *info);
 
 
 G_DEFINE_TYPE (GimpTransformGridTool, gimp_transform_grid_tool, GIMP_TYPE_TRANSFORM_TOOL)
@@ -188,13 +200,17 @@ gimp_transform_grid_tool_class_init (GimpTransformGridToolClass *klass)
   draw_class->draw           = gimp_transform_grid_tool_draw;
 
   tr_class->recalc_matrix    = gimp_transform_grid_tool_recalc_matrix;
+  tr_class->get_undo_desc    = gimp_transform_grid_tool_get_undo_desc;
+  tr_class->get_direction    = gimp_transform_grid_tool_get_direction;
   tr_class->transform        = gimp_transform_grid_tool_transform;
 
+  klass->info_to_matrix      = NULL;
+  klass->get_undo_desc       = gimp_transform_grid_tool_real_get_undo_desc;
   klass->dialog              = NULL;
   klass->dialog_update       = NULL;
   klass->prepare             = NULL;
   klass->get_widget          = NULL;
-  klass->update_widget       = NULL;
+  klass->update_widget       = gimp_transform_grid_tool_real_update_widget;
   klass->widget_changed      = gimp_transform_grid_tool_real_widget_changed;
   klass->transform           = gimp_transform_grid_tool_real_transform;
 
@@ -246,6 +262,7 @@ gimp_transform_grid_tool_initialize (GimpTool     *tool,
   GimpImage             *image    = gimp_display_get_image (display);
   GimpDrawable          *drawable = gimp_image_get_active_drawable (image);
   GimpItem              *item;
+  UndoInfo              *undo_info;
 
   item = gimp_transform_tool_check_active_item (tr_tool, display, error);
 
@@ -281,15 +298,13 @@ gimp_transform_grid_tool_initialize (GimpTool     *tool,
   gimp_draw_tool_start (GIMP_DRAW_TOOL (tool), display);
 
   /* Initialize undo and redo lists */
-  tg_tool->undo_list = g_list_prepend (NULL, trans_info_new ());
+  undo_info = undo_info_new ();
+  tg_tool->undo_list = g_list_prepend (NULL, undo_info);
   tg_tool->redo_list = NULL;
-  tg_tool->old_trans_info = g_list_last (tg_tool->undo_list)->data;
-  tg_tool->prev_trans_info = g_list_first (tg_tool->undo_list)->data;
-  gimp_transform_grid_tool_update_sensitivity (tg_tool);
 
   /*  Save the current transformation info  */
-  memcpy (tg_tool->prev_trans_info, tg_tool->trans_info,
-          sizeof (TransInfo));
+  memcpy (undo_info->trans_infos, tg_tool->trans_infos,
+          sizeof (tg_tool->trans_infos));
 
   return TRUE;
 }
@@ -375,9 +390,11 @@ gimp_transform_grid_tool_button_release (GimpTool              *tool,
     }
   else
     {
+      UndoInfo *undo_info = tg_tool->undo_list->data;
+
       /*  Restore the last saved state  */
-      memcpy (tg_tool->trans_info, tg_tool->prev_trans_info,
-              sizeof (TransInfo));
+      memcpy (tg_tool->trans_infos, undo_info->trans_infos,
+              sizeof (tg_tool->trans_infos));
 
       /*  recalculate the tool's transformation matrix  */
       gimp_transform_tool_recalc_matrix (tr_tool, display);
@@ -488,23 +505,32 @@ static gboolean
 gimp_transform_grid_tool_undo (GimpTool    *tool,
                                GimpDisplay *display)
 {
-  GimpTransformTool     *tr_tool = GIMP_TRANSFORM_TOOL (tool);
-  GimpTransformGridTool *tg_tool = GIMP_TRANSFORM_GRID_TOOL (tool);
-  GList                 *item;
+  GimpTransformTool      *tr_tool    = GIMP_TRANSFORM_TOOL (tool);
+  GimpTransformGridTool  *tg_tool    = GIMP_TRANSFORM_GRID_TOOL (tool);
+  GimpTransformOptions   *tr_options = GIMP_TRANSFORM_TOOL_GET_OPTIONS (tool);
+  UndoInfo               *undo_info;
+  GimpTransformDirection  direction;
 
-  item = g_list_next (tg_tool->undo_list);
+  undo_info = tg_tool->undo_list->data;
+  direction = undo_info->direction;
 
-  /* Move prev_trans_info from undo_list to redo_list */
-  tg_tool->redo_list = g_list_prepend (tg_tool->redo_list,
-                                       tg_tool->prev_trans_info);
-  tg_tool->undo_list = g_list_remove (tg_tool->undo_list,
-                                      tg_tool->prev_trans_info);
+  /* Move undo_info from undo_list to redo_list */
+  tg_tool->redo_list = g_list_prepend (tg_tool->redo_list, undo_info);
+  tg_tool->undo_list = g_list_remove (tg_tool->undo_list, undo_info);
 
-  tg_tool->prev_trans_info = item->data;
+  undo_info = tg_tool->undo_list->data;
 
   /*  Restore the previous transformation info  */
-  memcpy (tg_tool->trans_info, tg_tool->prev_trans_info,
-          sizeof (TransInfo));
+  memcpy (tg_tool->trans_infos, undo_info->trans_infos,
+          sizeof (tg_tool->trans_infos));
+
+  /*  Restore the previous transformation direction  */
+  if (direction != tr_options->direction)
+    {
+      g_object_set (tr_options,
+                    "direction", direction,
+                    NULL);
+    }
 
   /*  recalculate the tool's transformation matrix  */
   gimp_transform_tool_recalc_matrix (tr_tool, display);
@@ -516,23 +542,30 @@ static gboolean
 gimp_transform_grid_tool_redo (GimpTool    *tool,
                                GimpDisplay *display)
 {
-  GimpTransformTool     *tr_tool = GIMP_TRANSFORM_TOOL (tool);
-  GimpTransformGridTool *tg_tool = GIMP_TRANSFORM_GRID_TOOL (tool);
-  GList                 *item;
-
-  item = tg_tool->redo_list;
+  GimpTransformTool      *tr_tool    = GIMP_TRANSFORM_TOOL (tool);
+  GimpTransformGridTool  *tg_tool    = GIMP_TRANSFORM_GRID_TOOL (tool);
+  GimpTransformOptions   *tr_options = GIMP_TRANSFORM_TOOL_GET_OPTIONS (tool);
+  UndoInfo               *undo_info;
+  GimpTransformDirection  direction;
 
-  /* Move prev_trans_info from redo_list to undo_list */
-  tg_tool->prev_trans_info = item->data;
+  undo_info = tg_tool->redo_list->data;
+  direction = undo_info->direction;
 
-  tg_tool->undo_list = g_list_prepend (tg_tool->undo_list,
-                                       tg_tool->prev_trans_info);
-  tg_tool->redo_list = g_list_remove (tg_tool->redo_list,
-                                      tg_tool->prev_trans_info);
+  /* Move undo_info from redo_list to undo_list */
+  tg_tool->undo_list = g_list_prepend (tg_tool->undo_list, undo_info);
+  tg_tool->redo_list = g_list_remove (tg_tool->redo_list, undo_info);
 
   /*  Restore the previous transformation info  */
-  memcpy (tg_tool->trans_info, tg_tool->prev_trans_info,
-          sizeof (TransInfo));
+  memcpy (tg_tool->trans_infos, undo_info->trans_infos,
+          sizeof (tg_tool->trans_infos));
+
+  /*  Restore the previous transformation direction  */
+  if (direction != tr_options->direction)
+    {
+      g_object_set (tr_options,
+                    "direction", direction,
+                    NULL);
+    }
 
   /*  recalculate the tool's transformation matrix  */
   gimp_transform_tool_recalc_matrix (tr_tool, display);
@@ -720,7 +753,35 @@ gimp_transform_grid_tool_draw (GimpDrawTool *draw_tool)
 static void
 gimp_transform_grid_tool_recalc_matrix (GimpTransformTool *tr_tool)
 {
-  GimpTransformGridTool *tg_tool = GIMP_TRANSFORM_GRID_TOOL (tr_tool);
+  GimpTransformGridTool *tg_tool    = GIMP_TRANSFORM_GRID_TOOL (tr_tool);
+  GimpTransformOptions  *tr_options = GIMP_TRANSFORM_TOOL_GET_OPTIONS (tr_tool);
+
+  if (GIMP_TRANSFORM_GRID_TOOL_GET_CLASS (tg_tool)->info_to_matrix)
+    {
+      GimpMatrix3 forward_transform;
+      GimpMatrix3 backward_transform;
+
+      tr_tool->transform_valid = TRUE;
+
+      tg_tool->trans_info      = tg_tool->trans_infos[GIMP_TRANSFORM_FORWARD];
+      tr_tool->transform_valid = tr_tool->transform_valid &&
+                                 gimp_transform_grid_tool_info_to_matrix (
+                                   tg_tool, &forward_transform);
+
+      tg_tool->trans_info      = tg_tool->trans_infos[GIMP_TRANSFORM_BACKWARD];
+      tr_tool->transform_valid = tr_tool->transform_valid &&
+                                 gimp_transform_grid_tool_info_to_matrix (
+                                   tg_tool, &backward_transform);
+
+      if (tr_tool->transform_valid)
+        {
+          tr_tool->transform = backward_transform;
+          gimp_matrix3_invert (&tr_tool->transform);
+          gimp_matrix3_mult (&forward_transform, &tr_tool->transform);
+        }
+    }
+
+  tg_tool->trans_info = tg_tool->trans_infos[tr_options->direction];
 
   gimp_transform_grid_tool_dialog_update (tg_tool);
   gimp_transform_grid_tool_update_sensitivity (tg_tool);
@@ -731,6 +792,50 @@ gimp_transform_grid_tool_recalc_matrix (GimpTransformTool *tr_tool)
     gimp_tool_gui_show (tg_tool->gui);
 }
 
+static gchar *
+gimp_transform_grid_tool_get_undo_desc (GimpTransformTool *tr_tool)
+{
+  GimpTransformGridTool *tg_tool    = GIMP_TRANSFORM_GRID_TOOL (tr_tool);
+  GimpTransformOptions  *tr_options = GIMP_TRANSFORM_TOOL_GET_OPTIONS (tr_tool);
+  gchar                 *result;
+
+  if (! memcmp (tg_tool->trans_infos[GIMP_TRANSFORM_BACKWARD],
+                tg_tool->init_trans_info, sizeof (TransInfo)))
+    {
+      tg_tool->trans_info = tg_tool->trans_infos[GIMP_TRANSFORM_FORWARD];
+      result = GIMP_TRANSFORM_GRID_TOOL_GET_CLASS (tg_tool)->get_undo_desc (
+        tg_tool);
+    }
+  else if (! memcmp (tg_tool->trans_infos[GIMP_TRANSFORM_FORWARD],
+                     tg_tool->init_trans_info, sizeof (TransInfo)))
+    {
+      gchar *desc;
+
+      tg_tool->trans_info = tg_tool->trans_infos[GIMP_TRANSFORM_BACKWARD];
+      desc = GIMP_TRANSFORM_GRID_TOOL_GET_CLASS (tg_tool)->get_undo_desc (
+        tg_tool);
+
+      result = g_strdup_printf (_("%s (Corrective)"), desc);
+
+      g_free (desc);
+    }
+  else
+    {
+      result = GIMP_TRANSFORM_TOOL_CLASS (parent_class)->get_undo_desc (
+        tr_tool);
+    }
+
+  tg_tool->trans_info = tg_tool->trans_infos[tr_options->direction];
+
+  return result;
+}
+
+static GimpTransformDirection
+gimp_transform_grid_tool_get_direction (GimpTransformTool *tr_tool)
+{
+  return GIMP_TRANSFORM_FORWARD;
+}
+
 static GeglBuffer *
 gimp_transform_grid_tool_transform (GimpTransformTool  *tr_tool,
                                     GimpItem           *item,
@@ -768,6 +873,29 @@ gimp_transform_grid_tool_transform (GimpTransformTool  *tr_tool,
   return new_buffer;
 }
 
+static gchar *
+gimp_transform_grid_tool_real_get_undo_desc (GimpTransformGridTool *tg_tool)
+{
+  GimpTransformTool *tr_tool = GIMP_TRANSFORM_TOOL (tg_tool);
+
+  return GIMP_TRANSFORM_TOOL_CLASS (parent_class)->get_undo_desc (tr_tool);
+}
+
+static void
+gimp_transform_grid_tool_real_update_widget (GimpTransformGridTool *tg_tool)
+{
+  if (GIMP_TRANSFORM_GRID_TOOL_GET_CLASS (tg_tool)->info_to_matrix)
+    {
+      GimpMatrix3 transform;
+
+      gimp_transform_grid_tool_info_to_matrix (tg_tool, &transform);
+
+      g_object_set (tg_tool->widget,
+                    "transform", &transform,
+                    NULL);
+    }
+}
+
 static void
 gimp_transform_grid_tool_real_widget_changed (GimpTransformGridTool *tg_tool)
 {
@@ -853,15 +981,14 @@ gimp_transform_grid_tool_halt (GimpTransformGridTool *tg_tool)
 
   if (tg_tool->redo_list)
     {
-      g_list_free_full (tg_tool->redo_list, (GDestroyNotify) trans_info_free);
+      g_list_free_full (tg_tool->redo_list, (GDestroyNotify) undo_info_free);
       tg_tool->redo_list = NULL;
     }
 
   if (tg_tool->undo_list)
     {
-      g_list_free_full (tg_tool->undo_list, (GDestroyNotify) trans_info_free);
+      g_list_free_full (tg_tool->undo_list, (GDestroyNotify) undo_info_free);
       tg_tool->undo_list = NULL;
-      tg_tool->prev_trans_info = NULL;
     }
 
   gimp_transform_grid_tool_show_active_item (tg_tool);
@@ -955,7 +1082,18 @@ gimp_transform_grid_tool_prepare (GimpTransformGridTool *tg_tool,
     }
 
   if (GIMP_TRANSFORM_GRID_TOOL_GET_CLASS (tg_tool)->prepare)
-    GIMP_TRANSFORM_GRID_TOOL_GET_CLASS (tg_tool)->prepare (tg_tool);
+    {
+      tg_tool->trans_info = tg_tool->init_trans_info;
+      GIMP_TRANSFORM_GRID_TOOL_GET_CLASS (tg_tool)->prepare (tg_tool);
+
+      memcpy (tg_tool->trans_infos[GIMP_TRANSFORM_FORWARD],
+              tg_tool->init_trans_info, sizeof (TransInfo));
+      memcpy (tg_tool->trans_infos[GIMP_TRANSFORM_BACKWARD],
+              tg_tool->init_trans_info, sizeof (TransInfo));
+    }
+
+  gimp_matrix3_identity (&tr_tool->transform);
+  tr_tool->transform_valid = TRUE;
 }
 
 static GimpToolWidget *
@@ -1044,29 +1182,15 @@ gimp_transform_grid_tool_response (GimpToolGui           *gui,
   switch (response_id)
     {
     case RESPONSE_RESET:
-      /* Move all undo events to redo, and pop off the first
-       * one as that's the current one, which always sits on
-       * the undo_list
-       */
-      tg_tool->redo_list =
-        g_list_remove (g_list_concat (g_list_reverse (tg_tool->undo_list),
-                                      tg_tool->redo_list),
-                       tg_tool->old_trans_info);
-      tg_tool->prev_trans_info = tg_tool->old_trans_info;
-      tg_tool->undo_list = g_list_prepend (NULL,
-                                           tg_tool->prev_trans_info);
-
-      gimp_transform_grid_tool_update_sensitivity (tg_tool);
-
-      /*  Restore the previous transformation info  */
-      memcpy (tg_tool->trans_info, tg_tool->prev_trans_info,
+      /*  restore the initial transformation info  */
+      memcpy (tg_tool->trans_info, tg_tool->init_trans_info,
               sizeof (TransInfo));
 
       /*  recalculate the tool's transformtion matrix  */
       gimp_transform_tool_recalc_matrix (tr_tool, display);
 
-      /*  update the undo actions / menu items  */
-      gimp_image_flush (gimp_display_get_image (display));
+      /*  push the restored info to the undo stack  */
+      gimp_transform_grid_tool_push_internal_undo (tg_tool);
       break;
 
     case GTK_RESPONSE_OK:
@@ -1095,23 +1219,18 @@ gimp_transform_grid_tool_update_sensitivity (GimpTransformGridTool *tg_tool)
   gimp_tool_gui_set_response_sensitive (tg_tool->gui, GTK_RESPONSE_OK,
                                         tr_tool->transform_valid);
   gimp_tool_gui_set_response_sensitive (tg_tool->gui, RESPONSE_RESET,
-                                        g_list_next (tg_tool->undo_list) != NULL);
+                                        memcmp (tg_tool->trans_info,
+                                                tg_tool->init_trans_info,
+                                                sizeof (TransInfo)) != 0);
 }
 
 static void
 gimp_transform_grid_tool_update_preview (GimpTransformGridTool *tg_tool)
 {
-  GimpTransformTool        *tr_tool    = GIMP_TRANSFORM_TOOL (tg_tool);
-  GimpTransformGridOptions *options    = GIMP_TRANSFORM_GRID_TOOL_GET_OPTIONS (tg_tool);
-  GimpTransformOptions     *tr_options = GIMP_TRANSFORM_OPTIONS (options);
-  GimpMatrix3               matrix;
+  GimpTransformTool        *tr_tool = GIMP_TRANSFORM_TOOL (tg_tool);
+  GimpTransformGridOptions *options = GIMP_TRANSFORM_GRID_TOOL_GET_OPTIONS (tg_tool);
   gint                      i;
 
-  matrix = tr_tool->transform;
-
-  if (tr_options->direction == GIMP_TRANSFORM_BACKWARD)
-    gimp_matrix3_invert (&matrix);
-
   if (tg_tool->preview)
     {
       gboolean show_preview = gimp_transform_grid_options_show_preview (options) &&
@@ -1120,7 +1239,7 @@ gimp_transform_grid_tool_update_preview (GimpTransformGridTool *tg_tool)
       gimp_canvas_item_begin_change (tg_tool->preview);
       gimp_canvas_item_set_visible (tg_tool->preview, show_preview);
       g_object_set (tg_tool->preview,
-                    "transform", &matrix,
+                    "transform", &tr_tool->transform,
                     NULL);
       gimp_canvas_item_end_change (tg_tool->preview);
     }
@@ -1131,7 +1250,7 @@ gimp_transform_grid_tool_update_preview (GimpTransformGridTool *tg_tool)
       gimp_canvas_item_set_visible (tg_tool->boundary_in,
                                     tr_tool->transform_valid);
       g_object_set (tg_tool->boundary_in,
-                    "transform", &matrix,
+                    "transform", &tr_tool->transform,
                     NULL);
       gimp_canvas_item_end_change (tg_tool->boundary_in);
     }
@@ -1142,7 +1261,7 @@ gimp_transform_grid_tool_update_preview (GimpTransformGridTool *tg_tool)
       gimp_canvas_item_set_visible (tg_tool->boundary_out,
                                     tr_tool->transform_valid);
       g_object_set (tg_tool->boundary_out,
-                    "transform", &matrix,
+                    "transform", &tr_tool->transform,
                     NULL);
       gimp_canvas_item_end_change (tg_tool->boundary_out);
     }
@@ -1154,7 +1273,7 @@ gimp_transform_grid_tool_update_preview (GimpTransformGridTool *tg_tool)
       gimp_canvas_item_begin_change (item);
       gimp_canvas_item_set_visible (item, tr_tool->transform_valid);
       g_object_set (item,
-                    "transform", &matrix,
+                    "transform", &tr_tool->transform,
                     NULL);
       gimp_canvas_item_end_change (item);
     }
@@ -1199,41 +1318,63 @@ gimp_transform_grid_tool_show_active_item (GimpTransformGridTool *tg_tool)
     }
 }
 
-static TransInfo *
-trans_info_new (void)
+static UndoInfo *
+undo_info_new (void)
 {
-  return g_slice_new0 (TransInfo);
+  return g_slice_new0 (UndoInfo);
 }
 
 static void
-trans_info_free (TransInfo *info)
+undo_info_free (UndoInfo *info)
 {
-  g_slice_free (TransInfo, info);
+  g_slice_free (UndoInfo, info);
+}
+
+gboolean
+gimp_transform_grid_tool_info_to_matrix (GimpTransformGridTool *tg_tool,
+                                         GimpMatrix3           *transform)
+{
+  g_return_val_if_fail (GIMP_IS_TRANSFORM_GRID_TOOL (tg_tool), FALSE);
+  g_return_val_if_fail (transform != NULL, FALSE);
+
+  if (GIMP_TRANSFORM_GRID_TOOL_GET_CLASS (tg_tool)->info_to_matrix)
+    {
+      return GIMP_TRANSFORM_GRID_TOOL_GET_CLASS (tg_tool)->info_to_matrix (
+        tg_tool, transform);
+    }
+
+  return FALSE;
 }
 
 void
 gimp_transform_grid_tool_push_internal_undo (GimpTransformGridTool *tg_tool)
 {
+  UndoInfo *undo_info;
+
   g_return_if_fail (GIMP_IS_TRANSFORM_GRID_TOOL (tg_tool));
-  g_return_if_fail (tg_tool->prev_trans_info != NULL);
+  g_return_if_fail (tg_tool->undo_list != NULL);
+
+  undo_info = tg_tool->undo_list->data;
 
   /* push current state on the undo list and set this state as the
    * current state, but avoid doing this if there were no changes
    */
-  if (memcmp (tg_tool->prev_trans_info, tg_tool->trans_info,
-              sizeof (TransInfo)) != 0)
+  if (memcmp (undo_info->trans_infos, tg_tool->trans_infos,
+              sizeof (tg_tool->trans_infos)) != 0)
     {
-      tg_tool->prev_trans_info = trans_info_new ();
-      memcpy (tg_tool->prev_trans_info, tg_tool->trans_info,
-              sizeof (TransInfo));
+      GimpTransformOptions *tr_options = GIMP_TRANSFORM_TOOL_GET_OPTIONS (tg_tool);
+
+      undo_info            = undo_info_new ();
+      undo_info->direction = tr_options->direction;
+      memcpy (undo_info->trans_infos, tg_tool->trans_infos,
+              sizeof (tg_tool->trans_infos));
 
-      tg_tool->undo_list = g_list_prepend (tg_tool->undo_list,
-                                           tg_tool->prev_trans_info);
+      tg_tool->undo_list = g_list_prepend (tg_tool->undo_list, undo_info);
 
       /* If we undid anything and started interacting, we have to
        * discard the redo history
        */
-      g_list_free_full (tg_tool->redo_list, (GDestroyNotify) trans_info_free);
+      g_list_free_full (tg_tool->redo_list, (GDestroyNotify) undo_info_free);
       tg_tool->redo_list = NULL;
 
       gimp_transform_grid_tool_update_sensitivity (tg_tool);
diff --git a/app/tools/gimptransformgridtool.h b/app/tools/gimptransformgridtool.h
index f946ddb9c6..401baaf456 100644
--- a/app/tools/gimptransformgridtool.h
+++ b/app/tools/gimptransformgridtool.h
@@ -47,17 +47,17 @@ struct _GimpTransformGridTool
 {
   GimpTransformTool  parent_instance;
 
-  TransInfo          trans_info;       /*  transformation info                */
-  TransInfo         *old_trans_info;   /*  for resetting everything           */
-  TransInfo         *prev_trans_info;  /*  the current finished state         */
+  TransInfo          init_trans_info;  /*  initial transformation info           */
+  TransInfo          trans_infos[2];   /*  forward/backward transformation info  */
+  gdouble           *trans_info;       /*  current transformation info           */
   GList             *undo_list;        /*  list of all states,
                                            head is current == prev_trans_info,
-                                           tail is original == old_trans_info */
+                                           tail is original == old_trans_info    */
   GList             *redo_list;        /*  list of all undone states,
                                            NULL when nothing undone */
 
   GimpItem          *hidden_item;      /*  the item that was hidden during
-                                           the transform                      */
+                                           the transform                         */
 
   GimpToolWidget    *widget;
   GimpToolWidget    *grab_widget;
@@ -74,6 +74,9 @@ struct _GimpTransformGridToolClass
   GimpTransformToolClass  parent_class;
 
   /*  virtual functions  */
+  gboolean         (* info_to_matrix) (GimpTransformGridTool  *tg_tool,
+                                       GimpMatrix3            *transform);
+  gchar          * (* get_undo_desc)  (GimpTransformGridTool  *tg_tool);
   void             (* dialog)         (GimpTransformGridTool  *tg_tool);
   void             (* dialog_update)  (GimpTransformGridTool  *tg_tool);
   void             (* prepare)        (GimpTransformGridTool  *tg_tool);
@@ -93,9 +96,12 @@ struct _GimpTransformGridToolClass
 };
 
 
-GType   gimp_transform_grid_tool_get_type           (void) G_GNUC_CONST;
+GType      gimp_transform_grid_tool_get_type           (void) G_GNUC_CONST;
 
-void    gimp_transform_grid_tool_push_internal_undo (GimpTransformGridTool *tg_tool);
+gboolean   gimp_transform_grid_tool_info_to_matrix     (GimpTransformGridTool *tg_tool,
+                                                        GimpMatrix3           *transform);
+
+void       gimp_transform_grid_tool_push_internal_undo (GimpTransformGridTool *tg_tool);
 
 
 #endif  /*  __GIMP_TRANSFORM_GRID_TOOL_H__  */
diff --git a/app/tools/gimptransformgridtoolundo.c b/app/tools/gimptransformgridtoolundo.c
index b60aecd9cb..035d9e51ed 100644
--- a/app/tools/gimptransformgridtoolundo.c
+++ b/app/tools/gimptransformgridtoolundo.c
@@ -87,7 +87,6 @@ gimp_transform_grid_tool_undo_constructed (GObject *object)
 {
   GimpTransformGridToolUndo *tg_tool_undo = GIMP_TRANSFORM_GRID_TOOL_UNDO (object);
   GimpTransformGridTool     *tg_tool;
-  gint                       i;
 
   G_OBJECT_CLASS (parent_class)->constructed (object);
 
@@ -95,8 +94,10 @@ gimp_transform_grid_tool_undo_constructed (GObject *object)
 
   tg_tool = tg_tool_undo->tg_tool;
 
-  for (i = 0; i < TRANS_INFO_SIZE; i++)
-    tg_tool_undo->trans_info[i] = (*tg_tool->old_trans_info)[i];
+  memcpy (tg_tool_undo->trans_infos[GIMP_TRANSFORM_FORWARD],
+          tg_tool->init_trans_info, sizeof (TransInfo));
+  memcpy (tg_tool_undo->trans_infos[GIMP_TRANSFORM_BACKWARD],
+          tg_tool->init_trans_info, sizeof (TransInfo));
 
 #if 0
   if (tg_tool->original)
@@ -162,18 +163,17 @@ gimp_transform_grid_tool_undo_pop (GimpUndo            *undo,
 #if 0
       TileManager           *temp;
 #endif
-      gdouble                d;
-      gint                   i;
+      TransInfo              temp_trans_infos[2];
 
       tg_tool = tg_tool_undo->tg_tool;
 
-      /*  swap the transformation information arrays  */
-      for (i = 0; i < TRANS_INFO_SIZE; i++)
-        {
-          d = tg_tool_undo->trans_info[i];
-          tg_tool_undo->trans_info[i] = tg_tool->trans_info[i];
-          tg_tool->trans_info[i] = d;
-        }
+      /*  swap the transformation information00 arrays  */
+      memcpy (temp_trans_infos, tg_tool_undo->trans_infos,
+              sizeof (tg_tool->trans_infos));
+      memcpy (tg_tool_undo->trans_infos, tg_tool->trans_infos,
+              sizeof (tg_tool->trans_infos));
+      memcpy (tg_tool->trans_infos, temp_trans_infos,
+              sizeof (tg_tool->trans_infos));
 
 #if 0
       /*  swap the original buffer--the source buffer for repeated transform_grids
diff --git a/app/tools/gimptransformgridtoolundo.h b/app/tools/gimptransformgridtoolundo.h
index 8252de4a41..3fc7a24b4b 100644
--- a/app/tools/gimptransformgridtoolundo.h
+++ b/app/tools/gimptransformgridtoolundo.h
@@ -38,7 +38,7 @@ struct _GimpTransformGridToolUndo
   GimpUndo               parent_instance;
 
   GimpTransformGridTool *tg_tool;
-  TransInfo              trans_info;
+  TransInfo              trans_infos[2];
 #if 0                   
   TileManager           *original;
 #endif
diff --git a/app/tools/gimptransformtool.c b/app/tools/gimptransformtool.c
index a77c7e0061..f1eb1976b6 100644
--- a/app/tools/gimptransformtool.c
+++ b/app/tools/gimptransformtool.c
@@ -61,15 +61,16 @@
 
 /*  local function prototypes  */
 
-static gchar      * gimp_transform_tool_real_get_undo_desc (GimpTransformTool  *tr_tool);
-static GeglBuffer * gimp_transform_tool_real_transform     (GimpTransformTool  *tr_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);
+static gchar                  * gimp_transform_tool_real_get_undo_desc (GimpTransformTool  *tr_tool);
+static GimpTransformDirection   gimp_transform_tool_real_get_direction (GimpTransformTool  *tr_tool);
+static GeglBuffer             * gimp_transform_tool_real_transform     (GimpTransformTool  *tr_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);
 
 static gboolean     gimp_transform_tool_confirm        (GimpTransformTool  *tr_tool,
                                                         GimpDisplay        *display);
@@ -88,6 +89,7 @@ gimp_transform_tool_class_init (GimpTransformToolClass *klass)
 {
   klass->recalc_matrix = NULL;
   klass->get_undo_desc = gimp_transform_tool_real_get_undo_desc;
+  klass->get_direction = gimp_transform_tool_real_get_direction;
   klass->transform     = gimp_transform_tool_real_transform;
 
   klass->undo_desc     = _("Transform");
@@ -107,6 +109,14 @@ gimp_transform_tool_real_get_undo_desc (GimpTransformTool *tr_tool)
   return g_strdup (GIMP_TRANSFORM_TOOL_GET_CLASS (tr_tool)->undo_desc);
 }
 
+static GimpTransformDirection
+gimp_transform_tool_real_get_direction (GimpTransformTool *tr_tool)
+{
+  GimpTransformOptions *options = GIMP_TRANSFORM_TOOL_GET_OPTIONS (tr_tool);
+
+  return options->direction;
+}
+
 static GeglBuffer *
 gimp_transform_tool_real_transform (GimpTransformTool *tr_tool,
                                     GimpItem          *active_item,
@@ -123,8 +133,11 @@ gimp_transform_tool_real_transform (GimpTransformTool *tr_tool,
   GimpContext            *context = GIMP_CONTEXT (options);
   GeglBuffer             *ret     = NULL;
   GimpTransformResize     clip    = options->clip;
+  GimpTransformDirection  direction;
   GimpProgress           *progress;
 
+  direction = GIMP_TRANSFORM_TOOL_GET_CLASS (tr_tool)->get_direction (tr_tool);
+
   progress = gimp_progress_start (GIMP_PROGRESS (tool), FALSE,
                                   "%s", klass->progress_text);
 
@@ -147,7 +160,7 @@ gimp_transform_tool_real_transform (GimpTransformTool *tr_tool,
                                                    orig_offset_x,
                                                    orig_offset_y,
                                                    &tr_tool->transform,
-                                                   options->direction,
+                                                   direction,
                                                    options->interpolation,
                                                    clip,
                                                    buffer_profile,
@@ -163,7 +176,7 @@ gimp_transform_tool_real_transform (GimpTransformTool *tr_tool,
         {
           gimp_item_linked_transform (active_item, context,
                                       &tr_tool->transform,
-                                      options->direction,
+                                      direction,
                                       options->interpolation,
                                       clip,
                                       progress);
@@ -177,7 +190,7 @@ gimp_transform_tool_real_transform (GimpTransformTool *tr_tool,
 
           gimp_item_transform (active_item, context,
                                &tr_tool->transform,
-                               options->direction,
+                               direction,
                                options->interpolation,
                                clip,
                                progress);
@@ -204,15 +217,18 @@ gimp_transform_tool_confirm (GimpTransformTool *tr_tool,
 
   if (GIMP_TRANSFORM_TOOL_GET_CLASS (tr_tool)->recalc_matrix)
     {
-      GimpMatrix3    transform;
-      GeglRectangle  selection_bounds;
-      gboolean       selection_empty = TRUE;
-      GList         *items;
-      GList         *iter;
+      GimpMatrix3             transform;
+      GimpTransformDirection  direction;
+      GeglRectangle           selection_bounds;
+      gboolean                selection_empty = TRUE;
+      GList                  *items;
+      GList                  *iter;
 
       transform = tr_tool->transform;
+      direction = GIMP_TRANSFORM_TOOL_GET_CLASS (tr_tool)->get_direction (
+        tr_tool);
 
-      if (options->direction == GIMP_TRANSFORM_BACKWARD)
+      if (direction == GIMP_TRANSFORM_BACKWARD)
         gimp_matrix3_invert (&transform);
 
       if (options->type == GIMP_TRANSFORM_TYPE_LAYER &&
diff --git a/app/tools/gimptransformtool.h b/app/tools/gimptransformtool.h
index 2c9e0624b2..2212f7ae53 100644
--- a/app/tools/gimptransformtool.h
+++ b/app/tools/gimptransformtool.h
@@ -61,16 +61,17 @@ struct _GimpTransformToolClass
   GimpDrawToolClass  parent_class;
 
   /*  virtual functions  */
-  void         (* recalc_matrix) (GimpTransformTool  *tr_tool);
-  gchar      * (* get_undo_desc) (GimpTransformTool  *tr_tool);
-  GeglBuffer * (* transform)     (GimpTransformTool  *tr_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                     (* recalc_matrix) (GimpTransformTool  *tr_tool);
+  gchar                  * (* get_undo_desc) (GimpTransformTool  *tr_tool);
+  GimpTransformDirection   (* get_direction) (GimpTransformTool  *tr_tool);
+  GeglBuffer             * (* transform)     (GimpTransformTool  *tr_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 *undo_desc;
   const gchar *progress_text;
diff --git a/app/tools/gimpunifiedtransformtool.c b/app/tools/gimpunifiedtransformtool.c
index 8e91298ca6..0c8ded9fc1 100644
--- a/app/tools/gimpunifiedtransformtool.c
+++ b/app/tools/gimpunifiedtransformtool.c
@@ -61,7 +61,7 @@ static GimpToolWidget * gimp_unified_transform_tool_get_widget     (GimpTransfor
 static void             gimp_unified_transform_tool_update_widget  (GimpTransformGridTool    *tg_tool);
 static void             gimp_unified_transform_tool_widget_changed (GimpTransformGridTool    *tg_tool);
 
-static void             gimp_unified_transform_tool_recalc_points  (GimpGenericTransformTool *generic);
+static void             gimp_unified_transform_tool_info_to_points (GimpGenericTransformTool *generic);
 
 
 G_DEFINE_TYPE (GimpUnifiedTransformTool, gimp_unified_transform_tool,
@@ -95,15 +95,15 @@ gimp_unified_transform_tool_class_init (GimpUnifiedTransformToolClass *klass)
   GimpTransformGridToolClass    *tg_class      = GIMP_TRANSFORM_GRID_TOOL_CLASS (klass);
   GimpGenericTransformToolClass *generic_class = GIMP_GENERIC_TRANSFORM_TOOL_CLASS (klass);
 
-  tg_class->prepare            = gimp_unified_transform_tool_prepare;
-  tg_class->get_widget         = gimp_unified_transform_tool_get_widget;
-  tg_class->update_widget      = gimp_unified_transform_tool_update_widget;
-  tg_class->widget_changed     = gimp_unified_transform_tool_widget_changed;
+  tg_class->prepare             = gimp_unified_transform_tool_prepare;
+  tg_class->get_widget          = gimp_unified_transform_tool_get_widget;
+  tg_class->update_widget       = gimp_unified_transform_tool_update_widget;
+  tg_class->widget_changed      = gimp_unified_transform_tool_widget_changed;
 
-  generic_class->recalc_points = gimp_unified_transform_tool_recalc_points;
+  generic_class->info_to_points = gimp_unified_transform_tool_info_to_points;
 
-  tr_class->undo_desc          = C_("undo-type", "Unified Transform");
-  tr_class->progress_text      = _("Unified transform");
+  tr_class->undo_desc           = C_("undo-type", "Unified Transform");
+  tr_class->progress_text       = _("Unified transform");
 }
 
 static void
@@ -166,14 +166,15 @@ gimp_unified_transform_tool_update_widget (GimpTransformGridTool *tg_tool)
 {
   GimpTransformTool *tr_tool = GIMP_TRANSFORM_TOOL (tg_tool);
 
+  GIMP_TRANSFORM_GRID_TOOL_CLASS (parent_class)->update_widget (tg_tool);
+
   g_object_set (tg_tool->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",   tg_tool->trans_info[PIVOT_X],
-                "pivot-y",   tg_tool->trans_info[PIVOT_Y],
+                "x1",      (gdouble) tr_tool->x1,
+                "y1",      (gdouble) tr_tool->y1,
+                "x2",      (gdouble) tr_tool->x2,
+                "y2",      (gdouble) tr_tool->y2,
+                "pivot-x", tg_tool->trans_info[PIVOT_X],
+                "pivot-y", tg_tool->trans_info[PIVOT_Y],
                 NULL);
 }
 
@@ -212,7 +213,7 @@ gimp_unified_transform_tool_widget_changed (GimpTransformGridTool *tg_tool)
 }
 
 static void
-gimp_unified_transform_tool_recalc_points (GimpGenericTransformTool *generic)
+gimp_unified_transform_tool_info_to_points (GimpGenericTransformTool *generic)
 {
   GimpTransformTool     *tr_tool = GIMP_TRANSFORM_TOOL (generic);
   GimpTransformGridTool *tg_tool = GIMP_TRANSFORM_GRID_TOOL (generic);


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