[gimp/soc-2011-seamless-clone] Rewrite most of the gui for the seamless clone tool



commit f9aef67885adaabec71e40720f6ac0256c8bee22
Author: Barak Itkin <lightningismyname gmail com>
Date:   Thu Jun 30 03:30:55 2011 +0300

    Rewrite most of the gui for the seamless clone tool
    
    It now supports live preview of the paste while moving it (dragging the mouse).
    Note that it will crash if no paste is active, and it also doesn't free the
    GimpImageMap object yet (so "the preview remains").

 app/tools/gimpseamlessclonetool.c |  415 ++++++++++++++++++++++++-------------
 app/tools/gimpseamlessclonetool.h |   32 ++-
 2 files changed, 287 insertions(+), 160 deletions(-)
---
diff --git a/app/tools/gimpseamlessclonetool.c b/app/tools/gimpseamlessclonetool.c
index 1ebaa85..9178572 100644
--- a/app/tools/gimpseamlessclonetool.c
+++ b/app/tools/gimpseamlessclonetool.c
@@ -24,6 +24,8 @@
 #include <stdlib.h>
 
 #include <gegl.h>
+#include <gegl-plugin.h>
+
 #include <gtk/gtk.h>
 #include <gdk/gdkkeysyms.h>
 
@@ -59,6 +61,8 @@
 
 #include "gimp-intl.h"
 
+#define DBG_CALL_NAME() g_print ("@@@ %s @@@\n", __func__)
+#define SEAMLESS_CLONE_LIVE_PREVIEW TRUE
 
 enum
 {
@@ -76,53 +80,72 @@ enum
   SEAMLESS_CLONE_STATE_MOTION
 };
 
+G_DEFINE_TYPE (GimpSeamlessCloneTool, gimp_seamless_clone_tool, GIMP_TYPE_DRAW_TOOL)
 
-static void       gimp_seamless_clone_tool_button_press       (GimpTool              *tool,
-                                                               const GimpCoords      *coords,
-                                                               guint32                time,
-                                                               GdkModifierType        state,
-                                                               GimpButtonPressType    press_type,
-                                                               GimpDisplay           *display);
-static void       gimp_seamless_clone_tool_button_release     (GimpTool              *tool,
-                                                               const GimpCoords      *coords,
-                                                               guint32                time,
-                                                               GdkModifierType        state,
-                                                               GimpButtonReleaseType  release_type,
-                                                               GimpDisplay           *display);
-static gboolean   gimp_seamless_clone_tool_key_press          (GimpTool              *tool,
-                                                               GdkEventKey           *kevent,
-                                                               GimpDisplay           *display);
-static void       gimp_seamless_clone_tool_motion             (GimpTool              *tool,
-                                                               const GimpCoords      *coords,
-                                                               guint32                time,
-                                                               GdkModifierType        state,
-                                                               GimpDisplay           *display);
-static void       gimp_seamless_clone_tool_cursor_update      (GimpTool              *tool,
-                                                               const GimpCoords      *coords,
-                                                               GdkModifierType        state,
-                                                               GimpDisplay           *display);
-static void       gimp_seamless_clone_tool_oper_update        (GimpTool              *tool,
-                                                               const GimpCoords      *coords,
-                                                               GdkModifierType        state,
-                                                               gboolean               proximity,
-                                                               GimpDisplay           *display);
-
-static void       gimp_seamless_clone_tool_draw               (GimpDrawTool          *draw_tool);
-
-static void       gimp_seamless_clone_tool_create_image_map   (GimpSeamlessCloneTool          *ct,
-                                                               GimpDrawable                   *drawable);
-static void       gimp_seamless_clone_tool_image_map_flush    (GimpImageMap          *image_map,
-                                                               GimpTool              *tool);
-static void       gimp_seamless_clone_tool_image_map_update   (GimpSeamlessCloneTool          *ct);
-
-static void       gimp_seamless_clone_tool_create_render_node (GimpSeamlessCloneTool          *ct);
-static void       gimp_seamless_clone_tool_render_node_update (GimpSeamlessCloneTool          *ct);
+#define parent_class gimp_seamless_clone_tool_parent_class
 
