[gimp/soc-2012-unified-transformation: 5/25] transformtool: add old "new" unified transformation tool



commit ccc940e06de45e79792385573a763174b43f5652
Author: Mikael Magnusson <mikachu src gnome org>
Date:   Sat Aug 6 00:00:35 2011 +0200

    transformtool: add old "new" unified transformation tool
    
    This is the proof of concept code I wrote before gsoc, with very naive
    behaviour and simple interface.

 app/dialogs/dialogs.c                              |    1 +
 app/tools/Makefile.am                              |    2 +
 app/tools/gimp-tools.c                             |    2 +
 app/tools/gimptransformoptions.c                   |   34 ++
 app/tools/gimptransformoptions.h                   |    1 +
 app/tools/gimptransformtool.c                      |   19 +-
 app/tools/gimptransformtool.h                      |    8 +-
 app/tools/gimpunifiedtransformationtool.c          |  440 ++++++++++++++++++++
 app/tools/gimpunifiedtransformationtool.h          |   55 +++
 app/widgets/gimphelp-ids.h                         |    1 +
 app/widgets/widgets-enums.h                        |    1 +
 libgimpwidgets/gimpstock.c                         |    3 +
 libgimpwidgets/gimpstock.h                         |    1 +
 themes/Default/images/Makefile.am                  |    2 +
 .../tools/stock-tool-unified-transformation-16.png |  Bin 0 -> 586 bytes
 .../tools/stock-tool-unified-transformation-22.png |  Bin 0 -> 914 bytes
 .../tools/stock-tool-unified-transformation-22.xcf |  Bin 0 -> 3778 bytes
 17 files changed, 562 insertions(+), 8 deletions(-)
---
diff --git a/app/dialogs/dialogs.c b/app/dialogs/dialogs.c
index b121708..9a74d7d 100644
--- a/app/dialogs/dialogs.c
+++ b/app/dialogs/dialogs.c
@@ -240,6 +240,7 @@ static const GimpDialogFactoryEntry entries[] =
   FOREIGN ("gimp-text-tool-dialog",                TRUE,  TRUE),
   FOREIGN ("gimp-threshold-tool-dialog",           TRUE,  FALSE),
   FOREIGN ("gimp-perspective-tool-dialog",         TRUE,  FALSE),
+  FOREIGN ("gimp-unified-transformation-tool-dialog", TRUE, FALSE),
 
   FOREIGN ("gimp-toolbox-color-dialog",            TRUE,  FALSE),
   FOREIGN ("gimp-gradient-editor-color-dialog",    TRUE,  FALSE),
diff --git a/app/tools/Makefile.am b/app/tools/Makefile.am
index ba4ba83..1e80cca 100644
--- a/app/tools/Makefile.am
+++ b/app/tools/Makefile.am
@@ -194,6 +194,8 @@ libapptools_a_sources = \
 	gimptransformtool.h		\
 	gimptransformtoolundo.c		\
 	gimptransformtoolundo.h		\
+	gimpunifiedtransformationtool.c		\
+	gimpunifiedtransformationtool.h		\
 	gimpvectoroptions.c		\
 	gimpvectoroptions.h		\
 	gimpvectortool.c		\
diff --git a/app/tools/gimp-tools.c b/app/tools/gimp-tools.c
index ca01aed..60342e9 100644
--- a/app/tools/gimp-tools.c
+++ b/app/tools/gimp-tools.c
@@ -82,6 +82,7 @@
 #include "gimpsheartool.h"
 #include "gimpsmudgetool.h"
 #include "gimptexttool.h"
+#include "gimpunifiedtransformationtool.h"
 #include "gimpvectortool.h"
 
 #include "gimp-intl.h"
@@ -156,6 +157,7 @@ gimp_tools_init (Gimp *gimp)
     gimp_shear_tool_register,
     gimp_scale_tool_register,
     gimp_rotate_tool_register,
+    gimp_unified_transformation_tool_register,
     gimp_crop_tool_register,
     gimp_align_tool_register,
     gimp_move_tool_register,
diff --git a/app/tools/gimptransformoptions.c b/app/tools/gimptransformoptions.c
index 6e47e93..5dc9422 100644
--- a/app/tools/gimptransformoptions.c
+++ b/app/tools/gimptransformoptions.c
@@ -35,6 +35,7 @@
 
 #include "gimprotatetool.h"
 #include "gimpscaletool.h"
+#include "gimpunifiedtransformationtool.h"
 #include "gimptooloptions-gui.h"
 #include "gimptransformoptions.h"
 
