[gimp] app: add gimp_item_{start,end}_move()



commit 02a20c6c73c8a718cc03c60f1ca9f2ad5517a348
Author: Ell <ell_se yahoo com>
Date:   Mon Feb 5 10:59:28 2018 -0500

    app: add gimp_item_{start,end}_move()
    
    Add gimp_item_{start,end}_move(), and corresponding
    GimpItem::{start,end}_move() virtual functions, which should be
    called before/after "moving" the item (i.e., translating, scaling,
    resizing, flipping, rotating, or transforming the item).  Moves
    performed between the outermost pair of start/end calls are treated
    atomically.
    
    What exactly does "treated atomically" entail depends on the
    subclasses -- GimpItem doesn't provide a default implementation for
    these functions, so the current commit doesn't change any behavior.
    The next commit, which adds layer-mask support for group layers,
    uses the functions to avoid cropping the mask too early while a
    child is moving.
    
    GimpItem calls {start,end}_move() in the various "move" functions
    (gimp_item_{translate,scale,...}(), before performing the actual
    operation.  Additionally we call the functions in the
    gimp_image_item_list_foo() functions, for each participating item,
    so that the items are moved as a unit.  We call the functions in
    the various gimp_image_remove_foo() functions, since removing an
    item may affect the size of its ancestors, and is therefore akin to
    moving.  We also call the functions in GimpEditSelectionTool, so
    that the move tool moves items atomically while dragging.

 app/core/gimpimage-item-list.c    |   72 +++++++++++++++++++++-----
 app/core/gimpimage.c              |   41 +++++++++++-----
 app/core/gimpitem.c               |   99 ++++++++++++++++++++++++++++++++-----
 app/core/gimpitem.h               |    9 +++
 app/tools/gimpeditselectiontool.c |    9 +++
 5 files changed, 191 insertions(+), 39 deletions(-)
---
diff --git a/app/core/gimpimage-item-list.c b/app/core/gimpimage-item-list.c
index e3fef5e..a9019d3 100644
--- a/app/core/gimpimage-item-list.c
+++ b/app/core/gimpimage-item-list.c
@@ -108,16 +108,30 @@ gimp_image_item_list_translate (GimpImage *image,
     {
       GList *l;
 
-      if (push_undo && list->next)
-        gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_ITEM_DISPLACE,
-                                     C_("undo-type", "Translate Items"));
+      if (list->next)
+        {
+          if (push_undo)
+            {
+              gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_ITEM_DISPLACE,
+                                           C_("undo-type", "Translate Items"));
+            }
+
+          for (l = list; l; l = g_list_next (l))
+            gimp_item_start_move (GIMP_ITEM (l->data), push_undo);
+        }
 
       for (l = list; l; l = g_list_next (l))
         gimp_item_translate (GIMP_ITEM (l->data),
                              offset_x, offset_y, push_undo);
 
-      if (push_undo && list->next)
-        gimp_image_undo_group_end (image);
+      if (list->next)
+        {
+          for (l = list; l; l = g_list_next (l))
+            gimp_item_end_move (GIMP_ITEM (l->data), push_undo);
+
+          if (push_undo)
+            gimp_image_undo_group_end (image);
+        }
     }
 }
 
@@ -137,15 +151,25 @@ gimp_image_item_list_flip (GimpImage           *image,
       GList *l;
 
       if (list->next)
-        gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_TRANSFORM,
-                                     C_("undo-type", "Flip Items"));
+        {
+          gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_TRANSFORM,
+                                       C_("undo-type", "Flip Items"));
+
+          for (l = list; l; l = g_list_next (l))
+            gimp_item_start_move (GIMP_ITEM (l->data), TRUE);
+        }
 
       for (l = list; l; l = g_list_next (l))
         gimp_item_flip (GIMP_ITEM (l->data), context,
                         flip_type, axis, clip_result);
 
       if (list->next)
-        gimp_image_undo_group_end (image);
+        {
+          for (l = list; l; l = g_list_next (l))
+            gimp_item_end_move (GIMP_ITEM (l->data), TRUE);
+
+          gimp_image_undo_group_end (image);
+        }
     }
 }
 
@@ -166,15 +190,25 @@ gimp_image_item_list_rotate (GimpImage        *image,
       GList *l;
 
       if (list->next)
-        gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_TRANSFORM,
-                                     C_("undo-type", "Rotate Items"));
+        {
+          gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_TRANSFORM,
+                                       C_("undo-type", "Rotate Items"));
+
+          for (l = list; l; l = g_list_next (l))
+            gimp_item_start_move (GIMP_ITEM (l->data), TRUE);
+        }
 
       for (l = list; l; l = g_list_next (l))
         gimp_item_rotate (GIMP_ITEM (l->data), context,
                           rotate_type, center_x, center_y, clip_result);
 
       if (list->next)
