mirror of https://github.com/GNOME/gimp.git
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:
parent
35eeae1447
commit
5e07ceb851
24
ChangeLog
24
ChangeLog
|
@ -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
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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
|
@ -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
|
@ -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__ */
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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__ */
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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__ */
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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__ */
|
|
@ -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');
|
||||
}
|
||||
}
|
|
@ -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
|
@ -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;
|
||||
};
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue