Files
gimp/app/core/gimpitem.c
Ell 4f9c3f2a6a app: avoid deleting empty layer groups when downscaling image
When dowscaling an image (or a layer group), empty layer groups
can be discarded as a result of their new dimensions being too
small, since we're calculating their new dimensions according to
their fake 1x1 dimensions.  However, these dimensions are purely an
implementation detail and shouldn't affect the result, and neither
do we show a warning for them.

Instead, simply avoid discarding empty layer groups.

(cherry picked from commit b99a2631ef)
2020-01-21 20:16:02 +02:00

2690 lines
80 KiB
C

/* GIMP - The GNU Image Manipulation Program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <stdlib.h>
#include <string.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
#include <gegl.h>
#include "libgimpbase/gimpbase.h"
#include "libgimpmath/gimpmath.h"
#include "core-types.h"
#include "gimp.h"
#include "gimp-parasites.h"
#include "gimpchannel.h"
#include "gimpcontainer.h"
#include "gimpidtable.h"
#include "gimpimage.h"
#include "gimpimage-undo.h"
#include "gimpimage-undo-push.h"
#include "gimpitem.h"
#include "gimpitem-linked.h"
#include "gimpitem-preview.h"
#include "gimpitemtree.h"
#include "gimplist.h"
#include "gimpmarshal.h"
#include "gimpparasitelist.h"
#include "gimpprogress.h"
#include "gimpstrokeoptions.h"
#include "paint/gimppaintoptions.h"
#include "gimp-intl.h"
enum
{
REMOVED,
VISIBILITY_CHANGED,
LINKED_CHANGED,
COLOR_TAG_CHANGED,
LOCK_CONTENT_CHANGED,
LOCK_POSITION_CHANGED,
LAST_SIGNAL
};
enum
{
PROP_0,
PROP_IMAGE,
PROP_ID,
PROP_WIDTH,
PROP_HEIGHT,
PROP_OFFSET_X,
PROP_OFFSET_Y,
PROP_VISIBLE,
PROP_LINKED,
PROP_COLOR_TAG,
PROP_LOCK_CONTENT,
PROP_LOCK_POSITION
};
typedef struct _GimpItemPrivate GimpItemPrivate;
struct _GimpItemPrivate
{
gint ID; /* provides a unique ID */
guint32 tattoo; /* provides a permanent ID */
GimpImage *image; /* item owner */
GimpParasiteList *parasites; /* Plug-in parasite data */
gint width, height; /* size in pixels */
gint offset_x, offset_y; /* pixel offset in image */
guint visible : 1; /* item visibility */
guint bind_visible_to_active : 1; /* visibility bound to active */
guint linked : 1; /* control linkage */
guint lock_content : 1; /* content editability */
guint lock_position : 1; /* content movability */
guint removed : 1; /* removed from the image? */
GimpColorTag color_tag; /* color tag */
GList *offset_nodes; /* offset nodes to manage */
};
#define GET_PRIVATE(item) ((GimpItemPrivate *) gimp_item_get_instance_private ((GimpItem *) (item)))
/* local function prototypes */
static void gimp_item_constructed (GObject *object);
static void gimp_item_finalize (GObject *object);
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);
static gboolean gimp_item_real_is_content_locked (GimpItem *item);
static gboolean gimp_item_real_is_position_locked (GimpItem *item);
static gboolean gimp_item_real_bounds (GimpItem *item,
gdouble *x,
gdouble *y,
gdouble *width,
gdouble *height);
static GimpItem * gimp_item_real_duplicate (GimpItem *item,
GType new_type);
static void gimp_item_real_convert (GimpItem *item,
GimpImage *dest_image,
GType old_type);
static gboolean gimp_item_real_rename (GimpItem *item,
const gchar *new_name,
const gchar *undo_desc,
GError **error);
static void gimp_item_real_start_transform (GimpItem *item,
gboolean push_undo);
static void gimp_item_real_end_transform (GimpItem *item,
gboolean push_undo);
static void gimp_item_real_translate (GimpItem *item,
gdouble offset_x,
gdouble offset_y,
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,
GimpFillType fill_type,
gint new_width,
gint new_height,
gint offset_x,
gint offset_y);
static GimpTransformResize
gimp_item_real_get_clip (GimpItem *item,
GimpTransformResize clip_result);
G_DEFINE_TYPE_WITH_PRIVATE (GimpItem, gimp_item, GIMP_TYPE_FILTER)
#define parent_class gimp_item_parent_class
static guint gimp_item_signals[LAST_SIGNAL] = { 0 };
static void
gimp_item_class_init (GimpItemClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GimpObjectClass *gimp_object_class = GIMP_OBJECT_CLASS (klass);
GimpViewableClass *viewable_class = GIMP_VIEWABLE_CLASS (klass);
gimp_item_signals[REMOVED] =
g_signal_new ("removed",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (GimpItemClass, removed),
NULL, NULL,
gimp_marshal_VOID__VOID,
G_TYPE_NONE, 0);
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);
gimp_item_signals[LINKED_CHANGED] =
g_signal_new ("linked-changed",
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);
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);
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);
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);
object_class->constructed = gimp_item_constructed;
object_class->finalize = gimp_item_finalize;
object_class->set_property = gimp_item_set_property;
object_class->get_property = gimp_item_get_property;
gimp_object_class->get_memsize = gimp_item_get_memsize;
viewable_class->name_editable = TRUE;
viewable_class->get_preview_size = gimp_item_get_preview_size;
viewable_class->get_popup_size = gimp_item_get_popup_size;
klass->removed = NULL;
klass->visibility_changed = NULL;
klass->linked_changed = NULL;
klass->color_tag_changed = NULL;
klass->lock_content_changed = NULL;
klass->lock_position_changed = NULL;
klass->unset_removed = NULL;
klass->is_attached = NULL;
klass->is_content_locked = gimp_item_real_is_content_locked;
klass->is_position_locked = gimp_item_real_is_position_locked;
klass->get_tree = NULL;
klass->bounds = gimp_item_real_bounds;
klass->duplicate = gimp_item_real_duplicate;
klass->convert = gimp_item_real_convert;
klass->rename = gimp_item_real_rename;
klass->start_move = NULL;
klass->end_move = NULL;
klass->start_transform = gimp_item_real_start_transform;
klass->end_transform = gimp_item_real_end_transform;
klass->translate = gimp_item_real_translate;
klass->scale = gimp_item_real_scale;
klass->resize = gimp_item_real_resize;
klass->flip = NULL;
klass->rotate = NULL;
klass->transform = NULL;
klass->get_clip = gimp_item_real_get_clip;
klass->fill = NULL;
klass->stroke = NULL;
klass->to_selection = NULL;
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;
klass->fill_desc = NULL;
klass->stroke_desc = NULL;
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));
g_object_class_install_property (object_class, PROP_ID,
g_param_spec_int ("id", NULL, NULL,
0, G_MAXINT, 0,
GIMP_PARAM_READABLE));
g_object_class_install_property (object_class, PROP_WIDTH,
g_param_spec_int ("width", NULL, NULL,
1, GIMP_MAX_IMAGE_SIZE, 1,
GIMP_PARAM_READABLE));
g_object_class_install_property (object_class, PROP_HEIGHT,
g_param_spec_int ("height", NULL, NULL,
1, GIMP_MAX_IMAGE_SIZE, 1,
GIMP_PARAM_READABLE));
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));
g_object_class_install_property (object_class, PROP_VISIBLE,
g_param_spec_boolean ("visible", NULL, NULL,
TRUE,
GIMP_PARAM_READABLE));
g_object_class_install_property (object_class, PROP_LINKED,
g_param_spec_boolean ("linked", NULL, NULL,
FALSE,
GIMP_PARAM_READABLE));
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));
g_object_class_install_property (object_class, PROP_LOCK_CONTENT,
g_param_spec_boolean ("lock-content",
NULL, NULL,
FALSE,
GIMP_PARAM_READABLE));
g_object_class_install_property (object_class, PROP_LOCK_POSITION,
g_param_spec_boolean ("lock-position",
NULL, NULL,
FALSE,
GIMP_PARAM_READABLE));
}
static void
gimp_item_init (GimpItem *item)
{
GimpItemPrivate *private = GET_PRIVATE (item);
g_object_force_floating (G_OBJECT (item));
private->parasites = gimp_parasite_list_new ();
private->visible = TRUE;
private->bind_visible_to_active = TRUE;
}
static void
gimp_item_constructed (GObject *object)
{
GimpItemPrivate *private = GET_PRIVATE (object);
G_OBJECT_CLASS (parent_class)->constructed (object);
gimp_assert (GIMP_IS_IMAGE (private->image));
gimp_assert (private->ID != 0);
}
static void
gimp_item_finalize (GObject *object)
{
GimpItemPrivate *private = GET_PRIVATE (object);
if (private->offset_nodes)
{
g_list_free_full (private->offset_nodes,
(GDestroyNotify) g_object_unref);
private->offset_nodes = NULL;
}
if (private->image && private->image->gimp)
{
gimp_id_table_remove (private->image->gimp->item_table, private->ID);
private->image = NULL;
}
g_clear_object (&private->parasites);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
static void
gimp_item_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
GimpItem *item = GIMP_ITEM (object);
switch (property_id)
{
case PROP_IMAGE:
gimp_item_set_image (item, g_value_get_object (value));
break;
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)
{
GimpItemPrivate *private = GET_PRIVATE (object);
switch (property_id)
{
case PROP_IMAGE:
g_value_set_object (value, private->image);
break;
case PROP_ID:
g_value_set_int (value, private->ID);
break;
case PROP_WIDTH:
g_value_set_int (value, private->width);
break;
case PROP_HEIGHT:
g_value_set_int (value, private->height);
break;
case PROP_OFFSET_X:
g_value_set_int (value, private->offset_x);
break;
case PROP_OFFSET_Y:
g_value_set_int (value, private->offset_y);
break;
case PROP_VISIBLE:
g_value_set_boolean (value, private->visible);
break;
case PROP_LINKED:
g_value_set_boolean (value, private->linked);
break;
case PROP_COLOR_TAG:
g_value_set_enum (value, private->color_tag);
break;
case PROP_LOCK_CONTENT:
g_value_set_boolean (value, private->lock_content);
break;
case PROP_LOCK_POSITION:
g_value_set_boolean (value, private->lock_position);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static gint64
gimp_item_get_memsize (GimpObject *object,
gint64 *gui_size)
{
GimpItemPrivate *private = GET_PRIVATE (object);
gint64 memsize = 0;
memsize += gimp_object_get_memsize (GIMP_OBJECT (private->parasites),
gui_size);
return memsize + GIMP_OBJECT_CLASS (parent_class)->get_memsize (object,
gui_size);
}
static gboolean
gimp_item_real_is_content_locked (GimpItem *item)
{
GimpItem *parent = gimp_item_get_parent (item);
if (parent && gimp_item_is_content_locked (parent))
return TRUE;
return GET_PRIVATE (item)->lock_content;
}
static gboolean
gimp_item_real_is_position_locked (GimpItem *item)
{
if (gimp_item_get_linked (item))
if (gimp_item_linked_is_locked (item))
return TRUE;
return GET_PRIVATE (item)->lock_position;
}
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;
}
static GimpItem *
gimp_item_real_duplicate (GimpItem *item,
GType new_type)
{
GimpItemPrivate *private;
GimpItem *new_item;
gchar *new_name;
g_return_val_if_fail (GIMP_IS_ITEM (item), NULL);
private = GET_PRIVATE (item);
g_return_val_if_fail (GIMP_IS_IMAGE (private->image), NULL);
g_return_val_if_fail (g_type_is_a (new_type, GIMP_TYPE_ITEM), NULL);
/* formulate the new name */
{
const gchar *name;
gint len;
name = gimp_object_get_name (item);
g_return_val_if_fail (name != NULL, NULL);
len = strlen (_("copy"));
if ((strlen (name) >= len &&
strcmp (&name[strlen (name) - len], _("copy")) == 0) ||
g_regex_match_simple ("#([0-9]+)\\s*$", name, 0, 0))
{
/* don't have redundant "copy"s */
new_name = g_strdup (name);
}
else
{
new_name = g_strdup_printf (_("%s copy"), name);
}
}
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));
g_free (new_name);
gimp_viewable_set_expanded (GIMP_VIEWABLE (new_item),
gimp_viewable_get_expanded (GIMP_VIEWABLE (item)));
g_object_unref (GET_PRIVATE (new_item)->parasites);
GET_PRIVATE (new_item)->parasites = gimp_parasite_list_copy (private->parasites);
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);
if (gimp_item_can_lock_content (new_item))
gimp_item_set_lock_content (new_item, gimp_item_get_lock_content (item),
FALSE);
if (gimp_item_can_lock_position (new_item))
gimp_item_set_lock_position (new_item, gimp_item_get_lock_position (item),
FALSE);
return new_item;
}
static void
gimp_item_real_convert (GimpItem *item,
GimpImage *dest_image,
GType old_type)
{
gimp_item_set_image (item, dest_image);
}
static gboolean
gimp_item_real_rename (GimpItem *item,
const gchar *new_name,
const gchar *undo_desc,
GError **error)
{
if (gimp_item_is_attached (item))
gimp_item_tree_rename_item (gimp_item_get_tree (item), item,
new_name, TRUE, undo_desc);
else
gimp_object_set_name (GIMP_OBJECT (item), new_name);
return TRUE;
}
static void
gimp_item_real_translate (GimpItem *item,
gdouble offset_x,
gdouble offset_y,
gboolean push_undo)
{
GimpItemPrivate *private = GET_PRIVATE (item);
gimp_item_set_offset (item,
private->offset_x + SIGNED_ROUND (offset_x),
private->offset_y + SIGNED_ROUND (offset_y));
}
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);
}
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)
{
GimpItemPrivate *private = GET_PRIVATE (item);
if (private->width != new_width)
{
private->width = new_width;
g_object_notify (G_OBJECT (item), "width");
}
if (private->height != new_height)
{
private->height = new_height;
g_object_notify (G_OBJECT (item), "height");
}
gimp_item_set_offset (item, new_offset_x, new_offset_y);
}
static void
gimp_item_real_resize (GimpItem *item,
GimpContext *context,
GimpFillType fill_type,
gint new_width,
gint new_height,
gint offset_x,
gint offset_y)
{
GimpItemPrivate *private = GET_PRIVATE (item);
if (private->width != new_width)
{
private->width = new_width;
g_object_notify (G_OBJECT (item), "width");
}
if (private->height != new_height)
{
private->height = new_height;
g_object_notify (G_OBJECT (item), "height");
}
gimp_item_set_offset (item,
private->offset_x - offset_x,
private->offset_y - offset_y);
}
static GimpTransformResize
gimp_item_real_get_clip (GimpItem *item,
GimpTransformResize clip_result)
{
if (gimp_item_get_lock_position (item))
return GIMP_TRANSFORM_RESIZE_CLIP;
else
return clip_result;
}
/* 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);
private->width = width;
private->height = height;
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;
}
/**
* 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.
*/
void
gimp_item_removed (GimpItem *item)
{
GimpContainer *children;
g_return_if_fail (GIMP_IS_ITEM (item));
GET_PRIVATE (item)->removed = TRUE;
children = gimp_viewable_get_children (GIMP_VIEWABLE (item));
if (children)
gimp_container_foreach (children, (GFunc) gimp_item_removed, NULL);
g_signal_emit (item, gimp_item_signals[REMOVED], 0);
}
/**
* gimp_item_is_removed:
* @item: the #GimpItem to check.
*
* Returns: %TRUE if the 'removed' flag is set for @item, %FALSE otherwise.
*/
gboolean
gimp_item_is_removed (GimpItem *item)
{
g_return_val_if_fail (GIMP_IS_ITEM (item), FALSE);
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)
{
GimpContainer *children;
g_return_if_fail (GIMP_IS_ITEM (item));
g_return_if_fail (gimp_item_is_removed (item));
GET_PRIVATE (item)->removed = FALSE;
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);
}
/**
* gimp_item_is_attached:
* @item: The #GimpItem to check.
*
* Returns: %TRUE if the item is attached to an image, %FALSE otherwise.
*/
gboolean
gimp_item_is_attached (GimpItem *item)
{
GimpItem *parent;
g_return_val_if_fail (GIMP_IS_ITEM (item), FALSE);
parent = gimp_item_get_parent (item);
if (parent)
return gimp_item_is_attached (parent);
return GIMP_ITEM_GET_CLASS (item)->is_attached (item);
}
GimpItem *
gimp_item_get_parent (GimpItem *item)
{
g_return_val_if_fail (GIMP_IS_ITEM (item), NULL);
return GIMP_ITEM (gimp_viewable_get_parent (GIMP_VIEWABLE (item)));
}
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;
}
GimpContainer *
gimp_item_get_container (GimpItem *item)
{
GimpItem *parent;
GimpItemTree *tree;
g_return_val_if_fail (GIMP_IS_ITEM (item), NULL);
parent = gimp_item_get_parent (item);
if (parent)
return gimp_viewable_get_children (GIMP_VIEWABLE (parent));
tree = gimp_item_get_tree (item);
if (tree)
return tree->container;
return NULL;
}
GList *
gimp_item_get_container_iter (GimpItem *item)
{
GimpContainer *container;
g_return_val_if_fail (GIMP_IS_ITEM (item), NULL);
container = gimp_item_get_container (item);
if (container)
return GIMP_LIST (container)->queue->head;
return NULL;
}
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;
}
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));
item = gimp_item_get_parent (item);
if (item)
container = gimp_item_get_container (item);
else
container = NULL;
}
return path;
}
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;
}
/**
* gimp_item_duplicate:
* @item: The #GimpItem to duplicate.
* @new_type: The type to make the new item.
*
* Returns: the newly created item.
*/
GimpItem *
gimp_item_duplicate (GimpItem *item,
GType new_type)
{
GimpItemPrivate *private;
g_return_val_if_fail (GIMP_IS_ITEM (item), NULL);
private = GET_PRIVATE (item);
g_return_val_if_fail (GIMP_IS_IMAGE (private->image), NULL);
g_return_val_if_fail (g_type_is_a (new_type, GIMP_TYPE_ITEM), NULL);
return GIMP_ITEM_GET_CLASS (item)->duplicate (item, new_type);
}
/**
* gimp_item_convert:
* @item: The #GimpItem to convert.
* @dest_image: The #GimpImage in which to place the converted item.
* @new_type: The type to convert the item to.
*
* Returns: the new item that results from the conversion.
*/
GimpItem *
gimp_item_convert (GimpItem *item,
GimpImage *dest_image,
GType new_type)
{
GimpItem *new_item;
GType old_type;
g_return_val_if_fail (GIMP_IS_ITEM (item), NULL);
g_return_val_if_fail (GIMP_IS_IMAGE (GET_PRIVATE (item)->image), NULL);
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);
old_type = G_TYPE_FROM_INSTANCE (item);
new_item = gimp_item_duplicate (item, new_type);
if (new_item)
GIMP_ITEM_GET_CLASS (new_item)->convert (new_item, dest_image, old_type);
return new_item;
}
/**
* gimp_item_rename:
* @item: The #GimpItem to rename.
* @new_name: The new name to give the item.
* @error: Return location for error message.
*
* 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,
* the GimpObject::name-changed signal is emitted for the item.
*
* Returns: %TRUE if the @item could be renamed, %FALSE otherwise.
*/
gboolean
gimp_item_rename (GimpItem *item,
const gchar *new_name,
GError **error)
{
GimpItemClass *item_class;
g_return_val_if_fail (GIMP_IS_ITEM (item), FALSE);
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
item_class = GIMP_ITEM_GET_CLASS (item);
if (! new_name || ! *new_name)
new_name = item_class->default_name;
if (strcmp (new_name, gimp_object_get_name (item)))
return item_class->rename (item, new_name, item_class->rename_desc, error);
return TRUE;
}
/**
* gimp_item_get_width:
* @item: The #GimpItem to check.
*
* Returns: The width of the item.
*/
gint
gimp_item_get_width (GimpItem *item)
{
g_return_val_if_fail (GIMP_IS_ITEM (item), -1);
return GET_PRIVATE (item)->width;
}
/**
* gimp_item_get_height:
* @item: The #GimpItem to check.
*
* Returns: The height of the item.
*/
gint
gimp_item_get_height (GimpItem *item)
{
g_return_val_if_fail (GIMP_IS_ITEM (item), -1);
return GET_PRIVATE (item)->height;
}
void
gimp_item_set_size (GimpItem *item,
gint width,
gint height)
{
GimpItemPrivate *private;
g_return_if_fail (GIMP_IS_ITEM (item));
private = GET_PRIVATE (item);
if (private->width != width ||
private->height != height)
{
g_object_freeze_notify (G_OBJECT (item));
if (private->width != width)
{
private->width = width;
g_object_notify (G_OBJECT (item), "width");
}
if (private->height != height)
{
private->height = height;
g_object_notify (G_OBJECT (item), "height");
}
g_object_thaw_notify (G_OBJECT (item));
gimp_viewable_size_changed (GIMP_VIEWABLE (item));
}
}
/**
* gimp_item_get_offset:
* @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.
*
* Reveals the X and Y offsets of the item.
*/
void
gimp_item_get_offset (GimpItem *item,
gint *offset_x,
gint *offset_y)
{
GimpItemPrivate *private;
g_return_if_fail (GIMP_IS_ITEM (item));
private = GET_PRIVATE (item);
if (offset_x) *offset_x = private->offset_x;
if (offset_y) *offset_y = private->offset_y;
}
void
gimp_item_set_offset (GimpItem *item,
gint offset_x,
gint offset_y)
{
GimpItemPrivate *private;
GList *list;
g_return_if_fail (GIMP_IS_ITEM (item));
private = GET_PRIVATE (item);
g_object_freeze_notify (G_OBJECT (item));
if (private->offset_x != offset_x)
{
private->offset_x = offset_x;
g_object_notify (G_OBJECT (item), "offset-x");
}
if (private->offset_y != offset_y)
{
private->offset_y = offset_y;
g_object_notify (G_OBJECT (item), "offset-y");
}
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);
}
g_object_thaw_notify (G_OBJECT (item));
}
gint
gimp_item_get_offset_x (GimpItem *item)
{
g_return_val_if_fail (GIMP_IS_ITEM (item), 0);
return GET_PRIVATE (item)->offset_x;
}
gint
gimp_item_get_offset_y (GimpItem *item)
{
g_return_val_if_fail (GIMP_IS_ITEM (item), 0);
return GET_PRIVATE (item)->offset_y;
}
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);
}
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);
}
/**
* gimp_item_translate:
* @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.
* @push_undo: If #TRUE, create an entry in the image's undo stack
* for this action.
*
* Adds the specified increments to the X and Y offsets for the item.
*/
void
gimp_item_translate (GimpItem *item,
gdouble offset_x,
gdouble offset_y,
gboolean push_undo)
{
GimpItemClass *item_class;
GimpImage *image;
g_return_if_fail (GIMP_IS_ITEM (item));
item_class = GIMP_ITEM_GET_CLASS (item);
image = gimp_item_get_image (item);
if (! gimp_item_is_attached (item))
push_undo = FALSE;
if (push_undo)
gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_ITEM_DISPLACE,
item_class->translate_desc);
gimp_item_start_transform (item, push_undo);
item_class->translate (item, offset_x, offset_y, push_undo);
gimp_item_end_transform (item, push_undo);
if (push_undo)
gimp_image_undo_group_end (image);
}
/**
* 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
*
* Returns: #FALSE if any dimension reduces to zero as a result
* of this; otherwise, returns #TRUE.
**/
gboolean
gimp_item_check_scaling (GimpItem *item,
gint new_width,
gint new_height)
{
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;
g_return_val_if_fail (GIMP_IS_ITEM (item), FALSE);
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;
return (new_item_width > 0 && new_item_height > 0);
}
void
gimp_item_scale (GimpItem *item,
gint new_width,
gint new_height,
gint new_offset_x,
gint new_offset_y,
GimpInterpolationType interpolation,
GimpProgress *progress)
{
GimpItemClass *item_class;
GimpImage *image;
gboolean push_undo;
g_return_if_fail (GIMP_IS_ITEM (item));
g_return_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress));
if (new_width < 1 || new_height < 1)
return;
item_class = GIMP_ITEM_GET_CLASS (item);
image = gimp_item_get_image (item);
push_undo = gimp_item_is_attached (item);
if (push_undo)
gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_ITEM_SCALE,
item_class->scale_desc);
gimp_item_start_transform (item, push_undo);
g_object_freeze_notify (G_OBJECT (item));
item_class->scale (item, new_width, new_height, new_offset_x, new_offset_y,
interpolation, progress);
g_object_thaw_notify (G_OBJECT (item));
gimp_item_end_transform (item, push_undo);
if (push_undo)
gimp_image_undo_group_end (image);
}
/**
* 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
* @interpolation:
* @progress:
*
* Scales item dimensions and offsets by uniform width and
* height factors.
*
* 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
* dimension; returns #TRUE otherwise.
*
* Use gimp_item_scale() in circumstances where new item width
* and height dimensions are predetermined instead.
*
* Side effects: Undo set created for item. Old item imagery
* scaled & painted to new item tiles.
*
* 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,
GimpInterpolationType interpolation,
GimpProgress *progress)
{
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)
{
GimpItemPrivate *private;
GimpContainer *children;
gint new_width, new_height;
gint new_offset_x, new_offset_y;
g_return_val_if_fail (GIMP_IS_ITEM (item), FALSE);
g_return_val_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress), FALSE);
private = GET_PRIVATE (item);
if (w_factor <= 0.0 || h_factor <= 0.0)
{
g_warning ("%s: requested width or height scale is non-positive",
G_STRFUNC);
return FALSE;
}
children = gimp_viewable_get_children (GIMP_VIEWABLE (item));
/* avoid discarding empty layer groups */
if (children && gimp_container_is_empty (children))
return TRUE;
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;
if (new_width > 0 && new_height > 0)
{
gimp_item_scale (item,
new_width, new_height,
new_offset_x, new_offset_y,
interpolation, progress);
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
* @interpolation:
* @progress:
* @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
* #TRUE, the fixed point of the scaling transform coincides
* with the item's center point. Otherwise, the fixed
* point is taken to be [-GimpItem::offset_x, -GimpItem::->offset_y].
*
* 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
* dimensions approach pixel dimensions. Use
* 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.
* Old item imagery scaled
* & painted to new item tiles
**/
void
gimp_item_scale_by_origin (GimpItem *item,
gint new_width,
gint new_height,
GimpInterpolationType interpolation,
GimpProgress *progress,
gboolean local_origin)
{
GimpItemPrivate *private;
gint new_offset_x, new_offset_y;
g_return_if_fail (GIMP_IS_ITEM (item));
g_return_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress));
private = GET_PRIVATE (item);
if (new_width == 0 || new_height == 0)
{
g_warning ("%s: requested width or height equals zero", G_STRFUNC);
return;
}
if (local_origin)
{
new_offset_x = (private->offset_x +
((gimp_item_get_width (item) - new_width) / 2.0));
new_offset_y = (private->offset_y +
((gimp_item_get_height (item) - new_height) / 2.0));
}
else
{
new_offset_x = (gint) (((gdouble) new_width *
(gdouble) private->offset_x /
(gdouble) gimp_item_get_width (item)));
new_offset_y = (gint) (((gdouble) new_height *
(gdouble) private->offset_y /
(gdouble) gimp_item_get_height (item)));
}
gimp_item_scale (item,
new_width, new_height,
new_offset_x, new_offset_y,
interpolation, progress);
}
void
gimp_item_resize (GimpItem *item,
GimpContext *context,
GimpFillType fill_type,
gint new_width,
gint new_height,
gint offset_x,
gint offset_y)
{
GimpItemClass *item_class;
GimpImage *image;
gboolean push_undo;
g_return_if_fail (GIMP_IS_ITEM (item));
g_return_if_fail (GIMP_IS_CONTEXT (context));
if (new_width < 1 || new_height < 1)
return;
item_class = GIMP_ITEM_GET_CLASS (item);
image = gimp_item_get_image (item);
push_undo = gimp_item_is_attached (item);
if (push_undo)
gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_ITEM_RESIZE,
item_class->resize_desc);
/* 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.
*/
gimp_item_start_move (item, push_undo);
g_object_freeze_notify (G_OBJECT (item));
item_class->resize (item, context, fill_type,
new_width, new_height, offset_x, offset_y);
g_object_thaw_notify (G_OBJECT (item));
gimp_item_end_move (item, push_undo);
if (push_undo)
gimp_image_undo_group_end (image);
}
void
gimp_item_flip (GimpItem *item,
GimpContext *context,
GimpOrientationType flip_type,
gdouble axis,
gboolean clip_result)
{
GimpItemClass *item_class;
GimpImage *image;
gboolean push_undo;
g_return_if_fail (GIMP_IS_ITEM (item));
g_return_if_fail (gimp_item_is_attached (item));
g_return_if_fail (GIMP_IS_CONTEXT (context));
item_class = GIMP_ITEM_GET_CLASS (item);
image = gimp_item_get_image (item);
push_undo = gimp_item_is_attached (item);
if (push_undo)
gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_TRANSFORM,
item_class->flip_desc);
gimp_item_start_transform (item, push_undo);
g_object_freeze_notify (G_OBJECT (item));
item_class->flip (item, context, flip_type, axis, clip_result);
g_object_thaw_notify (G_OBJECT (item));
gimp_item_end_transform (item, push_undo);
if (push_undo)
gimp_image_undo_group_end (image);
}
void
gimp_item_rotate (GimpItem *item,
GimpContext *context,
GimpRotationType rotate_type,
gdouble center_x,
gdouble center_y,
gboolean clip_result)
{
GimpItemClass *item_class;
GimpImage *image;
gboolean push_undo;
g_return_if_fail (GIMP_IS_ITEM (item));
g_return_if_fail (gimp_item_is_attached (item));
g_return_if_fail (GIMP_IS_CONTEXT (context));
item_class = GIMP_ITEM_GET_CLASS (item);
image = gimp_item_get_image (item);
push_undo = gimp_item_is_attached (item);
if (push_undo)
gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_TRANSFORM,
item_class->rotate_desc);
gimp_item_start_transform (item, push_undo);
g_object_freeze_notify (G_OBJECT (item));
item_class->rotate (item, context, rotate_type, center_x, center_y,
clip_result);
g_object_thaw_notify (G_OBJECT (item));
gimp_item_end_transform (item, push_undo);
if (push_undo)
gimp_image_undo_group_end (image);
}
void
gimp_item_transform (GimpItem *item,
GimpContext *context,
const GimpMatrix3 *matrix,
GimpTransformDirection direction,
GimpInterpolationType interpolation,
GimpTransformResize clip_result,
GimpProgress *progress)
{
GimpItemClass *item_class;
GimpImage *image;
gboolean push_undo;
g_return_if_fail (GIMP_IS_ITEM (item));
g_return_if_fail (gimp_item_is_attached (item));
g_return_if_fail (GIMP_IS_CONTEXT (context));
g_return_if_fail (matrix != NULL);
g_return_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress));
item_class = GIMP_ITEM_GET_CLASS (item);
image = gimp_item_get_image (item);
push_undo = gimp_item_is_attached (item);
if (push_undo)
gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_TRANSFORM,
item_class->transform_desc);
gimp_item_start_transform (item, push_undo);
g_object_freeze_notify (G_OBJECT (item));
item_class->transform (item, context, matrix, direction, interpolation,
clip_result, progress);
g_object_thaw_notify (G_OBJECT (item));
gimp_item_end_transform (item, push_undo);
if (push_undo)
gimp_image_undo_group_end (image);
}
GimpTransformResize
gimp_item_get_clip (GimpItem *item,
GimpTransformResize clip_result)
{
g_return_val_if_fail (GIMP_IS_ITEM (item), GIMP_TRANSFORM_RESIZE_ADJUST);
return GIMP_ITEM_GET_CLASS (item)->get_clip (item, clip_result);
}
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;
}
gboolean
gimp_item_stroke (GimpItem *item,
GimpDrawable *drawable,
GimpContext *context,
GimpStrokeOptions *stroke_options,
GimpPaintOptions *paint_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_CONTEXT (context), FALSE);
g_return_val_if_fail (GIMP_IS_STROKE_OPTIONS (stroke_options), FALSE);
g_return_val_if_fail (paint_options == NULL ||
GIMP_IS_PAINT_OPTIONS (paint_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->stroke)
{
GimpImage *image = gimp_item_get_image (item);
gimp_stroke_options_prepare (stroke_options, context, paint_options);
if (push_undo)
gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_PAINT,
item_class->stroke_desc);
retval = item_class->stroke (item, drawable, stroke_options, push_undo,
progress, error);
if (push_undo)
gimp_image_undo_group_end (image);
gimp_stroke_options_finish (stroke_options);
}
return retval;
}
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);
}
void
gimp_item_add_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);
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);
private->offset_nodes = g_list_remove (private->offset_nodes, node);
g_object_unref (node);
}
gint
gimp_item_get_ID (GimpItem *item)
{
g_return_val_if_fail (GIMP_IS_ITEM (item), -1);
return GET_PRIVATE (item)->ID;
}
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;
return (GimpItem *) gimp_id_table_lookup (gimp->item_table, item_id);
}
GimpTattoo
gimp_item_get_tattoo (GimpItem *item)
{
g_return_val_if_fail (GIMP_IS_ITEM (item), 0);
return GET_PRIVATE (item)->tattoo;
}
void
gimp_item_set_tattoo (GimpItem *item,
GimpTattoo tattoo)
{
g_return_if_fail (GIMP_IS_ITEM (item));
GET_PRIVATE (item)->tattoo = tattoo;
}
GimpImage *
gimp_item_get_image (GimpItem *item)
{
g_return_val_if_fail (GIMP_IS_ITEM (item), NULL);
return GET_PRIVATE (item)->image;
}
void
gimp_item_set_image (GimpItem *item,
GimpImage *image)
{
GimpItemPrivate *private;
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_IMAGE (image));
private = GET_PRIVATE (item);
if (image == private->image)
return;
g_object_freeze_notify (G_OBJECT (item));
if (private->ID == 0)
{
private->ID = gimp_id_table_insert (image->gimp->item_table, item);
g_object_notify (G_OBJECT (item), "id");
}
if (private->tattoo == 0 || private->image != image)
{
private->tattoo = gimp_image_get_new_tattoo (image);
}
private->image = image;
g_object_notify (G_OBJECT (item), "image");
g_object_thaw_notify (G_OBJECT (item));
}
/**
* 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)
{
GimpItemPrivate *private;
gint offset_x;
gint offset_y;
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));
private = GET_PRIVATE (item);
gimp_object_set_name (GIMP_OBJECT (item), gimp_object_get_name (replace));
if (private->ID)
gimp_id_table_remove (gimp_item_get_image (item)->gimp->item_table,
gimp_item_get_ID (item));
private->ID = gimp_item_get_ID (replace);
gimp_id_table_replace (gimp_item_get_image (item)->gimp->item_table,
gimp_item_get_ID (item),
item);
/* Set image before tattoo so that the explicitly set tattoo overrides
* the one implicitly set when setting the image
*/
gimp_item_set_image (item, gimp_item_get_image (replace));
GET_PRIVATE (replace)->image = NULL;
gimp_item_set_tattoo (item, gimp_item_get_tattoo (replace));
gimp_item_set_tattoo (replace, 0);
g_object_unref (private->parasites);
private->parasites = GET_PRIVATE (replace)->parasites;
GET_PRIVATE (replace)->parasites = NULL;
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));
gimp_item_set_visible (item, gimp_item_get_visible (replace), FALSE);
gimp_item_set_linked (item, gimp_item_get_linked (replace), FALSE);
gimp_item_set_color_tag (item, gimp_item_get_color_tag (replace), FALSE);
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);
}
/**
* 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);
g_set_object (&private->parasites, parasites);
}
/**
* 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 *
gimp_item_get_parasites (GimpItem *item)
{
g_return_val_if_fail (GIMP_IS_ITEM (item), NULL);
return GET_PRIVATE (item)->parasites;
}
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;
}
void
gimp_item_parasite_attach (GimpItem *item,
const GimpParasite *parasite,
gboolean push_undo)
{
GimpItemPrivate *private;
GimpParasite copy;
g_return_if_fail (GIMP_IS_ITEM (item));
g_return_if_fail (parasite != NULL);
private = GET_PRIVATE (item);
/* make a temporary copy of the GimpParasite struct because
* gimp_parasite_shift_parent() changes it
*/
copy = *parasite;
if (! gimp_item_is_attached (item))
push_undo = FALSE;
if (push_undo)
{
/* 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
*/
if (gimp_parasite_is_undoable (&copy))
{
/* do a group in case we have attach_parent set */
gimp_image_undo_group_start (private->image,
GIMP_UNDO_GROUP_PARASITE_ATTACH,
C_("undo-type", "Attach Parasite"));
gimp_image_undo_push_item_parasite (private->image, NULL, item, &copy);
}
else if (gimp_parasite_is_persistent (&copy) &&
! gimp_parasite_compare (&copy,
gimp_item_parasite_find
(item, gimp_parasite_name (&copy))))
{
gimp_image_undo_push_cantundo (private->image,
C_("undo-type", "Attach Parasite to Item"));
}
}
gimp_parasite_list_add (private->parasites, &copy);
if (gimp_parasite_has_flag (&copy, GIMP_PARASITE_ATTACH_PARENT))
{
gimp_parasite_shift_parent (&copy);
gimp_image_parasite_attach (private->image, &copy, TRUE);
}
else if (gimp_parasite_has_flag (&copy, GIMP_PARASITE_ATTACH_GRANDPARENT))
{
gimp_parasite_shift_parent (&copy);
gimp_parasite_shift_parent (&copy);
gimp_parasite_attach (private->image->gimp, &copy);
}
if (gimp_item_is_attached (item) &&
gimp_parasite_is_undoable (&copy))
{
gimp_image_undo_group_end (private->image);
}
}
void
gimp_item_parasite_detach (GimpItem *item,
const gchar *name,
gboolean push_undo)
{
GimpItemPrivate *private;
const GimpParasite *parasite;
g_return_if_fail (GIMP_IS_ITEM (item));
g_return_if_fail (name != NULL);
private = GET_PRIVATE (item);
parasite = gimp_parasite_list_find (private->parasites, name);
if (! parasite)
return;
if (! gimp_item_is_attached (item))
push_undo = FALSE;
if (push_undo)
{
if (gimp_parasite_is_undoable (parasite))
{
gimp_image_undo_push_item_parasite_remove (private->image,
C_("undo-type", "Remove Parasite from Item"),
item,
gimp_parasite_name (parasite));
}
else if (gimp_parasite_is_persistent (parasite))
{
gimp_image_undo_push_cantundo (private->image,
C_("undo-type", "Remove Parasite from Item"));
}
}
gimp_parasite_list_remove (private->parasites, name);
}
const GimpParasite *
gimp_item_parasite_find (GimpItem *item,
const gchar *name)
{
g_return_val_if_fail (GIMP_IS_ITEM (item), NULL);
return gimp_parasite_list_find (GET_PRIVATE (item)->parasites, name);
}
static void
gimp_item_parasite_list_foreach_func (gchar *name,
GimpParasite *parasite,
gchar ***cur)
{
*(*cur)++ = (gchar *) g_strdup (name);
}
gchar **
gimp_item_parasite_list (GimpItem *item,
gint *count)
{
GimpItemPrivate *private;
gchar **list;
gchar **cur;
g_return_val_if_fail (GIMP_IS_ITEM (item), NULL);
g_return_val_if_fail (count != NULL, NULL);
private = GET_PRIVATE (item);
*count = gimp_parasite_list_length (private->parasites);
cur = list = g_new (gchar *, *count);
gimp_parasite_list_foreach (private->parasites,
(GHFunc) gimp_item_parasite_list_foreach_func,
&cur);
return list;
}
void
gimp_item_set_visible (GimpItem *item,
gboolean visible,
gboolean push_undo)
{
g_return_if_fail (GIMP_IS_ITEM (item));
visible = visible ? TRUE : FALSE;
if (gimp_item_get_visible (item) != visible)
{
if (push_undo && gimp_item_is_attached (item))
{
GimpImage *image = gimp_item_get_image (item);
if (image)
gimp_image_undo_push_item_visibility (image, NULL, item);
}
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");
}
}
gboolean
gimp_item_get_visible (GimpItem *item)
{
g_return_val_if_fail (GIMP_IS_ITEM (item), FALSE);
return GET_PRIVATE (item)->visible;
}
gboolean
gimp_item_is_visible (GimpItem *item)
{
g_return_val_if_fail (GIMP_IS_ITEM (item), FALSE);
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));
}
void
gimp_item_set_linked (GimpItem *item,
gboolean linked,
gboolean push_undo)
{
g_return_if_fail (GIMP_IS_ITEM (item));
linked = linked ? TRUE : FALSE;
if (gimp_item_get_linked (item) != linked)
{
GimpImage *image = gimp_item_get_image (item);
gboolean is_attached = gimp_item_is_attached (item);
if (push_undo && is_attached && image)
gimp_image_undo_push_item_linked (image, NULL, item);
GET_PRIVATE (item)->linked = linked;
g_signal_emit (item, gimp_item_signals[LINKED_CHANGED], 0);
if (is_attached && image)
gimp_image_linked_items_changed (image);
g_object_notify (G_OBJECT (item), "linked");
}
}
gboolean
gimp_item_get_linked (GimpItem *item)
{
g_return_val_if_fail (GIMP_IS_ITEM (item), FALSE);
return GET_PRIVATE (item)->linked;
}
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;
}
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);
}
void
gimp_item_set_lock_content (GimpItem *item,
gboolean lock_content,
gboolean push_undo)
{
g_return_if_fail (GIMP_IS_ITEM (item));
g_return_if_fail (gimp_item_can_lock_content (item));
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
}
GET_PRIVATE (item)->lock_content = lock_content;
g_signal_emit (item, gimp_item_signals[LOCK_CONTENT_CHANGED], 0);
g_object_notify (G_OBJECT (item), "lock-content");
}
}
gboolean
gimp_item_get_lock_content (GimpItem *item)
{
g_return_val_if_fail (GIMP_IS_ITEM (item), FALSE);
return GET_PRIVATE (item)->lock_content;
}
gboolean
gimp_item_can_lock_content (GimpItem *item)
{
g_return_val_if_fail (GIMP_IS_ITEM (item), FALSE);
return TRUE;
}
gboolean
gimp_item_is_content_locked (GimpItem *item)
{
g_return_val_if_fail (GIMP_IS_ITEM (item), FALSE);
return GIMP_ITEM_GET_CLASS (item)->is_content_locked (item);
}
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
gimp_item_get_lock_position (GimpItem *item)
{
g_return_val_if_fail (GIMP_IS_ITEM (item), FALSE);
return GET_PRIVATE (item)->lock_position;
}
gboolean
gimp_item_can_lock_position (GimpItem *item)
{
g_return_val_if_fail (GIMP_IS_ITEM (item), FALSE);
if (gimp_viewable_get_children (GIMP_VIEWABLE (item)))
return FALSE;
return TRUE;
}
gboolean
gimp_item_is_position_locked (GimpItem *item)
{
g_return_val_if_fail (GIMP_IS_ITEM (item), FALSE);
return GIMP_ITEM_GET_CLASS (item)->is_position_locked (item);
}
gboolean
gimp_item_mask_bounds (GimpItem *item,
gint *x1,
gint *y1,
gint *x2,
gint *y2)
{
GimpImage *image;
GimpChannel *selection;
gint x, y, width, 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);
/* 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) &&
gimp_item_bounds (GIMP_ITEM (selection), &x, &y, &width, &height))
{
gint off_x, off_y;
gint x2, y2;
gimp_item_get_offset (item, &off_x, &off_y);
x2 = x + width;
y2 = y + height;
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));
width = x2 - x;
height = y2 - y;
retval = TRUE;
}
else
{
x = 0;
y = 0;
width = gimp_item_get_width (item);
height = gimp_item_get_height (item);
retval = FALSE;
}
if (x1) *x1 = x;
if (y1) *y1 = y;
if (x2) *x2 = x + width;
if (y2) *y2 = y + height;
return retval;
}
/**
* 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.
**/
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);
/* 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) &&
gimp_item_bounds (GIMP_ITEM (selection),
&tmp_x, &tmp_y, &tmp_width, &tmp_height))
{
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;
}
gboolean
gimp_item_is_in_set (GimpItem *item,
GimpItemSet set)
{
GimpItemPrivate *private;
g_return_val_if_fail (GIMP_IS_ITEM (item), FALSE);
private = GET_PRIVATE (item);
switch (set)
{
case GIMP_ITEM_SET_NONE:
return FALSE;
case GIMP_ITEM_SET_ALL:
return TRUE;
case GIMP_ITEM_SET_IMAGE_SIZED:
return (gimp_item_get_width (item) == gimp_image_get_width (private->image) &&
gimp_item_get_height (item) == gimp_image_get_height (private->image));
case GIMP_ITEM_SET_VISIBLE:
return gimp_item_get_visible (item);
case GIMP_ITEM_SET_LINKED:
return gimp_item_get_linked (item);
}
return FALSE;
}