From 6b829c7008e788124fcff8bf92277ff5174ad764 Mon Sep 17 00:00:00 2001 From: Jehan Date: Sat, 1 Aug 2020 13:12:21 +0200 Subject: [PATCH] app: Selection fill and "Fill Path" now multi-layer aware. This includes the actions "select-fill*" as well as the "Fill Path" feature in the Vector tool which were using common code. --- app/actions/items-commands.c | 28 +++++++++++++++------------- app/actions/select-actions.c | 26 +++++++++++++++++++++++--- app/core/gimpitem.c | 20 +++++++++++++++----- app/core/gimpitem.h | 2 +- app/dialogs/fill-dialog.c | 11 ++++++----- app/dialogs/fill-dialog.h | 4 ++-- app/tools/gimpvectortool.c | 18 ++++++++++-------- 7 files changed, 72 insertions(+), 37 deletions(-) diff --git a/app/actions/items-commands.c b/app/actions/items-commands.c index 43e17d90c9..2ae86417b1 100644 --- a/app/actions/items-commands.c +++ b/app/actions/items-commands.c @@ -47,7 +47,7 @@ static void items_fill_callback (GtkWidget *dialog, GimpItem *item, - GimpDrawable *drawable, + GList *drawables, GimpContext *context, GimpFillOptions *options, gpointer user_data); @@ -190,18 +190,18 @@ items_fill_cmd_callback (GimpAction *action, const gchar *dialog_help_id, gpointer data) { - GimpDrawable *drawable; + GList *drawables; GtkWidget *dialog; GtkWidget *widget; return_if_no_widget (widget, data); - drawable = gimp_image_get_active_drawable (image); + drawables = gimp_image_get_selected_drawables (image); - if (! drawable) + if (! drawables) { gimp_message_literal (image->gimp, G_OBJECT (widget), GIMP_MESSAGE_WARNING, - _("There is no active layer or channel to fill.")); + _("There are no selected layers or channels to fill.")); return; } @@ -212,7 +212,7 @@ items_fill_cmd_callback (GimpAction *action, GimpDialogConfig *config = GIMP_DIALOG_CONFIG (image->gimp->config); dialog = fill_dialog_new (item, - drawable, + drawables, action_data_get_context (data), dialog_title, dialog_icon_name, @@ -226,6 +226,7 @@ items_fill_cmd_callback (GimpAction *action, } gtk_window_present (GTK_WINDOW (dialog)); + g_list_free (drawables); } void @@ -234,25 +235,25 @@ items_fill_last_vals_cmd_callback (GimpAction *action, GimpItem *item, gpointer data) { - GimpDrawable *drawable; + GList *drawables; GimpDialogConfig *config; GtkWidget *widget; GError *error = NULL; return_if_no_widget (widget, data); - drawable = gimp_image_get_active_drawable (image); + drawables = gimp_image_get_selected_drawables (image); - if (! drawable) + if (! drawables) { gimp_message_literal (image->gimp, G_OBJECT (widget), GIMP_MESSAGE_WARNING, - _("There is no active layer or channel to fill.")); + _("There are no selected layers or channels to fill.")); return; } config = GIMP_DIALOG_CONFIG (image->gimp->config); - if (! gimp_item_fill (item, drawable, + if (! gimp_item_fill (item, drawables, config->fill_options, TRUE, NULL, &error)) { gimp_message_literal (image->gimp, G_OBJECT (widget), @@ -263,6 +264,7 @@ items_fill_last_vals_cmd_callback (GimpAction *action, { gimp_image_flush (image); } + g_list_free (drawables); } void @@ -358,7 +360,7 @@ items_stroke_last_vals_cmd_callback (GimpAction *action, static void items_fill_callback (GtkWidget *dialog, GimpItem *item, - GimpDrawable *drawable, + GList *drawables, GimpContext *context, GimpFillOptions *options, gpointer user_data) @@ -370,7 +372,7 @@ items_fill_callback (GtkWidget *dialog, gimp_config_sync (G_OBJECT (options), G_OBJECT (config->fill_options), 0); - if (! gimp_item_fill (item, drawable, options, TRUE, NULL, &error)) + if (! gimp_item_fill (item, drawables, options, TRUE, NULL, &error)) { gimp_message_literal (context->gimp, G_OBJECT (dialog), diff --git a/app/actions/select-actions.c b/app/actions/select-actions.c index 100d5f3d6b..96c8c79ac9 100644 --- a/app/actions/select-actions.c +++ b/app/actions/select-actions.c @@ -120,7 +120,7 @@ static const GimpActionEntry select_actions[] = GIMP_HELP_SELECTION_FILL }, { "select-fill-last-values", GIMP_ICON_TOOL_BUCKET_FILL, - NC_("select-action", "_Fill Selection Outline"), NULL, + NC_("select-action", "_Fill Selection Outline with last values"), NULL, NC_("select-action", "Fill the selection outline with last used values"), select_fill_last_vals_cmd_callback, GIMP_HELP_SELECTION_FILL }, @@ -158,9 +158,27 @@ select_actions_update (GimpActionGroup *group, gboolean writable = FALSE; gboolean children = FALSE; + GList *drawables = NULL; + GList *iter; + gboolean all_writable = TRUE; + gboolean no_groups = TRUE; + if (image) { drawable = gimp_image_get_active_drawable (image); + drawables = gimp_image_get_selected_drawables (image); + + for (iter = drawables; iter; iter = iter->next) + { + if (gimp_item_is_content_locked (iter->data)) + all_writable = FALSE; + + if (gimp_viewable_get_children (iter->data)) + no_groups = FALSE; + + if (! all_writable && ! no_groups) + break; + } if (drawable) { @@ -190,10 +208,12 @@ select_actions_update (GimpActionGroup *group, SET_SENSITIVE ("select-flood", image && sel); SET_SENSITIVE ("select-save", image && !fs); - SET_SENSITIVE ("select-fill", writable && !children && sel); - SET_SENSITIVE ("select-fill-last-values", writable && !children && sel); + SET_SENSITIVE ("select-fill", drawables && all_writable && no_groups && sel); + SET_SENSITIVE ("select-fill-last-values", drawables && all_writable && no_groups && sel); SET_SENSITIVE ("select-stroke", writable && !children && sel); SET_SENSITIVE ("select-stroke-last-values", writable && !children && sel); #undef SET_SENSITIVE + + g_list_free (drawables); } diff --git a/app/core/gimpitem.c b/app/core/gimpitem.c index 724bde7342..5177c3741e 100644 --- a/app/core/gimpitem.c +++ b/app/core/gimpitem.c @@ -1775,25 +1775,30 @@ gimp_item_get_clip (GimpItem *item, gboolean gimp_item_fill (GimpItem *item, - GimpDrawable *drawable, + GList *drawables, GimpFillOptions *fill_options, gboolean push_undo, GimpProgress *progress, GError **error) { GimpItemClass *item_class; + GList *iter; gboolean retval = FALSE; g_return_val_if_fail (GIMP_IS_ITEM (item), FALSE); g_return_val_if_fail (gimp_item_is_attached (item), FALSE); - g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), FALSE); - g_return_val_if_fail (gimp_item_is_attached (GIMP_ITEM (drawable)), FALSE); g_return_val_if_fail (GIMP_IS_FILL_OPTIONS (fill_options), FALSE); g_return_val_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress), FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); item_class = GIMP_ITEM_GET_CLASS (item); + for (iter = drawables; iter; iter = iter->next) + { + g_return_val_if_fail (GIMP_IS_DRAWABLE (iter->data), FALSE); + g_return_val_if_fail (gimp_item_is_attached (GIMP_ITEM (iter->data)), FALSE); + } + if (item_class->fill) { GimpImage *image = gimp_item_get_image (item); @@ -1802,8 +1807,13 @@ gimp_item_fill (GimpItem *item, gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_PAINT, item_class->fill_desc); - retval = item_class->fill (item, drawable, fill_options, push_undo, - progress, error); + for (iter = drawables; iter; iter = iter->next) + { + retval = item_class->fill (item, iter->data, fill_options, + push_undo, progress, error); + if (! retval) + break; + } if (push_undo) gimp_image_undo_group_end (image); diff --git a/app/core/gimpitem.h b/app/core/gimpitem.h index 4b7a9de24c..f72beb8cfe 100644 --- a/app/core/gimpitem.h +++ b/app/core/gimpitem.h @@ -296,7 +296,7 @@ GimpTransformResize gimp_item_get_clip (GimpItem *item, GimpTransformResize clip_result); gboolean gimp_item_fill (GimpItem *item, - GimpDrawable *drawable, + GList *drawables, GimpFillOptions *fill_options, gboolean push_undo, GimpProgress *progress, diff --git a/app/dialogs/fill-dialog.c b/app/dialogs/fill-dialog.c index 2a0d5551c0..a94bf0dd5e 100644 --- a/app/dialogs/fill-dialog.c +++ b/app/dialogs/fill-dialog.c @@ -47,7 +47,7 @@ typedef struct _FillDialog FillDialog; struct _FillDialog { GimpItem *item; - GimpDrawable *drawable; + GList *drawables; GimpContext *context; GimpFillOptions *options; GimpFillCallback callback; @@ -67,7 +67,7 @@ static void fill_dialog_response (GtkWidget *dialog, GtkWidget * fill_dialog_new (GimpItem *item, - GimpDrawable *drawable, + GList *drawables, GimpContext *context, const gchar *title, const gchar *icon_name, @@ -83,7 +83,7 @@ fill_dialog_new (GimpItem *item, GtkWidget *fill_editor; g_return_val_if_fail (GIMP_IS_ITEM (item), NULL); - g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), NULL); + g_return_val_if_fail (drawables, NULL); g_return_val_if_fail (GIMP_IS_CONTEXT (context), NULL); g_return_val_if_fail (GIMP_IS_FILL_OPTIONS (options), NULL); g_return_val_if_fail (icon_name != NULL, NULL); @@ -94,7 +94,7 @@ fill_dialog_new (GimpItem *item, private = g_slice_new0 (FillDialog); private->item = item; - private->drawable = drawable; + private->drawables = g_list_copy (drawables); private->context = context; private->options = gimp_fill_options_new (context->gimp, context, TRUE); private->callback = callback; @@ -152,6 +152,7 @@ static void fill_dialog_free (FillDialog *private) { g_object_unref (private->options); + g_list_free (private->drawables); g_slice_free (FillDialog, private); } @@ -170,7 +171,7 @@ fill_dialog_response (GtkWidget *dialog, case GTK_RESPONSE_OK: private->callback (dialog, private->item, - private->drawable, + private->drawables, private->context, private->options, private->user_data); diff --git a/app/dialogs/fill-dialog.h b/app/dialogs/fill-dialog.h index 35570cb698..671fe90af3 100644 --- a/app/dialogs/fill-dialog.h +++ b/app/dialogs/fill-dialog.h @@ -24,14 +24,14 @@ typedef void (* GimpFillCallback) (GtkWidget *dialog, GimpItem *item, - GimpDrawable *drawable, + GList *drawables, GimpContext *context, GimpFillOptions *options, gpointer user_data); GtkWidget * fill_dialog_new (GimpItem *item, - GimpDrawable *drawable, + GList *drawables, GimpContext *context, const gchar *title, const gchar *icon_name, diff --git a/app/tools/gimpvectortool.c b/app/tools/gimpvectortool.c index 7e40e22291..97b4c4a41d 100644 --- a/app/tools/gimpvectortool.c +++ b/app/tools/gimpvectortool.c @@ -133,7 +133,7 @@ static void gimp_vector_tool_fill_vectors (GimpVectorTool *vector_ GtkWidget *button); static void gimp_vector_tool_fill_callback (GtkWidget *dialog, GimpItem *item, - GimpDrawable *drawable, + GList *drawables, GimpContext *context, GimpFillOptions *options, gpointer data); @@ -718,7 +718,7 @@ gimp_vector_tool_fill_vectors (GimpVectorTool *vector_tool, { GimpDialogConfig *config; GimpImage *image; - GimpDrawable *drawable; + GList *drawables; GtkWidget *dialog; if (! vector_tool->vectors) @@ -728,18 +728,18 @@ gimp_vector_tool_fill_vectors (GimpVectorTool *vector_tool, config = GIMP_DIALOG_CONFIG (image->gimp->config); - drawable = gimp_image_get_active_drawable (image); + drawables = gimp_image_get_selected_drawables (image); - if (! drawable) + if (! drawables) { gimp_tool_message (GIMP_TOOL (vector_tool), GIMP_TOOL (vector_tool)->display, - _("There is no active layer or channel to fill")); + _("There are no selected layers or channels to fill.")); return; } dialog = fill_dialog_new (GIMP_ITEM (vector_tool->vectors), - drawable, + drawables, GIMP_CONTEXT (GIMP_TOOL_GET_OPTIONS (vector_tool)), _("Fill Path"), GIMP_ICON_TOOL_BUCKET_FILL, @@ -749,12 +749,14 @@ gimp_vector_tool_fill_vectors (GimpVectorTool *vector_tool, gimp_vector_tool_fill_callback, vector_tool); gtk_widget_show (dialog); + + g_list_free (drawables); } static void gimp_vector_tool_fill_callback (GtkWidget *dialog, GimpItem *item, - GimpDrawable *drawable, + GList *drawables, GimpContext *context, GimpFillOptions *options, gpointer data) @@ -766,7 +768,7 @@ gimp_vector_tool_fill_callback (GtkWidget *dialog, gimp_config_sync (G_OBJECT (options), G_OBJECT (config->fill_options), 0); - if (! gimp_item_fill (item, drawable, options, + if (! gimp_item_fill (item, drawables, options, TRUE, NULL, &error)) { gimp_message_literal (context->gimp,