[gimp] Bug 735906 - Transform tools give unexpected results when transforming...



commit 358f13f5b89249ca9bac4857f3ce37bc454b5929
Author: Michael Natterer <mitch gimp org>
Date:   Sat Jun 27 12:34:19 2015 +0200

    Bug 735906 - Transform tools give unexpected results when transforming...
    
    ...certain sets of linked layers
    
    Fix the move tool (GimpEditSelectionTool) using the same principle
    as the other "linked item" features, just a bit more complicated...
    
    Never translate the active item and its linked items separately,
    always translate the entire list at once.
    
    The linked logic was distributed across the entire file. Changed the
    code to prepare lists of items that are translated live (layers and
    vectors), and items that are translated at the end (channels, masks
    and the selection). In the motion and button release functions, simply
    use the prepared lists without any further duplicated checking.
    
    Also clean up the stuff a bit, there is more cleanup needed but first
    the fix...

 app/tools/gimpeditselectiontool.c |  346 ++++++++++++++++--------------------
 1 files changed, 154 insertions(+), 192 deletions(-)
---
diff --git a/app/tools/gimpeditselectiontool.c b/app/tools/gimpeditselectiontool.c
index 8e6193f..5f25991 100644
--- a/app/tools/gimpeditselectiontool.c
+++ b/app/tools/gimpeditselectiontool.c
@@ -87,6 +87,9 @@ struct _GimpEditSelectionTool
 
   GimpTranslateMode   edit_mode;       /*  Translate the mask or layer?      */
 
+  GList              *live_items;      /*  Items that are transformed live   */
+  GList              *delayed_items;   /*  Items that are transformed later  */
+
   gboolean            first_move;      /*  Don't push undos after the first  */
 
   gboolean            propagate_release;
@@ -102,26 +105,26 @@ struct _GimpEditSelectionToolClass
 };
 
 
-static void       gimp_edit_selection_tool_button_release      (GimpTool                    *tool,
-                                                                const GimpCoords            *coords,
-                                                                guint32                      time,
-                                                                GdkModifierType              state,
-                                                                GimpButtonReleaseType        release_type,
-                                                                GimpDisplay                 *display);
-static void       gimp_edit_selection_tool_motion              (GimpTool                    *tool,
-                                                                const GimpCoords            *coords,
-                                                                guint32                      time,
-                                                                GdkModifierType              state,
-                                                                GimpDisplay                 *display);
-static void       gimp_edit_selection_tool_active_modifier_key (GimpTool                    *tool,
-                                                                GdkModifierType              key,
-                                                                gboolean                     press,
-                                                                GdkModifierType              state,
-                                                                GimpDisplay                 *display);
-static void       gimp_edit_selection_tool_draw                (GimpDrawTool                *tool);
-
-static GimpItem * gimp_edit_selection_tool_get_active_item     (const GimpEditSelectionTool *edit_select,
-                                                                const GimpImage             *image);
+static void       gimp_edit_selection_tool_button_release      (GimpTool              *tool,
+                                                                const GimpCoords      *coords,
+                                                                guint32                time,
+                                                                GdkModifierType        state,
+                                                                GimpButtonReleaseType  release_type,
+                                                                GimpDisplay           *display);
+static void       gimp_edit_selection_tool_motion              (GimpTool              *tool,
+                                                                const GimpCoords      *coords,
+                                                                guint32                time,
+                                                                GdkModifierType        state,
+                                                                GimpDisplay           *display);
+static void       gimp_edit_selection_tool_active_modifier_key (GimpTool              *tool,
+                                                                GdkModifierType        key,
+                                                                gboolean               press,
+                                                                GdkModifierType        state,
+                                                                GimpDisplay           *display);
+static void       gimp_edit_selection_tool_draw                (GimpDrawTool          *tool);
+
+static GimpItem * gimp_edit_selection_tool_get_active_item     (GimpEditSelectionTool *edit_select,
+                                                                GimpImage             *image);
 
 
 G_DEFINE_TYPE (GimpEditSelectionTool, gimp_edit_selection_tool,
@@ -144,17 +147,9 @@ gimp_edit_selection_tool_class_init (GimpEditSelectionToolClass *klass)
 }
 
 static void