+static gboolean
+gimp_seamless_clone_tool_initialize (GimpTool              *tool,
+                                     GimpDisplay           *display,
+                                     GError               **error);
 
-G_DEFINE_TYPE (GimpSeamlessCloneTool, gimp_seamless_clone_tool, GIMP_TYPE_DRAW_TOOL)
+static void
+gimp_seamless_clone_tool_update_image_map_easy (GimpSeamlessCloneTool *sct);
 
-#define parent_class gimp_seamless_clone_tool_parent_class
+static void
+gimp_seamless_clone_tool_options_notify (GimpTool         *tool,
+                                         GimpToolOptions  *options,
+                                         const GParamSpec *pspec);
+static void
+gimp_seamless_clone_tool_button_press (GimpTool            *tool,
+                                       const GimpCoords    *coords,
+                                       guint32              time,
+                                       GdkModifierType      state,
+                                       GimpButtonPressType  press_type,
+                                       GimpDisplay         *display);
+static void
+gimp_seamless_clone_tool_motion (GimpTool         *tool,
+                                 const GimpCoords *coords,
+                                 guint32           time,
+                                 GdkModifierType   state,
+                                 GimpDisplay      *display);
 
+void
+gimp_seamless_clone_tool_button_release (GimpTool              *tool,
+                                         const GimpCoords      *coords,
+                                         guint32                time,
+                                         GdkModifierType        state,
+                                         GimpButtonReleaseType  release_type,
+                                         GimpDisplay           *display);
+
+static void
+gimp_seamless_clone_tool_cursor_update (GimpTool         *tool,
+                                        const GimpCoords *coords,
+                                        GdkModifierType   state,
+                                        GimpDisplay      *display);
+
+static void
+gimp_seamless_clone_tool_draw (GimpDrawTool *draw_tool);
+
+static void
+gimp_buffer_to_gegl_buffer_with_progress (GimpSeamlessCloneTool *sct);
+
+static void
+gimp_seamless_clone_tool_create_render_node (GimpSeamlessCloneTool *sct);
+
+static void
+gimp_seamless_clone_tool_render_node_update (GimpSeamlessCloneTool *sct);
+
+static void
+gimp_seamless_clone_tool_create_image_map (GimpSeamlessCloneTool *sct,
+                                           GimpDrawable          *drawable);
+
+static void
+gimp_seamless_clone_tool_image_map_flush (GimpImageMap *image_map,
+                                          GimpTool     *tool);
+
+static void
+gimp_seamless_clone_tool_image_map_update (GimpSeamlessCloneTool *ct);
 
 void
 gimp_seamless_clone_tool_register (GimpToolRegisterCallback  callback,
@@ -147,14 +170,27 @@ gimp_seamless_clone_tool_class_init (GimpSeamlessCloneToolClass *klass)
   GimpToolClass     *tool_class      = GIMP_TOOL_CLASS (klass);
   GimpDrawToolClass *draw_tool_class = GIMP_DRAW_TOOL_CLASS (klass);
 
-  tool_class->button_press   = gimp_seamless_clone_tool_button_press;
-  tool_class->button_release = gimp_seamless_clone_tool_button_release;
-  tool_class->key_press      = gimp_seamless_clone_tool_key_press;
-  tool_class->motion         = gimp_seamless_clone_tool_motion;
-  tool_class->cursor_update  = gimp_seamless_clone_tool_cursor_update;
-  tool_class->oper_update    = gimp_seamless_clone_tool_oper_update;
+  tool_class->initialize = gimp_seamless_clone_tool_initialize;
+
+  tool_class->options_notify  = gimp_seamless_clone_tool_options_notify;
+  tool_class->button_press    = gimp_seamless_clone_tool_button_press;
+  tool_class->button_release  = gimp_seamless_clone_tool_button_release;
+  tool_class->motion          = gimp_seamless_clone_tool_motion;
+  tool_class->cursor_update   = gimp_seamless_clone_tool_cursor_update;
 
-  draw_tool_class->draw      = gimp_seamless_clone_tool_draw;
+  draw_tool_class->draw       = gimp_seamless_clone_tool_draw;
+}
+
+#define gimp_has_pixels_on_clipboard() TRUE
+static gboolean
+gimp_seamless_clone_tool_initialize (GimpTool              *tool,
+                                     GimpDisplay           *display,
+                                     GError               **error)
+{
+  /* TODO: add a check to see if there are pixels on the clipboard */
+  if ((tool->display = display) == NULL)
+    return FALSE;
+  return TRUE;
 }
 
 static void