@@ -53,6 +54,7 @@ enum
   PROP_GRID_TYPE,
   PROP_GRID_SIZE,
   PROP_CONSTRAIN,
+  PROP_ALTERNATE,
 };
 
 
@@ -139,6 +141,11 @@ gimp_transform_options_class_init (GimpTransformOptionsClass *klass)
                                     NULL,
                                     FALSE,
                                     GIMP_PARAM_STATIC_STRINGS);
+  GIMP_CONFIG_INSTALL_PROP_BOOLEAN (object_class, PROP_ALTERNATE,
+                                    "alternate",
+                                    N_("Use alternate set of controls"),
+                                    TRUE,
+                                    GIMP_PARAM_STATIC_STRINGS);
 }
 
 static void
@@ -184,6 +191,9 @@ gimp_transform_options_set_property (GObject      *object,
     case PROP_CONSTRAIN:
       options->constrain = g_value_get_boolean (value);
       break;
+    case PROP_ALTERNATE:
+      options->alternate = g_value_get_boolean (value);
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
       break;
@@ -227,6 +237,9 @@ gimp_transform_options_get_property (GObject    *object,
     case PROP_CONSTRAIN:
       g_value_set_boolean (value, options->constrain);
       break;
+    case PROP_ALTERNATE:
+      g_value_set_boolean (value, options->alternate);
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
       break;
@@ -270,6 +283,7 @@ gimp_transform_options_gui (GimpToolOptions *tool_options)
   GtkWidget   *grid_box;
   const gchar *constrain_label = NULL;
   const gchar *constrain_tip   = NULL;
+  const gchar *alternate = NULL;
 
   hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 2);
   gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
@@ -352,6 +366,26 @@ gimp_transform_options_gui (GimpToolOptions *tool_options)
       constrain_label = _("Keep aspect  (%s)");
       constrain_tip   = _("Keep the original aspect ratio");
     }
+  else if (tool_options->tool_info->tool_type == GIMP_TYPE_UNIFIED_TRANSFORMATION_TOOL)
+    {
+      alternate = (_("Move points  (%s)"));
+      constrain_label = constrain_tip = (_("Keep aspect when scaling  (%s)"));
+    }
+
+  if (alternate)
+    {
+      GtkWidget *button;
+      gchar     *label;
+
+      label = g_strdup_printf (alternate,
+                               gimp_get_mod_string (GDK_MOD1_MASK));
+
+      button = gimp_prop_check_button_new (config, "alternate", label);
+      gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
+      gtk_widget_show (button);
+
+      g_free (label);
+    }
 
   if (constrain_label)
     {
diff --git a/app/tools/gimptransformoptions.h b/app/tools/gimptransformoptions.h
index 18196b8..e9d2698 100644
--- a/app/tools/gimptransformoptions.h
+++ b/app/tools/gimptransformoptions.h
@@ -47,6 +47,7 @@ struct _GimpTransformOptions
   GimpGuidesType            grid_type;
   gint                      grid_size;
   gboolean                  constrain;
+  gboolean                  alternate;
 };
 
 
diff --git a/app/tools/gimptransformtool.c b/app/tools/gimptransformtool.c
index 06a2007..4068e38 100644
--- a/app/tools/gimptransformtool.c
+++ b/app/tools/gimptransformtool.c
@@ -59,6 +59,7 @@
 
 #include "gimptoolcontrol.h"
 #include "gimpperspectivetool.h"
+#include "gimpunifiedtransformationtool.h"
 #include "gimptransformoptions.h"
 #include "gimptransformtool.h"
 #include "gimptransformtoolundo.h"
@@ -208,10 +209,9 @@ gimp_transform_tool_init (GimpTransformTool *tr_tool)
                                      GIMP_CURSOR_PRECISION_SUBPIXEL);
 
   tr_tool->function      = TRANSFORM_CREATING;
+  tr_tool->progress_text = _("Transforming");
 
   gimp_matrix3_identity (&tr_tool->transform);
-
-  tr_tool->progress_text = _("Transforming");
 }
 
 static void
@@ -499,6 +499,11 @@ gimp_transform_tool_modifier_key (GimpTool        *tool,
     g_object_set (options,
                   "constrain", ! options->constrain,
                   NULL);
+
+  if (key == GDK_MOD1_MASK)
+    g_object_set (options,
+                  "alternate", ! options->alternate,
+                  NULL);
 }
 
 static void
