core: Use prior filter size for stack crops

Previously filters were cropped to the layer size in the
"crop_before" node. This was fine when we had destructive-only
filters, but now that we can multiple active layers, this causes
new layers to crop the prior ones if they're larger than the layer
(e.g. If gegl:drop-shadow goes out of the layer boundaries)

This patch sets the crop_before to the current sizes, then searches
the filter stack to see if there's a filter that needs a larger width
or height (or if it needs a smaller x or y values), then sets the crop
to that size. This crop update is also run when a filter is raised or
lowered.
This commit is contained in:
Alx Sa 2024-10-05 16:17:01 -04:00 committed by Jehan
parent 42f8a61923
commit 59b7b6a5fb
4 changed files with 110 additions and 20 deletions

View file

@ -43,6 +43,7 @@
#include "gimpchannel.h"
#include "gimpdrawable-filters.h"
#include "gimpdrawablefilter.h"
#include "gimpfilterstack.h"
#include "gimpimage.h"
#include "gimplayer.h"
#include "gimpprogress.h"
@ -1021,14 +1022,28 @@ gimp_drawable_filter_sync_region (GimpDrawableFilter *filter)
{
if (filter->has_input)
{
GeglRectangle rect;
GimpContainer *filters;
rect.x = filter->filter_area.x;
rect.y = filter->filter_area.y;
rect.width = filter->filter_area.width;
rect.height = filter->filter_area.height;
filters = gimp_drawable_get_filters (filter->drawable);
gimp_filter_stack_get_bounding_box (GIMP_FILTER_STACK (filters),
&rect);
gegl_node_set (filter->translate,
"x", (gdouble) -filter->filter_area.x,
"y", (gdouble) -filter->filter_area.y,
NULL);
gegl_node_set (filter->crop_before,
"width", (gdouble) filter->filter_area.width,
"height", (gdouble) filter->filter_area.height,
"x", (gdouble) rect.x,
"y", (gdouble) rect.y,
"width", (gdouble) rect.width,
"height", (gdouble) rect.height,
NULL);
}
@ -1061,14 +1076,23 @@ gimp_drawable_filter_sync_region (GimpDrawableFilter *filter)
if (filter->has_input)
{
GeglRectangle rect = { 0, 0, width, height };
GimpContainer *filters;
filters = gimp_drawable_get_filters (filter->drawable);
gimp_filter_stack_get_bounding_box (GIMP_FILTER_STACK (filters),
&rect);
gegl_node_set (filter->translate,
"x", (gdouble) 0.0,
"y", (gdouble) 0.0,
NULL);
gegl_node_set (filter->crop_before,
"width", width,
"height", height,
"x", (gdouble) rect.x,
"y", (gdouble) rect.y,
"width", (gdouble) rect.width,
"height", (gdouble) rect.height,
NULL);
}

View file

@ -25,6 +25,7 @@
#include "core-types.h"
#include "gimpdrawablefilter.h"
#include "gimpfilter.h"
#include "gimpfilterstack.h"
@ -223,6 +224,39 @@ gimp_filter_stack_get_graph (GimpFilterStack *stack)
return stack->graph;
}
void
gimp_filter_stack_get_bounding_box (GimpFilterStack *stack,
GeglRectangle *rect)
{
GList *list;
GeglRectangle current_rect;
g_return_if_fail (GIMP_IS_FILTER_STACK (stack));
for (list = GIMP_LIST (stack)->queue->tail;
list; list = g_list_previous (list))
{
if (GIMP_IS_DRAWABLE_FILTER (list->data))
{
GimpFilter *filter = GIMP_FILTER (list->data);
current_rect = gegl_node_get_bounding_box (gimp_filter_get_node (filter));
if (rect->x > current_rect.x)
rect->x = current_rect.x;
if (rect->y > current_rect.y)
rect->y = current_rect.y;
if (rect->width < (current_rect.width - current_rect.x))
rect->width = (current_rect.width - current_rect.x);
if (rect->height < (current_rect.height - current_rect.y))
rect->height = (current_rect.height - current_rect.y);
}
}
}
/* private functions */

View file

@ -50,6 +50,7 @@ GType gimp_filter_stack_get_type (void) G_GNUC_CONST;
GimpContainer * gimp_filter_stack_new (GType filter_type);
GeglNode * gimp_filter_stack_get_graph (GimpFilterStack *stack);
void gimp_filter_stack_get_bounding_box (GimpFilterStack *stack,
GeglRectangle *rect);
#endif /* __GIMP_FILTER_STACK_H__ */

View file

