2006-12-10 05:33:38 +08:00
|
|
|
/* GIMP - The GNU Image Manipulation Program
|
1997-11-25 06:05:25 +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
|
1997-11-25 06:05:25 +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
|
1997-11-25 06:05:25 +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
|
2009-01-18 06:28:01 +08:00
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
1997-11-25 06:05:25 +08:00
|
|
|
*/
|
2000-12-14 21:52:16 +08:00
|
|
|
|
2000-04-28 01:27:28 +08:00
|
|
|
#include "config.h"
|
|
|
|
|
1998-09-24 09:19:57 +08:00
|
|
|
#include <stdlib.h>
|
2000-12-14 21:52:16 +08:00
|
|
|
#include <string.h>
|
2000-04-28 01:27:28 +08:00
|
|
|
|
2012-03-16 22:15:53 +08:00
|
|
|
#include <cairo.h>
|
2008-10-10 04:24:04 +08:00
|
|
|
#include <gegl.h>
|
2012-05-03 09:36:22 +08:00
|
|
|
#include <gdk-pixbuf/gdk-pixbuf.h>
|
2001-08-14 22:53:55 +08:00
|
|
|
|
2006-08-29 22:46:32 +08:00
|
|
|
#include "libgimpbase/gimpbase.h"
|
2012-03-16 22:15:53 +08:00
|
|
|
#include "libgimpcolor/gimpcolor.h"
|
2015-08-16 21:47:43 +08:00
|
|
|
#include "libgimpconfig/gimpconfig.h"
|
2001-01-24 07:56:18 +08:00
|
|
|
#include "libgimpmath/gimpmath.h"
|
|
|
|
|
2001-05-10 06:34:59 +08:00
|
|
|
#include "core-types.h"
|
2000-12-29 23:22:01 +08:00
|
|
|
|
2017-02-14 05:12:39 +08:00
|
|
|
#include "operations/layer-modes/gimp-layer-modes.h"
|
|
|
|
|
2015-10-21 05:53:47 +08:00
|
|
|
#include "gegl/gimp-babl.h"
|
2012-10-22 22:03:40 +08:00
|
|
|
#include "gegl/gimp-gegl-apply-operation.h"
|
2015-08-16 22:00:32 +08:00
|
|
|
#include "gegl/gimp-gegl-loops.h"
|
2012-03-16 19:49:34 +08:00
|
|
|
#include "gegl/gimp-gegl-nodes.h"
|
2008-10-10 04:44:23 +08:00
|
|
|
|
2012-03-19 21:22:41 +08:00
|
|
|
#include "gimpboundary.h"
|
2010-07-21 05:09:19 +08:00
|
|
|
#include "gimpchannel-select.h"
|
2004-04-15 07:37:34 +08:00
|
|
|
#include "gimpcontext.h"
|
2001-11-01 05:18:57 +08:00
|
|
|
#include "gimpcontainer.h"
|
2016-05-19 23:38:55 +08:00
|
|
|
#include "gimpdrawable-floating-selection.h"
|
2008-11-12 18:56:06 +08:00
|
|
|
#include "gimperror.h"
|
Bug 51112 - Support layer masks on layer groups
Add layer-mask support for group layers. Group-layer masks work
similarly to ordinary-layer masks, with the following
considerations:
The group's mask size is the same as group's size (i.e., the
bounding box of its children) at all times. When the group's size
changes, the mask is cropped to the new size -- areas of the mask
that fall outside of the new bounds are discarded and their data is
lost (sans undo), and newly added areas are filled with black (and
hence are transparent by default).
The new gimp_group_layer_{suspend,resume}_mask() functions can be
used to modify this behavior. Between the outermost pair of
suspend/resume calls, the old mask data is remembered, and is used
to fill the newly added areas while cropping the mask when the
group is resized. We override GimpItem::{start,end}_move() for
GimpLayer, to call these functions (suspend() in start_move(), and
resume() in end_move()) for each of the layer's ancestors.
As a result, while moving a layer, or a set of layers, atomically,
such as while dragging with the move tool, or moving linked layers,
the ancestors' mask data is not lost, and is only discarded at the
end of the operation.
This commit also takes care of properly handling undo for group-
layer mask crops, properly invalidating the image when the group
layer's mask is shown, and enabling the mask actions for group
layers (obviously :).
2018-02-06 00:19:18 +08:00
|
|
|
#include "gimpgrouplayer.h"
|
2003-02-14 22:14:29 +08:00
|
|
|
#include "gimpimage-undo-push.h"
|
2004-04-15 07:37:34 +08:00
|
|
|
#include "gimpimage-undo.h"
|
|
|
|
#include "gimpimage.h"
|
2015-10-21 05:53:47 +08:00
|
|
|
#include "gimpimage-color-profile.h"
|
2016-05-20 22:46:26 +08:00
|
|
|
#include "gimplayer-floating-selection.h"
|
2004-04-15 07:37:34 +08:00
|
|
|
#include "gimplayer.h"
|
2001-01-29 00:44:22 +08:00
|
|
|
#include "gimplayermask.h"
|
2001-11-23 07:46:13 +08:00
|
|
|
#include "gimpmarshal.h"
|
app: use GimpObjectQueue in lots of places
Use GimpObjectQueue, added in the previous commit, in various
instances where we perform an action on a set of objects. This
improves progress reporting, by using a single progress for the
entire operation, rather than reporting the progress of each object
individually, and by taking the relative cost of each object into
account, instead of assuming a uniform cost for all objects.
In particular, this affects the various whole-image operations
(i.e., transformations and color conversions), operations on linked
items, and operations on layer groups. This also affects layers
with masks, whose progress is now reported together instead of
individually.
Additionally, this commit fixes erroneous group-layer mask cropping
during undo when resizing the image, by properly calling
{start,end}_move() on all the resized layers before starting the
operation, and when scaling the image, by only scaling top-level
layers, and letting group layers scale their children themselves.
2018-03-25 22:18:46 +08:00
|
|
|
#include "gimpobjectqueue.h"
|
2005-07-12 03:21:52 +08:00
|
|
|
#include "gimppickable.h"
|
app: use GimpObjectQueue in lots of places
Use GimpObjectQueue, added in the previous commit, in various
instances where we perform an action on a set of objects. This
improves progress reporting, by using a single progress for the
entire operation, rather than reporting the progress of each object
individually, and by taking the relative cost of each object into
account, instead of assuming a uniform cost for all objects.
In particular, this affects the various whole-image operations
(i.e., transformations and color conversions), operations on linked
items, and operations on layer groups. This also affects layers
with masks, whose progress is now reported together instead of
individually.
Additionally, this commit fixes erroneous group-layer mask cropping
during undo when resizing the image, by properly calling
{start,end}_move() on all the resized layers before starting the
operation, and when scaling the image, by only scaling top-level
layers, and letting group layers scale their children themselves.
2018-03-25 22:18:46 +08:00
|
|
|
#include "gimpprogress.h"
|
2001-07-10 03:48:30 +08:00
|
|
|
|
2003-03-26 00:38:19 +08:00
|
|
|
#include "gimp-intl.h"
|
2000-04-28 01:27:28 +08:00
|
|
|
|
|
|
|
|
2001-03-05 04:06:48 +08:00
|
|
|
enum
|
|
|
|
{
|
2001-03-12 01:24:47 +08:00
|
|
|
OPACITY_CHANGED,
|
|
|
|
MODE_CHANGED,
|
2017-02-13 06:49:26 +08:00
|
|
|
BLEND_SPACE_CHANGED,
|
|
|
|
COMPOSITE_SPACE_CHANGED,
|
|
|
|
COMPOSITE_MODE_CHANGED,
|
2017-12-07 02:10:38 +08:00
|
|
|
EFFECTIVE_MODE_CHANGED,
|
2017-05-08 06:49:38 +08:00
|
|
|
EXCLUDES_BACKDROP_CHANGED,
|
2005-07-11 05:17:22 +08:00
|
|
|
LOCK_ALPHA_CHANGED,
|
2001-03-05 04:06:48 +08:00
|
|
|
MASK_CHANGED,
|
2012-03-18 01:30:13 +08:00
|
|
|
APPLY_MASK_CHANGED,
|
|
|
|
EDIT_MASK_CHANGED,
|
|
|
|
SHOW_MASK_CHANGED,
|
2001-03-05 04:06:48 +08:00
|
|
|
LAST_SIGNAL
|
|
|
|
};
|
|
|
|
|
2005-07-12 00:46:28 +08:00
|
|
|
enum
|
|
|
|
{
|
|
|
|
PROP_0,
|
|
|
|
PROP_OPACITY,
|
|
|
|
PROP_MODE,
|
2017-02-13 06:49:26 +08:00
|
|
|
PROP_BLEND_SPACE,
|
|
|
|
PROP_COMPOSITE_SPACE,
|
|
|
|
PROP_COMPOSITE_MODE,
|
2017-05-08 06:49:38 +08:00
|
|
|
PROP_EXCLUDES_BACKDROP,
|
2008-11-17 08:02:15 +08:00
|
|
|
PROP_LOCK_ALPHA,
|
2008-11-20 07:37:15 +08:00
|
|
|
PROP_MASK,
|
2008-11-17 08:02:15 +08:00
|
|
|
PROP_FLOATING_SELECTION
|
2005-07-12 00:46:28 +08:00
|
|
|
};
|
|
|
|
|
2001-03-05 04:06:48 +08:00
|
|
|
|
2015-09-03 06:19:05 +08:00
|
|
|
static void gimp_color_managed_iface_init (GimpColorManagedInterface *iface);
|
|
|
|
static void gimp_pickable_iface_init (GimpPickableInterface *iface);
|
2001-08-11 22:39:19 +08:00
|
|
|
|
2005-07-12 00:46:28 +08:00
|
|
|
static void gimp_layer_set_property (GObject *object,
|
|
|
|
guint property_id,
|
|
|
|
const GValue *value,
|
|
|
|
GParamSpec *pspec);
|
|
|
|
static void gimp_layer_get_property (GObject *object,
|
|
|
|
guint property_id,
|
|
|
|
GValue *value,
|
|
|
|
GParamSpec *pspec);
|
To optimize duplicate and/or wrong image updates away, introduced new
2003-09-06 Michael Natterer <mitch@gimp.org>
To optimize duplicate and/or wrong image updates away, introduced
new policy that a child object must never explicitly update or
invalidate its parent object (just like the GUI is not updated
explicitly by the core):
* app/core/gimpdrawable.[ch]: added new signal
GimpDrawable::update(). Never update or invalidate the image when
the drawable is updated or invalidated.
(gimp_drawable_set_visible): don't gimp_drawable_update() the
drawable since its pixels have not changed.
* app/core/gimpimage.[ch]: connect to the "add" and "remove"
signals of the layers and channels containers. Also connect to the
"update" and "visibility_changed" signals of all drawables in
these containers (optimizes away updates issued by drawables which
are not yet added to the image and updates of the selection
mask). Also, don't propagate updates to the image if the emitting
drawable is invisible (optimizes away updates issued by invisible
drawables).
(gimp_image_add_layer,channel)
(gimp_image_remove_layer,channel): don't update the image since
that's done by our "add" and "remove" handlers now.
(gimp_image_position_layer,channel): update just the image, not
the drawable since its pixels have not changed.
(gimp_image_real_colormap_changed)
(gimp_image_set_component_visible): always call
gimp_image_update() *and* gimp_viewable_invalidate_preview() to
get everything updated, since update and invalidate of images are
not connected.
* app/core/gimpimage-undo-push.c (undo_pop_layer,channel): don't
update the drawable since (a) its pixels don't change and (b) the
image updates itself upon adding/removing now.
(undo_pop_layer_mod): replaced gimp_image_update() by
gimp_drawable_update() (just for consistency with other similar
functions).
* app/core/gimplayer.c: connect to "update" of the layer mask and
issue updates on the layer if the mask update has any effect on
the projection.
(gimp_layer_create_mask): don't set the mask's offsets here since
they may be different when we later add the mask to the layer.
* app/core/gimplayermask.c (gimp_layer_mask_set_layer): set the
mask offsets here instead.
* app/core/gimpchannel.c (gimp_channel_translate): update the
channel even if push_undo == FALSE.
* app/paint/gimppaintcore.c (gimp_paint_core_finish)
* app/tools/gimpinktool.c (ink_finish): invalidate both the
drawable and the image preview since invalidating the drawable
doesn't invalidate the image any more.
* app/text/gimptextlayer.c (gimp_text_layer_render_now): also
update the new extents of the text layer, not only the old one.
(gimp_text_layer_render_layout): don't update the drawable since
gimp_drawable_fill() already updated it.
2003-09-07 04:06:53 +08:00
|
|
|
static void gimp_layer_dispose (GObject *object);
|
2003-02-11 21:52:47 +08:00
|
|
|
static void gimp_layer_finalize (GObject *object);
|
2012-11-12 17:55:41 +08:00
|
|
|
static void gimp_layer_notify (GObject *object,
|
|
|
|
GParamSpec *pspec);
|
2001-08-11 22:39:19 +08:00
|
|
|
|
2004-02-02 04:38:26 +08:00
|
|
|
static void gimp_layer_name_changed (GimpObject *object);
|
2003-11-17 01:51:36 +08:00
|
|
|
static gint64 gimp_layer_get_memsize (GimpObject *object,
|
|
|
|
gint64 *gui_size);
|
1998-01-22 15:02:57 +08:00
|
|
|
|
2003-02-11 21:52:47 +08:00
|
|
|
static void gimp_layer_invalidate_preview (GimpViewable *viewable);
|
2004-09-22 20:46:35 +08:00
|
|
|
static gchar * gimp_layer_get_description (GimpViewable *viewable,
|
|
|
|
gchar **tooltip);
|
2002-01-31 00:14:26 +08:00
|
|
|
|
2013-04-11 08:54:42 +08:00
|
|
|
static GeglNode * gimp_layer_get_node (GimpFilter *filter);
|
|
|
|
|
2004-02-17 19:45:46 +08:00
|
|
|
static void gimp_layer_removed (GimpItem *item);
|
2011-02-03 02:40:20 +08:00
|
|
|
static void gimp_layer_unset_removed (GimpItem *item);
|
2016-05-20 05:51:44 +08:00
|
|
|
static gboolean gimp_layer_is_attached (GimpItem *item);
|
2010-02-06 23:17:23 +08:00
|
|
|
static GimpItemTree * gimp_layer_get_tree (GimpItem *item);
|
2003-02-11 21:52:47 +08:00
|
|
|
static GimpItem * gimp_layer_duplicate (GimpItem *item,
|
2008-01-08 19:46:15 +08:00
|
|
|
GType new_type);
|
2005-01-14 02:17:24 +08:00
|
|
|
static void gimp_layer_convert (GimpItem *item,
|
2015-08-16 21:47:43 +08:00
|
|
|
GimpImage *dest_image,
|
|
|
|
GType old_type);
|
2004-02-02 04:38:26 +08:00
|
|
|
static gboolean gimp_layer_rename (GimpItem *item,
|
2003-03-17 08:14:59 +08:00
|
|
|
const gchar *new_name,
|
2007-12-12 21:57:11 +08:00
|
|
|
const gchar *undo_desc,
|
|
|
|
GError **error);
|
Bug 51112 - Support layer masks on layer groups
Add layer-mask support for group layers. Group-layer masks work
similarly to ordinary-layer masks, with the following
considerations:
The group's mask size is the same as group's size (i.e., the
bounding box of its children) at all times. When the group's size
changes, the mask is cropped to the new size -- areas of the mask
that fall outside of the new bounds are discarded and their data is
lost (sans undo), and newly added areas are filled with black (and
hence are transparent by default).
The new gimp_group_layer_{suspend,resume}_mask() functions can be
used to modify this behavior. Between the outermost pair of
suspend/resume calls, the old mask data is remembered, and is used
to fill the newly added areas while cropping the mask when the
group is resized. We override GimpItem::{start,end}_move() for
GimpLayer, to call these functions (suspend() in start_move(), and
resume() in end_move()) for each of the layer's ancestors.
As a result, while moving a layer, or a set of layers, atomically,
such as while dragging with the move tool, or moving linked layers,
the ancestors' mask data is not lost, and is only discarded at the
end of the operation.
This commit also takes care of properly handling undo for group-
layer mask crops, properly invalidating the image when the group
layer's mask is shown, and enabling the mask actions for group
layers (obviously :).
2018-02-06 00:19:18 +08:00
|
|
|
static void gimp_layer_start_move (GimpItem *item,
|
|
|
|
gboolean push_undo);
|
|
|
|
static void gimp_layer_end_move (GimpItem *item,
|
|
|
|
gboolean push_undo);
|
2003-05-09 03:11:17 +08:00
|
|
|
static void gimp_layer_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-07 19:09:00 +08:00
|
|
|
static void gimp_layer_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 interp_type,
|
2004-08-11 02:47:21 +08:00
|
|
|
GimpProgress *progress);
|
2003-05-07 21:01:17 +08:00
|
|
|
static void gimp_layer_resize (GimpItem *item,
|
2004-04-15 07:37:34 +08:00
|
|
|
GimpContext *context,
|
2016-10-10 06:02:16 +08:00
|
|
|
GimpFillType fill_type,
|
2003-05-07 21:01:17 +08:00
|
|
|
gint new_width,
|
|
|
|
gint new_height,
|
|
|
|
gint offset_x,
|
|
|
|
gint offset_y);
|
2003-05-12 23:56:36 +08:00
|
|
|
static void gimp_layer_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-20 18:36:29 +08:00
|
|
|
static void gimp_layer_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);
|
2003-05-12 23:56:36 +08:00
|
|
|
static void gimp_layer_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,
|
|
|
|
GimpInterpolationType interpolation_type,
|
2010-07-21 05:09:19 +08:00
|
|
|
GimpTransformResize clip_result,
|
2004-08-11 02:47:21 +08:00
|
|
|
GimpProgress *progress);
|
2010-07-21 05:09:19 +08:00
|
|
|
static void gimp_layer_to_selection (GimpItem *item,
|
|
|
|
GimpChannelOps op,
|
|
|
|
gboolean antialias,
|
|
|
|
gboolean feather,
|
|
|
|
gdouble feather_radius_x,
|
|
|
|
gdouble feather_radius_y);
|
2007-12-04 19:30:31 +08:00
|
|
|
|
2015-09-22 02:20:02 +08:00
|
|
|
static void gimp_layer_alpha_changed (GimpDrawable *drawable);
|
2016-05-20 05:51:44 +08:00
|
|
|
static gint64 gimp_layer_estimate_memsize (GimpDrawable *drawable,
|
2014-06-15 05:12:22 +08:00
|
|
|
GimpComponentType component_type,
|
2007-12-04 19:30:31 +08:00
|
|
|
gint width,
|
|
|
|
gint height);
|
2015-09-22 02:20:02 +08:00
|
|
|
static void gimp_layer_convert_type (GimpDrawable *drawable,
|
2012-04-25 22:10:27 +08:00
|
|
|
GimpImage *dest_image,
|
2012-10-14 04:56:32 +08:00
|
|
|
const Babl *new_format,
|
2016-04-29 06:42:42 +08:00
|
|
|
GimpColorProfile *dest_profile,
|
2016-11-08 03:41:39 +08:00
|
|
|
GeglDitherMethod layer_dither_type,
|
|
|
|
GeglDitherMethod mask_dither_type,
|
2015-10-22 04:22:30 +08:00
|
|
|
gboolean push_undo,
|
|
|
|
GimpProgress *progress);
|
2003-10-06 22:40:12 +08:00
|
|
|
static void gimp_layer_invalidate_boundary (GimpDrawable *drawable);
|
2016-05-20 05:51:44 +08:00
|
|
|
static void gimp_layer_get_active_components (GimpDrawable *drawable,
|
2003-10-06 22:40:12 +08:00
|
|
|
gboolean *active);
|
2012-04-26 05:23:31 +08:00
|
|
|
static GimpComponentMask
|
2016-05-20 05:51:44 +08:00
|
|
|
gimp_layer_get_active_mask (GimpDrawable *drawable);
|
2013-06-30 05:34:12 +08:00
|
|
|
static void gimp_layer_set_buffer (GimpDrawable *drawable,
|
|
|
|
gboolean push_undo,
|
|
|
|
const gchar *undo_desc,
|
|
|
|
GeglBuffer *buffer,
|
|
|
|
gint offset_x,
|
|
|
|
gint offset_y);
|
2008-10-11 03:36:17 +08:00
|
|
|
|
2015-09-03 06:19:05 +08:00
|
|
|
static GimpColorProfile *
|
|
|
|
gimp_layer_get_color_profile (GimpColorManaged *managed);
|
|
|
|
|
2012-04-21 22:05:49 +08:00
|
|
|
static gdouble gimp_layer_get_opacity_at (GimpPickable *pickable,
|
2005-07-12 03:21:52 +08:00
|
|
|
gint x,
|
|
|
|
gint y);
|
2016-05-23 05:28:31 +08:00
|
|
|
static void gimp_layer_pixel_to_srgb (GimpPickable *pickable,
|
|
|
|
const Babl *format,
|
|
|
|
gpointer pixel,
|
|
|
|
GimpRGB *color);
|
2016-05-23 07:25:35 +08:00
|
|
|
static void gimp_layer_srgb_to_pixel (GimpPickable *pickable,
|
|
|
|
const GimpRGB *color,
|
|
|
|
const Babl *format,
|
|
|
|
gpointer pixel);
|
2003-09-04 19:33:06 +08:00
|
|
|
|
2017-06-17 08:15:56 +08:00
|
|
|
static void gimp_layer_real_translate (GimpLayer *layer,
|
|
|
|
gint offset_x,
|
|
|
|
gint offset_y);
|
|
|
|
static void gimp_layer_real_scale (GimpLayer *layer,
|
|
|
|
gint new_width,
|
|
|
|
gint new_height,
|
|
|
|
gint new_offset_x,
|
|
|
|
gint new_offset_y,
|
|
|
|
GimpInterpolationType interp_type,
|
|
|
|
GimpProgress *progress);
|
|
|
|
static void gimp_layer_real_resize (GimpLayer *layer,
|
|
|
|
GimpContext *context,
|
|
|
|
GimpFillType fill_type,
|
|
|
|
gint new_width,
|
|
|
|
gint new_height,
|
|
|
|
gint offset_x,
|
|
|
|
gint offset_y);
|
|
|
|
static void gimp_layer_real_flip (GimpLayer *layer,
|
|
|
|
GimpContext *context,
|
|
|
|
GimpOrientationType flip_type,
|
|
|
|
gdouble axis,
|
|
|
|
gboolean clip_result);
|
|
|
|
static void gimp_layer_real_rotate (GimpLayer *layer,
|
|
|
|
GimpContext *context,
|
|
|
|
GimpRotationType rotate_type,
|
|
|
|
gdouble center_x,
|
|
|
|
gdouble center_y,
|
|
|
|
gboolean clip_result);
|
|
|
|
static void gimp_layer_real_transform (GimpLayer *layer,
|
|
|
|
GimpContext *context,
|
|
|
|
const GimpMatrix3 *matrix,
|
|
|
|
GimpTransformDirection direction,
|
|
|
|
GimpInterpolationType interpolation_type,
|
|
|
|
GimpTransformResize clip_result,
|
|
|
|
GimpProgress *progress);
|
|
|
|
static void gimp_layer_real_convert_type (GimpLayer *layer,
|
|
|
|
GimpImage *dest_image,
|
|
|
|
const Babl *new_format,
|
|
|
|
GimpColorProfile *dest_profile,
|
|
|
|
GeglDitherMethod layer_dither_type,
|
|
|
|
GeglDitherMethod mask_dither_type,
|
|
|
|
gboolean push_undo,
|
|
|
|
GimpProgress *progress);
|
2017-12-07 02:10:38 +08:00
|
|
|
static void gimp_layer_real_get_effective_mode (GimpLayer *layer,
|
|
|
|
GimpLayerMode *mode,
|
|
|
|
GimpLayerColorSpace *blend_space,
|
|
|
|
GimpLayerColorSpace *composite_space,
|
|
|
|
GimpLayerCompositeMode *composite_mode);
|
2017-05-08 06:49:38 +08:00
|
|
|
static gboolean
|
|
|
|
gimp_layer_real_get_excludes_backdrop (GimpLayer *layer);
|
|
|
|
|
To optimize duplicate and/or wrong image updates away, introduced new
2003-09-06 Michael Natterer <mitch@gimp.org>
To optimize duplicate and/or wrong image updates away, introduced
new policy that a child object must never explicitly update or
invalidate its parent object (just like the GUI is not updated
explicitly by the core):
* app/core/gimpdrawable.[ch]: added new signal
GimpDrawable::update(). Never update or invalidate the image when
the drawable is updated or invalidated.
(gimp_drawable_set_visible): don't gimp_drawable_update() the
drawable since its pixels have not changed.
* app/core/gimpimage.[ch]: connect to the "add" and "remove"
signals of the layers and channels containers. Also connect to the
"update" and "visibility_changed" signals of all drawables in
these containers (optimizes away updates issued by drawables which
are not yet added to the image and updates of the selection
mask). Also, don't propagate updates to the image if the emitting
drawable is invisible (optimizes away updates issued by invisible
drawables).
(gimp_image_add_layer,channel)
(gimp_image_remove_layer,channel): don't update the image since
that's done by our "add" and "remove" handlers now.
(gimp_image_position_layer,channel): update just the image, not
the drawable since its pixels have not changed.
(gimp_image_real_colormap_changed)
(gimp_image_set_component_visible): always call
gimp_image_update() *and* gimp_viewable_invalidate_preview() to
get everything updated, since update and invalidate of images are
not connected.
* app/core/gimpimage-undo-push.c (undo_pop_layer,channel): don't
update the drawable since (a) its pixels don't change and (b) the
image updates itself upon adding/removing now.
(undo_pop_layer_mod): replaced gimp_image_update() by
gimp_drawable_update() (just for consistency with other similar
functions).
* app/core/gimplayer.c: connect to "update" of the layer mask and
issue updates on the layer if the mask update has any effect on
the projection.
(gimp_layer_create_mask): don't set the mask's offsets here since
they may be different when we later add the mask to the layer.
* app/core/gimplayermask.c (gimp_layer_mask_set_layer): set the
mask offsets here instead.
* app/core/gimpchannel.c (gimp_channel_translate): update the
channel even if push_undo == FALSE.
* app/paint/gimppaintcore.c (gimp_paint_core_finish)
* app/tools/gimpinktool.c (ink_finish): invalidate both the
drawable and the image preview since invalidating the drawable
doesn't invalidate the image any more.
* app/text/gimptextlayer.c (gimp_text_layer_render_now): also
update the new extents of the text layer, not only the old one.
(gimp_text_layer_render_layout): don't update the drawable since
gimp_drawable_fill() already updated it.
2003-09-07 04:06:53 +08:00
|
|
|
static void gimp_layer_layer_mask_update (GimpDrawable *layer_mask,
|
|
|
|
gint x,
|
|
|
|
gint y,
|
|
|
|
gint width,
|
|
|
|
gint height,
|
|
|
|
GimpLayer *layer);
|
|
|
|
|
2000-12-17 06:02:10 +08:00
|
|
|
|
2005-12-11 03:24:36 +08:00
|
|
|
G_DEFINE_TYPE_WITH_CODE (GimpLayer, gimp_layer, GIMP_TYPE_DRAWABLE,
|
2015-09-03 06:19:05 +08:00
|
|
|
G_IMPLEMENT_INTERFACE (GIMP_TYPE_COLOR_MANAGED,
|
|
|
|
gimp_color_managed_iface_init)
|
2005-12-11 03:24:36 +08:00
|
|
|
G_IMPLEMENT_INTERFACE (GIMP_TYPE_PICKABLE,
|
2015-09-03 06:19:05 +08:00
|
|
|
gimp_pickable_iface_init))
|
2001-03-05 04:06:48 +08:00
|
|
|
|
2005-12-11 03:24:36 +08:00
|
|
|
#define parent_class gimp_layer_parent_class
|
1998-01-22 15:02:57 +08:00
|
|
|
|
2005-12-11 03:24:36 +08:00
|
|
|
static guint layer_signals[LAST_SIGNAL] = { 0 };
|
2001-01-10 08:36:54 +08:00
|
|
|
|
1998-01-22 15:02:57 +08:00
|
|
|
|
|
|
|
static void
|
2000-12-29 00:19:55 +08:00
|
|
|
gimp_layer_class_init (GimpLayerClass *klass)
|
1998-01-22 15:02:57 +08:00
|
|
|
{
|
2004-03-17 00:23:06 +08:00
|
|
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
|
|
|
GimpObjectClass *gimp_object_class = GIMP_OBJECT_CLASS (klass);
|
|
|
|
GimpViewableClass *viewable_class = GIMP_VIEWABLE_CLASS (klass);
|
2013-04-11 08:54:42 +08:00
|
|
|
GimpFilterClass *filter_class = GIMP_FILTER_CLASS (klass);
|
2004-03-17 00:23:06 +08:00
|
|
|
GimpItemClass *item_class = GIMP_ITEM_CLASS (klass);
|
|
|
|
GimpDrawableClass *drawable_class = GIMP_DRAWABLE_CLASS (klass);
|
1998-01-22 15:02:57 +08:00
|
|
|
|
2001-03-12 01:24:47 +08:00
|
|
|
layer_signals[OPACITY_CHANGED] =
|
2005-05-27 21:05:26 +08:00
|
|
|
g_signal_new ("opacity-changed",
|
2006-04-12 20:49:29 +08:00
|
|
|
G_TYPE_FROM_CLASS (klass),
|
|
|
|
G_SIGNAL_RUN_FIRST,
|
|
|
|
G_STRUCT_OFFSET (GimpLayerClass, opacity_changed),
|
|
|
|
NULL, NULL,
|
|
|
|
gimp_marshal_VOID__VOID,
|
|
|
|
G_TYPE_NONE, 0);
|
2001-03-12 01:24:47 +08:00
|
|
|
|
|
|
|
layer_signals[MODE_CHANGED] =
|
2005-05-27 21:05:26 +08:00
|
|
|
g_signal_new ("mode-changed",
|
2006-04-12 20:49:29 +08:00
|
|
|
G_TYPE_FROM_CLASS (klass),
|
|
|
|
G_SIGNAL_RUN_FIRST,
|
|
|
|
G_STRUCT_OFFSET (GimpLayerClass, mode_changed),
|
|
|
|
NULL, NULL,
|
|
|
|
gimp_marshal_VOID__VOID,
|
|
|
|
G_TYPE_NONE, 0);
|
2001-03-12 01:24:47 +08:00
|
|
|
|
2017-02-13 06:49:26 +08:00
|
|
|
layer_signals[BLEND_SPACE_CHANGED] =
|
|
|
|
g_signal_new ("blend-space-changed",
|
2017-02-02 07:38:25 +08:00
|
|
|
G_TYPE_FROM_CLASS (klass),
|
|
|
|
G_SIGNAL_RUN_FIRST,
|
2017-02-13 06:49:26 +08:00
|
|
|
G_STRUCT_OFFSET (GimpLayerClass, blend_space_changed),
|
|
|
|
NULL, NULL,
|
|
|
|
gimp_marshal_VOID__VOID,
|
|
|
|
G_TYPE_NONE, 0);
|
|
|
|
|
|
|
|
layer_signals[COMPOSITE_SPACE_CHANGED] =
|
|
|
|
g_signal_new ("composite-space-changed",
|
|
|
|
G_TYPE_FROM_CLASS (klass),
|
|
|
|
G_SIGNAL_RUN_FIRST,
|
|
|
|
G_STRUCT_OFFSET (GimpLayerClass, composite_space_changed),
|
|
|
|
NULL, NULL,
|
|
|
|
gimp_marshal_VOID__VOID,
|
|
|
|
G_TYPE_NONE, 0);
|
|
|
|
|
|
|
|
layer_signals[COMPOSITE_MODE_CHANGED] =
|
|
|
|
g_signal_new ("composite-mode-changed",
|
|
|
|
G_TYPE_FROM_CLASS (klass),
|
|
|
|
G_SIGNAL_RUN_FIRST,
|
|
|
|
G_STRUCT_OFFSET (GimpLayerClass, composite_mode_changed),
|
2017-02-02 07:38:25 +08:00
|
|
|
NULL, NULL,
|
|
|
|
gimp_marshal_VOID__VOID,
|
|
|
|
G_TYPE_NONE, 0);
|
|
|
|
|
2017-12-07 02:10:38 +08:00
|
|
|
layer_signals[EFFECTIVE_MODE_CHANGED] =
|
|
|
|
g_signal_new ("effective-mode-changed",
|
|
|
|
G_TYPE_FROM_CLASS (klass),
|
|
|
|
G_SIGNAL_RUN_FIRST,
|
|
|
|
G_STRUCT_OFFSET (GimpLayerClass, effective_mode_changed),
|
|
|
|
NULL, NULL,
|
|
|
|
gimp_marshal_VOID__VOID,
|
|
|
|
G_TYPE_NONE, 0);
|
|
|
|
|
2017-05-08 06:49:38 +08:00
|
|
|
layer_signals[EXCLUDES_BACKDROP_CHANGED] =
|
|
|
|
g_signal_new ("excludes-backdrop-changed",
|
|
|
|
G_TYPE_FROM_CLASS (klass),
|
|
|
|
G_SIGNAL_RUN_FIRST,
|
|
|
|
G_STRUCT_OFFSET (GimpLayerClass, excludes_backdrop_changed),
|
|
|
|
NULL, NULL,
|
|
|
|
gimp_marshal_VOID__VOID,
|
|
|
|
G_TYPE_NONE, 0);
|
|
|
|
|
2005-07-11 05:17:22 +08:00
|
|
|
layer_signals[LOCK_ALPHA_CHANGED] =
|
|
|
|
g_signal_new ("lock-alpha-changed",
|
2006-04-12 20:49:29 +08:00
|
|
|
G_TYPE_FROM_CLASS (klass),
|
|
|
|
G_SIGNAL_RUN_FIRST,
|
|
|
|
G_STRUCT_OFFSET (GimpLayerClass, lock_alpha_changed),
|
|
|
|
NULL, NULL,
|
|
|
|
gimp_marshal_VOID__VOID,
|
|
|
|
G_TYPE_NONE, 0);
|
2001-03-12 01:24:47 +08:00
|
|
|
|
2001-03-05 04:06:48 +08:00
|
|
|
layer_signals[MASK_CHANGED] =
|
2005-05-27 21:05:26 +08:00
|
|
|
g_signal_new ("mask-changed",
|
2006-04-12 20:49:29 +08:00
|
|
|
G_TYPE_FROM_CLASS (klass),
|
|
|
|
G_SIGNAL_RUN_FIRST,
|
|
|
|
G_STRUCT_OFFSET (GimpLayerClass, mask_changed),
|
|
|
|
NULL, NULL,
|
|
|
|
gimp_marshal_VOID__VOID,
|
|
|
|
G_TYPE_NONE, 0);
|
2001-03-05 04:06:48 +08:00
|
|
|
|
2012-03-18 01:30:13 +08:00
|
|
|
layer_signals[APPLY_MASK_CHANGED] =
|
|
|
|
g_signal_new ("apply-mask-changed",
|
|
|
|
G_TYPE_FROM_CLASS (klass),
|
|
|
|
G_SIGNAL_RUN_FIRST,
|
|
|
|
G_STRUCT_OFFSET (GimpLayerClass, apply_mask_changed),
|
|
|
|
NULL, NULL,
|
|
|
|
gimp_marshal_VOID__VOID,
|
|
|
|
G_TYPE_NONE, 0);
|
|
|
|
|
|
|
|
layer_signals[EDIT_MASK_CHANGED] =
|
|
|
|
g_signal_new ("edit-mask-changed",
|
|
|
|
G_TYPE_FROM_CLASS (klass),
|
|
|
|
G_SIGNAL_RUN_FIRST,
|
|
|
|
G_STRUCT_OFFSET (GimpLayerClass, edit_mask_changed),
|
|
|
|
NULL, NULL,
|
|
|
|
gimp_marshal_VOID__VOID,
|
|
|
|
G_TYPE_NONE, 0);
|
|
|
|
|
|
|
|
layer_signals[SHOW_MASK_CHANGED] =
|
|
|
|
g_signal_new ("show-mask-changed",
|
|
|
|
G_TYPE_FROM_CLASS (klass),
|
|
|
|
G_SIGNAL_RUN_FIRST,
|
|
|
|
G_STRUCT_OFFSET (GimpLayerClass, show_mask_changed),
|
|
|
|
NULL, NULL,
|
|
|
|
gimp_marshal_VOID__VOID,
|
|
|
|
G_TYPE_NONE, 0);
|
|
|
|
|
2005-07-12 00:46:28 +08:00
|
|
|
object_class->set_property = gimp_layer_set_property;
|
|
|
|
object_class->get_property = gimp_layer_get_property;
|
To optimize duplicate and/or wrong image updates away, introduced new
2003-09-06 Michael Natterer <mitch@gimp.org>
To optimize duplicate and/or wrong image updates away, introduced
new policy that a child object must never explicitly update or
invalidate its parent object (just like the GUI is not updated
explicitly by the core):
* app/core/gimpdrawable.[ch]: added new signal
GimpDrawable::update(). Never update or invalidate the image when
the drawable is updated or invalidated.
(gimp_drawable_set_visible): don't gimp_drawable_update() the
drawable since its pixels have not changed.
* app/core/gimpimage.[ch]: connect to the "add" and "remove"
signals of the layers and channels containers. Also connect to the
"update" and "visibility_changed" signals of all drawables in
these containers (optimizes away updates issued by drawables which
are not yet added to the image and updates of the selection
mask). Also, don't propagate updates to the image if the emitting
drawable is invisible (optimizes away updates issued by invisible
drawables).
(gimp_image_add_layer,channel)
(gimp_image_remove_layer,channel): don't update the image since
that's done by our "add" and "remove" handlers now.
(gimp_image_position_layer,channel): update just the image, not
the drawable since its pixels have not changed.
(gimp_image_real_colormap_changed)
(gimp_image_set_component_visible): always call
gimp_image_update() *and* gimp_viewable_invalidate_preview() to
get everything updated, since update and invalidate of images are
not connected.
* app/core/gimpimage-undo-push.c (undo_pop_layer,channel): don't
update the drawable since (a) its pixels don't change and (b) the
image updates itself upon adding/removing now.
(undo_pop_layer_mod): replaced gimp_image_update() by
gimp_drawable_update() (just for consistency with other similar
functions).
* app/core/gimplayer.c: connect to "update" of the layer mask and
issue updates on the layer if the mask update has any effect on
the projection.
(gimp_layer_create_mask): don't set the mask's offsets here since
they may be different when we later add the mask to the layer.
* app/core/gimplayermask.c (gimp_layer_mask_set_layer): set the
mask offsets here instead.
* app/core/gimpchannel.c (gimp_channel_translate): update the
channel even if push_undo == FALSE.
* app/paint/gimppaintcore.c (gimp_paint_core_finish)
* app/tools/gimpinktool.c (ink_finish): invalidate both the
drawable and the image preview since invalidating the drawable
doesn't invalidate the image any more.
* app/text/gimptextlayer.c (gimp_text_layer_render_now): also
update the new extents of the text layer, not only the old one.
(gimp_text_layer_render_layout): don't update the drawable since
gimp_drawable_fill() already updated it.
2003-09-07 04:06:53 +08:00
|
|
|
object_class->dispose = gimp_layer_dispose;
|
2003-09-04 19:33:06 +08:00
|
|
|
object_class->finalize = gimp_layer_finalize;
|
2012-11-12 17:55:41 +08:00
|
|
|
object_class->notify = gimp_layer_notify;
|
2003-09-04 19:33:06 +08:00
|
|
|
|
2004-02-02 04:38:26 +08:00
|
|
|
gimp_object_class->name_changed = gimp_layer_name_changed;
|
2003-09-04 19:33:06 +08:00
|
|
|
gimp_object_class->get_memsize = gimp_layer_get_memsize;
|
|
|
|
|
2014-05-07 07:01:56 +08:00
|
|
|
viewable_class->default_icon_name = "gimp-layer";
|
2003-09-04 19:33:06 +08:00
|
|
|
viewable_class->invalidate_preview = gimp_layer_invalidate_preview;
|
2004-09-22 20:46:35 +08:00
|
|
|
viewable_class->get_description = gimp_layer_get_description;
|
2003-09-04 19:33:06 +08:00
|
|
|
|
2013-04-11 08:54:42 +08:00
|
|
|
filter_class->get_node = gimp_layer_get_node;
|
|
|
|
|
2004-02-17 19:45:46 +08:00
|
|
|
item_class->removed = gimp_layer_removed;
|
2011-02-03 02:40:20 +08:00
|
|
|
item_class->unset_removed = gimp_layer_unset_removed;
|
2004-01-27 00:18:16 +08:00
|
|
|
item_class->is_attached = gimp_layer_is_attached;
|
2010-02-06 23:17:23 +08:00
|
|
|
item_class->get_tree = gimp_layer_get_tree;
|
2003-09-04 19:33:06 +08:00
|
|
|
item_class->duplicate = gimp_layer_duplicate;
|
2005-01-14 02:17:24 +08:00
|
|
|
item_class->convert = gimp_layer_convert;
|
2003-09-04 19:33:06 +08:00
|
|
|
item_class->rename = gimp_layer_rename;
|
Bug 51112 - Support layer masks on layer groups
Add layer-mask support for group layers. Group-layer masks work
similarly to ordinary-layer masks, with the following
considerations:
The group's mask size is the same as group's size (i.e., the
bounding box of its children) at all times. When the group's size
changes, the mask is cropped to the new size -- areas of the mask
that fall outside of the new bounds are discarded and their data is
lost (sans undo), and newly added areas are filled with black (and
hence are transparent by default).
The new gimp_group_layer_{suspend,resume}_mask() functions can be
used to modify this behavior. Between the outermost pair of
suspend/resume calls, the old mask data is remembered, and is used
to fill the newly added areas while cropping the mask when the
group is resized. We override GimpItem::{start,end}_move() for
GimpLayer, to call these functions (suspend() in start_move(), and
resume() in end_move()) for each of the layer's ancestors.
As a result, while moving a layer, or a set of layers, atomically,
such as while dragging with the move tool, or moving linked layers,
the ancestors' mask data is not lost, and is only discarded at the
end of the operation.
This commit also takes care of properly handling undo for group-
layer mask crops, properly invalidating the image when the group
layer's mask is shown, and enabling the mask actions for group
layers (obviously :).
2018-02-06 00:19:18 +08:00
|
|
|
item_class->start_move = gimp_layer_start_move;
|
|
|
|
item_class->end_move = gimp_layer_end_move;
|
2003-09-04 19:33:06 +08:00
|
|
|
item_class->translate = gimp_layer_translate;
|
|
|
|
item_class->scale = gimp_layer_scale;
|
|
|
|
item_class->resize = gimp_layer_resize;
|
|
|
|
item_class->flip = gimp_layer_flip;
|
|
|
|
item_class->rotate = gimp_layer_rotate;
|
|
|
|
item_class->transform = gimp_layer_transform;
|
2010-07-21 05:09:19 +08:00
|
|
|
item_class->to_selection = gimp_layer_to_selection;
|
2003-09-04 19:33:06 +08:00
|
|
|
item_class->default_name = _("Layer");
|
2010-06-08 19:24:11 +08:00
|
|
|
item_class->rename_desc = C_("undo-type", "Rename Layer");
|
|
|
|
item_class->translate_desc = C_("undo-type", "Move Layer");
|
|
|
|
item_class->scale_desc = C_("undo-type", "Scale Layer");
|
|
|
|
item_class->resize_desc = C_("undo-type", "Resize Layer");
|
|
|
|
item_class->flip_desc = C_("undo-type", "Flip Layer");
|
|
|
|
item_class->rotate_desc = C_("undo-type", "Rotate Layer");
|
|
|
|
item_class->transform_desc = C_("undo-type", "Transform Layer");
|
2010-07-21 05:09:19 +08:00
|
|
|
item_class->to_selection_desc = C_("undo-type", "Alpha to Selection");
|
2010-07-09 00:08:13 +08:00
|
|
|
item_class->reorder_desc = C_("undo-type", "Reorder Layer");
|
|
|
|
item_class->raise_desc = C_("undo-type", "Raise Layer");
|
|
|
|
item_class->raise_to_top_desc = C_("undo-type", "Raise Layer to Top");
|
|
|
|
item_class->lower_desc = C_("undo-type", "Lower Layer");
|
|
|
|
item_class->lower_to_bottom_desc = C_("undo-type", "Lower Layer to Bottom");
|
|
|
|
item_class->raise_failed = _("Layer cannot be raised higher.");
|
|
|
|
item_class->lower_failed = _("Layer cannot be lowered more.");
|
2003-09-04 19:33:06 +08:00
|
|
|
|
2015-09-22 02:20:02 +08:00
|
|
|
drawable_class->alpha_changed = gimp_layer_alpha_changed;
|
2007-12-04 19:30:31 +08:00
|
|
|
drawable_class->estimate_memsize = gimp_layer_estimate_memsize;
|
2012-04-25 22:10:27 +08:00
|
|
|
drawable_class->convert_type = gimp_layer_convert_type;
|
2003-10-06 22:40:12 +08:00
|
|
|
drawable_class->invalidate_boundary = gimp_layer_invalidate_boundary;
|
|
|
|
drawable_class->get_active_components = gimp_layer_get_active_components;
|
2012-04-26 05:23:31 +08:00
|
|
|
drawable_class->get_active_mask = gimp_layer_get_active_mask;
|
2013-06-30 05:34:12 +08:00
|
|
|
drawable_class->set_buffer = gimp_layer_set_buffer;
|
2003-09-04 19:33:06 +08:00
|
|
|
|
|
|
|
klass->opacity_changed = NULL;
|
|
|
|
klass->mode_changed = NULL;
|
2017-02-13 06:49:26 +08:00
|
|
|
klass->blend_space_changed = NULL;
|
|
|
|
klass->composite_space_changed = NULL;
|
|
|
|
klass->composite_mode_changed = NULL;
|
2017-05-08 06:49:38 +08:00
|
|
|
klass->excludes_backdrop_changed = NULL;
|
2005-07-11 05:17:22 +08:00
|
|
|
klass->lock_alpha_changed = NULL;
|
2003-09-04 19:33:06 +08:00
|
|
|
klass->mask_changed = NULL;
|
2012-03-18 01:30:13 +08:00
|
|
|
klass->apply_mask_changed = NULL;
|
|
|
|
klass->edit_mask_changed = NULL;
|
|
|
|
klass->show_mask_changed = NULL;
|
2017-06-17 08:15:56 +08:00
|
|
|
klass->translate = gimp_layer_real_translate;
|
|
|
|
klass->scale = gimp_layer_real_scale;
|
|
|
|
klass->resize = gimp_layer_real_resize;
|
|
|
|
klass->flip = gimp_layer_real_flip;
|
|
|
|
klass->rotate = gimp_layer_real_rotate;
|
|
|
|
klass->transform = gimp_layer_real_transform;
|
|
|
|
klass->convert_type = gimp_layer_real_convert_type;
|
2017-12-07 02:10:38 +08:00
|
|
|
klass->get_effective_mode = gimp_layer_real_get_effective_mode;
|
2017-05-08 06:49:38 +08:00
|
|
|
klass->get_excludes_backdrop = gimp_layer_real_get_excludes_backdrop;
|
2005-07-12 00:46:28 +08:00
|
|
|
|
|
|
|
g_object_class_install_property (object_class, PROP_OPACITY,
|
|
|
|
g_param_spec_double ("opacity", NULL, NULL,
|
|
|
|
GIMP_OPACITY_TRANSPARENT,
|
|
|
|
GIMP_OPACITY_OPAQUE,
|
|
|
|
GIMP_OPACITY_OPAQUE,
|
2006-01-19 04:29:40 +08:00
|
|
|
GIMP_PARAM_READABLE));
|
2005-07-12 00:46:28 +08:00
|
|
|
|
|
|
|
g_object_class_install_property (object_class, PROP_MODE,
|
|
|
|
g_param_spec_enum ("mode", NULL, NULL,
|
2017-01-09 06:00:19 +08:00
|
|
|
GIMP_TYPE_LAYER_MODE,
|
2017-08-20 02:33:47 +08:00
|
|
|
GIMP_LAYER_MODE_NORMAL,
|
2006-01-19 04:29:40 +08:00
|
|
|
GIMP_PARAM_READABLE));
|
2005-07-12 00:46:28 +08:00
|
|
|
|
2017-02-13 06:49:26 +08:00
|
|
|
g_object_class_install_property (object_class, PROP_BLEND_SPACE,
|
|
|
|
g_param_spec_enum ("blend-space",
|
|
|
|
NULL, NULL,
|
|
|
|
GIMP_TYPE_LAYER_COLOR_SPACE,
|
|
|
|
GIMP_LAYER_COLOR_SPACE_AUTO,
|
|
|
|
GIMP_PARAM_READABLE));
|
|
|
|
|
|
|
|
g_object_class_install_property (object_class, PROP_COMPOSITE_SPACE,
|
|
|
|
g_param_spec_enum ("composite-space",
|
|
|
|
NULL, NULL,
|
|
|
|
GIMP_TYPE_LAYER_COLOR_SPACE,
|
|
|
|
GIMP_LAYER_COLOR_SPACE_AUTO,
|
|
|
|
GIMP_PARAM_READABLE));
|
|
|
|
|
|
|
|
g_object_class_install_property (object_class, PROP_COMPOSITE_MODE,
|
|
|
|
g_param_spec_enum ("composite-mode",
|
|
|
|
NULL, NULL,
|
2017-02-02 07:38:25 +08:00
|
|
|
GIMP_TYPE_LAYER_COMPOSITE_MODE,
|
|
|
|
GIMP_LAYER_COMPOSITE_AUTO,
|
|
|
|
GIMP_PARAM_READABLE));
|
|
|
|
|
2017-05-08 06:49:38 +08:00
|
|
|
g_object_class_install_property (object_class, PROP_EXCLUDES_BACKDROP,
|
|
|
|
g_param_spec_boolean ("excludes-backdrop",
|
|
|
|
NULL, NULL,
|
|
|
|
FALSE,
|
|
|
|
GIMP_PARAM_READABLE));
|
|
|
|
|
2005-07-12 00:46:28 +08:00
|
|
|
g_object_class_install_property (object_class, PROP_LOCK_ALPHA,
|
|
|
|
g_param_spec_boolean ("lock-alpha",
|
|
|
|
NULL, NULL,
|
|
|
|
FALSE,
|
2006-01-19 04:29:40 +08:00
|
|
|
GIMP_PARAM_READABLE));
|
2008-11-17 08:02:15 +08:00
|
|
|
|
2008-11-20 07:37:15 +08:00
|
|
|
g_object_class_install_property (object_class, PROP_MASK,
|
|
|
|
g_param_spec_object ("mask",
|
|
|
|
NULL, NULL,
|
|
|
|
GIMP_TYPE_LAYER_MASK,
|
|
|
|
GIMP_PARAM_READABLE));
|
|
|
|
|
2008-11-17 08:02:15 +08:00
|
|
|
g_object_class_install_property (object_class, PROP_FLOATING_SELECTION,
|
|
|
|
g_param_spec_boolean ("floating-selection",
|
|
|
|
NULL, NULL,
|
|
|
|
FALSE,
|
|
|
|
GIMP_PARAM_READABLE));
|
1998-01-22 15:02:57 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gimp_layer_init (GimpLayer *layer)
|
|
|
|
{
|
2017-12-07 02:10:38 +08:00
|
|
|
layer->opacity = GIMP_OPACITY_OPAQUE;
|
|
|
|
layer->mode = GIMP_LAYER_MODE_NORMAL;
|
|
|
|
layer->blend_space = GIMP_LAYER_COLOR_SPACE_AUTO;
|
|
|
|
layer->composite_space = GIMP_LAYER_COLOR_SPACE_AUTO;
|
|
|
|
layer->composite_mode = GIMP_LAYER_COMPOSITE_AUTO;
|
|
|
|
layer->effective_mode = layer->mode;
|
|
|
|
layer->effective_blend_space = gimp_layer_get_real_blend_space (layer);
|
|
|
|
layer->effective_composite_space = gimp_layer_get_real_composite_space (layer);
|
|
|
|
layer->effective_composite_mode = gimp_layer_get_real_composite_mode (layer);
|
|
|
|
layer->excludes_backdrop = FALSE;
|
|
|
|
layer->lock_alpha = FALSE;
|
1998-01-22 15:02:57 +08:00
|
|
|
|
2005-07-11 05:17:22 +08:00
|
|
|
layer->mask = NULL;
|
2012-03-18 01:30:13 +08:00
|
|
|
layer->apply_mask = TRUE;
|
|
|
|
layer->edit_mask = TRUE;
|
|
|
|
layer->show_mask = FALSE;
|
1998-01-22 15:02:57 +08:00
|
|
|
|
2001-01-29 00:44:22 +08:00
|
|
|
/* floating selection */
|
|
|
|
layer->fs.drawable = NULL;
|
|
|
|
layer->fs.boundary_known = FALSE;
|
|
|
|
layer->fs.segs = NULL;
|
|
|
|
layer->fs.num_segs = 0;
|
1998-01-22 15:02:57 +08:00
|
|
|
}
|
|
|
|
|
2005-07-12 03:21:52 +08:00
|
|
|
static void
|
2015-09-03 06:19:05 +08:00
|
|
|
gimp_color_managed_iface_init (GimpColorManagedInterface *iface)
|
|
|
|
{
|
|
|
|
iface->get_color_profile = gimp_layer_get_color_profile;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gimp_pickable_iface_init (GimpPickableInterface *iface)
|
2005-07-12 03:21:52 +08:00
|
|
|
{
|
2015-09-03 03:23:13 +08:00
|
|
|
iface->get_opacity_at = gimp_layer_get_opacity_at;
|
2016-05-23 05:28:31 +08:00
|
|
|
iface->pixel_to_srgb = gimp_layer_pixel_to_srgb;
|
2016-05-23 07:25:35 +08:00
|
|
|
iface->srgb_to_pixel = gimp_layer_srgb_to_pixel;
|
2005-07-12 03:21:52 +08:00
|
|
|
}
|
|
|
|
|
2005-07-12 00:46:28 +08:00
|
|
|
static void
|
|
|
|
gimp_layer_set_property (GObject *object,
|
|
|
|
guint property_id,
|
|
|
|
const GValue *value,
|
|
|
|
GParamSpec *pspec)
|
|
|
|
{
|
|
|
|
switch (property_id)
|
|
|
|
{
|
|
|
|
default:
|
|
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gimp_layer_get_property (GObject *object,
|
|
|
|
guint property_id,
|
|
|
|
GValue *value,
|
|
|
|
GParamSpec *pspec)
|
|
|
|
{
|
|
|
|
GimpLayer *layer = GIMP_LAYER (object);
|
|
|
|
|
|
|
|
switch (property_id)
|
|
|
|
{
|
|
|
|
case PROP_OPACITY:
|
2008-11-17 08:02:15 +08:00
|
|
|
g_value_set_double (value, gimp_layer_get_opacity (layer));
|
2005-07-12 00:46:28 +08:00
|
|
|
break;
|
|
|
|
case PROP_MODE:
|
2008-11-17 08:02:15 +08:00
|
|
|
g_value_set_enum (value, gimp_layer_get_mode (layer));
|
2005-07-12 00:46:28 +08:00
|
|
|
break;
|
2017-02-13 06:49:26 +08:00
|
|
|
case PROP_BLEND_SPACE:
|
|
|
|
g_value_set_enum (value, gimp_layer_get_blend_space (layer));
|
|
|
|
break;
|
|
|
|
case PROP_COMPOSITE_SPACE:
|
|
|
|
g_value_set_enum (value, gimp_layer_get_composite_space (layer));
|
|
|
|
break;
|
|
|
|
case PROP_COMPOSITE_MODE:
|
|
|
|
g_value_set_enum (value, gimp_layer_get_composite_mode (layer));
|
2017-02-02 07:38:25 +08:00
|
|
|
break;
|
2017-05-08 06:49:38 +08:00
|
|
|
case PROP_EXCLUDES_BACKDROP:
|
|
|
|
g_value_set_boolean (value, gimp_layer_get_excludes_backdrop (layer));
|
|
|
|
break;
|
2005-07-12 00:46:28 +08:00
|
|
|
case PROP_LOCK_ALPHA:
|
2008-11-17 08:02:15 +08:00
|
|
|
g_value_set_boolean (value, gimp_layer_get_lock_alpha (layer));
|
|
|
|
break;
|
2008-11-20 07:37:15 +08:00
|
|
|
case PROP_MASK:
|
|
|
|
g_value_set_object (value, gimp_layer_get_mask (layer));
|
|
|
|
break;
|
2008-11-17 08:02:15 +08:00
|
|
|
case PROP_FLOATING_SELECTION:
|
|
|
|
g_value_set_boolean (value, gimp_layer_is_floating_sel (layer));
|
2005-07-12 00:46:28 +08:00
|
|
|
break;
|
2008-11-17 08:02:15 +08:00
|
|
|
|
2005-07-12 00:46:28 +08:00
|
|
|
default:
|
|
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
To optimize duplicate and/or wrong image updates away, introduced new
2003-09-06 Michael Natterer <mitch@gimp.org>
To optimize duplicate and/or wrong image updates away, introduced
new policy that a child object must never explicitly update or
invalidate its parent object (just like the GUI is not updated
explicitly by the core):
* app/core/gimpdrawable.[ch]: added new signal
GimpDrawable::update(). Never update or invalidate the image when
the drawable is updated or invalidated.
(gimp_drawable_set_visible): don't gimp_drawable_update() the
drawable since its pixels have not changed.
* app/core/gimpimage.[ch]: connect to the "add" and "remove"
signals of the layers and channels containers. Also connect to the
"update" and "visibility_changed" signals of all drawables in
these containers (optimizes away updates issued by drawables which
are not yet added to the image and updates of the selection
mask). Also, don't propagate updates to the image if the emitting
drawable is invisible (optimizes away updates issued by invisible
drawables).
(gimp_image_add_layer,channel)
(gimp_image_remove_layer,channel): don't update the image since
that's done by our "add" and "remove" handlers now.
(gimp_image_position_layer,channel): update just the image, not
the drawable since its pixels have not changed.
(gimp_image_real_colormap_changed)
(gimp_image_set_component_visible): always call
gimp_image_update() *and* gimp_viewable_invalidate_preview() to
get everything updated, since update and invalidate of images are
not connected.
* app/core/gimpimage-undo-push.c (undo_pop_layer,channel): don't
update the drawable since (a) its pixels don't change and (b) the
image updates itself upon adding/removing now.
(undo_pop_layer_mod): replaced gimp_image_update() by
gimp_drawable_update() (just for consistency with other similar
functions).
* app/core/gimplayer.c: connect to "update" of the layer mask and
issue updates on the layer if the mask update has any effect on
the projection.
(gimp_layer_create_mask): don't set the mask's offsets here since
they may be different when we later add the mask to the layer.
* app/core/gimplayermask.c (gimp_layer_mask_set_layer): set the
mask offsets here instead.
* app/core/gimpchannel.c (gimp_channel_translate): update the
channel even if push_undo == FALSE.
* app/paint/gimppaintcore.c (gimp_paint_core_finish)
* app/tools/gimpinktool.c (ink_finish): invalidate both the
drawable and the image preview since invalidating the drawable
doesn't invalidate the image any more.
* app/text/gimptextlayer.c (gimp_text_layer_render_now): also
update the new extents of the text layer, not only the old one.
(gimp_text_layer_render_layout): don't update the drawable since
gimp_drawable_fill() already updated it.
2003-09-07 04:06:53 +08:00
|
|
|
static void
|
|
|
|
gimp_layer_dispose (GObject *object)
|
|
|
|
{
|
|
|
|
GimpLayer *layer = GIMP_LAYER (object);
|
|
|
|
|
|
|
|
if (layer->mask)
|
|
|
|
g_signal_handlers_disconnect_by_func (layer->mask,
|
|
|
|
gimp_layer_layer_mask_update,
|
|
|
|
layer);
|
|
|
|
|
2011-09-24 01:55:24 +08:00
|
|
|
if (gimp_layer_is_floating_sel (layer))
|
|
|
|
{
|
|
|
|
GimpDrawable *fs_drawable = gimp_layer_get_floating_sel_drawable (layer);
|
|
|
|
|
2011-09-24 04:24:23 +08:00
|
|
|
/* only detach if this is actually the drawable's fs because the
|
2018-05-13 00:13:12 +08:00
|
|
|
* layer might be on the undo stack and not attached to anything
|
2011-09-24 04:24:23 +08:00
|
|
|
*/
|
|
|
|
if (gimp_drawable_get_floating_sel (fs_drawable) == layer)
|
|
|
|
gimp_drawable_detach_floating_sel (fs_drawable);
|
2014-05-21 05:39:53 +08:00
|
|
|
|
|
|
|
gimp_layer_set_floating_sel_drawable (layer, NULL);
|
2011-09-24 01:55:24 +08:00
|
|
|
}
|
|
|
|
|
To optimize duplicate and/or wrong image updates away, introduced new
2003-09-06 Michael Natterer <mitch@gimp.org>
To optimize duplicate and/or wrong image updates away, introduced
new policy that a child object must never explicitly update or
invalidate its parent object (just like the GUI is not updated
explicitly by the core):
* app/core/gimpdrawable.[ch]: added new signal
GimpDrawable::update(). Never update or invalidate the image when
the drawable is updated or invalidated.
(gimp_drawable_set_visible): don't gimp_drawable_update() the
drawable since its pixels have not changed.
* app/core/gimpimage.[ch]: connect to the "add" and "remove"
signals of the layers and channels containers. Also connect to the
"update" and "visibility_changed" signals of all drawables in
these containers (optimizes away updates issued by drawables which
are not yet added to the image and updates of the selection
mask). Also, don't propagate updates to the image if the emitting
drawable is invisible (optimizes away updates issued by invisible
drawables).
(gimp_image_add_layer,channel)
(gimp_image_remove_layer,channel): don't update the image since
that's done by our "add" and "remove" handlers now.
(gimp_image_position_layer,channel): update just the image, not
the drawable since its pixels have not changed.
(gimp_image_real_colormap_changed)
(gimp_image_set_component_visible): always call
gimp_image_update() *and* gimp_viewable_invalidate_preview() to
get everything updated, since update and invalidate of images are
not connected.
* app/core/gimpimage-undo-push.c (undo_pop_layer,channel): don't
update the drawable since (a) its pixels don't change and (b) the
image updates itself upon adding/removing now.
(undo_pop_layer_mod): replaced gimp_image_update() by
gimp_drawable_update() (just for consistency with other similar
functions).
* app/core/gimplayer.c: connect to "update" of the layer mask and
issue updates on the layer if the mask update has any effect on
the projection.
(gimp_layer_create_mask): don't set the mask's offsets here since
they may be different when we later add the mask to the layer.
* app/core/gimplayermask.c (gimp_layer_mask_set_layer): set the
mask offsets here instead.
* app/core/gimpchannel.c (gimp_channel_translate): update the
channel even if push_undo == FALSE.
* app/paint/gimppaintcore.c (gimp_paint_core_finish)
* app/tools/gimpinktool.c (ink_finish): invalidate both the
drawable and the image preview since invalidating the drawable
doesn't invalidate the image any more.
* app/text/gimptextlayer.c (gimp_text_layer_render_now): also
update the new extents of the text layer, not only the old one.
(gimp_text_layer_render_layout): don't update the drawable since
gimp_drawable_fill() already updated it.
2003-09-07 04:06:53 +08:00
|
|
|
G_OBJECT_CLASS (parent_class)->dispose (object);
|
|
|
|
}
|
|
|
|
|
2001-08-11 22:39:19 +08:00
|
|
|
static void
|
|
|
|
gimp_layer_finalize (GObject *object)
|
|
|
|
{
|
2003-09-02 21:43:26 +08:00
|
|
|
GimpLayer *layer = GIMP_LAYER (object);
|
2001-08-11 22:39:19 +08:00
|
|
|
|
2017-07-16 00:38:01 +08:00
|
|
|
g_clear_object (&layer->mask);
|
2001-08-11 22:39:19 +08:00
|
|
|
|
|
|
|
G_OBJECT_CLASS (parent_class)->finalize (object);
|
|
|
|
}
|
|
|
|
|
2015-08-30 04:39:35 +08:00
|
|
|
static void
|
|
|
|
gimp_layer_update_mode_node (GimpLayer *layer)
|
2012-11-12 17:55:41 +08:00
|
|
|
{
|
2017-02-02 07:38:25 +08:00
|
|
|
GeglNode *mode_node;
|
|
|
|
GimpLayerMode visible_mode;
|
2017-02-13 06:49:26 +08:00
|
|
|
GimpLayerColorSpace visible_blend_space;
|
|
|
|
GimpLayerColorSpace visible_composite_space;
|
|
|
|
GimpLayerCompositeMode visible_composite_mode;
|
2012-11-12 17:55:41 +08:00
|
|
|
|
2015-08-30 04:39:35 +08:00
|
|
|
mode_node = gimp_drawable_get_mode_node (GIMP_DRAWABLE (layer));
|
|
|
|
|
2015-09-01 16:26:21 +08:00
|
|
|
if (layer->mask && layer->show_mask)
|
2015-08-30 04:39:35 +08:00
|
|
|
{
|
2017-08-20 19:20:11 +08:00
|
|
|
visible_mode = GIMP_LAYER_MODE_NORMAL;
|
2017-02-13 06:49:26 +08:00
|
|
|
visible_blend_space = GIMP_LAYER_COLOR_SPACE_AUTO;
|
2017-10-21 23:10:29 +08:00
|
|
|
visible_composite_space = GIMP_LAYER_COLOR_SPACE_AUTO;
|
2017-02-13 06:49:26 +08:00
|
|
|
visible_composite_mode = GIMP_LAYER_COMPOSITE_AUTO;
|
2017-08-20 19:20:11 +08:00
|
|
|
|
|
|
|
/* This makes sure that masks of LEGACY-mode layers are
|
|
|
|
* composited in PERCEPTUAL space, and non-LEGACY layers in
|
|
|
|
* LINEAR space, or whatever composite space was chosen in the
|
|
|
|
* layer attributes dialog
|
|
|
|
*/
|
2017-10-21 23:10:29 +08:00
|
|
|
visible_composite_space = gimp_layer_get_real_composite_space (layer);
|
2015-08-30 04:39:35 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2017-12-07 02:10:38 +08:00
|
|
|
visible_mode = layer->effective_mode;
|
|
|
|
visible_blend_space = layer->effective_blend_space;
|
|
|
|
visible_composite_space = layer->effective_composite_space;
|
|
|
|
visible_composite_mode = layer->effective_composite_mode;
|
2015-08-30 04:39:35 +08:00
|
|
|
}
|
|
|
|
|
2017-02-13 06:49:26 +08:00
|
|
|
gimp_gegl_mode_node_set_mode (mode_node,
|
|
|
|
visible_mode,
|
|
|
|
visible_blend_space,
|
|
|
|
visible_composite_space,
|
|
|
|
visible_composite_mode);
|
2015-08-30 04:39:35 +08:00
|
|
|
gimp_gegl_mode_node_set_opacity (mode_node, layer->opacity);
|
2012-11-12 17:55:41 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gimp_layer_notify (GObject *object,
|
|
|
|
GParamSpec *pspec)
|
|
|
|
{
|
|
|
|
if (! strcmp (pspec->name, "is-last-node") &&
|
2013-04-11 08:54:42 +08:00
|
|
|
gimp_filter_peek_node (GIMP_FILTER (object)))
|
2012-11-12 17:55:41 +08:00
|
|
|
{
|
2015-08-30 04:39:35 +08:00
|
|
|
gimp_layer_update_mode_node (GIMP_LAYER (object));
|
2012-11-12 17:55:41 +08:00
|
|
|
|
2017-01-13 09:14:40 +08:00
|
|
|
gimp_drawable_update (GIMP_DRAWABLE (object), 0, 0, -1, -1);
|
2012-11-12 17:55:41 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-02-02 04:38:26 +08:00
|
|
|
static void
|
|
|
|
gimp_layer_name_changed (GimpObject *object)
|
|
|
|
{
|
|
|
|
GimpLayer *layer = GIMP_LAYER (object);
|
|
|
|
|
2004-05-24 18:49:34 +08:00
|
|
|
if (GIMP_OBJECT_CLASS (parent_class)->name_changed)
|
|
|
|
GIMP_OBJECT_CLASS (parent_class)->name_changed (object);
|
2004-02-02 04:38:26 +08:00
|
|
|
|
|
|
|
if (layer->mask)
|
|
|
|
{
|
2006-04-07 18:51:22 +08:00
|
|
|
gchar *mask_name = g_strdup_printf (_("%s mask"),
|
|
|
|
gimp_object_get_name (object));
|
2004-02-02 04:38:26 +08:00
|
|
|
|
2006-04-07 18:51:22 +08:00
|
|
|
gimp_object_take_name (GIMP_OBJECT (layer->mask), mask_name);
|
2004-02-02 04:38:26 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-11-17 01:51:36 +08:00
|
|
|
static gint64
|
2003-08-25 18:49:33 +08:00
|
|
|
gimp_layer_get_memsize (GimpObject *object,
|
2003-11-17 01:51:36 +08:00
|
|
|
gint64 *gui_size)
|
2002-01-31 00:14:26 +08:00
|
|
|
{
|
2004-02-02 04:38:26 +08:00
|
|
|
GimpLayer *layer = GIMP_LAYER (object);
|
2003-11-17 01:51:36 +08:00
|
|
|
gint64 memsize = 0;
|
2002-01-31 00:14:26 +08:00
|
|
|
|
2007-11-17 02:19:30 +08:00
|
|
|
memsize += gimp_object_get_memsize (GIMP_OBJECT (layer->mask), gui_size);
|
2002-01-31 00:14:26 +08:00
|
|
|
|
2012-03-19 22:04:20 +08:00
|
|
|
*gui_size += layer->fs.num_segs * sizeof (GimpBoundSeg);
|
2002-01-31 00:14:26 +08:00
|
|
|
|
2003-08-25 18:49:33 +08:00
|
|
|
return memsize + GIMP_OBJECT_CLASS (parent_class)->get_memsize (object,
|
|
|
|
gui_size);
|
2002-01-31 00:14:26 +08:00
|
|
|
}
|
|
|
|
|
1997-11-25 06:05:25 +08:00
|
|
|
static void
|
2001-02-05 06:10:54 +08:00
|
|
|
gimp_layer_invalidate_preview (GimpViewable *viewable)
|
1998-01-22 15:02:57 +08:00
|
|
|
{
|
To optimize duplicate and/or wrong image updates away, introduced new
2003-09-06 Michael Natterer <mitch@gimp.org>
To optimize duplicate and/or wrong image updates away, introduced
new policy that a child object must never explicitly update or
invalidate its parent object (just like the GUI is not updated
explicitly by the core):
* app/core/gimpdrawable.[ch]: added new signal
GimpDrawable::update(). Never update or invalidate the image when
the drawable is updated or invalidated.
(gimp_drawable_set_visible): don't gimp_drawable_update() the
drawable since its pixels have not changed.
* app/core/gimpimage.[ch]: connect to the "add" and "remove"
signals of the layers and channels containers. Also connect to the
"update" and "visibility_changed" signals of all drawables in
these containers (optimizes away updates issued by drawables which
are not yet added to the image and updates of the selection
mask). Also, don't propagate updates to the image if the emitting
drawable is invisible (optimizes away updates issued by invisible
drawables).
(gimp_image_add_layer,channel)
(gimp_image_remove_layer,channel): don't update the image since
that's done by our "add" and "remove" handlers now.
(gimp_image_position_layer,channel): update just the image, not
the drawable since its pixels have not changed.
(gimp_image_real_colormap_changed)
(gimp_image_set_component_visible): always call
gimp_image_update() *and* gimp_viewable_invalidate_preview() to
get everything updated, since update and invalidate of images are
not connected.
* app/core/gimpimage-undo-push.c (undo_pop_layer,channel): don't
update the drawable since (a) its pixels don't change and (b) the
image updates itself upon adding/removing now.
(undo_pop_layer_mod): replaced gimp_image_update() by
gimp_drawable_update() (just for consistency with other similar
functions).
* app/core/gimplayer.c: connect to "update" of the layer mask and
issue updates on the layer if the mask update has any effect on
the projection.
(gimp_layer_create_mask): don't set the mask's offsets here since
they may be different when we later add the mask to the layer.
* app/core/gimplayermask.c (gimp_layer_mask_set_layer): set the
mask offsets here instead.
* app/core/gimpchannel.c (gimp_channel_translate): update the
channel even if push_undo == FALSE.
* app/paint/gimppaintcore.c (gimp_paint_core_finish)
* app/tools/gimpinktool.c (ink_finish): invalidate both the
drawable and the image preview since invalidating the drawable
doesn't invalidate the image any more.
* app/text/gimptextlayer.c (gimp_text_layer_render_now): also
update the new extents of the text layer, not only the old one.
(gimp_text_layer_render_layout): don't update the drawable since
gimp_drawable_fill() already updated it.
2003-09-07 04:06:53 +08:00
|
|
|
GimpLayer *layer = GIMP_LAYER (viewable);
|
2002-06-07 03:07:59 +08:00
|
|
|
|
2009-09-02 05:35:26 +08:00
|
|
|
GIMP_VIEWABLE_CLASS (parent_class)->invalidate_preview (viewable);
|
2001-06-18 21:10:03 +08:00
|
|
|
|
2001-01-29 07:25:25 +08:00
|
|
|
if (gimp_layer_is_floating_sel (layer))
|
2001-06-18 21:10:03 +08:00
|
|
|
floating_sel_invalidate (layer);
|
1998-01-22 15:02:57 +08:00
|
|
|
}
|
|
|
|
|
2004-09-22 20:46:35 +08:00
|
|
|
static gchar *
|
|
|
|
gimp_layer_get_description (GimpViewable *viewable,
|
|
|
|
gchar **tooltip)
|
|
|
|
{
|
|
|
|
if (gimp_layer_is_floating_sel (GIMP_LAYER (viewable)))
|
|
|
|
{
|
|
|
|
return g_strdup_printf (_("Floating Selection\n(%s)"),
|
2009-09-01 04:47:18 +08:00
|
|
|
gimp_object_get_name (viewable));
|
2004-09-22 20:46:35 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return GIMP_VIEWABLE_CLASS (parent_class)->get_description (viewable,
|
|
|
|
tooltip);
|
|
|
|
}
|
|
|
|
|
2013-04-11 08:54:42 +08:00
|
|
|
static GeglNode *
|
|
|
|
gimp_layer_get_node (GimpFilter *filter)
|
|
|
|
{
|
|
|
|
GimpDrawable *drawable = GIMP_DRAWABLE (filter);
|
|
|
|
GimpLayer *layer = GIMP_LAYER (filter);
|
|
|
|
GeglNode *node;
|
2017-04-22 03:38:57 +08:00
|
|
|
GeglNode *input;
|
2013-04-11 08:54:42 +08:00
|
|
|
GeglNode *source;
|
|
|
|
GeglNode *mode_node;
|
|
|
|
gboolean source_node_hijacked = FALSE;
|
|
|
|
|
|
|
|
node = GIMP_FILTER_CLASS (parent_class)->get_node (filter);
|
|
|
|
|
2017-04-22 03:38:57 +08:00
|
|
|
input = gegl_node_get_input_proxy (node, "input");
|
|
|
|
|
2013-04-11 08:54:42 +08:00
|
|
|
source = gimp_drawable_get_source_node (drawable);
|
|
|
|
|
|
|
|
/* if the source node already has a parent, we are a floating
|
|
|
|
* selection and the source node has been hijacked by the fs'
|
|
|
|
* drawable
|
|
|
|
*/
|
|
|
|
if (gegl_node_get_parent (source))
|
|
|
|
source_node_hijacked = TRUE;
|
|
|
|
|
|
|
|
if (! source_node_hijacked)
|
|
|
|
gegl_node_add_child (node, source);
|
|
|
|
|
2017-04-22 03:38:57 +08:00
|
|
|
gegl_node_connect_to (input, "output",
|
|
|
|
source, "input");
|
|
|
|
|
2013-04-11 08:54:42 +08:00
|
|
|
g_warn_if_fail (layer->layer_offset_node == NULL);
|
|
|
|
g_warn_if_fail (layer->mask_offset_node == NULL);
|
|
|
|
|
|
|
|
/* the mode node connects it all, and has aux and aux2 inputs for
|
|
|
|
* the layer and its mask
|
|
|
|
*/
|
|
|
|
mode_node = gimp_drawable_get_mode_node (drawable);
|
2015-08-30 04:39:35 +08:00
|
|
|
gimp_layer_update_mode_node (layer);
|
2013-04-11 08:54:42 +08:00
|
|
|
|
|
|
|
/* the layer's offset node */
|
|
|
|
layer->layer_offset_node = gegl_node_new_child (node,
|
|
|
|
"operation", "gegl:translate",
|
|
|
|
NULL);
|
|
|
|
gimp_item_add_offset_node (GIMP_ITEM (layer), layer->layer_offset_node);
|
|
|
|
|
|
|
|
/* the layer mask's offset node */
|
|
|
|
layer->mask_offset_node = gegl_node_new_child (node,
|
|
|
|
"operation", "gegl:translate",
|
|
|
|
NULL);
|
|
|
|
gimp_item_add_offset_node (GIMP_ITEM (layer), layer->mask_offset_node);
|
|
|
|
|
|
|
|
if (! source_node_hijacked)
|
|
|
|
{
|
|
|
|
gegl_node_connect_to (source, "output",
|
|
|
|
layer->layer_offset_node, "input");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (! (layer->mask && gimp_layer_get_show_mask (layer)))
|
|
|
|
{
|
|
|
|
gegl_node_connect_to (layer->layer_offset_node, "output",
|
|
|
|
mode_node, "aux");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (layer->mask)
|
|
|
|
{
|
|
|
|
GeglNode *mask;
|
|
|
|
|
|
|
|
mask = gimp_drawable_get_source_node (GIMP_DRAWABLE (layer->mask));
|
|
|
|
|
|
|
|
gegl_node_connect_to (mask, "output",
|
|
|
|
layer->mask_offset_node, "input");
|
|
|
|
|
|
|
|
if (gimp_layer_get_show_mask (layer))
|
|
|
|
{
|
|
|
|
gegl_node_connect_to (layer->mask_offset_node, "output",
|
|
|
|
mode_node, "aux");
|
|
|
|
}
|
|
|
|
else if (gimp_layer_get_apply_mask (layer))
|
|
|
|
{
|
|
|
|
gegl_node_connect_to (layer->mask_offset_node, "output",
|
|
|
|
mode_node, "aux2");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return node;
|
|
|
|
}
|
|
|
|
|
2004-02-17 19:45:46 +08:00
|
|
|
static void
|
|
|
|
gimp_layer_removed (GimpItem *item)
|
|
|
|
{
|
|
|
|
GimpLayer *layer = GIMP_LAYER (item);
|
|
|
|
|
|
|
|
if (layer->mask)
|
|
|
|
gimp_item_removed (GIMP_ITEM (layer->mask));
|
|
|
|
|
|
|
|
if (GIMP_ITEM_CLASS (parent_class)->removed)
|
|
|
|
GIMP_ITEM_CLASS (parent_class)->removed (item);
|
|
|
|
}
|
|
|
|
|
2011-02-03 02:40:20 +08:00
|
|
|
static void
|
|
|
|
gimp_layer_unset_removed (GimpItem *item)
|
|
|
|
{
|
|
|
|
GimpLayer *layer = GIMP_LAYER (item);
|
|
|
|
|
|
|
|
if (layer->mask)
|
|
|
|
gimp_item_unset_removed (GIMP_ITEM (layer->mask));
|
|
|
|
|
|
|
|
if (GIMP_ITEM_CLASS (parent_class)->unset_removed)
|
|
|
|
GIMP_ITEM_CLASS (parent_class)->unset_removed (item);
|
|
|
|
}
|
|
|
|
|
2004-01-27 00:18:16 +08:00
|
|
|
static gboolean
|
2016-05-20 05:51:44 +08:00
|
|
|
gimp_layer_is_attached (GimpItem *item)
|
2004-01-27 00:18:16 +08:00
|
|
|
{
|
2010-02-04 06:00:31 +08:00
|
|
|
GimpImage *image = gimp_item_get_image (item);
|
|
|
|
|
|
|
|
return (GIMP_IS_IMAGE (image) &&
|
|
|
|
gimp_container_have (gimp_image_get_layers (image),
|
2009-08-30 01:47:52 +08:00
|
|
|
GIMP_OBJECT (item)));
|
2004-01-27 00:18:16 +08:00
|
|
|
}
|
|
|
|
|
2010-02-06 23:17:23 +08:00
|
|
|
static GimpItemTree *
|
|
|
|
gimp_layer_get_tree (GimpItem *item)
|
2009-08-02 02:22:07 +08:00
|
|
|
{
|
|
|
|
if (gimp_item_is_attached (item))
|
|
|
|
{
|
|
|
|
GimpImage *image = gimp_item_get_image (item);
|
|
|
|
|
2010-02-06 23:17:23 +08:00
|
|
|
return gimp_image_get_layer_tree (image);
|
2009-08-02 02:22:07 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2003-02-11 21:52:47 +08:00
|
|
|
static GimpItem *
|
|
|
|
gimp_layer_duplicate (GimpItem *item,
|
2008-01-08 19:46:15 +08:00
|
|
|
GType new_type)
|
2003-02-11 21:52:47 +08:00
|
|
|
{
|
2017-01-04 02:36:22 +08:00
|
|
|
GimpItem *new_item;
|
2003-02-11 21:52:47 +08:00
|
|
|
|
|
|
|
g_return_val_if_fail (g_type_is_a (new_type, GIMP_TYPE_DRAWABLE), NULL);
|
|
|
|
|
2008-01-08 19:46:15 +08:00
|
|
|
new_item = GIMP_ITEM_CLASS (parent_class)->duplicate (item, new_type);
|
2003-02-11 21:52:47 +08:00
|
|
|
|
2005-12-23 09:15:19 +08:00
|
|
|
if (GIMP_IS_LAYER (new_item))
|
2003-02-11 21:52:47 +08:00
|
|
|
{
|
2006-02-13 00:07:39 +08:00
|
|
|
GimpLayer *layer = GIMP_LAYER (item);
|
2005-12-23 09:15:19 +08:00
|
|
|
GimpLayer *new_layer = GIMP_LAYER (new_item);
|
|
|
|
|
2017-02-13 06:49:26 +08:00
|
|
|
gimp_layer_set_mode (new_layer,
|
|
|
|
gimp_layer_get_mode (layer), FALSE);
|
|
|
|
gimp_layer_set_blend_space (new_layer,
|
|
|
|
gimp_layer_get_blend_space (layer), FALSE);
|
|
|
|
gimp_layer_set_composite_space (new_layer,
|
|
|
|
gimp_layer_get_composite_space (layer), FALSE);
|
|
|
|
gimp_layer_set_composite_mode (new_layer,
|
|
|
|
gimp_layer_get_composite_mode (layer), FALSE);
|
|
|
|
gimp_layer_set_opacity (new_layer,
|
|
|
|
gimp_layer_get_opacity (layer), FALSE);
|
2009-09-09 04:09:03 +08:00
|
|
|
|
|
|
|
if (gimp_layer_can_lock_alpha (new_layer))
|
|
|
|
gimp_layer_set_lock_alpha (new_layer,
|
|
|
|
gimp_layer_get_lock_alpha (layer), FALSE);
|
2005-12-23 09:15:19 +08:00
|
|
|
|
|
|
|
/* duplicate the layer mask if necessary */
|
|
|
|
if (layer->mask)
|
|
|
|
{
|
2008-01-08 19:46:15 +08:00
|
|
|
GimpItem *mask;
|
|
|
|
|
|
|
|
mask = gimp_item_duplicate (GIMP_ITEM (layer->mask),
|
|
|
|
G_TYPE_FROM_INSTANCE (layer->mask));
|
2008-09-16 05:05:01 +08:00
|
|
|
gimp_layer_add_mask (new_layer, GIMP_LAYER_MASK (mask), FALSE, NULL);
|
2012-03-18 01:30:13 +08:00
|
|
|
|
|
|
|
new_layer->apply_mask = layer->apply_mask;
|
|
|
|
new_layer->edit_mask = layer->edit_mask;
|
|
|
|
new_layer->show_mask = layer->show_mask;
|
2005-12-23 09:15:19 +08:00
|
|
|
}
|
2003-02-11 21:52:47 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return new_item;
|
|
|
|
}
|
|
|
|
|
2004-12-23 19:53:14 +08:00
|
|
|
static void
|
2005-01-14 02:17:24 +08:00
|
|
|
gimp_layer_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
|
|
|
{
|
2004-12-23 19:53:14 +08:00
|
|
|
GimpLayer *layer = GIMP_LAYER (item);
|
|
|
|
GimpDrawable *drawable = GIMP_DRAWABLE (item);
|
|
|
|
GimpImageBaseType old_base_type;
|
2003-08-28 01:21:49 +08:00
|
|
|
GimpImageBaseType new_base_type;
|
2012-04-25 17:44:40 +08:00
|
|
|
GimpPrecision old_precision;
|
|
|
|
GimpPrecision new_precision;
|
2016-04-29 06:42:42 +08:00
|
|
|
GimpColorProfile *dest_profile = NULL;
|
2003-08-28 01:21:49 +08:00
|
|
|
|
2012-04-07 07:51:08 +08:00
|
|
|
old_base_type = gimp_drawable_get_base_type (drawable);
|
2012-05-08 03:57:33 +08:00
|
|
|
new_base_type = gimp_image_get_base_type (dest_image);
|
2003-08-28 01:21:49 +08:00
|
|
|
|
2012-04-25 17:44:40 +08:00
|
|
|
old_precision = gimp_drawable_get_precision (drawable);
|
|
|
|
new_precision = gimp_image_get_precision (dest_image);
|
|
|
|
|
2016-04-29 06:42:42 +08:00
|
|
|
if (g_type_is_a (old_type, GIMP_TYPE_LAYER) &&
|
2016-05-09 00:23:09 +08:00
|
|
|
gimp_image_get_is_color_managed (dest_image))
|
2016-04-29 06:42:42 +08:00
|
|
|
{
|
|
|
|
dest_profile =
|
|
|
|
gimp_color_managed_get_color_profile (GIMP_COLOR_MANAGED (dest_image));
|
|
|
|
}
|
2015-08-16 21:47:43 +08:00
|
|
|
|
2012-04-25 17:44:40 +08:00
|
|
|
if (old_base_type != new_base_type ||
|
2015-08-16 21:47:43 +08:00
|
|
|
old_precision != new_precision ||
|
2016-04-29 06:42:42 +08:00
|
|
|
dest_profile)
|
2012-04-25 18:09:45 +08:00
|
|
|
{
|
|
|
|
gimp_drawable_convert_type (drawable, dest_image,
|
2016-10-04 07:39:15 +08:00
|
|
|
new_base_type,
|
|
|
|
new_precision,
|
|
|
|
gimp_drawable_has_alpha (drawable),
|
2016-04-29 06:42:42 +08:00
|
|
|
dest_profile,
|
2016-11-08 03:41:39 +08:00
|
|
|
GEGL_DITHER_NONE, GEGL_DITHER_NONE,
|
2015-10-22 04:22:30 +08:00
|
|
|
FALSE, NULL);
|
2012-04-25 18:09:45 +08:00
|
|
|
}
|
2003-08-28 01:21:49 +08:00
|
|
|
|
2005-01-14 02:17:24 +08:00
|
|
|
if (layer->mask)
|
|
|
|
gimp_item_set_image (GIMP_ITEM (layer->mask), dest_image);
|
|
|
|
|
2015-08-16 21:47:43 +08:00
|
|
|
GIMP_ITEM_CLASS (parent_class)->convert (item, dest_image, old_type);
|
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_layer_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
|
|
|
GimpLayer *layer = GIMP_LAYER (item);
|
2006-03-29 01:08:36 +08:00
|
|
|
GimpImage *image = gimp_item_get_image (item);
|
2004-02-02 04:38:26 +08:00
|
|
|
gboolean attached;
|
|
|
|
gboolean floating_sel;
|
2003-03-17 08:14:59 +08:00
|
|
|
|
2004-02-02 04:38:26 +08:00
|
|
|
attached = gimp_item_is_attached (item);
|
|
|
|
floating_sel = gimp_layer_is_floating_sel (layer);
|
|
|
|
|
|
|
|
if (floating_sel)
|
2003-03-17 08:14:59 +08:00
|
|
|
{
|
2009-01-27 06:47:16 +08:00
|
|
|
if (GIMP_IS_CHANNEL (gimp_layer_get_floating_sel_drawable (layer)))
|
2007-12-12 21:57:11 +08:00
|
|
|
{
|
2008-11-12 18:56:06 +08:00
|
|
|
g_set_error_literal (error, GIMP_ERROR, GIMP_FAILED,
|
2015-11-11 22:19:45 +08:00
|
|
|
_("Cannot create a new layer from the floating "
|
|
|
|
"selection because it belongs to a layer mask "
|
|
|
|
"or channel."));
|
2007-12-12 21:57:11 +08:00
|
|
|
return FALSE;
|
|
|
|
}
|
2004-02-02 04:38:26 +08:00
|
|
|
|
|
|
|
if (attached)
|
|
|
|
{
|
2006-03-29 01:08:36 +08:00
|
|
|
gimp_image_undo_group_start (image,
|
2004-02-02 04:38:26 +08:00
|
|
|
GIMP_UNDO_GROUP_ITEM_PROPERTIES,
|
|
|
|
undo_desc);
|
2003-03-17 08:14:59 +08:00
|
|
|
|
2007-12-07 02:00:10 +08:00
|
|
|
floating_sel_to_layer (layer, NULL);
|
2004-02-02 04:38:26 +08:00
|
|
|
}
|
2003-03-17 08:14:59 +08:00
|
|
|
}
|
|
|
|
|
2007-12-12 21:57:11 +08:00
|
|
|
GIMP_ITEM_CLASS (parent_class)->rename (item, new_name, undo_desc, error);
|
2003-03-17 08:14:59 +08:00
|
|
|
|
2004-02-02 04:38:26 +08:00
|
|
|
if (attached && floating_sel)
|
2006-03-29 01:08:36 +08:00
|
|
|
gimp_image_undo_group_end (image);
|
2004-02-02 04:38:26 +08:00
|
|
|
|
|
|
|
return TRUE;
|
2003-03-17 08:14:59 +08:00
|
|
|
}
|
|
|
|
|
Bug 51112 - Support layer masks on layer groups
Add layer-mask support for group layers. Group-layer masks work
similarly to ordinary-layer masks, with the following
considerations:
The group's mask size is the same as group's size (i.e., the
bounding box of its children) at all times. When the group's size
changes, the mask is cropped to the new size -- areas of the mask
that fall outside of the new bounds are discarded and their data is
lost (sans undo), and newly added areas are filled with black (and
hence are transparent by default).
The new gimp_group_layer_{suspend,resume}_mask() functions can be
used to modify this behavior. Between the outermost pair of
suspend/resume calls, the old mask data is remembered, and is used
to fill the newly added areas while cropping the mask when the
group is resized. We override GimpItem::{start,end}_move() for
GimpLayer, to call these functions (suspend() in start_move(), and
resume() in end_move()) for each of the layer's ancestors.
As a result, while moving a layer, or a set of layers, atomically,
such as while dragging with the move tool, or moving linked layers,
the ancestors' mask data is not lost, and is only discarded at the
end of the operation.
This commit also takes care of properly handling undo for group-
layer mask crops, properly invalidating the image when the group
layer's mask is shown, and enabling the mask actions for group
layers (obviously :).
2018-02-06 00:19:18 +08:00
|
|
|
static void
|
|
|
|
gimp_layer_start_move (GimpItem *item,
|
|
|
|
gboolean push_undo)
|
|
|
|
{
|
2018-02-10 18:17:04 +08:00
|
|
|
GimpLayer *layer = GIMP_LAYER (item);
|
|
|
|
GimpLayer *ancestor = layer;
|
|
|
|
GSList *ancestors = NULL;
|
Bug 51112 - Support layer masks on layer groups
Add layer-mask support for group layers. Group-layer masks work
similarly to ordinary-layer masks, with the following
considerations:
The group's mask size is the same as group's size (i.e., the
bounding box of its children) at all times. When the group's size
changes, the mask is cropped to the new size -- areas of the mask
that fall outside of the new bounds are discarded and their data is
lost (sans undo), and newly added areas are filled with black (and
hence are transparent by default).
The new gimp_group_layer_{suspend,resume}_mask() functions can be
used to modify this behavior. Between the outermost pair of
suspend/resume calls, the old mask data is remembered, and is used
to fill the newly added areas while cropping the mask when the
group is resized. We override GimpItem::{start,end}_move() for
GimpLayer, to call these functions (suspend() in start_move(), and
resume() in end_move()) for each of the layer's ancestors.
As a result, while moving a layer, or a set of layers, atomically,
such as while dragging with the move tool, or moving linked layers,
the ancestors' mask data is not lost, and is only discarded at the
end of the operation.
This commit also takes care of properly handling undo for group-
layer mask crops, properly invalidating the image when the group
layer's mask is shown, and enabling the mask actions for group
layers (obviously :).
2018-02-06 00:19:18 +08:00
|
|
|
|
|
|
|
/* suspend mask cropping for all of the layer's ancestors */
|
2018-02-10 18:17:04 +08:00
|
|
|
while ((ancestor = gimp_layer_get_parent (ancestor)))
|
|
|
|
{
|
|
|
|
gimp_group_layer_suspend_mask (GIMP_GROUP_LAYER (ancestor), push_undo);
|
|
|
|
|
|
|
|
ancestors = g_slist_prepend (ancestors, g_object_ref (ancestor));
|
|
|
|
}
|
|
|
|
|
|
|
|
/* we keep the ancestor list around, so that we can resume mask cropping for
|
|
|
|
* the same set of groups in gimp_layer_end_move(). note that
|
|
|
|
* gimp_image_remove_layer() calls start_move() before removing the layer,
|
|
|
|
* while it's still part of the layer tree, and end_move() afterwards, when
|
|
|
|
* it's no longer part of the layer tree, and hence we can't use get_parent()
|
|
|
|
* in end_move() to get the same set of ancestors.
|
|
|
|
*/
|
|
|
|
layer->move_stack = g_slist_prepend (layer->move_stack, ancestors);
|
Bug 51112 - Support layer masks on layer groups
Add layer-mask support for group layers. Group-layer masks work
similarly to ordinary-layer masks, with the following
considerations:
The group's mask size is the same as group's size (i.e., the
bounding box of its children) at all times. When the group's size
changes, the mask is cropped to the new size -- areas of the mask
that fall outside of the new bounds are discarded and their data is
lost (sans undo), and newly added areas are filled with black (and
hence are transparent by default).
The new gimp_group_layer_{suspend,resume}_mask() functions can be
used to modify this behavior. Between the outermost pair of
suspend/resume calls, the old mask data is remembered, and is used
to fill the newly added areas while cropping the mask when the
group is resized. We override GimpItem::{start,end}_move() for
GimpLayer, to call these functions (suspend() in start_move(), and
resume() in end_move()) for each of the layer's ancestors.
As a result, while moving a layer, or a set of layers, atomically,
such as while dragging with the move tool, or moving linked layers,
the ancestors' mask data is not lost, and is only discarded at the
end of the operation.
This commit also takes care of properly handling undo for group-
layer mask crops, properly invalidating the image when the group
layer's mask is shown, and enabling the mask actions for group
layers (obviously :).
2018-02-06 00:19:18 +08:00
|
|
|
|
|
|
|
if (GIMP_ITEM_CLASS (parent_class)->start_move)
|
|
|
|
GIMP_ITEM_CLASS (parent_class)->start_move (item, push_undo);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gimp_layer_end_move (GimpItem *item,
|
|
|
|
gboolean push_undo)
|
|
|
|
{
|
|
|
|
GimpLayer *layer = GIMP_LAYER (item);
|
2018-02-12 18:03:53 +08:00
|
|
|
GSList *ancestors;
|
|
|
|
GSList *iter;
|
|
|
|
|
|
|
|
g_return_if_fail (layer->move_stack != NULL);
|
Bug 51112 - Support layer masks on layer groups
Add layer-mask support for group layers. Group-layer masks work
similarly to ordinary-layer masks, with the following
considerations:
The group's mask size is the same as group's size (i.e., the
bounding box of its children) at all times. When the group's size
changes, the mask is cropped to the new size -- areas of the mask
that fall outside of the new bounds are discarded and their data is
lost (sans undo), and newly added areas are filled with black (and
hence are transparent by default).
The new gimp_group_layer_{suspend,resume}_mask() functions can be
used to modify this behavior. Between the outermost pair of
suspend/resume calls, the old mask data is remembered, and is used
to fill the newly added areas while cropping the mask when the
group is resized. We override GimpItem::{start,end}_move() for
GimpLayer, to call these functions (suspend() in start_move(), and
resume() in end_move()) for each of the layer's ancestors.
As a result, while moving a layer, or a set of layers, atomically,
such as while dragging with the move tool, or moving linked layers,
the ancestors' mask data is not lost, and is only discarded at the
end of the operation.
This commit also takes care of properly handling undo for group-
layer mask crops, properly invalidating the image when the group
layer's mask is shown, and enabling the mask actions for group
layers (obviously :).
2018-02-06 00:19:18 +08:00
|
|
|
|
|
|
|
if (GIMP_ITEM_CLASS (parent_class)->end_move)
|
|
|
|
GIMP_ITEM_CLASS (parent_class)->end_move (item, push_undo);
|
|
|
|
|
2018-02-12 18:03:53 +08:00
|
|
|
ancestors = layer->move_stack->data;
|
2018-02-10 18:17:04 +08:00
|
|
|
|
2018-02-12 18:03:53 +08:00
|
|
|
layer->move_stack = g_slist_remove (layer->move_stack, ancestors);
|
2018-02-10 18:17:04 +08:00
|
|
|
|
2018-02-12 18:03:53 +08:00
|
|
|
/* resume mask cropping for all of the layer's ancestors */
|
|
|
|
for (iter = ancestors; iter; iter = g_slist_next (iter))
|
|
|
|
{
|
|
|
|
GimpGroupLayer *ancestor = iter->data;
|
2018-02-10 18:17:04 +08:00
|
|
|
|
2018-02-12 18:03:53 +08:00
|
|
|
gimp_group_layer_resume_mask (ancestor, push_undo);
|
2018-02-12 15:23:05 +08:00
|
|
|
|
2018-02-12 18:03:53 +08:00
|
|
|
g_object_unref (ancestor);
|
2018-02-12 15:23:05 +08:00
|
|
|
}
|
2018-02-12 18:03:53 +08:00
|
|
|
|
|
|
|
g_slist_free (ancestors);
|
Bug 51112 - Support layer masks on layer groups
Add layer-mask support for group layers. Group-layer masks work
similarly to ordinary-layer masks, with the following
considerations:
The group's mask size is the same as group's size (i.e., the
bounding box of its children) at all times. When the group's size
changes, the mask is cropped to the new size -- areas of the mask
that fall outside of the new bounds are discarded and their data is
lost (sans undo), and newly added areas are filled with black (and
hence are transparent by default).
The new gimp_group_layer_{suspend,resume}_mask() functions can be
used to modify this behavior. Between the outermost pair of
suspend/resume calls, the old mask data is remembered, and is used
to fill the newly added areas while cropping the mask when the
group is resized. We override GimpItem::{start,end}_move() for
GimpLayer, to call these functions (suspend() in start_move(), and
resume() in end_move()) for each of the layer's ancestors.
As a result, while moving a layer, or a set of layers, atomically,
such as while dragging with the move tool, or moving linked layers,
the ancestors' mask data is not lost, and is only discarded at the
end of the operation.
This commit also takes care of properly handling undo for group-
layer mask crops, properly invalidating the image when the group
layer's mask is shown, and enabling the mask actions for group
layers (obviously :).
2018-02-06 00:19:18 +08:00
|
|
|
}
|
|
|
|
|
2003-05-09 03:11:17 +08:00
|
|
|
static void
|
|
|
|
gimp_layer_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
|
|
|
{
|
2004-02-02 04:38:26 +08:00
|
|
|
GimpLayer *layer = GIMP_LAYER (item);
|
2003-05-09 03:11:17 +08:00
|
|
|
|
2003-05-09 21:05:37 +08:00
|
|
|
if (push_undo)
|
2004-04-13 19:43:27 +08:00
|
|
|
gimp_image_undo_push_item_displace (gimp_item_get_image (item), NULL, item);
|
2003-05-09 21:05:37 +08:00
|
|
|
|
2018-04-23 07:08:54 +08:00
|
|
|
GIMP_LAYER_GET_CLASS (layer)->translate (layer,
|
|
|
|
SIGNED_ROUND (offset_x),
|
|
|
|
SIGNED_ROUND (offset_y));
|
2003-05-09 03:11:17 +08:00
|
|
|
|
2003-08-28 01:21:49 +08:00
|
|
|
if (layer->mask)
|
2003-05-09 03:11:17 +08:00
|
|
|
{
|
2008-11-04 05:17:50 +08:00
|
|
|
gint off_x, off_y;
|
|
|
|
|
|
|
|
gimp_item_get_offset (item, &off_x, &off_y);
|
|
|
|
gimp_item_set_offset (GIMP_ITEM (layer->mask), off_x, off_y);
|
2003-05-09 03:11:17 +08:00
|
|
|
|
|
|
|
gimp_viewable_invalidate_preview (GIMP_VIEWABLE (layer->mask));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-05-07 19:09:00 +08:00
|
|
|
static void
|
|
|
|
gimp_layer_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_type,
|
2004-08-11 02:47:21 +08:00
|
|
|
GimpProgress *progress)
|
2003-05-07 19:09:00 +08:00
|
|
|
{
|
app: use GimpObjectQueue in lots of places
Use GimpObjectQueue, added in the previous commit, in various
instances where we perform an action on a set of objects. This
improves progress reporting, by using a single progress for the
entire operation, rather than reporting the progress of each object
individually, and by taking the relative cost of each object into
account, instead of assuming a uniform cost for all objects.
In particular, this affects the various whole-image operations
(i.e., transformations and color conversions), operations on linked
items, and operations on layer groups. This also affects layers
with masks, whose progress is now reported together instead of
individually.
Additionally, this commit fixes erroneous group-layer mask cropping
during undo when resizing the image, by properly calling
{start,end}_move() on all the resized layers before starting the
operation, and when scaling the image, by only scaling top-level
layers, and letting group layers scale their children themselves.
2018-03-25 22:18:46 +08:00
|
|
|
GimpLayer *layer = GIMP_LAYER (item);
|
|
|
|
GimpObjectQueue *queue = NULL;
|
|
|
|
|
|
|
|
if (progress && layer->mask)
|
|
|
|
{
|
|
|
|
GimpLayerMask *mask;
|
|
|
|
|
|
|
|
queue = gimp_object_queue_new (progress);
|
|
|
|
progress = GIMP_PROGRESS (queue);
|
|
|
|
|
|
|
|
/* temporarily set layer->mask to NULL, so that its size won't be counted
|
|
|
|
* when pushing the layer to the queue.
|
|
|
|
*/
|
|
|
|
mask = layer->mask;
|
|
|
|
layer->mask = NULL;
|
|
|
|
|
|
|
|
gimp_object_queue_push (queue, layer);
|
|
|
|
gimp_object_queue_push (queue, mask);
|
|
|
|
|
|
|
|
layer->mask = mask;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (queue)
|
|
|
|
gimp_object_queue_pop (queue);
|
2003-05-07 19:09:00 +08:00
|
|
|
|
2017-06-17 08:15:56 +08:00
|
|
|
GIMP_LAYER_GET_CLASS (layer)->scale (layer, new_width, new_height,
|
|
|
|
new_offset_x, new_offset_y,
|
|
|
|
interpolation_type, progress);
|
2003-05-07 19:09:00 +08:00
|
|
|
|
|
|
|
if (layer->mask)
|
app: use GimpObjectQueue in lots of places
Use GimpObjectQueue, added in the previous commit, in various
instances where we perform an action on a set of objects. This
improves progress reporting, by using a single progress for the
entire operation, rather than reporting the progress of each object
individually, and by taking the relative cost of each object into
account, instead of assuming a uniform cost for all objects.
In particular, this affects the various whole-image operations
(i.e., transformations and color conversions), operations on linked
items, and operations on layer groups. This also affects layers
with masks, whose progress is now reported together instead of
individually.
Additionally, this commit fixes erroneous group-layer mask cropping
during undo when resizing the image, by properly calling
{start,end}_move() on all the resized layers before starting the
operation, and when scaling the image, by only scaling top-level
layers, and letting group layers scale their children themselves.
2018-03-25 22:18:46 +08:00
|
|
|
{
|
|
|
|
if (queue)
|
|
|
|
gimp_object_queue_pop (queue);
|
|
|
|
|
|
|
|
gimp_item_scale (GIMP_ITEM (layer->mask),
|
|
|
|
new_width, new_height,
|
|
|
|
new_offset_x, new_offset_y,
|
|
|
|
interpolation_type, progress);
|
|
|
|
}
|
|
|
|
|
|
|
|
g_clear_object (&queue);
|
2003-05-07 19:09:00 +08:00
|
|
|
}
|
|
|
|
|
2003-05-07 21:01:17 +08:00
|
|
|
static void
|
2016-10-10 06:02:16 +08:00
|
|
|
gimp_layer_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
|
|
|
{
|
2004-03-17 00:23:06 +08:00
|
|
|
GimpLayer *layer = GIMP_LAYER (item);
|
2003-05-07 21:01:17 +08:00
|
|
|
|
2017-06-17 08:15:56 +08:00
|
|
|
GIMP_LAYER_GET_CLASS (layer)->resize (layer, context, fill_type,
|
|
|
|
new_width, new_height,
|
|
|
|
offset_x, offset_y);
|
2003-05-07 21:01:17 +08:00
|
|
|
|
|
|
|
if (layer->mask)
|
2016-10-10 06:02:16 +08:00
|
|
|
gimp_item_resize (GIMP_ITEM (layer->mask), context, GIMP_FILL_TRANSPARENT,
|
2004-04-13 19:43:27 +08:00
|
|
|
new_width, new_height, offset_x, offset_y);
|
2003-05-07 21:01:17 +08:00
|
|
|
}
|
|
|
|
|
2003-05-12 23:56:36 +08:00
|
|
|
static void
|
|
|
|
gimp_layer_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
|
|
|
{
|
2004-04-13 19:43:27 +08:00
|
|
|
GimpLayer *layer = GIMP_LAYER (item);
|
2003-05-12 23:56:36 +08:00
|
|
|
|
2017-06-17 08:15:56 +08:00
|
|
|
GIMP_LAYER_GET_CLASS (layer)->flip (layer, context, flip_type, axis,
|
|
|
|
clip_result);
|
2003-05-12 23:56:36 +08:00
|
|
|
|
|
|
|
if (layer->mask)
|
2004-04-15 07:37:34 +08:00
|
|
|
gimp_item_flip (GIMP_ITEM (layer->mask), context,
|
2003-05-13 21:57:11 +08:00
|
|
|
flip_type, axis, clip_result);
|
2003-05-12 23:56:36 +08:00
|
|
|
}
|
|
|
|
|
2003-05-20 18:36:29 +08:00
|
|
|
static void
|
|
|
|
gimp_layer_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)
|
|
|
|
{
|
2004-04-13 19:43:27 +08:00
|
|
|
GimpLayer *layer = GIMP_LAYER (item);
|
2003-05-20 18:36:29 +08:00
|
|
|
|
2017-06-17 08:15:56 +08:00
|
|
|
GIMP_LAYER_GET_CLASS (layer)->rotate (layer, context,
|
|
|
|
rotate_type, center_x, center_y,
|
|
|
|
clip_result);
|
2003-05-20 18:36:29 +08:00
|
|
|
|
|
|
|
if (layer->mask)
|
2004-04-15 07:37:34 +08:00
|
|
|
gimp_item_rotate (GIMP_ITEM (layer->mask), context,
|
2003-05-20 18:36:29 +08:00
|
|
|
rotate_type, center_x, center_y, clip_result);
|
|
|
|
}
|
|
|
|
|
2003-05-12 23:56:36 +08:00
|
|
|
static void
|
|
|
|
gimp_layer_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,
|
|
|
|
GimpInterpolationType interpolation_type,
|
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
|
|
|
{
|
app: use GimpObjectQueue in lots of places
Use GimpObjectQueue, added in the previous commit, in various
instances where we perform an action on a set of objects. This
improves progress reporting, by using a single progress for the
entire operation, rather than reporting the progress of each object
individually, and by taking the relative cost of each object into
account, instead of assuming a uniform cost for all objects.
In particular, this affects the various whole-image operations
(i.e., transformations and color conversions), operations on linked
items, and operations on layer groups. This also affects layers
with masks, whose progress is now reported together instead of
individually.
Additionally, this commit fixes erroneous group-layer mask cropping
during undo when resizing the image, by properly calling
{start,end}_move() on all the resized layers before starting the
operation, and when scaling the image, by only scaling top-level
layers, and letting group layers scale their children themselves.
2018-03-25 22:18:46 +08:00
|
|
|
GimpLayer *layer = GIMP_LAYER (item);
|
|
|
|
GimpObjectQueue *queue = NULL;
|
|
|
|
|
|
|
|
if (progress && layer->mask)
|
|
|
|
{
|
|
|
|
GimpLayerMask *mask;
|
|
|
|
|
|
|
|
queue = gimp_object_queue_new (progress);
|
|
|
|
progress = GIMP_PROGRESS (queue);
|
|
|
|
|
|
|
|
/* temporarily set layer->mask to NULL, so that its size won't be counted
|
|
|
|
* when pushing the layer to the queue.
|
|
|
|
*/
|
|
|
|
mask = layer->mask;
|
|
|
|
layer->mask = NULL;
|
|
|
|
|
|
|
|
gimp_object_queue_push (queue, layer);
|
|
|
|
gimp_object_queue_push (queue, mask);
|
|
|
|
|
|
|
|
layer->mask = mask;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (queue)
|
|
|
|
gimp_object_queue_pop (queue);
|
2003-05-12 23:56:36 +08:00
|
|
|
|
2017-06-17 08:15:56 +08:00
|
|
|
GIMP_LAYER_GET_CLASS (layer)->transform (layer, context, matrix, direction,
|
|
|
|
interpolation_type,
|
|
|
|
clip_result,
|
|
|
|
progress);
|
2003-05-12 23:56:36 +08:00
|
|
|
|
|
|
|
if (layer->mask)
|
app: use GimpObjectQueue in lots of places
Use GimpObjectQueue, added in the previous commit, in various
instances where we perform an action on a set of objects. This
improves progress reporting, by using a single progress for the
entire operation, rather than reporting the progress of each object
individually, and by taking the relative cost of each object into
account, instead of assuming a uniform cost for all objects.
In particular, this affects the various whole-image operations
(i.e., transformations and color conversions), operations on linked
items, and operations on layer groups. This also affects layers
with masks, whose progress is now reported together instead of
individually.
Additionally, this commit fixes erroneous group-layer mask cropping
during undo when resizing the image, by properly calling
{start,end}_move() on all the resized layers before starting the
operation, and when scaling the image, by only scaling top-level
layers, and letting group layers scale their children themselves.
2018-03-25 22:18:46 +08:00
|
|
|
{
|
|
|
|
if (queue)
|
|
|
|
gimp_object_queue_pop (queue);
|
|
|
|
|
|
|
|
gimp_item_transform (GIMP_ITEM (layer->mask), context,
|
|
|
|
matrix, direction,
|
|
|
|
interpolation_type,
|
|
|
|
clip_result, progress);
|
|
|
|
}
|
|
|
|
|
|
|
|
g_clear_object (&queue);
|
2003-09-04 19:33:06 +08:00
|
|
|
}
|
|
|
|
|
2010-07-21 05:09:19 +08:00
|
|
|
static void
|
|
|
|
gimp_layer_to_selection (GimpItem *item,
|
|
|
|
GimpChannelOps op,
|
|
|
|
gboolean antialias,
|
|
|
|
gboolean feather,
|
|
|
|
gdouble feather_radius_x,
|
|
|
|
gdouble feather_radius_y)
|
|
|
|
{
|
|
|
|
GimpLayer *layer = GIMP_LAYER (item);
|
|
|
|
GimpImage *image = gimp_item_get_image (item);
|
|
|
|
|
|
|
|
gimp_channel_select_alpha (gimp_image_get_mask (image),
|
|
|
|
GIMP_DRAWABLE (layer),
|
|
|
|
op,
|
|
|
|
feather, feather_radius_x, feather_radius_y);
|
|
|
|
}
|
|
|
|
|
2015-09-22 02:20:02 +08:00
|
|
|
static void
|
|
|
|
gimp_layer_alpha_changed (GimpDrawable *drawable)
|
|
|
|
{
|
|
|
|
if (GIMP_DRAWABLE_CLASS (parent_class)->alpha_changed)
|
|
|
|
GIMP_DRAWABLE_CLASS (parent_class)->alpha_changed (drawable);
|
|
|
|
|
|
|
|
/* When we add/remove alpha, whatever cached color transforms in
|
|
|
|
* view renderers need to be recreated because they cache the wrong
|
|
|
|
* lcms formats. See bug 478528.
|
|
|
|
*/
|
|
|
|
gimp_color_managed_profile_changed (GIMP_COLOR_MANAGED (drawable));
|
|
|
|
}
|
|
|
|
|
2007-12-04 19:30:31 +08:00
|
|
|
static gint64
|
2016-05-20 05:51:44 +08:00
|
|
|
gimp_layer_estimate_memsize (GimpDrawable *drawable,
|
|
|
|
GimpComponentType component_type,
|
|
|
|
gint width,
|
|
|
|
gint height)
|
2007-12-04 19:30:31 +08:00
|
|
|
{
|
|
|
|
GimpLayer *layer = GIMP_LAYER (drawable);
|
|
|
|
gint64 memsize = 0;
|
|
|
|
|
|
|
|
if (layer->mask)
|
|
|
|
memsize += gimp_drawable_estimate_memsize (GIMP_DRAWABLE (layer->mask),
|
2014-06-15 05:12:22 +08:00
|
|
|
component_type,
|
2007-12-04 19:30:31 +08:00
|
|
|
width, height);
|
|
|
|
|
2014-06-15 05:12:22 +08:00
|
|
|
return memsize +
|
|
|
|
GIMP_DRAWABLE_CLASS (parent_class)->estimate_memsize (drawable,
|
|
|
|
component_type,
|
|
|
|
width, height);
|
2007-12-04 19:30:31 +08:00
|
|
|
}
|
|
|
|
|
2012-04-25 22:10:27 +08:00
|
|
|
static void
|
2016-11-08 03:41:39 +08:00
|
|
|
gimp_layer_convert_type (GimpDrawable *drawable,
|
|
|
|
GimpImage *dest_image,
|
|
|
|
const Babl *new_format,
|
|
|
|
GimpColorProfile *dest_profile,
|
|
|
|
GeglDitherMethod layer_dither_type,
|
|
|
|
GeglDitherMethod mask_dither_type,
|
|
|
|
gboolean push_undo,
|
|
|
|
GimpProgress *progress)
|
2012-04-25 22:10:27 +08:00
|
|
|
{
|
app: use GimpObjectQueue in lots of places
Use GimpObjectQueue, added in the previous commit, in various
instances where we perform an action on a set of objects. This
improves progress reporting, by using a single progress for the
entire operation, rather than reporting the progress of each object
individually, and by taking the relative cost of each object into
account, instead of assuming a uniform cost for all objects.
In particular, this affects the various whole-image operations
(i.e., transformations and color conversions), operations on linked
items, and operations on layer groups. This also affects layers
with masks, whose progress is now reported together instead of
individually.
Additionally, this commit fixes erroneous group-layer mask cropping
during undo when resizing the image, by properly calling
{start,end}_move() on all the resized layers before starting the
operation, and when scaling the image, by only scaling top-level
layers, and letting group layers scale their children themselves.
2018-03-25 22:18:46 +08:00
|
|
|
GimpLayer *layer = GIMP_LAYER (drawable);
|
|
|
|
GimpObjectQueue *queue = NULL;
|
|
|
|
gboolean convert_mask;
|
|
|
|
|
|
|
|
convert_mask = layer->mask &&
|
|
|
|
gimp_babl_format_get_precision (new_format) !=
|
|
|
|
gimp_drawable_get_precision (GIMP_DRAWABLE (layer->mask));
|
|
|
|
|
|
|
|
if (progress && convert_mask)
|
|
|
|
{
|
|
|
|
GimpLayerMask *mask;
|
|
|
|
|
|
|
|
queue = gimp_object_queue_new (progress);
|
|
|
|
progress = GIMP_PROGRESS (queue);
|
|
|
|
|
|
|
|
/* temporarily set layer->mask to NULL, so that its size won't be counted
|
|
|
|
* when pushing the layer to the queue.
|
|
|
|
*/
|
|
|
|
mask = layer->mask;
|
|
|
|
layer->mask = NULL;
|
|
|
|
|
|
|
|
gimp_object_queue_push (queue, layer);
|
|
|
|
gimp_object_queue_push (queue, mask);
|
|
|
|
|
|
|
|
layer->mask = mask;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (queue)
|
|
|
|
gimp_object_queue_pop (queue);
|
2012-10-14 03:46:56 +08:00
|
|
|
|
2017-06-17 08:15:56 +08:00
|
|
|
GIMP_LAYER_GET_CLASS (layer)->convert_type (layer, dest_image, new_format,
|
|
|
|
dest_profile, layer_dither_type,
|
|
|
|
mask_dither_type, push_undo,
|
|
|
|
progress);
|
2012-04-25 22:10:27 +08:00
|
|
|
|
app: use GimpObjectQueue in lots of places
Use GimpObjectQueue, added in the previous commit, in various
instances where we perform an action on a set of objects. This
improves progress reporting, by using a single progress for the
entire operation, rather than reporting the progress of each object
individually, and by taking the relative cost of each object into
account, instead of assuming a uniform cost for all objects.
In particular, this affects the various whole-image operations
(i.e., transformations and color conversions), operations on linked
items, and operations on layer groups. This also affects layers
with masks, whose progress is now reported together instead of
individually.
Additionally, this commit fixes erroneous group-layer mask cropping
during undo when resizing the image, by properly calling
{start,end}_move() on all the resized layers before starting the
operation, and when scaling the image, by only scaling top-level
layers, and letting group layers scale their children themselves.
2018-03-25 22:18:46 +08:00
|
|
|
if (convert_mask)
|
2012-04-25 22:10:27 +08:00
|
|
|
{
|
app: use GimpObjectQueue in lots of places
Use GimpObjectQueue, added in the previous commit, in various
instances where we perform an action on a set of objects. This
improves progress reporting, by using a single progress for the
entire operation, rather than reporting the progress of each object
individually, and by taking the relative cost of each object into
account, instead of assuming a uniform cost for all objects.
In particular, this affects the various whole-image operations
(i.e., transformations and color conversions), operations on linked
items, and operations on layer groups. This also affects layers
with masks, whose progress is now reported together instead of
individually.
Additionally, this commit fixes erroneous group-layer mask cropping
during undo when resizing the image, by properly calling
{start,end}_move() on all the resized layers before starting the
operation, and when scaling the image, by only scaling top-level
layers, and letting group layers scale their children themselves.
2018-03-25 22:18:46 +08:00
|
|
|
if (queue)
|
|
|
|
gimp_object_queue_pop (queue);
|
|
|
|
|
2012-04-25 22:10:27 +08:00
|
|
|
gimp_drawable_convert_type (GIMP_DRAWABLE (layer->mask), dest_image,
|
2016-10-04 07:39:15 +08:00
|
|
|
GIMP_GRAY,
|
|
|
|
gimp_babl_format_get_precision (new_format),
|
|
|
|
gimp_drawable_has_alpha (GIMP_DRAWABLE (layer->mask)),
|
2016-04-29 06:42:42 +08:00
|
|
|
NULL,
|
2012-10-14 03:46:56 +08:00
|
|
|
layer_dither_type, mask_dither_type,
|
app: use GimpObjectQueue in lots of places
Use GimpObjectQueue, added in the previous commit, in various
instances where we perform an action on a set of objects. This
improves progress reporting, by using a single progress for the
entire operation, rather than reporting the progress of each object
individually, and by taking the relative cost of each object into
account, instead of assuming a uniform cost for all objects.
In particular, this affects the various whole-image operations
(i.e., transformations and color conversions), operations on linked
items, and operations on layer groups. This also affects layers
with masks, whose progress is now reported together instead of
individually.
Additionally, this commit fixes erroneous group-layer mask cropping
during undo when resizing the image, by properly calling
{start,end}_move() on all the resized layers before starting the
operation, and when scaling the image, by only scaling top-level
layers, and letting group layers scale their children themselves.
2018-03-25 22:18:46 +08:00
|
|
|
push_undo, progress);
|
2012-04-25 22:10:27 +08:00
|
|
|
}
|
app: use GimpObjectQueue in lots of places
Use GimpObjectQueue, added in the previous commit, in various
instances where we perform an action on a set of objects. This
improves progress reporting, by using a single progress for the
entire operation, rather than reporting the progress of each object
individually, and by taking the relative cost of each object into
account, instead of assuming a uniform cost for all objects.
In particular, this affects the various whole-image operations
(i.e., transformations and color conversions), operations on linked
items, and operations on layer groups. This also affects layers
with masks, whose progress is now reported together instead of
individually.
Additionally, this commit fixes erroneous group-layer mask cropping
during undo when resizing the image, by properly calling
{start,end}_move() on all the resized layers before starting the
operation, and when scaling the image, by only scaling top-level
layers, and letting group layers scale their children themselves.
2018-03-25 22:18:46 +08:00
|
|
|
|
|
|
|
g_clear_object (&queue);
|
2012-04-25 22:10:27 +08:00
|
|
|
}
|
|
|
|
|
2003-09-04 19:33:06 +08:00
|
|
|
static void
|
|
|
|
gimp_layer_invalidate_boundary (GimpDrawable *drawable)
|
|
|
|
{
|
2004-02-02 04:38:26 +08:00
|
|
|
GimpLayer *layer = GIMP_LAYER (drawable);
|
2006-03-29 01:08:36 +08:00
|
|
|
GimpImage *image;
|
2003-09-04 19:33:06 +08:00
|
|
|
GimpChannel *mask;
|
|
|
|
|
2006-03-29 01:08:36 +08:00
|
|
|
if (! (image = gimp_item_get_image (GIMP_ITEM (layer))))
|
2003-09-04 19:33:06 +08:00
|
|
|
return;
|
|
|
|
|
|
|
|
/* Turn the current selection off */
|
2010-10-10 02:23:05 +08:00
|
|
|
gimp_image_selection_invalidate (image);
|
2003-09-04 19:33:06 +08:00
|
|
|
|
|
|
|
/* get the selection mask channel */
|
2006-03-29 01:08:36 +08:00
|
|
|
mask = gimp_image_get_mask (image);
|
2003-09-04 19:33:06 +08:00
|
|
|
|
|
|
|
/* Only bother with the bounds if there is a selection */
|
|
|
|
if (! gimp_channel_is_empty (mask))
|
|
|
|
{
|
|
|
|
mask->bounds_known = FALSE;
|
|
|
|
mask->boundary_known = FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (gimp_layer_is_floating_sel (layer))
|
|
|
|
floating_sel_invalidate (layer);
|
2003-05-12 23:56:36 +08:00
|
|
|
}
|
|
|
|
|
2009-09-04 17:31:19 +08:00
|
|
|
static void
|
2016-05-20 05:51:44 +08:00
|
|
|
gimp_layer_get_active_components (GimpDrawable *drawable,
|
|
|
|
gboolean *active)
|
2009-09-04 17:31:19 +08:00
|
|
|
{
|
2012-04-25 19:35:37 +08:00
|
|
|
GimpLayer *layer = GIMP_LAYER (drawable);
|
|
|
|
GimpImage *image = gimp_item_get_image (GIMP_ITEM (drawable));
|
|
|
|
const Babl *format = gimp_drawable_get_format (drawable);
|
2009-09-04 17:31:19 +08:00
|
|
|
|
|
|
|
/* first copy the image active channels */
|
2010-02-04 16:08:50 +08:00
|
|
|
gimp_image_get_active_array (image, active);
|
2009-09-04 17:31:19 +08:00
|
|
|
|
|
|
|
if (gimp_drawable_has_alpha (drawable) && layer->lock_alpha)
|
2012-04-25 19:35:37 +08:00
|
|
|
active[babl_format_get_n_components (format) - 1] = FALSE;
|
2009-09-04 17:31:19 +08:00
|
|
|
}
|
|
|
|
|
2012-04-26 05:23:31 +08:00
|
|
|
static GimpComponentMask
|
2016-05-20 05:51:44 +08:00
|
|
|
gimp_layer_get_active_mask (GimpDrawable *drawable)
|
2012-04-26 05:23:31 +08:00
|
|
|
{
|
|
|
|
GimpLayer *layer = GIMP_LAYER (drawable);
|
|
|
|
GimpImage *image = gimp_item_get_image (GIMP_ITEM (drawable));
|
|
|
|
GimpComponentMask mask = gimp_image_get_active_mask (image);
|
|
|
|
|
|
|
|
if (gimp_drawable_has_alpha (drawable) && layer->lock_alpha)
|
2015-09-07 06:35:02 +08:00
|
|
|
mask &= ~GIMP_COMPONENT_MASK_ALPHA;
|
2012-04-26 05:23:31 +08:00
|
|
|
|
|
|
|
return mask;
|
|
|
|
}
|
|
|
|
|
2013-06-30 05:34:12 +08:00
|
|
|
static void
|
|
|
|
gimp_layer_set_buffer (GimpDrawable *drawable,
|
|
|
|
gboolean push_undo,
|
|
|
|
const gchar *undo_desc,
|
|
|
|
GeglBuffer *buffer,
|
|
|
|
gint offset_x,
|
|
|
|
gint offset_y)
|
|
|
|
{
|
2018-02-10 18:26:26 +08:00
|
|
|
GeglBuffer *old_buffer = gimp_drawable_get_buffer (drawable);
|
|
|
|
gint old_linear = -1;
|
|
|
|
|
|
|
|
if (old_buffer)
|
|
|
|
old_linear = gimp_drawable_get_linear (drawable);
|
2013-06-30 05:34:12 +08:00
|
|
|
|
|
|
|
GIMP_DRAWABLE_CLASS (parent_class)->set_buffer (drawable,
|
|
|
|
push_undo, undo_desc,
|
|
|
|
buffer,
|
|
|
|
offset_x, offset_y);
|
|
|
|
|
2018-02-14 23:29:35 +08:00
|
|
|
if (gimp_filter_peek_node (GIMP_FILTER (drawable)))
|
2013-06-30 05:34:12 +08:00
|
|
|
{
|
2018-02-14 23:29:35 +08:00
|
|
|
if (gimp_drawable_get_linear (drawable) != old_linear)
|
2015-08-30 04:39:35 +08:00
|
|
|
gimp_layer_update_mode_node (GIMP_LAYER (drawable));
|
2013-06-30 05:34:12 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-09-03 06:19:05 +08:00
|
|
|
static GimpColorProfile *
|
|
|
|
gimp_layer_get_color_profile (GimpColorManaged *managed)
|
|
|
|
{
|
|
|
|
GimpImage *image = gimp_item_get_image (GIMP_ITEM (managed));
|
|
|
|
|
|
|
|
return gimp_color_managed_get_color_profile (GIMP_COLOR_MANAGED (image));
|
|
|
|
}
|
|
|
|
|
2012-04-21 22:05:49 +08:00
|
|
|
static gdouble
|
2005-07-12 03:21:52 +08:00
|
|
|
gimp_layer_get_opacity_at (GimpPickable *pickable,
|
2006-04-12 20:49:29 +08:00
|
|
|
gint x,
|
|
|
|
gint y)
|
2005-07-12 03:21:52 +08:00
|
|
|
{
|
|
|
|
GimpLayer *layer = GIMP_LAYER (pickable);
|
2012-04-21 22:05:49 +08:00
|
|
|
gdouble value = GIMP_OPACITY_TRANSPARENT;
|
2005-07-12 03:21:52 +08:00
|
|
|
|
2008-11-03 08:09:01 +08:00
|
|
|
if (x >= 0 && x < gimp_item_get_width (GIMP_ITEM (layer)) &&
|
|
|
|
y >= 0 && y < gimp_item_get_height (GIMP_ITEM (layer)) &&
|
2012-05-16 01:46:47 +08:00
|
|
|
gimp_item_is_visible (GIMP_ITEM (layer)))
|
2005-07-12 03:21:52 +08:00
|
|
|
{
|
|
|
|
if (! gimp_drawable_has_alpha (GIMP_DRAWABLE (layer)))
|
2012-04-21 22:05:49 +08:00
|
|
|
{
|
|
|
|
value = GIMP_OPACITY_OPAQUE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
gegl_buffer_sample (gimp_drawable_get_buffer (GIMP_DRAWABLE (layer)),
|
|
|
|
x, y, NULL, &value, babl_format ("A double"),
|
|
|
|
GEGL_SAMPLER_NEAREST, GEGL_ABYSS_NONE);
|
|
|
|
}
|
2005-07-12 03:21:52 +08:00
|
|
|
|
2016-05-23 01:53:10 +08:00
|
|
|
if (gimp_layer_get_mask (layer) &&
|
|
|
|
gimp_layer_get_apply_mask (layer))
|
2006-04-12 20:49:29 +08:00
|
|
|
{
|
2012-04-21 22:05:49 +08:00
|
|
|
gdouble mask_value;
|
2005-07-12 03:21:52 +08:00
|
|
|
|
2012-03-19 02:56:56 +08:00
|
|
|
mask_value = gimp_pickable_get_opacity_at (GIMP_PICKABLE (layer->mask),
|
|
|
|
x, y);
|
2005-07-12 03:21:52 +08:00
|
|
|
|
2012-04-21 22:05:49 +08:00
|
|
|
value *= mask_value;
|
2006-04-12 20:49:29 +08:00
|
|
|
}
|
2005-07-12 03:21:52 +08:00
|
|
|
}
|
|
|
|
|
2012-03-19 02:56:56 +08:00
|
|
|
return value;
|
2005-07-12 03:21:52 +08:00
|
|
|
}
|
|
|
|
|
2016-05-23 05:28:31 +08:00
|
|
|
static void
|
|
|
|
gimp_layer_pixel_to_srgb (GimpPickable *pickable,
|
|
|
|
const Babl *format,
|
|
|
|
gpointer pixel,
|
|
|
|
GimpRGB *color)
|
|
|
|
{
|
|
|
|
GimpImage *image = gimp_item_get_image (GIMP_ITEM (pickable));
|
|
|
|
|
|
|
|
gimp_pickable_pixel_to_srgb (GIMP_PICKABLE (image), format, pixel, color);
|
|
|
|
}
|
|
|
|
|
2016-05-23 07:25:35 +08:00
|
|
|
static void
|
|
|
|
gimp_layer_srgb_to_pixel (GimpPickable *pickable,
|
|
|
|
const GimpRGB *color,
|
|
|
|
const Babl *format,
|
|
|
|
gpointer pixel)
|
|
|
|
{
|
|
|
|
GimpImage *image = gimp_item_get_image (GIMP_ITEM (pickable));
|
|
|
|
|
|
|
|
gimp_pickable_srgb_to_pixel (GIMP_PICKABLE (image), color, format, pixel);
|
|
|
|
}
|
|
|
|
|
2017-06-17 08:15:56 +08:00
|
|
|
static void
|
|
|
|
gimp_layer_real_translate (GimpLayer *layer,
|
|
|
|
gint offset_x,
|
|
|
|
gint offset_y)
|
|
|
|
{
|
|
|
|
/* update the old region */
|
|
|
|
gimp_drawable_update (GIMP_DRAWABLE (layer), 0, 0, -1, -1);
|
|
|
|
|
|
|
|
/* invalidate the selection boundary because of a layer modification */
|
|
|
|
gimp_drawable_invalidate_boundary (GIMP_DRAWABLE (layer));
|
|
|
|
|
|
|
|
GIMP_ITEM_CLASS (parent_class)->translate (GIMP_ITEM (layer),
|
|
|
|
offset_x, offset_y,
|
|
|
|
FALSE);
|
|
|
|
|
|
|
|
/* update the new region */
|
|
|
|
gimp_drawable_update (GIMP_DRAWABLE (layer), 0, 0, -1, -1);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gimp_layer_real_scale (GimpLayer *layer,
|
|
|
|
gint new_width,
|
|
|
|
gint new_height,
|
|
|
|
gint new_offset_x,
|
|
|
|
gint new_offset_y,
|
|
|
|
GimpInterpolationType interpolation_type,
|
|
|
|
GimpProgress *progress)
|
|
|
|
{
|
|
|
|
GIMP_ITEM_CLASS (parent_class)->scale (GIMP_ITEM (layer),
|
|
|
|
new_width, new_height,
|
|
|
|
new_offset_x, new_offset_y,
|
|
|
|
interpolation_type, progress);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gimp_layer_real_resize (GimpLayer *layer,
|
|
|
|
GimpContext *context,
|
|
|
|
GimpFillType fill_type,
|
|
|
|
gint new_width,
|
|
|
|
gint new_height,
|
|
|
|
gint offset_x,
|
|
|
|
gint offset_y)
|
|
|
|
{
|
|
|
|
if (fill_type == GIMP_FILL_TRANSPARENT &&
|
|
|
|
! gimp_drawable_has_alpha (GIMP_DRAWABLE (layer)))
|
|
|
|
{
|
|
|
|
fill_type = GIMP_FILL_BACKGROUND;
|
|
|
|
}
|
|
|
|
|
|
|
|
GIMP_ITEM_CLASS (parent_class)->resize (GIMP_ITEM (layer),
|
|
|
|
context, fill_type,
|
|
|
|
new_width, new_height,
|
|
|
|
offset_x, offset_y);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gimp_layer_real_flip (GimpLayer *layer,
|
|
|
|
GimpContext *context,
|
|
|
|
GimpOrientationType flip_type,
|
|
|
|
gdouble axis,
|
|
|
|
gboolean clip_result)
|
|
|
|
{
|
|
|
|
GIMP_ITEM_CLASS (parent_class)->flip (GIMP_ITEM (layer),
|
|
|
|
context, flip_type, axis, clip_result);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gimp_layer_real_rotate (GimpLayer *layer,
|
|
|
|
GimpContext *context,
|
|
|
|
GimpRotationType rotate_type,
|
|
|
|
gdouble center_x,
|
|
|
|
gdouble center_y,
|
|
|
|
gboolean clip_result)
|
|
|
|
{
|
|
|
|
GIMP_ITEM_CLASS (parent_class)->rotate (GIMP_ITEM (layer),
|
|
|
|
context, rotate_type,
|
|
|
|
center_x, center_y,
|
|
|
|
clip_result);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gimp_layer_real_transform (GimpLayer *layer,
|
|
|
|
GimpContext *context,
|
|
|
|
const GimpMatrix3 *matrix,
|
|
|
|
GimpTransformDirection direction,
|
|
|
|
GimpInterpolationType interpolation_type,
|
|
|
|
GimpTransformResize clip_result,
|
|
|
|
GimpProgress *progress)
|
|
|
|
{
|
|
|
|
GIMP_ITEM_CLASS (parent_class)->transform (GIMP_ITEM (layer),
|
|
|
|
context, matrix, direction,
|
|
|
|
interpolation_type,
|
|
|
|
clip_result,
|
|
|
|
progress);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gimp_layer_real_convert_type (GimpLayer *layer,
|
|
|
|
GimpImage *dest_image,
|
|
|
|
const Babl *new_format,
|
|
|
|
GimpColorProfile *dest_profile,
|
|
|
|
GeglDitherMethod layer_dither_type,
|
|
|
|
GeglDitherMethod mask_dither_type,
|
|
|
|
gboolean push_undo,
|
|
|
|
GimpProgress *progress)
|
|
|
|
{
|
|
|
|
GimpDrawable *drawable = GIMP_DRAWABLE (layer);
|
|
|
|
GeglBuffer *src_buffer;
|
|
|
|
GeglBuffer *dest_buffer;
|
|
|
|
|
|
|
|
if (layer_dither_type == GEGL_DITHER_NONE)
|
|
|
|
{
|
|
|
|
src_buffer = g_object_ref (gimp_drawable_get_buffer (drawable));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
gint bits;
|
|
|
|
|
|
|
|
src_buffer =
|
|
|
|
gegl_buffer_new (GEGL_RECTANGLE (0, 0,
|
|
|
|
gimp_item_get_width (GIMP_ITEM (layer)),
|
|
|
|
gimp_item_get_height (GIMP_ITEM (layer))),
|
|
|
|
gimp_drawable_get_format (drawable));
|
|
|
|
|
|
|
|
bits = (babl_format_get_bytes_per_pixel (new_format) * 8 /
|
|
|
|
babl_format_get_n_components (new_format));
|
|
|
|
|
|
|
|
gimp_gegl_apply_dither (gimp_drawable_get_buffer (drawable),
|
|
|
|
NULL, NULL,
|
|
|
|
src_buffer, 1 << bits, layer_dither_type);
|
|
|
|
}
|
|
|
|
|
|
|
|
dest_buffer =
|
|
|
|
gegl_buffer_new (GEGL_RECTANGLE (0, 0,
|
|
|
|
gimp_item_get_width (GIMP_ITEM (layer)),
|
|
|
|
gimp_item_get_height (GIMP_ITEM (layer))),
|
|
|
|
new_format);
|
|
|
|
|
|
|
|
if (dest_profile)
|
|
|
|
{
|
|
|
|
GimpColorProfile *src_profile =
|
|
|
|
gimp_color_managed_get_color_profile (GIMP_COLOR_MANAGED (layer));
|
|
|
|
|
|
|
|
gimp_gegl_convert_color_profile (src_buffer, NULL, src_profile,
|
|
|
|
dest_buffer, NULL, dest_profile,
|
|
|
|
GIMP_COLOR_RENDERING_INTENT_PERCEPTUAL,
|
|
|
|
TRUE, progress);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2018-05-24 22:21:21 +08:00
|
|
|
gimp_gegl_buffer_copy (src_buffer, NULL, GEGL_ABYSS_NONE,
|
|
|
|
dest_buffer, NULL);
|
2017-06-17 08:15:56 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
gimp_drawable_set_buffer (drawable, push_undo, NULL, dest_buffer);
|
|
|
|
|
|
|
|
g_object_unref (src_buffer);
|
|
|
|
g_object_unref (dest_buffer);
|
|
|
|
}
|
|
|
|
|
2017-12-07 02:10:38 +08:00
|
|
|
static void
|
|
|
|
gimp_layer_real_get_effective_mode (GimpLayer *layer,
|
|
|
|
GimpLayerMode *mode,
|
|
|
|
GimpLayerColorSpace *blend_space,
|
|
|
|
GimpLayerColorSpace *composite_space,
|
|
|
|
GimpLayerCompositeMode *composite_mode)
|
|
|
|
{
|
|
|
|
*mode = gimp_layer_get_mode (layer);
|
|
|
|
*blend_space = gimp_layer_get_real_blend_space (layer);
|
|
|
|
*composite_space = gimp_layer_get_real_composite_space (layer);
|
|
|
|
*composite_mode = gimp_layer_get_real_composite_mode (layer);
|
|
|
|
}
|
|
|
|
|
2017-05-08 06:49:38 +08:00
|
|
|
static gboolean
|
|
|
|
gimp_layer_real_get_excludes_backdrop (GimpLayer *layer)
|
|
|
|
{
|
|
|
|
GimpLayerCompositeRegion included_region;
|
|
|
|
|
|
|
|
included_region = gimp_layer_mode_get_included_region (layer->mode,
|
2017-12-07 02:10:38 +08:00
|
|
|
layer->effective_composite_mode);
|
2017-05-08 06:49:38 +08:00
|
|
|
|
|
|
|
return ! (included_region & GIMP_LAYER_COMPOSITE_REGION_DESTINATION);
|
|
|
|
}
|
|
|
|
|
To optimize duplicate and/or wrong image updates away, introduced new
2003-09-06 Michael Natterer <mitch@gimp.org>
To optimize duplicate and/or wrong image updates away, introduced
new policy that a child object must never explicitly update or
invalidate its parent object (just like the GUI is not updated
explicitly by the core):
* app/core/gimpdrawable.[ch]: added new signal
GimpDrawable::update(). Never update or invalidate the image when
the drawable is updated or invalidated.
(gimp_drawable_set_visible): don't gimp_drawable_update() the
drawable since its pixels have not changed.
* app/core/gimpimage.[ch]: connect to the "add" and "remove"
signals of the layers and channels containers. Also connect to the
"update" and "visibility_changed" signals of all drawables in
these containers (optimizes away updates issued by drawables which
are not yet added to the image and updates of the selection
mask). Also, don't propagate updates to the image if the emitting
drawable is invisible (optimizes away updates issued by invisible
drawables).
(gimp_image_add_layer,channel)
(gimp_image_remove_layer,channel): don't update the image since
that's done by our "add" and "remove" handlers now.
(gimp_image_position_layer,channel): update just the image, not
the drawable since its pixels have not changed.
(gimp_image_real_colormap_changed)
(gimp_image_set_component_visible): always call
gimp_image_update() *and* gimp_viewable_invalidate_preview() to
get everything updated, since update and invalidate of images are
not connected.
* app/core/gimpimage-undo-push.c (undo_pop_layer,channel): don't
update the drawable since (a) its pixels don't change and (b) the
image updates itself upon adding/removing now.
(undo_pop_layer_mod): replaced gimp_image_update() by
gimp_drawable_update() (just for consistency with other similar
functions).
* app/core/gimplayer.c: connect to "update" of the layer mask and
issue updates on the layer if the mask update has any effect on
the projection.
(gimp_layer_create_mask): don't set the mask's offsets here since
they may be different when we later add the mask to the layer.
* app/core/gimplayermask.c (gimp_layer_mask_set_layer): set the
mask offsets here instead.
* app/core/gimpchannel.c (gimp_channel_translate): update the
channel even if push_undo == FALSE.
* app/paint/gimppaintcore.c (gimp_paint_core_finish)
* app/tools/gimpinktool.c (ink_finish): invalidate both the
drawable and the image preview since invalidating the drawable
doesn't invalidate the image any more.
* app/text/gimptextlayer.c (gimp_text_layer_render_now): also
update the new extents of the text layer, not only the old one.
(gimp_text_layer_render_layout): don't update the drawable since
gimp_drawable_fill() already updated it.
2003-09-07 04:06:53 +08:00
|
|
|
static void
|
|
|
|
gimp_layer_layer_mask_update (GimpDrawable *drawable,
|
|
|
|
gint x,
|
|
|
|
gint y,
|
|
|
|
gint width,
|
|
|
|
gint height,
|
|
|
|
GimpLayer *layer)
|
|
|
|
{
|
2012-03-18 01:30:13 +08:00
|
|
|
if (gimp_layer_get_apply_mask (layer) ||
|
|
|
|
gimp_layer_get_show_mask (layer))
|
To optimize duplicate and/or wrong image updates away, introduced new
2003-09-06 Michael Natterer <mitch@gimp.org>
To optimize duplicate and/or wrong image updates away, introduced
new policy that a child object must never explicitly update or
invalidate its parent object (just like the GUI is not updated
explicitly by the core):
* app/core/gimpdrawable.[ch]: added new signal
GimpDrawable::update(). Never update or invalidate the image when
the drawable is updated or invalidated.
(gimp_drawable_set_visible): don't gimp_drawable_update() the
drawable since its pixels have not changed.
* app/core/gimpimage.[ch]: connect to the "add" and "remove"
signals of the layers and channels containers. Also connect to the
"update" and "visibility_changed" signals of all drawables in
these containers (optimizes away updates issued by drawables which
are not yet added to the image and updates of the selection
mask). Also, don't propagate updates to the image if the emitting
drawable is invisible (optimizes away updates issued by invisible
drawables).
(gimp_image_add_layer,channel)
(gimp_image_remove_layer,channel): don't update the image since
that's done by our "add" and "remove" handlers now.
(gimp_image_position_layer,channel): update just the image, not
the drawable since its pixels have not changed.
(gimp_image_real_colormap_changed)
(gimp_image_set_component_visible): always call
gimp_image_update() *and* gimp_viewable_invalidate_preview() to
get everything updated, since update and invalidate of images are
not connected.
* app/core/gimpimage-undo-push.c (undo_pop_layer,channel): don't
update the drawable since (a) its pixels don't change and (b) the
image updates itself upon adding/removing now.
(undo_pop_layer_mod): replaced gimp_image_update() by
gimp_drawable_update() (just for consistency with other similar
functions).
* app/core/gimplayer.c: connect to "update" of the layer mask and
issue updates on the layer if the mask update has any effect on
the projection.
(gimp_layer_create_mask): don't set the mask's offsets here since
they may be different when we later add the mask to the layer.
* app/core/gimplayermask.c (gimp_layer_mask_set_layer): set the
mask offsets here instead.
* app/core/gimpchannel.c (gimp_channel_translate): update the
channel even if push_undo == FALSE.
* app/paint/gimppaintcore.c (gimp_paint_core_finish)
* app/tools/gimpinktool.c (ink_finish): invalidate both the
drawable and the image preview since invalidating the drawable
doesn't invalidate the image any more.
* app/text/gimptextlayer.c (gimp_text_layer_render_now): also
update the new extents of the text layer, not only the old one.
(gimp_text_layer_render_layout): don't update the drawable since
gimp_drawable_fill() already updated it.
2003-09-07 04:06:53 +08:00
|
|
|
{
|
|
|
|
gimp_drawable_update (GIMP_DRAWABLE (layer),
|
|
|
|
x, y, width, height);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* public functions */
|
1997-11-25 06:05:25 +08:00
|
|
|
|
2010-02-07 19:03:07 +08:00
|
|
|
GimpLayer *
|
|
|
|
gimp_layer_get_parent (GimpLayer *layer)
|
|
|
|
{
|
|
|
|
g_return_val_if_fail (GIMP_IS_LAYER (layer), NULL);
|
|
|
|
|
|
|
|
return GIMP_LAYER (gimp_viewable_get_parent (GIMP_VIEWABLE (layer)));
|
|
|
|
}
|
|
|
|
|
2009-07-31 00:59:12 +08:00
|
|
|
GimpLayerMask *
|
2016-05-20 05:51:44 +08:00
|
|
|
gimp_layer_get_mask (GimpLayer *layer)
|
2009-07-31 00:59:12 +08:00
|
|
|
{
|
|
|
|
g_return_val_if_fail (GIMP_IS_LAYER (layer), NULL);
|
|
|
|
|
|
|
|
return layer->mask;
|
|
|
|
}
|
|
|
|
|
2001-01-29 00:44:22 +08:00
|
|
|
GimpLayerMask *
|
2008-09-16 05:05:01 +08:00
|
|
|
gimp_layer_add_mask (GimpLayer *layer,
|
|
|
|
GimpLayerMask *mask,
|
|
|
|
gboolean push_undo,
|
|
|
|
GError **error)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
2006-03-29 01:08:36 +08:00
|
|
|
GimpImage *image;
|
2001-03-05 04:06:48 +08:00
|
|
|
|
|
|
|
g_return_val_if_fail (GIMP_IS_LAYER (layer), NULL);
|
|
|
|
g_return_val_if_fail (GIMP_IS_LAYER_MASK (mask), NULL);
|
2008-10-06 17:26:44 +08:00
|
|
|
g_return_val_if_fail (gimp_item_get_image (GIMP_ITEM (layer)) ==
|
|
|
|
gimp_item_get_image (GIMP_ITEM (mask)), NULL);
|
2008-09-16 05:05:01 +08:00
|
|
|
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
|
2001-03-05 04:06:48 +08:00
|
|
|
|
2004-11-16 21:41:55 +08:00
|
|
|
if (! gimp_item_is_attached (GIMP_ITEM (layer)))
|
|
|
|
push_undo = FALSE;
|
|
|
|
|
2006-03-29 01:08:36 +08:00
|
|
|
image = gimp_item_get_image (GIMP_ITEM (layer));
|
2001-03-05 04:06:48 +08:00
|
|
|
|
1997-11-25 06:05:25 +08:00
|
|
|
if (layer->mask)
|
2001-03-05 04:06:48 +08:00
|
|
|
{
|
2008-11-12 18:56:06 +08:00
|
|
|
g_set_error_literal (error, GIMP_ERROR, GIMP_FAILED,
|
2015-11-11 22:19:45 +08:00
|
|
|
_("Unable to add a layer mask since "
|
|
|
|
"the layer already has one."));
|
2001-03-05 04:06:48 +08:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2008-11-03 08:09:01 +08:00
|
|
|
if ((gimp_item_get_width (GIMP_ITEM (layer)) !=
|
|
|
|
gimp_item_get_width (GIMP_ITEM (mask))) ||
|
|
|
|
(gimp_item_get_height (GIMP_ITEM (layer)) !=
|
|
|
|
gimp_item_get_height (GIMP_ITEM (mask))))
|
2001-03-05 04:06:48 +08:00
|
|
|
{
|
2008-11-12 18:56:06 +08:00
|
|
|
g_set_error_literal (error, GIMP_ERROR, GIMP_FAILED,
|
2015-11-11 22:19:45 +08:00
|
|
|
_("Cannot add layer mask of different "
|
|
|
|
"dimensions than specified layer."));
|
2001-03-05 04:06:48 +08:00
|
|
|
return NULL;
|
|
|
|
}
|
1997-11-25 06:05:25 +08:00
|
|
|
|
2004-11-16 21:41:55 +08:00
|
|
|
if (push_undo)
|
2010-06-08 19:24:11 +08:00
|
|
|
gimp_image_undo_push_layer_mask_add (image, C_("undo-type", "Add Layer Mask"),
|
2004-11-16 21:41:55 +08:00
|
|
|
layer, mask);
|
|
|
|
|
2006-10-17 01:09:17 +08:00
|
|
|
layer->mask = g_object_ref_sink (mask);
|
2012-03-18 01:30:13 +08:00
|
|
|
layer->apply_mask = TRUE;
|
|
|
|
layer->edit_mask = TRUE;
|
|
|
|
layer->show_mask = FALSE;
|
2003-12-10 02:59:35 +08:00
|
|
|
|
2001-01-29 00:44:22 +08:00
|
|
|
gimp_layer_mask_set_layer (mask, layer);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
2013-04-11 08:54:42 +08:00
|
|
|
if (gimp_filter_peek_node (GIMP_FILTER (layer)))
|
2008-10-10 04:44:23 +08:00
|
|
|
{
|
2012-05-17 01:45:18 +08:00
|
|
|
GeglNode *mode_node;
|
2008-10-10 04:44:23 +08:00
|
|
|
GeglNode *mask;
|
|
|
|
|
2012-05-17 01:45:18 +08:00
|
|
|
mode_node = gimp_drawable_get_mode_node (GIMP_DRAWABLE (layer));
|
|
|
|
|
2008-10-10 04:44:23 +08:00
|
|
|
mask = gimp_drawable_get_source_node (GIMP_DRAWABLE (layer->mask));
|
|
|
|
|
2012-05-17 01:45:18 +08:00
|
|
|
gegl_node_connect_to (mask, "output",
|
|
|
|
layer->mask_offset_node, "input");
|
|
|
|
|
2012-03-20 05:22:05 +08:00
|
|
|
if (layer->show_mask)
|
|
|
|
{
|
2012-05-17 01:45:18 +08:00
|
|
|
gegl_node_connect_to (layer->mask_offset_node, "output",
|
|
|
|
mode_node, "aux");
|
2012-03-20 05:22:05 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2012-05-17 01:45:18 +08:00
|
|
|
gegl_node_connect_to (layer->mask_offset_node, "output",
|
|
|
|
mode_node, "aux2");
|
2012-03-20 05:22:05 +08:00
|
|
|
}
|
2015-08-30 04:39:35 +08:00
|
|
|
|
2015-09-01 16:26:21 +08:00
|
|
|
gimp_layer_update_mode_node (layer);
|
2008-10-10 04:44:23 +08:00
|
|
|
}
|
|
|
|
|
2012-03-18 01:30:13 +08:00
|
|
|
if (gimp_layer_get_apply_mask (layer) ||
|
|
|
|
gimp_layer_get_show_mask (layer))
|
To optimize duplicate and/or wrong image updates away, introduced new
2003-09-06 Michael Natterer <mitch@gimp.org>
To optimize duplicate and/or wrong image updates away, introduced
new policy that a child object must never explicitly update or
invalidate its parent object (just like the GUI is not updated
explicitly by the core):
* app/core/gimpdrawable.[ch]: added new signal
GimpDrawable::update(). Never update or invalidate the image when
the drawable is updated or invalidated.
(gimp_drawable_set_visible): don't gimp_drawable_update() the
drawable since its pixels have not changed.
* app/core/gimpimage.[ch]: connect to the "add" and "remove"
signals of the layers and channels containers. Also connect to the
"update" and "visibility_changed" signals of all drawables in
these containers (optimizes away updates issued by drawables which
are not yet added to the image and updates of the selection
mask). Also, don't propagate updates to the image if the emitting
drawable is invisible (optimizes away updates issued by invisible
drawables).
(gimp_image_add_layer,channel)
(gimp_image_remove_layer,channel): don't update the image since
that's done by our "add" and "remove" handlers now.
(gimp_image_position_layer,channel): update just the image, not
the drawable since its pixels have not changed.
(gimp_image_real_colormap_changed)
(gimp_image_set_component_visible): always call
gimp_image_update() *and* gimp_viewable_invalidate_preview() to
get everything updated, since update and invalidate of images are
not connected.
* app/core/gimpimage-undo-push.c (undo_pop_layer,channel): don't
update the drawable since (a) its pixels don't change and (b) the
image updates itself upon adding/removing now.
(undo_pop_layer_mod): replaced gimp_image_update() by
gimp_drawable_update() (just for consistency with other similar
functions).
* app/core/gimplayer.c: connect to "update" of the layer mask and
issue updates on the layer if the mask update has any effect on
the projection.
(gimp_layer_create_mask): don't set the mask's offsets here since
they may be different when we later add the mask to the layer.
* app/core/gimplayermask.c (gimp_layer_mask_set_layer): set the
mask offsets here instead.
* app/core/gimpchannel.c (gimp_channel_translate): update the
channel even if push_undo == FALSE.
* app/paint/gimppaintcore.c (gimp_paint_core_finish)
* app/tools/gimpinktool.c (ink_finish): invalidate both the
drawable and the image preview since invalidating the drawable
doesn't invalidate the image any more.
* app/text/gimptextlayer.c (gimp_text_layer_render_now): also
update the new extents of the text layer, not only the old one.
(gimp_text_layer_render_layout): don't update the drawable since
gimp_drawable_fill() already updated it.
2003-09-07 04:06:53 +08:00
|
|
|
{
|
2017-01-13 09:14:40 +08:00
|
|
|
gimp_drawable_update (GIMP_DRAWABLE (layer), 0, 0, -1, -1);
|
To optimize duplicate and/or wrong image updates away, introduced new
2003-09-06 Michael Natterer <mitch@gimp.org>
To optimize duplicate and/or wrong image updates away, introduced
new policy that a child object must never explicitly update or
invalidate its parent object (just like the GUI is not updated
explicitly by the core):
* app/core/gimpdrawable.[ch]: added new signal
GimpDrawable::update(). Never update or invalidate the image when
the drawable is updated or invalidated.
(gimp_drawable_set_visible): don't gimp_drawable_update() the
drawable since its pixels have not changed.
* app/core/gimpimage.[ch]: connect to the "add" and "remove"
signals of the layers and channels containers. Also connect to the
"update" and "visibility_changed" signals of all drawables in
these containers (optimizes away updates issued by drawables which
are not yet added to the image and updates of the selection
mask). Also, don't propagate updates to the image if the emitting
drawable is invisible (optimizes away updates issued by invisible
drawables).
(gimp_image_add_layer,channel)
(gimp_image_remove_layer,channel): don't update the image since
that's done by our "add" and "remove" handlers now.
(gimp_image_position_layer,channel): update just the image, not
the drawable since its pixels have not changed.
(gimp_image_real_colormap_changed)
(gimp_image_set_component_visible): always call
gimp_image_update() *and* gimp_viewable_invalidate_preview() to
get everything updated, since update and invalidate of images are
not connected.
* app/core/gimpimage-undo-push.c (undo_pop_layer,channel): don't
update the drawable since (a) its pixels don't change and (b) the
image updates itself upon adding/removing now.
(undo_pop_layer_mod): replaced gimp_image_update() by
gimp_drawable_update() (just for consistency with other similar
functions).
* app/core/gimplayer.c: connect to "update" of the layer mask and
issue updates on the layer if the mask update has any effect on
the projection.
(gimp_layer_create_mask): don't set the mask's offsets here since
they may be different when we later add the mask to the layer.
* app/core/gimplayermask.c (gimp_layer_mask_set_layer): set the
mask offsets here instead.
* app/core/gimpchannel.c (gimp_channel_translate): update the
channel even if push_undo == FALSE.
* app/paint/gimppaintcore.c (gimp_paint_core_finish)
* app/tools/gimpinktool.c (ink_finish): invalidate both the
drawable and the image preview since invalidating the drawable
doesn't invalidate the image any more.
* app/text/gimptextlayer.c (gimp_text_layer_render_now): also
update the new extents of the text layer, not only the old one.
(gimp_text_layer_render_layout): don't update the drawable since
gimp_drawable_fill() already updated it.
2003-09-07 04:06:53 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
g_signal_connect (mask, "update",
|
|
|
|
G_CALLBACK (gimp_layer_layer_mask_update),
|
|
|
|
layer);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
2003-01-06 06:07:10 +08:00
|
|
|
g_signal_emit (layer, layer_signals[MASK_CHANGED], 0);
|
2001-03-05 04:06:48 +08:00
|
|
|
|
2008-11-20 07:37:15 +08:00
|
|
|
g_object_notify (G_OBJECT (layer), "mask");
|
|
|
|
|
2011-01-31 02:36:27 +08:00
|
|
|
/* if the mask came from the undo stack, reset its "removed" state */
|
|
|
|
if (gimp_item_is_removed (GIMP_ITEM (mask)))
|
2011-01-31 04:57:45 +08:00
|
|
|
gimp_item_unset_removed (GIMP_ITEM (mask));
|
2011-01-31 02:36:27 +08:00
|
|
|
|
1997-11-25 06:05:25 +08:00
|
|
|
return layer->mask;
|
|
|
|
}
|
|
|
|
|
2001-01-29 00:44:22 +08:00
|
|
|
GimpLayerMask *
|
2016-05-20 05:51:44 +08:00
|
|
|
gimp_layer_create_mask (GimpLayer *layer,
|
2006-05-15 00:24:31 +08:00
|
|
|
GimpAddMaskType add_mask_type,
|
|
|
|
GimpChannel *channel)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
2003-05-08 01:00:57 +08:00
|
|
|
GimpDrawable *drawable;
|
2003-05-08 19:52:31 +08:00
|
|
|
GimpItem *item;
|
2001-01-29 00:44:22 +08:00
|
|
|
GimpLayerMask *mask;
|
2006-03-29 01:08:36 +08:00
|
|
|
GimpImage *image;
|
2001-01-29 00:44:22 +08:00
|
|
|
gchar *mask_name;
|
2002-03-04 01:38:12 +08:00
|
|
|
GimpRGB black = { 0.0, 0.0, 0.0, GIMP_OPACITY_OPAQUE };
|
1997-11-25 06:05:25 +08:00
|
|
|
|
2002-06-07 03:07:59 +08:00
|
|
|
g_return_val_if_fail (GIMP_IS_LAYER (layer), NULL);
|
2014-04-30 02:55:08 +08:00
|
|
|
g_return_val_if_fail (add_mask_type != GIMP_ADD_MASK_CHANNEL ||
|
2006-05-15 00:24:31 +08:00
|
|
|
GIMP_IS_CHANNEL (channel), NULL);
|
2002-06-07 03:07:59 +08:00
|
|
|
|
2003-05-08 01:00:57 +08:00
|
|
|
drawable = GIMP_DRAWABLE (layer);
|
2003-05-08 19:52:31 +08:00
|
|
|
item = GIMP_ITEM (layer);
|
2006-05-15 00:24:31 +08:00
|
|
|
image = gimp_item_get_image (item);
|
2001-02-28 15:54:05 +08:00
|
|
|
|
2001-01-10 11:13:03 +08:00
|
|
|
mask_name = g_strdup_printf (_("%s mask"),
|
2009-09-01 04:47:18 +08:00
|
|
|
gimp_object_get_name (layer));
|
1997-11-25 06:05:25 +08:00
|
|
|
|
2006-03-29 01:08:36 +08:00
|
|
|
mask = gimp_layer_mask_new (image,
|
2008-11-03 08:09:01 +08:00
|
|
|
gimp_item_get_width (item),
|
|
|
|
gimp_item_get_height (item),
|
2006-04-12 20:49:29 +08:00
|
|
|
mask_name, &black);
|
2002-02-21 00:15:53 +08:00
|
|
|
|
|
|
|
g_free (mask_name);
|
|
|
|
|
2002-08-27 22:17:46 +08:00
|
|
|
switch (add_mask_type)
|
|
|
|
{
|
2014-04-30 02:55:08 +08:00
|
|
|
case GIMP_ADD_MASK_WHITE:
|
2002-08-27 22:17:46 +08:00
|
|
|
gimp_channel_all (GIMP_CHANNEL (mask), FALSE);
|
|
|
|
return mask;
|
|
|
|
|
2014-04-30 02:55:08 +08:00
|
|
|
case GIMP_ADD_MASK_BLACK:
|
2003-09-03 07:07:40 +08:00
|
|
|
gimp_channel_clear (GIMP_CHANNEL (mask), NULL, FALSE);
|
2002-08-27 22:17:46 +08:00
|
|
|
return mask;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
1997-11-25 06:05:25 +08:00
|
|
|
switch (add_mask_type)
|
|
|
|
{
|
2014-04-30 02:55:08 +08:00
|
|
|
case GIMP_ADD_MASK_WHITE:
|
|
|
|
case GIMP_ADD_MASK_BLACK:
|
1997-11-25 06:05:25 +08:00
|
|
|
break;
|
2001-12-13 07:48:18 +08:00
|
|
|
|
2014-04-30 02:55:08 +08:00
|
|
|
case GIMP_ADD_MASK_ALPHA:
|
|
|
|
case GIMP_ADD_MASK_ALPHA_TRANSFER:
|
2003-05-08 01:00:57 +08:00
|
|
|
if (gimp_drawable_has_alpha (drawable))
|
2006-04-12 20:49:29 +08:00
|
|
|
{
|
2012-03-27 05:27:52 +08:00
|
|
|
GeglBuffer *dest_buffer;
|
2012-04-22 21:50:02 +08:00
|
|
|
const Babl *component_format;
|
2003-05-08 19:52:31 +08:00
|
|
|
|
2012-03-27 05:27:52 +08:00
|
|
|
dest_buffer = gimp_drawable_get_buffer (GIMP_DRAWABLE (mask));
|
2012-03-16 20:21:53 +08:00
|
|
|
|
2012-04-22 21:50:02 +08:00
|
|
|
component_format =
|
2017-01-10 02:40:30 +08:00
|
|
|
gimp_image_get_component_format (image, GIMP_CHANNEL_ALPHA);
|
2012-04-22 21:50:02 +08:00
|
|
|
|
|
|
|
gegl_buffer_set_format (dest_buffer, component_format);
|
2018-05-24 22:21:21 +08:00
|
|
|
gimp_gegl_buffer_copy (gimp_drawable_get_buffer (drawable), NULL,
|
|
|
|
GEGL_ABYSS_NONE,
|
|
|
|
dest_buffer, NULL);
|
2012-03-27 05:27:52 +08:00
|
|
|
gegl_buffer_set_format (dest_buffer, NULL);
|
2003-11-26 23:48:50 +08:00
|
|
|
|
2014-04-30 02:55:08 +08:00
|
|
|
if (add_mask_type == GIMP_ADD_MASK_ALPHA_TRANSFER)
|
2003-11-26 23:48:50 +08:00
|
|
|
{
|
2006-05-15 00:24:31 +08:00
|
|
|
gimp_drawable_push_undo (drawable,
|
2010-06-08 19:24:11 +08:00
|
|
|
C_("undo-type", "Transfer Alpha to Mask"),
|
2012-03-22 21:13:17 +08:00
|
|
|
NULL,
|
2003-11-26 23:48:50 +08:00
|
|
|
0, 0,
|
2008-11-03 08:09:01 +08:00
|
|
|
gimp_item_get_width (item),
|
2012-03-22 21:13:17 +08:00
|
|
|
gimp_item_get_height (item));
|
2003-11-26 23:48:50 +08:00
|
|
|
|
2012-11-01 06:47:45 +08:00
|
|
|
gimp_gegl_apply_set_alpha (gimp_drawable_get_buffer (drawable),
|
2012-10-22 22:03:40 +08:00
|
|
|
NULL, NULL,
|
|
|
|
gimp_drawable_get_buffer (drawable),
|
2012-11-01 06:47:45 +08:00
|
|
|
1.0);
|
2003-11-26 23:48:50 +08:00
|
|
|
}
|
2006-04-12 20:49:29 +08:00
|
|
|
}
|
1997-11-25 06:05:25 +08:00
|
|
|
break;
|
2001-12-13 07:48:18 +08:00
|
|
|
|
2014-04-30 02:55:08 +08:00
|
|
|
case GIMP_ADD_MASK_SELECTION:
|
|
|
|
case GIMP_ADD_MASK_CHANNEL:
|
2002-02-21 00:15:53 +08:00
|
|
|
{
|
2006-05-15 00:24:31 +08:00
|
|
|
gboolean channel_empty;
|
2008-11-04 05:17:50 +08:00
|
|
|
gint offset_x, offset_y;
|
2006-05-15 00:24:31 +08:00
|
|
|
gint copy_x, copy_y;
|
|
|
|
gint copy_width, copy_height;
|
2002-02-21 00:15:53 +08:00
|
|
|
|
2014-04-30 02:55:08 +08:00
|
|
|
if (add_mask_type == GIMP_ADD_MASK_SELECTION)
|
2006-05-15 00:24:31 +08:00
|
|
|
channel = GIMP_CHANNEL (gimp_image_get_mask (image));
|
|
|
|
|
|
|
|
channel_empty = gimp_channel_is_empty (channel);
|
2002-02-21 00:15:53 +08:00
|
|
|
|
2008-11-04 05:17:50 +08:00
|
|
|
gimp_item_get_offset (item, &offset_x, &offset_y);
|
|
|
|
|
2007-12-24 00:58:41 +08:00
|
|
|
gimp_rectangle_intersect (0, 0,
|
2007-12-26 00:21:40 +08:00
|
|
|
gimp_image_get_width (image),
|
|
|
|
gimp_image_get_height (image),
|
2008-11-04 05:17:50 +08:00
|
|
|
offset_x, offset_y,
|
2008-11-03 08:09:01 +08:00
|
|
|
gimp_item_get_width (item),
|
|
|
|
gimp_item_get_height (item),
|
2007-12-24 00:58:41 +08:00
|
|
|
©_x, ©_y,
|
|
|
|
©_width, ©_height);
|
2003-05-08 01:00:57 +08:00
|
|
|
|
2008-11-03 08:09:01 +08:00
|
|
|
if (copy_width < gimp_item_get_width (item) ||
|
|
|
|
copy_height < gimp_item_get_height (item) ||
|
2006-05-15 00:24:31 +08:00
|
|
|
channel_empty)
|
2003-09-03 07:07:40 +08:00
|
|
|
gimp_channel_clear (GIMP_CHANNEL (mask), NULL, FALSE);
|
2003-05-08 01:00:57 +08:00
|
|
|
|
2006-05-15 00:24:31 +08:00
|
|
|
if ((copy_width || copy_height) && ! channel_empty)
|
2003-05-08 01:00:57 +08:00
|
|
|
{
|
2012-03-15 08:39:23 +08:00
|
|
|
GeglBuffer *src;
|
|
|
|
GeglBuffer *dest;
|
|
|
|
|
2012-03-21 07:42:44 +08:00
|
|
|
src = gimp_drawable_get_buffer (GIMP_DRAWABLE (channel));
|
|
|
|
dest = gimp_drawable_get_buffer (GIMP_DRAWABLE (mask));
|
2012-03-15 08:39:23 +08:00
|
|
|
|
2018-05-24 22:21:21 +08:00
|
|
|
gimp_gegl_buffer_copy (src,
|
|
|
|
GEGL_RECTANGLE (copy_x, copy_y,
|
|
|
|
copy_width, copy_height),
|
|
|
|
GEGL_ABYSS_NONE,
|
|
|
|
dest,
|
|
|
|
GEGL_RECTANGLE (copy_x - offset_x,
|
|
|
|
copy_y - offset_y,
|
|
|
|
0, 0));
|
2012-03-15 08:39:23 +08:00
|
|
|
|
2003-05-14 23:32:07 +08:00
|
|
|
GIMP_CHANNEL (mask)->bounds_known = FALSE;
|
2003-05-08 01:00:57 +08:00
|
|
|
}
|
2002-02-21 00:15:53 +08:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2014-04-30 02:55:08 +08:00
|
|
|
case GIMP_ADD_MASK_COPY:
|
2002-02-21 00:15:53 +08:00
|
|
|
{
|
2012-03-27 05:27:52 +08:00
|
|
|
GeglBuffer *src_buffer;
|
|
|
|
GeglBuffer *dest_buffer;
|
2002-02-21 00:15:53 +08:00
|
|
|
|
2009-09-08 23:49:48 +08:00
|
|
|
if (! gimp_drawable_is_gray (drawable))
|
2003-03-03 20:36:42 +08:00
|
|
|
{
|
2012-03-27 05:27:52 +08:00
|
|
|
const Babl *copy_format =
|
2012-04-12 00:40:30 +08:00
|
|
|
gimp_image_get_format (image, GIMP_GRAY,
|
2012-05-08 03:46:47 +08:00
|
|
|
gimp_drawable_get_precision (drawable),
|
2012-04-12 00:40:30 +08:00
|
|
|
gimp_drawable_has_alpha (drawable));
|
2002-02-21 00:15:53 +08:00
|
|
|
|
2012-03-27 05:27:52 +08:00
|
|
|
src_buffer =
|
2012-05-21 04:00:27 +08:00
|
|
|
gegl_buffer_new (GEGL_RECTANGLE (0, 0,
|
|
|
|
gimp_item_get_width (item),
|
|
|
|
gimp_item_get_height (item)),
|
|
|
|
copy_format);
|
2012-03-18 05:53:17 +08:00
|
|
|
|
2018-05-24 22:21:21 +08:00
|
|
|
gimp_gegl_buffer_copy (gimp_drawable_get_buffer (drawable), NULL,
|
|
|
|
GEGL_ABYSS_NONE,
|
|
|
|
src_buffer, NULL);
|
2003-03-03 20:36:42 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2012-03-21 07:42:44 +08:00
|
|
|
src_buffer = gimp_drawable_get_buffer (drawable);
|
2012-03-16 22:15:53 +08:00
|
|
|
g_object_ref (src_buffer);
|
2003-03-03 20:36:42 +08:00
|
|
|
}
|
2002-02-21 00:15:53 +08:00
|
|
|
|
2012-03-21 07:42:44 +08:00
|
|
|
dest_buffer = gimp_drawable_get_buffer (GIMP_DRAWABLE (mask));
|
2012-03-16 22:15:53 +08:00
|
|
|
|
2003-05-08 01:00:57 +08:00
|
|
|
if (gimp_drawable_has_alpha (drawable))
|
2002-02-21 00:15:53 +08:00
|
|
|
{
|
2012-11-01 06:47:45 +08:00
|
|
|
GimpRGB background;
|
2012-03-16 22:15:53 +08:00
|
|
|
|
|
|
|
gimp_rgba_set (&background, 0.0, 0.0, 0.0, 0.0);
|
|
|
|
|
2012-11-01 06:47:45 +08:00
|
|
|
gimp_gegl_apply_flatten (src_buffer, NULL, NULL,
|
2017-10-21 23:10:29 +08:00
|
|
|
dest_buffer, &background,
|
|
|
|
GIMP_LAYER_COLOR_SPACE_RGB_LINEAR);
|
2002-02-21 00:15:53 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2018-05-24 22:21:21 +08:00
|
|
|
gimp_gegl_buffer_copy (src_buffer, NULL, GEGL_ABYSS_NONE,
|
|
|
|
dest_buffer, NULL);
|
2002-02-21 00:15:53 +08:00
|
|
|
}
|
|
|
|
|
2012-03-16 22:15:53 +08:00
|
|
|
g_object_unref (src_buffer);
|
2002-02-21 00:15:53 +08:00
|
|
|
}
|
2002-08-27 22:17:46 +08:00
|
|
|
|
|
|
|
GIMP_CHANNEL (mask)->bounds_known = FALSE;
|
2002-02-21 00:15:53 +08:00
|
|
|
break;
|
|
|
|
}
|
2001-01-29 00:44:22 +08:00
|
|
|
|
1997-11-25 06:05:25 +08:00
|
|
|
return mask;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2002-03-18 19:07:34 +08:00
|
|
|
gimp_layer_apply_mask (GimpLayer *layer,
|
2006-04-12 20:49:29 +08:00
|
|
|
GimpMaskApplyMode mode,
|
2002-03-18 19:07:34 +08:00
|
|
|
gboolean push_undo)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
2007-12-24 00:58:41 +08:00
|
|
|
GimpItem *item;
|
|
|
|
GimpImage *image;
|
|
|
|
GimpLayerMask *mask;
|
|
|
|
gboolean view_changed = FALSE;
|
2001-03-05 04:06:48 +08:00
|
|
|
|
|
|
|
g_return_if_fail (GIMP_IS_LAYER (layer));
|
1997-11-25 06:05:25 +08:00
|
|
|
|
2007-12-24 00:58:41 +08:00
|
|
|
mask = gimp_layer_get_mask (layer);
|
|
|
|
|
|
|
|
if (! mask)
|
1997-11-25 06:05:25 +08:00
|
|
|
return;
|
|
|
|
|
2018-02-06 04:13:41 +08:00
|
|
|
/* APPLY can not be done to group layers */
|
|
|
|
g_return_if_fail (! gimp_viewable_get_children (GIMP_VIEWABLE (layer)) ||
|
|
|
|
mode == GIMP_MASK_DISCARD);
|
|
|
|
|
2007-09-16 03:23:20 +08:00
|
|
|
/* APPLY can only be done to layers with an alpha channel */
|
2018-02-06 04:13:41 +08:00
|
|
|
g_return_if_fail (gimp_drawable_has_alpha (GIMP_DRAWABLE (layer)) ||
|
|
|
|
mode == GIMP_MASK_DISCARD || push_undo == TRUE);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
2007-12-24 00:58:41 +08:00
|
|
|
item = GIMP_ITEM (layer);
|
2006-03-29 01:08:36 +08:00
|
|
|
image = gimp_item_get_image (item);
|
2001-03-05 04:06:48 +08:00
|
|
|
|
2006-03-29 01:08:36 +08:00
|
|
|
if (! image)
|
2001-03-05 04:06:48 +08:00
|
|
|
return;
|
|
|
|
|
|
|
|
if (push_undo)
|
|
|
|
{
|
2006-03-29 01:08:36 +08:00
|
|
|
gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_LAYER_APPLY_MASK,
|
2004-02-29 02:56:55 +08:00
|
|
|
(mode == GIMP_MASK_APPLY) ?
|
2010-06-08 19:24:11 +08:00
|
|
|
C_("undo-type", "Apply Layer Mask") :
|
|
|
|
C_("undo-type", "Delete Layer Mask"));
|
2001-03-05 04:06:48 +08:00
|
|
|
|
2012-03-18 01:30:13 +08:00
|
|
|
gimp_image_undo_push_layer_mask_show (image, NULL, layer);
|
|
|
|
gimp_image_undo_push_layer_mask_apply (image, NULL, layer);
|
2007-12-24 00:58:41 +08:00
|
|
|
gimp_image_undo_push_layer_mask_remove (image, NULL, layer, mask);
|
2007-09-16 03:23:20 +08:00
|
|
|
|
|
|
|
if (mode == GIMP_MASK_APPLY &&
|
|
|
|
! gimp_drawable_has_alpha (GIMP_DRAWABLE (layer)))
|
|
|
|
{
|
|
|
|
gimp_layer_add_alpha (layer);
|
|
|
|
}
|
2001-03-05 04:06:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* check if applying the mask changes the projection */
|
2012-03-18 01:30:13 +08:00
|
|
|
if (gimp_layer_get_show_mask (layer) ||
|
|
|
|
(mode == GIMP_MASK_APPLY && ! gimp_layer_get_apply_mask (layer)) ||
|
|
|
|
(mode == GIMP_MASK_DISCARD && gimp_layer_get_apply_mask (layer)))
|
2001-03-05 04:06:48 +08:00
|
|
|
{
|
|
|
|
view_changed = TRUE;
|
|
|
|
}
|
1997-11-25 06:05:25 +08:00
|
|
|
|
2002-03-18 19:07:34 +08:00
|
|
|
if (mode == GIMP_MASK_APPLY)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
2012-03-17 00:29:28 +08:00
|
|
|
GeglBuffer *mask_buffer;
|
|
|
|
GeglBuffer *dest_buffer;
|
|
|
|
|
2001-03-05 04:06:48 +08:00
|
|
|
if (push_undo)
|
2003-02-14 22:14:29 +08:00
|
|
|
gimp_drawable_push_undo (GIMP_DRAWABLE (layer), NULL,
|
2012-03-22 21:13:17 +08:00
|
|
|
NULL,
|
2002-06-07 03:44:05 +08:00
|
|
|
0, 0,
|
2008-11-03 08:09:01 +08:00
|
|
|
gimp_item_get_width (item),
|
2012-03-22 21:13:17 +08:00
|
|
|
gimp_item_get_height (item));
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
/* Combine the current layer's alpha channel and the mask */
|
2012-03-21 07:42:44 +08:00
|
|
|
mask_buffer = gimp_drawable_get_buffer (GIMP_DRAWABLE (mask));
|
|
|
|
dest_buffer = gimp_drawable_get_buffer (GIMP_DRAWABLE (layer));
|
2012-03-17 00:29:28 +08:00
|
|
|
|
2012-11-01 06:47:45 +08:00
|
|
|
gimp_gegl_apply_opacity (gimp_drawable_get_buffer (GIMP_DRAWABLE (layer)),
|
|
|
|
NULL, NULL, dest_buffer,
|
|
|
|
mask_buffer, 0, 0, 1.0);
|
2001-03-05 04:06:48 +08:00
|
|
|
}
|
1997-11-25 06:05:25 +08:00
|
|
|
|
2007-12-24 00:58:41 +08:00
|
|
|
g_signal_handlers_disconnect_by_func (mask,
|
To optimize duplicate and/or wrong image updates away, introduced new
2003-09-06 Michael Natterer <mitch@gimp.org>
To optimize duplicate and/or wrong image updates away, introduced
new policy that a child object must never explicitly update or
invalidate its parent object (just like the GUI is not updated
explicitly by the core):
* app/core/gimpdrawable.[ch]: added new signal
GimpDrawable::update(). Never update or invalidate the image when
the drawable is updated or invalidated.
(gimp_drawable_set_visible): don't gimp_drawable_update() the
drawable since its pixels have not changed.
* app/core/gimpimage.[ch]: connect to the "add" and "remove"
signals of the layers and channels containers. Also connect to the
"update" and "visibility_changed" signals of all drawables in
these containers (optimizes away updates issued by drawables which
are not yet added to the image and updates of the selection
mask). Also, don't propagate updates to the image if the emitting
drawable is invisible (optimizes away updates issued by invisible
drawables).
(gimp_image_add_layer,channel)
(gimp_image_remove_layer,channel): don't update the image since
that's done by our "add" and "remove" handlers now.
(gimp_image_position_layer,channel): update just the image, not
the drawable since its pixels have not changed.
(gimp_image_real_colormap_changed)
(gimp_image_set_component_visible): always call
gimp_image_update() *and* gimp_viewable_invalidate_preview() to
get everything updated, since update and invalidate of images are
not connected.
* app/core/gimpimage-undo-push.c (undo_pop_layer,channel): don't
update the drawable since (a) its pixels don't change and (b) the
image updates itself upon adding/removing now.
(undo_pop_layer_mod): replaced gimp_image_update() by
gimp_drawable_update() (just for consistency with other similar
functions).
* app/core/gimplayer.c: connect to "update" of the layer mask and
issue updates on the layer if the mask update has any effect on
the projection.
(gimp_layer_create_mask): don't set the mask's offsets here since
they may be different when we later add the mask to the layer.
* app/core/gimplayermask.c (gimp_layer_mask_set_layer): set the
mask offsets here instead.
* app/core/gimpchannel.c (gimp_channel_translate): update the
channel even if push_undo == FALSE.
* app/paint/gimppaintcore.c (gimp_paint_core_finish)
* app/tools/gimpinktool.c (ink_finish): invalidate both the
drawable and the image preview since invalidating the drawable
doesn't invalidate the image any more.
* app/text/gimptextlayer.c (gimp_text_layer_render_now): also
update the new extents of the text layer, not only the old one.
(gimp_text_layer_render_layout): don't update the drawable since
gimp_drawable_fill() already updated it.
2003-09-07 04:06:53 +08:00
|
|
|
gimp_layer_layer_mask_update,
|
|
|
|
layer);
|
|
|
|
|
2007-12-24 00:58:41 +08:00
|
|
|
gimp_item_removed (GIMP_ITEM (mask));
|
|
|
|
g_object_unref (mask);
|
2001-03-06 21:28:39 +08:00
|
|
|
layer->mask = NULL;
|
2001-03-05 04:06:48 +08:00
|
|
|
|
|
|
|
if (push_undo)
|
2006-03-29 01:08:36 +08:00
|
|
|
gimp_image_undo_group_end (image);
|
2001-03-05 04:06:48 +08:00
|
|
|
|
2013-04-11 08:54:42 +08:00
|
|
|
if (gimp_filter_peek_node (GIMP_FILTER (layer)))
|
2012-03-20 05:22:05 +08:00
|
|
|
{
|
2012-05-17 01:45:18 +08:00
|
|
|
GeglNode *mode_node;
|
2012-03-20 05:22:05 +08:00
|
|
|
|
2012-05-17 01:45:18 +08:00
|
|
|
mode_node = gimp_drawable_get_mode_node (GIMP_DRAWABLE (layer));
|
2012-03-20 05:22:05 +08:00
|
|
|
|
2012-05-17 01:45:18 +08:00
|
|
|
if (layer->show_mask)
|
|
|
|
{
|
|
|
|
gegl_node_connect_to (layer->layer_offset_node, "output",
|
|
|
|
mode_node, "aux");
|
2012-03-20 05:22:05 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2012-05-17 01:45:18 +08:00
|
|
|
gegl_node_disconnect (mode_node, "aux2");
|
2012-03-20 05:22:05 +08:00
|
|
|
}
|
2015-09-01 16:26:21 +08:00
|
|
|
|
|
|
|
gimp_layer_update_mode_node (layer);
|
2012-03-20 05:22:05 +08:00
|
|
|
}
|
2008-10-10 04:44:23 +08:00
|
|
|
|
2001-03-05 04:06:48 +08:00
|
|
|
/* If applying actually changed the view */
|
|
|
|
if (view_changed)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
2017-01-13 09:14:40 +08:00
|
|
|
gimp_drawable_update (GIMP_DRAWABLE (layer), 0, 0, -1, -1);
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
2003-03-24 20:21:58 +08:00
|
|
|
else
|
|
|
|
{
|
2003-04-07 17:27:08 +08:00
|
|
|
gimp_viewable_invalidate_preview (GIMP_VIEWABLE (layer));
|
2003-03-24 20:21:58 +08:00
|
|
|
}
|
2001-03-05 04:06:48 +08:00
|
|
|
|
2003-01-06 06:07:10 +08:00
|
|
|
g_signal_emit (layer, layer_signals[MASK_CHANGED], 0);
|
2008-11-20 07:37:15 +08:00
|
|
|
|
|
|
|
g_object_notify (G_OBJECT (layer), "mask");
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
|
2012-03-18 01:30:13 +08:00
|
|
|
void
|
|
|
|
gimp_layer_set_apply_mask (GimpLayer *layer,
|
|
|
|
gboolean apply,
|
|
|
|
gboolean push_undo)
|
|
|
|
{
|
|
|
|
g_return_if_fail (GIMP_IS_LAYER (layer));
|
|
|
|
g_return_if_fail (layer->mask != NULL);
|
|
|
|
|
|
|
|
if (layer->apply_mask != apply)
|
|
|
|
{
|
|
|
|
GimpImage *image = gimp_item_get_image (GIMP_ITEM (layer));
|
|
|
|
|
2018-02-20 18:03:21 +08:00
|
|
|
if (push_undo && gimp_item_is_attached (GIMP_ITEM (layer)))
|
2012-03-18 01:30:13 +08:00
|
|
|
gimp_image_undo_push_layer_mask_apply (image,
|
|
|
|
apply ?
|
|
|
|
C_("undo-type", "Enable Layer Mask") :
|
|
|
|
C_("undo-type", "Disable Layer Mask"),
|
|
|
|
layer);
|
|
|
|
|
|
|
|
layer->apply_mask = apply ? TRUE : FALSE;
|
|
|
|
|
2013-04-11 08:54:42 +08:00
|
|
|
if (gimp_filter_peek_node (GIMP_FILTER (layer)) &&
|
2012-05-16 03:57:40 +08:00
|
|
|
! gimp_layer_get_show_mask (layer))
|
2012-03-23 21:21:40 +08:00
|
|
|
{
|
2012-05-17 01:45:18 +08:00
|
|
|
GeglNode *mode_node;
|
2012-03-23 21:21:40 +08:00
|
|
|
|
2012-05-17 01:45:18 +08:00
|
|
|
mode_node = gimp_drawable_get_mode_node (GIMP_DRAWABLE (layer));
|
2012-03-23 21:21:40 +08:00
|
|
|
|
|
|
|
if (layer->apply_mask)
|
|
|
|
{
|
2012-05-17 01:45:18 +08:00
|
|
|
gegl_node_connect_to (layer->mask_offset_node, "output",
|
|
|
|
mode_node, "aux2");
|
2012-03-23 21:21:40 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2012-05-17 01:45:18 +08:00
|
|
|
gegl_node_disconnect (mode_node, "aux2");
|
2012-03-23 21:21:40 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-13 09:14:40 +08:00
|
|
|
gimp_drawable_update (GIMP_DRAWABLE (layer), 0, 0, -1, -1);
|
2012-03-18 01:30:13 +08:00
|
|
|
|
|
|
|
g_signal_emit (layer, layer_signals[APPLY_MASK_CHANGED], 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
gboolean
|
2016-05-20 05:51:44 +08:00
|
|
|
gimp_layer_get_apply_mask (GimpLayer *layer)
|
2012-03-18 01:30:13 +08:00
|
|
|
{
|
|
|
|
g_return_val_if_fail (GIMP_IS_LAYER (layer), FALSE);
|
|
|
|
g_return_val_if_fail (layer->mask, FALSE);
|
|
|
|
|
|
|
|
return layer->apply_mask;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
gimp_layer_set_edit_mask (GimpLayer *layer,
|
|
|
|
gboolean edit)
|
|
|
|
{
|
|
|
|
g_return_if_fail (GIMP_IS_LAYER (layer));
|
|
|
|
g_return_if_fail (layer->mask != NULL);
|
|
|
|
|
|
|
|
if (layer->edit_mask != edit)
|
|
|
|
{
|
|
|
|
layer->edit_mask = edit ? TRUE : FALSE;
|
|
|
|
|
|
|
|
g_signal_emit (layer, layer_signals[EDIT_MASK_CHANGED], 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
gboolean
|
2016-05-20 05:51:44 +08:00
|
|
|
gimp_layer_get_edit_mask (GimpLayer *layer)
|
2012-03-18 01:30:13 +08:00
|
|
|
{
|
|
|
|
g_return_val_if_fail (GIMP_IS_LAYER (layer), FALSE);
|
|
|
|
g_return_val_if_fail (layer->mask, FALSE);
|
|
|
|
|
|
|
|
return layer->edit_mask;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
gimp_layer_set_show_mask (GimpLayer *layer,
|
|
|
|
gboolean show,
|
|
|
|
gboolean push_undo)
|
|
|
|
{
|
|
|
|
g_return_if_fail (GIMP_IS_LAYER (layer));
|
|
|
|
g_return_if_fail (layer->mask != NULL);
|
|
|
|
|
|
|
|
if (layer->show_mask != show)
|
|
|
|
{
|
|
|
|
GimpImage *image = gimp_item_get_image (GIMP_ITEM (layer));
|
|
|
|
|
|
|
|
if (push_undo)
|
|
|
|
gimp_image_undo_push_layer_mask_show (image,
|
|
|
|
C_("undo-type", "Show Layer Mask"),
|
|
|
|
layer);
|
|
|
|
|
|
|
|
layer->show_mask = show ? TRUE : FALSE;
|
|
|
|
|
2013-04-11 08:54:42 +08:00
|
|
|
if (gimp_filter_peek_node (GIMP_FILTER (layer)))
|
2012-03-20 05:22:05 +08:00
|
|
|
{
|
2012-05-17 01:45:18 +08:00
|
|
|
GeglNode *mode_node;
|
2012-03-20 05:22:05 +08:00
|
|
|
|
2012-05-17 01:45:18 +08:00
|
|
|
mode_node = gimp_drawable_get_mode_node (GIMP_DRAWABLE (layer));
|
2012-03-20 05:22:05 +08:00
|
|
|
|
|
|
|
if (layer->show_mask)
|
|
|
|
{
|
2012-05-17 01:45:18 +08:00
|
|
|
gegl_node_disconnect (mode_node, "aux2");
|
2012-03-20 05:22:05 +08:00
|
|
|
|
2012-05-17 01:45:18 +08:00
|
|
|
gegl_node_connect_to (layer->mask_offset_node, "output",
|
|
|
|
mode_node, "aux");
|
2012-03-20 05:22:05 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2012-07-07 22:18:48 +08:00
|
|
|
gegl_node_connect_to (layer->layer_offset_node, "output",
|
2012-05-17 01:45:18 +08:00
|
|
|
mode_node, "aux");
|
2012-03-23 21:21:40 +08:00
|
|
|
|
|
|
|
if (gimp_layer_get_apply_mask (layer))
|
|
|
|
{
|
2012-05-17 01:45:18 +08:00
|
|
|
gegl_node_connect_to (layer->mask_offset_node, "output",
|
|
|
|
mode_node, "aux2");
|
2012-03-23 21:21:40 +08:00
|
|
|
}
|
2012-03-20 05:22:05 +08:00
|
|
|
}
|
2015-08-30 04:39:35 +08:00
|
|
|
|
2015-09-01 16:26:21 +08:00
|
|
|
gimp_layer_update_mode_node (layer);
|
2012-03-20 05:22:05 +08:00
|
|
|
}
|
|
|
|
|
2017-01-13 09:14:40 +08:00
|
|
|
gimp_drawable_update (GIMP_DRAWABLE (layer), 0, 0, -1, -1);
|
2012-03-18 01:30:13 +08:00
|
|
|
|
|
|
|
g_signal_emit (layer, layer_signals[SHOW_MASK_CHANGED], 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
gboolean
|
2016-05-20 05:51:44 +08:00
|
|
|
gimp_layer_get_show_mask (GimpLayer *layer)
|
2012-03-18 01:30:13 +08:00
|
|
|
{
|
|
|
|
g_return_val_if_fail (GIMP_IS_LAYER (layer), FALSE);
|
|
|
|
g_return_val_if_fail (layer->mask, FALSE);
|
|
|
|
|
|
|
|
return layer->show_mask;
|
|
|
|
}
|
|
|
|
|
1997-11-25 06:05:25 +08:00
|
|
|
void
|
2001-01-29 00:44:22 +08:00
|
|
|
gimp_layer_add_alpha (GimpLayer *layer)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
2012-03-22 06:37:16 +08:00
|
|
|
GimpItem *item;
|
|
|
|
GimpDrawable *drawable;
|
|
|
|
GeglBuffer *new_buffer;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
2002-06-07 03:07:59 +08:00
|
|
|
g_return_if_fail (GIMP_IS_LAYER (layer));
|
|
|
|
|
2001-12-13 07:48:18 +08:00
|
|
|
if (gimp_drawable_has_alpha (GIMP_DRAWABLE (layer)))
|
|
|
|
return;
|
|
|
|
|
2008-11-04 05:17:50 +08:00
|
|
|
item = GIMP_ITEM (layer);
|
|
|
|
drawable = GIMP_DRAWABLE (layer);
|
2007-12-24 00:58:41 +08:00
|
|
|
|
2012-06-21 03:44:09 +08:00
|
|
|
new_buffer = gegl_buffer_new (GEGL_RECTANGLE (0, 0,
|
|
|
|
gimp_item_get_width (item),
|
|
|
|
gimp_item_get_height (item)),
|
|
|
|
gimp_drawable_get_format_with_alpha (drawable));
|
2012-03-16 07:22:12 +08:00
|
|
|
|
2018-05-24 22:21:21 +08:00
|
|
|
gimp_gegl_buffer_copy (
|
|
|
|
gimp_drawable_get_buffer (drawable), NULL, GEGL_ABYSS_NONE,
|
|
|
|
new_buffer, NULL);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
2012-03-21 17:10:20 +08:00
|
|
|
gimp_drawable_set_buffer (GIMP_DRAWABLE (layer),
|
|
|
|
gimp_item_is_attached (GIMP_ITEM (layer)),
|
|
|
|
C_("undo-type", "Add Alpha Channel"),
|
2012-03-22 06:37:16 +08:00
|
|
|
new_buffer);
|
2012-03-21 17:10:20 +08:00
|
|
|
g_object_unref (new_buffer);
|
2000-02-27 02:46:08 +08:00
|
|
|
}
|
|
|
|
|
2005-08-08 00:38:35 +08:00
|
|
|
void
|
2016-09-21 17:56:25 +08:00
|
|
|
gimp_layer_remove_alpha (GimpLayer *layer,
|
|
|
|
GimpContext *context)
|
2005-08-08 00:38:35 +08:00
|
|
|
{
|
2012-03-22 06:37:16 +08:00
|
|
|
GeglBuffer *new_buffer;
|
|
|
|
GimpRGB background;
|
2005-08-08 00:38:35 +08:00
|
|
|
|
|
|
|
g_return_if_fail (GIMP_IS_LAYER (layer));
|
|
|
|
g_return_if_fail (GIMP_IS_CONTEXT (context));
|
|
|
|
|
|
|
|
if (! gimp_drawable_has_alpha (GIMP_DRAWABLE (layer)))
|
|
|
|
return;
|
|
|
|
|
2012-03-21 17:10:20 +08:00
|
|
|
new_buffer =
|
2012-06-21 03:44:09 +08:00
|
|
|
gegl_buffer_new (GEGL_RECTANGLE (0, 0,
|
|
|
|
gimp_item_get_width (GIMP_ITEM (layer)),
|
|
|
|
gimp_item_get_height (GIMP_ITEM (layer))),
|
|
|
|
gimp_drawable_get_format_without_alpha (GIMP_DRAWABLE (layer)));
|
2012-03-18 23:27:08 +08:00
|
|
|
|
2012-03-16 19:49:34 +08:00
|
|
|
gimp_context_get_background (context, &background);
|
2017-10-25 02:32:05 +08:00
|
|
|
gimp_pickable_srgb_to_image_color (GIMP_PICKABLE (layer),
|
|
|
|
&background, &background);
|
2005-08-08 00:38:35 +08:00
|
|
|
|
2012-11-01 06:47:45 +08:00
|
|
|
gimp_gegl_apply_flatten (gimp_drawable_get_buffer (GIMP_DRAWABLE (layer)),
|
|
|
|
NULL, NULL,
|
2017-10-21 23:10:29 +08:00
|
|
|
new_buffer, &background,
|
|
|
|
gimp_layer_get_real_composite_space (layer));
|
2005-08-08 00:38:35 +08:00
|
|
|
|
2012-03-21 17:10:20 +08:00
|
|
|
gimp_drawable_set_buffer (GIMP_DRAWABLE (layer),
|
|
|
|
gimp_item_is_attached (GIMP_ITEM (layer)),
|
|
|
|
C_("undo-type", "Remove Alpha Channel"),
|
2012-03-22 06:37:16 +08:00
|
|
|
new_buffer);
|
2012-03-21 17:10:20 +08:00
|
|
|
g_object_unref (new_buffer);
|
2005-08-08 00:38:35 +08:00
|
|
|
}
|
|
|
|
|
1999-11-27 22:00:26 +08:00
|
|
|
void
|
2016-10-10 06:02:16 +08:00
|
|
|
gimp_layer_resize_to_image (GimpLayer *layer,
|
|
|
|
GimpContext *context,
|
|
|
|
GimpFillType fill_type)
|
1999-11-27 22:00:26 +08:00
|
|
|
{
|
2006-03-29 01:08:36 +08:00
|
|
|
GimpImage *image;
|
2001-01-29 00:44:22 +08:00
|
|
|
gint offset_x;
|
|
|
|
gint offset_y;
|
1999-11-27 22:00:26 +08:00
|
|
|
|
2002-06-07 03:07:59 +08:00
|
|
|
g_return_if_fail (GIMP_IS_LAYER (layer));
|
2004-11-16 21:41:55 +08:00
|
|
|
g_return_if_fail (gimp_item_is_attached (GIMP_ITEM (layer)));
|
2004-04-15 07:37:34 +08:00
|
|
|
g_return_if_fail (GIMP_IS_CONTEXT (context));
|
2002-06-07 03:07:59 +08:00
|
|
|
|
2006-03-29 01:08:36 +08:00
|
|
|
image = gimp_item_get_image (GIMP_ITEM (layer));
|
1999-11-27 22:00:26 +08:00
|
|
|
|
2006-03-29 01:08:36 +08:00
|
|
|
gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_ITEM_RESIZE,
|
2010-06-08 19:24:11 +08:00
|
|
|
C_("undo-type", "Layer to Image Size"));
|
1999-11-27 22:00:26 +08:00
|
|
|
|
2008-11-03 07:03:29 +08:00
|
|
|
gimp_item_get_offset (GIMP_ITEM (layer), &offset_x, &offset_y);
|
2016-10-10 06:02:16 +08:00
|
|
|
gimp_item_resize (GIMP_ITEM (layer), context, fill_type,
|
2007-12-26 00:21:40 +08:00
|
|
|
gimp_image_get_width (image),
|
|
|
|
gimp_image_get_height (image),
|
|
|
|
offset_x, offset_y);
|
1999-11-27 22:00:26 +08:00
|
|
|
|
2006-03-29 01:08:36 +08:00
|
|
|
gimp_image_undo_group_end (image);
|
1999-11-27 22:00:26 +08:00
|
|
|
}
|
|
|
|
|
1999-08-22 19:45:31 +08:00
|
|
|
/**********************/
|
|
|
|
/* access functions */
|
|
|
|
/**********************/
|
1997-11-25 06:05:25 +08:00
|
|
|
|
2009-01-27 06:47:16 +08:00
|
|
|
GimpDrawable *
|
2016-05-20 05:51:44 +08:00
|
|
|
gimp_layer_get_floating_sel_drawable (GimpLayer *layer)
|
2009-01-27 06:47:16 +08:00
|
|
|
{
|
|
|
|
g_return_val_if_fail (GIMP_IS_LAYER (layer), NULL);
|
|
|
|
|
|
|
|
return layer->fs.drawable;
|
|
|
|
}
|
|
|
|
|
2008-11-17 08:02:15 +08:00
|
|
|
void
|
|
|
|
gimp_layer_set_floating_sel_drawable (GimpLayer *layer,
|
|
|
|
GimpDrawable *drawable)
|
|
|
|
{
|
|
|
|
g_return_if_fail (GIMP_IS_LAYER (layer));
|
|
|
|
g_return_if_fail (drawable == NULL || GIMP_IS_DRAWABLE (drawable));
|
|
|
|
|
2018-06-01 18:59:52 +08:00
|
|
|
if (g_set_object (&layer->fs.drawable, drawable))
|
2008-11-17 08:02:15 +08:00
|
|
|
{
|
|
|
|
if (layer->fs.segs)
|
|
|
|
{
|
|
|
|
g_free (layer->fs.segs);
|
|
|
|
layer->fs.segs = NULL;
|
|
|
|
layer->fs.num_segs = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
g_object_notify (G_OBJECT (layer), "floating-selection");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1999-08-22 19:45:31 +08:00
|
|
|
gboolean
|
2016-05-20 05:51:44 +08:00
|
|
|
gimp_layer_is_floating_sel (GimpLayer *layer)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
2001-01-29 00:44:22 +08:00
|
|
|
g_return_val_if_fail (GIMP_IS_LAYER (layer), FALSE);
|
|
|
|
|
2009-01-27 06:47:16 +08:00
|
|
|
return (gimp_layer_get_floating_sel_drawable (layer) != NULL);
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
|
2001-03-12 01:24:47 +08:00
|
|
|
void
|
|
|
|
gimp_layer_set_opacity (GimpLayer *layer,
|
Made drawable/layer properties (visibility, opacity etc.) undoable (fixes
2003-03-17 Michael Natterer <mitch@gimp.org>
Made drawable/layer properties (visibility, opacity etc.)
undoable (fixes bug #73893).
* app/core/core-enums.[ch]: added undo types/groups for
visibility, mode, opacity, linked and preserve_trans.
* app/core/Makefile.am
* app/core/core-types.h
* app/core/gimpitemundo.[ch]: new GimpUndo subclass which holds a
ref'ed GimpItem pointer so (1) this doesn't need to be done by all
undo steps related to an item and (2) the item the undo step is
for can be determined from outside the undo system.
* app/core/gimpimage-undo.[ch]: added gimp_image_undo_push_item()
which returns a new GimpItemUndo.
* app/core/gimpimage-undo-push.[ch]: use it for all item related
undo steps. Removed lots of GimpItem, GimpLayer, GimpDrawable
and GimpVectors pointers from the private undo structs. Added
undo push functions for the new undo types added above.
* app/core/gimpdrawable.[ch] (gimp_drawable_set_visible): added
"gboolean push_undo" parameter.
* app/core/gimplayer.[ch] (gimp_layer_set_opacity, _mode,
_preserve_trans, _linked): added "gboolean push_undo" parameters.
* app/core/gimpimage-mask.c
* app/core/gimpimage-merge.c
* app/core/gimplayer-floating-sel.c
* app/tools/gimpmovetool.c
* app/xcf/xcf-load.c
* app/widgets/gimpdrawablelistitem.c
* app/widgets/gimplayerlistitem.c
* app/widgets/gimplayerlistview.c: changed accordingly.
* tools/pdbgen/pdb/channel.pdb
* tools/pdbgen/pdb/layer.pdb: ditto. Added '$undo' paramaters to
the foo_accessors() functions. Removed $func from foo_accesors()
because we don't manipulate items without using getters/setters
any longer.
* app/pdb/channel_cmds.c
* app/pdb/layer_cmds.c: regenerated.
* app/widgets/gimpcellrenderertoggle.[ch]: added "clicked" signal
which carries an additional "GdkModifierType state" parameter as
in GimpCellRendererViewable .
* app/widgets/gimpcontainertreeview.c: emit "clicked" from
the toggle renderer, not "toggled" so the callbacks get the
modifier state.
* app/widgets/gimpdrawabletreeview.c: resurrected the "exclusive
visible by <shift>+click" feature as in 1.2.
* app/widgets/gimplayertreeview.c: compress layer opacity undos by
looking at the top of the undo stack and not pushing an undo if
there already is a GIMP_UNDO_DRAWABLE_OPACITY for the active
layer.
2003-03-18 02:02:41 +08:00
|
|
|
gdouble opacity,
|
|
|
|
gboolean push_undo)
|
2001-03-12 01:24:47 +08:00
|
|
|
{
|
|
|
|
g_return_if_fail (GIMP_IS_LAYER (layer));
|
|
|
|
|
2002-03-04 22:52:54 +08:00
|
|
|
opacity = CLAMP (opacity, GIMP_OPACITY_TRANSPARENT, GIMP_OPACITY_OPAQUE);
|
2001-03-12 01:24:47 +08:00
|
|
|
|
2002-03-04 22:52:54 +08:00
|
|
|
if (layer->opacity != opacity)
|
2001-03-12 01:24:47 +08:00
|
|
|
{
|
2004-11-16 21:41:55 +08:00
|
|
|
if (push_undo && gimp_item_is_attached (GIMP_ITEM (layer)))
|
Made drawable/layer properties (visibility, opacity etc.) undoable (fixes
2003-03-17 Michael Natterer <mitch@gimp.org>
Made drawable/layer properties (visibility, opacity etc.)
undoable (fixes bug #73893).
* app/core/core-enums.[ch]: added undo types/groups for
visibility, mode, opacity, linked and preserve_trans.
* app/core/Makefile.am
* app/core/core-types.h
* app/core/gimpitemundo.[ch]: new GimpUndo subclass which holds a
ref'ed GimpItem pointer so (1) this doesn't need to be done by all
undo steps related to an item and (2) the item the undo step is
for can be determined from outside the undo system.
* app/core/gimpimage-undo.[ch]: added gimp_image_undo_push_item()
which returns a new GimpItemUndo.
* app/core/gimpimage-undo-push.[ch]: use it for all item related
undo steps. Removed lots of GimpItem, GimpLayer, GimpDrawable
and GimpVectors pointers from the private undo structs. Added
undo push functions for the new undo types added above.
* app/core/gimpdrawable.[ch] (gimp_drawable_set_visible): added
"gboolean push_undo" parameter.
* app/core/gimplayer.[ch] (gimp_layer_set_opacity, _mode,
_preserve_trans, _linked): added "gboolean push_undo" parameters.
* app/core/gimpimage-mask.c
* app/core/gimpimage-merge.c
* app/core/gimplayer-floating-sel.c
* app/tools/gimpmovetool.c
* app/xcf/xcf-load.c
* app/widgets/gimpdrawablelistitem.c
* app/widgets/gimplayerlistitem.c
* app/widgets/gimplayerlistview.c: changed accordingly.
* tools/pdbgen/pdb/channel.pdb
* tools/pdbgen/pdb/layer.pdb: ditto. Added '$undo' paramaters to
the foo_accessors() functions. Removed $func from foo_accesors()
because we don't manipulate items without using getters/setters
any longer.
* app/pdb/channel_cmds.c
* app/pdb/layer_cmds.c: regenerated.
* app/widgets/gimpcellrenderertoggle.[ch]: added "clicked" signal
which carries an additional "GdkModifierType state" parameter as
in GimpCellRendererViewable .
* app/widgets/gimpcontainertreeview.c: emit "clicked" from
the toggle renderer, not "toggled" so the callbacks get the
modifier state.
* app/widgets/gimpdrawabletreeview.c: resurrected the "exclusive
visible by <shift>+click" feature as in 1.2.
* app/widgets/gimplayertreeview.c: compress layer opacity undos by
looking at the top of the undo stack and not pushing an undo if
there already is a GIMP_UNDO_DRAWABLE_OPACITY for the active
layer.
2003-03-18 02:02:41 +08:00
|
|
|
{
|
2006-03-29 01:08:36 +08:00
|
|
|
GimpImage *image = gimp_item_get_image (GIMP_ITEM (layer));
|
Made drawable/layer properties (visibility, opacity etc.) undoable (fixes
2003-03-17 Michael Natterer <mitch@gimp.org>
Made drawable/layer properties (visibility, opacity etc.)
undoable (fixes bug #73893).
* app/core/core-enums.[ch]: added undo types/groups for
visibility, mode, opacity, linked and preserve_trans.
* app/core/Makefile.am
* app/core/core-types.h
* app/core/gimpitemundo.[ch]: new GimpUndo subclass which holds a
ref'ed GimpItem pointer so (1) this doesn't need to be done by all
undo steps related to an item and (2) the item the undo step is
for can be determined from outside the undo system.
* app/core/gimpimage-undo.[ch]: added gimp_image_undo_push_item()
which returns a new GimpItemUndo.
* app/core/gimpimage-undo-push.[ch]: use it for all item related
undo steps. Removed lots of GimpItem, GimpLayer, GimpDrawable
and GimpVectors pointers from the private undo structs. Added
undo push functions for the new undo types added above.
* app/core/gimpdrawable.[ch] (gimp_drawable_set_visible): added
"gboolean push_undo" parameter.
* app/core/gimplayer.[ch] (gimp_layer_set_opacity, _mode,
_preserve_trans, _linked): added "gboolean push_undo" parameters.
* app/core/gimpimage-mask.c
* app/core/gimpimage-merge.c
* app/core/gimplayer-floating-sel.c
* app/tools/gimpmovetool.c
* app/xcf/xcf-load.c
* app/widgets/gimpdrawablelistitem.c
* app/widgets/gimplayerlistitem.c
* app/widgets/gimplayerlistview.c: changed accordingly.
* tools/pdbgen/pdb/channel.pdb
* tools/pdbgen/pdb/layer.pdb: ditto. Added '$undo' paramaters to
the foo_accessors() functions. Removed $func from foo_accesors()
because we don't manipulate items without using getters/setters
any longer.
* app/pdb/channel_cmds.c
* app/pdb/layer_cmds.c: regenerated.
* app/widgets/gimpcellrenderertoggle.[ch]: added "clicked" signal
which carries an additional "GdkModifierType state" parameter as
in GimpCellRendererViewable .
* app/widgets/gimpcontainertreeview.c: emit "clicked" from
the toggle renderer, not "toggled" so the callbacks get the
modifier state.
* app/widgets/gimpdrawabletreeview.c: resurrected the "exclusive
visible by <shift>+click" feature as in 1.2.
* app/widgets/gimplayertreeview.c: compress layer opacity undos by
looking at the top of the undo stack and not pushing an undo if
there already is a GIMP_UNDO_DRAWABLE_OPACITY for the active
layer.
2003-03-18 02:02:41 +08:00
|
|
|
|
2006-03-29 01:08:36 +08:00
|
|
|
gimp_image_undo_push_layer_opacity (image, NULL, layer);
|
Made drawable/layer properties (visibility, opacity etc.) undoable (fixes
2003-03-17 Michael Natterer <mitch@gimp.org>
Made drawable/layer properties (visibility, opacity etc.)
undoable (fixes bug #73893).
* app/core/core-enums.[ch]: added undo types/groups for
visibility, mode, opacity, linked and preserve_trans.
* app/core/Makefile.am
* app/core/core-types.h
* app/core/gimpitemundo.[ch]: new GimpUndo subclass which holds a
ref'ed GimpItem pointer so (1) this doesn't need to be done by all
undo steps related to an item and (2) the item the undo step is
for can be determined from outside the undo system.
* app/core/gimpimage-undo.[ch]: added gimp_image_undo_push_item()
which returns a new GimpItemUndo.
* app/core/gimpimage-undo-push.[ch]: use it for all item related
undo steps. Removed lots of GimpItem, GimpLayer, GimpDrawable
and GimpVectors pointers from the private undo structs. Added
undo push functions for the new undo types added above.
* app/core/gimpdrawable.[ch] (gimp_drawable_set_visible): added
"gboolean push_undo" parameter.
* app/core/gimplayer.[ch] (gimp_layer_set_opacity, _mode,
_preserve_trans, _linked): added "gboolean push_undo" parameters.
* app/core/gimpimage-mask.c
* app/core/gimpimage-merge.c
* app/core/gimplayer-floating-sel.c
* app/tools/gimpmovetool.c
* app/xcf/xcf-load.c
* app/widgets/gimpdrawablelistitem.c
* app/widgets/gimplayerlistitem.c
* app/widgets/gimplayerlistview.c: changed accordingly.
* tools/pdbgen/pdb/channel.pdb
* tools/pdbgen/pdb/layer.pdb: ditto. Added '$undo' paramaters to
the foo_accessors() functions. Removed $func from foo_accesors()
because we don't manipulate items without using getters/setters
any longer.
* app/pdb/channel_cmds.c
* app/pdb/layer_cmds.c: regenerated.
* app/widgets/gimpcellrenderertoggle.[ch]: added "clicked" signal
which carries an additional "GdkModifierType state" parameter as
in GimpCellRendererViewable .
* app/widgets/gimpcontainertreeview.c: emit "clicked" from
the toggle renderer, not "toggled" so the callbacks get the
modifier state.
* app/widgets/gimpdrawabletreeview.c: resurrected the "exclusive
visible by <shift>+click" feature as in 1.2.
* app/widgets/gimplayertreeview.c: compress layer opacity undos by
looking at the top of the undo stack and not pushing an undo if
there already is a GIMP_UNDO_DRAWABLE_OPACITY for the active
layer.
2003-03-18 02:02:41 +08:00
|
|
|
}
|
2003-08-28 01:21:49 +08:00
|
|
|
|
2002-03-04 22:52:54 +08:00
|
|
|
layer->opacity = opacity;
|
2001-03-12 01:24:47 +08:00
|
|
|
|
2003-01-06 06:07:10 +08:00
|
|
|
g_signal_emit (layer, layer_signals[OPACITY_CHANGED], 0);
|
2005-07-12 00:46:28 +08:00
|
|
|
g_object_notify (G_OBJECT (layer), "opacity");
|
2001-07-08 06:49:01 +08:00
|
|
|
|
2013-04-11 08:54:42 +08:00
|
|
|
if (gimp_filter_peek_node (GIMP_FILTER (layer)))
|
2015-08-30 04:39:35 +08:00
|
|
|
gimp_layer_update_mode_node (layer);
|
2008-10-10 04:44:23 +08:00
|
|
|
|
2017-01-13 09:14:40 +08:00
|
|
|
gimp_drawable_update (GIMP_DRAWABLE (layer), 0, 0, -1, -1);
|
2001-03-12 01:24:47 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
gdouble
|
2016-05-20 05:51:44 +08:00
|
|
|
gimp_layer_get_opacity (GimpLayer *layer)
|
2001-03-12 01:24:47 +08:00
|
|
|
{
|
2002-03-04 01:38:12 +08:00
|
|
|
g_return_val_if_fail (GIMP_IS_LAYER (layer), GIMP_OPACITY_OPAQUE);
|
2001-03-12 01:24:47 +08:00
|
|
|
|
2002-06-07 03:07:59 +08:00
|
|
|
return layer->opacity;
|
2001-03-12 01:24:47 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2017-01-09 06:00:19 +08:00
|
|
|
gimp_layer_set_mode (GimpLayer *layer,
|
|
|
|
GimpLayerMode mode,
|
|
|
|
gboolean push_undo)
|
2001-03-12 01:24:47 +08:00
|
|
|
{
|
|
|
|
g_return_if_fail (GIMP_IS_LAYER (layer));
|
|
|
|
|
2017-02-17 16:49:29 +08:00
|
|
|
if (gimp_viewable_get_children (GIMP_VIEWABLE (layer)) == NULL)
|
|
|
|
{
|
|
|
|
g_return_if_fail (gimp_layer_mode_get_context (mode) &
|
|
|
|
GIMP_LAYER_MODE_CONTEXT_LAYER);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
g_return_if_fail (gimp_layer_mode_get_context (mode) &
|
|
|
|
GIMP_LAYER_MODE_CONTEXT_GROUP);
|
|
|
|
}
|
|
|
|
|
2001-03-12 01:24:47 +08:00
|
|
|
if (layer->mode != mode)
|
|
|
|
{
|
2017-08-22 02:04:25 +08:00
|
|
|
if (gimp_item_is_attached (GIMP_ITEM (layer)))
|
Made drawable/layer properties (visibility, opacity etc.) undoable (fixes
2003-03-17 Michael Natterer <mitch@gimp.org>
Made drawable/layer properties (visibility, opacity etc.)
undoable (fixes bug #73893).
* app/core/core-enums.[ch]: added undo types/groups for
visibility, mode, opacity, linked and preserve_trans.
* app/core/Makefile.am
* app/core/core-types.h
* app/core/gimpitemundo.[ch]: new GimpUndo subclass which holds a
ref'ed GimpItem pointer so (1) this doesn't need to be done by all
undo steps related to an item and (2) the item the undo step is
for can be determined from outside the undo system.
* app/core/gimpimage-undo.[ch]: added gimp_image_undo_push_item()
which returns a new GimpItemUndo.
* app/core/gimpimage-undo-push.[ch]: use it for all item related
undo steps. Removed lots of GimpItem, GimpLayer, GimpDrawable
and GimpVectors pointers from the private undo structs. Added
undo push functions for the new undo types added above.
* app/core/gimpdrawable.[ch] (gimp_drawable_set_visible): added
"gboolean push_undo" parameter.
* app/core/gimplayer.[ch] (gimp_layer_set_opacity, _mode,
_preserve_trans, _linked): added "gboolean push_undo" parameters.
* app/core/gimpimage-mask.c
* app/core/gimpimage-merge.c
* app/core/gimplayer-floating-sel.c
* app/tools/gimpmovetool.c
* app/xcf/xcf-load.c
* app/widgets/gimpdrawablelistitem.c
* app/widgets/gimplayerlistitem.c
* app/widgets/gimplayerlistview.c: changed accordingly.
* tools/pdbgen/pdb/channel.pdb
* tools/pdbgen/pdb/layer.pdb: ditto. Added '$undo' paramaters to
the foo_accessors() functions. Removed $func from foo_accesors()
because we don't manipulate items without using getters/setters
any longer.
* app/pdb/channel_cmds.c
* app/pdb/layer_cmds.c: regenerated.
* app/widgets/gimpcellrenderertoggle.[ch]: added "clicked" signal
which carries an additional "GdkModifierType state" parameter as
in GimpCellRendererViewable .
* app/widgets/gimpcontainertreeview.c: emit "clicked" from
the toggle renderer, not "toggled" so the callbacks get the
modifier state.
* app/widgets/gimpdrawabletreeview.c: resurrected the "exclusive
visible by <shift>+click" feature as in 1.2.
* app/widgets/gimplayertreeview.c: compress layer opacity undos by
looking at the top of the undo stack and not pushing an undo if
there already is a GIMP_UNDO_DRAWABLE_OPACITY for the active
layer.
2003-03-18 02:02:41 +08:00
|
|
|
{
|
2006-03-29 01:08:36 +08:00
|
|
|
GimpImage *image = gimp_item_get_image (GIMP_ITEM (layer));
|
Made drawable/layer properties (visibility, opacity etc.) undoable (fixes
2003-03-17 Michael Natterer <mitch@gimp.org>
Made drawable/layer properties (visibility, opacity etc.)
undoable (fixes bug #73893).
* app/core/core-enums.[ch]: added undo types/groups for
visibility, mode, opacity, linked and preserve_trans.
* app/core/Makefile.am
* app/core/core-types.h
* app/core/gimpitemundo.[ch]: new GimpUndo subclass which holds a
ref'ed GimpItem pointer so (1) this doesn't need to be done by all
undo steps related to an item and (2) the item the undo step is
for can be determined from outside the undo system.
* app/core/gimpimage-undo.[ch]: added gimp_image_undo_push_item()
which returns a new GimpItemUndo.
* app/core/gimpimage-undo-push.[ch]: use it for all item related
undo steps. Removed lots of GimpItem, GimpLayer, GimpDrawable
and GimpVectors pointers from the private undo structs. Added
undo push functions for the new undo types added above.
* app/core/gimpdrawable.[ch] (gimp_drawable_set_visible): added
"gboolean push_undo" parameter.
* app/core/gimplayer.[ch] (gimp_layer_set_opacity, _mode,
_preserve_trans, _linked): added "gboolean push_undo" parameters.
* app/core/gimpimage-mask.c
* app/core/gimpimage-merge.c
* app/core/gimplayer-floating-sel.c
* app/tools/gimpmovetool.c
* app/xcf/xcf-load.c
* app/widgets/gimpdrawablelistitem.c
* app/widgets/gimplayerlistitem.c
* app/widgets/gimplayerlistview.c: changed accordingly.
* tools/pdbgen/pdb/channel.pdb
* tools/pdbgen/pdb/layer.pdb: ditto. Added '$undo' paramaters to
the foo_accessors() functions. Removed $func from foo_accesors()
because we don't manipulate items without using getters/setters
any longer.
* app/pdb/channel_cmds.c
* app/pdb/layer_cmds.c: regenerated.
* app/widgets/gimpcellrenderertoggle.[ch]: added "clicked" signal
which carries an additional "GdkModifierType state" parameter as
in GimpCellRendererViewable .
* app/widgets/gimpcontainertreeview.c: emit "clicked" from
the toggle renderer, not "toggled" so the callbacks get the
modifier state.
* app/widgets/gimpdrawabletreeview.c: resurrected the "exclusive
visible by <shift>+click" feature as in 1.2.
* app/widgets/gimplayertreeview.c: compress layer opacity undos by
looking at the top of the undo stack and not pushing an undo if
there already is a GIMP_UNDO_DRAWABLE_OPACITY for the active
layer.
2003-03-18 02:02:41 +08:00
|
|
|
|
2017-08-22 02:04:25 +08:00
|
|
|
gimp_image_unset_default_new_layer_mode (image);
|
|
|
|
|
|
|
|
if (push_undo)
|
|
|
|
gimp_image_undo_push_layer_mode (image, NULL, layer);
|
Made drawable/layer properties (visibility, opacity etc.) undoable (fixes
2003-03-17 Michael Natterer <mitch@gimp.org>
Made drawable/layer properties (visibility, opacity etc.)
undoable (fixes bug #73893).
* app/core/core-enums.[ch]: added undo types/groups for
visibility, mode, opacity, linked and preserve_trans.
* app/core/Makefile.am
* app/core/core-types.h
* app/core/gimpitemundo.[ch]: new GimpUndo subclass which holds a
ref'ed GimpItem pointer so (1) this doesn't need to be done by all
undo steps related to an item and (2) the item the undo step is
for can be determined from outside the undo system.
* app/core/gimpimage-undo.[ch]: added gimp_image_undo_push_item()
which returns a new GimpItemUndo.
* app/core/gimpimage-undo-push.[ch]: use it for all item related
undo steps. Removed lots of GimpItem, GimpLayer, GimpDrawable
and GimpVectors pointers from the private undo structs. Added
undo push functions for the new undo types added above.
* app/core/gimpdrawable.[ch] (gimp_drawable_set_visible): added
"gboolean push_undo" parameter.
* app/core/gimplayer.[ch] (gimp_layer_set_opacity, _mode,
_preserve_trans, _linked): added "gboolean push_undo" parameters.
* app/core/gimpimage-mask.c
* app/core/gimpimage-merge.c
* app/core/gimplayer-floating-sel.c
* app/tools/gimpmovetool.c
* app/xcf/xcf-load.c
* app/widgets/gimpdrawablelistitem.c
* app/widgets/gimplayerlistitem.c
* app/widgets/gimplayerlistview.c: changed accordingly.
* tools/pdbgen/pdb/channel.pdb
* tools/pdbgen/pdb/layer.pdb: ditto. Added '$undo' paramaters to
the foo_accessors() functions. Removed $func from foo_accesors()
because we don't manipulate items without using getters/setters
any longer.
* app/pdb/channel_cmds.c
* app/pdb/layer_cmds.c: regenerated.
* app/widgets/gimpcellrenderertoggle.[ch]: added "clicked" signal
which carries an additional "GdkModifierType state" parameter as
in GimpCellRendererViewable .
* app/widgets/gimpcontainertreeview.c: emit "clicked" from
the toggle renderer, not "toggled" so the callbacks get the
modifier state.
* app/widgets/gimpdrawabletreeview.c: resurrected the "exclusive
visible by <shift>+click" feature as in 1.2.
* app/widgets/gimplayertreeview.c: compress layer opacity undos by
looking at the top of the undo stack and not pushing an undo if
there already is a GIMP_UNDO_DRAWABLE_OPACITY for the active
layer.
2003-03-18 02:02:41 +08:00
|
|
|
}
|
2003-08-28 01:21:49 +08:00
|
|
|
|
2017-02-02 07:38:25 +08:00
|
|
|
g_object_freeze_notify (G_OBJECT (layer));
|
|
|
|
|
2001-03-12 01:24:47 +08:00
|
|
|
layer->mode = mode;
|
|
|
|
|
2003-01-06 06:07:10 +08:00
|
|
|
g_signal_emit (layer, layer_signals[MODE_CHANGED], 0);
|
2005-07-12 00:46:28 +08:00
|
|
|
g_object_notify (G_OBJECT (layer), "mode");
|
2001-07-08 06:49:01 +08:00
|
|
|
|
2017-02-13 06:49:26 +08:00
|
|
|
/* when changing modes, we always switch to AUTO blend and
|
|
|
|
* composite in order to avoid confusion
|
2017-02-02 07:38:25 +08:00
|
|
|
*/
|
2017-02-13 06:49:26 +08:00
|
|
|
if (layer->blend_space != GIMP_LAYER_COLOR_SPACE_AUTO)
|
2017-02-02 07:38:25 +08:00
|
|
|
{
|
2017-02-13 06:49:26 +08:00
|
|
|
layer->blend_space = GIMP_LAYER_COLOR_SPACE_AUTO;
|
2017-02-02 07:38:25 +08:00
|
|
|
|
2017-02-13 06:49:26 +08:00
|
|
|
g_signal_emit (layer, layer_signals[BLEND_SPACE_CHANGED], 0);
|
|
|
|
g_object_notify (G_OBJECT (layer), "blend-space");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (layer->composite_space != GIMP_LAYER_COLOR_SPACE_AUTO)
|
|
|
|
{
|
|
|
|
layer->composite_space = GIMP_LAYER_COLOR_SPACE_AUTO;
|
|
|
|
|
|
|
|
g_signal_emit (layer, layer_signals[COMPOSITE_SPACE_CHANGED], 0);
|
|
|
|
g_object_notify (G_OBJECT (layer), "composite-space");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (layer->composite_mode != GIMP_LAYER_COMPOSITE_AUTO)
|
|
|
|
{
|
|
|
|
layer->composite_mode = GIMP_LAYER_COMPOSITE_AUTO;
|
|
|
|
|
|
|
|
g_signal_emit (layer, layer_signals[COMPOSITE_MODE_CHANGED], 0);
|
|
|
|
g_object_notify (G_OBJECT (layer), "composite-mode");
|
2017-02-02 07:38:25 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
g_object_thaw_notify (G_OBJECT (layer));
|
|
|
|
|
2017-12-07 02:10:38 +08:00
|
|
|
gimp_layer_update_effective_mode (layer);
|
2017-05-08 06:49:38 +08:00
|
|
|
gimp_layer_update_excludes_backdrop (layer);
|
2001-03-12 01:24:47 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-09 06:00:19 +08:00
|
|
|
GimpLayerMode
|
2016-05-20 05:51:44 +08:00
|
|
|
gimp_layer_get_mode (GimpLayer *layer)
|
2001-03-12 01:24:47 +08:00
|
|
|
{
|
2017-08-20 02:33:47 +08:00
|
|
|
g_return_val_if_fail (GIMP_IS_LAYER (layer), GIMP_LAYER_MODE_NORMAL);
|
2001-03-12 01:24:47 +08:00
|
|
|
|
|
|
|
return layer->mode;
|
|
|
|
}
|
|
|
|
|
2017-02-02 07:38:25 +08:00
|
|
|
void
|
2017-02-13 06:49:26 +08:00
|
|
|
gimp_layer_set_blend_space (GimpLayer *layer,
|
|
|
|
GimpLayerColorSpace blend_space,
|
|
|
|
gboolean push_undo)
|
2017-02-02 07:38:25 +08:00
|
|
|
{
|
|
|
|
g_return_if_fail (GIMP_IS_LAYER (layer));
|
|
|
|
|
2017-02-14 05:12:39 +08:00
|
|
|
if (! gimp_layer_mode_is_blend_space_mutable (layer->mode))
|
|
|
|
return;
|
|
|
|
|
2017-02-13 06:49:26 +08:00
|
|
|
if (layer->blend_space != blend_space)
|
2017-02-02 07:38:25 +08:00
|
|
|
{
|
|
|
|
if (push_undo && gimp_item_is_attached (GIMP_ITEM (layer)))
|
|
|
|
{
|
|
|
|
GimpImage *image = gimp_item_get_image (GIMP_ITEM (layer));
|
|
|
|
|
|
|
|
gimp_image_undo_push_layer_mode (image, NULL, layer);
|
|
|
|
}
|
|
|
|
|
2017-02-13 06:49:26 +08:00
|
|
|
layer->blend_space = blend_space;
|
2017-02-02 07:38:25 +08:00
|
|
|
|
2017-02-13 06:49:26 +08:00
|
|
|
g_signal_emit (layer, layer_signals[BLEND_SPACE_CHANGED], 0);
|
|
|
|
g_object_notify (G_OBJECT (layer), "blend-space");
|
|
|
|
|
2017-12-07 02:10:38 +08:00
|
|
|
gimp_layer_update_effective_mode (layer);
|
2017-02-13 06:49:26 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
GimpLayerColorSpace
|
|
|
|
gimp_layer_get_blend_space (GimpLayer *layer)
|
|
|
|
{
|
|
|
|
g_return_val_if_fail (GIMP_IS_LAYER (layer), GIMP_LAYER_COLOR_SPACE_AUTO);
|
|
|
|
|
|
|
|
return layer->blend_space;
|
|
|
|
}
|
|
|
|
|
2017-10-21 23:10:29 +08:00
|
|
|
GimpLayerColorSpace
|
|
|
|
gimp_layer_get_real_blend_space (GimpLayer *layer)
|
|
|
|
{
|
|
|
|
g_return_val_if_fail (GIMP_IS_LAYER (layer), GIMP_LAYER_COLOR_SPACE_RGB_LINEAR);
|
|
|
|
|
|
|
|
if (layer->blend_space == GIMP_LAYER_COLOR_SPACE_AUTO)
|
|
|
|
return gimp_layer_mode_get_blend_space (layer->mode);
|
|
|
|
else
|
|
|
|
return layer->blend_space;
|
|
|
|
}
|
|
|
|
|
2017-02-13 06:49:26 +08:00
|
|
|
void
|
|
|
|
gimp_layer_set_composite_space (GimpLayer *layer,
|
|
|
|
GimpLayerColorSpace composite_space,
|
|
|
|
gboolean push_undo)
|
|
|
|
{
|
|
|
|
g_return_if_fail (GIMP_IS_LAYER (layer));
|
|
|
|
|
2017-02-14 05:12:39 +08:00
|
|
|
if (! gimp_layer_mode_is_composite_space_mutable (layer->mode))
|
|
|
|
return;
|
|
|
|
|
2017-02-13 06:49:26 +08:00
|
|
|
if (layer->composite_space != composite_space)
|
|
|
|
{
|
|
|
|
if (push_undo && gimp_item_is_attached (GIMP_ITEM (layer)))
|
|
|
|
{
|
|
|
|
GimpImage *image = gimp_item_get_image (GIMP_ITEM (layer));
|
|
|
|
|
|
|
|
gimp_image_undo_push_layer_mode (image, NULL, layer);
|
|
|
|
}
|
|
|
|
|
|
|
|
layer->composite_space = composite_space;
|
|
|
|
|
|
|
|
g_signal_emit (layer, layer_signals[COMPOSITE_SPACE_CHANGED], 0);
|
|
|
|
g_object_notify (G_OBJECT (layer), "composite-space");
|
|
|
|
|
2017-12-07 02:10:38 +08:00
|
|
|
gimp_layer_update_effective_mode (layer);
|
2017-02-13 06:49:26 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
GimpLayerColorSpace
|
|
|
|
gimp_layer_get_composite_space (GimpLayer *layer)
|
|
|
|
{
|
|
|
|
g_return_val_if_fail (GIMP_IS_LAYER (layer), GIMP_LAYER_COLOR_SPACE_AUTO);
|
|
|
|
|
|
|
|
return layer->composite_space;
|
|
|
|
}
|
|
|
|
|
2017-10-21 23:10:29 +08:00
|
|
|
GimpLayerColorSpace
|
|
|
|
gimp_layer_get_real_composite_space (GimpLayer *layer)
|
|
|
|
{
|
|
|
|
g_return_val_if_fail (GIMP_IS_LAYER (layer), GIMP_LAYER_COLOR_SPACE_RGB_LINEAR);
|
|
|
|
|
|
|
|
if (layer->composite_space == GIMP_LAYER_COLOR_SPACE_AUTO)
|
|
|
|
return gimp_layer_mode_get_composite_space (layer->mode);
|
|
|
|
else
|
|
|
|
return layer->composite_space;
|
|
|
|
}
|
|
|
|
|
2017-02-13 06:49:26 +08:00
|
|
|
void
|
|
|
|
gimp_layer_set_composite_mode (GimpLayer *layer,
|
|
|
|
GimpLayerCompositeMode composite_mode,
|
|
|
|
gboolean push_undo)
|
|
|
|
{
|
|
|
|
g_return_if_fail (GIMP_IS_LAYER (layer));
|
|
|
|
|
2017-02-14 05:12:39 +08:00
|
|
|
if (! gimp_layer_mode_is_composite_mode_mutable (layer->mode))
|
|
|
|
return;
|
|
|
|
|
2017-02-13 06:49:26 +08:00
|
|
|
if (layer->composite_mode != composite_mode)
|
|
|
|
{
|
|
|
|
if (push_undo && gimp_item_is_attached (GIMP_ITEM (layer)))
|
|
|
|
{
|
|
|
|
GimpImage *image = gimp_item_get_image (GIMP_ITEM (layer));
|
|
|
|
|
|
|
|
gimp_image_undo_push_layer_mode (image, NULL, layer);
|
|
|
|
}
|
|
|
|
|
|
|
|
layer->composite_mode = composite_mode;
|
|
|
|
|
|
|
|
g_signal_emit (layer, layer_signals[COMPOSITE_MODE_CHANGED], 0);
|
|
|
|
g_object_notify (G_OBJECT (layer), "composite-mode");
|
2017-02-02 07:38:25 +08:00
|
|
|
|
2017-12-07 02:10:38 +08:00
|
|
|
gimp_layer_update_effective_mode (layer);
|
|
|
|
gimp_layer_update_excludes_backdrop (layer);
|
2017-02-02 07:38:25 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
GimpLayerCompositeMode
|
2017-02-13 06:49:26 +08:00
|
|
|
gimp_layer_get_composite_mode (GimpLayer *layer)
|
2017-02-02 07:38:25 +08:00
|
|
|
{
|
2017-02-13 06:49:26 +08:00
|
|
|
g_return_val_if_fail (GIMP_IS_LAYER (layer), GIMP_LAYER_COMPOSITE_AUTO);
|
2017-02-02 07:38:25 +08:00
|
|
|
|
2017-02-13 06:49:26 +08:00
|
|
|
return layer->composite_mode;
|
2017-02-02 07:38:25 +08:00
|
|
|
}
|
|
|
|
|
2017-10-21 23:10:29 +08:00
|
|
|
GimpLayerCompositeMode
|
|
|
|
gimp_layer_get_real_composite_mode (GimpLayer *layer)
|
|
|
|
{
|
2018-03-15 02:52:10 +08:00
|
|
|
g_return_val_if_fail (GIMP_IS_LAYER (layer), GIMP_LAYER_COMPOSITE_UNION);
|
2017-10-21 23:10:29 +08:00
|
|
|
|
|
|
|
if (layer->composite_mode == GIMP_LAYER_COMPOSITE_AUTO)
|
|
|
|
return gimp_layer_mode_get_composite_mode (layer->mode);
|
|
|
|
else
|
|
|
|
return layer->composite_mode;
|
|
|
|
}
|
|
|
|
|
2017-12-07 02:10:38 +08:00
|
|
|
void
|
|
|
|
gimp_layer_get_effective_mode (GimpLayer *layer,
|
|
|
|
GimpLayerMode *mode,
|
|
|
|
GimpLayerColorSpace *blend_space,
|
|
|
|
GimpLayerColorSpace *composite_space,
|
|
|
|
GimpLayerCompositeMode *composite_mode)
|
|
|
|
{
|
|
|
|
g_return_if_fail (GIMP_IS_LAYER (layer));
|
|
|
|
|
|
|
|
if (mode) *mode = layer->effective_mode;
|
|
|
|
if (blend_space) *blend_space = layer->effective_blend_space;
|
|
|
|
if (composite_space) *composite_space = layer->effective_composite_space;
|
|
|
|
if (composite_mode) *composite_mode = layer->effective_composite_mode;
|
|
|
|
}
|
|
|
|
|
2017-05-08 06:49:38 +08:00
|
|
|
gboolean
|
|
|
|
gimp_layer_get_excludes_backdrop (GimpLayer *layer)
|
|
|
|
{
|
|
|
|
g_return_val_if_fail (GIMP_IS_LAYER (layer), FALSE);
|
|
|
|
|
|
|
|
return layer->excludes_backdrop;
|
|
|
|
}
|
|
|
|
|
2001-03-12 01:24:47 +08:00
|
|
|
void
|
2005-07-11 05:17:22 +08:00
|
|
|
gimp_layer_set_lock_alpha (GimpLayer *layer,
|
|
|
|
gboolean lock_alpha,
|
|
|
|
gboolean push_undo)
|
2001-03-12 01:24:47 +08:00
|
|
|
{
|
|
|
|
g_return_if_fail (GIMP_IS_LAYER (layer));
|
2009-08-24 01:54:19 +08:00
|
|
|
g_return_if_fail (gimp_layer_can_lock_alpha (layer));
|
2001-03-12 01:24:47 +08:00
|
|
|
|
2005-07-11 05:17:22 +08:00
|
|
|
lock_alpha = lock_alpha ? TRUE : FALSE;
|
|
|
|
|
|
|
|
if (layer->lock_alpha != lock_alpha)
|
2001-03-12 01:24:47 +08:00
|
|
|
{
|
2004-11-16 21:41:55 +08:00
|
|
|
if (push_undo && gimp_item_is_attached (GIMP_ITEM (layer)))
|
Made drawable/layer properties (visibility, opacity etc.) undoable (fixes
2003-03-17 Michael Natterer <mitch@gimp.org>
Made drawable/layer properties (visibility, opacity etc.)
undoable (fixes bug #73893).
* app/core/core-enums.[ch]: added undo types/groups for
visibility, mode, opacity, linked and preserve_trans.
* app/core/Makefile.am
* app/core/core-types.h
* app/core/gimpitemundo.[ch]: new GimpUndo subclass which holds a
ref'ed GimpItem pointer so (1) this doesn't need to be done by all
undo steps related to an item and (2) the item the undo step is
for can be determined from outside the undo system.
* app/core/gimpimage-undo.[ch]: added gimp_image_undo_push_item()
which returns a new GimpItemUndo.
* app/core/gimpimage-undo-push.[ch]: use it for all item related
undo steps. Removed lots of GimpItem, GimpLayer, GimpDrawable
and GimpVectors pointers from the private undo structs. Added
undo push functions for the new undo types added above.
* app/core/gimpdrawable.[ch] (gimp_drawable_set_visible): added
"gboolean push_undo" parameter.
* app/core/gimplayer.[ch] (gimp_layer_set_opacity, _mode,
_preserve_trans, _linked): added "gboolean push_undo" parameters.
* app/core/gimpimage-mask.c
* app/core/gimpimage-merge.c
* app/core/gimplayer-floating-sel.c
* app/tools/gimpmovetool.c
* app/xcf/xcf-load.c
* app/widgets/gimpdrawablelistitem.c
* app/widgets/gimplayerlistitem.c
* app/widgets/gimplayerlistview.c: changed accordingly.
* tools/pdbgen/pdb/channel.pdb
* tools/pdbgen/pdb/layer.pdb: ditto. Added '$undo' paramaters to
the foo_accessors() functions. Removed $func from foo_accesors()
because we don't manipulate items without using getters/setters
any longer.
* app/pdb/channel_cmds.c
* app/pdb/layer_cmds.c: regenerated.
* app/widgets/gimpcellrenderertoggle.[ch]: added "clicked" signal
which carries an additional "GdkModifierType state" parameter as
in GimpCellRendererViewable .
* app/widgets/gimpcontainertreeview.c: emit "clicked" from
the toggle renderer, not "toggled" so the callbacks get the
modifier state.
* app/widgets/gimpdrawabletreeview.c: resurrected the "exclusive
visible by <shift>+click" feature as in 1.2.
* app/widgets/gimplayertreeview.c: compress layer opacity undos by
looking at the top of the undo stack and not pushing an undo if
there already is a GIMP_UNDO_DRAWABLE_OPACITY for the active
layer.
2003-03-18 02:02:41 +08:00
|
|
|
{
|
2006-03-29 01:08:36 +08:00
|
|
|
GimpImage *image = gimp_item_get_image (GIMP_ITEM (layer));
|
Made drawable/layer properties (visibility, opacity etc.) undoable (fixes
2003-03-17 Michael Natterer <mitch@gimp.org>
Made drawable/layer properties (visibility, opacity etc.)
undoable (fixes bug #73893).
* app/core/core-enums.[ch]: added undo types/groups for
visibility, mode, opacity, linked and preserve_trans.
* app/core/Makefile.am
* app/core/core-types.h
* app/core/gimpitemundo.[ch]: new GimpUndo subclass which holds a
ref'ed GimpItem pointer so (1) this doesn't need to be done by all
undo steps related to an item and (2) the item the undo step is
for can be determined from outside the undo system.
* app/core/gimpimage-undo.[ch]: added gimp_image_undo_push_item()
which returns a new GimpItemUndo.
* app/core/gimpimage-undo-push.[ch]: use it for all item related
undo steps. Removed lots of GimpItem, GimpLayer, GimpDrawable
and GimpVectors pointers from the private undo structs. Added
undo push functions for the new undo types added above.
* app/core/gimpdrawable.[ch] (gimp_drawable_set_visible): added
"gboolean push_undo" parameter.
* app/core/gimplayer.[ch] (gimp_layer_set_opacity, _mode,
_preserve_trans, _linked): added "gboolean push_undo" parameters.
* app/core/gimpimage-mask.c
* app/core/gimpimage-merge.c
* app/core/gimplayer-floating-sel.c
* app/tools/gimpmovetool.c
* app/xcf/xcf-load.c
* app/widgets/gimpdrawablelistitem.c
* app/widgets/gimplayerlistitem.c
* app/widgets/gimplayerlistview.c: changed accordingly.
* tools/pdbgen/pdb/channel.pdb
* tools/pdbgen/pdb/layer.pdb: ditto. Added '$undo' paramaters to
the foo_accessors() functions. Removed $func from foo_accesors()
because we don't manipulate items without using getters/setters
any longer.
* app/pdb/channel_cmds.c
* app/pdb/layer_cmds.c: regenerated.
* app/widgets/gimpcellrenderertoggle.[ch]: added "clicked" signal
which carries an additional "GdkModifierType state" parameter as
in GimpCellRendererViewable .
* app/widgets/gimpcontainertreeview.c: emit "clicked" from
the toggle renderer, not "toggled" so the callbacks get the
modifier state.
* app/widgets/gimpdrawabletreeview.c: resurrected the "exclusive
visible by <shift>+click" feature as in 1.2.
* app/widgets/gimplayertreeview.c: compress layer opacity undos by
looking at the top of the undo stack and not pushing an undo if
there already is a GIMP_UNDO_DRAWABLE_OPACITY for the active
layer.
2003-03-18 02:02:41 +08:00
|
|
|
|
2006-03-29 01:08:36 +08:00
|
|
|
gimp_image_undo_push_layer_lock_alpha (image, NULL, layer);
|
Made drawable/layer properties (visibility, opacity etc.) undoable (fixes
2003-03-17 Michael Natterer <mitch@gimp.org>
Made drawable/layer properties (visibility, opacity etc.)
undoable (fixes bug #73893).
* app/core/core-enums.[ch]: added undo types/groups for
visibility, mode, opacity, linked and preserve_trans.
* app/core/Makefile.am
* app/core/core-types.h
* app/core/gimpitemundo.[ch]: new GimpUndo subclass which holds a
ref'ed GimpItem pointer so (1) this doesn't need to be done by all
undo steps related to an item and (2) the item the undo step is
for can be determined from outside the undo system.
* app/core/gimpimage-undo.[ch]: added gimp_image_undo_push_item()
which returns a new GimpItemUndo.
* app/core/gimpimage-undo-push.[ch]: use it for all item related
undo steps. Removed lots of GimpItem, GimpLayer, GimpDrawable
and GimpVectors pointers from the private undo structs. Added
undo push functions for the new undo types added above.
* app/core/gimpdrawable.[ch] (gimp_drawable_set_visible): added
"gboolean push_undo" parameter.
* app/core/gimplayer.[ch] (gimp_layer_set_opacity, _mode,
_preserve_trans, _linked): added "gboolean push_undo" parameters.
* app/core/gimpimage-mask.c
* app/core/gimpimage-merge.c
* app/core/gimplayer-floating-sel.c
* app/tools/gimpmovetool.c
* app/xcf/xcf-load.c
* app/widgets/gimpdrawablelistitem.c
* app/widgets/gimplayerlistitem.c
* app/widgets/gimplayerlistview.c: changed accordingly.
* tools/pdbgen/pdb/channel.pdb
* tools/pdbgen/pdb/layer.pdb: ditto. Added '$undo' paramaters to
the foo_accessors() functions. Removed $func from foo_accesors()
because we don't manipulate items without using getters/setters
any longer.
* app/pdb/channel_cmds.c
* app/pdb/layer_cmds.c: regenerated.
* app/widgets/gimpcellrenderertoggle.[ch]: added "clicked" signal
which carries an additional "GdkModifierType state" parameter as
in GimpCellRendererViewable .
* app/widgets/gimpcontainertreeview.c: emit "clicked" from
the toggle renderer, not "toggled" so the callbacks get the
modifier state.
* app/widgets/gimpdrawabletreeview.c: resurrected the "exclusive
visible by <shift>+click" feature as in 1.2.
* app/widgets/gimplayertreeview.c: compress layer opacity undos by
looking at the top of the undo stack and not pushing an undo if
there already is a GIMP_UNDO_DRAWABLE_OPACITY for the active
layer.
2003-03-18 02:02:41 +08:00
|
|
|
}
|
2003-08-28 01:21:49 +08:00
|
|
|
|
2005-07-11 05:17:22 +08:00
|
|
|
layer->lock_alpha = lock_alpha;
|
2001-03-12 01:24:47 +08:00
|
|
|
|
2005-07-11 05:17:22 +08:00
|
|
|
g_signal_emit (layer, layer_signals[LOCK_ALPHA_CHANGED], 0);
|
2005-07-12 00:46:28 +08:00
|
|
|
g_object_notify (G_OBJECT (layer), "lock-alpha");
|
2001-03-12 01:24:47 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
gboolean
|
2016-05-20 05:51:44 +08:00
|
|
|
gimp_layer_get_lock_alpha (GimpLayer *layer)
|
2001-03-12 01:24:47 +08:00
|
|
|
{
|
|
|
|
g_return_val_if_fail (GIMP_IS_LAYER (layer), FALSE);
|
|
|
|
|
2005-07-11 05:17:22 +08:00
|
|
|
return layer->lock_alpha;
|
2001-03-12 01:24:47 +08:00
|
|
|
}
|
2009-08-24 00:44:05 +08:00
|
|
|
|
|
|
|
gboolean
|
2016-05-20 05:51:44 +08:00
|
|
|
gimp_layer_can_lock_alpha (GimpLayer *layer)
|
2009-08-24 00:44:05 +08:00
|
|
|
{
|
|
|
|
g_return_val_if_fail (GIMP_IS_LAYER (layer), FALSE);
|
|
|
|
|
|
|
|
if (gimp_viewable_get_children (GIMP_VIEWABLE (layer)))
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
2017-05-08 06:49:38 +08:00
|
|
|
|
|
|
|
|
|
|
|
/* protected functions */
|
|
|
|
|
2017-12-07 02:10:38 +08:00
|
|
|
void
|
|
|
|
gimp_layer_update_effective_mode (GimpLayer *layer)
|
|
|
|
{
|
|
|
|
GimpLayerMode mode;
|
|
|
|
GimpLayerColorSpace blend_space;
|
|
|
|
GimpLayerColorSpace composite_space;
|
|
|
|
GimpLayerCompositeMode composite_mode;
|
|
|
|
|
|
|
|
g_return_if_fail (GIMP_IS_LAYER (layer));
|
|
|
|
|
|
|
|
GIMP_LAYER_GET_CLASS (layer)->get_effective_mode (layer,
|
|
|
|
&mode,
|
|
|
|
&blend_space,
|
|
|
|
&composite_space,
|
|
|
|
&composite_mode);
|
|
|
|
|
|
|
|
if (mode != layer->effective_mode ||
|
|
|
|
blend_space != layer->effective_blend_space ||
|
|
|
|
composite_space != layer->effective_composite_space ||
|
|
|
|
composite_mode != layer->effective_composite_mode)
|
|
|
|
{
|
|
|
|
layer->effective_mode = mode;
|
|
|
|
layer->effective_blend_space = blend_space;
|
|
|
|
layer->effective_composite_space = composite_space;
|
|
|
|
layer->effective_composite_mode = composite_mode;
|
|
|
|
|
|
|
|
g_signal_emit (layer, layer_signals[EFFECTIVE_MODE_CHANGED], 0);
|
|
|
|
|
|
|
|
if (gimp_filter_peek_node (GIMP_FILTER (layer)))
|
|
|
|
gimp_layer_update_mode_node (layer);
|
|
|
|
|
|
|
|
gimp_drawable_update (GIMP_DRAWABLE (layer), 0, 0, -1, -1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-05-08 06:49:38 +08:00
|
|
|
void
|
|
|
|
gimp_layer_update_excludes_backdrop (GimpLayer *layer)
|
|
|
|
{
|
|
|
|
gboolean excludes_backdrop;
|
|
|
|
|
|
|
|
g_return_if_fail (GIMP_IS_LAYER (layer));
|
|
|
|
|
|
|
|
excludes_backdrop =
|
|
|
|
GIMP_LAYER_GET_CLASS (layer)->get_excludes_backdrop (layer);
|
|
|
|
|
|
|
|
if (excludes_backdrop != layer->excludes_backdrop)
|
|
|
|
{
|
|
|
|
layer->excludes_backdrop = excludes_backdrop;
|
|
|
|
|
|
|
|
g_signal_emit (layer, layer_signals[EXCLUDES_BACKDROP_CHANGED], 0);
|
|
|
|
g_object_notify (G_OBJECT (layer), "excludes-backdrop");
|
|
|
|
}
|
|
|
|
}
|