[gimp/soc-2010-cage-2: 3/8] Implementation of the multi-selection in the cage tool and refactoring that come with. This editing



commit dd28e1fe0278cf0e0ddb076e8aaa4d8b73500218
Author: Michael Muré <batolettre gmail com>
Date:   Sun Jan 2 16:15:55 2011 +0100

    Implementation of the multi-selection in the cage tool and refactoring that come with.
    This editing mode should work like the path tool.
    The backup of the cages point for undo is replaced by a displacement that affect
    all the selected point in CageConfig with commit/reset displacement.

 app/core/core-types.h     |    1 +
 app/gegl/gimpcageconfig.c |  298 +++++++++++++++++++++++++++++++++------------
 app/gegl/gimpcageconfig.h |   22 +++-
 app/tools/gimpcagetool.c  |  225 +++++++++++++++++-----------------
 app/tools/gimpcagetool.h  |   22 ++--
 5 files changed, 361 insertions(+), 207 deletions(-)
---
diff --git a/app/core/core-types.h b/app/core/core-types.h
index e7e360c..1021f41 100644
--- a/app/core/core-types.h
+++ b/app/core/core-types.h
@@ -210,6 +210,7 @@ struct _GimpCagePoint
   GimpVector2 dest_point;
   GimpVector2 edge_normal;
   gdouble     edge_scaling_factor;
+  gboolean    selected;
 };
 
 struct _GimpCoords
diff --git a/app/gegl/gimpcageconfig.c b/app/gegl/gimpcageconfig.c
index 6d7458a..c61b805 100644
--- a/app/gegl/gimpcageconfig.c
+++ b/app/gegl/gimpcageconfig.c
@@ -50,8 +50,7 @@ static void   gimp_cage_config_set_property           (GObject        *object,
                                                        GParamSpec     *pspec);
 
 static void   gimp_cage_config_compute_scaling_factor (GimpCageConfig *gcc);
-static void   gimp_cage_config_compute_edge_normal    (GimpCageConfig *gcc);
-
+static void   gimp_cage_config_compute_edges_normal   (GimpCageConfig *gcc);
 
 G_DEFINE_TYPE_WITH_CODE (GimpCageConfig, gimp_cage_config,
                          GIMP_TYPE_IMAGE_MAP_CONFIG,
@@ -164,16 +163,16 @@ gimp_cage_config_add_cage_point (GimpCageConfig  *gcc,
                                   gcc->max_cage_vertices);
     }
 
-  gcc->cage_points[gcc->n_cage_vertices].src_point.x = x + DELTA - gcc->offset_x;
-  gcc->cage_points[gcc->n_cage_vertices].src_point.y = y + DELTA - gcc->offset_y;
+  gcc->cage_points[gcc->n_cage_vertices].src_point.x = x + DELTA;
+  gcc->cage_points[gcc->n_cage_vertices].src_point.y = y + DELTA;
 
-  gcc->cage_points[gcc->n_cage_vertices].dest_point.x = x + DELTA - gcc->offset_x;
-  gcc->cage_points[gcc->n_cage_vertices].dest_point.y = y + DELTA - gcc->offset_y;
+  gcc->cage_points[gcc->n_cage_vertices].dest_point.x = x + DELTA;
+  gcc->cage_points[gcc->n_cage_vertices].dest_point.y = y + DELTA;
 
   gcc->n_cage_vertices++;
 
   gimp_cage_config_compute_scaling_factor (gcc);
-  gimp_cage_config_compute_edge_normal (gcc);
+  gimp_cage_config_compute_edges_normal (gcc);
 }
 
 /**
@@ -191,46 +190,129 @@ gimp_cage_config_remove_last_cage_point (GimpCageConfig  *gcc)
     gcc->n_cage_vertices--;
 
   gimp_cage_config_compute_scaling_factor (gcc);
-  gimp_cage_config_compute_edge_normal (gcc);
+  gimp_cage_config_compute_edges_normal (gcc);
 }
 
 /**
- * gimp_cage_config_move_cage_point:
+ * gimp_cage_config_get_point_coordinate:
  * @gcc: the cage config
  * @mode: the actual mode of the cage, GIMP_CAGE_MODE_CAGE_CHANGE or GIMP_CAGE_MODE_DEFORM
- * @point_number: the point of the cage to move
- * @x: new x value
- * @y: new y value
+ * @point_number: the index of the point to return
  *
- * Move a point of the source or destination cage, according to the
- * cage mode provided
+ * Returns: the real position of the given point, as a GimpVector2
  */
