/* 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 #include "libgimpbase/gimpbase.h" #include "core-types.h" #include "base/brush-scale.h" #include "base/temp-buf.h" #include "gimpbrush.h" #include "gimpbrush-load.h" #include "gimpbrushgenerated.h" #include "gimpmarshal.h" #include "gimp-intl.h" enum { SPACING_CHANGED, LAST_SIGNAL }; static void gimp_brush_class_init (GimpBrushClass *klass); static void gimp_brush_init (GimpBrush *brush); static void gimp_brush_finalize (GObject *object); static gint64 gimp_brush_get_memsize (GimpObject *object, gint64 *gui_size); static gboolean gimp_brush_get_size (GimpViewable *viewable, gint *width, gint *height); static TempBuf * gimp_brush_get_new_preview (GimpViewable *viewable, gint width, gint height); static gchar * gimp_brush_get_description (GimpViewable *viewable, gchar **tooltip); static gchar * gimp_brush_get_extension (GimpData *data); static GimpBrush * gimp_brush_real_select_brush (GimpBrush *brush, GimpCoords *last_coords, GimpCoords *cur_coords); static gboolean gimp_brush_real_want_null_motion (GimpBrush *brush, GimpCoords *last_coords, GimpCoords *cur_coords); static guint brush_signals[LAST_SIGNAL] = { 0 }; static GimpDataClass *parent_class = NULL; GType gimp_brush_get_type (void) { static GType brush_type = 0; if (! brush_type) { static const GTypeInfo brush_info = { sizeof (GimpBrushClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) gimp_brush_class_init, NULL, /* class_finalize */ NULL, /* class_data */ sizeof (GimpBrush), 0, /* n_preallocs */ (GInstanceInitFunc) gimp_brush_init, }; brush_type = g_type_register_static (GIMP_TYPE_DATA, "GimpBrush", &brush_info, 0); } return brush_type; } static void gimp_brush_class_init (GimpBrushClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); GimpObjectClass *gimp_object_class = GIMP_OBJECT_CLASS (klass); GimpViewableClass *viewable_class = GIMP_VIEWABLE_CLASS (klass); GimpDataClass *data_class = GIMP_DATA_CLASS (klass); parent_class = g_type_class_peek_parent (klass); brush_signals[SPACING_CHANGED] = g_signal_new ("spacing-changed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GimpBrushClass, spacing_changed), NULL, NULL, gimp_marshal_VOID__VOID, G_TYPE_NONE, 0); object_class->finalize = gimp_brush_finalize; gimp_object_class->get_memsize = gimp_brush_get_memsize; viewable_class->default_stock_id = "gimp-tool-paintbrush"; viewable_class->get_size = gimp_brush_get_size; viewable_class->get_new_preview = gimp_brush_get_new_preview; viewable_class->get_description = gimp_brush_get_description; data_class->get_extension = gimp_brush_get_extension; klass->select_brush = gimp_brush_real_select_brush; klass->want_null_motion = gimp_brush_real_want_null_motion; klass->spacing_changed = NULL; } static void gimp_brush_init (GimpBrush *brush) { brush->mask = NULL; brush->pixmap = NULL; brush->spacing = 20; brush->x_axis.x = 15.0; brush->x_axis.y = 0.0; brush->y_axis.x = 0.0; brush->y_axis.y = 15.0; } static void gimp_brush_finalize (GObject *object) { GimpBrush *brush = GIMP_BRUSH (object); if (brush->mask) { temp_buf_free (brush->mask); brush->mask = NULL; } if (brush->pixmap) { temp_buf_free (brush->pixmap); brush->pixmap = NULL; } G_OBJECT_CLASS (parent_class)->finalize (object); } static gint64 gimp_brush_get_memsize (GimpObject *object, gint64 *gui_size) { GimpBrush *brush = GIMP_BRUSH (object); gint64 memsize = 0; if (brush->mask) memsize += temp_buf_get_memsize (brush->mask); if (brush->pixmap) memsize += temp_buf_get_memsize (brush->pixmap); return memsize + GIMP_OBJECT_CLASS (parent_class)->get_memsize (object, gui_size); } static gboolean gimp_brush_get_size (GimpViewable *viewable, gint *width, gint *height) { GimpBrush *brush = GIMP_BRUSH (viewable); *width = brush->mask->width; *height = brush->mask->height; return TRUE; } static TempBuf * gimp_brush_get_new_preview (GimpViewable *viewable, gint width, gint height) { GimpBrush *brush = GIMP_BRUSH (viewable); gint brush_width; gint brush_height; TempBuf *mask_buf = NULL; TempBuf *pixmap_buf = NULL; TempBuf *return_buf = NULL; guchar transp[4] = { 0, 0, 0, 0 }; guchar *mask; guchar *buf; gint x, y; gboolean scale = FALSE; mask_buf = gimp_brush_get_mask (brush); pixmap_buf = gimp_brush_get_pixmap (brush); brush_width = mask_buf->width; brush_height = mask_buf->height; if (brush_width > width || brush_height > height) { gdouble ratio_x = (gdouble) brush_width / width; gdouble ratio_y = (gdouble) brush_height / height; brush_width = (gdouble) brush_width / MAX (ratio_x, ratio_y) + 0.5; brush_height = (gdouble) brush_height / MAX (ratio_x, ratio_y) + 0.5; if (brush_width <= 0) brush_width = 1; if (brush_height <= 0) brush_height = 1; mask_buf = brush_scale_mask (mask_buf, brush_width, brush_height); if (pixmap_buf) { /* TODO: the scale function should scale the pixmap and the * mask in one run */ pixmap_buf = brush_scale_pixmap (pixmap_buf, brush_width, brush_height); } scale = TRUE; } return_buf = temp_buf_new (brush_width, brush_height, 4, 0, 0, transp); mask = temp_buf_data (mask_buf); buf = temp_buf_data (return_buf); if (pixmap_buf) { guchar *pixmap = temp_buf_data (pixmap_buf); for (y = 0; y < brush_height; y++) { for (x = 0; x < brush_width ; x++) { *buf++ = *pixmap++; *buf++ = *pixmap++; *buf++ = *pixmap++; *buf++ = *mask++; } } } else { for (y = 0; y < brush_height; y++) { for (x = 0; x < brush_width ; x++) { *buf++ = 0; *buf++ = 0; *buf++ = 0; *buf++ = *mask++; } } } if (scale) { temp_buf_free (mask_buf); if (pixmap_buf) temp_buf_free (pixmap_buf); } return return_buf; } static gchar * gimp_brush_get_description (GimpViewable *viewable, gchar **tooltip) { GimpBrush *brush = GIMP_BRUSH (viewable); if (tooltip) *tooltip = NULL; return g_strdup_printf ("%s (%d x %d)", GIMP_OBJECT (brush)->name, brush->mask->width, brush->mask->height); } static gchar * gimp_brush_get_extension (GimpData *data) { return GIMP_BRUSH_FILE_EXTENSION; } GimpData * gimp_brush_new (const gchar *name) { g_return_val_if_fail (name != NULL, NULL); return gimp_brush_generated_new (name, GIMP_BRUSH_GENERATED_CIRCLE, 5.0, 2, 0.5, 1.0, 0.0); } GimpData * gimp_brush_get_standard (void) { static GimpData *standard_brush = NULL; if (! standard_brush) { standard_brush = gimp_brush_new ("Standard"); standard_brush->dirty = FALSE; gimp_data_make_internal (standard_brush); /* set ref_count to 2 --> never swap the standard brush */ g_object_ref (standard_brush); } return standard_brush; } GimpBrush * gimp_brush_select_brush (GimpBrush *brush, GimpCoords *last_coords, GimpCoords *cur_coords) { g_return_val_if_fail (GIMP_IS_BRUSH (brush), NULL); g_return_val_if_fail (last_coords != NULL, NULL); g_return_val_if_fail (cur_coords != NULL, NULL); return GIMP_BRUSH_GET_CLASS (brush)->select_brush (brush, last_coords, cur_coords); } gboolean gimp_brush_want_null_motion (GimpBrush *brush, GimpCoords *last_coords, GimpCoords *cur_coords) { g_return_val_if_fail (GIMP_IS_BRUSH (brush), FALSE); g_return_val_if_fail (last_coords != NULL, FALSE); g_return_val_if_fail (cur_coords != NULL, FALSE); return GIMP_BRUSH_GET_CLASS (brush)->want_null_motion (brush, last_coords, cur_coords); } static GimpBrush * gimp_brush_real_select_brush (GimpBrush *brush, GimpCoords *last_coords, GimpCoords *cur_coords) { return brush; } static gboolean gimp_brush_real_want_null_motion (GimpBrush *brush, GimpCoords *last_coords, GimpCoords *cur_coords) { return TRUE; } TempBuf * gimp_brush_get_mask (const GimpBrush *brush) { g_return_val_if_fail (brush != NULL, NULL); g_return_val_if_fail (GIMP_IS_BRUSH (brush), NULL); return brush->mask; } TempBuf * gimp_brush_get_pixmap (const GimpBrush *brush) { g_return_val_if_fail (brush != NULL, NULL); g_return_val_if_fail (GIMP_IS_BRUSH (brush), NULL); return brush->pixmap; } gint gimp_brush_get_spacing (const GimpBrush *brush) { g_return_val_if_fail (GIMP_IS_BRUSH (brush), 0); return brush->spacing; } void gimp_brush_set_spacing (GimpBrush *brush, gint spacing) { g_return_if_fail (GIMP_IS_BRUSH (brush)); if (brush->spacing != spacing) { brush->spacing = spacing; gimp_brush_spacing_changed (brush); } } void gimp_brush_spacing_changed (GimpBrush *brush) { g_return_if_fail (GIMP_IS_BRUSH (brush)); g_signal_emit (brush, brush_signals[SPACING_CHANGED], 0); }