diff --git a/app/dialogs/dialogs.c b/app/dialogs/dialogs.c index 1624a8d84c..17eae74e54 100644 --- a/app/dialogs/dialogs.c +++ b/app/dialogs/dialogs.c @@ -244,6 +244,7 @@ static const GimpDialogFactoryEntry entries[] = FOREIGN ("gimp-threshold-tool-dialog", TRUE, FALSE), FOREIGN ("gimp-perspective-tool-dialog", TRUE, FALSE), FOREIGN ("gimp-unified-transform-tool-dialog", TRUE, FALSE), + FOREIGN ("gimp-handle-transform-tool-dialog", TRUE, FALSE), FOREIGN ("gimp-toolbox-color-dialog", TRUE, FALSE), FOREIGN ("gimp-gradient-editor-color-dialog", TRUE, FALSE), diff --git a/app/tools/Makefile.am b/app/tools/Makefile.am index dcdacdeff3..08186ac43a 100644 --- a/app/tools/Makefile.am +++ b/app/tools/Makefile.am @@ -96,6 +96,10 @@ libapptools_a_sources = \ gimpfuzzyselecttool.h \ gimpgegltool.c \ gimpgegltool.h \ + gimphandletransformoptions.c \ + gimphandletransformoptions.h \ + gimphandletransformtool.c \ + gimphandletransformtool.h \ gimphealtool.c \ gimphealtool.h \ gimphistogramoptions.c \ diff --git a/app/tools/gimp-tools.c b/app/tools/gimp-tools.c index 0ed25aee53..54b44fc305 100644 --- a/app/tools/gimp-tools.c +++ b/app/tools/gimp-tools.c @@ -61,6 +61,7 @@ #include "gimpforegroundselecttool.h" #include "gimpfuzzyselecttool.h" #include "gimpgegltool.h" +#include "gimphandletransformtool.h" #include "gimphealtool.h" #include "gimphuesaturationtool.h" #include "gimpinktool.h" @@ -160,6 +161,7 @@ gimp_tools_init (Gimp *gimp) gimp_cage_tool_register, gimp_flip_tool_register, gimp_perspective_tool_register, + gimp_handle_transform_tool_register, gimp_shear_tool_register, gimp_scale_tool_register, gimp_rotate_tool_register, diff --git a/app/tools/gimphandletransformoptions.c b/app/tools/gimphandletransformoptions.c new file mode 100644 index 0000000000..78ce7c6e23 --- /dev/null +++ b/app/tools/gimphandletransformoptions.c @@ -0,0 +1,201 @@ +/* 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 . + */ + +#include "config.h" + +#include +#include + +#include "libgimpconfig/gimpconfig.h" +#include "libgimpwidgets/gimpwidgets.h" + +#include "tools-types.h" + +#include "core/gimp.h" +#include "core/gimptoolinfo.h" + +#include "widgets/gimppropwidgets.h" +#include "widgets/gimpspinscale.h" +#include "widgets/gimpwidgets-utils.h" + +#include "gimphandletransformoptions.h" + +#include "gimp-intl.h" + + +enum +{ + PROP_0, + PROP_HANDLE_MODE +}; + + +static void gimp_handle_transform_options_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec); +static void gimp_handle_transform_options_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec); + + +G_DEFINE_TYPE (GimpHandleTransformOptions, gimp_handle_transform_options, + GIMP_TYPE_TRANSFORM_OPTIONS) + +#define parent_class gimp_handle_transform_options_parent_class + + +static void +gimp_handle_transform_options_class_init (GimpHandleTransformOptionsClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->set_property = gimp_handle_transform_options_set_property; + object_class->get_property = gimp_handle_transform_options_get_property; + + GIMP_CONFIG_INSTALL_PROP_ENUM (object_class, PROP_HANDLE_MODE, + "handle-mode", + N_("Handle mode"), + GIMP_TYPE_TRANSFORM_HANDLE_MODE, + GIMP_HANDLE_MODE_TRANSFORM, + GIMP_PARAM_STATIC_STRINGS); +} + +static void +gimp_handle_transform_options_init (GimpHandleTransformOptions *options) +{ +} + +static void +gimp_handle_transform_options_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + GimpHandleTransformOptions *options = GIMP_HANDLE_TRANSFORM_OPTIONS (object); + + switch (property_id) + { + case PROP_HANDLE_MODE: + options->handle_mode = g_value_get_enum (value); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +gimp_handle_transform_options_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + GimpHandleTransformOptions *options = GIMP_HANDLE_TRANSFORM_OPTIONS (object); + + switch (property_id) + { + case PROP_HANDLE_MODE: + g_value_set_enum (value, options->handle_mode); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +/** + * gimp_handle_transform_options_gui: + * @tool_options: a #GimpToolOptions + * + * Build the Transform Tool Options. + * + * Return value: a container holding the transform tool options + **/ +GtkWidget * +gimp_handle_transform_options_gui (GimpToolOptions *tool_options) +{ + GObject *config = G_OBJECT (tool_options); + GtkWidget *vbox = gimp_transform_options_gui (tool_options); + GtkWidget *frame; + GtkWidget *button; + gint i; + + frame = gimp_prop_enum_radio_frame_new (config, "handle-mode", + _("Handle mode"), 0, 0); + gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0); + gtk_widget_show (frame); + + /* add modifier to name, add tooltip */ + button = g_object_get_data (G_OBJECT (frame), "radio-button"); + + if (GTK_IS_RADIO_BUTTON (button)) + { + GSList *list = gtk_radio_button_get_group (GTK_RADIO_BUTTON (button)); + + for (i = g_slist_length (list) - 1 ; list; list = list->next, i--) + { + GdkModifierType shift = gimp_get_extend_selection_mask (); + GdkModifierType ctrl = gimp_get_constrain_behavior_mask (); + GdkModifierType modifier = 0; + gchar *tooltip = ""; + gchar *tip; + gchar *label; + + switch (i) + { + case GIMP_HANDLE_MODE_ADD_MOVE: + modifier = shift; + tooltip = "Add or move transform handles"; + break; + + case GIMP_HANDLE_MODE_REMOVE: + modifier = ctrl; + tooltip = "Remove transform handles"; + break; + + case GIMP_HANDLE_MODE_TRANSFORM: + modifier = 0; + tooltip = "Transform image by moving handles"; + break; + } + + if (modifier) + { + label = g_strdup_printf ("%s (%s)", + gtk_button_get_label (GTK_BUTTON (list->data)), + gimp_get_mod_string (modifier)); + gtk_button_set_label (GTK_BUTTON (list->data), label); + g_free (label); + + tip = g_strdup_printf ("%s (%s)", + tooltip, gimp_get_mod_string (modifier)); + gimp_help_set_help_data (list->data, tip, NULL); + g_free (tip); + } + else + { + gimp_help_set_help_data (list->data, tooltip, NULL); + } + } + } + + return vbox; +} diff --git a/app/tools/gimphandletransformoptions.h b/app/tools/gimphandletransformoptions.h new file mode 100644 index 0000000000..34077404c9 --- /dev/null +++ b/app/tools/gimphandletransformoptions.h @@ -0,0 +1,54 @@ +/* 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 . + */ + +#ifndef __GIMP_HANDLE_TRANSFORM_OPTIONS_H__ +#define __GIMP_HANDLE_TRANSFORM_OPTIONS_H__ + + +#include "gimptransformoptions.h" + + +#define GIMP_TYPE_HANDLE_TRANSFORM_OPTIONS (gimp_handle_transform_options_get_type ()) +#define GIMP_HANDLE_TRANSFORM_OPTIONS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_HANDLE_TRANSFORM_OPTIONS, GimpHandleTransformOptions)) +#define GIMP_HANDLE_TRANSFORM_OPTIONS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_HANDLE_TRANSFORM_OPTIONS, GimpHandleTransformOptionsClass)) +#define GIMP_IS_HANDLE_TRANSFORM_OPTIONS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_HANDLE_TRANSFORM_OPTIONS)) +#define GIMP_IS_HANDLE_TRANSFORM_OPTIONS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_HANDLE_TRANSFORM_OPTIONS)) +#define GIMP_HANDLE_TRANSFORM_OPTIONS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_HANDLE_TRANSFORM_OPTIONS, GimpHandleTransformOptionsClass)) + + +typedef struct _GimpHandleTransformOptions GimpHandleTransformOptions; +typedef struct _GimpHandleTransformOptionsClass GimpHandleTransformOptionsClass; + +struct _GimpHandleTransformOptions +{ + GimpTransformOptions parent_instance; + + GimpTransformHandleMode handle_mode; +}; + +struct _GimpHandleTransformOptionsClass +{ + GimpTransformOptionsClass parent_class; +}; + + +GType gimp_handle_transform_options_get_type (void) G_GNUC_CONST; + +GtkWidget * gimp_handle_transform_options_gui (GimpToolOptions *tool_options); + + +#endif /* __GIMP_HANDLE_TRANSFORM_OPTIONS_H__ */ diff --git a/app/tools/gimphandletransformtool.c b/app/tools/gimphandletransformtool.c new file mode 100644 index 0000000000..b214149c36 --- /dev/null +++ b/app/tools/gimphandletransformtool.c @@ -0,0 +1,985 @@ +/* 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 . + */ + +#include "config.h" + +#include + +#include +#include + +#include "libgimpmath/gimpmath.h" +#include "libgimpwidgets/gimpwidgets.h" + +#include "tools-types.h" + +#include "widgets/gimphelp-ids.h" +#include "widgets/gimpwidgets-utils.h" + +#include "display/gimpcanvasitem.h" +#include "display/gimpdisplay.h" +#include "display/gimptoolgui.h" + +#include "gimphandletransformoptions.h" +#include "gimphandletransformtool.h" +#include "gimptoolcontrol.h" + +#include "gimp-intl.h" + + +/* the transformation is defined by 8 points: + * + * 4 points on the original image and 4 corresponding points on the + * transformed image. The first NUM points on the transformed image + * are visible as handles. + * + * For these handles, the constants TRANSFORM_HANDLE_N, + * TRANSFORM_HANDLE_S, TRANSFORM_HANDLE_E and TRANSFORM_HANDLE_W are + * used. Actually, it makes no sense to name the handles with north, + * south, east, and west. But this way, we don't need to define even + * more enum constants. + */ + +/* index into trans_info array */ +enum +{ + X0, + Y0, + X1, + Y1, + X2, + Y2, + X3, + Y3, + OX0, + OY0, + OX1, + OY1, + OX2, + OY2, + OX3, + OY3, + NUM +}; + + +/* local function prototypes */ + +static void gimp_handle_transform_tool_button_press (GimpTool *tool, + const GimpCoords *coords, + guint32 time, + GdkModifierType state, + GimpButtonPressType press_type, + GimpDisplay *display); +static void gimp_handle_transform_tool_button_release (GimpTool *tool, + const GimpCoords *coords, + guint32 time, + GdkModifierType state, + GimpButtonReleaseType release_type, + GimpDisplay *display); +static void gimp_handle_transform_tool_modifier_key (GimpTool *tool, + GdkModifierType key, + gboolean press, + GdkModifierType state, + GimpDisplay *display); + +static void gimp_handle_transform_tool_dialog (GimpTransformTool *tr_tool); +static void gimp_handle_transform_tool_dialog_update (GimpTransformTool *tr_tool); +static void gimp_handle_transform_tool_prepare (GimpTransformTool *tr_tool); +static void gimp_handle_transform_tool_motion (GimpTransformTool *tr_tool); +static void gimp_handle_transform_tool_recalc_matrix (GimpTransformTool *tr_tool); +static gchar *gimp_handle_transform_tool_get_undo_desc (GimpTransformTool *tr_tool); +static TransformAction + gimp_handle_transform_tool_pick_function (GimpTransformTool *tr_tool, + const GimpCoords *coords, + GdkModifierType state, + GimpDisplay *display); +static void gimp_handle_transform_tool_cursor_update (GimpTransformTool *tr_tool, + GimpCursorType *cursor, + GimpCursorModifier *modifier); +static void gimp_handle_transform_tool_draw_gui (GimpTransformTool *tr_tool, + gint handle_w, + gint handle_h); + +static gboolean is_handle_position_valid (GimpTransformTool *tr_tool, + gint active_handle); +static void handle_micro_move (GimpTransformTool *tr_tool, + gint active_handle); +static inline gdouble calc_angle (gdouble ax, + gdouble ay, + gdouble bx, + gdouble by); +static inline gdouble calc_len (gdouble a, + gdouble b); +static inline gdouble calc_lineintersect_ratio (gdouble p1x, + gdouble p1y, + gdouble p2x, + gdouble p2y, + gdouble q1x, + gdouble q1y, + gdouble q2x, + gdouble q2y); +static gboolean mod_gauss (gdouble matrix[], + gdouble solution[], + gint s); + + +G_DEFINE_TYPE (GimpHandleTransformTool, gimp_handle_transform_tool, + GIMP_TYPE_TRANSFORM_TOOL) + +#define parent_class gimp_handle_transform_tool_parent_class + + +void +gimp_handle_transform_tool_register (GimpToolRegisterCallback callback, + gpointer data) +{ + (* callback) (GIMP_TYPE_HANDLE_TRANSFORM_TOOL, + GIMP_TYPE_HANDLE_TRANSFORM_OPTIONS, + gimp_handle_transform_options_gui, + GIMP_CONTEXT_BACKGROUND_MASK, + "gimp-handle-transform-tool", + _("Handle Transform"), + _("Handle Transform Tool: " + "Deform the layer, selection or path with handles"), + N_("_Handle Transform"), "H", + NULL, GIMP_HELP_TOOL_HANDLE_TRANSFORM, + GIMP_STOCK_TOOL_HANDLE_TRANSFORM, + data); +} + +static void +gimp_handle_transform_tool_class_init (GimpHandleTransformToolClass *klass) +{ + GimpToolClass *tool_class = GIMP_TOOL_CLASS (klass); + GimpTransformToolClass *trans_class = GIMP_TRANSFORM_TOOL_CLASS (klass); + + tool_class->button_press = gimp_handle_transform_tool_button_press; + tool_class->button_release = gimp_handle_transform_tool_button_release; + tool_class->modifier_key = gimp_handle_transform_tool_modifier_key; + + trans_class->dialog = gimp_handle_transform_tool_dialog; + trans_class->dialog_update = gimp_handle_transform_tool_dialog_update; + trans_class->prepare = gimp_handle_transform_tool_prepare; + trans_class->motion = gimp_handle_transform_tool_motion; + trans_class->recalc_matrix = gimp_handle_transform_tool_recalc_matrix; + trans_class->get_undo_desc = gimp_handle_transform_tool_get_undo_desc; + trans_class->pick_function = gimp_handle_transform_tool_pick_function; + trans_class->cursor_update = gimp_handle_transform_tool_cursor_update; + trans_class->draw_gui = gimp_handle_transform_tool_draw_gui; +} + +static void +gimp_handle_transform_tool_init (GimpHandleTransformTool *ht_tool) +{ + GimpTransformTool *tr_tool = GIMP_TRANSFORM_TOOL (ht_tool); + + tr_tool->progress_text = _("Handle transformation"); + tr_tool->use_grid = TRUE; + + ht_tool->saved_handle_mode = GIMP_HANDLE_MODE_TRANSFORM; +} + +static void +gimp_handle_transform_tool_button_press (GimpTool *tool, + const GimpCoords *coords, + guint32 time, + GdkModifierType state, + GimpButtonPressType press_type, + GimpDisplay *display) +{ + GimpHandleTransformTool *ht = GIMP_HANDLE_TRANSFORM_TOOL (tool); + GimpTransformTool *tr_tool = GIMP_TRANSFORM_TOOL (tool); + GimpHandleTransformOptions *options; + gint num; + gint active_handle; + + options = GIMP_HANDLE_TRANSFORM_TOOL_GET_OPTIONS (tr_tool); + + num = (gint) tr_tool->trans_info[NUM]; + active_handle = tr_tool->function - TRANSFORM_HANDLE_N; + + /* There is nothing to be done on creation */ + if (tr_tool->function == TRANSFORM_CREATING) + { + GIMP_TOOL_CLASS (parent_class)->button_press (tool, coords, time, + state, press_type, display); + return; + } + + if (options->handle_mode == GIMP_HANDLE_MODE_ADD_MOVE) + { + /* add handle */ + + if (num < 4 && tr_tool->function == TRANSFORM_HANDLE_NONE) + { + tr_tool->trans_info[X0 + 2 * num] = coords->x; + tr_tool->trans_info[Y0 + 2 * num] = coords->y; + tr_tool->function = TRANSFORM_HANDLE_N + num; + tr_tool->trans_info[NUM]++; + + /* check for valid position and calculating of OX0...OY3 is + * done on button release + */ + } + + /* move handles without changing the transformation matrix */ + ht->matrix_recalculation = FALSE; + } + else if (options->handle_mode == GIMP_HANDLE_MODE_REMOVE && + num > 0 && + active_handle >= 0 && + active_handle < 4) + { + /* remove handle */ + + gdouble tempx = tr_tool->trans_info[X0 + 2 * active_handle]; + gdouble tempy = tr_tool->trans_info[Y0 + 2 * active_handle]; + gdouble tempox = tr_tool->trans_info[OX0 + 2 * active_handle]; + gdouble tempoy = tr_tool->trans_info[OY0 + 2 * active_handle]; + gint i; + + num--; + tr_tool->trans_info[NUM]--; + + for (i = active_handle; i < num; i++) + { + tr_tool->trans_info[X0 + 2 * i] = tr_tool->trans_info[X1 + 2 * i]; + tr_tool->trans_info[Y0 + 2 * i] = tr_tool->trans_info[Y1 + 2 * i]; + tr_tool->trans_info[OX0 + 2 * i] = tr_tool->trans_info[OX1 + 2 * i]; + tr_tool->trans_info[OY0 + 2 * i] = tr_tool->trans_info[OY1 + 2 * i]; + } + + tr_tool->trans_info[X0 + 2 * num] = tempx; + tr_tool->trans_info[Y0 + 2 * num] = tempy; + tr_tool->trans_info[OX0 + 2 * num] = tempox; + tr_tool->trans_info[OY0 + 2 * num] = tempoy; + } + + GIMP_TOOL_CLASS (parent_class)->button_press (tool, coords, time, + state, press_type, display); +} + +static void +gimp_handle_transform_tool_button_release (GimpTool *tool, + const GimpCoords *coords, + guint32 time, + GdkModifierType state, + GimpButtonReleaseType release_type, + GimpDisplay *display) +{ + GimpHandleTransformTool *ht = GIMP_HANDLE_TRANSFORM_TOOL (tool); + GimpTransformTool *tr_tool = GIMP_TRANSFORM_TOOL (tool); + GimpHandleTransformOptions *options; + gint active_handle; + + options = GIMP_HANDLE_TRANSFORM_TOOL_GET_OPTIONS (tr_tool); + + active_handle = tr_tool->function - TRANSFORM_HANDLE_N; + + if (options->handle_mode == GIMP_HANDLE_MODE_ADD_MOVE && + active_handle >= 0 && + active_handle < 4) + { + GimpMatrix3 matrix; + + if (! is_handle_position_valid (tr_tool, active_handle)) + { + handle_micro_move (tr_tool, active_handle); + } + + /* handle was added or moved. calculate new original position */ + matrix = tr_tool->transform; + gimp_matrix3_invert (&matrix); + gimp_matrix3_transform_point (&matrix, + tr_tool->trans_info[X0 + 2 * active_handle], + tr_tool->trans_info[Y0 + 2 * active_handle], + &tr_tool->trans_info[OX0 + 2 * active_handle], + &tr_tool->trans_info[OY0 + 2 * active_handle]); + } + + if (release_type != GIMP_BUTTON_RELEASE_CANCEL) + { + /* force redraw */ + gimp_draw_tool_pause (GIMP_DRAW_TOOL (tool)); + gimp_draw_tool_resume (GIMP_DRAW_TOOL (tool)); + } + + ht->matrix_recalculation = TRUE; + + GIMP_TOOL_CLASS (parent_class)->button_release (tool, coords, time, + state, release_type, display); +} + +static void +gimp_handle_transform_tool_modifier_key (GimpTool *tool, + GdkModifierType key, + gboolean press, + GdkModifierType state, + GimpDisplay *display) +{ + GimpHandleTransformTool *ht_tool = GIMP_HANDLE_TRANSFORM_TOOL (tool); + GimpHandleTransformOptions *options; + GdkModifierType shift = gimp_get_extend_selection_mask (); + GdkModifierType ctrl = gimp_get_constrain_behavior_mask (); + GimpTransformHandleMode handle_mode; + + options = GIMP_HANDLE_TRANSFORM_TOOL_GET_OPTIONS (tool); + + handle_mode = options->handle_mode; + + if (press) + { + if (key == (state & (shift | ctrl))) + { + /* first modifier pressed */ + ht_tool->saved_handle_mode = options->handle_mode; + } + } + else + { + if (! (state & (shift | ctrl))) + { + /* last modifier released */ + handle_mode = ht_tool->saved_handle_mode; + } + } + + if (state & shift) + { + handle_mode = GIMP_HANDLE_MODE_ADD_MOVE; + } + else if (state & ctrl) + { + handle_mode = GIMP_HANDLE_MODE_REMOVE; + } + + if (handle_mode != options->handle_mode) + { + g_object_set (options, "handle-mode", handle_mode, NULL); + } + + GIMP_TOOL_CLASS (parent_class)->modifier_key (tool, key, press, + state, display); +} + +static void +gimp_handle_transform_tool_dialog (GimpTransformTool *tr_tool) +{ + GimpHandleTransformTool *handle_transform = GIMP_HANDLE_TRANSFORM_TOOL (tr_tool); + GtkWidget *frame; + GtkWidget *table; + gint x, y; + + frame = gimp_frame_new (_("Transformation Matrix")); + gtk_box_pack_start (GTK_BOX (gimp_tool_gui_get_vbox (tr_tool->gui)), frame, + FALSE, FALSE, 0); + gtk_widget_show (frame); + + table = gtk_table_new (3, 3, FALSE); + gtk_table_set_row_spacings (GTK_TABLE (table), 2); + gtk_table_set_col_spacings (GTK_TABLE (table), 2); + gtk_container_add (GTK_CONTAINER (frame), table); + gtk_widget_show (table); + + for (y = 0; y < 3; y++) + for (x = 0; x < 3; x++) + { + GtkWidget *label = gtk_label_new (" "); + + gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.0); + gtk_label_set_width_chars (GTK_LABEL (label), 12); + gtk_table_attach (GTK_TABLE (table), label, + x, x + 1, y, y + 1, GTK_EXPAND, GTK_FILL, 0, 0); + gtk_widget_show (label); + + handle_transform->label[y][x] = label; + } +} + +static void +gimp_handle_transform_tool_dialog_update (GimpTransformTool *tr_tool) +{ + GimpHandleTransformTool *ht_tool = GIMP_HANDLE_TRANSFORM_TOOL (tr_tool); + gint x, y; + + for (y = 0; y < 3; y++) + { + for (x = 0; x < 3; x++) + { + gchar buf[32]; + + g_snprintf (buf, sizeof (buf), + "%10.5f", tr_tool->transform.coeff[y][x]); + + gtk_label_set_text (GTK_LABEL (ht_tool->label[y][x]), buf); + } + } +} + +static void +gimp_handle_transform_tool_prepare (GimpTransformTool *tr_tool) +{ + GimpHandleTransformTool *ht_tool = GIMP_HANDLE_TRANSFORM_TOOL (tr_tool); + + tr_tool->trans_info[X0] = (gdouble) tr_tool->x1; + tr_tool->trans_info[Y0] = (gdouble) tr_tool->y1; + tr_tool->trans_info[X1] = (gdouble) tr_tool->x2; + tr_tool->trans_info[Y1] = (gdouble) tr_tool->y1; + tr_tool->trans_info[X2] = (gdouble) tr_tool->x1; + tr_tool->trans_info[Y2] = (gdouble) tr_tool->y2; + tr_tool->trans_info[X3] = (gdouble) tr_tool->x2; + tr_tool->trans_info[Y3] = (gdouble) tr_tool->y2; + tr_tool->trans_info[OX0] = (gdouble) tr_tool->x1; + tr_tool->trans_info[OY0] = (gdouble) tr_tool->y1; + tr_tool->trans_info[OX1] = (gdouble) tr_tool->x2; + tr_tool->trans_info[OY1] = (gdouble) tr_tool->y1; + tr_tool->trans_info[OX2] = (gdouble) tr_tool->x1; + tr_tool->trans_info[OY2] = (gdouble) tr_tool->y2; + tr_tool->trans_info[OX3] = (gdouble) tr_tool->x2; + tr_tool->trans_info[OY3] = (gdouble) tr_tool->y2; + tr_tool->trans_info[NUM] = 0; + + ht_tool->matrix_recalculation = TRUE; +} + +static void +gimp_handle_transform_tool_motion (GimpTransformTool *tr_tool) +{ + GimpHandleTransformOptions *options; + gint active_handle; + gint num; + + options = GIMP_HANDLE_TRANSFORM_TOOL_GET_OPTIONS (tr_tool); + + active_handle = tr_tool->function - TRANSFORM_HANDLE_N; + num = (gint) tr_tool->trans_info[NUM]; + + if (active_handle >= 0 && active_handle < 4) + { + if (options->handle_mode == GIMP_HANDLE_MODE_ADD_MOVE) + { + tr_tool->trans_info[X0 + 2*active_handle] += tr_tool->curx - tr_tool->lastx; + tr_tool->trans_info[Y0 + 2*active_handle] += tr_tool->cury - tr_tool->lasty; + /* check for valid position and calculating of OX0...OY3 is + * done on button release hopefully this makes the code run + * faster Moving could be even faster if there was caching + * for the image preview + */ + } + else if (options->handle_mode == GIMP_HANDLE_MODE_TRANSFORM) + { + gdouble angle, angle_sin, angle_cos, scale; + gdouble fixed_handles_x[3]; + gdouble fixed_handles_y[3]; + gdouble oldpos_x[4], oldpos_y[4]; + gdouble newpos_x[4], newpos_y[4]; + gint i, j; + + for (i = 0, j = 0; i < 4; i++) + { + /* Find all visible handles that are not being moved */ + if (i < num && i != active_handle) + { + fixed_handles_x[j] = tr_tool->prev_trans_info[0][X0+i*2]; + fixed_handles_y[j] = tr_tool->prev_trans_info[0][Y0+i*2]; + j++; + } + + newpos_x[i] = oldpos_x[i] = tr_tool->prev_trans_info[0][X0+i*2]; + newpos_y[i] = oldpos_y[i] = tr_tool->prev_trans_info[0][Y0+i*2]; + } + + newpos_x[active_handle] = oldpos_x[active_handle] + tr_tool->curx - tr_tool->mousex; + newpos_y[active_handle] = oldpos_y[active_handle] + tr_tool->cury - tr_tool->mousey; + + switch (num) + { + case 1: + /* move */ + for (i = 1; i < 4; i++) + { + newpos_x[i] = oldpos_x[i] + tr_tool->curx - tr_tool->mousex; + newpos_y[i] = oldpos_y[i] + tr_tool->cury - tr_tool->mousey; + } + break; + + case 2: + /* rotate and keep-aspect-scale */ + scale = calc_len (newpos_x[active_handle] - fixed_handles_x[0], + newpos_y[active_handle] - fixed_handles_y[0]) + / calc_len (oldpos_x[active_handle] - fixed_handles_x[0], + oldpos_y[active_handle] - fixed_handles_y[0]); + + angle = calc_angle (oldpos_x[active_handle] - fixed_handles_x[0], + oldpos_y[active_handle] - fixed_handles_y[0], + newpos_x[active_handle] - fixed_handles_x[0], + newpos_y[active_handle] - fixed_handles_y[0]); + + angle_sin = sin (angle); + angle_cos = cos (angle); + + for (i = 2; i < 4; i++) + { + newpos_x[i] = fixed_handles_x[0] + + scale * (angle_cos * (oldpos_x[i]-fixed_handles_x[0]) + + angle_sin * (oldpos_y[i]-fixed_handles_y[0]) ); + newpos_y[i] = fixed_handles_y[0] + + scale * (-angle_sin * (oldpos_x[i]-fixed_handles_x[0]) + + angle_cos * (oldpos_y[i]-fixed_handles_y[0]) ); + } + break; + + case 3: + /* shear and non-aspect-scale */ + scale = calc_lineintersect_ratio (oldpos_x[3], oldpos_y[3], + oldpos_x[active_handle], oldpos_y[active_handle], + fixed_handles_x[0], fixed_handles_y[0], + fixed_handles_x[1], fixed_handles_y[1]); + + newpos_x[3] = oldpos_x[3] + scale * (tr_tool->curx - tr_tool->mousex); + newpos_y[3] = oldpos_y[3] + scale * (tr_tool->cury - tr_tool->mousey); + break; + } + + for (i = 0; i < 4; i++) + { + tr_tool->trans_info[X0 + 2*i] = newpos_x[i]; + tr_tool->trans_info[Y0 + 2*i] = newpos_y[i]; + } + } + } +} + +static void +gimp_handle_transform_tool_recalc_matrix (GimpTransformTool *tr_tool) +{ + gdouble coeff[8*9]; + gdouble sol[8]; + int i; + gdouble opos_x[4], opos_y[4]; + gdouble pos_x[4], pos_y[4]; + GimpHandleTransformTool *handle_transform = GIMP_HANDLE_TRANSFORM_TOOL (tr_tool); + + if (handle_transform->matrix_recalculation) + { + for (i = 0; i < 4; i++) + { + pos_x[i] = tr_tool->trans_info[X0+i*2]; + pos_y[i] = tr_tool->trans_info[Y0+i*2]; + opos_x[i] = tr_tool->trans_info[OX0+i*2]; + opos_y[i] = tr_tool->trans_info[OY0+i*2]; + } + + for (i = 0; i < 4; i++) + { + coeff[i*9+0] = opos_x[i]; + coeff[i*9+1] = opos_y[i]; + coeff[i*9+2] = 1; + coeff[i*9+3] = 0; + coeff[i*9+4] = 0; + coeff[i*9+5] = 0; + coeff[i*9+6] = -opos_x[i]*pos_x[i]; + coeff[i*9+7] = -opos_y[i]*pos_x[i]; + coeff[i*9+8] = pos_x[i]; + + coeff[(i+4)*9+0] = 0; + coeff[(i+4)*9+1] = 0; + coeff[(i+4)*9+2] = 0; + coeff[(i+4)*9+3] = opos_x[i]; + coeff[(i+4)*9+4] = opos_y[i]; + coeff[(i+4)*9+5] = 1; + coeff[(i+4)*9+6] = -opos_x[i]*pos_y[i]; + coeff[(i+4)*9+7] = -opos_y[i]*pos_y[i]; + coeff[(i+4)*9+8] = pos_y[i]; + } + + if (mod_gauss(coeff, sol, 8)) + { + tr_tool->transform.coeff[0][0] = sol[0]; + tr_tool->transform.coeff[0][1] = sol[1]; + tr_tool->transform.coeff[0][2] = sol[2]; + tr_tool->transform.coeff[1][0] = sol[3]; + tr_tool->transform.coeff[1][1] = sol[4]; + tr_tool->transform.coeff[1][2] = sol[5]; + tr_tool->transform.coeff[2][0] = sol[6]; + tr_tool->transform.coeff[2][1] = sol[7]; + tr_tool->transform.coeff[2][2] = 1; + } + else + { + /* this should not happen + * reset the matrix so the user sees that something went wrong */ + gimp_matrix3_identity (&tr_tool->transform); + } + } +} + +static gchar * +gimp_handle_transform_tool_get_undo_desc (GimpTransformTool *tr_tool) +{ + return g_strdup (C_("undo-type", "Handle transform")); +} + +static TransformAction +gimp_handle_transform_tool_pick_function (GimpTransformTool *tr_tool, + const GimpCoords *coords, + GdkModifierType state, + GimpDisplay *display) +{ + TransformAction i; + + for (i = TRANSFORM_HANDLE_N; i < TRANSFORM_HANDLE_N + 4; i++) + { + if (tr_tool->handles[i] && + gimp_canvas_item_hit (tr_tool->handles[i], coords->x, coords->y)) + { + return i; + } + } + + return TRANSFORM_HANDLE_NONE; +} + +static void +gimp_handle_transform_tool_cursor_update (GimpTransformTool *tr_tool, + GimpCursorType *cursor, + GimpCursorModifier *modifier) +{ + GimpHandleTransformOptions *options; + GimpToolCursorType tool_cursor = GIMP_TOOL_CURSOR_NONE; + + options = GIMP_HANDLE_TRANSFORM_TOOL_GET_OPTIONS (tr_tool); + + *cursor = GIMP_CURSOR_CROSSHAIR_SMALL; + *modifier = GIMP_CURSOR_MODIFIER_NONE; + + /* do not show modifiers when the tool isn't active */ + if (! gimp_draw_tool_is_active (GIMP_DRAW_TOOL (tr_tool))) + return; + + if (options->handle_mode == GIMP_HANDLE_MODE_TRANSFORM && + tr_tool->function > TRANSFORM_HANDLE_NONE) + { + switch ((gint) tr_tool->trans_info[NUM]) + { + case 1: + tool_cursor = GIMP_TOOL_CURSOR_MOVE; + break; + case 2: + tool_cursor = GIMP_TOOL_CURSOR_ROTATE; + break; + case 3: + tool_cursor = GIMP_TOOL_CURSOR_SHEAR; + break; + case 4: + tool_cursor = GIMP_TOOL_CURSOR_PERSPECTIVE; + break; + } + } + else if (options->handle_mode == GIMP_HANDLE_MODE_ADD_MOVE) + { + if (tr_tool->function > TRANSFORM_HANDLE_NONE) + *modifier = GIMP_CURSOR_MODIFIER_MOVE; + else + *modifier = GIMP_CURSOR_MODIFIER_PLUS; + } + else if (options->handle_mode == GIMP_HANDLE_MODE_REMOVE) + { + *modifier = GIMP_CURSOR_MODIFIER_MINUS; + } + + gimp_tool_control_set_tool_cursor (GIMP_TOOL (tr_tool)->control, + tool_cursor); +} + +static void +gimp_handle_transform_tool_draw_gui (GimpTransformTool *tr_tool, + gint handle_w, + gint handle_h) +{ + GimpDrawTool *draw_tool = GIMP_DRAW_TOOL (tr_tool); + gint i; + +#if 0 + /* show additional points for debugging */ + for (i = tr_tool->trans_info[NUM]; i < 4; i++) + { + gimp_draw_tool_add_handle (draw_tool, + GIMP_HANDLE_FILLED_CIRCLE, + tr_tool->trans_info[X0+2*i], + tr_tool->trans_info[Y0+2*i], + GIMP_TOOL_HANDLE_SIZE_CIRCLE, + GIMP_TOOL_HANDLE_SIZE_CIRCLE, + GIMP_HANDLE_ANCHOR_CENTER); + gimp_draw_tool_add_handle (draw_tool, + GIMP_HANDLE_FILLED_DIAMOND, + tr_tool->trans_info[OX0+2*i], + tr_tool->trans_info[OY0+2*i], + GIMP_TOOL_HANDLE_SIZE_CIRCLE, + GIMP_TOOL_HANDLE_SIZE_CIRCLE, + GIMP_HANDLE_ANCHOR_CENTER); + } + + for (i = 0; i < tr_tool->trans_info[NUM]; i++) + { + tr_tool->handles[TRANSFORM_HANDLE_N + i] = + gimp_draw_tool_add_handle (draw_tool, + GIMP_HANDLE_DIAMOND, + tr_tool->trans_info[OX0+2*i], + tr_tool->trans_info[OY0+2*i], + GIMP_TOOL_HANDLE_SIZE_CIRCLE, + GIMP_TOOL_HANDLE_SIZE_CIRCLE, + GIMP_HANDLE_ANCHOR_CENTER); + } +#endif + + for (i = 0; i < tr_tool->trans_info[NUM]; i++) + { + tr_tool->handles[TRANSFORM_HANDLE_N + i] = + gimp_draw_tool_add_handle (draw_tool, + GIMP_HANDLE_CIRCLE, + tr_tool->trans_info[X0 + 2 * i], + tr_tool->trans_info[Y0 + 2 * i], + GIMP_TOOL_HANDLE_SIZE_CIRCLE, + GIMP_TOOL_HANDLE_SIZE_CIRCLE, + GIMP_HANDLE_ANCHOR_CENTER); + } +} + +/* check if a handle is not on the connection line of two other handles */ +static gboolean +is_handle_position_valid (GimpTransformTool *tr_tool, + gint active_handle) +{ + gint i, j, k; + + if (tr_tool->trans_info[NUM] < 3) + { + /* there aren't two other handles */ + return TRUE; + } + + if (tr_tool->trans_info[NUM] == 3) + { + return ((tr_tool->trans_info[X0] - tr_tool->trans_info[X1]) * + (tr_tool->trans_info[Y1] - tr_tool->trans_info[Y2]) != + + (tr_tool->trans_info[X1] - tr_tool->trans_info[X2]) * + (tr_tool->trans_info[Y0] - tr_tool->trans_info[Y1])); + } + + /* tr_tool->trans_info[NUM] == 4 */ + for (i = 0; i < 2; i++) + { + for (j = i + 1; j < 3; j++) + { + for (k = j + 1; i < 4; i++) + { + if (active_handle == i || + active_handle == j || + active_handle == k) + { + if ((tr_tool->trans_info[X0 + 2 * i] - + tr_tool->trans_info[X0 + 2 * j]) * + (tr_tool->trans_info[Y0 + 2 * j] - + tr_tool->trans_info[Y0 + 2 * k]) == + + (tr_tool->trans_info[X0 + 2 * j] - + tr_tool->trans_info[X0 + 2 * k]) * + (tr_tool->trans_info[Y0 + 2 * i] - + tr_tool->trans_info[Y0 + 2 * j])) + { + return FALSE; + } + } + } + } + } + + return TRUE; +} + +/* three handles on a line causes problems. + * Let's move the new handle around a bit to find a better position */ +static void +handle_micro_move (GimpTransformTool *tr_tool, + gint active_handle) +{ + gdouble posx = tr_tool->trans_info[X0 + 2 * active_handle]; + gdouble posy = tr_tool->trans_info[Y0 + 2 * active_handle]; + gdouble dx, dy; + + for (dx = -0.1; dx < 0.11; dx += 0.1) + { + tr_tool->trans_info[X0 + 2 * active_handle] = posx + dx; + + for (dy = -0.1; dy < 0.11; dy += 0.1) + { + tr_tool->trans_info[Y0 + 2 * active_handle] = posy + dy; + + if (is_handle_position_valid (tr_tool, active_handle)) + { + return; + } + } + } +} + +/* finds the clockwise angle between the vectors given, 0-2π */ +static inline gdouble +calc_angle (gdouble ax, + gdouble ay, + gdouble bx, + gdouble by) +{ + gdouble angle; + gdouble direction; + gdouble length = sqrt ((ax * ax + ay * ay) * (bx * bx + by * by)); + + angle = acos ((ax * bx + ay * by) / length); + direction = ax * by - ay * bx; + + return ((direction < 0) ? angle : 2 * G_PI - angle); +} + +static inline gdouble +calc_len (gdouble a, + gdouble b) +{ + return sqrt (a * a + b * b); +} + + +/* imagine two lines, one through the points p1 and p2, the other one + * through the points q1 and q2. Find the intersection point r. + * Calculate (distance p1 to r)/(distance p2 to r) + */ +static inline gdouble +calc_lineintersect_ratio (gdouble p1x, gdouble p1y, + gdouble p2x, gdouble p2y, + gdouble q1x, gdouble q1y, + gdouble q2x, gdouble q2y) +{ + gdouble denom, u; + + denom = (q2y - q1y) * (p2x - p1x) - (q2x - q1x) * (p2y - p1y); + if (denom == 0.0) + { + /* u is infinite, so u/(u-1) is 1 */ + return 1.0; + } + + u = (q2y - q1y) * (q1x - p1x) - (q1y - p1y) * (q2x - q1x); + u /= denom; + + return u / (u - 1); +} + + +/* modified gaussian algorithm + * solves a system of linear equations + * + * Example: + * 1x + 2y + 4z = 25 + * 2x + 1y = 4 + * 3x + 5y + 2z = 23 + * Solution: x=1, y=2, z=5 + * + * Input: + * matrix = { 1,2,4,25,2,1,0,4,3,5,2,23 } + * s = 3 (Number of variables) + * Output: + * return value == TRUE (TRUE, if there is a single unique solution) + * solution == { 1,2,5 } (if the return value is FALSE, the content + * of solution is of no use) + */ +static gboolean +mod_gauss (gdouble matrix[], + gdouble solution[], + gint s) +{ + gint p[s]; /* row permutation */ + gint i, j, r, temp; + gdouble q; + gint t = s + 1; + + for (i = 0; i < s; i++) + { + p[i] = i; + } + + for (r = 0; r < s; r++) + { + /* make sure that (r,r) is not 0 */ + if (matrix[p[r] * t + r] == 0.0) + { + /* we need to permutate rows */ + for (i = r + 1; i <= s; i++) + { + if (i == s) + { + /* if this happens, the linear system has zero or + * more than one solutions. + */ + return FALSE; + } + + if (matrix[p[i] * t + r] != 0.0) + break; + } + + temp = p[r]; + p[r] = p[i]; + p[i] = temp; + } + + /* make (r,r) == 1 */ + q = 1.0 / matrix[p[r] * t + r]; + matrix[p[r] * t + r] = 1.0; + + for (j = r + 1; j < t; j++) + { + matrix[p[r] * t + j] *= q; + } + + /* make that all entries in column r are 0 (except (r,r)) */ + for (i = 0; i < s; i++) + { + if (i == r) + continue; + + for (j = r + 1; j < t ; j++) + { + matrix[p[i] * t + j] -= matrix[p[r] * t + j] * matrix[p[i] * t + r]; + } + + /* we don't need to execute the following line + * since we won't access this element again: + * + * matrix[p[i] * t + r] = 0.0; + */ + } + } + + for (i = 0; i < s; i++) + { + solution[i] = matrix[p[i] * t + s]; + } + + return TRUE; +} diff --git a/app/tools/gimphandletransformtool.h b/app/tools/gimphandletransformtool.h new file mode 100644 index 0000000000..df6157efbf --- /dev/null +++ b/app/tools/gimphandletransformtool.h @@ -0,0 +1,60 @@ +/* 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 . + */ + +#ifndef __GIMP_HANDLE_TRANSFORM_TOOL_H__ +#define __GIMP_HANDLE_TRANSFORM_TOOL_H__ + + +#include "gimptransformtool.h" + + +#define GIMP_TYPE_HANDLE_TRANSFORM_TOOL (gimp_handle_transform_tool_get_type ()) +#define GIMP_HANDLE_TRANSFORM_TOOL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_HANDLE_TRANSFORM_TOOL, GimpHandleTransformTool)) +#define GIMP_HANDLE_TRANSFORM_TOOL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_HANDLE_TRANSFORM_TOOL, GimpHandleTransformToolClass)) +#define GIMP_IS_HANDLE_TRANSFORM_TOOL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_HANDLE_TRANSFORM_TOOL)) +#define GIMP_IS_HANDLE_TRANSFORM_TOOL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_HANDLE_TRANSFORM_TOOL)) +#define GIMP_HANDLE_TRANSFORM_TOOL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_HANDLE_TRANSFORM_TOOL, GimpHandleTransformToolClass)) + +#define GIMP_HANDLE_TRANSFORM_TOOL_GET_OPTIONS(t) (GIMP_HANDLE_TRANSFORM_OPTIONS (gimp_tool_get_options (GIMP_TOOL (t)))) + + +typedef struct _GimpHandleTransformTool GimpHandleTransformTool; +typedef struct _GimpHandleTransformToolClass GimpHandleTransformToolClass; + +struct _GimpHandleTransformTool +{ + GimpTransformTool parent_instance; + + GtkWidget *label[3][3]; + gboolean matrix_recalculation; + + GimpTransformHandleMode saved_handle_mode; +}; + +struct _GimpHandleTransformToolClass +{ + GimpTransformToolClass parent_class; +}; + + +void gimp_handle_transform_tool_register (GimpToolRegisterCallback callback, + gpointer data); + +GType gimp_handle_transform_tool_get_type (void) G_GNUC_CONST; + + +#endif /* __GIMP_HANDLE_TRANSFORM_TOOL_H__ */ diff --git a/app/tools/gimptransformtool.c b/app/tools/gimptransformtool.c index 885cc4d95b..34fcc1e524 100644 --- a/app/tools/gimptransformtool.c +++ b/app/tools/gimptransformtool.c @@ -59,6 +59,7 @@ #include "display/gimptoolgui.h" #include "gimptoolcontrol.h" +#include "gimphandletransformtool.h" #include "gimpperspectivetool.h" #include "gimpunifiedtransformtool.h" #include "gimptransformoptions.h" @@ -1088,10 +1089,15 @@ gimp_transform_tool_draw (GimpDrawTool *draw_tool) if (gimp_transform_options_show_preview (options)) { GimpMatrix3 matrix = tr_tool->transform; + gboolean perspective; if (options->direction == GIMP_TRANSFORM_BACKWARD) gimp_matrix3_invert (&matrix); + perspective = (GIMP_IS_PERSPECTIVE_TOOL (tr_tool) || + GIMP_IS_HANDLE_TRANSFORM_TOOL (tr_tool) || + GIMP_IS_UNIFIED_TRANSFORM_TOOL (tr_tool)); + gimp_draw_tool_add_transform_preview (draw_tool, tool->drawable, &matrix, @@ -1099,8 +1105,7 @@ gimp_transform_tool_draw (GimpDrawTool *draw_tool) tr_tool->y1, tr_tool->x2, tr_tool->y2, - GIMP_IS_PERSPECTIVE_TOOL (tr_tool) || - GIMP_IS_UNIFIED_TRANSFORM_TOOL (tr_tool), + perspective, options->preview_opacity); } diff --git a/app/tools/gimptransformtool.h b/app/tools/gimptransformtool.h index 2ee4634017..4ef6591fd2 100644 --- a/app/tools/gimptransformtool.h +++ b/app/tools/gimptransformtool.h @@ -54,7 +54,7 @@ typedef enum * of the enums at the top of each transformation tool, stored in * trans_info and related */ -#define TRANS_INFO_SIZE 10 +#define TRANS_INFO_SIZE 17 typedef gdouble TransInfo[TRANS_INFO_SIZE]; diff --git a/app/tools/tools-enums.c b/app/tools/tools-enums.c index 61155c7227..77b5fb8087 100644 --- a/app/tools/tools-enums.c +++ b/app/tools/tools-enums.c @@ -73,6 +73,37 @@ gimp_button_release_type_get_type (void) return type; } +GType +gimp_transform_handle_mode_get_type (void) +{ + static const GEnumValue values[] = + { + { GIMP_HANDLE_MODE_ADD_MOVE, "GIMP_HANDLE_MODE_ADD_MOVE", "add-move" }, + { GIMP_HANDLE_MODE_REMOVE, "GIMP_HANDLE_MODE_REMOVE", "remove" }, + { GIMP_HANDLE_MODE_TRANSFORM, "GIMP_HANDLE_MODE_TRANSFORM", "transform" }, + { 0, NULL, NULL } + }; + + static const GimpEnumDesc descs[] = + { + { GIMP_HANDLE_MODE_ADD_MOVE, NC_("transform-handle-mode", "Add/Move"), NULL }, + { GIMP_HANDLE_MODE_REMOVE, NC_("transform-handle-mode", "Remove"), NULL }, + { GIMP_HANDLE_MODE_TRANSFORM, NC_("transform-handle-mode", "Transform"), NULL }, + { 0, NULL, NULL } + }; + + static GType type = 0; + + if (G_UNLIKELY (! type)) + { + type = g_enum_register_static ("GimpTransformHandleMode", values); + gimp_type_set_translation_context (type, "transform-handle-mode"); + gimp_enum_set_value_descriptions (type, descs); + } + + return type; +} + GType gimp_rectangle_constraint_get_type (void) { diff --git a/app/tools/tools-enums.h b/app/tools/tools-enums.h index c2d2cc06cf..60246efe0d 100644 --- a/app/tools/tools-enums.h +++ b/app/tools/tools-enums.h @@ -47,6 +47,18 @@ typedef enum } GimpButtonReleaseType; +#define GIMP_TYPE_TRANSFORM_HANDLE_MODE (gimp_transform_handle_mode_get_type ()) + +GType gimp_transform_handle_mode_get_type (void) G_GNUC_CONST; + +typedef enum +{ + GIMP_HANDLE_MODE_ADD_MOVE, /*< desc="Add/Move" >*/ + GIMP_HANDLE_MODE_REMOVE, /*< desc="Remove" >*/ + GIMP_HANDLE_MODE_TRANSFORM, /*< desc="Transform" >*/ +} GimpTransformHandleMode; + + #define GIMP_TYPE_RECTANGLE_CONSTRAINT (gimp_rectangle_constraint_get_type ()) GType gimp_rectangle_constraint_get_type (void) G_GNUC_CONST; diff --git a/app/widgets/gimphelp-ids.h b/app/widgets/gimphelp-ids.h index 1d6754eb75..7e7076ae4a 100644 --- a/app/widgets/gimphelp-ids.h +++ b/app/widgets/gimphelp-ids.h @@ -281,6 +281,7 @@ #define GIMP_HELP_TOOL_FOREGROUND_SELECT "gimp-tool-foreground-select" #define GIMP_HELP_TOOL_FUZZY_SELECT "gimp-tool-fuzzy-select" #define GIMP_HELP_TOOL_GEGL "gimp-tool-gegl" +#define GIMP_HELP_TOOL_HANDLE_TRANSFORM "gimp-tool-handle-transform" #define GIMP_HELP_TOOL_HEAL "gimp-tool-heal" #define GIMP_HELP_TOOL_HUE_SATURATION "gimp-tool-hue-saturation" #define GIMP_HELP_TOOL_INK "gimp-tool-ink" diff --git a/icons/16/gimp-tool-handle-transform.png b/icons/16/gimp-tool-handle-transform.png new file mode 100644 index 0000000000..8bc2ed4f26 Binary files /dev/null and b/icons/16/gimp-tool-handle-transform.png differ diff --git a/icons/22/gimp-tool-handle-transform.png b/icons/22/gimp-tool-handle-transform.png new file mode 100644 index 0000000000..797b99b7d6 Binary files /dev/null and b/icons/22/gimp-tool-handle-transform.png differ diff --git a/icons/22/gimp-tool-handle-transform.xcf b/icons/22/gimp-tool-handle-transform.xcf new file mode 100644 index 0000000000..e69de29bb2 diff --git a/icons/Makefile.am b/icons/Makefile.am index a6a030e95b..71b007cb2b 100644 --- a/icons/Makefile.am +++ b/icons/Makefile.am @@ -180,6 +180,7 @@ icons16_DATA = \ 16/gimp-tool-foreground-select.png \ 16/gimp-tool-free-select.png \ 16/gimp-tool-fuzzy-select.png \ + 16/gimp-tool-handle-transform.png \ 16/gimp-tool-heal.png \ 16/gimp-tool-hue-saturation.png \ 16/gimp-tool-ink.png \ @@ -290,6 +291,7 @@ icons22_DATA = \ 22/gimp-tool-foreground-select.png \ 22/gimp-tool-free-select.png \ 22/gimp-tool-fuzzy-select.png \ + 22/gimp-tool-handle-transform.png \ 22/gimp-tool-heal.png \ 22/gimp-tool-hue-saturation.png \ 22/gimp-tool-ink.png \ diff --git a/libgimpwidgets/gimpstock.c b/libgimpwidgets/gimpstock.c index 320237180d..5a7e969072 100644 --- a/libgimpwidgets/gimpstock.c +++ b/libgimpwidgets/gimpstock.c @@ -256,6 +256,7 @@ static const GtkStockItem gimp_stock_items[] = { GIMP_STOCK_TOOL_FOREGROUND_SELECT, N_("_Select"), 0, 0, LIBGIMP_DOMAIN }, { GIMP_STOCK_TOOL_FUZZY_SELECT, NULL, 0, 0, LIBGIMP_DOMAIN }, { GIMP_STOCK_TOOL_HUE_SATURATION, NULL, 0, 0, LIBGIMP_DOMAIN }, + { GIMP_STOCK_TOOL_HANDLE_TRANSFORM,N_("_Transform"),0, 0, LIBGIMP_DOMAIN }, { GIMP_STOCK_TOOL_HEAL, NULL, 0, 0, LIBGIMP_DOMAIN }, { GIMP_STOCK_TOOL_INK, NULL, 0, 0, LIBGIMP_DOMAIN }, { GIMP_STOCK_TOOL_ISCISSORS, NULL, 0, 0, LIBGIMP_DOMAIN }, diff --git a/libgimpwidgets/gimpstock.h b/libgimpwidgets/gimpstock.h index 97936146dd..ed23e2d07d 100644 --- a/libgimpwidgets/gimpstock.h +++ b/libgimpwidgets/gimpstock.h @@ -125,6 +125,7 @@ G_BEGIN_DECLS #define GIMP_STOCK_TOOL_FREE_SELECT "gimp-tool-free-select" #define GIMP_STOCK_TOOL_FOREGROUND_SELECT "gimp-tool-foreground-select" #define GIMP_STOCK_TOOL_FUZZY_SELECT "gimp-tool-fuzzy-select" +#define GIMP_STOCK_TOOL_HANDLE_TRANSFORM "gimp-tool-handle-transform" #define GIMP_STOCK_TOOL_HEAL "gimp-tool-heal" #define GIMP_STOCK_TOOL_HUE_SATURATION "gimp-tool-hue-saturation" #define GIMP_STOCK_TOOL_INK "gimp-tool-ink" diff --git a/menus/image-menu.xml.in b/menus/image-menu.xml.in index c9162b581b..a1025b30eb 100644 --- a/menus/image-menu.xml.in +++ b/menus/image-menu.xml.in @@ -602,6 +602,7 @@ + diff --git a/po/POTFILES.in b/po/POTFILES.in index 7b5e93de12..c34dbce77e 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -368,6 +368,8 @@ app/tools/gimpforegroundselecttool.c app/tools/gimpfreeselecttool.c app/tools/gimpfuzzyselecttool.c app/tools/gimpgegltool.c +app/tools/gimphandletransformoptions.c +app/tools/gimphandletransformtool.c app/tools/gimphealtool.c app/tools/gimphistogramoptions.c app/tools/gimphuesaturationtool.c