made all functions which push an undo step virtual and added them all as

2003-09-03  Michael Natterer  <mitch@gimp.org>

	* app/core/gimpchannel.[ch]: made all functions which push an
	undo step virtual and added them all as default implementations.

	* app/core/Makefile.am
	* app/core/core-types.h
	* app/core/gimpselection.[ch]: new object which is a GimpChannel
	subclass and implements all of its virtual functions, pushes
	an image_mask undo and chains up with "push_undo = FALSE".

	* app/core/gimpimage-mask.[ch]: made most functions simple
	wrappers like gimp_channel_invert(gimp_image_get_mask(gimage));
	so the API stays the same for now.

	* app/core/gimpimage.[ch]: create a GimpSelection object
	as gimage->selection_mask. Removed "gboolean mask_stroking"
	since it is in GimpSelection now.

	* app/xcf/xcf-load.c (xcf_load_channel_props): added an evil hack
	which turns a GimpChannel into a GimpSelection once we figured the
	loaded channel is the selection.

	* app/core/gimplayer.c (gimp_layer_create_mask):
	gimp_channel_clear() takes an additional "const gchar *undo_desc"
	parameter now.

	* app/core/gimpscanconvert.c (gimp_scan_convert_to_channel): set
	mask->bounds_known to FALSE before returning the new channel

	* app/tools/gimpiscissorstool.c (iscissors_convert): no need to
	call gimp_channel_invalidate_boundary() on the channel returned by
	the above function.

	* app/core/gimpchannel.[ch]: removed
	gimp_channel_invalidate_boundary() since it is no longer needed.
This commit is contained in:
Michael Natterer 2003-09-02 23:07:40 +00:00 committed by Michael Natterer
parent 443a5f3fd2
commit 420d17d286
17 changed files with 2708 additions and 1755 deletions

View File

@ -1,3 +1,40 @@
2003-09-03 Michael Natterer <mitch@gimp.org>
* app/core/gimpchannel.[ch]: made all functions which push an
undo step virtual and added them all as default implementations.
* app/core/Makefile.am
* app/core/core-types.h
* app/core/gimpselection.[ch]: new object which is a GimpChannel
subclass and implements all of its virtual functions, pushes
an image_mask undo and chains up with "push_undo = FALSE".
* app/core/gimpimage-mask.[ch]: made most functions simple
wrappers like gimp_channel_invert(gimp_image_get_mask(gimage));
so the API stays the same for now.
* app/core/gimpimage.[ch]: create a GimpSelection object
as gimage->selection_mask. Removed "gboolean mask_stroking"
since it is in GimpSelection now.
* app/xcf/xcf-load.c (xcf_load_channel_props): added an evil hack
which turns a GimpChannel into a GimpSelection once we figured the
loaded channel is the selection.
* app/core/gimplayer.c (gimp_layer_create_mask):
gimp_channel_clear() takes an additional "const gchar *undo_desc"
parameter now.
* app/core/gimpscanconvert.c (gimp_scan_convert_to_channel): set
mask->bounds_known to FALSE before returning the new channel
* app/tools/gimpiscissorstool.c (iscissors_convert): no need to
call gimp_channel_invalidate_boundary() on the channel returned by
the above function.
* app/core/gimpchannel.[ch]: removed
gimp_channel_invalidate_boundary() since it is no longer needed.
2003-09-03 Sven Neumann <sven@gimp.org> 2003-09-03 Sven Neumann <sven@gimp.org>
* libgimpcolor/gimpcolorspace.[ch] (gimp_rgb_to_cmyk_int): made * libgimpcolor/gimpcolorspace.[ch] (gimp_rgb_to_cmyk_int): made

View File

@ -172,6 +172,8 @@ libappcore_a_sources = \
gimppreviewcache.h \ gimppreviewcache.h \
gimpscanconvert.c \ gimpscanconvert.c \
gimpscanconvert.h \ gimpscanconvert.h \
gimpselection.c \
gimpselection.h \
gimptemplate.c \ gimptemplate.c \
gimptemplate.h \ gimptemplate.h \
gimptoolinfo.c \ gimptoolinfo.c \

View File

@ -80,6 +80,7 @@ typedef struct _GimpGrid GimpGrid;
typedef struct _GimpDrawable GimpDrawable; typedef struct _GimpDrawable GimpDrawable;
typedef struct _GimpChannel GimpChannel; typedef struct _GimpChannel GimpChannel;
typedef struct _GimpSelection GimpSelection;
typedef struct _GimpLayer GimpLayer; typedef struct _GimpLayer GimpLayer;
typedef struct _GimpLayerMask GimpLayerMask; typedef struct _GimpLayerMask GimpLayerMask;

File diff suppressed because it is too large Load Diff

View File

@ -59,131 +59,175 @@ struct _GimpChannel
struct _GimpChannelClass struct _GimpChannelClass
{ {
GimpDrawableClass parent_class; GimpDrawableClass parent_class;
gboolean (* boundary) (GimpChannel *channel,
const BoundSeg **segs_in,
const BoundSeg **segs_out,
gint *num_segs_in,
gint *num_segs_out,
gint x1,
gint y1,
gint x2,
gint y2);
gboolean (* bounds) (GimpChannel *channel,
gint *x1,
gint *y1,
gint *x2,
gint *y2);
gint (* value) (GimpChannel *channel,
gint x,
gint y);
gboolean (* is_empty) (GimpChannel *channel);
void (* feather) (GimpChannel *channel,
gdouble radius_x,
gdouble radius_y,
gboolean push_undo);
void (* sharpen) (GimpChannel *channel,
gboolean push_undo);
void (* clear) (GimpChannel *channel,
const gchar *undo_desc,
gboolean push_undo);
void (* all) (GimpChannel *channel,
gboolean push_undo);
void (* invert) (GimpChannel *channel,
gboolean push_undo);
void (* border) (GimpChannel *channel,
gint radius_x,
gint radius_y,
gboolean push_undo);
void (* grow) (GimpChannel *channel,
gint radius_x,
gint radius_y,
gboolean push_undo);
void (* shrink) (GimpChannel *channel,
gint radius_x,
gint radius_y,
gboolean edge_lock,
gboolean push_undo);
}; };
/* function declarations */ /* function declarations */
GType gimp_channel_get_type (void) G_GNUC_CONST; GType gimp_channel_get_type (void) G_GNUC_CONST;
GimpChannel * gimp_channel_new (GimpImage *gimage, GimpChannel * gimp_channel_new (GimpImage *gimage,
gint width, gint width,
gint height, gint height,
const gchar *name, const gchar *name,
const GimpRGB *color); const GimpRGB *color);
GimpChannel * gimp_channel_new_from_alpha (GimpImage *gimage, GimpChannel * gimp_channel_new_from_alpha (GimpImage *gimage,
GimpLayer *layer, GimpLayer *layer,
const gchar *name, const gchar *name,
const GimpRGB *color); const GimpRGB *color);
GimpChannel * gimp_channel_new_from_component (GimpImage *gimage, GimpChannel * gimp_channel_new_from_component (GimpImage *gimage,
GimpChannelType type, GimpChannelType type,
const gchar *name, const gchar *name,
const GimpRGB *color); const GimpRGB *color);
gdouble gimp_channel_get_opacity (const GimpChannel *channel); gdouble gimp_channel_get_opacity (const GimpChannel *channel);
void gimp_channel_set_opacity (GimpChannel *channel, void gimp_channel_set_opacity (GimpChannel *channel,
gdouble opacity, gdouble opacity,
gboolean push_undo); gboolean push_undo);
void gimp_channel_get_color (const GimpChannel *channel, void gimp_channel_get_color (const GimpChannel *channel,
GimpRGB *color); GimpRGB *color);
void gimp_channel_set_color (GimpChannel *channel, void gimp_channel_set_color (GimpChannel *channel,
const GimpRGB *color, const GimpRGB *color,
gboolean push_undo); gboolean push_undo);
gboolean gimp_channel_get_show_masked (GimpChannel *channel); gboolean gimp_channel_get_show_masked (GimpChannel *channel);
void gimp_channel_set_show_masked (GimpChannel *channel, void gimp_channel_set_show_masked (GimpChannel *channel,
gboolean show_masked); gboolean show_masked);
/* selection mask functions */ /* selection mask functions */
GimpChannel * gimp_channel_new_mask (GimpImage *gimage, GimpChannel * gimp_channel_new_mask (GimpImage *gimage,
gint width, gint width,
gint height); gint height);
gboolean gimp_channel_boundary (GimpChannel *mask, gboolean gimp_channel_boundary (GimpChannel *mask,
const BoundSeg **segs_in, const BoundSeg **segs_in,
const BoundSeg **segs_out, const BoundSeg **segs_out,
gint *num_segs_in, gint *num_segs_in,
gint *num_segs_out, gint *num_segs_out,
gint x1, gint x1,
gint y1, gint y1,
gint x2, gint x2,
gint y2); gint y2);
gboolean gimp_channel_bounds (GimpChannel *mask, gboolean gimp_channel_bounds (GimpChannel *mask,
gint *x1, gint *x1,
gint *y1, gint *y1,
gint *x2, gint *x2,
gint *y2); gint *y2);
gint gimp_channel_value (GimpChannel *mask, gint gimp_channel_value (GimpChannel *mask,
gint x, gint x,
gint y); gint y);
gboolean gimp_channel_is_empty (GimpChannel *mask); gboolean gimp_channel_is_empty (GimpChannel *mask);
void gimp_channel_add_segment (GimpChannel *mask, void gimp_channel_add_segment (GimpChannel *mask,
gint x, gint x,
gint y, gint y,
gint width, gint width,
gint value); gint value);
void gimp_channel_sub_segment (GimpChannel *mask, void gimp_channel_sub_segment (GimpChannel *mask,
gint x, gint x,
gint y, gint y,
gint width, gint width,
gint value); gint value);
void gimp_channel_combine_rect (GimpChannel *mask, void gimp_channel_combine_rect (GimpChannel *mask,
GimpChannelOps op, GimpChannelOps op,
gint x, gint x,
gint y, gint y,
gint w, gint w,
gint h); gint h);
void gimp_channel_combine_ellipse (GimpChannel *mask, void gimp_channel_combine_ellipse (GimpChannel *mask,
GimpChannelOps op, GimpChannelOps op,
gint x, gint x,
gint y, gint y,
gint w, gint w,
gint h, gint h,
gboolean antialias); gboolean antialias);
void gimp_channel_combine_mask (GimpChannel *mask, void gimp_channel_combine_mask (GimpChannel *mask,
GimpChannel *add_on, GimpChannel *add_on,
GimpChannelOps op, GimpChannelOps op,
gint off_x, gint off_x,
gint off_y); gint off_y);
void gimp_channel_feather (GimpChannel *mask, void gimp_channel_feather (GimpChannel *mask,
gdouble radius_x, gdouble radius_x,
gdouble radius_y, gdouble radius_y,
gboolean push_undo); gboolean push_undo);
void gimp_channel_sharpen (GimpChannel *mask, void gimp_channel_sharpen (GimpChannel *mask,
gboolean push_undo); gboolean push_undo);
void gimp_channel_clear (GimpChannel *mask, void gimp_channel_clear (GimpChannel *mask,
gboolean push_undo); const gchar *undo_desc,
void gimp_channel_all (GimpChannel *mask, gboolean push_undo);
gboolean push_undo); void gimp_channel_all (GimpChannel *mask,
void gimp_channel_invert (GimpChannel *mask, gboolean push_undo);
gboolean push_undo); void gimp_channel_invert (GimpChannel *mask,
gboolean push_undo);
void gimp_channel_border (GimpChannel *mask, void gimp_channel_border (GimpChannel *mask,
gint radius_x, gint radius_x,
gint radius_y, gint radius_y,
gboolean push_undo); gboolean push_undo);
void gimp_channel_grow (GimpChannel *mask, void gimp_channel_grow (GimpChannel *mask,
gint radius_x, gint radius_x,
gint radius_y, gint radius_y,
gboolean push_undo); gboolean push_undo);
void gimp_channel_shrink (GimpChannel *mask, void gimp_channel_shrink (GimpChannel *mask,
gint radius_x, gint radius_x,
gint radius_y, gint radius_y,
gboolean edge_lock, gboolean edge_lock,
gboolean push_undo); gboolean push_undo);
void gimp_channel_load (GimpChannel *mask, void gimp_channel_load (GimpChannel *mask,
GimpChannel *channel, GimpChannel *channel,
gboolean push_undo); gboolean push_undo);
void gimp_channel_invalidate_bounds (GimpChannel *channel);
#endif /* __GIMP_CHANNEL_H__ */ #endif /* __GIMP_CHANNEL_H__ */

File diff suppressed because it is too large Load Diff

View File

@ -59,131 +59,175 @@ struct _GimpChannel
struct _GimpChannelClass struct _GimpChannelClass
{ {
GimpDrawableClass parent_class; GimpDrawableClass parent_class;
gboolean (* boundary) (GimpChannel *channel,
const BoundSeg **segs_in,
const BoundSeg **segs_out,
gint *num_segs_in,
gint *num_segs_out,
gint x1,
gint y1,
gint x2,
gint y2);
gboolean (* bounds) (GimpChannel *channel,
gint *x1,
gint *y1,
gint *x2,
gint *y2);
gint (* value) (GimpChannel *channel,
gint x,
gint y);
gboolean (* is_empty) (GimpChannel *channel);
void (* feather) (GimpChannel *channel,
gdouble radius_x,
gdouble radius_y,
gboolean push_undo);
void (* sharpen) (GimpChannel *channel,
gboolean push_undo);
void (* clear) (GimpChannel *channel,
const gchar *undo_desc,
gboolean push_undo);
void (* all) (GimpChannel *channel,
gboolean push_undo);
void (* invert) (GimpChannel *channel,
gboolean push_undo);
void (* border) (GimpChannel *channel,
gint radius_x,
gint radius_y,
gboolean push_undo);
void (* grow) (GimpChannel *channel,
gint radius_x,
gint radius_y,
gboolean push_undo);
void (* shrink) (GimpChannel *channel,
gint radius_x,
gint radius_y,
gboolean edge_lock,
gboolean push_undo);
}; };
/* function declarations */ /* function declarations */
GType gimp_channel_get_type (void) G_GNUC_CONST; GType gimp_channel_get_type (void) G_GNUC_CONST;
GimpChannel * gimp_channel_new (GimpImage *gimage, GimpChannel * gimp_channel_new (GimpImage *gimage,
gint width, gint width,
gint height, gint height,
const gchar *name, const gchar *name,
const GimpRGB *color); const GimpRGB *color);
GimpChannel * gimp_channel_new_from_alpha (GimpImage *gimage, GimpChannel * gimp_channel_new_from_alpha (GimpImage *gimage,
GimpLayer *layer, GimpLayer *layer,
const gchar *name, const gchar *name,
const GimpRGB *color); const GimpRGB *color);
GimpChannel * gimp_channel_new_from_component (GimpImage *gimage, GimpChannel * gimp_channel_new_from_component (GimpImage *gimage,
GimpChannelType type, GimpChannelType type,
const gchar *name, const gchar *name,
const GimpRGB *color); const GimpRGB *color);
gdouble gimp_channel_get_opacity (const GimpChannel *channel); gdouble gimp_channel_get_opacity (const GimpChannel *channel);
void gimp_channel_set_opacity (GimpChannel *channel, void gimp_channel_set_opacity (GimpChannel *channel,
gdouble opacity, gdouble opacity,
gboolean push_undo); gboolean push_undo);
void gimp_channel_get_color (const GimpChannel *channel, void gimp_channel_get_color (const GimpChannel *channel,
GimpRGB *color); GimpRGB *color);
void gimp_channel_set_color (GimpChannel *channel, void gimp_channel_set_color (GimpChannel *channel,
const GimpRGB *color, const GimpRGB *color,
gboolean push_undo); gboolean push_undo);
gboolean gimp_channel_get_show_masked (GimpChannel *channel); gboolean gimp_channel_get_show_masked (GimpChannel *channel);
void gimp_channel_set_show_masked (GimpChannel *channel, void gimp_channel_set_show_masked (GimpChannel *channel,
gboolean show_masked); gboolean show_masked);
/* selection mask functions */ /* selection mask functions */
GimpChannel * gimp_channel_new_mask (GimpImage *gimage, GimpChannel * gimp_channel_new_mask (GimpImage *gimage,
gint width, gint width,
gint height); gint height);
gboolean gimp_channel_boundary (GimpChannel *mask, gboolean gimp_channel_boundary (GimpChannel *mask,
const BoundSeg **segs_in, const BoundSeg **segs_in,
const BoundSeg **segs_out, const BoundSeg **segs_out,
gint *num_segs_in, gint *num_segs_in,
gint *num_segs_out, gint *num_segs_out,
gint x1, gint x1,
gint y1, gint y1,
gint x2, gint x2,
gint y2); gint y2);
gboolean gimp_channel_bounds (GimpChannel *mask, gboolean gimp_channel_bounds (GimpChannel *mask,
gint *x1, gint *x1,
gint *y1, gint *y1,
gint *x2, gint *x2,
gint *y2); gint *y2);
gint gimp_channel_value (GimpChannel *mask, gint gimp_channel_value (GimpChannel *mask,
gint x, gint x,
gint y); gint y);
gboolean gimp_channel_is_empty (GimpChannel *mask); gboolean gimp_channel_is_empty (GimpChannel *mask);
void gimp_channel_add_segment (GimpChannel *mask, void gimp_channel_add_segment (GimpChannel *mask,
gint x, gint x,
gint y, gint y,
gint width, gint width,
gint value); gint value);
void gimp_channel_sub_segment (GimpChannel *mask, void gimp_channel_sub_segment (GimpChannel *mask,
gint x, gint x,
gint y, gint y,
gint width, gint width,
gint value); gint value);
void gimp_channel_combine_rect (GimpChannel *mask, void gimp_channel_combine_rect (GimpChannel *mask,
GimpChannelOps op, GimpChannelOps op,
gint x, gint x,
gint y, gint y,
gint w, gint w,
gint h); gint h);
void gimp_channel_combine_ellipse (GimpChannel *mask, void gimp_channel_combine_ellipse (GimpChannel *mask,
GimpChannelOps op, GimpChannelOps op,
gint x, gint x,
gint y, gint y,
gint w, gint w,
gint h, gint h,
gboolean antialias); gboolean antialias);
void gimp_channel_combine_mask (GimpChannel *mask, void gimp_channel_combine_mask (GimpChannel *mask,
GimpChannel *add_on, GimpChannel *add_on,
GimpChannelOps op, GimpChannelOps op,
gint off_x, gint off_x,
gint off_y); gint off_y);
void gimp_channel_feather (GimpChannel *mask, void gimp_channel_feather (GimpChannel *mask,
gdouble radius_x, gdouble radius_x,
gdouble radius_y, gdouble radius_y,
gboolean push_undo); gboolean push_undo);
void gimp_channel_sharpen (GimpChannel *mask, void gimp_channel_sharpen (GimpChannel *mask,
gboolean push_undo); gboolean push_undo);
void gimp_channel_clear (GimpChannel *mask, void gimp_channel_clear (GimpChannel *mask,
gboolean push_undo); const gchar *undo_desc,
void gimp_channel_all (GimpChannel *mask, gboolean push_undo);
gboolean push_undo); void gimp_channel_all (GimpChannel *mask,
void gimp_channel_invert (GimpChannel *mask, gboolean push_undo);
gboolean push_undo); void gimp_channel_invert (GimpChannel *mask,
gboolean push_undo);
void gimp_channel_border (GimpChannel *mask, void gimp_channel_border (GimpChannel *mask,
gint radius_x, gint radius_x,
gint radius_y, gint radius_y,
gboolean push_undo); gboolean push_undo);
void gimp_channel_grow (GimpChannel *mask, void gimp_channel_grow (GimpChannel *mask,
gint radius_x, gint radius_x,
gint radius_y, gint radius_y,
gboolean push_undo); gboolean push_undo);
void gimp_channel_shrink (GimpChannel *mask, void gimp_channel_shrink (GimpChannel *mask,
gint radius_x, gint radius_x,
gint radius_y, gint radius_y,
gboolean edge_lock, gboolean edge_lock,
gboolean push_undo); gboolean push_undo);
void gimp_channel_load (GimpChannel *mask, void gimp_channel_load (GimpChannel *mask,
GimpChannel *channel, GimpChannel *channel,
gboolean push_undo); gboolean push_undo);
void gimp_channel_invalidate_bounds (GimpChannel *channel);
#endif /* __GIMP_CHANNEL_H__ */ #endif /* __GIMP_CHANNEL_H__ */

View File

@ -28,8 +28,6 @@
#include "paint-funcs/paint-funcs.h" #include "paint-funcs/paint-funcs.h"
#include "paint/gimppaintcore-stroke.h"
#include "gimp.h" #include "gimp.h"
#include "gimpchannel.h" #include "gimpchannel.h"
#include "gimpcontainer.h" #include "gimpcontainer.h"
@ -41,7 +39,7 @@
#include "gimplayer.h" #include "gimplayer.h"
#include "gimplayer-floating-sel.h" #include "gimplayer-floating-sel.h"
#include "gimplayermask.h" #include "gimplayermask.h"
#include "gimppaintinfo.h" #include "gimpselection.h"
#include "gimp-intl.h" #include "gimp-intl.h"
@ -55,83 +53,14 @@ gimp_image_mask_boundary (GimpImage *gimage,
gint *num_segs_in, gint *num_segs_in,
gint *num_segs_out) gint *num_segs_out)
{ {
GimpDrawable *drawable;
GimpLayer *layer;
g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE);
g_return_val_if_fail (segs_in != NULL, FALSE);
g_return_val_if_fail (segs_out != NULL, FALSE);
g_return_val_if_fail (num_segs_in != NULL, FALSE);
g_return_val_if_fail (num_segs_out != NULL, FALSE);
if ((layer = gimp_image_floating_sel (gimage))) return gimp_channel_boundary (gimp_image_get_mask (gimage),
{ segs_in, segs_out,
/* If there is a floating selection, then num_segs_in, num_segs_out,
* we need to do some slightly different boundaries. 0, 0, 0, 0);
* Instead of inside and outside boundaries being defined
* by the extents of the layer, the inside boundary (the one
* that actually marches and is black/white) is the boundary of
* the floating selection. The outside boundary (doesn't move,
* is black/gray) is defined as the normal selection mask
*/
/* Find the selection mask boundary */
gimp_channel_boundary (gimp_image_get_mask (gimage),
segs_in, segs_out,
num_segs_in, num_segs_out,
0, 0, 0, 0);
/* Find the floating selection boundary */
*segs_in = floating_sel_boundary (layer, num_segs_in);
return TRUE;
}
else if ((drawable = gimp_image_active_drawable (gimage)) &&
GIMP_IS_CHANNEL (drawable))
{
/* Otherwise, return the boundary...if a channel is active */
return gimp_channel_boundary (gimp_image_get_mask (gimage),
segs_in, segs_out,
num_segs_in, num_segs_out,
0, 0, gimage->width, gimage->height);
}
else if ((layer = gimp_image_get_active_layer (gimage)))
{
/* If a layer is active, we return multiple boundaries based
* on the extents
*/
gint x1, y1;
gint x2, y2;
gint off_x, off_y;
gimp_item_offsets (GIMP_ITEM (layer), &off_x, &off_y);
x1 = CLAMP (off_x, 0, gimage->width);
y1 = CLAMP (off_y, 0, gimage->height);
x2 = CLAMP (off_x + gimp_item_width (GIMP_ITEM (layer)), 0,
gimage->width);
y2 = CLAMP (off_y + gimp_item_height (GIMP_ITEM (layer)), 0,
gimage->height);
return gimp_channel_boundary (gimp_image_get_mask (gimage),
segs_in, segs_out,
num_segs_in, num_segs_out,
x1, y1, x2, y2);
}
else
{
*segs_in = NULL;
*segs_out = NULL;
*num_segs_in = 0;
*num_segs_out = 0;
return FALSE;
}
} }
gboolean gboolean
gimp_image_mask_bounds (GimpImage *gimage, gimp_image_mask_bounds (GimpImage *gimage,
gint *x1, gint *x1,
@ -139,61 +68,160 @@ gimp_image_mask_bounds (GimpImage *gimage,
gint *x2, gint *x2,
gint *y2) gint *y2)
{ {
g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE);
return gimp_channel_bounds (gimp_image_get_mask (gimage), x1, y1, x2, y2); return gimp_channel_bounds (gimp_image_get_mask (gimage), x1, y1, x2, y2);
} }
void
gimp_image_mask_invalidate (GimpImage *gimage)
{
GimpLayer *layer;
GimpChannel *mask;
/* Turn the current selection off */
gimp_image_selection_control (gimage, GIMP_SELECTION_OFF);
mask = gimp_image_get_mask (gimage);
mask->boundary_known = FALSE;
/* If there is a floating selection, update it's area...
* we need to do this since this selection mask can act as an additional
* mask in the composition of the floating selection
*/
layer = gimp_image_get_active_layer (gimage);
if (layer && gimp_layer_is_floating_sel (layer))
gimp_drawable_update (GIMP_DRAWABLE (layer),
0, 0,
GIMP_ITEM (layer)->width,
GIMP_ITEM (layer)->height);
/* invalidate the preview */
GIMP_DRAWABLE (mask)->preview_valid = FALSE;
}
gint gint
gimp_image_mask_value (GimpImage *gimage, gimp_image_mask_value (GimpImage *gimage,
gint x, gint x,
gint y) gint y)
{ {
g_return_val_if_fail (GIMP_IS_IMAGE (gimage), 0);
return gimp_channel_value (gimp_image_get_mask (gimage), x, y); return gimp_channel_value (gimp_image_get_mask (gimage), x, y);
} }
gboolean gboolean
gimp_image_mask_is_empty (GimpImage *gimage) gimp_image_mask_is_empty (GimpImage *gimage)
{ {
/* in order to allow stroking of selections, we need to pretend here g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE);
* that the selection mask is empty so that it doesn't mask the paint
* during the stroke operation. return gimp_channel_is_empty (gimp_image_get_mask (gimage));
*/
if (gimage->mask_stroking)
return TRUE;
else
return gimp_channel_is_empty (gimp_image_get_mask (gimage));
} }
void
gimp_image_mask_feather (GimpImage *gimage,
gdouble feather_radius_x,
gdouble feather_radius_y)
{
g_return_if_fail (GIMP_IS_IMAGE (gimage));
gimp_channel_feather (gimp_image_get_mask (gimage),
feather_radius_x,
feather_radius_y,
TRUE);
}
void
gimp_image_mask_sharpen (GimpImage *gimage)
{
g_return_if_fail (GIMP_IS_IMAGE (gimage));
gimp_channel_sharpen (gimp_image_get_mask (gimage), TRUE);
}
void
gimp_image_mask_clear (GimpImage *gimage,
const gchar *undo_desc)
{
g_return_if_fail (GIMP_IS_IMAGE (gimage));
gimp_channel_clear (gimp_image_get_mask (gimage), undo_desc, TRUE);
}
void
gimp_image_mask_all (GimpImage *gimage)
{
g_return_if_fail (GIMP_IS_IMAGE (gimage));
gimp_channel_all (gimp_image_get_mask (gimage), TRUE);
}
void
gimp_image_mask_invert (GimpImage *gimage)
{
g_return_if_fail (GIMP_IS_IMAGE (gimage));
gimp_channel_invert (gimp_image_get_mask (gimage), TRUE);
}
void
gimp_image_mask_border (GimpImage *gimage,
gint border_radius_x,
gint border_radius_y)
{
g_return_if_fail (GIMP_IS_IMAGE (gimage));
gimp_channel_border (gimp_image_get_mask (gimage),
border_radius_x,
border_radius_y,
TRUE);
}
void
gimp_image_mask_grow (GimpImage *gimage,
gint grow_pixels_x,
gint grow_pixels_y)
{
g_return_if_fail (GIMP_IS_IMAGE (gimage));
gimp_channel_grow (gimp_image_get_mask (gimage),
grow_pixels_x,
grow_pixels_y,
TRUE);
}
void
gimp_image_mask_shrink (GimpImage *gimage,
gint shrink_pixels_x,
gint shrink_pixels_y,
gboolean edge_lock)
{
g_return_if_fail (GIMP_IS_IMAGE (gimage));
gimp_channel_shrink (gimp_image_get_mask (gimage),
shrink_pixels_x,
shrink_pixels_y,
edge_lock,
TRUE);
}
void
gimp_image_mask_translate (GimpImage *gimage,
gint off_x,
gint off_y,
gboolean push_undo)
{
g_return_if_fail (GIMP_IS_IMAGE (gimage));
gimp_item_translate (GIMP_ITEM (gimp_image_get_mask (gimage)),
off_x, off_y, TRUE);
}
gboolean
gimp_image_mask_stroke (GimpImage *gimage,
GimpDrawable *drawable,
GimpPaintInfo *paint_info)
{
g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE);
return gimp_item_stroke (GIMP_ITEM (gimp_image_get_mask (gimage)),
drawable, paint_info);
}
void
gimp_image_mask_push_undo (GimpImage *gimage,
const gchar *undo_desc)
{
g_return_if_fail (GIMP_IS_IMAGE (gimage));
gimp_selection_push_undo (GIMP_SELECTION (gimp_image_get_mask (gimage)),
undo_desc);
}
void
gimp_image_mask_invalidate (GimpImage *gimage)
{
g_return_if_fail (GIMP_IS_IMAGE (gimage));
gimp_selection_invalidate (GIMP_SELECTION (gimp_image_get_mask (gimage)));
}
TileManager * TileManager *
gimp_image_mask_extract (GimpImage *gimage, gimp_image_mask_extract (GimpImage *gimage,
@ -421,163 +449,6 @@ gimp_image_mask_float (GimpImage *gimage,
return layer; return layer;
} }
void
gimp_image_mask_push_undo (GimpImage *gimage,
const gchar *undo_desc)
{
GimpChannel *mask;
g_return_if_fail (GIMP_IS_IMAGE (gimage));
mask = gimp_image_get_mask (gimage);
gimp_image_undo_push_mask (gimage, undo_desc, mask);
gimp_image_mask_invalidate (gimage);
}
void
gimp_image_mask_feather (GimpImage *gimage,
gdouble feather_radius_x,
gdouble feather_radius_y)
{
g_return_if_fail (GIMP_IS_IMAGE (gimage));
gimp_image_mask_push_undo (gimage, _("Feather Selection"));
gimp_channel_feather (gimp_image_get_mask (gimage),
feather_radius_x,
feather_radius_y,
FALSE);
gimp_image_mask_changed (gimage);
}
void
gimp_image_mask_sharpen (GimpImage *gimage)
{
g_return_if_fail (GIMP_IS_IMAGE (gimage));
gimp_image_mask_push_undo (gimage, _("Sharpen Selection"));
gimp_channel_sharpen (gimp_image_get_mask (gimage), FALSE);
gimp_image_mask_changed (gimage);
}
void
gimp_image_mask_clear (GimpImage *gimage,
const gchar *undo_desc)
{
g_return_if_fail (GIMP_IS_IMAGE (gimage));
if (! undo_desc)
undo_desc = _("Select None");
gimp_image_mask_push_undo (gimage, undo_desc);
gimp_channel_clear (gimp_image_get_mask (gimage), FALSE);
gimp_image_mask_changed (gimage);
}
void
gimp_image_mask_all (GimpImage *gimage)
{
g_return_if_fail (GIMP_IS_IMAGE (gimage));
gimp_image_mask_push_undo (gimage, _("Select All"));
gimp_channel_all (gimp_image_get_mask (gimage), FALSE);
gimp_image_mask_changed (gimage);
}
void
gimp_image_mask_invert (GimpImage *gimage)
{
g_return_if_fail (GIMP_IS_IMAGE (gimage));
gimp_image_mask_push_undo (gimage, _("Invert Selection"));
gimp_channel_invert (gimp_image_get_mask (gimage), FALSE);
gimp_image_mask_changed (gimage);
}
void
gimp_image_mask_border (GimpImage *gimage,
gint border_radius_x,
gint border_radius_y)
{
g_return_if_fail (GIMP_IS_IMAGE (gimage));
gimp_image_mask_push_undo (gimage, _("Border Selection"));
gimp_channel_border (gimp_image_get_mask (gimage),
border_radius_x,
border_radius_y,
FALSE);
gimp_image_mask_changed (gimage);
}
void
gimp_image_mask_grow (GimpImage *gimage,
gint grow_pixels_x,
gint grow_pixels_y)
{
g_return_if_fail (GIMP_IS_IMAGE (gimage));
gimp_image_mask_push_undo (gimage, _("Grow Selection"));
gimp_channel_grow (gimp_image_get_mask (gimage),
grow_pixels_x,
grow_pixels_y,
FALSE);
gimp_image_mask_changed (gimage);
}
void
gimp_image_mask_shrink (GimpImage *gimage,
gint shrink_pixels_x,
gint shrink_pixels_y,
gboolean edge_lock)
{
g_return_if_fail (GIMP_IS_IMAGE (gimage));
gimp_image_mask_push_undo (gimage, _("Shrink Selection"));
gimp_channel_shrink (gimp_image_get_mask (gimage),
shrink_pixels_x,
shrink_pixels_y,
edge_lock,
FALSE);
gimp_image_mask_changed (gimage);
}
void
gimp_image_mask_translate (GimpImage *gimage,
gint off_x,
gint off_y,
gboolean push_undo)
{
g_return_if_fail (GIMP_IS_IMAGE (gimage));
if (push_undo)
gimp_image_mask_push_undo (gimage, _("Move Selection"));
else
gimp_image_mask_invalidate (gimage);
gimp_item_translate (GIMP_ITEM (gimp_image_get_mask (gimage)),
off_x, off_y, FALSE);
gimp_image_mask_changed (gimage);
}
void void
gimp_image_mask_load (GimpImage *gimage, gimp_image_mask_load (GimpImage *gimage,
GimpChannel *channel) GimpChannel *channel)
@ -604,7 +475,7 @@ gimp_image_mask_save (GimpImage *gimage)
mask = gimp_image_get_mask (gimage); mask = gimp_image_get_mask (gimage);
new_channel = GIMP_CHANNEL (gimp_item_duplicate (GIMP_ITEM (mask), new_channel = GIMP_CHANNEL (gimp_item_duplicate (GIMP_ITEM (mask),
G_TYPE_FROM_INSTANCE (mask), GIMP_TYPE_CHANNEL,
FALSE)); FALSE));
/* saved selections are not visible by default */ /* saved selections are not visible by default */
@ -614,47 +485,3 @@ gimp_image_mask_save (GimpImage *gimage)
return new_channel; return new_channel;
} }
gboolean
gimp_image_mask_stroke (GimpImage *gimage,
GimpDrawable *drawable,
GimpPaintInfo *paint_info)
{
const BoundSeg *bs_in;
const BoundSeg *bs_out;
gint num_segs_in;
gint num_segs_out;
GimpPaintCore *core;
gboolean retval;
g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE);
g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), FALSE);
g_return_val_if_fail (GIMP_IS_PAINT_INFO (paint_info), FALSE);
if (! gimp_image_mask_boundary (gimage, &bs_in, &bs_out,
&num_segs_in, &num_segs_out))
{
g_message (_("No selection to stroke."));
return FALSE;
}
gimage->mask_stroking = TRUE;
gimp_image_undo_group_start (gimage, GIMP_UNDO_GROUP_PAINT,
_("Stroke Selection"));
core = g_object_new (paint_info->paint_type, NULL);
retval = gimp_paint_core_stroke_boundary (core, drawable,
paint_info->paint_options,
bs_in, num_segs_in,
0, 0);
g_object_unref (core);
gimp_image_undo_group_end (gimage);
gimage->mask_stroking = FALSE;
return retval;
}

