app/paint/Makefile.am app/paint/gimpink-blob.[ch] app/paint/gimpink.[ch]

2004-05-26  Michael Natterer  <mitch@gimp.org>

	* app/paint/Makefile.am
	* app/paint/gimpink-blob.[ch]
	* app/paint/gimpink.[ch]
	* app/paint/gimpinkoptions.[ch]: new files. Ported the ink tool
	to be a direct GimpPaintCore subclass without any GUI.

	* app/paint/gimp-paint.c: register GimpInk with the list of paint
	cores.

	* app/tools/Makefile.am
	* app/tools/gimpinkoptions.[ch]
	* app/tools/gimpinktool-blob.[ch]: removed these files.

	* app/tools/gimpinkoptions-gui.[ch]: new files containing only
	the GUI for GimpInkOptions.

	* app/tools/gimpinktool.[ch]: reduced to some few lines which
	implement a simple GimpPaintTool subclass.

	* app/tools/gimp-tools.c: associate the GimpInk paint_core with
	the GimpInkTool.
This commit is contained in:
Michael Natterer 2004-05-26 15:34:45 +00:00 committed by Michael Natterer
parent 35eeae1447
commit 5e07ceb851
19 changed files with 1021 additions and 4696 deletions

View File

@ -1,3 +1,27 @@
2004-05-26 Michael Natterer <mitch@gimp.org>
* app/paint/Makefile.am
* app/paint/gimpink-blob.[ch]
* app/paint/gimpink.[ch]
* app/paint/gimpinkoptions.[ch]: new files. Ported the ink tool
to be a direct GimpPaintCore subclass without any GUI.
* app/paint/gimp-paint.c: register GimpInk with the list of paint
cores.
* app/tools/Makefile.am
* app/tools/gimpinkoptions.[ch]
* app/tools/gimpinktool-blob.[ch]: removed these files.
* app/tools/gimpinkoptions-gui.[ch]: new files containing only
the GUI for GimpInkOptions.
* app/tools/gimpinktool.[ch]: reduced to some few lines which
implement a simple GimpPaintTool subclass.
* app/tools/gimp-tools.c: associate the GimpInk paint_core with
the GimpInkTool.
2004-05-26 Michael Natterer <mitch@gimp.org>
* app/paint/gimppaintcore-stroke.c: check if we really have

View File

@ -43,6 +43,12 @@ libapppaint_a_sources = \
gimperaser.h \
gimperaseroptions.c \
gimperaseroptions.h \
gimpink.c \
gimpink.h \
gimpink-blob.c \
gimpink-blob.h \
gimpinkoptions.c \
gimpinkoptions.h \
gimppaintcore.c \
gimppaintcore.h \
gimppaintcore-stroke.c \

View File

@ -32,6 +32,7 @@
#include "gimpconvolve.h"
#include "gimpdodgeburn.h"
#include "gimperaser.h"
#include "gimpink.h"
#include "gimppaintoptions.h"
#include "gimppaintbrush.h"
#include "gimppencil.h"
@ -61,6 +62,7 @@ gimp_paint_init (Gimp *gimp)
gimp_eraser_register,
gimp_paintbrush_register,
gimp_pencil_register,
gimp_ink_register
};
gint i;

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
/* blob.h: routines for manipulating scan converted convex
* polygons.
*
*
* Copyright 1998, Owen Taylor <otaylor@gtk.org>
*
* > Please contact the above author before modifying the copy <
@ -22,20 +22,20 @@
*
*/
#ifndef __GIMP_INK_TOOL_BLOB_H__
#define __GIMP_INK_TOOL_BLOB_H__
#ifndef __GIMP_INK_BLOB_H__
#define __GIMP_INK_BLOB_H__
typedef struct _BlobPoint BlobPoint;
typedef struct _BlobSpan BlobSpan;
typedef struct _Blob Blob;
typedef Blob * (* BlobFunc) (gdouble,
gdouble,
gdouble,
gdouble,
gdouble,
gdouble);
typedef Blob * (* BlobFunc) (gdouble xc,
gdouble yc,
gdouble xp,
gdouble yp,
gdouble xq,
gdouble yq);
struct _BlobPoint
{
@ -57,33 +57,33 @@ struct _Blob
};
Blob * blob_convex_union (Blob *b1,
Blob *b2);
Blob * blob_polygon (BlobPoint *points,
gint npoints);
gint npoints);
Blob * blob_square (gdouble xc,
gdouble yc,
gdouble xp,
gdouble yp,
gdouble xq,
gdouble yq);
gdouble yc,
gdouble xp,
gdouble yp,
gdouble xq,
gdouble yq);
Blob * blob_diamond (gdouble xc,
gdouble yc,
gdouble xp,
gdouble yp,
gdouble xq,
gdouble yq);
gdouble yc,
gdouble xp,
gdouble yp,
gdouble xq,
gdouble yq);
Blob * blob_ellipse (gdouble xc,
gdouble yc,
gdouble xp,
gdouble yp,
gdouble xq,
gdouble yq);
gdouble yc,
gdouble xp,
gdouble yp,
gdouble xq,
gdouble yq);
void blob_bounds (Blob *b,
gint *x,
gint *y,
gint *width,
gint *height);
gint *x,
gint *y,
gint *width,
gint *height);
Blob * blob_convex_union (Blob *b1,
Blob *b2);
#endif /* __GIMP_INK_TOOL_BLOB_H__ */
#endif /* __GIMP_INK_BLOB_H__ */

File diff suppressed because it is too large Load Diff

View File

@ -16,62 +16,60 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef __GIMP_INK_TOOL_H__
#define __GIMP_INK_TOOL_H__
#ifndef __GIMP_INK_H__
#define __GIMP_INK_H__
#include "gimptool.h"
#include "gimpinktool-blob.h" /* only used by ink */
#include "gimppaintcore.h"
#include "gimpink-blob.h"
#define DIST_SMOOTHER_BUFFER 10
#define TIME_SMOOTHER_BUFFER 10
#define GIMP_TYPE_INK_TOOL (gimp_ink_tool_get_type ())
#define GIMP_INK_TOOL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_INK_TOOL, GimpInkTool))
#define GIMP_INK_TOOL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_INK_TOOL, GimpInkToolClass))
#define GIMP_IS_INK_TOOL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_INK_TOOL))
#define GIMP_IS_INK_TOOL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_INK_TOOL))
#define GIMP_INK_TOOL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_INK_TOOL, GimpInkToolClass))
#define GIMP_TYPE_INK (gimp_ink_get_type ())
#define GIMP_INK(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_INK, GimpInk))
#define GIMP_INK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_INK, GimpInkClass))
#define GIMP_IS_INK(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_INK))
#define GIMP_IS_INK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_INK))
#define GIMP_INK_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_INK, GimpInkClass))
typedef struct _GimpInkTool GimpInkTool;
typedef struct _GimpInkToolClass GimpInkToolClass;
typedef struct _GimpInk GimpInk;
typedef struct _GimpInkClass GimpInkClass;
struct _GimpInkTool
struct _GimpInk
{
GimpTool parent_instance;
Blob *last_blob; /* blob for last cursor position */
GimpPaintCore parent_instance;
gint x1, y1; /* image space coordinate */
gint x2, y2; /* image space coords */
Blob *blob; /* current blob */
Blob *last_blob; /* blob for last cursor position */
/* circular distance history buffer */
gdouble dt_buffer[DIST_SMOOTHER_BUFFER];
gint dt_index;
gdouble dt_buffer[DIST_SMOOTHER_BUFFER];
gint dt_index;
/* circular timing history buffer */
guint32 ts_buffer[TIME_SMOOTHER_BUFFER];
gint ts_index;
guint32 ts_buffer[TIME_SMOOTHER_BUFFER];
gint ts_index;
gdouble last_time; /* previous time of a motion event */
gdouble lastx, lasty; /* previous position of a motion event */
gdouble last_time; /* previous time of a motion event */
gdouble lastx, lasty; /* previous position of a motion event */
gboolean init_velocity;
gboolean init_velocity;
};
struct _GimpInkToolClass
struct _GimpInkClass
{
GimpToolClass parent_class;
GimpPaintCoreClass parent_class;
};
void gimp_ink_tool_register (GimpToolRegisterCallback callback,
gpointer data);
void gimp_ink_register (Gimp *gimp,
GimpPaintRegisterCallback callback);
GType gimp_ink_tool_get_type (void) G_GNUC_CONST;
GType gimp_ink_get_type (void) G_GNUC_CONST;
#endif /* __GIMP_INK_TOOL_H__ */
#endif /* __GIMP_INK_H__ */

View File

@ -18,23 +18,18 @@
#include "config.h"
#include <gtk/gtk.h>
#include <glib-object.h>
#include "libgimpwidgets/gimpwidgets.h"
#include "tools-types.h"
#include "paint-types.h"
#include "config/gimpconfig-params.h"
#include "core/gimp.h"
#include "core/gimpdrawable.h"
#include "core/gimptoolinfo.h"
#include "widgets/gimppropwidgets.h"
#include "core/gimppaintinfo.h"
#include "gimpinkoptions.h"
#include "gimpinktool-blob.h"
#include "gimppaintoptions-gui.h"
#include "gimpink-blob.h"
#include "gimp-intl.h"
@ -65,9 +60,6 @@ static void gimp_ink_options_get_property (GObject *object,
GValue *value,
GParamSpec *pspec);
static GtkWidget * brush_widget_new (GimpInkOptions *options);
static GtkWidget * blob_button_new (GimpInkBlobType blob_type);
static GimpPaintOptionsClass *parent_class = NULL;
@ -103,9 +95,7 @@ gimp_ink_options_get_type (void)
static void
gimp_ink_options_class_init (GimpInkOptionsClass *klass)
{
GObjectClass *object_class;
object_class = G_OBJECT_CLASS (klass);
GObjectClass *object_class = G_OBJECT_CLASS (klass);
parent_class = g_type_class_peek_parent (klass);
@ -160,9 +150,7 @@ gimp_ink_options_set_property (GObject *object,
const GValue *value,
GParamSpec *pspec)
{
GimpInkOptions *options;
options = GIMP_INK_OPTIONS (object);
GimpInkOptions *options = GIMP_INK_OPTIONS (object);
switch (property_id)
{
@ -202,9 +190,7 @@ gimp_ink_options_get_property (GObject *object,
GValue *value,
GParamSpec *pspec)
{
GimpInkOptions *options;
options = GIMP_INK_OPTIONS (object);
GimpInkOptions *options = GIMP_INK_OPTIONS (object);
switch (property_id)
{
@ -237,472 +223,3 @@ gimp_ink_options_get_property (GObject *object,
break;
}
}
GtkWidget *
gimp_ink_options_gui (GimpToolOptions *tool_options)
{
GObject *config;
GtkWidget *table;
GtkWidget *vbox;
GtkWidget *brush_vbox;
GtkWidget *hbox;
GtkWidget *frame;
GtkWidget *brush;
config = G_OBJECT (tool_options);
vbox = gimp_paint_options_gui (tool_options);
/* adjust sliders */
frame = gimp_frame_new (_("Adjustment"));
gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, TRUE, 0);
gtk_widget_show (frame);
table = gtk_table_new (2, 3, FALSE);
gtk_table_set_col_spacings (GTK_TABLE (table), 2);
gtk_container_set_border_width (GTK_CONTAINER (table), 2);
gtk_container_add (GTK_CONTAINER (frame), table);
gtk_widget_show (table);
/* size slider */
gimp_prop_scale_entry_new (config, "size",
GTK_TABLE (table), 0, 0,
_("Size:"),
1.0, 2.0, 1,
FALSE, 0.0, 0.0);
/* angle adjust slider */
gimp_prop_scale_entry_new (config, "tilt-angle",
GTK_TABLE (table), 0, 1,
_("Angle:"),
1.0, 10.0, 1,
FALSE, 0.0, 0.0);
/* sens sliders */
frame = gimp_frame_new (_("Sensitivity"));
gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, TRUE, 0);
gtk_widget_show (frame);
table = gtk_table_new (3, 3, FALSE);
gtk_table_set_col_spacings (GTK_TABLE (table), 2);
gtk_container_set_border_width (GTK_CONTAINER (table), 2);
gtk_container_add (GTK_CONTAINER (frame), table);
gtk_widget_show (table);
/* size sens slider */
gimp_prop_scale_entry_new (config, "size-sensitivity",
GTK_TABLE (table), 0, 0,
_("Size:"),
0.01, 0.1, 1,
FALSE, 0.0, 0.0);
/* tilt sens slider */
gimp_prop_scale_entry_new (config, "tilt-sensitivity",
GTK_TABLE (table), 0, 1,
_("Tilt:"),
0.01, 0.1, 1,
FALSE, 0.0, 0.0);
/* velocity sens slider */
gimp_prop_scale_entry_new (config, "vel-sensitivity",
GTK_TABLE (table), 0, 2,
_("Speed:"),
0.01, 0.1, 1,
FALSE, 0.0, 0.0);
/* bottom hbox */
hbox = gtk_hbox_new (FALSE, 2);
gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
gtk_widget_show (hbox);
/* Brush type radiobuttons */
frame = gimp_prop_enum_radio_frame_new (config, "blob-type",
_("Type"), 0, 0);
gtk_box_pack_start (GTK_BOX (hbox), frame, TRUE, TRUE, 0);
gtk_widget_show (frame);
{
GList *children;
GList *list;
GimpInkBlobType blob_type;
children =
gtk_container_get_children (GTK_CONTAINER (GTK_BIN (frame)->child));
for (list = children, blob_type = GIMP_INK_BLOB_TYPE_ELLIPSE;
list;
list = g_list_next (list), blob_type++)
{
GtkWidget *radio;
GtkWidget *blob;
radio = GTK_WIDGET (list->data);
gtk_container_remove (GTK_CONTAINER (radio), GTK_BIN (radio)->child);
blob = blob_button_new (blob_type);
gtk_container_add (GTK_CONTAINER (radio), blob);
gtk_widget_show (blob);
}
g_list_free (children);
}
/* Brush shape widget */
frame = gimp_frame_new (_("Shape"));
gtk_box_pack_start (GTK_BOX (hbox), frame, TRUE, TRUE, 0);
gtk_widget_show (frame);
brush_vbox = gtk_vbox_new (FALSE, 2);
gtk_container_set_border_width (GTK_CONTAINER (brush_vbox), 2);
gtk_container_add (GTK_CONTAINER (frame), brush_vbox);
gtk_widget_show (brush_vbox);
frame = gtk_aspect_frame_new (NULL, 0.0, 0.5, 1.0, FALSE);
gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
gtk_box_pack_start (GTK_BOX (brush_vbox), frame, TRUE, TRUE, 0);
gtk_widget_show (frame);
brush = brush_widget_new (GIMP_INK_OPTIONS (tool_options));
gtk_container_add (GTK_CONTAINER (frame), brush);
gtk_widget_show (brush);
return vbox;
}
/* BrushWidget functions */
typedef struct _BrushWidget BrushWidget;
struct _BrushWidget
{
GtkWidget *widget;
gboolean active;
/* EEK */
GimpInkOptions *ink_options;
};
static void brush_widget_notify (GimpInkOptions *options,
GParamSpec *pspec,
BrushWidget *brush_widget);
static void brush_widget_active_rect (BrushWidget *brush_widget,
GtkWidget *widget,
GdkRectangle *rect);
static void brush_widget_realize (GtkWidget *widget);
static gboolean brush_widget_expose (GtkWidget *widget,
GdkEventExpose *event,
BrushWidget *brush_widget);
static gboolean brush_widget_button_press (GtkWidget *widget,
GdkEventButton *event,
BrushWidget *brush_widget);
static gboolean brush_widget_button_release (GtkWidget *widget,
GdkEventButton *event,
BrushWidget *brush_widget);
static gboolean brush_widget_motion_notify (GtkWidget *widget,
GdkEventMotion *event,
BrushWidget *brush_widget);
static void paint_blob (GdkDrawable *drawable,
GdkGC *gc,
Blob *blob);
static GtkWidget *
brush_widget_new (GimpInkOptions *options)
{
BrushWidget *brush_w;
brush_w = g_new (BrushWidget, 1);
brush_w->widget = gtk_drawing_area_new ();
brush_w->active = FALSE;
brush_w->ink_options = options;
gtk_widget_set_size_request (brush_w->widget, 60, 60);
gtk_widget_set_events (brush_w->widget,
GDK_BUTTON_PRESS_MASK |
GDK_BUTTON_RELEASE_MASK |
GDK_POINTER_MOTION_MASK |
GDK_EXPOSURE_MASK);
g_signal_connect (options, "notify",
G_CALLBACK (brush_widget_notify),
brush_w);
g_signal_connect (brush_w->widget, "button_press_event",
G_CALLBACK (brush_widget_button_press),
brush_w);
g_signal_connect (brush_w->widget, "button_release_event",
G_CALLBACK (brush_widget_button_release),
brush_w);
g_signal_connect (brush_w->widget, "motion_notify_event",
G_CALLBACK (brush_widget_motion_notify),
brush_w);
g_signal_connect (brush_w->widget, "expose_event",
G_CALLBACK (brush_widget_expose),
brush_w);
g_signal_connect (brush_w->widget, "realize",
G_CALLBACK (brush_widget_realize),
brush_w);
g_object_weak_ref (G_OBJECT (brush_w->widget),
(GWeakNotify) g_free, brush_w);
return brush_w->widget;
}
static void
brush_widget_notify (GimpInkOptions *options,
GParamSpec *pspec,
BrushWidget *brush_w)
{
switch (pspec->param_id)
{
case PROP_BLOB_TYPE:
case PROP_BLOB_ASPECT:
case PROP_BLOB_ANGLE:
gtk_widget_queue_draw (brush_w->widget);
break;
default:
break;
}
}
static void
brush_widget_active_rect (BrushWidget *brush_widget,
GtkWidget *widget,
GdkRectangle *rect)
{
gint x,y;
gint r;
r = MIN (widget->allocation.width, widget->allocation.height) / 2;
x = (widget->allocation.width / 2 +
0.85 * r * brush_widget->ink_options->blob_aspect / 10.0 *
cos (brush_widget->ink_options->blob_angle));
y = (widget->allocation.height / 2 +
0.85 * r * brush_widget->ink_options->blob_aspect / 10.0 *
sin (brush_widget->ink_options->blob_angle));
rect->x = x - 5;
rect->y = y - 5;
rect->width = 10;
rect->height = 10;
}
static void
brush_widget_realize (GtkWidget *widget)
{
gtk_style_set_background (widget->style, widget->window, GTK_STATE_ACTIVE);
}
static void
brush_widget_draw_brush (BrushWidget *brush_widget,
GtkWidget *widget,
gdouble xc,
gdouble yc,
gdouble radius)
{
BlobFunc function = blob_ellipse;
Blob *blob;
switch (brush_widget->ink_options->blob_type)
{
case GIMP_INK_BLOB_TYPE_ELLIPSE:
function = blob_ellipse;
break;
case GIMP_INK_BLOB_TYPE_SQUARE:
function = blob_square;
break;
case GIMP_INK_BLOB_TYPE_DIAMOND:
function = blob_diamond;
break;
}
blob = (* function) (xc, yc,
radius * cos (brush_widget->ink_options->blob_angle),
radius * sin (brush_widget->ink_options->blob_angle),
(- (radius / brush_widget->ink_options->blob_aspect) *
sin (brush_widget->ink_options->blob_angle)),
((radius / brush_widget->ink_options->blob_aspect) *
cos (brush_widget->ink_options->blob_angle)));
paint_blob (widget->window, widget->style->fg_gc[widget->state], blob);
g_free (blob);
}
static gboolean
brush_widget_expose (GtkWidget *widget,
GdkEventExpose *event,
BrushWidget *brush_widget)
{
GdkRectangle rect;
gint r0;
r0 = MIN (widget->allocation.width, widget->allocation.height) / 2;
if (r0 < 2)
return TRUE;
brush_widget_draw_brush (brush_widget, widget,
widget->allocation.width / 2,
widget->allocation.height / 2,
0.9 * r0);
brush_widget_active_rect (brush_widget, widget, &rect);
gdk_draw_rectangle (widget->window, widget->style->bg_gc[GTK_STATE_NORMAL],
TRUE, /* filled */
rect.x, rect.y,
rect.width, rect.height);
gtk_paint_shadow (widget->style, widget->window, widget->state,
GTK_SHADOW_OUT,
NULL, widget, NULL,
rect.x, rect.y,
rect.width, rect.height);
return TRUE;
}
static gboolean
brush_widget_button_press (GtkWidget *widget,
GdkEventButton *event,
BrushWidget *brush_widget)
{
GdkRectangle rect;
brush_widget_active_rect (brush_widget, widget, &rect);
if ((event->x >= rect.x) && (event->x-rect.x < rect.width) &&
(event->y >= rect.y) && (event->y-rect.y < rect.height))
{
brush_widget->active = TRUE;
}
return TRUE;
}
static gboolean
brush_widget_button_release (GtkWidget *widget,
GdkEventButton *event,
BrushWidget *brush_widget)
{
brush_widget->active = FALSE;
return TRUE;
}
static gboolean
brush_widget_motion_notify (GtkWidget *widget,
GdkEventMotion *event,
BrushWidget *brush_widget)
{
if (brush_widget->active)
{
gint x;
gint y;
gint rsquare;
x = event->x - widget->allocation.width / 2;
y = event->y - widget->allocation.height / 2;
rsquare = x*x + y*y;
if (rsquare != 0)
{
gint r0;
gdouble angle;
gdouble aspect;
r0 = MIN (widget->allocation.width, widget->allocation.height) / 2;
angle = atan2 (y, x);
aspect = 10.0 * sqrt ((gdouble) rsquare / (r0 * r0)) / 0.85;
aspect = CLAMP (aspect, 1.0, 10.0);
g_object_set (brush_widget->ink_options,
"blob-angle", angle,
"blob-aspect", aspect,
NULL);
gtk_widget_queue_draw (widget);
}
}
return TRUE;
}
/* blob button functions */
static gboolean blob_button_expose (GtkWidget *widget,
GdkEventExpose *event,
BlobFunc function);
static GtkWidget *
blob_button_new (GimpInkBlobType blob_type)
{
GtkWidget *blob;
BlobFunc function = blob_ellipse;
switch (blob_type)
{
case GIMP_INK_BLOB_TYPE_ELLIPSE:
function = blob_ellipse;
break;
case GIMP_INK_BLOB_TYPE_SQUARE:
function = blob_square;
break;
case GIMP_INK_BLOB_TYPE_DIAMOND:
function = blob_diamond;
break;
}
blob = gtk_drawing_area_new ();
gtk_widget_set_size_request (blob, 21, 21);
g_signal_connect (blob, "expose_event",
G_CALLBACK (blob_button_expose),
function);
return blob;
}
static gboolean
blob_button_expose (GtkWidget *widget,
GdkEventExpose *event,
BlobFunc function)
{
Blob *blob;
blob = (* function) (widget->allocation.width / 2,
widget->allocation.height / 2,
8, 0, 0, 8);
paint_blob (widget->window, widget->style->fg_gc[widget->state], blob);
g_free (blob);
return TRUE;
}
/* Draw a blob onto a drawable with the specified graphics context */
static void
paint_blob (GdkDrawable *drawable,
GdkGC *gc,
Blob *blob)
{
gint i;
for (i = 0; i < blob->height; i++)
if (blob->data[i].left <= blob->data[i].right)
gdk_draw_line (drawable, gc,
blob->data[i].left, i + blob->y,
blob->data[i].right + 1, i + blob->y);
}

View File

@ -20,7 +20,7 @@
#define __GIMP_INK_OPTIONS_H__
#include "paint/gimppaintoptions.h"
#include "gimppaintoptions.h"
#define GIMP_TYPE_INK_OPTIONS (gimp_ink_options_get_type ())
@ -51,9 +51,7 @@ struct _GimpInkOptions
};
GType gimp_ink_options_get_type (void) G_GNUC_CONST;
GtkWidget * gimp_ink_options_gui (GimpToolOptions *tool_options);
GType gimp_ink_options_get_type (void) G_GNUC_CONST;
#endif /* __GIMP_INK_OPTIONS_H__ */

View File

@ -72,12 +72,10 @@ libapptools_a_sources = \
gimpimagemapoptions.h \
gimpimagemaptool.c \
gimpimagemaptool.h \
gimpinkoptions.c \
gimpinkoptions.h \
gimpinkoptions-gui.c \
gimpinkoptions-gui.h \
gimpinktool.c \
gimpinktool.h \
gimpinktool-blob.c \
gimpinktool-blob.h \
gimpiscissorstool.c \
gimpiscissorstool.h \
gimplevelstool.c \

View File

@ -429,6 +429,10 @@ gimp_tools_register (GType tool_type,
{
paint_core_name = "GimpDodgeBurn";
}
else if (tool_type == GIMP_TYPE_INK_TOOL)
{
paint_core_name = "GimpInk";
}
else
{
paint_core_name = "GimpPaintbrush";

View File

@ -18,226 +18,29 @@
#include "config.h"
#include <string.h>
#include <gtk/gtk.h>
#include "libgimpwidgets/gimpwidgets.h"
#include "tools-types.h"
#include "config/gimpconfig-params.h"
#include "core/gimp.h"
#include "core/gimpdrawable.h"
#include "core/gimptoolinfo.h"
#include "paint/gimpink-blob.h"
#include "paint/gimpinkoptions.h"
#include "widgets/gimppropwidgets.h"
#include "gimpinkoptions.h"
#include "gimpinktool-blob.h"
#include "gimpinkoptions-gui.h"
#include "gimppaintoptions-gui.h"
#include "gimp-intl.h"
enum
{
PROP_0,
PROP_SIZE,
PROP_TILT_ANGLE,
PROP_SIZE_SENSITIVITY,
PROP_VEL_SENSITIVITY,
PROP_TILT_SENSITIVITY,
PROP_BLOB_TYPE,
PROP_BLOB_ASPECT,
PROP_BLOB_ANGLE
};
static void gimp_ink_options_init (GimpInkOptions *options);
static void gimp_ink_options_class_init (GimpInkOptionsClass *options_class);
static void gimp_ink_options_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec);
static void gimp_ink_options_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec);
static GtkWidget * brush_widget_new (GimpInkOptions *options);
static GtkWidget * blob_button_new (GimpInkBlobType blob_type);
static GimpPaintOptionsClass *parent_class = NULL;
GType
gimp_ink_options_get_type (void)
{
static GType type = 0;
if (! type)
{
static const GTypeInfo info =
{
sizeof (GimpInkOptionsClass),
(GBaseInitFunc) NULL,
(GBaseFinalizeFunc) NULL,
(GClassInitFunc) gimp_ink_options_class_init,
NULL, /* class_finalize */
NULL, /* class_data */
sizeof (GimpInkOptions),
0, /* n_preallocs */
(GInstanceInitFunc) gimp_ink_options_init,
};
type = g_type_register_static (GIMP_TYPE_PAINT_OPTIONS,
"GimpInkOptions",
&info, 0);
}
return type;
}
static void
gimp_ink_options_class_init (GimpInkOptionsClass *klass)
{
GObjectClass *object_class;
object_class = G_OBJECT_CLASS (klass);
parent_class = g_type_class_peek_parent (klass);
object_class->set_property = gimp_ink_options_set_property;
object_class->get_property = gimp_ink_options_get_property;
GIMP_CONFIG_INSTALL_PROP_DOUBLE (object_class, PROP_SIZE,
"size", NULL,
0.0, 20.0, 4.4,
0);
GIMP_CONFIG_INSTALL_PROP_DOUBLE (object_class, PROP_TILT_ANGLE,
"tilt-angle", NULL,
-90.0, 90.0, 0.0,
0);
GIMP_CONFIG_INSTALL_PROP_DOUBLE (object_class, PROP_SIZE_SENSITIVITY,
"size-sensitivity", NULL,
0.0, 1.0, 1.0,
0);
GIMP_CONFIG_INSTALL_PROP_DOUBLE (object_class, PROP_VEL_SENSITIVITY,
"vel-sensitivity", NULL,
0.0, 1.0, 0.8,
0);
GIMP_CONFIG_INSTALL_PROP_DOUBLE (object_class, PROP_TILT_SENSITIVITY,
"tilt-sensitivity", NULL,
0.0, 1.0, 0.4,
0);
GIMP_CONFIG_INSTALL_PROP_ENUM (object_class, PROP_BLOB_TYPE,
"blob-type", NULL,
GIMP_TYPE_INK_BLOB_TYPE,
GIMP_INK_BLOB_TYPE_ELLIPSE,
0);
GIMP_CONFIG_INSTALL_PROP_DOUBLE (object_class, PROP_BLOB_ASPECT,
"blob-aspect", NULL,
1.0, 10.0, 1.0,
0);
GIMP_CONFIG_INSTALL_PROP_DOUBLE (object_class, PROP_BLOB_ANGLE,
"blob-angle", NULL,
-90.0, 90.0, 0.0,
0);
}
static void
gimp_ink_options_init (GimpInkOptions *options)
{
}
static void
gimp_ink_options_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
GimpInkOptions *options;
options = GIMP_INK_OPTIONS (object);
switch (property_id)
{
case PROP_SIZE:
options->size = g_value_get_double (value);
break;
case PROP_TILT_ANGLE:
options->tilt_angle = g_value_get_double (value);
break;
case PROP_SIZE_SENSITIVITY:
options->size_sensitivity = g_value_get_double (value);
break;
case PROP_VEL_SENSITIVITY:
options->vel_sensitivity = g_value_get_double (value);
break;
case PROP_TILT_SENSITIVITY:
options->tilt_sensitivity = g_value_get_double (value);
break;
case PROP_BLOB_TYPE:
options->blob_type = g_value_get_enum (value);
break;
case PROP_BLOB_ASPECT:
options->blob_aspect = g_value_get_double (value);
break;
case PROP_BLOB_ANGLE:
options->blob_angle = g_value_get_double (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
gimp_ink_options_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
GimpInkOptions *options;
options = GIMP_INK_OPTIONS (object);
switch (property_id)
{
case PROP_SIZE:
g_value_set_double (value, options->size);
break;
case PROP_TILT_ANGLE:
g_value_set_double (value, options->tilt_angle);
break;
case PROP_SIZE_SENSITIVITY:
g_value_set_double (value, options->size_sensitivity);
break;
case PROP_VEL_SENSITIVITY:
g_value_set_double (value, options->vel_sensitivity);
break;
case PROP_TILT_SENSITIVITY:
g_value_set_double (value, options->tilt_sensitivity);
break;
case PROP_BLOB_TYPE:
g_value_set_enum (value, options->blob_type);
break;
case PROP_BLOB_ASPECT:
g_value_set_double (value, options->blob_aspect);
break;
case PROP_BLOB_ANGLE:
g_value_set_double (value, options->blob_angle);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
GtkWidget *
gimp_ink_options_gui (GimpToolOptions *tool_options)
{
@ -456,17 +259,8 @@ brush_widget_notify (GimpInkOptions *options,
GParamSpec *pspec,
BrushWidget *brush_w)
{
switch (pspec->param_id)
{
case PROP_BLOB_TYPE:
case PROP_BLOB_ASPECT:
case PROP_BLOB_ANGLE:
gtk_widget_queue_draw (brush_w->widget);
break;
default:
break;
}
if (! strncmp (pspec->name, "blob", 4))
gtk_widget_queue_draw (brush_w->widget);
}
static void

View File

@ -16,44 +16,11 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef __GIMP_INK_OPTIONS_H__
#define __GIMP_INK_OPTIONS_H__
#ifndef __GIMP_INK_OPTIONS_GUI_H__
#define __GIMP_INK_OPTIONS_GUI_H__
#include "paint/gimppaintoptions.h"
#define GIMP_TYPE_INK_OPTIONS (gimp_ink_options_get_type ())
#define GIMP_INK_OPTIONS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_INK_OPTIONS, GimpInkOptions))
#define GIMP_INK_OPTIONS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_INK_OPTIONS, GimpInkOptionsClass))
#define GIMP_IS_INK_OPTIONS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_INK_OPTIONS))
#define GIMP_IS_INK_OPTIONS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_INK_OPTIONS))
#define GIMP_INK_OPTIONS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_INK_OPTIONS, GimpInkOptionsClass))
typedef struct _GimpInkOptions GimpInkOptions;
typedef struct _GimpPaintOptionsClass GimpInkOptionsClass;
struct _GimpInkOptions
{
GimpPaintOptions paint_options;
gdouble size;
gdouble tilt_angle;
gdouble size_sensitivity;
gdouble vel_sensitivity;
gdouble tilt_sensitivity;
GimpInkBlobType blob_type;
gdouble blob_aspect;
gdouble blob_angle;
};
GType gimp_ink_options_get_type (void) G_GNUC_CONST;
GtkWidget * gimp_ink_options_gui (GimpToolOptions *tool_options);
#endif /* __GIMP_INK_OPTIONS_H__ */
#endif /* __GIMP_INK_OPTIONS_GUI_H__ */

View File

@ -1,708 +0,0 @@
/* 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 "libgimpwidgets/gimpwidgets.h"
#include "tools-types.h"
#include "config/gimpconfig-params.h"
#include "core/gimp.h"
#include "core/gimpdrawable.h"
#include "core/gimptoolinfo.h"
#include "widgets/gimppropwidgets.h"
#include "gimpinkoptions.h"
#include "gimpinktool-blob.h"
#include "gimppaintoptions-gui.h"
#include "gimp-intl.h"
enum
{
PROP_0,
PROP_SIZE,
PROP_TILT_ANGLE,
PROP_SIZE_SENSITIVITY,
PROP_VEL_SENSITIVITY,
PROP_TILT_SENSITIVITY,
PROP_BLOB_TYPE,
PROP_BLOB_ASPECT,
PROP_BLOB_ANGLE
};
static void gimp_ink_options_init (GimpInkOptions *options);
static void gimp_ink_options_class_init (GimpInkOptionsClass *options_class);
static void gimp_ink_options_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec);
static void gimp_ink_options_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec);
static GtkWidget * brush_widget_new (GimpInkOptions *options);
static GtkWidget * blob_button_new (GimpInkBlobType blob_type);
static GimpPaintOptionsClass *parent_class = NULL;
GType
gimp_ink_options_get_type (void)
{
static GType type = 0;
if (! type)
{
static const GTypeInfo info =
{
sizeof (GimpInkOptionsClass),
(GBaseInitFunc) NULL,
(GBaseFinalizeFunc) NULL,
(GClassInitFunc) gimp_ink_options_class_init,
NULL, /* class_finalize */
NULL, /* class_data */
sizeof (GimpInkOptions),
0, /* n_preallocs */
(GInstanceInitFunc) gimp_ink_options_init,
};
type = g_type_register_static (GIMP_TYPE_PAINT_OPTIONS,
"GimpInkOptions",
&info, 0);
}
return type;
}
static void
gimp_ink_options_class_init (GimpInkOptionsClass *klass)
{
GObjectClass *object_class;
object_class = G_OBJECT_CLASS (klass);
parent_class = g_type_class_peek_parent (klass);
object_class->set_property = gimp_ink_options_set_property;
object_class->get_property = gimp_ink_options_get_property;
GIMP_CONFIG_INSTALL_PROP_DOUBLE (object_class, PROP_SIZE,
"size", NULL,
0.0, 20.0, 4.4,
0);
GIMP_CONFIG_INSTALL_PROP_DOUBLE (object_class, PROP_TILT_ANGLE,
"tilt-angle", NULL,
-90.0, 90.0, 0.0,
0);
GIMP_CONFIG_INSTALL_PROP_DOUBLE (object_class, PROP_SIZE_SENSITIVITY,
"size-sensitivity", NULL,
0.0, 1.0, 1.0,
0);
GIMP_CONFIG_INSTALL_PROP_DOUBLE (object_class, PROP_VEL_SENSITIVITY,
"vel-sensitivity", NULL,
0.0, 1.0, 0.8,
0);
GIMP_CONFIG_INSTALL_PROP_DOUBLE (object_class, PROP_TILT_SENSITIVITY,
"tilt-sensitivity", NULL,
0.0, 1.0, 0.4,
0);
GIMP_CONFIG_INSTALL_PROP_ENUM (object_class, PROP_BLOB_TYPE,
"blob-type", NULL,
GIMP_TYPE_INK_BLOB_TYPE,
GIMP_INK_BLOB_TYPE_ELLIPSE,
0);
GIMP_CONFIG_INSTALL_PROP_DOUBLE (object_class, PROP_BLOB_ASPECT,
"blob-aspect", NULL,
1.0, 10.0, 1.0,
0);
GIMP_CONFIG_INSTALL_PROP_DOUBLE (object_class, PROP_BLOB_ANGLE,
"blob-angle", NULL,
-90.0, 90.0, 0.0,
0);
}
static void
gimp_ink_options_init (GimpInkOptions *options)
{
}
static void
gimp_ink_options_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
GimpInkOptions *options;
options = GIMP_INK_OPTIONS (object);
switch (property_id)
{
case PROP_SIZE:
options->size = g_value_get_double (value);
break;
case PROP_TILT_ANGLE:
options->tilt_angle = g_value_get_double (value);
break;
case PROP_SIZE_SENSITIVITY:
options->size_sensitivity = g_value_get_double (value);
break;
case PROP_VEL_SENSITIVITY:
options->vel_sensitivity = g_value_get_double (value);
break;
case PROP_TILT_SENSITIVITY:
options->tilt_sensitivity = g_value_get_double (value);
break;
case PROP_BLOB_TYPE:
options->blob_type = g_value_get_enum (value);
break;
case PROP_BLOB_ASPECT:
options->blob_aspect = g_value_get_double (value);
break;
case PROP_BLOB_ANGLE:
options->blob_angle = g_value_get_double (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
gimp_ink_options_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
GimpInkOptions *options;
options = GIMP_INK_OPTIONS (object);
switch (property_id)
{
case PROP_SIZE:
g_value_set_double (value, options->size);
break;
case PROP_TILT_ANGLE:
g_value_set_double (value, options->tilt_angle);
break;
case PROP_SIZE_SENSITIVITY:
g_value_set_double (value, options->size_sensitivity);
break;
case PROP_VEL_SENSITIVITY:
g_value_set_double (value, options->vel_sensitivity);
break;
case PROP_TILT_SENSITIVITY:
g_value_set_double (value, options->tilt_sensitivity);
break;
case PROP_BLOB_TYPE:
g_value_set_enum (value, options->blob_type);
break;
case PROP_BLOB_ASPECT:
g_value_set_double (value, options->blob_aspect);
break;
case PROP_BLOB_ANGLE:
g_value_set_double (value, options->blob_angle);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
GtkWidget *
gimp_ink_options_gui (GimpToolOptions *tool_options)
{
GObject *config;
GtkWidget *table;
GtkWidget *vbox;
GtkWidget *brush_vbox;
GtkWidget *hbox;
GtkWidget *frame;
GtkWidget *brush;
config = G_OBJECT (tool_options);
vbox = gimp_paint_options_gui (tool_options);
/* adjust sliders */
frame = gimp_frame_new (_("Adjustment"));
gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, TRUE, 0);
gtk_widget_show (frame);
table = gtk_table_new (2, 3, FALSE);
gtk_table_set_col_spacings (GTK_TABLE (table), 2);
gtk_container_set_border_width (GTK_CONTAINER (table), 2);
gtk_container_add (GTK_CONTAINER (frame), table);
gtk_widget_show (table);
/* size slider */
gimp_prop_scale_entry_new (config, "size",
GTK_TABLE (table), 0, 0,
_("Size:"),
1.0, 2.0, 1,
FALSE, 0.0, 0.0);
/* angle adjust slider */
gimp_prop_scale_entry_new (config, "tilt-angle",
GTK_TABLE (table), 0, 1,
_("Angle:"),
1.0, 10.0, 1,
FALSE, 0.0, 0.0);
/* sens sliders */
frame = gimp_frame_new (_("Sensitivity"));
gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, TRUE, 0);
gtk_widget_show (frame);
table = gtk_table_new (3, 3, FALSE);
gtk_table_set_col_spacings (GTK_TABLE (table), 2);
gtk_container_set_border_width (GTK_CONTAINER (table), 2);
gtk_container_add (GTK_CONTAINER (frame), table);
gtk_widget_show (table);
/* size sens slider */
gimp_prop_scale_entry_new (config, "size-sensitivity",
GTK_TABLE (table), 0, 0,
_("Size:"),
0.01, 0.1, 1,
FALSE, 0.0, 0.0);
/* tilt sens slider */
gimp_prop_scale_entry_new (config, "tilt-sensitivity",
GTK_TABLE (table), 0, 1,
_("Tilt:"),
0.01, 0.1, 1,
FALSE, 0.0, 0.0);
/* velocity sens slider */
gimp_prop_scale_entry_new (config, "vel-sensitivity",
GTK_TABLE (table), 0, 2,
_("Speed:"),
0.01, 0.1, 1,
FALSE, 0.0, 0.0);
/* bottom hbox */
hbox = gtk_hbox_new (FALSE, 2);
gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
gtk_widget_show (hbox);
/* Brush type radiobuttons */
frame = gimp_prop_enum_radio_frame_new (config, "blob-type",
_("Type"), 0, 0);
gtk_box_pack_start (GTK_BOX (hbox), frame, TRUE, TRUE, 0);
gtk_widget_show (frame);
{
GList *children;
GList *list;
GimpInkBlobType blob_type;
children =
gtk_container_get_children (GTK_CONTAINER (GTK_BIN (frame)->child));
for (list = children, blob_type = GIMP_INK_BLOB_TYPE_ELLIPSE;
list;
list = g_list_next (list), blob_type++)
{
GtkWidget *radio;
GtkWidget *blob;
radio = GTK_WIDGET (list->data);
gtk_container_remove (GTK_CONTAINER (radio), GTK_BIN (radio)->child);
blob = blob_button_new (blob_type);
gtk_container_add (GTK_CONTAINER (radio), blob);
gtk_widget_show (blob);
}
g_list_free (children);
}
/* Brush shape widget */
frame = gimp_frame_new (_("Shape"));
gtk_box_pack_start (GTK_BOX (hbox), frame, TRUE, TRUE, 0);
gtk_widget_show (frame);
brush_vbox = gtk_vbox_new (FALSE, 2);
gtk_container_set_border_width (GTK_CONTAINER (brush_vbox), 2);
gtk_container_add (GTK_CONTAINER (frame), brush_vbox);
gtk_widget_show (brush_vbox);
frame = gtk_aspect_frame_new (NULL, 0.0, 0.5, 1.0, FALSE);
gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
gtk_box_pack_start (GTK_BOX (brush_vbox), frame, TRUE, TRUE, 0);
gtk_widget_show (frame);
brush = brush_widget_new (GIMP_INK_OPTIONS (tool_options));
gtk_container_add (GTK_CONTAINER (frame), brush);
gtk_widget_show (brush);
return vbox;
}
/* BrushWidget functions */
typedef struct _BrushWidget BrushWidget;
struct _BrushWidget
{
GtkWidget *widget;
gboolean active;
/* EEK */
GimpInkOptions *ink_options;
};
static void brush_widget_notify (GimpInkOptions *options,
GParamSpec *pspec,
BrushWidget *brush_widget);
static void brush_widget_active_rect (BrushWidget *brush_widget,
GtkWidget *widget,
GdkRectangle *rect);
static void brush_widget_realize (GtkWidget *widget);
static gboolean brush_widget_expose (GtkWidget *widget,
GdkEventExpose *event,
BrushWidget *brush_widget);
static gboolean brush_widget_button_press (GtkWidget *widget,
GdkEventButton *event,
BrushWidget *brush_widget);
static gboolean brush_widget_button_release (GtkWidget *widget,
GdkEventButton *event,
BrushWidget *brush_widget);
static gboolean brush_widget_motion_notify (GtkWidget *widget,
GdkEventMotion *event,
BrushWidget *brush_widget);
static void paint_blob (GdkDrawable *drawable,
GdkGC *gc,
Blob *blob);
static GtkWidget *
brush_widget_new (GimpInkOptions *options)
{
BrushWidget *brush_w;
brush_w = g_new (BrushWidget, 1);
brush_w->widget = gtk_drawing_area_new ();
brush_w->active = FALSE;
brush_w->ink_options = options;
gtk_widget_set_size_request (brush_w->widget, 60, 60);
gtk_widget_set_events (brush_w->widget,
GDK_BUTTON_PRESS_MASK |
GDK_BUTTON_RELEASE_MASK |
GDK_POINTER_MOTION_MASK |
GDK_EXPOSURE_MASK);
g_signal_connect (options, "notify",
G_CALLBACK (brush_widget_notify),
brush_w);
g_signal_connect (brush_w->widget, "button_press_event",
G_CALLBACK (brush_widget_button_press),
brush_w);
g_signal_connect (brush_w->widget, "button_release_event",
G_CALLBACK (brush_widget_button_release),
brush_w);
g_signal_connect (brush_w->widget, "motion_notify_event",
G_CALLBACK (brush_widget_motion_notify),
brush_w);
g_signal_connect (brush_w->widget, "expose_event",
G_CALLBACK (brush_widget_expose),
brush_w);
g_signal_connect (brush_w->widget, "realize",
G_CALLBACK (brush_widget_realize),
brush_w);
g_object_weak_ref (G_OBJECT (brush_w->widget),
(GWeakNotify) g_free, brush_w);
return brush_w->widget;
}
static void
brush_widget_notify (GimpInkOptions *options,
GParamSpec *pspec,
BrushWidget *brush_w)
{
switch (pspec->param_id)
{
case PROP_BLOB_TYPE:
case PROP_BLOB_ASPECT:
case PROP_BLOB_ANGLE:
gtk_widget_queue_draw (brush_w->widget);
break;
default:
break;
}
}
static void
brush_widget_active_rect (BrushWidget *brush_widget,
GtkWidget *widget,
GdkRectangle *rect)
{
gint x,y;
gint r;
r = MIN (widget->allocation.width, widget->allocation.height) / 2;
x = (widget->allocation.width / 2 +
0.85 * r * brush_widget->ink_options->blob_aspect / 10.0 *
cos (brush_widget->ink_options->blob_angle));
y = (widget->allocation.height / 2 +
0.85 * r * brush_widget->ink_options->blob_aspect / 10.0 *
sin (brush_widget->ink_options->blob_angle));
rect->x = x - 5;
rect->y = y - 5;
rect->width = 10;
rect->height = 10;
}
static void
brush_widget_realize (GtkWidget *widget)
{
gtk_style_set_background (widget->style, widget->window, GTK_STATE_ACTIVE);
}
static void
brush_widget_draw_brush (BrushWidget *brush_widget,
GtkWidget *widget,
gdouble xc,
gdouble yc,
gdouble radius)
{
BlobFunc function = blob_ellipse;
Blob *blob;
switch (brush_widget->ink_options->blob_type)
{
case GIMP_INK_BLOB_TYPE_ELLIPSE:
function = blob_ellipse;
break;
case GIMP_INK_BLOB_TYPE_SQUARE:
function = blob_square;
break;
case GIMP_INK_BLOB_TYPE_DIAMOND:
function = blob_diamond;
break;
}
blob = (* function) (xc, yc,
radius * cos (brush_widget->ink_options->blob_angle),
radius * sin (brush_widget->ink_options->blob_angle),
(- (radius / brush_widget->ink_options->blob_aspect) *
sin (brush_widget->ink_options->blob_angle)),
((radius / brush_widget->ink_options->blob_aspect) *
cos (brush_widget->ink_options->blob_angle)));
paint_blob (widget->window, widget->style->fg_gc[widget->state], blob);
g_free (blob);
}
static gboolean
brush_widget_expose (GtkWidget *widget,
GdkEventExpose *event,
BrushWidget *brush_widget)
{
GdkRectangle rect;
gint r0;
r0 = MIN (widget->allocation.width, widget->allocation.height) / 2;
if (r0 < 2)
return TRUE;
brush_widget_draw_brush (brush_widget, widget,
widget->allocation.width / 2,
widget->allocation.height / 2,
0.9 * r0);
brush_widget_active_rect (brush_widget, widget, &rect);
gdk_draw_rectangle (widget->window, widget->style->bg_gc[GTK_STATE_NORMAL],
TRUE, /* filled */
rect.x, rect.y,
rect.width, rect.height);
gtk_paint_shadow (widget->style, widget->window, widget->state,
GTK_SHADOW_OUT,
NULL, widget, NULL,
rect.x, rect.y,
rect.width, rect.height);
return TRUE;
}
static gboolean
brush_widget_button_press (GtkWidget *widget,
GdkEventButton *event,
BrushWidget *brush_widget)
{
GdkRectangle rect;
brush_widget_active_rect (brush_widget, widget, &rect);
if ((event->x >= rect.x) && (event->x-rect.x < rect.width) &&
(event->y >= rect.y) && (event->y-rect.y < rect.height))
{
brush_widget->active = TRUE;
}
return TRUE;
}
static gboolean
brush_widget_button_release (GtkWidget *widget,
GdkEventButton *event,
BrushWidget *brush_widget)
{
brush_widget->active = FALSE;
return TRUE;
}
static gboolean
brush_widget_motion_notify (GtkWidget *widget,
GdkEventMotion *event,
BrushWidget *brush_widget)
{
if (brush_widget->active)
{
gint x;
gint y;
gint rsquare;
x = event->x - widget->allocation.width / 2;
y = event->y - widget->allocation.height / 2;
rsquare = x*x + y*y;
if (rsquare != 0)
{
gint r0;
gdouble angle;
gdouble aspect;
r0 = MIN (widget->allocation.width, widget->allocation.height) / 2;
angle = atan2 (y, x);
aspect = 10.0 * sqrt ((gdouble) rsquare / (r0 * r0)) / 0.85;
aspect = CLAMP (aspect, 1.0, 10.0);
g_object_set (brush_widget->ink_options,
"blob-angle", angle,
"blob-aspect", aspect,
NULL);
gtk_widget_queue_draw (widget);
}
}
return TRUE;
}
/* blob button functions */
static gboolean blob_button_expose (GtkWidget *widget,
GdkEventExpose *event,
BlobFunc function);
static GtkWidget *
blob_button_new (GimpInkBlobType blob_type)
{
GtkWidget *blob;
BlobFunc function = blob_ellipse;
switch (blob_type)
{
case GIMP_INK_BLOB_TYPE_ELLIPSE:
function = blob_ellipse;
break;
case GIMP_INK_BLOB_TYPE_SQUARE:
function = blob_square;
break;
case GIMP_INK_BLOB_TYPE_DIAMOND:
function = blob_diamond;
break;
}
blob = gtk_drawing_area_new ();
gtk_widget_set_size_request (blob, 21, 21);
g_signal_connect (blob, "expose_event",
G_CALLBACK (blob_button_expose),
function);
return blob;
}
static gboolean
blob_button_expose (GtkWidget *widget,
GdkEventExpose *event,
BlobFunc function)
{
Blob *blob;
blob = (* function) (widget->allocation.width / 2,
widget->allocation.height / 2,
8, 0, 0, 8);
paint_blob (widget->window, widget->style->fg_gc[widget->state], blob);
g_free (blob);
return TRUE;
}
/* Draw a blob onto a drawable with the specified graphics context */
static void
paint_blob (GdkDrawable *drawable,
GdkGC *gc,
Blob *blob)
{
gint i;
for (i = 0; i < blob->height; i++)
if (blob->data[i].left <= blob->data[i].right)
gdk_draw_line (drawable, gc,
blob->data[i].left, i + blob->y,
blob->data[i].right + 1, i + blob->y);
}

View File

@ -1,59 +0,0 @@
/* 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.
*/
#ifndef __GIMP_INK_OPTIONS_H__
#define __GIMP_INK_OPTIONS_H__
#include "paint/gimppaintoptions.h"
#define GIMP_TYPE_INK_OPTIONS (gimp_ink_options_get_type ())
#define GIMP_INK_OPTIONS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_INK_OPTIONS, GimpInkOptions))
#define GIMP_INK_OPTIONS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_INK_OPTIONS, GimpInkOptionsClass))
#define GIMP_IS_INK_OPTIONS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_INK_OPTIONS))
#define GIMP_IS_INK_OPTIONS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_INK_OPTIONS))
#define GIMP_INK_OPTIONS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_INK_OPTIONS, GimpInkOptionsClass))
typedef struct _GimpInkOptions GimpInkOptions;
typedef struct _GimpPaintOptionsClass GimpInkOptionsClass;
struct _GimpInkOptions
{
GimpPaintOptions paint_options;
gdouble size;
gdouble tilt_angle;
gdouble size_sensitivity;
gdouble vel_sensitivity;
gdouble tilt_sensitivity;
GimpInkBlobType blob_type;
gdouble blob_aspect;
gdouble blob_angle;
};
GType gimp_ink_options_get_type (void) G_GNUC_CONST;
GtkWidget * gimp_ink_options_gui (GimpToolOptions *tool_options);
#endif /* __GIMP_INK_OPTIONS_H__ */

View File

@ -1,778 +0,0 @@
/* blob.c: routines for manipulating scan converted convex
* polygons.
*
* Copyright 1998-1999, Owen Taylor <otaylor@gtk.org>
*
* > Please contact the above author before modifying the copy <
* > of this file in the GIMP distribution. Thanks. <
*
* 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <gtk/gtk.h>
#include "libgimpmath/gimpmath.h"
#include "tools-types.h"
#include "gimpinktool-blob.h"
typedef enum
{
EDGE_NONE = 0,
EDGE_LEFT = 1 << 0,
EDGE_RIGHT = 1 << 1
} EdgeType;
static Blob *
blob_new (gint y,
gint height)
{
Blob *result;
result = g_malloc (sizeof (Blob) + sizeof (BlobSpan) * (height - 1));
result->y = y;
result->height = height;
return result;
}
static void
blob_fill (Blob *b,
EdgeType *present)
{
gint start;
gint x1, x2, i1, i2;
gint i;
/* Mark empty lines at top and bottom as unused */
start = 0;
while (!(present[start]))
{
b->data[start].left = 0;
b->data[start].right = -1;
start++;
}
if (present[start] != (EDGE_RIGHT | EDGE_LEFT))
{
if (present[start] == EDGE_RIGHT)
b->data[start].left = b->data[start].right;
else
b->data[start].right = b->data[start].left;
present[start] = EDGE_RIGHT | EDGE_LEFT;
}
for (i=b->height-1;!present[i];i--)
{
b->data[i].left = 0;
b->data[i].right = -1;
}
if (present[i] != (EDGE_RIGHT | EDGE_LEFT))
{
if (present[i] == EDGE_RIGHT)
b->data[i].left = b->data[i].right;
else
b->data[i].right = b->data[i].left;
present[i] = EDGE_RIGHT | EDGE_LEFT;
}
/* Restore missing edges */
/* We fill only interior regions of convex hull, as if we were filling
polygons. But since we draw ellipses with nearest points, not interior
points, maybe it would look better if we did the same here. Probably
not a big deal either way after anti-aliasing */
/* left edge */
for (i1=start; i1<b->height-2; i1++)
{
/* Find empty gaps */
if (!(present[i1+1] & EDGE_LEFT))
{
gint increment; /* fractional part */
gint denom; /* denominator of fraction */
gint step; /* integral step */
gint frac; /* fractional step */
gint reverse;
/* find bottom of gap */
i2 = i1+2;
while (i2 < b->height && !(present[i2] & EDGE_LEFT)) i2++;
if (i2 < b->height)
{
denom = i2-i1;
x1 = b->data[i1].left;
x2 = b->data[i2].left;
step = (x2-x1)/denom;
frac = x2-x1 - step*denom;
if (frac < 0)
{
frac = -frac;
reverse = 1;
}
else
reverse = 0;
increment = 0;
for (i=i1+1; i<i2; i++)
{
x1 += step;
increment += frac;
if (increment >= denom)
{
increment -= denom;
x1 += reverse ? -1 : 1;
}
if (increment == 0 || reverse)
b->data[i].left = x1;
else
b->data[i].left = x1 + 1;
}
}
i1 = i2-1; /* advance to next possibility */
}
}
/* right edge */
for (i1=start; i1<b->height-2; i1++)
{
/* Find empty gaps */
if (!(present[i1+1] & EDGE_RIGHT))
{
int increment; /* fractional part */
int denom; /* denominator of fraction */
int step; /* integral step */
int frac; /* fractional step */
int reverse;
/* find bottom of gap */
i2 = i1+2;
while (i2 < b->height && !(present[i2] & EDGE_RIGHT)) i2++;
if (i2 < b->height)
{
denom = i2-i1;
x1 = b->data[i1].right;
x2 = b->data[i2].right;
step = (x2-x1)/denom;
frac = x2-x1 - step*denom;
if (frac < 0)
{
frac = -frac;
reverse = 1;
}
else
reverse = 0;
increment = 0;
for (i=i1+1; i<i2; i++)
{
x1 += step;
increment += frac;
if (increment >= denom)
{
increment -= denom;
x1 += reverse ? -1 : 1;
}
if (reverse && increment != 0)
b->data[i].right = x1 - 1;
else
b->data[i].right = x1;
}
}
i1 = i2-1; /* advance to next possibility */
}
}
}
static void
blob_make_convex (Blob *b, EdgeType *present)
{
int x1, x2, y1, y2, i1, i2;
int i;
int start;
/* Walk through edges, deleting points that aren't on convex hull */
start = 0;
while (!(present[start])) start++;
/* left edge */
i1 = start-1;
i2 = start;
x1 = b->data[start].left - b->data[start].right;
y1 = 0;
for (i=start+1;i<b->height;i++)
{
if (!(present[i] & EDGE_LEFT))
continue;
x2 = b->data[i].left - b->data[i2].left;
y2 = i-i2;
while (x2*y1 - x1*y2 < 0) /* clockwise rotation */
{
present[i2] &= ~EDGE_LEFT;
i2 = i1;
while (!(present[--i1] & EDGE_LEFT) && i1>=start);
if (i1<start)
{
x1 = b->data[start].left - b->data[start].right;
y1 = 0;
}
else
{
x1 = b->data[i2].left - b->data[i1].left;
y1 = i2 - i1;
}
x2 = b->data[i].left - b->data[i2].left;
y2 = i - i2;
}
x1 = x2;
y1 = y2;
i1 = i2;
i2 = i;
}
/* Right edge */
i1 = start -1;
i2 = start;
x1 = b->data[start].right - b->data[start].left;
y1 = 0;
for (i=start+1;i<b->height;i++)
{
if (!(present[i] & EDGE_RIGHT))
continue;
x2 = b->data[i].right - b->data[i2].right;
y2 = i-i2;
while (x2*y1 - x1*y2 > 0) /* counter-clockwise rotation */
{
present[i2] &= ~EDGE_RIGHT;
i2 = i1;
while (!(present[--i1] & EDGE_RIGHT) && i1>=start);
if (i1<start)
{
x1 = b->data[start].right - b->data[start].left;
y1 = 0;
}
else
{
x1 = b->data[i2].right - b->data[i1].right;
y1 = i2 - i1;
}
x2 = b->data[i].right - b->data[i2].right;
y2 = i - i2;
}
x1 = x2;
y1 = y2;
i1 = i2;
i2 = i;
}
blob_fill (b, present);
}
Blob *
blob_convex_union (Blob *b1, Blob *b2)
{
Blob *result;
int y;
int i, j;
EdgeType *present;
/* Create the storage for the result */
y = MIN(b1->y,b2->y);
result = blob_new (y, MAX(b1->y+b1->height,b2->y+b2->height)-y);
if (result->height == 0)
return result;
present = g_new0 (EdgeType, result->height);
/* Initialize spans from original objects */
for (i=0, j=b1->y-y; i<b1->height; i++,j++)
{
if (b1->data[i].right >= b1->data[i].left)
{
present[j] = EDGE_LEFT | EDGE_RIGHT;
result->data[j].left = b1->data[i].left;
result->data[j].right = b1->data[i].right;
}
}
for (i=0, j=b2->y-y; i<b2->height; i++,j++)
{
if (b2->data[i].right >= b2->data[i].left)
{
if (present[j])
{
if (result->data[j].left > b2->data[i].left)
result->data[j].left = b2->data[i].left;
if (result->data[j].right < b2->data[i].right)
result->data[j].right = b2->data[i].right;
}
else
{
present[j] = EDGE_LEFT | EDGE_RIGHT;
result->data[j].left = b2->data[i].left;
result->data[j].right = b2->data[i].right;
}
}
}
blob_make_convex (result, present);
g_free (present);
return result;
}
static void
blob_line_add_pixel (Blob *b, int x, int y)
{
if (b->data[y-b->y].left > b->data[y-b->y].right)
b->data[y-b->y].left = b->data[y-b->y].right = x;
else
{
b->data[y-b->y].left = MIN (b->data[y-b->y].left, x);
b->data[y-b->y].right = MAX (b->data[y-b->y].right, x);
}
}
void
blob_line (Blob *b, int x0, int y0, int x1, int y1)
{
int dx, dy, d;
int incrE, incrNE;
int x, y;
int xstep = 1;
int ystep = 1;
dx = x1 - x0;
dy = y1 - y0;
if (dx < 0)
{
dx = -dx;
xstep = -1;
}
if (dy < 0)
{
dy = -dy;
ystep = -1;
}
/* for (y = y0; y != y1 + ystep ; y += ystep)
{
b->data[y-b->y].left = 0;
b->data[y-b->y].right = -1;
}*/
x = x0;
y = y0;
if (dy < dx)
{
d = 2*dy - dx; /* initial value of d */
incrE = 2 * dy; /* increment used for move to E */
incrNE = 2 * (dy-dx); /* increment used for move to NE */
blob_line_add_pixel (b, x, y);
while (x != x1)
{
if (d <= 0)
{
d += incrE;
x += xstep;
}
else
{
d += incrNE;
x += xstep;
y += ystep;
}
blob_line_add_pixel (b, x, y);
}
}
else
{
d = 2*dx - dy; /* initial value of d */
incrE = 2 * dx; /* increment used for move to E */
incrNE = 2 * (dx-dy); /* increment used for move to NE */
blob_line_add_pixel (b, x, y);
while (y != y1)
{
if (d <= 0)
{
d += incrE;
y += ystep;
}
else
{
d += incrNE;
x += xstep;
y += ystep;
}
blob_line_add_pixel (b, x, y);
}
}
}
#define TABLE_SIZE 256
#define ELLIPSE_SHIFT 2
#define TABLE_SHIFT 12
#define TOTAL_SHIFT (ELLIPSE_SHIFT + TABLE_SHIFT)
/*
* The choose of this values limits the maximal image_size to
* 16384 x 16384 pixels. The values will overflow as soon as
* x or y > INT_MAX / (1 << (ELLIPSE_SHIFT + TABLE_SHIFT)) / SUBSAMPLE
*
* Alternatively the code could be change the code as follows:
*
* xc_base = floor (xc)
* xc_shift = 0.5 + (xc - xc_base) * (1 << TOTAL_SHIFT);
*
* gint x = xc_base + (xc_shift + c * xp_shift + s * xq_shift +
* (1 << (TOTAL_SHIFT - 1))) >> TOTAL_SHIFT;
*
* which would change the limit from the image to the ellipse size
*/
static int trig_initialized = 0;
static int trig_table[TABLE_SIZE];
/* Return blob for the given (convex) polygon
*/
Blob *
blob_polygon (BlobPoint *points, int npoints)
{
int i;
int im1;
int ip1;
int ymin, ymax;
Blob *result;
EdgeType *present;
ymax = points[0].y;
ymin = points[0].y;
for (i=1; i < npoints; i++)
{
if (points[i].y > ymax)
ymax = points[i].y;
if (points[i].y < ymin)
ymin = points[i].y;
}
result = blob_new (ymin, ymax - ymin + 1);
present = g_new0 (EdgeType, result->height);
im1 = npoints - 1;
i = 0;
ip1 = 1;
for (; i < npoints ; i++)
{
int sides = 0;
int j = points[i].y - ymin;
if (points[i].y < points[im1].y)
sides |= EDGE_RIGHT;
else if (points[i].y > points[im1].y)
sides |= EDGE_LEFT;
if (points[ip1].y < points[i].y)
sides |= EDGE_RIGHT;
else if (points[ip1].y > points[i].y)
sides |= EDGE_LEFT;
if (sides & EDGE_RIGHT)
{
if (present[j] & EDGE_RIGHT)
{
result->data[j].right = MAX (result->data[j].right, points[i].x);
}
else
{
present[j] |= EDGE_RIGHT;
result->data[j].right = points[i].x;
}
}
if (sides & EDGE_LEFT)
{
if (present[j] & EDGE_LEFT)
{
result->data[j].left = MIN (result->data[j].left, points[i].x);
}
else
{
present[j] |= EDGE_LEFT;
result->data[j].left = points[i].x;
}
}
im1 = i;
ip1++;
if (ip1 == npoints)
ip1 = 0;
}
blob_fill (result, present);
g_free (present);
return result;
}
/* Scan convert a square specified by _offsets_ of major and
minor axes, and by center into a blob */
Blob *
blob_square (double xc, double yc, double xp, double yp, double xq, double yq)
{
BlobPoint points[4];
/* Make sure we order points ccw */
if (xp * yq - yq * xp < 0)
{
xq = -xq;
yq = -yq;
}
points[0].x = xc + xp + xq;
points[0].y = yc + yp + yq;
points[1].x = xc + xp - xq;
points[1].y = yc + yp - yq;
points[2].x = xc - xp - xq;
points[2].y = yc - yp - yq;
points[3].x = xc - xp + xq;
points[3].y = yc - yp + yq;
return blob_polygon (points, 4);
}
/* Scan convert a diamond specified by _offsets_ of major and
minor axes, and by center into a blob */
Blob *
blob_diamond (double xc, double yc, double xp, double yp, double xq, double yq)
{
BlobPoint points[4];
/* Make sure we order points ccw */
if (xp * yq - yq * xp < 0)
{
xq = -xq;
yq = -yq;
}
points[0].x = xc + xp;
points[0].y = yc + yp;
points[1].x = xc - xq;
points[1].y = yc - yq;
points[2].x = xc - xp;
points[2].y = yc - yp;
points[3].x = xc + xq;
points[3].y = yc + yq;
return blob_polygon (points, 4);
}
/* Scan convert an ellipse specified by _offsets_ of major and
minor axes, and by center into a blob */
Blob *
blob_ellipse (double xc, double yc, double xp, double yp, double xq, double yq)
{
int i;
Blob *r;
gdouble r1, r2;
gint maxy, miny;
gint step;
double max_radius;
gint xc_shift, yc_shift;
gint xp_shift, yp_shift;
gint xq_shift, yq_shift;
EdgeType *present;
if (!trig_initialized)
{
trig_initialized = 1;
for (i=0; i<256; i++)
trig_table[i] = 0.5 + sin(i * (G_PI / 128.)) * (1 << TABLE_SHIFT);
}
/* Make sure we traverse ellipse in ccw direction */
if (xp * yq - yq * xp < 0)
{
xq = -xq;
yq = -yq;
}
/* Compute bounds as if we were drawing a rectangle */
maxy = ceil (yc + fabs (yp) + fabs(yq));
miny = floor (yc - fabs (yp) - fabs(yq));
r = blob_new (miny, maxy - miny + 1);
present = g_new0 (EdgeType, r->height);
/* Figure out a step that will draw most of the points */
r1 = sqrt (xp * xp + yp * yp);
r2 = sqrt (xq * xq + yq * yq);
max_radius = MAX (r1, r2);
step = TABLE_SIZE;
while (step > 1 && (TABLE_SIZE / step < 4*max_radius))
step >>= 1;
/* Fill in the edge points */
xc_shift = 0.5 + xc * (1 << TOTAL_SHIFT);
yc_shift = 0.5 + yc * (1 << TOTAL_SHIFT);
xp_shift = 0.5 + xp * (1 << ELLIPSE_SHIFT);
yp_shift = 0.5 + yp * (1 << ELLIPSE_SHIFT);
xq_shift = 0.5 + xq * (1 << ELLIPSE_SHIFT);
yq_shift = 0.5 + yq * (1 << ELLIPSE_SHIFT);
for (i = 0 ; i < TABLE_SIZE ; i += step)
{
gint s = trig_table[i];
gint c = trig_table[(TABLE_SIZE + TABLE_SIZE/4 - i) % TABLE_SIZE];
gint x = (xc_shift + c * xp_shift + s * xq_shift +
(1 << (TOTAL_SHIFT - 1))) >> TOTAL_SHIFT;
gint y = ((yc_shift + c * yp_shift + s * yq_shift +
(1 << (TOTAL_SHIFT - 1))) >> TOTAL_SHIFT) - r->y;
gint dydi = c * yq_shift - s * yp_shift;
if (dydi <= 0) /* left edge */
{
if (present[y] & EDGE_LEFT)
{
r->data[y].left = MIN (r->data[y].left, x);
}
else
{
present[y] |= EDGE_LEFT;
r->data[y].left = x;
}
}
if (dydi >= 0) /* right edge */
{
if (present[y] & EDGE_RIGHT)
{
r->data[y].right = MAX (r->data[y].right, x);
}
else
{
present[y] |= EDGE_RIGHT;
r->data[y].right = x;
}
}
}
/* Now fill in missing points */
blob_fill (r, present);
g_free (present);
return r;
}
void
blob_bounds(Blob *b, int *x, int *y, int *width, int *height)
{
int i;
int x0, x1, y0, y1;
i = 0;
while (i<b->height && b->data[i].left > b->data[i].right)
i++;
if (i<b->height)
{
y0 = b->y + i;
x0 = b->data[i].left;
x1 = b->data[i].right + 1;
while (i<b->height && b->data[i].left <= b->data[i].right)
{
x0 = MIN(b->data[i].left, x0);
x1 = MAX(b->data[i].right+1, x1);
i++;
}
y1 = b->y + i;
}
else
{
x0 = y0 = 0;
x1 = y1 = 0;
}
*x = x0;
*y = y0;
*width = x1 - x0;
*height = y1 - y0;
}
void
blob_dump(Blob *b) {
int i,j;
for (i=0; i<b->height; i++)
{
for (j=0;j<b->data[i].left;j++)
putchar(' ');
for (j=b->data[i].left;j<=b->data[i].right;j++)
putchar('*');
putchar('\n');
}
}

View File

@ -1,89 +0,0 @@
/* blob.h: routines for manipulating scan converted convex
* polygons.
*
* Copyright 1998, Owen Taylor <otaylor@gtk.org>
*
* > Please contact the above author before modifying the copy <
* > of this file in the GIMP distribution. Thanks. <
*
* 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.
*
*/
#ifndef __GIMP_INK_TOOL_BLOB_H__
#define __GIMP_INK_TOOL_BLOB_H__
typedef struct _BlobPoint BlobPoint;
typedef struct _BlobSpan BlobSpan;
typedef struct _Blob Blob;
typedef Blob * (* BlobFunc) (gdouble,
gdouble,
gdouble,
gdouble,
gdouble,
gdouble);
struct _BlobPoint
{
gint x;
gint y;
};
struct _BlobSpan
{
gint left;
gint right;
};
struct _Blob
{
gint y;
gint height;
BlobSpan data[1];
};
Blob * blob_convex_union (Blob *b1,
Blob *b2);
Blob * blob_polygon (BlobPoint *points,
gint npoints);
Blob * blob_square (gdouble xc,
gdouble yc,
gdouble xp,
gdouble yp,
gdouble xq,
gdouble yq);
Blob * blob_diamond (gdouble xc,
gdouble yc,
gdouble xp,
gdouble yp,
gdouble xq,
gdouble yq);
Blob * blob_ellipse (gdouble xc,
gdouble yc,
gdouble xp,
gdouble yp,
gdouble xq,
gdouble yq);
void blob_bounds (Blob *b,
gint *x,
gint *y,
gint *width,
gint *height);
#endif /* __GIMP_INK_TOOL_BLOB_H__ */

File diff suppressed because it is too large Load Diff

View File

@ -20,12 +20,7 @@
#define __GIMP_INK_TOOL_H__
#include "gimptool.h"
#include "gimpinktool-blob.h" /* only used by ink */
#define DIST_SMOOTHER_BUFFER 10
#define TIME_SMOOTHER_BUFFER 10
#include "gimppainttool.h"
#define GIMP_TYPE_INK_TOOL (gimp_ink_tool_get_type ())
@ -41,30 +36,12 @@ typedef struct _GimpInkToolClass GimpInkToolClass;
struct _GimpInkTool
{
GimpTool parent_instance;
Blob *last_blob; /* blob for last cursor position */
gint x1, y1; /* image space coordinate */
gint x2, y2; /* image space coords */
/* circular distance history buffer */
gdouble dt_buffer[DIST_SMOOTHER_BUFFER];
gint dt_index;
/* circular timing history buffer */
guint32 ts_buffer[TIME_SMOOTHER_BUFFER];
gint ts_index;
gdouble last_time; /* previous time of a motion event */
gdouble lastx, lasty; /* previous position of a motion event */
gboolean init_velocity;
GimpPaintTool parent_instance;
};
struct _GimpInkToolClass
{
GimpToolClass parent_class;
GimpPaintToolClass parent_class;
};