-        gimp_image_undo_group_end (image);
+        {
+          for (l = list; l; l = g_list_next (l))
+            gimp_item_end_move (GIMP_ITEM (l->data), TRUE);
+
+          gimp_image_undo_group_end (image);
+        }
     }
 }
 
@@ -197,8 +231,13 @@ gimp_image_item_list_transform (GimpImage              *image,
       GList *l;
 
       if (list->next)
-        gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_TRANSFORM,
-                                     C_("undo-type", "Transform Items"));
+        {
+          gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_TRANSFORM,
+                                       C_("undo-type", "Transform Items"));
+
+          for (l = list; l; l = g_list_next (l))
+            gimp_item_start_move (GIMP_ITEM (l->data), TRUE);
+        }
 
       for (l = list; l; l = g_list_next (l))
         gimp_item_transform (GIMP_ITEM (l->data), context,
@@ -207,7 +246,12 @@ gimp_image_item_list_transform (GimpImage              *image,
                              clip_result, progress);
 
       if (list->next)
-        gimp_image_undo_group_end (image);
+        {
+          for (l = list; l; l = g_list_next (l))
+            gimp_item_end_move (GIMP_ITEM (l->data), TRUE);
+
+          gimp_image_undo_group_end (image);
+        }
     }
 }
 
diff --git a/app/core/gimpimage.c b/app/core/gimpimage.c
index 8830a22..d8457c7 100644
--- a/app/core/gimpimage.c
+++ b/app/core/gimpimage.c
@@ -4316,7 +4316,6 @@ gimp_image_remove_layer (GimpImage *image,
   GimpImagePrivate *private;
   GimpLayer        *active_layer;
   gboolean          old_has_alpha;
-  gboolean          undo_group = FALSE;
   const gchar      *undo_desc;
 
   g_return_if_fail (GIMP_IS_IMAGE (image));
@@ -4328,6 +4327,12 @@ gimp_image_remove_layer (GimpImage *image,
 
   gimp_image_unset_default_new_layer_mode (image);
 
+  if (push_undo)
+    gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_IMAGE_ITEM_REMOVE,
+                                 C_("undo-type", "Remove Layer"));
+
+  gimp_item_start_move (GIMP_ITEM (layer), push_undo);
+
   if (gimp_drawable_get_floating_sel (GIMP_DRAWABLE (layer)))
     {
       if (! push_undo)
@@ -4338,10 +4343,6 @@ gimp_image_remove_layer (GimpImage *image,
           return;
         }
 
-      gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_IMAGE_ITEM_REMOVE,
-                                   C_("undo-type", "Remove Layer"));
-      undo_group = TRUE;
-
       gimp_image_remove_layer (image,
                                gimp_drawable_get_floating_sel (GIMP_DRAWABLE (layer)),
                                TRUE, NULL);
@@ -4413,12 +4414,14 @@ gimp_image_remove_layer (GimpImage *image,
       gimp_image_set_active_layer (image, new_active);
     }
 
+  gimp_item_end_move (GIMP_ITEM (layer), push_undo);
+
   g_object_unref (layer);
 
   if (old_has_alpha != gimp_image_has_alpha (image))
     private->flush_accum.alpha_changed = TRUE;
 
-  if (undo_group)
+  if (push_undo)
     gimp_image_undo_group_end (image);
 }
 