View File

@ -20,26 +20,63 @@
#define __GIMP_IMAGE_MASK_H__ #define __GIMP_IMAGE_MASK_H__
/* pure wrappers around the resp. GimpChannel::foo() functions: */
gboolean gimp_image_mask_boundary (GimpImage *gimage, gboolean gimp_image_mask_boundary (GimpImage *gimage,
const BoundSeg **segs_in, const BoundSeg **segs_in,
const BoundSeg **segs_out, const BoundSeg **segs_out,
gint *num_segs_in, gint *num_segs_in,
gint *num_segs_out); gint *num_segs_out);
gboolean gimp_image_mask_bounds (GimpImage *gimage, gboolean gimp_image_mask_bounds (GimpImage *gimage,
gint *x1, gint *x1,
gint *y1, gint *y1,
gint *x2, gint *x2,
gint *y2); gint *y2);
void gimp_image_mask_invalidate (GimpImage *gimage);
gint gimp_image_mask_value (GimpImage *gimage, gint gimp_image_mask_value (GimpImage *gimage,
gint x, gint x,
gint y); gint y);
gboolean gimp_image_mask_is_empty (GimpImage *gimage); gboolean gimp_image_mask_is_empty (GimpImage *gimage);
void gimp_image_mask_feather (GimpImage *gimage,
gdouble feather_radius_x,
gdouble feather_radius_y);
void gimp_image_mask_sharpen (GimpImage *gimage);
void gimp_image_mask_clear (GimpImage *gimage,
const gchar *undo_name);
void gimp_image_mask_all (GimpImage *gimage);
void gimp_image_mask_invert (GimpImage *gimage);
void gimp_image_mask_border (GimpImage *gimage,
gint border_radius_x,
gint border_radius_y);
void gimp_image_mask_grow (GimpImage *gimage,
gint grow_pixels_x,
gint grow_pixels_y);
void gimp_image_mask_shrink (GimpImage *gimage,
gint shrink_pixels_x,
gint shrink_pixels_y,
gboolean edge_lock);
/* pure wrappers around the resp. GimpItem::foo() functions: */
void gimp_image_mask_translate (GimpImage *gimage,
gint off_x,
gint off_y,
gboolean push_undo);
gboolean gimp_image_mask_stroke (GimpImage *gimage,
GimpDrawable *drawable,
GimpPaintInfo *paint_info);
/* pure wrappers around the resp. GimpSelection functions: */
void gimp_image_mask_push_undo (GimpImage *gimage,
const gchar *undo_desc);
void gimp_image_mask_invalidate (GimpImage *gimage);
/* really implemented here: */
TileManager * gimp_image_mask_extract (GimpImage *gimage, TileManager * gimp_image_mask_extract (GimpImage *gimage,
GimpDrawable *drawable, GimpDrawable *drawable,
gboolean cut_image, gboolean cut_image,
@ -52,44 +89,9 @@ GimpLayer * gimp_image_mask_float (GimpImage *gimage,
gint off_x, gint off_x,
gint off_y); gint off_y);
void gimp_image_mask_push_undo (GimpImage *gimage,
const gchar *undo_desc);
void gimp_image_mask_feather (GimpImage *gimage,
gdouble feather_radius_x,
gdouble feather_radius_y);
void gimp_image_mask_sharpen (GimpImage *gimage);
void gimp_image_mask_clear (GimpImage *gimage,
const gchar *undo_name);
void gimp_image_mask_all (GimpImage *gimage);
void gimp_image_mask_invert (GimpImage *gimage);
void gimp_image_mask_border (GimpImage *gimage,
gint border_radius_x,
gint border_radius_y);
void gimp_image_mask_grow (GimpImage *gimage,
gint grow_pixels_x,
gint grow_pixels_y);
void gimp_image_mask_shrink (GimpImage *gimage,
gint shrink_pixels_x,
gint shrink_pixels_y,
gboolean edge_lock);
void gimp_image_mask_translate (GimpImage *gimage,
gint off_x,
gint off_y,
gboolean push_undo);
void gimp_image_mask_load (GimpImage *gimage, void gimp_image_mask_load (GimpImage *gimage,
GimpChannel *channel); GimpChannel *channel);
GimpChannel * gimp_image_mask_save (GimpImage *gimage); GimpChannel * gimp_image_mask_save (GimpImage *gimage);
gboolean gimp_image_mask_stroke (GimpImage *gimage,
GimpDrawable *drawable,
GimpPaintInfo *paint_info);
#endif /* __GIMP_IMAGE_MASK_H__ */ #endif /* __GIMP_IMAGE_MASK_H__ */

View File

@ -54,6 +54,7 @@
#include "gimplist.h" #include "gimplist.h"
#include "gimpmarshal.h" #include "gimpmarshal.h"
#include "gimpparasitelist.h" #include "gimpparasitelist.h"
#include "gimpselection.h"
#include "gimpundostack.h" #include "gimpundostack.h"
#include "file/file-utils.h" #include "file/file-utils.h"
@ -483,7 +484,6 @@ gimp_image_init (GimpImage *gimage)
gimage->floating_sel = NULL; gimage->floating_sel = NULL;
gimage->selection_mask = NULL; gimage->selection_mask = NULL;
gimage->mask_stroking = FALSE;
gimage->parasites = gimp_parasite_list_new (); gimage->parasites = gimp_parasite_list_new ();
@ -851,9 +851,9 @@ gimp_image_new (Gimp *gimp,
} }
/* create the selection mask */ /* create the selection mask */
gimage->selection_mask = gimp_channel_new_mask (gimage, gimage->selection_mask = gimp_selection_new (gimage,
gimage->width, gimage->width,
gimage->height); gimage->height);
g_signal_connect_object (gimp->config, "notify::transparency-type", g_signal_connect_object (gimp->config, "notify::transparency-type",
G_CALLBACK (gimp_image_invalidate_layer_previews), G_CALLBACK (gimp_image_invalidate_layer_previews),

View File

@ -138,7 +138,6 @@ struct _GimpImage
GimpLayer *floating_sel; /* the FS layer */ GimpLayer *floating_sel; /* the FS layer */
GimpChannel *selection_mask; /* the selection mask channel */ GimpChannel *selection_mask; /* the selection mask channel */
gboolean mask_stroking; /* is a stroke being done */
GimpParasiteList *parasites; /* Plug-in parasite data */ GimpParasiteList *parasites; /* Plug-in parasite data */

View File

@ -925,7 +925,7 @@ gimp_layer_create_mask (const GimpLayer *layer,
return mask; return mask;
case GIMP_ADD_BLACK_MASK: case GIMP_ADD_BLACK_MASK:
gimp_channel_clear (GIMP_CHANNEL (mask), FALSE); gimp_channel_clear (GIMP_CHANNEL (mask), NULL, FALSE);
return mask; return mask;
default: default:
@ -973,7 +973,7 @@ gimp_layer_create_mask (const GimpLayer *layer,
if (copy_width < item->width || copy_height < item->height || if (copy_width < item->width || copy_height < item->height ||
selection_empty) selection_empty)
gimp_channel_clear (GIMP_CHANNEL (mask), FALSE); gimp_channel_clear (GIMP_CHANNEL (mask), NULL, FALSE);
if ((copy_width || copy_height) && ! selection_empty) if ((copy_width || copy_height) && ! selection_empty)
{ {

View File

@ -255,5 +255,7 @@ gimp_scan_convert_to_channel (GimpScanConvert *sc,
art_free (svp); art_free (svp);
art_free (pert_vpath); art_free (pert_vpath);
mask->bounds_known = FALSE;
return mask; return mask;
} }

586
app/core/gimpselection.c Normal file
View File

@ -0,0 +1,586 @@
/* The GIMP -- an image manipulation program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "config.h"
#include <string.h>
#include <glib-object.h>
#include "core-types.h"
#include "base/tile.h"
#include "base/tile-manager.h"
#include "gimpimage.h"
#include "gimpimage-undo.h"
#include "gimpimage-undo-push.h"
#include "gimplayer.h"
#include "gimplayer-floating-sel.h"
#include "gimpselection.h"
#include "gimp-intl.h"
static void gimp_selection_class_init (GimpSelectionClass *klass);
static void gimp_selection_init (GimpSelection *selection);
static void gimp_selection_translate (GimpItem *item,
gint offset_x,
gint offset_y,
gboolean push_undo);
static gboolean gimp_selection_stroke (GimpItem *item,
GimpDrawable *drawable,
GimpPaintInfo *paint_info);
static gboolean gimp_selection_boundary (GimpChannel *channel,
const BoundSeg **segs_in,
const BoundSeg **segs_out,
gint *num_segs_in,
gint *num_segs_out,
gint x1,
gint y1,
gint x2,
gint y2);
static gboolean gimp_selection_bounds (GimpChannel *channel,
gint *x1,
gint *y1,
gint *x2,
gint *y2);
static gint gimp_selection_value (GimpChannel *channel,
gint x,
gint y);
static gboolean gimp_selection_is_empty (GimpChannel *channel);
static void gimp_selection_feather (GimpChannel *channel,
gdouble radius_x,
gdouble radius_y,
gboolean push_undo);
static void gimp_selection_sharpen (GimpChannel *channel,
gboolean push_undo);
static void gimp_selection_clear (GimpChannel *channel,
const gchar *undo_desc,
gboolean push_undo);
static void gimp_selection_all (GimpChannel *channel,
gboolean push_undo);
static void gimp_selection_invert (GimpChannel *channel,
gboolean push_undo);
static void gimp_selection_border (GimpChannel *channel,
gint radius_x,
gint radius_y,
gboolean push_undo);
static void gimp_selection_grow (GimpChannel *channel,
gint radius_x,
gint radius_y,
gboolean push_undo);
static void gimp_selection_shrink (GimpChannel *channel,
gint radius_x,
gint radius_y,
gboolean edge_lock,
gboolean push_undo);
static void gimp_selection_changed (GimpSelection *selection);
static void gimp_selection_validate (TileManager *tm,
Tile *tile);
static GimpChannelClass *parent_class = NULL;
GType
gimp_selection_get_type (void)
{
static GType selection_type = 0;
if (! selection_type)
{
static const GTypeInfo selection_info =
{
sizeof (GimpSelectionClass),
(GBaseInitFunc) NULL,
(GBaseFinalizeFunc) NULL,
(GClassInitFunc) gimp_selection_class_init,
NULL, /* class_finalize */
NULL, /* class_data */
sizeof (GimpSelection),
0, /* n_preallocs */
(GInstanceInitFunc) gimp_selection_init,
};
selection_type = g_type_register_static (GIMP_TYPE_CHANNEL,
"GimpSelection",
&selection_info, 0);
}
return selection_type;
}
static void
gimp_selection_class_init (GimpSelectionClass *klass)
{
GimpItemClass *item_class;
GimpChannelClass *channel_class;
item_class = GIMP_ITEM_CLASS (klass);
channel_class = GIMP_CHANNEL_CLASS (klass);
parent_class = g_type_class_peek_parent (klass);
item_class->translate = gimp_selection_translate;
item_class->stroke = gimp_selection_stroke;
channel_class->boundary = gimp_selection_boundary;
channel_class->bounds = gimp_selection_bounds;
channel_class->value = gimp_selection_value;
channel_class->is_empty = gimp_selection_is_empty;
channel_class->feather = gimp_selection_feather;
channel_class->sharpen = gimp_selection_sharpen;
channel_class->clear = gimp_selection_clear;
channel_class->all = gimp_selection_all;
channel_class->invert = gimp_selection_invert;
channel_class->border = gimp_selection_border;
channel_class->grow = gimp_selection_grow;
channel_class->shrink = gimp_selection_shrink;
}
static void
gimp_selection_init (GimpSelection *selection)
{
selection->stroking = FALSE;
}
static void
gimp_selection_translate (GimpItem *item,
gint offset_x,
gint offset_y,
gboolean push_undo)
{
GimpSelection *selection = GIMP_SELECTION (item);
if (push_undo)
gimp_selection_push_undo (selection, _("Move Selection"));
else
gimp_selection_invalidate (selection);
GIMP_ITEM_CLASS (parent_class)->translate (item, offset_x, offset_y, FALSE);
gimp_selection_changed (selection);
}
static gboolean
gimp_selection_stroke (GimpItem *item,
GimpDrawable *drawable,
GimpPaintInfo *paint_info)
{
GimpSelection *selection;
GimpImage *gimage;
const BoundSeg *dummy_in;
const BoundSeg *dummy_out;
gint num_dummy_in;
gint num_dummy_out;
gboolean retval;
selection = GIMP_SELECTION (item);
if (! gimp_channel_boundary (GIMP_CHANNEL (selection),
&dummy_in, &dummy_out,
&num_dummy_in, &num_dummy_out,
0, 0, 0, 0))
{
g_message (_("No selection to stroke."));
return FALSE;
}
gimage = gimp_item_get_image (item);
selection->stroking = TRUE;
gimp_image_undo_group_start (gimage, GIMP_UNDO_GROUP_PAINT,
_("Stroke Selection"));
retval = GIMP_ITEM_CLASS (parent_class)->stroke (item, drawable, paint_info);
gimp_image_undo_group_end (gimage);
selection->stroking = FALSE;
return retval;
}
static gboolean
gimp_selection_boundary (GimpChannel *channel,
const BoundSeg **segs_in,
const BoundSeg **segs_out,
gint *num_segs_in,
gint *num_segs_out,
gint unused1,
gint unused2,
gint unused3,
gint unused4)
{
GimpImage *gimage;
GimpDrawable *drawable;
GimpLayer *layer;
gimage = gimp_item_get_image (GIMP_ITEM (channel));
if ((layer = gimp_image_floating_sel (gimage)))
{
/* If there is a floating selection, then
* we need to do some slightly different boundaries.
* Instead of inside and outside boundaries being defined
* by the extents of the layer, the inside boundary (the one
* that actually marches and is black/white) is the boundary of
* the floating selection. The outside boundary (doesn't move,
* is black/gray) is defined as the normal selection mask
*/
/* Find the selection mask boundary */
GIMP_CHANNEL_CLASS (parent_class)->boundary (channel,
segs_in, segs_out,
num_segs_in, num_segs_out,
0, 0, 0, 0);
/* Find the floating selection boundary */
*segs_in = floating_sel_boundary (layer, num_segs_in);
return TRUE;
}
else if ((drawable = gimp_image_active_drawable (gimage)) &&
GIMP_IS_CHANNEL (drawable))
{
/* Otherwise, return the boundary...if a channel is active */
return GIMP_CHANNEL_CLASS (parent_class)->boundary (channel,
segs_in, segs_out,
num_segs_in,
num_segs_out,
0, 0,
gimage->width,
gimage->height);
}
else if ((layer = gimp_image_get_active_layer (gimage)))
{
/* If a layer is active, we return multiple boundaries based
* on the extents
*/
gint x1, y1;
gint x2, y2;
gint off_x, off_y;
gimp_item_offsets (GIMP_ITEM (layer), &off_x, &off_y);
x1 = CLAMP (off_x, 0, gimage->width);
y1 = CLAMP (off_y, 0, gimage->height);
x2 = CLAMP (off_x + gimp_item_width (GIMP_ITEM (layer)), 0,
gimage->width);
y2 = CLAMP (off_y + gimp_item_height (GIMP_ITEM (layer)), 0,
gimage->height);
return GIMP_CHANNEL_CLASS (parent_class)->boundary (channel,
segs_in, segs_out,
num_segs_in,
num_segs_out,
x1, y1, x2, y2);
}
*segs_in = NULL;
*segs_out = NULL;
*num_segs_in = 0;
*num_segs_out = 0;
return FALSE;
}
static gboolean
gimp_selection_bounds (GimpChannel *channel,
gint *x1,
gint *y1,
gint *x2,
gint *y2)
{
return GIMP_CHANNEL_CLASS (parent_class)->bounds (channel, x1, y1, x2, y2);
}
static gint
gimp_selection_value (GimpChannel *channel,
gint x,
gint y)
{
return GIMP_CHANNEL_CLASS (parent_class)->value (channel, x, y);
}
static gboolean
gimp_selection_is_empty (GimpChannel *channel)
{
GimpSelection *selection = GIMP_SELECTION (channel);
/* in order to allow stroking of selections, we need to pretend here
* that the selection mask is empty so that it doesn't mask the paint
* during the stroke operation.
*/
if (selection->stroking)
return TRUE;
return GIMP_CHANNEL_CLASS (parent_class)->is_empty (channel);
}
static void
gimp_selection_feather (GimpChannel *channel,
gdouble radius_x,
gdouble radius_y,
gboolean push_undo)
{
GimpSelection *selection = GIMP_SELECTION (channel);
if (push_undo)
gimp_selection_push_undo (selection, _("Feather Selection"));
else
gimp_selection_invalidate (selection);
GIMP_CHANNEL_CLASS (parent_class)->feather (channel, radius_x, radius_y,
FALSE);
gimp_selection_changed (selection);
}
static void
gimp_selection_sharpen (GimpChannel *channel,
gboolean push_undo)
{
GimpSelection *selection = GIMP_SELECTION (channel);
if (push_undo)
gimp_selection_push_undo (selection, _("Sharpen Selection"));
else
gimp_selection_invalidate (selection);
GIMP_CHANNEL_CLASS (parent_class)->sharpen (channel, FALSE);
gimp_selection_changed (selection);
}
static void
gimp_selection_clear (GimpChannel *channel,
const gchar *undo_desc,
gboolean push_undo)
{
GimpSelection *selection = GIMP_SELECTION (channel);
if (push_undo)
{
if (! undo_desc)
undo_desc = _("Select None");
gimp_selection_push_undo (selection, undo_desc);
}
else
gimp_selection_invalidate (selection);
GIMP_CHANNEL_CLASS (parent_class)->clear (channel, NULL, FALSE);
gimp_selection_changed (selection);
}
static void
gimp_selection_all (GimpChannel *channel,
gboolean push_undo)
{
GimpSelection *selection = GIMP_SELECTION (channel);
if (push_undo)
gimp_selection_push_undo (selection, _("Select All"));
else
gimp_selection_invalidate (selection);
GIMP_CHANNEL_CLASS (parent_class)->all (channel, FALSE);
gimp_selection_changed (selection);
}
static void
gimp_selection_invert (GimpChannel *channel,
gboolean push_undo)
{
GimpSelection *selection = GIMP_SELECTION (channel);
if (push_undo)
gimp_selection_push_undo (selection, _("Invert Selection"));
else
gimp_selection_invalidate (selection);
GIMP_CHANNEL_CLASS (parent_class)->invert (channel, FALSE);
gimp_selection_changed (selection);
}
static void
gimp_selection_border (GimpChannel *channel,
gint radius_x,
gint radius_y,
gboolean push_undo)
{
GimpSelection *selection = GIMP_SELECTION (channel);
if (push_undo)
gimp_selection_push_undo (selection, _("Border Selection"));
else
gimp_selection_invalidate (selection);
GIMP_CHANNEL_CLASS (parent_class)->border (channel, radius_x, radius_y,
FALSE);
gimp_selection_changed (selection);
}
static void
gimp_selection_grow (GimpChannel *channel,
gint radius_x,
gint radius_y,
gboolean push_undo)
{
GimpSelection *selection = GIMP_SELECTION (channel);
if (push_undo)
gimp_selection_push_undo (selection, _("Grow Selection"));
else
gimp_selection_invalidate (selection);
GIMP_CHANNEL_CLASS (parent_class)->grow (channel, radius_x, radius_y,
FALSE);
gimp_selection_changed (selection);
}
static void
gimp_selection_shrink (GimpChannel *channel,
gint radius_x,
gint radius_y,
gboolean edge_lock,
gboolean push_undo)
{
GimpSelection *selection = GIMP_SELECTION (channel);
if (push_undo)
gimp_selection_push_undo (selection, _("Shrink Selection"));
else
gimp_selection_invalidate (selection);
GIMP_CHANNEL_CLASS (parent_class)->shrink (channel, radius_x, radius_y,
edge_lock, FALSE);
gimp_selection_changed (selection);
}
static void
gimp_selection_changed (GimpSelection *selection)
{
gimp_image_mask_changed (gimp_item_get_image (GIMP_ITEM (selection)));
}
static void
gimp_selection_validate (TileManager *tm,
Tile *tile)
{
/* Set the contents of the tile to empty */
memset (tile_data_pointer (tile, 0, 0),
TRANSPARENT_OPACITY, tile_size (tile));
}
/* public functions */
GimpChannel *
gimp_selection_new (GimpImage *gimage,
gint width,
gint height)
{
GimpRGB black = { 0.0, 0.0, 0.0, 0.5 };
GimpChannel *channel;
g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL);
channel = g_object_new (GIMP_TYPE_SELECTION, NULL);
gimp_drawable_configure (GIMP_DRAWABLE (channel),
gimage,
0, 0, width, height,
GIMP_GRAY_IMAGE,
_("Selection Mask"));
channel->color = black;
channel->show_masked = TRUE;
channel->x2 = width;
channel->y2 = height;
/* Set the validate procedure */
tile_manager_set_validate_proc (GIMP_DRAWABLE (channel)->tiles,
gimp_selection_validate);
return channel;
}
void
gimp_selection_push_undo (GimpSelection *selection,
const gchar *undo_desc)
{
GimpImage *gimage;
g_return_if_fail (GIMP_IS_SELECTION (selection));
gimage = gimp_item_get_image (GIMP_ITEM (selection));
g_return_if_fail (GIMP_IS_IMAGE (gimage));
gimp_image_undo_push_mask (gimage, undo_desc, GIMP_CHANNEL (selection));
gimp_selection_invalidate (selection);
}
void
gimp_selection_invalidate (GimpSelection *selection)
{
GimpLayer *layer;
GimpImage *gimage;
g_return_if_fail (GIMP_IS_SELECTION (selection));
gimage = gimp_item_get_image (GIMP_ITEM (selection));
g_return_if_fail (GIMP_IS_IMAGE (gimage));
/* Turn the current selection off */
gimp_image_selection_control (gimage, GIMP_SELECTION_OFF);
GIMP_CHANNEL (selection)->boundary_known = FALSE;
/* If there is a floating selection, update it's area...
* we need to do this since this selection mask can act as an additional
* mask in the composition of the floating selection
*/
layer = gimp_image_get_active_layer (gimage);
if (layer && gimp_layer_is_floating_sel (layer))
gimp_drawable_update (GIMP_DRAWABLE (layer),
0, 0,
GIMP_ITEM (layer)->width,
GIMP_ITEM (layer)->height);
/* invalidate the preview */
GIMP_DRAWABLE (selection)->preview_valid = FALSE;
}

59
app/core/gimpselection.h Normal file
View File

@ -0,0 +1,59 @@
/* The GIMP -- an image manipulation program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef __GIMP_SELECTION_H__
#define __GIMP_SELECTION_H__
#include "gimpchannel.h"
#define GIMP_TYPE_SELECTION (gimp_selection_get_type ())
#define GIMP_SELECTION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_SELECTION, GimpSelection))
#define GIMP_SELECTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_SELECTION, GimpSelectionClass))
#define GIMP_IS_SELECTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_SELECTION))
#define GIMP_IS_SELECTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_SELECTION))
#define GIMP_SELECTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_SELECTION, GimpSelectionClass))
typedef struct _GimpSelectionClass GimpSelectionClass;
struct _GimpSelection
{
GimpChannel parent_instance;
gboolean stroking;
};
struct _GimpSelectionClass
{
GimpChannelClass parent_class;
};
GType gimp_selection_get_type (void) G_GNUC_CONST;
GimpChannel * gimp_selection_new (GimpImage *gimage,
gint width,
gint height);
void gimp_selection_push_undo (GimpSelection *selection,
const gchar *undo_desc);
void gimp_selection_invalidate (GimpSelection *selection);
#endif /* __GIMP_SELECTION_H__ */

View File

@ -568,8 +568,6 @@ iscissors_convert (GimpIscissorsTool *iscissors,
iscissors->mask = gimp_scan_convert_to_channel (sc, gdisp->gimage); iscissors->mask = gimp_scan_convert_to_channel (sc, gdisp->gimage);
gimp_scan_convert_free (sc); gimp_scan_convert_free (sc);
gimp_channel_invalidate_bounds (iscissors->mask);
} }
static void static void

