Files
gimp/app/tools/gimpbucketfilltool.c
Michael Natterer 4fa2553253 should set the fs.backing_store TileManager pointer to NULL after deleting
2001-11-09  Michael Natterer  <mitch@gimp.org>

	* app/undo.c: should set the fs.backing_store TileManager pointer
	to NULL after deleting it. Why the heck didn't this crash
	before...?

	* app/core/Makefile.am
	* app/core/gimpdrawable-blend.[ch]: the blend stuff taken from
	the blend tool.

	* app/core/core-types.h: added the blend enums.

	* app/tools/gimpblendtool.[ch]: removed the stuff here.

	* tools/pdbgen/pdb/tools.pdb: changed blend wrapper accordingly.

	* app/pdb/tools_cmds.c: regenerated.

	* tools/pdbgen/Makefile.am: don't scan tools/gimpblendtool.c.

	* tools/pdbgen/enums.pl: regenerated.

	* app/tools/gimpbucketfilltool.c: fixed crash caused by my last
	change.

	* app/display/gimpdisplay.c
	* app/display/gimpdisplayshell-callbacks.c
	* app/display/gimpdisplayshell.c: removed lots of uglyness by
	using GtkImages for the qmask and navigation buttons. Don't realize
	anything before the shell is shown. Connect the realize
	callback and do stuff there. Don't call the realize callback
	from gimp_display_shell_canvas_events() any more.

	* pixmaps/navbutton.xpm
	* pixmaps/qmasknosel.xpm
	* pixmaps/qmasksel.xpm: removed.

	* themes/Default/Makefile.am
	* themes/Default/images/Makefile.am
	* themes/Default/images/stock-menu-navigation.png
	* themes/Default/images/stock-menu-qmask-off.png
	* themes/Default/images/stock-menu-qmask-on.png: new PNGs instead.

	* libgimpwidgets/gimpstock.[ch]: register them as stock icons.
2001-11-09 16:54:56 +00:00

450 lines
13 KiB
C

/* 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 <gtk/gtk.h>
#include <gdk/gdkkeysyms.h>
#include "libgimpwidgets/gimpwidgets.h"
#include "tools-types.h"
#include "core/gimp.h"
#include "core/gimpcontext.h"
#include "core/gimpdrawable.h"
#include "core/gimpdrawable-bucket-fill.h"
#include "core/gimpimage.h"
#include "core/gimpimage-mask.h"
#include "pdb/procedural_db.h"
#include "display/gimpdisplay.h"
#include "display/gimpdisplay-foreach.h"
#include "display/gimpdisplayshell.h"
#include "gimpbucketfilltool.h"
#include "paint_options.h"
#include "tool_manager.h"
#include "gimprc.h"
#include "undo.h"
#include "libgimp/gimpintl.h"
typedef struct _BucketOptions BucketOptions;
struct _BucketOptions
{
PaintOptions paint_options;
gboolean sample_merged;
gboolean sample_merged_d;
GtkWidget *sample_merged_w;
gdouble threshold;
/* gdouble threshold_d; (from gimprc) */
GtkObject *threshold_w;
BucketFillMode fill_mode;
BucketFillMode fill_mode_d;
GtkWidget *fill_mode_w[3];
};
static BucketOptions *bucket_options = NULL;
static GimpToolClass *parent_class = NULL;
/* local function prototypes */
static void gimp_bucket_fill_tool_class_init (GimpBucketFillToolClass *klass);
static void gimp_bucket_fill_tool_init (GimpBucketFillTool *bucket_fill_tool);
static void gimp_bucket_fill_tool_button_press (GimpTool *tool,
GimpCoords *coords,
guint32 time,
GdkModifierType state,
GimpDisplay *gdisp);
static void gimp_bucket_fill_tool_button_release (GimpTool *tool,
GimpCoords *coords,
guint32 time,
GdkModifierType state,
GimpDisplay *gdisp);
static void gimp_bucket_fill_tool_modifier_key (GimpTool *tool,
GdkModifierType key,
gboolean press,
GdkModifierType state,
GimpDisplay *gdisp);
static void gimp_bucket_fill_tool_cursor_update (GimpTool *tool,
GimpCoords *coords,
GdkModifierType state,
GimpDisplay *gdisp);
static BucketOptions * bucket_options_new (void);
static void bucket_options_reset (GimpToolOptions *tool_options);
/* public functions */
void
gimp_bucket_fill_tool_register (Gimp *gimp)
{
tool_manager_register_tool (gimp,
GIMP_TYPE_BUCKET_FILL_TOOL,
TRUE,
"gimp:bucket_fill_tool",
_("Bucket Fill"),
_("Fill with a color or pattern"),
N_("/Tools/Paint Tools/Bucket Fill"), "<shift>B",
NULL, "tools/bucket_fill.html",
GIMP_STOCK_TOOL_BUCKET_FILL);
}
GType
gimp_bucket_fill_tool_get_type (void)
{
static GType tool_type = 0;
if (! tool_type)
{
static const GTypeInfo tool_info =
{
sizeof (GimpBucketFillToolClass),
(GBaseInitFunc) NULL,
(GBaseFinalizeFunc) NULL,
(GClassInitFunc) gimp_bucket_fill_tool_class_init,
NULL, /* class_finalize */
NULL, /* class_data */
sizeof (GimpBucketFillTool),
0, /* n_preallocs */
(GInstanceInitFunc) gimp_bucket_fill_tool_init,
};
tool_type = g_type_register_static (GIMP_TYPE_TOOL,
"GimpBucketFillTool",
&tool_info, 0);
}
return tool_type;
}
/* private functions */
static void
gimp_bucket_fill_tool_class_init (GimpBucketFillToolClass *klass)
{
GimpToolClass *tool_class;
tool_class = GIMP_TOOL_CLASS (klass);
parent_class = g_type_class_peek_parent (klass);
tool_class->button_press = gimp_bucket_fill_tool_button_press;
tool_class->button_release = gimp_bucket_fill_tool_button_release;
tool_class->modifier_key = gimp_bucket_fill_tool_modifier_key;
tool_class->cursor_update = gimp_bucket_fill_tool_cursor_update;
}
static void
gimp_bucket_fill_tool_init (GimpBucketFillTool *bucket_fill_tool)
{
GimpTool *tool;
tool = GIMP_TOOL (bucket_fill_tool);
if (! bucket_options)
{
bucket_options = bucket_options_new ();
tool_manager_register_tool_options (GIMP_TYPE_BUCKET_FILL_TOOL,
(GimpToolOptions *) bucket_options);
}
tool->tool_cursor = GIMP_BUCKET_FILL_TOOL_CURSOR;
tool->scroll_lock = TRUE; /* Disallow scrolling */
}
static void
gimp_bucket_fill_tool_button_press (GimpTool *tool,
GimpCoords *coords,
guint32 time,
GdkModifierType state,
GimpDisplay *gdisp)
{
GimpBucketFillTool *bucket_tool;
GimpDisplayShell *shell;
bucket_tool = GIMP_BUCKET_FILL_TOOL (tool);
shell = GIMP_DISPLAY_SHELL (gdisp->shell);
bucket_tool->target_x = coords->x;
bucket_tool->target_y = coords->y;
if (! bucket_options->sample_merged)
{
gint off_x, off_y;
gimp_drawable_offsets (gimp_image_active_drawable (gdisp->gimage),
&off_x, &off_y);
bucket_tool->target_x -= off_x;
bucket_tool->target_y -= off_y;
}
gdk_pointer_grab (shell->canvas->window, FALSE,
GDK_POINTER_MOTION_HINT_MASK |
GDK_BUTTON1_MOTION_MASK |
GDK_BUTTON_RELEASE_MASK,
NULL, NULL, time);
/* Make the tool active and set the gdisplay which owns it */
tool->gdisp = gdisp;
tool->state = ACTIVE;
}
static void
gimp_bucket_fill_tool_button_release (GimpTool *tool,
GimpCoords *coords,
guint32 time,
GdkModifierType state,
GimpDisplay *gdisp)
{
GimpBucketFillTool *bucket_tool;
Argument *return_vals;
gint nreturn_vals;
bucket_tool = GIMP_BUCKET_FILL_TOOL (tool);
gdk_pointer_ungrab (time);
gdk_flush ();
/* if the 3rd button isn't pressed, fill the selected region */
if (! (state & GDK_BUTTON3_MASK))
{
GimpContext *context;
context = gimp_get_current_context (gdisp->gimage->gimp);
return_vals =
procedural_db_run_proc (gdisp->gimage->gimp,
"gimp_bucket_fill",
&nreturn_vals,
GIMP_PDB_DRAWABLE, gimp_drawable_get_ID (gimp_image_active_drawable (gdisp->gimage)),
GIMP_PDB_INT32, (gint32) bucket_options->fill_mode,
GIMP_PDB_INT32, (gint32) gimp_context_get_paint_mode (context),
GIMP_PDB_FLOAT, (gdouble) gimp_context_get_opacity (context) * 100,
GIMP_PDB_FLOAT, (gdouble) bucket_options->threshold,
GIMP_PDB_INT32, (gint32) bucket_options->sample_merged,
GIMP_PDB_FLOAT, (gdouble) bucket_tool->target_x,
GIMP_PDB_FLOAT, (gdouble) bucket_tool->target_y,
GIMP_PDB_END);
if (return_vals && return_vals[0].value.pdb_int == GIMP_PDB_SUCCESS)
gdisplays_flush ();
else
g_message (_("Bucket Fill operation failed."));
procedural_db_destroy_args (return_vals, nreturn_vals);
}
tool->state = INACTIVE;
}
static void
gimp_bucket_fill_tool_modifier_key (GimpTool *tool,
GdkModifierType key,
gboolean press,
GdkModifierType state,
GimpDisplay *gdisp)
{
if (key == GDK_CONTROL_MASK)
{
switch (bucket_options->fill_mode)
{
case FG_BUCKET_FILL:
gtk_toggle_button_set_active
(GTK_TOGGLE_BUTTON (bucket_options->fill_mode_w[BG_BUCKET_FILL]),
TRUE);
break;
case BG_BUCKET_FILL:
gtk_toggle_button_set_active
(GTK_TOGGLE_BUTTON (bucket_options->fill_mode_w[FG_BUCKET_FILL]),
TRUE);
break;
default:
break;
}
}
}
static void
gimp_bucket_fill_tool_cursor_update (GimpTool *tool,
GimpCoords *coords,
GdkModifierType state,
GimpDisplay *gdisp)
{
GimpDisplayShell *shell;
GimpLayer *layer;
GdkCursorType ctype = GDK_TOP_LEFT_ARROW;
GimpCursorModifier cmodifier = GIMP_CURSOR_MODIFIER_NONE;
gint off_x, off_y;
shell = GIMP_DISPLAY_SHELL (gdisp->shell);
if ((layer = gimp_image_get_active_layer (gdisp->gimage)))
{
gimp_drawable_offsets (GIMP_DRAWABLE (layer), &off_x, &off_y);
if (coords->x >= off_x &&
coords->y >= off_y &&
coords->x < (off_x + gimp_drawable_width (GIMP_DRAWABLE (layer))) &&
coords->y < (off_y + gimp_drawable_height (GIMP_DRAWABLE (layer))))
{
/* One more test--is there a selected region?
* if so, is cursor inside?
*/
if (gimage_mask_is_empty (gdisp->gimage) ||
gimage_mask_value (gdisp->gimage, coords->x, coords->y))
{
ctype = GIMP_MOUSE_CURSOR;
switch (bucket_options->fill_mode)
{
case FG_BUCKET_FILL:
cmodifier = GIMP_CURSOR_MODIFIER_FOREGROUND;
break;
case BG_BUCKET_FILL:
cmodifier = GIMP_CURSOR_MODIFIER_BACKGROUND;
break;
case PATTERN_BUCKET_FILL:
cmodifier = GIMP_CURSOR_MODIFIER_PATTERN;
break;
}
}
}
}
gimp_display_shell_install_tool_cursor (shell,
ctype,
GIMP_BUCKET_FILL_TOOL_CURSOR,
cmodifier);
}
static BucketOptions *
bucket_options_new (void)
{
BucketOptions *options;
GtkWidget *vbox;
GtkWidget *hbox;
GtkWidget *label;
GtkWidget *scale;
GtkWidget *frame;
options = g_new0 (BucketOptions, 1);
paint_options_init ((PaintOptions *) options,
GIMP_TYPE_BUCKET_FILL_TOOL,
bucket_options_reset);
options->sample_merged = options->sample_merged_d = FALSE;
options->threshold = gimprc.default_threshold;
options->fill_mode = options->fill_mode_d = FG_BUCKET_FILL;
/* the main vbox */
vbox = ((GimpToolOptions *) options)->main_vbox;
/* the sample merged toggle */
options->sample_merged_w =
gtk_check_button_new_with_label (_("Sample Merged"));
g_signal_connect (G_OBJECT (options->sample_merged_w), "toggled",
G_CALLBACK (gimp_toggle_button_update),
&options->sample_merged);
gtk_box_pack_start (GTK_BOX (vbox), options->sample_merged_w, FALSE, FALSE, 0);
gtk_widget_show (options->sample_merged_w);
/* the threshold scale */
hbox = gtk_hbox_new (FALSE, 4);
gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
label = gtk_label_new (_("Threshold:"));
gtk_misc_set_alignment (GTK_MISC (label), 1.0, 1.0);
gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
gtk_widget_show (label);
options->threshold_w =
gtk_adjustment_new (gimprc.default_threshold, 0.0, 255.0, 1.0, 1.0, 0.0);
scale = gtk_hscale_new (GTK_ADJUSTMENT (options->threshold_w));
gtk_box_pack_start (GTK_BOX (hbox), scale, TRUE, TRUE, 0);
gtk_scale_set_value_pos (GTK_SCALE (scale), GTK_POS_TOP);
gtk_range_set_update_policy (GTK_RANGE (scale), GTK_UPDATE_DELAYED);
g_signal_connect (G_OBJECT (options->threshold_w), "value_changed",
G_CALLBACK (gimp_double_adjustment_update),
&options->threshold);
gtk_widget_show (scale);
gtk_widget_show (hbox);
/* fill type */
frame =
gimp_radio_group_new2 (TRUE, _("Fill Type"),
G_CALLBACK (gimp_radio_button_update),
&options->fill_mode,
GINT_TO_POINTER (options->fill_mode),
_("FG Color Fill"),
GINT_TO_POINTER (FG_BUCKET_FILL),
&options->fill_mode_w[0],
_("BG Color Fill"),
GINT_TO_POINTER (BG_BUCKET_FILL),
&options->fill_mode_w[1],
_("Pattern Fill"),
GINT_TO_POINTER (PATTERN_BUCKET_FILL),
&options->fill_mode_w[2],
NULL);
gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
gtk_widget_show (frame);
bucket_options_reset ((GimpToolOptions *) options);
return options;
}
static void
bucket_options_reset (GimpToolOptions *tool_options)
{
BucketOptions *options;
options = (BucketOptions *) tool_options;
paint_options_reset (tool_options);
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (options->sample_merged_w),
options->sample_merged_d);
gtk_adjustment_set_value (GTK_ADJUSTMENT (options->threshold_w),
gimprc.default_threshold);
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (options->fill_mode_w[options->fill_mode_d]), TRUE);
}