@@ -723,7 +728,7 @@ gimp_transform_tool_options_notify (GimpTool         *tool,
       gimp_draw_tool_resume (GIMP_DRAW_TOOL (tr_tool));
     }
 
-  if (! strcmp (pspec->name, "constrain"))
+  if (! strcmp (pspec->name, "constrain") || ! strcmp (pspec->name, "alternate"))
     {
       gimp_transform_tool_dialog_update (tr_tool);
     }
@@ -754,7 +759,7 @@ gimp_transform_tool_draw (GimpDrawTool *draw_tool)
                                                 tr_tool->y1,
                                                 tr_tool->x2,
                                                 tr_tool->y2,
-                                                GIMP_IS_PERSPECTIVE_TOOL (tr_tool),
+                                                GIMP_IS_PERSPECTIVE_TOOL (tr_tool) || GIMP_IS_UNIFIED_TRANSFORMATION_TOOL (tr_tool),
                                                 options->preview_opacity);
         }
 
@@ -851,7 +856,7 @@ gimp_transform_tool_draw (GimpDrawTool *draw_tool)
   if (tr_tool->use_pivot)
     {
       GimpCanvasGroup *stroke_group;
-      gint d = MIN (handle_w, handle_h);
+      gint d = MIN (handle_w, handle_h) * 2; /* so you can grab it from under the center handle */
 
       stroke_group = gimp_draw_tool_add_stroke_group (draw_tool);
 
@@ -1310,11 +1315,11 @@ gimp_transform_tool_transform_bounding_box (GimpTransformTool *tr_tool)
   gimp_matrix3_transform_point (&tr_tool->transform,
                                 tr_tool->x2, tr_tool->y2,
                                 &tr_tool->tx4, &tr_tool->ty4);
-
-  /* don't transform these */
   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;
 
diff --git a/app/tools/gimptransformtool.h b/app/tools/gimptransformtool.h
index d8dacf1..03166e1 100644
--- a/app/tools/gimptransformtool.h
+++ b/app/tools/gimptransformtool.h
@@ -22,7 +22,7 @@
 #include "gimpdrawtool.h"
 
 
-#define TRANS_INFO_SIZE  8
+#define TRANS_INFO_SIZE 10
 
 typedef enum
 {
@@ -65,6 +65,12 @@ struct _GimpTransformTool
   gdouble         lastx;           /*  last x coord                      */
   gdouble         lasty;           /*  last y coord                      */
 
+  gdouble         previousx;       /*  previous x coord                  */
+  gdouble         previousy;       /*  previous y coord                  */
+
+  gdouble         mousex;          /*  x coord where mouse was clicked   */
+  gdouble         mousey;          /*  y coord where mouse was clicked   */
+
   gint            x1, y1;          /*  upper left hand coordinate        */
   gint            x2, y2;          /*  lower right hand coords           */
   gdouble         cx, cy;          /*  center point (for moving)         */
diff --git a/app/tools/gimpunifiedtransformationtool.c b/app/tools/gimpunifiedtransformationtool.c
new file mode 100644
index 0000000..347da02
--- /dev/null
+++ b/app/tools/gimpunifiedtransformationtool.c
@@ -0,0 +1,440 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include <string.h>
+
+#include <gegl.h>
+#include <gtk/gtk.h>
+
+#include "libgimpmath/gimpmath.h"
+#include "libgimpwidgets/gimpwidgets.h"
+
+#include "tools-types.h"
+
+#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 "gimpunifiedtransformationtool.h"
+#include "gimptoolcontrol.h"
+#include "gimptransformoptions.h"
+
+#include "gimp-intl.h"
+
+
+/*  index into trans_info array  */
+enum
+{
+  X0,
+  Y0,
+  X1,
+  Y1,
+  X2,
+  Y2,
+  X3,
+  Y3,
+  PIVOT_X,
+  PIVOT_Y,
+};
+
+
+/*  local function prototypes  */
+
+static void    gimp_unified_transformation_tool_dialog        (GimpTransformTool *tr_tool);
+static void    gimp_unified_transformation_tool_dialog_update (GimpTransformTool *tr_tool);
+static void    gimp_unified_transformation_tool_prepare       (GimpTransformTool *tr_tool);
+static void    gimp_unified_transformation_tool_motion        (GimpTransformTool *tr_tool);
+static void    gimp_unified_transformation_tool_recalc_matrix (GimpTransformTool *tr_tool);
+static gchar * gimp_unified_transformation_tool_get_undo_desc (GimpTransformTool *tr_tool);
+
+
+G_DEFINE_TYPE (GimpUnifiedTransformationTool, gimp_unified_transformation_tool,
+               GIMP_TYPE_TRANSFORM_TOOL)
+
+
+void
+gimp_unified_transformation_tool_register (GimpToolRegisterCallback  callback,
+                                           gpointer                  data)
+{
+  (* callback) (GIMP_TYPE_UNIFIED_TRANSFORMATION_TOOL,
+                GIMP_TYPE_TRANSFORM_OPTIONS,
+                gimp_transform_options_gui,
+                GIMP_CONTEXT_BACKGROUND_MASK,
+                "gimp-unified-transformation-tool",
+                _("Unified Transformation"),
+                _("Unified Transformation Tool: "
+                  "Transform the layer, selection or path"),
+                N_("_Unified Transformation"), "<shift>U",
+                NULL, GIMP_HELP_TOOL_UNIFIED_TRANSFORMATION,
+                GIMP_STOCK_TOOL_UNIFIED_TRANSFORMATION,
+                data);
+}
+
+static void
+gimp_unified_transformation_tool_class_init (GimpUnifiedTransformationToolClass *klass)
+{
+  GimpTransformToolClass *trans_class = GIMP_TRANSFORM_TOOL_CLASS (klass);
+
+  trans_class->dialog        = gimp_unified_transformation_tool_dialog;
+  trans_class->dialog_update = gimp_unified_transformation_tool_dialog_update;
+  trans_class->prepare       = gimp_unified_transformation_tool_prepare;
+  trans_class->motion        = gimp_unified_transformation_tool_motion;
+  trans_class->recalc_matrix = gimp_unified_transformation_tool_recalc_matrix;
+  trans_class->get_undo_desc = gimp_unified_transformation_tool_get_undo_desc;
+}
+
+static void
+gimp_unified_transformation_tool_init (GimpUnifiedTransformationTool *unified_tool)
+{
+  GimpTool          *tool    = GIMP_TOOL (unified_tool);
+  GimpTransformTool *tr_tool = GIMP_TRANSFORM_TOOL (unified_tool);
+
+  gimp_tool_control_set_tool_cursor (tool->control,
+                                     GIMP_TOOL_CURSOR_UNIFIED_TRANSFORMATION);
+
+  tr_tool->progress_text = _("Unified transformation");
+
+  tr_tool->use_grid        = TRUE;
+  tr_tool->use_handles     = TRUE;
+  tr_tool->use_center      = TRUE;
+  tr_tool->use_mid_handles = TRUE;
+  tr_tool->use_pivot       = TRUE;
+}
+
+static void
+gimp_unified_transformation_tool_dialog (GimpTransformTool *tr_tool)
+{
+  GimpUnifiedTransformationTool *unified = GIMP_UNIFIED_TRANSFORMATION_TOOL (tr_tool);
+  GtkWidget                     *content_area;
+  GtkWidget                     *frame;
+  GtkWidget                     *table;
+  gint                           x, y;
+
+  content_area = gtk_dialog_get_content_area (GTK_DIALOG (tr_tool->dialog));
+
+  frame = gimp_frame_new (_("Transformation Matrix"));
+  gtk_container_set_border_width (GTK_CONTAINER (frame), 6);
+  gtk_box_pack_start (GTK_BOX (content_area), frame, FALSE, FALSE, 0);
+  gtk_widget_show (frame);
+
+  table = gtk_table_new (3, 3, FALSE);
+  gtk_table_set_row_spacings (GTK_TABLE (table), 2);
+  gtk_table_set_col_spacings (GTK_TABLE (table), 2);
+  gtk_container_add (GTK_CONTAINER (frame), table);
+  gtk_widget_show (table);
+
+  for (y = 0; y < 3; y++)
+    for (x = 0; x < 3; x++)
+      {
+        GtkWidget *label = gtk_label_new (" ");
+
+        gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.0);
+        gtk_label_set_width_chars (GTK_LABEL (label), 12);
+        gtk_table_attach (GTK_TABLE (table), label,
+                          x, x + 1, y, y + 1, GTK_EXPAND, GTK_FILL, 0, 0);
+        gtk_widget_show (label);
+
+        unified->label[y][x] = label;
+      }
+}
+
+static void
+gimp_unified_transformation_tool_dialog_update (GimpTransformTool *tr_tool)
+{
+  GimpUnifiedTransformationTool *unified = GIMP_UNIFIED_TRANSFORMATION_TOOL (tr_tool);
+  gint                           x, y;
+
+  for (y = 0; y < 3; y++)
+    for (x = 0; x < 3; x++)
+      {
+        gchar buf[32];
+
+        g_snprintf (buf, sizeof (buf),
+                    "%10.5f", tr_tool->transform.coeff[y][x]);
+
+        gtk_label_set_text (GTK_LABEL (unified->label[y][x]), buf);
+      }
+}
+
+static void
+gimp_unified_transformation_tool_prepare (GimpTransformTool  *tr_tool)
+{
+  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;
+
+  tr_tool->trans_info[X0] = (gdouble) tr_tool->x1;
+  tr_tool->trans_info[Y0] = (gdouble) tr_tool->y1;
+  tr_tool->trans_info[X1] = (gdouble) tr_tool->x2;
+  tr_tool->trans_info[Y1] = (gdouble) tr_tool->y1;
+  tr_tool->trans_info[X2] = (gdouble) tr_tool->x1;
+  tr_tool->trans_info[Y2] = (gdouble) tr_tool->y2;
+  tr_tool->trans_info[X3] = (gdouble) tr_tool->x2;
+  tr_tool->trans_info[Y3] = (gdouble) tr_tool->y2;
+}
+
+
+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;
+}
+
+/* finds the clockwise angle between the vectors given, 0-2Ï */
+static inline gdouble calcangle(GimpVector2 a, GimpVector2 b) {
+    gdouble angle, angle2, 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.) ? 2*G_PI-angle : 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 shearvector(GimpVector2 p, gdouble factor) {
+    GimpVector2 ret;
+    ret.x = p.x + p.y * factor;
+    ret.y = p.y;
+    return ret;
+}
+
+static void
+gimp_unified_transformation_tool_motion (GimpTransformTool *transform_tool)
+{
+  gdouble diff_x = transform_tool->curx - transform_tool->lastx,
+          diff_y = transform_tool->cury - transform_tool->lasty;
+  gdouble *x[4], *y[4], px[4], py[4], *pivot_x, *pivot_y;
+  gint i;
+  gboolean horizontal = FALSE;
+  GimpTransformOptions *options = GIMP_TRANSFORM_TOOL_GET_OPTIONS (transform_tool);
+
+  x[0] = &transform_tool->trans_info[X0];
+  x[1] = &transform_tool->trans_info[X1];
+  x[2] = &transform_tool->trans_info[X2];
+  x[3] = &transform_tool->trans_info[X3];
+  y[0] = &transform_tool->trans_info[Y0];
+  y[1] = &transform_tool->trans_info[Y1];
+  y[2] = &transform_tool->trans_info[Y2];
+  y[3] = &transform_tool->trans_info[Y3];
+  
+  px[0] = (*transform_tool->prev_trans_info)[X0];
+  px[1] = (*transform_tool->prev_trans_info)[X1];
+  px[2] = (*transform_tool->prev_trans_info)[X2];
+  px[3] = (*transform_tool->prev_trans_info)[X3];
+  py[0] = (*transform_tool->prev_trans_info)[Y0];
+  py[1] = (*transform_tool->prev_trans_info)[Y1];
+  py[2] = (*transform_tool->prev_trans_info)[Y2];
+  py[3] = (*transform_tool->prev_trans_info)[Y3];
+
+  pivot_x = &transform_tool->trans_info[PIVOT_X];
+  pivot_y = &transform_tool->trans_info[PIVOT_Y];
+
+  if (options->alternate)
+    {
+      gdouble *x0, *x1, *y0, *y1;
+      gboolean moveedge = FALSE;
+
+      switch (transform_tool->function)
+        {
+        case TRANSFORM_HANDLE_W:
+          x0 = x[0]; y0 = y[0];
+          x1 = x[2]; y1 = y[2];
+          moveedge = TRUE;
+          break;
+
+        case TRANSFORM_HANDLE_S:
+          x0 = x[2]; y0 = y[2];
+          x1 = x[3]; y1 = y[3];
+          moveedge = TRUE;
+          break;
+
+        case TRANSFORM_HANDLE_N:
+          x0 = x[0]; y0 = y[0];
+          x1 = x[1]; y1 = y[1];
+          moveedge = TRUE;
+          break;
+
+        case TRANSFORM_HANDLE_E:
+          x0 = x[1]; y0 = y[1];
+          x1 = x[3]; y1 = y[3];
+          moveedge = TRUE;
+          break;
+
+        case TRANSFORM_HANDLE_NW:
+          *x[0] += diff_x;
+          *y[0] += diff_y;
+          return;
+
+        case TRANSFORM_HANDLE_NE:
+          *x[1] += diff_x;
+          *y[1] += diff_y;
+          return;
+
+        case TRANSFORM_HANDLE_SW:
+          *x[2] += diff_x;
+          *y[2] += diff_y;
+          return;
+
+        case TRANSFORM_HANDLE_SE:
+          *x[3] += diff_x;
+          *y[3] += diff_y;
+          return;
+
+        default:
+          break;
+        }
+      if (moveedge)
+        {
+          *x0 += diff_x;
+          *x1 += diff_x;
+          *y0 += diff_y;
+          *y1 += diff_y;
+          return;
+        }
+    }
+
+  switch (transform_tool->function)
+    {
+    case TRANSFORM_HANDLE_NW:
+    case TRANSFORM_HANDLE_NE:
+    case TRANSFORM_HANDLE_SW:
+    case TRANSFORM_HANDLE_SE:
+    {
+      GimpVector2 m = { .x = transform_tool->curx,   .y = transform_tool->cury };
+      GimpVector2 p = { .x = transform_tool->mousex, .y = transform_tool->mousey };
+      GimpVector2 c = { .x = *pivot_x,               .y = *pivot_y };
+      gdouble angle = calcangle(vectorsubtract(m, c), vectorsubtract(p, c));
+      for (i = 0; i < 4; i++) {
+        p.x = px[i]; p.y = py[i];
+        m = vectoradd(c, rotate2d(vectorsubtract(p, c), angle));
+        *x[i] = m.x;
+        *y[i] = m.y;
+      }
+      return;
+    }
+    case TRANSFORM_HANDLE_CENTER:
+      *x[0] += diff_x;
+      *y[0] += diff_y;
+      *x[1] += diff_x;
+      *y[1] += diff_y;
+      *x[2] += diff_x;
+      *y[2] += diff_y;
+      *x[3] += diff_x;
+      *y[3] += diff_y;
+      break;
+
+    case TRANSFORM_HANDLE_PIVOT:
+      *pivot_x += diff_x;
+      *pivot_y += diff_y;
+      break;
+
+    case TRANSFORM_HANDLE_E:
+    case TRANSFORM_HANDLE_W:
+      horizontal = TRUE;
+    case TRANSFORM_HANDLE_N:
+    case TRANSFORM_HANDLE_S:
+      if (! options->constrain)
+        {
+          for (i = 0; i < 4; i++)
+            {
+              if (horizontal)
+                *x[i] = *pivot_x + (*pivot_x-transform_tool->curx)/(*pivot_x-transform_tool->mousex)*(px[i]-*pivot_x);
+              else
+                *y[i] = *pivot_y + (*pivot_y-transform_tool->cury)/(*pivot_y-transform_tool->mousey)*(py[i]-*pivot_y);
+            }
+        } else {
+          GimpVector2 m = { .x = transform_tool->curx,   .y = transform_tool->cury };
+          GimpVector2 p = { .x = transform_tool->mousex, .y = transform_tool->mousey };
+          GimpVector2 c = { .x = *pivot_x,               .y = *pivot_y };
+          gdouble onorm = 1./norm(vectorsubtract(c, p));
+          gdouble distance = norm(vectorsubtract(c, m)) * onorm;
+          for (i = 0; i < 4; i++) {
+            p.x = px[i]; p.y = py[i];
+            m = vectoradd(c, scalemult(vectorsubtract(p, c), distance));
+            *x[i] = m.x;
+            *y[i] = m.y;
+          }
+        }
+      break;
+
+    default:
+      break;
+    }
+}
+
+static void
+gimp_unified_transformation_tool_recalc_matrix (GimpTransformTool *tr_tool)
+{
+  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,
+                                     tr_tool->y1,
+                                     tr_tool->x2 - tr_tool->x1,
+                                     tr_tool->y2 - tr_tool->y1,
+                                     tr_tool->trans_info[X0],
+                                     tr_tool->trans_info[Y0],
+                                     tr_tool->trans_info[X1],
+                                     tr_tool->trans_info[Y1],
+                                     tr_tool->trans_info[X2],
+                                     tr_tool->trans_info[Y2],
+                                     tr_tool->trans_info[X3],
+                                     tr_tool->trans_info[Y3]);
+}
+
+static gchar *
+gimp_unified_transformation_tool_get_undo_desc (GimpTransformTool *tr_tool)
+{
+  return g_strdup (C_("undo-type", "Unified Transform"));
+}
diff --git a/app/tools/gimpunifiedtransformationtool.h b/app/tools/gimpunifiedtransformationtool.h
new file mode 100644
index 0000000..1d9b02e
--- /dev/null
+++ b/app/tools/gimpunifiedtransformationtool.h
@@ -0,0 +1,55 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __GIMP_UNIFIED_TRANSFORMATION_TOOL_H__
+#define __GIMP_UNIFIED_TRANSFORMATION_TOOL_H__
+
+
+#include "gimptransformtool.h"
+
+
+#define GIMP_TYPE_UNIFIED_TRANSFORMATION_TOOL            (gimp_unified_transformation_tool_get_type ())
+#define GIMP_UNIFIED_TRANSFORMATION_TOOL(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_UNIFIED_TRANSFORMATION_TOOL, GimpUnifiedTransformationTool))
+#define GIMP_UNIFIED_TRANSFORMATION_TOOL_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_UNIFIED_TRANSFORMATION_TOOL, GimpUnifiedTransformationToolClass))
+#define GIMP_IS_UNIFIED_TRANSFORMATION_TOOL(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_UNIFIED_TRANSFORMATION_TOOL))
+#define GIMP_IS_UNIFIED_TRANSFORMATION_TOOL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_UNIFIED_TRANSFORMATION_TOOL))
+#define GIMP_UNIFIED_TRANSFORMATION_TOOL_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_UNIFIED_TRANSFORMATION_TOOL, GimpUnifiedTransformationToolClass))
+
+
+typedef struct _GimpUnifiedTransformationTool      GimpUnifiedTransformationTool;
+typedef struct _GimpUnifiedTransformationToolClass GimpUnifiedTransformationToolClass;
+
+struct _GimpUnifiedTransformationTool
+{
+  GimpTransformTool  parent_instance;
+
+  GtkWidget         *label[3][3];
+};
+
+struct _GimpUnifiedTransformationToolClass
+{
+  GimpTransformToolClass  parent_class;
+};
+
+
+void    gimp_unified_transformation_tool_register (GimpToolRegisterCallback  callback,
+                                        gpointer                  data);
+
+GType   gimp_unified_transformation_tool_get_type (void) G_GNUC_CONST;
+
+
+#endif  /*  __GIMP_UNIFIED_TRANSFORMATION_TOOL_H__  */
diff --git a/app/widgets/gimphelp-ids.h b/app/widgets/gimphelp-ids.h
index 92d722d..26ad596 100644
--- a/app/widgets/gimphelp-ids.h
+++ b/app/widgets/gimphelp-ids.h
@@ -285,6 +285,7 @@
 #define GIMP_HELP_TOOL_SMUDGE                     "gimp-tool-smudge"
 #define GIMP_HELP_TOOL_TEXT                       "gimp-tool-text"
 #define GIMP_HELP_TOOL_THRESHOLD                  "gimp-tool-threshold"