@@ -162,15 +198,77 @@ gimp_seamless_clone_tool_init (GimpSeamlessCloneTool *self)
 {
   GimpTool *tool = GIMP_TOOL (self);
 
-  g_print ("@@@ gimp_seamless_clone_tool_init @@@\n");
-  gimp_tool_control_set_tool_cursor (tool->control,
-                                     GIMP_TOOL_CURSOR_MOVE);
+  DBG_CALL_NAME();
+  gimp_tool_control_set_tool_cursor (tool->control, GIMP_TOOL_CURSOR_MOVE);
 
-  /* self->config          = g_object_new (GIMP_TYPE_SEAMLESS_CLONE_CONFIG, NULL); */
+  self->state           = SEAMLESS_CLONE_STATE_NOTHING;
 
   self->paste_buf       = NULL;
   self->render_node     = NULL;
   self->image_map       = NULL;
+  self->translate_op    = NULL;
+}
+
+/**
+ * gimp_seamless_clone_tool_update_image_map:
+ * @sct - an instance of the #GimpSeamlessCloneTool
+ *
+ * This function makes sure everything is set up for previewing, and then
+ * calls the preview update function
+ */
+static void
+gimp_seamless_clone_tool_update_image_map_easy (GimpSeamlessCloneTool *sct)
+{
+  DBG_CALL_NAME();
+
+  if (! sct->render_node)
+    {
+      gimp_seamless_clone_tool_create_render_node (sct);
+    }
+
+  if (! sct->image_map)
+    {
+      GimpImage    *image    = gimp_display_get_image (GIMP_TOOL(sct)->display);
+      GimpDrawable *drawable = gimp_image_get_active_drawable (image);
+
+      gimp_seamless_clone_tool_create_image_map (sct, drawable);
+    }
+
+  gimp_seamless_clone_tool_image_map_update (sct);
+}
+
+/* When one of the tool options was modified, we wish to take the following
+ * steps:
+ * 1. Update any GEGL node with information that was changed
+ * 2. Make the preview update
+ */
+static void
+gimp_seamless_clone_tool_options_notify (GimpTool         *tool,
+                                         GimpToolOptions  *options,
+                                         const GParamSpec *pspec)
+{
+  DBG_CALL_NAME();
+
+  GIMP_TOOL_CLASS (parent_class)->options_notify (tool, options, pspec);
+
+  /* If no display is open, then we don't have much to update in our case */
+  if (! tool->display)
+    return;
+
+  /* Pause the on canvas drawing while we are updating, so that there won't be
+   * any calls to the draw function with partially updated data structures */
+  gimp_draw_tool_pause (GIMP_DRAW_TOOL (tool));
+
+  /* TODO:
+   * Look at pspec->name to see which property was changed, and update the
+   * relevant data
+   */
+
+  /* Now, update the preview */
+  gimp_seamless_clone_tool_update_image_map_easy (GIMP_SEAMLESS_CLONE_TOOL (tool));
+
+  /* Allow drawing to continue */
+  gimp_draw_tool_resume (GIMP_DRAW_TOOL (tool));
 }
 
 static void
