Commit 49ffbbbb authored by Michael Natterer's avatar Michael Natterer 😴

app: add menu items and a dialog for GimpItem::fill()

which are essentially a copy of the stroking GUI. We now can fill the
exact shape outlined by stroking selections and paths. Suggestions for
the menu item labels are welcome.
parent c09a724b
......@@ -113,6 +113,18 @@ static const GimpActionEntry select_actions[] =
G_CALLBACK (select_save_cmd_callback),
GIMP_HELP_SELECTION_TO_CHANNEL },
{ "select-fill", GIMP_STOCK_TOOL_BUCKET_FILL,
NC_("select-action", "_Fill Selection Outline..."), NULL,
NC_("select-action", "Fill the selection outline"),
G_CALLBACK (select_fill_cmd_callback),
GIMP_HELP_SELECTION_FILL },
{ "select-fill-last-values", GIMP_STOCK_TOOL_BUCKET_FILL,
NC_("select-action", "_Fill Selection Outline"), NULL,
NC_("select-action", "Fill the selection outline with last used values"),
G_CALLBACK (select_fill_last_vals_cmd_callback),
GIMP_HELP_SELECTION_FILL },
{ "select-stroke", GIMP_STOCK_SELECTION_STROKE,
NC_("select-action", "_Stroke Selection..."), NULL,
NC_("select-action", "Paint along the selection outline"),
......@@ -178,6 +190,8 @@ select_actions_update (GimpActionGroup *group,
SET_SENSITIVE ("select-flood", drawable && sel);
SET_SENSITIVE ("select-save", drawable && !fs);
SET_SENSITIVE ("select-fill", writable && !children && sel);
SET_SENSITIVE ("select-fill-last-values", writable && !children && sel);
SET_SENSITIVE ("select-stroke", writable && !children && sel);
SET_SENSITIVE ("select-stroke-last-values", writable && !children && sel);
......
......@@ -39,6 +39,7 @@
#include "display/gimpdisplay.h"
#include "display/gimpdisplayshell.h"
#include "dialogs/fill-dialog.h"
#include "dialogs/stroke-dialog.h"
#include "actions.h"
......@@ -338,6 +339,82 @@ select_save_cmd_callback (GtkAction *action,
"gimp-channel-list");
}
void
select_fill_cmd_callback (GtkAction *action,
gpointer data)
{
GimpImage *image;
GimpDrawable *drawable;
GtkWidget *widget;
GtkWidget *dialog;
return_if_no_image (image, data);
return_if_no_widget (widget, data);
drawable = gimp_image_get_active_drawable (image);
if (! drawable)
{
gimp_message_literal (image->gimp,
G_OBJECT (widget), GIMP_MESSAGE_WARNING,
_("There is no active layer or channel to fill."));
return;
}
dialog = fill_dialog_new (GIMP_ITEM (gimp_image_get_mask (image)),
action_data_get_context (data),
_("Fill Selection Outline"),
GIMP_STOCK_TOOL_BUCKET_FILL,
GIMP_HELP_SELECTION_FILL,
widget);
gtk_widget_show (dialog);
}
void
select_fill_last_vals_cmd_callback (GtkAction *action,
gpointer data)
{
GimpImage *image;
GimpDrawable *drawable;
GtkWidget *widget;
GimpFillOptions *options;
GError *error = NULL;
return_if_no_image (image, data);
return_if_no_widget (widget, data);
drawable = gimp_image_get_active_drawable (image);
if (! drawable)
{
gimp_message_literal (image->gimp,
G_OBJECT (widget), GIMP_MESSAGE_WARNING,
_("There is no active layer or channel to fill."));
return;
}
options = g_object_get_data (G_OBJECT (image->gimp), "saved-fill-options");
if (options)
g_object_ref (options);
else
options = gimp_fill_options_new (image->gimp,
action_data_get_context (data), TRUE);
if (! gimp_item_fill (GIMP_ITEM (gimp_image_get_mask (image)),
drawable, options, TRUE, NULL, &error))
{
gimp_message_literal (image->gimp,
G_OBJECT (widget), GIMP_MESSAGE_WARNING,
error->message);
g_clear_error (&error);
}
else
{
gimp_image_flush (image);
}
g_object_unref (options);
}
void
select_stroke_cmd_callback (GtkAction *action,
gpointer data)
......
......@@ -41,6 +41,11 @@ void select_flood_cmd_callback (GtkAction *action,
gpointer data);
void select_save_cmd_callback (GtkAction *action,
gpointer data);
void select_fill_cmd_callback (GtkAction *action,
gpointer data);
void select_fill_last_vals_cmd_callback (GtkAction *action,
gpointer data);
void select_stroke_cmd_callback (GtkAction *action,
gpointer data);
void select_stroke_last_vals_cmd_callback (GtkAction *action,
......
......@@ -108,6 +108,18 @@ static const GimpActionEntry vectors_actions[] =
G_CALLBACK (vectors_lower_to_bottom_cmd_callback),
GIMP_HELP_PATH_LOWER_TO_BOTTOM },
{ "vectors-fill", GIMP_STOCK_TOOL_BUCKET_FILL,
NC_("vectors-action", "Fill Path..."), NULL,
NC_("vectors-action", "Fill the path"),
G_CALLBACK (vectors_fill_cmd_callback),
GIMP_HELP_PATH_FILL },
{ "vectors-fill-last-values", GIMP_STOCK_TOOL_BUCKET_FILL,
NC_("vectors-action", "Fill Path"), NULL,
NC_("vectors-action", "Fill the path with last values"),
G_CALLBACK (vectors_fill_last_vals_cmd_callback),
GIMP_HELP_PATH_FILL },
{ "vectors-stroke", GIMP_STOCK_PATH_STROKE,
NC_("vectors-action", "Stro_ke Path..."), NULL,
NC_("vectors-action", "Paint along the path"),
......@@ -345,6 +357,12 @@ vectors_actions_update (GimpActionGroup *group,
SET_SENSITIVE ("vectors-selection-to-vectors", image && !mask_empty);
SET_SENSITIVE ("vectors-selection-to-vectors-short", image && !mask_empty);
SET_SENSITIVE ("vectors-selection-to-vectors-advanced", image && !mask_empty);
SET_SENSITIVE ("vectors-fill", vectors &&
dr_writable &&
!dr_children);
SET_SENSITIVE ("vectors-fill-last-values", vectors &&
dr_writable &&
!dr_children);
SET_SENSITIVE ("vectors-stroke", vectors &&
dr_writable &&
!dr_children);
......
......@@ -56,6 +56,7 @@
#include "tools/gimpvectortool.h"
#include "tools/tool_manager.h"
#include "dialogs/fill-dialog.h"
#include "dialogs/stroke-dialog.h"
#include "dialogs/vectors-export-dialog.h"
#include "dialogs/vectors-import-dialog.h"
......@@ -368,6 +369,83 @@ vectors_selection_to_vectors_cmd_callback (GtkAction *action,
}
}
void
vectors_fill_cmd_callback (GtkAction *action,
gpointer data)
{
GimpImage *image;
GimpVectors *vectors;
GimpDrawable *drawable;
GtkWidget *widget;
GtkWidget *dialog;
return_if_no_vectors (image, vectors, data);
return_if_no_widget (widget, data);
drawable = gimp_image_get_active_drawable (image);
if (! drawable)
{
gimp_message_literal (image->gimp,
G_OBJECT (widget), GIMP_MESSAGE_WARNING,
_("There is no active layer or channel to fill."));
return;
}
dialog = fill_dialog_new (GIMP_ITEM (vectors),
action_data_get_context (data),
_("Fill Path"),
GIMP_STOCK_TOOL_BUCKET_FILL,
GIMP_HELP_PATH_FILL,
widget);
gtk_widget_show (dialog);
}
void
vectors_fill_last_vals_cmd_callback (GtkAction *action,
gpointer data)
{
GimpImage *image;
GimpVectors *vectors;
GimpDrawable *drawable;
GtkWidget *widget;
GimpFillOptions *options;
GError *error = NULL;
return_if_no_vectors (image, vectors, data);
return_if_no_widget (widget, data);
drawable = gimp_image_get_active_drawable (image);
if (! drawable)
{
gimp_message_literal (image->gimp,
G_OBJECT (widget), GIMP_MESSAGE_WARNING,
_("There is no active layer or channel to fill."));
return;
}
options = g_object_get_data (G_OBJECT (image->gimp), "saved-fill-options");
if (options)
g_object_ref (options);
else
options = gimp_fill_options_new (image->gimp,
action_data_get_context (data), TRUE);
if (! gimp_item_fill (GIMP_ITEM (vectors),
drawable, options, TRUE, NULL, &error))
{
gimp_message_literal (image->gimp, G_OBJECT (widget),
GIMP_MESSAGE_WARNING, error->message);
g_clear_error (&error);
}
else
{
gimp_image_flush (image);
}
g_object_unref (options);
}
void
vectors_stroke_cmd_callback (GtkAction *action,
gpointer data)
......@@ -424,7 +502,6 @@ vectors_stroke_last_vals_cmd_callback (GtkAction *action,
return;
}
options = g_object_get_data (G_OBJECT (image->gimp), "saved-stroke-options");
if (options)
......
......@@ -49,6 +49,11 @@ void vectors_to_selection_cmd_callback (GtkAction *action,
void vectors_selection_to_vectors_cmd_callback (GtkAction *action,
gint value,
gpointer data);
void vectors_fill_cmd_callback (GtkAction *action,
gpointer data);
void vectors_fill_last_vals_cmd_callback (GtkAction *action,
gpointer data);
void vectors_stroke_cmd_callback (GtkAction *action,
gpointer data);
void vectors_stroke_last_vals_cmd_callback (GtkAction *action,
......
......@@ -44,6 +44,8 @@ libappdialogs_a_sources = \
file-open-location-dialog.h \
file-save-dialog.c \
file-save-dialog.h \
fill-dialog.c \
fill-dialog.h \
grid-dialog.h \
grid-dialog.c \
image-merge-layers-dialog.c \
......
/* GIMP - The GNU Image Manipulation Program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* fill-dialog.c
* Copyright (C) 2016 Michael Natterer <mitch@gimp.org>
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <gegl.h>
#include <gtk/gtk.h>
#include "libgimpconfig/gimpconfig.h"
#include "libgimpwidgets/gimpwidgets.h"
#include "dialogs-types.h"
#include "core/gimp.h"
#include "core/gimpdrawable.h"
#include "core/gimpimage.h"
#include "core/gimpfilloptions.h"
#include "widgets/gimpfilleditor.h"
#include "widgets/gimpviewabledialog.h"
#include "fill-dialog.h"
#include "gimp-intl.h"
#define RESPONSE_RESET 1
/* local functions */
static void fill_dialog_response (GtkWidget *widget,
gint response_id,
GtkWidget *dialog);
/* public function */
GtkWidget *
fill_dialog_new (GimpItem *item,
GimpContext *context,
const gchar *title,
const gchar *icon_name,
const gchar *help_id,
GtkWidget *parent)
{
GimpFillOptions *options;
GimpFillOptions *saved_options;
GtkWidget *dialog;
GtkWidget *main_vbox;
GtkWidget *fill_editor;
g_return_val_if_fail (GIMP_IS_ITEM (item), NULL);
g_return_val_if_fail (GIMP_IS_CONTEXT (context), NULL);
g_return_val_if_fail (icon_name != NULL, NULL);
g_return_val_if_fail (help_id != NULL, NULL);
g_return_val_if_fail (parent == NULL || GTK_IS_WIDGET (parent), NULL);
options = gimp_fill_options_new (context->gimp, context, TRUE);
saved_options = g_object_get_data (G_OBJECT (context->gimp),
"saved-fill-options");
if (saved_options)
gimp_config_sync (G_OBJECT (saved_options), G_OBJECT (options), 0);
dialog = gimp_viewable_dialog_new (GIMP_VIEWABLE (item), context,
title, "gimp-fill-options",
icon_name,
_("Choose Fill Style"),
parent,
gimp_standard_help_func,
help_id,
GIMP_STOCK_RESET, RESPONSE_RESET,
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
_("_Fill"), GTK_RESPONSE_OK,
NULL);
gtk_dialog_set_alternative_button_order (GTK_DIALOG (dialog),
RESPONSE_RESET,
GTK_RESPONSE_OK,
GTK_RESPONSE_CANCEL,
-1);
gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
g_signal_connect (dialog, "response",
G_CALLBACK (fill_dialog_response),
dialog);
g_object_set_data (G_OBJECT (dialog), "gimp-item", item);
g_object_set_data_full (G_OBJECT (dialog), "gimp-fill-options", options,
(GDestroyNotify) g_object_unref);
main_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 12);
gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))),
main_vbox, TRUE, TRUE, 0);
gtk_widget_show (main_vbox);
fill_editor = gimp_fill_editor_new (options, FALSE);
gtk_box_pack_start (GTK_BOX (main_vbox), fill_editor, FALSE, FALSE, 0);
gtk_widget_show (fill_editor);
return dialog;
}
/* private functions */
static void
fill_dialog_response (GtkWidget *widget,
gint response_id,
GtkWidget *dialog)
{
GimpFillOptions *options;
GimpItem *item;
GimpImage *image;
GimpContext *context;
item = g_object_get_data (G_OBJECT (dialog), "gimp-item");
options = g_object_get_data (G_OBJECT (dialog), "gimp-fill-options");
image = gimp_item_get_image (item);
context = GIMP_VIEWABLE_DIALOG (dialog)->context;
switch (response_id)
{
case RESPONSE_RESET:
gimp_config_reset (GIMP_CONFIG (options));
break;
case GTK_RESPONSE_OK:
{
GimpDrawable *drawable = gimp_image_get_active_drawable (image);
GimpFillOptions *saved_options;
GError *error = NULL;
if (! drawable)
{
gimp_message_literal (context->gimp, G_OBJECT (widget),
GIMP_MESSAGE_WARNING,
_("There is no active layer or channel "
"to fill."));
return;
}
saved_options = g_object_get_data (G_OBJECT (context->gimp),
"saved-fill-options");
if (saved_options)
g_object_ref (saved_options);
else
saved_options = gimp_fill_options_new (context->gimp, context, TRUE);
gimp_config_sync (G_OBJECT (options), G_OBJECT (saved_options), 0);
g_object_set_data_full (G_OBJECT (context->gimp), "saved-fill-options",
saved_options,
(GDestroyNotify) g_object_unref);
if (! gimp_item_fill (item, drawable, options, TRUE, NULL, &error))
{
gimp_message_literal (context->gimp,
G_OBJECT (widget),
GIMP_MESSAGE_WARNING,
error ? error->message : "NULL");
g_clear_error (&error);
return;
}
gimp_image_flush (image);
}
/* fallthrough */
default:
gtk_widget_destroy (dialog);
break;
}
}
/* GIMP - The GNU Image Manipulation Program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* fill-dialog.h
* Copyright (C) 2016 Michael Natterer <mitch@gimp.org>
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*/
#ifndef __FILL_DIALOG_H__
#define __FILL_DIALOG_H__
GtkWidget * fill_dialog_new (GimpItem *item,
GimpContext *context,
const gchar *title,
const gchar *icon_name,
const gchar *help_id,
GtkWidget *parent);
#endif /* __FILL_DIALOG_H__ */
......@@ -75,6 +75,7 @@
#define GIMP_HELP_SELECTION_GROW "gimp-selection-grow"
#define GIMP_HELP_SELECTION_BORDER "gimp-selection-border"
#define GIMP_HELP_SELECTION_FLOOD "gimp-selection-flood"
#define GIMP_HELP_SELECTION_FILL "gimp-selection-fill"
#define GIMP_HELP_SELECTION_STROKE "gimp-selection-stroke"
#define GIMP_HELP_SELECTION_TO_CHANNEL "gimp-selection-to-channel"
#define GIMP_HELP_SELECTION_TO_PATH "gimp-selection-to-path"
......@@ -258,6 +259,7 @@
#define GIMP_HELP_PATH_SELECTION_ADD "gimp-path-selection-add"
#define GIMP_HELP_PATH_SELECTION_SUBTRACT "gimp-path-selection-subtract"
#define GIMP_HELP_PATH_SELECTION_INTERSECT "gimp-path-selection-intersect"
#define GIMP_HELP_PATH_FILL "gimp-path-fill"
#define GIMP_HELP_PATH_STROKE "gimp-path-stroke"
#define GIMP_HELP_PATH_COPY "gimp-path-copy"
#define GIMP_HELP_PATH_PASTE "gimp-path-paste"
......
......@@ -213,6 +213,8 @@
<menuitem action="edit-fill-fg" />
<menuitem action="edit-fill-bg" />
<menuitem action="edit-fill-pattern" />
<menuitem action="select-fill" />
<menuitem action="vectors-fill" />
</placeholder>
<placeholder name="Stroke">
<menuitem action="select-stroke" />
......
......@@ -200,6 +200,7 @@ app/dialogs/fade-dialog.c
app/dialogs/file-open-dialog.c
app/dialogs/file-open-location-dialog.c
app/dialogs/file-save-dialog.c
app/dialogs/fill-dialog.c
app/dialogs/grid-dialog.c
app/dialogs/image-merge-layers-dialog.c
app/dialogs/image-new-dialog.c
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment