app: add gimp_drawable_filter_set_clip()

In GimpDrawableFilter, add a new gimp_drawable_filter_set_clip()
function, which controls whether the filter clips the result to the
drawable's boundary, or extends it past it.  The latter is only
possible for layers, when the selection mask is empty.
This commit is contained in:
Ell 2019-08-01 23:33:03 +03:00
parent 89a9cf7e49
commit b7f53262fc
2 changed files with 147 additions and 46 deletions

View File

@ -65,6 +65,7 @@ struct _GimpDrawableFilter
gboolean has_input;
gboolean clip;
GimpFilterRegion region;
gboolean crop_enabled;
GeglRectangle crop_rect;
@ -80,6 +81,7 @@ struct _GimpDrawableFilter
gboolean gamma_hack;
GeglRectangle filter_area;
gboolean filter_clip;
GeglNode *translate;
GeglNode *crop_before;
@ -93,6 +95,8 @@ struct _GimpDrawableFilter
static void gimp_drawable_filter_dispose (GObject *object);
static void gimp_drawable_filter_finalize (GObject *object);
static void gimp_drawable_filter_sync_clip (GimpDrawableFilter *filter,
gboolean sync_region);
static void gimp_drawable_filter_sync_region (GimpDrawableFilter *filter);
static void gimp_drawable_filter_sync_crop (GimpDrawableFilter *filter,
gboolean old_crop_enabled,
@ -156,6 +160,7 @@ gimp_drawable_filter_class_init (GimpDrawableFilterClass *klass)
static void
gimp_drawable_filter_init (GimpDrawableFilter *drawable_filter)
{
drawable_filter->clip = TRUE;
drawable_filter->region = GIMP_FILTER_REGION_SELECTION;
drawable_filter->preview_alignment = GIMP_ALIGN_LEFT;
drawable_filter->preview_position = 1.0;
@ -269,6 +274,20 @@ gimp_drawable_filter_new (GimpDrawable *drawable,
return filter;
}
void
gimp_drawable_filter_set_clip (GimpDrawableFilter *filter,
gboolean clip)
{
g_return_if_fail (GIMP_IS_DRAWABLE_FILTER (filter));
if (clip != filter->clip)
{
filter->clip = clip;
gimp_drawable_filter_sync_clip (filter, TRUE);
}
}
void
gimp_drawable_filter_set_region (GimpDrawableFilter *filter,
GimpFilterRegion region)
@ -423,6 +442,11 @@ gimp_drawable_filter_apply (GimpDrawableFilter *filter,
g_return_if_fail (gimp_item_is_attached (GIMP_ITEM (filter->drawable)));
gimp_drawable_filter_add_filter (filter);
gimp_drawable_filter_sync_clip (filter, TRUE);
gimp_drawable_update_bounding_box (filter->drawable);
gimp_drawable_filter_update_drawable (filter, area);
}
@ -448,7 +472,7 @@ gimp_drawable_filter_commit (GimpDrawableFilter *filter,
GIMP_FILTER (filter),
progress,
gimp_object_get_name (filter),
TRUE,
filter->filter_clip,
cancellable,
FALSE);
@ -477,6 +501,46 @@ gimp_drawable_filter_abort (GimpDrawableFilter *filter)
/* private functions */
static void
gimp_drawable_filter_sync_clip (GimpDrawableFilter *filter,
gboolean sync_region)
{
gboolean clip = filter->clip;
if (! clip)
{
if (! GIMP_IS_LAYER (filter->drawable))
clip = TRUE;
}
if (! clip)
{
GimpImage *image = gimp_item_get_image (GIMP_ITEM (filter->drawable));
GimpChannel *mask = gimp_image_get_mask (image);
if (! gimp_channel_is_empty (mask))
clip = TRUE;
}
if (! clip)
{
GeglRectangle bounding_box;
bounding_box = gegl_node_get_bounding_box (filter->operation);
if (gegl_rectangle_is_infinite_plane (&bounding_box))
clip = TRUE;
}
if (clip != filter->filter_clip)
{
filter->filter_clip = clip;
if (sync_region)
gimp_drawable_filter_sync_region (filter);
}
}
static void
gimp_drawable_filter_sync_region (GimpDrawableFilter *filter)
{
@ -495,10 +559,22 @@ gimp_drawable_filter_sync_region (GimpDrawableFilter *filter)
NULL);
}
gegl_node_set (filter->crop_after,
"width", (gdouble) filter->filter_area.width,
"height", (gdouble) filter->filter_area.height,
NULL);
if (filter->filter_clip)
{
gegl_node_set (filter->crop_after,
"operation", "gegl:crop",
"x", 0.0,
"y", 0.0,
"width", (gdouble) filter->filter_area.width,
"height", (gdouble) filter->filter_area.height,
NULL);
}
else
{
gegl_node_set (filter->crop_after,
"operation", "gegl:nop",
NULL);
}
gimp_applicator_set_apply_offset (filter->applicator,
filter->filter_area.x,
@ -523,13 +599,31 @@ gimp_drawable_filter_sync_region (GimpDrawableFilter *filter)
NULL);
}
gegl_node_set (filter->crop_after,
"width", width,
"height", height,
NULL);
if (filter->filter_clip)
{
gegl_node_set (filter->crop_after,
"operation", "gegl:crop",
"x", (gdouble) filter->filter_area.x,
"y", (gdouble) filter->filter_area.y,
"width", (gdouble) filter->filter_area.width,
"height", (gdouble) filter->filter_area.height,
NULL);
}
else
{
gegl_node_set (filter->crop_after,
"operation", "gegl:nop",
NULL);
}
gimp_applicator_set_apply_offset (filter->applicator, 0, 0);
}
if (gimp_drawable_filter_is_filtering (filter))
{
if (gimp_drawable_update_bounding_box (filter->drawable))
g_signal_emit (filter, drawable_filter_signals[FLUSH], 0);
}
}
static gboolean
@ -541,37 +635,41 @@ gimp_drawable_filter_get_crop_rect (GimpDrawableFilter *filter,
gdouble preview_position,
GeglRectangle *rect)
{
gint width;
gint height;
GeglRectangle bounds;
gint width;
gint height;
gint x1, x2;
gint y1, y2;
rect->x = 0;
rect->y = 0;
rect->width = gimp_item_get_width (GIMP_ITEM (filter->drawable));
rect->height = gimp_item_get_height (GIMP_ITEM (filter->drawable));
bounds = gegl_rectangle_infinite_plane ();
width = rect->width;
height = rect->height;
width = gimp_item_get_width (GIMP_ITEM (filter->drawable));
height = gimp_item_get_height (GIMP_ITEM (filter->drawable));
x1 = bounds.x;
x2 = bounds.x + bounds.width;
y1 = bounds.y;
y2 = bounds.y + bounds.height;
if (preview_enabled)
{
switch (preview_alignment)
{
case GIMP_ALIGN_LEFT:
rect->width *= preview_position;
x2 = width * preview_position;
break;
case GIMP_ALIGN_RIGHT:
rect->width *= (1.0 - preview_position);
rect->x = width - rect->width;
x1 = width * preview_position;
break;
case GIMP_ALIGN_TOP:
rect->height *= preview_position;
y2 = height * preview_position;
break;
case GIMP_ALIGN_BOTTOM:
rect->height *= (1.0 - preview_position);
rect->y = height - rect->height;
y1 = height * preview_position;
break;
default:
@ -579,10 +677,12 @@ gimp_drawable_filter_get_crop_rect (GimpDrawableFilter *filter,
}
}
gegl_rectangle_set (rect, x1, y1, x2 - x1, y2 - y1);
if (crop_enabled)
gegl_rectangle_intersect (rect, rect, crop_rect);
return ! gegl_rectangle_equal_coords (rect, 0, 0, width, height);
return ! gegl_rectangle_equal (rect, &bounds);
}
static void
@ -616,30 +716,20 @@ gimp_drawable_filter_sync_crop (GimpDrawableFilter *filter,
gimp_applicator_set_crop (filter->applicator, enabled ? &new_rect : NULL);
if (update && ! gegl_rectangle_equal (&old_rect, &new_rect))
if (update &&
gimp_drawable_filter_is_filtering (filter) &&
! gegl_rectangle_equal (&old_rect, &new_rect))
{
cairo_region_t *region;
gint n_rects;
gint i;
GeglRectangle diff_rects[4];
gint n_diff_rects;
gint i;
region = cairo_region_create_rectangle ((cairo_rectangle_int_t *)
&old_rect);
cairo_region_xor_rectangle (region,
(cairo_rectangle_int_t *) &new_rect);
gimp_drawable_update_bounding_box (filter->drawable);
n_rects = cairo_region_num_rectangles (region);
n_diff_rects = gegl_rectangle_xor (diff_rects, &old_rect, &new_rect);
for (i = 0; i < n_rects; i++)
{
cairo_rectangle_int_t rect;
cairo_region_get_rectangle (region, i, &rect);
gimp_drawable_filter_update_drawable (filter,
(const GeglRectangle *) &rect);
}
cairo_region_destroy (region);
for (i = 0; i < n_diff_rects; i++)
gimp_drawable_filter_update_drawable (filter, &diff_rects[i]);
}
}
@ -791,6 +881,7 @@ gimp_drawable_filter_add_filter (GimpDrawableFilter *filter)
gimp_viewable_preview_freeze (GIMP_VIEWABLE (filter->drawable));
gimp_drawable_filter_sync_mask (filter);
gimp_drawable_filter_sync_clip (filter, FALSE);
gimp_drawable_filter_sync_region (filter);
gimp_drawable_filter_sync_crop (filter,
filter->crop_enabled,
@ -808,6 +899,8 @@ gimp_drawable_filter_add_filter (GimpDrawableFilter *filter)
gimp_drawable_add_filter (filter->drawable,
GIMP_FILTER (filter));
gimp_drawable_update_bounding_box (filter->drawable);
g_signal_connect (image, "component-active-changed",
G_CALLBACK (gimp_drawable_filter_affect_changed),
filter);
@ -864,6 +957,8 @@ gimp_drawable_filter_remove_filter (GimpDrawableFilter *filter)
gimp_drawable_remove_filter (filter->drawable,
GIMP_FILTER (filter));
gimp_drawable_update_bounding_box (filter->drawable);
gimp_viewable_preview_thaw (GIMP_VIEWABLE (filter->drawable));
return TRUE;
@ -876,12 +971,15 @@ static void
gimp_drawable_filter_update_drawable (GimpDrawableFilter *filter,
const GeglRectangle *area)
{
GeglRectangle bounding_box;
GeglRectangle update_area;
bounding_box = gimp_drawable_get_bounding_box (filter->drawable);
if (area)
{
if (! gegl_rectangle_intersect (&update_area,
area, &filter->filter_area))
area, &bounding_box))
{
return;
}
@ -897,7 +995,7 @@ gimp_drawable_filter_update_drawable (GimpDrawableFilter *filter,
&update_area);
if (! gegl_rectangle_intersect (&update_area,
&update_area, &filter->filter_area))
&update_area, &bounding_box))
{
return;
}
@ -932,6 +1030,7 @@ gimp_drawable_filter_mask_changed (GimpImage *image,
gimp_drawable_filter_update_drawable (filter, NULL);
gimp_drawable_filter_sync_mask (filter);
gimp_drawable_filter_sync_clip (filter, FALSE);
gimp_drawable_filter_sync_region (filter);
gimp_drawable_filter_update_drawable (filter, NULL);

View File

@ -55,6 +55,8 @@ GimpDrawableFilter *
GeglNode *operation,
const gchar *icon_name);
void gimp_drawable_filter_set_clip (GimpDrawableFilter *filter,
gboolean clip);
void gimp_drawable_filter_set_region (GimpDrawableFilter *filter,
GimpFilterRegion region);
void gimp_drawable_filter_set_crop (GimpDrawableFilter *filter,