-gimp_edit_selection_tool_init (GimpEditSelectionTool *edit_selection_tool)
+gimp_edit_selection_tool_init (GimpEditSelectionTool *edit_select)
 {
-  edit_selection_tool->origx      = 0;
-  edit_selection_tool->origy      = 0;
-
-  edit_selection_tool->cumlx      = 0;
-  edit_selection_tool->cumly      = 0;
-
-  edit_selection_tool->first_move = TRUE;
-
-  edit_selection_tool->constrain  = FALSE;
+  edit_select->first_move = TRUE;
 }
 
 static void
@@ -191,7 +186,7 @@ gimp_edit_selection_tool_start (GimpTool          *parent_tool,
   gint                   off_x, off_y;
   const GimpBoundSeg    *segs_in;
   const GimpBoundSeg    *segs_out;
-  const gchar           *undo_desc;
+  const gchar           *undo_desc = NULL;
 
   edit_select = g_object_new (GIMP_TYPE_EDIT_SELECTION_TOOL,
                               "tool-info", parent_tool->tool_info,
@@ -229,17 +224,19 @@ gimp_edit_selection_tool_start (GimpTool          *parent_tool,
     case GIMP_TRANSLATE_MODE_VECTORS:
     case GIMP_TRANSLATE_MODE_CHANNEL:
     case GIMP_TRANSLATE_MODE_LAYER_MASK:
+    case GIMP_TRANSLATE_MODE_MASK:
     case GIMP_TRANSLATE_MODE_LAYER:
       undo_desc = GIMP_ITEM_GET_CLASS (active_item)->translate_desc;
       break;
 
-    case GIMP_TRANSLATE_MODE_MASK:
-      undo_desc = _("Move Selection");
+    case GIMP_TRANSLATE_MODE_MASK_TO_LAYER:
+    case GIMP_TRANSLATE_MODE_MASK_COPY_TO_LAYER:
+    case GIMP_TRANSLATE_MODE_FLOATING_SEL:
+      undo_desc = _("Move Floating Selection");
       break;
 
     default:
-      undo_desc = _("Move Floating Selection");
-      break;
+      g_return_if_reached ();
     }
 
   gimp_image_undo_group_start (image,
@@ -260,17 +257,10 @@ gimp_edit_selection_tool_start (GimpTool          *parent_tool,
 
   edit_select->constrain = FALSE;
 
-  switch (edit_select->edit_mode)
-    {
-    case GIMP_TRANSLATE_MODE_CHANNEL:
-    case GIMP_TRANSLATE_MODE_LAYER_MASK:
-      channel = GIMP_CHANNEL (active_item);
-     break;
-
-    default:
-      channel = gimp_image_get_mask (image);
-      break;
-    }
+  if (GIMP_IS_CHANNEL (active_item))
+    channel = GIMP_CHANNEL (active_item);
+  else
+    channel = gimp_image_get_mask (image);
 
   gimp_channel_boundary (channel,
                          &segs_in, &segs_out,
@@ -278,10 +268,12 @@ gimp_edit_selection_tool_start (GimpTool          *parent_tool,
                          0, 0, 0, 0);
 
   edit_select->segs_in = g_memdup (segs_in,
-                                   edit_select->num_segs_in * sizeof (GimpBoundSeg));
+                                   edit_select->num_segs_in *
+                                   sizeof (GimpBoundSeg));
 
   edit_select->segs_out = g_memdup (segs_out,
-                                    edit_select->num_segs_out * sizeof (GimpBoundSeg));
+                                    edit_select->num_segs_out *
+                                    sizeof (GimpBoundSeg));
 
   if (edit_select->edit_mode == GIMP_TRANSLATE_MODE_VECTORS)
     {
@@ -312,10 +304,7 @@ gimp_edit_selection_tool_start (GimpTool          *parent_tool,
     switch (edit_select->edit_mode)
       {
       case GIMP_TRANSLATE_MODE_CHANNEL:
-        gimp_channel_bounds (GIMP_CHANNEL (active_item),
-                             &x1, &y1, &x2, &y2);
-        break;
-
+      case GIMP_TRANSLATE_MODE_MASK:
       case GIMP_TRANSLATE_MODE_LAYER_MASK:
         gimp_channel_bounds (GIMP_CHANNEL (active_item),
                              &x1, &y1, &x2, &y2);
@@ -325,11 +314,6 @@ gimp_edit_selection_tool_start (GimpTool          *parent_tool,
         y2 += off_y;
         break;
 
-      case GIMP_TRANSLATE_MODE_MASK:
-        gimp_channel_bounds (gimp_image_get_mask (image),
-                             &x1, &y1, &x2, &y2);
-        break;
-
       case GIMP_TRANSLATE_MODE_MASK_TO_LAYER:
       case GIMP_TRANSLATE_MODE_MASK_COPY_TO_LAYER:
         x1 = edit_select->x1 + off_x;
@@ -347,17 +331,17 @@ gimp_edit_selection_tool_start (GimpTool          *parent_tool,
 
         if (gimp_item_get_linked (active_item))
           {
+            /*  Expand the rectangle to include all linked layers as well  */
+
             GList *linked;
             GList *list;
 
-            linked = gimp_image_item_list_get_list (image,
-                                                    active_item,
+            linked = gimp_image_item_list_get_list (image, NULL,
                                                     GIMP_ITEM_TYPE_LAYERS,
                                                     GIMP_ITEM_SET_LINKED);
 
-            linked = gimp_image_item_list_filter (active_item, linked);
+            linked = gimp_image_item_list_filter (NULL, linked);
 
-            /*  Expand the rectangle to include all linked layers as well  */
             for (list = linked; list; list = g_list_next (list))
               {
                 GimpItem *item = list->data;
@@ -388,17 +372,16 @@ gimp_edit_selection_tool_start (GimpTool          *parent_tool,
 
           if (gimp_item_get_linked (active_item))
             {
-              /*  Expand the rectangle to include all linked layers as well  */
+              /*  Expand the rectangle to include all linked vectors as well  */
 
               GList *linked;
               GList *list;
 
-              linked = gimp_image_item_list_get_list (image,
-                                                      active_item,
+              linked = gimp_image_item_list_get_list (image, NULL,
                                                       GIMP_ITEM_TYPE_VECTORS,
                                                       GIMP_ITEM_SET_LINKED);
 
-              linked = gimp_image_item_list_filter (active_item, linked);
+              linked = gimp_image_item_list_filter (NULL, linked);
 
               for (list = linked; list; list = g_list_next (list))
                 {
@@ -434,6 +417,56 @@ gimp_edit_selection_tool_start (GimpTool          *parent_tool,
     edit_select->center_y = (y1 + y2) / 2.0;
   }
 
+  if (gimp_item_get_linked (active_item))
+    {
+      switch (edit_select->edit_mode)
+        {
+        case GIMP_TRANSLATE_MODE_CHANNEL:
+        case GIMP_TRANSLATE_MODE_LAYER:
+        case GIMP_TRANSLATE_MODE_VECTORS:
+          edit_select->live_items =
+            gimp_image_item_list_get_list (image, NULL,
+                                           GIMP_ITEM_TYPE_LAYERS |
+                                           GIMP_ITEM_TYPE_VECTORS,
+                                           GIMP_ITEM_SET_LINKED);
+          edit_select->live_items =
+            gimp_image_item_list_filter (NULL, edit_select->live_items);
+
+          edit_select->delayed_items =
+            gimp_image_item_list_get_list (image, NULL,
+                                           GIMP_ITEM_TYPE_CHANNELS,
+                                           GIMP_ITEM_SET_LINKED);
+          edit_select->delayed_items =
+            gimp_image_item_list_filter (NULL, edit_select->delayed_items);
+          break;
+
+        default:
+          /* other stuff can't be linked so don't bother */
+          break;
+        }
+    }
+  else
+    {
+      switch (edit_select->edit_mode)
+        {
+        case GIMP_TRANSLATE_MODE_VECTORS:
+        case GIMP_TRANSLATE_MODE_LAYER:
+        case GIMP_TRANSLATE_MODE_FLOATING_SEL:
+          edit_select->live_items = g_list_append (NULL, active_item);
+          break;
+
+        case GIMP_TRANSLATE_MODE_CHANNEL:
+        case GIMP_TRANSLATE_MODE_LAYER_MASK:
+        case GIMP_TRANSLATE_MODE_MASK:
+          edit_select->delayed_items = g_list_append (NULL, active_item);
+          break;
+
+        default:
+          /* MASK_TO_LAYER and MASK_COPY_TO_LAYER create a live_item later */
+          break;
+        }
+    }
+
   tool_manager_push_tool (display->gimp, tool);
 
   gimp_tool_control_activate (tool->control);
@@ -462,7 +495,6 @@ gimp_edit_selection_tool_button_release (GimpTool              *tool,
   GimpEditSelectionTool *edit_select = GIMP_EDIT_SELECTION_TOOL (tool);
   GimpDisplayShell      *shell       = gimp_display_get_shell (display);
   GimpImage             *image       = gimp_display_get_image (display);
-  GimpItem              *active_item;
 
   /*  resume the current selection  */
   gimp_display_shell_selection_resume (shell);
@@ -476,72 +508,18 @@ gimp_edit_selection_tool_button_release (GimpTool              *tool,
 
   tool_manager_pop_tool (display->gimp);
 
-  active_item = gimp_edit_selection_tool_get_active_item (edit_select, image);
-
   gimp_edit_selection_tool_calc_coords (edit_select,
                                         coords->x,
                                         coords->y);
 
-  /* GIMP_TRANSLATE_MODE_MASK is performed here at movement end, not 'live' like
-   *  the other translation types.
+  /* move the items -- whether there has been movement or not!
+   * (to ensure that there's something on the undo stack)
    */
-  if (edit_select->edit_mode == GIMP_TRANSLATE_MODE_MASK)
-    {
-      /* move the selection -- whether there has been movement or not!
-       * (to ensure that there's something on the undo stack)
-       */
-      gimp_item_translate (GIMP_ITEM (gimp_image_get_mask (image)),
-                           edit_select->cumlx,
-                           edit_select->cumly,
-                           TRUE);
-    }
-
-  /*  GIMP_TRANSLATE_MODE_CHANNEL and GIMP_TRANSLATE_MODE_LAYER_MASK
-   *  need to be preformed after thawing the undo.
-   */
-  if (edit_select->edit_mode == GIMP_TRANSLATE_MODE_CHANNEL ||
-      edit_select->edit_mode == GIMP_TRANSLATE_MODE_LAYER_MASK)
-    {
-      /* move the channel -- whether there has been movement or not!
-       * (to ensure that there's something on the undo stack)
-       */
-      gimp_item_translate (active_item,
-                           edit_select->cumlx,
-                           edit_select->cumly,
-                           TRUE);
-    }
-
-  if (edit_select->edit_mode == GIMP_TRANSLATE_MODE_VECTORS ||
-      edit_select->edit_mode == GIMP_TRANSLATE_MODE_CHANNEL ||
-      edit_select->edit_mode == GIMP_TRANSLATE_MODE_LAYER)
-    {
-      if ((release_type != GIMP_BUTTON_RELEASE_CANCEL) &&
-          (edit_select->cumlx != 0 ||
-           edit_select->cumly != 0))
-        {
-          if (gimp_item_get_linked (active_item))
-            {
-              /*  translate all linked channels as well  */
-
-              GList *linked;
-
-              linked = gimp_image_item_list_get_list (image,
-                                                      active_item,
-                                                      GIMP_ITEM_TYPE_CHANNELS,
-                                                      GIMP_ITEM_SET_LINKED);
-
-              linked = gimp_image_item_list_filter (active_item, linked);
-
-              gimp_image_item_list_translate (image,
-                                              linked,
-                                              edit_select->cumlx,
-                                              edit_select->cumly,
-                                              TRUE);
-
-              g_list_free (linked);
-            }
-        }
-    }
+  gimp_image_item_list_translate (image,
+                                  edit_select->delayed_items,
+                                  edit_select->cumlx,
+                                  edit_select->cumly,
+                                  TRUE);
 
   gimp_image_undo_group_end (image);
 
@@ -561,6 +539,12 @@ gimp_edit_selection_tool_button_release (GimpTool              *tool,
   edit_select->num_segs_in  = 0;
   edit_select->num_segs_out = 0;
 
+  g_list_free (edit_select->live_items);
+  g_list_free (edit_select->delayed_items);
+
+  edit_select->live_items    = NULL;
+  edit_select->delayed_items = NULL;
+
   if (edit_select->propagate_release &&
       tool_manager_get_active (display->gimp))
     {
@@ -629,11 +613,6 @@ gimp_edit_selection_tool_update_motion (GimpEditSelectionTool *edit_select,
         {
         case GIMP_TRANSLATE_MODE_LAYER_MASK:
         case GIMP_TRANSLATE_MODE_MASK:
-          /*  we don't do the actual edit selection move here.  */
-          edit_select->origx = x;
-          edit_select->origy = y;
-          break;
-
         case GIMP_TRANSLATE_MODE_VECTORS:
         case GIMP_TRANSLATE_MODE_CHANNEL:
           edit_select->origx = x;
@@ -642,35 +621,10 @@ gimp_edit_selection_tool_update_motion (GimpEditSelectionTool *edit_select,
           /*  fallthru  */
 
         case GIMP_TRANSLATE_MODE_LAYER:
-          /*  for CHANNEL_TRANSLATE, only translate the linked layers
-           *  and vectors on-the-fly, the channel is translated
-           *  on button_release.
-           */
-          if (edit_select->edit_mode != GIMP_TRANSLATE_MODE_CHANNEL)
-            gimp_item_translate (active_item, xoffset, yoffset,
-                                 edit_select->first_move);
-
-          if (gimp_item_get_linked (active_item))
-            {
-              /*  translate all linked layers & vectors as well  */
-
-              GList *linked;
-
-              linked = gimp_image_item_list_get_list (image,
-                                                      active_item,
-                                                      GIMP_ITEM_TYPE_LAYERS |
-                                                      GIMP_ITEM_TYPE_VECTORS,
-                                                      GIMP_ITEM_SET_LINKED);
-
-              linked = gimp_image_item_list_filter (active_item, linked);
-
-              gimp_image_item_list_translate (image,
-                                              linked,
-                                              xoffset, yoffset,
-                                              edit_select->first_move);
-
-              g_list_free (linked);
-            }
+          gimp_image_item_list_translate (image,
+                                          edit_select->live_items,
+                                          xoffset, yoffset,
+                                          edit_select->first_move);
           break;
 
         case GIMP_TRANSLATE_MODE_MASK_TO_LAYER:
@@ -701,14 +655,18 @@ gimp_edit_selection_tool_update_motion (GimpEditSelectionTool *edit_select,
 
           edit_select->edit_mode = GIMP_TRANSLATE_MODE_FLOATING_SEL;
 
-          active_item =
-            GIMP_ITEM (gimp_image_get_active_drawable (image));
+          active_item = gimp_edit_selection_tool_get_active_item (edit_select,
+                                                                  image);
 
-          /* fall through */
+          edit_select->live_items = g_list_prepend (NULL, active_item);
+
+          /*  fallthru  */
 
         case GIMP_TRANSLATE_MODE_FLOATING_SEL:
-          gimp_item_translate (active_item, xoffset, yoffset,
-                               edit_select->first_move);
+          gimp_image_item_list_translate (image,
+                                          edit_select->live_items,
+                                          xoffset, yoffset,
+                                          edit_select->first_move);
           break;
         }
 
@@ -788,8 +746,10 @@ gimp_edit_selection_tool_draw (GimpDrawTool *draw_tool)
     case GIMP_TRANSLATE_MODE_MASK:
       {
         gboolean floating_sel = FALSE;
-        gint     off_x        = 0;
-        gint     off_y        = 0;
+        gint     off_x;
+        gint     off_y;
+
+        gimp_item_get_offset (active_item, &off_x, &off_y);
 
         if (edit_select->edit_mode == GIMP_TRANSLATE_MODE_MASK)
           {
@@ -798,10 +758,6 @@ gimp_edit_selection_tool_draw (GimpDrawTool *draw_tool)
             if (layer)
               floating_sel = gimp_layer_is_floating_sel (layer);
           }
-        else
-          {
-            gimp_item_get_offset (active_item, &off_x, &off_y);
-          }
 
         if (! floating_sel && edit_select->segs_in)
           {
@@ -853,10 +809,7 @@ gimp_edit_selection_tool_draw (GimpDrawTool *draw_tool)
 
     case GIMP_TRANSLATE_MODE_LAYER:
       {
-        GimpItem *active_item;
-        gint      x1, y1, x2, y2;
-
-        active_item = GIMP_ITEM (gimp_image_get_active_layer (image));
+        gint x1, y1, x2, y2;
 
         gimp_item_get_offset (active_item, &x1, &y1);
 
@@ -870,12 +823,11 @@ gimp_edit_selection_tool_draw (GimpDrawTool *draw_tool)
             GList *linked;
             GList *list;
 
-            linked = gimp_image_item_list_get_list (image,
-                                                    active_item,
+            linked = gimp_image_item_list_get_list (image, NULL,
                                                     GIMP_ITEM_TYPE_LAYERS,
                                                     GIMP_ITEM_SET_LINKED);
 
-            linked = gimp_image_item_list_filter (active_item, linked);
+            linked = gimp_image_item_list_filter (NULL, linked);
 
             for (list = linked; list; list = g_list_next (list))
               {
@@ -905,10 +857,7 @@ gimp_edit_selection_tool_draw (GimpDrawTool *draw_tool)
 
     case GIMP_TRANSLATE_MODE_VECTORS:
       {
-        GimpItem *active_item;
-        gdouble   x1, y1, x2, y2;
-
-        active_item = GIMP_ITEM (gimp_image_get_active_vectors (image));
+        gdouble x1, y1, x2, y2;
 
         gimp_vectors_bounds (GIMP_VECTORS (active_item), &x1, &y1, &x2, &y2);
 
@@ -919,12 +868,11 @@ gimp_edit_selection_tool_draw (GimpDrawTool *draw_tool)
             GList *linked;
             GList *list;
 
-            linked = gimp_image_item_list_get_list (image,
-                                                    active_item,
+            linked = gimp_image_item_list_get_list (image, NULL,
                                                     GIMP_ITEM_TYPE_VECTORS,
                                                     GIMP_ITEM_SET_LINKED);
 
-            linked = gimp_image_item_list_filter (active_item, linked);
+            linked = gimp_image_item_list_filter (NULL, linked);
 
             for (list = linked; list; list = g_list_next (list))
               {
@@ -977,15 +925,29 @@ gimp_edit_selection_tool_draw (GimpDrawTool *draw_tool)
 }
 
 static GimpItem *
-gimp_edit_selection_tool_get_active_item (const GimpEditSelectionTool *edit_select,
-                                          const GimpImage             *image)
+gimp_edit_selection_tool_get_active_item (GimpEditSelectionTool *edit_select,
+                                          GimpImage             *image)
 {
   GimpItem *active_item;
 
-  if (edit_select->edit_mode == GIMP_TRANSLATE_MODE_VECTORS)
-    active_item = GIMP_ITEM (gimp_image_get_active_vectors (image));
-  else
-    active_item = GIMP_ITEM (gimp_image_get_active_drawable (image));
+  switch (edit_select->edit_mode)
+    {
+    case GIMP_TRANSLATE_MODE_VECTORS:
+      active_item = GIMP_ITEM (gimp_image_get_active_vectors (image));
+      break;
+
+    case GIMP_TRANSLATE_MODE_LAYER:
+      active_item = GIMP_ITEM (gimp_image_get_active_layer (image));
+      break;
+
+    case GIMP_TRANSLATE_MODE_MASK:
+      active_item = GIMP_ITEM (gimp_image_get_mask (image));
+      break;
+
+    default:
+      active_item = GIMP_ITEM (gimp_image_get_active_drawable (image));
+      break;
+    }
 
   return active_item;
 }


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