@@ -181,42 +279,39 @@ gimp_seamless_clone_tool_button_press (GimpTool            *tool,
                                        GimpButtonPressType  press_type,
                                        GimpDisplay         *display)
 {
-  GimpSeamlessCloneTool    *sct        = GIMP_SEAMLESS_CLONE_TOOL (tool);
-  GimpDisplayShell         *shell = gimp_display_get_shell (display);
-  
-  gint                      tx, ty;
-  
-  g_print ("@@@ gimp_seamless_clone_tool_button_press @@@\n");
-  gimp_display_shell_transform_xy (shell,
-                                   coords->x, coords->y,
-                                   &tx, &ty);
+  GimpSeamlessCloneTool *sct = GIMP_SEAMLESS_CLONE_TOOL (tool);
 
+  if (sct->state == SEAMLESS_CLONE_STATE_NOTHING)
+    {
+      if (! sct->render_node)
+        {
+          gimp_seamless_clone_tool_create_render_node (sct);
+        }
 
-  sct->movement_start_x = (gint) tx;
-  sct->movement_start_y = (gint) ty;
-}
+      if (! sct->image_map)
+        {
+          GimpImage    *image    = gimp_display_get_image (GIMP_TOOL(sct)->display);
+          GimpDrawable *drawable = gimp_image_get_active_drawable (image);
 
-static gboolean
-gimp_seamless_clone_tool_key_press (GimpTool    *tool,
-                                    GdkEventKey *kevent,
-                                    GimpDisplay *display)
-{
-  g_print ("@@@ gimp_seamless_clone_tool_key_press @@@\n");
-  /* GimpSeamlessCloneTool *sct = GIMP_SEAMLESS_CLONE_TOOL (tool); */
+          gimp_seamless_clone_tool_create_image_map (sct, drawable);
+        }
 
-  switch (kevent->keyval)
-    {
-    case GDK_KEY_Return:
-    case GDK_KEY_KP_Enter:
-    case GDK_KEY_ISO_Enter:
-      /* Should paste here */
-      break;
-
-    default:
-      break;
+      sct->paste_rect.x = (gint) 10;
+      sct->paste_rect.y = (gint) 10;
+
+      gimp_seamless_clone_tool_image_map_update (sct);
     }
+  //if (gimp_seamless_clone_coords_in_paste (sct,coords))
+    {
+      sct->movement_start_x = coords->x;
+      sct->movement_start_y = coords->y;
+
+      sct->state = SEAMLESS_CLONE_STATE_MOTION;
 
-  return FALSE;
+      /* In order to receive motion events from the current click, we must
+       * activate the tool control */
+      gimp_tool_control_activate (tool->control);
+    }
 }
 
 static void
@@ -227,48 +322,39 @@ gimp_seamless_clone_tool_motion (GimpTool         *tool,
                                  GimpDisplay      *display)
 {
   GimpSeamlessCloneTool    *sct     = GIMP_SEAMLESS_CLONE_TOOL (tool);
-  GimpDisplayShell         *shell   = gimp_display_get_shell (tool->display);
   
-  gint                      tx, ty;
+  DBG_CALL_NAME();
 
-  g_print ("@@@ gimp_seamless_clone_tool_motion @@@\n");
   gimp_draw_tool_pause (GIMP_DRAW_TOOL (tool));
   
-  gimp_display_shell_transform_xy (shell,
-                                   coords->x, coords->y,
-                                   &tx, &ty);
-
-  sct->cursor_x = (gint) tx;
-  sct->cursor_y = (gint) ty;
+  sct->cursor_x = coords->x;
+  sct->cursor_y = coords->y;
 
+  /* TODO:
+   * We do want live preview of our tool, during move operations. However, the
+   * preview should not be added before we make it quick enough - otherwise it
+   * would be painfully slow.
+   */
+#if SEAMLESS_CLONE_LIVE_PREVIEW
   /* Now, the paste should be positioned at
    * sct->paste_x + sct->cursor_x - sct->movement_start_x
    * sct->paste_y + sct->cursor_y - sct->movement_start_y
+   * also, we shouldn't call the easy version
    */
+  sct->paste_rect.x += (gint) (coords->x - sct->movement_start_x);
+  sct->paste_rect.y += (gint) (coords->y - sct->movement_start_y);
+  sct->movement_start_x = (gint) coords->x;
+  sct->movement_start_y = (gint) coords->y;
 
-  gimp_draw_tool_resume (GIMP_DRAW_TOOL (tool));
-}
-
-static void
-gimp_seamless_clone_tool_oper_update (GimpTool         *tool,
-                                      const GimpCoords *coords,
-                                      GdkModifierType   state,
-                                      gboolean          proximity,
-                                      GimpDisplay      *display)
-{
-  GimpSeamlessCloneTool *ct        = GIMP_SEAMLESS_CLONE_TOOL (tool);
-  GimpDrawTool *draw_tool = GIMP_DRAW_TOOL (tool);
+  if (sct->translate_op)
+    gegl_node_set (sct->translate_op, "x", (gdouble)sct->paste_rect.x, "y", (gdouble)sct->paste_rect.y, NULL);
 
-  g_print ("@@@ gimp_seamless_clone_tool_oper_update @@@\n");
-  gimp_draw_tool_pause (draw_tool);
+  gimp_seamless_clone_tool_update_image_map_easy (sct);
+#endif
 
-  ct->cursor_x        = coords->x;
-  ct->cursor_y        = coords->y;
-
-  gimp_draw_tool_resume (draw_tool);
+  gimp_draw_tool_resume (GIMP_DRAW_TOOL (tool));
 }
 
-
 void
 gimp_seamless_clone_tool_button_release (GimpTool              *tool,
                                          const GimpCoords      *coords,
@@ -277,24 +363,33 @@ gimp_seamless_clone_tool_button_release (GimpTool              *tool,
                                          GimpButtonReleaseType  release_type,
                                          GimpDisplay           *display)
 {
-  GimpSeamlessCloneTool    *ct      = GIMP_SEAMLESS_CLONE_TOOL (tool);
-  /* GimpSeamlessCloneOptions *options = GIMP_SEAMLESS_CLONE_TOOL_GET_OPTIONS (ct); */
-  g_print ("@@@ gimp_seamless_clone_tool_button_release @@@\n");
+  GimpSeamlessCloneTool    *sct      = GIMP_SEAMLESS_CLONE_TOOL (tool);
 
-  gimp_draw_tool_pause (GIMP_DRAW_TOOL (ct));
+  DBG_CALL_NAME();
 
-  gimp_tool_control_halt (tool->control);
+  gimp_draw_tool_pause (GIMP_DRAW_TOOL (sct));
 
-  if (release_type == GIMP_BUTTON_RELEASE_CANCEL)
+  if (sct->state == SEAMLESS_CLONE_STATE_MOTION)
     {
-      /* Cancelling */
+      /* Now deactivate the control to stop receiving motion events */
+      gimp_tool_control_halt (tool->control);
 
-      /* gimp_seamless_clone_config_reset_displacement (ct->config); */
-    }
-  else
-    {
-      /* Normal release */
+      if (release_type != GIMP_BUTTON_RELEASE_CANCEL)
+        {
+          sct->paste_rect.x += (gint) (coords->x - sct->movement_start_x);
+          sct->paste_rect.y += (gint) (coords->y - sct->movement_start_y);
+
+#if SEAMLESS_CLONE_LIVE_PREVIEW
+#else
+          if (sct->translate_op)
+            gegl_node_set (sct->translate_op, "x", (gdouble)sct->paste_rect.x, "y", (gdouble)sct->paste_rect.y, NULL);
+#endif
+          
+        }
 
+      gimp_seamless_clone_tool_update_image_map_easy (sct);
+
+      sct->state = SEAMLESS_CLONE_STATE_READY;
     }
 
   gimp_draw_tool_resume (GIMP_DRAW_TOOL (tool));
@@ -306,14 +401,14 @@ gimp_seamless_clone_tool_cursor_update (GimpTool         *tool,
                                         GdkModifierType   state,
                                         GimpDisplay      *display)
 {
-  /* GimpSeamlessCloneTool       *ct       = GIMP_SEAMLESS_CLONE_TOOL (tool); */
-  /* GimpSeamlessCloneOptions    *options  = GIMP_SEAMLESS_CLONE_TOOL_GET_OPTIONS (ct); */
-  GimpCursorModifier  modifier = GIMP_CURSOR_MODIFIER_MOVE;
-  /* See app/widgets/widgets-enums.h */
+  GimpSeamlessCloneTool    *sct      = GIMP_SEAMLESS_CLONE_TOOL (tool);
 
-  g_print ("@@@ gimp_seamless_clone_tool_cursor_update @@@\n");
+  DBG_CALL_NAME();
 
-  gimp_tool_control_set_cursor_modifier (tool->control, modifier);
+  if (gimp_seamless_clone_coords_in_paste (sct,coords))
+    gimp_tool_control_set_cursor_modifier (tool->control, GIMP_CURSOR_MODIFIER_NONE);
+  else
+    gimp_tool_control_set_cursor_modifier (tool->control, GIMP_CURSOR_MODIFIER_MOVE);
 
   GIMP_TOOL_CLASS (parent_class)->cursor_update (tool, coords, state, display);
 }
@@ -321,17 +416,18 @@ gimp_seamless_clone_tool_cursor_update (GimpTool         *tool,
 static void
 gimp_seamless_clone_tool_draw (GimpDrawTool *draw_tool)
 {
-  GimpSeamlessCloneTool    *ct        = GIMP_SEAMLESS_CLONE_TOOL (draw_tool);
-  /* GimpSeamlessCloneOptions *options   = GIMP_SEAMLESS_CLONE_TOOL_GET_OPTIONS (ct); */
+  GimpSeamlessCloneTool    *sct        = GIMP_SEAMLESS_CLONE_TOOL (draw_tool);
+
   GimpCanvasGroup          *stroke_group;
 
-  g_print ("@@@ gimp_seamless_clone_tool_draw @@@\n");
+  DBG_CALL_NAME();
+
   stroke_group = gimp_draw_tool_add_stroke_group (draw_tool);
 
   gimp_draw_tool_push_group (draw_tool, stroke_group);
 
-  /* Draw a crosshair showing the middle of the pasted area */
-  gimp_draw_tool_add_crosshair (draw_tool, ct->paste_x, ct->paste_y);
+  /* Draw the corner of the paste */
+  gimp_draw_tool_add_crosshair (draw_tool, sct->paste_rect.x, sct->paste_rect.y);
 
   gimp_draw_tool_pop_group (draw_tool);
 }
@@ -349,8 +445,10 @@ gimp_buffer_to_gegl_buffer_with_progress (GimpSeamlessCloneTool *sct)
   gdouble         value;
   GimpContext    *context = & gimp_tool_get_options (GIMP_TOOL (sct)) -> parent_instance;
   GimpBuffer     *gimpbuf = context->gimp->global_buffer;
+  TileManager    *tiles;
+
+  DBG_CALL_NAME();
 
-  g_print ("@@@ gimp_buffer_to_gegl_buffer_with_progress @@@\n");
   progress = gimp_progress_start (GIMP_PROGRESS (sct),
                                   _("Saving the current clipboard"), FALSE);
 
@@ -364,7 +462,7 @@ gimp_buffer_to_gegl_buffer_with_progress (GimpSeamlessCloneTool *sct)
 
   input = gegl_node_new_child (gegl,
                                "operation", "gimp:tilemanager-source",
-                               "tile-manager", gimp_buffer_get_tiles (gimpbuf),
+                               "tile-manager", tiles = gimp_buffer_get_tiles (gimpbuf),
                                NULL);
 
   output = gegl_node_new_child (gegl,
@@ -389,6 +487,9 @@ gimp_buffer_to_gegl_buffer_with_progress (GimpSeamlessCloneTool *sct)
   gegl_processor_destroy (processor);
 
   sct->paste_buf = buffer;
+  sct->paste_rect = * gegl_buffer_get_extent (buffer);
+
+  tile_manager_unref (tiles);
 }
 
 /* The final graph would be
@@ -396,9 +497,9 @@ gimp_buffer_to_gegl_buffer_with_progress (GimpSeamlessCloneTool *sct)
  *      input   paste
  *      /  \     /
  *     /    \   /
- *    /     diff
- *   |        |
- *   |   interpolate
+ *    /     diff        input = the layer into we paste
+ *   |        |         paste = the pattern we want to seamlessly paste
+ *   |   interpolate    diff = paste - input
  *    \     /
  *     \   /
  *      add
@@ -407,8 +508,7 @@ gimp_buffer_to_gegl_buffer_with_progress (GimpSeamlessCloneTool *sct)
  *
  *
  * However, untill we have proper interpolation and meshing, we will replace it
- * by a simple blur of the layer. That's a very "rough" approximation of the
- * original algorithm
+ * by a no-op (nop).
  */
 static void
 gimp_seamless_clone_tool_create_render_node (GimpSeamlessCloneTool *sct)
@@ -418,7 +518,8 @@ gimp_seamless_clone_tool_create_render_node (GimpSeamlessCloneTool *sct)
   GeglNode        *input, *output; /* Proxy nodes*/
   GeglNode        *node; /* wraper to be returned */
 
-  g_print ("@@@ gimp_seamless_clone_tool_create_render_node @@@\n");
+  DBG_CALL_NAME();
+
   g_return_if_fail (sct->render_node == NULL);
   /* render_node is not supposed to be recreated */
 
@@ -434,9 +535,14 @@ gimp_seamless_clone_tool_create_render_node (GimpSeamlessCloneTool *sct)
                               NULL);
 
   interpolate = gegl_node_new_child (node,
-                                     "operation", "gegl:gaussian-blur",
+                                     "operation", "gegl:nop",
                                      NULL);
 
+  sct->translate_op = gegl_node_new_child (node,
+                                           "operation", "gegl:translate",
+                                           "x", 0.0, "y", 0.0,
+                                           "filter", "nearest", NULL);
+
   add = gegl_node_new_child (node,
                               "operation", "gegl:add",
                               NULL);
@@ -446,14 +552,18 @@ gimp_seamless_clone_tool_create_render_node (GimpSeamlessCloneTool *sct)
                               "buffer", sct->paste_buf,
                               NULL);
 
+  sct->paste_node = paste;
 
-  gegl_node_connect_to (input, "output",
+  gegl_node_connect_to (paste, "output",
+                        sct->translate_op, "input");
+
+  gegl_node_connect_to (sct->translate_op, "output",
                         diff, "input");
 
   gegl_node_connect_to (input, "output",
                         add, "input");
 
-  gegl_node_connect_to (paste, "output",
+  gegl_node_connect_to (input, "output",
                         diff, "aux");
 
   gegl_node_connect_to (diff, "output",
@@ -471,7 +581,7 @@ gimp_seamless_clone_tool_create_render_node (GimpSeamlessCloneTool *sct)
 static void
 gimp_seamless_clone_tool_render_node_update (GimpSeamlessCloneTool *sct)
 {
-  g_print ("@@@ gimp_seamless_clone_tool_render_node_update @@@\n");
+  DBG_CALL_NAME();
   /* For now, do nothing */
 }
 
@@ -479,7 +589,7 @@ static void
 gimp_seamless_clone_tool_create_image_map (GimpSeamlessCloneTool *sct,
                                            GimpDrawable          *drawable)
 {
-  g_print ("@@@ gimp_seamless_clone_tool_create_image_map @@@\n");
+  DBG_CALL_NAME();
   if (!sct->render_node)
     gimp_seamless_clone_tool_create_render_node (sct);
 
@@ -500,7 +610,7 @@ gimp_seamless_clone_tool_image_map_flush (GimpImageMap *image_map,
 {
   GimpImage *image = gimp_display_get_image (tool->display);
 
-  g_print ("@@@ gimp_seamless_clone_tool_image_map_flush @@@\n");
+  DBG_CALL_NAME();
   gimp_projection_flush_now (gimp_image_get_projection (image));
   gimp_display_flush_now (tool->display);
 }
@@ -516,7 +626,14 @@ gimp_seamless_clone_tool_image_map_update (GimpSeamlessCloneTool *ct)
   gint              off_x, off_y;
   GeglRectangle     visible;
 
-  g_print ("@@@ gimp_seamless_clone_tool_image_map_update @@@\n");
+  DBG_CALL_NAME();
+
+  /* TODO: get rid of this HACK */
+  // ct->paste_rect.x = ct->paste_rect.y = 0;
+  //gegl_buffer_set_extent (ct->paste_buf, &ct->paste_rect);
+  gegl_rectangle_dump (&ct->paste_rect);
+  gegl_rectangle_dump (gegl_buffer_get_extent (ct->paste_buf));
+  //gegl_node_set (ct->paste_node, "buffer", ct->paste_buf, NULL);
 
   gimp_display_shell_untransform_viewport (shell, &x, &y, &w, &h);
 
diff --git a/app/tools/gimpseamlessclonetool.h b/app/tools/gimpseamlessclonetool.h
index 8be047b..f12480c 100644
--- a/app/tools/gimpseamlessclonetool.h
+++ b/app/tools/gimpseamlessclonetool.h
@@ -38,33 +38,43 @@
 typedef struct _GimpSeamlessCloneTool      GimpSeamlessCloneTool;
 typedef struct _GimpSeamlessCloneToolClass GimpSeamlessCloneToolClass;
 
+/**
+ *
+ */
 struct _GimpSeamlessCloneTool
 {
   GimpDrawTool    parent_instance;
 
-  /* GimpSeamlessCloneConfig *config; */
+  guint           state;
 
-  gint            movement_start_x; /* Hold the initial x position */
-  gint            movement_start_y; /* Hold the initial y position */
+  gdouble         movement_start_x; /* Hold the initial x position */
+  gdouble         movement_start_y; /* Hold the initial y position */
   
-  gint            cursor_x; /* Hold the cursor x position */
-  gint            cursor_y; /* Hold the cursor y position */
-
-  gint            paste_x; /* Hold the paste x position */
-  gint            paste_y; /* Hold the paste y position */
+  gdouble         cursor_x; /* Hold the cursor x position */
+  gdouble         cursor_y; /* Hold the cursor y position */
 
+  GeglRectangle   paste_rect;
   GeglBuffer     *paste_buf;
-  GeglNode       *render_node; /* Gegl node graph to render the clone */
 
-  GimpImageMap   *image_map; /* For preview */
+  GeglNode       *render_node; /* A GEGL graph for rendering the clone operation */
+  GeglNode       *paste_node;
+  GeglNode       *translate_op;
+
+  GimpImageMap   *image_map;   /* Used for preview of the resulting drawable */
 };
 
+#define gimp_seamless_clone_coords_in_paste(sct,c)                    \
+                                                                      \
+ (((sct)->paste_rect.x <= (c)->x)                                     \
+  && ((sct)->paste_rect.x + (sct)->paste_rect.width <= (c)->x)        \
+  && ((sct)->paste_rect.y <= (c)->y)                                  \
+  && ((sct)->paste_rect.y + (sct)->paste_rect.height <= (c)->y))
+
 struct _GimpSeamlessCloneToolClass
 {
   GimpDrawToolClass parent_class;
 };
 
-
 void    gimp_seamless_clone_tool_register (GimpToolRegisterCallback  callback,
                                            gpointer                  data);
 



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