@ -45,6 +45,7 @@
#include "core/gimpdrawable-filters.h"
#include "core/gimpdrawablefilter.h"
#include "core/gimpdrawablefilterundo.h"
#include "core/gimpfilterstack.h"
#include "core/gimpimage.h"
#include "core/gimpimage-undo.h"
#include "core/gimpimage-undo-push.h"
@ -2684,6 +2685,7 @@ gimp_item_tree_view_effects_raised_clicked (GtkWidget *widget,
GimpItemTreeView *view)
{
GimpImage *image = view->priv->image;
GimpDrawable *drawable = NULL;
if (! view->priv->effects_filter ||
! GIMP_IS_DRAWABLE_FILTER (view->priv->effects_filter))
@ -2696,12 +2698,13 @@ gimp_item_tree_view_effects_raised_clicked (GtkWidget *widget,
return;
}
if (view->priv->effects_drawable)
drawable = gimp_drawable_filter_get_drawable (view->priv->effects_filter);
if (drawable)
{
GimpContainer *filters;
gint index;
filters = gimp_drawable_get_filters (GIMP_DRAWABLE (view->priv->effects_drawable));
filters = gimp_drawable_get_filters (drawable);
index = gimp_container_get_child_index (filters,
GIMP_OBJECT (view->priv->effects_filter));
@ -2709,8 +2712,11 @@ gimp_item_tree_view_effects_raised_clicked (GtkWidget *widget,
if (index >= 0)
{
GimpChannel *mask = NULL;
GeglRectangle rect;
gimp_image_undo_push_filter_reorder (image, _("Reorder filter"),
view->priv->effects_drawable,
drawable,
view->priv->effects_filter);
gimp_container_reorder (filters, GIMP_OBJECT (view->priv->effects_filter),
@ -2723,10 +2729,18 @@ gimp_item_tree_view_effects_raised_clicked (GtkWidget *widget,
gtk_widget_set_sensitive (view->priv->effects_raise_button, FALSE);
}
mask = gimp_drawable_filter_get_mask (view->priv->effects_filter);
gimp_filter_stack_get_bounding_box (GIMP_FILTER_STACK (filters),
&rect);
if (gimp_channel_is_empty (mask))
gimp_drawable_filter_refresh_crop (view->priv->effects_filter,
&rect);
/* Hack to make the effects visibly change */
gimp_item_set_visible (GIMP_ITEM (view->priv->effects_drawable), FALSE, FALSE);
gimp_item_set_visible (GIMP_ITEM (drawable), FALSE, FALSE);
gimp_image_flush (image);
gimp_item_set_visible (GIMP_ITEM (view->priv->effects_drawable), TRUE, FALSE);
gimp_item_set_visible (GIMP_ITEM (drawable), TRUE, FALSE);
gimp_image_flush (image);
}
}
@ -2737,6 +2751,7 @@ gimp_item_tree_view_effects_lowered_clicked (GtkWidget *widget,
GimpItemTreeView *view)
{
GimpImage *image = view->priv->image;
GimpDrawable *drawable = NULL;
if (! view->priv->effects_filter ||
! GIMP_IS_DRAWABLE_FILTER (view->priv->effects_filter))
@ -2749,12 +2764,13 @@ gimp_item_tree_view_effects_lowered_clicked (GtkWidget *widget,
return;
}
if (view->priv->effects_drawable)
drawable = gimp_drawable_filter_get_drawable (view->priv->effects_filter);
if (drawable)
{
GimpContainer *filters;
gint index;
filters = gimp_drawable_get_filters (GIMP_DRAWABLE (view->priv->effects_drawable));
filters = gimp_drawable_get_filters (drawable);
index = gimp_container_get_child_index (filters,
GIMP_OBJECT (view->priv->effects_filter));
@ -2762,8 +2778,12 @@ gimp_item_tree_view_effects_lowered_clicked (GtkWidget *widget,
if (index < gimp_container_get_n_children (filters))
{
GimpDrawableFilter *moved_filter = NULL;
GimpChannel *mask = NULL;
GeglRectangle rect;
gimp_image_undo_push_filter_reorder (image, _("Reorder filter"),
view->priv->effects_drawable,
drawable,
view->priv->effects_filter);
gimp_container_reorder (filters, GIMP_OBJECT (view->priv->effects_filter),
@ -2776,10 +2796,21 @@ gimp_item_tree_view_effects_lowered_clicked (GtkWidget *widget,
gtk_widget_set_sensitive (view->priv->effects_lower_button, FALSE);
}
moved_filter = (GimpDrawableFilter *)
gimp_container_get_child_by_index (filters, index - 1);
mask = gimp_drawable_filter_get_mask (moved_filter);
gimp_filter_stack_get_bounding_box (GIMP_FILTER_STACK (filters),
&rect);
if (gimp_channel_is_empty (mask))
gimp_drawable_filter_refresh_crop (moved_filter, &rect);
/* Hack to make the effects visibly change */
gimp_item_set_visible (GIMP_ITEM (view->priv->effects_drawable), FALSE, FALSE);
gimp_item_set_visible (GIMP_ITEM (drawable), FALSE, FALSE);
gimp_image_flush (image);
gimp_item_set_visible (GIMP_ITEM (view->priv->effects_drawable), TRUE, FALSE);
gimp_item_set_visible (GIMP_ITEM (drawable), TRUE, FALSE);
gimp_image_flush (image);
}
}