2006-12-10 05:33:38 +08:00
|
|
|
/* GIMP - The GNU Image Manipulation Program
|
2001-03-01 14:56:57 +08:00
|
|
|
* Copyright (C) 1995-2001 Spencer Kimball, Peter Mattis, and others
|
|
|
|
*
|
2009-01-18 06:28:01 +08:00
|
|
|
* This program is free software: you can redistribute it and/or modify
|
2001-03-01 14:56:57 +08:00
|
|
|
* it under the terms of the GNU General Public License as published by
|
2009-01-18 06:28:01 +08:00
|
|
|
* the Free Software Foundation; either version 3 of the License, or
|
2001-03-01 14:56:57 +08:00
|
|
|
* (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
|
2018-07-12 05:27:07 +08:00
|
|
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
2001-03-01 14:56:57 +08:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
|
2008-10-10 04:24:04 +08:00
|
|
|
#include <gegl.h>
|
2001-03-01 14:56:57 +08:00
|
|
|
#include <gtk/gtk.h>
|
|
|
|
|
2007-03-09 21:00:01 +08:00
|
|
|
#include "libgimpmath/gimpmath.h"
|
2018-09-24 00:24:50 +08:00
|
|
|
#include "libgimpwidgets/gimpwidgets.h"
|
2001-03-01 14:56:57 +08:00
|
|
|
|
2001-05-10 06:34:59 +08:00
|
|
|
#include "tools-types.h"
|
2002-05-03 20:45:22 +08:00
|
|
|
|
2019-02-07 04:22:27 +08:00
|
|
|
#include "config/gimpguiconfig.h"
|
|
|
|
|
2006-09-28 19:07:55 +08:00
|
|
|
#include "core/gimp.h"
|
2001-11-20 02:23:43 +08:00
|
|
|
#include "core/gimpdrawable-transform.h"
|
2009-08-20 23:05:23 +08:00
|
|
|
#include "core/gimperror.h"
|
2001-05-09 10:32:03 +08:00
|
|
|
#include "core/gimpimage.h"
|
2018-09-24 00:24:50 +08:00
|
|
|
#include "core/gimpimage-item-list.h"
|
2019-08-11 03:57:55 +08:00
|
|
|
#include "core/gimpimage-transform.h"
|
2003-02-13 19:23:50 +08:00
|
|
|
#include "core/gimpimage-undo.h"
|
2001-05-09 10:32:03 +08:00
|
|
|
#include "core/gimplayer.h"
|
2017-04-06 06:29:30 +08:00
|
|
|
#include "core/gimplayermask.h"
|
2004-08-11 02:47:21 +08:00
|
|
|
#include "core/gimpprogress.h"
|
2018-09-24 00:24:50 +08:00
|
|
|
#include "core/gimp-transform-resize.h"
|
2001-05-09 10:32:03 +08:00
|
|
|
|
2003-07-16 22:08:24 +08:00
|
|
|
#include "vectors/gimpvectors.h"
|
|
|
|
|
2001-09-26 07:23:09 +08:00
|
|
|
#include "display/gimpdisplay.h"
|
2019-09-04 23:33:47 +08:00
|
|
|
#include "display/gimpdisplayshell.h"
|
2001-03-01 14:56:57 +08:00
|
|
|
|
2018-09-24 00:24:50 +08:00
|
|
|
#include "widgets/gimpmessagedialog.h"
|
|
|
|
#include "widgets/gimpmessagebox.h"
|
2018-12-10 20:39:32 +08:00
|
|
|
#include "widgets/gimpwidgets-utils.h"
|
2018-09-24 00:24:50 +08:00
|
|
|
|
2003-04-16 00:05:52 +08:00
|
|
|
#include "gimptoolcontrol.h"
|
2018-12-10 21:22:50 +08:00
|
|
|
#include "gimptools-utils.h"
|
2003-02-09 05:12:03 +08:00
|
|
|
#include "gimptransformoptions.h"
|
2003-02-14 22:14:29 +08:00
|
|
|
#include "gimptransformtool.h"
|
2001-03-15 12:57:24 +08:00
|
|
|
|
2003-03-26 00:38:19 +08:00
|
|
|
#include "gimp-intl.h"
|
2001-03-01 14:56:57 +08:00
|
|
|
|
2001-04-18 05:43:29 +08:00
|
|
|
|
2018-09-24 00:24:50 +08:00
|
|
|
/* the minimal ratio between the transformed item size and the image size,
|
|
|
|
* above which confirmation is required.
|
|
|
|
*/
|
|
|
|
#define MIN_CONFIRMATION_RATIO 10
|
|
|
|
|
|
|
|
|
|
|
|
/* local function prototypes */
|
|
|
|
|
2019-08-11 04:55:56 +08:00
|
|
|
static void gimp_transform_tool_control (GimpTool *tool,
|
|
|
|
GimpToolAction action,
|
|
|
|
GimpDisplay *display);
|
|
|
|
|
app: in GimpTransformGridTool, allow simultaneous forward and backward transforms
In GimpTransformGridTool, allow performing simultaneous forward
(normal) and backward (corrective) transforms, by having each
transform direction operate on an independent set of parameters.
In other words, whereas the transform-grid tools previously had a
single transform, which could be applied either normally or
correctively using the "direction" tool-option, they now have two
independent transforms, one applied normally and the other
applied correctively, which are toggled using the "direction"
option. The overall transform is the combination of the backward
transform, followed by the forward transform.
Another way to think about it, is that the tool transforms a source
shape into a destination shape. The source shape is defined by the
backward transform, and the destination shape is defined by the
forward transform. Wherewas previously only one of these shapes
could be controlled (the other shape always being the item bounds),
it's now possible to control both shapes in a single transform.
The next commit will allow modifying both shapes simultaneously,
making this even more useful.
Note that since both transforms start off as the identity, using
only one of the transform directions has the same behavior as
before.
2019-02-04 23:30:18 +08:00
|
|
|
static gchar * gimp_transform_tool_real_get_undo_desc (GimpTransformTool *tr_tool);
|
|
|
|
static GimpTransformDirection gimp_transform_tool_real_get_direction (GimpTransformTool *tr_tool);
|
|
|
|
static GeglBuffer * gimp_transform_tool_real_transform (GimpTransformTool *tr_tool,
|
2020-05-26 22:15:15 +08:00
|
|
|
GList *objects,
|
app: in GimpTransformGridTool, allow simultaneous forward and backward transforms
In GimpTransformGridTool, allow performing simultaneous forward
(normal) and backward (corrective) transforms, by having each
transform direction operate on an independent set of parameters.
In other words, whereas the transform-grid tools previously had a
single transform, which could be applied either normally or
correctively using the "direction" tool-option, they now have two
independent transforms, one applied normally and the other
applied correctively, which are toggled using the "direction"
option. The overall transform is the combination of the backward
transform, followed by the forward transform.
Another way to think about it, is that the tool transforms a source
shape into a destination shape. The source shape is defined by the
backward transform, and the destination shape is defined by the
forward transform. Wherewas previously only one of these shapes
could be controlled (the other shape always being the item bounds),
it's now possible to control both shapes in a single transform.
The next commit will allow modifying both shapes simultaneously,
making this even more useful.
Note that since both transforms start off as the identity, using
only one of the transform directions has the same behavior as
before.
2019-02-04 23:30:18 +08:00
|
|
|
GeglBuffer *orig_buffer,
|
|
|
|
gint orig_offset_x,
|
|
|
|
gint orig_offset_y,
|
|
|
|
GimpColorProfile **buffer_profile,
|
|
|
|
gint *new_offset_x,
|
|
|
|
gint *new_offset_y);
|
2017-04-03 18:39:33 +08:00
|
|
|
|
2019-08-11 04:55:56 +08:00
|
|
|
static void gimp_transform_tool_halt (GimpTransformTool *tr_tool);
|
|
|
|
|
2019-08-11 05:07:20 +08:00
|
|
|
static gboolean gimp_transform_tool_confirm (GimpTransformTool *tr_tool,
|
|
|
|
GimpDisplay *display);
|
2018-09-24 00:24:50 +08:00
|
|
|
|
2001-03-31 22:10:22 +08:00
|
|
|
|
2006-05-15 17:46:31 +08:00
|
|
|
G_DEFINE_TYPE (GimpTransformTool, gimp_transform_tool, GIMP_TYPE_DRAW_TOOL)
|
2005-12-13 17:13:50 +08:00
|
|
|
|
|
|
|
#define parent_class gimp_transform_tool_parent_class
|
Port to glib/gtk+ 2.0 episode I (every segfault has it's beginning)
2001-07-24 Michael Natterer <mitch@gimp.org>
Port to glib/gtk+ 2.0 episode I (every segfault has it's beginning)
* configure.in: require glib/gtk+ >= 1.3.7, commented out the
gtkxmhtml stuff.
From now on, you will need glib, pango, atk and gtk+ HEAD from CVS
to hack or use GIMP HEAD.
Beware, it crashes randomly :)
* app/core/Makefile.am
* app/core/gimpmarshal.list: new file plus rules to generate
gimpmarshal.[ch] from it.
* app/core/*
* app/tools/*
* app/widgets/*
* libgimpwidgets/*: started to use the glib object system. All
core/ objects are still gtk objects however. All signals are
created using g_signal_new(). There are many gtk+ artefacts left.
Finally, we will _not_ use the gtk_signal_foo() wrappers and
friends any more.
* app/colormaps.c
* app/devices.[ch]
* app/disp_callbacks.c
* app/errorconsole.c
* app/file-save.[ch]
* app/interface.c
* app/module_db.c
* app/nav_window.c
* app/ops_buttons.c
* app/scroll.c
* app/user_install.c
* app/gui/about-dialog.c
* app/gui/brush-editor.c
* app/gui/brushes-commands.c
* app/gui/color-notebook.c
* app/gui/colormap-dialog.c
* app/gui/dialogs-commands.c
* app/gui/dialogs-constructors.c
* app/gui/file-commands.c
* app/gui/file-dialog-utils.c
* app/gui/file-new-dialog.c
* app/gui/file-open-dialog.[ch]
* app/gui/file-save-dialog.c
* app/gui/gradient-editor.c
* app/gui/gradients-commands.c
* app/gui/image-commands.c
* app/gui/info-dialog.[ch]
* app/gui/layer-select.c
* app/gui/layers-commands.c
* app/gui/menus.c
* app/gui/offset-dialog.c
* app/gui/palette-editor.c
* app/gui/palettes-commands.c
* app/gui/patterns-commands.c
* app/gui/preferences-dialog.c
* app/gui/resize-dialog.[ch]
* app/gui/splash.c
* app/gui/tips-dialog.c
* app/gui/tool-options-dialog.c
* app/gui/toolbox.c
* app/gui/tools-commands.c
* libgimp/gimpbrushmenu.c
* libgimp/gimpmenu.c
* libgimp/gimppatternmenu.c
* libgimp/gimpui.c
* libgimpbase/gimpenv.c: tons and tons of changes like "const
gchar*", switch from GdkDeviceInfo to GdkDevice (very incomplete
and currently disables), lots of s/gtk_signal/g_signal/,
removal/replacement of deprecated stuff,
s/GtkSignalFunc/GCallback/ and lots of small changes and fixes
while I was on it, zillions of warnings left...
* modules/Makefile.am: disabled the water color selector
temporarily (XInput issues).
* plug-ins/Makefile.am
* plug-ins/common/.cvsignore
* plug-ins/common/Makefile.am
* plug-ins/common/plugin-defs.pl: simply excluded all plug-ins
which did not build (including Script-Fu). They are trivial to
fix.
2001-07-25 05:27:11 +08:00
|
|
|
|
2001-03-01 14:56:57 +08:00
|
|
|
|
2018-09-24 00:24:50 +08:00
|
|
|
/* private functions */
|
|
|
|
|
|
|
|
|
2001-03-01 14:56:57 +08:00
|
|
|
static void
|
|
|
|
gimp_transform_tool_class_init (GimpTransformToolClass *klass)
|
|
|
|
{
|
2019-08-11 04:55:56 +08:00
|
|
|
GimpToolClass *tool_class = GIMP_TOOL_CLASS (klass);
|
|
|
|
|
|
|
|
tool_class->control = gimp_transform_tool_control;
|
|
|
|
|
2018-06-10 04:25:03 +08:00
|
|
|
klass->recalc_matrix = NULL;
|
2019-02-04 23:21:31 +08:00
|
|
|
klass->get_undo_desc = gimp_transform_tool_real_get_undo_desc;
|
app: in GimpTransformGridTool, allow simultaneous forward and backward transforms
In GimpTransformGridTool, allow performing simultaneous forward
(normal) and backward (corrective) transforms, by having each
transform direction operate on an independent set of parameters.
In other words, whereas the transform-grid tools previously had a
single transform, which could be applied either normally or
correctively using the "direction" tool-option, they now have two
independent transforms, one applied normally and the other
applied correctively, which are toggled using the "direction"
option. The overall transform is the combination of the backward
transform, followed by the forward transform.
Another way to think about it, is that the tool transforms a source
shape into a destination shape. The source shape is defined by the
backward transform, and the destination shape is defined by the
forward transform. Wherewas previously only one of these shapes
could be controlled (the other shape always being the item bounds),
it's now possible to control both shapes in a single transform.
The next commit will allow modifying both shapes simultaneously,
making this even more useful.
Note that since both transforms start off as the identity, using
only one of the transform directions has the same behavior as
before.
2019-02-04 23:30:18 +08:00
|
|
|
klass->get_direction = gimp_transform_tool_real_get_direction;
|
2018-06-10 04:25:03 +08:00
|
|
|
klass->transform = gimp_transform_tool_real_transform;
|
|
|
|
|
2019-02-04 23:21:31 +08:00
|
|
|
klass->undo_desc = _("Transform");
|
2018-06-10 04:25:03 +08:00
|
|
|
klass->progress_text = _("Transforming");
|
2001-03-01 14:56:57 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2002-11-14 19:54:57 +08:00
|
|
|
gimp_transform_tool_init (GimpTransformTool *tr_tool)
|
2001-03-01 14:56:57 +08:00
|
|
|
{
|
2003-07-07 21:50:48 +08:00
|
|
|
gimp_matrix3_identity (&tr_tool->transform);
|
2018-01-27 17:29:03 +08:00
|
|
|
tr_tool->transform_valid = TRUE;
|
2019-08-11 04:55:56 +08:00
|
|
|
|
|
|
|
tr_tool->restore_type = FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gimp_transform_tool_control (GimpTool *tool,
|
|
|
|
GimpToolAction action,
|
|
|
|
GimpDisplay *display)
|
|
|
|
{
|
|
|
|
GimpTransformTool *tr_tool = GIMP_TRANSFORM_TOOL (tool);
|
|
|
|
|
|
|
|
switch (action)
|
|
|
|
{
|
|
|
|
case GIMP_TOOL_ACTION_PAUSE:
|
|
|
|
case GIMP_TOOL_ACTION_RESUME:
|
|
|
|
break;
|
|
|
|
|
|
|
|
case GIMP_TOOL_ACTION_HALT:
|
|
|
|
gimp_transform_tool_halt (tr_tool);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case GIMP_TOOL_ACTION_COMMIT:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
GIMP_TOOL_CLASS (parent_class)->control (tool, action, display);
|
2001-03-01 14:56:57 +08:00
|
|
|
}
|
|
|
|
|
2019-02-04 23:21:31 +08:00
|
|
|
static gchar *
|
|
|
|
gimp_transform_tool_real_get_undo_desc (GimpTransformTool *tr_tool)
|
|
|
|
{
|
|
|
|
return g_strdup (GIMP_TRANSFORM_TOOL_GET_CLASS (tr_tool)->undo_desc);
|
|
|
|
}
|
|
|
|
|
app: in GimpTransformGridTool, allow simultaneous forward and backward transforms
In GimpTransformGridTool, allow performing simultaneous forward
(normal) and backward (corrective) transforms, by having each
transform direction operate on an independent set of parameters.
In other words, whereas the transform-grid tools previously had a
single transform, which could be applied either normally or
correctively using the "direction" tool-option, they now have two
independent transforms, one applied normally and the other
applied correctively, which are toggled using the "direction"
option. The overall transform is the combination of the backward
transform, followed by the forward transform.
Another way to think about it, is that the tool transforms a source
shape into a destination shape. The source shape is defined by the
backward transform, and the destination shape is defined by the
forward transform. Wherewas previously only one of these shapes
could be controlled (the other shape always being the item bounds),
it's now possible to control both shapes in a single transform.
The next commit will allow modifying both shapes simultaneously,
making this even more useful.
Note that since both transforms start off as the identity, using
only one of the transform directions has the same behavior as
before.
2019-02-04 23:30:18 +08:00
|
|
|
static GimpTransformDirection
|
|
|
|
gimp_transform_tool_real_get_direction (GimpTransformTool *tr_tool)
|
|
|
|
{
|
|
|
|
GimpTransformOptions *options = GIMP_TRANSFORM_TOOL_GET_OPTIONS (tr_tool);
|
|
|
|
|
|
|
|
return options->direction;
|
|
|
|
}
|
|
|
|
|
2012-03-21 21:30:47 +08:00
|
|
|
static GeglBuffer *
|
2002-11-18 21:10:04 +08:00
|
|
|
gimp_transform_tool_real_transform (GimpTransformTool *tr_tool,
|
2020-05-26 22:15:15 +08:00
|
|
|
GList *objects,
|
2012-03-21 21:30:47 +08:00
|
|
|
GeglBuffer *orig_buffer,
|
2011-03-27 01:45:58 +08:00
|
|
|
gint orig_offset_x,
|
|
|
|
gint orig_offset_y,
|
2016-05-09 00:35:40 +08:00
|
|
|
GimpColorProfile **buffer_profile,
|
2011-03-26 15:30:15 +08:00
|
|
|
gint *new_offset_x,
|
|
|
|
gint *new_offset_y)
|
2002-11-18 21:10:04 +08:00
|
|
|
{
|
2018-06-10 04:25:03 +08:00
|
|
|
GimpTransformToolClass *klass = GIMP_TRANSFORM_TOOL_GET_CLASS (tr_tool);
|
|
|
|
GimpTool *tool = GIMP_TOOL (tr_tool);
|
|
|
|
GimpTransformOptions *options = GIMP_TRANSFORM_TOOL_GET_OPTIONS (tool);
|
|
|
|
GimpContext *context = GIMP_CONTEXT (options);
|
|
|
|
GeglBuffer *ret = NULL;
|
|
|
|
GimpTransformResize clip = options->clip;
|
app: in GimpTransformGridTool, allow simultaneous forward and backward transforms
In GimpTransformGridTool, allow performing simultaneous forward
(normal) and backward (corrective) transforms, by having each
transform direction operate on an independent set of parameters.
In other words, whereas the transform-grid tools previously had a
single transform, which could be applied either normally or
correctively using the "direction" tool-option, they now have two
independent transforms, one applied normally and the other
applied correctively, which are toggled using the "direction"
option. The overall transform is the combination of the backward
transform, followed by the forward transform.
Another way to think about it, is that the tool transforms a source
shape into a destination shape. The source shape is defined by the
backward transform, and the destination shape is defined by the
forward transform. Wherewas previously only one of these shapes
could be controlled (the other shape always being the item bounds),
it's now possible to control both shapes in a single transform.
The next commit will allow modifying both shapes simultaneously,
making this even more useful.
Note that since both transforms start off as the identity, using
only one of the transform directions has the same behavior as
before.
2019-02-04 23:30:18 +08:00
|
|
|
GimpTransformDirection direction;
|
2018-06-10 04:25:03 +08:00
|
|
|
GimpProgress *progress;
|
2002-11-18 21:10:04 +08:00
|
|
|
|
app: in GimpTransformGridTool, allow simultaneous forward and backward transforms
In GimpTransformGridTool, allow performing simultaneous forward
(normal) and backward (corrective) transforms, by having each
transform direction operate on an independent set of parameters.
In other words, whereas the transform-grid tools previously had a
single transform, which could be applied either normally or
correctively using the "direction" tool-option, they now have two
independent transforms, one applied normally and the other
applied correctively, which are toggled using the "direction"
option. The overall transform is the combination of the backward
transform, followed by the forward transform.
Another way to think about it, is that the tool transforms a source
shape into a destination shape. The source shape is defined by the
backward transform, and the destination shape is defined by the
forward transform. Wherewas previously only one of these shapes
could be controlled (the other shape always being the item bounds),
it's now possible to control both shapes in a single transform.
The next commit will allow modifying both shapes simultaneously,
making this even more useful.
Note that since both transforms start off as the identity, using
only one of the transform directions has the same behavior as
before.
2019-02-04 23:30:18 +08:00
|
|
|
direction = GIMP_TRANSFORM_TOOL_GET_CLASS (tr_tool)->get_direction (tr_tool);
|
|
|
|
|
2014-07-13 05:45:20 +08:00
|
|
|
progress = gimp_progress_start (GIMP_PROGRESS (tool), FALSE,
|
2018-06-10 04:25:03 +08:00
|
|
|
"%s", klass->progress_text);
|
2002-11-18 21:10:04 +08:00
|
|
|
|
2018-07-01 22:19:54 +08:00
|
|
|
while (g_main_context_pending (NULL))
|
|
|
|
g_main_context_iteration (NULL, FALSE);
|
|
|
|
|
2012-03-21 21:30:47 +08:00
|
|
|
if (orig_buffer)
|
2003-05-31 07:52:24 +08:00
|
|
|
{
|
2020-05-26 22:15:15 +08:00
|
|
|
/* this happens when transforming a selection cut out of
|
|
|
|
* normal drawables.
|
2011-03-18 04:52:43 +08:00
|
|
|
*/
|
|
|
|
|
2020-05-26 22:15:15 +08:00
|
|
|
ret = gimp_drawable_transform_buffer_affine (objects->data,
|
2012-03-21 21:30:47 +08:00
|
|
|
context,
|
|
|
|
orig_buffer,
|
|
|
|
orig_offset_x,
|
|
|
|
orig_offset_y,
|
|
|
|
&tr_tool->transform,
|
app: in GimpTransformGridTool, allow simultaneous forward and backward transforms
In GimpTransformGridTool, allow performing simultaneous forward
(normal) and backward (corrective) transforms, by having each
transform direction operate on an independent set of parameters.
In other words, whereas the transform-grid tools previously had a
single transform, which could be applied either normally or
correctively using the "direction" tool-option, they now have two
independent transforms, one applied normally and the other
applied correctively, which are toggled using the "direction"
option. The overall transform is the combination of the backward
transform, followed by the forward transform.
Another way to think about it, is that the tool transforms a source
shape into a destination shape. The source shape is defined by the
backward transform, and the destination shape is defined by the
forward transform. Wherewas previously only one of these shapes
could be controlled (the other shape always being the item bounds),
it's now possible to control both shapes in a single transform.
The next commit will allow modifying both shapes simultaneously,
making this even more useful.
Note that since both transforms start off as the identity, using
only one of the transform directions has the same behavior as
before.
2019-02-04 23:30:18 +08:00
|
|
|
direction,
|
2012-03-21 21:30:47 +08:00
|
|
|
options->interpolation,
|
|
|
|
clip,
|
2016-05-09 00:35:40 +08:00
|
|
|
buffer_profile,
|
2012-03-21 21:30:47 +08:00
|
|
|
new_offset_x,
|
|
|
|
new_offset_y,
|
|
|
|
progress);
|
2011-03-18 04:52:43 +08:00
|
|
|
}
|
2020-05-26 22:15:15 +08:00
|
|
|
else if (g_list_length (objects) == 1 && GIMP_IS_IMAGE (objects->data))
|
|
|
|
{
|
|
|
|
/* this happens for images */
|
|
|
|
|
|
|
|
gimp_image_transform (objects->data, context,
|
|
|
|
&tr_tool->transform,
|
|
|
|
direction,
|
|
|
|
options->interpolation,
|
|
|
|
clip,
|
|
|
|
progress);
|
|
|
|
}
|
|
|
|
else
|
2018-06-10 04:25:03 +08:00
|
|
|
{
|
2020-05-26 22:15:15 +08:00
|
|
|
GList *items;
|
|
|
|
|
2018-06-10 04:25:03 +08:00
|
|
|
/* this happens for entire drawables, paths and layer groups */
|
2020-05-26 22:15:15 +08:00
|
|
|
g_return_val_if_fail (g_list_length (objects) > 0, NULL);
|
2003-05-31 07:52:24 +08:00
|
|
|
|
2021-12-16 07:08:15 +08:00
|
|
|
items = gimp_image_item_list_filter (g_list_copy (objects));
|
2019-08-11 03:57:55 +08:00
|
|
|
|
2020-05-26 22:15:15 +08:00
|
|
|
gimp_image_item_list_transform (gimp_item_get_image (objects->data),
|
|
|
|
items, context,
|
2018-06-10 04:25:03 +08:00
|
|
|
&tr_tool->transform,
|
app: in GimpTransformGridTool, allow simultaneous forward and backward transforms
In GimpTransformGridTool, allow performing simultaneous forward
(normal) and backward (corrective) transforms, by having each
transform direction operate on an independent set of parameters.
In other words, whereas the transform-grid tools previously had a
single transform, which could be applied either normally or
correctively using the "direction" tool-option, they now have two
independent transforms, one applied normally and the other
applied correctively, which are toggled using the "direction"
option. The overall transform is the combination of the backward
transform, followed by the forward transform.
Another way to think about it, is that the tool transforms a source
shape into a destination shape. The source shape is defined by the
backward transform, and the destination shape is defined by the
forward transform. Wherewas previously only one of these shapes
could be controlled (the other shape always being the item bounds),
it's now possible to control both shapes in a single transform.
The next commit will allow modifying both shapes simultaneously,
making this even more useful.
Note that since both transforms start off as the identity, using
only one of the transform directions has the same behavior as
before.
2019-02-04 23:30:18 +08:00
|
|
|
direction,
|
2018-06-10 04:25:03 +08:00
|
|
|
options->interpolation,
|
|
|
|
clip,
|
|
|
|
progress);
|
2020-05-26 22:15:15 +08:00
|
|
|
g_list_free (items);
|
2019-08-11 03:57:55 +08:00
|
|
|
}
|
2001-11-20 02:23:43 +08:00
|
|
|
|
2018-06-10 04:25:03 +08:00
|
|
|
if (progress)
|
|
|
|
gimp_progress_end (progress);
|
2001-11-20 02:23:43 +08:00
|
|
|
|
2018-06-10 04:25:03 +08:00
|
|
|
return ret;
|
2001-11-20 02:23:43 +08:00
|
|
|
}
|
|
|
|
|
2019-08-11 04:55:56 +08:00
|
|
|
static void
|
|
|
|
gimp_transform_tool_halt (GimpTransformTool *tr_tool)
|
|
|
|
{
|
|
|
|
GimpTransformOptions *options = GIMP_TRANSFORM_TOOL_GET_OPTIONS (tr_tool);
|
|
|
|
|
2019-09-04 23:33:47 +08:00
|
|
|
tr_tool->x1 = 0;
|
|
|
|
tr_tool->y1 = 0;
|
|
|
|
tr_tool->x2 = 0;
|
|
|
|
tr_tool->y2 = 0;
|
|
|
|
|
2019-08-11 04:55:56 +08:00
|
|
|
if (tr_tool->restore_type)
|
|
|
|
{
|
|
|
|
g_object_set (options,
|
|
|
|
"type", tr_tool->saved_type,
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
tr_tool->restore_type = FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-09-24 00:24:50 +08:00
|
|
|
static gboolean
|
|
|
|
gimp_transform_tool_confirm (GimpTransformTool *tr_tool,
|
|
|
|
GimpDisplay *display)
|
|
|
|
{
|
2019-08-11 03:57:55 +08:00
|
|
|
GimpTransformOptions *options = GIMP_TRANSFORM_TOOL_GET_OPTIONS (tr_tool);
|
|
|
|
GimpDisplayShell *shell = gimp_display_get_shell (display);
|
|
|
|
GimpImage *image = gimp_display_get_image (display);
|
2020-05-26 22:15:15 +08:00
|
|
|
GList *selected_objects;
|
2019-08-11 03:57:55 +08:00
|
|
|
gdouble max_ratio = 0.0;
|
|
|
|
GimpObject *max_ratio_object = NULL;
|
2018-09-24 00:24:50 +08:00
|
|
|
|
2020-05-26 22:15:15 +08:00
|
|
|
selected_objects = gimp_transform_tool_get_selected_objects (tr_tool, display);
|
2018-09-24 00:24:50 +08:00
|
|
|
|
|
|
|
if (GIMP_TRANSFORM_TOOL_GET_CLASS (tr_tool)->recalc_matrix)
|
|
|
|
{
|
app: in GimpTransformGridTool, allow simultaneous forward and backward transforms
In GimpTransformGridTool, allow performing simultaneous forward
(normal) and backward (corrective) transforms, by having each
transform direction operate on an independent set of parameters.
In other words, whereas the transform-grid tools previously had a
single transform, which could be applied either normally or
correctively using the "direction" tool-option, they now have two
independent transforms, one applied normally and the other
applied correctively, which are toggled using the "direction"
option. The overall transform is the combination of the backward
transform, followed by the forward transform.
Another way to think about it, is that the tool transforms a source
shape into a destination shape. The source shape is defined by the
backward transform, and the destination shape is defined by the
forward transform. Wherewas previously only one of these shapes
could be controlled (the other shape always being the item bounds),
it's now possible to control both shapes in a single transform.
The next commit will allow modifying both shapes simultaneously,
making this even more useful.
Note that since both transforms start off as the identity, using
only one of the transform directions has the same behavior as
before.
2019-02-04 23:30:18 +08:00
|
|
|
GimpMatrix3 transform;
|
|
|
|
GimpTransformDirection direction;
|
|
|
|
GeglRectangle selection_bounds;
|
|
|
|
gboolean selection_empty = TRUE;
|
2020-05-26 22:15:15 +08:00
|
|
|
GList *objects = NULL;
|
app: in GimpTransformGridTool, allow simultaneous forward and backward transforms
In GimpTransformGridTool, allow performing simultaneous forward
(normal) and backward (corrective) transforms, by having each
transform direction operate on an independent set of parameters.
In other words, whereas the transform-grid tools previously had a
single transform, which could be applied either normally or
correctively using the "direction" tool-option, they now have two
independent transforms, one applied normally and the other
applied correctively, which are toggled using the "direction"
option. The overall transform is the combination of the backward
transform, followed by the forward transform.
Another way to think about it, is that the tool transforms a source
shape into a destination shape. The source shape is defined by the
backward transform, and the destination shape is defined by the
forward transform. Wherewas previously only one of these shapes
could be controlled (the other shape always being the item bounds),
it's now possible to control both shapes in a single transform.
The next commit will allow modifying both shapes simultaneously,
making this even more useful.
Note that since both transforms start off as the identity, using
only one of the transform directions has the same behavior as
before.
2019-02-04 23:30:18 +08:00
|
|
|
GList *iter;
|
2018-09-24 00:24:50 +08:00
|
|
|
|
|
|
|
transform = tr_tool->transform;
|
app: in GimpTransformGridTool, allow simultaneous forward and backward transforms
In GimpTransformGridTool, allow performing simultaneous forward
(normal) and backward (corrective) transforms, by having each
transform direction operate on an independent set of parameters.
In other words, whereas the transform-grid tools previously had a
single transform, which could be applied either normally or
correctively using the "direction" tool-option, they now have two
independent transforms, one applied normally and the other
applied correctively, which are toggled using the "direction"
option. The overall transform is the combination of the backward
transform, followed by the forward transform.
Another way to think about it, is that the tool transforms a source
shape into a destination shape. The source shape is defined by the
backward transform, and the destination shape is defined by the
forward transform. Wherewas previously only one of these shapes
could be controlled (the other shape always being the item bounds),
it's now possible to control both shapes in a single transform.
The next commit will allow modifying both shapes simultaneously,
making this even more useful.
Note that since both transforms start off as the identity, using
only one of the transform directions has the same behavior as
before.
2019-02-04 23:30:18 +08:00
|
|
|
direction = GIMP_TRANSFORM_TOOL_GET_CLASS (tr_tool)->get_direction (
|
|
|
|
tr_tool);
|
2018-09-24 00:24:50 +08:00
|
|
|
|
app: in GimpTransformGridTool, allow simultaneous forward and backward transforms
In GimpTransformGridTool, allow performing simultaneous forward
(normal) and backward (corrective) transforms, by having each
transform direction operate on an independent set of parameters.
In other words, whereas the transform-grid tools previously had a
single transform, which could be applied either normally or
correctively using the "direction" tool-option, they now have two
independent transforms, one applied normally and the other
applied correctively, which are toggled using the "direction"
option. The overall transform is the combination of the backward
transform, followed by the forward transform.
Another way to think about it, is that the tool transforms a source
shape into a destination shape. The source shape is defined by the
backward transform, and the destination shape is defined by the
forward transform. Wherewas previously only one of these shapes
could be controlled (the other shape always being the item bounds),
it's now possible to control both shapes in a single transform.
The next commit will allow modifying both shapes simultaneously,
making this even more useful.
Note that since both transforms start off as the identity, using
only one of the transform directions has the same behavior as
before.
2019-02-04 23:30:18 +08:00
|
|
|
if (direction == GIMP_TRANSFORM_BACKWARD)
|
2018-09-24 00:24:50 +08:00
|
|
|
gimp_matrix3_invert (&transform);
|
|
|
|
|
2020-05-26 22:15:15 +08:00
|
|
|
if (options->type == GIMP_TRANSFORM_TYPE_LAYER)
|
2018-09-24 00:24:50 +08:00
|
|
|
{
|
2020-05-26 22:15:15 +08:00
|
|
|
for (iter = selected_objects; iter; iter = iter->next)
|
|
|
|
if (! gimp_viewable_get_children (GIMP_VIEWABLE (iter->data)))
|
|
|
|
{
|
|
|
|
if (gimp_item_bounds (GIMP_ITEM (gimp_image_get_mask (image)),
|
|
|
|
&selection_bounds.x, &selection_bounds.y,
|
|
|
|
&selection_bounds.width, &selection_bounds.height))
|
|
|
|
{
|
|
|
|
selection_empty = FALSE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2018-09-24 00:24:50 +08:00
|
|
|
}
|
|
|
|
|
2020-05-26 22:15:15 +08:00
|
|
|
if (selection_empty &&
|
|
|
|
selected_objects &&
|
|
|
|
GIMP_IS_ITEM (selected_objects->data))
|
2018-09-24 00:24:50 +08:00
|
|
|
{
|
2021-12-16 07:08:15 +08:00
|
|
|
objects = gimp_image_item_list_filter (g_list_copy (selected_objects));
|
2020-05-26 22:15:15 +08:00
|
|
|
g_list_free (selected_objects);
|
2018-09-24 00:24:50 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-05-26 22:15:15 +08:00
|
|
|
objects = selected_objects;
|
2018-09-24 00:24:50 +08:00
|
|
|
}
|
|
|
|
|
2019-08-11 03:57:55 +08:00
|
|
|
if (options->type == GIMP_TRANSFORM_TYPE_IMAGE)
|
2018-09-24 00:24:50 +08:00
|
|
|
{
|
2019-08-11 03:57:55 +08:00
|
|
|
objects = g_list_concat (
|
|
|
|
objects,
|
|
|
|
gimp_image_item_list_get_list (image,
|
|
|
|
GIMP_ITEM_TYPE_ALL,
|
|
|
|
GIMP_ITEM_SET_ALL));
|
|
|
|
}
|
|
|
|
|
|
|
|
for (iter = objects; iter; iter = g_list_next (iter))
|
|
|
|
{
|
|
|
|
GimpObject *object = iter->data;
|
|
|
|
GimpTransformResize clip = options->clip;
|
2018-09-24 00:24:50 +08:00
|
|
|
GeglRectangle orig_bounds;
|
|
|
|
GeglRectangle new_bounds;
|
2019-08-11 03:57:55 +08:00
|
|
|
gdouble ratio = 0.0;
|
2018-09-24 00:24:50 +08:00
|
|
|
|
2019-08-11 03:57:55 +08:00
|
|
|
if (GIMP_IS_DRAWABLE (object))
|
2018-09-24 00:24:50 +08:00
|
|
|
{
|
|
|
|
if (selection_empty)
|
|
|
|
{
|
2019-08-11 03:57:55 +08:00
|
|
|
GimpItem *item = GIMP_ITEM (object);
|
|
|
|
|
2018-09-24 00:24:50 +08:00
|
|
|
gimp_item_get_offset (item, &orig_bounds.x, &orig_bounds.y);
|
|
|
|
|
|
|
|
orig_bounds.width = gimp_item_get_width (item);
|
|
|
|
orig_bounds.height = gimp_item_get_height (item);
|
app, pdb: use gimp_item_get_clip() everywhere
Remove the special clipping-mode handling for channels throughout
the transform (and drawable-filter) code, and rather use
gimp_item_get_clip(), added in the previous commit, instead. As
mentioned in the previous commit, we only modify the clipping mode
in top-level code, while having lower-level code use the clipping
mode as-is. This not only hides the actual clipping-mode logic
from the transform code, but, in particular, allows code performing
transformation internally to use arbitrary clipping modes.
Also, this commit fixes a bunch of PDB bugs all over the place :)
2019-08-10 02:51:27 +08:00
|
|
|
|
|
|
|
clip = gimp_item_get_clip (item, clip);
|
2018-09-24 00:24:50 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
orig_bounds = selection_bounds;
|
|
|
|
}
|
|
|
|
}
|
2019-08-11 03:57:55 +08:00
|
|
|
else if (GIMP_IS_ITEM (object))
|
2018-09-24 00:24:50 +08:00
|
|
|
{
|
2019-08-11 03:57:55 +08:00
|
|
|
GimpItem *item = GIMP_ITEM (object);
|
|
|
|
|
2018-09-24 00:24:50 +08:00
|
|
|
gimp_item_bounds (item,
|
|
|
|
&orig_bounds.x, &orig_bounds.y,
|
|
|
|
&orig_bounds.width, &orig_bounds.height);
|
|
|
|
|
app, pdb: use gimp_item_get_clip() everywhere
Remove the special clipping-mode handling for channels throughout
the transform (and drawable-filter) code, and rather use
gimp_item_get_clip(), added in the previous commit, instead. As
mentioned in the previous commit, we only modify the clipping mode
in top-level code, while having lower-level code use the clipping
mode as-is. This not only hides the actual clipping-mode logic
from the transform code, but, in particular, allows code performing
transformation internally to use arbitrary clipping modes.
Also, this commit fixes a bunch of PDB bugs all over the place :)
2019-08-10 02:51:27 +08:00
|
|
|
clip = gimp_item_get_clip (item, clip);
|
2018-09-24 00:24:50 +08:00
|
|
|
}
|
2019-08-11 03:57:55 +08:00
|
|
|
else
|
|
|
|
{
|
|
|
|
GimpImage *image;
|
|
|
|
|
|
|
|
g_return_val_if_fail (GIMP_IS_IMAGE (object), FALSE);
|
|
|
|
|
|
|
|
image = GIMP_IMAGE (object);
|
|
|
|
|
|
|
|
orig_bounds.x = 0;
|
|
|
|
orig_bounds.y = 0;
|
|
|
|
orig_bounds.width = gimp_image_get_width (image);
|
|
|
|
orig_bounds.height = gimp_image_get_height (image);
|
|
|
|
}
|
2018-09-24 00:24:50 +08:00
|
|
|
|
|
|
|
gimp_transform_resize_boundary (&transform, clip,
|
|
|
|
|
|
|
|
orig_bounds.x,
|
|
|
|
orig_bounds.y,
|
|
|
|
orig_bounds.x + orig_bounds.width,
|
|
|
|
orig_bounds.y + orig_bounds.height,
|
|
|
|
|
|
|
|
&new_bounds.x,
|
|
|
|
&new_bounds.y,
|
|
|
|
&new_bounds.width,
|
|
|
|
&new_bounds.height);
|
|
|
|
|
|
|
|
new_bounds.width -= new_bounds.x;
|
|
|
|
new_bounds.height -= new_bounds.y;
|
|
|
|
|
|
|
|
if (new_bounds.width > orig_bounds.width)
|
|
|
|
{
|
2019-08-11 03:57:55 +08:00
|
|
|
ratio = MAX (ratio,
|
|
|
|
(gdouble) new_bounds.width /
|
|
|
|
(gdouble) gimp_image_get_width (image));
|
2018-09-24 00:24:50 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (new_bounds.height > orig_bounds.height)
|
|
|
|
{
|
2019-08-11 03:57:55 +08:00
|
|
|
ratio = MAX (ratio,
|
|
|
|
(gdouble) new_bounds.height /
|
|
|
|
(gdouble) gimp_image_get_height (image));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ratio > max_ratio)
|
|
|
|
{
|
|
|
|
max_ratio = ratio;
|
|
|
|
max_ratio_object = object;
|
2018-09-24 00:24:50 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-08-11 03:57:55 +08:00
|
|
|
g_list_free (objects);
|
2018-09-24 00:24:50 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (max_ratio > MIN_CONFIRMATION_RATIO)
|
|
|
|
{
|
|
|
|
GtkWidget *dialog;
|
|
|
|
gint response;
|
|
|
|
|
|
|
|
dialog = gimp_message_dialog_new (_("Confirm Transformation"),
|
|
|
|
GIMP_ICON_DIALOG_WARNING,
|
|
|
|
GTK_WIDGET (shell),
|
|
|
|
GTK_DIALOG_MODAL |
|
|
|
|
GTK_DIALOG_DESTROY_WITH_PARENT,
|
|
|
|
gimp_standard_help_func, NULL,
|
|
|
|
|
|
|
|
_("_Cancel"), GTK_RESPONSE_CANCEL,
|
|
|
|
_("_Transform"), GTK_RESPONSE_OK,
|
|
|
|
|
|
|
|
NULL);
|
|
|
|
|
2018-09-24 02:08:05 +08:00
|
|
|
gimp_dialog_set_alternative_button_order (GTK_DIALOG (dialog),
|
|
|
|
GTK_RESPONSE_OK,
|
|
|
|
GTK_RESPONSE_CANCEL,
|
|
|
|
-1);
|
2018-09-24 00:24:50 +08:00
|
|
|
|
2019-08-11 03:57:55 +08:00
|
|
|
if (GIMP_IS_ITEM (max_ratio_object))
|
|
|
|
{
|
|
|
|
gimp_message_box_set_primary_text (GIMP_MESSAGE_DIALOG (dialog)->box,
|
|
|
|
_("Transformation creates "
|
|
|
|
"a very large item."));
|
|
|
|
|
|
|
|
gimp_message_box_set_text (
|
|
|
|
GIMP_MESSAGE_DIALOG (dialog)->box,
|
|
|
|
_("Applying the transformation will result "
|
|
|
|
"in an item that is over %g times larger "
|
|
|
|
"than the image."),
|
|
|
|
floor (max_ratio));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
gimp_message_box_set_primary_text (GIMP_MESSAGE_DIALOG (dialog)->box,
|
|
|
|
_("Transformation creates "
|
|
|
|
"a very large image."));
|
|
|
|
|
|
|
|
gimp_message_box_set_text (
|
|
|
|
GIMP_MESSAGE_DIALOG (dialog)->box,
|
|
|
|
_("Applying the transformation will enlarge "
|
|
|
|
"the image by a factor of %g."),
|
|
|
|
floor (max_ratio));
|
|
|
|
}
|
2018-09-24 00:24:50 +08:00
|
|
|
|
|
|
|
response = gtk_dialog_run (GTK_DIALOG (dialog));
|
|
|
|
|
|
|
|
gtk_widget_destroy (dialog);
|
|
|
|
|
|
|
|
if (response != GTK_RESPONSE_OK)
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* public functions */
|
|
|
|
|
|
|
|
|
2018-06-10 04:25:03 +08:00
|
|
|
gboolean
|
2001-03-31 22:10:22 +08:00
|
|
|
gimp_transform_tool_bounds (GimpTransformTool *tr_tool,
|
2006-03-29 01:55:52 +08:00
|
|
|
GimpDisplay *display)
|
2001-03-01 14:56:57 +08:00
|
|
|
{
|
2018-06-10 04:25:03 +08:00
|
|
|
GimpTransformOptions *options;
|
2019-09-04 23:33:47 +08:00
|
|
|
GimpDisplayShell *shell;
|
2018-06-10 04:25:03 +08:00
|
|
|
GimpImage *image;
|
2015-05-02 12:00:39 +08:00
|
|
|
gboolean non_empty = TRUE;
|
2006-06-28 02:52:24 +08:00
|
|
|
|
2018-06-10 04:25:03 +08:00
|
|
|
g_return_val_if_fail (GIMP_IS_TRANSFORM_TOOL (tr_tool), FALSE);
|
|
|
|
|
|
|
|
options = GIMP_TRANSFORM_TOOL_GET_OPTIONS (tr_tool);
|
|
|
|
image = gimp_display_get_image (display);
|
2019-09-04 23:33:47 +08:00
|
|
|
shell = gimp_display_get_shell (display);
|
2018-06-10 04:25:03 +08:00
|
|
|
|
|
|
|
g_return_val_if_fail (GIMP_IS_IMAGE (image), FALSE);
|
|
|
|
|
2011-03-27 01:45:58 +08:00
|
|
|
switch (options->type)
|
2001-03-01 14:56:57 +08:00
|
|
|
{
|
2011-03-27 01:45:58 +08:00
|
|
|
case GIMP_TRANSFORM_TYPE_LAYER:
|
|
|
|
{
|
2020-05-26 22:15:15 +08:00
|
|
|
GList *drawables;
|
|
|
|
gint offset_x;
|
|
|
|
gint offset_y;
|
|
|
|
gint x, y;
|
|
|
|
gint width, height;
|
2003-05-31 07:52:24 +08:00
|
|
|
|
2020-05-26 22:15:15 +08:00
|
|
|
drawables = gimp_image_get_selected_drawables (image);
|
2011-03-27 01:45:58 +08:00
|
|
|
|
2020-05-26 22:15:15 +08:00
|
|
|
gimp_item_get_offset (GIMP_ITEM (drawables->data), &offset_x, &offset_y);
|
2011-03-27 01:45:58 +08:00
|
|
|
|
2020-05-26 22:15:15 +08:00
|
|
|
non_empty = gimp_item_mask_intersect (GIMP_ITEM (drawables->data),
|
2015-05-02 12:00:39 +08:00
|
|
|
&x, &y, &width, &height);
|
|
|
|
tr_tool->x1 = x + offset_x;
|
|
|
|
tr_tool->y1 = y + offset_y;
|
|
|
|
tr_tool->x2 = x + width + offset_x;
|
|
|
|
tr_tool->y2 = y + height + offset_y;
|
2020-05-26 22:15:15 +08:00
|
|
|
|
|
|
|
g_list_free (drawables);
|
2011-03-27 01:45:58 +08:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case GIMP_TRANSFORM_TYPE_SELECTION:
|
2017-05-14 04:52:20 +08:00
|
|
|
{
|
|
|
|
gimp_item_bounds (GIMP_ITEM (gimp_image_get_mask (image)),
|
|
|
|
&tr_tool->x1, &tr_tool->y1,
|
|
|
|
&tr_tool->x2, &tr_tool->y2);
|
|
|
|
tr_tool->x2 += tr_tool->x1;
|
|
|
|
tr_tool->y2 += tr_tool->y1;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2011-03-27 01:45:58 +08:00
|
|
|
case GIMP_TRANSFORM_TYPE_PATH:
|
2017-05-14 04:52:20 +08:00
|
|
|
{
|
|
|
|
GimpChannel *selection = gimp_image_get_mask (image);
|
|
|
|
|
|
|
|
/* if selection is not empty, use its bounds to perform the
|
|
|
|
* transformation of the path
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (! gimp_channel_is_empty (selection))
|
|
|
|
{
|
|
|
|
gimp_item_bounds (GIMP_ITEM (selection),
|
|
|
|
&tr_tool->x1, &tr_tool->y1,
|
|
|
|
&tr_tool->x2, &tr_tool->y2);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* without selection, test the emptiness of the path bounds :
|
|
|
|
* if empty, use the canvas bounds
|
|
|
|
* else use the path bounds
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (! gimp_item_bounds (GIMP_ITEM (gimp_image_get_active_vectors (image)),
|
|
|
|
&tr_tool->x1, &tr_tool->y1,
|
|
|
|
&tr_tool->x2, &tr_tool->y2))
|
|
|
|
{
|
|
|
|
tr_tool->x1 = 0;
|
|
|
|
tr_tool->y1 = 0;
|
|
|
|
tr_tool->x2 = gimp_image_get_width (image);
|
|
|
|
tr_tool->y2 = gimp_image_get_height (image);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
tr_tool->x2 += tr_tool->x1;
|
|
|
|
tr_tool->y2 += tr_tool->y1;
|
|
|
|
}
|
|
|
|
|
2011-03-27 01:45:58 +08:00
|
|
|
break;
|
2019-08-11 03:57:55 +08:00
|
|
|
|
|
|
|
case GIMP_TRANSFORM_TYPE_IMAGE:
|
2019-09-04 23:33:47 +08:00
|
|
|
if (! shell->show_all)
|
|
|
|
{
|
|
|
|
tr_tool->x1 = 0;
|
|
|
|
tr_tool->y1 = 0;
|
|
|
|
tr_tool->x2 = gimp_image_get_width (image);
|
|
|
|
tr_tool->y2 = gimp_image_get_height (image);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
GeglRectangle bounding_box;
|
|
|
|
|
|
|
|
bounding_box = gimp_display_shell_get_bounding_box (shell);
|
|
|
|
|
|
|
|
tr_tool->x1 = bounding_box.x;
|
|
|
|
tr_tool->y1 = bounding_box.y;
|
|
|
|
tr_tool->x2 = bounding_box.x + bounding_box.width;
|
|
|
|
tr_tool->y2 = bounding_box.y + bounding_box.height;
|
|
|
|
}
|
2019-08-11 03:57:55 +08:00
|
|
|
break;
|
2001-03-01 14:56:57 +08:00
|
|
|
}
|
2001-03-09 15:09:12 +08:00
|
|
|
|
2015-05-02 12:00:39 +08:00
|
|
|
return non_empty;
|
2001-03-01 14:56:57 +08:00
|
|
|
}
|
|
|
|
|
2004-08-07 00:27:13 +08:00
|
|
|
void
|
2017-06-17 09:02:01 +08:00
|
|
|
gimp_transform_tool_recalc_matrix (GimpTransformTool *tr_tool,
|
2018-06-10 04:25:03 +08:00
|
|
|
GimpDisplay *display)
|
2001-03-01 14:56:57 +08:00
|
|
|
{
|
2011-03-27 23:38:49 +08:00
|
|
|
g_return_if_fail (GIMP_IS_TRANSFORM_TOOL (tr_tool));
|
2018-06-10 04:25:03 +08:00
|
|
|
g_return_if_fail (GIMP_IS_DISPLAY (display));
|
2011-08-13 23:42:41 +08:00
|
|
|
|
2019-09-04 23:33:47 +08:00
|
|
|
if (tr_tool->x1 == tr_tool->x2 && tr_tool->y1 == tr_tool->y2)
|
|
|
|
gimp_transform_tool_bounds (tr_tool, display);
|
2011-08-13 23:42:41 +08:00
|
|
|
|
2018-06-10 04:25:03 +08:00
|
|
|
if (GIMP_TRANSFORM_TOOL_GET_CLASS (tr_tool)->recalc_matrix)
|
|
|
|
GIMP_TRANSFORM_TOOL_GET_CLASS (tr_tool)->recalc_matrix (tr_tool);
|
2011-08-13 23:42:41 +08:00
|
|
|
}
|
2014-02-05 07:54:39 +08:00
|
|
|
|
2020-05-26 22:15:15 +08:00
|
|
|
GList *
|
|
|
|
gimp_transform_tool_get_selected_objects (GimpTransformTool *tr_tool,
|
|
|
|
GimpDisplay *display)
|
2014-02-05 07:54:39 +08:00
|
|
|
{
|
2018-06-10 04:25:03 +08:00
|
|
|
GimpTransformOptions *options;
|
|
|
|
GimpImage *image;
|
2020-05-26 22:15:15 +08:00
|
|
|
GList *objects = NULL;
|
2014-02-05 07:54:39 +08:00
|
|
|
|
2018-06-10 04:25:03 +08:00
|
|
|
g_return_val_if_fail (GIMP_IS_TRANSFORM_TOOL (tr_tool), NULL);
|
|
|
|
g_return_val_if_fail (GIMP_IS_DISPLAY (display), NULL);
|
2014-02-05 07:54:39 +08:00
|
|
|
|
2018-06-10 04:25:03 +08:00
|
|
|
options = GIMP_TRANSFORM_TOOL_GET_OPTIONS (tr_tool);
|
2014-02-05 07:54:39 +08:00
|
|
|
|
2018-06-10 04:25:03 +08:00
|
|
|
image = gimp_display_get_image (display);
|
2014-02-05 07:54:39 +08:00
|
|
|
|
2018-06-10 04:25:03 +08:00
|
|
|
g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL);
|
2014-02-05 07:54:39 +08:00
|
|
|
|
2020-05-26 22:15:15 +08:00
|
|
|
if (tr_tool->objects)
|
|
|
|
return g_list_copy (tr_tool->objects);
|
2018-10-05 09:46:10 +08:00
|
|
|
|
2014-02-05 07:54:39 +08:00
|
|
|
switch (options->type)
|
|
|
|
{
|
|
|
|
case GIMP_TRANSFORM_TYPE_LAYER:
|
2020-05-26 22:15:15 +08:00
|
|
|
objects = gimp_image_get_selected_drawables (image);
|
2018-06-10 15:48:30 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case GIMP_TRANSFORM_TYPE_SELECTION:
|
2020-05-26 22:15:15 +08:00
|
|
|
if (! gimp_channel_is_empty (gimp_image_get_mask (image)))
|
|
|
|
objects = g_list_prepend (NULL, gimp_image_get_mask (image));
|
2018-06-10 15:48:30 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case GIMP_TRANSFORM_TYPE_PATH:
|
2020-05-26 22:15:15 +08:00
|
|
|
objects = g_list_copy (gimp_image_get_selected_vectors (image));
|
2019-08-11 03:57:55 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case GIMP_TRANSFORM_TYPE_IMAGE:
|
2020-05-26 22:15:15 +08:00
|
|
|
objects = g_list_prepend (NULL, image);
|
2018-06-10 15:48:30 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2020-05-26 22:15:15 +08:00
|
|
|
return objects;
|
2018-06-10 15:48:30 +08:00
|
|
|
}
|
|
|
|
|
2020-05-26 22:15:15 +08:00
|
|
|
GList *
|
|
|
|
gimp_transform_tool_check_selected_objects (GimpTransformTool *tr_tool,
|
|
|
|
GimpDisplay *display,
|
|
|
|
GError **error)
|
2018-06-10 15:48:30 +08:00
|
|
|
{
|
|
|
|
GimpTransformOptions *options;
|
2020-05-26 22:15:15 +08:00
|
|
|
GList *objects;
|
|
|
|
GList *iter;
|
2018-06-10 15:48:30 +08:00
|
|
|
const gchar *null_message = NULL;
|
|
|
|
const gchar *locked_message = NULL;
|
2022-02-15 22:42:44 +08:00
|
|
|
GimpItem *locked_item = NULL;
|
2019-02-07 04:22:27 +08:00
|
|
|
GimpGuiConfig *config = GIMP_GUI_CONFIG (display->gimp->config);
|
2018-06-10 15:48:30 +08:00
|
|
|
|
|
|
|
g_return_val_if_fail (GIMP_IS_TRANSFORM_TOOL (tr_tool), NULL);
|
|
|
|
g_return_val_if_fail (GIMP_IS_DISPLAY (display), NULL);
|
|
|
|
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
|
|
|
|
|
|
|
|
options = GIMP_TRANSFORM_TOOL_GET_OPTIONS (tr_tool);
|
|
|
|
|
2020-05-26 22:15:15 +08:00
|
|
|
objects = gimp_transform_tool_get_selected_objects (tr_tool, display);
|
2018-06-10 15:48:30 +08:00
|
|
|
|
|
|
|
switch (options->type)
|
|
|
|
{
|
|
|
|
case GIMP_TRANSFORM_TYPE_LAYER:
|
2014-02-05 07:54:39 +08:00
|
|
|
null_message = _("There is no layer to transform.");
|
|
|
|
|
2020-05-26 22:15:15 +08:00
|
|
|
for (iter = objects; iter; iter = iter->next)
|
2014-02-05 07:54:39 +08:00
|
|
|
{
|
2020-05-26 22:15:15 +08:00
|
|
|
GimpItem *item = iter->data;
|
2019-08-11 03:57:55 +08:00
|
|
|
|
2022-02-15 22:42:44 +08:00
|
|
|
if (gimp_item_is_content_locked (item, &locked_item))
|
2020-05-26 22:15:15 +08:00
|
|
|
locked_message = _("A selected layer's pixels are locked.");
|
2017-04-03 18:39:33 +08:00
|
|
|
else if (gimp_item_is_position_locked (item))
|
2020-05-26 22:15:15 +08:00
|
|
|
locked_message = _("A selected layer's position and size are locked.");
|
2017-04-03 18:39:33 +08:00
|
|
|
|
2018-06-10 19:22:52 +08:00
|
|
|
if (! gimp_item_is_visible (item) &&
|
2019-02-07 04:22:27 +08:00
|
|
|
! config->edit_non_visible &&
|
2020-05-26 22:15:15 +08:00
|
|
|
! g_list_find (tr_tool->objects, item)) /* see bug #759194 */
|
2017-04-03 18:39:33 +08:00
|
|
|
{
|
|
|
|
g_set_error_literal (error, GIMP_ERROR, GIMP_FAILED,
|
2020-05-26 22:15:15 +08:00
|
|
|
_("A selected layer is not visible."));
|
2017-04-03 18:39:33 +08:00
|
|
|
return NULL;
|
|
|
|
}
|
2018-06-10 04:25:03 +08:00
|
|
|
|
|
|
|
if (! gimp_transform_tool_bounds (tr_tool, display))
|
|
|
|
{
|
|
|
|
g_set_error_literal (error, GIMP_ERROR, GIMP_FAILED,
|
2020-05-26 22:15:15 +08:00
|
|
|
_("The selection does not intersect with a selected layer."));
|
2018-06-10 04:25:03 +08:00
|
|
|
return NULL;
|
|
|
|
}
|
2014-02-05 07:54:39 +08:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case GIMP_TRANSFORM_TYPE_SELECTION:
|
2014-11-27 15:30:56 +08:00
|
|
|
null_message = _("There is no selection to transform.");
|
2014-02-05 07:54:39 +08:00
|
|
|
|
2020-05-26 22:15:15 +08:00
|
|
|
for (iter = objects; iter; iter = iter->next)
|
2017-04-03 18:39:33 +08:00
|
|
|
{
|
2020-05-26 22:15:15 +08:00
|
|
|
GimpItem *item = iter->data;
|
2019-08-11 03:57:55 +08:00
|
|
|
|
2017-04-03 18:39:33 +08:00
|
|
|
/* cannot happen, so don't translate these messages */
|
2022-02-15 22:42:44 +08:00
|
|
|
if (gimp_item_is_content_locked (item, &locked_item))
|
2017-04-03 18:39:33 +08:00
|
|
|
locked_message = "The selection's pixels are locked.";
|
|
|
|
else if (gimp_item_is_position_locked (item))
|
|
|
|
locked_message = "The selection's position and size are locked.";
|
|
|
|
}
|
2014-02-05 07:54:39 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case GIMP_TRANSFORM_TYPE_PATH:
|
|
|
|
null_message = _("There is no path to transform.");
|
|
|
|
|
2020-05-26 22:15:15 +08:00
|
|
|
for (iter = objects; iter; iter = iter->next)
|
2017-04-03 18:39:33 +08:00
|
|
|
{
|
2020-05-26 22:15:15 +08:00
|
|
|
GimpItem *item = iter->data;
|
2019-08-11 03:57:55 +08:00
|
|
|
|
2022-02-15 22:42:44 +08:00
|
|
|
if (gimp_item_is_content_locked (item, &locked_item))
|
|
|
|
locked_message = _("The selected path's strokes are locked.");
|
2017-04-03 18:39:33 +08:00
|
|
|
else if (gimp_item_is_position_locked (item))
|
|
|
|
locked_message = _("The active path's position is locked.");
|
2017-05-14 04:52:20 +08:00
|
|
|
else if (! gimp_vectors_get_n_strokes (GIMP_VECTORS (item)))
|
|
|
|
locked_message = _("The active path has no strokes.");
|
2017-04-03 18:39:33 +08:00
|
|
|
}
|
2014-02-05 07:54:39 +08:00
|
|
|
break;
|
2019-08-11 03:57:55 +08:00
|
|
|
|
|
|
|
case GIMP_TRANSFORM_TYPE_IMAGE:
|
|
|
|
/* cannot happen, so don't translate this message */
|
|
|
|
null_message = "There is no image to transform.";
|
|
|
|
break;
|
2014-02-05 07:54:39 +08:00
|
|
|
}
|
|
|
|
|
2020-05-26 22:15:15 +08:00
|
|
|
if (! objects)
|
2014-02-05 07:54:39 +08:00
|
|
|
{
|
|
|
|
g_set_error_literal (error, GIMP_ERROR, GIMP_FAILED, null_message);
|
2018-12-10 20:39:32 +08:00
|
|
|
if (error)
|
|
|
|
gimp_widget_blink (options->type_box);
|
2014-02-05 07:54:39 +08:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2017-04-03 18:39:33 +08:00
|
|
|
if (locked_message)
|
2014-02-05 07:54:39 +08:00
|
|
|
{
|
|
|
|
g_set_error_literal (error, GIMP_ERROR, GIMP_FAILED, locked_message);
|
2018-12-10 21:22:50 +08:00
|
|
|
if (error)
|
2022-02-15 22:42:44 +08:00
|
|
|
{
|
|
|
|
if (locked_item == NULL)
|
|
|
|
locked_item = GIMP_ITEM (objects->data);
|
|
|
|
|
|
|
|
gimp_tools_blink_lock_box (display->gimp, locked_item);
|
|
|
|
}
|
2014-02-05 07:54:39 +08:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2020-05-26 22:15:15 +08:00
|
|
|
return objects;
|
2014-02-05 07:54:39 +08:00
|
|
|
}
|
2017-04-03 18:39:33 +08:00
|
|
|
|
2018-06-10 04:25:03 +08:00
|
|
|
gboolean
|
|
|
|
gimp_transform_tool_transform (GimpTransformTool *tr_tool,
|
|
|
|
GimpDisplay *display)
|
2017-04-06 06:15:42 +08:00
|
|
|
{
|
2018-06-10 04:25:03 +08:00
|
|
|
GimpTool *tool;
|
|
|
|
GimpTransformOptions *options;
|
|
|
|
GimpImage *image;
|
2020-05-26 22:15:15 +08:00
|
|
|
GList *selected_objects;
|
2018-06-10 04:25:03 +08:00
|
|
|
GeglBuffer *orig_buffer = NULL;
|
|
|
|
gint orig_offset_x = 0;
|
|
|
|
gint orig_offset_y = 0;
|
|
|
|
GeglBuffer *new_buffer;
|
|
|
|
gint new_offset_x;
|
|
|
|
gint new_offset_y;
|
|
|
|
GimpColorProfile *buffer_profile;
|
|
|
|
gchar *undo_desc = NULL;
|
|
|
|
gboolean new_layer = FALSE;
|
|
|
|
GError *error = NULL;
|
|
|
|
|
|
|
|
g_return_val_if_fail (GIMP_IS_TRANSFORM_TOOL (tr_tool), FALSE);
|
|
|
|
g_return_val_if_fail (GIMP_IS_DISPLAY (display), FALSE);
|
|
|
|
|
|
|
|
tool = GIMP_TOOL (tr_tool);
|
|
|
|
options = GIMP_TRANSFORM_TOOL_GET_OPTIONS (tool);
|
|
|
|
image = gimp_display_get_image (display);
|
|
|
|
|
|
|
|
g_return_val_if_fail (GIMP_IS_IMAGE (image), FALSE);
|
|
|
|
|
2020-05-26 22:15:15 +08:00
|
|
|
selected_objects = gimp_transform_tool_check_selected_objects (tr_tool, display,
|
|
|
|
&error);
|
2018-06-10 04:25:03 +08:00
|
|
|
|
2020-05-26 22:15:15 +08:00
|
|
|
if (! selected_objects)
|
2017-04-06 06:15:42 +08:00
|
|
|
{
|
2018-06-10 04:25:03 +08:00
|
|
|
gimp_tool_message_literal (tool, display, error->message);
|
|
|
|
g_clear_error (&error);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
gimp_transform_tool_recalc_matrix (tr_tool, display);
|
2017-04-06 06:15:42 +08:00
|
|
|
|
2018-06-10 04:25:03 +08:00
|
|
|
if (! tr_tool->transform_valid)
|
|
|
|
{
|
|
|
|
gimp_tool_message_literal (tool, display,
|
|
|
|
_("The current transform is invalid"));
|
|
|
|
return FALSE;
|
2017-04-06 06:15:42 +08:00
|
|
|
}
|
|
|
|
|
2018-06-10 04:25:03 +08:00
|
|
|
if (GIMP_TRANSFORM_TOOL_GET_CLASS (tr_tool)->recalc_matrix &&
|
|
|
|
gimp_matrix3_is_identity (&tr_tool->transform))
|
|
|
|
{
|
|
|
|
/* No need to commit an identity transformation! */
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2018-09-24 00:24:50 +08:00
|
|
|
if (! gimp_transform_tool_confirm (tr_tool, display))
|
|
|
|
return FALSE;
|
|
|
|
|
2018-06-10 04:25:03 +08:00
|
|
|
gimp_set_busy (display->gimp);
|
|
|
|
|
|
|
|
/* We're going to dirty this image, but we want to keep the tool around */
|
|
|
|
gimp_tool_control_push_preserve (tool->control, TRUE);
|
|
|
|
|
|
|
|
undo_desc = GIMP_TRANSFORM_TOOL_GET_CLASS (tr_tool)->get_undo_desc (tr_tool);
|
|
|
|
gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_TRANSFORM, undo_desc);
|
|
|
|
g_free (undo_desc);
|
|
|
|
|
|
|
|
switch (options->type)
|
|
|
|
{
|
|
|
|
case GIMP_TRANSFORM_TYPE_LAYER:
|
2020-05-26 22:15:15 +08:00
|
|
|
if (! gimp_channel_is_empty (gimp_image_get_mask (image)))
|
2018-06-10 04:25:03 +08:00
|
|
|
{
|
2019-08-11 03:57:55 +08:00
|
|
|
orig_buffer = gimp_drawable_transform_cut (
|
2020-05-26 22:15:15 +08:00
|
|
|
selected_objects,
|
|
|
|
GIMP_CONTEXT (options),
|
2019-08-11 03:57:55 +08:00
|
|
|
&orig_offset_x,
|
|
|
|
&orig_offset_y,
|
|
|
|
&new_layer);
|
2018-06-10 04:25:03 +08:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case GIMP_TRANSFORM_TYPE_SELECTION:
|
|
|
|
case GIMP_TRANSFORM_TYPE_PATH:
|
2019-08-11 03:57:55 +08:00
|
|
|
case GIMP_TRANSFORM_TYPE_IMAGE:
|
2018-06-10 04:25:03 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Send the request for the transformation to the tool...
|
|
|
|
*/
|
2019-08-11 03:57:55 +08:00
|
|
|
new_buffer = GIMP_TRANSFORM_TOOL_GET_CLASS (tr_tool)->transform (
|
|
|
|
tr_tool,
|
2020-05-26 22:15:15 +08:00
|
|
|
selected_objects,
|
2019-08-11 03:57:55 +08:00
|
|
|
orig_buffer,
|
|
|
|
orig_offset_x,
|
|
|
|
orig_offset_y,
|
|
|
|
&buffer_profile,
|
|
|
|
&new_offset_x,
|
|
|
|
&new_offset_y);
|
2018-06-10 04:25:03 +08:00
|
|
|
|
|
|
|
if (orig_buffer)
|
|
|
|
g_object_unref (orig_buffer);
|
|
|
|
|
|
|
|
switch (options->type)
|
2017-04-06 06:15:42 +08:00
|
|
|
{
|
2018-06-10 04:25:03 +08:00
|
|
|
case GIMP_TRANSFORM_TYPE_LAYER:
|
|
|
|
if (new_buffer)
|
|
|
|
{
|
|
|
|
/* paste the new transformed image to the image...also implement
|
|
|
|
* undo...
|
|
|
|
*/
|
2020-05-26 22:15:15 +08:00
|
|
|
gimp_drawable_transform_paste (GIMP_DRAWABLE (selected_objects->data),
|
2018-06-10 04:25:03 +08:00
|
|
|
new_buffer, buffer_profile,
|
|
|
|
new_offset_x, new_offset_y,
|
|
|
|
new_layer);
|
|
|
|
g_object_unref (new_buffer);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
app, pdb: use gimp_item_get_clip() everywhere
Remove the special clipping-mode handling for channels throughout
the transform (and drawable-filter) code, and rather use
gimp_item_get_clip(), added in the previous commit, instead. As
mentioned in the previous commit, we only modify the clipping mode
in top-level code, while having lower-level code use the clipping
mode as-is. This not only hides the actual clipping-mode logic
from the transform code, but, in particular, allows code performing
transformation internally to use arbitrary clipping modes.
Also, this commit fixes a bunch of PDB bugs all over the place :)
2019-08-10 02:51:27 +08:00
|
|
|
case GIMP_TRANSFORM_TYPE_SELECTION:
|
2018-06-10 04:25:03 +08:00
|
|
|
case GIMP_TRANSFORM_TYPE_PATH:
|
2019-08-11 03:57:55 +08:00
|
|
|
case GIMP_TRANSFORM_TYPE_IMAGE:
|
2018-06-10 04:25:03 +08:00
|
|
|
/* Nothing to be done */
|
|
|
|
break;
|
2017-04-06 06:15:42 +08:00
|
|
|
}
|
|
|
|
|
2018-06-10 04:25:03 +08:00
|
|
|
gimp_image_undo_group_end (image);
|
2017-04-03 18:39:33 +08:00
|
|
|
|
2018-06-10 04:25:03 +08:00
|
|
|
/* We're done dirtying the image, and would like to be restarted if
|
|
|
|
* the image gets dirty while the tool exists
|
|
|
|
*/
|
|
|
|
gimp_tool_control_pop_preserve (tool->control);
|
|
|
|
|
|
|
|
gimp_unset_busy (display->gimp);
|
|
|
|
|
|
|
|
gimp_image_flush (image);
|
|
|
|
|
2020-05-26 22:15:15 +08:00
|
|
|
g_list_free (selected_objects);
|
|
|
|
|
2018-06-10 04:25:03 +08:00
|
|
|
return TRUE;
|
2017-04-03 18:39:33 +08:00
|
|
|
}
|
2019-08-11 04:55:56 +08:00
|
|
|
|
|
|
|
void
|
|
|
|
gimp_transform_tool_set_type (GimpTransformTool *tr_tool,
|
|
|
|
GimpTransformType type)
|
|
|
|
{
|
|
|
|
GimpTransformOptions *options;
|
|
|
|
|
|
|
|
g_return_if_fail (GIMP_IS_TRANSFORM_TOOL (tr_tool));
|
|
|
|
|
|
|
|
options = GIMP_TRANSFORM_TOOL_GET_OPTIONS (tr_tool);
|
|
|
|
|
|
|
|
if (! tr_tool->restore_type)
|
|
|
|
tr_tool->saved_type = options->type;
|
|
|
|
|
|
|
|
tr_tool->restore_type = FALSE;
|
|
|
|
|
|
|
|
g_object_set (options,
|
|
|
|
"type", type,
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
tr_tool->restore_type = TRUE;
|
|
|
|
}
|