+#define GIMP_HELP_TOOL_UNIFIED_TRANSFORMATION     "gimp-tool-unified-transformation"
 #define GIMP_HELP_TOOL_VECTORS                    "gimp-tool-vectors"
 #define GIMP_HELP_TOOL_ZOOM                       "gimp-tool-zoom"
 
diff --git a/app/widgets/widgets-enums.h b/app/widgets/widgets-enums.h
index ae8f5ae..c3935a0 100644
--- a/app/widgets/widgets-enums.h
+++ b/app/widgets/widgets-enums.h
@@ -221,6 +221,7 @@ typedef enum  /*< skip >*/
   GIMP_TOOL_CURSOR_ROTATE,
   GIMP_TOOL_CURSOR_SHEAR,
   GIMP_TOOL_CURSOR_PERSPECTIVE,
+  GIMP_TOOL_CURSOR_UNIFIED_TRANSFORMATION,
   GIMP_TOOL_CURSOR_FLIP_HORIZONTAL,
   GIMP_TOOL_CURSOR_FLIP_VERTICAL,
   GIMP_TOOL_CURSOR_TEXT,
diff --git a/libgimpwidgets/gimpstock.c b/libgimpwidgets/gimpstock.c
index 4e6b5ab..c3aa848 100644
--- a/libgimpwidgets/gimpstock.c
+++ b/libgimpwidgets/gimpstock.c
@@ -342,6 +342,7 @@ static const GtkStockItem gimp_stock_items[] =
   { GIMP_STOCK_TOOL_SMUDGE,              NULL,        0, 0, LIBGIMP_DOMAIN },
   { GIMP_STOCK_TOOL_TEXT,                NULL,        0, 0, LIBGIMP_DOMAIN },
   { GIMP_STOCK_TOOL_THRESHOLD,           NULL,        0, 0, LIBGIMP_DOMAIN },