@@ -4538,13 +4541,18 @@ gimp_image_remove_channel (GimpImage   *image,
 {
   GimpImagePrivate *private;
   GimpChannel      *active_channel;
-  gboolean          undo_group = FALSE;
 
   g_return_if_fail (GIMP_IS_IMAGE (image));
   g_return_if_fail (GIMP_IS_CHANNEL (channel));
   g_return_if_fail (gimp_item_is_attached (GIMP_ITEM (channel)));
   g_return_if_fail (gimp_item_get_image (GIMP_ITEM (channel)) == image);
 
+  if (push_undo)
+    gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_IMAGE_ITEM_REMOVE,
+                                 C_("undo-type", "Remove Channel"));
+
+  gimp_item_start_move (GIMP_ITEM (channel), push_undo);
+
   if (gimp_drawable_get_floating_sel (GIMP_DRAWABLE (channel)))
     {
       if (! push_undo)
@@ -4555,10 +4563,6 @@ gimp_image_remove_channel (GimpImage   *image,
           return;
         }
 
-      gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_IMAGE_ITEM_REMOVE,
-                                   C_("undo-type", "Remove Channel"));
-      undo_group = TRUE;
-
       gimp_image_remove_layer (image,
                                gimp_drawable_get_floating_sel (GIMP_DRAWABLE (channel)),
                                TRUE, NULL);
@@ -4592,9 +4596,11 @@ gimp_image_remove_channel (GimpImage   *image,
         gimp_image_unset_active_channel (image);
     }
 
+  gimp_item_end_move (GIMP_ITEM (channel), push_undo);
+
   g_object_unref (channel);
 
-  if (undo_group)
+  if (push_undo)
     gimp_image_undo_group_end (image);
 }
 
@@ -4651,6 +4657,12 @@ gimp_image_remove_vectors (GimpImage   *image,
 
   private = GIMP_IMAGE_GET_PRIVATE (image);
 
+  if (push_undo)
+    gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_IMAGE_ITEM_REMOVE,
+                                 C_("undo-type", "Remove Path"));
+
+  gimp_item_start_move (GIMP_ITEM (vectors), push_undo);
+
   active_vectors = gimp_image_get_active_vectors (image);
 
   if (push_undo)
@@ -4674,7 +4686,12 @@ gimp_image_remove_vectors (GimpImage   *image,
       gimp_image_set_active_vectors (image, new_active);
     }
 
+  gimp_item_end_move (GIMP_ITEM (vectors), push_undo);
+
   g_object_unref (vectors);
+
+  if (push_undo)
+    gimp_image_undo_group_end (image);
 }
 
 gboolean
diff --git a/app/core/gimpitem.c b/app/core/gimpitem.c
index b9b5ee7..3879f73 100644
--- a/app/core/gimpitem.c
+++ b/app/core/gimpitem.c
@@ -259,6 +259,8 @@ gimp_item_class_init (GimpItemClass *klass)
   klass->duplicate                 = gimp_item_real_duplicate;
   klass->convert                   = gimp_item_real_convert;
   klass->rename                    = gimp_item_real_rename;
+  klass->start_move                = NULL;
+  klass->end_move                  = NULL;
   klass->translate                 = gimp_item_real_translate;
   klass->scale                     = gimp_item_real_scale;
   klass->resize                    = gimp_item_real_resize;
@@ -1182,6 +1184,32 @@ gimp_item_get_offset_y (GimpItem *item)
   return GET_PRIVATE (item)->offset_y;
 }
 