-void
-gimp_cage_config_move_cage_point (GimpCageConfig  *gcc,
-                                  GimpCageMode     mode,
-                                  gint             point_number,
-                                  gdouble          x,
-                                  gdouble          y)
+GimpVector2
+gimp_cage_config_get_point_coordinate  (GimpCageConfig  *gcc,
+                                        GimpCageMode     mode,
+                                        gint             point_number)
 {
-  g_return_if_fail (GIMP_IS_CAGE_CONFIG (gcc));
-  g_return_if_fail (point_number < gcc->n_cage_vertices);
-  g_return_if_fail (point_number >= 0);
+  GimpVector2 point = {0.0, 0.0};
+
+  g_return_val_if_fail (GIMP_IS_CAGE_CONFIG (gcc), point);
+  g_return_val_if_fail (point_number < gcc->n_cage_vertices, point);
+  g_return_val_if_fail (point_number >= 0, point);
 
-  if (mode == GIMP_CAGE_MODE_CAGE_CHANGE)
+  if (gcc->cage_points[point_number].selected)
     {
-      gcc->cage_points[point_number].src_point.x = x + DELTA - gcc->offset_x;
-      gcc->cage_points[point_number].src_point.y = y + DELTA - gcc->offset_y;
-      gcc->cage_points[point_number].dest_point.x = x + DELTA - gcc->offset_x;
-      gcc->cage_points[point_number].dest_point.y = y + DELTA - gcc->offset_y;
+      if (mode == GIMP_CAGE_MODE_CAGE_CHANGE)
+        {
+          point.x = gcc->cage_points[point_number].src_point.x + gcc->displacement_x;
+          point.y = gcc->cage_points[point_number].src_point.y + gcc->displacement_y;
+        }
+      else
+        {
+          point.x = gcc->cage_points[point_number].dest_point.x + gcc->displacement_x;
+          point.y = gcc->cage_points[point_number].dest_point.y + gcc->displacement_y;
+        }
     }
   else
     {
-      gcc->cage_points[point_number].dest_point.x = x + DELTA - gcc->offset_x;
-      gcc->cage_points[point_number].dest_point.y = y + DELTA - gcc->offset_y;
+      if (mode == GIMP_CAGE_MODE_CAGE_CHANGE)
+        {
+          point.x = gcc->cage_points[point_number].src_point.x;
+          point.y = gcc->cage_points[point_number].src_point.y;
+        }
+      else
+        {
+          point.x = gcc->cage_points[point_number].dest_point.x;
+          point.y = gcc->cage_points[point_number].dest_point.y;
+        }
     }
 
-  gimp_cage_config_compute_scaling_factor (gcc);
-  gimp_cage_config_compute_edge_normal (gcc);
+  return point;
+}
+
+/**
+ * gimp_cage_config_add_displacement:
+ * @gcc: the cage config
+ * @mode: the actual mode of the cage, GIMP_CAGE_MODE_CAGE_CHANGE or GIMP_CAGE_MODE_DEFORM
+ * @point_number: the point of the cage to move
+ * @x: x displacement value
+ * @y: y displacement value
+ *
+ * Add a displacement for all slected point of the cage.
+ * This displacement need to be commited to become effective.
+ */
+void
+gimp_cage_config_add_displacement (GimpCageConfig  *gcc,
+                                   GimpCageMode     mode,
+                                   gdouble          x,
+                                   gdouble          y)
+{
+  g_return_if_fail (GIMP_IS_CAGE_CONFIG (gcc));
+
+  gcc->cage_mode = mode;
+  gcc->displacement_x = x;
+  gcc->displacement_y = y;
+}
+
+/**
+ * gimp_cage_config_commit_displacement:
+ * @gcc: the cage config
+ *
+ * Apply the displacement to the cage
+ */
+void
+gimp_cage_config_commit_displacement  (GimpCageConfig *gcc)
+{
+  gint  i;
+
+  g_return_if_fail (GIMP_IS_CAGE_CONFIG (gcc));
+
+  for (i = 0; i < gcc->n_cage_vertices; i++)
+    {
+      if (gcc->cage_points[i].selected)
+        {
+          if (gcc->cage_mode == GIMP_CAGE_MODE_CAGE_CHANGE)
+            {
+              gcc->cage_points[i].src_point.x += gcc->displacement_x;
+              gcc->cage_points[i].src_point.y += gcc->displacement_y;
+              gcc->cage_points[i].dest_point.x += gcc->displacement_x;
+              gcc->cage_points[i].dest_point.y += gcc->displacement_y;
+            }
+          else
+            {
+              gcc->cage_points[i].dest_point.x += gcc->displacement_x;
+              gcc->cage_points[i].dest_point.y += gcc->displacement_y;
+            }
+        }
+    }
+  gimp_cage_config_reset_displacement (gcc);
+}
+
+/**
+ * gimp_cage_config_reset_displacement:
+ * @gcc: the cage config
+ *
+ * Set the displacement to zero.
+ */
+void
+gimp_cage_config_reset_displacement (GimpCageConfig  *gcc)
+{
+  g_return_if_fail (GIMP_IS_CAGE_CONFIG (gcc));
+
+  gcc->displacement_x = 0.0;
+  gcc->displacement_y = 0.0;
 }
 
 /**
@@ -250,8 +332,17 @@ gimp_cage_config_get_bounding_box (GimpCageConfig  *gcc)
   g_return_val_if_fail (GIMP_IS_CAGE_CONFIG (gcc), bounding_box);
   g_return_val_if_fail (gcc->n_cage_vertices >= 0, bounding_box);
 
-  bounding_box.x = gcc->cage_points[0].src_point.x;
-  bounding_box.y = gcc->cage_points[0].src_point.y;
+  if (gcc->cage_points[0].selected)
+    {
+      bounding_box.x = gcc->cage_points[0].src_point.x + gcc->displacement_x;
+      bounding_box.y = gcc->cage_points[0].src_point.y + gcc->displacement_y;
+    }
+  else
+    {
+      bounding_box.x = gcc->cage_points[0].src_point.x;
+      bounding_box.y = gcc->cage_points[0].src_point.y;
+    }
+
   bounding_box.height = 0;
   bounding_box.width = 0;
 
@@ -259,8 +350,16 @@ gimp_cage_config_get_bounding_box (GimpCageConfig  *gcc)
     {
       gdouble x,y;
 
-      x = gcc->cage_points[i].src_point.x;
-      y = gcc->cage_points[i].src_point.y;
+      if (gcc->cage_points[i].selected)
+        {
+          x = gcc->cage_points[i].src_point.x + gcc->displacement_x;
+          y = gcc->cage_points[i].src_point.y + gcc->displacement_y;
+        }
+      else
+        {
+          x = gcc->cage_points[i].src_point.x;
+          y = gcc->cage_points[i].src_point.y;
+        }
 
       if (x < bounding_box.x)
         {
@@ -300,7 +399,7 @@ void
 gimp_cage_config_reverse_cage (GimpCageConfig *gcc)
 {
   GimpCagePoint temp;
-  gint        i;
+  gint          i;
 
   g_return_if_fail (GIMP_IS_CAGE_CONFIG (gcc));
 
@@ -312,7 +411,7 @@ gimp_cage_config_reverse_cage (GimpCageConfig *gcc)
     }
 
   gimp_cage_config_compute_scaling_factor (gcc);
-  gimp_cage_config_compute_edge_normal (gcc);
+  gimp_cage_config_compute_edges_normal (gcc);
 }
 
 /**
@@ -323,6 +422,8 @@ gimp_cage_config_reverse_cage (GimpCageConfig *gcc)
  * topological inside in the actual 'physical' inside of the cage,
  * this function compute if the cage is clockwise or not, and reverse
  * the cage if needed.
+ *
+ * This function does not take into account an eventual displacement
  */
 void
 gimp_cage_config_reverse_cage_if_needed (GimpCageConfig *gcc)
@@ -359,50 +460,12 @@ gimp_cage_config_reverse_cage_if_needed (GimpCageConfig *gcc)
 }
 
 /**
- * gimp_cage_config_get_cage_points:
+ * gimp_cage_config_compute_scaling_factor:
  * @gcc: the cage config
  *
- * Returns: a copy of the cage's point
+ * Update Green Coordinate scaling factor for the destination cage.
+ * This function does not take into account an eventual displacement.
  */
-GimpCagePoint*
-gimp_cage_config_get_cage_points (GimpCageConfig  *gcc)
-{
-  gint            i;
-  GimpCagePoint  *points_copy;
-
-  g_return_val_if_fail (GIMP_IS_CAGE_CONFIG (gcc), NULL);
-
-  points_copy = g_new (GimpCagePoint, gcc->n_cage_vertices);
-
-  for(i = 0; i < gcc->n_cage_vertices; i++)
-    {
-      points_copy[i] = gcc->cage_points[i];
-    }
-
-  return points_copy;
-}
-
-/**
- * gimp_cage_config_commit_cage_points:
- * @gcc: the cage config
- * @points: a GimpCagePoint array of point of the same length as the number of point in the cage
- *
- * This function update the cage's point with the array provided.
- */
-void
-gimp_cage_config_commit_cage_points (GimpCageConfig  *gcc,
-                                     GimpCagePoint   *points)
-{
-  gint          i;
-
-  g_return_if_fail (GIMP_IS_CAGE_CONFIG (gcc));
-
-  for(i = 0; i < gcc->n_cage_vertices; i++)
-    {
-      gcc->cage_points[i] = points[i];
-    }
-}
-
 static void
 gimp_cage_config_compute_scaling_factor (GimpCageConfig *gcc)
 {
@@ -432,8 +495,15 @@ gimp_cage_config_compute_scaling_factor (GimpCageConfig *gcc)
 #endif
 }
 
+/**
+ * gimp_cage_config_compute_edges_normal:
+ * @gcc: the cage config
+ *
+ * Update edges normal for the destination cage.
+ * This function does not take into account an eventual displacement.
+ */
 static void
-gimp_cage_config_compute_edge_normal (GimpCageConfig *gcc)
+gimp_cage_config_compute_edges_normal (GimpCageConfig *gcc)
 {
   GimpVector2 normal;
   gint        i;
@@ -460,6 +530,7 @@ gimp_cage_config_compute_edge_normal (GimpCageConfig *gcc)
  * the regard of the topological inside of the source cage.
  *
  * Returns: TRUE if the point is inside, FALSE if not.
+ * This function does not take into account an eventual displacement.
  */
 gboolean
 gimp_cage_config_point_inside (GimpCageConfig *gcc,
@@ -489,3 +560,70 @@ gimp_cage_config_point_inside (GimpCageConfig *gcc,
 
   return inside;
 }
+
+/**
+ * gimp_cage_config_select_point:
+ * @gcc: the cage config
+ * @point_number: the index of the point to select
+ *
+ * Select the given point of the cage, and deselect the others.
+ */
+void
+gimp_cage_config_select_point (GimpCageConfig  *gcc,
+                               gint             point_number)
+{
+  gint  i;
+
+  g_return_if_fail (GIMP_IS_CAGE_CONFIG (gcc));
+  g_return_if_fail (point_number < gcc->n_cage_vertices);
+  g_return_if_fail (point_number >= 0);
+
+  for (i = 0; i < gcc->n_cage_vertices; i++)
+    {
+      if (i == point_number)
+        {
+          gcc->cage_points[i].selected = TRUE;
+        }
+      else
+        {
+          gcc->cage_points[i].selected = FALSE;
+        }
+    }
+}
+
+/**
+ * gimp_cage_config_toggle_point_selection:
+ * @gcc: the cage config
+ * @point_number: the index of the point to toggle selection
+ *
+ * Toggle the selection of the given cage point
+ */
+void
+gimp_cage_config_toggle_point_selection (GimpCageConfig  *gcc,
+                                         gint             point_number)
+{
+  g_return_if_fail (GIMP_IS_CAGE_CONFIG (gcc));
+  g_return_if_fail (point_number < gcc->n_cage_vertices);
+  g_return_if_fail (point_number >= 0);
+
+  gcc->cage_points[point_number].selected = ! gcc->cage_points[point_number].selected;
+}
+
+/**
+ * gimp_cage_deselect_points:
+ * @gcc: the cage config
+ *
+ * Deselect all cage points.
+ */
+void
+gimp_cage_deselect_points (GimpCageConfig  *gcc)
+{
+  gint  i;
+
+  g_return_if_fail (GIMP_IS_CAGE_CONFIG (gcc));
+
+  for (i = 0; i < gcc->n_cage_vertices; i++)
+    {
+      gcc->cage_points[i].selected = FALSE;
+    }
+}
\ No newline at end of file
diff --git a/app/gegl/gimpcageconfig.h b/app/gegl/gimpcageconfig.h
index 3e6841b..f26f493 100644
--- a/app/gegl/gimpcageconfig.h
+++ b/app/gegl/gimpcageconfig.h
@@ -41,8 +41,9 @@ struct _GimpCageConfig
   gint                n_cage_vertices;   /* vertices used by the cage */
   gint                max_cage_vertices; /* vertices allocated        */
 
-  gint                offset_x;
-  gint                offset_y;
+  gdouble             displacement_x;
+  gdouble             displacement_y;
+  GimpCageMode        cage_mode;  /* Cage mode, used to commit displacement */
 
   GimpCagePoint      *cage_points;
 };
@@ -58,18 +59,25 @@ void            gimp_cage_config_add_cage_point         (GimpCageConfig  *gcc,
                                                          gdouble          x,
                                                          gdouble          y);
 void            gimp_cage_config_remove_last_cage_point (GimpCageConfig  *gcc);
-void            gimp_cage_config_move_cage_point        (GimpCageConfig  *gcc,
+GimpVector2     gimp_cage_config_get_point_coordinate   (GimpCageConfig  *gcc,
+                                                         GimpCageMode     mode,
+                                                         gint             point_number);
+void            gimp_cage_config_add_displacement       (GimpCageConfig  *gcc,
                                                          GimpCageMode     mode,
-                                                         gint             point_number,
                                                          gdouble          x,
                                                          gdouble          y);
+void            gimp_cage_config_commit_displacement    (GimpCageConfig  *gcc);
+void            gimp_cage_config_reset_displacement     (GimpCageConfig  *gcc);
 GeglRectangle   gimp_cage_config_get_bounding_box       (GimpCageConfig  *gcc);
 void            gimp_cage_config_reverse_cage_if_needed (GimpCageConfig  *gcc);
 void            gimp_cage_config_reverse_cage           (GimpCageConfig  *gcc);
 gboolean        gimp_cage_config_point_inside           (GimpCageConfig  *gcc,
                                                          gfloat           x,
                                                          gfloat           y);
-GimpCagePoint*  gimp_cage_config_get_cage_points        (GimpCageConfig  *gcc);
-void            gimp_cage_config_commit_cage_points     (GimpCageConfig  *gcc,
-                                                         GimpCagePoint   *points);
+void            gimp_cage_config_select_point           (GimpCageConfig  *gcc,
+                                                         gint             point_number);
+void            gimp_cage_config_toggle_point_selection (GimpCageConfig  *gcc,
+                                                         gint             point_number);
+void            gimp_cage_deselect_points               (GimpCageConfig  *gcc);
+
 #endif /* __GIMP_CAGE_CONFIG_H__ */
diff --git a/app/tools/gimpcagetool.c b/app/tools/gimpcagetool.c
index 0ce4829..ba97ac4 100644
--- a/app/tools/gimpcagetool.c
+++ b/app/tools/gimpcagetool.c
@@ -99,10 +99,9 @@ static void       gimp_cage_tool_oper_update        (GimpTool              *tool
 
 static void       gimp_cage_tool_draw               (GimpDrawTool          *draw_tool);
 
-static gint       gimp_cage_tool_is_on_handle       (GimpCageConfig        *gcc,
+static gint       gimp_cage_tool_is_on_handle       (GimpCageTool          *ct,
                                                      GimpDrawTool          *draw_tool,
                                                      GimpDisplay           *display,
-                                                     GimpCageMode           mode,
                                                      gdouble                x,
                                                      gdouble                y,
                                                      gint                   handle_size);
@@ -188,13 +187,11 @@ gimp_cage_tool_init (GimpCageTool *self)
 
   self->config          = g_object_new (GIMP_TYPE_CAGE_CONFIG, NULL);
   self->hovering_handle = -1;
-  self->moving_handle   = -1;
   self->cage_complete   = FALSE;
   self->tool_state      = CAGE_STATE_INIT;
 
   self->coef            = NULL;
   self->image_map       = NULL;
-  self->cage_backup     = NULL;
 
   gimp_tool_control_set_wants_click (tool->control, TRUE);
   gimp_tool_control_set_tool_cursor (tool->control,
@@ -259,7 +256,6 @@ gimp_cage_tool_start (GimpCageTool *ct,
 
   ct->config          = g_object_new (GIMP_TYPE_CAGE_CONFIG, NULL);
   ct->hovering_handle = -1;
-  ct->moving_handle   = -1;
   ct->cage_complete   = FALSE;
   ct->tool_state      = CAGE_STATE_INIT;
 
@@ -268,8 +264,8 @@ gimp_cage_tool_start (GimpCageTool *ct,
    */
   gimp_item_get_offset (GIMP_ITEM (drawable), &off_x, &off_y);
 
-  ct->config->offset_x = off_x;
-  ct->config->offset_y = off_y;
+  ct->offset_x = off_x;
+  ct->offset_y = off_y;
 
   gimp_draw_tool_start (GIMP_DRAW_TOOL (ct), display);
 }
@@ -337,11 +333,10 @@ gimp_cage_tool_motion (GimpTool         *tool,
     {
       case CAGE_STATE_MOVE_HANDLE:
       case DEFORM_STATE_MOVE_HANDLE:
-        gimp_cage_config_move_cage_point (ct->config,
-                                          options->cage_mode,
-                                          ct->moving_handle,
-                                          ct->cursor_x,
-                                          ct->cursor_y);
+        gimp_cage_config_add_displacement (ct->config,
+                                           options->cage_mode,
+                                           ct->cursor_x - ct->movement_start_x,
+                                           ct->cursor_y - ct->movement_start_y);
         break;
     }
 
@@ -357,15 +352,13 @@ gimp_cage_tool_oper_update (GimpTool         *tool,
 {
   GimpCageTool    *ct        = GIMP_CAGE_TOOL (tool);
   GimpDrawTool    *draw_tool = GIMP_DRAW_TOOL (tool);
-  GimpCageOptions *options   = GIMP_CAGE_TOOL_GET_OPTIONS (ct);
   GimpCageConfig  *config    = ct->config;
   gint             handle    = -1;
 
   if (config)
-    handle = gimp_cage_tool_is_on_handle (config,
+    handle = gimp_cage_tool_is_on_handle (ct,
                                           draw_tool,
                                           display,
-                                          options->cage_mode,
                                           coords->x,
                                           coords->y,
                                           GIMP_TOOL_HANDLE_SIZE_CIRCLE);
@@ -389,28 +382,29 @@ gimp_cage_tool_button_press (GimpTool            *tool,
 {
   GimpCageTool    *ct        = GIMP_CAGE_TOOL (tool);
   GimpDrawTool    *draw_tool = GIMP_DRAW_TOOL (tool);
-  GimpCageOptions *options   = GIMP_CAGE_TOOL_GET_OPTIONS (ct);
   gint             handle    = -1;
 
   if (display != tool->display)
     gimp_cage_tool_start (ct, display);
 
   if (ct->config)
-      handle = gimp_cage_tool_is_on_handle (ct->config,
+      handle = gimp_cage_tool_is_on_handle (ct,
                                             draw_tool,
                                             display,
-                                            options->cage_mode,
                                             coords->x,
                                             coords->y,
                                             GIMP_TOOL_HANDLE_SIZE_CIRCLE);
+  ct->movement_start_x = coords->x;
+  ct->movement_start_y = coords->y;
 
   switch (ct->tool_state)
     {
       case CAGE_STATE_INIT:
         /* No handle yet, we add the first one and swith the tool to moving handle state. */
         gimp_cage_config_add_cage_point (ct->config,
-                                         ct->cursor_x, ct->cursor_y);
-        ct->moving_handle = 0;
+                                         ct->cursor_x - ct->offset_x,
+                                         ct->cursor_y - ct->offset_y);
+        gimp_cage_config_select_point (ct->config, 0);
         ct->tool_state = CAGE_STATE_MOVE_HANDLE;
         break;
 
@@ -420,20 +414,34 @@ gimp_cage_tool_button_press (GimpTool            *tool,
             if (handle == -1)
             /* User clicked on the background, we add a new handle and move it */
               {
-                ct->moving_handle = ct->config->n_cage_vertices;
                 gimp_cage_config_add_cage_point (ct->config,
-                                                 ct->cursor_x, ct->cursor_y);
+                                                 ct->cursor_x - ct->offset_x,
+                                                 ct->cursor_y - ct->offset_y);
+                gimp_cage_config_select_point (ct->config, ct->config->n_cage_vertices - 1);
                 ct->tool_state = CAGE_STATE_MOVE_HANDLE;
               }
             if (handle == 0 && ct->config->n_cage_vertices > 2)
             /* User clicked on the first handle, we wait for release for closing the cage and switching to deform if possible */
               {
+                gimp_cage_config_select_point (ct->config, 0);
                 ct->tool_state = CAGE_STATE_CLOSING;
               }
             if (handle > 0)
             /* User clicked on a handle, so we move it */
               {
-                ct->moving_handle = handle;
+                if (state & GDK_SHIFT_MASK)
+                /* Multiple selection */
+                  {
+                    gimp_cage_config_toggle_point_selection (ct->config, handle);
+                  }
+                else
+                /* New selection */
+                  {
+                    if (! ct->config->cage_points[handle].selected)
+                      {
+                        gimp_cage_config_select_point (ct->config, handle);
+                      }
+                  }
                 ct->tool_state = CAGE_STATE_MOVE_HANDLE;
               }
           }
@@ -442,26 +450,41 @@ gimp_cage_tool_button_press (GimpTool            *tool,
             if (handle >= 0)
             /* User clicked on a handle, so we move it */
               {
-                ct->moving_handle = handle;
+                if (state & GDK_SHIFT_MASK)
+                /* Multiple selection */
+                  {
+                    gimp_cage_config_toggle_point_selection (ct->config, handle);
+                  }
+                else
+                /* New selection */
+                  {
+                    if (! ct->config->cage_points[handle].selected)
+                      {
+                        gimp_cage_config_select_point (ct->config, handle);
+                      }
+                  }
                 ct->tool_state = CAGE_STATE_MOVE_HANDLE;
               }
           }
         break;
 
       case DEFORM_STATE_WAIT:
-        /* keep a copy of cage's point, in case of cancel when release */
-        if (ct->cage_backup)
-          {
-            g_free (ct->cage_backup);
-            ct->cage_backup = NULL;
-          }
-
-        ct->cage_backup = gimp_cage_config_get_cage_points (ct->config);
-
         if (handle >= 0)
         /* User clicked on a handle, so we move it */
           {
-            ct->moving_handle = handle;
+            if (state & GDK_SHIFT_MASK)
+            /* Multiple selection */
+              {
+                gimp_cage_config_toggle_point_selection (ct->config, handle);
+              }
+            else
+            /* New selection */
+              {
+                if (! ct->config->cage_points[handle].selected)
+                  {
+                    gimp_cage_config_select_point (ct->config, handle);
+                  }
+              }
             ct->tool_state = DEFORM_STATE_MOVE_HANDLE;
           }
         break;
@@ -481,6 +504,7 @@ gimp_cage_tool_button_release (GimpTool              *tool,
   gimp_draw_tool_pause (GIMP_DRAW_TOOL (ct));
 
   if (state & GDK_BUTTON3_MASK)
+  /* Cancelling */
     {
       switch(ct->tool_state)
         {
@@ -494,14 +518,14 @@ gimp_cage_tool_button_release (GimpTool              *tool,
             break;
 
           case DEFORM_STATE_MOVE_HANDLE:
-            gimp_cage_config_commit_cage_points (ct->config,
-                                                 ct->cage_backup);
             gimp_cage_tool_image_map_update (ct);
             ct->tool_state = DEFORM_STATE_WAIT;
             break;
         }
+      gimp_cage_config_reset_displacement (ct->config);
     }
   else
+  /* Normal release */
     {
       switch(ct->tool_state)
         {
@@ -518,12 +542,7 @@ gimp_cage_tool_button_release (GimpTool              *tool,
             gimp_cage_tool_image_map_update (ct);
             break;
         }
-    }
-
-  if (ct->cage_backup)
-    {
-      g_free (ct->cage_backup);
-      ct->cage_backup = NULL;
+      gimp_cage_config_commit_displacement (ct->config);
     }
 
   gimp_draw_tool_resume (GIMP_DRAW_TOOL (tool));
@@ -579,18 +598,12 @@ gimp_cage_tool_draw (GimpDrawTool *draw_tool)
   /* If needed, draw ligne to the cursor. */
   if (ct->tool_state == CAGE_STATE_WAIT || ct->tool_state == CAGE_STATE_MOVE_HANDLE)
     {
-      if (options->cage_mode == GIMP_CAGE_MODE_CAGE_CHANGE)
-        gimp_draw_tool_add_line (draw_tool,
-                                 config->cage_points[n_vertices - 1].src_point.x + ct->config->offset_x,
-                                 config->cage_points[n_vertices - 1].src_point.y + ct->config->offset_y,
-                                 ct->cursor_x,
-                                 ct->cursor_y);
-      else
-        gimp_draw_tool_add_line (draw_tool,
-                                 config->cage_points[n_vertices - 1].dest_point.x + ct->config->offset_x,
-                                 config->cage_points[n_vertices - 1].dest_point.y + ct->config->offset_y,
-                                 ct->cursor_x,
-                                 ct->cursor_y);
+      GimpVector2 last_point = gimp_cage_config_get_point_coordinate (ct->config, GIMP_CAGE_MODE_CAGE_CHANGE, n_vertices - 1);
+      gimp_draw_tool_add_line (draw_tool,
+                               last_point.x + ct->offset_x,
+                               last_point.y + ct->offset_y,
+                               ct->cursor_x,
+                               ct->cursor_y);
     }
 
   gimp_draw_tool_pop_group (draw_tool);
@@ -598,47 +611,36 @@ gimp_cage_tool_draw (GimpDrawTool *draw_tool)
   /* Draw the cage with handles. */
   for (i = 0; i < n_vertices; i++)
     {
-      gdouble        x1, y1;
+      GimpVector2 point1, point2;
 
-      if (options->cage_mode == GIMP_CAGE_MODE_CAGE_CHANGE)
-        {
-          x1 = config->cage_points[i].src_point.x;
-          y1 = config->cage_points[i].src_point.y;
-        }
-      else
-        {
-          x1 = config->cage_points[i].dest_point.x;
-          y1 = config->cage_points[i].dest_point.y;
-        }
+      point1 = gimp_cage_config_get_point_coordinate (ct->config,
+                                                      options->cage_mode,
+                                                      i);
+      point1.x += ct->offset_x;
+      point1.y += ct->offset_y;
 
       if (i > 0 || ct->cage_complete)
         {
-          gdouble x2, y2;
-          gint    point2;
+          gint  index_point2;
 
           if (i == 0)
-            point2 = n_vertices - 1;
+            index_point2 = n_vertices - 1;
           else
-            point2 = i - 1;
+            index_point2 = i - 1;
 
-          if (options->cage_mode == GIMP_CAGE_MODE_CAGE_CHANGE)
-            {
-              x2 = config->cage_points[point2].src_point.x;
-              y2 = config->cage_points[point2].src_point.y;
-            }
-          else
-            {
-              x2 = config->cage_points[point2].dest_point.x;
-              y2 = config->cage_points[point2].dest_point.y;
-            }
+          point2 = gimp_cage_config_get_point_coordinate (ct->config,
+                                                          options->cage_mode,
+                                                          index_point2);
+          point2.x += ct->offset_x;
+          point2.y += ct->offset_y;
 
           gimp_draw_tool_push_group (draw_tool, stroke_group);
 
           gimp_draw_tool_add_line (draw_tool,
-                                   x1 + ct->config->offset_x,
-                                   y1 + ct->config->offset_y,
-                                   x2 + ct->config->offset_x,
-                                   y2 + ct->config->offset_y);
+                                   point1.x,
+                                   point1.y,
+                                   point2.x,
+                                   point2.y);
 
           gimp_draw_tool_pop_group (draw_tool);
         }
@@ -650,50 +652,57 @@ gimp_cage_tool_draw (GimpDrawTool *draw_tool)
 
       gimp_draw_tool_add_handle (draw_tool,
                                  handle,
-                                 x1 + ct->config->offset_x,
-                                 y1 + ct->config->offset_y,
+                                 point1.x,
+                                 point1.y,
                                  GIMP_TOOL_HANDLE_SIZE_CIRCLE,
                                  GIMP_TOOL_HANDLE_SIZE_CIRCLE,
                                  GIMP_HANDLE_ANCHOR_CENTER);
+
+      if (ct->config->cage_points[i].selected)
+        {
+          gimp_draw_tool_add_handle (draw_tool,
+                           GIMP_HANDLE_SQUARE,
+                           point1.x,
+                           point1.y,
+                           GIMP_TOOL_HANDLE_SIZE_CIRCLE,
+                           GIMP_TOOL_HANDLE_SIZE_CIRCLE,
+                           GIMP_HANDLE_ANCHOR_CENTER);
+        }
     }
 }
 
 static gint
-gimp_cage_tool_is_on_handle (GimpCageConfig *gcc,
+gimp_cage_tool_is_on_handle (GimpCageTool   *ct,
                              GimpDrawTool   *draw_tool,
                              GimpDisplay    *display,
-                             GimpCageMode    mode,
                              gdouble         x,
                              gdouble         y,
                              gint            handle_size)
 {
-  gint    i;
-  gdouble vert_x;
-  gdouble vert_y;
-  gdouble dist = G_MAXDOUBLE;
+  GimpCageOptions *options   = GIMP_CAGE_TOOL_GET_OPTIONS (ct);
+  GimpCageConfig  *config = ct->config;
+  gdouble          dist   = G_MAXDOUBLE;
+  gint             i;
+  GimpVector2      cage_point;
 
-  g_return_val_if_fail (GIMP_IS_CAGE_CONFIG (gcc), -1);
+  g_return_val_if_fail (GIMP_IS_CAGE_TOOL (ct), -1);
 
-  if (gcc->n_cage_vertices == 0)
+  if (config->n_cage_vertices == 0)
     return -1;
 
-  for (i = 0; i < gcc->n_cage_vertices; i++)
+  for (i = 0; i < config->n_cage_vertices; i++)
     {
-      if (mode == GIMP_CAGE_MODE_CAGE_CHANGE)
-        {
-          vert_x = gcc->cage_points[i].src_point.x + gcc->offset_x;
-          vert_y = gcc->cage_points[i].src_point.y + gcc->offset_y;
-        }
-      else
-        {
-          vert_x = gcc->cage_points[i].dest_point.x + gcc->offset_x;
-          vert_y = gcc->cage_points[i].dest_point.y + gcc->offset_y;
-        }
+      cage_point = gimp_cage_config_get_point_coordinate (config,
+                                                          options->cage_mode,
+                                                          i);
+      cage_point.x += ct->offset_x;
+      cage_point.y += ct->offset_y;
 
       dist = gimp_draw_tool_calc_distance_square (GIMP_DRAW_TOOL (draw_tool),
                                                   display,
                                                   x, y,
-                                                  vert_x, vert_y);
+                                                  cage_point.x,
+                                                  cage_point.y);
 
       if (dist <= SQR (handle_size / 2))
         return i;
@@ -958,11 +967,5 @@ gimp_cage_tool_halt (GimpCageTool *ct)
       gimp_image_flush (gimp_display_get_image (tool->display));
     }
 
-  if (ct->cage_backup)
-    {
-      g_free (ct->cage_backup);
-      ct->cage_backup = NULL;
-    }
-
   tool->display  = NULL;
 }
diff --git a/app/tools/gimpcagetool.h b/app/tools/gimpcagetool.h
index 144daf6..bc35fb0 100644
--- a/app/tools/gimpcagetool.h
+++ b/app/tools/gimpcagetool.h
@@ -44,19 +44,23 @@ struct _GimpCageTool
 
   GimpCageConfig *config;
 
-  gdouble         cursor_x;
-  gdouble         cursor_y;
-  gint            hovering_handle;
-  gint            moving_handle;
-  gboolean        cage_complete;
+  gint            offset_x; /* used to convert the cage point coords */
+  gint            offset_y; /* to drawable coords */
 
-  GeglBuffer     *coef;
+  gdouble         cursor_x; /* Hold the cursor x position */
+  gdouble         cursor_y; /* Hold the cursor y position */
 
-  gint            tool_state;
+  gdouble         movement_start_x; /* Where the movement started */
+  gdouble         movement_start_y; /* Where the movement started */
 
-  GimpImageMap   *image_map;
+  gint            hovering_handle; /* Handle which the cursor is above */
+  gboolean        cage_complete; /* Cage closed or not */
 
-  GimpCagePoint  *cage_backup;
+  GeglBuffer     *coef; /* Gegl where the coefficient of the transformation are stored */
+
+  gint            tool_state; /* Current state in statemachine */
+
+  GimpImageMap   *image_map; /* For preview */
 };
 
 struct _GimpCageToolClass



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