View File

@ -35,7 +35,6 @@
#include "config/gimpcoreconfig.h" #include "config/gimpcoreconfig.h"
#include "core/gimp.h" #include "core/gimp.h"
#include "core/gimpchannel.h"
#include "core/gimpcontainer.h" #include "core/gimpcontainer.h"
#include "core/gimpdrawable.h" #include "core/gimpdrawable.h"
#include "core/gimpimage.h" #include "core/gimpimage.h"
@ -45,6 +44,7 @@
#include "core/gimplayer-floating-sel.h" #include "core/gimplayer-floating-sel.h"
#include "core/gimplayermask.h" #include "core/gimplayermask.h"
#include "core/gimpparasitelist.h" #include "core/gimpparasitelist.h"
#include "core/gimpselection.h"
#include "core/gimpunit.h" #include "core/gimpunit.h"
#include "text/gimptextlayer.h" #include "text/gimptextlayer.h"
@ -61,46 +61,46 @@
#include "gimp-intl.h" #include "gimp-intl.h"
static gboolean xcf_load_image_props (XcfInfo *info, static gboolean xcf_load_image_props (XcfInfo *info,
GimpImage *gimage); GimpImage *gimage);
static gboolean xcf_load_layer_props (XcfInfo *info, static gboolean xcf_load_layer_props (XcfInfo *info,
GimpImage *gimage, GimpImage *gimage,
GimpLayer *layer, GimpLayer *layer,
gboolean *apply_mask, gboolean *apply_mask,
gboolean *edit_mask, gboolean *edit_mask,
gboolean *show_mask); gboolean *show_mask);
static gboolean xcf_load_channel_props (XcfInfo *info, static gboolean xcf_load_channel_props (XcfInfo *info,
GimpImage *gimage, GimpImage *gimage,
GimpChannel *channel); GimpChannel **channel);
static gboolean xcf_load_prop (XcfInfo *info, static gboolean xcf_load_prop (XcfInfo *info,
PropType *prop_type, PropType *prop_type,
guint32 *prop_size); guint32 *prop_size);
static GimpLayer * xcf_load_layer (XcfInfo *info, static GimpLayer * xcf_load_layer (XcfInfo *info,
GimpImage *gimage); GimpImage *gimage);
static GimpChannel * xcf_load_channel (XcfInfo *info, static GimpChannel * xcf_load_channel (XcfInfo *info,
GimpImage *gimage); GimpImage *gimage);
static GimpLayerMask * xcf_load_layer_mask (XcfInfo *info, static GimpLayerMask * xcf_load_layer_mask (XcfInfo *info,
GimpImage *gimage); GimpImage *gimage);
static gboolean xcf_load_hierarchy (XcfInfo *info, static gboolean xcf_load_hierarchy (XcfInfo *info,
TileManager *tiles); TileManager *tiles);
static gboolean xcf_load_level (XcfInfo *info, static gboolean xcf_load_level (XcfInfo *info,
TileManager *tiles); TileManager *tiles);
static gboolean xcf_load_tile (XcfInfo *info, static gboolean xcf_load_tile (XcfInfo *info,
Tile *tile); Tile *tile);
static gboolean xcf_load_tile_rle (XcfInfo *info, static gboolean xcf_load_tile_rle (XcfInfo *info,
Tile *tile, Tile *tile,
gint data_length); gint data_length);
static GimpParasite * xcf_load_parasite (XcfInfo *info); static GimpParasite * xcf_load_parasite (XcfInfo *info);
static gboolean xcf_load_old_paths (XcfInfo *info, static gboolean xcf_load_old_paths (XcfInfo *info,
GimpImage *gimage); GimpImage *gimage);
static gboolean xcf_load_old_path (XcfInfo *info, static gboolean xcf_load_old_path (XcfInfo *info,
GimpImage *gimage); GimpImage *gimage);
#ifdef SWAP_FROM_FILE #ifdef SWAP_FROM_FILE
static gboolean xcf_swap_func (gint fd, static gboolean xcf_swap_func (gint fd,
Tile *tile, Tile *tile,
gint cmd, gint cmd,
gpointer user_data); gpointer user_data);
#endif #endif
@ -624,9 +624,9 @@ xcf_load_layer_props (XcfInfo *info,
} }
static gboolean static gboolean
xcf_load_channel_props (XcfInfo *info, xcf_load_channel_props (XcfInfo *info,
GimpImage *gimage, GimpImage *gimage,
GimpChannel *channel) GimpChannel **channel)
{ {
PropType prop_type; PropType prop_type;
guint32 prop_size; guint32 prop_size;
@ -641,20 +641,29 @@ xcf_load_channel_props (XcfInfo *info,
case PROP_END: case PROP_END:
return TRUE; return TRUE;
case PROP_ACTIVE_CHANNEL: case PROP_ACTIVE_CHANNEL:
info->active_channel = channel; info->active_channel = *channel;
break; break;
case PROP_SELECTION: case PROP_SELECTION:
g_object_unref (gimage->selection_mask); g_object_unref (gimage->selection_mask);
gimage->selection_mask = channel; gimage->selection_mask =
channel->boundary_known = FALSE; gimp_selection_new (gimage,
channel->bounds_known = FALSE; gimp_item_width (GIMP_ITEM (*channel)),
gimp_item_height (GIMP_ITEM (*channel)));
tile_manager_unref (GIMP_DRAWABLE (gimage->selection_mask)->tiles);
GIMP_DRAWABLE (gimage->selection_mask)->tiles =
GIMP_DRAWABLE (*channel)->tiles;
GIMP_DRAWABLE (*channel)->tiles = NULL;
g_object_unref (*channel);
*channel = gimage->selection_mask;
(*channel)->boundary_known = FALSE;
(*channel)->bounds_known = FALSE;
break; break;
case PROP_OPACITY: case PROP_OPACITY:
{ {
guint32 opacity; guint32 opacity;
info->cp += xcf_read_int32 (info->fp, &opacity, 1); info->cp += xcf_read_int32 (info->fp, &opacity, 1);
channel->color.a = opacity / 255.0; (*channel)->color.a = opacity / 255.0;
} }
break; break;
case PROP_VISIBLE: case PROP_VISIBLE:
@ -662,7 +671,7 @@ xcf_load_channel_props (XcfInfo *info,
gboolean visible; gboolean visible;
info->cp += xcf_read_int32 (info->fp, (guint32 *) &visible, 1); info->cp += xcf_read_int32 (info->fp, (guint32 *) &visible, 1);
gimp_drawable_set_visible (GIMP_DRAWABLE (channel), gimp_drawable_set_visible (GIMP_DRAWABLE (*channel),
visible ? TRUE : FALSE, FALSE); visible ? TRUE : FALSE, FALSE);
} }
break; break;
@ -671,13 +680,17 @@ xcf_load_channel_props (XcfInfo *info,
gboolean linked; gboolean linked;
info->cp += xcf_read_int32 (info->fp, (guint32 *) &linked, 1); info->cp += xcf_read_int32 (info->fp, (guint32 *) &linked, 1);
gimp_item_set_linked (GIMP_ITEM (channel), gimp_item_set_linked (GIMP_ITEM (*channel),
linked ? TRUE : FALSE, FALSE); linked ? TRUE : FALSE, FALSE);
} }
break; break;
case PROP_SHOW_MASKED: case PROP_SHOW_MASKED:
info->cp += {
xcf_read_int32 (info->fp, (guint32 *) &channel->show_masked, 1); gboolean show_masked;
info->cp += xcf_read_int32 (info->fp, (guint32 *) &show_masked, 1);
gimp_channel_set_show_masked (*channel, show_masked);
}
break; break;
case PROP_COLOR: case PROP_COLOR:
{ {
@ -685,13 +698,12 @@ xcf_load_channel_props (XcfInfo *info,
info->cp += xcf_read_int8 (info->fp, (guint8 *) col, 3); info->cp += xcf_read_int8 (info->fp, (guint8 *) col, 3);
gimp_rgb_set_uchar (&channel->color, col[0], col[1], col[2]); gimp_rgb_set_uchar (&(*channel)->color, col[0], col[1], col[2]);
} }
break; break;
case PROP_TATTOO: case PROP_TATTOO:
info->cp += info->cp +=
xcf_read_int32 (info->fp, &GIMP_ITEM (channel)->tattoo, 1); xcf_read_int32 (info->fp, &GIMP_ITEM (*channel)->tattoo, 1);
break; break;
case PROP_PARASITES: case PROP_PARASITES:
{ {
@ -701,7 +713,7 @@ xcf_load_channel_props (XcfInfo *info,
while ((info->cp - base) < prop_size) while ((info->cp - base) < prop_size)
{ {
p = xcf_load_parasite (info); p = xcf_load_parasite (info);
gimp_item_parasite_attach (GIMP_ITEM (channel), p); gimp_item_parasite_attach (GIMP_ITEM (*channel), p);
gimp_parasite_free (p); gimp_parasite_free (p);
} }
if (info->cp - base != prop_size) if (info->cp - base != prop_size)
@ -896,7 +908,7 @@ xcf_load_channel (XcfInfo *info,
return NULL; return NULL;
/* read in the channel properties */ /* read in the channel properties */
if (!xcf_load_channel_props (info, gimage, channel)) if (!xcf_load_channel_props (info, gimage, &channel))
goto error; goto error;
/* read the hierarchy and layer mask offsets */ /* read the hierarchy and layer mask offsets */
@ -958,7 +970,7 @@ xcf_load_layer_mask (XcfInfo *info,
return NULL; return NULL;
/* read in the layer_mask properties */ /* read in the layer_mask properties */
if (!xcf_load_channel_props (info, gimage, GIMP_CHANNEL (layer_mask))) if (!xcf_load_channel_props (info, gimage, (GimpChannel **) &layer_mask))
goto error; goto error;
/* read the hierarchy and layer mask offsets */ /* read the hierarchy and layer mask offsets */