+void
+gimp_item_start_move (GimpItem *item,
+                      gboolean  push_undo)
+{
+  g_return_if_fail (GIMP_IS_ITEM (item));
+
+  if (! gimp_item_is_attached (item))
+    push_undo = FALSE;
+
+  if (GIMP_ITEM_GET_CLASS (item)->start_move)
+    GIMP_ITEM_GET_CLASS (item)->start_move (item, push_undo);
+}
+
+void
+gimp_item_end_move (GimpItem *item,
+                    gboolean  push_undo)
+{
+  g_return_if_fail (GIMP_IS_ITEM (item));
+
+  if (! gimp_item_is_attached (item))
+    push_undo = FALSE;
+
+  if (GIMP_ITEM_GET_CLASS (item)->end_move)
+    GIMP_ITEM_GET_CLASS (item)->end_move (item, push_undo);
+}
+
 /**
  * gimp_item_translate:
  * @item:      The #GimpItem to move.
@@ -1213,8 +1241,12 @@ gimp_item_translate (GimpItem *item,
     gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_ITEM_DISPLACE,
                                  item_class->translate_desc);
 
+  gimp_item_start_move (item, push_undo);
+
   item_class->translate (item, offset_x, offset_y, push_undo);
 
+  gimp_item_end_move (item, push_undo);
+
   if (push_undo)
     gimp_image_undo_group_end (image);
 }
@@ -1266,6 +1298,7 @@ gimp_item_scale (GimpItem              *item,
 {
   GimpItemClass *item_class;
   GimpImage     *image;
+  gboolean       push_undo;
 
   g_return_if_fail (GIMP_IS_ITEM (item));
   g_return_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress));
@@ -1276,10 +1309,14 @@ gimp_item_scale (GimpItem              *item,
   item_class = GIMP_ITEM_GET_CLASS (item);
   image = gimp_item_get_image (item);
 
-  if (gimp_item_is_attached (item))
+  push_undo = gimp_item_is_attached (item);
+
+  if (push_undo)
     gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_ITEM_SCALE,
                                  item_class->scale_desc);
 
+  gimp_item_start_move (item, push_undo);
+
   g_object_freeze_notify (G_OBJECT (item));
 
   item_class->scale (item, new_width, new_height, new_offset_x, new_offset_y,
@@ -1287,7 +1324,9 @@ gimp_item_scale (GimpItem              *item,
 
   g_object_thaw_notify (G_OBJECT (item));
 
-  if (gimp_item_is_attached (item))
+  gimp_item_end_move (item, push_undo);
+
+  if (push_undo)
     gimp_image_undo_group_end (image);
 }
 
@@ -1444,6 +1483,7 @@ gimp_item_resize (GimpItem     *item,
 {
   GimpItemClass *item_class;
   GimpImage     *image;
+  gboolean       push_undo;
 
   g_return_if_fail (GIMP_IS_ITEM (item));
   g_return_if_fail (GIMP_IS_CONTEXT (context));
@@ -1454,10 +1494,14 @@ gimp_item_resize (GimpItem     *item,
   item_class = GIMP_ITEM_GET_CLASS (item);
   image = gimp_item_get_image (item);
 
-  if (gimp_item_is_attached (item))
+  push_undo = gimp_item_is_attached (item);
+
+  if (push_undo)
     gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_ITEM_RESIZE,
                                  item_class->resize_desc);
 
+  gimp_item_start_move (item, push_undo);
+
   g_object_freeze_notify (G_OBJECT (item));
 
   item_class->resize (item, context, fill_type,
@@ -1465,7 +1509,9 @@ gimp_item_resize (GimpItem     *item,
 
   g_object_thaw_notify (G_OBJECT (item));
 
-  if (gimp_item_is_attached (item))
+  gimp_item_end_move (item, push_undo);
+
+  if (push_undo)
     gimp_image_undo_group_end (image);
 }
 
@@ -1478,6 +1524,7 @@ gimp_item_flip (GimpItem            *item,
 {
   GimpItemClass *item_class;
   GimpImage     *image;
+  gboolean       push_undo;
 
   g_return_if_fail (GIMP_IS_ITEM (item));
   g_return_if_fail (gimp_item_is_attached (item));
@@ -1486,8 +1533,13 @@ gimp_item_flip (GimpItem            *item,
   item_class = GIMP_ITEM_GET_CLASS (item);
   image = gimp_item_get_image (item);
 
-  gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_TRANSFORM,
-                               item_class->flip_desc);
+  push_undo = gimp_item_is_attached (item);
+
+  if (push_undo)
+    gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_TRANSFORM,
+                                 item_class->flip_desc);
+
+  gimp_item_start_move (item, push_undo);
 
   g_object_freeze_notify (G_OBJECT (item));
 
@@ -1495,7 +1547,10 @@ gimp_item_flip (GimpItem            *item,
 
   g_object_thaw_notify (G_OBJECT (item));
 
-  gimp_image_undo_group_end (image);
+  gimp_item_end_move (item, push_undo);
+
+  if (push_undo)
+    gimp_image_undo_group_end (image);
 }
 
 void
@@ -1508,6 +1563,7 @@ gimp_item_rotate (GimpItem         *item,
 {
   GimpItemClass *item_class;
   GimpImage     *image;
+  gboolean       push_undo;
 
   g_return_if_fail (GIMP_IS_ITEM (item));
   g_return_if_fail (gimp_item_is_attached (item));
@@ -1516,8 +1572,13 @@ gimp_item_rotate (GimpItem         *item,
   item_class = GIMP_ITEM_GET_CLASS (item);
   image = gimp_item_get_image (item);
 
-  gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_TRANSFORM,
-                               item_class->rotate_desc);
+  push_undo = gimp_item_is_attached (item);
+
+  if (push_undo)
+    gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_TRANSFORM,
+                                 item_class->rotate_desc);
+
+  gimp_item_start_move (item, push_undo);
 
   g_object_freeze_notify (G_OBJECT (item));
 
@@ -1526,7 +1587,10 @@ gimp_item_rotate (GimpItem         *item,
 
   g_object_thaw_notify (G_OBJECT (item));
 
-  gimp_image_undo_group_end (image);
+  gimp_item_end_move (item, push_undo);
+
+  if (push_undo)
+    gimp_image_undo_group_end (image);
 }
 
 void
@@ -1540,6 +1604,7 @@ gimp_item_transform (GimpItem               *item,
 {
   GimpItemClass *item_class;
   GimpImage     *image;
+  gboolean       push_undo;
 
   g_return_if_fail (GIMP_IS_ITEM (item));
   g_return_if_fail (gimp_item_is_attached (item));
@@ -1550,8 +1615,13 @@ gimp_item_transform (GimpItem               *item,
   item_class = GIMP_ITEM_GET_CLASS (item);
   image = gimp_item_get_image (item);
 
-  gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_TRANSFORM,
-                               item_class->transform_desc);
+  push_undo = gimp_item_is_attached (item);
+
+  if (push_undo)
+    gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_TRANSFORM,
+                                 item_class->transform_desc);
+
+  gimp_item_start_move (item, push_undo);
 
   g_object_freeze_notify (G_OBJECT (item));
 
@@ -1560,7 +1630,10 @@ gimp_item_transform (GimpItem               *item,
 
   g_object_thaw_notify (G_OBJECT (item));
 
-  gimp_image_undo_group_end (image);
+  gimp_item_end_move (item, push_undo);
+
+  if (push_undo)
+    gimp_image_undo_group_end (image);
 }
 
 gboolean
diff --git a/app/core/gimpitem.h b/app/core/gimpitem.h
index ad2d2e5..b9023cf 100644
--- a/app/core/gimpitem.h
+++ b/app/core/gimpitem.h
@@ -69,6 +69,10 @@ struct _GimpItemClass
                                           const gchar            *new_name,
                                           const gchar            *undo_desc,
                                           GError                **error);
+  void            (* start_move)         (GimpItem               *item,
+                                          gboolean                push_undo);
+  void            (* end_move)           (GimpItem               *item,
+                                          gboolean                push_undo);
   void            (* translate)          (GimpItem               *item,
                                           gint                    offset_x,
                                           gint                    offset_y,
@@ -207,6 +211,11 @@ void            gimp_item_set_offset         (GimpItem           *item,
 gint            gimp_item_get_offset_x       (GimpItem           *item);
 gint            gimp_item_get_offset_y       (GimpItem           *item);
 
+void            gimp_item_start_move         (GimpItem           *item,
+                                              gboolean            push_undo);
+void            gimp_item_end_move           (GimpItem           *item,
+                                              gboolean            push_undo);
+
 void            gimp_item_translate          (GimpItem           *item,
                                               gint                offset_x,
                                               gint                offset_y,
diff --git a/app/tools/gimpeditselectiontool.c b/app/tools/gimpeditselectiontool.c
index 245e730..36d8390 100644
--- a/app/tools/gimpeditselectiontool.c
+++ b/app/tools/gimpeditselectiontool.c
@@ -33,6 +33,7 @@
 #include "core/gimp.h"
 #include "core/gimp-utils.h"
 #include "core/gimpboundary.h"
+#include "core/gimpgrouplayer.h"
 #include "core/gimpimage.h"
 #include "core/gimpimage-guides.h"
 #include "core/gimpimage-item-list.h"
@@ -225,6 +226,7 @@ gimp_edit_selection_tool_start (GimpTool          *parent_tool,
   GimpDisplayShell      *shell;
   GimpImage             *image;
   GimpItem              *active_item;
+  GList                 *list;
   gint                   off_x, off_y;
 
   edit_select = g_object_new (GIMP_TYPE_EDIT_SELECTION_TOOL,
@@ -430,6 +432,9 @@ gimp_edit_selection_tool_start (GimpTool          *parent_tool,
         }
     }
 
+  for (list = edit_select->live_items; list; list = g_list_next (list))
+    gimp_item_start_move (GIMP_ITEM (list->data), TRUE);
+
   tool_manager_push_tool (display->gimp, tool);
 
   gimp_tool_control_activate (tool->control);
@@ -458,6 +463,7 @@ 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);
+  GList                 *list;
 
   /*  resume the current selection  */
   gimp_display_shell_selection_resume (shell);
@@ -480,6 +486,9 @@ gimp_edit_selection_tool_button_release (GimpTool              *tool,
                                   edit_select->cuml_y,
                                   TRUE);
 
+  for (list = edit_select->live_items; list; list = g_list_next (list))
+    gimp_item_end_move (GIMP_ITEM (list->data), TRUE);
+
   gimp_image_undo_group_end (image);
 
   if (release_type == GIMP_BUTTON_RELEASE_CANCEL)


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