+  { GIMP_STOCK_TOOL_UNIFIED_TRANSFORMATION, N_("_Transform"), 0, 0, LIBGIMP_DOMAIN },
   { GIMP_STOCK_TOOL_ZOOM,                NULL,        0, 0, LIBGIMP_DOMAIN }
 };
 
@@ -497,6 +498,7 @@ gimp_stock_button_pixbufs[] =
   { GIMP_STOCK_TOOL_SMUDGE,              stock_tool_smudge_22              },
   { GIMP_STOCK_TOOL_TEXT,                stock_tool_text_22                },
   { GIMP_STOCK_TOOL_THRESHOLD,           stock_tool_threshold_22           },
+  { GIMP_STOCK_TOOL_UNIFIED_TRANSFORMATION, stock_tool_unified_transformation_22 },
   { GIMP_STOCK_TOOL_ZOOM,                stock_tool_zoom_22                },
 
   { GIMP_STOCK_INFO,                     stock_info_24                     },
@@ -664,6 +666,7 @@ gimp_stock_menu_pixbufs[] =
   { GIMP_STOCK_TOOL_SMUDGE,              stock_tool_smudge_16              },
   { GIMP_STOCK_TOOL_TEXT,                stock_tool_text_16                },
   { GIMP_STOCK_TOOL_THRESHOLD,           stock_tool_threshold_16           },
