summaryrefslogtreecommitdiffstats
path: root/app/tools/gimpperspectiveclonetool.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--app/tools/gimpperspectiveclonetool.c913
1 files changed, 913 insertions, 0 deletions
diff --git a/app/tools/gimpperspectiveclonetool.c b/app/tools/gimpperspectiveclonetool.c
new file mode 100644
index 0000000..ff57634
--- /dev/null
+++ b/app/tools/gimpperspectiveclonetool.c
@@ -0,0 +1,913 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include <gegl.h>
+#include <gtk/gtk.h>
+
+#include "libgimpmath/gimpmath.h"
+#include "libgimpwidgets/gimpwidgets.h"
+
+#include "tools-types.h"
+
+#include "core/gimp-transform-utils.h"
+#include "core/gimpimage.h"
+
+#include "paint/gimpperspectiveclone.h"
+#include "paint/gimpperspectivecloneoptions.h"
+
+#include "widgets/gimphelp-ids.h"
+#include "widgets/gimpviewablebox.h"
+#include "widgets/gimpwidgets-utils.h"
+
+#include "display/gimpcanvasgroup.h"
+#include "display/gimpdisplay.h"
+#include "display/gimptooltransformgrid.h"
+
+#include "gimpperspectiveclonetool.h"
+#include "gimpcloneoptions-gui.h"
+#include "gimptoolcontrol.h"
+
+#include "gimp-intl.h"
+
+
+/* index into trans_info array */
+enum
+{
+ X0,
+ Y0,
+ X1,
+ Y1,
+ X2,
+ Y2,
+ X3,
+ Y3,
+ PIVOT_X,
+ PIVOT_Y
+};
+
+
+static void gimp_perspective_clone_tool_constructed (GObject *object);
+
+static gboolean gimp_perspective_clone_tool_initialize (GimpTool *tool,
+ GimpDisplay *display,
+ GError **error);
+
+static gboolean gimp_perspective_clone_tool_has_display (GimpTool *tool,
+ GimpDisplay *display);
+static GimpDisplay *
+ gimp_perspective_clone_tool_has_image (GimpTool *tool,
+ GimpImage *image);
+static void gimp_perspective_clone_tool_control (GimpTool *tool,
+ GimpToolAction action,
+ GimpDisplay *display);
+static void gimp_perspective_clone_tool_button_press (GimpTool *tool,
+ const GimpCoords *coords,
+ guint32 time,
+ GdkModifierType state,
+ GimpButtonPressType press_type,
+ GimpDisplay *display);
+static void gimp_perspective_clone_tool_button_release (GimpTool *tool,
+ const GimpCoords *coords,
+ guint32 time,
+ GdkModifierType state,
+ GimpButtonReleaseType release_type,
+ GimpDisplay *display);
+static void gimp_perspective_clone_tool_motion (GimpTool *tool,
+ const GimpCoords *coords,
+ guint32 time,
+ GdkModifierType state,
+ GimpDisplay *display);
+static void gimp_perspective_clone_tool_modifier_key (GimpTool *tool,
+ GdkModifierType key,
+ gboolean press,
+ GdkModifierType state,
+ GimpDisplay *display);
+static void gimp_perspective_clone_tool_cursor_update (GimpTool *tool,
+ const GimpCoords *coords,
+ GdkModifierType state,
+ GimpDisplay *display);
+static void gimp_perspective_clone_tool_oper_update (GimpTool *tool,
+ const GimpCoords *coords,
+ GdkModifierType state,
+ gboolean proximity,
+ GimpDisplay *display);
+static void gimp_perspective_clone_tool_options_notify (GimpTool *tool,
+ GimpToolOptions *options,
+ const GParamSpec *pspec);
+
+static void gimp_perspective_clone_tool_draw (GimpDrawTool *draw_tool);
+
+static void gimp_perspective_clone_tool_halt (GimpPerspectiveCloneTool *clone_tool);
+static void gimp_perspective_clone_tool_bounds (GimpPerspectiveCloneTool *clone_tool,
+ GimpDisplay *display);
+static void gimp_perspective_clone_tool_prepare (GimpPerspectiveCloneTool *clone_tool);
+static void gimp_perspective_clone_tool_recalc_matrix (GimpPerspectiveCloneTool *clone_tool,
+ GimpToolWidget *widget);
+
+static void gimp_perspective_clone_tool_widget_changed (GimpToolWidget *widget,
+ GimpPerspectiveCloneTool *clone_tool);
+static void gimp_perspective_clone_tool_widget_status (GimpToolWidget *widget,
+ const gchar *status,
+ GimpPerspectiveCloneTool *clone_tool);
+
+static GtkWidget *
+ gimp_perspective_clone_options_gui (GimpToolOptions *tool_options);
+
+
+G_DEFINE_TYPE (GimpPerspectiveCloneTool, gimp_perspective_clone_tool,
+ GIMP_TYPE_BRUSH_TOOL)
+
+#define parent_class gimp_perspective_clone_tool_parent_class
+
+
+void
+gimp_perspective_clone_tool_register (GimpToolRegisterCallback callback,
+ gpointer data)
+{
+ (* callback) (GIMP_TYPE_PERSPECTIVE_CLONE_TOOL,
+ GIMP_TYPE_PERSPECTIVE_CLONE_OPTIONS,
+ gimp_perspective_clone_options_gui,
+ GIMP_PAINT_OPTIONS_CONTEXT_MASK |
+ GIMP_CONTEXT_PROP_MASK_PATTERN,
+ "gimp-perspective-clone-tool",
+ _("Perspective Clone"),
+ _("Perspective Clone Tool: Clone from an image source "
+ "after applying a perspective transformation"),
+ N_("_Perspective Clone"), NULL,
+ NULL, GIMP_HELP_TOOL_PERSPECTIVE_CLONE,
+ GIMP_ICON_TOOL_PERSPECTIVE_CLONE,
+ data);
+}
+
+static void
+gimp_perspective_clone_tool_class_init (GimpPerspectiveCloneToolClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GimpToolClass *tool_class = GIMP_TOOL_CLASS (klass);
+ GimpDrawToolClass *draw_tool_class = GIMP_DRAW_TOOL_CLASS (klass);
+
+ object_class->constructed = gimp_perspective_clone_tool_constructed;
+
+ tool_class->initialize = gimp_perspective_clone_tool_initialize;
+ tool_class->has_display = gimp_perspective_clone_tool_has_display;
+ tool_class->has_image = gimp_perspective_clone_tool_has_image;
+ tool_class->control = gimp_perspective_clone_tool_control;
+ tool_class->button_press = gimp_perspective_clone_tool_button_press;
+ tool_class->button_release = gimp_perspective_clone_tool_button_release;
+ tool_class->motion = gimp_perspective_clone_tool_motion;
+ tool_class->modifier_key = gimp_perspective_clone_tool_modifier_key;
+ tool_class->cursor_update = gimp_perspective_clone_tool_cursor_update;
+ tool_class->oper_update = gimp_perspective_clone_tool_oper_update;
+ tool_class->options_notify = gimp_perspective_clone_tool_options_notify;
+
+ draw_tool_class->draw = gimp_perspective_clone_tool_draw;
+}
+
+static void
+gimp_perspective_clone_tool_init (GimpPerspectiveCloneTool *clone_tool)
+{
+ GimpTool *tool = GIMP_TOOL (clone_tool);
+
+ gimp_tool_control_set_action_object_2 (tool->control,
+ "context/context-pattern-select-set");
+
+ gimp_matrix3_identity (&clone_tool->transform);
+}
+
+static void
+gimp_perspective_clone_tool_constructed (GObject *object)
+{
+ GimpPerspectiveCloneOptions *options;
+
+ options = GIMP_PERSPECTIVE_CLONE_TOOL_GET_OPTIONS (object);
+
+ G_OBJECT_CLASS (parent_class)->constructed (object);
+
+ if (options->clone_mode == GIMP_PERSPECTIVE_CLONE_MODE_ADJUST)
+ gimp_paint_tool_set_active (GIMP_PAINT_TOOL (object), FALSE);
+}
+
+static gboolean
+gimp_perspective_clone_tool_initialize (GimpTool *tool,
+ GimpDisplay *display,
+ GError **error)
+{
+ GimpPerspectiveCloneTool *clone_tool = GIMP_PERSPECTIVE_CLONE_TOOL (tool);
+
+ if (! GIMP_TOOL_CLASS (parent_class)->initialize (tool, display, error))
+ {
+ return FALSE;
+ }
+
+ if (display != tool->display)
+ {
+ GimpDisplayShell *shell = gimp_display_get_shell (display);
+ GimpImage *image = gimp_display_get_image (display);
+ gint i;
+
+ tool->display = display;
+ tool->drawable = gimp_image_get_active_drawable (image);
+
+ /* Find the transform bounds initializing */
+ gimp_perspective_clone_tool_bounds (clone_tool, display);
+
+ gimp_perspective_clone_tool_prepare (clone_tool);
+
+ /* Recalculate the transform tool */
+ gimp_perspective_clone_tool_recalc_matrix (clone_tool, NULL);
+
+ clone_tool->widget =
+ gimp_tool_transform_grid_new (shell,
+ &clone_tool->transform,
+ clone_tool->x1,
+ clone_tool->y1,
+ clone_tool->x2,
+ clone_tool->y2);
+
+ g_object_set (clone_tool->widget,
+ "pivot-x", (clone_tool->x1 + clone_tool->x2) / 2.0,
+ "pivot-y", (clone_tool->y1 + clone_tool->y2) / 2.0,
+ "inside-function", GIMP_TRANSFORM_FUNCTION_MOVE,
+ "outside-function", GIMP_TRANSFORM_FUNCTION_ROTATE,
+ "use-corner-handles", TRUE,
+ "use-perspective-handles", TRUE,
+ "use-side-handles", TRUE,
+ "use-shear-handles", TRUE,
+ "use-pivot-handle", TRUE,
+ NULL);
+
+ g_signal_connect (clone_tool->widget, "changed",
+ G_CALLBACK (gimp_perspective_clone_tool_widget_changed),
+ clone_tool);
+ g_signal_connect (clone_tool->widget, "status",
+ G_CALLBACK (gimp_perspective_clone_tool_widget_status),
+ clone_tool);
+
+ /* start drawing the bounding box and handles... */
+ if (gimp_draw_tool_is_active (GIMP_DRAW_TOOL (tool)))
+ gimp_draw_tool_stop (GIMP_DRAW_TOOL (tool));
+
+ gimp_draw_tool_start (GIMP_DRAW_TOOL (tool), display);
+
+ /* Save the current transformation info */
+ for (i = 0; i < TRANS_INFO_SIZE; i++)
+ clone_tool->old_trans_info[i] = clone_tool->trans_info[i];
+ }
+
+ return TRUE;
+}
+
+static gboolean
+gimp_perspective_clone_tool_has_display (GimpTool *tool,
+ GimpDisplay *display)
+{
+ GimpPerspectiveCloneTool *clone_tool = GIMP_PERSPECTIVE_CLONE_TOOL (tool);
+
+ return (display == clone_tool->src_display ||
+ GIMP_TOOL_CLASS (parent_class)->has_display (tool, display));
+}
+
+static GimpDisplay *
+gimp_perspective_clone_tool_has_image (GimpTool *tool,
+ GimpImage *image)
+{
+ GimpPerspectiveCloneTool *clone_tool = GIMP_PERSPECTIVE_CLONE_TOOL (tool);
+ GimpDisplay *display;
+
+ display = GIMP_TOOL_CLASS (parent_class)->has_image (tool, image);
+
+ if (! display && clone_tool->src_display)
+ {
+ if (image && gimp_display_get_image (clone_tool->src_display) == image)
+ display = clone_tool->src_display;
+
+ /* NULL image means any display */
+ if (! image)
+ display = clone_tool->src_display;
+ }
+
+ return display;
+}
+
+static void
+gimp_perspective_clone_tool_control (GimpTool *tool,
+ GimpToolAction action,
+ GimpDisplay *display)
+{
+ GimpPerspectiveCloneTool *clone_tool = GIMP_PERSPECTIVE_CLONE_TOOL (tool);
+
+ switch (action)
+ {
+ case GIMP_TOOL_ACTION_PAUSE:
+ case GIMP_TOOL_ACTION_RESUME:
+ break;
+
+ case GIMP_TOOL_ACTION_HALT:
+ gimp_perspective_clone_tool_halt (clone_tool);
+ break;
+
+ case GIMP_TOOL_ACTION_COMMIT:
+ break;
+ }
+
+ GIMP_TOOL_CLASS (parent_class)->control (tool, action, display);
+}
+
+static void
+gimp_perspective_clone_tool_button_press (GimpTool *tool,
+ const GimpCoords *coords,
+ guint32 time,
+ GdkModifierType state,
+ GimpButtonPressType press_type,
+ GimpDisplay *display)
+{
+ GimpPaintTool *paint_tool = GIMP_PAINT_TOOL (tool);
+ GimpPerspectiveCloneTool *clone_tool = GIMP_PERSPECTIVE_CLONE_TOOL (tool);
+ GimpPerspectiveClone *clone = GIMP_PERSPECTIVE_CLONE (paint_tool->core);
+ GimpSourceCore *source_core = GIMP_SOURCE_CORE (clone);
+ GimpPerspectiveCloneOptions *options;
+
+ options = GIMP_PERSPECTIVE_CLONE_TOOL_GET_OPTIONS (tool);
+
+ if (options->clone_mode == GIMP_PERSPECTIVE_CLONE_MODE_ADJUST)
+ {
+ if (clone_tool->widget)
+ {
+ gimp_tool_widget_hover (clone_tool->widget, coords, state, TRUE);
+
+ if (gimp_tool_widget_button_press (clone_tool->widget, coords,
+ time, state, press_type))
+ {
+ clone_tool->grab_widget = clone_tool->widget;
+ }
+ }
+
+ gimp_tool_control_activate (tool->control);
+ }
+ else
+ {
+ GdkModifierType extend_mask = gimp_get_extend_selection_mask ();
+ GdkModifierType toggle_mask = gimp_get_toggle_behavior_mask ();
+ gdouble nnx, nny;
+
+ gimp_draw_tool_pause (GIMP_DRAW_TOOL (tool));
+
+ if ((state & (toggle_mask | extend_mask)) == toggle_mask)
+ {
+ source_core->set_source = TRUE;
+
+ clone_tool->src_display = display;
+ }
+ else
+ {
+ source_core->set_source = FALSE;
+ }
+
+ GIMP_TOOL_CLASS (parent_class)->button_press (tool, coords, time, state,
+ press_type, display);
+
+ /* Set the coordinates for the reference cross */
+ gimp_perspective_clone_get_source_point (clone,
+ coords->x, coords->y,
+ &nnx, &nny);
+
+ clone_tool->src_x = floor (nnx);
+ clone_tool->src_y = floor (nny);
+
+ gimp_draw_tool_resume (GIMP_DRAW_TOOL (tool));
+ }
+}
+
+static void
+gimp_perspective_clone_tool_button_release (GimpTool *tool,
+ const GimpCoords *coords,
+ guint32 time,
+ GdkModifierType state,
+ GimpButtonReleaseType release_type,
+ GimpDisplay *display)
+{
+ GimpPerspectiveCloneTool *clone_tool = GIMP_PERSPECTIVE_CLONE_TOOL (tool);
+ GimpPerspectiveCloneOptions *options;
+
+ options = GIMP_PERSPECTIVE_CLONE_TOOL_GET_OPTIONS (tool);
+
+ switch (options->clone_mode)
+ {
+ case GIMP_PERSPECTIVE_CLONE_MODE_ADJUST:
+ gimp_tool_control_halt (tool->control);
+
+ if (clone_tool->grab_widget)
+ {
+ gimp_tool_widget_button_release (clone_tool->grab_widget,
+ coords, time, state, release_type);
+ clone_tool->grab_widget = NULL;
+ }
+ break;
+
+ case GIMP_PERSPECTIVE_CLONE_MODE_PAINT:
+ GIMP_TOOL_CLASS (parent_class)->button_release (tool, coords, time, state,
+ release_type, display);
+ break;
+ }
+}
+
+static void
+gimp_perspective_clone_tool_motion (GimpTool *tool,
+ const GimpCoords *coords,
+ guint32 time,
+ GdkModifierType state,
+ GimpDisplay *display)
+{
+ GimpPerspectiveCloneTool *clone_tool = GIMP_PERSPECTIVE_CLONE_TOOL (tool);
+ GimpPaintTool *paint_tool = GIMP_PAINT_TOOL (tool);
+ GimpPerspectiveClone *clone = GIMP_PERSPECTIVE_CLONE (paint_tool->core);
+ GimpPerspectiveCloneOptions *options;
+
+ options = GIMP_PERSPECTIVE_CLONE_TOOL_GET_OPTIONS (tool);
+
+ if (options->clone_mode == GIMP_PERSPECTIVE_CLONE_MODE_ADJUST)
+ {
+ if (clone_tool->grab_widget)
+ {
+ gimp_tool_widget_motion (clone_tool->grab_widget, coords, time, state);
+ }
+ }
+ else if (options->clone_mode == GIMP_PERSPECTIVE_CLONE_MODE_PAINT)
+ {
+ gdouble nnx, nny;
+
+ gimp_draw_tool_pause (GIMP_DRAW_TOOL (tool));
+
+ GIMP_TOOL_CLASS (parent_class)->motion (tool, coords, time, state,
+ display);
+
+ /* Set the coordinates for the reference cross */
+ gimp_perspective_clone_get_source_point (clone,
+ coords->x, coords->y,
+ &nnx, &nny);
+
+ clone_tool->src_x = floor (nnx);
+ clone_tool->src_y = floor (nny);
+
+ gimp_draw_tool_resume (GIMP_DRAW_TOOL (tool));
+ }
+}
+
+static void
+gimp_perspective_clone_tool_modifier_key (GimpTool *tool,
+ GdkModifierType key,
+ gboolean press,
+ GdkModifierType state,
+ GimpDisplay *display)
+{
+ GimpPerspectiveCloneTool *clone_tool = GIMP_PERSPECTIVE_CLONE_TOOL (tool);
+ GimpPerspectiveCloneOptions *options;
+
+ options = GIMP_PERSPECTIVE_CLONE_TOOL_GET_OPTIONS (tool);
+
+ if (options->clone_mode == GIMP_PERSPECTIVE_CLONE_MODE_PAINT &&
+ key == gimp_get_toggle_behavior_mask ())
+ {
+ if (press)
+ {
+ clone_tool->saved_precision =
+ gimp_tool_control_get_precision (tool->control);
+ gimp_tool_control_set_precision (tool->control,
+ GIMP_CURSOR_PRECISION_PIXEL_CENTER);
+ }
+ else
+ {
+ gimp_tool_control_set_precision (tool->control,
+ clone_tool->saved_precision);
+ }
+ }
+
+ GIMP_TOOL_CLASS (parent_class)->modifier_key (tool, key, press, state,
+ display);
+}
+
+static void
+gimp_perspective_clone_tool_cursor_update (GimpTool *tool,
+ const GimpCoords *coords,
+ GdkModifierType state,
+ GimpDisplay *display)
+{
+ GimpPerspectiveCloneTool *clone_tool = GIMP_PERSPECTIVE_CLONE_TOOL (tool);
+ GimpPerspectiveCloneOptions *options;
+ GimpImage *image;
+ GimpToolClass *tool_class;
+ GimpCursorType cursor = GIMP_CURSOR_MOUSE;
+ GimpToolCursorType tool_cursor = GIMP_TOOL_CURSOR_NONE;
+ GimpCursorModifier modifier = GIMP_CURSOR_MODIFIER_NONE;
+
+ options = GIMP_PERSPECTIVE_CLONE_TOOL_GET_OPTIONS (tool);
+
+ image = gimp_display_get_image (display);
+
+ if (gimp_image_coords_in_active_pickable (image, coords,
+ FALSE, FALSE, TRUE))
+ {
+ cursor = GIMP_CURSOR_MOUSE;
+ }
+
+ if (options->clone_mode == GIMP_PERSPECTIVE_CLONE_MODE_ADJUST)
+ {
+ if (clone_tool->widget)
+ {
+ if (display == tool->display)
+ {
+ gimp_tool_widget_get_cursor (clone_tool->widget,
+ coords, state,
+ &cursor, &tool_cursor, &modifier);
+ }
+ }
+ }
+ else
+ {
+ GdkModifierType extend_mask = gimp_get_extend_selection_mask ();
+ GdkModifierType toggle_mask = gimp_get_toggle_behavior_mask ();
+
+ if ((state & (toggle_mask | extend_mask)) == toggle_mask)
+ {
+ cursor = GIMP_CURSOR_CROSSHAIR_SMALL;
+ }
+ else if (! GIMP_SOURCE_CORE (GIMP_PAINT_TOOL (tool)->core)->src_drawable)
+ {
+ modifier = GIMP_CURSOR_MODIFIER_BAD;
+ }
+
+ tool_cursor = GIMP_TOOL_CURSOR_CLONE;
+ }
+
+ gimp_tool_control_set_cursor (tool->control, cursor);
+ gimp_tool_control_set_tool_cursor (tool->control, tool_cursor);
+ gimp_tool_control_set_cursor_modifier (tool->control, modifier);
+
+ /* If we are in adjust mode, skip the GimpBrushClass when chaining up.
+ * This ensures that the cursor will be set regardless of
+ * GimpBrushTool::show_cursor (see bug #354933).
+ */
+ if (options->clone_mode == GIMP_PERSPECTIVE_CLONE_MODE_ADJUST)
+ tool_class = GIMP_TOOL_CLASS (g_type_class_peek_parent (parent_class));
+ else
+ tool_class = GIMP_TOOL_CLASS (parent_class);
+
+ tool_class->cursor_update (tool, coords, state, display);
+}
+
+static void
+gimp_perspective_clone_tool_oper_update (GimpTool *tool,
+ const GimpCoords *coords,
+ GdkModifierType state,
+ gboolean proximity,
+ GimpDisplay *display)
+{
+ GimpPerspectiveCloneTool *clone_tool = GIMP_PERSPECTIVE_CLONE_TOOL (tool);
+ GimpPerspectiveCloneOptions *options;
+
+ options = GIMP_PERSPECTIVE_CLONE_TOOL_GET_OPTIONS (tool);
+
+ if (options->clone_mode == GIMP_PERSPECTIVE_CLONE_MODE_ADJUST)
+ {
+ if (clone_tool->widget)
+ {
+ if (display == tool->display)
+ {
+ gimp_tool_widget_hover (clone_tool->widget, coords, state,
+ proximity);
+ }
+ }
+ }
+ else
+ {
+ GIMP_TOOL_CLASS (parent_class)->oper_update (tool, coords, state,
+ proximity, display);
+
+ if (proximity)
+ {
+ GimpPaintCore *core = GIMP_PAINT_TOOL (tool)->core;
+ GimpPerspectiveClone *clone = GIMP_PERSPECTIVE_CLONE (core);
+ GimpSourceCore *source_core = GIMP_SOURCE_CORE (core);
+
+ if (source_core->src_drawable == NULL)
+ {
+ gimp_tool_replace_status (tool, display,
+ _("Ctrl-Click to set a clone source"));
+ }
+ else
+ {
+ gimp_draw_tool_pause (GIMP_DRAW_TOOL (tool));
+
+ clone_tool->src_x = source_core->src_x;
+ clone_tool->src_y = source_core->src_y;
+
+ if (! source_core->first_stroke)
+ {
+ if (GIMP_SOURCE_OPTIONS (options)->align_mode ==
+ GIMP_SOURCE_ALIGN_YES)
+ {
+ gdouble nnx, nny;
+
+ /* Set the coordinates for the reference cross */
+ gimp_perspective_clone_get_source_point (clone,
+ coords->x,
+ coords->y,
+ &nnx, &nny);
+
+ clone_tool->src_x = floor (nnx);
+ clone_tool->src_y = floor (nny);
+ }
+ }
+
+ gimp_draw_tool_resume (GIMP_DRAW_TOOL (tool));
+ }
+ }
+ }
+}
+
+static void
+gimp_perspective_clone_tool_options_notify (GimpTool *tool,
+ GimpToolOptions *options,
+ const GParamSpec *pspec)
+{
+ GimpPerspectiveCloneTool *clone_tool = GIMP_PERSPECTIVE_CLONE_TOOL (tool);
+ GimpPaintTool *paint_tool = GIMP_PAINT_TOOL (tool);
+ GimpPerspectiveCloneOptions *clone_options;
+
+ clone_options = GIMP_PERSPECTIVE_CLONE_OPTIONS (options);
+
+ GIMP_TOOL_CLASS (parent_class)->options_notify (tool, options, pspec);
+
+ if (! strcmp (pspec->name, "clone-mode"))
+ {
+ GimpPerspectiveClone *clone;
+
+ clone = GIMP_PERSPECTIVE_CLONE (GIMP_PAINT_TOOL (tool)->core);
+
+ gimp_draw_tool_pause (GIMP_DRAW_TOOL (clone_tool));
+
+ if (clone_options->clone_mode == GIMP_PERSPECTIVE_CLONE_MODE_PAINT)
+ {
+ gimp_perspective_clone_set_transform (clone, &clone_tool->transform);
+
+ gimp_paint_tool_set_active (paint_tool, TRUE);
+ }
+ else
+ {
+ gimp_paint_tool_set_active (paint_tool, FALSE);
+
+ gimp_tool_control_set_precision (tool->control,
+ GIMP_CURSOR_PRECISION_SUBPIXEL);
+
+ /* start drawing the bounding box and handles... */
+ if (tool->display &&
+ ! gimp_draw_tool_is_active (GIMP_DRAW_TOOL (clone_tool)))
+ {
+ gimp_draw_tool_start (GIMP_DRAW_TOOL (clone_tool), tool->display);
+ }
+ }
+
+ gimp_draw_tool_resume (GIMP_DRAW_TOOL (clone_tool));
+ }
+}
+
+static void
+gimp_perspective_clone_tool_draw (GimpDrawTool *draw_tool)
+{
+ GimpTool *tool = GIMP_TOOL (draw_tool);
+ GimpPerspectiveCloneTool *clone_tool = GIMP_PERSPECTIVE_CLONE_TOOL (draw_tool);
+ GimpPerspectiveClone *clone = GIMP_PERSPECTIVE_CLONE (GIMP_PAINT_TOOL (tool)->core);
+ GimpSourceCore *source_core = GIMP_SOURCE_CORE (clone);
+ GimpPerspectiveCloneOptions *options;
+
+ options = GIMP_PERSPECTIVE_CLONE_TOOL_GET_OPTIONS (tool);
+
+ if (options->clone_mode == GIMP_PERSPECTIVE_CLONE_MODE_ADJUST)
+ {
+ if (clone_tool->widget)
+ {
+ GimpCanvasItem *item = gimp_tool_widget_get_item (clone_tool->widget);
+
+ gimp_draw_tool_add_item (draw_tool, item);
+ }
+ }
+ else
+ {
+ GimpCanvasGroup *stroke_group;
+
+ stroke_group = gimp_draw_tool_add_stroke_group (draw_tool);
+
+ /* draw the bounding box */
+ gimp_draw_tool_push_group (draw_tool, stroke_group);
+
+ gimp_draw_tool_add_line (draw_tool,
+ clone_tool->trans_info[X0],
+ clone_tool->trans_info[Y0],
+ clone_tool->trans_info[X1],
+ clone_tool->trans_info[Y1]);
+ gimp_draw_tool_add_line (draw_tool,
+ clone_tool->trans_info[X1],
+ clone_tool->trans_info[Y1],
+ clone_tool->trans_info[X3],
+ clone_tool->trans_info[Y3]);
+ gimp_draw_tool_add_line (draw_tool,
+ clone_tool->trans_info[X2],
+ clone_tool->trans_info[Y2],
+ clone_tool->trans_info[X3],
+ clone_tool->trans_info[Y3]);
+ gimp_draw_tool_add_line (draw_tool,
+ clone_tool->trans_info[X2],
+ clone_tool->trans_info[Y2],
+ clone_tool->trans_info[X0],
+ clone_tool->trans_info[Y0]);
+
+ gimp_draw_tool_pop_group (draw_tool);
+ }
+
+ if (source_core->src_drawable && clone_tool->src_display)
+ {
+ GimpDisplay *tmp_display;
+
+ tmp_display = draw_tool->display;
+ draw_tool->display = clone_tool->src_display;
+
+ gimp_draw_tool_add_handle (draw_tool,
+ GIMP_HANDLE_CROSS,
+ clone_tool->src_x + 0.5,
+ clone_tool->src_y + 0.5,
+ GIMP_TOOL_HANDLE_SIZE_CROSS,
+ GIMP_TOOL_HANDLE_SIZE_CROSS,
+ GIMP_HANDLE_ANCHOR_CENTER);
+
+ draw_tool->display = tmp_display;
+ }
+
+ GIMP_DRAW_TOOL_CLASS (parent_class)->draw (draw_tool);
+}
+
+static void
+gimp_perspective_clone_tool_halt (GimpPerspectiveCloneTool *clone_tool)
+{
+ GimpTool *tool = GIMP_TOOL (clone_tool);
+
+ clone_tool->src_display = NULL;
+
+ g_object_set (GIMP_PAINT_TOOL (tool)->core,
+ "src-drawable", NULL,
+ NULL);
+
+ if (gimp_draw_tool_is_active (GIMP_DRAW_TOOL (tool)))
+ gimp_draw_tool_stop (GIMP_DRAW_TOOL (tool));
+
+ g_clear_object (&clone_tool->widget);
+
+ tool->display = NULL;
+ tool->drawable = NULL;
+}
+
+static void
+gimp_perspective_clone_tool_bounds (GimpPerspectiveCloneTool *clone_tool,
+ GimpDisplay *display)
+{
+ GimpImage *image = gimp_display_get_image (display);
+
+ clone_tool->x1 = 0;
+ clone_tool->y1 = 0;
+ clone_tool->x2 = gimp_image_get_width (image);
+ clone_tool->y2 = gimp_image_get_height (image);
+}
+
+static void
+gimp_perspective_clone_tool_prepare (GimpPerspectiveCloneTool *clone_tool)
+{
+ clone_tool->trans_info[PIVOT_X] = (gdouble) (clone_tool->x1 + clone_tool->x2) / 2.0;
+ clone_tool->trans_info[PIVOT_Y] = (gdouble) (clone_tool->y1 + clone_tool->y2) / 2.0;
+
+ clone_tool->trans_info[X0] = clone_tool->x1;
+ clone_tool->trans_info[Y0] = clone_tool->y1;
+ clone_tool->trans_info[X1] = clone_tool->x2;
+ clone_tool->trans_info[Y1] = clone_tool->y1;
+ clone_tool->trans_info[X2] = clone_tool->x1;
+ clone_tool->trans_info[Y2] = clone_tool->y2;
+ clone_tool->trans_info[X3] = clone_tool->x2;
+ clone_tool->trans_info[Y3] = clone_tool->y2;
+}
+
+static void
+gimp_perspective_clone_tool_recalc_matrix (GimpPerspectiveCloneTool *clone_tool,
+ GimpToolWidget *widget)
+{
+ gimp_matrix3_identity (&clone_tool->transform);
+ gimp_transform_matrix_perspective (&clone_tool->transform,
+ clone_tool->x1,
+ clone_tool->y1,
+ clone_tool->x2 - clone_tool->x1,
+ clone_tool->y2 - clone_tool->y1,
+ clone_tool->trans_info[X0],
+ clone_tool->trans_info[Y0],
+ clone_tool->trans_info[X1],
+ clone_tool->trans_info[Y1],
+ clone_tool->trans_info[X2],
+ clone_tool->trans_info[Y2],
+ clone_tool->trans_info[X3],
+ clone_tool->trans_info[Y3]);
+
+ if (widget)
+ g_object_set (widget,
+ "transform", &clone_tool->transform,
+ "x1", (gdouble) clone_tool->x1,
+ "y1", (gdouble) clone_tool->y1,
+ "x2", (gdouble) clone_tool->x2,
+ "y2", (gdouble) clone_tool->y2,
+ "pivot-x", clone_tool->trans_info[PIVOT_X],
+ "pivot-y", clone_tool->trans_info[PIVOT_Y],
+ NULL);
+}
+
+static void
+gimp_perspective_clone_tool_widget_changed (GimpToolWidget *widget,
+ GimpPerspectiveCloneTool *clone_tool)
+{
+ GimpMatrix3 *transform;
+
+ g_object_get (widget,
+ "transform", &transform,
+ "pivot-x", &clone_tool->trans_info[PIVOT_X],
+ "pivot-y", &clone_tool->trans_info[PIVOT_Y],
+ NULL);
+
+ gimp_matrix3_transform_point (transform,
+ clone_tool->x1, clone_tool->y1,
+ &clone_tool->trans_info[X0],
+ &clone_tool->trans_info[Y0]);
+ gimp_matrix3_transform_point (transform,
+ clone_tool->x2, clone_tool->y1,
+ &clone_tool->trans_info[X1],
+ &clone_tool->trans_info[Y1]);
+ gimp_matrix3_transform_point (transform,
+ clone_tool->x1, clone_tool->y2,
+ &clone_tool->trans_info[X2],
+ &clone_tool->trans_info[Y2]);
+ gimp_matrix3_transform_point (transform,
+ clone_tool->x2, clone_tool->y2,
+ &clone_tool->trans_info[X3],
+ &clone_tool->trans_info[Y3]);
+
+ g_free (transform);
+
+ gimp_perspective_clone_tool_recalc_matrix (clone_tool, NULL);
+}
+
+static void
+gimp_perspective_clone_tool_widget_status (GimpToolWidget *widget,
+ const gchar *status,
+ GimpPerspectiveCloneTool *clone_tool)
+{
+ GimpTool *tool = GIMP_TOOL (clone_tool);
+
+ if (status)
+ {
+ gimp_tool_replace_status (tool, tool->display, "%s", status);
+ }
+ else
+ {
+ gimp_tool_pop_status (tool, tool->display);
+ }
+}
+
+
+/* tool options stuff */
+
+static GtkWidget *
+gimp_perspective_clone_options_gui (GimpToolOptions *tool_options)
+{
+ GObject *config = G_OBJECT (tool_options);
+ GtkWidget *vbox = gimp_clone_options_gui (tool_options);
+ GtkWidget *mode;
+
+ /* radio buttons to set if you are modifying the perspective plane
+ * or painting
+ */
+ mode = gimp_prop_enum_radio_box_new (config, "clone-mode", 0, 0);
+ gtk_box_pack_start (GTK_BOX (vbox), mode, FALSE, FALSE, 0);
+ gtk_box_reorder_child (GTK_BOX (vbox), mode, 0);
+ gtk_widget_show (mode);
+
+ return vbox;
+}