2006-12-10 05:33:38 +08:00
|
|
|
/* GIMP - The GNU Image Manipulation Program
|
2002-02-26 01:58:50 +08:00
|
|
|
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
|
|
|
*
|
2009-01-18 06:28:01 +08:00
|
|
|
* This program is free software: you can redistribute it and/or modify
|
2002-02-26 01:58:50 +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
|
2002-02-26 01:58:50 +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/>.
|
2002-02-26 01:58:50 +08:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
2013-10-15 07:58:39 +08:00
|
|
|
#include <gdk-pixbuf/gdk-pixbuf.h>
|
2008-10-10 04:24:04 +08:00
|
|
|
#include <gegl.h>
|
2002-02-26 01:58:50 +08:00
|
|
|
|
|
|
|
#include "libgimpbase/gimpbase.h"
|
2007-03-09 21:00:01 +08:00
|
|
|
#include "libgimpmath/gimpmath.h"
|
2002-02-26 01:58:50 +08:00
|
|
|
|
|
|
|
#include "core-types.h"
|
|
|
|
|
|
|
|
#include "gimp.h"
|
2002-05-15 19:05:32 +08:00
|
|
|
#include "gimp-parasites.h"
|
2010-09-08 03:28:00 +08:00
|
|
|
#include "gimpchannel.h"
|
2011-05-05 04:14:13 +08:00
|
|
|
#include "gimpidtable.h"
|
2002-02-26 01:58:50 +08:00
|
|
|
#include "gimpimage.h"
|
2003-02-13 19:23:50 +08:00
|
|
|
#include "gimpimage-undo.h"
|
2003-02-14 22:14:29 +08:00
|
|
|
#include "gimpimage-undo-push.h"
|
2002-02-26 01:58:50 +08:00
|
|
|
#include "gimpitem.h"
|
2012-11-09 18:17:25 +08:00
|
|
|
#include "gimpitem-linked.h"
|
2003-09-30 07:14:28 +08:00
|
|
|
#include "gimpitem-preview.h"
|
2010-02-06 23:17:23 +08:00
|
|
|
#include "gimpitemtree.h"
|
2002-02-26 01:58:50 +08:00
|
|
|
#include "gimplist.h"
|
|
|
|
#include "gimpmarshal.h"
|
|
|
|
#include "gimpparasitelist.h"
|
2004-08-11 02:47:21 +08:00
|
|
|
#include "gimpprogress.h"
|
2008-10-24 15:37:46 +08:00
|
|
|
#include "gimpstrokeoptions.h"
|
2002-02-26 01:58:50 +08:00
|
|
|
|
2014-02-07 06:20:39 +08:00
|
|
|
#include "paint/gimppaintoptions.h"
|
|
|
|
|
2003-03-26 00:38:19 +08:00
|
|
|
#include "gimp-intl.h"
|
2002-02-26 01:58:50 +08:00
|
|
|
|
|
|
|
|
|
|
|
enum
|
|
|
|
{
|
|
|
|
REMOVED,
|
app: add GimpFilter::active property; move ::visible to GimpItem
Add an "active" property to GimpFilter, which replaces its
"visible" property. The new property assumes the lower-level role
"visible" had -- controlling whether the filter has any effect as
part of its parent filter-stack.
Add a "visible" property to GimpItem, separate from the "active"
property, which assumes the higher-level role "visible" had --
controlling whether the item is considered "visible", as per the
GUI. By default, the item's "visible" property is bound to the
filter's "active" property, so that changes in visibility directly
affect the filter's "activeness"; this binding can be controlled
using the new gimp_item_bind_visible_to_active() function.
This distinction is currently necessary for floating selections.
Floating selection layers must not be active in their parent stack,
regardless of their visibility, in particular, so that their mode
node doesn't hide the entire backdrop when their composite mode
excludes the backdrop (i.e., when it's dst-atop or src-in).
Instead, their visibility should affect the activeness of the
floating-selection filter of the drawable they're attached to.
This is handled by the next commit.
2017-12-06 02:46:50 +08:00
|
|
|
VISIBILITY_CHANGED,
|
2003-05-09 04:26:01 +08:00
|
|
|
LINKED_CHANGED,
|
2016-10-29 22:50:13 +08:00
|
|
|
COLOR_TAG_CHANGED,
|
2009-08-19 19:37:41 +08:00
|
|
|
LOCK_CONTENT_CHANGED,
|
2012-11-09 18:17:25 +08:00
|
|
|
LOCK_POSITION_CHANGED,
|
2002-02-26 01:58:50 +08:00
|
|
|
LAST_SIGNAL
|
|
|
|
};
|
|
|
|
|
2005-09-20 18:30:01 +08:00
|
|
|
enum
|
|
|
|
{
|
|
|
|
PROP_0,
|
2011-02-01 17:28:10 +08:00
|
|
|
PROP_IMAGE,
|
2005-09-20 18:30:01 +08:00
|
|
|
PROP_ID,
|
|
|
|
PROP_WIDTH,
|
2008-11-12 05:14:52 +08:00
|
|
|
PROP_HEIGHT,
|
|
|
|
PROP_OFFSET_X,
|
2008-11-13 23:06:34 +08:00
|
|
|
PROP_OFFSET_Y,
|
app: add GimpFilter::active property; move ::visible to GimpItem
Add an "active" property to GimpFilter, which replaces its
"visible" property. The new property assumes the lower-level role
"visible" had -- controlling whether the filter has any effect as
part of its parent filter-stack.
Add a "visible" property to GimpItem, separate from the "active"
property, which assumes the higher-level role "visible" had --
controlling whether the item is considered "visible", as per the
GUI. By default, the item's "visible" property is bound to the
filter's "active" property, so that changes in visibility directly
affect the filter's "activeness"; this binding can be controlled
using the new gimp_item_bind_visible_to_active() function.
This distinction is currently necessary for floating selections.
Floating selection layers must not be active in their parent stack,
regardless of their visibility, in particular, so that their mode
node doesn't hide the entire backdrop when their composite mode
excludes the backdrop (i.e., when it's dst-atop or src-in).
Instead, their visibility should affect the activeness of the
floating-selection filter of the drawable they're attached to.
This is handled by the next commit.
2017-12-06 02:46:50 +08:00
|
|
|
PROP_VISIBLE,
|
2009-08-19 19:37:41 +08:00
|
|
|
PROP_LINKED,
|
2016-10-29 22:50:13 +08:00
|
|
|
PROP_COLOR_TAG,
|
2012-11-09 18:17:25 +08:00
|
|
|
PROP_LOCK_CONTENT,
|
|
|
|
PROP_LOCK_POSITION
|
2005-09-20 18:30:01 +08:00
|
|
|
};
|
|
|
|
|
2002-02-26 01:58:50 +08:00
|
|
|
|
2011-01-31 04:49:51 +08:00
|
|
|
typedef struct _GimpItemPrivate GimpItemPrivate;
|
|
|
|
|
|
|
|
struct _GimpItemPrivate
|
|
|
|
{
|
app: add GimpFilter::active property; move ::visible to GimpItem
Add an "active" property to GimpFilter, which replaces its
"visible" property. The new property assumes the lower-level role
"visible" had -- controlling whether the filter has any effect as
part of its parent filter-stack.
Add a "visible" property to GimpItem, separate from the "active"
property, which assumes the higher-level role "visible" had --
controlling whether the item is considered "visible", as per the
GUI. By default, the item's "visible" property is bound to the
filter's "active" property, so that changes in visibility directly
affect the filter's "activeness"; this binding can be controlled
using the new gimp_item_bind_visible_to_active() function.
This distinction is currently necessary for floating selections.
Floating selection layers must not be active in their parent stack,
regardless of their visibility, in particular, so that their mode
node doesn't hide the entire backdrop when their composite mode
excludes the backdrop (i.e., when it's dst-atop or src-in).
Instead, their visibility should affect the activeness of the
floating-selection filter of the drawable they're attached to.
This is handled by the next commit.
2017-12-06 02:46:50 +08:00
|
|
|
gint ID; /* provides a unique ID */
|
|
|
|
guint32 tattoo; /* provides a permanent ID */
|
2011-01-31 04:49:51 +08:00
|
|
|
|
app: add GimpFilter::active property; move ::visible to GimpItem
Add an "active" property to GimpFilter, which replaces its
"visible" property. The new property assumes the lower-level role
"visible" had -- controlling whether the filter has any effect as
part of its parent filter-stack.
Add a "visible" property to GimpItem, separate from the "active"
property, which assumes the higher-level role "visible" had --
controlling whether the item is considered "visible", as per the
GUI. By default, the item's "visible" property is bound to the
filter's "active" property, so that changes in visibility directly
affect the filter's "activeness"; this binding can be controlled
using the new gimp_item_bind_visible_to_active() function.
This distinction is currently necessary for floating selections.
Floating selection layers must not be active in their parent stack,
regardless of their visibility, in particular, so that their mode
node doesn't hide the entire backdrop when their composite mode
excludes the backdrop (i.e., when it's dst-atop or src-in).
Instead, their visibility should affect the activeness of the
floating-selection filter of the drawable they're attached to.
This is handled by the next commit.
2017-12-06 02:46:50 +08:00
|
|
|
GimpImage *image; /* item owner */
|
2011-01-31 04:49:51 +08:00
|
|
|
|
app: add GimpFilter::active property; move ::visible to GimpItem
Add an "active" property to GimpFilter, which replaces its
"visible" property. The new property assumes the lower-level role
"visible" had -- controlling whether the filter has any effect as
part of its parent filter-stack.
Add a "visible" property to GimpItem, separate from the "active"
property, which assumes the higher-level role "visible" had --
controlling whether the item is considered "visible", as per the
GUI. By default, the item's "visible" property is bound to the
filter's "active" property, so that changes in visibility directly
affect the filter's "activeness"; this binding can be controlled
using the new gimp_item_bind_visible_to_active() function.
This distinction is currently necessary for floating selections.
Floating selection layers must not be active in their parent stack,
regardless of their visibility, in particular, so that their mode
node doesn't hide the entire backdrop when their composite mode
excludes the backdrop (i.e., when it's dst-atop or src-in).
Instead, their visibility should affect the activeness of the
floating-selection filter of the drawable they're attached to.
This is handled by the next commit.
2017-12-06 02:46:50 +08:00
|
|
|
GimpParasiteList *parasites; /* Plug-in parasite data */
|
2011-01-31 04:49:51 +08:00
|
|
|
|
app: add GimpFilter::active property; move ::visible to GimpItem
Add an "active" property to GimpFilter, which replaces its
"visible" property. The new property assumes the lower-level role
"visible" had -- controlling whether the filter has any effect as
part of its parent filter-stack.
Add a "visible" property to GimpItem, separate from the "active"
property, which assumes the higher-level role "visible" had --
controlling whether the item is considered "visible", as per the
GUI. By default, the item's "visible" property is bound to the
filter's "active" property, so that changes in visibility directly
affect the filter's "activeness"; this binding can be controlled
using the new gimp_item_bind_visible_to_active() function.
This distinction is currently necessary for floating selections.
Floating selection layers must not be active in their parent stack,
regardless of their visibility, in particular, so that their mode
node doesn't hide the entire backdrop when their composite mode
excludes the backdrop (i.e., when it's dst-atop or src-in).
Instead, their visibility should affect the activeness of the
floating-selection filter of the drawable they're attached to.
This is handled by the next commit.
2017-12-06 02:46:50 +08:00
|
|
|
gint width, height; /* size in pixels */
|
|
|
|
gint offset_x, offset_y; /* pixel offset in image */
|
2011-01-31 04:49:51 +08:00
|
|
|
|
app: add GimpFilter::active property; move ::visible to GimpItem
Add an "active" property to GimpFilter, which replaces its
"visible" property. The new property assumes the lower-level role
"visible" had -- controlling whether the filter has any effect as
part of its parent filter-stack.
Add a "visible" property to GimpItem, separate from the "active"
property, which assumes the higher-level role "visible" had --
controlling whether the item is considered "visible", as per the
GUI. By default, the item's "visible" property is bound to the
filter's "active" property, so that changes in visibility directly
affect the filter's "activeness"; this binding can be controlled
using the new gimp_item_bind_visible_to_active() function.
This distinction is currently necessary for floating selections.
Floating selection layers must not be active in their parent stack,
regardless of their visibility, in particular, so that their mode
node doesn't hide the entire backdrop when their composite mode
excludes the backdrop (i.e., when it's dst-atop or src-in).
Instead, their visibility should affect the activeness of the
floating-selection filter of the drawable they're attached to.
This is handled by the next commit.
2017-12-06 02:46:50 +08:00
|
|
|
guint visible : 1; /* item visibility */
|
|
|
|
guint bind_visible_to_active : 1; /* visibility bound to active */
|
2011-01-31 04:49:51 +08:00
|
|
|
|
app: add GimpFilter::active property; move ::visible to GimpItem
Add an "active" property to GimpFilter, which replaces its
"visible" property. The new property assumes the lower-level role
"visible" had -- controlling whether the filter has any effect as
part of its parent filter-stack.
Add a "visible" property to GimpItem, separate from the "active"
property, which assumes the higher-level role "visible" had --
controlling whether the item is considered "visible", as per the
GUI. By default, the item's "visible" property is bound to the
filter's "active" property, so that changes in visibility directly
affect the filter's "activeness"; this binding can be controlled
using the new gimp_item_bind_visible_to_active() function.
This distinction is currently necessary for floating selections.
Floating selection layers must not be active in their parent stack,
regardless of their visibility, in particular, so that their mode
node doesn't hide the entire backdrop when their composite mode
excludes the backdrop (i.e., when it's dst-atop or src-in).
Instead, their visibility should affect the activeness of the
floating-selection filter of the drawable they're attached to.
This is handled by the next commit.
2017-12-06 02:46:50 +08:00
|
|
|
guint linked : 1; /* control linkage */
|
|
|
|
guint lock_content : 1; /* content editability */
|
|
|
|
guint lock_position : 1; /* content movability */
|
2016-10-29 22:50:13 +08:00
|
|
|
|
app: add GimpFilter::active property; move ::visible to GimpItem
Add an "active" property to GimpFilter, which replaces its
"visible" property. The new property assumes the lower-level role
"visible" had -- controlling whether the filter has any effect as
part of its parent filter-stack.
Add a "visible" property to GimpItem, separate from the "active"
property, which assumes the higher-level role "visible" had --
controlling whether the item is considered "visible", as per the
GUI. By default, the item's "visible" property is bound to the
filter's "active" property, so that changes in visibility directly
affect the filter's "activeness"; this binding can be controlled
using the new gimp_item_bind_visible_to_active() function.
This distinction is currently necessary for floating selections.
Floating selection layers must not be active in their parent stack,
regardless of their visibility, in particular, so that their mode
node doesn't hide the entire backdrop when their composite mode
excludes the backdrop (i.e., when it's dst-atop or src-in).
Instead, their visibility should affect the activeness of the
floating-selection filter of the drawable they're attached to.
This is handled by the next commit.
2017-12-06 02:46:50 +08:00
|
|
|
guint removed : 1; /* removed from the image? */
|
2011-01-31 04:49:51 +08:00
|
|
|
|
app: add GimpFilter::active property; move ::visible to GimpItem
Add an "active" property to GimpFilter, which replaces its
"visible" property. The new property assumes the lower-level role
"visible" had -- controlling whether the filter has any effect as
part of its parent filter-stack.
Add a "visible" property to GimpItem, separate from the "active"
property, which assumes the higher-level role "visible" had --
controlling whether the item is considered "visible", as per the
GUI. By default, the item's "visible" property is bound to the
filter's "active" property, so that changes in visibility directly
affect the filter's "activeness"; this binding can be controlled
using the new gimp_item_bind_visible_to_active() function.
This distinction is currently necessary for floating selections.
Floating selection layers must not be active in their parent stack,
regardless of their visibility, in particular, so that their mode
node doesn't hide the entire backdrop when their composite mode
excludes the backdrop (i.e., when it's dst-atop or src-in).
Instead, their visibility should affect the activeness of the
floating-selection filter of the drawable they're attached to.
This is handled by the next commit.
2017-12-06 02:46:50 +08:00
|
|
|
GimpColorTag color_tag; /* color tag */
|
|
|
|
|
|
|
|
GList *offset_nodes; /* offset nodes to manage */
|
2011-01-31 04:49:51 +08:00
|
|
|
};
|
|
|
|
|
app, libgimp*, modules: don't use g_type_class_add_private() ...
... and G_TYPE_INSTANCE_GET_PRIVATE()
g_type_class_add_private() and G_TYPE_INSTANCE_GET_PRIVATE() were
deprecated in GLib 2.58. Instead, use
G_DEFINE_[ABSTRACT_]TYPE_WITH_PRIVATE(), and
G_ADD_PRIVATE[_DYNAMIC](), and the implictly-defined
foo_get_instance_private() functions, all of which are available in
the GLib versions we depend on.
This commit only covers types registered using one of the
G_DEFINE_FOO() macros (i.e., most types), but not types with a
custom registration function, of which we still have a few -- GLib
currently only provides a (non-deprecated) public API for adding a
private struct using the G_DEFINE_FOO() macros.
Note that this commit was 99% auto-generated (because I'm not
*that* crazy :), so if there are any style mismatches... we'll have
to live with them for now.
2018-09-19 00:09:39 +08:00
|
|
|
#define GET_PRIVATE(item) ((GimpItemPrivate *) gimp_item_get_instance_private ((GimpItem *) (item)))
|
2011-01-31 04:49:51 +08:00
|
|
|
|
|
|
|
|
2002-02-26 01:58:50 +08:00
|
|
|
/* local function prototypes */
|
|
|
|
|
2011-02-01 17:28:10 +08:00
|
|
|
static void gimp_item_constructed (GObject *object);
|
|
|
|
static void gimp_item_finalize (GObject *object);
|
2009-08-29 20:59:07 +08:00
|
|
|
static void gimp_item_set_property (GObject *object,
|
|
|
|
guint property_id,
|
|
|
|
const GValue *value,
|
|
|
|
GParamSpec *pspec);
|
|
|
|
static void gimp_item_get_property (GObject *object,
|
|
|
|
guint property_id,
|
|
|
|
GValue *value,
|
|
|
|
GParamSpec *pspec);
|
|
|
|
|
|
|
|
static gint64 gimp_item_get_memsize (GimpObject *object,
|
|
|
|
gint64 *gui_size);
|
|
|
|
|
2016-05-20 05:51:44 +08:00
|
|
|
static gboolean gimp_item_real_is_content_locked (GimpItem *item);
|
|
|
|
static gboolean gimp_item_real_is_position_locked (GimpItem *item);
|
2015-06-30 18:34:46 +08:00
|
|
|
static gboolean gimp_item_real_bounds (GimpItem *item,
|
|
|
|
gdouble *x,
|
|
|
|
gdouble *y,
|
|
|
|
gdouble *width,
|
|
|
|
gdouble *height);
|
2009-08-29 20:59:07 +08:00
|
|
|
static GimpItem * gimp_item_real_duplicate (GimpItem *item,
|
|
|
|
GType new_type);
|
|
|
|
static void gimp_item_real_convert (GimpItem *item,
|
2015-08-16 21:47:43 +08:00
|
|
|
GimpImage *dest_image,
|
|
|
|
GType old_type);
|
2009-08-29 20:59:07 +08:00
|
|
|
static gboolean gimp_item_real_rename (GimpItem *item,
|
|
|
|
const gchar *new_name,
|
|
|
|
const gchar *undo_desc,
|
|
|
|
GError **error);
|
Bug 795410 - Deleting a layer group and then undoing the deletion ...
... raises a CRITICAL
gimp_item_{start,end}_move() currently serves two different
purposes: It is used by GimpLayer to suspend/resume mask resizing
of the layer's ancestors; this is necessary whenever an operation
on a layer might affect the size of its ancestors. It is also used
by GimpGroupLayer to suspend/resume its own mask resizing; this, on
the other hand, is only necessary before applying one of the
transformation functions to the group, so that mask modification is
handled by GimpLayer. In other words, the effects of
gimp_item_{start,end}_move() on group layers are only necessary in
a subset of the cases in which these functions are used.
While in itself this isn't a problem, it does cause issues when
removing a group layer: gimp_image_remove_layer() calls
gimp_item_start_move() before removing the layer, and
gimp_item_end_move() afterwards. While the former function is
called while the layer is still attached to the image, the latter
function is called after the layer is no longer attached. Since
GimpGroupLayer pushes an undo step in response to these calls, only
the call to start_move() results in an undo step, while the call to
end_move() doesn't, resulting in an unbalanced
GIMP_UNDO_GROUP_LAYER_START_MOVE undo step on the stack. This
causes problems when undoing the operation.
Add gimp_item_{start,end}_transform() functions, and corresponding
GimpItem::{start,end}_transform() virtual functions, which are more
specialized versions of gimp_item_{start,end}_move(), which should
be used instead of the former before/after transforming an item; in
other cases, such as when removing ot reordering an item,
gimp_item_{start,end}_move() should still be used. The default
implementation of GimpItem::{start,end}_transform() calls
gimp_item_{start,end}_move(), respectively, so subclasses that
override these functions don't have to do that themselves.
In GimpGroupLayer, override GimpItem::{start,end}_transform(),
instead of GimpItem::{start,end}_move(), for the same purpose of
suspending mask resize. This avoids these functions from being
called when removing a layer group, fixing the bug.
2018-04-22 15:39:40 +08:00
|
|
|
static void gimp_item_real_start_transform (GimpItem *item,
|
|
|
|
gboolean push_undo);
|
|
|
|
static void gimp_item_real_end_transform (GimpItem *item,
|
|
|
|
gboolean push_undo);
|
2009-08-29 20:59:07 +08:00
|
|
|
static void gimp_item_real_translate (GimpItem *item,
|
2018-04-23 07:08:54 +08:00
|
|
|
gdouble offset_x,
|
|
|
|
gdouble offset_y,
|
2009-08-29 20:59:07 +08:00
|
|
|
gboolean push_undo);
|
|
|
|
static void gimp_item_real_scale (GimpItem *item,
|
|
|
|
gint new_width,
|
|
|
|
gint new_height,
|
|
|
|
gint new_offset_x,
|
|
|
|
gint new_offset_y,
|
|
|
|
GimpInterpolationType interpolation,
|
|
|
|
GimpProgress *progress);
|
|
|
|
static void gimp_item_real_resize (GimpItem *item,
|
|
|
|
GimpContext *context,
|
2016-10-10 06:02:16 +08:00
|
|
|
GimpFillType fill_type,
|
2009-08-29 20:59:07 +08:00
|
|
|
gint new_width,
|
|
|
|
gint new_height,
|
|
|
|
gint offset_x,
|
|
|
|
gint offset_y);
|
2002-02-26 01:58:50 +08:00
|
|
|
|
|
|
|
|
2016-11-16 22:13:08 +08:00
|
|
|
|
app, libgimp*, modules: don't use g_type_class_add_private() ...
... and G_TYPE_INSTANCE_GET_PRIVATE()
g_type_class_add_private() and G_TYPE_INSTANCE_GET_PRIVATE() were
deprecated in GLib 2.58. Instead, use
G_DEFINE_[ABSTRACT_]TYPE_WITH_PRIVATE(), and
G_ADD_PRIVATE[_DYNAMIC](), and the implictly-defined
foo_get_instance_private() functions, all of which are available in
the GLib versions we depend on.
This commit only covers types registered using one of the
G_DEFINE_FOO() macros (i.e., most types), but not types with a
custom registration function, of which we still have a few -- GLib
currently only provides a (non-deprecated) public API for adding a
private struct using the G_DEFINE_FOO() macros.
Note that this commit was 99% auto-generated (because I'm not
*that* crazy :), so if there are any style mismatches... we'll have
to live with them for now.
2018-09-19 00:09:39 +08:00
|
|
|
G_DEFINE_TYPE_WITH_PRIVATE (GimpItem, gimp_item, GIMP_TYPE_FILTER)
|
2002-02-26 01:58:50 +08:00
|
|
|
|
2005-12-11 03:24:36 +08:00
|
|
|
#define parent_class gimp_item_parent_class
|
2002-02-26 01:58:50 +08:00
|
|
|
|
2005-12-11 03:24:36 +08:00
|
|
|
static guint gimp_item_signals[LAST_SIGNAL] = { 0 };
|
2002-02-26 01:58:50 +08:00
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
gimp_item_class_init (GimpItemClass *klass)
|
|
|
|
{
|
2004-07-14 19:52:03 +08:00
|
|
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
|
|
|
GimpObjectClass *gimp_object_class = GIMP_OBJECT_CLASS (klass);
|
|
|
|
GimpViewableClass *viewable_class = GIMP_VIEWABLE_CLASS (klass);
|
2002-02-26 01:58:50 +08:00
|
|
|
|
|
|
|
gimp_item_signals[REMOVED] =
|
|
|
|
g_signal_new ("removed",
|
2004-07-14 19:52:03 +08:00
|
|
|
G_TYPE_FROM_CLASS (klass),
|
|
|
|
G_SIGNAL_RUN_FIRST,
|
|
|
|
G_STRUCT_OFFSET (GimpItemClass, removed),
|
|
|
|
NULL, NULL,
|
|
|
|
gimp_marshal_VOID__VOID,
|
|
|
|
G_TYPE_NONE, 0);
|
2002-02-26 01:58:50 +08:00
|
|
|
|
app: add GimpFilter::active property; move ::visible to GimpItem
Add an "active" property to GimpFilter, which replaces its
"visible" property. The new property assumes the lower-level role
"visible" had -- controlling whether the filter has any effect as
part of its parent filter-stack.
Add a "visible" property to GimpItem, separate from the "active"
property, which assumes the higher-level role "visible" had --
controlling whether the item is considered "visible", as per the
GUI. By default, the item's "visible" property is bound to the
filter's "active" property, so that changes in visibility directly
affect the filter's "activeness"; this binding can be controlled
using the new gimp_item_bind_visible_to_active() function.
This distinction is currently necessary for floating selections.
Floating selection layers must not be active in their parent stack,
regardless of their visibility, in particular, so that their mode
node doesn't hide the entire backdrop when their composite mode
excludes the backdrop (i.e., when it's dst-atop or src-in).
Instead, their visibility should affect the activeness of the
floating-selection filter of the drawable they're attached to.
This is handled by the next commit.
2017-12-06 02:46:50 +08:00
|
|
|
gimp_item_signals[VISIBILITY_CHANGED] =
|
|
|
|
g_signal_new ("visibility-changed",
|
|
|
|
G_TYPE_FROM_CLASS (klass),
|
|
|
|
G_SIGNAL_RUN_FIRST,
|
|
|
|
G_STRUCT_OFFSET (GimpItemClass, visibility_changed),
|
|
|
|
NULL, NULL,
|
|
|
|
gimp_marshal_VOID__VOID,
|
|
|
|
G_TYPE_NONE, 0);
|
|
|
|
|
2003-05-09 04:26:01 +08:00
|
|
|
gimp_item_signals[LINKED_CHANGED] =
|
2005-05-27 21:05:26 +08:00
|
|
|
g_signal_new ("linked-changed",
|
2004-07-14 19:52:03 +08:00
|
|
|
G_TYPE_FROM_CLASS (klass),
|
|
|
|
G_SIGNAL_RUN_FIRST,
|
|
|
|
G_STRUCT_OFFSET (GimpItemClass, linked_changed),
|
|
|
|
NULL, NULL,
|
|
|
|
gimp_marshal_VOID__VOID,
|
|
|
|
G_TYPE_NONE, 0);
|
2003-05-09 04:26:01 +08:00
|
|
|
|
2016-10-29 22:50:13 +08:00
|
|
|
gimp_item_signals[COLOR_TAG_CHANGED] =
|
|
|
|
g_signal_new ("color-tag-changed",
|
|
|
|
G_TYPE_FROM_CLASS (klass),
|
|
|
|
G_SIGNAL_RUN_FIRST,
|
|
|
|
G_STRUCT_OFFSET (GimpItemClass, color_tag_changed),
|
|
|
|
NULL, NULL,
|
|
|
|
gimp_marshal_VOID__VOID,
|
|
|
|
G_TYPE_NONE, 0);
|
|
|
|
|
2009-08-19 19:37:41 +08:00
|
|
|
gimp_item_signals[LOCK_CONTENT_CHANGED] =
|
|
|
|
g_signal_new ("lock-content-changed",
|
|
|
|
G_TYPE_FROM_CLASS (klass),
|
|
|
|
G_SIGNAL_RUN_FIRST,
|
|
|
|
G_STRUCT_OFFSET (GimpItemClass, lock_content_changed),
|
|
|
|
NULL, NULL,
|
|
|
|
gimp_marshal_VOID__VOID,
|
|
|
|
G_TYPE_NONE, 0);
|
|
|
|
|
2012-11-09 18:17:25 +08:00
|
|
|
gimp_item_signals[LOCK_POSITION_CHANGED] =
|
|
|
|
g_signal_new ("lock-position-changed",
|
|
|
|
G_TYPE_FROM_CLASS (klass),
|
|
|
|
G_SIGNAL_RUN_FIRST,
|
|
|
|
G_STRUCT_OFFSET (GimpItemClass, lock_position_changed),
|
|
|
|
NULL, NULL,
|
|
|
|
gimp_marshal_VOID__VOID,
|
|
|
|
G_TYPE_NONE, 0);
|
|
|
|
|
2011-02-01 17:28:10 +08:00
|
|
|
object_class->constructed = gimp_item_constructed;
|
|
|
|
object_class->finalize = gimp_item_finalize;
|
2005-09-20 18:30:01 +08:00
|
|
|
object_class->set_property = gimp_item_set_property;
|
|
|
|
object_class->get_property = gimp_item_get_property;
|
2003-09-30 07:14:28 +08:00
|
|
|
|
|
|
|
gimp_object_class->get_memsize = gimp_item_get_memsize;
|
|
|
|
|
2016-11-16 22:13:08 +08:00
|
|
|
viewable_class->name_editable = TRUE;
|
2003-09-30 07:14:28 +08:00
|
|
|
viewable_class->get_preview_size = gimp_item_get_preview_size;
|
|
|
|
viewable_class->get_popup_size = gimp_item_get_popup_size;
|
|
|
|
|
|
|
|
klass->removed = NULL;
|
app: add GimpFilter::active property; move ::visible to GimpItem
Add an "active" property to GimpFilter, which replaces its
"visible" property. The new property assumes the lower-level role
"visible" had -- controlling whether the filter has any effect as
part of its parent filter-stack.
Add a "visible" property to GimpItem, separate from the "active"
property, which assumes the higher-level role "visible" had --
controlling whether the item is considered "visible", as per the
GUI. By default, the item's "visible" property is bound to the
filter's "active" property, so that changes in visibility directly
affect the filter's "activeness"; this binding can be controlled
using the new gimp_item_bind_visible_to_active() function.
This distinction is currently necessary for floating selections.
Floating selection layers must not be active in their parent stack,
regardless of their visibility, in particular, so that their mode
node doesn't hide the entire backdrop when their composite mode
excludes the backdrop (i.e., when it's dst-atop or src-in).
Instead, their visibility should affect the activeness of the
floating-selection filter of the drawable they're attached to.
This is handled by the next commit.
2017-12-06 02:46:50 +08:00
|
|
|
klass->visibility_changed = NULL;
|
2003-09-30 07:14:28 +08:00
|
|
|
klass->linked_changed = NULL;
|
2016-10-29 22:50:13 +08:00
|
|
|
klass->color_tag_changed = NULL;
|
2009-08-19 19:37:41 +08:00
|
|
|
klass->lock_content_changed = NULL;
|
2012-11-09 18:17:25 +08:00
|
|
|
klass->lock_position_changed = NULL;
|
2003-09-30 07:14:28 +08:00
|
|
|
|
2011-02-03 02:40:20 +08:00
|
|
|
klass->unset_removed = NULL;
|
2004-01-27 00:18:16 +08:00
|
|
|
klass->is_attached = NULL;
|
2009-08-29 20:59:07 +08:00
|
|
|
klass->is_content_locked = gimp_item_real_is_content_locked;
|
2012-11-09 18:17:25 +08:00
|
|
|
klass->is_position_locked = gimp_item_real_is_position_locked;
|
2010-02-06 23:17:23 +08:00
|
|
|
klass->get_tree = NULL;
|
2015-06-30 18:34:46 +08:00
|
|
|
klass->bounds = gimp_item_real_bounds;
|
2003-09-30 07:14:28 +08:00
|
|
|
klass->duplicate = gimp_item_real_duplicate;
|
2005-01-14 02:17:24 +08:00
|
|
|
klass->convert = gimp_item_real_convert;
|
2003-09-30 07:14:28 +08:00
|
|
|
klass->rename = gimp_item_real_rename;
|
app: add gimp_item_{start,end}_move()
Add gimp_item_{start,end}_move(), and corresponding
GimpItem::{start,end}_move() virtual functions, which should be
called before/after "moving" the item (i.e., translating, scaling,
resizing, flipping, rotating, or transforming the item). Moves
performed between the outermost pair of start/end calls are treated
atomically.
What exactly does "treated atomically" entail depends on the
subclasses -- GimpItem doesn't provide a default implementation for
these functions, so the current commit doesn't change any behavior.
The next commit, which adds layer-mask support for group layers,
uses the functions to avoid cropping the mask too early while a
child is moving.
GimpItem calls {start,end}_move() in the various "move" functions
(gimp_item_{translate,scale,...}(), before performing the actual
operation. Additionally we call the functions in the
gimp_image_item_list_foo() functions, for each participating item,
so that the items are moved as a unit. We call the functions in
the various gimp_image_remove_foo() functions, since removing an
item may affect the size of its ancestors, and is therefore akin to
moving. We also call the functions in GimpEditSelectionTool, so
that the move tool moves items atomically while dragging.
2018-02-05 23:59:28 +08:00
|
|
|
klass->start_move = NULL;
|
|
|
|
klass->end_move = NULL;
|
Bug 795410 - Deleting a layer group and then undoing the deletion ...
... raises a CRITICAL
gimp_item_{start,end}_move() currently serves two different
purposes: It is used by GimpLayer to suspend/resume mask resizing
of the layer's ancestors; this is necessary whenever an operation
on a layer might affect the size of its ancestors. It is also used
by GimpGroupLayer to suspend/resume its own mask resizing; this, on
the other hand, is only necessary before applying one of the
transformation functions to the group, so that mask modification is
handled by GimpLayer. In other words, the effects of
gimp_item_{start,end}_move() on group layers are only necessary in
a subset of the cases in which these functions are used.
While in itself this isn't a problem, it does cause issues when
removing a group layer: gimp_image_remove_layer() calls
gimp_item_start_move() before removing the layer, and
gimp_item_end_move() afterwards. While the former function is
called while the layer is still attached to the image, the latter
function is called after the layer is no longer attached. Since
GimpGroupLayer pushes an undo step in response to these calls, only
the call to start_move() results in an undo step, while the call to
end_move() doesn't, resulting in an unbalanced
GIMP_UNDO_GROUP_LAYER_START_MOVE undo step on the stack. This
causes problems when undoing the operation.
Add gimp_item_{start,end}_transform() functions, and corresponding
GimpItem::{start,end}_transform() virtual functions, which are more
specialized versions of gimp_item_{start,end}_move(), which should
be used instead of the former before/after transforming an item; in
other cases, such as when removing ot reordering an item,
gimp_item_{start,end}_move() should still be used. The default
implementation of GimpItem::{start,end}_transform() calls
gimp_item_{start,end}_move(), respectively, so subclasses that
override these functions don't have to do that themselves.
In GimpGroupLayer, override GimpItem::{start,end}_transform(),
instead of GimpItem::{start,end}_move(), for the same purpose of
suspending mask resize. This avoids these functions from being
called when removing a layer group, fixing the bug.
2018-04-22 15:39:40 +08:00
|
|
|
klass->start_transform = gimp_item_real_start_transform;
|
|
|
|
klass->end_transform = gimp_item_real_end_transform;
|
2003-09-30 07:14:28 +08:00
|
|
|
klass->translate = gimp_item_real_translate;
|
|
|
|
klass->scale = gimp_item_real_scale;
|
|
|
|
klass->resize = gimp_item_real_resize;
|
|
|
|
klass->flip = NULL;
|
|
|
|
klass->rotate = NULL;
|
2004-01-27 00:18:16 +08:00
|
|
|
klass->transform = NULL;
|
2016-03-15 02:02:18 +08:00
|
|
|
klass->fill = NULL;
|
2003-09-30 07:14:28 +08:00
|
|
|
klass->stroke = NULL;
|
2010-07-21 05:09:19 +08:00
|
|
|
klass->to_selection = NULL;
|
2004-04-13 19:43:27 +08:00
|
|
|
|
|
|
|
klass->default_name = NULL;
|
|
|
|
klass->rename_desc = NULL;
|
|
|
|
klass->translate_desc = NULL;
|
|
|
|
klass->scale_desc = NULL;
|
|
|
|
klass->resize_desc = NULL;
|
|
|
|
klass->flip_desc = NULL;
|
|
|
|
klass->rotate_desc = NULL;
|
|
|
|
klass->transform_desc = NULL;
|
2016-03-15 02:02:18 +08:00
|
|
|
klass->fill_desc = NULL;
|
|
|
|
klass->stroke_desc = NULL;
|
2005-09-20 18:30:01 +08:00
|
|
|
|
2011-02-01 17:28:10 +08:00
|
|
|
g_object_class_install_property (object_class, PROP_IMAGE,
|
|
|
|
g_param_spec_object ("image", NULL, NULL,
|
|
|
|
GIMP_TYPE_IMAGE,
|
|
|
|
GIMP_PARAM_READWRITE |
|
|
|
|
G_PARAM_CONSTRUCT));
|
2005-09-20 18:30:01 +08:00
|
|
|
g_object_class_install_property (object_class, PROP_ID,
|
|
|
|
g_param_spec_int ("id", NULL, NULL,
|
|
|
|
0, G_MAXINT, 0,
|
2006-01-19 04:29:40 +08:00
|
|
|
GIMP_PARAM_READABLE));
|
2005-09-20 18:30:01 +08:00
|
|
|
|
|
|
|
g_object_class_install_property (object_class, PROP_WIDTH,
|
|
|
|
g_param_spec_int ("width", NULL, NULL,
|
|
|
|
1, GIMP_MAX_IMAGE_SIZE, 1,
|
2006-01-19 04:29:40 +08:00
|
|
|
GIMP_PARAM_READABLE));
|
2005-09-20 18:30:01 +08:00
|
|
|
|
|
|
|
g_object_class_install_property (object_class, PROP_HEIGHT,
|
|
|
|
g_param_spec_int ("height", NULL, NULL,
|
|
|
|
1, GIMP_MAX_IMAGE_SIZE, 1,
|
2006-01-19 04:29:40 +08:00
|
|
|
GIMP_PARAM_READABLE));
|
2008-11-12 05:14:52 +08:00
|
|
|
|
|
|
|
g_object_class_install_property (object_class, PROP_OFFSET_X,
|
|
|
|
g_param_spec_int ("offset-x", NULL, NULL,
|
|
|
|
-GIMP_MAX_IMAGE_SIZE,
|
|
|
|
GIMP_MAX_IMAGE_SIZE, 0,
|
|
|
|
GIMP_PARAM_READABLE));
|
|
|
|
|
|
|
|
g_object_class_install_property (object_class, PROP_OFFSET_Y,
|
|
|
|
g_param_spec_int ("offset-y", NULL, NULL,
|
|
|
|
-GIMP_MAX_IMAGE_SIZE,
|
|
|
|
GIMP_MAX_IMAGE_SIZE, 0,
|
|
|
|
GIMP_PARAM_READABLE));
|
2008-11-13 23:06:34 +08:00
|
|
|
|
app: add GimpFilter::active property; move ::visible to GimpItem
Add an "active" property to GimpFilter, which replaces its
"visible" property. The new property assumes the lower-level role
"visible" had -- controlling whether the filter has any effect as
part of its parent filter-stack.
Add a "visible" property to GimpItem, separate from the "active"
property, which assumes the higher-level role "visible" had --
controlling whether the item is considered "visible", as per the
GUI. By default, the item's "visible" property is bound to the
filter's "active" property, so that changes in visibility directly
affect the filter's "activeness"; this binding can be controlled
using the new gimp_item_bind_visible_to_active() function.
This distinction is currently necessary for floating selections.
Floating selection layers must not be active in their parent stack,
regardless of their visibility, in particular, so that their mode
node doesn't hide the entire backdrop when their composite mode
excludes the backdrop (i.e., when it's dst-atop or src-in).
Instead, their visibility should affect the activeness of the
floating-selection filter of the drawable they're attached to.
This is handled by the next commit.
2017-12-06 02:46:50 +08:00
|
|
|
g_object_class_install_property (object_class, PROP_VISIBLE,
|
|
|
|
g_param_spec_boolean ("visible", NULL, NULL,
|
|
|
|
TRUE,
|
|
|
|
GIMP_PARAM_READABLE));
|
|
|
|
|
2008-11-13 23:06:34 +08:00
|
|
|
g_object_class_install_property (object_class, PROP_LINKED,
|
|
|
|
g_param_spec_boolean ("linked", NULL, NULL,
|
|
|
|
FALSE,
|
|
|
|
GIMP_PARAM_READABLE));
|
2009-08-19 19:37:41 +08:00
|
|
|
|
2016-10-29 22:50:13 +08:00
|
|
|
g_object_class_install_property (object_class, PROP_COLOR_TAG,
|
|
|
|
g_param_spec_enum ("color-tag", NULL, NULL,
|
|
|
|
GIMP_TYPE_COLOR_TAG,
|
|
|
|
GIMP_COLOR_TAG_NONE,
|
|
|
|
GIMP_PARAM_READABLE));
|
|
|
|
|
2009-08-19 19:37:41 +08:00
|
|
|
g_object_class_install_property (object_class, PROP_LOCK_CONTENT,
|
|
|
|
g_param_spec_boolean ("lock-content",
|
|
|
|
NULL, NULL,
|
|
|
|
FALSE,
|
|
|
|
GIMP_PARAM_READABLE));
|
2011-01-31 04:49:51 +08:00
|
|
|
|
2012-11-09 18:17:25 +08:00
|
|
|
g_object_class_install_property (object_class, PROP_LOCK_POSITION,
|
|
|
|
g_param_spec_boolean ("lock-position",
|
|
|
|
NULL, NULL,
|
|
|
|
FALSE,
|
|
|
|
GIMP_PARAM_READABLE));
|
2002-02-26 01:58:50 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gimp_item_init (GimpItem *item)
|
|
|
|
{
|
2011-01-31 04:49:51 +08:00
|
|
|
GimpItemPrivate *private = GET_PRIVATE (item);
|
|
|
|
|
2006-10-17 01:09:17 +08:00
|
|
|
g_object_force_floating (G_OBJECT (item));
|
|
|
|
|
app: add GimpFilter::active property; move ::visible to GimpItem
Add an "active" property to GimpFilter, which replaces its
"visible" property. The new property assumes the lower-level role
"visible" had -- controlling whether the filter has any effect as
part of its parent filter-stack.
Add a "visible" property to GimpItem, separate from the "active"
property, which assumes the higher-level role "visible" had --
controlling whether the item is considered "visible", as per the
GUI. By default, the item's "visible" property is bound to the
filter's "active" property, so that changes in visibility directly
affect the filter's "activeness"; this binding can be controlled
using the new gimp_item_bind_visible_to_active() function.
This distinction is currently necessary for floating selections.
Floating selection layers must not be active in their parent stack,
regardless of their visibility, in particular, so that their mode
node doesn't hide the entire backdrop when their composite mode
excludes the backdrop (i.e., when it's dst-atop or src-in).
Instead, their visibility should affect the activeness of the
floating-selection filter of the drawable they're attached to.
This is handled by the next commit.
2017-12-06 02:46:50 +08:00
|
|
|
private->parasites = gimp_parasite_list_new ();
|
|
|
|
private->visible = TRUE;
|
|
|
|
private->bind_visible_to_active = TRUE;
|
2002-02-26 01:58:50 +08:00
|
|
|
}
|
|
|
|
|
2011-02-01 17:28:10 +08:00
|
|
|
static void
|
|
|
|
gimp_item_constructed (GObject *object)
|
|
|
|
{
|
|
|
|
GimpItemPrivate *private = GET_PRIVATE (object);
|
|
|
|
|
2012-11-13 04:51:22 +08:00
|
|
|
G_OBJECT_CLASS (parent_class)->constructed (object);
|
2011-02-01 17:28:10 +08:00
|
|
|
|
2018-02-12 05:23:10 +08:00
|
|
|
gimp_assert (GIMP_IS_IMAGE (private->image));
|
|
|
|
gimp_assert (private->ID != 0);
|
2011-02-01 17:28:10 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gimp_item_finalize (GObject *object)
|
|
|
|
{
|
|
|
|
GimpItemPrivate *private = GET_PRIVATE (object);
|
|
|
|
|
2012-05-16 04:25:12 +08:00
|
|
|
if (private->offset_nodes)
|
|
|
|
{
|
|
|
|
g_list_free_full (private->offset_nodes,
|
|
|
|
(GDestroyNotify) g_object_unref);
|
|
|
|
private->offset_nodes = NULL;
|
|
|
|
}
|
|
|
|
|
2011-02-01 17:28:10 +08:00
|
|
|
if (private->image && private->image->gimp)
|
|
|
|
{
|
2011-05-05 04:14:13 +08:00
|
|
|
gimp_id_table_remove (private->image->gimp->item_table, private->ID);
|
2011-02-01 17:28:10 +08:00
|
|
|
private->image = NULL;
|
|
|
|
}
|
|
|
|
|
2017-07-16 00:38:01 +08:00
|
|
|
g_clear_object (&private->parasites);
|
2011-02-01 17:28:10 +08:00
|
|
|
|
|
|
|
G_OBJECT_CLASS (parent_class)->finalize (object);
|
|
|
|
}
|
|
|
|
|
2005-09-20 18:30:01 +08:00
|
|
|
static void
|
|
|
|
gimp_item_set_property (GObject *object,
|
|
|
|
guint property_id,
|
|
|
|
const GValue *value,
|
|
|
|
GParamSpec *pspec)
|
|
|
|
{
|
2011-02-01 17:28:10 +08:00
|
|
|
GimpItem *item = GIMP_ITEM (object);
|
|
|
|
|
2005-09-20 18:30:01 +08:00
|
|
|
switch (property_id)
|
|
|
|
{
|
2011-02-01 17:28:10 +08:00
|
|
|
case PROP_IMAGE:
|
|
|
|
gimp_item_set_image (item, g_value_get_object (value));
|
|
|
|
break;
|
|
|
|
|
2005-09-20 18:30:01 +08:00
|
|
|
default:
|
|
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gimp_item_get_property (GObject *object,
|
|
|
|
guint property_id,
|
|
|
|
GValue *value,
|
|
|
|
GParamSpec *pspec)
|
|
|
|
{
|
2011-01-31 04:49:51 +08:00
|
|
|
GimpItemPrivate *private = GET_PRIVATE (object);
|
2005-09-20 18:30:01 +08:00
|
|
|
|
|
|
|
switch (property_id)
|
|
|
|
{
|
2011-02-01 17:28:10 +08:00
|
|
|
case PROP_IMAGE:
|
|
|
|
g_value_set_object (value, private->image);
|
|
|
|
break;
|
2005-09-20 18:30:01 +08:00
|
|
|
case PROP_ID:
|
2011-01-31 04:49:51 +08:00
|
|
|
g_value_set_int (value, private->ID);
|
2005-09-20 18:30:01 +08:00
|
|
|
break;
|
|
|
|
case PROP_WIDTH:
|
2011-03-09 01:10:59 +08:00
|
|
|
g_value_set_int (value, private->width);
|
2005-09-20 18:30:01 +08:00
|
|
|
break;
|
|
|
|
case PROP_HEIGHT:
|
2011-03-09 01:10:59 +08:00
|
|
|
g_value_set_int (value, private->height);
|
2005-09-20 18:30:01 +08:00
|
|
|
break;
|
2008-11-12 05:14:52 +08:00
|
|
|
case PROP_OFFSET_X:
|
2011-01-31 04:49:51 +08:00
|
|
|
g_value_set_int (value, private->offset_x);
|
2008-11-12 05:14:52 +08:00
|
|
|
break;
|
|
|
|
case PROP_OFFSET_Y:
|
2011-01-31 04:49:51 +08:00
|
|
|
g_value_set_int (value, private->offset_y);
|
2008-11-12 05:14:52 +08:00
|
|
|
break;
|
app: add GimpFilter::active property; move ::visible to GimpItem
Add an "active" property to GimpFilter, which replaces its
"visible" property. The new property assumes the lower-level role
"visible" had -- controlling whether the filter has any effect as
part of its parent filter-stack.
Add a "visible" property to GimpItem, separate from the "active"
property, which assumes the higher-level role "visible" had --
controlling whether the item is considered "visible", as per the
GUI. By default, the item's "visible" property is bound to the
filter's "active" property, so that changes in visibility directly
affect the filter's "activeness"; this binding can be controlled
using the new gimp_item_bind_visible_to_active() function.
This distinction is currently necessary for floating selections.
Floating selection layers must not be active in their parent stack,
regardless of their visibility, in particular, so that their mode
node doesn't hide the entire backdrop when their composite mode
excludes the backdrop (i.e., when it's dst-atop or src-in).
Instead, their visibility should affect the activeness of the
floating-selection filter of the drawable they're attached to.
This is handled by the next commit.
2017-12-06 02:46:50 +08:00
|
|
|
case PROP_VISIBLE:
|
|
|
|
g_value_set_boolean (value, private->visible);
|
|
|
|
break;
|
2008-11-13 23:06:34 +08:00
|
|
|
case PROP_LINKED:
|
2011-01-31 04:49:51 +08:00
|
|
|
g_value_set_boolean (value, private->linked);
|
2008-11-13 23:06:34 +08:00
|
|
|
break;
|
2016-10-29 22:50:13 +08:00
|
|
|
case PROP_COLOR_TAG:
|
|
|
|
g_value_set_enum (value, private->color_tag);
|
|
|
|
break;
|
2009-08-19 19:37:41 +08:00
|
|
|
case PROP_LOCK_CONTENT:
|
2011-01-31 04:49:51 +08:00
|
|
|
g_value_set_boolean (value, private->lock_content);
|
2009-08-19 19:37:41 +08:00
|
|
|
break;
|
2012-11-09 18:17:25 +08:00
|
|
|
case PROP_LOCK_POSITION:
|
|
|
|
g_value_set_boolean (value, private->lock_position);
|
|
|
|
break;
|
2008-11-12 05:14:52 +08:00
|
|
|
|
2005-09-20 18:30:01 +08:00
|
|
|
default:
|
|
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-11-17 01:51:36 +08:00
|
|
|
static gint64
|
2003-08-25 18:49:33 +08:00
|
|
|
gimp_item_get_memsize (GimpObject *object,
|
2003-11-17 01:51:36 +08:00
|
|
|
gint64 *gui_size)
|
2002-02-26 01:58:50 +08:00
|
|
|
{
|
2011-02-01 06:51:18 +08:00
|
|
|
GimpItemPrivate *private = GET_PRIVATE (object);
|
|
|
|
gint64 memsize = 0;
|
2002-02-26 01:58:50 +08:00
|
|
|
|
2011-02-01 06:51:18 +08:00
|
|
|
memsize += gimp_object_get_memsize (GIMP_OBJECT (private->parasites),
|
|
|
|
gui_size);
|
2002-02-26 01:58:50 +08:00
|
|
|
|
2003-08-25 18:49:33 +08:00
|
|
|
return memsize + GIMP_OBJECT_CLASS (parent_class)->get_memsize (object,
|
|
|
|
gui_size);
|
2002-02-26 01:58:50 +08:00
|
|
|
}
|
|
|
|
|
2009-08-29 20:59:07 +08:00
|
|
|
static gboolean
|
2016-05-20 05:51:44 +08:00
|
|
|
gimp_item_real_is_content_locked (GimpItem *item)
|
2009-08-29 20:59:07 +08:00
|
|
|
{
|
2010-02-07 20:46:46 +08:00
|
|
|
GimpItem *parent = gimp_item_get_parent (item);
|
2009-08-29 21:10:38 +08:00
|
|
|
|
2010-02-07 20:46:46 +08:00
|
|
|
if (parent && gimp_item_is_content_locked (parent))
|
2009-08-29 21:10:38 +08:00
|
|
|
return TRUE;
|
|
|
|
|
2011-01-31 04:49:51 +08:00
|
|
|
return GET_PRIVATE (item)->lock_content;
|
2009-08-29 20:59:07 +08:00
|
|
|
}
|
|
|
|
|
2012-11-09 18:17:25 +08:00
|
|
|
static gboolean
|
2016-05-20 05:51:44 +08:00
|
|
|
gimp_item_real_is_position_locked (GimpItem *item)
|
2012-11-09 18:17:25 +08:00
|
|
|
{
|
|
|
|
if (gimp_item_get_linked (item))
|
|
|
|
if (gimp_item_linked_is_locked (item))
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
return GET_PRIVATE (item)->lock_position;
|
|
|
|
}
|
|
|
|
|
2015-06-30 18:34:46 +08:00
|
|
|
static gboolean
|
|
|
|
gimp_item_real_bounds (GimpItem *item,
|
|
|
|
gdouble *x,
|
|
|
|
gdouble *y,
|
|
|
|
gdouble *width,
|
|
|
|
gdouble *height)
|
|
|
|
{
|
|
|
|
GimpItemPrivate *private = GET_PRIVATE (item);
|
|
|
|
|
|
|
|
*x = 0;
|
|
|
|
*y = 0;
|
|
|
|
*width = private->width;
|
|
|
|
*height = private->height;
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2003-02-11 21:52:47 +08:00
|
|
|
static GimpItem *
|
|
|
|
gimp_item_real_duplicate (GimpItem *item,
|
2008-01-08 19:46:15 +08:00
|
|
|
GType new_type)
|
2003-02-01 02:08:32 +08:00
|
|
|
{
|
2011-01-31 04:49:51 +08:00
|
|
|
GimpItemPrivate *private;
|
|
|
|
GimpItem *new_item;
|
|
|
|
gchar *new_name;
|
2003-02-01 02:08:32 +08:00
|
|
|
|
|
|
|
g_return_val_if_fail (GIMP_IS_ITEM (item), NULL);
|
2011-01-31 04:49:51 +08:00
|
|
|
|
|
|
|
private = GET_PRIVATE (item);
|
|
|
|
|
|
|
|
g_return_val_if_fail (GIMP_IS_IMAGE (private->image), NULL);
|
2003-02-01 02:08:32 +08:00
|
|
|
g_return_val_if_fail (g_type_is_a (new_type, GIMP_TYPE_ITEM), NULL);
|
|
|
|
|
|
|
|
/* formulate the new name */
|
|
|
|
{
|
|
|
|
const gchar *name;
|
|
|
|
gint len;
|
|
|
|
|
2009-09-01 04:47:18 +08:00
|
|
|
name = gimp_object_get_name (item);
|
2003-02-01 02:08:32 +08:00
|
|
|
|
|
|
|
g_return_val_if_fail (name != NULL, NULL);
|
|
|
|
|
|
|
|
len = strlen (_("copy"));
|
|
|
|
|
|
|
|
if ((strlen (name) >= len &&
|
|
|
|
strcmp (&name[strlen (name) - len], _("copy")) == 0) ||
|
2015-11-20 01:58:31 +08:00
|
|
|
g_regex_match_simple ("#([0-9]+)\\s*$", name, 0, 0))
|
2003-02-01 02:08:32 +08:00
|
|
|
{
|
|
|
|
/* don't have redundant "copy"s */
|
|
|
|
new_name = g_strdup (name);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
new_name = g_strdup_printf (_("%s copy"), name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-02-01 19:47:24 +08:00
|
|
|
new_item = gimp_item_new (new_type,
|
|
|
|
gimp_item_get_image (item), new_name,
|
|
|
|
private->offset_x, private->offset_y,
|
|
|
|
gimp_item_get_width (item),
|
|
|
|
gimp_item_get_height (item));
|
2003-02-01 02:08:32 +08:00
|
|
|
|
|
|
|
g_free (new_name);
|
|
|
|
|
2017-12-09 00:04:05 +08:00
|
|
|
gimp_viewable_set_expanded (GIMP_VIEWABLE (new_item),
|
|
|
|
gimp_viewable_get_expanded (GIMP_VIEWABLE (item)));
|
|
|
|
|
2011-02-01 06:51:18 +08:00
|
|
|
g_object_unref (GET_PRIVATE (new_item)->parasites);
|
|
|
|
GET_PRIVATE (new_item)->parasites = gimp_parasite_list_copy (private->parasites);
|
2003-02-01 02:08:32 +08:00
|
|
|
|
2016-10-29 22:50:13 +08:00
|
|
|
gimp_item_set_visible (new_item, gimp_item_get_visible (item), FALSE);
|
|
|
|
gimp_item_set_linked (new_item, gimp_item_get_linked (item), FALSE);
|
|
|
|
gimp_item_set_color_tag (new_item, gimp_item_get_color_tag (item), FALSE);
|
2009-09-09 04:09:53 +08:00
|
|
|
|
|
|
|
if (gimp_item_can_lock_content (new_item))
|
|
|
|
gimp_item_set_lock_content (new_item, gimp_item_get_lock_content (item),
|
|
|
|
FALSE);
|
2003-05-09 04:26:01 +08:00
|
|
|
|
2012-11-09 18:17:25 +08:00
|
|
|
if (gimp_item_can_lock_position (new_item))
|
|
|
|
gimp_item_set_lock_position (new_item, gimp_item_get_lock_position (item),
|
|
|
|
FALSE);
|
|
|
|
|
2003-02-01 02:08:32 +08:00
|
|
|
return new_item;
|
|
|
|
}
|
|
|
|
|
2005-01-14 02:17:24 +08:00
|
|
|
static void
|
|
|
|
gimp_item_real_convert (GimpItem *item,
|
2015-08-16 21:47:43 +08:00
|
|
|
GimpImage *dest_image,
|
|
|
|
GType old_type)
|
2003-08-28 01:21:49 +08:00
|
|
|
{
|
2005-01-14 02:17:24 +08:00
|
|
|
gimp_item_set_image (item, dest_image);
|
2003-08-28 01:21:49 +08:00
|
|
|
}
|
|
|
|
|
2004-02-02 04:38:26 +08:00
|
|
|
static gboolean
|
2007-12-12 21:57:11 +08:00
|
|
|
gimp_item_real_rename (GimpItem *item,
|
|
|
|
const gchar *new_name,
|
|
|
|
const gchar *undo_desc,
|
|
|
|
GError **error)
|
2003-03-17 08:14:59 +08:00
|
|
|
{
|
2004-02-02 04:38:26 +08:00
|
|
|
if (gimp_item_is_attached (item))
|
2010-02-07 22:39:42 +08:00
|
|
|
gimp_item_tree_rename_item (gimp_item_get_tree (item), item,
|
2010-02-07 22:56:53 +08:00
|
|
|
new_name, TRUE, undo_desc);
|
2010-02-07 22:39:42 +08:00
|
|
|
else
|
|
|
|
gimp_object_set_name (GIMP_OBJECT (item), new_name);
|
2004-02-02 04:38:26 +08:00
|
|
|
|
|
|
|
return TRUE;
|
2003-03-17 08:14:59 +08:00
|
|
|
}
|
|
|
|
|
2003-05-09 03:11:17 +08:00
|
|
|
static void
|
|
|
|
gimp_item_real_translate (GimpItem *item,
|
2018-04-23 07:08:54 +08:00
|
|
|
gdouble offset_x,
|
|
|
|
gdouble offset_y,
|
2003-05-09 21:05:37 +08:00
|
|
|
gboolean push_undo)
|
2003-05-09 03:11:17 +08:00
|
|
|
{
|
2011-01-31 04:49:51 +08:00
|
|
|
GimpItemPrivate *private = GET_PRIVATE (item);
|
|
|
|
|
2008-11-12 05:14:52 +08:00
|
|
|
gimp_item_set_offset (item,
|
2018-04-23 07:08:54 +08:00
|
|
|
private->offset_x + SIGNED_ROUND (offset_x),
|
|
|
|
private->offset_y + SIGNED_ROUND (offset_y));
|
2003-05-09 03:11:17 +08:00
|
|
|
}
|
|
|
|
|
Bug 795410 - Deleting a layer group and then undoing the deletion ...
... raises a CRITICAL
gimp_item_{start,end}_move() currently serves two different
purposes: It is used by GimpLayer to suspend/resume mask resizing
of the layer's ancestors; this is necessary whenever an operation
on a layer might affect the size of its ancestors. It is also used
by GimpGroupLayer to suspend/resume its own mask resizing; this, on
the other hand, is only necessary before applying one of the
transformation functions to the group, so that mask modification is
handled by GimpLayer. In other words, the effects of
gimp_item_{start,end}_move() on group layers are only necessary in
a subset of the cases in which these functions are used.
While in itself this isn't a problem, it does cause issues when
removing a group layer: gimp_image_remove_layer() calls
gimp_item_start_move() before removing the layer, and
gimp_item_end_move() afterwards. While the former function is
called while the layer is still attached to the image, the latter
function is called after the layer is no longer attached. Since
GimpGroupLayer pushes an undo step in response to these calls, only
the call to start_move() results in an undo step, while the call to
end_move() doesn't, resulting in an unbalanced
GIMP_UNDO_GROUP_LAYER_START_MOVE undo step on the stack. This
causes problems when undoing the operation.
Add gimp_item_{start,end}_transform() functions, and corresponding
GimpItem::{start,end}_transform() virtual functions, which are more
specialized versions of gimp_item_{start,end}_move(), which should
be used instead of the former before/after transforming an item; in
other cases, such as when removing ot reordering an item,
gimp_item_{start,end}_move() should still be used. The default
implementation of GimpItem::{start,end}_transform() calls
gimp_item_{start,end}_move(), respectively, so subclasses that
override these functions don't have to do that themselves.
In GimpGroupLayer, override GimpItem::{start,end}_transform(),
instead of GimpItem::{start,end}_move(), for the same purpose of
suspending mask resize. This avoids these functions from being
called when removing a layer group, fixing the bug.
2018-04-22 15:39:40 +08:00
|
|
|
static void
|
|
|
|
gimp_item_real_start_transform (GimpItem *item,
|
|
|
|
gboolean push_undo)
|
|
|
|
{
|
|
|
|
gimp_item_start_move (item, push_undo);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gimp_item_real_end_transform (GimpItem *item,
|
|
|
|
gboolean push_undo)
|
|
|
|
{
|
|
|
|
gimp_item_end_move (item, push_undo);
|
|
|
|
}
|
|
|
|
|
2003-05-09 08:38:51 +08:00
|
|
|
static void
|
|
|
|
gimp_item_real_scale (GimpItem *item,
|
|
|
|
gint new_width,
|
|
|
|
gint new_height,
|
|
|
|
gint new_offset_x,
|
|
|
|
gint new_offset_y,
|
2004-02-09 08:09:20 +08:00
|
|
|
GimpInterpolationType interpolation,
|
2004-08-11 02:47:21 +08:00
|
|
|
GimpProgress *progress)
|
2003-05-09 08:38:51 +08:00
|
|
|
{
|
2011-03-09 01:10:59 +08:00
|
|
|
GimpItemPrivate *private = GET_PRIVATE (item);
|
|
|
|
|
|
|
|
if (private->width != new_width)
|
2008-11-12 05:14:52 +08:00
|
|
|
{
|
2011-03-09 01:10:59 +08:00
|
|
|
private->width = new_width;
|
2008-11-12 05:14:52 +08:00
|
|
|
g_object_notify (G_OBJECT (item), "width");
|
|
|
|
}
|
|
|
|
|
2011-03-09 01:10:59 +08:00
|
|
|
if (private->height != new_height)
|
2008-11-12 05:14:52 +08:00
|
|
|
{
|
2011-03-09 01:10:59 +08:00
|
|
|
private->height = new_height;
|
2008-11-12 05:14:52 +08:00
|
|
|
g_object_notify (G_OBJECT (item), "height");
|
|
|
|
}
|
2005-09-20 18:30:01 +08:00
|
|
|
|
2008-11-12 05:14:52 +08:00
|
|
|
gimp_item_set_offset (item, new_offset_x, new_offset_y);
|
2003-05-09 08:38:51 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2016-10-10 06:02:16 +08:00
|
|
|
gimp_item_real_resize (GimpItem *item,
|
|
|
|
GimpContext *context,
|
|
|
|
GimpFillType fill_type,
|
|
|
|
gint new_width,
|
|
|
|
gint new_height,
|
|
|
|
gint offset_x,
|
|
|
|
gint offset_y)
|
2003-05-09 08:38:51 +08:00
|
|
|
{
|
2011-01-31 04:49:51 +08:00
|
|
|
GimpItemPrivate *private = GET_PRIVATE (item);
|
|
|
|
|
2011-03-09 01:10:59 +08:00
|
|
|
if (private->width != new_width)
|
2008-11-12 05:14:52 +08:00
|
|
|
{
|
2011-03-09 01:10:59 +08:00
|
|
|
private->width = new_width;
|
2008-11-12 05:14:52 +08:00
|
|
|
g_object_notify (G_OBJECT (item), "width");
|
|
|
|
}
|
2005-09-20 18:30:01 +08:00
|
|
|
|
2011-03-09 01:10:59 +08:00
|
|
|
if (private->height != new_height)
|
2008-11-12 05:14:52 +08:00
|
|
|
{
|
2011-03-09 01:10:59 +08:00
|
|
|
private->height = new_height;
|
2008-11-12 05:14:52 +08:00
|
|
|
g_object_notify (G_OBJECT (item), "height");
|
|
|
|
}
|
|
|
|
|
|
|
|
gimp_item_set_offset (item,
|
2011-01-31 04:49:51 +08:00
|
|
|
private->offset_x - offset_x,
|
|
|
|
private->offset_y - offset_y);
|
2003-05-09 08:38:51 +08:00
|
|
|
}
|
|
|
|
|
2011-02-01 19:47:24 +08:00
|
|
|
|
|
|
|
/* public functions */
|
|
|
|
|
|
|
|
/**
|
|
|
|
* gimp_item_new:
|
|
|
|
* @type: The new item's type.
|
|
|
|
* @image: The new item's #GimpImage.
|
|
|
|
* @name: The name to assign the item.
|
|
|
|
* @offset_x: The X offset to assign the item.
|
|
|
|
* @offset_y: The Y offset to assign the item.
|
|
|
|
* @width: The width to assign the item.
|
|
|
|
* @height: The height to assign the item.
|
|
|
|
*
|
|
|
|
* Return value: The newly created item.
|
|
|
|
*/
|
|
|
|
GimpItem *
|
|
|
|
gimp_item_new (GType type,
|
|
|
|
GimpImage *image,
|
|
|
|
const gchar *name,
|
|
|
|
gint offset_x,
|
|
|
|
gint offset_y,
|
|
|
|
gint width,
|
|
|
|
gint height)
|
|
|
|
{
|
|
|
|
GimpItem *item;
|
|
|
|
GimpItemPrivate *private;
|
|
|
|
|
|
|
|
g_return_val_if_fail (g_type_is_a (type, GIMP_TYPE_ITEM), NULL);
|
|
|
|
g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL);
|
|
|
|
g_return_val_if_fail (width > 0 && height > 0, NULL);
|
|
|
|
|
|
|
|
item = g_object_new (type,
|
|
|
|
"image", image,
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
private = GET_PRIVATE (item);
|
|
|
|
|
2011-03-09 01:10:59 +08:00
|
|
|
private->width = width;
|
|
|
|
private->height = height;
|
2011-02-01 19:47:24 +08:00
|
|
|
gimp_item_set_offset (item, offset_x, offset_y);
|
|
|
|
|
|
|
|
if (name && strlen (name))
|
|
|
|
gimp_object_set_name (GIMP_OBJECT (item), name);
|
|
|
|
else
|
|
|
|
gimp_object_set_static_name (GIMP_OBJECT (item),
|
|
|
|
GIMP_ITEM_GET_CLASS (item)->default_name);
|
|
|
|
|
|
|
|
return item;
|
|
|
|
}
|
|
|
|
|
2004-07-14 08:32:09 +08:00
|
|
|
/**
|
|
|
|
* gimp_item_remove:
|
|
|
|
* @item: the #GimpItem to remove.
|
|
|
|
*
|
|
|
|
* This function sets the 'removed' flag on @item to #TRUE, and emits
|
|
|
|
* a 'removed' signal on the item.
|
|
|
|
*/
|
2003-02-11 21:52:47 +08:00
|
|
|
void
|
|
|
|
gimp_item_removed (GimpItem *item)
|
|
|
|
{
|
2009-08-02 01:21:43 +08:00
|
|
|
GimpContainer *children;
|
|
|
|
|
2003-02-11 21:52:47 +08:00
|
|
|
g_return_if_fail (GIMP_IS_ITEM (item));
|
|
|
|
|
2011-01-31 04:57:45 +08:00
|
|
|
GET_PRIVATE (item)->removed = TRUE;
|
2004-03-28 22:20:57 +08:00
|
|
|
|
2009-08-02 01:21:43 +08:00
|
|
|
children = gimp_viewable_get_children (GIMP_VIEWABLE (item));
|
|
|
|
|
|
|
|
if (children)
|
|
|
|
gimp_container_foreach (children, (GFunc) gimp_item_removed, NULL);
|
|
|
|
|
2003-02-11 21:52:47 +08:00
|
|
|
g_signal_emit (item, gimp_item_signals[REMOVED], 0);
|
|
|
|
}
|
|
|
|
|
2004-07-14 08:32:09 +08:00
|
|
|
/**
|
|
|
|
* gimp_item_is_removed:
|
|
|
|
* @item: the #GimpItem to check.
|
|
|
|
*
|
2007-10-09 23:59:04 +08:00
|
|
|
* Returns: %TRUE if the 'removed' flag is set for @item, %FALSE otherwise.
|
2004-07-14 08:32:09 +08:00
|
|
|
*/
|
2004-03-28 22:20:57 +08:00
|
|
|
gboolean
|
2016-05-20 05:51:44 +08:00
|
|
|
gimp_item_is_removed (GimpItem *item)
|
2004-03-28 22:20:57 +08:00
|
|
|
{
|
|
|
|
g_return_val_if_fail (GIMP_IS_ITEM (item), FALSE);
|
|
|
|
|
2011-01-31 04:57:45 +08:00
|
|
|
return GET_PRIVATE (item)->removed;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* gimp_item_unset_removed:
|
|
|
|
* @item: a #GimpItem which was on the undo stack
|
|
|
|
*
|
|
|
|
* Unsets an item's "removed" state. This function is called when an
|
|
|
|
* item was on the undo stack and is added back to its parent
|
|
|
|
* container during and undo or redo. It must never be called from
|
|
|
|
* anywhere else.
|
|
|
|
**/
|
|
|
|
void
|
|
|
|
gimp_item_unset_removed (GimpItem *item)
|
|
|
|
{
|
2011-02-03 02:40:20 +08:00
|
|
|
GimpContainer *children;
|
|
|
|
|
2011-01-31 04:57:45 +08:00
|
|
|
g_return_if_fail (GIMP_IS_ITEM (item));
|
|
|
|
g_return_if_fail (gimp_item_is_removed (item));
|
|
|
|
|
|
|
|
GET_PRIVATE (item)->removed = FALSE;
|
2011-02-03 02:40:20 +08:00
|
|
|
|
|
|
|
children = gimp_viewable_get_children (GIMP_VIEWABLE (item));
|
|
|
|
|
|
|
|
if (children)
|
|
|
|
gimp_container_foreach (children, (GFunc) gimp_item_unset_removed, NULL);
|
|
|
|
|
|
|
|
if (GIMP_ITEM_GET_CLASS (item)->unset_removed)
|
|
|
|
GIMP_ITEM_GET_CLASS (item)->unset_removed (item);
|
2004-03-28 22:20:57 +08:00
|
|
|
}
|
|
|
|
|
2004-07-14 08:32:09 +08:00
|
|
|
/**
|
|
|
|
* gimp_item_is_attached:
|
|
|
|
* @item: The #GimpItem to check.
|
|
|
|
*
|
2004-07-14 19:52:03 +08:00
|
|
|
* Returns: %TRUE if the item is attached to an image, %FALSE otherwise.
|
2004-07-14 08:32:09 +08:00
|
|
|
*/
|
2004-01-27 00:18:16 +08:00
|
|
|
gboolean
|
2016-05-20 05:51:44 +08:00
|
|
|
gimp_item_is_attached (GimpItem *item)
|
2004-01-27 00:18:16 +08:00
|
|
|
{
|
2010-02-07 20:46:46 +08:00
|
|
|
GimpItem *parent;
|
2009-08-02 01:39:10 +08:00
|
|
|
|
2004-01-27 00:18:16 +08:00
|
|
|
g_return_val_if_fail (GIMP_IS_ITEM (item), FALSE);
|
|
|
|
|
2010-02-07 20:46:46 +08:00
|
|
|
parent = gimp_item_get_parent (item);
|
2009-08-02 01:39:10 +08:00
|
|
|
|
|
|
|
if (parent)
|
2010-02-07 20:46:46 +08:00
|
|
|
return gimp_item_is_attached (parent);
|
2009-08-02 01:39:10 +08:00
|
|
|
|
2004-01-27 00:18:16 +08:00
|
|
|
return GIMP_ITEM_GET_CLASS (item)->is_attached (item);
|
|
|
|
}
|
|
|
|
|
2010-02-07 19:03:07 +08:00
|
|
|
GimpItem *
|
2016-05-20 05:51:44 +08:00
|
|
|
gimp_item_get_parent (GimpItem *item)
|
2010-02-07 19:03:07 +08:00
|
|
|
{
|
|
|
|
g_return_val_if_fail (GIMP_IS_ITEM (item), NULL);
|
|
|
|
|
|
|
|
return GIMP_ITEM (gimp_viewable_get_parent (GIMP_VIEWABLE (item)));
|
|
|
|
}
|
|
|
|
|
2010-02-06 23:17:23 +08:00
|
|
|
GimpItemTree *
|
|
|
|
gimp_item_get_tree (GimpItem *item)
|
|
|
|
{
|
|
|
|
g_return_val_if_fail (GIMP_IS_ITEM (item), NULL);
|
|
|
|
|
|
|
|
if (GIMP_ITEM_GET_CLASS (item)->get_tree)
|
|
|
|
return GIMP_ITEM_GET_CLASS (item)->get_tree (item);
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2009-08-02 02:22:07 +08:00
|
|
|
GimpContainer *
|
|
|
|
gimp_item_get_container (GimpItem *item)
|
|
|
|
{
|
2010-02-07 20:46:46 +08:00
|
|
|
GimpItem *parent;
|
2010-02-06 23:17:23 +08:00
|
|
|
GimpItemTree *tree;
|
2009-08-02 02:22:07 +08:00
|
|
|
|
|
|
|
g_return_val_if_fail (GIMP_IS_ITEM (item), NULL);
|
|
|
|
|
2010-02-07 20:46:46 +08:00
|
|
|
parent = gimp_item_get_parent (item);
|
2009-08-02 02:22:07 +08:00
|
|
|
|
|
|
|
if (parent)
|
|
|
|
return gimp_viewable_get_children (GIMP_VIEWABLE (parent));
|
|
|
|
|
2010-02-06 23:17:23 +08:00
|
|
|
tree = gimp_item_get_tree (item);
|
|
|
|
|
|
|
|
if (tree)
|
|
|
|
return tree->container;
|
2009-08-02 02:22:07 +08:00
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2009-08-02 04:40:32 +08:00
|
|
|
GList *
|
|
|
|
gimp_item_get_container_iter (GimpItem *item)
|
|
|
|
{
|
|
|
|
GimpContainer *container;
|
|
|
|
|
|
|
|
g_return_val_if_fail (GIMP_IS_ITEM (item), NULL);
|
|
|
|
|
2009-08-02 04:53:31 +08:00
|
|
|
container = gimp_item_get_container (item);
|
2009-08-02 04:40:32 +08:00
|
|
|
|
|
|
|
if (container)
|
2016-05-01 21:22:44 +08:00
|
|
|
return GIMP_LIST (container)->queue->head;
|
2009-08-02 04:40:32 +08:00
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2009-08-02 02:22:07 +08:00
|
|
|
gint
|
|
|
|
gimp_item_get_index (GimpItem *item)
|
|
|
|
{
|
|
|
|
GimpContainer *container;
|
|
|
|
|
|
|
|
g_return_val_if_fail (GIMP_IS_ITEM (item), -1);
|
|
|
|
|
|
|
|
container = gimp_item_get_container (item);
|
|
|
|
|
|
|
|
if (container)
|
|
|
|
return gimp_container_get_child_index (container, GIMP_OBJECT (item));
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2009-08-31 02:56:39 +08:00
|
|
|
GList *
|
|
|
|
gimp_item_get_path (GimpItem *item)
|
|
|
|
{
|
|
|
|
GimpContainer *container;
|
|
|
|
GList *path = NULL;
|
|
|
|
|
|
|
|
g_return_val_if_fail (GIMP_IS_ITEM (item), NULL);
|
|
|
|
g_return_val_if_fail (gimp_item_is_attached (item), NULL);
|
|
|
|
|
|
|
|
container = gimp_item_get_container (item);
|
|
|
|
|
|
|
|
while (container)
|
|
|
|
{
|
|
|
|
guint32 index = gimp_container_get_child_index (container,
|
|
|
|
GIMP_OBJECT (item));
|
|
|
|
|
|
|
|
path = g_list_prepend (path, GUINT_TO_POINTER (index));
|
|
|
|
|
2010-02-07 20:46:46 +08:00
|
|
|
item = gimp_item_get_parent (item);
|
2009-08-31 02:56:39 +08:00
|
|
|
|
|
|
|
if (item)
|
|
|
|
container = gimp_item_get_container (item);
|
|
|
|
else
|
|
|
|
container = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return path;
|
|
|
|
}
|
|
|
|
|
2015-06-30 18:34:46 +08:00
|
|
|
gboolean
|
|
|
|
gimp_item_bounds (GimpItem *item,
|
|
|
|
gint *x,
|
|
|
|
gint *y,
|
|
|
|
gint *width,
|
|
|
|
gint *height)
|
|
|
|
{
|
|
|
|
gdouble tmp_x, tmp_y, tmp_width, tmp_height;
|
|
|
|
gboolean retval;
|
|
|
|
|
|
|
|
g_return_val_if_fail (GIMP_IS_ITEM (item), FALSE);
|
|
|
|
|
|
|
|
retval = GIMP_ITEM_GET_CLASS (item)->bounds (item,
|
|
|
|
&tmp_x, &tmp_y,
|
|
|
|
&tmp_width, &tmp_height);
|
|
|
|
|
|
|
|
if (x) *x = floor (tmp_x);
|
|
|
|
if (y) *y = floor (tmp_y);
|
|
|
|
if (width) *width = ceil (tmp_x + tmp_width) - floor (tmp_x);
|
|
|
|
if (height) *height = ceil (tmp_y + tmp_height) - floor (tmp_y);
|
|
|
|
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
|
|
|
gboolean
|
|
|
|
gimp_item_bounds_f (GimpItem *item,
|
|
|
|
gdouble *x,
|
|
|
|
gdouble *y,
|
|
|
|
gdouble *width,
|
|
|
|
gdouble *height)
|
|
|
|
{
|
|
|
|
gdouble tmp_x, tmp_y, tmp_width, tmp_height;
|
|
|
|
gboolean retval;
|
|
|
|
|
|
|
|
g_return_val_if_fail (GIMP_IS_ITEM (item), FALSE);
|
|
|
|
|
|
|
|
retval = GIMP_ITEM_GET_CLASS (item)->bounds (item,
|
|
|
|
&tmp_x, &tmp_y,
|
|
|
|
&tmp_width, &tmp_height);
|
|
|
|
|
|
|
|
if (x) *x = tmp_x;
|
|
|
|
if (y) *y = tmp_y;
|
|
|
|
if (width) *width = tmp_width;
|
|
|
|
if (height) *height = tmp_height;
|
|
|
|
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
2004-07-14 08:32:09 +08:00
|
|
|
/**
|
|
|
|
* gimp_item_duplicate:
|
2008-01-08 19:46:15 +08:00
|
|
|
* @item: The #GimpItem to duplicate.
|
|
|
|
* @new_type: The type to make the new item.
|
2004-07-14 08:32:09 +08:00
|
|
|
*
|
|
|
|
* Returns: the newly created item.
|
|
|
|
*/
|
2003-02-11 21:52:47 +08:00
|
|
|
GimpItem *
|
|
|
|
gimp_item_duplicate (GimpItem *item,
|
2008-01-08 19:46:15 +08:00
|
|
|
GType new_type)
|
2003-02-11 21:52:47 +08:00
|
|
|
{
|
2011-01-31 04:49:51 +08:00
|
|
|
GimpItemPrivate *private;
|
|
|
|
|
2003-02-11 21:52:47 +08:00
|
|
|
g_return_val_if_fail (GIMP_IS_ITEM (item), NULL);
|
2011-01-31 04:49:51 +08:00
|
|
|
|
|
|
|
private = GET_PRIVATE (item);
|
|
|
|
|
|
|
|
g_return_val_if_fail (GIMP_IS_IMAGE (private->image), NULL);
|
2003-02-11 21:52:47 +08:00
|
|
|
g_return_val_if_fail (g_type_is_a (new_type, GIMP_TYPE_ITEM), NULL);
|
|
|
|
|
2008-01-08 19:46:15 +08:00
|
|
|
return GIMP_ITEM_GET_CLASS (item)->duplicate (item, new_type);
|
2003-02-11 21:52:47 +08:00
|
|
|
}
|
|
|
|
|
2004-07-14 08:32:09 +08:00
|
|
|
/**
|
|
|
|
* gimp_item_convert:
|
2004-07-15 07:14:49 +08:00
|
|
|
* @item: The #GimpItem to convert.
|
2004-07-14 08:32:09 +08:00
|
|
|
* @dest_image: The #GimpImage in which to place the converted item.
|
2004-07-15 07:14:49 +08:00
|
|
|
* @new_type: The type to convert the item to.
|
2004-07-14 08:32:09 +08:00
|
|
|
*
|
|
|
|
* Returns: the new item that results from the conversion.
|
|
|
|
*/
|
2003-08-28 01:21:49 +08:00
|
|
|
GimpItem *
|
|
|
|
gimp_item_convert (GimpItem *item,
|
|
|
|
GimpImage *dest_image,
|
2008-01-08 19:46:15 +08:00
|
|
|
GType new_type)
|
2003-08-28 01:21:49 +08:00
|
|
|
{
|
2003-10-02 19:42:43 +08:00
|
|
|
GimpItem *new_item;
|
2015-08-16 21:47:43 +08:00
|
|
|
GType old_type;
|
2003-10-02 19:42:43 +08:00
|
|
|
|
2003-08-28 01:21:49 +08:00
|
|
|
g_return_val_if_fail (GIMP_IS_ITEM (item), NULL);
|
2011-01-31 04:49:51 +08:00
|
|
|
g_return_val_if_fail (GIMP_IS_IMAGE (GET_PRIVATE (item)->image), NULL);
|
2003-08-28 01:21:49 +08:00
|
|
|
g_return_val_if_fail (GIMP_IS_IMAGE (dest_image), NULL);
|
|
|
|
g_return_val_if_fail (g_type_is_a (new_type, GIMP_TYPE_ITEM), NULL);
|
|
|
|
|
2015-08-16 21:47:43 +08:00
|
|
|
old_type = G_TYPE_FROM_INSTANCE (item);
|
|
|
|
|
2008-01-08 19:46:15 +08:00
|
|
|
new_item = gimp_item_duplicate (item, new_type);
|
2003-10-02 19:42:43 +08:00
|
|
|
|
2004-12-23 19:53:14 +08:00
|
|
|
if (new_item)
|
2015-08-16 21:47:43 +08:00
|
|
|
GIMP_ITEM_GET_CLASS (new_item)->convert (new_item, dest_image, old_type);
|
2003-10-02 19:42:43 +08:00
|
|
|
|
|
|
|
return new_item;
|
2003-08-28 01:21:49 +08:00
|
|
|
}
|
|
|
|
|
2004-07-14 08:32:09 +08:00
|
|
|
/**
|
|
|
|
* gimp_item_rename:
|
2004-07-15 07:14:49 +08:00
|
|
|
* @item: The #GimpItem to rename.
|
2004-07-14 08:32:09 +08:00
|
|
|
* @new_name: The new name to give the item.
|
2007-12-12 21:57:11 +08:00
|
|
|
* @error: Return location for error message.
|
2004-07-14 08:32:09 +08:00
|
|
|
*
|
|
|
|
* This function assigns a new name to the item, if the desired name is
|
|
|
|
* different from the name it already has, and pushes an entry onto the
|
|
|
|
* undo stack for the item's image. If @new_name is NULL or empty, the
|
|
|
|
* default name for the item's class is used. If the name is changed,
|
2008-08-12 22:45:59 +08:00
|
|
|
* the GimpObject::name-changed signal is emitted for the item.
|
2004-07-14 08:32:09 +08:00
|
|
|
*
|
2004-07-14 19:52:03 +08:00
|
|
|
* Returns: %TRUE if the @item could be renamed, %FALSE otherwise.
|
2004-07-14 08:32:09 +08:00
|
|
|
*/
|
2004-02-02 04:38:26 +08:00
|
|
|
gboolean
|
2007-12-12 21:57:11 +08:00
|
|
|
gimp_item_rename (GimpItem *item,
|
|
|
|
const gchar *new_name,
|
|
|
|
GError **error)
|
2003-03-17 08:14:59 +08:00
|
|
|
{
|
|
|
|
GimpItemClass *item_class;
|
|
|
|
|
2004-02-02 04:38:26 +08:00
|
|
|
g_return_val_if_fail (GIMP_IS_ITEM (item), FALSE);
|
2007-12-12 21:57:11 +08:00
|
|
|
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
|
2003-03-17 08:14:59 +08:00
|
|
|
|
|
|
|
item_class = GIMP_ITEM_GET_CLASS (item);
|
|
|
|
|
|
|
|
if (! new_name || ! *new_name)
|
|
|
|
new_name = item_class->default_name;
|
|
|
|
|
2009-09-01 04:47:18 +08:00
|
|
|
if (strcmp (new_name, gimp_object_get_name (item)))
|
2007-12-12 21:57:11 +08:00
|
|
|
return item_class->rename (item, new_name, item_class->rename_desc, error);
|
2004-02-02 04:38:26 +08:00
|
|
|
|
|
|
|
return TRUE;
|
2003-03-17 08:14:59 +08:00
|
|
|
}
|
|
|
|
|
2004-07-14 08:32:09 +08:00
|
|
|
/**
|
2008-11-03 08:09:01 +08:00
|
|
|
* gimp_item_get_width:
|
2004-07-14 08:32:09 +08:00
|
|
|
* @item: The #GimpItem to check.
|
|
|
|
*
|
2004-07-14 19:52:03 +08:00
|
|
|
* Returns: The width of the item.
|
2004-07-14 08:32:09 +08:00
|
|
|
*/
|
2003-05-08 21:12:46 +08:00
|
|
|
gint
|
2016-05-20 05:51:44 +08:00
|
|
|
gimp_item_get_width (GimpItem *item)
|
2003-05-08 21:12:46 +08:00
|
|
|
{
|
|
|
|
g_return_val_if_fail (GIMP_IS_ITEM (item), -1);
|
|
|
|
|
2011-03-09 01:10:59 +08:00
|
|
|
return GET_PRIVATE (item)->width;
|
2003-05-08 21:12:46 +08:00
|
|
|
}
|
|
|
|
|
2004-07-14 08:32:09 +08:00
|
|
|
/**
|
2008-11-03 08:09:01 +08:00
|
|
|
* gimp_item_get_height:
|
2004-07-14 08:32:09 +08:00
|
|
|
* @item: The #GimpItem to check.
|
|
|
|
*
|
2004-07-14 19:52:03 +08:00
|
|
|
* Returns: The height of the item.
|
2004-07-14 08:32:09 +08:00
|
|
|
*/
|
2003-05-08 21:12:46 +08:00
|
|
|
gint
|
2016-05-20 05:51:44 +08:00
|
|
|
gimp_item_get_height (GimpItem *item)
|
2003-05-08 21:12:46 +08:00
|
|
|
{
|
|
|
|
g_return_val_if_fail (GIMP_IS_ITEM (item), -1);
|
|
|
|
|
2011-03-09 01:10:59 +08:00
|
|
|
return GET_PRIVATE (item)->height;
|
2003-05-08 21:12:46 +08:00
|
|
|
}
|
|
|
|
|
2009-08-26 19:00:13 +08:00
|
|
|
void
|
|
|
|
gimp_item_set_size (GimpItem *item,
|
|
|
|
gint width,
|
|
|
|
gint height)
|
|
|
|
{
|
2011-03-09 01:10:59 +08:00
|
|
|
GimpItemPrivate *private;
|
|
|
|
|
2009-08-26 19:00:13 +08:00
|
|
|
g_return_if_fail (GIMP_IS_ITEM (item));
|
|
|
|
|
2011-03-09 01:10:59 +08:00
|
|
|
private = GET_PRIVATE (item);
|
|
|
|
|
|
|
|
if (private->width != width ||
|
|
|
|
private->height != height)
|
2009-08-26 19:00:13 +08:00
|
|
|
{
|
|
|
|
g_object_freeze_notify (G_OBJECT (item));
|
|
|
|
|
2011-03-09 01:10:59 +08:00
|
|
|
if (private->width != width)
|
2009-08-26 19:00:13 +08:00
|
|
|
{
|
2011-03-09 01:10:59 +08:00
|
|
|
private->width = width;
|
2009-08-26 19:00:13 +08:00
|
|
|
g_object_notify (G_OBJECT (item), "width");
|
|
|
|
}
|
|
|
|
|
2011-03-09 01:10:59 +08:00
|
|
|
if (private->height != height)
|
2009-08-26 19:00:13 +08:00
|
|
|
{
|
2011-03-09 01:10:59 +08:00
|
|
|
private->height = height;
|
2009-08-26 19:00:13 +08:00
|
|
|
g_object_notify (G_OBJECT (item), "height");
|
|
|
|
}
|
|
|
|
|
|
|
|
g_object_thaw_notify (G_OBJECT (item));
|
|
|
|
|
|
|
|
gimp_viewable_size_changed (GIMP_VIEWABLE (item));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-07-14 08:32:09 +08:00
|
|
|
/**
|
2008-11-03 07:16:47 +08:00
|
|
|
* gimp_item_get_offset:
|
2004-07-15 07:14:49 +08:00
|
|
|
* @item: The #GimpItem to check.
|
|
|
|
* @offset_x: Return location for the item's X offset.
|
|
|
|
* @offset_y: Return location for the item's Y offset.
|
2004-07-14 08:32:09 +08:00
|
|
|
*
|
2004-07-14 19:52:03 +08:00
|
|
|
* Reveals the X and Y offsets of the item.
|
2004-07-14 08:32:09 +08:00
|
|
|
*/
|
2003-05-08 22:06:03 +08:00
|
|
|
void
|
2016-05-20 05:51:44 +08:00
|
|
|
gimp_item_get_offset (GimpItem *item,
|
|
|
|
gint *offset_x,
|
|
|
|
gint *offset_y)
|
2003-05-08 22:06:03 +08:00
|
|
|
{
|
2011-01-31 04:49:51 +08:00
|
|
|
GimpItemPrivate *private;
|
|
|
|
|
2003-05-08 22:06:03 +08:00
|
|
|
g_return_if_fail (GIMP_IS_ITEM (item));
|
|
|
|
|
2011-01-31 04:49:51 +08:00
|
|
|
private = GET_PRIVATE (item);
|
|
|
|
|
|
|
|
if (offset_x) *offset_x = private->offset_x;
|
|
|
|
if (offset_y) *offset_y = private->offset_y;
|
2003-05-08 22:06:03 +08:00
|
|
|
}
|
|
|
|
|
2008-11-03 06:44:33 +08:00
|
|
|
void
|
2008-11-03 07:03:29 +08:00
|
|
|
gimp_item_set_offset (GimpItem *item,
|
|
|
|
gint offset_x,
|
|
|
|
gint offset_y)
|
2008-11-03 06:44:33 +08:00
|
|
|
{
|
2011-01-31 04:49:51 +08:00
|
|
|
GimpItemPrivate *private;
|
2012-05-16 04:25:12 +08:00
|
|
|
GList *list;
|
2011-01-31 04:49:51 +08:00
|
|
|
|
2008-11-03 06:44:33 +08:00
|
|
|
g_return_if_fail (GIMP_IS_ITEM (item));
|
|
|
|
|
2011-01-31 04:49:51 +08:00
|
|
|
private = GET_PRIVATE (item);
|
|
|
|
|
2008-11-12 05:14:52 +08:00
|
|
|
g_object_freeze_notify (G_OBJECT (item));
|
|
|
|
|
2011-01-31 04:49:51 +08:00
|
|
|
if (private->offset_x != offset_x)
|
2008-11-12 05:14:52 +08:00
|
|
|
{
|
2011-01-31 04:49:51 +08:00
|
|
|
private->offset_x = offset_x;
|
2008-11-12 05:14:52 +08:00
|
|
|
g_object_notify (G_OBJECT (item), "offset-x");
|
|
|
|
}
|
|
|
|
|
2011-01-31 04:49:51 +08:00
|
|
|
if (private->offset_y != offset_y)
|
2008-11-12 05:14:52 +08:00
|
|
|
{
|
2011-01-31 04:49:51 +08:00
|
|
|
private->offset_y = offset_y;
|
2008-11-12 05:14:52 +08:00
|
|
|
g_object_notify (G_OBJECT (item), "offset-y");
|
|
|
|
}
|
2008-11-03 06:44:33 +08:00
|
|
|
|
2012-05-16 04:25:12 +08:00
|
|
|
for (list = private->offset_nodes; list; list = g_list_next (list))
|
|
|
|
{
|
|
|
|
GeglNode *node = list->data;
|
|
|
|
|
|
|
|
gegl_node_set (node,
|
|
|
|
"x", (gdouble) private->offset_x,
|
|
|
|
"y", (gdouble) private->offset_y,
|
|
|
|
NULL);
|
|
|
|
}
|
2008-11-12 05:14:52 +08:00
|
|
|
|
|
|
|
g_object_thaw_notify (G_OBJECT (item));
|
2008-11-03 06:44:33 +08:00
|
|
|
}
|
|
|
|
|
2008-12-28 20:43:07 +08:00
|
|
|
gint
|
|
|
|
gimp_item_get_offset_x (GimpItem *item)
|
|
|
|
{
|
|
|
|
g_return_val_if_fail (GIMP_IS_ITEM (item), 0);
|
|
|
|
|
2011-01-31 04:49:51 +08:00
|
|
|
return GET_PRIVATE (item)->offset_x;
|
2008-12-28 20:43:07 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
gint
|
|
|
|
gimp_item_get_offset_y (GimpItem *item)
|
|
|
|
{
|
|
|
|
g_return_val_if_fail (GIMP_IS_ITEM (item), 0);
|
|
|
|
|
2011-01-31 04:49:51 +08:00
|
|
|
return GET_PRIVATE (item)->offset_y;
|
2008-12-28 20:43:07 +08:00
|
|
|
}
|
|
|
|
|
app: add gimp_item_{start,end}_move()
Add gimp_item_{start,end}_move(), and corresponding
GimpItem::{start,end}_move() virtual functions, which should be
called before/after "moving" the item (i.e., translating, scaling,
resizing, flipping, rotating, or transforming the item). Moves
performed between the outermost pair of start/end calls are treated
atomically.
What exactly does "treated atomically" entail depends on the
subclasses -- GimpItem doesn't provide a default implementation for
these functions, so the current commit doesn't change any behavior.
The next commit, which adds layer-mask support for group layers,
uses the functions to avoid cropping the mask too early while a
child is moving.
GimpItem calls {start,end}_move() in the various "move" functions
(gimp_item_{translate,scale,...}(), before performing the actual
operation. Additionally we call the functions in the
gimp_image_item_list_foo() functions, for each participating item,
so that the items are moved as a unit. We call the functions in
the various gimp_image_remove_foo() functions, since removing an
item may affect the size of its ancestors, and is therefore akin to
moving. We also call the functions in GimpEditSelectionTool, so
that the move tool moves items atomically while dragging.
2018-02-05 23:59:28 +08:00
|
|
|
void
|
|
|
|
gimp_item_start_move (GimpItem *item,
|
|
|
|
gboolean push_undo)
|
|
|
|
{
|
|
|
|
g_return_if_fail (GIMP_IS_ITEM (item));
|
|
|
|
|
|
|
|
if (GIMP_ITEM_GET_CLASS (item)->start_move)
|
|
|
|
GIMP_ITEM_GET_CLASS (item)->start_move (item, push_undo);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
gimp_item_end_move (GimpItem *item,
|
|
|
|
gboolean push_undo)
|
|
|
|
{
|
|
|
|
g_return_if_fail (GIMP_IS_ITEM (item));
|
|
|
|
|
|
|
|
if (GIMP_ITEM_GET_CLASS (item)->end_move)
|
|
|
|
GIMP_ITEM_GET_CLASS (item)->end_move (item, push_undo);
|
|
|
|
}
|
|
|
|
|
Bug 795410 - Deleting a layer group and then undoing the deletion ...
... raises a CRITICAL
gimp_item_{start,end}_move() currently serves two different
purposes: It is used by GimpLayer to suspend/resume mask resizing
of the layer's ancestors; this is necessary whenever an operation
on a layer might affect the size of its ancestors. It is also used
by GimpGroupLayer to suspend/resume its own mask resizing; this, on
the other hand, is only necessary before applying one of the
transformation functions to the group, so that mask modification is
handled by GimpLayer. In other words, the effects of
gimp_item_{start,end}_move() on group layers are only necessary in
a subset of the cases in which these functions are used.
While in itself this isn't a problem, it does cause issues when
removing a group layer: gimp_image_remove_layer() calls
gimp_item_start_move() before removing the layer, and
gimp_item_end_move() afterwards. While the former function is
called while the layer is still attached to the image, the latter
function is called after the layer is no longer attached. Since
GimpGroupLayer pushes an undo step in response to these calls, only
the call to start_move() results in an undo step, while the call to
end_move() doesn't, resulting in an unbalanced
GIMP_UNDO_GROUP_LAYER_START_MOVE undo step on the stack. This
causes problems when undoing the operation.
Add gimp_item_{start,end}_transform() functions, and corresponding
GimpItem::{start,end}_transform() virtual functions, which are more
specialized versions of gimp_item_{start,end}_move(), which should
be used instead of the former before/after transforming an item; in
other cases, such as when removing ot reordering an item,
gimp_item_{start,end}_move() should still be used. The default
implementation of GimpItem::{start,end}_transform() calls
gimp_item_{start,end}_move(), respectively, so subclasses that
override these functions don't have to do that themselves.
In GimpGroupLayer, override GimpItem::{start,end}_transform(),
instead of GimpItem::{start,end}_move(), for the same purpose of
suspending mask resize. This avoids these functions from being
called when removing a layer group, fixing the bug.
2018-04-22 15:39:40 +08:00
|
|
|
void
|
|
|
|
gimp_item_start_transform (GimpItem *item,
|
|
|
|
gboolean push_undo)
|
|
|
|
{
|
|
|
|
g_return_if_fail (GIMP_IS_ITEM (item));
|
|
|
|
|
|
|
|
if (GIMP_ITEM_GET_CLASS (item)->start_transform)
|
|
|
|
GIMP_ITEM_GET_CLASS (item)->start_transform (item, push_undo);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
gimp_item_end_transform (GimpItem *item,
|
|
|
|
gboolean push_undo)
|
|
|
|
{
|
|
|
|
g_return_if_fail (GIMP_IS_ITEM (item));
|
|
|
|
|
|
|
|
if (GIMP_ITEM_GET_CLASS (item)->end_transform)
|
|
|
|
GIMP_ITEM_GET_CLASS (item)->end_transform (item, push_undo);
|
|
|
|
}
|
|
|
|
|
2004-07-14 08:32:09 +08:00
|
|
|
/**
|
|
|
|
* gimp_item_translate:
|
2004-07-15 07:14:49 +08:00
|
|
|
* @item: The #GimpItem to move.
|
|
|
|
* @offset_x: Increment to the X offset of the item.
|
|
|
|
* @offset_y: Increment to the Y offset of the item.
|
2004-07-14 19:52:03 +08:00
|
|
|
* @push_undo: If #TRUE, create an entry in the image's undo stack
|
|
|
|
* for this action.
|
2004-07-14 08:32:09 +08:00
|
|
|
*
|
2004-07-14 19:52:03 +08:00
|
|
|
* Adds the specified increments to the X and Y offsets for the item.
|
2004-07-14 08:32:09 +08:00
|
|
|
*/
|
2003-05-09 03:11:17 +08:00
|
|
|
void
|
|
|
|
gimp_item_translate (GimpItem *item,
|
2018-04-23 07:08:54 +08:00
|
|
|
gdouble offset_x,
|
|
|
|
gdouble offset_y,
|
2003-05-09 03:11:17 +08:00
|
|
|
gboolean push_undo)
|
|
|
|
{
|
|
|
|
GimpItemClass *item_class;
|
2006-03-29 01:08:36 +08:00
|
|
|
GimpImage *image;
|
2003-05-09 03:11:17 +08:00
|
|
|
|
|
|
|
g_return_if_fail (GIMP_IS_ITEM (item));
|
|
|
|
|
|
|
|
item_class = GIMP_ITEM_GET_CLASS (item);
|
2006-11-05 02:18:32 +08:00
|
|
|
image = gimp_item_get_image (item);
|
2004-04-13 19:43:27 +08:00
|
|
|
|
2004-11-16 21:41:55 +08:00
|
|
|
if (! gimp_item_is_attached (item))
|
|
|
|
push_undo = FALSE;
|
|
|
|
|
2004-04-13 19:43:27 +08:00
|
|
|
if (push_undo)
|
2006-03-29 01:08:36 +08:00
|
|
|
gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_ITEM_DISPLACE,
|
2004-04-13 19:43:27 +08:00
|
|
|
item_class->translate_desc);
|
2003-05-09 03:11:17 +08:00
|
|
|
|
Bug 795410 - Deleting a layer group and then undoing the deletion ...
... raises a CRITICAL
gimp_item_{start,end}_move() currently serves two different
purposes: It is used by GimpLayer to suspend/resume mask resizing
of the layer's ancestors; this is necessary whenever an operation
on a layer might affect the size of its ancestors. It is also used
by GimpGroupLayer to suspend/resume its own mask resizing; this, on
the other hand, is only necessary before applying one of the
transformation functions to the group, so that mask modification is
handled by GimpLayer. In other words, the effects of
gimp_item_{start,end}_move() on group layers are only necessary in
a subset of the cases in which these functions are used.
While in itself this isn't a problem, it does cause issues when
removing a group layer: gimp_image_remove_layer() calls
gimp_item_start_move() before removing the layer, and
gimp_item_end_move() afterwards. While the former function is
called while the layer is still attached to the image, the latter
function is called after the layer is no longer attached. Since
GimpGroupLayer pushes an undo step in response to these calls, only
the call to start_move() results in an undo step, while the call to
end_move() doesn't, resulting in an unbalanced
GIMP_UNDO_GROUP_LAYER_START_MOVE undo step on the stack. This
causes problems when undoing the operation.
Add gimp_item_{start,end}_transform() functions, and corresponding
GimpItem::{start,end}_transform() virtual functions, which are more
specialized versions of gimp_item_{start,end}_move(), which should
be used instead of the former before/after transforming an item; in
other cases, such as when removing ot reordering an item,
gimp_item_{start,end}_move() should still be used. The default
implementation of GimpItem::{start,end}_transform() calls
gimp_item_{start,end}_move(), respectively, so subclasses that
override these functions don't have to do that themselves.
In GimpGroupLayer, override GimpItem::{start,end}_transform(),
instead of GimpItem::{start,end}_move(), for the same purpose of
suspending mask resize. This avoids these functions from being
called when removing a layer group, fixing the bug.
2018-04-22 15:39:40 +08:00
|
|
|
gimp_item_start_transform (item, push_undo);
|
app: add gimp_item_{start,end}_move()
Add gimp_item_{start,end}_move(), and corresponding
GimpItem::{start,end}_move() virtual functions, which should be
called before/after "moving" the item (i.e., translating, scaling,
resizing, flipping, rotating, or transforming the item). Moves
performed between the outermost pair of start/end calls are treated
atomically.
What exactly does "treated atomically" entail depends on the
subclasses -- GimpItem doesn't provide a default implementation for
these functions, so the current commit doesn't change any behavior.
The next commit, which adds layer-mask support for group layers,
uses the functions to avoid cropping the mask too early while a
child is moving.
GimpItem calls {start,end}_move() in the various "move" functions
(gimp_item_{translate,scale,...}(), before performing the actual
operation. Additionally we call the functions in the
gimp_image_item_list_foo() functions, for each participating item,
so that the items are moved as a unit. We call the functions in
the various gimp_image_remove_foo() functions, since removing an
item may affect the size of its ancestors, and is therefore akin to
moving. We also call the functions in GimpEditSelectionTool, so
that the move tool moves items atomically while dragging.
2018-02-05 23:59:28 +08:00
|
|
|
|
2004-07-15 07:14:49 +08:00
|
|
|
item_class->translate (item, offset_x, offset_y, push_undo);
|
2004-04-13 19:43:27 +08:00
|
|
|
|
Bug 795410 - Deleting a layer group and then undoing the deletion ...
... raises a CRITICAL
gimp_item_{start,end}_move() currently serves two different
purposes: It is used by GimpLayer to suspend/resume mask resizing
of the layer's ancestors; this is necessary whenever an operation
on a layer might affect the size of its ancestors. It is also used
by GimpGroupLayer to suspend/resume its own mask resizing; this, on
the other hand, is only necessary before applying one of the
transformation functions to the group, so that mask modification is
handled by GimpLayer. In other words, the effects of
gimp_item_{start,end}_move() on group layers are only necessary in
a subset of the cases in which these functions are used.
While in itself this isn't a problem, it does cause issues when
removing a group layer: gimp_image_remove_layer() calls
gimp_item_start_move() before removing the layer, and
gimp_item_end_move() afterwards. While the former function is
called while the layer is still attached to the image, the latter
function is called after the layer is no longer attached. Since
GimpGroupLayer pushes an undo step in response to these calls, only
the call to start_move() results in an undo step, while the call to
end_move() doesn't, resulting in an unbalanced
GIMP_UNDO_GROUP_LAYER_START_MOVE undo step on the stack. This
causes problems when undoing the operation.
Add gimp_item_{start,end}_transform() functions, and corresponding
GimpItem::{start,end}_transform() virtual functions, which are more
specialized versions of gimp_item_{start,end}_move(), which should
be used instead of the former before/after transforming an item; in
other cases, such as when removing ot reordering an item,
gimp_item_{start,end}_move() should still be used. The default
implementation of GimpItem::{start,end}_transform() calls
gimp_item_{start,end}_move(), respectively, so subclasses that
override these functions don't have to do that themselves.
In GimpGroupLayer, override GimpItem::{start,end}_transform(),
instead of GimpItem::{start,end}_move(), for the same purpose of
suspending mask resize. This avoids these functions from being
called when removing a layer group, fixing the bug.
2018-04-22 15:39:40 +08:00
|
|
|
gimp_item_end_transform (item, push_undo);
|
app: add gimp_item_{start,end}_move()
Add gimp_item_{start,end}_move(), and corresponding
GimpItem::{start,end}_move() virtual functions, which should be
called before/after "moving" the item (i.e., translating, scaling,
resizing, flipping, rotating, or transforming the item). Moves
performed between the outermost pair of start/end calls are treated
atomically.
What exactly does "treated atomically" entail depends on the
subclasses -- GimpItem doesn't provide a default implementation for
these functions, so the current commit doesn't change any behavior.
The next commit, which adds layer-mask support for group layers,
uses the functions to avoid cropping the mask too early while a
child is moving.
GimpItem calls {start,end}_move() in the various "move" functions
(gimp_item_{translate,scale,...}(), before performing the actual
operation. Additionally we call the functions in the
gimp_image_item_list_foo() functions, for each participating item,
so that the items are moved as a unit. We call the functions in
the various gimp_image_remove_foo() functions, since removing an
item may affect the size of its ancestors, and is therefore akin to
moving. We also call the functions in GimpEditSelectionTool, so
that the move tool moves items atomically while dragging.
2018-02-05 23:59:28 +08:00
|
|
|
|
2004-04-13 19:43:27 +08:00
|
|
|
if (push_undo)
|
2006-03-29 01:08:36 +08:00
|
|
|
gimp_image_undo_group_end (image);
|
2003-05-09 03:11:17 +08:00
|
|
|
}
|
|
|
|
|
2003-05-08 22:54:04 +08:00
|
|
|
/**
|
|
|
|
* gimp_item_check_scaling:
|
|
|
|
* @item: Item to check
|
|
|
|
* @new_width: proposed width of item, in pixels
|
|
|
|
* @new_height: proposed height of item, in pixels
|
|
|
|
*
|
|
|
|
* Scales item dimensions, then snaps them to pixel centers
|
|
|
|
*
|
2003-09-02 21:43:26 +08:00
|
|
|
* Returns: #FALSE if any dimension reduces to zero as a result
|
2003-05-08 22:54:04 +08:00
|
|
|
* of this; otherwise, returns #TRUE.
|
|
|
|
**/
|
|
|
|
gboolean
|
2016-05-20 05:51:44 +08:00
|
|
|
gimp_item_check_scaling (GimpItem *item,
|
|
|
|
gint new_width,
|
|
|
|
gint new_height)
|
2003-05-08 22:54:04 +08:00
|
|
|
{
|
2018-03-25 23:20:14 +08:00
|
|
|
GimpItemPrivate *private;
|
|
|
|
GimpImage *image;
|
|
|
|
gdouble img_scale_w;
|
|
|
|
gdouble img_scale_h;
|
|
|
|
gint new_item_offset_x;
|
|
|
|
gint new_item_offset_y;
|
|
|
|
gint new_item_width;
|
|
|
|
gint new_item_height;
|
2003-05-08 22:54:04 +08:00
|
|
|
|
|
|
|
g_return_val_if_fail (GIMP_IS_ITEM (item), FALSE);
|
|
|
|
|
2018-03-25 23:20:14 +08:00
|
|
|
private = GET_PRIVATE (item);
|
|
|
|
image = gimp_item_get_image (item);
|
|
|
|
|
|
|
|
img_scale_w = ((gdouble) new_width /
|
|
|
|
(gdouble) gimp_image_get_width (image));
|
|
|
|
img_scale_h = ((gdouble) new_height /
|
|
|
|
(gdouble) gimp_image_get_height (image));
|
|
|
|
new_item_offset_x = SIGNED_ROUND (img_scale_w * private->offset_x);
|
|
|
|
new_item_offset_y = SIGNED_ROUND (img_scale_h * private->offset_y);
|
|
|
|
new_item_width = SIGNED_ROUND (img_scale_w * (private->offset_x +
|
|
|
|
gimp_item_get_width (item))) -
|
|
|
|
new_item_offset_x;
|
|
|
|
new_item_height = SIGNED_ROUND (img_scale_h * (private->offset_y +
|
|
|
|
gimp_item_get_height (item))) -
|
|
|
|
new_item_offset_y;
|
2003-05-08 22:54:04 +08:00
|
|
|
|
2003-09-02 21:43:26 +08:00
|
|
|
return (new_item_width > 0 && new_item_height > 0);
|
2003-05-08 22:54:04 +08:00
|
|
|
}
|
|
|
|
|
2003-05-07 19:09:00 +08:00
|
|
|
void
|
|
|
|
gimp_item_scale (GimpItem *item,
|
|
|
|
gint new_width,
|
|
|
|
gint new_height,
|
|
|
|
gint new_offset_x,
|
|
|
|
gint new_offset_y,
|
2004-02-09 08:09:20 +08:00
|
|
|
GimpInterpolationType interpolation,
|
2004-08-11 02:47:21 +08:00
|
|
|
GimpProgress *progress)
|
2003-05-07 19:09:00 +08:00
|
|
|
{
|
|
|
|
GimpItemClass *item_class;
|
2006-03-29 01:08:36 +08:00
|
|
|
GimpImage *image;
|
app: add gimp_item_{start,end}_move()
Add gimp_item_{start,end}_move(), and corresponding
GimpItem::{start,end}_move() virtual functions, which should be
called before/after "moving" the item (i.e., translating, scaling,
resizing, flipping, rotating, or transforming the item). Moves
performed between the outermost pair of start/end calls are treated
atomically.
What exactly does "treated atomically" entail depends on the
subclasses -- GimpItem doesn't provide a default implementation for
these functions, so the current commit doesn't change any behavior.
The next commit, which adds layer-mask support for group layers,
uses the functions to avoid cropping the mask too early while a
child is moving.
GimpItem calls {start,end}_move() in the various "move" functions
(gimp_item_{translate,scale,...}(), before performing the actual
operation. Additionally we call the functions in the
gimp_image_item_list_foo() functions, for each participating item,
so that the items are moved as a unit. We call the functions in
the various gimp_image_remove_foo() functions, since removing an
item may affect the size of its ancestors, and is therefore akin to
moving. We also call the functions in GimpEditSelectionTool, so
that the move tool moves items atomically while dragging.
2018-02-05 23:59:28 +08:00
|
|
|
gboolean push_undo;
|
2003-05-07 19:09:00 +08:00
|
|
|
|
|
|
|
g_return_if_fail (GIMP_IS_ITEM (item));
|
2004-08-11 02:47:21 +08:00
|
|
|
g_return_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress));
|
2003-05-07 19:09:00 +08:00
|
|
|
|
2003-05-07 21:01:17 +08:00
|
|
|
if (new_width < 1 || new_height < 1)
|
2003-05-07 19:09:00 +08:00
|
|
|
return;
|
|
|
|
|
|
|
|
item_class = GIMP_ITEM_GET_CLASS (item);
|
2006-11-05 02:18:32 +08:00
|
|
|
image = gimp_item_get_image (item);
|
2004-04-13 19:43:27 +08:00
|
|
|
|
app: add gimp_item_{start,end}_move()
Add gimp_item_{start,end}_move(), and corresponding
GimpItem::{start,end}_move() virtual functions, which should be
called before/after "moving" the item (i.e., translating, scaling,
resizing, flipping, rotating, or transforming the item). Moves
performed between the outermost pair of start/end calls are treated
atomically.
What exactly does "treated atomically" entail depends on the
subclasses -- GimpItem doesn't provide a default implementation for
these functions, so the current commit doesn't change any behavior.
The next commit, which adds layer-mask support for group layers,
uses the functions to avoid cropping the mask too early while a
child is moving.
GimpItem calls {start,end}_move() in the various "move" functions
(gimp_item_{translate,scale,...}(), before performing the actual
operation. Additionally we call the functions in the
gimp_image_item_list_foo() functions, for each participating item,
so that the items are moved as a unit. We call the functions in
the various gimp_image_remove_foo() functions, since removing an
item may affect the size of its ancestors, and is therefore akin to
moving. We also call the functions in GimpEditSelectionTool, so
that the move tool moves items atomically while dragging.
2018-02-05 23:59:28 +08:00
|
|
|
push_undo = gimp_item_is_attached (item);
|
|
|
|
|
|
|
|
if (push_undo)
|
2006-03-29 01:08:36 +08:00
|
|
|
gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_ITEM_SCALE,
|
2005-01-16 03:17:11 +08:00
|
|
|
item_class->scale_desc);
|
2003-05-07 19:09:00 +08:00
|
|
|
|
Bug 795410 - Deleting a layer group and then undoing the deletion ...
... raises a CRITICAL
gimp_item_{start,end}_move() currently serves two different
purposes: It is used by GimpLayer to suspend/resume mask resizing
of the layer's ancestors; this is necessary whenever an operation
on a layer might affect the size of its ancestors. It is also used
by GimpGroupLayer to suspend/resume its own mask resizing; this, on
the other hand, is only necessary before applying one of the
transformation functions to the group, so that mask modification is
handled by GimpLayer. In other words, the effects of
gimp_item_{start,end}_move() on group layers are only necessary in
a subset of the cases in which these functions are used.
While in itself this isn't a problem, it does cause issues when
removing a group layer: gimp_image_remove_layer() calls
gimp_item_start_move() before removing the layer, and
gimp_item_end_move() afterwards. While the former function is
called while the layer is still attached to the image, the latter
function is called after the layer is no longer attached. Since
GimpGroupLayer pushes an undo step in response to these calls, only
the call to start_move() results in an undo step, while the call to
end_move() doesn't, resulting in an unbalanced
GIMP_UNDO_GROUP_LAYER_START_MOVE undo step on the stack. This
causes problems when undoing the operation.
Add gimp_item_{start,end}_transform() functions, and corresponding
GimpItem::{start,end}_transform() virtual functions, which are more
specialized versions of gimp_item_{start,end}_move(), which should
be used instead of the former before/after transforming an item; in
other cases, such as when removing ot reordering an item,
gimp_item_{start,end}_move() should still be used. The default
implementation of GimpItem::{start,end}_transform() calls
gimp_item_{start,end}_move(), respectively, so subclasses that
override these functions don't have to do that themselves.
In GimpGroupLayer, override GimpItem::{start,end}_transform(),
instead of GimpItem::{start,end}_move(), for the same purpose of
suspending mask resize. This avoids these functions from being
called when removing a layer group, fixing the bug.
2018-04-22 15:39:40 +08:00
|
|
|
gimp_item_start_transform (item, push_undo);
|
app: add gimp_item_{start,end}_move()
Add gimp_item_{start,end}_move(), and corresponding
GimpItem::{start,end}_move() virtual functions, which should be
called before/after "moving" the item (i.e., translating, scaling,
resizing, flipping, rotating, or transforming the item). Moves
performed between the outermost pair of start/end calls are treated
atomically.
What exactly does "treated atomically" entail depends on the
subclasses -- GimpItem doesn't provide a default implementation for
these functions, so the current commit doesn't change any behavior.
The next commit, which adds layer-mask support for group layers,
uses the functions to avoid cropping the mask too early while a
child is moving.
GimpItem calls {start,end}_move() in the various "move" functions
(gimp_item_{translate,scale,...}(), before performing the actual
operation. Additionally we call the functions in the
gimp_image_item_list_foo() functions, for each participating item,
so that the items are moved as a unit. We call the functions in
the various gimp_image_remove_foo() functions, since removing an
item may affect the size of its ancestors, and is therefore akin to
moving. We also call the functions in GimpEditSelectionTool, so
that the move tool moves items atomically while dragging.
2018-02-05 23:59:28 +08:00
|
|
|
|
2008-11-12 05:14:52 +08:00
|
|
|
g_object_freeze_notify (G_OBJECT (item));
|
|
|
|
|
2003-05-07 19:09:00 +08:00
|
|
|
item_class->scale (item, new_width, new_height, new_offset_x, new_offset_y,
|
2004-08-11 02:47:21 +08:00
|
|
|
interpolation, progress);
|
2004-04-13 19:43:27 +08:00
|
|
|
|
2008-11-12 05:14:52 +08:00
|
|
|
g_object_thaw_notify (G_OBJECT (item));
|
|
|
|
|
Bug 795410 - Deleting a layer group and then undoing the deletion ...
... raises a CRITICAL
gimp_item_{start,end}_move() currently serves two different
purposes: It is used by GimpLayer to suspend/resume mask resizing
of the layer's ancestors; this is necessary whenever an operation
on a layer might affect the size of its ancestors. It is also used
by GimpGroupLayer to suspend/resume its own mask resizing; this, on
the other hand, is only necessary before applying one of the
transformation functions to the group, so that mask modification is
handled by GimpLayer. In other words, the effects of
gimp_item_{start,end}_move() on group layers are only necessary in
a subset of the cases in which these functions are used.
While in itself this isn't a problem, it does cause issues when
removing a group layer: gimp_image_remove_layer() calls
gimp_item_start_move() before removing the layer, and
gimp_item_end_move() afterwards. While the former function is
called while the layer is still attached to the image, the latter
function is called after the layer is no longer attached. Since
GimpGroupLayer pushes an undo step in response to these calls, only
the call to start_move() results in an undo step, while the call to
end_move() doesn't, resulting in an unbalanced
GIMP_UNDO_GROUP_LAYER_START_MOVE undo step on the stack. This
causes problems when undoing the operation.
Add gimp_item_{start,end}_transform() functions, and corresponding
GimpItem::{start,end}_transform() virtual functions, which are more
specialized versions of gimp_item_{start,end}_move(), which should
be used instead of the former before/after transforming an item; in
other cases, such as when removing ot reordering an item,
gimp_item_{start,end}_move() should still be used. The default
implementation of GimpItem::{start,end}_transform() calls
gimp_item_{start,end}_move(), respectively, so subclasses that
override these functions don't have to do that themselves.
In GimpGroupLayer, override GimpItem::{start,end}_transform(),
instead of GimpItem::{start,end}_move(), for the same purpose of
suspending mask resize. This avoids these functions from being
called when removing a layer group, fixing the bug.
2018-04-22 15:39:40 +08:00
|
|
|
gimp_item_end_transform (item, push_undo);
|
app: add gimp_item_{start,end}_move()
Add gimp_item_{start,end}_move(), and corresponding
GimpItem::{start,end}_move() virtual functions, which should be
called before/after "moving" the item (i.e., translating, scaling,
resizing, flipping, rotating, or transforming the item). Moves
performed between the outermost pair of start/end calls are treated
atomically.
What exactly does "treated atomically" entail depends on the
subclasses -- GimpItem doesn't provide a default implementation for
these functions, so the current commit doesn't change any behavior.
The next commit, which adds layer-mask support for group layers,
uses the functions to avoid cropping the mask too early while a
child is moving.
GimpItem calls {start,end}_move() in the various "move" functions
(gimp_item_{translate,scale,...}(), before performing the actual
operation. Additionally we call the functions in the
gimp_image_item_list_foo() functions, for each participating item,
so that the items are moved as a unit. We call the functions in
the various gimp_image_remove_foo() functions, since removing an
item may affect the size of its ancestors, and is therefore akin to
moving. We also call the functions in GimpEditSelectionTool, so
that the move tool moves items atomically while dragging.
2018-02-05 23:59:28 +08:00
|
|
|
|
|
|
|
if (push_undo)
|
2006-03-29 01:08:36 +08:00
|
|
|
gimp_image_undo_group_end (image);
|
2003-05-07 19:09:00 +08:00
|
|
|
}
|
|
|
|
|
2003-05-08 22:54:04 +08:00
|
|
|
/**
|
|
|
|
* gimp_item_scale_by_factors:
|
|
|
|
* @item: Item to be transformed by explicit width and height factors.
|
|
|
|
* @w_factor: scale factor to apply to width and horizontal offset
|
|
|
|
* @h_factor: scale factor to apply to height and vertical offset
|
2003-09-02 21:43:26 +08:00
|
|
|
* @interpolation:
|
2004-08-11 02:47:21 +08:00
|
|
|
* @progress:
|
2003-09-02 21:43:26 +08:00
|
|
|
*
|
2003-05-08 22:54:04 +08:00
|
|
|
* Scales item dimensions and offsets by uniform width and
|
|
|
|
* height factors.
|
|
|
|
*
|
2006-08-09 05:06:36 +08:00
|
|
|
* Use gimp_item_scale_by_factors() in circumstances when the same
|
|
|
|
* width and height scaling factors are to be uniformly applied to a
|
|
|
|
* set of items. In this context, the item's dimensions and offsets
|
|
|
|
* from the sides of the containing image all change by these
|
|
|
|
* predetermined factors. By fiat, the fixed point of the transform is
|
|
|
|
* the upper left hand corner of the image. Returns #FALSE if a
|
|
|
|
* requested scale factor is zero or if a scaling zero's out a item
|
2003-05-08 22:54:04 +08:00
|
|
|
* dimension; returns #TRUE otherwise.
|
|
|
|
*
|
|
|
|
* Use gimp_item_scale() in circumstances where new item width
|
|
|
|
* and height dimensions are predetermined instead.
|
|
|
|
*
|
2003-09-02 21:43:26 +08:00
|
|
|
* Side effects: Undo set created for item. Old item imagery
|
|
|
|
* scaled & painted to new item tiles.
|
2003-05-08 22:54:04 +08:00
|
|
|
*
|
|
|
|
* Returns: #TRUE, if the scaled item has positive dimensions
|
|
|
|
* #FALSE if the scaled item has at least one zero dimension
|
|
|
|
**/
|
|
|
|
gboolean
|
|
|
|
gimp_item_scale_by_factors (GimpItem *item,
|
|
|
|
gdouble w_factor,
|
|
|
|
gdouble h_factor,
|
2004-02-09 08:09:20 +08:00
|
|
|
GimpInterpolationType interpolation,
|
2004-08-11 02:47:21 +08:00
|
|
|
GimpProgress *progress)
|
2018-03-25 23:20:14 +08:00
|
|
|
{
|
|
|
|
return gimp_item_scale_by_factors_with_origin (item,
|
|
|
|
w_factor, h_factor,
|
|
|
|
0, 0, 0, 0,
|
|
|
|
interpolation, progress);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* gimp_item_scale_by_factors:
|
|
|
|
* @item: Item to be transformed by explicit width and height factors.
|
|
|
|
* @w_factor: scale factor to apply to width and horizontal offset
|
|
|
|
* @h_factor: scale factor to apply to height and vertical offset
|
|
|
|
* @origin_x: x-coordinate of the transformation input origin
|
|
|
|
* @origin_y: y-coordinate of the transformation input origin
|
|
|
|
* @new_origin_x: x-coordinate of the transformation output origin
|
|
|
|
* @new_origin_y: y-coordinate of the transformation output origin
|
|
|
|
* @interpolation:
|
|
|
|
* @progress:
|
|
|
|
*
|
|
|
|
* Same as gimp_item_scale_by_factors(), but with the option to specify
|
|
|
|
* custom input and output points of origin for the transformation.
|
|
|
|
*
|
|
|
|
* Returns: #TRUE, if the scaled item has positive dimensions
|
|
|
|
* #FALSE if the scaled item has at least one zero dimension
|
|
|
|
**/
|
|
|
|
gboolean
|
|
|
|
gimp_item_scale_by_factors_with_origin (GimpItem *item,
|
|
|
|
gdouble w_factor,
|
|
|
|
gdouble h_factor,
|
|
|
|
gint origin_x,
|
|
|
|
gint origin_y,
|
|
|
|
gint new_origin_x,
|
|
|
|
gint new_origin_y,
|
|
|
|
GimpInterpolationType interpolation,
|
|
|
|
GimpProgress *progress)
|
2003-05-08 22:54:04 +08:00
|
|
|
{
|
2011-01-31 04:49:51 +08:00
|
|
|
GimpItemPrivate *private;
|
|
|
|
gint new_width, new_height;
|
|
|
|
gint new_offset_x, new_offset_y;
|
2003-05-08 22:54:04 +08:00
|
|
|
|
|
|
|
g_return_val_if_fail (GIMP_IS_ITEM (item), FALSE);
|
2004-08-11 02:47:21 +08:00
|
|
|
g_return_val_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress), FALSE);
|
2003-05-08 22:54:04 +08:00
|
|
|
|
2011-01-31 04:49:51 +08:00
|
|
|
private = GET_PRIVATE (item);
|
|
|
|
|
2018-03-25 23:20:14 +08:00
|
|
|
if (w_factor <= 0.0 || h_factor <= 0.0)
|
2003-05-08 22:54:04 +08:00
|
|
|
{
|
2018-03-25 23:20:14 +08:00
|
|
|
g_warning ("%s: requested width or height scale is non-positive",
|
|
|
|
G_STRFUNC);
|
2003-05-08 22:54:04 +08:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2018-03-25 23:20:14 +08:00
|
|
|
new_offset_x = SIGNED_ROUND (w_factor * (private->offset_x - origin_x));
|
|
|
|
new_offset_y = SIGNED_ROUND (h_factor * (private->offset_y - origin_y));
|
|
|
|
new_width = SIGNED_ROUND (w_factor * (private->offset_x - origin_x +
|
|
|
|
gimp_item_get_width (item))) -
|
|
|
|
new_offset_x;
|
|
|
|
new_height = SIGNED_ROUND (h_factor * (private->offset_y - origin_y +
|
|
|
|
gimp_item_get_height (item))) -
|
|
|
|
new_offset_y;
|
|
|
|
|
|
|
|
new_offset_x += new_origin_x;
|
|
|
|
new_offset_y += new_origin_y;
|
2003-05-08 22:54:04 +08:00
|
|
|
|
2018-03-25 23:20:14 +08:00
|
|
|
if (new_width > 0 && new_height > 0)
|
2003-05-08 22:54:04 +08:00
|
|
|
{
|
|
|
|
gimp_item_scale (item,
|
|
|
|
new_width, new_height,
|
|
|
|
new_offset_x, new_offset_y,
|
2004-08-11 02:47:21 +08:00
|
|
|
interpolation, progress);
|
2003-05-08 22:54:04 +08:00
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* gimp_item_scale_by_origin:
|
|
|
|
* @item: The item to be transformed by width & height scale factors
|
|
|
|
* @new_width: The width that item will acquire
|
|
|
|
* @new_height: The height that the item will acquire
|
2003-08-10 00:46:02 +08:00
|
|
|
* @interpolation:
|
2004-08-11 02:47:21 +08:00
|
|
|
* @progress:
|
2003-05-08 22:54:04 +08:00
|
|
|
* @local_origin: sets fixed point of the scaling transform. See below.
|
|
|
|
*
|
|
|
|
* Sets item dimensions to new_width and
|
|
|
|
* new_height. Derives vertical and horizontal scaling
|
|
|
|
* transforms from new width and height. If local_origin is
|
2004-07-14 08:32:09 +08:00
|
|
|
* #TRUE, the fixed point of the scaling transform coincides
|
2003-05-08 22:54:04 +08:00
|
|
|
* with the item's center point. Otherwise, the fixed
|
2011-01-31 04:49:51 +08:00
|
|
|
* point is taken to be [-GimpItem::offset_x, -GimpItem::->offset_y].
|
2003-05-08 22:54:04 +08:00
|
|
|
*
|
|
|
|
* Since this function derives scale factors from new and
|
|
|
|
* current item dimensions, these factors will vary from
|
|
|
|
* item to item because of aliasing artifacts; factor
|
|
|
|
* variations among items can be quite large where item
|
2003-09-02 21:43:26 +08:00
|
|
|
* dimensions approach pixel dimensions. Use
|
2003-05-08 22:54:04 +08:00
|
|
|
* gimp_item_scale_by_factors() where constant scales are to
|
|
|
|
* be uniformly applied to a number of items.
|
|
|
|
*
|
|
|
|
* Side effects: undo set created for item.
|
2003-09-02 21:43:26 +08:00
|
|
|
* Old item imagery scaled
|
|
|
|
* & painted to new item tiles
|
2003-05-08 22:54:04 +08:00
|
|
|
**/
|
|
|
|
void
|
|
|
|
gimp_item_scale_by_origin (GimpItem *item,
|
|
|
|
gint new_width,
|
|
|
|
gint new_height,
|
2003-08-09 03:30:23 +08:00
|
|
|
GimpInterpolationType interpolation,
|
2004-08-11 02:47:21 +08:00
|
|
|
GimpProgress *progress,
|
2003-05-08 22:54:04 +08:00
|
|
|
gboolean local_origin)
|
|
|
|
{
|
2011-01-31 04:49:51 +08:00
|
|
|
GimpItemPrivate *private;
|
|
|
|
gint new_offset_x, new_offset_y;
|
2003-05-08 22:54:04 +08:00
|
|
|
|
|
|
|
g_return_if_fail (GIMP_IS_ITEM (item));
|
2004-08-11 02:47:21 +08:00
|
|
|
g_return_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress));
|
2003-05-08 22:54:04 +08:00
|
|
|
|
2011-01-31 04:49:51 +08:00
|
|
|
private = GET_PRIVATE (item);
|
|
|
|
|
2003-05-08 22:54:04 +08:00
|
|
|
if (new_width == 0 || new_height == 0)
|
|
|
|
{
|
2006-08-09 05:06:36 +08:00
|
|
|
g_warning ("%s: requested width or height equals zero", G_STRFUNC);
|
2003-05-08 22:54:04 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (local_origin)
|
|
|
|
{
|
2011-01-31 04:49:51 +08:00
|
|
|
new_offset_x = (private->offset_x +
|
2008-11-03 08:09:01 +08:00
|
|
|
((gimp_item_get_width (item) - new_width) / 2.0));
|
2011-01-31 04:49:51 +08:00
|
|
|
new_offset_y = (private->offset_y +
|
2008-11-03 08:09:01 +08:00
|
|
|
((gimp_item_get_height (item) - new_height) / 2.0));
|
2003-05-08 22:54:04 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2003-09-02 21:43:26 +08:00
|
|
|
new_offset_x = (gint) (((gdouble) new_width *
|
2011-01-31 04:49:51 +08:00
|
|
|
(gdouble) private->offset_x /
|
2008-11-03 08:09:01 +08:00
|
|
|
(gdouble) gimp_item_get_width (item)));
|
2003-05-08 22:54:04 +08:00
|
|
|
|
2003-09-02 21:43:26 +08:00
|
|
|
new_offset_y = (gint) (((gdouble) new_height *
|
2011-01-31 04:49:51 +08:00
|
|
|
(gdouble) private->offset_y /
|
2008-11-03 08:09:01 +08:00
|
|
|
(gdouble) gimp_item_get_height (item)));
|
2003-05-08 22:54:04 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
gimp_item_scale (item,
|
|
|
|
new_width, new_height,
|
|
|
|
new_offset_x, new_offset_y,
|
2004-08-11 02:47:21 +08:00
|
|
|
interpolation, progress);
|
2003-05-08 22:54:04 +08:00
|
|
|
}
|
|
|
|
|
2003-05-07 21:01:17 +08:00
|
|
|
void
|
2016-10-10 06:02:16 +08:00
|
|
|
gimp_item_resize (GimpItem *item,
|
|
|
|
GimpContext *context,
|
|
|
|
GimpFillType fill_type,
|
|
|
|
gint new_width,
|
|
|
|
gint new_height,
|
|
|
|
gint offset_x,
|
|
|
|
gint offset_y)
|
2003-05-07 21:01:17 +08:00
|
|
|
{
|
|
|
|
GimpItemClass *item_class;
|
2006-03-29 01:08:36 +08:00
|
|
|
GimpImage *image;
|
app: add gimp_item_{start,end}_move()
Add gimp_item_{start,end}_move(), and corresponding
GimpItem::{start,end}_move() virtual functions, which should be
called before/after "moving" the item (i.e., translating, scaling,
resizing, flipping, rotating, or transforming the item). Moves
performed between the outermost pair of start/end calls are treated
atomically.
What exactly does "treated atomically" entail depends on the
subclasses -- GimpItem doesn't provide a default implementation for
these functions, so the current commit doesn't change any behavior.
The next commit, which adds layer-mask support for group layers,
uses the functions to avoid cropping the mask too early while a
child is moving.
GimpItem calls {start,end}_move() in the various "move" functions
(gimp_item_{translate,scale,...}(), before performing the actual
operation. Additionally we call the functions in the
gimp_image_item_list_foo() functions, for each participating item,
so that the items are moved as a unit. We call the functions in
the various gimp_image_remove_foo() functions, since removing an
item may affect the size of its ancestors, and is therefore akin to
moving. We also call the functions in GimpEditSelectionTool, so
that the move tool moves items atomically while dragging.
2018-02-05 23:59:28 +08:00
|
|
|
gboolean push_undo;
|
2003-05-07 21:01:17 +08:00
|
|
|
|
|
|
|
g_return_if_fail (GIMP_IS_ITEM (item));
|
2004-04-15 07:37:34 +08:00
|
|
|
g_return_if_fail (GIMP_IS_CONTEXT (context));
|
2003-05-07 21:01:17 +08:00
|
|
|
|
|
|
|
if (new_width < 1 || new_height < 1)
|
|
|
|
return;
|
|
|
|
|
|
|
|
item_class = GIMP_ITEM_GET_CLASS (item);
|
2006-11-05 02:18:32 +08:00
|
|
|
image = gimp_item_get_image (item);
|
2004-04-13 19:43:27 +08:00
|
|
|
|
app: add gimp_item_{start,end}_move()
Add gimp_item_{start,end}_move(), and corresponding
GimpItem::{start,end}_move() virtual functions, which should be
called before/after "moving" the item (i.e., translating, scaling,
resizing, flipping, rotating, or transforming the item). Moves
performed between the outermost pair of start/end calls are treated
atomically.
What exactly does "treated atomically" entail depends on the
subclasses -- GimpItem doesn't provide a default implementation for
these functions, so the current commit doesn't change any behavior.
The next commit, which adds layer-mask support for group layers,
uses the functions to avoid cropping the mask too early while a
child is moving.
GimpItem calls {start,end}_move() in the various "move" functions
(gimp_item_{translate,scale,...}(), before performing the actual
operation. Additionally we call the functions in the
gimp_image_item_list_foo() functions, for each participating item,
so that the items are moved as a unit. We call the functions in
the various gimp_image_remove_foo() functions, since removing an
item may affect the size of its ancestors, and is therefore akin to
moving. We also call the functions in GimpEditSelectionTool, so
that the move tool moves items atomically while dragging.
2018-02-05 23:59:28 +08:00
|
|
|
push_undo = gimp_item_is_attached (item);
|
|
|
|
|
|
|
|
if (push_undo)
|
2006-03-29 01:08:36 +08:00
|
|
|
gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_ITEM_RESIZE,
|
2005-01-16 03:17:11 +08:00
|
|
|
item_class->resize_desc);
|
2003-05-07 21:01:17 +08:00
|
|
|
|
Bug 795410 - Deleting a layer group and then undoing the deletion ...
... raises a CRITICAL
gimp_item_{start,end}_move() currently serves two different
purposes: It is used by GimpLayer to suspend/resume mask resizing
of the layer's ancestors; this is necessary whenever an operation
on a layer might affect the size of its ancestors. It is also used
by GimpGroupLayer to suspend/resume its own mask resizing; this, on
the other hand, is only necessary before applying one of the
transformation functions to the group, so that mask modification is
handled by GimpLayer. In other words, the effects of
gimp_item_{start,end}_move() on group layers are only necessary in
a subset of the cases in which these functions are used.
While in itself this isn't a problem, it does cause issues when
removing a group layer: gimp_image_remove_layer() calls
gimp_item_start_move() before removing the layer, and
gimp_item_end_move() afterwards. While the former function is
called while the layer is still attached to the image, the latter
function is called after the layer is no longer attached. Since
GimpGroupLayer pushes an undo step in response to these calls, only
the call to start_move() results in an undo step, while the call to
end_move() doesn't, resulting in an unbalanced
GIMP_UNDO_GROUP_LAYER_START_MOVE undo step on the stack. This
causes problems when undoing the operation.
Add gimp_item_{start,end}_transform() functions, and corresponding
GimpItem::{start,end}_transform() virtual functions, which are more
specialized versions of gimp_item_{start,end}_move(), which should
be used instead of the former before/after transforming an item; in
other cases, such as when removing ot reordering an item,
gimp_item_{start,end}_move() should still be used. The default
implementation of GimpItem::{start,end}_transform() calls
gimp_item_{start,end}_move(), respectively, so subclasses that
override these functions don't have to do that themselves.
In GimpGroupLayer, override GimpItem::{start,end}_transform(),
instead of GimpItem::{start,end}_move(), for the same purpose of
suspending mask resize. This avoids these functions from being
called when removing a layer group, fixing the bug.
2018-04-22 15:39:40 +08:00
|
|
|
/* note that we call gimp_item_start_move(), and not
|
|
|
|
* gimp_item_start_transform(). whether or not a resize operation should be
|
|
|
|
* considered a transform operation, or a move operation, depends on the
|
|
|
|
* intended use of these functions by subclasses. atm, we only use
|
|
|
|
* gimp_item_{start,end}_transform() to suspend mask resizing in group
|
|
|
|
* layers, which should not happen when reisizing a group, hence the call to
|
|
|
|
* gimp_item_start_move().
|
|
|
|
*
|
|
|
|
* see the comment in gimp_group_layer_resize() for more information.
|
|
|
|
*/
|
app: add gimp_item_{start,end}_move()
Add gimp_item_{start,end}_move(), and corresponding
GimpItem::{start,end}_move() virtual functions, which should be
called before/after "moving" the item (i.e., translating, scaling,
resizing, flipping, rotating, or transforming the item). Moves
performed between the outermost pair of start/end calls are treated
atomically.
What exactly does "treated atomically" entail depends on the
subclasses -- GimpItem doesn't provide a default implementation for
these functions, so the current commit doesn't change any behavior.
The next commit, which adds layer-mask support for group layers,
uses the functions to avoid cropping the mask too early while a
child is moving.
GimpItem calls {start,end}_move() in the various "move" functions
(gimp_item_{translate,scale,...}(), before performing the actual
operation. Additionally we call the functions in the
gimp_image_item_list_foo() functions, for each participating item,
so that the items are moved as a unit. We call the functions in
the various gimp_image_remove_foo() functions, since removing an
item may affect the size of its ancestors, and is therefore akin to
moving. We also call the functions in GimpEditSelectionTool, so
that the move tool moves items atomically while dragging.
2018-02-05 23:59:28 +08:00
|
|
|
gimp_item_start_move (item, push_undo);
|
|
|
|
|
2008-11-12 05:14:52 +08:00
|
|
|
g_object_freeze_notify (G_OBJECT (item));
|
|
|
|
|
2016-10-10 06:02:16 +08:00
|
|
|
item_class->resize (item, context, fill_type,
|
|
|
|
new_width, new_height, offset_x, offset_y);
|
2004-04-13 19:43:27 +08:00
|
|
|
|
2008-11-12 05:14:52 +08:00
|
|
|
g_object_thaw_notify (G_OBJECT (item));
|
|
|
|
|
app: add gimp_item_{start,end}_move()
Add gimp_item_{start,end}_move(), and corresponding
GimpItem::{start,end}_move() virtual functions, which should be
called before/after "moving" the item (i.e., translating, scaling,
resizing, flipping, rotating, or transforming the item). Moves
performed between the outermost pair of start/end calls are treated
atomically.
What exactly does "treated atomically" entail depends on the
subclasses -- GimpItem doesn't provide a default implementation for
these functions, so the current commit doesn't change any behavior.
The next commit, which adds layer-mask support for group layers,
uses the functions to avoid cropping the mask too early while a
child is moving.
GimpItem calls {start,end}_move() in the various "move" functions
(gimp_item_{translate,scale,...}(), before performing the actual
operation. Additionally we call the functions in the
gimp_image_item_list_foo() functions, for each participating item,
so that the items are moved as a unit. We call the functions in
the various gimp_image_remove_foo() functions, since removing an
item may affect the size of its ancestors, and is therefore akin to
moving. We also call the functions in GimpEditSelectionTool, so
that the move tool moves items atomically while dragging.
2018-02-05 23:59:28 +08:00
|
|
|
gimp_item_end_move (item, push_undo);
|
|
|
|
|
|
|
|
if (push_undo)
|
2006-03-29 01:08:36 +08:00
|
|
|
gimp_image_undo_group_end (image);
|
2003-05-07 21:01:17 +08:00
|
|
|
}
|
|
|
|
|
2003-05-12 23:56:36 +08:00
|
|
|
void
|
|
|
|
gimp_item_flip (GimpItem *item,
|
2004-04-15 07:37:34 +08:00
|
|
|
GimpContext *context,
|
2003-05-12 23:56:36 +08:00
|
|
|
GimpOrientationType flip_type,
|
2003-05-13 21:57:11 +08:00
|
|
|
gdouble axis,
|
|
|
|
gboolean clip_result)
|
2003-05-12 23:56:36 +08:00
|
|
|
{
|
|
|
|
GimpItemClass *item_class;
|
2006-03-29 01:08:36 +08:00
|
|
|
GimpImage *image;
|
app: add gimp_item_{start,end}_move()
Add gimp_item_{start,end}_move(), and corresponding
GimpItem::{start,end}_move() virtual functions, which should be
called before/after "moving" the item (i.e., translating, scaling,
resizing, flipping, rotating, or transforming the item). Moves
performed between the outermost pair of start/end calls are treated
atomically.
What exactly does "treated atomically" entail depends on the
subclasses -- GimpItem doesn't provide a default implementation for
these functions, so the current commit doesn't change any behavior.
The next commit, which adds layer-mask support for group layers,
uses the functions to avoid cropping the mask too early while a
child is moving.
GimpItem calls {start,end}_move() in the various "move" functions
(gimp_item_{translate,scale,...}(), before performing the actual
operation. Additionally we call the functions in the
gimp_image_item_list_foo() functions, for each participating item,
so that the items are moved as a unit. We call the functions in
the various gimp_image_remove_foo() functions, since removing an
item may affect the size of its ancestors, and is therefore akin to
moving. We also call the functions in GimpEditSelectionTool, so
that the move tool moves items atomically while dragging.
2018-02-05 23:59:28 +08:00
|
|
|
gboolean push_undo;
|
2003-05-12 23:56:36 +08:00
|
|
|
|
|
|
|
g_return_if_fail (GIMP_IS_ITEM (item));
|
2004-11-16 21:41:55 +08:00
|
|
|
g_return_if_fail (gimp_item_is_attached (item));
|
2004-04-15 07:37:34 +08:00
|
|
|
g_return_if_fail (GIMP_IS_CONTEXT (context));
|
2003-05-12 23:56:36 +08:00
|
|
|
|
|
|
|
item_class = GIMP_ITEM_GET_CLASS (item);
|
2006-11-05 02:18:32 +08:00
|
|
|
image = gimp_item_get_image (item);
|
2004-04-13 19:43:27 +08:00
|
|
|
|
app: add gimp_item_{start,end}_move()
Add gimp_item_{start,end}_move(), and corresponding
GimpItem::{start,end}_move() virtual functions, which should be
called before/after "moving" the item (i.e., translating, scaling,
resizing, flipping, rotating, or transforming the item). Moves
performed between the outermost pair of start/end calls are treated
atomically.
What exactly does "treated atomically" entail depends on the
subclasses -- GimpItem doesn't provide a default implementation for
these functions, so the current commit doesn't change any behavior.
The next commit, which adds layer-mask support for group layers,
uses the functions to avoid cropping the mask too early while a
child is moving.
GimpItem calls {start,end}_move() in the various "move" functions
(gimp_item_{translate,scale,...}(), before performing the actual
operation. Additionally we call the functions in the
gimp_image_item_list_foo() functions, for each participating item,
so that the items are moved as a unit. We call the functions in
the various gimp_image_remove_foo() functions, since removing an
item may affect the size of its ancestors, and is therefore akin to
moving. We also call the functions in GimpEditSelectionTool, so
that the move tool moves items atomically while dragging.
2018-02-05 23:59:28 +08:00
|
|
|
push_undo = gimp_item_is_attached (item);
|
|
|
|
|
|
|
|
if (push_undo)
|
|
|
|
gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_TRANSFORM,
|
|
|
|
item_class->flip_desc);
|
|
|
|
|
Bug 795410 - Deleting a layer group and then undoing the deletion ...
... raises a CRITICAL
gimp_item_{start,end}_move() currently serves two different
purposes: It is used by GimpLayer to suspend/resume mask resizing
of the layer's ancestors; this is necessary whenever an operation
on a layer might affect the size of its ancestors. It is also used
by GimpGroupLayer to suspend/resume its own mask resizing; this, on
the other hand, is only necessary before applying one of the
transformation functions to the group, so that mask modification is
handled by GimpLayer. In other words, the effects of
gimp_item_{start,end}_move() on group layers are only necessary in
a subset of the cases in which these functions are used.
While in itself this isn't a problem, it does cause issues when
removing a group layer: gimp_image_remove_layer() calls
gimp_item_start_move() before removing the layer, and
gimp_item_end_move() afterwards. While the former function is
called while the layer is still attached to the image, the latter
function is called after the layer is no longer attached. Since
GimpGroupLayer pushes an undo step in response to these calls, only
the call to start_move() results in an undo step, while the call to
end_move() doesn't, resulting in an unbalanced
GIMP_UNDO_GROUP_LAYER_START_MOVE undo step on the stack. This
causes problems when undoing the operation.
Add gimp_item_{start,end}_transform() functions, and corresponding
GimpItem::{start,end}_transform() virtual functions, which are more
specialized versions of gimp_item_{start,end}_move(), which should
be used instead of the former before/after transforming an item; in
other cases, such as when removing ot reordering an item,
gimp_item_{start,end}_move() should still be used. The default
implementation of GimpItem::{start,end}_transform() calls
gimp_item_{start,end}_move(), respectively, so subclasses that
override these functions don't have to do that themselves.
In GimpGroupLayer, override GimpItem::{start,end}_transform(),
instead of GimpItem::{start,end}_move(), for the same purpose of
suspending mask resize. This avoids these functions from being
called when removing a layer group, fixing the bug.
2018-04-22 15:39:40 +08:00
|
|
|
gimp_item_start_transform (item, push_undo);
|
2003-05-12 23:56:36 +08:00
|
|
|
|
2008-11-12 05:14:52 +08:00
|
|
|
g_object_freeze_notify (G_OBJECT (item));
|
|
|
|
|
2004-04-15 07:37:34 +08:00
|
|
|
item_class->flip (item, context, flip_type, axis, clip_result);
|
2004-04-13 19:43:27 +08:00
|
|
|
|
2008-11-12 05:14:52 +08:00
|
|
|
g_object_thaw_notify (G_OBJECT (item));
|
|
|
|
|
Bug 795410 - Deleting a layer group and then undoing the deletion ...
... raises a CRITICAL
gimp_item_{start,end}_move() currently serves two different
purposes: It is used by GimpLayer to suspend/resume mask resizing
of the layer's ancestors; this is necessary whenever an operation
on a layer might affect the size of its ancestors. It is also used
by GimpGroupLayer to suspend/resume its own mask resizing; this, on
the other hand, is only necessary before applying one of the
transformation functions to the group, so that mask modification is
handled by GimpLayer. In other words, the effects of
gimp_item_{start,end}_move() on group layers are only necessary in
a subset of the cases in which these functions are used.
While in itself this isn't a problem, it does cause issues when
removing a group layer: gimp_image_remove_layer() calls
gimp_item_start_move() before removing the layer, and
gimp_item_end_move() afterwards. While the former function is
called while the layer is still attached to the image, the latter
function is called after the layer is no longer attached. Since
GimpGroupLayer pushes an undo step in response to these calls, only
the call to start_move() results in an undo step, while the call to
end_move() doesn't, resulting in an unbalanced
GIMP_UNDO_GROUP_LAYER_START_MOVE undo step on the stack. This
causes problems when undoing the operation.
Add gimp_item_{start,end}_transform() functions, and corresponding
GimpItem::{start,end}_transform() virtual functions, which are more
specialized versions of gimp_item_{start,end}_move(), which should
be used instead of the former before/after transforming an item; in
other cases, such as when removing ot reordering an item,
gimp_item_{start,end}_move() should still be used. The default
implementation of GimpItem::{start,end}_transform() calls
gimp_item_{start,end}_move(), respectively, so subclasses that
override these functions don't have to do that themselves.
In GimpGroupLayer, override GimpItem::{start,end}_transform(),
instead of GimpItem::{start,end}_move(), for the same purpose of
suspending mask resize. This avoids these functions from being
called when removing a layer group, fixing the bug.
2018-04-22 15:39:40 +08:00
|
|
|
gimp_item_end_transform (item, push_undo);
|
app: add gimp_item_{start,end}_move()
Add gimp_item_{start,end}_move(), and corresponding
GimpItem::{start,end}_move() virtual functions, which should be
called before/after "moving" the item (i.e., translating, scaling,
resizing, flipping, rotating, or transforming the item). Moves
performed between the outermost pair of start/end calls are treated
atomically.
What exactly does "treated atomically" entail depends on the
subclasses -- GimpItem doesn't provide a default implementation for
these functions, so the current commit doesn't change any behavior.
The next commit, which adds layer-mask support for group layers,
uses the functions to avoid cropping the mask too early while a
child is moving.
GimpItem calls {start,end}_move() in the various "move" functions
(gimp_item_{translate,scale,...}(), before performing the actual
operation. Additionally we call the functions in the
gimp_image_item_list_foo() functions, for each participating item,
so that the items are moved as a unit. We call the functions in
the various gimp_image_remove_foo() functions, since removing an
item may affect the size of its ancestors, and is therefore akin to
moving. We also call the functions in GimpEditSelectionTool, so
that the move tool moves items atomically while dragging.
2018-02-05 23:59:28 +08:00
|
|
|
|
|
|
|
if (push_undo)
|
|
|
|
gimp_image_undo_group_end (image);
|
2003-05-12 23:56:36 +08:00
|
|
|
}
|
|
|
|
|
2003-05-20 18:36:29 +08:00
|
|
|
void
|
|
|
|
gimp_item_rotate (GimpItem *item,
|
2004-04-15 07:37:34 +08:00
|
|
|
GimpContext *context,
|
2003-05-20 18:36:29 +08:00
|
|
|
GimpRotationType rotate_type,
|
|
|
|
gdouble center_x,
|
|
|
|
gdouble center_y,
|
|
|
|
gboolean clip_result)
|
|
|
|
{
|
|
|
|
GimpItemClass *item_class;
|
2006-03-29 01:08:36 +08:00
|
|
|
GimpImage *image;
|
app: add gimp_item_{start,end}_move()
Add gimp_item_{start,end}_move(), and corresponding
GimpItem::{start,end}_move() virtual functions, which should be
called before/after "moving" the item (i.e., translating, scaling,
resizing, flipping, rotating, or transforming the item). Moves
performed between the outermost pair of start/end calls are treated
atomically.
What exactly does "treated atomically" entail depends on the
subclasses -- GimpItem doesn't provide a default implementation for
these functions, so the current commit doesn't change any behavior.
The next commit, which adds layer-mask support for group layers,
uses the functions to avoid cropping the mask too early while a
child is moving.
GimpItem calls {start,end}_move() in the various "move" functions
(gimp_item_{translate,scale,...}(), before performing the actual
operation. Additionally we call the functions in the
gimp_image_item_list_foo() functions, for each participating item,
so that the items are moved as a unit. We call the functions in
the various gimp_image_remove_foo() functions, since removing an
item may affect the size of its ancestors, and is therefore akin to
moving. We also call the functions in GimpEditSelectionTool, so
that the move tool moves items atomically while dragging.
2018-02-05 23:59:28 +08:00
|
|
|
gboolean push_undo;
|
2003-05-20 18:36:29 +08:00
|
|
|
|
|
|
|
g_return_if_fail (GIMP_IS_ITEM (item));
|
2018-09-06 06:34:54 +08:00
|
|
|
g_return_if_fail (gimp_item_is_attached (item));
|
2004-04-15 07:37:34 +08:00
|
|
|
g_return_if_fail (GIMP_IS_CONTEXT (context));
|
2003-05-20 18:36:29 +08:00
|
|
|
|
|
|
|
item_class = GIMP_ITEM_GET_CLASS (item);
|
2006-11-05 02:18:32 +08:00
|
|
|
image = gimp_item_get_image (item);
|
2004-04-13 19:43:27 +08:00
|
|
|
|
app: add gimp_item_{start,end}_move()
Add gimp_item_{start,end}_move(), and corresponding
GimpItem::{start,end}_move() virtual functions, which should be
called before/after "moving" the item (i.e., translating, scaling,
resizing, flipping, rotating, or transforming the item). Moves
performed between the outermost pair of start/end calls are treated
atomically.
What exactly does "treated atomically" entail depends on the
subclasses -- GimpItem doesn't provide a default implementation for
these functions, so the current commit doesn't change any behavior.
The next commit, which adds layer-mask support for group layers,
uses the functions to avoid cropping the mask too early while a
child is moving.
GimpItem calls {start,end}_move() in the various "move" functions
(gimp_item_{translate,scale,...}(), before performing the actual
operation. Additionally we call the functions in the
gimp_image_item_list_foo() functions, for each participating item,
so that the items are moved as a unit. We call the functions in
the various gimp_image_remove_foo() functions, since removing an
item may affect the size of its ancestors, and is therefore akin to
moving. We also call the functions in GimpEditSelectionTool, so
that the move tool moves items atomically while dragging.
2018-02-05 23:59:28 +08:00
|
|
|
push_undo = gimp_item_is_attached (item);
|
|
|
|
|
|
|
|
if (push_undo)
|
|
|
|
gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_TRANSFORM,
|
|
|
|
item_class->rotate_desc);
|
|
|
|
|
Bug 795410 - Deleting a layer group and then undoing the deletion ...
... raises a CRITICAL
gimp_item_{start,end}_move() currently serves two different
purposes: It is used by GimpLayer to suspend/resume mask resizing
of the layer's ancestors; this is necessary whenever an operation
on a layer might affect the size of its ancestors. It is also used
by GimpGroupLayer to suspend/resume its own mask resizing; this, on
the other hand, is only necessary before applying one of the
transformation functions to the group, so that mask modification is
handled by GimpLayer. In other words, the effects of
gimp_item_{start,end}_move() on group layers are only necessary in
a subset of the cases in which these functions are used.
While in itself this isn't a problem, it does cause issues when
removing a group layer: gimp_image_remove_layer() calls
gimp_item_start_move() before removing the layer, and
gimp_item_end_move() afterwards. While the former function is
called while the layer is still attached to the image, the latter
function is called after the layer is no longer attached. Since
GimpGroupLayer pushes an undo step in response to these calls, only
the call to start_move() results in an undo step, while the call to
end_move() doesn't, resulting in an unbalanced
GIMP_UNDO_GROUP_LAYER_START_MOVE undo step on the stack. This
causes problems when undoing the operation.
Add gimp_item_{start,end}_transform() functions, and corresponding
GimpItem::{start,end}_transform() virtual functions, which are more
specialized versions of gimp_item_{start,end}_move(), which should
be used instead of the former before/after transforming an item; in
other cases, such as when removing ot reordering an item,
gimp_item_{start,end}_move() should still be used. The default
implementation of GimpItem::{start,end}_transform() calls
gimp_item_{start,end}_move(), respectively, so subclasses that
override these functions don't have to do that themselves.
In GimpGroupLayer, override GimpItem::{start,end}_transform(),
instead of GimpItem::{start,end}_move(), for the same purpose of
suspending mask resize. This avoids these functions from being
called when removing a layer group, fixing the bug.
2018-04-22 15:39:40 +08:00
|
|
|
gimp_item_start_transform (item, push_undo);
|
2003-05-20 18:36:29 +08:00
|
|
|
|
2008-11-12 05:14:52 +08:00
|
|
|
g_object_freeze_notify (G_OBJECT (item));
|
|
|
|
|
2004-04-15 07:37:34 +08:00
|
|
|
item_class->rotate (item, context, rotate_type, center_x, center_y,
|
|
|
|
clip_result);
|
2004-04-13 19:43:27 +08:00
|
|
|
|
2008-11-12 05:14:52 +08:00
|
|
|
g_object_thaw_notify (G_OBJECT (item));
|
|
|
|
|
Bug 795410 - Deleting a layer group and then undoing the deletion ...
... raises a CRITICAL
gimp_item_{start,end}_move() currently serves two different
purposes: It is used by GimpLayer to suspend/resume mask resizing
of the layer's ancestors; this is necessary whenever an operation
on a layer might affect the size of its ancestors. It is also used
by GimpGroupLayer to suspend/resume its own mask resizing; this, on
the other hand, is only necessary before applying one of the
transformation functions to the group, so that mask modification is
handled by GimpLayer. In other words, the effects of
gimp_item_{start,end}_move() on group layers are only necessary in
a subset of the cases in which these functions are used.
While in itself this isn't a problem, it does cause issues when
removing a group layer: gimp_image_remove_layer() calls
gimp_item_start_move() before removing the layer, and
gimp_item_end_move() afterwards. While the former function is
called while the layer is still attached to the image, the latter
function is called after the layer is no longer attached. Since
GimpGroupLayer pushes an undo step in response to these calls, only
the call to start_move() results in an undo step, while the call to
end_move() doesn't, resulting in an unbalanced
GIMP_UNDO_GROUP_LAYER_START_MOVE undo step on the stack. This
causes problems when undoing the operation.
Add gimp_item_{start,end}_transform() functions, and corresponding
GimpItem::{start,end}_transform() virtual functions, which are more
specialized versions of gimp_item_{start,end}_move(), which should
be used instead of the former before/after transforming an item; in
other cases, such as when removing ot reordering an item,
gimp_item_{start,end}_move() should still be used. The default
implementation of GimpItem::{start,end}_transform() calls
gimp_item_{start,end}_move(), respectively, so subclasses that
override these functions don't have to do that themselves.
In GimpGroupLayer, override GimpItem::{start,end}_transform(),
instead of GimpItem::{start,end}_move(), for the same purpose of
suspending mask resize. This avoids these functions from being
called when removing a layer group, fixing the bug.
2018-04-22 15:39:40 +08:00
|
|
|
gimp_item_end_transform (item, push_undo);
|
app: add gimp_item_{start,end}_move()
Add gimp_item_{start,end}_move(), and corresponding
GimpItem::{start,end}_move() virtual functions, which should be
called before/after "moving" the item (i.e., translating, scaling,
resizing, flipping, rotating, or transforming the item). Moves
performed between the outermost pair of start/end calls are treated
atomically.
What exactly does "treated atomically" entail depends on the
subclasses -- GimpItem doesn't provide a default implementation for
these functions, so the current commit doesn't change any behavior.
The next commit, which adds layer-mask support for group layers,
uses the functions to avoid cropping the mask too early while a
child is moving.
GimpItem calls {start,end}_move() in the various "move" functions
(gimp_item_{translate,scale,...}(), before performing the actual
operation. Additionally we call the functions in the
gimp_image_item_list_foo() functions, for each participating item,
so that the items are moved as a unit. We call the functions in
the various gimp_image_remove_foo() functions, since removing an
item may affect the size of its ancestors, and is therefore akin to
moving. We also call the functions in GimpEditSelectionTool, so
that the move tool moves items atomically while dragging.
2018-02-05 23:59:28 +08:00
|
|
|
|
|
|
|
if (push_undo)
|
|
|
|
gimp_image_undo_group_end (image);
|
2003-05-20 18:36:29 +08:00
|
|
|
}
|
|
|
|
|
2003-05-12 23:56:36 +08:00
|
|
|
void
|
|
|
|
gimp_item_transform (GimpItem *item,
|
2004-04-15 07:37:34 +08:00
|
|
|
GimpContext *context,
|
2003-07-07 21:50:48 +08:00
|
|
|
const GimpMatrix3 *matrix,
|
2003-05-12 23:56:36 +08:00
|
|
|
GimpTransformDirection direction,
|
2003-08-09 03:30:23 +08:00
|
|
|
GimpInterpolationType interpolation,
|
2006-12-25 00:48:08 +08:00
|
|
|
GimpTransformResize clip_result,
|
2004-08-11 02:47:21 +08:00
|
|
|
GimpProgress *progress)
|
2003-05-12 23:56:36 +08:00
|
|
|
{
|
|
|
|
GimpItemClass *item_class;
|
2006-03-29 01:08:36 +08:00
|
|
|
GimpImage *image;
|
app: add gimp_item_{start,end}_move()
Add gimp_item_{start,end}_move(), and corresponding
GimpItem::{start,end}_move() virtual functions, which should be
called before/after "moving" the item (i.e., translating, scaling,
resizing, flipping, rotating, or transforming the item). Moves
performed between the outermost pair of start/end calls are treated
atomically.
What exactly does "treated atomically" entail depends on the
subclasses -- GimpItem doesn't provide a default implementation for
these functions, so the current commit doesn't change any behavior.
The next commit, which adds layer-mask support for group layers,
uses the functions to avoid cropping the mask too early while a
child is moving.
GimpItem calls {start,end}_move() in the various "move" functions
(gimp_item_{translate,scale,...}(), before performing the actual
operation. Additionally we call the functions in the
gimp_image_item_list_foo() functions, for each participating item,
so that the items are moved as a unit. We call the functions in
the various gimp_image_remove_foo() functions, since removing an
item may affect the size of its ancestors, and is therefore akin to
moving. We also call the functions in GimpEditSelectionTool, so
that the move tool moves items atomically while dragging.
2018-02-05 23:59:28 +08:00
|
|
|
gboolean push_undo;
|
2003-05-12 23:56:36 +08:00
|
|
|
|
|
|
|
g_return_if_fail (GIMP_IS_ITEM (item));
|
2004-11-16 21:41:55 +08:00
|
|
|
g_return_if_fail (gimp_item_is_attached (item));
|
2004-04-15 07:37:34 +08:00
|
|
|
g_return_if_fail (GIMP_IS_CONTEXT (context));
|
2004-08-11 02:47:21 +08:00
|
|
|
g_return_if_fail (matrix != NULL);
|
|
|
|
g_return_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress));
|
2003-05-12 23:56:36 +08:00
|
|
|
|
|
|
|
item_class = GIMP_ITEM_GET_CLASS (item);
|
2006-11-05 02:18:32 +08:00
|
|
|
image = gimp_item_get_image (item);
|
2004-04-13 19:43:27 +08:00
|
|
|
|
app: add gimp_item_{start,end}_move()
Add gimp_item_{start,end}_move(), and corresponding
GimpItem::{start,end}_move() virtual functions, which should be
called before/after "moving" the item (i.e., translating, scaling,
resizing, flipping, rotating, or transforming the item). Moves
performed between the outermost pair of start/end calls are treated
atomically.
What exactly does "treated atomically" entail depends on the
subclasses -- GimpItem doesn't provide a default implementation for
these functions, so the current commit doesn't change any behavior.
The next commit, which adds layer-mask support for group layers,
uses the functions to avoid cropping the mask too early while a
child is moving.
GimpItem calls {start,end}_move() in the various "move" functions
(gimp_item_{translate,scale,...}(), before performing the actual
operation. Additionally we call the functions in the
gimp_image_item_list_foo() functions, for each participating item,
so that the items are moved as a unit. We call the functions in
the various gimp_image_remove_foo() functions, since removing an
item may affect the size of its ancestors, and is therefore akin to
moving. We also call the functions in GimpEditSelectionTool, so
that the move tool moves items atomically while dragging.
2018-02-05 23:59:28 +08:00
|
|
|
push_undo = gimp_item_is_attached (item);
|
|
|
|
|
|
|
|
if (push_undo)
|
|
|
|
gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_TRANSFORM,
|
|
|
|
item_class->transform_desc);
|
|
|
|
|
Bug 795410 - Deleting a layer group and then undoing the deletion ...
... raises a CRITICAL
gimp_item_{start,end}_move() currently serves two different
purposes: It is used by GimpLayer to suspend/resume mask resizing
of the layer's ancestors; this is necessary whenever an operation
on a layer might affect the size of its ancestors. It is also used
by GimpGroupLayer to suspend/resume its own mask resizing; this, on
the other hand, is only necessary before applying one of the
transformation functions to the group, so that mask modification is
handled by GimpLayer. In other words, the effects of
gimp_item_{start,end}_move() on group layers are only necessary in
a subset of the cases in which these functions are used.
While in itself this isn't a problem, it does cause issues when
removing a group layer: gimp_image_remove_layer() calls
gimp_item_start_move() before removing the layer, and
gimp_item_end_move() afterwards. While the former function is
called while the layer is still attached to the image, the latter
function is called after the layer is no longer attached. Since
GimpGroupLayer pushes an undo step in response to these calls, only
the call to start_move() results in an undo step, while the call to
end_move() doesn't, resulting in an unbalanced
GIMP_UNDO_GROUP_LAYER_START_MOVE undo step on the stack. This
causes problems when undoing the operation.
Add gimp_item_{start,end}_transform() functions, and corresponding
GimpItem::{start,end}_transform() virtual functions, which are more
specialized versions of gimp_item_{start,end}_move(), which should
be used instead of the former before/after transforming an item; in
other cases, such as when removing ot reordering an item,
gimp_item_{start,end}_move() should still be used. The default
implementation of GimpItem::{start,end}_transform() calls
gimp_item_{start,end}_move(), respectively, so subclasses that
override these functions don't have to do that themselves.
In GimpGroupLayer, override GimpItem::{start,end}_transform(),
instead of GimpItem::{start,end}_move(), for the same purpose of
suspending mask resize. This avoids these functions from being
called when removing a layer group, fixing the bug.
2018-04-22 15:39:40 +08:00
|
|
|
gimp_item_start_transform (item, push_undo);
|
2003-05-12 23:56:36 +08:00
|
|
|
|
2008-11-12 05:14:52 +08:00
|
|
|
g_object_freeze_notify (G_OBJECT (item));
|
|
|
|
|
2004-04-15 07:37:34 +08:00
|
|
|
item_class->transform (item, context, matrix, direction, interpolation,
|
2013-05-31 07:15:32 +08:00
|
|
|
clip_result, progress);
|
2004-04-13 19:43:27 +08:00
|
|
|
|
2008-11-12 05:14:52 +08:00
|
|
|
g_object_thaw_notify (G_OBJECT (item));
|
|
|
|
|
Bug 795410 - Deleting a layer group and then undoing the deletion ...
... raises a CRITICAL
gimp_item_{start,end}_move() currently serves two different
purposes: It is used by GimpLayer to suspend/resume mask resizing
of the layer's ancestors; this is necessary whenever an operation
on a layer might affect the size of its ancestors. It is also used
by GimpGroupLayer to suspend/resume its own mask resizing; this, on
the other hand, is only necessary before applying one of the
transformation functions to the group, so that mask modification is
handled by GimpLayer. In other words, the effects of
gimp_item_{start,end}_move() on group layers are only necessary in
a subset of the cases in which these functions are used.
While in itself this isn't a problem, it does cause issues when
removing a group layer: gimp_image_remove_layer() calls
gimp_item_start_move() before removing the layer, and
gimp_item_end_move() afterwards. While the former function is
called while the layer is still attached to the image, the latter
function is called after the layer is no longer attached. Since
GimpGroupLayer pushes an undo step in response to these calls, only
the call to start_move() results in an undo step, while the call to
end_move() doesn't, resulting in an unbalanced
GIMP_UNDO_GROUP_LAYER_START_MOVE undo step on the stack. This
causes problems when undoing the operation.
Add gimp_item_{start,end}_transform() functions, and corresponding
GimpItem::{start,end}_transform() virtual functions, which are more
specialized versions of gimp_item_{start,end}_move(), which should
be used instead of the former before/after transforming an item; in
other cases, such as when removing ot reordering an item,
gimp_item_{start,end}_move() should still be used. The default
implementation of GimpItem::{start,end}_transform() calls
gimp_item_{start,end}_move(), respectively, so subclasses that
override these functions don't have to do that themselves.
In GimpGroupLayer, override GimpItem::{start,end}_transform(),
instead of GimpItem::{start,end}_move(), for the same purpose of
suspending mask resize. This avoids these functions from being
called when removing a layer group, fixing the bug.
2018-04-22 15:39:40 +08:00
|
|
|
gimp_item_end_transform (item, push_undo);
|
app: add gimp_item_{start,end}_move()
Add gimp_item_{start,end}_move(), and corresponding
GimpItem::{start,end}_move() virtual functions, which should be
called before/after "moving" the item (i.e., translating, scaling,
resizing, flipping, rotating, or transforming the item). Moves
performed between the outermost pair of start/end calls are treated
atomically.
What exactly does "treated atomically" entail depends on the
subclasses -- GimpItem doesn't provide a default implementation for
these functions, so the current commit doesn't change any behavior.
The next commit, which adds layer-mask support for group layers,
uses the functions to avoid cropping the mask too early while a
child is moving.
GimpItem calls {start,end}_move() in the various "move" functions
(gimp_item_{translate,scale,...}(), before performing the actual
operation. Additionally we call the functions in the
gimp_image_item_list_foo() functions, for each participating item,
so that the items are moved as a unit. We call the functions in
the various gimp_image_remove_foo() functions, since removing an
item may affect the size of its ancestors, and is therefore akin to
moving. We also call the functions in GimpEditSelectionTool, so
that the move tool moves items atomically while dragging.
2018-02-05 23:59:28 +08:00
|
|
|
|
|
|
|
if (push_undo)
|
|
|
|
gimp_image_undo_group_end (image);
|
2003-05-12 23:56:36 +08:00
|
|
|
}
|
|
|
|
|
2016-03-15 02:02:18 +08:00
|
|
|
gboolean
|
|
|
|
gimp_item_fill (GimpItem *item,
|
|
|
|
GimpDrawable *drawable,
|
|
|
|
GimpFillOptions *fill_options,
|
|
|
|
gboolean push_undo,
|
|
|
|
GimpProgress *progress,
|
|
|
|
GError **error)
|
|
|
|
{
|
|
|
|
GimpItemClass *item_class;
|
|
|
|
gboolean retval = FALSE;
|
|
|
|
|
|
|
|
g_return_val_if_fail (GIMP_IS_ITEM (item), FALSE);
|
|
|
|
g_return_val_if_fail (gimp_item_is_attached (item), FALSE);
|
|
|
|
g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), FALSE);
|
|
|
|
g_return_val_if_fail (gimp_item_is_attached (GIMP_ITEM (drawable)), FALSE);
|
|
|
|
g_return_val_if_fail (GIMP_IS_FILL_OPTIONS (fill_options), FALSE);
|
|
|
|
g_return_val_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress), FALSE);
|
|
|
|
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
|
|
|
|
|
|
|
|
item_class = GIMP_ITEM_GET_CLASS (item);
|
|
|
|
|
|
|
|
if (item_class->fill)
|
|
|
|
{
|
|
|
|
GimpImage *image = gimp_item_get_image (item);
|
|
|
|
|
|
|
|
if (push_undo)
|
|
|
|
gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_PAINT,
|
|
|
|
item_class->fill_desc);
|
|
|
|
|
|
|
|
retval = item_class->fill (item, drawable, fill_options, push_undo,
|
|
|
|
progress, error);
|
|
|
|
|
|
|
|
if (push_undo)
|
|
|
|
gimp_image_undo_group_end (image);
|
|
|
|
}
|
|
|
|
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
2003-09-02 01:56:44 +08:00
|
|
|
gboolean
|
2008-10-24 15:37:46 +08:00
|
|
|
gimp_item_stroke (GimpItem *item,
|
|
|
|
GimpDrawable *drawable,
|
|
|
|
GimpContext *context,
|
|
|
|
GimpStrokeOptions *stroke_options,
|
2014-02-07 06:20:39 +08:00
|
|
|
GimpPaintOptions *paint_options,
|
2008-10-25 19:59:03 +08:00
|
|
|
gboolean push_undo,
|
2008-10-24 15:37:46 +08:00
|
|
|
GimpProgress *progress,
|
|
|
|
GError **error)
|
2003-09-02 01:56:44 +08:00
|
|
|
{
|
|
|
|
GimpItemClass *item_class;
|
2004-04-15 22:41:36 +08:00
|
|
|
gboolean retval = FALSE;
|
2003-09-02 01:56:44 +08:00
|
|
|
|
|
|
|
g_return_val_if_fail (GIMP_IS_ITEM (item), FALSE);
|
2004-11-11 22:05:34 +08:00
|
|
|
g_return_val_if_fail (gimp_item_is_attached (item), FALSE);
|
2003-09-02 01:56:44 +08:00
|
|
|
g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), FALSE);
|
2004-11-11 22:05:34 +08:00
|
|
|
g_return_val_if_fail (gimp_item_is_attached (GIMP_ITEM (drawable)), FALSE);
|
2004-04-15 21:10:51 +08:00
|
|
|
g_return_val_if_fail (GIMP_IS_CONTEXT (context), FALSE);
|
2008-10-24 15:37:46 +08:00
|
|
|
g_return_val_if_fail (GIMP_IS_STROKE_OPTIONS (stroke_options), FALSE);
|
2014-02-07 06:20:39 +08:00
|
|
|
g_return_val_if_fail (paint_options == NULL ||
|
|
|
|
GIMP_IS_PAINT_OPTIONS (paint_options), FALSE);
|
2007-05-03 23:17:07 +08:00
|
|
|
g_return_val_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress), FALSE);
|
2007-12-07 02:40:12 +08:00
|
|
|
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
|
2003-09-02 01:56:44 +08:00
|
|
|
|
|
|
|
item_class = GIMP_ITEM_GET_CLASS (item);
|
|
|
|
|
|
|
|
if (item_class->stroke)
|
2004-04-15 22:41:36 +08:00
|
|
|
{
|
2006-03-29 01:08:36 +08:00
|
|
|
GimpImage *image = gimp_item_get_image (item);
|
2003-09-02 01:56:44 +08:00
|
|
|
|
2014-02-07 06:20:39 +08:00
|
|
|
gimp_stroke_options_prepare (stroke_options, context, paint_options);
|
2004-10-22 20:32:31 +08:00
|
|
|
|
2008-10-25 19:59:03 +08:00
|
|
|
if (push_undo)
|
|
|
|
gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_PAINT,
|
|
|
|
item_class->stroke_desc);
|
2004-04-15 22:41:36 +08:00
|
|
|
|
2008-10-25 19:59:03 +08:00
|
|
|
retval = item_class->stroke (item, drawable, stroke_options, push_undo,
|
|
|
|
progress, error);
|
2004-04-15 22:41:36 +08:00
|
|
|
|
2008-10-25 19:59:03 +08:00
|
|
|
if (push_undo)
|
|
|
|
gimp_image_undo_group_end (image);
|
2004-10-22 20:32:31 +08:00
|
|
|
|
2008-10-24 15:37:46 +08:00
|
|
|
gimp_stroke_options_finish (stroke_options);
|
2004-04-15 22:41:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return retval;
|
2003-09-02 01:56:44 +08:00
|
|
|
}
|
|
|
|
|
2010-07-21 05:09:19 +08:00
|
|
|
void
|
|
|
|
gimp_item_to_selection (GimpItem *item,
|
|
|
|
GimpChannelOps op,
|
|
|
|
gboolean antialias,
|
|
|
|
gboolean feather,
|
|
|
|
gdouble feather_radius_x,
|
|
|
|
gdouble feather_radius_y)
|
|
|
|
{
|
|
|
|
GimpItemClass *item_class;
|
|
|
|
|
|
|
|
g_return_if_fail (GIMP_IS_ITEM (item));
|
|
|
|
g_return_if_fail (gimp_item_is_attached (item));
|
|
|
|
|
|
|
|
item_class = GIMP_ITEM_GET_CLASS (item);
|
|
|
|
|
|
|
|
if (item_class->to_selection)
|
|
|
|
item_class->to_selection (item, op, antialias,
|
|
|
|
feather, feather_radius_x, feather_radius_y);
|
|
|
|
}
|
|
|
|
|
2012-05-16 04:25:12 +08:00
|
|
|
void
|
|
|
|
gimp_item_add_offset_node (GimpItem *item,
|
|
|
|
GeglNode *node)
|
2008-11-03 06:29:05 +08:00
|
|
|
{
|
2011-01-31 04:49:51 +08:00
|
|
|
GimpItemPrivate *private;
|
|
|
|
|
2012-05-16 04:25:12 +08:00
|
|
|
g_return_if_fail (GIMP_IS_ITEM (item));
|
|
|
|
g_return_if_fail (GEGL_IS_NODE (node));
|
2008-11-03 06:29:05 +08:00
|
|
|
|
2011-01-31 04:49:51 +08:00
|
|
|
private = GET_PRIVATE (item);
|
|
|
|
|
2012-05-16 04:25:12 +08:00
|
|
|
g_return_if_fail (g_list_find (private->offset_nodes, node) == NULL);
|
|
|
|
|
|
|
|
gegl_node_set (node,
|
|
|
|
"x", (gdouble) private->offset_x,
|
|
|
|
"y", (gdouble) private->offset_y,
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
private->offset_nodes = g_list_append (private->offset_nodes,
|
|
|
|
g_object_ref (node));
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
gimp_item_remove_offset_node (GimpItem *item,
|
|
|
|
GeglNode *node)
|
|
|
|
{
|
|
|
|
GimpItemPrivate *private;
|
|
|
|
|
|
|
|
g_return_if_fail (GIMP_IS_ITEM (item));
|
|
|
|
g_return_if_fail (GEGL_IS_NODE (node));
|
|
|
|
|
|
|
|
private = GET_PRIVATE (item);
|
|
|
|
|
|
|
|
g_return_if_fail (g_list_find (private->offset_nodes, node) != NULL);
|
2008-11-03 06:29:05 +08:00
|
|
|
|
2013-04-11 07:26:27 +08:00
|
|
|
private->offset_nodes = g_list_remove (private->offset_nodes, node);
|
2012-05-16 04:25:12 +08:00
|
|
|
g_object_unref (node);
|
2008-11-03 06:29:05 +08:00
|
|
|
}
|
|
|
|
|
2002-02-26 01:58:50 +08:00
|
|
|
gint
|
|
|
|
gimp_item_get_ID (GimpItem *item)
|
|
|
|
{
|
|
|
|
g_return_val_if_fail (GIMP_IS_ITEM (item), -1);
|
|
|
|
|
2011-01-31 04:49:51 +08:00
|
|
|
return GET_PRIVATE (item)->ID;
|
2002-02-26 01:58:50 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
GimpItem *
|
|
|
|
gimp_item_get_by_ID (Gimp *gimp,
|
|
|
|
gint item_id)
|
|
|
|
{
|
|
|
|
g_return_val_if_fail (GIMP_IS_GIMP (gimp), NULL);
|
|
|
|
|
|
|
|
if (gimp->item_table == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
2011-05-05 04:14:13 +08:00
|
|
|
return (GimpItem *) gimp_id_table_lookup (gimp->item_table, item_id);
|
2002-02-26 01:58:50 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
GimpTattoo
|
2016-05-20 05:51:44 +08:00
|
|
|
gimp_item_get_tattoo (GimpItem *item)
|
2002-02-26 01:58:50 +08:00
|
|
|
{
|
2003-09-02 21:43:26 +08:00
|
|
|
g_return_val_if_fail (GIMP_IS_ITEM (item), 0);
|
2002-02-26 01:58:50 +08:00
|
|
|
|
2011-01-31 04:49:51 +08:00
|
|
|
return GET_PRIVATE (item)->tattoo;
|
2002-02-26 01:58:50 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
gimp_item_set_tattoo (GimpItem *item,
|
|
|
|
GimpTattoo tattoo)
|
|
|
|
{
|
|
|
|
g_return_if_fail (GIMP_IS_ITEM (item));
|
|
|
|
|
2011-01-31 04:49:51 +08:00
|
|
|
GET_PRIVATE (item)->tattoo = tattoo;
|
2002-02-26 01:58:50 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
GimpImage *
|
2016-05-20 05:51:44 +08:00
|
|
|
gimp_item_get_image (GimpItem *item)
|
2002-02-26 01:58:50 +08:00
|
|
|
{
|
|
|
|
g_return_val_if_fail (GIMP_IS_ITEM (item), NULL);
|
|
|
|
|
2011-01-31 04:49:51 +08:00
|
|
|
return GET_PRIVATE (item)->image;
|
2002-02-26 01:58:50 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
gimp_item_set_image (GimpItem *item,
|
2006-03-29 01:08:36 +08:00
|
|
|
GimpImage *image)
|
2002-02-26 01:58:50 +08:00
|
|
|
{
|
2011-01-31 04:49:51 +08:00
|
|
|
GimpItemPrivate *private;
|
|
|
|
|
2002-02-26 01:58:50 +08:00
|
|
|
g_return_if_fail (GIMP_IS_ITEM (item));
|
2004-11-19 20:38:34 +08:00
|
|
|
g_return_if_fail (! gimp_item_is_attached (item));
|
2011-01-31 02:26:32 +08:00
|
|
|
g_return_if_fail (! gimp_item_is_removed (item));
|
|
|
|
g_return_if_fail (GIMP_IS_IMAGE (image));
|
2002-02-26 01:58:50 +08:00
|
|
|
|
2011-01-31 04:49:51 +08:00
|
|
|
private = GET_PRIVATE (item);
|
|
|
|
|
2011-02-01 17:28:10 +08:00
|
|
|
if (image == private->image)
|
|
|
|
return;
|
|
|
|
|
|
|
|
g_object_freeze_notify (G_OBJECT (item));
|
|
|
|
|
|
|
|
if (private->ID == 0)
|
|
|
|
{
|
2011-05-05 04:14:13 +08:00
|
|
|
private->ID = gimp_id_table_insert (image->gimp->item_table, item);
|
2011-02-01 17:28:10 +08:00
|
|
|
|
|
|
|
g_object_notify (G_OBJECT (item), "id");
|
|
|
|
}
|
|
|
|
|
2011-01-31 04:49:51 +08:00
|
|
|
if (private->tattoo == 0 || private->image != image)
|
2002-02-26 08:04:55 +08:00
|
|
|
{
|
2011-01-31 04:49:51 +08:00
|
|
|
private->tattoo = gimp_image_get_new_tattoo (image);
|
2002-02-26 08:04:55 +08:00
|
|
|
}
|
2002-02-26 01:58:50 +08:00
|
|
|
|
2011-01-31 04:49:51 +08:00
|
|
|
private->image = image;
|
2011-02-01 17:28:10 +08:00
|
|
|
g_object_notify (G_OBJECT (item), "image");
|
|
|
|
|
|
|
|
g_object_thaw_notify (G_OBJECT (item));
|
2002-02-26 01:58:50 +08:00
|
|
|
}
|
|
|
|
|
2011-01-31 02:26:32 +08:00
|
|
|
/**
|
|
|
|
* gimp_item_replace_item:
|
|
|
|
* @item: a newly allocated #GimpItem
|
|
|
|
* @replace: the #GimpItem to be replaced by @item
|
|
|
|
*
|
|
|
|
* This function shouly only be called right after @item has been
|
|
|
|
* newly allocated.
|
|
|
|
*
|
|
|
|
* Replaces @replace by @item, as far as possible within the #GimpItem
|
|
|
|
* class. The new @item takes over @replace's ID, tattoo, offset, size
|
|
|
|
* etc. and all these properties are set to %NULL on @replace.
|
|
|
|
*
|
|
|
|
* This function *only* exists to allow subclasses to do evil hacks
|
|
|
|
* like in XCF text layer loading. Don't ever use this function if you
|
|
|
|
* are not sure.
|
|
|
|
*
|
|
|
|
* After this function returns, @replace has become completely
|
|
|
|
* unusable, should only be used to steal everything it has (like its
|
|
|
|
* drawable properties if it's a drawable), and then be destroyed.
|
|
|
|
**/
|
|
|
|
void
|
|
|
|
gimp_item_replace_item (GimpItem *item,
|
|
|
|
GimpItem *replace)
|
|
|
|
{
|
2011-01-31 04:49:51 +08:00
|
|
|
GimpItemPrivate *private;
|
|
|
|
gint offset_x;
|
|
|
|
gint offset_y;
|
2011-01-31 02:26:32 +08:00
|
|
|
|
|
|
|
g_return_if_fail (GIMP_IS_ITEM (item));
|
|
|
|
g_return_if_fail (! gimp_item_is_attached (item));
|
|
|
|
g_return_if_fail (! gimp_item_is_removed (item));
|
|
|
|
g_return_if_fail (GIMP_IS_ITEM (replace));
|
|
|
|
|
2011-01-31 04:49:51 +08:00
|
|
|
private = GET_PRIVATE (item);
|
|
|
|
|
2011-01-31 02:26:32 +08:00
|
|
|
gimp_object_set_name (GIMP_OBJECT (item), gimp_object_get_name (replace));
|
|
|
|
|
2011-02-01 06:53:59 +08:00
|
|
|
if (private->ID)
|
2011-05-05 04:14:13 +08:00
|
|
|
gimp_id_table_remove (gimp_item_get_image (item)->gimp->item_table,
|
|
|
|
gimp_item_get_ID (item));
|
2011-02-01 06:53:59 +08:00
|
|
|
|
2011-01-31 04:49:51 +08:00
|
|
|
private->ID = gimp_item_get_ID (replace);
|
2011-05-05 04:14:13 +08:00
|
|
|
gimp_id_table_replace (gimp_item_get_image (item)->gimp->item_table,
|
|
|
|
gimp_item_get_ID (item),
|
|
|
|
item);
|
2011-01-31 02:26:32 +08:00
|
|
|
|
2018-04-26 02:31:11 +08:00
|
|
|
/* Set image before tattoo so that the explicitly set tattoo overrides
|
2011-01-31 02:26:32 +08:00
|
|
|
* the one implicitly set when setting the image
|
|
|
|
*/
|
|
|
|
gimp_item_set_image (item, gimp_item_get_image (replace));
|
2011-01-31 04:49:51 +08:00
|
|
|
GET_PRIVATE (replace)->image = NULL;
|
2011-01-31 02:26:32 +08:00
|
|
|
|
|
|
|
gimp_item_set_tattoo (item, gimp_item_get_tattoo (replace));
|
|
|
|
gimp_item_set_tattoo (replace, 0);
|
|
|
|
|
2011-02-01 06:52:41 +08:00
|
|
|
g_object_unref (private->parasites);
|
2011-02-01 06:51:18 +08:00
|
|
|
private->parasites = GET_PRIVATE (replace)->parasites;
|
|
|
|
GET_PRIVATE (replace)->parasites = NULL;
|
2011-01-31 02:26:32 +08:00
|
|
|
|
|
|
|
gimp_item_get_offset (replace, &offset_x, &offset_y);
|
|
|
|
gimp_item_set_offset (item, offset_x, offset_y);
|
|
|
|
|
|
|
|
gimp_item_set_size (item,
|
|
|
|
gimp_item_get_width (replace),
|
|
|
|
gimp_item_get_height (replace));
|
|
|
|
|
2012-11-09 18:17:25 +08:00
|
|
|
gimp_item_set_visible (item, gimp_item_get_visible (replace), FALSE);
|
|
|
|
gimp_item_set_linked (item, gimp_item_get_linked (replace), FALSE);
|
2016-10-29 22:50:13 +08:00
|
|
|
gimp_item_set_color_tag (item, gimp_item_get_color_tag (replace), FALSE);
|
2012-11-09 18:17:25 +08:00
|
|
|
gimp_item_set_lock_content (item, gimp_item_get_lock_content (replace), FALSE);
|
|
|
|
gimp_item_set_lock_position (item, gimp_item_get_lock_position (replace), FALSE);
|
2011-01-31 02:26:32 +08:00
|
|
|
}
|
|
|
|
|
2011-02-01 06:51:18 +08:00
|
|
|
/**
|
|
|
|
* gimp_item_set_parasites:
|
|
|
|
* @item: a #GimpItem
|
|
|
|
* @parasites: a #GimpParasiteList
|
|
|
|
*
|
|
|
|
* Set an @item's #GimpParasiteList. It's usually never needed to
|
|
|
|
* fiddle with an item's parasite list directly. This function exists
|
|
|
|
* for special purposes only, like when creating items from unusual
|
|
|
|
* sources.
|
|
|
|
**/
|
|
|
|
void
|
|
|
|
gimp_item_set_parasites (GimpItem *item,
|
|
|
|
GimpParasiteList *parasites)
|
|
|
|
{
|
|
|
|
GimpItemPrivate *private;
|
|
|
|
|
|
|
|
g_return_if_fail (GIMP_IS_ITEM (item));
|
|
|
|
g_return_if_fail (GIMP_IS_PARASITE_LIST (parasites));
|
|
|
|
|
|
|
|
private = GET_PRIVATE (item);
|
|
|
|
|
2018-06-01 18:59:52 +08:00
|
|
|
g_set_object (&private->parasites, parasites);
|
2011-02-01 06:51:18 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* gimp_item_get_parasites:
|
|
|
|
* @item: a #GimpItem
|
|
|
|
*
|
|
|
|
* Get an @item's #GimpParasiteList. It's usually never needed to
|
|
|
|
* fiddle with an item's parasite list directly. This function exists
|
|
|
|
* for special purposes only, like when saving an item to XCF.
|
|
|
|
*
|
|
|
|
* Return value: The @item's #GimpParasiteList.
|
|
|
|
**/
|
|
|
|
GimpParasiteList *
|
2016-05-20 05:51:44 +08:00
|
|
|
gimp_item_get_parasites (GimpItem *item)
|
2011-02-01 06:51:18 +08:00
|
|
|
{
|
|
|
|
g_return_val_if_fail (GIMP_IS_ITEM (item), NULL);
|
|
|
|
|
|
|
|
return GET_PRIVATE (item)->parasites;
|
|
|
|
}
|
|
|
|
|
2014-03-22 07:11:15 +08:00
|
|
|
gboolean
|
|
|
|
gimp_item_parasite_validate (GimpItem *item,
|
|
|
|
const GimpParasite *parasite,
|
|
|
|
GError **error)
|
|
|
|
{
|
|
|
|
g_return_val_if_fail (GIMP_IS_ITEM (item), FALSE);
|
|
|
|
g_return_val_if_fail (parasite != NULL, FALSE);
|
|
|
|
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2002-02-26 01:58:50 +08:00
|
|
|
void
|
2006-04-02 23:37:25 +08:00
|
|
|
gimp_item_parasite_attach (GimpItem *item,
|
2011-01-31 03:40:43 +08:00
|
|
|
const GimpParasite *parasite,
|
|
|
|
gboolean push_undo)
|
2002-02-26 01:58:50 +08:00
|
|
|
{
|
2011-01-31 04:49:51 +08:00
|
|
|
GimpItemPrivate *private;
|
|
|
|
GimpParasite copy;
|
2006-04-02 23:37:25 +08:00
|
|
|
|
2002-02-26 01:58:50 +08:00
|
|
|
g_return_if_fail (GIMP_IS_ITEM (item));
|
2006-04-02 23:37:25 +08:00
|
|
|
g_return_if_fail (parasite != NULL);
|
|
|
|
|
2011-01-31 04:49:51 +08:00
|
|
|
private = GET_PRIVATE (item);
|
|
|
|
|
2007-05-29 17:57:13 +08:00
|
|
|
/* make a temporary copy of the GimpParasite struct because
|
2006-04-02 23:37:25 +08:00
|
|
|
* gimp_parasite_shift_parent() changes it
|
|
|
|
*/
|
2007-05-29 17:57:13 +08:00
|
|
|
copy = *parasite;
|
2002-02-26 01:58:50 +08:00
|
|
|
|
2011-01-31 03:40:43 +08:00
|
|
|
if (! gimp_item_is_attached (item))
|
|
|
|
push_undo = FALSE;
|
|
|
|
|
|
|
|
if (push_undo)
|
2002-02-26 01:58:50 +08:00
|
|
|
{
|
2005-08-06 01:36:24 +08:00
|
|
|
/* only set the dirty bit manually if we can be saved and the new
|
|
|
|
* parasite differs from the current one and we aren't undoable
|
|
|
|
*/
|
2007-05-29 17:23:34 +08:00
|
|
|
if (gimp_parasite_is_undoable (©))
|
2005-08-05 22:13:10 +08:00
|
|
|
{
|
2005-08-06 01:36:24 +08:00
|
|
|
/* do a group in case we have attach_parent set */
|
2011-01-31 04:49:51 +08:00
|
|
|
gimp_image_undo_group_start (private->image,
|
2005-08-05 22:13:10 +08:00
|
|
|
GIMP_UNDO_GROUP_PARASITE_ATTACH,
|
2010-06-08 19:24:11 +08:00
|
|
|
C_("undo-type", "Attach Parasite"));
|
2005-08-05 22:13:10 +08:00
|
|
|
|
2011-01-31 04:49:51 +08:00
|
|
|
gimp_image_undo_push_item_parasite (private->image, NULL, item, ©);
|
2005-08-06 01:36:24 +08:00
|
|
|
}
|
2007-05-29 17:23:34 +08:00
|
|
|
else if (gimp_parasite_is_persistent (©) &&
|
|
|
|
! gimp_parasite_compare (©,
|
2005-08-06 01:36:24 +08:00
|
|
|
gimp_item_parasite_find
|
2007-05-29 17:23:34 +08:00
|
|
|
(item, gimp_parasite_name (©))))
|
2005-08-06 01:36:24 +08:00
|
|
|
{
|
2011-01-31 04:49:51 +08:00
|
|
|
gimp_image_undo_push_cantundo (private->image,
|
2010-06-08 19:24:11 +08:00
|
|
|
C_("undo-type", "Attach Parasite to Item"));
|
2005-08-05 22:13:10 +08:00
|
|
|
}
|
2002-02-26 01:58:50 +08:00
|
|
|
}
|
|
|
|
|
2011-02-01 06:51:18 +08:00
|
|
|
gimp_parasite_list_add (private->parasites, ©);
|
2002-02-26 01:58:50 +08:00
|
|
|
|
2007-05-29 17:23:34 +08:00
|
|
|
if (gimp_parasite_has_flag (©, GIMP_PARASITE_ATTACH_PARENT))
|
2002-02-26 01:58:50 +08:00
|
|
|
{
|
2007-05-29 17:23:34 +08:00
|
|
|
gimp_parasite_shift_parent (©);
|
2011-01-31 04:49:51 +08:00
|
|
|
gimp_image_parasite_attach (private->image, ©);
|
2002-02-26 01:58:50 +08:00
|
|
|
}
|
2007-05-29 17:23:34 +08:00
|
|
|
else if (gimp_parasite_has_flag (©, GIMP_PARASITE_ATTACH_GRANDPARENT))
|
2002-02-26 01:58:50 +08:00
|
|
|
{
|
2007-05-29 17:23:34 +08:00
|
|
|
gimp_parasite_shift_parent (©);
|
|
|
|
gimp_parasite_shift_parent (©);
|
2011-01-31 04:49:51 +08:00
|
|
|
gimp_parasite_attach (private->image->gimp, ©);
|
2002-02-26 01:58:50 +08:00
|
|
|
}
|
|
|
|
|
2005-08-06 01:36:24 +08:00
|
|
|
if (gimp_item_is_attached (item) &&
|
2007-05-29 17:23:34 +08:00
|
|
|
gimp_parasite_is_undoable (©))
|
2002-02-26 01:58:50 +08:00
|
|
|
{
|
2011-01-31 04:49:51 +08:00
|
|
|
gimp_image_undo_group_end (private->image);
|
2002-02-26 01:58:50 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
gimp_item_parasite_detach (GimpItem *item,
|
2011-01-31 03:40:43 +08:00
|
|
|
const gchar *name,
|
|
|
|
gboolean push_undo)
|
2002-02-26 01:58:50 +08:00
|
|
|
{
|
2011-01-31 04:49:51 +08:00
|
|
|
GimpItemPrivate *private;
|
2006-04-02 23:37:25 +08:00
|
|
|
const GimpParasite *parasite;
|
2002-02-26 01:58:50 +08:00
|
|
|
|
|
|
|
g_return_if_fail (GIMP_IS_ITEM (item));
|
2007-02-01 06:58:06 +08:00
|
|
|
g_return_if_fail (name != NULL);
|
2002-02-26 01:58:50 +08:00
|
|
|
|
2011-01-31 04:49:51 +08:00
|
|
|
private = GET_PRIVATE (item);
|
|
|
|
|
2011-02-01 06:51:18 +08:00
|
|
|
parasite = gimp_parasite_list_find (private->parasites, name);
|
2002-02-26 08:04:55 +08:00
|
|
|
|
|
|
|
if (! parasite)
|
2002-02-26 01:58:50 +08:00
|
|
|
return;
|
|
|
|
|
2011-01-31 03:40:43 +08:00
|
|
|
if (! gimp_item_is_attached (item))
|
|
|
|
push_undo = FALSE;
|
|
|
|
|
|
|
|
if (push_undo)
|
2002-02-26 08:04:55 +08:00
|
|
|
{
|
2011-01-31 03:40:43 +08:00
|
|
|
if (gimp_parasite_is_undoable (parasite))
|
|
|
|
{
|
2011-01-31 04:49:51 +08:00
|
|
|
gimp_image_undo_push_item_parasite_remove (private->image,
|
2011-01-31 03:40:43 +08:00
|
|
|
C_("undo-type", "Remove Parasite from Item"),
|
|
|
|
item,
|
|
|
|
gimp_parasite_name (parasite));
|
|
|
|
}
|
|
|
|
else if (gimp_parasite_is_persistent (parasite))
|
|
|
|
{
|
2011-01-31 04:49:51 +08:00
|
|
|
gimp_image_undo_push_cantundo (private->image,
|
2011-01-31 03:40:43 +08:00
|
|
|
C_("undo-type", "Remove Parasite from Item"));
|
|
|
|
}
|
2002-02-26 08:04:55 +08:00
|
|
|
}
|
2002-02-26 01:58:50 +08:00
|
|
|
|
2011-02-01 06:51:18 +08:00
|
|
|
gimp_parasite_list_remove (private->parasites, name);
|
2002-02-26 01:58:50 +08:00
|
|
|
}
|
|
|
|
|
2006-04-02 23:37:25 +08:00
|
|
|
const GimpParasite *
|
2016-05-20 05:51:44 +08:00
|
|
|
gimp_item_parasite_find (GimpItem *item,
|
|
|
|
const gchar *name)
|
2002-02-26 01:58:50 +08:00
|
|
|
{
|
|
|
|
g_return_val_if_fail (GIMP_IS_ITEM (item), NULL);
|
|
|
|
|
2011-02-01 06:51:18 +08:00
|
|
|
return gimp_parasite_list_find (GET_PRIVATE (item)->parasites, name);
|
2002-02-26 01:58:50 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2002-02-26 08:04:55 +08:00
|
|
|
gimp_item_parasite_list_foreach_func (gchar *name,
|
|
|
|
GimpParasite *parasite,
|
2002-02-26 01:58:50 +08:00
|
|
|
gchar ***cur)
|
|
|
|
{
|
2002-02-26 08:04:55 +08:00
|
|
|
*(*cur)++ = (gchar *) g_strdup (name);
|
2002-02-26 01:58:50 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
gchar **
|
2016-05-20 05:51:44 +08:00
|
|
|
gimp_item_parasite_list (GimpItem *item,
|
|
|
|
gint *count)
|
2002-02-26 01:58:50 +08:00
|
|
|
{
|
2011-02-01 06:51:18 +08:00
|
|
|
GimpItemPrivate *private;
|
|
|
|
gchar **list;
|
|
|
|
gchar **cur;
|
2002-02-26 01:58:50 +08:00
|
|
|
|
|
|
|
g_return_val_if_fail (GIMP_IS_ITEM (item), NULL);
|
|
|
|
g_return_val_if_fail (count != NULL, NULL);
|
|
|
|
|
2011-02-01 06:51:18 +08:00
|
|
|
private = GET_PRIVATE (item);
|
|
|
|
|
|
|
|
*count = gimp_parasite_list_length (private->parasites);
|
2002-02-26 08:04:55 +08:00
|
|
|
|
2002-02-26 01:58:50 +08:00
|
|
|
cur = list = g_new (gchar *, *count);
|
|
|
|
|
2011-02-01 06:51:18 +08:00
|
|
|
gimp_parasite_list_foreach (private->parasites,
|
2004-07-14 19:52:03 +08:00
|
|
|
(GHFunc) gimp_item_parasite_list_foreach_func,
|
|
|
|
&cur);
|
2002-02-26 01:58:50 +08:00
|
|
|
|
|
|
|
return list;
|
|
|
|
}
|
2003-05-09 04:26:01 +08:00
|
|
|
|
2003-09-12 03:52:29 +08:00
|
|
|
void
|
|
|
|
gimp_item_set_visible (GimpItem *item,
|
|
|
|
gboolean visible,
|
|
|
|
gboolean push_undo)
|
|
|
|
{
|
|
|
|
g_return_if_fail (GIMP_IS_ITEM (item));
|
|
|
|
|
2009-08-19 19:37:41 +08:00
|
|
|
visible = visible ? TRUE : FALSE;
|
|
|
|
|
2007-12-24 00:58:41 +08:00
|
|
|
if (gimp_item_get_visible (item) != visible)
|
2003-09-12 03:52:29 +08:00
|
|
|
{
|
2004-11-16 21:41:55 +08:00
|
|
|
if (push_undo && gimp_item_is_attached (item))
|
2003-09-12 03:52:29 +08:00
|
|
|
{
|
2006-03-29 01:08:36 +08:00
|
|
|
GimpImage *image = gimp_item_get_image (item);
|
2003-09-12 03:52:29 +08:00
|
|
|
|
2006-03-29 01:08:36 +08:00
|
|
|
if (image)
|
|
|
|
gimp_image_undo_push_item_visibility (image, NULL, item);
|
2003-09-12 03:52:29 +08:00
|
|
|
}
|
|
|
|
|
app: add GimpFilter::active property; move ::visible to GimpItem
Add an "active" property to GimpFilter, which replaces its
"visible" property. The new property assumes the lower-level role
"visible" had -- controlling whether the filter has any effect as
part of its parent filter-stack.
Add a "visible" property to GimpItem, separate from the "active"
property, which assumes the higher-level role "visible" had --
controlling whether the item is considered "visible", as per the
GUI. By default, the item's "visible" property is bound to the
filter's "active" property, so that changes in visibility directly
affect the filter's "activeness"; this binding can be controlled
using the new gimp_item_bind_visible_to_active() function.
This distinction is currently necessary for floating selections.
Floating selection layers must not be active in their parent stack,
regardless of their visibility, in particular, so that their mode
node doesn't hide the entire backdrop when their composite mode
excludes the backdrop (i.e., when it's dst-atop or src-in).
Instead, their visibility should affect the activeness of the
floating-selection filter of the drawable they're attached to.
This is handled by the next commit.
2017-12-06 02:46:50 +08:00
|
|
|
GET_PRIVATE (item)->visible = visible;
|
|
|
|
|
|
|
|
if (GET_PRIVATE (item)->bind_visible_to_active)
|
|
|
|
gimp_filter_set_active (GIMP_FILTER (item), visible);
|
|
|
|
|
|
|
|
g_signal_emit (item, gimp_item_signals[VISIBILITY_CHANGED], 0);
|
|
|
|
|
|
|
|
g_object_notify (G_OBJECT (item), "visible");
|
2003-09-12 03:52:29 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-08-19 19:37:41 +08:00
|
|
|
gboolean
|
2016-05-20 05:51:44 +08:00
|
|
|
gimp_item_get_visible (GimpItem *item)
|
2009-08-19 19:37:41 +08:00
|
|
|
{
|
|
|
|
g_return_val_if_fail (GIMP_IS_ITEM (item), FALSE);
|
|
|
|
|
app: add GimpFilter::active property; move ::visible to GimpItem
Add an "active" property to GimpFilter, which replaces its
"visible" property. The new property assumes the lower-level role
"visible" had -- controlling whether the filter has any effect as
part of its parent filter-stack.
Add a "visible" property to GimpItem, separate from the "active"
property, which assumes the higher-level role "visible" had --
controlling whether the item is considered "visible", as per the
GUI. By default, the item's "visible" property is bound to the
filter's "active" property, so that changes in visibility directly
affect the filter's "activeness"; this binding can be controlled
using the new gimp_item_bind_visible_to_active() function.
This distinction is currently necessary for floating selections.
Floating selection layers must not be active in their parent stack,
regardless of their visibility, in particular, so that their mode
node doesn't hide the entire backdrop when their composite mode
excludes the backdrop (i.e., when it's dst-atop or src-in).
Instead, their visibility should affect the activeness of the
floating-selection filter of the drawable they're attached to.
This is handled by the next commit.
2017-12-06 02:46:50 +08:00
|
|
|
return GET_PRIVATE (item)->visible;
|
2009-08-19 19:37:41 +08:00
|
|
|
}
|
|
|
|
|
2011-09-24 05:43:42 +08:00
|
|
|
gboolean
|
2016-05-20 05:51:44 +08:00
|
|
|
gimp_item_is_visible (GimpItem *item)
|
2011-09-24 05:43:42 +08:00
|
|
|
{
|
|
|
|
g_return_val_if_fail (GIMP_IS_ITEM (item), FALSE);
|
|
|
|
|
app: add GimpFilter::active property; move ::visible to GimpItem
Add an "active" property to GimpFilter, which replaces its
"visible" property. The new property assumes the lower-level role
"visible" had -- controlling whether the filter has any effect as
part of its parent filter-stack.
Add a "visible" property to GimpItem, separate from the "active"
property, which assumes the higher-level role "visible" had --
controlling whether the item is considered "visible", as per the
GUI. By default, the item's "visible" property is bound to the
filter's "active" property, so that changes in visibility directly
affect the filter's "activeness"; this binding can be controlled
using the new gimp_item_bind_visible_to_active() function.
This distinction is currently necessary for floating selections.
Floating selection layers must not be active in their parent stack,
regardless of their visibility, in particular, so that their mode
node doesn't hide the entire backdrop when their composite mode
excludes the backdrop (i.e., when it's dst-atop or src-in).
Instead, their visibility should affect the activeness of the
floating-selection filter of the drawable they're attached to.
This is handled by the next commit.
2017-12-06 02:46:50 +08:00
|
|
|
if (gimp_item_get_visible (item))
|
|
|
|
{
|
|
|
|
GimpItem *parent;
|
|
|
|
|
|
|
|
parent = GIMP_ITEM (gimp_viewable_get_parent (GIMP_VIEWABLE (item)));
|
|
|
|
|
|
|
|
if (parent)
|
|
|
|
return gimp_item_is_visible (parent);
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
gimp_item_bind_visible_to_active (GimpItem *item,
|
|
|
|
gboolean bind)
|
|
|
|
{
|
|
|
|
g_return_if_fail (GIMP_IS_ITEM (item));
|
|
|
|
|
|
|
|
GET_PRIVATE (item)->bind_visible_to_active = bind;
|
|
|
|
|
|
|
|
if (bind)
|
|
|
|
gimp_filter_set_active (GIMP_FILTER (item), gimp_item_get_visible (item));
|
2011-09-24 05:43:42 +08:00
|
|
|
}
|
|
|
|
|
2003-05-09 04:26:01 +08:00
|
|
|
void
|
|
|
|
gimp_item_set_linked (GimpItem *item,
|
|
|
|
gboolean linked,
|
|
|
|
gboolean push_undo)
|
|
|
|
{
|
|
|
|
g_return_if_fail (GIMP_IS_ITEM (item));
|
|
|
|
|
2009-08-19 19:37:41 +08:00
|
|
|
linked = linked ? TRUE : FALSE;
|
|
|
|
|
2007-12-24 00:58:41 +08:00
|
|
|
if (gimp_item_get_linked (item) != linked)
|
2003-05-09 04:26:01 +08:00
|
|
|
{
|
2004-11-16 21:41:55 +08:00
|
|
|
if (push_undo && gimp_item_is_attached (item))
|
2003-05-09 04:26:01 +08:00
|
|
|
{
|
2006-03-29 01:08:36 +08:00
|
|
|
GimpImage *image = gimp_item_get_image (item);
|
2003-05-09 04:26:01 +08:00
|
|
|
|
2006-03-29 01:08:36 +08:00
|
|
|
if (image)
|
|
|
|
gimp_image_undo_push_item_linked (image, NULL, item);
|
2003-05-09 04:26:01 +08:00
|
|
|
}
|
|
|
|
|
2011-01-31 04:49:51 +08:00
|
|
|
GET_PRIVATE (item)->linked = linked;
|
2003-05-09 04:26:01 +08:00
|
|
|
|
|
|
|
g_signal_emit (item, gimp_item_signals[LINKED_CHANGED], 0);
|
2008-11-13 23:06:34 +08:00
|
|
|
|
|
|
|
g_object_notify (G_OBJECT (item), "linked");
|
2003-05-09 04:26:01 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
gboolean
|
2016-05-20 05:51:44 +08:00
|
|
|
gimp_item_get_linked (GimpItem *item)
|
2003-05-09 04:26:01 +08:00
|
|
|
{
|
|
|
|
g_return_val_if_fail (GIMP_IS_ITEM (item), FALSE);
|
|
|
|
|
2011-01-31 04:49:51 +08:00
|
|
|
return GET_PRIVATE (item)->linked;
|
2003-05-09 04:26:01 +08:00
|
|
|
}
|
2006-05-21 19:32:41 +08:00
|
|
|
|
2016-10-29 22:50:13 +08:00
|
|
|
void
|
|
|
|
gimp_item_set_color_tag (GimpItem *item,
|
|
|
|
GimpColorTag color_tag,
|
|
|
|
gboolean push_undo)
|
|
|
|
{
|
|
|
|
g_return_if_fail (GIMP_IS_ITEM (item));
|
|
|
|
|
|
|
|
if (gimp_item_get_color_tag (item) != color_tag)
|
|
|
|
{
|
|
|
|
if (push_undo && gimp_item_is_attached (item))
|
|
|
|
{
|
|
|
|
GimpImage *image = gimp_item_get_image (item);
|
|
|
|
|
|
|
|
if (image)
|
|
|
|
gimp_image_undo_push_item_color_tag (image, NULL, item);
|
|
|
|
}
|
|
|
|
|
|
|
|
GET_PRIVATE (item)->color_tag = color_tag;
|
|
|
|
|
|
|
|
g_signal_emit (item, gimp_item_signals[COLOR_TAG_CHANGED], 0);
|
|
|
|
|
|
|
|
g_object_notify (G_OBJECT (item), "color-tag");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
GimpColorTag
|
|
|
|
gimp_item_get_color_tag (GimpItem *item)
|
|
|
|
{
|
|
|
|
g_return_val_if_fail (GIMP_IS_ITEM (item), GIMP_COLOR_TAG_NONE);
|
|
|
|
|
|
|
|
return GET_PRIVATE (item)->color_tag;
|
|
|
|
}
|
|
|
|
|
2017-12-08 05:42:54 +08:00
|
|
|
GimpColorTag
|
|
|
|
gimp_item_get_merged_color_tag (GimpItem *item)
|
|
|
|
{
|
|
|
|
g_return_val_if_fail (GIMP_IS_ITEM (item), GIMP_COLOR_TAG_NONE);
|
|
|
|
|
|
|
|
if (gimp_item_get_color_tag (item) == GIMP_COLOR_TAG_NONE)
|
|
|
|
{
|
|
|
|
GimpItem *parent;
|
|
|
|
|
|
|
|
parent = GIMP_ITEM (gimp_viewable_get_parent (GIMP_VIEWABLE (item)));
|
|
|
|
|
|
|
|
if (parent)
|
|
|
|
return gimp_item_get_merged_color_tag (parent);
|
|
|
|
}
|
|
|
|
|
|
|
|
return gimp_item_get_color_tag (item);
|
|
|
|
}
|
|
|
|
|
2009-08-19 19:37:41 +08:00
|
|
|
void
|
|
|
|
gimp_item_set_lock_content (GimpItem *item,
|
|
|
|
gboolean lock_content,
|
|
|
|
gboolean push_undo)
|
|
|
|
{
|
|
|
|
g_return_if_fail (GIMP_IS_ITEM (item));
|
2009-08-24 01:54:19 +08:00
|
|
|
g_return_if_fail (gimp_item_can_lock_content (item));
|
2009-08-19 19:37:41 +08:00
|
|
|
|
|
|
|
lock_content = lock_content ? TRUE : FALSE;
|
|
|
|
|
|
|
|
if (gimp_item_get_lock_content (item) != lock_content)
|
|
|
|
{
|
|
|
|
if (push_undo && gimp_item_is_attached (item))
|
|
|
|
{
|
|
|
|
/* Right now I don't think this should be pushed. */
|
|
|
|
#if 0
|
|
|
|
GimpImage *image = gimp_item_get_image (item);
|
|
|
|
|
|
|
|
gimp_image_undo_push_item_lock_content (image, NULL, item);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2011-01-31 04:49:51 +08:00
|
|
|
GET_PRIVATE (item)->lock_content = lock_content;
|
2009-08-19 19:37:41 +08:00
|
|
|
|
|
|
|
g_signal_emit (item, gimp_item_signals[LOCK_CONTENT_CHANGED], 0);
|
|
|
|
|
|
|
|
g_object_notify (G_OBJECT (item), "lock-content");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
gboolean
|
2016-05-20 05:51:44 +08:00
|
|
|
gimp_item_get_lock_content (GimpItem *item)
|
2009-08-19 19:37:41 +08:00
|
|
|
{
|
|
|
|
g_return_val_if_fail (GIMP_IS_ITEM (item), FALSE);
|
|
|
|
|
2011-01-31 04:49:51 +08:00
|
|
|
return GET_PRIVATE (item)->lock_content;
|
2009-08-19 19:37:41 +08:00
|
|
|
}
|
|
|
|
|
2009-08-24 00:44:05 +08:00
|
|
|
gboolean
|
2016-05-20 05:51:44 +08:00
|
|
|
gimp_item_can_lock_content (GimpItem *item)
|
2009-08-24 00:44:05 +08:00
|
|
|
{
|
|
|
|
g_return_val_if_fail (GIMP_IS_ITEM (item), FALSE);
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2009-08-29 20:59:07 +08:00
|
|
|
gboolean
|
2016-05-20 05:51:44 +08:00
|
|
|
gimp_item_is_content_locked (GimpItem *item)
|
2009-08-29 20:59:07 +08:00
|
|
|
{
|
|
|
|
g_return_val_if_fail (GIMP_IS_ITEM (item), FALSE);
|
|
|
|
|
|
|
|
return GIMP_ITEM_GET_CLASS (item)->is_content_locked (item);
|
|
|
|
}
|
|
|
|
|
2012-11-09 18:17:25 +08:00
|
|
|
void
|
|
|
|
gimp_item_set_lock_position (GimpItem *item,
|
|
|
|
gboolean lock_position,
|
|
|
|
gboolean push_undo)
|
|
|
|
{
|
|
|
|
g_return_if_fail (GIMP_IS_ITEM (item));
|
|
|
|
g_return_if_fail (gimp_item_can_lock_position (item));
|
|
|
|
|
|
|
|
lock_position = lock_position ? TRUE : FALSE;
|
|
|
|
|
|
|
|
if (gimp_item_get_lock_position (item) != lock_position)
|
|
|
|
{
|
|
|
|
if (push_undo && gimp_item_is_attached (item))
|
|
|
|
{
|
|
|
|
GimpImage *image = gimp_item_get_image (item);
|
|
|
|
|
|
|
|
gimp_image_undo_push_item_lock_position (image, NULL, item);
|
|
|
|
}
|
|
|
|
|
|
|
|
GET_PRIVATE (item)->lock_position = lock_position;
|
|
|
|
|
|
|
|
g_signal_emit (item, gimp_item_signals[LOCK_POSITION_CHANGED], 0);
|
|
|
|
|
|
|
|
g_object_notify (G_OBJECT (item), "lock-position");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
gboolean
|
2016-05-20 05:51:44 +08:00
|
|
|
gimp_item_get_lock_position (GimpItem *item)
|
2012-11-09 18:17:25 +08:00
|
|
|
{
|
|
|
|
g_return_val_if_fail (GIMP_IS_ITEM (item), FALSE);
|
|
|
|
|
|
|
|
return GET_PRIVATE (item)->lock_position;
|
|
|
|
}
|
|
|
|
|
|
|
|
gboolean
|
2016-05-20 05:51:44 +08:00
|
|
|
gimp_item_can_lock_position (GimpItem *item)
|
2012-11-09 18:17:25 +08:00
|
|
|
{
|
|
|
|
g_return_val_if_fail (GIMP_IS_ITEM (item), FALSE);
|
|
|
|
|
|
|
|
if (gimp_viewable_get_children (GIMP_VIEWABLE (item)))
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
gboolean
|
2016-05-20 05:51:44 +08:00
|
|
|
gimp_item_is_position_locked (GimpItem *item)
|
2012-11-09 18:17:25 +08:00
|
|
|
{
|
|
|
|
g_return_val_if_fail (GIMP_IS_ITEM (item), FALSE);
|
|
|
|
|
|
|
|
return GIMP_ITEM_GET_CLASS (item)->is_position_locked (item);
|
|
|
|
}
|
|
|
|
|
2010-09-08 03:28:00 +08:00
|
|
|
gboolean
|
|
|
|
gimp_item_mask_bounds (GimpItem *item,
|
|
|
|
gint *x1,
|
|
|
|
gint *y1,
|
|
|
|
gint *x2,
|
|
|
|
gint *y2)
|
|
|
|
{
|
|
|
|
GimpImage *image;
|
|
|
|
GimpChannel *selection;
|
2016-09-17 05:56:31 +08:00
|
|
|
gint x, y, width, height;
|
2010-09-08 03:28:00 +08:00
|
|
|
gboolean retval;
|
|
|
|
|
|
|
|
g_return_val_if_fail (GIMP_IS_ITEM (item), FALSE);
|
|
|
|
g_return_val_if_fail (gimp_item_is_attached (item), FALSE);
|
|
|
|
|
|
|
|
image = gimp_item_get_image (item);
|
|
|
|
selection = gimp_image_get_mask (image);
|
|
|
|
|
2016-11-05 05:16:22 +08:00
|
|
|
/* check for is_empty() before intersecting so we ignore the
|
|
|
|
* selection if it is suspended (like when stroking)
|
|
|
|
*/
|
|
|
|
if (GIMP_ITEM (selection) != item &&
|
|
|
|
! gimp_channel_is_empty (selection) &&
|
2016-09-17 05:56:31 +08:00
|
|
|
gimp_item_bounds (GIMP_ITEM (selection), &x, &y, &width, &height))
|
2010-09-08 03:28:00 +08:00
|
|
|
{
|
|
|
|
gint off_x, off_y;
|
2015-07-02 09:04:39 +08:00
|
|
|
gint x2, y2;
|
2010-09-08 03:28:00 +08:00
|
|
|
|
|
|
|
gimp_item_get_offset (item, &off_x, &off_y);
|
|
|
|
|
2016-09-17 05:56:31 +08:00
|
|
|
x2 = x + width;
|
|
|
|
y2 = y + height;
|
2015-07-02 09:04:39 +08:00
|
|
|
|
|
|
|
x = CLAMP (x - off_x, 0, gimp_item_get_width (item));
|
|
|
|
y = CLAMP (y - off_y, 0, gimp_item_get_height (item));
|
|
|
|
x2 = CLAMP (x2 - off_x, 0, gimp_item_get_width (item));
|
|
|
|
y2 = CLAMP (y2 - off_y, 0, gimp_item_get_height (item));
|
|
|
|
|
2016-09-17 05:56:31 +08:00
|
|
|
width = x2 - x;
|
|
|
|
height = y2 - y;
|
2010-09-08 03:28:00 +08:00
|
|
|
|
|
|
|
retval = TRUE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2016-09-17 05:56:31 +08:00
|
|
|
x = 0;
|
|
|
|
y = 0;
|
|
|
|
width = gimp_item_get_width (item);
|
|
|
|
height = gimp_item_get_height (item);
|
2010-09-08 03:28:00 +08:00
|
|
|
|
|
|
|
retval = FALSE;
|
|
|
|
}
|
|
|
|
|
2015-07-02 09:04:39 +08:00
|
|
|
if (x1) *x1 = x;
|
|
|
|
if (y1) *y1 = y;
|
2016-09-17 05:56:31 +08:00
|
|
|
if (x2) *x2 = x + width;
|
|
|
|
if (y2) *y2 = y + height;
|
2010-09-08 03:28:00 +08:00
|
|
|
|
2012-08-14 21:36:23 +08:00
|
|
|
return retval;
|
2010-09-08 03:28:00 +08:00
|
|
|
}
|
|
|
|
|
2011-07-03 04:27:48 +08:00
|
|
|
/**
|
|
|
|
* gimp_item_mask_intersect:
|
|
|
|
* @item: a #GimpItem
|
|
|
|
* @x: return location for x
|
|
|
|
* @y: return location for y
|
|
|
|
* @width: return location for the width
|
|
|
|
* @height: return location for the height
|
|
|
|
*
|
|
|
|
* Intersect the area of the @item and its image's selection mask.
|
|
|
|
* The computed area is the bounding box of he selection within the
|
|
|
|
* item.
|
|
|
|
**/
|
2010-09-08 03:28:00 +08:00
|
|
|
gboolean
|
|
|
|
gimp_item_mask_intersect (GimpItem *item,
|
|
|
|
gint *x,
|
|
|
|
gint *y,
|
|
|
|
gint *width,
|
|
|
|
gint *height)
|
|
|
|
{
|
|
|
|
GimpImage *image;
|
|
|
|
GimpChannel *selection;
|
|
|
|
gint tmp_x, tmp_y;
|
|
|
|
gint tmp_width, tmp_height;
|
|
|
|
gboolean retval;
|
|
|
|
|
|
|
|
g_return_val_if_fail (GIMP_IS_ITEM (item), FALSE);
|
|
|
|
g_return_val_if_fail (gimp_item_is_attached (item), FALSE);
|
|
|
|
|
|
|
|
image = gimp_item_get_image (item);
|
|
|
|
selection = gimp_image_get_mask (image);
|
|
|
|
|
2016-11-05 05:16:22 +08:00
|
|
|
/* check for is_empty() before intersecting so we ignore the
|
|
|
|
* selection if it is suspended (like when stroking)
|
|
|
|
*/
|
|
|
|
if (GIMP_ITEM (selection) != item &&
|
|
|
|
! gimp_channel_is_empty (selection) &&
|
2015-07-02 09:04:39 +08:00
|
|
|
gimp_item_bounds (GIMP_ITEM (selection),
|
|
|
|
&tmp_x, &tmp_y, &tmp_width, &tmp_height))
|
2010-09-08 03:28:00 +08:00
|
|
|
{
|
|
|
|
gint off_x, off_y;
|
|
|
|
|
|
|
|
gimp_item_get_offset (item, &off_x, &off_y);
|
|
|
|
|
|
|
|
retval = gimp_rectangle_intersect (tmp_x - off_x, tmp_y - off_y,
|
|
|
|
tmp_width, tmp_height,
|
|
|
|
0, 0,
|
|
|
|
gimp_item_get_width (item),
|
|
|
|
gimp_item_get_height (item),
|
|
|
|
&tmp_x, &tmp_y,
|
|
|
|
&tmp_width, &tmp_height);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
tmp_x = 0;
|
|
|
|
tmp_y = 0;
|
|
|
|
tmp_width = gimp_item_get_width (item);
|
|
|
|
tmp_height = gimp_item_get_height (item);
|
|
|
|
|
|
|
|
retval = TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (x) *x = tmp_x;
|
|
|
|
if (y) *y = tmp_y;
|
|
|
|
if (width) *width = tmp_width;
|
|
|
|
if (height) *height = tmp_height;
|
|
|
|
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
2006-05-21 19:32:41 +08:00
|
|
|
gboolean
|
|
|
|
gimp_item_is_in_set (GimpItem *item,
|
|
|
|
GimpItemSet set)
|
|
|
|
{
|
2011-01-31 04:49:51 +08:00
|
|
|
GimpItemPrivate *private;
|
|
|
|
|
2006-05-21 19:32:41 +08:00
|
|
|
g_return_val_if_fail (GIMP_IS_ITEM (item), FALSE);
|
|
|
|
|
2011-01-31 04:49:51 +08:00
|
|
|
private = GET_PRIVATE (item);
|
|
|
|
|
2006-05-21 19:32:41 +08:00
|
|
|
switch (set)
|
|
|
|
{
|
|
|
|
case GIMP_ITEM_SET_NONE:
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
case GIMP_ITEM_SET_ALL:
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
case GIMP_ITEM_SET_IMAGE_SIZED:
|
2011-01-31 04:49:51 +08:00
|
|
|
return (gimp_item_get_width (item) == gimp_image_get_width (private->image) &&
|
|
|
|
gimp_item_get_height (item) == gimp_image_get_height (private->image));
|
2006-05-21 19:32:41 +08:00
|
|
|
|
|
|
|
case GIMP_ITEM_SET_VISIBLE:
|
|
|
|
return gimp_item_get_visible (item);
|
|
|
|
|
|
|
|
case GIMP_ITEM_SET_LINKED:
|
|
|
|
return gimp_item_get_linked (item);
|
|
|
|
}
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|