+  { GIMP_STOCK_TOOL_UNIFIED_TRANSFORMATION, stock_tool_unified_transformation_16 },
   { GIMP_STOCK_TOOL_ZOOM,                stock_tool_zoom_16                },
 
   { GIMP_STOCK_INFO,                     stock_info_16                     },
diff --git a/libgimpwidgets/gimpstock.h b/libgimpwidgets/gimpstock.h
index cdb4423..b471d1d 100644
--- a/libgimpwidgets/gimpstock.h
+++ b/libgimpwidgets/gimpstock.h
@@ -142,6 +142,7 @@ G_BEGIN_DECLS
 #define GIMP_STOCK_TOOL_SMUDGE              "gimp-tool-smudge"
 #define GIMP_STOCK_TOOL_TEXT                "gimp-tool-text"
 #define GIMP_STOCK_TOOL_THRESHOLD           "gimp-tool-threshold"
+#define GIMP_STOCK_TOOL_UNIFIED_TRANSFORMATION "gimp-tool-unified-transformation"
 #define GIMP_STOCK_TOOL_ZOOM                "gimp-tool-zoom"
 
 
diff --git a/themes/Default/images/Makefile.am b/themes/Default/images/Makefile.am
index bf854d2..2cd5b84 100644
--- a/themes/Default/images/Makefile.am
+++ b/themes/Default/images/Makefile.am
@@ -347,6 +347,8 @@ STOCK_TOOL_IMAGES = \
 	tools/stock-tool-text-22.png			\
 	tools/stock-tool-threshold-16.png		\
 	tools/stock-tool-threshold-22.png		\
+	tools/stock-tool-unified-transformation-16.png		\
+	tools/stock-tool-unified-transformation-22.png		\
 	tools/stock-tool-zoom-16.png			\
 	tools/stock-tool-zoom-22.png
 
diff --git a/themes/Default/images/tools/stock-tool-unified-transformation-16.png b/themes/Default/images/tools/stock-tool-unified-transformation-16.png
new file mode 100644
index 0000000..9aa1f7e
Binary files /dev/null and b/themes/Default/images/tools/stock-tool-unified-transformation-16.png differ
diff --git a/themes/Default/images/tools/stock-tool-unified-transformation-22.png b/themes/Default/images/tools/stock-tool-unified-transformation-22.png
new file mode 100644
index 0000000..ef3430d
Binary files /dev/null and b/themes/Default/images/tools/stock-tool-unified-transformation-22.png differ
diff --git a/themes/Default/images/tools/stock-tool-unified-transformation-22.xcf b/themes/Default/images/tools/stock-tool-unified-transformation-22.xcf
new file mode 100644
index 0000000..e7101bb
Binary files /dev/null and b/themes/Default/images/tools/stock-tool-unified-transformation-22.xcf differ



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